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

1.1     ! misho       1: /*
        !             2:  * End-of-run cleanup routines.
        !             3:  *
        !             4:  * Copyright (C) 1996-2000 Andrew Tridgell
        !             5:  * Copyright (C) 1996 Paul Mackerras
        !             6:  * Copyright (C) 2002 Martin Pool
        !             7:  * Copyright (C) 2003-2009 Wayne Davison
        !             8:  *
        !             9:  * This program is free software; you can redistribute it and/or modify
        !            10:  * it under the terms of the GNU General Public License as published by
        !            11:  * the Free Software Foundation; either version 3 of the License, or
        !            12:  * (at your option) any later version.
        !            13:  *
        !            14:  * This program is distributed in the hope that it will be useful,
        !            15:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
        !            16:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        !            17:  * GNU General Public License for more details.
        !            18:  *
        !            19:  * You should have received a copy of the GNU General Public License along
        !            20:  * with this program; if not, visit the http://fsf.org website.
        !            21:  */
        !            22: 
        !            23: #include "rsync.h"
        !            24: 
        !            25: extern int am_server;
        !            26: extern int am_daemon;
        !            27: extern int am_receiver;
        !            28: extern int io_error;
        !            29: extern int keep_partial;
        !            30: extern int got_xfer_error;
        !            31: extern char *partial_dir;
        !            32: extern char *logfile_name;
        !            33: 
        !            34: #ifdef HAVE_SIGACTION
        !            35: static struct sigaction sigact;
        !            36: #endif
        !            37: 
        !            38: /**
        !            39:  * Close all open sockets and files, allowing a (somewhat) graceful
        !            40:  * shutdown() of socket connections.  This eliminates the abortive
        !            41:  * TCP RST sent by a Winsock-based system when the close() occurs.
        !            42:  **/
        !            43: void close_all(void)
        !            44: {
        !            45: #ifdef SHUTDOWN_ALL_SOCKETS
        !            46:        int max_fd;
        !            47:        int fd;
        !            48:        int ret;
        !            49:        STRUCT_STAT st;
        !            50: 
        !            51:        max_fd = sysconf(_SC_OPEN_MAX) - 1;
        !            52:        for (fd = max_fd; fd >= 0; fd--) {
        !            53:                if ((ret = do_fstat(fd, &st)) == 0) {
        !            54:                        if (is_a_socket(fd))
        !            55:                                ret = shutdown(fd, 2);
        !            56:                        ret = close(fd);
        !            57:                }
        !            58:        }
        !            59: #endif
        !            60: }
        !            61: 
        !            62: /**
        !            63:  * @file cleanup.c
        !            64:  *
        !            65:  * Code for handling interrupted transfers.  Depending on the @c
        !            66:  * --partial option, we may either delete the temporary file, or go
        !            67:  * ahead and overwrite the destination.  This second behaviour only
        !            68:  * occurs if we've sent literal data and therefore hopefully made
        !            69:  * progress on the transfer.
        !            70:  **/
        !            71: 
        !            72: /**
        !            73:  * Set to True once literal data has been sent across the link for the
        !            74:  * current file. (????)
        !            75:  *
        !            76:  * Handling the cleanup when a transfer is interrupted is tricky when
        !            77:  * --partial is selected.  We need to ensure that the partial file is
        !            78:  * kept if any real data has been transferred.
        !            79:  **/
        !            80: int cleanup_got_literal = 0;
        !            81: 
        !            82: static const char *cleanup_fname;
        !            83: static const char *cleanup_new_fname;
        !            84: static struct file_struct *cleanup_file;
        !            85: static int cleanup_fd_r, cleanup_fd_w;
        !            86: static pid_t cleanup_pid = 0;
        !            87: 
        !            88: pid_t cleanup_child_pid = -1;
        !            89: 
        !            90: /**
        !            91:  * Eventually calls exit(), passing @p code, therefore does not return.
        !            92:  *
        !            93:  * @param code one of the RERR_* codes from errcode.h.
        !            94:  **/
        !            95: NORETURN void _exit_cleanup(int code, const char *file, int line)
        !            96: {
        !            97:        static int switch_step = 0;
        !            98:        static int exit_code = 0, exit_line = 0;
        !            99:        static const char *exit_file = NULL;
        !           100:        static int unmodified_code = 0;
        !           101: 
        !           102:        SIGACTION(SIGUSR1, SIG_IGN);
        !           103:        SIGACTION(SIGUSR2, SIG_IGN);
        !           104: 
        !           105:        if (exit_code) { /* Preserve first exit info when recursing. */
        !           106:                code = exit_code;
        !           107:                file = exit_file;
        !           108:                line = exit_line;
        !           109:        }
        !           110: 
        !           111:        /* If this is the exit at the end of the run, the server side
        !           112:         * should not attempt to output a message (see log_exit()). */
        !           113:        if (am_server && code == 0)
        !           114:                am_server = 2;
        !           115: 
        !           116:        /* Some of our actions might cause a recursive call back here, so we
        !           117:         * keep track of where we are in the cleanup and never repeat a step. */
        !           118:        switch (switch_step) {
        !           119: #include "case_N.h" /* case 0: */
        !           120:                switch_step++;
        !           121: 
        !           122:                exit_code = unmodified_code = code;
        !           123:                exit_file = file;
        !           124:                exit_line = line;
        !           125: 
        !           126:                if (verbose > 3) {
        !           127:                        rprintf(FINFO,
        !           128:                                "[%s] _exit_cleanup(code=%d, file=%s, line=%d): entered\n",
        !           129:                                who_am_i(), code, file, line);
        !           130:                }
        !           131: 
        !           132:                /* FALLTHROUGH */
        !           133: #include "case_N.h"
        !           134:                switch_step++;
        !           135: 
        !           136:                if (cleanup_child_pid != -1) {
        !           137:                        int status;
        !           138:                        int pid = wait_process(cleanup_child_pid, &status, WNOHANG);
        !           139:                        if (pid == cleanup_child_pid) {
        !           140:                                status = WEXITSTATUS(status);
        !           141:                                if (status > code)
        !           142:                                        code = exit_code = status;
        !           143:                        }
        !           144:                }
        !           145: 
        !           146:                /* FALLTHROUGH */
        !           147: #include "case_N.h"
        !           148:                switch_step++;
        !           149: 
        !           150:                if (cleanup_got_literal && cleanup_fname && cleanup_new_fname
        !           151:                 && keep_partial && handle_partial_dir(cleanup_new_fname, PDIR_CREATE)) {
        !           152:                        const char *fname = cleanup_fname;
        !           153:                        cleanup_fname = NULL;
        !           154:                        if (cleanup_fd_r != -1)
        !           155:                                close(cleanup_fd_r);
        !           156:                        if (cleanup_fd_w != -1) {
        !           157:                                flush_write_file(cleanup_fd_w);
        !           158:                                close(cleanup_fd_w);
        !           159:                        }
        !           160:                        finish_transfer(cleanup_new_fname, fname, NULL, NULL,
        !           161:                                        cleanup_file, 0, !partial_dir);
        !           162:                }
        !           163: 
        !           164:                /* FALLTHROUGH */
        !           165: #include "case_N.h"
        !           166:                switch_step++;
        !           167: 
        !           168:                if (!code || am_server || am_receiver)
        !           169:                        io_flush(FULL_FLUSH);
        !           170: 
        !           171:                /* FALLTHROUGH */
        !           172: #include "case_N.h"
        !           173:                switch_step++;
        !           174: 
        !           175:                if (cleanup_fname)
        !           176:                        do_unlink(cleanup_fname);
        !           177:                if (code)
        !           178:                        kill_all(SIGUSR1);
        !           179:                if (cleanup_pid && cleanup_pid == getpid()) {
        !           180:                        char *pidf = lp_pid_file();
        !           181:                        if (pidf && *pidf)
        !           182:                                unlink(lp_pid_file());
        !           183:                }
        !           184: 
        !           185:                if (code == 0) {
        !           186:                        if (io_error & IOERR_DEL_LIMIT)
        !           187:                                code = exit_code = RERR_DEL_LIMIT;
        !           188:                        if (io_error & IOERR_VANISHED)
        !           189:                                code = exit_code = RERR_VANISHED;
        !           190:                        if (io_error & IOERR_GENERAL || got_xfer_error)
        !           191:                                code = exit_code = RERR_PARTIAL;
        !           192:                }
        !           193: 
        !           194:                if (code || am_daemon || (logfile_name && (am_server || !verbose)))
        !           195:                        log_exit(code, file, line);
        !           196: 
        !           197:                /* FALLTHROUGH */
        !           198: #include "case_N.h"
        !           199:                switch_step++;
        !           200: 
        !           201:                if (verbose > 2) {
        !           202:                        rprintf(FINFO,
        !           203:                                "[%s] _exit_cleanup(code=%d, file=%s, line=%d): "
        !           204:                                "about to call exit(%d)\n",
        !           205:                                who_am_i(), unmodified_code, file, line, code);
        !           206:                }
        !           207: 
        !           208:                /* FALLTHROUGH */
        !           209: #include "case_N.h"
        !           210:                switch_step++;
        !           211: 
        !           212:                if (am_server && code)
        !           213:                        msleep(100);
        !           214:                close_all();
        !           215: 
        !           216:                /* FALLTHROUGH */
        !           217:        default:
        !           218:                break;
        !           219:        }
        !           220: 
        !           221:        exit(code);
        !           222: }
        !           223: 
        !           224: void cleanup_disable(void)
        !           225: {
        !           226:        cleanup_fname = cleanup_new_fname = NULL;
        !           227:        cleanup_got_literal = 0;
        !           228: }
        !           229: 
        !           230: 
        !           231: void cleanup_set(const char *fnametmp, const char *fname, struct file_struct *file,
        !           232:                 int fd_r, int fd_w)
        !           233: {
        !           234:        cleanup_fname = fnametmp;
        !           235:        cleanup_new_fname = fname; /* can be NULL on a partial-dir failure */
        !           236:        cleanup_file = file;
        !           237:        cleanup_fd_r = fd_r;
        !           238:        cleanup_fd_w = fd_w;
        !           239: }
        !           240: 
        !           241: void cleanup_set_pid(pid_t pid)
        !           242: {
        !           243:        cleanup_pid = pid;
        !           244: }

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