自动执行 rsync 脚本的 udev 规则不起作用

自动执行 rsync 脚本的 udev 规则不起作用

我写了以下 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

所以我有两个问题:

  1. udev 规则有什么问题,导致无法运行脚本?我也尝试过使用 ENV 变量作为其他标识符,比如 UUID,但同样不起作用。

  2. 如何让脚本rsync以 root 身份执行?除了权限之外,在终端中运行脚本时,脚本可以正常工作sudorsync只需以当前 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

相关内容