*无需*字符串操作即可查找文件系统的分区和块设备

*无需*字符串操作即可查找文件系统的分区和块设备

给定一个文件系统,例如/dev/sda5或 ,/dev/mmcblk0p5是否可以在不进行字符串操作的情况下获取分区号(5)和块设备(即/dev/mmcblk0),或者通过最小化所需的字符串解析量来获取分区号( )和块设备(即 )?

假设内核为 5.x。下面的示例来自运行 5.10 的设备,但是如果答案是特定于内核或配置的,请在答案中指出。

详细信息/示例:

udevadm info(在 v247 中)返回许多有价值的信息,包括PARTN属性。 然而我不相信有一种方法可以“打印财产 X 的价值”。在 v247 中(可能在 v251 中?)所以我们将被降级为解析输出以查找我们的属性和值,例如:

udevadm info /dev/disk/by-label/rootfs | grep -e '^E: PARTN=' | awk -F '=' '{print $2}'    # prints '2'

udevadm还包括major稍后可能对我们有所帮助的数字,但没有“磁盘”属性或类似属性。

我们还可以通过读取 sysfs 文件来找到分区号,/sys/class/block/mmcblk0p2/partition假设我们愿意剥离/dev/留下mmcblk0p2

$ cat /sys/class/block/mmcblk0p2/partition 
2

以同样的方式,我们似乎也可以获得major:minor数字(使用最小的字符串标记):

$ cat /sys/class/block/mmcblk0p2/dev 
179:2

不幸的是,下面似乎没有任何东西/sys/class/block/mmcblk0p2直接指向分区所在的块设备,即mmcblk0在本例中。

要获取该磁盘,我们可以搜索下面的所有路径/sys/block/以找到具有我们分区的路径;即该路径/sys/block/mmcblk0/mmcblk0p2存在吗?如果是,那么第三个路径组件iemmcblk0就是我们的磁盘。

或者我们可以使用major分区中的数字(179在本例中),如下所示:

$ realpath /dev/block/179\:0
/dev/mmcblk0

我们还可以解析/proc/partitions(再次——字符串解析!)

$ cat /proc/partitions
major minor  #blocks  name

..snip..
 179        0    7782400 mmcblk0
 179        1      96632 mmcblk0p1
 179        2    3145728 mmcblk0p2

假设需要进行一些字符串欺骗,那么“最简单”/最不脆弱的方法是什么?

背景

我有一个支持多种分区方案的通用 ARM 设备映像。某些 ARM 设备需要特定的分区方案,而其他设备可能只使用一个分区。我有一个脚本来扩展 rootfs 以填充磁盘。

要调整分区大小,我们执行:

sfdisk --no-reread "$DISK" -N "$PART" <<EOF
, $SIZE, L
EOF

其中,例如,DISK=/dev/mmcblk0PART=2。然后我们使用resize2fs之后。

答案1

我们可以搜索 /sys/block/ 下的所有路径来找到具有我们分区的路径。

您可以只读取符号链接,而不是搜索所有路径...

$ readlink /sys/class/block/sdb17
[…]/block/sdb/sdb17
$ basename "$(realpath /sys/class/block/sdb17/..)"
sdb
$ basename "$(realpath /sys/class/block/nvme0n1p2/..)"
nvme0n1

或者我们可以使用分区中的主编号(在本例中为 179),如下所示:

对于大分区数来说,这会失败。

$ cat /sys/block/sdb/sdb17/dev
259:1
$ realpath /dev/block/259:0
/dev/sdb16

答案2

如果您创建 udev 规则,则可以使用参数将环境变量从该规则传递到脚本。

其中%n是设备的内核编号(即%nfrom/dev/sda1给你1)。

%P父设备的节点名称在哪里(即%Pfrom/dev/sda1给你sda)。因此,您可以在脚本中添加 like , 来完成您的%P任务/dev/dev/%P

因此,执行此操作的一个简短示例首先是创建一个 udev 规则(您需要比下面所示更好地识别您的设备):

KERNEL=="sd[a-z][0-9]", ACTION=="add", RUN+="/path/to/script.sh %P %n"

然后相应地编辑你的脚本:

sfdisk --no-reread "/dev/$1" -N "$2" <<EOF
, $SIZE, L
EOF

$1将会在哪里%P以及$2将会在哪里%n

尽管这假设您希望在每次插入设备时运行该脚本(由于ACTION=="add")。这仅适用于执行时间不长的脚本(udev 不处理长时间运行的进程)。

要绕过这个问题,您可以将环境变量传递给 systemd 实例单元,然后由它调用脚本。

相关内容