-/* -*- c-file-style: "linux"; -*-
-
- Copyright (C) 1998-2001 by Andrew Tridgell <tridge@samba.org>
- Copyright (C) 2000-2001 by Martin Pool <mbp@samba.org>
-
- 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
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
/*
- Logging and utility functions.
- tridge, May 1998
+ * Logging and utility functions.
+ *
+ * Copyright (C) 1998-2001 Andrew Tridgell <tridge@samba.org>
+ * Copyright (C) 2000-2001 Martin Pool <mbp@samba.org>
+ * Copyright (C) 2003, 2004, 2005, 2006 Wayne Davison
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
+ */
- Mapping to human-readable messages added by Martin Pool
- <mbp@samba.org>, Oct 2000.
- */
#include "rsync.h"
+#if defined HAVE_ICONV_OPEN && defined HAVE_ICONV_H
+#include <iconv.h>
+#endif
extern int verbose;
extern int dry_run;
extern int quiet;
extern int module_id;
extern int msg_fd_out;
+extern int allow_8bit_chars;
extern int protocol_version;
extern int preserve_times;
extern int log_format_has_i;
extern int log_format_has_o_or_i;
extern int daemon_log_format_has_o_or_i;
+extern mode_t orig_umask;
extern char *auth_user;
extern char *log_format;
+#if defined HAVE_ICONV_OPEN && defined HAVE_ICONV_H
+extern iconv_t ic_chck;
+#endif
static int log_initialised;
static int logfile_was_closed;
};
-
/*
* Map from rsync error code to name, or return NULL.
*/
return NULL;
}
-
static void logit(int priority, char *buf)
{
if (logfile_was_closed)
static void logfile_open(void)
{
- extern int orig_umask;
- int old_umask = umask(022 | orig_umask);
+ mode_t old_umask = umask(022 | orig_umask);
logfile = fopen(logfname, "a");
umask(old_umask);
if (!logfile) {
}
}
+static void filtered_fwrite(FILE *f, const char *buf, int len, int use_isprint)
+{
+ const char *s, *end = buf + len;
+ for (s = buf; s < end; s++) {
+ if ((s < end - 4
+ && *s == '\\' && s[1] == '#'
+ && isdigit(*(uchar*)(s+2))
+ && isdigit(*(uchar*)(s+3))
+ && isdigit(*(uchar*)(s+4)))
+ || (*s != '\t'
+ && ((use_isprint && !isprint(*(uchar*)s))
+ || *(uchar*)s < ' '))) {
+ if (s != buf && fwrite(buf, s - buf, 1, f) != 1)
+ exit_cleanup(RERR_MESSAGEIO);
+ fprintf(f, "\\#%03o", *(uchar*)s);
+ buf = s + 1;
+ }
+ }
+ if (buf != end && fwrite(buf, end - buf, 1, f) != 1)
+ exit_cleanup(RERR_MESSAGEIO);
+}
+
/* this is the underlying (unformatted) rsync debugging function. Call
- * it with FINFO, FERROR or FLOG */
+ * it with FINFO, FERROR or FLOG. Note: recursion can happen with
+ * certain fatal conditions. */
void rwrite(enum logcode code, char *buf, int len)
{
+ int trailing_CR_or_NL;
FILE *f = NULL;
- /* recursion can happen with certain fatal conditions */
-
- if (quiet && code == FINFO)
- return;
if (len < 0)
exit_cleanup(RERR_MESSAGEIO);
- buf[len] = 0;
+ if (quiet && code == FINFO)
+ return;
if (am_server && msg_fd_out >= 0) {
/* Pass the message to our sibling. */
return;
}
+ if (code == FSOCKERR) /* This gets simplified for a non-sibling. */
+ code = FERROR;
+
if (code == FCLIENT)
code = FINFO;
else if (am_daemon) {
}
}
- if (code == FERROR) {
+ switch (code) {
+ case FERROR:
log_got_error = 1;
f = stderr;
- }
-
- if (code == FINFO)
+ goto pre_scan;
+ case FINFO:
f = am_server ? stderr : stdout;
-
- if (!f)
+ pre_scan:
+ while (len > 1 && *buf == '\n') {
+ fputc(*buf, f);
+ buf++;
+ len--;
+ }
+ break;
+ case FNAME:
+ f = am_server ? stderr : stdout;
+ break;
+ default:
exit_cleanup(RERR_MESSAGEIO);
+ }
- if (fwrite(buf, len, 1, f) != 1)
- exit_cleanup(RERR_MESSAGEIO);
+ trailing_CR_or_NL = len && (buf[len-1] == '\n' || buf[len-1] == '\r')
+ ? buf[--len] : 0;
+
+#if defined HAVE_ICONV_OPEN && defined HAVE_ICONV_H
+ if (ic_chck != (iconv_t)-1) {
+ char convbuf[1024];
+ char *in_buf = buf, *out_buf = convbuf;
+ size_t in_cnt = len, out_cnt = sizeof convbuf - 1;
+
+ iconv(ic_chck, NULL, 0, NULL, 0);
+ while (iconv(ic_chck, &in_buf,&in_cnt,
+ &out_buf,&out_cnt) == (size_t)-1) {
+ if (out_buf != convbuf) {
+ filtered_fwrite(f, convbuf, out_buf - convbuf, 0);
+ out_buf = convbuf;
+ out_cnt = sizeof convbuf - 1;
+ }
+ if (errno == E2BIG)
+ continue;
+ fprintf(f, "\\#%03o", *(uchar*)in_buf++);
+ in_cnt--;
+ }
+ if (out_buf != convbuf)
+ filtered_fwrite(f, convbuf, out_buf - convbuf, 0);
+ } else
+#endif
+ filtered_fwrite(f, buf, len, !allow_8bit_chars);
- if (buf[len-1] == '\r' || buf[len-1] == '\n')
+ if (trailing_CR_or_NL) {
+ fputc(trailing_CR_or_NL, f);
fflush(f);
+ }
}
-
/* This is the rsync debugging function. Call it with FINFO, FERROR or
* FLOG. */
void rprintf(enum logcode code, const char *format, ...)
rwrite(code, buf, len);
}
-
/* This is like rprintf, but it also tries to print some
* representation of the error code. Normally errcode = errno.
*
rwrite(code, buf, len);
}
-
-
void rflush(enum logcode code)
{
FILE *f = NULL;
fflush(f);
}
-
-
/* a generic logging routine for send/recv, with parameter
* substitiution */
static void log_formatted(enum logcode code, char *format, char *op,
(double)file->length);
n = buf2;
break;
+ case 'U':
+ strlcat(fmt, "ld", sizeof fmt);
+ snprintf(buf2, sizeof buf2, fmt,
+ (long)file->uid);
+ n = buf2;
+ break;
+ case 'G':
+ if (file->gid == GID_NONE)
+ n = "DEFAULT";
+ else {
+ strlcat(fmt, "ld", sizeof fmt);
+ snprintf(buf2, sizeof buf2, fmt,
+ (long)file->gid);
+ n = buf2;
+ }
+ break;
case 'p':
strlcat(fmt, "ld", sizeof fmt);
snprintf(buf2, sizeof buf2, fmt,
(long)getpid());
n = buf2;
break;
+ case 'M':
+ n = timestring(file->modtime);
+ {
+ char *cp = n;
+ while ((cp = strchr(cp, ' ')) != NULL)
+ *cp = '-';
+ }
+ break;
+ case 'B':
+ n = buf2 + MAXPATHLEN - PERMSTRING_SIZE;
+ permstring(n - 1, file->mode); /* skip the type char */
+ break;
case 'o':
n = op;
break;
case 'f':
- n = safe_fname(f_name(file));
+ n = f_name(file, NULL);
if (am_sender && file->dir.root) {
pathjoin(buf2, sizeof buf2,
file->dir.root, n);
- /* The buffer from safe_fname() has more
- * room than MAXPATHLEN, so this is safe. */
+ clean_fname(buf2, 0);
if (fmt[1])
- strcpy(n, buf2);
+ strlcpy(n, buf2, MAXPATHLEN);
else
n = buf2;
- }
- clean_fname(n, 0);
+ } else
+ clean_fname(n, 0);
if (*n == '/')
n++;
break;
case 'n':
- n = safe_fname(f_name(file));
- if (S_ISDIR(file->mode)) {
- /* The buffer from safe_fname() has more
- * room than MAXPATHLEN, so this is safe. */
- strcat(n, "/");
- }
+ n = f_name(file, NULL);
+ if (S_ISDIR(file->mode))
+ strlcat(n, "/", MAXPATHLEN);
break;
case 'L':
if (hlink && *hlink) {
- n = safe_fname(hlink);
+ n = hlink;
strcpy(buf2, " => ");
} else if (S_ISLNK(file->mode) && file->u.link) {
- n = safe_fname(file->u.link);
+ n = file->u.link;
strcpy(buf2, " -> ");
} else {
n = "";
: !(iflags & ITEM_TRANSFER) ? '.'
: !local_server && *op == 's' ? '<' : '>';
n[1] = S_ISDIR(file->mode) ? 'd'
+ : IS_SPECIAL(file->mode) ? 'S'
: IS_DEVICE(file->mode) ? 'D'
: S_ISLNK(file->mode) ? 'L' : 'f';
n[2] = !(iflags & ITEM_REPORT_CHECKSUM) ? '.' : 'c';
n[3] = !(iflags & ITEM_REPORT_SIZE) ? '.' : 's';
n[4] = !(iflags & ITEM_REPORT_TIME) ? '.'
- : !preserve_times || IS_DEVICE(file->mode)
- || S_ISLNK(file->mode) ? 'T' : 't';
+ : !preserve_times || S_ISLNK(file->mode) ? 'T' : 't';
n[5] = !(iflags & ITEM_REPORT_PERMS) ? '.' : 'p';
n[6] = !(iflags & ITEM_REPORT_OWNER) ? '.' : 'o';
n[7] = !(iflags & ITEM_REPORT_GROUP) ? '.' : 'g';
- n[8] = !(iflags & ITEM_REPORT_XATTRS) ? '.' : 'a';
+ n[8] = '.';
n[9] = '\0';
if (iflags & (ITEM_IS_NEW|ITEM_MISSING_DATA)) {
log_formatted(FLOG, lp_log_format(module_id), s_or_r,
file, initial_stats, iflags, hlink);
} else if (log_format && !am_server) {
- log_formatted(FINFO, log_format, s_or_r,
+ log_formatted(FNAME, log_format, s_or_r,
file, initial_stats, iflags, hlink);
}
}
{
int significant_flags = iflags & SIGNIFICANT_ITEM_FLAGS;
int see_item = itemizing && (significant_flags || *buf
- || (verbose > 1 && log_format_has_i));
+ || log_format_has_i > 1 || (verbose > 1 && log_format_has_i));
int local_change = iflags & ITEM_LOCAL_CHANGE && significant_flags;
if (am_server) {
if (am_daemon && !dry_run && see_item)
log_formatted(FLOG, fmt, "del.", &file, &stats, ITEM_DELETED, NULL);
}
-
/*
* Called when the transfer is interrupted for some reason.
*
/* VANISHED is not an error, only a warning */
if (code == RERR_VANISHED) {
- rprintf(FINFO, "rsync warning: %s (code %d) at %s(%d)\n",
- name, code, file, line);
+ rprintf(FINFO, "rsync warning: %s (code %d) at %s(%d) [%s=%s]\n",
+ name, code, file, line, who_am_i(), RSYNC_VERSION);
} else {
- rprintf(FERROR, "rsync error: %s (code %d) at %s(%d)\n",
- name, code, file, line);
+ rprintf(FERROR, "rsync error: %s (code %d) at %s(%d) [%s=%s]\n",
+ name, code, file, line, who_am_i(), RSYNC_VERSION);
}
}
}