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