- We now filter all rwrite() output when it goes out to the terminal
[rsync/rsync.git] / log.c
CommitLineData
a039749b 1/* -*- c-file-style: "linux"; -*-
4a7319be 2
0c5a792a 3 Copyright (C) 1998-2001 by Andrew Tridgell <tridge@samba.org>
18c71e96 4 Copyright (C) 2000-2001 by Martin Pool <mbp@samba.org>
4a7319be 5
0b76cd63
AT
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
4a7319be 10
0b76cd63
AT
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
4a7319be 15
0b76cd63
AT
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19*/
20
21/*
3e3dcd62 22 Logging and utility functions.
0c5a792a 23 tridge, May 1998
0b76cd63 24
3e3dcd62
MP
25 Mapping to human-readable messages added by Martin Pool
26 <mbp@samba.org>, Oct 2000.
0b76cd63
AT
27 */
28#include "rsync.h"
29
41b5b5e7 30extern int verbose;
088aff1a 31extern int dry_run;
548abf96
WD
32extern int am_daemon;
33extern int am_server;
34extern int am_sender;
c1759b9f 35extern int local_server;
548abf96
WD
36extern int quiet;
37extern int module_id;
a644fc3c 38extern int msg_fd_out;
19bc826d 39extern int protocol_version;
ef74f5d6 40extern int preserve_times;
6d4ecad1 41extern int log_format_has_i;
d6707171 42extern int log_format_has_o_or_i;
1eec003a 43extern int daemon_log_format_has_o_or_i;
548abf96
WD
44extern char *auth_user;
45extern char *log_format;
46
30e8c8e1 47static int log_initialised;
64c37826 48static int logfile_was_closed;
45a83540 49static char *logfname;
4f6325c3 50static FILE *logfile;
b35d0d8e 51struct stats stats;
e0414f42 52
8fcdc444 53int log_got_error = 0;
af642a61
MP
54
55struct {
56 int code;
57 char const *name;
58} const rerr_names[] = {
4a7319be
WD
59 { RERR_SYNTAX , "syntax or usage error" },
60 { RERR_PROTOCOL , "protocol incompatibility" },
61 { RERR_FILESELECT , "errors selecting input/output files, dirs" },
62 { RERR_UNSUPPORTED, "requested action not supported" },
63 { RERR_STARTCLIENT, "error starting client-server protocol" },
64 { RERR_SOCKETIO , "error in socket IO" },
65 { RERR_FILEIO , "error in file IO" },
66 { RERR_STREAMIO , "error in rsync protocol data stream" },
67 { RERR_MESSAGEIO , "errors with program diagnostics" },
68 { RERR_IPC , "error in IPC code" },
60168410 69 { RERR_CRASHED , "sibling process crashed" },
0047f535 70 { RERR_TERMINATED , "sibling process terminated abnormally" },
4a50a217
WD
71 { RERR_SIGNAL1 , "received SIGUSR1" },
72 { RERR_SIGNAL , "received SIGINT, SIGTERM, or SIGHUP" },
f14a65d9 73 { RERR_WAITCHILD , "waitpid() failed" },
4a7319be
WD
74 { RERR_MALLOC , "error allocating core memory buffers" },
75 { RERR_PARTIAL , "some files could not be transferred" },
584ba4eb 76 { RERR_VANISHED , "some files vanished before they could be transferred" },
4a7319be 77 { RERR_TIMEOUT , "timeout in data send/receive" },
19b27a48
AT
78 { RERR_CMD_FAILED , "remote shell failed" },
79 { RERR_CMD_KILLED , "remote shell killed" },
24cecf13
WD
80 { RERR_CMD_RUN , "remote command could not be run" },
81 { RERR_CMD_NOTFOUND,"remote command not found" },
26718401 82 { RERR_DEL_LIMIT , "the --max-delete limit stopped deletions" },
4a7319be 83 { 0, NULL }
af642a61
MP
84};
85
86
87
88/*
89 * Map from rsync error code to name, or return NULL.
90 */
91static char const *rerr_name(int code)
92{
4a7319be
WD
93 int i;
94 for (i = 0; rerr_names[i].name; i++) {
95 if (rerr_names[i].code == code)
96 return rerr_names[i].name;
97 }
98 return NULL;
af642a61
MP
99}
100
2267efea 101
4f6325c3
AT
102static void logit(int priority, char *buf)
103{
64c37826
WD
104 if (logfile_was_closed)
105 logfile_reopen();
106 if (logfile) {
4a7319be 107 fprintf(logfile,"%s [%d] %s",
f7632fc6 108 timestring(time(NULL)), (int)getpid(), buf);
4f6325c3
AT
109 fflush(logfile);
110 } else {
111 syslog(priority, "%s", buf);
112 }
113}
e42c9458 114
6afb9077 115static void syslog_init()
1a016bfd 116{
6afb9077 117 static int been_here = 0;
1a016bfd 118 int options = LOG_PID;
6afb9077
WD
119
120 if (been_here)
121 return;
122 been_here = 1;
123
124#ifdef LOG_NDELAY
125 options |= LOG_NDELAY;
126#endif
127
128#ifdef LOG_DAEMON
129 openlog("rsyncd", options, lp_syslog_facility());
130#else
131 openlog("rsyncd", options);
132#endif
133
134#ifndef LOG_NDELAY
135 logit(LOG_INFO, "rsyncd started\n");
136#endif
137}
138
64c37826
WD
139static void logfile_open(void)
140{
141 extern int orig_umask;
142 int old_umask = umask(022 | orig_umask);
143 logfile = fopen(logfname, "a");
144 umask(old_umask);
145 if (!logfile) {
146 int fopen_errno = errno;
147 /* Rsync falls back to using syslog on failure. */
148 syslog_init();
149 rsyserr(FERROR, fopen_errno,
150 "failed to open log-file %s", logfname);
151 rprintf(FINFO, "Ignoring \"log file\" setting.\n");
152 }
153}
154
6afb9077
WD
155void log_init(void)
156{
bcf5b133 157 time_t t;
1a016bfd 158
0bb4d176
WD
159 if (log_initialised)
160 return;
30e8c8e1 161 log_initialised = 1;
1a016bfd 162
958f3735 163 /* this looks pointless, but it is needed in order for the
4a7319be
WD
164 * C library on some systems to fetch the timezone info
165 * before the chroot */
958f3735
AT
166 t = time(NULL);
167 localtime(&t);
168
169 /* optionally use a log file instead of syslog */
45a83540 170 logfname = lp_log_file();
64c37826
WD
171 if (logfname && *logfname)
172 logfile_open();
173 else
174 syslog_init();
1a016bfd 175}
1a016bfd 176
64c37826 177void logfile_close(void)
4a239e98 178{
64c37826
WD
179 if (logfile) {
180 logfile_was_closed = 1;
181 fclose(logfile);
182 logfile = NULL;
4a239e98
WD
183 }
184}
185
64c37826 186void logfile_reopen(void)
4a239e98 187{
64c37826
WD
188 if (logfile_was_closed) {
189 logfile_was_closed = 0;
190 logfile_open();
4a239e98
WD
191 }
192}
193
be0602ec
WD
194static void filtered_fwrite(const char *buf, int len, FILE *f)
195{
196 const char *s, *end = buf + len;
197 for (s = buf; s < end; s++) {
198 if ((s < end - 4
199 && *s == '\\' && s[1] == '0'
200 && isdigit(*(uchar*)(s+2))
201 && isdigit(*(uchar*)(s+3))
202 && isdigit(*(uchar*)(s+4)))
203 || !isprint(*(uchar*)s)
204 || *(uchar*)s < ' ') {
205 if (s != buf && fwrite(buf, s - buf, 1, f) != 1)
206 exit_cleanup(RERR_MESSAGEIO);
207 fprintf(f, "\\%04o", *(uchar*)s);
208 buf = s + 1;
209 }
210 }
211 if (buf != end && fwrite(buf, end - buf, 1, f) != 1)
212 exit_cleanup(RERR_MESSAGEIO);
213}
214
554e0a8d 215/* this is the underlying (unformatted) rsync debugging function. Call
be0602ec
WD
216 * it with FINFO, FERROR or FLOG. Note: recursion can happen with
217 * certain fatal conditions. */
ff41a59f 218void rwrite(enum logcode code, char *buf, int len)
0b76cd63 219{
be0602ec 220 int trailing_CR_or_NL;
8fcdc444 221 FILE *f = NULL;
8d9dc9f9 222
a644fc3c
WD
223 if (quiet && code == FINFO)
224 return;
b86f0cef 225
a644fc3c
WD
226 if (len < 0)
227 exit_cleanup(RERR_MESSAGEIO);
0b76cd63 228
0bb4d176
WD
229 if (am_server && msg_fd_out >= 0) {
230 /* Pass the message to our sibling. */
231 send_msg((enum msgcode)code, buf, len);
11a5a3c7
AT
232 return;
233 }
234
1eec003a
WD
235 if (code == FCLIENT)
236 code = FINFO;
237 else if (am_daemon) {
0bb4d176
WD
238 static int in_block;
239 char msg[2048];
240 int priority = code == FERROR ? LOG_WARNING : LOG_INFO;
241
242 if (in_block)
a644fc3c 243 return;
0bb4d176
WD
244 in_block = 1;
245 if (!log_initialised)
246 log_init();
247 strlcpy(msg, buf, MIN((int)sizeof msg, len + 1));
248 logit(priority, msg);
249 in_block = 0;
250
251 if (code == FLOG || !am_server)
a644fc3c 252 return;
0bb4d176 253 } else if (code == FLOG)
ff8b29b8 254 return;
0bb4d176
WD
255
256 if (am_server) {
257 /* Pass the message to the non-server side. */
258 if (io_multiplex_write((enum msgcode)code, buf, len))
259 return;
260 if (am_daemon) {
261 /* TODO: can we send the error to the user somehow? */
262 return;
263 }
0b76cd63
AT
264 }
265
be0602ec
WD
266 switch (code) {
267 case FERROR:
ff81e809 268 log_got_error = 1;
ff8b29b8 269 f = stderr;
be0602ec
WD
270 break;
271 case FINFO:
0bb4d176 272 f = am_server ? stderr : stdout;
be0602ec
WD
273 while (len && (*buf == '\n' || *buf == '\t')) {
274 fputc(*buf, f);
275 buf++;
276 len--;
277 }
278 break;
279 case FNAME:
280 f = am_server ? stderr : stdout;
281 break;
282 default:
0bb4d176 283 exit_cleanup(RERR_MESSAGEIO);
be0602ec 284 }
0b76cd63 285
be0602ec
WD
286 trailing_CR_or_NL = len && (buf[len-1] == '\n' || buf[len-1] == '\r')
287 ? buf[--len] : 0;
8d9dc9f9 288
be0602ec
WD
289 filtered_fwrite(buf, len, f);
290
291 if (trailing_CR_or_NL) {
292 fputc(trailing_CR_or_NL, f);
0bb4d176 293 fflush(f);
be0602ec 294 }
0b76cd63 295}
0455cd93 296
554e0a8d 297
a039749b
MP
298/* This is the rsync debugging function. Call it with FINFO, FERROR or
299 * FLOG. */
300void rprintf(enum logcode code, const char *format, ...)
554e0a8d 301{
4a7319be 302 va_list ap;
b74b3d53 303 char buf[BIGPATHBUFLEN];
8fcdc444 304 size_t len;
554e0a8d
AT
305
306 va_start(ap, format);
ef74f5d6 307 len = vsnprintf(buf, sizeof buf, format, ap);
554e0a8d
AT
308 va_end(ap);
309
b2f02464 310 /* Deal with buffer overruns. Instead of panicking, just
8fcdc444
WD
311 * truncate the resulting string. (Note that configure ensures
312 * that we have a vsnprintf() that doesn't ever return -1.) */
313 if (len > sizeof buf - 1) {
b74b3d53 314 static const char ellipsis[] = "[...]";
b2f02464
MP
315
316 /* Reset length, and zero-terminate the end of our buffer */
ef74f5d6 317 len = sizeof buf - 1;
b2f02464
MP
318 buf[len] = '\0';
319
320 /* Copy the ellipsis to the end of the string, but give
321 * us one extra character:
322 *
ef74f5d6 323 * v--- null byte at buf[sizeof buf - 1]
b2f02464
MP
324 * abcdefghij0
325 * -> abcd[...]00 <-- now two null bytes at end
326 *
327 * If the input format string has a trailing newline,
328 * we copy it into that extra null; if it doesn't, well,
329 * all we lose is one byte. */
b74b3d53 330 memcpy(buf+len-sizeof ellipsis, ellipsis, sizeof ellipsis);
b2f02464
MP
331 if (format[strlen(format)-1] == '\n') {
332 buf[len-1] = '\n';
333 }
334 }
554e0a8d 335
ff41a59f 336 rwrite(code, buf, len);
554e0a8d 337}
0b76cd63 338
a039749b
MP
339
340/* This is like rprintf, but it also tries to print some
341 * representation of the error code. Normally errcode = errno.
342 *
343 * Unlike rprintf, this always adds a newline and there should not be
344 * one in the format string.
345 *
346 * Note that since strerror might involve dynamically loading a
347 * message catalog we need to call it once before chroot-ing. */
348void rsyserr(enum logcode code, int errcode, const char *format, ...)
349{
4a7319be 350 va_list ap;
b74b3d53 351 char buf[BIGPATHBUFLEN];
8fcdc444
WD
352 size_t len;
353
354 strcpy(buf, RSYNC_NAME ": ");
355 len = (sizeof RSYNC_NAME ": ") - 1;
a039749b
MP
356
357 va_start(ap, format);
8fcdc444 358 len += vsnprintf(buf + len, sizeof buf - len, format, ap);
a039749b
MP
359 va_end(ap);
360
8fcdc444
WD
361 if (len < sizeof buf) {
362 len += snprintf(buf + len, sizeof buf - len,
363 ": %s (%d)\n", strerror(errcode), errcode);
364 }
365 if (len >= sizeof buf)
4a7319be 366 exit_cleanup(RERR_MESSAGEIO);
a039749b 367
a039749b
MP
368 rwrite(code, buf, len);
369}
370
371
372
ff41a59f 373void rflush(enum logcode code)
0b76cd63
AT
374{
375 FILE *f = NULL;
0455cd93 376
0b76cd63
AT
377 if (am_daemon) {
378 return;
379 }
380
ff41a59f 381 if (code == FLOG) {
e08bfe12 382 return;
4a7319be 383 }
e08bfe12 384
ff41a59f 385 if (code == FERROR) {
0b76cd63 386 f = stderr;
4a7319be 387 }
0b76cd63 388
ff41a59f 389 if (code == FINFO) {
4a7319be 390 if (am_server)
0b76cd63
AT
391 f = stderr;
392 else
393 f = stdout;
4a7319be 394 }
0b76cd63 395
65417579 396 if (!f) exit_cleanup(RERR_MESSAGEIO);
0b76cd63
AT
397 fflush(f);
398}
399
11a5a3c7 400
e08bfe12
AT
401
402/* a generic logging routine for send/recv, with parameter
4a7319be 403 * substitiution */
afc65a5a
WD
404static void log_formatted(enum logcode code, char *format, char *op,
405 struct file_struct *file, struct stats *initial_stats,
406 int iflags, char *hlink)
e08bfe12 407{
ddd74b67
WD
408 char buf[MAXPATHLEN+1024], buf2[MAXPATHLEN], fmt[32];
409 char *p, *s, *n;
ef74f5d6 410 size_t len, total;
1b7c47cb 411 int64 b;
e08bfe12 412
ddd74b67
WD
413 *fmt = '%';
414
aa126974 415 /* We expand % codes one by one in place in buf. We don't
126e7aff
WD
416 * copy in the terminating null of the inserted strings, but
417 * rather keep going until we reach the null of the format. */
ef74f5d6 418 total = strlcpy(buf, format, sizeof buf);
d9c0051f
WD
419 if (total > MAXPATHLEN) {
420 rprintf(FERROR, "log-format string is WAY too long!\n");
421 exit_cleanup(RERR_MESSAGEIO);
422 }
423 buf[total++] = '\n';
424 buf[total] = '\0';
0455cd93 425
16f960fe 426 for (p = buf; (p = strchr(p, '%')) != NULL; ) {
ddd74b67
WD
427 s = p++;
428 n = fmt + 1;
9baed760
WD
429 if (*p == '-')
430 *n++ = *p++;
b4bf2b5a 431 while (isdigit(*(uchar*)p) && n - fmt < (int)(sizeof fmt) - 8)
ddd74b67 432 *n++ = *p++;
e145d51b
WD
433 if (!*p)
434 break;
ddd74b67 435 *n = '\0';
e08bfe12 436 n = NULL;
e08bfe12 437
0455cd93 438 switch (*p) {
b74b3d53
WD
439 case 'h':
440 if (am_daemon)
441 n = client_name(0);
442 break;
443 case 'a':
444 if (am_daemon)
445 n = client_addr(0);
446 break;
4a7319be 447 case 'l':
ddd74b67
WD
448 strlcat(fmt, ".0f", sizeof fmt);
449 snprintf(buf2, sizeof buf2, fmt,
4a7319be 450 (double)file->length);
e08bfe12
AT
451 n = buf2;
452 break;
4a7319be 453 case 'p':
126e7aff 454 strlcat(fmt, "ld", sizeof fmt);
ddd74b67 455 snprintf(buf2, sizeof buf2, fmt,
126e7aff 456 (long)getpid());
e08bfe12
AT
457 n = buf2;
458 break;
b74b3d53
WD
459 case 'o':
460 n = op;
461 break;
4a7319be 462 case 'f':
be0602ec 463 n = f_name(file, NULL);
9baed760
WD
464 if (am_sender && file->dir.root) {
465 pathjoin(buf2, sizeof buf2,
466 file->dir.root, n);
0ee6ca98 467 clean_fname(buf2, 0);
dcbae654 468 if (fmt[1])
0ee6ca98 469 strlcpy(n, buf2, MAXPATHLEN);
dcbae654
WD
470 else
471 n = buf2;
0ee6ca98
WD
472 } else
473 clean_fname(n, 0);
9baed760
WD
474 if (*n == '/')
475 n++;
ab7104da 476 break;
ef74f5d6 477 case 'n':
be0602ec 478 n = f_name(file, NULL);
0ee6ca98
WD
479 if (S_ISDIR(file->mode))
480 strlcat(n, "/", MAXPATHLEN);
ef74f5d6
WD
481 break;
482 case 'L':
afc65a5a 483 if (hlink && *hlink) {
0ee6ca98 484 n = hlink;
126e7aff 485 strcpy(buf2, " => ");
afc65a5a 486 } else if (S_ISLNK(file->mode) && file->u.link) {
0ee6ca98 487 n = file->u.link;
126e7aff
WD
488 strcpy(buf2, " -> ");
489 } else {
ef74f5d6 490 n = "";
126e7aff
WD
491 if (!fmt[1])
492 break;
493 strcpy(buf2, " ");
494 }
495 strlcat(fmt, "s", sizeof fmt);
496 snprintf(buf2 + 4, sizeof buf2 - 4, fmt, n);
497 n = buf2;
ef74f5d6 498 break;
b74b3d53
WD
499 case 'm':
500 n = lp_name(module_id);
501 break;
502 case 't':
503 n = timestring(time(NULL));
504 break;
505 case 'P':
506 n = lp_path(module_id);
507 break;
508 case 'u':
509 n = auth_user;
510 break;
4a7319be 511 case 'b':
1b7c47cb 512 if (am_sender) {
4a7319be 513 b = stats.total_written -
1b7c47cb
AT
514 initial_stats->total_written;
515 } else {
4a7319be 516 b = stats.total_read -
1b7c47cb
AT
517 initial_stats->total_read;
518 }
0455cd93 519 strlcat(fmt, ".0f", sizeof fmt);
ddd74b67 520 snprintf(buf2, sizeof buf2, fmt, (double)b);
1b7c47cb
AT
521 n = buf2;
522 break;
4a7319be 523 case 'c':
1b7c47cb 524 if (!am_sender) {
4a7319be 525 b = stats.total_written -
1b7c47cb
AT
526 initial_stats->total_written;
527 } else {
4a7319be 528 b = stats.total_read -
1b7c47cb
AT
529 initial_stats->total_read;
530 }
0455cd93 531 strlcat(fmt, ".0f", sizeof fmt);
ddd74b67 532 snprintf(buf2, sizeof buf2, fmt, (double)b);
1b7c47cb
AT
533 n = buf2;
534 break;
ef74f5d6 535 case 'i':
19bc826d 536 if (iflags & ITEM_DELETED) {
d5609e96 537 n = "*deleting";
19bc826d
WD
538 break;
539 }
b4bf2b5a 540 n = buf2 + MAXPATHLEN - 32;
fd84673e
WD
541 n[0] = iflags & ITEM_LOCAL_CHANGE
542 ? iflags & ITEM_XNAME_FOLLOWS ? 'h' : 'c'
ca62acc3 543 : !(iflags & ITEM_TRANSFER) ? '.'
c1759b9f 544 : !local_server && *op == 's' ? '<' : '>';
19bc826d
WD
545 n[1] = S_ISDIR(file->mode) ? 'd'
546 : IS_DEVICE(file->mode) ? 'D'
ef74f5d6 547 : S_ISLNK(file->mode) ? 'L' : 'f';
d4e01963
WD
548 n[2] = !(iflags & ITEM_REPORT_CHECKSUM) ? '.' : 'c';
549 n[3] = !(iflags & ITEM_REPORT_SIZE) ? '.' : 's';
550 n[4] = !(iflags & ITEM_REPORT_TIME) ? '.'
ef74f5d6
WD
551 : !preserve_times || IS_DEVICE(file->mode)
552 || S_ISLNK(file->mode) ? 'T' : 't';
d4e01963
WD
553 n[5] = !(iflags & ITEM_REPORT_PERMS) ? '.' : 'p';
554 n[6] = !(iflags & ITEM_REPORT_OWNER) ? '.' : 'o';
555 n[7] = !(iflags & ITEM_REPORT_GROUP) ? '.' : 'g';
ca62acc3 556 n[8] = !(iflags & ITEM_REPORT_XATTRS) ? '.' : 'a';
afc65a5a 557 n[9] = '\0';
ef74f5d6
WD
558
559 if (iflags & (ITEM_IS_NEW|ITEM_MISSING_DATA)) {
560 char ch = iflags & ITEM_IS_NEW ? '+' : '?';
561 int i;
562 for (i = 2; n[i]; i++)
563 n[i] = ch;
6d4ecad1
WD
564 } else if (n[0] == '.' || n[0] == 'h'
565 || (n[0] == 'c' && n[1] == 'f')) {
19bc826d
WD
566 int i;
567 for (i = 2; n[i]; i++) {
568 if (n[i] != '.')
569 break;
570 }
571 if (!n[i]) {
572 for (i = 2; n[i]; i++)
573 n[i] = ' ';
19bc826d 574 }
ef74f5d6
WD
575 }
576 break;
e08bfe12
AT
577 }
578
ddd74b67
WD
579 /* "n" is the string to be inserted in place of this % code. */
580 if (!n)
581 continue;
9baed760
WD
582 if (n != buf2 && fmt[1]) {
583 strlcat(fmt, "s", sizeof fmt);
584 snprintf(buf2, sizeof buf2, fmt, n);
585 n = buf2;
586 }
ef74f5d6 587 len = strlen(n);
e08bfe12 588
e145d51b 589 /* Subtract the length of the escape from the string's size. */
0455cd93 590 total -= p - s + 1;
e145d51b 591
d9c0051f 592 if (len + total >= (size_t)sizeof buf) {
1e7098b5
WD
593 rprintf(FERROR,
594 "buffer overflow expanding %%%c -- exiting\n",
0455cd93 595 p[0]);
65417579 596 exit_cleanup(RERR_MESSAGEIO);
e08bfe12
AT
597 }
598
aa126974 599 /* Shuffle the rest of the string along to make space for n */
0455cd93
WD
600 if (len != (size_t)(p - s + 1))
601 memmove(s + len, p + 1, total - (s - buf) + 1);
ddd74b67 602 total += len;
aa126974 603
ddd74b67 604 /* Insert the contents of string "n", but NOT its null. */
ef74f5d6 605 if (len)
ddd74b67 606 memcpy(s, n, len);
e08bfe12 607
aa126974 608 /* Skip over inserted string; continue looking */
ddd74b67 609 p = s + len;
e08bfe12
AT
610 }
611
d9c0051f 612 rwrite(code, buf, total);
e08bfe12
AT
613}
614
0455cd93
WD
615/* Return 1 if the format escape is in the log-format string (e.g. look for
616 * the 'b' in the "%9b" format escape). */
16f960fe
WD
617int log_format_has(const char *format, char esc)
618{
619 const char *p;
620
621 if (!format)
622 return 0;
623
624 for (p = format; (p = strchr(p, '%')) != NULL; ) {
625 if (*++p == '-')
626 p++;
627 while (isdigit(*(uchar*)p))
628 p++;
629 if (!*p)
630 break;
631 if (*p == esc)
632 return 1;
633 }
634 return 0;
635}
636
afc65a5a
WD
637/* log the transfer of a file */
638void log_item(struct file_struct *file, struct stats *initial_stats,
639 int iflags, char *hlink)
11a5a3c7 640{
afc65a5a 641 char *s_or_r = am_sender ? "send" : "recv";
11a5a3c7 642
11a5a3c7 643 if (lp_transfer_logging(module_id)) {
afc65a5a
WD
644 log_formatted(FLOG, lp_log_format(module_id), s_or_r,
645 file, initial_stats, iflags, hlink);
b6062654 646 } else if (log_format && !am_server) {
be0602ec 647 log_formatted(FNAME, log_format, s_or_r,
afc65a5a 648 file, initial_stats, iflags, hlink);
11a5a3c7
AT
649 }
650}
651
1c3e3679
WD
652void maybe_log_item(struct file_struct *file, int iflags, int itemizing,
653 char *buf)
654{
f2b6fe44 655 int significant_flags = iflags & SIGNIFICANT_ITEM_FLAGS;
6d4ecad1
WD
656 int see_item = itemizing && (significant_flags || *buf
657 || (verbose > 1 && log_format_has_i));
658 int local_change = iflags & ITEM_LOCAL_CHANGE && significant_flags;
1c3e3679
WD
659 if (am_server) {
660 if (am_daemon && !dry_run && see_item)
661 log_item(file, &stats, iflags, buf);
f2b6fe44
WD
662 } else if (see_item || local_change || *buf
663 || (S_ISDIR(file->mode) && significant_flags))
1c3e3679
WD
664 log_item(file, &stats, iflags, buf);
665}
666
19bc826d
WD
667void log_delete(char *fname, int mode)
668{
669 static struct file_struct file;
670 int len = strlen(fname);
19bc826d
WD
671 char *fmt;
672
673 file.mode = mode;
674 file.basename = fname;
675
41b5b5e7
WD
676 if (!verbose && !log_format)
677 ;
678 else if (am_server && protocol_version >= 29 && len < MAXPATHLEN) {
19bc826d
WD
679 if (S_ISDIR(mode))
680 len++; /* directories include trailing null */
681 send_msg(MSG_DELETED, fname, len);
19bc826d 682 } else {
d5609e96 683 fmt = log_format_has_o_or_i ? log_format : "deleting %n";
afc65a5a
WD
684 log_formatted(FCLIENT, fmt, "del.", &file, &stats,
685 ITEM_DELETED, NULL);
19bc826d
WD
686 }
687
41b5b5e7 688 if (!am_daemon || dry_run || !lp_transfer_logging(module_id))
1eec003a
WD
689 return;
690
d5609e96 691 fmt = daemon_log_format_has_o_or_i ? lp_log_format(module_id) : "deleting %n";
afc65a5a 692 log_formatted(FLOG, fmt, "del.", &file, &stats, ITEM_DELETED, NULL);
19bc826d 693}
af642a61
MP
694
695
696/*
697 * Called when the transfer is interrupted for some reason.
698 *
699 * Code is one of the RERR_* codes from errcode.h, or terminating
700 * successfully.
701 */
a9766ef1 702void log_exit(int code, const char *file, int line)
9b73d1c0
AT
703{
704 if (code == 0) {
088aff1a 705 rprintf(FLOG,"sent %.0f bytes received %.0f bytes total size %.0f\n",
9b73d1c0
AT
706 (double)stats.total_written,
707 (double)stats.total_read,
708 (double)stats.total_size);
709 } else {
4a7319be
WD
710 const char *name;
711
712 name = rerr_name(code);
713 if (!name)
714 name = "unexplained error";
af642a61 715
1bca1de6
WD
716 /* VANISHED is not an error, only a warning */
717 if (code == RERR_VANISHED) {
718 rprintf(FINFO, "rsync warning: %s (code %d) at %s(%d)\n",
719 name, code, file, line);
720 } else {
721 rprintf(FERROR, "rsync error: %s (code %d) at %s(%d)\n",
722 name, code, file, line);
723 }
9b73d1c0
AT
724 }
725}