#!/bin/ksh # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # [ -f /lib/svc/share/smf_include.sh ] || exit 1 . /lib/svc/share/smf_include.sh SVCADM=/usr/sbin/svcadm SVCCFG=/usr/sbin/svccfg SVCPROP=/bin/svcprop SVCS=/usr/bin/svcs MFSTPG=manifestfiles MFSTSCAN=/lib/svc/bin/mfstscan MCLEANUPFILE=/etc/svc/volatile/mcleanup.$$ IGNORELIST="system/install-discovery smf/manifest" MFSTHISTORY=/lib/svc/share/mfsthistory UPLIST=0 # # Create a list of service to manifest pairs for the upgrade # process to determine what files are associated with a service # function create_list { for cl_mfile in `find /var/svc/manifest -name "*.xml"` do for cl_invent in `svccfg inventory $cl_mfile` do cl_invent=${cl_invent#svc:/*} cl_instance=${cl_invent#*:} cl_instance=${cl_instance##*/*} [ $cl_instance ] && continue cl_invent=${cl_invent%:*} cl_invent=`echo $cl_invent | sed -e 's/[-\/\,]/_/g'` eval $cl_invent=\"\$$cl_invent $cl_mfile\" done done UPLIST=1 } # # Inventory the instances listed with a manifest file # function get_instances { gi_mfile=$1 lst="" for gi_invent in `svccfg inventory $gi_mfile` do gi_tmp=${gi_invent#svc:/*} gi_tmp=${gi_tmp#*:} gi_tmp=${gi_tmp##*/*} [ $gi_tmp ] && lst="$lst $gi_invent" done echo $lst } function pid_timeout { pt_pid=$1 pt_cnt=0 while [ `ps -p $pt_pid -o pid | grep -v PID` -a $pt_cnt -lt 30 ] do sleep 1 cnt=`expr $pt_cnt + 1` done if [ $pt_cnt -eq 30 -a "`ps -p $pt_pid -o pid | grep -v PID`" ]; then return 1 else return 0 fi } # # Process a service to ensure that it's manifests exist # and are in sync with the service. # function process_service { ps_service=$1 # # Throw away unsupported services, if there is a false listing # for manifestfiles support # $SVCPROP -p $MFSTPG/support $ps_service 2>/dev/null | grep false > /dev/null [ $? -eq 0 ] && return # # Create the list of instances for this service. # $SVCPROP -p $MFSTPG $ps_service > $MCLEANUPFILE set -A ps_mfiles `grep astring $MCLEANUPFILE | awk '{print $3}'` # # Check to see if the manifest files associated with the service are # missing, or if the manifest file has changed, either caught here # or by the caller. # ps_x=`$MFSTSCAN ${ps_mfiles[@]} 2>&1` if [ $? -eq 0 ]; then if [ "$force" != "true" -a ! "$ps_x" ]; then ps_ret=0 for ps_f in ${ps_mfiles[@]} do echo "$force" | grep -v $ps_f > /dev/null 2>&1 ps_ret=`expr $ps_ret + $?` done [ $ps_ret -eq 0 ] && return fi fi ps_refresh=0 ps_mfiles_tmp="" ps_mfiles_cnt=${#ps_mfiles[@]} ps_instances=`$SVCS -H -oFMRI $ps_service 2>/dev/null` # # For each manifest file that is listed by the service # check for its existance. If it exists, then check that # the instances of the service are supported by at least # one of the manifest files listed. # for mf in ${ps_mfiles[@]} do # # This is an unsupported service just return # skipping the service. # [ ${mf%/var/svc/manifest*} ] && return if [ ! -f $mf ]; then ps_mfiles_tmp="$ps_mfiles_tmp $mf" continue fi inst=`get_instances $mf` set -A ps_inst_list for i in $inst do ps_inst_tmp="" for j in $ps_instances do if [ "$i" == "$j" ]; then set -A ps_inst_list ${ps_inst_list[*]} $j continue else ps_inst_tmp="$ps_inst_tmp $j" fi done # # If there are any instances not accounted for add # them to the list to be cleaned up. # ps_instances=$ps_inst_tmp done done # # If there are any manifest files set them to the list # to be cleaned up. # set -A ps_mfiles $ps_mfiles_tmp # # For each manifest file that was not found remove it from # the service's list of manifest files. # for mf in ${ps_mfiles[@]} do # # Need to remove the file from the smf/manifest # list. # ps_refresh=1 mf_nw=`echo "$needwork" | grep -v $mf` needwork="$mf_nw" mf_srch=`echo $mf | sed -e 's/\./\\\./g'` mf_pg=`grep "$mf_srch" $MCLEANUPFILE | awk '{print $1}'` [ $ps_mfiles_cnt -ne ${#ps_mfiles[@]} ] && \ $SVCCFG -s $ps_service delprop $mf_pg > /dev/null 2>&1 mf_pg=`echo $mf_pg | awk -F'/' '{print $2}'` $SVCCFG -s smf/manifest delpg $mf_pg > /dev/null 2>&1 done # # If all the manifest files that were listed in the service have now # been removed, delete the service. # if [ $ps_mfiles_cnt -eq ${#ps_mfiles[@]} ]; then # # Disable each of the instances for the service # then delete the service. # # If the restarter is not startd then the service # will not be online at this point and we need # to not wait on the disable. # # Set the delete opt to -f if the disable is not # synchronous. # $SVCPROP -q -p general/restarter $ps_service if [ $? -ne 0 ]; then DISOPT="-s" DELOP="" else DISOPT="" DELOP="-f" fi for i in `$SVCS -H -oFMRI $ps_service` do $SVCADM disable $DISOPT $i & CPID=$! pid_timeout $CPID if [ $? -ne 0 ]; then DELOPT="-f" kill $CPID fi done echo "$SVCCFG delete $ps_service" $SVCCFG delete $DELOPT $ps_service return fi # # Need to only cleanup instances that are no longer supported # by the manifest files associated with the service. # for i in $ps_instances do # # Ignore any instances that are hand created # ps_refresh=1 $SVCCFG -s $i selectsnap last-import > /dev/null 2>&1 [ $? -ne 0 ] && continue # # If the restarter is not startd then the service # will not be online at this point and we need # to not wait on the disable. # $SVCPROP -q -p general/restarter $ps_service if [ $? -ne 0 ]; then DELOP="" $SVCADM disable -s $i & CPID=$! pid_timeout $CPID if [ $? -ne 0 ]; then DELOPT="-f" kill $CPID fi else DELOP="-f" $SVCADM disable $i fi echo "$SVCCFG delete $i" $SVCCFG delete $DELOP $i done # # If instances of the services were removed, refresh the # additional instances, or cleanup any leftover services. # if [ $ps_refresh -ne 0 ]; then if [ ${#ps_inst_list[@]} -gt 0 ]; then for i in ${ps_inst_list[@]} do $SVCCFG -s $i refresh done else ps_support=0 for ps_mfile in `awk '{print $3}' $MCLEANUPFILE` do $SVCCFG inventory $ps_mfile | grep $ps_service > /dev/null 2>&1 [ $? -eq 0 ] && ps_supprt=1 done [ $ps_support -eq 0 ] && $SVCCFG delete $ps_service fi fi } # # Upgrade a service to have the manifest files associated with # listed in the manifestfiles property group. # # If the first argument is FALSE, then check to see if the service # has any previous import indications. If so then delete the # service, otherwise set the service as a non-supported service # for the automated manifest deletion process. # function add_manifest { am_service=$1 shift $SVCCFG -s $am_service addpg $MFSTPG framework if [ "$1" == "FALSE" ]; then am_lisnap=1 am_inst=`svcs -H -oFMRI $am_service 2>/dev/null` # # Check for a last-import snapshot, if there is not # one then the service was hand crafted and the support # should be set to false. # if [ $? -eq 0 ]; then for i in $am_inst do $SVCCFG -s $i selectsnap last-import > /dev/null 2>&1 [ $? -eq 0 ] && am_lisnap=0 done fi if [ $am_lisnap -ne 0 ]; then $SVCCFG -s $am_service setprop $MFSTPG/support = boolean: 0 return fi # # If the service was not hand crafted then check to see if # the service has ever been installed in the /var/svc/manifest # directory and therefore a known removed service. # grep "$am_service " $MFSTHISTORY | grep -v "^#" > /dev/null 2>&1 if [ $? -eq 0 ]; then echo "$SVCCFG delete $am_service" $SVCCFG delete -f $am_service else # # Do not know where the service came from so set # it to false. # $SVCCFG -s $am_service setprop $MFSTPG/support = boolean: 0 fi else for am_mfile in $@ do CF=${am_mfile#/*} CF=`echo $CF | sed -e 's/[\/\,\.]/_/g'` $SVCCFG -s $am_service setprop $MFSTPG/$CF = astring: $am_mfile done fi } # # upgrade the entries in the smf/manifest table to have # a pointer to the actual manifest file. # function upgrade_smfmanifest { us_unfnd="" for us_E in `$SVCPROP smf/manifest | grep md5sum | grep var_svc_manifest | awk '{print $1}' | awk -F'/' '{print $1}'` do $SVCPROP -q -p $us_E/manifestfile smf/manifest [ $? -eq 0 ] && continue us_S=`echo $us_E | sed -e 's/_xml/.xml/'` us_S=`echo $us_S | sed -e 's/var_svc_manifest_/var\/svc\/manifest\//'` us_R="" while [ ! -f $us_S -a ! "$us_R" ] do us_S=`echo $us_S | sed -e 's/_/\//'` us_R=${us_S##*_*} done us_S="/$us_S" if [ -f $us_S ]; then us_R=`$MFSTSCAN $us_S` [ ! "$R" ] && \ $SVCCFG -s smf/manifest setprop ${us_E}/manifestfile = astring: $us_S else us_unfnd="$us_unfnd $us_E" fi done echo "$us_unfnd" } function manifest_cleanup { # # If manifest-import had activity then need to make checks to override # a mfstscan that returns no modifications. This is because the hash # table will already have been updated by the manifest-import run, # therefor manifest-cleanup will not see those changes in the mfstscan # call. # # activity indicates changes and overrides the needwork check. # force can be a list of files that will only be processed # or force can be set to true, so that all files are checked # regardless. # arg1=$1 activity=${arg1:-true} [ "$1" ] && shift argrest=$@ force=${argrest:-false} # # Check the smf/manifest table to see if it needs upgrading # md5c=`$SVCPROP smf/manifest | grep var_svc_manifest | grep -c md5sum` mfc=`$SVCPROP smf/manifest | grep var_svc_manifest | grep -cw manifestfile` if [ $md5c -ne $mfc ]; then unfnd_upgrade=`upgrade_smfmanifest` if [ "$force" == false ]; then activity="true" force="true" fi fi smfmfiles=`svcprop smf/manifest | grep manifestfile | grep astring | awk '{print $3}'` needwork=`/lib/svc/bin/mfstscan $smfmfiles 2>&1 1>/dev/null` if [ ! "$needwork" ]; then [ "$activity" == false ] && return [ "$activity" == true -a "$force" == false ] && return fi # # Walk the list of services... # export SVCCFG_CHECKHASH=1 for service in `$SVCCFG list` do svcprop -q -p $MFSTPG $service if [ $? -ne 0 ]; then mc_igchk=`eval expr \"$IGNORELIST \" : "'.*\($service \)'"` if [[ -n $mc_igchk ]]; then echo "add_manifest $service FALSE" add_manifest $service FALSE continue fi [ $UPLIST -eq 0 ] && create_list CS=`echo $service | sed -e 's/[-\/\,]/_/g'` eval manifestlist=\$$CS if [ -n "$manifestlist" ]; then echo "add_manifest $service $manifestlist" add_manifest $service $manifestlist else echo "add_manifest $service FALSE" add_manifest $service FALSE fi else process_service $service fi done rm -f $MCLEANUPFILE unset SVCCFG_CHECKHASH # # Check to make sure all work was processed and # that all the files were removed correctly from # the smf/manifest table. # leftover=`echo "$needwork" | grep "cannot stat" | awk '{print $4}'` for f in $leftover $unfnd_upgrade do f_srch=`echo $f | sed -e 's/\./\\\./g; s/:$//'` f_entry=`$SVCPROP smf/manifest | grep "$f_srch" | awk -F'/' '{print $1}'` [ "$f_entry" ] && $SVCCFG -s smf/manifest delpg $f_entry done }