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>