From 5596defa1e212242c1bf1b028139143fbb7777a0 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Mon, 19 Jul 1999 15:27:37 +0000 Subject: [PATCH] Many files: unix.c: Add support for calculating a progress bar if the -C0 option is given. The function e2fsck_clear_progbar() clears the progress bar and must be called before any message is issued. SIGUSR1 will enable the progress bar, and SIGUSR2 will disable the progress bar. This is used by fsck to handle parallel filesystem checks. Also, set the device_name from the filesystem label if it is available. e2fsck.h: Add new flags E2F_FLAG_PROG_BAR and E2F_FLAG_PROG_SUPRESS. Add new field in the e2fsck structure which contains the last tenth of a percent printed for the user. message.c (print_e2fsck_message): Add call to e2fsck_clear_progbar(). pass1.c (e2fsck_pass1): pass2.c (e2fsck_pass2): pass3.c (e2fsck_pass3): pass4.c (e2fsck_pass4): pass5.c (e2fsck_pass5): Add call to e2fsck_clear_progbar when printing the resource tracking information. pass5.c (check_block_bitmaps, check_inode_bitmaps): If there is an error in the bitmaps, suppress printing the progress bar using the suppression flag for the remainder of the check, in order to clean up the display. --- e2fsck/ChangeLog | 31 ++++++++++++ e2fsck/e2fsck.8.in | 28 ++++++++--- e2fsck/e2fsck.h | 6 +++ e2fsck/message.c | 3 +- e2fsck/pass1.c | 4 +- e2fsck/pass2.c | 4 +- e2fsck/pass3.c | 8 ++- e2fsck/pass4.c | 4 +- e2fsck/pass5.c | 10 +++- e2fsck/unix.c | 120 ++++++++++++++++++++++++++++++++++++++++++--- 10 files changed, 197 insertions(+), 21 deletions(-) diff --git a/e2fsck/ChangeLog b/e2fsck/ChangeLog index 79bd9aae4..c25e478e9 100644 --- a/e2fsck/ChangeLog +++ b/e2fsck/ChangeLog @@ -1,3 +1,34 @@ +1999-07-18 + + * unix.c: Add support for calculating a progress bar if the -C0 + option is given. The function e2fsck_clear_progbar() + clears the progress bar and must be called before any + message is issued. SIGUSR1 will enable the progress bar, + and SIGUSR2 will disable the progress bar. This is used + by fsck to handle parallel filesystem checks. Also, set + the device_name from the filesystem label if it is + available. + + * e2fsck.h: Add new flags E2F_FLAG_PROG_BAR and + E2F_FLAG_PROG_SUPRESS. Add new field in the e2fsck + structure which contains the last tenth of a percent + printed for the user. + + * message.c (print_e2fsck_message): Add call to + e2fsck_clear_progbar(). + + * pass1.c (e2fsck_pass1): + * pass2.c (e2fsck_pass2): + * pass3.c (e2fsck_pass3): + * pass4.c (e2fsck_pass4): + * pass5.c (e2fsck_pass5): Add call to e2fsck_clear_progbar when + printing the resource tracking information. + + * pass5.c (check_block_bitmaps, check_inode_bitmaps): If there is + an error in the bitmaps, suppress printing the progress + bar using the suppression flag for the remainder of the + check, in order to clean up the display. + 1999-06-30 * unix.c (check_mount): Clean up the abort message displayed when diff --git a/e2fsck/e2fsck.8.in b/e2fsck/e2fsck.8.in index 41e6dc894..df4e6da6f 100644 --- a/e2fsck/e2fsck.8.in +++ b/e2fsck/e2fsck.8.in @@ -78,14 +78,13 @@ This option causes .B e2fsck to write completion information to the specified file descriptor so that the progress of the filesystem -check can be monitored. This option is typically used by programs which are -executing -.BR e2fsck , -although -C 0 is a special case which will output a spinning -character which can be useful for users who want to have something to watch -while +check can be monitored. This option is typically used by programs +which are running +.BR e2fsck . +If the file descriptor specified is 0, .B e2fsck -goes about its business. +will print a completion bar as it goes about its business. This requires +that e2fsck is running on a video console or terminal. .TP .I -d Print debugging output (useless unless you are debugging @@ -186,6 +185,21 @@ is the sum of the following conditions: .br \ 128\ \-\ Shared library error .br +.SH SIGNALS +The following signals have the following effect when sent to +.BR e2fsck . +.TP +.B SIGUSR1 +This signal causes +.B e2fsck +to start displaying a completion bar. (See discussion of the +.I -C +option.) +.TP +.B SIGUSR2 +This signal causes +.B e2fsck +to stop displaying a completion bar. .SH REPORTING BUGS Almost any piece of software will have bugs. If you manage to find a filesystem which causes diff --git a/e2fsck/e2fsck.h b/e2fsck/e2fsck.h index 782edbc7f..86b411ce7 100644 --- a/e2fsck/e2fsck.h +++ b/e2fsck/e2fsck.h @@ -102,6 +102,9 @@ struct resource_track { #define E2F_FLAG_SETJMP_OK 0x0010 /* Setjmp valid for abort */ +#define E2F_FLAG_PROG_BAR 0x0020 /* Progress bar on screen */ +#define E2F_FLAG_PROG_SUPPRESS 0x0040 /* Progress suspended */ + /* * Defines for indicating the e2fsck pass number */ @@ -196,6 +199,7 @@ struct e2fsck_struct { */ int progress_fd; int progress_pos; + int progress_last_percent; /* File counts */ int fs_directory_count; @@ -299,3 +303,5 @@ extern void mtrace_print(char *mesg); #endif extern blk_t get_backup_sb(ext2_filsys fs); +/* unix.c */ +extern void e2fsck_clear_progbar(e2fsck_t ctx); diff --git a/e2fsck/message.c b/e2fsck/message.c index 1e440c5cf..8bb11df80 100644 --- a/e2fsck/message.c +++ b/e2fsck/message.c @@ -385,7 +385,8 @@ void print_e2fsck_message(e2fsck_t ctx, const char *msg, ext2_filsys fs = ctx->fs; const char * cp; int i; - + + e2fsck_clear_progbar(ctx); for (cp = msg; *cp; cp++) { if (cp[0] == '@') { cp++; diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c index 5ebd6e032..cebc82c50 100644 --- a/e2fsck/pass1.c +++ b/e2fsck/pass1.c @@ -524,8 +524,10 @@ endit: } #ifdef RESOURCE_TRACK - if (ctx->options & E2F_OPT_TIME2) + if (ctx->options & E2F_OPT_TIME2) { + e2fsck_clear_progbar(ctx); print_resource_track("Pass 1", &rtrack); + } #endif } diff --git a/e2fsck/pass2.c b/e2fsck/pass2.c index 38c1eda63..37114e315 100644 --- a/e2fsck/pass2.c +++ b/e2fsck/pass2.c @@ -135,8 +135,10 @@ void e2fsck_pass2(e2fsck_t ctx) ctx->inode_bad_map = 0; } #ifdef RESOURCE_TRACK - if (ctx->options & E2F_OPT_TIME2) + if (ctx->options & E2F_OPT_TIME2) { + e2fsck_clear_progbar(ctx); print_resource_track("Pass 2", &rtrack); + } #endif } diff --git a/e2fsck/pass3.c b/e2fsck/pass3.c index a3aaa04ba..2e4bfe210 100644 --- a/e2fsck/pass3.c +++ b/e2fsck/pass3.c @@ -99,8 +99,10 @@ void e2fsck_pass3(e2fsck_t ctx) goto abort_exit; } #ifdef RESOURCE_TRACK - if (ctx->options & E2F_OPT_TIME) + if (ctx->options & E2F_OPT_TIME) { + e2fsck_clear_progbar(ctx); print_resource_track("Peak memory", &ctx->global_rtrack); + } #endif check_root(ctx); @@ -137,8 +139,10 @@ abort_exit: if (inode_done_map) ext2fs_free_inode_bitmap(inode_done_map); #ifdef RESOURCE_TRACK - if (ctx->options & E2F_OPT_TIME2) + if (ctx->options & E2F_OPT_TIME2) { + e2fsck_clear_progbar(ctx); print_resource_track("Pass 3", &rtrack); + } #endif } diff --git a/e2fsck/pass4.c b/e2fsck/pass4.c index e059cc341..264b1c783 100644 --- a/e2fsck/pass4.c +++ b/e2fsck/pass4.c @@ -153,8 +153,10 @@ void e2fsck_pass4(e2fsck_t ctx) ext2fs_free_inode_bitmap(ctx->inode_bb_map); ctx->inode_bb_map = 0; #ifdef RESOURCE_TRACK - if (ctx->options & E2F_OPT_TIME2) + if (ctx->options & E2F_OPT_TIME2) { + e2fsck_clear_progbar(ctx); print_resource_track("Pass 4", &rtrack); + } #endif } diff --git a/e2fsck/pass5.c b/e2fsck/pass5.c index 274052ece..b39b31343 100644 --- a/e2fsck/pass5.c +++ b/e2fsck/pass5.c @@ -65,8 +65,10 @@ void e2fsck_pass5(e2fsck_t ctx) ctx->block_found_map = 0; #ifdef RESOURCE_TRACK - if (ctx->options & E2F_OPT_TIME2) + if (ctx->options & E2F_OPT_TIME2) { + e2fsck_clear_progbar(ctx); print_resource_track("Pass 5", &rtrack); + } #endif } @@ -142,6 +144,7 @@ redo_counts: } pctx.blk = i; fix_problem(ctx, problem, &pctx); + ctx->flags |= E2F_FLAG_PROG_SUPPRESS; had_problem++; do_counts: @@ -166,6 +169,8 @@ redo_counts: fixit = end_problem_latch(ctx, PR_LATCH_BBITMAP); else fixit = -1; + ctx->flags &= ~E2F_FLAG_PROG_SUPPRESS; + if (fixit == 1) { ext2fs_free_block_bitmap(fs->block_map); retval = ext2fs_copy_bitmap(ctx->block_found_map, @@ -282,6 +287,7 @@ redo_counts: } pctx.ino = i; fix_problem(ctx, problem, &pctx); + ctx->flags |= E2F_FLAG_PROG_SUPPRESS; had_problem++; do_counts: @@ -312,6 +318,8 @@ do_counts: fixit = end_problem_latch(ctx, PR_LATCH_IBITMAP); else fixit = -1; + ctx->flags &= ~E2F_FLAG_PROG_SUPPRESS; + if (fixit == 1) { ext2fs_free_inode_bitmap(fs->inode_map); retval = ext2fs_copy_bitmap(ctx->inode_used_map, diff --git a/e2fsck/unix.c b/e2fsck/unix.c index ed8082d58..e33a814ec 100644 --- a/e2fsck/unix.c +++ b/e2fsck/unix.c @@ -18,6 +18,7 @@ #include #include #include +#include #ifdef HAVE_GETOPT_H #include #endif @@ -60,7 +61,8 @@ static void usage(e2fsck_t ctx) fprintf(stderr, "Usage: %s [-panyrcdfvstFSV] [-b superblock] [-B blocksize]\n" "\t\t[-I inode_buffer_blocks] [-P process_inode_size]\n" - "\t\t[-l|-L bad_blocks_file] device\n", ctx->program_name); + "\t\t[-l|-L bad_blocks_file] [-C fd] device\n", + ctx->program_name); exit(FSCK_USAGE); } @@ -165,11 +167,11 @@ static void check_mount(e2fsck_t ctx) #endif if (ctx->options & E2F_OPT_READONLY) { - printf("Warning! %s is mounted.\n", ctx->device_name); + printf("Warning! %s is mounted.\n", ctx->filesystem_name); return; } - printf("%s is mounted. ", ctx->device_name); + printf("%s is mounted. ", ctx->filesystem_name); if (!isatty(0) || !isatty(1)) { printf("Cannot continue, aborting.\n\n"); exit(FSCK_ERROR); @@ -225,11 +227,51 @@ static void check_if_skip(e2fsck_t ctx) /* * For completion notice */ +struct percent_tbl { + int max_pass; + int table[32]; +}; +struct percent_tbl e2fsck_tbl = { + 5, { 0, 70, 90, 92, 95, 100 } +}; +static int dpywidth = 50; +static char bar[] = + "===============================================================" + "==============================================================="; +static char spaces[] = + " " + " "; + +static float calc_percent(struct percent_tbl *tbl, int pass, int curr, + int max) +{ + float percent; + + if (pass <= 0) + return 0.0; + if (pass > tbl->max_pass) + return 100.0; + percent = ((float) curr) / ((float) max); + return ((percent * (tbl->table[pass] - tbl->table[pass-1])) + + tbl->table[pass-1]); +} + +extern void e2fsck_clear_progbar(e2fsck_t ctx) +{ + if (!(ctx->flags & E2F_FLAG_PROG_BAR)) + return; + + printf("%s\r", spaces + (sizeof(spaces) - 80)); + ctx->flags &= ~E2F_FLAG_PROG_BAR; +} + static int e2fsck_update_progress(e2fsck_t ctx, int pass, unsigned long cur, unsigned long max) { const char spinner[] = "\\|/-"; char buf[80]; + int i; + float percent; if (pass == 0) return 0; @@ -238,9 +280,25 @@ static int e2fsck_update_progress(e2fsck_t ctx, int pass, sprintf(buf, "%d %lu %lu\n", pass, cur, max); write(ctx->progress_fd, buf, strlen(buf)); } else { + if (ctx->flags & E2F_FLAG_PROG_SUPPRESS) + return 0; ctx->progress_pos = (ctx->progress_pos+1) & 3; - fputc(spinner[ctx->progress_pos], stdout); - fputc('\b', stdout); + ctx->flags |= E2F_FLAG_PROG_BAR; + percent = calc_percent(&e2fsck_tbl, pass, cur, max); + if (ctx->progress_last_percent == (int) 1000 * percent) + return 0; + ctx->progress_last_percent = (int) 1000 * percent; + i = ((percent * dpywidth) + 50) / 100; + printf("%s: |%s%s", ctx->device_name, + bar + (sizeof(bar) - (i+1)), + spaces + (sizeof(spaces) - (dpywidth - i + 1))); + if (percent == 100.0) + fputc('|', stdout); + else + fputc(spinner[ctx->progress_pos & 3], stdout); + printf(" %4.1f%% \r", percent); + if (percent == 100.0) + e2fsck_clear_progbar(ctx); fflush(stdout); } return 0; @@ -266,6 +324,30 @@ static void reserve_stdio_fds(NOARGS) close(fd); } +static e2fsck_t global_signal_ctx; + +static void signal_progress_on(int sig) +{ + e2fsck_t ctx = global_signal_ctx; + + if (!ctx) + return; + + ctx->progress = e2fsck_update_progress; + ctx->progress_fd = 0; +} + +static void signal_progress_off(int sig) +{ + e2fsck_t ctx = global_signal_ctx; + + if (!ctx) + return; + + e2fsck_clear_progbar(ctx); + ctx->progress = 0; +} + static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx) { int flush = 0; @@ -276,6 +358,7 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx) char *oldpath = getenv("PATH"); e2fsck_t ctx; errcode_t retval; + struct sigaction sa; retval = e2fsck_allocate_context(&ctx); if (retval) @@ -407,8 +490,6 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx) !cflag && !swapfs) ctx->options |= E2F_OPT_READONLY; ctx->filesystem_name = argv[optind]; - if (ctx->device_name == 0) - ctx->device_name = ctx->filesystem_name; if (flush) { #ifdef BLKFLSBUF int fd = open(ctx->filesystem_name, O_RDONLY, 0); @@ -435,6 +516,18 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx) exit(FSCK_ERROR); } } + /* + * Set up signal action + */ + memset(&sa, 0, sizeof(struct sigaction)); +#ifdef SA_RESTART + sa.sa_flags = SA_RESTART; +#endif + global_signal_ctx = ctx; + sa.sa_handler = signal_progress_on; + sigaction(SIGUSR1, &sa, 0); + sa.sa_handler = signal_progress_off; + sigaction(SIGUSR2, &sa, 0); return 0; } @@ -594,6 +687,18 @@ restart: "(%s)", ctx->filesystem_name); goto get_newer; } + if (ctx->device_name == 0 && + (s->s_volume_name[0] != 0)) { + char *cp = malloc(sizeof(s->s_volume_name)+1); + if (cp) { + strncpy(cp, s->s_volume_name, + sizeof(s->s_volume_name)); + cp[sizeof(s->s_volume_name)] = 0; + ctx->device_name = cp; + } + } + if (ctx->device_name == 0) + ctx->device_name = ctx->filesystem_name; /* * If the user specified a specific superblock, presumably the @@ -653,6 +758,7 @@ restart: } run_result = e2fsck_run(ctx); + e2fsck_clear_progbar(ctx); if (run_result == E2F_FLAG_RESTART) { printf("Restarting e2fsck from the beginning...\n"); retval = e2fsck_reset_context(ctx); -- 2.39.2