build: use getgr*_nomembers functions on Interix
[coreutils/ericb.git] / src / df.c
blob982d6074228be9d37a2d19cc200ff656f4c7ae3c
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>
25 #include <assert.h>
27 #include "system.h"
28 #include "error.h"
29 #include "fsusage.h"
30 #include "human.h"
31 #include "mbsalign.h"
32 #include "mbswidth.h"
33 #include "mountlist.h"
34 #include "quote.h"
35 #include "find-mount-point.h"
37 /* The official name of this program (e.g., no `g' prefix). */
38 #define PROGRAM_NAME "df"
40 #define AUTHORS \
41 proper_name_utf8 ("Torbjorn Granlund", "Torbj\303\266rn Granlund"), \
42 proper_name ("David MacKenzie"), \
43 proper_name ("Paul Eggert")
45 /* If true, show inode information. */
46 static bool inode_format;
48 /* If true, show even file systems with zero size or
49 uninteresting types. */
50 static bool show_all_fs;
52 /* If true, show only local file systems. */
53 static bool show_local_fs;
55 /* If true, output data for each file system corresponding to a
56 command line argument -- even if it's a dummy (automounter) entry. */
57 static bool show_listed_fs;
59 /* Human-readable options for output. */
60 static int human_output_opts;
62 /* The units to use when printing sizes. */
63 static uintmax_t output_block_size;
65 /* If true, use the POSIX output format. */
66 static bool posix_format;
68 /* True if a file system has been processed for output. */
69 static bool file_systems_processed;
71 /* If true, invoke the `sync' system call before getting any usage data.
72 Using this option can make df very slow, especially with many or very
73 busy disks. Note that this may make a difference on some systems --
74 SunOS 4.1.3, for one. It is *not* necessary on GNU/Linux. */
75 static bool require_sync;
77 /* Desired exit status. */
78 static int exit_status;
80 /* A file system type to display. */
82 struct fs_type_list
84 char *fs_name;
85 struct fs_type_list *fs_next;
88 /* Linked list of file system types to display.
89 If `fs_select_list' is NULL, list all types.
90 This table is generated dynamically from command-line options,
91 rather than hardcoding into the program what it thinks are the
92 valid file system types; let the user specify any file system type
93 they want to, and if there are any file systems of that type, they
94 will be shown.
96 Some file system types:
97 4.2 4.3 ufs nfs swap ignore io vm efs dbg */
99 static struct fs_type_list *fs_select_list;
101 /* Linked list of file system types to omit.
102 If the list is empty, don't exclude any types. */
104 static struct fs_type_list *fs_exclude_list;
106 /* Linked list of mounted file systems. */
107 static struct mount_entry *mount_list;
109 /* If true, print file system type as well. */
110 static bool print_type;
112 /* If true, print a grand total at the end. */
113 static bool print_grand_total;
115 /* Grand total data. */
116 static struct fs_usage grand_fsu;
118 /* Display modes. */
119 enum { DEFAULT_MODE, INODES_MODE, HUMAN_MODE, POSIX_MODE, NMODES };
120 static int header_mode = DEFAULT_MODE;
122 /* Displayable fields. */
123 enum
125 DEV_FIELD, /* file system */
126 TYPE_FIELD, /* FS type */
127 TOTAL_FIELD, /* blocks or inodes */
128 USED_FIELD, /* ditto */
129 FREE_FIELD, /* ditto */
130 PCENT_FIELD, /* percent used */
131 MNT_FIELD, /* mount point */
132 NFIELDS
135 /* Header strings for the above fields in each mode.
136 NULL means to use the header for the default mode. */
137 static const char *headers[NFIELDS][NMODES] = {
138 /* DEFAULT_MODE INODES_MODE HUMAN_MODE POSIX_MODE */
139 { N_("Filesystem"), NULL, NULL, NULL },
140 { N_("Type"), NULL, NULL, NULL },
141 { N_("blocks"), N_("Inodes"), N_("Size"), NULL },
142 { N_("Used"), N_("IUsed"), NULL, NULL },
143 { N_("Available"), N_("IFree"), N_("Avail"), NULL },
144 { N_("Use%"), N_("IUse%"), NULL, N_("Capacity") },
145 { N_("Mounted on"), NULL, NULL, NULL }
148 /* Alignments for the 3 textual and 4 numeric fields. */
149 static mbs_align_t alignments[NFIELDS] = {
150 MBS_ALIGN_LEFT, MBS_ALIGN_LEFT,
151 MBS_ALIGN_RIGHT, MBS_ALIGN_RIGHT, MBS_ALIGN_RIGHT, MBS_ALIGN_RIGHT,
152 MBS_ALIGN_LEFT
155 /* Auto adjusted (up) widths used to align columns. */
156 static size_t widths[NFIELDS] = { 14, 4, 5, 5, 5, 4, 0 };
158 /* Storage for pointers for each string (cell of table). */
159 static char ***table;
161 /* The current number of processed rows (including header). */
162 static size_t nrows;
164 /* For long options that have no equivalent short option, use a
165 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
166 enum
168 NO_SYNC_OPTION = CHAR_MAX + 1,
169 SYNC_OPTION
172 static struct option const long_options[] =
174 {"all", no_argument, NULL, 'a'},
175 {"block-size", required_argument, NULL, 'B'},
176 {"inodes", no_argument, NULL, 'i'},
177 {"human-readable", no_argument, NULL, 'h'},
178 {"si", no_argument, NULL, 'H'},
179 {"local", no_argument, NULL, 'l'},
180 {"megabytes", no_argument, NULL, 'm'}, /* obsolescent */
181 {"portability", no_argument, NULL, 'P'},
182 {"print-type", no_argument, NULL, 'T'},
183 {"sync", no_argument, NULL, SYNC_OPTION},
184 {"no-sync", no_argument, NULL, NO_SYNC_OPTION},
185 {"total", no_argument, NULL, 'c'},
186 {"type", required_argument, NULL, 't'},
187 {"exclude-type", required_argument, NULL, 'x'},
188 {GETOPT_HELP_OPTION_DECL},
189 {GETOPT_VERSION_OPTION_DECL},
190 {NULL, 0, NULL, 0}
193 /* Dynamically allocate a row of pointers in TABLE, which
194 can then be accessed with standard 2D array notation. */
196 static void
197 alloc_table_row (void)
199 nrows++;
200 table = xnrealloc (table, nrows, sizeof (char *));
201 table[nrows-1] = xnmalloc (NFIELDS, sizeof (char *));
204 /* Output each cell in the table, accounting for the
205 alignment and max width of each column. */
207 static void
208 print_table (void)
210 size_t field, row;
212 for (row = 0; row < nrows; row ++)
214 for (field = 0; field < NFIELDS; field++)
216 size_t width = widths[field];
217 char *cell = table[row][field];
218 if (!cell) /* Missing type column, or mount point etc. */
219 continue;
221 /* Note the DEV_FIELD used to be displayed on it's own line
222 if (!posix_format && mbswidth (cell) > 20), but that
223 functionality is probably more problematic than helpful. */
224 if (field != 0)
225 putchar (' ');
226 if (field == MNT_FIELD) /* The last one. */
227 fputs (cell, stdout);
228 else
230 cell = ambsalign (cell, &width, alignments[field], 0);
231 /* When ambsalign fails, output unaligned data. */
232 fputs (cell ? cell : table[row][field], stdout);
233 free (cell);
235 IF_LINT (free (table[row][field]));
237 putchar ('\n');
238 IF_LINT (free (table[row]));
241 IF_LINT (free (table));
244 /* Obtain the appropriate header entries. */
246 static void
247 get_header (void)
249 size_t field;
251 alloc_table_row ();
253 for (field = 0; field < NFIELDS; field++)
255 if (field == TYPE_FIELD && !print_type)
257 table[nrows-1][field] = NULL;
258 continue;
261 char *cell = NULL;
262 char const *header = _(headers[field][header_mode]);
263 if (!header)
264 header = _(headers[field][DEFAULT_MODE]);
266 if (header_mode == DEFAULT_MODE && field == TOTAL_FIELD)
268 char buf[LONGEST_HUMAN_READABLE + 1];
270 int opts = (human_suppress_point_zero
271 | human_autoscale | human_SI
272 | (human_output_opts
273 & (human_group_digits | human_base_1024 | human_B)));
275 /* Prefer the base that makes the human-readable value more exact,
276 if there is a difference. */
278 uintmax_t q1000 = output_block_size;
279 uintmax_t q1024 = output_block_size;
280 bool divisible_by_1000;
281 bool divisible_by_1024;
285 divisible_by_1000 = q1000 % 1000 == 0; q1000 /= 1000;
286 divisible_by_1024 = q1024 % 1024 == 0; q1024 /= 1024;
288 while (divisible_by_1000 & divisible_by_1024);
290 if (divisible_by_1000 < divisible_by_1024)
291 opts |= human_base_1024;
292 if (divisible_by_1024 < divisible_by_1000)
293 opts &= ~human_base_1024;
294 if (! (opts & human_base_1024))
295 opts |= human_B;
297 char *num = human_readable (output_block_size, buf, opts, 1, 1);
299 if (asprintf (&cell, "%s-%s", num, header) == -1)
300 cell = NULL;
302 else if (header_mode == POSIX_MODE && field == TOTAL_FIELD)
304 char buf[INT_BUFSIZE_BOUND (uintmax_t)];
305 char *num = umaxtostr (output_block_size, buf);
307 if (asprintf (&cell, "%s-%s", num, header) == -1)
308 cell = NULL;
310 else
311 cell = strdup (header);
313 if (!cell)
314 xalloc_die ();
316 table[nrows-1][field] = cell;
318 widths[field] = MAX (widths[field], mbswidth (cell, 0));
322 /* Is FSTYPE a type of file system that should be listed? */
324 static bool _GL_ATTRIBUTE_PURE
325 selected_fstype (const char *fstype)
327 const struct fs_type_list *fsp;
329 if (fs_select_list == NULL || fstype == NULL)
330 return true;
331 for (fsp = fs_select_list; fsp; fsp = fsp->fs_next)
332 if (STREQ (fstype, fsp->fs_name))
333 return true;
334 return false;
337 /* Is FSTYPE a type of file system that should be omitted? */
339 static bool _GL_ATTRIBUTE_PURE
340 excluded_fstype (const char *fstype)
342 const struct fs_type_list *fsp;
344 if (fs_exclude_list == NULL || fstype == NULL)
345 return false;
346 for (fsp = fs_exclude_list; fsp; fsp = fsp->fs_next)
347 if (STREQ (fstype, fsp->fs_name))
348 return true;
349 return false;
352 /* Return true if N is a known integer value. On many file systems,
353 UINTMAX_MAX represents an unknown value; on AIX, UINTMAX_MAX - 1
354 represents unknown. Use a rule that works on AIX file systems, and
355 that almost-always works on other types. */
356 static bool
357 known_value (uintmax_t n)
359 return n < UINTMAX_MAX - 1;
362 /* Like human_readable (N, BUF, human_output_opts, INPUT_UNITS, OUTPUT_UNITS),
363 except:
365 - If NEGATIVE, then N represents a negative number,
366 expressed in two's complement.
367 - Otherwise, return "-" if N is unknown. */
369 static char const *
370 df_readable (bool negative, uintmax_t n, char *buf,
371 uintmax_t input_units, uintmax_t output_units)
373 if (! known_value (n) && !negative)
374 return "-";
375 else
377 char *p = human_readable (negative ? -n : n, buf + negative,
378 human_output_opts, input_units, output_units);
379 if (negative)
380 *--p = '-';
381 return p;
385 /* Logical equivalence */
386 #define LOG_EQ(a, b) (!(a) == !(b))
388 /* Add integral value while using uintmax_t for value part and separate
389 negation flag. It adds value of SRC and SRC_NEG to DEST and DEST_NEG.
390 The result will be in DEST and DEST_NEG. See df_readable to understand
391 how the negation flag is used. */
392 static void
393 add_uint_with_neg_flag (uintmax_t *dest, bool *dest_neg,
394 uintmax_t src, bool src_neg)
396 if (LOG_EQ (*dest_neg, src_neg))
398 *dest += src;
399 return;
402 if (*dest_neg)
403 *dest = -*dest;
405 if (src_neg)
406 src = -src;
408 if (src < *dest)
409 *dest -= src;
410 else
412 *dest = src - *dest;
413 *dest_neg = src_neg;
416 if (*dest_neg)
417 *dest = -*dest;
420 /* Obtain a space listing for the disk device with absolute file name DISK.
421 If MOUNT_POINT is non-NULL, it is the name of the root of the
422 file system on DISK.
423 If STAT_FILE is non-null, it is the name of a file within the file
424 system that the user originally asked for; this provides better
425 diagnostics, and sometimes it provides better results on networked
426 file systems that give different free-space results depending on
427 where in the file system you probe.
428 If FSTYPE is non-NULL, it is the type of the file system on DISK.
429 If MOUNT_POINT is non-NULL, then DISK may be NULL -- certain systems may
430 not be able to produce statistics in this case.
431 ME_DUMMY and ME_REMOTE are the mount entry flags. */
433 static void
434 get_dev (char const *disk, char const *mount_point,
435 char const *stat_file, char const *fstype,
436 bool me_dummy, bool me_remote,
437 const struct fs_usage *force_fsu)
439 struct fs_usage fsu;
440 char buf[LONGEST_HUMAN_READABLE + 2];
441 uintmax_t input_units;
442 uintmax_t output_units;
443 uintmax_t total;
444 uintmax_t available;
445 bool negate_available;
446 uintmax_t available_to_root;
447 uintmax_t used;
448 bool negate_used;
449 double pct = -1;
450 char* cell;
451 size_t field;
453 if (me_remote && show_local_fs)
454 return;
456 if (me_dummy && !show_all_fs && !show_listed_fs)
457 return;
459 if (!selected_fstype (fstype) || excluded_fstype (fstype))
460 return;
462 /* If MOUNT_POINT is NULL, then the file system is not mounted, and this
463 program reports on the file system that the special file is on.
464 It would be better to report on the unmounted file system,
465 but statfs doesn't do that on most systems. */
466 if (!stat_file)
467 stat_file = mount_point ? mount_point : disk;
469 if (force_fsu)
470 fsu = *force_fsu;
471 else if (get_fs_usage (stat_file, disk, &fsu))
473 error (0, errno, "%s", quote (stat_file));
474 exit_status = EXIT_FAILURE;
475 return;
478 if (fsu.fsu_blocks == 0 && !show_all_fs && !show_listed_fs)
479 return;
481 if (! file_systems_processed)
483 file_systems_processed = true;
484 get_header ();
487 alloc_table_row ();
489 if (! disk)
490 disk = "-"; /* unknown */
491 if (! fstype)
492 fstype = "-"; /* unknown */
494 if (inode_format)
496 input_units = output_units = 1;
497 total = fsu.fsu_files;
498 available = fsu.fsu_ffree;
499 negate_available = false;
500 available_to_root = available;
502 if (known_value (total))
503 grand_fsu.fsu_files += total;
504 if (known_value (available))
505 grand_fsu.fsu_ffree += available;
507 else
509 input_units = fsu.fsu_blocksize;
510 output_units = output_block_size;
511 total = fsu.fsu_blocks;
512 available = fsu.fsu_bavail;
513 negate_available = (fsu.fsu_bavail_top_bit_set
514 && known_value (available));
515 available_to_root = fsu.fsu_bfree;
517 if (known_value (total))
518 grand_fsu.fsu_blocks += input_units * total;
519 if (known_value (available_to_root))
520 grand_fsu.fsu_bfree += input_units * available_to_root;
521 if (known_value (available))
522 add_uint_with_neg_flag (&grand_fsu.fsu_bavail,
523 &grand_fsu.fsu_bavail_top_bit_set,
524 input_units * available, negate_available);
527 used = UINTMAX_MAX;
528 negate_used = false;
529 if (known_value (total) && known_value (available_to_root))
531 used = total - available_to_root;
532 negate_used = (total < available_to_root);
535 for (field = 0; field < NFIELDS; field++)
537 switch (field)
539 case DEV_FIELD:
540 cell = xstrdup (disk);
541 break;
543 case TYPE_FIELD:
544 cell = print_type ? xstrdup (fstype) : NULL;
545 break;
547 case TOTAL_FIELD:
548 cell = xstrdup (df_readable (false, total, buf,
549 input_units, output_units));
550 break;
551 case USED_FIELD:
552 cell = xstrdup (df_readable (negate_used, used, buf,
553 input_units, output_units));
554 break;
555 case FREE_FIELD:
556 cell = xstrdup (df_readable (negate_available, available, buf,
557 input_units, output_units));
558 break;
560 case PCENT_FIELD:
561 if (! known_value (used) || ! known_value (available))
563 else if (!negate_used
564 && used <= TYPE_MAXIMUM (uintmax_t) / 100
565 && used + available != 0
566 && (used + available < used) == negate_available)
568 uintmax_t u100 = used * 100;
569 uintmax_t nonroot_total = used + available;
570 pct = u100 / nonroot_total + (u100 % nonroot_total != 0);
572 else
574 /* The calculation cannot be done easily with integer
575 arithmetic. Fall back on floating point. This can suffer
576 from minor rounding errors, but doing it exactly requires
577 multiple precision arithmetic, and it's not worth the
578 aggravation. */
579 double u = negate_used ? - (double) - used : used;
580 double a = negate_available ? - (double) - available : available;
581 double nonroot_total = u + a;
582 if (nonroot_total)
584 long int lipct = pct = u * 100 / nonroot_total;
585 double ipct = lipct;
587 /* Like `pct = ceil (dpct);', but avoid ceil so that
588 the math library needn't be linked. */
589 if (ipct - 1 < pct && pct <= ipct + 1)
590 pct = ipct + (ipct < pct);
594 if (0 <= pct)
596 if (asprintf (&cell, "%.0f%%", pct) == -1)
597 cell = NULL;
599 else
600 cell = strdup ("-");
602 if (!cell)
603 xalloc_die ();
605 break;
607 case MNT_FIELD:
608 if (mount_point)
610 #ifdef HIDE_AUTOMOUNT_PREFIX
611 /* Don't print the first directory name in MOUNT_POINT if it's an
612 artifact of an automounter. This is a bit too aggressive to be
613 the default. */
614 if (STRNCMP_LIT (mount_point, "/auto/") == 0)
615 mount_point += 5;
616 else if (STRNCMP_LIT (mount_point, "/tmp_mnt/") == 0)
617 mount_point += 8;
618 #endif
619 cell = xstrdup (mount_point);
621 else
622 cell = NULL;
623 break;
625 default:
626 assert (!"unhandled field");
629 if (cell)
630 widths[field] = MAX (widths[field], mbswidth (cell, 0));
631 table[nrows-1][field] = cell;
635 /* If DISK corresponds to a mount point, show its usage
636 and return true. Otherwise, return false. */
637 static bool
638 get_disk (char const *disk)
640 struct mount_entry const *me;
641 struct mount_entry const *best_match = NULL;
643 for (me = mount_list; me; me = me->me_next)
644 if (STREQ (disk, me->me_devname))
645 best_match = me;
647 if (best_match)
649 get_dev (best_match->me_devname, best_match->me_mountdir, NULL,
650 best_match->me_type, best_match->me_dummy,
651 best_match->me_remote, NULL);
652 return true;
655 return false;
658 /* Figure out which device file or directory POINT is mounted on
659 and show its disk usage.
660 STATP must be the result of `stat (POINT, STATP)'. */
661 static void
662 get_point (const char *point, const struct stat *statp)
664 struct stat disk_stats;
665 struct mount_entry *me;
666 struct mount_entry const *best_match = NULL;
668 /* Calculate the real absolute file name for POINT, and use that to find
669 the mount point. This avoids statting unavailable mount points,
670 which can hang df. */
671 char *resolved = canonicalize_file_name (point);
672 if (resolved && resolved[0] == '/')
674 size_t resolved_len = strlen (resolved);
675 size_t best_match_len = 0;
677 for (me = mount_list; me; me = me->me_next)
678 if (!STREQ (me->me_type, "lofs")
679 && (!best_match || best_match->me_dummy || !me->me_dummy))
681 size_t len = strlen (me->me_mountdir);
682 if (best_match_len <= len && len <= resolved_len
683 && (len == 1 /* root file system */
684 || ((len == resolved_len || resolved[len] == '/')
685 && STREQ_LEN (me->me_mountdir, resolved, len))))
687 best_match = me;
688 best_match_len = len;
692 free (resolved);
693 if (best_match
694 && (stat (best_match->me_mountdir, &disk_stats) != 0
695 || disk_stats.st_dev != statp->st_dev))
696 best_match = NULL;
698 if (! best_match)
699 for (me = mount_list; me; me = me->me_next)
701 if (me->me_dev == (dev_t) -1)
703 if (stat (me->me_mountdir, &disk_stats) == 0)
704 me->me_dev = disk_stats.st_dev;
705 else
707 /* Report only I/O errors. Other errors might be
708 caused by shadowed mount points, which means POINT
709 can't possibly be on this file system. */
710 if (errno == EIO)
712 error (0, errno, "%s", quote (me->me_mountdir));
713 exit_status = EXIT_FAILURE;
716 /* So we won't try and fail repeatedly. */
717 me->me_dev = (dev_t) -2;
721 if (statp->st_dev == me->me_dev
722 && !STREQ (me->me_type, "lofs")
723 && (!best_match || best_match->me_dummy || !me->me_dummy))
725 /* Skip bogus mtab entries. */
726 if (stat (me->me_mountdir, &disk_stats) != 0
727 || disk_stats.st_dev != me->me_dev)
728 me->me_dev = (dev_t) -2;
729 else
730 best_match = me;
734 if (best_match)
735 get_dev (best_match->me_devname, best_match->me_mountdir, point,
736 best_match->me_type, best_match->me_dummy, best_match->me_remote,
737 NULL);
738 else
740 /* We couldn't find the mount entry corresponding to POINT. Go ahead and
741 print as much info as we can; methods that require the device to be
742 present will fail at a later point. */
744 /* Find the actual mount point. */
745 char *mp = find_mount_point (point, statp);
746 if (mp)
748 get_dev (NULL, mp, NULL, NULL, false, false, NULL);
749 free (mp);
754 /* Determine what kind of node NAME is and show the disk usage
755 for it. STATP is the results of `stat' on NAME. */
757 static void
758 get_entry (char const *name, struct stat const *statp)
760 if ((S_ISBLK (statp->st_mode) || S_ISCHR (statp->st_mode))
761 && get_disk (name))
762 return;
764 get_point (name, statp);
767 /* Show all mounted file systems, except perhaps those that are of
768 an unselected type or are empty. */
770 static void
771 get_all_entries (void)
773 struct mount_entry *me;
775 for (me = mount_list; me; me = me->me_next)
776 get_dev (me->me_devname, me->me_mountdir, NULL, me->me_type,
777 me->me_dummy, me->me_remote, NULL);
780 /* Add FSTYPE to the list of file system types to display. */
782 static void
783 add_fs_type (const char *fstype)
785 struct fs_type_list *fsp;
787 fsp = xmalloc (sizeof *fsp);
788 fsp->fs_name = (char *) fstype;
789 fsp->fs_next = fs_select_list;
790 fs_select_list = fsp;
793 /* Add FSTYPE to the list of file system types to be omitted. */
795 static void
796 add_excluded_fs_type (const char *fstype)
798 struct fs_type_list *fsp;
800 fsp = xmalloc (sizeof *fsp);
801 fsp->fs_name = (char *) fstype;
802 fsp->fs_next = fs_exclude_list;
803 fs_exclude_list = fsp;
806 void
807 usage (int status)
809 if (status != EXIT_SUCCESS)
810 fprintf (stderr, _("Try `%s --help' for more information.\n"),
811 program_name);
812 else
814 printf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name);
815 fputs (_("\
816 Show information about the file system on which each FILE resides,\n\
817 or all file systems by default.\n\
819 "), stdout);
820 fputs (_("\
821 Mandatory arguments to long options are mandatory for short options too.\n\
822 "), stdout);
823 fputs (_("\
824 -a, --all include dummy file systems\n\
825 -B, --block-size=SIZE scale sizes by SIZE before printing them. E.g.,\n\
826 `-BM' prints sizes in units of 1,048,576 bytes.\n\
827 See SIZE format below.\n\
828 --total produce a grand total\n\
829 -h, --human-readable print sizes in human readable format (e.g., 1K 234M 2G)\
831 -H, --si likewise, but use powers of 1000 not 1024\n\
832 "), stdout);
833 fputs (_("\
834 -i, --inodes list inode information instead of block usage\n\
835 -k like --block-size=1K\n\
836 -l, --local limit listing to local file systems\n\
837 --no-sync do not invoke sync before getting usage info (default)\
839 "), stdout);
840 fputs (_("\
841 -P, --portability use the POSIX output format\n\
842 --sync invoke sync before getting usage info\n\
843 -t, --type=TYPE limit listing to file systems of type TYPE\n\
844 -T, --print-type print file system type\n\
845 -x, --exclude-type=TYPE limit listing to file systems not of type TYPE\n\
846 -v (ignored)\n\
847 "), stdout);
848 fputs (HELP_OPTION_DESCRIPTION, stdout);
849 fputs (VERSION_OPTION_DESCRIPTION, stdout);
850 emit_blocksize_note ("DF");
851 emit_size_note ();
852 emit_ancillary_info ();
854 exit (status);
858 main (int argc, char **argv)
860 struct stat *stats IF_LINT ( = 0);
862 initialize_main (&argc, &argv);
863 set_program_name (argv[0]);
864 setlocale (LC_ALL, "");
865 bindtextdomain (PACKAGE, LOCALEDIR);
866 textdomain (PACKAGE);
868 atexit (close_stdout);
870 fs_select_list = NULL;
871 fs_exclude_list = NULL;
872 inode_format = false;
873 show_all_fs = false;
874 show_listed_fs = false;
875 human_output_opts = -1;
876 print_type = false;
877 file_systems_processed = false;
878 posix_format = false;
879 exit_status = EXIT_SUCCESS;
880 print_grand_total = false;
881 grand_fsu.fsu_blocksize = 1;
883 while (true)
885 int oi = -1;
886 int c = getopt_long (argc, argv, "aB:iF:hHklmPTt:vx:", long_options,
887 &oi);
888 if (c == -1)
889 break;
891 switch (c)
893 case 'a':
894 show_all_fs = true;
895 break;
896 case 'B':
898 enum strtol_error e = human_options (optarg, &human_output_opts,
899 &output_block_size);
900 if (e != LONGINT_OK)
901 xstrtol_fatal (e, oi, c, long_options, optarg);
903 break;
904 case 'i':
905 inode_format = true;
906 break;
907 case 'h':
908 human_output_opts = human_autoscale | human_SI | human_base_1024;
909 output_block_size = 1;
910 break;
911 case 'H':
912 human_output_opts = human_autoscale | human_SI;
913 output_block_size = 1;
914 break;
915 case 'k':
916 human_output_opts = 0;
917 output_block_size = 1024;
918 break;
919 case 'l':
920 show_local_fs = true;
921 break;
922 case 'm': /* obsolescent */
923 human_output_opts = 0;
924 output_block_size = 1024 * 1024;
925 break;
926 case 'T':
927 print_type = true;
928 break;
929 case 'P':
930 posix_format = true;
931 break;
932 case SYNC_OPTION:
933 require_sync = true;
934 break;
935 case NO_SYNC_OPTION:
936 require_sync = false;
937 break;
939 case 'F':
940 /* Accept -F as a synonym for -t for compatibility with Solaris. */
941 case 't':
942 add_fs_type (optarg);
943 break;
945 case 'v': /* For SysV compatibility. */
946 /* ignore */
947 break;
948 case 'x':
949 add_excluded_fs_type (optarg);
950 break;
952 case 'c':
953 print_grand_total = true;
954 break;
956 case_GETOPT_HELP_CHAR;
957 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
959 default:
960 usage (EXIT_FAILURE);
964 if (human_output_opts == -1)
966 if (posix_format)
968 human_output_opts = 0;
969 output_block_size = (getenv ("POSIXLY_CORRECT") ? 512 : 1024);
971 else
972 human_options (getenv ("DF_BLOCK_SIZE"),
973 &human_output_opts, &output_block_size);
976 if (inode_format)
977 header_mode = INODES_MODE;
978 else if (human_output_opts & human_autoscale)
979 header_mode = HUMAN_MODE;
980 else if (posix_format)
981 header_mode = POSIX_MODE;
983 /* Fail if the same file system type was both selected and excluded. */
985 bool match = false;
986 struct fs_type_list *fs_incl;
987 for (fs_incl = fs_select_list; fs_incl; fs_incl = fs_incl->fs_next)
989 struct fs_type_list *fs_excl;
990 for (fs_excl = fs_exclude_list; fs_excl; fs_excl = fs_excl->fs_next)
992 if (STREQ (fs_incl->fs_name, fs_excl->fs_name))
994 error (0, 0,
995 _("file system type %s both selected and excluded"),
996 quote (fs_incl->fs_name));
997 match = true;
998 break;
1002 if (match)
1003 exit (EXIT_FAILURE);
1006 if (optind < argc)
1008 int i;
1010 /* Open each of the given entries to make sure any corresponding
1011 partition is automounted. This must be done before reading the
1012 file system table. */
1013 stats = xnmalloc (argc - optind, sizeof *stats);
1014 for (i = optind; i < argc; ++i)
1016 /* Prefer to open with O_NOCTTY and use fstat, but fall back
1017 on using "stat", in case the file is unreadable. */
1018 int fd = open (argv[i], O_RDONLY | O_NOCTTY);
1019 if ((fd < 0 || fstat (fd, &stats[i - optind]))
1020 && stat (argv[i], &stats[i - optind]))
1022 error (0, errno, "%s", quote (argv[i]));
1023 exit_status = EXIT_FAILURE;
1024 argv[i] = NULL;
1026 if (0 <= fd)
1027 close (fd);
1031 mount_list =
1032 read_file_system_list ((fs_select_list != NULL
1033 || fs_exclude_list != NULL
1034 || print_type
1035 || show_local_fs));
1037 if (mount_list == NULL)
1039 /* Couldn't read the table of mounted file systems.
1040 Fail if df was invoked with no file name arguments;
1041 Otherwise, merely give a warning and proceed. */
1042 int status = (optind < argc ? 0 : EXIT_FAILURE);
1043 const char *warning = (optind < argc ? _("Warning: ") : "");
1044 error (status, errno, "%s%s", warning,
1045 _("cannot read table of mounted file systems"));
1048 if (require_sync)
1049 sync ();
1051 if (optind < argc)
1053 int i;
1055 /* Display explicitly requested empty file systems. */
1056 show_listed_fs = true;
1058 for (i = optind; i < argc; ++i)
1059 if (argv[i])
1060 get_entry (argv[i], &stats[i - optind]);
1062 else
1063 get_all_entries ();
1065 if (print_grand_total)
1067 if (inode_format)
1068 grand_fsu.fsu_blocks = 1;
1069 get_dev ("total", NULL, NULL, NULL, false, false, &grand_fsu);
1072 print_table ();
1074 if (! file_systems_processed)
1075 error (EXIT_FAILURE, 0, _("no file systems processed"));
1077 exit (exit_status);