设备文件的大小( ls -l 输出中缺失)

设备文件的大小( ls -l 输出中缺失)

当我尝试打印设备文件时,输出显示十六进制格式的二进制数据。但是执行后ls -l /dev/sda我得到:

brw-rw----  1 root disk      8,   0 Jan 29 12:29 /dev/sda

我不明白文件的实际大小是多少?这些数字代表什么意思?

答案1

总结:这就是开发人员实现的ls.c。根据文件类型,长选项的输出字符串-l将以不同的方式构建。GNU 文档未提及格式差异(请参阅有关 OpenBSD 手册页的附注)。

设备文件和 ls 源代码

/dev/sda是块设备(本部分后面会解释)。它与常规文件不同。ls.c根据正在处理的文件类型构建长输出字符串。如下所示,对于块设备,输出字符串中不会附加任何有关大小的信息!

ls.c有以下几行代码:

   3757 static void
   3758 print_long_format (const struct fileinfo *f)
   3759 {

( partially omited )

   3868   if (f->stat_ok
   3869       && (S_ISCHR (f->stat.st_mode) || S_ISBLK (f->stat.st_mode)))
   3870     {
   3871       char majorbuf[INT_BUFSIZE_BOUND (uintmax_t)];
   3872       char minorbuf[INT_BUFSIZE_BOUND (uintmax_t)];
   3873       int blanks_width = (file_size_width
   3874                           - (major_device_number_width + 2
   3875                              + minor_device_number_width));
   3876       sprintf (p, "%*s, %*s ",
   3877                major_device_number_width + MAX (0, blanks_width),
   3878                umaxtostr (major (f->stat.st_rdev), majorbuf),
   3879                minor_device_number_width,
   3880                umaxtostr (minor (f->stat.st_rdev), minorbuf));
   3881       p += file_size_width + 1;
   3882     }
   3883   else
   3884     {
   3885       char hbuf[LONGEST_HUMAN_READABLE + 1];
   3886       char const *size =
   3887         (! f->stat_ok
   3888          ? "?"
   3889          : human_readable (unsigned_file_size (f->stat.st_size),
   3890                            hbuf, file_human_output_opts, 1,
   3891                            file_output_block_size));
   3892       int pad;
   3893       for (pad = file_size_width - mbswidth (size, 0); 0 < pad; pad--)
   3894         *p++ = ' ';
   3895       while ((*p++ = *size++))
   3896         continue;
   3897       p[-1] = ' ';
   3898     }

请注意,如果文件类型为S_ISCHR(字符设备,连续数据流)或 S_ISBLK(块设备,随机访问),则主设备号和次设备号将打印到字符数组中p(本质上是一个字符串)。这是附加到输出字符串的唯一数据p。然而,当我们else说到ls会明白我们正在处理文件除了块设备或字符设备之外p. 对于那些文件,它将存储在大小数组中的数据分配给该大小数组的下一段(这是while ((*p++ = *size++))一部分)。

核心思想是 ls 知道它正在查看的文件类型,并据此建立输出

设备文件到底是什么?

本质上它们是引用。它们是应用程序处理实际物理设备及其驱动程序的方式。例如,/dev/sda/dev/sr0(即 CD/DVD 驱动器)。有些设备只是抽象。例如,,/dev/zero/dev/null不是/dev/random物理设备。它们是与内核进程交互的方式。

因为它们是引用,所以它们没有文件大小是有道理的。可以知道这些文件在/dev目录中占用的大小,但它们与它们所代表的实际设备并不对应!

因此,开发人员以这种方式实现代码的原因也是可以理解的ls.c。99.99% 的情况下,引用的文件大小都是不需要的。

但是块设备(我们通常指的是硬盘和 USB 驱动器)是物理设备,具有真实的物理大小,那么我们如何找出这一点呢?

找出实际块设备的大小

下面的方法说明了如何找出 /dev/ 中块设备引用的硬盘 /ssd /USB 驱动器的大小

  • lsblk或者lsblk /dev/sda
  • sudo blockdev --getsize64 /dev/sda
  • sudo fdisk -l /dev/sdasudo fdisk -l适用于所有开发者
  • sudo parted /dev/sda printsudo parted -l适用于所有开发者
  • awk '{print $1*512}' /sys/class/block/sda/size
  • awk '{$3=$3*1024;print}' /proc/partitionsawk '$4 == "sda1" {$3=$3*1024;print}' /proc/partitions特定分区。

补充说明

  • /proc/devices包含与块设备对应的所有主设备编号的列表
  • dustat命令find可以显示这些引用的大小,但对于日常生活来说不是必需的(如果有的话)
  • 块设备的表示形式有所不同;一些文件实现了块的表示512(例如在/sys文件系统下),而其他文件 -1024。这是 Unix/Linux 世界中的惯例,因为这就是硬盘上实际物理块的分配方式。
  • 与 GNU 不同ls文档不同,OpenBSD 手册页明确指出:“如果文件是字符特殊文件或块特殊文件,文件的主设备号和次设备号显示在大小字段中“(我加了强调)

参考

答案2

我找不到任何文档来解释为什么ls显示它们而不是简单的0类似dustat的简单内容,但正如 Byte Commander 所说,它们是主设备号和次设备号该特殊文件。从源头来看

if (f->stat_ok
  && (S_ISCHR (f->stat.st_mode) || S_ISBLK (f->stat.st_mode)))
{
  char majorbuf[INT_BUFSIZE_BOUND (uintmax_t)];
  char minorbuf[INT_BUFSIZE_BOUND (uintmax_t)];
  int blanks_width = (file_size_width
                      - (major_device_number_width + 2
                         + minor_device_number_width));
  sprintf (p, "%*s, %*s ",
           major_device_number_width + MAX (0, blanks_width),
           umaxtostr (major (f->stat.st_rdev), majorbuf),
           minor_device_number_width,
           umaxtostr (minor (f->stat.st_rdev), minorbuf));
  p += file_size_width + 1;
}

此代码是print_long_format(),当输出格式很长(就是-l)时使用,使用设备编号代替字符和块设备的大小。

要获取设备的实际尺寸,可以列出以下几种方法这篇 Unix 和 Linux 文章

答案3

看来你错过了“一切皆文件”的概念。

在 UNIX 世界中,一切(数据、设备、套接字等)都映射到文件。这些文件有类型 - 就您的主目录而言,您(大多数情况下)会找到所谓的常规文件(文本、程序……)。

与这些常规文件相比,/dev 目录包含(顾名思义)设备文件。因此,您将找到以下类型的文件C性格,b锁定并ipe 代表设备,例如 /dev/mem 是一个代表系统内存的文件,/dev/ttyACM0 可以是一个串行调制解调器。这些(设备)文件和负责的驱动程序之间的链接是使用 ls 所示的主编号和次编号创建的(如上所述)。

设备的大小是设备特定的属性,必须使用设备特定的工具进行查询(如上文所示),因为没有唯一的方法来处理该属性(SSD 可能有固定大小 - 但串行端口可以提供无限的数据流,所以没有固定的大小,/dev/null 有无限的存储空间:))。

您可以在这里继续阅读:https://en.wikipedia.org/wiki/Everything_is_a_file

相关内容