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