id: support multiple specified users
[coreutils.git] / src / df.c
blob55532219f3e7732ca971699ee24378134f7af050
1 /* df - summarize free disk space
2 Copyright (C) 1991-2018 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 <wchar.h>
27 #include <wctype.h>
29 #include "system.h"
30 #include "canonicalize.h"
31 #include "die.h"
32 #include "error.h"
33 #include "fsusage.h"
34 #include "human.h"
35 #include "mbsalign.h"
36 #include "mbswidth.h"
37 #include "mountlist.h"
38 #include "quote.h"
39 #include "find-mount-point.h"
40 #include "hash.h"
42 /* The official name of this program (e.g., no 'g' prefix). */
43 #define PROGRAM_NAME "df"
45 #define AUTHORS \
46 proper_name ("Torbjorn Granlund"), \
47 proper_name ("David MacKenzie"), \
48 proper_name ("Paul Eggert")
50 struct devlist
52 dev_t dev_num;
53 struct mount_entry *me;
54 struct devlist *next;
57 /* Filled with device numbers of examined file systems to avoid
58 duplicates in output. */
59 static Hash_table *devlist_table;
61 /* If true, show even file systems with zero size or
62 uninteresting types. */
63 static bool show_all_fs;
65 /* If true, show only local file systems. */
66 static bool show_local_fs;
68 /* If true, output data for each file system corresponding to a
69 command line argument -- even if it's a dummy (automounter) entry. */
70 static bool show_listed_fs;
72 /* Human-readable options for output. */
73 static int human_output_opts;
75 /* The units to use when printing sizes. */
76 static uintmax_t output_block_size;
78 /* True if a file system has been processed for output. */
79 static bool file_systems_processed;
81 /* If true, invoke the 'sync' system call before getting any usage data.
82 Using this option can make df very slow, especially with many or very
83 busy disks. Note that this may make a difference on some systems --
84 SunOS 4.1.3, for one. It is *not* necessary on GNU/Linux. */
85 static bool require_sync;
87 /* Desired exit status. */
88 static int exit_status;
90 /* A file system type to display. */
92 struct fs_type_list
94 char *fs_name;
95 struct fs_type_list *fs_next;
98 /* Linked list of file system types to display.
99 If 'fs_select_list' is NULL, list all types.
100 This table is generated dynamically from command-line options,
101 rather than hardcoding into the program what it thinks are the
102 valid file system types; let the user specify any file system type
103 they want to, and if there are any file systems of that type, they
104 will be shown.
106 Some file system types:
107 4.2 4.3 ufs nfs swap ignore io vm efs dbg */
109 static struct fs_type_list *fs_select_list;
111 /* Linked list of file system types to omit.
112 If the list is empty, don't exclude any types. */
114 static struct fs_type_list *fs_exclude_list;
116 /* Linked list of mounted file systems. */
117 static struct mount_entry *mount_list;
119 /* If true, print file system type as well. */
120 static bool print_type;
122 /* If true, print a grand total at the end. */
123 static bool print_grand_total;
125 /* Grand total data. */
126 static struct fs_usage grand_fsu;
128 /* Display modes. */
129 enum
131 DEFAULT_MODE,
132 INODES_MODE,
133 HUMAN_MODE,
134 POSIX_MODE,
135 OUTPUT_MODE
137 static int header_mode = DEFAULT_MODE;
139 /* Displayable fields. */
140 typedef enum
142 SOURCE_FIELD, /* file system */
143 FSTYPE_FIELD, /* FS type */
144 SIZE_FIELD, /* FS size */
145 USED_FIELD, /* FS size used */
146 AVAIL_FIELD, /* FS size available */
147 PCENT_FIELD, /* percent used */
148 ITOTAL_FIELD, /* inode total */
149 IUSED_FIELD, /* inodes used */
150 IAVAIL_FIELD, /* inodes available */
151 IPCENT_FIELD, /* inodes used in percent */
152 TARGET_FIELD, /* mount point */
153 FILE_FIELD, /* specified file name */
154 INVALID_FIELD /* validation marker */
155 } display_field_t;
157 /* Flag if a field contains a block, an inode or another value. */
158 typedef enum
160 BLOCK_FLD, /* Block values field */
161 INODE_FLD, /* Inode values field */
162 OTHER_FLD /* Neutral field, e.g. target */
163 } field_type_t;
165 /* Attributes of a display field. */
166 struct field_data_t
168 display_field_t field;
169 char const *arg;
170 field_type_t field_type;
171 const char *caption;/* NULL means to use the default header of this field. */
172 size_t width; /* Auto adjusted (up) widths used to align columns. */
173 mbs_align_t align; /* Alignment for this field. */
174 bool used;
177 /* Header strings, minimum width and alignment for the above fields. */
178 static struct field_data_t field_data[] = {
179 [SOURCE_FIELD] = { SOURCE_FIELD,
180 "source", OTHER_FLD, N_("Filesystem"), 14, MBS_ALIGN_LEFT, false },
182 [FSTYPE_FIELD] = { FSTYPE_FIELD,
183 "fstype", OTHER_FLD, N_("Type"), 4, MBS_ALIGN_LEFT, false },
185 [SIZE_FIELD] = { SIZE_FIELD,
186 "size", BLOCK_FLD, N_("blocks"), 5, MBS_ALIGN_RIGHT, false },
188 [USED_FIELD] = { USED_FIELD,
189 "used", BLOCK_FLD, N_("Used"), 5, MBS_ALIGN_RIGHT, false },
191 [AVAIL_FIELD] = { AVAIL_FIELD,
192 "avail", BLOCK_FLD, N_("Available"), 5, MBS_ALIGN_RIGHT, false },
194 [PCENT_FIELD] = { PCENT_FIELD,
195 "pcent", BLOCK_FLD, N_("Use%"), 4, MBS_ALIGN_RIGHT, false },
197 [ITOTAL_FIELD] = { ITOTAL_FIELD,
198 "itotal", INODE_FLD, N_("Inodes"), 5, MBS_ALIGN_RIGHT, false },
200 [IUSED_FIELD] = { IUSED_FIELD,
201 "iused", INODE_FLD, N_("IUsed"), 5, MBS_ALIGN_RIGHT, false },
203 [IAVAIL_FIELD] = { IAVAIL_FIELD,
204 "iavail", INODE_FLD, N_("IFree"), 5, MBS_ALIGN_RIGHT, false },
206 [IPCENT_FIELD] = { IPCENT_FIELD,
207 "ipcent", INODE_FLD, N_("IUse%"), 4, MBS_ALIGN_RIGHT, false },
209 [TARGET_FIELD] = { TARGET_FIELD,
210 "target", OTHER_FLD, N_("Mounted on"), 0, MBS_ALIGN_LEFT, false },
212 [FILE_FIELD] = { FILE_FIELD,
213 "file", OTHER_FLD, N_("File"), 0, MBS_ALIGN_LEFT, false }
216 static char const *all_args_string =
217 "source,fstype,itotal,iused,iavail,ipcent,size,"
218 "used,avail,pcent,file,target";
220 /* Storage for the definition of output columns. */
221 static struct field_data_t **columns;
223 /* The current number of output columns. */
224 static size_t ncolumns;
226 /* Field values. */
227 struct field_values_t
229 uintmax_t input_units;
230 uintmax_t output_units;
231 uintmax_t total;
232 uintmax_t available;
233 bool negate_available;
234 uintmax_t available_to_root;
235 uintmax_t used;
236 bool negate_used;
239 /* Storage for pointers for each string (cell of table). */
240 static char ***table;
242 /* The current number of processed rows (including header). */
243 static size_t nrows;
245 /* For long options that have no equivalent short option, use a
246 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
247 enum
249 NO_SYNC_OPTION = CHAR_MAX + 1,
250 SYNC_OPTION,
251 TOTAL_OPTION,
252 OUTPUT_OPTION
255 static struct option const long_options[] =
257 {"all", no_argument, NULL, 'a'},
258 {"block-size", required_argument, NULL, 'B'},
259 {"inodes", no_argument, NULL, 'i'},
260 {"human-readable", no_argument, NULL, 'h'},
261 {"si", no_argument, NULL, 'H'},
262 {"local", no_argument, NULL, 'l'},
263 {"output", optional_argument, NULL, OUTPUT_OPTION},
264 {"portability", no_argument, NULL, 'P'},
265 {"print-type", no_argument, NULL, 'T'},
266 {"sync", no_argument, NULL, SYNC_OPTION},
267 {"no-sync", no_argument, NULL, NO_SYNC_OPTION},
268 {"total", no_argument, NULL, TOTAL_OPTION},
269 {"type", required_argument, NULL, 't'},
270 {"exclude-type", required_argument, NULL, 'x'},
271 {GETOPT_HELP_OPTION_DECL},
272 {GETOPT_VERSION_OPTION_DECL},
273 {NULL, 0, NULL, 0}
276 /* Replace problematic chars with '?'. */
278 static void
279 hide_problematic_chars (char *cell)
281 char *srcend = cell + strlen (cell);
282 char *dst = cell;
283 mbstate_t mbstate = { 0, };
284 size_t n;
286 for (char *src = cell; src != srcend; src += n)
288 wchar_t wc;
289 size_t srcbytes = srcend - src;
290 n = mbrtowc (&wc, src, srcbytes, &mbstate);
291 bool ok = n <= srcbytes;
293 if (ok)
294 ok = !iswcntrl (wc);
295 else
296 n = 1;
298 if (ok)
300 memmove (dst, src, n);
301 dst += n;
303 else
305 *dst++ = '?';
306 memset (&mbstate, 0, sizeof mbstate);
310 *dst = '\0';
313 /* Dynamically allocate a row of pointers in TABLE, which
314 can then be accessed with standard 2D array notation. */
316 static void
317 alloc_table_row (void)
319 nrows++;
320 table = xnrealloc (table, nrows, sizeof (char **));
321 table[nrows - 1] = xnmalloc (ncolumns, sizeof (char *));
324 /* Output each cell in the table, accounting for the
325 alignment and max width of each column. */
327 static void
328 print_table (void)
330 size_t row;
332 for (row = 0; row < nrows; row++)
334 size_t col;
335 for (col = 0; col < ncolumns; col++)
337 char *cell = table[row][col];
339 /* Note the SOURCE_FIELD used to be displayed on it's own line
340 if (!posix_format && mbswidth (cell) > 20), but that
341 functionality was probably more problematic than helpful,
342 hence changed in commit v8.10-40-g99679ff. */
343 if (col != 0)
344 putchar (' ');
346 int flags = 0;
347 if (col == ncolumns - 1) /* The last one. */
348 flags = MBA_NO_RIGHT_PAD;
350 size_t width = columns[col]->width;
351 cell = ambsalign (cell, &width, columns[col]->align, flags);
352 /* When ambsalign fails, output unaligned data. */
353 fputs (cell ? cell : table[row][col], stdout);
354 free (cell);
356 IF_LINT (free (table[row][col]));
358 putchar ('\n');
359 IF_LINT (free (table[row]));
362 IF_LINT (free (table));
365 /* Dynamically allocate a struct field_t in COLUMNS, which
366 can then be accessed with standard array notation. */
368 static void
369 alloc_field (int f, const char *c)
371 ncolumns++;
372 columns = xnrealloc (columns, ncolumns, sizeof (struct field_data_t *));
373 columns[ncolumns - 1] = &field_data[f];
374 if (c != NULL)
375 columns[ncolumns - 1]->caption = c;
377 if (field_data[f].used)
378 assert (!"field used");
380 /* Mark field as used. */
381 field_data[f].used = true;
385 /* Given a string, ARG, containing a comma-separated list of arguments
386 to the --output option, add the appropriate fields to columns. */
387 static void
388 decode_output_arg (char const *arg)
390 char *arg_writable = xstrdup (arg);
391 char *s = arg_writable;
394 /* find next comma */
395 char *comma = strchr (s, ',');
397 /* If we found a comma, put a NUL in its place and advance. */
398 if (comma)
399 *comma++ = 0;
401 /* process S. */
402 display_field_t field = INVALID_FIELD;
403 for (unsigned int i = 0; i < ARRAY_CARDINALITY (field_data); i++)
405 if (STREQ (field_data[i].arg, s))
407 field = i;
408 break;
411 if (field == INVALID_FIELD)
413 error (0, 0, _("option --output: field %s unknown"), quote (s));
414 usage (EXIT_FAILURE);
417 if (field_data[field].used)
419 /* Prevent the fields from being used more than once. */
420 error (0, 0, _("option --output: field %s used more than once"),
421 quote (field_data[field].arg));
422 usage (EXIT_FAILURE);
425 switch (field)
427 case SOURCE_FIELD:
428 case FSTYPE_FIELD:
429 case USED_FIELD:
430 case PCENT_FIELD:
431 case ITOTAL_FIELD:
432 case IUSED_FIELD:
433 case IAVAIL_FIELD:
434 case IPCENT_FIELD:
435 case TARGET_FIELD:
436 case FILE_FIELD:
437 alloc_field (field, NULL);
438 break;
440 case SIZE_FIELD:
441 alloc_field (field, N_("Size"));
442 break;
444 case AVAIL_FIELD:
445 alloc_field (field, N_("Avail"));
446 break;
448 default:
449 assert (!"invalid field");
451 s = comma;
453 while (s);
455 free (arg_writable);
458 /* Get the appropriate columns for the mode. */
459 static void
460 get_field_list (void)
462 switch (header_mode)
464 case DEFAULT_MODE:
465 alloc_field (SOURCE_FIELD, NULL);
466 if (print_type)
467 alloc_field (FSTYPE_FIELD, NULL);
468 alloc_field (SIZE_FIELD, NULL);
469 alloc_field (USED_FIELD, NULL);
470 alloc_field (AVAIL_FIELD, NULL);
471 alloc_field (PCENT_FIELD, NULL);
472 alloc_field (TARGET_FIELD, NULL);
473 break;
475 case HUMAN_MODE:
476 alloc_field (SOURCE_FIELD, NULL);
477 if (print_type)
478 alloc_field (FSTYPE_FIELD, NULL);
480 alloc_field (SIZE_FIELD, N_("Size"));
481 alloc_field (USED_FIELD, NULL);
482 alloc_field (AVAIL_FIELD, N_("Avail"));
483 alloc_field (PCENT_FIELD, NULL);
484 alloc_field (TARGET_FIELD, NULL);
485 break;
487 case INODES_MODE:
488 alloc_field (SOURCE_FIELD, NULL);
489 if (print_type)
490 alloc_field (FSTYPE_FIELD, NULL);
491 alloc_field (ITOTAL_FIELD, NULL);
492 alloc_field (IUSED_FIELD, NULL);
493 alloc_field (IAVAIL_FIELD, NULL);
494 alloc_field (IPCENT_FIELD, NULL);
495 alloc_field (TARGET_FIELD, NULL);
496 break;
498 case POSIX_MODE:
499 alloc_field (SOURCE_FIELD, NULL);
500 if (print_type)
501 alloc_field (FSTYPE_FIELD, NULL);
502 alloc_field (SIZE_FIELD, NULL);
503 alloc_field (USED_FIELD, NULL);
504 alloc_field (AVAIL_FIELD, NULL);
505 alloc_field (PCENT_FIELD, N_("Capacity"));
506 alloc_field (TARGET_FIELD, NULL);
507 break;
509 case OUTPUT_MODE:
510 if (!ncolumns)
512 /* Add all fields if --output was given without a field list. */
513 decode_output_arg (all_args_string);
515 break;
517 default:
518 assert (!"invalid header_mode");
522 /* Obtain the appropriate header entries. */
524 static void
525 get_header (void)
527 size_t col;
529 alloc_table_row ();
531 for (col = 0; col < ncolumns; col++)
533 char *cell = NULL;
534 char const *header = _(columns[col]->caption);
536 if (columns[col]->field == SIZE_FIELD
537 && (header_mode == DEFAULT_MODE
538 || (header_mode == OUTPUT_MODE
539 && !(human_output_opts & human_autoscale))))
541 char buf[LONGEST_HUMAN_READABLE + 1];
543 int opts = (human_suppress_point_zero
544 | human_autoscale | human_SI
545 | (human_output_opts
546 & (human_group_digits | human_base_1024 | human_B)));
548 /* Prefer the base that makes the human-readable value more exact,
549 if there is a difference. */
551 uintmax_t q1000 = output_block_size;
552 uintmax_t q1024 = output_block_size;
553 bool divisible_by_1000;
554 bool divisible_by_1024;
558 divisible_by_1000 = q1000 % 1000 == 0; q1000 /= 1000;
559 divisible_by_1024 = q1024 % 1024 == 0; q1024 /= 1024;
561 while (divisible_by_1000 & divisible_by_1024);
563 if (divisible_by_1000 < divisible_by_1024)
564 opts |= human_base_1024;
565 if (divisible_by_1024 < divisible_by_1000)
566 opts &= ~human_base_1024;
567 if (! (opts & human_base_1024))
568 opts |= human_B;
570 char *num = human_readable (output_block_size, buf, opts, 1, 1);
572 /* Reset the header back to the default in OUTPUT_MODE. */
573 header = _("blocks");
575 /* TRANSLATORS: this is the "1K-blocks" header in "df" output. */
576 if (asprintf (&cell, _("%s-%s"), num, header) == -1)
577 cell = NULL;
579 else if (header_mode == POSIX_MODE && columns[col]->field == SIZE_FIELD)
581 char buf[INT_BUFSIZE_BOUND (uintmax_t)];
582 char *num = umaxtostr (output_block_size, buf);
584 /* TRANSLATORS: this is the "1024-blocks" header in "df -P". */
585 if (asprintf (&cell, _("%s-%s"), num, header) == -1)
586 cell = NULL;
588 else
589 cell = strdup (header);
591 if (!cell)
592 xalloc_die ();
594 hide_problematic_chars (cell);
596 table[nrows - 1][col] = cell;
598 size_t cell_width = mbswidth (cell, 0);
599 columns[col]->width = MAX (columns[col]->width, cell_width);
603 /* Is FSTYPE a type of file system that should be listed? */
605 static bool _GL_ATTRIBUTE_PURE
606 selected_fstype (const char *fstype)
608 const struct fs_type_list *fsp;
610 if (fs_select_list == NULL || fstype == NULL)
611 return true;
612 for (fsp = fs_select_list; fsp; fsp = fsp->fs_next)
613 if (STREQ (fstype, fsp->fs_name))
614 return true;
615 return false;
618 /* Is FSTYPE a type of file system that should be omitted? */
620 static bool _GL_ATTRIBUTE_PURE
621 excluded_fstype (const char *fstype)
623 const struct fs_type_list *fsp;
625 if (fs_exclude_list == NULL || fstype == NULL)
626 return false;
627 for (fsp = fs_exclude_list; fsp; fsp = fsp->fs_next)
628 if (STREQ (fstype, fsp->fs_name))
629 return true;
630 return false;
633 static size_t
634 devlist_hash (void const *x, size_t table_size)
636 struct devlist const *p = x;
637 return (uintmax_t) p->dev_num % table_size;
640 static bool
641 devlist_compare (void const *x, void const *y)
643 struct devlist const *a = x;
644 struct devlist const *b = y;
645 return a->dev_num == b->dev_num;
648 static struct devlist *
649 devlist_for_dev (dev_t dev)
651 if (devlist_table == NULL)
652 return NULL;
653 struct devlist dev_entry;
654 dev_entry.dev_num = dev;
655 return hash_lookup (devlist_table, &dev_entry);
658 static void
659 devlist_free (void *p)
661 free (p);
664 /* Filter mount list by skipping duplicate entries.
665 In the case of duplicates - based on the device number - the mount entry
666 with a '/' in its me_devname (i.e., not pseudo name like tmpfs) wins.
667 If both have a real devname (e.g. bind mounts), then that with the shorter
668 me_mountdir wins. With DEVICES_ONLY == true (set with df -a), only update
669 the global devlist_table, rather than filtering the global mount_list. */
671 static void
672 filter_mount_list (bool devices_only)
674 struct mount_entry *me;
676 /* Temporary list to keep entries ordered. */
677 struct devlist *device_list = NULL;
678 int mount_list_size = 0;
680 for (me = mount_list; me; me = me->me_next)
681 mount_list_size++;
683 devlist_table = hash_initialize (mount_list_size, NULL,
684 devlist_hash,
685 devlist_compare,
686 devlist_free);
687 if (devlist_table == NULL)
688 xalloc_die ();
690 /* Sort all 'wanted' entries into the list device_list. */
691 for (me = mount_list; me;)
693 struct stat buf;
694 struct mount_entry *discard_me = NULL;
696 /* Avoid stating remote file systems as that may hang.
697 On Linux we probably have me_dev populated from /proc/self/mountinfo,
698 however we still stat() in case another device was mounted later. */
699 if ((me->me_remote && show_local_fs)
700 || (me->me_dummy && !show_all_fs && !show_listed_fs)
701 || (!selected_fstype (me->me_type) || excluded_fstype (me->me_type))
702 || -1 == stat (me->me_mountdir, &buf))
704 /* If remote, and showing just local, or FS type is excluded,
705 add ME for filtering later.
706 If stat failed; add ME to be able to complain about it later. */
707 buf.st_dev = me->me_dev;
709 else
711 /* If we've already seen this device... */
712 struct devlist *seen_dev = devlist_for_dev (buf.st_dev);
714 if (seen_dev)
716 bool target_nearer_root = strlen (seen_dev->me->me_mountdir)
717 > strlen (me->me_mountdir);
718 /* With bind mounts, prefer items nearer the root of the source */
719 bool source_below_root = seen_dev->me->me_mntroot != NULL
720 && me->me_mntroot != NULL
721 && (strlen (seen_dev->me->me_mntroot)
722 < strlen (me->me_mntroot));
723 if (! print_grand_total
724 && me->me_remote && seen_dev->me->me_remote
725 && ! STREQ (seen_dev->me->me_devname, me->me_devname))
727 /* Don't discard remote entries with different locations,
728 as these are more likely to be explicitly mounted.
729 However avoid this when producing a total to give
730 a more accurate value in that case. */
732 else if ((strchr (me->me_devname, '/')
733 /* let "real" devices with '/' in the name win. */
734 && ! strchr (seen_dev->me->me_devname, '/'))
735 /* let points towards the root of the device win. */
736 || (target_nearer_root && ! source_below_root)
737 /* let an entry overmounted on a new device win... */
738 || (! STREQ (seen_dev->me->me_devname, me->me_devname)
739 /* ... but only when matching an existing mnt point,
740 to avoid problematic replacement when given
741 inaccurate mount lists, seen with some chroot
742 environments for example. */
743 && STREQ (me->me_mountdir,
744 seen_dev->me->me_mountdir)))
746 /* Discard mount entry for existing device. */
747 discard_me = seen_dev->me;
748 seen_dev->me = me;
750 else
752 /* Discard mount entry currently being processed. */
753 discard_me = me;
759 if (discard_me)
761 me = me->me_next;
762 if (! devices_only)
763 free_mount_entry (discard_me);
765 else
767 /* Add the device number to the device_table. */
768 struct devlist *devlist = xmalloc (sizeof *devlist);
769 devlist->me = me;
770 devlist->dev_num = buf.st_dev;
771 devlist->next = device_list;
772 device_list = devlist;
773 if (hash_insert (devlist_table, devlist) == NULL)
774 xalloc_die ();
776 me = me->me_next;
780 /* Finally rebuild the mount_list from the devlist. */
781 if (! devices_only) {
782 mount_list = NULL;
783 while (device_list)
785 /* Add the mount entry. */
786 me = device_list->me;
787 me->me_next = mount_list;
788 mount_list = me;
789 device_list = device_list->next;
792 hash_free (devlist_table);
793 devlist_table = NULL;
798 /* Search a mount entry list for device id DEV.
799 Return the corresponding mount entry if found or NULL if not. */
801 static struct mount_entry const * _GL_ATTRIBUTE_PURE
802 me_for_dev (dev_t dev)
804 struct devlist *dl = devlist_for_dev (dev);
805 if (dl)
806 return dl->me;
808 return NULL;
811 /* Return true if N is a known integer value. On many file systems,
812 UINTMAX_MAX represents an unknown value; on AIX, UINTMAX_MAX - 1
813 represents unknown. Use a rule that works on AIX file systems, and
814 that almost-always works on other types. */
815 static bool
816 known_value (uintmax_t n)
818 return n < UINTMAX_MAX - 1;
821 /* Like human_readable (N, BUF, human_output_opts, INPUT_UNITS, OUTPUT_UNITS),
822 except:
824 - If NEGATIVE, then N represents a negative number,
825 expressed in two's complement.
826 - Otherwise, return "-" if N is unknown. */
828 static char const *
829 df_readable (bool negative, uintmax_t n, char *buf,
830 uintmax_t input_units, uintmax_t output_units)
832 if (! known_value (n) && !negative)
833 return "-";
834 else
836 char *p = human_readable (negative ? -n : n, buf + negative,
837 human_output_opts, input_units, output_units);
838 if (negative)
839 *--p = '-';
840 return p;
844 /* Logical equivalence */
845 #define LOG_EQ(a, b) (!(a) == !(b))
847 /* Add integral value while using uintmax_t for value part and separate
848 negation flag. It adds value of SRC and SRC_NEG to DEST and DEST_NEG.
849 The result will be in DEST and DEST_NEG. See df_readable to understand
850 how the negation flag is used. */
851 static void
852 add_uint_with_neg_flag (uintmax_t *dest, bool *dest_neg,
853 uintmax_t src, bool src_neg)
855 if (LOG_EQ (*dest_neg, src_neg))
857 *dest += src;
858 return;
861 if (*dest_neg)
862 *dest = -*dest;
864 if (src_neg)
865 src = -src;
867 if (src < *dest)
868 *dest -= src;
869 else
871 *dest = src - *dest;
872 *dest_neg = src_neg;
875 if (*dest_neg)
876 *dest = -*dest;
879 /* Return true if S ends in a string that may be a 36-byte UUID,
880 i.e., of the form HHHHHHHH-HHHH-HHHH-HHHH-HHHHHHHHHHHH, where
881 each H is an upper or lower case hexadecimal digit. */
882 static bool _GL_ATTRIBUTE_PURE
883 has_uuid_suffix (char const *s)
885 size_t len = strlen (s);
886 return (36 < len
887 && strspn (s + len - 36, "-0123456789abcdefABCDEF") == 36);
890 /* Obtain the block values BV and inode values IV
891 from the file system usage FSU. */
892 static void
893 get_field_values (struct field_values_t *bv,
894 struct field_values_t *iv,
895 const struct fs_usage *fsu)
897 /* Inode values. */
898 iv->input_units = iv->output_units = 1;
899 iv->total = fsu->fsu_files;
900 iv->available = iv->available_to_root = fsu->fsu_ffree;
901 iv->negate_available = false;
903 iv->used = UINTMAX_MAX;
904 iv->negate_used = false;
905 if (known_value (iv->total) && known_value (iv->available_to_root))
907 iv->used = iv->total - iv->available_to_root;
908 iv->negate_used = (iv->total < iv->available_to_root);
911 /* Block values. */
912 bv->input_units = fsu->fsu_blocksize;
913 bv->output_units = output_block_size;
914 bv->total = fsu->fsu_blocks;
915 bv->available = fsu->fsu_bavail;
916 bv->available_to_root = fsu->fsu_bfree;
917 bv->negate_available = (fsu->fsu_bavail_top_bit_set
918 && known_value (fsu->fsu_bavail));
920 bv->used = UINTMAX_MAX;
921 bv->negate_used = false;
922 if (known_value (bv->total) && known_value (bv->available_to_root))
924 bv->used = bv->total - bv->available_to_root;
925 bv->negate_used = (bv->total < bv->available_to_root);
929 /* Add block and inode values to grand total. */
930 static void
931 add_to_grand_total (struct field_values_t *bv, struct field_values_t *iv)
933 if (known_value (iv->total))
934 grand_fsu.fsu_files += iv->total;
935 if (known_value (iv->available))
936 grand_fsu.fsu_ffree += iv->available;
938 if (known_value (bv->total))
939 grand_fsu.fsu_blocks += bv->input_units * bv->total;
940 if (known_value (bv->available_to_root))
941 grand_fsu.fsu_bfree += bv->input_units * bv->available_to_root;
942 if (known_value (bv->available))
943 add_uint_with_neg_flag (&grand_fsu.fsu_bavail,
944 &grand_fsu.fsu_bavail_top_bit_set,
945 bv->input_units * bv->available,
946 bv->negate_available);
949 /* Obtain a space listing for the disk device with absolute file name DISK.
950 If MOUNT_POINT is non-NULL, it is the name of the root of the
951 file system on DISK.
952 If STAT_FILE is non-null, it is the name of a file within the file
953 system that the user originally asked for; this provides better
954 diagnostics, and sometimes it provides better results on networked
955 file systems that give different free-space results depending on
956 where in the file system you probe.
957 If FSTYPE is non-NULL, it is the type of the file system on DISK.
958 If MOUNT_POINT is non-NULL, then DISK may be NULL -- certain systems may
959 not be able to produce statistics in this case.
960 ME_DUMMY and ME_REMOTE are the mount entry flags.
961 Caller must set PROCESS_ALL to true when iterating over all entries, as
962 when df is invoked with no non-option argument. See below for details. */
964 static void
965 get_dev (char const *disk, char const *mount_point, char const* file,
966 char const *stat_file, char const *fstype,
967 bool me_dummy, bool me_remote,
968 const struct fs_usage *force_fsu,
969 bool process_all)
971 if (me_remote && show_local_fs)
972 return;
974 if (me_dummy && !show_all_fs && !show_listed_fs)
975 return;
977 if (!selected_fstype (fstype) || excluded_fstype (fstype))
978 return;
980 /* Ignore relative MOUNT_POINTs, which are present for example
981 in /proc/mounts on Linux with network namespaces. */
982 if (!force_fsu && mount_point && ! IS_ABSOLUTE_FILE_NAME (mount_point))
983 return;
985 /* If MOUNT_POINT is NULL, then the file system is not mounted, and this
986 program reports on the file system that the special file is on.
987 It would be better to report on the unmounted file system,
988 but statfs doesn't do that on most systems. */
989 if (!stat_file)
990 stat_file = mount_point ? mount_point : disk;
992 struct fs_usage fsu;
993 if (force_fsu)
994 fsu = *force_fsu;
995 else if (get_fs_usage (stat_file, disk, &fsu))
997 /* If we can't access a system provided entry due
998 to it not being present (now), or due to permissions,
999 just output placeholder values rather than failing. */
1000 if (process_all && (errno == EACCES || errno == ENOENT))
1002 if (! show_all_fs)
1003 return;
1005 fstype = "-";
1006 fsu.fsu_bavail_top_bit_set = false;
1007 fsu.fsu_blocksize = fsu.fsu_blocks = fsu.fsu_bfree =
1008 fsu.fsu_bavail = fsu.fsu_files = fsu.fsu_ffree = UINTMAX_MAX;
1010 else
1012 error (0, errno, "%s", quotef (stat_file));
1013 exit_status = EXIT_FAILURE;
1014 return;
1017 else if (process_all && show_all_fs)
1019 /* Ensure we don't output incorrect stats for over-mounted directories.
1020 Discard stats when the device name doesn't match. Though don't
1021 discard when used and current mount entries are both remote due
1022 to the possibility of aliased host names or exports. */
1023 struct stat sb;
1024 if (stat (stat_file, &sb) == 0)
1026 struct mount_entry const * dev_me = me_for_dev (sb.st_dev);
1027 if (dev_me && ! STREQ (dev_me->me_devname, disk)
1028 && (! dev_me->me_remote || ! me_remote))
1030 fstype = "-";
1031 fsu.fsu_bavail_top_bit_set = false;
1032 fsu.fsu_blocksize = fsu.fsu_blocks = fsu.fsu_bfree =
1033 fsu.fsu_bavail = fsu.fsu_files = fsu.fsu_ffree = UINTMAX_MAX;
1038 if (fsu.fsu_blocks == 0 && !show_all_fs && !show_listed_fs)
1039 return;
1041 if (! force_fsu)
1042 file_systems_processed = true;
1044 alloc_table_row ();
1046 if (! disk)
1047 disk = "-"; /* unknown */
1049 if (! file)
1050 file = "-"; /* unspecified */
1052 char *dev_name = xstrdup (disk);
1053 char *resolved_dev;
1055 /* On some systems, dev_name is a long-named symlink like
1056 /dev/disk/by-uuid/828fc648-9f30-43d8-a0b1-f7196a2edb66 pointing to a
1057 much shorter and more useful name like /dev/sda1. It may also look
1058 like /dev/mapper/luks-828fc648-9f30-43d8-a0b1-f7196a2edb66 and point to
1059 /dev/dm-0. When process_all is true and dev_name is a symlink whose
1060 name ends with a UUID use the resolved name instead. */
1061 if (process_all
1062 && has_uuid_suffix (dev_name)
1063 && (resolved_dev = canonicalize_filename_mode (dev_name, CAN_EXISTING)))
1065 free (dev_name);
1066 dev_name = resolved_dev;
1069 if (! fstype)
1070 fstype = "-"; /* unknown */
1072 struct field_values_t block_values;
1073 struct field_values_t inode_values;
1074 get_field_values (&block_values, &inode_values, &fsu);
1076 /* Add to grand total unless processing grand total line. */
1077 if (print_grand_total && ! force_fsu)
1078 add_to_grand_total (&block_values, &inode_values);
1080 size_t col;
1081 for (col = 0; col < ncolumns; col++)
1083 char buf[LONGEST_HUMAN_READABLE + 2];
1084 char *cell;
1086 struct field_values_t *v;
1087 switch (columns[col]->field_type)
1089 case BLOCK_FLD:
1090 v = &block_values;
1091 break;
1092 case INODE_FLD:
1093 v = &inode_values;
1094 break;
1095 case OTHER_FLD:
1096 v = NULL;
1097 break;
1098 default:
1099 v = NULL; /* Avoid warnings where assert() is not __noreturn__. */
1100 assert (!"bad field_type");
1103 switch (columns[col]->field)
1105 case SOURCE_FIELD:
1106 cell = xstrdup (dev_name);
1107 break;
1109 case FSTYPE_FIELD:
1110 cell = xstrdup (fstype);
1111 break;
1113 case SIZE_FIELD:
1114 case ITOTAL_FIELD:
1115 cell = xstrdup (df_readable (false, v->total, buf,
1116 v->input_units, v->output_units));
1117 break;
1119 case USED_FIELD:
1120 case IUSED_FIELD:
1121 cell = xstrdup (df_readable (v->negate_used, v->used, buf,
1122 v->input_units, v->output_units));
1123 break;
1125 case AVAIL_FIELD:
1126 case IAVAIL_FIELD:
1127 cell = xstrdup (df_readable (v->negate_available, v->available, buf,
1128 v->input_units, v->output_units));
1129 break;
1131 case PCENT_FIELD:
1132 case IPCENT_FIELD:
1134 double pct = -1;
1135 if (! known_value (v->used) || ! known_value (v->available))
1137 else if (!v->negate_used
1138 && v->used <= TYPE_MAXIMUM (uintmax_t) / 100
1139 && v->used + v->available != 0
1140 && (v->used + v->available < v->used)
1141 == v->negate_available)
1143 uintmax_t u100 = v->used * 100;
1144 uintmax_t nonroot_total = v->used + v->available;
1145 pct = u100 / nonroot_total + (u100 % nonroot_total != 0);
1147 else
1149 /* The calculation cannot be done easily with integer
1150 arithmetic. Fall back on floating point. This can suffer
1151 from minor rounding errors, but doing it exactly requires
1152 multiple precision arithmetic, and it's not worth the
1153 aggravation. */
1154 double u = v->negate_used ? - (double) - v->used : v->used;
1155 double a = v->negate_available
1156 ? - (double) - v->available : v->available;
1157 double nonroot_total = u + a;
1158 if (nonroot_total)
1160 long int lipct = pct = u * 100 / nonroot_total;
1161 double ipct = lipct;
1163 /* Like 'pct = ceil (dpct);', but avoid ceil so that
1164 the math library needn't be linked. */
1165 if (ipct - 1 < pct && pct <= ipct + 1)
1166 pct = ipct + (ipct < pct);
1170 if (0 <= pct)
1172 if (asprintf (&cell, "%.0f%%", pct) == -1)
1173 cell = NULL;
1175 else
1176 cell = strdup ("-");
1178 if (!cell)
1179 xalloc_die ();
1181 break;
1184 case FILE_FIELD:
1185 cell = xstrdup (file);
1186 break;
1188 case TARGET_FIELD:
1189 #ifdef HIDE_AUTOMOUNT_PREFIX
1190 /* Don't print the first directory name in MOUNT_POINT if it's an
1191 artifact of an automounter. This is a bit too aggressive to be
1192 the default. */
1193 if (STRNCMP_LIT (mount_point, "/auto/") == 0)
1194 mount_point += 5;
1195 else if (STRNCMP_LIT (mount_point, "/tmp_mnt/") == 0)
1196 mount_point += 8;
1197 #endif
1198 cell = xstrdup (mount_point);
1199 break;
1201 default:
1202 assert (!"unhandled field");
1205 if (!cell)
1206 assert (!"empty cell");
1208 hide_problematic_chars (cell);
1209 size_t cell_width = mbswidth (cell, 0);
1210 columns[col]->width = MAX (columns[col]->width, cell_width);
1211 table[nrows - 1][col] = cell;
1213 free (dev_name);
1216 /* Scan the mount list returning the _last_ device found for MOUNT.
1217 NULL is returned if MOUNT not found. The result is malloced. */
1218 static char *
1219 last_device_for_mount (char const* mount)
1221 struct mount_entry const *me;
1222 struct mount_entry const *le = NULL;
1224 for (me = mount_list; me; me = me->me_next)
1226 if (STREQ (me->me_mountdir, mount))
1227 le = me;
1230 if (le)
1232 char *devname = le->me_devname;
1233 char *canon_dev = canonicalize_file_name (devname);
1234 if (canon_dev && IS_ABSOLUTE_FILE_NAME (canon_dev))
1235 return canon_dev;
1236 free (canon_dev);
1237 return xstrdup (le->me_devname);
1239 else
1240 return NULL;
1243 /* If DISK corresponds to a mount point, show its usage
1244 and return true. Otherwise, return false. */
1245 static bool
1246 get_disk (char const *disk)
1248 struct mount_entry const *me;
1249 struct mount_entry const *best_match = NULL;
1250 bool best_match_accessible = false;
1251 bool eclipsed_device = false;
1252 char const *file = disk;
1254 char *resolved = canonicalize_file_name (disk);
1255 if (resolved && IS_ABSOLUTE_FILE_NAME (resolved))
1256 disk = resolved;
1258 size_t best_match_len = SIZE_MAX;
1259 for (me = mount_list; me; me = me->me_next)
1261 /* TODO: Should cache canon_dev in the mount_entry struct. */
1262 char *devname = me->me_devname;
1263 char *canon_dev = canonicalize_file_name (me->me_devname);
1264 if (canon_dev && IS_ABSOLUTE_FILE_NAME (canon_dev))
1265 devname = canon_dev;
1267 if (STREQ (disk, devname))
1269 char *last_device = last_device_for_mount (me->me_mountdir);
1270 eclipsed_device = last_device && ! STREQ (last_device, devname);
1271 size_t len = strlen (me->me_mountdir);
1273 if (! eclipsed_device
1274 && (! best_match_accessible || len < best_match_len))
1276 struct stat disk_stats;
1277 bool this_match_accessible = false;
1279 if (stat (me->me_mountdir, &disk_stats) == 0)
1280 best_match_accessible = this_match_accessible = true;
1282 if (this_match_accessible
1283 || (! best_match_accessible && len < best_match_len))
1285 best_match = me;
1286 if (len == 1) /* Traditional root. */
1288 free (last_device);
1289 free (canon_dev);
1290 break;
1292 else
1293 best_match_len = len;
1297 free (last_device);
1300 free (canon_dev);
1303 free (resolved);
1305 if (best_match)
1307 get_dev (best_match->me_devname, best_match->me_mountdir, file, NULL,
1308 best_match->me_type, best_match->me_dummy,
1309 best_match->me_remote, NULL, false);
1310 return true;
1312 else if (eclipsed_device)
1314 error (0, 0, _("cannot access %s: over-mounted by another device"),
1315 quoteaf (file));
1316 exit_status = EXIT_FAILURE;
1317 return true;
1320 return false;
1323 /* Figure out which device file or directory POINT is mounted on
1324 and show its disk usage.
1325 STATP must be the result of 'stat (POINT, STATP)'. */
1326 static void
1327 get_point (const char *point, const struct stat *statp)
1329 struct stat disk_stats;
1330 struct mount_entry *me;
1331 struct mount_entry const *best_match = NULL;
1333 /* Calculate the real absolute file name for POINT, and use that to find
1334 the mount point. This avoids statting unavailable mount points,
1335 which can hang df. */
1336 char *resolved = canonicalize_file_name (point);
1337 if (resolved && resolved[0] == '/')
1339 size_t resolved_len = strlen (resolved);
1340 size_t best_match_len = 0;
1342 for (me = mount_list; me; me = me->me_next)
1344 if (!STREQ (me->me_type, "lofs")
1345 && (!best_match || best_match->me_dummy || !me->me_dummy))
1347 size_t len = strlen (me->me_mountdir);
1348 if (best_match_len <= len && len <= resolved_len
1349 && (len == 1 /* root file system */
1350 || ((len == resolved_len || resolved[len] == '/')
1351 && STREQ_LEN (me->me_mountdir, resolved, len))))
1353 best_match = me;
1354 best_match_len = len;
1359 free (resolved);
1360 if (best_match
1361 && (stat (best_match->me_mountdir, &disk_stats) != 0
1362 || disk_stats.st_dev != statp->st_dev))
1363 best_match = NULL;
1365 if (! best_match)
1366 for (me = mount_list; me; me = me->me_next)
1368 if (me->me_dev == (dev_t) -1)
1370 if (stat (me->me_mountdir, &disk_stats) == 0)
1371 me->me_dev = disk_stats.st_dev;
1372 else
1374 /* Report only I/O errors. Other errors might be
1375 caused by shadowed mount points, which means POINT
1376 can't possibly be on this file system. */
1377 if (errno == EIO)
1379 error (0, errno, "%s", quotef (me->me_mountdir));
1380 exit_status = EXIT_FAILURE;
1383 /* So we won't try and fail repeatedly. */
1384 me->me_dev = (dev_t) -2;
1388 if (statp->st_dev == me->me_dev
1389 && !STREQ (me->me_type, "lofs")
1390 && (!best_match || best_match->me_dummy || !me->me_dummy))
1392 /* Skip bogus mtab entries. */
1393 if (stat (me->me_mountdir, &disk_stats) != 0
1394 || disk_stats.st_dev != me->me_dev)
1395 me->me_dev = (dev_t) -2;
1396 else
1397 best_match = me;
1401 if (best_match)
1402 get_dev (best_match->me_devname, best_match->me_mountdir, point, point,
1403 best_match->me_type, best_match->me_dummy, best_match->me_remote,
1404 NULL, false);
1405 else
1407 /* We couldn't find the mount entry corresponding to POINT. Go ahead and
1408 print as much info as we can; methods that require the device to be
1409 present will fail at a later point. */
1411 /* Find the actual mount point. */
1412 char *mp = find_mount_point (point, statp);
1413 if (mp)
1415 get_dev (NULL, mp, point, NULL, NULL, false, false, NULL, false);
1416 free (mp);
1421 /* Determine what kind of node NAME is and show the disk usage
1422 for it. STATP is the results of 'stat' on NAME. */
1424 static void
1425 get_entry (char const *name, struct stat const *statp)
1427 if ((S_ISBLK (statp->st_mode) || S_ISCHR (statp->st_mode))
1428 && get_disk (name))
1429 return;
1431 get_point (name, statp);
1434 /* Show all mounted file systems, except perhaps those that are of
1435 an unselected type or are empty. */
1437 static void
1438 get_all_entries (void)
1440 struct mount_entry *me;
1442 filter_mount_list (show_all_fs);
1444 for (me = mount_list; me; me = me->me_next)
1445 get_dev (me->me_devname, me->me_mountdir, NULL, NULL, me->me_type,
1446 me->me_dummy, me->me_remote, NULL, true);
1449 /* Add FSTYPE to the list of file system types to display. */
1451 static void
1452 add_fs_type (const char *fstype)
1454 struct fs_type_list *fsp;
1456 fsp = xmalloc (sizeof *fsp);
1457 fsp->fs_name = (char *) fstype;
1458 fsp->fs_next = fs_select_list;
1459 fs_select_list = fsp;
1462 /* Add FSTYPE to the list of file system types to be omitted. */
1464 static void
1465 add_excluded_fs_type (const char *fstype)
1467 struct fs_type_list *fsp;
1469 fsp = xmalloc (sizeof *fsp);
1470 fsp->fs_name = (char *) fstype;
1471 fsp->fs_next = fs_exclude_list;
1472 fs_exclude_list = fsp;
1475 void
1476 usage (int status)
1478 if (status != EXIT_SUCCESS)
1479 emit_try_help ();
1480 else
1482 printf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name);
1483 fputs (_("\
1484 Show information about the file system on which each FILE resides,\n\
1485 or all file systems by default.\n\
1486 "), stdout);
1488 emit_mandatory_arg_note ();
1490 /* TRANSLATORS: The thousands and decimal separators are best
1491 adjusted to an appropriate default for your locale. */
1492 fputs (_("\
1493 -a, --all include pseudo, duplicate, inaccessible file systems\n\
1494 -B, --block-size=SIZE scale sizes by SIZE before printing them; e.g.,\n\
1495 '-BM' prints sizes in units of 1,048,576 bytes;\n\
1496 see SIZE format below\n\
1497 -h, --human-readable print sizes in powers of 1024 (e.g., 1023M)\n\
1498 -H, --si print sizes in powers of 1000 (e.g., 1.1G)\n\
1499 "), stdout);
1500 fputs (_("\
1501 -i, --inodes list inode information instead of block usage\n\
1502 -k like --block-size=1K\n\
1503 -l, --local limit listing to local file systems\n\
1504 --no-sync do not invoke sync before getting usage info (default)\
1506 "), stdout);
1507 fputs (_("\
1508 --output[=FIELD_LIST] use the output format defined by FIELD_LIST,\n\
1509 or print all fields if FIELD_LIST is omitted.\n\
1510 -P, --portability use the POSIX output format\n\
1511 --sync invoke sync before getting usage info\n\
1512 "), stdout);
1513 fputs (_("\
1514 --total elide all entries insignificant to available space,\n\
1515 and produce a grand total\n\
1516 "), stdout);
1517 fputs (_("\
1518 -t, --type=TYPE limit listing to file systems of type TYPE\n\
1519 -T, --print-type print file system type\n\
1520 -x, --exclude-type=TYPE limit listing to file systems not of type TYPE\n\
1521 -v (ignored)\n\
1522 "), stdout);
1523 fputs (HELP_OPTION_DESCRIPTION, stdout);
1524 fputs (VERSION_OPTION_DESCRIPTION, stdout);
1525 emit_blocksize_note ("DF");
1526 emit_size_note ();
1527 fputs (_("\n\
1528 FIELD_LIST is a comma-separated list of columns to be included. Valid\n\
1529 field names are: 'source', 'fstype', 'itotal', 'iused', 'iavail', 'ipcent',\n\
1530 'size', 'used', 'avail', 'pcent', 'file' and 'target' (see info page).\n\
1531 "), stdout);
1532 emit_ancillary_info (PROGRAM_NAME);
1534 exit (status);
1538 main (int argc, char **argv)
1540 struct stat *stats IF_LINT ( = 0);
1542 initialize_main (&argc, &argv);
1543 set_program_name (argv[0]);
1544 setlocale (LC_ALL, "");
1545 bindtextdomain (PACKAGE, LOCALEDIR);
1546 textdomain (PACKAGE);
1548 atexit (close_stdout);
1550 fs_select_list = NULL;
1551 fs_exclude_list = NULL;
1552 show_all_fs = false;
1553 show_listed_fs = false;
1554 human_output_opts = -1;
1555 print_type = false;
1556 file_systems_processed = false;
1557 exit_status = EXIT_SUCCESS;
1558 print_grand_total = false;
1559 grand_fsu.fsu_blocksize = 1;
1561 /* If true, use the POSIX output format. */
1562 bool posix_format = false;
1564 const char *msg_mut_excl = _("options %s and %s are mutually exclusive");
1566 while (true)
1568 int oi = -1;
1569 int c = getopt_long (argc, argv, "aB:iF:hHklmPTt:vx:", long_options,
1570 &oi);
1571 if (c == -1)
1572 break;
1574 switch (c)
1576 case 'a':
1577 show_all_fs = true;
1578 break;
1579 case 'B':
1581 enum strtol_error e = human_options (optarg, &human_output_opts,
1582 &output_block_size);
1583 if (e != LONGINT_OK)
1584 xstrtol_fatal (e, oi, c, long_options, optarg);
1586 break;
1587 case 'i':
1588 if (header_mode == OUTPUT_MODE)
1590 error (0, 0, msg_mut_excl, "-i", "--output");
1591 usage (EXIT_FAILURE);
1593 header_mode = INODES_MODE;
1594 break;
1595 case 'h':
1596 human_output_opts = human_autoscale | human_SI | human_base_1024;
1597 output_block_size = 1;
1598 break;
1599 case 'H':
1600 human_output_opts = human_autoscale | human_SI;
1601 output_block_size = 1;
1602 break;
1603 case 'k':
1604 human_output_opts = 0;
1605 output_block_size = 1024;
1606 break;
1607 case 'l':
1608 show_local_fs = true;
1609 break;
1610 case 'm': /* obsolescent, exists for BSD compatibility */
1611 human_output_opts = 0;
1612 output_block_size = 1024 * 1024;
1613 break;
1614 case 'T':
1615 if (header_mode == OUTPUT_MODE)
1617 error (0, 0, msg_mut_excl, "-T", "--output");
1618 usage (EXIT_FAILURE);
1620 print_type = true;
1621 break;
1622 case 'P':
1623 if (header_mode == OUTPUT_MODE)
1625 error (0, 0, msg_mut_excl, "-P", "--output");
1626 usage (EXIT_FAILURE);
1628 posix_format = true;
1629 break;
1630 case SYNC_OPTION:
1631 require_sync = true;
1632 break;
1633 case NO_SYNC_OPTION:
1634 require_sync = false;
1635 break;
1637 case 'F':
1638 /* Accept -F as a synonym for -t for compatibility with Solaris. */
1639 case 't':
1640 add_fs_type (optarg);
1641 break;
1643 case 'v': /* For SysV compatibility. */
1644 /* ignore */
1645 break;
1646 case 'x':
1647 add_excluded_fs_type (optarg);
1648 break;
1650 case OUTPUT_OPTION:
1651 if (header_mode == INODES_MODE)
1653 error (0, 0, msg_mut_excl, "-i", "--output");
1654 usage (EXIT_FAILURE);
1656 if (posix_format && header_mode == DEFAULT_MODE)
1658 error (0, 0, msg_mut_excl, "-P", "--output");
1659 usage (EXIT_FAILURE);
1661 if (print_type)
1663 error (0, 0, msg_mut_excl, "-T", "--output");
1664 usage (EXIT_FAILURE);
1666 header_mode = OUTPUT_MODE;
1667 if (optarg)
1668 decode_output_arg (optarg);
1669 break;
1671 case TOTAL_OPTION:
1672 print_grand_total = true;
1673 break;
1675 case_GETOPT_HELP_CHAR;
1676 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
1678 default:
1679 usage (EXIT_FAILURE);
1683 if (human_output_opts == -1)
1685 if (posix_format)
1687 human_output_opts = 0;
1688 output_block_size = (getenv ("POSIXLY_CORRECT") ? 512 : 1024);
1690 else
1691 human_options (getenv ("DF_BLOCK_SIZE"),
1692 &human_output_opts, &output_block_size);
1695 if (header_mode == INODES_MODE || header_mode == OUTPUT_MODE)
1697 else if (human_output_opts & human_autoscale)
1698 header_mode = HUMAN_MODE;
1699 else if (posix_format)
1700 header_mode = POSIX_MODE;
1702 /* Fail if the same file system type was both selected and excluded. */
1704 bool match = false;
1705 struct fs_type_list *fs_incl;
1706 for (fs_incl = fs_select_list; fs_incl; fs_incl = fs_incl->fs_next)
1708 struct fs_type_list *fs_excl;
1709 for (fs_excl = fs_exclude_list; fs_excl; fs_excl = fs_excl->fs_next)
1711 if (STREQ (fs_incl->fs_name, fs_excl->fs_name))
1713 error (0, 0,
1714 _("file system type %s both selected and excluded"),
1715 quote (fs_incl->fs_name));
1716 match = true;
1717 break;
1721 if (match)
1722 return EXIT_FAILURE;
1725 assume (0 < optind);
1727 if (optind < argc)
1729 /* stat each of the given entries to make sure any corresponding
1730 partition is automounted. This must be done before reading the
1731 file system table. */
1732 stats = xnmalloc (argc - optind, sizeof *stats);
1733 for (int i = optind; i < argc; ++i)
1735 if (stat (argv[i], &stats[i - optind]))
1737 error (0, errno, "%s", quotef (argv[i]));
1738 exit_status = EXIT_FAILURE;
1739 argv[i] = NULL;
1741 else if (! S_ISFIFO (stats[i - optind].st_mode))
1743 /* open() is needed to automount in some cases. */
1744 int fd = open (argv[i], O_RDONLY | O_NOCTTY);
1745 if (0 <= fd)
1746 close (fd);
1751 mount_list =
1752 read_file_system_list ((fs_select_list != NULL
1753 || fs_exclude_list != NULL
1754 || print_type
1755 || field_data[FSTYPE_FIELD].used
1756 || show_local_fs));
1758 if (mount_list == NULL)
1760 /* Couldn't read the table of mounted file systems.
1761 Fail if df was invoked with no file name arguments,
1762 or when either of -a, -l, -t or -x is used with file name
1763 arguments. Otherwise, merely give a warning and proceed. */
1764 int status = 0;
1765 if ( ! (optind < argc)
1766 || (show_all_fs
1767 || show_local_fs
1768 || fs_select_list != NULL
1769 || fs_exclude_list != NULL))
1771 status = EXIT_FAILURE;
1773 const char *warning = (status == 0 ? _("Warning: ") : "");
1774 error (status, errno, "%s%s", warning,
1775 _("cannot read table of mounted file systems"));
1778 if (require_sync)
1779 sync ();
1781 get_field_list ();
1782 get_header ();
1784 if (optind < argc)
1786 /* Display explicitly requested empty file systems. */
1787 show_listed_fs = true;
1789 for (int i = optind; i < argc; ++i)
1790 if (argv[i])
1791 get_entry (argv[i], &stats[i - optind]);
1793 IF_LINT (free (stats));
1795 else
1796 get_all_entries ();
1798 if (file_systems_processed)
1800 if (print_grand_total)
1801 get_dev ("total",
1802 (field_data[SOURCE_FIELD].used ? "-" : "total"),
1803 NULL, NULL, NULL, false, false, &grand_fsu, false);
1805 print_table ();
1807 else
1809 /* Print the "no FS processed" diagnostic only if there was no preceding
1810 diagnostic, e.g., if all have been excluded. */
1811 if (exit_status == EXIT_SUCCESS)
1812 die (EXIT_FAILURE, 0, _("no file systems processed"));
1815 IF_LINT (free (columns));
1817 return exit_status;