Systemd Automation: Solving USB Drive Mounting Issues in Headless Debian Systems


2 views

When migrating from legacy systems to modern Debian Jessie with systemd, many administrators encounter USB mounting issues where udev-mounted drives become inaccessible with "Transport endpoint not connected" errors. The fundamental conflict arises from systemd's process management interfering with traditional udev mounting techniques.

The proper approach leverages udisks2, which maintains compatibility with systemd's expectations. Unlike direct udev mounting, udisks2:

  • Maintains proper DBus communication channels
  • Respects systemd's service management
  • Provides proper event sequencing

Replace your old mounting rule with this udisks2-triggering alternative:

# /etc/udev/rules.d/99-usb-backup.rules
ACTION=="add", SUBSYSTEM=="block", ENV{ID_FS_USAGE}=="filesystem", RUN+="/usr/bin/udisksctl mount -b /dev/%k"

After implementing the rule, test with:

sudo udevadm control --reload-rules
sudo udevadm trigger

Check mount status with:

udisksctl status

For more control, create a systemd service that watches for mount events:

# /etc/systemd/system/usb-backup.service
[Unit]
Description=USB Backup Trigger
Requires=udisks2.service
After=udisks2.service

[Service]
ExecStart=/usr/bin/udisksctl monitor
ExecStartPost=/usr/local/bin/handle-mount.sh

[Install]
WantedBy=multi-user.target

The companion script might look like:

#!/bin/bash
# /usr/local/bin/handle-mount.sh
while read -r line; do
  if [[ $line =~ "mounted /dev/" ]]; then
    DEVICE=$(echo $line | cut -d' ' -f3)
    MOUNTPOINT=$(findmnt -n -o TARGET $DEVICE)
    # Trigger backup process
    /usr/local/bin/run-backup $MOUNTPOINT
  fi
done

When migrating older Linux systems to modern systemd-based distributions, one particularly stubborn issue is reliable USB drive automounting. The traditional udev rules approach that worked perfectly on SysV-init systems starts behaving unpredictably under systemd.

The core issue stems from systemd's process management. When udev triggers a mount operation, systemd considers it part of the device setup transaction. Even if you try to background the mount process, systemd's cgroup tracking will still maintain the connection and potentially kill the mount when it considers the transaction complete.

# Traditional udev rule that partially works but gets disconnected
ACTION=="add", KERNEL=="sd[a-z][0-9]", RUN+="/bin/mount -t auto /dev/%k /mnt/usb"

The modern approach leverages udisks2, which properly integrates with systemd's service model. Here's how to implement it:

# First, install required packages
sudo apt-get install udisks2

# Then create a udev rule that triggers udisks
ACTION=="add", KERNEL=="sd[a-z][0-9]", ENV{ID_FS_USAGE}=="filesystem", \
    RUN+="/usr/bin/udisksctl mount -b /dev/%k"

For headless servers where you need more control over mount points and options, create a systemd service:

# /etc/systemd/system/usb-mount@.service
[Unit]
Description=Mount USB Drive %i
Requires=dev-%i.device
After=dev-%i.device

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/bin/mkdir -p /media/usb-%i
ExecStart=/bin/mount -t auto -o sync,noatime /dev/%i /media/usb-%i
ExecStop=/bin/umount -l /dev/%i
ExecStop=/bin/rmdir /media/usb-%i

# Corresponding udev rule
ACTION=="add", KERNEL=="sd[a-z][0-9]", TAG+="systemd", \
    ENV{SYSTEMD_WANTS}="usb-mount@%k.service"

For production systems, you'll want to add filesystem verification:

# Enhanced mount script
#!/bin/bash
DEVICE=$1
MOUNT_POINT="/media/usb-$(basename $DEVICE)"

fsck -a $DEVICE
case $? in
    0)  # No errors
        mkdir -p $MOUNT_POINT
        mount -t auto -o sync,noatime $DEVICE $MOUNT_POINT
        ;;
    1)  # Filesystem errors corrected
        mkdir -p $MOUNT_POINT
        mount -t auto -o sync,noatime $DEVICE $MOUNT_POINT
        ;;
    *)  # Serious errors
        logger -t usb-mount "Filesystem errors on $DEVICE not repaired"
        exit 1
        ;;
esac

For cron jobs accessing these mounts, ensure proper permissions:

# Add to your udev rule
ACTION=="add", KERNEL=="sd[a-z][0-9]", GROUP="backup", MODE="0660", \
    RUN+="/usr/bin/udisksctl mount -b /dev/%k --no-user-interaction"