summaryrefslogtreecommitdiff
path: root/usr/src/cmd/svc/common
diff options
context:
space:
mode:
authorTom Whitten <Thomas.Whitten@Sun.COM>2010-03-25 14:57:35 -0700
committerTom Whitten <Thomas.Whitten@Sun.COM>2010-03-25 14:57:35 -0700
commit9444c26f4faabda140242c3986089704c4073ced (patch)
tree9e367f2f58dc2b2daa66ea7d430e35d834d913b8 /usr/src/cmd/svc/common
parente765faef9c0385c419aa16d67aa529de3c41ac01 (diff)
downloadillumos-joyent-9444c26f4faabda140242c3986089704c4073ced.tar.gz
PSARC 2010/013 SMF Early Manifest Import
6503835 manifest-import should be done earlier in boot
Diffstat (limited to 'usr/src/cmd/svc/common')
-rw-r--r--usr/src/cmd/svc/common/manifest_find.c324
-rw-r--r--usr/src/cmd/svc/common/manifest_find.h59
-rw-r--r--usr/src/cmd/svc/common/manifest_hash.c158
-rw-r--r--usr/src/cmd/svc/common/manifest_hash.h15
4 files changed, 530 insertions, 26 deletions
diff --git a/usr/src/cmd/svc/common/manifest_find.c b/usr/src/cmd/svc/common/manifest_find.c
new file mode 100644
index 0000000000..4d43e92c67
--- /dev/null
+++ b/usr/src/cmd/svc/common/manifest_find.c
@@ -0,0 +1,324 @@
+/*
+ * 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 2010 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * The primary role of this file is to obtain a list of manifests that are
+ * located in a specified directory or one of its subdirectories. The
+ * find_manifests() function provides this service, and
+ * free_manifest_array() is used to free the memory associated with the
+ * returned list.
+ *
+ * The find_manifests() function can return an array consisting of all the
+ * .xml files in the directory and its subdirectories. Alternatively,
+ * find_manifests() can be asked to only return new manifests based on the
+ * return of mhash_test_file(). The list that is returned is an array of
+ * pointers to manifest_info structures.
+ *
+ * Implementation Notes:
+ * ====================
+ * This module makes use of the nftw(3C) function to scan the directory.
+ * nftw() calls a processing function for every file that it finds.
+ * Unfortunately, nftw does not allow us to pass in any structure pointers
+ * to the processing function, and that makes it hard to accumulate a list.
+ * Thus, we will use the thread specific data area to hold data that must
+ * be retained between calls to the processing function. This will allow
+ * this module to be used in multi-threaded applications if the need
+ * arises.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <ftw.h>
+#include <libscf.h>
+#include <libuutil.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+#include "manifest_find.h"
+#include "manifest_hash.h"
+
+#define MAX_DEPTH 24
+
+/* Thread specific data */
+typedef struct mftsd {
+ manifest_info_t ** tsd_array; /* Array of manifest_info structs */
+ int tsd_count; /* Number items in list */
+ int tsd_max; /* Number of pointers allocated */
+ /* at tsd_array. */
+ int tsd_flags; /* Check flags for hash and extension */
+ scf_handle_t *tsd_hndl; /* Handle for libscf. */
+} mftsd_t;
+
+static pthread_key_t tsd_key = PTHREAD_ONCE_KEY_NP;
+
+/*
+ * Add the manifest info consisting of filename (fn), hash property name
+ * (pname) and hash to the array at tsd_array. If necessary, realloc()
+ * will be called to increase the size of the buffer at tsd_array.
+ *
+ * Returns 0 on success and -1 on failure. If a failure occurs, errno will
+ * be set.
+ */
+static int
+add_pointer(mftsd_t *tsdp, const char *fn, const char *pname, uchar_t *hash)
+{
+ manifest_info_t *info;
+ manifest_info_t **newblock;
+ int new_max;
+
+ if (tsdp->tsd_count >= (tsdp->tsd_max - 1)) {
+ /* Need more memory. */
+ new_max = (tsdp->tsd_max == 0) ? 16 : 2 * tsdp->tsd_max;
+ newblock = realloc(tsdp->tsd_array,
+ new_max * sizeof (*tsdp->tsd_array));
+ if (newblock == NULL)
+ return (-1);
+ tsdp->tsd_array = newblock;
+ /* NULL terminate list in case allocations fail below. */
+ *(tsdp->tsd_array + tsdp->tsd_count) = NULL;
+ tsdp->tsd_max = new_max;
+ }
+ info = uu_zalloc(sizeof (*info));
+ if (info == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ info->mi_path = uu_strdup(fn);
+ if (info->mi_path == NULL) {
+ uu_free(info);
+ errno = ENOMEM;
+ return (-1);
+ }
+ info->mi_prop = pname;
+ if (hash != NULL)
+ (void) memcpy(info->mi_hash, hash, MHASH_SIZE);
+ *(tsdp->tsd_array + tsdp->tsd_count) = info;
+ tsdp->tsd_count++;
+
+ /* NULL terminate the list. */
+ *(tsdp->tsd_array + tsdp->tsd_count) = NULL;
+
+ return (0);
+}
+
+/*
+ * If necessary initialize the thread specific data key at tsd_key, and
+ * allocate a mftsd_t structure to hold our thread specific data. Upon
+ * success, the address the thread specific data is returned. On failure,
+ * NULL is returned and errno is set.
+ */
+static mftsd_t *
+get_thread_specific_data()
+{
+ mftsd_t *tsdp;
+
+ if (pthread_key_create_once_np(&tsd_key, NULL) != 0)
+ return (NULL);
+ tsdp = (mftsd_t *)pthread_getspecific(tsd_key);
+ if (tsdp == NULL) {
+ /*
+ * First time for this thread. We need to allocate memory
+ * for our thread specific data.
+ */
+ tsdp = uu_zalloc(sizeof (*tsdp));
+ if (tsdp == NULL) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ errno = pthread_setspecific(tsd_key, tsdp);
+ if (errno != 0) {
+ /*
+ * EINVAL means that our key is invalid, which
+ * would be a coding error.
+ */
+ assert(errno != EINVAL);
+ return (NULL);
+ }
+ }
+ return (tsdp);
+}
+
+/*
+ * This function is called by nftw(3C) every time that it finds an object
+ * in a directory of interest. If the object is a file, process() checks
+ * to see if it is a manifest file by insuring that it has a .xml
+ * extension.
+ *
+ * If the file is a manifest file, and the CHECKHASH flag is set process()
+ * calls mhash_test_file() to see if it is a new manifest. Manfest data
+ * for selected manifests is added to tsd_array in our thread specific data.
+ *
+ * The CHECKEXT flag may be set if this was not a directory search request
+ * but a single manifest file check that was determined by the caller to
+ * be found based not on the extension of the file.
+ */
+/*ARGSUSED*/
+static int
+process(const char *fn, const struct stat *sp, int ftw_type,
+ struct FTW *ftws)
+{
+ char *suffix_match;
+ uchar_t hash[MHASH_SIZE];
+ char *pname;
+ mftsd_t *tsdp;
+
+ if (ftw_type != FTW_F)
+ return (0);
+
+ tsdp = get_thread_specific_data();
+ if (tsdp == NULL)
+ return (-1);
+
+ /*
+ * Only check the extension on the file when
+ * requested.
+ */
+ if (tsdp->tsd_flags & CHECKEXT) {
+ suffix_match = strstr(fn, ".xml");
+ if (suffix_match == NULL || strcmp(suffix_match, ".xml") != 0)
+ return (0);
+ }
+
+ if (tsdp->tsd_flags & CHECKHASH) {
+ if (mhash_test_file(tsdp->tsd_hndl, fn, 0, &pname, hash) ==
+ MHASH_NEWFILE) {
+ return (add_pointer(tsdp, fn, pname, hash));
+ }
+ } else {
+ return (add_pointer(tsdp, fn, NULL, NULL));
+ }
+
+ return (0);
+}
+
+/*
+ * This function returns a pointer to an array of manifest_info_t pointers.
+ * There is one manifest_info_t pointer for each manifest file in the
+ * directory, dir, that satifies the selection criteria. The array is
+ * returned to arrayp. The array will be terminated with a NULL pointer.
+ * It is the responsibility of the caller to free the memory associated
+ * with the array by calling free_manifest_array().
+ *
+ * flags :
+ * 0x1 - CHECKHASH - do the hash check and only return manifest
+ * files that do not have a hash entry in the smf/manifest table
+ * or the hash value has changed due to the manifest file having
+ * been modified. If not set then all manifest files found are
+ * returned, regardless of the hash status.
+ *
+ * 0x2 - CHECKEXT - Check the extension of the file is .xml
+ *
+ * On success a count of the number of selected manifests is returned.
+ * Note, however, that *arrayp will be set to NULL if the selection is
+ * empty, and a count of 0 will be returned. In the case of failure, -1
+ * will be returned and errno will be set.
+ */
+int
+find_manifests(const char *dir, manifest_info_t ***arrayp, int flags)
+{
+ mftsd_t *tsdp;
+ int status = -1;
+ int count;
+
+ tsdp = get_thread_specific_data();
+ if (tsdp == NULL)
+ return (NULL);
+
+ tsdp->tsd_flags = flags;
+
+ /*
+ * Create a handle for use by mhast_test_file() if
+ * the flag is set to request hash checking be enabled.
+ */
+ if (tsdp->tsd_flags & CHECKHASH) {
+ tsdp->tsd_hndl = scf_handle_create(SCF_VERSION);
+ if (tsdp->tsd_hndl == NULL) {
+ if (scf_error() == SCF_ERROR_NO_MEMORY) {
+ errno = ENOMEM;
+ } else {
+ errno = EINVAL;
+ }
+ goto out;
+ }
+ if (scf_handle_bind(tsdp->tsd_hndl) != SCF_SUCCESS) {
+ if (scf_error() == SCF_ERROR_NO_RESOURCES) {
+ errno = ENOMEM;
+ } else {
+ errno = EINVAL;
+ }
+ goto out;
+ }
+ }
+
+ if (nftw(dir, process, MAX_DEPTH, FTW_MOUNT) == 0) {
+ status = 0;
+ }
+
+out:
+ if (tsdp->tsd_hndl != NULL) {
+ (void) scf_handle_unbind(tsdp->tsd_hndl);
+ (void) scf_handle_destroy(tsdp->tsd_hndl);
+ }
+ if (status == 0) {
+ *arrayp = tsdp->tsd_array;
+ count = tsdp->tsd_count;
+ } else {
+ *arrayp = NULL;
+ free_manifest_array(tsdp->tsd_array);
+ count = -1;
+ }
+
+ /* Reset thread specific data. */
+ (void) memset(tsdp, 0, sizeof (*tsdp));
+
+ return (count);
+}
+
+/*
+ * Free the memory associated with the array of manifest_info structures.
+ */
+void
+free_manifest_array(manifest_info_t **array)
+{
+ manifest_info_t **entry;
+ manifest_info_t *info;
+
+ if (array == NULL)
+ return;
+
+ for (entry = array; *entry != NULL; entry++) {
+ info = *entry;
+ uu_free((void *) info->mi_path);
+ uu_free((void *) info->mi_prop);
+ uu_free(info);
+ }
+
+ /*
+ * Array is allocated with realloc(3C), so it must be freed with
+ * free(3c) rather than uu_free().
+ */
+ free(array);
+}
diff --git a/usr/src/cmd/svc/common/manifest_find.h b/usr/src/cmd/svc/common/manifest_find.h
new file mode 100644
index 0000000000..faca3548c3
--- /dev/null
+++ b/usr/src/cmd/svc/common/manifest_find.h
@@ -0,0 +1,59 @@
+/*
+ * 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 2010 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _MANIFEST_FIND_H
+#define _MANIFEST_FIND_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+#include "manifest_hash.h"
+
+#define CHECKHASH 0x1
+#define CHECKEXT 0x2
+
+typedef struct manifest_info {
+ const char *mi_path; /* Path of manifest file */
+ const char *mi_prop; /* Property that holds manifest hash */
+ uchar_t mi_hash[MHASH_SIZE]; /* Manifest hash */
+} manifest_info_t;
+
+/*
+ * Declare functions that are used for finding manifest files in a
+ * directory.
+ */
+
+
+int find_manifests(const char *, manifest_info_t ***, int);
+void free_manifest_array(manifest_info_t **);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _MANIFEST_FIND_H */
diff --git a/usr/src/cmd/svc/common/manifest_hash.c b/usr/src/cmd/svc/common/manifest_hash.c
index d833a53325..705117a7f4 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -110,16 +110,21 @@ mhash_filename_to_propname(const char *in, boolean_t deathrow)
}
int
-mhash_retrieve_entry(scf_handle_t *hndl, const char *name, uchar_t *hash)
+mhash_retrieve_entry(scf_handle_t *hndl, const char *name, uchar_t *hash,
+ apply_action_t *action)
{
scf_scope_t *scope;
scf_service_t *svc;
scf_propertygroup_t *pg;
scf_property_t *prop;
scf_value_t *val;
+ scf_error_t err;
ssize_t szret;
int result = 0;
+ if (action)
+ *action = APPLY_NONE;
+
/*
* In this implementation the hash for name is the opaque value of
* svc:/MHASH_SVC/:properties/name/MHASH_PROP
@@ -178,6 +183,38 @@ mhash_retrieve_entry(scf_handle_t *hndl, const char *name, uchar_t *hash)
goto out;
}
+ /*
+ * If caller has requested the apply_last property, read the
+ * property if it exists.
+ */
+ if (action != NULL) {
+ uint8_t apply_value;
+
+ if (scf_pg_get_property(pg, MHASH_APPLY_PROP, prop) !=
+ SCF_SUCCESS) {
+ err = scf_error();
+ if ((err != SCF_ERROR_DELETED) &&
+ (err != SCF_ERROR_NOT_FOUND)) {
+ result = -1;
+ }
+ goto out;
+ }
+ if (scf_property_get_value(prop, val) != SCF_SUCCESS) {
+ err = scf_error();
+ if ((err != SCF_ERROR_DELETED) &&
+ (err != SCF_ERROR_NOT_FOUND)) {
+ result = -1;
+ }
+ goto out;
+ }
+ if (scf_value_get_boolean(val, &apply_value) != SCF_SUCCESS) {
+ result = -1;
+ goto out;
+ }
+ if (apply_value)
+ *action = APPLY_LATE;
+ }
+
out:
(void) scf_value_destroy(val);
scf_property_destroy(prop);
@@ -190,17 +227,20 @@ out:
int
mhash_store_entry(scf_handle_t *hndl, const char *name, const char *fname,
- uchar_t *hash, char **errstr)
+ uchar_t *hash, apply_action_t apply_late, 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 *aval = NULL;
scf_value_t *val = NULL;
scf_value_t *fval = NULL;
scf_transaction_t *tx = NULL;
+ scf_transaction_entry_t *ae = NULL;
scf_transaction_entry_t *e = NULL;
scf_transaction_entry_t *fe = NULL;
+ scf_error_t err;
int ret, result = 0;
int i;
@@ -223,7 +263,6 @@ mhash_store_entry(scf_handle_t *hndl, const char *name, const char *fname,
}
for (i = 0; i < 5; ++i) {
- scf_error_t err;
if (scf_scope_get_service(scope, MHASH_SVC, svc) ==
SCF_SUCCESS)
@@ -270,8 +309,6 @@ mhash_store_entry(scf_handle_t *hndl, const char *name, const char *fname,
}
for (i = 0; i < 5; ++i) {
- scf_error_t err;
-
if (scf_service_get_pg(svc, name, pg) == SCF_SUCCESS)
break;
@@ -316,7 +353,9 @@ mhash_store_entry(scf_handle_t *hndl, const char *name, const char *fname,
if ((e = scf_entry_create(hndl)) == NULL ||
(val = scf_value_create(hndl)) == NULL ||
(fe = scf_entry_create(hndl)) == NULL ||
- (fval = scf_value_create(hndl)) == NULL) {
+ (fval = scf_value_create(hndl)) == NULL ||
+ (ae = scf_entry_create(hndl)) == NULL ||
+ (aval = scf_value_create(hndl)) == NULL) {
if (errstr != NULL)
*errstr = gettext("Could not store file hash: "
"permission denied.\n");
@@ -328,6 +367,9 @@ mhash_store_entry(scf_handle_t *hndl, const char *name, const char *fname,
assert(ret == SCF_SUCCESS);
ret = scf_value_set_astring(fval, fname);
assert(ret == SCF_SUCCESS);
+ if (apply_late == APPLY_LATE) {
+ scf_value_set_boolean(aval, 1);
+ }
tx = scf_transaction_create(hndl);
if (tx == NULL) {
@@ -378,10 +420,10 @@ mhash_store_entry(scf_handle_t *hndl, const char *name, const char *fname,
ret = scf_entry_add_value(e, val);
assert(ret == SCF_SUCCESS);
- if (scf_transaction_property_new(tx, fe, MFILE_PROP,
+ if (scf_transaction_property_new(tx, fe, MHASH_FILE_PROP,
SCF_TYPE_ASTRING) != SCF_SUCCESS &&
- scf_transaction_property_change_type(tx, fe, MFILE_PROP,
- SCF_TYPE_ASTRING) != SCF_SUCCESS) {
+ scf_transaction_property_change_type(tx, fe,
+ MHASH_FILE_PROP, SCF_TYPE_ASTRING) != SCF_SUCCESS) {
if (errstr != NULL)
*errstr = gettext("Could not modify file "
"entry");
@@ -392,6 +434,45 @@ mhash_store_entry(scf_handle_t *hndl, const char *name, const char *fname,
ret = scf_entry_add_value(fe, fval);
assert(ret == SCF_SUCCESS);
+ switch (apply_late) {
+ case APPLY_NONE:
+ if (scf_transaction_property_delete(tx, ae,
+ MHASH_APPLY_PROP) != 0) {
+ err = scf_error();
+ if ((err != SCF_ERROR_DELETED) &&
+ (err != SCF_ERROR_NOT_FOUND)) {
+ if (errstr != NULL) {
+ *errstr = gettext("Could not "
+ "delete apply_late "
+ "property");
+ }
+ result = -1;
+ goto out;
+ }
+ }
+ break;
+ case APPLY_LATE:
+ if ((scf_transaction_property_new(tx, ae,
+ MHASH_APPLY_PROP,
+ SCF_TYPE_BOOLEAN) != SCF_SUCCESS) &&
+ (scf_transaction_property_change_type(tx, ae,
+ MHASH_APPLY_PROP, SCF_TYPE_BOOLEAN) !=
+ SCF_SUCCESS)) {
+ if (errstr != NULL) {
+ *errstr = gettext("Could not modify "
+ "apply_late property");
+ }
+ result = -1;
+ goto out;
+ }
+
+ ret = scf_entry_add_value(ae, aval);
+ assert(ret == SCF_SUCCESS);
+ break;
+ default:
+ abort();
+ };
+
ret = scf_transaction_commit(tx);
if (ret == 0)
@@ -415,10 +496,12 @@ mhash_store_entry(scf_handle_t *hndl, const char *name, const char *fname,
scf_transaction_destroy(tx);
(void) scf_entry_destroy(e);
(void) scf_entry_destroy(fe);
+ (void) scf_entry_destroy(ae);
out:
(void) scf_value_destroy(val);
(void) scf_value_destroy(fval);
+ (void) scf_value_destroy(aval);
scf_property_destroy(prop);
scf_pg_destroy(pg);
scf_service_destroy(svc);
@@ -495,6 +578,7 @@ int
mhash_test_file(scf_handle_t *hndl, const char *file, uint_t is_profile,
char **pnamep, uchar_t *hashbuf)
{
+ apply_action_t action;
boolean_t do_hash;
struct stat64 st;
char *cp;
@@ -506,6 +590,9 @@ mhash_test_file(scf_handle_t *hndl, const char *file, uint_t is_profile,
int hashash;
int metahashok = 0;
+ if (pnamep)
+ *pnamep = NULL;
+
/*
* In the case where we are doing automated imports, we reduce the UID,
* the GID, the size, and the mtime into a string (to eliminate
@@ -542,8 +629,6 @@ mhash_test_file(scf_handle_t *hndl, const char *file, uint_t is_profile,
cp = getenv("SVCCFG_CHECKHASH");
do_hash = (cp != NULL && *cp != '\0');
if (!do_hash) {
- if (pnamep != NULL)
- *pnamep = NULL;
return (MHASH_NEWFILE);
}
@@ -551,12 +636,25 @@ mhash_test_file(scf_handle_t *hndl, const char *file, uint_t is_profile,
if (pname == NULL)
return (MHASH_FAILURE);
- hashash = mhash_retrieve_entry(hndl, pname, stored_hash) == 0;
+ hashash = mhash_retrieve_entry(hndl, pname, stored_hash, &action) == 0;
+ if (is_profile == 0) {
+ /* Actions other than APPLY_NONE are restricted to profiles. */
+ assert(action == APPLY_NONE);
+ }
- /* Never reread a profile. */
+ /*
+ * As a general rule, we do not reread a profile. The exception to
+ * this rule is when we are running as part of the manifest import
+ * service and the apply_late property is set to true.
+ */
if (hashash && is_profile) {
- uu_free(pname);
- return (MHASH_RECONCILED);
+ cp = getenv("SMF_FMRI");
+ if ((cp == NULL) ||
+ (strcmp(cp, SCF_INSTANCE_MI) != 0) ||
+ (action != APPLY_LATE)) {
+ uu_free(pname);
+ return (MHASH_RECONCILED);
+ }
}
/*
@@ -604,8 +702,15 @@ mhash_test_file(scf_handle_t *hndl, const char *file, uint_t is_profile,
*/
for (i = 0; i < MD5_DIGEST_LENGTH; i++) {
if (stored_hash[MD5_DIGEST_LENGTH+i] != 0) {
- uu_free(pname);
- return (MHASH_RECONCILED);
+ if (action == APPLY_LATE) {
+ if (pnamep != NULL)
+ *pnamep = pname;
+ ret = MHASH_NEWFILE;
+ } else {
+ uu_free(pname);
+ ret = MHASH_RECONCILED;
+ }
+ return (ret);
}
}
}
@@ -631,9 +736,17 @@ 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, file, hash, NULL);
- uu_free(pname);
- return (MHASH_RECONCILED);
+ (void) mhash_store_entry(hndl, pname, file, hash,
+ APPLY_NONE, NULL);
+ if (action == APPLY_LATE) {
+ if (pnamep != NULL)
+ *pnamep = pname;
+ ret = MHASH_NEWFILE;
+ } else {
+ uu_free(pname);
+ ret = MHASH_RECONCILED;
+ }
+ return (ret);
}
/*
@@ -655,7 +768,8 @@ 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, file, hash, NULL);
+ (void) mhash_store_entry(hndl, pname, file, hash,
+ APPLY_NONE, 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 1a43137e44..4f2688aab0 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -41,7 +41,8 @@ extern "C" {
#define MHASH_PG_TYPE "framework"
#define MHASH_PG_FLAGS 0
#define MHASH_PROP "md5sum"
-#define MFILE_PROP "manifestfile"
+#define MHASH_FILE_PROP "manifestfile"
+#define MHASH_APPLY_PROP "apply_late"
#define MHASH_FORMAT_V1 "%llx%x%llx%lx"
#define MHASH_FORMAT_V2 "%x%x%llx%lx"
@@ -50,10 +51,16 @@ extern "C" {
#define MHASH_RECONCILED (1)
#define MHASH_FAILURE (-1)
+typedef enum apply_action {
+ APPLY_NONE, /* No special apply action. */
+ APPLY_LATE /* Apply profile in late manifest import. */
+} apply_action_t;
+
char *mhash_filename_to_propname(const char *, boolean_t);
-int mhash_retrieve_entry(scf_handle_t *, const char *, uchar_t *);
+int mhash_retrieve_entry(scf_handle_t *, const char *, uchar_t *,
+ apply_action_t *);
int mhash_store_entry(scf_handle_t *, const char *, const char *, uchar_t *,
- char **);
+ apply_action_t, char **);
int mhash_test_file(scf_handle_t *, const char *, uint_t, char **, uchar_t *);
#ifdef __cplusplus