Better message grammar.
[rsync/rsync.git] / log.c
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
28 static char *logfname;
29 static FILE *logfile;
30 static int log_error_fd = -1;
31
32
33 struct {
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  */
58 static 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
69 static 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
82 void 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
122 void 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
132 void 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 */
142 void 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 */
149 void 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. */
215 void 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. */
239 void 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
269 void 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 */
302 static 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 */
396 void 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 */
410 void 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  */
432 void 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 */
460 void 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