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 nonzero, show inode information. */
51 static int inode_format
;
53 /* If nonzero, show even filesystems with zero size or
54 uninteresting types. */
55 static int show_all_fs
;
57 /* If nonzero, show only local filesystems. */
58 static int show_local_fs
;
60 /* If nonzero, output data for each filesystem corresponding to a
61 command line argument -- even if it's a dummy (automounter) entry. */
62 static int 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 nonzero, use the POSIX output format. */
71 static int posix_format
;
73 /* If nonzero, 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 SunOs4.1.3, for one. It is *not* necessary on Linux. */
77 static int require_sync
= 0;
79 /* Nonzero if errors have occurred. */
80 static int exit_status
;
82 /* A filesystem type to display. */
87 struct fs_type_list
*fs_next
;
90 /* Linked list of filesystem 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 filesystem types; let the user specify any filesystem type
95 they want to, and if there are any filesystems of that type, they
98 Some filesystem 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 filesystem 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 filesystems. */
109 static struct mount_entry
*mount_list
;
111 /* If nonzero, print filesystem type as well. */
112 static int 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 /* If FSTYPE is a type of filesystem that should be listed,
202 return nonzero, else zero. */
205 selected_fstype (const char *fstype
)
207 const struct fs_type_list
*fsp
;
209 if (fs_select_list
== NULL
|| fstype
== NULL
)
211 for (fsp
= fs_select_list
; fsp
; fsp
= fsp
->fs_next
)
212 if (STREQ (fstype
, fsp
->fs_name
))
217 /* If FSTYPE is a type of filesystem that should be omitted,
218 return nonzero, else zero. */
221 excluded_fstype (const char *fstype
)
223 const struct fs_type_list
*fsp
;
225 if (fs_exclude_list
== NULL
|| fstype
== NULL
)
227 for (fsp
= fs_exclude_list
; fsp
; fsp
= fsp
->fs_next
)
228 if (STREQ (fstype
, fsp
->fs_name
))
233 /* Like human_readable (N, BUF, human_output_opts, INPUT_UNITS, OUTPUT_UNITS),
236 - Return "-" if N is -1,
237 - If NEGATIVE is 1 then N represents a negative number,
238 expressed in two's complement. */
241 df_readable (int negative
, uintmax_t n
, char *buf
,
242 uintmax_t input_units
, uintmax_t output_units
)
248 char *p
= human_readable (negative
? -n
: n
, buf
+ negative
,
249 human_output_opts
, input_units
, output_units
);
256 /* Display a space listing for the disk device with absolute path DISK.
257 If MOUNT_POINT is non-NULL, it is the path of the root of the
259 If FSTYPE is non-NULL, it is the type of the filesystem on DISK.
260 If MOUNT_POINT is non-NULL, then DISK may be NULL -- certain systems may
261 not be able to produce statistics in this case.
262 ME_DUMMY and ME_REMOTE are the mount entry flags. */
265 show_dev (const char *disk
, const char *mount_point
, const char *fstype
,
266 int me_dummy
, int me_remote
)
269 const char *stat_file
;
270 char buf
[3][LONGEST_HUMAN_READABLE
+ 2];
273 uintmax_t input_units
;
274 uintmax_t output_units
;
277 int negate_available
;
278 uintmax_t available_to_root
;
283 if (me_remote
&& show_local_fs
)
286 if (me_dummy
&& show_all_fs
== 0 && !show_listed_fs
)
289 if (!selected_fstype (fstype
) || excluded_fstype (fstype
))
292 /* If MOUNT_POINT is NULL, then the filesystem is not mounted, and this
293 program reports on the filesystem that the special file is on.
294 It would be better to report on the unmounted filesystem,
295 but statfs doesn't do that on most systems. */
296 stat_file
= mount_point
? mount_point
: disk
;
298 if (get_fs_usage (stat_file
, disk
, &fsu
))
300 error (0, errno
, "%s", quote (stat_file
));
305 if (fsu
.fsu_blocks
== 0 && !show_all_fs
&& !show_listed_fs
)
309 disk
= "-"; /* unknown */
311 fstype
= "-"; /* unknown */
313 /* df.c reserved 5 positions for fstype,
314 but that does not suffice for type iso9660 */
317 int disk_name_len
= (int) strlen (disk
);
318 int fstype_len
= (int) strlen (fstype
);
319 if (disk_name_len
+ fstype_len
+ 2 < 20)
320 printf ("%s%*s ", disk
, 18 - disk_name_len
, fstype
);
321 else if (!posix_format
)
322 printf ("%s\n%18s ", disk
, fstype
);
324 printf ("%s %s", disk
, fstype
);
328 if ((int) strlen (disk
) > 20 && !posix_format
)
329 printf ("%s\n%20s", disk
, "");
331 printf ("%-20s", disk
);
338 input_units
= output_units
= 1;
339 total
= fsu
.fsu_files
;
340 available
= fsu
.fsu_ffree
;
341 negate_available
= 0;
342 available_to_root
= available
;
346 width
= (human_output_opts
& human_autoscale
347 ? 5 + ! (human_output_opts
& human_base_1024
)
349 use_width
= ((posix_format
350 && ! (human_output_opts
& human_autoscale
))
352 input_units
= fsu
.fsu_blocksize
;
353 output_units
= output_block_size
;
354 total
= fsu
.fsu_blocks
;
355 available
= fsu
.fsu_bavail
;
356 negate_available
= fsu
.fsu_bavail_top_bit_set
;
357 available_to_root
= fsu
.fsu_bfree
;
362 if (total
!= -1 && available_to_root
!= -1)
364 used
= total
- available_to_root
;
365 if (total
< available_to_root
)
372 printf (" %*s %*s %*s ",
373 width
, df_readable (0, total
,
374 buf
[0], input_units
, output_units
),
375 width
, df_readable (negate_used
, used
,
376 buf
[1], input_units
, output_units
),
377 width
, df_readable (negate_available
, available
,
378 buf
[2], input_units
, output_units
));
380 if (used
== -1 || available
== -1)
382 else if (!negate_used
383 && used
<= TYPE_MAXIMUM (uintmax_t) / 100
384 && used
+ available
!= 0
385 && (used
+ available
< used
) == negate_available
)
387 uintmax_t u100
= used
* 100;
388 uintmax_t nonroot_total
= used
+ available
;
389 pct
= u100
/ nonroot_total
+ (u100
% nonroot_total
!= 0);
393 /* The calculation cannot be done easily with integer
394 arithmetic. Fall back on floating point. This can suffer
395 from minor rounding errors, but doing it exactly requires
396 multiple precision arithmetic, and it's not worth the
398 double u
= negate_used
? - (double) - used
: used
;
399 double a
= negate_available
? - (double) - available
: available
;
400 double nonroot_total
= u
+ a
;
404 pct
= u
* 100 / nonroot_total
;
407 /* Like `pct = ceil (dpct);', but avoid ceil so that
408 the math library needn't be linked. */
409 if (ipct
- 1 < pct
&& pct
<= ipct
+ 1)
410 pct
= ipct
+ (ipct
< pct
);
415 printf ("%*.0f%%", use_width
- 1, pct
);
417 printf ("%*s", use_width
, "- ");
421 #ifdef HIDE_AUTOMOUNT_PREFIX
422 /* Don't print the first directory name in MOUNT_POINT if it's an
423 artifact of an automounter. This is a bit too aggressive to be
425 if (strncmp ("/auto/", mount_point
, 6) == 0)
427 else if (strncmp ("/tmp_mnt/", mount_point
, 9) == 0)
430 printf (" %s", mount_point
);
435 /* Return the root mountpoint of the filesystem on which FILE exists, in
436 malloced storage. FILE_STAT should be the result of stating FILE.
437 Give a diagnostic and return NULL if unable to determine the mount point.
438 Exit if unable to restore current working directory. */
440 find_mount_point (const char *file
, const struct stat
*file_stat
)
442 struct saved_cwd cwd
;
443 struct stat last_stat
;
444 char *mp
= 0; /* The malloced mount point path. */
448 error (0, errno
, _("cannot get current directory"));
452 if (S_ISDIR (file_stat
->st_mode
))
453 /* FILE is a directory, so just chdir there directly. */
455 last_stat
= *file_stat
;
456 if (chdir (file
) < 0)
458 error (0, errno
, _("cannot change to directory %s"), quote (file
));
463 /* FILE is some other kind of file; use its directory. */
465 char *xdir
= dir_name (file
);
467 ASSIGN_STRDUPA (dir
, xdir
);
472 error (0, errno
, _("cannot change to directory %s"), quote (dir
));
476 if (stat (".", &last_stat
) < 0)
478 error (0, errno
, _("cannot stat current directory (now %s)"),
484 /* Now walk up FILE's parents until we find another filesystem or /,
485 chdiring as we go. LAST_STAT holds stat information for the last place
490 if (stat ("..", &st
) < 0)
492 error (0, errno
, _("cannot stat %s"), quote (".."));
495 if (st
.st_dev
!= last_stat
.st_dev
|| st
.st_ino
== last_stat
.st_ino
)
496 /* cwd is the mount point. */
498 if (chdir ("..") < 0)
500 error (0, errno
, _("cannot change to directory %s"), quote (".."));
506 /* Finally reached a mount point, see what it's called. */
510 /* Restore the original cwd. */
512 int save_errno
= errno
;
513 if (restore_cwd (&cwd
))
514 error (EXIT_FAILURE
, errno
,
515 _("failed to return to initial working directory"));
523 /* If DISK corresponds to a mount point, show its usage
524 and return nonzero. Otherwise, return zero.
525 STATP must be the result of `stat (DISK, STATP)'. */
527 show_disk (const char *disk
, const struct stat
*statp
)
529 struct mount_entry
*me
;
531 for (me
= mount_list
; me
; me
= me
->me_next
)
532 if (STREQ (disk
, me
->me_devname
))
534 show_dev (me
->me_devname
, me
->me_mountdir
, me
->me_type
,
535 me
->me_dummy
, me
->me_remote
);
542 /* Figure out which device file or directory POINT is mounted on
543 and show its disk usage.
544 STATP must be the result of `stat (POINT, STATP)'. */
546 show_point (const char *point
, const struct stat
*statp
)
548 struct stat disk_stats
;
549 struct mount_entry
*me
;
550 struct mount_entry
*matching_dummy
= NULL
;
552 /* If POINT is an absolute path name, see if we can find the
553 mount point without performing any extra stat calls at all. */
556 for (me
= mount_list
; me
; me
= me
->me_next
)
558 if (STREQ (me
->me_mountdir
, point
) && !STREQ (me
->me_type
, "lofs"))
560 /* Prefer non-dummy entries. */
568 goto show_matching_dummy
;
571 /* Calculate the real absolute path for POINT, and use that to find
572 the mount point. This avoids statting unavailable mount points,
573 which can hang df. */
575 char *resolved
= canonicalize_file_name (point
);
576 ssize_t resolved_len
= resolved
? strlen (resolved
) : -1;
577 struct mount_entry
*best_match
= NULL
;
579 if (1 <= resolved_len
&& resolved
[0] == '/')
581 size_t best_match_len
= 0;
583 for (me
= mount_list
; me
; me
= me
->me_next
)
586 size_t len
= strlen (me
->me_mountdir
);
587 if (best_match_len
< len
&& len
<= resolved_len
588 && (len
== 1 /* root file system */
589 || ((len
== resolved_len
|| resolved
[len
] == '/')
590 && strncmp (me
->me_mountdir
, resolved
, len
) == 0)))
593 best_match_len
= len
;
601 if (best_match
&& !STREQ (best_match
->me_type
, "lofs")
602 && stat (best_match
->me_mountdir
, &disk_stats
) == 0
603 && disk_stats
.st_dev
== statp
->st_dev
)
610 for (me
= mount_list
; me
; me
= me
->me_next
)
612 if (me
->me_dev
== (dev_t
) -1)
614 if (stat (me
->me_mountdir
, &disk_stats
) == 0)
615 me
->me_dev
= disk_stats
.st_dev
;
618 error (0, errno
, "%s", quote (me
->me_mountdir
));
620 /* So we won't try and fail repeatedly. */
621 me
->me_dev
= (dev_t
) -2;
625 if (statp
->st_dev
== me
->me_dev
)
627 /* Skip bogus mtab entries. */
628 if (stat (me
->me_mountdir
, &disk_stats
) != 0
629 || disk_stats
.st_dev
!= me
->me_dev
)
631 me
->me_dev
= (dev_t
) -2;
635 /* Prefer non-dummy entries. */
643 goto show_matching_dummy
;
645 /* We couldn't find the mount entry corresponding to POINT. Go ahead and
646 print as much info as we can; methods that require the device to be
647 present will fail at a later point. */
649 /* Find the actual mount point. */
650 char *mp
= find_mount_point (point
, statp
);
653 show_dev (0, mp
, 0, 0, 0);
663 show_dev (me
->me_devname
, me
->me_mountdir
, me
->me_type
, me
->me_dummy
,
667 /* Determine what kind of node PATH is and show the disk usage
668 for it. STATP is the results of `stat' on PATH. */
671 show_entry (const char *path
, const struct stat
*statp
)
673 if ((S_ISBLK (statp
->st_mode
) || S_ISCHR (statp
->st_mode
))
674 && show_disk (path
, statp
))
677 show_point (path
, statp
);
680 /* Show all mounted filesystems, except perhaps those that are of
681 an unselected type or are empty. */
684 show_all_entries (void)
686 struct mount_entry
*me
;
688 for (me
= mount_list
; me
; me
= me
->me_next
)
689 show_dev (me
->me_devname
, me
->me_mountdir
, me
->me_type
,
690 me
->me_dummy
, me
->me_remote
);
693 /* Add FSTYPE to the list of filesystem types to display. */
696 add_fs_type (const char *fstype
)
698 struct fs_type_list
*fsp
;
700 fsp
= xmalloc (sizeof *fsp
);
701 fsp
->fs_name
= (char *) fstype
;
702 fsp
->fs_next
= fs_select_list
;
703 fs_select_list
= fsp
;
706 /* Add FSTYPE to the list of filesystem types to be omitted. */
709 add_excluded_fs_type (const char *fstype
)
711 struct fs_type_list
*fsp
;
713 fsp
= xmalloc (sizeof *fsp
);
714 fsp
->fs_name
= (char *) fstype
;
715 fsp
->fs_next
= fs_exclude_list
;
716 fs_exclude_list
= fsp
;
722 if (status
!= EXIT_SUCCESS
)
723 fprintf (stderr
, _("Try `%s --help' for more information.\n"),
727 printf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name
);
729 Show information about the filesystem on which each FILE resides,\n\
730 or all filesystems by default.\n\
734 Mandatory arguments to long options are mandatory for short options too.\n\
737 -a, --all include filesystems having 0 blocks\n\
738 -B, --block-size=SIZE use SIZE-byte blocks\n\
739 -h, --human-readable print sizes in human readable format (e.g., 1K 234M 2G)\n\
740 -H, --si likewise, but use powers of 1000 not 1024\n\
743 -i, --inodes list inode information instead of block usage\n\
744 -k like --block-size=1K\n\
745 -l, --local limit listing to local filesystems\n\
746 --no-sync do not invoke sync before getting usage info (default)\n\
749 -P, --portability use the POSIX output format\n\
750 --sync invoke sync before getting usage info\n\
751 -t, --type=TYPE limit listing to filesystems of type TYPE\n\
752 -T, --print-type print filesystem type\n\
753 -x, --exclude-type=TYPE limit listing to filesystems not of type TYPE\n\
756 fputs (HELP_OPTION_DESCRIPTION
, stdout
);
757 fputs (VERSION_OPTION_DESCRIPTION
, stdout
);
759 SIZE may be (or may be an integer optionally followed by) one of following:\n\
760 kB 1000, K 1024, MB 1000*1000, M 1024*1024, and so on for G, T, P, E, Z, Y.\n\
762 printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT
);
768 main (int argc
, char **argv
)
771 struct stat
*stats
IF_LINT (= 0);
772 int n_valid_args
= 0;
774 initialize_main (&argc
, &argv
);
775 program_name
= argv
[0];
776 setlocale (LC_ALL
, "");
777 bindtextdomain (PACKAGE
, LOCALEDIR
);
778 textdomain (PACKAGE
);
780 atexit (close_stdout
);
782 fs_select_list
= NULL
;
783 fs_exclude_list
= NULL
;
788 human_output_opts
= human_options (getenv ("DF_BLOCK_SIZE"), false,
795 while ((c
= getopt_long (argc
, argv
, "aB:iF:hHklmPTt:vx:", long_options
, NULL
))
800 case 0: /* Long option. */
806 human_output_opts
= human_options (optarg
, true, &output_block_size
);
812 human_output_opts
= human_autoscale
| human_SI
| human_base_1024
;
813 output_block_size
= 1;
816 human_output_opts
= human_autoscale
| human_SI
;
817 output_block_size
= 1;
820 human_output_opts
= 0;
821 output_block_size
= 1024;
826 case 'm': /* obsolescent */
827 human_output_opts
= 0;
828 output_block_size
= 1024 * 1024;
844 /* Accept -F as a synonym for -t for compatibility with Solaris. */
846 add_fs_type (optarg
);
849 case 'v': /* For SysV compatibility. */
853 add_excluded_fs_type (optarg
);
856 case_GETOPT_HELP_CHAR
;
857 case_GETOPT_VERSION_CHAR (PROGRAM_NAME
, AUTHORS
);
860 usage (EXIT_FAILURE
);
864 /* Fail if the same file system type was both selected and excluded. */
867 struct fs_type_list
*fs_incl
;
868 for (fs_incl
= fs_select_list
; fs_incl
; fs_incl
= fs_incl
->fs_next
)
870 struct fs_type_list
*fs_excl
;
871 for (fs_excl
= fs_exclude_list
; fs_excl
; fs_excl
= fs_excl
->fs_next
)
873 if (STREQ (fs_incl
->fs_name
, fs_excl
->fs_name
))
876 _("file system type %s both selected and excluded"),
877 quote (fs_incl
->fs_name
));
891 /* stat all the given entries to make sure they get automounted,
892 if necessary, before reading the filesystem table. */
893 stats
= xmalloc ((argc
- optind
) * sizeof *stats
);
894 for (i
= optind
; i
< argc
; ++i
)
896 if (stat (argv
[i
], &stats
[i
- optind
]))
898 error (0, errno
, "%s", quote (argv
[i
]));
910 read_filesystem_list ((fs_select_list
!= NULL
911 || fs_exclude_list
!= NULL
915 if (mount_list
== NULL
)
917 /* Couldn't read the table of mounted filesystems.
918 Fail if df was invoked with no file name arguments;
919 Otherwise, merely give a warning and proceed. */
920 const char *warning
= (optind
< argc
? _("Warning: ") : "");
921 int status
= (optind
< argc
? 0 : EXIT_FAILURE
);
922 error (status
, errno
,
923 _("%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
]);
949 exit (exit_status
== 0 ? EXIT_SUCCESS
: EXIT_FAILURE
);