version 1.1.1.3, 2016/11/01 09:54:32
|
version 1.1.1.4, 2021/03/17 00:32:36
|
Line 3
|
Line 3
|
* |
* |
* Copyright (C) 1998-2001 Andrew Tridgell <tridge@samba.org> |
* Copyright (C) 1998-2001 Andrew Tridgell <tridge@samba.org> |
* Copyright (C) 2000-2001 Martin Pool <mbp@samba.org> |
* Copyright (C) 2000-2001 Martin Pool <mbp@samba.org> |
* Copyright (C) 2003-2015 Wayne Davison | * Copyright (C) 2003-2020 Wayne Davison |
* |
* |
* This program is free software; you can redistribute it and/or modify |
* This program is free software; you can redistribute it and/or modify |
* it under the terms of the GNU General Public License as published by |
* it under the terms of the GNU General Public License as published by |
Line 31 extern int am_generator;
|
Line 31 extern int am_generator;
|
extern int local_server; |
extern int local_server; |
extern int quiet; |
extern int quiet; |
extern int module_id; |
extern int module_id; |
extern int checksum_len; |
|
extern int allow_8bit_chars; |
extern int allow_8bit_chars; |
extern int protocol_version; |
extern int protocol_version; |
extern int always_checksum; |
extern int always_checksum; |
extern int preserve_times; |
extern int preserve_times; |
extern int msgs2stderr; |
extern int msgs2stderr; |
|
extern int xfersum_type; |
|
extern int checksum_type; |
extern int stdout_format_has_i; |
extern int stdout_format_has_i; |
extern int stdout_format_has_o_or_i; |
extern int stdout_format_has_o_or_i; |
extern int logfile_format_has_i; |
extern int logfile_format_has_i; |
Line 74 static int64 initial_data_written;
|
Line 75 static int64 initial_data_written;
|
static int64 initial_data_read; |
static int64 initial_data_read; |
|
|
struct { |
struct { |
int code; | int code; |
char const *name; | char const *name; |
} const rerr_names[] = { |
} const rerr_names[] = { |
{ RERR_SYNTAX , "syntax or usage error" }, |
{ RERR_SYNTAX , "syntax or usage error" }, |
{ RERR_PROTOCOL , "protocol incompatibility" }, |
{ RERR_PROTOCOL , "protocol incompatibility" }, |
Line 91 struct {
|
Line 92 struct {
|
{ RERR_TERMINATED , "sibling process terminated abnormally" }, |
{ RERR_TERMINATED , "sibling process terminated abnormally" }, |
{ RERR_SIGNAL1 , "received SIGUSR1" }, |
{ RERR_SIGNAL1 , "received SIGUSR1" }, |
{ RERR_SIGNAL , "received SIGINT, SIGTERM, or SIGHUP" }, |
{ RERR_SIGNAL , "received SIGINT, SIGTERM, or SIGHUP" }, |
|
{ RERR_WECRASHED , "rsync caught a CRASH-causing signal" }, |
{ RERR_WAITCHILD , "waitpid() failed" }, |
{ RERR_WAITCHILD , "waitpid() failed" }, |
{ RERR_MALLOC , "error allocating core memory buffers" }, |
{ RERR_MALLOC , "error allocating core memory buffers" }, |
{ RERR_PARTIAL , "some files/attrs were not transferred (see previous errors)" }, |
{ RERR_PARTIAL , "some files/attrs were not transferred (see previous errors)" }, |
Line 132 static void logit(int priority, const char *buf)
|
Line 134 static void logit(int priority, const char *buf)
|
|
|
static void syslog_init() |
static void syslog_init() |
{ |
{ |
static int been_here = 0; |
|
int options = LOG_PID; |
int options = LOG_PID; |
|
|
if (been_here) |
|
return; |
|
been_here = 1; |
|
|
|
#ifdef LOG_NDELAY |
#ifdef LOG_NDELAY |
options |= LOG_NDELAY; |
options |= LOG_NDELAY; |
#endif |
#endif |
|
|
#ifdef LOG_DAEMON |
#ifdef LOG_DAEMON |
openlog("rsyncd", options, lp_syslog_facility(module_id)); | openlog(lp_syslog_tag(module_id), options, lp_syslog_facility(module_id)); |
#else |
#else |
openlog("rsyncd", options); | openlog(lp_syslog_tag(module_id), options); |
#endif |
#endif |
|
|
#ifndef LOG_NDELAY |
#ifndef LOG_NDELAY |
Line 166 static void logfile_open(void)
|
Line 163 static void logfile_open(void)
|
rsyserr(FERROR, fopen_errno, |
rsyserr(FERROR, fopen_errno, |
"failed to open log-file %s", logfile_name); |
"failed to open log-file %s", logfile_name); |
rprintf(FINFO, "Ignoring \"log file\" setting.\n"); |
rprintf(FINFO, "Ignoring \"log file\" setting.\n"); |
|
logfile_name = ""; |
} |
} |
} |
} |
|
|
void log_init(int restart) |
void log_init(int restart) |
{ |
{ |
if (log_initialised) { |
if (log_initialised) { |
if (!restart) | if (!restart) /* Note: a restart only happens with am_daemon */ |
return; |
return; |
|
assert(logfile_name); /* all am_daemon procs got at least an empty string */ |
if (strcmp(logfile_name, lp_log_file(module_id)) != 0) { |
if (strcmp(logfile_name, lp_log_file(module_id)) != 0) { |
if (logfile_fp) { |
if (logfile_fp) { |
fclose(logfile_fp); |
fclose(logfile_fp); |
Line 183 void log_init(int restart)
|
Line 182 void log_init(int restart)
|
logfile_name = NULL; |
logfile_name = NULL; |
} else if (*logfile_name) |
} else if (*logfile_name) |
return; /* unchanged, non-empty "log file" names */ |
return; /* unchanged, non-empty "log file" names */ |
else if (lp_syslog_facility(-1) != lp_syslog_facility(module_id)) | else if (lp_syslog_facility(-1) != lp_syslog_facility(module_id) |
| || strcmp(lp_syslog_tag(-1), lp_syslog_tag(module_id)) != 0) |
closelog(); |
closelog(); |
else |
else |
return; /* unchanged syslog settings */ |
return; /* unchanged syslog settings */ |
Line 205 void log_init(int restart)
|
Line 205 void log_init(int restart)
|
syslog_init(); |
syslog_init(); |
} |
} |
|
|
|
/* Note that this close & reopen idiom intentionally ignores syslog logging. */ |
void logfile_close(void) |
void logfile_close(void) |
{ |
{ |
if (logfile_fp) { |
if (logfile_fp) { |
Line 222 void logfile_reopen(void)
|
Line 223 void logfile_reopen(void)
|
} |
} |
} |
} |
|
|
static void filtered_fwrite(FILE *f, const char *buf, int len, int use_isprint) | static void filtered_fwrite(FILE *f, const char *in_buf, int in_len, int use_isprint, char end_char) |
{ |
{ |
const char *s, *end = buf + len; | char outbuf[1024], *ob = outbuf; |
for (s = buf; s < end; s++) { | const char *end = in_buf + in_len; |
if ((s < end - 4 | while (in_buf < end) { |
&& *s == '\\' && s[1] == '#' | if (ob - outbuf >= (int)sizeof outbuf - 10) { |
&& isDigit(s + 2) | if (fwrite(outbuf, ob - outbuf, 1, f) != 1) |
&& isDigit(s + 3) | |
&& isDigit(s + 4)) | |
|| (*s != '\t' | |
&& ((use_isprint && !isPrint(s)) | |
|| *(uchar*)s < ' '))) { | |
if (s != buf && fwrite(buf, s - buf, 1, f) != 1) | |
exit_cleanup(RERR_MESSAGEIO); |
exit_cleanup(RERR_MESSAGEIO); |
fprintf(f, "\\#%03o", *(uchar*)s); | ob = outbuf; |
buf = s + 1; | |
} |
} |
|
if ((in_buf < end - 4 && *in_buf == '\\' && in_buf[1] == '#' |
|
&& isDigit(in_buf + 2) && isDigit(in_buf + 3) && isDigit(in_buf + 4)) |
|
|| (*in_buf != '\t' && ((use_isprint && !isPrint(in_buf)) || *(uchar*)in_buf < ' '))) |
|
ob += snprintf(ob, 6, "\\#%03o", *(uchar*)in_buf++); |
|
else |
|
*ob++ = *in_buf++; |
} |
} |
if (buf != end && fwrite(buf, end - buf, 1, f) != 1) | if (end_char) /* The "- 10" above means that there is always room for one more char here. */ |
| *ob++ = end_char; |
| if (ob != outbuf && fwrite(outbuf, ob - outbuf, 1, f) != 1) |
exit_cleanup(RERR_MESSAGEIO); |
exit_cleanup(RERR_MESSAGEIO); |
} |
} |
|
|
Line 249 static void filtered_fwrite(FILE *f, const char *buf,
|
Line 251 static void filtered_fwrite(FILE *f, const char *buf,
|
* can happen with certain fatal conditions. */ |
* can happen with certain fatal conditions. */ |
void rwrite(enum logcode code, const char *buf, int len, int is_utf8) |
void rwrite(enum logcode code, const char *buf, int len, int is_utf8) |
{ |
{ |
int trailing_CR_or_NL; | char trailing_CR_or_NL; |
FILE *f = msgs2stderr ? stderr : stdout; | FILE *f = msgs2stderr == 1 ? stderr : stdout; |
#ifdef ICONV_OPTION |
#ifdef ICONV_OPTION |
iconv_t ic = is_utf8 && ic_recv != (iconv_t)-1 ? ic_recv : ic_chck; |
iconv_t ic = is_utf8 && ic_recv != (iconv_t)-1 ? ic_recv : ic_chck; |
#else |
#else |
Line 262 void rwrite(enum logcode code, const char *buf, int le
|
Line 264 void rwrite(enum logcode code, const char *buf, int le
|
if (len < 0) |
if (len < 0) |
exit_cleanup(RERR_MESSAGEIO); |
exit_cleanup(RERR_MESSAGEIO); |
|
|
if (msgs2stderr) { | if (msgs2stderr == 1) { |
if (!am_daemon) { | /* A normal daemon can get msgs2stderr set if the socket is busted, so we |
if (code == FLOG) | * change the message destination into an FLOG message in order to try to |
return; | * get some info about an abnormal-exit into the log file. An rsh daemon |
goto output_msg; | * can have this set via user request, so we'll leave the code alone so |
} | * that the msg gets logged and then sent to stderr after that. */ |
if (code == FCLIENT) | if (am_daemon > 0 && code != FCLIENT) |
return; | code = FLOG; |
code = FLOG; | |
} else if (send_msgs_to_gen) { |
} else if (send_msgs_to_gen) { |
assert(!is_utf8); |
assert(!is_utf8); |
/* Pass the message to our sibling in native charset. */ |
/* Pass the message to our sibling in native charset. */ |
Line 306 void rwrite(enum logcode code, const char *buf, int le
|
Line 307 void rwrite(enum logcode code, const char *buf, int le
|
} else if (code == FLOG) |
} else if (code == FLOG) |
return; |
return; |
|
|
if (quiet && code == FINFO) | switch (code) { |
return; | case FERROR_XFER: |
| got_xfer_error = 1; |
| /* FALL THROUGH */ |
| case FERROR: |
| case FWARNING: |
| f = stderr; |
| break; |
| case FINFO: |
| if (quiet) |
| return; |
| break; |
| /*case FLOG:*/ |
| /*case FCLIENT:*/ |
| /*case FERROR_UTF8:*/ |
| /*case FERROR_SOCKET:*/ |
| default: |
| fprintf(stderr, "Bad logcode in rwrite(): %d [%s]\n", (int)code, who_am_i()); |
| exit_cleanup(RERR_MESSAGEIO); |
| } |
|
|
if (am_server) { | if (am_server && msgs2stderr != 1 && (msgs2stderr != 2 || f != stderr)) { |
enum msgcode msg = (enum msgcode)code; |
enum msgcode msg = (enum msgcode)code; |
if (protocol_version < 30) { |
if (protocol_version < 30) { |
if (msg == MSG_ERROR) |
if (msg == MSG_ERROR) |
Line 320 void rwrite(enum logcode code, const char *buf, int le
|
Line 339 void rwrite(enum logcode code, const char *buf, int le
|
/* Pass the message to the non-server side. */ |
/* Pass the message to the non-server side. */ |
if (send_msg(msg, buf, len, !is_utf8)) |
if (send_msg(msg, buf, len, !is_utf8)) |
return; |
return; |
if (am_daemon) { | if (am_daemon > 0) { |
/* TODO: can we send the error to the user somehow? */ |
/* TODO: can we send the error to the user somehow? */ |
return; |
return; |
} |
} |
f = stderr; |
f = stderr; |
} |
} |
|
|
output_msg: |
|
switch (code) { |
|
case FERROR_XFER: |
|
got_xfer_error = 1; |
|
/* FALL THROUGH */ |
|
case FERROR: |
|
case FERROR_UTF8: |
|
case FERROR_SOCKET: |
|
case FWARNING: |
|
f = stderr; |
|
break; |
|
case FLOG: |
|
case FINFO: |
|
case FCLIENT: |
|
break; |
|
default: |
|
fprintf(stderr, "Unknown logcode in rwrite(): %d [%s]\n", (int)code, who_am_i()); |
|
exit_cleanup(RERR_MESSAGEIO); |
|
} |
|
|
|
if (output_needs_newline) { |
if (output_needs_newline) { |
fputc('\n', f); |
fputc('\n', f); |
output_needs_newline = 0; |
output_needs_newline = 0; |
} |
} |
|
|
trailing_CR_or_NL = len && (buf[len-1] == '\n' || buf[len-1] == '\r') | trailing_CR_or_NL = len && (buf[len-1] == '\n' || buf[len-1] == '\r') ? buf[--len] : '\0'; |
? buf[--len] : 0; | |
|
|
if (len && buf[0] == '\r') { |
if (len && buf[0] == '\r') { |
fputc('\r', f); |
fputc('\r', f); |
Line 374 output_msg:
|
Line 372 output_msg:
|
iconvbufs(ic, &inbuf, &outbuf, inbuf.pos ? 0 : ICB_INIT); |
iconvbufs(ic, &inbuf, &outbuf, inbuf.pos ? 0 : ICB_INIT); |
ierrno = errno; |
ierrno = errno; |
if (outbuf.len) { |
if (outbuf.len) { |
filtered_fwrite(f, convbuf, outbuf.len, 0); | char trailing = inbuf.len ? '\0' : trailing_CR_or_NL; |
| filtered_fwrite(f, convbuf, outbuf.len, 0, trailing); |
| if (trailing) { |
| trailing_CR_or_NL = '\0'; |
| fflush(f); |
| } |
outbuf.len = 0; |
outbuf.len = 0; |
} |
} |
if (!ierrno || ierrno == E2BIG) | /* Log one byte of illegal/incomplete sequence and continue with |
continue; | * the next character. Check that the buffer is non-empty for the |
fprintf(f, "\\#%03o", CVAL(inbuf.buf, inbuf.pos++)); | * sake of robustness. */ |
inbuf.len--; | if ((ierrno == EILSEQ || ierrno == EINVAL) && inbuf.len) { |
| fprintf(f, "\\#%03o", CVAL(inbuf.buf, inbuf.pos++)); |
| inbuf.len--; |
| } |
} |
} |
|
|
|
if (trailing_CR_or_NL) { |
|
fputc(trailing_CR_or_NL, f); |
|
fflush(f); |
|
} |
} else |
} else |
#endif |
#endif |
filtered_fwrite(f, buf, len, !allow_8bit_chars); | { |
| filtered_fwrite(f, buf, len, !allow_8bit_chars, trailing_CR_or_NL); |
if (trailing_CR_or_NL) { | if (trailing_CR_or_NL) |
fputc(trailing_CR_or_NL, f); | fflush(f); |
fflush(f); | |
} |
} |
} |
} |
|
|
Line 447 void rsyserr(enum logcode code, int errcode, const cha
|
Line 457 void rsyserr(enum logcode code, int errcode, const cha
|
char buf[BIGPATHBUFLEN]; |
char buf[BIGPATHBUFLEN]; |
size_t len; |
size_t len; |
|
|
strlcpy(buf, RSYNC_NAME ": ", sizeof buf); | len = snprintf(buf, sizeof buf, RSYNC_NAME ": [%s] ", who_am_i()); |
len = (sizeof RSYNC_NAME ": ") - 1; | |
|
|
va_start(ap, format); |
va_start(ap, format); |
len += vsnprintf(buf + len, sizeof buf - len, format, ap); |
len += vsnprintf(buf + len, sizeof buf - len, format, ap); |
Line 669 static void log_formatted(enum logcode code, const cha
|
Line 678 static void log_formatted(enum logcode code, const cha
|
n = buf2; |
n = buf2; |
break; |
break; |
case 'C': |
case 'C': |
if (protocol_version >= 30 | n = NULL; |
&& (iflags & ITEM_TRANSFER | if (S_ISREG(file->mode)) { |
|| (always_checksum && S_ISREG(file->mode)))) { | if (always_checksum) |
const char *sum = iflags & ITEM_TRANSFER | n = sum_as_hex(checksum_type, F_SUM(file), 1); |
? sender_file_sum : F_SUM(file); | else if (iflags & ITEM_TRANSFER) |
n = sum_as_hex(sum); | n = sum_as_hex(xfersum_type, sender_file_sum, 0); |
} else { | } |
memset(buf2, ' ', checksum_len*2); | if (!n) { |
buf2[checksum_len*2] = '\0'; | int sum_len = csum_len_for_type(always_checksum ? checksum_type : xfersum_type, |
| always_checksum); |
| memset(buf2, ' ', sum_len*2); |
| buf2[sum_len*2] = '\0'; |
n = buf2; |
n = buf2; |
} |
} |
break; |
break; |
Line 688 static void log_formatted(enum logcode code, const cha
|
Line 700 static void log_formatted(enum logcode code, const cha
|
} |
} |
n = c = buf2 + MAXPATHLEN - 32; |
n = c = buf2 + MAXPATHLEN - 32; |
c[0] = iflags & ITEM_LOCAL_CHANGE |
c[0] = iflags & ITEM_LOCAL_CHANGE |
? iflags & ITEM_XNAME_FOLLOWS ? 'h' : 'c' | ? iflags & ITEM_XNAME_FOLLOWS ? 'h' : 'c' |
: !(iflags & ITEM_TRANSFER) ? '.' |
: !(iflags & ITEM_TRANSFER) ? '.' |
: !local_server && *op == 's' ? '<' : '>'; |
: !local_server && *op == 's' ? '<' : '>'; |
if (S_ISLNK(file->mode)) { |
if (S_ISLNK(file->mode)) { |
Line 709 static void log_formatted(enum logcode code, const cha
|
Line 721 static void log_formatted(enum logcode code, const cha
|
c[5] = !(iflags & ITEM_REPORT_PERMS) ? '.' : 'p'; |
c[5] = !(iflags & ITEM_REPORT_PERMS) ? '.' : 'p'; |
c[6] = !(iflags & ITEM_REPORT_OWNER) ? '.' : 'o'; |
c[6] = !(iflags & ITEM_REPORT_OWNER) ? '.' : 'o'; |
c[7] = !(iflags & ITEM_REPORT_GROUP) ? '.' : 'g'; |
c[7] = !(iflags & ITEM_REPORT_GROUP) ? '.' : 'g'; |
c[8] = !(iflags & ITEM_REPORT_ATIME) ? '.' : 'u'; | c[8] = !(iflags & (ITEM_REPORT_ATIME|ITEM_REPORT_CRTIME)) ? '.' |
| : BITS_SET(iflags, ITEM_REPORT_ATIME|ITEM_REPORT_CRTIME) ? 'b' |
| : iflags & ITEM_REPORT_ATIME ? 'u' : 'n'; |
c[9] = !(iflags & ITEM_REPORT_ACL) ? '.' : 'a'; |
c[9] = !(iflags & ITEM_REPORT_ACL) ? '.' : 'a'; |
c[10] = !(iflags & ITEM_REPORT_XATTR) ? '.' : 'x'; |
c[10] = !(iflags & ITEM_REPORT_XATTR) ? '.' : 'x'; |
c[11] = '\0'; | c[11] = !(iflags & ITEM_REPORT_FFLAGS) ? '.' : 'f'; |
| c[12] = '\0'; |
|
|
if (iflags & (ITEM_IS_NEW|ITEM_MISSING_DATA)) { |
if (iflags & (ITEM_IS_NEW|ITEM_MISSING_DATA)) { |
char ch = iflags & ITEM_IS_NEW ? '+' : '?'; |
char ch = iflags & ITEM_IS_NEW ? '+' : '?'; |
Line 806 void log_item(enum logcode code, struct file_struct *f
|
Line 821 void log_item(enum logcode code, struct file_struct *f
|
log_formatted(FLOG, logfile_format, s_or_r, file, NULL, iflags, hlink); |
log_formatted(FLOG, logfile_format, s_or_r, file, NULL, iflags, hlink); |
} |
} |
|
|
void maybe_log_item(struct file_struct *file, int iflags, int itemizing, | void maybe_log_item(struct file_struct *file, int iflags, int itemizing, const char *buf) |
const char *buf) | |
{ |
{ |
int significant_flags = iflags & SIGNIFICANT_ITEM_FLAGS; |
int significant_flags = iflags & SIGNIFICANT_ITEM_FLAGS; |
int see_item = itemizing && (significant_flags || *buf |
int see_item = itemizing && (significant_flags || *buf |
Line 861 void log_delete(const char *fname, int mode)
|
Line 875 void log_delete(const char *fname, int mode)
|
*/ |
*/ |
void log_exit(int code, const char *file, int line) |
void log_exit(int code, const char *file, int line) |
{ |
{ |
if (code == 0) { | /* The receiving side's stats are split between 2 procs until the |
| * end of the run, so only the sender can output non-final info. */ |
| if (code == 0 || am_sender) { |
rprintf(FLOG,"sent %s bytes received %s bytes total size %s\n", |
rprintf(FLOG,"sent %s bytes received %s bytes total size %s\n", |
big_num(stats.total_written), |
big_num(stats.total_written), |
big_num(stats.total_read), |
big_num(stats.total_read), |
big_num(stats.total_size)); |
big_num(stats.total_size)); |
} else if (am_server != 2) { | } |
| if (code != 0 && am_server != 2) { |
const char *name; |
const char *name; |
|
|
name = rerr_name(code); |
name = rerr_name(code); |
Line 876 void log_exit(int code, const char *file, int line)
|
Line 893 void log_exit(int code, const char *file, int line)
|
/* VANISHED is not an error, only a warning */ |
/* VANISHED is not an error, only a warning */ |
if (code == RERR_VANISHED) { |
if (code == RERR_VANISHED) { |
rprintf(FWARNING, "rsync warning: %s (code %d) at %s(%d) [%s=%s]\n", |
rprintf(FWARNING, "rsync warning: %s (code %d) at %s(%d) [%s=%s]\n", |
name, code, file, line, who_am_i(), RSYNC_VERSION); | name, code, src_file(file), line, who_am_i(), rsync_version()); |
} else { |
} else { |
rprintf(FERROR, "rsync error: %s (code %d) at %s(%d) [%s=%s]\n", |
rprintf(FERROR, "rsync error: %s (code %d) at %s(%d) [%s=%s]\n", |
name, code, file, line, who_am_i(), RSYNC_VERSION); | name, code, src_file(file), line, who_am_i(), rsync_version()); |
} |
} |
} |
} |
} |
} |