我写了以下 udev 规则/lib/udev/rules.d/99-Goprobackup.rules
# when device /dev/sd* is added to the KERNEL with the UUID defined RUN the script
ACTION=="add", KERNEL=="/dev/sd[b-z][!0-9]", ENV{ID_SERIAL_SHORT}=="57584A314541334A414C4535", RUN+="/usr/bin/gopro_autobackup.sh"
脚本本身如下:
#!/bin/sh
sleep 30
/usr/bin/sudo --user=sebthomas rsync -a --delete --ignore-existing /media/sebthomas/Gopro-Local/ /media/sebthomas/GoPro-Video-Backup/
aplay /usr/share/sounds/sound-icons/canary-long.wav
所以我有两个问题:
udev 规则有什么问题,导致无法运行脚本?我也尝试过使用 ENV 变量作为其他标识符,比如 UUID,但同样不起作用。
如何让脚本
rsync
以 root 身份执行?除了权限之外,在终端中运行脚本时,脚本可以正常工作sudo
。rsync
只需以当前 bash 用户身份运行,我就会得到以下输出(包括音频):rsync: opendir "/media/sebthomas/Gopro-Local/lost+found" failed: Permission denied (13) IO error encountered -- skipping file deletion rsync error: some files/attrs were not transferred (see previous errors) (code 23) at main.c(1207) [sender=3.1.3] Playing WAVE '/usr/share/sounds/sound-icons/canary-long.wav' : Signed 16 bit Little Endian, Rate 16000 Hz, Mono
这就是我拉的方式ID_SERIAL_SHORT
:
sebthomas@Ubuntu-Desktop:~$ udevadm info --query=all --name=/dev/sdd | grep ID_SERIAL
E: ID_SERIAL=WD_Elements_10B8_57584A314541334A414C4535-0:0
E: ID_SERIAL_SHORT=57584A314541334A414C4535
提前感谢任何建议。
解决方案
所以这就是最终可行的方法,非常感谢 bac0n 的所有帮助(谁不爱 bac0n!)...
我有一个 udev 规则:
/lib/udev/rules.d/10-gopro_backup.service
包含下列内容:
#run backup on mounting specific partition
ACTION=="add", \
ENV{ID_FS_UUID}=="679ECE115B048FC5", \
TAG+="systemd", ENV{SYSTEMD_WANTS}="gopro_backup.service"
确保sudo udevadm control --reload && udevadm trigger
每次对此进行更改后都运行。
这将运行服务/etc/systemd/system/gopro_backup.service
包含下列内容:
[UNIT]
Description=Autorun backup of local gopro media
[Service]
Type=oneshot
ExecStart=/usr/bin/gopro_backup.sh
这将执行脚本/usr/bin/gopro_backup.sh
包含下列内容:
#!/bin/sh
sleep 60
rsync -a --delete --ignore-existing /media/sebthomas/Gopro-Local/ /media/sebthomas/Gopro-Backup/
aplay /usr/share/sounds/sound-icons/canary-long.wav
确保sudo chmod +x /usr/bin/gopro_backup.sh
在创建这个之后运行。
细心的读者会注意到,我在这个最终版本中大量清理了语法和命名约定,因此文件名实际上是相同的,驱动器安装位置和标签的名称也遵循相同的格式。这不是必需的,但确实有助于检查错误,这些错误会在以后给你带来巨大的麻烦。
再次感谢 bac0n 对此的指导!
答案1
当您尝试匹配一个设备(在这种情况下是块设备)时,您应该尝试尽可能唯一且尽可能晚地匹配该设备(在您的示例中ENV{ID_SERIAL_SHORT}
是多个事件的一部分,这将使您的脚本运行多次)。
udevadm 将允许您监视 udev 事件:
udevadm monitor --environment --udev
或者内核 uevents:
udevadm monitor
您还可以通过写入 /sys 树中的 uevent 文件来触发这些事件:
echo add > /sys/block/sdc/sdc1/uevent
根据哪个 udevadm 监视器处于活动状态,打印事件或 uevent。
如何使用 UUID 触发特定分区。
ACTION=="add", \
ENV{ID_FS_UUID}=="9AE4-6A76", \
TAG+="systemd", \
ENV{SYSTEMD_WANTS}+="gopro-backup@%E{ID_FS_UUID}.service"
不要忘记重新加载你的 udev.rule。
/etc/systemd/系统/[电子邮件保护]:
[Unit]
Description=Backup action for GoPro
[Service]
Type=oneshot
ExecStart=/opt/bin/gopro_backup.sh %i
您不需要启动或启用此服务。
您可以使用 fstab 条目控制备份的示例(使用:lsblk /dev/sda -o +UUID
列出部分 uuid):
UUID=<uuid> /media/GoPro vfat defaults,noauto 0 0
(如果您评论此条目则备份需要运行)。
/opt/bin/gopro_backup.sh(非常简单):
#!/bin/bash
[[ -n $1 ]] && uuid=$1 || exit 1
if ! findmnt -f --fstab UUID=$uuid &>/dev/null
then
systemd-cat -t GoPro -p 4 <<< \
"Warning: Device entry is missing, check your fstab."
exit 1
fi
[[ -b /dev/disk/by-uuid/$uuid ]] || exit 1
# Retry 5 times.
while :; do
if (($((++b)) > 5)); then
exit 1
elif findmnt -f UUID=$uuid &>/dev/null; then
break
else
mount UUID=$uuid || sleep 5
fi
done
source=$(findmnt UUID=$uuid -nfo TARGET)
mkdir -p /opt/backup/GoPro/video
rsync -a --delete --ignore-existing "$source/" /opt/backup/GoPro/video
# Success ?
if (($?)); then
systemd-cat -t GoPro -p 3 <<< \
"Error: Backup: Failed."
else
systemd-cat -t GoPro -p 6 <<< \
"Info: Backup: successful."
fi