This guide documents a working setup for automatically mounting USB devices (sticks, SD cards, etc.), sharing them via Samba, and cleanly unmounting them via script or udev triggers, using systemd
, udev
, and CLI tools.
/etc/samba/smb.conf # Samba config
/etc/systemd/system/[email protected] # Mount handler unit (template)
/etc/systemd/system/[email protected] # Unmount handler unit (template)
/etc/udev/rules.d/99-usb-mount.rules # udev rules to trigger systemd units
/usr/local/bin/usb-mount-handler.sh # Script to handle mounting
/usr/local/bin/usb-umount-handler.sh # Script to handle unmounting and cleanup
~/safe-eject.sh # Manual safe eject script for the user
ACTION=="add", KERNEL=="sd[b-z][0-9]", ENV{ID_FS_TYPE}!="", RUN+="/bin/systemctl start usb-mount@%k.service"
ACTION=="remove", KERNEL=="sd[b-z][0-9]", RUN+="/bin/systemctl start usb-umount@%k.service"
/etc/systemd/system/[email protected]
[Unit]
Description=Mount USB device %i
After=local-fs.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/usb-mount-handler.sh %i
RemainAfterExit=true
StandardOutput=journal
StandardError=journal
/etc/systemd/system/[email protected]
[Unit]
Description=Unmount USB device %i
After=local-fs.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/usb-umount-handler.sh %i
StandardOutput=journal
StandardError=journal
#!/bin/bash
DEVICE="/dev/$1"
MOUNTPOINT="/media/usb-mount/usb-$1"
LOGGER="/usr/bin/logger"
BLKID="/usr/sbin/blkid"
MOUNT="/bin/mount"
MKDIR="/bin/mkdir"
CHMOD="/bin/chmod"
SLEEP="/bin/sleep"
$SLEEP 1
$MKDIR -p "$MOUNTPOINT"
FS=$($BLKID -o value -s TYPE "$DEVICE" 2>/dev/null)
$LOGGER "usb-mount: mounting $DEVICE (FS: $FS)"
case "$FS" in
vfat|exfat|ntfs)
$MOUNT -o uid=1000,gid=1000 "$DEVICE" "$MOUNTPOINT"
;;
*)
$MOUNT "$DEVICE" "$MOUNTPOINT"
;;
esac
$CHMOD -R 777 "$MOUNTPOINT"
$LOGGER "usb-mount: $DEVICE mounted at $MOUNTPOINT"
#!/bin/bash
DEVICE="/dev/$1"
MOUNTPOINT="/media/usb-mount/usb-$1"
LOGGER="/usr/bin/logger"
UMOUNT="/bin/umount"
RM="/bin/rm"
MOUNTPOINT_BIN="/usr/bin/mountpoint"
SLEEP="/bin/sleep"
$SLEEP 1
if $MOUNTPOINT_BIN -q "$MOUNTPOINT"; then
$UMOUNT "$MOUNTPOINT" && $LOGGER "usb-umount: $MOUNTPOINT unmounted"
else
$LOGGER "usb-umount: device $DEVICE already removed, skipping umount"
fi
$RM -rf "$MOUNTPOINT"
$LOGGER "usb-umount: $MOUNTPOINT removed"
#!/bin/bash
MOUNTBASE="/media/usb-mount"
LOGGER="/usr/bin/logger"
echo
echo "π Devices mounted in $MOUNTBASE:"
echo
FOUND=0
for dir in "$MOUNTBASE"/usb-*; do
[ -d "$dir" ] || continue
dev=$(findmnt -n -o SOURCE --target "$dir")
echo "π $dev mounted on $dir"
FOUND=1
done
if [ $FOUND -eq 0 ]; then
echo "β No mounted devices found in $MOUNTBASE."
exit 1
fi
echo
read -p "π¦ Enter the device name to eject (e.g., sdb1): " DEV
DEVPATH="/dev/$DEV"
BASENAME="/dev/${DEV%%[0-9]*}" # e.g., sdb1 β sdb
echo
echo "π© Unmounting $DEVPATH..."
udisksctl unmount -b "$DEVPATH"
UMOUNT_STATUS=$?
if [ $UMOUNT_STATUS -eq 0 ]; then
echo "β
Successfully unmounted."
echo "β‘ Powering off device ($BASENAME)..."
udisksctl power-off -b "$BASENAME"
echo "β
Device powered off and safe to remove!"
$LOGGER "safe-eject: $DEVPATH unmounted and powered off successfully"
else
echo "β Failed to unmount $DEVPATH"
$LOGGER "safe-eject: ERROR while unmounting $DEVPATH"
fi
[usb-share]
path = /media/usb-mount
browsable = yes
writable = yes
guest ok = yes
force user = nobody
create mask = 0777
directory mask = 0777
This share allows browsing and full access (read/write) to all mounted USB folders under /media/usb-mount
.
- π Insert USB β auto-mounted via
systemd
, exposed via Samba - β Remove USB β auto-unmounted via
systemd
, mount folder deleted - ποΈ Run
~/safe-eject.sh
β graceful unmount and power off viaudisksctl
System is headless-friendly, persistent, modular, and clean.
systemctl daemon-reload
after modifying units- Ensure all scripts in
/usr/local/bin
arechmod +x
- Adjust
UID/GID
in scripts if needed (default: 1000) - Monitor logs with:
journalctl -u usb-mount@...
,-u usb-umount@...
, orudevadm monitor
Made with β€οΈ for a reliable, DIY home server setup. Special thanks to GPT-4o π€.