通过以编程方式关闭打开的应用程序来强制卸载USB驱动器

时间:2015-12-12 17:09:11

标签: linux bash ubuntu mount udev

当我从笔记本电脑上拔下AC适配器时,我希望所有USB驱动器都能自动卸载。如果应用程序打开阻止设备,则应该将其杀死。一旦所有东西都被杀死并卸下,信号音就会格格不齐,表明它现在可以安全拔掉它。

用例是快速抓取并移动您的笔记本电脑而不必使用ui来解决所有驱动器断开连接但避免不干净的卸载。

任何有关如何开始的提示都会非常棒,谢谢!

ANSWER

  

有关完整的副本和粘贴脚本,请参阅下面的答案。

如果您的USB设备安装到/ mount / media,请执行以下操作:

kill -9 $(lsof -t $(mount | grep "/mount/media" | cut -d " " -f 1)) # Exit processes blocking umount cleanly
kill $(lsof -t $(mount | grep "/mount/media" | cut -d " " -f 1)) # Force kill remaining open processes
umount $(mount | grep "/mount/media" | cut -d " " -f 1) # Unmount USB drives

请注意这一点,因为如果您没有阻止应用程序打开lsof将返回所有pids,您将kill正在运行的操作系统。请参阅下面的复制和粘贴脚本,了解处理此案例的工作实现。

然后通过将此行添加到/etc/udev/rules.d

,只要拔下AC适配器,就可以调用此脚本
SUBSYSTEM=="power_supply", ACTION=="change", ATTR{online}=="0" ,     RUN+="/path/to/script/shown/above"

Nuetrino下面的答案显示了如何检测AC拔出事件,这个答案: How do I find out which process is preventing a umount?显示如何列出并杀死阻止设备卸载的所有进程(我使用lsof比fuser -c更成功有时候没有列出任何进程,即使umount仍然被阻止了)

详情

使用udevadm monitor记录事件,例如

KERNEL[20154.545075] change   /devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0003:00/power_supply/ADP0 (power_supply)

然后将udevadm info -a -p与事件一起使用以获取属性

udevadm info -a -p /devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0003:00/power_supply/ADP0
    looking at device '/devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0003:00/power_supply/ADP0':
        KERNEL=="ADP0"
        SUBSYSTEM=="power_supply"
        DRIVER==""
        ATTR{online}=="0"
        ATTR{type}=="Mains"

现在,您可以使用您喜欢的属性设置udev规则,如下所示。

2 个答案:

答案 0 :(得分:1)

您可以定义udev规则来执行此操作。

只需将您的规则放入/etc/udev/rules.d

即可

以下是我用来控制亮度的示例,当我取下AC适配器时。

SUBSYSTEM=="power_supply", ACTION=="change", ATTR{online}=="0" , RUN+="/usr/local/bin/bright_unplug"
SUBSYSTEM=="power_supply", ACTION=="change", ATTR{online}=="1" , RUN+="/usr/local/bin/bright_replug

当我收到内核uvent时,我运行自定义脚本'bright_replug'和'bright_unplug'。

您可以使用udevadm monitor

  

monitor将打印收到的事件:UDEV - 事件当中   udev在规则处理后发出KERNEL - 内核uevent

您可以使用udevadm info来匹配更多属性

答案 1 :(得分:-1)

分步解决方案

1。 创建此脚本,例如在/home/user/uall.sh中,将mount_root替换为您的发行版安装usb驱动器的文件夹,例如/media/user

#!/bin/bash
mount_root=/run/media/user

echo "Try unmounting.."
umount $(ls -d -1 $mount_root/*) # Unmount USB drives
mounted=$(ls -d -1 $mount_root/*) # Probe if there are still applications blocking
if ! [ -z "$mounted" ]
then
    echo "Found blocked devices: $mounted, killing.."
    kill -9 $(lsof -t $mounted) # Exit processes blocking umount cleanly
    kill $(lsof -t $mounted) # Force kill remaining open processes
    echo "Unmounting.."
    umount $(ls -d -1 $mount_root/*) # Unmount USB drives
    mounted=$(ls -d -1 $mount_root/*) # Probe if there are still applications blocking
fi

if [ -z "$mounted" ]
then
    echo "Success!"
    echo "All USB devices umount."
    paplay /usr/share/sounds/speech-dispatcher/test.wav
else
    echo "Error!"
    echo "Tried it all but couldn't umount all USB devices."
    echo "These devices are still mounted:"
    echo "$mounted"
fi

2。 创建一个执行/home/user/uall-udev-wrapper作为用户名的udev包装器脚本(称之为uall.sh):

#!/bin/bash
runuser -l <user> -c '/home/user/uall.sh > /home/user/uall.log'

3。 使用内容

创建文件/etc/udev/rules.d/99-usb-unmount.rules
SUBSYSTEM=="power_supply", ACTION=="change", ATTR{online}=="0" ,     RUN+="/home/user/uall-udev-wrapper"

4。 重新启动或运行sudo udevadm control --reload-rules && udevadm trigger以加载新的udev规则

可选。将alias uall=/home/user/uall.sh添加到~/.bashrc以便从终端轻松访问脚本,并使用桌面环境配置热键以快速卸载所有USB驱动器

<强>注意事项

1。 当udev运行时,脚本mount将不会显示gvfsd-fuse个挂载点,即使使用cat /proc/mounts包装器,也不会cat /etc/mtabrunuser -l <user>。相反,我现在使用ls -d -1 $mount_root/*仅返回由$mount_root中指定的当前用户挂载的设备,在由不同用户挂载的多用户系统设备上将不会被此脚本卸载。

2。 当udev运行脚本时,我无法从paplayspd-say获取音频。

对这些警告的任何意见都将不胜感激。