2011-04-01 25 views
5

我想知道/ dev文件所在的哪个条目。例如,如果/ dev/sdc1挂载在/ media/disk下,并且我要求/ media/disk/foo.txt,我想以/ dev/sdc作为回应。Linux编程:文件位于哪个设备

使用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 

在此先感谢!

回答

8

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

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

如果您将其限制为Linux,则可以使用/proc/mounts来获取已装入文件系统的列表。其他特定的Unix可以类似地进行优化:例如,在OS X上,我认为FreeBSD,您可以在vfs树上使用sysctl()来获取挂载点。在最坏的情况下,你可以找到并使用适当的头文件来解密任何挂载表文件(是的,甚至是不同的:在Solaris上它是/etc/mnttab,在许多其他系统上它是/etc/mtab,有些系统把它放在/var/run而不是/etc,在许多Linux上,它不存在或者符号连接到/proc/mounts)。其几乎所有类Unix操作系统的格式都不相同。

+0

谢谢,但我想实现这一目标只用系统/库调用。此外,你的建议是给我的分区号;-) – Grieih 2011-04-01 19:39:25

+0

@Grieih:+1,因为你从来没有指定你想要在C代码中。附:添加'-F'[0-9]''将删除分区号 – SiegeX 2011-04-01 19:51:28

+1

@Greih:请参阅更新。不幸的是,我出于某种原因去处理这个问题。 – geekosaur 2011-04-01 19:54:28

2

你在寻找什么是不可能的 - 块设备文件和它所描述的分区之间没有1:1的连接。

考虑:

  1. 您可以创建具有不同名称的多个块设备文件(但相同的主要和次要号码),他们是无法区分的(N:1)

  2. 可以使用将设备文件作为参数挂载以装入分区,然后删除块设备文件,使其离开挂载的分区。 (0:1)

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

1

主号码会告诉你它是哪个设备:3 - 第一个控制器上的IDE,22 - 第二个控制器上的IDE,SCSI上的8。

次要编号会告诉你分区号和 - 对于IDE设备 - 如果它是主驱动器或次驱动器。IDE和SCSI的计算方法不同。

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

对于SCSI它为:y * 16 + p,其中y是驱动器数字和p是分区

3

你想要的信息存在于暴露linux设备树的sysfs中。这样可以模拟系统中设备之间的关系,并且由于您试图从分区中确定父级磁盘设备,因此这里是您需要查看的地方。我不知道是否有任何硬性和快速规则可以用来阻止您的代码与未来版本的内核打交道,但内核开发人员确实试图将sysfs作为稳定的接口来维护。

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

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

或者,你可以采取在磁盘目录分区目录中的嵌套的优势(再次外壳,但是从C,它的open(2)read(2)close(2)):

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

,它假定您启动重大:其实是次要的分区,而不是一些其他种类的非嵌套设备。