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
{