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