dd: output final progress before syncing
[coreutils.git] / src / df.c
blobb803fc73bafbb633a433349964c5a6b065a90b9f
1 /* df - summarize free file system space
2 Copyright (C) 1991-2022 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17 /* Written by David MacKenzie <djm@gnu.ai.mit.edu>.
18 --human-readable option added by lm@sgi.com.
19 --si and large file support added by eggert@twinsun.com. */
21 #include <config.h>
22 #include <stdio.h>
23 #include <sys/types.h>
24 #include <getopt.h>
25 #include <assert.h>
26 #include <c-ctype.h>
27 #include <wchar.h>
28 #include <wctype.h>
30 #include "system.h"
31 #include "canonicalize.h"
32 #include "die.h"
33 #include "error.h"
34 #include "fsusage.h"
35 #include "human.h"
36 #include "mbsalign.h"
37 #include "mbswidth.h"
38 #include "mountlist.h"
39 #include "quote.h"
40 #include "find-mount-point.h"
41 #include "hash.h"
42 #include "xstrtol-error.h"
44 /* The official name of this program (e.g., no 'g' prefix). */
45 #define PROGRAM_NAME "df"
47 #define AUTHORS \
48 proper_name ("Torbjorn Granlund"), \
49 proper_name ("David MacKenzie"), \
50 proper_name ("Paul Eggert")
52 struct devlist
54 dev_t dev_num;
55 struct mount_entry *me;
56 struct devlist *next;
57 struct devlist *seen_last; /* valid for hashed devlist entries only */
60 /* Filled with device numbers of examined file systems to avoid
61 duplicates in output. */
62 static Hash_table *devlist_table;
64 /* If true, show even file systems with zero size or
65 uninteresting types. */
66 static bool show_all_fs;
68 /* If true, show only local file systems. */
69 static bool show_local_fs;
71 /* If true, output data for each file system corresponding to a
72 command line argument -- even if it's a dummy (automounter) entry. */
73 static bool show_listed_fs;
75 /* Human-readable options for output. */
76 static int human_output_opts;
78 /* The units to use when printing sizes. */
79 static uintmax_t output_block_size;
81 /* True if a file system has been processed for output. */
82 static bool file_systems_processed;
84 /* If true, invoke the 'sync' system call before getting any usage data.
85 Using this option can make df very slow, especially with many or very
86 busy file systems. This may make a difference on some systems --
87 SunOS 4.1.3, for one. It is *not* necessary on GNU/Linux. */
88 static bool require_sync;
90 /* Desired exit status. */
91 static int exit_status;
93 /* A file system type to display. */
95 struct fs_type_list
97 char *fs_name;
98 struct fs_type_list *fs_next;
101 /* Linked list of file system types to display.
102 If 'fs_select_list' is NULL, list all types.
103 This table is generated dynamically from command-line options,
104 rather than hardcoding into the program what it thinks are the
105 valid file system types; let the user specify any file system type
106 they want to, and if there are any file systems of that type, they
107 will be shown.
109 Some file system types:
110 4.2 4.3 ufs nfs swap ignore io vm efs dbg */
112 static struct fs_type_list *fs_select_list;
114 /* Linked list of file system types to omit.
115 If the list is empty, don't exclude any types. */
117 static struct fs_type_list *fs_exclude_list;
119 /* Linked list of mounted file systems. */
120 static struct mount_entry *mount_list;
122 /* If true, print file system type as well. */
123 static bool print_type;
125 /* If true, print a grand total at the end. */
126 static bool print_grand_total;
128 /* Grand total data. */
129 static struct fs_usage grand_fsu;
131 /* Display modes. */
132 enum
134 DEFAULT_MODE,
135 INODES_MODE,
136 HUMAN_MODE,
137 POSIX_MODE,
138 OUTPUT_MODE
140 static int header_mode = DEFAULT_MODE;
142 /* Displayable fields. */
143 typedef enum
145 SOURCE_FIELD, /* file system */
146 FSTYPE_FIELD, /* FS type */
147 SIZE_FIELD, /* FS size */
148 USED_FIELD, /* FS size used */
149 AVAIL_FIELD, /* FS size available */
150 PCENT_FIELD, /* percent used */
151 ITOTAL_FIELD, /* inode total */
152 IUSED_FIELD, /* inodes used */
153 IAVAIL_FIELD, /* inodes available */
154 IPCENT_FIELD, /* inodes used in percent */
155 TARGET_FIELD, /* mount point */
156 FILE_FIELD, /* specified file name */
157 INVALID_FIELD /* validation marker */
158 } display_field_t;
160 /* Flag if a field contains a block, an inode or another value. */
161 typedef enum
163 BLOCK_FLD, /* Block values field */
164 INODE_FLD, /* Inode values field */
165 OTHER_FLD /* Neutral field, e.g. target */
166 } field_type_t;
168 /* Attributes of a display field. */
169 struct field_data_t
171 display_field_t field;
172 char const *arg;
173 field_type_t field_type;
174 char const *caption;/* NULL means to use the default header of this field. */
175 size_t width; /* Auto adjusted (up) widths used to align columns. */
176 mbs_align_t align; /* Alignment for this field. */
177 bool used;
180 /* Header strings, minimum width and alignment for the above fields. */
181 static struct field_data_t field_data[] = {
182 [SOURCE_FIELD] = { SOURCE_FIELD,
183 "source", OTHER_FLD, N_("Filesystem"), 14, MBS_ALIGN_LEFT, false },
185 [FSTYPE_FIELD] = { FSTYPE_FIELD,
186 "fstype", OTHER_FLD, N_("Type"), 4, MBS_ALIGN_LEFT, false },
188 [SIZE_FIELD] = { SIZE_FIELD,
189 "size", BLOCK_FLD, N_("blocks"), 5, MBS_ALIGN_RIGHT, false },
191 [USED_FIELD] = { USED_FIELD,
192 "used", BLOCK_FLD, N_("Used"), 5, MBS_ALIGN_RIGHT, false },
194 [AVAIL_FIELD] = { AVAIL_FIELD,
195 "avail", BLOCK_FLD, N_("Available"), 5, MBS_ALIGN_RIGHT, false },
197 [PCENT_FIELD] = { PCENT_FIELD,
198 "pcent", BLOCK_FLD, N_("Use%"), 4, MBS_ALIGN_RIGHT, false },
200 [ITOTAL_FIELD] = { ITOTAL_FIELD,
201 "itotal", INODE_FLD, N_("Inodes"), 5, MBS_ALIGN_RIGHT, false },
203 [IUSED_FIELD] = { IUSED_FIELD,
204 "iused", INODE_FLD, N_("IUsed"), 5, MBS_ALIGN_RIGHT, false },
206 [IAVAIL_FIELD] = { IAVAIL_FIELD,
207 "iavail", INODE_FLD, N_("IFree"), 5, MBS_ALIGN_RIGHT, false },
209 [IPCENT_FIELD] = { IPCENT_FIELD,
210 "ipcent", INODE_FLD, N_("IUse%"), 4, MBS_ALIGN_RIGHT, false },
212 [TARGET_FIELD] = { TARGET_FIELD,
213 "target", OTHER_FLD, N_("Mounted on"), 0, MBS_ALIGN_LEFT, false },
215 [FILE_FIELD] = { FILE_FIELD,
216 "file", OTHER_FLD, N_("File"), 0, MBS_ALIGN_LEFT, false }
219 static char const *all_args_string =
220 "source,fstype,itotal,iused,iavail,ipcent,size,"
221 "used,avail,pcent,file,target";
223 /* Storage for the definition of output columns. */
224 static struct field_data_t **columns;
226 /* The current number of output columns. */
227 static size_t ncolumns;
229 /* Field values. */
230 struct field_values_t
232 uintmax_t input_units;
233 uintmax_t output_units;
234 uintmax_t total;
235 uintmax_t available;
236 bool negate_available;
237 uintmax_t available_to_root;
238 uintmax_t used;
239 bool negate_used;
242 /* Storage for pointers for each string (cell of table). */
243 static char ***table;
245 /* The current number of processed rows (including header). */
246 static size_t nrows;
248 /* For long options that have no equivalent short option, use a
249 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
250 enum
252 NO_SYNC_OPTION = CHAR_MAX + 1,
253 SYNC_OPTION,
254 TOTAL_OPTION,
255 OUTPUT_OPTION
258 static struct option const long_options[] =
260 {"all", no_argument, NULL, 'a'},
261 {"block-size", required_argument, NULL, 'B'},
262 {"inodes", no_argument, NULL, 'i'},
263 {"human-readable", no_argument, NULL, 'h'},
264 {"si", no_argument, NULL, 'H'},
265 {"local", no_argument, NULL, 'l'},
266 {"output", optional_argument, NULL, OUTPUT_OPTION},
267 {"portability", no_argument, NULL, 'P'},
268 {"print-type", no_argument, NULL, 'T'},
269 {"sync", no_argument, NULL, SYNC_OPTION},
270 {"no-sync", no_argument, NULL, NO_SYNC_OPTION},
271 {"total", no_argument, NULL, TOTAL_OPTION},
272 {"type", required_argument, NULL, 't'},
273 {"exclude-type", required_argument, NULL, 'x'},
274 {GETOPT_HELP_OPTION_DECL},
275 {GETOPT_VERSION_OPTION_DECL},
276 {NULL, 0, NULL, 0}
279 /* Stat FILE and put the results into *ST. Return 0 if successful, an
280 error number otherwise. Try to open FILE before statting, to
281 trigger automounts. */
283 static int
284 automount_stat_err (char const *file, struct stat *st)
286 int fd = open (file, O_RDONLY | O_NOCTTY | O_NONBLOCK);
287 if (fd < 0)
289 if (errno == ENOENT || errno == ENOTDIR)
290 return errno;
291 return stat (file, st) == 0 ? 0 : errno;
293 else
295 int err = fstat (fd, st) == 0 ? 0 : errno;
296 close (fd);
297 return err;
301 /* Replace problematic chars with '?'.
302 Since only control characters are currently considered,
303 this should work in all encodings. */
305 static void
306 replace_control_chars (char *cell)
308 char *p = cell;
309 while (*p)
311 if (c_iscntrl (to_uchar (*p)))
312 *p = '?';
313 p++;
317 /* Replace problematic chars with '?'. */
319 static void
320 replace_invalid_chars (char *cell)
322 char *srcend = cell + strlen (cell);
323 char *dst = cell;
324 mbstate_t mbstate = { 0, };
325 size_t n;
327 for (char *src = cell; src != srcend; src += n)
329 wchar_t wc;
330 size_t srcbytes = srcend - src;
331 n = mbrtowc (&wc, src, srcbytes, &mbstate);
332 bool ok = n <= srcbytes;
334 if (ok)
335 ok = !iswcntrl (wc);
336 else
337 n = 1;
339 if (ok)
341 memmove (dst, src, n);
342 dst += n;
344 else
346 *dst++ = '?';
347 memset (&mbstate, 0, sizeof mbstate);
351 *dst = '\0';
354 static void
355 replace_problematic_chars (char *cell)
357 static int tty_out = -1;
358 if (tty_out < 0)
359 tty_out = isatty (STDOUT_FILENO);
361 (tty_out ? replace_invalid_chars : replace_control_chars) (cell) ;
365 /* Dynamically allocate a row of pointers in TABLE, which
366 can then be accessed with standard 2D array notation. */
368 static void
369 alloc_table_row (void)
371 nrows++;
372 table = xnrealloc (table, nrows, sizeof (char **));
373 table[nrows - 1] = xnmalloc (ncolumns, sizeof (char *));
376 /* Output each cell in the table, accounting for the
377 alignment and max width of each column. */
379 static void
380 print_table (void)
382 size_t row;
384 for (row = 0; row < nrows; row++)
386 size_t col;
387 for (col = 0; col < ncolumns; col++)
389 char *cell = table[row][col];
391 /* Note the SOURCE_FIELD used to be displayed on it's own line
392 if (!posix_format && mbswidth (cell) > 20), but that
393 functionality was probably more problematic than helpful,
394 hence changed in commit v8.10-40-g99679ff. */
395 if (col != 0)
396 putchar (' ');
398 int flags = 0;
399 if (col == ncolumns - 1) /* The last one. */
400 flags = MBA_NO_RIGHT_PAD;
402 size_t width = columns[col]->width;
403 cell = ambsalign (cell, &width, columns[col]->align, flags);
404 /* When ambsalign fails, output unaligned data. */
405 fputs (cell ? cell : table[row][col], stdout);
406 free (cell);
408 IF_LINT (free (table[row][col]));
410 putchar ('\n');
411 IF_LINT (free (table[row]));
414 IF_LINT (free (table));
417 /* Dynamically allocate a struct field_t in COLUMNS, which
418 can then be accessed with standard array notation. */
420 static void
421 alloc_field (int f, char const *c)
423 ncolumns++;
424 columns = xnrealloc (columns, ncolumns, sizeof (struct field_data_t *));
425 columns[ncolumns - 1] = &field_data[f];
426 if (c != NULL)
427 columns[ncolumns - 1]->caption = c;
429 if (field_data[f].used)
430 assert (!"field used");
432 /* Mark field as used. */
433 field_data[f].used = true;
437 /* Given a string, ARG, containing a comma-separated list of arguments
438 to the --output option, add the appropriate fields to columns. */
439 static void
440 decode_output_arg (char const *arg)
442 char *arg_writable = xstrdup (arg);
443 char *s = arg_writable;
446 /* find next comma */
447 char *comma = strchr (s, ',');
449 /* If we found a comma, put a NUL in its place and advance. */
450 if (comma)
451 *comma++ = 0;
453 /* process S. */
454 display_field_t field = INVALID_FIELD;
455 for (unsigned int i = 0; i < ARRAY_CARDINALITY (field_data); i++)
457 if (STREQ (field_data[i].arg, s))
459 field = i;
460 break;
463 if (field == INVALID_FIELD)
465 error (0, 0, _("option --output: field %s unknown"), quote (s));
466 usage (EXIT_FAILURE);
469 if (field_data[field].used)
471 /* Prevent the fields from being used more than once. */
472 error (0, 0, _("option --output: field %s used more than once"),
473 quote (field_data[field].arg));
474 usage (EXIT_FAILURE);
477 switch (field)
479 case SOURCE_FIELD:
480 case FSTYPE_FIELD:
481 case USED_FIELD:
482 case PCENT_FIELD:
483 case ITOTAL_FIELD:
484 case IUSED_FIELD:
485 case IAVAIL_FIELD:
486 case IPCENT_FIELD:
487 case TARGET_FIELD:
488 case FILE_FIELD:
489 alloc_field (field, NULL);
490 break;
492 case SIZE_FIELD:
493 alloc_field (field, N_("Size"));
494 break;
496 case AVAIL_FIELD:
497 alloc_field (field, N_("Avail"));
498 break;
500 default:
501 assert (!"invalid field");
503 s = comma;
505 while (s);
507 free (arg_writable);
510 /* Get the appropriate columns for the mode. */
511 static void
512 get_field_list (void)
514 switch (header_mode)
516 case DEFAULT_MODE:
517 alloc_field (SOURCE_FIELD, NULL);
518 if (print_type)
519 alloc_field (FSTYPE_FIELD, NULL);
520 alloc_field (SIZE_FIELD, NULL);
521 alloc_field (USED_FIELD, NULL);
522 alloc_field (AVAIL_FIELD, NULL);
523 alloc_field (PCENT_FIELD, NULL);
524 alloc_field (TARGET_FIELD, NULL);
525 break;
527 case HUMAN_MODE:
528 alloc_field (SOURCE_FIELD, NULL);
529 if (print_type)
530 alloc_field (FSTYPE_FIELD, NULL);
532 alloc_field (SIZE_FIELD, N_("Size"));
533 alloc_field (USED_FIELD, NULL);
534 alloc_field (AVAIL_FIELD, N_("Avail"));
535 alloc_field (PCENT_FIELD, NULL);
536 alloc_field (TARGET_FIELD, NULL);
537 break;
539 case INODES_MODE:
540 alloc_field (SOURCE_FIELD, NULL);
541 if (print_type)
542 alloc_field (FSTYPE_FIELD, NULL);
543 alloc_field (ITOTAL_FIELD, NULL);
544 alloc_field (IUSED_FIELD, NULL);
545 alloc_field (IAVAIL_FIELD, NULL);
546 alloc_field (IPCENT_FIELD, NULL);
547 alloc_field (TARGET_FIELD, NULL);
548 break;
550 case POSIX_MODE:
551 alloc_field (SOURCE_FIELD, NULL);
552 if (print_type)
553 alloc_field (FSTYPE_FIELD, NULL);
554 alloc_field (SIZE_FIELD, NULL);
555 alloc_field (USED_FIELD, NULL);
556 alloc_field (AVAIL_FIELD, NULL);
557 alloc_field (PCENT_FIELD, N_("Capacity"));
558 alloc_field (TARGET_FIELD, NULL);
559 break;
561 case OUTPUT_MODE:
562 if (!ncolumns)
564 /* Add all fields if --output was given without a field list. */
565 decode_output_arg (all_args_string);
567 break;
569 default:
570 assert (!"invalid header_mode");
574 /* Obtain the appropriate header entries. */
576 static void
577 get_header (void)
579 size_t col;
581 alloc_table_row ();
583 for (col = 0; col < ncolumns; col++)
585 char *cell = NULL;
586 char const *header = _(columns[col]->caption);
588 if (columns[col]->field == SIZE_FIELD
589 && (header_mode == DEFAULT_MODE
590 || (header_mode == OUTPUT_MODE
591 && !(human_output_opts & human_autoscale))))
593 char buf[LONGEST_HUMAN_READABLE + 1];
595 int opts = (human_suppress_point_zero
596 | human_autoscale | human_SI
597 | (human_output_opts
598 & (human_group_digits | human_base_1024 | human_B)));
600 /* Prefer the base that makes the human-readable value more exact,
601 if there is a difference. */
603 uintmax_t q1000 = output_block_size;
604 uintmax_t q1024 = output_block_size;
605 bool divisible_by_1000;
606 bool divisible_by_1024;
610 divisible_by_1000 = q1000 % 1000 == 0; q1000 /= 1000;
611 divisible_by_1024 = q1024 % 1024 == 0; q1024 /= 1024;
613 while (divisible_by_1000 & divisible_by_1024);
615 if (divisible_by_1000 < divisible_by_1024)
616 opts |= human_base_1024;
617 if (divisible_by_1024 < divisible_by_1000)
618 opts &= ~human_base_1024;
619 if (! (opts & human_base_1024))
620 opts |= human_B;
622 char *num = human_readable (output_block_size, buf, opts, 1, 1);
624 /* Reset the header back to the default in OUTPUT_MODE. */
625 header = _("blocks");
627 /* TRANSLATORS: this is the "1K-blocks" header in "df" output. */
628 if (asprintf (&cell, _("%s-%s"), num, header) == -1)
629 cell = NULL;
631 else if (header_mode == POSIX_MODE && columns[col]->field == SIZE_FIELD)
633 char buf[INT_BUFSIZE_BOUND (uintmax_t)];
634 char *num = umaxtostr (output_block_size, buf);
636 /* TRANSLATORS: this is the "1024-blocks" header in "df -P". */
637 if (asprintf (&cell, _("%s-%s"), num, header) == -1)
638 cell = NULL;
640 else
641 cell = strdup (header);
643 if (!cell)
644 xalloc_die ();
646 replace_problematic_chars (cell);
648 table[nrows - 1][col] = cell;
650 size_t cell_width = mbswidth (cell, 0);
651 columns[col]->width = MAX (columns[col]->width, cell_width);
655 /* Is FSTYPE a type of file system that should be listed? */
657 ATTRIBUTE_PURE
658 static bool
659 selected_fstype (char const *fstype)
661 const struct fs_type_list *fsp;
663 if (fs_select_list == NULL || fstype == NULL)
664 return true;
665 for (fsp = fs_select_list; fsp; fsp = fsp->fs_next)
666 if (STREQ (fstype, fsp->fs_name))
667 return true;
668 return false;
671 /* Is FSTYPE a type of file system that should be omitted? */
673 ATTRIBUTE_PURE
674 static bool
675 excluded_fstype (char const *fstype)
677 const struct fs_type_list *fsp;
679 if (fs_exclude_list == NULL || fstype == NULL)
680 return false;
681 for (fsp = fs_exclude_list; fsp; fsp = fsp->fs_next)
682 if (STREQ (fstype, fsp->fs_name))
683 return true;
684 return false;
687 static size_t
688 devlist_hash (void const *x, size_t table_size)
690 struct devlist const *p = x;
691 return (uintmax_t) p->dev_num % table_size;
694 static bool
695 devlist_compare (void const *x, void const *y)
697 struct devlist const *a = x;
698 struct devlist const *b = y;
699 return a->dev_num == b->dev_num;
702 static struct devlist *
703 devlist_for_dev (dev_t dev)
705 if (devlist_table == NULL)
706 return NULL;
707 struct devlist dev_entry;
708 dev_entry.dev_num = dev;
710 struct devlist *found = hash_lookup (devlist_table, &dev_entry);
711 if (found == NULL)
712 return NULL;
714 /* Return the last devlist entry we have seen with this dev_num */
715 return found->seen_last;
718 static void
719 devlist_free (void *p)
721 free (p);
724 /* Filter mount list by skipping duplicate entries.
725 In the case of duplicates - based on the device number - the mount entry
726 with a '/' in its me_devname (i.e., not pseudo name like tmpfs) wins.
727 If both have a real devname (e.g. bind mounts), then that with the shorter
728 me_mountdir wins. With DEVICES_ONLY == true (set with df -a), only update
729 the global devlist_table, rather than filtering the global mount_list. */
731 static void
732 filter_mount_list (bool devices_only)
734 struct mount_entry *me;
736 /* Temporary list to keep entries ordered. */
737 struct devlist *device_list = NULL;
738 int mount_list_size = 0;
740 for (me = mount_list; me; me = me->me_next)
741 mount_list_size++;
743 devlist_table = hash_initialize (mount_list_size, NULL,
744 devlist_hash,
745 devlist_compare,
746 devlist_free);
747 if (devlist_table == NULL)
748 xalloc_die ();
750 /* Sort all 'wanted' entries into the list device_list. */
751 for (me = mount_list; me;)
753 struct stat buf;
754 struct mount_entry *discard_me = NULL;
756 /* Avoid stating remote file systems as that may hang.
757 On Linux we probably have me_dev populated from /proc/self/mountinfo,
758 however we still stat() in case another device was mounted later. */
759 if ((me->me_remote && show_local_fs)
760 || (me->me_dummy && !show_all_fs && !show_listed_fs)
761 || (!selected_fstype (me->me_type) || excluded_fstype (me->me_type))
762 || -1 == stat (me->me_mountdir, &buf))
764 /* If remote, and showing just local, or FS type is excluded,
765 add ME for filtering later.
766 If stat failed; add ME to be able to complain about it later. */
767 buf.st_dev = me->me_dev;
769 else
771 /* If we've already seen this device... */
772 struct devlist *seen_dev = devlist_for_dev (buf.st_dev);
774 if (seen_dev)
776 bool target_nearer_root = strlen (seen_dev->me->me_mountdir)
777 > strlen (me->me_mountdir);
778 /* With bind mounts, prefer items nearer the root of the source */
779 bool source_below_root = seen_dev->me->me_mntroot != NULL
780 && me->me_mntroot != NULL
781 && (strlen (seen_dev->me->me_mntroot)
782 < strlen (me->me_mntroot));
783 if (! print_grand_total
784 && me->me_remote && seen_dev->me->me_remote
785 && ! STREQ (seen_dev->me->me_devname, me->me_devname))
787 /* Don't discard remote entries with different locations,
788 as these are more likely to be explicitly mounted.
789 However avoid this when producing a total to give
790 a more accurate value in that case. */
792 else if ((strchr (me->me_devname, '/')
793 /* let "real" devices with '/' in the name win. */
794 && ! strchr (seen_dev->me->me_devname, '/'))
795 /* let points towards the root of the device win. */
796 || (target_nearer_root && ! source_below_root)
797 /* let an entry overmounted on a new device win... */
798 || (! STREQ (seen_dev->me->me_devname, me->me_devname)
799 /* ... but only when matching an existing mnt point,
800 to avoid problematic replacement when given
801 inaccurate mount lists, seen with some chroot
802 environments for example. */
803 && STREQ (me->me_mountdir,
804 seen_dev->me->me_mountdir)))
806 /* Discard mount entry for existing device. */
807 discard_me = seen_dev->me;
808 seen_dev->me = me;
810 else
812 /* Discard mount entry currently being processed. */
813 discard_me = me;
819 if (discard_me)
821 me = me->me_next;
822 if (! devices_only)
823 free_mount_entry (discard_me);
825 else
827 /* Add the device number to the device_table. */
828 struct devlist *devlist = xmalloc (sizeof *devlist);
829 devlist->me = me;
830 devlist->dev_num = buf.st_dev;
831 devlist->next = device_list;
832 device_list = devlist;
834 struct devlist *hash_entry = hash_insert (devlist_table, devlist);
835 if (hash_entry == NULL)
836 xalloc_die ();
837 /* Ensure lookups use this latest devlist. */
838 hash_entry->seen_last = devlist;
840 me = me->me_next;
844 /* Finally rebuild the mount_list from the devlist. */
845 if (! devices_only) {
846 mount_list = NULL;
847 while (device_list)
849 /* Add the mount entry. */
850 me = device_list->me;
851 me->me_next = mount_list;
852 mount_list = me;
853 device_list = device_list->next;
856 hash_free (devlist_table);
857 devlist_table = NULL;
862 /* Search a mount entry list for device id DEV.
863 Return the corresponding mount entry if found or NULL if not. */
865 ATTRIBUTE_PURE
866 static struct mount_entry const *
867 me_for_dev (dev_t dev)
869 struct devlist *dl = devlist_for_dev (dev);
870 if (dl)
871 return dl->me;
873 return NULL;
876 /* Return true if N is a known integer value. On many file systems,
877 UINTMAX_MAX represents an unknown value; on AIX, UINTMAX_MAX - 1
878 represents unknown. Use a rule that works on AIX file systems, and
879 that almost-always works on other types. */
880 static bool
881 known_value (uintmax_t n)
883 return n < UINTMAX_MAX - 1;
886 /* Like human_readable (N, BUF, human_output_opts, INPUT_UNITS, OUTPUT_UNITS),
887 except:
889 - If NEGATIVE, then N represents a negative number,
890 expressed in two's complement.
891 - Otherwise, return "-" if N is unknown. */
893 static char const *
894 df_readable (bool negative, uintmax_t n, char *buf,
895 uintmax_t input_units, uintmax_t output_units)
897 if (! known_value (n) && !negative)
898 return "-";
899 else
901 char *p = human_readable (negative ? -n : n, buf + negative,
902 human_output_opts, input_units, output_units);
903 if (negative)
904 *--p = '-';
905 return p;
909 /* Add integral value while using uintmax_t for value part and separate
910 negation flag. It adds value of SRC and SRC_NEG to DEST and DEST_NEG.
911 The result will be in DEST and DEST_NEG. See df_readable to understand
912 how the negation flag is used. */
913 static void
914 add_uint_with_neg_flag (uintmax_t *dest, bool *dest_neg,
915 uintmax_t src, bool src_neg)
917 if (*dest_neg == src_neg)
919 *dest += src;
920 return;
923 if (*dest_neg)
924 *dest = -*dest;
926 if (src_neg)
927 src = -src;
929 if (src < *dest)
930 *dest -= src;
931 else
933 *dest = src - *dest;
934 *dest_neg = src_neg;
937 if (*dest_neg)
938 *dest = -*dest;
941 /* Return true if S ends in a string that may be a 36-byte UUID,
942 i.e., of the form HHHHHHHH-HHHH-HHHH-HHHH-HHHHHHHHHHHH, where
943 each H is an upper or lower case hexadecimal digit. */
944 ATTRIBUTE_PURE
945 static bool
946 has_uuid_suffix (char const *s)
948 size_t len = strlen (s);
949 return (36 < len
950 && strspn (s + len - 36, "-0123456789abcdefABCDEF") == 36);
953 /* Obtain the block values BV and inode values IV
954 from the file system usage FSU. */
955 static void
956 get_field_values (struct field_values_t *bv,
957 struct field_values_t *iv,
958 const struct fs_usage *fsu)
960 /* Inode values. */
961 iv->input_units = iv->output_units = 1;
962 iv->total = fsu->fsu_files;
963 iv->available = iv->available_to_root = fsu->fsu_ffree;
964 iv->negate_available = false;
966 iv->used = UINTMAX_MAX;
967 iv->negate_used = false;
968 if (known_value (iv->total) && known_value (iv->available_to_root))
970 iv->used = iv->total - iv->available_to_root;
971 iv->negate_used = (iv->total < iv->available_to_root);
974 /* Block values. */
975 bv->input_units = fsu->fsu_blocksize;
976 bv->output_units = output_block_size;
977 bv->total = fsu->fsu_blocks;
978 bv->available = fsu->fsu_bavail;
979 bv->available_to_root = fsu->fsu_bfree;
980 bv->negate_available = (fsu->fsu_bavail_top_bit_set
981 && known_value (fsu->fsu_bavail));
983 bv->used = UINTMAX_MAX;
984 bv->negate_used = false;
985 if (known_value (bv->total) && known_value (bv->available_to_root))
987 bv->used = bv->total - bv->available_to_root;
988 bv->negate_used = (bv->total < bv->available_to_root);
992 /* Add block and inode values to grand total. */
993 static void
994 add_to_grand_total (struct field_values_t *bv, struct field_values_t *iv)
996 if (known_value (iv->total))
997 grand_fsu.fsu_files += iv->total;
998 if (known_value (iv->available))
999 grand_fsu.fsu_ffree += iv->available;
1001 if (known_value (bv->total))
1002 grand_fsu.fsu_blocks += bv->input_units * bv->total;
1003 if (known_value (bv->available_to_root))
1004 grand_fsu.fsu_bfree += bv->input_units * bv->available_to_root;
1005 if (known_value (bv->available))
1006 add_uint_with_neg_flag (&grand_fsu.fsu_bavail,
1007 &grand_fsu.fsu_bavail_top_bit_set,
1008 bv->input_units * bv->available,
1009 bv->negate_available);
1012 /* Obtain a space listing for the device with absolute file name DEVICE.
1013 If MOUNT_POINT is non-NULL, it is the name of the root of the
1014 file system on DEVICE.
1015 If STAT_FILE is non-null, it is the name of a file within the file
1016 system that the user originally asked for; this provides better
1017 diagnostics, and sometimes it provides better results on networked
1018 file systems that give different free-space results depending on
1019 where in the file system you probe.
1020 If FSTYPE is non-NULL, it is the type of the file system on DEVICE.
1021 If MOUNT_POINT is non-NULL, then DEVICE may be NULL -- certain systems may
1022 not be able to produce statistics in this case.
1023 ME_DUMMY and ME_REMOTE are the mount entry flags.
1024 Caller must set PROCESS_ALL to true when iterating over all entries, as
1025 when df is invoked with no non-option argument. See below for details. */
1027 static void
1028 get_dev (char const *device, char const *mount_point, char const *file,
1029 char const *stat_file, char const *fstype,
1030 bool me_dummy, bool me_remote,
1031 const struct fs_usage *force_fsu,
1032 bool process_all)
1034 if (me_remote && show_local_fs)
1035 return;
1037 if (me_dummy && !show_all_fs && !show_listed_fs)
1038 return;
1040 if (!selected_fstype (fstype) || excluded_fstype (fstype))
1041 return;
1043 /* Ignore relative MOUNT_POINTs, which are present for example
1044 in /proc/mounts on Linux with network namespaces. */
1045 if (!force_fsu && mount_point && ! IS_ABSOLUTE_FILE_NAME (mount_point))
1046 return;
1048 /* If MOUNT_POINT is NULL, then the file system is not mounted, and this
1049 program reports on the file system that the special file is on.
1050 It would be better to report on the unmounted file system,
1051 but statfs doesn't do that on most systems. */
1052 if (!stat_file)
1053 stat_file = mount_point ? mount_point : device;
1055 struct fs_usage fsu;
1056 if (force_fsu)
1057 fsu = *force_fsu;
1058 else if (get_fs_usage (stat_file, device, &fsu))
1060 /* If we can't access a system provided entry due
1061 to it not being present (now), or due to permissions,
1062 just output placeholder values rather than failing. */
1063 if (process_all && (errno == EACCES || errno == ENOENT))
1065 if (! show_all_fs)
1066 return;
1068 fstype = "-";
1069 fsu.fsu_bavail_top_bit_set = false;
1070 fsu.fsu_blocksize = fsu.fsu_blocks = fsu.fsu_bfree =
1071 fsu.fsu_bavail = fsu.fsu_files = fsu.fsu_ffree = UINTMAX_MAX;
1073 else
1075 error (0, errno, "%s", quotef (stat_file));
1076 exit_status = EXIT_FAILURE;
1077 return;
1080 else if (process_all && show_all_fs)
1082 /* Ensure we don't output incorrect stats for over-mounted directories.
1083 Discard stats when the device name doesn't match. Though don't
1084 discard when used and current mount entries are both remote due
1085 to the possibility of aliased host names or exports. */
1086 struct stat sb;
1087 if (stat (stat_file, &sb) == 0)
1089 struct mount_entry const * dev_me = me_for_dev (sb.st_dev);
1090 if (dev_me && ! STREQ (dev_me->me_devname, device)
1091 && (! dev_me->me_remote || ! me_remote))
1093 fstype = "-";
1094 fsu.fsu_bavail_top_bit_set = false;
1095 fsu.fsu_blocksize = fsu.fsu_blocks = fsu.fsu_bfree =
1096 fsu.fsu_bavail = fsu.fsu_files = fsu.fsu_ffree = UINTMAX_MAX;
1101 if (fsu.fsu_blocks == 0 && !show_all_fs && !show_listed_fs)
1102 return;
1104 if (! force_fsu)
1105 file_systems_processed = true;
1107 alloc_table_row ();
1109 if (! device)
1110 device = "-"; /* unknown */
1112 if (! file)
1113 file = "-"; /* unspecified */
1115 char *dev_name = xstrdup (device);
1116 char *resolved_dev;
1118 /* On some systems, dev_name is a long-named symlink like
1119 /dev/disk/by-uuid/828fc648-9f30-43d8-a0b1-f7196a2edb66 pointing to a
1120 much shorter and more useful name like /dev/sda1. It may also look
1121 like /dev/mapper/luks-828fc648-9f30-43d8-a0b1-f7196a2edb66 and point to
1122 /dev/dm-0. When process_all is true and dev_name is a symlink whose
1123 name ends with a UUID use the resolved name instead. */
1124 if (process_all
1125 && has_uuid_suffix (dev_name)
1126 && (resolved_dev = canonicalize_filename_mode (dev_name, CAN_EXISTING)))
1128 free (dev_name);
1129 dev_name = resolved_dev;
1132 if (! fstype)
1133 fstype = "-"; /* unknown */
1135 struct field_values_t block_values;
1136 struct field_values_t inode_values;
1137 get_field_values (&block_values, &inode_values, &fsu);
1139 /* Add to grand total unless processing grand total line. */
1140 if (print_grand_total && ! force_fsu)
1141 add_to_grand_total (&block_values, &inode_values);
1143 size_t col;
1144 for (col = 0; col < ncolumns; col++)
1146 char buf[LONGEST_HUMAN_READABLE + 2];
1147 char *cell;
1149 struct field_values_t *v;
1150 switch (columns[col]->field_type)
1152 case BLOCK_FLD:
1153 v = &block_values;
1154 break;
1155 case INODE_FLD:
1156 v = &inode_values;
1157 break;
1158 case OTHER_FLD:
1159 v = NULL;
1160 break;
1161 default:
1162 v = NULL; /* Avoid warnings where assert() is not __noreturn__. */
1163 assert (!"bad field_type");
1166 switch (columns[col]->field)
1168 case SOURCE_FIELD:
1169 cell = xstrdup (dev_name);
1170 break;
1172 case FSTYPE_FIELD:
1173 cell = xstrdup (fstype);
1174 break;
1176 case SIZE_FIELD:
1177 case ITOTAL_FIELD:
1178 cell = xstrdup (df_readable (false, v->total, buf,
1179 v->input_units, v->output_units));
1180 break;
1182 case USED_FIELD:
1183 case IUSED_FIELD:
1184 cell = xstrdup (df_readable (v->negate_used, v->used, buf,
1185 v->input_units, v->output_units));
1186 break;
1188 case AVAIL_FIELD:
1189 case IAVAIL_FIELD:
1190 cell = xstrdup (df_readable (v->negate_available, v->available, buf,
1191 v->input_units, v->output_units));
1192 break;
1194 case PCENT_FIELD:
1195 case IPCENT_FIELD:
1197 double pct = -1;
1198 if (! known_value (v->used) || ! known_value (v->available))
1200 else if (!v->negate_used
1201 && v->used <= TYPE_MAXIMUM (uintmax_t) / 100
1202 && v->used + v->available != 0
1203 && (v->used + v->available < v->used)
1204 == v->negate_available)
1206 uintmax_t u100 = v->used * 100;
1207 uintmax_t nonroot_total = v->used + v->available;
1208 pct = u100 / nonroot_total + (u100 % nonroot_total != 0);
1210 else
1212 /* The calculation cannot be done easily with integer
1213 arithmetic. Fall back on floating point. This can suffer
1214 from minor rounding errors, but doing it exactly requires
1215 multiple precision arithmetic, and it's not worth the
1216 aggravation. */
1217 double u = v->negate_used ? - (double) - v->used : v->used;
1218 double a = v->negate_available
1219 ? - (double) - v->available : v->available;
1220 double nonroot_total = u + a;
1221 if (nonroot_total)
1223 long int lipct = pct = u * 100 / nonroot_total;
1224 double ipct = lipct;
1226 /* Like 'pct = ceil (dpct);', but avoid ceil so that
1227 the math library needn't be linked. */
1228 if (ipct - 1 < pct && pct <= ipct + 1)
1229 pct = ipct + (ipct < pct);
1233 if (0 <= pct)
1235 if (asprintf (&cell, "%.0f%%", pct) == -1)
1236 cell = NULL;
1238 else
1239 cell = strdup ("-");
1241 if (!cell)
1242 xalloc_die ();
1244 break;
1247 case FILE_FIELD:
1248 cell = xstrdup (file);
1249 break;
1251 case TARGET_FIELD:
1252 #ifdef HIDE_AUTOMOUNT_PREFIX
1253 /* Don't print the first directory name in MOUNT_POINT if it's an
1254 artifact of an automounter. This is a bit too aggressive to be
1255 the default. */
1256 if (STRNCMP_LIT (mount_point, "/auto/") == 0)
1257 mount_point += 5;
1258 else if (STRNCMP_LIT (mount_point, "/tmp_mnt/") == 0)
1259 mount_point += 8;
1260 #endif
1261 cell = xstrdup (mount_point);
1262 break;
1264 default:
1265 assert (!"unhandled field");
1268 if (!cell)
1269 assert (!"empty cell");
1271 replace_problematic_chars (cell);
1272 size_t cell_width = mbswidth (cell, 0);
1273 columns[col]->width = MAX (columns[col]->width, cell_width);
1274 table[nrows - 1][col] = cell;
1276 free (dev_name);
1279 /* Scan the mount list returning the _last_ device found for MOUNT.
1280 NULL is returned if MOUNT not found. The result is malloced. */
1281 static char *
1282 last_device_for_mount (char const *mount)
1284 struct mount_entry const *me;
1285 struct mount_entry const *le = NULL;
1287 for (me = mount_list; me; me = me->me_next)
1289 if (STREQ (me->me_mountdir, mount))
1290 le = me;
1293 if (le)
1295 char *devname = le->me_devname;
1296 char *canon_dev = canonicalize_file_name (devname);
1297 if (canon_dev && IS_ABSOLUTE_FILE_NAME (canon_dev))
1298 return canon_dev;
1299 free (canon_dev);
1300 return xstrdup (le->me_devname);
1302 else
1303 return NULL;
1306 /* If DEVICE corresponds to a mount point, show its usage
1307 and return true. Otherwise, return false. */
1308 static bool
1309 get_device (char const *device)
1311 struct mount_entry const *me;
1312 struct mount_entry const *best_match = NULL;
1313 bool best_match_accessible = false;
1314 bool eclipsed_device = false;
1315 char const *file = device;
1317 char *resolved = canonicalize_file_name (device);
1318 if (resolved && IS_ABSOLUTE_FILE_NAME (resolved))
1319 device = resolved;
1321 size_t best_match_len = SIZE_MAX;
1322 for (me = mount_list; me; me = me->me_next)
1324 /* TODO: Should cache canon_dev in the mount_entry struct. */
1325 char *devname = me->me_devname;
1326 char *canon_dev = canonicalize_file_name (me->me_devname);
1327 if (canon_dev && IS_ABSOLUTE_FILE_NAME (canon_dev))
1328 devname = canon_dev;
1330 if (STREQ (device, devname))
1332 char *last_device = last_device_for_mount (me->me_mountdir);
1333 eclipsed_device = last_device && ! STREQ (last_device, devname);
1334 size_t len = strlen (me->me_mountdir);
1336 if (! eclipsed_device
1337 && (! best_match_accessible || len < best_match_len))
1339 struct stat device_stats;
1340 bool this_match_accessible = false;
1342 if (stat (me->me_mountdir, &device_stats) == 0)
1343 best_match_accessible = this_match_accessible = true;
1345 if (this_match_accessible
1346 || (! best_match_accessible && len < best_match_len))
1348 best_match = me;
1349 if (len == 1) /* Traditional root. */
1351 free (last_device);
1352 free (canon_dev);
1353 break;
1355 else
1356 best_match_len = len;
1360 free (last_device);
1363 free (canon_dev);
1366 free (resolved);
1368 if (best_match)
1370 get_dev (best_match->me_devname, best_match->me_mountdir, file, NULL,
1371 best_match->me_type, best_match->me_dummy,
1372 best_match->me_remote, NULL, false);
1373 return true;
1375 else if (eclipsed_device)
1377 error (0, 0, _("cannot access %s: over-mounted by another device"),
1378 quoteaf (file));
1379 exit_status = EXIT_FAILURE;
1380 return true;
1383 return false;
1386 /* Figure out which device file or directory POINT is mounted on
1387 and show its device usage.
1388 STATP must be the result of 'stat (POINT, STATP)'. */
1389 static void
1390 get_point (char const *point, const struct stat *statp)
1392 struct stat device_stats;
1393 struct mount_entry *me;
1394 struct mount_entry const *best_match = NULL;
1396 /* Calculate the real absolute file name for POINT, and use that to find
1397 the mount point. This avoids statting unavailable mount points,
1398 which can hang df. */
1399 char *resolved = canonicalize_file_name (point);
1400 if (resolved && resolved[0] == '/')
1402 size_t resolved_len = strlen (resolved);
1403 size_t best_match_len = 0;
1405 for (me = mount_list; me; me = me->me_next)
1407 if (!STREQ (me->me_type, "lofs")
1408 && (!best_match || best_match->me_dummy || !me->me_dummy))
1410 size_t len = strlen (me->me_mountdir);
1411 if (best_match_len <= len && len <= resolved_len
1412 && (len == 1 /* root file system */
1413 || ((len == resolved_len || resolved[len] == '/')
1414 && STREQ_LEN (me->me_mountdir, resolved, len))))
1416 best_match = me;
1417 best_match_len = len;
1422 free (resolved);
1423 if (best_match
1424 && (stat (best_match->me_mountdir, &device_stats) != 0
1425 || device_stats.st_dev != statp->st_dev))
1426 best_match = NULL;
1428 if (! best_match)
1429 for (me = mount_list; me; me = me->me_next)
1431 if (me->me_dev == (dev_t) -1)
1433 if (stat (me->me_mountdir, &device_stats) == 0)
1434 me->me_dev = device_stats.st_dev;
1435 else
1437 /* Report only I/O errors. Other errors might be
1438 caused by shadowed mount points, which means POINT
1439 can't possibly be on this file system. */
1440 if (errno == EIO)
1442 error (0, errno, "%s", quotef (me->me_mountdir));
1443 exit_status = EXIT_FAILURE;
1446 /* So we won't try and fail repeatedly. */
1447 me->me_dev = (dev_t) -2;
1451 if (statp->st_dev == me->me_dev
1452 && !STREQ (me->me_type, "lofs")
1453 && (!best_match || best_match->me_dummy || !me->me_dummy))
1455 /* Skip bogus mtab entries. */
1456 if (stat (me->me_mountdir, &device_stats) != 0
1457 || device_stats.st_dev != me->me_dev)
1458 me->me_dev = (dev_t) -2;
1459 else
1460 best_match = me;
1464 if (best_match)
1465 get_dev (best_match->me_devname, best_match->me_mountdir, point, point,
1466 best_match->me_type, best_match->me_dummy, best_match->me_remote,
1467 NULL, false);
1468 else
1470 /* We couldn't find the mount entry corresponding to POINT. Go ahead and
1471 print as much info as we can; methods that require the device to be
1472 present will fail at a later point. */
1474 /* Find the actual mount point. */
1475 char *mp = find_mount_point (point, statp);
1476 if (mp)
1478 get_dev (NULL, mp, point, NULL, NULL, false, false, NULL, false);
1479 free (mp);
1484 /* Determine what kind of node NAME is and show the device usage
1485 for it. STATP is the results of 'stat' on NAME. */
1487 static void
1488 get_entry (char const *name, struct stat const *statp)
1490 if ((S_ISBLK (statp->st_mode) || S_ISCHR (statp->st_mode))
1491 && get_device (name))
1492 return;
1494 get_point (name, statp);
1497 /* Show all mounted file systems, except perhaps those that are of
1498 an unselected type or are empty. */
1500 static void
1501 get_all_entries (void)
1503 struct mount_entry *me;
1505 filter_mount_list (show_all_fs);
1507 for (me = mount_list; me; me = me->me_next)
1508 get_dev (me->me_devname, me->me_mountdir, NULL, NULL, me->me_type,
1509 me->me_dummy, me->me_remote, NULL, true);
1512 /* Add FSTYPE to the list of file system types to display. */
1514 static void
1515 add_fs_type (char const *fstype)
1517 struct fs_type_list *fsp;
1519 fsp = xmalloc (sizeof *fsp);
1520 fsp->fs_name = (char *) fstype;
1521 fsp->fs_next = fs_select_list;
1522 fs_select_list = fsp;
1525 /* Add FSTYPE to the list of file system types to be omitted. */
1527 static void
1528 add_excluded_fs_type (char const *fstype)
1530 struct fs_type_list *fsp;
1532 fsp = xmalloc (sizeof *fsp);
1533 fsp->fs_name = (char *) fstype;
1534 fsp->fs_next = fs_exclude_list;
1535 fs_exclude_list = fsp;
1538 void
1539 usage (int status)
1541 if (status != EXIT_SUCCESS)
1542 emit_try_help ();
1543 else
1545 printf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name);
1546 fputs (_("\
1547 Show information about the file system on which each FILE resides,\n\
1548 or all file systems by default.\n\
1549 "), stdout);
1551 emit_mandatory_arg_note ();
1553 /* TRANSLATORS: The thousands and decimal separators are best
1554 adjusted to an appropriate default for your locale. */
1555 fputs (_("\
1556 -a, --all include pseudo, duplicate, inaccessible file systems\n\
1557 -B, --block-size=SIZE scale sizes by SIZE before printing them; e.g.,\n\
1558 '-BM' prints sizes in units of 1,048,576 bytes;\n\
1559 see SIZE format below\n\
1560 -h, --human-readable print sizes in powers of 1024 (e.g., 1023M)\n\
1561 -H, --si print sizes in powers of 1000 (e.g., 1.1G)\n\
1562 "), stdout);
1563 fputs (_("\
1564 -i, --inodes list inode information instead of block usage\n\
1565 -k like --block-size=1K\n\
1566 -l, --local limit listing to local file systems\n\
1567 --no-sync do not invoke sync before getting usage info (default)\
1569 "), stdout);
1570 fputs (_("\
1571 --output[=FIELD_LIST] use the output format defined by FIELD_LIST,\n\
1572 or print all fields if FIELD_LIST is omitted.\n\
1573 -P, --portability use the POSIX output format\n\
1574 --sync invoke sync before getting usage info\n\
1575 "), stdout);
1576 fputs (_("\
1577 --total elide all entries insignificant to available space,\n\
1578 and produce a grand total\n\
1579 "), stdout);
1580 fputs (_("\
1581 -t, --type=TYPE limit listing to file systems of type TYPE\n\
1582 -T, --print-type print file system type\n\
1583 -x, --exclude-type=TYPE limit listing to file systems not of type TYPE\n\
1584 -v (ignored)\n\
1585 "), stdout);
1586 fputs (HELP_OPTION_DESCRIPTION, stdout);
1587 fputs (VERSION_OPTION_DESCRIPTION, stdout);
1588 emit_blocksize_note ("DF");
1589 emit_size_note ();
1590 fputs (_("\n\
1591 FIELD_LIST is a comma-separated list of columns to be included. Valid\n\
1592 field names are: 'source', 'fstype', 'itotal', 'iused', 'iavail', 'ipcent',\n\
1593 'size', 'used', 'avail', 'pcent', 'file' and 'target' (see info page).\n\
1594 "), stdout);
1595 emit_ancillary_info (PROGRAM_NAME);
1597 exit (status);
1601 main (int argc, char **argv)
1603 struct stat *stats IF_LINT ( = 0);
1605 initialize_main (&argc, &argv);
1606 set_program_name (argv[0]);
1607 setlocale (LC_ALL, "");
1608 bindtextdomain (PACKAGE, LOCALEDIR);
1609 textdomain (PACKAGE);
1611 atexit (close_stdout);
1613 fs_select_list = NULL;
1614 fs_exclude_list = NULL;
1615 show_all_fs = false;
1616 show_listed_fs = false;
1617 human_output_opts = -1;
1618 print_type = false;
1619 file_systems_processed = false;
1620 exit_status = EXIT_SUCCESS;
1621 print_grand_total = false;
1622 grand_fsu.fsu_blocksize = 1;
1624 /* If true, use the POSIX output format. */
1625 bool posix_format = false;
1627 char const *msg_mut_excl = _("options %s and %s are mutually exclusive");
1629 while (true)
1631 int oi = -1;
1632 int c = getopt_long (argc, argv, "aB:iF:hHklmPTt:vx:", long_options,
1633 &oi);
1634 if (c == -1)
1635 break;
1637 switch (c)
1639 case 'a':
1640 show_all_fs = true;
1641 break;
1642 case 'B':
1644 enum strtol_error e = human_options (optarg, &human_output_opts,
1645 &output_block_size);
1646 if (e != LONGINT_OK)
1647 xstrtol_fatal (e, oi, c, long_options, optarg);
1649 break;
1650 case 'i':
1651 if (header_mode == OUTPUT_MODE)
1653 error (0, 0, msg_mut_excl, "-i", "--output");
1654 usage (EXIT_FAILURE);
1656 header_mode = INODES_MODE;
1657 break;
1658 case 'h':
1659 human_output_opts = human_autoscale | human_SI | human_base_1024;
1660 output_block_size = 1;
1661 break;
1662 case 'H':
1663 human_output_opts = human_autoscale | human_SI;
1664 output_block_size = 1;
1665 break;
1666 case 'k':
1667 human_output_opts = 0;
1668 output_block_size = 1024;
1669 break;
1670 case 'l':
1671 show_local_fs = true;
1672 break;
1673 case 'm': /* obsolescent, exists for BSD compatibility */
1674 human_output_opts = 0;
1675 output_block_size = 1024 * 1024;
1676 break;
1677 case 'T':
1678 if (header_mode == OUTPUT_MODE)
1680 error (0, 0, msg_mut_excl, "-T", "--output");
1681 usage (EXIT_FAILURE);
1683 print_type = true;
1684 break;
1685 case 'P':
1686 if (header_mode == OUTPUT_MODE)
1688 error (0, 0, msg_mut_excl, "-P", "--output");
1689 usage (EXIT_FAILURE);
1691 posix_format = true;
1692 break;
1693 case SYNC_OPTION:
1694 require_sync = true;
1695 break;
1696 case NO_SYNC_OPTION:
1697 require_sync = false;
1698 break;
1700 case 'F':
1701 /* Accept -F as a synonym for -t for compatibility with Solaris. */
1702 case 't':
1703 add_fs_type (optarg);
1704 break;
1706 case 'v': /* For SysV compatibility. */
1707 /* ignore */
1708 break;
1709 case 'x':
1710 add_excluded_fs_type (optarg);
1711 break;
1713 case OUTPUT_OPTION:
1714 if (header_mode == INODES_MODE)
1716 error (0, 0, msg_mut_excl, "-i", "--output");
1717 usage (EXIT_FAILURE);
1719 if (posix_format && header_mode == DEFAULT_MODE)
1721 error (0, 0, msg_mut_excl, "-P", "--output");
1722 usage (EXIT_FAILURE);
1724 if (print_type)
1726 error (0, 0, msg_mut_excl, "-T", "--output");
1727 usage (EXIT_FAILURE);
1729 header_mode = OUTPUT_MODE;
1730 if (optarg)
1731 decode_output_arg (optarg);
1732 break;
1734 case TOTAL_OPTION:
1735 print_grand_total = true;
1736 break;
1738 case_GETOPT_HELP_CHAR;
1739 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
1741 default:
1742 usage (EXIT_FAILURE);
1746 if (human_output_opts == -1)
1748 if (posix_format)
1750 human_output_opts = 0;
1751 output_block_size = (getenv ("POSIXLY_CORRECT") ? 512 : 1024);
1753 else
1754 human_options (getenv ("DF_BLOCK_SIZE"),
1755 &human_output_opts, &output_block_size);
1758 if (header_mode == INODES_MODE || header_mode == OUTPUT_MODE)
1760 else if (human_output_opts & human_autoscale)
1761 header_mode = HUMAN_MODE;
1762 else if (posix_format)
1763 header_mode = POSIX_MODE;
1765 /* Fail if the same file system type was both selected and excluded. */
1767 bool match = false;
1768 struct fs_type_list *fs_incl;
1769 for (fs_incl = fs_select_list; fs_incl; fs_incl = fs_incl->fs_next)
1771 struct fs_type_list *fs_excl;
1772 for (fs_excl = fs_exclude_list; fs_excl; fs_excl = fs_excl->fs_next)
1774 if (STREQ (fs_incl->fs_name, fs_excl->fs_name))
1776 error (0, 0,
1777 _("file system type %s both selected and excluded"),
1778 quote (fs_incl->fs_name));
1779 match = true;
1780 break;
1784 if (match)
1785 return EXIT_FAILURE;
1788 assume (0 < optind);
1790 if (optind < argc)
1792 /* stat each of the given entries to make sure any corresponding
1793 partition is automounted. This must be done before reading the
1794 file system table. */
1795 stats = xnmalloc (argc - optind, sizeof *stats);
1796 for (int i = optind; i < argc; ++i)
1798 int err = automount_stat_err (argv[i], &stats[i - optind]);
1799 if (err != 0)
1801 error (0, err, "%s", quotef (argv[i]));
1802 exit_status = EXIT_FAILURE;
1803 argv[i] = NULL;
1808 mount_list =
1809 read_file_system_list ((fs_select_list != NULL
1810 || fs_exclude_list != NULL
1811 || print_type
1812 || field_data[FSTYPE_FIELD].used
1813 || show_local_fs));
1815 if (mount_list == NULL)
1817 /* Couldn't read the table of mounted file systems.
1818 Fail if df was invoked with no file name arguments,
1819 or when either of -a, -l, -t or -x is used with file name
1820 arguments. Otherwise, merely give a warning and proceed. */
1821 int status = 0;
1822 if ( ! (optind < argc)
1823 || (show_all_fs
1824 || show_local_fs
1825 || fs_select_list != NULL
1826 || fs_exclude_list != NULL))
1828 status = EXIT_FAILURE;
1830 char const *warning = (status == 0 ? _("Warning: ") : "");
1831 error (status, errno, "%s%s", warning,
1832 _("cannot read table of mounted file systems"));
1835 if (require_sync)
1836 sync ();
1838 get_field_list ();
1839 get_header ();
1841 if (optind < argc)
1843 /* Display explicitly requested empty file systems. */
1844 show_listed_fs = true;
1846 for (int i = optind; i < argc; ++i)
1847 if (argv[i])
1848 get_entry (argv[i], &stats[i - optind]);
1850 IF_LINT (free (stats));
1852 else
1853 get_all_entries ();
1855 if (file_systems_processed)
1857 if (print_grand_total)
1858 get_dev ("total",
1859 (field_data[SOURCE_FIELD].used ? "-" : "total"),
1860 NULL, NULL, NULL, false, false, &grand_fsu, false);
1862 print_table ();
1864 else
1866 /* Print the "no FS processed" diagnostic only if there was no preceding
1867 diagnostic, e.g., if all have been excluded. */
1868 if (exit_status == EXIT_SUCCESS)
1869 die (EXIT_FAILURE, 0, _("no file systems processed"));
1872 IF_LINT (free (columns));
1874 return exit_status;