1 /* df - summarize free disk space
2 Copyright (C) 91, 95, 96, 97, 1998 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>
31 #include "mountlist.h"
40 void strip_trailing_slashes ();
44 /* Name this program was run with. */
47 /* If nonzero, show inode information. */
48 static int inode_format
;
50 /* If positive, show all entries; if zero, omit size-zero entries and
51 automounter dummies; if negative, also omit non-local filesystems. */
52 static int show_all_fs
;
54 /* If nonzero, output data for each filesystem corresponding to a
55 command line argument -- even if it's a dummy (automounter) entry. */
56 static int show_listed_fs
;
58 /* If positive, the units to use when printing sizes;
59 if negative, the human-readable base. */
60 static int output_block_size
;
62 /* If nonzero, use the POSIX output format. */
63 static int posix_format
;
65 /* If nonzero, invoke the `sync' system call before getting any usage data.
66 Using this option can make df very slow, especially with many or very
67 busy disks. Note that this may make a difference on some systems --
68 SunOs4.1.3, for one. It is *not* necessary on Linux. */
69 static int require_sync
= 0;
71 /* Nonzero if errors have occurred. */
72 static int exit_status
;
74 /* A filesystem type to display. */
79 struct fs_type_list
*fs_next
;
82 /* Linked list of filesystem types to display.
83 If `fs_select_list' is NULL, list all types.
84 This table is generated dynamically from command-line options,
85 rather than hardcoding into the program what it thinks are the
86 valid filesystem types; let the user specify any filesystem type
87 they want to, and if there are any filesystems of that type, they
90 Some filesystem types:
91 4.2 4.3 ufs nfs swap ignore io vm efs dbg */
93 static struct fs_type_list
*fs_select_list
;
95 /* Linked list of filesystem types to omit.
96 If the list is empty, don't exclude any types. */
98 static struct fs_type_list
*fs_exclude_list
;
100 /* Linked list of mounted filesystems. */
101 static struct mount_entry
*mount_list
;
103 /* If nonzero, display usage information and exit. */
104 static int show_help
;
106 /* If nonzero, print the version on standard output and exit. */
107 static int show_version
;
109 /* If nonzero, print filesystem type as well. */
110 static int print_type
;
112 static struct option
const long_options
[] =
114 {"all", no_argument
, NULL
, 'a'},
115 {"block-size", required_argument
, NULL
, 131},
116 {"inodes", no_argument
, NULL
, 'i'},
117 {"human-readable", no_argument
, NULL
, 'h'},
118 {"si", no_argument
, NULL
, 'H'},
119 {"kilobytes", no_argument
, NULL
, 'k'},
120 {"local", no_argument
, NULL
, 'l'},
121 {"megabytes", no_argument
, NULL
, 'm'},
122 {"portability", no_argument
, NULL
, 'P'},
123 {"print-type", no_argument
, NULL
, 'T'},
124 {"sync", no_argument
, NULL
, 129},
125 {"no-sync", no_argument
, NULL
, 130},
126 {"type", required_argument
, NULL
, 't'},
127 {"exclude-type", required_argument
, NULL
, 'x'},
128 {"help", no_argument
, &show_help
, 1},
129 {"version", no_argument
, &show_version
, 1},
136 printf ("Filesystem ");
144 printf (" Inodes IUsed IFree IUse%%");
145 else if (output_block_size
< 0)
146 printf (" Size Used Avail Use%%");
149 char buf
[LONGEST_HUMAN_READABLE
+ 1];
150 char *p
= human_readable (output_block_size
, buf
, 1, -1024);
152 /* Replace e.g. "1.0k" by "1k". */
153 size_t plen
= strlen (p
);
154 if (3 <= plen
&& strncmp (p
+ plen
- 3, ".0", 2) == 0)
155 strcpy (p
+ plen
- 3, p
+ plen
- 1);
157 printf (" %4s-blocks Used Available Use%%", p
);
160 printf (" Mounted on\n");
163 /* If FSTYPE is a type of filesystem that should be listed,
164 return nonzero, else zero. */
167 selected_fstype (const char *fstype
)
169 const struct fs_type_list
*fsp
;
171 if (fs_select_list
== NULL
|| fstype
== NULL
)
173 for (fsp
= fs_select_list
; fsp
; fsp
= fsp
->fs_next
)
174 if (STREQ (fstype
, fsp
->fs_name
))
179 /* If FSTYPE is a type of filesystem that should be omitted,
180 return nonzero, else zero. */
183 excluded_fstype (const char *fstype
)
185 const struct fs_type_list
*fsp
;
187 if (fs_exclude_list
== NULL
|| fstype
== NULL
)
189 for (fsp
= fs_exclude_list
; fsp
; fsp
= fsp
->fs_next
)
190 if (STREQ (fstype
, fsp
->fs_name
))
195 /* Like human_readable, except return "-" if the argument is -1. */
197 df_readable (uintmax_t n
, char *buf
,
198 int from_block_size
, int t_output_block_size
)
200 return (n
== -1 ? "-"
201 : human_readable (n
, buf
, from_block_size
, t_output_block_size
));
204 /* Display a space listing for the disk device with absolute path DISK.
205 If MOUNT_POINT is non-NULL, it is the path of the root of the
207 If FSTYPE is non-NULL, it is the type of the filesystem on DISK.
208 If MOUNT_POINT is non-NULL, then DISK may be NULL -- certain systems may
209 not be able to produce statistics in this case. */
212 show_dev (const char *disk
, const char *mount_point
, const char *fstype
)
215 const char *stat_file
;
217 /* If MOUNT_POINT is NULL, then the filesystem is not mounted, and this
218 program reports on the filesystem that the special file is on.
219 It would be better to report on the unmounted filesystem,
220 but statfs doesn't do that on most systems. */
221 stat_file
= mount_point
? mount_point
: disk
;
223 if (show_all_fs
< 0 && fstype
&& REMOTE_FS_TYPE (fstype
))
226 if (!selected_fstype (fstype
) || excluded_fstype (fstype
))
229 if (get_fs_usage (stat_file
, disk
, &fsu
))
231 error (0, errno
, "%s", stat_file
);
236 if (fsu
.fsu_blocks
== 0 && show_all_fs
<= 0 && !show_listed_fs
)
240 disk
= "-"; /* unknown */
242 printf ((print_type
? "%-13s" : "%-20s"), disk
);
243 if ((int) strlen (disk
) > (print_type
? 13 : 20) && !posix_format
)
244 printf ((print_type
? "\n%13s" : "\n%20s"), "");
247 fstype
= "-"; /* unknown */
249 printf (" %-5s ", fstype
);
253 char buf
[3][LONGEST_HUMAN_READABLE
+ 1];
254 double inodes_percent_used
;
255 uintmax_t inodes_used
;
256 int inode_units
= output_block_size
< 0 ? output_block_size
: 1;
258 if (fsu
.fsu_files
== -1 || fsu
.fsu_files
< fsu
.fsu_ffree
)
261 inodes_percent_used
= -1;
265 inodes_used
= fsu
.fsu_files
- fsu
.fsu_ffree
;
266 inodes_percent_used
=
267 (fsu
.fsu_files
== 0 ? 0
268 : inodes_used
* 100.0 / fsu
.fsu_files
);
271 printf (" %7s %7s %7s ",
272 df_readable (fsu
.fsu_files
, buf
[0], 1, inode_units
),
273 df_readable (inodes_used
, buf
[1], 1, inode_units
),
274 df_readable (fsu
.fsu_ffree
, buf
[2], 1, inode_units
));
276 if (inodes_percent_used
< 0)
279 printf ("%4.0f%%", inodes_percent_used
);
283 int w
= output_block_size
< 0 ? 5 : 9;
284 char buf
[2][LONGEST_HUMAN_READABLE
+ 1];
285 char availbuf
[LONGEST_HUMAN_READABLE
+ 2];
287 double blocks_percent_used
;
288 uintmax_t blocks_used
;
290 if (fsu
.fsu_blocks
== -1 || fsu
.fsu_blocks
< fsu
.fsu_bfree
)
293 blocks_percent_used
= -1;
297 blocks_used
= fsu
.fsu_blocks
- fsu
.fsu_bfree
;
298 blocks_percent_used
=
299 ((fsu
.fsu_bavail
== -1
300 || blocks_used
+ fsu
.fsu_bavail
== 0
301 || (fsu
.fsu_bavail_top_bit_set
302 ? blocks_used
< - fsu
.fsu_bavail
303 : fsu
.fsu_bfree
< fsu
.fsu_bavail
))
305 : blocks_used
* 100.0 / (blocks_used
+ fsu
.fsu_bavail
));
308 avail
= df_readable ((fsu
.fsu_bavail_top_bit_set
311 availbuf
+ 1, fsu
.fsu_blocksize
,
314 if (fsu
.fsu_bavail_top_bit_set
)
317 printf (" %*s %*s %*s ",
318 w
, df_readable (fsu
.fsu_blocks
, buf
[0], fsu
.fsu_blocksize
,
320 w
, df_readable (blocks_used
, buf
[1], fsu
.fsu_blocksize
,
324 if (blocks_percent_used
< 0)
327 printf ("%3.0f%%", blocks_percent_used
);
332 #ifdef HIDE_AUTOMOUNT_PREFIX
333 /* Don't print the first directory name in MOUNT_POINT if it's an
334 artifact of an automounter. This is a bit too aggressive to be
336 if (strncmp ("/auto/", mount_point
, 6) == 0)
338 else if (strncmp ("/tmp_mnt/", mount_point
, 9) == 0)
341 printf (" %s", mount_point
);
346 /* Identify the directory, if any, that device
347 DISK is mounted on, and show its disk usage. */
350 show_disk (const char *disk
)
352 struct mount_entry
*me
;
354 for (me
= mount_list
; me
; me
= me
->me_next
)
355 if (STREQ (disk
, me
->me_devname
))
357 show_dev (me
->me_devname
, me
->me_mountdir
, me
->me_type
);
360 /* No filesystem is mounted on DISK. */
361 show_dev (disk
, (char *) NULL
, (char *) NULL
);
364 /* Return the root mountpoint of the filesystem on which FILE exists, in
365 malloced storage. FILE_STAT should be the result of stating FILE. */
367 find_mount_point (const char *file
, const struct stat
*file_stat
)
369 struct saved_cwd cwd
;
370 struct stat last_stat
;
371 char *mp
= 0; /* The malloced mount point path. */
376 if (S_ISDIR (file_stat
->st_mode
))
377 /* FILE is a directory, so just chdir there directly. */
379 last_stat
= *file_stat
;
380 if (chdir (file
) < 0)
384 /* FILE is some other kind of file, we need to use its directory. */
387 char *tmp
= xstrdup (file
);
390 strip_trailing_slashes (tmp
);
399 if (stat (".", &last_stat
) < 0)
403 /* Now walk up FILE's parents until we find another filesystem or /,
404 chdiring as we go. LAST_STAT holds stat information for the last place
409 if (stat ("..", &st
) < 0)
411 if (st
.st_dev
!= last_stat
.st_dev
|| st
.st_ino
== last_stat
.st_ino
)
412 /* cwd is the mount point. */
414 if (chdir ("..") < 0)
419 /* Finally reached a mount point, see what it's called. */
423 /* Restore the original cwd. */
425 int save_errno
= errno
;
426 if (restore_cwd (&cwd
, 0, mp
))
427 exit (1); /* We're scrod. */
435 /* Figure out which device file or directory POINT is mounted on
436 and show its disk usage.
437 STATP is the results of `stat' on POINT. */
439 show_point (const char *point
, const struct stat
*statp
)
441 struct stat disk_stats
;
442 struct mount_entry
*me
;
444 for (me
= mount_list
; me
; me
= me
->me_next
)
446 if (me
->me_dev
== (dev_t
) -1)
448 if (stat (me
->me_mountdir
, &disk_stats
) == 0)
449 me
->me_dev
= disk_stats
.st_dev
;
452 error (0, errno
, "%s", me
->me_mountdir
);
454 /* So we won't try and fail repeatedly. */
455 me
->me_dev
= (dev_t
) -2;
459 if (statp
->st_dev
== me
->me_dev
)
461 /* Skip bogus mtab entries. */
462 if (stat (me
->me_mountdir
, &disk_stats
) != 0 ||
463 disk_stats
.st_dev
!= me
->me_dev
)
465 show_dev (me
->me_devname
, me
->me_mountdir
, me
->me_type
);
470 /* We couldn't find the mount entry corresponding to POINT. Go ahead and
471 print as much info as we can; methods that require the device to be
472 present will fail at a later point. */
474 /* Find the actual mount point. */
475 char *mp
= find_mount_point (point
, statp
);
482 error (0, errno
, "%s", point
);
486 /* Determine what kind of node PATH is and show the disk usage
487 for it. STATP is the results of `stat' on PATH. */
490 show_entry (const char *path
, const struct stat
*statp
)
492 if (S_ISBLK (statp
->st_mode
) || S_ISCHR (statp
->st_mode
))
495 show_point (path
, statp
);
498 /* Show all mounted filesystems, except perhaps those that are of
499 an unselected type or are empty. */
502 show_all_entries (void)
504 struct mount_entry
*me
;
506 for (me
= mount_list
; me
; me
= me
->me_next
)
507 show_dev (me
->me_devname
, me
->me_mountdir
, me
->me_type
);
510 /* Add FSTYPE to the list of filesystem types to display. */
513 add_fs_type (const char *fstype
)
515 struct fs_type_list
*fsp
;
517 fsp
= (struct fs_type_list
*) xmalloc (sizeof (struct fs_type_list
));
518 fsp
->fs_name
= (char *) fstype
;
519 fsp
->fs_next
= fs_select_list
;
520 fs_select_list
= fsp
;
523 /* Add FSTYPE to the list of filesystem types to be omitted. */
526 add_excluded_fs_type (const char *fstype
)
528 struct fs_type_list
*fsp
;
530 fsp
= (struct fs_type_list
*) xmalloc (sizeof (struct fs_type_list
));
531 fsp
->fs_name
= (char *) fstype
;
532 fsp
->fs_next
= fs_exclude_list
;
533 fs_exclude_list
= fsp
;
540 fprintf (stderr
, _("Try `%s --help' for more information.\n"),
544 printf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name
);
546 Show information about the filesystem on which each FILE resides,\n\
547 or all filesystems by default.\n\
549 -a, --all include filesystems having 0 blocks\n\
550 --block-size=SIZE use SIZE-byte blocks\n\
551 -h, --human-readable print sizes in human readable format (e.g., 1K 234M 2G)\n\
552 -H, --si likewise, but use powers of 1000 not 1024\n\
553 -i, --inodes list inode information instead of block usage\n\
554 -k, --kilobytes like --block-size=1024\n\
555 -l, --local limit listing to local filesystems\n\
556 -m, --megabytes like --block-size=1048576\n\
557 --no-sync do not invoke sync before getting usage info (default)\n\
558 -P, --portability use the POSIX output format\n\
559 --sync invoke sync before getting usage info\n\
560 -t, --type=TYPE limit listing to filesystems of type TYPE\n\
561 -T, --print-type print filesystem type\n\
562 -x, --exclude-type=TYPE limit listing to filesystems not of type TYPE\n\
564 --help display this help and exit\n\
565 --version output version information and exit\n\
567 puts (_("\nReport bugs to <fileutils-bugs@gnu.org>."));
574 main (int argc
, char **argv
)
579 program_name
= argv
[0];
580 setlocale (LC_ALL
, "");
581 bindtextdomain (PACKAGE
, LOCALEDIR
);
582 textdomain (PACKAGE
);
584 fs_select_list
= NULL
;
585 fs_exclude_list
= NULL
;
590 human_block_size (getenv ("DF_BLOCK_SIZE"), 0, &output_block_size
);
596 while ((c
= getopt_long (argc
, argv
, "aiF:hHklmPTt:vx:", long_options
, NULL
))
601 case 0: /* Long option. */
610 output_block_size
= -1024;
613 output_block_size
= -1000;
616 output_block_size
= 1024;
622 output_block_size
= 1024 * 1024;
638 human_block_size (optarg
, 1, &output_block_size
);
642 /* Accept -F as a synonym for -t for compatibility with Solaris. */
644 add_fs_type (optarg
);
647 case 'v': /* For SysV compatibility. */
651 add_excluded_fs_type (optarg
);
660 printf ("df (%s) %s\n", GNU_PACKAGE
, VERSION
);
668 /* Fail if the same file system type was both selected and excluded. */
671 struct fs_type_list
*i
;
672 for (i
= fs_select_list
; i
; i
= i
->fs_next
)
674 struct fs_type_list
*j
;
675 for (j
= fs_exclude_list
; j
; j
= j
->fs_next
)
677 if (STREQ (i
->fs_name
, j
->fs_name
))
680 _("file system type `%s' both selected and excluded"),
694 /* Suppress `used before initialized' warning. */
702 /* stat all the given entries to make sure they get automounted,
703 if necessary, before reading the filesystem table. */
704 stats
= (struct stat
*)
705 xmalloc ((argc
- optind
) * sizeof (struct stat
));
706 for (i
= optind
; i
< argc
; ++i
)
707 if (stat (argv
[i
], &stats
[i
- optind
]))
709 error (0, errno
, "%s", argv
[i
]);
716 read_filesystem_list ((fs_select_list
!= NULL
717 || fs_exclude_list
!= NULL
719 optind
== argc
? show_all_fs
: 1);
721 if (mount_list
== NULL
)
722 error (1, errno
, _("cannot read table of mounted filesystems"));
736 /* Display explicitly requested empty filesystems. */
740 for (i
= optind
; i
< argc
; ++i
)
742 show_entry (argv
[i
], &stats
[i
- optind
]);