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