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