28dec8d84188622e09b0d5b88599855af98c5fbb
[rsync/rsync-patches.git] / log-file.diff
1 This patch allows a non-daemon server and a client rsync to log what they
2 are doing, similar to how a daemon logs its actions.
3
4 --- old/cleanup.c
5 +++ new/cleanup.c
6 @@ -21,6 +21,7 @@
7  
8  #include "rsync.h"
9  
10 +extern int am_server;
11  extern int io_error;
12  extern int keep_partial;
13  extern int log_got_error;
14 @@ -149,7 +150,7 @@ void _exit_cleanup(int code, const char 
15                         code = RERR_PARTIAL;
16         }
17  
18 -       if (code)
19 +       if (code || am_server)
20                 log_exit(code, file, line);
21  
22         if (verbose > 2) {
23 --- old/clientserver.c
24 +++ new/clientserver.c
25 @@ -44,10 +44,14 @@ extern int protocol_version;
26  extern int io_timeout;
27  extern int no_detach;
28  extern int default_af_hint;
29 +extern int logfile_format_has_i;
30 +extern int logfile_format_has_o_or_i;
31  extern mode_t orig_umask;
32  extern char *bind_address;
33  extern char *sockopts;
34  extern char *config_file;
35 +extern char *logfile_format;
36 +extern char *logfile_name;
37  extern char *files_from;
38  extern char *tmpdir;
39  extern struct chmod_mode_struct *chmod_modes;
40 @@ -55,8 +59,6 @@ extern struct filter_list_struct server_
41  
42  char *auth_user;
43  int read_only = 0;
44 -int daemon_log_format_has_i = 0;
45 -int daemon_log_format_has_o_or_i = 0;
46  int module_id = -1;
47  struct chmod_mode_struct *daemon_chmod_modes;
48  
49 @@ -329,11 +331,12 @@ static int rsync_module(int f_in, int f_
50                 read_only = 1;
51  
52         if (lp_transfer_logging(i)) {
53 -               if (log_format_has(lp_log_format(i), 'i'))
54 -                       daemon_log_format_has_i = 1;
55 -               if (daemon_log_format_has_i
56 -                   || log_format_has(lp_log_format(i), 'o'))
57 -                       daemon_log_format_has_o_or_i = 1;
58 +               logfile_format = lp_log_format(i);
59 +               if (log_format_has(logfile_format, 'i'))
60 +                       logfile_format_has_i = 1;
61 +               if (logfile_format_has_i
62 +                   || log_format_has(logfile_format, 'o'))
63 +                       logfile_format_has_o_or_i = 1;
64         }
65  
66         am_root = (MY_UID() == 0);
67 --- old/flist.c
68 +++ new/flist.c
69 @@ -95,15 +95,15 @@ static int show_filelist_p(void)
70  
71  static void start_filelist_progress(char *kind)
72  {
73 -       rprintf(FINFO, "%s ... ", kind);
74 +       rprintf(FCLIENT, "%s ... ", kind);
75         if (verbose > 1 || do_progress)
76 -               rprintf(FINFO, "\n");
77 +               rprintf(FCLIENT, "\n");
78         rflush(FINFO);
79  }
80  
81  static void emit_filelist_progress(int count)
82  {
83 -       rprintf(FINFO, " %d files...\r", count);
84 +       rprintf(FCLIENT, " %d files...\r", count);
85  }
86  
87  static void maybe_emit_filelist_progress(int count)
88 @@ -295,7 +295,7 @@ void flist_expand(struct file_list *flis
89                                 flist->malloced);
90  
91         if (verbose >= 2 && flist->malloced != FLIST_START) {
92 -               rprintf(FINFO, "[%s] expand file_list to %.0f bytes, did%s move\n",
93 +               rprintf(FCLIENT, "[%s] expand file_list to %.0f bytes, did%s move\n",
94                     who_am_i(),
95                     (double)sizeof flist->files[0] * flist->malloced,
96                     (new_ptr == flist->files) ? " not" : "");
97 @@ -1077,6 +1077,7 @@ struct file_list *send_file_list(int f, 
98         int64 start_write;
99         int use_ff_fd = 0;
100  
101 +       rprintf(FLOG, "building file list\n");
102         if (show_filelist_p())
103                 start_filelist_progress("building file list");
104  
105 @@ -1343,6 +1344,7 @@ struct file_list *recv_file_list(int f)
106         unsigned short flags;
107         int64 start_read;
108  
109 +       rprintf(FLOG, "receiving file list\n");
110         if (show_filelist_p())
111                 start_filelist_progress("receiving file list");
112  
113 --- old/generator.c
114 +++ new/generator.c
115 @@ -27,7 +27,7 @@ extern int verbose;
116  extern int dry_run;
117  extern int do_xfers;
118  extern int log_format_has_i;
119 -extern int daemon_log_format_has_i;
120 +extern int logfile_format_has_i;
121  extern int am_root;
122  extern int am_server;
123  extern int am_daemon;
124 @@ -663,7 +663,7 @@ static int try_dests_reg(struct file_str
125                 } else if (itemizing)
126                         itemize(file, ndx, 0, stp, 0, 0, NULL);
127                 if (verbose > 1 && maybe_ATTRS_REPORT) {
128 -                       code = daemon_log_format_has_i || dry_run
129 +                       code = logfile_format_has_i || dry_run
130                              ? FCLIENT : FINFO;
131                         rprintf(code, "%s is uptodate\n", fname);
132                 }
133 @@ -686,7 +686,7 @@ static int try_dests_reg(struct file_str
134                 if (maybe_ATTRS_REPORT
135                  && ((!itemizing && verbose && match_level == 2)
136                   || (verbose > 1 && match_level == 3))) {
137 -                       code = daemon_log_format_has_i || dry_run
138 +                       code = logfile_format_has_i || dry_run
139                              ? FCLIENT : FINFO;
140                         rprintf(code, "%s%s\n", fname,
141                                 match_level == 3 ? " is uptodate" : "");
142 @@ -742,7 +742,7 @@ static int try_dests_non(struct file_str
143                         itemize(file, ndx, 0, &st, changes, 0, lp);
144                 }
145                 if (verbose > 1 && maybe_ATTRS_REPORT) {
146 -                       code = daemon_log_format_has_i || dry_run
147 +                       code = logfile_format_has_i || dry_run
148                              ? FCLIENT : FINFO;
149                         rprintf(code, "%s is uptodate\n", fname);
150                 }
151 @@ -1304,9 +1304,9 @@ void generate_files(int f_out, struct fi
152         if (protocol_version >= 29) {
153                 itemizing = 1;
154                 maybe_ATTRS_REPORT = log_format_has_i ? 0 : ATTRS_REPORT;
155 -               code = daemon_log_format_has_i ? 0 : FLOG;
156 +               code = logfile_format_has_i ? 0 : FLOG;
157         } else if (am_daemon) {
158 -               itemizing = daemon_log_format_has_i && do_xfers;
159 +               itemizing = logfile_format_has_i && do_xfers;
160                 maybe_ATTRS_REPORT = ATTRS_REPORT;
161                 code = itemizing || !do_xfers ? FCLIENT : FINFO;
162         } else if (!am_server) {
163 --- old/log.c
164 +++ new/log.c
165 @@ -44,18 +44,19 @@ extern int protocol_version;
166  extern int preserve_times;
167  extern int log_format_has_i;
168  extern int log_format_has_o_or_i;
169 -extern int daemon_log_format_has_o_or_i;
170 +extern int logfile_format_has_o_or_i;
171  extern mode_t orig_umask;
172  extern char *auth_user;
173  extern char *log_format;
174 +extern char *logfile_format;
175 +extern char *logfile_name;
176  #if defined HAVE_ICONV_OPEN && defined HAVE_ICONV_H
177  extern iconv_t ic_chck;
178  #endif
179  
180  static int log_initialised;
181  static int logfile_was_closed;
182 -static char *logfname;
183 -static FILE *logfile;
184 +static FILE *logfile_fp;
185  struct stats stats;
186  
187  int log_got_error = 0;
188 @@ -109,10 +110,10 @@ static void logit(int priority, char *bu
189  {
190         if (logfile_was_closed)
191                 logfile_reopen();
192 -       if (logfile) {
193 -               fprintf(logfile,"%s [%d] %s",
194 +       if (logfile_fp) {
195 +               fprintf(logfile_fp, "%s [%d] %s",
196                         timestring(time(NULL)), (int)getpid(), buf);
197 -               fflush(logfile);
198 +               fflush(logfile_fp);
199         } else {
200                 syslog(priority, "%s", buf);
201         }
202 @@ -145,14 +146,14 @@ static void syslog_init()
203  static void logfile_open(void)
204  {
205         mode_t old_umask = umask(022 | orig_umask);
206 -       logfile = fopen(logfname, "a");
207 +       logfile_fp = fopen(logfile_name, "a");
208         umask(old_umask);
209 -       if (!logfile) {
210 +       if (!logfile_fp) {
211                 int fopen_errno = errno;
212                 /* Rsync falls back to using syslog on failure. */
213                 syslog_init();
214                 rsyserr(FERROR, fopen_errno,
215 -                       "failed to open log-file %s", logfname);
216 +                       "failed to open log-file %s", logfile_name);
217                 rprintf(FINFO, "Ignoring \"log file\" setting.\n");
218         }
219  }
220 @@ -171,9 +172,11 @@ void log_init(void)
221         t = time(NULL);
222         localtime(&t);
223  
224 -       /* optionally use a log file instead of syslog */
225 -       logfname = lp_log_file();
226 -       if (logfname && *logfname)
227 +       /* Optionally use a log file instead of syslog.  (Non-daemon
228 +        * rsyncs will have already set logfile_name, as needed.) */
229 +       if (am_daemon)
230 +               logfile_name = lp_log_file();
231 +       if (logfile_name && *logfile_name)
232                 logfile_open();
233         else
234                 syslog_init();
235 @@ -181,10 +184,10 @@ void log_init(void)
236  
237  void logfile_close(void)
238  {
239 -       if (logfile) {
240 +       if (logfile_fp) {
241                 logfile_was_closed = 1;
242 -               fclose(logfile);
243 -               logfile = NULL;
244 +               fclose(logfile_fp);
245 +               logfile_fp = NULL;
246         }
247  }
248  
249 @@ -243,9 +246,9 @@ void rwrite(enum logcode code, char *buf
250  
251         if (code == FCLIENT)
252                 code = FINFO;
253 -       else if (am_daemon) {
254 +       else if (am_daemon || logfile_name) {
255                 static int in_block;
256 -               char msg[2048];
257 +               char msg[2048], *s;
258                 int priority = code == FERROR ? LOG_WARNING : LOG_INFO;
259  
260                 if (in_block)
261 @@ -254,10 +257,11 @@ void rwrite(enum logcode code, char *buf
262                 if (!log_initialised)
263                         log_init();
264                 strlcpy(msg, buf, MIN((int)sizeof msg, len + 1));
265 -               logit(priority, msg);
266 +               for (s = msg; *s == '\n' && s[1]; s++) {}
267 +               logit(priority, s);
268                 in_block = 0;
269  
270 -               if (code == FLOG || !am_server)
271 +               if (code == FLOG || (am_daemon && !am_server))
272                         return;
273         } else if (code == FLOG)
274                 return;
275 @@ -403,26 +407,14 @@ void rflush(enum logcode code)
276  {
277         FILE *f = NULL;
278  
279 -       if (am_daemon) {
280 +       if (am_daemon || code == FLOG)
281                 return;
282 -       }
283  
284 -       if (code == FLOG) {
285 -               return;
286 -       }
287 -
288 -       if (code == FERROR) {
289 +       if (code == FERROR || am_server)
290                 f = stderr;
291 -       }
292 -
293 -       if (code == FINFO) {
294 -               if (am_server)
295 -                       f = stderr;
296 -               else
297 -                       f = stdout;
298 -       }
299 +       else
300 +               f = stdout;
301  
302 -       if (!f) exit_cleanup(RERR_MESSAGEIO);
303         fflush(f);
304  }
305  
306 @@ -695,12 +687,12 @@ void log_item(struct file_struct *file, 
307  {
308         char *s_or_r = am_sender ? "send" : "recv";
309  
310 -       if (lp_transfer_logging(module_id)) {
311 -               log_formatted(FLOG, lp_log_format(module_id), s_or_r,
312 -                             file, initial_stats, iflags, hlink);
313 -       } else if (log_format && !am_server) {
314 +       if (log_format && !am_server) {
315                 log_formatted(FNAME, log_format, s_or_r,
316                               file, initial_stats, iflags, hlink);
317 +       } else if (logfile_format) {
318 +               log_formatted(FLOG, logfile_format, s_or_r,
319 +                             file, initial_stats, iflags, hlink);
320         }
321  }
322  
323 @@ -712,7 +704,7 @@ void maybe_log_item(struct file_struct *
324                 || log_format_has_i > 1 || (verbose > 1 && log_format_has_i));
325         int local_change = iflags & ITEM_LOCAL_CHANGE && significant_flags;
326         if (am_server) {
327 -               if (am_daemon && !dry_run && see_item)
328 +               if (logfile_name && !dry_run && see_item)
329                         log_item(file, &stats, iflags, buf);
330         } else if (see_item || local_change || *buf
331             || (S_ISDIR(file->mode) && significant_flags))
332 @@ -740,10 +732,10 @@ void log_delete(char *fname, int mode)
333                               ITEM_DELETED, NULL);
334         }
335  
336 -       if (!am_daemon || dry_run || !lp_transfer_logging(module_id))
337 +       if (!logfile_name || dry_run || !logfile_format)
338                 return;
339  
340 -       fmt = daemon_log_format_has_o_or_i ? lp_log_format(module_id) : "deleting %n";
341 +       fmt = logfile_format_has_o_or_i ? logfile_format : "deleting %n";
342         log_formatted(FLOG, fmt, "del.", &file, &stats, ITEM_DELETED, NULL);
343  }
344  
345 --- old/main.c
346 +++ new/main.c
347 @@ -168,7 +168,6 @@ static void handle_stats(int f)
348                 return;
349  
350         if (am_daemon) {
351 -               log_exit(0, __FILE__, __LINE__);
352                 if (f == -1 || !am_sender)
353                         return;
354         }
355 --- old/options.c
356 +++ new/options.c
357 @@ -146,6 +146,8 @@ char *basis_dir[MAX_BASIS_DIRS+1];
358  char *config_file = NULL;
359  char *shell_cmd = NULL;
360  char *log_format = NULL;
361 +char *logfile_name = NULL;
362 +char *logfile_format = NULL;
363  char *password_file = NULL;
364  char *rsync_path = RSYNC_PATH;
365  char *backup_dir = NULL;
366 @@ -162,7 +164,9 @@ int verbose = 0;
367  int quiet = 0;
368  int log_before_transfer = 0;
369  int log_format_has_i = 0;
370 +int logfile_format_has_i = 0;
371  int log_format_has_o_or_i = 0;
372 +int logfile_format_has_o_or_i = 0;
373  int always_checksum = 0;
374  int list_only = 0;
375  
376 @@ -359,6 +363,7 @@ void usage(enum logcode F)
377    rprintf(F,"     --progress              show progress during transfer\n");
378    rprintf(F," -P                          same as --partial --progress\n");
379    rprintf(F," -i, --itemize-changes       output a change-summary for all updates\n");
380 +  rprintf(F,"     --log-file=FILE         output what we're doing to a log file\n");
381    rprintf(F,"     --log-format=FORMAT     output filenames using the specified format\n");
382    rprintf(F,"     --password-file=FILE    read password from FILE\n");
383    rprintf(F,"     --list-only             list the files instead of copying them\n");
384 @@ -492,6 +497,7 @@ static struct poptOption long_options[] 
385    {"partial-dir",      0,  POPT_ARG_STRING, &partial_dir, 0, 0, 0 },
386    {"delay-updates",    0,  POPT_ARG_NONE,   &delay_updates, 0, 0, 0 },
387    {"prune-empty-dirs",'m', POPT_ARG_NONE,   &prune_empty_dirs, 0, 0, 0 },
388 +  {"log-file",         0,  POPT_ARG_STRING, &logfile_name, 0, 0, 0 },
389    {"log-format",       0,  POPT_ARG_STRING, &log_format, 0, 0, 0 },
390    {"itemize-changes", 'i', POPT_ARG_NONE,   0, 'i', 0, 0 },
391    {"bwlimit",          0,  POPT_ARG_INT,    &bwlimit, 0, 0, 0 },
392 @@ -1311,6 +1317,21 @@ int parse_arguments(int *argc, const cha
393         if (log_format_has_i || log_format_has(log_format, 'o'))
394                 log_format_has_o_or_i = 1;
395  
396 +       if (am_daemon)
397 +               logfile_name = NULL;
398 +       else if (logfile_name) {
399 +               if (am_server) {
400 +                       logfile_format = "%i %n%L";
401 +                       logfile_format_has_i = logfile_format_has_o_or_i = 1;
402 +               } else if (log_format) {
403 +                       logfile_format = log_format;
404 +                       logfile_format_has_i = log_format_has_i;
405 +                       logfile_format_has_o_or_i = log_format_has_o_or_i;
406 +               }
407 +               log_before_transfer = !am_server;
408 +               log_init();
409 +       }
410 +
411         if (daemon_bwlimit && (!bwlimit || bwlimit > daemon_bwlimit))
412                 bwlimit = daemon_bwlimit;
413         if (bwlimit) {
414 --- old/progress.c
415 +++ new/progress.c
416 @@ -103,7 +103,7 @@ static void rprint_progress(OFF_T ofs, O
417                         stats.num_files);
418         } else
419                 strcpy(eol, "\r");
420 -       rprintf(FINFO, "%12s %3d%% %7.2f%s %4d:%02d:%02d%s",
421 +       rprintf(FCLIENT, "%12s %3d%% %7.2f%s %4d:%02d:%02d%s",
422                 human_num(ofs), pct, rate, units,
423                 remain_h, remain_m, remain_s, eol);
424  }
425 --- old/receiver.c
426 +++ new/receiver.c
427 @@ -27,7 +27,7 @@ extern int am_server;
428  extern int do_progress;
429  extern int log_before_transfer;
430  extern int log_format_has_i;
431 -extern int daemon_log_format_has_i;
432 +extern int logfile_format_has_i;
433  extern int csum_length;
434  extern int read_batch;
435  extern int write_batch;
436 @@ -341,8 +341,7 @@ int recv_files(int f_in, struct file_lis
437         struct file_struct *file;
438         struct stats initial_stats;
439         int save_make_backups = make_backups;
440 -       int itemizing = am_daemon ? daemon_log_format_has_i
441 -                     : !am_server && log_format_has_i;
442 +       int itemizing = am_server ? logfile_format_has_i : log_format_has_i;
443         int max_phase = protocol_version >= 29 ? 2 : 1;
444         int i, recv_ok;
445  
446 --- old/rsync.c
447 +++ new/rsync.c
448 @@ -32,7 +32,7 @@
449  
450  extern int verbose;
451  extern int dry_run;
452 -extern int daemon_log_format_has_i;
453 +extern int logfile_format_has_i;
454  extern int preserve_perms;
455  extern int preserve_executability;
456  extern int preserve_times;
457 @@ -218,7 +218,7 @@ int set_file_attrs(char *fname, struct f
458  #endif
459  
460         if (verbose > 1 && flags & ATTRS_REPORT) {
461 -               enum logcode code = daemon_log_format_has_i || dry_run
462 +               enum logcode code = logfile_format_has_i || dry_run
463                                   ? FCLIENT : FINFO;
464                 if (updated)
465                         rprintf(code, "%s\n", fname);
466 --- old/rsync.h
467 +++ new/rsync.h
468 @@ -158,8 +158,8 @@
469  
470  
471  /* Log-message categories.  Only FERROR and FINFO get sent over the socket.
472 - * FLOG and FCLIENT are only used on the daemon side for custom logging,
473 - * while FNAME is only used on the client side. */
474 + * FLOG only goes to the log file, not to the client; FCLIENT is the opposite.
475 + * FNAME is a client-side message when outputting a filename on its own. */
476  enum logcode { FERROR=1, FINFO=2, FLOG=3, FCLIENT=4, FNAME=5, FSOCKERR=6 };
477  
478  /* Messages types that are sent over the message channel.  The logcode
479 --- old/rsync.yo
480 +++ new/rsync.yo
481 @@ -387,6 +387,7 @@ to the detailed description below for a 
482       --progress              show progress during transfer
483   -P                          same as --partial --progress
484   -i, --itemize-changes       output a change-summary for all updates
485 +     --log-file=FILE         output what we're doing to a log file
486       --log-format=FORMAT     output filenames using the specified format
487       --password-file=FILE    read password from FILE
488       --list-only             list the files instead of copying them
489 @@ -1423,6 +1424,23 @@ the string "*deleting" for each item tha
490  you are talking to a recent enough rsync that it logs deletions instead of
491  outputting them as a verbose message).
492  
493 +dit(bf(--log-file=FILE)) This option causes rsync to log what it is doing
494 +to a file.  This is similar to the logging that a daemon does, but can be
495 +requested for the client side and/or the server side of a non-daemon
496 +transfer.  If specified as a client option, transfer logging will in effect
497 +if the bf(--log-format) option was either specified or implied (e.g.
498 +bf(--verbose) implies a basic log format).  If explicitly sent to a server
499 +via the bf(--rsync-path) option, transfer logging will always occur using
500 +the default bf(--itemize-changes) format.
501 +
502 +Here's a example command that requests the remote side to log what is
503 +happening:
504 +
505 +verb(  rsync -av --rsync-path="path --log-file=/tmp/rlog" src/ dest/)
506 +
507 +This is very useful if you need to debug why a connection is closing
508 +unexpectedly.
509 +
510  dit(bf(--log-format=FORMAT)) This allows you to specify exactly what the
511  rsync client outputs to the user on a per-file basis.  The format is a text
512  string containing embedded single-character escape sequences prefixed with
513 --- old/sender.c
514 +++ new/sender.c
515 @@ -25,7 +25,7 @@ extern int am_server;
516  extern int am_daemon;
517  extern int log_before_transfer;
518  extern int log_format_has_i;
519 -extern int daemon_log_format_has_i;
520 +extern int logfile_format_has_i;
521  extern int csum_length;
522  extern int append_mode;
523  extern int io_error;
524 @@ -215,8 +215,7 @@ void send_files(struct file_list *flist,
525         int phase = 0, max_phase = protocol_version >= 29 ? 2 : 1;
526         struct stats initial_stats;
527         int save_make_backups = make_backups;
528 -       int itemizing = am_daemon ? daemon_log_format_has_i
529 -                     : !am_server && log_format_has_i;
530 +       int itemizing = am_server ? logfile_format_has_i : log_format_has_i;
531         int f_xfer = write_batch < 0 ? batch_fd : f_out;
532         int i, j;
533