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.

diff --git a/e2fsck/ChangeLog b/e2fsck/ChangeLog
index 79bd9aa..c25e478 100644
--- a/e2fsck/ChangeLog
+++ b/e2fsck/ChangeLog
@@ -1,3 +1,34 @@
+1999-07-18    <tytso@valinux.com>
+
+	* 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    <tytso@valinux.com>
 
 	* unix.c (check_mount): Clean up the abort message displayed when
diff --git a/e2fsck/e2fsck.8.in b/e2fsck/e2fsck.8.in
index 41e6dc8..df4e6da 100644
--- a/e2fsck/e2fsck.8.in
+++ b/e2fsck/e2fsck.8.in
@@ -78,14 +78,13 @@
 .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 @@
 .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 782edbc..86b411c 100644
--- a/e2fsck/e2fsck.h
+++ b/e2fsck/e2fsck.h
@@ -102,6 +102,9 @@
 
 #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 @@
 	 */
 	int progress_fd;
 	int progress_pos;
+	int progress_last_percent;
 
 	/* File counts */
 	int fs_directory_count;
@@ -299,3 +303,5 @@
 #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 1e440c5..8bb11df 100644
--- a/e2fsck/message.c
+++ b/e2fsck/message.c
@@ -385,7 +385,8 @@
 	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 5ebd6e0..cebc82c 100644
--- a/e2fsck/pass1.c
+++ b/e2fsck/pass1.c
@@ -524,8 +524,10 @@
 	}
 	
 #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 38c1eda..37114e3 100644
--- a/e2fsck/pass2.c
+++ b/e2fsck/pass2.c
@@ -135,8 +135,10 @@
 		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 a3aaa04..2e4bfe2 100644
--- a/e2fsck/pass3.c
+++ b/e2fsck/pass3.c
@@ -99,8 +99,10 @@
 		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 @@
 	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 e059cc3..264b1c7 100644
--- a/e2fsck/pass4.c
+++ b/e2fsck/pass4.c
@@ -153,8 +153,10 @@
 	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 274052e..b39b313 100644
--- a/e2fsck/pass5.c
+++ b/e2fsck/pass5.c
@@ -65,8 +65,10 @@
 	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 @@
 		}
 		pctx.blk = i;
 		fix_problem(ctx, problem, &pctx);
+		ctx->flags |= E2F_FLAG_PROG_SUPPRESS;
 		had_problem++;
 		
 	do_counts:
@@ -166,6 +169,8 @@
 		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 @@
 		}
 		pctx.ino = i;
 		fix_problem(ctx, problem, &pctx);
+		ctx->flags |= E2F_FLAG_PROG_SUPPRESS;
 		had_problem++;
 		
 do_counts:
@@ -312,6 +318,8 @@
 		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 ed8082d..e33a814 100644
--- a/e2fsck/unix.c
+++ b/e2fsck/unix.c
@@ -18,6 +18,7 @@
 #include <ctype.h>
 #include <termios.h>
 #include <time.h>
+#include <signal.h>
 #ifdef HAVE_GETOPT_H
 #include <getopt.h>
 #endif
@@ -60,7 +61,8 @@
 	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 @@
 #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 @@
 /*
  * 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 @@
 		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 @@
 	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 @@
 	char		*oldpath = getenv("PATH");
 	e2fsck_t	ctx;
 	errcode_t	retval;
+	struct sigaction	sa;
 
 	retval = e2fsck_allocate_context(&ctx);
 	if (retval)
@@ -407,8 +490,6 @@
 	    !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 @@
 			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 @@
 			"(%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 @@
 	}
 
 	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);