Home | History | Annotate | Download | only in allocate
      1 #! /usr/bin/sh
      2 #
      3 # CDDL HEADER START
      4 #
      5 # The contents of this file are subject to the terms of the
      6 # Common Development and Distribution License (the "License").
      7 # You may not use this file except in compliance with the License.
      8 #
      9 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
     10 # or http://www.opensolaris.org/os/licensing.
     11 # See the License for the specific language governing permissions
     12 # and limitations under the License.
     13 #
     14 # When distributing Covered Code, include this CDDL HEADER in each
     15 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     16 # If applicable, add the following below this CDDL HEADER, with the
     17 # fields enclosed by brackets "[]" replaced with your own identifying
     18 # information: Portions Copyright [yyyy] [name of copyright owner]
     19 #
     20 # CDDL HEADER END
     21 #
     22 # Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
     23 # Use is subject to license terms.
     24 #
     25 #
     26 # ident	"%Z%%M%	%I%	%E% SMI"
     27 #
     28 #
     29 # This is a clean script for removable disks
     30 # 
     31 # Following is the syntax for calling the script:
     32 #	scriptname [-s|-f|-i|-I] devicename [-A|-D] username zonename zonepath
     33 #
     34 #    	-s for standard cleanup by a user
     35 # 	-f for forced cleanup by an administrator
     36 # 	-i for boot-time initialization (when the system is booted with -r) 
     37 # 	-I to suppress error/warning messages; the script is run in the '-i'
     38 #	   mode
     39 #
     40 # $1:	devicename - device to be allocated/deallocated, e.g., sr0
     41 #
     42 # $2:	-A if cleanup is for allocation, or -D if cleanup is for deallocation.
     43 #
     44 # $3:	username - run the script as this user, rather than as the caller.
     45 #
     46 # $4:	zonename - zone in which device to be allocated/deallocated
     47 #
     48 # $5:	zonepath - root path of zonename
     49 #
     50 # A clean script for a removable media device should prompt the user to 
     51 # insert correctly labeled media at allocation time, and ensure that the
     52 # media is ejected at deallocation time.
     53 #
     54 # Unless the clean script is being called for boot-time
     55 # initialization, it may communicate with the user via stdin and
     56 # stdout.  To communicate with the user via CDE dialogs, create a
     57 # script or link with the same name, but with ".windowing" appended.
     58 # For example, if the clean script specified in device_allocate is
     59 # /etc/security/xyz_clean, that script must use stdin/stdout.  If a
     60 # script named /etc/security/xyz_clean.windowing exists, it must use
     61 # dialogs.  To present dialogs to the user, the dtksh script
     62 # /etc/security/lib/wdwmsg may be used.
     63 #
     64 # This particular script, disk_clean, will work using stdin/stdout, or
     65 # using dialogs.  A symbolic link disk_clean.windowing points to
     66 # disk_clean.
     67 #
     68  
     69 # ####################################################
     70 # ################  Local Functions  #################
     71 # ####################################################
     72  
     73 #
     74 # Set up for windowing and non-windowing messages
     75 #
     76 msg_init()
     77 {
     78     if [ `basename $0` != `basename $0 .windowing` ]; then
     79 	WINDOWING="yes"
     80 	case $VOLUME_MEDIATYPE in
     81 	  cdrom)   TITLE="CD-ROM";;
     82 	  rmdisk)  TITLE="Removable Disk";;
     83 	  floppy)  TITLE="Floppy";;
     84 	  *)       TITLE="Disk";;
     85 	esac
     86 	
     87 	if [ "$MODE" = "allocate" ]; then
     88 	    TITLE="$TITLE Allocation"
     89 	else
     90 	    TITLE="$TITLE Deallocation"
     91 	fi
     92     else
     93 	WINDOWING="no"
     94     fi
     95 }
     96 
     97 #
     98 # Display a message for the user.  For windowing, user must press OK button 
     99 # to continue. For non-windowing, no response is required.
    100 #
    101 msg() {
    102     if [ "$WINDOWING" = "yes" ]; then
    103 	$WDWMSG "$*" "$TITLE" OK
    104     elif [ "$silent" != "y" ]; then
    105 	echo "$*" > /dev/${MSGDEV}
    106     fi
    107 }
    108 
    109 ok_msg() {
    110 	if [ "$WINDOWING" = "yes" ]; then
    111 		$WDWMSG "$*" "$TITLE" READY
    112 	else
    113 		form=`gettext "Media in %s is ready. Please store safely."`
    114 		printf "${form}\n" $PROG $DEVICE > /dev/{MSGDEV}
    115 	fi
    116 }
    117 
    118 error_msg() {
    119 	if [ "$WINDOWING" = "yes" ]; then
    120 		$WDWMSG "$*" "$TITLE" ERROR
    121 	else
    122 		form=`gettext "%s: Error cleaning up device %s."`
    123 		printf "${form}\n" $PROG $DEVICE > /dev/${MSGDEV}
    124 	fi
    125 }
    126 
    127 #
    128 # Ask the user an OK/Cancel question.  Return 0 for OK, 1 for Cancel.
    129 #
    130 okcancel() {
    131     if [ "$WINDOWING" = "yes" ]; then
    132 	$WDWMSG "$*" "$TITLE" OK Cancel
    133     elif [ "$silent" != "y" ]; then
    134 	get_reply "$* (y to continue, n to cancel) \c" y n
    135     fi
    136 }
    137 
    138 #
    139 # Ask the user an Yes/No question.  Return 0 for Yes, 1 for No
    140 #
    141 yesno() {
    142     if [ "$WINDOWING" = "yes" ]; then
    143 	$WDWMSG "$*" "$TITLE" Yes No
    144     elif [ "$silent" != "y" ]; then
    145 	get_reply "$* (y/n) \c" y n
    146     fi
    147 }
    148 
    149 #
    150 # Display an error message, put the device in the error state, and exit.
    151 #
    152 error_exit() {
    153 	if [ "$silent" != "y" ]; then
    154 		msg "$2" "$3" \
    155 		    "\n\nDevice has been placed in allocation error state." \
    156 		    "\nPlease inform system administrator."
    157 	fi
    158 	exit 1
    159 }
    160 
    161 #
    162 # get_reply prompt choice ...
    163 #
    164 get_reply() {
    165 	prompt=$1; shift
    166 	while true
    167 	do
    168 		echo $prompt > /dev/tty
    169 		read reply
    170 		i=0
    171 		for choice in $*
    172 		do
    173 			if [ "$choice" = "$reply" ]
    174 			then
    175 				return $i
    176 			else
    177 				i=`expr $i + 1`
    178 			fi
    179 		done
    180 	done
    181 }
    182 
    183 #
    184 # Find the first disk slice containing a HSFS file system
    185 #
    186 find_fs()
    187 {
    188 	for DEVn in $FILES ; do
    189 		x="`labelit -F hsfs $DEVn 2>&1| grep 'Volume id'`"
    190 		if [ $? = 0 ]; then
    191 			FSPATH=$DEVn
    192 			if [ "$x" != "" ]; then
    193 				y="`echo $x|cut -f3- -d' '|\
    194 				    /usr/xpg4/bin/tr '[:upper:] ' '[:lower:]_'`"
    195 				FSNAME=$y
    196 			fi
    197 			return
    198 		fi
    199 	done
    200 }
    201 
    202 #
    203 # Find all mountpoints in use for a set of device special files.
    204 # Usage: findmounts devpath ...
    205 #
    206 
    207 findmounts() {
    208 	nawk -f - -v vold_root="$VOLD_ROOT" -v devs="$*" /etc/mnttab <<\
    209 	    "ENDOFAWKPGM"
    210 	BEGIN {
    211 		split(devs, devlist, " ");
    212 		for (devN in devlist) {
    213 			dev = devlist[devN];
    214 			realdevlist[dev] = 1;
    215 			sub(/.*\//, "", dev);
    216 			sub(/s[0-9]$/, "", dev);
    217 			if (vold_root != "") {
    218 				vold_dir[vold_root "/dev/dsk/" dev] = 1;
    219 				vold_dir[vold_root "/dev/rdsk/" dev] = 1;
    220 			}
    221 		}
    222 	}
    223 
    224 	{
    225 		for (dev in realdevlist) {
    226 			if ($1 == dev) {
    227 				mountpoint = $2;
    228 				print mountpoint;
    229 			}
    230 		}
    231 		for (dev in vold_dir) {
    232 			if (substr($1, 1, length(dev)) == dev) {
    233 				mountpoint = $2;
    234 				print mountpoint;
    235 			}
    236 		}
    237 	}
    238 ENDOFAWKPGM
    239 }
    240 
    241 #
    242 # Allocate a device.
    243 # Ask the user to make sure the disk is properly labeled.
    244 # Ask if the disk should be mounted.
    245 #
    246 do_allocate()
    247 {
    248 	if [ $VOLUME_MEDIATYPE = floppy ]; then
    249 		# Determine if media is in drive
    250 		eject_msg="`eject -q $DEVFILE 2>&1`"
    251 		eject_status="$?"
    252 		case $eject_status in
    253 		1) # Media is not in drive
    254 			okcancel "Insert disk in $DEVICE."
    255 			if [ $? != 0 ]; then
    256 				exit 0
    257 			fi;;
    258 		3) # Error 
    259 			error_exit $DEVICE \
    260 			    "Error checking for media in drive.";;
    261 		esac
    262 	else
    263 		okcancel "Insert disk in $DEVICE."
    264 		if [ $? != 0 ]; then
    265 			exit 0
    266 		fi
    267 	fi
    268     
    269 	yesno "Do you want $DEVICE mounted?"
    270 	if [ $? != 0 ]; then
    271 		exit 0
    272 	fi
    273 
    274 	if [ $VOLUME_MEDIATYPE = cdrom -o $VOLUME_MEDIATYPE = rmdisk ]; then
    275 		# Get the device path and volume name of a partition
    276 		find_fs
    277 		if [ "$FSPATH" != "" ]; then
    278 			VOLUME_PATH=$FSPATH	
    279 		fi
    280 		if [ "$FSNAME" != "" ]; then
    281 			VOLUME_NAME=$FSNAME
    282 		fi
    283 	fi
    284 	VOLUME_ACTION=insert
    285 
    286 	# Give ourself write permission on device file so file system gets
    287 	# mounted read/write if possible.
    288 	# rmmount only cares about permissions not user...
    289 	chown $VOLUME_USER $VOLUME_PATH
    290 	chmod 700 $VOLUME_PATH
    291 
    292 	# Do the actual mount.  VOLUME_* environment variables are inputs to
    293 	# rmmount.
    294 	rmmount_msg="`/usr/sbin/rmmount 2>&1`"
    295 	rmmount_status="$?"
    296 	if [ $rmmount_status -eq 0 ]; then
    297 		EXIT_STATUS=$CLEAN_MOUNT
    298 	elif [ $rmmount_status -gt 0 -a $VOLUME_MEDIATYPE != cdrom ]; then
    299 		# Try again in readonly mode. cdrom is always mounted ro, so
    300 		# no need to try again.
    301 		echo "Read-write mount of $DEVICE failed. Mounting read-only."
    302 		VOLUME_ACTION=remount; export VOLUME_ACTION
    303 		VOLUME_MOUNT_MODE=ro; export VOLUME_MOUNT_MODE
    304 		`/usr/sbin/rmmount`
    305 		if [ $? -eq 0 ]; then
    306 			EXIT_STATUS=$CLEAN_MOUNT
    307 		fi
    308 	fi
    309 
    310 	# Set permissions on directory used by vold, sdtvolcheck, etc.
    311 	if [ -d /tmp/.removable ]; then
    312 		chown root /tmp/.removable
    313 		chmod 777 /tmp/.removable
    314 	fi
    315 }
    316 
    317 
    318 do_deallocate()
    319 {
    320 	if [ $VOLUME_MEDIATYPE = cdrom -o $VOLUME_MEDIATYPE = rmdisk ]; then
    321 		# Get the device path and volume name of a partition
    322 		find_fs
    323 		if [ "$FSPATH" != "" ]; then
    324 			VOLUME_PATH=$FSPATH	
    325 		fi
    326 		if [ "$FSNAME" != "" ]; then
    327 			VOLUME_NAME=$FSNAME
    328 		fi
    329 	fi
    330 	VOLUME_ACTION=eject
    331 
    332 	# Do the actual unmount.  VOLUME_* environment variables are inputs to
    333 	# rmmount.
    334 	rmmount_msg="`/usr/sbin/rmmount 2>&1`"
    335 	rmmount_status="$?"
    336 
    337 	# Remove symbolic links to mount point
    338 	for name in $VOLUME_ZONE_PATH/$VOLUME_MEDIATYPE/*; do
    339 		if [ -h $name ]; then
    340 			target=`ls -l $name | awk '{ print $NF; }'`
    341 			target_dir=`dirname $target`
    342 			target_device=`echo $target_dir | \
    343 			    sed -e 's/^.*-\(.*\)$/\1/'`
    344 			if [ "$target_device" = "$DEVICE" ]; then
    345 				rm -f $name
    346 			fi
    347 		fi
    348 	done
    349 
    350 	case $rmmount_status in
    351 	1) # still mounted
    352 		error_exit $DEVICE "Error unmounting $DEVICE" "$rmmount_msg";;
    353 	0) # not mounted
    354 		# Eject the media
    355 		if [ "$FLAG" = "f" ] ; then
    356 			eject_msg="`eject -f $DEVFILE 2>&1`"
    357 		else
    358 			eject_msg="`eject $DEVFILE 2>&1`"
    359 		fi
    360 		eject_status="$?"
    361 		case $eject_status in
    362 		0|4) # Media has been ejected
    363 			case $VOLUME_MEDIATYPE in
    364 			floppy|cdrom|rmdisk)
    365 				msg "Please remove the disk from $DEVICE.";;
    366 			esac;;
    367 		1|3) # Media didn't eject
    368 			EXIT_STATUS=2
    369 			msg $DEVICE "Error ejecting disk from $DEVICE" \
    370 			"$eject_msg";;
    371 		esac
    372 	esac
    373 }
    374 
    375 #
    376 # Reclaim a device
    377 #
    378 do_init()
    379 {
    380 	eject_msg="`eject -f $DEVFILE 2>&1`"
    381 	eject_status="$?"
    382 
    383 	case $eject_status in
    384 	0) # Media has been ejected 
    385 		if [ "$silent" != "y" ]; then
    386 			ok_msg
    387 		fi
    388 		exit 0;;
    389 	1) # Media not ejected
    390 		if [ "$silent" != "y" ]; then
    391 			error_msg
    392 		fi
    393 		exit 0;;
    394 	3) # Error 
    395 		if [ "$silent" != "y" ]; then
    396 			error_msg
    397 		fi
    398 		msg $DEVICE "Error ejecting disk from $DEVICE" \
    399 		    "$eject_msg"
    400 		exit 2;;
    401 	esac
    402 }
    403 
    404 
    405 # ####################################################
    406 # ################ Begin main program ################
    407 # ####################################################
    408 
    409 trap "" INT TERM QUIT TSTP ABRT
    410 
    411 PATH="/usr/bin:/usr/sbin"
    412 MODE="allocate"
    413 SILENT=n
    414 WDWMSG="/etc/security/lib/wdwmsg"
    415 VOLUME_ZONE_PATH="/"
    416 USAGE="Usage: disk_clean [-s|-f|-i|-I] devicename -[A|D] [username] [zonename] [zonepath]"
    417 EXIT_STATUS=0
    418 CLEAN_MOUNT=4
    419 MACH=`uname -p`
    420 FLAG=i
    421 #
    422 # Parse the command line arguments
    423 #
    424 while getopts ifsI c
    425 do
    426 	case $c in
    427 	i)
    428 		FLAG=$c;;
    429 	f)
    430 		FLAG=$c;;
    431 	s)
    432 		FLAG=$c;;
    433 	I)
    434 		FLAG=i
    435 		silent=y;;
    436 	\?)
    437 		echo $USAGE
    438 		exit 1;;
    439       esac
    440 done
    441 
    442 shift `expr $OPTIND - 1`
    443 
    444 DEVICE=$1
    445 MODE="deallocate"
    446 if [ "$2" = "-A" ]; then
    447 	MODE="allocate"
    448 elif [ "$2" = "-D" ]; then
    449 	MODE="deallocate"
    450 fi
    451 
    452 #get the device_maps information
    453 MAP=`/usr/sbin/list_devices -s -l $DEVICE`
    454 FILES=`echo $MAP | cut -f4 -d:`	# e.g., /dev/dsk/c0t6d0s0 /dev/dsk/c0t6d0s1 ...
    455 DEVFILE=`echo $FILES | cut -f1 -d" "` 		# e.g., "/dev/dsk/c0t6d0s0"
    456 
    457 # Set VOLUME_ variables that are inputs to rmmount
    458 
    459 VOLUME_DEVICE=`echo $FILES | cut -f2 -d" "` 	# e.g., "/dev/dsk/c0t6d0s1"
    460 MEDIATYPE=`echo $MAP | cut -f3 -d: | cut -f2 -d" "`
    461 					 	# e.g., "cdrom" or "floppy"
    462 if [ "$MEDIATYPE" = "sr" ]; then
    463 	VOLUME_MEDIATYPE="cdrom"
    464 elif [ "$MEDIATYPE" = "fd" ]; then
    465 	VOLUME_MEDIATYPE="floppy"
    466 elif [ "$MEDIATYPE" = "rmdisk" ]; then
    467 	VOLUME_MEDIATYPE="rmdisk"
    468 fi
    469 
    470 VOLUME_PATH=$DEVFILE				# e.g., "/dev/dsk/c0t6d0s0"
    471 if [ "$MACH" = "i386" ] && [ "$MEDIATYPE" = "rmdisk" ]; then
    472 	VOLUME_PATH=`echo $DEVFILE | sed -e 's/s0/p0/'`
    473 fi
    474 
    475 SYMDEV=`echo $DEVICE | sed -e 's/_//'`		# e.g., "cdrom" or "floppy"
    476 SYMNUM=`echo $SYMDEV | sed -e 's/[a-z]*//g'`
    477 SYMDEV=`echo $SYMDEV | sed -e 's/[0-9]*//g'`
    478 if [ "$SYMDEV" = "sr" ]; then
    479 	VOLUME_SYMDEV="cdrom"$SYMNUM
    480 elif [ "$SYMDEV" = "fd" ]; then
    481 	VOLUME_SYMDEV="floppy"$SYMNUM
    482 elif [ "$SYMDEV" = "rmdisk" ]; then
    483 	VOLUME_SYMDEV="rmdisk"$SYMNUM
    484 else
    485 	VOLUME_SYMDEV=$SYMDEV$SYMNUM
    486 fi
    487 
    488 VOLUME_ZONE_NAME=$4
    489 
    490 VOLUME_ZONE_PATH=$5
    491 
    492 if [ "$MODE" = "allocate" ]; then
    493 	if [ -n "$3" ]; then			# e.g., "joeuser"
    494 		VOLUME_USER=$3
    495 	else
    496 		VOLUME_USER=`/usr/xpg4/bin/id -u -nr`
    497 	fi
    498 else
    499 	# If there's a directory for the device under /<mediatype>, get the 
    500 	# user name from there, to use in cleaning up that directory. Otherwise,
    501 	# the user name isn't actually used in deallocation.
    502 	if [ -d ${VOLUME_ZONE_PATH}/${VOLUME_MEDIATYPE}/*-${DEVICE} ]; then
    503 		VOLUME_USER=`ls -ld ${VOLUME_ZONE_PATH}/${VOLUME_MEDIATYPE}/*-${DEVICE} | awk '/^d/{print $3}'`
    504 	else
    505 		if [ -n "$3" ]; then
    506 			VOLUME_USER=$3
    507 		else
    508 			VOLUME_USER=`/usr/xpg4/bin/id -u -nr`
    509 		fi
    510 	fi
    511 fi    
    512 
    513 VOLUME_NAME=unnamed_${VOLUME_MEDIATYPE}
    514 					# e.g., "joeuser-cdrom0/unnamed_cdrom"
    515 
    516 if [ "$VOLUME_MEDIATYPE" = "rmdisk" ]; then
    517 	VOLUME_PCFS_ID=c
    518 else
    519 	VOLUME_PCFS_ID=
    520 fi
    521 
    522 export VOLUME_ACTION VOLUME_DEVICE VOLUME_MEDIATYPE VOLUME_NAME VOLUME_PCFS_ID
    523 export VOLUME_PATH VOLUME_SYMDEV VOLUME_USER VOLUME_ZONE_NAME VOLUME_ZONE_PATH
    524 
    525 USERDIR=${VOLUME_USER}-${DEVICE}	# e.g., "joeusr-cdrom0"
    526 
    527 msg_init
    528 
    529 if [ "$MODE" = "allocate" ]; then
    530 	MSGDEV=tty
    531   	do_allocate
    532 else
    533     if [ "$FLAG" = "i" ] ; then
    534 	MSGDEV=console
    535 	do_init
    536     else
    537 	MSGDEV=tty
    538 	do_deallocate
    539     fi
    540 fi
    541 
    542 exit $EXIT_STATUS
    543