#!/bin/bash # exit immediately if /usr/bin/ is not yet available (during boot if /usr is a separate partition) test -d /usr/bin || exit # name: /etc/dev.d/default/updfstab.dev # version: 17 # purpose: automatic handling of /etc/fstab for usb_storage devices under kernel 2.6 with udev # This script is automatically called by udevd at each plug/unplug event of an usb device. # It adds a line in /etc/fstab for each usb_storage device found, # with a pretty name as mountpoint. (based on label or info read from /sys) # it takes three environment variables as input : ACTION, DEVPATH and DEVNAME or SUBSYSTEM # These variables are provided by udevd ################################################################## # Copyright (C) 2004-2005 Christophe Combelles (ccomb@free.fr) # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ################################################################## # to debug this script, set DEBUG to 1 and see /tmp/updfstab.debug.* after execution DEBUG=0 # remove all aliases unalias -a DEBUGOUT=/tmp/updfstab.debug.$$ if [ "$DEBUG" = "1" -a -z "$2" ]; then echo "executing $0 $@" > $DEBUGOUT echo "with the following environment variables:" >> $DEBUGOUT env >> $DEBUGOUT echo "----" >> $DEBUGOUT bash -x $0 $@ debug >> $DEBUGOUT 2>&1 exit fi # we only manage block devices if [ "$1" != "block" ]; then exit; fi # Who add plug ? XUSER=`who | awk '{ if($2==":0") print $1 }' | uniq` # get /dev DEV=`udevinfo -r` if [ $? -eq 127 ]; then exit; fi # we need DEVPATH, and ACTION, and (DEVNAME or SUBSYSTEM) so we warn the user who executes this script himself if [ -z "$DEVNAME" -a -z "$SUBSYSTEM" -o -z "$DEVPATH" -o -z "$ACTION" ]; then echo echo "This script must be called by udevd because it needs the following environment variables: DEVPATH, ACTION, and DEVNAME or SUBSYSTEM" echo "So you must copy this script as /etc/dev.d/default/updfstab-2.6.dev and set it executable" echo "See: http://www.kernel.org/pub/linux/utils/kernel/hotplug/RFC-dev.d" echo exit fi # Just in case there is no DEVNAME at removal. if [ -z "$DEVNAME" ]; then DEVNAME="$DEV/`basename $DEVPATH`"; fi # if $DEVPATH/device exists, we are a device. # If we find partitions, exit because the other instances will manage them. # Otherwise, we're just a device formatted as is, without partitions. if [ -d /sys${DEVPATH}/device ]; then WE_ARE="DEVICE" # do we have partitions? BASE=`echo $DEVPATH | cut -d"/" -f3` /bin/ls -d /sys${DEVPATH}/${BASE}* 1>/dev/null 2>/dev/null if [ $? -eq 0 ]; then exit fi else WE_ARE="PARTITION" fi # we only manage usb_storage devices # ( better detection is welcome) if [ "$ACTION" = "add" ]; then # two possibilities, because the /sys tree has not always the same depth if [ "$WE_ARE" = "PARTITION" ]; then device1="`cd -P /sys${DEVPATH}/../device/../../../../ 2> $DEV/null ; /bin/ls 2> /dev/null | grep ':' | head -n 1`" device2="`cd -P /sys${DEVPATH}/../device/../../../ 2> $DEV/null ; /bin/ls 2> /dev/null | grep ':' | head -n 1`" else if [ "$WE_ARE" = "DEVICE" ]; then device1="`cd -P /sys${DEVPATH}/device/../../../../ 2> $DEV/null ; /bin/ls 2> /dev/null | grep ':' | head -n 1`" device2="`cd -P /sys${DEVPATH}/device/../../../ 2> $DEV/null ; /bin/ls 2> /dev/null | grep ':' | head -n 1`" fi; fi if [ -z "$device1" -o ! -e /sys/bus/usb/drivers/usb-storage/$device1 ]; then if [ -z "$device2" -o ! -e /sys/bus/usb/drivers/usb-storage/$device2 ]; then exit fi; fi fi # lockfile used when modifying /etc/fstab LOCKFILE=/var/run/updfstab.dev.fstab # remove the lockfile when exiting cleanquit() { rm -f $LOCKFILE; exit } trap cleanquit INT trap cleanquit TERM trap cleanquit QUIT trap cleanquit HUP # write a lockfile to avoid simultaneous modifications of fstab by parallel executions or simultaneous access to the device # previous command : lockfile -1 -l 5 -s 5 $LOCKFILE COUNT=25 while [ -e $LOCKFILE -a $COUNT -gt 0 ]; do sleep 0.2 COUNT=$((COUNT-1)) done touch $LOCKFILE # functions for syslog LOGGER="logger -t `basename $0`[$$] -p user.notice" write_syslog () { echo ${@} | $LOGGER } # be sure the drivers are loaded /sbin/modprobe -q usb_storage /sbin/modprobe -q vfat # create the FHS required /media directory # See: http://www.pathname.com/fhs/pub/fhs-2.3.html#MEDIAMOUNTPOINT MNT=media if [ ! -d /$MNT ]; then mkdir /$MNT write_syslog "Created the /$MNT directory" if [ "$MNT" = "media" ]; then write_syslog "It is required by FHS standard" write_syslog "Please read: http://www.pathname.com/fhs/pub/fhs-2.3.html#MEDIAMOUNTPOINT" fi fi #------------------------------------UNPLUG---------------------------------- # remove the fstab entry and the mountpoint if they already exist # (even when plugging, to purge the possible bad old lines) if grep -q "^$DEVNAME\ .*\#updfstab$" /etc/fstab; then # get the mount point from fstab mntpoint=`grep "^$DEVNAME\ .*\#updfstab$" /etc/fstab | sed "s/.* \/${MNT}/\/${MNT}/g; s/ .*//g"` # if we want to unplug a mounted device, we are a fool, so limit the damage. if mount | grep -q "^$DEVNAME\ "; then # if the mountpoint is used by famd, and we kill it, we'll need to restart it if fuser -v $mntpoint 2>&1 | grep -q " famd$"; then RESTARTFAMD=1; fi fuser -k $mntpoint fuser -k -9 $mntpoint umount $mntpoint FAM=/etc/init.d/fam if [ "$RESTARTFAMD" = "1" -a -x $FAM ]; then $FAM restart; fi fi # remove the mount point if [ ! -z "$mntpoint" -a -d $mntpoint ]; then rmdir $mntpoint; fi write_syslog "Deleted mountpoint $mntpoint" # remove Desktop Icon if [ ! -z "$XUSER" ]; then TMP=$mntpoint for i in 0 1 2; do RES[$i]=${TMP%%/*} TMP=${TMP#*/} done dirFile="/home/$XUSER/Desktop/${RES[2]}" if [ -e "$dirFile" ] then unlink $dirFile write_syslog "Deleted Desktop's icon ($dirFile)" else write_syslog "Desktop's icon don't exist" fi fi # remove the fstab entry corresponding to the device TMP=/etc/fstab.updated$$ grep -v "^$DEVNAME\ .*\#updfstab$" /etc/fstab > $TMP if diff /etc/fstab $TMP > $DEV/null 2>&1; then rm -f $TMP else if [ -s /etc/fstab.updated$$ ]; then cat $TMP > /etc/fstab write_syslog "Removed $DEVNAME from fstab" fi rm -f $TMP fi fi #------------------------------------PLUG---------------------------------- # if the current device is being added if [ "$ACTION" = "add" ]; then # get partition information FILETYPE="`file -Ls $DEVNAME`" label=`echo "$FILETYPE" | grep "label:" | sed 's/.*label:\ *"//; s/".*//; s/[ \/]//g'` if [ "$WE_ARE" = "DEVICE" ]; then cd -P /sys${DEVPATH}/device; fi if [ "$WE_ARE" = "PARTITION" ]; then cd -P /sys${DEVPATH}/../device; fi [ -e model ] && model="`cat model | sed 's/[ \/]//g'`" [ -e vendor ] && vendor="`cat vendor | sed 's/[ \/]//g'`" # if we are an extended partition, just exit if echo "$FILETYPE" | grep -q "extended partition table"; then cleanquit; fi # handle XFS ('file' doesn't print label) xfs=`echo "$FILETYPE" | grep "XFS"` if [ -z "${label}" -a ! -z "${xfs}" -a -x "`which xfs_admin`" ]; then label=`xfs_admin -l $DEVNAME | sed 's/.*label\ =\ *"\+//; s/"\+$//; s/[ \/]//g'` fi # handle EXT2/3 ext=`echo "$FILETYPE" | grep "ext[23]"` if [ ! -z "${ext}" -a -z "${label}" -a -x "`which e2label`" ]; then label=`e2label $DEVNAME | sed 's/[ \/]//g'` fi # build a mountpoint name = label, else model, else vendor, else usb-disk if [ ! -z "${label}" ]; then mntpoint="/$MNT/${label}" else if [ ! -z "${model}" ]; then mntpoint="/$MNT/${model}" else if [ ! -z "${vendor}" ]; then mntpoint="/$MNT/${vendor}" else mntpoint="/$MNT/usb-disk" fi; fi; fi # if the mount point is already used in fstab, append a number if grep -qE "^[^#]*[[:space:]]$mntpoint[[:space:]]" /etc/fstab ; then count=1 while grep -qE "^[^#]*[[:space:]]${mntpoint}_${count}[[:space:]]" /etc/fstab ; do count=$((count+1)) done mntpoint=${mntpoint}_${count} fi # create the mountpoint and the fstab entry if they don't exist if [ ! -d "${mntpoint}" ]; then mkdir ${mntpoint} write_syslog "Created mountpoint ${mntpoint}" fi FSTYPE=auto # if we are a FAT or NTFS, set the charset to utf8 # Also determine the filesystem. ("auto" does not always work) if echo $FILETYPE | grep -q "FAT"; then IOCHARSET=",iocharset=utf8"; FSTYPE=vfat; else if echo $FILETYPE | grep -q "NTFS"; then IOCHARSET=",iocharset=utf8"; FSTYPE=ntfs; else if echo $FILETYPE | grep -q "XFS"; then FSTYPE=xfs; else if echo $FILETYPE | grep -q "ext2"; then FSTYPE=ext2; else if echo $FILETYPE | grep -q "ext3"; then FSTYPE=ext3; fi; fi; fi; fi; fi FSTABLINE="$DEVNAME $mntpoint $FSTYPE user,noauto,noatime,rw${IOCHARSET} 0 0 #updfstab" echo "$FSTABLINE" >> /etc/fstab write_syslog "Added $DEVNAME to fstab" if [ ! -z "$XUSER" ]; then # Mount this model su - $XUSER -c "mount $mntpoint"; # Add Desktop's icon dirFile="/home/$XUSER/Desktop/$model" write_syslog "Add icon on Desktop ($dirFile)" cat > "$dirFile" <<-EOF [Desktop Entry] Dev=$DEVNAME Encoding=UTF-8 Icon=usbpendrive_mount MountPoint=$mntpoint ReadOnly=false Type=FSDevice UnmountIcon=usbpendrive_unmount EOF fi fi # remove the lockfile rm -f $LOCKFILE