#!/bin/sh # # Automount hotplugged block devices, by Wout Mertens (wmertens@gentoo.org) # # Linux v2.6 version # This script is released under version 2 of the GPL. # To install this, either make it /sbin/hotplug, or, if you have # linux-hotplug installed, make it /etc/hotplug.d/block/automount.hotplug . # It needs to be executable. I tested it with busybox's ash. # # The devices will be mounted for the console user if applicable. # # To work, this needs: # - v2.6 kernel support: # - hotplugging, /proc mounted, /sys mounted # - filesystems that will be mounted, like vfat # - sh, echo, sed, stat or ls, getent or grep passwd, # mount, umount, mkdir, rmdir. logger is used if there. # # Possible improvements: # - Create a desktop entry for the device. # - Call a notifier script when mounting/unmounting. This could create the # desktop entry by itself. # - Edit fstab instead, and give the "user" option. This depends more on # the user/desktop knowing what he/it is doing. # - Mount as supermount if available. This will improve behaviour for # synchronous writes and hanging mounts, although umount -lf already # does a good job. UPDATE: added, but untested. Let me know if it works. # - Detect filesystem on device, so filesystems that don't need a mounting # user can skip user detection. #ChangeLog: #2004-05-03: Jaromir Malenko # Minor changes #2004-05-01: Jaromir Malenko # FIX: Supermount # Cleanup #Previous changes: Wout Mertens (wmertens@gentoo.org) # Debugging # set -xv # exec > /tmp/hotplug.$$ 2>&1 PATH="/bin:/sbin:/usr/bin:/usr/sbin" export PATH # We only handle block device messages [ "$1" != "block" ] && exit 0 # Proclaim stuff to the world mesg () { logger -t $0 "$*" } # Is path already mounted? is_path_mounted () { while read dev path rest do if [ "$path" = "$1" ] then return 0 fi done < /proc/self/mounts return 1 } # Get mounted path for a device get_mounted_path () { while read dev path type rest do if [ "$type" = "supermount" ] then if echo "$rest" | grep -q "$1" then echo "$path" return 0 fi else if [ "$dev" = "$1" ] then echo "$path" return 0 fi fi done < /proc/self/mounts return 1 } # Wait for a file to appear wait_for () { local count=0 while [ $count -lt 10 ] && [ ! -e "$1" ] do sleep 1 done [ $count -eq 10 ] && return 1 return 0 } # Remove strange characters from a filename clean_filename () { # Note the lack of quotes around $1, this strips off spaces. echo $1 | sed 's/[ /?*\"<>]/_/g' } # Figure out the device to mount set `echo $DEVPATH | sed 's/\// /g'` [ $# -ne 3 ] && exit 0 DEVICE=/dev/$3 case $ACTION in remove) # Is it ours? dir=`get_mounted_path $DEVICE` echo "$dir" | grep -q ^/mnt/usb || exit 0 # Unmount it [ -d "$dir" ] || exit 1 mesg Unmounting: "$dir" umount -lf "$dir" rmdir "$dir" exit 1 ;; add) # Is it a usb device? Exit if not. ls -l /sys/$1/$2/device | sed 's/^.* -> //g' | grep -q usb || exit 0 # Mount it # Make sure we have support for vfat modprobe -q vfat wait_for /sys/$1/$2/device/vendor || exit 1 # Find the name PRODUCT=`cat /sys/$1/$2/device/model` if [ -z "$PRODUCT" ] then PRODUCT=generic fi # Find out where we mount it MOUNTPATH=/mnt/usb/`clean_filename "$PRODUCT"` if is_path_mounted "$MOUNTPATH" then count=1 while is_path_mounted "${MOUNTPATH}_${count}" do count=$(( $count + 1 )) done MOUNTPATH="${MOUNTPATH}_${count}" fi # Make sure it's a directory if [ -e "$MOUNTPATH" ] then if [ ! -d "$MOUNTPATH" ] then mesg "$MOUNTPATH exists but is not a directory" exit 1 fi else mkdir -p "$MOUNTPATH" if [ $? -ne 0 ] then mesg "Could not create mountpoint $MOUNTPATH" exit 1 fi fi # Find out who we are going to mount it as #CONSOLEUSER=`stat -c%U /dev/console 2>/dev/null` CONSOLEUSER=`who | grep ":0" | cut -f 1 -d " "` if [ -z "$CONSOLEUSER" ] then set `ls -l /dev/console` CONSOLEUSER=$3 fi [ -n "$CONSOLEUSER" ] || CONSOLEUSER=root PASSWD=`getent passwd $CONSOLEUSER 2>/dev/null` if [ -z "$PASSWD" ] then PASSWD=`grep "^$CONSOLEUSER:" /etc/passwd || grep "^root:" /etc/passwd` fi if [ -z "$PASSWD" ] then mesg "Could not get password entry for $CONSOLEUSER nor root" exit 1 fi set `echo $PASSWD | sed 's/:/ /g'` if [ $# -lt 4 ] then mesg "Bad password entry for $CONSOLEUSER" exit 1 fi # These options should prevent abuse and make it writeable for the # console user. if grep -q supermount /proc/filesystems then MOUNTOPTS="-s -t supermount -odev=$DEVICE,fs=auto,--,noatime,nosuid,umask=077,uid=$3,gid=$4" DEVICE="none" else MOUNTOPTS="-s -onoatime,sync,dirsync,nosuid,umask=007,uid=$3,gid=$4" fi mesg Mounting $DEVICE on $MOUNTPATH, options $MOUNTOPTS mount $MOUNTOPTS $DEVICE $MOUNTPATH ;; *) mesg automount.hotplug $ACTION event not supported exit 1 ;; esac