df と ls

以下、昨日のメモです。
coreutils パケジのソースを解凍して色々確認。

df.c

まず df.c から。いっちゃん最後にある main() 関数のさらに最後らへん。

  if (optind < argc)
    {
      int i;

      /* Display explicitly requested empty file systems. */
      show_listed_fs = true;

      if (n_valid_args > 0)
	print_header ();

      for (i = optind; i < argc; ++i)
	if (argv[i])
	  show_entry (argv[i], &stats[i - optind]);
    }
  else
    {
      print_header ();
      show_all_entries ();
    }

通常 df には引数は渡さない、という事で対象は show_all_entries() な関数と見て掘削開始。show_all_entries() 関数の定義が以下。

/* Show all mounted file systems, 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, NULL, me->me_type,
	      me->me_dummy, me->me_remote);
}

コメント的にもビンゴな模様。がしかし、mount_list って何でしょ、と言いつつ M-t しても知らぬ、と言われます。ちなみに mount_list は df.c にて定義されてます。

/* Linked list of mounted file systems. */
static struct mount_entry *mount_list;

mount_entry 構造体はどこで定義されとるのかいな。include されてるヘッダの名前で適当なのに当たりを付けて find してみたら lib 配下にファイルを発見。lib/mountlist.h にて定義されている mount_entry 構造体の定義は以下。

/* A mount table entry. */
struct mount_entry
{
  char *me_devname;             /* Device node name, including "/dev/". */
  char *me_mountdir;            /* Mount point directory name. */
  char *me_type;                /* "nfs", "4.2", etc. */
  dev_t me_dev;                 /* Device number of me_mountdir. */
  unsigned int me_dummy : 1;    /* Nonzero for dummy file systems. */
  unsigned int me_remote : 1;   /* Nonzero for remote fileystems. */
  unsigned int me_type_malloced : 1; /* Nonzero if me_type was malloced. */
  struct mount_entry *me_next;
};

確かにリストになっとりますな。で、df.c にて mount_entry なリストのどこかのポインタを取得しているのが以下。

  mount_list =
    read_file_system_list ((fs_select_list != NULL
			    || fs_exclude_list != NULL
			    || print_type
			    || show_local_fs));

read_file_system_list() 関数の定義は lib/mountlist.c な模様。以下なコメントが関数定義の直上に記述。

/* Return a list of the currently mounted file systems, or NULL on error.
   Add each entry to the tail of the list so that they stay in order.
   If NEED_FS_TYPE is true, ensure that the file system type fields in
   the returned list are valid.  Otherwise, they might not be.  */

おそらく mount されたナニを順に列挙するんだろうと踏んで show_all_entries() に戻ってループの中で呼ばれている show_dev() 関数を確認。
この中で fs_usage 構造体なローカル領域に get_fs_usage() という関数を使って情報を取得している模様。

  if (get_fs_usage (stat_file, disk, &fsu))
    {
      error (0, errno, "%s", quote (stat_file));
      exit_status = EXIT_FAILURE;
      return;
    }

この fs_usage な構造体は lib/fsusage.h にて定義。

struct fs_usage
{
  uintmax_t fsu_blocksize;      /* Size of a block.  */
  uintmax_t fsu_blocks;         /* Total blocks. */
  uintmax_t fsu_bfree;          /* Free blocks available to superuser. */
  uintmax_t fsu_bavail;         /* Free blocks available to non-superuser. */
  bool fsu_bavail_top_bit_set;  /* 1 if fsu_bavail represents a value < 0.  */
  uintmax_t fsu_files;          /* Total file nodes. */
  uintmax_t fsu_ffree;          /* Free file nodes. */
};

ブロックサイズとかがあるな。で、get_fs_usage() 関数は fsusage.c にて定義。

int
get_fs_usage (char const *file, char const *disk, struct fs_usage *fsp)
{
#ifdef STAT_STATFS3_OSF1

  struct statfs fsd;

  if (statfs (file, &fsd, sizeof (struct statfs)) != 0)
    return -1;

statfs() はシステムコールです。df は statfs() を使って情報取得しているという事にします。

ls.c

読みづらい。stat() 読んでるとみて、とりあえず報告。カーネル側を読む方向。