log.c 21 KB

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