Skip to content
Advertisement

Force unmount of usb drive by closing open applications programatically [closed]

When I unplug the AC adapter from my laptop I want all USB drives to automatically unmount. If applications are open that block the device, they should be killed. Once everything is killed and unmount a signal tone could be plaid to indicate that it’s now safe to unplug it.

The use case is to quickly grab and go your laptop without having to fumble with the ui to get all drives disconnected but avoid unclean unmounts.

Any hints on how to start would be fantastic, thanks you!

ANSWER

For a full copy&paste script see my answer below.


If your USB devices mount to /mount/media do:

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

Be careful with this since if you don’t have blocking applications open lsof will return all pids and you will kill your running OS. See the copy&paste script below for a working implementation that handles this case.

Then call this script whenever the AC adapter is unplugged by adding this line to /etc/udev/rules.d

SUBSYSTEM=="power_supply", ACTION=="change", ATTR{online}=="0" ,     RUN+="/path/to/script/shown/above"

The answer below by Nuetrino shows how to detect the AC unplug event, this answer: How do I find out which process is preventing a umount? shows how to list and kill all processes blocking the device from unmounting (I had more success with lsof than fuser -c which sometimes didn’t list any processes even though umount was still being blocked)

Details

Use udevadm monitor to log the event, e.g.

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

then use udevadm info -a -p with the event to get the attributes

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"

Now you can set up the udev rules with the attributes you like as answered below.

Advertisement

Answer

Step by step solution

1. Create this script e.g. in /home/user/uall.sh and replace mount_root with the folder where your distribution mounts usb drives, e.g. /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. Create a udev wrapper script (call it /home/user/uall-udev-wrapper) that executes uall.sh as your username:

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

3. Create the file /etc/udev/rules.d/99-usb-unmount.rules with the content

SUBSYSTEM=="power_supply", ACTION=="change", ATTR{online}=="0" ,     RUN+="/home/user/uall-udev-wrapper"

4. Reboot or run sudo udevadm control --reload-rules && udevadm trigger to load the new udev rule

Optional. Add an alias uall=/home/user/uall.sh to your ~/.bashrc to access the script easily from your terminal and use your Desktop environment to configure a hotkey to quickly unmount all usb drives

Caveats

1. When udev runs the script mount will not display gvfsd-fuse mount points, neither will cat /proc/mounts or cat /etc/mtab not even if using the runuser -l <user> wrapper. Instead I’m using now ls -d -1 $mount_root/* which only returns the devices mounted by the current user specified in $mount_root, on a multi user system devices mounted by a different user will not be unmounted by this script.

2. When udev runs the script I do not get audio from paplay or spd-say.

Any input on these caveats would be greatly appreciated.

User contributions licensed under: CC BY-SA
3 People found this is helpful
Advertisement