Mac OS X/Darwin 上的 stat 有什么问题?或者没有名字的文件系统

Mac OS X/Darwin 上的 stat 有什么问题?或者没有名字的文件系统

在回答我关于 SO 的一个问题时,给出路径的挂载点,一位受访者建议使用stat来获取与给定路径的卷关联的设备名称。这在 Linux 上运行良好,但在 Mac OS X 10.4 上会产生奇怪的结果。对于我的系统,自由度给:

cas cas$ df
Filesystem              512-blocks     Used     Avail Capacity  Mounted on
/dev/disk0s3              58342896 49924456   7906440    86%    /
devfs                          194      194         0   100%    /dev
fdesc                            2        2         0   100%    /dev
<volfs>                       1024     1024         0   100%    /.vol
automount -nsl [166]             0        0         0   100%    /Network
automount -fstab [170]           0        0         0   100%    /automount/Servers
automount -static [170]          0        0         0   100%    /automount/static
/dev/disk2s1             163577856 23225520 140352336    14%    /Volumes/Snapshot
/dev/disk2s2             409404102  5745938 383187960     1%    /Volumes/Sparse
cas cas$ mount
/dev/disk0s3 on / (local, journaled)
devfs on /dev (local)
fdesc on /dev (union)
<volfs> on /.vol
automount -nsl [166] on /Network (automounted)
automount -fstab [170] on /automount/Servers (automounted)
automount -static [170] on /automount/static (automounted)
/dev/disk2s1 on /Volumes/Snapshot (local, nodev, nosuid, journaled)
/dev/disk2s2 on /Volumes/Sparse (asynchronous, local, nodev, nosuid)

但是尝试从挂载点获取设备:

cas cas$ df | grep -e/ 
            | awk '{print $NF}' 
            |  while read line; do echo $line $(stat -f"%Sdr" $line); done
/ disk0s3r
/dev ???r
/dev ???r
/.vol ???r
/Network ???r
/automount/Servers ???r
/automount/static ???r
/Volumes/Snapshot disk2s1r
/Volumes/Sparse disk2s2r

在这里,我正在将从中抓取的每个挂载点自由度统计,输出结果“%特别提款权”格式字符串,应该是设备名称:参见 stat(1) 手册页:

特殊输出说明符 S 可用于指示
输出(如果适用)应采用字符串格式。可以使用
结合:
...
             dr 显示实际的设备名称。

发生了什么事?这是统计或者一些达尔文 VFS 怪异现象?

后记根据安德鲁·麦格雷戈的说法,尝试传球“%Sd”统计更多怪异之处。它列出了一些来自 CWD 的看似任意的文件子集……

答案1

首先,作为统计格式,“%Sdr”被解释为d字段选择器,由说明符修改S,后跟一个小写的 R 字符。

如果在 的描述下用“d, r”代替“dr”,那么手册页可能会更清楚。Sd都是r单独的字段选择器。r从中选择设备编号统计(2)info(即 st_rdev;仅在统计设备条目(即 /dev 下的条目)时有用)。d选择保存统计条目(即 st_dev)的设备的设备号。它打印的数字是主号码和次号码的组合,如下所示ls(主要 << 24 | 次要)。

S是一个修饰符,可以应用于dr和其他几个字段选择器。当应用于d或 时r,它会尝试打印设备的名称而不是其原始编号。某些设备(如虚拟文件系统设备)没有正确的名称,因此它会打印???(如果打印出来可能会更好<major>,<minor>)。这并不意味着这些文件系统没有设备,只是它们的设备没有像“disk0s3”这样的正常名称。

“shell 怪异之处”(“显然是来自 CWD 的任意文件子集”)是由于缺少引号造成的。shell 看到(未加引号的)“???”结果并将其扩展为 glob 模式。如果 cwd 包含任何恰好三个字节(字符,取决于语言环境?)的条目,shell 将用 glob 模式替换这些条目。行为(引号和 glob 扩展)因 shell 而异,通常可以通过各种 shell 选项进行修改。

您可以像这样修改原始命令以避免通配符和尾随的“r”:

df | grep -e/ | awk '{print $NF}' |  while read line; do echo "$line" "$(stat -f%Sd "$line"); done

但我可能会这样写:

df | tail +2 | awk '{print $NF}' | xargs stat -f'%N %Sd %d'
  • 请注意,如果任何挂载的文件系统的挂载点名称中有空格,此操作将失败。或者自由度非常容易解析(两者都有可能包含几乎任意字符串的字段)。

通过该输出(名称、设备编号、设备名称),您也许可以更好地了解正在发生的事情。

或者,也许您除了想查看原始设备编号之外,还想查看主编号和次编号(将它们与您在 (eg) 中看到的内容进行比较ls -l /dev/disk0s3):

df | tail +2 | awk '{print $NF}' | xargs stat -f'%N %Sd %d' | 
  awk 'BEGIN{f=2^24} {$(NF+1) = int($NF/f) "," ($NF%f) } 1'

这是一个小型 C 程序,可以替换有问题的“df | head | awk”管道。

当然,这样的 C 程序可以自己完成剩下的工作,但是如果有一个独立的程序可以输出以 NUL 终止的挂载点就更好了。

mountz | xargs -0 stat -f'%N %Sd %d' | 
  awk 'BEGIN{f=2^24} {$(NF+1) = int($NF/f) "," ($NF%f) } 1'

代码:

#include <sys/mount.h>
#include <stdio.h>
#include <stdlib.h>

/* usage: mountz | xargs -0 command_for_each_mount_point */

int main(int argc, const char *argv[]) {
    struct statfs *buf;
    int flags = MNT_NOWAIT, num_fs, num_stat, i;
    unsigned bufsz;

    num_fs = getfsstat(NULL, 0, flags);
    if (num_fs < 0) {
        perror("unable to count mounted filesystems: getfsstat");
    exit(1);
    }

    bufsz = sizeof(*buf) * num_fs;
    buf = malloc(bufsz);
    if (!buf) {
        perror("unable to allocate %u statfs structs");
    exit(1);
    }
    fprintf(stderr, "p=%p\n", buf);

    num_stat = getfsstat(buf, bufsz, flags);
    if (num_stat < 0) {
        perror("unable to getfsstat");
    exit(1);
    }
    if (num_stat != num_fs) {
    fprintf(stderr, "Hmm, expected %u, got %d.\n", num_fs, num_stat);
    }

    for (i = 0; i < num_stat; i++) {
    fprintf(stdout, "%s%c", buf[i].f_mntonname, 0);
    }
}

答案2

因此虚拟文件系统没有设备 - 我没有尝试过这些文件系统。对于 /Network、/automount/Servers 或 /automount/static 来说这不是问题,因为它们不应该包含文件。但 /dev 很有趣。

答案3

df | grep -e/ | awk '{print $NF}' |  while read line; do echo $line $(stat -f"%Sd" $line); done
/ disk0s2
/dev XGS bin tmp
/net XGS bin tmp
/home XGS bin tmp

我想说,达尔文 VFS 很奇怪。

相关内容