⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 df.c

📁 《linux应用开发技术详解》的配套代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	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 + -