File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / rsync / cleanup.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Fri Feb 17 15:09:30 2012 UTC (12 years, 5 months ago) by misho
Branches: rsync, MAIN
CVS tags: rsync3_0_9p0, RSYNC3_0_9, HEAD
rsync

    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>