给定一个文件系统,例如/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/mmcblk0
和PART=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
是设备的内核编号(即%n
from/dev/sda1
给你1
)。
%P
父设备的节点名称在哪里(即%P
from/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 实例单元,然后由它调用脚本。