dd: add a flag to discard cached data
[coreutils/ericb.git] / src / df.c
blob4523c440f5f14f4933545841d54c68b525e97897
1 /* df - summarize free disk space
2 Copyright (C) 1991, 1995-2011 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)\
720 -H, --si likewise, but use powers of 1000 not 1024\n\
721 "), stdout);
722 fputs (_("\
723 -i, --inodes list inode information instead of block usage\n\
724 -k like --block-size=1K\n\
725 -l, --local limit listing to local file systems\n\
726 --no-sync do not invoke sync before getting usage info (default)\
728 "), stdout);
729 fputs (_("\
730 -P, --portability use the POSIX output format\n\
731 --sync invoke sync before getting usage info\n\
732 -t, --type=TYPE limit listing to file systems of type TYPE\n\
733 -T, --print-type print file system type\n\
734 -x, --exclude-type=TYPE limit listing to file systems not of type TYPE\n\
735 -v (ignored)\n\
736 "), stdout);
737 fputs (HELP_OPTION_DESCRIPTION, stdout);
738 fputs (VERSION_OPTION_DESCRIPTION, stdout);
739 emit_blocksize_note ("DF");
740 emit_size_note ();
741 emit_ancillary_info ();
743 exit (status);
747 main (int argc, char **argv)
749 struct stat *stats IF_LINT ( = 0);
751 initialize_main (&argc, &argv);
752 set_program_name (argv[0]);
753 setlocale (LC_ALL, "");
754 bindtextdomain (PACKAGE, LOCALEDIR);
755 textdomain (PACKAGE);
757 atexit (close_stdout);
759 fs_select_list = NULL;
760 fs_exclude_list = NULL;
761 inode_format = false;
762 show_all_fs = false;
763 show_listed_fs = false;
764 human_output_opts = -1;
765 print_type = false;
766 file_systems_processed = false;
767 posix_format = false;
768 exit_status = EXIT_SUCCESS;
769 print_grand_total = false;
770 grand_fsu.fsu_blocksize = 1;
772 while (true)
774 int oi = -1;
775 int c = getopt_long (argc, argv, "aB:iF:hHklmPTt:vx:", long_options,
776 &oi);
777 if (c == -1)
778 break;
780 switch (c)
782 case 'a':
783 show_all_fs = true;
784 break;
785 case 'B':
787 enum strtol_error e = human_options (optarg, &human_output_opts,
788 &output_block_size);
789 if (e != LONGINT_OK)
790 xstrtol_fatal (e, oi, c, long_options, optarg);
792 break;
793 case 'i':
794 inode_format = true;
795 break;
796 case 'h':
797 human_output_opts = human_autoscale | human_SI | human_base_1024;
798 output_block_size = 1;
799 break;
800 case 'H':
801 human_output_opts = human_autoscale | human_SI;
802 output_block_size = 1;
803 break;
804 case 'k':
805 human_output_opts = 0;
806 output_block_size = 1024;
807 break;
808 case 'l':
809 show_local_fs = true;
810 break;
811 case 'm': /* obsolescent */
812 human_output_opts = 0;
813 output_block_size = 1024 * 1024;
814 break;
815 case 'T':
816 print_type = true;
817 break;
818 case 'P':
819 posix_format = true;
820 break;
821 case SYNC_OPTION:
822 require_sync = true;
823 break;
824 case NO_SYNC_OPTION:
825 require_sync = false;
826 break;
828 case 'F':
829 /* Accept -F as a synonym for -t for compatibility with Solaris. */
830 case 't':
831 add_fs_type (optarg);
832 break;
834 case 'v': /* For SysV compatibility. */
835 /* ignore */
836 break;
837 case 'x':
838 add_excluded_fs_type (optarg);
839 break;
841 case 'c':
842 print_grand_total = true;
843 break;
845 case_GETOPT_HELP_CHAR;
846 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
848 default:
849 usage (EXIT_FAILURE);
853 if (human_output_opts == -1)
855 if (posix_format)
857 human_output_opts = 0;
858 output_block_size = (getenv ("POSIXLY_CORRECT") ? 512 : 1024);
860 else
861 human_options (getenv ("DF_BLOCK_SIZE"),
862 &human_output_opts, &output_block_size);
865 /* Fail if the same file system type was both selected and excluded. */
867 bool match = false;
868 struct fs_type_list *fs_incl;
869 for (fs_incl = fs_select_list; fs_incl; fs_incl = fs_incl->fs_next)
871 struct fs_type_list *fs_excl;
872 for (fs_excl = fs_exclude_list; fs_excl; fs_excl = fs_excl->fs_next)
874 if (STREQ (fs_incl->fs_name, fs_excl->fs_name))
876 error (0, 0,
877 _("file system type %s both selected and excluded"),
878 quote (fs_incl->fs_name));
879 match = true;
880 break;
884 if (match)
885 exit (EXIT_FAILURE);
888 if (optind < argc)
890 int i;
892 /* Open each of the given entries to make sure any corresponding
893 partition is automounted. This must be done before reading the
894 file system table. */
895 stats = xnmalloc (argc - optind, sizeof *stats);
896 for (i = optind; i < argc; ++i)
898 /* Prefer to open with O_NOCTTY and use fstat, but fall back
899 on using "stat", in case the file is unreadable. */
900 int fd = open (argv[i], O_RDONLY | O_NOCTTY);
901 if ((fd < 0 || fstat (fd, &stats[i - optind]))
902 && stat (argv[i], &stats[i - optind]))
904 error (0, errno, "%s", quote (argv[i]));
905 exit_status = EXIT_FAILURE;
906 argv[i] = NULL;
908 if (0 <= fd)
909 close (fd);
913 mount_list =
914 read_file_system_list ((fs_select_list != NULL
915 || fs_exclude_list != NULL
916 || print_type
917 || show_local_fs));
919 if (mount_list == NULL)
921 /* Couldn't read the table of mounted file systems.
922 Fail if df was invoked with no file name arguments;
923 Otherwise, merely give a warning and proceed. */
924 int status = (optind < argc ? 0 : EXIT_FAILURE);
925 const char *warning = (optind < argc ? _("Warning: ") : "");
926 error (status, errno, "%s%s", warning,
927 _("cannot read table of mounted file systems"));
930 if (require_sync)
931 sync ();
933 if (optind < argc)
935 int i;
937 /* Display explicitly requested empty file systems. */
938 show_listed_fs = true;
940 for (i = optind; i < argc; ++i)
941 if (argv[i])
942 show_entry (argv[i], &stats[i - optind]);
944 else
945 show_all_entries ();
947 if (print_grand_total)
949 if (inode_format)
950 grand_fsu.fsu_blocks = 1;
951 show_dev ("total", NULL, NULL, NULL, false, false, &grand_fsu);
954 if (! file_systems_processed)
955 error (EXIT_FAILURE, 0, _("no file systems processed"));
957 exit (exit_status);