1 /* df - summarize free disk space
2 Copyright (C) 1991-2016 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 <http://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. */
23 #include <sys/types.h>
28 #include "canonicalize.h"
35 #include "mountlist.h"
37 #include "find-mount-point.h"
40 /* The official name of this program (e.g., no 'g' prefix). */
41 #define PROGRAM_NAME "df"
44 proper_name ("Torbjorn Granlund"), \
45 proper_name ("David MacKenzie"), \
46 proper_name ("Paul Eggert")
51 struct mount_entry
*me
;
55 /* Filled with device numbers of examined file systems to avoid
56 duplicates in output. */
57 static Hash_table
*devlist_table
;
59 /* If true, show even file systems with zero size or
60 uninteresting types. */
61 static bool show_all_fs
;
63 /* If true, show only local file systems. */
64 static bool show_local_fs
;
66 /* If true, output data for each file system corresponding to a
67 command line argument -- even if it's a dummy (automounter) entry. */
68 static bool show_listed_fs
;
70 /* Human-readable options for output. */
71 static int human_output_opts
;
73 /* The units to use when printing sizes. */
74 static uintmax_t output_block_size
;
76 /* True if a file system has been processed for output. */
77 static bool file_systems_processed
;
79 /* If true, invoke the 'sync' system call before getting any usage data.
80 Using this option can make df very slow, especially with many or very
81 busy disks. Note that this may make a difference on some systems --
82 SunOS 4.1.3, for one. It is *not* necessary on GNU/Linux. */
83 static bool require_sync
;
85 /* Desired exit status. */
86 static int exit_status
;
88 /* A file system type to display. */
93 struct fs_type_list
*fs_next
;
96 /* Linked list of file system types to display.
97 If 'fs_select_list' is NULL, list all types.
98 This table is generated dynamically from command-line options,
99 rather than hardcoding into the program what it thinks are the
100 valid file system types; let the user specify any file system type
101 they want to, and if there are any file systems of that type, they
104 Some file system types:
105 4.2 4.3 ufs nfs swap ignore io vm efs dbg */
107 static struct fs_type_list
*fs_select_list
;
109 /* Linked list of file system types to omit.
110 If the list is empty, don't exclude any types. */
112 static struct fs_type_list
*fs_exclude_list
;
114 /* Linked list of mounted file systems. */
115 static struct mount_entry
*mount_list
;
117 /* If true, print file system type as well. */
118 static bool print_type
;
120 /* If true, print a grand total at the end. */
121 static bool print_grand_total
;
123 /* Grand total data. */
124 static struct fs_usage grand_fsu
;
135 static int header_mode
= DEFAULT_MODE
;
137 /* Displayable fields. */
140 SOURCE_FIELD
, /* file system */
141 FSTYPE_FIELD
, /* FS type */
142 SIZE_FIELD
, /* FS size */
143 USED_FIELD
, /* FS size used */
144 AVAIL_FIELD
, /* FS size available */
145 PCENT_FIELD
, /* percent used */
146 ITOTAL_FIELD
, /* inode total */
147 IUSED_FIELD
, /* inodes used */
148 IAVAIL_FIELD
, /* inodes available */
149 IPCENT_FIELD
, /* inodes used in percent */
150 TARGET_FIELD
, /* mount point */
151 FILE_FIELD
, /* specified file name */
152 INVALID_FIELD
/* validation marker */
155 /* Flag if a field contains a block, an inode or another value. */
158 BLOCK_FLD
, /* Block values field */
159 INODE_FLD
, /* Inode values field */
160 OTHER_FLD
/* Neutral field, e.g. target */
163 /* Attributes of a display field. */
166 display_field_t field
;
168 field_type_t field_type
;
169 const char *caption
;/* NULL means to use the default header of this field. */
170 size_t width
; /* Auto adjusted (up) widths used to align columns. */
171 mbs_align_t align
; /* Alignment for this field. */
175 /* Header strings, minimum width and alignment for the above fields. */
176 static struct field_data_t field_data
[] = {
177 [SOURCE_FIELD
] = { SOURCE_FIELD
,
178 "source", OTHER_FLD
, N_("Filesystem"), 14, MBS_ALIGN_LEFT
, false },
180 [FSTYPE_FIELD
] = { FSTYPE_FIELD
,
181 "fstype", OTHER_FLD
, N_("Type"), 4, MBS_ALIGN_LEFT
, false },
183 [SIZE_FIELD
] = { SIZE_FIELD
,
184 "size", BLOCK_FLD
, N_("blocks"), 5, MBS_ALIGN_RIGHT
, false },
186 [USED_FIELD
] = { USED_FIELD
,
187 "used", BLOCK_FLD
, N_("Used"), 5, MBS_ALIGN_RIGHT
, false },
189 [AVAIL_FIELD
] = { AVAIL_FIELD
,
190 "avail", BLOCK_FLD
, N_("Available"), 5, MBS_ALIGN_RIGHT
, false },
192 [PCENT_FIELD
] = { PCENT_FIELD
,
193 "pcent", BLOCK_FLD
, N_("Use%"), 4, MBS_ALIGN_RIGHT
, false },
195 [ITOTAL_FIELD
] = { ITOTAL_FIELD
,
196 "itotal", INODE_FLD
, N_("Inodes"), 5, MBS_ALIGN_RIGHT
, false },
198 [IUSED_FIELD
] = { IUSED_FIELD
,
199 "iused", INODE_FLD
, N_("IUsed"), 5, MBS_ALIGN_RIGHT
, false },
201 [IAVAIL_FIELD
] = { IAVAIL_FIELD
,
202 "iavail", INODE_FLD
, N_("IFree"), 5, MBS_ALIGN_RIGHT
, false },
204 [IPCENT_FIELD
] = { IPCENT_FIELD
,
205 "ipcent", INODE_FLD
, N_("IUse%"), 4, MBS_ALIGN_RIGHT
, false },
207 [TARGET_FIELD
] = { TARGET_FIELD
,
208 "target", OTHER_FLD
, N_("Mounted on"), 0, MBS_ALIGN_LEFT
, false },
210 [FILE_FIELD
] = { FILE_FIELD
,
211 "file", OTHER_FLD
, N_("File"), 0, MBS_ALIGN_LEFT
, false }
214 static char const *all_args_string
=
215 "source,fstype,itotal,iused,iavail,ipcent,size,"
216 "used,avail,pcent,file,target";
218 /* Storage for the definition of output columns. */
219 static struct field_data_t
**columns
;
221 /* The current number of output columns. */
222 static size_t ncolumns
;
225 struct field_values_t
227 uintmax_t input_units
;
228 uintmax_t output_units
;
231 bool negate_available
;
232 uintmax_t available_to_root
;
237 /* Storage for pointers for each string (cell of table). */
238 static char ***table
;
240 /* The current number of processed rows (including header). */
243 /* For long options that have no equivalent short option, use a
244 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
247 NO_SYNC_OPTION
= CHAR_MAX
+ 1,
253 static struct option
const long_options
[] =
255 {"all", no_argument
, NULL
, 'a'},
256 {"block-size", required_argument
, NULL
, 'B'},
257 {"inodes", no_argument
, NULL
, 'i'},
258 {"human-readable", no_argument
, NULL
, 'h'},
259 {"si", no_argument
, NULL
, 'H'},
260 {"local", no_argument
, NULL
, 'l'},
261 {"output", optional_argument
, NULL
, OUTPUT_OPTION
},
262 {"portability", no_argument
, NULL
, 'P'},
263 {"print-type", no_argument
, NULL
, 'T'},
264 {"sync", no_argument
, NULL
, SYNC_OPTION
},
265 {"no-sync", no_argument
, NULL
, NO_SYNC_OPTION
},
266 {"total", no_argument
, NULL
, TOTAL_OPTION
},
267 {"type", required_argument
, NULL
, 't'},
268 {"exclude-type", required_argument
, NULL
, 'x'},
269 {GETOPT_HELP_OPTION_DECL
},
270 {GETOPT_VERSION_OPTION_DECL
},
274 /* Replace problematic chars with '?'.
275 Since only control characters are currently considered,
276 this should work in all encodings. */
279 hide_problematic_chars (char *cell
)
284 if (iscntrl (to_uchar (*p
)))
291 /* Dynamically allocate a row of pointers in TABLE, which
292 can then be accessed with standard 2D array notation. */
295 alloc_table_row (void)
298 table
= xnrealloc (table
, nrows
, sizeof (char **));
299 table
[nrows
- 1] = xnmalloc (ncolumns
, sizeof (char *));
302 /* Output each cell in the table, accounting for the
303 alignment and max width of each column. */
310 for (row
= 0; row
< nrows
; row
++)
313 for (col
= 0; col
< ncolumns
; col
++)
315 char *cell
= table
[row
][col
];
317 /* Note the SOURCE_FIELD used to be displayed on it's own line
318 if (!posix_format && mbswidth (cell) > 20), but that
319 functionality was probably more problematic than helpful,
320 hence changed in commit v8.10-40-g99679ff. */
325 if (col
== ncolumns
- 1) /* The last one. */
326 flags
= MBA_NO_RIGHT_PAD
;
328 size_t width
= columns
[col
]->width
;
329 cell
= ambsalign (cell
, &width
, columns
[col
]->align
, flags
);
330 /* When ambsalign fails, output unaligned data. */
331 fputs (cell
? cell
: table
[row
][col
], stdout
);
334 IF_LINT (free (table
[row
][col
]));
337 IF_LINT (free (table
[row
]));
340 IF_LINT (free (table
));
343 /* Dynamically allocate a struct field_t in COLUMNS, which
344 can then be accessed with standard array notation. */
347 alloc_field (int f
, const char *c
)
350 columns
= xnrealloc (columns
, ncolumns
, sizeof (struct field_data_t
*));
351 columns
[ncolumns
- 1] = &field_data
[f
];
353 columns
[ncolumns
- 1]->caption
= c
;
355 if (field_data
[f
].used
)
356 assert (!"field used");
358 /* Mark field as used. */
359 field_data
[f
].used
= true;
363 /* Given a string, ARG, containing a comma-separated list of arguments
364 to the --output option, add the appropriate fields to columns. */
366 decode_output_arg (char const *arg
)
368 char *arg_writable
= xstrdup (arg
);
369 char *s
= arg_writable
;
372 /* find next comma */
373 char *comma
= strchr (s
, ',');
375 /* If we found a comma, put a NUL in its place and advance. */
380 display_field_t field
= INVALID_FIELD
;
381 for (unsigned int i
= 0; i
< ARRAY_CARDINALITY (field_data
); i
++)
383 if (STREQ (field_data
[i
].arg
, s
))
389 if (field
== INVALID_FIELD
)
391 error (0, 0, _("option --output: field %s unknown"), quote (s
));
392 usage (EXIT_FAILURE
);
395 if (field_data
[field
].used
)
397 /* Prevent the fields from being used more than once. */
398 error (0, 0, _("option --output: field %s used more than once"),
399 quote (field_data
[field
].arg
));
400 usage (EXIT_FAILURE
);
415 alloc_field (field
, NULL
);
419 alloc_field (field
, N_("Size"));
423 alloc_field (field
, N_("Avail"));
427 assert (!"invalid field");
436 /* Get the appropriate columns for the mode. */
438 get_field_list (void)
443 alloc_field (SOURCE_FIELD
, NULL
);
445 alloc_field (FSTYPE_FIELD
, NULL
);
446 alloc_field (SIZE_FIELD
, NULL
);
447 alloc_field (USED_FIELD
, NULL
);
448 alloc_field (AVAIL_FIELD
, NULL
);
449 alloc_field (PCENT_FIELD
, NULL
);
450 alloc_field (TARGET_FIELD
, NULL
);
454 alloc_field (SOURCE_FIELD
, NULL
);
456 alloc_field (FSTYPE_FIELD
, NULL
);
458 alloc_field (SIZE_FIELD
, N_("Size"));
459 alloc_field (USED_FIELD
, NULL
);
460 alloc_field (AVAIL_FIELD
, N_("Avail"));
461 alloc_field (PCENT_FIELD
, NULL
);
462 alloc_field (TARGET_FIELD
, NULL
);
466 alloc_field (SOURCE_FIELD
, NULL
);
468 alloc_field (FSTYPE_FIELD
, NULL
);
469 alloc_field (ITOTAL_FIELD
, NULL
);
470 alloc_field (IUSED_FIELD
, NULL
);
471 alloc_field (IAVAIL_FIELD
, NULL
);
472 alloc_field (IPCENT_FIELD
, NULL
);
473 alloc_field (TARGET_FIELD
, NULL
);
477 alloc_field (SOURCE_FIELD
, NULL
);
479 alloc_field (FSTYPE_FIELD
, NULL
);
480 alloc_field (SIZE_FIELD
, NULL
);
481 alloc_field (USED_FIELD
, NULL
);
482 alloc_field (AVAIL_FIELD
, NULL
);
483 alloc_field (PCENT_FIELD
, N_("Capacity"));
484 alloc_field (TARGET_FIELD
, NULL
);
490 /* Add all fields if --output was given without a field list. */
491 decode_output_arg (all_args_string
);
496 assert (!"invalid header_mode");
500 /* Obtain the appropriate header entries. */
509 for (col
= 0; col
< ncolumns
; col
++)
512 char const *header
= _(columns
[col
]->caption
);
514 if (columns
[col
]->field
== SIZE_FIELD
515 && (header_mode
== DEFAULT_MODE
516 || (header_mode
== OUTPUT_MODE
517 && !(human_output_opts
& human_autoscale
))))
519 char buf
[LONGEST_HUMAN_READABLE
+ 1];
521 int opts
= (human_suppress_point_zero
522 | human_autoscale
| human_SI
524 & (human_group_digits
| human_base_1024
| human_B
)));
526 /* Prefer the base that makes the human-readable value more exact,
527 if there is a difference. */
529 uintmax_t q1000
= output_block_size
;
530 uintmax_t q1024
= output_block_size
;
531 bool divisible_by_1000
;
532 bool divisible_by_1024
;
536 divisible_by_1000
= q1000
% 1000 == 0; q1000
/= 1000;
537 divisible_by_1024
= q1024
% 1024 == 0; q1024
/= 1024;
539 while (divisible_by_1000
& divisible_by_1024
);
541 if (divisible_by_1000
< divisible_by_1024
)
542 opts
|= human_base_1024
;
543 if (divisible_by_1024
< divisible_by_1000
)
544 opts
&= ~human_base_1024
;
545 if (! (opts
& human_base_1024
))
548 char *num
= human_readable (output_block_size
, buf
, opts
, 1, 1);
550 /* Reset the header back to the default in OUTPUT_MODE. */
551 header
= _("blocks");
553 /* TRANSLATORS: this is the "1K-blocks" header in "df" output. */
554 if (asprintf (&cell
, _("%s-%s"), num
, header
) == -1)
557 else if (header_mode
== POSIX_MODE
&& columns
[col
]->field
== SIZE_FIELD
)
559 char buf
[INT_BUFSIZE_BOUND (uintmax_t)];
560 char *num
= umaxtostr (output_block_size
, buf
);
562 /* TRANSLATORS: this is the "1024-blocks" header in "df -P". */
563 if (asprintf (&cell
, _("%s-%s"), num
, header
) == -1)
567 cell
= strdup (header
);
572 hide_problematic_chars (cell
);
574 table
[nrows
- 1][col
] = cell
;
576 columns
[col
]->width
= MAX (columns
[col
]->width
, mbswidth (cell
, 0));
580 /* Is FSTYPE a type of file system that should be listed? */
582 static bool _GL_ATTRIBUTE_PURE
583 selected_fstype (const char *fstype
)
585 const struct fs_type_list
*fsp
;
587 if (fs_select_list
== NULL
|| fstype
== NULL
)
589 for (fsp
= fs_select_list
; fsp
; fsp
= fsp
->fs_next
)
590 if (STREQ (fstype
, fsp
->fs_name
))
595 /* Is FSTYPE a type of file system that should be omitted? */
597 static bool _GL_ATTRIBUTE_PURE
598 excluded_fstype (const char *fstype
)
600 const struct fs_type_list
*fsp
;
602 if (fs_exclude_list
== NULL
|| fstype
== NULL
)
604 for (fsp
= fs_exclude_list
; fsp
; fsp
= fsp
->fs_next
)
605 if (STREQ (fstype
, fsp
->fs_name
))
611 devlist_hash (void const *x
, size_t table_size
)
613 struct devlist
const *p
= x
;
614 return (uintmax_t) p
->dev_num
% table_size
;
618 devlist_compare (void const *x
, void const *y
)
620 struct devlist
const *a
= x
;
621 struct devlist
const *b
= y
;
622 return a
->dev_num
== b
->dev_num
;
625 static struct devlist
*
626 devlist_for_dev (dev_t dev
)
628 if (devlist_table
== NULL
)
630 struct devlist dev_entry
;
631 dev_entry
.dev_num
= dev
;
632 return hash_lookup (devlist_table
, &dev_entry
);
636 devlist_free (void *p
)
641 /* Filter mount list by skipping duplicate entries.
642 In the case of duplicates - based on the device number - the mount entry
643 with a '/' in its me_devname (i.e., not pseudo name like tmpfs) wins.
644 If both have a real devname (e.g. bind mounts), then that with the shorter
645 me_mountdir wins. With DEVICES_ONLY == true (set with df -a), only update
646 the global devlist_table, rather than filtering the global mount_list. */
649 filter_mount_list (bool devices_only
)
651 struct mount_entry
*me
;
653 /* Temporary list to keep entries ordered. */
654 struct devlist
*device_list
= NULL
;
655 int mount_list_size
= 0;
657 for (me
= mount_list
; me
; me
= me
->me_next
)
660 devlist_table
= hash_initialize (mount_list_size
, NULL
,
664 if (devlist_table
== NULL
)
667 /* Sort all 'wanted' entries into the list device_list. */
668 for (me
= mount_list
; me
;)
671 struct mount_entry
*discard_me
= NULL
;
673 /* Avoid stating remote file systems as that may hang.
674 On Linux we probably have me_dev populated from /proc/self/mountinfo,
675 however we still stat() in case another device was mounted later. */
676 if ((me
->me_remote
&& show_local_fs
)
677 || -1 == stat (me
->me_mountdir
, &buf
))
679 /* If remote, and showing just local, add ME for filtering later.
680 If stat failed; add ME to be able to complain about it later. */
681 buf
.st_dev
= me
->me_dev
;
685 /* If we've already seen this device... */
686 struct devlist
*seen_dev
= devlist_for_dev (buf
.st_dev
);
690 bool target_nearer_root
= strlen (seen_dev
->me
->me_mountdir
)
691 > strlen (me
->me_mountdir
);
692 /* With bind mounts, prefer items nearer the root of the source */
693 bool source_below_root
= seen_dev
->me
->me_mntroot
!= NULL
694 && me
->me_mntroot
!= NULL
695 && (strlen (seen_dev
->me
->me_mntroot
)
696 < strlen (me
->me_mntroot
));
697 if (! print_grand_total
698 && me
->me_remote
&& seen_dev
->me
->me_remote
699 && ! STREQ (seen_dev
->me
->me_devname
, me
->me_devname
))
701 /* Don't discard remote entries with different locations,
702 as these are more likely to be explicitly mounted.
703 However avoid this when producing a total to give
704 a more accurate value in that case. */
706 else if ((strchr (me
->me_devname
, '/')
707 /* let "real" devices with '/' in the name win. */
708 && ! strchr (seen_dev
->me
->me_devname
, '/'))
709 /* let points towards the root of the device win. */
710 || (target_nearer_root
&& ! source_below_root
)
711 /* let an entry overmounted on a new device win... */
712 || (! STREQ (seen_dev
->me
->me_devname
, me
->me_devname
)
713 /* ... but only when matching an existing mnt point,
714 to avoid problematic replacement when given
715 inaccurate mount lists, seen with some chroot
716 environments for example. */
717 && STREQ (me
->me_mountdir
,
718 seen_dev
->me
->me_mountdir
)))
720 /* Discard mount entry for existing device. */
721 discard_me
= seen_dev
->me
;
726 /* Discard mount entry currently being processed. */
737 free_mount_entry (discard_me
);
741 /* Add the device number to the device_table. */
742 struct devlist
*devlist
= xmalloc (sizeof *devlist
);
744 devlist
->dev_num
= buf
.st_dev
;
745 devlist
->next
= device_list
;
746 device_list
= devlist
;
747 if (hash_insert (devlist_table
, devlist
) == NULL
)
754 /* Finally rebuild the mount_list from the devlist. */
755 if (! devices_only
) {
759 /* Add the mount entry. */
760 me
= device_list
->me
;
761 me
->me_next
= mount_list
;
763 device_list
= device_list
->next
;
766 hash_free (devlist_table
);
767 devlist_table
= NULL
;
772 /* Search a mount entry list for device id DEV.
773 Return the corresponding mount entry if found or NULL if not. */
775 static struct mount_entry
const * _GL_ATTRIBUTE_PURE
776 me_for_dev (dev_t dev
)
778 struct devlist
*dl
= devlist_for_dev (dev
);
785 /* Return true if N is a known integer value. On many file systems,
786 UINTMAX_MAX represents an unknown value; on AIX, UINTMAX_MAX - 1
787 represents unknown. Use a rule that works on AIX file systems, and
788 that almost-always works on other types. */
790 known_value (uintmax_t n
)
792 return n
< UINTMAX_MAX
- 1;
795 /* Like human_readable (N, BUF, human_output_opts, INPUT_UNITS, OUTPUT_UNITS),
798 - If NEGATIVE, then N represents a negative number,
799 expressed in two's complement.
800 - Otherwise, return "-" if N is unknown. */
803 df_readable (bool negative
, uintmax_t n
, char *buf
,
804 uintmax_t input_units
, uintmax_t output_units
)
806 if (! known_value (n
) && !negative
)
810 char *p
= human_readable (negative
? -n
: n
, buf
+ negative
,
811 human_output_opts
, input_units
, output_units
);
818 /* Logical equivalence */
819 #define LOG_EQ(a, b) (!(a) == !(b))
821 /* Add integral value while using uintmax_t for value part and separate
822 negation flag. It adds value of SRC and SRC_NEG to DEST and DEST_NEG.
823 The result will be in DEST and DEST_NEG. See df_readable to understand
824 how the negation flag is used. */
826 add_uint_with_neg_flag (uintmax_t *dest
, bool *dest_neg
,
827 uintmax_t src
, bool src_neg
)
829 if (LOG_EQ (*dest_neg
, src_neg
))
853 /* Return true if S ends in a string that may be a 36-byte UUID,
854 i.e., of the form HHHHHHHH-HHHH-HHHH-HHHH-HHHHHHHHHHHH, where
855 each H is an upper or lower case hexadecimal digit. */
856 static bool _GL_ATTRIBUTE_PURE
857 has_uuid_suffix (char const *s
)
859 size_t len
= strlen (s
);
861 && strspn (s
+ len
- 36, "-0123456789abcdefABCDEF") == 36);
864 /* Obtain the block values BV and inode values IV
865 from the file system usage FSU. */
867 get_field_values (struct field_values_t
*bv
,
868 struct field_values_t
*iv
,
869 const struct fs_usage
*fsu
)
872 iv
->input_units
= iv
->output_units
= 1;
873 iv
->total
= fsu
->fsu_files
;
874 iv
->available
= iv
->available_to_root
= fsu
->fsu_ffree
;
875 iv
->negate_available
= false;
877 iv
->used
= UINTMAX_MAX
;
878 iv
->negate_used
= false;
879 if (known_value (iv
->total
) && known_value (iv
->available_to_root
))
881 iv
->used
= iv
->total
- iv
->available_to_root
;
882 iv
->negate_used
= (iv
->total
< iv
->available_to_root
);
886 bv
->input_units
= fsu
->fsu_blocksize
;
887 bv
->output_units
= output_block_size
;
888 bv
->total
= fsu
->fsu_blocks
;
889 bv
->available
= fsu
->fsu_bavail
;
890 bv
->available_to_root
= fsu
->fsu_bfree
;
891 bv
->negate_available
= (fsu
->fsu_bavail_top_bit_set
892 && known_value (fsu
->fsu_bavail
));
894 bv
->used
= UINTMAX_MAX
;
895 bv
->negate_used
= false;
896 if (known_value (bv
->total
) && known_value (bv
->available_to_root
))
898 bv
->used
= bv
->total
- bv
->available_to_root
;
899 bv
->negate_used
= (bv
->total
< bv
->available_to_root
);
903 /* Add block and inode values to grand total. */
905 add_to_grand_total (struct field_values_t
*bv
, struct field_values_t
*iv
)
907 if (known_value (iv
->total
))
908 grand_fsu
.fsu_files
+= iv
->total
;
909 if (known_value (iv
->available
))
910 grand_fsu
.fsu_ffree
+= iv
->available
;
912 if (known_value (bv
->total
))
913 grand_fsu
.fsu_blocks
+= bv
->input_units
* bv
->total
;
914 if (known_value (bv
->available_to_root
))
915 grand_fsu
.fsu_bfree
+= bv
->input_units
* bv
->available_to_root
;
916 if (known_value (bv
->available
))
917 add_uint_with_neg_flag (&grand_fsu
.fsu_bavail
,
918 &grand_fsu
.fsu_bavail_top_bit_set
,
919 bv
->input_units
* bv
->available
,
920 bv
->negate_available
);
923 /* Obtain a space listing for the disk device with absolute file name DISK.
924 If MOUNT_POINT is non-NULL, it is the name of the root of the
926 If STAT_FILE is non-null, it is the name of a file within the file
927 system that the user originally asked for; this provides better
928 diagnostics, and sometimes it provides better results on networked
929 file systems that give different free-space results depending on
930 where in the file system you probe.
931 If FSTYPE is non-NULL, it is the type of the file system on DISK.
932 If MOUNT_POINT is non-NULL, then DISK may be NULL -- certain systems may
933 not be able to produce statistics in this case.
934 ME_DUMMY and ME_REMOTE are the mount entry flags.
935 Caller must set PROCESS_ALL to true when iterating over all entries, as
936 when df is invoked with no non-option argument. See below for details. */
939 get_dev (char const *disk
, char const *mount_point
, char const* file
,
940 char const *stat_file
, char const *fstype
,
941 bool me_dummy
, bool me_remote
,
942 const struct fs_usage
*force_fsu
,
945 if (me_remote
&& show_local_fs
)
948 if (me_dummy
&& !show_all_fs
&& !show_listed_fs
)
951 if (!selected_fstype (fstype
) || excluded_fstype (fstype
))
954 /* Ignore relative MOUNT_POINTs, which are present for example
955 in /proc/mounts on Linux with network namespaces. */
956 if (!force_fsu
&& mount_point
&& ! IS_ABSOLUTE_FILE_NAME (mount_point
))
959 /* If MOUNT_POINT is NULL, then the file system is not mounted, and this
960 program reports on the file system that the special file is on.
961 It would be better to report on the unmounted file system,
962 but statfs doesn't do that on most systems. */
964 stat_file
= mount_point
? mount_point
: disk
;
969 else if (get_fs_usage (stat_file
, disk
, &fsu
))
971 /* If we can't access a system provided entry due
972 to it not being present (now), or due to permissions,
973 just output placeholder values rather than failing. */
974 if (process_all
&& (errno
== EACCES
|| errno
== ENOENT
))
980 fsu
.fsu_bavail_top_bit_set
= false;
981 fsu
.fsu_blocksize
= fsu
.fsu_blocks
= fsu
.fsu_bfree
=
982 fsu
.fsu_bavail
= fsu
.fsu_files
= fsu
.fsu_ffree
= UINTMAX_MAX
;
986 error (0, errno
, "%s", quotef (stat_file
));
987 exit_status
= EXIT_FAILURE
;
991 else if (process_all
&& show_all_fs
)
993 /* Ensure we don't output incorrect stats for over-mounted directories.
994 Discard stats when the device name doesn't match. Though don't
995 discard when used and current mount entries are both remote due
996 to the possibility of aliased host names or exports. */
998 if (stat (stat_file
, &sb
) == 0)
1000 struct mount_entry
const * dev_me
= me_for_dev (sb
.st_dev
);
1001 if (dev_me
&& ! STREQ (dev_me
->me_devname
, disk
)
1002 && (! dev_me
->me_remote
|| ! me_remote
))
1005 fsu
.fsu_bavail_top_bit_set
= false;
1006 fsu
.fsu_blocksize
= fsu
.fsu_blocks
= fsu
.fsu_bfree
=
1007 fsu
.fsu_bavail
= fsu
.fsu_files
= fsu
.fsu_ffree
= UINTMAX_MAX
;
1012 if (fsu
.fsu_blocks
== 0 && !show_all_fs
&& !show_listed_fs
)
1016 file_systems_processed
= true;
1021 disk
= "-"; /* unknown */
1024 file
= "-"; /* unspecified */
1026 char *dev_name
= xstrdup (disk
);
1029 /* On some systems, dev_name is a long-named symlink like
1030 /dev/disk/by-uuid/828fc648-9f30-43d8-a0b1-f7196a2edb66 pointing to a
1031 much shorter and more useful name like /dev/sda1. It may also look
1032 like /dev/mapper/luks-828fc648-9f30-43d8-a0b1-f7196a2edb66 and point to
1033 /dev/dm-0. When process_all is true and dev_name is a symlink whose
1034 name ends with a UUID use the resolved name instead. */
1036 && has_uuid_suffix (dev_name
)
1037 && (resolved_dev
= canonicalize_filename_mode (dev_name
, CAN_EXISTING
)))
1040 dev_name
= resolved_dev
;
1044 fstype
= "-"; /* unknown */
1046 struct field_values_t block_values
;
1047 struct field_values_t inode_values
;
1048 get_field_values (&block_values
, &inode_values
, &fsu
);
1050 /* Add to grand total unless processing grand total line. */
1051 if (print_grand_total
&& ! force_fsu
)
1052 add_to_grand_total (&block_values
, &inode_values
);
1055 for (col
= 0; col
< ncolumns
; col
++)
1057 char buf
[LONGEST_HUMAN_READABLE
+ 2];
1060 struct field_values_t
*v
;
1061 switch (columns
[col
]->field_type
)
1073 v
= NULL
; /* Avoid warnings where assert() is not __noreturn__. */
1074 assert (!"bad field_type");
1077 switch (columns
[col
]->field
)
1080 cell
= xstrdup (dev_name
);
1084 cell
= xstrdup (fstype
);
1089 cell
= xstrdup (df_readable (false, v
->total
, buf
,
1090 v
->input_units
, v
->output_units
));
1095 cell
= xstrdup (df_readable (v
->negate_used
, v
->used
, buf
,
1096 v
->input_units
, v
->output_units
));
1101 cell
= xstrdup (df_readable (v
->negate_available
, v
->available
, buf
,
1102 v
->input_units
, v
->output_units
));
1109 if (! known_value (v
->used
) || ! known_value (v
->available
))
1111 else if (!v
->negate_used
1112 && v
->used
<= TYPE_MAXIMUM (uintmax_t) / 100
1113 && v
->used
+ v
->available
!= 0
1114 && (v
->used
+ v
->available
< v
->used
)
1115 == v
->negate_available
)
1117 uintmax_t u100
= v
->used
* 100;
1118 uintmax_t nonroot_total
= v
->used
+ v
->available
;
1119 pct
= u100
/ nonroot_total
+ (u100
% nonroot_total
!= 0);
1123 /* The calculation cannot be done easily with integer
1124 arithmetic. Fall back on floating point. This can suffer
1125 from minor rounding errors, but doing it exactly requires
1126 multiple precision arithmetic, and it's not worth the
1128 double u
= v
->negate_used
? - (double) - v
->used
: v
->used
;
1129 double a
= v
->negate_available
1130 ? - (double) - v
->available
: v
->available
;
1131 double nonroot_total
= u
+ a
;
1134 long int lipct
= pct
= u
* 100 / nonroot_total
;
1135 double ipct
= lipct
;
1137 /* Like 'pct = ceil (dpct);', but avoid ceil so that
1138 the math library needn't be linked. */
1139 if (ipct
- 1 < pct
&& pct
<= ipct
+ 1)
1140 pct
= ipct
+ (ipct
< pct
);
1146 if (asprintf (&cell
, "%.0f%%", pct
) == -1)
1150 cell
= strdup ("-");
1159 cell
= xstrdup (file
);
1163 #ifdef HIDE_AUTOMOUNT_PREFIX
1164 /* Don't print the first directory name in MOUNT_POINT if it's an
1165 artifact of an automounter. This is a bit too aggressive to be
1167 if (STRNCMP_LIT (mount_point
, "/auto/") == 0)
1169 else if (STRNCMP_LIT (mount_point
, "/tmp_mnt/") == 0)
1172 cell
= xstrdup (mount_point
);
1176 assert (!"unhandled field");
1180 assert (!"empty cell");
1182 hide_problematic_chars (cell
);
1183 columns
[col
]->width
= MAX (columns
[col
]->width
, mbswidth (cell
, 0));
1184 table
[nrows
- 1][col
] = cell
;
1189 /* Scan the mount list returning the _last_ device found for MOUNT.
1190 NULL is returned if MOUNT not found. The result is malloced. */
1192 last_device_for_mount (char const* mount
)
1194 struct mount_entry
const *me
;
1195 struct mount_entry
const *le
= NULL
;
1197 for (me
= mount_list
; me
; me
= me
->me_next
)
1199 if (STREQ (me
->me_mountdir
, mount
))
1205 char *devname
= le
->me_devname
;
1206 char *canon_dev
= canonicalize_file_name (devname
);
1207 if (canon_dev
&& IS_ABSOLUTE_FILE_NAME (canon_dev
))
1210 return xstrdup (le
->me_devname
);
1216 /* If DISK corresponds to a mount point, show its usage
1217 and return true. Otherwise, return false. */
1219 get_disk (char const *disk
)
1221 struct mount_entry
const *me
;
1222 struct mount_entry
const *best_match
= NULL
;
1223 bool best_match_accessible
= false;
1224 bool eclipsed_device
= false;
1225 char const *file
= disk
;
1227 char *resolved
= canonicalize_file_name (disk
);
1228 if (resolved
&& IS_ABSOLUTE_FILE_NAME (resolved
))
1231 size_t best_match_len
= SIZE_MAX
;
1232 for (me
= mount_list
; me
; me
= me
->me_next
)
1234 /* TODO: Should cache canon_dev in the mount_entry struct. */
1235 char *devname
= me
->me_devname
;
1236 char *canon_dev
= canonicalize_file_name (me
->me_devname
);
1237 if (canon_dev
&& IS_ABSOLUTE_FILE_NAME (canon_dev
))
1238 devname
= canon_dev
;
1240 if (STREQ (disk
, devname
))
1242 char *last_device
= last_device_for_mount (me
->me_mountdir
);
1243 eclipsed_device
= last_device
&& ! STREQ (last_device
, devname
);
1244 size_t len
= strlen (me
->me_mountdir
);
1246 if (! eclipsed_device
1247 && (! best_match_accessible
|| len
< best_match_len
))
1249 struct stat disk_stats
;
1250 bool this_match_accessible
= false;
1252 if (stat (me
->me_mountdir
, &disk_stats
) == 0)
1253 best_match_accessible
= this_match_accessible
= true;
1255 if (this_match_accessible
1256 || (! best_match_accessible
&& len
< best_match_len
))
1259 if (len
== 1) /* Traditional root. */
1266 best_match_len
= len
;
1280 get_dev (best_match
->me_devname
, best_match
->me_mountdir
, file
, NULL
,
1281 best_match
->me_type
, best_match
->me_dummy
,
1282 best_match
->me_remote
, NULL
, false);
1285 else if (eclipsed_device
)
1287 error (0, 0, _("cannot access %s: over-mounted by another device"),
1289 exit_status
= EXIT_FAILURE
;
1296 /* Figure out which device file or directory POINT is mounted on
1297 and show its disk usage.
1298 STATP must be the result of 'stat (POINT, STATP)'. */
1300 get_point (const char *point
, const struct stat
*statp
)
1302 struct stat disk_stats
;
1303 struct mount_entry
*me
;
1304 struct mount_entry
const *best_match
= NULL
;
1306 /* Calculate the real absolute file name for POINT, and use that to find
1307 the mount point. This avoids statting unavailable mount points,
1308 which can hang df. */
1309 char *resolved
= canonicalize_file_name (point
);
1310 if (resolved
&& resolved
[0] == '/')
1312 size_t resolved_len
= strlen (resolved
);
1313 size_t best_match_len
= 0;
1315 for (me
= mount_list
; me
; me
= me
->me_next
)
1317 if (!STREQ (me
->me_type
, "lofs")
1318 && (!best_match
|| best_match
->me_dummy
|| !me
->me_dummy
))
1320 size_t len
= strlen (me
->me_mountdir
);
1321 if (best_match_len
<= len
&& len
<= resolved_len
1322 && (len
== 1 /* root file system */
1323 || ((len
== resolved_len
|| resolved
[len
] == '/')
1324 && STREQ_LEN (me
->me_mountdir
, resolved
, len
))))
1327 best_match_len
= len
;
1334 && (stat (best_match
->me_mountdir
, &disk_stats
) != 0
1335 || disk_stats
.st_dev
!= statp
->st_dev
))
1339 for (me
= mount_list
; me
; me
= me
->me_next
)
1341 if (me
->me_dev
== (dev_t
) -1)
1343 if (stat (me
->me_mountdir
, &disk_stats
) == 0)
1344 me
->me_dev
= disk_stats
.st_dev
;
1347 /* Report only I/O errors. Other errors might be
1348 caused by shadowed mount points, which means POINT
1349 can't possibly be on this file system. */
1352 error (0, errno
, "%s", quotef (me
->me_mountdir
));
1353 exit_status
= EXIT_FAILURE
;
1356 /* So we won't try and fail repeatedly. */
1357 me
->me_dev
= (dev_t
) -2;
1361 if (statp
->st_dev
== me
->me_dev
1362 && !STREQ (me
->me_type
, "lofs")
1363 && (!best_match
|| best_match
->me_dummy
|| !me
->me_dummy
))
1365 /* Skip bogus mtab entries. */
1366 if (stat (me
->me_mountdir
, &disk_stats
) != 0
1367 || disk_stats
.st_dev
!= me
->me_dev
)
1368 me
->me_dev
= (dev_t
) -2;
1375 get_dev (best_match
->me_devname
, best_match
->me_mountdir
, point
, point
,
1376 best_match
->me_type
, best_match
->me_dummy
, best_match
->me_remote
,
1380 /* We couldn't find the mount entry corresponding to POINT. Go ahead and
1381 print as much info as we can; methods that require the device to be
1382 present will fail at a later point. */
1384 /* Find the actual mount point. */
1385 char *mp
= find_mount_point (point
, statp
);
1388 get_dev (NULL
, mp
, point
, NULL
, NULL
, false, false, NULL
, false);
1394 /* Determine what kind of node NAME is and show the disk usage
1395 for it. STATP is the results of 'stat' on NAME. */
1398 get_entry (char const *name
, struct stat
const *statp
)
1400 if ((S_ISBLK (statp
->st_mode
) || S_ISCHR (statp
->st_mode
))
1404 get_point (name
, statp
);
1407 /* Show all mounted file systems, except perhaps those that are of
1408 an unselected type or are empty. */
1411 get_all_entries (void)
1413 struct mount_entry
*me
;
1415 filter_mount_list (show_all_fs
);
1417 for (me
= mount_list
; me
; me
= me
->me_next
)
1418 get_dev (me
->me_devname
, me
->me_mountdir
, NULL
, NULL
, me
->me_type
,
1419 me
->me_dummy
, me
->me_remote
, NULL
, true);
1422 /* Add FSTYPE to the list of file system types to display. */
1425 add_fs_type (const char *fstype
)
1427 struct fs_type_list
*fsp
;
1429 fsp
= xmalloc (sizeof *fsp
);
1430 fsp
->fs_name
= (char *) fstype
;
1431 fsp
->fs_next
= fs_select_list
;
1432 fs_select_list
= fsp
;
1435 /* Add FSTYPE to the list of file system types to be omitted. */
1438 add_excluded_fs_type (const char *fstype
)
1440 struct fs_type_list
*fsp
;
1442 fsp
= xmalloc (sizeof *fsp
);
1443 fsp
->fs_name
= (char *) fstype
;
1444 fsp
->fs_next
= fs_exclude_list
;
1445 fs_exclude_list
= fsp
;
1451 if (status
!= EXIT_SUCCESS
)
1455 printf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name
);
1457 Show information about the file system on which each FILE resides,\n\
1458 or all file systems by default.\n\
1461 emit_mandatory_arg_note ();
1463 /* TRANSLATORS: The thousands and decimal separators are best
1464 adjusted to an appropriate default for your locale. */
1466 -a, --all include pseudo, duplicate, inaccessible file systems\n\
1467 -B, --block-size=SIZE scale sizes by SIZE before printing them; e.g.,\n\
1468 '-BM' prints sizes in units of 1,048,576 bytes;\n\
1469 see SIZE format below\n\
1470 -h, --human-readable print sizes in powers of 1024 (e.g., 1023M)\n\
1471 -H, --si print sizes in powers of 1000 (e.g., 1.1G)\n\
1474 -i, --inodes list inode information instead of block usage\n\
1475 -k like --block-size=1K\n\
1476 -l, --local limit listing to local file systems\n\
1477 --no-sync do not invoke sync before getting usage info (default)\
1481 --output[=FIELD_LIST] use the output format defined by FIELD_LIST,\n\
1482 or print all fields if FIELD_LIST is omitted.\n\
1483 -P, --portability use the POSIX output format\n\
1484 --sync invoke sync before getting usage info\n\
1487 --total elide all entries insignificant to available space,\n\
1488 and produce a grand total\n\
1491 -t, --type=TYPE limit listing to file systems of type TYPE\n\
1492 -T, --print-type print file system type\n\
1493 -x, --exclude-type=TYPE limit listing to file systems not of type TYPE\n\
1496 fputs (HELP_OPTION_DESCRIPTION
, stdout
);
1497 fputs (VERSION_OPTION_DESCRIPTION
, stdout
);
1498 emit_blocksize_note ("DF");
1501 FIELD_LIST is a comma-separated list of columns to be included. Valid\n\
1502 field names are: 'source', 'fstype', 'itotal', 'iused', 'iavail', 'ipcent',\n\
1503 'size', 'used', 'avail', 'pcent', 'file' and 'target' (see info page).\n\
1505 emit_ancillary_info (PROGRAM_NAME
);
1511 main (int argc
, char **argv
)
1513 struct stat
*stats
IF_LINT ( = 0);
1515 initialize_main (&argc
, &argv
);
1516 set_program_name (argv
[0]);
1517 setlocale (LC_ALL
, "");
1518 bindtextdomain (PACKAGE
, LOCALEDIR
);
1519 textdomain (PACKAGE
);
1521 atexit (close_stdout
);
1523 fs_select_list
= NULL
;
1524 fs_exclude_list
= NULL
;
1525 show_all_fs
= false;
1526 show_listed_fs
= false;
1527 human_output_opts
= -1;
1529 file_systems_processed
= false;
1530 exit_status
= EXIT_SUCCESS
;
1531 print_grand_total
= false;
1532 grand_fsu
.fsu_blocksize
= 1;
1534 /* If true, use the POSIX output format. */
1535 bool posix_format
= false;
1537 const char *msg_mut_excl
= _("options %s and %s are mutually exclusive");
1542 int c
= getopt_long (argc
, argv
, "aB:iF:hHklmPTt:vx:", long_options
,
1554 enum strtol_error e
= human_options (optarg
, &human_output_opts
,
1555 &output_block_size
);
1556 if (e
!= LONGINT_OK
)
1557 xstrtol_fatal (e
, oi
, c
, long_options
, optarg
);
1561 if (header_mode
== OUTPUT_MODE
)
1563 error (0, 0, msg_mut_excl
, "-i", "--output");
1564 usage (EXIT_FAILURE
);
1566 header_mode
= INODES_MODE
;
1569 human_output_opts
= human_autoscale
| human_SI
| human_base_1024
;
1570 output_block_size
= 1;
1573 human_output_opts
= human_autoscale
| human_SI
;
1574 output_block_size
= 1;
1577 human_output_opts
= 0;
1578 output_block_size
= 1024;
1581 show_local_fs
= true;
1583 case 'm': /* obsolescent, exists for BSD compatibility */
1584 human_output_opts
= 0;
1585 output_block_size
= 1024 * 1024;
1588 if (header_mode
== OUTPUT_MODE
)
1590 error (0, 0, msg_mut_excl
, "-T", "--output");
1591 usage (EXIT_FAILURE
);
1596 if (header_mode
== OUTPUT_MODE
)
1598 error (0, 0, msg_mut_excl
, "-P", "--output");
1599 usage (EXIT_FAILURE
);
1601 posix_format
= true;
1604 require_sync
= true;
1606 case NO_SYNC_OPTION
:
1607 require_sync
= false;
1611 /* Accept -F as a synonym for -t for compatibility with Solaris. */
1613 add_fs_type (optarg
);
1616 case 'v': /* For SysV compatibility. */
1620 add_excluded_fs_type (optarg
);
1624 if (header_mode
== INODES_MODE
)
1626 error (0, 0, msg_mut_excl
, "-i", "--output");
1627 usage (EXIT_FAILURE
);
1629 if (posix_format
&& header_mode
== DEFAULT_MODE
)
1631 error (0, 0, msg_mut_excl
, "-P", "--output");
1632 usage (EXIT_FAILURE
);
1636 error (0, 0, msg_mut_excl
, "-T", "--output");
1637 usage (EXIT_FAILURE
);
1639 header_mode
= OUTPUT_MODE
;
1641 decode_output_arg (optarg
);
1645 print_grand_total
= true;
1648 case_GETOPT_HELP_CHAR
;
1649 case_GETOPT_VERSION_CHAR (PROGRAM_NAME
, AUTHORS
);
1652 usage (EXIT_FAILURE
);
1656 if (human_output_opts
== -1)
1660 human_output_opts
= 0;
1661 output_block_size
= (getenv ("POSIXLY_CORRECT") ? 512 : 1024);
1664 human_options (getenv ("DF_BLOCK_SIZE"),
1665 &human_output_opts
, &output_block_size
);
1668 if (header_mode
== INODES_MODE
|| header_mode
== OUTPUT_MODE
)
1670 else if (human_output_opts
& human_autoscale
)
1671 header_mode
= HUMAN_MODE
;
1672 else if (posix_format
)
1673 header_mode
= POSIX_MODE
;
1675 /* Fail if the same file system type was both selected and excluded. */
1678 struct fs_type_list
*fs_incl
;
1679 for (fs_incl
= fs_select_list
; fs_incl
; fs_incl
= fs_incl
->fs_next
)
1681 struct fs_type_list
*fs_excl
;
1682 for (fs_excl
= fs_exclude_list
; fs_excl
; fs_excl
= fs_excl
->fs_next
)
1684 if (STREQ (fs_incl
->fs_name
, fs_excl
->fs_name
))
1687 _("file system type %s both selected and excluded"),
1688 quote (fs_incl
->fs_name
));
1695 return EXIT_FAILURE
;
1698 assume (0 < optind
);
1704 /* Open each of the given entries to make sure any corresponding
1705 partition is automounted. This must be done before reading the
1706 file system table. */
1707 stats
= xnmalloc (argc
- optind
, sizeof *stats
);
1708 for (i
= optind
; i
< argc
; ++i
)
1710 /* Prefer to open with O_NOCTTY and use fstat, but fall back
1711 on using "stat", in case the file is unreadable. */
1712 int fd
= open (argv
[i
], O_RDONLY
| O_NOCTTY
);
1713 if ((fd
< 0 || fstat (fd
, &stats
[i
- optind
]))
1714 && stat (argv
[i
], &stats
[i
- optind
]))
1716 error (0, errno
, "%s", quotef (argv
[i
]));
1717 exit_status
= EXIT_FAILURE
;
1726 read_file_system_list ((fs_select_list
!= NULL
1727 || fs_exclude_list
!= NULL
1729 || field_data
[FSTYPE_FIELD
].used
1732 if (mount_list
== NULL
)
1734 /* Couldn't read the table of mounted file systems.
1735 Fail if df was invoked with no file name arguments,
1736 or when either of -a, -l, -t or -x is used with file name
1737 arguments. Otherwise, merely give a warning and proceed. */
1739 if ( ! (optind
< argc
)
1742 || fs_select_list
!= NULL
1743 || fs_exclude_list
!= NULL
))
1745 status
= EXIT_FAILURE
;
1747 const char *warning
= (status
== 0 ? _("Warning: ") : "");
1748 error (status
, errno
, "%s%s", warning
,
1749 _("cannot read table of mounted file systems"));
1762 /* Display explicitly requested empty file systems. */
1763 show_listed_fs
= true;
1765 for (i
= optind
; i
< argc
; ++i
)
1767 get_entry (argv
[i
], &stats
[i
- optind
]);
1769 IF_LINT (free (stats
));
1774 if (file_systems_processed
)
1776 if (print_grand_total
)
1778 (field_data
[SOURCE_FIELD
].used
? "-" : "total"),
1779 NULL
, NULL
, NULL
, false, false, &grand_fsu
, false);
1785 /* Print the "no FS processed" diagnostic only if there was no preceding
1786 diagnostic, e.g., if all have been excluded. */
1787 if (exit_status
== EXIT_SUCCESS
)
1788 die (EXIT_FAILURE
, 0, _("no file systems processed"));
1791 IF_LINT (free (columns
));