1 /* df - summarize free disk space
2 Copyright (C) 91, 95, 1996 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. */
23 #include <sys/types.h>
27 #include "mountlist.h"
35 /* The maximum length of a human-readable string. Be pessimistic
36 and assume `int' is 64-bits wide. Converting 2^63 - 1 gives the
37 14-character string, 8796093022208G. The number being converted
38 is the number of 1024-byte blocks, so we divide by 1024 * 1024. */
39 #define LONGEST_HUMAN_READABLE_1K_BYTE_BLOCKS 14
41 /* Name this program was run with. */
44 /* If nonzero, show inode information. */
45 static int inode_format;
47 /* If nonzero, show even filesystems with zero size or
48 uninteresting types. */
49 static int show_all_fs;
51 /* If nonzero, output data for each filesystem corresponding to a
52 command line argument -- even if it's a dummy (automounter) entry. */
53 static int show_listed_fs;
55 /* If nonzero, use variable sized printouts instead of 512-byte blocks. */
56 static int human_blocks;
58 /* If nonzero, use 1K blocks instead of 512-byte blocks. */
59 static int kilobyte_blocks;
61 /* If nonzero, use 1M blocks instead of 512-byte blocks. */
62 static int megabyte_blocks;
64 /* If nonzero, use the POSIX output format. */
65 static int posix_format;
67 /* If nonzero, invoke the `sync' system call before getting any usage data.
68 Using this option can make df very slow, especially with many or very
69 busy disks. Note that this may make a difference on some systems --
70 SunOs4.1.3, for one. It is *not* necessary on Linux. */
71 static int require_sync = 0;
73 /* Nonzero if errors have occurred. */
74 static int exit_status;
76 /* A filesystem type to display. */
81 struct fs_type_list *fs_next;
84 /* Linked list of filesystem types to display.
85 If `fs_select_list' is NULL, list all types.
86 This table is generated dynamically from command-line options,
87 rather than hardcoding into the program what it thinks are the
88 valid filesystem types; let the user specify any filesystem type
89 they want to, and if there are any filesystems of that type, they
92 Some filesystem types:
93 4.2 4.3 ufs nfs swap ignore io vm efs dbg */
95 static struct fs_type_list *fs_select_list;
97 /* Linked list of filesystem types to omit.
98 If the list is empty, don't exclude any types. */
100 static struct fs_type_list *fs_exclude_list;
102 /* Linked list of mounted filesystems. */
103 static struct mount_entry *mount_list;
105 /* If nonzero, display usage information and exit. */
106 static int show_help;
108 /* If nonzero, print the version on standard output and exit. */
109 static int show_version;
111 /* If nonzero, print filesystem type as well. */
112 static int print_type;
114 static struct option const long_options[] =
116 {"all", no_argument, &show_all_fs, 1},
117 {"inodes", no_argument, &inode_format, 1},
118 {"human-readable", no_argument, 0, 'h'},
119 {"kilobytes", no_argument, 0, 'k'},
120 {"megabytes", no_argument, 0, 'm'},
121 {"portability", no_argument, &posix_format, 1},
122 {"print-type", no_argument, &print_type, 1},
123 {"sync", no_argument, 0, 129},
124 {"no-sync", no_argument, 0, 130},
125 {"type", required_argument, 0, 't'},
126 {"exclude-type", required_argument, 0, 'x'},
127 {"help", no_argument, &show_help, 1},
128 {"version", no_argument, &show_version, 1},
135 printf ("Filesystem ");
143 printf (" Inodes IUsed IFree %%IUsed");
146 printf (" MB-blocks Used Available Capacity");
147 else if (human_blocks)
148 printf (" Size Used Avail Capacity");
150 printf (" %s Used Available Capacity",
151 kilobyte_blocks ? "1024-blocks" : " 512-blocks");
152 printf (" Mounted on\n");
155 /* Convert N_1K_BYTE_BLOCKS to a more readable string than %d would.
156 Most people visually process strings of 3-4 digits effectively,
157 but longer strings of digits are more prone to misinterpretation.
158 Hence, converting to an abbreviated form usually improves readability.
159 Use a suffix indicating multiples of 1024 (M) and 1024*1024 (G).
160 For example, 8500 would be converted to 8.3M, 133456345 to 127G,
161 and so on. Numbers smaller than 1024 get the `K' suffix. */
164 human_readable_1k_blocks (int n_1k_byte_blocks, char *buf, int buf_len)
170 assert (buf_len > LONGEST_HUMAN_READABLE_1K_BYTE_BLOCKS);
173 amt = n_1k_byte_blocks;
175 if (amt >= 1024 * 1024)
177 amt /= (1024 * 1024);
180 else if (amt >= 1024)
192 sprintf (p, "%4.0f%s", amt, suffix);
200 sprintf (p, "%4.1f%s", amt, suffix);
205 /* If FSTYPE is a type of filesystem that should be listed,
206 return nonzero, else zero. */
209 selected_fstype (const char *fstype)
211 const struct fs_type_list *fsp;
213 if (fs_select_list == NULL || fstype == NULL)
215 for (fsp = fs_select_list; fsp; fsp = fsp->fs_next)
216 if (STREQ (fstype, fsp->fs_name))
221 /* If FSTYPE is a type of filesystem that should be omitted,
222 return nonzero, else zero. */
225 excluded_fstype (const char *fstype)
227 const struct fs_type_list *fsp;
229 if (fs_exclude_list == NULL || fstype == NULL)
231 for (fsp = fs_exclude_list; fsp; fsp = fsp->fs_next)
232 if (STREQ (fstype, fsp->fs_name))
237 /* Display a space listing for the disk device with absolute path DISK.
238 If MOUNT_POINT is non-NULL, it is the path of the root of the
240 If FSTYPE is non-NULL, it is the type of the filesystem on DISK. */
243 show_dev (const char *disk, const char *mount_point, const char *fstype)
247 long blocks_percent_used;
249 long inodes_percent_used;
250 const char *stat_file;
252 if (!selected_fstype (fstype) || excluded_fstype (fstype))
255 /* If MOUNT_POINT is NULL, then the filesystem is not mounted, and this
256 program reports on the filesystem that the special file is on.
257 It would be better to report on the unmounted filesystem,
258 but statfs doesn't do that on most systems. */
259 stat_file = mount_point ? mount_point : disk;
261 if (get_fs_usage (stat_file, disk, &fsu))
263 error (0, errno, "%s", stat_file);
270 fsu.fsu_blocks /= 2*1024;
271 fsu.fsu_bfree /= 2*1024;
272 fsu.fsu_bavail /= 2*1024;
274 else if (kilobyte_blocks)
281 if (fsu.fsu_blocks == 0)
283 if (!show_all_fs && !show_listed_fs)
285 blocks_used = fsu.fsu_bavail = blocks_percent_used = 0;
289 blocks_used = fsu.fsu_blocks - fsu.fsu_bfree;
290 blocks_percent_used = (long)
291 (blocks_used * 100.0 / (blocks_used + fsu.fsu_bavail) + 0.5);
294 if (fsu.fsu_files == 0)
296 inodes_used = fsu.fsu_ffree = inodes_percent_used = 0;
300 inodes_used = fsu.fsu_files - fsu.fsu_ffree;
301 inodes_percent_used = (long)
302 (inodes_used * 100.0 / fsu.fsu_files + 0.5);
305 printf ((print_type ? "%-13s" : "%-20s"), disk);
306 if (strlen (disk) > (print_type ? 13 : 20) && !posix_format)
307 printf ((print_type ? "\n%13s" : "\n%20s"), "");
310 printf (" %-5s ", fstype);
313 printf (" %7ld %7ld %7ld %5ld%%",
314 fsu.fsu_files, inodes_used, fsu.fsu_ffree, inodes_percent_used);
315 else if (human_blocks)
317 char buf[3][LONGEST_HUMAN_READABLE_1K_BYTE_BLOCKS + 1];
318 printf (" %4s %4s %5s %5ld%% ",
319 human_readable_1k_blocks (fsu.fsu_blocks, buf[0],
320 LONGEST_HUMAN_READABLE_1K_BYTE_BLOCKS + 1),
321 human_readable_1k_blocks (blocks_used, buf[1],
322 LONGEST_HUMAN_READABLE_1K_BYTE_BLOCKS + 1),
323 human_readable_1k_blocks (fsu.fsu_bavail, buf[2],
324 LONGEST_HUMAN_READABLE_1K_BYTE_BLOCKS + 1),
325 blocks_percent_used);
328 printf (" %7ld %7ld %7ld %5ld%% ",
329 fsu.fsu_blocks, blocks_used, fsu.fsu_bavail, blocks_percent_used);
333 #ifdef HIDE_AUTOMOUNT_PREFIX
334 /* Don't print the first directory name in MOUNT_POINT if it's an
335 artifact of an automounter. This is a bit too aggressive to be
337 if (strncmp ("/auto/", mount_point, 6) == 0)
339 else if (strncmp ("/tmp_mnt/", mount_point, 9) == 0)
342 printf (" %s", mount_point);
347 /* Identify the directory, if any, that device
348 DISK is mounted on, and show its disk usage. */
351 show_disk (const char *disk)
353 struct mount_entry *me;
355 for (me = mount_list; me; me = me->me_next)
356 if (STREQ (disk, me->me_devname))
358 show_dev (me->me_devname, me->me_mountdir, me->me_type);
361 /* No filesystem is mounted on DISK. */
362 show_dev (disk, (char *) NULL, (char *) NULL);
365 /* Figure out which device file or directory POINT is mounted on
366 and show its disk usage.
367 STATP is the results of `stat' on POINT. */
370 show_point (const char *point, const struct stat *statp)
372 struct stat disk_stats;
373 struct mount_entry *me;
375 for (me = mount_list; me; me = me->me_next)
377 if (me->me_dev == (dev_t) -1)
379 if (stat (me->me_mountdir, &disk_stats) == 0)
380 me->me_dev = disk_stats.st_dev;
383 error (0, errno, "%s", me->me_mountdir);
385 /* So we won't try and fail repeatedly. */
386 me->me_dev = (dev_t) -2;
390 if (statp->st_dev == me->me_dev)
392 /* Skip bogus mtab entries. */
393 if (stat (me->me_mountdir, &disk_stats) != 0 ||
394 disk_stats.st_dev != me->me_dev)
396 show_dev (me->me_devname, me->me_mountdir, me->me_type);
400 error (0, 0, _("cannot find mount point for %s"), point);
404 /* Determine what kind of node PATH is and show the disk usage
405 for it. STATP is the results of `stat' on PATH. */
408 show_entry (const char *path, const struct stat *statp)
410 if (S_ISBLK (statp->st_mode) || S_ISCHR (statp->st_mode))
413 show_point (path, statp);
416 /* Show all mounted filesystems, except perhaps those that are of
417 an unselected type or are empty. */
420 show_all_entries (void)
422 struct mount_entry *me;
424 for (me = mount_list; me; me = me->me_next)
425 show_dev (me->me_devname, me->me_mountdir, me->me_type);
428 /* Add FSTYPE to the list of filesystem types to display. */
431 add_fs_type (const char *fstype)
433 struct fs_type_list *fsp;
435 fsp = (struct fs_type_list *) xmalloc (sizeof (struct fs_type_list));
436 fsp->fs_name = (char *) fstype;
437 fsp->fs_next = fs_select_list;
438 fs_select_list = fsp;
441 /* Add FSTYPE to the list of filesystem types to be omitted. */
444 add_excluded_fs_type (const char *fstype)
446 struct fs_type_list *fsp;
448 fsp = (struct fs_type_list *) xmalloc (sizeof (struct fs_type_list));
449 fsp->fs_name = (char *) fstype;
450 fsp->fs_next = fs_exclude_list;
451 fs_exclude_list = fsp;
458 fprintf (stderr, _("Try `%s --help' for more information.\n"),
462 printf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name);
464 Show information about the filesystem on which each FILE resides,\n\
465 or all filesystems by default.\n\
467 -a, --all include filesystems having 0 blocks\n\
468 -h, --human-readable print sizes in human readable format (e.g. 1K 234M 2G)\n\
469 -i, --inodes list inode information instead of block usage\n\
470 -k, --kilobytes use 1024-byte blocks, not 512 despite POSIXLY_CORRECT\n\
471 -m, --megabytes use 1024K-byte blocks, not 512 despite POSIXLY_CORRECT\n\
472 --no-sync do not invoke sync before getting usage info (default)\n\
473 --sync invoke sync before getting usage info\n\
474 -t, --type=TYPE limit listing to filesystems of type TYPE\n\
475 -x, --exclude-type=TYPE limit listing to filesystems not of type TYPE\n\
477 -P, --portability use the POSIX output format\n\
478 -T, --print-type print filesystem type\n\
479 --help display this help and exit\n\
480 --version output version information and exit\n\
482 puts (_("\nReport bugs to bug-gnu-utils@gnu.ai.mit.edu"));
488 main (int argc, char **argv)
493 program_name = argv[0];
494 setlocale (LC_ALL, "");
495 bindtextdomain (PACKAGE, LOCALEDIR);
496 textdomain (PACKAGE);
498 fs_select_list = NULL;
499 fs_exclude_list = NULL;
504 if (getenv ("POSIXLY_CORRECT"))
510 if ((bs = getenv ("BLOCKSIZE"))
511 && strncmp (bs, "HUMAN", sizeof ("HUMAN") - 1) == 0)
519 while ((i = getopt_long (argc, argv, "aihkmPTt:vx:", long_options, NULL))
524 case 0: /* Long option. */
560 add_fs_type (optarg);
562 case 'v': /* For SysV compatibility. */
566 add_excluded_fs_type (optarg);
575 printf ("df - %s\n", PACKAGE_VERSION);
582 if (posix_format && megabyte_blocks)
583 error (1, 0, _("the option for counting 1MB blocks may not be used\n\
584 with the portable output format"));
586 if (posix_format && human_blocks)
588 _("the option for printing with adaptive units may not be used\n\
589 with the portable output format"));
591 /* Fail if the same file system type was both selected and excluded. */
594 struct fs_type_list *i;
595 for (i = fs_select_list; i; i = i->fs_next)
597 struct fs_type_list *j;
598 for (j = fs_exclude_list; j; j = j->fs_next)
600 if (STREQ (i->fs_name, j->fs_name))
603 _("file system type `%s' both selected and excluded"),
617 /* Suppress `used before initialized' warning. */
623 /* stat all the given entries to make sure they get automounted,
624 if necessary, before reading the filesystem table. */
625 stats = (struct stat *)
626 xmalloc ((argc - optind) * sizeof (struct stat));
627 for (i = optind; i < argc; ++i)
628 if (stat (argv[i], &stats[i - optind]))
630 error (0, errno, "%s", argv[i]);
637 read_filesystem_list ((fs_select_list != NULL
638 || fs_exclude_list != NULL
642 if (mount_list == NULL)
643 error (1, errno, _("cannot read table of mounted filesystems"));
653 /* Display explicitly requested empty filesystems. */
656 for (i = optind; i < argc; ++i)
658 show_entry (argv[i], &stats[i - optind]);