diff options
author | Theodore Ts'o <tytso@mit.edu> | 2002-07-21 14:14:03 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2002-07-21 14:14:03 -0400 |
commit | 4cae04529eda0e482ceaa86b48e532f9c8d35f24 (patch) | |
tree | 67e9f2fac948b282dde6b0a52138738cec03f43b | |
parent | b7a00563b22b0ea47ddc7117508c0b8e0d65df43 (diff) | |
download | e2fsprogs-4cae04529eda0e482ceaa86b48e532f9c8d35f24.tar.gz |
Add SIGINT and SIGTERM handling to fsck and e2fsck. For e2fsck,
make sure we gracefully clean up and only exit at safe points.
For fsck, we pass the SIGINT/SIGTERM signal to the child processes,
so they can do their own cleanup.
-rw-r--r-- | e2fsck/ChangeLog | 17 | ||||
-rw-r--r-- | e2fsck/e2fsck.8.in | 4 | ||||
-rw-r--r-- | e2fsck/e2fsck.h | 1 | ||||
-rw-r--r-- | e2fsck/pass2.c | 10 | ||||
-rw-r--r-- | e2fsck/pass3.c | 7 | ||||
-rw-r--r-- | e2fsck/pass4.c | 2 | ||||
-rw-r--r-- | e2fsck/unix.c | 38 | ||||
-rw-r--r-- | misc/ChangeLog | 7 | ||||
-rw-r--r-- | misc/fsck.8.in | 2 | ||||
-rw-r--r-- | misc/fsck.c | 56 |
10 files changed, 128 insertions, 16 deletions
diff --git a/e2fsck/ChangeLog b/e2fsck/ChangeLog index aaf77636..132fcdf6 100644 --- a/e2fsck/ChangeLog +++ b/e2fsck/ChangeLog @@ -1,3 +1,20 @@ +2002-07-21 Theodore Ts'o <tytso@mit.edu> + + * e2fsck.8.in: Document new exit code FSCK_CANCELED + + * unix.c (PRS, signal_cancel): Capture SIGINT and SIGTERM signals + and set a flag in the e2fsck context indicating that + cancellation has been requested, so that e2fsck will exit + only at safe points. + (main): Change the exit handling so that if a cancellation + is requested, return FSCK_CANCELED (a new exit code 32). + e2fsck can now return more than one exit code as part of a + bitmask (as had been documented in the man page). + + * pass2.c (e2fsck_pass2, check_dir_block), pass3.c (e2fsck_pass3), + pass4.c (e2fsck_pass4): Check to see if a cancellation was + requested, and abort processing if necessary. + 2002-07-19 Theodore Ts'o <tytso@mit.edu> * rehash.c, Makefile.in: New file which rewrites directories using diff --git a/e2fsck/e2fsck.8.in b/e2fsck/e2fsck.8.in index ad517c12..57383f7a 100644 --- a/e2fsck/e2fsck.8.in +++ b/e2fsck/e2fsck.8.in @@ -214,7 +214,7 @@ is the sum of the following conditions: .br \ 2\ \-\ File system errors corrected, system should .br -\ \ \ \ be rebooted if file system was mounted +\ \ \ \ be rebooted .br \ 4\ \-\ File system errors left uncorrected .br @@ -222,6 +222,8 @@ is the sum of the following conditions: .br \ 16\ \-\ Usage or syntax error .br +\ 32\ \-\ E2fsck canceled by user request +.br \ 128\ \-\ Shared library error .br .SH SIGNALS diff --git a/e2fsck/e2fsck.h b/e2fsck/e2fsck.h index d68b79c1..c35bf684 100644 --- a/e2fsck/e2fsck.h +++ b/e2fsck/e2fsck.h @@ -58,6 +58,7 @@ #define FSCK_UNCORRECTED 4 /* File system errors left uncorrected */ #define FSCK_ERROR 8 /* Operational error */ #define FSCK_USAGE 16 /* Usage or syntax error */ +#define FSCK_CANCELED 32 /* Aborted with a signal or ^C */ #define FSCK_LIBRARY 128 /* Shared library error */ /* diff --git a/e2fsck/pass2.c b/e2fsck/pass2.c index db23c88e..1f484f45 100644 --- a/e2fsck/pass2.c +++ b/e2fsck/pass2.c @@ -148,6 +148,8 @@ void e2fsck_pass2(e2fsck_t ctx) #ifdef ENABLE_HTREE for (i=0; (dx_dir = e2fsck_dx_dir_info_iter(ctx, &i)) != 0;) { + if (ctx->flags & E2F_FLAG_SIGNAL_MASK) + return; if (dx_dir->numblocks == 0) continue; clear_problem_context(&pctx); @@ -565,9 +567,11 @@ static int check_dir_block(ext2_filsys fs, buf = cd->buf; ctx = cd->ctx; - if (ctx->progress) - if ((ctx->progress)(ctx, 2, cd->count++, cd->max)) - return DIRENT_ABORT; + if (ctx->flags & E2F_FLAG_SIGNAL_MASK) + return DIRENT_ABORT; + + if (ctx->progress && (ctx->progress)(ctx, 2, cd->count++, cd->max)) + return DIRENT_ABORT; /* * Make sure the inode is still in use (could have been diff --git a/e2fsck/pass3.c b/e2fsck/pass3.c index 7fdd8146..4b1f3970 100644 --- a/e2fsck/pass3.c +++ b/e2fsck/pass3.c @@ -110,9 +110,10 @@ void e2fsck_pass3(e2fsck_t ctx) goto abort_exit; for (i=0; (dir = e2fsck_dir_info_iter(ctx, &i)) != 0;) { - if (ctx->progress) - if ((ctx->progress)(ctx, 3, count++, maxdirs)) - goto abort_exit; + if (ctx->flags & E2F_FLAG_SIGNAL_MASK) + goto abort_exit; + if (ctx->progress && (ctx->progress)(ctx, 3, count++, maxdirs)) + goto abort_exit; if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, dir->ino)) if (check_directory(ctx, dir, &pctx)) goto abort_exit; diff --git a/e2fsck/pass4.c b/e2fsck/pass4.c index 895b77ad..28c0996c 100644 --- a/e2fsck/pass4.c +++ b/e2fsck/pass4.c @@ -109,6 +109,8 @@ void e2fsck_pass4(e2fsck_t ctx) return; for (i=1; i <= fs->super->s_inodes_count; i++) { + if (ctx->flags & E2F_FLAG_SIGNAL_MASK) + return; if ((i % fs->super->s_inodes_per_group) == 0) { group++; if (ctx->progress) diff --git a/e2fsck/unix.c b/e2fsck/unix.c index 18f2b2c7..7fca08c0 100644 --- a/e2fsck/unix.c +++ b/e2fsck/unix.c @@ -436,6 +436,16 @@ static void signal_progress_off(int sig) e2fsck_clear_progbar(ctx); ctx->progress = 0; } + +static void signal_cancel(int sig) +{ + e2fsck_t ctx = e2fsck_global_ctx; + + if (!ctx) + exit(FSCK_CANCELED); + + ctx->flags |= E2F_FLAG_CANCEL; +} #endif static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx) @@ -632,6 +642,9 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx) sigaction(SIGUSR1, &sa, 0); sa.sa_handler = signal_progress_off; sigaction(SIGUSR2, &sa, 0); + sa.sa_handler = signal_cancel; + sigaction(SIGINT, &sa, 0); + sigaction(SIGTERM, &sa, 0); #endif /* Update our PATH to include /sbin if we need to run badblocks */ @@ -958,23 +971,26 @@ restart: ext2fs_close(fs); goto restart; } - if (run_result & E2F_FLAG_SIGNAL_MASK) - fatal_error(ctx, 0); - if (run_result & E2F_FLAG_CANCEL) - ext2fs_unmark_valid(fs); + if (run_result & E2F_FLAG_CANCEL) { + printf(_("%s: e2fsck canceled.\n"), ctx->device_name ? + ctx->device_name : ctx->filesystem_name); + exit_value |= FSCK_CANCELED; + } + if (run_result & E2F_FLAG_ABORT) + fatal_error(ctx, _("aborted")); #ifdef MTRACE mtrace_print("Cleanup"); #endif if (ext2fs_test_changed(fs)) { - exit_value = FSCK_NONDESTRUCT; + exit_value |= FSCK_NONDESTRUCT; if (!(ctx->options & E2F_OPT_PREEN)) printf(_("\n%s: ***** FILE SYSTEM WAS MODIFIED *****\n"), ctx->device_name); if (root_filesystem && !read_only_root) { printf(_("%s: ***** REBOOT LINUX *****\n"), ctx->device_name); - exit_value = FSCK_REBOOT; + exit_value |= FSCK_REBOOT; } } if (ext2fs_test_valid(fs)) @@ -982,12 +998,13 @@ restart: else { printf(_("\n%s: ********** WARNING: Filesystem still has " "errors **********\n\n"), ctx->device_name); - exit_value = FSCK_UNCORRECTED; + exit_value |= FSCK_UNCORRECTED; + exit_value &= ~FSCK_NONDESTRUCT; } if (!(ctx->options & E2F_OPT_READONLY)) { if (ext2fs_test_valid(fs)) { if (!(sb->s_state & EXT2_VALID_FS)) - exit_value = FSCK_NONDESTRUCT; + exit_value |= FSCK_NONDESTRUCT; sb->s_state = EXT2_VALID_FS; } else sb->s_state &= ~EXT2_VALID_FS; @@ -995,7 +1012,10 @@ restart: sb->s_lastcheck = time(NULL); ext2fs_mark_super_dirty(fs); } - show_stats(ctx); + if (exit_value & FSCK_CANCELED) + exit_value &= ~FSCK_NONDESTRUCT; + else + show_stats(ctx); e2fsck_write_bitmaps(ctx); diff --git a/misc/ChangeLog b/misc/ChangeLog index 6de1398a..0469b719 100644 --- a/misc/ChangeLog +++ b/misc/ChangeLog @@ -1,3 +1,10 @@ +2002-07-21 Theodore Ts'o <tytso@mit.edu> + + * fsck.8.in: Document new fsck exit code, FSCK_CANCELED. + + * fsck.c: Trap SIGINT and SIGTERM, and relay it to all of the + child fsck processes. + 2002-07-14 Theodore Ts'o <tytso@mit.edu> * mke2fs.c (zap_sector): Clear the buffer *after* testing for the diff --git a/misc/fsck.8.in b/misc/fsck.8.in index fb205214..fd136ecc 100644 --- a/misc/fsck.8.in +++ b/misc/fsck.8.in @@ -49,6 +49,8 @@ is the sum of the following conditions: .br \ 16\ \-\ Usage or syntax error .br +\ 32\ \-\ Fsck canceled by user request +.br \ 128\ \-\ Shared library error .br The exit code returned when all file systems are checked using the diff --git a/misc/fsck.c b/misc/fsck.c index 8c4499ef..8503eee4 100644 --- a/misc/fsck.c +++ b/misc/fsck.c @@ -100,6 +100,8 @@ int progress = 0; int force_all_parallel = 0; int num_running = 0; int max_running = 0; +volatile int cancel_requested = 0; +int kill_sent = 0; char *progname; char *fstype = NULL; struct fs_info *filesys_info; @@ -468,6 +470,23 @@ static int execute(const char *type, char *device, char *mntpt, } /* + * Send a signal to all outstanding fsck child processes + */ +static int kill_all(int signal) +{ + struct fsck_instance *inst; + int n = 0; + + for (inst = instance_list; inst; inst = inst->next) { + if (inst->flags & FLAG_DONE) + continue; + kill(inst->pid, signal); + n++; + } + return n; +} + +/* * Wait for one child process to exit; when it does, unlink it from * the list of executing child processes, and return it. */ @@ -502,6 +521,10 @@ static struct fsck_instance *wait_one(int flags) do { pid = waitpid(-1, &status, flags); + if (cancel_requested && !kill_sent) { + kill_all(SIGTERM); + kill_sent++; + } if ((pid == 0) && (flags & WNOHANG)) return NULL; if (pid < 0) { @@ -908,6 +931,8 @@ static int check_all(NOARGS) pass_done = 1; for (fs = filesys_info; fs; fs = fs->next) { + if (cancel_requested) + break; if (fs->flags & FLAG_DONE) continue; /* @@ -945,6 +970,8 @@ static int check_all(NOARGS) break; } } + if (cancel_requested) + break; if (verbose > 1) printf(_("--waiting-- (pass %d)\n"), passno); status |= wait_all(pass_done ? 0 : WNOHANG); @@ -955,6 +982,10 @@ static int check_all(NOARGS) } else not_done_yet++; } + if (cancel_requested && !kill_sent) { + kill_all(SIGTERM); + kill_sent++; + } status |= wait_all(0); return status; } @@ -966,6 +997,13 @@ static void usage(NOARGS) exit(EXIT_USAGE); } +#ifdef HAVE_SIGNAL_H +static void signal_cancel(int sig) +{ + cancel_requested++; +} +#endif + static void PRS(int argc, char *argv[]) { int i, j; @@ -973,6 +1011,17 @@ static void PRS(int argc, char *argv[]) char options[128]; int opt = 0; int opts_for_fsck = 0; +#ifdef HAVE_SIGNAL_H + struct sigaction sa; + + /* + * Set up signal action + */ + memset(&sa, 0, sizeof(struct sigaction)); + sa.sa_handler = signal_cancel; + sigaction(SIGINT, &sa, 0); + sigaction(SIGTERM, &sa, 0); +#endif num_devices = 0; num_args = 0; @@ -1128,6 +1177,13 @@ int main(int argc, char *argv[]) exit(EXIT_ERROR); } for (i = 0 ; i < num_devices; i++) { + if (cancel_requested) { + if (!kill_sent) { + kill_all(SIGTERM); + kill_sent++; + } + break; + } fsck_device(devices[i], interactive); if (serialize || (num_running >= max_running)) { struct fsck_instance *inst; |