1 #
   2 # CDDL HEADER START
   3 #
   4 # The contents of this file are subject to the terms of the
   5 # Common Development and Distribution License (the "License").
   6 # You may not use this file except in compliance with the License.
   7 #
   8 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9 # or http://www.opensolaris.org/os/licensing.
  10 # See the License for the specific language governing permissions
  11 # and limitations under the License.
  12 #
  13 # When distributing Covered Code, include this CDDL HEADER in each
  14 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15 # If applicable, add the following below this CDDL HEADER, with the
  16 # fields enclosed by brackets "[]" replaced with your own identifying
  17 # information: Portions Copyright [yyyy] [name of copyright owner]
  18 #
  19 # CDDL HEADER END
  20 #
  21 #
  22 # Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  23 # Use is subject to license terms.
  24 #
  25 
  26 unset LD_LIBRARY_PATH
  27 PATH=/usr/bin:/usr/sbin
  28 export PATH
  29 
  30 . /usr/lib/brand/shared/common.ksh
  31 
  32 # Values for service tags.
  33 STCLIENT=/usr/bin/stclient
  34 ST_PRODUCT_NAME="Solaris 10 Containers"
  35 ST_PRODUCT_REV="1.0"
  36 ST_PRODUCT_UUID="urn:uuid:2f459121-dec7-11de-9af7-080020a9ed93"
  37 
  38 w_sanity_detail=$(gettext "       WARNING: Skipping image sanity checks.")
  39 f_sanity_detail=$(gettext  "Missing %s at %s")
  40 f_sanity_sparse=$(gettext  "Is this a sparse zone image?  The image must be whole-root.")
  41 f_sanity_vers=$(gettext  "The image release version must be 10 (got %s), the zone is not usable on this system.")
  42 f_not_s10_image=$(gettext  "%s doesn't look like a Solaris 10 image.")
  43 f_sanity_nopatch=$(gettext "Unable to determine the image's patch level.")
  44 f_sanity_downrev=$(gettext "The image patch level is downrev for running in a solaris10 branded zone.\n(patchlist %s)")
  45 f_need_newer_emul=$(gettext "The image requires a newer version of the solaris10 brand emulation.")
  46 f_zfs_create=$(gettext "Unable to create the zone's ZFS dataset.")
  47 f_no_ds=$(gettext "No zonepath dataset; the zonepath must be a ZFS dataset.")
  48 f_multiple_ds=$(gettext "Multiple active datasets.")
  49 f_no_active_ds=$(gettext "No active dataset; the zone's ZFS root dataset must be configured as\n\ta zone boot environment.")
  50 f_zfs_unmount=$(gettext "Unable to unmount the zone's root ZFS dataset (%s).\nIs there a global zone process inside the zone root?\nThe current zone boot environment will remain mounted.\n")
  51 f_zfs_mount=$(gettext "Unable to mount the zone's ZFS dataset.")
  52 incompat_options=$(gettext "mutually exclusive options.\n%s")
  53 
  54 sanity_ok=$(gettext     "  Sanity Check: Passed.  Looks like a Solaris 10 image.")
  55 sanity_fail=$(gettext   "  Sanity Check: FAILED (see log for details).")
  56 
  57 e_badboot=$(gettext "Zone boot failed")
  58 e_nosingleuser=$(gettext "ERROR: zone did not finish booting to single-user.")
  59 e_unconfig=$(gettext "sys-unconfig failed")
  60 v_unconfig=$(gettext "Performing zone sys-unconfig")
  61 
  62 v_no_tags=$(gettext "Service tags facility not present.")
  63 e_bad_uuid=$(gettext "Failed to get zone UUID")
  64 v_addtag=$(gettext "Adding service tag: %s")
  65 v_deltag=$(gettext "Removing service tag: %s")
  66 e_addtag_fail=$(gettext "Adding service tag failed (error: %s)")
  67 
  68 sanity_check()
  69 {
  70         typeset dir="$1"
  71         res=0
  72 
  73         #
  74         # Check for some required directories and make sure this isn't a
  75         # sparse zone image.
  76         #
  77         checks="etc etc/svc var var/svc"
  78         for x in $checks; do
  79                 if [[ ! -e $dir/$x ]]; then
  80                         log "$f_sanity_detail" "$x" "$dir"
  81                         res=1
  82                 fi
  83         done
  84         # Files from SUNWcsr and SUNWcsu that are in sparse inherit-pkg-dirs.
  85         checks="lib/svc sbin/zonename usr/bin/chmod"
  86         for x in $checks; do
  87                 if [[ ! -e $dir/$x ]]; then
  88                         log "$f_sanity_detail" "$x" "$dir"
  89                         log "$f_sanity_sparse"
  90                         res=1
  91                 fi
  92         done
  93 
  94         if (( $res != 0 )); then
  95                 log "$sanity_fail"
  96                 fatal "$install_fail" "$ZONENAME"
  97         fi
  98 
  99         if [[ "$SANITY_SKIP" == 1 ]]; then
 100                 log "$w_sanity_detail"
 101                 return
 102         fi
 103 
 104         #
 105         # Check image release to be sure its S10.
 106         #
 107         image_vers="unknown"
 108         if [[ -f $dir/var/sadm/system/admin/INST_RELEASE ]]; then
 109                 image_vers=$(nawk -F= '{if ($1 == "VERSION") print $2}' \
 110                     $dir/var/sadm/system/admin/INST_RELEASE)
 111         fi
 112 
 113         if [[ "$image_vers" != "10" ]]; then
 114                 log "$f_sanity_vers" "$image_vers"
 115                 res=1
 116         fi
 117 
 118         #
 119         # Make sure we have the minimal KU patch we support.  These are the
 120         # KUs for S10u8.
 121         #
 122         if [[ $(uname -p) == "i386" ]]; then
 123                 req_patch="141445-09"
 124         else
 125                 req_patch="141444-09"
 126         fi
 127 
 128         for i in $dir/var/sadm/pkg/SUNWcakr*
 129         do
 130                 if [[ ! -d $i || ! -f $i/pkginfo ]]; then
 131                         log "$f_sanity_nopatch"
 132                         res=1
 133                 fi
 134         done
 135 
 136         #
 137         # Check the core kernel pkg for the required KU patch.
 138         #
 139         found=0
 140         for i in $dir/var/sadm/pkg/SUNWcakr*/pkginfo
 141         do
 142                 patches=$(nawk -F= '{if ($1 == "PATCHLIST") print $2}' $i)
 143                 for patch in $patches
 144                 do
 145                         if [[ $patch == $req_patch ]]; then
 146                                 found=1
 147                                 break
 148                         fi
 149                 done
 150 
 151                 if (( $found == 1 )); then
 152                         break
 153                 fi
 154         done
 155 
 156         if (( $found != 1 )); then
 157                 log "$f_sanity_downrev" "$patches"
 158                 res=1
 159         fi
 160 
 161         #
 162         # Check the S10 image for a required version of the emulation.
 163         #
 164         VERS_FILE=/usr/lib/brand/solaris10/version
 165         s10vers_needs=0
 166         if [[ -f $dir/$VERS_FILE ]]; then
 167                 s10vers_needs=$(/usr/bin/egrep -v "^#" $dir/$VERS_FILE)
 168         fi
 169 
 170         # Now get the current emulation version.
 171         emul_vers=$(/usr/bin/egrep -v "^#" $VERS_FILE)
 172 
 173         # Verify that the emulation can run this version of S10.
 174         if (( $s10vers_needs > $emul_vers )); then
 175                 log "$f_need_newer_emul"
 176                 res=1
 177         fi
 178 
 179         if (( $res != 0 )); then
 180                 log "$sanity_fail"
 181                 fatal "$install_fail" "$ZONENAME"
 182         fi
 183 
 184         vlog "$sanity_ok"
 185 }
 186 
 187 # Find the active dataset under the zonepath dataset to mount on zonepath/root.
 188 # $1 ZONEPATH_DS
 189 get_active_ds() {
 190         ACTIVE_DS=$1/ROOT/zbe-0
 191 }
 192 
 193 #
 194 # Make sure the active dataset is mounted for the zone.
 195 #
 196 mount_active_ds() {
 197         get_zonepath_ds $zonepath
 198         get_active_ds $ZONEPATH_DS
 199 
 200         # If already mounted then we're done.
 201         mnted=`zfs get -H mounted $ACTIVE_DS | cut -f3`
 202         [[ $mnted = "yes" ]] && return
 203 
 204         mount -F zfs $ACTIVE_DS $zonepath/root || fail_fatal "$f_zfs_mount"
 205 }
 206 
 207 #
 208 # Set up ZFS dataset hierarchy for the zone root dataset.
 209 #
 210 create_active_ds() {
 211         # Find the zone's current dataset.  This should have been created by
 212         # zoneadm (or the attach hook).
 213         get_zonepath_ds $zonepath
 214 
 215         #
 216         # We need to tolerate errors while creating the datasets and making the
 217         # mountpoint, since these could already exist from an attach scenario.
 218         #
 219 
 220         /usr/sbin/zfs list -H -o name $ZONEPATH_DS/ROOT >/dev/null 2>&1
 221         if (( $? != 0 )); then
 222                 /usr/sbin/zfs create -o mountpoint=legacy -o zoned=on \
 223                     $ZONEPATH_DS/ROOT
 224                 if (( $? != 0 )); then
 225                         fail_fatal "$f_zfs_create"
 226                 fi
 227         else
 228                 /usr/sbin/zfs set mountpoint=legacy $ZONEPATH_DS/ROOT \
 229                     >/dev/null 2>&1
 230                 /usr/sbin/zfs set zoned=on $ZONEPATH_DS/ROOT \
 231                     >/dev/null 2>&1
 232         fi
 233 
 234         get_active_ds $ZONEPATH_DS
 235         zfs list -H -o name $ACTIVE_DS >/dev/null 2>&1
 236         if (( $? != 0 )); then
 237                 zfs create -o canmount=noauto $ACTIVE_DS
 238                 (( $? != 0 )) && fail_fatal "$f_zfs_create"
 239         else
 240                 zfs set canmount=noauto $ACTIVE_DS >/dev/null 2>&1
 241                 zfs inherit mountpoint $ACTIVE_DS >/dev/null 2>&1
 242                 zfs inherit zoned $ACTIVE_DS >/dev/null 2>&1
 243         fi
 244 
 245         if [ ! -d $ZONEROOT ]; then
 246                 /usr/bin/mkdir -m 0755 -p $ZONEROOT || \
 247                     fail_fatal "$f_mkdir" "$ZONEROOT"
 248         fi
 249         /usr/bin/chmod 700 $ZONEPATH || fail_fatal "$f_chmod" "$ZONEPATH"
 250 
 251         mount -F zfs $ACTIVE_DS $ZONEROOT || fail_fatal "$f_zfs_mount"
 252 }
 253 
 254 #
 255 # Before booting the zone we may need to create a few mnt points, just in
 256 # case they don't exist for some reason.
 257 #
 258 # Whenever we reach into the zone while running in the global zone we
 259 # need to validate that none of the interim directories are symlinks
 260 # that could cause us to inadvertently modify the global zone.
 261 #
 262 mk_zone_dirs() {
 263         vlog "$v_mkdirs"
 264         if [[ ! -f $ZONEROOT/tmp && ! -d $ZONEROOT/tmp ]]; then
 265                 mkdir -m 1777 -p $ZONEROOT/tmp || exit $EXIT_CODE
 266         fi
 267         if [[ ! -f $ZONEROOT/var/run && ! -d $ZONEROOT/var/run ]]; then
 268                 mkdir -m 1755 -p $ZONEROOT/var/run || exit $EXIT_CODE
 269         fi
 270         if [[ ! -f $ZONEROOT/var/tmp && ! -d $ZONEROOT/var/tmp ]]; then
 271                 mkdir -m 1777 -p $ZONEROOT/var/tmp || exit $EXIT_CODE
 272         fi
 273         if [[ ! -h $ZONEROOT/etc && ! -f $ZONEROOT/etc/mnttab ]]; then
 274                 /usr/bin/touch $ZONEROOT/etc/mnttab || exit $EXIT_CODE
 275                 /usr/bin/chmod 444 $ZONEROOT/etc/mnttab || exit $EXIT_CODE
 276         fi
 277         if [[ ! -f $ZONEROOT/proc && ! -d $ZONEROOT/proc ]]; then
 278                 mkdir -m 755 -p $ZONEROOT/proc || exit $EXIT_CODE
 279         fi
 280         if [[ ! -f $ZONEROOT/dev && ! -d $ZONEROOT/dev ]]; then
 281                 mkdir -m 755 -p $ZONEROOT/dev || exit $EXIT_CODE
 282         fi
 283         if [[ ! -h $ZONEROOT/etc && ! -h $ZONEROOT/etc/svc && \
 284             ! -d $ZONEROOT/etc/svc ]]; then
 285                 mkdir -m 755 -p $ZONEROOT/etc/svc/volatile || exit $EXIT_CODE
 286         fi
 287 }
 288 
 289 #
 290 # We're sys-unconfig-ing the zone.  This will normally halt the zone, however
 291 # there are problems with sys-unconfig and it can hang when the zone is booted
 292 # to milestone=none.  Sys-unconfig also sometimes hangs halting the zone.
 293 # Thus, we take some care to workaround these sys-unconfig limitations.
 294 #
 295 # On entry we expect the zone to be booted.  We use sys-unconfig -R to make it
 296 # think its working on an alternate root and let the caller halt the zone.
 297 #
 298 sysunconfig_zone() {
 299         /usr/sbin/zlogin -S $ZONENAME /usr/sbin/sys-unconfig -R /./ \
 300             >/dev/null 2>&1
 301         if (( $? != 0 )); then
 302                 error "$e_unconfig"
 303                 return 1
 304         fi
 305 
 306         return 0
 307 }
 308 
 309 #
 310 # Get zone's uuid for service tag.
 311 #
 312 get_inst_uuid()
 313 {
 314         typeset ZONENAME="$1"
 315 
 316         ZONEUUID=`zoneadm -z $ZONENAME list -p | nawk -F: '{print $5}'`
 317         [[ $? -ne 0 || -z $ZONEUUID ]] && return 1
 318 
 319         INSTANCE_UUID="urn:st:${ZONEUUID}"
 320         return 0
 321 }
 322 
 323 #
 324 # Add a service tag for a given zone.  We use two UUIDs-- the first,
 325 # the Product UUID, comes from the Sun swoRDFish ontology.  The second
 326 # is the UUID of the zone itself, which forms the instance UUID.
 327 #
 328 add_svc_tag()
 329 {
 330         typeset ZONENAME="$1"
 331         typeset SOURCE="$2"
 332 
 333         if [ ! -x $STCLIENT ]; then
 334                 vlog "$v_no_tags"
 335                 return 0
 336         fi
 337 
 338         get_inst_uuid "$ZONENAME" || (error "$e_bad_uuid"; return 1)
 339 
 340         vlog "$v_addtag" "$INSTANCE_UUID"
 341         $STCLIENT -a \
 342             -p "$ST_PRODUCT_NAME" \
 343             -e "$ST_PRODUCT_REV" \
 344             -t "$ST_PRODUCT_UUID" \
 345             -i "$INSTANCE_UUID" \
 346             -P "none" \
 347             -m "Sun" \
 348             -A `uname -p` \
 349             -z "$ZONENAME" \
 350             -S "$SOURCE" >/dev/null 2>&1
 351 
 352         err=$?
 353 
 354         # 226 means "duplicate record," which we can ignore.
 355         if [[ $err -ne 0 && $err -ne 226 ]]; then
 356                 error "$e_addtag_fail" "$err" 
 357                 return 1
 358         fi
 359         return 0
 360 }
 361 
 362 #
 363 # Remove a service tag for a given zone.
 364 #
 365 del_svc_tag()
 366 {
 367         typeset ZONENAME="$1"
 368 
 369         if [ ! -x $STCLIENT ]; then
 370                 vlog "$v_no_tags"
 371                 return 0
 372         fi
 373 
 374         get_inst_uuid "$ZONENAME" || (error "$e_bad_uuid"; return 1)
 375 
 376         vlog "$v_deltag" "$INSTANCE_UUID"
 377         $STCLIENT -d -i "$INSTANCE_UUID" >/dev/null 2>&1
 378         return 0
 379 }