doc: od --strings: clarify operation
[coreutils.git] / src / df.c
blobf3d8e2e2baa736bf935da7b8a52f29814826b00d
1 /* df - summarize free file system space
2 Copyright (C) 1991-2023 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 putchar ('\n');
412 /* Dynamically allocate a struct field_t in COLUMNS, which
413 can then be accessed with standard array notation. */
415 static void
416 alloc_field (int f, char const *c)
418 ncolumns++;
419 columns = xnrealloc (columns, ncolumns, sizeof (struct field_data_t *));
420 columns[ncolumns - 1] = &field_data[f];
421 if (c != NULL)
422 columns[ncolumns - 1]->caption = c;
424 if (field_data[f].used)
425 assert (!"field used");
427 /* Mark field as used. */
428 field_data[f].used = true;
432 /* Given a string, ARG, containing a comma-separated list of arguments
433 to the --output option, add the appropriate fields to columns. */
434 static void
435 decode_output_arg (char const *arg)
437 char *arg_writable = xstrdup (arg);
438 char *s = arg_writable;
441 /* find next comma */
442 char *comma = strchr (s, ',');
444 /* If we found a comma, put a NUL in its place and advance. */
445 if (comma)
446 *comma++ = 0;
448 /* process S. */
449 display_field_t field = INVALID_FIELD;
450 for (unsigned int i = 0; i < ARRAY_CARDINALITY (field_data); i++)
452 if (STREQ (field_data[i].arg, s))
454 field = i;
455 break;
458 if (field == INVALID_FIELD)
460 error (0, 0, _("option --output: field %s unknown"), quote (s));
461 usage (EXIT_FAILURE);
464 if (field_data[field].used)
466 /* Prevent the fields from being used more than once. */
467 error (0, 0, _("option --output: field %s used more than once"),
468 quote (field_data[field].arg));
469 usage (EXIT_FAILURE);
472 switch (field)
474 case SOURCE_FIELD:
475 case FSTYPE_FIELD:
476 case USED_FIELD:
477 case PCENT_FIELD:
478 case ITOTAL_FIELD:
479 case IUSED_FIELD:
480 case IAVAIL_FIELD:
481 case IPCENT_FIELD:
482 case TARGET_FIELD:
483 case FILE_FIELD:
484 alloc_field (field, NULL);
485 break;
487 case SIZE_FIELD:
488 alloc_field (field, N_("Size"));
489 break;
491 case AVAIL_FIELD:
492 alloc_field (field, N_("Avail"));
493 break;
495 default:
496 assert (!"invalid field");
498 s = comma;
500 while (s);
502 free (arg_writable);
505 /* Get the appropriate columns for the mode. */
506 static void
507 get_field_list (void)
509 switch (header_mode)
511 case DEFAULT_MODE:
512 alloc_field (SOURCE_FIELD, NULL);
513 if (print_type)
514 alloc_field (FSTYPE_FIELD, NULL);
515 alloc_field (SIZE_FIELD, NULL);
516 alloc_field (USED_FIELD, NULL);
517 alloc_field (AVAIL_FIELD, NULL);
518 alloc_field (PCENT_FIELD, NULL);
519 alloc_field (TARGET_FIELD, NULL);
520 break;
522 case HUMAN_MODE:
523 alloc_field (SOURCE_FIELD, NULL);
524 if (print_type)
525 alloc_field (FSTYPE_FIELD, NULL);
527 alloc_field (SIZE_FIELD, N_("Size"));
528 alloc_field (USED_FIELD, NULL);
529 alloc_field (AVAIL_FIELD, N_("Avail"));
530 alloc_field (PCENT_FIELD, NULL);
531 alloc_field (TARGET_FIELD, NULL);
532 break;
534 case INODES_MODE:
535 alloc_field (SOURCE_FIELD, NULL);
536 if (print_type)
537 alloc_field (FSTYPE_FIELD, NULL);
538 alloc_field (ITOTAL_FIELD, NULL);
539 alloc_field (IUSED_FIELD, NULL);
540 alloc_field (IAVAIL_FIELD, NULL);
541 alloc_field (IPCENT_FIELD, NULL);
542 alloc_field (TARGET_FIELD, NULL);
543 break;
545 case POSIX_MODE:
546 alloc_field (SOURCE_FIELD, NULL);
547 if (print_type)
548 alloc_field (FSTYPE_FIELD, NULL);
549 alloc_field (SIZE_FIELD, NULL);
550 alloc_field (USED_FIELD, NULL);
551 alloc_field (AVAIL_FIELD, NULL);
552 alloc_field (PCENT_FIELD, N_("Capacity"));
553 alloc_field (TARGET_FIELD, NULL);
554 break;
556 case OUTPUT_MODE:
557 if (!ncolumns)
559 /* Add all fields if --output was given without a field list. */
560 decode_output_arg (all_args_string);
562 break;
564 default:
565 assert (!"invalid header_mode");
569 /* Obtain the appropriate header entries. */
571 static void
572 get_header (void)
574 size_t col;
576 alloc_table_row ();
578 for (col = 0; col < ncolumns; col++)
580 char *cell = NULL;
581 char const *header = _(columns[col]->caption);
583 if (columns[col]->field == SIZE_FIELD
584 && (header_mode == DEFAULT_MODE
585 || (header_mode == OUTPUT_MODE
586 && !(human_output_opts & human_autoscale))))
588 char buf[LONGEST_HUMAN_READABLE + 1];
590 int opts = (human_suppress_point_zero
591 | human_autoscale | human_SI
592 | (human_output_opts
593 & (human_group_digits | human_base_1024 | human_B)));
595 /* Prefer the base that makes the human-readable value more exact,
596 if there is a difference. */
598 uintmax_t q1000 = output_block_size;
599 uintmax_t q1024 = output_block_size;
600 bool divisible_by_1000;
601 bool divisible_by_1024;
605 divisible_by_1000 = q1000 % 1000 == 0; q1000 /= 1000;
606 divisible_by_1024 = q1024 % 1024 == 0; q1024 /= 1024;
608 while (divisible_by_1000 & divisible_by_1024);
610 if (divisible_by_1000 < divisible_by_1024)
611 opts |= human_base_1024;
612 if (divisible_by_1024 < divisible_by_1000)
613 opts &= ~human_base_1024;
614 if (! (opts & human_base_1024))
615 opts |= human_B;
617 char *num = human_readable (output_block_size, buf, opts, 1, 1);
619 /* Reset the header back to the default in OUTPUT_MODE. */
620 header = _("blocks");
622 /* TRANSLATORS: this is the "1K-blocks" header in "df" output. */
623 if (asprintf (&cell, _("%s-%s"), num, header) == -1)
624 cell = NULL;
626 else if (header_mode == POSIX_MODE && columns[col]->field == SIZE_FIELD)
628 char buf[INT_BUFSIZE_BOUND (uintmax_t)];
629 char *num = umaxtostr (output_block_size, buf);
631 /* TRANSLATORS: this is the "1024-blocks" header in "df -P". */
632 if (asprintf (&cell, _("%s-%s"), num, header) == -1)
633 cell = NULL;
635 else
636 cell = strdup (header);
638 if (!cell)
639 xalloc_die ();
641 replace_problematic_chars (cell);
643 table[nrows - 1][col] = cell;
645 size_t cell_width = mbswidth (cell, 0);
646 columns[col]->width = MAX (columns[col]->width, cell_width);
650 /* Is FSTYPE a type of file system that should be listed? */
652 ATTRIBUTE_PURE
653 static bool
654 selected_fstype (char const *fstype)
656 const struct fs_type_list *fsp;
658 if (fs_select_list == NULL || fstype == NULL)
659 return true;
660 for (fsp = fs_select_list; fsp; fsp = fsp->fs_next)
661 if (STREQ (fstype, fsp->fs_name))
662 return true;
663 return false;
666 /* Is FSTYPE a type of file system that should be omitted? */
668 ATTRIBUTE_PURE
669 static bool
670 excluded_fstype (char const *fstype)
672 const struct fs_type_list *fsp;
674 if (fs_exclude_list == NULL || fstype == NULL)
675 return false;
676 for (fsp = fs_exclude_list; fsp; fsp = fsp->fs_next)
677 if (STREQ (fstype, fsp->fs_name))
678 return true;
679 return false;
682 static size_t
683 devlist_hash (void const *x, size_t table_size)
685 struct devlist const *p = x;
686 return (uintmax_t) p->dev_num % table_size;
689 static bool
690 devlist_compare (void const *x, void const *y)
692 struct devlist const *a = x;
693 struct devlist const *b = y;
694 return a->dev_num == b->dev_num;
697 static struct devlist *
698 devlist_for_dev (dev_t dev)
700 if (devlist_table == NULL)
701 return NULL;
702 struct devlist dev_entry;
703 dev_entry.dev_num = dev;
705 struct devlist *found = hash_lookup (devlist_table, &dev_entry);
706 if (found == NULL)
707 return NULL;
709 /* Return the last devlist entry we have seen with this dev_num */
710 return found->seen_last;
713 /* Filter mount list by skipping duplicate entries.
714 In the case of duplicates - based on the device number - the mount entry
715 with a '/' in its me_devname (i.e., not pseudo name like tmpfs) wins.
716 If both have a real devname (e.g. bind mounts), then that with the shorter
717 me_mountdir wins. With DEVICES_ONLY == true (set with df -a), only update
718 the global devlist_table, rather than filtering the global mount_list. */
720 static void
721 filter_mount_list (bool devices_only)
723 struct mount_entry *me;
725 /* Temporary list to keep entries ordered. */
726 struct devlist *device_list = NULL;
727 int mount_list_size = 0;
729 for (me = mount_list; me; me = me->me_next)
730 mount_list_size++;
732 devlist_table = hash_initialize (mount_list_size, NULL,
733 devlist_hash, devlist_compare, NULL);
734 if (devlist_table == NULL)
735 xalloc_die ();
737 /* Sort all 'wanted' entries into the list device_list. */
738 for (me = mount_list; me;)
740 struct stat buf;
741 struct mount_entry *discard_me = NULL;
743 /* Avoid stating remote file systems as that may hang.
744 On Linux we probably have me_dev populated from /proc/self/mountinfo,
745 however we still stat() in case another device was mounted later. */
746 if ((me->me_remote && show_local_fs)
747 || (me->me_dummy && !show_all_fs && !show_listed_fs)
748 || (!selected_fstype (me->me_type) || excluded_fstype (me->me_type))
749 || -1 == stat (me->me_mountdir, &buf))
751 /* If remote, and showing just local, or FS type is excluded,
752 add ME for filtering later.
753 If stat failed; add ME to be able to complain about it later. */
754 buf.st_dev = me->me_dev;
756 else
758 /* If we've already seen this device... */
759 struct devlist *seen_dev = devlist_for_dev (buf.st_dev);
761 if (seen_dev)
763 bool target_nearer_root = strlen (seen_dev->me->me_mountdir)
764 > strlen (me->me_mountdir);
765 /* With bind mounts, prefer items nearer the root of the source */
766 bool source_below_root = seen_dev->me->me_mntroot != NULL
767 && me->me_mntroot != NULL
768 && (strlen (seen_dev->me->me_mntroot)
769 < strlen (me->me_mntroot));
770 if (! print_grand_total
771 && me->me_remote && seen_dev->me->me_remote
772 && ! STREQ (seen_dev->me->me_devname, me->me_devname))
774 /* Don't discard remote entries with different locations,
775 as these are more likely to be explicitly mounted.
776 However avoid this when producing a total to give
777 a more accurate value in that case. */
779 else if ((strchr (me->me_devname, '/')
780 /* let "real" devices with '/' in the name win. */
781 && ! strchr (seen_dev->me->me_devname, '/'))
782 /* let points towards the root of the device win. */
783 || (target_nearer_root && ! source_below_root)
784 /* let an entry overmounted on a new device win... */
785 || (! STREQ (seen_dev->me->me_devname, me->me_devname)
786 /* ... but only when matching an existing mnt point,
787 to avoid problematic replacement when given
788 inaccurate mount lists, seen with some chroot
789 environments for example. */
790 && STREQ (me->me_mountdir,
791 seen_dev->me->me_mountdir)))
793 /* Discard mount entry for existing device. */
794 discard_me = seen_dev->me;
795 seen_dev->me = me;
797 else
799 /* Discard mount entry currently being processed. */
800 discard_me = me;
806 if (discard_me)
808 me = me->me_next;
809 if (! devices_only)
810 free_mount_entry (discard_me);
812 else
814 /* Add the device number to the device_table. */
815 struct devlist *devlist = xmalloc (sizeof *devlist);
816 devlist->me = me;
817 devlist->dev_num = buf.st_dev;
818 devlist->next = device_list;
819 device_list = devlist;
821 struct devlist *hash_entry = hash_insert (devlist_table, devlist);
822 if (hash_entry == NULL)
823 xalloc_die ();
824 /* Ensure lookups use this latest devlist. */
825 hash_entry->seen_last = devlist;
827 me = me->me_next;
831 /* Finally rebuild the mount_list from the devlist. */
832 if (! devices_only) {
833 mount_list = NULL;
834 while (device_list)
836 /* Add the mount entry. */
837 me = device_list->me;
838 me->me_next = mount_list;
839 mount_list = me;
840 struct devlist *next = device_list->next;
841 free (device_list);
842 device_list = next;
845 hash_free (devlist_table);
846 devlist_table = NULL;
851 /* Search a mount entry list for device id DEV.
852 Return the corresponding mount entry if found or NULL if not. */
854 ATTRIBUTE_PURE
855 static struct mount_entry const *
856 me_for_dev (dev_t dev)
858 struct devlist *dl = devlist_for_dev (dev);
859 if (dl)
860 return dl->me;
862 return NULL;
865 /* Return true if N is a known integer value. On many file systems,
866 UINTMAX_MAX represents an unknown value; on AIX, UINTMAX_MAX - 1
867 represents unknown. Use a rule that works on AIX file systems, and
868 that almost-always works on other types. */
869 static bool
870 known_value (uintmax_t n)
872 return n < UINTMAX_MAX - 1;
875 /* Like human_readable (N, BUF, human_output_opts, INPUT_UNITS, OUTPUT_UNITS),
876 except:
878 - If NEGATIVE, then N represents a negative number,
879 expressed in two's complement.
880 - Otherwise, return "-" if N is unknown. */
882 static char const *
883 df_readable (bool negative, uintmax_t n, char *buf,
884 uintmax_t input_units, uintmax_t output_units)
886 if (! known_value (n) && !negative)
887 return "-";
888 else
890 char *p = human_readable (negative ? -n : n, buf + negative,
891 human_output_opts, input_units, output_units);
892 if (negative)
893 *--p = '-';
894 return p;
898 /* Add integral value while using uintmax_t for value part and separate
899 negation flag. It adds value of SRC and SRC_NEG to DEST and DEST_NEG.
900 The result will be in DEST and DEST_NEG. See df_readable to understand
901 how the negation flag is used. */
902 static void
903 add_uint_with_neg_flag (uintmax_t *dest, bool *dest_neg,
904 uintmax_t src, bool src_neg)
906 if (*dest_neg == src_neg)
908 *dest += src;
909 return;
912 if (*dest_neg)
913 *dest = -*dest;
915 if (src_neg)
916 src = -src;
918 if (src < *dest)
919 *dest -= src;
920 else
922 *dest = src - *dest;
923 *dest_neg = src_neg;
926 if (*dest_neg)
927 *dest = -*dest;
930 /* Return true if S ends in a string that may be a 36-byte UUID,
931 i.e., of the form HHHHHHHH-HHHH-HHHH-HHHH-HHHHHHHHHHHH, where
932 each H is an upper or lower case hexadecimal digit. */
933 ATTRIBUTE_PURE
934 static bool
935 has_uuid_suffix (char const *s)
937 size_t len = strlen (s);
938 return (36 < len
939 && strspn (s + len - 36, "-0123456789abcdefABCDEF") == 36);
942 /* Obtain the block values BV and inode values IV
943 from the file system usage FSU. */
944 static void
945 get_field_values (struct field_values_t *bv,
946 struct field_values_t *iv,
947 const struct fs_usage *fsu)
949 /* Inode values. */
950 iv->input_units = iv->output_units = 1;
951 iv->total = fsu->fsu_files;
952 iv->available = iv->available_to_root = fsu->fsu_ffree;
953 iv->negate_available = false;
955 iv->used = UINTMAX_MAX;
956 iv->negate_used = false;
957 if (known_value (iv->total) && known_value (iv->available_to_root))
959 iv->used = iv->total - iv->available_to_root;
960 iv->negate_used = (iv->total < iv->available_to_root);
963 /* Block values. */
964 bv->input_units = fsu->fsu_blocksize;
965 bv->output_units = output_block_size;
966 bv->total = fsu->fsu_blocks;
967 bv->available = fsu->fsu_bavail;
968 bv->available_to_root = fsu->fsu_bfree;
969 bv->negate_available = (fsu->fsu_bavail_top_bit_set
970 && known_value (fsu->fsu_bavail));
972 bv->used = UINTMAX_MAX;
973 bv->negate_used = false;
974 if (known_value (bv->total) && known_value (bv->available_to_root))
976 bv->used = bv->total - bv->available_to_root;
977 bv->negate_used = (bv->total < bv->available_to_root);
981 /* Add block and inode values to grand total. */
982 static void
983 add_to_grand_total (struct field_values_t *bv, struct field_values_t *iv)
985 if (known_value (iv->total))
986 grand_fsu.fsu_files += iv->total;
987 if (known_value (iv->available))
988 grand_fsu.fsu_ffree += iv->available;
990 if (known_value (bv->total))
991 grand_fsu.fsu_blocks += bv->input_units * bv->total;
992 if (known_value (bv->available_to_root))
993 grand_fsu.fsu_bfree += bv->input_units * bv->available_to_root;
994 if (known_value (bv->available))
995 add_uint_with_neg_flag (&grand_fsu.fsu_bavail,
996 &grand_fsu.fsu_bavail_top_bit_set,
997 bv->input_units * bv->available,
998 bv->negate_available);
1001 /* Obtain a space listing for the device with absolute file name DEVICE.
1002 If MOUNT_POINT is non-NULL, it is the name of the root of the
1003 file system on DEVICE.
1004 If STAT_FILE is non-null, it is the name of a file within the file
1005 system that the user originally asked for; this provides better
1006 diagnostics, and sometimes it provides better results on networked
1007 file systems that give different free-space results depending on
1008 where in the file system you probe.
1009 If FSTYPE is non-NULL, it is the type of the file system on DEVICE.
1010 If MOUNT_POINT is non-NULL, then DEVICE may be NULL -- certain systems may
1011 not be able to produce statistics in this case.
1012 ME_DUMMY and ME_REMOTE are the mount entry flags.
1013 Caller must set PROCESS_ALL to true when iterating over all entries, as
1014 when df is invoked with no non-option argument. See below for details. */
1016 static void
1017 get_dev (char const *device, char const *mount_point, char const *file,
1018 char const *stat_file, char const *fstype,
1019 bool me_dummy, bool me_remote,
1020 const struct fs_usage *force_fsu,
1021 bool process_all)
1023 if (me_remote && show_local_fs)
1024 return;
1026 if (me_dummy && !show_all_fs && !show_listed_fs)
1027 return;
1029 if (!selected_fstype (fstype) || excluded_fstype (fstype))
1030 return;
1032 /* Ignore relative MOUNT_POINTs, which are present for example
1033 in /proc/mounts on Linux with network namespaces. */
1034 if (!force_fsu && mount_point && ! IS_ABSOLUTE_FILE_NAME (mount_point))
1035 return;
1037 /* If MOUNT_POINT is NULL, then the file system is not mounted, and this
1038 program reports on the file system that the special file is on.
1039 It would be better to report on the unmounted file system,
1040 but statfs doesn't do that on most systems. */
1041 if (!stat_file)
1042 stat_file = mount_point ? mount_point : device;
1044 struct fs_usage fsu;
1045 if (force_fsu)
1046 fsu = *force_fsu;
1047 else if (get_fs_usage (stat_file, device, &fsu))
1049 /* If we can't access a system provided entry due
1050 to it not being present (now), or due to permissions,
1051 just output placeholder values rather than failing. */
1052 if (process_all && (errno == EACCES || errno == ENOENT))
1054 if (! show_all_fs)
1055 return;
1057 fstype = "-";
1058 fsu.fsu_bavail_top_bit_set = false;
1059 fsu.fsu_blocksize = fsu.fsu_blocks = fsu.fsu_bfree =
1060 fsu.fsu_bavail = fsu.fsu_files = fsu.fsu_ffree = UINTMAX_MAX;
1062 else
1064 error (0, errno, "%s", quotef (stat_file));
1065 exit_status = EXIT_FAILURE;
1066 return;
1069 else if (process_all && show_all_fs)
1071 /* Ensure we don't output incorrect stats for over-mounted directories.
1072 Discard stats when the device name doesn't match. Though don't
1073 discard when used and current mount entries are both remote due
1074 to the possibility of aliased host names or exports. */
1075 struct stat sb;
1076 if (stat (stat_file, &sb) == 0)
1078 struct mount_entry const * dev_me = me_for_dev (sb.st_dev);
1079 if (dev_me && ! STREQ (dev_me->me_devname, device)
1080 && (! dev_me->me_remote || ! me_remote))
1082 fstype = "-";
1083 fsu.fsu_bavail_top_bit_set = false;
1084 fsu.fsu_blocksize = fsu.fsu_blocks = fsu.fsu_bfree =
1085 fsu.fsu_bavail = fsu.fsu_files = fsu.fsu_ffree = UINTMAX_MAX;
1090 if (fsu.fsu_blocks == 0 && !show_all_fs && !show_listed_fs)
1091 return;
1093 if (! force_fsu)
1094 file_systems_processed = true;
1096 alloc_table_row ();
1098 if (! device)
1099 device = "-"; /* unknown */
1101 if (! file)
1102 file = "-"; /* unspecified */
1104 char *dev_name = xstrdup (device);
1105 char *resolved_dev;
1107 /* On some systems, dev_name is a long-named symlink like
1108 /dev/disk/by-uuid/828fc648-9f30-43d8-a0b1-f7196a2edb66 pointing to a
1109 much shorter and more useful name like /dev/sda1. It may also look
1110 like /dev/mapper/luks-828fc648-9f30-43d8-a0b1-f7196a2edb66 and point to
1111 /dev/dm-0. When process_all is true and dev_name is a symlink whose
1112 name ends with a UUID use the resolved name instead. */
1113 if (process_all
1114 && has_uuid_suffix (dev_name)
1115 && (resolved_dev = canonicalize_filename_mode (dev_name, CAN_EXISTING)))
1117 free (dev_name);
1118 dev_name = resolved_dev;
1121 if (! fstype)
1122 fstype = "-"; /* unknown */
1124 struct field_values_t block_values;
1125 struct field_values_t inode_values;
1126 get_field_values (&block_values, &inode_values, &fsu);
1128 /* Add to grand total unless processing grand total line. */
1129 if (print_grand_total && ! force_fsu)
1130 add_to_grand_total (&block_values, &inode_values);
1132 size_t col;
1133 for (col = 0; col < ncolumns; col++)
1135 char buf[LONGEST_HUMAN_READABLE + 2];
1136 char *cell;
1138 struct field_values_t *v;
1139 switch (columns[col]->field_type)
1141 case BLOCK_FLD:
1142 v = &block_values;
1143 break;
1144 case INODE_FLD:
1145 v = &inode_values;
1146 break;
1147 case OTHER_FLD:
1148 v = NULL;
1149 break;
1150 default:
1151 v = NULL; /* Avoid warnings where assert() is not __noreturn__. */
1152 assert (!"bad field_type");
1155 switch (columns[col]->field)
1157 case SOURCE_FIELD:
1158 cell = xstrdup (dev_name);
1159 break;
1161 case FSTYPE_FIELD:
1162 cell = xstrdup (fstype);
1163 break;
1165 case SIZE_FIELD:
1166 case ITOTAL_FIELD:
1167 cell = xstrdup (df_readable (false, v->total, buf,
1168 v->input_units, v->output_units));
1169 break;
1171 case USED_FIELD:
1172 case IUSED_FIELD:
1173 cell = xstrdup (df_readable (v->negate_used, v->used, buf,
1174 v->input_units, v->output_units));
1175 break;
1177 case AVAIL_FIELD:
1178 case IAVAIL_FIELD:
1179 cell = xstrdup (df_readable (v->negate_available, v->available, buf,
1180 v->input_units, v->output_units));
1181 break;
1183 case PCENT_FIELD:
1184 case IPCENT_FIELD:
1186 double pct = -1;
1187 if (! known_value (v->used) || ! known_value (v->available))
1189 else if (!v->negate_used
1190 && v->used <= TYPE_MAXIMUM (uintmax_t) / 100
1191 && v->used + v->available != 0
1192 && (v->used + v->available < v->used)
1193 == v->negate_available)
1195 uintmax_t u100 = v->used * 100;
1196 uintmax_t nonroot_total = v->used + v->available;
1197 pct = u100 / nonroot_total + (u100 % nonroot_total != 0);
1199 else
1201 /* The calculation cannot be done easily with integer
1202 arithmetic. Fall back on floating point. This can suffer
1203 from minor rounding errors, but doing it exactly requires
1204 multiple precision arithmetic, and it's not worth the
1205 aggravation. */
1206 double u = v->negate_used ? - (double) - v->used : v->used;
1207 double a = v->negate_available
1208 ? - (double) - v->available : v->available;
1209 double nonroot_total = u + a;
1210 if (nonroot_total)
1212 long int lipct = pct = u * 100 / nonroot_total;
1213 double ipct = lipct;
1215 /* Like 'pct = ceil (dpct);', but avoid ceil so that
1216 the math library needn't be linked. */
1217 if (ipct - 1 < pct && pct <= ipct + 1)
1218 pct = ipct + (ipct < pct);
1222 if (0 <= pct)
1224 if (asprintf (&cell, "%.0f%%", pct) == -1)
1225 cell = NULL;
1227 else
1228 cell = strdup ("-");
1230 if (!cell)
1231 xalloc_die ();
1233 break;
1236 case FILE_FIELD:
1237 cell = xstrdup (file);
1238 break;
1240 case TARGET_FIELD:
1241 #ifdef HIDE_AUTOMOUNT_PREFIX
1242 /* Don't print the first directory name in MOUNT_POINT if it's an
1243 artifact of an automounter. This is a bit too aggressive to be
1244 the default. */
1245 if (STRNCMP_LIT (mount_point, "/auto/") == 0)
1246 mount_point += 5;
1247 else if (STRNCMP_LIT (mount_point, "/tmp_mnt/") == 0)
1248 mount_point += 8;
1249 #endif
1250 cell = xstrdup (mount_point);
1251 break;
1253 default:
1254 assert (!"unhandled field");
1257 if (!cell)
1258 assert (!"empty cell");
1260 replace_problematic_chars (cell);
1261 size_t cell_width = mbswidth (cell, 0);
1262 columns[col]->width = MAX (columns[col]->width, cell_width);
1263 table[nrows - 1][col] = cell;
1265 free (dev_name);
1268 /* Scan the mount list returning the _last_ device found for MOUNT.
1269 NULL is returned if MOUNT not found. The result is malloced. */
1270 static char *
1271 last_device_for_mount (char const *mount)
1273 struct mount_entry const *me;
1274 struct mount_entry const *le = NULL;
1276 for (me = mount_list; me; me = me->me_next)
1278 if (STREQ (me->me_mountdir, mount))
1279 le = me;
1282 if (le)
1284 char *devname = le->me_devname;
1285 char *canon_dev = canonicalize_file_name (devname);
1286 if (canon_dev && IS_ABSOLUTE_FILE_NAME (canon_dev))
1287 return canon_dev;
1288 free (canon_dev);
1289 return xstrdup (le->me_devname);
1291 else
1292 return NULL;
1295 /* If DEVICE corresponds to a mount point, show its usage
1296 and return true. Otherwise, return false. */
1297 static bool
1298 get_device (char const *device)
1300 struct mount_entry const *me;
1301 struct mount_entry const *best_match = NULL;
1302 bool best_match_accessible = false;
1303 bool eclipsed_device = false;
1304 char const *file = device;
1306 char *resolved = canonicalize_file_name (device);
1307 if (resolved && IS_ABSOLUTE_FILE_NAME (resolved))
1308 device = resolved;
1310 size_t best_match_len = SIZE_MAX;
1311 for (me = mount_list; me; me = me->me_next)
1313 /* TODO: Should cache canon_dev in the mount_entry struct. */
1314 char *devname = me->me_devname;
1315 char *canon_dev = canonicalize_file_name (me->me_devname);
1316 if (canon_dev && IS_ABSOLUTE_FILE_NAME (canon_dev))
1317 devname = canon_dev;
1319 if (STREQ (device, devname))
1321 char *last_device = last_device_for_mount (me->me_mountdir);
1322 eclipsed_device = last_device && ! STREQ (last_device, devname);
1323 size_t len = strlen (me->me_mountdir);
1325 if (! eclipsed_device
1326 && (! best_match_accessible || len < best_match_len))
1328 struct stat device_stats;
1329 bool this_match_accessible = false;
1331 if (stat (me->me_mountdir, &device_stats) == 0)
1332 best_match_accessible = this_match_accessible = true;
1334 if (this_match_accessible
1335 || (! best_match_accessible && len < best_match_len))
1337 best_match = me;
1338 if (len == 1) /* Traditional root. */
1340 free (last_device);
1341 free (canon_dev);
1342 break;
1344 else
1345 best_match_len = len;
1349 free (last_device);
1352 free (canon_dev);
1355 free (resolved);
1357 if (best_match)
1359 get_dev (best_match->me_devname, best_match->me_mountdir, file, NULL,
1360 best_match->me_type, best_match->me_dummy,
1361 best_match->me_remote, NULL, false);
1362 return true;
1364 else if (eclipsed_device)
1366 error (0, 0, _("cannot access %s: over-mounted by another device"),
1367 quoteaf (file));
1368 exit_status = EXIT_FAILURE;
1369 return true;
1372 return false;
1375 /* Figure out which device file or directory POINT is mounted on
1376 and show its device usage.
1377 STATP must be the result of 'stat (POINT, STATP)'. */
1378 static void
1379 get_point (char const *point, const struct stat *statp)
1381 struct stat device_stats;
1382 struct mount_entry *me;
1383 struct mount_entry const *best_match = NULL;
1385 /* Calculate the real absolute file name for POINT, and use that to find
1386 the mount point. This avoids statting unavailable mount points,
1387 which can hang df. */
1388 char *resolved = canonicalize_file_name (point);
1389 if (resolved && resolved[0] == '/')
1391 size_t resolved_len = strlen (resolved);
1392 size_t best_match_len = 0;
1394 for (me = mount_list; me; me = me->me_next)
1396 if (!STREQ (me->me_type, "lofs")
1397 && (!best_match || best_match->me_dummy || !me->me_dummy))
1399 size_t len = strlen (me->me_mountdir);
1400 if (best_match_len <= len && len <= resolved_len
1401 && (len == 1 /* root file system */
1402 || ((len == resolved_len || resolved[len] == '/')
1403 && STREQ_LEN (me->me_mountdir, resolved, len))))
1405 best_match = me;
1406 best_match_len = len;
1411 free (resolved);
1412 if (best_match
1413 && (stat (best_match->me_mountdir, &device_stats) != 0
1414 || device_stats.st_dev != statp->st_dev))
1415 best_match = NULL;
1417 if (! best_match)
1418 for (me = mount_list; me; me = me->me_next)
1420 if (me->me_dev == (dev_t) -1)
1422 if (stat (me->me_mountdir, &device_stats) == 0)
1423 me->me_dev = device_stats.st_dev;
1424 else
1426 /* Report only I/O errors. Other errors might be
1427 caused by shadowed mount points, which means POINT
1428 can't possibly be on this file system. */
1429 if (errno == EIO)
1431 error (0, errno, "%s", quotef (me->me_mountdir));
1432 exit_status = EXIT_FAILURE;
1435 /* So we won't try and fail repeatedly. */
1436 me->me_dev = (dev_t) -2;
1440 if (statp->st_dev == me->me_dev
1441 && !STREQ (me->me_type, "lofs")
1442 && (!best_match || best_match->me_dummy || !me->me_dummy))
1444 /* Skip bogus mtab entries. */
1445 if (stat (me->me_mountdir, &device_stats) != 0
1446 || device_stats.st_dev != me->me_dev)
1447 me->me_dev = (dev_t) -2;
1448 else
1449 best_match = me;
1453 if (best_match)
1454 get_dev (best_match->me_devname, best_match->me_mountdir, point, point,
1455 best_match->me_type, best_match->me_dummy, best_match->me_remote,
1456 NULL, false);
1457 else
1459 /* We couldn't find the mount entry corresponding to POINT. Go ahead and
1460 print as much info as we can; methods that require the device to be
1461 present will fail at a later point. */
1463 /* Find the actual mount point. */
1464 char *mp = find_mount_point (point, statp);
1465 if (mp)
1467 get_dev (NULL, mp, point, NULL, NULL, false, false, NULL, false);
1468 free (mp);
1473 /* Determine what kind of node NAME is and show the device usage
1474 for it. STATP is the results of 'stat' on NAME. */
1476 static void
1477 get_entry (char const *name, struct stat const *statp)
1479 if ((S_ISBLK (statp->st_mode) || S_ISCHR (statp->st_mode))
1480 && get_device (name))
1481 return;
1483 get_point (name, statp);
1486 /* Show all mounted file systems, except perhaps those that are of
1487 an unselected type or are empty. */
1489 static void
1490 get_all_entries (void)
1492 struct mount_entry *me;
1494 filter_mount_list (show_all_fs);
1496 for (me = mount_list; me; me = me->me_next)
1497 get_dev (me->me_devname, me->me_mountdir, NULL, NULL, me->me_type,
1498 me->me_dummy, me->me_remote, NULL, true);
1501 /* Add FSTYPE to the list of file system types to display. */
1503 static void
1504 add_fs_type (char const *fstype)
1506 struct fs_type_list *fsp;
1508 fsp = xmalloc (sizeof *fsp);
1509 fsp->fs_name = (char *) fstype;
1510 fsp->fs_next = fs_select_list;
1511 fs_select_list = fsp;
1514 /* Add FSTYPE to the list of file system types to be omitted. */
1516 static void
1517 add_excluded_fs_type (char const *fstype)
1519 struct fs_type_list *fsp;
1521 fsp = xmalloc (sizeof *fsp);
1522 fsp->fs_name = (char *) fstype;
1523 fsp->fs_next = fs_exclude_list;
1524 fs_exclude_list = fsp;
1527 void
1528 usage (int status)
1530 if (status != EXIT_SUCCESS)
1531 emit_try_help ();
1532 else
1534 printf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name);
1535 fputs (_("\
1536 Show information about the file system on which each FILE resides,\n\
1537 or all file systems by default.\n\
1538 "), stdout);
1540 emit_mandatory_arg_note ();
1542 /* TRANSLATORS: The thousands and decimal separators are best
1543 adjusted to an appropriate default for your locale. */
1544 fputs (_("\
1545 -a, --all include pseudo, duplicate, inaccessible file systems\n\
1546 -B, --block-size=SIZE scale sizes by SIZE before printing them; e.g.,\n\
1547 '-BM' prints sizes in units of 1,048,576 bytes;\n\
1548 see SIZE format below\n\
1549 -h, --human-readable print sizes in powers of 1024 (e.g., 1023M)\n\
1550 -H, --si print sizes in powers of 1000 (e.g., 1.1G)\n\
1551 "), stdout);
1552 fputs (_("\
1553 -i, --inodes list inode information instead of block usage\n\
1554 -k like --block-size=1K\n\
1555 -l, --local limit listing to local file systems\n\
1556 --no-sync do not invoke sync before getting usage info (default)\
1558 "), stdout);
1559 fputs (_("\
1560 --output[=FIELD_LIST] use the output format defined by FIELD_LIST,\n\
1561 or print all fields if FIELD_LIST is omitted.\n\
1562 -P, --portability use the POSIX output format\n\
1563 --sync invoke sync before getting usage info\n\
1564 "), stdout);
1565 fputs (_("\
1566 --total elide all entries insignificant to available space,\n\
1567 and produce a grand total\n\
1568 "), stdout);
1569 fputs (_("\
1570 -t, --type=TYPE limit listing to file systems of type TYPE\n\
1571 -T, --print-type print file system type\n\
1572 -x, --exclude-type=TYPE limit listing to file systems not of type TYPE\n\
1573 -v (ignored)\n\
1574 "), stdout);
1575 fputs (HELP_OPTION_DESCRIPTION, stdout);
1576 fputs (VERSION_OPTION_DESCRIPTION, stdout);
1577 emit_blocksize_note ("DF");
1578 emit_size_note ();
1579 fputs (_("\n\
1580 FIELD_LIST is a comma-separated list of columns to be included. Valid\n\
1581 field names are: 'source', 'fstype', 'itotal', 'iused', 'iavail', 'ipcent',\n\
1582 'size', 'used', 'avail', 'pcent', 'file' and 'target' (see info page).\n\
1583 "), stdout);
1584 emit_ancillary_info (PROGRAM_NAME);
1586 exit (status);
1590 main (int argc, char **argv)
1592 struct stat *stats = NULL;
1594 initialize_main (&argc, &argv);
1595 set_program_name (argv[0]);
1596 setlocale (LC_ALL, "");
1597 bindtextdomain (PACKAGE, LOCALEDIR);
1598 textdomain (PACKAGE);
1600 atexit (close_stdout);
1602 fs_select_list = NULL;
1603 fs_exclude_list = NULL;
1604 show_all_fs = false;
1605 show_listed_fs = false;
1606 human_output_opts = -1;
1607 print_type = false;
1608 file_systems_processed = false;
1609 exit_status = EXIT_SUCCESS;
1610 print_grand_total = false;
1611 grand_fsu.fsu_blocksize = 1;
1613 /* If true, use the POSIX output format. */
1614 bool posix_format = false;
1616 char const *msg_mut_excl = _("options %s and %s are mutually exclusive");
1618 while (true)
1620 int oi = -1;
1621 int c = getopt_long (argc, argv, "aB:iF:hHklmPTt:vx:", long_options,
1622 &oi);
1623 if (c == -1)
1624 break;
1626 switch (c)
1628 case 'a':
1629 show_all_fs = true;
1630 break;
1631 case 'B':
1633 enum strtol_error e = human_options (optarg, &human_output_opts,
1634 &output_block_size);
1635 if (e != LONGINT_OK)
1636 xstrtol_fatal (e, oi, c, long_options, optarg);
1638 break;
1639 case 'i':
1640 if (header_mode == OUTPUT_MODE)
1642 error (0, 0, msg_mut_excl, "-i", "--output");
1643 usage (EXIT_FAILURE);
1645 header_mode = INODES_MODE;
1646 break;
1647 case 'h':
1648 human_output_opts = human_autoscale | human_SI | human_base_1024;
1649 output_block_size = 1;
1650 break;
1651 case 'H':
1652 human_output_opts = human_autoscale | human_SI;
1653 output_block_size = 1;
1654 break;
1655 case 'k':
1656 human_output_opts = 0;
1657 output_block_size = 1024;
1658 break;
1659 case 'l':
1660 show_local_fs = true;
1661 break;
1662 case 'm': /* obsolescent, exists for BSD compatibility */
1663 human_output_opts = 0;
1664 output_block_size = 1024 * 1024;
1665 break;
1666 case 'T':
1667 if (header_mode == OUTPUT_MODE)
1669 error (0, 0, msg_mut_excl, "-T", "--output");
1670 usage (EXIT_FAILURE);
1672 print_type = true;
1673 break;
1674 case 'P':
1675 if (header_mode == OUTPUT_MODE)
1677 error (0, 0, msg_mut_excl, "-P", "--output");
1678 usage (EXIT_FAILURE);
1680 posix_format = true;
1681 break;
1682 case SYNC_OPTION:
1683 require_sync = true;
1684 break;
1685 case NO_SYNC_OPTION:
1686 require_sync = false;
1687 break;
1689 case 'F':
1690 /* Accept -F as a synonym for -t for compatibility with Solaris. */
1691 case 't':
1692 add_fs_type (optarg);
1693 break;
1695 case 'v': /* For SysV compatibility. */
1696 /* ignore */
1697 break;
1698 case 'x':
1699 add_excluded_fs_type (optarg);
1700 break;
1702 case OUTPUT_OPTION:
1703 if (header_mode == INODES_MODE)
1705 error (0, 0, msg_mut_excl, "-i", "--output");
1706 usage (EXIT_FAILURE);
1708 if (posix_format && header_mode == DEFAULT_MODE)
1710 error (0, 0, msg_mut_excl, "-P", "--output");
1711 usage (EXIT_FAILURE);
1713 if (print_type)
1715 error (0, 0, msg_mut_excl, "-T", "--output");
1716 usage (EXIT_FAILURE);
1718 header_mode = OUTPUT_MODE;
1719 if (optarg)
1720 decode_output_arg (optarg);
1721 break;
1723 case TOTAL_OPTION:
1724 print_grand_total = true;
1725 break;
1727 case_GETOPT_HELP_CHAR;
1728 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
1730 default:
1731 usage (EXIT_FAILURE);
1735 if (human_output_opts == -1)
1737 if (posix_format)
1739 human_output_opts = 0;
1740 output_block_size = (getenv ("POSIXLY_CORRECT") ? 512 : 1024);
1742 else
1743 human_options (getenv ("DF_BLOCK_SIZE"),
1744 &human_output_opts, &output_block_size);
1747 if (header_mode == INODES_MODE || header_mode == OUTPUT_MODE)
1749 else if (human_output_opts & human_autoscale)
1750 header_mode = HUMAN_MODE;
1751 else if (posix_format)
1752 header_mode = POSIX_MODE;
1754 /* Fail if the same file system type was both selected and excluded. */
1756 bool match = false;
1757 struct fs_type_list *fs_incl;
1758 for (fs_incl = fs_select_list; fs_incl; fs_incl = fs_incl->fs_next)
1760 struct fs_type_list *fs_excl;
1761 for (fs_excl = fs_exclude_list; fs_excl; fs_excl = fs_excl->fs_next)
1763 if (STREQ (fs_incl->fs_name, fs_excl->fs_name))
1765 error (0, 0,
1766 _("file system type %s both selected and excluded"),
1767 quote (fs_incl->fs_name));
1768 match = true;
1769 break;
1773 if (match)
1774 return EXIT_FAILURE;
1777 assume (0 < optind);
1779 if (optind < argc)
1781 /* stat each of the given entries to make sure any corresponding
1782 partition is automounted. This must be done before reading the
1783 file system table. */
1784 stats = xnmalloc (argc - optind, sizeof *stats);
1785 for (int i = optind; i < argc; ++i)
1787 int err = automount_stat_err (argv[i], &stats[i - optind]);
1788 if (err != 0)
1790 error (0, err, "%s", quotef (argv[i]));
1791 exit_status = EXIT_FAILURE;
1792 argv[i] = NULL;
1797 mount_list =
1798 read_file_system_list ((fs_select_list != NULL
1799 || fs_exclude_list != NULL
1800 || print_type
1801 || field_data[FSTYPE_FIELD].used
1802 || show_local_fs));
1804 if (mount_list == NULL)
1806 /* Couldn't read the table of mounted file systems.
1807 Fail if df was invoked with no file name arguments,
1808 or when either of -a, -l, -t or -x is used with file name
1809 arguments. Otherwise, merely give a warning and proceed. */
1810 int status = 0;
1811 if ( ! (optind < argc)
1812 || (show_all_fs
1813 || show_local_fs
1814 || fs_select_list != NULL
1815 || fs_exclude_list != NULL))
1817 status = EXIT_FAILURE;
1819 char const *warning = (status == 0 ? _("Warning: ") : "");
1820 error (status, errno, "%s%s", warning,
1821 _("cannot read table of mounted file systems"));
1824 if (require_sync)
1825 sync ();
1827 get_field_list ();
1828 get_header ();
1830 if (stats)
1832 /* Display explicitly requested empty file systems. */
1833 show_listed_fs = true;
1835 for (int i = optind; i < argc; ++i)
1836 if (argv[i])
1837 get_entry (argv[i], &stats[i - optind]);
1839 else
1840 get_all_entries ();
1842 if (file_systems_processed)
1844 if (print_grand_total)
1845 get_dev ("total",
1846 (field_data[SOURCE_FIELD].used ? "-" : "total"),
1847 NULL, NULL, NULL, false, false, &grand_fsu, false);
1849 print_table ();
1851 else
1853 /* Print the "no FS processed" diagnostic only if there was no preceding
1854 diagnostic, e.g., if all have been excluded. */
1855 if (exit_status == EXIT_SUCCESS)
1856 die (EXIT_FAILURE, 0, _("no file systems processed"));
1859 main_exit (exit_status);