global: convert indentation-TABs to spaces
[coreutils.git] / src / df.c
blob787fcde214d1bbb18bbdda7c4f56db0d891a7c2e
1 /* df - summarize free disk space
2 Copyright (C) 91, 1995-2009 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 "mountlist.h"
32 #include "quote.h"
33 #include "save-cwd.h"
34 #include "xgetcwd.h"
36 /* The official name of this program (e.g., no `g' prefix). */
37 #define PROGRAM_NAME "df"
39 #define AUTHORS \
40 proper_name_utf8 ("Torbjorn Granlund", "Torbj\303\266rn Granlund"), \
41 proper_name ("David MacKenzie"), \
42 proper_name ("Paul Eggert")
44 /* If true, show inode information. */
45 static bool inode_format;
47 /* If true, show even file systems with zero size or
48 uninteresting types. */
49 static bool show_all_fs;
51 /* If true, show only local file systems. */
52 static bool show_local_fs;
54 /* If true, output data for each file system corresponding to a
55 command line argument -- even if it's a dummy (automounter) entry. */
56 static bool show_listed_fs;
58 /* Human-readable options for output. */
59 static int human_output_opts;
61 /* The units to use when printing sizes. */
62 static uintmax_t output_block_size;
64 /* If true, use the POSIX output format. */
65 static bool posix_format;
67 /* True if a file system has been processed for output. */
68 static bool file_systems_processed;
70 /* If true, invoke the `sync' system call before getting any usage data.
71 Using this option can make df very slow, especially with many or very
72 busy disks. Note that this may make a difference on some systems --
73 SunOS 4.1.3, for one. It is *not* necessary on GNU/Linux. */
74 static bool require_sync;
76 /* Desired exit status. */
77 static int exit_status;
79 /* A file system type to display. */
81 struct fs_type_list
83 char *fs_name;
84 struct fs_type_list *fs_next;
87 /* Linked list of file system types to display.
88 If `fs_select_list' is NULL, list all types.
89 This table is generated dynamically from command-line options,
90 rather than hardcoding into the program what it thinks are the
91 valid file system types; let the user specify any file system type
92 they want to, and if there are any file systems of that type, they
93 will be shown.
95 Some file system types:
96 4.2 4.3 ufs nfs swap ignore io vm efs dbg */
98 static struct fs_type_list *fs_select_list;
100 /* Linked list of file system types to omit.
101 If the list is empty, don't exclude any types. */
103 static struct fs_type_list *fs_exclude_list;
105 /* Linked list of mounted file systems. */
106 static struct mount_entry *mount_list;
108 /* If true, print file system type as well. */
109 static bool print_type;
111 /* If true, print a grand total at the end. */
112 static bool print_grand_total;
114 /* Grand total data. */
115 static struct fs_usage grand_fsu;
117 /* For long options that have no equivalent short option, use a
118 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
119 enum
121 NO_SYNC_OPTION = CHAR_MAX + 1,
122 SYNC_OPTION
125 static struct option const long_options[] =
127 {"all", no_argument, NULL, 'a'},
128 {"block-size", required_argument, NULL, 'B'},
129 {"inodes", no_argument, NULL, 'i'},
130 {"human-readable", no_argument, NULL, 'h'},
131 {"si", no_argument, NULL, 'H'},
132 {"local", no_argument, NULL, 'l'},
133 {"megabytes", no_argument, NULL, 'm'}, /* obsolescent */
134 {"portability", no_argument, NULL, 'P'},
135 {"print-type", no_argument, NULL, 'T'},
136 {"sync", no_argument, NULL, SYNC_OPTION},
137 {"no-sync", no_argument, NULL, NO_SYNC_OPTION},
138 {"total", no_argument, NULL, 'c'},
139 {"type", required_argument, NULL, 't'},
140 {"exclude-type", required_argument, NULL, 'x'},
141 {GETOPT_HELP_OPTION_DECL},
142 {GETOPT_VERSION_OPTION_DECL},
143 {NULL, 0, NULL, 0}
146 static void
147 print_header (void)
149 char buf[MAX (LONGEST_HUMAN_READABLE + 1, INT_BUFSIZE_BOUND (uintmax_t))];
151 if (print_type)
152 fputs (_("Filesystem Type"), stdout);
153 else
154 fputs (_("Filesystem "), stdout);
156 if (inode_format)
157 printf (_(" Inodes IUsed IFree IUse%%"));
158 else if (human_output_opts & human_autoscale)
160 if (human_output_opts & human_base_1024)
161 printf (_(" Size Used Avail Use%%"));
162 else
163 printf (_(" Size Used Avail Use%%"));
165 else if (posix_format)
166 printf (_(" %s-blocks Used Available Capacity"),
167 umaxtostr (output_block_size, buf));
168 else
170 int opts = (human_suppress_point_zero
171 | human_autoscale | human_SI
172 | (human_output_opts
173 & (human_group_digits | human_base_1024 | human_B)));
175 /* Prefer the base that makes the human-readable value more exact,
176 if there is a difference. */
178 uintmax_t q1000 = output_block_size;
179 uintmax_t q1024 = output_block_size;
180 bool divisible_by_1000;
181 bool divisible_by_1024;
185 divisible_by_1000 = q1000 % 1000 == 0; q1000 /= 1000;
186 divisible_by_1024 = q1024 % 1024 == 0; q1024 /= 1024;
188 while (divisible_by_1000 & divisible_by_1024);
190 if (divisible_by_1000 < divisible_by_1024)
191 opts |= human_base_1024;
192 if (divisible_by_1024 < divisible_by_1000)
193 opts &= ~human_base_1024;
194 if (! (opts & human_base_1024))
195 opts |= human_B;
197 printf (_(" %4s-blocks Used Available Use%%"),
198 human_readable (output_block_size, buf, opts, 1, 1));
201 printf (_(" Mounted on\n"));
204 /* Is FSTYPE a type of file system that should be listed? */
206 static bool
207 selected_fstype (const char *fstype)
209 const struct fs_type_list *fsp;
211 if (fs_select_list == NULL || fstype == NULL)
212 return true;
213 for (fsp = fs_select_list; fsp; fsp = fsp->fs_next)
214 if (STREQ (fstype, fsp->fs_name))
215 return true;
216 return false;
219 /* Is FSTYPE a type of file system that should be omitted? */
221 static bool
222 excluded_fstype (const char *fstype)
224 const struct fs_type_list *fsp;
226 if (fs_exclude_list == NULL || fstype == NULL)
227 return false;
228 for (fsp = fs_exclude_list; fsp; fsp = fsp->fs_next)
229 if (STREQ (fstype, fsp->fs_name))
230 return true;
231 return false;
234 /* Return true if N is a known integer value. On many file systems,
235 UINTMAX_MAX represents an unknown value; on AIX, UINTMAX_MAX - 1
236 represents unknown. Use a rule that works on AIX file systems, and
237 that almost-always works on other types. */
238 static bool
239 known_value (uintmax_t n)
241 return n < UINTMAX_MAX - 1;
244 /* Like human_readable (N, BUF, human_output_opts, INPUT_UNITS, OUTPUT_UNITS),
245 except:
247 - If NEGATIVE, then N represents a negative number,
248 expressed in two's complement.
249 - Otherwise, return "-" if N is unknown. */
251 static char const *
252 df_readable (bool negative, uintmax_t n, char *buf,
253 uintmax_t input_units, uintmax_t output_units)
255 if (! known_value (n) && !negative)
256 return "-";
257 else
259 char *p = human_readable (negative ? -n : n, buf + negative,
260 human_output_opts, input_units, output_units);
261 if (negative)
262 *--p = '-';
263 return p;
267 /* Logical equivalence */
268 #define LOG_EQ(a, b) (!(a) == !(b))
270 /* Add integral value while using uintmax_t for value part and separate
271 negation flag. It adds value of SRC and SRC_NEG to DEST and DEST_NEG.
272 The result will be in DEST and DEST_NEG. See df_readable to understand
273 how the negation flag is used. */
274 static void
275 add_uint_with_neg_flag (uintmax_t *dest, bool *dest_neg,
276 uintmax_t src, bool src_neg)
278 if (LOG_EQ (*dest_neg, src_neg))
280 *dest += src;
281 return;
284 if (*dest_neg)
285 *dest = -*dest;
287 if (src_neg)
288 src = -src;
290 if (src < *dest)
291 *dest -= src;
292 else
294 *dest = src - *dest;
295 *dest_neg = src_neg;
298 if (*dest_neg)
299 *dest = -*dest;
302 /* Display a space listing for the disk device with absolute file name DISK.
303 If MOUNT_POINT is non-NULL, it is the name of the root of the
304 file system on DISK.
305 If STAT_FILE is non-null, it is the name of a file within the file
306 system that the user originally asked for; this provides better
307 diagnostics, and sometimes it provides better results on networked
308 file systems that give different free-space results depending on
309 where in the file system you probe.
310 If FSTYPE is non-NULL, it is the type of the file system on DISK.
311 If MOUNT_POINT is non-NULL, then DISK may be NULL -- certain systems may
312 not be able to produce statistics in this case.
313 ME_DUMMY and ME_REMOTE are the mount entry flags. */
315 static void
316 show_dev (char const *disk, char const *mount_point,
317 char const *stat_file, char const *fstype,
318 bool me_dummy, bool me_remote,
319 const struct fs_usage *force_fsu)
321 struct fs_usage fsu;
322 char buf[3][LONGEST_HUMAN_READABLE + 2];
323 int width;
324 int col1_adjustment = 0;
325 int use_width;
326 uintmax_t input_units;
327 uintmax_t output_units;
328 uintmax_t total;
329 uintmax_t available;
330 bool negate_available;
331 uintmax_t available_to_root;
332 uintmax_t used;
333 bool negate_used;
334 double pct = -1;
336 if (me_remote & show_local_fs)
337 return;
339 if (me_dummy & !show_all_fs & !show_listed_fs)
340 return;
342 if (!selected_fstype (fstype) || excluded_fstype (fstype))
343 return;
345 /* If MOUNT_POINT is NULL, then the file system is not mounted, and this
346 program reports on the file system that the special file is on.
347 It would be better to report on the unmounted file system,
348 but statfs doesn't do that on most systems. */
349 if (!stat_file)
350 stat_file = mount_point ? mount_point : disk;
352 if (force_fsu)
353 fsu = *force_fsu;
354 else if (get_fs_usage (stat_file, disk, &fsu))
356 error (0, errno, "%s", quote (stat_file));
357 exit_status = EXIT_FAILURE;
358 return;
361 if (fsu.fsu_blocks == 0 && !show_all_fs && !show_listed_fs)
362 return;
364 if (! file_systems_processed)
366 file_systems_processed = true;
367 print_header ();
370 if (! disk)
371 disk = "-"; /* unknown */
372 if (! fstype)
373 fstype = "-"; /* unknown */
375 /* df.c reserved 5 positions for fstype,
376 but that does not suffice for type iso9660 */
377 if (print_type)
379 size_t disk_name_len = strlen (disk);
380 size_t fstype_len = strlen (fstype);
381 if (disk_name_len + fstype_len < 18)
382 printf ("%s%*s ", disk, 18 - (int) disk_name_len, fstype);
383 else if (!posix_format)
384 printf ("%s\n%18s ", disk, fstype);
385 else
386 printf ("%s %s", disk, fstype);
388 else
390 if (strlen (disk) > 20 && !posix_format)
391 printf ("%s\n%20s", disk, "");
392 else
393 printf ("%-20s", disk);
396 if (inode_format)
398 width = 7;
399 use_width = 5;
400 input_units = output_units = 1;
401 total = fsu.fsu_files;
402 available = fsu.fsu_ffree;
403 negate_available = false;
404 available_to_root = available;
406 if (known_value (total))
407 grand_fsu.fsu_files += total;
408 if (known_value (available))
409 grand_fsu.fsu_ffree += available;
411 else
413 if (human_output_opts & human_autoscale)
414 width = 5 + ! (human_output_opts & human_base_1024);
415 else
417 width = 9;
418 if (posix_format)
420 uintmax_t b;
421 col1_adjustment = -3;
422 for (b = output_block_size; 9 < b; b /= 10)
423 col1_adjustment++;
426 use_width = ((posix_format
427 && ! (human_output_opts & human_autoscale))
428 ? 8 : 4);
429 input_units = fsu.fsu_blocksize;
430 output_units = output_block_size;
431 total = fsu.fsu_blocks;
432 available = fsu.fsu_bavail;
433 negate_available = (fsu.fsu_bavail_top_bit_set
434 & known_value (available));
435 available_to_root = fsu.fsu_bfree;
437 if (known_value (total))
438 grand_fsu.fsu_blocks += input_units * total;
439 if (known_value (available_to_root))
440 grand_fsu.fsu_bfree += input_units * available_to_root;
441 if (known_value (available))
442 add_uint_with_neg_flag (&grand_fsu.fsu_bavail,
443 &grand_fsu.fsu_bavail_top_bit_set,
444 input_units * available, negate_available);
447 used = UINTMAX_MAX;
448 negate_used = false;
449 if (known_value (total) && known_value (available_to_root))
451 used = total - available_to_root;
452 negate_used = (total < available_to_root);
455 printf (" %*s %*s %*s ",
456 width + col1_adjustment,
457 df_readable (false, total,
458 buf[0], input_units, output_units),
459 width, df_readable (negate_used, used,
460 buf[1], input_units, output_units),
461 width, df_readable (negate_available, available,
462 buf[2], input_units, output_units));
464 if (! known_value (used) || ! known_value (available))
466 else if (!negate_used
467 && used <= TYPE_MAXIMUM (uintmax_t) / 100
468 && used + available != 0
469 && (used + available < used) == negate_available)
471 uintmax_t u100 = used * 100;
472 uintmax_t nonroot_total = used + available;
473 pct = u100 / nonroot_total + (u100 % nonroot_total != 0);
475 else
477 /* The calculation cannot be done easily with integer
478 arithmetic. Fall back on floating point. This can suffer
479 from minor rounding errors, but doing it exactly requires
480 multiple precision arithmetic, and it's not worth the
481 aggravation. */
482 double u = negate_used ? - (double) - used : used;
483 double a = negate_available ? - (double) - available : available;
484 double nonroot_total = u + a;
485 if (nonroot_total)
487 long int lipct = pct = u * 100 / nonroot_total;
488 double ipct = lipct;
490 /* Like `pct = ceil (dpct);', but avoid ceil so that
491 the math library needn't be linked. */
492 if (ipct - 1 < pct && pct <= ipct + 1)
493 pct = ipct + (ipct < pct);
497 if (0 <= pct)
498 printf ("%*.0f%%", use_width - 1, pct);
499 else
500 printf ("%*s", use_width, "- ");
502 if (mount_point)
504 #ifdef HIDE_AUTOMOUNT_PREFIX
505 /* Don't print the first directory name in MOUNT_POINT if it's an
506 artifact of an automounter. This is a bit too aggressive to be
507 the default. */
508 if (strncmp ("/auto/", mount_point, 6) == 0)
509 mount_point += 5;
510 else if (strncmp ("/tmp_mnt/", mount_point, 9) == 0)
511 mount_point += 8;
512 #endif
513 printf (" %s", mount_point);
515 putchar ('\n');
518 /* Return the root mountpoint of the file system on which FILE exists, in
519 malloced storage. FILE_STAT should be the result of stating FILE.
520 Give a diagnostic and return NULL if unable to determine the mount point.
521 Exit if unable to restore current working directory. */
522 static char *
523 find_mount_point (const char *file, const struct stat *file_stat)
525 struct saved_cwd cwd;
526 struct stat last_stat;
527 char *mp = NULL; /* The malloced mount point. */
529 if (save_cwd (&cwd) != 0)
531 error (0, errno, _("cannot get current directory"));
532 return NULL;
535 if (S_ISDIR (file_stat->st_mode))
536 /* FILE is a directory, so just chdir there directly. */
538 last_stat = *file_stat;
539 if (chdir (file) < 0)
541 error (0, errno, _("cannot change to directory %s"), quote (file));
542 return NULL;
545 else
546 /* FILE is some other kind of file; use its directory. */
548 char *xdir = dir_name (file);
549 char *dir;
550 ASSIGN_STRDUPA (dir, xdir);
551 free (xdir);
553 if (chdir (dir) < 0)
555 error (0, errno, _("cannot change to directory %s"), quote (dir));
556 return NULL;
559 if (stat (".", &last_stat) < 0)
561 error (0, errno, _("cannot stat current directory (now %s)"),
562 quote (dir));
563 goto done;
567 /* Now walk up FILE's parents until we find another file system or /,
568 chdiring as we go. LAST_STAT holds stat information for the last place
569 we visited. */
570 for (;;)
572 struct stat st;
573 if (stat ("..", &st) < 0)
575 error (0, errno, _("cannot stat %s"), quote (".."));
576 goto done;
578 if (st.st_dev != last_stat.st_dev || st.st_ino == last_stat.st_ino)
579 /* cwd is the mount point. */
580 break;
581 if (chdir ("..") < 0)
583 error (0, errno, _("cannot change to directory %s"), quote (".."));
584 goto done;
586 last_stat = st;
589 /* Finally reached a mount point, see what it's called. */
590 mp = xgetcwd ();
592 done:
593 /* Restore the original cwd. */
595 int save_errno = errno;
596 if (restore_cwd (&cwd) != 0)
597 error (EXIT_FAILURE, errno,
598 _("failed to return to initial working directory"));
599 free_cwd (&cwd);
600 errno = save_errno;
603 return mp;
606 /* If DISK corresponds to a mount point, show its usage
607 and return true. Otherwise, return false. */
608 static bool
609 show_disk (char const *disk)
611 struct mount_entry const *me;
612 struct mount_entry const *best_match = NULL;
614 for (me = mount_list; me; me = me->me_next)
615 if (STREQ (disk, me->me_devname))
616 best_match = me;
618 if (best_match)
620 show_dev (best_match->me_devname, best_match->me_mountdir, NULL,
621 best_match->me_type, best_match->me_dummy,
622 best_match->me_remote, NULL);
623 return true;
626 return false;
629 /* Figure out which device file or directory POINT is mounted on
630 and show its disk usage.
631 STATP must be the result of `stat (POINT, STATP)'. */
632 static void
633 show_point (const char *point, const struct stat *statp)
635 struct stat disk_stats;
636 struct mount_entry *me;
637 struct mount_entry const *best_match = NULL;
639 /* If POINT is an absolute file name, see if we can find the
640 mount point without performing any extra stat calls at all. */
641 if (*point == '/')
643 /* Find the best match: prefer non-dummies, and then prefer the
644 last match if there are ties. */
646 for (me = mount_list; me; me = me->me_next)
647 if (STREQ (me->me_mountdir, point) && !STREQ (me->me_type, "lofs")
648 && (!best_match || best_match->me_dummy || !me->me_dummy))
649 best_match = me;
652 /* Calculate the real absolute file name for POINT, and use that to find
653 the mount point. This avoids statting unavailable mount points,
654 which can hang df. */
655 if (! best_match)
657 char *resolved = canonicalize_file_name (point);
659 if (resolved && resolved[0] == '/')
661 size_t resolved_len = strlen (resolved);
662 size_t best_match_len = 0;
664 for (me = mount_list; me; me = me->me_next)
665 if (!STREQ (me->me_type, "lofs")
666 && (!best_match || best_match->me_dummy || !me->me_dummy))
668 size_t len = strlen (me->me_mountdir);
669 if (best_match_len <= len && len <= resolved_len
670 && (len == 1 /* root file system */
671 || ((len == resolved_len || resolved[len] == '/')
672 && strncmp (me->me_mountdir, resolved, len) == 0)))
674 best_match = me;
675 best_match_len = len;
680 free (resolved);
682 if (best_match
683 && (stat (best_match->me_mountdir, &disk_stats) != 0
684 || disk_stats.st_dev != statp->st_dev))
685 best_match = NULL;
688 if (! best_match)
689 for (me = mount_list; me; me = me->me_next)
691 if (me->me_dev == (dev_t) -1)
693 if (stat (me->me_mountdir, &disk_stats) == 0)
694 me->me_dev = disk_stats.st_dev;
695 else
697 /* Report only I/O errors. Other errors might be
698 caused by shadowed mount points, which means POINT
699 can't possibly be on this file system. */
700 if (errno == EIO)
702 error (0, errno, "%s", quote (me->me_mountdir));
703 exit_status = EXIT_FAILURE;
706 /* So we won't try and fail repeatedly. */
707 me->me_dev = (dev_t) -2;
711 if (statp->st_dev == me->me_dev
712 && !STREQ (me->me_type, "lofs")
713 && (!best_match || best_match->me_dummy || !me->me_dummy))
715 /* Skip bogus mtab entries. */
716 if (stat (me->me_mountdir, &disk_stats) != 0
717 || disk_stats.st_dev != me->me_dev)
718 me->me_dev = (dev_t) -2;
719 else
720 best_match = me;
724 if (best_match)
725 show_dev (best_match->me_devname, best_match->me_mountdir, point,
726 best_match->me_type, best_match->me_dummy, best_match->me_remote,
727 NULL);
728 else
730 /* We couldn't find the mount entry corresponding to POINT. Go ahead and
731 print as much info as we can; methods that require the device to be
732 present will fail at a later point. */
734 /* Find the actual mount point. */
735 char *mp = find_mount_point (point, statp);
736 if (mp)
738 show_dev (NULL, mp, NULL, NULL, false, false, NULL);
739 free (mp);
744 /* Determine what kind of node NAME is and show the disk usage
745 for it. STATP is the results of `stat' on NAME. */
747 static void
748 show_entry (char const *name, struct stat const *statp)
750 if ((S_ISBLK (statp->st_mode) || S_ISCHR (statp->st_mode))
751 && show_disk (name))
752 return;
754 show_point (name, statp);
757 /* Show all mounted file systems, except perhaps those that are of
758 an unselected type or are empty. */
760 static void
761 show_all_entries (void)
763 struct mount_entry *me;
765 for (me = mount_list; me; me = me->me_next)
766 show_dev (me->me_devname, me->me_mountdir, NULL, me->me_type,
767 me->me_dummy, me->me_remote, NULL);
770 /* Add FSTYPE to the list of file system types to display. */
772 static void
773 add_fs_type (const char *fstype)
775 struct fs_type_list *fsp;
777 fsp = xmalloc (sizeof *fsp);
778 fsp->fs_name = (char *) fstype;
779 fsp->fs_next = fs_select_list;
780 fs_select_list = fsp;
783 /* Add FSTYPE to the list of file system types to be omitted. */
785 static void
786 add_excluded_fs_type (const char *fstype)
788 struct fs_type_list *fsp;
790 fsp = xmalloc (sizeof *fsp);
791 fsp->fs_name = (char *) fstype;
792 fsp->fs_next = fs_exclude_list;
793 fs_exclude_list = fsp;
796 void
797 usage (int status)
799 if (status != EXIT_SUCCESS)
800 fprintf (stderr, _("Try `%s --help' for more information.\n"),
801 program_name);
802 else
804 printf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name);
805 fputs (_("\
806 Show information about the file system on which each FILE resides,\n\
807 or all file systems by default.\n\
809 "), stdout);
810 fputs (_("\
811 Mandatory arguments to long options are mandatory for short options too.\n\
812 "), stdout);
813 fputs (_("\
814 -a, --all include dummy file systems\n\
815 -B, --block-size=SIZE use SIZE-byte blocks\n\
816 --total produce a grand total\n\
817 -h, --human-readable print sizes in human readable format (e.g., 1K 234M 2G)\n\
818 -H, --si likewise, but use powers of 1000 not 1024\n\
819 "), stdout);
820 fputs (_("\
821 -i, --inodes list inode information instead of block usage\n\
822 -k like --block-size=1K\n\
823 -l, --local limit listing to local file systems\n\
824 --no-sync do not invoke sync before getting usage info (default)\n\
825 "), stdout);
826 fputs (_("\
827 -P, --portability use the POSIX output format\n\
828 --sync invoke sync before getting usage info\n\
829 -t, --type=TYPE limit listing to file systems of type TYPE\n\
830 -T, --print-type print file system type\n\
831 -x, --exclude-type=TYPE limit listing to file systems not of type TYPE\n\
832 -v (ignored)\n\
833 "), stdout);
834 fputs (HELP_OPTION_DESCRIPTION, stdout);
835 fputs (VERSION_OPTION_DESCRIPTION, stdout);
836 fputs (_("\n\
837 SIZE may be (or may be an integer optionally followed by) one of following:\n\
838 kB 1000, K 1024, MB 1000*1000, M 1024*1024, and so on for G, T, P, E, Z, Y.\n\
839 "), stdout);
840 emit_bug_reporting_address ();
842 exit (status);
846 main (int argc, char **argv)
848 struct stat *stats IF_LINT (= 0);
850 initialize_main (&argc, &argv);
851 set_program_name (argv[0]);
852 setlocale (LC_ALL, "");
853 bindtextdomain (PACKAGE, LOCALEDIR);
854 textdomain (PACKAGE);
856 atexit (close_stdout);
858 fs_select_list = NULL;
859 fs_exclude_list = NULL;
860 inode_format = false;
861 show_all_fs = false;
862 show_listed_fs = false;
863 human_output_opts = -1;
864 print_type = false;
865 file_systems_processed = false;
866 posix_format = false;
867 exit_status = EXIT_SUCCESS;
868 print_grand_total = false;
869 grand_fsu.fsu_blocksize = 1;
871 for (;;)
873 int oi = -1;
874 int c = getopt_long (argc, argv, "aB:iF:hHklmPTt:vx:", long_options,
875 &oi);
876 if (c == -1)
877 break;
879 switch (c)
881 case 'a':
882 show_all_fs = true;
883 break;
884 case 'B':
886 enum strtol_error e = human_options (optarg, &human_output_opts,
887 &output_block_size);
888 if (e != LONGINT_OK)
889 xstrtol_fatal (e, oi, c, long_options, optarg);
891 break;
892 case 'i':
893 inode_format = true;
894 break;
895 case 'h':
896 human_output_opts = human_autoscale | human_SI | human_base_1024;
897 output_block_size = 1;
898 break;
899 case 'H':
900 human_output_opts = human_autoscale | human_SI;
901 output_block_size = 1;
902 break;
903 case 'k':
904 human_output_opts = 0;
905 output_block_size = 1024;
906 break;
907 case 'l':
908 show_local_fs = true;
909 break;
910 case 'm': /* obsolescent */
911 human_output_opts = 0;
912 output_block_size = 1024 * 1024;
913 break;
914 case 'T':
915 print_type = true;
916 break;
917 case 'P':
918 posix_format = true;
919 break;
920 case SYNC_OPTION:
921 require_sync = true;
922 break;
923 case NO_SYNC_OPTION:
924 require_sync = false;
925 break;
927 case 'F':
928 /* Accept -F as a synonym for -t for compatibility with Solaris. */
929 case 't':
930 add_fs_type (optarg);
931 break;
933 case 'v': /* For SysV compatibility. */
934 /* ignore */
935 break;
936 case 'x':
937 add_excluded_fs_type (optarg);
938 break;
940 case 'c':
941 print_grand_total = true;
942 break;
944 case_GETOPT_HELP_CHAR;
945 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
947 default:
948 usage (EXIT_FAILURE);
952 if (human_output_opts == -1)
954 if (posix_format)
956 human_output_opts = 0;
957 output_block_size = (getenv ("POSIXLY_CORRECT") ? 512 : 1024);
959 else
960 human_options (getenv ("DF_BLOCK_SIZE"),
961 &human_output_opts, &output_block_size);
964 /* Fail if the same file system type was both selected and excluded. */
966 bool match = false;
967 struct fs_type_list *fs_incl;
968 for (fs_incl = fs_select_list; fs_incl; fs_incl = fs_incl->fs_next)
970 struct fs_type_list *fs_excl;
971 for (fs_excl = fs_exclude_list; fs_excl; fs_excl = fs_excl->fs_next)
973 if (STREQ (fs_incl->fs_name, fs_excl->fs_name))
975 error (0, 0,
976 _("file system type %s both selected and excluded"),
977 quote (fs_incl->fs_name));
978 match = true;
979 break;
983 if (match)
984 exit (EXIT_FAILURE);
987 if (optind < argc)
989 int i;
991 /* Open each of the given entries to make sure any corresponding
992 partition is automounted. This must be done before reading the
993 file system table. */
994 stats = xnmalloc (argc - optind, sizeof *stats);
995 for (i = optind; i < argc; ++i)
997 int fd = open (argv[i], O_RDONLY | O_NOCTTY);
998 if (fd < 0 || fstat (fd, &stats[i - optind]))
1000 error (0, errno, "%s", quote (argv[i]));
1001 exit_status = EXIT_FAILURE;
1002 argv[i] = NULL;
1004 if (0 <= fd)
1005 close (fd);
1009 mount_list =
1010 read_file_system_list ((fs_select_list != NULL
1011 || fs_exclude_list != NULL
1012 || print_type
1013 || show_local_fs));
1015 if (mount_list == NULL)
1017 /* Couldn't read the table of mounted file systems.
1018 Fail if df was invoked with no file name arguments;
1019 Otherwise, merely give a warning and proceed. */
1020 int status = (optind < argc ? 0 : EXIT_FAILURE);
1021 const char *warning = (optind < argc ? _("Warning: ") : "");
1022 error (status, errno, "%s%s", warning,
1023 _("cannot read table of mounted file systems"));
1026 if (require_sync)
1027 sync ();
1029 if (optind < argc)
1031 int i;
1033 /* Display explicitly requested empty file systems. */
1034 show_listed_fs = true;
1036 for (i = optind; i < argc; ++i)
1037 if (argv[i])
1038 show_entry (argv[i], &stats[i - optind]);
1040 else
1041 show_all_entries ();
1043 if (print_grand_total)
1045 if (inode_format)
1046 grand_fsu.fsu_blocks = 1;
1047 show_dev ("total", NULL, NULL, NULL, false, false, &grand_fsu);
1050 if (! file_systems_processed)
1051 error (EXIT_FAILURE, 0, _("no file systems processed"));
1053 exit (exit_status);