Changed RERR_CRASH to RERR_CRASHED.
[rsync/rsync.git] / log.c
diff --git a/log.c b/log.c
index 9278c42..b03fc08 100644 (file)
--- a/log.c
+++ b/log.c
@@ -44,6 +44,7 @@ extern char *auth_user;
 extern char *log_format;
 
 static int log_initialised;
+static int logfile_was_closed;
 static char *logfname;
 static FILE *logfile;
 struct stats stats;
@@ -59,12 +60,13 @@ struct {
        { RERR_FILESELECT , "errors selecting input/output files, dirs" },
        { RERR_UNSUPPORTED, "requested action not supported" },
        { RERR_STARTCLIENT, "error starting client-server protocol" },
-       { RERR_LOG_FAILURE, "daemon unable to append to log-file" },
        { RERR_SOCKETIO   , "error in socket IO" },
        { RERR_FILEIO     , "error in file IO" },
        { RERR_STREAMIO   , "error in rsync protocol data stream" },
        { RERR_MESSAGEIO  , "errors with program diagnostics" },
        { RERR_IPC        , "error in IPC code" },
+       { RERR_CRASHED    , "sibling process crashed" },
+       { RERR_TERMINATED , "sibling process terminated abnormally" },
        { RERR_SIGNAL     , "received SIGUSR1 or SIGINT" },
        { RERR_WAITCHILD  , "some error returned by waitpid()" },
        { RERR_MALLOC     , "error allocating core memory buffers" },
@@ -97,9 +99,9 @@ static char const *rerr_name(int code)
 
 static void logit(int priority, char *buf)
 {
-       if (logfname) {
-               if (!logfile)
-                       log_open();
+       if (logfile_was_closed)
+               logfile_reopen();
+       if (logfile) {
                fprintf(logfile,"%s [%d] %s",
                        timestring(time(NULL)), (int)getpid(), buf);
                fflush(logfile);
@@ -108,30 +110,14 @@ static void logit(int priority, char *buf)
        }
 }
 
-void log_init(void)
+static void syslog_init()
 {
+       static int been_here = 0;
        int options = LOG_PID;
-       time_t t;
 
-       if (log_initialised)
+       if (been_here)
                return;
-       log_initialised = 1;
-
-       /* this looks pointless, but it is needed in order for the
-        * C library on some systems to fetch the timezone info
-        * before the chroot */
-       t = time(NULL);
-       localtime(&t);
-
-       /* optionally use a log file instead of syslog */
-       logfname = lp_log_file();
-       if (logfname) {
-               if (*logfname) {
-                       log_open();
-                       return;
-               }
-               logfname = NULL;
-       }
+       been_here = 1;
 
 #ifdef LOG_NDELAY
        options |= LOG_NDELAY;
@@ -144,33 +130,65 @@ void log_init(void)
 #endif
 
 #ifndef LOG_NDELAY
-       logit(LOG_INFO,"rsyncd started\n");
+       logit(LOG_INFO, "rsyncd started\n");
 #endif
 }
 
-void log_open(void)
+static void logfile_open(void)
 {
-       if (logfname && !logfile) {
-               extern int orig_umask;
-               int old_umask = umask(022 | orig_umask);
-               logfile = fopen(logfname, "a");
-               umask(old_umask);
-               if (!logfile) {
-                       am_daemon = 0; /* avoid trying to log again */
-                       rsyserr(FERROR, errno, "fopen() of log-file failed");
-                       exit_cleanup(RERR_LOG_FAILURE);
-               }
+       extern int orig_umask;
+       int old_umask = umask(022 | orig_umask);
+       logfile = fopen(logfname, "a");
+       umask(old_umask);
+       if (!logfile) {
+               int fopen_errno = errno;
+               /* Rsync falls back to using syslog on failure. */
+               syslog_init();
+               rsyserr(FERROR, fopen_errno,
+                       "failed to open log-file %s", logfname);
+               rprintf(FINFO, "Ignoring \"log file\" setting.\n");
        }
 }
 
-void log_close(void)
+void log_init(void)
+{
+       time_t t;
+
+       if (log_initialised)
+               return;
+       log_initialised = 1;
+
+       /* this looks pointless, but it is needed in order for the
+        * C library on some systems to fetch the timezone info
+        * before the chroot */
+       t = time(NULL);
+       localtime(&t);
+
+       /* optionally use a log file instead of syslog */
+       logfname = lp_log_file();
+       if (logfname && *logfname)
+               logfile_open();
+       else
+               syslog_init();
+}
+
+void logfile_close(void)
 {
        if (logfile) {
+               logfile_was_closed = 1;
                fclose(logfile);
                logfile = NULL;
        }
 }
 
+void logfile_reopen(void)
+{
+       if (logfile_was_closed) {
+               logfile_was_closed = 0;
+               logfile_open();
+       }
+}
+
 /* this is the underlying (unformatted) rsync debugging function. Call
  * it with FINFO, FERROR or FLOG */
 void rwrite(enum logcode code, char *buf, int len)
@@ -240,7 +258,7 @@ void rwrite(enum logcode code, char *buf, int len)
        if (buf[len-1] == '\r' || buf[len-1] == '\n')
                fflush(f);
 }
-               
+
 
 /* This is the rsync debugging function. Call it with FINFO, FERROR or
  * FLOG. */
@@ -320,7 +338,7 @@ void rsyserr(enum logcode code, int errcode, const char *format, ...)
 void rflush(enum logcode code)
 {
        FILE *f = NULL;
-       
+
        if (am_daemon) {
                return;
        }
@@ -369,7 +387,7 @@ static void log_formatted(enum logcode code, char *format, char *op,
        }
        buf[total++] = '\n';
        buf[total] = '\0';
-       
+
        for (p = buf; (p = strchr(p, '%')) != NULL; ) {
                s = p++;
                n = fmt + 1;
@@ -382,7 +400,7 @@ static void log_formatted(enum logcode code, char *format, char *op,
                *n = '\0';
                n = NULL;
 
-               switch (*p++) {
+               switch (*p) {
                case 'h': if (am_daemon) n = client_name(0); break;
                case 'a': if (am_daemon) n = client_addr(0); break;
                case 'l':
@@ -444,7 +462,6 @@ static void log_formatted(enum logcode code, char *format, char *op,
                case 'P': n = lp_path(module_id); break;
                case 'u': n = auth_user; break;
                case 'b':
-                       strlcat(fmt, ".0f", sizeof fmt);
                        if (am_sender) {
                                b = stats.total_written -
                                        initial_stats->total_written;
@@ -452,11 +469,11 @@ static void log_formatted(enum logcode code, char *format, char *op,
                                b = stats.total_read -
                                        initial_stats->total_read;
                        }
+                       strlcat(fmt, ".0f", sizeof fmt);
                        snprintf(buf2, sizeof buf2, fmt, (double)b);
                        n = buf2;
                        break;
                case 'c':
-                       strlcat(fmt, ".0f", sizeof fmt);
                        if (!am_sender) {
                                b = stats.total_written -
                                        initial_stats->total_written;
@@ -464,6 +481,7 @@ static void log_formatted(enum logcode code, char *format, char *op,
                                b = stats.total_read -
                                        initial_stats->total_read;
                        }
+                       strlcat(fmt, ".0f", sizeof fmt);
                        snprintf(buf2, sizeof buf2, fmt, (double)b);
                        n = buf2;
                        break;
@@ -496,7 +514,7 @@ static void log_formatted(enum logcode code, char *format, char *op,
                                int i;
                                for (i = 2; n[i]; i++)
                                        n[i] = ch;
-                       } else if (!(iflags & (ITEM_TRANSFER|ITEM_LOCAL_CHANGE))) {
+                       } else if (n[0] == '.' || n[0] == 'h') {
                                int i;
                                for (i = 2; n[i]; i++) {
                                        if (n[i] != '.')
@@ -521,18 +539,18 @@ static void log_formatted(enum logcode code, char *format, char *op,
                len = strlen(n);
 
                /* Subtract the length of the escape from the string's size. */
-               total -= p - s;
+               total -= p - s + 1;
 
                if (len + total >= (size_t)sizeof buf) {
                        rprintf(FERROR,
                                "buffer overflow expanding %%%c -- exiting\n",
-                               p[-1]);
+                               p[0]);
                        exit_cleanup(RERR_MESSAGEIO);
                }
 
                /* Shuffle the rest of the string along to make space for n */
-               if (len != (size_t)(p - s))
-                       memmove(s + len, p, total - (s - buf) + 1);
+               if (len != (size_t)(p - s + 1))
+                       memmove(s + len, p + 1, total - (s - buf) + 1);
                total += len;
 
                /* Insert the contents of string "n", but NOT its null. */
@@ -546,6 +564,8 @@ static void log_formatted(enum logcode code, char *format, char *op,
        rwrite(code, buf, total);
 }
 
+/* Return 1 if the format escape is in the log-format string (e.g. look for
+ * the 'b' in the "%9b" format escape). */
 int log_format_has(const char *format, char esc)
 {
        const char *p;
@@ -584,12 +604,15 @@ void log_item(struct file_struct *file, struct stats *initial_stats,
 void maybe_log_item(struct file_struct *file, int iflags, int itemizing,
                    char *buf)
 {
-       int see_item = itemizing && (iflags || verbose > 1);
+       int significant_flags = iflags & SIGNIFICANT_ITEM_FLAGS;
+       int see_item = itemizing && (significant_flags || *buf || verbose > 1);
+       int local_change = iflags & ITEM_LOCAL_CHANGE
+           && (!(iflags & ITEM_XNAME_FOLLOWS) || significant_flags);
        if (am_server) {
                if (am_daemon && !dry_run && see_item)
                        log_item(file, &stats, iflags, buf);
-       } else if (see_item || iflags & ITEM_LOCAL_CHANGE || *buf
-           || (S_ISDIR(file->mode) && iflags & SIGNIFICANT_ITEM_FLAGS))
+       } else if (see_item || local_change || *buf
+           || (S_ISDIR(file->mode) && significant_flags))
                log_item(file, &stats, iflags, buf);
 }