I gave up on vc-dwim and send you my patch this way.
I think the first few lines  are not proper "patch/diff" format.
Sorry.

I hope the texinfo documentation will suffice to explain.

Best regards
Gunnar
df: Introduce new b and f options which will allow easier scripting when checking if there is enough diskspace

* doc/coreutils.texi: Documentation about new -b and -f options
* src/df.c (exit_status, percentage_free_requirement)
(quit_on_low_percentage, bytes_free_requirement)
(quit_on_low_bytes, long_options, get_dev, usage, main): Handle new -b and -f options by suppressing output and return after first compare

diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index 4d7d9439d..aac63cff3 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -12100,6 +12100,16 @@ Inaccessible file systems are those which are mounted but subsequently
 over-mounted by another file system at that point, or otherwise inaccessible
 due to permissions of the mount point etc.

+@item -b @var{size}
+@itemx --bytes-free=@var{size}
+@opindex -b
+@opindex --bytes-free
+@cindex free file system size
+This option requires the user to specify exactly one @var{file} argument. df
+will then determine if the corresponding filesystem has atleast @var{size} bytes
+of available space. If so df will return 0 and produce no output, otherwise the
+return code will be 1 and produce no output.
+
 @item -B @var{size}
 @itemx --block-size=@var{size}
 @opindex -B
@@ -12108,6 +12118,14 @@ due to permissions of the mount point etc.
 Scale sizes by @var{size} before printing them (@pxref{Block size}).
 For example, @option{-BG} prints sizes in units of 1,073,741,824 bytes.

+@item -f @var{percentage}
+@itemx --free=@var{percentage}
+@opindex -f
+@opindex --free
+@cindex free file system size
+This option works exactly as the @option{-b} with the difference that it checks
+if atleast @var{percentage} of the filesystem is available.
+
 @optHumanReadable

 @item -H
@@ -12343,6 +12361,10 @@ inspect the exit status of a command like @samp{df -t ext3 -t reiserfs
 @var{dir}} to test whether @var{dir} is on a file system of type
 @samp{ext3} or @samp{reiserfs}.

+With the @option{-b} and @option{-f} options one can use the exit status to
+verify the available space (in bytes or percentage) with a command like
+@samp{if df -b 640000 /var/log ; then echo "That is big enough for everyone"; fi}
+
 Since the list of file systems (@var{mtab}) is needed to determine the
 file system type, failure includes the cases when that list cannot
 be read and one or more of the options @option{-a}, @option{-l}, @option{-t}
diff --git a/src/df.c b/src/df.c
index f3d8e2e2b..6aeee11d2 100644
--- a/src/df.c
+++ b/src/df.c
@@ -90,6 +90,18 @@ static bool require_sync;
 /* Desired exit status.  */
 static int exit_status;

+/* Required percentage disk free on all examined filesystems*/
+static uintmax_t percentage_free_requirement;
+
+/* Should we quit if the percentage is below percentage_free_requirement?*/
+static bool quit_on_low_percentage;
+
+/* Required number of bytes disk free on all examined filesystems*/
+static uintmax_t bytes_free_requirement;
+
+/* Should we quit if the number of bytes is below bytes_free_requirement?*/
+static bool quit_on_low_bytes;
+
 /* A file system type to display.  */

 struct fs_type_list
@@ -271,6 +283,8 @@ static struct option const long_options[] =
   {"total", no_argument, NULL, TOTAL_OPTION},
   {"type", required_argument, NULL, 't'},
   {"exclude-type", required_argument, NULL, 'x'},
+  {"free", required_argument, NULL, 'f'},
+  {"free-bytes", required_argument, NULL, 'b'},
   {GETOPT_HELP_OPTION_DECL},
   {GETOPT_VERSION_OPTION_DECL},
   {NULL, 0, NULL, 0}
