From 154c345db03bd0c5a93a28373352c9d9363d587b Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Sat, 14 Oct 2006 19:58:52 +0000 Subject: [PATCH] Improved the _exit_cleanup() function to handle potential recursions back to the function via the calls that it is making. The new code treats each recursion back into the function as an opportunity to take up where we left off (skipping whatever step just failed). --- cleanup.c | 147 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 96 insertions(+), 51 deletions(-) diff --git a/cleanup.c b/cleanup.c index 2f47ef7f..df8c95bd 100644 --- a/cleanup.c +++ b/cleanup.c @@ -87,8 +87,6 @@ static pid_t cleanup_pid = 0; pid_t cleanup_child_pid = -1; -int in_exit_cleanup = 0; - /** * Eventually calls exit(), passing @p code, therefore does not return. * @@ -96,69 +94,116 @@ int in_exit_cleanup = 0; **/ NORETURN void _exit_cleanup(int code, const char *file, int line) { - int ocode = code; + static int cleanup_step = 0; + static int exit_code = 0; + static int unmodified_code = 0; SIGACTION(SIGUSR1, SIG_IGN); SIGACTION(SIGUSR2, SIG_IGN); - in_exit_cleanup = 1; + if (exit_code) /* Preserve first error code when recursing. */ + code = exit_code; - if (verbose > 3) { - rprintf(FINFO,"_exit_cleanup(code=%d, file=%s, line=%d): entered\n", - code, file, line); - } + /* Some of our actions might cause a recursive call back here, so we + * keep track of where we are in the cleanup and never repeat a step. */ + switch (cleanup_step) { + case 0: + cleanup_step++; + + exit_code = unmodified_code = code; - if (cleanup_child_pid != -1) { - int status; - if (wait_process(cleanup_child_pid, &status, WNOHANG) == cleanup_child_pid) { - status = WEXITSTATUS(status); - if (status > code) - code = status; + if (verbose > 3) { + rprintf(FINFO, + "_exit_cleanup(code=%d, file=%s, line=%d): entered\n", + code, file, line); } - } - if (cleanup_got_literal && cleanup_fname && cleanup_new_fname - && keep_partial && handle_partial_dir(cleanup_new_fname, PDIR_CREATE)) { - char *fname = cleanup_fname; - cleanup_fname = NULL; - if (cleanup_fd_r != -1) - close(cleanup_fd_r); - if (cleanup_fd_w != -1) { - flush_write_file(cleanup_fd_w); - close(cleanup_fd_w); + /* FALLTHROUGH */ + case 1: + cleanup_step++; + + if (cleanup_child_pid != -1) { + int status; + int pid = wait_process(cleanup_child_pid, &status, WNOHANG); + if (pid == cleanup_child_pid) { + status = WEXITSTATUS(status); + if (status > code) + code = exit_code = status; + } } - finish_transfer(cleanup_new_fname, fname, NULL, - cleanup_file, 0, !partial_dir); - } - io_flush(FULL_FLUSH); - if (cleanup_fname) - do_unlink(cleanup_fname); - if (code) - kill_all(SIGUSR1); - if (cleanup_pid && cleanup_pid == getpid()) { - char *pidf = lp_pid_file(); - if (pidf && *pidf) - unlink(lp_pid_file()); - } - if (code == 0) { - if (io_error & IOERR_DEL_LIMIT) - code = RERR_DEL_LIMIT; - if (io_error & IOERR_VANISHED) - code = RERR_VANISHED; - if (io_error & IOERR_GENERAL || log_got_error) - code = RERR_PARTIAL; - } + /* FALLTHROUGH */ + case 2: + cleanup_step++; + + if (cleanup_got_literal && cleanup_fname && cleanup_new_fname + && keep_partial && handle_partial_dir(cleanup_new_fname, PDIR_CREATE)) { + char *fname = cleanup_fname; + cleanup_fname = NULL; + if (cleanup_fd_r != -1) + close(cleanup_fd_r); + if (cleanup_fd_w != -1) { + flush_write_file(cleanup_fd_w); + close(cleanup_fd_w); + } + finish_transfer(cleanup_new_fname, fname, NULL, + cleanup_file, 0, !partial_dir); + } + + /* FALLTHROUGH */ + case 3: + cleanup_step++; + + io_flush(FULL_FLUSH); + + /* FALLTHROUGH */ + case 4: + cleanup_step++; + + if (cleanup_fname) + do_unlink(cleanup_fname); + if (code) + kill_all(SIGUSR1); + if (cleanup_pid && cleanup_pid == getpid()) { + char *pidf = lp_pid_file(); + if (pidf && *pidf) + unlink(lp_pid_file()); + } + + if (code == 0) { + if (io_error & IOERR_DEL_LIMIT) + code = exit_code = RERR_DEL_LIMIT; + if (io_error & IOERR_VANISHED) + code = exit_code = RERR_VANISHED; + if (io_error & IOERR_GENERAL || log_got_error) + code = exit_code = RERR_PARTIAL; + } + + if (code || am_daemon || (logfile_name && (am_server || !verbose))) + log_exit(code, file, line); + + /* FALLTHROUGH */ + case 5: + cleanup_step++; + + if (verbose > 2) { + rprintf(FINFO, + "_exit_cleanup(code=%d, file=%s, line=%d): " + "about to call exit(%d)\n", + unmodified_code, file, line, code); + } + + /* FALLTHROUGH */ + case 6: + cleanup_step++; - if (code || am_daemon || (logfile_name && (am_server || !verbose))) - log_exit(code, file, line); + close_all(); - if (verbose > 2) { - rprintf(FINFO,"_exit_cleanup(code=%d, file=%s, line=%d): about to call exit(%d)\n", - ocode, file, line, code); + /* FALLTHROUGH */ + default: + break; } - close_all(); exit(code); } -- 2.34.1