【问题标题】:Linux programming: which device a file is inLinux编程:文件在哪个设备
【发布时间】:2011-07-27 22:35:47
【问题描述】:

我想知道文件在/dev下的哪个条目。例如,如果/dev/sdc1挂载在/media/disk下,我要求/media/disk/foo.txt,我想获取 /dev/sdc 作为响应。

在该文件上使用 stat 系统调用,我将获得它的分区主要和次要编号(8 和 33,对于 sdc1)。现在我需要从中获取“根”设备(sdc)或其主要/次要设备。是否有任何系统调用或库函数可用于将分区链接到其主设备?或者更好的是,直接从文件中获取该设备?

brw-rw---- 1 root floppy 8, 32 2011-04-01 20:00 /dev/sdc
brw-rw---- 1 root floppy 8, 33 2011-04-01 20:00 /dev/sdc1

提前致谢!

【问题讨论】:

    标签: c linux file device


    【解决方案1】:

    又快又脏的版本:df $file | awk 'NR == 2 {print $1}'

    以编程方式...好吧,我从快速而肮脏的版本开始是有原因的。没有可移植的方式以编程方式获取已安装文件系统的列表。 (getmntent() 得到fstab 条目,这不是一回事。)此外,您甚至无法可靠地解析mount(8) 的输出;在不同的 Unix 上,挂载点可能是第一项或最后一项。最便携的方法最终是...解析df 输出(即使这是不确定的,正如您在分区号上注意到的那样。)。所以无论如何你都回到了快速而肮脏的shell解决方案,除非你想遍历/dev并寻找与major(st_rdev)匹配的块设备(major()来自sys/types.h)。

    如果你把它限制在 Linux,你可以使用/proc/mounts 来获取挂载文件系统的列表。其他特定的 Unix 也可以类似地进行优化:例如,在 OS X 和我认为的 FreeBSD 上,您可以在 vfs 树上使用 sysctl() 来获取挂载点。在最坏的情况下,您可以找到并使用适当的头文件来破译任何挂载表文件(是的,即使是不同的:在 Solaris 上它是 /etc/mnttab,在许多其他系统上它是 /etc/mtab,有些系统将它放在 @987654335 @ 而不是 /etc,在许多 Linux 上,它要么不存在,要么是指向 /proc/mounts 的符号链接)。而且它的格式在几乎每个类 Unix 操作系统上都不同。

    【讨论】:

    • 谢谢,但我想只使用系统/库调用来实现这一点。另外,您的建议是给我分区号;-)
    • @Grieih:对此 +1,因为您从未在 C 代码中指定您想要这个。附言添加-F'[0-9]' 将删除分区号
    • @Greih:查看更新。不幸的是,我选择这样做是有原因的。
    • @Grieih,尽管作为一般规则应该避免使用system(),但它就是为此而生的。因为在这种情况下它允许更多的便携性,所以我不会对使用它感到难过。
    • 确实;在编写一个需要在 Linux 版本(包括 2.2 到 2.6 内核、几个 Solaris 版本、AIX 4.3 和 Tru64)上工作的文件系统监视器时,我看到了这一切的可怕之处。最后,我确保我需要担心的每个系统都安装了 GNU df(实际上,他们已经安装了)并解析了它的输出。
    【解决方案2】:

    您想要的信息存在于 sysfs 中,它公开了 linux 设备树。这对系统上的设备之间的关系进行建模,并且由于您试图从分区中确定父磁盘设备,因此这是查看的地方。我不知道您是否可以依靠任何硬性规则来阻止您的代码在未来版本的内核中出现问题,但内核开发人员确实会尝试将 sysfs 维护为一个稳定的接口。

    如果您查看/sys/dev/block/<major>:<minor>,您会发现它是一个符号链接,尾部组件为block/<disk-device-name>/<partition-device-name>。如果要对其执行readlink(2) 系统调用,则可以解析链接目标以获取磁盘设备名称。在 shell 中(因为这种方式更容易表达,但在 C 中会很容易):

    $ echo $(basename $(dirname $(readlink /sys/dev/block/8:33)))
    sdc
    

    或者,您可以利用磁盘目录中分区目录的嵌套(同样在 shell 中,但在 C 中,它是 open(2)read(2)close(2)):

    $ cat /sys/dev/block/8:33/../dev
    8:32
    

    假设您的起始专业:次要实际上是用于分区,而不是其他类型的非嵌套设备。

    【讨论】:

      【解决方案3】:

      您要查找的内容是不可能的 - 块设备文件和它所描述的分区之间没有 1:1 的连接。

      考虑:

      1. 您可以创建多个具有不同名称(但主次编号相同)且无法区分的块设备文件 (N:1)

      2. 您可以使用块设备文件作为挂载参数来挂载分区,然后删除块设备文件,使分区挂载。 (0:1)

      因此,除了少数特定和狭隘的情况外,没有办法做你想做的事。

      【讨论】:

        【解决方案4】:

        主要数字会告诉您它是哪个设备:3 - IDE 在第一个控制器上,22 - IDE 在第二个控制器上,8 用于 SCSI。

        次要数字将告诉您分区号以及 - 对于 IDE 设备 - 它是主驱动器还是辅助驱动器。这种计算对于 IDE 和 SCSI 是不同的。

        对于 IDE,它是:x*64 + p,x 是控制器上的驱动器号(0 或 1),p 是分区

        对于 SCSI,它是:y*16 + p,其中 y 是驱动器号,p 是分区

        【讨论】:

          【解决方案5】:

          不是系统调用,而是:

          df -h /path/to/my/file

          来自https://unix.stackexchange.com/questions/128471/determine-what-device-a-directory-is-located-on

          所以你可以看看 df 的源代码,看看它做了什么。

          我知道这篇文章很旧,但这个问题是我搜索的第二个结果,没有人提到 df -h

          【讨论】:

            猜你喜欢
            • 2022-01-14
            • 1970-01-01
            • 1970-01-01
            • 2012-05-26
            • 1970-01-01
            • 1970-01-01
            • 2013-03-23
            • 2017-04-21
            • 1970-01-01
            相关资源
            最近更新 更多