【问题标题】:Executing a script after mounting USB key挂载 USB 密钥后执行脚本
【发布时间】:2019-02-09 15:43:41
【问题描述】:

我尝试运行一个脚本来通过检查它的标签来识别 USB 密钥,并且它还有一个包含标识符的文件。我首先受到这个启发 -> Script not working when evoked by udev rule

这里首先是 udev 规则。它可以正常工作并正确调用我的脚本。

KERNEL=="sd[b-z]1", SUBSYSTEM=="block", ACTION=="add", GROUP="plugdev", OWNER="tuxin", RUN+="/home/tuxin/insert-usbkey.sh %k"

这是一个脚本,简化为最简单的表达式,用于测试操作。

#!/bin/bash
exec </dev/null >/tmp/key-inserted.log 2>&1; PS4=':$LINENO+'; set -x

KEY_LABEL="DEV_JP"

cd /media/tuxin || exit
(
  for ((retries=0; retries<10; retries++)); do
    [[ -d "$KEY_LABEL" ]] && grep -q -e "$KEY_LABEL" /proc/mounts && continue
    sleep 1
  done
  cd "$KEY_LABEL" || exit
  echo "SUCCESS"
) &

很遗憾,尽管挂载了密钥,但“SUCCESS”从未写入日志文件,其内容为:

:4+KEY_LABEL=DEV_JP
:6+cd /media/tuxin
:8+(( retries=0 ))
:8+(( retries<10 ))
:9+[[ -d DEV_JP ]]
:10+sleep 1

我们可以看到,在 'sleep' 命令之后,没有执行任何其他操作。通过多次测试,我得出的结论是,我的脚本在挂载密钥后立即停止,并且在挂载密钥时我无法执行任何操作。

所以我继续我的研究并关注了这个讨论 -> how to execute a script every time any USB get mounted

所以我制定了以下规则,我理解起来有点麻烦,但结果完全一样:

KERNEL!="sd[a-z]*", GOTO="media_by_label_auto_mount_end" ACTION=="add", PROGRAM!="/sbin/blkid %N", GOTO="media_by_label_auto_mount_end"

# Get label
PROGRAM=="/sbin/blkid -o value -s LABEL %N", ENV{dir_name}="%c"

# use basename to correctly handle labels such as ../mnt/foo
PROGRAM=="/usr/bin/basename '%E{dir_name}'", ENV{dir_name}="%c" ENV{dir_name}=="", ENV{dir_name}="usbhd-%k"

ACTION=="add", ENV{dir_name}!="", RUN+="/bin/su tuxin -c '/usr/bin/pmount %N %E{dir_name}'", RUN+="/home/tuxin/insert-usbkey.sh"

ACTION=="remove", ENV{dir_name}!="", RUN+="/bin/su tuxin -c '/usr/bin/pumount /media/%E{dir_name}'"

LABEL="media_by_label_auto_mount_end"

脚本在手动启动时正常工作,但由 udev 执行,一旦安装密钥,在我看来它就被杀死了。在自动检测安装后,我该如何做我想做的事情?

这里是对该脚本进行测试的机器的摘要(有或没有后台操作)。为什么这在 Linux Mint 中不起作用还有待理解。

  Distribution    udev version   Result
  -------------------------------------
  Linux Mint 18       229          KO
  L.M.D.E.            215          OK
  Poky custom.        182          OK
  Linux Mint 18       229          KO
  Lubuntu 18.04       237          OK

【问题讨论】:

  • 我不能告诉你,但是对于一个写得很好的问题 +1。
  • 很奇怪。如何添加一些陷阱来检测它是否被发送信号,并重定向到/tmp/key-inserted.log.$$ 以确保文件不会被另一个实例截断
  • 我将 udev 日志置于“调试”模式:udevadm control --log-priority=debug,我的脚本只有一个调用。

标签: bash udev


【解决方案1】:

您的测试脚本在后台子shell中运行其主要逻辑。因此,它几乎在启动子 shell 后立即完成,因此父 bash 进程尽职尽责地向所有子进程发出信号,在子shell 能够做很多事情之前杀死它。

既不需要背景,也不需要下壳;以下内容在我的系统上与 udev 完美配合:

#!/bin/bash
exec </dev/null >/tmp/key-inserted.log 2>&1; PS4=':$LINENO+'; set -x

KEY_LABEL="DEV_JP"

cd /media/tuxin || exit

for ((retries=0; retries<10; retries++)); do
  [[ -d "$KEY_LABEL" ]] && grep -q -e "$KEY_LABEL" /proc/mounts && break
  sleep 1
done
cd "$KEY_LABEL" || exit
ls .  # Double-check by listing the drive's contents
echo "SUCCESS"

另请注意,我将您的 continue 更改为 break,因为这正是您在找到所需内容后想要做的事情:跳出循环

【讨论】:

  • @Tuxin 如果此脚本没有看到挂载点,但在脚本退出后您确实看到了,可能是您的脚本的 udev 规则运行得太早了.使用 99-zzz-usbkey.rules 之类的名称命名您的规则文件,以确保它会在所有系统 USB 安装相关规则之后运行。正如udev(7) 手册页所说:“所有规则文件都按照词法顺序进行集体排序和处理,而不管它们所在的目录。”
  • 没有阿德里安,我已经测试了几个规则名称,包括99,它没有改变任何东西。当脚本没有看到挂载点时,真的没有!当挂载点存在时,脚本在看到之前已经停止。
  • 然后发生了一些奇怪的事情。请在 pastebin.com(或其他一些 pastebin 网站)上发布 完整 udev 调试日志,准确显示插入 USB 驱动器时发生的情况。
  • Here 是挂载密钥并停止脚本时的日志(backgrounded subshel​​l)。还有these,当key没有挂载,脚本走到最后。
  • 好吧,我很难过。我可以确认我发布的前台脚本在带有 system-udev v237 的 Lubuntu 18.04 上完美运行,并且不会阻止 udisksd 自动挂载。您可以尝试不同的发行版,以防 v215 和 v237 之间出现回归。
猜你喜欢
  • 2019-07-22
  • 1970-01-01
  • 1970-01-01
  • 2014-09-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-01
  • 1970-01-01
相关资源
最近更新 更多