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