#! /usr/bin/sh # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # Copyright 2010 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # # This is a clean script for removable disks # # Following is the syntax for calling the script: # scriptname [-s|-f|-i|-I] devicename [-A|-D] username zonename zonepath # # -s for standard cleanup by a user # -f for forced cleanup by an administrator # -i for boot-time initialization (when the system is booted with -r) # -I to suppress error/warning messages; the script is run in the '-i' # mode # # $1: devicename - device to be allocated/deallocated, e.g., sr0 # # $2: -A if cleanup is for allocation, or -D if cleanup is for deallocation. # # $3: username - run the script as this user, rather than as the caller. # # $4: zonename - zone in which device to be allocated/deallocated # # $5: zonepath - root path of zonename # # A clean script for a removable media device should prompt the user to # insert correctly labeled media at allocation time, and ensure that the # media is ejected at deallocation time. # # Unless the clean script is being called for boot-time # initialization, it may communicate with the user via stdin and # stdout. To communicate with the user via CDE dialogs, create a # script or link with the same name, but with ".windowing" appended. # For example, if the clean script specified in device_allocate is # /etc/security/xyz_clean, that script must use stdin/stdout. If a # script named /etc/security/xyz_clean.windowing exists, it must use # dialogs. To present dialogs to the user, the dtksh script # /etc/security/lib/wdwmsg may be used. # # This particular script, disk_clean, will work using stdin/stdout, or # using dialogs. A symbolic link disk_clean.windowing points to # disk_clean. # # #################################################### # ################ Local Functions ################# # #################################################### # # Set up for windowing and non-windowing messages # msg_init() { if [ `basename $0` != `basename $0 .windowing` ]; then WINDOWING="yes" case $VOLUME_MEDIATYPE in cdrom) TITLE="CD-ROM";; rmdisk) TITLE="Removable Disk";; floppy) TITLE="Floppy";; *) TITLE="Disk";; esac if [ "$MODE" = "allocate" ]; then TITLE="$TITLE Allocation" else TITLE="$TITLE Deallocation" fi else WINDOWING="no" fi } # # Display a message for the user. For windowing, user must press OK button # to continue. For non-windowing, no response is required. # msg() { if [ "$WINDOWING" = "yes" ]; then $WDWMSG "$*" "$TITLE" OK elif [ "$silent" != "y" ]; then echo "$*" > /dev/${MSGDEV} fi } ok_msg() { if [ "$WINDOWING" = "yes" ]; then $WDWMSG "$*" "$TITLE" READY else form=`gettext "Media in %s is ready. Please store safely."` printf "${form}\n" $PROG $DEVICE > /dev/{MSGDEV} fi } error_msg() { if [ "$WINDOWING" = "yes" ]; then $WDWMSG "$*" "$TITLE" ERROR else form=`gettext "%s: Error cleaning up device %s."` printf "${form}\n" $PROG $DEVICE > /dev/${MSGDEV} fi } # # Ask the user an OK/Cancel question. Return 0 for OK, 1 for Cancel. # okcancel() { if [ "$WINDOWING" = "yes" ]; then $WDWMSG "$*" "$TITLE" OK Cancel elif [ "$silent" != "y" ]; then get_reply "$* (y to continue, n to cancel) \c" y n fi } # # Ask the user an Yes/No question. Return 0 for Yes, 1 for No # yesno() { if [ "$WINDOWING" = "yes" ]; then $WDWMSG "$*" "$TITLE" Yes No elif [ "$silent" != "y" ]; then get_reply "$* (y/n) \c" y n fi } # # Display an error message, put the device in the error state, and exit. # error_exit() { if [ "$silent" != "y" ]; then msg "$2" "$3" \ "\n\nDevice has been placed in allocation error state." \ "\nPlease inform system administrator." fi exit 1 } # # get_reply prompt choice ... # get_reply() { prompt=$1; shift while true do echo $prompt > /dev/tty read reply i=0 for choice in $* do if [ "$choice" = "$reply" ] then return $i else i=`expr $i + 1` fi done done } # # Find the first disk slice containing a file system # find_fs() { # The list of files in device_maps(4) is in an unspecified order. # To speed up the fstyp(1M) scanning below in most cases, perform # the search for filesystems as follows: # 1) Select only block device files of the form "/dev/dsk/*". # 2) Sort the list of files in an order more likely to yield # matches: first the fdisk(1M) partitions ("/dev/dsk/cNtNdNpN") # then the format(1M) slices ("/dev/dsk/cNtNdNsN"), in ascending # numeric order within each group. DEVall="`echo $FILES | \ /usr/bin/tr ' ' '\n' | \ /usr/bin/sed '/^\/dev\/dsk\//!d; s/\([sp]\)\([0-9]*\)$/ \1 \2/;' | \ /usr/bin/sort -t ' ' -k 2,2d -k 3,3n | \ /usr/bin/tr -d ' '`" for DEVn in $DEVall ; do fstyp_output="`/usr/sbin/fstyp -a $DEVn 2>&1`" if [ $? = 0 ]; then FSPATH=$DEVn gen_volume_label="`echo "$fstyp_output" | \ sed -n '/^gen_volume_label: .\(.*\).$/s//\1/p'`" if [ "$gen_volume_label" != "" ]; then FSNAME="`echo $gen_volume_label | \ /usr/xpg4/bin/tr '[:upper:] ' '[:lower:]_'`" fi # For consistency, hsfs filesystems detected at # /dev/dsk/*p0 are mounted as /dev/dsk/*s2 FSTYPE=`echo "$fstyp_output" | /usr/bin/head -1` if [ "$FSTYPE" = hsfs -a \ `/usr/bin/expr $FSPATH : '.*p0'` -gt 0 ]; then FSPATH=`echo $FSPATH | /usr/bin/sed 's/p0$/s2/'` fi return fi done } # # Find all mountpoints in use for a set of device special files. # Usage: findmounts devpath ... # findmounts() { nawk -f - -v vold_root="$VOLD_ROOT" -v devs="$*" /etc/mnttab <<\ "ENDOFAWKPGM" BEGIN { split(devs, devlist, " "); for (devN in devlist) { dev = devlist[devN]; realdevlist[dev] = 1; sub(/.*\//, "", dev); sub(/s[0-9]$/, "", dev); if (vold_root != "") { vold_dir[vold_root "/dev/dsk/" dev] = 1; vold_dir[vold_root "/dev/rdsk/" dev] = 1; } } } { for (dev in realdevlist) { if ($1 == dev) { mountpoint = $2; print mountpoint; } } for (dev in vold_dir) { if (substr($1, 1, length(dev)) == dev) { mountpoint = $2; print mountpoint; } } } ENDOFAWKPGM } # # Allocate a device. # Ask the user to make sure the disk is properly labeled. # Ask if the disk should be mounted. # do_allocate() { if [ $VOLUME_MEDIATYPE = floppy ]; then # Determine if media is in drive eject_msg="`eject -q $DEVFILE 2>&1`" eject_status="$?" case $eject_status in 1) # Media is not in drive okcancel "Insert disk in $DEVICE." if [ $? != 0 ]; then exit 0 fi;; 3) # Error error_exit $DEVICE \ "Error checking for media in drive.";; esac else okcancel "Insert disk in $DEVICE." if [ $? != 0 ]; then exit 0 fi fi yesno "Do you want $DEVICE mounted?" if [ $? != 0 ]; then exit 0 fi if [ $VOLUME_MEDIATYPE = cdrom -o $VOLUME_MEDIATYPE = rmdisk ]; then # Get the device path and volume name of a partition find_fs if [ "$FSPATH" != "" ]; then VOLUME_PATH=$FSPATH fi if [ "$FSNAME" != "" ]; then VOLUME_NAME=$FSNAME fi fi VOLUME_ACTION=insert # Give ourself write permission on device file so file system gets # mounted read/write if possible. # rmmount only cares about permissions not user... chown $VOLUME_USER $VOLUME_PATH chmod 700 $VOLUME_PATH # Do the actual mount. VOLUME_* environment variables are inputs to # rmmount. rmmount_msg="`/usr/sbin/rmmount 2>&1`" rmmount_status="$?" if [ $rmmount_status -eq 0 ]; then EXIT_STATUS=$CLEAN_MOUNT elif [ $rmmount_status -gt 0 -a $VOLUME_MEDIATYPE != cdrom ]; then # Try again in readonly mode. cdrom is always mounted ro, so # no need to try again. echo "Read-write mount of $DEVICE failed. Mounting read-only." VOLUME_ACTION=remount; export VOLUME_ACTION VOLUME_MOUNT_MODE=ro; export VOLUME_MOUNT_MODE `/usr/sbin/rmmount` if [ $? -eq 0 ]; then EXIT_STATUS=$CLEAN_MOUNT fi fi # Set permissions on directory used by vold, sdtvolcheck, etc. if [ -d /tmp/.removable ]; then chown root /tmp/.removable chmod 777 /tmp/.removable fi } do_deallocate() { if [ $VOLUME_MEDIATYPE = cdrom -o $VOLUME_MEDIATYPE = rmdisk ]; then if [ -h /$VOLUME_MEDIATYPE/$DEVICE ]; then # Get the device path and volume name of a partition VOLUME_PATH=`ls -l /$VOLUME_MEDIATYPE/$DEVICE|\ cut -d '>' -f2` VOLUME_DEVICE=`mount -p|grep $VOLUME_PATH|\ cut -d ' ' -f1` fi fi if [ -d "$VOLUME_PATH" ]; then VOLUME_ACTION=eject # Do the actual unmount. # VOLUME_* environment variables are inputs to rmmount. rmmount_msg="`/usr/sbin/rmmount 2>&1`" rmmount_status="$?" # Remove symbolic links to mount point for name in /$VOLUME_MEDIATYPE/*; do if [ -h $name ]; then target=`ls -l $name | awk '{ print $NF; }'` target_dir=`dirname $target` target_device=`echo $target_dir | \ sed -e 's/^.*-\(.*\)$/\1/'` if [ "$target_device" = "$DEVICE" ]; then rm -f $name fi fi done else rmmount_status=0 fi case $rmmount_status in 1) # still mounted error_exit $DEVICE "Error unmounting $DEVICE" "$rmmount_msg";; 0) # not mounted # Eject the media if [ "$FLAG" = "f" ] ; then eject_msg="`eject -f $DEVICE 2>&1`" else eject_msg="`eject $DEVICE 2>&1`" fi eject_status="$?" case $eject_status in 0|1|4) # Media has been ejected case $VOLUME_MEDIATYPE in floppy|cdrom|rmdisk) msg "Please remove the disk from $DEVICE.";; esac;; 3) # Media didn't eject msg $DEVICE "Error ejecting disk from $DEVICE" \ "$eject_msg";; esac esac } # # Reclaim a device # do_init() { eject_msg="`eject -f $DEVICE 2>&1`" eject_status="$?" case $eject_status in 0) # Media has been ejected if [ "$silent" != "y" ]; then ok_msg fi exit 0;; 1) # Media not ejected if [ "$silent" != "y" ]; then error_msg fi exit 0;; 3) # Error if [ "$silent" != "y" ]; then error_msg fi msg $DEVICE "Error ejecting disk from $DEVICE" \ "$eject_msg" exit 2;; esac } # #################################################### # ################ Begin main program ################ # #################################################### trap "" INT TERM QUIT TSTP ABRT PATH="/usr/bin:/usr/sbin" MODE="allocate" SILENT=n WDWMSG="/etc/security/lib/wdwmsg" VOLUME_ZONE_PATH="/" USAGE="Usage: disk_clean [-s|-f|-i|-I] devicename -[A|D] [username] [zonename] [zonepath]" EXIT_STATUS=0 CLEAN_MOUNT=4 MACH=`uname -p` FLAG=i # # Parse the command line arguments # while getopts ifsI c do case $c in i) FLAG=$c;; f) FLAG=$c;; s) FLAG=$c;; I) FLAG=i silent=y;; \?) echo $USAGE exit 1;; esac done shift `expr $OPTIND - 1` DEVICE=$1 MODE="deallocate" if [ "$2" = "-A" ]; then MODE="allocate" elif [ "$2" = "-D" ]; then MODE="deallocate" fi #get the device_maps information MAP=`/usr/sbin/list_devices -s -l $DEVICE` FILES=`echo $MAP | cut -f4 -d:` # e.g., /dev/dsk/c0t6d0s0 /dev/dsk/c0t6d0s1 ... DEVFILE=`echo $FILES | cut -f1 -d" "` # e.g., "/dev/dsk/c0t6d0s0" # Set VOLUME_ variables that are inputs to rmmount VOLUME_DEVICE=`echo $FILES | cut -f2 -d" "` # e.g., "/dev/dsk/c0t6d0s1" MEDIATYPE=`echo $MAP | cut -f3 -d: | cut -f2 -d" "` # e.g., "cdrom" or "floppy" if [ "$MEDIATYPE" = "sr" ]; then VOLUME_MEDIATYPE="cdrom" elif [ "$MEDIATYPE" = "fd" ]; then VOLUME_MEDIATYPE="floppy" elif [ "$MEDIATYPE" = "rmdisk" ]; then VOLUME_MEDIATYPE="rmdisk" fi VOLUME_PATH=$DEVFILE # e.g., "/dev/dsk/c0t6d0s0" if [ "$MACH" = "i386" ] && [ "$MEDIATYPE" = "rmdisk" ]; then VOLUME_PATH=`echo $DEVFILE | sed -e 's/s0/p0/'` fi SYMDEV=`echo $DEVICE | sed -e 's/_//'` # e.g., "cdrom" or "floppy" SYMNUM=`echo $SYMDEV | sed -e 's/[a-z]*//g'` SYMDEV=`echo $SYMDEV | sed -e 's/[0-9]*//g'` if [ "$SYMDEV" = "sr" ]; then VOLUME_SYMDEV="cdrom"$SYMNUM elif [ "$SYMDEV" = "fd" ]; then VOLUME_SYMDEV="floppy"$SYMNUM elif [ "$SYMDEV" = "rmdisk" ]; then VOLUME_SYMDEV="rmdisk"$SYMNUM else VOLUME_SYMDEV=$SYMDEV$SYMNUM fi VOLUME_ZONE_NAME=$4 VOLUME_ZONE_PATH=$5 if [ "$MODE" = "allocate" ]; then if [ -n "$3" ]; then # e.g., "joeuser" VOLUME_USER=$3 else VOLUME_USER=`/usr/xpg4/bin/id -u -nr` fi else # If there's a directory for the device under /, get the # user name from there, to use in cleaning up that directory. Otherwise, # the user name isn't actually used in deallocation. if [ -d ${VOLUME_ZONE_PATH}/${VOLUME_MEDIATYPE}/*-${DEVICE} ]; then VOLUME_USER=`ls -ld ${VOLUME_ZONE_PATH}/${VOLUME_MEDIATYPE}/*-${DEVICE} | awk '/^d/{print $3}'` else if [ -n "$3" ]; then VOLUME_USER=$3 else VOLUME_USER=`/usr/xpg4/bin/id -u -nr` fi fi fi VOLUME_NAME=unnamed_${VOLUME_MEDIATYPE} # e.g., "joeuser-cdrom0/unnamed_cdrom" if [ "$VOLUME_MEDIATYPE" = "rmdisk" ]; then VOLUME_PCFS_ID=1 else VOLUME_PCFS_ID= fi export VOLUME_ACTION VOLUME_DEVICE VOLUME_MEDIATYPE VOLUME_NAME VOLUME_PCFS_ID export VOLUME_PATH VOLUME_SYMDEV VOLUME_USER VOLUME_ZONE_NAME VOLUME_ZONE_PATH USERDIR=${VOLUME_USER}-${DEVICE} # e.g., "joeusr-cdrom0" msg_init if [ "$MODE" = "allocate" ]; then MSGDEV=tty do_allocate else if [ "$FLAG" = "i" ] ; then MSGDEV=console do_init else MSGDEV=tty do_deallocate fi fi exit $EXIT_STATUS