1 /* df - summarize free disk space
2 Copyright (C) 91, 1995-1999 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>
36 #include "mountlist.h"
39 /* The official name of this program (e.g., no `g' prefix). */
40 #define PROGRAM_NAME "df"
43 "Torbjorn Granlund, David MacKenzie, Larry McVoy, and Paul Eggert"
45 void strip_trailing_slashes ();
49 /* Name this program was run with. */
52 /* If nonzero, show inode information. */
53 static int inode_format
;
55 /* If nonzero, show even filesystems with zero size or
56 uninteresting types. */
57 static int show_all_fs
;
59 /* If nonzero, show only local filesystems. */
60 static int show_local_fs
;
62 /* If nonzero, output data for each filesystem corresponding to a
63 command line argument -- even if it's a dummy (automounter) entry. */
64 static int show_listed_fs
;
66 /* If positive, the units to use when printing sizes;
67 if negative, the human-readable base. */
68 static int output_block_size
;
70 /* If nonzero, use the POSIX output format. */
71 static int posix_format
;
73 /* If nonzero, invoke the `sync' system call before getting any usage data.
74 Using this option can make df very slow, especially with many or very
75 busy disks. Note that this may make a difference on some systems --
76 SunOs4.1.3, for one. It is *not* necessary on Linux. */
77 static int require_sync
= 0;
79 /* Nonzero if errors have occurred. */
80 static int exit_status
;
82 /* A filesystem type to display. */
87 struct fs_type_list
*fs_next
;
90 /* Linked list of filesystem types to display.
91 If `fs_select_list' is NULL, list all types.
92 This table is generated dynamically from command-line options,
93 rather than hardcoding into the program what it thinks are the
94 valid filesystem types; let the user specify any filesystem type
95 they want to, and if there are any filesystems of that type, they
98 Some filesystem types:
99 4.2 4.3 ufs nfs swap ignore io vm efs dbg */
101 static struct fs_type_list
*fs_select_list
;
103 /* Linked list of filesystem types to omit.
104 If the list is empty, don't exclude any types. */
106 static struct fs_type_list
*fs_exclude_list
;
108 /* Linked list of mounted filesystems. */
109 static struct mount_entry
*mount_list
;
111 /* If nonzero, print filesystem type as well. */
112 static int print_type
;
114 static struct option
const long_options
[] =
116 {"all", no_argument
, NULL
, 'a'},
117 {"block-size", required_argument
, NULL
, CHAR_MAX
+ 3},
118 {"inodes", no_argument
, NULL
, 'i'},
119 {"human-readable", no_argument
, NULL
, 'h'},
120 {"si", no_argument
, NULL
, 'H'},
121 {"kilobytes", no_argument
, NULL
, 'k'},
122 {"local", no_argument
, NULL
, 'l'},
123 {"megabytes", no_argument
, NULL
, 'm'},
124 {"portability", no_argument
, NULL
, 'P'},
125 {"print-type", no_argument
, NULL
, 'T'},
126 {"sync", no_argument
, NULL
, CHAR_MAX
+ 1},
127 {"no-sync", no_argument
, NULL
, CHAR_MAX
+ 2},
128 {"type", required_argument
, NULL
, 't'},
129 {"exclude-type", required_argument
, NULL
, 'x'},
130 {GETOPT_HELP_OPTION_DECL
},
131 {GETOPT_VERSION_OPTION_DECL
},
138 printf ("Filesystem ");
146 printf (" Inodes IUsed IFree IUse%%");
147 else if (output_block_size
< 0)
148 printf (" Size Used Avail Use%%");
151 char buf
[LONGEST_HUMAN_READABLE
+ 1];
152 char *p
= human_readable (output_block_size
, buf
, 1, -1024);
154 /* Replace e.g. "1.0k" by "1k". */
155 size_t plen
= strlen (p
);
156 if (3 <= plen
&& strncmp (p
+ plen
- 3, ".0", 2) == 0)
157 strcpy (p
+ plen
- 3, p
+ plen
- 1);
159 printf (" %4s-blocks Used Available Use%%", p
);
162 printf (" Mounted on\n");
165 /* If FSTYPE is a type of filesystem that should be listed,
166 return nonzero, else zero. */
169 selected_fstype (const char *fstype
)
171 const struct fs_type_list
*fsp
;
173 if (fs_select_list
== NULL
|| fstype
== NULL
)
175 for (fsp
= fs_select_list
; fsp
; fsp
= fsp
->fs_next
)
176 if (STREQ (fstype
, fsp
->fs_name
))
181 /* If FSTYPE is a type of filesystem that should be omitted,
182 return nonzero, else zero. */
185 excluded_fstype (const char *fstype
)
187 const struct fs_type_list
*fsp
;
189 if (fs_exclude_list
== NULL
|| fstype
== NULL
)
191 for (fsp
= fs_exclude_list
; fsp
; fsp
= fsp
->fs_next
)
192 if (STREQ (fstype
, fsp
->fs_name
))
197 /* Like human_readable, except return "-" if the argument is -1. */
199 df_readable (uintmax_t n
, char *buf
,
200 int from_block_size
, int t_output_block_size
)
202 return (n
== -1 ? "-"
203 : human_readable (n
, buf
, from_block_size
, t_output_block_size
));
206 /* Display a space listing for the disk device with absolute path DISK.
207 If MOUNT_POINT is non-NULL, it is the path of the root of the
209 If FSTYPE is non-NULL, it is the type of the filesystem on DISK.
210 If MOUNT_POINT is non-NULL, then DISK may be NULL -- certain systems may
211 not be able to produce statistics in this case.
212 ME_DUMMY and ME_REMOTE are the mount entry flags. */
215 show_dev (const char *disk
, const char *mount_point
, const char *fstype
,
216 int me_dummy
, int me_remote
)
219 const char *stat_file
;
221 if (me_remote
&& show_local_fs
)
224 if (me_dummy
&& show_all_fs
== 0 && !show_listed_fs
)
227 if (!selected_fstype (fstype
) || excluded_fstype (fstype
))
230 /* If MOUNT_POINT is NULL, then the filesystem is not mounted, and this
231 program reports on the filesystem that the special file is on.
232 It would be better to report on the unmounted filesystem,
233 but statfs doesn't do that on most systems. */
234 stat_file
= mount_point
? mount_point
: disk
;
236 if (get_fs_usage (stat_file
, disk
, &fsu
))
238 error (0, errno
, "%s", stat_file
);
243 if (fsu
.fsu_blocks
== 0 && !show_all_fs
&& !show_listed_fs
)
247 disk
= "-"; /* unknown */
249 fstype
= "-"; /* unknown */
251 /* df.c reserved 5 positions for fstype,
252 but that does not suffice for type iso9660 */
255 int disk_name_len
= (int) strlen (disk
);
256 int fstype_len
= (int) strlen (fstype
);
257 if (disk_name_len
+ fstype_len
+ 2 < 20)
258 printf ("%s%*s ", disk
, 18 - disk_name_len
, fstype
);
259 else if (!posix_format
)
260 printf ("%s\n%18s ", disk
, fstype
);
262 printf ("%s %s", disk
, fstype
);
266 if ((int) strlen (disk
) > 20 && !posix_format
)
267 printf ("%s\n%20s", disk
, "");
269 printf ("%-20s", disk
);
274 char buf
[3][LONGEST_HUMAN_READABLE
+ 1];
275 double inodes_percent_used
;
276 uintmax_t inodes_used
;
277 int inode_units
= output_block_size
< 0 ? output_block_size
: 1;
279 if (fsu
.fsu_files
== -1 || fsu
.fsu_files
< fsu
.fsu_ffree
)
282 inodes_percent_used
= -1;
286 inodes_used
= fsu
.fsu_files
- fsu
.fsu_ffree
;
287 inodes_percent_used
=
288 (fsu
.fsu_files
== 0 ? 0
289 : inodes_used
* 100.0 / fsu
.fsu_files
);
292 printf (" %7s %7s %7s ",
293 df_readable (fsu
.fsu_files
, buf
[0], 1, inode_units
),
294 df_readable (inodes_used
, buf
[1], 1, inode_units
),
295 df_readable (fsu
.fsu_ffree
, buf
[2], 1, inode_units
));
297 if (inodes_percent_used
< 0)
300 printf ("%4.0f%%", inodes_percent_used
);
304 int w
= output_block_size
< 0 ? 5 : 9;
305 char buf
[2][LONGEST_HUMAN_READABLE
+ 1];
306 char availbuf
[LONGEST_HUMAN_READABLE
+ 2];
308 double blocks_percent_used
;
309 uintmax_t blocks_used
;
311 if (fsu
.fsu_blocks
== -1 || fsu
.fsu_blocks
< fsu
.fsu_bfree
)
314 blocks_percent_used
= -1;
318 blocks_used
= fsu
.fsu_blocks
- fsu
.fsu_bfree
;
319 blocks_percent_used
=
320 ((fsu
.fsu_bavail
== -1
321 || blocks_used
+ fsu
.fsu_bavail
== 0
322 || (fsu
.fsu_bavail_top_bit_set
323 ? blocks_used
< - fsu
.fsu_bavail
324 : fsu
.fsu_bfree
< fsu
.fsu_bavail
))
326 : blocks_used
* 100.0 / (blocks_used
+ fsu
.fsu_bavail
));
329 avail
= df_readable ((fsu
.fsu_bavail_top_bit_set
332 availbuf
+ 1, fsu
.fsu_blocksize
,
335 if (fsu
.fsu_bavail_top_bit_set
)
338 printf (" %*s %*s %*s ",
339 w
, df_readable (fsu
.fsu_blocks
, buf
[0], fsu
.fsu_blocksize
,
341 w
, df_readable (blocks_used
, buf
[1], fsu
.fsu_blocksize
,
345 if (blocks_percent_used
< 0)
348 printf ("%3.0f%%", blocks_percent_used
);
353 #ifdef HIDE_AUTOMOUNT_PREFIX
354 /* Don't print the first directory name in MOUNT_POINT if it's an
355 artifact of an automounter. This is a bit too aggressive to be
357 if (strncmp ("/auto/", mount_point
, 6) == 0)
359 else if (strncmp ("/tmp_mnt/", mount_point
, 9) == 0)
362 printf (" %s", mount_point
);
367 /* Identify the directory, if any, that device
368 DISK is mounted on, and show its disk usage. */
371 show_disk (const char *disk
)
373 struct mount_entry
*me
;
375 for (me
= mount_list
; me
; me
= me
->me_next
)
376 if (STREQ (disk
, me
->me_devname
))
378 show_dev (me
->me_devname
, me
->me_mountdir
, me
->me_type
,
379 me
->me_dummy
, me
->me_remote
);
382 /* No filesystem is mounted on DISK. */
383 show_dev (disk
, (char *) NULL
, (char *) NULL
, 0, 0);
386 /* Return the root mountpoint of the filesystem on which FILE exists, in
387 malloced storage. FILE_STAT should be the result of stating FILE. */
389 find_mount_point (const char *file
, const struct stat
*file_stat
)
391 struct saved_cwd cwd
;
392 struct stat last_stat
;
393 char *mp
= 0; /* The malloced mount point path. */
398 if (S_ISDIR (file_stat
->st_mode
))
399 /* FILE is a directory, so just chdir there directly. */
401 last_stat
= *file_stat
;
402 if (chdir (file
) < 0)
406 /* FILE is some other kind of file, we need to use its directory. */
409 char *tmp
= xstrdup (file
);
412 strip_trailing_slashes (tmp
);
413 dir
= dir_name (tmp
);
421 if (stat (".", &last_stat
) < 0)
425 /* Now walk up FILE's parents until we find another filesystem or /,
426 chdiring as we go. LAST_STAT holds stat information for the last place
431 if (stat ("..", &st
) < 0)
433 if (st
.st_dev
!= last_stat
.st_dev
|| st
.st_ino
== last_stat
.st_ino
)
434 /* cwd is the mount point. */
436 if (chdir ("..") < 0)
441 /* Finally reached a mount point, see what it's called. */
445 /* Restore the original cwd. */
447 int save_errno
= errno
;
448 if (restore_cwd (&cwd
, 0, mp
))
449 exit (1); /* We're scrod. */
457 /* Figure out which device file or directory POINT is mounted on
458 and show its disk usage.
459 STATP is the results of `stat' on POINT. */
461 show_point (const char *point
, const struct stat
*statp
)
463 struct stat disk_stats
;
464 struct mount_entry
*me
;
465 struct mount_entry
*matching_dummy
= NULL
;
467 for (me
= mount_list
; me
; me
= me
->me_next
)
469 if (me
->me_dev
== (dev_t
) -1)
471 if (stat (me
->me_mountdir
, &disk_stats
) == 0)
472 me
->me_dev
= disk_stats
.st_dev
;
475 error (0, errno
, "%s", me
->me_mountdir
);
477 /* So we won't try and fail repeatedly. */
478 me
->me_dev
= (dev_t
) -2;
482 if (statp
->st_dev
== me
->me_dev
)
484 /* Skip bogus mtab entries. */
485 if (stat (me
->me_mountdir
, &disk_stats
) != 0 ||
486 disk_stats
.st_dev
!= me
->me_dev
)
489 /* Prefer non-dummy entries. */
496 show_dev (me
->me_devname
, me
->me_mountdir
, me
->me_type
,
497 me
->me_dummy
, me
->me_remote
);
504 show_dev (matching_dummy
->me_devname
, matching_dummy
->me_mountdir
,
505 matching_dummy
->me_type
, 1, matching_dummy
->me_remote
);
509 /* We couldn't find the mount entry corresponding to POINT. Go ahead and
510 print as much info as we can; methods that require the device to be
511 present will fail at a later point. */
513 /* Find the actual mount point. */
514 char *mp
= find_mount_point (point
, statp
);
517 show_dev (0, mp
, 0, 0, 0);
521 error (0, errno
, "%s", point
);
525 /* Determine what kind of node PATH is and show the disk usage
526 for it. STATP is the results of `stat' on PATH. */
529 show_entry (const char *path
, const struct stat
*statp
)
531 if (S_ISBLK (statp
->st_mode
) || S_ISCHR (statp
->st_mode
))
534 show_point (path
, statp
);
537 /* Show all mounted filesystems, except perhaps those that are of
538 an unselected type or are empty. */
541 show_all_entries (void)
543 struct mount_entry
*me
;
545 for (me
= mount_list
; me
; me
= me
->me_next
)
546 show_dev (me
->me_devname
, me
->me_mountdir
, me
->me_type
,
547 me
->me_dummy
, me
->me_remote
);
550 /* Add FSTYPE to the list of filesystem types to display. */
553 add_fs_type (const char *fstype
)
555 struct fs_type_list
*fsp
;
557 fsp
= (struct fs_type_list
*) xmalloc (sizeof (struct fs_type_list
));
558 fsp
->fs_name
= (char *) fstype
;
559 fsp
->fs_next
= fs_select_list
;
560 fs_select_list
= fsp
;
563 /* Add FSTYPE to the list of filesystem types to be omitted. */
566 add_excluded_fs_type (const char *fstype
)
568 struct fs_type_list
*fsp
;
570 fsp
= (struct fs_type_list
*) xmalloc (sizeof (struct fs_type_list
));
571 fsp
->fs_name
= (char *) fstype
;
572 fsp
->fs_next
= fs_exclude_list
;
573 fs_exclude_list
= fsp
;
580 fprintf (stderr
, _("Try `%s --help' for more information.\n"),
584 printf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name
);
586 Show information about the filesystem on which each FILE resides,\n\
587 or all filesystems by default.\n\
589 -a, --all include filesystems having 0 blocks\n\
590 --block-size=SIZE use SIZE-byte blocks\n\
591 -h, --human-readable print sizes in human readable format (e.g., 1K 234M 2G)\n\
592 -H, --si likewise, but use powers of 1000 not 1024\n\
593 -i, --inodes list inode information instead of block usage\n\
594 -k, --kilobytes like --block-size=1024\n\
595 -l, --local limit listing to local filesystems\n\
596 -m, --megabytes like --block-size=1048576\n\
597 --no-sync do not invoke sync before getting usage info (default)\n\
598 -P, --portability use the POSIX output format\n\
599 --sync invoke sync before getting usage info\n\
600 -t, --type=TYPE limit listing to filesystems of type TYPE\n\
601 -T, --print-type print filesystem type\n\
602 -x, --exclude-type=TYPE limit listing to filesystems not of type TYPE\n\
604 --help display this help and exit\n\
605 --version output version information and exit\n\
607 puts (_("\nReport bugs to <bug-fileutils@gnu.org>."));
614 main (int argc
, char **argv
)
619 program_name
= argv
[0];
620 setlocale (LC_ALL
, "");
621 bindtextdomain (PACKAGE
, LOCALEDIR
);
622 textdomain (PACKAGE
);
624 fs_select_list
= NULL
;
625 fs_exclude_list
= NULL
;
630 human_block_size (getenv ("DF_BLOCK_SIZE"), 0, &output_block_size
);
636 while ((c
= getopt_long (argc
, argv
, "aiF:hHklmPTt:vx:", long_options
, NULL
))
641 case 0: /* Long option. */
650 output_block_size
= -1024;
653 output_block_size
= -1000;
656 output_block_size
= 1024;
662 output_block_size
= 1024 * 1024;
678 human_block_size (optarg
, 1, &output_block_size
);
682 /* Accept -F as a synonym for -t for compatibility with Solaris. */
684 add_fs_type (optarg
);
687 case 'v': /* For SysV compatibility. */
691 add_excluded_fs_type (optarg
);
694 case_GETOPT_HELP_CHAR
;
695 case_GETOPT_VERSION_CHAR (PROGRAM_NAME
, AUTHORS
);
702 /* Fail if the same file system type was both selected and excluded. */
705 struct fs_type_list
*i
;
706 for (i
= fs_select_list
; i
; i
= i
->fs_next
)
708 struct fs_type_list
*j
;
709 for (j
= fs_exclude_list
; j
; j
= j
->fs_next
)
711 if (STREQ (i
->fs_name
, j
->fs_name
))
714 _("file system type `%s' both selected and excluded"),
728 /* Suppress `used before initialized' warning. */
736 /* stat all the given entries to make sure they get automounted,
737 if necessary, before reading the filesystem table. */
738 stats
= (struct stat
*)
739 xmalloc ((argc
- optind
) * sizeof (struct stat
));
740 for (i
= optind
; i
< argc
; ++i
)
741 if (stat (argv
[i
], &stats
[i
- optind
]))
743 error (0, errno
, "%s", argv
[i
]);
750 read_filesystem_list ((fs_select_list
!= NULL
751 || fs_exclude_list
!= NULL
755 if (mount_list
== NULL
)
756 error (1, errno
, _("cannot read table of mounted filesystems"));
770 /* Display explicitly requested empty filesystems. */
774 for (i
= optind
; i
< argc
; ++i
)
776 show_entry (argv
[i
], &stats
[i
- optind
]);