@@ -1125,6 +1139,72 @@ get_dev (char const *device, char const *mount_point, char const *file,
   struct field_values_t inode_values;
   get_field_values (&block_values, &inode_values, &fsu);

+  /* If this is set, then we either fail directly or just return from the function since it fullfilled the space requirements */
+  if (quit_on_low_bytes)
+    {
+      /* This code is basically a copy of the code for the percentage calculation below */
+      struct field_values_t *v;
+
+      v = &block_values;
+      if (! known_value (v->used) || ! known_value (v->available))
+        main_exit (1);
+
+      if (bytes_free_requirement <= v->available * v->input_units)
+         return;
+      else
+        main_exit (1);
+    }
+  else if (quit_on_low_percentage)
+    {
+      /* This code is basically a copy of the code for the percentage calculation below */
+      double pct = -1;
+      struct field_values_t *v;
+
+      v = &block_values;
+      if (! known_value (v->used) || ! known_value (v->available))
+        main_exit (1);
+      else if (!v->negate_used
+                && v->used <= TYPE_MAXIMUM (uintmax_t) / 100
+                && v->used + v->available != 0
+                && (v->used + v->available < v->used)
+                == v->negate_available)
+        {
+          uintmax_t u100 = v->used * 100;
+          uintmax_t nonroot_total = v->used + v->available;
+          pct = u100 / nonroot_total + (u100 % nonroot_total != 0);
+        }
+      else
+        {
+          /* The calculation cannot be done easily with integer
+              arithmetic.  Fall back on floating point.  This can suffer
+              from minor rounding errors, but doing it exactly requires
+              multiple precision arithmetic, and it's not worth the
+              aggravation.  */
+          double u = v->negate_used ? - (double) - v->used : v->used;
+          double a = v->negate_available
+                      ? - (double) - v->available : v->available;
+          double nonroot_total = u + a;
+          if (nonroot_total)
+            {
+              long int lipct = pct = u * 100 / nonroot_total;
+              double ipct = lipct;
+
+              /* Like 'pct = ceil (dpct);', but avoid ceil so that
+                  the math library needn't be linked.  */
+              if (ipct - 1 < pct && pct <= ipct + 1)
+                pct = ipct + (ipct < pct);
+            }
+        }
+
+      if (percentage_free_requirement <= 100 - pct)
+       {
+         free (dev_name);
+         return;
+       }
+      else
+        main_exit (1);
+    }
+
   /* Add to grand total unless processing grand total line.  */
   if (print_grand_total && ! force_fsu)
     add_to_grand_total (&block_values, &inode_values);
@@ -1565,6 +1645,16 @@ or all file systems by default.\n\
       fputs (_("\
       --total           elide all entries insignificant to available space,\n\
                           and produce a grand total\n\
+"), stdout);
+      fputs (_("\
+  -f, --free=PERCENTAGE  Produce no output and return 1 if there is any specified device with\n\
+                        less than PERCENTAGE % bytes free, else return 0. You must specify\n\
+                        exactly one FILE with this option and no other options\n\
+"), stdout);
+      fputs (_("\
+  -b, --free-bytes=BYTES  Produce no output and return 1 if there is any specified device with\n\
+                        less than BYTES bytes free, else return 0. You must specify\n\
+                        exactly one FILE with this option and no other options\n\
 "), stdout);
       fputs (_("\
   -t, --type=TYPE       limit listing to file systems of type TYPE\n\
@@ -1599,6 +1689,10 @@ main (int argc, char **argv)

   atexit (close_stdout);

+  percentage_free_requirement = 0;
+  bytes_free_requirement = 0;
+  quit_on_low_percentage = false;
+  quit_on_low_bytes = false;
   fs_select_list = NULL;
   fs_exclude_list = NULL;
   show_all_fs = false;
@@ -1618,7 +1712,7 @@ main (int argc, char **argv)
   while (true)
     {
       int oi = -1;
-      int c = getopt_long (argc, argv, "aB:iF:hHklmPTt:vx:", long_options,
+      int c = getopt_long (argc, argv, "aB:iF:f:b:hHklmPTt:vx:", long_options,
                            &oi);
       if (c == -1)
         break;
@@ -1636,6 +1730,24 @@ main (int argc, char **argv)
               xstrtol_fatal (e, oi, c, long_options, optarg);
           }
           break;
+        case 'f':
+          {
+            enum strtol_error e = human_options (optarg, &human_output_opts,
+                                                 &percentage_free_requirement);
+            if (e != LONGINT_OK)
+              xstrtol_fatal (e, oi, c, long_options, optarg);
+            quit_on_low_percentage = true;
+            break;
+          }
+        case 'b':
+          {
+            enum strtol_error e = human_options (optarg, &human_output_opts,
+                                                 &bytes_free_requirement);
+            if (e != LONGINT_OK)
+              xstrtol_fatal (e, oi, c, long_options, optarg);
+            quit_on_low_bytes = true;
+            break;
+          }
         case 'i':
           if (header_mode == OUTPUT_MODE)
             {
@@ -1732,24 +1844,31 @@ main (int argc, char **argv)
         }
     }

-  if (human_output_opts == -1)
+  if ( (quit_on_low_percentage || quit_on_low_bytes) && (argc != 4 )) {
+    usage (EXIT_FAILURE);
+  }
+
+  if (!quit_on_low_percentage && !quit_on_low_bytes)
     {
-      if (posix_format)
+      if (human_output_opts == -1)
         {
-          human_output_opts = 0;
-          output_block_size = (getenv ("POSIXLY_CORRECT") ? 512 : 1024);
+          if (posix_format)
+            {
+              human_output_opts = 0;
+              output_block_size = (getenv ("POSIXLY_CORRECT") ? 512 : 1024);
+            }
+          else
+            human_options (getenv ("DF_BLOCK_SIZE"),
+                          &human_output_opts, &output_block_size);
         }
-      else
-        human_options (getenv ("DF_BLOCK_SIZE"),
-                       &human_output_opts, &output_block_size);
-    }

-  if (header_mode == INODES_MODE || header_mode == OUTPUT_MODE)
-    ;
-  else if (human_output_opts & human_autoscale)
-    header_mode = HUMAN_MODE;
-  else if (posix_format)
-    header_mode = POSIX_MODE;
+        if (header_mode == INODES_MODE || header_mode == OUTPUT_MODE)
+          ;
+        else if (human_output_opts & human_autoscale)
+          header_mode = HUMAN_MODE;
+        else if (posix_format)
+          header_mode = POSIX_MODE;
+    }

   /* Fail if the same file system type was both selected and excluded.  */
   {
@@ -1824,8 +1943,12 @@ main (int argc, char **argv)
   if (require_sync)
     sync ();

-  get_field_list ();
-  get_header ();
+
+  if (!quit_on_low_percentage && !quit_on_low_bytes)
+  {
+    get_field_list ();
+    get_header ();
+  }

   if (stats)
     {
@@ -1846,7 +1969,8 @@ main (int argc, char **argv)
                  (field_data[SOURCE_FIELD].used ? "-" : "total"),
                  NULL, NULL, NULL, false, false, &grand_fsu, false);

-      print_table ();
+      if ( ! quit_on_low_percentage && ! quit_on_low_bytes)
+        print_table ();
     }
   else
     {

Reply via email to