Test yesterday's change to groups.
[coreutils.git] / src / df.c
blob94cf330b5a577fb32a8d308bc66cbc58789316d0
1 /* df - summarize free disk space
2 Copyright (C) 91, 1995-2007 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 "canonicalize.h"
28 #include "error.h"
29 #include "fsusage.h"
30 #include "human.h"
31 #include "inttostr.h"
32 #include "mountlist.h"
33 #include "quote.h"
34 #include "save-cwd.h"
35 #include "xgetcwd.h"
37 /* The official name of this program (e.g., no `g' prefix). */
38 #define PROGRAM_NAME "df"
40 #define AUTHORS \
41 "Torbjorn Granlund", "David MacKenzie", "Paul Eggert"
43 /* Name this program was run with. */
44 char *program_name;
46 /* If true, show inode information. */
47 static bool inode_format;
49 /* If true, show even file systems with zero size or
50 uninteresting types. */
51 static bool show_all_fs;
53 /* If true, show only local file systems. */
54 static bool show_local_fs;
56 /* If true, output data for each file system corresponding to a
57 command line argument -- even if it's a dummy (automounter) entry. */
58 static bool show_listed_fs;
60 /* Human-readable options for output. */
61 static int human_output_opts;
63 /* The units to use when printing sizes. */
64 static uintmax_t output_block_size;
66 /* If true, use the POSIX output format. */
67 static bool posix_format;
69 /* True if a file system has been processed for output. */
70 static bool file_systems_processed;
72 /* If true, invoke the `sync' system call before getting any usage data.
73 Using this option can make df very slow, especially with many or very
74 busy disks. Note that this may make a difference on some systems --
75 SunOS 4.1.3, for one. It is *not* necessary on Linux. */
76 static bool require_sync;
78 /* Desired exit status. */
79 static int exit_status;
81 /* A file system type to display. */
83 struct fs_type_list
85 char *fs_name;
86 struct fs_type_list *fs_next;
89 /* Linked list of file system types to display.
90 If `fs_select_list' is NULL, list all types.
91 This table is generated dynamically from command-line options,
92 rather than hardcoding into the program what it thinks are the
93 valid file system types; let the user specify any file system type
94 they want to, and if there are any file systems of that type, they
95 will be shown.
97 Some file system types:
98 4.2 4.3 ufs nfs swap ignore io vm efs dbg */
100 static struct fs_type_list *fs_select_list;
102 /* Linked list of file system types to omit.
103 If the list is empty, don't exclude any types. */
105 static struct fs_type_list *fs_exclude_list;
107 /* Linked list of mounted file systems. */
108 static struct mount_entry *mount_list;
110 /* If true, print file system type as well. */
111 static bool print_type;
113 /* For long options that have no equivalent short option, use a
114 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
115 enum
117 NO_SYNC_OPTION = CHAR_MAX + 1,
118 SYNC_OPTION
121 static struct option const long_options[] =
123 {"all", no_argument, NULL, 'a'},
124 {"block-size", required_argument, NULL, 'B'},
125 {"inodes", no_argument, NULL, 'i'},
126 {"human-readable", no_argument, NULL, 'h'},
127 {"si", no_argument, NULL, 'H'},
128 {"local", no_argument, NULL, 'l'},
129 {"megabytes", no_argument, NULL, 'm'}, /* obsolescent */
130 {"portability", no_argument, NULL, 'P'},
131 {"print-type", no_argument, NULL, 'T'},
132 {"sync", no_argument, NULL, SYNC_OPTION},
133 {"no-sync", no_argument, NULL, NO_SYNC_OPTION},
134 {"type", required_argument, NULL, 't'},
135 {"exclude-type", required_argument, NULL, 'x'},
136 {GETOPT_HELP_OPTION_DECL},
137 {GETOPT_VERSION_OPTION_DECL},
138 {NULL, 0, NULL, 0}
141 static void
142 print_header (void)
144 char buf[MAX (LONGEST_HUMAN_READABLE + 1, INT_BUFSIZE_BOUND (uintmax_t))];
146 if (print_type)
147 fputs (_("Filesystem Type"), stdout);
148 else
149 fputs (_("Filesystem "), stdout);
151 if (inode_format)
152 printf (_(" Inodes IUsed IFree IUse%%"));
153 else if (human_output_opts & human_autoscale)
155 if (human_output_opts & human_base_1024)
156 printf (_(" Size Used Avail Use%%"));
157 else
158 printf (_(" Size Used Avail Use%%"));
160 else if (posix_format)
161 printf (_(" %s-blocks Used Available Capacity"),
162 umaxtostr (output_block_size, buf));
163 else
165 int opts = (human_suppress_point_zero
166 | human_autoscale | human_SI
167 | (human_output_opts
168 & (human_group_digits | human_base_1024 | human_B)));
170 /* Prefer the base that makes the human-readable value more exact,
171 if there is a difference. */
173 uintmax_t q1000 = output_block_size;
174 uintmax_t q1024 = output_block_size;
175 bool divisible_by_1000;
176 bool divisible_by_1024;
180 divisible_by_1000 = q1000 % 1000 == 0; q1000 /= 1000;
181 divisible_by_1024 = q1024 % 1024 == 0; q1024 /= 1024;
183 while (divisible_by_1000 & divisible_by_1024);
185 if (divisible_by_1000 < divisible_by_1024)
186 opts |= human_base_1024;
187 if (divisible_by_1024 < divisible_by_1000)
188 opts &= ~human_base_1024;
189 if (! (opts & human_base_1024))
190 opts |= human_B;
192 printf (_(" %4s-blocks Used Available Use%%"),
193 human_readable (output_block_size, buf, opts, 1, 1));
196 printf (_(" Mounted on\n"));
199 /* Is FSTYPE a type of file system that should be listed? */
201 static bool
202 selected_fstype (const char *fstype)
204 const struct fs_type_list *fsp;
206 if (fs_select_list == NULL || fstype == NULL)
207 return true;
208 for (fsp = fs_select_list; fsp; fsp = fsp->fs_next)
209 if (STREQ (fstype, fsp->fs_name))
210 return true;
211 return false;
214 /* Is FSTYPE a type of file system that should be omitted? */
216 static bool
217 excluded_fstype (const char *fstype)
219 const struct fs_type_list *fsp;
221 if (fs_exclude_list == NULL || fstype == NULL)
222 return false;
223 for (fsp = fs_exclude_list; fsp; fsp = fsp->fs_next)
224 if (STREQ (fstype, fsp->fs_name))
225 return true;
226 return false;
229 /* Like human_readable (N, BUF, human_output_opts, INPUT_UNITS, OUTPUT_UNITS),
230 except:
232 - If NEGATIVE, then N represents a negative number,
233 expressed in two's complement.
234 - Otherwise, return "-" if N is UINTMAX_MAX. */
236 static char const *
237 df_readable (bool negative, uintmax_t n, char *buf,
238 uintmax_t input_units, uintmax_t output_units)
240 if (n == UINTMAX_MAX && !negative)
241 return "-";
242 else
244 char *p = human_readable (negative ? -n : n, buf + negative,
245 human_output_opts, input_units, output_units);
246 if (negative)
247 *--p = '-';
248 return p;
252 /* Display a space listing for the disk device with absolute file name DISK.
253 If MOUNT_POINT is non-NULL, it is the name of the root of the
254 file system on DISK.
255 If STAT_FILE is non-null, it is the name of a file within the file
256 system that the user originally asked for; this provides better
257 diagnostics, and sometimes it provides better results on networked
258 file systems that give different free-space results depending on
259 where in the file system you probe.
260 If FSTYPE is non-NULL, it is the type of the file system on DISK.
261 If MOUNT_POINT is non-NULL, then DISK may be NULL -- certain systems may
262 not be able to produce statistics in this case.
263 ME_DUMMY and ME_REMOTE are the mount entry flags. */
265 static void
266 show_dev (char const *disk, char const *mount_point,
267 char const *stat_file, char const *fstype,
268 bool me_dummy, bool me_remote)
270 struct fs_usage fsu;
271 char buf[3][LONGEST_HUMAN_READABLE + 2];
272 int width;
273 int col1_adjustment = 0;
274 int use_width;
275 uintmax_t input_units;
276 uintmax_t output_units;
277 uintmax_t total;
278 uintmax_t available;
279 bool negate_available;
280 uintmax_t available_to_root;
281 uintmax_t used;
282 bool negate_used;
283 double pct = -1;
285 if (me_remote & show_local_fs)
286 return;
288 if (me_dummy & !show_all_fs & !show_listed_fs)
289 return;
291 if (!selected_fstype (fstype) || excluded_fstype (fstype))
292 return;
294 /* If MOUNT_POINT is NULL, then the file system is not mounted, and this
295 program reports on the file system that the special file is on.
296 It would be better to report on the unmounted file system,
297 but statfs doesn't do that on most systems. */
298 if (!stat_file)
299 stat_file = mount_point ? mount_point : disk;
301 if (get_fs_usage (stat_file, disk, &fsu))
303 error (0, errno, "%s", quote (stat_file));
304 exit_status = EXIT_FAILURE;
305 return;
308 if (fsu.fsu_blocks == 0 && !show_all_fs && !show_listed_fs)
309 return;
311 if (! file_systems_processed)
313 file_systems_processed = true;
314 print_header ();
317 if (! disk)
318 disk = "-"; /* unknown */
319 if (! fstype)
320 fstype = "-"; /* unknown */
322 /* df.c reserved 5 positions for fstype,
323 but that does not suffice for type iso9660 */
324 if (print_type)
326 size_t disk_name_len = strlen (disk);
327 size_t fstype_len = strlen (fstype);
328 if (disk_name_len + fstype_len < 18)
329 printf ("%s%*s ", disk, 18 - (int) disk_name_len, fstype);
330 else if (!posix_format)
331 printf ("%s\n%18s ", disk, fstype);
332 else
333 printf ("%s %s", disk, fstype);
335 else
337 if (strlen (disk) > 20 && !posix_format)
338 printf ("%s\n%20s", disk, "");
339 else
340 printf ("%-20s", disk);
343 if (inode_format)
345 width = 7;
346 use_width = 5;
347 input_units = output_units = 1;
348 total = fsu.fsu_files;
349 available = fsu.fsu_ffree;
350 negate_available = false;
351 available_to_root = available;
353 else
355 if (human_output_opts & human_autoscale)
356 width = 5 + ! (human_output_opts & human_base_1024);
357 else
359 width = 9;
360 if (posix_format)
362 uintmax_t b;
363 col1_adjustment = -3;
364 for (b = output_block_size; 9 < b; b /= 10)
365 col1_adjustment++;
368 use_width = ((posix_format
369 && ! (human_output_opts & human_autoscale))
370 ? 8 : 4);
371 input_units = fsu.fsu_blocksize;
372 output_units = output_block_size;
373 total = fsu.fsu_blocks;
374 available = fsu.fsu_bavail;
375 negate_available = (fsu.fsu_bavail_top_bit_set
376 & (available != UINTMAX_MAX));
377 available_to_root = fsu.fsu_bfree;
380 used = UINTMAX_MAX;
381 negate_used = false;
382 if (total != UINTMAX_MAX && available_to_root != UINTMAX_MAX)
384 used = total - available_to_root;
385 negate_used = (total < available_to_root);
388 printf (" %*s %*s %*s ",
389 width + col1_adjustment,
390 df_readable (false, total,
391 buf[0], input_units, output_units),
392 width, df_readable (negate_used, used,
393 buf[1], input_units, output_units),
394 width, df_readable (negate_available, available,
395 buf[2], input_units, output_units));
397 if (used == UINTMAX_MAX || available == UINTMAX_MAX)
399 else if (!negate_used
400 && used <= TYPE_MAXIMUM (uintmax_t) / 100
401 && used + available != 0
402 && (used + available < used) == negate_available)
404 uintmax_t u100 = used * 100;
405 uintmax_t nonroot_total = used + available;
406 pct = u100 / nonroot_total + (u100 % nonroot_total != 0);
408 else
410 /* The calculation cannot be done easily with integer
411 arithmetic. Fall back on floating point. This can suffer
412 from minor rounding errors, but doing it exactly requires
413 multiple precision arithmetic, and it's not worth the
414 aggravation. */
415 double u = negate_used ? - (double) - used : used;
416 double a = negate_available ? - (double) - available : available;
417 double nonroot_total = u + a;
418 if (nonroot_total)
420 long int lipct = pct = u * 100 / nonroot_total;
421 double ipct = lipct;
423 /* Like `pct = ceil (dpct);', but avoid ceil so that
424 the math library needn't be linked. */
425 if (ipct - 1 < pct && pct <= ipct + 1)
426 pct = ipct + (ipct < pct);
430 if (0 <= pct)
431 printf ("%*.0f%%", use_width - 1, pct);
432 else
433 printf ("%*s", use_width, "- ");
435 if (mount_point)
437 #ifdef HIDE_AUTOMOUNT_PREFIX
438 /* Don't print the first directory name in MOUNT_POINT if it's an
439 artifact of an automounter. This is a bit too aggressive to be
440 the default. */
441 if (strncmp ("/auto/", mount_point, 6) == 0)
442 mount_point += 5;
443 else if (strncmp ("/tmp_mnt/", mount_point, 9) == 0)
444 mount_point += 8;
445 #endif
446 printf (" %s", mount_point);
448 putchar ('\n');
451 /* Return the root mountpoint of the file system on which FILE exists, in
452 malloced storage. FILE_STAT should be the result of stating FILE.
453 Give a diagnostic and return NULL if unable to determine the mount point.
454 Exit if unable to restore current working directory. */
455 static char *
456 find_mount_point (const char *file, const struct stat *file_stat)
458 struct saved_cwd cwd;
459 struct stat last_stat;
460 char *mp = NULL; /* The malloced mount point. */
462 if (save_cwd (&cwd) != 0)
464 error (0, errno, _("cannot get current directory"));
465 return NULL;
468 if (S_ISDIR (file_stat->st_mode))
469 /* FILE is a directory, so just chdir there directly. */
471 last_stat = *file_stat;
472 if (chdir (file) < 0)
474 error (0, errno, _("cannot change to directory %s"), quote (file));
475 return NULL;
478 else
479 /* FILE is some other kind of file; use its directory. */
481 char *xdir = dir_name (file);
482 char *dir;
483 ASSIGN_STRDUPA (dir, xdir);
484 free (xdir);
486 if (chdir (dir) < 0)
488 error (0, errno, _("cannot change to directory %s"), quote (dir));
489 return NULL;
492 if (stat (".", &last_stat) < 0)
494 error (0, errno, _("cannot stat current directory (now %s)"),
495 quote (dir));
496 goto done;
500 /* Now walk up FILE's parents until we find another file system or /,
501 chdiring as we go. LAST_STAT holds stat information for the last place
502 we visited. */
503 for (;;)
505 struct stat st;
506 if (stat ("..", &st) < 0)
508 error (0, errno, _("cannot stat %s"), quote (".."));
509 goto done;
511 if (st.st_dev != last_stat.st_dev || st.st_ino == last_stat.st_ino)
512 /* cwd is the mount point. */
513 break;
514 if (chdir ("..") < 0)
516 error (0, errno, _("cannot change to directory %s"), quote (".."));
517 goto done;
519 last_stat = st;
522 /* Finally reached a mount point, see what it's called. */
523 mp = xgetcwd ();
525 done:
526 /* Restore the original cwd. */
528 int save_errno = errno;
529 if (restore_cwd (&cwd) != 0)
530 error (EXIT_FAILURE, errno,
531 _("failed to return to initial working directory"));
532 free_cwd (&cwd);
533 errno = save_errno;
536 return mp;
539 /* If DISK corresponds to a mount point, show its usage
540 and return true. Otherwise, return false. */
541 static bool
542 show_disk (char const *disk)
544 struct mount_entry const *me;
545 struct mount_entry const *best_match = NULL;
547 for (me = mount_list; me; me = me->me_next)
548 if (STREQ (disk, me->me_devname))
549 best_match = me;
551 if (best_match)
553 show_dev (best_match->me_devname, best_match->me_mountdir, NULL,
554 best_match->me_type, best_match->me_dummy,
555 best_match->me_remote);
556 return true;
559 return false;
562 /* Figure out which device file or directory POINT is mounted on
563 and show its disk usage.
564 STATP must be the result of `stat (POINT, STATP)'. */
565 static void
566 show_point (const char *point, const struct stat *statp)
568 struct stat disk_stats;
569 struct mount_entry *me;
570 struct mount_entry const *best_match = NULL;
572 /* If POINT is an absolute file name, see if we can find the
573 mount point without performing any extra stat calls at all. */
574 if (*point == '/')
576 /* Find the best match: prefer non-dummies, and then prefer the
577 last match if there are ties. */
579 for (me = mount_list; me; me = me->me_next)
580 if (STREQ (me->me_mountdir, point) && !STREQ (me->me_type, "lofs")
581 && (!best_match || best_match->me_dummy || !me->me_dummy))
582 best_match = me;
585 /* Calculate the real absolute file name for POINT, and use that to find
586 the mount point. This avoids statting unavailable mount points,
587 which can hang df. */
588 if (! best_match)
590 char *resolved = canonicalize_file_name (point);
592 if (resolved && resolved[0] == '/')
594 size_t resolved_len = strlen (resolved);
595 size_t best_match_len = 0;
597 for (me = mount_list; me; me = me->me_next)
598 if (!STREQ (me->me_type, "lofs")
599 && (!best_match || best_match->me_dummy || !me->me_dummy))
601 size_t len = strlen (me->me_mountdir);
602 if (best_match_len <= len && len <= resolved_len
603 && (len == 1 /* root file system */
604 || ((len == resolved_len || resolved[len] == '/')
605 && strncmp (me->me_mountdir, resolved, len) == 0)))
607 best_match = me;
608 best_match_len = len;
613 free (resolved);
615 if (best_match
616 && (stat (best_match->me_mountdir, &disk_stats) != 0
617 || disk_stats.st_dev != statp->st_dev))
618 best_match = NULL;
621 if (! best_match)
622 for (me = mount_list; me; me = me->me_next)
624 if (me->me_dev == (dev_t) -1)
626 if (stat (me->me_mountdir, &disk_stats) == 0)
627 me->me_dev = disk_stats.st_dev;
628 else
630 /* Report only I/O errors. Other errors might be
631 caused by shadowed mount points, which means POINT
632 can't possibly be on this file system. */
633 if (errno == EIO)
635 error (0, errno, "%s", quote (me->me_mountdir));
636 exit_status = EXIT_FAILURE;
639 /* So we won't try and fail repeatedly. */
640 me->me_dev = (dev_t) -2;
644 if (statp->st_dev == me->me_dev
645 && !STREQ (me->me_type, "lofs")
646 && (!best_match || best_match->me_dummy || !me->me_dummy))
648 /* Skip bogus mtab entries. */
649 if (stat (me->me_mountdir, &disk_stats) != 0
650 || disk_stats.st_dev != me->me_dev)
651 me->me_dev = (dev_t) -2;
652 else
653 best_match = me;
657 if (best_match)
658 show_dev (best_match->me_devname, best_match->me_mountdir, point,
659 best_match->me_type, best_match->me_dummy, best_match->me_remote);
660 else
662 /* We couldn't find the mount entry corresponding to POINT. Go ahead and
663 print as much info as we can; methods that require the device to be
664 present will fail at a later point. */
666 /* Find the actual mount point. */
667 char *mp = find_mount_point (point, statp);
668 if (mp)
670 show_dev (NULL, mp, NULL, NULL, false, false);
671 free (mp);
676 /* Determine what kind of node NAME is and show the disk usage
677 for it. STATP is the results of `stat' on NAME. */
679 static void
680 show_entry (char const *name, struct stat const *statp)
682 if ((S_ISBLK (statp->st_mode) || S_ISCHR (statp->st_mode))
683 && show_disk (name))
684 return;
686 show_point (name, statp);
689 /* Show all mounted file systems, except perhaps those that are of
690 an unselected type or are empty. */
692 static void
693 show_all_entries (void)
695 struct mount_entry *me;
697 for (me = mount_list; me; me = me->me_next)
698 show_dev (me->me_devname, me->me_mountdir, NULL, me->me_type,
699 me->me_dummy, me->me_remote);
702 /* Add FSTYPE to the list of file system types to display. */
704 static void
705 add_fs_type (const char *fstype)
707 struct fs_type_list *fsp;
709 fsp = xmalloc (sizeof *fsp);
710 fsp->fs_name = (char *) fstype;
711 fsp->fs_next = fs_select_list;
712 fs_select_list = fsp;
715 /* Add FSTYPE to the list of file system types to be omitted. */
717 static void
718 add_excluded_fs_type (const char *fstype)
720 struct fs_type_list *fsp;
722 fsp = xmalloc (sizeof *fsp);
723 fsp->fs_name = (char *) fstype;
724 fsp->fs_next = fs_exclude_list;
725 fs_exclude_list = fsp;
728 void
729 usage (int status)
731 if (status != EXIT_SUCCESS)
732 fprintf (stderr, _("Try `%s --help' for more information.\n"),
733 program_name);
734 else
736 printf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name);
737 fputs (_("\
738 Show information about the file system on which each FILE resides,\n\
739 or all file systems by default.\n\
741 "), stdout);
742 fputs (_("\
743 Mandatory arguments to long options are mandatory for short options too.\n\
744 "), stdout);
745 fputs (_("\
746 -a, --all include dummy file systems\n\
747 -B, --block-size=SIZE use SIZE-byte blocks\n\
748 -h, --human-readable print sizes in human readable format (e.g., 1K 234M 2G)\n\
749 -H, --si likewise, but use powers of 1000 not 1024\n\
750 "), stdout);
751 fputs (_("\
752 -i, --inodes list inode information instead of block usage\n\
753 -k like --block-size=1K\n\
754 -l, --local limit listing to local file systems\n\
755 --no-sync do not invoke sync before getting usage info (default)\n\
756 "), stdout);
757 fputs (_("\
758 -P, --portability use the POSIX output format\n\
759 --sync invoke sync before getting usage info\n\
760 -t, --type=TYPE limit listing to file systems of type TYPE\n\
761 -T, --print-type print file system type\n\
762 -x, --exclude-type=TYPE limit listing to file systems not of type TYPE\n\
763 -v (ignored)\n\
764 "), stdout);
765 fputs (HELP_OPTION_DESCRIPTION, stdout);
766 fputs (VERSION_OPTION_DESCRIPTION, stdout);
767 fputs (_("\n\
768 SIZE may be (or may be an integer optionally followed by) one of following:\n\
769 kB 1000, K 1024, MB 1000*1000, M 1024*1024, and so on for G, T, P, E, Z, Y.\n\
770 "), stdout);
771 emit_bug_reporting_address ();
773 exit (status);
777 main (int argc, char **argv)
779 struct stat *stats IF_LINT (= 0);
781 initialize_main (&argc, &argv);
782 program_name = argv[0];
783 setlocale (LC_ALL, "");
784 bindtextdomain (PACKAGE, LOCALEDIR);
785 textdomain (PACKAGE);
787 atexit (close_stdout);
789 fs_select_list = NULL;
790 fs_exclude_list = NULL;
791 inode_format = false;
792 show_all_fs = false;
793 show_listed_fs = false;
794 human_output_opts = -1;
795 print_type = false;
796 file_systems_processed = false;
797 posix_format = false;
798 exit_status = EXIT_SUCCESS;
800 for (;;)
802 int oi = -1;
803 int c = getopt_long (argc, argv, "aB:iF:hHklmPTt:vx:", long_options,
804 &oi);
805 if (c == -1)
806 break;
808 switch (c)
810 case 'a':
811 show_all_fs = true;
812 break;
813 case 'B':
815 enum strtol_error e = human_options (optarg, &human_output_opts,
816 &output_block_size);
817 if (e != LONGINT_OK)
818 xstrtol_fatal (e, oi, c, long_options, optarg);
820 break;
821 case 'i':
822 inode_format = true;
823 break;
824 case 'h':
825 human_output_opts = human_autoscale | human_SI | human_base_1024;
826 output_block_size = 1;
827 break;
828 case 'H':
829 human_output_opts = human_autoscale | human_SI;
830 output_block_size = 1;
831 break;
832 case 'k':
833 human_output_opts = 0;
834 output_block_size = 1024;
835 break;
836 case 'l':
837 show_local_fs = true;
838 break;
839 case 'm': /* obsolescent */
840 human_output_opts = 0;
841 output_block_size = 1024 * 1024;
842 break;
843 case 'T':
844 print_type = true;
845 break;
846 case 'P':
847 posix_format = true;
848 break;
849 case SYNC_OPTION:
850 require_sync = true;
851 break;
852 case NO_SYNC_OPTION:
853 require_sync = false;
854 break;
856 case 'F':
857 /* Accept -F as a synonym for -t for compatibility with Solaris. */
858 case 't':
859 add_fs_type (optarg);
860 break;
862 case 'v': /* For SysV compatibility. */
863 /* ignore */
864 break;
865 case 'x':
866 add_excluded_fs_type (optarg);
867 break;
869 case_GETOPT_HELP_CHAR;
870 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
872 default:
873 usage (EXIT_FAILURE);
877 if (human_output_opts == -1)
879 if (posix_format)
881 human_output_opts = 0;
882 output_block_size = (getenv ("POSIXLY_CORRECT") ? 512 : 1024);
884 else
885 human_options (getenv ("DF_BLOCK_SIZE"),
886 &human_output_opts, &output_block_size);
889 /* Fail if the same file system type was both selected and excluded. */
891 bool match = false;
892 struct fs_type_list *fs_incl;
893 for (fs_incl = fs_select_list; fs_incl; fs_incl = fs_incl->fs_next)
895 struct fs_type_list *fs_excl;
896 for (fs_excl = fs_exclude_list; fs_excl; fs_excl = fs_excl->fs_next)
898 if (STREQ (fs_incl->fs_name, fs_excl->fs_name))
900 error (0, 0,
901 _("file system type %s both selected and excluded"),
902 quote (fs_incl->fs_name));
903 match = true;
904 break;
908 if (match)
909 exit (EXIT_FAILURE);
912 if (optind < argc)
914 int i;
916 /* stat all the given entries to make sure they get automounted,
917 if necessary, before reading the file system table. */
918 stats = xnmalloc (argc - optind, sizeof *stats);
919 for (i = optind; i < argc; ++i)
921 if (stat (argv[i], &stats[i - optind]))
923 error (0, errno, "%s", quote (argv[i]));
924 exit_status = EXIT_FAILURE;
925 argv[i] = NULL;
930 mount_list =
931 read_file_system_list ((fs_select_list != NULL
932 || fs_exclude_list != NULL
933 || print_type
934 || show_local_fs));
936 if (mount_list == NULL)
938 /* Couldn't read the table of mounted file systems.
939 Fail if df was invoked with no file name arguments;
940 Otherwise, merely give a warning and proceed. */
941 const char *warning = (optind < argc ? _("Warning: ") : "");
942 int status = (optind < argc ? 0 : EXIT_FAILURE);
943 error (status, errno,
944 _("%scannot read table of mounted file systems"), warning);
947 if (require_sync)
948 sync ();
950 if (optind < argc)
952 int i;
954 /* Display explicitly requested empty file systems. */
955 show_listed_fs = true;
957 for (i = optind; i < argc; ++i)
958 if (argv[i])
959 show_entry (argv[i], &stats[i - optind]);
961 else
962 show_all_entries ();
964 if (! file_systems_processed)
965 error (EXIT_FAILURE, 0, _("no file systems processed"));
967 exit (exit_status);