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