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

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

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