diff options
author | Sean Wilcox <Sean.Wilcox@Sun.COM> | 2009-09-07 10:46:52 -0700 |
---|---|---|
committer | Sean Wilcox <Sean.Wilcox@Sun.COM> | 2009-09-07 10:46:52 -0700 |
commit | 23294c7da48c2eb5222bccedbefb1e06cf5c4df3 (patch) | |
tree | 4459e74ddb1749d95bc583a78419b66c5bdc285c | |
parent | 7b3411b6ce9d5ba373d2e36a6c8db48b2dfb74b7 (diff) | |
download | illumos-joyent-23294c7da48c2eb5222bccedbefb1e06cf5c4df3.tar.gz |
6859248 manifest removal should automatically cause repository cleanup
-rw-r--r-- | usr/src/cmd/svc/common/manifest_hash.c | 34 | ||||
-rw-r--r-- | usr/src/cmd/svc/common/manifest_hash.h | 6 | ||||
-rw-r--r-- | usr/src/cmd/svc/milestone/manifest-import | 48 | ||||
-rw-r--r-- | usr/src/cmd/svc/prophist/prophist.c | 10 | ||||
-rw-r--r-- | usr/src/cmd/svc/shell/Makefile | 3 | ||||
-rw-r--r-- | usr/src/cmd/svc/shell/manifest_cleanup.ksh | 474 | ||||
-rw-r--r-- | usr/src/cmd/svc/svccfg/svccfg_engine.c | 4 | ||||
-rw-r--r-- | usr/src/cmd/svc/svccfg/svccfg_libscf.c | 145 | ||||
-rw-r--r-- | usr/src/cmd/svc/svccfg/svccfg_xml.c | 37 | ||||
-rw-r--r-- | usr/src/lib/libscf/inc/libscf.h | 1 | ||||
-rw-r--r-- | usr/src/pkgdefs/SUNWcsr/prototype_com | 1 | ||||
-rw-r--r-- | usr/src/pkgdefs/common_files/i.manifest | 5 | ||||
-rw-r--r-- | usr/src/pkgdefs/common_files/r.manifest | 64 |
13 files changed, 735 insertions, 97 deletions
diff --git a/usr/src/cmd/svc/common/manifest_hash.c b/usr/src/cmd/svc/common/manifest_hash.c index 547f791df9..d833a53325 100644 --- a/usr/src/cmd/svc/common/manifest_hash.c +++ b/usr/src/cmd/svc/common/manifest_hash.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -189,16 +189,18 @@ out: } int -mhash_store_entry(scf_handle_t *hndl, const char *name, uchar_t *hash, - char **errstr) +mhash_store_entry(scf_handle_t *hndl, const char *name, const char *fname, + uchar_t *hash, char **errstr) { scf_scope_t *scope = NULL; scf_service_t *svc = NULL; scf_propertygroup_t *pg = NULL; scf_property_t *prop = NULL; scf_value_t *val = NULL; + scf_value_t *fval = NULL; scf_transaction_t *tx = NULL; scf_transaction_entry_t *e = NULL; + scf_transaction_entry_t *fe = NULL; int ret, result = 0; int i; @@ -312,7 +314,9 @@ mhash_store_entry(scf_handle_t *hndl, const char *name, uchar_t *hash, } if ((e = scf_entry_create(hndl)) == NULL || - (val = scf_value_create(hndl)) == NULL) { + (val = scf_value_create(hndl)) == NULL || + (fe = scf_entry_create(hndl)) == NULL || + (fval = scf_value_create(hndl)) == NULL) { if (errstr != NULL) *errstr = gettext("Could not store file hash: " "permission denied.\n"); @@ -322,6 +326,8 @@ mhash_store_entry(scf_handle_t *hndl, const char *name, uchar_t *hash, ret = scf_value_set_opaque(val, hash, MHASH_SIZE); assert(ret == SCF_SUCCESS); + ret = scf_value_set_astring(fval, fname); + assert(ret == SCF_SUCCESS); tx = scf_transaction_create(hndl); if (tx == NULL) { @@ -372,6 +378,20 @@ mhash_store_entry(scf_handle_t *hndl, const char *name, uchar_t *hash, ret = scf_entry_add_value(e, val); assert(ret == SCF_SUCCESS); + if (scf_transaction_property_new(tx, fe, MFILE_PROP, + SCF_TYPE_ASTRING) != SCF_SUCCESS && + scf_transaction_property_change_type(tx, fe, MFILE_PROP, + SCF_TYPE_ASTRING) != SCF_SUCCESS) { + if (errstr != NULL) + *errstr = gettext("Could not modify file " + "entry"); + result = -1; + goto out; + } + + ret = scf_entry_add_value(fe, fval); + assert(ret == SCF_SUCCESS); + ret = scf_transaction_commit(tx); if (ret == 0) @@ -394,9 +414,11 @@ mhash_store_entry(scf_handle_t *hndl, const char *name, uchar_t *hash, scf_transaction_destroy(tx); (void) scf_entry_destroy(e); + (void) scf_entry_destroy(fe); out: (void) scf_value_destroy(val); + (void) scf_value_destroy(fval); scf_property_destroy(prop); scf_pg_destroy(pg); scf_service_destroy(svc); @@ -609,7 +631,7 @@ mhash_test_file(scf_handle_t *hndl, const char *file, uint_t is_profile, * we then update the database with the complete * new hash so we can be a bit quicker next time. */ - (void) mhash_store_entry(hndl, pname, hash, NULL); + (void) mhash_store_entry(hndl, pname, file, hash, NULL); uu_free(pname); return (MHASH_RECONCILED); } @@ -633,7 +655,7 @@ mhash_test_file(scf_handle_t *hndl, const char *file, uint_t is_profile, * Update the new entry so we don't have to go through * all this trouble next time. */ - (void) mhash_store_entry(hndl, pname, hash, NULL); + (void) mhash_store_entry(hndl, pname, file, hash, NULL); uu_free(pname); return (MHASH_RECONCILED); } diff --git a/usr/src/cmd/svc/common/manifest_hash.h b/usr/src/cmd/svc/common/manifest_hash.h index ec718b9c76..1a43137e44 100644 --- a/usr/src/cmd/svc/common/manifest_hash.h +++ b/usr/src/cmd/svc/common/manifest_hash.h @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -41,6 +41,7 @@ extern "C" { #define MHASH_PG_TYPE "framework" #define MHASH_PG_FLAGS 0 #define MHASH_PROP "md5sum" +#define MFILE_PROP "manifestfile" #define MHASH_FORMAT_V1 "%llx%x%llx%lx" #define MHASH_FORMAT_V2 "%x%x%llx%lx" @@ -51,7 +52,8 @@ extern "C" { char *mhash_filename_to_propname(const char *, boolean_t); int mhash_retrieve_entry(scf_handle_t *, const char *, uchar_t *); -int mhash_store_entry(scf_handle_t *, const char *, uchar_t *, char **); +int mhash_store_entry(scf_handle_t *, const char *, const char *, uchar_t *, + char **); int mhash_test_file(scf_handle_t *, const char *, uint_t, char **, uchar_t *); #ifdef __cplusplus diff --git a/usr/src/cmd/svc/milestone/manifest-import b/usr/src/cmd/svc/milestone/manifest-import index 0b3586d0ae..113b308b99 100644 --- a/usr/src/cmd/svc/milestone/manifest-import +++ b/usr/src/cmd/svc/milestone/manifest-import @@ -1,4 +1,4 @@ -#!/sbin/sh +#!/bin/ksh # # CDDL HEADER START # @@ -20,7 +20,7 @@ # CDDL HEADER END # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -29,6 +29,7 @@ [ -f /lib/svc/share/smf_include.sh ] || exit 1 . /lib/svc/share/smf_include.sh +. /lib/svc/share/manifest_cleanup.ksh activity=false @@ -41,14 +42,14 @@ while getopts n opt; do esac done -svccfg_apply () { +function svccfg_apply { $X /usr/sbin/svccfg apply $1 if [ $? -ne 0 ]; then echo "WARNING: svccfg apply $1 failed" | tee /dev/msglog fi } -svccfg_import () { +function svccfg_import { $X /usr/sbin/svccfg import $1 2>>/tmp/manifest_import.$$ if [ $? -ne 0 ]; then echo > /dev/msglog @@ -56,7 +57,7 @@ svccfg_import () { fi } -prophist_upgrade () { +function prophist_upgrade { # # A property has changed in the manifest that we wish to propagate into # the repository during manifest import. We don't want to pollute @@ -73,7 +74,7 @@ prophist_upgrade () { [ $? = 0 ] && instance_refresh $fmri } -prophist_override () { +function prophist_override { # # A property has changed in the manifest that we wish to propagate # into the repository during manifest import. @@ -87,7 +88,7 @@ prophist_override () { [ $? = 0 ] && instance_refresh $fmri } -prophist_delete_svc_pg () { +function prophist_delete_svc_pg { # # Certain property groups have migrated from the service level to the # instance level. We don't care if they are at both, as the instance @@ -108,7 +109,7 @@ prophist_delete_svc_pg () { fi } -prophist_delete_dependency () { +function prophist_delete_dependency { # # Some services have stale dependencies that need to be removed. # This is done by removing the dependency property group. @@ -125,7 +126,7 @@ prophist_delete_dependency () { fi } -prophist_delete_pg () { +function prophist_delete_pg { # Delete obsolete property groups from old manifests. Instances # should be refreshed for changes to take effect. fmri=$1 @@ -135,7 +136,7 @@ prophist_delete_pg () { /lib/svc/bin/prophist delete -e $fmri -g $pg } -prophist_addprop () { +function prophist_addprop { # # If a property doesn't exist, create it. Instances should be # refreshed for changes to take effect. @@ -161,7 +162,7 @@ prophist_addprop () { /usr/sbin/svccfg -s $fmri setprop $pg/$prop = $* } -prophist_addmeth () { +function prophist_addmeth { # # If a method doesn't exist, create it. Instances should be refreshed # for changes to take effect. @@ -188,7 +189,7 @@ prophist_addmeth () { END } -prophist_adddep () { +function prophist_adddep { # # If a dependency doesn't exist, create it. Instances should be # refreshed for changes to take effect. @@ -218,7 +219,7 @@ prophist_adddep () { END } -prophist_adddpt () { +function prophist_adddpt { # # If a dependent doesn't exist, create it. Instances should be # refresh for changes to take effect. @@ -242,26 +243,26 @@ prophist_adddpt () { prophist_adddep $target $name service $group $ro $fmri } -instance_refresh () { +function instance_refresh { echo $1 >> /etc/svc/volatile/refreshes } -refresh_instances () { +function refresh_instances { [ -r /etc/svc/volatile/refreshes ] && { sort -u /etc/svc/volatile/refreshes | xargs -l svcadm refresh } } -instance_clear () { +function instance_clear { echo $1 >> /etc/svc/volatile/clears } -clear_conditionally () { +function clear_conditionally { [ "`/usr/bin/svcprop -p restarter/state $1`" = "maintenance" ] && \ /usr/sbin/svcadm clear $1 } -clear_instances () { +function clear_instances { [ -r /etc/svc/volatile/clears ] && { for inst in `/usr/bin/sort -u /etc/svc/volatile/clears`; do clear_conditionally $inst @@ -269,7 +270,7 @@ clear_instances () { } } -prepare_last_import () { +function prepare_last_import { # Preserve the five hashes for the profiles: generic (two # cases), platform (uname -i, uname -m outputs), and site. @@ -458,6 +459,7 @@ if [ -n "$nonsite_manifests" -o -n "$site_manifests" ]; then rm -f /tmp/manifest_import.$$ set -- $manifests + cleanup="" backup=`echo "$#/$#" | sed 's/.//g'` fwidth=`echo "$#\c" | wc -c` @@ -471,13 +473,19 @@ if [ -n "$nonsite_manifests" -o -n "$site_manifests" ]; then doswitch=$? i=1; n=$# + svcprop smf/manifest > /etc/svc/volatile/smf_manifest_svcprop 2>&1 while [ $# -gt 0 ]; do printf "%${fwidth}s/%${fwidth}s" $i $n > /dev/msglog + grep $1 /etc/svc/volatile/smf_manifest_svcprop > /dev/null 2>&1 + if [ $? -eq 0 ]; then + cleanup="$cleanup $1" + fi svccfg_import $1 i=`expr $i + 1` shift echo "$backup\c" > /dev/msglog done + rm -f /etc/svc/volatile/smf_manifest_svcprop # # If switch back fails, exit with the fatal error code. @@ -578,4 +586,6 @@ if $activity; then svcadm _smf_backup "manifest_import" || true fi +manifest_cleanup $activity $cleanup + exit 0 diff --git a/usr/src/cmd/svc/prophist/prophist.c b/usr/src/cmd/svc/prophist/prophist.c index 0f42c906ec..8f1aedb1a5 100644 --- a/usr/src/cmd/svc/prophist/prophist.c +++ b/usr/src/cmd/svc/prophist/prophist.c @@ -19,12 +19,10 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - /* * prophist - property history utility * @@ -193,15 +191,15 @@ hash(char *arg) uu_die(gettext("mhash_test_file() failed")); default: uu_die(gettext("unknown return value (%d) from " - "mhash_test_file()"), ret); + "mhash_test_file()"), ret); } - if (mhash_store_entry(hndl, pname, hash, &errstr)) { + if (mhash_store_entry(hndl, pname, arg, hash, &errstr)) { if (errstr) uu_die(errstr); else uu_die(gettext("Unknown error from " - "mhash_store_entry()\n")); + "mhash_store_entry()\n")); } return (3); diff --git a/usr/src/cmd/svc/shell/Makefile b/usr/src/cmd/svc/shell/Makefile index 3367b317be..fc9bc37da3 100644 --- a/usr/src/cmd/svc/shell/Makefile +++ b/usr/src/cmd/svc/shell/Makefile @@ -31,7 +31,8 @@ SRCS = \ net_include.sh \ routing_include.sh \ sendmail_include.sh \ - smf_include.sh + smf_include.sh \ + manifest_cleanup.ksh SCRIPTS = $(SRCS:%=$(ROOT)/lib/svc/share/%) diff --git a/usr/src/cmd/svc/shell/manifest_cleanup.ksh b/usr/src/cmd/svc/shell/manifest_cleanup.ksh new file mode 100644 index 0000000000..8c29e9fabb --- /dev/null +++ b/usr/src/cmd/svc/shell/manifest_cleanup.ksh @@ -0,0 +1,474 @@ +#!/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" +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\" + # XXX - remove this line at some point " + # I clears up the above escaped quote throwing + # off my color scheme in vim. + 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 + if [ ! -f $mf ]; then + ps_mfiles_tmp="$ps_mfiles_tmp $mf" + continue + fi + + [ ${mf%/var/svc/manifest*} ] && continue + + 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` + 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 -eq 0 ]; then + $SVCCFG delete -f $am_service + else + $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 + if [[ $IGNORELIST == $ps_service ]]; then + echo "add_manifest $service FALSE" + add_manifest $service FALSE + 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 +} diff --git a/usr/src/cmd/svc/svccfg/svccfg_engine.c b/usr/src/cmd/svc/svccfg/svccfg_engine.c index 660582fe07..365f2c9ac5 100644 --- a/usr/src/cmd/svc/svccfg/svccfg_engine.c +++ b/usr/src/cmd/svc/svccfg/svccfg_engine.c @@ -622,7 +622,7 @@ engine_import(uu_list_t *args) if (pname) { char *errstr; - if (mhash_store_entry(g_hndl, pname, hash, &errstr)) { + if (mhash_store_entry(g_hndl, pname, file, hash, &errstr)) { if (errstr) semerr(errstr); else @@ -671,7 +671,7 @@ engine_apply(const char *file, int apply_changes) if (pname) { char *errstr; - if (mhash_store_entry(g_hndl, pname, hash, &errstr)) + if (mhash_store_entry(g_hndl, pname, file, hash, &errstr)) semerr(errstr); free(pname); diff --git a/usr/src/cmd/svc/svccfg/svccfg_libscf.c b/usr/src/cmd/svc/svccfg/svccfg_libscf.c index d7dc1311de..76b8ed2e87 100644 --- a/usr/src/cmd/svc/svccfg/svccfg_libscf.c +++ b/usr/src/cmd/svc/svccfg/svccfg_libscf.c @@ -48,6 +48,8 @@ #include <libxml/tree.h> +#include <sys/param.h> + #include "svccfg.h" #include "manifest_hash.h" @@ -3288,6 +3290,145 @@ commit: } /* + * Used to add the manifests to the list of currently supported manifests. + * We could modify the existing manifest list removing entries if the files + * don't exist. + * + * Get the old list and the new file name + * If the new file name is in the list return + * If not then add the file to the list. + * As we process the list check to see if the files in the old list exist + * if not then remove the file from the list. + * Commit the list of manifest file names. + * + */ +static int +upgrade_manifestfiles(const entity_t *ient, const scf_snaplevel_t *running, + void *ent) +{ + scf_propertygroup_t *ud_run_mfsts_pg = NULL; + scf_property_t *ud_run_prop = NULL; + scf_iter_t *ud_prop_iter; + scf_value_t *fname_value; + pgroup_t *mfst_pgroup; + property_t *mfst_prop; + property_t *old_prop; + char *pname = malloc(MAXPATHLEN); + char *fval; + char *old_pname; + char *old_fval; + int mfst_seen; + int r; + + const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); + + /* + * This should always be the service base on the code + * path, and the fact that the manifests pg is a service + * level property group only. + */ + ud_run_mfsts_pg = scf_pg_create(g_hndl); + ud_run_prop = scf_property_create(g_hndl); + ud_prop_iter = scf_iter_create(g_hndl); + fname_value = scf_value_create(g_hndl); + + /* Fetch the running version of the "manifests" property group */ + if (running != NULL) + r = scf_snaplevel_get_pg(running, SCF_PG_MANIFESTFILES, + ud_run_mfsts_pg); + else + r = entity_get_pg(ent, issvc, SCF_PG_MANIFESTFILES, + ud_run_mfsts_pg); + + if (r != 0) { + switch (scf_error()) { + case SCF_ERROR_NOT_FOUND: + break; + + case SCF_ERROR_DELETED: + case SCF_ERROR_CONNECTION_BROKEN: + return (scferror2errno(scf_error())); + + case SCF_ERROR_NOT_SET: + case SCF_ERROR_INVALID_ARGUMENT: + case SCF_ERROR_HANDLE_MISMATCH: + case SCF_ERROR_NOT_BOUND: + default: + bad_error(running ? "scf_snaplevel_get_pg" : + "entity_get_pg", scf_error()); + } + } + + /* Fetch the new manifests property group */ + for (mfst_pgroup = uu_list_first(ient->sc_pgroups); + mfst_pgroup != NULL; + mfst_pgroup = uu_list_next(ient->sc_pgroups, mfst_pgroup)) { + if (strcmp(mfst_pgroup->sc_pgroup_name, + SCF_PG_MANIFESTFILES) == 0) + break; + } + + if (scf_iter_pg_properties(ud_prop_iter, ud_run_mfsts_pg) != + SCF_SUCCESS) + return (-1); + + while ((r = scf_iter_next_property(ud_prop_iter, ud_run_prop)) == 1) { + mfst_seen = 0; + if (scf_property_get_name(ud_run_prop, pname, MAXPATHLEN) < 0) + continue; + + for (mfst_prop = uu_list_first(mfst_pgroup->sc_pgroup_props); + mfst_prop != NULL; + mfst_prop = uu_list_next(mfst_pgroup->sc_pgroup_props, + mfst_prop)) { + if (strcmp(mfst_prop->sc_property_name, pname) == 0) { + mfst_seen = 1; + } + } + + /* + * If the manifest is not seen then add it to the new mfst + * property list to get proccessed into the repo. + */ + if (mfst_seen == 0) { + fval = malloc(MAXPATHLEN); + + /* + * If we cannot get the value then there is no + * reasont to attempt to attach the value to + * the property group + */ + if (fval != NULL && + prop_get_val(ud_run_prop, fname_value) == 0 && + scf_value_get_astring(fname_value, fval, + MAXPATHLEN) != -1) { + /* + * First check to see if the manifest is there + * if not then there is no need to add it. + */ + if (access(fval, F_OK) == -1) { + free(fval); + continue; + } + old_pname = safe_strdup(pname); + old_fval = safe_strdup(fval); + old_prop = internal_property_create(old_pname, + SCF_TYPE_ASTRING, 1, old_fval); + + /* + * Already checked to see if the property exists + * in the group, and it does not. + */ + (void) internal_attach_property(mfst_pgroup, + old_prop); + } + } + } + + return (r); +} + +/* * prop is taken to be a property in the "dependents" property group of snpl, * which is taken to be the snaplevel of a last-import snapshot corresponding * to ient. If prop is a valid dependents property, upgrade the dependent it @@ -4698,6 +4839,10 @@ process_old_pg(const scf_propertygroup_t *lipg, entity_t *ient, void *ent, if (strcmp(imp_str, "dependents") == 0) return (upgrade_dependents(lipg, imp_snpl, ient, running, ent)); + if (strcmp(imp_str, SCF_PG_MANIFESTFILES) == 0) + if ((r = upgrade_manifestfiles(ient, running, ent)) != 0) + return (r); + if (mpg == NULL || mpg->sc_pgroup_delete) { /* property group was deleted from manifest */ if (entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) { diff --git a/usr/src/cmd/svc/svccfg/svccfg_xml.c b/usr/src/cmd/svc/svccfg/svccfg_xml.c index 0947068b8f..dd9236bc08 100644 --- a/usr/src/cmd/svc/svccfg/svccfg_xml.c +++ b/usr/src/cmd/svc/svccfg/svccfg_xml.c @@ -50,6 +50,9 @@ #include <sys/stat.h> #include <unistd.h> +#include <sys/param.h> +#include "manifest_hash.h" + #include "svccfg.h" /* @@ -2948,6 +2951,8 @@ lxml_get_single_instance(entity_t *entity, xmlNodePtr si) static int lxml_get_service(bundle_t *bundle, xmlNodePtr svc, svccfg_op_t op) { + pgroup_t *pg; + property_t *p; entity_t *s; xmlNodePtr cursor; xmlChar *type; @@ -2969,6 +2974,36 @@ lxml_get_service(bundle_t *bundle, xmlNodePtr svc, svccfg_op_t op) xmlFree(type); /* + * Now that the service is created create the manifest + * property group and add the property value of the service. + */ + if (svc->doc->name != NULL && + bundle->sc_bundle_type == SVCCFG_MANIFEST) { + char *buf, *base, *fname; + + pg = internal_pgroup_create_strict(s, SCF_PG_MANIFESTFILES, + SCF_GROUP_FRAMEWORK); + + if (pg == NULL) { + uu_die(gettext("Property group for prop_pattern, " + "\"%s\", already exists in %s\n"), + SCF_PG_MANIFESTFILES, s->sc_name); + } + buf = mhash_filename_to_propname(svc->doc->name, B_FALSE); + /* + * Must remove the PKG_INSTALL_ROOT, point to the correct + * directory after install + */ + base = getenv("PKG_INSTALL_ROOT"); + fname = safe_strdup(svc->doc->name + + ((base != NULL) ? strlen(base) : 0)); + + p = internal_property_create(buf, SCF_TYPE_ASTRING, 1, fname); + + (void) internal_attach_property(pg, p); + } + + /* * Walk its child elements, as appropriate. */ for (cursor = svc->xmlChildrenNode; cursor != NULL; @@ -3166,6 +3201,8 @@ lxml_get_bundle_file(bundle_t *bundle, const char *filename, svccfg_op_t op) return (-1); } + document->name = strdup(filename); + /* * Verify that this is a document type we understand. */ diff --git a/usr/src/lib/libscf/inc/libscf.h b/usr/src/lib/libscf/inc/libscf.h index f3864f03f4..2e040a2a3e 100644 --- a/usr/src/lib/libscf/inc/libscf.h +++ b/usr/src/lib/libscf/inc/libscf.h @@ -266,6 +266,7 @@ typedef struct scf_tmpl_error scf_tmpl_error_t; #define SCF_PG_STARTD ((const char *)"startd") #define SCF_PG_STARTD_PRIVATE ((const char *)"svc-startd-private") #define SCF_PG_DEATHROW ((const char *)"deathrow") +#define SCF_PG_MANIFESTFILES ((const char *)"manifestfiles") /* * Template property group names and prefixes diff --git a/usr/src/pkgdefs/SUNWcsr/prototype_com b/usr/src/pkgdefs/SUNWcsr/prototype_com index 962c49fd1d..aa4f57b0b1 100644 --- a/usr/src/pkgdefs/SUNWcsr/prototype_com +++ b/usr/src/pkgdefs/SUNWcsr/prototype_com @@ -393,6 +393,7 @@ f none lib/svc/share/ipf_include.sh 0444 root bin f none lib/svc/share/net_include.sh 0444 root bin f none lib/svc/share/routing_include.sh 0444 root bin f none lib/svc/share/smf_include.sh 0444 root bin +f none lib/svc/share/manifest_cleanup.ksh 0444 root bin d none mnt 755 root sys d none opt 755 root sys d none proc 555 root root diff --git a/usr/src/pkgdefs/common_files/i.manifest b/usr/src/pkgdefs/common_files/i.manifest index 07c4b8ca78..18d2c2622d 100644 --- a/usr/src/pkgdefs/common_files/i.manifest +++ b/usr/src/pkgdefs/common_files/i.manifest @@ -20,7 +20,7 @@ # CDDL HEADER END # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # i.manifest - smf(5) service manifest install class action script @@ -30,6 +30,7 @@ repfile=$PKG_INSTALL_ROOT/etc/svc/repository.db export repfile SVCCFG=/usr/sbin/svccfg +SVCADM=/usr/sbin/svcadm AWK=/usr/bin/awk RM=/usr/bin/rm CP=/usr/bin/cp @@ -109,7 +110,7 @@ else $CP -p $src $dst [ "$PKG_INSTALL_ROOT" = "" -o "$PKG_INSTALL_ROOT" = "/" ] && \ - SVCCFG_CHECKHASH=1 $SVCCFG import $dst + $SVCADM restart svc:/system/manifest-import:default done fi diff --git a/usr/src/pkgdefs/common_files/r.manifest b/usr/src/pkgdefs/common_files/r.manifest index 879016a302..98c6e48f19 100644 --- a/usr/src/pkgdefs/common_files/r.manifest +++ b/usr/src/pkgdefs/common_files/r.manifest @@ -20,7 +20,7 @@ # CDDL HEADER END # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # @@ -117,70 +117,16 @@ fi while read mfst; do if [ "$smf_alive" = "yes" ]; then - ENTITIES=`$SVCCFG inventory $mfst` + $RM -f $mfst - for fmri in $ENTITIES; do - - # Determine whether fmri refers to an instance or a service. - $SVCPROP -p restarter/state $fmri >/dev/null 2>&1 - if [ $? -eq 1 ]; then - # this is a service fmri, all instances have been deleted - $SVCCFG delete $fmri 2>/dev/null - # process next instance - continue - fi - - # - # Try to disable the instance within a reasonable amount of time - # (eg. 60 secs). If it fails, forcibly delete the instance. - # - echo "Waiting up to $STOP_DELAY seconds for $fmri to stop..." - $SVCADM disable $fmri 2>/dev/null - if [ $? -eq 0 ]; then - wait_disable $fmri $STOP_DELAY - if [ $? -eq 0 ]; then - # the instance is disabled and can be safely deleted - $SVCCFG delete $fmri 2>/dev/null - # process next instance - continue - fi - echo "Failed to disable $fmri after $STOP_DELAY seconds" - else - echo "Failed to disable $fmri" - fi - - echo "Force deleting $fmri" - - ctid=`$SVCPROP -p restarter/contract $fmri 2>/dev/null` - tctid=`$SVCPROP -p restarter/transient_contract $fmri 2>/dev/null` - - $SVCCFG delete -f $fmri - - # - # Kill any remaining processes. - # pkill must occur after the delete to prevent startd - # from retrying the STOP method. - # - if [ -n "${tctid}" -a "${tctid}" -gt 1 ]; then - # kill the STOP method processes - /usr/bin/pkill -9 -c $tctid - fi - if [ -n "${ctid}" -a "${ctid}" -gt 1 ]; then - # kill any remaining running processes for the instance - /usr/bin/pkill -9 -c $ctid - fi - done - - # - # Delete the manifest hash value. - # - svc_delhash $mfst + $SVCADM restart svc:/system/manifest-import:default else # deathrow handling svc_deathrow $mfst $PKGINST + + $RM -f $mfst fi - $RM -f $mfst done exit 0 |