1 /* df - summarize free disk space
2 Copyright (C) 91, 1995-2003 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. */
28 #include <sys/types.h>
33 #include "canonicalize.h"
39 #include "mountlist.h"
40 #include "path-concat.h"
45 /* The official name of this program (e.g., no `g' prefix). */
46 #define PROGRAM_NAME "df"
49 N_ ("Torbjorn Granlund, David MacKenzie, Larry McVoy, and Paul Eggert")
51 /* Name this program was run with. */
54 /* If nonzero, show inode information. */
55 static int inode_format
;
57 /* If nonzero, show even filesystems with zero size or
58 uninteresting types. */
59 static int show_all_fs
;
61 /* If nonzero, show only local filesystems. */
62 static int show_local_fs
;
64 /* If nonzero, output data for each filesystem corresponding to a
65 command line argument -- even if it's a dummy (automounter) entry. */
66 static int show_listed_fs
;
68 /* Human-readable options for output. */
69 static int human_output_opts
;
71 /* The units to use when printing sizes. */
72 static uintmax_t output_block_size
;
74 /* If nonzero, use the POSIX output format. */
75 static int posix_format
;
77 /* If nonzero, invoke the `sync' system call before getting any usage data.
78 Using this option can make df very slow, especially with many or very
79 busy disks. Note that this may make a difference on some systems --
80 SunOs4.1.3, for one. It is *not* necessary on Linux. */
81 static int require_sync
= 0;
83 /* Nonzero if errors have occurred. */
84 static int exit_status
;
86 /* A filesystem type to display. */
91 struct fs_type_list
*fs_next
;
94 /* Linked list of filesystem types to display.
95 If `fs_select_list' is NULL, list all types.
96 This table is generated dynamically from command-line options,
97 rather than hardcoding into the program what it thinks are the
98 valid filesystem types; let the user specify any filesystem type
99 they want to, and if there are any filesystems of that type, they
102 Some filesystem types:
103 4.2 4.3 ufs nfs swap ignore io vm efs dbg */
105 static struct fs_type_list
*fs_select_list
;
107 /* Linked list of filesystem types to omit.
108 If the list is empty, don't exclude any types. */
110 static struct fs_type_list
*fs_exclude_list
;
112 /* Linked list of mounted filesystems. */
113 static struct mount_entry
*mount_list
;
115 /* If nonzero, print filesystem type as well. */
116 static int print_type
;
118 /* For long options that have no equivalent short option, use a
119 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
122 SYNC_OPTION
= CHAR_MAX
+ 1,
126 static struct option
const long_options
[] =
128 {"all", no_argument
, NULL
, 'a'},
129 {"block-size", required_argument
, NULL
, 'B'},
130 {"inodes", no_argument
, NULL
, 'i'},
131 {"human-readable", no_argument
, NULL
, 'h'},
132 {"si", no_argument
, NULL
, 'H'},
133 {"kilobytes", no_argument
, NULL
, 'k'}, /* long form is obsolescent */
134 {"local", no_argument
, NULL
, 'l'},
135 {"megabytes", no_argument
, NULL
, 'm'}, /* obsolescent */
136 {"portability", no_argument
, NULL
, 'P'},
137 {"print-type", no_argument
, NULL
, 'T'},
138 {"sync", no_argument
, NULL
, SYNC_OPTION
},
139 {"no-sync", no_argument
, NULL
, NO_SYNC_OPTION
},
140 {"type", required_argument
, NULL
, 't'},
141 {"exclude-type", required_argument
, NULL
, 'x'},
142 {GETOPT_HELP_OPTION_DECL
},
143 {GETOPT_VERSION_OPTION_DECL
},
150 char buf
[MAX (LONGEST_HUMAN_READABLE
+ 1, INT_BUFSIZE_BOUND (uintmax_t))];
152 printf (_("Filesystem "));
160 printf (_(" Inodes IUsed IFree IUse%%"));
161 else if (human_output_opts
& human_autoscale
)
163 if (human_output_opts
& human_base_1024
)
164 printf (_(" Size Used Avail Use%%"));
166 printf (_(" Size Used Avail Use%%"));
168 else if (posix_format
)
169 printf (_(" %4s-blocks Used Available Capacity"),
170 umaxtostr (output_block_size
, buf
));
173 int opts
= (human_suppress_point_zero
174 | human_autoscale
| human_SI
176 & (human_group_digits
| human_base_1024
| human_B
)));
178 /* Prefer the base that makes the human-readable value more exact,
179 if there is a difference. */
181 uintmax_t q1000
= output_block_size
;
182 uintmax_t q1024
= output_block_size
;
183 bool divisible_by_1000
;
184 bool divisible_by_1024
;
188 divisible_by_1000
= q1000
% 1000 == 0; q1000
/= 1000;
189 divisible_by_1024
= q1024
% 1024 == 0; q1024
/= 1024;
191 while (divisible_by_1000
& divisible_by_1024
);
193 if (divisible_by_1000
< divisible_by_1024
)
194 opts
|= human_base_1024
;
195 if (divisible_by_1024
< divisible_by_1000
)
196 opts
&= ~human_base_1024
;
197 if (! (opts
& human_base_1024
))
200 printf (_(" %4s-blocks Used Available Use%%"),
201 human_readable (output_block_size
, buf
, opts
, 1, 1));
204 printf (_(" Mounted on\n"));
207 /* If FSTYPE is a type of filesystem that should be listed,
208 return nonzero, else zero. */
211 selected_fstype (const char *fstype
)
213 const struct fs_type_list
*fsp
;
215 if (fs_select_list
== NULL
|| fstype
== NULL
)
217 for (fsp
= fs_select_list
; fsp
; fsp
= fsp
->fs_next
)
218 if (STREQ (fstype
, fsp
->fs_name
))
223 /* If FSTYPE is a type of filesystem that should be omitted,
224 return nonzero, else zero. */
227 excluded_fstype (const char *fstype
)
229 const struct fs_type_list
*fsp
;
231 if (fs_exclude_list
== NULL
|| fstype
== NULL
)
233 for (fsp
= fs_exclude_list
; fsp
; fsp
= fsp
->fs_next
)
234 if (STREQ (fstype
, fsp
->fs_name
))
239 /* Like human_readable (N, BUF, human_output_opts, INPUT_UNITS, OUTPUT_UNITS),
242 - Return "-" if N is -1,
243 - If NEGATIVE is 1 then N represents a negative number,
244 expressed in two's complement. */
247 df_readable (int negative
, uintmax_t n
, char *buf
,
248 uintmax_t input_units
, uintmax_t output_units
)
254 char *p
= human_readable (negative
? -n
: n
, buf
+ negative
,
255 human_output_opts
, input_units
, output_units
);
262 /* Display a space listing for the disk device with absolute path DISK.
263 If MOUNT_POINT is non-NULL, it is the path of the root of the
265 If FSTYPE is non-NULL, it is the type of the filesystem on DISK.
266 If MOUNT_POINT is non-NULL, then DISK may be NULL -- certain systems may
267 not be able to produce statistics in this case.
268 ME_DUMMY and ME_REMOTE are the mount entry flags. */
271 show_dev (const char *disk
, const char *mount_point
, const char *fstype
,
272 int me_dummy
, int me_remote
)
275 const char *stat_file
;
276 char buf
[3][LONGEST_HUMAN_READABLE
+ 2];
279 uintmax_t input_units
;
280 uintmax_t output_units
;
283 int negate_available
;
284 uintmax_t available_to_root
;
289 if (me_remote
&& show_local_fs
)
292 if (me_dummy
&& show_all_fs
== 0 && !show_listed_fs
)
295 if (!selected_fstype (fstype
) || excluded_fstype (fstype
))
298 /* If MOUNT_POINT is NULL, then the filesystem is not mounted, and this
299 program reports on the filesystem that the special file is on.
300 It would be better to report on the unmounted filesystem,
301 but statfs doesn't do that on most systems. */
302 stat_file
= mount_point
? mount_point
: disk
;
304 if (get_fs_usage (stat_file
, disk
, &fsu
))
306 error (0, errno
, "%s", quote (stat_file
));
311 if (fsu
.fsu_blocks
== 0 && !show_all_fs
&& !show_listed_fs
)
315 disk
= "-"; /* unknown */
317 fstype
= "-"; /* unknown */
319 /* df.c reserved 5 positions for fstype,
320 but that does not suffice for type iso9660 */
323 int disk_name_len
= (int) strlen (disk
);
324 int fstype_len
= (int) strlen (fstype
);
325 if (disk_name_len
+ fstype_len
+ 2 < 20)
326 printf ("%s%*s ", disk
, 18 - disk_name_len
, fstype
);
327 else if (!posix_format
)
328 printf ("%s\n%18s ", disk
, fstype
);
330 printf ("%s %s", disk
, fstype
);
334 if ((int) strlen (disk
) > 20 && !posix_format
)
335 printf ("%s\n%20s", disk
, "");
337 printf ("%-20s", disk
);
344 input_units
= output_units
= 1;
345 total
= fsu
.fsu_files
;
346 available
= fsu
.fsu_ffree
;
347 negate_available
= 0;
348 available_to_root
= available
;
352 width
= (human_output_opts
& human_autoscale
353 ? 5 + ! (human_output_opts
& human_base_1024
)
355 use_width
= ((posix_format
356 && ! (human_output_opts
& human_autoscale
))
358 input_units
= fsu
.fsu_blocksize
;
359 output_units
= output_block_size
;
360 total
= fsu
.fsu_blocks
;
361 available
= fsu
.fsu_bavail
;
362 negate_available
= fsu
.fsu_bavail_top_bit_set
;
363 available_to_root
= fsu
.fsu_bfree
;
368 if (total
!= -1 && available_to_root
!= -1)
370 used
= total
- available_to_root
;
371 if (total
< available_to_root
)
378 printf (" %*s %*s %*s ",
379 width
, df_readable (0, total
,
380 buf
[0], input_units
, output_units
),
381 width
, df_readable (negate_used
, used
,
382 buf
[1], input_units
, output_units
),
383 width
, df_readable (negate_available
, available
,
384 buf
[2], input_units
, output_units
));
386 if (used
== -1 || available
== -1)
388 else if (!negate_used
389 && used
<= TYPE_MAXIMUM (uintmax_t) / 100
390 && used
+ available
!= 0
391 && (used
+ available
< used
) == negate_available
)
393 uintmax_t u100
= used
* 100;
394 uintmax_t nonroot_total
= used
+ available
;
395 pct
= u100
/ nonroot_total
+ (u100
% nonroot_total
!= 0);
399 /* The calculation cannot be done easily with integer
400 arithmetic. Fall back on floating point. This can suffer
401 from minor rounding errors, but doing it exactly requires
402 multiple precision arithmetic, and it's not worth the
404 double u
= negate_used
? - (double) - used
: used
;
405 double a
= negate_available
? - (double) - available
: available
;
406 double nonroot_total
= u
+ a
;
410 pct
= u
* 100 / nonroot_total
;
413 /* Like `pct = ceil (dpct);', but avoid ceil so that
414 the math library needn't be linked. */
415 if (ipct
- 1 < pct
&& pct
<= ipct
+ 1)
416 pct
= ipct
+ (ipct
< pct
);
421 printf ("%*.0f%%", use_width
- 1, pct
);
423 printf ("%*s", use_width
, "- ");
427 #ifdef HIDE_AUTOMOUNT_PREFIX
428 /* Don't print the first directory name in MOUNT_POINT if it's an
429 artifact of an automounter. This is a bit too aggressive to be
431 if (strncmp ("/auto/", mount_point
, 6) == 0)
433 else if (strncmp ("/tmp_mnt/", mount_point
, 9) == 0)
436 printf (" %s", mount_point
);
441 /* Return the root mountpoint of the filesystem on which FILE exists, in
442 malloced storage. FILE_STAT should be the result of stating FILE. */
444 find_mount_point (const char *file
, const struct stat
*file_stat
)
446 struct saved_cwd cwd
;
447 struct stat last_stat
;
448 char *mp
= 0; /* The malloced mount point path. */
453 if (S_ISDIR (file_stat
->st_mode
))
454 /* FILE is a directory, so just chdir there directly. */
456 last_stat
= *file_stat
;
457 if (chdir (file
) < 0)
461 /* FILE is some other kind of file, we need to use its directory. */
463 char *dir
= dir_name (file
);
464 int rv
= chdir (dir
);
470 if (stat (".", &last_stat
) < 0)
474 /* Now walk up FILE's parents until we find another filesystem or /,
475 chdiring as we go. LAST_STAT holds stat information for the last place
480 if (stat ("..", &st
) < 0)
482 if (st
.st_dev
!= last_stat
.st_dev
|| st
.st_ino
== last_stat
.st_ino
)
483 /* cwd is the mount point. */
485 if (chdir ("..") < 0)
490 /* Finally reached a mount point, see what it's called. */
494 /* Restore the original cwd. */
496 int save_errno
= errno
;
497 if (restore_cwd (&cwd
, 0, mp
))
498 exit (EXIT_FAILURE
); /* We're scrod. */
506 /* Identify the directory, if any, that device
507 DISK is mounted on, and show its disk usage.
508 STATP must be the result of `stat (DISK, STATP)'. */
511 show_disk (const char *disk
, const struct stat
*statp
)
513 struct mount_entry
*me
;
516 for (me
= mount_list
; me
; me
= me
->me_next
)
517 if (STREQ (disk
, me
->me_devname
))
519 show_dev (me
->me_devname
, me
->me_mountdir
, me
->me_type
,
520 me
->me_dummy
, me
->me_remote
);
524 mount_point
= find_mount_point (disk
, statp
);
527 error (0, errno
, "%s", quote (disk
));
528 exit_status
= EXIT_FAILURE
;
531 /* No filesystem is mounted on DISK. */
532 show_dev (disk
, mount_point
, NULL
, 0, 0);
537 /* Figure out which device file or directory POINT is mounted on
538 and show its disk usage.
539 STATP must be the result of `stat (POINT, STATP)'. */
541 show_point (const char *point
, const struct stat
*statp
)
543 struct stat disk_stats
;
544 struct mount_entry
*me
;
545 struct mount_entry
*matching_dummy
= NULL
;
547 /* If POINT is an absolute path name, see if we can find the
548 mount point without performing any extra stat calls at all. */
551 for (me
= mount_list
; me
; me
= me
->me_next
)
553 if (STREQ (me
->me_mountdir
, point
) && !STREQ (me
->me_type
, "lofs"))
555 /* Prefer non-dummy entries. */
563 goto show_matching_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. */
570 char *resolved
= canonicalize_file_name (point
);
571 ssize_t resolved_len
= resolved
? strlen (resolved
) : -1;
572 struct mount_entry
*best_match
= NULL
;
574 if (1 <= resolved_len
&& resolved
[0] == '/')
576 size_t best_match_len
= 0;
578 for (me
= mount_list
; me
; me
= me
->me_next
)
581 size_t len
= strlen (me
->me_mountdir
);
582 if (best_match_len
< len
&& len
<= resolved_len
583 && (len
== 1 /* root file system */
584 || ((len
== resolved_len
|| resolved
[len
] == '/')
585 && strncmp (me
->me_mountdir
, resolved
, len
) == 0)))
588 best_match_len
= len
;
596 if (best_match
&& !STREQ (best_match
->me_type
, "lofs")
597 && stat (best_match
->me_mountdir
, &disk_stats
) == 0
598 && disk_stats
.st_dev
== statp
->st_dev
)
605 for (me
= mount_list
; me
; me
= me
->me_next
)
607 if (me
->me_dev
== (dev_t
) -1)
609 if (stat (me
->me_mountdir
, &disk_stats
) == 0)
610 me
->me_dev
= disk_stats
.st_dev
;
613 error (0, errno
, "%s", quote (me
->me_mountdir
));
615 /* So we won't try and fail repeatedly. */
616 me
->me_dev
= (dev_t
) -2;
620 if (statp
->st_dev
== me
->me_dev
)
622 /* Skip bogus mtab entries. */
623 if (stat (me
->me_mountdir
, &disk_stats
) != 0
624 || disk_stats
.st_dev
!= me
->me_dev
)
626 me
->me_dev
= (dev_t
) -2;
630 /* Prefer non-dummy entries. */
638 goto show_matching_dummy
;
640 /* We couldn't find the mount entry corresponding to POINT. Go ahead and
641 print as much info as we can; methods that require the device to be
642 present will fail at a later point. */
644 /* Find the actual mount point. */
645 char *mp
= find_mount_point (point
, statp
);
648 show_dev (0, mp
, 0, 0, 0);
652 error (0, errno
, "%s", quote (point
));
660 show_dev (me
->me_devname
, me
->me_mountdir
, me
->me_type
, me
->me_dummy
,
664 /* Determine what kind of node PATH is and show the disk usage
665 for it. STATP is the results of `stat' on PATH. */
668 show_entry (const char *path
, const struct stat
*statp
)
670 if (S_ISBLK (statp
->st_mode
) || S_ISCHR (statp
->st_mode
))
671 show_disk (path
, statp
);
673 show_point (path
, statp
);
676 /* Show all mounted filesystems, except perhaps those that are of
677 an unselected type or are empty. */
680 show_all_entries (void)
682 struct mount_entry
*me
;
684 for (me
= mount_list
; me
; me
= me
->me_next
)
685 show_dev (me
->me_devname
, me
->me_mountdir
, me
->me_type
,
686 me
->me_dummy
, me
->me_remote
);
689 /* Add FSTYPE to the list of filesystem types to display. */
692 add_fs_type (const char *fstype
)
694 struct fs_type_list
*fsp
;
696 fsp
= (struct fs_type_list
*) xmalloc (sizeof (struct fs_type_list
));
697 fsp
->fs_name
= (char *) fstype
;
698 fsp
->fs_next
= fs_select_list
;
699 fs_select_list
= fsp
;
702 /* Add FSTYPE to the list of filesystem types to be omitted. */
705 add_excluded_fs_type (const char *fstype
)
707 struct fs_type_list
*fsp
;
709 fsp
= (struct fs_type_list
*) xmalloc (sizeof (struct fs_type_list
));
710 fsp
->fs_name
= (char *) fstype
;
711 fsp
->fs_next
= fs_exclude_list
;
712 fs_exclude_list
= fsp
;
719 fprintf (stderr
, _("Try `%s --help' for more information.\n"),
723 printf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name
);
725 Show information about the filesystem on which each FILE resides,\n\
726 or all filesystems by default.\n\
730 Mandatory arguments to long options are mandatory for short options too.\n\
733 -a, --all include filesystems having 0 blocks\n\
734 -B, --block-size=SIZE use SIZE-byte blocks\n\
735 -h, --human-readable print sizes in human readable format (e.g., 1K 234M 2G)\n\
736 -H, --si likewise, but use powers of 1000 not 1024\n\
739 -i, --inodes list inode information instead of block usage\n\
740 -k like --block-size=1K\n\
741 -l, --local limit listing to local filesystems\n\
742 --no-sync do not invoke sync before getting usage info (default)\n\
745 -P, --portability use the POSIX output format\n\
746 --sync invoke sync before getting usage info\n\
747 -t, --type=TYPE limit listing to filesystems of type TYPE\n\
748 -T, --print-type print filesystem type\n\
749 -x, --exclude-type=TYPE limit listing to filesystems not of type TYPE\n\
752 fputs (HELP_OPTION_DESCRIPTION
, stdout
);
753 fputs (VERSION_OPTION_DESCRIPTION
, stdout
);
755 SIZE may be (or may be an integer optionally followed by) one of following:\n\
756 kB 1000, K 1024, MB 1,000,000, M 1,048,576, and so on for G, T, P, E, Z, Y.\n\
758 printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT
);
764 main (int argc
, char **argv
)
767 struct stat
*stats
IF_LINT (= 0);
768 int n_valid_args
= 0;
770 program_name
= argv
[0];
771 setlocale (LC_ALL
, "");
772 bindtextdomain (PACKAGE
, LOCALEDIR
);
773 textdomain (PACKAGE
);
775 atexit (close_stdout
);
777 fs_select_list
= NULL
;
778 fs_exclude_list
= NULL
;
783 human_output_opts
= human_options (getenv ("DF_BLOCK_SIZE"), false,
790 while ((c
= getopt_long (argc
, argv
, "aB:iF:hHklmPTt:vx:", long_options
, NULL
))
795 case 0: /* Long option. */
801 human_output_opts
= human_options (optarg
, true, &output_block_size
);
807 human_output_opts
= human_autoscale
| human_SI
| human_base_1024
;
808 output_block_size
= 1;
811 human_output_opts
= human_autoscale
| human_SI
;
812 output_block_size
= 1;
815 human_output_opts
= 0;
816 output_block_size
= 1024;
821 case 'm': /* obsolescent */
822 human_output_opts
= 0;
823 output_block_size
= 1024 * 1024;
839 /* Accept -F as a synonym for -t for compatibility with Solaris. */
841 add_fs_type (optarg
);
844 case 'v': /* For SysV compatibility. */
848 add_excluded_fs_type (optarg
);
851 case_GETOPT_HELP_CHAR
;
852 case_GETOPT_VERSION_CHAR (PROGRAM_NAME
, AUTHORS
);
855 usage (EXIT_FAILURE
);
859 /* Fail if the same file system type was both selected and excluded. */
862 struct fs_type_list
*fs_incl
;
863 for (fs_incl
= fs_select_list
; fs_incl
; fs_incl
= fs_incl
->fs_next
)
865 struct fs_type_list
*fs_excl
;
866 for (fs_excl
= fs_exclude_list
; fs_excl
; fs_excl
= fs_excl
->fs_next
)
868 if (STREQ (fs_incl
->fs_name
, fs_excl
->fs_name
))
871 _("file system type %s both selected and excluded"),
872 quote (fs_incl
->fs_name
));
885 /* stat all the given entries to make sure they get automounted,
886 if necessary, before reading the filesystem table. */
887 stats
= (struct stat
*)
888 xmalloc ((argc
- optind
) * sizeof (struct stat
));
889 for (i
= optind
; i
< argc
; ++i
)
891 if (stat (argv
[i
], &stats
[i
- optind
]))
893 error (0, errno
, "%s", quote (argv
[i
]));
905 read_filesystem_list ((fs_select_list
!= NULL
906 || fs_exclude_list
!= NULL
910 if (mount_list
== NULL
)
912 /* Couldn't read the table of mounted filesystems.
913 Fail if df was invoked with no file name arguments;
914 Otherwise, merely give a warning and proceed. */
915 const char *warning
= (optind
== argc
? "" : _("Warning: "));
916 int status
= (optind
== argc
? 1 : 0);
917 error (status
, errno
,
918 _("%scannot read table of mounted filesystems"), warning
);
933 /* Display explicitly requested empty filesystems. */
936 if (n_valid_args
> 0)
939 for (i
= optind
; i
< argc
; ++i
)
941 show_entry (argv
[i
], &stats
[i
- optind
]);