113
116
/* If true, print a grand total at the end. */
114
117
static bool print_grand_total;
116
/* Grand total data. */
119
/* Grand total data. */
117
120
static struct fs_usage grand_fsu;
119
122
/* Display modes. */
120
enum { DEFAULT_MODE, INODES_MODE, HUMAN_MODE, POSIX_MODE, NMODES };
121
131
static int header_mode = DEFAULT_MODE;
123
133
/* Displayable fields. */
126
DEV_FIELD, /* file system */
127
TYPE_FIELD, /* FS type */
128
TOTAL_FIELD, /* blocks or inodes */
129
USED_FIELD, /* ditto */
130
FREE_FIELD, /* ditto */
131
PCENT_FIELD, /* percent used */
132
MNT_FIELD, /* mount point */
136
/* Header strings for the above fields in each mode.
137
NULL means to use the header for the default mode. */
138
static const char *headers[NFIELDS][NMODES] = {
139
/* DEFAULT_MODE INODES_MODE HUMAN_MODE POSIX_MODE */
140
{ N_("Filesystem"), NULL, NULL, NULL },
141
{ N_("Type"), NULL, NULL, NULL },
142
{ N_("blocks"), N_("Inodes"), N_("Size"), NULL },
143
{ N_("Used"), N_("IUsed"), NULL, NULL },
144
{ N_("Available"), N_("IFree"), N_("Avail"), NULL },
145
{ N_("Use%"), N_("IUse%"), NULL, N_("Capacity") },
146
{ N_("Mounted on"), NULL, NULL, NULL }
149
/* Alignments for the 3 textual and 4 numeric fields. */
150
static mbs_align_t alignments[NFIELDS] = {
151
MBS_ALIGN_LEFT, MBS_ALIGN_LEFT,
152
MBS_ALIGN_RIGHT, MBS_ALIGN_RIGHT, MBS_ALIGN_RIGHT, MBS_ALIGN_RIGHT,
156
/* Auto adjusted (up) widths used to align columns. */
157
static size_t widths[NFIELDS] = { 14, 4, 5, 5, 5, 4, 0 };
136
SOURCE_FIELD, /* file system */
137
FSTYPE_FIELD, /* FS type */
138
SIZE_FIELD, /* FS size */
139
USED_FIELD, /* FS size used */
140
AVAIL_FIELD, /* FS size available */
141
PCENT_FIELD, /* percent used */
142
ITOTAL_FIELD, /* inode total */
143
IUSED_FIELD, /* inodes used */
144
IAVAIL_FIELD, /* inodes available */
145
IPCENT_FIELD, /* inodes used in percent */
146
TARGET_FIELD /* mount point */
149
/* Flag if a field contains a block, an inode or another value. */
152
BLOCK_FLD, /* Block values field */
153
INODE_FLD, /* Inode values field */
154
OTHER_FLD /* Neutral field, e.g. target */
157
/* Attributes of a display field. */
160
display_field_t field;
162
field_type_t field_type;
163
const char *caption;/* NULL means to use the default header of this field. */
164
size_t width; /* Auto adjusted (up) widths used to align columns. */
165
mbs_align_t align; /* Alignment for this field. */
169
/* Header strings, minimum width and alignment for the above fields. */
170
static struct field_data_t field_data[] = {
171
[SOURCE_FIELD] = { SOURCE_FIELD,
172
"source", OTHER_FLD, N_("Filesystem"), 14, MBS_ALIGN_LEFT, false },
174
[FSTYPE_FIELD] = { FSTYPE_FIELD,
175
"fstype", OTHER_FLD, N_("Type"), 4, MBS_ALIGN_LEFT, false },
177
[SIZE_FIELD] = { SIZE_FIELD,
178
"size", BLOCK_FLD, N_("blocks"), 5, MBS_ALIGN_RIGHT, false },
180
[USED_FIELD] = { USED_FIELD,
181
"used", BLOCK_FLD, N_("Used"), 5, MBS_ALIGN_RIGHT, false },
183
[AVAIL_FIELD] = { AVAIL_FIELD,
184
"avail", BLOCK_FLD, N_("Available"), 5, MBS_ALIGN_RIGHT, false },
186
[PCENT_FIELD] = { PCENT_FIELD,
187
"pcent", BLOCK_FLD, N_("Use%"), 4, MBS_ALIGN_RIGHT, false },
189
[ITOTAL_FIELD] = { ITOTAL_FIELD,
190
"itotal", INODE_FLD, N_("Inodes"), 5, MBS_ALIGN_RIGHT, false },
192
[IUSED_FIELD] = { IUSED_FIELD,
193
"iused", INODE_FLD, N_("IUsed"), 5, MBS_ALIGN_RIGHT, false },
195
[IAVAIL_FIELD] = { IAVAIL_FIELD,
196
"iavail", INODE_FLD, N_("IFree"), 5, MBS_ALIGN_RIGHT, false },
198
[IPCENT_FIELD] = { IPCENT_FIELD,
199
"ipcent", INODE_FLD, N_("IUse%"), 4, MBS_ALIGN_RIGHT, false },
201
[TARGET_FIELD] = { TARGET_FIELD,
202
"target", OTHER_FLD, N_("Mounted on"), 0, MBS_ALIGN_LEFT, false }
205
static char const *all_args_string =
206
"source,fstype,itotal,iused,iavail,ipcent,size,used,avail,pcent,target";
208
/* Storage for the definition of output columns. */
209
static struct field_data_t **columns;
211
/* The current number of output columns. */
212
static size_t ncolumns;
215
struct field_values_t
217
uintmax_t input_units;
218
uintmax_t output_units;
221
bool negate_available;
222
uintmax_t available_to_root;
159
227
/* Storage for pointers for each string (cell of table). */
160
228
static char ***table;
180
250
{"si", no_argument, NULL, 'H'},
181
251
{"local", no_argument, NULL, 'l'},
182
252
{"megabytes", no_argument, NULL, MEGABYTES_OPTION}, /* obsolescent, */
253
{"output", optional_argument, NULL, OUTPUT_OPTION},
183
254
{"portability", no_argument, NULL, 'P'},
184
255
{"print-type", no_argument, NULL, 'T'},
185
256
{"sync", no_argument, NULL, SYNC_OPTION},
186
257
{"no-sync", no_argument, NULL, NO_SYNC_OPTION},
187
{"total", no_argument, NULL, 'c'},
258
{"total", no_argument, NULL, TOTAL_OPTION},
188
259
{"type", required_argument, NULL, 't'},
189
260
{"exclude-type", required_argument, NULL, 'x'},
190
261
{GETOPT_HELP_OPTION_DECL},
227
298
print_table (void)
231
for (row = 0; row < nrows; row ++)
302
for (row = 0; row < nrows; row++)
233
for (field = 0; field < NFIELDS; field++)
305
for (col = 0; col < ncolumns; col++)
235
size_t width = widths[field];
236
char *cell = table[row][field];
237
if (!cell) /* Missing type column, or mount point etc. */
307
char *cell = table[row][col];
240
/* Note the DEV_FIELD used to be displayed on it's own line
309
/* Note the SOURCE_FIELD used to be displayed on it's own line
241
310
if (!posix_format && mbswidth (cell) > 20), but that
242
functionality is probably more problematic than helpful. */
311
functionality was probably more problematic than helpful,
312
hence changed in commit v8.10-40-g99679ff. */
245
if (field == MNT_FIELD) /* The last one. */
246
fputs (cell, stdout);
249
cell = ambsalign (cell, &width, alignments[field], 0);
250
/* When ambsalign fails, output unaligned data. */
251
fputs (cell ? cell : table[row][field], stdout);
254
IF_LINT (free (table[row][field]));
317
if (col == ncolumns - 1) /* The last one. */
318
flags = MBA_NO_RIGHT_PAD;
320
size_t width = columns[col]->width;
321
cell = ambsalign (cell, &width, columns[col]->align, flags);
322
/* When ambsalign fails, output unaligned data. */
323
fputs (cell ? cell : table[row][col], stdout);
326
IF_LINT (free (table[row][col]));
257
329
IF_LINT (free (table[row]));
260
332
IF_LINT (free (table));
335
/* Dynamically allocate a struct field_t in COLUMNS, which
336
can then be accessed with standard array notation. */
339
alloc_field (int f, const char *c)
342
columns = xnrealloc (columns, ncolumns, sizeof (struct field_data_t *));
343
columns[ncolumns - 1] = &field_data[f];
345
columns[ncolumns - 1]->caption = c;
347
if (field_data[f].used)
348
assert (!"field used");
350
/* Mark field as used. */
351
field_data[f].used = true;
355
/* Given a string, ARG, containing a comma-separated list of arguments
356
to the --output option, add the appropriate fields to columns. */
358
decode_output_arg (char const *arg)
360
char *arg_writable = xstrdup (arg);
361
char *s = arg_writable;
364
/* find next comma */
365
char *comma = strchr (s, ',');
367
/* If we found a comma, put a NUL in its place and advance. */
372
display_field_t field = -1;
373
for (unsigned int i = 0; i < ARRAY_CARDINALITY (field_data); i++)
375
if (STREQ (field_data[i].arg, s))
383
error (0, 0, _("option --output: field '%s' unknown"), s);
384
usage (EXIT_FAILURE);
387
if (field_data[field].used)
389
/* Prevent the fields from being used more than once. */
390
error (0, 0, _("option --output: field '%s' used more than once"),
391
field_data[field].arg);
392
usage (EXIT_FAILURE);
406
alloc_field (field, NULL);
410
alloc_field (field, N_("Size"));
414
alloc_field (field, N_("Avail"));
418
assert (!"invalid field");
427
/* Get the appropriate columns for the mode. */
429
get_field_list (void)
434
alloc_field (SOURCE_FIELD, NULL);
436
alloc_field (FSTYPE_FIELD, NULL);
437
alloc_field (SIZE_FIELD, NULL);
438
alloc_field (USED_FIELD, NULL);
439
alloc_field (AVAIL_FIELD, NULL);
440
alloc_field (PCENT_FIELD, NULL);
441
alloc_field (TARGET_FIELD, NULL);
445
alloc_field (SOURCE_FIELD, NULL);
447
alloc_field (FSTYPE_FIELD, NULL);
449
alloc_field (SIZE_FIELD, N_("Size"));
450
alloc_field (USED_FIELD, NULL);
451
alloc_field (AVAIL_FIELD, N_("Avail"));
452
alloc_field (PCENT_FIELD, NULL);
453
alloc_field (TARGET_FIELD, NULL);
457
alloc_field (SOURCE_FIELD, NULL);
459
alloc_field (FSTYPE_FIELD, NULL);
460
alloc_field (ITOTAL_FIELD, NULL);
461
alloc_field (IUSED_FIELD, NULL);
462
alloc_field (IAVAIL_FIELD, NULL);
463
alloc_field (IPCENT_FIELD, NULL);
464
alloc_field (TARGET_FIELD, NULL);
468
alloc_field (SOURCE_FIELD, NULL);
470
alloc_field (FSTYPE_FIELD, NULL);
471
alloc_field (SIZE_FIELD, NULL);
472
alloc_field (USED_FIELD, NULL);
473
alloc_field (AVAIL_FIELD, NULL);
474
alloc_field (PCENT_FIELD, N_("Capacity"));
475
alloc_field (TARGET_FIELD, NULL);
481
/* Add all fields if --output was given without a field list. */
482
decode_output_arg (all_args_string);
487
assert (!"invalid header_mode");
263
491
/* Obtain the appropriate header entries. */
266
494
get_header (void)
270
498
alloc_table_row ();
272
for (field = 0; field < NFIELDS; field++)
500
for (col = 0; col < ncolumns; col++)
274
if (field == TYPE_FIELD && !print_type)
276
table[nrows-1][field] = NULL;
280
502
char *cell = NULL;
281
char const *header = _(headers[field][header_mode]);
283
header = _(headers[field][DEFAULT_MODE]);
503
char const *header = _(columns[col]->caption);
285
if (header_mode == DEFAULT_MODE && field == TOTAL_FIELD)
505
if (columns[col]->field == SIZE_FIELD
506
&& (header_mode == DEFAULT_MODE
507
|| (header_mode == OUTPUT_MODE
508
&& !(human_output_opts & human_autoscale))))
287
510
char buf[LONGEST_HUMAN_READABLE + 1];
601
/* Filter mount list by skipping duplicate entries.
602
In the case of duplicities - based on to the device number - the mount entry
603
with a '/' in its me_devname (i.e. not pseudo name like tmpfs) wins.
604
If both have a real devname (e.g. bind mounts), then that with the shorter
608
filter_mount_list (void)
610
struct mount_entry *me;
612
/* Store of already-processed device numbers. */
613
struct devlist *devlist_head = NULL;
615
/* Sort all 'wanted' entries into the list devlist_head. */
616
for (me = mount_list; me; me = me->me_next)
619
struct devlist *devlist;
621
if (-1 == stat (me->me_mountdir, &buf))
623
; /* Stat failed - add ME to be able to complain about it later. */
627
/* If the device name is a real path name ... */
628
if (strchr (me->me_devname, '/'))
630
/* ... try to find its device number in the devlist. */
631
for (devlist = devlist_head; devlist; devlist = devlist->next)
632
if (devlist->dev_num == buf.st_dev)
637
/* Let the shorter mountdir win. */
638
if ( !strchr (devlist->me->me_devname, '/')
639
|| ( strlen (devlist->me->me_mountdir)
640
> strlen (me->me_mountdir)))
642
/* FIXME: free ME - the others are also not free()d. */
645
continue; /* ... with the loop over the mount_list. */
650
/* Add the device number to the global list devlist. */
651
devlist = xmalloc (sizeof *devlist);
653
devlist->dev_num = buf.st_dev;
654
devlist->next = devlist_head;
655
devlist_head = devlist;
658
/* Finally rebuild the mount_list from the devlist. */
662
/* Add the mount entry. */
663
me = devlist_head->me;
664
me->me_next = mount_list;
666
/* Free devlist entry and advance. */
667
struct devlist *devlist = devlist_head->next;
669
devlist_head = devlist;
375
673
/* Return true if N is a known integer value. On many file systems,
376
674
UINTMAX_MAX represents an unknown value; on AIX, UINTMAX_MAX - 1
377
675
represents unknown. Use a rule that works on AIX file systems, and
451
749
&& strspn (s + len - 36, "-0123456789abcdefABCDEF") == 36);
752
/* Obtain the block values BV and inode values IV
753
from the file system usage FSU. */
755
get_field_values (struct field_values_t *bv,
756
struct field_values_t *iv,
757
const struct fs_usage *fsu)
760
iv->input_units = iv->output_units = 1;
761
iv->total = fsu->fsu_files;
762
iv->available = iv->available_to_root = fsu->fsu_ffree;
763
iv->negate_available = false;
765
iv->used = UINTMAX_MAX;
766
iv->negate_used = false;
767
if (known_value (iv->total) && known_value (iv->available_to_root))
769
iv->used = iv->total - iv->available_to_root;
770
iv->negate_used = (iv->total < iv->available_to_root);
774
bv->input_units = fsu->fsu_blocksize;
775
bv->output_units = output_block_size;
776
bv->total = fsu->fsu_blocks;
777
bv->available = fsu->fsu_bavail;
778
bv->available_to_root = fsu->fsu_bfree;
779
bv->negate_available = (fsu->fsu_bavail_top_bit_set
780
&& known_value (fsu->fsu_bavail));
782
bv->used = UINTMAX_MAX;
783
bv->negate_used = false;
784
if (known_value (bv->total) && known_value (bv->available_to_root))
786
bv->used = bv->total - bv->available_to_root;
787
bv->negate_used = (bv->total < bv->available_to_root);
791
/* Add block and inode values to grand total. */
793
add_to_grand_total (struct field_values_t *bv, struct field_values_t *iv)
795
if (known_value (iv->total))
796
grand_fsu.fsu_files += iv->total;
797
if (known_value (iv->available))
798
grand_fsu.fsu_ffree += iv->available;
800
if (known_value (bv->total))
801
grand_fsu.fsu_blocks += bv->input_units * bv->total;
802
if (known_value (bv->available_to_root))
803
grand_fsu.fsu_bfree += bv->input_units * bv->available_to_root;
804
if (known_value (bv->available))
805
add_uint_with_neg_flag (&grand_fsu.fsu_bavail,
806
&grand_fsu.fsu_bavail_top_bit_set,
807
bv->input_units * bv->available,
808
bv->negate_available);
454
811
/* Obtain a space listing for the disk device with absolute file name DISK.
455
812
If MOUNT_POINT is non-NULL, it is the name of the root of the
456
813
file system on DISK.
548
888
fstype = "-"; /* unknown */
552
input_units = output_units = 1;
553
total = fsu.fsu_files;
554
available = fsu.fsu_ffree;
555
negate_available = false;
556
available_to_root = available;
558
if (known_value (total))
559
grand_fsu.fsu_files += total;
560
if (known_value (available))
561
grand_fsu.fsu_ffree += available;
565
input_units = fsu.fsu_blocksize;
566
output_units = output_block_size;
567
total = fsu.fsu_blocks;
568
available = fsu.fsu_bavail;
569
negate_available = (fsu.fsu_bavail_top_bit_set
570
&& known_value (available));
571
available_to_root = fsu.fsu_bfree;
573
if (known_value (total))
574
grand_fsu.fsu_blocks += input_units * total;
575
if (known_value (available_to_root))
576
grand_fsu.fsu_bfree += input_units * available_to_root;
577
if (known_value (available))
578
add_uint_with_neg_flag (&grand_fsu.fsu_bavail,
579
&grand_fsu.fsu_bavail_top_bit_set,
580
input_units * available, negate_available);
585
if (known_value (total) && known_value (available_to_root))
587
used = total - available_to_root;
588
negate_used = (total < available_to_root);
591
for (field = 0; field < NFIELDS; field++)
600
cell = print_type ? xstrdup (fstype) : NULL;
604
cell = xstrdup (df_readable (false, total, buf,
605
input_units, output_units));
890
struct field_values_t block_values;
891
struct field_values_t inode_values;
892
get_field_values (&block_values, &inode_values, &fsu);
894
/* Add to grand total unless processing grand total line. */
895
if (print_grand_total && ! force_fsu)
896
add_to_grand_total (&block_values, &inode_values);
899
for (col = 0; col < ncolumns; col++)
901
char buf[LONGEST_HUMAN_READABLE + 2];
904
struct field_values_t *v;
905
switch (columns[col]->field_type)
917
assert (!"bad field_type");
920
switch (columns[col]->field)
923
cell = xstrdup (dev_name);
927
cell = xstrdup (fstype);
932
cell = xstrdup (df_readable (false, v->total, buf,
933
v->input_units, v->output_units));
608
cell = xstrdup (df_readable (negate_used, used, buf,
609
input_units, output_units));
938
cell = xstrdup (df_readable (v->negate_used, v->used, buf,
939
v->input_units, v->output_units));
612
cell = xstrdup (df_readable (negate_available, available, buf,
613
input_units, output_units));
944
cell = xstrdup (df_readable (v->negate_available, v->available, buf,
945
v->input_units, v->output_units));
616
948
case PCENT_FIELD:
617
if (! known_value (used) || ! known_value (available))
619
else if (!negate_used
620
&& used <= TYPE_MAXIMUM (uintmax_t) / 100
621
&& used + available != 0
622
&& (used + available < used) == negate_available)
624
uintmax_t u100 = used * 100;
625
uintmax_t nonroot_total = used + available;
626
pct = u100 / nonroot_total + (u100 % nonroot_total != 0);
630
/* The calculation cannot be done easily with integer
631
arithmetic. Fall back on floating point. This can suffer
632
from minor rounding errors, but doing it exactly requires
633
multiple precision arithmetic, and it's not worth the
635
double u = negate_used ? - (double) - used : used;
636
double a = negate_available ? - (double) - available : available;
637
double nonroot_total = u + a;
640
long int lipct = pct = u * 100 / nonroot_total;
643
/* Like 'pct = ceil (dpct);', but avoid ceil so that
644
the math library needn't be linked. */
645
if (ipct - 1 < pct && pct <= ipct + 1)
646
pct = ipct + (ipct < pct);
652
if (asprintf (&cell, "%.0f%%", pct) == -1)
952
if (! known_value (v->used) || ! known_value (v->available))
954
else if (!v->negate_used
955
&& v->used <= TYPE_MAXIMUM (uintmax_t) / 100
956
&& v->used + v->available != 0
957
&& (v->used + v->available < v->used)
958
== v->negate_available)
960
uintmax_t u100 = v->used * 100;
961
uintmax_t nonroot_total = v->used + v->available;
962
pct = u100 / nonroot_total + (u100 % nonroot_total != 0);
966
/* The calculation cannot be done easily with integer
967
arithmetic. Fall back on floating point. This can suffer
968
from minor rounding errors, but doing it exactly requires
969
multiple precision arithmetic, and it's not worth the
971
double u = v->negate_used ? - (double) - v->used : v->used;
972
double a = v->negate_available
973
? - (double) - v->available : v->available;
974
double nonroot_total = u + a;
977
long int lipct = pct = u * 100 / nonroot_total;
980
/* Like 'pct = ceil (dpct);', but avoid ceil so that
981
the math library needn't be linked. */
982
if (ipct - 1 < pct && pct <= ipct + 1)
983
pct = ipct + (ipct < pct);
989
if (asprintf (&cell, "%.0f%%", pct) == -1)
666
1002
#ifdef HIDE_AUTOMOUNT_PREFIX
667
/* Don't print the first directory name in MOUNT_POINT if it's an
668
artifact of an automounter. This is a bit too aggressive to be
670
if (STRNCMP_LIT (mount_point, "/auto/") == 0)
672
else if (STRNCMP_LIT (mount_point, "/tmp_mnt/") == 0)
1003
/* Don't print the first directory name in MOUNT_POINT if it's an
1004
artifact of an automounter. This is a bit too aggressive to be
1006
if (STRNCMP_LIT (mount_point, "/auto/") == 0)
1008
else if (STRNCMP_LIT (mount_point, "/tmp_mnt/") == 0)
675
cell = xstrdup (mount_point);
1011
cell = xstrdup (mount_point);
682
1015
assert (!"unhandled field");
687
hide_problematic_chars (cell);
688
widths[field] = MAX (widths[field], mbswidth (cell, 0));
690
table[nrows-1][field] = cell;
1019
assert (!"empty cell");
1021
hide_problematic_chars (cell);
1022
columns[col]->width = MAX (columns[col]->width, mbswidth (cell, 0));
1023
table[nrows - 1][col] = cell;
694
1028
/* If DISK corresponds to a mount point, show its usage