1 #!/bin/ksh
   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 # Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
  23 #
  24 
  25 # 0a  Initialization.
  26 
  27 [ -f /lib/svc/share/smf_include.sh ] || exit 1
  28 
  29 . /lib/svc/share/smf_include.sh
  30 
  31 activity=false
  32 
  33 EMI_SERVICE="svc:/system/early-manifest-import:default"
  34 PROFILE_DIR_SITE="/etc/svc/profile/site"
  35 
  36 X=
  37 ALT_REPOSITORY=
  38 ALT_MFST_DIR=
  39 early=false
  40 [ "$SMF_FMRI" == "$EMI_SERVICE" ] && early=true
  41 
  42 usage()
  43 {
  44         echo "Usage: /lib/svc/method/manifest-import [-n]" \
  45             "[-f repository-file -d manifest-directory]"
  46         echo "\nOptions:"
  47         echo "-n dryrun"
  48         echo "-f and -d specify alternate repository and" \
  49             "manifest directory for import\n"
  50         exit 2
  51 }
  52 
  53 while getopts "nd:f:" opt; do
  54         case $opt in
  55                 n)      X=echo;;
  56                 d)      ALT_MFST_DIR=$OPTARG;;
  57                 f)      ALT_REPOSITORY=$OPTARG;;
  58                 ?)      usage;;
  59         esac
  60 done
  61 
  62 #
  63 # Both -f and -d options must be specified together or not specified at all
  64 #
  65 [ -n "$ALT_REPOSITORY" -a -z "$ALT_MFST_DIR" ] && usage
  66 [ -n "$ALT_MFST_DIR" -a -z "$ALT_REPOSITORY" ] && usage
  67 
  68 function svccfg_apply {
  69         $X /usr/sbin/svccfg apply $1
  70         if [ $? -ne 0 ]; then
  71                 echo "WARNING: svccfg apply $1 failed" | tee /dev/msglog
  72         fi
  73 }
  74 
  75 #
  76 # If the smf/manifest table has file entries that are missing
  77 # then there is work to be done by the cleanup process.
  78 #
  79 function cleanup_needwork {
  80         if [ "$early" == true ]; then
  81                 smfmfiles=`/usr/bin/svcprop smf/manifest | \
  82                     awk '(/^lib_/ && /\/manifestfile /) {print $3}'`
  83         else
  84                 smfmfiles=`/usr/bin/svcprop smf/manifest | \
  85                     awk '/\/manifestfile / {print $3}'`
  86         fi
  87 
  88         nw=`/lib/svc/bin/mfstscan $smfmfiles 2>&1 1>/dev/null`
  89         [ "$nw" ] && return 1
  90 
  91         return 0
  92 }
  93 
  94 #
  95 # Upon upgrading to early manifest import code, preserve hashes of system
  96 # profiles which lived under /var/svc/profile so that svccfg apply would
  97 # not re-apply the profiles and overwrite user customizations. Simply 
  98 # migrate manifestfile and hash values to new property groups named after
  99 # profiles under /etc/svc/profile. If the profiles don't really exist,
 100 # svccfg cleanup will remove the property groups in a later step.
 101 # 
 102 # Existing generic.xml, inetd_services.xml, and name_service.xml symlinks
 103 # need to be preserved.
 104 #
 105 # Don't process site.xml profile since it is still supported under
 106 # /var/svc/profile directory.
 107 #
 108 function preserve_system_profiles {
 109 
 110         #
 111         # If /var is a separate fs, return and let Late Import
 112         # preserves the hashes.
 113         #       
 114         [ -d "/var/svc/profile" ] || return 1
 115 
 116         #
 117         # Preserve hashes for the following profiles: generic (two
 118         # cases) and platform (uname -i, uname -m outputs).
 119         #
 120         gn="var_svc_profile_generic_open_xml"
 121         gh=`/usr/bin/svcprop -p ${gn}/md5sum smf/manifest 2>/dev/null`
 122         [ $? = 0 ] || gh=""
 123         gn="etc_svc_profile_generic_open_xml"
 124 
 125         gln="var_svc_profile_generic_limited_net_xml"
 126         glh=`/usr/bin/svcprop -p ${gln}/md5sum smf/manifest 2>/dev/null`
 127         [ $? = 0 ] || glh=""
 128         gln="etc_svc_profile_generic_limited_net_xml"
 129 
 130         LC_ALL=C pl=`/usr/bin/uname -i | /usr/bin/tr , _`
 131         pln="var_svc_profile_platform_${pl}_xml"
 132         plh=`/usr/bin/svcprop -p ${pln}/md5sum smf/manifest 2>/dev/null`
 133         [ $? = 0 ] || plh=""
 134         pln="etc_svc_profile_platform_${pl}_xml"
 135 
 136         LC_ALL=C plm=`/usr/bin/uname -m | /usr/bin/tr , _`
 137         if [ $plm != $pl ]; then
 138                 plmn="var_svc_profile_platform_${plm}_xml"
 139                 plmh=`/usr/bin/svcprop -p ${plmn}/md5sum smf/manifest \
 140                     2>/dev/null`
 141                 [ $? = 0 ] || plmh=""
 142                 plmn="etc_svc_profile_platform_${plm}_xml"
 143         else
 144                 plmh=""
 145         fi
 146 
 147         [ -n "$gh" ] && {
 148                 echo "Preserving generic hash ($gh)."
 149                 /usr/sbin/svccfg -s smf/manifest addpg ${gn} framework
 150                 /usr/sbin/svccfg -s smf/manifest setprop ${gn}/md5sum = \
 151                     opaque: $gh
 152                 /usr/sbin/svccfg -s smf/manifest setprop ${gn}/manifestfile = \
 153                     astring: "/etc/svc/profile/generic.xml"
 154         }
 155         [ -n "$glh" ] && {
 156                 echo "Preserving generic_limited hash ($glh)."
 157                 /usr/sbin/svccfg -s smf/manifest addpg ${gln} framework
 158                 /usr/sbin/svccfg -s smf/manifest setprop ${gln}/md5sum = \
 159                     opaque: $glh
 160                 /usr/sbin/svccfg -s smf/manifest setprop ${gln}/manifestfile = \
 161                     astring: "/etc/svc/profile/generic.xml"
 162         }
 163         [ -n "$plh" ] && {
 164                 echo "Preserving platform hash ($plh)."
 165                 /usr/sbin/svccfg -s smf/manifest addpg $pln framework
 166                 /usr/sbin/svccfg -s smf/manifest setprop $pln/md5sum = \
 167                     opaque: $plh
 168                 /usr/sbin/svccfg -s smf/manifest setprop ${pln}/manifestfile = \
 169                     astring: "/etc/svc/profile/platform_${pl}_xml"
 170         }
 171         [ -n "$plmh" ] && {
 172                 echo "Preserving platform hash ($plmh)."
 173                 /usr/sbin/svccfg -s smf/manifest addpg $plmn framework
 174                 /usr/sbin/svccfg -s smf/manifest setprop $plmn/md5sum = \
 175                     opaque: $plmh
 176                 /usr/sbin/svccfg -s smf/manifest setprop \
 177                     ${plmn}/manifestfile = \
 178                     astring: "/etc/svc/profile/platform_${plm}_xml"
 179         }
 180 
 181         #
 182         # Move symlinks from /var/svc/profile to /etc/svc/profile
 183         #
 184         generic_prof="/var/svc/profile/generic.xml"
 185         ns_prof="/var/svc/profile/name_service.xml"
 186         inetd_prof="/var/svc/profile/inetd_services.xml"
 187         platform_prof="/var/svc/profile/platform.xml"
 188         [ -L "$generic_prof" ] && mv $generic_prof /etc/svc/profile/
 189         [ -L "$ns_prof" ] && mv $ns_prof /etc/svc/profile/
 190         [ -L "$inetd_prof" ] && mv $inetd_prof /etc/svc/profile/
 191         [ -L "$platform_prof" ] && mv $platform_prof /etc/svc/profile/
 192 
 193         return 0
 194 }
 195 
 196 #
 197 # 2.  Manifest import.  Application directories first, then
 198 # site-specific manifests.
 199 #
 200 function import_manifests {
 201         typeset basedir=$1
 202         typeset console_print=$2
 203         typeset logf="/etc/svc/volatile/manifest_import.$$"
 204 
 205         rm -f $logf
 206 
 207         nonsite_dirs=`/usr/bin/find $basedir/* -name site \
 208             -prune -o -type d -print -prune`
 209 
 210         if [ -n "$_MFST_DEBUG" ]; then
 211                 nonsite_manifests=`/lib/svc/bin/mfstscan $nonsite_dirs`
 212                 site_manifests=`/lib/svc/bin/mfstscan $basedir/site`
 213 
 214                 manifests="$nonsite_manifests $site_manifests"
 215 
 216                 echo "Changed manifests to import:"
 217                 for m in $manifests; do echo "  $m"; done
 218         fi
 219 
 220         #
 221         # Upon boot, attempt to move the repository to tmpfs.
 222         #
 223         if [ -z "$ALT_REPOSITORY" -a -z "$ALT_MFST_DIR" ]; then 
 224                 /usr/sbin/svcadm _smf_repository_switch fast
 225         fi
 226 
 227         #
 228         # Import the manifests while giving a running display of imports on
 229         # console, and a final count in the logfile.
 230         #
 231         dirs="$nonsite_dirs"
 232         [ -d "$basedir/site" ] && dirs="$dirs $basedir/site"
 233 
 234         if [ "$console_print" = "true" ]; then
 235                 $X /usr/sbin/svccfg import -p /dev/msglog $dirs > $logf 2>&1
 236         else
 237                 $X /usr/sbin/svccfg import $dirs > $logf 2>&1
 238         fi
 239 
 240         grep "Loaded .*. smf(5) service descriptions" $logf > /dev/null 2>&1
 241         if [ $? -eq 0 ]; then
 242                 activity=true
 243         fi
 244 
 245         if [ -s $logf ]; then
 246                 grep "smf(5) service descriptions failed to load" $logf > /dev/null 2>&1
 247                 failures=$?
 248                 if [ $failures -eq 0 ]; then
 249                         echo "svccfg warnings:"
 250                 fi
 251                 cat $logf
 252 
 253                 if [ $failures -eq 0 -a "$console_print" = "true" ]; then
 254                         msg="svccfg import warnings.  See"
 255                         msg="$msg /var/svc/log/system-manifest-import:default.log ."
 256                         echo $msg > /dev/msglog
 257                 fi
 258         fi
 259         rm -f $logf
 260 }
 261 
 262 #
 263 # 3.  Profile application.  We must create the platform profile upon
 264 # first boot, as we may be a diskless client of a platform or
 265 # architecture distinct from our NFS server.
 266 #
 267 # Generic and platform profiles are only supported in /etc.
 268 #
 269 function apply_profile {
 270         #
 271         # If smf/manifest doesn't have any profile under /etc/var/profile,
 272         # this is very likely an import after upgrade so call
 273         # preserve_system_profiles in that case.
 274         #
 275         LC_ALL=C pl=`/usr/bin/uname -i | /usr/bin/tr , _`
 276         pln="etc_svc_profile_platform_${pl}_xml"
 277 
 278         LC_ALL=C plm=`/usr/bin/uname -m | /usr/bin/tr , _`
 279         [ $plm != $pl ] && plmn="etc_svc_profile_platform_${plm}_xml"
 280 
 281         preserve_profiles=1
 282         for prof in $pln $plmn etc_svc_profile_platform_none_xml \
 283             etc_svc_profile_generic_limited_net_xml \
 284             etc_svc_profile_generic_open_xml; do
 285                 if /usr/bin/svcprop -p $prof smf/manifest >/dev/null 2>&1
 286                 then
 287                         preserve_profiles=0
 288                         break
 289                 fi
 290         done
 291 
 292         if [ $preserve_profiles -eq 1 ]; then
 293                 echo "/etc/svc system profiles not found: upgrade system profiles"
 294                 preserve_system_profiles || return
 295         fi
 296 
 297         typeset prefix="/etc/svc/profile"
 298         svccfg_apply $prefix/generic.xml
 299         if [ ! -f $prefix/platform.xml ]; then
 300                 this_karch=`uname -m`
 301                 this_plat=`uname -i`
 302 
 303                 if [ -f $prefix/platform_$this_plat.xml ]; then
 304                         platform_profile=platform_$this_plat.xml
 305                 elif [ -f $prefix/platform_$this_karch.xml ]; then
 306                         platform_profile=platform_$this_karch.xml
 307                 else
 308                         platform_profile=platform_none.xml
 309                 fi
 310 
 311                 ln -s $platform_profile $prefix/platform.xml
 312         fi
 313 
 314         svccfg_apply $prefix/platform.xml
 315 }
 316 
 317 #
 318 # 4.  Upgrade handling.  The upgrade file generally consists of a series
 319 # of svcadm(1M) and svccfg(1M) commands.
 320 #
 321 function handle_upgrade {
 322 
 323         [ -f /var/svc/profile/upgrade ] && activity=true
 324 
 325         (
 326                 unset SVCCFG_CHECKHASH
 327 
 328                 if [ -f /var/svc/profile/upgrade ]; then
 329                         . /var/svc/profile/upgrade
 330 
 331                         /usr/bin/mv /var/svc/profile/upgrade \
 332                             /var/svc/profile/upgrade.app.`date +\%Y\%m\%d\%H\%M\%S`
 333                 fi
 334 
 335                 #
 336                 # Rename the datalink upgrade script file. This script is used in the
 337                 # network/physical service to upgrade datalink configuration, but
 338                 # the file cannot be renamed until now (when the file system becomes
 339                 # read-write).
 340                 #
 341                 datalink_script=/var/svc/profile/upgrade_datalink
 342                 if [ -f "${datalink_script}" ]; then
 343                         /usr/bin/mv "${datalink_script}" \
 344                             "${datalink_script}".app.`date +\%Y\%m\%d\%H\%M\%S`
 345                 fi
 346         )
 347 }
 348 
 349 #
 350 # 5.  Giving administrator the final say, apply site.xml profile and profiles
 351 #     under /etc/svc/profile/site directory.
 352 #
 353 function apply_site_profile {
 354         typeset prefix="$1"
 355         [ -f $prefix/site.xml ] && svccfg_apply $prefix/site.xml
 356 
 357         if [ -d $PROFILE_DIR_SITE -a "$1" = "/etc/svc/profile" ]; then
 358                 svccfg_apply $PROFILE_DIR_SITE
 359         fi
 360 }
 361 
 362 #
 363 # 0b Cleanup deathrow
 364 #
 365 if [ "$early" = "false" ];then
 366         deathrow=/etc/svc/deathrow
 367         if [ -s $deathrow ];then
 368                 #
 369                 # svc.startd has unconfigured the services found in deathrow,
 370                 # clean them now.
 371                 #
 372                 while read fmri mfst pkgname; do
 373                         # Delete services and instances from the deathrow file.
 374                         /usr/sbin/svccfg delete -f $fmri >/dev/null 2>&1
 375                         # Remove deathrow manifest hash.
 376                         /usr/sbin/svccfg delhash -d $mfst >/dev/null 2>&1
 377                 done < $deathrow
 378                 /usr/bin/mv $deathrow $deathrow.old
 379         fi
 380 fi
 381 
 382 SVCCFG_CHECKHASH=1 export SVCCFG_CHECKHASH
 383 
 384 #
 385 # 0c Clean up repository
 386 #
 387 if [ "$early" = "false" ]; then
 388         if [ -z "$X" ] && /usr/bin/svcprop smf/manifest 2>/dev/null |
 389             /usr/bin/grep '^ar_svc_[^/]*/md5sum opaque ' >/dev/null
 390         then
 391                 set -- `
 392                         /usr/bin/svcprop smf/manifest 2>/dev/null |
 393                             /usr/bin/grep '^ar_svc[^/]*/md5sum opaque ' |
 394                             /usr/bin/tr '/' ' ' |
 395                             while read pg prop type value; do
 396                                 echo "$pg/$value"
 397                         done
 398                 `
 399                 backup=`echo "$#/$#" | sed 's/.//g'`
 400                 fwidth=`echo "$#\c" | wc -c`
 401 
 402                 echo "Converting obsolete repository entries: \c" > /dev/msglog
 403                 i=1; n=$#
 404                 while [ $# -gt 0 ]; do
 405                         printf "%${fwidth}s/%${fwidth}s" $i $n > /dev/msglog
 406                         echo $1 | sed 's:/: :' | (
 407                                 read pg value
 408 
 409                                 (echo "select /smf/manifest"; echo "delpg v$pg") |
 410                                     /usr/sbin/svccfg 2>/dev/null >/dev/null
 411                                 (echo "select /smf/manifest"; echo "delpg $pg") |
 412                                     /usr/sbin/svccfg 2>/dev/null >/dev/null
 413                                 (echo "select /smf/manifest";
 414                                     echo "addpg v$pg framework") |
 415                                     /usr/sbin/svccfg 2>/dev/null >/dev/null
 416                                 (echo "select /smf/manifest";
 417                                     echo "setprop v$pg/md5sum = opaque: $value") |
 418                                     /usr/sbin/svccfg 2>/dev/null >/dev/null
 419                         )
 420                         i=`expr $i + 1`
 421                         shift
 422                         echo "$backup\c" > /dev/msglog
 423                 done
 424                 echo > /dev/msglog
 425                 echo "Converted $n obsolete repository entries"
 426                 activity=true
 427         fi
 428 
 429 fi
 430 
 431 #
 432 # If the alternate repository and directory are specified, simply set
 433 # SVCCFG_REPOSITORY env, run svccfg import on the given directory, and
 434 # exit.
 435 #
 436 if [ -n "$ALT_REPOSITORY" -a -n "$ALT_MFST_DIR" ]; then 
 437         SVCCFG_REPOSITORY=$ALT_REPOSITORY export SVCCFG_REPOSITORY
 438         import_manifests "$ALT_MFST_DIR" false
 439         unset SVCCFG_REPOSITORY
 440         exit 0
 441 fi
 442 
 443 #
 444 # Call import and apply profiles here
 445 #
 446 if [ "$early" = "true" ]; then
 447         import_manifests "/lib/svc/manifest" true
 448         apply_profile
 449         apply_site_profile "/etc/svc/profile"
 450 else
 451         #
 452         # Process both /lib/svc/manifest and /var/svc/manifest
 453         # during late manifest-import
 454         #
 455         # First import the manifests
 456         #
 457         import_manifests "/lib/svc/manifest" true
 458         import_manifests "/var/svc/manifest" true
 459 
 460         #
 461         # Apply profiles
 462         #
 463         apply_profile
 464         apply_site_profile "/etc/svc/profile"
 465 
 466         #
 467         # Run the upgrade script
 468         #
 469         handle_upgrade
 470         apply_site_profile "/var/svc/profile"
 471 fi
 472 
 473 
 474 #
 475 # 6.  Final actions.
 476 #
 477 
 478 if $activity; then
 479         /usr/sbin/svcadm _smf_backup "manifest_import" || true
 480 fi
 481 
 482 #
 483 # If the filesystem is NOT read only then move the repo back to perm
 484 # There is no care wether the switch was made or not, but just want
 485 # to move it.  If it is already perm this does not affect anything
 486 # at least on the surface.  REALLY want to improve on this...
 487 #
 488 touch /etc/svc/smf_rwtest.$$ > /dev/null 2>&1
 489 if [ $? -eq 0 ]; then
 490         rm -f /etc/svc/smf_rwtest.$$
 491         /usr/sbin/svcadm _smf_repository_switch perm || { \
 492             echo "Repository switch back operation failed, \c"
 493             echo "please check the system log for the"
 494             echo "possible fatal error messages."
 495             exit $SMF_EXIT_ERR_FATAL
 496             }
 497 fi
 498 
 499 if $activity; then
 500         /usr/sbin/svccfg cleanup | /usr/bin/tee /dev/msglog
 501 else
 502         cleanup_needwork
 503         if [ $? -ne 0 ]; then
 504                 /usr/sbin/svccfg cleanup -a | /usr/bin/tee /dev/msglog
 505         fi
 506 fi
 507 
 508 exit 0