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