1 /* df - summarize free file system space
2 Copyright (C) 1991-2022 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17 /* Written by David MacKenzie <djm@gnu.ai.mit.edu>.
18 --human-readable option added by lm@sgi.com.
19 --si and large file support added by eggert@twinsun.com. */
23 #include <sys/types.h>
31 #include "canonicalize.h"
38 #include "mountlist.h"
40 #include "find-mount-point.h"
42 #include "xstrtol-error.h"
44 /* The official name of this program (e.g., no 'g' prefix). */
45 #define PROGRAM_NAME "df"
48 proper_name ("Torbjorn Granlund"), \
49 proper_name ("David MacKenzie"), \
50 proper_name ("Paul Eggert")
55 struct mount_entry
*me
;
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. */
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
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
;
140 static int header_mode
= DEFAULT_MODE
;
142 /* Displayable fields. */
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 */
160 /* Flag if a field contains a block, an inode or another value. */
163 BLOCK_FLD
, /* Block values field */
164 INODE_FLD
, /* Inode values field */
165 OTHER_FLD
/* Neutral field, e.g. target */
168 /* Attributes of a display field. */
171 display_field_t field
;
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. */
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
;
230 struct field_values_t
232 uintmax_t input_units
;
233 uintmax_t output_units
;
236 bool negate_available
;
237 uintmax_t available_to_root
;
242 /* Storage for pointers for each string (cell of table). */
243 static char ***table
;
245 /* The current number of processed rows (including header). */
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. */
252 NO_SYNC_OPTION
= CHAR_MAX
+ 1,
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
},
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. */
284 automount_stat_err (char const *file
, struct stat
*st
)
286 int fd
= open (file
, O_RDONLY
| O_NOCTTY
| O_NONBLOCK
);
289 if (errno
== ENOENT
|| errno
== ENOTDIR
)
291 return stat (file
, st
) == 0 ? 0 : errno
;
295 int err
= fstat (fd
, st
) == 0 ? 0 : errno
;
301 /* Replace problematic chars with '?'.
302 Since only control characters are currently considered,
303 this should work in all encodings. */
306 replace_control_chars (char *cell
)
311 if (c_iscntrl (to_uchar (*p
)))
317 /* Replace problematic chars with '?'. */
320 replace_invalid_chars (char *cell
)
322 char *srcend
= cell
+ strlen (cell
);
324 mbstate_t mbstate
= { 0, };
327 for (char *src
= cell
; src
!= srcend
; src
+= n
)
330 size_t srcbytes
= srcend
- src
;
331 n
= mbrtowc (&wc
, src
, srcbytes
, &mbstate
);
332 bool ok
= n
<= srcbytes
;
341 memmove (dst
, src
, n
);
347 memset (&mbstate
, 0, sizeof mbstate
);
355 replace_problematic_chars (char *cell
)
357 static int tty_out
= -1;
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. */
369 alloc_table_row (void)
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. */
384 for (row
= 0; row
< nrows
; row
++)
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. */
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
);
408 IF_LINT (free (table
[row
][col
]));
411 IF_LINT (free (table
[row
]));
414 IF_LINT (free (table
));
417 /* Dynamically allocate a struct field_t in COLUMNS, which
418 can then be accessed with standard array notation. */
421 alloc_field (int f
, char const *c
)
424 columns
= xnrealloc (columns
, ncolumns
, sizeof (struct field_data_t
*));
425 columns
[ncolumns
- 1] = &field_data
[f
];
427 columns
[ncolumns
- 1]->caption
= c
;
429 if (field_data
[f
].used
)
430 assert (!"field used");
432 /* Mark field as used. */
433 field_data
[f
].used
= true;
437 /* Given a string, ARG, containing a comma-separated list of arguments
438 to the --output option, add the appropriate fields to columns. */
440 decode_output_arg (char const *arg
)
442 char *arg_writable
= xstrdup (arg
);
443 char *s
= arg_writable
;
446 /* find next comma */
447 char *comma
= strchr (s
, ',');
449 /* If we found a comma, put a NUL in its place and advance. */
454 display_field_t field
= INVALID_FIELD
;
455 for (unsigned int i
= 0; i
< ARRAY_CARDINALITY (field_data
); i
++)
457 if (STREQ (field_data
[i
].arg
, s
))
463 if (field
== INVALID_FIELD
)
465 error (0, 0, _("option --output: field %s unknown"), quote (s
));
466 usage (EXIT_FAILURE
);
469 if (field_data
[field
].used
)
471 /* Prevent the fields from being used more than once. */
472 error (0, 0, _("option --output: field %s used more than once"),
473 quote (field_data
[field
].arg
));
474 usage (EXIT_FAILURE
);
489 alloc_field (field
, NULL
);
493 alloc_field (field
, N_("Size"));
497 alloc_field (field
, N_("Avail"));
501 assert (!"invalid field");
510 /* Get the appropriate columns for the mode. */
512 get_field_list (void)
517 alloc_field (SOURCE_FIELD
, NULL
);
519 alloc_field (FSTYPE_FIELD
, NULL
);
520 alloc_field (SIZE_FIELD
, NULL
);
521 alloc_field (USED_FIELD
, NULL
);
522 alloc_field (AVAIL_FIELD
, NULL
);
523 alloc_field (PCENT_FIELD
, NULL
);
524 alloc_field (TARGET_FIELD
, NULL
);
528 alloc_field (SOURCE_FIELD
, NULL
);
530 alloc_field (FSTYPE_FIELD
, NULL
);
532 alloc_field (SIZE_FIELD
, N_("Size"));
533 alloc_field (USED_FIELD
, NULL
);
534 alloc_field (AVAIL_FIELD
, N_("Avail"));
535 alloc_field (PCENT_FIELD
, NULL
);
536 alloc_field (TARGET_FIELD
, NULL
);
540 alloc_field (SOURCE_FIELD
, NULL
);
542 alloc_field (FSTYPE_FIELD
, NULL
);
543 alloc_field (ITOTAL_FIELD
, NULL
);
544 alloc_field (IUSED_FIELD
, NULL
);
545 alloc_field (IAVAIL_FIELD
, NULL
);
546 alloc_field (IPCENT_FIELD
, NULL
);
547 alloc_field (TARGET_FIELD
, NULL
);
551 alloc_field (SOURCE_FIELD
, NULL
);
553 alloc_field (FSTYPE_FIELD
, NULL
);
554 alloc_field (SIZE_FIELD
, NULL
);
555 alloc_field (USED_FIELD
, NULL
);
556 alloc_field (AVAIL_FIELD
, NULL
);
557 alloc_field (PCENT_FIELD
, N_("Capacity"));
558 alloc_field (TARGET_FIELD
, NULL
);
564 /* Add all fields if --output was given without a field list. */
565 decode_output_arg (all_args_string
);
570 assert (!"invalid header_mode");
574 /* Obtain the appropriate header entries. */
583 for (col
= 0; col
< ncolumns
; col
++)
586 char const *header
= _(columns
[col
]->caption
);
588 if (columns
[col
]->field
== SIZE_FIELD
589 && (header_mode
== DEFAULT_MODE
590 || (header_mode
== OUTPUT_MODE
591 && !(human_output_opts
& human_autoscale
))))
593 char buf
[LONGEST_HUMAN_READABLE
+ 1];
595 int opts
= (human_suppress_point_zero
596 | human_autoscale
| human_SI
598 & (human_group_digits
| human_base_1024
| human_B
)));
600 /* Prefer the base that makes the human-readable value more exact,
601 if there is a difference. */
603 uintmax_t q1000
= output_block_size
;
604 uintmax_t q1024
= output_block_size
;
605 bool divisible_by_1000
;
606 bool divisible_by_1024
;
610 divisible_by_1000
= q1000
% 1000 == 0; q1000
/= 1000;
611 divisible_by_1024
= q1024
% 1024 == 0; q1024
/= 1024;
613 while (divisible_by_1000
& divisible_by_1024
);
615 if (divisible_by_1000
< divisible_by_1024
)
616 opts
|= human_base_1024
;
617 if (divisible_by_1024
< divisible_by_1000
)
618 opts
&= ~human_base_1024
;
619 if (! (opts
& human_base_1024
))
622 char *num
= human_readable (output_block_size
, buf
, opts
, 1, 1);
624 /* Reset the header back to the default in OUTPUT_MODE. */
625 header
= _("blocks");
627 /* TRANSLATORS: this is the "1K-blocks" header in "df" output. */
628 if (asprintf (&cell
, _("%s-%s"), num
, header
) == -1)
631 else if (header_mode
== POSIX_MODE
&& columns
[col
]->field
== SIZE_FIELD
)
633 char buf
[INT_BUFSIZE_BOUND (uintmax_t)];
634 char *num
= umaxtostr (output_block_size
, buf
);
636 /* TRANSLATORS: this is the "1024-blocks" header in "df -P". */
637 if (asprintf (&cell
, _("%s-%s"), num
, header
) == -1)
641 cell
= strdup (header
);
646 replace_problematic_chars (cell
);
648 table
[nrows
- 1][col
] = cell
;
650 size_t cell_width
= mbswidth (cell
, 0);
651 columns
[col
]->width
= MAX (columns
[col
]->width
, cell_width
);
655 /* Is FSTYPE a type of file system that should be listed? */
659 selected_fstype (char const *fstype
)
661 const struct fs_type_list
*fsp
;
663 if (fs_select_list
== NULL
|| fstype
== NULL
)
665 for (fsp
= fs_select_list
; fsp
; fsp
= fsp
->fs_next
)
666 if (STREQ (fstype
, fsp
->fs_name
))
671 /* Is FSTYPE a type of file system that should be omitted? */
675 excluded_fstype (char const *fstype
)
677 const struct fs_type_list
*fsp
;
679 if (fs_exclude_list
== NULL
|| fstype
== NULL
)
681 for (fsp
= fs_exclude_list
; fsp
; fsp
= fsp
->fs_next
)
682 if (STREQ (fstype
, fsp
->fs_name
))
688 devlist_hash (void const *x
, size_t table_size
)
690 struct devlist
const *p
= x
;
691 return (uintmax_t) p
->dev_num
% table_size
;
695 devlist_compare (void const *x
, void const *y
)
697 struct devlist
const *a
= x
;
698 struct devlist
const *b
= y
;
699 return a
->dev_num
== b
->dev_num
;
702 static struct devlist
*
703 devlist_for_dev (dev_t dev
)
705 if (devlist_table
== NULL
)
707 struct devlist dev_entry
;
708 dev_entry
.dev_num
= dev
;
710 struct devlist
*found
= hash_lookup (devlist_table
, &dev_entry
);
714 /* Return the last devlist entry we have seen with this dev_num */
715 return found
->seen_last
;
719 devlist_free (void *p
)
724 /* Filter mount list by skipping duplicate entries.
725 In the case of duplicates - based on the device number - the mount entry
726 with a '/' in its me_devname (i.e., not pseudo name like tmpfs) wins.
727 If both have a real devname (e.g. bind mounts), then that with the shorter
728 me_mountdir wins. With DEVICES_ONLY == true (set with df -a), only update
729 the global devlist_table, rather than filtering the global mount_list. */
732 filter_mount_list (bool devices_only
)
734 struct mount_entry
*me
;
736 /* Temporary list to keep entries ordered. */
737 struct devlist
*device_list
= NULL
;
738 int mount_list_size
= 0;
740 for (me
= mount_list
; me
; me
= me
->me_next
)
743 devlist_table
= hash_initialize (mount_list_size
, NULL
,
747 if (devlist_table
== NULL
)
750 /* Sort all 'wanted' entries into the list device_list. */
751 for (me
= mount_list
; me
;)
754 struct mount_entry
*discard_me
= NULL
;
756 /* Avoid stating remote file systems as that may hang.
757 On Linux we probably have me_dev populated from /proc/self/mountinfo,
758 however we still stat() in case another device was mounted later. */
759 if ((me
->me_remote
&& show_local_fs
)
760 || (me
->me_dummy
&& !show_all_fs
&& !show_listed_fs
)
761 || (!selected_fstype (me
->me_type
) || excluded_fstype (me
->me_type
))
762 || -1 == stat (me
->me_mountdir
, &buf
))
764 /* If remote, and showing just local, or FS type is excluded,
765 add ME for filtering later.
766 If stat failed; add ME to be able to complain about it later. */
767 buf
.st_dev
= me
->me_dev
;
771 /* If we've already seen this device... */
772 struct devlist
*seen_dev
= devlist_for_dev (buf
.st_dev
);
776 bool target_nearer_root
= strlen (seen_dev
->me
->me_mountdir
)
777 > strlen (me
->me_mountdir
);
778 /* With bind mounts, prefer items nearer the root of the source */
779 bool source_below_root
= seen_dev
->me
->me_mntroot
!= NULL
780 && me
->me_mntroot
!= NULL
781 && (strlen (seen_dev
->me
->me_mntroot
)
782 < strlen (me
->me_mntroot
));
783 if (! print_grand_total
784 && me
->me_remote
&& seen_dev
->me
->me_remote
785 && ! STREQ (seen_dev
->me
->me_devname
, me
->me_devname
))
787 /* Don't discard remote entries with different locations,
788 as these are more likely to be explicitly mounted.
789 However avoid this when producing a total to give
790 a more accurate value in that case. */
792 else if ((strchr (me
->me_devname
, '/')
793 /* let "real" devices with '/' in the name win. */
794 && ! strchr (seen_dev
->me
->me_devname
, '/'))
795 /* let points towards the root of the device win. */
796 || (target_nearer_root
&& ! source_below_root
)
797 /* let an entry overmounted on a new device win... */
798 || (! STREQ (seen_dev
->me
->me_devname
, me
->me_devname
)
799 /* ... but only when matching an existing mnt point,
800 to avoid problematic replacement when given
801 inaccurate mount lists, seen with some chroot
802 environments for example. */
803 && STREQ (me
->me_mountdir
,
804 seen_dev
->me
->me_mountdir
)))
806 /* Discard mount entry for existing device. */
807 discard_me
= seen_dev
->me
;
812 /* Discard mount entry currently being processed. */
823 free_mount_entry (discard_me
);
827 /* Add the device number to the device_table. */
828 struct devlist
*devlist
= xmalloc (sizeof *devlist
);
830 devlist
->dev_num
= buf
.st_dev
;
831 devlist
->next
= device_list
;
832 device_list
= devlist
;
834 struct devlist
*hash_entry
= hash_insert (devlist_table
, devlist
);
835 if (hash_entry
== NULL
)
837 /* Ensure lookups use this latest devlist. */
838 hash_entry
->seen_last
= devlist
;
844 /* Finally rebuild the mount_list from the devlist. */
845 if (! devices_only
) {
849 /* Add the mount entry. */
850 me
= device_list
->me
;
851 me
->me_next
= mount_list
;
853 device_list
= device_list
->next
;
856 hash_free (devlist_table
);
857 devlist_table
= NULL
;
862 /* Search a mount entry list for device id DEV.
863 Return the corresponding mount entry if found or NULL if not. */
866 static struct mount_entry
const *
867 me_for_dev (dev_t dev
)
869 struct devlist
*dl
= devlist_for_dev (dev
);
876 /* Return true if N is a known integer value. On many file systems,
877 UINTMAX_MAX represents an unknown value; on AIX, UINTMAX_MAX - 1
878 represents unknown. Use a rule that works on AIX file systems, and
879 that almost-always works on other types. */
881 known_value (uintmax_t n
)
883 return n
< UINTMAX_MAX
- 1;
886 /* Like human_readable (N, BUF, human_output_opts, INPUT_UNITS, OUTPUT_UNITS),
889 - If NEGATIVE, then N represents a negative number,
890 expressed in two's complement.
891 - Otherwise, return "-" if N is unknown. */
894 df_readable (bool negative
, uintmax_t n
, char *buf
,
895 uintmax_t input_units
, uintmax_t output_units
)
897 if (! known_value (n
) && !negative
)
901 char *p
= human_readable (negative
? -n
: n
, buf
+ negative
,
902 human_output_opts
, input_units
, output_units
);
909 /* Add integral value while using uintmax_t for value part and separate
910 negation flag. It adds value of SRC and SRC_NEG to DEST and DEST_NEG.
911 The result will be in DEST and DEST_NEG. See df_readable to understand
912 how the negation flag is used. */
914 add_uint_with_neg_flag (uintmax_t *dest
, bool *dest_neg
,
915 uintmax_t src
, bool src_neg
)
917 if (*dest_neg
== src_neg
)
941 /* Return true if S ends in a string that may be a 36-byte UUID,
942 i.e., of the form HHHHHHHH-HHHH-HHHH-HHHH-HHHHHHHHHHHH, where
943 each H is an upper or lower case hexadecimal digit. */
946 has_uuid_suffix (char const *s
)
948 size_t len
= strlen (s
);
950 && strspn (s
+ len
- 36, "-0123456789abcdefABCDEF") == 36);
953 /* Obtain the block values BV and inode values IV
954 from the file system usage FSU. */
956 get_field_values (struct field_values_t
*bv
,
957 struct field_values_t
*iv
,
958 const struct fs_usage
*fsu
)
961 iv
->input_units
= iv
->output_units
= 1;
962 iv
->total
= fsu
->fsu_files
;
963 iv
->available
= iv
->available_to_root
= fsu
->fsu_ffree
;
964 iv
->negate_available
= false;
966 iv
->used
= UINTMAX_MAX
;
967 iv
->negate_used
= false;
968 if (known_value (iv
->total
) && known_value (iv
->available_to_root
))
970 iv
->used
= iv
->total
- iv
->available_to_root
;
971 iv
->negate_used
= (iv
->total
< iv
->available_to_root
);
975 bv
->input_units
= fsu
->fsu_blocksize
;
976 bv
->output_units
= output_block_size
;
977 bv
->total
= fsu
->fsu_blocks
;
978 bv
->available
= fsu
->fsu_bavail
;
979 bv
->available_to_root
= fsu
->fsu_bfree
;
980 bv
->negate_available
= (fsu
->fsu_bavail_top_bit_set
981 && known_value (fsu
->fsu_bavail
));
983 bv
->used
= UINTMAX_MAX
;
984 bv
->negate_used
= false;
985 if (known_value (bv
->total
) && known_value (bv
->available_to_root
))
987 bv
->used
= bv
->total
- bv
->available_to_root
;
988 bv
->negate_used
= (bv
->total
< bv
->available_to_root
);
992 /* Add block and inode values to grand total. */
994 add_to_grand_total (struct field_values_t
*bv
, struct field_values_t
*iv
)
996 if (known_value (iv
->total
))
997 grand_fsu
.fsu_files
+= iv
->total
;
998 if (known_value (iv
->available
))
999 grand_fsu
.fsu_ffree
+= iv
->available
;
1001 if (known_value (bv
->total
))
1002 grand_fsu
.fsu_blocks
+= bv
->input_units
* bv
->total
;
1003 if (known_value (bv
->available_to_root
))
1004 grand_fsu
.fsu_bfree
+= bv
->input_units
* bv
->available_to_root
;
1005 if (known_value (bv
->available
))
1006 add_uint_with_neg_flag (&grand_fsu
.fsu_bavail
,
1007 &grand_fsu
.fsu_bavail_top_bit_set
,
1008 bv
->input_units
* bv
->available
,
1009 bv
->negate_available
);
1012 /* Obtain a space listing for the device with absolute file name DEVICE.
1013 If MOUNT_POINT is non-NULL, it is the name of the root of the
1014 file system on DEVICE.
1015 If STAT_FILE is non-null, it is the name of a file within the file
1016 system that the user originally asked for; this provides better
1017 diagnostics, and sometimes it provides better results on networked
1018 file systems that give different free-space results depending on
1019 where in the file system you probe.
1020 If FSTYPE is non-NULL, it is the type of the file system on DEVICE.
1021 If MOUNT_POINT is non-NULL, then DEVICE may be NULL -- certain systems may
1022 not be able to produce statistics in this case.
1023 ME_DUMMY and ME_REMOTE are the mount entry flags.
1024 Caller must set PROCESS_ALL to true when iterating over all entries, as
1025 when df is invoked with no non-option argument. See below for details. */
1028 get_dev (char const *device
, char const *mount_point
, char const *file
,
1029 char const *stat_file
, char const *fstype
,
1030 bool me_dummy
, bool me_remote
,
1031 const struct fs_usage
*force_fsu
,
1034 if (me_remote
&& show_local_fs
)
1037 if (me_dummy
&& !show_all_fs
&& !show_listed_fs
)
1040 if (!selected_fstype (fstype
) || excluded_fstype (fstype
))
1043 /* Ignore relative MOUNT_POINTs, which are present for example
1044 in /proc/mounts on Linux with network namespaces. */
1045 if (!force_fsu
&& mount_point
&& ! IS_ABSOLUTE_FILE_NAME (mount_point
))
1048 /* If MOUNT_POINT is NULL, then the file system is not mounted, and this
1049 program reports on the file system that the special file is on.
1050 It would be better to report on the unmounted file system,
1051 but statfs doesn't do that on most systems. */
1053 stat_file
= mount_point
? mount_point
: device
;
1055 struct fs_usage fsu
;
1058 else if (get_fs_usage (stat_file
, device
, &fsu
))
1060 /* If we can't access a system provided entry due
1061 to it not being present (now), or due to permissions,
1062 just output placeholder values rather than failing. */
1063 if (process_all
&& (errno
== EACCES
|| errno
== ENOENT
))
1069 fsu
.fsu_bavail_top_bit_set
= false;
1070 fsu
.fsu_blocksize
= fsu
.fsu_blocks
= fsu
.fsu_bfree
=
1071 fsu
.fsu_bavail
= fsu
.fsu_files
= fsu
.fsu_ffree
= UINTMAX_MAX
;
1075 error (0, errno
, "%s", quotef (stat_file
));
1076 exit_status
= EXIT_FAILURE
;
1080 else if (process_all
&& show_all_fs
)
1082 /* Ensure we don't output incorrect stats for over-mounted directories.
1083 Discard stats when the device name doesn't match. Though don't
1084 discard when used and current mount entries are both remote due
1085 to the possibility of aliased host names or exports. */
1087 if (stat (stat_file
, &sb
) == 0)
1089 struct mount_entry
const * dev_me
= me_for_dev (sb
.st_dev
);
1090 if (dev_me
&& ! STREQ (dev_me
->me_devname
, device
)
1091 && (! dev_me
->me_remote
|| ! me_remote
))
1094 fsu
.fsu_bavail_top_bit_set
= false;
1095 fsu
.fsu_blocksize
= fsu
.fsu_blocks
= fsu
.fsu_bfree
=
1096 fsu
.fsu_bavail
= fsu
.fsu_files
= fsu
.fsu_ffree
= UINTMAX_MAX
;
1101 if (fsu
.fsu_blocks
== 0 && !show_all_fs
&& !show_listed_fs
)
1105 file_systems_processed
= true;
1110 device
= "-"; /* unknown */
1113 file
= "-"; /* unspecified */
1115 char *dev_name
= xstrdup (device
);
1118 /* On some systems, dev_name is a long-named symlink like
1119 /dev/disk/by-uuid/828fc648-9f30-43d8-a0b1-f7196a2edb66 pointing to a
1120 much shorter and more useful name like /dev/sda1. It may also look
1121 like /dev/mapper/luks-828fc648-9f30-43d8-a0b1-f7196a2edb66 and point to
1122 /dev/dm-0. When process_all is true and dev_name is a symlink whose
1123 name ends with a UUID use the resolved name instead. */
1125 && has_uuid_suffix (dev_name
)
1126 && (resolved_dev
= canonicalize_filename_mode (dev_name
, CAN_EXISTING
)))
1129 dev_name
= resolved_dev
;
1133 fstype
= "-"; /* unknown */
1135 struct field_values_t block_values
;
1136 struct field_values_t inode_values
;
1137 get_field_values (&block_values
, &inode_values
, &fsu
);
1139 /* Add to grand total unless processing grand total line. */
1140 if (print_grand_total
&& ! force_fsu
)
1141 add_to_grand_total (&block_values
, &inode_values
);
1144 for (col
= 0; col
< ncolumns
; col
++)
1146 char buf
[LONGEST_HUMAN_READABLE
+ 2];
1149 struct field_values_t
*v
;
1150 switch (columns
[col
]->field_type
)
1162 v
= NULL
; /* Avoid warnings where assert() is not __noreturn__. */
1163 assert (!"bad field_type");
1166 switch (columns
[col
]->field
)
1169 cell
= xstrdup (dev_name
);
1173 cell
= xstrdup (fstype
);
1178 cell
= xstrdup (df_readable (false, v
->total
, buf
,
1179 v
->input_units
, v
->output_units
));
1184 cell
= xstrdup (df_readable (v
->negate_used
, v
->used
, buf
,
1185 v
->input_units
, v
->output_units
));
1190 cell
= xstrdup (df_readable (v
->negate_available
, v
->available
, buf
,
1191 v
->input_units
, v
->output_units
));
1198 if (! known_value (v
->used
) || ! known_value (v
->available
))
1200 else if (!v
->negate_used
1201 && v
->used
<= TYPE_MAXIMUM (uintmax_t) / 100
1202 && v
->used
+ v
->available
!= 0
1203 && (v
->used
+ v
->available
< v
->used
)
1204 == v
->negate_available
)
1206 uintmax_t u100
= v
->used
* 100;
1207 uintmax_t nonroot_total
= v
->used
+ v
->available
;
1208 pct
= u100
/ nonroot_total
+ (u100
% nonroot_total
!= 0);
1212 /* The calculation cannot be done easily with integer
1213 arithmetic. Fall back on floating point. This can suffer
1214 from minor rounding errors, but doing it exactly requires
1215 multiple precision arithmetic, and it's not worth the
1217 double u
= v
->negate_used
? - (double) - v
->used
: v
->used
;
1218 double a
= v
->negate_available
1219 ? - (double) - v
->available
: v
->available
;
1220 double nonroot_total
= u
+ a
;
1223 long int lipct
= pct
= u
* 100 / nonroot_total
;
1224 double ipct
= lipct
;
1226 /* Like 'pct = ceil (dpct);', but avoid ceil so that
1227 the math library needn't be linked. */
1228 if (ipct
- 1 < pct
&& pct
<= ipct
+ 1)
1229 pct
= ipct
+ (ipct
< pct
);
1235 if (asprintf (&cell
, "%.0f%%", pct
) == -1)
1239 cell
= strdup ("-");
1248 cell
= xstrdup (file
);
1252 #ifdef HIDE_AUTOMOUNT_PREFIX
1253 /* Don't print the first directory name in MOUNT_POINT if it's an
1254 artifact of an automounter. This is a bit too aggressive to be
1256 if (STRNCMP_LIT (mount_point
, "/auto/") == 0)
1258 else if (STRNCMP_LIT (mount_point
, "/tmp_mnt/") == 0)
1261 cell
= xstrdup (mount_point
);
1265 assert (!"unhandled field");
1269 assert (!"empty cell");
1271 replace_problematic_chars (cell
);
1272 size_t cell_width
= mbswidth (cell
, 0);
1273 columns
[col
]->width
= MAX (columns
[col
]->width
, cell_width
);
1274 table
[nrows
- 1][col
] = cell
;
1279 /* Scan the mount list returning the _last_ device found for MOUNT.
1280 NULL is returned if MOUNT not found. The result is malloced. */
1282 last_device_for_mount (char const *mount
)
1284 struct mount_entry
const *me
;
1285 struct mount_entry
const *le
= NULL
;
1287 for (me
= mount_list
; me
; me
= me
->me_next
)
1289 if (STREQ (me
->me_mountdir
, mount
))
1295 char *devname
= le
->me_devname
;
1296 char *canon_dev
= canonicalize_file_name (devname
);
1297 if (canon_dev
&& IS_ABSOLUTE_FILE_NAME (canon_dev
))
1300 return xstrdup (le
->me_devname
);
1306 /* If DEVICE corresponds to a mount point, show its usage
1307 and return true. Otherwise, return false. */
1309 get_device (char const *device
)
1311 struct mount_entry
const *me
;
1312 struct mount_entry
const *best_match
= NULL
;
1313 bool best_match_accessible
= false;
1314 bool eclipsed_device
= false;
1315 char const *file
= device
;
1317 char *resolved
= canonicalize_file_name (device
);
1318 if (resolved
&& IS_ABSOLUTE_FILE_NAME (resolved
))
1321 size_t best_match_len
= SIZE_MAX
;
1322 for (me
= mount_list
; me
; me
= me
->me_next
)
1324 /* TODO: Should cache canon_dev in the mount_entry struct. */
1325 char *devname
= me
->me_devname
;
1326 char *canon_dev
= canonicalize_file_name (me
->me_devname
);
1327 if (canon_dev
&& IS_ABSOLUTE_FILE_NAME (canon_dev
))
1328 devname
= canon_dev
;
1330 if (STREQ (device
, devname
))
1332 char *last_device
= last_device_for_mount (me
->me_mountdir
);
1333 eclipsed_device
= last_device
&& ! STREQ (last_device
, devname
);
1334 size_t len
= strlen (me
->me_mountdir
);
1336 if (! eclipsed_device
1337 && (! best_match_accessible
|| len
< best_match_len
))
1339 struct stat device_stats
;
1340 bool this_match_accessible
= false;
1342 if (stat (me
->me_mountdir
, &device_stats
) == 0)
1343 best_match_accessible
= this_match_accessible
= true;
1345 if (this_match_accessible
1346 || (! best_match_accessible
&& len
< best_match_len
))
1349 if (len
== 1) /* Traditional root. */
1356 best_match_len
= len
;
1370 get_dev (best_match
->me_devname
, best_match
->me_mountdir
, file
, NULL
,
1371 best_match
->me_type
, best_match
->me_dummy
,
1372 best_match
->me_remote
, NULL
, false);
1375 else if (eclipsed_device
)
1377 error (0, 0, _("cannot access %s: over-mounted by another device"),
1379 exit_status
= EXIT_FAILURE
;
1386 /* Figure out which device file or directory POINT is mounted on
1387 and show its device usage.
1388 STATP must be the result of 'stat (POINT, STATP)'. */
1390 get_point (char const *point
, const struct stat
*statp
)
1392 struct stat device_stats
;
1393 struct mount_entry
*me
;
1394 struct mount_entry
const *best_match
= NULL
;
1396 /* Calculate the real absolute file name for POINT, and use that to find
1397 the mount point. This avoids statting unavailable mount points,
1398 which can hang df. */
1399 char *resolved
= canonicalize_file_name (point
);
1400 if (resolved
&& resolved
[0] == '/')
1402 size_t resolved_len
= strlen (resolved
);
1403 size_t best_match_len
= 0;
1405 for (me
= mount_list
; me
; me
= me
->me_next
)
1407 if (!STREQ (me
->me_type
, "lofs")
1408 && (!best_match
|| best_match
->me_dummy
|| !me
->me_dummy
))
1410 size_t len
= strlen (me
->me_mountdir
);
1411 if (best_match_len
<= len
&& len
<= resolved_len
1412 && (len
== 1 /* root file system */
1413 || ((len
== resolved_len
|| resolved
[len
] == '/')
1414 && STREQ_LEN (me
->me_mountdir
, resolved
, len
))))
1417 best_match_len
= len
;
1424 && (stat (best_match
->me_mountdir
, &device_stats
) != 0
1425 || device_stats
.st_dev
!= statp
->st_dev
))
1429 for (me
= mount_list
; me
; me
= me
->me_next
)
1431 if (me
->me_dev
== (dev_t
) -1)
1433 if (stat (me
->me_mountdir
, &device_stats
) == 0)
1434 me
->me_dev
= device_stats
.st_dev
;
1437 /* Report only I/O errors. Other errors might be
1438 caused by shadowed mount points, which means POINT
1439 can't possibly be on this file system. */
1442 error (0, errno
, "%s", quotef (me
->me_mountdir
));
1443 exit_status
= EXIT_FAILURE
;
1446 /* So we won't try and fail repeatedly. */
1447 me
->me_dev
= (dev_t
) -2;
1451 if (statp
->st_dev
== me
->me_dev
1452 && !STREQ (me
->me_type
, "lofs")
1453 && (!best_match
|| best_match
->me_dummy
|| !me
->me_dummy
))
1455 /* Skip bogus mtab entries. */
1456 if (stat (me
->me_mountdir
, &device_stats
) != 0
1457 || device_stats
.st_dev
!= me
->me_dev
)
1458 me
->me_dev
= (dev_t
) -2;
1465 get_dev (best_match
->me_devname
, best_match
->me_mountdir
, point
, point
,
1466 best_match
->me_type
, best_match
->me_dummy
, best_match
->me_remote
,
1470 /* We couldn't find the mount entry corresponding to POINT. Go ahead and
1471 print as much info as we can; methods that require the device to be
1472 present will fail at a later point. */
1474 /* Find the actual mount point. */
1475 char *mp
= find_mount_point (point
, statp
);
1478 get_dev (NULL
, mp
, point
, NULL
, NULL
, false, false, NULL
, false);
1484 /* Determine what kind of node NAME is and show the device usage
1485 for it. STATP is the results of 'stat' on NAME. */
1488 get_entry (char const *name
, struct stat
const *statp
)
1490 if ((S_ISBLK (statp
->st_mode
) || S_ISCHR (statp
->st_mode
))
1491 && get_device (name
))
1494 get_point (name
, statp
);
1497 /* Show all mounted file systems, except perhaps those that are of
1498 an unselected type or are empty. */
1501 get_all_entries (void)
1503 struct mount_entry
*me
;
1505 filter_mount_list (show_all_fs
);
1507 for (me
= mount_list
; me
; me
= me
->me_next
)
1508 get_dev (me
->me_devname
, me
->me_mountdir
, NULL
, NULL
, me
->me_type
,
1509 me
->me_dummy
, me
->me_remote
, NULL
, true);
1512 /* Add FSTYPE to the list of file system types to display. */
1515 add_fs_type (char const *fstype
)
1517 struct fs_type_list
*fsp
;
1519 fsp
= xmalloc (sizeof *fsp
);
1520 fsp
->fs_name
= (char *) fstype
;
1521 fsp
->fs_next
= fs_select_list
;
1522 fs_select_list
= fsp
;
1525 /* Add FSTYPE to the list of file system types to be omitted. */
1528 add_excluded_fs_type (char const *fstype
)
1530 struct fs_type_list
*fsp
;
1532 fsp
= xmalloc (sizeof *fsp
);
1533 fsp
->fs_name
= (char *) fstype
;
1534 fsp
->fs_next
= fs_exclude_list
;
1535 fs_exclude_list
= fsp
;
1541 if (status
!= EXIT_SUCCESS
)
1545 printf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name
);
1547 Show information about the file system on which each FILE resides,\n\
1548 or all file systems by default.\n\
1551 emit_mandatory_arg_note ();
1553 /* TRANSLATORS: The thousands and decimal separators are best
1554 adjusted to an appropriate default for your locale. */
1556 -a, --all include pseudo, duplicate, inaccessible file systems\n\
1557 -B, --block-size=SIZE scale sizes by SIZE before printing them; e.g.,\n\
1558 '-BM' prints sizes in units of 1,048,576 bytes;\n\
1559 see SIZE format below\n\
1560 -h, --human-readable print sizes in powers of 1024 (e.g., 1023M)\n\
1561 -H, --si print sizes in powers of 1000 (e.g., 1.1G)\n\
1564 -i, --inodes list inode information instead of block usage\n\
1565 -k like --block-size=1K\n\
1566 -l, --local limit listing to local file systems\n\
1567 --no-sync do not invoke sync before getting usage info (default)\
1571 --output[=FIELD_LIST] use the output format defined by FIELD_LIST,\n\
1572 or print all fields if FIELD_LIST is omitted.\n\
1573 -P, --portability use the POSIX output format\n\
1574 --sync invoke sync before getting usage info\n\
1577 --total elide all entries insignificant to available space,\n\
1578 and produce a grand total\n\
1581 -t, --type=TYPE limit listing to file systems of type TYPE\n\
1582 -T, --print-type print file system type\n\
1583 -x, --exclude-type=TYPE limit listing to file systems not of type TYPE\n\
1586 fputs (HELP_OPTION_DESCRIPTION
, stdout
);
1587 fputs (VERSION_OPTION_DESCRIPTION
, stdout
);
1588 emit_blocksize_note ("DF");
1591 FIELD_LIST is a comma-separated list of columns to be included. Valid\n\
1592 field names are: 'source', 'fstype', 'itotal', 'iused', 'iavail', 'ipcent',\n\
1593 'size', 'used', 'avail', 'pcent', 'file' and 'target' (see info page).\n\
1595 emit_ancillary_info (PROGRAM_NAME
);
1601 main (int argc
, char **argv
)
1603 struct stat
*stats
IF_LINT ( = 0);
1605 initialize_main (&argc
, &argv
);
1606 set_program_name (argv
[0]);
1607 setlocale (LC_ALL
, "");
1608 bindtextdomain (PACKAGE
, LOCALEDIR
);
1609 textdomain (PACKAGE
);
1611 atexit (close_stdout
);
1613 fs_select_list
= NULL
;
1614 fs_exclude_list
= NULL
;
1615 show_all_fs
= false;
1616 show_listed_fs
= false;
1617 human_output_opts
= -1;
1619 file_systems_processed
= false;
1620 exit_status
= EXIT_SUCCESS
;
1621 print_grand_total
= false;
1622 grand_fsu
.fsu_blocksize
= 1;
1624 /* If true, use the POSIX output format. */
1625 bool posix_format
= false;
1627 char const *msg_mut_excl
= _("options %s and %s are mutually exclusive");
1632 int c
= getopt_long (argc
, argv
, "aB:iF:hHklmPTt:vx:", long_options
,
1644 enum strtol_error e
= human_options (optarg
, &human_output_opts
,
1645 &output_block_size
);
1646 if (e
!= LONGINT_OK
)
1647 xstrtol_fatal (e
, oi
, c
, long_options
, optarg
);
1651 if (header_mode
== OUTPUT_MODE
)
1653 error (0, 0, msg_mut_excl
, "-i", "--output");
1654 usage (EXIT_FAILURE
);
1656 header_mode
= INODES_MODE
;
1659 human_output_opts
= human_autoscale
| human_SI
| human_base_1024
;
1660 output_block_size
= 1;
1663 human_output_opts
= human_autoscale
| human_SI
;
1664 output_block_size
= 1;
1667 human_output_opts
= 0;
1668 output_block_size
= 1024;
1671 show_local_fs
= true;
1673 case 'm': /* obsolescent, exists for BSD compatibility */
1674 human_output_opts
= 0;
1675 output_block_size
= 1024 * 1024;
1678 if (header_mode
== OUTPUT_MODE
)
1680 error (0, 0, msg_mut_excl
, "-T", "--output");
1681 usage (EXIT_FAILURE
);
1686 if (header_mode
== OUTPUT_MODE
)
1688 error (0, 0, msg_mut_excl
, "-P", "--output");
1689 usage (EXIT_FAILURE
);
1691 posix_format
= true;
1694 require_sync
= true;
1696 case NO_SYNC_OPTION
:
1697 require_sync
= false;
1701 /* Accept -F as a synonym for -t for compatibility with Solaris. */
1703 add_fs_type (optarg
);
1706 case 'v': /* For SysV compatibility. */
1710 add_excluded_fs_type (optarg
);
1714 if (header_mode
== INODES_MODE
)
1716 error (0, 0, msg_mut_excl
, "-i", "--output");
1717 usage (EXIT_FAILURE
);
1719 if (posix_format
&& header_mode
== DEFAULT_MODE
)
1721 error (0, 0, msg_mut_excl
, "-P", "--output");
1722 usage (EXIT_FAILURE
);
1726 error (0, 0, msg_mut_excl
, "-T", "--output");
1727 usage (EXIT_FAILURE
);
1729 header_mode
= OUTPUT_MODE
;
1731 decode_output_arg (optarg
);
1735 print_grand_total
= true;
1738 case_GETOPT_HELP_CHAR
;
1739 case_GETOPT_VERSION_CHAR (PROGRAM_NAME
, AUTHORS
);
1742 usage (EXIT_FAILURE
);
1746 if (human_output_opts
== -1)
1750 human_output_opts
= 0;
1751 output_block_size
= (getenv ("POSIXLY_CORRECT") ? 512 : 1024);
1754 human_options (getenv ("DF_BLOCK_SIZE"),
1755 &human_output_opts
, &output_block_size
);
1758 if (header_mode
== INODES_MODE
|| header_mode
== OUTPUT_MODE
)
1760 else if (human_output_opts
& human_autoscale
)
1761 header_mode
= HUMAN_MODE
;
1762 else if (posix_format
)
1763 header_mode
= POSIX_MODE
;
1765 /* Fail if the same file system type was both selected and excluded. */
1768 struct fs_type_list
*fs_incl
;
1769 for (fs_incl
= fs_select_list
; fs_incl
; fs_incl
= fs_incl
->fs_next
)
1771 struct fs_type_list
*fs_excl
;
1772 for (fs_excl
= fs_exclude_list
; fs_excl
; fs_excl
= fs_excl
->fs_next
)
1774 if (STREQ (fs_incl
->fs_name
, fs_excl
->fs_name
))
1777 _("file system type %s both selected and excluded"),
1778 quote (fs_incl
->fs_name
));
1785 return EXIT_FAILURE
;
1788 assume (0 < optind
);
1792 /* stat each of the given entries to make sure any corresponding
1793 partition is automounted. This must be done before reading the
1794 file system table. */
1795 stats
= xnmalloc (argc
- optind
, sizeof *stats
);
1796 for (int i
= optind
; i
< argc
; ++i
)
1798 int err
= automount_stat_err (argv
[i
], &stats
[i
- optind
]);
1801 error (0, err
, "%s", quotef (argv
[i
]));
1802 exit_status
= EXIT_FAILURE
;
1809 read_file_system_list ((fs_select_list
!= NULL
1810 || fs_exclude_list
!= NULL
1812 || field_data
[FSTYPE_FIELD
].used
1815 if (mount_list
== NULL
)
1817 /* Couldn't read the table of mounted file systems.
1818 Fail if df was invoked with no file name arguments,
1819 or when either of -a, -l, -t or -x is used with file name
1820 arguments. Otherwise, merely give a warning and proceed. */
1822 if ( ! (optind
< argc
)
1825 || fs_select_list
!= NULL
1826 || fs_exclude_list
!= NULL
))
1828 status
= EXIT_FAILURE
;
1830 char const *warning
= (status
== 0 ? _("Warning: ") : "");
1831 error (status
, errno
, "%s%s", warning
,
1832 _("cannot read table of mounted file systems"));
1843 /* Display explicitly requested empty file systems. */
1844 show_listed_fs
= true;
1846 for (int i
= optind
; i
< argc
; ++i
)
1848 get_entry (argv
[i
], &stats
[i
- optind
]);
1850 IF_LINT (free (stats
));
1855 if (file_systems_processed
)
1857 if (print_grand_total
)
1859 (field_data
[SOURCE_FIELD
].used
? "-" : "total"),
1860 NULL
, NULL
, NULL
, false, false, &grand_fsu
, false);
1866 /* Print the "no FS processed" diagnostic only if there was no preceding
1867 diagnostic, e.g., if all have been excluded. */
1868 if (exit_status
== EXIT_SUCCESS
)
1869 die (EXIT_FAILURE
, 0, _("no file systems processed"));
1872 IF_LINT (free (columns
));