从 udev 规则和 shell 脚本自动挂载 USB 驱动器
Auto mount usb drive from udev rules and shell script
我目前正在尝试自动安装连接到我的计算机的任何 USB 驱动器。
我的目标是挂载 usb 设备,如果有,则使用标签;如果没有,则使用 uuid。
为此,我在 /etc/udev/rules.d/10-usb-detect.rules 中编写了一个 udev 规则:
ACTION=="add", KERNEL=="sd?[0-9]", SUBSYSTEM=="block", RUN+="/usr/local/bin/add.sh"
每次在块子系统上追加添加事件时都会调用该脚本。
udev 规则工作正常,但是当我尝试从脚本挂载文件系统时它不起作用。
奇怪的是,脚本中的挂载命令总是 return $?=0,所以逻辑上应该挂载文件系统,但实际上没有挂载。
这是我的脚本:
#!/bin/bash
LOG_FILE=<path_to_file>
echo "New usb device detected at $DEVNAME" >> $LOG_FILE
echo "mount $DEVNAME /media/usb/test" >> $LOG_FILE
mount $DEVNAME /media/usb/test &>> $LOG_FILE
ret=$?
echo "$ret" >> $LOG_FILE
if [ $ret == "0" ]; then
echo "$DEVNAME mounted at /media/usb/test" >> $LOG_FILE
else
echo "Failed to mount $DEVNAME at /media/usb/test" >> $LOG_FILE
fi
echo "" >> $LOG_FILE
我尝试使用 /media/usb/test 不存在,并且我从 mount 命令中得到了预期的错误。
但是,当文件夹存在时,即使未安装文件系统,他也会安装命令 returns 0。
这是日志文件的输出:
New usb device detected at /dev/sdc1
mount /dev/sdc1 /media/usb/test
mount: mount point /media/usb/test does not exist
32
Failed to mount /dev/sdc1 at /media/usb/test
New usb device detected at /dev/sdc1
mount /dev/sdc1 /media/usb/test
0
/dev/sdc1 mounted at /media/usb/test
/dev/sdc1 即使 mount returns 0.
也没有挂载
我准确地说,当我从命令行挂载文件系统时,绝对没有问题,并且文件系统已按预期挂载。
有人知道我该如何调试吗?
我认为问题是因为脚本是从 udev 调用的,因为如果我从命令行调用它也可以。
如果您通过在命令中添加 -t FILESYSTEMTYPE 参数来指定文件系统类型,则系统类型问题可能会更好。
mount -t FILESYSTEMTYPE /device_name /mount_point
.
同时尝试改变记录事件的方式,使用 exec 命令记录信息,无需每次都继续重定向命令输出。
exec > $LOG_FILE 2>&1
你也可以替换
mount $DEVNAME /media/usb/test &>> $LOG_FILE
ret=$?
echo "$ret" >> $LOG_FILE
if [ $ret == "0" ]; then
echo "$DEVNAME mounted at /media/usb/test" >> $LOG_FILE
else
echo "Failed to mount $DEVNAME at /media/usb/test" >> $LOG_FILE
fi
和
mount -t vfat $DEVNAME /media/usb/test
if [ $? -eq 0 ]; then
echo " $DEVNAME Mounted"
else
echo " $DEVNAME not Mounted"
fi
我不确定为什么即使您获得退出状态为成功,设备仍未安装。只是尝试优化代码以解决真正的问题。
我想我发现了问题所在。
显然,udev 使用特定的命名空间,实际上我可以通过打印 /proc/<daemon_pid>/mountinfo
的内容来查看挂载点,其中 systemd-udevd 服务的 pid 在哪里。
$ cat /proc/240/mountinfo
[...]
228 43 8:17 / /media/usb/test rw,relatime - vfat /dev/sdb1 rw,fmask=0022,dmask=0022,codepage=437,iocharset=ascii,shortname=mixed,utf8,errors=remount-ro
$ df
Sys. de fichiers blocs de 1K Utilisé Disponible Uti% Monté sur
udev 1975740 0 1975740 0% /dev
tmpfs 397376 5916 391460 2% /run
/dev/sda2 75733088 69473400 2389532 97% /
tmpfs 1986868 111860 1875008 6% /dev/shm
tmpfs 5120 4 5116 1% /run/lock
tmpfs 1986868 0 1986868 0% /sys/fs/cgroup
tmpfs 397372 28 397344 1% /run/user/112
tmpfs 397372 24 397348 1% /run/user/1001
所以解决办法应该是强制udev在root用户空间执行脚本。
我尝试了在这里找到的解决方案 https://unix.stackexchange.com/questions/330094/udev-rule-to-mount-disk-does-not-work
但是,我的系统没有 /usr/lib/systemd/system/systemd-udevd.service
文件。我创建了一个文件 /etc/systemd/system/systemd-udevd.service
,内容为
MountFlags=shared
但是使用这个解决方案,我的系统无法再启动了。
有人知道我如何在 root 用户空间中执行脚本或与用户共享挂载点吗?
PS : 我准确地说我是 运行 64 位 Debian 9
已解决编辑: 最后文件位于 /lib/systemd/system/systemd-udevd.service
。我在 /etc/systemd/system/systemd-udevd.service
中复制了它
并将 MountFlags=slave
更改为 MountFlags=shared
,现在它完美运行了:)
我希望我的 Raspberrypi Pico 微控制器板能够自动安装和卸载,这与最初的问题非常相似,因为当您插入时按下 bootsel 按钮时,RPi Pico 被识别为 USB 存储。
所以这是我在 /lib/udev/rules.d/10-usb-storage.rules 中输入的内容(确切路径可能取决于分布)
root@darkstar:/lib/udev/rules.d# cat 10-usb-storage.rules
ACTION=="add", KERNEL=="sd?[0-9]", SUBSYSTEM=="block", RUN+="usb_automount"
ACTION=="remove", KERNEL=="sd?[0-9]", SUBSYSTEM=="block", RUN+="usb_automount"
root@darkstar:/lib/udev/rules.d#
这是名为的帮助脚本:
root@darkstar:/lib/udev/rules.d# cat /lib/udev/usb_automount
#!/bin/bash
#this will automatically mount and umount th RPi Pico on /mnt/pico
Name=$(basename [=11=])
Logger="/usr/bin/logger -p local3.info -t $Name "
#logger -p local3.info -t aoutomount -- testing
Message="$* $DEVNAME $ACTION $ID_FS_LABEL"
$Logger <<< $Message
pico_add ()
{ Message="automounting $DEVNAME $ID_FS_LABEL"
$Logger <<< $Message
/sbin/mount $DEVNAME /mnt/pico && $Logger <<< "mounted" || $Logger <<< "failed"
}
pico_remove ()
{ Message="umounting $DEVNAME $ID_FS_LABEL"
$Logger <<< $Message
/sbin/umount -f /mnt/pico && $Logger <<< "umounted" || $LOGGER "failed"
}
case $ID_FS_LABEL in
RPI-RP2) pico_$ACTION ;;
*) $Logger <<< "$ID_FS_LABEL is not configured for any automatic action"
esac
root@darkstar:/lib/udev/rules.d#
要重新加载 udev 规则:https://unix.stackexchange.com/questions/39370/how-to-reload-udev-rules-without-reboot/39371
udevadm control --reload-rules && udevadm trigger
顺便说一句:udev 似乎忽略了 /etc/fstab
的内容
我目前正在尝试自动安装连接到我的计算机的任何 USB 驱动器。 我的目标是挂载 usb 设备,如果有,则使用标签;如果没有,则使用 uuid。
为此,我在 /etc/udev/rules.d/10-usb-detect.rules 中编写了一个 udev 规则:
ACTION=="add", KERNEL=="sd?[0-9]", SUBSYSTEM=="block", RUN+="/usr/local/bin/add.sh"
每次在块子系统上追加添加事件时都会调用该脚本。
udev 规则工作正常,但是当我尝试从脚本挂载文件系统时它不起作用。 奇怪的是,脚本中的挂载命令总是 return $?=0,所以逻辑上应该挂载文件系统,但实际上没有挂载。
这是我的脚本:
#!/bin/bash
LOG_FILE=<path_to_file>
echo "New usb device detected at $DEVNAME" >> $LOG_FILE
echo "mount $DEVNAME /media/usb/test" >> $LOG_FILE
mount $DEVNAME /media/usb/test &>> $LOG_FILE
ret=$?
echo "$ret" >> $LOG_FILE
if [ $ret == "0" ]; then
echo "$DEVNAME mounted at /media/usb/test" >> $LOG_FILE
else
echo "Failed to mount $DEVNAME at /media/usb/test" >> $LOG_FILE
fi
echo "" >> $LOG_FILE
我尝试使用 /media/usb/test 不存在,并且我从 mount 命令中得到了预期的错误。 但是,当文件夹存在时,即使未安装文件系统,他也会安装命令 returns 0。
这是日志文件的输出:
New usb device detected at /dev/sdc1
mount /dev/sdc1 /media/usb/test
mount: mount point /media/usb/test does not exist
32
Failed to mount /dev/sdc1 at /media/usb/test
New usb device detected at /dev/sdc1
mount /dev/sdc1 /media/usb/test
0
/dev/sdc1 mounted at /media/usb/test
/dev/sdc1 即使 mount returns 0.
也没有挂载我准确地说,当我从命令行挂载文件系统时,绝对没有问题,并且文件系统已按预期挂载。
有人知道我该如何调试吗?
我认为问题是因为脚本是从 udev 调用的,因为如果我从命令行调用它也可以。
如果您通过在命令中添加 -t FILESYSTEMTYPE 参数来指定文件系统类型,则系统类型问题可能会更好。
mount -t FILESYSTEMTYPE /device_name /mount_point
.
同时尝试改变记录事件的方式,使用 exec 命令记录信息,无需每次都继续重定向命令输出。
exec > $LOG_FILE 2>&1
你也可以替换
mount $DEVNAME /media/usb/test &>> $LOG_FILE
ret=$?
echo "$ret" >> $LOG_FILE
if [ $ret == "0" ]; then
echo "$DEVNAME mounted at /media/usb/test" >> $LOG_FILE
else
echo "Failed to mount $DEVNAME at /media/usb/test" >> $LOG_FILE
fi
和
mount -t vfat $DEVNAME /media/usb/test
if [ $? -eq 0 ]; then
echo " $DEVNAME Mounted"
else
echo " $DEVNAME not Mounted"
fi
我不确定为什么即使您获得退出状态为成功,设备仍未安装。只是尝试优化代码以解决真正的问题。
我想我发现了问题所在。
显然,udev 使用特定的命名空间,实际上我可以通过打印 /proc/<daemon_pid>/mountinfo
的内容来查看挂载点,其中 systemd-udevd 服务的 pid 在哪里。
$ cat /proc/240/mountinfo
[...]
228 43 8:17 / /media/usb/test rw,relatime - vfat /dev/sdb1 rw,fmask=0022,dmask=0022,codepage=437,iocharset=ascii,shortname=mixed,utf8,errors=remount-ro
$ df
Sys. de fichiers blocs de 1K Utilisé Disponible Uti% Monté sur
udev 1975740 0 1975740 0% /dev
tmpfs 397376 5916 391460 2% /run
/dev/sda2 75733088 69473400 2389532 97% /
tmpfs 1986868 111860 1875008 6% /dev/shm
tmpfs 5120 4 5116 1% /run/lock
tmpfs 1986868 0 1986868 0% /sys/fs/cgroup
tmpfs 397372 28 397344 1% /run/user/112
tmpfs 397372 24 397348 1% /run/user/1001
所以解决办法应该是强制udev在root用户空间执行脚本。 我尝试了在这里找到的解决方案 https://unix.stackexchange.com/questions/330094/udev-rule-to-mount-disk-does-not-work
但是,我的系统没有 /usr/lib/systemd/system/systemd-udevd.service
文件。我创建了一个文件 /etc/systemd/system/systemd-udevd.service
,内容为
MountFlags=shared
但是使用这个解决方案,我的系统无法再启动了。
有人知道我如何在 root 用户空间中执行脚本或与用户共享挂载点吗?
PS : 我准确地说我是 运行 64 位 Debian 9
已解决编辑: 最后文件位于 /lib/systemd/system/systemd-udevd.service
。我在 /etc/systemd/system/systemd-udevd.service
中复制了它
并将 MountFlags=slave
更改为 MountFlags=shared
,现在它完美运行了:)
我希望我的 Raspberrypi Pico 微控制器板能够自动安装和卸载,这与最初的问题非常相似,因为当您插入时按下 bootsel 按钮时,RPi Pico 被识别为 USB 存储。 所以这是我在 /lib/udev/rules.d/10-usb-storage.rules 中输入的内容(确切路径可能取决于分布)
root@darkstar:/lib/udev/rules.d# cat 10-usb-storage.rules
ACTION=="add", KERNEL=="sd?[0-9]", SUBSYSTEM=="block", RUN+="usb_automount"
ACTION=="remove", KERNEL=="sd?[0-9]", SUBSYSTEM=="block", RUN+="usb_automount"
root@darkstar:/lib/udev/rules.d#
这是名为的帮助脚本:
root@darkstar:/lib/udev/rules.d# cat /lib/udev/usb_automount
#!/bin/bash
#this will automatically mount and umount th RPi Pico on /mnt/pico
Name=$(basename [=11=])
Logger="/usr/bin/logger -p local3.info -t $Name "
#logger -p local3.info -t aoutomount -- testing
Message="$* $DEVNAME $ACTION $ID_FS_LABEL"
$Logger <<< $Message
pico_add ()
{ Message="automounting $DEVNAME $ID_FS_LABEL"
$Logger <<< $Message
/sbin/mount $DEVNAME /mnt/pico && $Logger <<< "mounted" || $Logger <<< "failed"
}
pico_remove ()
{ Message="umounting $DEVNAME $ID_FS_LABEL"
$Logger <<< $Message
/sbin/umount -f /mnt/pico && $Logger <<< "umounted" || $LOGGER "failed"
}
case $ID_FS_LABEL in
RPI-RP2) pico_$ACTION ;;
*) $Logger <<< "$ID_FS_LABEL is not configured for any automatic action"
esac
root@darkstar:/lib/udev/rules.d#
要重新加载 udev 规则:https://unix.stackexchange.com/questions/39370/how-to-reload-udev-rules-without-reboot/39371
udevadm control --reload-rules && udevadm trigger
顺便说一句:udev 似乎忽略了 /etc/fstab
的内容