.
[coreutils.git] / src / df.c
blob3de9a62e104a8234a85790dd68a96a6212fa0e08
1 /* df - summarize free disk space
2 Copyright (C) 1991, 1995 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
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
18 /* Usage: df [-aikPT] [-t fstype] [-x fstype] [--all] [--inodes] [--print-type]
19 [--type fstype] [--exclude-type fstype] [--kilobytes] [--portability]
20 [file...]
22 Options:
23 -a, --all List all filesystems, even zero-size ones.
24 -i, --inodes List inode usage information instead of block usage.
25 -k, --kilobytes Print sizes in 1K blocks instead of 512-byte blocks.
26 -P, --portability Use the POSIX output format (one line per filesystem).
27 -T, --print-type Print filesystem type.
28 -t, --type fstype Limit the listing to filesystems of type `fstype'.
29 -x, --exclude-type=fstype
30 Limit the listing to filesystems not of type `fstype'.
31 Multiple -t and/or -x options can be given.
32 By default, all filesystem types are listed.
34 Written by David MacKenzie <djm@gnu.ai.mit.edu> */
36 #include <config.h>
37 #include <stdio.h>
38 #include <sys/types.h>
39 #include <getopt.h>
41 #include "mountlist.h"
42 #include "fsusage.h"
43 #include "system.h"
44 #include "version.h"
45 #include "error.h"
47 char *xmalloc ();
48 char *xstrdup ();
50 static int selected_fstype ();
51 static int excluded_fstype ();
52 static void add_excluded_fs_type ();
53 static void add_fs_type ();
54 static void print_header ();
55 static void show_entry ();
56 static void show_all_entries ();
57 static void show_dev ();
58 static void show_disk ();
59 static void show_point ();
60 static void usage ();
62 /* Name this program was run with. */
63 char *program_name;
65 /* If nonzero, show inode information. */
66 static int inode_format;
68 /* If nonzero, show even filesystems with zero size or
69 uninteresting types. */
70 static int show_all_fs;
72 /* If nonzero, output data for each filesystem corresponding to a
73 command line argument -- even if it's a dummy (automounter) entry. */
74 static int show_listed_fs;
76 /* If nonzero, use 1K blocks instead of 512-byte blocks. */
77 static int kilobyte_blocks;
79 /* If nonzero, use the POSIX output format. */
80 static int posix_format;
82 /* If nonzero, invoke the `sync' system call before getting any usage data.
83 Using this option can make df very slow, especially with many or very
84 busy disks. Default to non-zero because the sync call does make a
85 difference on some systems -- SunOs4.1.3, for one. I have been assured
86 that it is *not* necessary on Linux, so there should be a way to
87 configure this. FIXME. */
88 static int require_sync = 1;
90 /* Nonzero if errors have occurred. */
91 static int exit_status;
93 /* A filesystem type to display. */
95 struct fs_type_list
97 char *fs_name;
98 struct fs_type_list *fs_next;
101 /* Linked list of filesystem types to display.
102 If `fs_select_list' is NULL, list all types.
103 This table is generated dynamically from command-line options,
104 rather than hardcoding into the program what it thinks are the
105 valid filesystem types; let the user specify any filesystem type
106 they want to, and if there are any filesystems of that type, they
107 will be shown.
109 Some filesystem types:
110 4.2 4.3 ufs nfs swap ignore io vm efs dbg */
112 static struct fs_type_list *fs_select_list;
114 /* Linked list of filesystem types to omit.
115 If the list is empty, don't exclude any types. */
117 static struct fs_type_list *fs_exclude_list;
119 /* Linked list of mounted filesystems. */
120 static struct mount_entry *mount_list;
122 /* If non-zero, display usage information and exit. */
123 static int show_help;
125 /* If non-zero, print the version on standard output and exit. */
126 static int show_version;
128 /* If non-zero, print filesystem type as well. */
129 static int print_type;
131 static struct option const long_options[] =
133 {"all", no_argument, &show_all_fs, 1},
134 {"inodes", no_argument, &inode_format, 1},
135 {"kilobytes", no_argument, &kilobyte_blocks, 1},
136 {"portability", no_argument, &posix_format, 1},
137 {"print-type", no_argument, &print_type, 1},
138 {"sync", no_argument, 0, 129},
139 {"no-sync", no_argument, 0, 130},
140 {"type", required_argument, 0, 't'},
141 {"exclude-type", required_argument, 0, 'x'},
142 {"help", no_argument, &show_help, 1},
143 {"version", no_argument, &show_version, 1},
144 {NULL, 0, NULL, 0}
147 void
148 main (argc, argv)
149 int argc;
150 char **argv;
152 int i;
153 struct stat *stats;
155 program_name = argv[0];
156 fs_select_list = NULL;
157 fs_exclude_list = NULL;
158 inode_format = 0;
159 show_all_fs = 0;
160 show_listed_fs = 0;
161 kilobyte_blocks = getenv ("POSIXLY_CORRECT") == 0;
162 print_type = 0;
163 posix_format = 0;
164 exit_status = 0;
166 while ((i = getopt_long (argc, argv, "aikPTt:vx:", long_options, (int *) 0))
167 != EOF)
169 switch (i)
171 case 0: /* Long option. */
172 break;
173 case 'a':
174 show_all_fs = 1;
175 break;
176 case 'i':
177 inode_format = 1;
178 break;
179 case 'k':
180 kilobyte_blocks = 1;
181 break;
182 case 'T':
183 print_type = 1;
184 break;
185 case 'P':
186 posix_format = 1;
187 break;
188 case 129:
189 require_sync = 1;
190 break;
191 case 130:
192 require_sync = 0;
193 break;
194 case 't':
195 add_fs_type (optarg);
196 break;
197 case 'v': /* For SysV compatibility. */
198 break;
199 case 'x':
200 add_excluded_fs_type (optarg);
201 break;
202 default:
203 usage (1);
207 if (show_version)
209 printf ("df - %s\n", version_string);
210 exit (0);
213 if (show_help)
214 usage (0);
216 if (optind == argc)
218 #ifdef lint
219 /* Suppress `used before initialized' warning. */
220 stats = NULL;
221 #endif
223 else
225 /* stat all the given entries to make sure they get automounted,
226 if necessary, before reading the filesystem table. */
227 stats = (struct stat *)
228 xmalloc ((argc - optind) * sizeof (struct stat));
229 for (i = optind; i < argc; ++i)
230 if (stat (argv[i], &stats[i - optind]))
232 error (0, errno, "%s", argv[i]);
233 exit_status = 1;
234 argv[i] = NULL;
238 mount_list =
239 read_filesystem_list ((fs_select_list != NULL || fs_exclude_list != NULL),
240 show_all_fs);
242 if (mount_list == NULL)
243 error (1, errno, "cannot read table of mounted filesystems");
245 print_header ();
246 if (require_sync)
247 sync ();
249 if (optind == argc)
250 show_all_entries ();
251 else
253 /* Display explicitly requested empty filesystems. */
254 show_listed_fs = 1;
256 for (i = optind; i < argc; ++i)
257 if (argv[i])
258 show_entry (argv[i], &stats[i - optind]);
261 exit (exit_status);
264 static void
265 print_header ()
267 printf ("Filesystem ");
269 if (print_type)
270 printf (" Type");
271 else
272 printf (" ");
274 if (inode_format)
275 printf (" Inodes IUsed IFree %%IUsed");
276 else
277 printf (" %s Used Available Capacity",
278 kilobyte_blocks ? "1024-blocks" : " 512-blocks");
279 printf (" Mounted on\n");
282 /* Show all mounted filesystems, except perhaps those that are of
283 an unselected type or are empty. */
285 static void
286 show_all_entries ()
288 struct mount_entry *me;
290 for (me = mount_list; me; me = me->me_next)
291 show_dev (me->me_devname, me->me_mountdir, me->me_type);
294 /* Determine what kind of node PATH is and show the disk usage
295 for it. STATP is the results of `stat' on PATH. */
297 static void
298 show_entry (path, statp)
299 char *path;
300 struct stat *statp;
302 if (S_ISBLK (statp->st_mode) || S_ISCHR (statp->st_mode))
303 show_disk (path);
304 else
305 show_point (path, statp);
308 /* Identify the directory, if any, that device
309 DISK is mounted on, and show its disk usage. */
311 static void
312 show_disk (disk)
313 char *disk;
315 struct mount_entry *me;
317 for (me = mount_list; me; me = me->me_next)
318 if (!strcmp (disk, me->me_devname))
320 show_dev (me->me_devname, me->me_mountdir, me->me_type);
321 return;
323 /* No filesystem is mounted on DISK. */
324 show_dev (disk, (char *) NULL, (char *) NULL);
327 /* Figure out which device file or directory POINT is mounted on
328 and show its disk usage.
329 STATP is the results of `stat' on POINT. */
331 static void
332 show_point (point, statp)
333 char *point;
334 struct stat *statp;
336 struct stat disk_stats;
337 struct mount_entry *me;
339 for (me = mount_list; me; me = me->me_next)
341 if (me->me_dev == (dev_t) -1)
343 if (stat (me->me_mountdir, &disk_stats) == 0)
344 me->me_dev = disk_stats.st_dev;
345 else
347 error (0, errno, "%s", me->me_mountdir);
348 exit_status = 1;
349 me->me_dev = -2; /* So we won't try and fail repeatedly. */
353 if (statp->st_dev == me->me_dev)
355 show_dev (me->me_devname, me->me_mountdir, me->me_type);
356 return;
359 error (0, 0, "cannot find mount point for %s", point);
360 exit_status = 1;
363 /* Display a space listing for the disk device with absolute path DISK.
364 If MOUNT_POINT is non-NULL, it is the path of the root of the
365 filesystem on DISK.
366 If FSTYPE is non-NULL, it is the type of the filesystem on DISK. */
368 static void
369 show_dev (disk, mount_point, fstype)
370 char *disk;
371 char *mount_point;
372 char *fstype;
374 struct fs_usage fsu;
375 long blocks_used;
376 long blocks_percent_used;
377 long inodes_used;
378 long inodes_percent_used;
379 char *stat_file;
381 if (!selected_fstype (fstype) || excluded_fstype (fstype))
382 return;
384 /* If MOUNT_POINT is NULL, then the filesystem is not mounted, and this
385 program reports on the filesystem that the special file is on.
386 It would be better to report on the unmounted filesystem,
387 but statfs doesn't do that on most systems. */
388 stat_file = mount_point ? mount_point : disk;
390 if (get_fs_usage (stat_file, disk, &fsu))
392 error (0, errno, "%s", stat_file);
393 exit_status = 1;
394 return;
397 if (kilobyte_blocks)
399 fsu.fsu_blocks /= 2;
400 fsu.fsu_bfree /= 2;
401 fsu.fsu_bavail /= 2;
404 if (fsu.fsu_blocks == 0)
406 if (!show_all_fs && !show_listed_fs)
407 return;
408 blocks_used = fsu.fsu_bavail = blocks_percent_used = 0;
410 else
412 blocks_used = fsu.fsu_blocks - fsu.fsu_bfree;
413 blocks_percent_used = (long)
414 (blocks_used * 100.0 / (blocks_used + fsu.fsu_bavail) + 0.5);
417 if (fsu.fsu_files == 0)
419 inodes_used = fsu.fsu_ffree = inodes_percent_used = 0;
421 else
423 inodes_used = fsu.fsu_files - fsu.fsu_ffree;
424 inodes_percent_used = (long)
425 (inodes_used * 100.0 / fsu.fsu_files + 0.5);
428 printf ((print_type ? "%-13s" : "%-20s"), disk);
429 if (strlen (disk) > (print_type ? 13 : 20) && !posix_format)
430 printf ((print_type ? "\n%13s" : "\n%20s"), "");
432 if (print_type)
433 printf (" %-5s ", fstype);
435 if (inode_format)
436 printf (" %7ld %7ld %7ld %5ld%%",
437 fsu.fsu_files, inodes_used, fsu.fsu_ffree, inodes_percent_used);
438 else
439 printf (" %7ld %7ld %7ld %5ld%% ",
440 fsu.fsu_blocks, blocks_used, fsu.fsu_bavail, blocks_percent_used);
442 if (mount_point)
443 printf (" %s", mount_point);
444 putchar ('\n');
447 /* Add FSTYPE to the list of filesystem types to display. */
449 static void
450 add_fs_type (fstype)
451 char *fstype;
453 struct fs_type_list *fsp;
455 fsp = (struct fs_type_list *) xmalloc (sizeof (struct fs_type_list));
456 fsp->fs_name = fstype;
457 fsp->fs_next = fs_select_list;
458 fs_select_list = fsp;
461 /* Add FSTYPE to the list of filesystem types to be omitted. */
463 static void
464 add_excluded_fs_type (fstype)
465 char *fstype;
467 struct fs_type_list *fsp;
469 fsp = (struct fs_type_list *) xmalloc (sizeof (struct fs_type_list));
470 fsp->fs_name = fstype;
471 fsp->fs_next = fs_exclude_list;
472 fs_exclude_list = fsp;
475 /* If FSTYPE is a type of filesystem that should be listed,
476 return nonzero, else zero. */
478 static int
479 selected_fstype (fstype)
480 char *fstype;
482 struct fs_type_list *fsp;
484 if (fs_select_list == NULL || fstype == NULL)
485 return 1;
486 for (fsp = fs_select_list; fsp; fsp = fsp->fs_next)
487 if (!strcmp (fstype, fsp->fs_name))
488 return 1;
489 return 0;
493 /* If FSTYPE is a type of filesystem that should be omitted,
494 return nonzero, else zero. */
496 static int
497 excluded_fstype (fstype)
498 char *fstype;
500 struct fs_type_list *fsp;
502 if (fs_exclude_list == NULL || fstype == NULL)
503 return 0;
504 for (fsp = fs_exclude_list; fsp; fsp = fsp->fs_next)
505 if (!strcmp (fstype, fsp->fs_name))
506 return 1;
507 return 0;
510 static void
511 usage (status)
512 int status;
514 if (status != 0)
515 fprintf (stderr, "Try `%s --help' for more information.\n",
516 program_name);
517 else
519 printf ("Usage: %s [OPTION]... [FILE]...\n", program_name);
520 printf ("\
521 Show information about the filesystem on which each FILE resides,\n\
522 or all filesystems by default.\n\
524 -a, --all include filesystems having 0 blocks\n\
525 -i, --inodes list inode information instead of block usage\n\
526 -k, --kilobytes use 1024 blocks, not 512 despite POSIXLY_CORRECT\n\
527 --sync invoke sync before getting usage info (default)\n\
528 --no-sync do not invoke sync before getting usage info\n\
529 -t, --type=TYPE limit the listing to TYPE filesystems type\n\
530 -x, --exclude-type=TYPE limit the listing to not TYPE filesystems type\n\
531 -v (ignored)\n\
532 -P, --portability use the POSIX output format\n\
533 -T, --print-type print filesystem type\n\
534 --help display this help and exit\n\
535 --version output version information and exit\n");
537 exit (status);