Change from getopt to popt -- requires const-correctness on arguments.
[rsync/rsync.git] / log.c
... / ...
CommitLineData
1/* -*- c-file-style: "linux"; -*-
2
3 Copyright (C) 1998-2001 by Andrew Tridgell
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18*/
19
20/*
21 Logging and utility functions.
22
23 Mapping to human-readable messages added by Martin Pool
24 <mbp@samba.org>, Oct 2000.
25 */
26#include "rsync.h"
27
28static char *logfname;
29static FILE *logfile;
30static int log_error_fd = -1;
31
32
33struct {
34 int code;
35 char const *name;
36} const rerr_names[] = {
37 { RERR_SYNTAX , "syntax or usage error" },
38 { RERR_PROTOCOL , "protocol incompatibility" },
39 { RERR_FILESELECT , "errors selecting input/output files, dirs" },
40 { RERR_UNSUPPORTED , "requested action not supported" },
41 { RERR_SOCKETIO , "error in socket IO" },
42 { RERR_FILEIO , "error in file IO" },
43 { RERR_STREAMIO , "error in rsync protocol data stream" },
44 { RERR_MESSAGEIO , "errors with program diagnostics" },
45 { RERR_IPC , "error in IPC code" },
46 { RERR_SIGNAL , "received SIGUSR1 or SIGINT" },
47 { RERR_WAITCHILD , "some error returned by waitpid()" },
48 { RERR_MALLOC , "error allocating core memory buffers" },
49 { RERR_TIMEOUT , "timeout in data send/receive" },
50 { 0, NULL }
51};
52
53
54
55/*
56 * Map from rsync error code to name, or return NULL.
57 */
58static char const *rerr_name(int code)
59{
60 int i;
61 for (i = 0; rerr_names[i].name; i++) {
62 if (rerr_names[i].code == code)
63 return rerr_names[i].name;
64 }
65 return NULL;
66}
67
68
69static void logit(int priority, char *buf)
70{
71 if (logfname) {
72 if (!logfile)
73 log_open();
74 fprintf(logfile,"%s [%d] %s",
75 timestring(time(NULL)), (int)getpid(), buf);
76 fflush(logfile);
77 } else {
78 syslog(priority, "%s", buf);
79 }
80}
81
82void log_init(void)
83{
84 static int initialised;
85 int options = LOG_PID;
86 time_t t;
87
88 if (initialised) return;
89 initialised = 1;
90
91 /* this looks pointless, but it is needed in order for the
92 C library on some systems to fetch the timezone info
93 before the chroot */
94 t = time(NULL);
95 localtime(&t);
96
97 /* optionally use a log file instead of syslog */
98 logfname = lp_log_file();
99 if (logfname) {
100 if (*logfname) {
101 log_open();
102 return;
103 }
104 logfname = NULL;
105 }
106
107#ifdef LOG_NDELAY
108 options |= LOG_NDELAY;
109#endif
110
111#ifdef LOG_DAEMON
112 openlog("rsyncd", options, lp_syslog_facility());
113#else
114 openlog("rsyncd", options);
115#endif
116
117#ifndef LOG_NDELAY
118 logit(LOG_INFO,"rsyncd started\n");
119#endif
120}
121
122void log_open()
123{
124 if (logfname && !logfile) {
125 extern int orig_umask;
126 int old_umask = umask(022 | orig_umask);
127 logfile = fopen(logfname, "a");
128 umask(old_umask);
129 }
130}
131
132void log_close()
133{
134 if (logfile) {
135 fclose(logfile);
136 logfile = NULL;
137 }
138}
139
140/* setup the error file descriptor - used when we are a server
141 that is receiving files */
142void set_error_fd(int fd)
143{
144 log_error_fd = fd;
145}
146
147/* this is the underlying (unformatted) rsync debugging function. Call
148 it with FINFO, FERROR or FLOG */
149void rwrite(enum logcode code, char *buf, int len)
150{
151 FILE *f=NULL;
152 extern int am_daemon;
153 extern int am_server;
154 extern int quiet;
155 /* recursion can happen with certain fatal conditions */
156
157 if (quiet && code == FINFO) return;
158
159 if (len < 0) exit_cleanup(RERR_MESSAGEIO);
160
161 buf[len] = 0;
162
163 if (code == FLOG) {
164 if (am_daemon) logit(LOG_INFO, buf);
165 return;
166 }
167
168 /* first try to pass it off the our sibling */
169 if (am_server && io_error_write(log_error_fd, code, buf, len)) {
170 return;
171 }
172
173 /* then try to pass it to the other end */
174 if (am_server && io_multiplex_write(code, buf, len)) {
175 return;
176 }
177
178 if (am_daemon) {
179 static int depth;
180 int priority = LOG_INFO;
181 if (code == FERROR) priority = LOG_WARNING;
182
183 if (depth) return;
184
185 depth++;
186
187 log_init();
188 logit(priority, buf);
189
190 depth--;
191 return;
192 }
193
194 if (code == FERROR) {
195 f = stderr;
196 }
197
198 if (code == FINFO) {
199 if (am_server)
200 f = stderr;
201 else
202 f = stdout;
203 }
204
205 if (!f) exit_cleanup(RERR_MESSAGEIO);
206
207 if (fwrite(buf, len, 1, f) != 1) exit_cleanup(RERR_MESSAGEIO);
208
209 if (buf[len-1] == '\r' || buf[len-1] == '\n') fflush(f);
210}
211
212
213/* This is the rsync debugging function. Call it with FINFO, FERROR or
214 * FLOG. */
215void rprintf(enum logcode code, const char *format, ...)
216{
217 va_list ap;
218 char buf[1024];
219 int len;
220
221 va_start(ap, format);
222 len = vslprintf(buf, sizeof(buf), format, ap);
223 va_end(ap);
224
225 if (len > sizeof(buf)-1) exit_cleanup(RERR_MESSAGEIO);
226
227 rwrite(code, buf, len);
228}
229
230
231/* This is like rprintf, but it also tries to print some
232 * representation of the error code. Normally errcode = errno.
233 *
234 * Unlike rprintf, this always adds a newline and there should not be
235 * one in the format string.
236 *
237 * Note that since strerror might involve dynamically loading a
238 * message catalog we need to call it once before chroot-ing. */
239void rsyserr(enum logcode code, int errcode, const char *format, ...)
240{
241 va_list ap;
242 char buf[1024];
243 int len, sys_len;
244 char *sysmsg;
245
246 va_start(ap, format);
247 len = vslprintf(buf, sizeof(buf), format, ap);
248 va_end(ap);
249
250 if (len > sizeof(buf)-1) exit_cleanup(RERR_MESSAGEIO);
251
252 sysmsg = strerror(errcode);
253 sys_len = strlen(sysmsg);
254 if (len + 3 + sys_len > sizeof(buf) - 1)
255 exit_cleanup(RERR_MESSAGEIO);
256
257 strcpy(buf + len, ": ");
258 len += 2;
259 strcpy(buf + len, sysmsg);
260 len += sys_len;
261 strcpy(buf + len, "\n");
262 len++;
263
264 rwrite(code, buf, len);
265}
266
267
268
269void rflush(enum logcode code)
270{
271 FILE *f = NULL;
272 extern int am_daemon;
273
274 if (am_daemon) {
275 return;
276 }
277
278 if (code == FLOG) {
279 return;
280 }
281
282 if (code == FERROR) {
283 f = stderr;
284 }
285
286 if (code == FINFO) {
287 extern int am_server;
288 if (am_server)
289 f = stderr;
290 else
291 f = stdout;
292 }
293
294 if (!f) exit_cleanup(RERR_MESSAGEIO);
295 fflush(f);
296}
297
298
299
300/* a generic logging routine for send/recv, with parameter
301 substitiution */
302static void log_formatted(enum logcode code,
303 char *format, char *op, struct file_struct *file,
304 struct stats *initial_stats)
305{
306 extern int module_id;
307 extern char *auth_user;
308 char buf[1024];
309 char buf2[1024];
310 char *p, *s, *n;
311 int l;
312 extern struct stats stats;
313 extern int am_sender;
314 extern int am_daemon;
315 int64 b;
316
317 strlcpy(buf, format, sizeof(buf));
318
319 for (s=&buf[0];
320 s && (p=strchr(s,'%')); ) {
321 n = NULL;
322 s = p + 1;
323
324 switch (p[1]) {
325 case 'h': if (am_daemon) n = client_name(0); break;
326 case 'a': if (am_daemon) n = client_addr(0); break;
327 case 'l':
328 slprintf(buf2,sizeof(buf2),"%.0f",
329 (double)file->length);
330 n = buf2;
331 break;
332 case 'p':
333 slprintf(buf2,sizeof(buf2),"%d",
334 (int)getpid());
335 n = buf2;
336 break;
337 case 'o': n = op; break;
338 case 'f':
339 slprintf(buf2, sizeof(buf2), "%s/%s",
340 file->basedir?file->basedir:"",
341 f_name(file));
342 clean_fname(buf2);
343 n = buf2;
344 if (*n == '/') n++;
345 break;
346 case 'm': n = lp_name(module_id); break;
347 case 't': n = timestring(time(NULL)); break;
348 case 'P': n = lp_path(module_id); break;
349 case 'u': n = auth_user; break;
350 case 'b':
351 if (am_sender) {
352 b = stats.total_written -
353 initial_stats->total_written;
354 } else {
355 b = stats.total_read -
356 initial_stats->total_read;
357 }
358 slprintf(buf2,sizeof(buf2),"%.0f", (double)b);
359 n = buf2;
360 break;
361 case 'c':
362 if (!am_sender) {
363 b = stats.total_written -
364 initial_stats->total_written;
365 } else {
366 b = stats.total_read -
367 initial_stats->total_read;
368 }
369 slprintf(buf2,sizeof(buf2),"%.0f", (double)b);
370 n = buf2;
371 break;
372 }
373
374 if (!n) continue;
375
376 l = strlen(n);
377
378 if ((l-1) + ((int)(s - &buf[0])) > sizeof(buf)) {
379 rprintf(FERROR,"buffer overflow expanding %%%c - exiting\n",
380 p[0]);
381 exit_cleanup(RERR_MESSAGEIO);
382 }
383
384 if (l != 2) {
385 memmove(s+(l-1), s+1, strlen(s+1)+1);
386 }
387 memcpy(p, n, l);
388
389 s = p+l;
390 }
391
392 rprintf(code,"%s\n", buf);
393}
394
395/* log the outgoing transfer of a file */
396void log_send(struct file_struct *file, struct stats *initial_stats)
397{
398 extern int module_id;
399 extern int am_server;
400 extern char *log_format;
401
402 if (lp_transfer_logging(module_id)) {
403 log_formatted(FLOG, lp_log_format(module_id), "send", file, initial_stats);
404 } else if (log_format && !am_server) {
405 log_formatted(FINFO, log_format, "send", file, initial_stats);
406 }
407}
408
409/* log the incoming transfer of a file */
410void log_recv(struct file_struct *file, struct stats *initial_stats)
411{
412 extern int module_id;
413 extern int am_server;
414 extern char *log_format;
415
416 if (lp_transfer_logging(module_id)) {
417 log_formatted(FLOG, lp_log_format(module_id), "recv", file, initial_stats);
418 } else if (log_format && !am_server) {
419 log_formatted(FINFO, log_format, "recv", file, initial_stats);
420 }
421}
422
423
424
425
426/*
427 * Called when the transfer is interrupted for some reason.
428 *
429 * Code is one of the RERR_* codes from errcode.h, or terminating
430 * successfully.
431 */
432void log_exit(int code, const char *file, int line)
433{
434 if (code == 0) {
435 extern struct stats stats;
436 rprintf(FLOG,"wrote %.0f bytes read %.0f bytes total size %.0f\n",
437 (double)stats.total_written,
438 (double)stats.total_read,
439 (double)stats.total_size);
440 } else {
441 const char *name;
442
443 name = rerr_name(code);
444 if (!name)
445 name = "unexplained error";
446
447 rprintf(FLOG,"transfer interrupted: %s (code %d) at %s(%d)\n",
448 name, code, file, line);
449 }
450}
451
452
453
454
455/* log the incoming transfer of a file for interactive use, this
456 will be called at the end where the client was run
457
458 it i called when a file starts to be transferred
459*/
460void log_transfer(struct file_struct *file, const char *fname)
461{
462 extern int verbose;
463
464 if (!verbose) return;
465
466 rprintf(FINFO,"%s\n", fname);
467}
468