1 /* df - summarize free disk space
2 Copyright (C) 91, 95, 96, 97, 1998 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.
20 --si and large file support added by eggert@twinsun.com. */
24 # include <inttypes.h>
27 #include <sys/types.h>
31 #include "mountlist.h"
40 void strip_trailing_slashes ();
44 /* Name this program was run with. */
47 /* If nonzero, show inode information. */
48 static int inode_format
;
50 /* If nonzero, show even filesystems with zero size or
51 uninteresting types. */
52 static int show_all_fs
;
54 /* If nonzero, show only local filesystems. */
55 static int show_local_fs
;
57 /* If nonzero, output data for each filesystem corresponding to a
58 command line argument -- even if it's a dummy (automounter) entry. */
59 static int show_listed_fs
;
61 /* If positive, the units to use when printing sizes;
62 if negative, the human-readable base. */
63 static int output_block_size
;
65 /* If nonzero, use the POSIX output format. */
66 static int posix_format
;
68 /* If nonzero, invoke the `sync' system call before getting any usage data.
69 Using this option can make df very slow, especially with many or very
70 busy disks. Note that this may make a difference on some systems --
71 SunOs4.1.3, for one. It is *not* necessary on Linux. */
72 static int require_sync
= 0;
74 /* Nonzero if errors have occurred. */
75 static int exit_status
;
77 /* A filesystem type to display. */
82 struct fs_type_list
*fs_next
;
85 /* Linked list of filesystem types to display.
86 If `fs_select_list' is NULL, list all types.
87 This table is generated dynamically from command-line options,
88 rather than hardcoding into the program what it thinks are the
89 valid filesystem types; let the user specify any filesystem type
90 they want to, and if there are any filesystems of that type, they
93 Some filesystem types:
94 4.2 4.3 ufs nfs swap ignore io vm efs dbg */
96 static struct fs_type_list
*fs_select_list
;
98 /* Linked list of filesystem types to omit.
99 If the list is empty, don't exclude any types. */
101 static struct fs_type_list
*fs_exclude_list
;
103 /* Linked list of mounted filesystems. */
104 static struct mount_entry
*mount_list
;
106 /* If nonzero, display usage information and exit. */
107 static int show_help
;
109 /* If nonzero, print the version on standard output and exit. */
110 static int show_version
;
112 /* If nonzero, print filesystem type as well. */
113 static int print_type
;
115 static struct option
const long_options
[] =
117 {"all", no_argument
, NULL
, 'a'},
118 {"block-size", required_argument
, NULL
, CHAR_MAX
+ 3},
119 {"inodes", no_argument
, NULL
, 'i'},
120 {"human-readable", no_argument
, NULL
, 'h'},
121 {"si", no_argument
, NULL
, 'H'},
122 {"kilobytes", no_argument
, NULL
, 'k'},
123 {"local", no_argument
, NULL
, 'l'},
124 {"megabytes", no_argument
, NULL
, 'm'},
125 {"portability", no_argument
, NULL
, 'P'},
126 {"print-type", no_argument
, NULL
, 'T'},
127 {"sync", no_argument
, NULL
, CHAR_MAX
+ 1},
128 {"no-sync", no_argument
, NULL
, CHAR_MAX
+ 2},
129 {"type", required_argument
, NULL
, 't'},
130 {"exclude-type", required_argument
, NULL
, 'x'},
131 {"help", no_argument
, &show_help
, 1},
132 {"version", no_argument
, &show_version
, 1},
139 printf ("Filesystem ");
147 printf (" Inodes IUsed IFree IUse%%");
148 else if (output_block_size
< 0)
149 printf (" Size Used Avail Use%%");
152 char buf
[LONGEST_HUMAN_READABLE
+ 1];
153 char *p
= human_readable (output_block_size
, buf
, 1, -1024);
155 /* Replace e.g. "1.0k" by "1k". */
156 size_t plen
= strlen (p
);
157 if (3 <= plen
&& strncmp (p
+ plen
- 3, ".0", 2) == 0)
158 strcpy (p
+ plen
- 3, p
+ plen
- 1);
160 printf (" %4s-blocks Used Available Use%%", p
);
163 printf (" Mounted on\n");
166 /* If FSTYPE is a type of filesystem that should be listed,
167 return nonzero, else zero. */
170 selected_fstype (const char *fstype
)
172 const struct fs_type_list
*fsp
;
174 if (fs_select_list
== NULL
|| fstype
== NULL
)
176 for (fsp
= fs_select_list
; fsp
; fsp
= fsp
->fs_next
)
177 if (STREQ (fstype
, fsp
->fs_name
))
182 /* If FSTYPE is a type of filesystem that should be omitted,
183 return nonzero, else zero. */
186 excluded_fstype (const char *fstype
)
188 const struct fs_type_list
*fsp
;
190 if (fs_exclude_list
== NULL
|| fstype
== NULL
)
192 for (fsp
= fs_exclude_list
; fsp
; fsp
= fsp
->fs_next
)
193 if (STREQ (fstype
, fsp
->fs_name
))
198 /* Like human_readable, except return "-" if the argument is -1. */
200 df_readable (uintmax_t n
, char *buf
,
201 int from_block_size
, int t_output_block_size
)
203 return (n
== -1 ? "-"
204 : human_readable (n
, buf
, from_block_size
, t_output_block_size
));
207 /* Display a space listing for the disk device with absolute path DISK.
208 If MOUNT_POINT is non-NULL, it is the path of the root of the
210 If FSTYPE is non-NULL, it is the type of the filesystem on DISK.
211 If MOUNT_POINT is non-NULL, then DISK may be NULL -- certain systems may
212 not be able to produce statistics in this case.
213 ME_DUMMY and ME_REMOTE are the mount entry flags. */
216 show_dev (const char *disk
, const char *mount_point
, const char *fstype
,
217 int me_dummy
, int me_remote
)
220 const char *stat_file
;
222 if (me_remote
&& show_local_fs
)
225 if (me_dummy
&& show_all_fs
== 0 && !show_listed_fs
)
228 if (!selected_fstype (fstype
) || excluded_fstype (fstype
))
231 /* If MOUNT_POINT is NULL, then the filesystem is not mounted, and this
232 program reports on the filesystem that the special file is on.
233 It would be better to report on the unmounted filesystem,
234 but statfs doesn't do that on most systems. */
235 stat_file
= mount_point
? mount_point
: disk
;
237 if (get_fs_usage (stat_file
, disk
, &fsu
))
239 error (0, errno
, "%s", stat_file
);
244 if (fsu
.fsu_blocks
== 0 && !show_all_fs
&& !show_listed_fs
)
248 disk
= "-"; /* unknown */
250 fstype
= "-"; /* unknown */
252 /* df.c reserved 5 positions for fstype,
253 but that does not suffice for type iso9660 */
256 int disk_name_len
= (int) strlen (disk
);
257 int fstype_len
= (int) strlen (fstype
);
258 if (disk_name_len
+ fstype_len
+ 2 < 20)
259 printf ("%s%*s ", disk
, 18 - disk_name_len
, fstype
);
260 else if (!posix_format
)
261 printf ("%s\n%18s ", disk
, fstype
);
263 printf ("%s %s", disk
, fstype
);
267 if ((int) strlen (disk
) > 20 && !posix_format
)
268 printf ("%s\n%20s", disk
, "");
270 printf ("%-20s", disk
);
275 char buf
[3][LONGEST_HUMAN_READABLE
+ 1];
276 double inodes_percent_used
;
277 uintmax_t inodes_used
;
278 int inode_units
= output_block_size
< 0 ? output_block_size
: 1;
280 if (fsu
.fsu_files
== -1 || fsu
.fsu_files
< fsu
.fsu_ffree
)
283 inodes_percent_used
= -1;
287 inodes_used
= fsu
.fsu_files
- fsu
.fsu_ffree
;
288 inodes_percent_used
=
289 (fsu
.fsu_files
== 0 ? 0
290 : inodes_used
* 100.0 / fsu
.fsu_files
);
293 printf (" %7s %7s %7s ",
294 df_readable (fsu
.fsu_files
, buf
[0], 1, inode_units
),
295 df_readable (inodes_used
, buf
[1], 1, inode_units
),
296 df_readable (fsu
.fsu_ffree
, buf
[2], 1, inode_units
));
298 if (inodes_percent_used
< 0)
301 printf ("%4.0f%%", inodes_percent_used
);
305 int w
= output_block_size
< 0 ? 5 : 9;
306 char buf
[2][LONGEST_HUMAN_READABLE
+ 1];
307 char availbuf
[LONGEST_HUMAN_READABLE
+ 2];
309 double blocks_percent_used
;
310 uintmax_t blocks_used
;
312 if (fsu
.fsu_blocks
== -1 || fsu
.fsu_blocks
< fsu
.fsu_bfree
)
315 blocks_percent_used
= -1;
319 blocks_used
= fsu
.fsu_blocks
- fsu
.fsu_bfree
;
320 blocks_percent_used
=
321 ((fsu
.fsu_bavail
== -1
322 || blocks_used
+ fsu
.fsu_bavail
== 0
323 || (fsu
.fsu_bavail_top_bit_set
324 ? blocks_used
< - fsu
.fsu_bavail
325 : fsu
.fsu_bfree
< fsu
.fsu_bavail
))
327 : blocks_used
* 100.0 / (blocks_used
+ fsu
.fsu_bavail
));
330 avail
= df_readable ((fsu
.fsu_bavail_top_bit_set
333 availbuf
+ 1, fsu
.fsu_blocksize
,
336 if (fsu
.fsu_bavail_top_bit_set
)
339 printf (" %*s %*s %*s ",
340 w
, df_readable (fsu
.fsu_blocks
, buf
[0], fsu
.fsu_blocksize
,
342 w
, df_readable (blocks_used
, buf
[1], fsu
.fsu_blocksize
,
346 if (blocks_percent_used
< 0)
349 printf ("%3.0f%%", blocks_percent_used
);
354 #ifdef HIDE_AUTOMOUNT_PREFIX
355 /* Don't print the first directory name in MOUNT_POINT if it's an
356 artifact of an automounter. This is a bit too aggressive to be
358 if (strncmp ("/auto/", mount_point
, 6) == 0)
360 else if (strncmp ("/tmp_mnt/", mount_point
, 9) == 0)
363 printf (" %s", mount_point
);
368 /* Identify the directory, if any, that device
369 DISK is mounted on, and show its disk usage. */
372 show_disk (const char *disk
)
374 struct mount_entry
*me
;
376 for (me
= mount_list
; me
; me
= me
->me_next
)
377 if (STREQ (disk
, me
->me_devname
))
379 show_dev (me
->me_devname
, me
->me_mountdir
, me
->me_type
,
380 me
->me_dummy
, me
->me_remote
);
383 /* No filesystem is mounted on DISK. */
384 show_dev (disk
, (char *) NULL
, (char *) NULL
, 0, 0);
387 /* Return the root mountpoint of the filesystem on which FILE exists, in
388 malloced storage. FILE_STAT should be the result of stating FILE. */
390 find_mount_point (const char *file
, const struct stat
*file_stat
)
392 struct saved_cwd cwd
;
393 struct stat last_stat
;
394 char *mp
= 0; /* The malloced mount point path. */
399 if (S_ISDIR (file_stat
->st_mode
))
400 /* FILE is a directory, so just chdir there directly. */
402 last_stat
= *file_stat
;
403 if (chdir (file
) < 0)
407 /* FILE is some other kind of file, we need to use its directory. */
410 char *tmp
= xstrdup (file
);
413 strip_trailing_slashes (tmp
);
414 dir
= dir_name (tmp
);
422 if (stat (".", &last_stat
) < 0)
426 /* Now walk up FILE's parents until we find another filesystem or /,
427 chdiring as we go. LAST_STAT holds stat information for the last place
432 if (stat ("..", &st
) < 0)
434 if (st
.st_dev
!= last_stat
.st_dev
|| st
.st_ino
== last_stat
.st_ino
)
435 /* cwd is the mount point. */
437 if (chdir ("..") < 0)
442 /* Finally reached a mount point, see what it's called. */
446 /* Restore the original cwd. */
448 int save_errno
= errno
;
449 if (restore_cwd (&cwd
, 0, mp
))
450 exit (1); /* We're scrod. */
458 /* Figure out which device file or directory POINT is mounted on
459 and show its disk usage.
460 STATP is the results of `stat' on POINT. */
462 show_point (const char *point
, const struct stat
*statp
)
464 struct stat disk_stats
;
465 struct mount_entry
*me
;
466 struct mount_entry
*matching_dummy
= NULL
;
468 for (me
= mount_list
; me
; me
= me
->me_next
)
470 if (me
->me_dev
== (dev_t
) -1)
472 if (stat (me
->me_mountdir
, &disk_stats
) == 0)
473 me
->me_dev
= disk_stats
.st_dev
;
476 error (0, errno
, "%s", me
->me_mountdir
);
478 /* So we won't try and fail repeatedly. */
479 me
->me_dev
= (dev_t
) -2;
483 if (statp
->st_dev
== me
->me_dev
)
485 /* Skip bogus mtab entries. */
486 if (stat (me
->me_mountdir
, &disk_stats
) != 0 ||
487 disk_stats
.st_dev
!= me
->me_dev
)
490 /* Prefer non-dummy entries. */
497 show_dev (me
->me_devname
, me
->me_mountdir
, me
->me_type
,
498 me
->me_dummy
, me
->me_remote
);
505 show_dev (matching_dummy
->me_devname
, matching_dummy
->me_mountdir
,
506 matching_dummy
->me_type
, 1, matching_dummy
->me_remote
);
510 /* We couldn't find the mount entry corresponding to POINT. Go ahead and
511 print as much info as we can; methods that require the device to be
512 present will fail at a later point. */
514 /* Find the actual mount point. */
515 char *mp
= find_mount_point (point
, statp
);
518 show_dev (0, mp
, 0, 0, 0);
522 error (0, errno
, "%s", point
);
526 /* Determine what kind of node PATH is and show the disk usage
527 for it. STATP is the results of `stat' on PATH. */
530 show_entry (const char *path
, const struct stat
*statp
)
532 if (S_ISBLK (statp
->st_mode
) || S_ISCHR (statp
->st_mode
))
535 show_point (path
, statp
);
538 /* Show all mounted filesystems, except perhaps those that are of
539 an unselected type or are empty. */
542 show_all_entries (void)
544 struct mount_entry
*me
;
546 for (me
= mount_list
; me
; me
= me
->me_next
)
547 show_dev (me
->me_devname
, me
->me_mountdir
, me
->me_type
,
548 me
->me_dummy
, me
->me_remote
);
551 /* Add FSTYPE to the list of filesystem types to display. */
554 add_fs_type (const char *fstype
)
556 struct fs_type_list
*fsp
;
558 fsp
= (struct fs_type_list
*) xmalloc (sizeof (struct fs_type_list
));
559 fsp
->fs_name
= (char *) fstype
;
560 fsp
->fs_next
= fs_select_list
;
561 fs_select_list
= fsp
;
564 /* Add FSTYPE to the list of filesystem types to be omitted. */
567 add_excluded_fs_type (const char *fstype
)
569 struct fs_type_list
*fsp
;
571 fsp
= (struct fs_type_list
*) xmalloc (sizeof (struct fs_type_list
));
572 fsp
->fs_name
= (char *) fstype
;
573 fsp
->fs_next
= fs_exclude_list
;
574 fs_exclude_list
= fsp
;
581 fprintf (stderr
, _("Try `%s --help' for more information.\n"),
585 printf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name
);
587 Show information about the filesystem on which each FILE resides,\n\
588 or all filesystems by default.\n\
590 -a, --all include filesystems having 0 blocks\n\
591 --block-size=SIZE use SIZE-byte blocks\n\
592 -h, --human-readable print sizes in human readable format (e.g., 1K 234M 2G)\n\
593 -H, --si likewise, but use powers of 1000 not 1024\n\
594 -i, --inodes list inode information instead of block usage\n\
595 -k, --kilobytes like --block-size=1024\n\
596 -l, --local limit listing to local filesystems\n\
597 -m, --megabytes like --block-size=1048576\n\
598 --no-sync do not invoke sync before getting usage info (default)\n\
599 -P, --portability use the POSIX output format\n\
600 --sync invoke sync before getting usage info\n\
601 -t, --type=TYPE limit listing to filesystems of type TYPE\n\
602 -T, --print-type print filesystem type\n\
603 -x, --exclude-type=TYPE limit listing to filesystems not of type TYPE\n\
605 --help display this help and exit\n\
606 --version output version information and exit\n\
608 puts (_("\nReport bugs to <bug-fileutils@gnu.org>."));
615 main (int argc
, char **argv
)
620 program_name
= argv
[0];
621 setlocale (LC_ALL
, "");
622 bindtextdomain (PACKAGE
, LOCALEDIR
);
623 textdomain (PACKAGE
);
625 fs_select_list
= NULL
;
626 fs_exclude_list
= NULL
;
631 human_block_size (getenv ("DF_BLOCK_SIZE"), 0, &output_block_size
);
637 while ((c
= getopt_long (argc
, argv
, "aiF:hHklmPTt:vx:", long_options
, NULL
))
642 case 0: /* Long option. */
651 output_block_size
= -1024;
654 output_block_size
= -1000;
657 output_block_size
= 1024;
663 output_block_size
= 1024 * 1024;
679 human_block_size (optarg
, 1, &output_block_size
);
683 /* Accept -F as a synonym for -t for compatibility with Solaris. */
685 add_fs_type (optarg
);
688 case 'v': /* For SysV compatibility. */
692 add_excluded_fs_type (optarg
);
701 printf ("df (%s) %s\n", GNU_PACKAGE
, VERSION
);
709 /* Fail if the same file system type was both selected and excluded. */
712 struct fs_type_list
*i
;
713 for (i
= fs_select_list
; i
; i
= i
->fs_next
)
715 struct fs_type_list
*j
;
716 for (j
= fs_exclude_list
; j
; j
= j
->fs_next
)
718 if (STREQ (i
->fs_name
, j
->fs_name
))
721 _("file system type `%s' both selected and excluded"),
735 /* Suppress `used before initialized' warning. */
743 /* stat all the given entries to make sure they get automounted,
744 if necessary, before reading the filesystem table. */
745 stats
= (struct stat
*)
746 xmalloc ((argc
- optind
) * sizeof (struct stat
));
747 for (i
= optind
; i
< argc
; ++i
)
748 if (stat (argv
[i
], &stats
[i
- optind
]))
750 error (0, errno
, "%s", argv
[i
]);
757 read_filesystem_list ((fs_select_list
!= NULL
758 || fs_exclude_list
!= NULL
762 if (mount_list
== NULL
)
763 error (1, errno
, _("cannot read table of mounted filesystems"));
777 /* Display explicitly requested empty filesystems. */
781 for (i
= optind
; i
< argc
; ++i
)
783 show_entry (argv
[i
], &stats
[i
- optind
]);