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