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