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