xref: /titanic_41/usr/src/cmd/stmsboot/mpxio-upgrade (revision 7fc66be0e007780898c439e8aa5cffb3fdaa08ea)
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 #
25 
26 . /lib/svc/share/fs_include.sh
27 . /lib/svc/share/net_include.sh
28 
29 # Make sure that the essential libraries can be found.
30 LD_LIBRARY_PATH=/lib; export LD_LIBRARY_PATH
31 STMSBOOTUTIL=/lib/mpxio/stmsboot_util
32 SAVEDIR=/etc/mpxio
33 BOOTDEVICES=$SAVEDIR/boot-devices
34 RECOVERFILE=$SAVEDIR/recover_instructions
35 DEVFSADM=/usr/sbin/devfsadm
36 DUMPADM=/usr/sbin/dumpadm
37 METADEVADM=/usr/sbin/metadevadm
38 ISROOTDEV=""
39 ISROOTDEVPATH=""
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 				for device in `$CAT $BOOTDEVICES`; do
130 					new_special="/devices${device}"
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 						ISROOTDEVPATH=`$ECHO $device | \
136 						$AWK -F":" '{print $1}'`
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 #
159 mpxio_mount_usr()
160 {
161 	exec < $vfstab; readvfstab "/usr"
162 	ret_val=0
163 	if [ -n "$mountp" ]; then
164 		case "$special" in
165 		/dev/md/*)
166 			new_special=$special
167 			;;
168 		/dev/vx/*)
169 			new_special=$special
170 			;;
171 		*)
172 			new_special=`$STMSBOOTUTIL -m $special`
173 			;;
174 		esac
175 
176 		if [ "$fstype" = "cachefs" ]; then
177 			# Mount read-only without the cache.
178 			case "$mntopts" in
179 			*backfstype=nfs*)
180 				cfsbacktype=nfs
181 				;;
182 			*backfstype=hsfs*)
183 				cfsbacktype=hsfs
184 				;;
185 			*)
186 				cecho 'stmsboot: invalid vfstab entry for /usr'
187 				cfsbacktype=nfs
188 				;;
189 			esac
190 			# see the comment below for /dev/null
191 			$MOUNT -m -F $cfsbacktype -o ro $new_special $mountp \
192 >/dev/null 2>&1
193 			ret_val=$?
194 		else
195 			#
196 			# Must use -o largefiles here to ensure the read-only
197 			# mount does not fail as a result of having a large
198 			# file present on /usr.
199 			#
200 			if [ "$mntopts" = "-" ]; then
201 				mntopts='ro,largefiles'
202 			else
203 				checkopt largefiles $mntopts
204 				if [ "$option" != "largefiles" ]; then
205 					mntopts="largefiles,$mntopts"
206 				fi
207 
208 				checkopt ro $mntopts
209 				if [ "$option" != "ro" ]; then
210 					mntopts="ro,$mntopts"
211 				fi
212 
213 				# Requesting logging on a read-only mount
214 				# causes errors to be displayed, so remove
215 				# "logging" from the list of options.
216 				checkopt logging $mntopts
217 				if [ "$option" = "logging" ]; then
218 					mntopts="$otherops"
219 				fi
220 			fi
221 
222 			# In case of a manual restart of the service, mount
223 			# will emit messages if /usr is already mounted.
224 			# So redirect the output to /dev/null.
225 			$MOUNT -m -F $fstype -o $mntopts $new_special /usr \
226 >/dev/null 2>&1
227 			ret_val=$?
228 		fi
229 		if [ $ret_val -eq 0 ]; then
230 			usrmounted=1
231 		fi
232 	fi
233 
234 	return $ret_val
235 }
236 
237 # update system dump configuration
238 update_dumpconf()
239 {
240 	# Disable device-in-use checking (done in libdiskmgt).
241 	# Without disabling this check, the configuration of dump device
242 	# would fail as the device-in-use code incorrectly concludes that
243 	# the device is in use and hence prevents configuration of the dump
244 	# device.
245 	NOINUSE_CHECK=1
246 	export NOINUSE_CHECK
247 
248 	DUMPISZFS=`$AWK -F"=" '/DUMPADM_DEVICE/ {print $2}' /etc/dumpadm.conf|$EGREP zvol`
249 	if [ -z "$DUMPISZFS" ]; then
250 		set -- `$DUMPADM -u 2>&1 | $EGREP 'cannot use /dev.* as dump device'`
251 		if [ -n "$4" ]; then
252 			newname=`$STMSBOOTUTIL -m $4`
253 			if [ $? -eq 0 ]; then
254 				if $DUMPADM -d $newname > /dev/msglog 2> /dev/console; then
255 					cecho "stmsboot: dump configuration \
256 					has been updated."
257 				else
258 					mpxio_error "failed to configure \
259 					the dump device.\nold \
260 					dump device name: $4"
261 					return 1
262 				fi
263 			fi
264 		fi
265 	else
266 		# make sure we can get to it, force zfs to load fully
267 		$LS $DUMPISZFS >>/dev/null 2>&1
268 		cecho "stmsboot: dump on ZFS, no dumpadm update required"
269 	fi
270 	return 0
271 }
272 
273 # Update bootpath for x86 here when we are enabling mpxio on root
274 update_bootpath()
275 {
276 	cur_bootpath=`$STMSBOOTUTIL -b`
277 	if [ $? -ne 0 ]; then
278 		cecho "stmsboot: ERROR! Unable to retrieve bootpath property\n"
279 		exit 1
280 	fi
281 
282 	# Since on x64 platforms the eeprom command doesn't update the
283 	# kernel, the file /boot/solaris/bootenv.rc and the kernel's
284 	# bootpath variable have a good chance of differing. We do some
285 	# extra handwaving to get the correct bootpath variable setting.
286 
287 	ONDISKVER=`$AWK '/bootpath/ {print $3}' /boot/solaris/bootenv.rc|\
288 		$SED -e"s,',,g"`
289 	if [ "$ONDISKVER" != "$cur_bootpath" ]; then
290 		cur_bootpath="$ONDISKVER"
291 	fi
292 
293 	NEWBOOTPATH=""
294 	for path in $cur_bootpath; do
295 		mapped=`$STMSBOOTUTIL -p $path`
296 		if [ "$mapped" != "NOT_MAPPED" ]; then
297 			if [ "$mapped" != "$path" ]; then
298 				NEWBOOTPATH=`echo "$path " | \
299 				    $SED -e"s|$path|$mapped|"`" $NEWBOOTPATH"
300 			else
301 				NEWBOOTPATH="$NEWBOOTPATH $path"
302 			fi
303 		fi
304 	done
305 	# now strip off leading and trailing space chars
306 	new_bootpath=`echo $NEWBOOTPATH`
307 	$EEPROM bootpath="$new_bootpath"
308 	cecho "stmsboot: bootpath has been updated"
309 	cecho ""
310 }
311 
312 # Now do the actual work
313 mpxio_main()
314 {
315 	# NOTE: If the first attempt to run the service has failed due to an
316 	# expected error, users should be able to manually rerun the service.
317 	#
318 	# First mount /usr read only. This must be done to run
319 	# utilities such as fsck and devfsadm.
320 	# In the case of a manual rerun of the service, mounting of /usr here
321 	# fails if /usr already happens to be mounted. It is better that we
322 	# do not mount /usr if already mounted, but there seems to be no
323 	# apparent way to check whether /usr is mounted or not as we mount
324 	# /usr without making an entry into /etc/mnttab. So instead of
325 	# explicitly checking for mount failures, we just do a sanity check
326 	# by looking for some file (in this case devfsadm) in /usr.
327 	#
328 	mpxio_mount_usr
329 	if [ ! -s $DEVFSADM ]; then
330 		mpxio_error "failed to mount the /usr filesystem."
331 		return
332 	fi
333 
334 	if mpxio_mount_root; then
335 		# create /dev links
336 		cecho "stmsboot: configuring devices"
337 		$DEVFSADM
338 
339 		if [ -n "$ISROOTDEVPATH" ]; then
340 			ISROOTDEV=`$STMSBOOTUTIL -o $ISROOTDEVPATH`
341 		fi
342 
343 		# update /etc/vfstab to reflect device name changes
344 		$STMSBOOTUTIL -u >/dev/msglog 2>&1
345 		if [ $? -eq 0 ]; then
346 			$CP /etc/vfstab /etc/vfstab.old
347 			# handle active-active paths, where the probe order
348 			# for the hba reports a different path to what the
349 			# boot-device variable gives us
350 			if [ -n "$ISROOTDEV" ]; then
351 				ROOTDEVCHK=`grep $ISROOTDEV /etc/vfstab`
352 				if [ $? -ne 0 ]; then
353 					# we got a different path for root
354 					exec < $SAVEDIR/vfstab.new; readvfstab /
355 					FILEDEV=`$ECHO $special | \
356 					    $SED -e"s,/dev/dsk/,," -e"s,s[0-9]*,,"`
357 					$SED -e"s,$FILEDEV,$ISROOTDEV,g" < \
358 					    $SAVEDIR/vfstab.new > /etc/vfstab
359 				fi
360 			else
361 				$CP $SAVEDIR/vfstab.new /etc/vfstab
362 			fi
363 			$RM $SAVEDIR/vfstab.new
364 			cecho ""
365 			cecho "stmsboot: vfstab has been updated"
366 
367 			if update_dumpconf; then
368 				# update svm configuration to reflect new names
369 				if [ -s /kernel/drv/md.conf ] && \
370 				    [ -x $METADEVADM ]; then
371 					$METADEVADM -r >/dev/msglog 2>&1
372 				fi
373 			fi
374 
375 			MACH=`$UNAME -p`
376 			if [ "$MACH" = "i386" ]; then
377 				# only update bootpath here for x86
378 				update_bootpath
379 			fi
380 			cecho "stmsboot: now regenerating boot archive"
381 			$BOOTADM update-archive
382 		else
383 			mpxio_error "failed to update /etc/vfstab."
384 		fi
385 
386 		$SVCADM disable system/device/mpxio-upgrade
387 
388 		if [ $usrmounted -eq 1 ]; then
389 			cecho "stmsboot: rebooting the system now."
390 			$REBOOT
391 		fi
392 	else
393 		mpxio_error "failed to mount the root filesystem."
394 	fi
395 }
396 
397 mpxio_main
398