summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2002-07-21 14:14:03 -0400
committerTheodore Ts'o <tytso@mit.edu>2002-07-21 14:14:03 -0400
commit4cae04529eda0e482ceaa86b48e532f9c8d35f24 (patch)
tree67e9f2fac948b282dde6b0a52138738cec03f43b
parentb7a00563b22b0ea47ddc7117508c0b8e0d65df43 (diff)
downloade2fsprogs-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/ChangeLog17
-rw-r--r--e2fsck/e2fsck.8.in4
-rw-r--r--e2fsck/e2fsck.h1
-rw-r--r--e2fsck/pass2.c10
-rw-r--r--e2fsck/pass3.c7
-rw-r--r--e2fsck/pass4.c2
-rw-r--r--e2fsck/unix.c38
-rw-r--r--misc/ChangeLog7
-rw-r--r--misc/fsck.8.in2
-rw-r--r--misc/fsck.c56
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;