我有以下要求:
- 如果插入了特定的 USB 存储设备,系统会自动检测并安装它。安装位置信息
/etc/fstab
(当然)会显示在这里。 - 如果 USB 驱动器坏了,必须自动进行彻底清理;从而不会留下任何残留痕迹,例如它曾被安装(或仍然被安装)和/或任何未完成的 systemd 单元。
- 如果手动编辑了有问题的分区
umount
,那么所有内容也应该被清理,即使该棒仍然存在;将其从插头中拔出应该只会清理之前无法清理的内容(可能是单元.device
)。
为了以干净的方式实现上述操作,插入 USB 驱动器将导致自定义 systemd 单元的启动,然后我们将对其进行配置以完成其余操作。
写这个需要什么?
假设我们有一个有三个分区的 USB 驱动器:
/dev/sdc1
和/dev/sdc2
- 它们是 LUKS 加密的,以及/dev/sdc3
- 它们是未加密的。
例如,
>sudo blkid /dev/sdc{1,2,3}
/dev/sdc1: UUID="de9a000f-fa60-4050-8d11-864e97829b8a" TYPE="crypto_LUKS" PARTUUID="219578f5-5905-41cd-895d-7b937ac0756a"
/dev/sdc2: UUID="012059c1-6b88-4937-889a-a21448740492" TYPE="crypto_LUKS" PARTUUID="59c7f6f3-a5cb-41af-82fa-b515031d85d5"
/dev/sdc3: LABEL="README" UUID="9d262deb-2343-4096-bccf-bb26ed4415ad" BLOCK_SIZE="1024" TYPE="ext2" PARTUUID="165db3da-4ebb-4f59-ab09-ee5e5b26ed43"
以下UUID
是所使用的内容/dev/disk/by-uuid
:
>ls -l /dev/disk/by-uuid | grep sdc
lrwxrwxrwx 1 root root 10 Dec 22 18:27 012059c1-6b88-4937-889a-a21448740492 -> ../../sdc2
lrwxrwxrwx 1 root root 10 Dec 22 18:27 9d262deb-2343-4096-bccf-bb26ed4415ad -> ../../sdc3
lrwxrwxrwx 1 root root 10 Dec 22 18:27 de9a000f-fa60-4050-8d11-864e97829b8a -> ../../sdc1
由于设备名称/dev/sdc
相当随机,从现在开始我们应该只使用 UUID。
为了手动挂载未加密的分区,我们需要执行(确保 /mnt 和/或 /mnt/usb 上尚未挂载任何内容!):
UUID=9d262deb-2343-4096-bccf-bb26ed4415ad
SERIAL=408D5CBECAC3E7C0E9170AEC
sudo /bin/mkdir -p /mnt/usb/$SERIAL/part3
sudo mount -t ext2 /dev/disk/by-uuid/$UUID /mnt/usb/$SERIAL/part3
我确实选择使用 USB 设备的值ID_SERIAL_SHORT
,例如可以通过以下方式获取:
>udevadm info -n /dev/sdc3 | grep -E '(ID_SERIAL_SHORT|ID_FS_UUID)='
E: ID_SERIAL_SHORT=408D5CBECAC3E7C0E9170AEC
E: ID_FS_UUID=9d262deb-2343-4096-bccf-bb26ed4415ad
/etc/fstab
让我们通过向该文件添加以下内容来存储挂载点:
UUID=9d262deb-2343-4096-bccf-bb26ed4415ad /mnt/usb/408D5CBECAC3E7C0E9170AEC/part3 ext2 rw,noauto 0 0
请注意,此后我们可以执行以下操作:
sudo mount /dev/sdc3
只要该块设备具有预期的 UUID,它就能顺利完成挂载。
另外两个分区/dev/sdc{1,2}
已加密,首先需要
UUID1=573bfda0-69f5-4fb9-9d7e-333a70a51710
UUID2=6d7bdc1d-3eb0-4774-a9fb-3d1ac1027010
echo $LUKS_PASS | sudo cryptsetup -q luksOpen /dev/disk/by-uuid/$UUID1 usb-$UUID1
echo $LUKS_PASS | sudo cryptsetup -q luksOpen /dev/disk/by-uuid/$UUID2 usb-$UUID2
要执行的命令,我假设环境变量LUKS_PASS
包含解密 LUKS 分区所需的密码。这里的 UUID 是 blkid 返回的:
>sudo blkid /dev/sdc{1,2}
/dev/sdc1: UUID="573bfda0-69f5-4fb9-9d7e-333a70a51710" TYPE="crypto_LUKS" PARTUUID="caa57a9d-7389-4990-a243-34b19a179368"
/dev/sdc2: UUID="6d7bdc1d-3eb0-4774-a9fb-3d1ac1027010" TYPE="crypto_LUKS" PARTUUID="10813450-6dcc-4700-9e88-d0577c0c9aeb"
这将为/dev/mapper/usb-$UUID
每个分区创建一个设备,每个设备都有自己的 UUID:
>sudo blkid /dev/mapper/usb*
/dev/mapper/usb-573bfda0-69f5-4fb9-9d7e-333a70a51710: LABEL="gold1-2024-12-21" UUID="67f056be-dbbc-4f7a-979d-6ff077d16e93" BLOCK_SIZE="4096" TYPE="ext2"
/dev/mapper/usb-6d7bdc1d-3eb0-4774-a9fb-3d1ac1027010: LABEL="gold2-2024-12-21" UUID="94bfcc55-6b52-431f-bc76-3aa198c107c7" BLOCK_SIZE="4096" TYPE="ext2"
这些就是我们想要添加的 UUID /etc/fstab
。
为了让生活更轻松,我编写了以下脚本,该脚本/etc/fstab
在插入 USB 后运行时打印所需的配置(就我的特定情况而言):
# Get the device path.
DEVPATH=$(/bin/ls /dev/disk/by-id/usb-Kingston_DataTraveler* | grep -E -v -- '-part[0-9]+$')
# Get the serial of the USB stick.
ID_SERIAL_SHORT=$(udevadm info -n $DEVPATH | grep ID_SERIAL_SHORT | sed -e 's/.*ID_SERIAL_SHORT=//')
# Run over all existing partitions.
for p in $(/bin/ls $DEVPATH-part*); do
# Extract the "part?" string.
PART=$(echo $p | sed -r -e 's/.*-(part[0-9]+)$/\1/')
# Get the UUID of the block device of this partition iff it is a LUKS encrypted partition.
UUID=$(blkid --match-token TYPE=crypto_LUKS $p | sed -e 's/.* UUID="\([^ ]*\)".*/\1/' || true)
if [ -n "$UUID" ]; then
# Decrypt the partition.
echo $LUKS_PASS | sudo cryptsetup -q luksOpen /dev/disk/by-uuid/$UUID usb-$UUID
# Get the UUID of the encrypted partition.
UUID2=$(blkid /dev/mapper/usb-$UUID | sed -e 's/.* UUID="\([^ ]*\)".*/\1/')
echo -e "UUID=$UUID2\t/mnt/usb/$ID_SERIAL_SHORT/$PART\text2\trw,noauto\t0 0"
sudo cryptsetup luksClose usb-$UUID
else
# Get UUID of non-encrypted partition.
UUID=$(blkid $p | sed -e 's/.* UUID="\([^ ]*\)".*/\1/')
echo -e "UUID=$UUID\t/mnt/usb/$ID_SERIAL_SHORT/$PART\text2\trw,noauto\t0 0"
fi
done
导出后,LUKS_PASS
请确保运行上述脚本sudo -E
以保存环境。示例输出:
>sudo -E ./foo.sh
UUID=db97c4b0-8f92-4edc-bacb-dc90e62de2e2 /mnt/usb/408D5CBECAC3E7C0E9170AEC/part1 ext2 rw,noauto 0 0
UUID=c45c6a7a-1c0f-49c4-bcfb-15766114daa1 /mnt/usb/408D5CBECAC3E7C0E9170AEC/part2 ext2 rw,noauto 0 0
UUID=9d262deb-2343-4096-bccf-bb26ed4415ad /mnt/usb/408D5CBECAC3E7C0E9170AEC/part3 ext2 rw,noauto 0 0
设置完毕/etc/fstab
并确切知道需要什么命令后,剩下的就是使用udev
和来自动执行此操作systemd units
。
问题是:如何做?