1 /* df - summarize free disk space
2 Copyright (C) 91, 1995-2004 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 2, or (at your option)
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, write to the Free Software Foundation,
16 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
18 /* Written by David MacKenzie <djm@gnu.ai.mit.edu>.
19 --human-readable and --megabyte options added by lm@sgi.com.
20 --si and large file support added by eggert@twinsun.com. */
24 #include <sys/types.h>
29 #include "canonicalize.h"
35 #include "mountlist.h"
36 #include "path-concat.h"
41 /* The official name of this program (e.g., no `g' prefix). */
42 #define PROGRAM_NAME "df"
45 "Torbjorn Granlund", "David MacKenzie", "Paul Eggert"
47 /* Name this program was run with. */
50 /* If true, show inode information. */
51 static bool inode_format
;
53 /* If true, show even file systems with zero size or
54 uninteresting types. */
55 static bool show_all_fs
;
57 /* If true, show only local file systems. */
58 static bool show_local_fs
;
60 /* If true, output data for each file system corresponding to a
61 command line argument -- even if it's a dummy (automounter) entry. */
62 static bool show_listed_fs
;
64 /* Human-readable options for output. */
65 static int human_output_opts
;
67 /* The units to use when printing sizes. */
68 static uintmax_t output_block_size
;
70 /* If true, use the POSIX output format. */
71 static bool posix_format
;
73 /* If true, invoke the `sync' system call before getting any usage data.
74 Using this option can make df very slow, especially with many or very
75 busy disks. Note that this may make a difference on some systems --
76 SunOS 4.1.3, for one. It is *not* necessary on Linux. */
77 static bool require_sync
;
79 /* Desired exit status. */
80 static int exit_status
;
82 /* A file system type to display. */
87 struct fs_type_list
*fs_next
;
90 /* Linked list of file system types to display.
91 If `fs_select_list' is NULL, list all types.
92 This table is generated dynamically from command-line options,
93 rather than hardcoding into the program what it thinks are the
94 valid file system types; let the user specify any file system type
95 they want to, and if there are any file systems of that type, they
98 Some file system types:
99 4.2 4.3 ufs nfs swap ignore io vm efs dbg */
101 static struct fs_type_list
*fs_select_list
;
103 /* Linked list of file system types to omit.
104 If the list is empty, don't exclude any types. */
106 static struct fs_type_list
*fs_exclude_list
;
108 /* Linked list of mounted file systems. */
109 static struct mount_entry
*mount_list
;
111 /* If true, print file system type as well. */
112 static bool print_type
;
114 /* For long options that have no equivalent short option, use a
115 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
118 SYNC_OPTION
= CHAR_MAX
+ 1,
122 static struct option
const long_options
[] =
124 {"all", no_argument
, NULL
, 'a'},
125 {"block-size", required_argument
, NULL
, 'B'},
126 {"inodes", no_argument
, NULL
, 'i'},
127 {"human-readable", no_argument
, NULL
, 'h'},
128 {"si", no_argument
, NULL
, 'H'},
129 {"kilobytes", no_argument
, NULL
, 'k'}, /* long form is obsolescent */
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 {"type", required_argument
, NULL
, 't'},
137 {"exclude-type", required_argument
, NULL
, 'x'},
138 {GETOPT_HELP_OPTION_DECL
},
139 {GETOPT_VERSION_OPTION_DECL
},
146 char buf
[MAX (LONGEST_HUMAN_READABLE
+ 1, INT_BUFSIZE_BOUND (uintmax_t))];
149 fputs (_("Filesystem Type"), stdout
);
151 fputs (_("Filesystem "), stdout
);
154 printf (_(" Inodes IUsed IFree IUse%%"));
155 else if (human_output_opts
& human_autoscale
)
157 if (human_output_opts
& human_base_1024
)
158 printf (_(" Size Used Avail Use%%"));
160 printf (_(" Size Used Avail Use%%"));
162 else if (posix_format
)
163 printf (_(" %4s-blocks Used Available Capacity"),
164 umaxtostr (output_block_size
, buf
));
167 int opts
= (human_suppress_point_zero
168 | human_autoscale
| human_SI
170 & (human_group_digits
| human_base_1024
| human_B
)));
172 /* Prefer the base that makes the human-readable value more exact,
173 if there is a difference. */
175 uintmax_t q1000
= output_block_size
;
176 uintmax_t q1024
= output_block_size
;
177 bool divisible_by_1000
;
178 bool divisible_by_1024
;
182 divisible_by_1000
= q1000
% 1000 == 0; q1000
/= 1000;
183 divisible_by_1024
= q1024
% 1024 == 0; q1024
/= 1024;
185 while (divisible_by_1000
& divisible_by_1024
);
187 if (divisible_by_1000
< divisible_by_1024
)
188 opts
|= human_base_1024
;
189 if (divisible_by_1024
< divisible_by_1000
)
190 opts
&= ~human_base_1024
;
191 if (! (opts
& human_base_1024
))
194 printf (_(" %4s-blocks Used Available Use%%"),
195 human_readable (output_block_size
, buf
, opts
, 1, 1));
198 printf (_(" Mounted on\n"));
201 /* Is FSTYPE a type of file system that should be listed? */
204 selected_fstype (const char *fstype
)
206 const struct fs_type_list
*fsp
;
208 if (fs_select_list
== NULL
|| fstype
== NULL
)
210 for (fsp
= fs_select_list
; fsp
; fsp
= fsp
->fs_next
)
211 if (STREQ (fstype
, fsp
->fs_name
))
216 /* Is FSTYPE a type of file system that should be omitted? */
219 excluded_fstype (const char *fstype
)
221 const struct fs_type_list
*fsp
;
223 if (fs_exclude_list
== NULL
|| fstype
== NULL
)
225 for (fsp
= fs_exclude_list
; fsp
; fsp
= fsp
->fs_next
)
226 if (STREQ (fstype
, fsp
->fs_name
))
231 /* Like human_readable (N, BUF, human_output_opts, INPUT_UNITS, OUTPUT_UNITS),
234 - Return "-" if N is -1,
235 - If NEGATIVE is 1 then N represents a negative number,
236 expressed in two's complement. */
239 df_readable (bool negative
, uintmax_t n
, char *buf
,
240 uintmax_t input_units
, uintmax_t output_units
)
242 if (n
== UINTMAX_MAX
)
246 char *p
= human_readable (negative
? -n
: n
, buf
+ negative
,
247 human_output_opts
, input_units
, output_units
);
254 /* Display a space listing for the disk device with absolute path DISK.
255 If MOUNT_POINT is non-NULL, it is the path of the root of the
257 If FSTYPE is non-NULL, it is the type of the file system on DISK.
258 If MOUNT_POINT is non-NULL, then DISK may be NULL -- certain systems may
259 not be able to produce statistics in this case.
260 ME_DUMMY and ME_REMOTE are the mount entry flags. */
263 show_dev (const char *disk
, const char *mount_point
, const char *fstype
,
264 bool me_dummy
, bool me_remote
)
267 const char *stat_file
;
268 char buf
[3][LONGEST_HUMAN_READABLE
+ 2];
271 uintmax_t input_units
;
272 uintmax_t output_units
;
275 bool negate_available
;
276 uintmax_t available_to_root
;
281 if (me_remote
& show_local_fs
)
284 if (me_dummy
& !show_all_fs
& !show_listed_fs
)
287 if (!selected_fstype (fstype
) || excluded_fstype (fstype
))
290 /* If MOUNT_POINT is NULL, then the file system is not mounted, and this
291 program reports on the file system that the special file is on.
292 It would be better to report on the unmounted file system,
293 but statfs doesn't do that on most systems. */
294 stat_file
= mount_point
? mount_point
: disk
;
296 if (get_fs_usage (stat_file
, disk
, &fsu
))
298 error (0, errno
, "%s", quote (stat_file
));
299 exit_status
= EXIT_FAILURE
;
303 if (fsu
.fsu_blocks
== 0 && !show_all_fs
&& !show_listed_fs
)
307 disk
= "-"; /* unknown */
309 fstype
= "-"; /* unknown */
311 /* df.c reserved 5 positions for fstype,
312 but that does not suffice for type iso9660 */
315 size_t disk_name_len
= strlen (disk
);
316 size_t fstype_len
= strlen (fstype
);
317 if (disk_name_len
+ fstype_len
< 18)
318 printf ("%s%*s ", disk
, 18 - (int) disk_name_len
, fstype
);
319 else if (!posix_format
)
320 printf ("%s\n%18s ", disk
, fstype
);
322 printf ("%s %s", disk
, fstype
);
326 if (strlen (disk
) > 20 && !posix_format
)
327 printf ("%s\n%20s", disk
, "");
329 printf ("%-20s", disk
);
336 input_units
= output_units
= 1;
337 total
= fsu
.fsu_files
;
338 available
= fsu
.fsu_ffree
;
339 negate_available
= false;
340 available_to_root
= available
;
344 width
= (human_output_opts
& human_autoscale
345 ? 5 + ! (human_output_opts
& human_base_1024
)
347 use_width
= ((posix_format
348 && ! (human_output_opts
& human_autoscale
))
350 input_units
= fsu
.fsu_blocksize
;
351 output_units
= output_block_size
;
352 total
= fsu
.fsu_blocks
;
353 available
= fsu
.fsu_bavail
;
354 negate_available
= fsu
.fsu_bavail_top_bit_set
;
355 available_to_root
= fsu
.fsu_bfree
;
360 if (total
!= UINTMAX_MAX
&& available_to_root
!= UINTMAX_MAX
)
362 used
= total
- available_to_root
;
363 if (total
< available_to_root
)
370 printf (" %*s %*s %*s ",
371 width
, df_readable (false, total
,
372 buf
[0], input_units
, output_units
),
373 width
, df_readable (negate_used
, used
,
374 buf
[1], input_units
, output_units
),
375 width
, df_readable (negate_available
, available
,
376 buf
[2], input_units
, output_units
));
378 if (used
== UINTMAX_MAX
|| available
== UINTMAX_MAX
)
380 else if (!negate_used
381 && used
<= TYPE_MAXIMUM (uintmax_t) / 100
382 && used
+ available
!= 0
383 && (used
+ available
< used
) == negate_available
)
385 uintmax_t u100
= used
* 100;
386 uintmax_t nonroot_total
= used
+ available
;
387 pct
= u100
/ nonroot_total
+ (u100
% nonroot_total
!= 0);
391 /* The calculation cannot be done easily with integer
392 arithmetic. Fall back on floating point. This can suffer
393 from minor rounding errors, but doing it exactly requires
394 multiple precision arithmetic, and it's not worth the
396 double u
= negate_used
? - (double) - used
: used
;
397 double a
= negate_available
? - (double) - available
: available
;
398 double nonroot_total
= u
+ a
;
401 long int lipct
= pct
= u
* 100 / nonroot_total
;
404 /* Like `pct = ceil (dpct);', but avoid ceil so that
405 the math library needn't be linked. */
406 if (ipct
- 1 < pct
&& pct
<= ipct
+ 1)
407 pct
= ipct
+ (ipct
< pct
);
412 printf ("%*.0f%%", use_width
- 1, pct
);
414 printf ("%*s", use_width
, "- ");
418 #ifdef HIDE_AUTOMOUNT_PREFIX
419 /* Don't print the first directory name in MOUNT_POINT if it's an
420 artifact of an automounter. This is a bit too aggressive to be
422 if (strncmp ("/auto/", mount_point
, 6) == 0)
424 else if (strncmp ("/tmp_mnt/", mount_point
, 9) == 0)
427 printf (" %s", mount_point
);
432 /* Return the root mountpoint of the file system on which FILE exists, in
433 malloced storage. FILE_STAT should be the result of stating FILE.
434 Give a diagnostic and return NULL if unable to determine the mount point.
435 Exit if unable to restore current working directory. */
437 find_mount_point (const char *file
, const struct stat
*file_stat
)
439 struct saved_cwd cwd
;
440 struct stat last_stat
;
441 char *mp
= 0; /* The malloced mount point path. */
443 if (save_cwd (&cwd
) != 0)
445 error (0, errno
, _("cannot get current directory"));
449 if (S_ISDIR (file_stat
->st_mode
))
450 /* FILE is a directory, so just chdir there directly. */
452 last_stat
= *file_stat
;
453 if (chdir (file
) < 0)
455 error (0, errno
, _("cannot change to directory %s"), quote (file
));
460 /* FILE is some other kind of file; use its directory. */
462 char *xdir
= dir_name (file
);
464 ASSIGN_STRDUPA (dir
, xdir
);
469 error (0, errno
, _("cannot change to directory %s"), quote (dir
));
473 if (stat (".", &last_stat
) < 0)
475 error (0, errno
, _("cannot stat current directory (now %s)"),
481 /* Now walk up FILE's parents until we find another file system or /,
482 chdiring as we go. LAST_STAT holds stat information for the last place
487 if (stat ("..", &st
) < 0)
489 error (0, errno
, _("cannot stat %s"), quote (".."));
492 if (st
.st_dev
!= last_stat
.st_dev
|| st
.st_ino
== last_stat
.st_ino
)
493 /* cwd is the mount point. */
495 if (chdir ("..") < 0)
497 error (0, errno
, _("cannot change to directory %s"), quote (".."));
503 /* Finally reached a mount point, see what it's called. */
507 /* Restore the original cwd. */
509 int save_errno
= errno
;
510 if (restore_cwd (&cwd
) != 0)
511 error (EXIT_FAILURE
, errno
,
512 _("failed to return to initial working directory"));
520 /* If DISK corresponds to a mount point, show its usage
521 and return true. Otherwise, return false. */
523 show_disk (char const *disk
)
525 struct mount_entry
const *me
;
526 struct mount_entry
const *best_match
= NULL
;
528 for (me
= mount_list
; me
; me
= me
->me_next
)
529 if (STREQ (disk
, me
->me_devname
))
534 show_dev (best_match
->me_devname
, best_match
->me_mountdir
,
535 best_match
->me_type
, best_match
->me_dummy
,
536 best_match
->me_remote
);
543 /* Figure out which device file or directory POINT is mounted on
544 and show its disk usage.
545 STATP must be the result of `stat (POINT, STATP)'. */
547 show_point (const char *point
, const struct stat
*statp
)
549 struct stat disk_stats
;
550 struct mount_entry
*me
;
551 struct mount_entry
const *best_match
= NULL
;
553 /* If POINT is an absolute path name, see if we can find the
554 mount point without performing any extra stat calls at all. */
557 /* Find the best match: prefer non-dummies, and then prefer the
558 last match if there are ties. */
560 for (me
= mount_list
; me
; me
= me
->me_next
)
561 if (STREQ (me
->me_mountdir
, point
) && !STREQ (me
->me_type
, "lofs")
562 && (!best_match
|| best_match
->me_dummy
|| !me
->me_dummy
))
566 /* Calculate the real absolute path for POINT, and use that to find
567 the mount point. This avoids statting unavailable mount points,
568 which can hang df. */
571 char *resolved
= canonicalize_file_name (point
);
573 if (resolved
&& resolved
[0] == '/')
575 size_t resolved_len
= strlen (resolved
);
576 size_t best_match_len
= 0;
578 for (me
= mount_list
; me
; me
= me
->me_next
)
579 if (!STREQ (me
->me_type
, "lofs")
580 && (!best_match
|| best_match
->me_dummy
|| !me
->me_dummy
))
582 size_t len
= strlen (me
->me_mountdir
);
583 if (best_match_len
<= len
&& len
<= resolved_len
584 && (len
== 1 /* root file system */
585 || ((len
== resolved_len
|| resolved
[len
] == '/')
586 && strncmp (me
->me_mountdir
, resolved
, len
) == 0)))
589 best_match_len
= len
;
598 && (stat (best_match
->me_mountdir
, &disk_stats
) != 0
599 || disk_stats
.st_dev
!= statp
->st_dev
))
604 for (me
= mount_list
; me
; me
= me
->me_next
)
606 if (me
->me_dev
== (dev_t
) -1)
608 if (stat (me
->me_mountdir
, &disk_stats
) == 0)
609 me
->me_dev
= disk_stats
.st_dev
;
612 error (0, errno
, "%s", quote (me
->me_mountdir
));
613 exit_status
= EXIT_FAILURE
;
614 /* So we won't try and fail repeatedly. */
615 me
->me_dev
= (dev_t
) -2;
619 if (statp
->st_dev
== me
->me_dev
620 && !STREQ (me
->me_type
, "lofs")
621 && (!best_match
|| best_match
->me_dummy
|| !me
->me_dummy
))
623 /* Skip bogus mtab entries. */
624 if (stat (me
->me_mountdir
, &disk_stats
) != 0
625 || disk_stats
.st_dev
!= me
->me_dev
)
626 me
->me_dev
= (dev_t
) -2;
633 show_dev (best_match
->me_devname
, best_match
->me_mountdir
,
634 best_match
->me_type
, best_match
->me_dummy
, best_match
->me_remote
);
637 /* We couldn't find the mount entry corresponding to POINT. Go ahead and
638 print as much info as we can; methods that require the device to be
639 present will fail at a later point. */
641 /* Find the actual mount point. */
642 char *mp
= find_mount_point (point
, statp
);
645 show_dev (0, mp
, 0, false, false);
651 /* Determine what kind of node PATH is and show the disk usage
652 for it. STATP is the results of `stat' on PATH. */
655 show_entry (const char *path
, const struct stat
*statp
)
657 if ((S_ISBLK (statp
->st_mode
) || S_ISCHR (statp
->st_mode
))
661 show_point (path
, statp
);
664 /* Show all mounted file systems, except perhaps those that are of
665 an unselected type or are empty. */
668 show_all_entries (void)
670 struct mount_entry
*me
;
672 for (me
= mount_list
; me
; me
= me
->me_next
)
673 show_dev (me
->me_devname
, me
->me_mountdir
, me
->me_type
,
674 me
->me_dummy
, me
->me_remote
);
677 /* Add FSTYPE to the list of file system types to display. */
680 add_fs_type (const char *fstype
)
682 struct fs_type_list
*fsp
;
684 fsp
= xmalloc (sizeof *fsp
);
685 fsp
->fs_name
= (char *) fstype
;
686 fsp
->fs_next
= fs_select_list
;
687 fs_select_list
= fsp
;
690 /* Add FSTYPE to the list of file system types to be omitted. */
693 add_excluded_fs_type (const char *fstype
)
695 struct fs_type_list
*fsp
;
697 fsp
= xmalloc (sizeof *fsp
);
698 fsp
->fs_name
= (char *) fstype
;
699 fsp
->fs_next
= fs_exclude_list
;
700 fs_exclude_list
= fsp
;
706 if (status
!= EXIT_SUCCESS
)
707 fprintf (stderr
, _("Try `%s --help' for more information.\n"),
711 printf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name
);
713 Show information about the file system on which each FILE resides,\n\
714 or all file systems by default.\n\
718 Mandatory arguments to long options are mandatory for short options too.\n\
721 -a, --all include file systems having 0 blocks\n\
722 -B, --block-size=SIZE use SIZE-byte blocks\n\
723 -h, --human-readable print sizes in human readable format (e.g., 1K 234M 2G)\n\
724 -H, --si likewise, but use powers of 1000 not 1024\n\
727 -i, --inodes list inode information instead of block usage\n\
728 -k like --block-size=1K\n\
729 -l, --local limit listing to local file systems\n\
730 --no-sync do not invoke sync before getting usage info (default)\n\
733 -P, --portability use the POSIX output format\n\
734 --sync invoke sync before getting usage info\n\
735 -t, --type=TYPE limit listing to file systems of type TYPE\n\
736 -T, --print-type print file system type\n\
737 -x, --exclude-type=TYPE limit listing to file systems not of type TYPE\n\
740 fputs (HELP_OPTION_DESCRIPTION
, stdout
);
741 fputs (VERSION_OPTION_DESCRIPTION
, stdout
);
743 SIZE may be (or may be an integer optionally followed by) one of following:\n\
744 kB 1000, K 1024, MB 1000*1000, M 1024*1024, and so on for G, T, P, E, Z, Y.\n\
746 printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT
);
752 main (int argc
, char **argv
)
755 struct stat
*stats
IF_LINT (= 0);
756 int n_valid_args
= 0;
758 initialize_main (&argc
, &argv
);
759 program_name
= argv
[0];
760 setlocale (LC_ALL
, "");
761 bindtextdomain (PACKAGE
, LOCALEDIR
);
762 textdomain (PACKAGE
);
764 atexit (close_stdout
);
766 fs_select_list
= NULL
;
767 fs_exclude_list
= NULL
;
768 inode_format
= false;
770 show_listed_fs
= false;
772 human_output_opts
= human_options (getenv ("DF_BLOCK_SIZE"), false,
776 posix_format
= false;
777 exit_status
= EXIT_SUCCESS
;
779 while ((c
= getopt_long (argc
, argv
, "aB:iF:hHklmPTt:vx:", long_options
, NULL
))
788 human_output_opts
= human_options (optarg
, true, &output_block_size
);
794 human_output_opts
= human_autoscale
| human_SI
| human_base_1024
;
795 output_block_size
= 1;
798 human_output_opts
= human_autoscale
| human_SI
;
799 output_block_size
= 1;
802 human_output_opts
= 0;
803 output_block_size
= 1024;
806 show_local_fs
= true;
808 case 'm': /* obsolescent */
809 human_output_opts
= 0;
810 output_block_size
= 1024 * 1024;
822 require_sync
= false;
826 /* Accept -F as a synonym for -t for compatibility with Solaris. */
828 add_fs_type (optarg
);
831 case 'v': /* For SysV compatibility. */
835 add_excluded_fs_type (optarg
);
838 case_GETOPT_HELP_CHAR
;
839 case_GETOPT_VERSION_CHAR (PROGRAM_NAME
, AUTHORS
);
842 usage (EXIT_FAILURE
);
846 /* Fail if the same file system type was both selected and excluded. */
849 struct fs_type_list
*fs_incl
;
850 for (fs_incl
= fs_select_list
; fs_incl
; fs_incl
= fs_incl
->fs_next
)
852 struct fs_type_list
*fs_excl
;
853 for (fs_excl
= fs_exclude_list
; fs_excl
; fs_excl
= fs_excl
->fs_next
)
855 if (STREQ (fs_incl
->fs_name
, fs_excl
->fs_name
))
858 _("file system type %s both selected and excluded"),
859 quote (fs_incl
->fs_name
));
873 /* stat all the given entries to make sure they get automounted,
874 if necessary, before reading the file system table. */
875 stats
= xnmalloc (argc
- optind
, sizeof *stats
);
876 for (i
= optind
; i
< argc
; ++i
)
878 if (stat (argv
[i
], &stats
[i
- optind
]))
880 error (0, errno
, "%s", quote (argv
[i
]));
881 exit_status
= EXIT_FAILURE
;
892 read_file_system_list ((fs_select_list
!= NULL
893 || fs_exclude_list
!= NULL
897 if (mount_list
== NULL
)
899 /* Couldn't read the table of mounted file systems.
900 Fail if df was invoked with no file name arguments;
901 Otherwise, merely give a warning and proceed. */
902 const char *warning
= (optind
< argc
? _("Warning: ") : "");
903 int status
= (optind
< argc
? 0 : EXIT_FAILURE
);
904 error (status
, errno
,
905 _("%scannot read table of mounted file systems"), warning
);
915 /* Display explicitly requested empty file systems. */
916 show_listed_fs
= true;
918 if (n_valid_args
> 0)
921 for (i
= optind
; i
< argc
; ++i
)
923 show_entry (argv
[i
], &stats
[i
- optind
]);