version 8.7
[coreutils.git] / src / df.c
blob749ce1a120654fb76d6a6f835146829ae1e9ceca
1 /* df - summarize free disk space
2 Copyright (C) 1991, 1995-2010 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 and --megabyte options added by lm@sgi.com.
19 --si and large file support added by eggert@twinsun.com. */
21 #include <config.h>
22 #include <stdio.h>
23 #include <sys/types.h>
24 #include <getopt.h>
26 #include "system.h"
27 #include "error.h"
28 #include "fsusage.h"
29 #include "human.h"
30 #include "mountlist.h"
31 #include "quote.h"
32 #include "find-mount-point.h"
34 /* The official name of this program (e.g., no `g' prefix). */
35 #define PROGRAM_NAME "df"
37 #define AUTHORS \
38 proper_name_utf8 ("Torbjorn Granlund", "Torbj\303\266rn Granlund"), \
39 proper_name ("David MacKenzie"), \
40 proper_name ("Paul Eggert")
42 /* If true, show inode information. */
43 static bool inode_format;
45 /* If true, show even file systems with zero size or
46 uninteresting types. */
47 static bool show_all_fs;
49 /* If true, show only local file systems. */
50 static bool show_local_fs;
52 /* If true, output data for each file system corresponding to a
53 command line argument -- even if it's a dummy (automounter) entry. */
54 static bool show_listed_fs;
56 /* Human-readable options for output. */
57 static int human_output_opts;
59 /* The units to use when printing sizes. */
60 static uintmax_t output_block_size;
62 /* If true, use the POSIX output format. */
63 static bool posix_format;
65 /* True if a file system has been processed for output. */
66 static bool file_systems_processed;
68 /* If true, invoke the `sync' system call before getting any usage data.
69 Using this option can make df very slow, especially with many or very
70 busy disks. Note that this may make a difference on some systems --
71 SunOS 4.1.3, for one. It is *not* necessary on GNU/Linux. */
72 static bool require_sync;
74 /* Desired exit status. */
75 static int exit_status;
77 /* A file system type to display. */
79 struct fs_type_list
81 char *fs_name;
82 struct fs_type_list *fs_next;
85 /* Linked list of file system types to display.
86 If `fs_select_list' is NULL, list all types.
87 This table is generated dynamically from command-line options,
88 rather than hardcoding into the program what it thinks are the
89 valid file system types; let the user specify any file system type
90 they want to, and if there are any file systems of that type, they
91 will be shown.
93 Some file system types:
94 4.2 4.3 ufs nfs swap ignore io vm efs dbg */
96 static struct fs_type_list *fs_select_list;
98 /* Linked list of file system types to omit.
99 If the list is empty, don't exclude any types. */
101 static struct fs_type_list *fs_exclude_list;
103 /* Linked list of mounted file systems. */
104 static struct mount_entry *mount_list;
106 /* If true, print file system type as well. */
107 static bool print_type;
109 /* If true, print a grand total at the end. */
110 static bool print_grand_total;
112 /* Grand total data. */
113 static struct fs_usage grand_fsu;
115 /* For long options that have no equivalent short option, use a
116 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
117 enum
119 NO_SYNC_OPTION = CHAR_MAX + 1,
120 SYNC_OPTION
123 static struct option const long_options[] =
125 {"all", no_argument, NULL, 'a'},
126 {"block-size", required_argument, NULL, 'B'},
127 {"inodes", no_argument, NULL, 'i'},
128 {"human-readable", no_argument, NULL, 'h'},
129 {"si", no_argument, NULL, 'H'},
130 {"local", no_argument, NULL, 'l'},
131 {"megabytes", no_argument, NULL, 'm'}, /* obsolescent */
132 {"portability", no_argument, NULL, 'P'},
133 {"print-type", no_argument, NULL, 'T'},
134 {"sync", no_argument, NULL, SYNC_OPTION},
135 {"no-sync", no_argument, NULL, NO_SYNC_OPTION},
136 {"total", no_argument, NULL, 'c'},
137 {"type", required_argument, NULL, 't'},
138 {"exclude-type", required_argument, NULL, 'x'},
139 {GETOPT_HELP_OPTION_DECL},
140 {GETOPT_VERSION_OPTION_DECL},
141 {NULL, 0, NULL, 0}
144 static void
145 print_header (void)
147 char buf[MAX (LONGEST_HUMAN_READABLE + 1, INT_BUFSIZE_BOUND (uintmax_t))];
149 if (print_type)
150 /* TRANSLATORS:
151 For best results (df header/column alignment), ensure that
152 your translation has the same length as the original. */
153 fputs (_("Filesystem Type"), stdout);
154 else
155 fputs (_("Filesystem "), stdout);
157 if (inode_format)
158 /* TRANSLATORS:
159 For best results (df header/column alignment), ensure that
160 your translation has the same length as the original.
161 Also, each column name translation should end at the same
162 column as the corresponding original. */
163 fputs (_(" Inodes IUsed IFree IUse%"), stdout);
164 else if (human_output_opts & human_autoscale)
166 if (human_output_opts & human_base_1024)
167 fputs (_(" Size Used Avail Use%"), stdout);
168 else
169 fputs (_(" Size Used Avail Use%"), stdout);
171 else if (posix_format)
172 printf (_(" %s-blocks Used Available Capacity"),
173 umaxtostr (output_block_size, buf));
174 else
176 int opts = (human_suppress_point_zero
177 | human_autoscale | human_SI
178 | (human_output_opts
179 & (human_group_digits | human_base_1024 | human_B)));
181 /* Prefer the base that makes the human-readable value more exact,
182 if there is a difference. */
184 uintmax_t q1000 = output_block_size;
185 uintmax_t q1024 = output_block_size;
186 bool divisible_by_1000;
187 bool divisible_by_1024;
191 divisible_by_1000 = q1000 % 1000 == 0; q1000 /= 1000;
192 divisible_by_1024 = q1024 % 1024 == 0; q1024 /= 1024;
194 while (divisible_by_1000 & divisible_by_1024);
196 if (divisible_by_1000 < divisible_by_1024)
197 opts |= human_base_1024;
198 if (divisible_by_1024 < divisible_by_1000)
199 opts &= ~human_base_1024;
200 if (! (opts & human_base_1024))
201 opts |= human_B;
203 printf (_(" %4s-blocks Used Available Use%%"),
204 human_readable (output_block_size, buf, opts, 1, 1));
207 fputs (_(" Mounted on\n"), stdout);
210 /* Is FSTYPE a type of file system that should be listed? */
212 static bool
213 selected_fstype (const char *fstype)
215 const struct fs_type_list *fsp;
217 if (fs_select_list == NULL || fstype == NULL)
218 return true;
219 for (fsp = fs_select_list; fsp; fsp = fsp->fs_next)
220 if (STREQ (fstype, fsp->fs_name))
221 return true;
222 return false;
225 /* Is FSTYPE a type of file system that should be omitted? */
227 static bool
228 excluded_fstype (const char *fstype)
230 const struct fs_type_list *fsp;
232 if (fs_exclude_list == NULL || fstype == NULL)
233 return false;
234 for (fsp = fs_exclude_list; fsp; fsp = fsp->fs_next)
235 if (STREQ (fstype, fsp->fs_name))
236 return true;
237 return false;
240 /* Return true if N is a known integer value. On many file systems,
241 UINTMAX_MAX represents an unknown value; on AIX, UINTMAX_MAX - 1
242 represents unknown. Use a rule that works on AIX file systems, and
243 that almost-always works on other types. */
244 static bool
245 known_value (uintmax_t n)
247 return n < UINTMAX_MAX - 1;
250 /* Like human_readable (N, BUF, human_output_opts, INPUT_UNITS, OUTPUT_UNITS),
251 except:
253 - If NEGATIVE, then N represents a negative number,
254 expressed in two's complement.
255 - Otherwise, return "-" if N is unknown. */
257 static char const *
258 df_readable (bool negative, uintmax_t n, char *buf,
259 uintmax_t input_units, uintmax_t output_units)
261 if (! known_value (n) && !negative)
262 return "-";
263 else
265 char *p = human_readable (negative ? -n : n, buf + negative,
266 human_output_opts, input_units, output_units);
267 if (negative)
268 *--p = '-';
269 return p;
273 /* Logical equivalence */
274 #define LOG_EQ(a, b) (!(a) == !(b))
276 /* Add integral value while using uintmax_t for value part and separate
277 negation flag. It adds value of SRC and SRC_NEG to DEST and DEST_NEG.
278 The result will be in DEST and DEST_NEG. See df_readable to understand
279 how the negation flag is used. */
280 static void
281 add_uint_with_neg_flag (uintmax_t *dest, bool *dest_neg,
282 uintmax_t src, bool src_neg)
284 if (LOG_EQ (*dest_neg, src_neg))
286 *dest += src;
287 return;
290 if (*dest_neg)
291 *dest = -*dest;
293 if (src_neg)
294 src = -src;
296 if (src < *dest)
297 *dest -= src;
298 else
300 *dest = src - *dest;
301 *dest_neg = src_neg;
304 if (*dest_neg)
305 *dest = -*dest;
308 /* Display a space listing for the disk device with absolute file name DISK.
309 If MOUNT_POINT is non-NULL, it is the name of the root of the
310 file system on DISK.
311 If STAT_FILE is non-null, it is the name of a file within the file
312 system that the user originally asked for; this provides better
313 diagnostics, and sometimes it provides better results on networked
314 file systems that give different free-space results depending on
315 where in the file system you probe.
316 If FSTYPE is non-NULL, it is the type of the file system on DISK.
317 If MOUNT_POINT is non-NULL, then DISK may be NULL -- certain systems may
318 not be able to produce statistics in this case.
319 ME_DUMMY and ME_REMOTE are the mount entry flags. */
321 static void
322 show_dev (char const *disk, char const *mount_point,
323 char const *stat_file, char const *fstype,
324 bool me_dummy, bool me_remote,
325 const struct fs_usage *force_fsu)
327 struct fs_usage fsu;
328 char buf[3][LONGEST_HUMAN_READABLE + 2];
329 int width;
330 int col1_adjustment = 0;
331 int use_width;
332 uintmax_t input_units;
333 uintmax_t output_units;
334 uintmax_t total;
335 uintmax_t available;
336 bool negate_available;
337 uintmax_t available_to_root;
338 uintmax_t used;
339 bool negate_used;
340 double pct = -1;
342 if (me_remote && show_local_fs)
343 return;
345 if (me_dummy && !show_all_fs && !show_listed_fs)
346 return;
348 if (!selected_fstype (fstype) || excluded_fstype (fstype))
349 return;
351 /* If MOUNT_POINT is NULL, then the file system is not mounted, and this
352 program reports on the file system that the special file is on.
353 It would be better to report on the unmounted file system,
354 but statfs doesn't do that on most systems. */
355 if (!stat_file)
356 stat_file = mount_point ? mount_point : disk;
358 if (force_fsu)
359 fsu = *force_fsu;
360 else if (get_fs_usage (stat_file, disk, &fsu))
362 error (0, errno, "%s", quote (stat_file));
363 exit_status = EXIT_FAILURE;
364 return;
367 if (fsu.fsu_blocks == 0 && !show_all_fs && !show_listed_fs)
368 return;
370 if (! file_systems_processed)
372 file_systems_processed = true;
373 print_header ();
376 if (! disk)
377 disk = "-"; /* unknown */
378 if (! fstype)
379 fstype = "-"; /* unknown */
381 /* df.c reserved 5 positions for fstype,
382 but that does not suffice for type iso9660 */
383 if (print_type)
385 size_t disk_name_len = strlen (disk);
386 size_t fstype_len = strlen (fstype);
387 if (disk_name_len + fstype_len < 18)
388 printf ("%s%*s ", disk, 18 - (int) disk_name_len, fstype);
389 else if (!posix_format)
390 printf ("%s\n%18s ", disk, fstype);
391 else
392 printf ("%s %s", disk, fstype);
394 else
396 if (strlen (disk) > 20 && !posix_format)
397 printf ("%s\n%20s", disk, "");
398 else
399 printf ("%-20s", disk);
402 if (inode_format)
404 width = 7;
405 use_width = 5;
406 input_units = output_units = 1;
407 total = fsu.fsu_files;
408 available = fsu.fsu_ffree;
409 negate_available = false;
410 available_to_root = available;
412 if (known_value (total))
413 grand_fsu.fsu_files += total;
414 if (known_value (available))
415 grand_fsu.fsu_ffree += available;
417 else
419 if (human_output_opts & human_autoscale)
420 width = 5 + ! (human_output_opts & human_base_1024);
421 else
423 width = 9;
424 if (posix_format)
426 uintmax_t b;
427 col1_adjustment = -3;
428 for (b = output_block_size; 9 < b; b /= 10)
429 col1_adjustment++;
432 use_width = ((posix_format
433 && ! (human_output_opts & human_autoscale))
434 ? 8 : 4);
435 input_units = fsu.fsu_blocksize;
436 output_units = output_block_size;
437 total = fsu.fsu_blocks;
438 available = fsu.fsu_bavail;
439 negate_available = (fsu.fsu_bavail_top_bit_set
440 && known_value (available));
441 available_to_root = fsu.fsu_bfree;
443 if (known_value (total))
444 grand_fsu.fsu_blocks += input_units * total;
445 if (known_value (available_to_root))
446 grand_fsu.fsu_bfree += input_units * available_to_root;
447 if (known_value (available))
448 add_uint_with_neg_flag (&grand_fsu.fsu_bavail,
449 &grand_fsu.fsu_bavail_top_bit_set,
450 input_units * available, negate_available);
453 used = UINTMAX_MAX;
454 negate_used = false;
455 if (known_value (total) && known_value (available_to_root))
457 used = total - available_to_root;
458 negate_used = (total < available_to_root);
461 printf (" %*s %*s %*s ",
462 width + col1_adjustment,
463 df_readable (false, total,
464 buf[0], input_units, output_units),
465 width, df_readable (negate_used, used,
466 buf[1], input_units, output_units),
467 width, df_readable (negate_available, available,
468 buf[2], input_units, output_units));
470 if (! known_value (used) || ! known_value (available))
472 else if (!negate_used
473 && used <= TYPE_MAXIMUM (uintmax_t) / 100
474 && used + available != 0
475 && (used + available < used) == negate_available)
477 uintmax_t u100 = used * 100;
478 uintmax_t nonroot_total = used + available;
479 pct = u100 / nonroot_total + (u100 % nonroot_total != 0);
481 else
483 /* The calculation cannot be done easily with integer
484 arithmetic. Fall back on floating point. This can suffer
485 from minor rounding errors, but doing it exactly requires
486 multiple precision arithmetic, and it's not worth the
487 aggravation. */
488 double u = negate_used ? - (double) - used : used;
489 double a = negate_available ? - (double) - available : available;
490 double nonroot_total = u + a;
491 if (nonroot_total)
493 long int lipct = pct = u * 100 / nonroot_total;
494 double ipct = lipct;
496 /* Like `pct = ceil (dpct);', but avoid ceil so that
497 the math library needn't be linked. */
498 if (ipct - 1 < pct && pct <= ipct + 1)
499 pct = ipct + (ipct < pct);
503 if (0 <= pct)
504 printf ("%*.0f%%", use_width - 1, pct);
505 else
506 printf ("%*s", use_width, "- ");
508 if (mount_point)
510 #ifdef HIDE_AUTOMOUNT_PREFIX
511 /* Don't print the first directory name in MOUNT_POINT if it's an
512 artifact of an automounter. This is a bit too aggressive to be
513 the default. */
514 if (strncmp ("/auto/", mount_point, 6) == 0)
515 mount_point += 5;
516 else if (strncmp ("/tmp_mnt/", mount_point, 9) == 0)
517 mount_point += 8;
518 #endif
519 printf (" %s", mount_point);
521 putchar ('\n');
524 /* If DISK corresponds to a mount point, show its usage
525 and return true. Otherwise, return false. */
526 static bool
527 show_disk (char const *disk)
529 struct mount_entry const *me;
530 struct mount_entry const *best_match = NULL;
532 for (me = mount_list; me; me = me->me_next)
533 if (STREQ (disk, me->me_devname))
534 best_match = me;
536 if (best_match)
538 show_dev (best_match->me_devname, best_match->me_mountdir, NULL,
539 best_match->me_type, best_match->me_dummy,
540 best_match->me_remote, NULL);
541 return true;
544 return false;
547 /* Figure out which device file or directory POINT is mounted on
548 and show its disk usage.
549 STATP must be the result of `stat (POINT, STATP)'. */
550 static void
551 show_point (const char *point, const struct stat *statp)
553 struct stat disk_stats;
554 struct mount_entry *me;
555 struct mount_entry const *best_match = NULL;
557 /* Calculate the real absolute file name for POINT, and use that to find
558 the mount point. This avoids statting unavailable mount points,
559 which can hang df. */
560 char *resolved = canonicalize_file_name (point);
561 if (resolved && resolved[0] == '/')
563 size_t resolved_len = strlen (resolved);
564 size_t best_match_len = 0;
566 for (me = mount_list; me; me = me->me_next)
567 if (!STREQ (me->me_type, "lofs")
568 && (!best_match || best_match->me_dummy || !me->me_dummy))
570 size_t len = strlen (me->me_mountdir);
571 if (best_match_len <= len && len <= resolved_len
572 && (len == 1 /* root file system */
573 || ((len == resolved_len || resolved[len] == '/')
574 && strncmp (me->me_mountdir, resolved, len) == 0)))
576 best_match = me;
577 best_match_len = len;
581 free (resolved);
582 if (best_match
583 && (stat (best_match->me_mountdir, &disk_stats) != 0
584 || disk_stats.st_dev != statp->st_dev))
585 best_match = NULL;
587 if (! best_match)
588 for (me = mount_list; me; me = me->me_next)
590 if (me->me_dev == (dev_t) -1)
592 if (stat (me->me_mountdir, &disk_stats) == 0)
593 me->me_dev = disk_stats.st_dev;
594 else
596 /* Report only I/O errors. Other errors might be
597 caused by shadowed mount points, which means POINT
598 can't possibly be on this file system. */
599 if (errno == EIO)
601 error (0, errno, "%s", quote (me->me_mountdir));
602 exit_status = EXIT_FAILURE;
605 /* So we won't try and fail repeatedly. */
606 me->me_dev = (dev_t) -2;
610 if (statp->st_dev == me->me_dev
611 && !STREQ (me->me_type, "lofs")
612 && (!best_match || best_match->me_dummy || !me->me_dummy))
614 /* Skip bogus mtab entries. */
615 if (stat (me->me_mountdir, &disk_stats) != 0
616 || disk_stats.st_dev != me->me_dev)
617 me->me_dev = (dev_t) -2;
618 else
619 best_match = me;
623 if (best_match)
624 show_dev (best_match->me_devname, best_match->me_mountdir, point,
625 best_match->me_type, best_match->me_dummy, best_match->me_remote,
626 NULL);
627 else
629 /* We couldn't find the mount entry corresponding to POINT. Go ahead and
630 print as much info as we can; methods that require the device to be
631 present will fail at a later point. */
633 /* Find the actual mount point. */
634 char *mp = find_mount_point (point, statp);
635 if (mp)
637 show_dev (NULL, mp, NULL, NULL, false, false, NULL);
638 free (mp);
643 /* Determine what kind of node NAME is and show the disk usage
644 for it. STATP is the results of `stat' on NAME. */
646 static void
647 show_entry (char const *name, struct stat const *statp)
649 if ((S_ISBLK (statp->st_mode) || S_ISCHR (statp->st_mode))
650 && show_disk (name))
651 return;
653 show_point (name, statp);
656 /* Show all mounted file systems, except perhaps those that are of
657 an unselected type or are empty. */
659 static void
660 show_all_entries (void)
662 struct mount_entry *me;
664 for (me = mount_list; me; me = me->me_next)
665 show_dev (me->me_devname, me->me_mountdir, NULL, me->me_type,
666 me->me_dummy, me->me_remote, NULL);
669 /* Add FSTYPE to the list of file system types to display. */
671 static void
672 add_fs_type (const char *fstype)
674 struct fs_type_list *fsp;
676 fsp = xmalloc (sizeof *fsp);
677 fsp->fs_name = (char *) fstype;
678 fsp->fs_next = fs_select_list;
679 fs_select_list = fsp;
682 /* Add FSTYPE to the list of file system types to be omitted. */
684 static void
685 add_excluded_fs_type (const char *fstype)
687 struct fs_type_list *fsp;
689 fsp = xmalloc (sizeof *fsp);
690 fsp->fs_name = (char *) fstype;
691 fsp->fs_next = fs_exclude_list;
692 fs_exclude_list = fsp;
695 void
696 usage (int status)
698 if (status != EXIT_SUCCESS)
699 fprintf (stderr, _("Try `%s --help' for more information.\n"),
700 program_name);
701 else
703 printf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name);
704 fputs (_("\
705 Show information about the file system on which each FILE resides,\n\
706 or all file systems by default.\n\
708 "), stdout);
709 fputs (_("\
710 Mandatory arguments to long options are mandatory for short options too.\n\
711 "), stdout);
712 fputs (_("\
713 -a, --all include dummy file systems\n\
714 -B, --block-size=SIZE scale sizes by SIZE before printing them. E.g.,\n\
715 `-BM' prints sizes in units of 1,048,576 bytes.\n\
716 See SIZE format below.\n\
717 --total produce a grand total\n\
718 -h, --human-readable print sizes in human readable format (e.g., 1K 234M 2G)\n\
719 -H, --si likewise, but use powers of 1000 not 1024\n\
720 "), stdout);
721 fputs (_("\
722 -i, --inodes list inode information instead of block usage\n\
723 -k like --block-size=1K\n\
724 -l, --local limit listing to local file systems\n\
725 --no-sync do not invoke sync before getting usage info (default)\n\
726 "), stdout);
727 fputs (_("\
728 -P, --portability use the POSIX output format\n\
729 --sync invoke sync before getting usage info\n\
730 -t, --type=TYPE limit listing to file systems of type TYPE\n\
731 -T, --print-type print file system type\n\
732 -x, --exclude-type=TYPE limit listing to file systems not of type TYPE\n\
733 -v (ignored)\n\
734 "), stdout);
735 fputs (HELP_OPTION_DESCRIPTION, stdout);
736 fputs (VERSION_OPTION_DESCRIPTION, stdout);
737 emit_blocksize_note ("DF");
738 emit_size_note ();
739 emit_ancillary_info ();
741 exit (status);
745 main (int argc, char **argv)
747 struct stat *stats IF_LINT ( = 0);
749 initialize_main (&argc, &argv);
750 set_program_name (argv[0]);
751 setlocale (LC_ALL, "");
752 bindtextdomain (PACKAGE, LOCALEDIR);
753 textdomain (PACKAGE);
755 atexit (close_stdout);
757 fs_select_list = NULL;
758 fs_exclude_list = NULL;
759 inode_format = false;
760 show_all_fs = false;
761 show_listed_fs = false;
762 human_output_opts = -1;
763 print_type = false;
764 file_systems_processed = false;
765 posix_format = false;
766 exit_status = EXIT_SUCCESS;
767 print_grand_total = false;
768 grand_fsu.fsu_blocksize = 1;
770 while (true)
772 int oi = -1;
773 int c = getopt_long (argc, argv, "aB:iF:hHklmPTt:vx:", long_options,
774 &oi);
775 if (c == -1)
776 break;
778 switch (c)
780 case 'a':
781 show_all_fs = true;
782 break;
783 case 'B':
785 enum strtol_error e = human_options (optarg, &human_output_opts,
786 &output_block_size);
787 if (e != LONGINT_OK)
788 xstrtol_fatal (e, oi, c, long_options, optarg);
790 break;
791 case 'i':
792 inode_format = true;
793 break;
794 case 'h':
795 human_output_opts = human_autoscale | human_SI | human_base_1024;
796 output_block_size = 1;
797 break;
798 case 'H':
799 human_output_opts = human_autoscale | human_SI;
800 output_block_size = 1;
801 break;
802 case 'k':
803 human_output_opts = 0;
804 output_block_size = 1024;
805 break;
806 case 'l':
807 show_local_fs = true;
808 break;
809 case 'm': /* obsolescent */
810 human_output_opts = 0;
811 output_block_size = 1024 * 1024;
812 break;
813 case 'T':
814 print_type = true;
815 break;
816 case 'P':
817 posix_format = true;
818 break;
819 case SYNC_OPTION:
820 require_sync = true;
821 break;
822 case NO_SYNC_OPTION:
823 require_sync = false;
824 break;
826 case 'F':
827 /* Accept -F as a synonym for -t for compatibility with Solaris. */
828 case 't':
829 add_fs_type (optarg);
830 break;
832 case 'v': /* For SysV compatibility. */
833 /* ignore */
834 break;
835 case 'x':
836 add_excluded_fs_type (optarg);
837 break;
839 case 'c':
840 print_grand_total = true;
841 break;
843 case_GETOPT_HELP_CHAR;
844 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
846 default:
847 usage (EXIT_FAILURE);
851 if (human_output_opts == -1)
853 if (posix_format)
855 human_output_opts = 0;
856 output_block_size = (getenv ("POSIXLY_CORRECT") ? 512 : 1024);
858 else
859 human_options (getenv ("DF_BLOCK_SIZE"),
860 &human_output_opts, &output_block_size);
863 /* Fail if the same file system type was both selected and excluded. */
865 bool match = false;
866 struct fs_type_list *fs_incl;
867 for (fs_incl = fs_select_list; fs_incl; fs_incl = fs_incl->fs_next)
869 struct fs_type_list *fs_excl;
870 for (fs_excl = fs_exclude_list; fs_excl; fs_excl = fs_excl->fs_next)
872 if (STREQ (fs_incl->fs_name, fs_excl->fs_name))
874 error (0, 0,
875 _("file system type %s both selected and excluded"),
876 quote (fs_incl->fs_name));
877 match = true;
878 break;
882 if (match)
883 exit (EXIT_FAILURE);
886 if (optind < argc)
888 int i;
890 /* Open each of the given entries to make sure any corresponding
891 partition is automounted. This must be done before reading the
892 file system table. */
893 stats = xnmalloc (argc - optind, sizeof *stats);
894 for (i = optind; i < argc; ++i)
896 /* Prefer to open with O_NOCTTY and use fstat, but fall back
897 on using "stat", in case the file is unreadable. */
898 int fd = open (argv[i], O_RDONLY | O_NOCTTY);
899 if ((fd < 0 || fstat (fd, &stats[i - optind]))
900 && stat (argv[i], &stats[i - optind]))
902 error (0, errno, "%s", quote (argv[i]));
903 exit_status = EXIT_FAILURE;
904 argv[i] = NULL;
906 if (0 <= fd)
907 close (fd);
911 mount_list =
912 read_file_system_list ((fs_select_list != NULL
913 || fs_exclude_list != NULL
914 || print_type
915 || show_local_fs));
917 if (mount_list == NULL)
919 /* Couldn't read the table of mounted file systems.
920 Fail if df was invoked with no file name arguments;
921 Otherwise, merely give a warning and proceed. */
922 int status = (optind < argc ? 0 : EXIT_FAILURE);
923 const char *warning = (optind < argc ? _("Warning: ") : "");
924 error (status, errno, "%s%s", warning,
925 _("cannot read table of mounted file systems"));
928 if (require_sync)
929 sync ();
931 if (optind < argc)
933 int i;
935 /* Display explicitly requested empty file systems. */
936 show_listed_fs = true;
938 for (i = optind; i < argc; ++i)
939 if (argv[i])
940 show_entry (argv[i], &stats[i - optind]);
942 else
943 show_all_entries ();
945 if (print_grand_total)
947 if (inode_format)
948 grand_fsu.fsu_blocks = 1;
949 show_dev ("total", NULL, NULL, NULL, false, false, &grand_fsu);
952 if (! file_systems_processed)
953 error (EXIT_FAILURE, 0, _("no file systems processed"));
955 exit (exit_status);