diff options
| author | Tom Whitten <Thomas.Whitten@Sun.COM> | 2010-03-25 14:57:35 -0700 |
|---|---|---|
| committer | Tom Whitten <Thomas.Whitten@Sun.COM> | 2010-03-25 14:57:35 -0700 |
| commit | 9444c26f4faabda140242c3986089704c4073ced (patch) | |
| tree | 9e367f2f58dc2b2daa66ea7d430e35d834d913b8 /usr/src/cmd/svc/common | |
| parent | e765faef9c0385c419aa16d67aa529de3c41ac01 (diff) | |
| download | illumos-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.c | 324 | ||||
| -rw-r--r-- | usr/src/cmd/svc/common/manifest_find.h | 59 | ||||
| -rw-r--r-- | usr/src/cmd/svc/common/manifest_hash.c | 158 | ||||
| -rw-r--r-- | usr/src/cmd/svc/common/manifest_hash.h | 15 |
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 |
