.
[coreutils.git] / src / df.c
blobef4976f1ad6759b9638b073172a37b3abdd20712
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)
7 any later version.
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. */
21 #include <config.h>
22 #include <stdio.h>
23 #include <sys/types.h>
24 #include <getopt.h>
25 #include <assert.h>
27 #include "mountlist.h"
28 #include "fsusage.h"
29 #include "system.h"
30 #include "error.h"
32 char *xmalloc ();
33 char *xstrdup ();
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. */
42 char *program_name;
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. */
78 struct fs_type_list
80 char *fs_name;
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
90 will be shown.
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},
129 {NULL, 0, NULL, 0}
132 static void
133 print_header (void)
135 printf ("Filesystem ");
137 if (print_type)
138 printf (" Type");
139 else
140 printf (" ");
142 if (inode_format)
143 printf (" Inodes IUsed IFree %%IUsed");
144 else
145 if (megabyte_blocks)
146 printf (" MB-blocks Used Available Capacity");
147 else if (human_blocks)
148 printf (" Size Used Avail Capacity");
149 else
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. */
163 static char *
164 human_readable_1k_blocks (int n_1k_byte_blocks, char *buf, int buf_len)
166 const char *suffix;
167 double amt;
168 char *p;
170 assert (buf_len > LONGEST_HUMAN_READABLE_1K_BYTE_BLOCKS);
172 p = buf;
173 amt = n_1k_byte_blocks;
175 if (amt >= 1024 * 1024)
177 amt /= (1024 * 1024);
178 suffix = "G";
180 else if (amt >= 1024)
182 amt /= 1024;
183 suffix = "M";
185 else
187 suffix = "K";
190 if (amt >= 10)
192 sprintf (p, "%4.0f%s", amt, suffix);
194 else if (amt == 0)
196 strcpy (p, "0");
198 else
200 sprintf (p, "%4.1f%s", amt, suffix);
202 return (p);
205 /* If FSTYPE is a type of filesystem that should be listed,
206 return nonzero, else zero. */
208 static int
209 selected_fstype (const char *fstype)
211 const struct fs_type_list *fsp;
213 if (fs_select_list == NULL || fstype == NULL)
214 return 1;
215 for (fsp = fs_select_list; fsp; fsp = fsp->fs_next)
216 if (!strcmp (fstype, fsp->fs_name))
217 return 1;
218 return 0;
221 /* If FSTYPE is a type of filesystem that should be omitted,
222 return nonzero, else zero. */
224 static int
225 excluded_fstype (const char *fstype)
227 const struct fs_type_list *fsp;
229 if (fs_exclude_list == NULL || fstype == NULL)
230 return 0;
231 for (fsp = fs_exclude_list; fsp; fsp = fsp->fs_next)
232 if (!strcmp (fstype, fsp->fs_name))
233 return 1;
234 return 0;
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
239 filesystem on DISK.
240 If FSTYPE is non-NULL, it is the type of the filesystem on DISK. */
242 static void
243 show_dev (const char *disk, const char *mount_point, const char *fstype)
245 struct fs_usage fsu;
246 long blocks_used;
247 long blocks_percent_used;
248 long inodes_used;
249 long inodes_percent_used;
250 const char *stat_file;
252 if (!selected_fstype (fstype) || excluded_fstype (fstype))
253 return;
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);
264 exit_status = 1;
265 return;
268 if (megabyte_blocks)
270 fsu.fsu_blocks /= 2*1024;
271 fsu.fsu_bfree /= 2*1024;
272 fsu.fsu_bavail /= 2*1024;
274 else if (kilobyte_blocks)
276 fsu.fsu_blocks /= 2;
277 fsu.fsu_bfree /= 2;
278 fsu.fsu_bavail /= 2;
281 if (fsu.fsu_blocks == 0)
283 if (!show_all_fs && !show_listed_fs)
284 return;
285 blocks_used = fsu.fsu_bavail = blocks_percent_used = 0;
287 else
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;
298 else
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"), "");
309 if (print_type)
310 printf (" %-5s ", fstype);
312 if (inode_format)
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);
327 else
328 printf (" %7ld %7ld %7ld %5ld%% ",
329 fsu.fsu_blocks, blocks_used, fsu.fsu_bavail, blocks_percent_used);
331 if (mount_point)
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
336 the default. */
337 if (strncmp ("/auto/", mount_point, 6) == 0)
338 mount_point += 5;
339 else if (strncmp ("/tmp_mnt/", mount_point, 9) == 0)
340 mount_point += 8;
341 #endif
342 printf (" %s", mount_point);
344 putchar ('\n');
347 /* Identify the directory, if any, that device
348 DISK is mounted on, and show its disk usage. */
350 static void
351 show_disk (const char *disk)
353 struct mount_entry *me;
355 for (me = mount_list; me; me = me->me_next)
356 if (!strcmp (disk, me->me_devname))
358 show_dev (me->me_devname, me->me_mountdir, me->me_type);
359 return;
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. */
369 static void
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;
381 else
383 error (0, errno, "%s", me->me_mountdir);
384 exit_status = 1;
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)
395 continue;
396 show_dev (me->me_devname, me->me_mountdir, me->me_type);
397 return;
400 error (0, 0, _("cannot find mount point for %s"), point);
401 exit_status = 1;
404 /* Determine what kind of node PATH is and show the disk usage
405 for it. STATP is the results of `stat' on PATH. */
407 static void
408 show_entry (const char *path, const struct stat *statp)
410 if (S_ISBLK (statp->st_mode) || S_ISCHR (statp->st_mode))
411 show_disk (path);
412 else
413 show_point (path, statp);
416 /* Show all mounted filesystems, except perhaps those that are of
417 an unselected type or are empty. */
419 static void
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. */
430 static void
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. */
443 static void
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;
454 static void
455 usage (int status)
457 if (status != 0)
458 fprintf (stderr, _("Try `%s --help' for more information.\n"),
459 program_name);
460 else
462 printf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name);
463 printf (_("\
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\
476 -v (ignored)\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 exit (status);
486 main (int argc, char **argv)
488 int i;
489 struct stat *stats;
491 program_name = argv[0];
492 setlocale (LC_ALL, "");
493 bindtextdomain (PACKAGE, LOCALEDIR);
494 textdomain (PACKAGE);
496 fs_select_list = NULL;
497 fs_exclude_list = NULL;
498 inode_format = 0;
499 show_all_fs = 0;
500 show_listed_fs = 0;
502 if (getenv ("POSIXLY_CORRECT"))
503 kilobyte_blocks = 0;
504 else
506 char *bs;
507 kilobyte_blocks = 1;
508 if ((bs = getenv ("BLOCKSIZE"))
509 && strncmp (bs, "HUMAN", sizeof ("HUMAN") - 1) == 0)
510 human_blocks = 1;
513 print_type = 0;
514 posix_format = 0;
515 exit_status = 0;
517 while ((i = getopt_long (argc, argv, "aihkmPTt:vx:", long_options, NULL))
518 != EOF)
520 switch (i)
522 case 0: /* Long option. */
523 break;
524 case 'a':
525 show_all_fs = 1;
526 break;
527 case 'i':
528 inode_format = 1;
529 break;
530 case 'h':
531 human_blocks = 1;
532 kilobyte_blocks = 1;
533 megabyte_blocks = 0;
534 break;
535 case 'k':
536 human_blocks = 0;
537 kilobyte_blocks = 1;
538 megabyte_blocks = 0;
539 break;
540 case 'm':
541 human_blocks = 0;
542 kilobyte_blocks = 0;
543 megabyte_blocks = 1;
544 break;
545 case 'T':
546 print_type = 1;
547 break;
548 case 'P':
549 posix_format = 1;
550 break;
551 case 129:
552 require_sync = 1;
553 break;
554 case 130:
555 require_sync = 0;
556 break;
557 case 't':
558 add_fs_type (optarg);
559 break;
560 case 'v': /* For SysV compatibility. */
561 /* ignore */
562 break;
563 case 'x':
564 add_excluded_fs_type (optarg);
565 break;
566 default:
567 usage (1);
571 if (show_version)
573 printf ("df - %s\n", PACKAGE_VERSION);
574 exit (0);
577 if (show_help)
578 usage (0);
580 if (posix_format && megabyte_blocks)
581 error (1, 0, _("the option for counting 1MB blocks may not be used\n\
582 with the portable output format"));
584 if (posix_format && human_blocks)
585 error (1, 0,
586 _("the option for printing with adaptive units may not be used\n\
587 with the portable output format"));
589 /* Fail if the same file system type was both selected and excluded. */
591 int match = 0;
592 struct fs_type_list *i;
593 for (i = fs_select_list; i; i = i->fs_next)
595 struct fs_type_list *j;
596 for (j = fs_exclude_list; j; j = j->fs_next)
598 if (strcmp (i->fs_name, j->fs_name) == 0)
600 error (0, 0,
601 _("file system type `%s' both selected and excluded"),
602 i->fs_name);
603 match = 1;
604 break;
608 if (match)
609 exit (1);
612 if (optind == argc)
614 #ifdef lint
615 /* Suppress `used before initialized' warning. */
616 stats = NULL;
617 #endif
619 else
621 /* stat all the given entries to make sure they get automounted,
622 if necessary, before reading the filesystem table. */
623 stats = (struct stat *)
624 xmalloc ((argc - optind) * sizeof (struct stat));
625 for (i = optind; i < argc; ++i)
626 if (stat (argv[i], &stats[i - optind]))
628 error (0, errno, "%s", argv[i]);
629 exit_status = 1;
630 argv[i] = NULL;
634 mount_list =
635 read_filesystem_list ((fs_select_list != NULL
636 || fs_exclude_list != NULL
637 || print_type),
638 show_all_fs);
640 if (mount_list == NULL)
641 error (1, errno, _("cannot read table of mounted filesystems"));
643 print_header ();
644 if (require_sync)
645 sync ();
647 if (optind == argc)
648 show_all_entries ();
649 else
651 /* Display explicitly requested empty filesystems. */
652 show_listed_fs = 1;
654 for (i = optind; i < argc; ++i)
655 if (argv[i])
656 show_entry (argv[i], &stats[i - optind]);
659 exit (exit_status);