1 /* df - summarize free disk space
2 Copyright (C) 91, 1995-1999 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 <inttypes.h>
27 #include <sys/types.h>
36 #include "mountlist.h"
39 /* The official name of this program (e.g., no `g' prefix). */
40 #define PROGRAM_NAME "df"
43 "Torbjorn Granlund, David MacKenzie, Larry McVoy, and Paul Eggert"
45 void strip_trailing_slashes ();
49 /* Name this program was run with. */
52 /* If nonzero, show inode information. */
53 static int inode_format
;
55 /* If nonzero, show even filesystems with zero size or
56 uninteresting types. */
57 static int show_all_fs
;
59 /* If nonzero, show only local filesystems. */
60 static int show_local_fs
;
62 /* If nonzero, output data for each filesystem corresponding to a
63 command line argument -- even if it's a dummy (automounter) entry. */
64 static int show_listed_fs
;
66 /* If positive, the units to use when printing sizes;
67 if negative, the human-readable base. */
68 static int 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 static struct option
const long_options
[] =
116 {"all", no_argument
, NULL
, 'a'},
117 {"block-size", required_argument
, NULL
, CHAR_MAX
+ 3},
118 {"inodes", no_argument
, NULL
, 'i'},
119 {"human-readable", no_argument
, NULL
, 'h'},
120 {"si", no_argument
, NULL
, 'H'},
121 {"kilobytes", no_argument
, NULL
, 'k'},
122 {"local", no_argument
, NULL
, 'l'},
123 {"megabytes", no_argument
, NULL
, 'm'},
124 {"portability", no_argument
, NULL
, 'P'},
125 {"print-type", no_argument
, NULL
, 'T'},
126 {"sync", no_argument
, NULL
, CHAR_MAX
+ 1},
127 {"no-sync", no_argument
, NULL
, CHAR_MAX
+ 2},
128 {"type", required_argument
, NULL
, 't'},
129 {"exclude-type", required_argument
, NULL
, 'x'},
130 {GETOPT_HELP_OPTION_DECL
},
131 {GETOPT_VERSION_OPTION_DECL
},
138 printf ("Filesystem ");
146 printf (" Inodes IUsed IFree IUse%%");
147 else if (output_block_size
< 0)
148 printf (" Size Used Avail Use%%");
149 else if (posix_format
)
150 printf (" %4d-blocks Used Available Capacity", output_block_size
);
153 char buf
[LONGEST_HUMAN_READABLE
+ 1];
154 char *p
= human_readable (output_block_size
, buf
, 1, -1024);
156 /* Replace e.g. "1.0k" by "1k". */
157 size_t plen
= strlen (p
);
158 if (3 <= plen
&& strncmp (p
+ plen
- 3, ".0", 2) == 0)
159 strcpy (p
+ plen
- 3, p
+ plen
- 1);
161 printf (" %4s-blocks Used Available Use%%", p
);
164 printf (" Mounted on\n");
167 /* If FSTYPE is a type of filesystem that should be listed,
168 return nonzero, else zero. */
171 selected_fstype (const char *fstype
)
173 const struct fs_type_list
*fsp
;
175 if (fs_select_list
== NULL
|| fstype
== NULL
)
177 for (fsp
= fs_select_list
; fsp
; fsp
= fsp
->fs_next
)
178 if (STREQ (fstype
, fsp
->fs_name
))
183 /* If FSTYPE is a type of filesystem that should be omitted,
184 return nonzero, else zero. */
187 excluded_fstype (const char *fstype
)
189 const struct fs_type_list
*fsp
;
191 if (fs_exclude_list
== NULL
|| fstype
== NULL
)
193 for (fsp
= fs_exclude_list
; fsp
; fsp
= fsp
->fs_next
)
194 if (STREQ (fstype
, fsp
->fs_name
))
199 /* Like human_readable, except return "-" if the argument is -1,
200 and take ceiling of fractions if posix_format. */
202 df_readable (uintmax_t n
, char *buf
,
203 int from_block_size
, int t_output_block_size
)
205 return (n
== -1 ? "-"
206 : human_readable_inexact (n
, buf
, from_block_size
,
210 : human_round_to_even
)));
213 /* Return the ceiling of N * 100 / D. Avoid the ceil function, so that
214 we needn't link the math library. */
216 ceil_percent (uintmax_t n
, uintmax_t d
)
218 if (n
<= (uintmax_t) -1 / 100)
220 uintmax_t n100
= n
* 100;
221 return n100
/ d
+ (n100
% d
!= 0);
225 /* Avoid integer overflow. We should use multiple precision
226 arithmetic here, but we'll be lazy and resort to floating
227 point. This can yield answers that are slightly off. In
228 practice it is quite rare to overflow uintmax_t, so this is
229 good enough for now. */
230 double pct
= n
* 100.0 / d
;
232 return r
+ (r
!= pct
);
236 /* Display a space listing for the disk device with absolute path DISK.
237 If MOUNT_POINT is non-NULL, it is the path of the root of the
239 If FSTYPE is non-NULL, it is the type of the filesystem on DISK.
240 If MOUNT_POINT is non-NULL, then DISK may be NULL -- certain systems may
241 not be able to produce statistics in this case.
242 ME_DUMMY and ME_REMOTE are the mount entry flags. */
245 show_dev (const char *disk
, const char *mount_point
, const char *fstype
,
246 int me_dummy
, int me_remote
)
249 const char *stat_file
;
251 if (me_remote
&& show_local_fs
)
254 if (me_dummy
&& show_all_fs
== 0 && !show_listed_fs
)
257 if (!selected_fstype (fstype
) || excluded_fstype (fstype
))
260 /* If MOUNT_POINT is NULL, then the filesystem is not mounted, and this
261 program reports on the filesystem that the special file is on.
262 It would be better to report on the unmounted filesystem,
263 but statfs doesn't do that on most systems. */
264 stat_file
= mount_point
? mount_point
: disk
;
266 if (get_fs_usage (stat_file
, disk
, &fsu
))
268 error (0, errno
, "%s", stat_file
);
273 if (fsu
.fsu_blocks
== 0 && !show_all_fs
&& !show_listed_fs
)
277 disk
= "-"; /* unknown */
279 fstype
= "-"; /* unknown */
281 /* df.c reserved 5 positions for fstype,
282 but that does not suffice for type iso9660 */
285 int disk_name_len
= (int) strlen (disk
);
286 int fstype_len
= (int) strlen (fstype
);
287 if (disk_name_len
+ fstype_len
+ 2 < 20)
288 printf ("%s%*s ", disk
, 18 - disk_name_len
, fstype
);
289 else if (!posix_format
)
290 printf ("%s\n%18s ", disk
, fstype
);
292 printf ("%s %s", disk
, fstype
);
296 if ((int) strlen (disk
) > 20 && !posix_format
)
297 printf ("%s\n%20s", disk
, "");
299 printf ("%-20s", disk
);
304 char buf
[3][LONGEST_HUMAN_READABLE
+ 1];
305 double inodes_percent_used
;
306 uintmax_t inodes_used
;
307 int inode_units
= output_block_size
< 0 ? output_block_size
: 1;
309 if (fsu
.fsu_files
== -1 || fsu
.fsu_files
< fsu
.fsu_ffree
)
312 inodes_percent_used
= -1;
316 inodes_used
= fsu
.fsu_files
- fsu
.fsu_ffree
;
317 inodes_percent_used
=
318 (fsu
.fsu_files
== 0 ? 0
319 : inodes_used
* 100.0 / fsu
.fsu_files
);
322 printf (" %7s %7s %7s ",
323 df_readable (fsu
.fsu_files
, buf
[0], 1, inode_units
),
324 df_readable (inodes_used
, buf
[1], 1, inode_units
),
325 df_readable (fsu
.fsu_ffree
, buf
[2], 1, inode_units
));
327 if (inodes_percent_used
< 0)
330 printf ("%4.0f%%", inodes_percent_used
);
334 int w
= output_block_size
< 0 ? 5 : 9;
335 char buf
[2][LONGEST_HUMAN_READABLE
+ 1];
336 char availbuf
[LONGEST_HUMAN_READABLE
+ 2];
338 double blocks_percent_used
;
339 uintmax_t blocks_used
;
341 if (fsu
.fsu_blocks
== -1 || fsu
.fsu_blocks
< fsu
.fsu_bfree
)
344 blocks_percent_used
= -1;
348 uintmax_t blocks_avail
;
350 blocks_used
= fsu
.fsu_blocks
- fsu
.fsu_bfree
;
351 blocks_avail
= blocks_used
+ fsu
.fsu_bavail
;
352 blocks_percent_used
=
353 ((fsu
.fsu_bavail
== -1
355 || (fsu
.fsu_bavail_top_bit_set
356 ? blocks_used
< - fsu
.fsu_bavail
357 : fsu
.fsu_bfree
< fsu
.fsu_bavail
))
360 ? ceil_percent (blocks_used
, blocks_avail
)
361 : blocks_used
* 100.0 / blocks_avail
);
364 avail
= df_readable ((fsu
.fsu_bavail_top_bit_set
367 availbuf
+ 1, fsu
.fsu_blocksize
,
370 if (fsu
.fsu_bavail_top_bit_set
)
373 printf (" %*s %*s %*s ",
374 w
, df_readable (fsu
.fsu_blocks
, buf
[0], fsu
.fsu_blocksize
,
376 w
, df_readable (blocks_used
, buf
[1], fsu
.fsu_blocksize
,
381 int use_width
= posix_format
? 8 : 4;
383 if (blocks_percent_used
< 0)
384 printf ("%*s", use_width
, "- ");
386 printf ("%*.0f%%", use_width
- 1, blocks_percent_used
);
392 #ifdef HIDE_AUTOMOUNT_PREFIX
393 /* Don't print the first directory name in MOUNT_POINT if it's an
394 artifact of an automounter. This is a bit too aggressive to be
396 if (strncmp ("/auto/", mount_point
, 6) == 0)
398 else if (strncmp ("/tmp_mnt/", mount_point
, 9) == 0)
401 printf (" %s", mount_point
);
406 /* Identify the directory, if any, that device
407 DISK is mounted on, and show its disk usage. */
410 show_disk (const char *disk
)
412 struct mount_entry
*me
;
414 for (me
= mount_list
; me
; me
= me
->me_next
)
415 if (STREQ (disk
, me
->me_devname
))
417 show_dev (me
->me_devname
, me
->me_mountdir
, me
->me_type
,
418 me
->me_dummy
, me
->me_remote
);
421 /* No filesystem is mounted on DISK. */
422 show_dev (disk
, (char *) NULL
, (char *) NULL
, 0, 0);
425 /* Return the root mountpoint of the filesystem on which FILE exists, in
426 malloced storage. FILE_STAT should be the result of stating FILE. */
428 find_mount_point (const char *file
, const struct stat
*file_stat
)
430 struct saved_cwd cwd
;
431 struct stat last_stat
;
432 char *mp
= 0; /* The malloced mount point path. */
437 if (S_ISDIR (file_stat
->st_mode
))
438 /* FILE is a directory, so just chdir there directly. */
440 last_stat
= *file_stat
;
441 if (chdir (file
) < 0)
445 /* FILE is some other kind of file, we need to use its directory. */
448 char *tmp
= xstrdup (file
);
451 strip_trailing_slashes (tmp
);
452 dir
= dir_name (tmp
);
460 if (stat (".", &last_stat
) < 0)
464 /* Now walk up FILE's parents until we find another filesystem or /,
465 chdiring as we go. LAST_STAT holds stat information for the last place
470 if (stat ("..", &st
) < 0)
472 if (st
.st_dev
!= last_stat
.st_dev
|| st
.st_ino
== last_stat
.st_ino
)
473 /* cwd is the mount point. */
475 if (chdir ("..") < 0)
480 /* Finally reached a mount point, see what it's called. */
484 /* Restore the original cwd. */
486 int save_errno
= errno
;
487 if (restore_cwd (&cwd
, 0, mp
))
488 exit (1); /* We're scrod. */
496 /* Figure out which device file or directory POINT is mounted on
497 and show its disk usage.
498 STATP is the results of `stat' on POINT. */
500 show_point (const char *point
, const struct stat
*statp
)
502 struct stat disk_stats
;
503 struct mount_entry
*me
;
504 struct mount_entry
*matching_dummy
= NULL
;
506 for (me
= mount_list
; me
; me
= me
->me_next
)
508 if (me
->me_dev
== (dev_t
) -1)
510 if (stat (me
->me_mountdir
, &disk_stats
) == 0)
511 me
->me_dev
= disk_stats
.st_dev
;
514 error (0, errno
, "%s", me
->me_mountdir
);
516 /* So we won't try and fail repeatedly. */
517 me
->me_dev
= (dev_t
) -2;
521 if (statp
->st_dev
== me
->me_dev
)
523 /* Skip bogus mtab entries. */
524 if (stat (me
->me_mountdir
, &disk_stats
) != 0 ||
525 disk_stats
.st_dev
!= me
->me_dev
)
528 /* Prefer non-dummy entries. */
535 show_dev (me
->me_devname
, me
->me_mountdir
, me
->me_type
,
536 me
->me_dummy
, me
->me_remote
);
543 show_dev (matching_dummy
->me_devname
, matching_dummy
->me_mountdir
,
544 matching_dummy
->me_type
, 1, matching_dummy
->me_remote
);
548 /* We couldn't find the mount entry corresponding to POINT. Go ahead and
549 print as much info as we can; methods that require the device to be
550 present will fail at a later point. */
552 /* Find the actual mount point. */
553 char *mp
= find_mount_point (point
, statp
);
556 show_dev (0, mp
, 0, 0, 0);
560 error (0, errno
, "%s", point
);
564 /* Determine what kind of node PATH is and show the disk usage
565 for it. STATP is the results of `stat' on PATH. */
568 show_entry (const char *path
, const struct stat
*statp
)
570 if (S_ISBLK (statp
->st_mode
) || S_ISCHR (statp
->st_mode
))
573 show_point (path
, statp
);
576 /* Show all mounted filesystems, except perhaps those that are of
577 an unselected type or are empty. */
580 show_all_entries (void)
582 struct mount_entry
*me
;
584 for (me
= mount_list
; me
; me
= me
->me_next
)
585 show_dev (me
->me_devname
, me
->me_mountdir
, me
->me_type
,
586 me
->me_dummy
, me
->me_remote
);
589 /* Add FSTYPE to the list of filesystem types to display. */
592 add_fs_type (const char *fstype
)
594 struct fs_type_list
*fsp
;
596 fsp
= (struct fs_type_list
*) xmalloc (sizeof (struct fs_type_list
));
597 fsp
->fs_name
= (char *) fstype
;
598 fsp
->fs_next
= fs_select_list
;
599 fs_select_list
= fsp
;
602 /* Add FSTYPE to the list of filesystem types to be omitted. */
605 add_excluded_fs_type (const char *fstype
)
607 struct fs_type_list
*fsp
;
609 fsp
= (struct fs_type_list
*) xmalloc (sizeof (struct fs_type_list
));
610 fsp
->fs_name
= (char *) fstype
;
611 fsp
->fs_next
= fs_exclude_list
;
612 fs_exclude_list
= fsp
;
619 fprintf (stderr
, _("Try `%s --help' for more information.\n"),
623 printf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name
);
625 Show information about the filesystem on which each FILE resides,\n\
626 or all filesystems by default.\n\
628 -a, --all include filesystems having 0 blocks\n\
629 --block-size=SIZE use SIZE-byte blocks\n\
630 -h, --human-readable print sizes in human readable format (e.g., 1K 234M 2G)\n\
631 -H, --si likewise, but use powers of 1000 not 1024\n\
632 -i, --inodes list inode information instead of block usage\n\
633 -k, --kilobytes like --block-size=1024\n\
634 -l, --local limit listing to local filesystems\n\
635 -m, --megabytes like --block-size=1048576\n\
636 --no-sync do not invoke sync before getting usage info (default)\n\
637 -P, --portability use the POSIX output format\n\
638 --sync invoke sync before getting usage info\n\
639 -t, --type=TYPE limit listing to filesystems of type TYPE\n\
640 -T, --print-type print filesystem type\n\
641 -x, --exclude-type=TYPE limit listing to filesystems not of type TYPE\n\
643 --help display this help and exit\n\
644 --version output version information and exit\n\
646 puts (_("\nReport bugs to <bug-fileutils@gnu.org>."));
653 main (int argc
, char **argv
)
658 program_name
= argv
[0];
659 setlocale (LC_ALL
, "");
660 bindtextdomain (PACKAGE
, LOCALEDIR
);
661 textdomain (PACKAGE
);
663 fs_select_list
= NULL
;
664 fs_exclude_list
= NULL
;
669 human_block_size (getenv ("DF_BLOCK_SIZE"), 0, &output_block_size
);
675 while ((c
= getopt_long (argc
, argv
, "aiF:hHklmPTt:vx:", long_options
, NULL
))
680 case 0: /* Long option. */
689 output_block_size
= -1024;
692 output_block_size
= -1000;
695 output_block_size
= 1024;
701 output_block_size
= 1024 * 1024;
717 human_block_size (optarg
, 1, &output_block_size
);
721 /* Accept -F as a synonym for -t for compatibility with Solaris. */
723 add_fs_type (optarg
);
726 case 'v': /* For SysV compatibility. */
730 add_excluded_fs_type (optarg
);
733 case_GETOPT_HELP_CHAR
;
734 case_GETOPT_VERSION_CHAR (PROGRAM_NAME
, AUTHORS
);
741 /* Fail if the same file system type was both selected and excluded. */
744 struct fs_type_list
*i
;
745 for (i
= fs_select_list
; i
; i
= i
->fs_next
)
747 struct fs_type_list
*j
;
748 for (j
= fs_exclude_list
; j
; j
= j
->fs_next
)
750 if (STREQ (i
->fs_name
, j
->fs_name
))
753 _("file system type `%s' both selected and excluded"),
767 /* Suppress `used before initialized' warning. */
775 /* stat all the given entries to make sure they get automounted,
776 if necessary, before reading the filesystem table. */
777 stats
= (struct stat
*)
778 xmalloc ((argc
- optind
) * sizeof (struct stat
));
779 for (i
= optind
; i
< argc
; ++i
)
780 if (stat (argv
[i
], &stats
[i
- optind
]))
782 error (0, errno
, "%s", argv
[i
]);
789 read_filesystem_list ((fs_select_list
!= NULL
790 || fs_exclude_list
!= NULL
794 if (mount_list
== NULL
)
796 /* Couldn't read the table of mounted filesystems.
797 Fail if df was invoked with no file name arguments;
798 Otherwise, merely give a warning and proceed. */
799 const char *warning
= (optind
== argc
? "" : _("Warning: "));
800 int status
= (optind
== argc
? 1 : 0);
801 error (status
, errno
,
802 _("%scannot read table of mounted filesystems"), warning
);
817 /* Display explicitly requested empty filesystems. */
821 for (i
= optind
; i
< argc
; ++i
)
823 show_entry (argv
[i
], &stats
[i
- optind
]);