从udev规则和shell脚本自动挂载USB驱动器

时间:2017-07-19 09:37:43

标签: linux shell mount usb-drive udev

我正在尝试自动安装连接到我的电脑的任何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规则正常但是当我尝试从脚本安装文件系统时它不起作用。 奇怪的是脚本中的mount命令总是返回$?= 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命令的预期错误。 但是当文件夹存在时,即使没有挂载文件系统,mount命令也会返回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
即使mount返回0,也不会挂载

/ dev / sdc1。

我确切地说,当我从命令行挂载文件系统时,绝对没有问题,文件系统按原样安装。

有人对我如何调试这个有线索吗?

我认为问题是因为脚本是从udev调用的,因为如果我从命令行调用它也可以。

3 个答案:

答案 0 :(得分:5)

我想我发现了这个问题。 显然,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,现在它完美无缺:)

答案 1 :(得分:1)

如果通过向命令添加-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

我不确定为什么即使您将退出状态视为成功,设备也无法安装。只是尝试优化代码以捕捉真正的问题。

答案 2 :(得分:1)

我希望我的 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 $0)
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 的内容