xref: /illumos-gate/usr/src/lib/libscf/common/scf_tmpl.c (revision f6e214c7418f43af38bd8c3a557e3d0a1d311cfa)
11f6eb021SLiane Praza /*
21f6eb021SLiane Praza  * CDDL HEADER START
31f6eb021SLiane Praza  *
41f6eb021SLiane Praza  * The contents of this file are subject to the terms of the
51f6eb021SLiane Praza  * Common Development and Distribution License (the "License").
61f6eb021SLiane Praza  * You may not use this file except in compliance with the License.
71f6eb021SLiane Praza  *
81f6eb021SLiane Praza  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91f6eb021SLiane Praza  * or http://www.opensolaris.org/os/licensing.
101f6eb021SLiane Praza  * See the License for the specific language governing permissions
111f6eb021SLiane Praza  * and limitations under the License.
121f6eb021SLiane Praza  *
131f6eb021SLiane Praza  * When distributing Covered Code, include this CDDL HEADER in each
141f6eb021SLiane Praza  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151f6eb021SLiane Praza  * If applicable, add the following below this CDDL HEADER, with the
161f6eb021SLiane Praza  * fields enclosed by brackets "[]" replaced with your own identifying
171f6eb021SLiane Praza  * information: Portions Copyright [yyyy] [name of copyright owner]
181f6eb021SLiane Praza  *
191f6eb021SLiane Praza  * CDDL HEADER END
201f6eb021SLiane Praza  */
211f6eb021SLiane Praza /*
22*f6e214c7SGavin Maltby  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
231f6eb021SLiane Praza  */
241f6eb021SLiane Praza 
251f6eb021SLiane Praza /*
261f6eb021SLiane Praza  * scf_tmpl.c
271f6eb021SLiane Praza  *
281f6eb021SLiane Praza  * This file implements the bulk of the libscf templates interfaces.
291f6eb021SLiane Praza  * Templates describe metadata about a service or instance in general,
301f6eb021SLiane Praza  * and individual configuration properties on those services and instances.
311f6eb021SLiane Praza  * Human-consumable descriptions can be provided, along with definitions
321f6eb021SLiane Praza  * of valid configuration.  See service_bundle.dtd.1 for XML definitions
331f6eb021SLiane Praza  * of templates, and the svccfg code for information on how those definitions
341f6eb021SLiane Praza  * are translated into the repository.
351f6eb021SLiane Praza  *
361f6eb021SLiane Praza  * The main data structures are scf_pg_tmpl and scf_prop_tmpl.  These
371f6eb021SLiane Praza  * are allocated by the callers through scf_tmpl_[pg|prop]_create(), and
381f6eb021SLiane Praza  * destroyed with scf_tmpl_[pg|prop]_destroy().  They are populated by
391f6eb021SLiane Praza  * scf_tmpl_get_by_pg_name(), scf_tmpl_get_by_pg(), and
401f6eb021SLiane Praza  * scf_tmpl_get_by_prop().  They also store the iterator state for
411f6eb021SLiane Praza  * scf_tmpl_iter_pgs() and scf_tmpl_iter_props().
421f6eb021SLiane Praza  *
431f6eb021SLiane Praza  * These data structures are then consumed by other functions to
441f6eb021SLiane Praza  * gather information about the template (e.g. name, description,
451f6eb021SLiane Praza  * choices, constraints, etc.).
461f6eb021SLiane Praza  *
471f6eb021SLiane Praza  * scf_tmpl_validate_fmri() does instance validation against template
481f6eb021SLiane Praza  * data, and populates a set of template errors which can be explored using
491f6eb021SLiane Praza  * the scf_tmpl_next_error() and the scf_tmpl_error*() suite of functions.
501f6eb021SLiane Praza  *
511f6eb021SLiane Praza  * The main data structures for template errors are scf_tmpl_errors,
521f6eb021SLiane Praza  * defined in this file, and scf_tmpl_error, defined in libscf_priv.h.
531f6eb021SLiane Praza  * scf_tmpl_error is shared with svccfg to offer common printing
541f6eb021SLiane Praza  * of error messages between libscf and svccfg.
551f6eb021SLiane Praza  *
561f6eb021SLiane Praza  * General convenience functions are towards the top of this file,
571f6eb021SLiane Praza  * followed by pg and prop template discovery functions, followed
581f6eb021SLiane Praza  * by functions which gather information about the discovered
591f6eb021SLiane Praza  * template.  Validation and error functions are at the end of this file.
601f6eb021SLiane Praza  */
611f6eb021SLiane Praza 
621f6eb021SLiane Praza #include "lowlevel_impl.h"
631f6eb021SLiane Praza #include "libscf_impl.h"
641f6eb021SLiane Praza #include <assert.h>
651f6eb021SLiane Praza #include <errno.h>
661f6eb021SLiane Praza #include <libintl.h>
671f6eb021SLiane Praza #include <stdlib.h>
681f6eb021SLiane Praza #include <stdio.h>
691f6eb021SLiane Praza #include <strings.h>
701f6eb021SLiane Praza #include <locale.h>
711f6eb021SLiane Praza #include <ctype.h>
721f6eb021SLiane Praza #include <inttypes.h>
731f6eb021SLiane Praza 
741f6eb021SLiane Praza #define	SCF_TMPL_PG_COMMON_NAME_C	"common_name_C"
751f6eb021SLiane Praza 
761f6eb021SLiane Praza #define	SCF__TMPL_ITER_NONE		0
771f6eb021SLiane Praza #define	SCF__TMPL_ITER_INST		1
781f6eb021SLiane Praza #define	SCF__TMPL_ITER_RESTARTER	2
791f6eb021SLiane Praza #define	SCF__TMPL_ITER_GLOBAL		3
801f6eb021SLiane Praza 
811f6eb021SLiane Praza #define	SCF_TMPL_PG_NT		0
821f6eb021SLiane Praza #define	SCF_TMPL_PG_N		1
831f6eb021SLiane Praza #define	SCF_TMPL_PG_T		2
841f6eb021SLiane Praza #define	SCF_TMPL_PG_WILD	3
851f6eb021SLiane Praza 
861f6eb021SLiane Praza struct scf_pg_tmpl {
871f6eb021SLiane Praza 	int pt_populated;
881f6eb021SLiane Praza 	scf_handle_t *pt_h;
891f6eb021SLiane Praza 	scf_propertygroup_t *pt_pg;
901f6eb021SLiane Praza 	scf_service_t *pt_orig_svc;
911f6eb021SLiane Praza 	scf_service_t *pt_svc;
921f6eb021SLiane Praza 	scf_instance_t *pt_orig_inst;
931f6eb021SLiane Praza 	scf_instance_t *pt_inst;
941f6eb021SLiane Praza 	scf_snapshot_t *pt_snap;
951f6eb021SLiane Praza 	int pt_is_iter;
961f6eb021SLiane Praza 	scf_iter_t *pt_iter;
971f6eb021SLiane Praza 	int pt_iter_last;
981f6eb021SLiane Praza };
991f6eb021SLiane Praza 
1001f6eb021SLiane Praza #define	SCF_WALK_ERROR		-1
1011f6eb021SLiane Praza #define	SCF_WALK_NEXT		0
1021f6eb021SLiane Praza #define	SCF_WALK_DONE		1
1031f6eb021SLiane Praza 
1041f6eb021SLiane Praza struct pg_tmpl_walk {
1051f6eb021SLiane Praza 	const char *pw_snapname;
1061f6eb021SLiane Praza 	const char *pw_pgname;
1071f6eb021SLiane Praza 	const char *pw_pgtype;
1081f6eb021SLiane Praza 	scf_instance_t *pw_inst;
1091f6eb021SLiane Praza 	scf_service_t *pw_svc;
1101f6eb021SLiane Praza 	scf_snapshot_t *pw_snap;
1111f6eb021SLiane Praza 	scf_propertygroup_t *pw_pg;
1121f6eb021SLiane Praza 	const char *pw_target;
1131f6eb021SLiane Praza 	char *pw_tmpl_pgname;
1141f6eb021SLiane Praza };
1151f6eb021SLiane Praza 
1161f6eb021SLiane Praza typedef struct pg_tmpl_walk pg_tmpl_walk_t;
1171f6eb021SLiane Praza 
1181f6eb021SLiane Praza typedef int walk_template_inst_func_t(scf_service_t *_svc,
1191f6eb021SLiane Praza     scf_instance_t *_inst, pg_tmpl_walk_t *p);
1201f6eb021SLiane Praza 
1211f6eb021SLiane Praza struct scf_prop_tmpl {
1221f6eb021SLiane Praza 	int prt_populated;
1231f6eb021SLiane Praza 	scf_handle_t *prt_h;
1241f6eb021SLiane Praza 	scf_pg_tmpl_t *prt_t;
1251f6eb021SLiane Praza 	scf_propertygroup_t *prt_pg;
1261f6eb021SLiane Praza 	char *prt_pg_name;
1271f6eb021SLiane Praza 	scf_iter_t *prt_iter;
1281f6eb021SLiane Praza };
1291f6eb021SLiane Praza 
1301f6eb021SLiane Praza /*
1311f6eb021SLiane Praza  * Common server errors are usually passed back to the caller.  This
1321f6eb021SLiane Praza  * array defines them centrally so that they don't need to be enumerated
1331f6eb021SLiane Praza  * in every libscf call.
1341f6eb021SLiane Praza  */
1351f6eb021SLiane Praza static const scf_error_t errors_server[] = {
1361f6eb021SLiane Praza 	SCF_ERROR_BACKEND_ACCESS,
1371f6eb021SLiane Praza 	SCF_ERROR_CONNECTION_BROKEN,
1381f6eb021SLiane Praza 	SCF_ERROR_DELETED,
1391f6eb021SLiane Praza 	SCF_ERROR_HANDLE_DESTROYED,
1401f6eb021SLiane Praza 	SCF_ERROR_INTERNAL,
1411f6eb021SLiane Praza 	SCF_ERROR_NO_MEMORY,
1421f6eb021SLiane Praza 	SCF_ERROR_NO_RESOURCES,
1431f6eb021SLiane Praza 	SCF_ERROR_NOT_BOUND,
1441f6eb021SLiane Praza 	SCF_ERROR_PERMISSION_DENIED,
1451f6eb021SLiane Praza 	0
1461f6eb021SLiane Praza 	};
1471f6eb021SLiane Praza 
1481f6eb021SLiane Praza /*
1491f6eb021SLiane Praza  * int ismember()
1501f6eb021SLiane Praza  *
1511f6eb021SLiane Praza  * Returns 1 if the supplied error is a member of the error array, 0
1521f6eb021SLiane Praza  * if it is not.
1531f6eb021SLiane Praza  */
154*f6e214c7SGavin Maltby int
155*f6e214c7SGavin Maltby ismember(const scf_error_t error, const scf_error_t error_array[])
1561f6eb021SLiane Praza {
1571f6eb021SLiane Praza 	int i;
1581f6eb021SLiane Praza 
1591f6eb021SLiane Praza 	for (i = 0; error_array[i] != 0; ++i) {
1601f6eb021SLiane Praza 		if (error == error_array[i])
1611f6eb021SLiane Praza 			return (1);
1621f6eb021SLiane Praza 	}
1631f6eb021SLiane Praza 
1641f6eb021SLiane Praza 	return (0);
1651f6eb021SLiane Praza }
1661f6eb021SLiane Praza 
1671f6eb021SLiane Praza /*
1681f6eb021SLiane Praza  * char *_scf_tmpl_get_fmri()
1691f6eb021SLiane Praza  *
1701f6eb021SLiane Praza  * Given a pg_tmpl, returns the FMRI of the service or instance that
1711f6eb021SLiane Praza  * template describes.  The allocated string must be freed with free().
1721f6eb021SLiane Praza  *
1731f6eb021SLiane Praza  * On failure, returns NULL and sets scf_error() to _CONNECTION_BROKEN,
1741f6eb021SLiane Praza  * _DELETED, or _NO_MEMORY.
1751f6eb021SLiane Praza  */
1761f6eb021SLiane Praza static char *
1771f6eb021SLiane Praza _scf_tmpl_get_fmri(const scf_pg_tmpl_t *t)
1781f6eb021SLiane Praza {
1791f6eb021SLiane Praza 	ssize_t sz = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH) + 1;
1801f6eb021SLiane Praza 	int r;
1811f6eb021SLiane Praza 	char *buf = malloc(sz);
1821f6eb021SLiane Praza 
1831f6eb021SLiane Praza 	assert(t->pt_svc != NULL || t->pt_inst != NULL);
1841f6eb021SLiane Praza 	assert(t->pt_svc == NULL || t->pt_inst == NULL);
1851f6eb021SLiane Praza 
1861f6eb021SLiane Praza 	if (buf == NULL) {
1871f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
1881f6eb021SLiane Praza 		return (buf);
1891f6eb021SLiane Praza 	}
1901f6eb021SLiane Praza 
1911f6eb021SLiane Praza 	if (t->pt_inst != NULL)
1921f6eb021SLiane Praza 		r = scf_instance_to_fmri(t->pt_inst, buf, sz);
1931f6eb021SLiane Praza 	else
1941f6eb021SLiane Praza 		r = scf_service_to_fmri(t->pt_svc, buf, sz);
1951f6eb021SLiane Praza 
1961f6eb021SLiane Praza 	if (r == -1) {
1971f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
1981f6eb021SLiane Praza 			free(buf);
1991f6eb021SLiane Praza 			buf = NULL;
2001f6eb021SLiane Praza 		} else {
2011f6eb021SLiane Praza 			assert(0);
2021f6eb021SLiane Praza 			abort();
2031f6eb021SLiane Praza 		}
2041f6eb021SLiane Praza 	}
2051f6eb021SLiane Praza 
2061f6eb021SLiane Praza 	return (buf);
2071f6eb021SLiane Praza }
2081f6eb021SLiane Praza 
2091f6eb021SLiane Praza /*
2101f6eb021SLiane Praza  * char *_scf_get_pg_type()
2111f6eb021SLiane Praza  *
2121f6eb021SLiane Praza  * Given a propertygroup, returns an allocated string containing the
2131f6eb021SLiane Praza  * type.  The string must be freed with free().
2141f6eb021SLiane Praza  *
2151f6eb021SLiane Praza  * On failure, returns NULL and sets scf_error() to: _CONNECTION_BROKEN,
2161f6eb021SLiane Praza  * _DELETED, or _NO_MEMORY.
2171f6eb021SLiane Praza  */
2181f6eb021SLiane Praza static char *
2191f6eb021SLiane Praza _scf_get_pg_type(scf_propertygroup_t *pg)
2201f6eb021SLiane Praza {
2211f6eb021SLiane Praza 	ssize_t sz = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH) + 1;
2221f6eb021SLiane Praza 	char *buf = malloc(sz);
2231f6eb021SLiane Praza 
2241f6eb021SLiane Praza 	if (buf == NULL) {
2251f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
2261f6eb021SLiane Praza 	} else if (scf_pg_get_type(pg, buf, sz) == -1) {
2271f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
2281f6eb021SLiane Praza 			free(buf);
2291f6eb021SLiane Praza 			buf = NULL;
2301f6eb021SLiane Praza 		} else {
2311f6eb021SLiane Praza 			assert(0);
2321f6eb021SLiane Praza 			abort();
2331f6eb021SLiane Praza 		}
2341f6eb021SLiane Praza 	}
2351f6eb021SLiane Praza 
2361f6eb021SLiane Praza 	return (buf);
2371f6eb021SLiane Praza }
2381f6eb021SLiane Praza 
2391f6eb021SLiane Praza /*
2401f6eb021SLiane Praza  * char *_scf_get_prop_name()
2411f6eb021SLiane Praza  *
2421f6eb021SLiane Praza  * Given a property, returns the name in an allocated string.  The string must
2431f6eb021SLiane Praza  * be freed with free().
2441f6eb021SLiane Praza  *
2451f6eb021SLiane Praza  * On error, returns NULL and sets scf_error() to _CONNECTION_BROKEN,
2461f6eb021SLiane Praza  * _DELETED, or _NO_MEMORY.
2471f6eb021SLiane Praza  */
2481f6eb021SLiane Praza static char *
2491f6eb021SLiane Praza _scf_get_prop_name(scf_property_t *prop)
2501f6eb021SLiane Praza {
2511f6eb021SLiane Praza 	ssize_t sz = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
2521f6eb021SLiane Praza 	char *buf = malloc(sz);
2531f6eb021SLiane Praza 
2541f6eb021SLiane Praza 	if (buf == NULL) {
2551f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
2561f6eb021SLiane Praza 	} else if (scf_property_get_name(prop, buf, sz) == -1) {
2571f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
2581f6eb021SLiane Praza 			free(buf);
2591f6eb021SLiane Praza 			buf = NULL;
2601f6eb021SLiane Praza 		} else {
2611f6eb021SLiane Praza 			assert(0);
2621f6eb021SLiane Praza 			abort();
2631f6eb021SLiane Praza 		}
2641f6eb021SLiane Praza 	}
2651f6eb021SLiane Praza 
2661f6eb021SLiane Praza 	return (buf);
2671f6eb021SLiane Praza }
2681f6eb021SLiane Praza 
2691f6eb021SLiane Praza /*
2701f6eb021SLiane Praza  * char *_scf_get_prop_type()
2711f6eb021SLiane Praza  *
2721f6eb021SLiane Praza  * Given a property, returns the type in an allocated string.  The string must
2731f6eb021SLiane Praza  * be freed with free().
2741f6eb021SLiane Praza  *
2751f6eb021SLiane Praza  * On error, returns NULL and sets scf_error() to _CONNECTION_BROKEN,
2761f6eb021SLiane Praza  * _DELETED, or _NO_MEMORY.
2771f6eb021SLiane Praza  */
2781f6eb021SLiane Praza static char *
2791f6eb021SLiane Praza _scf_get_prop_type(scf_property_t *prop)
2801f6eb021SLiane Praza {
2811f6eb021SLiane Praza 	scf_type_t type;
2821f6eb021SLiane Praza 	char *ret;
2831f6eb021SLiane Praza 
2841f6eb021SLiane Praza 	if (scf_property_type(prop, &type) == -1) {
2851f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
2861f6eb021SLiane Praza 			return (NULL);
2871f6eb021SLiane Praza 		} else {
2881f6eb021SLiane Praza 			assert(0);
2891f6eb021SLiane Praza 			abort();
2901f6eb021SLiane Praza 		}
2911f6eb021SLiane Praza 	}
2921f6eb021SLiane Praza 
2931f6eb021SLiane Praza 	ret = strdup(scf_type_to_string(type));
2941f6eb021SLiane Praza 	if (ret == NULL)
2951f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
2961f6eb021SLiane Praza 
2971f6eb021SLiane Praza 	return (ret);
2981f6eb021SLiane Praza }
2991f6eb021SLiane Praza 
3001f6eb021SLiane Praza /*
3011f6eb021SLiane Praza  * int _read_single_value_from_pg()
3021f6eb021SLiane Praza  *
3031f6eb021SLiane Praza  * Reads a single value from the pg and property name specified.  On success,
3041f6eb021SLiane Praza  * returns an allocated value that must be freed.
3051f6eb021SLiane Praza  *
3061f6eb021SLiane Praza  * Returns -1 on failure, sets scf_error() to:
3071f6eb021SLiane Praza  *  SCF_ERROR_BACKEND_ACCESS
3081f6eb021SLiane Praza  *  SCF_ERROR_CONNECTION_BROKEN
3091f6eb021SLiane Praza  *  SCF_ERROR_CONSTRAINT_VIOLATED
3101f6eb021SLiane Praza  *    Property has more than one value associated with it.
3111f6eb021SLiane Praza  *  SCF_ERROR_DELETED
3121f6eb021SLiane Praza  *  SCF_ERROR_HANDLE_DESTROYED
3131f6eb021SLiane Praza  *  SCF_ERROR_INTERNAL
3141f6eb021SLiane Praza  *  SCF_ERROR_INVALID_ARGUMENT
3151f6eb021SLiane Praza  *    prop_name not a valid property name.
3161f6eb021SLiane Praza  *  SCF_ERROR_NO_MEMORY
3171f6eb021SLiane Praza  *  SCF_ERROR_NO_RESOURCES
3181f6eb021SLiane Praza  *  SCF_ERROR_NOT_BOUND
3191f6eb021SLiane Praza  *  SCF_ERROR_NOT_FOUND
3201f6eb021SLiane Praza  *    Property doesn't exist or exists and has no value.
3211f6eb021SLiane Praza  *  SCF_ERROR_NOT_SET
3221f6eb021SLiane Praza  *    Property group specified by pg is not set.
3231f6eb021SLiane Praza  *  SCF_ERROR_PERMISSION_DENIED
3241f6eb021SLiane Praza  */
3251f6eb021SLiane Praza static int
3261f6eb021SLiane Praza _read_single_value_from_pg(scf_propertygroup_t *pg, const char *prop_name,
3271f6eb021SLiane Praza     scf_value_t **val)
3281f6eb021SLiane Praza {
3291f6eb021SLiane Praza 	scf_handle_t *h;
3301f6eb021SLiane Praza 	scf_property_t *prop;
3311f6eb021SLiane Praza 	int ret = 0;
3321f6eb021SLiane Praza 
3331f6eb021SLiane Praza 	assert(val != NULL);
3341f6eb021SLiane Praza 	if ((h = scf_pg_handle(pg)) == NULL) {
3351f6eb021SLiane Praza 		assert(scf_error() == SCF_ERROR_HANDLE_DESTROYED);
3361f6eb021SLiane Praza 		return (-1);
3371f6eb021SLiane Praza 	}
3381f6eb021SLiane Praza 
3391f6eb021SLiane Praza 	prop = scf_property_create(h);
3401f6eb021SLiane Praza 	*val = scf_value_create(h);
3411f6eb021SLiane Praza 
3421f6eb021SLiane Praza 	if (prop == NULL || *val == NULL) {
3431f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_INVALID_ARGUMENT);
3441f6eb021SLiane Praza 		goto read_single_value_from_pg_fail;
3451f6eb021SLiane Praza 	}
3461f6eb021SLiane Praza 
3471f6eb021SLiane Praza 	if (scf_pg_get_property(pg, prop_name, prop) != 0) {
3481f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_HANDLE_MISMATCH);
3491f6eb021SLiane Praza 		goto read_single_value_from_pg_fail;
3501f6eb021SLiane Praza 	}
3511f6eb021SLiane Praza 
3521f6eb021SLiane Praza 	if (scf_property_get_value(prop, *val) == -1) {
3531f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_NOT_SET);
3541f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_HANDLE_MISMATCH);
3551f6eb021SLiane Praza 		goto read_single_value_from_pg_fail;
3561f6eb021SLiane Praza 	}
3571f6eb021SLiane Praza 
3581f6eb021SLiane Praza 	goto read_single_value_from_pg_done;
3591f6eb021SLiane Praza 
3601f6eb021SLiane Praza read_single_value_from_pg_fail:
3611f6eb021SLiane Praza 	scf_value_destroy(*val);
3621f6eb021SLiane Praza 	*val = NULL;
3631f6eb021SLiane Praza 	ret = -1;
3641f6eb021SLiane Praza 
3651f6eb021SLiane Praza read_single_value_from_pg_done:
3661f6eb021SLiane Praza 	scf_property_destroy(prop);
3671f6eb021SLiane Praza 	return (ret);
3681f6eb021SLiane Praza }
3691f6eb021SLiane Praza 
3701f6eb021SLiane Praza /*
3711f6eb021SLiane Praza  * char *_scf_read_single_astring_from_pg()
3721f6eb021SLiane Praza  *
3731f6eb021SLiane Praza  * Reads an astring from the pg and property name specified.  On success,
3741f6eb021SLiane Praza  * returns an allocated string.  The string must be freed with free().
3751f6eb021SLiane Praza  *
3761f6eb021SLiane Praza  * Returns NULL on failure, sets scf_error() to:
3771f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
3781f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
3791f6eb021SLiane Praza  *   SCF_ERROR_CONSTRAINT_VIOLATED
3801f6eb021SLiane Praza  *     Property has more than one value associated with it.
3811f6eb021SLiane Praza  *   SCF_ERROR_DELETED
3821f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
3831f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
3841f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
3851f6eb021SLiane Praza  *     prop_name not a valid property name.
3861f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
3871f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
3881f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
3891f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
3901f6eb021SLiane Praza  *     Property doesn't exist or exists and has no value.
3911f6eb021SLiane Praza  *   SCF_ERROR_NOT_SET
3921f6eb021SLiane Praza  *     The property group specified by pg is not set.
3931f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
3941f6eb021SLiane Praza  *   SCF_ERROR_TYPE_MISMATCH
3951f6eb021SLiane Praza  */
3961f6eb021SLiane Praza char *
3971f6eb021SLiane Praza _scf_read_single_astring_from_pg(scf_propertygroup_t *pg, const char *prop_name)
3981f6eb021SLiane Praza {
3991f6eb021SLiane Praza 	scf_value_t *val;
4001f6eb021SLiane Praza 	char *ret = NULL;
4011f6eb021SLiane Praza 	ssize_t rsize = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH) + 1;
4021f6eb021SLiane Praza 
4031f6eb021SLiane Praza 	assert(rsize != 0);
4041f6eb021SLiane Praza 	if (_read_single_value_from_pg(pg, prop_name, &val) == -1)
4051f6eb021SLiane Praza 		return (NULL);
4061f6eb021SLiane Praza 
4071f6eb021SLiane Praza 	ret = malloc(rsize);
4081f6eb021SLiane Praza 	if (ret == NULL) {
4091f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
4101f6eb021SLiane Praza 		goto cleanup;
4111f6eb021SLiane Praza 	}
4121f6eb021SLiane Praza 
4131f6eb021SLiane Praza 	if (scf_value_get_astring(val, ret, rsize) < 0) {
4141f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_NOT_SET);
4151f6eb021SLiane Praza 		free(ret);
4161f6eb021SLiane Praza 		ret = NULL;
4171f6eb021SLiane Praza 	}
4181f6eb021SLiane Praza 
4191f6eb021SLiane Praza cleanup:
4201f6eb021SLiane Praza 	scf_value_destroy(val);
4211f6eb021SLiane Praza 	return (ret);
4221f6eb021SLiane Praza }
4231f6eb021SLiane Praza 
4241f6eb021SLiane Praza /*
4251f6eb021SLiane Praza  * char *_scf_read_tmpl_prop_type_as_string()
4261f6eb021SLiane Praza  *
4271f6eb021SLiane Praza  * Reads the property type and returns it as an allocated string.  The string
4281f6eb021SLiane Praza  * must be freed with free().
4291f6eb021SLiane Praza  *
4301f6eb021SLiane Praza  * Returns NULL on failure, sets scf_error() to _BACKEND_ACCESS,
4311f6eb021SLiane Praza  * _CONNECTION_BROKEN, _DELETED, _HANDLE_DESTROYED, _INTERNAL, _NO_MEMORY,
4321f6eb021SLiane Praza  * _NO_RESOURCES, _NOT_BOUND, _PERMISSION_DENIED, or _TEMPLATE_INVALID.
4331f6eb021SLiane Praza  */
4341f6eb021SLiane Praza char *
4351f6eb021SLiane Praza _scf_read_tmpl_prop_type_as_string(const scf_prop_tmpl_t *pt)
4361f6eb021SLiane Praza {
4371f6eb021SLiane Praza 	char *type;
4381f6eb021SLiane Praza 
4391f6eb021SLiane Praza 	type = _scf_read_single_astring_from_pg(pt->prt_pg,
4401f6eb021SLiane Praza 	    SCF_PROPERTY_TM_TYPE);
4411f6eb021SLiane Praza 	if (type == NULL) {
4421f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
4431f6eb021SLiane Praza 			return (NULL);
4441f6eb021SLiane Praza 		} else switch (scf_error()) {
4451f6eb021SLiane Praza 		case SCF_ERROR_CONSTRAINT_VIOLATED:
4461f6eb021SLiane Praza 		case SCF_ERROR_NOT_FOUND:
4471f6eb021SLiane Praza 		case SCF_ERROR_TYPE_MISMATCH:
4481f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
4491f6eb021SLiane Praza 			return (NULL);
4501f6eb021SLiane Praza 
4511f6eb021SLiane Praza 		case SCF_ERROR_INVALID_ARGUMENT:
4521f6eb021SLiane Praza 		case SCF_ERROR_NOT_SET:
4531f6eb021SLiane Praza 		default:
4541f6eb021SLiane Praza 			assert(0);
4551f6eb021SLiane Praza 			abort();
4561f6eb021SLiane Praza 		}
4571f6eb021SLiane Praza 	}
4581f6eb021SLiane Praza 
4591f6eb021SLiane Praza 	return (type);
4601f6eb021SLiane Praza }
4611f6eb021SLiane Praza 
4621f6eb021SLiane Praza /*
4631f6eb021SLiane Praza  * int _read_single_boolean_from_pg()
4641f6eb021SLiane Praza  *
4651f6eb021SLiane Praza  * Reads a boolean from the pg and property name specified.
4661f6eb021SLiane Praza  *
4671f6eb021SLiane Praza  * Returns -1 on failure, sets scf_error() to:
4681f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
4691f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
4701f6eb021SLiane Praza  *   SCF_ERROR_CONSTRAINT_VIOLATED
4711f6eb021SLiane Praza  *     Property has more than one value associated with it.
4721f6eb021SLiane Praza  *   SCF_ERROR_DELETED
4731f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
4741f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
4751f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
4761f6eb021SLiane Praza  *     prop_name is not a valid property name.
4771f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
4781f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
4791f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
4801f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
4811f6eb021SLiane Praza  *     Property doesn't exist or exists and has no value.
4821f6eb021SLiane Praza  *   SCF_ERROR_NOT_SET
4831f6eb021SLiane Praza  *     The property group specified by pg is not set.
4841f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
4851f6eb021SLiane Praza  *   SCF_ERROR_TYPE_MISMATCH
4861f6eb021SLiane Praza  */
4871f6eb021SLiane Praza static int
4881f6eb021SLiane Praza _read_single_boolean_from_pg(scf_propertygroup_t *pg, const char *prop_name,
4891f6eb021SLiane Praza     uint8_t *bool)
4901f6eb021SLiane Praza {
4911f6eb021SLiane Praza 	scf_value_t *val;
4921f6eb021SLiane Praza 	int ret = 0;
4931f6eb021SLiane Praza 
4941f6eb021SLiane Praza 	if (_read_single_value_from_pg(pg, prop_name, &val) == -1)
4951f6eb021SLiane Praza 		return (-1);
4961f6eb021SLiane Praza 
4971f6eb021SLiane Praza 	if (scf_value_get_boolean(val, bool) < 0) {
4981f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_NOT_SET);
4991f6eb021SLiane Praza 		ret = -1;
5001f6eb021SLiane Praza 	}
5011f6eb021SLiane Praza 
5021f6eb021SLiane Praza 	scf_value_destroy(val);
5031f6eb021SLiane Praza 	return (ret);
5041f6eb021SLiane Praza }
5051f6eb021SLiane Praza 
5061f6eb021SLiane Praza /*
507*f6e214c7SGavin Maltby  * static char ** _append_astrings_values()
5081f6eb021SLiane Praza  *
5091f6eb021SLiane Praza  * This function reads the values from the property prop_name in pg and
5101f6eb021SLiane Praza  * appends to an existing scf_values_t *vals.  vals may be empty, but
5111f6eb021SLiane Praza  * must exist.  The function skips over zero-length and duplicate values.
5121f6eb021SLiane Praza  *
5131f6eb021SLiane Praza  * Returns NULL on failure, sets scf_error() to:
5141f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
5151f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
5161f6eb021SLiane Praza  *   SCF_ERROR_DELETED
5171f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
5181f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
5191f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
5201f6eb021SLiane Praza  *     prop_name is not a valid property name.
5211f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
5221f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
5231f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
5241f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
5251f6eb021SLiane Praza  *   SCF_ERROR_NOT_SET
5261f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
5271f6eb021SLiane Praza  *   SCF_ERROR_TYPE_MISMATCH
5281f6eb021SLiane Praza  */
5291f6eb021SLiane Praza static char **
5301f6eb021SLiane Praza _append_astrings_values(scf_propertygroup_t *pg, const char *prop_name,
5311f6eb021SLiane Praza     scf_values_t *vals)
5321f6eb021SLiane Praza {
5331f6eb021SLiane Praza 	scf_handle_t *h;
5341f6eb021SLiane Praza 	scf_property_t *prop;
5351f6eb021SLiane Praza 	scf_value_t *val;
5361f6eb021SLiane Praza 	scf_iter_t *iter;
5371f6eb021SLiane Praza 	ssize_t rsize = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH) + 1;
5381f6eb021SLiane Praza 	int err, count, cursz, i;
5391f6eb021SLiane Praza 
5401f6eb021SLiane Praza 	assert(vals != NULL);
5411f6eb021SLiane Praza 	assert(vals->value_type == SCF_TYPE_ASTRING);
5421f6eb021SLiane Praza 	assert(vals->reserved == NULL);
5431f6eb021SLiane Praza 	count = vals->value_count;
5441f6eb021SLiane Praza 	if (count == 0) {
5451f6eb021SLiane Praza 		cursz = 8;
5461f6eb021SLiane Praza 		vals->values.v_astring = calloc(cursz, sizeof (char *));
5471f6eb021SLiane Praza 		if (vals->values.v_astring == NULL) {
5481f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
5491f6eb021SLiane Praza 			return (NULL);
5501f6eb021SLiane Praza 		}
5511f6eb021SLiane Praza 	} else {
5521f6eb021SLiane Praza 		/*
5531f6eb021SLiane Praza 		 * The array may be bigger, but it is irrelevant since
5541f6eb021SLiane Praza 		 * we will always re-allocate a new one.
5551f6eb021SLiane Praza 		 */
5561f6eb021SLiane Praza 		cursz = count;
5571f6eb021SLiane Praza 	}
5581f6eb021SLiane Praza 
5591f6eb021SLiane Praza 	if ((h = scf_pg_handle(pg)) == NULL) {
5601f6eb021SLiane Praza 		assert(scf_error() == SCF_ERROR_HANDLE_DESTROYED);
5611f6eb021SLiane Praza 		return (NULL);
5621f6eb021SLiane Praza 	}
5631f6eb021SLiane Praza 
5641f6eb021SLiane Praza 	prop = scf_property_create(h);
5651f6eb021SLiane Praza 	val = scf_value_create(h);
5661f6eb021SLiane Praza 	iter = scf_iter_create(h);
5671f6eb021SLiane Praza 
5681f6eb021SLiane Praza 	if (prop == NULL || val == NULL || iter == NULL) {
5691f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_INVALID_ARGUMENT);
5701f6eb021SLiane Praza 		goto append_single_astring_from_pg_fail;
5711f6eb021SLiane Praza 	}
5721f6eb021SLiane Praza 
5731f6eb021SLiane Praza 	if (scf_pg_get_property(pg, prop_name, prop) != 0) {
5741f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_HANDLE_MISMATCH);
5751f6eb021SLiane Praza 		goto append_single_astring_from_pg_fail;
5761f6eb021SLiane Praza 	}
5771f6eb021SLiane Praza 
5781f6eb021SLiane Praza 	if (scf_iter_property_values(iter, prop) != 0) {
5791f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_NOT_SET);
5801f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_HANDLE_MISMATCH);
5811f6eb021SLiane Praza 		goto append_single_astring_from_pg_fail;
5821f6eb021SLiane Praza 	}
5831f6eb021SLiane Praza 
5841f6eb021SLiane Praza 	while ((err = scf_iter_next_value(iter, val)) == 1) {
5851f6eb021SLiane Praza 		int flag;
5861f6eb021SLiane Praza 		int r;
5871f6eb021SLiane Praza 
5881f6eb021SLiane Praza 		if (count + 1 >= cursz) {
5891f6eb021SLiane Praza 			void *aux;
5901f6eb021SLiane Praza 
5911f6eb021SLiane Praza 			cursz *= 2;
5921f6eb021SLiane Praza 			if ((aux = calloc(cursz, sizeof (char *))) == NULL) {
5931f6eb021SLiane Praza 				(void) scf_set_error(SCF_ERROR_NO_MEMORY);
5941f6eb021SLiane Praza 				goto append_single_astring_from_pg_fail;
5951f6eb021SLiane Praza 			}
5961f6eb021SLiane Praza 			(void) memcpy(aux, vals->values.v_astring,
5971f6eb021SLiane Praza 			    count * sizeof (char *));
5981f6eb021SLiane Praza 			free(vals->values.v_astring);
5991f6eb021SLiane Praza 			vals->values.v_astring = aux;
6001f6eb021SLiane Praza 		}
6011f6eb021SLiane Praza 
6021f6eb021SLiane Praza 		vals->values.v_astring[count] = malloc(rsize);
6031f6eb021SLiane Praza 		if (vals->values.v_astring[count] == NULL) {
6041f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
6051f6eb021SLiane Praza 			goto append_single_astring_from_pg_fail;
6061f6eb021SLiane Praza 		}
6071f6eb021SLiane Praza 
6081f6eb021SLiane Praza 		if ((r = scf_value_get_astring(val,
6091f6eb021SLiane Praza 		    vals->values.v_astring[count], rsize)) <= 0) {
6101f6eb021SLiane Praza 			/* discard zero length strings */
6111f6eb021SLiane Praza 			if (r == 0) {
6121f6eb021SLiane Praza 				free(vals->values.v_astring[count]);
6131f6eb021SLiane Praza 				continue;
6141f6eb021SLiane Praza 			}
6151f6eb021SLiane Praza 			assert(scf_error() != SCF_ERROR_NOT_SET);
6161f6eb021SLiane Praza 			goto append_single_astring_from_pg_fail;
6171f6eb021SLiane Praza 		}
6181f6eb021SLiane Praza 		for (i = 0, flag = 0; i < count; ++i) {
6191f6eb021SLiane Praza 			/* find  and discard duplicates */
6201f6eb021SLiane Praza 			if (strncmp(vals->values.v_astring[i],
6211f6eb021SLiane Praza 			    vals->values.v_astring[count], rsize) == 0) {
6221f6eb021SLiane Praza 				free(vals->values.v_astring[count]);
6231f6eb021SLiane Praza 				flag = 1;
6241f6eb021SLiane Praza 				break;
6251f6eb021SLiane Praza 			}
6261f6eb021SLiane Praza 		}
6271f6eb021SLiane Praza 		if (flag == 1)
6281f6eb021SLiane Praza 			continue;
6291f6eb021SLiane Praza 
6301f6eb021SLiane Praza 		count++;
6311f6eb021SLiane Praza 	}
6321f6eb021SLiane Praza 
6331f6eb021SLiane Praza 	vals->value_count = count;
6341f6eb021SLiane Praza 
6351f6eb021SLiane Praza 	if (err != 0) {
6361f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_NOT_SET);
6371f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_INVALID_ARGUMENT);
6381f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_HANDLE_MISMATCH);
6391f6eb021SLiane Praza 		goto append_single_astring_from_pg_fail;
6401f6eb021SLiane Praza 	} else {
6411f6eb021SLiane Praza 		vals->values_as_strings = vals->values.v_astring;
6421f6eb021SLiane Praza 	}
6431f6eb021SLiane Praza 
6441f6eb021SLiane Praza 	goto append_single_astring_from_pg_done;
6451f6eb021SLiane Praza 
6461f6eb021SLiane Praza append_single_astring_from_pg_fail:
6471f6eb021SLiane Praza 	for (i = 0; i <= count; ++i) {
6481f6eb021SLiane Praza 		if (vals->values.v_astring[i] != NULL)
6491f6eb021SLiane Praza 			free(vals->values.v_astring[i]);
6501f6eb021SLiane Praza 		vals->values.v_astring[i] = NULL;
6511f6eb021SLiane Praza 	}
6521f6eb021SLiane Praza 	free(vals->values.v_astring);
6531f6eb021SLiane Praza 	vals->values.v_astring = NULL;
6541f6eb021SLiane Praza 	vals->value_count = 0;
6551f6eb021SLiane Praza 
6561f6eb021SLiane Praza append_single_astring_from_pg_done:
6571f6eb021SLiane Praza 	scf_iter_destroy(iter);
6581f6eb021SLiane Praza 	scf_property_destroy(prop);
6591f6eb021SLiane Praza 	scf_value_destroy(val);
6601f6eb021SLiane Praza 	return (vals->values.v_astring);
6611f6eb021SLiane Praza }
6621f6eb021SLiane Praza 
6631f6eb021SLiane Praza /*
6641f6eb021SLiane Praza  * Returns NULL on failure, sets scf_error() to:
6651f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
6661f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
6671f6eb021SLiane Praza  *   SCF_ERROR_DELETED
6681f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
6691f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
6701f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
6711f6eb021SLiane Praza  *     prop_name is not a valid property name.
6721f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
6731f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
6741f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
6751f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
6761f6eb021SLiane Praza  *   SCF_ERROR_NOT_SET
6771f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
6781f6eb021SLiane Praza  *   SCF_ERROR_TYPE_MISMATCH
6791f6eb021SLiane Praza  */
6801f6eb021SLiane Praza static char **
6811f6eb021SLiane Praza _read_astrings_values(scf_propertygroup_t *pg, const char *prop_name,
6821f6eb021SLiane Praza     scf_values_t *vals)
6831f6eb021SLiane Praza {
6841f6eb021SLiane Praza 	assert(vals != NULL);
6851f6eb021SLiane Praza 	vals->value_count = 0;
6861f6eb021SLiane Praza 	vals->value_type = SCF_TYPE_ASTRING;
6871f6eb021SLiane Praza 	vals->reserved = NULL;
6881f6eb021SLiane Praza 	return (_append_astrings_values(pg, prop_name, vals));
6891f6eb021SLiane Praza }
6901f6eb021SLiane Praza 
6911f6eb021SLiane Praza void
6921f6eb021SLiane Praza _scf_sanitize_locale(char *locale)
6931f6eb021SLiane Praza {
6941f6eb021SLiane Praza 	for (; *locale != '\0'; locale++)
6951f6eb021SLiane Praza 		if (!isalnum(*locale) && *locale != '_')
6961f6eb021SLiane Praza 			*locale = '_';
6971f6eb021SLiane Praza }
6981f6eb021SLiane Praza 
6991f6eb021SLiane Praza /*
7001f6eb021SLiane Praza  * The returned string needs to be freed by the caller
7011f6eb021SLiane Praza  * Returns NULL on failure.  Sets scf_error() to:
7021f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
7031f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
7041f6eb021SLiane Praza  *     Name isn't short enough to add the locale to.
7051f6eb021SLiane Praza  */
7061f6eb021SLiane Praza static char *
7071f6eb021SLiane Praza _add_locale_to_name(const char *name, const char *locale)
7081f6eb021SLiane Praza {
7091f6eb021SLiane Praza 	char *lname = NULL;
7101f6eb021SLiane Praza 	ssize_t lsz;
7111f6eb021SLiane Praza 	char *loc;
7121f6eb021SLiane Praza 
7131f6eb021SLiane Praza 	if (locale == NULL)
7141f6eb021SLiane Praza 		locale = setlocale(LC_MESSAGES, NULL);
7151f6eb021SLiane Praza 	loc = strdup(locale);
7161f6eb021SLiane Praza 	if (loc == NULL) {
7171f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
7181f6eb021SLiane Praza 		return (NULL);
7191f6eb021SLiane Praza 	} else {
7201f6eb021SLiane Praza 		_scf_sanitize_locale(loc);
7211f6eb021SLiane Praza 	}
7221f6eb021SLiane Praza 
7231f6eb021SLiane Praza 	lsz = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
7241f6eb021SLiane Praza 	lname = malloc(lsz);
7251f6eb021SLiane Praza 	if (lname == NULL) {
7261f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
7271f6eb021SLiane Praza 		goto cleanup;
7281f6eb021SLiane Praza 	}
7291f6eb021SLiane Praza 
7301f6eb021SLiane Praza 	(void) strlcpy(lname, name, lsz);
7311f6eb021SLiane Praza 	if (strlcat(lname, loc, lsz) >= lsz) {
7321f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
7331f6eb021SLiane Praza 		free(lname);
7341f6eb021SLiane Praza 		lname = NULL;
7351f6eb021SLiane Praza 	}
7361f6eb021SLiane Praza cleanup:
7371f6eb021SLiane Praza 	free(loc);
7381f6eb021SLiane Praza 
7391f6eb021SLiane Praza 	return (lname);
7401f6eb021SLiane Praza }
7411f6eb021SLiane Praza 
7421f6eb021SLiane Praza /*
7431f6eb021SLiane Praza  * char *_tmpl_pg_name(pg, type, use_type)
7441f6eb021SLiane Praza  *
7451f6eb021SLiane Praza  * pg and type can both be NULL.  Returns the name of the most specific
7461f6eb021SLiane Praza  * template property group name based on the inputs.
7471f6eb021SLiane Praza  * If use_type is set and pg is not NULL, a property group name for a
7481f6eb021SLiane Praza  * property group template that has type defined is returned, even if no
7491f6eb021SLiane Praza  * type is provided.
7501f6eb021SLiane Praza  *
7511f6eb021SLiane Praza  * Returns NULL on failure and sets scf_error() to:
7521f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
7531f6eb021SLiane Praza  *     can't combine the arguments and get a reasonable length name
7541f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
7551f6eb021SLiane Praza  *
7561f6eb021SLiane Praza  */
7571f6eb021SLiane Praza static char *
7581f6eb021SLiane Praza _tmpl_pg_name(const char *pg, const char *type, int use_type)
7591f6eb021SLiane Praza {
7601f6eb021SLiane Praza 	char *name;
7611f6eb021SLiane Praza 	ssize_t limit, size = 0;
7621f6eb021SLiane Praza 
7631f6eb021SLiane Praza 	limit = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
7641f6eb021SLiane Praza 	name = malloc(limit);
7651f6eb021SLiane Praza 	if (name == NULL) {
7661f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
7671f6eb021SLiane Praza 		return (NULL);
7681f6eb021SLiane Praza 	}
7691f6eb021SLiane Praza 
7701f6eb021SLiane Praza 	if (pg == NULL && type == NULL) {
7711f6eb021SLiane Praza 		if (strlcpy(name, SCF_PG_TM_PG_PATTERN_PREFIX, limit) >=
7721f6eb021SLiane Praza 		    limit) {
7731f6eb021SLiane Praza 			assert(0);
7741f6eb021SLiane Praza 			abort();
7751f6eb021SLiane Praza 		}
7761f6eb021SLiane Praza 		return (name);
7771f6eb021SLiane Praza 	} else if (pg != NULL && type != NULL) {
7781f6eb021SLiane Praza 		size = snprintf(name, limit, "%s%s",
7791f6eb021SLiane Praza 		    SCF_PG_TM_PG_PATTERN_NT_PREFIX, pg);
7801f6eb021SLiane Praza 	} else if (pg != NULL && type == NULL && use_type == 1) {
7811f6eb021SLiane Praza 		size = snprintf(name, limit, "%s%s",
7821f6eb021SLiane Praza 		    SCF_PG_TM_PG_PATTERN_NT_PREFIX, pg);
7831f6eb021SLiane Praza 	} else if (pg != NULL && type == NULL) {
7841f6eb021SLiane Praza 		size = snprintf(name, limit, "%s%s",
7851f6eb021SLiane Praza 		    SCF_PG_TM_PG_PATTERN_N_PREFIX, pg);
7861f6eb021SLiane Praza 	} else if (type != NULL && pg == NULL) {
7871f6eb021SLiane Praza 		size = snprintf(name, limit, "%s%s",
7881f6eb021SLiane Praza 		    SCF_PG_TM_PG_PATTERN_T_PREFIX, type);
7891f6eb021SLiane Praza 	} else {
7901f6eb021SLiane Praza 		assert(0);
7911f6eb021SLiane Praza 		abort();
7921f6eb021SLiane Praza 	}
7931f6eb021SLiane Praza 
7941f6eb021SLiane Praza 	if (size >= limit) {
7951f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
7961f6eb021SLiane Praza 		free(name);
7971f6eb021SLiane Praza 		return (NULL);
7981f6eb021SLiane Praza 	} else {
7991f6eb021SLiane Praza 		return (name);
8001f6eb021SLiane Praza 	}
8011f6eb021SLiane Praza }
8021f6eb021SLiane Praza 
8031f6eb021SLiane Praza /*
8041f6eb021SLiane Praza  * _scf_get_pg_name()
8051f6eb021SLiane Praza  * Gets the name of the supplied property group.  On success, returns an
8061f6eb021SLiane Praza  * allocated string.  The string must be freed by free().
8071f6eb021SLiane Praza  *
8081f6eb021SLiane Praza  * Returns NULL on failure and sets scf_error() to _CONNECTION_BROKEN,
8091f6eb021SLiane Praza  * _DELETED, or _NO_MEMORY.
8101f6eb021SLiane Praza  */
8111f6eb021SLiane Praza static char *
8121f6eb021SLiane Praza _scf_get_pg_name(scf_propertygroup_t *pg)
8131f6eb021SLiane Praza {
8141f6eb021SLiane Praza 	ssize_t sz = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
8151f6eb021SLiane Praza 	char *buf = malloc(sz);
8161f6eb021SLiane Praza 
8171f6eb021SLiane Praza 	if (buf == NULL) {
8181f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
8191f6eb021SLiane Praza 	} else if (scf_pg_get_name(pg, buf, sz) == -1) {
8201f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
8211f6eb021SLiane Praza 			free(buf);
8221f6eb021SLiane Praza 			buf = NULL;
8231f6eb021SLiane Praza 		} else {
8241f6eb021SLiane Praza 			assert(0);
8251f6eb021SLiane Praza 			abort();
8261f6eb021SLiane Praza 		}
8271f6eb021SLiane Praza 	}
8281f6eb021SLiane Praza 
8291f6eb021SLiane Praza 	return (buf);
8301f6eb021SLiane Praza }
8311f6eb021SLiane Praza 
8321f6eb021SLiane Praza /*
8331f6eb021SLiane Praza  * char *_tmpl_prop_name()
8341f6eb021SLiane Praza  *
8351f6eb021SLiane Praza  * Returns the name of the property template prop (which is the name of
8361f6eb021SLiane Praza  * the property template property group) in the property group
8371f6eb021SLiane Praza  * template t. Returns NULL on failure and sets scf_error() to:
8381f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
8391f6eb021SLiane Praza  *   SCF_ERROR_DELETED
8401f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
8411f6eb021SLiane Praza  *     can't combine the arguments and get a reasonable length name
8421f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
8431f6eb021SLiane Praza  */
8441f6eb021SLiane Praza static char *
8451f6eb021SLiane Praza _tmpl_prop_name(const char *prop, scf_pg_tmpl_t *t)
8461f6eb021SLiane Praza {
8471f6eb021SLiane Praza 	char *name = NULL, *pg_name = NULL;
8481f6eb021SLiane Praza 	size_t prefix_size;
8491f6eb021SLiane Praza 	ssize_t limit, size = 0;
8501f6eb021SLiane Praza 
8511f6eb021SLiane Praza 	assert(prop != NULL);
8521f6eb021SLiane Praza 	assert(t->pt_pg != NULL);
8531f6eb021SLiane Praza 
8541f6eb021SLiane Praza 	limit = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
8551f6eb021SLiane Praza 	name = malloc(limit);
8561f6eb021SLiane Praza 	if (name == NULL) {
8571f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
8581f6eb021SLiane Praza 		return (NULL);
8591f6eb021SLiane Praza 	}
8601f6eb021SLiane Praza 
8611f6eb021SLiane Praza 	if ((pg_name = _scf_get_pg_name(t->pt_pg)) == NULL) {
8621f6eb021SLiane Praza 		free(name);
8631f6eb021SLiane Praza 		return (NULL);
8641f6eb021SLiane Praza 	}
8651f6eb021SLiane Praza 
8661f6eb021SLiane Praza 	prefix_size = strlen(SCF_PG_TM_PG_PAT_BASE);
8671f6eb021SLiane Praza 	if (strncmp(pg_name, SCF_PG_TM_PG_PAT_BASE, prefix_size) != 0) {
8681f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
8691f6eb021SLiane Praza 		free(name);
8701f6eb021SLiane Praza 		free(pg_name);
8711f6eb021SLiane Praza 		return (NULL);
8721f6eb021SLiane Praza 	}
8731f6eb021SLiane Praza 
8741f6eb021SLiane Praza 	size = snprintf(name, limit, "%s%s_%s", SCF_PG_TM_PROP_PATTERN_PREFIX,
8751f6eb021SLiane Praza 	    pg_name + prefix_size, prop);
8761f6eb021SLiane Praza 
8771f6eb021SLiane Praza 	if (size >= limit) {
8781f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
8791f6eb021SLiane Praza 		free(name);
8801f6eb021SLiane Praza 		free(pg_name);
8811f6eb021SLiane Praza 		return (NULL);
8821f6eb021SLiane Praza 	} else {
8831f6eb021SLiane Praza 		free(pg_name);
8841f6eb021SLiane Praza 		return (name);
8851f6eb021SLiane Praza 	}
8861f6eb021SLiane Praza }
8871f6eb021SLiane Praza 
8881f6eb021SLiane Praza /*
8891f6eb021SLiane Praza  *  int _get_snapshot()
8901f6eb021SLiane Praza  *
8911f6eb021SLiane Praza  *  Gets the specified snapshot.  If "snapshot" isn't defined, use the
8921f6eb021SLiane Praza  *  running snapshot.  If the snapshot isn't found, that may or may
8931f6eb021SLiane Praza  *  not be an error depending on the caller.  Return 0 in that case,
8941f6eb021SLiane Praza  *  but leave scf_error() set to SCF_ERROR_NOT_FOUND.  On all other
8951f6eb021SLiane Praza  *  errors, set scf_error() to:
8961f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
8971f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
8981f6eb021SLiane Praza  *   SCF_ERROR_DELETED
8991f6eb021SLiane Praza  *   SCF_ERR_HANDLE_DESTROYED
9001f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
9011f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
9021f6eb021SLiane Praza  *     The handle argument is NULL, or snaphot is not a valid snapshot name
9031f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
9041f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
9051f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
9061f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
9071f6eb021SLiane Praza  */
9081f6eb021SLiane Praza static int
9091f6eb021SLiane Praza _get_snapshot(scf_instance_t *inst, const char *snapshot,
9101f6eb021SLiane Praza     scf_snapshot_t **snap)
9111f6eb021SLiane Praza {
9121f6eb021SLiane Praza 	int err;
9131f6eb021SLiane Praza 	scf_handle_t *h;
9141f6eb021SLiane Praza 
9151f6eb021SLiane Praza 	h = scf_instance_handle(inst);
9161f6eb021SLiane Praza 	if (h == NULL)
9171f6eb021SLiane Praza 		return (-1);
9181f6eb021SLiane Praza 
9191f6eb021SLiane Praza 	if ((*snap = scf_snapshot_create(h)) == NULL) {
9201f6eb021SLiane Praza 		return (-1);
9211f6eb021SLiane Praza 	}
9221f6eb021SLiane Praza 
9231f6eb021SLiane Praza 	/* Use running snapshot by default. */
9241f6eb021SLiane Praza 	if (snapshot == NULL)
9251f6eb021SLiane Praza 		err = scf_instance_get_snapshot(inst, "running", *snap);
9261f6eb021SLiane Praza 	else
9271f6eb021SLiane Praza 		err = scf_instance_get_snapshot(inst, snapshot, *snap);
9281f6eb021SLiane Praza 
9291f6eb021SLiane Praza 	if (err != 0) {
9301f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
9311f6eb021SLiane Praza 			scf_snapshot_destroy(*snap);
9321f6eb021SLiane Praza 			*snap = NULL;
9331f6eb021SLiane Praza 			return (-1);
9341f6eb021SLiane Praza 		} else switch (scf_error()) {
9351f6eb021SLiane Praza 		case SCF_ERROR_INVALID_ARGUMENT:
9361f6eb021SLiane Praza 			scf_snapshot_destroy(*snap);
9371f6eb021SLiane Praza 			*snap = NULL;
9381f6eb021SLiane Praza 			return (-1);
9391f6eb021SLiane Praza 
9401f6eb021SLiane Praza 		case SCF_ERROR_NOT_FOUND:
9411f6eb021SLiane Praza 			scf_snapshot_destroy(*snap);
9421f6eb021SLiane Praza 			*snap = NULL;
9431f6eb021SLiane Praza 			return (0);
9441f6eb021SLiane Praza 
9451f6eb021SLiane Praza 		case SCF_ERROR_NOT_SET:
9461f6eb021SLiane Praza 		case SCF_ERROR_HANDLE_MISMATCH:
9471f6eb021SLiane Praza 		default:
9481f6eb021SLiane Praza 			assert(0);
9491f6eb021SLiane Praza 			abort();
9501f6eb021SLiane Praza 		}
9511f6eb021SLiane Praza 	}
9521f6eb021SLiane Praza 
9531f6eb021SLiane Praza 	/*
9541f6eb021SLiane Praza 	 * Explicitly set SCF_ERROR_NONE so that the SCF_ERROR_NOT_FOUND
9551f6eb021SLiane Praza 	 * return above is explicitly guaranteed to be from
9561f6eb021SLiane Praza 	 * scf_instance_get_snapshot().
9571f6eb021SLiane Praza 	 */
9581f6eb021SLiane Praza 	(void) scf_set_error(SCF_ERROR_NONE);
9591f6eb021SLiane Praza 	return (0);
9601f6eb021SLiane Praza }
9611f6eb021SLiane Praza 
9621f6eb021SLiane Praza /*
9631f6eb021SLiane Praza  * Returns NULL on error, sets scf_error() to:
9641f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
9651f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
9661f6eb021SLiane Praza  *   SCF_ERROR_CONSTRAINT_VIOLATED
9671f6eb021SLiane Praza  *     The restarter's FMRI does not match an existing instance.
9681f6eb021SLiane Praza  *   SCF_ERROR_DELETED
9691f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
9701f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
9711f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
9721f6eb021SLiane Praza  *     The restarter's FMRI is not a valid FMRI.
9731f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
9741f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
9751f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
9761f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
9771f6eb021SLiane Praza  *     Property doesn't exist or exists and has no value.
9781f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
9791f6eb021SLiane Praza  *     restarter property is not SCF_TYPE_ASTRING or has more than one value
9801f6eb021SLiane Praza  */
9811f6eb021SLiane Praza static scf_instance_t *
9821f6eb021SLiane Praza _get_restarter_inst(scf_handle_t *h, scf_service_t *svc,
9831f6eb021SLiane Praza     scf_instance_t *inst, scf_snapshot_t *s)
9841f6eb021SLiane Praza {
9851f6eb021SLiane Praza 	char *restarter = NULL;
9861f6eb021SLiane Praza 	scf_instance_t *ri = NULL;
9871f6eb021SLiane Praza 	scf_propertygroup_t *pg = NULL;
9881f6eb021SLiane Praza 	int ret = 0;
9891f6eb021SLiane Praza 
9901f6eb021SLiane Praza 	assert(svc != NULL || inst != NULL);
9911f6eb021SLiane Praza 	assert(svc ==  NULL || inst == NULL);
9921f6eb021SLiane Praza 
9931f6eb021SLiane Praza 	if ((ri = scf_instance_create(h)) == NULL ||
9941f6eb021SLiane Praza 	    (pg = scf_pg_create(h)) == NULL) {
9951f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_INVALID_ARGUMENT);
99676fa7285SAntonello Cruz 		goto _get_restarter_inst_fail;
9971f6eb021SLiane Praza 	}
9981f6eb021SLiane Praza 
9991f6eb021SLiane Praza 	if (inst != NULL)
10001f6eb021SLiane Praza 		ret = scf_instance_get_pg_composed(inst, s, SCF_PG_GENERAL,
10011f6eb021SLiane Praza 		    pg);
10021f6eb021SLiane Praza 	else
10031f6eb021SLiane Praza 		ret = scf_service_get_pg(svc, SCF_PG_GENERAL, pg);
10041f6eb021SLiane Praza 
10051f6eb021SLiane Praza 	if (ret != 0) {
10061f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
10071f6eb021SLiane Praza 			goto _get_restarter_inst_fail;
10081f6eb021SLiane Praza 		} else switch (scf_error()) {
10091f6eb021SLiane Praza 		case SCF_ERROR_NOT_FOUND:
10101f6eb021SLiane Praza 			/* Assume default restarter. */
10111f6eb021SLiane Praza 			break;
10121f6eb021SLiane Praza 
10131f6eb021SLiane Praza 		case SCF_ERROR_NOT_SET:
10141f6eb021SLiane Praza 		case SCF_ERROR_HANDLE_MISMATCH:
10151f6eb021SLiane Praza 			/*
10161f6eb021SLiane Praza 			 * If the arguments to the above functions
10171f6eb021SLiane Praza 			 * aren't derived from the same handle, there's
10181f6eb021SLiane Praza 			 * something wrong with the internal implementation,
10191f6eb021SLiane Praza 			 * not the public caller further up the chain.
10201f6eb021SLiane Praza 			 */
10211f6eb021SLiane Praza 		case SCF_ERROR_INVALID_ARGUMENT:
10221f6eb021SLiane Praza 		default:
10231f6eb021SLiane Praza 			assert(0);
10241f6eb021SLiane Praza 			abort();
10251f6eb021SLiane Praza 		}
10261f6eb021SLiane Praza 	} else {
10271f6eb021SLiane Praza 		restarter = _scf_read_single_astring_from_pg(pg,
10281f6eb021SLiane Praza 		    SCF_PROPERTY_RESTARTER);
10291f6eb021SLiane Praza 		/* zero length string is NOT a valid restarter */
10301f6eb021SLiane Praza 		if (restarter != NULL && restarter[0] == '\0') {
10311f6eb021SLiane Praza 			free(restarter);
10321f6eb021SLiane Praza 			restarter = NULL;
10331f6eb021SLiane Praza 		} else if (restarter == NULL) {
10341f6eb021SLiane Praza 			if (ismember(scf_error(), errors_server)) {
10351f6eb021SLiane Praza 				goto _get_restarter_inst_fail;
10361f6eb021SLiane Praza 			} else switch (scf_error()) {
10371f6eb021SLiane Praza 			case SCF_ERROR_NOT_FOUND:
10381f6eb021SLiane Praza 				break;
10391f6eb021SLiane Praza 
10401f6eb021SLiane Praza 			case SCF_ERROR_CONSTRAINT_VIOLATED:
10411f6eb021SLiane Praza 			case SCF_ERROR_TYPE_MISMATCH:
10421f6eb021SLiane Praza 				(void) scf_set_error(
10431f6eb021SLiane Praza 				    SCF_ERROR_TEMPLATE_INVALID);
10441f6eb021SLiane Praza 				goto _get_restarter_inst_fail;
10451f6eb021SLiane Praza 
10461f6eb021SLiane Praza 			case SCF_ERROR_NOT_SET:
10471f6eb021SLiane Praza 			case SCF_ERROR_INVALID_ARGUMENT:
10481f6eb021SLiane Praza 			default:
10491f6eb021SLiane Praza 				assert(0);
10501f6eb021SLiane Praza 				abort();
10511f6eb021SLiane Praza 			}
10521f6eb021SLiane Praza 		}
10531f6eb021SLiane Praza 	}
10541f6eb021SLiane Praza 
10551f6eb021SLiane Praza 	if (restarter == NULL) {
10561f6eb021SLiane Praza 		/* Use default restarter */
10571f6eb021SLiane Praza 		restarter = strdup(SCF_SERVICE_STARTD);
10581f6eb021SLiane Praza 		if (restarter == NULL) {
10591f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
10601f6eb021SLiane Praza 			goto _get_restarter_inst_fail;
10611f6eb021SLiane Praza 		}
10621f6eb021SLiane Praza 	}
10631f6eb021SLiane Praza 
10641f6eb021SLiane Praza 	if (scf_handle_decode_fmri(h, restarter, NULL, NULL, ri, NULL, NULL,
10651f6eb021SLiane Praza 	    SCF_DECODE_FMRI_EXACT|SCF_DECODE_FMRI_REQUIRE_INSTANCE) != 0) {
10661f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
10671f6eb021SLiane Praza 			goto _get_restarter_inst_fail;
10681f6eb021SLiane Praza 		} else switch (scf_error()) {
10691f6eb021SLiane Praza 		case SCF_ERROR_CONSTRAINT_VIOLATED:
10701f6eb021SLiane Praza 		case SCF_ERROR_INVALID_ARGUMENT:
10711f6eb021SLiane Praza 		case SCF_ERROR_NOT_FOUND:
10721f6eb021SLiane Praza 			goto _get_restarter_inst_fail;
10731f6eb021SLiane Praza 
10741f6eb021SLiane Praza 		case SCF_ERROR_HANDLE_MISMATCH:
10751f6eb021SLiane Praza 		case SCF_ERROR_NOT_SET:
10761f6eb021SLiane Praza 		default:
10771f6eb021SLiane Praza 			assert(0);
10781f6eb021SLiane Praza 			abort();
10791f6eb021SLiane Praza 		}
10801f6eb021SLiane Praza 	}
10811f6eb021SLiane Praza 	free(restarter);
10821f6eb021SLiane Praza 	scf_pg_destroy(pg);
10831f6eb021SLiane Praza 
10841f6eb021SLiane Praza 	return (ri);
10851f6eb021SLiane Praza 
10861f6eb021SLiane Praza _get_restarter_inst_fail:
108776fa7285SAntonello Cruz 	free(restarter);
10881f6eb021SLiane Praza 	scf_instance_destroy(ri);
10891f6eb021SLiane Praza 	scf_pg_destroy(pg);
10901f6eb021SLiane Praza 	return (NULL);
10911f6eb021SLiane Praza }
10921f6eb021SLiane Praza 
10931f6eb021SLiane Praza /*
10941f6eb021SLiane Praza  * Returns NULL on error, sets scf_error() to:
10951f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
10961f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
10971f6eb021SLiane Praza  *   SCF_ERROR_CONSTRAINT_VIOLATED
10981f6eb021SLiane Praza  *     Restarter property has more than one value associated with it,
10991f6eb021SLiane Praza  *     or FMRI does not meet restrictions in scf_handle_decode_fmri() flags.
11001f6eb021SLiane Praza  *   SCF_ERROR_DELETED
11011f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
11021f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
11031f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
11041f6eb021SLiane Praza  *     The fmri argument in scf_handle_decode_fmri() is not a valid FMRI.
11051f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
11061f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
11071f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
11081f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
11091f6eb021SLiane Praza  *     Property doesn't exist or exists and has no value.
11101f6eb021SLiane Praza  */
11111f6eb021SLiane Praza static scf_instance_t *
11121f6eb021SLiane Praza _get_global_inst(scf_handle_t *h)
11131f6eb021SLiane Praza {
11141f6eb021SLiane Praza 	scf_instance_t *ri;
11151f6eb021SLiane Praza 
11161f6eb021SLiane Praza 	if ((ri = scf_instance_create(h)) == NULL) {
11171f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_INVALID_ARGUMENT);
11181f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_RESOURCES);
11191f6eb021SLiane Praza 		return (NULL);
11201f6eb021SLiane Praza 	}
11211f6eb021SLiane Praza 
11221f6eb021SLiane Praza 	if (scf_handle_decode_fmri(h, SCF_INSTANCE_GLOBAL, NULL, NULL, ri,
11231f6eb021SLiane Praza 	    NULL, NULL,
11241f6eb021SLiane Praza 	    SCF_DECODE_FMRI_EXACT|SCF_DECODE_FMRI_REQUIRE_INSTANCE) != 0) {
11251f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
11261f6eb021SLiane Praza 			scf_instance_destroy(ri);
11271f6eb021SLiane Praza 			return (NULL);
11281f6eb021SLiane Praza 		} else switch (scf_error()) {
11291f6eb021SLiane Praza 		case SCF_ERROR_CONSTRAINT_VIOLATED:
11301f6eb021SLiane Praza 		case SCF_ERROR_INVALID_ARGUMENT:
11311f6eb021SLiane Praza 		case SCF_ERROR_NOT_FOUND:
11321f6eb021SLiane Praza 			scf_instance_destroy(ri);
11331f6eb021SLiane Praza 			return (NULL);
11341f6eb021SLiane Praza 
11351f6eb021SLiane Praza 		case SCF_ERROR_HANDLE_MISMATCH:
11361f6eb021SLiane Praza 		case SCF_ERROR_NOT_SET:
11371f6eb021SLiane Praza 		default:
11381f6eb021SLiane Praza 			assert(0);
11391f6eb021SLiane Praza 			abort();
11401f6eb021SLiane Praza 		}
11411f6eb021SLiane Praza 	}
11421f6eb021SLiane Praza 
11431f6eb021SLiane Praza 	return (ri);
11441f6eb021SLiane Praza }
11451f6eb021SLiane Praza 
11461f6eb021SLiane Praza /*
11471f6eb021SLiane Praza  * Call the supplied function for each of the service or instance, the
11481f6eb021SLiane Praza  * service's restarter, and the globally defined template instance.
11491f6eb021SLiane Praza  * If the function returns SCF_WALK_ERROR, the walk is ended.  If
11501f6eb021SLiane Praza  * the function returns SCF_WALK_NEXT, the next entity is tried.
11511f6eb021SLiane Praza  *
11521f6eb021SLiane Praza  * The function is only expected to return SCF_WALK_DONE if it has
11531f6eb021SLiane Praza  * found a property group match in the current entity, and has
11541f6eb021SLiane Praza  * populated p->pw_pg with the matching property group.
115576fa7285SAntonello Cruz  *
115676fa7285SAntonello Cruz  * The caller of _walk_template_instances() MUST check if the passed parameters
115776fa7285SAntonello Cruz  * inst and svc match the fields pw_inst and pw_svc in the resulting
115876fa7285SAntonello Cruz  * pg_tmpl_walk_t and call the destructor for the unmatching objects. The walker
115976fa7285SAntonello Cruz  * may silently drop them if the template definition is in the restarter or in
116076fa7285SAntonello Cruz  * the global instance.
11611f6eb021SLiane Praza  */
11621f6eb021SLiane Praza static void
11631f6eb021SLiane Praza _walk_template_instances(scf_service_t *svc, scf_instance_t *inst,
11641f6eb021SLiane Praza     scf_snapshot_t *snap, walk_template_inst_func_t *func,
11651f6eb021SLiane Praza     pg_tmpl_walk_t *p, int flag)
11661f6eb021SLiane Praza {
11671f6eb021SLiane Praza 	scf_instance_t *tmpl_inst = NULL;
11681f6eb021SLiane Praza 	scf_handle_t *h;
11691f6eb021SLiane Praza 	int ret;
11701f6eb021SLiane Praza 	char *tg = NULL;
11711f6eb021SLiane Praza 
11721f6eb021SLiane Praza 	assert(svc != NULL || inst != NULL);
11731f6eb021SLiane Praza 	assert(svc == NULL || inst == NULL);
11741f6eb021SLiane Praza 
11751f6eb021SLiane Praza 	if (inst != NULL)
11761f6eb021SLiane Praza 		h = scf_instance_handle(inst);
11771f6eb021SLiane Praza 	else
11781f6eb021SLiane Praza 		h = scf_service_handle(svc);
11791f6eb021SLiane Praza 	if (h == NULL)
11801f6eb021SLiane Praza 		goto done;
11811f6eb021SLiane Praza 
11821f6eb021SLiane Praza 	/* First, use supplied service or instance */
11831f6eb021SLiane Praza 	p->pw_target = SCF_TM_TARGET_THIS;
11841f6eb021SLiane Praza 	ret = func(svc, inst, p);
11851f6eb021SLiane Praza 	switch (ret) {
11861f6eb021SLiane Praza 	case SCF_WALK_NEXT:
11871f6eb021SLiane Praza 		break;
11881f6eb021SLiane Praza 	case SCF_WALK_DONE:
11891f6eb021SLiane Praza 		/*
11901f6eb021SLiane Praza 		 * Check that the template scoping matches and if not,
11911f6eb021SLiane Praza 		 * continue.
11921f6eb021SLiane Praza 		 */
11931f6eb021SLiane Praza 		assert(p->pw_pg != NULL);
11941f6eb021SLiane Praza 		tg = _scf_read_single_astring_from_pg(p->pw_pg,
11951f6eb021SLiane Praza 		    SCF_PROPERTY_TM_TARGET);
11961f6eb021SLiane Praza 		if (tg == NULL || /* scf_error() was set */
11971f6eb021SLiane Praza 		    (strcmp(tg, SCF_TM_TARGET_INSTANCE) != 0 &&
11981f6eb021SLiane Praza 		    strcmp(tg, SCF_TM_TARGET_THIS) != 0 &&
11991f6eb021SLiane Praza 		    (flag & SCF_PG_TMPL_FLAG_EXACT) !=
12001f6eb021SLiane Praza 		    SCF_PG_TMPL_FLAG_EXACT)) {
12011f6eb021SLiane Praza 			scf_pg_destroy(p->pw_pg);
12021f6eb021SLiane Praza 			p->pw_pg = NULL;
12031f6eb021SLiane Praza 			if (tg != NULL) {
12041f6eb021SLiane Praza 				free(tg);
12051f6eb021SLiane Praza 				tg = NULL;
12061f6eb021SLiane Praza 				break;
12071f6eb021SLiane Praza 			}
12081f6eb021SLiane Praza 		}
12091f6eb021SLiane Praza 		/*FALLTHROUGH*/
12101f6eb021SLiane Praza 	case SCF_WALK_ERROR:
12111f6eb021SLiane Praza 		goto done;
12121f6eb021SLiane Praza 		/*NOTREACHED*/
12131f6eb021SLiane Praza 	default:
12141f6eb021SLiane Praza 		assert(0);
12151f6eb021SLiane Praza 		abort();
12161f6eb021SLiane Praza 	}
12171f6eb021SLiane Praza 
12181f6eb021SLiane Praza 	/* Next the restarter. */
12191f6eb021SLiane Praza 	p->pw_target = SCF_TM_TARGET_DELEGATE;
12201f6eb021SLiane Praza 	tmpl_inst = _get_restarter_inst(h, svc, inst, snap);
12211f6eb021SLiane Praza 	if (tmpl_inst != NULL) {
12221f6eb021SLiane Praza 		ret = func(NULL, tmpl_inst, p);
12231f6eb021SLiane Praza 		switch (ret) {
12241f6eb021SLiane Praza 		case SCF_WALK_NEXT:
12251f6eb021SLiane Praza 			break;
12261f6eb021SLiane Praza 		case SCF_WALK_DONE:
12271f6eb021SLiane Praza 			/*
12281f6eb021SLiane Praza 			 * Check that the template scoping matches and if not,
12291f6eb021SLiane Praza 			 * continue.
12301f6eb021SLiane Praza 			 */
12311f6eb021SLiane Praza 			assert(p->pw_pg != NULL);
12321f6eb021SLiane Praza 			tg = _scf_read_single_astring_from_pg(p->pw_pg,
12331f6eb021SLiane Praza 			    SCF_PROPERTY_TM_TARGET);
12341f6eb021SLiane Praza 			if (tg == NULL || /* scf_error() was set */
12351f6eb021SLiane Praza 			    strcmp(tg, SCF_TM_TARGET_DELEGATE) != 0) {
12361f6eb021SLiane Praza 				scf_pg_destroy(p->pw_pg);
12371f6eb021SLiane Praza 				p->pw_pg = NULL;
12381f6eb021SLiane Praza 				if (tg != NULL) {
12391f6eb021SLiane Praza 					free(tg);
12401f6eb021SLiane Praza 					tg = NULL;
12411f6eb021SLiane Praza 					break;
12421f6eb021SLiane Praza 				}
12431f6eb021SLiane Praza 			}
12441f6eb021SLiane Praza 			/*FALLTHROUGH*/
12451f6eb021SLiane Praza 		case SCF_WALK_ERROR:
12461f6eb021SLiane Praza 			goto done;
12471f6eb021SLiane Praza 			/*NOTREACHED*/
12481f6eb021SLiane Praza 		default:
12491f6eb021SLiane Praza 			assert(0);
12501f6eb021SLiane Praza 			abort();
12511f6eb021SLiane Praza 		}
12521f6eb021SLiane Praza 	}
12531f6eb021SLiane Praza 
12541f6eb021SLiane Praza 	p->pw_target = SCF_TM_TARGET_ALL;
12551f6eb021SLiane Praza 	scf_instance_destroy(tmpl_inst);
12561f6eb021SLiane Praza 	tmpl_inst = _get_global_inst(h);
12571f6eb021SLiane Praza 	if (tmpl_inst != NULL) {
12581f6eb021SLiane Praza 		ret = func(NULL, tmpl_inst, p);
12591f6eb021SLiane Praza 		switch (ret) {
12601f6eb021SLiane Praza 		case SCF_WALK_NEXT:
12611f6eb021SLiane Praza 			break;
12621f6eb021SLiane Praza 		case SCF_WALK_DONE:
12631f6eb021SLiane Praza 			/*
12641f6eb021SLiane Praza 			 * Check that the template scoping matches and if not,
12651f6eb021SLiane Praza 			 * continue.
12661f6eb021SLiane Praza 			 */
12671f6eb021SLiane Praza 			assert(p->pw_pg != NULL);
12681f6eb021SLiane Praza 			tg = _scf_read_single_astring_from_pg(p->pw_pg,
12691f6eb021SLiane Praza 			    SCF_PROPERTY_TM_TARGET);
12701f6eb021SLiane Praza 			if (tg == NULL || /* scf_error() was set */
12711f6eb021SLiane Praza 			    strcmp(tg, SCF_TM_TARGET_ALL) != 0) {
12721f6eb021SLiane Praza 				scf_pg_destroy(p->pw_pg);
12731f6eb021SLiane Praza 				p->pw_pg = NULL;
12741f6eb021SLiane Praza 				if (tg != NULL) {
12751f6eb021SLiane Praza 					free(tg);
12761f6eb021SLiane Praza 					tg = NULL;
12771f6eb021SLiane Praza 					break;
12781f6eb021SLiane Praza 				}
12791f6eb021SLiane Praza 			}
12801f6eb021SLiane Praza 			/*FALLTHROUGH*/
12811f6eb021SLiane Praza 		case SCF_WALK_ERROR:
12821f6eb021SLiane Praza 			goto done;
12831f6eb021SLiane Praza 			/*NOTREACHED*/
12841f6eb021SLiane Praza 		default:
12851f6eb021SLiane Praza 			assert(0);
12861f6eb021SLiane Praza 			abort();
12871f6eb021SLiane Praza 		}
12881f6eb021SLiane Praza 	}
12891f6eb021SLiane Praza 
12901f6eb021SLiane Praza done:
12911f6eb021SLiane Praza 	free(tg);
12921f6eb021SLiane Praza 	if (ret != SCF_WALK_DONE)
12931f6eb021SLiane Praza 		scf_instance_destroy(tmpl_inst);
12941f6eb021SLiane Praza 	p->pw_target = NULL;
12951f6eb021SLiane Praza }
12961f6eb021SLiane Praza 
12971f6eb021SLiane Praza /*
12981f6eb021SLiane Praza  * _get_pg() returns 0 on success and -1 on failure.  Sets scf_error()
12991f6eb021SLiane Praza  * on failure.
13001f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
13011f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
13021f6eb021SLiane Praza  *   SCF_ERROR_DELETED
13031f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_MISMATCH
13041f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
13051f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
13061f6eb021SLiane Praza  *     name is not a valid property group.
13071f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
13081f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
13091f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
13101f6eb021SLiane Praza  *   SCF_ERROR_NOT_SET
13111f6eb021SLiane Praza  */
13121f6eb021SLiane Praza static int
13131f6eb021SLiane Praza _get_pg(scf_service_t *svc, scf_instance_t *inst,
13141f6eb021SLiane Praza     const scf_snapshot_t *snap, const char *name, scf_propertygroup_t *pg)
13151f6eb021SLiane Praza {
13161f6eb021SLiane Praza 	int ret;
13171f6eb021SLiane Praza 
13181f6eb021SLiane Praza 	assert(svc != NULL || inst != NULL);
13191f6eb021SLiane Praza 	assert(svc == NULL || inst == NULL);
13201f6eb021SLiane Praza 	assert(pg != NULL);
13211f6eb021SLiane Praza 
13221f6eb021SLiane Praza 	if (inst != NULL)
13231f6eb021SLiane Praza 		ret = scf_instance_get_pg_composed(inst, snap, name, pg);
13241f6eb021SLiane Praza 	else
13251f6eb021SLiane Praza 		ret = scf_service_get_pg(svc, name, pg);
13261f6eb021SLiane Praza 
13271f6eb021SLiane Praza 	return (ret);
13281f6eb021SLiane Praza }
13291f6eb021SLiane Praza 
13301f6eb021SLiane Praza /*
13311f6eb021SLiane Praza  * Returns SCF_WALK_NEXT for not found, SCF_WALK_ERROR for error,
13321f6eb021SLiane Praza  * and SCF_WALK_DONE for found.
13331f6eb021SLiane Praza  * On error, destroy pg and set it to NULL.
13341f6eb021SLiane Praza  *
13351f6eb021SLiane Praza  * Sets scf_error() if SCF_WALK_ERROR is returned to _BACKEND_ACCESS,
13361f6eb021SLiane Praza  * _CONNECTION_BROKEN, _INTERNAL, _INVALID_ARGUMENT (name is not a
13371f6eb021SLiane Praza  *  valid property group), _NO_RESOURCES, or _NOT_BOUND.
13381f6eb021SLiane Praza  */
13391f6eb021SLiane Praza static int
13401f6eb021SLiane Praza _lookup_pg(scf_service_t *svc, scf_instance_t *inst,
13411f6eb021SLiane Praza     const scf_snapshot_t *snap, const char *name, scf_propertygroup_t *pg)
13421f6eb021SLiane Praza {
13431f6eb021SLiane Praza 	int ret;
13441f6eb021SLiane Praza 
13451f6eb021SLiane Praza 	ret = _get_pg(svc, inst, snap, name, pg);
13461f6eb021SLiane Praza 
13471f6eb021SLiane Praza 	if (ret == 0) {
13481f6eb021SLiane Praza 		return (SCF_WALK_DONE);
13491f6eb021SLiane Praza 	} else {
13501f6eb021SLiane Praza 		switch (scf_error()) {
13511f6eb021SLiane Praza 		case SCF_ERROR_NOT_FOUND:
13521f6eb021SLiane Praza 		case SCF_ERROR_DELETED:
13531f6eb021SLiane Praza 			return (SCF_WALK_NEXT);
13541f6eb021SLiane Praza 
13551f6eb021SLiane Praza 		case SCF_ERROR_BACKEND_ACCESS:
13561f6eb021SLiane Praza 		case SCF_ERROR_CONNECTION_BROKEN:
13571f6eb021SLiane Praza 		case SCF_ERROR_INTERNAL:
13581f6eb021SLiane Praza 		case SCF_ERROR_INVALID_ARGUMENT:
13591f6eb021SLiane Praza 		case SCF_ERROR_NOT_BOUND:
13601f6eb021SLiane Praza 		case SCF_ERROR_NO_RESOURCES:
13611f6eb021SLiane Praza 			scf_pg_destroy(pg);
13621f6eb021SLiane Praza 			pg = NULL;
13631f6eb021SLiane Praza 			return (SCF_WALK_ERROR);
13641f6eb021SLiane Praza 
13651f6eb021SLiane Praza 		case SCF_ERROR_NOT_SET:
13661f6eb021SLiane Praza 		case SCF_ERROR_HANDLE_MISMATCH:
13671f6eb021SLiane Praza 		default:
13681f6eb021SLiane Praza 			assert(0);
13691f6eb021SLiane Praza 			abort();
13701f6eb021SLiane Praza 		}
13711f6eb021SLiane Praza 	}
13721f6eb021SLiane Praza 
13731f6eb021SLiane Praza 	/*NOTREACHED*/
13741f6eb021SLiane Praza }
13751f6eb021SLiane Praza 
13761f6eb021SLiane Praza /*
13771f6eb021SLiane Praza  * If match, return 0.  If no match, return 1.  If error, return -1.
13781f6eb021SLiane Praza  * On error set scf_error() to _BACKEND_ACCESS, _CONNECTION_BROKEN,
13791f6eb021SLiane Praza  * _HANDLE_DESTROYED, _INTERNAL, _NO_MEMORY, _NO_RESOURCES, _NOT_BOUND,
13801f6eb021SLiane Praza  * _NOT_SET (property group specified by pg is not set), _PERMISSION_DENIED,
13811f6eb021SLiane Praza  * or _TEMPLATE_INVALID (target property is not SCF_TYPE_ASTRING or has
13821f6eb021SLiane Praza  * more than one value).
13831f6eb021SLiane Praza  */
13841f6eb021SLiane Praza static int
13851f6eb021SLiane Praza check_target_match(scf_propertygroup_t *pg, const char *target)
13861f6eb021SLiane Praza {
13871f6eb021SLiane Praza 	char *pg_target;
13881f6eb021SLiane Praza 	int ret = 0;
13891f6eb021SLiane Praza 
13901f6eb021SLiane Praza 	pg_target = _scf_read_single_astring_from_pg(pg,
13911f6eb021SLiane Praza 	    SCF_PROPERTY_TM_TARGET);
13921f6eb021SLiane Praza 	if (pg_target == NULL) {
13931f6eb021SLiane Praza 		switch (scf_error()) {
13941f6eb021SLiane Praza 		case SCF_ERROR_DELETED:
13951f6eb021SLiane Praza 		case SCF_ERROR_NOT_FOUND:
13961f6eb021SLiane Praza 			return (1);
13971f6eb021SLiane Praza 
13981f6eb021SLiane Praza 		case SCF_ERROR_CONSTRAINT_VIOLATED:
13991f6eb021SLiane Praza 		case SCF_ERROR_TYPE_MISMATCH:
14001f6eb021SLiane Praza 			(void) scf_set_error(
14011f6eb021SLiane Praza 			    SCF_ERROR_TEMPLATE_INVALID);
14021f6eb021SLiane Praza 			/*FALLTHROUGH*/
14031f6eb021SLiane Praza 
14041f6eb021SLiane Praza 		case SCF_ERROR_BACKEND_ACCESS:
14051f6eb021SLiane Praza 		case SCF_ERROR_CONNECTION_BROKEN:
14061f6eb021SLiane Praza 		case SCF_ERROR_HANDLE_DESTROYED:
14071f6eb021SLiane Praza 		case SCF_ERROR_INTERNAL:
14081f6eb021SLiane Praza 		case SCF_ERROR_NO_RESOURCES:
14091f6eb021SLiane Praza 		case SCF_ERROR_NOT_BOUND:
14101f6eb021SLiane Praza 		case SCF_ERROR_PERMISSION_DENIED:
14111f6eb021SLiane Praza 			return (-1);
14121f6eb021SLiane Praza 
14131f6eb021SLiane Praza 		case SCF_ERROR_NOT_SET:
14141f6eb021SLiane Praza 		case SCF_ERROR_INVALID_ARGUMENT:
14151f6eb021SLiane Praza 		default:
14161f6eb021SLiane Praza 			assert(0);
14171f6eb021SLiane Praza 			abort();
14181f6eb021SLiane Praza 		}
14191f6eb021SLiane Praza 		/*NOTREACHED*/
14201f6eb021SLiane Praza 	}
14211f6eb021SLiane Praza 
14221f6eb021SLiane Praza 	/* For a desired target of 'this', check for 'this' and 'instance'. */
14231f6eb021SLiane Praza 	if ((strcmp(target, SCF_TM_TARGET_INSTANCE) == 0 ||
14241f6eb021SLiane Praza 	    strcmp(target, SCF_TM_TARGET_THIS) == 0) &&
14251f6eb021SLiane Praza 	    (strcmp(pg_target, SCF_TM_TARGET_INSTANCE) == 0 ||
14261f6eb021SLiane Praza 	    strcmp(pg_target, SCF_TM_TARGET_THIS) == 0)) {
14271f6eb021SLiane Praza 		goto cleanup;
14281f6eb021SLiane Praza 	}
14291f6eb021SLiane Praza 
14301f6eb021SLiane Praza 	if (strcmp(target, SCF_TM_TARGET_DELEGATE) == 0 &&
14311f6eb021SLiane Praza 	    strcmp(pg_target, SCF_TM_TARGET_DELEGATE) == 0) {
14321f6eb021SLiane Praza 		goto cleanup;
14331f6eb021SLiane Praza 	}
14341f6eb021SLiane Praza 
14351f6eb021SLiane Praza 	if (strcmp(target, SCF_TM_TARGET_ALL) == 0 &&
14361f6eb021SLiane Praza 	    strcmp(pg_target, SCF_TM_TARGET_ALL) == 0) {
14371f6eb021SLiane Praza 		goto cleanup;
14381f6eb021SLiane Praza 	}
14391f6eb021SLiane Praza 
14401f6eb021SLiane Praza 	ret = 1;
14411f6eb021SLiane Praza cleanup:
14421f6eb021SLiane Praza 	free(pg_target);
14431f6eb021SLiane Praza 	return (ret);
14441f6eb021SLiane Praza }
14451f6eb021SLiane Praza 
14461f6eb021SLiane Praza /*
14471f6eb021SLiane Praza  * Check if a matching template property group exists for each of:
14481f6eb021SLiane Praza  * name and type, name only, type only, and completely wildcarded
14491f6eb021SLiane Praza  * template.
14501f6eb021SLiane Praza  *
14511f6eb021SLiane Praza  * Both pg_name and pg_type are optional.
14521f6eb021SLiane Praza  *
14531f6eb021SLiane Praza  * Returns NULL on failure, sets scf_error():
14541f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
14551f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
14561f6eb021SLiane Praza  *   SCF_ERROR_DELETED
14571f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
14581f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
14591f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
14601f6eb021SLiane Praza  *     can't combine the _tmpl_pg_name arguments and get a reasonable
14611f6eb021SLiane Praza  *     length name, or pg_name is not a valid property group.
14621f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
14631f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
14641f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
14651f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
14661f6eb021SLiane Praza  *     Property doesn't exist or exists and has no value.
14671f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
14681f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
14691f6eb021SLiane Praza  *     target property is not SCF_TYPE_ASTRING or has more than one value.
14701f6eb021SLiane Praza  */
14711f6eb021SLiane Praza static scf_propertygroup_t *
14721f6eb021SLiane Praza _find_template_pg_match(scf_service_t *svc, scf_instance_t *inst,
14731f6eb021SLiane Praza     const scf_snapshot_t *snap, const char *pg_name, const char *pg_type,
14741f6eb021SLiane Praza     const char *target, char **tmpl_pg_name)
14751f6eb021SLiane Praza {
14761f6eb021SLiane Praza 	int ret, r;
14771f6eb021SLiane Praza 	scf_propertygroup_t *pg = NULL;
14781f6eb021SLiane Praza 	scf_handle_t *h;
14791f6eb021SLiane Praza 	scf_iter_t *iter;
14801f6eb021SLiane Praza 	char *name, *type;
14811f6eb021SLiane Praza 
14821f6eb021SLiane Praza 	assert(inst != NULL || svc != NULL);
14831f6eb021SLiane Praza 	assert(inst == NULL || svc == NULL);
14841f6eb021SLiane Praza 
14851f6eb021SLiane Praza 	if (inst != NULL)
14861f6eb021SLiane Praza 		h = scf_instance_handle(inst);
14871f6eb021SLiane Praza 	else
14881f6eb021SLiane Praza 		h = scf_service_handle(svc);
14891f6eb021SLiane Praza 	if (h == NULL) {
14901f6eb021SLiane Praza 		return (NULL);
14911f6eb021SLiane Praza 	}
14921f6eb021SLiane Praza 
14931f6eb021SLiane Praza 	if ((pg = scf_pg_create(h)) == NULL ||
14941f6eb021SLiane Praza 	    (iter = scf_iter_create(h)) == NULL) {
14951f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_INVALID_ARGUMENT);
14961f6eb021SLiane Praza 		scf_pg_destroy(pg);
14971f6eb021SLiane Praza 		return (NULL);
14981f6eb021SLiane Praza 	}
14991f6eb021SLiane Praza 
15001f6eb021SLiane Praza 	/*
15011f6eb021SLiane Praza 	 * We're going to walk through the possible pg templates that
15021f6eb021SLiane Praza 	 * could match the supplied name and type.  We do this
15031f6eb021SLiane Praza 	 * by explicit name lookups when possible to avoid having to
15041f6eb021SLiane Praza 	 * keep track of a most-explicit-match during iteration.
15051f6eb021SLiane Praza 	 */
15061f6eb021SLiane Praza 
15071f6eb021SLiane Praza 	/* First look for a template with name and type set and matching. */
15081f6eb021SLiane Praza 	*tmpl_pg_name = _tmpl_pg_name(pg_name, pg_type, 1);
15091f6eb021SLiane Praza 	if (*tmpl_pg_name == NULL)
15101f6eb021SLiane Praza 		goto fail;
15111f6eb021SLiane Praza 	ret = _lookup_pg(svc, inst, snap, *tmpl_pg_name, pg);
15121f6eb021SLiane Praza 	if (ret != SCF_WALK_NEXT) {
15131f6eb021SLiane Praza 		if (pg != NULL) {
15141f6eb021SLiane Praza 			if ((r = check_target_match(pg, target)) == 0)
15151f6eb021SLiane Praza 				goto done;
15161f6eb021SLiane Praza 			else if (r == -1)
15171f6eb021SLiane Praza 				goto fail;
15181f6eb021SLiane Praza 		} else {
15191f6eb021SLiane Praza 			goto done;
15201f6eb021SLiane Praza 		}
15211f6eb021SLiane Praza 	}
15221f6eb021SLiane Praza 	free(*tmpl_pg_name);
15231f6eb021SLiane Praza 
15241f6eb021SLiane Praza 	/*
15251f6eb021SLiane Praza 	 * Need to search on a name-only match before searching on
15261f6eb021SLiane Praza 	 * type matches.
15271f6eb021SLiane Praza 	 */
15281f6eb021SLiane Praza 
15291f6eb021SLiane Praza 	*tmpl_pg_name = _tmpl_pg_name(pg_name, NULL, 0);
15301f6eb021SLiane Praza 	if (*tmpl_pg_name == NULL)
15311f6eb021SLiane Praza 		goto fail;
15321f6eb021SLiane Praza 	ret = _lookup_pg(svc, inst, snap, *tmpl_pg_name, pg);
15331f6eb021SLiane Praza 	if (ret != SCF_WALK_NEXT) {
15341f6eb021SLiane Praza 		if (pg != NULL) {
15351f6eb021SLiane Praza 			if ((r = check_target_match(pg, target)) == 0)
15361f6eb021SLiane Praza 				goto done;
15371f6eb021SLiane Praza 			else if (r == -1)
15381f6eb021SLiane Praza 				goto fail;
15391f6eb021SLiane Praza 		} else {
15401f6eb021SLiane Praza 			goto done;
15411f6eb021SLiane Praza 		}
15421f6eb021SLiane Praza 	}
15431f6eb021SLiane Praza 	free(*tmpl_pg_name);
15441f6eb021SLiane Praza 
15451f6eb021SLiane Praza 	/* Next, see if there's an "nt" template where the type matches. */
15461f6eb021SLiane Praza 	if (pg_type != NULL && pg_name == NULL) {
15471f6eb021SLiane Praza 		if (inst != NULL)
15481f6eb021SLiane Praza 			ret = scf_iter_instance_pgs_typed_composed(iter, inst,
15491f6eb021SLiane Praza 			    snap, SCF_GROUP_TEMPLATE_PG_PATTERN);
15501f6eb021SLiane Praza 		else
15511f6eb021SLiane Praza 			ret = scf_iter_service_pgs_typed(iter, svc,
15521f6eb021SLiane Praza 			    SCF_GROUP_TEMPLATE_PG_PATTERN);
15531f6eb021SLiane Praza 
15541f6eb021SLiane Praza 		if (ret != 0) {
15551f6eb021SLiane Praza 			if (ismember(scf_error(), errors_server)) {
15561f6eb021SLiane Praza 				goto fail;
15571f6eb021SLiane Praza 			} else {
15581f6eb021SLiane Praza 				assert(0);
15591f6eb021SLiane Praza 				abort();
15601f6eb021SLiane Praza 			}
15611f6eb021SLiane Praza 		}
15621f6eb021SLiane Praza 
15631f6eb021SLiane Praza 		while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
15641f6eb021SLiane Praza 			/* Make sure this is a name and type specified pg. */
15651f6eb021SLiane Praza 			name = _scf_read_single_astring_from_pg(pg,
15661f6eb021SLiane Praza 			    SCF_PROPERTY_TM_NAME);
15671f6eb021SLiane Praza 			if (name == NULL)
15681f6eb021SLiane Praza 				continue;
15691f6eb021SLiane Praza 			type = _scf_read_single_astring_from_pg(pg,
15701f6eb021SLiane Praza 			    SCF_PROPERTY_TM_TYPE);
15711f6eb021SLiane Praza 			if (type == NULL) {
15721f6eb021SLiane Praza 				free(name);
15731f6eb021SLiane Praza 				continue;
15741f6eb021SLiane Praza 			}
15751f6eb021SLiane Praza 			if (strcmp(pg_type, type) == 0 &&
15761f6eb021SLiane Praza 			    check_target_match(pg, target) == 0) {
15771f6eb021SLiane Praza 				*tmpl_pg_name = name;
15781f6eb021SLiane Praza 				free(type);
15791f6eb021SLiane Praza 				goto done;
15801f6eb021SLiane Praza 			}
15811f6eb021SLiane Praza 			free(type);
15821f6eb021SLiane Praza 			free(name);
15831f6eb021SLiane Praza 		}
15841f6eb021SLiane Praza 		if (ret == -1) {
15851f6eb021SLiane Praza 			if (ismember(scf_error(), errors_server)) {
15861f6eb021SLiane Praza 				goto fail;
15871f6eb021SLiane Praza 			} else {
15881f6eb021SLiane Praza 				assert(0);
15891f6eb021SLiane Praza 				abort();
15901f6eb021SLiane Praza 			}
15911f6eb021SLiane Praza 		}
15921f6eb021SLiane Praza 	}
15931f6eb021SLiane Praza 
15941f6eb021SLiane Praza 	*tmpl_pg_name = _tmpl_pg_name(NULL, pg_type, 0);
15951f6eb021SLiane Praza 	if (*tmpl_pg_name == NULL)
15961f6eb021SLiane Praza 		goto fail;
15971f6eb021SLiane Praza 	ret = _lookup_pg(svc, inst, snap, *tmpl_pg_name, pg);
15981f6eb021SLiane Praza 	if (ret != SCF_WALK_NEXT) {
15991f6eb021SLiane Praza 		if (pg != NULL) {
16001f6eb021SLiane Praza 			if ((r = check_target_match(pg, target)) == 0)
16011f6eb021SLiane Praza 				goto done;
16021f6eb021SLiane Praza 			else if (r == -1)
16031f6eb021SLiane Praza 				goto fail;
16041f6eb021SLiane Praza 		} else {
16051f6eb021SLiane Praza 			goto done;
16061f6eb021SLiane Praza 		}
16071f6eb021SLiane Praza 	}
16081f6eb021SLiane Praza 	free(*tmpl_pg_name);
16091f6eb021SLiane Praza 
16101f6eb021SLiane Praza 	*tmpl_pg_name = _tmpl_pg_name(NULL, NULL, 0);
16111f6eb021SLiane Praza 	if (*tmpl_pg_name == NULL)
16121f6eb021SLiane Praza 		goto fail;
16131f6eb021SLiane Praza 	ret = _lookup_pg(svc, inst, snap, *tmpl_pg_name, pg);
16141f6eb021SLiane Praza 	if (ret != SCF_WALK_NEXT) {
16151f6eb021SLiane Praza 		if (pg != NULL) {
16161f6eb021SLiane Praza 			if ((r = check_target_match(pg, target)) == 0)
16171f6eb021SLiane Praza 				goto done;
16181f6eb021SLiane Praza 			else if (r == -1)
16191f6eb021SLiane Praza 				goto fail;
16201f6eb021SLiane Praza 		} else {
16211f6eb021SLiane Praza 			goto done;
16221f6eb021SLiane Praza 		}
16231f6eb021SLiane Praza 	}
16241f6eb021SLiane Praza 
16251f6eb021SLiane Praza 	(void) scf_set_error(SCF_ERROR_NOT_FOUND);
16261f6eb021SLiane Praza fail:
16271f6eb021SLiane Praza 	scf_pg_destroy(pg);
16281f6eb021SLiane Praza 	if (*tmpl_pg_name != NULL)
16291f6eb021SLiane Praza 		free(*tmpl_pg_name);
16301f6eb021SLiane Praza 	*tmpl_pg_name = NULL;
16311f6eb021SLiane Praza 	pg = NULL;
16321f6eb021SLiane Praza done:
16331f6eb021SLiane Praza 	if (ret == SCF_WALK_ERROR)
16341f6eb021SLiane Praza 		free(*tmpl_pg_name);
16351f6eb021SLiane Praza 	scf_iter_destroy(iter);
16361f6eb021SLiane Praza 	return (pg);
16371f6eb021SLiane Praza }
16381f6eb021SLiane Praza 
16391f6eb021SLiane Praza /*
16401f6eb021SLiane Praza  * Finds the pg match in either the supplied service or instance.
16411f6eb021SLiane Praza  * Returns SCF_WALK_ERROR, SCF_WALK_NEXT, or SCF_WALK_DONE.
16421f6eb021SLiane Praza  * If returning SCF_WALK_ERROR, sets scf_error():
16431f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
16441f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
16451f6eb021SLiane Praza  *   SCF_ERROR_DELETED
16461f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
16471f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
16481f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
16491f6eb021SLiane Praza  *     The snaphot is not a valid snapshot name,
16501f6eb021SLiane Praza  *     or can't create a reasonable property group template name.
16511f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
16521f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
16531f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
16541f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
16551f6eb021SLiane Praza  *     Property doesn't exist or exists and has no value.
16561f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
16571f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
16581f6eb021SLiane Praza  *     target property is not SCF_TYPE_ASTRING or has more than one value.
16591f6eb021SLiane Praza  */
16601f6eb021SLiane Praza static int
16611f6eb021SLiane Praza find_pg_match(scf_service_t *svc, scf_instance_t *inst, pg_tmpl_walk_t *p)
16621f6eb021SLiane Praza {
16631f6eb021SLiane Praza 	scf_snapshot_t *tmpl_snap = NULL;
16641f6eb021SLiane Praza 	scf_propertygroup_t *pg;
16651f6eb021SLiane Praza 	scf_handle_t *h;
16661f6eb021SLiane Praza 	char *tmpl_pg_name;
16671f6eb021SLiane Praza 
16681f6eb021SLiane Praza 	assert(svc != NULL || inst != NULL);
16691f6eb021SLiane Praza 	assert(svc == NULL || inst == NULL);
16701f6eb021SLiane Praza 
16711f6eb021SLiane Praza 	if (inst != NULL)
16721f6eb021SLiane Praza 		h = scf_instance_handle(inst);
16731f6eb021SLiane Praza 	else
16741f6eb021SLiane Praza 		h = scf_service_handle(svc);
16751f6eb021SLiane Praza 	if (h == NULL)
16761f6eb021SLiane Praza 		return (SCF_WALK_ERROR);
16771f6eb021SLiane Praza 
16781f6eb021SLiane Praza 	if (p->pw_snapname != NULL) {
16791f6eb021SLiane Praza 		if (_get_snapshot(inst, p->pw_snapname, &tmpl_snap) == -1)
16801f6eb021SLiane Praza 			return (SCF_WALK_ERROR);
16811f6eb021SLiane Praza 	}
16821f6eb021SLiane Praza 	pg = _find_template_pg_match(svc, inst, tmpl_snap, p->pw_pgname,
16831f6eb021SLiane Praza 	    p->pw_pgtype, p->pw_target, &tmpl_pg_name);
16841f6eb021SLiane Praza 
16851f6eb021SLiane Praza 	if (pg != NULL) {
16861f6eb021SLiane Praza 		p->pw_snap = tmpl_snap;
16871f6eb021SLiane Praza 		p->pw_pg = pg;
16881f6eb021SLiane Praza 		p->pw_tmpl_pgname = tmpl_pg_name;
16891f6eb021SLiane Praza 		p->pw_inst = inst;
16901f6eb021SLiane Praza 		p->pw_svc = svc;
16911f6eb021SLiane Praza 		return (SCF_WALK_DONE);
16921f6eb021SLiane Praza 	}
16931f6eb021SLiane Praza 
16941f6eb021SLiane Praza 	scf_snapshot_destroy(tmpl_snap);
16951f6eb021SLiane Praza 	return (SCF_WALK_NEXT);
16961f6eb021SLiane Praza }
16971f6eb021SLiane Praza 
16981f6eb021SLiane Praza /*
16991f6eb021SLiane Praza  * return 0 on success and -1 on failure.
17001f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
17011f6eb021SLiane Praza  *   SCF_ERROR_DELETED
17021f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
17031f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_MISMATCH
17041f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
17051f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
17061f6eb021SLiane Praza  *     FMRI argument, snapshot name, pg_name, or pg is invalid.
17071f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
17081f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
17091f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
17101f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
17111f6eb021SLiane Praza  *   SCF_ERROR_NOT_SET
17121f6eb021SLiane Praza  */
17131f6eb021SLiane Praza int
17141f6eb021SLiane Praza scf_tmpl_get_by_pg(scf_propertygroup_t *pg, scf_pg_tmpl_t *pg_tmpl, int flags)
17151f6eb021SLiane Praza {
17161f6eb021SLiane Praza 	char *fmribuf = NULL, *snapbuf = NULL, *pg_name = NULL, *pg_type = NULL;
171776fa7285SAntonello Cruz 	int ret;
17181f6eb021SLiane Praza 	ssize_t fbufsz = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH) + 1;
17191f6eb021SLiane Praza 	ssize_t nbufsz = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
17201f6eb021SLiane Praza 	ssize_t tbufsz = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH) + 1;
17211f6eb021SLiane Praza 	scf_instance_t *inst = NULL;
17221f6eb021SLiane Praza 	scf_snaplevel_t *snaplvl = NULL;
17231f6eb021SLiane Praza 	scf_service_t *svc = NULL;
17241f6eb021SLiane Praza 	scf_handle_t *h;
17251f6eb021SLiane Praza 	scf_snapshot_t *snap = NULL;
172676fa7285SAntonello Cruz 	pg_tmpl_walk_t *p = NULL;
17271f6eb021SLiane Praza 
17281f6eb021SLiane Praza 	assert(fbufsz != 0 && nbufsz != 0 && tbufsz != 0);
17291f6eb021SLiane Praza 
17301f6eb021SLiane Praza 	scf_tmpl_pg_reset(pg_tmpl);
17311f6eb021SLiane Praza 
17321f6eb021SLiane Praza 	if ((h = scf_pg_handle(pg)) == NULL)
17331f6eb021SLiane Praza 		return (-1);
17341f6eb021SLiane Praza 
17351f6eb021SLiane Praza 	if ((inst = scf_instance_create(h)) == NULL ||
17361f6eb021SLiane Praza 	    (svc = scf_service_create(h)) == NULL ||
17371f6eb021SLiane Praza 	    (snaplvl = scf_snaplevel_create(h)) == NULL) {
173876fa7285SAntonello Cruz 		goto fail;
17391f6eb021SLiane Praza 	}
17401f6eb021SLiane Praza 
17411f6eb021SLiane Praza 	if ((fmribuf = malloc(fbufsz)) == NULL ||
17421f6eb021SLiane Praza 	    (pg_name = malloc(nbufsz)) == NULL ||
17431f6eb021SLiane Praza 	    (pg_type = malloc(tbufsz)) == NULL ||
17441f6eb021SLiane Praza 	    (p = calloc(1, sizeof (pg_tmpl_walk_t))) == NULL) {
17451f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
174676fa7285SAntonello Cruz 		goto fail;
17471f6eb021SLiane Praza 	}
17481f6eb021SLiane Praza 
17491f6eb021SLiane Praza 	if (scf_pg_get_name(pg, pg_name, nbufsz) < 0) {
17501f6eb021SLiane Praza 		goto fail;
17511f6eb021SLiane Praza 	}
17521f6eb021SLiane Praza 
17531f6eb021SLiane Praza 	if (scf_pg_get_type(pg, pg_type, tbufsz) < 0) {
17541f6eb021SLiane Praza 		goto fail;
17551f6eb021SLiane Praza 	}
17561f6eb021SLiane Praza 	p->pw_pgname = pg_name;
17571f6eb021SLiane Praza 	p->pw_pgtype = pg_type;
17581f6eb021SLiane Praza 
17591f6eb021SLiane Praza 	ret = scf_pg_get_parent_snaplevel(pg, snaplvl);
17601f6eb021SLiane Praza 	if (ret == -1) {
17611f6eb021SLiane Praza 		switch (scf_error()) {
17621f6eb021SLiane Praza 		case SCF_ERROR_CONSTRAINT_VIOLATED:
17631f6eb021SLiane Praza 			/* Parent type doesn't match.  Keep looking. */
17641f6eb021SLiane Praza 			break;
17651f6eb021SLiane Praza 
17661f6eb021SLiane Praza 		case SCF_ERROR_DELETED:
17671f6eb021SLiane Praza 		case SCF_ERROR_NOT_BOUND:
17681f6eb021SLiane Praza 		case SCF_ERROR_NOT_SET:
17691f6eb021SLiane Praza 			/* Pass these back to the caller. */
17701f6eb021SLiane Praza 			goto fail;
17711f6eb021SLiane Praza 
17721f6eb021SLiane Praza 		case SCF_ERROR_HANDLE_MISMATCH:
17731f6eb021SLiane Praza 		default:
17741f6eb021SLiane Praza 			assert(0);
17751f6eb021SLiane Praza 			abort();
17761f6eb021SLiane Praza 		}
17771f6eb021SLiane Praza 
17781f6eb021SLiane Praza 		/*
17791f6eb021SLiane Praza 		 * No snapshot.  We'll use 'editing' by default since
17801f6eb021SLiane Praza 		 * snap and snapbuf are NULL.
17811f6eb021SLiane Praza 		 */
17821f6eb021SLiane Praza 		p->pw_snapname = NULL;
17831f6eb021SLiane Praza 
17841f6eb021SLiane Praza 	} else {
17851f6eb021SLiane Praza 		if ((snap = scf_snapshot_create(h)) == NULL) {
17861f6eb021SLiane Praza 			goto fail;
17871f6eb021SLiane Praza 		}
17881f6eb021SLiane Praza 
17891f6eb021SLiane Praza 		ret = scf_snaplevel_get_parent(snaplvl, snap);
17901f6eb021SLiane Praza 		if (ret == -1) {
17911f6eb021SLiane Praza 			if (ismember(scf_error(), errors_server)) {
17921f6eb021SLiane Praza 				goto fail;
17931f6eb021SLiane Praza 			} else {
17941f6eb021SLiane Praza 				assert(0);
17951f6eb021SLiane Praza 				abort();
17961f6eb021SLiane Praza 			}
17971f6eb021SLiane Praza 		}
17981f6eb021SLiane Praza 
17991f6eb021SLiane Praza 		/* Grab snapshot name while we're here. */
18001f6eb021SLiane Praza 		if ((snapbuf = malloc(nbufsz)) == NULL) {
18011f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
18021f6eb021SLiane Praza 			goto fail;
18031f6eb021SLiane Praza 		}
18041f6eb021SLiane Praza 		if (scf_snapshot_get_name(snap, snapbuf, nbufsz) < 0) {
18051f6eb021SLiane Praza 			if (ismember(scf_error(), errors_server)) {
18061f6eb021SLiane Praza 				goto fail;
18071f6eb021SLiane Praza 			} else {
18081f6eb021SLiane Praza 				assert(0);
18091f6eb021SLiane Praza 				abort();
18101f6eb021SLiane Praza 			}
18111f6eb021SLiane Praza 		}
18121f6eb021SLiane Praza 		p->pw_snapname = snapbuf;
18131f6eb021SLiane Praza 
18141f6eb021SLiane Praza 		ret = scf_snapshot_get_parent(snap, inst);
18151f6eb021SLiane Praza 		if (ret == -1) {
18161f6eb021SLiane Praza 			if (ismember(scf_error(), errors_server)) {
18171f6eb021SLiane Praza 				goto fail;
18181f6eb021SLiane Praza 			} else {
18191f6eb021SLiane Praza 				assert(0);
18201f6eb021SLiane Praza 				abort();
18211f6eb021SLiane Praza 			}
18221f6eb021SLiane Praza 		}
18231f6eb021SLiane Praza 
18241f6eb021SLiane Praza 		_walk_template_instances(NULL, inst, snap,
18251f6eb021SLiane Praza 		    (walk_template_inst_func_t *)find_pg_match, p, flags);
18261f6eb021SLiane Praza 	}
18271f6eb021SLiane Praza 
18281f6eb021SLiane Praza 	/* No snapshot parent.  Go looking for instance parent. */
18291f6eb021SLiane Praza 	if (snapbuf == NULL) {
18301f6eb021SLiane Praza 		/* First look for instance parent. */
18311f6eb021SLiane Praza 		ret = scf_pg_get_parent_instance(pg, inst);
18321f6eb021SLiane Praza 		if (ret == 0) {
18331f6eb021SLiane Praza 			_walk_template_instances(NULL, inst, snap,
18341f6eb021SLiane Praza 			    (walk_template_inst_func_t *)find_pg_match,
18351f6eb021SLiane Praza 			    p, flags);
18361f6eb021SLiane Praza 		/* OK, check for service parent */
18371f6eb021SLiane Praza 		} else if (ret == -1 &&
18381f6eb021SLiane Praza 		    scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED) {
18391f6eb021SLiane Praza 			ret = scf_pg_get_parent_service(pg, svc);
18401f6eb021SLiane Praza 			if (ret == 0) {
18411f6eb021SLiane Praza 				_walk_template_instances(svc, NULL, snap,
18421f6eb021SLiane Praza 				    (walk_template_inst_func_t *)find_pg_match,
18431f6eb021SLiane Praza 				    p, flags);
18441f6eb021SLiane Praza 			} else {
18451f6eb021SLiane Praza 				switch (scf_error()) {
18461f6eb021SLiane Praza 				case SCF_ERROR_CONSTRAINT_VIOLATED:
18471f6eb021SLiane Praza 					(void) scf_set_error(
18481f6eb021SLiane Praza 					    SCF_ERROR_NOT_FOUND);
18491f6eb021SLiane Praza 					/*FALLTHROUGH*/
18501f6eb021SLiane Praza 
18511f6eb021SLiane Praza 				case SCF_ERROR_CONNECTION_BROKEN:
18521f6eb021SLiane Praza 				case SCF_ERROR_DELETED:
18531f6eb021SLiane Praza 				case SCF_ERROR_HANDLE_MISMATCH:
18541f6eb021SLiane Praza 				case SCF_ERROR_NOT_BOUND:
18551f6eb021SLiane Praza 				case SCF_ERROR_NOT_SET:
18561f6eb021SLiane Praza 					goto fail;
18571f6eb021SLiane Praza 
18581f6eb021SLiane Praza 				default:
18591f6eb021SLiane Praza 					assert(0);
18601f6eb021SLiane Praza 					abort();
18611f6eb021SLiane Praza 				}
18621f6eb021SLiane Praza 			}
18631f6eb021SLiane Praza 		} else {
18641f6eb021SLiane Praza 			goto fail;
18651f6eb021SLiane Praza 		}
18661f6eb021SLiane Praza 	}
18671f6eb021SLiane Praza 
18681f6eb021SLiane Praza 	if (p->pw_pg != NULL) {
18691f6eb021SLiane Praza 		pg_tmpl->pt_h = h;
18701f6eb021SLiane Praza 		pg_tmpl->pt_pg = p->pw_pg;
18711f6eb021SLiane Praza 		pg_tmpl->pt_inst = p->pw_inst;
187276fa7285SAntonello Cruz 		/* we may get a different instance back */
187376fa7285SAntonello Cruz 		if (p->pw_inst != inst)
187476fa7285SAntonello Cruz 			scf_instance_destroy(inst);
18751f6eb021SLiane Praza 		pg_tmpl->pt_snap = p->pw_snap;
18761f6eb021SLiane Praza 		pg_tmpl->pt_svc = p->pw_svc;
187776fa7285SAntonello Cruz 		/* we may get a different service back */
187876fa7285SAntonello Cruz 		if (p->pw_svc != svc)
187976fa7285SAntonello Cruz 			scf_service_destroy(svc);
18801f6eb021SLiane Praza 		pg_tmpl->pt_populated = 1;
18811f6eb021SLiane Praza 		free(p->pw_tmpl_pgname);
18821f6eb021SLiane Praza 		ret = 0;
18831f6eb021SLiane Praza 		goto done;
18841f6eb021SLiane Praza 	}
18851f6eb021SLiane Praza 
18861f6eb021SLiane Praza 	(void) scf_set_error(SCF_ERROR_NOT_FOUND);
18871f6eb021SLiane Praza 
18881f6eb021SLiane Praza fail:
188976fa7285SAntonello Cruz 	ret = -1;
18901f6eb021SLiane Praza 	scf_instance_destroy(inst);
18911f6eb021SLiane Praza 	scf_service_destroy(svc);
18921f6eb021SLiane Praza done:
189376fa7285SAntonello Cruz 	scf_snapshot_destroy(snap);
18941f6eb021SLiane Praza 	free(snapbuf);
18951f6eb021SLiane Praza 	free(fmribuf);
18961f6eb021SLiane Praza 	free(pg_name);
18971f6eb021SLiane Praza 	free(pg_type);
18981f6eb021SLiane Praza 	free(p);
18991f6eb021SLiane Praza 	scf_snaplevel_destroy(snaplvl);
19001f6eb021SLiane Praza 	return (ret);
19011f6eb021SLiane Praza }
19021f6eb021SLiane Praza 
19031f6eb021SLiane Praza /*
19041f6eb021SLiane Praza  * int scf_tmpl_get_by_pg_name()
19051f6eb021SLiane Praza  *
19061f6eb021SLiane Praza  * Get a template by a combination of the name and type.  Either name
19071f6eb021SLiane Praza  * or type can be null, which indicates a wildcard.  flags may be
19081f6eb021SLiane Praza  * SCF_PG_TMPL_FLAG_CURRENT (use current properties rather than
19091f6eb021SLiane Praza  * the defined or running snapshot), and SCF_PG_TMPL_FLAG_EXACT (match
19101f6eb021SLiane Praza  * only templates defined by the FMRI in question, not by its restarter
19111f6eb021SLiane Praza  * or globally).  Returns 0 on success and -1 on error, and sets
19121f6eb021SLiane Praza  * scf_error() to:
19131f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
19141f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
19151f6eb021SLiane Praza  *     The connection to the repository was lost.
19161f6eb021SLiane Praza  *   SCF_ERROR_DELETED
19171f6eb021SLiane Praza  *     The instance has been deleted.
19181f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
19191f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
19201f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
19211f6eb021SLiane Praza  *     FMRI isn't valid, pg_name is too long to look for a template, or
19221f6eb021SLiane Praza  *     snapshot specified isn't a valid name
19231f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
19241f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
19251f6eb021SLiane Praza  *     The server does not have adequate resources to complete the request.
19261f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
19271f6eb021SLiane Praza  *     The handle is not currently bound.
19281f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
19291f6eb021SLiane Praza  *     Object matching FMRI doesn't exist in the repository, or snapshot
19301f6eb021SLiane Praza  *     doesn't exist.
19311f6eb021SLiane Praza  */
19321f6eb021SLiane Praza int
19331f6eb021SLiane Praza scf_tmpl_get_by_pg_name(const char *fmri, const char *snapshot,
19341f6eb021SLiane Praza     const char *pg_name, const char *pg_type, scf_pg_tmpl_t *pg_tmpl, int flags)
19351f6eb021SLiane Praza {
19361f6eb021SLiane Praza 	scf_instance_t *inst = NULL;
19371f6eb021SLiane Praza 	scf_service_t *svc = NULL;
19381f6eb021SLiane Praza 	scf_snapshot_t *snap = NULL;
193976fa7285SAntonello Cruz 	pg_tmpl_walk_t *p = NULL;
19401f6eb021SLiane Praza 	scf_handle_t *h;
19411f6eb021SLiane Praza 	int ret;
19421f6eb021SLiane Praza 
19431f6eb021SLiane Praza 	assert(pg_tmpl != NULL);
19441f6eb021SLiane Praza 	h = pg_tmpl->pt_h;
19451f6eb021SLiane Praza 	assert(h != NULL);
19461f6eb021SLiane Praza 
19471f6eb021SLiane Praza 	scf_tmpl_pg_reset(pg_tmpl);
19481f6eb021SLiane Praza 
19491f6eb021SLiane Praza 	if ((inst = scf_instance_create(h)) == NULL ||
19501f6eb021SLiane Praza 	    (svc = scf_service_create(h)) == NULL) {
195176fa7285SAntonello Cruz 		goto fail;
19521f6eb021SLiane Praza 	}
19531f6eb021SLiane Praza 
19541f6eb021SLiane Praza 	p = calloc(1, sizeof (pg_tmpl_walk_t));
19551f6eb021SLiane Praza 	if (p == NULL) {
19561f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
195776fa7285SAntonello Cruz 		goto fail;
19581f6eb021SLiane Praza 	}
19591f6eb021SLiane Praza 
19601f6eb021SLiane Praza 	ret = scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
19611f6eb021SLiane Praza 	    NULL, SCF_DECODE_FMRI_EXACT);
19621f6eb021SLiane Praza 	if (ret == 0) {
19631f6eb021SLiane Praza 		scf_service_destroy(svc);
19641f6eb021SLiane Praza 		svc = NULL;
19651f6eb021SLiane Praza 	} else if (ret != 0 &&
19661f6eb021SLiane Praza 	    scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED) {
19671f6eb021SLiane Praza 		ret = scf_handle_decode_fmri(h, fmri, NULL, svc,
19681f6eb021SLiane Praza 		    NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT);
19691f6eb021SLiane Praza 		if (ret == 0) {
19701f6eb021SLiane Praza 			scf_instance_destroy(inst);
19711f6eb021SLiane Praza 			inst = NULL;
19721f6eb021SLiane Praza 		}
19731f6eb021SLiane Praza 	}
19741f6eb021SLiane Praza 	if (ret != 0) {
19751f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
19761f6eb021SLiane Praza 			goto fail;
19771f6eb021SLiane Praza 		} else switch (scf_error()) {
19781f6eb021SLiane Praza 		case SCF_ERROR_CONSTRAINT_VIOLATED:
19791f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
19801f6eb021SLiane Praza 			goto fail;
19811f6eb021SLiane Praza 
19821f6eb021SLiane Praza 		case SCF_ERROR_INVALID_ARGUMENT:
19831f6eb021SLiane Praza 		case SCF_ERROR_NOT_FOUND:
19841f6eb021SLiane Praza 			goto fail;
19851f6eb021SLiane Praza 
19861f6eb021SLiane Praza 		case SCF_ERROR_HANDLE_MISMATCH:
19871f6eb021SLiane Praza 		case SCF_ERROR_NOT_SET:
19881f6eb021SLiane Praza 		default:
19891f6eb021SLiane Praza 			assert(0);
19901f6eb021SLiane Praza 			abort();
19911f6eb021SLiane Praza 		}
19921f6eb021SLiane Praza 	}
19931f6eb021SLiane Praza 
19941f6eb021SLiane Praza 	assert(svc == NULL || inst == NULL);
19951f6eb021SLiane Praza 	assert(svc != NULL || inst != NULL);
19961f6eb021SLiane Praza 
199776fa7285SAntonello Cruz 	/* If we have a service fmri, snapshot is ignored. */
19981f6eb021SLiane Praza 	if (inst != NULL) {
19991f6eb021SLiane Praza 		if (snapshot == NULL || strcmp(snapshot, "running") == 0 ||
20001f6eb021SLiane Praza 		    (flags & SCF_PG_TMPL_FLAG_CURRENT) ==
20011f6eb021SLiane Praza 		    SCF_PG_TMPL_FLAG_CURRENT) {
20021f6eb021SLiane Praza 			if (_get_snapshot(inst, NULL, &snap) == -1)
20031f6eb021SLiane Praza 				goto fail;
20041f6eb021SLiane Praza 		} else {
20051f6eb021SLiane Praza 			if (_get_snapshot(inst, snapshot, &snap) == -1) {
20061f6eb021SLiane Praza 				goto fail;
20071f6eb021SLiane Praza 			} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
20081f6eb021SLiane Praza 				goto fail;
20091f6eb021SLiane Praza 			}
20101f6eb021SLiane Praza 		}
20111f6eb021SLiane Praza 	}
20121f6eb021SLiane Praza 
20131f6eb021SLiane Praza 	p->pw_snapname = snapshot;
20141f6eb021SLiane Praza 	p->pw_pgname = pg_name;
20151f6eb021SLiane Praza 	p->pw_pgtype = pg_type;
20161f6eb021SLiane Praza 
20171f6eb021SLiane Praza 	/*
20181f6eb021SLiane Praza 	 * For each of instance, restarter, global
20191f6eb021SLiane Praza 	 *    - check for a tm_pg_pattern_nt_<name> matching type
20201f6eb021SLiane Praza 	 *    - check for a tm_pg_pattern_t_<type> matching type
20211f6eb021SLiane Praza 	 *    - check for any tm_pg_pattern_
20221f6eb021SLiane Praza 	 * Currently plan to return the most specific match only.
20231f6eb021SLiane Praza 	 */
20241f6eb021SLiane Praza 	_walk_template_instances(svc, inst, snap,
20251f6eb021SLiane Praza 	    (walk_template_inst_func_t *)find_pg_match, p, flags);
20261f6eb021SLiane Praza 
20271f6eb021SLiane Praza 	if (p->pw_pg != NULL) {
20281f6eb021SLiane Praza 		pg_tmpl->pt_h = h;
20291f6eb021SLiane Praza 		pg_tmpl->pt_pg = p->pw_pg;
20301f6eb021SLiane Praza 		pg_tmpl->pt_inst = p->pw_inst;
203176fa7285SAntonello Cruz 		/* we may get a different instance back */
203276fa7285SAntonello Cruz 		if (p->pw_inst != inst)
203376fa7285SAntonello Cruz 			scf_instance_destroy(inst);
20341f6eb021SLiane Praza 		pg_tmpl->pt_snap = p->pw_snap;
20351f6eb021SLiane Praza 		pg_tmpl->pt_svc = p->pw_svc;
203676fa7285SAntonello Cruz 		/* we may get a different service back */
203776fa7285SAntonello Cruz 		if (p->pw_svc != svc)
203876fa7285SAntonello Cruz 			scf_service_destroy(svc);
20391f6eb021SLiane Praza 		pg_tmpl->pt_populated = 1;
204076fa7285SAntonello Cruz 		scf_snapshot_destroy(snap);
20411f6eb021SLiane Praza 		free(p->pw_tmpl_pgname);
20421f6eb021SLiane Praza 		free(p);
20431f6eb021SLiane Praza 		return (0);
20441f6eb021SLiane Praza 	}
20451f6eb021SLiane Praza 
20461f6eb021SLiane Praza 	(void) scf_set_error(SCF_ERROR_NOT_FOUND);
20471f6eb021SLiane Praza fail:
20481f6eb021SLiane Praza 	free(p);
20491f6eb021SLiane Praza 	scf_instance_destroy(inst);
20501f6eb021SLiane Praza 	scf_service_destroy(svc);
20511f6eb021SLiane Praza 	scf_snapshot_destroy(snap);
20521f6eb021SLiane Praza 	return (-1);
20531f6eb021SLiane Praza }
20541f6eb021SLiane Praza 
20551f6eb021SLiane Praza /*
20561f6eb021SLiane Praza  * Returns NULL on failure, sets scf_error() to _CONNECTION_BROKEN,
20571f6eb021SLiane Praza  * _DELETED, _NO_RESOURCES, or _NOT_BOUND.
20581f6eb021SLiane Praza  */
20591f6eb021SLiane Praza static scf_iter_t *
20601f6eb021SLiane Praza _get_svc_or_inst_iter(scf_handle_t *h, scf_pg_tmpl_t *t)
20611f6eb021SLiane Praza {
20621f6eb021SLiane Praza 	scf_iter_t *iter;
20631f6eb021SLiane Praza 	int ret;
20641f6eb021SLiane Praza 
20651f6eb021SLiane Praza 	assert(t->pt_svc != NULL || t->pt_inst != NULL);
20661f6eb021SLiane Praza 	assert(t->pt_svc == NULL || t->pt_inst == NULL);
20671f6eb021SLiane Praza 
20681f6eb021SLiane Praza 	if ((iter = scf_iter_create(h)) == NULL) {
20691f6eb021SLiane Praza 		return (NULL);
20701f6eb021SLiane Praza 	}
20711f6eb021SLiane Praza 
20721f6eb021SLiane Praza 	/* Iterate on property groups of type template_pg_pattern */
20731f6eb021SLiane Praza 
20741f6eb021SLiane Praza 	if (t->pt_inst != NULL)
20751f6eb021SLiane Praza 		ret = scf_iter_instance_pgs_typed_composed(iter,
20761f6eb021SLiane Praza 		    t->pt_inst, t->pt_snap,
20771f6eb021SLiane Praza 		    SCF_GROUP_TEMPLATE_PG_PATTERN);
20781f6eb021SLiane Praza 	if (t->pt_svc != NULL)
20791f6eb021SLiane Praza 		ret = scf_iter_service_pgs_typed(iter, t->pt_svc,
20801f6eb021SLiane Praza 		    SCF_GROUP_TEMPLATE_PG_PATTERN);
20811f6eb021SLiane Praza 
20821f6eb021SLiane Praza 	if (ret != 0) {
20831f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
20841f6eb021SLiane Praza 			scf_iter_destroy(iter);
20851f6eb021SLiane Praza 			return (NULL);
20861f6eb021SLiane Praza 		} else {
20871f6eb021SLiane Praza 			assert(0);
20881f6eb021SLiane Praza 			abort();
20891f6eb021SLiane Praza 		}
20901f6eb021SLiane Praza 	}
20911f6eb021SLiane Praza 
20921f6eb021SLiane Praza 	return (iter);
20931f6eb021SLiane Praza }
20941f6eb021SLiane Praza 
20951f6eb021SLiane Praza /*
20961f6eb021SLiane Praza  * Returns NULL on failure, sets scf_error() to:
20971f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
20981f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
20991f6eb021SLiane Praza  *   SCF_ERROR_DELETED
21001f6eb021SLiane Praza  *   SCF_HANDLE_DESTROYED
21011f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
21021f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
21031f6eb021SLiane Praza  *     Handle argument is NULL, or snaphot is not a valid snapshot name.
21041f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
21051f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
21061f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
21071f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
21081f6eb021SLiane Praza  */
21091f6eb021SLiane Praza static scf_iter_t *
21101f6eb021SLiane Praza _get_next_iterator(scf_handle_t *h, scf_pg_tmpl_t *t, const char *snapshot,
21111f6eb021SLiane Praza     int exact)
21121f6eb021SLiane Praza {
21131f6eb021SLiane Praza 	scf_iter_t  *iter = NULL;
21141f6eb021SLiane Praza 	ssize_t limit;
21151f6eb021SLiane Praza 
21161f6eb021SLiane Praza 	limit = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
21171f6eb021SLiane Praza 	assert(limit != 0);
21181f6eb021SLiane Praza 
21191f6eb021SLiane Praza 	/*
21201f6eb021SLiane Praza 	 * Check what level we last iterated on: none, service,
21211f6eb021SLiane Praza 	 * restarter, or global.  Make sure that if one in the middle
21221f6eb021SLiane Praza 	 * doesn't exist, we move on to the next entity.
212376fa7285SAntonello Cruz 	 *
212476fa7285SAntonello Cruz 	 * Before we drop any references to pt_inst or pt_svc we must
212576fa7285SAntonello Cruz 	 * destroy them so we don't leak them.
21261f6eb021SLiane Praza 	 */
21271f6eb021SLiane Praza 	do {
21281f6eb021SLiane Praza 		switch (t->pt_iter_last) {
21291f6eb021SLiane Praza 		case SCF__TMPL_ITER_NONE:
21301f6eb021SLiane Praza 			t->pt_iter_last = SCF__TMPL_ITER_INST;
213176fa7285SAntonello Cruz 			if (t->pt_inst != t->pt_orig_inst)
213276fa7285SAntonello Cruz 				scf_instance_destroy(t->pt_inst);
21331f6eb021SLiane Praza 			t->pt_inst = t->pt_orig_inst;
213476fa7285SAntonello Cruz 			if (t->pt_svc != t->pt_orig_svc)
213576fa7285SAntonello Cruz 				scf_service_destroy(t->pt_svc);
21361f6eb021SLiane Praza 			t->pt_svc = t->pt_orig_svc;
21371f6eb021SLiane Praza 			break;
21381f6eb021SLiane Praza 
21391f6eb021SLiane Praza 		case SCF__TMPL_ITER_INST:
21401f6eb021SLiane Praza 			/*
21411f6eb021SLiane Praza 			 * Don't go any further than the specified instance
21421f6eb021SLiane Praza 			 * if exact was set.
21431f6eb021SLiane Praza 			 */
21441f6eb021SLiane Praza 			if (exact == 1) {
21451f6eb021SLiane Praza 				(void) scf_set_error(SCF_ERROR_NOT_FOUND);
21461f6eb021SLiane Praza 				goto fail;
21471f6eb021SLiane Praza 			}
21481f6eb021SLiane Praza 			t->pt_iter_last = SCF__TMPL_ITER_RESTARTER;
214976fa7285SAntonello Cruz 			if (t->pt_inst != t->pt_orig_inst)
215076fa7285SAntonello Cruz 				scf_instance_destroy(t->pt_inst);
21511f6eb021SLiane Praza 			t->pt_inst = _get_restarter_inst(h, t->pt_orig_svc,
21521f6eb021SLiane Praza 			    t->pt_orig_inst, t->pt_snap);
215376fa7285SAntonello Cruz 			scf_service_destroy(t->pt_svc);
21541f6eb021SLiane Praza 			t->pt_svc = NULL;
21551f6eb021SLiane Praza 			break;
21561f6eb021SLiane Praza 
21571f6eb021SLiane Praza 		case SCF__TMPL_ITER_RESTARTER:
21581f6eb021SLiane Praza 			t->pt_iter_last = SCF__TMPL_ITER_GLOBAL;
215976fa7285SAntonello Cruz 			if (t->pt_inst != t->pt_orig_inst)
216076fa7285SAntonello Cruz 				scf_instance_destroy(t->pt_inst);
21611f6eb021SLiane Praza 			t->pt_inst = _get_global_inst(h);
216276fa7285SAntonello Cruz 			scf_service_destroy(t->pt_svc);
21631f6eb021SLiane Praza 			t->pt_svc = NULL;
21641f6eb021SLiane Praza 			break;
21651f6eb021SLiane Praza 
21661f6eb021SLiane Praza 		case SCF__TMPL_ITER_GLOBAL:
21671f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_NOT_FOUND);
21681f6eb021SLiane Praza 			return (NULL);
21691f6eb021SLiane Praza 
21701f6eb021SLiane Praza 		default:
21711f6eb021SLiane Praza 			assert(0);
21721f6eb021SLiane Praza 			abort();
21731f6eb021SLiane Praza 		}
21741f6eb021SLiane Praza 	} while (t->pt_inst == NULL && t->pt_svc == NULL);
21751f6eb021SLiane Praza 
21761f6eb021SLiane Praza 	/* Set pt_snap to the snapshot for this instance */
21771f6eb021SLiane Praza 	if (t->pt_inst != NULL) {
21781f6eb021SLiane Praza 		scf_snapshot_destroy(t->pt_snap);
21791f6eb021SLiane Praza 		if (_get_snapshot(t->pt_inst, snapshot,
21801f6eb021SLiane Praza 		    &t->pt_snap) == -1)
21811f6eb021SLiane Praza 			goto fail;
21821f6eb021SLiane Praza 	}
21831f6eb021SLiane Praza 
21841f6eb021SLiane Praza 
21851f6eb021SLiane Praza 	iter = _get_svc_or_inst_iter(h, t);
21861f6eb021SLiane Praza fail:
21871f6eb021SLiane Praza 	return (iter);
21881f6eb021SLiane Praza }
21891f6eb021SLiane Praza 
21901f6eb021SLiane Praza /*
21911f6eb021SLiane Praza  * scf_pg_tmpl_t *scf_tmpl_pg_create(scf_handle_t *)
21921f6eb021SLiane Praza  *
21931f6eb021SLiane Praza  * Returns NULL on failure, sets scf_error() to _INVALID_ARGUMENT
21941f6eb021SLiane Praza  * or _NO_MEMORY.
21951f6eb021SLiane Praza  */
21961f6eb021SLiane Praza scf_pg_tmpl_t *
21971f6eb021SLiane Praza scf_tmpl_pg_create(scf_handle_t *handle)
21981f6eb021SLiane Praza {
21991f6eb021SLiane Praza 	scf_pg_tmpl_t *pg_tmpl = NULL;
22001f6eb021SLiane Praza 
22011f6eb021SLiane Praza 	if (handle == NULL) {
22021f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
22031f6eb021SLiane Praza 		return (NULL);
22041f6eb021SLiane Praza 	}
22051f6eb021SLiane Praza 	pg_tmpl = calloc(1, sizeof (scf_pg_tmpl_t));
22061f6eb021SLiane Praza 	if (pg_tmpl == NULL)
22071f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
22081f6eb021SLiane Praza 	else
22091f6eb021SLiane Praza 		pg_tmpl->pt_h = handle;
22101f6eb021SLiane Praza 
22111f6eb021SLiane Praza 	return (pg_tmpl);
22121f6eb021SLiane Praza }
22131f6eb021SLiane Praza 
22141f6eb021SLiane Praza /*
22151f6eb021SLiane Praza  * Retrieves name or type of a template pg.
22161f6eb021SLiane Praza  * Returns -1 on failure.  Sets scf_error():
22171f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
22181f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
22191f6eb021SLiane Praza  *   SCF_ERROR_DELETED
22201f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
22211f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
22221f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
22231f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
22241f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
22251f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
22261f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
22271f6eb021SLiane Praza  *     pname property is not SCF_TYPE_ASTRING or has more than one value.
22281f6eb021SLiane Praza  */
22291f6eb021SLiane Praza static ssize_t
22301f6eb021SLiane Praza _scf_tmpl_prop_value(scf_propertygroup_t *pg, const char *pname, char **out)
22311f6eb021SLiane Praza {
22321f6eb021SLiane Praza 	assert(strcmp(pname, SCF_PROPERTY_TM_NAME) == 0 ||
22331f6eb021SLiane Praza 	    strcmp(pname, SCF_PROPERTY_TM_TYPE) == 0);
22341f6eb021SLiane Praza 
22351f6eb021SLiane Praza 	*out = _scf_read_single_astring_from_pg(pg, pname);
22361f6eb021SLiane Praza 
22371f6eb021SLiane Praza 	if (*out != NULL && *out[0] == '\0') {
22381f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NONE);
22391f6eb021SLiane Praza 		free(*out);
22401f6eb021SLiane Praza 		*out = strdup(SCF_TMPL_WILDCARD);
22411f6eb021SLiane Praza 		if (*out == NULL)
22421f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
22431f6eb021SLiane Praza 	}
22441f6eb021SLiane Praza 	if (*out == NULL) {
22451f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
22461f6eb021SLiane Praza 			return (-1);
22471f6eb021SLiane Praza 		} else switch (scf_error()) {
22481f6eb021SLiane Praza 		case SCF_ERROR_CONSTRAINT_VIOLATED:
22491f6eb021SLiane Praza 		case SCF_ERROR_NOT_FOUND:
22501f6eb021SLiane Praza 		case SCF_ERROR_TYPE_MISMATCH:
22511f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
22521f6eb021SLiane Praza 			return (-1);
22531f6eb021SLiane Praza 
22541f6eb021SLiane Praza 		case SCF_ERROR_INVALID_ARGUMENT:
22551f6eb021SLiane Praza 		case SCF_ERROR_NOT_SET:
22561f6eb021SLiane Praza 		default:
22571f6eb021SLiane Praza 			assert(0);
22581f6eb021SLiane Praza 			abort();
22591f6eb021SLiane Praza 		}
22601f6eb021SLiane Praza 	}
22611f6eb021SLiane Praza 
22621f6eb021SLiane Praza 	return (strlen(*out));
22631f6eb021SLiane Praza }
22641f6eb021SLiane Praza 
22651f6eb021SLiane Praza /*
22661f6eb021SLiane Praza  * int scf_tmpl_iter_pgs()
22671f6eb021SLiane Praza  *
22681f6eb021SLiane Praza  * Iterates through the property group templates for the fmri given.
22691f6eb021SLiane Praza  * When t is uninitialized or reset, sets t to the first property group
22701f6eb021SLiane Praza  * template in fmri. On subsequent calls, sets t to the next property group
22711f6eb021SLiane Praza  * template in frmi.
22721f6eb021SLiane Praza  * Returns 1 on success, 0 when no property group templates are left to
22731f6eb021SLiane Praza  * iterate, -1 on error.
22741f6eb021SLiane Praza  * The flags argument may include SCF_PG_TMPL_FLAG_REQUIRED,
22751f6eb021SLiane Praza  * SCF_PG_TMPL_FLAG_CURRENT,  and/or SCF_PG_TMPL_FLAG_EXACT.
22761f6eb021SLiane Praza  *
22771f6eb021SLiane Praza  * Returns -1 on error and sets scf_error() to:
22781f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
22791f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
22801f6eb021SLiane Praza  *   SCF_ERROR_DELETED
22811f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
22821f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
22831f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
22841f6eb021SLiane Praza  *      The handle argument is NULL, fmri is invalid, or snapshot is invalid.
22851f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
22861f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
22871f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
22881f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
22891f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
22901f6eb021SLiane Praza  */
22911f6eb021SLiane Praza int
22921f6eb021SLiane Praza scf_tmpl_iter_pgs(scf_pg_tmpl_t *t, const char *fmri, const char *snapshot,
22931f6eb021SLiane Praza     const char *type, int flags)
22941f6eb021SLiane Praza {
22951f6eb021SLiane Praza 	scf_handle_t *h;
22961f6eb021SLiane Praza 	scf_service_t *svc = NULL;
22971f6eb021SLiane Praza 	scf_instance_t *inst = NULL;
22981f6eb021SLiane Praza 	scf_propertygroup_t *pg = NULL;
22991f6eb021SLiane Praza 	scf_snapshot_t *snap = NULL;
23001f6eb021SLiane Praza 	scf_pg_tmpl_t *pg_tmpl = NULL;
23011f6eb021SLiane Praza 	int err;
23021f6eb021SLiane Praza 	int found = 0;
23031f6eb021SLiane Praza 	char *tmpl_type;
23041f6eb021SLiane Praza 	uint8_t required;
23051f6eb021SLiane Praza 	int ret;
23061f6eb021SLiane Praza 
23071f6eb021SLiane Praza 	if (t == NULL) {
23081f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
23091f6eb021SLiane Praza 		return (-1);
23101f6eb021SLiane Praza 	}
23111f6eb021SLiane Praza 
23121f6eb021SLiane Praza 	h = t->pt_h;
23131f6eb021SLiane Praza 
23141f6eb021SLiane Praza 	if (t->pt_populated == 0) {
23151f6eb021SLiane Praza 		if ((svc = scf_service_create(h)) == NULL ||
23161f6eb021SLiane Praza 		    (inst = scf_instance_create(h)) == NULL ||
23171f6eb021SLiane Praza 		    (pg = scf_pg_create(h)) == NULL) {
23181f6eb021SLiane Praza 			goto fail_non_populated;
23191f6eb021SLiane Praza 		}
23201f6eb021SLiane Praza 
23211f6eb021SLiane Praza 		ret = scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
23221f6eb021SLiane Praza 		    NULL, SCF_DECODE_FMRI_EXACT);
23231f6eb021SLiane Praza 		if (ret == 0) {
23241f6eb021SLiane Praza 			scf_service_destroy(svc);
23251f6eb021SLiane Praza 			svc = NULL;
23261f6eb021SLiane Praza 		} else if (ret != 0 &&
23271f6eb021SLiane Praza 		    scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED) {
23281f6eb021SLiane Praza 			ret = scf_handle_decode_fmri(h, fmri, NULL, svc,
23291f6eb021SLiane Praza 			    NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT);
23301f6eb021SLiane Praza 			if (ret == 0) {
23311f6eb021SLiane Praza 				scf_instance_destroy(inst);
23321f6eb021SLiane Praza 				inst = NULL;
23331f6eb021SLiane Praza 			}
23341f6eb021SLiane Praza 		}
23351f6eb021SLiane Praza 
23361f6eb021SLiane Praza 		if (ret != 0) {
23371f6eb021SLiane Praza 			if (ismember(scf_error(), errors_server)) {
23381f6eb021SLiane Praza 				goto fail_non_populated;
23391f6eb021SLiane Praza 			} else switch (scf_error()) {
23401f6eb021SLiane Praza 			case SCF_ERROR_CONSTRAINT_VIOLATED:
23411f6eb021SLiane Praza 				(void) scf_set_error(
23421f6eb021SLiane Praza 				    SCF_ERROR_INVALID_ARGUMENT);
23431f6eb021SLiane Praza 				goto fail_non_populated;
23441f6eb021SLiane Praza 
23451f6eb021SLiane Praza 			case SCF_ERROR_INVALID_ARGUMENT:
23461f6eb021SLiane Praza 			case SCF_ERROR_NOT_FOUND:
23471f6eb021SLiane Praza 				goto fail_non_populated;
23481f6eb021SLiane Praza 
23491f6eb021SLiane Praza 			case SCF_ERROR_HANDLE_MISMATCH:
23501f6eb021SLiane Praza 			case SCF_ERROR_NOT_SET:
23511f6eb021SLiane Praza 			default:
23521f6eb021SLiane Praza 				assert(0);
23531f6eb021SLiane Praza 				abort();
23541f6eb021SLiane Praza 			}
23551f6eb021SLiane Praza 		}
23561f6eb021SLiane Praza 
23571f6eb021SLiane Praza 		assert(svc == NULL || inst == NULL);
23581f6eb021SLiane Praza 		assert(svc != NULL || inst != NULL);
23591f6eb021SLiane Praza 
23601f6eb021SLiane Praza 		if (inst != NULL) {
23611f6eb021SLiane Praza 			if (snapshot == NULL ||
23621f6eb021SLiane Praza 			    strcmp(snapshot, "running") == 0 ||
23631f6eb021SLiane Praza 			    (flags & SCF_PG_TMPL_FLAG_CURRENT) ==
23641f6eb021SLiane Praza 			    SCF_PG_TMPL_FLAG_CURRENT) {
23651f6eb021SLiane Praza 				if (_get_snapshot(inst, NULL, &snap) == -1)
23661f6eb021SLiane Praza 					goto fail_non_populated;
23671f6eb021SLiane Praza 			} else {
23681f6eb021SLiane Praza 				(void) scf_set_error(SCF_ERROR_NONE);
23691f6eb021SLiane Praza 				if (_get_snapshot(inst, snapshot,
23701f6eb021SLiane Praza 				    &snap) == -1) {
23711f6eb021SLiane Praza 					goto fail_non_populated;
23721f6eb021SLiane Praza 				} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
23731f6eb021SLiane Praza 					goto fail_non_populated;
23741f6eb021SLiane Praza 				}
23751f6eb021SLiane Praza 			}
23761f6eb021SLiane Praza 		} else {
23771f6eb021SLiane Praza 			scf_snapshot_destroy(snap);
23781f6eb021SLiane Praza 			snap = NULL;
23791f6eb021SLiane Praza 		}
23801f6eb021SLiane Praza 
23811f6eb021SLiane Praza 		pg_tmpl = t;
23821f6eb021SLiane Praza 		pg_tmpl->pt_orig_inst = inst;
23831f6eb021SLiane Praza 		pg_tmpl->pt_orig_svc = svc;
23841f6eb021SLiane Praza 		pg_tmpl->pt_snap = snap;
23851f6eb021SLiane Praza 		pg_tmpl->pt_is_iter = 1;
23861f6eb021SLiane Praza 		pg_tmpl->pt_iter_last = SCF__TMPL_ITER_NONE;
23871f6eb021SLiane Praza 		pg_tmpl->pt_pg = pg;
23881f6eb021SLiane Praza 		pg_tmpl->pt_populated = 1;
23891f6eb021SLiane Praza 	} else {
23901f6eb021SLiane Praza 		if (t->pt_is_iter != 1) {
23911f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
23921f6eb021SLiane Praza 			return (-1);
23931f6eb021SLiane Praza 		}
23941f6eb021SLiane Praza 		pg_tmpl = t;
23951f6eb021SLiane Praza 		assert(pg_tmpl->pt_pg != NULL);
23961f6eb021SLiane Praza 	}
23971f6eb021SLiane Praza 
23981f6eb021SLiane Praza 	if (pg_tmpl->pt_iter == NULL) {
23991f6eb021SLiane Praza 		pg_tmpl->pt_iter = _get_next_iterator(h, pg_tmpl, snapshot,
24001f6eb021SLiane Praza 		    (flags & SCF_PG_TMPL_FLAG_EXACT) ? 1 : 0);
24011f6eb021SLiane Praza 		if (pg_tmpl->pt_iter == NULL) {
24021f6eb021SLiane Praza 			if (scf_error() == SCF_ERROR_NOT_FOUND)
24031f6eb021SLiane Praza 				return (0);
24041f6eb021SLiane Praza 			else
24051f6eb021SLiane Praza 				return (-1);
24061f6eb021SLiane Praza 		}
24071f6eb021SLiane Praza 	}
24081f6eb021SLiane Praza 
24091f6eb021SLiane Praza 	while (found == 0) {
24101f6eb021SLiane Praza 		while ((err = scf_iter_next_pg(pg_tmpl->pt_iter,
24111f6eb021SLiane Praza 		    pg_tmpl->pt_pg)) != 1) {
24121f6eb021SLiane Praza 			if (err == -1) {
24131f6eb021SLiane Praza 				if (ismember(scf_error(), errors_server)) {
24141f6eb021SLiane Praza 					return (-1);
24151f6eb021SLiane Praza 				} else switch (scf_error()) {
24161f6eb021SLiane Praza 				case SCF_ERROR_HANDLE_MISMATCH:
24171f6eb021SLiane Praza 					return (-1);
24181f6eb021SLiane Praza 
24191f6eb021SLiane Praza 				case SCF_ERROR_NOT_SET:
24201f6eb021SLiane Praza 				case SCF_ERROR_INVALID_ARGUMENT:
24211f6eb021SLiane Praza 				default:
24221f6eb021SLiane Praza 					assert(0);
24231f6eb021SLiane Praza 					abort();
24241f6eb021SLiane Praza 				}
24251f6eb021SLiane Praza 			} else if (err == 0)  {
24261f6eb021SLiane Praza 				/* This iteration is done.  Get the next one */
24271f6eb021SLiane Praza 				scf_iter_destroy(pg_tmpl->pt_iter);
24281f6eb021SLiane Praza 				pg_tmpl->pt_iter = _get_next_iterator(h,
24291f6eb021SLiane Praza 				    pg_tmpl, snapshot,
24301f6eb021SLiane Praza 				    (flags & SCF_PG_TMPL_FLAG_EXACT) ? 1 : 0);
24311f6eb021SLiane Praza 				if (pg_tmpl->pt_iter == NULL) {
24321f6eb021SLiane Praza 					if (scf_error() == SCF_ERROR_NOT_FOUND)
24331f6eb021SLiane Praza 						return (0);
24341f6eb021SLiane Praza 					else
24351f6eb021SLiane Praza 						return (-1);
24361f6eb021SLiane Praza 				}
24371f6eb021SLiane Praza 				continue;
24381f6eb021SLiane Praza 			} else {
24391f6eb021SLiane Praza 				assert(0);
24401f6eb021SLiane Praza 				abort();
24411f6eb021SLiane Praza 			}
24421f6eb021SLiane Praza 		}
24431f6eb021SLiane Praza 
24441f6eb021SLiane Praza 		/*
24451f6eb021SLiane Praza 		 * Discard pgs which don't exist at the right scoping.  This
24461f6eb021SLiane Praza 		 * check also makes sure that if we're looking at, for
24471f6eb021SLiane Praza 		 * example, svc:/system/svc/restarter:default, that we
24481f6eb021SLiane Praza 		 * don't hand back the same property groups twice.
24491f6eb021SLiane Praza 		 */
24501f6eb021SLiane Praza 		switch (t->pt_iter_last) {
24511f6eb021SLiane Praza 		case SCF__TMPL_ITER_INST:
24521f6eb021SLiane Praza 			ret = check_target_match(pg_tmpl->pt_pg,
24531f6eb021SLiane Praza 			    SCF_TM_TARGET_THIS);
24541f6eb021SLiane Praza 			break;
24551f6eb021SLiane Praza 		case SCF__TMPL_ITER_RESTARTER:
24561f6eb021SLiane Praza 			ret = check_target_match(pg_tmpl->pt_pg,
24571f6eb021SLiane Praza 			    SCF_TM_TARGET_DELEGATE);
24581f6eb021SLiane Praza 			break;
24591f6eb021SLiane Praza 		case SCF__TMPL_ITER_GLOBAL:
24601f6eb021SLiane Praza 			ret = check_target_match(pg_tmpl->pt_pg,
24611f6eb021SLiane Praza 			    SCF_TM_TARGET_ALL);
24621f6eb021SLiane Praza 			break;
24631f6eb021SLiane Praza 		case SCF__TMPL_ITER_NONE:
24641f6eb021SLiane Praza 		default:
24651f6eb021SLiane Praza 			assert(0);
24661f6eb021SLiane Praza 			abort();
24671f6eb021SLiane Praza 		}
24681f6eb021SLiane Praza 
24691f6eb021SLiane Praza 		if (ret != 0)
24701f6eb021SLiane Praza 			continue;
24711f6eb021SLiane Praza 
24721f6eb021SLiane Praza 		/*
24731f6eb021SLiane Praza 		 * If walking only required property groups, check if
24741f6eb021SLiane Praza 		 * the retrieved group is required.
24751f6eb021SLiane Praza 		 */
24761f6eb021SLiane Praza 		if (flags & SCF_PG_TMPL_FLAG_REQUIRED) {
24771f6eb021SLiane Praza 			if (scf_tmpl_pg_required(pg_tmpl, &required) == 0) {
24781f6eb021SLiane Praza 				if (required == 0)
24791f6eb021SLiane Praza 					continue;
24801f6eb021SLiane Praza 			} else {
24811f6eb021SLiane Praza 				return (-1);
24821f6eb021SLiane Praza 			}
24831f6eb021SLiane Praza 		}
24841f6eb021SLiane Praza 
24851f6eb021SLiane Praza 		/*
24861f6eb021SLiane Praza 		 * If type != NULL, check if type property matches.  If no
24871f6eb021SLiane Praza 		 * type property exists, consider it a match.
24881f6eb021SLiane Praza 		 */
24891f6eb021SLiane Praza 		if (type != NULL) {
24901f6eb021SLiane Praza 			if (scf_tmpl_pg_type(pg_tmpl, &tmpl_type) != -1) {
24911f6eb021SLiane Praza 				if (strcmp(tmpl_type, SCF_TMPL_WILDCARD)
24921f6eb021SLiane Praza 				    == 0 || strcmp(type, tmpl_type) == 0) {
24931f6eb021SLiane Praza 					free(tmpl_type);
24941f6eb021SLiane Praza 					break;
24951f6eb021SLiane Praza 				}
24961f6eb021SLiane Praza 				free(tmpl_type);
24971f6eb021SLiane Praza 			} else if (scf_error() == SCF_ERROR_NOT_FOUND ||
24981f6eb021SLiane Praza 			    scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED ||
24991f6eb021SLiane Praza 			    scf_error() == SCF_ERROR_TYPE_MISMATCH) {
25001f6eb021SLiane Praza 				break;
25011f6eb021SLiane Praza 			} else {
25021f6eb021SLiane Praza 				return (-1);
25031f6eb021SLiane Praza 			}
25041f6eb021SLiane Praza 		} else {
25051f6eb021SLiane Praza 			break;
25061f6eb021SLiane Praza 		}
25071f6eb021SLiane Praza 	}
25081f6eb021SLiane Praza 
25091f6eb021SLiane Praza 	return (1);
25101f6eb021SLiane Praza 
25111f6eb021SLiane Praza fail_non_populated:
25121f6eb021SLiane Praza 	scf_service_destroy(svc);
25131f6eb021SLiane Praza 	scf_instance_destroy(inst);
25141f6eb021SLiane Praza 	scf_pg_destroy(pg);
25151f6eb021SLiane Praza 	scf_snapshot_destroy(snap);
25161f6eb021SLiane Praza 	return (-1);
25171f6eb021SLiane Praza }
25181f6eb021SLiane Praza 
25191f6eb021SLiane Praza void
25201f6eb021SLiane Praza scf_tmpl_pg_destroy(scf_pg_tmpl_t *t)
25211f6eb021SLiane Praza {
25221f6eb021SLiane Praza 	if (t == NULL)
25231f6eb021SLiane Praza 		return;
25241f6eb021SLiane Praza 
25251f6eb021SLiane Praza 	scf_pg_destroy(t->pt_pg);
25261f6eb021SLiane Praza 	scf_instance_destroy(t->pt_inst);
25271f6eb021SLiane Praza 	if (t->pt_inst != t->pt_orig_inst)
25281f6eb021SLiane Praza 		scf_instance_destroy(t->pt_orig_inst);
25291f6eb021SLiane Praza 	scf_snapshot_destroy(t->pt_snap);
25301f6eb021SLiane Praza 	scf_service_destroy(t->pt_orig_svc);
25311f6eb021SLiane Praza 	if (t->pt_svc != t->pt_orig_svc)
25321f6eb021SLiane Praza 		scf_service_destroy(t->pt_svc);
25331f6eb021SLiane Praza 	scf_iter_destroy(t->pt_iter);
25341f6eb021SLiane Praza 	free(t);
25351f6eb021SLiane Praza }
25361f6eb021SLiane Praza 
25371f6eb021SLiane Praza void
25381f6eb021SLiane Praza scf_tmpl_pg_reset(scf_pg_tmpl_t *t)
25391f6eb021SLiane Praza {
25401f6eb021SLiane Praza 	scf_pg_destroy(t->pt_pg);
25411f6eb021SLiane Praza 	t->pt_pg = NULL;
25421f6eb021SLiane Praza 
25431f6eb021SLiane Praza 	scf_instance_destroy(t->pt_inst);
25441f6eb021SLiane Praza 	if (t->pt_inst != t->pt_orig_inst)
25451f6eb021SLiane Praza 		scf_instance_destroy(t->pt_orig_inst);
25461f6eb021SLiane Praza 	t->pt_inst = NULL;
25471f6eb021SLiane Praza 	t->pt_orig_inst = NULL;
25481f6eb021SLiane Praza 
25491f6eb021SLiane Praza 	scf_snapshot_destroy(t->pt_snap);
25501f6eb021SLiane Praza 	t->pt_snap = NULL;
25511f6eb021SLiane Praza 
25521f6eb021SLiane Praza 	scf_service_destroy(t->pt_orig_svc);
25531f6eb021SLiane Praza 	if (t->pt_svc != t->pt_orig_svc)
25541f6eb021SLiane Praza 		scf_service_destroy(t->pt_svc);
25551f6eb021SLiane Praza 	t->pt_orig_svc = NULL;
25561f6eb021SLiane Praza 	t->pt_svc = NULL;
25571f6eb021SLiane Praza 
25581f6eb021SLiane Praza 	scf_iter_destroy(t->pt_iter);
25591f6eb021SLiane Praza 	t->pt_iter = NULL;
25601f6eb021SLiane Praza 
25611f6eb021SLiane Praza 	t->pt_populated = 0;
25621f6eb021SLiane Praza 	t->pt_is_iter = 0;
25631f6eb021SLiane Praza 	t->pt_iter_last = 0;
25641f6eb021SLiane Praza 
25651f6eb021SLiane Praza 	/* Do not reset t->pt_h. */
25661f6eb021SLiane Praza }
25671f6eb021SLiane Praza 
25681f6eb021SLiane Praza /*
25691f6eb021SLiane Praza  * int scf_tmpl_get_by_prop()
25701f6eb021SLiane Praza  *
25711f6eb021SLiane Praza  * Get the property template given a property group template and property
25721f6eb021SLiane Praza  * name.  No flags are currently defined for this function.
25731f6eb021SLiane Praza  *
25741f6eb021SLiane Praza  * Returns NULL on failure, and sets scf_error():
25751f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
25761f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
25771f6eb021SLiane Praza  *   SCF_ERROR_DELETED
25781f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
25791f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
25801f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
25811f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
25821f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
25831f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
25841f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
25851f6eb021SLiane Praza  *     Template object matching property doesn't exist in the repository.
25861f6eb021SLiane Praza  *   SCF_ERROR_TYPE_MISMATCH
25871f6eb021SLiane Praza  *     Matching template object is the wrong type in the repository.
25881f6eb021SLiane Praza  */
25891f6eb021SLiane Praza int
25901f6eb021SLiane Praza scf_tmpl_get_by_prop(scf_pg_tmpl_t *t, const char *prop,
25911f6eb021SLiane Praza     scf_prop_tmpl_t *prop_tmpl, int flags)
25921f6eb021SLiane Praza {
25931f6eb021SLiane Praza 	char *tmpl_prop_name;
25941f6eb021SLiane Praza 	scf_propertygroup_t *pg = NULL;
25951f6eb021SLiane Praza 	char *pg_type;
25961f6eb021SLiane Praza 	int found = 0;
25971f6eb021SLiane Praza 
25981f6eb021SLiane Praza 	if (flags != 0) {
25991f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
26001f6eb021SLiane Praza 		return (-1);
26011f6eb021SLiane Praza 	}
26021f6eb021SLiane Praza 
26031f6eb021SLiane Praza 	scf_tmpl_prop_reset(prop_tmpl);
26041f6eb021SLiane Praza 	if ((pg = scf_pg_create(scf_pg_handle(t->pt_pg))) == NULL)
26051f6eb021SLiane Praza 		return (-1);
26061f6eb021SLiane Praza 
26071f6eb021SLiane Praza 	tmpl_prop_name = _tmpl_prop_name(prop, t);
26081f6eb021SLiane Praza 	if (tmpl_prop_name == NULL) {
26091f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_NOT_SET);
26101f6eb021SLiane Praza 		return (-1);
26111f6eb021SLiane Praza 	}
26121f6eb021SLiane Praza 
26131f6eb021SLiane Praza 	if (_get_pg(t->pt_svc, t->pt_inst, t->pt_snap,
26141f6eb021SLiane Praza 	    tmpl_prop_name, pg) != 0) {
26151f6eb021SLiane Praza 		if (!ismember(scf_error(), errors_server)) {
26161f6eb021SLiane Praza 			switch (scf_error()) {
26171f6eb021SLiane Praza 			case SCF_ERROR_NOT_FOUND:
26181f6eb021SLiane Praza 			case SCF_ERROR_INVALID_ARGUMENT:
26191f6eb021SLiane Praza 				break;
26201f6eb021SLiane Praza 
26211f6eb021SLiane Praza 			case SCF_ERROR_NOT_SET:
26221f6eb021SLiane Praza 			case SCF_ERROR_HANDLE_MISMATCH:
26231f6eb021SLiane Praza 			default:
26241f6eb021SLiane Praza 				assert(0);
26251f6eb021SLiane Praza 				abort();
26261f6eb021SLiane Praza 			}
26271f6eb021SLiane Praza 		}
26281f6eb021SLiane Praza 	} else {
26291f6eb021SLiane Praza 		/*
26301f6eb021SLiane Praza 		 * We've only found a template property group if the type
26311f6eb021SLiane Praza 		 * is correct.
26321f6eb021SLiane Praza 		 */
26331f6eb021SLiane Praza 		if ((pg_type = _scf_get_pg_type(pg)) != NULL &&
26341f6eb021SLiane Praza 		    strcmp(pg_type, SCF_GROUP_TEMPLATE_PROP_PATTERN) == 0)
26351f6eb021SLiane Praza 			found++;
26361f6eb021SLiane Praza 		else
26371f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_TYPE_MISMATCH);
26381f6eb021SLiane Praza 
26391f6eb021SLiane Praza 
26401f6eb021SLiane Praza 		free(pg_type);
26411f6eb021SLiane Praza 	}
26421f6eb021SLiane Praza 
26431f6eb021SLiane Praza 	if (found == 0) {
26441f6eb021SLiane Praza 		scf_pg_destroy(pg);
26451f6eb021SLiane Praza 		free(tmpl_prop_name);
26461f6eb021SLiane Praza 		return (-1);
26471f6eb021SLiane Praza 	}
26481f6eb021SLiane Praza 
26491f6eb021SLiane Praza 	prop_tmpl->prt_h = scf_pg_handle(t->pt_pg);
26501f6eb021SLiane Praza 	prop_tmpl->prt_t = t;
26511f6eb021SLiane Praza 	prop_tmpl->prt_pg = pg;
26521f6eb021SLiane Praza 	prop_tmpl->prt_pg_name = tmpl_prop_name;
26531f6eb021SLiane Praza 	prop_tmpl->prt_populated = 1;
26541f6eb021SLiane Praza 
26551f6eb021SLiane Praza 	return (0);
26561f6eb021SLiane Praza }
26571f6eb021SLiane Praza 
26581f6eb021SLiane Praza /*
26591f6eb021SLiane Praza  * scf_prop_tmpl_t *scf_tmpl_prop_create(scf_handle_t *);
26601f6eb021SLiane Praza  *
26611f6eb021SLiane Praza  * Returns NULL on failure, sets scf_error() to _INVALID_ARGUMENT, or
26621f6eb021SLiane Praza  * _NO_MEMORY.
26631f6eb021SLiane Praza  */
26641f6eb021SLiane Praza scf_prop_tmpl_t *
26651f6eb021SLiane Praza scf_tmpl_prop_create(scf_handle_t *handle)
26661f6eb021SLiane Praza {
26671f6eb021SLiane Praza 	scf_prop_tmpl_t *pt;
26681f6eb021SLiane Praza 
26691f6eb021SLiane Praza 	if (handle == NULL) {
26701f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
26711f6eb021SLiane Praza 		return (NULL);
26721f6eb021SLiane Praza 	}
26731f6eb021SLiane Praza 	pt = calloc(1, sizeof (scf_prop_tmpl_t));
26741f6eb021SLiane Praza 	if (pt == NULL)
26751f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
26761f6eb021SLiane Praza 	else
26771f6eb021SLiane Praza 		pt->prt_h = handle;
26781f6eb021SLiane Praza 
26791f6eb021SLiane Praza 	return (pt);
26801f6eb021SLiane Praza }
26811f6eb021SLiane Praza 
26821f6eb021SLiane Praza /*
26831f6eb021SLiane Praza  * int scf_tmpl_iter_props()
26841f6eb021SLiane Praza  *
26851f6eb021SLiane Praza  * Iterates over all property templates defined in the specified property
26861f6eb021SLiane Praza  * group template.  The iterator state is stored on the property template
26871f6eb021SLiane Praza  * data structure, and the data structure should be allocated with
26881f6eb021SLiane Praza  * scf_tmpl_prop_create().  To continue the iteration, the previously
26891f6eb021SLiane Praza  * returned structure should be passed in as an argument to this function.
26901f6eb021SLiane Praza  * flags can include SCF_PROP_TMPL_FLAG_REQUIRED.  The function returns
26911f6eb021SLiane Praza  * 1 when a result was found, and 0 when the iteration is complete.
26921f6eb021SLiane Praza  *
26931f6eb021SLiane Praza  * Returns -1 on failure, and sets scf_error():
26941f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
26951f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
26961f6eb021SLiane Praza  *   SCF_ERROR_DELETED
26971f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
26981f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
26991f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
27001f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
27011f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
27021f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
27031f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
27041f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
27051f6eb021SLiane Praza  *     Template data is invalid.  One of the property templates in this
27061f6eb021SLiane Praza  *     pg_tmpl is malformed.
27071f6eb021SLiane Praza  */
27081f6eb021SLiane Praza int
27091f6eb021SLiane Praza scf_tmpl_iter_props(scf_pg_tmpl_t *t, scf_prop_tmpl_t *pt, int flags)
27101f6eb021SLiane Praza {
27111f6eb021SLiane Praza 	scf_prop_tmpl_t *prop_tmpl;
27121f6eb021SLiane Praza 	char *pg_pat;
27131f6eb021SLiane Praza 	char *pg_name = NULL;
27141f6eb021SLiane Praza 	int err;
27151f6eb021SLiane Praza 	int ret;
27161f6eb021SLiane Praza 	ssize_t size = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
27171f6eb021SLiane Praza 	uint8_t required;
27181f6eb021SLiane Praza 	scf_handle_t *h;
27191f6eb021SLiane Praza 	scf_propertygroup_t *pg = NULL;
27201f6eb021SLiane Praza 	scf_iter_t *iter = NULL;
27211f6eb021SLiane Praza 
27221f6eb021SLiane Praza 	assert(size != 0);
27231f6eb021SLiane Praza 	if (t == NULL || pt == NULL) {
27241f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
27251f6eb021SLiane Praza 		return (-1);
27261f6eb021SLiane Praza 	}
27271f6eb021SLiane Praza 
27281f6eb021SLiane Praza 	assert(t->pt_inst == NULL || t->pt_svc == NULL);
27291f6eb021SLiane Praza 	assert(t->pt_inst != NULL || t->pt_svc != NULL);
27301f6eb021SLiane Praza 
27311f6eb021SLiane Praza 	if ((pg_name = malloc(size)) == NULL) {
27321f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
27331f6eb021SLiane Praza 		return (-1);
27341f6eb021SLiane Praza 	}
27351f6eb021SLiane Praza 
27361f6eb021SLiane Praza 	if (pt->prt_populated == 0) {
27371f6eb021SLiane Praza 		if ((h = scf_pg_handle(t->pt_pg)) == NULL)
27381f6eb021SLiane Praza 			goto fail_non_populated;
27391f6eb021SLiane Praza 
27401f6eb021SLiane Praza 		if ((pg = scf_pg_create(h)) == NULL ||
27411f6eb021SLiane Praza 		    (iter = scf_iter_create(h)) == NULL)
27421f6eb021SLiane Praza 			goto fail_non_populated;
27431f6eb021SLiane Praza 
27441f6eb021SLiane Praza 		if (t->pt_inst != NULL)
27451f6eb021SLiane Praza 			err = scf_iter_instance_pgs_typed_composed(iter,
27461f6eb021SLiane Praza 			    t->pt_inst, t->pt_snap,
27471f6eb021SLiane Praza 			    SCF_GROUP_TEMPLATE_PROP_PATTERN);
27481f6eb021SLiane Praza 		else if (t->pt_svc != NULL)
27491f6eb021SLiane Praza 			err = scf_iter_service_pgs_typed(iter, t->pt_svc,
27501f6eb021SLiane Praza 			    SCF_GROUP_TEMPLATE_PROP_PATTERN);
27511f6eb021SLiane Praza 
27521f6eb021SLiane Praza 		if (err != 0) {
27531f6eb021SLiane Praza 			if (ismember(scf_error(), errors_server)) {
27541f6eb021SLiane Praza 				goto fail_non_populated;
27551f6eb021SLiane Praza 			} else switch (scf_error()) {
27561f6eb021SLiane Praza 			case SCF_ERROR_INVALID_ARGUMENT:
27571f6eb021SLiane Praza 				goto fail_non_populated;
27581f6eb021SLiane Praza 
27591f6eb021SLiane Praza 			case SCF_ERROR_NOT_SET:
27601f6eb021SLiane Praza 			case SCF_ERROR_HANDLE_MISMATCH:
27611f6eb021SLiane Praza 			default:
27621f6eb021SLiane Praza 				assert(0);
27631f6eb021SLiane Praza 				abort();
27641f6eb021SLiane Praza 			}
27651f6eb021SLiane Praza 
27661f6eb021SLiane Praza 		}
27671f6eb021SLiane Praza 		prop_tmpl = pt;
27681f6eb021SLiane Praza 		prop_tmpl->prt_t = t;
27691f6eb021SLiane Praza 		prop_tmpl->prt_populated = 1;
27701f6eb021SLiane Praza 		prop_tmpl->prt_pg = pg;
27711f6eb021SLiane Praza 		prop_tmpl->prt_iter = iter;
27721f6eb021SLiane Praza 	} else {
27731f6eb021SLiane Praza 		prop_tmpl = pt;
27741f6eb021SLiane Praza 	}
27751f6eb021SLiane Praza 
27761f6eb021SLiane Praza 	while ((err = scf_iter_next_pg(prop_tmpl->prt_iter,
27771f6eb021SLiane Praza 	    prop_tmpl->prt_pg)) > 0) {
27781f6eb021SLiane Praza 		/*
27791f6eb021SLiane Praza 		 * Check if the name matches the appropriate property
27801f6eb021SLiane Praza 		 * group template name.
27811f6eb021SLiane Praza 		 */
27821f6eb021SLiane Praza 		pg_pat = _scf_read_single_astring_from_pg(prop_tmpl->prt_pg,
27831f6eb021SLiane Praza 		    SCF_PROPERTY_TM_PG_PATTERN);
27841f6eb021SLiane Praza 		if (pg_pat == NULL) {
27851f6eb021SLiane Praza 			if (ismember(scf_error(), errors_server)) {
27861f6eb021SLiane Praza 				uu_free(pg_name);
27871f6eb021SLiane Praza 				return (-1);
27881f6eb021SLiane Praza 			} else switch (scf_error()) {
27891f6eb021SLiane Praza 			case SCF_ERROR_NOT_FOUND:
27901f6eb021SLiane Praza 				continue;
27911f6eb021SLiane Praza 
27921f6eb021SLiane Praza 			case SCF_ERROR_CONSTRAINT_VIOLATED:
27931f6eb021SLiane Praza 			case SCF_ERROR_TYPE_MISMATCH:
27941f6eb021SLiane Praza 				(void) scf_set_error(
27951f6eb021SLiane Praza 				    SCF_ERROR_TEMPLATE_INVALID);
27961f6eb021SLiane Praza 				free(pg_name);
27971f6eb021SLiane Praza 				return (-1);
27981f6eb021SLiane Praza 
27991f6eb021SLiane Praza 			case SCF_ERROR_INVALID_ARGUMENT:
28001f6eb021SLiane Praza 			case SCF_ERROR_NOT_SET:
28011f6eb021SLiane Praza 			default:
28021f6eb021SLiane Praza 				assert(0);
28031f6eb021SLiane Praza 				abort();
28041f6eb021SLiane Praza 			}
28051f6eb021SLiane Praza 		}
28061f6eb021SLiane Praza 		if ((ret = scf_pg_get_name(t->pt_pg, pg_name, size)) <= 0) {
28071f6eb021SLiane Praza 			free(pg_pat);
28081f6eb021SLiane Praza 			if (ret == 0)
28091f6eb021SLiane Praza 				continue;
28101f6eb021SLiane Praza 
28111f6eb021SLiane Praza 			if (ismember(scf_error(), errors_server)) {
28121f6eb021SLiane Praza 				free(pg_name);
28131f6eb021SLiane Praza 				return (-1);
28141f6eb021SLiane Praza 			} else {
28151f6eb021SLiane Praza 				assert(0);
28161f6eb021SLiane Praza 				abort();
28171f6eb021SLiane Praza 			}
28181f6eb021SLiane Praza 		}
28191f6eb021SLiane Praza 		if (strcmp(pg_pat, pg_name) != 0) {
28201f6eb021SLiane Praza 			free(pg_pat);
28211f6eb021SLiane Praza 			continue;
28221f6eb021SLiane Praza 		}
28231f6eb021SLiane Praza 		free(pg_pat);
28241f6eb021SLiane Praza 
28251f6eb021SLiane Praza 		/*
28261f6eb021SLiane Praza 		 * If walking only required properties, check if
28271f6eb021SLiane Praza 		 * the retrieved property is required.
28281f6eb021SLiane Praza 		 */
28291f6eb021SLiane Praza 		if (flags & SCF_PROP_TMPL_FLAG_REQUIRED) {
28301f6eb021SLiane Praza 			if (scf_tmpl_prop_required(prop_tmpl, &required) == 0) {
28311f6eb021SLiane Praza 				if (required == 0)
28321f6eb021SLiane Praza 					continue;
28331f6eb021SLiane Praza 			} else {
28341f6eb021SLiane Praza 				free(pg_name);
28351f6eb021SLiane Praza 				return (-1);
28361f6eb021SLiane Praza 			}
28371f6eb021SLiane Praza 		}
28381f6eb021SLiane Praza 		free(pg_name);
28391f6eb021SLiane Praza 		return (0);
28401f6eb021SLiane Praza 	}
28411f6eb021SLiane Praza 
28421f6eb021SLiane Praza 	if (err == -1) {
28431f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
28441f6eb021SLiane Praza 			free(pg_name);
28451f6eb021SLiane Praza 			return (-1);
28461f6eb021SLiane Praza 		} else {
28471f6eb021SLiane Praza 			assert(0);
28481f6eb021SLiane Praza 			abort();
28491f6eb021SLiane Praza 		}
28501f6eb021SLiane Praza 	} else if (err == 0)  {
28511f6eb021SLiane Praza 		scf_iter_destroy(prop_tmpl->prt_iter);
28521f6eb021SLiane Praza 		prop_tmpl->prt_iter = NULL;
28531f6eb021SLiane Praza 		prop_tmpl->prt_populated = 0;
28541f6eb021SLiane Praza 	}
28551f6eb021SLiane Praza 	free(pg_name);
28561f6eb021SLiane Praza 
28571f6eb021SLiane Praza 	return (1);
28581f6eb021SLiane Praza 
28591f6eb021SLiane Praza fail_non_populated:
28601f6eb021SLiane Praza 	free(pg_name);
28611f6eb021SLiane Praza 	scf_pg_destroy(pg);
28621f6eb021SLiane Praza 	scf_iter_destroy(iter);
28631f6eb021SLiane Praza 	return (-1);
28641f6eb021SLiane Praza }
28651f6eb021SLiane Praza 
28661f6eb021SLiane Praza void
28671f6eb021SLiane Praza scf_tmpl_prop_destroy(scf_prop_tmpl_t *t)
28681f6eb021SLiane Praza {
28691f6eb021SLiane Praza 	if (t == NULL)
28701f6eb021SLiane Praza 		return;
28711f6eb021SLiane Praza 
28721f6eb021SLiane Praza 	scf_pg_destroy(t->prt_pg);
28731f6eb021SLiane Praza 	free(t->prt_pg_name);
28741f6eb021SLiane Praza 	free(t->prt_iter);
28751f6eb021SLiane Praza 	free(t);
28761f6eb021SLiane Praza }
28771f6eb021SLiane Praza 
28781f6eb021SLiane Praza void
28791f6eb021SLiane Praza scf_tmpl_prop_reset(scf_prop_tmpl_t *t)
28801f6eb021SLiane Praza {
28811f6eb021SLiane Praza 	scf_pg_destroy(t->prt_pg);
28821f6eb021SLiane Praza 	t->prt_pg = NULL;
28831f6eb021SLiane Praza 
28841f6eb021SLiane Praza 	free(t->prt_pg_name);
28851f6eb021SLiane Praza 	t->prt_pg_name = NULL;
28861f6eb021SLiane Praza 
28871f6eb021SLiane Praza 	free(t->prt_iter);
28881f6eb021SLiane Praza 	t->prt_iter = NULL;
28891f6eb021SLiane Praza 
28901f6eb021SLiane Praza 	t->prt_populated = 0;
28911f6eb021SLiane Praza 	t->prt_h = NULL;
28921f6eb021SLiane Praza 	t->prt_t = NULL;
28931f6eb021SLiane Praza }
28941f6eb021SLiane Praza 
28951f6eb021SLiane Praza /*
28961f6eb021SLiane Praza  * Returns -1 on failure.  Sets scf_error():
28971f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
28981f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
28991f6eb021SLiane Praza  *   SCF_ERROR_DELETED
29001f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
29011f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
29021f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
29031f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
29041f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
29051f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
29061f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
29071f6eb021SLiane Praza  *     The name of the template property group (the pname property) has
29081f6eb021SLiane Praza  *     an improper repository format and is not type astring or has
29091f6eb021SLiane Praza  *     more than one value.
29101f6eb021SLiane Praza  */
29111f6eb021SLiane Praza ssize_t
29121f6eb021SLiane Praza scf_tmpl_pg_name(const scf_pg_tmpl_t *t, char **out)
29131f6eb021SLiane Praza {
29141f6eb021SLiane Praza 	return (_scf_tmpl_prop_value(t->pt_pg, SCF_PROPERTY_TM_NAME, out));
29151f6eb021SLiane Praza }
29161f6eb021SLiane Praza 
29171f6eb021SLiane Praza /*
29181f6eb021SLiane Praza  * returns an allocated string that must be freed
29191f6eb021SLiane Praza  *
29201f6eb021SLiane Praza  * Returns NULL on failure, sets scf_error() to:
29211f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
29221f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
29231f6eb021SLiane Praza  *   SCF_ERROR_DELETED
29241f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
29251f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
29261f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
29271f6eb021SLiane Praza  *     name not a valid property name
29281f6eb021SLiane Praza  *     name and locale are too long to make a property name
29291f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
29301f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
29311f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
29321f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
29331f6eb021SLiane Praza  *     Property doesn't exist or exists and has no value.
29341f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
29351f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
29361f6eb021SLiane Praza  */
29371f6eb021SLiane Praza static char *
29381f6eb021SLiane Praza _read_localized_astring_from_pg(scf_propertygroup_t *pg, const char *name,
29391f6eb021SLiane Praza     const char *locale)
29401f6eb021SLiane Praza {
29411f6eb021SLiane Praza 	char *str;
29421f6eb021SLiane Praza 	char *lname_prop;
29431f6eb021SLiane Praza 
29441f6eb021SLiane Praza 	str = _add_locale_to_name(name, locale);
29451f6eb021SLiane Praza 	if (str == NULL)
29461f6eb021SLiane Praza 		return (NULL);
29471f6eb021SLiane Praza 	lname_prop = _scf_read_single_astring_from_pg(pg, str);
29481f6eb021SLiane Praza 	if (lname_prop == NULL) {
29491f6eb021SLiane Praza 		free(str);
29501f6eb021SLiane Praza 		if (scf_error() != SCF_ERROR_NOT_FOUND)
29511f6eb021SLiane Praza 			return (NULL);
29521f6eb021SLiane Praza 		str = _add_locale_to_name(name, "C");
29531f6eb021SLiane Praza 		if (str == NULL)
29541f6eb021SLiane Praza 			return (NULL);
29551f6eb021SLiane Praza 		lname_prop = _scf_read_single_astring_from_pg(pg, str);
29561f6eb021SLiane Praza 	}
29571f6eb021SLiane Praza 	free(str);
29581f6eb021SLiane Praza 	if (lname_prop == NULL) {
29591f6eb021SLiane Praza 		if (scf_error() == SCF_ERROR_TYPE_MISMATCH ||
29601f6eb021SLiane Praza 		    scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED)
29611f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
29621f6eb021SLiane Praza 	}
29631f6eb021SLiane Praza 	return (lname_prop);
29641f6eb021SLiane Praza }
29651f6eb021SLiane Praza 
29661f6eb021SLiane Praza /*
29671f6eb021SLiane Praza  * returns an allocated string that must be freed
29681f6eb021SLiane Praza  *
29691f6eb021SLiane Praza  * Returns -1 on failure, sets scf_error() to:
29701f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
29711f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
29721f6eb021SLiane Praza  *   SCF_ERROR_DELETED
29731f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
29741f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
29751f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
29761f6eb021SLiane Praza  *     locale is too long to make a valid property name
29771f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
29781f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
29791f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
29801f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
29811f6eb021SLiane Praza  *     Property doesn't exist or exists and has no value.
29821f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
29831f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
29841f6eb021SLiane Praza  */
29851f6eb021SLiane Praza ssize_t
29861f6eb021SLiane Praza scf_tmpl_pg_common_name(const scf_pg_tmpl_t *t, const char *locale, char **out)
29871f6eb021SLiane Praza {
29881f6eb021SLiane Praza 	assert(out != NULL);
29891f6eb021SLiane Praza 	if ((*out = _read_localized_astring_from_pg(t->pt_pg,
29901f6eb021SLiane Praza 	    SCF_PROPERTY_TM_COMMON_NAME_PREFIX, locale)) == NULL)
29911f6eb021SLiane Praza 		return (-1);
29921f6eb021SLiane Praza 
29931f6eb021SLiane Praza 	return (strlen(*out));
29941f6eb021SLiane Praza }
29951f6eb021SLiane Praza 
29961f6eb021SLiane Praza /*
29971f6eb021SLiane Praza  * returns an allocated string that must be freed
29981f6eb021SLiane Praza  *
29991f6eb021SLiane Praza  * Returns -1 on failure, sets scf_error() to:
30001f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
30011f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
30021f6eb021SLiane Praza  *   SCF_ERROR_DELETED
30031f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
30041f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
30051f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
30061f6eb021SLiane Praza  *     locale is too long to make a valid property name
30071f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
30081f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
30091f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
30101f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
30111f6eb021SLiane Praza  *     Property doesn't exist or exists and has no value.
30121f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
30131f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
30141f6eb021SLiane Praza  */
30151f6eb021SLiane Praza ssize_t
30161f6eb021SLiane Praza scf_tmpl_pg_description(const scf_pg_tmpl_t *t, const char *locale, char **out)
30171f6eb021SLiane Praza {
30181f6eb021SLiane Praza 	assert(out != NULL);
30191f6eb021SLiane Praza 	if ((*out = _read_localized_astring_from_pg(t->pt_pg,
30201f6eb021SLiane Praza 	    SCF_PROPERTY_TM_DESCRIPTION_PREFIX, locale)) == NULL)
30211f6eb021SLiane Praza 		return (-1);
30221f6eb021SLiane Praza 
30231f6eb021SLiane Praza 	return (strlen(*out));
30241f6eb021SLiane Praza }
30251f6eb021SLiane Praza 
30261f6eb021SLiane Praza /*
30271f6eb021SLiane Praza  * Returns -1 on failure.  Sets scf_error():
30281f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
30291f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
30301f6eb021SLiane Praza  *   SCF_ERROR_DELETED
30311f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
30321f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
30331f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
30341f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
30351f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
30361f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
30371f6eb021SLiane Praza  *     'type' property doesn't exist or exists and has no value.
30381f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
30391f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
30401f6eb021SLiane Praza  *     'type' property is not SCF_TYPE_ASTRING or has more than one value.
30411f6eb021SLiane Praza  */
30421f6eb021SLiane Praza ssize_t
30431f6eb021SLiane Praza scf_tmpl_pg_type(const scf_pg_tmpl_t *t, char **out)
30441f6eb021SLiane Praza {
30451f6eb021SLiane Praza 	return (_scf_tmpl_prop_value(t->pt_pg, SCF_PROPERTY_TM_TYPE, out));
30461f6eb021SLiane Praza }
30471f6eb021SLiane Praza 
30481f6eb021SLiane Praza /*
30491f6eb021SLiane Praza  * Returns -1 on failure, sets scf_error() to:
30501f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
30511f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
30521f6eb021SLiane Praza  *   SCF_ERROR_DELETED
30531f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
30541f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
30551f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
30561f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
30571f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
30581f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
30591f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
30601f6eb021SLiane Praza  *     required property is not SCF_TYPE_BOOLEAN or has more than one value.
30611f6eb021SLiane Praza  */
30621f6eb021SLiane Praza int
30631f6eb021SLiane Praza scf_tmpl_pg_required(const scf_pg_tmpl_t *t, uint8_t *out)
30641f6eb021SLiane Praza {
30651f6eb021SLiane Praza 
30661f6eb021SLiane Praza 	if (_read_single_boolean_from_pg(t->pt_pg, SCF_PROPERTY_TM_REQUIRED,
30671f6eb021SLiane Praza 	    out) == -1) {
30681f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
30691f6eb021SLiane Praza 			return (-1);
30701f6eb021SLiane Praza 		} else switch (scf_error()) {
30711f6eb021SLiane Praza 		case SCF_ERROR_CONSTRAINT_VIOLATED:
30721f6eb021SLiane Praza 		case SCF_ERROR_TYPE_MISMATCH:
30731f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
30741f6eb021SLiane Praza 			return (-1);
30751f6eb021SLiane Praza 
30761f6eb021SLiane Praza 		case SCF_ERROR_NOT_FOUND:
30771f6eb021SLiane Praza 			*out = 0;
30781f6eb021SLiane Praza 			return (0);
30791f6eb021SLiane Praza 
30801f6eb021SLiane Praza 		case SCF_ERROR_INVALID_ARGUMENT:
30811f6eb021SLiane Praza 		default:
30821f6eb021SLiane Praza 			assert(0);
30831f6eb021SLiane Praza 			abort();
30841f6eb021SLiane Praza 		}
30851f6eb021SLiane Praza 	}
30861f6eb021SLiane Praza 
30871f6eb021SLiane Praza 	return (0);
30881f6eb021SLiane Praza }
30891f6eb021SLiane Praza 
30901f6eb021SLiane Praza /*
30911f6eb021SLiane Praza  * Returns -1 on failure.  Sets scf_error():
30921f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
30931f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
30941f6eb021SLiane Praza  *   SCF_ERROR_DELETED
30951f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
30961f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
30971f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
30981f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
30991f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
31001f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
31011f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
31021f6eb021SLiane Praza  *     target property is not SCF_TYPE_ASTRING or has more than one value.
31031f6eb021SLiane Praza  */
31041f6eb021SLiane Praza ssize_t
31051f6eb021SLiane Praza scf_tmpl_pg_target(const scf_pg_tmpl_t *t, char **out)
31061f6eb021SLiane Praza {
31071f6eb021SLiane Praza 	*out = _scf_read_single_astring_from_pg(t->pt_pg,
31081f6eb021SLiane Praza 	    SCF_PROPERTY_TM_TARGET);
31091f6eb021SLiane Praza 
31101f6eb021SLiane Praza 	if (*out == NULL) {
31111f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
31121f6eb021SLiane Praza 			return (-1);
31131f6eb021SLiane Praza 		} else switch (scf_error()) {
31141f6eb021SLiane Praza 		case SCF_ERROR_CONSTRAINT_VIOLATED:
31151f6eb021SLiane Praza 		case SCF_ERROR_NOT_FOUND:
31161f6eb021SLiane Praza 		case SCF_ERROR_TYPE_MISMATCH:
31171f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
31181f6eb021SLiane Praza 			return (-1);
31191f6eb021SLiane Praza 
31201f6eb021SLiane Praza 		case SCF_ERROR_INVALID_ARGUMENT:
31211f6eb021SLiane Praza 		case SCF_ERROR_NOT_SET:
31221f6eb021SLiane Praza 		default:
31231f6eb021SLiane Praza 			assert(0);
31241f6eb021SLiane Praza 			abort();
31251f6eb021SLiane Praza 		}
31261f6eb021SLiane Praza 	}
31271f6eb021SLiane Praza 
31281f6eb021SLiane Praza 	return (strlen(*out));
31291f6eb021SLiane Praza }
31301f6eb021SLiane Praza 
31311f6eb021SLiane Praza /*
31321f6eb021SLiane Praza  * Returns -1 on failure.  Sets scf_error():
31331f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
31341f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
31351f6eb021SLiane Praza  *   SCF_ERROR_DELETED
31361f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
31371f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
31381f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
31391f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
31401f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
31411f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
31421f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
31431f6eb021SLiane Praza  */
31441f6eb021SLiane Praza ssize_t
31451f6eb021SLiane Praza scf_tmpl_prop_name(const scf_prop_tmpl_t *t, char **out)
31461f6eb021SLiane Praza {
31471f6eb021SLiane Praza 	*out = _scf_read_single_astring_from_pg(t->prt_pg,
31481f6eb021SLiane Praza 	    SCF_PROPERTY_TM_NAME);
31491f6eb021SLiane Praza 
31501f6eb021SLiane Praza 	if (*out != NULL && *out[0] == '\0') {
31511f6eb021SLiane Praza 		free(*out);
31521f6eb021SLiane Praza 		*out = NULL;
31531f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
31541f6eb021SLiane Praza 	}
31551f6eb021SLiane Praza 	if (*out == NULL) {
31561f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
31571f6eb021SLiane Praza 			return (-1);
31581f6eb021SLiane Praza 		} else switch (scf_error()) {
31591f6eb021SLiane Praza 		case SCF_ERROR_CONSTRAINT_VIOLATED:
31601f6eb021SLiane Praza 		case SCF_ERROR_NOT_FOUND:
31611f6eb021SLiane Praza 		case SCF_ERROR_TEMPLATE_INVALID:
31621f6eb021SLiane Praza 		case SCF_ERROR_TYPE_MISMATCH:
31631f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
31641f6eb021SLiane Praza 			return (-1);
31651f6eb021SLiane Praza 
31661f6eb021SLiane Praza 		case SCF_ERROR_INVALID_ARGUMENT:
31671f6eb021SLiane Praza 		case SCF_ERROR_NOT_SET:
31681f6eb021SLiane Praza 		default:
31691f6eb021SLiane Praza 			assert(0);
31701f6eb021SLiane Praza 			abort();
31711f6eb021SLiane Praza 		}
31721f6eb021SLiane Praza 	}
31731f6eb021SLiane Praza 
31741f6eb021SLiane Praza 	return (strlen(*out));
31751f6eb021SLiane Praza }
31761f6eb021SLiane Praza 
31771f6eb021SLiane Praza /*
31781f6eb021SLiane Praza  * Returns -1 on failure.  Sets scf_error():
31791f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
31801f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
31811f6eb021SLiane Praza  *   SCF_ERROR_DELETED
31821f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
31831f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
31841f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
31851f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
31861f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
31871f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
31881f6eb021SLiane Praza  *     'type' property doesn't exist or exists and has no value.
31891f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
31901f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
31911f6eb021SLiane Praza  *     'type' property is not SCF_TYPE_ASTRING, has more than one value,
31921f6eb021SLiane Praza  *     is SCF_TYPE_INVALID, or is the empty string.
31931f6eb021SLiane Praza  */
31941f6eb021SLiane Praza int
31951f6eb021SLiane Praza scf_tmpl_prop_type(const scf_prop_tmpl_t *t, scf_type_t *out)
31961f6eb021SLiane Praza {
31971f6eb021SLiane Praza 	char *type;
31981f6eb021SLiane Praza 
31991f6eb021SLiane Praza 	type = _scf_read_single_astring_from_pg(t->prt_pg,
32001f6eb021SLiane Praza 	    SCF_PROPERTY_TM_TYPE);
32011f6eb021SLiane Praza 	if (type != NULL && type[0] == '\0') {
32021f6eb021SLiane Praza 		free(type);
32031f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NOT_FOUND);
32041f6eb021SLiane Praza 		return (-1);
32051f6eb021SLiane Praza 	}
32061f6eb021SLiane Praza 	if (type == NULL) {
32071f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
32081f6eb021SLiane Praza 			return (-1);
32091f6eb021SLiane Praza 		} else switch (scf_error()) {
32101f6eb021SLiane Praza 		case SCF_ERROR_CONSTRAINT_VIOLATED:
32111f6eb021SLiane Praza 		case SCF_ERROR_TYPE_MISMATCH:
32121f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
32131f6eb021SLiane Praza 			/*FALLTHROUGH*/
32141f6eb021SLiane Praza 
32151f6eb021SLiane Praza 		case SCF_ERROR_NOT_FOUND:
32161f6eb021SLiane Praza 			return (-1);
32171f6eb021SLiane Praza 
32181f6eb021SLiane Praza 		case SCF_ERROR_INVALID_ARGUMENT:
32191f6eb021SLiane Praza 		case SCF_ERROR_NOT_SET:
32201f6eb021SLiane Praza 		default:
32211f6eb021SLiane Praza 			assert(0);
32221f6eb021SLiane Praza 			abort();
32231f6eb021SLiane Praza 		}
32241f6eb021SLiane Praza 	}
32251f6eb021SLiane Praza 
32261f6eb021SLiane Praza 	*out = scf_string_to_type(type);
32271f6eb021SLiane Praza 	free(type);
32281f6eb021SLiane Praza 
32291f6eb021SLiane Praza 	if (*out == SCF_TYPE_INVALID) {
32301f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
32311f6eb021SLiane Praza 		return (-1);
32321f6eb021SLiane Praza 	}
32331f6eb021SLiane Praza 
32341f6eb021SLiane Praza 	return (0);
32351f6eb021SLiane Praza }
32361f6eb021SLiane Praza 
32371f6eb021SLiane Praza /*
32381f6eb021SLiane Praza  * Returns -1 on failure, sets scf_error() to:
32391f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
32401f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
32411f6eb021SLiane Praza  *   SCF_ERROR_DELETED
32421f6eb021SLiane Praza  *    Property group which represents t was deleted.
32431f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
32441f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
32451f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
32461f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
32471f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
32481f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
32491f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
32501f6eb021SLiane Praza  *     required property is not SCF_TYPE_ASTRING has more than one value.
32511f6eb021SLiane Praza  */
32521f6eb021SLiane Praza int
32531f6eb021SLiane Praza scf_tmpl_prop_required(const scf_prop_tmpl_t *t, uint8_t *out)
32541f6eb021SLiane Praza {
32551f6eb021SLiane Praza 	if (_read_single_boolean_from_pg(t->prt_pg, SCF_PROPERTY_TM_REQUIRED,
32561f6eb021SLiane Praza 	    out) == -1) {
32571f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
32581f6eb021SLiane Praza 			return (-1);
32591f6eb021SLiane Praza 		} else switch (scf_error()) {
32601f6eb021SLiane Praza 		case SCF_ERROR_CONSTRAINT_VIOLATED:
32611f6eb021SLiane Praza 		case SCF_ERROR_TYPE_MISMATCH:
32621f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
32631f6eb021SLiane Praza 			return (-1);
32641f6eb021SLiane Praza 
32651f6eb021SLiane Praza 		case SCF_ERROR_NOT_FOUND:
32661f6eb021SLiane Praza 			*out = 0;
32671f6eb021SLiane Praza 			return (0);
32681f6eb021SLiane Praza 
32691f6eb021SLiane Praza 		case SCF_ERROR_INVALID_ARGUMENT:
32701f6eb021SLiane Praza 		case SCF_ERROR_NOT_SET:
32711f6eb021SLiane Praza 		default:
32721f6eb021SLiane Praza 			assert(0);
32731f6eb021SLiane Praza 			abort();
32741f6eb021SLiane Praza 		}
32751f6eb021SLiane Praza 	}
32761f6eb021SLiane Praza 
32771f6eb021SLiane Praza 	return (0);
32781f6eb021SLiane Praza }
32791f6eb021SLiane Praza 
32801f6eb021SLiane Praza /*
32811f6eb021SLiane Praza  * Returns -1 on failure.  Sets scf_error():
32821f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
32831f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
32841f6eb021SLiane Praza  *   SCF_ERROR_DELETED
32851f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
32861f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
32871f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
32881f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
32891f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
32901f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
32911f6eb021SLiane Praza  *     Property doesn't exist or exists and has no value.
32921f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
32931f6eb021SLiane Praza  *     locale is too long to make a property name
32941f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
32951f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
32961f6eb021SLiane Praza  *     common_name property is not SCF_TYPE_ASTRING has more than one value.
32971f6eb021SLiane Praza  */
32981f6eb021SLiane Praza ssize_t
32991f6eb021SLiane Praza scf_tmpl_prop_common_name(const scf_prop_tmpl_t *t, const char *locale,
33001f6eb021SLiane Praza     char **out)
33011f6eb021SLiane Praza {
33021f6eb021SLiane Praza 	assert(out != NULL);
33031f6eb021SLiane Praza 	if ((*out = _read_localized_astring_from_pg(t->prt_pg,
33041f6eb021SLiane Praza 	    SCF_PROPERTY_TM_COMMON_NAME_PREFIX, locale)) == NULL)
33051f6eb021SLiane Praza 		return (-1);
33061f6eb021SLiane Praza 
33071f6eb021SLiane Praza 	return (strlen(*out));
33081f6eb021SLiane Praza }
33091f6eb021SLiane Praza 
33101f6eb021SLiane Praza /*
33111f6eb021SLiane Praza  * Returns -1 on failure.  Sets scf_error():
33121f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
33131f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
33141f6eb021SLiane Praza  *   SCF_ERROR_DELETED
33151f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
33161f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
33171f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
33181f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
33191f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
33201f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
33211f6eb021SLiane Praza  *     Property doesn't exist or exists and has no value.
33221f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
33231f6eb021SLiane Praza  *     locale is too long to make a property name
33241f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
33251f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
33261f6eb021SLiane Praza  *     description property is not SCF_TYPE_ASTRING has more than one value.
33271f6eb021SLiane Praza  */
33281f6eb021SLiane Praza ssize_t
33291f6eb021SLiane Praza scf_tmpl_prop_description(const scf_prop_tmpl_t *t, const char *locale,
33301f6eb021SLiane Praza     char **out)
33311f6eb021SLiane Praza {
33321f6eb021SLiane Praza 	assert(out != NULL);
33331f6eb021SLiane Praza 	if ((*out = _read_localized_astring_from_pg(t->prt_pg,
33341f6eb021SLiane Praza 	    SCF_PROPERTY_TM_DESCRIPTION_PREFIX, locale)) == NULL)
33351f6eb021SLiane Praza 		return (-1);
33361f6eb021SLiane Praza 
33371f6eb021SLiane Praza 	return (strlen(*out));
33381f6eb021SLiane Praza }
33391f6eb021SLiane Praza 
33401f6eb021SLiane Praza /*
33411f6eb021SLiane Praza  * Returns -1 on failure.  Sets scf_error():
33421f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
33431f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
33441f6eb021SLiane Praza  *   SCF_ERROR_DELETED
33451f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
33461f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
33471f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
33481f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
33491f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
33501f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
33511f6eb021SLiane Praza  *     Property doesn't exist or exists and has no value.
33521f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
33531f6eb021SLiane Praza  *     locale is too long to make a property name
33541f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
33551f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
33561f6eb021SLiane Praza  *     units property is not SCF_TYPE_ASTRING has more than one value.
33571f6eb021SLiane Praza  */
33581f6eb021SLiane Praza ssize_t
33591f6eb021SLiane Praza scf_tmpl_prop_units(const scf_prop_tmpl_t *t, const char *locale, char **out)
33601f6eb021SLiane Praza {
33611f6eb021SLiane Praza 	assert(out != NULL);
33621f6eb021SLiane Praza 	if ((*out = _read_localized_astring_from_pg(t->prt_pg,
33631f6eb021SLiane Praza 	    SCF_PROPERTY_TM_UNITS_PREFIX, locale)) == NULL)
33641f6eb021SLiane Praza 		return (-1);
33651f6eb021SLiane Praza 
33661f6eb021SLiane Praza 	return (strlen(*out));
33671f6eb021SLiane Praza }
33681f6eb021SLiane Praza 
33691f6eb021SLiane Praza /*
33701f6eb021SLiane Praza  * Returns -1 on failure.  Sets scf_error():
33711f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
33721f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
33731f6eb021SLiane Praza  *   SCF_ERROR_DELETED
33741f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
33751f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
33761f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
33771f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
33781f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
33791f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
33801f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
33811f6eb021SLiane Praza  *     visibility property is not SCF_TYPE_ASTRING has more than one value.
33821f6eb021SLiane Praza  */
33831f6eb021SLiane Praza int
33841f6eb021SLiane Praza scf_tmpl_prop_visibility(const scf_prop_tmpl_t *t, uint8_t *out)
33851f6eb021SLiane Praza {
33861f6eb021SLiane Praza 	char *visibility;
33871f6eb021SLiane Praza 
33881f6eb021SLiane Praza 	visibility = _scf_read_single_astring_from_pg(t->prt_pg,
33891f6eb021SLiane Praza 	    SCF_PROPERTY_TM_VISIBILITY);
33901f6eb021SLiane Praza 	if (visibility == NULL) {
33911f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
33921f6eb021SLiane Praza 			return (-1);
33931f6eb021SLiane Praza 		} else switch (scf_error()) {
33941f6eb021SLiane Praza 		/* prop doesn't exist we take the default value */
33951f6eb021SLiane Praza 		case SCF_ERROR_NOT_FOUND:
33961f6eb021SLiane Praza 			*out = SCF_TMPL_VISIBILITY_READWRITE;
33971f6eb021SLiane Praza 			return (0);
33981f6eb021SLiane Praza 
33991f6eb021SLiane Praza 		case SCF_ERROR_CONSTRAINT_VIOLATED:
34001f6eb021SLiane Praza 		case SCF_ERROR_TYPE_MISMATCH:
34011f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
34021f6eb021SLiane Praza 			return (-1);
34031f6eb021SLiane Praza 
34041f6eb021SLiane Praza 		case SCF_ERROR_INVALID_ARGUMENT:
34051f6eb021SLiane Praza 		case SCF_ERROR_NOT_SET:
34061f6eb021SLiane Praza 		default:
34071f6eb021SLiane Praza 			assert(0);
34081f6eb021SLiane Praza 			abort();
34091f6eb021SLiane Praza 		}
34101f6eb021SLiane Praza 	} else if (strcmp(visibility, SCF_TM_VISIBILITY_READWRITE) == 0) {
34111f6eb021SLiane Praza 		*out = SCF_TMPL_VISIBILITY_READWRITE;
34121f6eb021SLiane Praza 	} else if (strcmp(visibility, SCF_TM_VISIBILITY_HIDDEN) == 0) {
34131f6eb021SLiane Praza 		*out = SCF_TMPL_VISIBILITY_HIDDEN;
34141f6eb021SLiane Praza 	} else if (strcmp(visibility, SCF_TM_VISIBILITY_READONLY) == 0) {
34151f6eb021SLiane Praza 		*out = SCF_TMPL_VISIBILITY_READONLY;
34161f6eb021SLiane Praza 	} else {
34171f6eb021SLiane Praza 		free(visibility);
34181f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
34191f6eb021SLiane Praza 		return (-1);
34201f6eb021SLiane Praza 	}
34211f6eb021SLiane Praza 
34221f6eb021SLiane Praza 	free(visibility);
34231f6eb021SLiane Praza 	return (0);
34241f6eb021SLiane Praza }
34251f6eb021SLiane Praza 
34261f6eb021SLiane Praza /*
34271f6eb021SLiane Praza  * Return an allocated string containing the value that must be freed
34281f6eb021SLiane Praza  * with free().
34291f6eb021SLiane Praza  *
34301f6eb021SLiane Praza  * On error set scf_error() _NO_MEMORY, or _NOT_SET (val has not been set
34311f6eb021SLiane Praza  * to a value).
34321f6eb021SLiane Praza  */
34331f6eb021SLiane Praza static char *
34341f6eb021SLiane Praza _scf_value_get_as_string(scf_value_t *val)
34351f6eb021SLiane Praza {
34361f6eb021SLiane Praza 	ssize_t sz = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH) + 1;
34371f6eb021SLiane Praza 	char *buf = malloc(sz);
34381f6eb021SLiane Praza 
34391f6eb021SLiane Praza 	if (buf == NULL) {
34401f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
34411f6eb021SLiane Praza 	} else if (scf_value_get_as_string(val, buf, sz) == -1) {
34421f6eb021SLiane Praza 		free(buf);
34431f6eb021SLiane Praza 		buf = NULL;
34441f6eb021SLiane Praza 	}
34451f6eb021SLiane Praza 
34461f6eb021SLiane Praza 	return (buf);
34471f6eb021SLiane Praza }
34481f6eb021SLiane Praza 
34491f6eb021SLiane Praza /*
34501f6eb021SLiane Praza  * Returns -1 on failure, sets scf_error() to:
34511f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
34521f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
34531f6eb021SLiane Praza  *   SCF_ERROR_DELETED
34541f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
34551f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
34561f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
34571f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
34581f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
34591f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
34601f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
34611f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
34621f6eb021SLiane Praza  */
34631f6eb021SLiane Praza int
34641f6eb021SLiane Praza scf_tmpl_prop_cardinality(const scf_prop_tmpl_t *t, uint64_t *min,
34651f6eb021SLiane Praza     uint64_t *max)
34661f6eb021SLiane Praza {
34671f6eb021SLiane Praza 	scf_value_t *val_min = NULL;
34681f6eb021SLiane Praza 	scf_value_t *val_max = NULL;
34691f6eb021SLiane Praza 	int ret = 0;
34701f6eb021SLiane Praza 
34711f6eb021SLiane Praza 	if (_read_single_value_from_pg(t->prt_pg,
34721f6eb021SLiane Praza 	    SCF_PROPERTY_TM_CARDINALITY_MIN, &val_min) == 0) {
34731f6eb021SLiane Praza 		if (scf_value_get_count(val_min, min) < 0)
34741f6eb021SLiane Praza 			goto error;
34751f6eb021SLiane Praza 	} else {
34761f6eb021SLiane Praza 		if (scf_error() == SCF_ERROR_NOT_FOUND)
34771f6eb021SLiane Praza 			*min = 0;
34781f6eb021SLiane Praza 		else
34791f6eb021SLiane Praza 			goto error;
34801f6eb021SLiane Praza 	}
34811f6eb021SLiane Praza 
34821f6eb021SLiane Praza 	if (_read_single_value_from_pg(t->prt_pg,
34831f6eb021SLiane Praza 	    SCF_PROPERTY_TM_CARDINALITY_MAX, &val_max) == 0) {
34841f6eb021SLiane Praza 		if (scf_value_get_count(val_max, max) < 0)
34851f6eb021SLiane Praza 			goto error;
34861f6eb021SLiane Praza 	} else {
34871f6eb021SLiane Praza 		if (scf_error() == SCF_ERROR_NOT_FOUND)
34881f6eb021SLiane Praza 			*max = UINT64_MAX;
34891f6eb021SLiane Praza 		else
34901f6eb021SLiane Praza 			goto error;
34911f6eb021SLiane Praza 	}
34921f6eb021SLiane Praza 	goto cleanup;
34931f6eb021SLiane Praza 
34941f6eb021SLiane Praza error:
34951f6eb021SLiane Praza 	if (ismember(scf_error(), errors_server)) {
34961f6eb021SLiane Praza 		ret = -1;
34971f6eb021SLiane Praza 	} else switch (scf_error()) {
34981f6eb021SLiane Praza 	case SCF_ERROR_TYPE_MISMATCH:
34991f6eb021SLiane Praza 	case SCF_ERROR_CONSTRAINT_VIOLATED:
35001f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
35011f6eb021SLiane Praza 		/*FALLTHROUGH*/
35021f6eb021SLiane Praza 
35031f6eb021SLiane Praza 	case SCF_ERROR_NOT_FOUND:
35041f6eb021SLiane Praza 	case SCF_ERROR_TEMPLATE_INVALID:
35051f6eb021SLiane Praza 		ret = -1;
35061f6eb021SLiane Praza 		break;
35071f6eb021SLiane Praza 
35081f6eb021SLiane Praza 	case SCF_ERROR_NOT_SET:
35091f6eb021SLiane Praza 	case SCF_ERROR_INVALID_ARGUMENT:
35101f6eb021SLiane Praza 	default:
35111f6eb021SLiane Praza 		assert(0);
35121f6eb021SLiane Praza 		abort();
35131f6eb021SLiane Praza 	}
35141f6eb021SLiane Praza 
35151f6eb021SLiane Praza cleanup:
35161f6eb021SLiane Praza 	scf_value_destroy(val_min);
35171f6eb021SLiane Praza 	scf_value_destroy(val_max);
35181f6eb021SLiane Praza 
35191f6eb021SLiane Praza 	return (ret);
35201f6eb021SLiane Praza }
35211f6eb021SLiane Praza 
35221f6eb021SLiane Praza /*
35231f6eb021SLiane Praza  * Returns -1 on failure.  Sets scf_error():
35241f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
35251f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
35261f6eb021SLiane Praza  *   SCF_ERROR_DELETED
35271f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
35281f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
35291f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
35301f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
35311f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
35321f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
35331f6eb021SLiane Praza  *     Property doesn't exist or exists and has no value.
35341f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
35351f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
35361f6eb021SLiane Praza  */
35371f6eb021SLiane Praza int
35381f6eb021SLiane Praza scf_tmpl_prop_internal_seps(const scf_prop_tmpl_t *t, scf_values_t *vals)
35391f6eb021SLiane Praza {
35401f6eb021SLiane Praza 	if (_read_astrings_values(t->prt_pg,
35411f6eb021SLiane Praza 	    SCF_PROPERTY_INTERNAL_SEPARATORS, vals) == NULL) {
35421f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
35431f6eb021SLiane Praza 			return (-1);
35441f6eb021SLiane Praza 		} else switch (scf_error()) {
35451f6eb021SLiane Praza 		case SCF_ERROR_CONSTRAINT_VIOLATED:
35461f6eb021SLiane Praza 		case SCF_ERROR_TYPE_MISMATCH:
35471f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
35481f6eb021SLiane Praza 			/*FALLTHROUGH*/
35491f6eb021SLiane Praza 
35501f6eb021SLiane Praza 		case SCF_ERROR_NOT_FOUND:
35511f6eb021SLiane Praza 			return (-1);
35521f6eb021SLiane Praza 
35531f6eb021SLiane Praza 		case SCF_ERROR_INVALID_ARGUMENT:
35541f6eb021SLiane Praza 		case SCF_ERROR_NOT_SET:
35551f6eb021SLiane Praza 		default:
35561f6eb021SLiane Praza 			assert(0);
35571f6eb021SLiane Praza 			abort();
35581f6eb021SLiane Praza 		}
35591f6eb021SLiane Praza 	} else if (vals->value_count == 0) {
35601f6eb021SLiane Praza 		/* property has no value */
35611f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NOT_FOUND);
35621f6eb021SLiane Praza 		scf_values_destroy(vals);
35631f6eb021SLiane Praza 		return (-1);
35641f6eb021SLiane Praza 	}
35651f6eb021SLiane Praza 
35661f6eb021SLiane Praza 	return (0);
35671f6eb021SLiane Praza }
35681f6eb021SLiane Praza 
35691f6eb021SLiane Praza /*
35701f6eb021SLiane Praza  * Returns -1 on failure.  Sets scf_error():
35711f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
35721f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
35731f6eb021SLiane Praza  *   SCF_ERROR_DELETED
35741f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
35751f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
35761f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
35771f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
35781f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
35791f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
35801f6eb021SLiane Praza  *     Property doesn't exist or exists and has no value.
35811f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
35821f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
35831f6eb021SLiane Praza  */
35841f6eb021SLiane Praza int
35851f6eb021SLiane Praza scf_tmpl_value_name_constraints(const scf_prop_tmpl_t *t,
35861f6eb021SLiane Praza     scf_values_t *vals)
35871f6eb021SLiane Praza {
35881f6eb021SLiane Praza 	char **ret;
35891f6eb021SLiane Praza 
35901f6eb021SLiane Praza 	ret = _read_astrings_values(t->prt_pg,
35911f6eb021SLiane Praza 	    SCF_PROPERTY_TM_CONSTRAINT_NAME, vals);
35921f6eb021SLiane Praza 
35931f6eb021SLiane Praza 	if (ret == NULL) {
35941f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
35951f6eb021SLiane Praza 			return (-1);
35961f6eb021SLiane Praza 		} else switch (scf_error()) {
35971f6eb021SLiane Praza 		case SCF_ERROR_CONSTRAINT_VIOLATED:
35981f6eb021SLiane Praza 		case SCF_ERROR_TYPE_MISMATCH:
35991f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
36001f6eb021SLiane Praza 			/*FALLTHROUGH*/
36011f6eb021SLiane Praza 
36021f6eb021SLiane Praza 		case SCF_ERROR_NOT_FOUND:
36031f6eb021SLiane Praza 			return (-1);
36041f6eb021SLiane Praza 
36051f6eb021SLiane Praza 		case SCF_ERROR_INVALID_ARGUMENT:
36061f6eb021SLiane Praza 		case SCF_ERROR_NOT_SET:
36071f6eb021SLiane Praza 		default:
36081f6eb021SLiane Praza 			assert(0);
36091f6eb021SLiane Praza 			abort();
36101f6eb021SLiane Praza 		}
36111f6eb021SLiane Praza 	} else if (vals->value_count == 0) {
36121f6eb021SLiane Praza 		/* property has no value */
36131f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NOT_FOUND);
36141f6eb021SLiane Praza 		scf_values_destroy(vals);
36151f6eb021SLiane Praza 		return (-1);
36161f6eb021SLiane Praza 	}
36171f6eb021SLiane Praza 
36181f6eb021SLiane Praza 	return (0);
36191f6eb021SLiane Praza }
36201f6eb021SLiane Praza 
36211f6eb021SLiane Praza /*
36221f6eb021SLiane Praza  * Returns NULL on failure.  Sets scf_error():
36231f6eb021SLiane Praza  * Caller is responsible for freeing returned pointer after use.
36241f6eb021SLiane Praza  *   SCF_ERROR_CONSTRAINT_VIOLATED
36251f6eb021SLiane Praza  *    More tokens than the array size supplied.
36261f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
36271f6eb021SLiane Praza  */
36281f6eb021SLiane Praza static void *
36291f6eb021SLiane Praza _separate_by_separator(char *string, const char *sep, char **array, int size)
36301f6eb021SLiane Praza {
36311f6eb021SLiane Praza 	char *str, *token;
36321f6eb021SLiane Praza 	char *lasts;
36331f6eb021SLiane Praza 	int n = 0;
36341f6eb021SLiane Praza 
36351f6eb021SLiane Praza 	assert(array != NULL);
36361f6eb021SLiane Praza 	assert(string != NULL);
36371f6eb021SLiane Praza 	assert(sep != NULL);
36381f6eb021SLiane Praza 	assert(size > 0);
36391f6eb021SLiane Praza 
36401f6eb021SLiane Praza 	str = strdup(string);
36411f6eb021SLiane Praza 	if (str == NULL) {
36421f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
36431f6eb021SLiane Praza 		return (NULL);
36441f6eb021SLiane Praza 	}
36451f6eb021SLiane Praza 
36461f6eb021SLiane Praza 	if ((array[n] = strtok_r(str, sep, &lasts)) == NULL) {
36471f6eb021SLiane Praza 		assert(0);
36481f6eb021SLiane Praza 		abort();
36491f6eb021SLiane Praza 	}
36501f6eb021SLiane Praza 
36511f6eb021SLiane Praza 	n++;
36521f6eb021SLiane Praza 	while ((token = strtok_r(NULL, sep, &lasts)) != NULL) {
36531f6eb021SLiane Praza 		if (n >= size) {
36541f6eb021SLiane Praza 			goto error;
36551f6eb021SLiane Praza 		}
36561f6eb021SLiane Praza 		array[n] = token;
36571f6eb021SLiane Praza 		n++;
36581f6eb021SLiane Praza 	}
36591f6eb021SLiane Praza 	if (n < size) {
36601f6eb021SLiane Praza 		goto error;
36611f6eb021SLiane Praza 	}
36621f6eb021SLiane Praza 
36631f6eb021SLiane Praza 	return (str);
36641f6eb021SLiane Praza error:
36651f6eb021SLiane Praza 	free(str);
36661f6eb021SLiane Praza 	(void) scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED);
36671f6eb021SLiane Praza 	return (NULL);
36681f6eb021SLiane Praza }
36691f6eb021SLiane Praza 
36701f6eb021SLiane Praza /*
36711f6eb021SLiane Praza  * check if name is among values of CHOICES_INCLUDE_VALUES
36721f6eb021SLiane Praza  * return 0 if name is present, 1 name is not present, -1 on failure
36731f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
36741f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
36751f6eb021SLiane Praza  *   SCF_ERROR_DELETED
36761f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
36771f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
36781f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
36791f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
36801f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
36811f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
36821f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
36831f6eb021SLiane Praza  */
36841f6eb021SLiane Praza static int
36851f6eb021SLiane Praza _check_choices_include_values(scf_propertygroup_t *pg, const char *name)
36861f6eb021SLiane Praza {
36871f6eb021SLiane Praza 	int n = 0, r = 1;
36881f6eb021SLiane Praza 	char **ret;
36891f6eb021SLiane Praza 	scf_values_t vals;
36901f6eb021SLiane Praza 
36911f6eb021SLiane Praza 	if ((ret = _read_astrings_values(pg,
36921f6eb021SLiane Praza 	    SCF_PROPERTY_TM_CHOICES_INCLUDE_VALUES, &vals)) == NULL) {
36931f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
36941f6eb021SLiane Praza 			return (-1);
36951f6eb021SLiane Praza 		} else switch (scf_error()) {
36961f6eb021SLiane Praza 		case SCF_ERROR_NOT_FOUND:
36971f6eb021SLiane Praza 			return (1);
36981f6eb021SLiane Praza 
36991f6eb021SLiane Praza 		case SCF_ERROR_TYPE_MISMATCH:
37001f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
37011f6eb021SLiane Praza 			return (-1);
37021f6eb021SLiane Praza 
37031f6eb021SLiane Praza 		case SCF_ERROR_INVALID_ARGUMENT:
37041f6eb021SLiane Praza 		case SCF_ERROR_NOT_SET:
37051f6eb021SLiane Praza 		default:
37061f6eb021SLiane Praza 			assert(0);
37071f6eb021SLiane Praza 			abort();
37081f6eb021SLiane Praza 		}
37091f6eb021SLiane Praza 	}
37101f6eb021SLiane Praza 
37111f6eb021SLiane Praza 	for (n = 0; n < vals.value_count; ++n) {
37121f6eb021SLiane Praza 		if (strcmp(name, ret[n]) == 0) {
37131f6eb021SLiane Praza 			r = 0;
37141f6eb021SLiane Praza 			break;
37151f6eb021SLiane Praza 		}
37161f6eb021SLiane Praza 	}
37171f6eb021SLiane Praza 	scf_values_destroy(&vals);
37181f6eb021SLiane Praza 	return (r);
37191f6eb021SLiane Praza }
37201f6eb021SLiane Praza 
37211f6eb021SLiane Praza void
37221f6eb021SLiane Praza scf_count_ranges_destroy(scf_count_ranges_t *ranges)
37231f6eb021SLiane Praza {
37241f6eb021SLiane Praza 	if (ranges == NULL)
37251f6eb021SLiane Praza 		return;
37261f6eb021SLiane Praza 
37271f6eb021SLiane Praza 	ranges->scr_num_ranges = 0;
37281f6eb021SLiane Praza 	free(ranges->scr_min);
37291f6eb021SLiane Praza 	free(ranges->scr_max);
37301f6eb021SLiane Praza 	ranges->scr_min = NULL;
37311f6eb021SLiane Praza 	ranges->scr_max = NULL;
37321f6eb021SLiane Praza }
37331f6eb021SLiane Praza 
37341f6eb021SLiane Praza void
37351f6eb021SLiane Praza scf_int_ranges_destroy(scf_int_ranges_t *ranges)
37361f6eb021SLiane Praza {
37371f6eb021SLiane Praza 	if (ranges == NULL)
37381f6eb021SLiane Praza 		return;
37391f6eb021SLiane Praza 
37401f6eb021SLiane Praza 	ranges->sir_num_ranges = 0;
37411f6eb021SLiane Praza 	free(ranges->sir_min);
37421f6eb021SLiane Praza 	free(ranges->sir_max);
37431f6eb021SLiane Praza 	ranges->sir_min = NULL;
37441f6eb021SLiane Praza 	ranges->sir_max = NULL;
37451f6eb021SLiane Praza }
37461f6eb021SLiane Praza 
37471f6eb021SLiane Praza /*
37481f6eb021SLiane Praza  * Returns -1 on failure.  Sets scf_error():
37491f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
37501f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
37511f6eb021SLiane Praza  *   SCF_ERROR_CONSTRAINT_VIOLATED
37521f6eb021SLiane Praza  *   SCF_ERROR_DELETED
37531f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
37541f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
37551f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
37561f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
37571f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
37581f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
37591f6eb021SLiane Praza  *     Property doesn't exist or exists and has no value.
37601f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
37611f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
37621f6eb021SLiane Praza  */
37631f6eb021SLiane Praza static int
37641f6eb021SLiane Praza _scf_tmpl_get_count_ranges(const scf_prop_tmpl_t *t, const char *prop,
37651f6eb021SLiane Praza     scf_count_ranges_t *ranges)
37661f6eb021SLiane Praza {
37671f6eb021SLiane Praza 	scf_values_t vals;
37681f6eb021SLiane Praza 	int i = 0;
37691f6eb021SLiane Praza 	char **ret;
37701f6eb021SLiane Praza 	char *one_range[2];
37711f6eb021SLiane Praza 	char *endptr;
37721f6eb021SLiane Praza 	char *str = NULL;
37731f6eb021SLiane Praza 	uint64_t *min = NULL;
37741f6eb021SLiane Praza 	uint64_t *max = NULL;
37751f6eb021SLiane Praza 
37761f6eb021SLiane Praza 	assert(ranges != NULL);
37771f6eb021SLiane Praza 	if ((ret = _read_astrings_values(t->prt_pg, prop, &vals)) == NULL)
37781f6eb021SLiane Praza 		goto error;
37791f6eb021SLiane Praza 	if (vals.value_count == 0) {
37801f6eb021SLiane Praza 		/* range values are empty */
37811f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NOT_FOUND);
37821f6eb021SLiane Praza 		goto cleanup;
37831f6eb021SLiane Praza 	}
37841f6eb021SLiane Praza 
37851f6eb021SLiane Praza 	min = malloc(vals.value_count * sizeof (uint64_t));
37861f6eb021SLiane Praza 	max = malloc(vals.value_count * sizeof (uint64_t));
37871f6eb021SLiane Praza 	if (min == NULL || max == NULL) {
37881f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
37891f6eb021SLiane Praza 		goto cleanup;
37901f6eb021SLiane Praza 	}
37911f6eb021SLiane Praza 	for (i = 0; i < vals.value_count; ++i) {
37921f6eb021SLiane Praza 		/* min and max should be separated by a "," */
37931f6eb021SLiane Praza 		if ((str = _separate_by_separator(ret[i], ",", one_range,
37941f6eb021SLiane Praza 		    2)) == NULL)
37951f6eb021SLiane Praza 			goto cleanup;
37961f6eb021SLiane Praza 		errno = 0;
37971f6eb021SLiane Praza 		min[i] = strtoull(one_range[0], &endptr, 10);
37981f6eb021SLiane Praza 		if (errno != 0 || endptr == one_range[0] || *endptr) {
37991f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED);
38001f6eb021SLiane Praza 			goto cleanup;
38011f6eb021SLiane Praza 		}
38021f6eb021SLiane Praza 		errno = 0;
38031f6eb021SLiane Praza 		max[i] = strtoull(one_range[1], &endptr, 10);
38041f6eb021SLiane Praza 		if (errno != 0 || endptr == one_range[1] || *endptr) {
38051f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED);
38061f6eb021SLiane Praza 			goto cleanup;
38071f6eb021SLiane Praza 		}
38081f6eb021SLiane Praza 		if (min[i] > max[i]) {
38091f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED);
38101f6eb021SLiane Praza 			goto cleanup;
38111f6eb021SLiane Praza 		}
38121f6eb021SLiane Praza 		free(str);
38131f6eb021SLiane Praza 		str = NULL;
38141f6eb021SLiane Praza 	}
38151f6eb021SLiane Praza 	ranges->scr_num_ranges = vals.value_count;
38161f6eb021SLiane Praza 	ranges->scr_min = min;
38171f6eb021SLiane Praza 	ranges->scr_max = max;
38181f6eb021SLiane Praza 	scf_values_destroy(&vals);
38191f6eb021SLiane Praza 	return (0);
38201f6eb021SLiane Praza cleanup:
38211f6eb021SLiane Praza 	free(str);
38221f6eb021SLiane Praza 	free(min);
38231f6eb021SLiane Praza 	free(max);
38241f6eb021SLiane Praza 	scf_values_destroy(&vals);
38251f6eb021SLiane Praza error:
38261f6eb021SLiane Praza 	if (ismember(scf_error(), errors_server)) {
38271f6eb021SLiane Praza 		return (-1);
38281f6eb021SLiane Praza 	} else switch (scf_error()) {
38291f6eb021SLiane Praza 	case SCF_ERROR_TYPE_MISMATCH:
38301f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
38311f6eb021SLiane Praza 		/*FALLTHROUGH*/
38321f6eb021SLiane Praza 
38331f6eb021SLiane Praza 	case SCF_ERROR_CONSTRAINT_VIOLATED:
38341f6eb021SLiane Praza 	case SCF_ERROR_NOT_FOUND:
38351f6eb021SLiane Praza 		return (-1);
38361f6eb021SLiane Praza 
38371f6eb021SLiane Praza 	case SCF_ERROR_INVALID_ARGUMENT:
38381f6eb021SLiane Praza 	case SCF_ERROR_NOT_SET:
38391f6eb021SLiane Praza 	default:
38401f6eb021SLiane Praza 		assert(0);
38411f6eb021SLiane Praza 		abort();
38421f6eb021SLiane Praza 	}
38431f6eb021SLiane Praza 	/*NOTREACHED*/
38441f6eb021SLiane Praza }
38451f6eb021SLiane Praza 
38461f6eb021SLiane Praza /*
38471f6eb021SLiane Praza  * Returns -1 on failure.  Sets scf_error():
38481f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
38491f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
38501f6eb021SLiane Praza  *   SCF_ERROR_CONSTRAINT_VIOLATED
38511f6eb021SLiane Praza  *   SCF_ERROR_DELETED
38521f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
38531f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
38541f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
38551f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
38561f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
38571f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
38581f6eb021SLiane Praza  *     Property doesn't exist or exists and has no value.
38591f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
38601f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
38611f6eb021SLiane Praza  */
38621f6eb021SLiane Praza static int
38631f6eb021SLiane Praza _scf_tmpl_get_int_ranges(const scf_prop_tmpl_t *t, const char *prop,
38641f6eb021SLiane Praza     scf_int_ranges_t *ranges)
38651f6eb021SLiane Praza {
38661f6eb021SLiane Praza 	scf_values_t vals;
38671f6eb021SLiane Praza 	int n = 0;
38681f6eb021SLiane Praza 	char **ret;
38691f6eb021SLiane Praza 	char *one_range[2];
38701f6eb021SLiane Praza 	char *endptr;
38711f6eb021SLiane Praza 	char *str = NULL;
38721f6eb021SLiane Praza 	int64_t *min = NULL;
38731f6eb021SLiane Praza 	int64_t *max = NULL;
38741f6eb021SLiane Praza 
38751f6eb021SLiane Praza 	assert(ranges != NULL);
38761f6eb021SLiane Praza 	if ((ret = _read_astrings_values(t->prt_pg, prop, &vals)) == NULL)
38771f6eb021SLiane Praza 		goto error;
38781f6eb021SLiane Praza 	if (vals.value_count == 0) {
38791f6eb021SLiane Praza 		/* range values are empty */
38801f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NOT_FOUND);
38811f6eb021SLiane Praza 		goto cleanup;
38821f6eb021SLiane Praza 	}
38831f6eb021SLiane Praza 
38841f6eb021SLiane Praza 	min = malloc(vals.value_count * sizeof (int64_t));
38851f6eb021SLiane Praza 	max = malloc(vals.value_count * sizeof (int64_t));
38861f6eb021SLiane Praza 	if (min == NULL || max == NULL) {
38871f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
38881f6eb021SLiane Praza 		goto cleanup;
38891f6eb021SLiane Praza 	}
38901f6eb021SLiane Praza 	while (n < vals.value_count) {
38911f6eb021SLiane Praza 		/* min and max should be separated by a "," */
38921f6eb021SLiane Praza 		if ((str = _separate_by_separator(ret[n], ",", one_range, 2))
38931f6eb021SLiane Praza 		    == NULL)
38941f6eb021SLiane Praza 			goto cleanup;
38951f6eb021SLiane Praza 		errno = 0;
38961f6eb021SLiane Praza 		min[n] = strtoll(one_range[0], &endptr, 10);
38971f6eb021SLiane Praza 		if (errno != 0 || endptr == one_range[0] || *endptr) {
38981f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED);
38991f6eb021SLiane Praza 			goto cleanup;
39001f6eb021SLiane Praza 		}
39011f6eb021SLiane Praza 		errno = 0;
39021f6eb021SLiane Praza 		max[n] = strtoll(one_range[1], &endptr, 10);
39031f6eb021SLiane Praza 		if (errno != 0 || endptr == one_range[1] || *endptr) {
39041f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED);
39051f6eb021SLiane Praza 			goto cleanup;
39061f6eb021SLiane Praza 		}
39071f6eb021SLiane Praza 		if (min[n] > max[n]) {
39081f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
39091f6eb021SLiane Praza 			goto cleanup;
39101f6eb021SLiane Praza 		}
39111f6eb021SLiane Praza 		++n;
39121f6eb021SLiane Praza 		free(str);
39131f6eb021SLiane Praza 		str = NULL;
39141f6eb021SLiane Praza 	}
39151f6eb021SLiane Praza 	ranges->sir_num_ranges = vals.value_count;
39161f6eb021SLiane Praza 	ranges->sir_min = min;
39171f6eb021SLiane Praza 	ranges->sir_max = max;
39181f6eb021SLiane Praza 	scf_values_destroy(&vals);
39191f6eb021SLiane Praza 	return (0);
39201f6eb021SLiane Praza cleanup:
39211f6eb021SLiane Praza 	free(str);
39221f6eb021SLiane Praza 	free(min);
39231f6eb021SLiane Praza 	free(max);
39241f6eb021SLiane Praza 	scf_values_destroy(&vals);
39251f6eb021SLiane Praza error:
39261f6eb021SLiane Praza 	if (ismember(scf_error(), errors_server)) {
39271f6eb021SLiane Praza 		return (-1);
39281f6eb021SLiane Praza 	} else switch (scf_error()) {
39291f6eb021SLiane Praza 	case SCF_ERROR_TYPE_MISMATCH:
39301f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
39311f6eb021SLiane Praza 		/*FALLTHROUGH*/
39321f6eb021SLiane Praza 
39331f6eb021SLiane Praza 	case SCF_ERROR_CONSTRAINT_VIOLATED:
39341f6eb021SLiane Praza 	case SCF_ERROR_NOT_FOUND:
39351f6eb021SLiane Praza 	case SCF_ERROR_TEMPLATE_INVALID:
39361f6eb021SLiane Praza 		return (-1);
39371f6eb021SLiane Praza 
39381f6eb021SLiane Praza 	case SCF_ERROR_INVALID_ARGUMENT:
39391f6eb021SLiane Praza 	case SCF_ERROR_NOT_SET:
39401f6eb021SLiane Praza 	default:
39411f6eb021SLiane Praza 		assert(0);
39421f6eb021SLiane Praza 		abort();
39431f6eb021SLiane Praza 	}
39441f6eb021SLiane Praza 	/*NOTREACHED*/
39451f6eb021SLiane Praza }
39461f6eb021SLiane Praza 
39471f6eb021SLiane Praza /*
39481f6eb021SLiane Praza  * Returns -1 on failure.  Sets scf_error():
39491f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
39501f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
39511f6eb021SLiane Praza  *   SCF_ERROR_CONSTRAINT_VIOLATED
39521f6eb021SLiane Praza  *   SCF_ERROR_DELETED
39531f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
39541f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
39551f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
39561f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
39571f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
39581f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
39591f6eb021SLiane Praza  *     Property doesn't exist or exists and has no value.
39601f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
39611f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
39621f6eb021SLiane Praza  */
39631f6eb021SLiane Praza int
39641f6eb021SLiane Praza scf_tmpl_value_count_range_constraints(const scf_prop_tmpl_t *t,
39651f6eb021SLiane Praza     scf_count_ranges_t *ranges)
39661f6eb021SLiane Praza {
39671f6eb021SLiane Praza 	return (_scf_tmpl_get_count_ranges(t, SCF_PROPERTY_TM_CONSTRAINT_RANGE,
39681f6eb021SLiane Praza 	    ranges));
39691f6eb021SLiane Praza }
39701f6eb021SLiane Praza 
39711f6eb021SLiane Praza int
39721f6eb021SLiane Praza scf_tmpl_value_int_range_constraints(const scf_prop_tmpl_t *t,
39731f6eb021SLiane Praza     scf_int_ranges_t *ranges)
39741f6eb021SLiane Praza {
39751f6eb021SLiane Praza 	return (_scf_tmpl_get_int_ranges(t, SCF_PROPERTY_TM_CONSTRAINT_RANGE,
39761f6eb021SLiane Praza 	    ranges));
39771f6eb021SLiane Praza }
39781f6eb021SLiane Praza 
39791f6eb021SLiane Praza int
39801f6eb021SLiane Praza scf_tmpl_value_count_range_choices(const scf_prop_tmpl_t *t,
39811f6eb021SLiane Praza     scf_count_ranges_t *ranges)
39821f6eb021SLiane Praza {
39831f6eb021SLiane Praza 	return (_scf_tmpl_get_count_ranges(t, SCF_PROPERTY_TM_CHOICES_RANGE,
39841f6eb021SLiane Praza 	    ranges));
39851f6eb021SLiane Praza }
39861f6eb021SLiane Praza 
39871f6eb021SLiane Praza int
39881f6eb021SLiane Praza scf_tmpl_value_int_range_choices(const scf_prop_tmpl_t *t,
39891f6eb021SLiane Praza     scf_int_ranges_t *ranges)
39901f6eb021SLiane Praza {
39911f6eb021SLiane Praza 	return (_scf_tmpl_get_int_ranges(t, SCF_PROPERTY_TM_CHOICES_RANGE,
39921f6eb021SLiane Praza 	    ranges));
39931f6eb021SLiane Praza }
39941f6eb021SLiane Praza 
39951f6eb021SLiane Praza /*
39961f6eb021SLiane Praza  * Returns -1 on failure.  Sets scf_error():
39971f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
39981f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
39991f6eb021SLiane Praza  *   SCF_ERROR_DELETED
40001f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
40011f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
40021f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
40031f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
40041f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
40051f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
40061f6eb021SLiane Praza  *     Property doesn't exist or exists and has no value.
40071f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
40081f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
40091f6eb021SLiane Praza  */
40101f6eb021SLiane Praza int
40111f6eb021SLiane Praza scf_tmpl_value_name_choices(const scf_prop_tmpl_t *t, scf_values_t *vals)
40121f6eb021SLiane Praza {
40131f6eb021SLiane Praza 	int c_flag = 0; /* have not read any value yet */
40141f6eb021SLiane Praza 	int r;
40151f6eb021SLiane Praza 	char **ret;
40161f6eb021SLiane Praza 
40171f6eb021SLiane Praza 	/* First, look for explicitly declared choices. */
40181f6eb021SLiane Praza 	if ((ret = _read_astrings_values(t->prt_pg,
40191f6eb021SLiane Praza 	    SCF_PROPERTY_TM_CHOICES_NAME, vals)) != NULL) {
40201f6eb021SLiane Praza 		c_flag = 1;
40211f6eb021SLiane Praza 	} else if (scf_error() != SCF_ERROR_NOT_FOUND) {
40221f6eb021SLiane Praza 		goto error;
40231f6eb021SLiane Praza 	}
40241f6eb021SLiane Praza 
40251f6eb021SLiane Praza 	/* Next, check for choices included by 'values'. */
40261f6eb021SLiane Praza 	if ((r = _check_choices_include_values(t->prt_pg, "values")) == 0) {
40271f6eb021SLiane Praza 		/* read values_name */
40281f6eb021SLiane Praza 		if (c_flag == 1)
40291f6eb021SLiane Praza 			/* append values */
40301f6eb021SLiane Praza 			ret = _append_astrings_values(t->prt_pg,
40311f6eb021SLiane Praza 			    SCF_PROPERTY_TM_VALUES_NAME, vals);
40321f6eb021SLiane Praza 		else
40331f6eb021SLiane Praza 			/* read values */
40341f6eb021SLiane Praza 			ret = _read_astrings_values(t->prt_pg,
40351f6eb021SLiane Praza 			    SCF_PROPERTY_TM_VALUES_NAME, vals);
40361f6eb021SLiane Praza 		if (ret != NULL) {
40371f6eb021SLiane Praza 			c_flag = 1;
40381f6eb021SLiane Praza 		} else if (scf_error() != SCF_ERROR_NOT_FOUND) {
40391f6eb021SLiane Praza 			goto error;
40401f6eb021SLiane Praza 		}
40411f6eb021SLiane Praza 	} else if (r == -1) {
40421f6eb021SLiane Praza 		goto error;
40431f6eb021SLiane Praza 	}
40441f6eb021SLiane Praza 
40451f6eb021SLiane Praza 	/* Finally check for choices included by 'constraints'. */
40461f6eb021SLiane Praza 	if ((r = _check_choices_include_values(t->prt_pg, "constraints")) ==
40471f6eb021SLiane Praza 	    0) {
40481f6eb021SLiane Praza 		/* read constraint_name */
40491f6eb021SLiane Praza 		if (c_flag == 1)
40501f6eb021SLiane Praza 			/* append values */
40511f6eb021SLiane Praza 			ret = _append_astrings_values(t->prt_pg,
40521f6eb021SLiane Praza 			    SCF_PROPERTY_TM_CONSTRAINT_NAME, vals);
40531f6eb021SLiane Praza 		else
40541f6eb021SLiane Praza 			/* read values */
40551f6eb021SLiane Praza 			ret = _read_astrings_values(t->prt_pg,
40561f6eb021SLiane Praza 			    SCF_PROPERTY_TM_CONSTRAINT_NAME, vals);
40571f6eb021SLiane Praza 		if (ret != NULL) {
40581f6eb021SLiane Praza 			c_flag = 1;
40591f6eb021SLiane Praza 		} else if (scf_error() != SCF_ERROR_NOT_FOUND) {
40601f6eb021SLiane Praza 			goto error;
40611f6eb021SLiane Praza 		}
40621f6eb021SLiane Praza 	} else if (r == -1) {
40631f6eb021SLiane Praza 		goto error;
40641f6eb021SLiane Praza 	}
40651f6eb021SLiane Praza 
40661f6eb021SLiane Praza 	if (c_flag == 0 || vals->value_count == 0) {
40671f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NOT_FOUND);
40681f6eb021SLiane Praza 		return (-1);
40691f6eb021SLiane Praza 	}
40701f6eb021SLiane Praza 
40711f6eb021SLiane Praza 	return (0);
40721f6eb021SLiane Praza 
40731f6eb021SLiane Praza error:
40741f6eb021SLiane Praza 	if (ismember(scf_error(), errors_server)) {
40751f6eb021SLiane Praza 		return (-1);
40761f6eb021SLiane Praza 	} else switch (scf_error()) {
40771f6eb021SLiane Praza 	case SCF_ERROR_TYPE_MISMATCH:
40781f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
40791f6eb021SLiane Praza 		return (-1);
40801f6eb021SLiane Praza 
40811f6eb021SLiane Praza 	case SCF_ERROR_NOT_SET:
40821f6eb021SLiane Praza 	case SCF_ERROR_INVALID_ARGUMENT:
40831f6eb021SLiane Praza 	default:
40841f6eb021SLiane Praza 		assert(0);
40851f6eb021SLiane Praza 		abort();
40861f6eb021SLiane Praza 	}
40871f6eb021SLiane Praza 	/*NOTREACHED*/
40881f6eb021SLiane Praza }
40891f6eb021SLiane Praza 
40901f6eb021SLiane Praza void
40911f6eb021SLiane Praza scf_values_destroy(scf_values_t *vals)
40921f6eb021SLiane Praza {
40931f6eb021SLiane Praza 	int i;
40941f6eb021SLiane Praza 	char **items = NULL;
4095*f6e214c7SGavin Maltby 	char **str = NULL;
40961f6eb021SLiane Praza 
40971f6eb021SLiane Praza 	if (vals == NULL)
40981f6eb021SLiane Praza 		return;
40991f6eb021SLiane Praza 
4100*f6e214c7SGavin Maltby 	str = vals->values_as_strings;
4101*f6e214c7SGavin Maltby 
41021f6eb021SLiane Praza 	/* free values */
41031f6eb021SLiane Praza 	switch (vals->value_type) {
41041f6eb021SLiane Praza 	case SCF_TYPE_BOOLEAN:
41051f6eb021SLiane Praza 		free(vals->values.v_boolean);
41061f6eb021SLiane Praza 		break;
41071f6eb021SLiane Praza 	case SCF_TYPE_COUNT:
41081f6eb021SLiane Praza 		free(vals->values.v_count);
41091f6eb021SLiane Praza 		break;
41101f6eb021SLiane Praza 	case SCF_TYPE_INTEGER:
41111f6eb021SLiane Praza 		free(vals->values.v_integer);
41121f6eb021SLiane Praza 		break;
41131f6eb021SLiane Praza 	case SCF_TYPE_ASTRING:
41141f6eb021SLiane Praza 		items = vals->values.v_astring;
41151f6eb021SLiane Praza 		str = NULL;
41161f6eb021SLiane Praza 		break;
41171f6eb021SLiane Praza 	case SCF_TYPE_USTRING:
41181f6eb021SLiane Praza 		items = vals->values.v_ustring;
41191f6eb021SLiane Praza 		str = NULL;
41201f6eb021SLiane Praza 		break;
41211f6eb021SLiane Praza 	case SCF_TYPE_OPAQUE:
41221f6eb021SLiane Praza 		items = vals->values.v_opaque;
41231f6eb021SLiane Praza 		str = NULL;
41241f6eb021SLiane Praza 		break;
41251f6eb021SLiane Praza 	case SCF_TYPE_TIME:
41261f6eb021SLiane Praza 		free(vals->values.v_time);
41271f6eb021SLiane Praza 		break;
41281f6eb021SLiane Praza 	default:
41291f6eb021SLiane Praza 		assert(0);
41301f6eb021SLiane Praza 		abort();
41311f6eb021SLiane Praza 	}
41321f6eb021SLiane Praza 	for (i = 0; i < vals->value_count; ++i) {
41331f6eb021SLiane Praza 		if (items != NULL)
41341f6eb021SLiane Praza 			free(items[i]);
41351f6eb021SLiane Praza 		if (str != NULL)
41361f6eb021SLiane Praza 			free(str[i]);
41371f6eb021SLiane Praza 	}
41381f6eb021SLiane Praza 	vals->value_count = 0;
41391f6eb021SLiane Praza 	free(items);
41401f6eb021SLiane Praza 	free(str);
41411f6eb021SLiane Praza }
41421f6eb021SLiane Praza 
41431f6eb021SLiane Praza /*
41441f6eb021SLiane Praza  * char *_make_value_name()
41451f6eb021SLiane Praza  *
41461f6eb021SLiane Praza  * Construct the prefix for a value common name or value description property.
41471f6eb021SLiane Praza  * It takes the form:
41481f6eb021SLiane Praza  *   value_<BASE32 name>_<common_name|description>_
41491f6eb021SLiane Praza  * This is then combined with a localized suffix by the caller to look
41501f6eb021SLiane Praza  * up the property in the repository:
41511f6eb021SLiane Praza  *   value_<BASE32 name>_<common_name|description>_<lang>
41521f6eb021SLiane Praza  *
41531f6eb021SLiane Praza  * Returns NULL on failure.  Sets scf_error():
41541f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
41551f6eb021SLiane Praza  *     Name isn't short enough make a value name with.
41561f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
41571f6eb021SLiane Praza  */
41581f6eb021SLiane Praza static char *
41591f6eb021SLiane Praza _make_value_name(char *desc_name, const char *value)
41601f6eb021SLiane Praza {
41611f6eb021SLiane Praza 	char *name = NULL;
41621f6eb021SLiane Praza 	char *encoded = NULL;
41631f6eb021SLiane Praza 	ssize_t sz = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
41641f6eb021SLiane Praza 
41651f6eb021SLiane Praza 	name = malloc(sz);
41661f6eb021SLiane Praza 	encoded = malloc(sz);
41671f6eb021SLiane Praza 	if (name == NULL || encoded == NULL) {
41681f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
41691f6eb021SLiane Praza 		free(name);
41701f6eb021SLiane Praza 		free(encoded);
41711f6eb021SLiane Praza 		return (NULL);
41721f6eb021SLiane Praza 	}
41731f6eb021SLiane Praza 
41741f6eb021SLiane Praza 	if (scf_encode32(value, strlen(value), encoded, sz, NULL,
41751f6eb021SLiane Praza 	    SCF_ENCODE32_PAD) != 0) {
41761f6eb021SLiane Praza 		/* Shouldn't happen. */
41771f6eb021SLiane Praza 		assert(0);
41781f6eb021SLiane Praza 	}
41791f6eb021SLiane Praza 
41801f6eb021SLiane Praza 	(void) strlcpy(name, SCF_PROPERTY_TM_VALUE_PREFIX, sz);
41811f6eb021SLiane Praza 
41821f6eb021SLiane Praza 	if (strlcat(name, encoded, sz) >= sz) {
41831f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
41841f6eb021SLiane Praza 		free(name);
41851f6eb021SLiane Praza 		free(encoded);
41861f6eb021SLiane Praza 		return (NULL);
41871f6eb021SLiane Praza 	}
41881f6eb021SLiane Praza 
41891f6eb021SLiane Praza 	if (strlcat(name, "_", sz) >= sz) {
41901f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
41911f6eb021SLiane Praza 		free(name);
41921f6eb021SLiane Praza 		free(encoded);
41931f6eb021SLiane Praza 		return (NULL);
41941f6eb021SLiane Praza 	}
41951f6eb021SLiane Praza 
41961f6eb021SLiane Praza 	if (strlcat(name, desc_name, sz) >= sz) {
41971f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
41981f6eb021SLiane Praza 		free(name);
41991f6eb021SLiane Praza 		free(encoded);
42001f6eb021SLiane Praza 		return (NULL);
42011f6eb021SLiane Praza 	}
42021f6eb021SLiane Praza 
42031f6eb021SLiane Praza 	if (strlcat(name, "_", sz) >= sz) {
42041f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
42051f6eb021SLiane Praza 		free(name);
42061f6eb021SLiane Praza 		free(encoded);
42071f6eb021SLiane Praza 		return (NULL);
42081f6eb021SLiane Praza 	}
42091f6eb021SLiane Praza 
42101f6eb021SLiane Praza 	free(encoded);
42111f6eb021SLiane Praza 	return (name);
42121f6eb021SLiane Praza }
42131f6eb021SLiane Praza 
42141f6eb021SLiane Praza /*
42151f6eb021SLiane Praza  * ssize_t scf_tmpl_value_common_name()
42161f6eb021SLiane Praza  *
42171f6eb021SLiane Praza  * Populates "out" with an allocated string containing the value's
42181f6eb021SLiane Praza  * common name.  Returns the size of the string on successful return.
42191f6eb021SLiane Praza  * out must be freed with free() on successful return.
42201f6eb021SLiane Praza  *
42211f6eb021SLiane Praza  * Returns -1 on failure, sets scf_error() to:
42221f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
42231f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
42241f6eb021SLiane Praza  *   SCF_ERROR_DELETED
42251f6eb021SLiane Praza  *     Property group was deleted.
42261f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
42271f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
42281f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
42291f6eb021SLiane Praza  *     name not a valid property name
42301f6eb021SLiane Praza  *     name and locale are too long to make a property name
42311f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
42321f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
42331f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
42341f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
42351f6eb021SLiane Praza  *     Property doesn't exist or exists and has no value.
42361f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
42371f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
42381f6eb021SLiane Praza  *     property is not SCF_TYPE_ASTRING has more than one value.
42391f6eb021SLiane Praza  */
42401f6eb021SLiane Praza ssize_t
42411f6eb021SLiane Praza scf_tmpl_value_common_name(const scf_prop_tmpl_t *t, const char *locale,
42421f6eb021SLiane Praza     const char *value, char **out)
42431f6eb021SLiane Praza {
42441f6eb021SLiane Praza 	char *value_name = NULL;
42451f6eb021SLiane Praza 
42461f6eb021SLiane Praza 	value_name = _make_value_name("common_name", value);
42471f6eb021SLiane Praza 	if (value_name == NULL)
42481f6eb021SLiane Praza 		return (-1);
42491f6eb021SLiane Praza 
42501f6eb021SLiane Praza 	*out = _read_localized_astring_from_pg(t->prt_pg, value_name, locale);
42511f6eb021SLiane Praza 
42521f6eb021SLiane Praza 	free(value_name);
42531f6eb021SLiane Praza 
42541f6eb021SLiane Praza 	if (*out == NULL)
42551f6eb021SLiane Praza 		return (-1);
42561f6eb021SLiane Praza 
42571f6eb021SLiane Praza 	return (strlen(*out));
42581f6eb021SLiane Praza }
42591f6eb021SLiane Praza 
42601f6eb021SLiane Praza /*
42611f6eb021SLiane Praza  * ssize_t scf_tmpl_value_description()
42621f6eb021SLiane Praza  *
42631f6eb021SLiane Praza  * Populates "out" with an allocated string containing the value's
42641f6eb021SLiane Praza  * description.  Returns the size of the string on successful return.
42651f6eb021SLiane Praza  * out must be freed with free() on successful return.
42661f6eb021SLiane Praza  *
42671f6eb021SLiane Praza  * Returns -1 on failure, sets scf_error() to:
42681f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
42691f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
42701f6eb021SLiane Praza  *   SCF_ERROR_DELETED
42711f6eb021SLiane Praza  *     Property group was deleted.
42721f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
42731f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
42741f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
42751f6eb021SLiane Praza  *     name not a valid property name
42761f6eb021SLiane Praza  *     name and locale are too long to make a property name
42771f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
42781f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
42791f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
42801f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
42811f6eb021SLiane Praza  *     Property doesn't exist or exists and has no value.
42821f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
42831f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
42841f6eb021SLiane Praza  *     property is not SCF_TYPE_ASTRING has more than one value.
42851f6eb021SLiane Praza  */
42861f6eb021SLiane Praza ssize_t
42871f6eb021SLiane Praza scf_tmpl_value_description(const scf_prop_tmpl_t *t, const char *locale,
42881f6eb021SLiane Praza     const char *value, char **out)
42891f6eb021SLiane Praza {
42901f6eb021SLiane Praza 	char *value_name = NULL;
42911f6eb021SLiane Praza 
42921f6eb021SLiane Praza 	value_name = _make_value_name("description", value);
42931f6eb021SLiane Praza 	if (value_name == NULL)
42941f6eb021SLiane Praza 		return (-1);
42951f6eb021SLiane Praza 
42961f6eb021SLiane Praza 
42971f6eb021SLiane Praza 	*out = _read_localized_astring_from_pg(t->prt_pg, value_name, locale);
42981f6eb021SLiane Praza 
42991f6eb021SLiane Praza 	free(value_name);
43001f6eb021SLiane Praza 
43011f6eb021SLiane Praza 	if (*out == NULL)
43021f6eb021SLiane Praza 		return (-1);
43031f6eb021SLiane Praza 
43041f6eb021SLiane Praza 	return (strlen(*out));
43051f6eb021SLiane Praza }
43061f6eb021SLiane Praza 
43071f6eb021SLiane Praza /*
43081f6eb021SLiane Praza  * Templates error messages format, in human readable form.
43091f6eb021SLiane Praza  * Each line is one error item:
43101f6eb021SLiane Praza  *
43111f6eb021SLiane Praza  * prefix error message
43121f6eb021SLiane Praza  * 	FMRI="err->te_errs->tes_fmri"
43131f6eb021SLiane Praza  * 	Property group="err->te_pg_name"
43141f6eb021SLiane Praza  * 	Property name="err->te_prop_name"
43151f6eb021SLiane Praza  * 	expected value 1="err->te_ev1"
43161f6eb021SLiane Praza  * 	expected value 2="err->te_ev2"
43171f6eb021SLiane Praza  * 	actual value="err->te_actual"
43181f6eb021SLiane Praza  * 	Tempalte source="err->te_tmpl_fmri"
43191f6eb021SLiane Praza  * 	pg_pattern name="err->tmpl_pg_name"
43201f6eb021SLiane Praza  * 	pg_pattern type="err->tmpl_pg_type"
43211f6eb021SLiane Praza  * 	prop_pattern name="err->tmpl_prop_name"
43221f6eb021SLiane Praza  * 	prop_pattern type="err->tmpl_prop_type"
43231f6eb021SLiane Praza  *
43241f6eb021SLiane Praza  * To add a new error type, include scf_tmpl_error_type_t in libscf.h
43251f6eb021SLiane Praza  * add one entry in em_desc[], and update the functions pointed by the
43261f6eb021SLiane Praza  * _tmpl_error_access array with the new error code. Also, update the
43271f6eb021SLiane Praza  * scf_tmpl_error_* functions to provide access to desired
43281f6eb021SLiane Praza  * scf_tmpl_error_t fields.
43291f6eb021SLiane Praza  *
43301f6eb021SLiane Praza  * To add a new error item, add a new field to scf_tmpl_error_t, a new field
43311f6eb021SLiane Praza  * in _scf_tmpl_error_desc or a new non-error-dependent string, add a new entry
43321f6eb021SLiane Praza  * in _tmpl_error_access array and create the appropriate get_val, get_desc
43331f6eb021SLiane Praza  * functions.
43341f6eb021SLiane Praza  *
43351f6eb021SLiane Praza  * Changes to both the validation logic and the error types and items must
43361f6eb021SLiane Praza  * be coordinated with the code in svccfg to ensure both libscf and svccfg's
43371f6eb021SLiane Praza  * manifest validation validate the same things.
43381f6eb021SLiane Praza  */
43391f6eb021SLiane Praza 
43401f6eb021SLiane Praza /*
43411f6eb021SLiane Praza  * Container for all template errors on a validated object.
43421f6eb021SLiane Praza  */
43431f6eb021SLiane Praza struct scf_tmpl_errors {
43441f6eb021SLiane Praza 	int			tes_index;
43451f6eb021SLiane Praza 	int			tes_num_errs;
43461f6eb021SLiane Praza 	scf_tmpl_error_t	**tes_errs;
43471f6eb021SLiane Praza 	int			tes_errs_size;
43481f6eb021SLiane Praza 	const char		*tes_fmri;
43491f6eb021SLiane Praza 	const char		*tes_prefix;
43501f6eb021SLiane Praza 	int			tes_flag; /* if set, scf_tmpl_error_destroy */
43511f6eb021SLiane Praza 					    /* will free strings in tes_errs  */
43521f6eb021SLiane Praza };
43531f6eb021SLiane Praza 
43541f6eb021SLiane Praza /*
43551f6eb021SLiane Praza  * Templates error-dependent labels
43561f6eb021SLiane Praza  */
43571f6eb021SLiane Praza struct _scf_tmpl_error_desc {
43581f6eb021SLiane Praza 	const char *em_msg;
43591f6eb021SLiane Praza 	const char *em_ev1;
43601f6eb021SLiane Praza 	const char *em_ev2;
43611f6eb021SLiane Praza 	const char *em_actual;
43621f6eb021SLiane Praza };
43631f6eb021SLiane Praza 
43641f6eb021SLiane Praza /*
43651f6eb021SLiane Praza  * This array MUST be kept in synch with the template error definition of
43661f6eb021SLiane Praza  * scf_tmpl_error_type_t in libscf.h
43671f6eb021SLiane Praza  */
43681f6eb021SLiane Praza static struct _scf_tmpl_error_desc em_desc[] = {
43691f6eb021SLiane Praza 	/* SCF_TERR_MISSING_PG */
43701f6eb021SLiane Praza 	{ "Required property group missing", "Name of missing property group",
43711f6eb021SLiane Praza 	    "Type of missing property group", NULL },
43721f6eb021SLiane Praza 	/* SCF_TERR_WRONG_PG_TYPE */
43731f6eb021SLiane Praza 	{ "Property group has bad type", "Specified type", NULL,
43741f6eb021SLiane Praza 	    "Actual type" },
43751f6eb021SLiane Praza 	/* SCF_TERR_MISSING_PROP */
43761f6eb021SLiane Praza 	{ "Required property missing", "Name of missing property", NULL, NULL },
43771f6eb021SLiane Praza 	/* SCF_TERR_WRONG_PROP_TYPE */
43781f6eb021SLiane Praza 	{ "Property has bad type", "Specified property type", NULL,
43791f6eb021SLiane Praza 	    "Actual property type" },
43801f6eb021SLiane Praza 	/* SCF_TERR_CARDINALITY_VIOLATION */
43811f6eb021SLiane Praza 	{ "Number of property values violates cardinality restriction",
43821f6eb021SLiane Praza 	    "Cardinality minimum", "Cardinality maximum",
43831f6eb021SLiane Praza 	    "Actual number of values" },
43841f6eb021SLiane Praza 	/* SCF_TERR_VALUE_CONSTRAINT_VIOLATED */
43851f6eb021SLiane Praza 	{ "Property has illegal value", NULL, NULL, "Illegal value" },
43861f6eb021SLiane Praza 	/* SCF_TERR_RANGE_VIOLATION */
43871f6eb021SLiane Praza 	{ "Property value is out of range", NULL, NULL, "Actual value" },
43881f6eb021SLiane Praza 	/* SCF_TERR_PG_REDEFINE */
43891f6eb021SLiane Praza 	{ "Instance redefines pg_pattern", "Instance pg_pattern name",
43901f6eb021SLiane Praza 	    "Instance pg_pattern type", NULL },
43911f6eb021SLiane Praza 	/* SCF_TERR_PROP_TYPE_MISMATCH */
43921f6eb021SLiane Praza 	{ "Property type and value type mismatch", NULL, NULL, "Value type" },
43931f6eb021SLiane Praza 	/* SCF_TERR_VALUE_OUT_OF_RANGE */
43941f6eb021SLiane Praza 	{ "Value is out of range", NULL, NULL, "Value" },
43951f6eb021SLiane Praza 	/* SCF_TERR_INVALID_VALUE */
43961f6eb021SLiane Praza 	{ "Value is not valid", NULL, NULL, "Value" },
43971f6eb021SLiane Praza 	/* SCF_TERR_PG_PATTERN_CONFLICT */
43981f6eb021SLiane Praza 	{ "Conflicting pg_pattern specifications", "Template source",
43991f6eb021SLiane Praza 	    "pg_pattern name", "pg_pattern type" },
44001f6eb021SLiane Praza 	/* SCF_TERR_PROP_PATTERN_CONFLICT */
44011f6eb021SLiane Praza 	{ "Conflicting prop_pattern specifications", "Template source",
44021f6eb021SLiane Praza 	    "prop_pattern name", "prop_pattern type" },
44031f6eb021SLiane Praza 	/* SCF_TERR_GENERAL_REDEFINE */
44041f6eb021SLiane Praza 	{ "Service or instance pg_pattern redefines a global or restarter "
44051f6eb021SLiane Praza 	    "pg_pattern", "Template source", "pg_pattern name",
44061f6eb021SLiane Praza 	    "pg_pattern type" },
44071f6eb021SLiane Praza 	/* SCF_TERR_INCLUDE_VALUES */
44081f6eb021SLiane Praza 	{ "Missing constraints or values for include_values element",
44091f6eb021SLiane Praza 	    "include_values type", NULL, NULL },
44101f6eb021SLiane Praza 	/* SCF_TERR_PG_PATTERN_INCOMPLETE */
44111f6eb021SLiane Praza 	{ "Required pg_pattern is missing a name or type attribute",
44121f6eb021SLiane Praza 	    NULL, NULL, NULL },
44131f6eb021SLiane Praza 	/* SCF_TERR_PROP_PATTERN_INCOMPLETE */
44141f6eb021SLiane Praza 	{ "Required prop_pattern is missing a type attribute",
44151f6eb021SLiane Praza 	    NULL, NULL, NULL }
44161f6eb021SLiane Praza };
44171f6eb021SLiane Praza 
44181f6eb021SLiane Praza /*
44191f6eb021SLiane Praza  * Templates non error-dependent labels
44201f6eb021SLiane Praza  */
44211f6eb021SLiane Praza static const char *em_fmri = "FMRI";
44221f6eb021SLiane Praza static const char *em_pg_name = "Property group";
44231f6eb021SLiane Praza static const char *em_prop_name = "Property name";
44241f6eb021SLiane Praza static const char *em_tmpl_fmri = "Template source";
44251f6eb021SLiane Praza static const char *em_tmpl_pg_name = "pg_pattern name";
44261f6eb021SLiane Praza static const char *em_tmpl_pg_type = "pg_pattern type";
44271f6eb021SLiane Praza static const char *em_tmpl_prop_name = "prop_pattern name";
44281f6eb021SLiane Praza static const char *em_tmpl_prop_type = "prop_pattern type";
44291f6eb021SLiane Praza 
44301f6eb021SLiane Praza static const char *
44311f6eb021SLiane Praza _get_fmri_desc(scf_tmpl_error_t *err)
44321f6eb021SLiane Praza {
44331f6eb021SLiane Praza 	switch (err->te_type) {
44341f6eb021SLiane Praza 	case SCF_TERR_MISSING_PG:
44351f6eb021SLiane Praza 	case SCF_TERR_WRONG_PG_TYPE:
44361f6eb021SLiane Praza 	case SCF_TERR_MISSING_PROP:
44371f6eb021SLiane Praza 	case SCF_TERR_WRONG_PROP_TYPE:
44381f6eb021SLiane Praza 	case SCF_TERR_CARDINALITY_VIOLATION:
44391f6eb021SLiane Praza 	case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
44401f6eb021SLiane Praza 	case SCF_TERR_RANGE_VIOLATION:
44411f6eb021SLiane Praza 	case SCF_TERR_PG_REDEFINE:
44421f6eb021SLiane Praza 	case SCF_TERR_PG_PATTERN_INCOMPLETE:
44431f6eb021SLiane Praza 	case SCF_TERR_PROP_PATTERN_INCOMPLETE:
44441f6eb021SLiane Praza 	case SCF_TERR_INCLUDE_VALUES:
44451f6eb021SLiane Praza 		return (dgettext(TEXT_DOMAIN, em_fmri));
44461f6eb021SLiane Praza 	case SCF_TERR_PROP_TYPE_MISMATCH:
44471f6eb021SLiane Praza 	case SCF_TERR_VALUE_OUT_OF_RANGE:
44481f6eb021SLiane Praza 	case SCF_TERR_INVALID_VALUE:
44491f6eb021SLiane Praza 	case SCF_TERR_PG_PATTERN_CONFLICT:
44501f6eb021SLiane Praza 	case SCF_TERR_PROP_PATTERN_CONFLICT:
44511f6eb021SLiane Praza 	case SCF_TERR_GENERAL_REDEFINE:
44521f6eb021SLiane Praza 	default:
44531f6eb021SLiane Praza 		return (NULL);
44541f6eb021SLiane Praza 	}
44551f6eb021SLiane Praza }
44561f6eb021SLiane Praza 
44571f6eb021SLiane Praza static const char *
44581f6eb021SLiane Praza _get_pg_name_desc(scf_tmpl_error_t *err)
44591f6eb021SLiane Praza {
44601f6eb021SLiane Praza 	switch (err->te_type) {
44611f6eb021SLiane Praza 	case SCF_TERR_WRONG_PG_TYPE:
44621f6eb021SLiane Praza 	case SCF_TERR_MISSING_PROP:
44631f6eb021SLiane Praza 	case SCF_TERR_WRONG_PROP_TYPE:
44641f6eb021SLiane Praza 	case SCF_TERR_CARDINALITY_VIOLATION:
44651f6eb021SLiane Praza 	case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
44661f6eb021SLiane Praza 	case SCF_TERR_RANGE_VIOLATION:
44671f6eb021SLiane Praza 		return (dgettext(TEXT_DOMAIN, em_pg_name));
44681f6eb021SLiane Praza 	case SCF_TERR_MISSING_PG:
44691f6eb021SLiane Praza 	case SCF_TERR_PG_REDEFINE:
44701f6eb021SLiane Praza 	case SCF_TERR_PROP_TYPE_MISMATCH:
44711f6eb021SLiane Praza 	case SCF_TERR_VALUE_OUT_OF_RANGE:
44721f6eb021SLiane Praza 	case SCF_TERR_INVALID_VALUE:
44731f6eb021SLiane Praza 	case SCF_TERR_PG_PATTERN_CONFLICT:
44741f6eb021SLiane Praza 	case SCF_TERR_PROP_PATTERN_CONFLICT:
44751f6eb021SLiane Praza 	case SCF_TERR_GENERAL_REDEFINE:
44761f6eb021SLiane Praza 	case SCF_TERR_INCLUDE_VALUES:
44771f6eb021SLiane Praza 	case SCF_TERR_PG_PATTERN_INCOMPLETE:
44781f6eb021SLiane Praza 	case SCF_TERR_PROP_PATTERN_INCOMPLETE:
44791f6eb021SLiane Praza 	default:
44801f6eb021SLiane Praza 		return (NULL);
44811f6eb021SLiane Praza 	}
44821f6eb021SLiane Praza }
44831f6eb021SLiane Praza 
44841f6eb021SLiane Praza static const char *
44851f6eb021SLiane Praza _get_prop_name_desc(scf_tmpl_error_t *err)
44861f6eb021SLiane Praza {
44871f6eb021SLiane Praza 	switch (err->te_type) {
44881f6eb021SLiane Praza 	case SCF_TERR_WRONG_PROP_TYPE:
44891f6eb021SLiane Praza 	case SCF_TERR_CARDINALITY_VIOLATION:
44901f6eb021SLiane Praza 	case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
44911f6eb021SLiane Praza 	case SCF_TERR_RANGE_VIOLATION:
44921f6eb021SLiane Praza 		return (dgettext(TEXT_DOMAIN, em_prop_name));
44931f6eb021SLiane Praza 	case SCF_TERR_MISSING_PG:
44941f6eb021SLiane Praza 	case SCF_TERR_WRONG_PG_TYPE:
44951f6eb021SLiane Praza 	case SCF_TERR_MISSING_PROP:
44961f6eb021SLiane Praza 	case SCF_TERR_PG_REDEFINE:
44971f6eb021SLiane Praza 	case SCF_TERR_PROP_TYPE_MISMATCH:
44981f6eb021SLiane Praza 	case SCF_TERR_VALUE_OUT_OF_RANGE:
44991f6eb021SLiane Praza 	case SCF_TERR_INVALID_VALUE:
45001f6eb021SLiane Praza 	case SCF_TERR_PG_PATTERN_CONFLICT:
45011f6eb021SLiane Praza 	case SCF_TERR_PROP_PATTERN_CONFLICT:
45021f6eb021SLiane Praza 	case SCF_TERR_GENERAL_REDEFINE:
45031f6eb021SLiane Praza 	case SCF_TERR_INCLUDE_VALUES:
45041f6eb021SLiane Praza 	case SCF_TERR_PG_PATTERN_INCOMPLETE:
45051f6eb021SLiane Praza 	case SCF_TERR_PROP_PATTERN_INCOMPLETE:
45061f6eb021SLiane Praza 	default:
45071f6eb021SLiane Praza 		return (NULL);
45081f6eb021SLiane Praza 	}
45091f6eb021SLiane Praza }
45101f6eb021SLiane Praza 
45111f6eb021SLiane Praza static const char *
45121f6eb021SLiane Praza _get_ev1_desc(scf_tmpl_error_t *err)
45131f6eb021SLiane Praza {
45141f6eb021SLiane Praza 	switch (err->te_type) {
45151f6eb021SLiane Praza 	case SCF_TERR_MISSING_PG:
45161f6eb021SLiane Praza 	case SCF_TERR_WRONG_PG_TYPE:
45171f6eb021SLiane Praza 	case SCF_TERR_MISSING_PROP:
45181f6eb021SLiane Praza 	case SCF_TERR_WRONG_PROP_TYPE:
45191f6eb021SLiane Praza 	case SCF_TERR_CARDINALITY_VIOLATION:
45201f6eb021SLiane Praza 	case SCF_TERR_RANGE_VIOLATION:
45211f6eb021SLiane Praza 	case SCF_TERR_PG_REDEFINE:
45221f6eb021SLiane Praza 	case SCF_TERR_PG_PATTERN_CONFLICT:
45231f6eb021SLiane Praza 	case SCF_TERR_PROP_PATTERN_CONFLICT:
45241f6eb021SLiane Praza 	case SCF_TERR_GENERAL_REDEFINE:
45251f6eb021SLiane Praza 	case SCF_TERR_INCLUDE_VALUES:
45261f6eb021SLiane Praza 		return (dgettext(TEXT_DOMAIN, em_desc[err->te_type].em_ev1));
45271f6eb021SLiane Praza 	case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
45281f6eb021SLiane Praza 	case SCF_TERR_PROP_TYPE_MISMATCH:
45291f6eb021SLiane Praza 	case SCF_TERR_VALUE_OUT_OF_RANGE:
45301f6eb021SLiane Praza 	case SCF_TERR_INVALID_VALUE:
45311f6eb021SLiane Praza 	case SCF_TERR_PG_PATTERN_INCOMPLETE:
45321f6eb021SLiane Praza 	case SCF_TERR_PROP_PATTERN_INCOMPLETE:
45331f6eb021SLiane Praza 	default:
45341f6eb021SLiane Praza 		return (NULL);
45351f6eb021SLiane Praza 	}
45361f6eb021SLiane Praza }
45371f6eb021SLiane Praza 
45381f6eb021SLiane Praza static const char *
45391f6eb021SLiane Praza _get_ev2_desc(scf_tmpl_error_t *err)
45401f6eb021SLiane Praza {
45411f6eb021SLiane Praza 	switch (err->te_type) {
45421f6eb021SLiane Praza 	case SCF_TERR_MISSING_PG:
45431f6eb021SLiane Praza 	case SCF_TERR_CARDINALITY_VIOLATION:
45441f6eb021SLiane Praza 	case SCF_TERR_RANGE_VIOLATION:
45451f6eb021SLiane Praza 	case SCF_TERR_PG_REDEFINE:
45461f6eb021SLiane Praza 	case SCF_TERR_PG_PATTERN_CONFLICT:
45471f6eb021SLiane Praza 	case SCF_TERR_PROP_PATTERN_CONFLICT:
45481f6eb021SLiane Praza 	case SCF_TERR_GENERAL_REDEFINE:
45491f6eb021SLiane Praza 		return (dgettext(TEXT_DOMAIN, em_desc[err->te_type].em_ev2));
45501f6eb021SLiane Praza 	case SCF_TERR_WRONG_PG_TYPE:
45511f6eb021SLiane Praza 	case SCF_TERR_MISSING_PROP:
45521f6eb021SLiane Praza 	case SCF_TERR_WRONG_PROP_TYPE:
45531f6eb021SLiane Praza 	case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
45541f6eb021SLiane Praza 	case SCF_TERR_PROP_TYPE_MISMATCH:
45551f6eb021SLiane Praza 	case SCF_TERR_VALUE_OUT_OF_RANGE:
45561f6eb021SLiane Praza 	case SCF_TERR_INVALID_VALUE:
45571f6eb021SLiane Praza 	case SCF_TERR_INCLUDE_VALUES:
45581f6eb021SLiane Praza 	case SCF_TERR_PG_PATTERN_INCOMPLETE:
45591f6eb021SLiane Praza 	case SCF_TERR_PROP_PATTERN_INCOMPLETE:
45601f6eb021SLiane Praza 	default:
45611f6eb021SLiane Praza 		return (NULL);
45621f6eb021SLiane Praza 	}
45631f6eb021SLiane Praza }
45641f6eb021SLiane Praza 
45651f6eb021SLiane Praza static const char *
45661f6eb021SLiane Praza _get_actual_desc(scf_tmpl_error_t *err)
45671f6eb021SLiane Praza {
45681f6eb021SLiane Praza 	switch (err->te_type) {
45691f6eb021SLiane Praza 	case SCF_TERR_MISSING_PG:
45701f6eb021SLiane Praza 	case SCF_TERR_WRONG_PG_TYPE:
45711f6eb021SLiane Praza 	case SCF_TERR_WRONG_PROP_TYPE:
45721f6eb021SLiane Praza 	case SCF_TERR_CARDINALITY_VIOLATION:
45731f6eb021SLiane Praza 	case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
45741f6eb021SLiane Praza 	case SCF_TERR_RANGE_VIOLATION:
45751f6eb021SLiane Praza 	case SCF_TERR_PROP_TYPE_MISMATCH:
45761f6eb021SLiane Praza 	case SCF_TERR_VALUE_OUT_OF_RANGE:
45771f6eb021SLiane Praza 	case SCF_TERR_INVALID_VALUE:
45781f6eb021SLiane Praza 	case SCF_TERR_PG_PATTERN_CONFLICT:
45791f6eb021SLiane Praza 	case SCF_TERR_PROP_PATTERN_CONFLICT:
45801f6eb021SLiane Praza 	case SCF_TERR_GENERAL_REDEFINE:
45811f6eb021SLiane Praza 	case SCF_TERR_INCLUDE_VALUES:
45821f6eb021SLiane Praza 		return (dgettext(TEXT_DOMAIN,
45831f6eb021SLiane Praza 		    em_desc[err->te_type].em_actual));
45841f6eb021SLiane Praza 	case SCF_TERR_MISSING_PROP:
45851f6eb021SLiane Praza 	case SCF_TERR_PG_REDEFINE:
45861f6eb021SLiane Praza 	case SCF_TERR_PG_PATTERN_INCOMPLETE:
45871f6eb021SLiane Praza 	case SCF_TERR_PROP_PATTERN_INCOMPLETE:
45881f6eb021SLiane Praza 	default:
45891f6eb021SLiane Praza 		return (NULL);
45901f6eb021SLiane Praza 	}
45911f6eb021SLiane Praza }
45921f6eb021SLiane Praza 
45931f6eb021SLiane Praza static const char *
45941f6eb021SLiane Praza _get_tmpl_fmri_desc(scf_tmpl_error_t *err)
45951f6eb021SLiane Praza {
45961f6eb021SLiane Praza 	switch (err->te_type) {
45971f6eb021SLiane Praza 	case SCF_TERR_MISSING_PG:
45981f6eb021SLiane Praza 	case SCF_TERR_WRONG_PG_TYPE:
45991f6eb021SLiane Praza 	case SCF_TERR_MISSING_PROP:
46001f6eb021SLiane Praza 	case SCF_TERR_WRONG_PROP_TYPE:
46011f6eb021SLiane Praza 	case SCF_TERR_CARDINALITY_VIOLATION:
46021f6eb021SLiane Praza 	case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
46031f6eb021SLiane Praza 	case SCF_TERR_RANGE_VIOLATION:
46041f6eb021SLiane Praza 	case SCF_TERR_PG_REDEFINE:
46051f6eb021SLiane Praza 	case SCF_TERR_PROP_TYPE_MISMATCH:
46061f6eb021SLiane Praza 	case SCF_TERR_VALUE_OUT_OF_RANGE:
46071f6eb021SLiane Praza 	case SCF_TERR_INVALID_VALUE:
46081f6eb021SLiane Praza 	case SCF_TERR_PG_PATTERN_CONFLICT:
46091f6eb021SLiane Praza 	case SCF_TERR_PROP_PATTERN_CONFLICT:
46101f6eb021SLiane Praza 	case SCF_TERR_GENERAL_REDEFINE:
46111f6eb021SLiane Praza 	case SCF_TERR_INCLUDE_VALUES:
46121f6eb021SLiane Praza 	case SCF_TERR_PG_PATTERN_INCOMPLETE:
46131f6eb021SLiane Praza 	case SCF_TERR_PROP_PATTERN_INCOMPLETE:
46141f6eb021SLiane Praza 		return (dgettext(TEXT_DOMAIN, em_tmpl_fmri));
46151f6eb021SLiane Praza 	default:
46161f6eb021SLiane Praza 		return (NULL);
46171f6eb021SLiane Praza 	}
46181f6eb021SLiane Praza }
46191f6eb021SLiane Praza 
46201f6eb021SLiane Praza static const char *
46211f6eb021SLiane Praza _get_tmpl_pg_name_desc(scf_tmpl_error_t *err)
46221f6eb021SLiane Praza {
46231f6eb021SLiane Praza 	switch (err->te_type) {
46241f6eb021SLiane Praza 	case SCF_TERR_MISSING_PG:
46251f6eb021SLiane Praza 	case SCF_TERR_WRONG_PG_TYPE:
46261f6eb021SLiane Praza 	case SCF_TERR_MISSING_PROP:
46271f6eb021SLiane Praza 	case SCF_TERR_WRONG_PROP_TYPE:
46281f6eb021SLiane Praza 	case SCF_TERR_CARDINALITY_VIOLATION:
46291f6eb021SLiane Praza 	case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
46301f6eb021SLiane Praza 	case SCF_TERR_RANGE_VIOLATION:
46311f6eb021SLiane Praza 	case SCF_TERR_PG_REDEFINE:
46321f6eb021SLiane Praza 	case SCF_TERR_PROP_TYPE_MISMATCH:
46331f6eb021SLiane Praza 	case SCF_TERR_VALUE_OUT_OF_RANGE:
46341f6eb021SLiane Praza 	case SCF_TERR_INVALID_VALUE:
46351f6eb021SLiane Praza 	case SCF_TERR_PG_PATTERN_CONFLICT:
46361f6eb021SLiane Praza 	case SCF_TERR_PROP_PATTERN_CONFLICT:
46371f6eb021SLiane Praza 	case SCF_TERR_GENERAL_REDEFINE:
46381f6eb021SLiane Praza 	case SCF_TERR_INCLUDE_VALUES:
46391f6eb021SLiane Praza 	case SCF_TERR_PG_PATTERN_INCOMPLETE:
46401f6eb021SLiane Praza 	case SCF_TERR_PROP_PATTERN_INCOMPLETE:
46411f6eb021SLiane Praza 		return (dgettext(TEXT_DOMAIN, em_tmpl_pg_name));
46421f6eb021SLiane Praza 	default:
46431f6eb021SLiane Praza 		return (NULL);
46441f6eb021SLiane Praza 	}
46451f6eb021SLiane Praza }
46461f6eb021SLiane Praza 
46471f6eb021SLiane Praza static const char *
46481f6eb021SLiane Praza _get_tmpl_pg_type_desc(scf_tmpl_error_t *err)
46491f6eb021SLiane Praza {
46501f6eb021SLiane Praza 	switch (err->te_type) {
46511f6eb021SLiane Praza 	case SCF_TERR_MISSING_PG:
46521f6eb021SLiane Praza 	case SCF_TERR_WRONG_PG_TYPE:
46531f6eb021SLiane Praza 	case SCF_TERR_MISSING_PROP:
46541f6eb021SLiane Praza 	case SCF_TERR_WRONG_PROP_TYPE:
46551f6eb021SLiane Praza 	case SCF_TERR_CARDINALITY_VIOLATION:
46561f6eb021SLiane Praza 	case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
46571f6eb021SLiane Praza 	case SCF_TERR_RANGE_VIOLATION:
46581f6eb021SLiane Praza 	case SCF_TERR_PG_REDEFINE:
46591f6eb021SLiane Praza 	case SCF_TERR_PROP_TYPE_MISMATCH:
46601f6eb021SLiane Praza 	case SCF_TERR_VALUE_OUT_OF_RANGE:
46611f6eb021SLiane Praza 	case SCF_TERR_INVALID_VALUE:
46621f6eb021SLiane Praza 	case SCF_TERR_PG_PATTERN_CONFLICT:
46631f6eb021SLiane Praza 	case SCF_TERR_PROP_PATTERN_CONFLICT:
46641f6eb021SLiane Praza 	case SCF_TERR_GENERAL_REDEFINE:
46651f6eb021SLiane Praza 	case SCF_TERR_INCLUDE_VALUES:
46661f6eb021SLiane Praza 	case SCF_TERR_PROP_PATTERN_INCOMPLETE:
46671f6eb021SLiane Praza 	case SCF_TERR_PG_PATTERN_INCOMPLETE:
46681f6eb021SLiane Praza 		return (dgettext(TEXT_DOMAIN, em_tmpl_pg_type));
46691f6eb021SLiane Praza 	default:
46701f6eb021SLiane Praza 		return (NULL);
46711f6eb021SLiane Praza 	}
46721f6eb021SLiane Praza }
46731f6eb021SLiane Praza 
46741f6eb021SLiane Praza static const char *
46751f6eb021SLiane Praza _get_tmpl_prop_name_desc(scf_tmpl_error_t *err)
46761f6eb021SLiane Praza {
46771f6eb021SLiane Praza 	switch (err->te_type) {
46781f6eb021SLiane Praza 	case SCF_TERR_MISSING_PROP:
46791f6eb021SLiane Praza 	case SCF_TERR_WRONG_PROP_TYPE:
46801f6eb021SLiane Praza 	case SCF_TERR_CARDINALITY_VIOLATION:
46811f6eb021SLiane Praza 	case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
46821f6eb021SLiane Praza 	case SCF_TERR_RANGE_VIOLATION:
46831f6eb021SLiane Praza 	case SCF_TERR_PROP_TYPE_MISMATCH:
46841f6eb021SLiane Praza 	case SCF_TERR_VALUE_OUT_OF_RANGE:
46851f6eb021SLiane Praza 	case SCF_TERR_INVALID_VALUE:
46861f6eb021SLiane Praza 	case SCF_TERR_PROP_PATTERN_CONFLICT:
46871f6eb021SLiane Praza 	case SCF_TERR_INCLUDE_VALUES:
46881f6eb021SLiane Praza 	case SCF_TERR_PROP_PATTERN_INCOMPLETE:
46891f6eb021SLiane Praza 		return (dgettext(TEXT_DOMAIN, em_tmpl_prop_name));
46901f6eb021SLiane Praza 	case SCF_TERR_MISSING_PG:
46911f6eb021SLiane Praza 	case SCF_TERR_WRONG_PG_TYPE:
46921f6eb021SLiane Praza 	case SCF_TERR_PG_REDEFINE:
46931f6eb021SLiane Praza 	case SCF_TERR_PG_PATTERN_CONFLICT:
46941f6eb021SLiane Praza 	case SCF_TERR_GENERAL_REDEFINE:
46951f6eb021SLiane Praza 	case SCF_TERR_PG_PATTERN_INCOMPLETE:
46961f6eb021SLiane Praza 	default:
46971f6eb021SLiane Praza 		return (NULL);
46981f6eb021SLiane Praza 	}
46991f6eb021SLiane Praza }
47001f6eb021SLiane Praza 
47011f6eb021SLiane Praza static const char *
47021f6eb021SLiane Praza _get_tmpl_prop_type_desc(scf_tmpl_error_t *err)
47031f6eb021SLiane Praza {
47041f6eb021SLiane Praza 	switch (err->te_type) {
47051f6eb021SLiane Praza 	case SCF_TERR_MISSING_PROP:
47061f6eb021SLiane Praza 	case SCF_TERR_WRONG_PROP_TYPE:
47071f6eb021SLiane Praza 	case SCF_TERR_CARDINALITY_VIOLATION:
47081f6eb021SLiane Praza 	case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
47091f6eb021SLiane Praza 	case SCF_TERR_RANGE_VIOLATION:
47101f6eb021SLiane Praza 	case SCF_TERR_PROP_TYPE_MISMATCH:
47111f6eb021SLiane Praza 	case SCF_TERR_VALUE_OUT_OF_RANGE:
47121f6eb021SLiane Praza 	case SCF_TERR_INVALID_VALUE:
47131f6eb021SLiane Praza 	case SCF_TERR_PROP_PATTERN_CONFLICT:
47141f6eb021SLiane Praza 	case SCF_TERR_INCLUDE_VALUES:
47151f6eb021SLiane Praza 		return (dgettext(TEXT_DOMAIN, em_tmpl_prop_type));
47161f6eb021SLiane Praza 	case SCF_TERR_MISSING_PG:
47171f6eb021SLiane Praza 	case SCF_TERR_WRONG_PG_TYPE:
47181f6eb021SLiane Praza 	case SCF_TERR_PG_REDEFINE:
47191f6eb021SLiane Praza 	case SCF_TERR_PG_PATTERN_CONFLICT:
47201f6eb021SLiane Praza 	case SCF_TERR_GENERAL_REDEFINE:
47211f6eb021SLiane Praza 	case SCF_TERR_PG_PATTERN_INCOMPLETE:
47221f6eb021SLiane Praza 	case SCF_TERR_PROP_PATTERN_INCOMPLETE:
47231f6eb021SLiane Praza 	default:
47241f6eb021SLiane Praza 		return (NULL);
47251f6eb021SLiane Praza 	}
47261f6eb021SLiane Praza }
47271f6eb021SLiane Praza 
47281f6eb021SLiane Praza static const char *
47291f6eb021SLiane Praza _get_fmri_val(scf_tmpl_error_t *err)
47301f6eb021SLiane Praza {
47311f6eb021SLiane Praza 	assert(err != NULL && err->te_errs != NULL &&
47321f6eb021SLiane Praza 	    err->te_errs->tes_fmri != NULL);
47331f6eb021SLiane Praza 	return (err->te_errs->tes_fmri);
47341f6eb021SLiane Praza }
47351f6eb021SLiane Praza 
47361f6eb021SLiane Praza static const char *
47371f6eb021SLiane Praza _get_pg_name_val(scf_tmpl_error_t *err)
47381f6eb021SLiane Praza {
47391f6eb021SLiane Praza 	assert(err != NULL);
47401f6eb021SLiane Praza 	return (err->te_pg_name);
47411f6eb021SLiane Praza }
47421f6eb021SLiane Praza 
47431f6eb021SLiane Praza static const char *
47441f6eb021SLiane Praza _get_prop_name_val(scf_tmpl_error_t *err)
47451f6eb021SLiane Praza {
47461f6eb021SLiane Praza 	assert(err != NULL);
47471f6eb021SLiane Praza 	return (err->te_prop_name);
47481f6eb021SLiane Praza }
47491f6eb021SLiane Praza 
47501f6eb021SLiane Praza static const char *
47511f6eb021SLiane Praza _get_ev1_val(scf_tmpl_error_t *err)
47521f6eb021SLiane Praza {
47531f6eb021SLiane Praza 	assert(err != NULL);
47541f6eb021SLiane Praza 	return (err->te_ev1);
47551f6eb021SLiane Praza }
47561f6eb021SLiane Praza 
47571f6eb021SLiane Praza static const char *
47581f6eb021SLiane Praza _get_ev2_val(scf_tmpl_error_t *err)
47591f6eb021SLiane Praza {
47601f6eb021SLiane Praza 	assert(err != NULL);
47611f6eb021SLiane Praza 	return (err->te_ev2);
47621f6eb021SLiane Praza }
47631f6eb021SLiane Praza 
47641f6eb021SLiane Praza static const char *
47651f6eb021SLiane Praza _get_actual_val(scf_tmpl_error_t *err)
47661f6eb021SLiane Praza {
47671f6eb021SLiane Praza 	assert(err != NULL);
47681f6eb021SLiane Praza 	return (err->te_actual);
47691f6eb021SLiane Praza }
47701f6eb021SLiane Praza 
47711f6eb021SLiane Praza static const char *
47721f6eb021SLiane Praza _get_tmpl_fmri_val(scf_tmpl_error_t *err)
47731f6eb021SLiane Praza {
47741f6eb021SLiane Praza 	assert(err != NULL);
47751f6eb021SLiane Praza 	return (err->te_tmpl_fmri);
47761f6eb021SLiane Praza }
47771f6eb021SLiane Praza 
47781f6eb021SLiane Praza static const char *
47791f6eb021SLiane Praza _get_tmpl_pg_name_val(scf_tmpl_error_t *err)
47801f6eb021SLiane Praza {
47811f6eb021SLiane Praza 	assert(err != NULL);
47821f6eb021SLiane Praza 	return (err->te_tmpl_pg_name);
47831f6eb021SLiane Praza }
47841f6eb021SLiane Praza 
47851f6eb021SLiane Praza static const char *
47861f6eb021SLiane Praza _get_tmpl_pg_type_val(scf_tmpl_error_t *err)
47871f6eb021SLiane Praza {
47881f6eb021SLiane Praza 	assert(err != NULL);
47891f6eb021SLiane Praza 	return (err->te_tmpl_pg_type);
47901f6eb021SLiane Praza }
47911f6eb021SLiane Praza 
47921f6eb021SLiane Praza static const char *
47931f6eb021SLiane Praza _get_tmpl_prop_name_val(scf_tmpl_error_t *err)
47941f6eb021SLiane Praza {
47951f6eb021SLiane Praza 	assert(err != NULL);
47961f6eb021SLiane Praza 	return (err->te_tmpl_prop_name);
47971f6eb021SLiane Praza }
47981f6eb021SLiane Praza 
47991f6eb021SLiane Praza static const char *
48001f6eb021SLiane Praza _get_tmpl_prop_type_val(scf_tmpl_error_t *err)
48011f6eb021SLiane Praza {
48021f6eb021SLiane Praza 	assert(err != NULL);
48031f6eb021SLiane Praza 	return (err->te_tmpl_prop_type);
48041f6eb021SLiane Praza }
48051f6eb021SLiane Praza 
48061f6eb021SLiane Praza /*
48071f6eb021SLiane Praza  * Templates error item retrival functions
48081f6eb021SLiane Praza  */
48091f6eb021SLiane Praza typedef const char *(*get_em)(scf_tmpl_error_t *);
48101f6eb021SLiane Praza 
48111f6eb021SLiane Praza /*
48121f6eb021SLiane Praza  * if new items (lines) are added to the templates error messages,
48131f6eb021SLiane Praza  * new entries in this array (and new fuctions) will be required.
48141f6eb021SLiane Praza  */
48151f6eb021SLiane Praza static struct _tmpl_error_access {
48161f6eb021SLiane Praza 	get_em get_desc;
48171f6eb021SLiane Praza 	get_em get_val;
48181f6eb021SLiane Praza } _tmpl_error_items[] = {
48191f6eb021SLiane Praza 	{ (get_em)_get_fmri_desc, (get_em)_get_fmri_val },
48201f6eb021SLiane Praza 	{ (get_em)_get_pg_name_desc, (get_em)_get_pg_name_val },
48211f6eb021SLiane Praza 	{ (get_em)_get_prop_name_desc, (get_em)_get_prop_name_val },
48221f6eb021SLiane Praza 	{ (get_em)_get_ev1_desc, (get_em)_get_ev1_val },
48231f6eb021SLiane Praza 	{ (get_em)_get_ev2_desc, (get_em)_get_ev2_val },
48241f6eb021SLiane Praza 	{ (get_em)_get_actual_desc, (get_em)_get_actual_val },
48251f6eb021SLiane Praza 	{ (get_em)_get_tmpl_fmri_desc, (get_em)_get_tmpl_fmri_val },
48261f6eb021SLiane Praza 	{ (get_em)_get_tmpl_pg_name_desc, (get_em)_get_tmpl_pg_name_val },
48271f6eb021SLiane Praza 	{ (get_em)_get_tmpl_pg_type_desc, (get_em)_get_tmpl_pg_type_val },
48281f6eb021SLiane Praza 	{ (get_em)_get_tmpl_prop_name_desc, (get_em)_get_tmpl_prop_name_val },
48291f6eb021SLiane Praza 	{ (get_em)_get_tmpl_prop_type_desc, (get_em)_get_tmpl_prop_type_val },
48301f6eb021SLiane Praza 	{ NULL }
48311f6eb021SLiane Praza };
48321f6eb021SLiane Praza 
48331f6eb021SLiane Praza /*
48341f6eb021SLiane Praza  * Allocate a new scf_tmpl_error_t and add it to the errs list provided.
48351f6eb021SLiane Praza  * Returns NULL on failure.  Sets scf_error():
48361f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
48371f6eb021SLiane Praza  */
48381f6eb021SLiane Praza static scf_tmpl_error_t *
48391f6eb021SLiane Praza _create_error(scf_tmpl_errors_t *errs)
48401f6eb021SLiane Praza {
48411f6eb021SLiane Praza 	scf_tmpl_error_t *ret;
48421f6eb021SLiane Praza 	scf_tmpl_error_t **saved_errs;
48431f6eb021SLiane Praza 
48441f6eb021SLiane Praza 	assert(errs != NULL);
48451f6eb021SLiane Praza 	ret = calloc(1, sizeof (scf_tmpl_error_t));
48461f6eb021SLiane Praza 	if (ret == NULL) {
48471f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
48481f6eb021SLiane Praza 		return (NULL);
48491f6eb021SLiane Praza 	}
48501f6eb021SLiane Praza 
48511f6eb021SLiane Praza 	ret->te_errs = errs;
48521f6eb021SLiane Praza 
48531f6eb021SLiane Praza 	assert(errs->tes_num_errs <= errs->tes_errs_size);
48541f6eb021SLiane Praza 	if (errs->tes_num_errs == errs->tes_errs_size) {
48551f6eb021SLiane Praza 		/* Time to grow the pointer array. */
48561f6eb021SLiane Praza 		saved_errs = errs->tes_errs;
48571f6eb021SLiane Praza 		errs->tes_errs = calloc(2 * errs->tes_errs_size,
48581f6eb021SLiane Praza 		    sizeof (scf_tmpl_error_t *));
48591f6eb021SLiane Praza 		if (errs->tes_errs == NULL) {
48601f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
48611f6eb021SLiane Praza 			errs->tes_errs = saved_errs;
48621f6eb021SLiane Praza 			free(ret);
48631f6eb021SLiane Praza 			return (NULL);
48641f6eb021SLiane Praza 		}
48651f6eb021SLiane Praza 		(void) memcpy(errs->tes_errs, saved_errs, errs->tes_errs_size *
48661f6eb021SLiane Praza 		    sizeof (scf_tmpl_error_t *));
48671f6eb021SLiane Praza 		errs->tes_errs_size = 2 * errs->tes_errs_size;
48681f6eb021SLiane Praza 		free(saved_errs);
48691f6eb021SLiane Praza 	}
48701f6eb021SLiane Praza 
48711f6eb021SLiane Praza 	errs->tes_errs[errs->tes_num_errs] = ret;
48721f6eb021SLiane Praza 	errs->tes_num_errs++;
48731f6eb021SLiane Praza 
48741f6eb021SLiane Praza 	return (ret);
48751f6eb021SLiane Praza }
48761f6eb021SLiane Praza 
48771f6eb021SLiane Praza /*
48781f6eb021SLiane Praza  *
48791f6eb021SLiane Praza  * If destroy_strings is set, scf_tmpl_errors_destroy will free the
48801f6eb021SLiane Praza  * strings in scf_tmpl_error_t entries.
48811f6eb021SLiane Praza  *
48821f6eb021SLiane Praza  * Returns NULL on failure.  Sets scf_error():
48831f6eb021SLiane Praza  *    SCF_ERROR_NO_MEMORY
48841f6eb021SLiane Praza  */
48851f6eb021SLiane Praza scf_tmpl_errors_t *
48861f6eb021SLiane Praza _scf_create_errors(const char *fmri, int destroy_strings)
48871f6eb021SLiane Praza {
48881f6eb021SLiane Praza 	scf_tmpl_errors_t *ret;
48891f6eb021SLiane Praza 	int errs_size = 20;
48901f6eb021SLiane Praza 
48911f6eb021SLiane Praza 	assert(fmri != NULL);
48921f6eb021SLiane Praza 
48931f6eb021SLiane Praza 	ret = calloc(1, sizeof (scf_tmpl_errors_t));
48941f6eb021SLiane Praza 	if (ret == NULL) {
48951f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
48961f6eb021SLiane Praza 		return (NULL);
48971f6eb021SLiane Praza 	}
48981f6eb021SLiane Praza 
48991f6eb021SLiane Praza 	ret->tes_index = 0;
49001f6eb021SLiane Praza 	ret->tes_num_errs = 0;
49011f6eb021SLiane Praza 	if ((ret->tes_fmri = strdup(fmri)) == NULL) {
49021f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
49031f6eb021SLiane Praza 		free(ret);
49041f6eb021SLiane Praza 		return (NULL);
49051f6eb021SLiane Praza 	}
49061f6eb021SLiane Praza 
49071f6eb021SLiane Praza 	ret->tes_prefix = strdup("");
49081f6eb021SLiane Praza 	if (ret->tes_prefix == NULL) {
49091f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
49101f6eb021SLiane Praza 		free((char *)ret->tes_fmri);
49111f6eb021SLiane Praza 		free(ret);
49121f6eb021SLiane Praza 		return (NULL);
49131f6eb021SLiane Praza 	}
49141f6eb021SLiane Praza 	ret->tes_flag = destroy_strings;
49151f6eb021SLiane Praza 
49161f6eb021SLiane Praza 	/* Make space for a few errors. */
49171f6eb021SLiane Praza 	ret->tes_errs = calloc(errs_size, sizeof (scf_tmpl_error_t *));
49181f6eb021SLiane Praza 	if (ret->tes_errs == NULL) {
49191f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
49201f6eb021SLiane Praza 		free((char *)ret->tes_fmri);
49211f6eb021SLiane Praza 		free((char *)ret->tes_prefix);
49221f6eb021SLiane Praza 		free(ret);
49231f6eb021SLiane Praza 		return (NULL);
49241f6eb021SLiane Praza 	}
49251f6eb021SLiane Praza 	ret->tes_errs_size = errs_size;
49261f6eb021SLiane Praza 
49271f6eb021SLiane Praza 	return (ret);
49281f6eb021SLiane Praza }
49291f6eb021SLiane Praza 
49301f6eb021SLiane Praza /*
49311f6eb021SLiane Praza  * return 0 on success, if fails set scf_error() to:
49321f6eb021SLiane Praza  *
49331f6eb021SLiane Praza  *    SCF_ERROR_NO_MEMORY
49341f6eb021SLiane Praza  */
49351f6eb021SLiane Praza int
49361f6eb021SLiane Praza _scf_tmpl_error_set_prefix(scf_tmpl_errors_t *errs, const char *prefix)
49371f6eb021SLiane Praza {
49381f6eb021SLiane Praza 	free((void *) errs->tes_prefix);
49391f6eb021SLiane Praza 	if (prefix == NULL)
49401f6eb021SLiane Praza 		errs->tes_prefix = strdup("");
49411f6eb021SLiane Praza 	else
49421f6eb021SLiane Praza 		errs->tes_prefix = strdup(prefix);
49431f6eb021SLiane Praza 	if (errs->tes_prefix == NULL) {
49441f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
49451f6eb021SLiane Praza 		return (-1);
49461f6eb021SLiane Praza 	}
49471f6eb021SLiane Praza 	return (0);
49481f6eb021SLiane Praza }
49491f6eb021SLiane Praza 
49501f6eb021SLiane Praza /*
49511f6eb021SLiane Praza  *
49521f6eb021SLiane Praza  * Returns -1 on failure.  Sets scf_error():
49531f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
49541f6eb021SLiane Praza  */
49551f6eb021SLiane Praza int
49561f6eb021SLiane Praza _scf_tmpl_add_error(scf_tmpl_errors_t *errs, scf_tmpl_error_type_t type,
49571f6eb021SLiane Praza     const char *pg_name, const char *prop_name,
49581f6eb021SLiane Praza     const char *ev1, const char *ev2, const char *actual,
49591f6eb021SLiane Praza     const char *tmpl_fmri, const char *tmpl_pg_name, const char *tmpl_pg_type,
49601f6eb021SLiane Praza     const char *tmpl_prop_name, const char *tmpl_prop_type)
49611f6eb021SLiane Praza {
49621f6eb021SLiane Praza 	scf_tmpl_error_t *err;
49631f6eb021SLiane Praza 
49641f6eb021SLiane Praza 	assert(errs != NULL);
49651f6eb021SLiane Praza 	assert(tmpl_fmri != NULL);
49661f6eb021SLiane Praza 
49671f6eb021SLiane Praza 	err = _create_error(errs);
49681f6eb021SLiane Praza 	if (err == NULL)
49691f6eb021SLiane Praza 		return (-1);
49701f6eb021SLiane Praza 
49711f6eb021SLiane Praza 	err->te_type = type;
49721f6eb021SLiane Praza 	err->te_pg_name = pg_name;
49731f6eb021SLiane Praza 	err->te_prop_name = prop_name;
49741f6eb021SLiane Praza 	err->te_ev1 = ev1;
49751f6eb021SLiane Praza 	err->te_ev2 = ev2;
49761f6eb021SLiane Praza 	err->te_actual = actual;
49771f6eb021SLiane Praza 	err->te_tmpl_fmri = tmpl_fmri;
49781f6eb021SLiane Praza 	err->te_tmpl_pg_name = tmpl_pg_name;
49791f6eb021SLiane Praza 	err->te_tmpl_pg_type = tmpl_pg_type;
49801f6eb021SLiane Praza 	err->te_tmpl_prop_name = tmpl_prop_name;
49811f6eb021SLiane Praza 	err->te_tmpl_prop_type = tmpl_prop_type;
49821f6eb021SLiane Praza 
49831f6eb021SLiane Praza 	return (0);
49841f6eb021SLiane Praza }
49851f6eb021SLiane Praza 
49861f6eb021SLiane Praza /*
49871f6eb021SLiane Praza  * returns an allocated string that must be freed with free()
49881f6eb021SLiane Praza  * string contains converted 64-bit integer value
49891f6eb021SLiane Praza  * flag set for signed values
49901f6eb021SLiane Praza  * if fails return NULL and set scf_error() to:
49911f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
49921f6eb021SLiane Praza  */
49931f6eb021SLiane Praza static char *
49941f6eb021SLiane Praza _val_to_string(uint64_t val, int flag)
49951f6eb021SLiane Praza {
49961f6eb021SLiane Praza 	ssize_t sz = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH) + 1;
49971f6eb021SLiane Praza 	char *buf;
49981f6eb021SLiane Praza 
49991f6eb021SLiane Praza 	buf = malloc(sz);
50001f6eb021SLiane Praza 	if (buf == NULL) {
50011f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
50021f6eb021SLiane Praza 		return (NULL);
50031f6eb021SLiane Praza 	}
50041f6eb021SLiane Praza 
50051f6eb021SLiane Praza 	if (flag == 0)
50061f6eb021SLiane Praza 		(void) snprintf(buf, sz, "%" PRIu64, val);
50071f6eb021SLiane Praza 	else
50081f6eb021SLiane Praza 		(void) snprintf(buf, sz, "%" PRIi64, (int64_t)val);
50091f6eb021SLiane Praza 
50101f6eb021SLiane Praza 	return (buf);
50111f6eb021SLiane Praza }
50121f6eb021SLiane Praza 
50131f6eb021SLiane Praza /*
50141f6eb021SLiane Praza  * return 0 on success, -1 on failure.
50151f6eb021SLiane Praza  * set scf_error() to:
50161f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
50171f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
50181f6eb021SLiane Praza  *   SCF_ERROR_DELETED
50191f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
50201f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
50211f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
50221f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
50231f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
50241f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
50251f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
50261f6eb021SLiane Praza  */
50271f6eb021SLiane Praza static int
50281f6eb021SLiane Praza _add_tmpl_missing_pg_error(scf_tmpl_errors_t *errs, scf_pg_tmpl_t *t)
50291f6eb021SLiane Praza {
50301f6eb021SLiane Praza 	char *ev1 = NULL;
50311f6eb021SLiane Praza 	char *ev2 = NULL;
50321f6eb021SLiane Praza 	char *t_fmri = NULL;
50331f6eb021SLiane Praza 	char *t_pg_name = NULL;
50341f6eb021SLiane Praza 	char *t_pg_type = NULL;
50351f6eb021SLiane Praza 
50361f6eb021SLiane Praza 	if ((t_fmri = _scf_tmpl_get_fmri(t)) == NULL)
50371f6eb021SLiane Praza 		return (-1);
50381f6eb021SLiane Praza 	if (scf_tmpl_pg_name(t, &t_pg_name) == -1) {
50391f6eb021SLiane Praza 		goto cleanup;
50401f6eb021SLiane Praza 	}
50411f6eb021SLiane Praza 	if (scf_tmpl_pg_type(t, &t_pg_type) == -1) {
50421f6eb021SLiane Praza 		goto cleanup;
50431f6eb021SLiane Praza 	}
50441f6eb021SLiane Praza 	if ((ev1 = strdup(t_pg_name)) == NULL) {
50451f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
50461f6eb021SLiane Praza 		goto cleanup;
50471f6eb021SLiane Praza 	}
50481f6eb021SLiane Praza 	if ((ev2 = strdup(t_pg_type)) == NULL) {
50491f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
50501f6eb021SLiane Praza 		goto cleanup;
50511f6eb021SLiane Praza 	}
50521f6eb021SLiane Praza 
50531f6eb021SLiane Praza 	return (_scf_tmpl_add_error(errs, SCF_TERR_MISSING_PG, NULL, NULL, ev1,
50541f6eb021SLiane Praza 	    ev2, NULL, t_fmri, t_pg_name, t_pg_type, NULL, NULL));
50551f6eb021SLiane Praza cleanup:
50561f6eb021SLiane Praza 	free(ev1);
50571f6eb021SLiane Praza 	free(ev2);
50581f6eb021SLiane Praza 	free(t_fmri);
50591f6eb021SLiane Praza 	free(t_pg_name);
50601f6eb021SLiane Praza 	free(t_pg_type);
50611f6eb021SLiane Praza 	return (-1);
50621f6eb021SLiane Praza }
50631f6eb021SLiane Praza 
50641f6eb021SLiane Praza /*
50651f6eb021SLiane Praza  * return 0 on success, -1 on failure.
50661f6eb021SLiane Praza  * set scf_error() to:
50671f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
50681f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
50691f6eb021SLiane Praza  *   SCF_ERROR_DELETED
50701f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
50711f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
50721f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
50731f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
50741f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
50751f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
50761f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
50771f6eb021SLiane Praza  */
50781f6eb021SLiane Praza static int
50791f6eb021SLiane Praza _add_tmpl_wrong_pg_type_error(scf_tmpl_errors_t *errs, scf_pg_tmpl_t *t,
50801f6eb021SLiane Praza     scf_propertygroup_t *pg)
50811f6eb021SLiane Praza {
50821f6eb021SLiane Praza 	char *pg_name = NULL;
50831f6eb021SLiane Praza 	char *ev1 = NULL;
50841f6eb021SLiane Praza 	char *actual = NULL;
50851f6eb021SLiane Praza 	char *t_fmri = NULL;
50861f6eb021SLiane Praza 	char *t_pg_name = NULL;
50871f6eb021SLiane Praza 	char *t_pg_type = NULL;
50881f6eb021SLiane Praza 
50891f6eb021SLiane Praza 	if ((t_fmri = _scf_tmpl_get_fmri(t)) == NULL)
50901f6eb021SLiane Praza 		return (-1);
50911f6eb021SLiane Praza 	if ((pg_name = _scf_get_pg_name(pg)) == NULL)
50921f6eb021SLiane Praza 		goto cleanup;
50931f6eb021SLiane Praza 	if ((actual = _scf_get_pg_type(pg)) == NULL)
50941f6eb021SLiane Praza 		goto cleanup;
50951f6eb021SLiane Praza 	if (scf_tmpl_pg_name(t, &t_pg_name) == -1) {
50961f6eb021SLiane Praza 		goto cleanup;
50971f6eb021SLiane Praza 	}
50981f6eb021SLiane Praza 	if (scf_tmpl_pg_type(t, &t_pg_type) == -1) {
50991f6eb021SLiane Praza 		goto cleanup;
51001f6eb021SLiane Praza 	}
51011f6eb021SLiane Praza 	if ((ev1 = strdup(t_pg_type)) == NULL) {
51021f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
51031f6eb021SLiane Praza 		goto cleanup;
51041f6eb021SLiane Praza 	}
51051f6eb021SLiane Praza 
51061f6eb021SLiane Praza 	return (_scf_tmpl_add_error(errs, SCF_TERR_WRONG_PG_TYPE, pg_name, NULL,
51071f6eb021SLiane Praza 	    ev1, NULL, actual, t_fmri, t_pg_name, t_pg_type, NULL, NULL));
51081f6eb021SLiane Praza cleanup:
51091f6eb021SLiane Praza 	free(pg_name);
51101f6eb021SLiane Praza 	free(ev1);
51111f6eb021SLiane Praza 	free(actual);
51121f6eb021SLiane Praza 	free(t_fmri);
51131f6eb021SLiane Praza 	free(t_pg_name);
51141f6eb021SLiane Praza 	free(t_pg_type);
51151f6eb021SLiane Praza 	return (-1);
51161f6eb021SLiane Praza }
51171f6eb021SLiane Praza 
51181f6eb021SLiane Praza /*
51191f6eb021SLiane Praza  * return 0 on success, -1 on failure.
51201f6eb021SLiane Praza  * set scf_error() to:
51211f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
51221f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
51231f6eb021SLiane Praza  *   SCF_ERROR_DELETED
51241f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
51251f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
51261f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
51271f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
51281f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
51291f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
51301f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
51311f6eb021SLiane Praza  */
51321f6eb021SLiane Praza static int
51331f6eb021SLiane Praza _add_tmpl_missing_prop_error(scf_tmpl_errors_t *errs, scf_pg_tmpl_t *t,
51341f6eb021SLiane Praza     scf_propertygroup_t *pg, const scf_prop_tmpl_t *pt)
51351f6eb021SLiane Praza {
51361f6eb021SLiane Praza 	char *pg_name = NULL;
51371f6eb021SLiane Praza 	char *ev1 = NULL;
51381f6eb021SLiane Praza 	char *t_fmri = NULL;
51391f6eb021SLiane Praza 	char *t_pg_name = NULL;
51401f6eb021SLiane Praza 	char *t_pg_type = NULL;
51411f6eb021SLiane Praza 	char *t_prop_name = NULL;
51421f6eb021SLiane Praza 	char *t_prop_type = NULL;
51431f6eb021SLiane Praza 
51441f6eb021SLiane Praza 	if ((t_fmri = _scf_tmpl_get_fmri(t)) == NULL)
51451f6eb021SLiane Praza 		return (-1);
51461f6eb021SLiane Praza 	if ((pg_name = _scf_get_pg_name(pg)) == NULL)
51471f6eb021SLiane Praza 		goto cleanup;
51481f6eb021SLiane Praza 	if (scf_tmpl_pg_name(t, &t_pg_name) == -1) {
51491f6eb021SLiane Praza 		goto cleanup;
51501f6eb021SLiane Praza 	}
51511f6eb021SLiane Praza 	if (scf_tmpl_pg_type(t, &t_pg_type) == -1) {
51521f6eb021SLiane Praza 		goto cleanup;
51531f6eb021SLiane Praza 	}
51541f6eb021SLiane Praza 	if (scf_tmpl_prop_name(pt, &t_prop_name) == -1) {
51551f6eb021SLiane Praza 		goto cleanup;
51561f6eb021SLiane Praza 	}
51571f6eb021SLiane Praza 	t_prop_type = _scf_read_tmpl_prop_type_as_string(pt);
51581f6eb021SLiane Praza 	if (t_prop_type != NULL && t_prop_type[0] == '\0') {
51591f6eb021SLiane Praza 		free(t_prop_type);
51601f6eb021SLiane Praza 		t_prop_type = NULL;
51611f6eb021SLiane Praza 	} else if (t_prop_type == NULL) {
51621f6eb021SLiane Praza 		goto cleanup;
51631f6eb021SLiane Praza 	}
51641f6eb021SLiane Praza 	if (t_prop_type == NULL)
51651f6eb021SLiane Praza 		if ((t_prop_type = strdup(SCF_TMPL_WILDCARD)) == NULL) {
51661f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
51671f6eb021SLiane Praza 			goto cleanup;
51681f6eb021SLiane Praza 		}
51691f6eb021SLiane Praza 	if ((ev1 = strdup(t_prop_name)) == NULL) {
51701f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
51711f6eb021SLiane Praza 		goto cleanup;
51721f6eb021SLiane Praza 	}
51731f6eb021SLiane Praza 
51741f6eb021SLiane Praza 	return (_scf_tmpl_add_error(errs, SCF_TERR_MISSING_PROP, pg_name, NULL,
51751f6eb021SLiane Praza 	    ev1, NULL, NULL, t_fmri, t_pg_name, t_pg_type, t_prop_name,
51761f6eb021SLiane Praza 	    t_prop_type));
51771f6eb021SLiane Praza cleanup:
51781f6eb021SLiane Praza 	free(pg_name);
51791f6eb021SLiane Praza 	free(ev1);
51801f6eb021SLiane Praza 	free(t_fmri);
51811f6eb021SLiane Praza 	free(t_pg_name);
51821f6eb021SLiane Praza 	free(t_pg_type);
51831f6eb021SLiane Praza 	free(t_prop_name);
51841f6eb021SLiane Praza 	free(t_prop_type);
51851f6eb021SLiane Praza 	return (-1);
51861f6eb021SLiane Praza }
51871f6eb021SLiane Praza 
51881f6eb021SLiane Praza /*
51891f6eb021SLiane Praza  * return 0 on success, -1 on failure.
51901f6eb021SLiane Praza  * set scf_error() to:
51911f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
51921f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
51931f6eb021SLiane Praza  *   SCF_ERROR_DELETED
51941f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
51951f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
51961f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
51971f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
51981f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
51991f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
52001f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
52011f6eb021SLiane Praza  */
52021f6eb021SLiane Praza static int
52031f6eb021SLiane Praza _add_tmpl_wrong_prop_type_error(scf_tmpl_errors_t *errs,
52041f6eb021SLiane Praza     scf_propertygroup_t *pg, const scf_prop_tmpl_t *pt, scf_property_t *prop)
52051f6eb021SLiane Praza {
52061f6eb021SLiane Praza 	char *pg_name = NULL;
52071f6eb021SLiane Praza 	char *prop_name = NULL;
52081f6eb021SLiane Praza 	char *ev1 = NULL;
52091f6eb021SLiane Praza 	char *actual = NULL;
52101f6eb021SLiane Praza 	char *t_fmri = NULL;
52111f6eb021SLiane Praza 	char *t_pg_name = NULL;
52121f6eb021SLiane Praza 	char *t_pg_type = NULL;
52131f6eb021SLiane Praza 	char *t_prop_name = NULL;
52141f6eb021SLiane Praza 	char *t_prop_type = NULL;
52151f6eb021SLiane Praza 
52161f6eb021SLiane Praza 	if ((t_fmri = _scf_tmpl_get_fmri(pt->prt_t)) == NULL)
52171f6eb021SLiane Praza 		return (-1);
52181f6eb021SLiane Praza 	if ((pg_name = _scf_get_pg_name(pg)) == NULL)
52191f6eb021SLiane Praza 		goto cleanup;
52201f6eb021SLiane Praza 	if ((prop_name = _scf_get_prop_name(prop)) == NULL)
52211f6eb021SLiane Praza 		goto cleanup;
52221f6eb021SLiane Praza 	if ((actual = _scf_get_prop_type(prop)) == NULL)
52231f6eb021SLiane Praza 		goto cleanup;
52241f6eb021SLiane Praza 	if (scf_tmpl_pg_name(pt->prt_t, &t_pg_name) == -1) {
52251f6eb021SLiane Praza 		goto cleanup;
52261f6eb021SLiane Praza 	}
52271f6eb021SLiane Praza 	if (scf_tmpl_pg_type(pt->prt_t, &t_pg_type) == -1) {
52281f6eb021SLiane Praza 		goto cleanup;
52291f6eb021SLiane Praza 	}
52301f6eb021SLiane Praza 	if (scf_tmpl_prop_name(pt, &t_prop_name) == -1) {
52311f6eb021SLiane Praza 		goto cleanup;
52321f6eb021SLiane Praza 	}
52331f6eb021SLiane Praza 	t_prop_type = _scf_read_tmpl_prop_type_as_string(pt);
52341f6eb021SLiane Praza 	if (t_prop_type != NULL && t_prop_type[0] == '\0') {
52351f6eb021SLiane Praza 		free(t_prop_type);
52361f6eb021SLiane Praza 		t_prop_type = NULL;
52371f6eb021SLiane Praza 	} else if (t_prop_type == NULL) {
52381f6eb021SLiane Praza 		goto cleanup;
52391f6eb021SLiane Praza 	}
52401f6eb021SLiane Praza 	if (t_prop_type == NULL)
52411f6eb021SLiane Praza 		if ((t_prop_type = strdup(SCF_TMPL_WILDCARD)) == NULL) {
52421f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
52431f6eb021SLiane Praza 			goto cleanup;
52441f6eb021SLiane Praza 		}
52451f6eb021SLiane Praza 	if ((ev1 = strdup(t_prop_type)) == NULL) {
52461f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
52471f6eb021SLiane Praza 		goto cleanup;
52481f6eb021SLiane Praza 	}
52491f6eb021SLiane Praza 
52501f6eb021SLiane Praza 	return (_scf_tmpl_add_error(errs, SCF_TERR_WRONG_PROP_TYPE, pg_name,
52511f6eb021SLiane Praza 	    prop_name, ev1, NULL, actual, t_fmri, t_pg_name, t_pg_type,
52521f6eb021SLiane Praza 	    t_prop_name, t_prop_type));
52531f6eb021SLiane Praza cleanup:
52541f6eb021SLiane Praza 	free(pg_name);
52551f6eb021SLiane Praza 	free(prop_name);
52561f6eb021SLiane Praza 	free(ev1);
52571f6eb021SLiane Praza 	free(actual);
52581f6eb021SLiane Praza 	free(t_fmri);
52591f6eb021SLiane Praza 	free(t_pg_name);
52601f6eb021SLiane Praza 	free(t_pg_type);
52611f6eb021SLiane Praza 	free(t_prop_name);
52621f6eb021SLiane Praza 	free(t_prop_type);
52631f6eb021SLiane Praza 	return (-1);
52641f6eb021SLiane Praza }
52651f6eb021SLiane Praza 
52661f6eb021SLiane Praza /*
52671f6eb021SLiane Praza  * return 0 on success, -1 on failure.
52681f6eb021SLiane Praza  * set scf_error() to:
52691f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
52701f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
52711f6eb021SLiane Praza  *   SCF_ERROR_DELETED
52721f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
52731f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
52741f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
52751f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
52761f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
52771f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
52781f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
52791f6eb021SLiane Praza  */
52801f6eb021SLiane Praza static int
52811f6eb021SLiane Praza _add_tmpl_count_error(scf_tmpl_errors_t *errs, scf_tmpl_error_type_t type,
52821f6eb021SLiane Praza     scf_propertygroup_t *pg, const scf_prop_tmpl_t *pt, scf_property_t *prop,
52831f6eb021SLiane Praza     uint64_t count, uint64_t *min, uint64_t *max)
52841f6eb021SLiane Praza {
52851f6eb021SLiane Praza 	char *pg_name = NULL;
52861f6eb021SLiane Praza 	char *prop_name = NULL;
52871f6eb021SLiane Praza 	char *s_min = NULL;
52881f6eb021SLiane Praza 	char *s_max = NULL;
52891f6eb021SLiane Praza 	char *num = NULL;
52901f6eb021SLiane Praza 	char *t_fmri = NULL;
52911f6eb021SLiane Praza 	char *t_pg_name = NULL;
52921f6eb021SLiane Praza 	char *t_pg_type = NULL;
52931f6eb021SLiane Praza 	char *t_prop_name = NULL;
52941f6eb021SLiane Praza 	char *t_prop_type = NULL;
52951f6eb021SLiane Praza 
52961f6eb021SLiane Praza 	if ((t_fmri = _scf_tmpl_get_fmri(pt->prt_t)) == NULL)
52971f6eb021SLiane Praza 		return (-1);
52981f6eb021SLiane Praza 	switch (type) {
52991f6eb021SLiane Praza 	case SCF_TERR_RANGE_VIOLATION:
53001f6eb021SLiane Praza 	case SCF_TERR_CARDINALITY_VIOLATION:
53011f6eb021SLiane Praza 		if ((pg_name = _scf_get_pg_name(pg)) == NULL)
53021f6eb021SLiane Praza 			goto cleanup;
53031f6eb021SLiane Praza 		if ((prop_name = _scf_get_prop_name(prop)) == NULL)
53041f6eb021SLiane Praza 			goto cleanup;
53051f6eb021SLiane Praza 		break;
53061f6eb021SLiane Praza 	case SCF_TERR_VALUE_OUT_OF_RANGE:
53071f6eb021SLiane Praza 		/* keep pg_name = NULL and prop_name = NULL */
53081f6eb021SLiane Praza 		break;
53091f6eb021SLiane Praza 	}
53101f6eb021SLiane Praza 	if (scf_tmpl_pg_name(pt->prt_t, &t_pg_name) == -1) {
53111f6eb021SLiane Praza 		goto cleanup;
53121f6eb021SLiane Praza 	}
53131f6eb021SLiane Praza 	if (scf_tmpl_pg_type(pt->prt_t, &t_pg_type) == -1) {
53141f6eb021SLiane Praza 		goto cleanup;
53151f6eb021SLiane Praza 	}
53161f6eb021SLiane Praza 	if (scf_tmpl_prop_name(pt, &t_prop_name) == -1) {
53171f6eb021SLiane Praza 		goto cleanup;
53181f6eb021SLiane Praza 	}
53191f6eb021SLiane Praza 	t_prop_type = _scf_read_tmpl_prop_type_as_string(pt);
53201f6eb021SLiane Praza 	if (t_prop_type != NULL && t_prop_type[0] == '\0') {
53211f6eb021SLiane Praza 		free(t_prop_type);
53221f6eb021SLiane Praza 		t_prop_type = NULL;
53231f6eb021SLiane Praza 	} else if (t_prop_type == NULL) {
53241f6eb021SLiane Praza 		goto cleanup;
53251f6eb021SLiane Praza 	}
53261f6eb021SLiane Praza 	if (t_prop_type == NULL)
53271f6eb021SLiane Praza 		if ((t_prop_type = strdup(SCF_TMPL_WILDCARD)) == NULL) {
53281f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
53291f6eb021SLiane Praza 			goto cleanup;
53301f6eb021SLiane Praza 		}
53311f6eb021SLiane Praza 	if (min == NULL) {
53321f6eb021SLiane Praza 		if ((s_min = strdup("")) == NULL) {
53331f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
53341f6eb021SLiane Praza 			goto cleanup;
53351f6eb021SLiane Praza 		}
53361f6eb021SLiane Praza 	} else {
53371f6eb021SLiane Praza 		if ((s_min = _val_to_string(*min, 0)) == NULL) {
53381f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
53391f6eb021SLiane Praza 			goto cleanup;
53401f6eb021SLiane Praza 		}
53411f6eb021SLiane Praza 	}
53421f6eb021SLiane Praza 	if (max == NULL) {
53431f6eb021SLiane Praza 		if ((s_max = strdup("")) == NULL) {
53441f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
53451f6eb021SLiane Praza 			goto cleanup;
53461f6eb021SLiane Praza 		}
53471f6eb021SLiane Praza 	} else {
53481f6eb021SLiane Praza 		if ((s_max = _val_to_string(*max, 0)) == NULL) {
53491f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
53501f6eb021SLiane Praza 			goto cleanup;
53511f6eb021SLiane Praza 		}
53521f6eb021SLiane Praza 	}
53531f6eb021SLiane Praza 	if ((num = _val_to_string(count, 0)) == NULL) {
53541f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
53551f6eb021SLiane Praza 		goto cleanup;
53561f6eb021SLiane Praza 	}
53571f6eb021SLiane Praza 
53581f6eb021SLiane Praza 	return (_scf_tmpl_add_error(errs, type, pg_name, prop_name, s_min,
53591f6eb021SLiane Praza 	    s_max, num, t_fmri, t_pg_name, t_pg_type, t_prop_name,
53601f6eb021SLiane Praza 	    t_prop_type));
53611f6eb021SLiane Praza cleanup:
53621f6eb021SLiane Praza 	free(pg_name);
53631f6eb021SLiane Praza 	free(prop_name);
53641f6eb021SLiane Praza 	free(s_min);
53651f6eb021SLiane Praza 	free(s_max);
53661f6eb021SLiane Praza 	free(num);
53671f6eb021SLiane Praza 	free(t_fmri);
53681f6eb021SLiane Praza 	free(t_pg_name);
53691f6eb021SLiane Praza 	free(t_pg_type);
53701f6eb021SLiane Praza 	free(t_prop_name);
53711f6eb021SLiane Praza 	free(t_prop_type);
53721f6eb021SLiane Praza 	return (-1);
53731f6eb021SLiane Praza }
53741f6eb021SLiane Praza 
53751f6eb021SLiane Praza /*
53761f6eb021SLiane Praza  * return 0 on success, -1 on failure.
53771f6eb021SLiane Praza  * set scf_error() to:
53781f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
53791f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
53801f6eb021SLiane Praza  *   SCF_ERROR_DELETED
53811f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
53821f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
53831f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
53841f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
53851f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
53861f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
53871f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
53881f6eb021SLiane Praza  */
53891f6eb021SLiane Praza static int
53901f6eb021SLiane Praza _add_tmpl_constraint_error(scf_tmpl_errors_t *errs, scf_tmpl_error_type_t type,
53911f6eb021SLiane Praza     scf_propertygroup_t *pg, const scf_prop_tmpl_t *pt, scf_property_t *prop,
53921f6eb021SLiane Praza     scf_value_t *val)
53931f6eb021SLiane Praza {
53941f6eb021SLiane Praza 	scf_type_t val_type;
53951f6eb021SLiane Praza 	char *pg_name = NULL;
53961f6eb021SLiane Praza 	char *prop_name = NULL;
53971f6eb021SLiane Praza 	char *value = NULL;
53981f6eb021SLiane Praza 	char *t_fmri = NULL;
53991f6eb021SLiane Praza 	char *t_pg_name = NULL;
54001f6eb021SLiane Praza 	char *t_pg_type = NULL;
54011f6eb021SLiane Praza 	char *t_prop_name = NULL;
54021f6eb021SLiane Praza 	char *t_prop_type = NULL;
54031f6eb021SLiane Praza 
54041f6eb021SLiane Praza 	if ((t_fmri = _scf_tmpl_get_fmri(pt->prt_t)) == NULL)
54051f6eb021SLiane Praza 		return (-1);
54061f6eb021SLiane Praza 	switch (type) {
54071f6eb021SLiane Praza 	case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
54081f6eb021SLiane Praza 		if ((pg_name = _scf_get_pg_name(pg)) == NULL)
54091f6eb021SLiane Praza 			goto cleanup;
54101f6eb021SLiane Praza 		if ((prop_name = _scf_get_prop_name(prop)) == NULL)
54111f6eb021SLiane Praza 			goto cleanup;
54121f6eb021SLiane Praza 		/*FALLTHROUGH*/
54131f6eb021SLiane Praza 	case SCF_TERR_INVALID_VALUE:
54141f6eb021SLiane Praza 		/* keep pg_name = NULL and prop_name = NULL */
54151f6eb021SLiane Praza 		if ((value = _scf_value_get_as_string(val)) == NULL)
54161f6eb021SLiane Praza 			goto cleanup;
54171f6eb021SLiane Praza 		break;
54181f6eb021SLiane Praza 	case SCF_TERR_PROP_TYPE_MISMATCH:
54191f6eb021SLiane Praza 		/* keep pg_name = NULL and prop_name = NULL */
54201f6eb021SLiane Praza 		/* use value for value type */
54211f6eb021SLiane Praza 		val_type = scf_value_type(val);
54221f6eb021SLiane Praza 		if ((value = strdup(scf_type_to_string(val_type))) ==
54231f6eb021SLiane Praza 		    NULL) {
54241f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
54251f6eb021SLiane Praza 			goto cleanup;
54261f6eb021SLiane Praza 		}
54271f6eb021SLiane Praza 		break;
54281f6eb021SLiane Praza 	}
54291f6eb021SLiane Praza 	if (scf_tmpl_pg_name(pt->prt_t, &t_pg_name) == -1) {
54301f6eb021SLiane Praza 		goto cleanup;
54311f6eb021SLiane Praza 	}
54321f6eb021SLiane Praza 	if (scf_tmpl_pg_type(pt->prt_t, &t_pg_type) == -1) {
54331f6eb021SLiane Praza 		goto cleanup;
54341f6eb021SLiane Praza 	}
54351f6eb021SLiane Praza 	if (scf_tmpl_prop_name(pt, &t_prop_name) == -1) {
54361f6eb021SLiane Praza 		goto cleanup;
54371f6eb021SLiane Praza 	}
54381f6eb021SLiane Praza 	t_prop_type = _scf_read_tmpl_prop_type_as_string(pt);
54391f6eb021SLiane Praza 	if (t_prop_type != NULL && t_prop_type[0] == '\0') {
54401f6eb021SLiane Praza 		free(t_prop_type);
54411f6eb021SLiane Praza 		t_prop_type = NULL;
54421f6eb021SLiane Praza 	} else if (t_prop_type == NULL) {
54431f6eb021SLiane Praza 		goto cleanup;
54441f6eb021SLiane Praza 	}
54451f6eb021SLiane Praza 	if (t_prop_type == NULL)
54461f6eb021SLiane Praza 		if ((t_prop_type = strdup(SCF_TMPL_WILDCARD)) == NULL) {
54471f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
54481f6eb021SLiane Praza 			goto cleanup;
54491f6eb021SLiane Praza 		}
54501f6eb021SLiane Praza 
54511f6eb021SLiane Praza 	return (_scf_tmpl_add_error(errs, type, pg_name, prop_name, NULL, NULL,
54521f6eb021SLiane Praza 	    value, t_fmri, t_pg_name, t_pg_type, t_prop_name, t_prop_type));
54531f6eb021SLiane Praza cleanup:
54541f6eb021SLiane Praza 	assert(scf_error() != SCF_ERROR_NOT_SET);
54551f6eb021SLiane Praza 	free(pg_name);
54561f6eb021SLiane Praza 	free(prop_name);
54571f6eb021SLiane Praza 	free(value);
54581f6eb021SLiane Praza 	free(t_fmri);
54591f6eb021SLiane Praza 	free(t_pg_name);
54601f6eb021SLiane Praza 	free(t_pg_type);
54611f6eb021SLiane Praza 	free(t_prop_name);
54621f6eb021SLiane Praza 	free(t_prop_type);
54631f6eb021SLiane Praza 	return (-1);
54641f6eb021SLiane Praza }
54651f6eb021SLiane Praza 
54661f6eb021SLiane Praza /*
54671f6eb021SLiane Praza  * return 0 on success, -1 on failure.
54681f6eb021SLiane Praza  * set scf_error() to:
54691f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
54701f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
54711f6eb021SLiane Praza  *   SCF_ERROR_DELETED
54721f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
54731f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
54741f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
54751f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
54761f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
54771f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
54781f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
54791f6eb021SLiane Praza  */
54801f6eb021SLiane Praza static int
54811f6eb021SLiane Praza _add_tmpl_int_error(scf_tmpl_errors_t *errs, scf_tmpl_error_type_t type,
54821f6eb021SLiane Praza     scf_propertygroup_t *pg, const scf_prop_tmpl_t *pt, scf_property_t *prop,
54831f6eb021SLiane Praza     int64_t val, int64_t *min, int64_t *max)
54841f6eb021SLiane Praza {
54851f6eb021SLiane Praza 	char *pg_name = NULL;
54861f6eb021SLiane Praza 	char *prop_name = NULL;
54871f6eb021SLiane Praza 	char *s_min = NULL;
54881f6eb021SLiane Praza 	char *s_max = NULL;
54891f6eb021SLiane Praza 	char *value = NULL;
54901f6eb021SLiane Praza 	char *t_fmri = NULL;
54911f6eb021SLiane Praza 	char *t_pg_name = NULL;
54921f6eb021SLiane Praza 	char *t_pg_type = NULL;
54931f6eb021SLiane Praza 	char *t_prop_name = NULL;
54941f6eb021SLiane Praza 	char *t_prop_type = NULL;
54951f6eb021SLiane Praza 
54961f6eb021SLiane Praza 	if ((t_fmri = _scf_tmpl_get_fmri(pt->prt_t)) == NULL)
54971f6eb021SLiane Praza 		return (-1);
54981f6eb021SLiane Praza 
54991f6eb021SLiane Praza 	switch (type) {
55001f6eb021SLiane Praza 	case SCF_TERR_RANGE_VIOLATION:
55011f6eb021SLiane Praza 		if ((pg_name = _scf_get_pg_name(pg)) == NULL)
55021f6eb021SLiane Praza 			goto cleanup;
55031f6eb021SLiane Praza 		if ((prop_name = _scf_get_prop_name(prop)) == NULL)
55041f6eb021SLiane Praza 			goto cleanup;
55051f6eb021SLiane Praza 		break;
55061f6eb021SLiane Praza 	case SCF_TERR_VALUE_OUT_OF_RANGE:
55071f6eb021SLiane Praza 		/* keep pg_name = NULL and prop_name = NULL */
55081f6eb021SLiane Praza 		break;
55091f6eb021SLiane Praza 	}
55101f6eb021SLiane Praza 	if (scf_tmpl_pg_name(pt->prt_t, &t_pg_name) == -1) {
55111f6eb021SLiane Praza 		goto cleanup;
55121f6eb021SLiane Praza 	}
55131f6eb021SLiane Praza 	if (scf_tmpl_pg_type(pt->prt_t, &t_pg_type) == -1) {
55141f6eb021SLiane Praza 		goto cleanup;
55151f6eb021SLiane Praza 	}
55161f6eb021SLiane Praza 	if (scf_tmpl_prop_name(pt, &t_prop_name) == -1) {
55171f6eb021SLiane Praza 		goto cleanup;
55181f6eb021SLiane Praza 	}
55191f6eb021SLiane Praza 	t_prop_type = _scf_read_tmpl_prop_type_as_string(pt);
55201f6eb021SLiane Praza 	if (t_prop_type != NULL && t_prop_type[0] == '\0') {
55211f6eb021SLiane Praza 		free(t_prop_type);
55221f6eb021SLiane Praza 		t_prop_type = NULL;
55231f6eb021SLiane Praza 	} else if (t_prop_type == NULL) {
55241f6eb021SLiane Praza 		goto cleanup;
55251f6eb021SLiane Praza 	}
55261f6eb021SLiane Praza 	if (t_prop_type == NULL)
55271f6eb021SLiane Praza 		if ((t_prop_type = strdup(SCF_TMPL_WILDCARD)) == NULL) {
55281f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
55291f6eb021SLiane Praza 			goto cleanup;
55301f6eb021SLiane Praza 		}
55311f6eb021SLiane Praza 	if (min == NULL) {
55321f6eb021SLiane Praza 		if ((s_min = strdup("")) == NULL) {
55331f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
55341f6eb021SLiane Praza 			goto cleanup;
55351f6eb021SLiane Praza 		}
55361f6eb021SLiane Praza 	} else {
55371f6eb021SLiane Praza 		if ((s_min = _val_to_string(*((uint64_t *)min), 1)) == NULL) {
55381f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
55391f6eb021SLiane Praza 			goto cleanup;
55401f6eb021SLiane Praza 		}
55411f6eb021SLiane Praza 	}
55421f6eb021SLiane Praza 	if (max == NULL) {
55431f6eb021SLiane Praza 		if ((s_max = strdup("")) == NULL) {
55441f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
55451f6eb021SLiane Praza 			goto cleanup;
55461f6eb021SLiane Praza 		}
55471f6eb021SLiane Praza 	} else {
55481f6eb021SLiane Praza 		if ((s_max = _val_to_string(*((uint64_t *)max), 1)) == NULL) {
55491f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
55501f6eb021SLiane Praza 			goto cleanup;
55511f6eb021SLiane Praza 		}
55521f6eb021SLiane Praza 	}
55531f6eb021SLiane Praza 	if ((value = _val_to_string((uint64_t)val, 1)) == NULL) {
55541f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
55551f6eb021SLiane Praza 		goto cleanup;
55561f6eb021SLiane Praza 	}
55571f6eb021SLiane Praza 
55581f6eb021SLiane Praza 	return (_scf_tmpl_add_error(errs, type, pg_name, prop_name, s_min,
55591f6eb021SLiane Praza 	    s_max, value, t_fmri, t_pg_name, t_pg_type, t_prop_name,
55601f6eb021SLiane Praza 	    t_prop_type));
55611f6eb021SLiane Praza cleanup:
55621f6eb021SLiane Praza 	free(pg_name);
55631f6eb021SLiane Praza 	free(prop_name);
55641f6eb021SLiane Praza 	free(s_min);
55651f6eb021SLiane Praza 	free(s_max);
55661f6eb021SLiane Praza 	free(value);
55671f6eb021SLiane Praza 	free(t_fmri);
55681f6eb021SLiane Praza 	free(t_pg_name);
55691f6eb021SLiane Praza 	free(t_pg_type);
55701f6eb021SLiane Praza 	free(t_prop_name);
55711f6eb021SLiane Praza 	free(t_prop_type);
55721f6eb021SLiane Praza 	return (-1);
55731f6eb021SLiane Praza }
55741f6eb021SLiane Praza 
55751f6eb021SLiane Praza /*
55761f6eb021SLiane Praza  * return 0 on success, -1 on failure.
55771f6eb021SLiane Praza  * set scf_error() to:
55781f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
55791f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
55801f6eb021SLiane Praza  *   SCF_ERROR_DELETED
55811f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
55821f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
55831f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
55841f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
55851f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
55861f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
55871f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
55881f6eb021SLiane Praza  */
55891f6eb021SLiane Praza static int
55901f6eb021SLiane Praza _add_tmpl_pg_redefine_error(scf_tmpl_errors_t *errs, scf_pg_tmpl_t *t,
55911f6eb021SLiane Praza     scf_pg_tmpl_t *r)
55921f6eb021SLiane Praza {
55931f6eb021SLiane Praza 	char *ev1 = NULL;
55941f6eb021SLiane Praza 	char *ev2 = NULL;
55951f6eb021SLiane Praza 	char *t_fmri = NULL;
55961f6eb021SLiane Praza 	char *t_pg_name = NULL;
55971f6eb021SLiane Praza 	char *t_pg_type = NULL;
55981f6eb021SLiane Praza 
55991f6eb021SLiane Praza 	if ((t_fmri = _scf_tmpl_get_fmri(r)) == NULL)
56001f6eb021SLiane Praza 		return (-1);
56011f6eb021SLiane Praza 	if (scf_tmpl_pg_name(r, &t_pg_name) == -1) {
56021f6eb021SLiane Praza 		goto cleanup;
56031f6eb021SLiane Praza 	}
56041f6eb021SLiane Praza 	if (scf_tmpl_pg_type(r, &t_pg_type) == -1) {
56051f6eb021SLiane Praza 		goto cleanup;
56061f6eb021SLiane Praza 	}
56071f6eb021SLiane Praza 	if (scf_tmpl_pg_name(t, &ev1) == -1) {
56081f6eb021SLiane Praza 		goto cleanup;
56091f6eb021SLiane Praza 	}
56101f6eb021SLiane Praza 	if (scf_tmpl_pg_type(t, &ev2) == -1) {
56111f6eb021SLiane Praza 		goto cleanup;
56121f6eb021SLiane Praza 	}
56131f6eb021SLiane Praza 
56141f6eb021SLiane Praza 	return (_scf_tmpl_add_error(errs, SCF_TERR_PG_REDEFINE, NULL, NULL,
56151f6eb021SLiane Praza 	    ev1, ev2, NULL, t_fmri, t_pg_name, t_pg_type, NULL, NULL));
56161f6eb021SLiane Praza cleanup:
56171f6eb021SLiane Praza 	free(ev1);
56181f6eb021SLiane Praza 	free(ev2);
56191f6eb021SLiane Praza 	free(t_fmri);
56201f6eb021SLiane Praza 	free(t_pg_name);
56211f6eb021SLiane Praza 	free(t_pg_type);
56221f6eb021SLiane Praza 	return (-1);
56231f6eb021SLiane Praza }
56241f6eb021SLiane Praza 
56251f6eb021SLiane Praza /*
56261f6eb021SLiane Praza  * return 0 if value is within count ranges constraint.
56271f6eb021SLiane Praza  * return -1 otherwise
56281f6eb021SLiane Praza  */
56291f6eb021SLiane Praza static int
56301f6eb021SLiane Praza _check_count_ranges(scf_count_ranges_t *cr, uint64_t v)
56311f6eb021SLiane Praza {
56321f6eb021SLiane Praza 	int i;
56331f6eb021SLiane Praza 
56341f6eb021SLiane Praza 	for (i = 0; i < cr->scr_num_ranges; ++i) {
56351f6eb021SLiane Praza 		if (v >= cr->scr_min[i] &&
56361f6eb021SLiane Praza 		    v <= cr->scr_max[i]) {
56371f6eb021SLiane Praza 			/* value is within ranges constraint */
56381f6eb021SLiane Praza 			return (0);
56391f6eb021SLiane Praza 		}
56401f6eb021SLiane Praza 	}
56411f6eb021SLiane Praza 	return (-1);
56421f6eb021SLiane Praza }
56431f6eb021SLiane Praza 
56441f6eb021SLiane Praza /*
56451f6eb021SLiane Praza  * return 0 if value is within count ranges constraint.
56461f6eb021SLiane Praza  * return -1 otherwise
56471f6eb021SLiane Praza  */
56481f6eb021SLiane Praza static int
56491f6eb021SLiane Praza _check_int_ranges(scf_int_ranges_t *ir, int64_t v)
56501f6eb021SLiane Praza {
56511f6eb021SLiane Praza 	int i;
56521f6eb021SLiane Praza 
56531f6eb021SLiane Praza 	for (i = 0; i < ir->sir_num_ranges; ++i) {
56541f6eb021SLiane Praza 		if (v >= ir->sir_min[i] &&
56551f6eb021SLiane Praza 		    v <= ir->sir_max[i]) {
56561f6eb021SLiane Praza 			/* value is within integer ranges constraint */
56571f6eb021SLiane Praza 			return (0);
56581f6eb021SLiane Praza 		}
56591f6eb021SLiane Praza 	}
56601f6eb021SLiane Praza 	return (-1);
56611f6eb021SLiane Praza }
56621f6eb021SLiane Praza 
56631f6eb021SLiane Praza /*
56641f6eb021SLiane Praza  * int _value_in_constraint()
56651f6eb021SLiane Praza  *
56661f6eb021SLiane Praza  * Checks whether the supplied value violates any of the constraints
56671f6eb021SLiane Praza  * specified in the supplied property template.  If it does, an appropriate
56681f6eb021SLiane Praza  * error is appended to "errs".  pg and prop, if supplied, are used to
56691f6eb021SLiane Praza  * augment the information in the error.  Returns 0 on success.
56701f6eb021SLiane Praza  *
56711f6eb021SLiane Praza  * Returns -1 on failure.  Sets scf_error():
56721f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
56731f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
56741f6eb021SLiane Praza  *   SCF_ERROR_DELETED
56751f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
56761f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
56771f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
56781f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
56791f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
56801f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
56811f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
56821f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
56831f6eb021SLiane Praza  */
56841f6eb021SLiane Praza static int
56851f6eb021SLiane Praza _value_in_constraint(scf_propertygroup_t *pg, scf_property_t *prop,
56861f6eb021SLiane Praza     const scf_prop_tmpl_t *pt, scf_value_t *value, scf_tmpl_errors_t *errs)
56871f6eb021SLiane Praza {
56881f6eb021SLiane Praza 	scf_type_t type, tmpl_type;
56891f6eb021SLiane Praza 	scf_values_t vals;
56901f6eb021SLiane Praza 	scf_tmpl_error_type_t terr_type;
56911f6eb021SLiane Praza 	uint64_t v_count;
56921f6eb021SLiane Praza 	int64_t v_int;
56931f6eb021SLiane Praza 	char *vstr;
56941f6eb021SLiane Praza 	ssize_t sz = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH) + 1;
56951f6eb021SLiane Praza 	ssize_t ret = 0;
56961f6eb021SLiane Praza 	char **constraints;
56971f6eb021SLiane Praza 	int n = 0;
56981f6eb021SLiane Praza 	int r;
56991f6eb021SLiane Praza 	int err_flag = 0;
57001f6eb021SLiane Praza 	scf_count_ranges_t cr;
57011f6eb021SLiane Praza 	scf_int_ranges_t ir;
57021f6eb021SLiane Praza 
57031f6eb021SLiane Praza 	type = scf_value_type(value);
57041f6eb021SLiane Praza 	if (type == SCF_TYPE_INVALID) {
57051f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
57061f6eb021SLiane Praza 		return (-1);
57071f6eb021SLiane Praza 	}
57081f6eb021SLiane Praza 
57091f6eb021SLiane Praza 	/* Check if template type matches value type. */
57101f6eb021SLiane Praza 	if (scf_tmpl_prop_type(pt, &tmpl_type) == -1) {
57111f6eb021SLiane Praza 		if (scf_error() != SCF_ERROR_NOT_FOUND)
57121f6eb021SLiane Praza 			/* type is not wildcarded */
57131f6eb021SLiane Praza 			return (-1);
57141f6eb021SLiane Praza 	} else if (tmpl_type != type) {
57151f6eb021SLiane Praza 		if (errs != NULL) {
57161f6eb021SLiane Praza 			if (pg == NULL && prop == NULL) {
57171f6eb021SLiane Praza 				if (_add_tmpl_constraint_error(errs,
57181f6eb021SLiane Praza 				    SCF_TERR_PROP_TYPE_MISMATCH, NULL, pt,
57191f6eb021SLiane Praza 				    NULL, value) == -1)
57201f6eb021SLiane Praza 					return (-1);
57211f6eb021SLiane Praza 			}
57221f6eb021SLiane Praza 		}
57231f6eb021SLiane Praza 		return (1);
57241f6eb021SLiane Praza 	}
57251f6eb021SLiane Praza 
57261f6eb021SLiane Praza 	/* Numeric values should be checked against any range constraints. */
57271f6eb021SLiane Praza 	switch (type) {
57281f6eb021SLiane Praza 	case SCF_TYPE_COUNT:
57291f6eb021SLiane Praza 		r = scf_value_get_count(value, &v_count);
57301f6eb021SLiane Praza 		assert(r == 0);
57311f6eb021SLiane Praza 
57321f6eb021SLiane Praza 		if (scf_tmpl_value_count_range_constraints(pt, &cr) != 0) {
57331f6eb021SLiane Praza 			if (scf_error() == SCF_ERROR_NOT_FOUND)
57341f6eb021SLiane Praza 				break;
57351f6eb021SLiane Praza 			if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED)
57361f6eb021SLiane Praza 				(void) scf_set_error(
57371f6eb021SLiane Praza 				    SCF_ERROR_TEMPLATE_INVALID);
57381f6eb021SLiane Praza 			return (-1);
57391f6eb021SLiane Praza 		} else {
57401f6eb021SLiane Praza 			if (_check_count_ranges(&cr, v_count) == 0) {
57411f6eb021SLiane Praza 				/* value is within ranges constraint */
57421f6eb021SLiane Praza 				scf_count_ranges_destroy(&cr);
57431f6eb021SLiane Praza 				return (0);
57441f6eb021SLiane Praza 			}
57451f6eb021SLiane Praza 			scf_count_ranges_destroy(&cr);
57461f6eb021SLiane Praza 		}
57471f6eb021SLiane Praza 
57481f6eb021SLiane Praza 		/*
57491f6eb021SLiane Praza 		 * If we get here, we have a possible constraint
57501f6eb021SLiane Praza 		 * violation.
57511f6eb021SLiane Praza 		 */
57521f6eb021SLiane Praza 		err_flag |= 0x1; /* RANGE_VIOLATION, count */
57531f6eb021SLiane Praza 		break;
57541f6eb021SLiane Praza 	case SCF_TYPE_INTEGER:
57551f6eb021SLiane Praza 		if (scf_value_get_integer(value, &v_int) != 0)
57561f6eb021SLiane Praza 			assert(0);
57571f6eb021SLiane Praza 		if (scf_tmpl_value_int_range_constraints(pt, &ir) != 0) {
57581f6eb021SLiane Praza 			if (scf_error() == SCF_ERROR_NOT_FOUND)
57591f6eb021SLiane Praza 				break;
57601f6eb021SLiane Praza 			if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED)
57611f6eb021SLiane Praza 				(void) scf_set_error(
57621f6eb021SLiane Praza 				    SCF_ERROR_TEMPLATE_INVALID);
57631f6eb021SLiane Praza 			return (-1);
57641f6eb021SLiane Praza 		} else {
57651f6eb021SLiane Praza 			if (_check_int_ranges(&ir, v_int) == 0) {
57661f6eb021SLiane Praza 				/* value is within ranges constraint */
57671f6eb021SLiane Praza 				scf_int_ranges_destroy(&ir);
57681f6eb021SLiane Praza 				return (0);
57691f6eb021SLiane Praza 			}
57701f6eb021SLiane Praza 			scf_int_ranges_destroy(&ir);
57711f6eb021SLiane Praza 		}
57721f6eb021SLiane Praza 		/*
57731f6eb021SLiane Praza 		 * If we get here, we have a possible constraint
57741f6eb021SLiane Praza 		 * violation.
57751f6eb021SLiane Praza 		 */
57761f6eb021SLiane Praza 		err_flag |= 0x2; /* RANGE_VIOLATION, integer */
57771f6eb021SLiane Praza 		break;
57781f6eb021SLiane Praza 	default:
57791f6eb021SLiane Praza 		break;
57801f6eb021SLiane Praza 	}
57811f6eb021SLiane Praza 
57821f6eb021SLiane Praza 	vstr = malloc(sz);
57831f6eb021SLiane Praza 	if (vstr == NULL) {
57841f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
57851f6eb021SLiane Praza 		return (-1);
57861f6eb021SLiane Praza 	}
57871f6eb021SLiane Praza 
57881f6eb021SLiane Praza 	/*
57891f6eb021SLiane Praza 	 * If a set of names is provided, confirm value has one of
57901f6eb021SLiane Praza 	 * those names.
57911f6eb021SLiane Praza 	 */
57921f6eb021SLiane Praza 	if (scf_tmpl_value_name_constraints(pt, &vals) != 0) {
57931f6eb021SLiane Praza 		free(vstr);
57941f6eb021SLiane Praza 		if (scf_error() != SCF_ERROR_NOT_FOUND) {
57951f6eb021SLiane Praza 			return (-1);
57961f6eb021SLiane Praza 		}
57971f6eb021SLiane Praza 	} else {
57981f6eb021SLiane Praza 		r = scf_value_get_as_string_typed(value, type, vstr, sz);
57991f6eb021SLiane Praza 
58001f6eb021SLiane Praza 		/*
58011f6eb021SLiane Praza 		 * All errors (INVALID_ARGUMENT, NOT_SET, TYPE_MISMATCH)
58021f6eb021SLiane Praza 		 * should be impossible or already caught above.
58031f6eb021SLiane Praza 		 */
58041f6eb021SLiane Praza 		assert(r > 0);
58051f6eb021SLiane Praza 
58061f6eb021SLiane Praza 		constraints = vals.values.v_astring;
58071f6eb021SLiane Praza 		for (n = 0; constraints[n] != NULL; ++n) {
58081f6eb021SLiane Praza 			if (strcmp(constraints[n], vstr) == 0) {
58091f6eb021SLiane Praza 				/* value is within constraint */
58101f6eb021SLiane Praza 				scf_values_destroy(&vals);
58111f6eb021SLiane Praza 				free(vstr);
58121f6eb021SLiane Praza 				return (0);
58131f6eb021SLiane Praza 			}
58141f6eb021SLiane Praza 		}
58151f6eb021SLiane Praza 		/* if we get here, we have a constraint violation */
58161f6eb021SLiane Praza 		err_flag |= 0x4; /* CONSTRAINT_VIOLATED */
58171f6eb021SLiane Praza 		scf_values_destroy(&vals);
58181f6eb021SLiane Praza 		free(vstr);
58191f6eb021SLiane Praza 	}
58201f6eb021SLiane Praza 	if (err_flag != 0)
58211f6eb021SLiane Praza 		ret = 1;
58221f6eb021SLiane Praza 	/* register the errors found */
58231f6eb021SLiane Praza 	if (ret == 1 && errs != NULL) {
58241f6eb021SLiane Praza 		if ((err_flag & 0x1) == 0x1) {
58251f6eb021SLiane Praza 			/*
58261f6eb021SLiane Praza 			 * Help make the error more human-friendly.  If
58271f6eb021SLiane Praza 			 * pg and prop are provided, we know we're
58281f6eb021SLiane Praza 			 * validating repository data.  If they're not,
58291f6eb021SLiane Praza 			 * we're validating a potentially hypothetical
58301f6eb021SLiane Praza 			 * value.
58311f6eb021SLiane Praza 			 */
58321f6eb021SLiane Praza 			if (pg == NULL && prop == NULL)
58331f6eb021SLiane Praza 				terr_type = SCF_TERR_VALUE_OUT_OF_RANGE;
58341f6eb021SLiane Praza 			else
58351f6eb021SLiane Praza 				terr_type = SCF_TERR_RANGE_VIOLATION;
58361f6eb021SLiane Praza 			if (_add_tmpl_count_error(errs, terr_type, pg, pt,
58371f6eb021SLiane Praza 			    prop, v_count, 0, 0) == -1)
58381f6eb021SLiane Praza 				ret = -1;
58391f6eb021SLiane Praza 		}
58401f6eb021SLiane Praza 		if ((err_flag & 0x2) == 0x2) {
58411f6eb021SLiane Praza 			if (pg == NULL && prop == NULL)
58421f6eb021SLiane Praza 				terr_type = SCF_TERR_VALUE_OUT_OF_RANGE;
58431f6eb021SLiane Praza 			else
58441f6eb021SLiane Praza 				terr_type = SCF_TERR_RANGE_VIOLATION;
58451f6eb021SLiane Praza 			if (_add_tmpl_int_error(errs, terr_type, pg, pt, prop,
58461f6eb021SLiane Praza 			    v_int, 0, 0) == -1)
58471f6eb021SLiane Praza 				ret = -1;
58481f6eb021SLiane Praza 		}
58491f6eb021SLiane Praza 		if ((err_flag & 0x4) == 0x4) {
58501f6eb021SLiane Praza 			if (pg == NULL && prop == NULL)
58511f6eb021SLiane Praza 				terr_type = SCF_TERR_INVALID_VALUE;
58521f6eb021SLiane Praza 			else
58531f6eb021SLiane Praza 				terr_type = SCF_TERR_VALUE_CONSTRAINT_VIOLATED;
58541f6eb021SLiane Praza 			if (_add_tmpl_constraint_error(errs, terr_type, pg,
58551f6eb021SLiane Praza 			    pt, prop, value) == -1)
58561f6eb021SLiane Praza 				ret = -1;
58571f6eb021SLiane Praza 		}
58581f6eb021SLiane Praza 	}
58591f6eb021SLiane Praza 	return (ret);
58601f6eb021SLiane Praza }
58611f6eb021SLiane Praza 
58621f6eb021SLiane Praza /*
58631f6eb021SLiane Praza  * Returns -1 on failure.  Sets scf_error():
58641f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
58651f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
58661f6eb021SLiane Praza  *   SCF_ERROR_DELETED
58671f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
58681f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
58691f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
58701f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
58711f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
58721f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
58731f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
58741f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
58751f6eb021SLiane Praza  */
58761f6eb021SLiane Praza int
58771f6eb021SLiane Praza scf_tmpl_value_in_constraint(const scf_prop_tmpl_t *pt, scf_value_t *value,
58781f6eb021SLiane Praza     scf_tmpl_errors_t **errs)
58791f6eb021SLiane Praza {
58801f6eb021SLiane Praza 	scf_tmpl_errors_t *e = NULL;
58811f6eb021SLiane Praza 
58821f6eb021SLiane Praza 	if (errs != NULL) {
58831f6eb021SLiane Praza 		char *fmri;
58841f6eb021SLiane Praza 
58851f6eb021SLiane Praza 		if ((fmri = _scf_tmpl_get_fmri(pt->prt_t)) == NULL)
58861f6eb021SLiane Praza 			return (-1);
58871f6eb021SLiane Praza 		*errs = _scf_create_errors(fmri, 1);
58881f6eb021SLiane Praza 		free(fmri);
58891f6eb021SLiane Praza 		if (*errs == NULL)
58901f6eb021SLiane Praza 			return (-1);
58911f6eb021SLiane Praza 		e = *errs;
58921f6eb021SLiane Praza 	}
58931f6eb021SLiane Praza 
58941f6eb021SLiane Praza 	return (_value_in_constraint(NULL, NULL, pt, value, e));
58951f6eb021SLiane Praza }
58961f6eb021SLiane Praza 
58971f6eb021SLiane Praza scf_tmpl_error_t *
58981f6eb021SLiane Praza scf_tmpl_next_error(scf_tmpl_errors_t *errs)
58991f6eb021SLiane Praza {
59001f6eb021SLiane Praza 	if (errs->tes_index < errs->tes_num_errs) {
59011f6eb021SLiane Praza 		assert(errs->tes_errs[errs->tes_index] != NULL);
59021f6eb021SLiane Praza 		return (errs->tes_errs[errs->tes_index++]);
59031f6eb021SLiane Praza 	} else {
59041f6eb021SLiane Praza 		return (NULL);
59051f6eb021SLiane Praza 	}
59061f6eb021SLiane Praza }
59071f6eb021SLiane Praza 
59081f6eb021SLiane Praza void
59091f6eb021SLiane Praza scf_tmpl_reset_errors(scf_tmpl_errors_t *errs)
59101f6eb021SLiane Praza {
59111f6eb021SLiane Praza 	errs->tes_index = 0;
59121f6eb021SLiane Praza }
59131f6eb021SLiane Praza 
59141f6eb021SLiane Praza int
59151f6eb021SLiane Praza scf_tmpl_strerror(scf_tmpl_error_t *err,  char *s, size_t n, int flag)
59161f6eb021SLiane Praza {
59171f6eb021SLiane Praza 	const char *str;
59181f6eb021SLiane Praza 	int i;
59191f6eb021SLiane Praza 	int ret = -1;
59201f6eb021SLiane Praza 	int nsz = 0;	/* err msg length */
59211f6eb021SLiane Praza 	int sz = n;	/* available buffer size */
59221f6eb021SLiane Praza 	char *buf = s;	/* where to append in buffer */
59231f6eb021SLiane Praza 	char *s0 = (flag == SCF_TMPL_STRERROR_HUMAN) ? ":\n\t" : ": ";
59241f6eb021SLiane Praza 	char *s1 = (flag == SCF_TMPL_STRERROR_HUMAN) ? "\n\t" : "; ";
59251f6eb021SLiane Praza 	char *sep = s0;
59261f6eb021SLiane Praza 	const char *val;
59271f6eb021SLiane Praza 
59281f6eb021SLiane Praza 	/* prefix */
59291f6eb021SLiane Praza 	if (err->te_errs->tes_prefix != NULL) {
59301f6eb021SLiane Praza 		ret = snprintf(buf, sz, "%s", dgettext(TEXT_DOMAIN,
59311f6eb021SLiane Praza 		    err->te_errs->tes_prefix));
59321f6eb021SLiane Praza 		nsz += ret;
59331f6eb021SLiane Praza 		sz = (sz - ret) > 0 ? sz - ret : 0;
59341f6eb021SLiane Praza 		buf = (sz > 0) ? s + nsz : NULL;
59351f6eb021SLiane Praza 	}
59361f6eb021SLiane Praza 	/* error message */
59371f6eb021SLiane Praza 	ret = snprintf(buf, sz, "%s", dgettext(TEXT_DOMAIN,
59381f6eb021SLiane Praza 	    em_desc[err->te_type].em_msg));
59391f6eb021SLiane Praza 	nsz += ret;
59401f6eb021SLiane Praza 	sz = (sz - ret) > 0 ? sz - ret : 0;
59411f6eb021SLiane Praza 	buf = (sz > 0) ? s + nsz : NULL;
59421f6eb021SLiane Praza 
59431f6eb021SLiane Praza 	for (i = 0; _tmpl_error_items[i].get_desc != NULL; ++i) {
59441f6eb021SLiane Praza 		if ((str = _tmpl_error_items[i].get_desc(err)) == NULL)
59451f6eb021SLiane Praza 			/* no item to print */
59461f6eb021SLiane Praza 			continue;
59471f6eb021SLiane Praza 		val = _tmpl_error_items[i].get_val(err);
59481f6eb021SLiane Praza 		ret = snprintf(buf, sz, "%s%s=\"%s\"", sep, str,
59491f6eb021SLiane Praza 		    (val == NULL) ? "" : val);
59501f6eb021SLiane Praza 		nsz += ret;
59511f6eb021SLiane Praza 		sz = (sz - ret) > 0 ? sz - ret : 0;
59521f6eb021SLiane Praza 		buf = (sz > 0) ? s + nsz : NULL;
59531f6eb021SLiane Praza 		sep = s1;
59541f6eb021SLiane Praza 	}
59551f6eb021SLiane Praza 	return (nsz);
59561f6eb021SLiane Praza }
59571f6eb021SLiane Praza 
59581f6eb021SLiane Praza /*
59591f6eb021SLiane Praza  * return 0 on success, -1 on failure.
59601f6eb021SLiane Praza  * set scf_error() to:
59611f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
59621f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
59631f6eb021SLiane Praza  *   SCF_ERROR_DELETED
59641f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
59651f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
59661f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
59671f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
59681f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
59691f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
59701f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
59711f6eb021SLiane Praza  */
59721f6eb021SLiane Praza static int
59731f6eb021SLiane Praza _validate_cardinality(scf_propertygroup_t *pg, scf_prop_tmpl_t *pt,
59741f6eb021SLiane Praza     scf_property_t *prop, scf_tmpl_errors_t *errs)
59751f6eb021SLiane Praza {
59761f6eb021SLiane Praza 	uint64_t min, max;
59771f6eb021SLiane Praza 	scf_handle_t *h;
59781f6eb021SLiane Praza 	scf_iter_t *iter = NULL;
59791f6eb021SLiane Praza 	scf_value_t *val = NULL;
59801f6eb021SLiane Praza 	int count = 0;
59811f6eb021SLiane Praza 	int ret = -1;
59821f6eb021SLiane Praza 	int r;
59831f6eb021SLiane Praza 
59841f6eb021SLiane Praza 	if (scf_tmpl_prop_cardinality(pt, &min, &max) != 0) {
59851f6eb021SLiane Praza 		if (scf_error() == SCF_ERROR_NOT_FOUND)
59861f6eb021SLiane Praza 			return (0);
59871f6eb021SLiane Praza 		else
59881f6eb021SLiane Praza 			return (-1);
59891f6eb021SLiane Praza 	}
59901f6eb021SLiane Praza 
59911f6eb021SLiane Praza 	/* Any number of values permitted.  Just return success. */
59921f6eb021SLiane Praza 	if (min == 0 && max == UINT64_MAX) {
59931f6eb021SLiane Praza 		return (0);
59941f6eb021SLiane Praza 	}
59951f6eb021SLiane Praza 
59961f6eb021SLiane Praza 	h = scf_property_handle(prop);
59971f6eb021SLiane Praza 	if (h == NULL) {
59981f6eb021SLiane Praza 		assert(scf_error() == SCF_ERROR_HANDLE_DESTROYED);
59991f6eb021SLiane Praza 		goto cleanup;
60001f6eb021SLiane Praza 	}
60011f6eb021SLiane Praza 
60021f6eb021SLiane Praza 	iter = scf_iter_create(h);
60031f6eb021SLiane Praza 	val = scf_value_create(h);
60041f6eb021SLiane Praza 	if (iter == NULL || val == NULL) {
60051f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
60061f6eb021SLiane Praza 			goto cleanup;
60071f6eb021SLiane Praza 		} else {
60081f6eb021SLiane Praza 			assert(0);
60091f6eb021SLiane Praza 			abort();
60101f6eb021SLiane Praza 		}
60111f6eb021SLiane Praza 	}
60121f6eb021SLiane Praza 
60131f6eb021SLiane Praza 	if (scf_iter_property_values(iter, prop) != 0) {
60141f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
60151f6eb021SLiane Praza 			goto cleanup;
60161f6eb021SLiane Praza 		} else {
60171f6eb021SLiane Praza 			assert(0);
60181f6eb021SLiane Praza 			abort();
60191f6eb021SLiane Praza 		}
60201f6eb021SLiane Praza 	}
60211f6eb021SLiane Praza 
60221f6eb021SLiane Praza 	while ((r = scf_iter_next_value(iter, val)) == 1)
60231f6eb021SLiane Praza 		count++;
60241f6eb021SLiane Praza 
60251f6eb021SLiane Praza 	if (r < 0) {
60261f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
60271f6eb021SLiane Praza 			goto cleanup;
60281f6eb021SLiane Praza 		} else {
60291f6eb021SLiane Praza 			assert(0);
60301f6eb021SLiane Praza 			abort();
60311f6eb021SLiane Praza 		}
60321f6eb021SLiane Praza 	}
60331f6eb021SLiane Praza 
60341f6eb021SLiane Praza 	if (count < min || count > max)
60351f6eb021SLiane Praza 		if (_add_tmpl_count_error(errs, SCF_TERR_CARDINALITY_VIOLATION,
60361f6eb021SLiane Praza 		    pg, pt, prop, (uint64_t)count, &min, &max) == -1)
60371f6eb021SLiane Praza 			goto cleanup;
60381f6eb021SLiane Praza 
60391f6eb021SLiane Praza 	ret = 0;
60401f6eb021SLiane Praza 
60411f6eb021SLiane Praza cleanup:
60421f6eb021SLiane Praza 	scf_iter_destroy(iter);
60431f6eb021SLiane Praza 	scf_value_destroy(val);
60441f6eb021SLiane Praza 	return (ret);
60451f6eb021SLiane Praza }
60461f6eb021SLiane Praza 
60471f6eb021SLiane Praza /*
60481f6eb021SLiane Praza  * Returns -1 on error.  Sets scf_error():
60491f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
60501f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
60511f6eb021SLiane Praza  *   SCF_ERROR_DELETED
60521f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
60531f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
60541f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
60551f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
60561f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
60571f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
60581f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
60591f6eb021SLiane Praza  */
60601f6eb021SLiane Praza static int
60611f6eb021SLiane Praza _check_property(scf_prop_tmpl_t *pt, scf_propertygroup_t *pg,
60621f6eb021SLiane Praza     scf_property_t *prop, scf_tmpl_errors_t *errs)
60631f6eb021SLiane Praza {
60641f6eb021SLiane Praza 	scf_type_t tmpl_type;
60651f6eb021SLiane Praza 	uint8_t required;
60661f6eb021SLiane Praza 	scf_handle_t *h;
60671f6eb021SLiane Praza 	scf_iter_t *iter = NULL;
60681f6eb021SLiane Praza 	scf_value_t *val = NULL;
60691f6eb021SLiane Praza 	int r;
60701f6eb021SLiane Praza 	int ret = -1;
60711f6eb021SLiane Praza 
60721f6eb021SLiane Praza 	h = scf_pg_handle(pg);
60731f6eb021SLiane Praza 	if (h == NULL) {
60741f6eb021SLiane Praza 		assert(scf_error() == SCF_ERROR_HANDLE_DESTROYED);
60751f6eb021SLiane Praza 		return (-1);
60761f6eb021SLiane Praza 	}
60771f6eb021SLiane Praza 
60781f6eb021SLiane Praza 	iter = scf_iter_create(h);
60791f6eb021SLiane Praza 	val = scf_value_create(h);
60801f6eb021SLiane Praza 	if (iter == NULL || val == NULL) {
60811f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
60821f6eb021SLiane Praza 			scf_iter_destroy(iter);
60831f6eb021SLiane Praza 			scf_value_destroy(val);
60841f6eb021SLiane Praza 			return (-1);
60851f6eb021SLiane Praza 		} else {
60861f6eb021SLiane Praza 			assert(0);
60871f6eb021SLiane Praza 			abort();
60881f6eb021SLiane Praza 		}
60891f6eb021SLiane Praza 	}
60901f6eb021SLiane Praza 
60911f6eb021SLiane Praza 	if (scf_tmpl_prop_required(pt, &required) != 0)
60921f6eb021SLiane Praza 		goto cleanup;
60931f6eb021SLiane Praza 
60941f6eb021SLiane Praza 	/* Check type */
60951f6eb021SLiane Praza 	if (scf_tmpl_prop_type(pt, &tmpl_type) == -1) {
60961f6eb021SLiane Praza 		if (scf_error() != SCF_ERROR_NOT_FOUND) {
60971f6eb021SLiane Praza 			goto cleanup;
60981f6eb021SLiane Praza 		} else if (required) {
60991f6eb021SLiane Praza 			/* If required, type must be specified. */
61001f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
61011f6eb021SLiane Praza 			goto cleanup;
61021f6eb021SLiane Praza 		}
61031f6eb021SLiane Praza 	} else if (scf_property_is_type(prop, tmpl_type) != 0) {
61041f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
61051f6eb021SLiane Praza 			goto cleanup;
61061f6eb021SLiane Praza 		} else switch (scf_error()) {
61071f6eb021SLiane Praza 		case SCF_ERROR_TYPE_MISMATCH:
61081f6eb021SLiane Praza 			if (_add_tmpl_wrong_prop_type_error(errs, pg, pt,
61091f6eb021SLiane Praza 			    prop) == -1)
61101f6eb021SLiane Praza 				goto cleanup;
61111f6eb021SLiane Praza 			break;
61121f6eb021SLiane Praza 
61131f6eb021SLiane Praza 		case SCF_ERROR_INVALID_ARGUMENT:
61141f6eb021SLiane Praza 			/*
61151f6eb021SLiane Praza 			 * tmpl_prop_type shouldn't have handed back
61161f6eb021SLiane Praza 			 * an invalid property type.
61171f6eb021SLiane Praza 			 */
61181f6eb021SLiane Praza 		case SCF_ERROR_NOT_SET:
61191f6eb021SLiane Praza 		default:
61201f6eb021SLiane Praza 			assert(0);
61211f6eb021SLiane Praza 			abort();
61221f6eb021SLiane Praza 		}
61231f6eb021SLiane Praza 	}
61241f6eb021SLiane Praza 
61251f6eb021SLiane Praza 
61261f6eb021SLiane Praza 	/* Cardinality */
61271f6eb021SLiane Praza 	if (_validate_cardinality(pg, pt, prop, errs) == -1)
61281f6eb021SLiane Praza 		goto cleanup;
61291f6eb021SLiane Praza 
61301f6eb021SLiane Praza 	/* Value constraints */
61311f6eb021SLiane Praza 	/*
61321f6eb021SLiane Praza 	 * Iterate through each value, and confirm it is defined as
61331f6eb021SLiane Praza 	 * constrained.
61341f6eb021SLiane Praza 	 */
61351f6eb021SLiane Praza 	if (scf_iter_property_values(iter, prop) != 0) {
61361f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_NOT_SET &&
61371f6eb021SLiane Praza 		    scf_error() != SCF_ERROR_HANDLE_MISMATCH);
61381f6eb021SLiane Praza 		goto cleanup;
61391f6eb021SLiane Praza 	}
61401f6eb021SLiane Praza 
61411f6eb021SLiane Praza 	while ((r = scf_iter_next_value(iter, val)) == 1) {
61421f6eb021SLiane Praza 		if (_value_in_constraint(pg, prop, pt, val, errs) == -1) {
61431f6eb021SLiane Praza 			if (ismember(scf_error(), errors_server)) {
61441f6eb021SLiane Praza 				goto cleanup;
61451f6eb021SLiane Praza 			} else switch (scf_error()) {
61461f6eb021SLiane Praza 			case SCF_ERROR_TEMPLATE_INVALID:
61471f6eb021SLiane Praza 				goto cleanup;
61481f6eb021SLiane Praza 
61491f6eb021SLiane Praza 			case SCF_ERROR_INVALID_ARGUMENT:
61501f6eb021SLiane Praza 			default:
61511f6eb021SLiane Praza 				assert(0);
61521f6eb021SLiane Praza 				abort();
61531f6eb021SLiane Praza 			}
61541f6eb021SLiane Praza 		}
61551f6eb021SLiane Praza 	}
61561f6eb021SLiane Praza 
61571f6eb021SLiane Praza 	if (r < 0) {
61581f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
61591f6eb021SLiane Praza 			goto cleanup;
61601f6eb021SLiane Praza 		} else {
61611f6eb021SLiane Praza 			assert(0);
61621f6eb021SLiane Praza 			abort();
61631f6eb021SLiane Praza 		}
61641f6eb021SLiane Praza 	}
61651f6eb021SLiane Praza 
61661f6eb021SLiane Praza 	ret = 0;
61671f6eb021SLiane Praza 
61681f6eb021SLiane Praza cleanup:
61691f6eb021SLiane Praza 	scf_iter_destroy(iter);
61701f6eb021SLiane Praza 	scf_value_destroy(val);
61711f6eb021SLiane Praza 	return (ret);
61721f6eb021SLiane Praza }
61731f6eb021SLiane Praza 
61741f6eb021SLiane Praza /*
61751f6eb021SLiane Praza  * Returns -1 on failure, sets scf_error() to:
61761f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
61771f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
61781f6eb021SLiane Praza  *   SCF_ERROR_DELETED
61791f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
61801f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
61811f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
61821f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
61831f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
61841f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
61851f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
61861f6eb021SLiane Praza  */
61871f6eb021SLiane Praza static int
61881f6eb021SLiane Praza _check_pg(scf_pg_tmpl_t *t, scf_propertygroup_t *pg, char *pg_name,
61891f6eb021SLiane Praza     char *type, scf_tmpl_errors_t *errs)
61901f6eb021SLiane Praza {
61911f6eb021SLiane Praza 	scf_prop_tmpl_t *pt = NULL;
61921f6eb021SLiane Praza 	char *pg_type = NULL;
61931f6eb021SLiane Praza 	scf_iter_t *iter = NULL;
61941f6eb021SLiane Praza 	uint8_t pg_required;
61951f6eb021SLiane Praza 	scf_property_t *prop = NULL;
61961f6eb021SLiane Praza 	scf_handle_t *h;
61971f6eb021SLiane Praza 	int r;
61981f6eb021SLiane Praza 	char *prop_name = NULL;
61991f6eb021SLiane Praza 	ssize_t nsize = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
62001f6eb021SLiane Praza 	int ret = -1;
62011f6eb021SLiane Praza 
62021f6eb021SLiane Praza 	assert(pg_name != NULL);
62031f6eb021SLiane Praza 	assert(t != NULL);
62041f6eb021SLiane Praza 	assert(pg != NULL);
62051f6eb021SLiane Praza 	assert(type != NULL);
62061f6eb021SLiane Praza 	assert(nsize != 0);
62071f6eb021SLiane Praza 
62081f6eb021SLiane Praza 	if ((h = scf_pg_handle(pg)) == NULL) {
62091f6eb021SLiane Praza 		assert(scf_error() == SCF_ERROR_HANDLE_DESTROYED);
62101f6eb021SLiane Praza 		return (-1);
62111f6eb021SLiane Praza 	}
62121f6eb021SLiane Praza 	if ((pt = scf_tmpl_prop_create(h)) == NULL) {
62131f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_INVALID_ARGUMENT);
62141f6eb021SLiane Praza 		return (-1);
62151f6eb021SLiane Praza 	}
62161f6eb021SLiane Praza 
62171f6eb021SLiane Praza 	if ((prop = scf_property_create(h)) == NULL) {
62181f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_INVALID_ARGUMENT);
62191f6eb021SLiane Praza 		goto cleanup;
62201f6eb021SLiane Praza 	}
62211f6eb021SLiane Praza 
62221f6eb021SLiane Praza 	if ((iter = scf_iter_create(h)) == NULL) {
62231f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_INVALID_ARGUMENT);
62241f6eb021SLiane Praza 		goto cleanup;
62251f6eb021SLiane Praza 	}
62261f6eb021SLiane Praza 	if ((prop_name = malloc(nsize)) == NULL) {
62271f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
62281f6eb021SLiane Praza 		goto cleanup;
62291f6eb021SLiane Praza 	}
62301f6eb021SLiane Praza 
62311f6eb021SLiane Praza 	if (scf_tmpl_pg_required(t, &pg_required) != 0)
62321f6eb021SLiane Praza 		goto cleanup;
62331f6eb021SLiane Praza 
62341f6eb021SLiane Praza 	if (scf_tmpl_pg_type(t, &pg_type) == -1) {
62351f6eb021SLiane Praza 		goto cleanup;
62361f6eb021SLiane Praza 	} else if (pg_required != 0 &&
62371f6eb021SLiane Praza 	    strcmp(SCF_TMPL_WILDCARD, pg_type) == 0) {
62381f6eb021SLiane Praza 		/* Type must be specified for required pgs. */
62391f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
62401f6eb021SLiane Praza 		goto cleanup;
62411f6eb021SLiane Praza 	}
62421f6eb021SLiane Praza 
62431f6eb021SLiane Praza 	if (pg_type != NULL) {
62441f6eb021SLiane Praza 		if (strcmp(pg_type, type) != 0 &&
62451f6eb021SLiane Praza 		    strcmp(pg_type, SCF_TMPL_WILDCARD) != 0) {
62461f6eb021SLiane Praza 			if (_add_tmpl_wrong_pg_type_error(errs, t, pg) == -1)
62471f6eb021SLiane Praza 				goto cleanup;
62481f6eb021SLiane Praza 		}
62491f6eb021SLiane Praza 	}
62501f6eb021SLiane Praza 
62511f6eb021SLiane Praza 
62521f6eb021SLiane Praza 	/* Iterate through properties in the repository and check them. */
62531f6eb021SLiane Praza 	if (scf_iter_pg_properties(iter, pg) != 0) {
62541f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
62551f6eb021SLiane Praza 			goto cleanup;
62561f6eb021SLiane Praza 		} else {
62571f6eb021SLiane Praza 			assert(0);
62581f6eb021SLiane Praza 			abort();
62591f6eb021SLiane Praza 		}
62601f6eb021SLiane Praza 	}
62611f6eb021SLiane Praza 
62621f6eb021SLiane Praza 	while ((r = scf_iter_next_property(iter, prop)) == 1) {
62631f6eb021SLiane Praza 		if (scf_property_get_name(prop, prop_name, nsize) == -1) {
62641f6eb021SLiane Praza 			assert(scf_error() != SCF_ERROR_NOT_SET);
62651f6eb021SLiane Praza 			goto cleanup;
62661f6eb021SLiane Praza 		}
62671f6eb021SLiane Praza 		if (scf_tmpl_get_by_prop(t, prop_name, pt, 0) != 0) {
62681f6eb021SLiane Praza 			if (ismember(scf_error(), errors_server)) {
62691f6eb021SLiane Praza 				goto cleanup;
62701f6eb021SLiane Praza 			} else switch (scf_error()) {
62711f6eb021SLiane Praza 			case SCF_ERROR_NOT_FOUND:
62721f6eb021SLiane Praza 				/* No template.  Continue. */
62731f6eb021SLiane Praza 				continue;
62741f6eb021SLiane Praza 
62751f6eb021SLiane Praza 			case SCF_ERROR_INVALID_ARGUMENT:
62761f6eb021SLiane Praza 			default:
62771f6eb021SLiane Praza 				assert(0);
62781f6eb021SLiane Praza 				abort();
62791f6eb021SLiane Praza 			}
62801f6eb021SLiane Praza 		}
62811f6eb021SLiane Praza 
62821f6eb021SLiane Praza 		if (_check_property(pt, pg, prop, errs) != 0)
62831f6eb021SLiane Praza 			goto cleanup;
62841f6eb021SLiane Praza 	}
62851f6eb021SLiane Praza 
62861f6eb021SLiane Praza 	if (r < 0) {
62871f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
62881f6eb021SLiane Praza 			goto cleanup;
62891f6eb021SLiane Praza 		} else {
62901f6eb021SLiane Praza 			assert(0);
62911f6eb021SLiane Praza 			abort();
62921f6eb021SLiane Praza 		}
62931f6eb021SLiane Praza 	}
62941f6eb021SLiane Praza 
62951f6eb021SLiane Praza 	scf_tmpl_prop_reset(pt);
62961f6eb021SLiane Praza 	free(prop_name);
62971f6eb021SLiane Praza 	prop_name = NULL;
62981f6eb021SLiane Praza 	/*
62991f6eb021SLiane Praza 	 * Confirm required properties are present.
63001f6eb021SLiane Praza 	 */
63011f6eb021SLiane Praza 	while ((r = scf_tmpl_iter_props(t, pt,
63021f6eb021SLiane Praza 	    SCF_PROP_TMPL_FLAG_REQUIRED)) == 0) {
63031f6eb021SLiane Praza 		scf_type_t prop_type;
63041f6eb021SLiane Praza 
63051f6eb021SLiane Praza 		if (scf_tmpl_prop_name(pt, &prop_name) == -1)
63061f6eb021SLiane Praza 			goto cleanup;
63071f6eb021SLiane Praza 
63081f6eb021SLiane Praza 		/* required properties cannot have type wildcarded */
63091f6eb021SLiane Praza 		if (scf_tmpl_prop_type(pt, &prop_type) == -1) {
63101f6eb021SLiane Praza 			if (scf_error() == SCF_ERROR_NOT_FOUND)
63111f6eb021SLiane Praza 				(void) scf_set_error(
63121f6eb021SLiane Praza 				    SCF_ERROR_TEMPLATE_INVALID);
63131f6eb021SLiane Praza 			goto cleanup;
63141f6eb021SLiane Praza 		}
63151f6eb021SLiane Praza 
63161f6eb021SLiane Praza 		if (scf_pg_get_property(pg, prop_name, prop) != 0) {
63171f6eb021SLiane Praza 			if (ismember(scf_error(), errors_server)) {
63181f6eb021SLiane Praza 				goto cleanup;
63191f6eb021SLiane Praza 			} else switch (scf_error()) {
63201f6eb021SLiane Praza 			case SCF_ERROR_NOT_FOUND:
63211f6eb021SLiane Praza 				if (_add_tmpl_missing_prop_error(errs, t, pg,
63221f6eb021SLiane Praza 				    pt) == -1)
63231f6eb021SLiane Praza 					goto cleanup;
63241f6eb021SLiane Praza 				break;
63251f6eb021SLiane Praza 
63261f6eb021SLiane Praza 			case SCF_ERROR_INVALID_ARGUMENT:
63271f6eb021SLiane Praza 				(void) scf_set_error(
63281f6eb021SLiane Praza 				    SCF_ERROR_TEMPLATE_INVALID);
63291f6eb021SLiane Praza 				goto cleanup;
63301f6eb021SLiane Praza 
63311f6eb021SLiane Praza 			case SCF_ERROR_HANDLE_MISMATCH:
63321f6eb021SLiane Praza 			case SCF_ERROR_NOT_SET:
63331f6eb021SLiane Praza 			default:
63341f6eb021SLiane Praza 				assert(0);
63351f6eb021SLiane Praza 				abort();
63361f6eb021SLiane Praza 			}
63371f6eb021SLiane Praza 		}
63381f6eb021SLiane Praza 		free(prop_name);
63391f6eb021SLiane Praza 		prop_name = NULL;
63401f6eb021SLiane Praza 	}
63411f6eb021SLiane Praza 	if (r < 0) {
63421f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
63431f6eb021SLiane Praza 			goto cleanup;
63441f6eb021SLiane Praza 		} else switch (scf_error()) {
63451f6eb021SLiane Praza 		case SCF_ERROR_NOT_FOUND:
63461f6eb021SLiane Praza 			break;
63471f6eb021SLiane Praza 
63481f6eb021SLiane Praza 		case SCF_ERROR_TEMPLATE_INVALID:
63491f6eb021SLiane Praza 			goto cleanup;
63501f6eb021SLiane Praza 
63511f6eb021SLiane Praza 		case SCF_ERROR_INVALID_ARGUMENT:
63521f6eb021SLiane Praza 		default:
63531f6eb021SLiane Praza 			assert(0);
63541f6eb021SLiane Praza 			abort();
63551f6eb021SLiane Praza 		}
63561f6eb021SLiane Praza 	}
63571f6eb021SLiane Praza 
63581f6eb021SLiane Praza 	ret = 0;
63591f6eb021SLiane Praza cleanup:
63601f6eb021SLiane Praza 	scf_tmpl_prop_destroy(pt);
63611f6eb021SLiane Praza 	scf_iter_destroy(iter);
63621f6eb021SLiane Praza 	scf_property_destroy(prop);
63631f6eb021SLiane Praza 	free(prop_name);
63641f6eb021SLiane Praza 	free(pg_type);
63651f6eb021SLiane Praza 	return (ret);
63661f6eb021SLiane Praza }
63671f6eb021SLiane Praza 
63681f6eb021SLiane Praza /*
63691f6eb021SLiane Praza  * Checks if instance fmri redefines any pgs defined in restarter or global
63701f6eb021SLiane Praza  * Return -1 on failure, sets scf_error() to:
63711f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
63721f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
63731f6eb021SLiane Praza  *   SCF_ERROR_DELETED
63741f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
63751f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
63761f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
63771f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
63781f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
63791f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
63801f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
63811f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
63821f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
63831f6eb021SLiane Praza  */
63841f6eb021SLiane Praza static int
63851f6eb021SLiane Praza _scf_tmpl_check_pg_redef(scf_handle_t *h, const char *fmri,
63861f6eb021SLiane Praza     const char *snapname, scf_tmpl_errors_t *errs)
63871f6eb021SLiane Praza {
63881f6eb021SLiane Praza 	scf_pg_tmpl_t *t = NULL;
63891f6eb021SLiane Praza 	scf_pg_tmpl_t *r = NULL;
63901f6eb021SLiane Praza 	char *pg_name = NULL;
63911f6eb021SLiane Praza 	char *pg_name_r = NULL;
63921f6eb021SLiane Praza 	char *pg_type = NULL;
63931f6eb021SLiane Praza 	char *pg_type_r = NULL;
63941f6eb021SLiane Praza 	char *target = NULL;
63951f6eb021SLiane Praza 	int ret_val = -1;
63961f6eb021SLiane Praza 	int ret;
63971f6eb021SLiane Praza 
63981f6eb021SLiane Praza 	t = scf_tmpl_pg_create(h);
63991f6eb021SLiane Praza 	r = scf_tmpl_pg_create(h);
64001f6eb021SLiane Praza 	if (t == NULL || r == NULL)
64011f6eb021SLiane Praza 		goto cleanup;
64021f6eb021SLiane Praza 
64031f6eb021SLiane Praza 	while ((ret = scf_tmpl_iter_pgs(t, fmri, snapname, NULL,
64041f6eb021SLiane Praza 	    SCF_PG_TMPL_FLAG_EXACT)) == 1) {
64051f6eb021SLiane Praza 		if (scf_tmpl_pg_name(t, &pg_name) == -1) {
64061f6eb021SLiane Praza 			goto cleanup;
64071f6eb021SLiane Praza 		}
64081f6eb021SLiane Praza 		if (scf_tmpl_pg_type(t, &pg_type) == -1) {
64091f6eb021SLiane Praza 			goto cleanup;
64101f6eb021SLiane Praza 		}
64111f6eb021SLiane Praza 		/* look for a redefinition of a global/restarter pg_pattern */
64121f6eb021SLiane Praza 		while ((ret = scf_tmpl_iter_pgs(r, fmri, snapname, pg_type,
64131f6eb021SLiane Praza 		    0)) == 1) {
64141f6eb021SLiane Praza 			if (scf_tmpl_pg_name(r, &pg_name_r) == -1) {
64151f6eb021SLiane Praza 				goto cleanup;
64161f6eb021SLiane Praza 			} else if (strcmp(pg_name_r, SCF_TMPL_WILDCARD) != 0 &&
64171f6eb021SLiane Praza 			    strcmp(pg_name, SCF_TMPL_WILDCARD) != 0 &&
64181f6eb021SLiane Praza 			    strcmp(pg_name, pg_name_r) != 0) {
64191f6eb021SLiane Praza 				/* not a match */
64201f6eb021SLiane Praza 				free(pg_name_r);
64211f6eb021SLiane Praza 				pg_name_r = NULL;
64221f6eb021SLiane Praza 				continue;
64231f6eb021SLiane Praza 			}
64241f6eb021SLiane Praza 			if (scf_tmpl_pg_type(r, &pg_type_r) == -1) {
64251f6eb021SLiane Praza 				goto cleanup;
64261f6eb021SLiane Praza 			} else if (strcmp(pg_type_r, SCF_TMPL_WILDCARD) != 0 &&
64271f6eb021SLiane Praza 			    strcmp(pg_type, SCF_TMPL_WILDCARD) != 0 &&
64281f6eb021SLiane Praza 			    strcmp(pg_type, pg_type_r) != 0) {
64291f6eb021SLiane Praza 				/* not a match */
64301f6eb021SLiane Praza 				free(pg_name_r);
64311f6eb021SLiane Praza 				pg_name_r = NULL;
64321f6eb021SLiane Praza 				free(pg_type_r);
64331f6eb021SLiane Praza 				pg_type_r = NULL;
64341f6eb021SLiane Praza 				continue;
64351f6eb021SLiane Praza 			}
64361f6eb021SLiane Praza 			if (scf_tmpl_pg_target(r, &target) == -1) {
64371f6eb021SLiane Praza 				target = NULL;
64381f6eb021SLiane Praza 				goto cleanup;
64391f6eb021SLiane Praza 			}
64401f6eb021SLiane Praza 			if (strcmp(target, SCF_TM_TARGET_ALL) == 0 ||
64411f6eb021SLiane Praza 			    strcmp(target, SCF_TM_TARGET_DELEGATE) == 0) {
64421f6eb021SLiane Praza 				/* found a pg_pattern redefinition */
64431f6eb021SLiane Praza 				if (_add_tmpl_pg_redefine_error(errs, t,
64441f6eb021SLiane Praza 				    r) == -1)
64451f6eb021SLiane Praza 					goto cleanup;
64461f6eb021SLiane Praza 				free(pg_name_r);
64471f6eb021SLiane Praza 				pg_name_r = NULL;
644876fa7285SAntonello Cruz 				free(pg_type_r);
644976fa7285SAntonello Cruz 				pg_type_r = NULL;
64501f6eb021SLiane Praza 				free(target);
64511f6eb021SLiane Praza 				target = NULL;
64521f6eb021SLiane Praza 				break;
64531f6eb021SLiane Praza 			}
64541f6eb021SLiane Praza 			free(pg_name_r);
64551f6eb021SLiane Praza 			pg_name_r = NULL;
645676fa7285SAntonello Cruz 			free(pg_type_r);
645776fa7285SAntonello Cruz 			pg_type_r = NULL;
64581f6eb021SLiane Praza 			free(target);
64591f6eb021SLiane Praza 			target = NULL;
64601f6eb021SLiane Praza 		}
64611f6eb021SLiane Praza 		if (ret == -1)
64621f6eb021SLiane Praza 			goto cleanup;
64631f6eb021SLiane Praza 		scf_tmpl_pg_reset(r);
64641f6eb021SLiane Praza 
64651f6eb021SLiane Praza 		free(pg_name);
64661f6eb021SLiane Praza 		free(pg_type);
64671f6eb021SLiane Praza 		pg_name = NULL;
64681f6eb021SLiane Praza 		pg_type = NULL;
64691f6eb021SLiane Praza 	}
64701f6eb021SLiane Praza 	if (ret == -1)
64711f6eb021SLiane Praza 		goto cleanup;
64721f6eb021SLiane Praza 
64731f6eb021SLiane Praza 	ret_val = 0;
64741f6eb021SLiane Praza 
64751f6eb021SLiane Praza cleanup:
64761f6eb021SLiane Praza 	scf_tmpl_pg_destroy(t);
64771f6eb021SLiane Praza 	scf_tmpl_pg_destroy(r);
64781f6eb021SLiane Praza 	free(pg_name);
64791f6eb021SLiane Praza 	free(pg_type);
64801f6eb021SLiane Praza 	free(pg_name_r);
64811f6eb021SLiane Praza 	free(pg_type_r);
64821f6eb021SLiane Praza 	free(target);
64831f6eb021SLiane Praza 
64841f6eb021SLiane Praza 	if (ret_val == -1) {
64851f6eb021SLiane Praza 		if (!ismember(scf_error(), errors_server)) {
64861f6eb021SLiane Praza 			switch (scf_error()) {
64871f6eb021SLiane Praza 			case SCF_ERROR_TYPE_MISMATCH:
64881f6eb021SLiane Praza 				(void) scf_set_error(
64891f6eb021SLiane Praza 				    SCF_ERROR_TEMPLATE_INVALID);
64901f6eb021SLiane Praza 				/*FALLTHROUGH*/
64911f6eb021SLiane Praza 
64921f6eb021SLiane Praza 			case SCF_ERROR_CONSTRAINT_VIOLATED:
64931f6eb021SLiane Praza 			case SCF_ERROR_INVALID_ARGUMENT:
64941f6eb021SLiane Praza 			case SCF_ERROR_NOT_FOUND:
64951f6eb021SLiane Praza 			case SCF_ERROR_TEMPLATE_INVALID:
64961f6eb021SLiane Praza 				break;
64971f6eb021SLiane Praza 
64981f6eb021SLiane Praza 			case SCF_ERROR_HANDLE_MISMATCH:
64991f6eb021SLiane Praza 			case SCF_ERROR_NOT_SET:
65001f6eb021SLiane Praza 			default:
65011f6eb021SLiane Praza 				assert(0);
65021f6eb021SLiane Praza 				abort();
65031f6eb021SLiane Praza 			}
65041f6eb021SLiane Praza 		}
65051f6eb021SLiane Praza 	}
65061f6eb021SLiane Praza 	return (ret_val);
65071f6eb021SLiane Praza }
65081f6eb021SLiane Praza 
65091f6eb021SLiane Praza /*
65101f6eb021SLiane Praza  * Returns -1 on failure, sets scf_error() to:
65111f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
65121f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
65131f6eb021SLiane Praza  *   SCF_ERROR_DELETED
65141f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
65151f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
65161f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
65171f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
65181f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
65191f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
65201f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
65211f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
65221f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
65231f6eb021SLiane Praza  */
65241f6eb021SLiane Praza int
65251f6eb021SLiane Praza scf_tmpl_validate_fmri(scf_handle_t *h, const char *fmri, const char *snapshot,
65261f6eb021SLiane Praza     scf_tmpl_errors_t **errs, int flags)
65271f6eb021SLiane Praza {
65281f6eb021SLiane Praza 	scf_pg_tmpl_t *t = NULL;
65291f6eb021SLiane Praza 	scf_iter_t *iter = NULL;
65301f6eb021SLiane Praza 	scf_propertygroup_t *pg = NULL;
65311f6eb021SLiane Praza 	scf_instance_t *inst = NULL;
65321f6eb021SLiane Praza 	scf_snapshot_t *snap = NULL;
65331f6eb021SLiane Praza 	char *type = NULL;
65341f6eb021SLiane Praza 	char *pg_name = NULL;
65351f6eb021SLiane Praza 	ssize_t rsize = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH) + 1;
65361f6eb021SLiane Praza 	ssize_t nsize = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
65371f6eb021SLiane Praza 	int ret = -1;
65381f6eb021SLiane Praza 	int r;
65391f6eb021SLiane Praza 
65401f6eb021SLiane Praza 	assert(errs != NULL);
65411f6eb021SLiane Praza 
65421f6eb021SLiane Praza 	if ((*errs = _scf_create_errors(fmri, 1)) == NULL)
65431f6eb021SLiane Praza 		return (-1);
65441f6eb021SLiane Praza 
65451f6eb021SLiane Praza 	if ((pg = scf_pg_create(h)) == NULL ||
65461f6eb021SLiane Praza 	    (iter = scf_iter_create(h)) == NULL ||
65471f6eb021SLiane Praza 	    (inst = scf_instance_create(h)) == NULL ||
65481f6eb021SLiane Praza 	    (t = scf_tmpl_pg_create(h)) == NULL) {
65491f6eb021SLiane Praza 		/*
65501f6eb021SLiane Praza 		 * Sets SCF_ERROR_INVALID_ARGUMENT, SCF_ERROR_NO_MEMORY,
65511f6eb021SLiane Praza 		 * SCF_ERROR_NO_RESOURCES, SCF_ERROR_INTERNAL or
65521f6eb021SLiane Praza 		 * SCF_ERROR_HANDLE_DESTROYED.
65531f6eb021SLiane Praza 		 */
65541f6eb021SLiane Praza 		goto cleanup;
65551f6eb021SLiane Praza 	}
65561f6eb021SLiane Praza 
65571f6eb021SLiane Praza 	if ((type = malloc(rsize)) == NULL ||
65581f6eb021SLiane Praza 	    (pg_name = malloc(nsize)) == NULL) {
65591f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
65601f6eb021SLiane Praza 		goto cleanup;
65611f6eb021SLiane Praza 	}
65621f6eb021SLiane Praza 
65631f6eb021SLiane Praza 	if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL, NULL,
65641f6eb021SLiane Praza 	    SCF_DECODE_FMRI_EXACT|SCF_DECODE_FMRI_REQUIRE_INSTANCE) != 0) {
65651f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
65661f6eb021SLiane Praza 			goto cleanup;
65671f6eb021SLiane Praza 		} else switch (scf_error()) {
65681f6eb021SLiane Praza 		case SCF_ERROR_CONSTRAINT_VIOLATED:
65691f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
65701f6eb021SLiane Praza 			/*FALLTHROUGH*/
65711f6eb021SLiane Praza 
65721f6eb021SLiane Praza 		case SCF_ERROR_INVALID_ARGUMENT:
65731f6eb021SLiane Praza 		case SCF_ERROR_NOT_FOUND:
65741f6eb021SLiane Praza 			goto cleanup;
65751f6eb021SLiane Praza 
65761f6eb021SLiane Praza 		case SCF_ERROR_HANDLE_MISMATCH:
65771f6eb021SLiane Praza 		case SCF_ERROR_NOT_SET:
65781f6eb021SLiane Praza 		default:
65791f6eb021SLiane Praza 			assert(0);
65801f6eb021SLiane Praza 			abort();
65811f6eb021SLiane Praza 		}
65821f6eb021SLiane Praza 	}
65831f6eb021SLiane Praza 
65841f6eb021SLiane Praza 	if (snapshot == NULL || strcmp(snapshot, "running") == 0 ||
65851f6eb021SLiane Praza 	    (flags & SCF_TMPL_VALIDATE_FLAG_CURRENT)) {
65861f6eb021SLiane Praza 		if (_get_snapshot(inst, NULL, &snap) == -1)
65871f6eb021SLiane Praza 			goto cleanup;
65881f6eb021SLiane Praza 	} else {
65891f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NONE);
65901f6eb021SLiane Praza 		if (_get_snapshot(inst, snapshot, &snap) == -1) {
65911f6eb021SLiane Praza 			goto cleanup;
65921f6eb021SLiane Praza 		} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
65931f6eb021SLiane Praza 			goto cleanup;
65941f6eb021SLiane Praza 		}
65951f6eb021SLiane Praza 	}
65961f6eb021SLiane Praza 	if (_scf_tmpl_check_pg_redef(h, fmri, snapshot, *errs) != 0) {
65971f6eb021SLiane Praza 		goto cleanup;
65981f6eb021SLiane Praza 	}
65991f6eb021SLiane Praza 
66001f6eb021SLiane Praza 	/*
66011f6eb021SLiane Praza 	 * Check that property groups on this instance conform to the template.
66021f6eb021SLiane Praza 	 */
66031f6eb021SLiane Praza 	if (scf_iter_instance_pgs_composed(iter, inst, snap) != 0) {
66041f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
66051f6eb021SLiane Praza 			goto cleanup;
66061f6eb021SLiane Praza 		} else {
66071f6eb021SLiane Praza 			assert(0);
66081f6eb021SLiane Praza 			abort();
66091f6eb021SLiane Praza 		}
66101f6eb021SLiane Praza 	}
66111f6eb021SLiane Praza 
66121f6eb021SLiane Praza 	while ((r = scf_iter_next_pg(iter, pg)) == 1) {
66131f6eb021SLiane Praza 		if (scf_pg_get_name(pg, pg_name, nsize) == -1) {
66141f6eb021SLiane Praza 			if (ismember(scf_error(), errors_server)) {
66151f6eb021SLiane Praza 				goto cleanup;
66161f6eb021SLiane Praza 			} else {
66171f6eb021SLiane Praza 				assert(0);
66181f6eb021SLiane Praza 				abort();
66191f6eb021SLiane Praza 			}
66201f6eb021SLiane Praza 		}
66211f6eb021SLiane Praza 
66221f6eb021SLiane Praza 		if (scf_pg_get_type(pg, type, rsize) == -1) {
66231f6eb021SLiane Praza 			if (ismember(scf_error(), errors_server)) {
66241f6eb021SLiane Praza 				goto cleanup;
66251f6eb021SLiane Praza 			} else {
66261f6eb021SLiane Praza 				assert(0);
66271f6eb021SLiane Praza 				abort();
66281f6eb021SLiane Praza 			}
66291f6eb021SLiane Praza 		}
66301f6eb021SLiane Praza 
66311f6eb021SLiane Praza 		if (scf_tmpl_get_by_pg_name(fmri, snapshot, pg_name, type, t,
66321f6eb021SLiane Praza 		    0) != 0) {
66331f6eb021SLiane Praza 			if (ismember(scf_error(), errors_server)) {
66341f6eb021SLiane Praza 				goto cleanup;
66351f6eb021SLiane Praza 			} else switch (scf_error()) {
66361f6eb021SLiane Praza 			case SCF_ERROR_NOT_FOUND:
66371f6eb021SLiane Praza 				continue;
66381f6eb021SLiane Praza 
66391f6eb021SLiane Praza 			case SCF_ERROR_INVALID_ARGUMENT:
66401f6eb021SLiane Praza 				goto cleanup;
66411f6eb021SLiane Praza 
66421f6eb021SLiane Praza 			default:
66431f6eb021SLiane Praza 				assert(0);
66441f6eb021SLiane Praza 				abort();
66451f6eb021SLiane Praza 			}
66461f6eb021SLiane Praza 		}
66471f6eb021SLiane Praza 
66481f6eb021SLiane Praza 		if (_check_pg(t, pg, pg_name, type, *errs) != 0)
66491f6eb021SLiane Praza 			goto cleanup;
66501f6eb021SLiane Praza 	}
66511f6eb021SLiane Praza 	if (r < 0) {
66521f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
66531f6eb021SLiane Praza 			goto cleanup;
66541f6eb021SLiane Praza 		} else {
66551f6eb021SLiane Praza 			assert(0);
66561f6eb021SLiane Praza 			abort();
66571f6eb021SLiane Praza 		}
66581f6eb021SLiane Praza 	}
66591f6eb021SLiane Praza 
66601f6eb021SLiane Praza 	scf_tmpl_pg_reset(t);
66611f6eb021SLiane Praza 
66621f6eb021SLiane Praza 	/*
66631f6eb021SLiane Praza 	 * Confirm required property groups are present.
66641f6eb021SLiane Praza 	 */
66651f6eb021SLiane Praza 	while ((r = scf_tmpl_iter_pgs(t, fmri, snapshot, NULL,
66661f6eb021SLiane Praza 	    SCF_PG_TMPL_FLAG_REQUIRED)) == 1) {
66671f6eb021SLiane Praza 		free(pg_name);
66681f6eb021SLiane Praza 		free(type);
66691f6eb021SLiane Praza 
66701f6eb021SLiane Praza 		if (scf_tmpl_pg_name(t, &pg_name) == -1)
66711f6eb021SLiane Praza 			goto cleanup;
66721f6eb021SLiane Praza 		if (scf_tmpl_pg_type(t, &type) == -1)
66731f6eb021SLiane Praza 			goto cleanup;
66741f6eb021SLiane Praza 		/*
66751f6eb021SLiane Praza 		 * required property group templates should not have
66761f6eb021SLiane Praza 		 * wildcarded name or type
66771f6eb021SLiane Praza 		 */
66781f6eb021SLiane Praza 		if (strcmp(pg_name, SCF_TMPL_WILDCARD) == 0 ||
66791f6eb021SLiane Praza 		    strcmp(type, SCF_TMPL_WILDCARD) == 0) {
66801f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
66811f6eb021SLiane Praza 			goto cleanup;
66821f6eb021SLiane Praza 		}
66831f6eb021SLiane Praza 
66841f6eb021SLiane Praza 		if (_get_pg(NULL, inst, snap, pg_name, pg) != 0) {
66851f6eb021SLiane Praza 			if (ismember(scf_error(), errors_server)) {
66861f6eb021SLiane Praza 				goto cleanup;
66871f6eb021SLiane Praza 			} else switch (scf_error()) {
66881f6eb021SLiane Praza 			case SCF_ERROR_NOT_FOUND:
66891f6eb021SLiane Praza 				if (_add_tmpl_missing_pg_error(*errs, t) == -1)
66901f6eb021SLiane Praza 					goto cleanup;
66911f6eb021SLiane Praza 				continue;
66921f6eb021SLiane Praza 
66931f6eb021SLiane Praza 			case SCF_ERROR_INVALID_ARGUMENT:
66941f6eb021SLiane Praza 			case SCF_ERROR_HANDLE_MISMATCH:
66951f6eb021SLiane Praza 			case SCF_ERROR_NOT_SET:
66961f6eb021SLiane Praza 			default:
66971f6eb021SLiane Praza 				assert(0);
66981f6eb021SLiane Praza 				abort();
66991f6eb021SLiane Praza 			}
67001f6eb021SLiane Praza 		}
67011f6eb021SLiane Praza 	}
67021f6eb021SLiane Praza 	if (r < 0) {
67031f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
67041f6eb021SLiane Praza 			goto cleanup;
67051f6eb021SLiane Praza 		} else switch (scf_error()) {
67061f6eb021SLiane Praza 		case SCF_ERROR_NOT_FOUND:
67071f6eb021SLiane Praza 			break;
67081f6eb021SLiane Praza 
67091f6eb021SLiane Praza 		case SCF_ERROR_INVALID_ARGUMENT:
67101f6eb021SLiane Praza 			goto cleanup;
67111f6eb021SLiane Praza 
67121f6eb021SLiane Praza 		default:
67131f6eb021SLiane Praza 			assert(0);
67141f6eb021SLiane Praza 			abort();
67151f6eb021SLiane Praza 		}
67161f6eb021SLiane Praza 	}
67171f6eb021SLiane Praza 
67181f6eb021SLiane Praza 	ret = 0;
67191f6eb021SLiane Praza 	if ((*errs)->tes_num_errs > 0)
67201f6eb021SLiane Praza 		ret = 1;
67211f6eb021SLiane Praza cleanup:
67221f6eb021SLiane Praza 	if (ret != 1) {
67231f6eb021SLiane Praza 		/* there are no errors to report */
67241f6eb021SLiane Praza 		scf_tmpl_errors_destroy(*errs);
67251f6eb021SLiane Praza 		*errs = NULL;
67261f6eb021SLiane Praza 	}
67271f6eb021SLiane Praza 	scf_tmpl_pg_destroy(t);
67281f6eb021SLiane Praza 	free(type);
67291f6eb021SLiane Praza 	free(pg_name);
67301f6eb021SLiane Praza 
67311f6eb021SLiane Praza 	scf_iter_destroy(iter);
67321f6eb021SLiane Praza 	scf_pg_destroy(pg);
67331f6eb021SLiane Praza 	scf_instance_destroy(inst);
67341f6eb021SLiane Praza 	scf_snapshot_destroy(snap);
67351f6eb021SLiane Praza 
67361f6eb021SLiane Praza 	return (ret);
67371f6eb021SLiane Praza }
67381f6eb021SLiane Praza 
67391f6eb021SLiane Praza void
67401f6eb021SLiane Praza scf_tmpl_errors_destroy(scf_tmpl_errors_t *errs)
67411f6eb021SLiane Praza {
67421f6eb021SLiane Praza 	int i;
67431f6eb021SLiane Praza 	scf_tmpl_error_t *e;
67441f6eb021SLiane Praza 
67451f6eb021SLiane Praza 	if (errs == NULL)
67461f6eb021SLiane Praza 		return;
67471f6eb021SLiane Praza 
67481f6eb021SLiane Praza 	for (i = 0; i < errs->tes_num_errs; ++i) {
67491f6eb021SLiane Praza 		e = errs->tes_errs[i];
67501f6eb021SLiane Praza 		if (errs->tes_flag != 0) {
67511f6eb021SLiane Praza 			free((char *)e->te_pg_name);
67521f6eb021SLiane Praza 			free((char *)e->te_prop_name);
67531f6eb021SLiane Praza 			free((char *)e->te_ev1);
67541f6eb021SLiane Praza 			free((char *)e->te_ev2);
67551f6eb021SLiane Praza 			free((char *)e->te_actual);
67561f6eb021SLiane Praza 			free((char *)e->te_tmpl_fmri);
67571f6eb021SLiane Praza 			free((char *)e->te_tmpl_pg_name);
67581f6eb021SLiane Praza 			free((char *)e->te_tmpl_pg_type);
67591f6eb021SLiane Praza 			free((char *)e->te_tmpl_prop_name);
67601f6eb021SLiane Praza 			free((char *)e->te_tmpl_prop_type);
67611f6eb021SLiane Praza 		}
67621f6eb021SLiane Praza 		free(e);
67631f6eb021SLiane Praza 	}
67641f6eb021SLiane Praza 	free((char *)errs->tes_fmri);
67651f6eb021SLiane Praza 	free((char *)errs->tes_prefix);
67661f6eb021SLiane Praza 	free(errs->tes_errs);
67671f6eb021SLiane Praza 	free(errs);
67681f6eb021SLiane Praza }
67691f6eb021SLiane Praza 
67701f6eb021SLiane Praza int
67711f6eb021SLiane Praza scf_tmpl_error_source_fmri(const scf_tmpl_error_t *err, char **fmri)
67721f6eb021SLiane Praza {
67731f6eb021SLiane Praza 	assert(err != NULL);
67741f6eb021SLiane Praza 	switch (err->te_type) {
67751f6eb021SLiane Praza 	case SCF_TERR_MISSING_PG:
67761f6eb021SLiane Praza 	case SCF_TERR_WRONG_PG_TYPE:
67771f6eb021SLiane Praza 	case SCF_TERR_MISSING_PROP:
67781f6eb021SLiane Praza 	case SCF_TERR_WRONG_PROP_TYPE:
67791f6eb021SLiane Praza 	case SCF_TERR_CARDINALITY_VIOLATION:
67801f6eb021SLiane Praza 	case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
67811f6eb021SLiane Praza 	case SCF_TERR_RANGE_VIOLATION:
67821f6eb021SLiane Praza 	case SCF_TERR_PROP_TYPE_MISMATCH:
67831f6eb021SLiane Praza 	case SCF_TERR_VALUE_OUT_OF_RANGE:
67841f6eb021SLiane Praza 	case SCF_TERR_INVALID_VALUE:
67851f6eb021SLiane Praza 	case SCF_TERR_PG_REDEFINE:
67861f6eb021SLiane Praza 		*fmri = (char *)err->te_tmpl_fmri;
67871f6eb021SLiane Praza 		return (0);
67881f6eb021SLiane Praza 		/*NOTREACHED*/
67891f6eb021SLiane Praza 	default:
67901f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
67911f6eb021SLiane Praza 	}
67921f6eb021SLiane Praza 	return (-1);
67931f6eb021SLiane Praza }
67941f6eb021SLiane Praza 
67951f6eb021SLiane Praza int
67961f6eb021SLiane Praza scf_tmpl_error_type(const scf_tmpl_error_t *err, scf_tmpl_error_type_t *type)
67971f6eb021SLiane Praza {
67981f6eb021SLiane Praza 	assert(err != NULL);
67991f6eb021SLiane Praza 	switch (err->te_type) {
68001f6eb021SLiane Praza 	case SCF_TERR_MISSING_PG:
68011f6eb021SLiane Praza 	case SCF_TERR_WRONG_PG_TYPE:
68021f6eb021SLiane Praza 	case SCF_TERR_MISSING_PROP:
68031f6eb021SLiane Praza 	case SCF_TERR_WRONG_PROP_TYPE:
68041f6eb021SLiane Praza 	case SCF_TERR_CARDINALITY_VIOLATION:
68051f6eb021SLiane Praza 	case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
68061f6eb021SLiane Praza 	case SCF_TERR_RANGE_VIOLATION:
68071f6eb021SLiane Praza 	case SCF_TERR_PROP_TYPE_MISMATCH:
68081f6eb021SLiane Praza 	case SCF_TERR_VALUE_OUT_OF_RANGE:
68091f6eb021SLiane Praza 	case SCF_TERR_INVALID_VALUE:
68101f6eb021SLiane Praza 	case SCF_TERR_PG_REDEFINE:
68111f6eb021SLiane Praza 		*type = err->te_type;
68121f6eb021SLiane Praza 		return (0);
68131f6eb021SLiane Praza 		/*NOTREACHED*/
68141f6eb021SLiane Praza 	default:
68151f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
68161f6eb021SLiane Praza 	}
68171f6eb021SLiane Praza 	return (-1);
68181f6eb021SLiane Praza }
68191f6eb021SLiane Praza 
68201f6eb021SLiane Praza int
68211f6eb021SLiane Praza scf_tmpl_error_pg_tmpl(const scf_tmpl_error_t *err, char **name, char **type)
68221f6eb021SLiane Praza {
68231f6eb021SLiane Praza 	assert(err != NULL);
68241f6eb021SLiane Praza 	switch (err->te_type) {
68251f6eb021SLiane Praza 	case SCF_TERR_MISSING_PG:
68261f6eb021SLiane Praza 	case SCF_TERR_WRONG_PG_TYPE:
68271f6eb021SLiane Praza 	case SCF_TERR_MISSING_PROP:
68281f6eb021SLiane Praza 	case SCF_TERR_WRONG_PROP_TYPE:
68291f6eb021SLiane Praza 	case SCF_TERR_CARDINALITY_VIOLATION:
68301f6eb021SLiane Praza 	case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
68311f6eb021SLiane Praza 	case SCF_TERR_RANGE_VIOLATION:
68321f6eb021SLiane Praza 	case SCF_TERR_PROP_TYPE_MISMATCH:
68331f6eb021SLiane Praza 	case SCF_TERR_VALUE_OUT_OF_RANGE:
68341f6eb021SLiane Praza 	case SCF_TERR_INVALID_VALUE:
68351f6eb021SLiane Praza 	case SCF_TERR_PG_REDEFINE:
68361f6eb021SLiane Praza 		if (err->te_tmpl_pg_name != NULL &&
68371f6eb021SLiane Praza 		    err->te_tmpl_pg_type != NULL) {
68381f6eb021SLiane Praza 			if (name != NULL)
68391f6eb021SLiane Praza 				*name = (char *)err->te_tmpl_pg_name;
68401f6eb021SLiane Praza 			if (type != NULL)
68411f6eb021SLiane Praza 				*type = (char *)err->te_tmpl_pg_type;
68421f6eb021SLiane Praza 			return (0);
68431f6eb021SLiane Praza 		}
68441f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NOT_FOUND);
68451f6eb021SLiane Praza 		break;
68461f6eb021SLiane Praza 	default:
68471f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
68481f6eb021SLiane Praza 	}
68491f6eb021SLiane Praza 	return (-1);
68501f6eb021SLiane Praza }
68511f6eb021SLiane Praza 
68521f6eb021SLiane Praza int
68531f6eb021SLiane Praza scf_tmpl_error_pg(const scf_tmpl_error_t *err, char **name, char **type)
68541f6eb021SLiane Praza {
68551f6eb021SLiane Praza 	assert(err != NULL);
68561f6eb021SLiane Praza 	switch (err->te_type) {
68571f6eb021SLiane Praza 	case SCF_TERR_WRONG_PG_TYPE:
68581f6eb021SLiane Praza 		if (err->te_pg_name != NULL &&
68591f6eb021SLiane Praza 		    err->te_actual != NULL) {
68601f6eb021SLiane Praza 			if (name != NULL)
68611f6eb021SLiane Praza 				*name = (char *)err->te_pg_name;
68621f6eb021SLiane Praza 			if (type != NULL)
68631f6eb021SLiane Praza 				*type = (char *)err->te_actual;
68641f6eb021SLiane Praza 			return (0);
68651f6eb021SLiane Praza 		}
68661f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NOT_FOUND);
68671f6eb021SLiane Praza 		break;
68681f6eb021SLiane Praza 	case SCF_TERR_WRONG_PROP_TYPE:
68691f6eb021SLiane Praza 	case SCF_TERR_CARDINALITY_VIOLATION:
68701f6eb021SLiane Praza 	case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
68711f6eb021SLiane Praza 	case SCF_TERR_RANGE_VIOLATION:
68721f6eb021SLiane Praza 		if (err->te_pg_name != NULL &&
68731f6eb021SLiane Praza 		    err->te_tmpl_pg_type != NULL) {
68741f6eb021SLiane Praza 			if (name != NULL)
68751f6eb021SLiane Praza 				*name = (char *)err->te_pg_name;
68761f6eb021SLiane Praza 			if (type != NULL)
68771f6eb021SLiane Praza 				*type = (char *)err->te_tmpl_pg_type;
68781f6eb021SLiane Praza 			return (0);
68791f6eb021SLiane Praza 		}
68801f6eb021SLiane Praza 		/*FALLTHROUGH*/
68811f6eb021SLiane Praza 	case SCF_TERR_MISSING_PROP:
68821f6eb021SLiane Praza 	case SCF_TERR_MISSING_PG:
68831f6eb021SLiane Praza 	case SCF_TERR_PROP_TYPE_MISMATCH:
68841f6eb021SLiane Praza 	case SCF_TERR_VALUE_OUT_OF_RANGE:
68851f6eb021SLiane Praza 	case SCF_TERR_INVALID_VALUE:
68861f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NOT_FOUND);
68871f6eb021SLiane Praza 		break;
68881f6eb021SLiane Praza 	case SCF_TERR_PG_REDEFINE:
68891f6eb021SLiane Praza 		if (err->te_ev1 != NULL && err->te_ev2 != NULL) {
68901f6eb021SLiane Praza 			if (name != NULL)
68911f6eb021SLiane Praza 				*name = (char *)err->te_ev1;
68921f6eb021SLiane Praza 			if (type != NULL)
68931f6eb021SLiane Praza 				*type = (char *)err->te_ev2;
68941f6eb021SLiane Praza 			return (0);
68951f6eb021SLiane Praza 		}
68961f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NOT_FOUND);
68971f6eb021SLiane Praza 		break;
68981f6eb021SLiane Praza 	default:
68991f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
69001f6eb021SLiane Praza 	}
69011f6eb021SLiane Praza 	return (-1);
69021f6eb021SLiane Praza }
69031f6eb021SLiane Praza 
69041f6eb021SLiane Praza int
69051f6eb021SLiane Praza scf_tmpl_error_prop_tmpl(const scf_tmpl_error_t *err, char **name, char **type)
69061f6eb021SLiane Praza {
69071f6eb021SLiane Praza 	assert(err != NULL);
69081f6eb021SLiane Praza 	switch (err->te_type) {
69091f6eb021SLiane Praza 	case SCF_TERR_MISSING_PROP:
69101f6eb021SLiane Praza 	case SCF_TERR_WRONG_PROP_TYPE:
69111f6eb021SLiane Praza 	case SCF_TERR_CARDINALITY_VIOLATION:
69121f6eb021SLiane Praza 	case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
69131f6eb021SLiane Praza 	case SCF_TERR_RANGE_VIOLATION:
69141f6eb021SLiane Praza 	case SCF_TERR_PROP_TYPE_MISMATCH:
69151f6eb021SLiane Praza 	case SCF_TERR_VALUE_OUT_OF_RANGE:
69161f6eb021SLiane Praza 	case SCF_TERR_INVALID_VALUE:
69171f6eb021SLiane Praza 		if (err->te_tmpl_prop_name != NULL &&
69181f6eb021SLiane Praza 		    err->te_tmpl_prop_type != NULL) {
69191f6eb021SLiane Praza 			if (name != NULL)
69201f6eb021SLiane Praza 				*name = (char *)err->te_tmpl_prop_name;
69211f6eb021SLiane Praza 			if (type != NULL)
69221f6eb021SLiane Praza 				*type = (char *)err->te_tmpl_prop_type;
69231f6eb021SLiane Praza 			return (0);
69241f6eb021SLiane Praza 		}
69251f6eb021SLiane Praza 		/*FALLTHROUGH*/
69261f6eb021SLiane Praza 	case SCF_TERR_MISSING_PG:
69271f6eb021SLiane Praza 	case SCF_TERR_WRONG_PG_TYPE:
69281f6eb021SLiane Praza 	case SCF_TERR_PG_REDEFINE:
69291f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NOT_FOUND);
69301f6eb021SLiane Praza 		break;
69311f6eb021SLiane Praza 	default:
69321f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
69331f6eb021SLiane Praza 	}
69341f6eb021SLiane Praza 	return (-1);
69351f6eb021SLiane Praza }
69361f6eb021SLiane Praza 
69371f6eb021SLiane Praza int
69381f6eb021SLiane Praza scf_tmpl_error_prop(const scf_tmpl_error_t *err, char **name, char **type)
69391f6eb021SLiane Praza {
69401f6eb021SLiane Praza 	assert(err != NULL);
69411f6eb021SLiane Praza 	switch (err->te_type) {
69421f6eb021SLiane Praza 	case SCF_TERR_WRONG_PROP_TYPE:
69431f6eb021SLiane Praza 	case SCF_TERR_CARDINALITY_VIOLATION:
69441f6eb021SLiane Praza 	case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
69451f6eb021SLiane Praza 	case SCF_TERR_RANGE_VIOLATION:
69461f6eb021SLiane Praza 		if (err->te_prop_name != NULL &&
69471f6eb021SLiane Praza 		    err->te_tmpl_prop_type != NULL) {
69481f6eb021SLiane Praza 			if (name != NULL)
69491f6eb021SLiane Praza 				*name = (char *)err->te_prop_name;
69501f6eb021SLiane Praza 			if (type != NULL)
69511f6eb021SLiane Praza 				*type = (char *)err->te_tmpl_prop_type;
69521f6eb021SLiane Praza 			return (0);
69531f6eb021SLiane Praza 		}
69541f6eb021SLiane Praza 		/*FALLTHROUGH*/
69551f6eb021SLiane Praza 	case SCF_TERR_MISSING_PG:
69561f6eb021SLiane Praza 	case SCF_TERR_WRONG_PG_TYPE:
69571f6eb021SLiane Praza 	case SCF_TERR_MISSING_PROP:
69581f6eb021SLiane Praza 	case SCF_TERR_PROP_TYPE_MISMATCH:
69591f6eb021SLiane Praza 	case SCF_TERR_VALUE_OUT_OF_RANGE:
69601f6eb021SLiane Praza 	case SCF_TERR_INVALID_VALUE:
69611f6eb021SLiane Praza 	case SCF_TERR_PG_REDEFINE:
69621f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NOT_FOUND);
69631f6eb021SLiane Praza 		break;
69641f6eb021SLiane Praza 	default:
69651f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
69661f6eb021SLiane Praza 	}
69671f6eb021SLiane Praza 	return (-1);
69681f6eb021SLiane Praza }
69691f6eb021SLiane Praza 
69701f6eb021SLiane Praza int
69711f6eb021SLiane Praza scf_tmpl_error_value(const scf_tmpl_error_t *err, char **val)
69721f6eb021SLiane Praza {
69731f6eb021SLiane Praza 	assert(err != NULL);
69741f6eb021SLiane Praza 	switch (err->te_type) {
69751f6eb021SLiane Praza 	case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
69761f6eb021SLiane Praza 	case SCF_TERR_RANGE_VIOLATION:
69771f6eb021SLiane Praza 	case SCF_TERR_VALUE_OUT_OF_RANGE:
69781f6eb021SLiane Praza 	case SCF_TERR_INVALID_VALUE:
69791f6eb021SLiane Praza 		if (err->te_actual != NULL) {
69801f6eb021SLiane Praza 			if (val != NULL)
69811f6eb021SLiane Praza 				*val = (char *)err->te_actual;
69821f6eb021SLiane Praza 			return (0);
69831f6eb021SLiane Praza 		}
69841f6eb021SLiane Praza 		/*FALLTHROUGH*/
69851f6eb021SLiane Praza 	case SCF_TERR_MISSING_PG:
69861f6eb021SLiane Praza 	case SCF_TERR_WRONG_PG_TYPE:
69871f6eb021SLiane Praza 	case SCF_TERR_MISSING_PROP:
69881f6eb021SLiane Praza 	case SCF_TERR_WRONG_PROP_TYPE:
69891f6eb021SLiane Praza 	case SCF_TERR_CARDINALITY_VIOLATION:
69901f6eb021SLiane Praza 	case SCF_TERR_PROP_TYPE_MISMATCH:
69911f6eb021SLiane Praza 	case SCF_TERR_PG_REDEFINE:
69921f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NOT_FOUND);
69931f6eb021SLiane Praza 		break;
69941f6eb021SLiane Praza 	default:
69951f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
69961f6eb021SLiane Praza 	}
69971f6eb021SLiane Praza 	return (-1);
69981f6eb021SLiane Praza }
69991f6eb021SLiane Praza 
70001f6eb021SLiane Praza const char *
70011f6eb021SLiane Praza scf_tmpl_visibility_to_string(uint8_t vis)
70021f6eb021SLiane Praza {
70031f6eb021SLiane Praza 	if (vis == SCF_TMPL_VISIBILITY_READONLY)
70041f6eb021SLiane Praza 		return (SCF_TM_VISIBILITY_READONLY);
70051f6eb021SLiane Praza 	else if (vis == SCF_TMPL_VISIBILITY_HIDDEN)
70061f6eb021SLiane Praza 		return (SCF_TM_VISIBILITY_HIDDEN);
70071f6eb021SLiane Praza 	else if (vis == SCF_TMPL_VISIBILITY_READWRITE)
70081f6eb021SLiane Praza 		return (SCF_TM_VISIBILITY_READWRITE);
70091f6eb021SLiane Praza 	else
70101f6eb021SLiane Praza 		return ("unknown");
70111f6eb021SLiane Praza }
7012