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.