badblocks: Add options for parseable status output

Message ID f7c3f906-e96d-a35c-e068-495f286ab2ee@keepertech.com
State New
Headers show
Series
  • badblocks: Add options for parseable status output
Related show

Commit Message

Wyllys Ingersoll Feb. 21, 2018, 6:55 p.m.
(2nd attempt submitting this patch due to white space issues):

Add new command line arguments for badblocks utility:   
    -a alarm_interval       
    -P

alarm_interval controls the frequency of the status update output.
-P makes the output more parseable by external programs (comma separated,
LF terminated)

Signed-off-by: Wyllys Ingersoll <wyllys.ingersoll@keepertech.com>
---

                          * number of bad blocks has been
                          * encountered */
@@ -97,9 +99,10 @@ static unsigned int sys_page_size = 4096;
 static void usage(void)
 {
     fprintf(stderr, _(
-"Usage: %s [-b block_size] [-i input_file] [-o output_file] [-svwnfBX]\n"
+"Usage: %s [-b block_size] [-i input_file] [-o output_file] [-svwnfBPX]\n"
 "       [-c blocks_at_once] [-d delay_factor_between_reads] [-e
max_bad_blocks]\n"
 "       [-p num_passes] [-t test_pattern [-t test_pattern [...]]]\n"
+"       [-a alarm_interval]\n"
 "       device [last_block [first_block]]\n"),
          program_name);
     exit (1);
@@ -223,17 +226,23 @@ static void print_status(void)
     wchar_t wline_buf[128];
 #endif
     int len;
+    char format_str[128];
+
+    if (parseable_output) {
+        strcpy(format_str, "%6.2f, %s, %d, %d, %d");
+    } else {
+        strcpy(format_str, "%6.2f%% done, %s elapsed. (%d/%d/%d errors)");
+    }
 
     gettimeofday(&time_end, 0);
     len = snprintf(line_buf, sizeof(line_buf),
-               _("%6.2f%% done, %s elapsed. "
-                 "(%d/%d/%d errors)"),
-               calc_percent((unsigned long) currently_testing,
-                    (unsigned long) num_blocks),
-               time_diff_format(&time_end, &time_start, diff_buf),
-               num_read_errors,
-               num_write_errors,
-               num_corruption_errors);
+            _(format_str),
+            calc_percent((unsigned long) currently_testing,
+            (unsigned long) num_blocks),
+            time_diff_format(&time_end, &time_start, diff_buf),
+            num_read_errors,
+            num_write_errors,
+            num_corruption_errors);
 #ifdef HAVE_MBSTOWCS
     mbstowcs(wline_buf, line_buf, sizeof(line_buf));
     len = wcswidth(wline_buf, sizeof(line_buf));
@@ -241,16 +250,20 @@ static void print_status(void)
         len = strlen(line_buf); /* Should never happen... */
 #endif
     fputs(line_buf, stderr);
-    memset(line_buf, '\b', len);
-    line_buf[len] = 0;
-    fputs(line_buf, stderr);   
+    if (!parseable_output) {
+        memset(line_buf, '\b', len);
+        line_buf[len] = 0;
+        fputs(line_buf, stderr);
+    } else {
+        fputs("\n", stderr);
+    }
     fflush (stderr);
 }
 
 static void alarm_intr(int alnum EXT2FS_ATTR((unused)))
 {
     signal (SIGALRM, alarm_intr);
-    alarm(1);
+    alarm(alarm_interval);
     if (!num_blocks)
         return;
     print_status();
@@ -1094,7 +1107,7 @@ int main (int argc, char ** argv)
 
     if (argc && *argv)
         program_name = *argv;
-    while ((c = getopt (argc, argv, "b:d:e:fi:o:svwnc:p:h:t:BX")) != EOF) {
+    while ((c = getopt (argc, argv, "a:b:d:e:fi:o:svwnc:p:h:t:BXP")) !=
EOF) {
         switch (c) {
         case 'b':
             block_size = parse_uint(optarg, "block size");
@@ -1183,6 +1196,17 @@ int main (int argc, char ** argv)
         case 'X':
             exclusive_ok++;
             break;
+        case 'P':
+            parseable_output = 1;
+            break;
+        case 'a':
+            alarm_interval = parse_uint(optarg, "status alarm interval
(seconds)");
+            if (alarm_interval == 0) {
+                com_err(program_name, 0, "%s",
+                    _("Minimum alarm interval is 1 second"));
+                exit(1);
+            }
+            break;
         default:
             usage();
         }

Patch

diff --git a/misc/badblocks.8.in b/misc/badblocks.8.in
index ca43593..043e420 100644
--- a/misc/badblocks.8.in
+++ b/misc/badblocks.8.in
@@ -5,7 +5,11 @@  badblocks \- search a device for bad blocks
 .SH SYNOPSIS
 .B badblocks
 [
-.B \-svwnfBX
+.B \-svwnfBXP
+]
+[
+.B \-a
+.I alarm_interval
 ]
 [
 .B \-b
@@ -83,6 +87,9 @@  and
 programs.
 .SH OPTIONS
 .TP
+.BI \-a " alarm_interval"
+Interval (in seconds) used for displaying status updates. The default is 1.
+.TP
 .BI \-b " block_size"
 Specify the size of blocks in bytes.  The default is 1024.
 .TP
@@ -199,6 +206,13 @@  option, as they are mutually exclusive.
 .B \-B
 Use buffered I/O and do not use Direct I/O, even if it is available.
 .TP
+.B \-P
+Display status in machine parseable format. The data is comma separated and
+LF terminated to make it easier to parsing by external applications. The
+data format is:
+% completed, time elapsed, read errors, write errors, corruption errors.
+Example: 10.06, 1:22, 0, 0, 0
+.TP
 .B \-X
 Internal flag only to be used by
 .BR e2fsck (8)
diff --git a/misc/badblocks.c b/misc/badblocks.c
index 44252dc..cddd591 100644
--- a/misc/badblocks.c
+++ b/misc/badblocks.c
@@ -84,6 +84,8 @@  static int t_max;            /* allocated test patterns */
 static unsigned int *t_patts;        /* test patterns */
 static int use_buffered_io;
 static int exclusive_ok;
+static int parseable_output = 0;  /* print output that can be easily
parsed */
+static int alarm_interval = 1;
 static unsigned int max_bb = MAX_BAD_BLOCKS;    /* Abort test if more
than this