Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/env bash
- set -euo pipefail
- # Fixed mountpoint (login-independent)
- MOUNTPOINT="/media/mcp/device"
- # Optional: if set, only mount a filesystem with this label (leave empty to accept any)
- WANTED_LABEL=""
- # Optional: for vfat/exfat/ntfs, force ownership to this uid:gid
- OWNER_USER="mcp"
- OWNER_GROUP="mcp"
- LOG_TAG="usb-auto-mount"
- log() {
- logger -t "$LOG_TAG" -- "$*"
- echo "[$(date '+%F %T')] $*"
- }
- ensure_mountpoint() {
- mkdir -p "$MOUNTPOINT"
- }
- uid_of() { id -u "$OWNER_USER"; }
- gid_of() { id -g "$OWNER_GROUP"; }
- # Return 0 if MOUNTPOINT is currently mounted
- is_mounted() {
- findmnt -rno TARGET "$MOUNTPOINT" >/dev/null 2>&1
- }
- # If mounted, unmount it
- do_unmount() {
- if is_mounted; then
- local src
- src="$(findmnt -rno SOURCE "$MOUNTPOINT" || true)"
- log "Unmounting $MOUNTPOINT (source: ${src:-unknown})"
- umount -l "$MOUNTPOINT" || umount "$MOUNTPOINT" || true
- fi
- }
- # Pick a USB partition device node to mount, e.g. /dev/sda1
- # Strategy:
- # 1) look at /dev/disk/by-id/usb-* symlinks
- # 2) resolve to kernel device
- # 3) choose a PARTITION if present; else use whole-disk block if it has a filesystem
- pick_usb_partition() {
- local byid dev kname part
- # Prefer stable USB by-id names
- for byid in /dev/disk/by-id/usb-*; do
- [[ -e "$byid" ]] || continue
- dev="$(readlink -f "$byid" || true)"
- [[ -b "$dev" ]] || continue
- # Get kernel name (e.g. sda, sdb)
- kname="$(lsblk -no KNAME "$dev" 2>/dev/null | head -n1 || true)"
- [[ -n "$kname" ]] || continue
- # Prefer first partition on that disk (e.g. /dev/sda1)
- part="/dev/${kname}1"
- if [[ -b "$part" ]]; then
- echo "$part"
- return 0
- fi
- # Otherwise, if the whole device has a filesystem, allow it (rare but possible)
- if lsblk -no FSTYPE "$dev" 2>/dev/null | grep -qE '.+'; then
- echo "$dev"
- return 0
- fi
- done
- return 1
- }
- # Get filesystem type and label
- fstype_of() { lsblk -no FSTYPE "$1" 2>/dev/null | head -n1 || true; }
- label_of() { lsblk -no LABEL "$1" 2>/dev/null | head -n1 || true; }
- # Mount with sane options per filesystem
- do_mount() {
- local dev="$1"
- local fstype label opts uid gid
- fstype="$(fstype_of "$dev")"
- label="$(label_of "$dev")"
- if [[ -z "$fstype" ]]; then
- log "Device $dev has no detectable filesystem (skipping)"
- return 1
- fi
- if [[ -n "$WANTED_LABEL" && "$label" != "$WANTED_LABEL" ]]; then
- log "Device $dev label '$label' != wanted '$WANTED_LABEL' (skipping)"
- return 1
- fi
- uid="$(uid_of)"
- gid="$(gid_of)"
- # Default mount options
- opts="rw,nosuid,nodev,noatime"
- # For non-POSIX fs, set ownership/masks so mcp can write
- case "$fstype" in
- vfat|fat|msdos)
- opts="$opts,uid=$uid,gid=$gid,fmask=0022,dmask=0002,utf8=1"
- ;;
- exfat)
- opts="$opts,uid=$uid,gid=$gid,fmask=0022,dmask=0002"
- ;;
- ntfs|ntfs3)
- opts="$opts,uid=$uid,gid=$gid,umask=0002"
- ;;
- ext4|ext3|ext2|xfs|btrfs)
- # ownership handled by filesystem permissions
- ;;
- *)
- log "Filesystem type '$fstype' on $dev is unhandled; trying generic mount"
- ;;
- esac
- log "Mounting $dev (fstype=$fstype label='${label:-}' ) -> $MOUNTPOINT"
- mount -t "$fstype" -o "$opts" "$dev" "$MOUNTPOINT"
- }
- # Try to mount if nothing is mounted
- try_mount_once() {
- ensure_mountpoint
- if is_mounted; then
- return 0
- fi
- local dev=""
- if dev="$(pick_usb_partition)"; then
- do_mount "$dev" || true
- else
- # No USB devices currently visible
- :
- fi
- }
- main() {
- ensure_mountpoint
- # Serialize (avoid multiple instances fighting)
- exec 9>/run/usb-auto-mount.lock
- if ! flock -n 9; then
- log "Another instance is running; exiting."
- exit 0
- fi
- # Initial attempt in case USB is already plugged in
- try_mount_once
- log "Watching udev for USB block add/remove events..."
- # Monitor udev events for block devices.
- # We'll react to add/remove and re-check state each time.
- udevadm monitor --udev --subsystem-match=block | while IFS= read -r line; do
- # We react on lines that contain "add" or "remove"
- if grep -qE '\b(add|remove)\b' <<<"$line"; then
- # Small settle to let partitions appear/disappear
- udevadm settle --timeout=5 || true
- # If current mount source disappeared, unmount
- if is_mounted; then
- local src
- src="$(findmnt -rno SOURCE "$MOUNTPOINT" || true)"
- if [[ -n "$src" && ! -b "$src" ]]; then
- log "Mounted source $src no longer exists; unmounting."
- do_unmount
- fi
- fi
- # If not mounted, try mounting
- try_mount_once
- fi
- done
- }
- trap 'log "Shutting down; unmounting."; do_unmount' INT TERM
- main
Advertisement
Add Comment
Please, Sign In to add comment