Annotation of embedaddon/rsync/log.c, revision 1.1.1.4

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>