#!/bin/sh # this is a small automounter (and unmounter) for usb and other # removable devices for the kernel hotplug framework with busybox/mdev # Author: Alexander Zangerl (az) # Licence: GPL version 1 or version 2 # $Id: block.agent,v 1.23 2016/07/16 11:49:50 az Exp $ # this agent mounts at /media/LABEL, /media/UUID or /media/devname in # this order, if the config file says "do mount" for this fs label/uuid. # the agent ignores non-removable devices. # it removes the mount point dir on device remove and unmounts the defice, # if it was still mounted. # the unmount/remove logic uses a statefile in /var/run to keep track # of what is "ours" and should be cleaned up on demand. # requirements: busybox and mdev, pmount, and either # a mounted /usr (for pinky and pmount) or the mounted devices will # belong to root. # terminal on stderr -> log to that and to syslog, otherwise syslog only ME=$(busybox basename $0)"[$$]" [ -t 2 ] && LOGARGS=-s mesg () { busybox logger $LOGARGS -t "$ME" "$@" } debug_mesg () { [ -z "$DEBUG" ] && return mesg "$@" } [ -z "$BASE" ] && BASE=/media STATEF=/var/run/block.agent.state OPTIONFILE="/etc/mdev/block.settings" cd /tmp # finds a mountpoint for $1, the realdev # sets $MOUNT to the full mount command, or empty if not to be mounted # also sets $TARGET findmount () { local RD=$1 MOUNT="" debug_mesg "testing $RD for filesystem" eval `/sbin/blkid -o udev $RD` if [ "$?" != 0 -o -z "$ID_FS_TYPE" ]; then debug_mesg "$RD has no detectable filesystem" return fi if [ -n "$ID_FS_LABEL" ] ; then ID_FS_LABEL=$( echo "$ID_FS_LABEL" | tr '[A-Z]' '[a-z]' ) TARGET=$BASE/$ID_FS_LABEL PREF=$ID_FS_LABEL elif [ -n "$ID_FS_UUID" ]; then TARGET=$BASE/$ID_FS_UUID PREF=$ID_FS_UUID else TARGET=$BASE/$(busybox basename $RD) PREF=$(busybox basename $RD) fi local MOUNTOPT="-" # determine where, how and if to mount this thing while read U L T O ; do ISCOMMENT=$(printf %.1s "$U") [ "$ISCOMMENT" = "#" -o -z "$U" ] && continue; debug_mesg "testing $ID_FS_UUID $ID_FS_LABEL $ID_FS_TYPE against $U $L $T" if [ \( "$U" = "$ID_FS_UUID" -o "$U" = "*" \) \ -a \( "$L" = "$ID_FS_LABEL" -o "$L" = "*" \) \ -a \( "$T" = "$ID_FS_TYPE" -o "$T" = "*" \) ] ; then debug_mesg "found entry $U $L $T $O for $RD"; MOUNTOPT="$O"; break; fi done < $OPTIONFILE if [ "$MOUNTOPT" = "-" ] ; then mesg "$RD: no automounting" return else mesg "$RD: $TARGET options $MOUNTOPT" if [ "$MOUNTOPT" = "+" ]; then # pmount and use first logged in user # x11 user first, console as fallback MAINUSER=`pinky -fw 2>/dev/null| awk '{ if ($2 ~ /^\??:0/ || $(NF) ~ /^\??:0/ ) { print $1; exit; } }'` if [ -z "$MAINUSER" ]; then MAINUSER=`pinky -fw 2>/dev/null|fgrep '*'|head -1 | cut -f 1 -d " "` fi if [ -n "$MAINUSER" ]; then MOUNT="su -c 'pmount $RD \"$PREF\"' $MAINUSER" else MOUNT="pmount $RD \"$PREF\"" fi else if [ -n "$MOUNTOPT" ] ; then MOUNT="mount -o $MOUNTOPT $RD $TARGET" else MOUNT="mount $RD $TARGET" fi fi fi return } # what we get: # ACTION=add HOME=/ SEQNUM=2223 PWD=/dev # DEVNAME=sdd1 MAJOR=8 MINOR=49 DEVTYPE=partition # that's from mdev: MDEV=sdd1 SUBSYSTEM=block # DEVPATH=/devices/pci0000:00/0000:00:1d.7/usb1/1-7/1-7:1.0/host3/target3:0:0/3:0:0:0/block/sdd/sdd1 REALDEV=/dev/$MDEV if [ "$ACTION" = "add" -o "$ACTION" = "change" ]; then REMF="/sys/$DEVPATH/removable" [ -f "$REMF" ] || REMF="/sys/$DEVPATH/../removable" if [ "`cat $REMF`" != 1 ]; then debug_mesg "device $REALDEV is not removable." exit 0 fi # prime the cache /sbin/blkid >/dev/null 2>&1 # sets $MOUNT, $TARGET findmount $REALDEV if [ -z "$MOUNT" ] ; then exit 0; else mesg "trying automount of $REALDEV at $TARGET" [ ! -d "$TARGET" ] && mkdir $TARGET debug_mesg "$MOUNT" eval $MOUNT # necessary if we need to su and pmount RES=$? if [ $RES != 0 ] ; then mesg "mounting $REALDEV failed with $RES" exit 1 fi echo $REALDEV $TARGET >> $STATEF fi elif [ "$ACTION" = "remove" ] ; then MPT=$(egrep "^$REALDEV /" $STATEF|cut -f 2 -d " ") # ours? unmount if mounted, remove dir if [ -n "$MPT" ]; then egrep -v "^$REALDEV $MPT" $STATEF > $STATEF.x mv $STATEF.x $STATEF LOC=$(egrep "^$REALDEV $MPT" /proc/mounts) if [ -n "$LOC" ] ; then mesg "attempting late unmount of $REALDEV from $MPT" umount -f $REALDEV RES=$? if [ $RES != 0 ] ; then mesg "unmounting $REALDEV failed with $RES" fi fi mesg "cleaning up mountpoint dir $MPT for $REALDEV" rmdir $MPT fi else debug_mesg "ignoring action $ACTION with $MDEV" exit 1 fi exit 0