I like Fabby's approach, but it is good to teach people about this bad habit (They are not working all the time on controlled machines). This is similar to an OSX feature, as described here.
There is a small difference that you may use it to know if it was a safe remove:
Noticed by monitoring udev events:
udevadm monitor -u --environment
Safe remove
UDEV [8292.380554] change /devices/pci0000:00/0000:00:14.0/usb1/1-2/1-2:1.0/host16/target16:0:0/16:0:0:0/block/sdb (block)
ACTION=change
DEVLINKS=/dev/disk/by-id/usb-ADATA_USB_Flash_Drive_8d90ec535e6663-0:0 /dev/disk/by-path/pci-0000:00:14.0-usb-0:2:1.0-scsi-0:0:0:0
DEVNAME=/dev/sdb
DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-2/1-2:1.0/host16/target16:0:0/16:0:0:0/block/sdb
DEVTYPE=disk
DISK_MEDIA_CHANGE=1
ID_BUS=usb
ID_INSTANCE=0:0
ID_MODEL=USB_Flash_Drive
ID_MODEL_ENC=USB\x20Flash\x20Drive\x20
ID_MODEL_ID=c96a
ID_PATH=pci-0000:00:14.0-usb-0:2:1.0-scsi-0:0:0:0
ID_PATH_TAG=pci-0000_00_14_0-usb-0_2_1_0-scsi-0_0_0_0
ID_REVISION=0.00
ID_SERIAL=ADATA_USB_Flash_Drive_8d90ec535e6663-0:0
ID_SERIAL_SHORT=8d90ec535e6663
ID_TYPE=disk
ID_USB_DRIVER=usb-storage
ID_USB_INTERFACES=:080650:
ID_USB_INTERFACE_NUM=00
ID_VENDOR=ADATA
ID_VENDOR_ENC=ADATA\x20\x20\x20
ID_VENDOR_ID=125f
MAJOR=8
MINOR=16
SEQNUM=2989
SUBSYSTEM=block
TAGS=:systemd:
USEC_INITIALIZED=554873
Unsafe remove
UDEV [8391.320280] remove /devices/pci0000:00/0000:00:14.0/usb1/1-3/1-3:1.0/host17/target17:0:0/17:0:0:0/block/sdb (block)
ACTION=remove
DEVLINKS=/dev/disk/by-id/usb-ADATA_USB_Flash_Drive_8d90ec535e6663-0:0 /dev/disk/by-path/pci-0000:00:14.0-usb-0:3:1.0-scsi-0:0:0:0
DEVNAME=/dev/sdb
DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-3/1-3:1.0/host17/target17:0:0/17:0:0:0/block/sdb
DEVTYPE=disk
ID_BUS=usb
ID_INSTANCE=0:0
ID_MODEL=USB_Flash_Drive
ID_MODEL_ENC=USB\x20Flash\x20Drive\x20
ID_MODEL_ID=c96a
ID_PART_TABLE_TYPE=dos
ID_PATH=pci-0000:00:14.0-usb-0:3:1.0-scsi-0:0:0:0
ID_PATH_TAG=pci-0000_00_14_0-usb-0_3_1_0-scsi-0_0_0_0
ID_REVISION=0.00
ID_SERIAL=ADATA_USB_Flash_Drive_8d90ec535e6663-0:0
ID_SERIAL_SHORT=8d90ec535e6663
ID_TYPE=disk
ID_USB_DRIVER=usb-storage
ID_USB_INTERFACES=:080650:
ID_USB_INTERFACE_NUM=00
ID_VENDOR=ADATA
ID_VENDOR_ENC=ADATA\x20\x20\x20
ID_VENDOR_ID=125f
MAJOR=8
MINOR=16
SEQNUM=3022
SUBSYSTEM=block
TAGS=:systemd:
USEC_INITIALIZED=436355
Create a udev rule (change useranme
)
$ sudo nano /etc/udev/rules.d/90-unsafe-remove-notify.rules
ACTION=="remove", KERNEL=="sd?", ENV{ID_PART_TABLE_TYPE}!="", RUN+="/usr/bin/sudo -u username DISPLAY=:0 notify-send 'Unsafe Remove' '<b><i>Your long message</b></i>' -i /usr/share/icons/gnome/48x48/emotes/face-worried.png -t 10000"
Reload rules
sudo udevadm control --reload-rules
Another way, you may use a script (python) that connect to udisks
DBUS. It has all needed info you need about partition mount/unmount, disks plug/unplug...
Reference/Source: Gentoo Wiki: Udisks - USB_Thumb_Drive_Example
df -a | grep 'sd[b-z]'
command. A udev rule can send date of removal to a log of some sort. If the time of removal given by the script matches that of udev rule (at least by minutes, with the seconds there may be delay), then usb wasnt mounted. – Sergiy Kolodyazhnyy Jun 20 '15 at 23:45