📄 df.c
字号:
goto done;
if (st.st_dev != last_stat.st_dev || st.st_ino == last_stat.st_ino)
/* cwd is the mount point. */
break;
if (chdir ("..") < 0)
goto done;
last_stat = st;
}
/* Finally reached a mount point, see what it's called. */
mp = xgetcwd ();
done:
/* Restore the original cwd. */
{
int save_errno = errno;
if (restore_cwd (&cwd, 0, mp))
exit (EXIT_FAILURE); /* We're scrod. */
free_cwd (&cwd);
errno = save_errno;
}
return mp;
}
/* Figure out which device file or directory POINT is mounted on
and show its disk usage.
STATP is the results of `stat' on POINT. */
static void
show_point (const char *point, const struct stat *statp)
{
struct stat disk_stats;
struct mount_entry *me;
struct mount_entry *matching_dummy = NULL;
char *needs_freeing = NULL;
/* If POINT is an absolute path name, see if we can find the
mount point without performing any extra stat calls at all. */
if (*point == '/')
{
for (me = mount_list; me; me = me->me_next)
{
if (STREQ (me->me_mountdir, point) && !STREQ (me->me_type, "lofs"))
{
/* Prefer non-dummy entries. */
if (! me->me_dummy)
goto show_me;
matching_dummy = me;
}
}
if (matching_dummy)
goto show_matching_dummy;
}
/* Ideally, the following mess of #if'd code would be in a separate
file, and there'd be a single function call here. FIXME, someday. */
#if HAVE_REALPATH || HAVE_RESOLVEPATH || HAVE_CANONICALIZE_FILE_NAME
/* Calculate the real absolute path for POINT, and use that to find
the mount point. This avoids statting unavailable mount points,
which can hang df. */
{
char const *abspoint = point;
char *resolved;
ssize_t resolved_len;
struct mount_entry *best_match = NULL;
# if HAVE_CANONICALIZE_FILE_NAME
resolved = canonicalize_file_name (abspoint);
resolved_len = resolved ? strlen (resolved) : -1;
# else
# if HAVE_RESOLVEPATH
/* All known hosts with resolvepath (e.g. Solaris 7) don't turn
relative names into absolute ones, so prepend the working
directory if the path is not absolute. */
if (*point != '/')
{
static char const *wd;
if (! wd)
{
struct stat pwd_stats;
struct stat dot_stats;
/* Use PWD if it is correct; this is usually cheaper than
xgetcwd. */
wd = getenv ("PWD");
if (! (wd
&& stat (wd, &pwd_stats) == 0
&& stat (".", &dot_stats) == 0
&& SAME_INODE (pwd_stats, dot_stats)))
wd = xgetcwd ();
}
if (wd)
{
needs_freeing = path_concat (wd, point, NULL);
if (needs_freeing)
abspoint = needs_freeing;
}
}
# endif
# if HAVE_RESOLVEPATH
{
size_t resolved_size = strlen (abspoint);
while (1)
{
resolved_size = 2 * resolved_size + 1;
resolved = xmalloc (resolved_size);
resolved_len = resolvepath (abspoint, resolved, resolved_size);
if (resolved_len < resolved_size)
break;
free (resolved);
}
}
# else
/* Use realpath only as a last resort.
It provides a very poor interface. */
resolved = xmalloc (PATH_MAX + 1);
resolved = (char *) realpath (abspoint, resolved);
resolved_len = resolved ? strlen (resolved) : -1;
# endif
# endif
if (1 <= resolved_len && resolved[0] == '/')
{
size_t best_match_len = 0;
for (me = mount_list; me; me = me->me_next)
if (! me->me_dummy)
{
size_t len = strlen (me->me_mountdir);
if (best_match_len < len && len <= resolved_len
&& (len == 1 /* root file system */
|| ((len == resolved_len || resolved[len] == '/')
&& strncmp (me->me_mountdir, resolved, len) == 0)))
{
best_match = me;
best_match_len = len;
}
}
}
if (resolved)
free (resolved);
if (best_match && !STREQ (best_match->me_type, "lofs")
&& stat (best_match->me_mountdir, &disk_stats) == 0
&& disk_stats.st_dev == statp->st_dev)
{
me = best_match;
goto show_me;
}
}
#endif
for (me = mount_list; me; me = me->me_next)
{
if (me->me_dev == (dev_t) -1)
{
if (stat (me->me_mountdir, &disk_stats) == 0)
me->me_dev = disk_stats.st_dev;
else
{
error (0, errno, "%s", quote (me->me_mountdir));
exit_status = 1;
/* So we won't try and fail repeatedly. */
me->me_dev = (dev_t) -2;
}
}
if (statp->st_dev == me->me_dev)
{
/* Skip bogus mtab entries. */
if (stat (me->me_mountdir, &disk_stats) != 0
|| disk_stats.st_dev != me->me_dev)
{
me->me_dev = (dev_t) -2;
continue;
}
/* Prefer non-dummy entries. */
if (! me->me_dummy)
goto show_me;
matching_dummy = me;
}
}
if (matching_dummy)
goto show_matching_dummy;
/* We couldn't find the mount entry corresponding to POINT. Go ahead and
print as much info as we can; methods that require the device to be
present will fail at a later point. */
{
/* Find the actual mount point. */
char *mp = find_mount_point (point, statp);
if (mp)
{
show_dev (0, mp, 0, 0, 0);
free (mp);
}
else
error (0, errno, "%s", quote (point));
}
goto free_then_return;
show_matching_dummy:
me = matching_dummy;
show_me:
show_dev (me->me_devname, me->me_mountdir, me->me_type, me->me_dummy,
me->me_remote);
free_then_return:
if (needs_freeing)
free (needs_freeing);
}
/* Determine what kind of node PATH is and show the disk usage
for it. STATP is the results of `stat' on PATH. */
static void
show_entry (const char *path, const struct stat *statp)
{
if (S_ISBLK (statp->st_mode) || S_ISCHR (statp->st_mode))
show_disk (path);
else
show_point (path, statp);
}
/* Show all mounted filesystems, except perhaps those that are of
an unselected type or are empty. */
static void
show_all_entries (void)
{
struct mount_entry *me;
for (me = mount_list; me; me = me->me_next)
show_dev (me->me_devname, me->me_mountdir, me->me_type,
me->me_dummy, me->me_remote);
}
/* Add FSTYPE to the list of filesystem types to display. */
static void
add_fs_type (const char *fstype)
{
struct fs_type_list *fsp;
fsp = (struct fs_type_list *) xmalloc (sizeof (struct fs_type_list));
fsp->fs_name = (char *) fstype;
fsp->fs_next = fs_select_list;
fs_select_list = fsp;
}
/* Add FSTYPE to the list of filesystem types to be omitted. */
static void
add_excluded_fs_type (const char *fstype)
{
struct fs_type_list *fsp;
fsp = (struct fs_type_list *) xmalloc (sizeof (struct fs_type_list));
fsp->fs_name = (char *) fstype;
fsp->fs_next = fs_exclude_list;
fs_exclude_list = fsp;
}
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name);
fputs (_("\
Show information about the filesystem on which each FILE resides,\n\
or all filesystems by default.\n\
\n\
"), stdout);
fputs (_("\
Mandatory arguments to long options are mandatory for short options too.\n\
"), stdout);
fputs (_("\
-a, --all include filesystems having 0 blocks\n\
-B, --block-size=SIZE use SIZE-byte blocks\n\
-h, --human-readable print sizes in human readable format (e.g., 1K 234M 2G)\n\
-H, --si likewise, but use powers of 1000 not 1024\n\
"), stdout);
fputs (_("\
-i, --inodes list inode information instead of block usage\n\
-k like --block-size=1K\n\
-l, --local limit listing to local filesystems\n\
--no-sync do not invoke sync before getting usage info (default)\n\
"), stdout);
fputs (_("\
-P, --portability use the POSIX output format\n\
--sync invoke sync before getting usage info\n\
-t, --type=TYPE limit listing to filesystems of type TYPE\n\
-T, --print-type print filesystem type\n\
-x, --exclude-type=TYPE limit listing to filesystems not of type TYPE\n\
-v (ignored)\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
fputs (_("\n\
SIZE may be (or may be an integer optionally followed by) one of following:\n\
kB 1000, K 1024, MB 1,000,000, M 1,048,576, and so on for G, T, P, E, Z, Y.\n\
"), stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status);
}
int
main (int argc, char **argv)
{
int c;
struct stat *stats IF_LINT (= 0);
int n_valid_args = 0;
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
fs_select_list = NULL;
fs_exclude_list = NULL;
inode_format = 0;
show_all_fs = 0;
show_listed_fs = 0;
human_block_size (getenv ("DF_BLOCK_SIZE"), 0, &output_block_size);
print_type = 0;
posix_format = 0;
exit_status = 0;
while ((c = getopt_long (argc, argv, "aB:iF:hHklmPTt:vx:", long_options, NULL))
!= -1)
{
switch (c)
{
case 0: /* Long option. */
break;
case 'a':
show_all_fs = 1;
break;
case 'B':
human_block_size (optarg, 1, &output_block_size);
break;
case 'i':
inode_format = 1;
break;
case 'h':
output_block_size = -1024;
break;
case 'H':
output_block_size = -1000;
break;
case 'k':
output_block_size = 1024;
break;
case 'l':
show_local_fs = 1;
break;
case 'm': /* obsolescent */
output_block_size = 1024 * 1024;
break;
case 'T':
print_type = 1;
break;
case 'P':
posix_format = 1;
break;
case SYNC_OPTION:
require_sync = 1;
break;
case NO_SYNC_OPTION:
require_sync = 0;
break;
case 'F':
/* Accept -F as a synonym for -t for compatibility with Solaris. */
case 't':
add_fs_type (optarg);
break;
case 'v': /* For SysV compatibility. */
/* ignore */
break;
case 'x':
add_excluded_fs_type (optarg);
break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
default:
usage (EXIT_FAILURE);
}
}
/* Fail if the same file system type was both selected and excluded. */
{
int match = 0;
struct fs_type_list *fs_incl;
for (fs_incl = fs_select_list; fs_incl; fs_incl = fs_incl->fs_next)
{
struct fs_type_list *fs_excl;
for (fs_excl = fs_exclude_list; fs_excl; fs_excl = fs_excl->fs_next)
{
if (STREQ (fs_incl->fs_name, fs_excl->fs_name))
{
error (0, 0,
_("file system type %s both selected and excluded"),
quote (fs_incl->fs_name));
match = 1;
break;
}
}
}
if (match)
exit (EXIT_FAILURE);
}
{
int i;
/* stat all the given entries to make sure they get automounted,
if necessary, before reading the filesystem table. */
stats = (struct stat *)
xmalloc ((argc - optind) * sizeof (struct stat));
for (i = optind; i < argc; ++i)
{
if (stat (argv[i], &stats[i - optind]))
{
error (0, errno, "%s", quote (argv[i]));
exit_status = 1;
argv[i] = NULL;
}
else
{
++n_valid_args;
}
}
}
mount_list =
read_filesystem_list ((fs_select_list != NULL
|| fs_exclude_list != NULL
|| print_type
|| show_local_fs));
if (mount_list == NULL)
{
/* Couldn't read the table of mounted filesystems.
Fail if df was invoked with no file name arguments;
Otherwise, merely give a warning and proceed. */
const char *warning = (optind == argc ? "" : _("Warning: "));
int status = (optind == argc ? 1 : 0);
error (status, errno,
_("%scannot read table of mounted filesystems"), warning);
}
if (require_sync)
sync ();
if (optind == argc)
{
print_header ();
show_all_entries ();
}
else
{
int i;
/* Display explicitly requested empty filesystems. */
show_listed_fs = 1;
if (n_valid_args > 0)
print_header ();
for (i = optind; i < argc; ++i)
if (argv[i])
show_entry (argv[i], &stats[i - optind]);
}
exit (exit_status);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -