1 #!/sbin/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 # 23 # Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. 24 # Copyright 2015 Nexenta Systems, Inc. All rights reserved. 25 # 26 27 . /lib/svc/share/fs_include.sh 28 . /lib/svc/share/net_include.sh 29 30 # Make sure that the essential libraries can be found. 31 LD_LIBRARY_PATH=/lib; export LD_LIBRARY_PATH 32 STMSBOOTUTIL=/lib/mpxio/stmsboot_util 33 SAVEDIR=/etc/mpxio 34 BOOTDEVICES=$SAVEDIR/boot-devices 35 RECOVERFILE=$SAVEDIR/recover_instructions 36 DEVFSADM=/usr/sbin/devfsadm 37 DUMPADM=/usr/sbin/dumpadm 38 METADEVADM=/usr/sbin/metadevadm 39 ISROOTDEV="" 40 ISROOTDEVPATH="" 41 usrmounted=0 42 UNAME=/usr/bin/uname 43 ECHO=/usr/bin/echo 44 CAT=/usr/bin/cat 45 CP=/usr/bin/cp 46 DF=/usr/bin/df 47 LS=/usr/bin/ls 48 RM=/usr/bin/rm 49 EGREP=/usr/bin/egrep 50 SED=/usr/bin/sed 51 ZPOOL=/usr/sbin/zpool 52 AWK=/usr/bin/awk 53 MOUNT=/sbin/mount 54 UMOUNT=/sbin/mount 55 EEPROM=/usr/sbin/eeprom 56 BOOTADM=/usr/sbin/bootadm 57 SVCADM=/usr/sbin/svcadm 58 REBOOT=/usr/sbin/reboot 59 60 mpxio_error() 61 { 62 cecho "\nERROR: stmsboot: $1" 63 # 64 # display recovery instructions - the first call logs to the service 65 # log and the second call displays on the console. 66 # 67 shcat $RECOVERFILE 68 shcat $RECOVERFILE >/dev/msglog 2>&1 69 cecho "These instructions were also logged to the file $RECOVERFILE\n" 70 } 71 72 # 73 # root ("/") is already mounted read only by the kernel. 74 # Remount the root read-write. 75 # 76 mpxio_mount_root() 77 { 78 HASZFSROOT=`$DF -g / |grep zfs` 79 RVAL="" 80 81 # In single-user maintenance mode, we don't have a writable 82 # root partition, so we _cannot_ use devlinks. Therefore we 83 # have to do some dancing - first mount the physical path 84 # read-write, then re-run $STMSBOOTUTIL to get the real 85 # devlink mapping, and then re-mount the root slice. Of course, 86 # if we all used ZFS this wouldn't be such a pain! 87 exec < $vfstab; readvfstab / 88 # ZFS root environments should _not_ have an entry for / 89 # in their /etc/vfstab. 90 if [ -n "$special" ]; then 91 # sanity check for ZFSRoot _and_ / in /etc/vfstab 92 if [ -n "$HASZFSROOT" ]; then 93 # ERROR - this would cause a failure later 94 # so let root know about it now and provide 95 # a chance to handle it before filesystem/usr 96 cecho "stmsboot: System has ZFS Root *and* an entry for / in /etc/vfstab\nstmsboot: Please remove the / entry from /etc/vfstab and then run\n# svcadm clear mpxio-upgrade" 97 exit 1 98 fi 99 ISPHYS=`echo $special |$AWK '/^\/dev\/dsk/ {print}'`; 100 if [ -z "$ISPHYS" ]; then 101 # a metadevice, either /dev/md or /dev/vx 102 new_special=$special 103 $MOUNT -o remount,rw $new_special / >/dev/msglog 2>&1 104 else 105 new_special=`$STMSBOOTUTIL -m $special` 106 if [ "$new_special" = "NOT_MAPPED" ]; then 107 # this is a bad state to be in, exit 108 cecho "Error: Your root device is not mapped." 109 exit 1 110 fi 111 checkopt "llock" $mntopts 112 mntopts='remount' 113 [ -n "$otherops" ] && mntopts="${mntopts},${otherops}" 114 RVAL=`$MOUNT -m -F $fstype -o $mntopts $new_special \ 115 $mountp >/dev/msglog 2>&1` 116 # if we've got active-active paths to our rootvp and 117 # the first path returned by $STMSBOOTUTIL is not the 118 # same as the one we booted from, then we need some 119 # handwaving due to restrictions in the ufs module 120 # (see the remountfs() function in 121 # $SRC/uts/common/fs/ufs/ufs_vfsops.c) 122 if [ $? -eq 0 ]; then 123 # now re-run $STMSBOOTUTIL to get the real 124 # mapping for this device 125 new_special=`$STMSBOOTUTIL -m $special` 126 # mount root for real 127 $MOUNT -o remount,rw $new_special / \ 128 >/dev/msglog 2>&1 129 else 130 for device in `$CAT $BOOTDEVICES`; do 131 new_special="/devices${device}" 132 $MOUNT -m -F $fstype -o $mntopts \ 133 $new_special $mountp >/dev/msglog 2>&1 134 if [ $? -eq 0 ]; then 135 # success, break out 136 ISROOTDEVPATH=`$ECHO $device | \ 137 $AWK -F":" '{print $1}'` 138 break; 139 fi 140 done 141 if [ -n "$RVAL" ]; then 142 cecho "Error: Unable to remount your root device" 143 exit 1; 144 fi 145 fi 146 fi 147 else 148 if [ -z "$HASZFSROOT" ]; then 149 cecho "stmsboot: Error: your root slice is invalid" 150 exit 1 151 else 152 cecho "stmsboot: Root is on ZFS" 153 fi 154 fi 155 } 156 157 # 158 # mount /usr read only 159 # 160 mpxio_mount_usr() 161 { 162 exec < $vfstab; readvfstab "/usr" 163 ret_val=0 164 if [ -n "$mountp" ]; then 165 case "$special" in 166 /dev/md/*) 167 new_special=$special 168 ;; 169 /dev/vx/*) 170 new_special=$special 171 ;; 172 *) 173 new_special=`$STMSBOOTUTIL -m $special` 174 ;; 175 esac 176 177 # 178 # Must use -o largefiles here to ensure the read-only 179 # mount does not fail as a result of having a large 180 # file present on /usr. 181 # 182 if [ "$mntopts" = "-" ]; then 183 mntopts='ro,largefiles' 184 else 185 checkopt largefiles $mntopts 186 if [ "$option" != "largefiles" ]; then 187 mntopts="largefiles,$mntopts" 188 fi 189 190 checkopt ro $mntopts 191 if [ "$option" != "ro" ]; then 192 mntopts="ro,$mntopts" 193 fi 194 195 # Requesting logging on a read-only mount 196 # causes errors to be displayed, so remove 197 # "logging" from the list of options. 198 checkopt logging $mntopts 199 if [ "$option" = "logging" ]; then 200 mntopts="$otherops" 201 fi 202 fi 203 204 # In case of a manual restart of the service, mount 205 # will emit messages if /usr is already mounted. 206 # So redirect the output to /dev/null. 207 $MOUNT -m -F $fstype -o $mntopts $new_special /usr \ 208 >/dev/null 2>&1 209 ret_val=$? 210 if [ $ret_val -eq 0 ]; then 211 usrmounted=1 212 fi 213 fi 214 215 return $ret_val 216 } 217 218 # update system dump configuration 219 update_dumpconf() 220 { 221 # Disable device-in-use checking (done in libdiskmgt). 222 # Without disabling this check, the configuration of dump device 223 # would fail as the device-in-use code incorrectly concludes that 224 # the device is in use and hence prevents configuration of the dump 225 # device. 226 NOINUSE_CHECK=1 227 export NOINUSE_CHECK 228 229 DUMPISZFS=`$AWK -F"=" '/DUMPADM_DEVICE/ {print $2}' /etc/dumpadm.conf|$EGREP zvol` 230 if [ -z "$DUMPISZFS" ]; then 231 set -- `$DUMPADM -u 2>&1 | $EGREP 'cannot use /dev.* as dump device'` 232 if [ -n "$4" ]; then 233 newname=`$STMSBOOTUTIL -m $4` 234 if [ $? -eq 0 ]; then 235 if $DUMPADM -d $newname > /dev/msglog 2> /dev/console; then 236 cecho "stmsboot: dump configuration \ 237 has been updated." 238 else 239 mpxio_error "failed to configure \ 240 the dump device.\nold \ 241 dump device name: $4" 242 return 1 243 fi 244 fi 245 fi 246 else 247 # make sure we can get to it, force zfs to load fully 248 $LS $DUMPISZFS >>/dev/null 2>&1 249 cecho "stmsboot: dump on ZFS, no dumpadm update required" 250 fi 251 return 0 252 } 253 254 # Update bootpath for x86 here when we are enabling mpxio on root 255 update_bootpath() 256 { 257 cur_bootpath=`$STMSBOOTUTIL -b` 258 if [ $? -ne 0 ]; then 259 cecho "stmsboot: ERROR! Unable to retrieve bootpath property\n" 260 exit 1 261 fi 262 263 # Since on x64 platforms the eeprom command doesn't update the 264 # kernel, the file /boot/solaris/bootenv.rc and the kernel's 265 # bootpath variable have a good chance of differing. We do some 266 # extra handwaving to get the correct bootpath variable setting. 267 268 ONDISKVER=`$AWK '/bootpath/ {print $3}' /boot/solaris/bootenv.rc|\ 269 $SED -e"s,',,g"` 270 if [ "$ONDISKVER" != "$cur_bootpath" ]; then 271 cur_bootpath="$ONDISKVER" 272 fi 273 274 NEWBOOTPATH="" 275 for path in $cur_bootpath; do 276 mapped=`$STMSBOOTUTIL -p $path` 277 if [ "$mapped" != "NOT_MAPPED" ]; then 278 if [ "$mapped" != "$path" ]; then 279 NEWBOOTPATH=`echo "$path " | \ 280 $SED -e"s|$path|$mapped|"`" $NEWBOOTPATH" 281 else 282 NEWBOOTPATH="$NEWBOOTPATH $path" 283 fi 284 fi 285 done 286 # now strip off leading and trailing space chars 287 new_bootpath=`echo $NEWBOOTPATH` 288 $EEPROM bootpath="$new_bootpath" 289 cecho "stmsboot: bootpath has been updated" 290 cecho "" 291 } 292 293 # Now do the actual work 294 mpxio_main() 295 { 296 # NOTE: If the first attempt to run the service has failed due to an 297 # expected error, users should be able to manually rerun the service. 298 # 299 # First mount /usr read only. This must be done to run 300 # utilities such as fsck and devfsadm. 301 # In the case of a manual rerun of the service, mounting of /usr here 302 # fails if /usr already happens to be mounted. It is better that we 303 # do not mount /usr if already mounted, but there seems to be no 304 # apparent way to check whether /usr is mounted or not as we mount 305 # /usr without making an entry into /etc/mnttab. So instead of 306 # explicitly checking for mount failures, we just do a sanity check 307 # by looking for some file (in this case devfsadm) in /usr. 308 # 309 mpxio_mount_usr 310 if [ ! -s $DEVFSADM ]; then 311 mpxio_error "failed to mount the /usr filesystem." 312 return 313 fi 314 315 if mpxio_mount_root; then 316 # create /dev links 317 cecho "stmsboot: configuring devices" 318 $DEVFSADM 319 320 if [ -n "$ISROOTDEVPATH" ]; then 321 ISROOTDEV=`$STMSBOOTUTIL -o $ISROOTDEVPATH` 322 fi 323 324 # update /etc/vfstab to reflect device name changes 325 $STMSBOOTUTIL -u >/dev/msglog 2>&1 326 if [ $? -eq 0 ]; then 327 $CP /etc/vfstab /etc/vfstab.old 328 # handle active-active paths, where the probe order 329 # for the hba reports a different path to what the 330 # boot-device variable gives us 331 if [ -n "$ISROOTDEV" ]; then 332 ROOTDEVCHK=`grep $ISROOTDEV /etc/vfstab` 333 if [ $? -ne 0 ]; then 334 # we got a different path for root 335 exec < $SAVEDIR/vfstab.new; readvfstab / 336 FILEDEV=`$ECHO $special | \ 337 $SED -e"s,/dev/dsk/,," -e"s,s[0-9]*,,"` 338 $SED -e"s,$FILEDEV,$ISROOTDEV,g" < \ 339 $SAVEDIR/vfstab.new > /etc/vfstab 340 fi 341 else 342 $CP $SAVEDIR/vfstab.new /etc/vfstab 343 fi 344 $RM $SAVEDIR/vfstab.new 345 cecho "" 346 cecho "stmsboot: vfstab has been updated" 347 348 if update_dumpconf; then 349 # update svm configuration to reflect new names 350 if [ -s /kernel/drv/md.conf ] && \ 351 [ -x $METADEVADM ]; then 352 $METADEVADM -r >/dev/msglog 2>&1 353 fi 354 fi 355 356 MACH=`$UNAME -p` 357 if [ "$MACH" = "i386" ]; then 358 # only update bootpath here for x86 359 update_bootpath 360 fi 361 cecho "stmsboot: now regenerating boot archive" 362 $BOOTADM update-archive 363 else 364 mpxio_error "failed to update /etc/vfstab." 365 fi 366 367 $SVCADM disable system/device/mpxio-upgrade 368 369 if [ $usrmounted -eq 1 ]; then 370 cecho "stmsboot: rebooting the system now." 371 $REBOOT 372 fi 373 else 374 mpxio_error "failed to mount the root filesystem." 375 fi 376 } 377 378 mpxio_main