1 /* df - summarize free file system space
2 Copyright (C) 1991-2024 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>
30 #include "canonicalize.h"
34 #include "mountlist.h"
36 #include "find-mount-point.h"
38 #include "xstrtol-error.h"
39 #include "xvasprintf.h"
41 /* The official name of this program (e.g., no 'g' prefix). */
42 #define PROGRAM_NAME "df"
45 proper_name_lite ("Torbjorn Granlund", "Torbj\303\266rn Granlund"), \
46 proper_name ("David MacKenzie"), \
47 proper_name ("Paul Eggert")
52 struct mount_entry
*me
;
54 struct devlist
*seen_last
; /* valid for hashed devlist entries only */
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 file systems. 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. */
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
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
;
136 } header_mode
= DEFAULT_MODE
;
138 /* Displayable fields. */
141 SOURCE_FIELD
, /* file system */
142 FSTYPE_FIELD
, /* FS type */
143 SIZE_FIELD
, /* FS size */
144 USED_FIELD
, /* FS size used */
145 AVAIL_FIELD
, /* FS size available */
146 PCENT_FIELD
, /* percent used */
147 ITOTAL_FIELD
, /* inode total */
148 IUSED_FIELD
, /* inodes used */
149 IAVAIL_FIELD
, /* inodes available */
150 IPCENT_FIELD
, /* inodes used in percent */
151 TARGET_FIELD
, /* mount point */
152 FILE_FIELD
, /* specified file name */
153 INVALID_FIELD
/* validation marker */
156 /* Flag if a field contains a block, an inode or another value. */
159 BLOCK_FLD
, /* Block values field */
160 INODE_FLD
, /* Inode values field */
161 OTHER_FLD
/* Neutral field, e.g. target */
164 /* Attributes of a display field. */
167 display_field_t field
;
169 field_type_t field_type
;
170 char const *caption
;/* nullptr means use default header of this field. */
171 int width
; /* Auto adjusted (up) widths used to align columns. */
172 bool align_right
; /* Whether to right-align columns, not left-align. */
176 /* Header strings, minimum width and alignment for the above fields. */
177 static struct field_data_t field_data
[] = {
178 [SOURCE_FIELD
] = { SOURCE_FIELD
,
179 "source", OTHER_FLD
, N_("Filesystem"), 14, false, false },
181 [FSTYPE_FIELD
] = { FSTYPE_FIELD
,
182 "fstype", OTHER_FLD
, N_("Type"), 4, false, false },
184 [SIZE_FIELD
] = { SIZE_FIELD
,
185 "size", BLOCK_FLD
, N_("blocks"), 5, true, false },
187 [USED_FIELD
] = { USED_FIELD
,
188 "used", BLOCK_FLD
, N_("Used"), 5, true, false },
190 [AVAIL_FIELD
] = { AVAIL_FIELD
,
191 "avail", BLOCK_FLD
, N_("Available"), 5, true, false },
193 [PCENT_FIELD
] = { PCENT_FIELD
,
194 "pcent", BLOCK_FLD
, N_("Use%"), 4, true, false },
196 [ITOTAL_FIELD
] = { ITOTAL_FIELD
,
197 "itotal", INODE_FLD
, N_("Inodes"), 5, true, false },
199 [IUSED_FIELD
] = { IUSED_FIELD
,
200 "iused", INODE_FLD
, N_("IUsed"), 5, true, false },
202 [IAVAIL_FIELD
] = { IAVAIL_FIELD
,
203 "iavail", INODE_FLD
, N_("IFree"), 5, true, false },
205 [IPCENT_FIELD
] = { IPCENT_FIELD
,
206 "ipcent", INODE_FLD
, N_("IUse%"), 4, true, false },
208 [TARGET_FIELD
] = { TARGET_FIELD
,
209 "target", OTHER_FLD
, N_("Mounted on"), 0, false, false },
211 [FILE_FIELD
] = { FILE_FIELD
,
212 "file", OTHER_FLD
, N_("File"), 0, false, false }
215 static char const *all_args_string
=
216 "source,fstype,itotal,iused,iavail,ipcent,size,"
217 "used,avail,pcent,file,target";
219 /* Storage for the definition of output columns. */
220 static struct field_data_t
**columns
;
222 /* The current and allocated number of output columns. */
223 static idx_t ncolumns
, ncolumns_alloc
;
226 struct field_values_t
228 uintmax_t input_units
;
229 uintmax_t output_units
;
232 bool negate_available
;
233 uintmax_t available_to_root
;
238 /* Storage for pointers for each string (cell of table). */
239 static char ***table
;
241 /* The current number of processed rows (including header),
242 and the number of slots allocated for rows. */
243 static idx_t nrows
, nrows_alloc
;
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. */
249 NO_SYNC_OPTION
= CHAR_MAX
+ 1,
255 static struct option
const long_options
[] =
257 {"all", no_argument
, nullptr, 'a'},
258 {"block-size", required_argument
, nullptr, 'B'},
259 {"inodes", no_argument
, nullptr, 'i'},
260 {"human-readable", no_argument
, nullptr, 'h'},
261 {"si", no_argument
, nullptr, 'H'},
262 {"local", no_argument
, nullptr, 'l'},
263 {"output", optional_argument
, nullptr, OUTPUT_OPTION
},
264 {"portability", no_argument
, nullptr, 'P'},
265 {"print-type", no_argument
, nullptr, 'T'},
266 {"sync", no_argument
, nullptr, SYNC_OPTION
},
267 {"no-sync", no_argument
, nullptr, NO_SYNC_OPTION
},
268 {"total", no_argument
, nullptr, TOTAL_OPTION
},
269 {"type", required_argument
, nullptr, 't'},
270 {"exclude-type", required_argument
, nullptr, 'x'},
271 {GETOPT_HELP_OPTION_DECL
},
272 {GETOPT_VERSION_OPTION_DECL
},
273 {nullptr, 0, nullptr, 0}
276 /* Stat FILE and put the results into *ST. Return 0 if successful, an
277 error number otherwise. Try to open FILE before statting, to
278 trigger automounts. */
281 automount_stat_err (char const *file
, struct stat
*st
)
283 int fd
= open (file
, O_RDONLY
| O_NOCTTY
| O_NONBLOCK
);
286 if (errno
== ENOENT
|| errno
== ENOTDIR
)
288 return stat (file
, st
) == 0 ? 0 : errno
;
292 int err
= fstat (fd
, st
) == 0 ? 0 : errno
;
298 enum { MBSWIDTH_FLAGS
= MBSW_REJECT_INVALID
| MBSW_REJECT_UNPRINTABLE
};
300 /* Replace problematic chars with '?'.
301 Since only control characters are currently considered,
302 this should work in all encodings. */
305 replace_control_chars (char *cell
)
316 /* Replace problematic chars with '?'. */
319 replace_invalid_chars (char *cell
)
321 char *srcend
= cell
+ strlen (cell
);
323 mbstate_t mbstate
; mbszero (&mbstate
);
326 for (char *src
= cell
; src
!= srcend
; src
+= n
)
329 size_t srcbytes
= srcend
- src
;
330 n
= mbrtoc32 (&wc
, src
, srcbytes
, &mbstate
);
331 bool ok
= n
<= srcbytes
;
334 ok
= !c32iscntrl (wc
);
340 memmove (dst
, src
, n
);
354 replace_problematic_chars (char *cell
)
356 static int tty_out
= -1;
358 tty_out
= isatty (STDOUT_FILENO
);
360 (tty_out
? replace_invalid_chars
: replace_control_chars
) (cell
) ;
364 /* Dynamically allocate a row of pointers in TABLE, which
365 can then be accessed with standard 2D array notation. */
368 alloc_table_row (void)
370 if (nrows
== nrows_alloc
)
371 table
= xpalloc (table
, &nrows_alloc
, 1, -1, sizeof *table
);
372 table
[nrows
++] = xinmalloc (ncolumns
, sizeof *table
[0]);
375 /* Output each cell in the table, accounting for the
376 alignment and max width of each column. */
381 for (idx_t row
= 0; row
< nrows
; row
++)
383 for (idx_t col
= 0; col
< ncolumns
; col
++)
385 char *cell
= table
[row
][col
];
387 /* Note the SOURCE_FIELD used to be displayed on it's own line
388 if (!posix_format && mbswidth (cell) > 20), but that
389 functionality was probably more problematic than helpful,
390 hence changed in commit v8.10-40-g99679ff. */
394 int width
= mbswidth (cell
, MBSWIDTH_FLAGS
);
395 int fill
= width
< 0 ? 0 : columns
[col
]->width
- width
;
396 if (columns
[col
]->align_right
)
397 for (; 0 < fill
; fill
--)
399 fputs (cell
, stdout
);
400 if (col
+ 1 < ncolumns
)
401 for (; 0 < fill
; fill
--)
408 /* Dynamically allocate a struct field_t in COLUMNS, which
409 can then be accessed with standard array notation. */
412 alloc_field (int f
, char const *c
)
414 if (ncolumns
== ncolumns_alloc
)
415 columns
= xpalloc (columns
, &ncolumns_alloc
, 1, -1, sizeof *columns
);
416 columns
[ncolumns
++] = &field_data
[f
];
418 field_data
[f
].caption
= c
;
420 affirm (!field_data
[f
].used
);
422 /* Mark field as used. */
423 field_data
[f
].used
= true;
427 /* Given a string, ARG, containing a comma-separated list of arguments
428 to the --output option, add the appropriate fields to columns. */
430 decode_output_arg (char const *arg
)
432 char *arg_writable
= xstrdup (arg
);
433 char *s
= arg_writable
;
436 /* find next comma */
437 char *comma
= strchr (s
, ',');
439 /* If we found a comma, put a NUL in its place and advance. */
444 display_field_t field
= INVALID_FIELD
;
445 for (idx_t i
= 0; i
< ARRAY_CARDINALITY (field_data
); i
++)
447 if (STREQ (field_data
[i
].arg
, s
))
453 if (field
== INVALID_FIELD
)
455 error (0, 0, _("option --output: field %s unknown"), quote (s
));
456 usage (EXIT_FAILURE
);
459 if (field_data
[field
].used
)
461 /* Prevent the fields from being used more than once. */
462 error (0, 0, _("option --output: field %s used more than once"),
463 quote (field_data
[field
].arg
));
464 usage (EXIT_FAILURE
);
479 alloc_field (field
, nullptr);
483 alloc_field (field
, N_("Size"));
487 alloc_field (field
, N_("Avail"));
491 affirm (!"invalid field");
500 /* Get the appropriate columns for the mode. */
502 get_field_list (void)
507 alloc_field (SOURCE_FIELD
, nullptr);
509 alloc_field (FSTYPE_FIELD
, nullptr);
510 alloc_field (SIZE_FIELD
, nullptr);
511 alloc_field (USED_FIELD
, nullptr);
512 alloc_field (AVAIL_FIELD
, nullptr);
513 alloc_field (PCENT_FIELD
, nullptr);
514 alloc_field (TARGET_FIELD
, nullptr);
518 alloc_field (SOURCE_FIELD
, nullptr);
520 alloc_field (FSTYPE_FIELD
, nullptr);
522 alloc_field (SIZE_FIELD
, N_("Size"));
523 alloc_field (USED_FIELD
, nullptr);
524 alloc_field (AVAIL_FIELD
, N_("Avail"));
525 alloc_field (PCENT_FIELD
, nullptr);
526 alloc_field (TARGET_FIELD
, nullptr);
530 alloc_field (SOURCE_FIELD
, nullptr);
532 alloc_field (FSTYPE_FIELD
, nullptr);
533 alloc_field (ITOTAL_FIELD
, nullptr);
534 alloc_field (IUSED_FIELD
, nullptr);
535 alloc_field (IAVAIL_FIELD
, nullptr);
536 alloc_field (IPCENT_FIELD
, nullptr);
537 alloc_field (TARGET_FIELD
, nullptr);
541 alloc_field (SOURCE_FIELD
, nullptr);
543 alloc_field (FSTYPE_FIELD
, nullptr);
544 alloc_field (SIZE_FIELD
, nullptr);
545 alloc_field (USED_FIELD
, nullptr);
546 alloc_field (AVAIL_FIELD
, nullptr);
547 alloc_field (PCENT_FIELD
, N_("Capacity"));
548 alloc_field (TARGET_FIELD
, nullptr);
554 /* Add all fields if --output was given without a field list. */
555 decode_output_arg (all_args_string
);
564 /* Obtain the appropriate header entries. */
571 for (idx_t col
= 0; col
< ncolumns
; col
++)
574 char const *header
= _(columns
[col
]->caption
);
576 if (columns
[col
]->field
== SIZE_FIELD
577 && (header_mode
== DEFAULT_MODE
578 || (header_mode
== OUTPUT_MODE
579 && !(human_output_opts
& human_autoscale
))))
581 char buf
[LONGEST_HUMAN_READABLE
+ 1];
583 int opts
= (human_suppress_point_zero
584 | human_autoscale
| human_SI
586 & (human_group_digits
| human_base_1024
| human_B
)));
588 /* Prefer the base that makes the human-readable value more exact,
589 if there is a difference. */
591 uintmax_t q1000
= output_block_size
;
592 uintmax_t q1024
= output_block_size
;
593 bool divisible_by_1000
;
594 bool divisible_by_1024
;
598 divisible_by_1000
= q1000
% 1000 == 0; q1000
/= 1000;
599 divisible_by_1024
= q1024
% 1024 == 0; q1024
/= 1024;
601 while (divisible_by_1000
& divisible_by_1024
);
603 if (divisible_by_1000
< divisible_by_1024
)
604 opts
|= human_base_1024
;
605 if (divisible_by_1024
< divisible_by_1000
)
606 opts
&= ~human_base_1024
;
607 if (! (opts
& human_base_1024
))
610 char *num
= human_readable (output_block_size
, buf
, opts
, 1, 1);
612 /* Reset the header back to the default in OUTPUT_MODE. */
613 header
= _("blocks");
615 /* TRANSLATORS: this is the "1K-blocks" header in "df" output. */
616 cell
= xasprintf (_("%s-%s"), num
, header
);
618 else if (header_mode
== POSIX_MODE
&& columns
[col
]->field
== SIZE_FIELD
)
620 char buf
[INT_BUFSIZE_BOUND (uintmax_t)];
621 char *num
= umaxtostr (output_block_size
, buf
);
623 /* TRANSLATORS: this is the "1024-blocks" header in "df -P". */
624 cell
= xasprintf (_("%s-%s"), num
, header
);
627 cell
= xstrdup (header
);
629 replace_problematic_chars (cell
);
631 table
[nrows
- 1][col
] = cell
;
633 int cell_width
= mbswidth (cell
, MBSWIDTH_FLAGS
);
634 columns
[col
]->width
= MAX (columns
[col
]->width
, cell_width
);
638 /* Is FSTYPE a type of file system that should be listed? */
642 selected_fstype (char const *fstype
)
644 const struct fs_type_list
*fsp
;
646 if (fs_select_list
== nullptr || fstype
== nullptr)
648 for (fsp
= fs_select_list
; fsp
; fsp
= fsp
->fs_next
)
649 if (STREQ (fstype
, fsp
->fs_name
))
654 /* Is FSTYPE a type of file system that should be omitted? */
658 excluded_fstype (char const *fstype
)
660 const struct fs_type_list
*fsp
;
662 if (fs_exclude_list
== nullptr || fstype
== nullptr)
664 for (fsp
= fs_exclude_list
; fsp
; fsp
= fsp
->fs_next
)
665 if (STREQ (fstype
, fsp
->fs_name
))
671 devlist_hash (void const *x
, size_t table_size
)
673 struct devlist
const *p
= x
;
674 return (uintmax_t) p
->dev_num
% table_size
;
678 devlist_compare (void const *x
, void const *y
)
680 struct devlist
const *a
= x
;
681 struct devlist
const *b
= y
;
682 return a
->dev_num
== b
->dev_num
;
685 static struct devlist
*
686 devlist_for_dev (dev_t dev
)
688 if (devlist_table
== nullptr)
690 struct devlist dev_entry
;
691 dev_entry
.dev_num
= dev
;
693 struct devlist
*found
= hash_lookup (devlist_table
, &dev_entry
);
694 if (found
== nullptr)
697 /* Return the last devlist entry we have seen with this dev_num */
698 return found
->seen_last
;
701 /* Filter mount list by skipping duplicate entries.
702 In the case of duplicates - based on the device number - the mount entry
703 with a '/' in its me_devname (i.e., not pseudo name like tmpfs) wins.
704 If both have a real devname (e.g. bind mounts), then that with the shorter
705 me_mountdir wins. With DEVICES_ONLY == true (set with df -a), only update
706 the global devlist_table, rather than filtering the global mount_list. */
709 filter_mount_list (bool devices_only
)
711 struct mount_entry
*me
;
713 /* Temporary list to keep entries ordered. */
714 struct devlist
*device_list
= nullptr;
715 int mount_list_size
= 0;
717 for (me
= mount_list
; me
; me
= me
->me_next
)
720 devlist_table
= hash_initialize (mount_list_size
, nullptr,
721 devlist_hash
, devlist_compare
, nullptr);
722 if (devlist_table
== nullptr)
725 /* Sort all 'wanted' entries into the list device_list. */
726 for (me
= mount_list
; me
;)
729 struct mount_entry
*discard_me
= nullptr;
731 /* Avoid stating remote file systems as that may hang.
732 On Linux we probably have me_dev populated from /proc/self/mountinfo,
733 however we still stat() in case another device was mounted later. */
734 if ((me
->me_remote
&& show_local_fs
)
735 || (me
->me_dummy
&& !show_all_fs
&& !show_listed_fs
)
736 || (!selected_fstype (me
->me_type
) || excluded_fstype (me
->me_type
))
737 || -1 == stat (me
->me_mountdir
, &buf
))
739 /* If remote, and showing just local, or FS type is excluded,
740 add ME for filtering later.
741 If stat failed; add ME to be able to complain about it later. */
742 buf
.st_dev
= me
->me_dev
;
746 /* If we've already seen this device... */
747 struct devlist
*seen_dev
= devlist_for_dev (buf
.st_dev
);
751 bool target_nearer_root
= strlen (seen_dev
->me
->me_mountdir
)
752 > strlen (me
->me_mountdir
);
753 /* With bind mounts, prefer items nearer the root of the source */
754 bool source_below_root
= seen_dev
->me
->me_mntroot
!= nullptr
755 && me
->me_mntroot
!= nullptr
756 && (strlen (seen_dev
->me
->me_mntroot
)
757 < strlen (me
->me_mntroot
));
758 if (! print_grand_total
759 && me
->me_remote
&& seen_dev
->me
->me_remote
760 && ! STREQ (seen_dev
->me
->me_devname
, me
->me_devname
))
762 /* Don't discard remote entries with different locations,
763 as these are more likely to be explicitly mounted.
764 However avoid this when producing a total to give
765 a more accurate value in that case. */
767 else if ((strchr (me
->me_devname
, '/')
768 /* let "real" devices with '/' in the name win. */
769 && ! strchr (seen_dev
->me
->me_devname
, '/'))
770 /* let points towards the root of the device win. */
771 || (target_nearer_root
&& ! source_below_root
)
772 /* let an entry overmounted on a new device win... */
773 || (! STREQ (seen_dev
->me
->me_devname
, me
->me_devname
)
774 /* ... but only when matching an existing mnt point,
775 to avoid problematic replacement when given
776 inaccurate mount lists, seen with some chroot
777 environments for example. */
778 && STREQ (me
->me_mountdir
,
779 seen_dev
->me
->me_mountdir
)))
781 /* Discard mount entry for existing device. */
782 discard_me
= seen_dev
->me
;
787 /* Discard mount entry currently being processed. */
798 free_mount_entry (discard_me
);
802 /* Add the device number to the device_table. */
803 struct devlist
*devlist
= xmalloc (sizeof *devlist
);
805 devlist
->dev_num
= buf
.st_dev
;
806 devlist
->next
= device_list
;
807 device_list
= devlist
;
809 struct devlist
*hash_entry
= hash_insert (devlist_table
, devlist
);
810 if (hash_entry
== nullptr)
812 /* Ensure lookups use this latest devlist. */
813 hash_entry
->seen_last
= devlist
;
819 /* Finally rebuild the mount_list from the devlist. */
820 if (! devices_only
) {
821 mount_list
= nullptr;
824 /* Add the mount entry. */
825 me
= device_list
->me
;
826 me
->me_next
= mount_list
;
828 struct devlist
*next
= device_list
->next
;
833 hash_free (devlist_table
);
834 devlist_table
= nullptr;
839 /* Search a mount entry list for device id DEV.
840 Return the corresponding mount entry if found or nullptr if not. */
843 static struct mount_entry
const *
844 me_for_dev (dev_t dev
)
846 struct devlist
*dl
= devlist_for_dev (dev
);
853 /* Return true if N is a known integer value. On many file systems,
854 UINTMAX_MAX represents an unknown value; on AIX, UINTMAX_MAX - 1
855 represents unknown. Use a rule that works on AIX file systems, and
856 that almost-always works on other types. */
858 known_value (uintmax_t n
)
860 return n
< UINTMAX_MAX
- 1;
863 /* Like human_readable (N, BUF, human_output_opts, INPUT_UNITS, OUTPUT_UNITS),
866 - If NEGATIVE, then N represents a negative number,
867 expressed in two's complement.
868 - Otherwise, return "-" if N is unknown. */
871 df_readable (bool negative
, uintmax_t n
, char *buf
,
872 uintmax_t input_units
, uintmax_t output_units
)
874 if (! known_value (n
) && !negative
)
878 char *p
= human_readable (negative
? -n
: n
, buf
+ negative
,
879 human_output_opts
, input_units
, output_units
);
886 /* Add integral value while using uintmax_t for value part and separate
887 negation flag. It adds value of SRC and SRC_NEG to DEST and DEST_NEG.
888 The result will be in DEST and DEST_NEG. See df_readable to understand
889 how the negation flag is used. */
891 add_uint_with_neg_flag (uintmax_t *dest
, bool *dest_neg
,
892 uintmax_t src
, bool src_neg
)
894 if (*dest_neg
== src_neg
)
918 /* Return true if S ends in a string that may be a 36-byte UUID,
919 i.e., of the form HHHHHHHH-HHHH-HHHH-HHHH-HHHHHHHHHHHH, where
920 each H is an upper or lower case hexadecimal digit. */
923 has_uuid_suffix (char const *s
)
925 size_t len
= strlen (s
);
927 && strspn (s
+ len
- 36, "-0123456789abcdefABCDEF") == 36);
930 /* Obtain the block values BV and inode values IV
931 from the file system usage FSU. */
933 get_field_values (struct field_values_t
*bv
,
934 struct field_values_t
*iv
,
935 const struct fs_usage
*fsu
)
938 iv
->input_units
= iv
->output_units
= 1;
939 iv
->total
= fsu
->fsu_files
;
940 iv
->available
= iv
->available_to_root
= fsu
->fsu_ffree
;
941 iv
->negate_available
= false;
943 iv
->used
= UINTMAX_MAX
;
944 iv
->negate_used
= false;
945 if (known_value (iv
->total
) && known_value (iv
->available_to_root
))
947 iv
->used
= iv
->total
- iv
->available_to_root
;
948 iv
->negate_used
= (iv
->total
< iv
->available_to_root
);
952 bv
->input_units
= fsu
->fsu_blocksize
;
953 bv
->output_units
= output_block_size
;
954 bv
->total
= fsu
->fsu_blocks
;
955 bv
->available
= fsu
->fsu_bavail
;
956 bv
->available_to_root
= fsu
->fsu_bfree
;
957 bv
->negate_available
= (fsu
->fsu_bavail_top_bit_set
958 && known_value (fsu
->fsu_bavail
));
960 bv
->used
= UINTMAX_MAX
;
961 bv
->negate_used
= false;
962 if (known_value (bv
->total
) && known_value (bv
->available_to_root
))
964 bv
->used
= bv
->total
- bv
->available_to_root
;
965 bv
->negate_used
= (bv
->total
< bv
->available_to_root
);
969 /* Add block and inode values to grand total. */
971 add_to_grand_total (struct field_values_t
*bv
, struct field_values_t
*iv
)
973 if (known_value (iv
->total
))
974 grand_fsu
.fsu_files
+= iv
->total
;
975 if (known_value (iv
->available
))
976 grand_fsu
.fsu_ffree
+= iv
->available
;
978 if (known_value (bv
->total
))
979 grand_fsu
.fsu_blocks
+= bv
->input_units
* bv
->total
;
980 if (known_value (bv
->available_to_root
))
981 grand_fsu
.fsu_bfree
+= bv
->input_units
* bv
->available_to_root
;
982 if (known_value (bv
->available
))
983 add_uint_with_neg_flag (&grand_fsu
.fsu_bavail
,
984 &grand_fsu
.fsu_bavail_top_bit_set
,
985 bv
->input_units
* bv
->available
,
986 bv
->negate_available
);
989 /* Obtain a space listing for the device with absolute file name DEVICE.
990 If MOUNT_POINT is non-null, it is the name of the root of the
991 file system on DEVICE.
992 If STAT_FILE is non-null, it is the name of a file within the file
993 system that the user originally asked for; this provides better
994 diagnostics, and sometimes it provides better results on networked
995 file systems that give different free-space results depending on
996 where in the file system you probe.
997 If FSTYPE is non-null, it is the type of the file system on DEVICE.
998 If MOUNT_POINT is non-null, then DEVICE may be null -- certain systems may
999 not be able to produce statistics in this case.
1000 ME_DUMMY and ME_REMOTE are the mount entry flags.
1001 Caller must set PROCESS_ALL to true when iterating over all entries, as
1002 when df is invoked with no non-option argument. See below for details. */
1005 get_dev (char const *device
, char const *mount_point
, char const *file
,
1006 char const *stat_file
, char const *fstype
,
1007 bool me_dummy
, bool me_remote
,
1008 const struct fs_usage
*force_fsu
,
1011 if (me_remote
&& show_local_fs
)
1014 if (me_dummy
&& !show_all_fs
&& !show_listed_fs
)
1017 if (!selected_fstype (fstype
) || excluded_fstype (fstype
))
1020 /* Ignore relative MOUNT_POINTs, which are present for example
1021 in /proc/mounts on Linux with network namespaces. */
1022 if (!force_fsu
&& mount_point
&& ! IS_ABSOLUTE_FILE_NAME (mount_point
))
1025 /* If MOUNT_POINT is null, then the file system is not mounted, and this
1026 program reports on the file system that the special file is on.
1027 It would be better to report on the unmounted file system,
1028 but statfs doesn't do that on most systems. */
1030 stat_file
= mount_point
? mount_point
: device
;
1032 struct fs_usage fsu
;
1035 else if (get_fs_usage (stat_file
, device
, &fsu
))
1037 /* If we can't access a system provided entry due
1038 to it not being present (now), or due to permissions,
1039 just output placeholder values rather than failing. */
1040 if (process_all
&& (errno
== EACCES
|| errno
== ENOENT
))
1046 fsu
.fsu_bavail_top_bit_set
= false;
1047 fsu
.fsu_blocksize
= fsu
.fsu_blocks
= fsu
.fsu_bfree
=
1048 fsu
.fsu_bavail
= fsu
.fsu_files
= fsu
.fsu_ffree
= UINTMAX_MAX
;
1052 error (0, errno
, "%s", quotef (stat_file
));
1053 exit_status
= EXIT_FAILURE
;
1057 else if (process_all
&& show_all_fs
)
1059 /* Ensure we don't output incorrect stats for over-mounted directories.
1060 Discard stats when the device name doesn't match. Though don't
1061 discard when used and current mount entries are both remote due
1062 to the possibility of aliased host names or exports. */
1064 if (stat (stat_file
, &sb
) == 0)
1066 struct mount_entry
const * dev_me
= me_for_dev (sb
.st_dev
);
1067 if (dev_me
&& ! STREQ (dev_me
->me_devname
, device
)
1068 && (! dev_me
->me_remote
|| ! me_remote
))
1071 fsu
.fsu_bavail_top_bit_set
= false;
1072 fsu
.fsu_blocksize
= fsu
.fsu_blocks
= fsu
.fsu_bfree
=
1073 fsu
.fsu_bavail
= fsu
.fsu_files
= fsu
.fsu_ffree
= UINTMAX_MAX
;
1078 if (fsu
.fsu_blocks
== 0 && !show_all_fs
&& !show_listed_fs
)
1082 file_systems_processed
= true;
1087 device
= "-"; /* unknown */
1090 file
= "-"; /* unspecified */
1092 char *dev_name
= xstrdup (device
);
1095 /* On some systems, dev_name is a long-named symlink like
1096 /dev/disk/by-uuid/828fc648-9f30-43d8-a0b1-f7196a2edb66 pointing to a
1097 much shorter and more useful name like /dev/sda1. It may also look
1098 like /dev/mapper/luks-828fc648-9f30-43d8-a0b1-f7196a2edb66 and point to
1099 /dev/dm-0. When process_all is true and dev_name is a symlink whose
1100 name ends with a UUID use the resolved name instead. */
1102 && has_uuid_suffix (dev_name
)
1103 && (resolved_dev
= canonicalize_filename_mode (dev_name
, CAN_EXISTING
)))
1106 dev_name
= resolved_dev
;
1110 fstype
= "-"; /* unknown */
1112 struct field_values_t block_values
;
1113 struct field_values_t inode_values
;
1114 get_field_values (&block_values
, &inode_values
, &fsu
);
1116 /* Add to grand total unless processing grand total line. */
1117 if (print_grand_total
&& ! force_fsu
)
1118 add_to_grand_total (&block_values
, &inode_values
);
1120 for (idx_t col
= 0; col
< ncolumns
; col
++)
1122 char buf
[LONGEST_HUMAN_READABLE
+ 2];
1125 struct field_values_t
*v
;
1126 switch (columns
[col
]->field_type
)
1138 affirm (!"bad field_type");
1141 switch (columns
[col
]->field
)
1144 cell
= xstrdup (dev_name
);
1148 cell
= xstrdup (fstype
);
1153 cell
= xstrdup (df_readable (false, v
->total
, buf
,
1154 v
->input_units
, v
->output_units
));
1159 cell
= xstrdup (df_readable (v
->negate_used
, v
->used
, buf
,
1160 v
->input_units
, v
->output_units
));
1165 cell
= xstrdup (df_readable (v
->negate_available
, v
->available
, buf
,
1166 v
->input_units
, v
->output_units
));
1173 if (! known_value (v
->used
) || ! known_value (v
->available
))
1175 else if (!v
->negate_used
1176 && v
->used
<= TYPE_MAXIMUM (uintmax_t) / 100
1177 && v
->used
+ v
->available
!= 0
1178 && (v
->used
+ v
->available
< v
->used
)
1179 == v
->negate_available
)
1181 uintmax_t u100
= v
->used
* 100;
1182 uintmax_t nonroot_total
= v
->used
+ v
->available
;
1183 pct
= u100
/ nonroot_total
+ (u100
% nonroot_total
!= 0);
1187 /* The calculation cannot be done easily with integer
1188 arithmetic. Fall back on floating point. This can suffer
1189 from minor rounding errors, but doing it exactly requires
1190 multiple precision arithmetic, and it's not worth the
1192 double u
= v
->negate_used
? - (double) - v
->used
: v
->used
;
1193 double a
= v
->negate_available
1194 ? - (double) - v
->available
: v
->available
;
1195 double nonroot_total
= u
+ a
;
1198 long int lipct
= pct
= u
* 100 / nonroot_total
;
1199 double ipct
= lipct
;
1201 /* Like 'pct = ceil (dpct);', but avoid ceil so that
1202 the math library needn't be linked. */
1203 if (ipct
- 1 < pct
&& pct
<= ipct
+ 1)
1204 pct
= ipct
+ (ipct
< pct
);
1208 cell
= pct
< 0 ? xstrdup ("-") : xasprintf ("%.0f%%", pct
);
1213 cell
= xstrdup (file
);
1217 #ifdef HIDE_AUTOMOUNT_PREFIX
1218 /* Don't print the first directory name in MOUNT_POINT if it's an
1219 artifact of an automounter. This is a bit too aggressive to be
1221 if (STRNCMP_LIT (mount_point
, "/auto/") == 0)
1223 else if (STRNCMP_LIT (mount_point
, "/tmp_mnt/") == 0)
1226 cell
= xstrdup (mount_point
);
1230 affirm (!"unhandled field");
1235 replace_problematic_chars (cell
);
1236 int cell_width
= mbswidth (cell
, MBSWIDTH_FLAGS
);
1237 columns
[col
]->width
= MAX (columns
[col
]->width
, cell_width
);
1238 table
[nrows
- 1][col
] = cell
;
1243 /* Scan the mount list returning the _last_ device found for MOUNT.
1244 nullptr is returned if MOUNT not found. The result is malloced. */
1246 last_device_for_mount (char const *mount
)
1248 struct mount_entry
const *me
;
1249 struct mount_entry
const *le
= nullptr;
1251 for (me
= mount_list
; me
; me
= me
->me_next
)
1253 if (STREQ (me
->me_mountdir
, mount
))
1259 char *devname
= le
->me_devname
;
1260 char *canon_dev
= canonicalize_file_name (devname
);
1261 if (canon_dev
&& IS_ABSOLUTE_FILE_NAME (canon_dev
))
1264 return xstrdup (le
->me_devname
);
1270 /* If DEVICE corresponds to a mount point, show its usage
1271 and return true. Otherwise, return false. */
1273 get_device (char const *device
)
1275 struct mount_entry
const *me
;
1276 struct mount_entry
const *best_match
= nullptr;
1277 bool best_match_accessible
= false;
1278 bool eclipsed_device
= false;
1279 char const *file
= device
;
1281 char *resolved
= canonicalize_file_name (device
);
1282 if (resolved
&& IS_ABSOLUTE_FILE_NAME (resolved
))
1285 size_t best_match_len
= SIZE_MAX
;
1286 for (me
= mount_list
; me
; me
= me
->me_next
)
1288 /* TODO: Should cache canon_dev in the mount_entry struct. */
1289 char *devname
= me
->me_devname
;
1290 char *canon_dev
= canonicalize_file_name (me
->me_devname
);
1291 if (canon_dev
&& IS_ABSOLUTE_FILE_NAME (canon_dev
))
1292 devname
= canon_dev
;
1294 if (STREQ (device
, devname
))
1296 char *last_device
= last_device_for_mount (me
->me_mountdir
);
1297 eclipsed_device
= last_device
&& ! STREQ (last_device
, devname
);
1298 size_t len
= strlen (me
->me_mountdir
);
1300 if (! eclipsed_device
1301 && (! best_match_accessible
|| len
< best_match_len
))
1303 struct stat device_stats
;
1304 bool this_match_accessible
= false;
1306 if (stat (me
->me_mountdir
, &device_stats
) == 0)
1307 best_match_accessible
= this_match_accessible
= true;
1309 if (this_match_accessible
1310 || (! best_match_accessible
&& len
< best_match_len
))
1313 if (len
== 1) /* Traditional root. */
1320 best_match_len
= len
;
1334 get_dev (best_match
->me_devname
, best_match
->me_mountdir
, file
, nullptr,
1335 best_match
->me_type
, best_match
->me_dummy
,
1336 best_match
->me_remote
, nullptr, false);
1339 else if (eclipsed_device
)
1341 error (0, 0, _("cannot access %s: over-mounted by another device"),
1343 exit_status
= EXIT_FAILURE
;
1350 /* Figure out which device file or directory POINT is mounted on
1351 and show its device usage.
1352 STATP must be the result of 'stat (POINT, STATP)'. */
1354 get_point (char const *point
, const struct stat
*statp
)
1356 struct stat device_stats
;
1357 struct mount_entry
*me
;
1358 struct mount_entry
const *best_match
= nullptr;
1360 /* Calculate the real absolute file name for POINT, and use that to find
1361 the mount point. This avoids statting unavailable mount points,
1362 which can hang df. */
1363 char *resolved
= canonicalize_file_name (point
);
1364 if (resolved
&& resolved
[0] == '/')
1366 size_t resolved_len
= strlen (resolved
);
1367 size_t best_match_len
= 0;
1369 for (me
= mount_list
; me
; me
= me
->me_next
)
1371 if (!STREQ (me
->me_type
, "lofs")
1372 && (!best_match
|| best_match
->me_dummy
|| !me
->me_dummy
))
1374 size_t len
= strlen (me
->me_mountdir
);
1375 if (best_match_len
<= len
&& len
<= resolved_len
1376 && (len
== 1 /* root file system */
1377 || ((len
== resolved_len
|| resolved
[len
] == '/')
1378 && STREQ_LEN (me
->me_mountdir
, resolved
, len
))))
1381 best_match_len
= len
;
1388 && (stat (best_match
->me_mountdir
, &device_stats
) != 0
1389 || device_stats
.st_dev
!= statp
->st_dev
))
1390 best_match
= nullptr;
1393 for (me
= mount_list
; me
; me
= me
->me_next
)
1395 if (me
->me_dev
== (dev_t
) -1)
1397 if (stat (me
->me_mountdir
, &device_stats
) == 0)
1398 me
->me_dev
= device_stats
.st_dev
;
1401 /* Report only I/O errors. Other errors might be
1402 caused by shadowed mount points, which means POINT
1403 can't possibly be on this file system. */
1406 error (0, errno
, "%s", quotef (me
->me_mountdir
));
1407 exit_status
= EXIT_FAILURE
;
1410 /* So we won't try and fail repeatedly. */
1411 me
->me_dev
= (dev_t
) -2;
1415 if (statp
->st_dev
== me
->me_dev
1416 && !STREQ (me
->me_type
, "lofs")
1417 && (!best_match
|| best_match
->me_dummy
|| !me
->me_dummy
))
1419 /* Skip bogus mtab entries. */
1420 if (stat (me
->me_mountdir
, &device_stats
) != 0
1421 || device_stats
.st_dev
!= me
->me_dev
)
1422 me
->me_dev
= (dev_t
) -2;
1429 get_dev (best_match
->me_devname
, best_match
->me_mountdir
, point
, point
,
1430 best_match
->me_type
, best_match
->me_dummy
, best_match
->me_remote
,
1434 /* We couldn't find the mount entry corresponding to POINT. Go ahead and
1435 print as much info as we can; methods that require the device to be
1436 present will fail at a later point. */
1438 /* Find the actual mount point. */
1439 char *mp
= find_mount_point (point
, statp
);
1442 get_dev (nullptr, mp
, point
, nullptr, nullptr,
1443 false, false, nullptr, false);
1449 /* Determine what kind of node NAME is and show the device usage
1450 for it. STATP is the results of 'stat' on NAME. */
1453 get_entry (char const *name
, struct stat
const *statp
)
1455 if ((S_ISBLK (statp
->st_mode
) || S_ISCHR (statp
->st_mode
))
1456 && get_device (name
))
1459 get_point (name
, statp
);
1462 /* Show all mounted file systems, except perhaps those that are of
1463 an unselected type or are empty. */
1466 get_all_entries (void)
1468 struct mount_entry
*me
;
1470 filter_mount_list (show_all_fs
);
1472 for (me
= mount_list
; me
; me
= me
->me_next
)
1473 get_dev (me
->me_devname
, me
->me_mountdir
, nullptr, nullptr, me
->me_type
,
1474 me
->me_dummy
, me
->me_remote
, nullptr, true);
1477 /* Add FSTYPE to the list of file system types to display. */
1480 add_fs_type (char const *fstype
)
1482 struct fs_type_list
*fsp
;
1484 fsp
= xmalloc (sizeof *fsp
);
1485 fsp
->fs_name
= (char *) fstype
;
1486 fsp
->fs_next
= fs_select_list
;
1487 fs_select_list
= fsp
;
1490 /* Add FSTYPE to the list of file system types to be omitted. */
1493 add_excluded_fs_type (char const *fstype
)
1495 struct fs_type_list
*fsp
;
1497 fsp
= xmalloc (sizeof *fsp
);
1498 fsp
->fs_name
= (char *) fstype
;
1499 fsp
->fs_next
= fs_exclude_list
;
1500 fs_exclude_list
= fsp
;
1506 if (status
!= EXIT_SUCCESS
)
1510 printf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name
);
1512 Show information about the file system on which each FILE resides,\n\
1513 or all file systems by default.\n\
1516 emit_mandatory_arg_note ();
1518 /* TRANSLATORS: The thousands and decimal separators are best
1519 adjusted to an appropriate default for your locale. */
1521 -a, --all include pseudo, duplicate, inaccessible file systems\n\
1522 -B, --block-size=SIZE scale sizes by SIZE before printing them; e.g.,\n\
1523 '-BM' prints sizes in units of 1,048,576 bytes;\n\
1524 see SIZE format below\n\
1525 -h, --human-readable print sizes in powers of 1024 (e.g., 1023M)\n\
1526 -H, --si print sizes in powers of 1000 (e.g., 1.1G)\n\
1529 -i, --inodes list inode information instead of block usage\n\
1530 -k like --block-size=1K\n\
1531 -l, --local limit listing to local file systems\n\
1532 --no-sync do not invoke sync before getting usage info (default)\
1536 --output[=FIELD_LIST] use the output format defined by FIELD_LIST,\n\
1537 or print all fields if FIELD_LIST is omitted\n\
1540 -P, --portability use the POSIX output format\n\
1543 --sync invoke sync before getting usage info\n\
1546 --total elide all entries insignificant to available space,\n\
1547 and produce a grand total\n\
1550 -t, --type=TYPE limit listing to file systems of type TYPE\n\
1551 -T, --print-type print file system type\n\
1552 -x, --exclude-type=TYPE limit listing to file systems not of type TYPE\n\
1555 fputs (HELP_OPTION_DESCRIPTION
, stdout
);
1556 fputs (VERSION_OPTION_DESCRIPTION
, stdout
);
1557 emit_blocksize_note ("DF");
1560 FIELD_LIST is a comma-separated list of columns to be included. Valid\n\
1561 field names are: 'source', 'fstype', 'itotal', 'iused', 'iavail', 'ipcent',\n\
1562 'size', 'used', 'avail', 'pcent', 'file' and 'target' (see info page).\n\
1564 emit_ancillary_info (PROGRAM_NAME
);
1570 main (int argc
, char **argv
)
1572 struct stat
*stats
= nullptr;
1574 initialize_main (&argc
, &argv
);
1575 set_program_name (argv
[0]);
1576 setlocale (LC_ALL
, "");
1577 bindtextdomain (PACKAGE
, LOCALEDIR
);
1578 textdomain (PACKAGE
);
1580 atexit (close_stdout
);
1582 fs_select_list
= nullptr;
1583 fs_exclude_list
= nullptr;
1584 show_all_fs
= false;
1585 show_listed_fs
= false;
1586 human_output_opts
= -1;
1588 file_systems_processed
= false;
1589 exit_status
= EXIT_SUCCESS
;
1590 print_grand_total
= false;
1591 grand_fsu
.fsu_blocksize
= 1;
1593 /* If true, use the POSIX output format. */
1594 bool posix_format
= false;
1596 char const *msg_mut_excl
= _("options %s and %s are mutually exclusive");
1601 int c
= getopt_long (argc
, argv
, "aB:iF:hHklmPTt:vx:", long_options
,
1613 enum strtol_error e
= human_options (optarg
, &human_output_opts
,
1614 &output_block_size
);
1615 if (e
!= LONGINT_OK
)
1616 xstrtol_fatal (e
, oi
, c
, long_options
, optarg
);
1620 if (header_mode
== OUTPUT_MODE
)
1622 error (0, 0, msg_mut_excl
, "-i", "--output");
1623 usage (EXIT_FAILURE
);
1625 header_mode
= INODES_MODE
;
1628 human_output_opts
= human_autoscale
| human_SI
| human_base_1024
;
1629 output_block_size
= 1;
1632 human_output_opts
= human_autoscale
| human_SI
;
1633 output_block_size
= 1;
1636 human_output_opts
= 0;
1637 output_block_size
= 1024;
1640 show_local_fs
= true;
1642 case 'm': /* obsolescent, exists for BSD compatibility */
1643 human_output_opts
= 0;
1644 output_block_size
= 1024 * 1024;
1647 if (header_mode
== OUTPUT_MODE
)
1649 error (0, 0, msg_mut_excl
, "-T", "--output");
1650 usage (EXIT_FAILURE
);
1655 if (header_mode
== OUTPUT_MODE
)
1657 error (0, 0, msg_mut_excl
, "-P", "--output");
1658 usage (EXIT_FAILURE
);
1660 posix_format
= true;
1663 require_sync
= true;
1665 case NO_SYNC_OPTION
:
1666 require_sync
= false;
1670 /* Accept -F as a synonym for -t for compatibility with Solaris. */
1672 add_fs_type (optarg
);
1675 case 'v': /* For SysV compatibility. */
1679 add_excluded_fs_type (optarg
);
1683 if (header_mode
== INODES_MODE
)
1685 error (0, 0, msg_mut_excl
, "-i", "--output");
1686 usage (EXIT_FAILURE
);
1688 if (posix_format
&& header_mode
== DEFAULT_MODE
)
1690 error (0, 0, msg_mut_excl
, "-P", "--output");
1691 usage (EXIT_FAILURE
);
1695 error (0, 0, msg_mut_excl
, "-T", "--output");
1696 usage (EXIT_FAILURE
);
1698 header_mode
= OUTPUT_MODE
;
1700 decode_output_arg (optarg
);
1704 print_grand_total
= true;
1707 case_GETOPT_HELP_CHAR
;
1708 case_GETOPT_VERSION_CHAR (PROGRAM_NAME
, AUTHORS
);
1711 usage (EXIT_FAILURE
);
1715 if (human_output_opts
== -1)
1719 human_output_opts
= 0;
1720 output_block_size
= (getenv ("POSIXLY_CORRECT") ? 512 : 1024);
1723 human_options (getenv ("DF_BLOCK_SIZE"),
1724 &human_output_opts
, &output_block_size
);
1727 if (header_mode
== INODES_MODE
|| header_mode
== OUTPUT_MODE
)
1729 else if (human_output_opts
& human_autoscale
)
1730 header_mode
= HUMAN_MODE
;
1731 else if (posix_format
)
1732 header_mode
= POSIX_MODE
;
1734 /* Fail if the same file system type was both selected and excluded. */
1737 struct fs_type_list
*fs_incl
;
1738 for (fs_incl
= fs_select_list
; fs_incl
; fs_incl
= fs_incl
->fs_next
)
1740 struct fs_type_list
*fs_excl
;
1741 for (fs_excl
= fs_exclude_list
; fs_excl
; fs_excl
= fs_excl
->fs_next
)
1743 if (STREQ (fs_incl
->fs_name
, fs_excl
->fs_name
))
1746 _("file system type %s both selected and excluded"),
1747 quote (fs_incl
->fs_name
));
1754 return EXIT_FAILURE
;
1759 /* stat each of the given entries to make sure any corresponding
1760 partition is automounted. This must be done before reading the
1761 file system table. */
1762 stats
= xnmalloc (argc
- optind
, sizeof *stats
);
1763 for (int i
= optind
; i
< argc
; ++i
)
1765 int err
= automount_stat_err (argv
[i
], &stats
[i
- optind
]);
1768 error (0, err
, "%s", quotef (argv
[i
]));
1769 exit_status
= EXIT_FAILURE
;
1776 read_file_system_list ((fs_select_list
!= nullptr
1777 || fs_exclude_list
!= nullptr
1779 || field_data
[FSTYPE_FIELD
].used
1782 if (mount_list
== nullptr)
1784 /* Couldn't read the table of mounted file systems.
1785 Fail if df was invoked with no file name arguments,
1786 or when either of -a, -l, -t or -x is used with file name
1787 arguments. Otherwise, merely give a warning and proceed. */
1789 if ( ! (optind
< argc
)
1792 || fs_select_list
!= nullptr
1793 || fs_exclude_list
!= nullptr))
1795 status
= EXIT_FAILURE
;
1797 char const *warning
= (status
== 0 ? _("Warning: ") : "");
1798 error (status
, errno
, "%s%s", warning
,
1799 _("cannot read table of mounted file systems"));
1810 /* Display explicitly requested empty file systems. */
1811 show_listed_fs
= true;
1813 for (int i
= optind
; i
< argc
; ++i
)
1815 get_entry (argv
[i
], &stats
[i
- optind
]);
1820 if (file_systems_processed
)
1822 if (print_grand_total
)
1824 (field_data
[SOURCE_FIELD
].used
? "-" : "total"),
1825 nullptr, nullptr, nullptr, false, false, &grand_fsu
, false);
1831 /* Print the "no FS processed" diagnostic only if there was no preceding
1832 diagnostic, e.g., if all have been excluded. */
1833 if (exit_status
== EXIT_SUCCESS
)
1834 error (EXIT_FAILURE
, 0, _("no file systems processed"));
1837 main_exit (exit_status
);