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"
34 void strip_trailing_slashes ();
39 /* The maximum length of a human-readable string. Be pessimistic
40 and assume `int' is 64-bits wide. Converting 2^63 - 1 gives the
41 14-character string, 8796093022208G. The number being converted
42 is the number of 1024-byte blocks, so we divide by 1024 * 1024. */
43 #define LONGEST_HUMAN_READABLE_1K_BYTE_BLOCKS 14
45 /* Name this program was run with. */
48 /* If nonzero, show inode information. */
49 static int inode_format;
51 /* If nonzero, show even filesystems with zero size or
52 uninteresting types. */
53 static int show_all_fs;
55 /* If nonzero, output data for each filesystem corresponding to a
56 command line argument -- even if it's a dummy (automounter) entry. */
57 static int show_listed_fs;
59 /* If nonzero, use variable sized printouts instead of 512-byte blocks. */
60 static int human_blocks;
62 /* If nonzero, use 1K blocks instead of 512-byte blocks. */
63 static int kilobyte_blocks;
65 /* If nonzero, use 1M blocks instead of 512-byte blocks. */
66 static int megabyte_blocks;
68 /* If nonzero, use the POSIX output format. */
69 static int posix_format;
71 /* If nonzero, invoke the `sync' system call before getting any usage data.
72 Using this option can make df very slow, especially with many or very
73 busy disks. Note that this may make a difference on some systems --
74 SunOs4.1.3, for one. It is *not* necessary on Linux. */
75 static int require_sync = 0;
77 /* Nonzero if errors have occurred. */
78 static int exit_status;
80 /* A filesystem type to display. */
85 struct fs_type_list *fs_next;
88 /* Linked list of filesystem types to display.
89 If `fs_select_list' is NULL, list all types.
90 This table is generated dynamically from command-line options,
91 rather than hardcoding into the program what it thinks are the
92 valid filesystem types; let the user specify any filesystem type
93 they want to, and if there are any filesystems of that type, they
96 Some filesystem types:
97 4.2 4.3 ufs nfs swap ignore io vm efs dbg */
99 static struct fs_type_list *fs_select_list;
101 /* Linked list of filesystem types to omit.
102 If the list is empty, don't exclude any types. */
104 static struct fs_type_list *fs_exclude_list;
106 /* Linked list of mounted filesystems. */
107 static struct mount_entry *mount_list;
109 /* If nonzero, display usage information and exit. */
110 static int show_help;
112 /* If nonzero, print the version on standard output and exit. */
113 static int show_version;
115 /* If nonzero, print filesystem type as well. */
116 static int print_type;
118 static struct option const long_options[] =
120 {"all", no_argument, &show_all_fs, 1},
121 {"inodes", no_argument, &inode_format, 1},
122 {"human-readable", no_argument, 0, 'h'},
123 {"kilobytes", no_argument, 0, 'k'},
124 {"megabytes", no_argument, 0, 'm'},
125 {"portability", no_argument, &posix_format, 1},
126 {"print-type", no_argument, &print_type, 1},
127 {"sync", no_argument, 0, 129},
128 {"no-sync", no_argument, 0, 130},
129 {"type", required_argument, 0, 't'},
130 {"exclude-type", required_argument, 0, 'x'},
131 {"help", no_argument, &show_help, 1},
132 {"version", no_argument, &show_version, 1},
139 printf ("Filesystem ");
147 printf (" Inodes IUsed IFree %%IUsed");
150 printf (" MB-blocks Used Available Capacity");
151 else if (human_blocks)
152 printf (" Size Used Avail Capacity");
154 printf (" %s Used Available Capacity",
155 kilobyte_blocks ? "1024-blocks" : " 512-blocks");
156 printf (" Mounted on\n");
159 /* Convert N_1K_BYTE_BLOCKS to a more readable string than %d would.
160 Most people visually process strings of 3-4 digits effectively,
161 but longer strings of digits are more prone to misinterpretation.
162 Hence, converting to an abbreviated form usually improves readability.
163 Use a suffix indicating multiples of 1024 (M) and 1024*1024 (G).
164 For example, 8500 would be converted to 8.3M, 133456345 to 127G,
165 and so on. Numbers smaller than 1024 get the `K' suffix. */
168 human_readable_1k_blocks (int n_1k_byte_blocks, char *buf, int buf_len)
174 assert (buf_len > LONGEST_HUMAN_READABLE_1K_BYTE_BLOCKS);
177 amt = n_1k_byte_blocks;
179 if (amt >= 1024 * 1024)
181 amt /= (1024 * 1024);
184 else if (amt >= 1024)
196 sprintf (p, "%4.0f%s", amt, suffix);
204 sprintf (p, "%4.1f%s", amt, suffix);
209 /* If FSTYPE is a type of filesystem that should be listed,
210 return nonzero, else zero. */
213 selected_fstype (const char *fstype)
215 const struct fs_type_list *fsp;
217 if (fs_select_list == NULL || fstype == NULL)
219 for (fsp = fs_select_list; fsp; fsp = fsp->fs_next)
220 if (STREQ (fstype, fsp->fs_name))
225 /* If FSTYPE is a type of filesystem that should be omitted,
226 return nonzero, else zero. */
229 excluded_fstype (const char *fstype)
231 const struct fs_type_list *fsp;
233 if (fs_exclude_list == NULL || fstype == NULL)
235 for (fsp = fs_exclude_list; fsp; fsp = fsp->fs_next)
236 if (STREQ (fstype, fsp->fs_name))
241 /* Display a space listing for the disk device with absolute path DISK.
242 If MOUNT_POINT is non-NULL, it is the path of the root of the
244 If FSTYPE is non-NULL, it is the type of the filesystem on DISK.
245 If MOUNT_POINT is non-NULL, then DISK may be NULL -- certain systems may
246 not be able to produce statistics in this case. */
249 show_dev (const char *disk, const char *mount_point, const char *fstype)
253 long blocks_percent_used;
255 long inodes_percent_used;
256 const char *stat_file;
258 if (!selected_fstype (fstype) || excluded_fstype (fstype))
261 /* If MOUNT_POINT is NULL, then the filesystem is not mounted, and this
262 program reports on the filesystem that the special file is on.
263 It would be better to report on the unmounted filesystem,
264 but statfs doesn't do that on most systems. */
265 stat_file = mount_point ? mount_point : disk;
267 if (get_fs_usage (stat_file, disk, &fsu))
269 error (0, errno, "%s", stat_file);
276 fsu.fsu_blocks /= 2*1024;
277 fsu.fsu_bfree /= 2*1024;
278 fsu.fsu_bavail /= 2*1024;
280 else if (kilobyte_blocks)
287 if (fsu.fsu_blocks == 0)
289 if (!show_all_fs && !show_listed_fs)
291 blocks_used = fsu.fsu_bavail = blocks_percent_used = 0;
295 blocks_used = fsu.fsu_blocks - fsu.fsu_bfree;
296 blocks_percent_used = (long)
297 (blocks_used * 100.0 / (blocks_used + fsu.fsu_bavail) + 0.5);
300 if (fsu.fsu_files == 0)
302 inodes_used = fsu.fsu_ffree = inodes_percent_used = 0;
306 inodes_used = fsu.fsu_files - fsu.fsu_ffree;
307 inodes_percent_used = (long)
308 (inodes_used * 100.0 / fsu.fsu_files + 0.5);
312 disk = "-"; /* unknown */
314 printf ((print_type ? "%-13s" : "%-20s"), disk);
315 if ((int) strlen (disk) > (print_type ? 13 : 20) && !posix_format)
316 printf ((print_type ? "\n%13s" : "\n%20s"), "");
319 fstype = "-"; /* unknown */
321 printf (" %-5s ", fstype);
324 printf (" %7ld %7ld %7ld %5ld%%",
325 fsu.fsu_files, inodes_used, fsu.fsu_ffree, inodes_percent_used);
326 else if (human_blocks)
328 char buf[3][LONGEST_HUMAN_READABLE_1K_BYTE_BLOCKS + 1];
329 printf (" %4s %4s %5s %5ld%% ",
330 human_readable_1k_blocks (fsu.fsu_blocks, buf[0],
331 LONGEST_HUMAN_READABLE_1K_BYTE_BLOCKS + 1),
332 human_readable_1k_blocks (blocks_used, buf[1],
333 LONGEST_HUMAN_READABLE_1K_BYTE_BLOCKS + 1),
334 human_readable_1k_blocks (fsu.fsu_bavail, buf[2],
335 LONGEST_HUMAN_READABLE_1K_BYTE_BLOCKS + 1),
336 blocks_percent_used);
339 printf (" %7ld %7ld %7ld %5ld%% ",
340 fsu.fsu_blocks, blocks_used, fsu.fsu_bavail, blocks_percent_used);
344 #ifdef HIDE_AUTOMOUNT_PREFIX
345 /* Don't print the first directory name in MOUNT_POINT if it's an
346 artifact of an automounter. This is a bit too aggressive to be
348 if (strncmp ("/auto/", mount_point, 6) == 0)
350 else if (strncmp ("/tmp_mnt/", mount_point, 9) == 0)
353 printf (" %s", mount_point);
358 /* Identify the directory, if any, that device
359 DISK is mounted on, and show its disk usage. */
362 show_disk (const char *disk)
364 struct mount_entry *me;
366 for (me = mount_list; me; me = me->me_next)
367 if (STREQ (disk, me->me_devname))
369 show_dev (me->me_devname, me->me_mountdir, me->me_type);
372 /* No filesystem is mounted on DISK. */
373 show_dev (disk, (char *) NULL, (char *) NULL);
376 /* Return the root mountpoint of the filesystem on which FILE exists, in
377 malloced storage. FILE_STAT should be the result of stating FILE. */
379 find_mount_point (const char *file, const struct stat *file_stat)
381 struct saved_cwd cwd;
382 struct stat last_stat;
383 char *mp = 0; /* The malloced mount point path. */
388 if (S_ISDIR (file_stat->st_mode))
389 /* FILE is a directory, so just chdir there directly. */
391 last_stat = *file_stat;
392 if (chdir (file) < 0)
396 /* FILE is some other kind of file, we need to use its directory. */
399 char *tmp = xstrdup (file);
402 strip_trailing_slashes (tmp);
411 if (stat (".", &last_stat) < 0)
415 /* Now walk up FILE's parents until we find another filesystem or /,
416 chdiring as we go. LAST_STAT holds stat information for the last place
421 if (stat ("..", &st) < 0)
423 if (st.st_dev != last_stat.st_dev || st.st_ino == last_stat.st_ino)
424 /* cwd is the mount point. */
426 if (chdir ("..") < 0)
431 /* Finally reached a mount point, see what it's called. */
435 /* Restore the original cwd. */
437 int save_errno = errno;
438 if (restore_cwd (&cwd, 0, mp))
439 exit (1); /* We're scrod. */
447 /* Figure out which device file or directory POINT is mounted on
448 and show its disk usage.
449 STATP is the results of `stat' on POINT. */
451 show_point (const char *point, const struct stat *statp)
453 struct stat disk_stats;
454 struct mount_entry *me;
456 for (me = mount_list; me; me = me->me_next)
458 if (me->me_dev == (dev_t) -1)
460 if (stat (me->me_mountdir, &disk_stats) == 0)
461 me->me_dev = disk_stats.st_dev;
464 error (0, errno, "%s", me->me_mountdir);
466 /* So we won't try and fail repeatedly. */
467 me->me_dev = (dev_t) -2;
471 if (statp->st_dev == me->me_dev)
473 /* Skip bogus mtab entries. */
474 if (stat (me->me_mountdir, &disk_stats) != 0 ||
475 disk_stats.st_dev != me->me_dev)
477 show_dev (me->me_devname, me->me_mountdir, me->me_type);
482 /* We couldn't find the mount entry corresponding to POINT. Go ahead and
483 print as much info as we can; methods that require the device to be
484 present will fail at a later point. */
486 /* Find the actual mount point. */
487 char *mp = find_mount_point (point, statp);
494 error (0, errno, "%s", point);
498 /* Determine what kind of node PATH is and show the disk usage
499 for it. STATP is the results of `stat' on PATH. */
502 show_entry (const char *path, const struct stat *statp)
504 if (S_ISBLK (statp->st_mode) || S_ISCHR (statp->st_mode))
507 show_point (path, statp);
510 /* Show all mounted filesystems, except perhaps those that are of
511 an unselected type or are empty. */
514 show_all_entries (void)
516 struct mount_entry *me;
518 for (me = mount_list; me; me = me->me_next)
519 show_dev (me->me_devname, me->me_mountdir, me->me_type);
522 /* Add FSTYPE to the list of filesystem types to display. */
525 add_fs_type (const char *fstype)
527 struct fs_type_list *fsp;
529 fsp = (struct fs_type_list *) xmalloc (sizeof (struct fs_type_list));
530 fsp->fs_name = (char *) fstype;
531 fsp->fs_next = fs_select_list;
532 fs_select_list = fsp;
535 /* Add FSTYPE to the list of filesystem types to be omitted. */
538 add_excluded_fs_type (const char *fstype)
540 struct fs_type_list *fsp;
542 fsp = (struct fs_type_list *) xmalloc (sizeof (struct fs_type_list));
543 fsp->fs_name = (char *) fstype;
544 fsp->fs_next = fs_exclude_list;
545 fs_exclude_list = fsp;
552 fprintf (stderr, _("Try `%s --help' for more information.\n"),
556 printf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name);
558 Show information about the filesystem on which each FILE resides,\n\
559 or all filesystems by default.\n\
561 -a, --all include filesystems having 0 blocks\n\
562 -h, --human-readable print sizes in human readable format (e.g., 1K 234M 2G)\n\
563 -i, --inodes list inode information instead of block usage\n\
564 -k, --kilobytes use 1024-byte blocks, not 512 despite POSIXLY_CORRECT\n\
565 -m, --megabytes use 1024K-byte blocks, not 512 despite POSIXLY_CORRECT\n\
566 --no-sync do not invoke sync before getting usage info (default)\n\
567 -P, --portability use the POSIX output format\n\
568 --sync invoke sync before getting usage info\n\
569 -t, --type=TYPE limit listing to filesystems of type TYPE\n\
570 -T, --print-type print filesystem type\n\
571 -x, --exclude-type=TYPE limit listing to filesystems not of type TYPE\n\
573 --help display this help and exit\n\
574 --version output version information and exit\n\
576 puts (_("\nReport bugs to fileutils-bugs@gnu.ai.mit.edu"));
582 main (int argc, char **argv)
587 program_name = argv[0];
588 setlocale (LC_ALL, "");
589 bindtextdomain (PACKAGE, LOCALEDIR);
590 textdomain (PACKAGE);
592 fs_select_list = NULL;
593 fs_exclude_list = NULL;
598 if (getenv ("POSIXLY_CORRECT"))
604 if ((bs = getenv ("BLOCKSIZE"))
605 && strncmp (bs, "HUMAN", sizeof ("HUMAN") - 1) == 0)
613 while ((i = getopt_long (argc, argv, "aiF:hkmPTt:vx:", long_options, NULL))
618 case 0: /* Long option. */
655 /* Accept -F as a synonym for -t for compatibility with Solaris. */
657 add_fs_type (optarg);
660 case 'v': /* For SysV compatibility. */
664 add_excluded_fs_type (optarg);
673 printf ("df (%s) %s\n", GNU_PACKAGE, VERSION);
680 if (posix_format && megabyte_blocks)
681 error (1, 0, _("the option for counting 1MB blocks may not be used\n\
682 with the portable output format"));
684 if (posix_format && human_blocks)
686 _("the option for printing with adaptive units may not be used\n\
687 with the portable output format"));
689 /* Fail if the same file system type was both selected and excluded. */
692 struct fs_type_list *i;
693 for (i = fs_select_list; i; i = i->fs_next)
695 struct fs_type_list *j;
696 for (j = fs_exclude_list; j; j = j->fs_next)
698 if (STREQ (i->fs_name, j->fs_name))
701 _("file system type `%s' both selected and excluded"),
715 /* Suppress `used before initialized' warning. */
721 /* stat all the given entries to make sure they get automounted,
722 if necessary, before reading the filesystem table. */
723 stats = (struct stat *)
724 xmalloc ((argc - optind) * sizeof (struct stat));
725 for (i = optind; i < argc; ++i)
726 if (stat (argv[i], &stats[i - optind]))
728 error (0, errno, "%s", argv[i]);
735 read_filesystem_list ((fs_select_list != NULL
736 || fs_exclude_list != NULL
745 if (mount_list == NULL)
746 error (1, errno, _("cannot read table of mounted filesystems"));
752 /* Display explicitly requested empty filesystems. */
756 for (i = optind; i < argc; ++i)
758 show_entry (argv[i], &stats[i - optind]);