.
[coreutils.git] / src / df.c
blob799ba2c75ceada24ccbfc2b4dab336e1905b7259
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 __P ((char *fstype));
51 static int excluded_fstype __P ((char *fstype));
52 static void add_excluded_fs_type __P ((char *fstype));
53 static void add_fs_type __P ((char *fstype));
54 static void print_header __P ((void));
55 static void show_entry __P ((char *path, struct stat *statp));
56 static void show_all_entries __P ((void));
57 static void show_dev __P ((char *disk, char *mount_point, char *fstype));
58 static void show_disk __P ((char *disk));
59 static void show_point __P ((char *point, struct stat *statp));
60 static void usage __P ((int status));
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 nonzero 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 nonzero, display usage information and exit. */
123 static int show_help;
125 /* If nonzero, print the version on standard output and exit. */
126 static int show_version;
128 /* If nonzero, 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 (int argc, char **argv)
150 int i;
151 struct stat *stats;
153 program_name = argv[0];
154 fs_select_list = NULL;
155 fs_exclude_list = NULL;
156 inode_format = 0;
157 show_all_fs = 0;
158 show_listed_fs = 0;
159 kilobyte_blocks = getenv ("POSIXLY_CORRECT") == 0;
160 print_type = 0;
161 posix_format = 0;
162 exit_status = 0;
164 while ((i = getopt_long (argc, argv, "aikPTt:vx:", long_options, (int *) 0))
165 != EOF)
167 switch (i)
169 case 0: /* Long option. */
170 break;
171 case 'a':
172 show_all_fs = 1;
173 break;
174 case 'i':
175 inode_format = 1;
176 break;
177 case 'k':
178 kilobyte_blocks = 1;
179 break;
180 case 'T':
181 print_type = 1;
182 break;
183 case 'P':
184 posix_format = 1;
185 break;
186 case 129:
187 require_sync = 1;
188 break;
189 case 130:
190 require_sync = 0;
191 break;
192 case 't':
193 add_fs_type (optarg);
194 break;
195 case 'v': /* For SysV compatibility. */
196 break;
197 case 'x':
198 add_excluded_fs_type (optarg);
199 break;
200 default:
201 usage (1);
205 if (show_version)
207 printf ("df - %s\n", version_string);
208 exit (0);
211 if (show_help)
212 usage (0);
214 /* Fail if the same file system type was both selected and excluded. */
216 int match = 0;
217 struct fs_type_list *i;
218 for (i = fs_select_list; i; i = i->fs_next)
220 struct fs_type_list *j;
221 for (j = fs_exclude_list; j; j = j->fs_next)
223 if (strcmp (i->fs_name, j->fs_name) == 0)
225 error (0, 0,
226 _("file system type `%s' both selected and excluded"),
227 i->fs_name);
228 match = 1;
229 break;
233 if (match)
234 exit (1);
237 if (optind == argc)
239 #ifdef lint
240 /* Suppress `used before initialized' warning. */
241 stats = NULL;
242 #endif
244 else
246 /* stat all the given entries to make sure they get automounted,
247 if necessary, before reading the filesystem table. */
248 stats = (struct stat *)
249 xmalloc ((argc - optind) * sizeof (struct stat));
250 for (i = optind; i < argc; ++i)
251 if (stat (argv[i], &stats[i - optind]))
253 error (0, errno, "%s", argv[i]);
254 exit_status = 1;
255 argv[i] = NULL;
259 mount_list =
260 read_filesystem_list ((fs_select_list != NULL || fs_exclude_list != NULL),
261 show_all_fs);
263 if (mount_list == NULL)
264 error (1, errno, _("cannot read table of mounted filesystems"));
266 print_header ();
267 if (require_sync)
268 sync ();
270 if (optind == argc)
271 show_all_entries ();
272 else
274 /* Display explicitly requested empty filesystems. */
275 show_listed_fs = 1;
277 for (i = optind; i < argc; ++i)
278 if (argv[i])
279 show_entry (argv[i], &stats[i - optind]);
282 exit (exit_status);
285 static void
286 print_header (void)
288 printf ("Filesystem ");
290 if (print_type)
291 printf (" Type");
292 else
293 printf (" ");
295 if (inode_format)
296 printf (" Inodes IUsed IFree %%IUsed");
297 else
298 printf (" %s Used Available Capacity",
299 kilobyte_blocks ? "1024-blocks" : " 512-blocks");
300 printf (" Mounted on\n");
303 /* Show all mounted filesystems, except perhaps those that are of
304 an unselected type or are empty. */
306 static void
307 show_all_entries (void)
309 struct mount_entry *me;
311 for (me = mount_list; me; me = me->me_next)
312 show_dev (me->me_devname, me->me_mountdir, me->me_type);
315 /* Determine what kind of node PATH is and show the disk usage
316 for it. STATP is the results of `stat' on PATH. */
318 static void
319 show_entry (char *path, struct stat *statp)
321 if (S_ISBLK (statp->st_mode) || S_ISCHR (statp->st_mode))
322 show_disk (path);
323 else
324 show_point (path, statp);
327 /* Identify the directory, if any, that device
328 DISK is mounted on, and show its disk usage. */
330 static void
331 show_disk (char *disk)
333 struct mount_entry *me;
335 for (me = mount_list; me; me = me->me_next)
336 if (!strcmp (disk, me->me_devname))
338 show_dev (me->me_devname, me->me_mountdir, me->me_type);
339 return;
341 /* No filesystem is mounted on DISK. */
342 show_dev (disk, (char *) NULL, (char *) NULL);
345 /* Figure out which device file or directory POINT is mounted on
346 and show its disk usage.
347 STATP is the results of `stat' on POINT. */
349 static void
350 show_point (char *point, struct stat *statp)
352 struct stat disk_stats;
353 struct mount_entry *me;
355 for (me = mount_list; me; me = me->me_next)
357 if (me->me_dev == (dev_t) -1)
359 if (stat (me->me_mountdir, &disk_stats) == 0)
360 me->me_dev = disk_stats.st_dev;
361 else
363 error (0, errno, "%s", me->me_mountdir);
364 exit_status = 1;
365 /* So we won't try and fail repeatedly. */
366 me->me_dev = (dev_t) -2;
370 if (statp->st_dev == me->me_dev)
372 /* Skip bogus mtab entries. */
373 if (stat (me->me_mountdir, &disk_stats) != 0 ||
374 disk_stats.st_dev != me->me_dev)
375 continue;
376 show_dev (me->me_devname, me->me_mountdir, me->me_type);
377 return;
380 error (0, 0, _("cannot find mount point for %s"), point);
381 exit_status = 1;
384 /* Display a space listing for the disk device with absolute path DISK.
385 If MOUNT_POINT is non-NULL, it is the path of the root of the
386 filesystem on DISK.
387 If FSTYPE is non-NULL, it is the type of the filesystem on DISK. */
389 static void
390 show_dev (char *disk, char *mount_point, char *fstype)
392 struct fs_usage fsu;
393 long blocks_used;
394 long blocks_percent_used;
395 long inodes_used;
396 long inodes_percent_used;
397 char *stat_file;
399 if (!selected_fstype (fstype) || excluded_fstype (fstype))
400 return;
402 /* If MOUNT_POINT is NULL, then the filesystem is not mounted, and this
403 program reports on the filesystem that the special file is on.
404 It would be better to report on the unmounted filesystem,
405 but statfs doesn't do that on most systems. */
406 stat_file = mount_point ? mount_point : disk;
408 if (get_fs_usage (stat_file, disk, &fsu))
410 error (0, errno, "%s", stat_file);
411 exit_status = 1;
412 return;
415 if (kilobyte_blocks)
417 fsu.fsu_blocks /= 2;
418 fsu.fsu_bfree /= 2;
419 fsu.fsu_bavail /= 2;
422 if (fsu.fsu_blocks == 0)
424 if (!show_all_fs && !show_listed_fs)
425 return;
426 blocks_used = fsu.fsu_bavail = blocks_percent_used = 0;
428 else
430 blocks_used = fsu.fsu_blocks - fsu.fsu_bfree;
431 blocks_percent_used = (long)
432 (blocks_used * 100.0 / (blocks_used + fsu.fsu_bavail) + 0.5);
435 if (fsu.fsu_files == 0)
437 inodes_used = fsu.fsu_ffree = inodes_percent_used = 0;
439 else
441 inodes_used = fsu.fsu_files - fsu.fsu_ffree;
442 inodes_percent_used = (long)
443 (inodes_used * 100.0 / fsu.fsu_files + 0.5);
446 printf ((print_type ? "%-13s" : "%-20s"), disk);
447 if (strlen (disk) > (print_type ? 13 : 20) && !posix_format)
448 printf ((print_type ? "\n%13s" : "\n%20s"), "");
450 if (print_type)
451 printf (" %-5s ", fstype);
453 if (inode_format)
454 printf (" %7ld %7ld %7ld %5ld%%",
455 fsu.fsu_files, inodes_used, fsu.fsu_ffree, inodes_percent_used);
456 else
457 printf (" %7ld %7ld %7ld %5ld%% ",
458 fsu.fsu_blocks, blocks_used, fsu.fsu_bavail, blocks_percent_used);
460 if (mount_point)
461 printf (" %s", mount_point);
462 putchar ('\n');
465 /* Add FSTYPE to the list of filesystem types to display. */
467 static void
468 add_fs_type (char *fstype)
470 struct fs_type_list *fsp;
472 fsp = (struct fs_type_list *) xmalloc (sizeof (struct fs_type_list));
473 fsp->fs_name = fstype;
474 fsp->fs_next = fs_select_list;
475 fs_select_list = fsp;
478 /* Add FSTYPE to the list of filesystem types to be omitted. */
480 static void
481 add_excluded_fs_type (char *fstype)
483 struct fs_type_list *fsp;
485 fsp = (struct fs_type_list *) xmalloc (sizeof (struct fs_type_list));
486 fsp->fs_name = fstype;
487 fsp->fs_next = fs_exclude_list;
488 fs_exclude_list = fsp;
491 /* If FSTYPE is a type of filesystem that should be listed,
492 return nonzero, else zero. */
494 static int
495 selected_fstype (char *fstype)
497 struct fs_type_list *fsp;
499 if (fs_select_list == NULL || fstype == NULL)
500 return 1;
501 for (fsp = fs_select_list; fsp; fsp = fsp->fs_next)
502 if (!strcmp (fstype, fsp->fs_name))
503 return 1;
504 return 0;
508 /* If FSTYPE is a type of filesystem that should be omitted,
509 return nonzero, else zero. */
511 static int
512 excluded_fstype (char *fstype)
514 struct fs_type_list *fsp;
516 if (fs_exclude_list == NULL || fstype == NULL)
517 return 0;
518 for (fsp = fs_exclude_list; fsp; fsp = fsp->fs_next)
519 if (!strcmp (fstype, fsp->fs_name))
520 return 1;
521 return 0;
524 static void
525 usage (int status)
527 if (status != 0)
528 fprintf (stderr, _("Try `%s --help' for more information.\n"),
529 program_name);
530 else
532 printf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name);
533 printf (_("\
534 Show information about the filesystem on which each FILE resides,\n\
535 or all filesystems by default.\n\
537 -a, --all include filesystems having 0 blocks\n\
538 -i, --inodes list inode information instead of block usage\n\
539 -k, --kilobytes use 1024 blocks, not 512 despite POSIXLY_CORRECT\n\
540 --sync invoke sync before getting usage info (default)\n\
541 --no-sync do not invoke sync before getting usage info\n\
542 -t, --type=TYPE limit listing to filesystems of type TYPE\n\
543 -x, --exclude-type=TYPE limit listing to filesystems not of type TYPE\n\
544 -v (ignored)\n\
545 -P, --portability use the POSIX output format\n\
546 -T, --print-type print filesystem type\n\
547 --help display this help and exit\n\
548 --version output version information and exit\n"));
550 exit (status);