xref: /illumos-gate/usr/src/lib/libscf/common/scf_tmpl.c (revision 1f6eb0216cb17ca5fdff9563329f1dda47c8b801)
1*1f6eb021SLiane Praza /*
2*1f6eb021SLiane Praza  * CDDL HEADER START
3*1f6eb021SLiane Praza  *
4*1f6eb021SLiane Praza  * The contents of this file are subject to the terms of the
5*1f6eb021SLiane Praza  * Common Development and Distribution License (the "License").
6*1f6eb021SLiane Praza  * You may not use this file except in compliance with the License.
7*1f6eb021SLiane Praza  *
8*1f6eb021SLiane Praza  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*1f6eb021SLiane Praza  * or http://www.opensolaris.org/os/licensing.
10*1f6eb021SLiane Praza  * See the License for the specific language governing permissions
11*1f6eb021SLiane Praza  * and limitations under the License.
12*1f6eb021SLiane Praza  *
13*1f6eb021SLiane Praza  * When distributing Covered Code, include this CDDL HEADER in each
14*1f6eb021SLiane Praza  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*1f6eb021SLiane Praza  * If applicable, add the following below this CDDL HEADER, with the
16*1f6eb021SLiane Praza  * fields enclosed by brackets "[]" replaced with your own identifying
17*1f6eb021SLiane Praza  * information: Portions Copyright [yyyy] [name of copyright owner]
18*1f6eb021SLiane Praza  *
19*1f6eb021SLiane Praza  * CDDL HEADER END
20*1f6eb021SLiane Praza  */
21*1f6eb021SLiane Praza /*
22*1f6eb021SLiane Praza  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23*1f6eb021SLiane Praza  * Use is subject to license terms.
24*1f6eb021SLiane Praza  */
25*1f6eb021SLiane Praza 
26*1f6eb021SLiane Praza /*
27*1f6eb021SLiane Praza  * scf_tmpl.c
28*1f6eb021SLiane Praza  *
29*1f6eb021SLiane Praza  * This file implements the bulk of the libscf templates interfaces.
30*1f6eb021SLiane Praza  * Templates describe metadata about a service or instance in general,
31*1f6eb021SLiane Praza  * and individual configuration properties on those services and instances.
32*1f6eb021SLiane Praza  * Human-consumable descriptions can be provided, along with definitions
33*1f6eb021SLiane Praza  * of valid configuration.  See service_bundle.dtd.1 for XML definitions
34*1f6eb021SLiane Praza  * of templates, and the svccfg code for information on how those definitions
35*1f6eb021SLiane Praza  * are translated into the repository.
36*1f6eb021SLiane Praza  *
37*1f6eb021SLiane Praza  * The main data structures are scf_pg_tmpl and scf_prop_tmpl.  These
38*1f6eb021SLiane Praza  * are allocated by the callers through scf_tmpl_[pg|prop]_create(), and
39*1f6eb021SLiane Praza  * destroyed with scf_tmpl_[pg|prop]_destroy().  They are populated by
40*1f6eb021SLiane Praza  * scf_tmpl_get_by_pg_name(), scf_tmpl_get_by_pg(), and
41*1f6eb021SLiane Praza  * scf_tmpl_get_by_prop().  They also store the iterator state for
42*1f6eb021SLiane Praza  * scf_tmpl_iter_pgs() and scf_tmpl_iter_props().
43*1f6eb021SLiane Praza  *
44*1f6eb021SLiane Praza  * These data structures are then consumed by other functions to
45*1f6eb021SLiane Praza  * gather information about the template (e.g. name, description,
46*1f6eb021SLiane Praza  * choices, constraints, etc.).
47*1f6eb021SLiane Praza  *
48*1f6eb021SLiane Praza  * scf_tmpl_validate_fmri() does instance validation against template
49*1f6eb021SLiane Praza  * data, and populates a set of template errors which can be explored using
50*1f6eb021SLiane Praza  * the scf_tmpl_next_error() and the scf_tmpl_error*() suite of functions.
51*1f6eb021SLiane Praza  *
52*1f6eb021SLiane Praza  * The main data structures for template errors are scf_tmpl_errors,
53*1f6eb021SLiane Praza  * defined in this file, and scf_tmpl_error, defined in libscf_priv.h.
54*1f6eb021SLiane Praza  * scf_tmpl_error is shared with svccfg to offer common printing
55*1f6eb021SLiane Praza  * of error messages between libscf and svccfg.
56*1f6eb021SLiane Praza  *
57*1f6eb021SLiane Praza  * General convenience functions are towards the top of this file,
58*1f6eb021SLiane Praza  * followed by pg and prop template discovery functions, followed
59*1f6eb021SLiane Praza  * by functions which gather information about the discovered
60*1f6eb021SLiane Praza  * template.  Validation and error functions are at the end of this file.
61*1f6eb021SLiane Praza  */
62*1f6eb021SLiane Praza 
63*1f6eb021SLiane Praza #include "lowlevel_impl.h"
64*1f6eb021SLiane Praza #include "libscf_impl.h"
65*1f6eb021SLiane Praza #include <assert.h>
66*1f6eb021SLiane Praza #include <errno.h>
67*1f6eb021SLiane Praza #include <libintl.h>
68*1f6eb021SLiane Praza #include <stdlib.h>
69*1f6eb021SLiane Praza #include <stdio.h>
70*1f6eb021SLiane Praza #include <strings.h>
71*1f6eb021SLiane Praza #include <locale.h>
72*1f6eb021SLiane Praza #include <ctype.h>
73*1f6eb021SLiane Praza #include <inttypes.h>
74*1f6eb021SLiane Praza 
75*1f6eb021SLiane Praza #define	SCF_TMPL_PG_COMMON_NAME_C	"common_name_C"
76*1f6eb021SLiane Praza 
77*1f6eb021SLiane Praza #define	SCF__TMPL_ITER_NONE		0
78*1f6eb021SLiane Praza #define	SCF__TMPL_ITER_INST		1
79*1f6eb021SLiane Praza #define	SCF__TMPL_ITER_RESTARTER	2
80*1f6eb021SLiane Praza #define	SCF__TMPL_ITER_GLOBAL		3
81*1f6eb021SLiane Praza 
82*1f6eb021SLiane Praza #define	SCF_TMPL_PG_NT		0
83*1f6eb021SLiane Praza #define	SCF_TMPL_PG_N		1
84*1f6eb021SLiane Praza #define	SCF_TMPL_PG_T		2
85*1f6eb021SLiane Praza #define	SCF_TMPL_PG_WILD	3
86*1f6eb021SLiane Praza 
87*1f6eb021SLiane Praza struct scf_pg_tmpl {
88*1f6eb021SLiane Praza 	int pt_populated;
89*1f6eb021SLiane Praza 	scf_handle_t *pt_h;
90*1f6eb021SLiane Praza 	scf_propertygroup_t *pt_pg;
91*1f6eb021SLiane Praza 	scf_service_t *pt_orig_svc;
92*1f6eb021SLiane Praza 	scf_service_t *pt_svc;
93*1f6eb021SLiane Praza 	scf_instance_t *pt_orig_inst;
94*1f6eb021SLiane Praza 	scf_instance_t *pt_inst;
95*1f6eb021SLiane Praza 	scf_snapshot_t *pt_snap;
96*1f6eb021SLiane Praza 	int pt_is_iter;
97*1f6eb021SLiane Praza 	scf_iter_t *pt_iter;
98*1f6eb021SLiane Praza 	int pt_iter_last;
99*1f6eb021SLiane Praza };
100*1f6eb021SLiane Praza 
101*1f6eb021SLiane Praza #define	SCF_WALK_ERROR		-1
102*1f6eb021SLiane Praza #define	SCF_WALK_NEXT		0
103*1f6eb021SLiane Praza #define	SCF_WALK_DONE		1
104*1f6eb021SLiane Praza 
105*1f6eb021SLiane Praza struct pg_tmpl_walk {
106*1f6eb021SLiane Praza 	const char *pw_snapname;
107*1f6eb021SLiane Praza 	const char *pw_pgname;
108*1f6eb021SLiane Praza 	const char *pw_pgtype;
109*1f6eb021SLiane Praza 	scf_instance_t *pw_inst;
110*1f6eb021SLiane Praza 	scf_service_t *pw_svc;
111*1f6eb021SLiane Praza 	scf_snapshot_t *pw_snap;
112*1f6eb021SLiane Praza 	scf_propertygroup_t *pw_pg;
113*1f6eb021SLiane Praza 	const char *pw_target;
114*1f6eb021SLiane Praza 	char *pw_tmpl_pgname;
115*1f6eb021SLiane Praza };
116*1f6eb021SLiane Praza 
117*1f6eb021SLiane Praza typedef struct pg_tmpl_walk pg_tmpl_walk_t;
118*1f6eb021SLiane Praza 
119*1f6eb021SLiane Praza typedef int walk_template_inst_func_t(scf_service_t *_svc,
120*1f6eb021SLiane Praza     scf_instance_t *_inst, pg_tmpl_walk_t *p);
121*1f6eb021SLiane Praza 
122*1f6eb021SLiane Praza struct scf_prop_tmpl {
123*1f6eb021SLiane Praza 	int prt_populated;
124*1f6eb021SLiane Praza 	scf_handle_t *prt_h;
125*1f6eb021SLiane Praza 	scf_pg_tmpl_t *prt_t;
126*1f6eb021SLiane Praza 	scf_propertygroup_t *prt_pg;
127*1f6eb021SLiane Praza 	char *prt_pg_name;
128*1f6eb021SLiane Praza 	scf_iter_t *prt_iter;
129*1f6eb021SLiane Praza };
130*1f6eb021SLiane Praza 
131*1f6eb021SLiane Praza /*
132*1f6eb021SLiane Praza  * Common server errors are usually passed back to the caller.  This
133*1f6eb021SLiane Praza  * array defines them centrally so that they don't need to be enumerated
134*1f6eb021SLiane Praza  * in every libscf call.
135*1f6eb021SLiane Praza  */
136*1f6eb021SLiane Praza static const scf_error_t errors_server[] = {
137*1f6eb021SLiane Praza 	SCF_ERROR_BACKEND_ACCESS,
138*1f6eb021SLiane Praza 	SCF_ERROR_CONNECTION_BROKEN,
139*1f6eb021SLiane Praza 	SCF_ERROR_DELETED,
140*1f6eb021SLiane Praza 	SCF_ERROR_HANDLE_DESTROYED,
141*1f6eb021SLiane Praza 	SCF_ERROR_INTERNAL,
142*1f6eb021SLiane Praza 	SCF_ERROR_NO_MEMORY,
143*1f6eb021SLiane Praza 	SCF_ERROR_NO_RESOURCES,
144*1f6eb021SLiane Praza 	SCF_ERROR_NOT_BOUND,
145*1f6eb021SLiane Praza 	SCF_ERROR_PERMISSION_DENIED,
146*1f6eb021SLiane Praza 	0
147*1f6eb021SLiane Praza 	};
148*1f6eb021SLiane Praza 
149*1f6eb021SLiane Praza /*
150*1f6eb021SLiane Praza  * int ismember()
151*1f6eb021SLiane Praza  *
152*1f6eb021SLiane Praza  * Returns 1 if the supplied error is a member of the error array, 0
153*1f6eb021SLiane Praza  * if it is not.
154*1f6eb021SLiane Praza  */
155*1f6eb021SLiane Praza static scf_error_t
156*1f6eb021SLiane Praza ismember(const int error, const scf_error_t error_array[])
157*1f6eb021SLiane Praza {
158*1f6eb021SLiane Praza 	int i;
159*1f6eb021SLiane Praza 
160*1f6eb021SLiane Praza 	for (i = 0; error_array[i] != 0; ++i) {
161*1f6eb021SLiane Praza 		if (error == error_array[i])
162*1f6eb021SLiane Praza 			return (1);
163*1f6eb021SLiane Praza 	}
164*1f6eb021SLiane Praza 
165*1f6eb021SLiane Praza 	return (0);
166*1f6eb021SLiane Praza }
167*1f6eb021SLiane Praza 
168*1f6eb021SLiane Praza /*
169*1f6eb021SLiane Praza  * char *_scf_tmpl_get_fmri()
170*1f6eb021SLiane Praza  *
171*1f6eb021SLiane Praza  * Given a pg_tmpl, returns the FMRI of the service or instance that
172*1f6eb021SLiane Praza  * template describes.  The allocated string must be freed with free().
173*1f6eb021SLiane Praza  *
174*1f6eb021SLiane Praza  * On failure, returns NULL and sets scf_error() to _CONNECTION_BROKEN,
175*1f6eb021SLiane Praza  * _DELETED, or _NO_MEMORY.
176*1f6eb021SLiane Praza  */
177*1f6eb021SLiane Praza static char *
178*1f6eb021SLiane Praza _scf_tmpl_get_fmri(const scf_pg_tmpl_t *t)
179*1f6eb021SLiane Praza {
180*1f6eb021SLiane Praza 	ssize_t sz = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH) + 1;
181*1f6eb021SLiane Praza 	int r;
182*1f6eb021SLiane Praza 	char *buf = malloc(sz);
183*1f6eb021SLiane Praza 
184*1f6eb021SLiane Praza 	assert(t->pt_svc != NULL || t->pt_inst != NULL);
185*1f6eb021SLiane Praza 	assert(t->pt_svc == NULL || t->pt_inst == NULL);
186*1f6eb021SLiane Praza 
187*1f6eb021SLiane Praza 	if (buf == NULL) {
188*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
189*1f6eb021SLiane Praza 		return (buf);
190*1f6eb021SLiane Praza 	}
191*1f6eb021SLiane Praza 
192*1f6eb021SLiane Praza 	if (t->pt_inst != NULL)
193*1f6eb021SLiane Praza 		r = scf_instance_to_fmri(t->pt_inst, buf, sz);
194*1f6eb021SLiane Praza 	else
195*1f6eb021SLiane Praza 		r = scf_service_to_fmri(t->pt_svc, buf, sz);
196*1f6eb021SLiane Praza 
197*1f6eb021SLiane Praza 	if (r == -1) {
198*1f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
199*1f6eb021SLiane Praza 			free(buf);
200*1f6eb021SLiane Praza 			buf = NULL;
201*1f6eb021SLiane Praza 		} else {
202*1f6eb021SLiane Praza 			assert(0);
203*1f6eb021SLiane Praza 			abort();
204*1f6eb021SLiane Praza 		}
205*1f6eb021SLiane Praza 	}
206*1f6eb021SLiane Praza 
207*1f6eb021SLiane Praza 	return (buf);
208*1f6eb021SLiane Praza }
209*1f6eb021SLiane Praza 
210*1f6eb021SLiane Praza /*
211*1f6eb021SLiane Praza  * char *_scf_get_pg_type()
212*1f6eb021SLiane Praza  *
213*1f6eb021SLiane Praza  * Given a propertygroup, returns an allocated string containing the
214*1f6eb021SLiane Praza  * type.  The string must be freed with free().
215*1f6eb021SLiane Praza  *
216*1f6eb021SLiane Praza  * On failure, returns NULL and sets scf_error() to: _CONNECTION_BROKEN,
217*1f6eb021SLiane Praza  * _DELETED, or _NO_MEMORY.
218*1f6eb021SLiane Praza  */
219*1f6eb021SLiane Praza static char *
220*1f6eb021SLiane Praza _scf_get_pg_type(scf_propertygroup_t *pg)
221*1f6eb021SLiane Praza {
222*1f6eb021SLiane Praza 	ssize_t sz = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH) + 1;
223*1f6eb021SLiane Praza 	char *buf = malloc(sz);
224*1f6eb021SLiane Praza 
225*1f6eb021SLiane Praza 	if (buf == NULL) {
226*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
227*1f6eb021SLiane Praza 	} else if (scf_pg_get_type(pg, buf, sz) == -1) {
228*1f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
229*1f6eb021SLiane Praza 			free(buf);
230*1f6eb021SLiane Praza 			buf = NULL;
231*1f6eb021SLiane Praza 		} else {
232*1f6eb021SLiane Praza 			assert(0);
233*1f6eb021SLiane Praza 			abort();
234*1f6eb021SLiane Praza 		}
235*1f6eb021SLiane Praza 	}
236*1f6eb021SLiane Praza 
237*1f6eb021SLiane Praza 	return (buf);
238*1f6eb021SLiane Praza }
239*1f6eb021SLiane Praza 
240*1f6eb021SLiane Praza /*
241*1f6eb021SLiane Praza  * char *_scf_get_prop_name()
242*1f6eb021SLiane Praza  *
243*1f6eb021SLiane Praza  * Given a property, returns the name in an allocated string.  The string must
244*1f6eb021SLiane Praza  * be freed with free().
245*1f6eb021SLiane Praza  *
246*1f6eb021SLiane Praza  * On error, returns NULL and sets scf_error() to _CONNECTION_BROKEN,
247*1f6eb021SLiane Praza  * _DELETED, or _NO_MEMORY.
248*1f6eb021SLiane Praza  */
249*1f6eb021SLiane Praza static char *
250*1f6eb021SLiane Praza _scf_get_prop_name(scf_property_t *prop)
251*1f6eb021SLiane Praza {
252*1f6eb021SLiane Praza 	ssize_t sz = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
253*1f6eb021SLiane Praza 	char *buf = malloc(sz);
254*1f6eb021SLiane Praza 
255*1f6eb021SLiane Praza 	if (buf == NULL) {
256*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
257*1f6eb021SLiane Praza 	} else if (scf_property_get_name(prop, buf, sz) == -1) {
258*1f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
259*1f6eb021SLiane Praza 			free(buf);
260*1f6eb021SLiane Praza 			buf = NULL;
261*1f6eb021SLiane Praza 		} else {
262*1f6eb021SLiane Praza 			assert(0);
263*1f6eb021SLiane Praza 			abort();
264*1f6eb021SLiane Praza 		}
265*1f6eb021SLiane Praza 	}
266*1f6eb021SLiane Praza 
267*1f6eb021SLiane Praza 	return (buf);
268*1f6eb021SLiane Praza }
269*1f6eb021SLiane Praza 
270*1f6eb021SLiane Praza /*
271*1f6eb021SLiane Praza  * char *_scf_get_prop_type()
272*1f6eb021SLiane Praza  *
273*1f6eb021SLiane Praza  * Given a property, returns the type in an allocated string.  The string must
274*1f6eb021SLiane Praza  * be freed with free().
275*1f6eb021SLiane Praza  *
276*1f6eb021SLiane Praza  * On error, returns NULL and sets scf_error() to _CONNECTION_BROKEN,
277*1f6eb021SLiane Praza  * _DELETED, or _NO_MEMORY.
278*1f6eb021SLiane Praza  */
279*1f6eb021SLiane Praza static char *
280*1f6eb021SLiane Praza _scf_get_prop_type(scf_property_t *prop)
281*1f6eb021SLiane Praza {
282*1f6eb021SLiane Praza 	scf_type_t type;
283*1f6eb021SLiane Praza 	char *ret;
284*1f6eb021SLiane Praza 
285*1f6eb021SLiane Praza 	if (scf_property_type(prop, &type) == -1) {
286*1f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
287*1f6eb021SLiane Praza 			return (NULL);
288*1f6eb021SLiane Praza 		} else {
289*1f6eb021SLiane Praza 			assert(0);
290*1f6eb021SLiane Praza 			abort();
291*1f6eb021SLiane Praza 		}
292*1f6eb021SLiane Praza 	}
293*1f6eb021SLiane Praza 
294*1f6eb021SLiane Praza 	ret = strdup(scf_type_to_string(type));
295*1f6eb021SLiane Praza 	if (ret == NULL)
296*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
297*1f6eb021SLiane Praza 
298*1f6eb021SLiane Praza 	return (ret);
299*1f6eb021SLiane Praza }
300*1f6eb021SLiane Praza 
301*1f6eb021SLiane Praza /*
302*1f6eb021SLiane Praza  * int _read_single_value_from_pg()
303*1f6eb021SLiane Praza  *
304*1f6eb021SLiane Praza  * Reads a single value from the pg and property name specified.  On success,
305*1f6eb021SLiane Praza  * returns an allocated value that must be freed.
306*1f6eb021SLiane Praza  *
307*1f6eb021SLiane Praza  * Returns -1 on failure, sets scf_error() to:
308*1f6eb021SLiane Praza  *  SCF_ERROR_BACKEND_ACCESS
309*1f6eb021SLiane Praza  *  SCF_ERROR_CONNECTION_BROKEN
310*1f6eb021SLiane Praza  *  SCF_ERROR_CONSTRAINT_VIOLATED
311*1f6eb021SLiane Praza  *    Property has more than one value associated with it.
312*1f6eb021SLiane Praza  *  SCF_ERROR_DELETED
313*1f6eb021SLiane Praza  *  SCF_ERROR_HANDLE_DESTROYED
314*1f6eb021SLiane Praza  *  SCF_ERROR_INTERNAL
315*1f6eb021SLiane Praza  *  SCF_ERROR_INVALID_ARGUMENT
316*1f6eb021SLiane Praza  *    prop_name not a valid property name.
317*1f6eb021SLiane Praza  *  SCF_ERROR_NO_MEMORY
318*1f6eb021SLiane Praza  *  SCF_ERROR_NO_RESOURCES
319*1f6eb021SLiane Praza  *  SCF_ERROR_NOT_BOUND
320*1f6eb021SLiane Praza  *  SCF_ERROR_NOT_FOUND
321*1f6eb021SLiane Praza  *    Property doesn't exist or exists and has no value.
322*1f6eb021SLiane Praza  *  SCF_ERROR_NOT_SET
323*1f6eb021SLiane Praza  *    Property group specified by pg is not set.
324*1f6eb021SLiane Praza  *  SCF_ERROR_PERMISSION_DENIED
325*1f6eb021SLiane Praza  */
326*1f6eb021SLiane Praza static int
327*1f6eb021SLiane Praza _read_single_value_from_pg(scf_propertygroup_t *pg, const char *prop_name,
328*1f6eb021SLiane Praza     scf_value_t **val)
329*1f6eb021SLiane Praza {
330*1f6eb021SLiane Praza 	scf_handle_t *h;
331*1f6eb021SLiane Praza 	scf_property_t *prop;
332*1f6eb021SLiane Praza 	int ret = 0;
333*1f6eb021SLiane Praza 
334*1f6eb021SLiane Praza 	assert(val != NULL);
335*1f6eb021SLiane Praza 	if ((h = scf_pg_handle(pg)) == NULL) {
336*1f6eb021SLiane Praza 		assert(scf_error() == SCF_ERROR_HANDLE_DESTROYED);
337*1f6eb021SLiane Praza 		return (-1);
338*1f6eb021SLiane Praza 	}
339*1f6eb021SLiane Praza 
340*1f6eb021SLiane Praza 	prop = scf_property_create(h);
341*1f6eb021SLiane Praza 	*val = scf_value_create(h);
342*1f6eb021SLiane Praza 
343*1f6eb021SLiane Praza 	if (prop == NULL || *val == NULL) {
344*1f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_INVALID_ARGUMENT);
345*1f6eb021SLiane Praza 		goto read_single_value_from_pg_fail;
346*1f6eb021SLiane Praza 	}
347*1f6eb021SLiane Praza 
348*1f6eb021SLiane Praza 	if (scf_pg_get_property(pg, prop_name, prop) != 0) {
349*1f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_HANDLE_MISMATCH);
350*1f6eb021SLiane Praza 		goto read_single_value_from_pg_fail;
351*1f6eb021SLiane Praza 	}
352*1f6eb021SLiane Praza 
353*1f6eb021SLiane Praza 	if (scf_property_get_value(prop, *val) == -1) {
354*1f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_NOT_SET);
355*1f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_HANDLE_MISMATCH);
356*1f6eb021SLiane Praza 		goto read_single_value_from_pg_fail;
357*1f6eb021SLiane Praza 	}
358*1f6eb021SLiane Praza 
359*1f6eb021SLiane Praza 	goto read_single_value_from_pg_done;
360*1f6eb021SLiane Praza 
361*1f6eb021SLiane Praza read_single_value_from_pg_fail:
362*1f6eb021SLiane Praza 	scf_value_destroy(*val);
363*1f6eb021SLiane Praza 	*val = NULL;
364*1f6eb021SLiane Praza 	ret = -1;
365*1f6eb021SLiane Praza 
366*1f6eb021SLiane Praza read_single_value_from_pg_done:
367*1f6eb021SLiane Praza 	scf_property_destroy(prop);
368*1f6eb021SLiane Praza 	return (ret);
369*1f6eb021SLiane Praza }
370*1f6eb021SLiane Praza 
371*1f6eb021SLiane Praza /*
372*1f6eb021SLiane Praza  * char *_scf_read_single_astring_from_pg()
373*1f6eb021SLiane Praza  *
374*1f6eb021SLiane Praza  * Reads an astring from the pg and property name specified.  On success,
375*1f6eb021SLiane Praza  * returns an allocated string.  The string must be freed with free().
376*1f6eb021SLiane Praza  *
377*1f6eb021SLiane Praza  * Returns NULL on failure, sets scf_error() to:
378*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
379*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
380*1f6eb021SLiane Praza  *   SCF_ERROR_CONSTRAINT_VIOLATED
381*1f6eb021SLiane Praza  *     Property has more than one value associated with it.
382*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
383*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
384*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
385*1f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
386*1f6eb021SLiane Praza  *     prop_name not a valid property name.
387*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
388*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
389*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
390*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
391*1f6eb021SLiane Praza  *     Property doesn't exist or exists and has no value.
392*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_SET
393*1f6eb021SLiane Praza  *     The property group specified by pg is not set.
394*1f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
395*1f6eb021SLiane Praza  *   SCF_ERROR_TYPE_MISMATCH
396*1f6eb021SLiane Praza  */
397*1f6eb021SLiane Praza char *
398*1f6eb021SLiane Praza _scf_read_single_astring_from_pg(scf_propertygroup_t *pg, const char *prop_name)
399*1f6eb021SLiane Praza {
400*1f6eb021SLiane Praza 	scf_value_t *val;
401*1f6eb021SLiane Praza 	char *ret = NULL;
402*1f6eb021SLiane Praza 	ssize_t rsize = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH) + 1;
403*1f6eb021SLiane Praza 
404*1f6eb021SLiane Praza 	assert(rsize != 0);
405*1f6eb021SLiane Praza 	if (_read_single_value_from_pg(pg, prop_name, &val) == -1)
406*1f6eb021SLiane Praza 		return (NULL);
407*1f6eb021SLiane Praza 
408*1f6eb021SLiane Praza 	ret = malloc(rsize);
409*1f6eb021SLiane Praza 	if (ret == NULL) {
410*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
411*1f6eb021SLiane Praza 		goto cleanup;
412*1f6eb021SLiane Praza 	}
413*1f6eb021SLiane Praza 
414*1f6eb021SLiane Praza 	if (scf_value_get_astring(val, ret, rsize) < 0) {
415*1f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_NOT_SET);
416*1f6eb021SLiane Praza 		free(ret);
417*1f6eb021SLiane Praza 		ret = NULL;
418*1f6eb021SLiane Praza 	}
419*1f6eb021SLiane Praza 
420*1f6eb021SLiane Praza cleanup:
421*1f6eb021SLiane Praza 	scf_value_destroy(val);
422*1f6eb021SLiane Praza 	return (ret);
423*1f6eb021SLiane Praza }
424*1f6eb021SLiane Praza 
425*1f6eb021SLiane Praza /*
426*1f6eb021SLiane Praza  * char *_scf_read_tmpl_prop_type_as_string()
427*1f6eb021SLiane Praza  *
428*1f6eb021SLiane Praza  * Reads the property type and returns it as an allocated string.  The string
429*1f6eb021SLiane Praza  * must be freed with free().
430*1f6eb021SLiane Praza  *
431*1f6eb021SLiane Praza  * Returns NULL on failure, sets scf_error() to _BACKEND_ACCESS,
432*1f6eb021SLiane Praza  * _CONNECTION_BROKEN, _DELETED, _HANDLE_DESTROYED, _INTERNAL, _NO_MEMORY,
433*1f6eb021SLiane Praza  * _NO_RESOURCES, _NOT_BOUND, _PERMISSION_DENIED, or _TEMPLATE_INVALID.
434*1f6eb021SLiane Praza  */
435*1f6eb021SLiane Praza char *
436*1f6eb021SLiane Praza _scf_read_tmpl_prop_type_as_string(const scf_prop_tmpl_t *pt)
437*1f6eb021SLiane Praza {
438*1f6eb021SLiane Praza 	char *type;
439*1f6eb021SLiane Praza 
440*1f6eb021SLiane Praza 	type = _scf_read_single_astring_from_pg(pt->prt_pg,
441*1f6eb021SLiane Praza 	    SCF_PROPERTY_TM_TYPE);
442*1f6eb021SLiane Praza 	if (type == NULL) {
443*1f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
444*1f6eb021SLiane Praza 			return (NULL);
445*1f6eb021SLiane Praza 		} else switch (scf_error()) {
446*1f6eb021SLiane Praza 		case SCF_ERROR_CONSTRAINT_VIOLATED:
447*1f6eb021SLiane Praza 		case SCF_ERROR_NOT_FOUND:
448*1f6eb021SLiane Praza 		case SCF_ERROR_TYPE_MISMATCH:
449*1f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
450*1f6eb021SLiane Praza 			return (NULL);
451*1f6eb021SLiane Praza 
452*1f6eb021SLiane Praza 		case SCF_ERROR_INVALID_ARGUMENT:
453*1f6eb021SLiane Praza 		case SCF_ERROR_NOT_SET:
454*1f6eb021SLiane Praza 		default:
455*1f6eb021SLiane Praza 			assert(0);
456*1f6eb021SLiane Praza 			abort();
457*1f6eb021SLiane Praza 		}
458*1f6eb021SLiane Praza 	}
459*1f6eb021SLiane Praza 
460*1f6eb021SLiane Praza 	return (type);
461*1f6eb021SLiane Praza }
462*1f6eb021SLiane Praza 
463*1f6eb021SLiane Praza /*
464*1f6eb021SLiane Praza  * int _read_single_boolean_from_pg()
465*1f6eb021SLiane Praza  *
466*1f6eb021SLiane Praza  * Reads a boolean from the pg and property name specified.
467*1f6eb021SLiane Praza  *
468*1f6eb021SLiane Praza  * Returns -1 on failure, sets scf_error() to:
469*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
470*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
471*1f6eb021SLiane Praza  *   SCF_ERROR_CONSTRAINT_VIOLATED
472*1f6eb021SLiane Praza  *     Property has more than one value associated with it.
473*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
474*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
475*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
476*1f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
477*1f6eb021SLiane Praza  *     prop_name is not a valid property name.
478*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
479*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
480*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
481*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
482*1f6eb021SLiane Praza  *     Property doesn't exist or exists and has no value.
483*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_SET
484*1f6eb021SLiane Praza  *     The property group specified by pg is not set.
485*1f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
486*1f6eb021SLiane Praza  *   SCF_ERROR_TYPE_MISMATCH
487*1f6eb021SLiane Praza  */
488*1f6eb021SLiane Praza static int
489*1f6eb021SLiane Praza _read_single_boolean_from_pg(scf_propertygroup_t *pg, const char *prop_name,
490*1f6eb021SLiane Praza     uint8_t *bool)
491*1f6eb021SLiane Praza {
492*1f6eb021SLiane Praza 	scf_value_t *val;
493*1f6eb021SLiane Praza 	int ret = 0;
494*1f6eb021SLiane Praza 
495*1f6eb021SLiane Praza 	if (_read_single_value_from_pg(pg, prop_name, &val) == -1)
496*1f6eb021SLiane Praza 		return (-1);
497*1f6eb021SLiane Praza 
498*1f6eb021SLiane Praza 	if (scf_value_get_boolean(val, bool) < 0) {
499*1f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_NOT_SET);
500*1f6eb021SLiane Praza 		ret = -1;
501*1f6eb021SLiane Praza 	}
502*1f6eb021SLiane Praza 
503*1f6eb021SLiane Praza 	scf_value_destroy(val);
504*1f6eb021SLiane Praza 	return (ret);
505*1f6eb021SLiane Praza }
506*1f6eb021SLiane Praza 
507*1f6eb021SLiane Praza /*
508*1f6eb021SLiane Praza  * char **_append_astrings_values()
509*1f6eb021SLiane Praza  *
510*1f6eb021SLiane Praza  * This function reads the values from the property prop_name in pg and
511*1f6eb021SLiane Praza  * appends to an existing scf_values_t *vals.  vals may be empty, but
512*1f6eb021SLiane Praza  * must exist.  The function skips over zero-length and duplicate values.
513*1f6eb021SLiane Praza  *
514*1f6eb021SLiane Praza  * Returns NULL on failure, sets scf_error() to:
515*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
516*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
517*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
518*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
519*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
520*1f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
521*1f6eb021SLiane Praza  *     prop_name is not a valid property name.
522*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
523*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
524*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
525*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
526*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_SET
527*1f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
528*1f6eb021SLiane Praza  *   SCF_ERROR_TYPE_MISMATCH
529*1f6eb021SLiane Praza  */
530*1f6eb021SLiane Praza static char **
531*1f6eb021SLiane Praza _append_astrings_values(scf_propertygroup_t *pg, const char *prop_name,
532*1f6eb021SLiane Praza     scf_values_t *vals)
533*1f6eb021SLiane Praza {
534*1f6eb021SLiane Praza 	scf_handle_t *h;
535*1f6eb021SLiane Praza 	scf_property_t *prop;
536*1f6eb021SLiane Praza 	scf_value_t *val;
537*1f6eb021SLiane Praza 	scf_iter_t *iter;
538*1f6eb021SLiane Praza 	ssize_t rsize = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH) + 1;
539*1f6eb021SLiane Praza 	int err, count, cursz, i;
540*1f6eb021SLiane Praza 
541*1f6eb021SLiane Praza 	assert(vals != NULL);
542*1f6eb021SLiane Praza 	assert(vals->value_type == SCF_TYPE_ASTRING);
543*1f6eb021SLiane Praza 	assert(vals->reserved == NULL);
544*1f6eb021SLiane Praza 	count = vals->value_count;
545*1f6eb021SLiane Praza 	if (count == 0) {
546*1f6eb021SLiane Praza 		cursz = 8;
547*1f6eb021SLiane Praza 		vals->values.v_astring = calloc(cursz, sizeof (char *));
548*1f6eb021SLiane Praza 		if (vals->values.v_astring == NULL) {
549*1f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
550*1f6eb021SLiane Praza 			return (NULL);
551*1f6eb021SLiane Praza 		}
552*1f6eb021SLiane Praza 	} else {
553*1f6eb021SLiane Praza 		/*
554*1f6eb021SLiane Praza 		 * The array may be bigger, but it is irrelevant since
555*1f6eb021SLiane Praza 		 * we will always re-allocate a new one.
556*1f6eb021SLiane Praza 		 */
557*1f6eb021SLiane Praza 		cursz = count;
558*1f6eb021SLiane Praza 	}
559*1f6eb021SLiane Praza 
560*1f6eb021SLiane Praza 	if ((h = scf_pg_handle(pg)) == NULL) {
561*1f6eb021SLiane Praza 		assert(scf_error() == SCF_ERROR_HANDLE_DESTROYED);
562*1f6eb021SLiane Praza 		return (NULL);
563*1f6eb021SLiane Praza 	}
564*1f6eb021SLiane Praza 
565*1f6eb021SLiane Praza 	prop = scf_property_create(h);
566*1f6eb021SLiane Praza 	val = scf_value_create(h);
567*1f6eb021SLiane Praza 	iter = scf_iter_create(h);
568*1f6eb021SLiane Praza 
569*1f6eb021SLiane Praza 	if (prop == NULL || val == NULL || iter == NULL) {
570*1f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_INVALID_ARGUMENT);
571*1f6eb021SLiane Praza 		goto append_single_astring_from_pg_fail;
572*1f6eb021SLiane Praza 	}
573*1f6eb021SLiane Praza 
574*1f6eb021SLiane Praza 	if (scf_pg_get_property(pg, prop_name, prop) != 0) {
575*1f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_HANDLE_MISMATCH);
576*1f6eb021SLiane Praza 		goto append_single_astring_from_pg_fail;
577*1f6eb021SLiane Praza 	}
578*1f6eb021SLiane Praza 
579*1f6eb021SLiane Praza 	if (scf_iter_property_values(iter, prop) != 0) {
580*1f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_NOT_SET);
581*1f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_HANDLE_MISMATCH);
582*1f6eb021SLiane Praza 		goto append_single_astring_from_pg_fail;
583*1f6eb021SLiane Praza 	}
584*1f6eb021SLiane Praza 
585*1f6eb021SLiane Praza 	while ((err = scf_iter_next_value(iter, val)) == 1) {
586*1f6eb021SLiane Praza 		int flag;
587*1f6eb021SLiane Praza 		int r;
588*1f6eb021SLiane Praza 
589*1f6eb021SLiane Praza 		if (count + 1 >= cursz) {
590*1f6eb021SLiane Praza 			void *aux;
591*1f6eb021SLiane Praza 
592*1f6eb021SLiane Praza 			cursz *= 2;
593*1f6eb021SLiane Praza 			if ((aux = calloc(cursz, sizeof (char *))) == NULL) {
594*1f6eb021SLiane Praza 				(void) scf_set_error(SCF_ERROR_NO_MEMORY);
595*1f6eb021SLiane Praza 				goto append_single_astring_from_pg_fail;
596*1f6eb021SLiane Praza 			}
597*1f6eb021SLiane Praza 			(void) memcpy(aux, vals->values.v_astring,
598*1f6eb021SLiane Praza 			    count * sizeof (char *));
599*1f6eb021SLiane Praza 			free(vals->values.v_astring);
600*1f6eb021SLiane Praza 			vals->values.v_astring = aux;
601*1f6eb021SLiane Praza 		}
602*1f6eb021SLiane Praza 
603*1f6eb021SLiane Praza 		vals->values.v_astring[count] = malloc(rsize);
604*1f6eb021SLiane Praza 		if (vals->values.v_astring[count] == NULL) {
605*1f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
606*1f6eb021SLiane Praza 			goto append_single_astring_from_pg_fail;
607*1f6eb021SLiane Praza 		}
608*1f6eb021SLiane Praza 
609*1f6eb021SLiane Praza 		if ((r = scf_value_get_astring(val,
610*1f6eb021SLiane Praza 		    vals->values.v_astring[count], rsize)) <= 0) {
611*1f6eb021SLiane Praza 			/* discard zero length strings */
612*1f6eb021SLiane Praza 			if (r == 0) {
613*1f6eb021SLiane Praza 				free(vals->values.v_astring[count]);
614*1f6eb021SLiane Praza 				continue;
615*1f6eb021SLiane Praza 			}
616*1f6eb021SLiane Praza 			assert(scf_error() != SCF_ERROR_NOT_SET);
617*1f6eb021SLiane Praza 			goto append_single_astring_from_pg_fail;
618*1f6eb021SLiane Praza 		}
619*1f6eb021SLiane Praza 		for (i = 0, flag = 0; i < count; ++i) {
620*1f6eb021SLiane Praza 			/* find  and discard duplicates */
621*1f6eb021SLiane Praza 			if (strncmp(vals->values.v_astring[i],
622*1f6eb021SLiane Praza 			    vals->values.v_astring[count], rsize) == 0) {
623*1f6eb021SLiane Praza 				free(vals->values.v_astring[count]);
624*1f6eb021SLiane Praza 				flag = 1;
625*1f6eb021SLiane Praza 				break;
626*1f6eb021SLiane Praza 			}
627*1f6eb021SLiane Praza 		}
628*1f6eb021SLiane Praza 		if (flag == 1)
629*1f6eb021SLiane Praza 			continue;
630*1f6eb021SLiane Praza 
631*1f6eb021SLiane Praza 		count++;
632*1f6eb021SLiane Praza 	}
633*1f6eb021SLiane Praza 
634*1f6eb021SLiane Praza 	vals->value_count = count;
635*1f6eb021SLiane Praza 
636*1f6eb021SLiane Praza 	if (err != 0) {
637*1f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_NOT_SET);
638*1f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_INVALID_ARGUMENT);
639*1f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_HANDLE_MISMATCH);
640*1f6eb021SLiane Praza 		goto append_single_astring_from_pg_fail;
641*1f6eb021SLiane Praza 	} else {
642*1f6eb021SLiane Praza 		vals->values_as_strings = vals->values.v_astring;
643*1f6eb021SLiane Praza 	}
644*1f6eb021SLiane Praza 
645*1f6eb021SLiane Praza 	goto append_single_astring_from_pg_done;
646*1f6eb021SLiane Praza 
647*1f6eb021SLiane Praza append_single_astring_from_pg_fail:
648*1f6eb021SLiane Praza 	for (i = 0; i <= count; ++i) {
649*1f6eb021SLiane Praza 		if (vals->values.v_astring[i] != NULL)
650*1f6eb021SLiane Praza 			free(vals->values.v_astring[i]);
651*1f6eb021SLiane Praza 		vals->values.v_astring[i] = NULL;
652*1f6eb021SLiane Praza 	}
653*1f6eb021SLiane Praza 	free(vals->values.v_astring);
654*1f6eb021SLiane Praza 	vals->values.v_astring = NULL;
655*1f6eb021SLiane Praza 	vals->value_count = 0;
656*1f6eb021SLiane Praza 
657*1f6eb021SLiane Praza append_single_astring_from_pg_done:
658*1f6eb021SLiane Praza 	scf_iter_destroy(iter);
659*1f6eb021SLiane Praza 	scf_property_destroy(prop);
660*1f6eb021SLiane Praza 	scf_value_destroy(val);
661*1f6eb021SLiane Praza 	return (vals->values.v_astring);
662*1f6eb021SLiane Praza }
663*1f6eb021SLiane Praza 
664*1f6eb021SLiane Praza /*
665*1f6eb021SLiane Praza  * Returns NULL on failure, sets scf_error() to:
666*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
667*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
668*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
669*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
670*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
671*1f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
672*1f6eb021SLiane Praza  *     prop_name is not a valid property name.
673*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
674*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
675*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
676*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
677*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_SET
678*1f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
679*1f6eb021SLiane Praza  *   SCF_ERROR_TYPE_MISMATCH
680*1f6eb021SLiane Praza  */
681*1f6eb021SLiane Praza static char **
682*1f6eb021SLiane Praza _read_astrings_values(scf_propertygroup_t *pg, const char *prop_name,
683*1f6eb021SLiane Praza     scf_values_t *vals)
684*1f6eb021SLiane Praza {
685*1f6eb021SLiane Praza 	assert(vals != NULL);
686*1f6eb021SLiane Praza 	vals->value_count = 0;
687*1f6eb021SLiane Praza 	vals->value_type = SCF_TYPE_ASTRING;
688*1f6eb021SLiane Praza 	vals->reserved = NULL;
689*1f6eb021SLiane Praza 	return (_append_astrings_values(pg, prop_name, vals));
690*1f6eb021SLiane Praza }
691*1f6eb021SLiane Praza 
692*1f6eb021SLiane Praza void
693*1f6eb021SLiane Praza _scf_sanitize_locale(char *locale)
694*1f6eb021SLiane Praza {
695*1f6eb021SLiane Praza 	for (; *locale != '\0'; locale++)
696*1f6eb021SLiane Praza 		if (!isalnum(*locale) && *locale != '_')
697*1f6eb021SLiane Praza 			*locale = '_';
698*1f6eb021SLiane Praza }
699*1f6eb021SLiane Praza 
700*1f6eb021SLiane Praza /*
701*1f6eb021SLiane Praza  * The returned string needs to be freed by the caller
702*1f6eb021SLiane Praza  * Returns NULL on failure.  Sets scf_error() to:
703*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
704*1f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
705*1f6eb021SLiane Praza  *     Name isn't short enough to add the locale to.
706*1f6eb021SLiane Praza  */
707*1f6eb021SLiane Praza static char *
708*1f6eb021SLiane Praza _add_locale_to_name(const char *name, const char *locale)
709*1f6eb021SLiane Praza {
710*1f6eb021SLiane Praza 	char *lname = NULL;
711*1f6eb021SLiane Praza 	ssize_t lsz;
712*1f6eb021SLiane Praza 	char *loc;
713*1f6eb021SLiane Praza 
714*1f6eb021SLiane Praza 	if (locale == NULL)
715*1f6eb021SLiane Praza 		locale = setlocale(LC_MESSAGES, NULL);
716*1f6eb021SLiane Praza 	loc = strdup(locale);
717*1f6eb021SLiane Praza 	if (loc == NULL) {
718*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
719*1f6eb021SLiane Praza 		return (NULL);
720*1f6eb021SLiane Praza 	} else {
721*1f6eb021SLiane Praza 		_scf_sanitize_locale(loc);
722*1f6eb021SLiane Praza 	}
723*1f6eb021SLiane Praza 
724*1f6eb021SLiane Praza 	lsz = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
725*1f6eb021SLiane Praza 	lname = malloc(lsz);
726*1f6eb021SLiane Praza 	if (lname == NULL) {
727*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
728*1f6eb021SLiane Praza 		goto cleanup;
729*1f6eb021SLiane Praza 	}
730*1f6eb021SLiane Praza 
731*1f6eb021SLiane Praza 	(void) strlcpy(lname, name, lsz);
732*1f6eb021SLiane Praza 	if (strlcat(lname, loc, lsz) >= lsz) {
733*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
734*1f6eb021SLiane Praza 		free(lname);
735*1f6eb021SLiane Praza 		lname = NULL;
736*1f6eb021SLiane Praza 	}
737*1f6eb021SLiane Praza cleanup:
738*1f6eb021SLiane Praza 	free(loc);
739*1f6eb021SLiane Praza 
740*1f6eb021SLiane Praza 	return (lname);
741*1f6eb021SLiane Praza }
742*1f6eb021SLiane Praza 
743*1f6eb021SLiane Praza /*
744*1f6eb021SLiane Praza  * char *_tmpl_pg_name(pg, type, use_type)
745*1f6eb021SLiane Praza  *
746*1f6eb021SLiane Praza  * pg and type can both be NULL.  Returns the name of the most specific
747*1f6eb021SLiane Praza  * template property group name based on the inputs.
748*1f6eb021SLiane Praza  * If use_type is set and pg is not NULL, a property group name for a
749*1f6eb021SLiane Praza  * property group template that has type defined is returned, even if no
750*1f6eb021SLiane Praza  * type is provided.
751*1f6eb021SLiane Praza  *
752*1f6eb021SLiane Praza  * Returns NULL on failure and sets scf_error() to:
753*1f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
754*1f6eb021SLiane Praza  *     can't combine the arguments and get a reasonable length name
755*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
756*1f6eb021SLiane Praza  *
757*1f6eb021SLiane Praza  */
758*1f6eb021SLiane Praza static char *
759*1f6eb021SLiane Praza _tmpl_pg_name(const char *pg, const char *type, int use_type)
760*1f6eb021SLiane Praza {
761*1f6eb021SLiane Praza 	char *name;
762*1f6eb021SLiane Praza 	ssize_t limit, size = 0;
763*1f6eb021SLiane Praza 
764*1f6eb021SLiane Praza 	limit = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
765*1f6eb021SLiane Praza 	name = malloc(limit);
766*1f6eb021SLiane Praza 	if (name == NULL) {
767*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
768*1f6eb021SLiane Praza 		return (NULL);
769*1f6eb021SLiane Praza 	}
770*1f6eb021SLiane Praza 
771*1f6eb021SLiane Praza 	if (pg == NULL && type == NULL) {
772*1f6eb021SLiane Praza 		if (strlcpy(name, SCF_PG_TM_PG_PATTERN_PREFIX, limit) >=
773*1f6eb021SLiane Praza 		    limit) {
774*1f6eb021SLiane Praza 			assert(0);
775*1f6eb021SLiane Praza 			abort();
776*1f6eb021SLiane Praza 		}
777*1f6eb021SLiane Praza 		return (name);
778*1f6eb021SLiane Praza 	} else if (pg != NULL && type != NULL) {
779*1f6eb021SLiane Praza 		size = snprintf(name, limit, "%s%s",
780*1f6eb021SLiane Praza 		    SCF_PG_TM_PG_PATTERN_NT_PREFIX, pg);
781*1f6eb021SLiane Praza 	} else if (pg != NULL && type == NULL && use_type == 1) {
782*1f6eb021SLiane Praza 		size = snprintf(name, limit, "%s%s",
783*1f6eb021SLiane Praza 		    SCF_PG_TM_PG_PATTERN_NT_PREFIX, pg);
784*1f6eb021SLiane Praza 	} else if (pg != NULL && type == NULL) {
785*1f6eb021SLiane Praza 		size = snprintf(name, limit, "%s%s",
786*1f6eb021SLiane Praza 		    SCF_PG_TM_PG_PATTERN_N_PREFIX, pg);
787*1f6eb021SLiane Praza 	} else if (type != NULL && pg == NULL) {
788*1f6eb021SLiane Praza 		size = snprintf(name, limit, "%s%s",
789*1f6eb021SLiane Praza 		    SCF_PG_TM_PG_PATTERN_T_PREFIX, type);
790*1f6eb021SLiane Praza 	} else {
791*1f6eb021SLiane Praza 		assert(0);
792*1f6eb021SLiane Praza 		abort();
793*1f6eb021SLiane Praza 	}
794*1f6eb021SLiane Praza 
795*1f6eb021SLiane Praza 	if (size >= limit) {
796*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
797*1f6eb021SLiane Praza 		free(name);
798*1f6eb021SLiane Praza 		return (NULL);
799*1f6eb021SLiane Praza 	} else {
800*1f6eb021SLiane Praza 		return (name);
801*1f6eb021SLiane Praza 	}
802*1f6eb021SLiane Praza }
803*1f6eb021SLiane Praza 
804*1f6eb021SLiane Praza /*
805*1f6eb021SLiane Praza  * _scf_get_pg_name()
806*1f6eb021SLiane Praza  * Gets the name of the supplied property group.  On success, returns an
807*1f6eb021SLiane Praza  * allocated string.  The string must be freed by free().
808*1f6eb021SLiane Praza  *
809*1f6eb021SLiane Praza  * Returns NULL on failure and sets scf_error() to _CONNECTION_BROKEN,
810*1f6eb021SLiane Praza  * _DELETED, or _NO_MEMORY.
811*1f6eb021SLiane Praza  */
812*1f6eb021SLiane Praza static char *
813*1f6eb021SLiane Praza _scf_get_pg_name(scf_propertygroup_t *pg)
814*1f6eb021SLiane Praza {
815*1f6eb021SLiane Praza 	ssize_t sz = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
816*1f6eb021SLiane Praza 	char *buf = malloc(sz);
817*1f6eb021SLiane Praza 
818*1f6eb021SLiane Praza 	if (buf == NULL) {
819*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
820*1f6eb021SLiane Praza 	} else if (scf_pg_get_name(pg, buf, sz) == -1) {
821*1f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
822*1f6eb021SLiane Praza 			free(buf);
823*1f6eb021SLiane Praza 			buf = NULL;
824*1f6eb021SLiane Praza 		} else {
825*1f6eb021SLiane Praza 			assert(0);
826*1f6eb021SLiane Praza 			abort();
827*1f6eb021SLiane Praza 		}
828*1f6eb021SLiane Praza 	}
829*1f6eb021SLiane Praza 
830*1f6eb021SLiane Praza 	return (buf);
831*1f6eb021SLiane Praza }
832*1f6eb021SLiane Praza 
833*1f6eb021SLiane Praza /*
834*1f6eb021SLiane Praza  * char *_tmpl_prop_name()
835*1f6eb021SLiane Praza  *
836*1f6eb021SLiane Praza  * Returns the name of the property template prop (which is the name of
837*1f6eb021SLiane Praza  * the property template property group) in the property group
838*1f6eb021SLiane Praza  * template t. Returns NULL on failure and sets scf_error() to:
839*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
840*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
841*1f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
842*1f6eb021SLiane Praza  *     can't combine the arguments and get a reasonable length name
843*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
844*1f6eb021SLiane Praza  */
845*1f6eb021SLiane Praza static char *
846*1f6eb021SLiane Praza _tmpl_prop_name(const char *prop, scf_pg_tmpl_t *t)
847*1f6eb021SLiane Praza {
848*1f6eb021SLiane Praza 	char *name = NULL, *pg_name = NULL;
849*1f6eb021SLiane Praza 	size_t prefix_size;
850*1f6eb021SLiane Praza 	ssize_t limit, size = 0;
851*1f6eb021SLiane Praza 
852*1f6eb021SLiane Praza 	assert(prop != NULL);
853*1f6eb021SLiane Praza 	assert(t->pt_pg != NULL);
854*1f6eb021SLiane Praza 
855*1f6eb021SLiane Praza 	limit = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
856*1f6eb021SLiane Praza 	name = malloc(limit);
857*1f6eb021SLiane Praza 	if (name == NULL) {
858*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
859*1f6eb021SLiane Praza 		return (NULL);
860*1f6eb021SLiane Praza 	}
861*1f6eb021SLiane Praza 
862*1f6eb021SLiane Praza 	if ((pg_name = _scf_get_pg_name(t->pt_pg)) == NULL) {
863*1f6eb021SLiane Praza 		free(name);
864*1f6eb021SLiane Praza 		return (NULL);
865*1f6eb021SLiane Praza 	}
866*1f6eb021SLiane Praza 
867*1f6eb021SLiane Praza 	prefix_size = strlen(SCF_PG_TM_PG_PAT_BASE);
868*1f6eb021SLiane Praza 	if (strncmp(pg_name, SCF_PG_TM_PG_PAT_BASE, prefix_size) != 0) {
869*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
870*1f6eb021SLiane Praza 		free(name);
871*1f6eb021SLiane Praza 		free(pg_name);
872*1f6eb021SLiane Praza 		return (NULL);
873*1f6eb021SLiane Praza 	}
874*1f6eb021SLiane Praza 
875*1f6eb021SLiane Praza 	size = snprintf(name, limit, "%s%s_%s", SCF_PG_TM_PROP_PATTERN_PREFIX,
876*1f6eb021SLiane Praza 	    pg_name + prefix_size, prop);
877*1f6eb021SLiane Praza 
878*1f6eb021SLiane Praza 	if (size >= limit) {
879*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
880*1f6eb021SLiane Praza 		free(name);
881*1f6eb021SLiane Praza 		free(pg_name);
882*1f6eb021SLiane Praza 		return (NULL);
883*1f6eb021SLiane Praza 	} else {
884*1f6eb021SLiane Praza 		free(pg_name);
885*1f6eb021SLiane Praza 		return (name);
886*1f6eb021SLiane Praza 	}
887*1f6eb021SLiane Praza }
888*1f6eb021SLiane Praza 
889*1f6eb021SLiane Praza /*
890*1f6eb021SLiane Praza  *  int _get_snapshot()
891*1f6eb021SLiane Praza  *
892*1f6eb021SLiane Praza  *  Gets the specified snapshot.  If "snapshot" isn't defined, use the
893*1f6eb021SLiane Praza  *  running snapshot.  If the snapshot isn't found, that may or may
894*1f6eb021SLiane Praza  *  not be an error depending on the caller.  Return 0 in that case,
895*1f6eb021SLiane Praza  *  but leave scf_error() set to SCF_ERROR_NOT_FOUND.  On all other
896*1f6eb021SLiane Praza  *  errors, set scf_error() to:
897*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
898*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
899*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
900*1f6eb021SLiane Praza  *   SCF_ERR_HANDLE_DESTROYED
901*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
902*1f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
903*1f6eb021SLiane Praza  *     The handle argument is NULL, or snaphot is not a valid snapshot name
904*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
905*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
906*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
907*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
908*1f6eb021SLiane Praza  */
909*1f6eb021SLiane Praza static int
910*1f6eb021SLiane Praza _get_snapshot(scf_instance_t *inst, const char *snapshot,
911*1f6eb021SLiane Praza     scf_snapshot_t **snap)
912*1f6eb021SLiane Praza {
913*1f6eb021SLiane Praza 	int err;
914*1f6eb021SLiane Praza 	scf_handle_t *h;
915*1f6eb021SLiane Praza 
916*1f6eb021SLiane Praza 	h = scf_instance_handle(inst);
917*1f6eb021SLiane Praza 	if (h == NULL)
918*1f6eb021SLiane Praza 		return (-1);
919*1f6eb021SLiane Praza 
920*1f6eb021SLiane Praza 	if ((*snap = scf_snapshot_create(h)) == NULL) {
921*1f6eb021SLiane Praza 		return (-1);
922*1f6eb021SLiane Praza 	}
923*1f6eb021SLiane Praza 
924*1f6eb021SLiane Praza 	/* Use running snapshot by default. */
925*1f6eb021SLiane Praza 	if (snapshot == NULL)
926*1f6eb021SLiane Praza 		err = scf_instance_get_snapshot(inst, "running", *snap);
927*1f6eb021SLiane Praza 	else
928*1f6eb021SLiane Praza 		err = scf_instance_get_snapshot(inst, snapshot, *snap);
929*1f6eb021SLiane Praza 
930*1f6eb021SLiane Praza 	if (err != 0) {
931*1f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
932*1f6eb021SLiane Praza 			scf_snapshot_destroy(*snap);
933*1f6eb021SLiane Praza 			*snap = NULL;
934*1f6eb021SLiane Praza 			return (-1);
935*1f6eb021SLiane Praza 		} else switch (scf_error()) {
936*1f6eb021SLiane Praza 		case SCF_ERROR_INVALID_ARGUMENT:
937*1f6eb021SLiane Praza 			scf_snapshot_destroy(*snap);
938*1f6eb021SLiane Praza 			*snap = NULL;
939*1f6eb021SLiane Praza 			return (-1);
940*1f6eb021SLiane Praza 
941*1f6eb021SLiane Praza 		case SCF_ERROR_NOT_FOUND:
942*1f6eb021SLiane Praza 			scf_snapshot_destroy(*snap);
943*1f6eb021SLiane Praza 			*snap = NULL;
944*1f6eb021SLiane Praza 			return (0);
945*1f6eb021SLiane Praza 
946*1f6eb021SLiane Praza 		case SCF_ERROR_NOT_SET:
947*1f6eb021SLiane Praza 		case SCF_ERROR_HANDLE_MISMATCH:
948*1f6eb021SLiane Praza 		default:
949*1f6eb021SLiane Praza 			assert(0);
950*1f6eb021SLiane Praza 			abort();
951*1f6eb021SLiane Praza 		}
952*1f6eb021SLiane Praza 	}
953*1f6eb021SLiane Praza 
954*1f6eb021SLiane Praza 	/*
955*1f6eb021SLiane Praza 	 * Explicitly set SCF_ERROR_NONE so that the SCF_ERROR_NOT_FOUND
956*1f6eb021SLiane Praza 	 * return above is explicitly guaranteed to be from
957*1f6eb021SLiane Praza 	 * scf_instance_get_snapshot().
958*1f6eb021SLiane Praza 	 */
959*1f6eb021SLiane Praza 	(void) scf_set_error(SCF_ERROR_NONE);
960*1f6eb021SLiane Praza 	return (0);
961*1f6eb021SLiane Praza }
962*1f6eb021SLiane Praza 
963*1f6eb021SLiane Praza /*
964*1f6eb021SLiane Praza  * Returns NULL on error, sets scf_error() to:
965*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
966*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
967*1f6eb021SLiane Praza  *   SCF_ERROR_CONSTRAINT_VIOLATED
968*1f6eb021SLiane Praza  *     The restarter's FMRI does not match an existing instance.
969*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
970*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
971*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
972*1f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
973*1f6eb021SLiane Praza  *     The restarter's FMRI is not a valid FMRI.
974*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
975*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
976*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
977*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
978*1f6eb021SLiane Praza  *     Property doesn't exist or exists and has no value.
979*1f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
980*1f6eb021SLiane Praza  *     restarter property is not SCF_TYPE_ASTRING or has more than one value
981*1f6eb021SLiane Praza  */
982*1f6eb021SLiane Praza static scf_instance_t *
983*1f6eb021SLiane Praza _get_restarter_inst(scf_handle_t *h, scf_service_t *svc,
984*1f6eb021SLiane Praza     scf_instance_t *inst, scf_snapshot_t *s)
985*1f6eb021SLiane Praza {
986*1f6eb021SLiane Praza 	char *restarter = NULL;
987*1f6eb021SLiane Praza 	scf_instance_t *ri = NULL;
988*1f6eb021SLiane Praza 	scf_propertygroup_t *pg = NULL;
989*1f6eb021SLiane Praza 	int ret = 0;
990*1f6eb021SLiane Praza 
991*1f6eb021SLiane Praza 	assert(svc != NULL || inst != NULL);
992*1f6eb021SLiane Praza 	assert(svc ==  NULL || inst == NULL);
993*1f6eb021SLiane Praza 
994*1f6eb021SLiane Praza 	if ((ri = scf_instance_create(h)) == NULL ||
995*1f6eb021SLiane Praza 	    (pg = scf_pg_create(h)) == NULL) {
996*1f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_INVALID_ARGUMENT);
997*1f6eb021SLiane Praza 		scf_instance_destroy(ri);
998*1f6eb021SLiane Praza 		return (NULL);
999*1f6eb021SLiane Praza 	}
1000*1f6eb021SLiane Praza 
1001*1f6eb021SLiane Praza 	if (inst != NULL)
1002*1f6eb021SLiane Praza 		ret = scf_instance_get_pg_composed(inst, s, SCF_PG_GENERAL,
1003*1f6eb021SLiane Praza 		    pg);
1004*1f6eb021SLiane Praza 	else
1005*1f6eb021SLiane Praza 		ret = scf_service_get_pg(svc, SCF_PG_GENERAL, pg);
1006*1f6eb021SLiane Praza 
1007*1f6eb021SLiane Praza 	if (ret != 0) {
1008*1f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
1009*1f6eb021SLiane Praza 			goto _get_restarter_inst_fail;
1010*1f6eb021SLiane Praza 		} else switch (scf_error()) {
1011*1f6eb021SLiane Praza 		case SCF_ERROR_NOT_FOUND:
1012*1f6eb021SLiane Praza 			/* Assume default restarter. */
1013*1f6eb021SLiane Praza 			break;
1014*1f6eb021SLiane Praza 
1015*1f6eb021SLiane Praza 		case SCF_ERROR_NOT_SET:
1016*1f6eb021SLiane Praza 		case SCF_ERROR_HANDLE_MISMATCH:
1017*1f6eb021SLiane Praza 			/*
1018*1f6eb021SLiane Praza 			 * If the arguments to the above functions
1019*1f6eb021SLiane Praza 			 * aren't derived from the same handle, there's
1020*1f6eb021SLiane Praza 			 * something wrong with the internal implementation,
1021*1f6eb021SLiane Praza 			 * not the public caller further up the chain.
1022*1f6eb021SLiane Praza 			 */
1023*1f6eb021SLiane Praza 		case SCF_ERROR_INVALID_ARGUMENT:
1024*1f6eb021SLiane Praza 		default:
1025*1f6eb021SLiane Praza 			assert(0);
1026*1f6eb021SLiane Praza 			abort();
1027*1f6eb021SLiane Praza 		}
1028*1f6eb021SLiane Praza 	} else {
1029*1f6eb021SLiane Praza 		restarter = _scf_read_single_astring_from_pg(pg,
1030*1f6eb021SLiane Praza 		    SCF_PROPERTY_RESTARTER);
1031*1f6eb021SLiane Praza 		/* zero length string is NOT a valid restarter */
1032*1f6eb021SLiane Praza 		if (restarter != NULL && restarter[0] == '\0') {
1033*1f6eb021SLiane Praza 			free(restarter);
1034*1f6eb021SLiane Praza 			restarter = NULL;
1035*1f6eb021SLiane Praza 		} else if (restarter == NULL) {
1036*1f6eb021SLiane Praza 			if (ismember(scf_error(), errors_server)) {
1037*1f6eb021SLiane Praza 				goto _get_restarter_inst_fail;
1038*1f6eb021SLiane Praza 			} else switch (scf_error()) {
1039*1f6eb021SLiane Praza 			case SCF_ERROR_NOT_FOUND:
1040*1f6eb021SLiane Praza 				break;
1041*1f6eb021SLiane Praza 
1042*1f6eb021SLiane Praza 			case SCF_ERROR_CONSTRAINT_VIOLATED:
1043*1f6eb021SLiane Praza 			case SCF_ERROR_TYPE_MISMATCH:
1044*1f6eb021SLiane Praza 				(void) scf_set_error(
1045*1f6eb021SLiane Praza 				    SCF_ERROR_TEMPLATE_INVALID);
1046*1f6eb021SLiane Praza 				goto _get_restarter_inst_fail;
1047*1f6eb021SLiane Praza 
1048*1f6eb021SLiane Praza 			case SCF_ERROR_NOT_SET:
1049*1f6eb021SLiane Praza 			case SCF_ERROR_INVALID_ARGUMENT:
1050*1f6eb021SLiane Praza 			default:
1051*1f6eb021SLiane Praza 				assert(0);
1052*1f6eb021SLiane Praza 				abort();
1053*1f6eb021SLiane Praza 			}
1054*1f6eb021SLiane Praza 		}
1055*1f6eb021SLiane Praza 	}
1056*1f6eb021SLiane Praza 
1057*1f6eb021SLiane Praza 	if (restarter == NULL) {
1058*1f6eb021SLiane Praza 		/* Use default restarter */
1059*1f6eb021SLiane Praza 		restarter = strdup(SCF_SERVICE_STARTD);
1060*1f6eb021SLiane Praza 		if (restarter == NULL) {
1061*1f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
1062*1f6eb021SLiane Praza 			goto _get_restarter_inst_fail;
1063*1f6eb021SLiane Praza 		}
1064*1f6eb021SLiane Praza 	}
1065*1f6eb021SLiane Praza 
1066*1f6eb021SLiane Praza 	if (scf_handle_decode_fmri(h, restarter, NULL, NULL, ri, NULL, NULL,
1067*1f6eb021SLiane Praza 	    SCF_DECODE_FMRI_EXACT|SCF_DECODE_FMRI_REQUIRE_INSTANCE) != 0) {
1068*1f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
1069*1f6eb021SLiane Praza 			uu_free(restarter);
1070*1f6eb021SLiane Praza 			goto _get_restarter_inst_fail;
1071*1f6eb021SLiane Praza 		} else switch (scf_error()) {
1072*1f6eb021SLiane Praza 		case SCF_ERROR_CONSTRAINT_VIOLATED:
1073*1f6eb021SLiane Praza 		case SCF_ERROR_INVALID_ARGUMENT:
1074*1f6eb021SLiane Praza 		case SCF_ERROR_NOT_FOUND:
1075*1f6eb021SLiane Praza 			free(restarter);
1076*1f6eb021SLiane Praza 			goto _get_restarter_inst_fail;
1077*1f6eb021SLiane Praza 
1078*1f6eb021SLiane Praza 		case SCF_ERROR_HANDLE_MISMATCH:
1079*1f6eb021SLiane Praza 		case SCF_ERROR_NOT_SET:
1080*1f6eb021SLiane Praza 		default:
1081*1f6eb021SLiane Praza 			assert(0);
1082*1f6eb021SLiane Praza 			abort();
1083*1f6eb021SLiane Praza 		}
1084*1f6eb021SLiane Praza 	}
1085*1f6eb021SLiane Praza 	free(restarter);
1086*1f6eb021SLiane Praza 	scf_pg_destroy(pg);
1087*1f6eb021SLiane Praza 
1088*1f6eb021SLiane Praza 	return (ri);
1089*1f6eb021SLiane Praza 
1090*1f6eb021SLiane Praza _get_restarter_inst_fail:
1091*1f6eb021SLiane Praza 	scf_instance_destroy(ri);
1092*1f6eb021SLiane Praza 	scf_pg_destroy(pg);
1093*1f6eb021SLiane Praza 	return (NULL);
1094*1f6eb021SLiane Praza }
1095*1f6eb021SLiane Praza 
1096*1f6eb021SLiane Praza /*
1097*1f6eb021SLiane Praza  * Returns NULL on error, sets scf_error() to:
1098*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
1099*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
1100*1f6eb021SLiane Praza  *   SCF_ERROR_CONSTRAINT_VIOLATED
1101*1f6eb021SLiane Praza  *     Restarter property has more than one value associated with it,
1102*1f6eb021SLiane Praza  *     or FMRI does not meet restrictions in scf_handle_decode_fmri() flags.
1103*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
1104*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
1105*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
1106*1f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
1107*1f6eb021SLiane Praza  *     The fmri argument in scf_handle_decode_fmri() is not a valid FMRI.
1108*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
1109*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
1110*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
1111*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
1112*1f6eb021SLiane Praza  *     Property doesn't exist or exists and has no value.
1113*1f6eb021SLiane Praza  */
1114*1f6eb021SLiane Praza static scf_instance_t *
1115*1f6eb021SLiane Praza _get_global_inst(scf_handle_t *h)
1116*1f6eb021SLiane Praza {
1117*1f6eb021SLiane Praza 	scf_instance_t *ri;
1118*1f6eb021SLiane Praza 
1119*1f6eb021SLiane Praza 	if ((ri = scf_instance_create(h)) == NULL) {
1120*1f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_INVALID_ARGUMENT);
1121*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_RESOURCES);
1122*1f6eb021SLiane Praza 		return (NULL);
1123*1f6eb021SLiane Praza 	}
1124*1f6eb021SLiane Praza 
1125*1f6eb021SLiane Praza 	if (scf_handle_decode_fmri(h, SCF_INSTANCE_GLOBAL, NULL, NULL, ri,
1126*1f6eb021SLiane Praza 	    NULL, NULL,
1127*1f6eb021SLiane Praza 	    SCF_DECODE_FMRI_EXACT|SCF_DECODE_FMRI_REQUIRE_INSTANCE) != 0) {
1128*1f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
1129*1f6eb021SLiane Praza 			scf_instance_destroy(ri);
1130*1f6eb021SLiane Praza 			return (NULL);
1131*1f6eb021SLiane Praza 		} else switch (scf_error()) {
1132*1f6eb021SLiane Praza 		case SCF_ERROR_CONSTRAINT_VIOLATED:
1133*1f6eb021SLiane Praza 		case SCF_ERROR_INVALID_ARGUMENT:
1134*1f6eb021SLiane Praza 		case SCF_ERROR_NOT_FOUND:
1135*1f6eb021SLiane Praza 			scf_instance_destroy(ri);
1136*1f6eb021SLiane Praza 			return (NULL);
1137*1f6eb021SLiane Praza 
1138*1f6eb021SLiane Praza 		case SCF_ERROR_HANDLE_MISMATCH:
1139*1f6eb021SLiane Praza 		case SCF_ERROR_NOT_SET:
1140*1f6eb021SLiane Praza 		default:
1141*1f6eb021SLiane Praza 			assert(0);
1142*1f6eb021SLiane Praza 			abort();
1143*1f6eb021SLiane Praza 		}
1144*1f6eb021SLiane Praza 	}
1145*1f6eb021SLiane Praza 
1146*1f6eb021SLiane Praza 	return (ri);
1147*1f6eb021SLiane Praza }
1148*1f6eb021SLiane Praza 
1149*1f6eb021SLiane Praza /*
1150*1f6eb021SLiane Praza  * Call the supplied function for each of the service or instance, the
1151*1f6eb021SLiane Praza  * service's restarter, and the globally defined template instance.
1152*1f6eb021SLiane Praza  * If the function returns SCF_WALK_ERROR, the walk is ended.  If
1153*1f6eb021SLiane Praza  * the function returns SCF_WALK_NEXT, the next entity is tried.
1154*1f6eb021SLiane Praza  *
1155*1f6eb021SLiane Praza  * The function is only expected to return SCF_WALK_DONE if it has
1156*1f6eb021SLiane Praza  * found a property group match in the current entity, and has
1157*1f6eb021SLiane Praza  * populated p->pw_pg with the matching property group.
1158*1f6eb021SLiane Praza  */
1159*1f6eb021SLiane Praza static void
1160*1f6eb021SLiane Praza _walk_template_instances(scf_service_t *svc, scf_instance_t *inst,
1161*1f6eb021SLiane Praza     scf_snapshot_t *snap, walk_template_inst_func_t *func,
1162*1f6eb021SLiane Praza     pg_tmpl_walk_t *p, int flag)
1163*1f6eb021SLiane Praza {
1164*1f6eb021SLiane Praza 	scf_instance_t *tmpl_inst = NULL;
1165*1f6eb021SLiane Praza 	scf_handle_t *h;
1166*1f6eb021SLiane Praza 	int ret;
1167*1f6eb021SLiane Praza 	char *tg = NULL;
1168*1f6eb021SLiane Praza 
1169*1f6eb021SLiane Praza 	assert(svc != NULL || inst != NULL);
1170*1f6eb021SLiane Praza 	assert(svc == NULL || inst == NULL);
1171*1f6eb021SLiane Praza 
1172*1f6eb021SLiane Praza 	if (inst != NULL)
1173*1f6eb021SLiane Praza 		h = scf_instance_handle(inst);
1174*1f6eb021SLiane Praza 	else
1175*1f6eb021SLiane Praza 		h = scf_service_handle(svc);
1176*1f6eb021SLiane Praza 	if (h == NULL)
1177*1f6eb021SLiane Praza 		goto done;
1178*1f6eb021SLiane Praza 
1179*1f6eb021SLiane Praza 	/* First, use supplied service or instance */
1180*1f6eb021SLiane Praza 	p->pw_target = SCF_TM_TARGET_THIS;
1181*1f6eb021SLiane Praza 	ret = func(svc, inst, p);
1182*1f6eb021SLiane Praza 	switch (ret) {
1183*1f6eb021SLiane Praza 	case SCF_WALK_NEXT:
1184*1f6eb021SLiane Praza 		break;
1185*1f6eb021SLiane Praza 	case SCF_WALK_DONE:
1186*1f6eb021SLiane Praza 		/*
1187*1f6eb021SLiane Praza 		 * Check that the template scoping matches and if not,
1188*1f6eb021SLiane Praza 		 * continue.
1189*1f6eb021SLiane Praza 		 */
1190*1f6eb021SLiane Praza 		assert(p->pw_pg != NULL);
1191*1f6eb021SLiane Praza 		tg = _scf_read_single_astring_from_pg(p->pw_pg,
1192*1f6eb021SLiane Praza 		    SCF_PROPERTY_TM_TARGET);
1193*1f6eb021SLiane Praza 		if (tg == NULL || /* scf_error() was set */
1194*1f6eb021SLiane Praza 		    (strcmp(tg, SCF_TM_TARGET_INSTANCE) != 0 &&
1195*1f6eb021SLiane Praza 		    strcmp(tg, SCF_TM_TARGET_THIS) != 0 &&
1196*1f6eb021SLiane Praza 		    (flag & SCF_PG_TMPL_FLAG_EXACT) !=
1197*1f6eb021SLiane Praza 		    SCF_PG_TMPL_FLAG_EXACT)) {
1198*1f6eb021SLiane Praza 			scf_pg_destroy(p->pw_pg);
1199*1f6eb021SLiane Praza 			p->pw_pg = NULL;
1200*1f6eb021SLiane Praza 			if (tg != NULL) {
1201*1f6eb021SLiane Praza 				free(tg);
1202*1f6eb021SLiane Praza 				tg = NULL;
1203*1f6eb021SLiane Praza 				break;
1204*1f6eb021SLiane Praza 			}
1205*1f6eb021SLiane Praza 		}
1206*1f6eb021SLiane Praza 		/*FALLTHROUGH*/
1207*1f6eb021SLiane Praza 	case SCF_WALK_ERROR:
1208*1f6eb021SLiane Praza 		goto done;
1209*1f6eb021SLiane Praza 		/*NOTREACHED*/
1210*1f6eb021SLiane Praza 	default:
1211*1f6eb021SLiane Praza 		assert(0);
1212*1f6eb021SLiane Praza 		abort();
1213*1f6eb021SLiane Praza 	}
1214*1f6eb021SLiane Praza 
1215*1f6eb021SLiane Praza 	/* Next the restarter. */
1216*1f6eb021SLiane Praza 	p->pw_target = SCF_TM_TARGET_DELEGATE;
1217*1f6eb021SLiane Praza 	tmpl_inst = _get_restarter_inst(h, svc, inst, snap);
1218*1f6eb021SLiane Praza 	if (tmpl_inst != NULL) {
1219*1f6eb021SLiane Praza 		ret = func(NULL, tmpl_inst, p);
1220*1f6eb021SLiane Praza 		switch (ret) {
1221*1f6eb021SLiane Praza 		case SCF_WALK_NEXT:
1222*1f6eb021SLiane Praza 			break;
1223*1f6eb021SLiane Praza 		case SCF_WALK_DONE:
1224*1f6eb021SLiane Praza 			/*
1225*1f6eb021SLiane Praza 			 * Check that the template scoping matches and if not,
1226*1f6eb021SLiane Praza 			 * continue.
1227*1f6eb021SLiane Praza 			 */
1228*1f6eb021SLiane Praza 			assert(p->pw_pg != NULL);
1229*1f6eb021SLiane Praza 			tg = _scf_read_single_astring_from_pg(p->pw_pg,
1230*1f6eb021SLiane Praza 			    SCF_PROPERTY_TM_TARGET);
1231*1f6eb021SLiane Praza 			if (tg == NULL || /* scf_error() was set */
1232*1f6eb021SLiane Praza 			    strcmp(tg, SCF_TM_TARGET_DELEGATE) != 0) {
1233*1f6eb021SLiane Praza 				scf_pg_destroy(p->pw_pg);
1234*1f6eb021SLiane Praza 				p->pw_pg = NULL;
1235*1f6eb021SLiane Praza 				if (tg != NULL) {
1236*1f6eb021SLiane Praza 					free(tg);
1237*1f6eb021SLiane Praza 					tg = NULL;
1238*1f6eb021SLiane Praza 					break;
1239*1f6eb021SLiane Praza 				}
1240*1f6eb021SLiane Praza 			}
1241*1f6eb021SLiane Praza 			/*FALLTHROUGH*/
1242*1f6eb021SLiane Praza 		case SCF_WALK_ERROR:
1243*1f6eb021SLiane Praza 			goto done;
1244*1f6eb021SLiane Praza 			/*NOTREACHED*/
1245*1f6eb021SLiane Praza 		default:
1246*1f6eb021SLiane Praza 			assert(0);
1247*1f6eb021SLiane Praza 			abort();
1248*1f6eb021SLiane Praza 		}
1249*1f6eb021SLiane Praza 	}
1250*1f6eb021SLiane Praza 
1251*1f6eb021SLiane Praza 	p->pw_target = SCF_TM_TARGET_ALL;
1252*1f6eb021SLiane Praza 	scf_instance_destroy(tmpl_inst);
1253*1f6eb021SLiane Praza 	tmpl_inst = _get_global_inst(h);
1254*1f6eb021SLiane Praza 	if (tmpl_inst != NULL) {
1255*1f6eb021SLiane Praza 		ret = func(NULL, tmpl_inst, p);
1256*1f6eb021SLiane Praza 		switch (ret) {
1257*1f6eb021SLiane Praza 		case SCF_WALK_NEXT:
1258*1f6eb021SLiane Praza 			break;
1259*1f6eb021SLiane Praza 		case SCF_WALK_DONE:
1260*1f6eb021SLiane Praza 			/*
1261*1f6eb021SLiane Praza 			 * Check that the template scoping matches and if not,
1262*1f6eb021SLiane Praza 			 * continue.
1263*1f6eb021SLiane Praza 			 */
1264*1f6eb021SLiane Praza 			assert(p->pw_pg != NULL);
1265*1f6eb021SLiane Praza 			tg = _scf_read_single_astring_from_pg(p->pw_pg,
1266*1f6eb021SLiane Praza 			    SCF_PROPERTY_TM_TARGET);
1267*1f6eb021SLiane Praza 			if (tg == NULL || /* scf_error() was set */
1268*1f6eb021SLiane Praza 			    strcmp(tg, SCF_TM_TARGET_ALL) != 0) {
1269*1f6eb021SLiane Praza 				scf_pg_destroy(p->pw_pg);
1270*1f6eb021SLiane Praza 				p->pw_pg = NULL;
1271*1f6eb021SLiane Praza 				if (tg != NULL) {
1272*1f6eb021SLiane Praza 					free(tg);
1273*1f6eb021SLiane Praza 					tg = NULL;
1274*1f6eb021SLiane Praza 					break;
1275*1f6eb021SLiane Praza 				}
1276*1f6eb021SLiane Praza 			}
1277*1f6eb021SLiane Praza 			/*FALLTHROUGH*/
1278*1f6eb021SLiane Praza 		case SCF_WALK_ERROR:
1279*1f6eb021SLiane Praza 			goto done;
1280*1f6eb021SLiane Praza 			/*NOTREACHED*/
1281*1f6eb021SLiane Praza 		default:
1282*1f6eb021SLiane Praza 			assert(0);
1283*1f6eb021SLiane Praza 			abort();
1284*1f6eb021SLiane Praza 		}
1285*1f6eb021SLiane Praza 	}
1286*1f6eb021SLiane Praza 
1287*1f6eb021SLiane Praza done:
1288*1f6eb021SLiane Praza 	free(tg);
1289*1f6eb021SLiane Praza 	if (ret != SCF_WALK_DONE)
1290*1f6eb021SLiane Praza 		scf_instance_destroy(tmpl_inst);
1291*1f6eb021SLiane Praza 	p->pw_target = NULL;
1292*1f6eb021SLiane Praza }
1293*1f6eb021SLiane Praza 
1294*1f6eb021SLiane Praza /*
1295*1f6eb021SLiane Praza  * _get_pg() returns 0 on success and -1 on failure.  Sets scf_error()
1296*1f6eb021SLiane Praza  * on failure.
1297*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
1298*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
1299*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
1300*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_MISMATCH
1301*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
1302*1f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
1303*1f6eb021SLiane Praza  *     name is not a valid property group.
1304*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
1305*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
1306*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
1307*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_SET
1308*1f6eb021SLiane Praza  */
1309*1f6eb021SLiane Praza static int
1310*1f6eb021SLiane Praza _get_pg(scf_service_t *svc, scf_instance_t *inst,
1311*1f6eb021SLiane Praza     const scf_snapshot_t *snap, const char *name, scf_propertygroup_t *pg)
1312*1f6eb021SLiane Praza {
1313*1f6eb021SLiane Praza 	int ret;
1314*1f6eb021SLiane Praza 
1315*1f6eb021SLiane Praza 	assert(svc != NULL || inst != NULL);
1316*1f6eb021SLiane Praza 	assert(svc == NULL || inst == NULL);
1317*1f6eb021SLiane Praza 	assert(pg != NULL);
1318*1f6eb021SLiane Praza 
1319*1f6eb021SLiane Praza 	if (inst != NULL)
1320*1f6eb021SLiane Praza 		ret = scf_instance_get_pg_composed(inst, snap, name, pg);
1321*1f6eb021SLiane Praza 	else
1322*1f6eb021SLiane Praza 		ret = scf_service_get_pg(svc, name, pg);
1323*1f6eb021SLiane Praza 
1324*1f6eb021SLiane Praza 	return (ret);
1325*1f6eb021SLiane Praza }
1326*1f6eb021SLiane Praza 
1327*1f6eb021SLiane Praza /*
1328*1f6eb021SLiane Praza  * Returns SCF_WALK_NEXT for not found, SCF_WALK_ERROR for error,
1329*1f6eb021SLiane Praza  * and SCF_WALK_DONE for found.
1330*1f6eb021SLiane Praza  * On error, destroy pg and set it to NULL.
1331*1f6eb021SLiane Praza  *
1332*1f6eb021SLiane Praza  * Sets scf_error() if SCF_WALK_ERROR is returned to _BACKEND_ACCESS,
1333*1f6eb021SLiane Praza  * _CONNECTION_BROKEN, _INTERNAL, _INVALID_ARGUMENT (name is not a
1334*1f6eb021SLiane Praza  *  valid property group), _NO_RESOURCES, or _NOT_BOUND.
1335*1f6eb021SLiane Praza  */
1336*1f6eb021SLiane Praza static int
1337*1f6eb021SLiane Praza _lookup_pg(scf_service_t *svc, scf_instance_t *inst,
1338*1f6eb021SLiane Praza     const scf_snapshot_t *snap, const char *name, scf_propertygroup_t *pg)
1339*1f6eb021SLiane Praza {
1340*1f6eb021SLiane Praza 	int ret;
1341*1f6eb021SLiane Praza 
1342*1f6eb021SLiane Praza 	ret = _get_pg(svc, inst, snap, name, pg);
1343*1f6eb021SLiane Praza 
1344*1f6eb021SLiane Praza 	if (ret == 0) {
1345*1f6eb021SLiane Praza 		return (SCF_WALK_DONE);
1346*1f6eb021SLiane Praza 	} else {
1347*1f6eb021SLiane Praza 		switch (scf_error()) {
1348*1f6eb021SLiane Praza 		case SCF_ERROR_NOT_FOUND:
1349*1f6eb021SLiane Praza 		case SCF_ERROR_DELETED:
1350*1f6eb021SLiane Praza 			return (SCF_WALK_NEXT);
1351*1f6eb021SLiane Praza 
1352*1f6eb021SLiane Praza 		case SCF_ERROR_BACKEND_ACCESS:
1353*1f6eb021SLiane Praza 		case SCF_ERROR_CONNECTION_BROKEN:
1354*1f6eb021SLiane Praza 		case SCF_ERROR_INTERNAL:
1355*1f6eb021SLiane Praza 		case SCF_ERROR_INVALID_ARGUMENT:
1356*1f6eb021SLiane Praza 		case SCF_ERROR_NOT_BOUND:
1357*1f6eb021SLiane Praza 		case SCF_ERROR_NO_RESOURCES:
1358*1f6eb021SLiane Praza 			scf_pg_destroy(pg);
1359*1f6eb021SLiane Praza 			pg = NULL;
1360*1f6eb021SLiane Praza 			return (SCF_WALK_ERROR);
1361*1f6eb021SLiane Praza 
1362*1f6eb021SLiane Praza 		case SCF_ERROR_NOT_SET:
1363*1f6eb021SLiane Praza 		case SCF_ERROR_HANDLE_MISMATCH:
1364*1f6eb021SLiane Praza 		default:
1365*1f6eb021SLiane Praza 			assert(0);
1366*1f6eb021SLiane Praza 			abort();
1367*1f6eb021SLiane Praza 		}
1368*1f6eb021SLiane Praza 	}
1369*1f6eb021SLiane Praza 
1370*1f6eb021SLiane Praza 	/*NOTREACHED*/
1371*1f6eb021SLiane Praza }
1372*1f6eb021SLiane Praza 
1373*1f6eb021SLiane Praza /*
1374*1f6eb021SLiane Praza  * If match, return 0.  If no match, return 1.  If error, return -1.
1375*1f6eb021SLiane Praza  * On error set scf_error() to _BACKEND_ACCESS, _CONNECTION_BROKEN,
1376*1f6eb021SLiane Praza  * _HANDLE_DESTROYED, _INTERNAL, _NO_MEMORY, _NO_RESOURCES, _NOT_BOUND,
1377*1f6eb021SLiane Praza  * _NOT_SET (property group specified by pg is not set), _PERMISSION_DENIED,
1378*1f6eb021SLiane Praza  * or _TEMPLATE_INVALID (target property is not SCF_TYPE_ASTRING or has
1379*1f6eb021SLiane Praza  * more than one value).
1380*1f6eb021SLiane Praza  */
1381*1f6eb021SLiane Praza static int
1382*1f6eb021SLiane Praza check_target_match(scf_propertygroup_t *pg, const char *target)
1383*1f6eb021SLiane Praza {
1384*1f6eb021SLiane Praza 	char *pg_target;
1385*1f6eb021SLiane Praza 	int ret = 0;
1386*1f6eb021SLiane Praza 
1387*1f6eb021SLiane Praza 	pg_target = _scf_read_single_astring_from_pg(pg,
1388*1f6eb021SLiane Praza 	    SCF_PROPERTY_TM_TARGET);
1389*1f6eb021SLiane Praza 	if (pg_target == NULL) {
1390*1f6eb021SLiane Praza 		switch (scf_error()) {
1391*1f6eb021SLiane Praza 		case SCF_ERROR_DELETED:
1392*1f6eb021SLiane Praza 		case SCF_ERROR_NOT_FOUND:
1393*1f6eb021SLiane Praza 			return (1);
1394*1f6eb021SLiane Praza 
1395*1f6eb021SLiane Praza 		case SCF_ERROR_CONSTRAINT_VIOLATED:
1396*1f6eb021SLiane Praza 		case SCF_ERROR_TYPE_MISMATCH:
1397*1f6eb021SLiane Praza 			(void) scf_set_error(
1398*1f6eb021SLiane Praza 			    SCF_ERROR_TEMPLATE_INVALID);
1399*1f6eb021SLiane Praza 			/*FALLTHROUGH*/
1400*1f6eb021SLiane Praza 
1401*1f6eb021SLiane Praza 		case SCF_ERROR_BACKEND_ACCESS:
1402*1f6eb021SLiane Praza 		case SCF_ERROR_CONNECTION_BROKEN:
1403*1f6eb021SLiane Praza 		case SCF_ERROR_HANDLE_DESTROYED:
1404*1f6eb021SLiane Praza 		case SCF_ERROR_INTERNAL:
1405*1f6eb021SLiane Praza 		case SCF_ERROR_NO_RESOURCES:
1406*1f6eb021SLiane Praza 		case SCF_ERROR_NOT_BOUND:
1407*1f6eb021SLiane Praza 		case SCF_ERROR_PERMISSION_DENIED:
1408*1f6eb021SLiane Praza 			return (-1);
1409*1f6eb021SLiane Praza 
1410*1f6eb021SLiane Praza 		case SCF_ERROR_NOT_SET:
1411*1f6eb021SLiane Praza 		case SCF_ERROR_INVALID_ARGUMENT:
1412*1f6eb021SLiane Praza 		default:
1413*1f6eb021SLiane Praza 			assert(0);
1414*1f6eb021SLiane Praza 			abort();
1415*1f6eb021SLiane Praza 		}
1416*1f6eb021SLiane Praza 		/*NOTREACHED*/
1417*1f6eb021SLiane Praza 	}
1418*1f6eb021SLiane Praza 
1419*1f6eb021SLiane Praza 	/* For a desired target of 'this', check for 'this' and 'instance'. */
1420*1f6eb021SLiane Praza 	if ((strcmp(target, SCF_TM_TARGET_INSTANCE) == 0 ||
1421*1f6eb021SLiane Praza 	    strcmp(target, SCF_TM_TARGET_THIS) == 0) &&
1422*1f6eb021SLiane Praza 	    (strcmp(pg_target, SCF_TM_TARGET_INSTANCE) == 0 ||
1423*1f6eb021SLiane Praza 	    strcmp(pg_target, SCF_TM_TARGET_THIS) == 0)) {
1424*1f6eb021SLiane Praza 		goto cleanup;
1425*1f6eb021SLiane Praza 	}
1426*1f6eb021SLiane Praza 
1427*1f6eb021SLiane Praza 	if (strcmp(target, SCF_TM_TARGET_DELEGATE) == 0 &&
1428*1f6eb021SLiane Praza 	    strcmp(pg_target, SCF_TM_TARGET_DELEGATE) == 0) {
1429*1f6eb021SLiane Praza 		goto cleanup;
1430*1f6eb021SLiane Praza 	}
1431*1f6eb021SLiane Praza 
1432*1f6eb021SLiane Praza 	if (strcmp(target, SCF_TM_TARGET_ALL) == 0 &&
1433*1f6eb021SLiane Praza 	    strcmp(pg_target, SCF_TM_TARGET_ALL) == 0) {
1434*1f6eb021SLiane Praza 		goto cleanup;
1435*1f6eb021SLiane Praza 	}
1436*1f6eb021SLiane Praza 
1437*1f6eb021SLiane Praza 	ret = 1;
1438*1f6eb021SLiane Praza cleanup:
1439*1f6eb021SLiane Praza 	free(pg_target);
1440*1f6eb021SLiane Praza 	return (ret);
1441*1f6eb021SLiane Praza }
1442*1f6eb021SLiane Praza 
1443*1f6eb021SLiane Praza /*
1444*1f6eb021SLiane Praza  * Check if a matching template property group exists for each of:
1445*1f6eb021SLiane Praza  * name and type, name only, type only, and completely wildcarded
1446*1f6eb021SLiane Praza  * template.
1447*1f6eb021SLiane Praza  *
1448*1f6eb021SLiane Praza  * Both pg_name and pg_type are optional.
1449*1f6eb021SLiane Praza  *
1450*1f6eb021SLiane Praza  * Returns NULL on failure, sets scf_error():
1451*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
1452*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
1453*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
1454*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
1455*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
1456*1f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
1457*1f6eb021SLiane Praza  *     can't combine the _tmpl_pg_name arguments and get a reasonable
1458*1f6eb021SLiane Praza  *     length name, or pg_name is not a valid property group.
1459*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
1460*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
1461*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
1462*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
1463*1f6eb021SLiane Praza  *     Property doesn't exist or exists and has no value.
1464*1f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
1465*1f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
1466*1f6eb021SLiane Praza  *     target property is not SCF_TYPE_ASTRING or has more than one value.
1467*1f6eb021SLiane Praza  */
1468*1f6eb021SLiane Praza static scf_propertygroup_t *
1469*1f6eb021SLiane Praza _find_template_pg_match(scf_service_t *svc, scf_instance_t *inst,
1470*1f6eb021SLiane Praza     const scf_snapshot_t *snap, const char *pg_name, const char *pg_type,
1471*1f6eb021SLiane Praza     const char *target, char **tmpl_pg_name)
1472*1f6eb021SLiane Praza {
1473*1f6eb021SLiane Praza 	int ret, r;
1474*1f6eb021SLiane Praza 	scf_propertygroup_t *pg = NULL;
1475*1f6eb021SLiane Praza 	scf_handle_t *h;
1476*1f6eb021SLiane Praza 	scf_iter_t *iter;
1477*1f6eb021SLiane Praza 	char *name, *type;
1478*1f6eb021SLiane Praza 
1479*1f6eb021SLiane Praza 	assert(inst != NULL || svc != NULL);
1480*1f6eb021SLiane Praza 	assert(inst == NULL || svc == NULL);
1481*1f6eb021SLiane Praza 
1482*1f6eb021SLiane Praza 	if (inst != NULL)
1483*1f6eb021SLiane Praza 		h = scf_instance_handle(inst);
1484*1f6eb021SLiane Praza 	else
1485*1f6eb021SLiane Praza 		h = scf_service_handle(svc);
1486*1f6eb021SLiane Praza 	if (h == NULL) {
1487*1f6eb021SLiane Praza 		return (NULL);
1488*1f6eb021SLiane Praza 	}
1489*1f6eb021SLiane Praza 
1490*1f6eb021SLiane Praza 	if ((pg = scf_pg_create(h)) == NULL ||
1491*1f6eb021SLiane Praza 	    (iter = scf_iter_create(h)) == NULL) {
1492*1f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_INVALID_ARGUMENT);
1493*1f6eb021SLiane Praza 		scf_pg_destroy(pg);
1494*1f6eb021SLiane Praza 		return (NULL);
1495*1f6eb021SLiane Praza 	}
1496*1f6eb021SLiane Praza 
1497*1f6eb021SLiane Praza 	/*
1498*1f6eb021SLiane Praza 	 * We're going to walk through the possible pg templates that
1499*1f6eb021SLiane Praza 	 * could match the supplied name and type.  We do this
1500*1f6eb021SLiane Praza 	 * by explicit name lookups when possible to avoid having to
1501*1f6eb021SLiane Praza 	 * keep track of a most-explicit-match during iteration.
1502*1f6eb021SLiane Praza 	 */
1503*1f6eb021SLiane Praza 
1504*1f6eb021SLiane Praza 	/* First look for a template with name and type set and matching. */
1505*1f6eb021SLiane Praza 	*tmpl_pg_name = _tmpl_pg_name(pg_name, pg_type, 1);
1506*1f6eb021SLiane Praza 	if (*tmpl_pg_name == NULL)
1507*1f6eb021SLiane Praza 		goto fail;
1508*1f6eb021SLiane Praza 	ret = _lookup_pg(svc, inst, snap, *tmpl_pg_name, pg);
1509*1f6eb021SLiane Praza 	if (ret != SCF_WALK_NEXT) {
1510*1f6eb021SLiane Praza 		if (pg != NULL) {
1511*1f6eb021SLiane Praza 			if ((r = check_target_match(pg, target)) == 0)
1512*1f6eb021SLiane Praza 				goto done;
1513*1f6eb021SLiane Praza 			else if (r == -1)
1514*1f6eb021SLiane Praza 				goto fail;
1515*1f6eb021SLiane Praza 		} else {
1516*1f6eb021SLiane Praza 			goto done;
1517*1f6eb021SLiane Praza 		}
1518*1f6eb021SLiane Praza 	}
1519*1f6eb021SLiane Praza 	free(*tmpl_pg_name);
1520*1f6eb021SLiane Praza 
1521*1f6eb021SLiane Praza 	/*
1522*1f6eb021SLiane Praza 	 * Need to search on a name-only match before searching on
1523*1f6eb021SLiane Praza 	 * type matches.
1524*1f6eb021SLiane Praza 	 */
1525*1f6eb021SLiane Praza 
1526*1f6eb021SLiane Praza 	*tmpl_pg_name = _tmpl_pg_name(pg_name, NULL, 0);
1527*1f6eb021SLiane Praza 	if (*tmpl_pg_name == NULL)
1528*1f6eb021SLiane Praza 		goto fail;
1529*1f6eb021SLiane Praza 	ret = _lookup_pg(svc, inst, snap, *tmpl_pg_name, pg);
1530*1f6eb021SLiane Praza 	if (ret != SCF_WALK_NEXT) {
1531*1f6eb021SLiane Praza 		if (pg != NULL) {
1532*1f6eb021SLiane Praza 			if ((r = check_target_match(pg, target)) == 0)
1533*1f6eb021SLiane Praza 				goto done;
1534*1f6eb021SLiane Praza 			else if (r == -1)
1535*1f6eb021SLiane Praza 				goto fail;
1536*1f6eb021SLiane Praza 		} else {
1537*1f6eb021SLiane Praza 			goto done;
1538*1f6eb021SLiane Praza 		}
1539*1f6eb021SLiane Praza 	}
1540*1f6eb021SLiane Praza 	free(*tmpl_pg_name);
1541*1f6eb021SLiane Praza 
1542*1f6eb021SLiane Praza 	/* Next, see if there's an "nt" template where the type matches. */
1543*1f6eb021SLiane Praza 	if (pg_type != NULL && pg_name == NULL) {
1544*1f6eb021SLiane Praza 		if (inst != NULL)
1545*1f6eb021SLiane Praza 			ret = scf_iter_instance_pgs_typed_composed(iter, inst,
1546*1f6eb021SLiane Praza 			    snap, SCF_GROUP_TEMPLATE_PG_PATTERN);
1547*1f6eb021SLiane Praza 		else
1548*1f6eb021SLiane Praza 			ret = scf_iter_service_pgs_typed(iter, svc,
1549*1f6eb021SLiane Praza 			    SCF_GROUP_TEMPLATE_PG_PATTERN);
1550*1f6eb021SLiane Praza 
1551*1f6eb021SLiane Praza 		if (ret != 0) {
1552*1f6eb021SLiane Praza 			if (ismember(scf_error(), errors_server)) {
1553*1f6eb021SLiane Praza 				goto fail;
1554*1f6eb021SLiane Praza 			} else {
1555*1f6eb021SLiane Praza 				assert(0);
1556*1f6eb021SLiane Praza 				abort();
1557*1f6eb021SLiane Praza 			}
1558*1f6eb021SLiane Praza 		}
1559*1f6eb021SLiane Praza 
1560*1f6eb021SLiane Praza 		while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
1561*1f6eb021SLiane Praza 			/* Make sure this is a name and type specified pg. */
1562*1f6eb021SLiane Praza 			name = _scf_read_single_astring_from_pg(pg,
1563*1f6eb021SLiane Praza 			    SCF_PROPERTY_TM_NAME);
1564*1f6eb021SLiane Praza 			if (name == NULL)
1565*1f6eb021SLiane Praza 				continue;
1566*1f6eb021SLiane Praza 			type = _scf_read_single_astring_from_pg(pg,
1567*1f6eb021SLiane Praza 			    SCF_PROPERTY_TM_TYPE);
1568*1f6eb021SLiane Praza 			if (type == NULL) {
1569*1f6eb021SLiane Praza 				free(name);
1570*1f6eb021SLiane Praza 				continue;
1571*1f6eb021SLiane Praza 			}
1572*1f6eb021SLiane Praza 			if (strcmp(pg_type, type) == 0 &&
1573*1f6eb021SLiane Praza 			    check_target_match(pg, target) == 0) {
1574*1f6eb021SLiane Praza 				*tmpl_pg_name = name;
1575*1f6eb021SLiane Praza 				free(type);
1576*1f6eb021SLiane Praza 				goto done;
1577*1f6eb021SLiane Praza 			}
1578*1f6eb021SLiane Praza 			free(type);
1579*1f6eb021SLiane Praza 			free(name);
1580*1f6eb021SLiane Praza 		}
1581*1f6eb021SLiane Praza 		if (ret == -1) {
1582*1f6eb021SLiane Praza 			if (ismember(scf_error(), errors_server)) {
1583*1f6eb021SLiane Praza 				goto fail;
1584*1f6eb021SLiane Praza 			} else {
1585*1f6eb021SLiane Praza 				assert(0);
1586*1f6eb021SLiane Praza 				abort();
1587*1f6eb021SLiane Praza 			}
1588*1f6eb021SLiane Praza 		}
1589*1f6eb021SLiane Praza 	}
1590*1f6eb021SLiane Praza 
1591*1f6eb021SLiane Praza 	*tmpl_pg_name = _tmpl_pg_name(NULL, pg_type, 0);
1592*1f6eb021SLiane Praza 	if (*tmpl_pg_name == NULL)
1593*1f6eb021SLiane Praza 		goto fail;
1594*1f6eb021SLiane Praza 	ret = _lookup_pg(svc, inst, snap, *tmpl_pg_name, pg);
1595*1f6eb021SLiane Praza 	if (ret != SCF_WALK_NEXT) {
1596*1f6eb021SLiane Praza 		if (pg != NULL) {
1597*1f6eb021SLiane Praza 			if ((r = check_target_match(pg, target)) == 0)
1598*1f6eb021SLiane Praza 				goto done;
1599*1f6eb021SLiane Praza 			else if (r == -1)
1600*1f6eb021SLiane Praza 				goto fail;
1601*1f6eb021SLiane Praza 		} else {
1602*1f6eb021SLiane Praza 			goto done;
1603*1f6eb021SLiane Praza 		}
1604*1f6eb021SLiane Praza 	}
1605*1f6eb021SLiane Praza 	free(*tmpl_pg_name);
1606*1f6eb021SLiane Praza 
1607*1f6eb021SLiane Praza 	*tmpl_pg_name = _tmpl_pg_name(NULL, NULL, 0);
1608*1f6eb021SLiane Praza 	if (*tmpl_pg_name == NULL)
1609*1f6eb021SLiane Praza 		goto fail;
1610*1f6eb021SLiane Praza 	ret = _lookup_pg(svc, inst, snap, *tmpl_pg_name, pg);
1611*1f6eb021SLiane Praza 	if (ret != SCF_WALK_NEXT) {
1612*1f6eb021SLiane Praza 		if (pg != NULL) {
1613*1f6eb021SLiane Praza 			if ((r = check_target_match(pg, target)) == 0)
1614*1f6eb021SLiane Praza 				goto done;
1615*1f6eb021SLiane Praza 			else if (r == -1)
1616*1f6eb021SLiane Praza 				goto fail;
1617*1f6eb021SLiane Praza 		} else {
1618*1f6eb021SLiane Praza 			goto done;
1619*1f6eb021SLiane Praza 		}
1620*1f6eb021SLiane Praza 	}
1621*1f6eb021SLiane Praza 
1622*1f6eb021SLiane Praza 	(void) scf_set_error(SCF_ERROR_NOT_FOUND);
1623*1f6eb021SLiane Praza fail:
1624*1f6eb021SLiane Praza 	scf_pg_destroy(pg);
1625*1f6eb021SLiane Praza 	if (*tmpl_pg_name != NULL)
1626*1f6eb021SLiane Praza 		free(*tmpl_pg_name);
1627*1f6eb021SLiane Praza 	*tmpl_pg_name = NULL;
1628*1f6eb021SLiane Praza 	pg = NULL;
1629*1f6eb021SLiane Praza done:
1630*1f6eb021SLiane Praza 	if (ret == SCF_WALK_ERROR)
1631*1f6eb021SLiane Praza 		free(*tmpl_pg_name);
1632*1f6eb021SLiane Praza 	scf_iter_destroy(iter);
1633*1f6eb021SLiane Praza 	return (pg);
1634*1f6eb021SLiane Praza }
1635*1f6eb021SLiane Praza 
1636*1f6eb021SLiane Praza /*
1637*1f6eb021SLiane Praza  * Finds the pg match in either the supplied service or instance.
1638*1f6eb021SLiane Praza  * Returns SCF_WALK_ERROR, SCF_WALK_NEXT, or SCF_WALK_DONE.
1639*1f6eb021SLiane Praza  * If returning SCF_WALK_ERROR, sets scf_error():
1640*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
1641*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
1642*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
1643*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
1644*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
1645*1f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
1646*1f6eb021SLiane Praza  *     The snaphot is not a valid snapshot name,
1647*1f6eb021SLiane Praza  *     or can't create a reasonable property group template name.
1648*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
1649*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
1650*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
1651*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
1652*1f6eb021SLiane Praza  *     Property doesn't exist or exists and has no value.
1653*1f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
1654*1f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
1655*1f6eb021SLiane Praza  *     target property is not SCF_TYPE_ASTRING or has more than one value.
1656*1f6eb021SLiane Praza  */
1657*1f6eb021SLiane Praza static int
1658*1f6eb021SLiane Praza find_pg_match(scf_service_t *svc, scf_instance_t *inst, pg_tmpl_walk_t *p)
1659*1f6eb021SLiane Praza {
1660*1f6eb021SLiane Praza 	scf_snapshot_t *tmpl_snap = NULL;
1661*1f6eb021SLiane Praza 	scf_propertygroup_t *pg;
1662*1f6eb021SLiane Praza 	scf_handle_t *h;
1663*1f6eb021SLiane Praza 	char *tmpl_pg_name;
1664*1f6eb021SLiane Praza 
1665*1f6eb021SLiane Praza 	assert(svc != NULL || inst != NULL);
1666*1f6eb021SLiane Praza 	assert(svc == NULL || inst == NULL);
1667*1f6eb021SLiane Praza 
1668*1f6eb021SLiane Praza 	if (inst != NULL)
1669*1f6eb021SLiane Praza 		h = scf_instance_handle(inst);
1670*1f6eb021SLiane Praza 	else
1671*1f6eb021SLiane Praza 		h = scf_service_handle(svc);
1672*1f6eb021SLiane Praza 	if (h == NULL)
1673*1f6eb021SLiane Praza 		return (SCF_WALK_ERROR);
1674*1f6eb021SLiane Praza 
1675*1f6eb021SLiane Praza 	if (p->pw_snapname != NULL) {
1676*1f6eb021SLiane Praza 		if (_get_snapshot(inst, p->pw_snapname, &tmpl_snap) == -1)
1677*1f6eb021SLiane Praza 			return (SCF_WALK_ERROR);
1678*1f6eb021SLiane Praza 	}
1679*1f6eb021SLiane Praza 	pg = _find_template_pg_match(svc, inst, tmpl_snap, p->pw_pgname,
1680*1f6eb021SLiane Praza 	    p->pw_pgtype, p->pw_target, &tmpl_pg_name);
1681*1f6eb021SLiane Praza 
1682*1f6eb021SLiane Praza 	if (pg != NULL) {
1683*1f6eb021SLiane Praza 		p->pw_snap = tmpl_snap;
1684*1f6eb021SLiane Praza 		p->pw_pg = pg;
1685*1f6eb021SLiane Praza 		p->pw_tmpl_pgname = tmpl_pg_name;
1686*1f6eb021SLiane Praza 		p->pw_inst = inst;
1687*1f6eb021SLiane Praza 		p->pw_svc = svc;
1688*1f6eb021SLiane Praza 		return (SCF_WALK_DONE);
1689*1f6eb021SLiane Praza 	}
1690*1f6eb021SLiane Praza 
1691*1f6eb021SLiane Praza 	scf_snapshot_destroy(tmpl_snap);
1692*1f6eb021SLiane Praza 	return (SCF_WALK_NEXT);
1693*1f6eb021SLiane Praza }
1694*1f6eb021SLiane Praza 
1695*1f6eb021SLiane Praza /*
1696*1f6eb021SLiane Praza  * return 0 on success and -1 on failure.
1697*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
1698*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
1699*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
1700*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_MISMATCH
1701*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
1702*1f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
1703*1f6eb021SLiane Praza  *     FMRI argument, snapshot name, pg_name, or pg is invalid.
1704*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
1705*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
1706*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
1707*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
1708*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_SET
1709*1f6eb021SLiane Praza  */
1710*1f6eb021SLiane Praza int
1711*1f6eb021SLiane Praza scf_tmpl_get_by_pg(scf_propertygroup_t *pg, scf_pg_tmpl_t *pg_tmpl, int flags)
1712*1f6eb021SLiane Praza {
1713*1f6eb021SLiane Praza 	char *fmribuf = NULL, *snapbuf = NULL, *pg_name = NULL, *pg_type = NULL;
1714*1f6eb021SLiane Praza 	int ret = 0;
1715*1f6eb021SLiane Praza 	ssize_t fbufsz = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH) + 1;
1716*1f6eb021SLiane Praza 	ssize_t nbufsz = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
1717*1f6eb021SLiane Praza 	ssize_t tbufsz = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH) + 1;
1718*1f6eb021SLiane Praza 	scf_instance_t *inst = NULL;
1719*1f6eb021SLiane Praza 	scf_snaplevel_t *snaplvl = NULL;
1720*1f6eb021SLiane Praza 	scf_service_t *svc = NULL;
1721*1f6eb021SLiane Praza 	scf_handle_t *h;
1722*1f6eb021SLiane Praza 	scf_snapshot_t *snap = NULL;
1723*1f6eb021SLiane Praza 	pg_tmpl_walk_t *p;
1724*1f6eb021SLiane Praza 
1725*1f6eb021SLiane Praza 	assert(fbufsz != 0 && nbufsz != 0 && tbufsz != 0);
1726*1f6eb021SLiane Praza 
1727*1f6eb021SLiane Praza 	scf_tmpl_pg_reset(pg_tmpl);
1728*1f6eb021SLiane Praza 
1729*1f6eb021SLiane Praza 	if ((h = scf_pg_handle(pg)) == NULL)
1730*1f6eb021SLiane Praza 		return (-1);
1731*1f6eb021SLiane Praza 
1732*1f6eb021SLiane Praza 	if ((inst = scf_instance_create(h)) == NULL ||
1733*1f6eb021SLiane Praza 	    (svc = scf_service_create(h)) == NULL ||
1734*1f6eb021SLiane Praza 	    (snaplvl = scf_snaplevel_create(h)) == NULL) {
1735*1f6eb021SLiane Praza 		scf_instance_destroy(inst);
1736*1f6eb021SLiane Praza 		scf_service_destroy(svc);
1737*1f6eb021SLiane Praza 		return (-1);
1738*1f6eb021SLiane Praza 	}
1739*1f6eb021SLiane Praza 
1740*1f6eb021SLiane Praza 	if ((fmribuf = malloc(fbufsz)) == NULL ||
1741*1f6eb021SLiane Praza 	    (pg_name = malloc(nbufsz)) == NULL ||
1742*1f6eb021SLiane Praza 	    (pg_type = malloc(tbufsz)) == NULL ||
1743*1f6eb021SLiane Praza 	    (p = calloc(1, sizeof (pg_tmpl_walk_t))) == NULL) {
1744*1f6eb021SLiane Praza 		free(fmribuf);
1745*1f6eb021SLiane Praza 		free(pg_name);
1746*1f6eb021SLiane Praza 		free(pg_type);
1747*1f6eb021SLiane Praza 		scf_instance_destroy(inst);
1748*1f6eb021SLiane Praza 		scf_service_destroy(svc);
1749*1f6eb021SLiane Praza 		scf_snaplevel_destroy(snaplvl);
1750*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
1751*1f6eb021SLiane Praza 		return (-1);
1752*1f6eb021SLiane Praza 	}
1753*1f6eb021SLiane Praza 
1754*1f6eb021SLiane Praza 	if (scf_pg_get_name(pg, pg_name, nbufsz) < 0) {
1755*1f6eb021SLiane Praza 		ret = -1;
1756*1f6eb021SLiane Praza 		goto fail;
1757*1f6eb021SLiane Praza 	}
1758*1f6eb021SLiane Praza 
1759*1f6eb021SLiane Praza 	if (scf_pg_get_type(pg, pg_type, tbufsz) < 0) {
1760*1f6eb021SLiane Praza 		ret = -1;
1761*1f6eb021SLiane Praza 		goto fail;
1762*1f6eb021SLiane Praza 	}
1763*1f6eb021SLiane Praza 	p->pw_pgname = pg_name;
1764*1f6eb021SLiane Praza 	p->pw_pgtype = pg_type;
1765*1f6eb021SLiane Praza 
1766*1f6eb021SLiane Praza 	ret = scf_pg_get_parent_snaplevel(pg, snaplvl);
1767*1f6eb021SLiane Praza 	if (ret == -1) {
1768*1f6eb021SLiane Praza 		switch (scf_error()) {
1769*1f6eb021SLiane Praza 		case SCF_ERROR_CONSTRAINT_VIOLATED:
1770*1f6eb021SLiane Praza 			/* Parent type doesn't match.  Keep looking. */
1771*1f6eb021SLiane Praza 			break;
1772*1f6eb021SLiane Praza 
1773*1f6eb021SLiane Praza 		case SCF_ERROR_DELETED:
1774*1f6eb021SLiane Praza 		case SCF_ERROR_NOT_BOUND:
1775*1f6eb021SLiane Praza 		case SCF_ERROR_NOT_SET:
1776*1f6eb021SLiane Praza 			/* Pass these back to the caller. */
1777*1f6eb021SLiane Praza 			goto fail;
1778*1f6eb021SLiane Praza 
1779*1f6eb021SLiane Praza 		case SCF_ERROR_HANDLE_MISMATCH:
1780*1f6eb021SLiane Praza 		default:
1781*1f6eb021SLiane Praza 			assert(0);
1782*1f6eb021SLiane Praza 			abort();
1783*1f6eb021SLiane Praza 		}
1784*1f6eb021SLiane Praza 
1785*1f6eb021SLiane Praza 		/*
1786*1f6eb021SLiane Praza 		 * No snapshot.  We'll use 'editing' by default since
1787*1f6eb021SLiane Praza 		 * snap and snapbuf are NULL.
1788*1f6eb021SLiane Praza 		 */
1789*1f6eb021SLiane Praza 		p->pw_snapname = NULL;
1790*1f6eb021SLiane Praza 
1791*1f6eb021SLiane Praza 	} else {
1792*1f6eb021SLiane Praza 		if ((snap = scf_snapshot_create(h)) == NULL) {
1793*1f6eb021SLiane Praza 			ret = -1;
1794*1f6eb021SLiane Praza 			goto fail;
1795*1f6eb021SLiane Praza 		}
1796*1f6eb021SLiane Praza 
1797*1f6eb021SLiane Praza 		ret = scf_snaplevel_get_parent(snaplvl, snap);
1798*1f6eb021SLiane Praza 		if (ret == -1) {
1799*1f6eb021SLiane Praza 			if (ismember(scf_error(), errors_server)) {
1800*1f6eb021SLiane Praza 				ret = -1;
1801*1f6eb021SLiane Praza 				goto fail;
1802*1f6eb021SLiane Praza 			} else {
1803*1f6eb021SLiane Praza 				assert(0);
1804*1f6eb021SLiane Praza 				abort();
1805*1f6eb021SLiane Praza 			}
1806*1f6eb021SLiane Praza 		}
1807*1f6eb021SLiane Praza 
1808*1f6eb021SLiane Praza 		/* Grab snapshot name while we're here. */
1809*1f6eb021SLiane Praza 		if ((snapbuf = malloc(nbufsz)) == NULL) {
1810*1f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
1811*1f6eb021SLiane Praza 			ret = -1;
1812*1f6eb021SLiane Praza 			goto fail;
1813*1f6eb021SLiane Praza 		}
1814*1f6eb021SLiane Praza 		if (scf_snapshot_get_name(snap, snapbuf, nbufsz) < 0) {
1815*1f6eb021SLiane Praza 			if (ismember(scf_error(), errors_server)) {
1816*1f6eb021SLiane Praza 				ret = -1;
1817*1f6eb021SLiane Praza 				goto fail;
1818*1f6eb021SLiane Praza 			} else {
1819*1f6eb021SLiane Praza 				assert(0);
1820*1f6eb021SLiane Praza 				abort();
1821*1f6eb021SLiane Praza 			}
1822*1f6eb021SLiane Praza 		}
1823*1f6eb021SLiane Praza 		p->pw_snapname = snapbuf;
1824*1f6eb021SLiane Praza 
1825*1f6eb021SLiane Praza 		ret = scf_snapshot_get_parent(snap, inst);
1826*1f6eb021SLiane Praza 		if (ret == -1) {
1827*1f6eb021SLiane Praza 			if (ismember(scf_error(), errors_server)) {
1828*1f6eb021SLiane Praza 				ret = -1;
1829*1f6eb021SLiane Praza 				goto fail;
1830*1f6eb021SLiane Praza 			} else {
1831*1f6eb021SLiane Praza 				assert(0);
1832*1f6eb021SLiane Praza 				abort();
1833*1f6eb021SLiane Praza 			}
1834*1f6eb021SLiane Praza 		}
1835*1f6eb021SLiane Praza 
1836*1f6eb021SLiane Praza 		_walk_template_instances(NULL, inst, snap,
1837*1f6eb021SLiane Praza 		    (walk_template_inst_func_t *)find_pg_match, p, flags);
1838*1f6eb021SLiane Praza 	}
1839*1f6eb021SLiane Praza 
1840*1f6eb021SLiane Praza 	/* No snapshot parent.  Go looking for instance parent. */
1841*1f6eb021SLiane Praza 	if (snapbuf == NULL) {
1842*1f6eb021SLiane Praza 		/* First look for instance parent. */
1843*1f6eb021SLiane Praza 		ret = scf_pg_get_parent_instance(pg, inst);
1844*1f6eb021SLiane Praza 		if (ret == 0) {
1845*1f6eb021SLiane Praza 			_walk_template_instances(NULL, inst, snap,
1846*1f6eb021SLiane Praza 			    (walk_template_inst_func_t *)find_pg_match,
1847*1f6eb021SLiane Praza 			    p, flags);
1848*1f6eb021SLiane Praza 		/* OK, check for service parent */
1849*1f6eb021SLiane Praza 		} else if (ret == -1 &&
1850*1f6eb021SLiane Praza 		    scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED) {
1851*1f6eb021SLiane Praza 			ret = scf_pg_get_parent_service(pg, svc);
1852*1f6eb021SLiane Praza 			if (ret == 0) {
1853*1f6eb021SLiane Praza 				_walk_template_instances(svc, NULL, snap,
1854*1f6eb021SLiane Praza 				    (walk_template_inst_func_t *)find_pg_match,
1855*1f6eb021SLiane Praza 				    p, flags);
1856*1f6eb021SLiane Praza 			} else {
1857*1f6eb021SLiane Praza 				switch (scf_error()) {
1858*1f6eb021SLiane Praza 				case SCF_ERROR_CONSTRAINT_VIOLATED:
1859*1f6eb021SLiane Praza 					(void) scf_set_error(
1860*1f6eb021SLiane Praza 					    SCF_ERROR_NOT_FOUND);
1861*1f6eb021SLiane Praza 					/*FALLTHROUGH*/
1862*1f6eb021SLiane Praza 
1863*1f6eb021SLiane Praza 				case SCF_ERROR_CONNECTION_BROKEN:
1864*1f6eb021SLiane Praza 				case SCF_ERROR_DELETED:
1865*1f6eb021SLiane Praza 				case SCF_ERROR_HANDLE_MISMATCH:
1866*1f6eb021SLiane Praza 				case SCF_ERROR_NOT_BOUND:
1867*1f6eb021SLiane Praza 				case SCF_ERROR_NOT_SET:
1868*1f6eb021SLiane Praza 					ret = -1;
1869*1f6eb021SLiane Praza 					goto fail;
1870*1f6eb021SLiane Praza 
1871*1f6eb021SLiane Praza 				default:
1872*1f6eb021SLiane Praza 					assert(0);
1873*1f6eb021SLiane Praza 					abort();
1874*1f6eb021SLiane Praza 				}
1875*1f6eb021SLiane Praza 			}
1876*1f6eb021SLiane Praza 		} else {
1877*1f6eb021SLiane Praza 			ret = -1;
1878*1f6eb021SLiane Praza 			goto fail;
1879*1f6eb021SLiane Praza 		}
1880*1f6eb021SLiane Praza 	}
1881*1f6eb021SLiane Praza 
1882*1f6eb021SLiane Praza 	if (p->pw_pg != NULL) {
1883*1f6eb021SLiane Praza 		pg_tmpl->pt_h = h;
1884*1f6eb021SLiane Praza 		pg_tmpl->pt_pg = p->pw_pg;
1885*1f6eb021SLiane Praza 		pg_tmpl->pt_inst = p->pw_inst;
1886*1f6eb021SLiane Praza 		pg_tmpl->pt_snap = p->pw_snap;
1887*1f6eb021SLiane Praza 		pg_tmpl->pt_svc = p->pw_svc;
1888*1f6eb021SLiane Praza 		pg_tmpl->pt_populated = 1;
1889*1f6eb021SLiane Praza 		free(p->pw_tmpl_pgname);
1890*1f6eb021SLiane Praza 		ret = 0;
1891*1f6eb021SLiane Praza 		goto done;
1892*1f6eb021SLiane Praza 	}
1893*1f6eb021SLiane Praza 
1894*1f6eb021SLiane Praza 	ret = -1;
1895*1f6eb021SLiane Praza 	(void) scf_set_error(SCF_ERROR_NOT_FOUND);
1896*1f6eb021SLiane Praza 
1897*1f6eb021SLiane Praza fail:
1898*1f6eb021SLiane Praza 	scf_instance_destroy(inst);
1899*1f6eb021SLiane Praza 	scf_service_destroy(svc);
1900*1f6eb021SLiane Praza 	scf_snapshot_destroy(snap);
1901*1f6eb021SLiane Praza done:
1902*1f6eb021SLiane Praza 	free(snapbuf);
1903*1f6eb021SLiane Praza 	free(fmribuf);
1904*1f6eb021SLiane Praza 	free(pg_name);
1905*1f6eb021SLiane Praza 	free(pg_type);
1906*1f6eb021SLiane Praza 	free(p);
1907*1f6eb021SLiane Praza 	scf_snaplevel_destroy(snaplvl);
1908*1f6eb021SLiane Praza 	return (ret);
1909*1f6eb021SLiane Praza }
1910*1f6eb021SLiane Praza 
1911*1f6eb021SLiane Praza /*
1912*1f6eb021SLiane Praza  * int scf_tmpl_get_by_pg_name()
1913*1f6eb021SLiane Praza  *
1914*1f6eb021SLiane Praza  * Get a template by a combination of the name and type.  Either name
1915*1f6eb021SLiane Praza  * or type can be null, which indicates a wildcard.  flags may be
1916*1f6eb021SLiane Praza  * SCF_PG_TMPL_FLAG_CURRENT (use current properties rather than
1917*1f6eb021SLiane Praza  * the defined or running snapshot), and SCF_PG_TMPL_FLAG_EXACT (match
1918*1f6eb021SLiane Praza  * only templates defined by the FMRI in question, not by its restarter
1919*1f6eb021SLiane Praza  * or globally).  Returns 0 on success and -1 on error, and sets
1920*1f6eb021SLiane Praza  * scf_error() to:
1921*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
1922*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
1923*1f6eb021SLiane Praza  *     The connection to the repository was lost.
1924*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
1925*1f6eb021SLiane Praza  *     The instance has been deleted.
1926*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
1927*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
1928*1f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
1929*1f6eb021SLiane Praza  *     FMRI isn't valid, pg_name is too long to look for a template, or
1930*1f6eb021SLiane Praza  *     snapshot specified isn't a valid name
1931*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
1932*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
1933*1f6eb021SLiane Praza  *     The server does not have adequate resources to complete the request.
1934*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
1935*1f6eb021SLiane Praza  *     The handle is not currently bound.
1936*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
1937*1f6eb021SLiane Praza  *     Object matching FMRI doesn't exist in the repository, or snapshot
1938*1f6eb021SLiane Praza  *     doesn't exist.
1939*1f6eb021SLiane Praza  */
1940*1f6eb021SLiane Praza int
1941*1f6eb021SLiane Praza scf_tmpl_get_by_pg_name(const char *fmri, const char *snapshot,
1942*1f6eb021SLiane Praza     const char *pg_name, const char *pg_type, scf_pg_tmpl_t *pg_tmpl, int flags)
1943*1f6eb021SLiane Praza {
1944*1f6eb021SLiane Praza 	scf_instance_t *inst = NULL;
1945*1f6eb021SLiane Praza 	scf_service_t *svc = NULL;
1946*1f6eb021SLiane Praza 	scf_snapshot_t *snap = NULL;
1947*1f6eb021SLiane Praza 	pg_tmpl_walk_t *p;
1948*1f6eb021SLiane Praza 	scf_handle_t *h;
1949*1f6eb021SLiane Praza 	int ret;
1950*1f6eb021SLiane Praza 
1951*1f6eb021SLiane Praza 	assert(pg_tmpl != NULL);
1952*1f6eb021SLiane Praza 	h = pg_tmpl->pt_h;
1953*1f6eb021SLiane Praza 	assert(h != NULL);
1954*1f6eb021SLiane Praza 
1955*1f6eb021SLiane Praza 	scf_tmpl_pg_reset(pg_tmpl);
1956*1f6eb021SLiane Praza 
1957*1f6eb021SLiane Praza 	if ((inst = scf_instance_create(h)) == NULL ||
1958*1f6eb021SLiane Praza 	    (svc = scf_service_create(h)) == NULL) {
1959*1f6eb021SLiane Praza 		scf_instance_destroy(inst);
1960*1f6eb021SLiane Praza 		return (-1);
1961*1f6eb021SLiane Praza 	}
1962*1f6eb021SLiane Praza 
1963*1f6eb021SLiane Praza 	p = calloc(1, sizeof (pg_tmpl_walk_t));
1964*1f6eb021SLiane Praza 	if (p == NULL) {
1965*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
1966*1f6eb021SLiane Praza 		goto fail_zalloc;
1967*1f6eb021SLiane Praza 	}
1968*1f6eb021SLiane Praza 
1969*1f6eb021SLiane Praza 	ret = scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
1970*1f6eb021SLiane Praza 	    NULL, SCF_DECODE_FMRI_EXACT);
1971*1f6eb021SLiane Praza 	if (ret == 0) {
1972*1f6eb021SLiane Praza 		scf_service_destroy(svc);
1973*1f6eb021SLiane Praza 		svc = NULL;
1974*1f6eb021SLiane Praza 	} else if (ret != 0 &&
1975*1f6eb021SLiane Praza 	    scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED) {
1976*1f6eb021SLiane Praza 		ret = scf_handle_decode_fmri(h, fmri, NULL, svc,
1977*1f6eb021SLiane Praza 		    NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT);
1978*1f6eb021SLiane Praza 		if (ret == 0) {
1979*1f6eb021SLiane Praza 			scf_instance_destroy(inst);
1980*1f6eb021SLiane Praza 			inst = NULL;
1981*1f6eb021SLiane Praza 		}
1982*1f6eb021SLiane Praza 	}
1983*1f6eb021SLiane Praza 	if (ret != 0) {
1984*1f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
1985*1f6eb021SLiane Praza 			goto fail;
1986*1f6eb021SLiane Praza 		} else switch (scf_error()) {
1987*1f6eb021SLiane Praza 		case SCF_ERROR_CONSTRAINT_VIOLATED:
1988*1f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1989*1f6eb021SLiane Praza 			goto fail;
1990*1f6eb021SLiane Praza 
1991*1f6eb021SLiane Praza 		case SCF_ERROR_INVALID_ARGUMENT:
1992*1f6eb021SLiane Praza 		case SCF_ERROR_NOT_FOUND:
1993*1f6eb021SLiane Praza 			goto fail;
1994*1f6eb021SLiane Praza 
1995*1f6eb021SLiane Praza 		case SCF_ERROR_HANDLE_MISMATCH:
1996*1f6eb021SLiane Praza 		case SCF_ERROR_NOT_SET:
1997*1f6eb021SLiane Praza 		default:
1998*1f6eb021SLiane Praza 			assert(0);
1999*1f6eb021SLiane Praza 			abort();
2000*1f6eb021SLiane Praza 		}
2001*1f6eb021SLiane Praza 	}
2002*1f6eb021SLiane Praza 
2003*1f6eb021SLiane Praza 	assert(svc == NULL || inst == NULL);
2004*1f6eb021SLiane Praza 	assert(svc != NULL || inst != NULL);
2005*1f6eb021SLiane Praza 
2006*1f6eb021SLiane Praza 	if (inst != NULL) {
2007*1f6eb021SLiane Praza 		if (snapshot == NULL || strcmp(snapshot, "running") == 0 ||
2008*1f6eb021SLiane Praza 		    (flags & SCF_PG_TMPL_FLAG_CURRENT) ==
2009*1f6eb021SLiane Praza 		    SCF_PG_TMPL_FLAG_CURRENT) {
2010*1f6eb021SLiane Praza 			if (_get_snapshot(inst, NULL, &snap) == -1)
2011*1f6eb021SLiane Praza 				goto fail;
2012*1f6eb021SLiane Praza 		} else {
2013*1f6eb021SLiane Praza 			if (_get_snapshot(inst, snapshot, &snap) == -1) {
2014*1f6eb021SLiane Praza 				goto fail;
2015*1f6eb021SLiane Praza 			} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
2016*1f6eb021SLiane Praza 				goto fail;
2017*1f6eb021SLiane Praza 			}
2018*1f6eb021SLiane Praza 		}
2019*1f6eb021SLiane Praza 	} else {
2020*1f6eb021SLiane Praza 		/* If we have a service fmri, snapshot is ignored. */
2021*1f6eb021SLiane Praza 		scf_snapshot_destroy(snap);
2022*1f6eb021SLiane Praza 		snap = NULL;
2023*1f6eb021SLiane Praza 	}
2024*1f6eb021SLiane Praza 
2025*1f6eb021SLiane Praza 	p->pw_snapname = snapshot;
2026*1f6eb021SLiane Praza 	p->pw_pgname = pg_name;
2027*1f6eb021SLiane Praza 	p->pw_pgtype = pg_type;
2028*1f6eb021SLiane Praza 
2029*1f6eb021SLiane Praza 	/*
2030*1f6eb021SLiane Praza 	 * For each of instance, restarter, global
2031*1f6eb021SLiane Praza 	 *    - check for a tm_pg_pattern_nt_<name> matching type
2032*1f6eb021SLiane Praza 	 *    - check for a tm_pg_pattern_t_<type> matching type
2033*1f6eb021SLiane Praza 	 *    - check for any tm_pg_pattern_
2034*1f6eb021SLiane Praza 	 * Currently plan to return the most specific match only.
2035*1f6eb021SLiane Praza 	 */
2036*1f6eb021SLiane Praza 	_walk_template_instances(svc, inst, snap,
2037*1f6eb021SLiane Praza 	    (walk_template_inst_func_t *)find_pg_match, p, flags);
2038*1f6eb021SLiane Praza 
2039*1f6eb021SLiane Praza 	if (p->pw_pg != NULL) {
2040*1f6eb021SLiane Praza 		pg_tmpl->pt_h = h;
2041*1f6eb021SLiane Praza 		pg_tmpl->pt_pg = p->pw_pg;
2042*1f6eb021SLiane Praza 		pg_tmpl->pt_inst = p->pw_inst;
2043*1f6eb021SLiane Praza 		pg_tmpl->pt_snap = p->pw_snap;
2044*1f6eb021SLiane Praza 		pg_tmpl->pt_svc = p->pw_svc;
2045*1f6eb021SLiane Praza 		pg_tmpl->pt_populated = 1;
2046*1f6eb021SLiane Praza 		free(p->pw_tmpl_pgname);
2047*1f6eb021SLiane Praza 		free(p);
2048*1f6eb021SLiane Praza 		return (0);
2049*1f6eb021SLiane Praza 	}
2050*1f6eb021SLiane Praza 
2051*1f6eb021SLiane Praza 	(void) scf_set_error(SCF_ERROR_NOT_FOUND);
2052*1f6eb021SLiane Praza fail:
2053*1f6eb021SLiane Praza 	free(p);
2054*1f6eb021SLiane Praza fail_zalloc:
2055*1f6eb021SLiane Praza 	scf_instance_destroy(inst);
2056*1f6eb021SLiane Praza 	scf_service_destroy(svc);
2057*1f6eb021SLiane Praza 	scf_snapshot_destroy(snap);
2058*1f6eb021SLiane Praza 	return (-1);
2059*1f6eb021SLiane Praza }
2060*1f6eb021SLiane Praza 
2061*1f6eb021SLiane Praza /*
2062*1f6eb021SLiane Praza  * Returns NULL on failure, sets scf_error() to _CONNECTION_BROKEN,
2063*1f6eb021SLiane Praza  * _DELETED, _NO_RESOURCES, or _NOT_BOUND.
2064*1f6eb021SLiane Praza  */
2065*1f6eb021SLiane Praza static scf_iter_t *
2066*1f6eb021SLiane Praza _get_svc_or_inst_iter(scf_handle_t *h, scf_pg_tmpl_t *t)
2067*1f6eb021SLiane Praza {
2068*1f6eb021SLiane Praza 	scf_iter_t *iter;
2069*1f6eb021SLiane Praza 	int ret;
2070*1f6eb021SLiane Praza 
2071*1f6eb021SLiane Praza 	assert(t->pt_svc != NULL || t->pt_inst != NULL);
2072*1f6eb021SLiane Praza 	assert(t->pt_svc == NULL || t->pt_inst == NULL);
2073*1f6eb021SLiane Praza 
2074*1f6eb021SLiane Praza 	if ((iter = scf_iter_create(h)) == NULL) {
2075*1f6eb021SLiane Praza 		return (NULL);
2076*1f6eb021SLiane Praza 	}
2077*1f6eb021SLiane Praza 
2078*1f6eb021SLiane Praza 	/* Iterate on property groups of type template_pg_pattern */
2079*1f6eb021SLiane Praza 
2080*1f6eb021SLiane Praza 	if (t->pt_inst != NULL)
2081*1f6eb021SLiane Praza 		ret = scf_iter_instance_pgs_typed_composed(iter,
2082*1f6eb021SLiane Praza 		    t->pt_inst, t->pt_snap,
2083*1f6eb021SLiane Praza 		    SCF_GROUP_TEMPLATE_PG_PATTERN);
2084*1f6eb021SLiane Praza 	if (t->pt_svc != NULL)
2085*1f6eb021SLiane Praza 		ret = scf_iter_service_pgs_typed(iter, t->pt_svc,
2086*1f6eb021SLiane Praza 		    SCF_GROUP_TEMPLATE_PG_PATTERN);
2087*1f6eb021SLiane Praza 
2088*1f6eb021SLiane Praza 	if (ret != 0) {
2089*1f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
2090*1f6eb021SLiane Praza 			scf_iter_destroy(iter);
2091*1f6eb021SLiane Praza 			return (NULL);
2092*1f6eb021SLiane Praza 		} else {
2093*1f6eb021SLiane Praza 			assert(0);
2094*1f6eb021SLiane Praza 			abort();
2095*1f6eb021SLiane Praza 		}
2096*1f6eb021SLiane Praza 	}
2097*1f6eb021SLiane Praza 
2098*1f6eb021SLiane Praza 	return (iter);
2099*1f6eb021SLiane Praza }
2100*1f6eb021SLiane Praza 
2101*1f6eb021SLiane Praza /*
2102*1f6eb021SLiane Praza  * Returns NULL on failure, sets scf_error() to:
2103*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
2104*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
2105*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
2106*1f6eb021SLiane Praza  *   SCF_HANDLE_DESTROYED
2107*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
2108*1f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
2109*1f6eb021SLiane Praza  *     Handle argument is NULL, or snaphot is not a valid snapshot name.
2110*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
2111*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
2112*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
2113*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
2114*1f6eb021SLiane Praza  */
2115*1f6eb021SLiane Praza static scf_iter_t *
2116*1f6eb021SLiane Praza _get_next_iterator(scf_handle_t *h, scf_pg_tmpl_t *t, const char *snapshot,
2117*1f6eb021SLiane Praza     int exact)
2118*1f6eb021SLiane Praza {
2119*1f6eb021SLiane Praza 	scf_iter_t  *iter = NULL;
2120*1f6eb021SLiane Praza 	ssize_t limit;
2121*1f6eb021SLiane Praza 
2122*1f6eb021SLiane Praza 	limit = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
2123*1f6eb021SLiane Praza 	assert(limit != 0);
2124*1f6eb021SLiane Praza 
2125*1f6eb021SLiane Praza 	/*
2126*1f6eb021SLiane Praza 	 * Check what level we last iterated on: none, service,
2127*1f6eb021SLiane Praza 	 * restarter, or global.  Make sure that if one in the middle
2128*1f6eb021SLiane Praza 	 * doesn't exist, we move on to the next entity.
2129*1f6eb021SLiane Praza 	 */
2130*1f6eb021SLiane Praza 	do {
2131*1f6eb021SLiane Praza 		switch (t->pt_iter_last) {
2132*1f6eb021SLiane Praza 		case SCF__TMPL_ITER_NONE:
2133*1f6eb021SLiane Praza 			t->pt_iter_last = SCF__TMPL_ITER_INST;
2134*1f6eb021SLiane Praza 			t->pt_inst = t->pt_orig_inst;
2135*1f6eb021SLiane Praza 			t->pt_svc = t->pt_orig_svc;
2136*1f6eb021SLiane Praza 			break;
2137*1f6eb021SLiane Praza 
2138*1f6eb021SLiane Praza 		case SCF__TMPL_ITER_INST:
2139*1f6eb021SLiane Praza 			/*
2140*1f6eb021SLiane Praza 			 * Don't go any further than the specified instance
2141*1f6eb021SLiane Praza 			 * if exact was set.
2142*1f6eb021SLiane Praza 			 */
2143*1f6eb021SLiane Praza 			if (exact == 1) {
2144*1f6eb021SLiane Praza 				(void) scf_set_error(SCF_ERROR_NOT_FOUND);
2145*1f6eb021SLiane Praza 				goto fail;
2146*1f6eb021SLiane Praza 			}
2147*1f6eb021SLiane Praza 			t->pt_iter_last = SCF__TMPL_ITER_RESTARTER;
2148*1f6eb021SLiane Praza 			t->pt_inst = _get_restarter_inst(h, t->pt_orig_svc,
2149*1f6eb021SLiane Praza 			    t->pt_orig_inst, t->pt_snap);
2150*1f6eb021SLiane Praza 			t->pt_svc = NULL;
2151*1f6eb021SLiane Praza 			break;
2152*1f6eb021SLiane Praza 
2153*1f6eb021SLiane Praza 		case SCF__TMPL_ITER_RESTARTER:
2154*1f6eb021SLiane Praza 			t->pt_iter_last = SCF__TMPL_ITER_GLOBAL;
2155*1f6eb021SLiane Praza 			t->pt_inst = _get_global_inst(h);
2156*1f6eb021SLiane Praza 			t->pt_svc = NULL;
2157*1f6eb021SLiane Praza 			break;
2158*1f6eb021SLiane Praza 
2159*1f6eb021SLiane Praza 		case SCF__TMPL_ITER_GLOBAL:
2160*1f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_NOT_FOUND);
2161*1f6eb021SLiane Praza 			return (NULL);
2162*1f6eb021SLiane Praza 
2163*1f6eb021SLiane Praza 		default:
2164*1f6eb021SLiane Praza 			assert(0);
2165*1f6eb021SLiane Praza 			abort();
2166*1f6eb021SLiane Praza 		}
2167*1f6eb021SLiane Praza 	} while (t->pt_inst == NULL && t->pt_svc == NULL);
2168*1f6eb021SLiane Praza 
2169*1f6eb021SLiane Praza 	/* Set pt_snap to the snapshot for this instance */
2170*1f6eb021SLiane Praza 	if (t->pt_inst != NULL) {
2171*1f6eb021SLiane Praza 		scf_snapshot_destroy(t->pt_snap);
2172*1f6eb021SLiane Praza 		if (_get_snapshot(t->pt_inst, snapshot,
2173*1f6eb021SLiane Praza 		    &t->pt_snap) == -1)
2174*1f6eb021SLiane Praza 			goto fail;
2175*1f6eb021SLiane Praza 	}
2176*1f6eb021SLiane Praza 
2177*1f6eb021SLiane Praza 
2178*1f6eb021SLiane Praza 	iter = _get_svc_or_inst_iter(h, t);
2179*1f6eb021SLiane Praza fail:
2180*1f6eb021SLiane Praza 	return (iter);
2181*1f6eb021SLiane Praza }
2182*1f6eb021SLiane Praza 
2183*1f6eb021SLiane Praza /*
2184*1f6eb021SLiane Praza  * scf_pg_tmpl_t *scf_tmpl_pg_create(scf_handle_t *)
2185*1f6eb021SLiane Praza  *
2186*1f6eb021SLiane Praza  * Returns NULL on failure, sets scf_error() to _INVALID_ARGUMENT
2187*1f6eb021SLiane Praza  * or _NO_MEMORY.
2188*1f6eb021SLiane Praza  */
2189*1f6eb021SLiane Praza scf_pg_tmpl_t *
2190*1f6eb021SLiane Praza scf_tmpl_pg_create(scf_handle_t *handle)
2191*1f6eb021SLiane Praza {
2192*1f6eb021SLiane Praza 	scf_pg_tmpl_t *pg_tmpl = NULL;
2193*1f6eb021SLiane Praza 
2194*1f6eb021SLiane Praza 	if (handle == NULL) {
2195*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
2196*1f6eb021SLiane Praza 		return (NULL);
2197*1f6eb021SLiane Praza 	}
2198*1f6eb021SLiane Praza 	pg_tmpl = calloc(1, sizeof (scf_pg_tmpl_t));
2199*1f6eb021SLiane Praza 	if (pg_tmpl == NULL)
2200*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
2201*1f6eb021SLiane Praza 	else
2202*1f6eb021SLiane Praza 		pg_tmpl->pt_h = handle;
2203*1f6eb021SLiane Praza 
2204*1f6eb021SLiane Praza 	return (pg_tmpl);
2205*1f6eb021SLiane Praza }
2206*1f6eb021SLiane Praza 
2207*1f6eb021SLiane Praza /*
2208*1f6eb021SLiane Praza  * Retrieves name or type of a template pg.
2209*1f6eb021SLiane Praza  * Returns -1 on failure.  Sets scf_error():
2210*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
2211*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
2212*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
2213*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
2214*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
2215*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
2216*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
2217*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
2218*1f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
2219*1f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
2220*1f6eb021SLiane Praza  *     pname property is not SCF_TYPE_ASTRING or has more than one value.
2221*1f6eb021SLiane Praza  */
2222*1f6eb021SLiane Praza static ssize_t
2223*1f6eb021SLiane Praza _scf_tmpl_prop_value(scf_propertygroup_t *pg, const char *pname, char **out)
2224*1f6eb021SLiane Praza {
2225*1f6eb021SLiane Praza 	assert(strcmp(pname, SCF_PROPERTY_TM_NAME) == 0 ||
2226*1f6eb021SLiane Praza 	    strcmp(pname, SCF_PROPERTY_TM_TYPE) == 0);
2227*1f6eb021SLiane Praza 
2228*1f6eb021SLiane Praza 	*out = _scf_read_single_astring_from_pg(pg, pname);
2229*1f6eb021SLiane Praza 
2230*1f6eb021SLiane Praza 	if (*out != NULL && *out[0] == '\0') {
2231*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NONE);
2232*1f6eb021SLiane Praza 		free(*out);
2233*1f6eb021SLiane Praza 		*out = strdup(SCF_TMPL_WILDCARD);
2234*1f6eb021SLiane Praza 		if (*out == NULL)
2235*1f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
2236*1f6eb021SLiane Praza 	}
2237*1f6eb021SLiane Praza 	if (*out == NULL) {
2238*1f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
2239*1f6eb021SLiane Praza 			return (-1);
2240*1f6eb021SLiane Praza 		} else switch (scf_error()) {
2241*1f6eb021SLiane Praza 		case SCF_ERROR_CONSTRAINT_VIOLATED:
2242*1f6eb021SLiane Praza 		case SCF_ERROR_NOT_FOUND:
2243*1f6eb021SLiane Praza 		case SCF_ERROR_TYPE_MISMATCH:
2244*1f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
2245*1f6eb021SLiane Praza 			return (-1);
2246*1f6eb021SLiane Praza 
2247*1f6eb021SLiane Praza 		case SCF_ERROR_INVALID_ARGUMENT:
2248*1f6eb021SLiane Praza 		case SCF_ERROR_NOT_SET:
2249*1f6eb021SLiane Praza 		default:
2250*1f6eb021SLiane Praza 			assert(0);
2251*1f6eb021SLiane Praza 			abort();
2252*1f6eb021SLiane Praza 		}
2253*1f6eb021SLiane Praza 	}
2254*1f6eb021SLiane Praza 
2255*1f6eb021SLiane Praza 	return (strlen(*out));
2256*1f6eb021SLiane Praza }
2257*1f6eb021SLiane Praza 
2258*1f6eb021SLiane Praza /*
2259*1f6eb021SLiane Praza  * int scf_tmpl_iter_pgs()
2260*1f6eb021SLiane Praza  *
2261*1f6eb021SLiane Praza  * Iterates through the property group templates for the fmri given.
2262*1f6eb021SLiane Praza  * When t is uninitialized or reset, sets t to the first property group
2263*1f6eb021SLiane Praza  * template in fmri. On subsequent calls, sets t to the next property group
2264*1f6eb021SLiane Praza  * template in frmi.
2265*1f6eb021SLiane Praza  * Returns 1 on success, 0 when no property group templates are left to
2266*1f6eb021SLiane Praza  * iterate, -1 on error.
2267*1f6eb021SLiane Praza  * The flags argument may include SCF_PG_TMPL_FLAG_REQUIRED,
2268*1f6eb021SLiane Praza  * SCF_PG_TMPL_FLAG_CURRENT,  and/or SCF_PG_TMPL_FLAG_EXACT.
2269*1f6eb021SLiane Praza  *
2270*1f6eb021SLiane Praza  * Returns -1 on error and sets scf_error() to:
2271*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
2272*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
2273*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
2274*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
2275*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
2276*1f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
2277*1f6eb021SLiane Praza  *      The handle argument is NULL, fmri is invalid, or snapshot is invalid.
2278*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
2279*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
2280*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
2281*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
2282*1f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
2283*1f6eb021SLiane Praza  */
2284*1f6eb021SLiane Praza int
2285*1f6eb021SLiane Praza scf_tmpl_iter_pgs(scf_pg_tmpl_t *t, const char *fmri, const char *snapshot,
2286*1f6eb021SLiane Praza     const char *type, int flags)
2287*1f6eb021SLiane Praza {
2288*1f6eb021SLiane Praza 	scf_handle_t *h;
2289*1f6eb021SLiane Praza 	scf_service_t *svc = NULL;
2290*1f6eb021SLiane Praza 	scf_instance_t *inst = NULL;
2291*1f6eb021SLiane Praza 	scf_propertygroup_t *pg = NULL;
2292*1f6eb021SLiane Praza 	scf_snapshot_t *snap = NULL;
2293*1f6eb021SLiane Praza 	scf_pg_tmpl_t *pg_tmpl = NULL;
2294*1f6eb021SLiane Praza 	int err;
2295*1f6eb021SLiane Praza 	int found = 0;
2296*1f6eb021SLiane Praza 	char *tmpl_type;
2297*1f6eb021SLiane Praza 	uint8_t required;
2298*1f6eb021SLiane Praza 	int ret;
2299*1f6eb021SLiane Praza 
2300*1f6eb021SLiane Praza 	if (t == NULL) {
2301*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
2302*1f6eb021SLiane Praza 		return (-1);
2303*1f6eb021SLiane Praza 	}
2304*1f6eb021SLiane Praza 
2305*1f6eb021SLiane Praza 	h = t->pt_h;
2306*1f6eb021SLiane Praza 
2307*1f6eb021SLiane Praza 	if (t->pt_populated == 0) {
2308*1f6eb021SLiane Praza 		if ((svc = scf_service_create(h)) == NULL ||
2309*1f6eb021SLiane Praza 		    (inst = scf_instance_create(h)) == NULL ||
2310*1f6eb021SLiane Praza 		    (pg = scf_pg_create(h)) == NULL) {
2311*1f6eb021SLiane Praza 			goto fail_non_populated;
2312*1f6eb021SLiane Praza 		}
2313*1f6eb021SLiane Praza 
2314*1f6eb021SLiane Praza 		ret = scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
2315*1f6eb021SLiane Praza 		    NULL, SCF_DECODE_FMRI_EXACT);
2316*1f6eb021SLiane Praza 		if (ret == 0) {
2317*1f6eb021SLiane Praza 			scf_service_destroy(svc);
2318*1f6eb021SLiane Praza 			svc = NULL;
2319*1f6eb021SLiane Praza 		} else if (ret != 0 &&
2320*1f6eb021SLiane Praza 		    scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED) {
2321*1f6eb021SLiane Praza 			ret = scf_handle_decode_fmri(h, fmri, NULL, svc,
2322*1f6eb021SLiane Praza 			    NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT);
2323*1f6eb021SLiane Praza 			if (ret == 0) {
2324*1f6eb021SLiane Praza 				scf_instance_destroy(inst);
2325*1f6eb021SLiane Praza 				inst = NULL;
2326*1f6eb021SLiane Praza 			}
2327*1f6eb021SLiane Praza 		}
2328*1f6eb021SLiane Praza 
2329*1f6eb021SLiane Praza 		if (ret != 0) {
2330*1f6eb021SLiane Praza 			if (ismember(scf_error(), errors_server)) {
2331*1f6eb021SLiane Praza 				goto fail_non_populated;
2332*1f6eb021SLiane Praza 			} else switch (scf_error()) {
2333*1f6eb021SLiane Praza 			case SCF_ERROR_CONSTRAINT_VIOLATED:
2334*1f6eb021SLiane Praza 				(void) scf_set_error(
2335*1f6eb021SLiane Praza 				    SCF_ERROR_INVALID_ARGUMENT);
2336*1f6eb021SLiane Praza 				goto fail_non_populated;
2337*1f6eb021SLiane Praza 
2338*1f6eb021SLiane Praza 			case SCF_ERROR_INVALID_ARGUMENT:
2339*1f6eb021SLiane Praza 			case SCF_ERROR_NOT_FOUND:
2340*1f6eb021SLiane Praza 				goto fail_non_populated;
2341*1f6eb021SLiane Praza 
2342*1f6eb021SLiane Praza 			case SCF_ERROR_HANDLE_MISMATCH:
2343*1f6eb021SLiane Praza 			case SCF_ERROR_NOT_SET:
2344*1f6eb021SLiane Praza 			default:
2345*1f6eb021SLiane Praza 				assert(0);
2346*1f6eb021SLiane Praza 				abort();
2347*1f6eb021SLiane Praza 			}
2348*1f6eb021SLiane Praza 		}
2349*1f6eb021SLiane Praza 
2350*1f6eb021SLiane Praza 		assert(svc == NULL || inst == NULL);
2351*1f6eb021SLiane Praza 		assert(svc != NULL || inst != NULL);
2352*1f6eb021SLiane Praza 
2353*1f6eb021SLiane Praza 		if (inst != NULL) {
2354*1f6eb021SLiane Praza 			if (snapshot == NULL ||
2355*1f6eb021SLiane Praza 			    strcmp(snapshot, "running") == 0 ||
2356*1f6eb021SLiane Praza 			    (flags & SCF_PG_TMPL_FLAG_CURRENT) ==
2357*1f6eb021SLiane Praza 			    SCF_PG_TMPL_FLAG_CURRENT) {
2358*1f6eb021SLiane Praza 				if (_get_snapshot(inst, NULL, &snap) == -1)
2359*1f6eb021SLiane Praza 					goto fail_non_populated;
2360*1f6eb021SLiane Praza 			} else {
2361*1f6eb021SLiane Praza 				(void) scf_set_error(SCF_ERROR_NONE);
2362*1f6eb021SLiane Praza 				if (_get_snapshot(inst, snapshot,
2363*1f6eb021SLiane Praza 				    &snap) == -1) {
2364*1f6eb021SLiane Praza 					goto fail_non_populated;
2365*1f6eb021SLiane Praza 				} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
2366*1f6eb021SLiane Praza 					goto fail_non_populated;
2367*1f6eb021SLiane Praza 				}
2368*1f6eb021SLiane Praza 			}
2369*1f6eb021SLiane Praza 		} else {
2370*1f6eb021SLiane Praza 			scf_snapshot_destroy(snap);
2371*1f6eb021SLiane Praza 			snap = NULL;
2372*1f6eb021SLiane Praza 		}
2373*1f6eb021SLiane Praza 
2374*1f6eb021SLiane Praza 		pg_tmpl = t;
2375*1f6eb021SLiane Praza 		pg_tmpl->pt_orig_inst = inst;
2376*1f6eb021SLiane Praza 		pg_tmpl->pt_orig_svc = svc;
2377*1f6eb021SLiane Praza 		pg_tmpl->pt_snap = snap;
2378*1f6eb021SLiane Praza 		pg_tmpl->pt_is_iter = 1;
2379*1f6eb021SLiane Praza 		pg_tmpl->pt_iter_last = SCF__TMPL_ITER_NONE;
2380*1f6eb021SLiane Praza 		pg_tmpl->pt_pg = pg;
2381*1f6eb021SLiane Praza 		pg_tmpl->pt_populated = 1;
2382*1f6eb021SLiane Praza 	} else {
2383*1f6eb021SLiane Praza 		if (t->pt_is_iter != 1) {
2384*1f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
2385*1f6eb021SLiane Praza 			return (-1);
2386*1f6eb021SLiane Praza 		}
2387*1f6eb021SLiane Praza 		pg_tmpl = t;
2388*1f6eb021SLiane Praza 		assert(pg_tmpl->pt_pg != NULL);
2389*1f6eb021SLiane Praza 	}
2390*1f6eb021SLiane Praza 
2391*1f6eb021SLiane Praza 	if (pg_tmpl->pt_iter == NULL) {
2392*1f6eb021SLiane Praza 		pg_tmpl->pt_iter = _get_next_iterator(h, pg_tmpl, snapshot,
2393*1f6eb021SLiane Praza 		    (flags & SCF_PG_TMPL_FLAG_EXACT) ? 1 : 0);
2394*1f6eb021SLiane Praza 		if (pg_tmpl->pt_iter == NULL) {
2395*1f6eb021SLiane Praza 			if (scf_error() == SCF_ERROR_NOT_FOUND)
2396*1f6eb021SLiane Praza 				return (0);
2397*1f6eb021SLiane Praza 			else
2398*1f6eb021SLiane Praza 				return (-1);
2399*1f6eb021SLiane Praza 		}
2400*1f6eb021SLiane Praza 	}
2401*1f6eb021SLiane Praza 
2402*1f6eb021SLiane Praza 	while (found == 0) {
2403*1f6eb021SLiane Praza 		while ((err = scf_iter_next_pg(pg_tmpl->pt_iter,
2404*1f6eb021SLiane Praza 		    pg_tmpl->pt_pg)) != 1) {
2405*1f6eb021SLiane Praza 			if (err == -1) {
2406*1f6eb021SLiane Praza 				if (ismember(scf_error(), errors_server)) {
2407*1f6eb021SLiane Praza 					return (-1);
2408*1f6eb021SLiane Praza 				} else switch (scf_error()) {
2409*1f6eb021SLiane Praza 				case SCF_ERROR_HANDLE_MISMATCH:
2410*1f6eb021SLiane Praza 					return (-1);
2411*1f6eb021SLiane Praza 
2412*1f6eb021SLiane Praza 				case SCF_ERROR_NOT_SET:
2413*1f6eb021SLiane Praza 				case SCF_ERROR_INVALID_ARGUMENT:
2414*1f6eb021SLiane Praza 				default:
2415*1f6eb021SLiane Praza 					assert(0);
2416*1f6eb021SLiane Praza 					abort();
2417*1f6eb021SLiane Praza 				}
2418*1f6eb021SLiane Praza 			} else if (err == 0)  {
2419*1f6eb021SLiane Praza 				/* This iteration is done.  Get the next one */
2420*1f6eb021SLiane Praza 				scf_iter_destroy(pg_tmpl->pt_iter);
2421*1f6eb021SLiane Praza 				pg_tmpl->pt_iter = _get_next_iterator(h,
2422*1f6eb021SLiane Praza 				    pg_tmpl, snapshot,
2423*1f6eb021SLiane Praza 				    (flags & SCF_PG_TMPL_FLAG_EXACT) ? 1 : 0);
2424*1f6eb021SLiane Praza 				if (pg_tmpl->pt_iter == NULL) {
2425*1f6eb021SLiane Praza 					if (scf_error() == SCF_ERROR_NOT_FOUND)
2426*1f6eb021SLiane Praza 						return (0);
2427*1f6eb021SLiane Praza 					else
2428*1f6eb021SLiane Praza 						return (-1);
2429*1f6eb021SLiane Praza 				}
2430*1f6eb021SLiane Praza 				continue;
2431*1f6eb021SLiane Praza 			} else {
2432*1f6eb021SLiane Praza 				assert(0);
2433*1f6eb021SLiane Praza 				abort();
2434*1f6eb021SLiane Praza 			}
2435*1f6eb021SLiane Praza 		}
2436*1f6eb021SLiane Praza 
2437*1f6eb021SLiane Praza 		/*
2438*1f6eb021SLiane Praza 		 * Discard pgs which don't exist at the right scoping.  This
2439*1f6eb021SLiane Praza 		 * check also makes sure that if we're looking at, for
2440*1f6eb021SLiane Praza 		 * example, svc:/system/svc/restarter:default, that we
2441*1f6eb021SLiane Praza 		 * don't hand back the same property groups twice.
2442*1f6eb021SLiane Praza 		 */
2443*1f6eb021SLiane Praza 		switch (t->pt_iter_last) {
2444*1f6eb021SLiane Praza 		case SCF__TMPL_ITER_INST:
2445*1f6eb021SLiane Praza 			ret = check_target_match(pg_tmpl->pt_pg,
2446*1f6eb021SLiane Praza 			    SCF_TM_TARGET_THIS);
2447*1f6eb021SLiane Praza 			break;
2448*1f6eb021SLiane Praza 		case SCF__TMPL_ITER_RESTARTER:
2449*1f6eb021SLiane Praza 			ret = check_target_match(pg_tmpl->pt_pg,
2450*1f6eb021SLiane Praza 			    SCF_TM_TARGET_DELEGATE);
2451*1f6eb021SLiane Praza 			break;
2452*1f6eb021SLiane Praza 		case SCF__TMPL_ITER_GLOBAL:
2453*1f6eb021SLiane Praza 			ret = check_target_match(pg_tmpl->pt_pg,
2454*1f6eb021SLiane Praza 			    SCF_TM_TARGET_ALL);
2455*1f6eb021SLiane Praza 			break;
2456*1f6eb021SLiane Praza 		case SCF__TMPL_ITER_NONE:
2457*1f6eb021SLiane Praza 		default:
2458*1f6eb021SLiane Praza 			assert(0);
2459*1f6eb021SLiane Praza 			abort();
2460*1f6eb021SLiane Praza 		}
2461*1f6eb021SLiane Praza 
2462*1f6eb021SLiane Praza 		if (ret != 0)
2463*1f6eb021SLiane Praza 			continue;
2464*1f6eb021SLiane Praza 
2465*1f6eb021SLiane Praza 		/*
2466*1f6eb021SLiane Praza 		 * If walking only required property groups, check if
2467*1f6eb021SLiane Praza 		 * the retrieved group is required.
2468*1f6eb021SLiane Praza 		 */
2469*1f6eb021SLiane Praza 		if (flags & SCF_PG_TMPL_FLAG_REQUIRED) {
2470*1f6eb021SLiane Praza 			if (scf_tmpl_pg_required(pg_tmpl, &required) == 0) {
2471*1f6eb021SLiane Praza 				if (required == 0)
2472*1f6eb021SLiane Praza 					continue;
2473*1f6eb021SLiane Praza 			} else {
2474*1f6eb021SLiane Praza 				return (-1);
2475*1f6eb021SLiane Praza 			}
2476*1f6eb021SLiane Praza 		}
2477*1f6eb021SLiane Praza 
2478*1f6eb021SLiane Praza 		/*
2479*1f6eb021SLiane Praza 		 * If type != NULL, check if type property matches.  If no
2480*1f6eb021SLiane Praza 		 * type property exists, consider it a match.
2481*1f6eb021SLiane Praza 		 */
2482*1f6eb021SLiane Praza 		if (type != NULL) {
2483*1f6eb021SLiane Praza 			if (scf_tmpl_pg_type(pg_tmpl, &tmpl_type) != -1) {
2484*1f6eb021SLiane Praza 				if (strcmp(tmpl_type, SCF_TMPL_WILDCARD)
2485*1f6eb021SLiane Praza 				    == 0 || strcmp(type, tmpl_type) == 0) {
2486*1f6eb021SLiane Praza 					free(tmpl_type);
2487*1f6eb021SLiane Praza 					break;
2488*1f6eb021SLiane Praza 				}
2489*1f6eb021SLiane Praza 				free(tmpl_type);
2490*1f6eb021SLiane Praza 			} else if (scf_error() == SCF_ERROR_NOT_FOUND ||
2491*1f6eb021SLiane Praza 			    scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED ||
2492*1f6eb021SLiane Praza 			    scf_error() == SCF_ERROR_TYPE_MISMATCH) {
2493*1f6eb021SLiane Praza 				break;
2494*1f6eb021SLiane Praza 			} else {
2495*1f6eb021SLiane Praza 				return (-1);
2496*1f6eb021SLiane Praza 			}
2497*1f6eb021SLiane Praza 		} else {
2498*1f6eb021SLiane Praza 			break;
2499*1f6eb021SLiane Praza 		}
2500*1f6eb021SLiane Praza 	}
2501*1f6eb021SLiane Praza 
2502*1f6eb021SLiane Praza 	return (1);
2503*1f6eb021SLiane Praza 
2504*1f6eb021SLiane Praza fail_non_populated:
2505*1f6eb021SLiane Praza 	scf_service_destroy(svc);
2506*1f6eb021SLiane Praza 	scf_instance_destroy(inst);
2507*1f6eb021SLiane Praza 	scf_pg_destroy(pg);
2508*1f6eb021SLiane Praza 	scf_snapshot_destroy(snap);
2509*1f6eb021SLiane Praza 	return (-1);
2510*1f6eb021SLiane Praza }
2511*1f6eb021SLiane Praza 
2512*1f6eb021SLiane Praza void
2513*1f6eb021SLiane Praza scf_tmpl_pg_destroy(scf_pg_tmpl_t *t)
2514*1f6eb021SLiane Praza {
2515*1f6eb021SLiane Praza 	if (t == NULL)
2516*1f6eb021SLiane Praza 		return;
2517*1f6eb021SLiane Praza 
2518*1f6eb021SLiane Praza 	scf_pg_destroy(t->pt_pg);
2519*1f6eb021SLiane Praza 	scf_instance_destroy(t->pt_inst);
2520*1f6eb021SLiane Praza 	if (t->pt_inst != t->pt_orig_inst)
2521*1f6eb021SLiane Praza 		scf_instance_destroy(t->pt_orig_inst);
2522*1f6eb021SLiane Praza 	scf_snapshot_destroy(t->pt_snap);
2523*1f6eb021SLiane Praza 	scf_service_destroy(t->pt_orig_svc);
2524*1f6eb021SLiane Praza 	if (t->pt_svc != t->pt_orig_svc)
2525*1f6eb021SLiane Praza 		scf_service_destroy(t->pt_svc);
2526*1f6eb021SLiane Praza 	scf_iter_destroy(t->pt_iter);
2527*1f6eb021SLiane Praza 	free(t);
2528*1f6eb021SLiane Praza }
2529*1f6eb021SLiane Praza 
2530*1f6eb021SLiane Praza void
2531*1f6eb021SLiane Praza scf_tmpl_pg_reset(scf_pg_tmpl_t *t)
2532*1f6eb021SLiane Praza {
2533*1f6eb021SLiane Praza 	scf_pg_destroy(t->pt_pg);
2534*1f6eb021SLiane Praza 	t->pt_pg = NULL;
2535*1f6eb021SLiane Praza 
2536*1f6eb021SLiane Praza 	scf_instance_destroy(t->pt_inst);
2537*1f6eb021SLiane Praza 	if (t->pt_inst != t->pt_orig_inst)
2538*1f6eb021SLiane Praza 		scf_instance_destroy(t->pt_orig_inst);
2539*1f6eb021SLiane Praza 	t->pt_inst = NULL;
2540*1f6eb021SLiane Praza 	t->pt_orig_inst = NULL;
2541*1f6eb021SLiane Praza 
2542*1f6eb021SLiane Praza 	scf_snapshot_destroy(t->pt_snap);
2543*1f6eb021SLiane Praza 	t->pt_snap = NULL;
2544*1f6eb021SLiane Praza 
2545*1f6eb021SLiane Praza 	scf_service_destroy(t->pt_orig_svc);
2546*1f6eb021SLiane Praza 	if (t->pt_svc != t->pt_orig_svc)
2547*1f6eb021SLiane Praza 		scf_service_destroy(t->pt_svc);
2548*1f6eb021SLiane Praza 	t->pt_orig_svc = NULL;
2549*1f6eb021SLiane Praza 	t->pt_svc = NULL;
2550*1f6eb021SLiane Praza 
2551*1f6eb021SLiane Praza 	scf_iter_destroy(t->pt_iter);
2552*1f6eb021SLiane Praza 	t->pt_iter = NULL;
2553*1f6eb021SLiane Praza 
2554*1f6eb021SLiane Praza 	t->pt_populated = 0;
2555*1f6eb021SLiane Praza 	t->pt_is_iter = 0;
2556*1f6eb021SLiane Praza 	t->pt_iter_last = 0;
2557*1f6eb021SLiane Praza 
2558*1f6eb021SLiane Praza 	/* Do not reset t->pt_h. */
2559*1f6eb021SLiane Praza }
2560*1f6eb021SLiane Praza 
2561*1f6eb021SLiane Praza /*
2562*1f6eb021SLiane Praza  * int scf_tmpl_get_by_prop()
2563*1f6eb021SLiane Praza  *
2564*1f6eb021SLiane Praza  * Get the property template given a property group template and property
2565*1f6eb021SLiane Praza  * name.  No flags are currently defined for this function.
2566*1f6eb021SLiane Praza  *
2567*1f6eb021SLiane Praza  * Returns NULL on failure, and sets scf_error():
2568*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
2569*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
2570*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
2571*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
2572*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
2573*1f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
2574*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
2575*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
2576*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
2577*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
2578*1f6eb021SLiane Praza  *     Template object matching property doesn't exist in the repository.
2579*1f6eb021SLiane Praza  *   SCF_ERROR_TYPE_MISMATCH
2580*1f6eb021SLiane Praza  *     Matching template object is the wrong type in the repository.
2581*1f6eb021SLiane Praza  */
2582*1f6eb021SLiane Praza int
2583*1f6eb021SLiane Praza scf_tmpl_get_by_prop(scf_pg_tmpl_t *t, const char *prop,
2584*1f6eb021SLiane Praza     scf_prop_tmpl_t *prop_tmpl, int flags)
2585*1f6eb021SLiane Praza {
2586*1f6eb021SLiane Praza 	char *tmpl_prop_name;
2587*1f6eb021SLiane Praza 	scf_propertygroup_t *pg = NULL;
2588*1f6eb021SLiane Praza 	char *pg_type;
2589*1f6eb021SLiane Praza 	int found = 0;
2590*1f6eb021SLiane Praza 
2591*1f6eb021SLiane Praza 	if (flags != 0) {
2592*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
2593*1f6eb021SLiane Praza 		return (-1);
2594*1f6eb021SLiane Praza 	}
2595*1f6eb021SLiane Praza 
2596*1f6eb021SLiane Praza 	scf_tmpl_prop_reset(prop_tmpl);
2597*1f6eb021SLiane Praza 	if ((pg = scf_pg_create(scf_pg_handle(t->pt_pg))) == NULL)
2598*1f6eb021SLiane Praza 		return (-1);
2599*1f6eb021SLiane Praza 
2600*1f6eb021SLiane Praza 	tmpl_prop_name = _tmpl_prop_name(prop, t);
2601*1f6eb021SLiane Praza 	if (tmpl_prop_name == NULL) {
2602*1f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_NOT_SET);
2603*1f6eb021SLiane Praza 		return (-1);
2604*1f6eb021SLiane Praza 	}
2605*1f6eb021SLiane Praza 
2606*1f6eb021SLiane Praza 	if (_get_pg(t->pt_svc, t->pt_inst, t->pt_snap,
2607*1f6eb021SLiane Praza 	    tmpl_prop_name, pg) != 0) {
2608*1f6eb021SLiane Praza 		if (!ismember(scf_error(), errors_server)) {
2609*1f6eb021SLiane Praza 			switch (scf_error()) {
2610*1f6eb021SLiane Praza 			case SCF_ERROR_NOT_FOUND:
2611*1f6eb021SLiane Praza 			case SCF_ERROR_INVALID_ARGUMENT:
2612*1f6eb021SLiane Praza 				break;
2613*1f6eb021SLiane Praza 
2614*1f6eb021SLiane Praza 			case SCF_ERROR_NOT_SET:
2615*1f6eb021SLiane Praza 			case SCF_ERROR_HANDLE_MISMATCH:
2616*1f6eb021SLiane Praza 			default:
2617*1f6eb021SLiane Praza 				assert(0);
2618*1f6eb021SLiane Praza 				abort();
2619*1f6eb021SLiane Praza 			}
2620*1f6eb021SLiane Praza 		}
2621*1f6eb021SLiane Praza 	} else {
2622*1f6eb021SLiane Praza 		/*
2623*1f6eb021SLiane Praza 		 * We've only found a template property group if the type
2624*1f6eb021SLiane Praza 		 * is correct.
2625*1f6eb021SLiane Praza 		 */
2626*1f6eb021SLiane Praza 		if ((pg_type = _scf_get_pg_type(pg)) != NULL &&
2627*1f6eb021SLiane Praza 		    strcmp(pg_type, SCF_GROUP_TEMPLATE_PROP_PATTERN) == 0)
2628*1f6eb021SLiane Praza 			found++;
2629*1f6eb021SLiane Praza 		else
2630*1f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_TYPE_MISMATCH);
2631*1f6eb021SLiane Praza 
2632*1f6eb021SLiane Praza 
2633*1f6eb021SLiane Praza 		free(pg_type);
2634*1f6eb021SLiane Praza 	}
2635*1f6eb021SLiane Praza 
2636*1f6eb021SLiane Praza 	if (found == 0) {
2637*1f6eb021SLiane Praza 		scf_pg_destroy(pg);
2638*1f6eb021SLiane Praza 		free(tmpl_prop_name);
2639*1f6eb021SLiane Praza 		return (-1);
2640*1f6eb021SLiane Praza 	}
2641*1f6eb021SLiane Praza 
2642*1f6eb021SLiane Praza 	prop_tmpl->prt_h = scf_pg_handle(t->pt_pg);
2643*1f6eb021SLiane Praza 	prop_tmpl->prt_t = t;
2644*1f6eb021SLiane Praza 	prop_tmpl->prt_pg = pg;
2645*1f6eb021SLiane Praza 	prop_tmpl->prt_pg_name = tmpl_prop_name;
2646*1f6eb021SLiane Praza 	prop_tmpl->prt_populated = 1;
2647*1f6eb021SLiane Praza 
2648*1f6eb021SLiane Praza 	return (0);
2649*1f6eb021SLiane Praza }
2650*1f6eb021SLiane Praza 
2651*1f6eb021SLiane Praza /*
2652*1f6eb021SLiane Praza  * scf_prop_tmpl_t *scf_tmpl_prop_create(scf_handle_t *);
2653*1f6eb021SLiane Praza  *
2654*1f6eb021SLiane Praza  * Returns NULL on failure, sets scf_error() to _INVALID_ARGUMENT, or
2655*1f6eb021SLiane Praza  * _NO_MEMORY.
2656*1f6eb021SLiane Praza  */
2657*1f6eb021SLiane Praza scf_prop_tmpl_t *
2658*1f6eb021SLiane Praza scf_tmpl_prop_create(scf_handle_t *handle)
2659*1f6eb021SLiane Praza {
2660*1f6eb021SLiane Praza 	scf_prop_tmpl_t *pt;
2661*1f6eb021SLiane Praza 
2662*1f6eb021SLiane Praza 	if (handle == NULL) {
2663*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
2664*1f6eb021SLiane Praza 		return (NULL);
2665*1f6eb021SLiane Praza 	}
2666*1f6eb021SLiane Praza 	pt = calloc(1, sizeof (scf_prop_tmpl_t));
2667*1f6eb021SLiane Praza 	if (pt == NULL)
2668*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
2669*1f6eb021SLiane Praza 	else
2670*1f6eb021SLiane Praza 		pt->prt_h = handle;
2671*1f6eb021SLiane Praza 
2672*1f6eb021SLiane Praza 	return (pt);
2673*1f6eb021SLiane Praza }
2674*1f6eb021SLiane Praza 
2675*1f6eb021SLiane Praza /*
2676*1f6eb021SLiane Praza  * int scf_tmpl_iter_props()
2677*1f6eb021SLiane Praza  *
2678*1f6eb021SLiane Praza  * Iterates over all property templates defined in the specified property
2679*1f6eb021SLiane Praza  * group template.  The iterator state is stored on the property template
2680*1f6eb021SLiane Praza  * data structure, and the data structure should be allocated with
2681*1f6eb021SLiane Praza  * scf_tmpl_prop_create().  To continue the iteration, the previously
2682*1f6eb021SLiane Praza  * returned structure should be passed in as an argument to this function.
2683*1f6eb021SLiane Praza  * flags can include SCF_PROP_TMPL_FLAG_REQUIRED.  The function returns
2684*1f6eb021SLiane Praza  * 1 when a result was found, and 0 when the iteration is complete.
2685*1f6eb021SLiane Praza  *
2686*1f6eb021SLiane Praza  * Returns -1 on failure, and sets scf_error():
2687*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
2688*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
2689*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
2690*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
2691*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
2692*1f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
2693*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
2694*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
2695*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
2696*1f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
2697*1f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
2698*1f6eb021SLiane Praza  *     Template data is invalid.  One of the property templates in this
2699*1f6eb021SLiane Praza  *     pg_tmpl is malformed.
2700*1f6eb021SLiane Praza  */
2701*1f6eb021SLiane Praza int
2702*1f6eb021SLiane Praza scf_tmpl_iter_props(scf_pg_tmpl_t *t, scf_prop_tmpl_t *pt, int flags)
2703*1f6eb021SLiane Praza {
2704*1f6eb021SLiane Praza 	scf_prop_tmpl_t *prop_tmpl;
2705*1f6eb021SLiane Praza 	char *pg_pat;
2706*1f6eb021SLiane Praza 	char *pg_name = NULL;
2707*1f6eb021SLiane Praza 	int err;
2708*1f6eb021SLiane Praza 	int ret;
2709*1f6eb021SLiane Praza 	ssize_t size = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
2710*1f6eb021SLiane Praza 	uint8_t required;
2711*1f6eb021SLiane Praza 	scf_handle_t *h;
2712*1f6eb021SLiane Praza 	scf_propertygroup_t *pg = NULL;
2713*1f6eb021SLiane Praza 	scf_iter_t *iter = NULL;
2714*1f6eb021SLiane Praza 
2715*1f6eb021SLiane Praza 	assert(size != 0);
2716*1f6eb021SLiane Praza 	if (t == NULL || pt == NULL) {
2717*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
2718*1f6eb021SLiane Praza 		return (-1);
2719*1f6eb021SLiane Praza 	}
2720*1f6eb021SLiane Praza 
2721*1f6eb021SLiane Praza 	assert(t->pt_inst == NULL || t->pt_svc == NULL);
2722*1f6eb021SLiane Praza 	assert(t->pt_inst != NULL || t->pt_svc != NULL);
2723*1f6eb021SLiane Praza 
2724*1f6eb021SLiane Praza 	if ((pg_name = malloc(size)) == NULL) {
2725*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
2726*1f6eb021SLiane Praza 		return (-1);
2727*1f6eb021SLiane Praza 	}
2728*1f6eb021SLiane Praza 
2729*1f6eb021SLiane Praza 	if (pt->prt_populated == 0) {
2730*1f6eb021SLiane Praza 		if ((h = scf_pg_handle(t->pt_pg)) == NULL)
2731*1f6eb021SLiane Praza 			goto fail_non_populated;
2732*1f6eb021SLiane Praza 
2733*1f6eb021SLiane Praza 		if ((pg = scf_pg_create(h)) == NULL ||
2734*1f6eb021SLiane Praza 		    (iter = scf_iter_create(h)) == NULL)
2735*1f6eb021SLiane Praza 			goto fail_non_populated;
2736*1f6eb021SLiane Praza 
2737*1f6eb021SLiane Praza 		if (t->pt_inst != NULL)
2738*1f6eb021SLiane Praza 			err = scf_iter_instance_pgs_typed_composed(iter,
2739*1f6eb021SLiane Praza 			    t->pt_inst, t->pt_snap,
2740*1f6eb021SLiane Praza 			    SCF_GROUP_TEMPLATE_PROP_PATTERN);
2741*1f6eb021SLiane Praza 		else if (t->pt_svc != NULL)
2742*1f6eb021SLiane Praza 			err = scf_iter_service_pgs_typed(iter, t->pt_svc,
2743*1f6eb021SLiane Praza 			    SCF_GROUP_TEMPLATE_PROP_PATTERN);
2744*1f6eb021SLiane Praza 
2745*1f6eb021SLiane Praza 		if (err != 0) {
2746*1f6eb021SLiane Praza 			if (ismember(scf_error(), errors_server)) {
2747*1f6eb021SLiane Praza 				goto fail_non_populated;
2748*1f6eb021SLiane Praza 			} else switch (scf_error()) {
2749*1f6eb021SLiane Praza 			case SCF_ERROR_INVALID_ARGUMENT:
2750*1f6eb021SLiane Praza 				goto fail_non_populated;
2751*1f6eb021SLiane Praza 
2752*1f6eb021SLiane Praza 			case SCF_ERROR_NOT_SET:
2753*1f6eb021SLiane Praza 			case SCF_ERROR_HANDLE_MISMATCH:
2754*1f6eb021SLiane Praza 			default:
2755*1f6eb021SLiane Praza 				assert(0);
2756*1f6eb021SLiane Praza 				abort();
2757*1f6eb021SLiane Praza 			}
2758*1f6eb021SLiane Praza 
2759*1f6eb021SLiane Praza 		}
2760*1f6eb021SLiane Praza 		prop_tmpl = pt;
2761*1f6eb021SLiane Praza 		prop_tmpl->prt_t = t;
2762*1f6eb021SLiane Praza 		prop_tmpl->prt_populated = 1;
2763*1f6eb021SLiane Praza 		prop_tmpl->prt_pg = pg;
2764*1f6eb021SLiane Praza 		prop_tmpl->prt_iter = iter;
2765*1f6eb021SLiane Praza 	} else {
2766*1f6eb021SLiane Praza 		prop_tmpl = pt;
2767*1f6eb021SLiane Praza 	}
2768*1f6eb021SLiane Praza 
2769*1f6eb021SLiane Praza 	while ((err = scf_iter_next_pg(prop_tmpl->prt_iter,
2770*1f6eb021SLiane Praza 	    prop_tmpl->prt_pg)) > 0) {
2771*1f6eb021SLiane Praza 		/*
2772*1f6eb021SLiane Praza 		 * Check if the name matches the appropriate property
2773*1f6eb021SLiane Praza 		 * group template name.
2774*1f6eb021SLiane Praza 		 */
2775*1f6eb021SLiane Praza 		pg_pat = _scf_read_single_astring_from_pg(prop_tmpl->prt_pg,
2776*1f6eb021SLiane Praza 		    SCF_PROPERTY_TM_PG_PATTERN);
2777*1f6eb021SLiane Praza 		if (pg_pat == NULL) {
2778*1f6eb021SLiane Praza 			if (ismember(scf_error(), errors_server)) {
2779*1f6eb021SLiane Praza 				uu_free(pg_name);
2780*1f6eb021SLiane Praza 				return (-1);
2781*1f6eb021SLiane Praza 			} else switch (scf_error()) {
2782*1f6eb021SLiane Praza 			case SCF_ERROR_NOT_FOUND:
2783*1f6eb021SLiane Praza 				continue;
2784*1f6eb021SLiane Praza 
2785*1f6eb021SLiane Praza 			case SCF_ERROR_CONSTRAINT_VIOLATED:
2786*1f6eb021SLiane Praza 			case SCF_ERROR_TYPE_MISMATCH:
2787*1f6eb021SLiane Praza 				(void) scf_set_error(
2788*1f6eb021SLiane Praza 				    SCF_ERROR_TEMPLATE_INVALID);
2789*1f6eb021SLiane Praza 				free(pg_name);
2790*1f6eb021SLiane Praza 				return (-1);
2791*1f6eb021SLiane Praza 
2792*1f6eb021SLiane Praza 			case SCF_ERROR_INVALID_ARGUMENT:
2793*1f6eb021SLiane Praza 			case SCF_ERROR_NOT_SET:
2794*1f6eb021SLiane Praza 			default:
2795*1f6eb021SLiane Praza 				assert(0);
2796*1f6eb021SLiane Praza 				abort();
2797*1f6eb021SLiane Praza 			}
2798*1f6eb021SLiane Praza 		}
2799*1f6eb021SLiane Praza 		if ((ret = scf_pg_get_name(t->pt_pg, pg_name, size)) <= 0) {
2800*1f6eb021SLiane Praza 			free(pg_pat);
2801*1f6eb021SLiane Praza 			if (ret == 0)
2802*1f6eb021SLiane Praza 				continue;
2803*1f6eb021SLiane Praza 
2804*1f6eb021SLiane Praza 			if (ismember(scf_error(), errors_server)) {
2805*1f6eb021SLiane Praza 				free(pg_name);
2806*1f6eb021SLiane Praza 				return (-1);
2807*1f6eb021SLiane Praza 			} else {
2808*1f6eb021SLiane Praza 				assert(0);
2809*1f6eb021SLiane Praza 				abort();
2810*1f6eb021SLiane Praza 			}
2811*1f6eb021SLiane Praza 		}
2812*1f6eb021SLiane Praza 		if (strcmp(pg_pat, pg_name) != 0) {
2813*1f6eb021SLiane Praza 			free(pg_pat);
2814*1f6eb021SLiane Praza 			continue;
2815*1f6eb021SLiane Praza 		}
2816*1f6eb021SLiane Praza 		free(pg_pat);
2817*1f6eb021SLiane Praza 
2818*1f6eb021SLiane Praza 		/*
2819*1f6eb021SLiane Praza 		 * If walking only required properties, check if
2820*1f6eb021SLiane Praza 		 * the retrieved property is required.
2821*1f6eb021SLiane Praza 		 */
2822*1f6eb021SLiane Praza 		if (flags & SCF_PROP_TMPL_FLAG_REQUIRED) {
2823*1f6eb021SLiane Praza 			if (scf_tmpl_prop_required(prop_tmpl, &required) == 0) {
2824*1f6eb021SLiane Praza 				if (required == 0)
2825*1f6eb021SLiane Praza 					continue;
2826*1f6eb021SLiane Praza 			} else {
2827*1f6eb021SLiane Praza 				free(pg_name);
2828*1f6eb021SLiane Praza 				return (-1);
2829*1f6eb021SLiane Praza 			}
2830*1f6eb021SLiane Praza 		}
2831*1f6eb021SLiane Praza 		free(pg_name);
2832*1f6eb021SLiane Praza 		return (0);
2833*1f6eb021SLiane Praza 	}
2834*1f6eb021SLiane Praza 
2835*1f6eb021SLiane Praza 	if (err == -1) {
2836*1f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
2837*1f6eb021SLiane Praza 			free(pg_name);
2838*1f6eb021SLiane Praza 			return (-1);
2839*1f6eb021SLiane Praza 		} else {
2840*1f6eb021SLiane Praza 			assert(0);
2841*1f6eb021SLiane Praza 			abort();
2842*1f6eb021SLiane Praza 		}
2843*1f6eb021SLiane Praza 	} else if (err == 0)  {
2844*1f6eb021SLiane Praza 		scf_iter_destroy(prop_tmpl->prt_iter);
2845*1f6eb021SLiane Praza 		prop_tmpl->prt_iter = NULL;
2846*1f6eb021SLiane Praza 		prop_tmpl->prt_populated = 0;
2847*1f6eb021SLiane Praza 	}
2848*1f6eb021SLiane Praza 	free(pg_name);
2849*1f6eb021SLiane Praza 
2850*1f6eb021SLiane Praza 	return (1);
2851*1f6eb021SLiane Praza 
2852*1f6eb021SLiane Praza fail_non_populated:
2853*1f6eb021SLiane Praza 	free(pg_name);
2854*1f6eb021SLiane Praza 	scf_pg_destroy(pg);
2855*1f6eb021SLiane Praza 	scf_iter_destroy(iter);
2856*1f6eb021SLiane Praza 	return (-1);
2857*1f6eb021SLiane Praza }
2858*1f6eb021SLiane Praza 
2859*1f6eb021SLiane Praza void
2860*1f6eb021SLiane Praza scf_tmpl_prop_destroy(scf_prop_tmpl_t *t)
2861*1f6eb021SLiane Praza {
2862*1f6eb021SLiane Praza 	if (t == NULL)
2863*1f6eb021SLiane Praza 		return;
2864*1f6eb021SLiane Praza 
2865*1f6eb021SLiane Praza 	scf_pg_destroy(t->prt_pg);
2866*1f6eb021SLiane Praza 	free(t->prt_pg_name);
2867*1f6eb021SLiane Praza 	free(t->prt_iter);
2868*1f6eb021SLiane Praza 	free(t);
2869*1f6eb021SLiane Praza }
2870*1f6eb021SLiane Praza 
2871*1f6eb021SLiane Praza void
2872*1f6eb021SLiane Praza scf_tmpl_prop_reset(scf_prop_tmpl_t *t)
2873*1f6eb021SLiane Praza {
2874*1f6eb021SLiane Praza 	scf_pg_destroy(t->prt_pg);
2875*1f6eb021SLiane Praza 	t->prt_pg = NULL;
2876*1f6eb021SLiane Praza 
2877*1f6eb021SLiane Praza 	free(t->prt_pg_name);
2878*1f6eb021SLiane Praza 	t->prt_pg_name = NULL;
2879*1f6eb021SLiane Praza 
2880*1f6eb021SLiane Praza 	free(t->prt_iter);
2881*1f6eb021SLiane Praza 	t->prt_iter = NULL;
2882*1f6eb021SLiane Praza 
2883*1f6eb021SLiane Praza 	t->prt_populated = 0;
2884*1f6eb021SLiane Praza 	t->prt_h = NULL;
2885*1f6eb021SLiane Praza 	t->prt_t = NULL;
2886*1f6eb021SLiane Praza }
2887*1f6eb021SLiane Praza 
2888*1f6eb021SLiane Praza /*
2889*1f6eb021SLiane Praza  * Returns -1 on failure.  Sets scf_error():
2890*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
2891*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
2892*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
2893*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
2894*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
2895*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
2896*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
2897*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
2898*1f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
2899*1f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
2900*1f6eb021SLiane Praza  *     The name of the template property group (the pname property) has
2901*1f6eb021SLiane Praza  *     an improper repository format and is not type astring or has
2902*1f6eb021SLiane Praza  *     more than one value.
2903*1f6eb021SLiane Praza  */
2904*1f6eb021SLiane Praza ssize_t
2905*1f6eb021SLiane Praza scf_tmpl_pg_name(const scf_pg_tmpl_t *t, char **out)
2906*1f6eb021SLiane Praza {
2907*1f6eb021SLiane Praza 	return (_scf_tmpl_prop_value(t->pt_pg, SCF_PROPERTY_TM_NAME, out));
2908*1f6eb021SLiane Praza }
2909*1f6eb021SLiane Praza 
2910*1f6eb021SLiane Praza /*
2911*1f6eb021SLiane Praza  * returns an allocated string that must be freed
2912*1f6eb021SLiane Praza  *
2913*1f6eb021SLiane Praza  * Returns NULL on failure, sets scf_error() to:
2914*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
2915*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
2916*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
2917*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
2918*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
2919*1f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
2920*1f6eb021SLiane Praza  *     name not a valid property name
2921*1f6eb021SLiane Praza  *     name and locale are too long to make a property name
2922*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
2923*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
2924*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
2925*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
2926*1f6eb021SLiane Praza  *     Property doesn't exist or exists and has no value.
2927*1f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
2928*1f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
2929*1f6eb021SLiane Praza  */
2930*1f6eb021SLiane Praza static char *
2931*1f6eb021SLiane Praza _read_localized_astring_from_pg(scf_propertygroup_t *pg, const char *name,
2932*1f6eb021SLiane Praza     const char *locale)
2933*1f6eb021SLiane Praza {
2934*1f6eb021SLiane Praza 	char *str;
2935*1f6eb021SLiane Praza 	char *lname_prop;
2936*1f6eb021SLiane Praza 
2937*1f6eb021SLiane Praza 	str = _add_locale_to_name(name, locale);
2938*1f6eb021SLiane Praza 	if (str == NULL)
2939*1f6eb021SLiane Praza 		return (NULL);
2940*1f6eb021SLiane Praza 	lname_prop = _scf_read_single_astring_from_pg(pg, str);
2941*1f6eb021SLiane Praza 	if (lname_prop == NULL) {
2942*1f6eb021SLiane Praza 		free(str);
2943*1f6eb021SLiane Praza 		if (scf_error() != SCF_ERROR_NOT_FOUND)
2944*1f6eb021SLiane Praza 			return (NULL);
2945*1f6eb021SLiane Praza 		str = _add_locale_to_name(name, "C");
2946*1f6eb021SLiane Praza 		if (str == NULL)
2947*1f6eb021SLiane Praza 			return (NULL);
2948*1f6eb021SLiane Praza 		lname_prop = _scf_read_single_astring_from_pg(pg, str);
2949*1f6eb021SLiane Praza 	}
2950*1f6eb021SLiane Praza 	free(str);
2951*1f6eb021SLiane Praza 	if (lname_prop == NULL) {
2952*1f6eb021SLiane Praza 		if (scf_error() == SCF_ERROR_TYPE_MISMATCH ||
2953*1f6eb021SLiane Praza 		    scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED)
2954*1f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
2955*1f6eb021SLiane Praza 	}
2956*1f6eb021SLiane Praza 	return (lname_prop);
2957*1f6eb021SLiane Praza }
2958*1f6eb021SLiane Praza 
2959*1f6eb021SLiane Praza /*
2960*1f6eb021SLiane Praza  * returns an allocated string that must be freed
2961*1f6eb021SLiane Praza  *
2962*1f6eb021SLiane Praza  * Returns -1 on failure, sets scf_error() to:
2963*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
2964*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
2965*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
2966*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
2967*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
2968*1f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
2969*1f6eb021SLiane Praza  *     locale is too long to make a valid property name
2970*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
2971*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
2972*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
2973*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
2974*1f6eb021SLiane Praza  *     Property doesn't exist or exists and has no value.
2975*1f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
2976*1f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
2977*1f6eb021SLiane Praza  */
2978*1f6eb021SLiane Praza ssize_t
2979*1f6eb021SLiane Praza scf_tmpl_pg_common_name(const scf_pg_tmpl_t *t, const char *locale, char **out)
2980*1f6eb021SLiane Praza {
2981*1f6eb021SLiane Praza 	assert(out != NULL);
2982*1f6eb021SLiane Praza 	if ((*out = _read_localized_astring_from_pg(t->pt_pg,
2983*1f6eb021SLiane Praza 	    SCF_PROPERTY_TM_COMMON_NAME_PREFIX, locale)) == NULL)
2984*1f6eb021SLiane Praza 		return (-1);
2985*1f6eb021SLiane Praza 
2986*1f6eb021SLiane Praza 	return (strlen(*out));
2987*1f6eb021SLiane Praza }
2988*1f6eb021SLiane Praza 
2989*1f6eb021SLiane Praza /*
2990*1f6eb021SLiane Praza  * returns an allocated string that must be freed
2991*1f6eb021SLiane Praza  *
2992*1f6eb021SLiane Praza  * Returns -1 on failure, sets scf_error() to:
2993*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
2994*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
2995*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
2996*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
2997*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
2998*1f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
2999*1f6eb021SLiane Praza  *     locale is too long to make a valid property name
3000*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
3001*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
3002*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
3003*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
3004*1f6eb021SLiane Praza  *     Property doesn't exist or exists and has no value.
3005*1f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
3006*1f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
3007*1f6eb021SLiane Praza  */
3008*1f6eb021SLiane Praza ssize_t
3009*1f6eb021SLiane Praza scf_tmpl_pg_description(const scf_pg_tmpl_t *t, const char *locale, char **out)
3010*1f6eb021SLiane Praza {
3011*1f6eb021SLiane Praza 	assert(out != NULL);
3012*1f6eb021SLiane Praza 	if ((*out = _read_localized_astring_from_pg(t->pt_pg,
3013*1f6eb021SLiane Praza 	    SCF_PROPERTY_TM_DESCRIPTION_PREFIX, locale)) == NULL)
3014*1f6eb021SLiane Praza 		return (-1);
3015*1f6eb021SLiane Praza 
3016*1f6eb021SLiane Praza 	return (strlen(*out));
3017*1f6eb021SLiane Praza }
3018*1f6eb021SLiane Praza 
3019*1f6eb021SLiane Praza /*
3020*1f6eb021SLiane Praza  * Returns -1 on failure.  Sets scf_error():
3021*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
3022*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
3023*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
3024*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
3025*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
3026*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
3027*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
3028*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
3029*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
3030*1f6eb021SLiane Praza  *     'type' property doesn't exist or exists and has no value.
3031*1f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
3032*1f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
3033*1f6eb021SLiane Praza  *     'type' property is not SCF_TYPE_ASTRING or has more than one value.
3034*1f6eb021SLiane Praza  */
3035*1f6eb021SLiane Praza ssize_t
3036*1f6eb021SLiane Praza scf_tmpl_pg_type(const scf_pg_tmpl_t *t, char **out)
3037*1f6eb021SLiane Praza {
3038*1f6eb021SLiane Praza 	return (_scf_tmpl_prop_value(t->pt_pg, SCF_PROPERTY_TM_TYPE, out));
3039*1f6eb021SLiane Praza }
3040*1f6eb021SLiane Praza 
3041*1f6eb021SLiane Praza /*
3042*1f6eb021SLiane Praza  * Returns -1 on failure, sets scf_error() to:
3043*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
3044*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
3045*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
3046*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
3047*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
3048*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
3049*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
3050*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
3051*1f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
3052*1f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
3053*1f6eb021SLiane Praza  *     required property is not SCF_TYPE_BOOLEAN or has more than one value.
3054*1f6eb021SLiane Praza  */
3055*1f6eb021SLiane Praza int
3056*1f6eb021SLiane Praza scf_tmpl_pg_required(const scf_pg_tmpl_t *t, uint8_t *out)
3057*1f6eb021SLiane Praza {
3058*1f6eb021SLiane Praza 
3059*1f6eb021SLiane Praza 	if (_read_single_boolean_from_pg(t->pt_pg, SCF_PROPERTY_TM_REQUIRED,
3060*1f6eb021SLiane Praza 	    out) == -1) {
3061*1f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
3062*1f6eb021SLiane Praza 			return (-1);
3063*1f6eb021SLiane Praza 		} else switch (scf_error()) {
3064*1f6eb021SLiane Praza 		case SCF_ERROR_CONSTRAINT_VIOLATED:
3065*1f6eb021SLiane Praza 		case SCF_ERROR_TYPE_MISMATCH:
3066*1f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
3067*1f6eb021SLiane Praza 			return (-1);
3068*1f6eb021SLiane Praza 
3069*1f6eb021SLiane Praza 		case SCF_ERROR_NOT_FOUND:
3070*1f6eb021SLiane Praza 			*out = 0;
3071*1f6eb021SLiane Praza 			return (0);
3072*1f6eb021SLiane Praza 
3073*1f6eb021SLiane Praza 		case SCF_ERROR_INVALID_ARGUMENT:
3074*1f6eb021SLiane Praza 		default:
3075*1f6eb021SLiane Praza 			assert(0);
3076*1f6eb021SLiane Praza 			abort();
3077*1f6eb021SLiane Praza 		}
3078*1f6eb021SLiane Praza 	}
3079*1f6eb021SLiane Praza 
3080*1f6eb021SLiane Praza 	return (0);
3081*1f6eb021SLiane Praza }
3082*1f6eb021SLiane Praza 
3083*1f6eb021SLiane Praza /*
3084*1f6eb021SLiane Praza  * Returns -1 on failure.  Sets scf_error():
3085*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
3086*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
3087*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
3088*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
3089*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
3090*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
3091*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
3092*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
3093*1f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
3094*1f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
3095*1f6eb021SLiane Praza  *     target property is not SCF_TYPE_ASTRING or has more than one value.
3096*1f6eb021SLiane Praza  */
3097*1f6eb021SLiane Praza ssize_t
3098*1f6eb021SLiane Praza scf_tmpl_pg_target(const scf_pg_tmpl_t *t, char **out)
3099*1f6eb021SLiane Praza {
3100*1f6eb021SLiane Praza 	*out = _scf_read_single_astring_from_pg(t->pt_pg,
3101*1f6eb021SLiane Praza 	    SCF_PROPERTY_TM_TARGET);
3102*1f6eb021SLiane Praza 
3103*1f6eb021SLiane Praza 	if (*out == NULL) {
3104*1f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
3105*1f6eb021SLiane Praza 			return (-1);
3106*1f6eb021SLiane Praza 		} else switch (scf_error()) {
3107*1f6eb021SLiane Praza 		case SCF_ERROR_CONSTRAINT_VIOLATED:
3108*1f6eb021SLiane Praza 		case SCF_ERROR_NOT_FOUND:
3109*1f6eb021SLiane Praza 		case SCF_ERROR_TYPE_MISMATCH:
3110*1f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
3111*1f6eb021SLiane Praza 			return (-1);
3112*1f6eb021SLiane Praza 
3113*1f6eb021SLiane Praza 		case SCF_ERROR_INVALID_ARGUMENT:
3114*1f6eb021SLiane Praza 		case SCF_ERROR_NOT_SET:
3115*1f6eb021SLiane Praza 		default:
3116*1f6eb021SLiane Praza 			assert(0);
3117*1f6eb021SLiane Praza 			abort();
3118*1f6eb021SLiane Praza 		}
3119*1f6eb021SLiane Praza 	}
3120*1f6eb021SLiane Praza 
3121*1f6eb021SLiane Praza 	return (strlen(*out));
3122*1f6eb021SLiane Praza }
3123*1f6eb021SLiane Praza 
3124*1f6eb021SLiane Praza /*
3125*1f6eb021SLiane Praza  * Returns -1 on failure.  Sets scf_error():
3126*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
3127*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
3128*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
3129*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
3130*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
3131*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
3132*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
3133*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
3134*1f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
3135*1f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
3136*1f6eb021SLiane Praza  */
3137*1f6eb021SLiane Praza ssize_t
3138*1f6eb021SLiane Praza scf_tmpl_prop_name(const scf_prop_tmpl_t *t, char **out)
3139*1f6eb021SLiane Praza {
3140*1f6eb021SLiane Praza 	*out = _scf_read_single_astring_from_pg(t->prt_pg,
3141*1f6eb021SLiane Praza 	    SCF_PROPERTY_TM_NAME);
3142*1f6eb021SLiane Praza 
3143*1f6eb021SLiane Praza 	if (*out != NULL && *out[0] == '\0') {
3144*1f6eb021SLiane Praza 		free(*out);
3145*1f6eb021SLiane Praza 		*out = NULL;
3146*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
3147*1f6eb021SLiane Praza 	}
3148*1f6eb021SLiane Praza 	if (*out == NULL) {
3149*1f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
3150*1f6eb021SLiane Praza 			return (-1);
3151*1f6eb021SLiane Praza 		} else switch (scf_error()) {
3152*1f6eb021SLiane Praza 		case SCF_ERROR_CONSTRAINT_VIOLATED:
3153*1f6eb021SLiane Praza 		case SCF_ERROR_NOT_FOUND:
3154*1f6eb021SLiane Praza 		case SCF_ERROR_TEMPLATE_INVALID:
3155*1f6eb021SLiane Praza 		case SCF_ERROR_TYPE_MISMATCH:
3156*1f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
3157*1f6eb021SLiane Praza 			return (-1);
3158*1f6eb021SLiane Praza 
3159*1f6eb021SLiane Praza 		case SCF_ERROR_INVALID_ARGUMENT:
3160*1f6eb021SLiane Praza 		case SCF_ERROR_NOT_SET:
3161*1f6eb021SLiane Praza 		default:
3162*1f6eb021SLiane Praza 			assert(0);
3163*1f6eb021SLiane Praza 			abort();
3164*1f6eb021SLiane Praza 		}
3165*1f6eb021SLiane Praza 	}
3166*1f6eb021SLiane Praza 
3167*1f6eb021SLiane Praza 	return (strlen(*out));
3168*1f6eb021SLiane Praza }
3169*1f6eb021SLiane Praza 
3170*1f6eb021SLiane Praza /*
3171*1f6eb021SLiane Praza  * Returns -1 on failure.  Sets scf_error():
3172*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
3173*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
3174*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
3175*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
3176*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
3177*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
3178*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
3179*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
3180*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
3181*1f6eb021SLiane Praza  *     'type' property doesn't exist or exists and has no value.
3182*1f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
3183*1f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
3184*1f6eb021SLiane Praza  *     'type' property is not SCF_TYPE_ASTRING, has more than one value,
3185*1f6eb021SLiane Praza  *     is SCF_TYPE_INVALID, or is the empty string.
3186*1f6eb021SLiane Praza  */
3187*1f6eb021SLiane Praza int
3188*1f6eb021SLiane Praza scf_tmpl_prop_type(const scf_prop_tmpl_t *t, scf_type_t *out)
3189*1f6eb021SLiane Praza {
3190*1f6eb021SLiane Praza 	char *type;
3191*1f6eb021SLiane Praza 
3192*1f6eb021SLiane Praza 	type = _scf_read_single_astring_from_pg(t->prt_pg,
3193*1f6eb021SLiane Praza 	    SCF_PROPERTY_TM_TYPE);
3194*1f6eb021SLiane Praza 	if (type != NULL && type[0] == '\0') {
3195*1f6eb021SLiane Praza 		free(type);
3196*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NOT_FOUND);
3197*1f6eb021SLiane Praza 		return (-1);
3198*1f6eb021SLiane Praza 	}
3199*1f6eb021SLiane Praza 	if (type == NULL) {
3200*1f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
3201*1f6eb021SLiane Praza 			return (-1);
3202*1f6eb021SLiane Praza 		} else switch (scf_error()) {
3203*1f6eb021SLiane Praza 		case SCF_ERROR_CONSTRAINT_VIOLATED:
3204*1f6eb021SLiane Praza 		case SCF_ERROR_TYPE_MISMATCH:
3205*1f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
3206*1f6eb021SLiane Praza 			/*FALLTHROUGH*/
3207*1f6eb021SLiane Praza 
3208*1f6eb021SLiane Praza 		case SCF_ERROR_NOT_FOUND:
3209*1f6eb021SLiane Praza 			return (-1);
3210*1f6eb021SLiane Praza 
3211*1f6eb021SLiane Praza 		case SCF_ERROR_INVALID_ARGUMENT:
3212*1f6eb021SLiane Praza 		case SCF_ERROR_NOT_SET:
3213*1f6eb021SLiane Praza 		default:
3214*1f6eb021SLiane Praza 			assert(0);
3215*1f6eb021SLiane Praza 			abort();
3216*1f6eb021SLiane Praza 		}
3217*1f6eb021SLiane Praza 	}
3218*1f6eb021SLiane Praza 
3219*1f6eb021SLiane Praza 	*out = scf_string_to_type(type);
3220*1f6eb021SLiane Praza 	free(type);
3221*1f6eb021SLiane Praza 
3222*1f6eb021SLiane Praza 	if (*out == SCF_TYPE_INVALID) {
3223*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
3224*1f6eb021SLiane Praza 		return (-1);
3225*1f6eb021SLiane Praza 	}
3226*1f6eb021SLiane Praza 
3227*1f6eb021SLiane Praza 	return (0);
3228*1f6eb021SLiane Praza }
3229*1f6eb021SLiane Praza 
3230*1f6eb021SLiane Praza /*
3231*1f6eb021SLiane Praza  * Returns -1 on failure, sets scf_error() to:
3232*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
3233*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
3234*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
3235*1f6eb021SLiane Praza  *    Property group which represents t was deleted.
3236*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
3237*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
3238*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
3239*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
3240*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
3241*1f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
3242*1f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
3243*1f6eb021SLiane Praza  *     required property is not SCF_TYPE_ASTRING has more than one value.
3244*1f6eb021SLiane Praza  */
3245*1f6eb021SLiane Praza int
3246*1f6eb021SLiane Praza scf_tmpl_prop_required(const scf_prop_tmpl_t *t, uint8_t *out)
3247*1f6eb021SLiane Praza {
3248*1f6eb021SLiane Praza 	if (_read_single_boolean_from_pg(t->prt_pg, SCF_PROPERTY_TM_REQUIRED,
3249*1f6eb021SLiane Praza 	    out) == -1) {
3250*1f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
3251*1f6eb021SLiane Praza 			return (-1);
3252*1f6eb021SLiane Praza 		} else switch (scf_error()) {
3253*1f6eb021SLiane Praza 		case SCF_ERROR_CONSTRAINT_VIOLATED:
3254*1f6eb021SLiane Praza 		case SCF_ERROR_TYPE_MISMATCH:
3255*1f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
3256*1f6eb021SLiane Praza 			return (-1);
3257*1f6eb021SLiane Praza 
3258*1f6eb021SLiane Praza 		case SCF_ERROR_NOT_FOUND:
3259*1f6eb021SLiane Praza 			*out = 0;
3260*1f6eb021SLiane Praza 			return (0);
3261*1f6eb021SLiane Praza 
3262*1f6eb021SLiane Praza 		case SCF_ERROR_INVALID_ARGUMENT:
3263*1f6eb021SLiane Praza 		case SCF_ERROR_NOT_SET:
3264*1f6eb021SLiane Praza 		default:
3265*1f6eb021SLiane Praza 			assert(0);
3266*1f6eb021SLiane Praza 			abort();
3267*1f6eb021SLiane Praza 		}
3268*1f6eb021SLiane Praza 	}
3269*1f6eb021SLiane Praza 
3270*1f6eb021SLiane Praza 	return (0);
3271*1f6eb021SLiane Praza }
3272*1f6eb021SLiane Praza 
3273*1f6eb021SLiane Praza /*
3274*1f6eb021SLiane Praza  * Returns -1 on failure.  Sets scf_error():
3275*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
3276*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
3277*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
3278*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
3279*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
3280*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
3281*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
3282*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
3283*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
3284*1f6eb021SLiane Praza  *     Property doesn't exist or exists and has no value.
3285*1f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
3286*1f6eb021SLiane Praza  *     locale is too long to make a property name
3287*1f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
3288*1f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
3289*1f6eb021SLiane Praza  *     common_name property is not SCF_TYPE_ASTRING has more than one value.
3290*1f6eb021SLiane Praza  */
3291*1f6eb021SLiane Praza ssize_t
3292*1f6eb021SLiane Praza scf_tmpl_prop_common_name(const scf_prop_tmpl_t *t, const char *locale,
3293*1f6eb021SLiane Praza     char **out)
3294*1f6eb021SLiane Praza {
3295*1f6eb021SLiane Praza 	assert(out != NULL);
3296*1f6eb021SLiane Praza 	if ((*out = _read_localized_astring_from_pg(t->prt_pg,
3297*1f6eb021SLiane Praza 	    SCF_PROPERTY_TM_COMMON_NAME_PREFIX, locale)) == NULL)
3298*1f6eb021SLiane Praza 		return (-1);
3299*1f6eb021SLiane Praza 
3300*1f6eb021SLiane Praza 	return (strlen(*out));
3301*1f6eb021SLiane Praza }
3302*1f6eb021SLiane Praza 
3303*1f6eb021SLiane Praza /*
3304*1f6eb021SLiane Praza  * Returns -1 on failure.  Sets scf_error():
3305*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
3306*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
3307*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
3308*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
3309*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
3310*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
3311*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
3312*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
3313*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
3314*1f6eb021SLiane Praza  *     Property doesn't exist or exists and has no value.
3315*1f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
3316*1f6eb021SLiane Praza  *     locale is too long to make a property name
3317*1f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
3318*1f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
3319*1f6eb021SLiane Praza  *     description property is not SCF_TYPE_ASTRING has more than one value.
3320*1f6eb021SLiane Praza  */
3321*1f6eb021SLiane Praza ssize_t
3322*1f6eb021SLiane Praza scf_tmpl_prop_description(const scf_prop_tmpl_t *t, const char *locale,
3323*1f6eb021SLiane Praza     char **out)
3324*1f6eb021SLiane Praza {
3325*1f6eb021SLiane Praza 	assert(out != NULL);
3326*1f6eb021SLiane Praza 	if ((*out = _read_localized_astring_from_pg(t->prt_pg,
3327*1f6eb021SLiane Praza 	    SCF_PROPERTY_TM_DESCRIPTION_PREFIX, locale)) == NULL)
3328*1f6eb021SLiane Praza 		return (-1);
3329*1f6eb021SLiane Praza 
3330*1f6eb021SLiane Praza 	return (strlen(*out));
3331*1f6eb021SLiane Praza }
3332*1f6eb021SLiane Praza 
3333*1f6eb021SLiane Praza /*
3334*1f6eb021SLiane Praza  * Returns -1 on failure.  Sets scf_error():
3335*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
3336*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
3337*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
3338*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
3339*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
3340*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
3341*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
3342*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
3343*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
3344*1f6eb021SLiane Praza  *     Property doesn't exist or exists and has no value.
3345*1f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
3346*1f6eb021SLiane Praza  *     locale is too long to make a property name
3347*1f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
3348*1f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
3349*1f6eb021SLiane Praza  *     units property is not SCF_TYPE_ASTRING has more than one value.
3350*1f6eb021SLiane Praza  */
3351*1f6eb021SLiane Praza ssize_t
3352*1f6eb021SLiane Praza scf_tmpl_prop_units(const scf_prop_tmpl_t *t, const char *locale, char **out)
3353*1f6eb021SLiane Praza {
3354*1f6eb021SLiane Praza 	assert(out != NULL);
3355*1f6eb021SLiane Praza 	if ((*out = _read_localized_astring_from_pg(t->prt_pg,
3356*1f6eb021SLiane Praza 	    SCF_PROPERTY_TM_UNITS_PREFIX, locale)) == NULL)
3357*1f6eb021SLiane Praza 		return (-1);
3358*1f6eb021SLiane Praza 
3359*1f6eb021SLiane Praza 	return (strlen(*out));
3360*1f6eb021SLiane Praza }
3361*1f6eb021SLiane Praza 
3362*1f6eb021SLiane Praza /*
3363*1f6eb021SLiane Praza  * Returns -1 on failure.  Sets scf_error():
3364*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
3365*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
3366*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
3367*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
3368*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
3369*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
3370*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
3371*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
3372*1f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
3373*1f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
3374*1f6eb021SLiane Praza  *     visibility property is not SCF_TYPE_ASTRING has more than one value.
3375*1f6eb021SLiane Praza  */
3376*1f6eb021SLiane Praza int
3377*1f6eb021SLiane Praza scf_tmpl_prop_visibility(const scf_prop_tmpl_t *t, uint8_t *out)
3378*1f6eb021SLiane Praza {
3379*1f6eb021SLiane Praza 	char *visibility;
3380*1f6eb021SLiane Praza 
3381*1f6eb021SLiane Praza 	visibility = _scf_read_single_astring_from_pg(t->prt_pg,
3382*1f6eb021SLiane Praza 	    SCF_PROPERTY_TM_VISIBILITY);
3383*1f6eb021SLiane Praza 	if (visibility == NULL) {
3384*1f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
3385*1f6eb021SLiane Praza 			return (-1);
3386*1f6eb021SLiane Praza 		} else switch (scf_error()) {
3387*1f6eb021SLiane Praza 		/* prop doesn't exist we take the default value */
3388*1f6eb021SLiane Praza 		case SCF_ERROR_NOT_FOUND:
3389*1f6eb021SLiane Praza 			*out = SCF_TMPL_VISIBILITY_READWRITE;
3390*1f6eb021SLiane Praza 			return (0);
3391*1f6eb021SLiane Praza 
3392*1f6eb021SLiane Praza 		case SCF_ERROR_CONSTRAINT_VIOLATED:
3393*1f6eb021SLiane Praza 		case SCF_ERROR_TYPE_MISMATCH:
3394*1f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
3395*1f6eb021SLiane Praza 			return (-1);
3396*1f6eb021SLiane Praza 
3397*1f6eb021SLiane Praza 		case SCF_ERROR_INVALID_ARGUMENT:
3398*1f6eb021SLiane Praza 		case SCF_ERROR_NOT_SET:
3399*1f6eb021SLiane Praza 		default:
3400*1f6eb021SLiane Praza 			assert(0);
3401*1f6eb021SLiane Praza 			abort();
3402*1f6eb021SLiane Praza 		}
3403*1f6eb021SLiane Praza 	} else if (strcmp(visibility, SCF_TM_VISIBILITY_READWRITE) == 0) {
3404*1f6eb021SLiane Praza 		*out = SCF_TMPL_VISIBILITY_READWRITE;
3405*1f6eb021SLiane Praza 	} else if (strcmp(visibility, SCF_TM_VISIBILITY_HIDDEN) == 0) {
3406*1f6eb021SLiane Praza 		*out = SCF_TMPL_VISIBILITY_HIDDEN;
3407*1f6eb021SLiane Praza 	} else if (strcmp(visibility, SCF_TM_VISIBILITY_READONLY) == 0) {
3408*1f6eb021SLiane Praza 		*out = SCF_TMPL_VISIBILITY_READONLY;
3409*1f6eb021SLiane Praza 	} else {
3410*1f6eb021SLiane Praza 		free(visibility);
3411*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
3412*1f6eb021SLiane Praza 		return (-1);
3413*1f6eb021SLiane Praza 	}
3414*1f6eb021SLiane Praza 
3415*1f6eb021SLiane Praza 	free(visibility);
3416*1f6eb021SLiane Praza 	return (0);
3417*1f6eb021SLiane Praza }
3418*1f6eb021SLiane Praza 
3419*1f6eb021SLiane Praza /*
3420*1f6eb021SLiane Praza  * Return an allocated string containing the value that must be freed
3421*1f6eb021SLiane Praza  * with free().
3422*1f6eb021SLiane Praza  *
3423*1f6eb021SLiane Praza  * On error set scf_error() _NO_MEMORY, or _NOT_SET (val has not been set
3424*1f6eb021SLiane Praza  * to a value).
3425*1f6eb021SLiane Praza  */
3426*1f6eb021SLiane Praza static char *
3427*1f6eb021SLiane Praza _scf_value_get_as_string(scf_value_t *val)
3428*1f6eb021SLiane Praza {
3429*1f6eb021SLiane Praza 	ssize_t sz = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH) + 1;
3430*1f6eb021SLiane Praza 	char *buf = malloc(sz);
3431*1f6eb021SLiane Praza 
3432*1f6eb021SLiane Praza 	if (buf == NULL) {
3433*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
3434*1f6eb021SLiane Praza 	} else if (scf_value_get_as_string(val, buf, sz) == -1) {
3435*1f6eb021SLiane Praza 		free(buf);
3436*1f6eb021SLiane Praza 		buf = NULL;
3437*1f6eb021SLiane Praza 	}
3438*1f6eb021SLiane Praza 
3439*1f6eb021SLiane Praza 	return (buf);
3440*1f6eb021SLiane Praza }
3441*1f6eb021SLiane Praza 
3442*1f6eb021SLiane Praza /*
3443*1f6eb021SLiane Praza  * Returns -1 on failure, sets scf_error() to:
3444*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
3445*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
3446*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
3447*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
3448*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
3449*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
3450*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
3451*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
3452*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
3453*1f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
3454*1f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
3455*1f6eb021SLiane Praza  */
3456*1f6eb021SLiane Praza int
3457*1f6eb021SLiane Praza scf_tmpl_prop_cardinality(const scf_prop_tmpl_t *t, uint64_t *min,
3458*1f6eb021SLiane Praza     uint64_t *max)
3459*1f6eb021SLiane Praza {
3460*1f6eb021SLiane Praza 	scf_value_t *val_min = NULL;
3461*1f6eb021SLiane Praza 	scf_value_t *val_max = NULL;
3462*1f6eb021SLiane Praza 	int ret = 0;
3463*1f6eb021SLiane Praza 
3464*1f6eb021SLiane Praza 	if (_read_single_value_from_pg(t->prt_pg,
3465*1f6eb021SLiane Praza 	    SCF_PROPERTY_TM_CARDINALITY_MIN, &val_min) == 0) {
3466*1f6eb021SLiane Praza 		if (scf_value_get_count(val_min, min) < 0)
3467*1f6eb021SLiane Praza 			goto error;
3468*1f6eb021SLiane Praza 	} else {
3469*1f6eb021SLiane Praza 		if (scf_error() == SCF_ERROR_NOT_FOUND)
3470*1f6eb021SLiane Praza 			*min = 0;
3471*1f6eb021SLiane Praza 		else
3472*1f6eb021SLiane Praza 			goto error;
3473*1f6eb021SLiane Praza 	}
3474*1f6eb021SLiane Praza 
3475*1f6eb021SLiane Praza 	if (_read_single_value_from_pg(t->prt_pg,
3476*1f6eb021SLiane Praza 	    SCF_PROPERTY_TM_CARDINALITY_MAX, &val_max) == 0) {
3477*1f6eb021SLiane Praza 		if (scf_value_get_count(val_max, max) < 0)
3478*1f6eb021SLiane Praza 			goto error;
3479*1f6eb021SLiane Praza 	} else {
3480*1f6eb021SLiane Praza 		if (scf_error() == SCF_ERROR_NOT_FOUND)
3481*1f6eb021SLiane Praza 			*max = UINT64_MAX;
3482*1f6eb021SLiane Praza 		else
3483*1f6eb021SLiane Praza 			goto error;
3484*1f6eb021SLiane Praza 	}
3485*1f6eb021SLiane Praza 	goto cleanup;
3486*1f6eb021SLiane Praza 
3487*1f6eb021SLiane Praza error:
3488*1f6eb021SLiane Praza 	if (ismember(scf_error(), errors_server)) {
3489*1f6eb021SLiane Praza 		ret = -1;
3490*1f6eb021SLiane Praza 	} else switch (scf_error()) {
3491*1f6eb021SLiane Praza 	case SCF_ERROR_TYPE_MISMATCH:
3492*1f6eb021SLiane Praza 	case SCF_ERROR_CONSTRAINT_VIOLATED:
3493*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
3494*1f6eb021SLiane Praza 		/*FALLTHROUGH*/
3495*1f6eb021SLiane Praza 
3496*1f6eb021SLiane Praza 	case SCF_ERROR_NOT_FOUND:
3497*1f6eb021SLiane Praza 	case SCF_ERROR_TEMPLATE_INVALID:
3498*1f6eb021SLiane Praza 		ret = -1;
3499*1f6eb021SLiane Praza 		break;
3500*1f6eb021SLiane Praza 
3501*1f6eb021SLiane Praza 	case SCF_ERROR_NOT_SET:
3502*1f6eb021SLiane Praza 	case SCF_ERROR_INVALID_ARGUMENT:
3503*1f6eb021SLiane Praza 	default:
3504*1f6eb021SLiane Praza 		assert(0);
3505*1f6eb021SLiane Praza 		abort();
3506*1f6eb021SLiane Praza 	}
3507*1f6eb021SLiane Praza 
3508*1f6eb021SLiane Praza cleanup:
3509*1f6eb021SLiane Praza 	scf_value_destroy(val_min);
3510*1f6eb021SLiane Praza 	scf_value_destroy(val_max);
3511*1f6eb021SLiane Praza 
3512*1f6eb021SLiane Praza 	return (ret);
3513*1f6eb021SLiane Praza }
3514*1f6eb021SLiane Praza 
3515*1f6eb021SLiane Praza /*
3516*1f6eb021SLiane Praza  * Returns -1 on failure.  Sets scf_error():
3517*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
3518*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
3519*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
3520*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
3521*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
3522*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
3523*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
3524*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
3525*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
3526*1f6eb021SLiane Praza  *     Property doesn't exist or exists and has no value.
3527*1f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
3528*1f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
3529*1f6eb021SLiane Praza  */
3530*1f6eb021SLiane Praza int
3531*1f6eb021SLiane Praza scf_tmpl_prop_internal_seps(const scf_prop_tmpl_t *t, scf_values_t *vals)
3532*1f6eb021SLiane Praza {
3533*1f6eb021SLiane Praza 	if (_read_astrings_values(t->prt_pg,
3534*1f6eb021SLiane Praza 	    SCF_PROPERTY_INTERNAL_SEPARATORS, vals) == NULL) {
3535*1f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
3536*1f6eb021SLiane Praza 			return (-1);
3537*1f6eb021SLiane Praza 		} else switch (scf_error()) {
3538*1f6eb021SLiane Praza 		case SCF_ERROR_CONSTRAINT_VIOLATED:
3539*1f6eb021SLiane Praza 		case SCF_ERROR_TYPE_MISMATCH:
3540*1f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
3541*1f6eb021SLiane Praza 			/*FALLTHROUGH*/
3542*1f6eb021SLiane Praza 
3543*1f6eb021SLiane Praza 		case SCF_ERROR_NOT_FOUND:
3544*1f6eb021SLiane Praza 			return (-1);
3545*1f6eb021SLiane Praza 
3546*1f6eb021SLiane Praza 		case SCF_ERROR_INVALID_ARGUMENT:
3547*1f6eb021SLiane Praza 		case SCF_ERROR_NOT_SET:
3548*1f6eb021SLiane Praza 		default:
3549*1f6eb021SLiane Praza 			assert(0);
3550*1f6eb021SLiane Praza 			abort();
3551*1f6eb021SLiane Praza 		}
3552*1f6eb021SLiane Praza 	} else if (vals->value_count == 0) {
3553*1f6eb021SLiane Praza 		/* property has no value */
3554*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NOT_FOUND);
3555*1f6eb021SLiane Praza 		scf_values_destroy(vals);
3556*1f6eb021SLiane Praza 		return (-1);
3557*1f6eb021SLiane Praza 	}
3558*1f6eb021SLiane Praza 
3559*1f6eb021SLiane Praza 	return (0);
3560*1f6eb021SLiane Praza }
3561*1f6eb021SLiane Praza 
3562*1f6eb021SLiane Praza /*
3563*1f6eb021SLiane Praza  * Returns -1 on failure.  Sets scf_error():
3564*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
3565*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
3566*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
3567*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
3568*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
3569*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
3570*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
3571*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
3572*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
3573*1f6eb021SLiane Praza  *     Property doesn't exist or exists and has no value.
3574*1f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
3575*1f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
3576*1f6eb021SLiane Praza  */
3577*1f6eb021SLiane Praza int
3578*1f6eb021SLiane Praza scf_tmpl_value_name_constraints(const scf_prop_tmpl_t *t,
3579*1f6eb021SLiane Praza     scf_values_t *vals)
3580*1f6eb021SLiane Praza {
3581*1f6eb021SLiane Praza 	char **ret;
3582*1f6eb021SLiane Praza 
3583*1f6eb021SLiane Praza 	ret = _read_astrings_values(t->prt_pg,
3584*1f6eb021SLiane Praza 	    SCF_PROPERTY_TM_CONSTRAINT_NAME, vals);
3585*1f6eb021SLiane Praza 
3586*1f6eb021SLiane Praza 	if (ret == NULL) {
3587*1f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
3588*1f6eb021SLiane Praza 			return (-1);
3589*1f6eb021SLiane Praza 		} else switch (scf_error()) {
3590*1f6eb021SLiane Praza 		case SCF_ERROR_CONSTRAINT_VIOLATED:
3591*1f6eb021SLiane Praza 		case SCF_ERROR_TYPE_MISMATCH:
3592*1f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
3593*1f6eb021SLiane Praza 			/*FALLTHROUGH*/
3594*1f6eb021SLiane Praza 
3595*1f6eb021SLiane Praza 		case SCF_ERROR_NOT_FOUND:
3596*1f6eb021SLiane Praza 			return (-1);
3597*1f6eb021SLiane Praza 
3598*1f6eb021SLiane Praza 		case SCF_ERROR_INVALID_ARGUMENT:
3599*1f6eb021SLiane Praza 		case SCF_ERROR_NOT_SET:
3600*1f6eb021SLiane Praza 		default:
3601*1f6eb021SLiane Praza 			assert(0);
3602*1f6eb021SLiane Praza 			abort();
3603*1f6eb021SLiane Praza 		}
3604*1f6eb021SLiane Praza 	} else if (vals->value_count == 0) {
3605*1f6eb021SLiane Praza 		/* property has no value */
3606*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NOT_FOUND);
3607*1f6eb021SLiane Praza 		scf_values_destroy(vals);
3608*1f6eb021SLiane Praza 		return (-1);
3609*1f6eb021SLiane Praza 	}
3610*1f6eb021SLiane Praza 
3611*1f6eb021SLiane Praza 	return (0);
3612*1f6eb021SLiane Praza }
3613*1f6eb021SLiane Praza 
3614*1f6eb021SLiane Praza /*
3615*1f6eb021SLiane Praza  * Returns NULL on failure.  Sets scf_error():
3616*1f6eb021SLiane Praza  * Caller is responsible for freeing returned pointer after use.
3617*1f6eb021SLiane Praza  *   SCF_ERROR_CONSTRAINT_VIOLATED
3618*1f6eb021SLiane Praza  *    More tokens than the array size supplied.
3619*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
3620*1f6eb021SLiane Praza  */
3621*1f6eb021SLiane Praza static void *
3622*1f6eb021SLiane Praza _separate_by_separator(char *string, const char *sep, char **array, int size)
3623*1f6eb021SLiane Praza {
3624*1f6eb021SLiane Praza 	char *str, *token;
3625*1f6eb021SLiane Praza 	char *lasts;
3626*1f6eb021SLiane Praza 	int n = 0;
3627*1f6eb021SLiane Praza 
3628*1f6eb021SLiane Praza 	assert(array != NULL);
3629*1f6eb021SLiane Praza 	assert(string != NULL);
3630*1f6eb021SLiane Praza 	assert(sep != NULL);
3631*1f6eb021SLiane Praza 	assert(size > 0);
3632*1f6eb021SLiane Praza 
3633*1f6eb021SLiane Praza 	str = strdup(string);
3634*1f6eb021SLiane Praza 	if (str == NULL) {
3635*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
3636*1f6eb021SLiane Praza 		return (NULL);
3637*1f6eb021SLiane Praza 	}
3638*1f6eb021SLiane Praza 
3639*1f6eb021SLiane Praza 	if ((array[n] = strtok_r(str, sep, &lasts)) == NULL) {
3640*1f6eb021SLiane Praza 		assert(0);
3641*1f6eb021SLiane Praza 		abort();
3642*1f6eb021SLiane Praza 	}
3643*1f6eb021SLiane Praza 
3644*1f6eb021SLiane Praza 	n++;
3645*1f6eb021SLiane Praza 	while ((token = strtok_r(NULL, sep, &lasts)) != NULL) {
3646*1f6eb021SLiane Praza 		if (n >= size) {
3647*1f6eb021SLiane Praza 			goto error;
3648*1f6eb021SLiane Praza 		}
3649*1f6eb021SLiane Praza 		array[n] = token;
3650*1f6eb021SLiane Praza 		n++;
3651*1f6eb021SLiane Praza 	}
3652*1f6eb021SLiane Praza 	if (n < size) {
3653*1f6eb021SLiane Praza 		goto error;
3654*1f6eb021SLiane Praza 	}
3655*1f6eb021SLiane Praza 
3656*1f6eb021SLiane Praza 	return (str);
3657*1f6eb021SLiane Praza error:
3658*1f6eb021SLiane Praza 	free(str);
3659*1f6eb021SLiane Praza 	(void) scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED);
3660*1f6eb021SLiane Praza 	return (NULL);
3661*1f6eb021SLiane Praza }
3662*1f6eb021SLiane Praza 
3663*1f6eb021SLiane Praza /*
3664*1f6eb021SLiane Praza  * check if name is among values of CHOICES_INCLUDE_VALUES
3665*1f6eb021SLiane Praza  * return 0 if name is present, 1 name is not present, -1 on failure
3666*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
3667*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
3668*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
3669*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
3670*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
3671*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
3672*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
3673*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
3674*1f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
3675*1f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
3676*1f6eb021SLiane Praza  */
3677*1f6eb021SLiane Praza static int
3678*1f6eb021SLiane Praza _check_choices_include_values(scf_propertygroup_t *pg, const char *name)
3679*1f6eb021SLiane Praza {
3680*1f6eb021SLiane Praza 	int n = 0, r = 1;
3681*1f6eb021SLiane Praza 	char **ret;
3682*1f6eb021SLiane Praza 	scf_values_t vals;
3683*1f6eb021SLiane Praza 
3684*1f6eb021SLiane Praza 	if ((ret = _read_astrings_values(pg,
3685*1f6eb021SLiane Praza 	    SCF_PROPERTY_TM_CHOICES_INCLUDE_VALUES, &vals)) == NULL) {
3686*1f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
3687*1f6eb021SLiane Praza 			return (-1);
3688*1f6eb021SLiane Praza 		} else switch (scf_error()) {
3689*1f6eb021SLiane Praza 		case SCF_ERROR_NOT_FOUND:
3690*1f6eb021SLiane Praza 			return (1);
3691*1f6eb021SLiane Praza 
3692*1f6eb021SLiane Praza 		case SCF_ERROR_TYPE_MISMATCH:
3693*1f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
3694*1f6eb021SLiane Praza 			return (-1);
3695*1f6eb021SLiane Praza 
3696*1f6eb021SLiane Praza 		case SCF_ERROR_INVALID_ARGUMENT:
3697*1f6eb021SLiane Praza 		case SCF_ERROR_NOT_SET:
3698*1f6eb021SLiane Praza 		default:
3699*1f6eb021SLiane Praza 			assert(0);
3700*1f6eb021SLiane Praza 			abort();
3701*1f6eb021SLiane Praza 		}
3702*1f6eb021SLiane Praza 	}
3703*1f6eb021SLiane Praza 
3704*1f6eb021SLiane Praza 	for (n = 0; n < vals.value_count; ++n) {
3705*1f6eb021SLiane Praza 		if (strcmp(name, ret[n]) == 0) {
3706*1f6eb021SLiane Praza 			r = 0;
3707*1f6eb021SLiane Praza 			break;
3708*1f6eb021SLiane Praza 		}
3709*1f6eb021SLiane Praza 	}
3710*1f6eb021SLiane Praza 	scf_values_destroy(&vals);
3711*1f6eb021SLiane Praza 	return (r);
3712*1f6eb021SLiane Praza }
3713*1f6eb021SLiane Praza 
3714*1f6eb021SLiane Praza void
3715*1f6eb021SLiane Praza scf_count_ranges_destroy(scf_count_ranges_t *ranges)
3716*1f6eb021SLiane Praza {
3717*1f6eb021SLiane Praza 	if (ranges == NULL)
3718*1f6eb021SLiane Praza 		return;
3719*1f6eb021SLiane Praza 
3720*1f6eb021SLiane Praza 	ranges->scr_num_ranges = 0;
3721*1f6eb021SLiane Praza 	free(ranges->scr_min);
3722*1f6eb021SLiane Praza 	free(ranges->scr_max);
3723*1f6eb021SLiane Praza 	ranges->scr_min = NULL;
3724*1f6eb021SLiane Praza 	ranges->scr_max = NULL;
3725*1f6eb021SLiane Praza }
3726*1f6eb021SLiane Praza 
3727*1f6eb021SLiane Praza void
3728*1f6eb021SLiane Praza scf_int_ranges_destroy(scf_int_ranges_t *ranges)
3729*1f6eb021SLiane Praza {
3730*1f6eb021SLiane Praza 	if (ranges == NULL)
3731*1f6eb021SLiane Praza 		return;
3732*1f6eb021SLiane Praza 
3733*1f6eb021SLiane Praza 	ranges->sir_num_ranges = 0;
3734*1f6eb021SLiane Praza 	free(ranges->sir_min);
3735*1f6eb021SLiane Praza 	free(ranges->sir_max);
3736*1f6eb021SLiane Praza 	ranges->sir_min = NULL;
3737*1f6eb021SLiane Praza 	ranges->sir_max = NULL;
3738*1f6eb021SLiane Praza }
3739*1f6eb021SLiane Praza 
3740*1f6eb021SLiane Praza /*
3741*1f6eb021SLiane Praza  * Returns -1 on failure.  Sets scf_error():
3742*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
3743*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
3744*1f6eb021SLiane Praza  *   SCF_ERROR_CONSTRAINT_VIOLATED
3745*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
3746*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
3747*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
3748*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
3749*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
3750*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
3751*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
3752*1f6eb021SLiane Praza  *     Property doesn't exist or exists and has no value.
3753*1f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
3754*1f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
3755*1f6eb021SLiane Praza  */
3756*1f6eb021SLiane Praza static int
3757*1f6eb021SLiane Praza _scf_tmpl_get_count_ranges(const scf_prop_tmpl_t *t, const char *prop,
3758*1f6eb021SLiane Praza     scf_count_ranges_t *ranges)
3759*1f6eb021SLiane Praza {
3760*1f6eb021SLiane Praza 	scf_values_t vals;
3761*1f6eb021SLiane Praza 	int i = 0;
3762*1f6eb021SLiane Praza 	char **ret;
3763*1f6eb021SLiane Praza 	char *one_range[2];
3764*1f6eb021SLiane Praza 	char *endptr;
3765*1f6eb021SLiane Praza 	char *str = NULL;
3766*1f6eb021SLiane Praza 	uint64_t *min = NULL;
3767*1f6eb021SLiane Praza 	uint64_t *max = NULL;
3768*1f6eb021SLiane Praza 
3769*1f6eb021SLiane Praza 	assert(ranges != NULL);
3770*1f6eb021SLiane Praza 	if ((ret = _read_astrings_values(t->prt_pg, prop, &vals)) == NULL)
3771*1f6eb021SLiane Praza 		goto error;
3772*1f6eb021SLiane Praza 	if (vals.value_count == 0) {
3773*1f6eb021SLiane Praza 		/* range values are empty */
3774*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NOT_FOUND);
3775*1f6eb021SLiane Praza 		goto cleanup;
3776*1f6eb021SLiane Praza 	}
3777*1f6eb021SLiane Praza 
3778*1f6eb021SLiane Praza 	min = malloc(vals.value_count * sizeof (uint64_t));
3779*1f6eb021SLiane Praza 	max = malloc(vals.value_count * sizeof (uint64_t));
3780*1f6eb021SLiane Praza 	if (min == NULL || max == NULL) {
3781*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
3782*1f6eb021SLiane Praza 		goto cleanup;
3783*1f6eb021SLiane Praza 	}
3784*1f6eb021SLiane Praza 	for (i = 0; i < vals.value_count; ++i) {
3785*1f6eb021SLiane Praza 		/* min and max should be separated by a "," */
3786*1f6eb021SLiane Praza 		if ((str = _separate_by_separator(ret[i], ",", one_range,
3787*1f6eb021SLiane Praza 		    2)) == NULL)
3788*1f6eb021SLiane Praza 			goto cleanup;
3789*1f6eb021SLiane Praza 		errno = 0;
3790*1f6eb021SLiane Praza 		min[i] = strtoull(one_range[0], &endptr, 10);
3791*1f6eb021SLiane Praza 		if (errno != 0 || endptr == one_range[0] || *endptr) {
3792*1f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED);
3793*1f6eb021SLiane Praza 			goto cleanup;
3794*1f6eb021SLiane Praza 		}
3795*1f6eb021SLiane Praza 		errno = 0;
3796*1f6eb021SLiane Praza 		max[i] = strtoull(one_range[1], &endptr, 10);
3797*1f6eb021SLiane Praza 		if (errno != 0 || endptr == one_range[1] || *endptr) {
3798*1f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED);
3799*1f6eb021SLiane Praza 			goto cleanup;
3800*1f6eb021SLiane Praza 		}
3801*1f6eb021SLiane Praza 		if (min[i] > max[i]) {
3802*1f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED);
3803*1f6eb021SLiane Praza 			goto cleanup;
3804*1f6eb021SLiane Praza 		}
3805*1f6eb021SLiane Praza 		free(str);
3806*1f6eb021SLiane Praza 		str = NULL;
3807*1f6eb021SLiane Praza 	}
3808*1f6eb021SLiane Praza 	ranges->scr_num_ranges = vals.value_count;
3809*1f6eb021SLiane Praza 	ranges->scr_min = min;
3810*1f6eb021SLiane Praza 	ranges->scr_max = max;
3811*1f6eb021SLiane Praza 	scf_values_destroy(&vals);
3812*1f6eb021SLiane Praza 	return (0);
3813*1f6eb021SLiane Praza cleanup:
3814*1f6eb021SLiane Praza 	free(str);
3815*1f6eb021SLiane Praza 	free(min);
3816*1f6eb021SLiane Praza 	free(max);
3817*1f6eb021SLiane Praza 	scf_values_destroy(&vals);
3818*1f6eb021SLiane Praza error:
3819*1f6eb021SLiane Praza 	if (ismember(scf_error(), errors_server)) {
3820*1f6eb021SLiane Praza 		return (-1);
3821*1f6eb021SLiane Praza 	} else switch (scf_error()) {
3822*1f6eb021SLiane Praza 	case SCF_ERROR_TYPE_MISMATCH:
3823*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
3824*1f6eb021SLiane Praza 		/*FALLTHROUGH*/
3825*1f6eb021SLiane Praza 
3826*1f6eb021SLiane Praza 	case SCF_ERROR_CONSTRAINT_VIOLATED:
3827*1f6eb021SLiane Praza 	case SCF_ERROR_NOT_FOUND:
3828*1f6eb021SLiane Praza 		return (-1);
3829*1f6eb021SLiane Praza 
3830*1f6eb021SLiane Praza 	case SCF_ERROR_INVALID_ARGUMENT:
3831*1f6eb021SLiane Praza 	case SCF_ERROR_NOT_SET:
3832*1f6eb021SLiane Praza 	default:
3833*1f6eb021SLiane Praza 		assert(0);
3834*1f6eb021SLiane Praza 		abort();
3835*1f6eb021SLiane Praza 	}
3836*1f6eb021SLiane Praza 	/*NOTREACHED*/
3837*1f6eb021SLiane Praza }
3838*1f6eb021SLiane Praza 
3839*1f6eb021SLiane Praza /*
3840*1f6eb021SLiane Praza  * Returns -1 on failure.  Sets scf_error():
3841*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
3842*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
3843*1f6eb021SLiane Praza  *   SCF_ERROR_CONSTRAINT_VIOLATED
3844*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
3845*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
3846*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
3847*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
3848*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
3849*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
3850*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
3851*1f6eb021SLiane Praza  *     Property doesn't exist or exists and has no value.
3852*1f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
3853*1f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
3854*1f6eb021SLiane Praza  */
3855*1f6eb021SLiane Praza static int
3856*1f6eb021SLiane Praza _scf_tmpl_get_int_ranges(const scf_prop_tmpl_t *t, const char *prop,
3857*1f6eb021SLiane Praza     scf_int_ranges_t *ranges)
3858*1f6eb021SLiane Praza {
3859*1f6eb021SLiane Praza 	scf_values_t vals;
3860*1f6eb021SLiane Praza 	int n = 0;
3861*1f6eb021SLiane Praza 	char **ret;
3862*1f6eb021SLiane Praza 	char *one_range[2];
3863*1f6eb021SLiane Praza 	char *endptr;
3864*1f6eb021SLiane Praza 	char *str = NULL;
3865*1f6eb021SLiane Praza 	int64_t *min = NULL;
3866*1f6eb021SLiane Praza 	int64_t *max = NULL;
3867*1f6eb021SLiane Praza 
3868*1f6eb021SLiane Praza 	assert(ranges != NULL);
3869*1f6eb021SLiane Praza 	if ((ret = _read_astrings_values(t->prt_pg, prop, &vals)) == NULL)
3870*1f6eb021SLiane Praza 		goto error;
3871*1f6eb021SLiane Praza 	if (vals.value_count == 0) {
3872*1f6eb021SLiane Praza 		/* range values are empty */
3873*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NOT_FOUND);
3874*1f6eb021SLiane Praza 		goto cleanup;
3875*1f6eb021SLiane Praza 	}
3876*1f6eb021SLiane Praza 
3877*1f6eb021SLiane Praza 	min = malloc(vals.value_count * sizeof (int64_t));
3878*1f6eb021SLiane Praza 	max = malloc(vals.value_count * sizeof (int64_t));
3879*1f6eb021SLiane Praza 	if (min == NULL || max == NULL) {
3880*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
3881*1f6eb021SLiane Praza 		goto cleanup;
3882*1f6eb021SLiane Praza 	}
3883*1f6eb021SLiane Praza 	while (n < vals.value_count) {
3884*1f6eb021SLiane Praza 		/* min and max should be separated by a "," */
3885*1f6eb021SLiane Praza 		if ((str = _separate_by_separator(ret[n], ",", one_range, 2))
3886*1f6eb021SLiane Praza 		    == NULL)
3887*1f6eb021SLiane Praza 			goto cleanup;
3888*1f6eb021SLiane Praza 		errno = 0;
3889*1f6eb021SLiane Praza 		min[n] = strtoll(one_range[0], &endptr, 10);
3890*1f6eb021SLiane Praza 		if (errno != 0 || endptr == one_range[0] || *endptr) {
3891*1f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED);
3892*1f6eb021SLiane Praza 			goto cleanup;
3893*1f6eb021SLiane Praza 		}
3894*1f6eb021SLiane Praza 		errno = 0;
3895*1f6eb021SLiane Praza 		max[n] = strtoll(one_range[1], &endptr, 10);
3896*1f6eb021SLiane Praza 		if (errno != 0 || endptr == one_range[1] || *endptr) {
3897*1f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED);
3898*1f6eb021SLiane Praza 			goto cleanup;
3899*1f6eb021SLiane Praza 		}
3900*1f6eb021SLiane Praza 		if (min[n] > max[n]) {
3901*1f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
3902*1f6eb021SLiane Praza 			goto cleanup;
3903*1f6eb021SLiane Praza 		}
3904*1f6eb021SLiane Praza 		++n;
3905*1f6eb021SLiane Praza 		free(str);
3906*1f6eb021SLiane Praza 		str = NULL;
3907*1f6eb021SLiane Praza 	}
3908*1f6eb021SLiane Praza 	ranges->sir_num_ranges = vals.value_count;
3909*1f6eb021SLiane Praza 	ranges->sir_min = min;
3910*1f6eb021SLiane Praza 	ranges->sir_max = max;
3911*1f6eb021SLiane Praza 	scf_values_destroy(&vals);
3912*1f6eb021SLiane Praza 	return (0);
3913*1f6eb021SLiane Praza cleanup:
3914*1f6eb021SLiane Praza 	free(str);
3915*1f6eb021SLiane Praza 	free(min);
3916*1f6eb021SLiane Praza 	free(max);
3917*1f6eb021SLiane Praza 	scf_values_destroy(&vals);
3918*1f6eb021SLiane Praza error:
3919*1f6eb021SLiane Praza 	if (ismember(scf_error(), errors_server)) {
3920*1f6eb021SLiane Praza 		return (-1);
3921*1f6eb021SLiane Praza 	} else switch (scf_error()) {
3922*1f6eb021SLiane Praza 	case SCF_ERROR_TYPE_MISMATCH:
3923*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
3924*1f6eb021SLiane Praza 		/*FALLTHROUGH*/
3925*1f6eb021SLiane Praza 
3926*1f6eb021SLiane Praza 	case SCF_ERROR_CONSTRAINT_VIOLATED:
3927*1f6eb021SLiane Praza 	case SCF_ERROR_NOT_FOUND:
3928*1f6eb021SLiane Praza 	case SCF_ERROR_TEMPLATE_INVALID:
3929*1f6eb021SLiane Praza 		return (-1);
3930*1f6eb021SLiane Praza 
3931*1f6eb021SLiane Praza 	case SCF_ERROR_INVALID_ARGUMENT:
3932*1f6eb021SLiane Praza 	case SCF_ERROR_NOT_SET:
3933*1f6eb021SLiane Praza 	default:
3934*1f6eb021SLiane Praza 		assert(0);
3935*1f6eb021SLiane Praza 		abort();
3936*1f6eb021SLiane Praza 	}
3937*1f6eb021SLiane Praza 	/*NOTREACHED*/
3938*1f6eb021SLiane Praza }
3939*1f6eb021SLiane Praza 
3940*1f6eb021SLiane Praza /*
3941*1f6eb021SLiane Praza  * Returns -1 on failure.  Sets scf_error():
3942*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
3943*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
3944*1f6eb021SLiane Praza  *   SCF_ERROR_CONSTRAINT_VIOLATED
3945*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
3946*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
3947*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
3948*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
3949*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
3950*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
3951*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
3952*1f6eb021SLiane Praza  *     Property doesn't exist or exists and has no value.
3953*1f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
3954*1f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
3955*1f6eb021SLiane Praza  */
3956*1f6eb021SLiane Praza int
3957*1f6eb021SLiane Praza scf_tmpl_value_count_range_constraints(const scf_prop_tmpl_t *t,
3958*1f6eb021SLiane Praza     scf_count_ranges_t *ranges)
3959*1f6eb021SLiane Praza {
3960*1f6eb021SLiane Praza 	return (_scf_tmpl_get_count_ranges(t, SCF_PROPERTY_TM_CONSTRAINT_RANGE,
3961*1f6eb021SLiane Praza 	    ranges));
3962*1f6eb021SLiane Praza }
3963*1f6eb021SLiane Praza 
3964*1f6eb021SLiane Praza int
3965*1f6eb021SLiane Praza scf_tmpl_value_int_range_constraints(const scf_prop_tmpl_t *t,
3966*1f6eb021SLiane Praza     scf_int_ranges_t *ranges)
3967*1f6eb021SLiane Praza {
3968*1f6eb021SLiane Praza 	return (_scf_tmpl_get_int_ranges(t, SCF_PROPERTY_TM_CONSTRAINT_RANGE,
3969*1f6eb021SLiane Praza 	    ranges));
3970*1f6eb021SLiane Praza }
3971*1f6eb021SLiane Praza 
3972*1f6eb021SLiane Praza int
3973*1f6eb021SLiane Praza scf_tmpl_value_count_range_choices(const scf_prop_tmpl_t *t,
3974*1f6eb021SLiane Praza     scf_count_ranges_t *ranges)
3975*1f6eb021SLiane Praza {
3976*1f6eb021SLiane Praza 	return (_scf_tmpl_get_count_ranges(t, SCF_PROPERTY_TM_CHOICES_RANGE,
3977*1f6eb021SLiane Praza 	    ranges));
3978*1f6eb021SLiane Praza }
3979*1f6eb021SLiane Praza 
3980*1f6eb021SLiane Praza int
3981*1f6eb021SLiane Praza scf_tmpl_value_int_range_choices(const scf_prop_tmpl_t *t,
3982*1f6eb021SLiane Praza     scf_int_ranges_t *ranges)
3983*1f6eb021SLiane Praza {
3984*1f6eb021SLiane Praza 	return (_scf_tmpl_get_int_ranges(t, SCF_PROPERTY_TM_CHOICES_RANGE,
3985*1f6eb021SLiane Praza 	    ranges));
3986*1f6eb021SLiane Praza }
3987*1f6eb021SLiane Praza 
3988*1f6eb021SLiane Praza /*
3989*1f6eb021SLiane Praza  * Returns -1 on failure.  Sets scf_error():
3990*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
3991*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
3992*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
3993*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
3994*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
3995*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
3996*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
3997*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
3998*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
3999*1f6eb021SLiane Praza  *     Property doesn't exist or exists and has no value.
4000*1f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
4001*1f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
4002*1f6eb021SLiane Praza  */
4003*1f6eb021SLiane Praza int
4004*1f6eb021SLiane Praza scf_tmpl_value_name_choices(const scf_prop_tmpl_t *t, scf_values_t *vals)
4005*1f6eb021SLiane Praza {
4006*1f6eb021SLiane Praza 	int c_flag = 0; /* have not read any value yet */
4007*1f6eb021SLiane Praza 	int r;
4008*1f6eb021SLiane Praza 	char **ret;
4009*1f6eb021SLiane Praza 
4010*1f6eb021SLiane Praza 	/* First, look for explicitly declared choices. */
4011*1f6eb021SLiane Praza 	if ((ret = _read_astrings_values(t->prt_pg,
4012*1f6eb021SLiane Praza 	    SCF_PROPERTY_TM_CHOICES_NAME, vals)) != NULL) {
4013*1f6eb021SLiane Praza 		c_flag = 1;
4014*1f6eb021SLiane Praza 	} else if (scf_error() != SCF_ERROR_NOT_FOUND) {
4015*1f6eb021SLiane Praza 		goto error;
4016*1f6eb021SLiane Praza 	}
4017*1f6eb021SLiane Praza 
4018*1f6eb021SLiane Praza 	/* Next, check for choices included by 'values'. */
4019*1f6eb021SLiane Praza 	if ((r = _check_choices_include_values(t->prt_pg, "values")) == 0) {
4020*1f6eb021SLiane Praza 		/* read values_name */
4021*1f6eb021SLiane Praza 		if (c_flag == 1)
4022*1f6eb021SLiane Praza 			/* append values */
4023*1f6eb021SLiane Praza 			ret = _append_astrings_values(t->prt_pg,
4024*1f6eb021SLiane Praza 			    SCF_PROPERTY_TM_VALUES_NAME, vals);
4025*1f6eb021SLiane Praza 		else
4026*1f6eb021SLiane Praza 			/* read values */
4027*1f6eb021SLiane Praza 			ret = _read_astrings_values(t->prt_pg,
4028*1f6eb021SLiane Praza 			    SCF_PROPERTY_TM_VALUES_NAME, vals);
4029*1f6eb021SLiane Praza 		if (ret != NULL) {
4030*1f6eb021SLiane Praza 			c_flag = 1;
4031*1f6eb021SLiane Praza 		} else if (scf_error() != SCF_ERROR_NOT_FOUND) {
4032*1f6eb021SLiane Praza 			goto error;
4033*1f6eb021SLiane Praza 		}
4034*1f6eb021SLiane Praza 	} else if (r == -1) {
4035*1f6eb021SLiane Praza 		goto error;
4036*1f6eb021SLiane Praza 	}
4037*1f6eb021SLiane Praza 
4038*1f6eb021SLiane Praza 	/* Finally check for choices included by 'constraints'. */
4039*1f6eb021SLiane Praza 	if ((r = _check_choices_include_values(t->prt_pg, "constraints")) ==
4040*1f6eb021SLiane Praza 	    0) {
4041*1f6eb021SLiane Praza 		/* read constraint_name */
4042*1f6eb021SLiane Praza 		if (c_flag == 1)
4043*1f6eb021SLiane Praza 			/* append values */
4044*1f6eb021SLiane Praza 			ret = _append_astrings_values(t->prt_pg,
4045*1f6eb021SLiane Praza 			    SCF_PROPERTY_TM_CONSTRAINT_NAME, vals);
4046*1f6eb021SLiane Praza 		else
4047*1f6eb021SLiane Praza 			/* read values */
4048*1f6eb021SLiane Praza 			ret = _read_astrings_values(t->prt_pg,
4049*1f6eb021SLiane Praza 			    SCF_PROPERTY_TM_CONSTRAINT_NAME, vals);
4050*1f6eb021SLiane Praza 		if (ret != NULL) {
4051*1f6eb021SLiane Praza 			c_flag = 1;
4052*1f6eb021SLiane Praza 		} else if (scf_error() != SCF_ERROR_NOT_FOUND) {
4053*1f6eb021SLiane Praza 			goto error;
4054*1f6eb021SLiane Praza 		}
4055*1f6eb021SLiane Praza 	} else if (r == -1) {
4056*1f6eb021SLiane Praza 		goto error;
4057*1f6eb021SLiane Praza 	}
4058*1f6eb021SLiane Praza 
4059*1f6eb021SLiane Praza 	if (c_flag == 0 || vals->value_count == 0) {
4060*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NOT_FOUND);
4061*1f6eb021SLiane Praza 		return (-1);
4062*1f6eb021SLiane Praza 	}
4063*1f6eb021SLiane Praza 
4064*1f6eb021SLiane Praza 	return (0);
4065*1f6eb021SLiane Praza 
4066*1f6eb021SLiane Praza error:
4067*1f6eb021SLiane Praza 	if (ismember(scf_error(), errors_server)) {
4068*1f6eb021SLiane Praza 		return (-1);
4069*1f6eb021SLiane Praza 	} else switch (scf_error()) {
4070*1f6eb021SLiane Praza 	case SCF_ERROR_TYPE_MISMATCH:
4071*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
4072*1f6eb021SLiane Praza 		return (-1);
4073*1f6eb021SLiane Praza 
4074*1f6eb021SLiane Praza 	case SCF_ERROR_NOT_SET:
4075*1f6eb021SLiane Praza 	case SCF_ERROR_INVALID_ARGUMENT:
4076*1f6eb021SLiane Praza 	default:
4077*1f6eb021SLiane Praza 		assert(0);
4078*1f6eb021SLiane Praza 		abort();
4079*1f6eb021SLiane Praza 	}
4080*1f6eb021SLiane Praza 	/*NOTREACHED*/
4081*1f6eb021SLiane Praza }
4082*1f6eb021SLiane Praza 
4083*1f6eb021SLiane Praza void
4084*1f6eb021SLiane Praza scf_values_destroy(scf_values_t *vals)
4085*1f6eb021SLiane Praza {
4086*1f6eb021SLiane Praza 	int i;
4087*1f6eb021SLiane Praza 	char **items = NULL;
4088*1f6eb021SLiane Praza 	char **str = vals->values_as_strings;
4089*1f6eb021SLiane Praza 
4090*1f6eb021SLiane Praza 	if (vals == NULL)
4091*1f6eb021SLiane Praza 		return;
4092*1f6eb021SLiane Praza 
4093*1f6eb021SLiane Praza 	/* free values */
4094*1f6eb021SLiane Praza 	switch (vals->value_type) {
4095*1f6eb021SLiane Praza 	case SCF_TYPE_BOOLEAN:
4096*1f6eb021SLiane Praza 		free(vals->values.v_boolean);
4097*1f6eb021SLiane Praza 		break;
4098*1f6eb021SLiane Praza 	case SCF_TYPE_COUNT:
4099*1f6eb021SLiane Praza 		free(vals->values.v_count);
4100*1f6eb021SLiane Praza 		break;
4101*1f6eb021SLiane Praza 	case SCF_TYPE_INTEGER:
4102*1f6eb021SLiane Praza 		free(vals->values.v_integer);
4103*1f6eb021SLiane Praza 		break;
4104*1f6eb021SLiane Praza 	case SCF_TYPE_ASTRING:
4105*1f6eb021SLiane Praza 		items = vals->values.v_astring;
4106*1f6eb021SLiane Praza 		str = NULL;
4107*1f6eb021SLiane Praza 		break;
4108*1f6eb021SLiane Praza 	case SCF_TYPE_USTRING:
4109*1f6eb021SLiane Praza 		items = vals->values.v_ustring;
4110*1f6eb021SLiane Praza 		str = NULL;
4111*1f6eb021SLiane Praza 		break;
4112*1f6eb021SLiane Praza 	case SCF_TYPE_OPAQUE:
4113*1f6eb021SLiane Praza 		items = vals->values.v_opaque;
4114*1f6eb021SLiane Praza 		str = NULL;
4115*1f6eb021SLiane Praza 		break;
4116*1f6eb021SLiane Praza 	case SCF_TYPE_TIME:
4117*1f6eb021SLiane Praza 		free(vals->values.v_time);
4118*1f6eb021SLiane Praza 		break;
4119*1f6eb021SLiane Praza 	default:
4120*1f6eb021SLiane Praza 		assert(0);
4121*1f6eb021SLiane Praza 		abort();
4122*1f6eb021SLiane Praza 	}
4123*1f6eb021SLiane Praza 	for (i = 0; i < vals->value_count; ++i) {
4124*1f6eb021SLiane Praza 		if (items != NULL)
4125*1f6eb021SLiane Praza 			free(items[i]);
4126*1f6eb021SLiane Praza 		if (str != NULL)
4127*1f6eb021SLiane Praza 			free(str[i]);
4128*1f6eb021SLiane Praza 	}
4129*1f6eb021SLiane Praza 	vals->value_count = 0;
4130*1f6eb021SLiane Praza 	free(items);
4131*1f6eb021SLiane Praza 	free(str);
4132*1f6eb021SLiane Praza }
4133*1f6eb021SLiane Praza 
4134*1f6eb021SLiane Praza /*
4135*1f6eb021SLiane Praza  * char *_make_value_name()
4136*1f6eb021SLiane Praza  *
4137*1f6eb021SLiane Praza  * Construct the prefix for a value common name or value description property.
4138*1f6eb021SLiane Praza  * It takes the form:
4139*1f6eb021SLiane Praza  *   value_<BASE32 name>_<common_name|description>_
4140*1f6eb021SLiane Praza  * This is then combined with a localized suffix by the caller to look
4141*1f6eb021SLiane Praza  * up the property in the repository:
4142*1f6eb021SLiane Praza  *   value_<BASE32 name>_<common_name|description>_<lang>
4143*1f6eb021SLiane Praza  *
4144*1f6eb021SLiane Praza  * Returns NULL on failure.  Sets scf_error():
4145*1f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
4146*1f6eb021SLiane Praza  *     Name isn't short enough make a value name with.
4147*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
4148*1f6eb021SLiane Praza  */
4149*1f6eb021SLiane Praza static char *
4150*1f6eb021SLiane Praza _make_value_name(char *desc_name, const char *value)
4151*1f6eb021SLiane Praza {
4152*1f6eb021SLiane Praza 	char *name = NULL;
4153*1f6eb021SLiane Praza 	char *encoded = NULL;
4154*1f6eb021SLiane Praza 	ssize_t sz = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
4155*1f6eb021SLiane Praza 
4156*1f6eb021SLiane Praza 	name = malloc(sz);
4157*1f6eb021SLiane Praza 	encoded = malloc(sz);
4158*1f6eb021SLiane Praza 	if (name == NULL || encoded == NULL) {
4159*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
4160*1f6eb021SLiane Praza 		free(name);
4161*1f6eb021SLiane Praza 		free(encoded);
4162*1f6eb021SLiane Praza 		return (NULL);
4163*1f6eb021SLiane Praza 	}
4164*1f6eb021SLiane Praza 
4165*1f6eb021SLiane Praza 	if (scf_encode32(value, strlen(value), encoded, sz, NULL,
4166*1f6eb021SLiane Praza 	    SCF_ENCODE32_PAD) != 0) {
4167*1f6eb021SLiane Praza 		/* Shouldn't happen. */
4168*1f6eb021SLiane Praza 		assert(0);
4169*1f6eb021SLiane Praza 	}
4170*1f6eb021SLiane Praza 
4171*1f6eb021SLiane Praza 	(void) strlcpy(name, SCF_PROPERTY_TM_VALUE_PREFIX, sz);
4172*1f6eb021SLiane Praza 
4173*1f6eb021SLiane Praza 	if (strlcat(name, encoded, sz) >= sz) {
4174*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
4175*1f6eb021SLiane Praza 		free(name);
4176*1f6eb021SLiane Praza 		free(encoded);
4177*1f6eb021SLiane Praza 		return (NULL);
4178*1f6eb021SLiane Praza 	}
4179*1f6eb021SLiane Praza 
4180*1f6eb021SLiane Praza 	if (strlcat(name, "_", sz) >= sz) {
4181*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
4182*1f6eb021SLiane Praza 		free(name);
4183*1f6eb021SLiane Praza 		free(encoded);
4184*1f6eb021SLiane Praza 		return (NULL);
4185*1f6eb021SLiane Praza 	}
4186*1f6eb021SLiane Praza 
4187*1f6eb021SLiane Praza 	if (strlcat(name, desc_name, sz) >= sz) {
4188*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
4189*1f6eb021SLiane Praza 		free(name);
4190*1f6eb021SLiane Praza 		free(encoded);
4191*1f6eb021SLiane Praza 		return (NULL);
4192*1f6eb021SLiane Praza 	}
4193*1f6eb021SLiane Praza 
4194*1f6eb021SLiane Praza 	if (strlcat(name, "_", sz) >= sz) {
4195*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
4196*1f6eb021SLiane Praza 		free(name);
4197*1f6eb021SLiane Praza 		free(encoded);
4198*1f6eb021SLiane Praza 		return (NULL);
4199*1f6eb021SLiane Praza 	}
4200*1f6eb021SLiane Praza 
4201*1f6eb021SLiane Praza 	free(encoded);
4202*1f6eb021SLiane Praza 	return (name);
4203*1f6eb021SLiane Praza }
4204*1f6eb021SLiane Praza 
4205*1f6eb021SLiane Praza /*
4206*1f6eb021SLiane Praza  * ssize_t scf_tmpl_value_common_name()
4207*1f6eb021SLiane Praza  *
4208*1f6eb021SLiane Praza  * Populates "out" with an allocated string containing the value's
4209*1f6eb021SLiane Praza  * common name.  Returns the size of the string on successful return.
4210*1f6eb021SLiane Praza  * out must be freed with free() on successful return.
4211*1f6eb021SLiane Praza  *
4212*1f6eb021SLiane Praza  * Returns -1 on failure, sets scf_error() to:
4213*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
4214*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
4215*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
4216*1f6eb021SLiane Praza  *     Property group was deleted.
4217*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
4218*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
4219*1f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
4220*1f6eb021SLiane Praza  *     name not a valid property name
4221*1f6eb021SLiane Praza  *     name and locale are too long to make a property name
4222*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
4223*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
4224*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
4225*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
4226*1f6eb021SLiane Praza  *     Property doesn't exist or exists and has no value.
4227*1f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
4228*1f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
4229*1f6eb021SLiane Praza  *     property is not SCF_TYPE_ASTRING has more than one value.
4230*1f6eb021SLiane Praza  */
4231*1f6eb021SLiane Praza ssize_t
4232*1f6eb021SLiane Praza scf_tmpl_value_common_name(const scf_prop_tmpl_t *t, const char *locale,
4233*1f6eb021SLiane Praza     const char *value, char **out)
4234*1f6eb021SLiane Praza {
4235*1f6eb021SLiane Praza 	char *value_name = NULL;
4236*1f6eb021SLiane Praza 
4237*1f6eb021SLiane Praza 	value_name = _make_value_name("common_name", value);
4238*1f6eb021SLiane Praza 	if (value_name == NULL)
4239*1f6eb021SLiane Praza 		return (-1);
4240*1f6eb021SLiane Praza 
4241*1f6eb021SLiane Praza 	*out = _read_localized_astring_from_pg(t->prt_pg, value_name, locale);
4242*1f6eb021SLiane Praza 
4243*1f6eb021SLiane Praza 	free(value_name);
4244*1f6eb021SLiane Praza 
4245*1f6eb021SLiane Praza 	if (*out == NULL)
4246*1f6eb021SLiane Praza 		return (-1);
4247*1f6eb021SLiane Praza 
4248*1f6eb021SLiane Praza 	return (strlen(*out));
4249*1f6eb021SLiane Praza }
4250*1f6eb021SLiane Praza 
4251*1f6eb021SLiane Praza /*
4252*1f6eb021SLiane Praza  * ssize_t scf_tmpl_value_description()
4253*1f6eb021SLiane Praza  *
4254*1f6eb021SLiane Praza  * Populates "out" with an allocated string containing the value's
4255*1f6eb021SLiane Praza  * description.  Returns the size of the string on successful return.
4256*1f6eb021SLiane Praza  * out must be freed with free() on successful return.
4257*1f6eb021SLiane Praza  *
4258*1f6eb021SLiane Praza  * Returns -1 on failure, sets scf_error() to:
4259*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
4260*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
4261*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
4262*1f6eb021SLiane Praza  *     Property group was deleted.
4263*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
4264*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
4265*1f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
4266*1f6eb021SLiane Praza  *     name not a valid property name
4267*1f6eb021SLiane Praza  *     name and locale are too long to make a property name
4268*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
4269*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
4270*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
4271*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
4272*1f6eb021SLiane Praza  *     Property doesn't exist or exists and has no value.
4273*1f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
4274*1f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
4275*1f6eb021SLiane Praza  *     property is not SCF_TYPE_ASTRING has more than one value.
4276*1f6eb021SLiane Praza  */
4277*1f6eb021SLiane Praza ssize_t
4278*1f6eb021SLiane Praza scf_tmpl_value_description(const scf_prop_tmpl_t *t, const char *locale,
4279*1f6eb021SLiane Praza     const char *value, char **out)
4280*1f6eb021SLiane Praza {
4281*1f6eb021SLiane Praza 	char *value_name = NULL;
4282*1f6eb021SLiane Praza 
4283*1f6eb021SLiane Praza 	value_name = _make_value_name("description", value);
4284*1f6eb021SLiane Praza 	if (value_name == NULL)
4285*1f6eb021SLiane Praza 		return (-1);
4286*1f6eb021SLiane Praza 
4287*1f6eb021SLiane Praza 
4288*1f6eb021SLiane Praza 	*out = _read_localized_astring_from_pg(t->prt_pg, value_name, locale);
4289*1f6eb021SLiane Praza 
4290*1f6eb021SLiane Praza 	free(value_name);
4291*1f6eb021SLiane Praza 
4292*1f6eb021SLiane Praza 	if (*out == NULL)
4293*1f6eb021SLiane Praza 		return (-1);
4294*1f6eb021SLiane Praza 
4295*1f6eb021SLiane Praza 	return (strlen(*out));
4296*1f6eb021SLiane Praza }
4297*1f6eb021SLiane Praza 
4298*1f6eb021SLiane Praza /*
4299*1f6eb021SLiane Praza  * Templates error messages format, in human readable form.
4300*1f6eb021SLiane Praza  * Each line is one error item:
4301*1f6eb021SLiane Praza  *
4302*1f6eb021SLiane Praza  * prefix error message
4303*1f6eb021SLiane Praza  * 	FMRI="err->te_errs->tes_fmri"
4304*1f6eb021SLiane Praza  * 	Property group="err->te_pg_name"
4305*1f6eb021SLiane Praza  * 	Property name="err->te_prop_name"
4306*1f6eb021SLiane Praza  * 	expected value 1="err->te_ev1"
4307*1f6eb021SLiane Praza  * 	expected value 2="err->te_ev2"
4308*1f6eb021SLiane Praza  * 	actual value="err->te_actual"
4309*1f6eb021SLiane Praza  * 	Tempalte source="err->te_tmpl_fmri"
4310*1f6eb021SLiane Praza  * 	pg_pattern name="err->tmpl_pg_name"
4311*1f6eb021SLiane Praza  * 	pg_pattern type="err->tmpl_pg_type"
4312*1f6eb021SLiane Praza  * 	prop_pattern name="err->tmpl_prop_name"
4313*1f6eb021SLiane Praza  * 	prop_pattern type="err->tmpl_prop_type"
4314*1f6eb021SLiane Praza  *
4315*1f6eb021SLiane Praza  * To add a new error type, include scf_tmpl_error_type_t in libscf.h
4316*1f6eb021SLiane Praza  * add one entry in em_desc[], and update the functions pointed by the
4317*1f6eb021SLiane Praza  * _tmpl_error_access array with the new error code. Also, update the
4318*1f6eb021SLiane Praza  * scf_tmpl_error_* functions to provide access to desired
4319*1f6eb021SLiane Praza  * scf_tmpl_error_t fields.
4320*1f6eb021SLiane Praza  *
4321*1f6eb021SLiane Praza  * To add a new error item, add a new field to scf_tmpl_error_t, a new field
4322*1f6eb021SLiane Praza  * in _scf_tmpl_error_desc or a new non-error-dependent string, add a new entry
4323*1f6eb021SLiane Praza  * in _tmpl_error_access array and create the appropriate get_val, get_desc
4324*1f6eb021SLiane Praza  * functions.
4325*1f6eb021SLiane Praza  *
4326*1f6eb021SLiane Praza  * Changes to both the validation logic and the error types and items must
4327*1f6eb021SLiane Praza  * be coordinated with the code in svccfg to ensure both libscf and svccfg's
4328*1f6eb021SLiane Praza  * manifest validation validate the same things.
4329*1f6eb021SLiane Praza  */
4330*1f6eb021SLiane Praza 
4331*1f6eb021SLiane Praza /*
4332*1f6eb021SLiane Praza  * Container for all template errors on a validated object.
4333*1f6eb021SLiane Praza  */
4334*1f6eb021SLiane Praza struct scf_tmpl_errors {
4335*1f6eb021SLiane Praza 	int			tes_index;
4336*1f6eb021SLiane Praza 	int			tes_num_errs;
4337*1f6eb021SLiane Praza 	scf_tmpl_error_t	**tes_errs;
4338*1f6eb021SLiane Praza 	int			tes_errs_size;
4339*1f6eb021SLiane Praza 	const char		*tes_fmri;
4340*1f6eb021SLiane Praza 	const char		*tes_prefix;
4341*1f6eb021SLiane Praza 	int			tes_flag; /* if set, scf_tmpl_error_destroy */
4342*1f6eb021SLiane Praza 					    /* will free strings in tes_errs  */
4343*1f6eb021SLiane Praza };
4344*1f6eb021SLiane Praza 
4345*1f6eb021SLiane Praza /*
4346*1f6eb021SLiane Praza  * Templates error-dependent labels
4347*1f6eb021SLiane Praza  */
4348*1f6eb021SLiane Praza struct _scf_tmpl_error_desc {
4349*1f6eb021SLiane Praza 	const char *em_msg;
4350*1f6eb021SLiane Praza 	const char *em_ev1;
4351*1f6eb021SLiane Praza 	const char *em_ev2;
4352*1f6eb021SLiane Praza 	const char *em_actual;
4353*1f6eb021SLiane Praza };
4354*1f6eb021SLiane Praza 
4355*1f6eb021SLiane Praza /*
4356*1f6eb021SLiane Praza  * This array MUST be kept in synch with the template error definition of
4357*1f6eb021SLiane Praza  * scf_tmpl_error_type_t in libscf.h
4358*1f6eb021SLiane Praza  */
4359*1f6eb021SLiane Praza static struct _scf_tmpl_error_desc em_desc[] = {
4360*1f6eb021SLiane Praza 	/* SCF_TERR_MISSING_PG */
4361*1f6eb021SLiane Praza 	{ "Required property group missing", "Name of missing property group",
4362*1f6eb021SLiane Praza 	    "Type of missing property group", NULL },
4363*1f6eb021SLiane Praza 	/* SCF_TERR_WRONG_PG_TYPE */
4364*1f6eb021SLiane Praza 	{ "Property group has bad type", "Specified type", NULL,
4365*1f6eb021SLiane Praza 	    "Actual type" },
4366*1f6eb021SLiane Praza 	/* SCF_TERR_MISSING_PROP */
4367*1f6eb021SLiane Praza 	{ "Required property missing", "Name of missing property", NULL, NULL },
4368*1f6eb021SLiane Praza 	/* SCF_TERR_WRONG_PROP_TYPE */
4369*1f6eb021SLiane Praza 	{ "Property has bad type", "Specified property type", NULL,
4370*1f6eb021SLiane Praza 	    "Actual property type" },
4371*1f6eb021SLiane Praza 	/* SCF_TERR_CARDINALITY_VIOLATION */
4372*1f6eb021SLiane Praza 	{ "Number of property values violates cardinality restriction",
4373*1f6eb021SLiane Praza 	    "Cardinality minimum", "Cardinality maximum",
4374*1f6eb021SLiane Praza 	    "Actual number of values" },
4375*1f6eb021SLiane Praza 	/* SCF_TERR_VALUE_CONSTRAINT_VIOLATED */
4376*1f6eb021SLiane Praza 	{ "Property has illegal value", NULL, NULL, "Illegal value" },
4377*1f6eb021SLiane Praza 	/* SCF_TERR_RANGE_VIOLATION */
4378*1f6eb021SLiane Praza 	{ "Property value is out of range", NULL, NULL, "Actual value" },
4379*1f6eb021SLiane Praza 	/* SCF_TERR_PG_REDEFINE */
4380*1f6eb021SLiane Praza 	{ "Instance redefines pg_pattern", "Instance pg_pattern name",
4381*1f6eb021SLiane Praza 	    "Instance pg_pattern type", NULL },
4382*1f6eb021SLiane Praza 	/* SCF_TERR_PROP_TYPE_MISMATCH */
4383*1f6eb021SLiane Praza 	{ "Property type and value type mismatch", NULL, NULL, "Value type" },
4384*1f6eb021SLiane Praza 	/* SCF_TERR_VALUE_OUT_OF_RANGE */
4385*1f6eb021SLiane Praza 	{ "Value is out of range", NULL, NULL, "Value" },
4386*1f6eb021SLiane Praza 	/* SCF_TERR_INVALID_VALUE */
4387*1f6eb021SLiane Praza 	{ "Value is not valid", NULL, NULL, "Value" },
4388*1f6eb021SLiane Praza 	/* SCF_TERR_PG_PATTERN_CONFLICT */
4389*1f6eb021SLiane Praza 	{ "Conflicting pg_pattern specifications", "Template source",
4390*1f6eb021SLiane Praza 	    "pg_pattern name", "pg_pattern type" },
4391*1f6eb021SLiane Praza 	/* SCF_TERR_PROP_PATTERN_CONFLICT */
4392*1f6eb021SLiane Praza 	{ "Conflicting prop_pattern specifications", "Template source",
4393*1f6eb021SLiane Praza 	    "prop_pattern name", "prop_pattern type" },
4394*1f6eb021SLiane Praza 	/* SCF_TERR_GENERAL_REDEFINE */
4395*1f6eb021SLiane Praza 	{ "Service or instance pg_pattern redefines a global or restarter "
4396*1f6eb021SLiane Praza 	    "pg_pattern", "Template source", "pg_pattern name",
4397*1f6eb021SLiane Praza 	    "pg_pattern type" },
4398*1f6eb021SLiane Praza 	/* SCF_TERR_INCLUDE_VALUES */
4399*1f6eb021SLiane Praza 	{ "Missing constraints or values for include_values element",
4400*1f6eb021SLiane Praza 	    "include_values type", NULL, NULL },
4401*1f6eb021SLiane Praza 	/* SCF_TERR_PG_PATTERN_INCOMPLETE */
4402*1f6eb021SLiane Praza 	{ "Required pg_pattern is missing a name or type attribute",
4403*1f6eb021SLiane Praza 	    NULL, NULL, NULL },
4404*1f6eb021SLiane Praza 	/* SCF_TERR_PROP_PATTERN_INCOMPLETE */
4405*1f6eb021SLiane Praza 	{ "Required prop_pattern is missing a type attribute",
4406*1f6eb021SLiane Praza 	    NULL, NULL, NULL }
4407*1f6eb021SLiane Praza };
4408*1f6eb021SLiane Praza 
4409*1f6eb021SLiane Praza /*
4410*1f6eb021SLiane Praza  * Templates non error-dependent labels
4411*1f6eb021SLiane Praza  */
4412*1f6eb021SLiane Praza static const char *em_fmri = "FMRI";
4413*1f6eb021SLiane Praza static const char *em_pg_name = "Property group";
4414*1f6eb021SLiane Praza static const char *em_prop_name = "Property name";
4415*1f6eb021SLiane Praza static const char *em_tmpl_fmri = "Template source";
4416*1f6eb021SLiane Praza static const char *em_tmpl_pg_name = "pg_pattern name";
4417*1f6eb021SLiane Praza static const char *em_tmpl_pg_type = "pg_pattern type";
4418*1f6eb021SLiane Praza static const char *em_tmpl_prop_name = "prop_pattern name";
4419*1f6eb021SLiane Praza static const char *em_tmpl_prop_type = "prop_pattern type";
4420*1f6eb021SLiane Praza 
4421*1f6eb021SLiane Praza static const char *
4422*1f6eb021SLiane Praza _get_fmri_desc(scf_tmpl_error_t *err)
4423*1f6eb021SLiane Praza {
4424*1f6eb021SLiane Praza 	switch (err->te_type) {
4425*1f6eb021SLiane Praza 	case SCF_TERR_MISSING_PG:
4426*1f6eb021SLiane Praza 	case SCF_TERR_WRONG_PG_TYPE:
4427*1f6eb021SLiane Praza 	case SCF_TERR_MISSING_PROP:
4428*1f6eb021SLiane Praza 	case SCF_TERR_WRONG_PROP_TYPE:
4429*1f6eb021SLiane Praza 	case SCF_TERR_CARDINALITY_VIOLATION:
4430*1f6eb021SLiane Praza 	case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
4431*1f6eb021SLiane Praza 	case SCF_TERR_RANGE_VIOLATION:
4432*1f6eb021SLiane Praza 	case SCF_TERR_PG_REDEFINE:
4433*1f6eb021SLiane Praza 	case SCF_TERR_PG_PATTERN_INCOMPLETE:
4434*1f6eb021SLiane Praza 	case SCF_TERR_PROP_PATTERN_INCOMPLETE:
4435*1f6eb021SLiane Praza 	case SCF_TERR_INCLUDE_VALUES:
4436*1f6eb021SLiane Praza 		return (dgettext(TEXT_DOMAIN, em_fmri));
4437*1f6eb021SLiane Praza 	case SCF_TERR_PROP_TYPE_MISMATCH:
4438*1f6eb021SLiane Praza 	case SCF_TERR_VALUE_OUT_OF_RANGE:
4439*1f6eb021SLiane Praza 	case SCF_TERR_INVALID_VALUE:
4440*1f6eb021SLiane Praza 	case SCF_TERR_PG_PATTERN_CONFLICT:
4441*1f6eb021SLiane Praza 	case SCF_TERR_PROP_PATTERN_CONFLICT:
4442*1f6eb021SLiane Praza 	case SCF_TERR_GENERAL_REDEFINE:
4443*1f6eb021SLiane Praza 	default:
4444*1f6eb021SLiane Praza 		return (NULL);
4445*1f6eb021SLiane Praza 	}
4446*1f6eb021SLiane Praza }
4447*1f6eb021SLiane Praza 
4448*1f6eb021SLiane Praza static const char *
4449*1f6eb021SLiane Praza _get_pg_name_desc(scf_tmpl_error_t *err)
4450*1f6eb021SLiane Praza {
4451*1f6eb021SLiane Praza 	switch (err->te_type) {
4452*1f6eb021SLiane Praza 	case SCF_TERR_WRONG_PG_TYPE:
4453*1f6eb021SLiane Praza 	case SCF_TERR_MISSING_PROP:
4454*1f6eb021SLiane Praza 	case SCF_TERR_WRONG_PROP_TYPE:
4455*1f6eb021SLiane Praza 	case SCF_TERR_CARDINALITY_VIOLATION:
4456*1f6eb021SLiane Praza 	case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
4457*1f6eb021SLiane Praza 	case SCF_TERR_RANGE_VIOLATION:
4458*1f6eb021SLiane Praza 		return (dgettext(TEXT_DOMAIN, em_pg_name));
4459*1f6eb021SLiane Praza 	case SCF_TERR_MISSING_PG:
4460*1f6eb021SLiane Praza 	case SCF_TERR_PG_REDEFINE:
4461*1f6eb021SLiane Praza 	case SCF_TERR_PROP_TYPE_MISMATCH:
4462*1f6eb021SLiane Praza 	case SCF_TERR_VALUE_OUT_OF_RANGE:
4463*1f6eb021SLiane Praza 	case SCF_TERR_INVALID_VALUE:
4464*1f6eb021SLiane Praza 	case SCF_TERR_PG_PATTERN_CONFLICT:
4465*1f6eb021SLiane Praza 	case SCF_TERR_PROP_PATTERN_CONFLICT:
4466*1f6eb021SLiane Praza 	case SCF_TERR_GENERAL_REDEFINE:
4467*1f6eb021SLiane Praza 	case SCF_TERR_INCLUDE_VALUES:
4468*1f6eb021SLiane Praza 	case SCF_TERR_PG_PATTERN_INCOMPLETE:
4469*1f6eb021SLiane Praza 	case SCF_TERR_PROP_PATTERN_INCOMPLETE:
4470*1f6eb021SLiane Praza 	default:
4471*1f6eb021SLiane Praza 		return (NULL);
4472*1f6eb021SLiane Praza 	}
4473*1f6eb021SLiane Praza }
4474*1f6eb021SLiane Praza 
4475*1f6eb021SLiane Praza static const char *
4476*1f6eb021SLiane Praza _get_prop_name_desc(scf_tmpl_error_t *err)
4477*1f6eb021SLiane Praza {
4478*1f6eb021SLiane Praza 	switch (err->te_type) {
4479*1f6eb021SLiane Praza 	case SCF_TERR_WRONG_PROP_TYPE:
4480*1f6eb021SLiane Praza 	case SCF_TERR_CARDINALITY_VIOLATION:
4481*1f6eb021SLiane Praza 	case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
4482*1f6eb021SLiane Praza 	case SCF_TERR_RANGE_VIOLATION:
4483*1f6eb021SLiane Praza 		return (dgettext(TEXT_DOMAIN, em_prop_name));
4484*1f6eb021SLiane Praza 	case SCF_TERR_MISSING_PG:
4485*1f6eb021SLiane Praza 	case SCF_TERR_WRONG_PG_TYPE:
4486*1f6eb021SLiane Praza 	case SCF_TERR_MISSING_PROP:
4487*1f6eb021SLiane Praza 	case SCF_TERR_PG_REDEFINE:
4488*1f6eb021SLiane Praza 	case SCF_TERR_PROP_TYPE_MISMATCH:
4489*1f6eb021SLiane Praza 	case SCF_TERR_VALUE_OUT_OF_RANGE:
4490*1f6eb021SLiane Praza 	case SCF_TERR_INVALID_VALUE:
4491*1f6eb021SLiane Praza 	case SCF_TERR_PG_PATTERN_CONFLICT:
4492*1f6eb021SLiane Praza 	case SCF_TERR_PROP_PATTERN_CONFLICT:
4493*1f6eb021SLiane Praza 	case SCF_TERR_GENERAL_REDEFINE:
4494*1f6eb021SLiane Praza 	case SCF_TERR_INCLUDE_VALUES:
4495*1f6eb021SLiane Praza 	case SCF_TERR_PG_PATTERN_INCOMPLETE:
4496*1f6eb021SLiane Praza 	case SCF_TERR_PROP_PATTERN_INCOMPLETE:
4497*1f6eb021SLiane Praza 	default:
4498*1f6eb021SLiane Praza 		return (NULL);
4499*1f6eb021SLiane Praza 	}
4500*1f6eb021SLiane Praza }
4501*1f6eb021SLiane Praza 
4502*1f6eb021SLiane Praza static const char *
4503*1f6eb021SLiane Praza _get_ev1_desc(scf_tmpl_error_t *err)
4504*1f6eb021SLiane Praza {
4505*1f6eb021SLiane Praza 	switch (err->te_type) {
4506*1f6eb021SLiane Praza 	case SCF_TERR_MISSING_PG:
4507*1f6eb021SLiane Praza 	case SCF_TERR_WRONG_PG_TYPE:
4508*1f6eb021SLiane Praza 	case SCF_TERR_MISSING_PROP:
4509*1f6eb021SLiane Praza 	case SCF_TERR_WRONG_PROP_TYPE:
4510*1f6eb021SLiane Praza 	case SCF_TERR_CARDINALITY_VIOLATION:
4511*1f6eb021SLiane Praza 	case SCF_TERR_RANGE_VIOLATION:
4512*1f6eb021SLiane Praza 	case SCF_TERR_PG_REDEFINE:
4513*1f6eb021SLiane Praza 	case SCF_TERR_PG_PATTERN_CONFLICT:
4514*1f6eb021SLiane Praza 	case SCF_TERR_PROP_PATTERN_CONFLICT:
4515*1f6eb021SLiane Praza 	case SCF_TERR_GENERAL_REDEFINE:
4516*1f6eb021SLiane Praza 	case SCF_TERR_INCLUDE_VALUES:
4517*1f6eb021SLiane Praza 		return (dgettext(TEXT_DOMAIN, em_desc[err->te_type].em_ev1));
4518*1f6eb021SLiane Praza 	case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
4519*1f6eb021SLiane Praza 	case SCF_TERR_PROP_TYPE_MISMATCH:
4520*1f6eb021SLiane Praza 	case SCF_TERR_VALUE_OUT_OF_RANGE:
4521*1f6eb021SLiane Praza 	case SCF_TERR_INVALID_VALUE:
4522*1f6eb021SLiane Praza 	case SCF_TERR_PG_PATTERN_INCOMPLETE:
4523*1f6eb021SLiane Praza 	case SCF_TERR_PROP_PATTERN_INCOMPLETE:
4524*1f6eb021SLiane Praza 	default:
4525*1f6eb021SLiane Praza 		return (NULL);
4526*1f6eb021SLiane Praza 	}
4527*1f6eb021SLiane Praza }
4528*1f6eb021SLiane Praza 
4529*1f6eb021SLiane Praza static const char *
4530*1f6eb021SLiane Praza _get_ev2_desc(scf_tmpl_error_t *err)
4531*1f6eb021SLiane Praza {
4532*1f6eb021SLiane Praza 	switch (err->te_type) {
4533*1f6eb021SLiane Praza 	case SCF_TERR_MISSING_PG:
4534*1f6eb021SLiane Praza 	case SCF_TERR_CARDINALITY_VIOLATION:
4535*1f6eb021SLiane Praza 	case SCF_TERR_RANGE_VIOLATION:
4536*1f6eb021SLiane Praza 	case SCF_TERR_PG_REDEFINE:
4537*1f6eb021SLiane Praza 	case SCF_TERR_PG_PATTERN_CONFLICT:
4538*1f6eb021SLiane Praza 	case SCF_TERR_PROP_PATTERN_CONFLICT:
4539*1f6eb021SLiane Praza 	case SCF_TERR_GENERAL_REDEFINE:
4540*1f6eb021SLiane Praza 		return (dgettext(TEXT_DOMAIN, em_desc[err->te_type].em_ev2));
4541*1f6eb021SLiane Praza 	case SCF_TERR_WRONG_PG_TYPE:
4542*1f6eb021SLiane Praza 	case SCF_TERR_MISSING_PROP:
4543*1f6eb021SLiane Praza 	case SCF_TERR_WRONG_PROP_TYPE:
4544*1f6eb021SLiane Praza 	case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
4545*1f6eb021SLiane Praza 	case SCF_TERR_PROP_TYPE_MISMATCH:
4546*1f6eb021SLiane Praza 	case SCF_TERR_VALUE_OUT_OF_RANGE:
4547*1f6eb021SLiane Praza 	case SCF_TERR_INVALID_VALUE:
4548*1f6eb021SLiane Praza 	case SCF_TERR_INCLUDE_VALUES:
4549*1f6eb021SLiane Praza 	case SCF_TERR_PG_PATTERN_INCOMPLETE:
4550*1f6eb021SLiane Praza 	case SCF_TERR_PROP_PATTERN_INCOMPLETE:
4551*1f6eb021SLiane Praza 	default:
4552*1f6eb021SLiane Praza 		return (NULL);
4553*1f6eb021SLiane Praza 	}
4554*1f6eb021SLiane Praza }
4555*1f6eb021SLiane Praza 
4556*1f6eb021SLiane Praza static const char *
4557*1f6eb021SLiane Praza _get_actual_desc(scf_tmpl_error_t *err)
4558*1f6eb021SLiane Praza {
4559*1f6eb021SLiane Praza 	switch (err->te_type) {
4560*1f6eb021SLiane Praza 	case SCF_TERR_MISSING_PG:
4561*1f6eb021SLiane Praza 	case SCF_TERR_WRONG_PG_TYPE:
4562*1f6eb021SLiane Praza 	case SCF_TERR_WRONG_PROP_TYPE:
4563*1f6eb021SLiane Praza 	case SCF_TERR_CARDINALITY_VIOLATION:
4564*1f6eb021SLiane Praza 	case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
4565*1f6eb021SLiane Praza 	case SCF_TERR_RANGE_VIOLATION:
4566*1f6eb021SLiane Praza 	case SCF_TERR_PROP_TYPE_MISMATCH:
4567*1f6eb021SLiane Praza 	case SCF_TERR_VALUE_OUT_OF_RANGE:
4568*1f6eb021SLiane Praza 	case SCF_TERR_INVALID_VALUE:
4569*1f6eb021SLiane Praza 	case SCF_TERR_PG_PATTERN_CONFLICT:
4570*1f6eb021SLiane Praza 	case SCF_TERR_PROP_PATTERN_CONFLICT:
4571*1f6eb021SLiane Praza 	case SCF_TERR_GENERAL_REDEFINE:
4572*1f6eb021SLiane Praza 	case SCF_TERR_INCLUDE_VALUES:
4573*1f6eb021SLiane Praza 		return (dgettext(TEXT_DOMAIN,
4574*1f6eb021SLiane Praza 		    em_desc[err->te_type].em_actual));
4575*1f6eb021SLiane Praza 	case SCF_TERR_MISSING_PROP:
4576*1f6eb021SLiane Praza 	case SCF_TERR_PG_REDEFINE:
4577*1f6eb021SLiane Praza 	case SCF_TERR_PG_PATTERN_INCOMPLETE:
4578*1f6eb021SLiane Praza 	case SCF_TERR_PROP_PATTERN_INCOMPLETE:
4579*1f6eb021SLiane Praza 	default:
4580*1f6eb021SLiane Praza 		return (NULL);
4581*1f6eb021SLiane Praza 	}
4582*1f6eb021SLiane Praza }
4583*1f6eb021SLiane Praza 
4584*1f6eb021SLiane Praza static const char *
4585*1f6eb021SLiane Praza _get_tmpl_fmri_desc(scf_tmpl_error_t *err)
4586*1f6eb021SLiane Praza {
4587*1f6eb021SLiane Praza 	switch (err->te_type) {
4588*1f6eb021SLiane Praza 	case SCF_TERR_MISSING_PG:
4589*1f6eb021SLiane Praza 	case SCF_TERR_WRONG_PG_TYPE:
4590*1f6eb021SLiane Praza 	case SCF_TERR_MISSING_PROP:
4591*1f6eb021SLiane Praza 	case SCF_TERR_WRONG_PROP_TYPE:
4592*1f6eb021SLiane Praza 	case SCF_TERR_CARDINALITY_VIOLATION:
4593*1f6eb021SLiane Praza 	case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
4594*1f6eb021SLiane Praza 	case SCF_TERR_RANGE_VIOLATION:
4595*1f6eb021SLiane Praza 	case SCF_TERR_PG_REDEFINE:
4596*1f6eb021SLiane Praza 	case SCF_TERR_PROP_TYPE_MISMATCH:
4597*1f6eb021SLiane Praza 	case SCF_TERR_VALUE_OUT_OF_RANGE:
4598*1f6eb021SLiane Praza 	case SCF_TERR_INVALID_VALUE:
4599*1f6eb021SLiane Praza 	case SCF_TERR_PG_PATTERN_CONFLICT:
4600*1f6eb021SLiane Praza 	case SCF_TERR_PROP_PATTERN_CONFLICT:
4601*1f6eb021SLiane Praza 	case SCF_TERR_GENERAL_REDEFINE:
4602*1f6eb021SLiane Praza 	case SCF_TERR_INCLUDE_VALUES:
4603*1f6eb021SLiane Praza 	case SCF_TERR_PG_PATTERN_INCOMPLETE:
4604*1f6eb021SLiane Praza 	case SCF_TERR_PROP_PATTERN_INCOMPLETE:
4605*1f6eb021SLiane Praza 		return (dgettext(TEXT_DOMAIN, em_tmpl_fmri));
4606*1f6eb021SLiane Praza 	default:
4607*1f6eb021SLiane Praza 		return (NULL);
4608*1f6eb021SLiane Praza 	}
4609*1f6eb021SLiane Praza }
4610*1f6eb021SLiane Praza 
4611*1f6eb021SLiane Praza static const char *
4612*1f6eb021SLiane Praza _get_tmpl_pg_name_desc(scf_tmpl_error_t *err)
4613*1f6eb021SLiane Praza {
4614*1f6eb021SLiane Praza 	switch (err->te_type) {
4615*1f6eb021SLiane Praza 	case SCF_TERR_MISSING_PG:
4616*1f6eb021SLiane Praza 	case SCF_TERR_WRONG_PG_TYPE:
4617*1f6eb021SLiane Praza 	case SCF_TERR_MISSING_PROP:
4618*1f6eb021SLiane Praza 	case SCF_TERR_WRONG_PROP_TYPE:
4619*1f6eb021SLiane Praza 	case SCF_TERR_CARDINALITY_VIOLATION:
4620*1f6eb021SLiane Praza 	case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
4621*1f6eb021SLiane Praza 	case SCF_TERR_RANGE_VIOLATION:
4622*1f6eb021SLiane Praza 	case SCF_TERR_PG_REDEFINE:
4623*1f6eb021SLiane Praza 	case SCF_TERR_PROP_TYPE_MISMATCH:
4624*1f6eb021SLiane Praza 	case SCF_TERR_VALUE_OUT_OF_RANGE:
4625*1f6eb021SLiane Praza 	case SCF_TERR_INVALID_VALUE:
4626*1f6eb021SLiane Praza 	case SCF_TERR_PG_PATTERN_CONFLICT:
4627*1f6eb021SLiane Praza 	case SCF_TERR_PROP_PATTERN_CONFLICT:
4628*1f6eb021SLiane Praza 	case SCF_TERR_GENERAL_REDEFINE:
4629*1f6eb021SLiane Praza 	case SCF_TERR_INCLUDE_VALUES:
4630*1f6eb021SLiane Praza 	case SCF_TERR_PG_PATTERN_INCOMPLETE:
4631*1f6eb021SLiane Praza 	case SCF_TERR_PROP_PATTERN_INCOMPLETE:
4632*1f6eb021SLiane Praza 		return (dgettext(TEXT_DOMAIN, em_tmpl_pg_name));
4633*1f6eb021SLiane Praza 	default:
4634*1f6eb021SLiane Praza 		return (NULL);
4635*1f6eb021SLiane Praza 	}
4636*1f6eb021SLiane Praza }
4637*1f6eb021SLiane Praza 
4638*1f6eb021SLiane Praza static const char *
4639*1f6eb021SLiane Praza _get_tmpl_pg_type_desc(scf_tmpl_error_t *err)
4640*1f6eb021SLiane Praza {
4641*1f6eb021SLiane Praza 	switch (err->te_type) {
4642*1f6eb021SLiane Praza 	case SCF_TERR_MISSING_PG:
4643*1f6eb021SLiane Praza 	case SCF_TERR_WRONG_PG_TYPE:
4644*1f6eb021SLiane Praza 	case SCF_TERR_MISSING_PROP:
4645*1f6eb021SLiane Praza 	case SCF_TERR_WRONG_PROP_TYPE:
4646*1f6eb021SLiane Praza 	case SCF_TERR_CARDINALITY_VIOLATION:
4647*1f6eb021SLiane Praza 	case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
4648*1f6eb021SLiane Praza 	case SCF_TERR_RANGE_VIOLATION:
4649*1f6eb021SLiane Praza 	case SCF_TERR_PG_REDEFINE:
4650*1f6eb021SLiane Praza 	case SCF_TERR_PROP_TYPE_MISMATCH:
4651*1f6eb021SLiane Praza 	case SCF_TERR_VALUE_OUT_OF_RANGE:
4652*1f6eb021SLiane Praza 	case SCF_TERR_INVALID_VALUE:
4653*1f6eb021SLiane Praza 	case SCF_TERR_PG_PATTERN_CONFLICT:
4654*1f6eb021SLiane Praza 	case SCF_TERR_PROP_PATTERN_CONFLICT:
4655*1f6eb021SLiane Praza 	case SCF_TERR_GENERAL_REDEFINE:
4656*1f6eb021SLiane Praza 	case SCF_TERR_INCLUDE_VALUES:
4657*1f6eb021SLiane Praza 	case SCF_TERR_PROP_PATTERN_INCOMPLETE:
4658*1f6eb021SLiane Praza 	case SCF_TERR_PG_PATTERN_INCOMPLETE:
4659*1f6eb021SLiane Praza 		return (dgettext(TEXT_DOMAIN, em_tmpl_pg_type));
4660*1f6eb021SLiane Praza 	default:
4661*1f6eb021SLiane Praza 		return (NULL);
4662*1f6eb021SLiane Praza 	}
4663*1f6eb021SLiane Praza }
4664*1f6eb021SLiane Praza 
4665*1f6eb021SLiane Praza static const char *
4666*1f6eb021SLiane Praza _get_tmpl_prop_name_desc(scf_tmpl_error_t *err)
4667*1f6eb021SLiane Praza {
4668*1f6eb021SLiane Praza 	switch (err->te_type) {
4669*1f6eb021SLiane Praza 	case SCF_TERR_MISSING_PROP:
4670*1f6eb021SLiane Praza 	case SCF_TERR_WRONG_PROP_TYPE:
4671*1f6eb021SLiane Praza 	case SCF_TERR_CARDINALITY_VIOLATION:
4672*1f6eb021SLiane Praza 	case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
4673*1f6eb021SLiane Praza 	case SCF_TERR_RANGE_VIOLATION:
4674*1f6eb021SLiane Praza 	case SCF_TERR_PROP_TYPE_MISMATCH:
4675*1f6eb021SLiane Praza 	case SCF_TERR_VALUE_OUT_OF_RANGE:
4676*1f6eb021SLiane Praza 	case SCF_TERR_INVALID_VALUE:
4677*1f6eb021SLiane Praza 	case SCF_TERR_PROP_PATTERN_CONFLICT:
4678*1f6eb021SLiane Praza 	case SCF_TERR_INCLUDE_VALUES:
4679*1f6eb021SLiane Praza 	case SCF_TERR_PROP_PATTERN_INCOMPLETE:
4680*1f6eb021SLiane Praza 		return (dgettext(TEXT_DOMAIN, em_tmpl_prop_name));
4681*1f6eb021SLiane Praza 	case SCF_TERR_MISSING_PG:
4682*1f6eb021SLiane Praza 	case SCF_TERR_WRONG_PG_TYPE:
4683*1f6eb021SLiane Praza 	case SCF_TERR_PG_REDEFINE:
4684*1f6eb021SLiane Praza 	case SCF_TERR_PG_PATTERN_CONFLICT:
4685*1f6eb021SLiane Praza 	case SCF_TERR_GENERAL_REDEFINE:
4686*1f6eb021SLiane Praza 	case SCF_TERR_PG_PATTERN_INCOMPLETE:
4687*1f6eb021SLiane Praza 	default:
4688*1f6eb021SLiane Praza 		return (NULL);
4689*1f6eb021SLiane Praza 	}
4690*1f6eb021SLiane Praza }
4691*1f6eb021SLiane Praza 
4692*1f6eb021SLiane Praza static const char *
4693*1f6eb021SLiane Praza _get_tmpl_prop_type_desc(scf_tmpl_error_t *err)
4694*1f6eb021SLiane Praza {
4695*1f6eb021SLiane Praza 	switch (err->te_type) {
4696*1f6eb021SLiane Praza 	case SCF_TERR_MISSING_PROP:
4697*1f6eb021SLiane Praza 	case SCF_TERR_WRONG_PROP_TYPE:
4698*1f6eb021SLiane Praza 	case SCF_TERR_CARDINALITY_VIOLATION:
4699*1f6eb021SLiane Praza 	case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
4700*1f6eb021SLiane Praza 	case SCF_TERR_RANGE_VIOLATION:
4701*1f6eb021SLiane Praza 	case SCF_TERR_PROP_TYPE_MISMATCH:
4702*1f6eb021SLiane Praza 	case SCF_TERR_VALUE_OUT_OF_RANGE:
4703*1f6eb021SLiane Praza 	case SCF_TERR_INVALID_VALUE:
4704*1f6eb021SLiane Praza 	case SCF_TERR_PROP_PATTERN_CONFLICT:
4705*1f6eb021SLiane Praza 	case SCF_TERR_INCLUDE_VALUES:
4706*1f6eb021SLiane Praza 		return (dgettext(TEXT_DOMAIN, em_tmpl_prop_type));
4707*1f6eb021SLiane Praza 	case SCF_TERR_MISSING_PG:
4708*1f6eb021SLiane Praza 	case SCF_TERR_WRONG_PG_TYPE:
4709*1f6eb021SLiane Praza 	case SCF_TERR_PG_REDEFINE:
4710*1f6eb021SLiane Praza 	case SCF_TERR_PG_PATTERN_CONFLICT:
4711*1f6eb021SLiane Praza 	case SCF_TERR_GENERAL_REDEFINE:
4712*1f6eb021SLiane Praza 	case SCF_TERR_PG_PATTERN_INCOMPLETE:
4713*1f6eb021SLiane Praza 	case SCF_TERR_PROP_PATTERN_INCOMPLETE:
4714*1f6eb021SLiane Praza 	default:
4715*1f6eb021SLiane Praza 		return (NULL);
4716*1f6eb021SLiane Praza 	}
4717*1f6eb021SLiane Praza }
4718*1f6eb021SLiane Praza 
4719*1f6eb021SLiane Praza static const char *
4720*1f6eb021SLiane Praza _get_fmri_val(scf_tmpl_error_t *err)
4721*1f6eb021SLiane Praza {
4722*1f6eb021SLiane Praza 	assert(err != NULL && err->te_errs != NULL &&
4723*1f6eb021SLiane Praza 	    err->te_errs->tes_fmri != NULL);
4724*1f6eb021SLiane Praza 	return (err->te_errs->tes_fmri);
4725*1f6eb021SLiane Praza }
4726*1f6eb021SLiane Praza 
4727*1f6eb021SLiane Praza static const char *
4728*1f6eb021SLiane Praza _get_pg_name_val(scf_tmpl_error_t *err)
4729*1f6eb021SLiane Praza {
4730*1f6eb021SLiane Praza 	assert(err != NULL);
4731*1f6eb021SLiane Praza 	return (err->te_pg_name);
4732*1f6eb021SLiane Praza }
4733*1f6eb021SLiane Praza 
4734*1f6eb021SLiane Praza static const char *
4735*1f6eb021SLiane Praza _get_prop_name_val(scf_tmpl_error_t *err)
4736*1f6eb021SLiane Praza {
4737*1f6eb021SLiane Praza 	assert(err != NULL);
4738*1f6eb021SLiane Praza 	return (err->te_prop_name);
4739*1f6eb021SLiane Praza }
4740*1f6eb021SLiane Praza 
4741*1f6eb021SLiane Praza static const char *
4742*1f6eb021SLiane Praza _get_ev1_val(scf_tmpl_error_t *err)
4743*1f6eb021SLiane Praza {
4744*1f6eb021SLiane Praza 	assert(err != NULL);
4745*1f6eb021SLiane Praza 	return (err->te_ev1);
4746*1f6eb021SLiane Praza }
4747*1f6eb021SLiane Praza 
4748*1f6eb021SLiane Praza static const char *
4749*1f6eb021SLiane Praza _get_ev2_val(scf_tmpl_error_t *err)
4750*1f6eb021SLiane Praza {
4751*1f6eb021SLiane Praza 	assert(err != NULL);
4752*1f6eb021SLiane Praza 	return (err->te_ev2);
4753*1f6eb021SLiane Praza }
4754*1f6eb021SLiane Praza 
4755*1f6eb021SLiane Praza static const char *
4756*1f6eb021SLiane Praza _get_actual_val(scf_tmpl_error_t *err)
4757*1f6eb021SLiane Praza {
4758*1f6eb021SLiane Praza 	assert(err != NULL);
4759*1f6eb021SLiane Praza 	return (err->te_actual);
4760*1f6eb021SLiane Praza }
4761*1f6eb021SLiane Praza 
4762*1f6eb021SLiane Praza static const char *
4763*1f6eb021SLiane Praza _get_tmpl_fmri_val(scf_tmpl_error_t *err)
4764*1f6eb021SLiane Praza {
4765*1f6eb021SLiane Praza 	assert(err != NULL);
4766*1f6eb021SLiane Praza 	return (err->te_tmpl_fmri);
4767*1f6eb021SLiane Praza }
4768*1f6eb021SLiane Praza 
4769*1f6eb021SLiane Praza static const char *
4770*1f6eb021SLiane Praza _get_tmpl_pg_name_val(scf_tmpl_error_t *err)
4771*1f6eb021SLiane Praza {
4772*1f6eb021SLiane Praza 	assert(err != NULL);
4773*1f6eb021SLiane Praza 	return (err->te_tmpl_pg_name);
4774*1f6eb021SLiane Praza }
4775*1f6eb021SLiane Praza 
4776*1f6eb021SLiane Praza static const char *
4777*1f6eb021SLiane Praza _get_tmpl_pg_type_val(scf_tmpl_error_t *err)
4778*1f6eb021SLiane Praza {
4779*1f6eb021SLiane Praza 	assert(err != NULL);
4780*1f6eb021SLiane Praza 	return (err->te_tmpl_pg_type);
4781*1f6eb021SLiane Praza }
4782*1f6eb021SLiane Praza 
4783*1f6eb021SLiane Praza static const char *
4784*1f6eb021SLiane Praza _get_tmpl_prop_name_val(scf_tmpl_error_t *err)
4785*1f6eb021SLiane Praza {
4786*1f6eb021SLiane Praza 	assert(err != NULL);
4787*1f6eb021SLiane Praza 	return (err->te_tmpl_prop_name);
4788*1f6eb021SLiane Praza }
4789*1f6eb021SLiane Praza 
4790*1f6eb021SLiane Praza static const char *
4791*1f6eb021SLiane Praza _get_tmpl_prop_type_val(scf_tmpl_error_t *err)
4792*1f6eb021SLiane Praza {
4793*1f6eb021SLiane Praza 	assert(err != NULL);
4794*1f6eb021SLiane Praza 	return (err->te_tmpl_prop_type);
4795*1f6eb021SLiane Praza }
4796*1f6eb021SLiane Praza 
4797*1f6eb021SLiane Praza /*
4798*1f6eb021SLiane Praza  * Templates error item retrival functions
4799*1f6eb021SLiane Praza  */
4800*1f6eb021SLiane Praza typedef const char *(*get_em)(scf_tmpl_error_t *);
4801*1f6eb021SLiane Praza 
4802*1f6eb021SLiane Praza /*
4803*1f6eb021SLiane Praza  * if new items (lines) are added to the templates error messages,
4804*1f6eb021SLiane Praza  * new entries in this array (and new fuctions) will be required.
4805*1f6eb021SLiane Praza  */
4806*1f6eb021SLiane Praza static struct _tmpl_error_access {
4807*1f6eb021SLiane Praza 	get_em get_desc;
4808*1f6eb021SLiane Praza 	get_em get_val;
4809*1f6eb021SLiane Praza } _tmpl_error_items[] = {
4810*1f6eb021SLiane Praza 	{ (get_em)_get_fmri_desc, (get_em)_get_fmri_val },
4811*1f6eb021SLiane Praza 	{ (get_em)_get_pg_name_desc, (get_em)_get_pg_name_val },
4812*1f6eb021SLiane Praza 	{ (get_em)_get_prop_name_desc, (get_em)_get_prop_name_val },
4813*1f6eb021SLiane Praza 	{ (get_em)_get_ev1_desc, (get_em)_get_ev1_val },
4814*1f6eb021SLiane Praza 	{ (get_em)_get_ev2_desc, (get_em)_get_ev2_val },
4815*1f6eb021SLiane Praza 	{ (get_em)_get_actual_desc, (get_em)_get_actual_val },
4816*1f6eb021SLiane Praza 	{ (get_em)_get_tmpl_fmri_desc, (get_em)_get_tmpl_fmri_val },
4817*1f6eb021SLiane Praza 	{ (get_em)_get_tmpl_pg_name_desc, (get_em)_get_tmpl_pg_name_val },
4818*1f6eb021SLiane Praza 	{ (get_em)_get_tmpl_pg_type_desc, (get_em)_get_tmpl_pg_type_val },
4819*1f6eb021SLiane Praza 	{ (get_em)_get_tmpl_prop_name_desc, (get_em)_get_tmpl_prop_name_val },
4820*1f6eb021SLiane Praza 	{ (get_em)_get_tmpl_prop_type_desc, (get_em)_get_tmpl_prop_type_val },
4821*1f6eb021SLiane Praza 	{ NULL }
4822*1f6eb021SLiane Praza };
4823*1f6eb021SLiane Praza 
4824*1f6eb021SLiane Praza /*
4825*1f6eb021SLiane Praza  * Allocate a new scf_tmpl_error_t and add it to the errs list provided.
4826*1f6eb021SLiane Praza  * Returns NULL on failure.  Sets scf_error():
4827*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
4828*1f6eb021SLiane Praza  */
4829*1f6eb021SLiane Praza static scf_tmpl_error_t *
4830*1f6eb021SLiane Praza _create_error(scf_tmpl_errors_t *errs)
4831*1f6eb021SLiane Praza {
4832*1f6eb021SLiane Praza 	scf_tmpl_error_t *ret;
4833*1f6eb021SLiane Praza 	scf_tmpl_error_t **saved_errs;
4834*1f6eb021SLiane Praza 
4835*1f6eb021SLiane Praza 	assert(errs != NULL);
4836*1f6eb021SLiane Praza 	ret = calloc(1, sizeof (scf_tmpl_error_t));
4837*1f6eb021SLiane Praza 	if (ret == NULL) {
4838*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
4839*1f6eb021SLiane Praza 		return (NULL);
4840*1f6eb021SLiane Praza 	}
4841*1f6eb021SLiane Praza 
4842*1f6eb021SLiane Praza 	ret->te_errs = errs;
4843*1f6eb021SLiane Praza 
4844*1f6eb021SLiane Praza 	assert(errs->tes_num_errs <= errs->tes_errs_size);
4845*1f6eb021SLiane Praza 	if (errs->tes_num_errs == errs->tes_errs_size) {
4846*1f6eb021SLiane Praza 		/* Time to grow the pointer array. */
4847*1f6eb021SLiane Praza 		saved_errs = errs->tes_errs;
4848*1f6eb021SLiane Praza 		errs->tes_errs = calloc(2 * errs->tes_errs_size,
4849*1f6eb021SLiane Praza 		    sizeof (scf_tmpl_error_t *));
4850*1f6eb021SLiane Praza 		if (errs->tes_errs == NULL) {
4851*1f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
4852*1f6eb021SLiane Praza 			errs->tes_errs = saved_errs;
4853*1f6eb021SLiane Praza 			free(ret);
4854*1f6eb021SLiane Praza 			return (NULL);
4855*1f6eb021SLiane Praza 		}
4856*1f6eb021SLiane Praza 		(void) memcpy(errs->tes_errs, saved_errs, errs->tes_errs_size *
4857*1f6eb021SLiane Praza 		    sizeof (scf_tmpl_error_t *));
4858*1f6eb021SLiane Praza 		errs->tes_errs_size = 2 * errs->tes_errs_size;
4859*1f6eb021SLiane Praza 		free(saved_errs);
4860*1f6eb021SLiane Praza 	}
4861*1f6eb021SLiane Praza 
4862*1f6eb021SLiane Praza 	errs->tes_errs[errs->tes_num_errs] = ret;
4863*1f6eb021SLiane Praza 	errs->tes_num_errs++;
4864*1f6eb021SLiane Praza 
4865*1f6eb021SLiane Praza 	return (ret);
4866*1f6eb021SLiane Praza }
4867*1f6eb021SLiane Praza 
4868*1f6eb021SLiane Praza /*
4869*1f6eb021SLiane Praza  *
4870*1f6eb021SLiane Praza  * If destroy_strings is set, scf_tmpl_errors_destroy will free the
4871*1f6eb021SLiane Praza  * strings in scf_tmpl_error_t entries.
4872*1f6eb021SLiane Praza  *
4873*1f6eb021SLiane Praza  * Returns NULL on failure.  Sets scf_error():
4874*1f6eb021SLiane Praza  *    SCF_ERROR_NO_MEMORY
4875*1f6eb021SLiane Praza  */
4876*1f6eb021SLiane Praza scf_tmpl_errors_t *
4877*1f6eb021SLiane Praza _scf_create_errors(const char *fmri, int destroy_strings)
4878*1f6eb021SLiane Praza {
4879*1f6eb021SLiane Praza 	scf_tmpl_errors_t *ret;
4880*1f6eb021SLiane Praza 	int errs_size = 20;
4881*1f6eb021SLiane Praza 
4882*1f6eb021SLiane Praza 	assert(fmri != NULL);
4883*1f6eb021SLiane Praza 
4884*1f6eb021SLiane Praza 	ret = calloc(1, sizeof (scf_tmpl_errors_t));
4885*1f6eb021SLiane Praza 	if (ret == NULL) {
4886*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
4887*1f6eb021SLiane Praza 		return (NULL);
4888*1f6eb021SLiane Praza 	}
4889*1f6eb021SLiane Praza 
4890*1f6eb021SLiane Praza 	ret->tes_index = 0;
4891*1f6eb021SLiane Praza 	ret->tes_num_errs = 0;
4892*1f6eb021SLiane Praza 	if ((ret->tes_fmri = strdup(fmri)) == NULL) {
4893*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
4894*1f6eb021SLiane Praza 		free(ret);
4895*1f6eb021SLiane Praza 		return (NULL);
4896*1f6eb021SLiane Praza 	}
4897*1f6eb021SLiane Praza 
4898*1f6eb021SLiane Praza 	ret->tes_prefix = strdup("");
4899*1f6eb021SLiane Praza 	if (ret->tes_prefix == NULL) {
4900*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
4901*1f6eb021SLiane Praza 		free((char *)ret->tes_fmri);
4902*1f6eb021SLiane Praza 		free(ret);
4903*1f6eb021SLiane Praza 		return (NULL);
4904*1f6eb021SLiane Praza 	}
4905*1f6eb021SLiane Praza 	ret->tes_flag = destroy_strings;
4906*1f6eb021SLiane Praza 
4907*1f6eb021SLiane Praza 	/* Make space for a few errors. */
4908*1f6eb021SLiane Praza 	ret->tes_errs = calloc(errs_size, sizeof (scf_tmpl_error_t *));
4909*1f6eb021SLiane Praza 	if (ret->tes_errs == NULL) {
4910*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
4911*1f6eb021SLiane Praza 		free((char *)ret->tes_fmri);
4912*1f6eb021SLiane Praza 		free((char *)ret->tes_prefix);
4913*1f6eb021SLiane Praza 		free(ret);
4914*1f6eb021SLiane Praza 		return (NULL);
4915*1f6eb021SLiane Praza 	}
4916*1f6eb021SLiane Praza 	ret->tes_errs_size = errs_size;
4917*1f6eb021SLiane Praza 
4918*1f6eb021SLiane Praza 	return (ret);
4919*1f6eb021SLiane Praza }
4920*1f6eb021SLiane Praza 
4921*1f6eb021SLiane Praza /*
4922*1f6eb021SLiane Praza  * return 0 on success, if fails set scf_error() to:
4923*1f6eb021SLiane Praza  *
4924*1f6eb021SLiane Praza  *    SCF_ERROR_NO_MEMORY
4925*1f6eb021SLiane Praza  */
4926*1f6eb021SLiane Praza int
4927*1f6eb021SLiane Praza _scf_tmpl_error_set_prefix(scf_tmpl_errors_t *errs, const char *prefix)
4928*1f6eb021SLiane Praza {
4929*1f6eb021SLiane Praza 	free((void *) errs->tes_prefix);
4930*1f6eb021SLiane Praza 	if (prefix == NULL)
4931*1f6eb021SLiane Praza 		errs->tes_prefix = strdup("");
4932*1f6eb021SLiane Praza 	else
4933*1f6eb021SLiane Praza 		errs->tes_prefix = strdup(prefix);
4934*1f6eb021SLiane Praza 	if (errs->tes_prefix == NULL) {
4935*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
4936*1f6eb021SLiane Praza 		return (-1);
4937*1f6eb021SLiane Praza 	}
4938*1f6eb021SLiane Praza 	return (0);
4939*1f6eb021SLiane Praza }
4940*1f6eb021SLiane Praza 
4941*1f6eb021SLiane Praza /*
4942*1f6eb021SLiane Praza  *
4943*1f6eb021SLiane Praza  * Returns -1 on failure.  Sets scf_error():
4944*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
4945*1f6eb021SLiane Praza  */
4946*1f6eb021SLiane Praza int
4947*1f6eb021SLiane Praza _scf_tmpl_add_error(scf_tmpl_errors_t *errs, scf_tmpl_error_type_t type,
4948*1f6eb021SLiane Praza     const char *pg_name, const char *prop_name,
4949*1f6eb021SLiane Praza     const char *ev1, const char *ev2, const char *actual,
4950*1f6eb021SLiane Praza     const char *tmpl_fmri, const char *tmpl_pg_name, const char *tmpl_pg_type,
4951*1f6eb021SLiane Praza     const char *tmpl_prop_name, const char *tmpl_prop_type)
4952*1f6eb021SLiane Praza {
4953*1f6eb021SLiane Praza 	scf_tmpl_error_t *err;
4954*1f6eb021SLiane Praza 
4955*1f6eb021SLiane Praza 	assert(errs != NULL);
4956*1f6eb021SLiane Praza 	assert(tmpl_fmri != NULL);
4957*1f6eb021SLiane Praza 
4958*1f6eb021SLiane Praza 	err = _create_error(errs);
4959*1f6eb021SLiane Praza 	if (err == NULL)
4960*1f6eb021SLiane Praza 		return (-1);
4961*1f6eb021SLiane Praza 
4962*1f6eb021SLiane Praza 	err->te_type = type;
4963*1f6eb021SLiane Praza 	err->te_pg_name = pg_name;
4964*1f6eb021SLiane Praza 	err->te_prop_name = prop_name;
4965*1f6eb021SLiane Praza 	err->te_ev1 = ev1;
4966*1f6eb021SLiane Praza 	err->te_ev2 = ev2;
4967*1f6eb021SLiane Praza 	err->te_actual = actual;
4968*1f6eb021SLiane Praza 	err->te_tmpl_fmri = tmpl_fmri;
4969*1f6eb021SLiane Praza 	err->te_tmpl_pg_name = tmpl_pg_name;
4970*1f6eb021SLiane Praza 	err->te_tmpl_pg_type = tmpl_pg_type;
4971*1f6eb021SLiane Praza 	err->te_tmpl_prop_name = tmpl_prop_name;
4972*1f6eb021SLiane Praza 	err->te_tmpl_prop_type = tmpl_prop_type;
4973*1f6eb021SLiane Praza 
4974*1f6eb021SLiane Praza 	return (0);
4975*1f6eb021SLiane Praza }
4976*1f6eb021SLiane Praza 
4977*1f6eb021SLiane Praza /*
4978*1f6eb021SLiane Praza  * returns an allocated string that must be freed with free()
4979*1f6eb021SLiane Praza  * string contains converted 64-bit integer value
4980*1f6eb021SLiane Praza  * flag set for signed values
4981*1f6eb021SLiane Praza  * if fails return NULL and set scf_error() to:
4982*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
4983*1f6eb021SLiane Praza  */
4984*1f6eb021SLiane Praza static char *
4985*1f6eb021SLiane Praza _val_to_string(uint64_t val, int flag)
4986*1f6eb021SLiane Praza {
4987*1f6eb021SLiane Praza 	ssize_t sz = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH) + 1;
4988*1f6eb021SLiane Praza 	char *buf;
4989*1f6eb021SLiane Praza 
4990*1f6eb021SLiane Praza 	buf = malloc(sz);
4991*1f6eb021SLiane Praza 	if (buf == NULL) {
4992*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
4993*1f6eb021SLiane Praza 		return (NULL);
4994*1f6eb021SLiane Praza 	}
4995*1f6eb021SLiane Praza 
4996*1f6eb021SLiane Praza 	if (flag == 0)
4997*1f6eb021SLiane Praza 		(void) snprintf(buf, sz, "%" PRIu64, val);
4998*1f6eb021SLiane Praza 	else
4999*1f6eb021SLiane Praza 		(void) snprintf(buf, sz, "%" PRIi64, (int64_t)val);
5000*1f6eb021SLiane Praza 
5001*1f6eb021SLiane Praza 	return (buf);
5002*1f6eb021SLiane Praza }
5003*1f6eb021SLiane Praza 
5004*1f6eb021SLiane Praza /*
5005*1f6eb021SLiane Praza  * return 0 on success, -1 on failure.
5006*1f6eb021SLiane Praza  * set scf_error() to:
5007*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
5008*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
5009*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
5010*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
5011*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
5012*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
5013*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
5014*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
5015*1f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
5016*1f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
5017*1f6eb021SLiane Praza  */
5018*1f6eb021SLiane Praza static int
5019*1f6eb021SLiane Praza _add_tmpl_missing_pg_error(scf_tmpl_errors_t *errs, scf_pg_tmpl_t *t)
5020*1f6eb021SLiane Praza {
5021*1f6eb021SLiane Praza 	char *ev1 = NULL;
5022*1f6eb021SLiane Praza 	char *ev2 = NULL;
5023*1f6eb021SLiane Praza 	char *t_fmri = NULL;
5024*1f6eb021SLiane Praza 	char *t_pg_name = NULL;
5025*1f6eb021SLiane Praza 	char *t_pg_type = NULL;
5026*1f6eb021SLiane Praza 
5027*1f6eb021SLiane Praza 	if ((t_fmri = _scf_tmpl_get_fmri(t)) == NULL)
5028*1f6eb021SLiane Praza 		return (-1);
5029*1f6eb021SLiane Praza 	if (scf_tmpl_pg_name(t, &t_pg_name) == -1) {
5030*1f6eb021SLiane Praza 		goto cleanup;
5031*1f6eb021SLiane Praza 	}
5032*1f6eb021SLiane Praza 	if (scf_tmpl_pg_type(t, &t_pg_type) == -1) {
5033*1f6eb021SLiane Praza 		goto cleanup;
5034*1f6eb021SLiane Praza 	}
5035*1f6eb021SLiane Praza 	if ((ev1 = strdup(t_pg_name)) == NULL) {
5036*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
5037*1f6eb021SLiane Praza 		goto cleanup;
5038*1f6eb021SLiane Praza 	}
5039*1f6eb021SLiane Praza 	if ((ev2 = strdup(t_pg_type)) == NULL) {
5040*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
5041*1f6eb021SLiane Praza 		goto cleanup;
5042*1f6eb021SLiane Praza 	}
5043*1f6eb021SLiane Praza 
5044*1f6eb021SLiane Praza 	return (_scf_tmpl_add_error(errs, SCF_TERR_MISSING_PG, NULL, NULL, ev1,
5045*1f6eb021SLiane Praza 	    ev2, NULL, t_fmri, t_pg_name, t_pg_type, NULL, NULL));
5046*1f6eb021SLiane Praza cleanup:
5047*1f6eb021SLiane Praza 	free(ev1);
5048*1f6eb021SLiane Praza 	free(ev2);
5049*1f6eb021SLiane Praza 	free(t_fmri);
5050*1f6eb021SLiane Praza 	free(t_pg_name);
5051*1f6eb021SLiane Praza 	free(t_pg_type);
5052*1f6eb021SLiane Praza 	return (-1);
5053*1f6eb021SLiane Praza }
5054*1f6eb021SLiane Praza 
5055*1f6eb021SLiane Praza /*
5056*1f6eb021SLiane Praza  * return 0 on success, -1 on failure.
5057*1f6eb021SLiane Praza  * set scf_error() to:
5058*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
5059*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
5060*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
5061*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
5062*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
5063*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
5064*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
5065*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
5066*1f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
5067*1f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
5068*1f6eb021SLiane Praza  */
5069*1f6eb021SLiane Praza static int
5070*1f6eb021SLiane Praza _add_tmpl_wrong_pg_type_error(scf_tmpl_errors_t *errs, scf_pg_tmpl_t *t,
5071*1f6eb021SLiane Praza     scf_propertygroup_t *pg)
5072*1f6eb021SLiane Praza {
5073*1f6eb021SLiane Praza 	char *pg_name = NULL;
5074*1f6eb021SLiane Praza 	char *ev1 = NULL;
5075*1f6eb021SLiane Praza 	char *actual = NULL;
5076*1f6eb021SLiane Praza 	char *t_fmri = NULL;
5077*1f6eb021SLiane Praza 	char *t_pg_name = NULL;
5078*1f6eb021SLiane Praza 	char *t_pg_type = NULL;
5079*1f6eb021SLiane Praza 
5080*1f6eb021SLiane Praza 	if ((t_fmri = _scf_tmpl_get_fmri(t)) == NULL)
5081*1f6eb021SLiane Praza 		return (-1);
5082*1f6eb021SLiane Praza 	if ((pg_name = _scf_get_pg_name(pg)) == NULL)
5083*1f6eb021SLiane Praza 		goto cleanup;
5084*1f6eb021SLiane Praza 	if ((actual = _scf_get_pg_type(pg)) == NULL)
5085*1f6eb021SLiane Praza 		goto cleanup;
5086*1f6eb021SLiane Praza 	if (scf_tmpl_pg_name(t, &t_pg_name) == -1) {
5087*1f6eb021SLiane Praza 		goto cleanup;
5088*1f6eb021SLiane Praza 	}
5089*1f6eb021SLiane Praza 	if (scf_tmpl_pg_type(t, &t_pg_type) == -1) {
5090*1f6eb021SLiane Praza 		goto cleanup;
5091*1f6eb021SLiane Praza 	}
5092*1f6eb021SLiane Praza 	if ((ev1 = strdup(t_pg_type)) == NULL) {
5093*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
5094*1f6eb021SLiane Praza 		goto cleanup;
5095*1f6eb021SLiane Praza 	}
5096*1f6eb021SLiane Praza 
5097*1f6eb021SLiane Praza 	return (_scf_tmpl_add_error(errs, SCF_TERR_WRONG_PG_TYPE, pg_name, NULL,
5098*1f6eb021SLiane Praza 	    ev1, NULL, actual, t_fmri, t_pg_name, t_pg_type, NULL, NULL));
5099*1f6eb021SLiane Praza cleanup:
5100*1f6eb021SLiane Praza 	free(pg_name);
5101*1f6eb021SLiane Praza 	free(ev1);
5102*1f6eb021SLiane Praza 	free(actual);
5103*1f6eb021SLiane Praza 	free(t_fmri);
5104*1f6eb021SLiane Praza 	free(t_pg_name);
5105*1f6eb021SLiane Praza 	free(t_pg_type);
5106*1f6eb021SLiane Praza 	return (-1);
5107*1f6eb021SLiane Praza }
5108*1f6eb021SLiane Praza 
5109*1f6eb021SLiane Praza /*
5110*1f6eb021SLiane Praza  * return 0 on success, -1 on failure.
5111*1f6eb021SLiane Praza  * set scf_error() to:
5112*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
5113*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
5114*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
5115*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
5116*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
5117*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
5118*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
5119*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
5120*1f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
5121*1f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
5122*1f6eb021SLiane Praza  */
5123*1f6eb021SLiane Praza static int
5124*1f6eb021SLiane Praza _add_tmpl_missing_prop_error(scf_tmpl_errors_t *errs, scf_pg_tmpl_t *t,
5125*1f6eb021SLiane Praza     scf_propertygroup_t *pg, const scf_prop_tmpl_t *pt)
5126*1f6eb021SLiane Praza {
5127*1f6eb021SLiane Praza 	char *pg_name = NULL;
5128*1f6eb021SLiane Praza 	char *ev1 = NULL;
5129*1f6eb021SLiane Praza 	char *t_fmri = NULL;
5130*1f6eb021SLiane Praza 	char *t_pg_name = NULL;
5131*1f6eb021SLiane Praza 	char *t_pg_type = NULL;
5132*1f6eb021SLiane Praza 	char *t_prop_name = NULL;
5133*1f6eb021SLiane Praza 	char *t_prop_type = NULL;
5134*1f6eb021SLiane Praza 
5135*1f6eb021SLiane Praza 	if ((t_fmri = _scf_tmpl_get_fmri(t)) == NULL)
5136*1f6eb021SLiane Praza 		return (-1);
5137*1f6eb021SLiane Praza 	if ((pg_name = _scf_get_pg_name(pg)) == NULL)
5138*1f6eb021SLiane Praza 		goto cleanup;
5139*1f6eb021SLiane Praza 	if (scf_tmpl_pg_name(t, &t_pg_name) == -1) {
5140*1f6eb021SLiane Praza 		goto cleanup;
5141*1f6eb021SLiane Praza 	}
5142*1f6eb021SLiane Praza 	if (scf_tmpl_pg_type(t, &t_pg_type) == -1) {
5143*1f6eb021SLiane Praza 		goto cleanup;
5144*1f6eb021SLiane Praza 	}
5145*1f6eb021SLiane Praza 	if (scf_tmpl_prop_name(pt, &t_prop_name) == -1) {
5146*1f6eb021SLiane Praza 		goto cleanup;
5147*1f6eb021SLiane Praza 	}
5148*1f6eb021SLiane Praza 	t_prop_type = _scf_read_tmpl_prop_type_as_string(pt);
5149*1f6eb021SLiane Praza 	if (t_prop_type != NULL && t_prop_type[0] == '\0') {
5150*1f6eb021SLiane Praza 		free(t_prop_type);
5151*1f6eb021SLiane Praza 		t_prop_type = NULL;
5152*1f6eb021SLiane Praza 	} else if (t_prop_type == NULL) {
5153*1f6eb021SLiane Praza 		goto cleanup;
5154*1f6eb021SLiane Praza 	}
5155*1f6eb021SLiane Praza 	if (t_prop_type == NULL)
5156*1f6eb021SLiane Praza 		if ((t_prop_type = strdup(SCF_TMPL_WILDCARD)) == NULL) {
5157*1f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
5158*1f6eb021SLiane Praza 			goto cleanup;
5159*1f6eb021SLiane Praza 		}
5160*1f6eb021SLiane Praza 	if ((ev1 = strdup(t_prop_name)) == NULL) {
5161*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
5162*1f6eb021SLiane Praza 		goto cleanup;
5163*1f6eb021SLiane Praza 	}
5164*1f6eb021SLiane Praza 
5165*1f6eb021SLiane Praza 	return (_scf_tmpl_add_error(errs, SCF_TERR_MISSING_PROP, pg_name, NULL,
5166*1f6eb021SLiane Praza 	    ev1, NULL, NULL, t_fmri, t_pg_name, t_pg_type, t_prop_name,
5167*1f6eb021SLiane Praza 	    t_prop_type));
5168*1f6eb021SLiane Praza cleanup:
5169*1f6eb021SLiane Praza 	free(pg_name);
5170*1f6eb021SLiane Praza 	free(ev1);
5171*1f6eb021SLiane Praza 	free(t_fmri);
5172*1f6eb021SLiane Praza 	free(t_pg_name);
5173*1f6eb021SLiane Praza 	free(t_pg_type);
5174*1f6eb021SLiane Praza 	free(t_prop_name);
5175*1f6eb021SLiane Praza 	free(t_prop_type);
5176*1f6eb021SLiane Praza 	return (-1);
5177*1f6eb021SLiane Praza }
5178*1f6eb021SLiane Praza 
5179*1f6eb021SLiane Praza /*
5180*1f6eb021SLiane Praza  * return 0 on success, -1 on failure.
5181*1f6eb021SLiane Praza  * set scf_error() to:
5182*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
5183*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
5184*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
5185*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
5186*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
5187*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
5188*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
5189*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
5190*1f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
5191*1f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
5192*1f6eb021SLiane Praza  */
5193*1f6eb021SLiane Praza static int
5194*1f6eb021SLiane Praza _add_tmpl_wrong_prop_type_error(scf_tmpl_errors_t *errs,
5195*1f6eb021SLiane Praza     scf_propertygroup_t *pg, const scf_prop_tmpl_t *pt, scf_property_t *prop)
5196*1f6eb021SLiane Praza {
5197*1f6eb021SLiane Praza 	char *pg_name = NULL;
5198*1f6eb021SLiane Praza 	char *prop_name = NULL;
5199*1f6eb021SLiane Praza 	char *ev1 = NULL;
5200*1f6eb021SLiane Praza 	char *actual = NULL;
5201*1f6eb021SLiane Praza 	char *t_fmri = NULL;
5202*1f6eb021SLiane Praza 	char *t_pg_name = NULL;
5203*1f6eb021SLiane Praza 	char *t_pg_type = NULL;
5204*1f6eb021SLiane Praza 	char *t_prop_name = NULL;
5205*1f6eb021SLiane Praza 	char *t_prop_type = NULL;
5206*1f6eb021SLiane Praza 
5207*1f6eb021SLiane Praza 	if ((t_fmri = _scf_tmpl_get_fmri(pt->prt_t)) == NULL)
5208*1f6eb021SLiane Praza 		return (-1);
5209*1f6eb021SLiane Praza 	if ((pg_name = _scf_get_pg_name(pg)) == NULL)
5210*1f6eb021SLiane Praza 		goto cleanup;
5211*1f6eb021SLiane Praza 	if ((prop_name = _scf_get_prop_name(prop)) == NULL)
5212*1f6eb021SLiane Praza 		goto cleanup;
5213*1f6eb021SLiane Praza 	if ((actual = _scf_get_prop_type(prop)) == NULL)
5214*1f6eb021SLiane Praza 		goto cleanup;
5215*1f6eb021SLiane Praza 	if (scf_tmpl_pg_name(pt->prt_t, &t_pg_name) == -1) {
5216*1f6eb021SLiane Praza 		goto cleanup;
5217*1f6eb021SLiane Praza 	}
5218*1f6eb021SLiane Praza 	if (scf_tmpl_pg_type(pt->prt_t, &t_pg_type) == -1) {
5219*1f6eb021SLiane Praza 		goto cleanup;
5220*1f6eb021SLiane Praza 	}
5221*1f6eb021SLiane Praza 	if (scf_tmpl_prop_name(pt, &t_prop_name) == -1) {
5222*1f6eb021SLiane Praza 		goto cleanup;
5223*1f6eb021SLiane Praza 	}
5224*1f6eb021SLiane Praza 	t_prop_type = _scf_read_tmpl_prop_type_as_string(pt);
5225*1f6eb021SLiane Praza 	if (t_prop_type != NULL && t_prop_type[0] == '\0') {
5226*1f6eb021SLiane Praza 		free(t_prop_type);
5227*1f6eb021SLiane Praza 		t_prop_type = NULL;
5228*1f6eb021SLiane Praza 	} else if (t_prop_type == NULL) {
5229*1f6eb021SLiane Praza 		goto cleanup;
5230*1f6eb021SLiane Praza 	}
5231*1f6eb021SLiane Praza 	if (t_prop_type == NULL)
5232*1f6eb021SLiane Praza 		if ((t_prop_type = strdup(SCF_TMPL_WILDCARD)) == NULL) {
5233*1f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
5234*1f6eb021SLiane Praza 			goto cleanup;
5235*1f6eb021SLiane Praza 		}
5236*1f6eb021SLiane Praza 	if ((ev1 = strdup(t_prop_type)) == NULL) {
5237*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
5238*1f6eb021SLiane Praza 		goto cleanup;
5239*1f6eb021SLiane Praza 	}
5240*1f6eb021SLiane Praza 
5241*1f6eb021SLiane Praza 	return (_scf_tmpl_add_error(errs, SCF_TERR_WRONG_PROP_TYPE, pg_name,
5242*1f6eb021SLiane Praza 	    prop_name, ev1, NULL, actual, t_fmri, t_pg_name, t_pg_type,
5243*1f6eb021SLiane Praza 	    t_prop_name, t_prop_type));
5244*1f6eb021SLiane Praza cleanup:
5245*1f6eb021SLiane Praza 	free(pg_name);
5246*1f6eb021SLiane Praza 	free(prop_name);
5247*1f6eb021SLiane Praza 	free(ev1);
5248*1f6eb021SLiane Praza 	free(actual);
5249*1f6eb021SLiane Praza 	free(t_fmri);
5250*1f6eb021SLiane Praza 	free(t_pg_name);
5251*1f6eb021SLiane Praza 	free(t_pg_type);
5252*1f6eb021SLiane Praza 	free(t_prop_name);
5253*1f6eb021SLiane Praza 	free(t_prop_type);
5254*1f6eb021SLiane Praza 	return (-1);
5255*1f6eb021SLiane Praza }
5256*1f6eb021SLiane Praza 
5257*1f6eb021SLiane Praza /*
5258*1f6eb021SLiane Praza  * return 0 on success, -1 on failure.
5259*1f6eb021SLiane Praza  * set scf_error() to:
5260*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
5261*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
5262*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
5263*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
5264*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
5265*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
5266*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
5267*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
5268*1f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
5269*1f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
5270*1f6eb021SLiane Praza  */
5271*1f6eb021SLiane Praza static int
5272*1f6eb021SLiane Praza _add_tmpl_count_error(scf_tmpl_errors_t *errs, scf_tmpl_error_type_t type,
5273*1f6eb021SLiane Praza     scf_propertygroup_t *pg, const scf_prop_tmpl_t *pt, scf_property_t *prop,
5274*1f6eb021SLiane Praza     uint64_t count, uint64_t *min, uint64_t *max)
5275*1f6eb021SLiane Praza {
5276*1f6eb021SLiane Praza 	char *pg_name = NULL;
5277*1f6eb021SLiane Praza 	char *prop_name = NULL;
5278*1f6eb021SLiane Praza 	char *s_min = NULL;
5279*1f6eb021SLiane Praza 	char *s_max = NULL;
5280*1f6eb021SLiane Praza 	char *num = NULL;
5281*1f6eb021SLiane Praza 	char *t_fmri = NULL;
5282*1f6eb021SLiane Praza 	char *t_pg_name = NULL;
5283*1f6eb021SLiane Praza 	char *t_pg_type = NULL;
5284*1f6eb021SLiane Praza 	char *t_prop_name = NULL;
5285*1f6eb021SLiane Praza 	char *t_prop_type = NULL;
5286*1f6eb021SLiane Praza 
5287*1f6eb021SLiane Praza 	if ((t_fmri = _scf_tmpl_get_fmri(pt->prt_t)) == NULL)
5288*1f6eb021SLiane Praza 		return (-1);
5289*1f6eb021SLiane Praza 	switch (type) {
5290*1f6eb021SLiane Praza 	case SCF_TERR_RANGE_VIOLATION:
5291*1f6eb021SLiane Praza 	case SCF_TERR_CARDINALITY_VIOLATION:
5292*1f6eb021SLiane Praza 		if ((pg_name = _scf_get_pg_name(pg)) == NULL)
5293*1f6eb021SLiane Praza 			goto cleanup;
5294*1f6eb021SLiane Praza 		if ((prop_name = _scf_get_prop_name(prop)) == NULL)
5295*1f6eb021SLiane Praza 			goto cleanup;
5296*1f6eb021SLiane Praza 		break;
5297*1f6eb021SLiane Praza 	case SCF_TERR_VALUE_OUT_OF_RANGE:
5298*1f6eb021SLiane Praza 		/* keep pg_name = NULL and prop_name = NULL */
5299*1f6eb021SLiane Praza 		break;
5300*1f6eb021SLiane Praza 	}
5301*1f6eb021SLiane Praza 	if (scf_tmpl_pg_name(pt->prt_t, &t_pg_name) == -1) {
5302*1f6eb021SLiane Praza 		goto cleanup;
5303*1f6eb021SLiane Praza 	}
5304*1f6eb021SLiane Praza 	if (scf_tmpl_pg_type(pt->prt_t, &t_pg_type) == -1) {
5305*1f6eb021SLiane Praza 		goto cleanup;
5306*1f6eb021SLiane Praza 	}
5307*1f6eb021SLiane Praza 	if (scf_tmpl_prop_name(pt, &t_prop_name) == -1) {
5308*1f6eb021SLiane Praza 		goto cleanup;
5309*1f6eb021SLiane Praza 	}
5310*1f6eb021SLiane Praza 	t_prop_type = _scf_read_tmpl_prop_type_as_string(pt);
5311*1f6eb021SLiane Praza 	if (t_prop_type != NULL && t_prop_type[0] == '\0') {
5312*1f6eb021SLiane Praza 		free(t_prop_type);
5313*1f6eb021SLiane Praza 		t_prop_type = NULL;
5314*1f6eb021SLiane Praza 	} else if (t_prop_type == NULL) {
5315*1f6eb021SLiane Praza 		goto cleanup;
5316*1f6eb021SLiane Praza 	}
5317*1f6eb021SLiane Praza 	if (t_prop_type == NULL)
5318*1f6eb021SLiane Praza 		if ((t_prop_type = strdup(SCF_TMPL_WILDCARD)) == NULL) {
5319*1f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
5320*1f6eb021SLiane Praza 			goto cleanup;
5321*1f6eb021SLiane Praza 		}
5322*1f6eb021SLiane Praza 	if (min == NULL) {
5323*1f6eb021SLiane Praza 		if ((s_min = strdup("")) == NULL) {
5324*1f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
5325*1f6eb021SLiane Praza 			goto cleanup;
5326*1f6eb021SLiane Praza 		}
5327*1f6eb021SLiane Praza 	} else {
5328*1f6eb021SLiane Praza 		if ((s_min = _val_to_string(*min, 0)) == NULL) {
5329*1f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
5330*1f6eb021SLiane Praza 			goto cleanup;
5331*1f6eb021SLiane Praza 		}
5332*1f6eb021SLiane Praza 	}
5333*1f6eb021SLiane Praza 	if (max == NULL) {
5334*1f6eb021SLiane Praza 		if ((s_max = strdup("")) == NULL) {
5335*1f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
5336*1f6eb021SLiane Praza 			goto cleanup;
5337*1f6eb021SLiane Praza 		}
5338*1f6eb021SLiane Praza 	} else {
5339*1f6eb021SLiane Praza 		if ((s_max = _val_to_string(*max, 0)) == NULL) {
5340*1f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
5341*1f6eb021SLiane Praza 			goto cleanup;
5342*1f6eb021SLiane Praza 		}
5343*1f6eb021SLiane Praza 	}
5344*1f6eb021SLiane Praza 	if ((num = _val_to_string(count, 0)) == NULL) {
5345*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
5346*1f6eb021SLiane Praza 		goto cleanup;
5347*1f6eb021SLiane Praza 	}
5348*1f6eb021SLiane Praza 
5349*1f6eb021SLiane Praza 	return (_scf_tmpl_add_error(errs, type, pg_name, prop_name, s_min,
5350*1f6eb021SLiane Praza 	    s_max, num, t_fmri, t_pg_name, t_pg_type, t_prop_name,
5351*1f6eb021SLiane Praza 	    t_prop_type));
5352*1f6eb021SLiane Praza cleanup:
5353*1f6eb021SLiane Praza 	free(pg_name);
5354*1f6eb021SLiane Praza 	free(prop_name);
5355*1f6eb021SLiane Praza 	free(s_min);
5356*1f6eb021SLiane Praza 	free(s_max);
5357*1f6eb021SLiane Praza 	free(num);
5358*1f6eb021SLiane Praza 	free(t_fmri);
5359*1f6eb021SLiane Praza 	free(t_pg_name);
5360*1f6eb021SLiane Praza 	free(t_pg_type);
5361*1f6eb021SLiane Praza 	free(t_prop_name);
5362*1f6eb021SLiane Praza 	free(t_prop_type);
5363*1f6eb021SLiane Praza 	return (-1);
5364*1f6eb021SLiane Praza }
5365*1f6eb021SLiane Praza 
5366*1f6eb021SLiane Praza /*
5367*1f6eb021SLiane Praza  * return 0 on success, -1 on failure.
5368*1f6eb021SLiane Praza  * set scf_error() to:
5369*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
5370*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
5371*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
5372*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
5373*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
5374*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
5375*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
5376*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
5377*1f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
5378*1f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
5379*1f6eb021SLiane Praza  */
5380*1f6eb021SLiane Praza static int
5381*1f6eb021SLiane Praza _add_tmpl_constraint_error(scf_tmpl_errors_t *errs, scf_tmpl_error_type_t type,
5382*1f6eb021SLiane Praza     scf_propertygroup_t *pg, const scf_prop_tmpl_t *pt, scf_property_t *prop,
5383*1f6eb021SLiane Praza     scf_value_t *val)
5384*1f6eb021SLiane Praza {
5385*1f6eb021SLiane Praza 	scf_type_t val_type;
5386*1f6eb021SLiane Praza 	char *pg_name = NULL;
5387*1f6eb021SLiane Praza 	char *prop_name = NULL;
5388*1f6eb021SLiane Praza 	char *value = NULL;
5389*1f6eb021SLiane Praza 	char *t_fmri = NULL;
5390*1f6eb021SLiane Praza 	char *t_pg_name = NULL;
5391*1f6eb021SLiane Praza 	char *t_pg_type = NULL;
5392*1f6eb021SLiane Praza 	char *t_prop_name = NULL;
5393*1f6eb021SLiane Praza 	char *t_prop_type = NULL;
5394*1f6eb021SLiane Praza 
5395*1f6eb021SLiane Praza 	if ((t_fmri = _scf_tmpl_get_fmri(pt->prt_t)) == NULL)
5396*1f6eb021SLiane Praza 		return (-1);
5397*1f6eb021SLiane Praza 	switch (type) {
5398*1f6eb021SLiane Praza 	case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
5399*1f6eb021SLiane Praza 		if ((pg_name = _scf_get_pg_name(pg)) == NULL)
5400*1f6eb021SLiane Praza 			goto cleanup;
5401*1f6eb021SLiane Praza 		if ((prop_name = _scf_get_prop_name(prop)) == NULL)
5402*1f6eb021SLiane Praza 			goto cleanup;
5403*1f6eb021SLiane Praza 		/*FALLTHROUGH*/
5404*1f6eb021SLiane Praza 	case SCF_TERR_INVALID_VALUE:
5405*1f6eb021SLiane Praza 		/* keep pg_name = NULL and prop_name = NULL */
5406*1f6eb021SLiane Praza 		if ((value = _scf_value_get_as_string(val)) == NULL)
5407*1f6eb021SLiane Praza 			goto cleanup;
5408*1f6eb021SLiane Praza 		break;
5409*1f6eb021SLiane Praza 	case SCF_TERR_PROP_TYPE_MISMATCH:
5410*1f6eb021SLiane Praza 		/* keep pg_name = NULL and prop_name = NULL */
5411*1f6eb021SLiane Praza 		/* use value for value type */
5412*1f6eb021SLiane Praza 		val_type = scf_value_type(val);
5413*1f6eb021SLiane Praza 		if ((value = strdup(scf_type_to_string(val_type))) ==
5414*1f6eb021SLiane Praza 		    NULL) {
5415*1f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
5416*1f6eb021SLiane Praza 			goto cleanup;
5417*1f6eb021SLiane Praza 		}
5418*1f6eb021SLiane Praza 		break;
5419*1f6eb021SLiane Praza 	}
5420*1f6eb021SLiane Praza 	if (scf_tmpl_pg_name(pt->prt_t, &t_pg_name) == -1) {
5421*1f6eb021SLiane Praza 		goto cleanup;
5422*1f6eb021SLiane Praza 	}
5423*1f6eb021SLiane Praza 	if (scf_tmpl_pg_type(pt->prt_t, &t_pg_type) == -1) {
5424*1f6eb021SLiane Praza 		goto cleanup;
5425*1f6eb021SLiane Praza 	}
5426*1f6eb021SLiane Praza 	if (scf_tmpl_prop_name(pt, &t_prop_name) == -1) {
5427*1f6eb021SLiane Praza 		goto cleanup;
5428*1f6eb021SLiane Praza 	}
5429*1f6eb021SLiane Praza 	t_prop_type = _scf_read_tmpl_prop_type_as_string(pt);
5430*1f6eb021SLiane Praza 	if (t_prop_type != NULL && t_prop_type[0] == '\0') {
5431*1f6eb021SLiane Praza 		free(t_prop_type);
5432*1f6eb021SLiane Praza 		t_prop_type = NULL;
5433*1f6eb021SLiane Praza 	} else if (t_prop_type == NULL) {
5434*1f6eb021SLiane Praza 		goto cleanup;
5435*1f6eb021SLiane Praza 	}
5436*1f6eb021SLiane Praza 	if (t_prop_type == NULL)
5437*1f6eb021SLiane Praza 		if ((t_prop_type = strdup(SCF_TMPL_WILDCARD)) == NULL) {
5438*1f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
5439*1f6eb021SLiane Praza 			goto cleanup;
5440*1f6eb021SLiane Praza 		}
5441*1f6eb021SLiane Praza 
5442*1f6eb021SLiane Praza 	return (_scf_tmpl_add_error(errs, type, pg_name, prop_name, NULL, NULL,
5443*1f6eb021SLiane Praza 	    value, t_fmri, t_pg_name, t_pg_type, t_prop_name, t_prop_type));
5444*1f6eb021SLiane Praza cleanup:
5445*1f6eb021SLiane Praza 	assert(scf_error() != SCF_ERROR_NOT_SET);
5446*1f6eb021SLiane Praza 	free(pg_name);
5447*1f6eb021SLiane Praza 	free(prop_name);
5448*1f6eb021SLiane Praza 	free(value);
5449*1f6eb021SLiane Praza 	free(t_fmri);
5450*1f6eb021SLiane Praza 	free(t_pg_name);
5451*1f6eb021SLiane Praza 	free(t_pg_type);
5452*1f6eb021SLiane Praza 	free(t_prop_name);
5453*1f6eb021SLiane Praza 	free(t_prop_type);
5454*1f6eb021SLiane Praza 	return (-1);
5455*1f6eb021SLiane Praza }
5456*1f6eb021SLiane Praza 
5457*1f6eb021SLiane Praza /*
5458*1f6eb021SLiane Praza  * return 0 on success, -1 on failure.
5459*1f6eb021SLiane Praza  * set scf_error() to:
5460*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
5461*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
5462*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
5463*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
5464*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
5465*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
5466*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
5467*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
5468*1f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
5469*1f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
5470*1f6eb021SLiane Praza  */
5471*1f6eb021SLiane Praza static int
5472*1f6eb021SLiane Praza _add_tmpl_int_error(scf_tmpl_errors_t *errs, scf_tmpl_error_type_t type,
5473*1f6eb021SLiane Praza     scf_propertygroup_t *pg, const scf_prop_tmpl_t *pt, scf_property_t *prop,
5474*1f6eb021SLiane Praza     int64_t val, int64_t *min, int64_t *max)
5475*1f6eb021SLiane Praza {
5476*1f6eb021SLiane Praza 	char *pg_name = NULL;
5477*1f6eb021SLiane Praza 	char *prop_name = NULL;
5478*1f6eb021SLiane Praza 	char *s_min = NULL;
5479*1f6eb021SLiane Praza 	char *s_max = NULL;
5480*1f6eb021SLiane Praza 	char *value = NULL;
5481*1f6eb021SLiane Praza 	char *t_fmri = NULL;
5482*1f6eb021SLiane Praza 	char *t_pg_name = NULL;
5483*1f6eb021SLiane Praza 	char *t_pg_type = NULL;
5484*1f6eb021SLiane Praza 	char *t_prop_name = NULL;
5485*1f6eb021SLiane Praza 	char *t_prop_type = NULL;
5486*1f6eb021SLiane Praza 
5487*1f6eb021SLiane Praza 	if ((t_fmri = _scf_tmpl_get_fmri(pt->prt_t)) == NULL)
5488*1f6eb021SLiane Praza 		return (-1);
5489*1f6eb021SLiane Praza 
5490*1f6eb021SLiane Praza 	switch (type) {
5491*1f6eb021SLiane Praza 	case SCF_TERR_RANGE_VIOLATION:
5492*1f6eb021SLiane Praza 		if ((pg_name = _scf_get_pg_name(pg)) == NULL)
5493*1f6eb021SLiane Praza 			goto cleanup;
5494*1f6eb021SLiane Praza 		if ((prop_name = _scf_get_prop_name(prop)) == NULL)
5495*1f6eb021SLiane Praza 			goto cleanup;
5496*1f6eb021SLiane Praza 		break;
5497*1f6eb021SLiane Praza 	case SCF_TERR_VALUE_OUT_OF_RANGE:
5498*1f6eb021SLiane Praza 		/* keep pg_name = NULL and prop_name = NULL */
5499*1f6eb021SLiane Praza 		break;
5500*1f6eb021SLiane Praza 	}
5501*1f6eb021SLiane Praza 	if (scf_tmpl_pg_name(pt->prt_t, &t_pg_name) == -1) {
5502*1f6eb021SLiane Praza 		goto cleanup;
5503*1f6eb021SLiane Praza 	}
5504*1f6eb021SLiane Praza 	if (scf_tmpl_pg_type(pt->prt_t, &t_pg_type) == -1) {
5505*1f6eb021SLiane Praza 		goto cleanup;
5506*1f6eb021SLiane Praza 	}
5507*1f6eb021SLiane Praza 	if (scf_tmpl_prop_name(pt, &t_prop_name) == -1) {
5508*1f6eb021SLiane Praza 		goto cleanup;
5509*1f6eb021SLiane Praza 	}
5510*1f6eb021SLiane Praza 	t_prop_type = _scf_read_tmpl_prop_type_as_string(pt);
5511*1f6eb021SLiane Praza 	if (t_prop_type != NULL && t_prop_type[0] == '\0') {
5512*1f6eb021SLiane Praza 		free(t_prop_type);
5513*1f6eb021SLiane Praza 		t_prop_type = NULL;
5514*1f6eb021SLiane Praza 	} else if (t_prop_type == NULL) {
5515*1f6eb021SLiane Praza 		goto cleanup;
5516*1f6eb021SLiane Praza 	}
5517*1f6eb021SLiane Praza 	if (t_prop_type == NULL)
5518*1f6eb021SLiane Praza 		if ((t_prop_type = strdup(SCF_TMPL_WILDCARD)) == NULL) {
5519*1f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
5520*1f6eb021SLiane Praza 			goto cleanup;
5521*1f6eb021SLiane Praza 		}
5522*1f6eb021SLiane Praza 	if (min == NULL) {
5523*1f6eb021SLiane Praza 		if ((s_min = strdup("")) == NULL) {
5524*1f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
5525*1f6eb021SLiane Praza 			goto cleanup;
5526*1f6eb021SLiane Praza 		}
5527*1f6eb021SLiane Praza 	} else {
5528*1f6eb021SLiane Praza 		if ((s_min = _val_to_string(*((uint64_t *)min), 1)) == NULL) {
5529*1f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
5530*1f6eb021SLiane Praza 			goto cleanup;
5531*1f6eb021SLiane Praza 		}
5532*1f6eb021SLiane Praza 	}
5533*1f6eb021SLiane Praza 	if (max == NULL) {
5534*1f6eb021SLiane Praza 		if ((s_max = strdup("")) == NULL) {
5535*1f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
5536*1f6eb021SLiane Praza 			goto cleanup;
5537*1f6eb021SLiane Praza 		}
5538*1f6eb021SLiane Praza 	} else {
5539*1f6eb021SLiane Praza 		if ((s_max = _val_to_string(*((uint64_t *)max), 1)) == NULL) {
5540*1f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
5541*1f6eb021SLiane Praza 			goto cleanup;
5542*1f6eb021SLiane Praza 		}
5543*1f6eb021SLiane Praza 	}
5544*1f6eb021SLiane Praza 	if ((value = _val_to_string((uint64_t)val, 1)) == NULL) {
5545*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
5546*1f6eb021SLiane Praza 		goto cleanup;
5547*1f6eb021SLiane Praza 	}
5548*1f6eb021SLiane Praza 
5549*1f6eb021SLiane Praza 	return (_scf_tmpl_add_error(errs, type, pg_name, prop_name, s_min,
5550*1f6eb021SLiane Praza 	    s_max, value, t_fmri, t_pg_name, t_pg_type, t_prop_name,
5551*1f6eb021SLiane Praza 	    t_prop_type));
5552*1f6eb021SLiane Praza cleanup:
5553*1f6eb021SLiane Praza 	free(pg_name);
5554*1f6eb021SLiane Praza 	free(prop_name);
5555*1f6eb021SLiane Praza 	free(s_min);
5556*1f6eb021SLiane Praza 	free(s_max);
5557*1f6eb021SLiane Praza 	free(value);
5558*1f6eb021SLiane Praza 	free(t_fmri);
5559*1f6eb021SLiane Praza 	free(t_pg_name);
5560*1f6eb021SLiane Praza 	free(t_pg_type);
5561*1f6eb021SLiane Praza 	free(t_prop_name);
5562*1f6eb021SLiane Praza 	free(t_prop_type);
5563*1f6eb021SLiane Praza 	return (-1);
5564*1f6eb021SLiane Praza }
5565*1f6eb021SLiane Praza 
5566*1f6eb021SLiane Praza /*
5567*1f6eb021SLiane Praza  * return 0 on success, -1 on failure.
5568*1f6eb021SLiane Praza  * set scf_error() to:
5569*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
5570*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
5571*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
5572*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
5573*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
5574*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
5575*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
5576*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
5577*1f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
5578*1f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
5579*1f6eb021SLiane Praza  */
5580*1f6eb021SLiane Praza static int
5581*1f6eb021SLiane Praza _add_tmpl_pg_redefine_error(scf_tmpl_errors_t *errs, scf_pg_tmpl_t *t,
5582*1f6eb021SLiane Praza     scf_pg_tmpl_t *r)
5583*1f6eb021SLiane Praza {
5584*1f6eb021SLiane Praza 	char *ev1 = NULL;
5585*1f6eb021SLiane Praza 	char *ev2 = NULL;
5586*1f6eb021SLiane Praza 	char *t_fmri = NULL;
5587*1f6eb021SLiane Praza 	char *t_pg_name = NULL;
5588*1f6eb021SLiane Praza 	char *t_pg_type = NULL;
5589*1f6eb021SLiane Praza 
5590*1f6eb021SLiane Praza 	if ((t_fmri = _scf_tmpl_get_fmri(r)) == NULL)
5591*1f6eb021SLiane Praza 		return (-1);
5592*1f6eb021SLiane Praza 	if (scf_tmpl_pg_name(r, &t_pg_name) == -1) {
5593*1f6eb021SLiane Praza 		goto cleanup;
5594*1f6eb021SLiane Praza 	}
5595*1f6eb021SLiane Praza 	if (scf_tmpl_pg_type(r, &t_pg_type) == -1) {
5596*1f6eb021SLiane Praza 		goto cleanup;
5597*1f6eb021SLiane Praza 	}
5598*1f6eb021SLiane Praza 	if (scf_tmpl_pg_name(t, &ev1) == -1) {
5599*1f6eb021SLiane Praza 		goto cleanup;
5600*1f6eb021SLiane Praza 	}
5601*1f6eb021SLiane Praza 	if (scf_tmpl_pg_type(t, &ev2) == -1) {
5602*1f6eb021SLiane Praza 		goto cleanup;
5603*1f6eb021SLiane Praza 	}
5604*1f6eb021SLiane Praza 
5605*1f6eb021SLiane Praza 	return (_scf_tmpl_add_error(errs, SCF_TERR_PG_REDEFINE, NULL, NULL,
5606*1f6eb021SLiane Praza 	    ev1, ev2, NULL, t_fmri, t_pg_name, t_pg_type, NULL, NULL));
5607*1f6eb021SLiane Praza cleanup:
5608*1f6eb021SLiane Praza 	free(ev1);
5609*1f6eb021SLiane Praza 	free(ev2);
5610*1f6eb021SLiane Praza 	free(t_fmri);
5611*1f6eb021SLiane Praza 	free(t_pg_name);
5612*1f6eb021SLiane Praza 	free(t_pg_type);
5613*1f6eb021SLiane Praza 	return (-1);
5614*1f6eb021SLiane Praza }
5615*1f6eb021SLiane Praza 
5616*1f6eb021SLiane Praza /*
5617*1f6eb021SLiane Praza  * return 0 if value is within count ranges constraint.
5618*1f6eb021SLiane Praza  * return -1 otherwise
5619*1f6eb021SLiane Praza  */
5620*1f6eb021SLiane Praza static int
5621*1f6eb021SLiane Praza _check_count_ranges(scf_count_ranges_t *cr, uint64_t v)
5622*1f6eb021SLiane Praza {
5623*1f6eb021SLiane Praza 	int i;
5624*1f6eb021SLiane Praza 
5625*1f6eb021SLiane Praza 	for (i = 0; i < cr->scr_num_ranges; ++i) {
5626*1f6eb021SLiane Praza 		if (v >= cr->scr_min[i] &&
5627*1f6eb021SLiane Praza 		    v <= cr->scr_max[i]) {
5628*1f6eb021SLiane Praza 			/* value is within ranges constraint */
5629*1f6eb021SLiane Praza 			return (0);
5630*1f6eb021SLiane Praza 		}
5631*1f6eb021SLiane Praza 	}
5632*1f6eb021SLiane Praza 	return (-1);
5633*1f6eb021SLiane Praza }
5634*1f6eb021SLiane Praza 
5635*1f6eb021SLiane Praza /*
5636*1f6eb021SLiane Praza  * return 0 if value is within count ranges constraint.
5637*1f6eb021SLiane Praza  * return -1 otherwise
5638*1f6eb021SLiane Praza  */
5639*1f6eb021SLiane Praza static int
5640*1f6eb021SLiane Praza _check_int_ranges(scf_int_ranges_t *ir, int64_t v)
5641*1f6eb021SLiane Praza {
5642*1f6eb021SLiane Praza 	int i;
5643*1f6eb021SLiane Praza 
5644*1f6eb021SLiane Praza 	for (i = 0; i < ir->sir_num_ranges; ++i) {
5645*1f6eb021SLiane Praza 		if (v >= ir->sir_min[i] &&
5646*1f6eb021SLiane Praza 		    v <= ir->sir_max[i]) {
5647*1f6eb021SLiane Praza 			/* value is within integer ranges constraint */
5648*1f6eb021SLiane Praza 			return (0);
5649*1f6eb021SLiane Praza 		}
5650*1f6eb021SLiane Praza 	}
5651*1f6eb021SLiane Praza 	return (-1);
5652*1f6eb021SLiane Praza }
5653*1f6eb021SLiane Praza 
5654*1f6eb021SLiane Praza /*
5655*1f6eb021SLiane Praza  * int _value_in_constraint()
5656*1f6eb021SLiane Praza  *
5657*1f6eb021SLiane Praza  * Checks whether the supplied value violates any of the constraints
5658*1f6eb021SLiane Praza  * specified in the supplied property template.  If it does, an appropriate
5659*1f6eb021SLiane Praza  * error is appended to "errs".  pg and prop, if supplied, are used to
5660*1f6eb021SLiane Praza  * augment the information in the error.  Returns 0 on success.
5661*1f6eb021SLiane Praza  *
5662*1f6eb021SLiane Praza  * Returns -1 on failure.  Sets scf_error():
5663*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
5664*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
5665*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
5666*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
5667*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
5668*1f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
5669*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
5670*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
5671*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
5672*1f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
5673*1f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
5674*1f6eb021SLiane Praza  */
5675*1f6eb021SLiane Praza static int
5676*1f6eb021SLiane Praza _value_in_constraint(scf_propertygroup_t *pg, scf_property_t *prop,
5677*1f6eb021SLiane Praza     const scf_prop_tmpl_t *pt, scf_value_t *value, scf_tmpl_errors_t *errs)
5678*1f6eb021SLiane Praza {
5679*1f6eb021SLiane Praza 	scf_type_t type, tmpl_type;
5680*1f6eb021SLiane Praza 	scf_values_t vals;
5681*1f6eb021SLiane Praza 	scf_tmpl_error_type_t terr_type;
5682*1f6eb021SLiane Praza 	uint64_t v_count;
5683*1f6eb021SLiane Praza 	int64_t v_int;
5684*1f6eb021SLiane Praza 	char *vstr;
5685*1f6eb021SLiane Praza 	ssize_t sz = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH) + 1;
5686*1f6eb021SLiane Praza 	ssize_t ret = 0;
5687*1f6eb021SLiane Praza 	char **constraints;
5688*1f6eb021SLiane Praza 	int n = 0;
5689*1f6eb021SLiane Praza 	int r;
5690*1f6eb021SLiane Praza 	int err_flag = 0;
5691*1f6eb021SLiane Praza 	scf_count_ranges_t cr;
5692*1f6eb021SLiane Praza 	scf_int_ranges_t ir;
5693*1f6eb021SLiane Praza 
5694*1f6eb021SLiane Praza 	type = scf_value_type(value);
5695*1f6eb021SLiane Praza 	if (type == SCF_TYPE_INVALID) {
5696*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
5697*1f6eb021SLiane Praza 		return (-1);
5698*1f6eb021SLiane Praza 	}
5699*1f6eb021SLiane Praza 
5700*1f6eb021SLiane Praza 	/* Check if template type matches value type. */
5701*1f6eb021SLiane Praza 	if (scf_tmpl_prop_type(pt, &tmpl_type) == -1) {
5702*1f6eb021SLiane Praza 		if (scf_error() != SCF_ERROR_NOT_FOUND)
5703*1f6eb021SLiane Praza 			/* type is not wildcarded */
5704*1f6eb021SLiane Praza 			return (-1);
5705*1f6eb021SLiane Praza 	} else if (tmpl_type != type) {
5706*1f6eb021SLiane Praza 		if (errs != NULL) {
5707*1f6eb021SLiane Praza 			if (pg == NULL && prop == NULL) {
5708*1f6eb021SLiane Praza 				if (_add_tmpl_constraint_error(errs,
5709*1f6eb021SLiane Praza 				    SCF_TERR_PROP_TYPE_MISMATCH, NULL, pt,
5710*1f6eb021SLiane Praza 				    NULL, value) == -1)
5711*1f6eb021SLiane Praza 					return (-1);
5712*1f6eb021SLiane Praza 			} else {
5713*1f6eb021SLiane Praza 				if (_add_tmpl_wrong_prop_type_error(errs, pg,
5714*1f6eb021SLiane Praza 				    pt, prop) == -1)
5715*1f6eb021SLiane Praza 					return (-1);
5716*1f6eb021SLiane Praza 			}
5717*1f6eb021SLiane Praza 		}
5718*1f6eb021SLiane Praza 		return (1);
5719*1f6eb021SLiane Praza 	}
5720*1f6eb021SLiane Praza 
5721*1f6eb021SLiane Praza 	/* Numeric values should be checked against any range constraints. */
5722*1f6eb021SLiane Praza 	switch (type) {
5723*1f6eb021SLiane Praza 	case SCF_TYPE_COUNT:
5724*1f6eb021SLiane Praza 		r = scf_value_get_count(value, &v_count);
5725*1f6eb021SLiane Praza 		assert(r == 0);
5726*1f6eb021SLiane Praza 
5727*1f6eb021SLiane Praza 		if (scf_tmpl_value_count_range_constraints(pt, &cr) != 0) {
5728*1f6eb021SLiane Praza 			if (scf_error() == SCF_ERROR_NOT_FOUND)
5729*1f6eb021SLiane Praza 				break;
5730*1f6eb021SLiane Praza 			if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED)
5731*1f6eb021SLiane Praza 				(void) scf_set_error(
5732*1f6eb021SLiane Praza 				    SCF_ERROR_TEMPLATE_INVALID);
5733*1f6eb021SLiane Praza 			return (-1);
5734*1f6eb021SLiane Praza 		} else {
5735*1f6eb021SLiane Praza 			if (_check_count_ranges(&cr, v_count) == 0) {
5736*1f6eb021SLiane Praza 				/* value is within ranges constraint */
5737*1f6eb021SLiane Praza 				scf_count_ranges_destroy(&cr);
5738*1f6eb021SLiane Praza 				return (0);
5739*1f6eb021SLiane Praza 			}
5740*1f6eb021SLiane Praza 			scf_count_ranges_destroy(&cr);
5741*1f6eb021SLiane Praza 		}
5742*1f6eb021SLiane Praza 
5743*1f6eb021SLiane Praza 		/*
5744*1f6eb021SLiane Praza 		 * If we get here, we have a possible constraint
5745*1f6eb021SLiane Praza 		 * violation.
5746*1f6eb021SLiane Praza 		 */
5747*1f6eb021SLiane Praza 		err_flag |= 0x1; /* RANGE_VIOLATION, count */
5748*1f6eb021SLiane Praza 		break;
5749*1f6eb021SLiane Praza 	case SCF_TYPE_INTEGER:
5750*1f6eb021SLiane Praza 		if (scf_value_get_integer(value, &v_int) != 0)
5751*1f6eb021SLiane Praza 			assert(0);
5752*1f6eb021SLiane Praza 		if (scf_tmpl_value_int_range_constraints(pt, &ir) != 0) {
5753*1f6eb021SLiane Praza 			if (scf_error() == SCF_ERROR_NOT_FOUND)
5754*1f6eb021SLiane Praza 				break;
5755*1f6eb021SLiane Praza 			if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED)
5756*1f6eb021SLiane Praza 				(void) scf_set_error(
5757*1f6eb021SLiane Praza 				    SCF_ERROR_TEMPLATE_INVALID);
5758*1f6eb021SLiane Praza 			return (-1);
5759*1f6eb021SLiane Praza 		} else {
5760*1f6eb021SLiane Praza 			if (_check_int_ranges(&ir, v_int) == 0) {
5761*1f6eb021SLiane Praza 				/* value is within ranges constraint */
5762*1f6eb021SLiane Praza 				scf_int_ranges_destroy(&ir);
5763*1f6eb021SLiane Praza 				return (0);
5764*1f6eb021SLiane Praza 			}
5765*1f6eb021SLiane Praza 			scf_int_ranges_destroy(&ir);
5766*1f6eb021SLiane Praza 		}
5767*1f6eb021SLiane Praza 		/*
5768*1f6eb021SLiane Praza 		 * If we get here, we have a possible constraint
5769*1f6eb021SLiane Praza 		 * violation.
5770*1f6eb021SLiane Praza 		 */
5771*1f6eb021SLiane Praza 		err_flag |= 0x2; /* RANGE_VIOLATION, integer */
5772*1f6eb021SLiane Praza 		break;
5773*1f6eb021SLiane Praza 	default:
5774*1f6eb021SLiane Praza 		break;
5775*1f6eb021SLiane Praza 	}
5776*1f6eb021SLiane Praza 
5777*1f6eb021SLiane Praza 	vstr = malloc(sz);
5778*1f6eb021SLiane Praza 	if (vstr == NULL) {
5779*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
5780*1f6eb021SLiane Praza 		return (-1);
5781*1f6eb021SLiane Praza 	}
5782*1f6eb021SLiane Praza 
5783*1f6eb021SLiane Praza 	/*
5784*1f6eb021SLiane Praza 	 * If a set of names is provided, confirm value has one of
5785*1f6eb021SLiane Praza 	 * those names.
5786*1f6eb021SLiane Praza 	 */
5787*1f6eb021SLiane Praza 	if (scf_tmpl_value_name_constraints(pt, &vals) != 0) {
5788*1f6eb021SLiane Praza 		free(vstr);
5789*1f6eb021SLiane Praza 		if (scf_error() != SCF_ERROR_NOT_FOUND) {
5790*1f6eb021SLiane Praza 			return (-1);
5791*1f6eb021SLiane Praza 		}
5792*1f6eb021SLiane Praza 	} else {
5793*1f6eb021SLiane Praza 		r = scf_value_get_as_string_typed(value, type, vstr, sz);
5794*1f6eb021SLiane Praza 
5795*1f6eb021SLiane Praza 		/*
5796*1f6eb021SLiane Praza 		 * All errors (INVALID_ARGUMENT, NOT_SET, TYPE_MISMATCH)
5797*1f6eb021SLiane Praza 		 * should be impossible or already caught above.
5798*1f6eb021SLiane Praza 		 */
5799*1f6eb021SLiane Praza 		assert(r > 0);
5800*1f6eb021SLiane Praza 
5801*1f6eb021SLiane Praza 		constraints = vals.values.v_astring;
5802*1f6eb021SLiane Praza 		for (n = 0; constraints[n] != NULL; ++n) {
5803*1f6eb021SLiane Praza 			if (strcmp(constraints[n], vstr) == 0) {
5804*1f6eb021SLiane Praza 				/* value is within constraint */
5805*1f6eb021SLiane Praza 				scf_values_destroy(&vals);
5806*1f6eb021SLiane Praza 				free(vstr);
5807*1f6eb021SLiane Praza 				return (0);
5808*1f6eb021SLiane Praza 			}
5809*1f6eb021SLiane Praza 		}
5810*1f6eb021SLiane Praza 		/* if we get here, we have a constraint violation */
5811*1f6eb021SLiane Praza 		err_flag |= 0x4; /* CONSTRAINT_VIOLATED */
5812*1f6eb021SLiane Praza 		scf_values_destroy(&vals);
5813*1f6eb021SLiane Praza 		free(vstr);
5814*1f6eb021SLiane Praza 	}
5815*1f6eb021SLiane Praza 	if (err_flag != 0)
5816*1f6eb021SLiane Praza 		ret = 1;
5817*1f6eb021SLiane Praza 	/* register the errors found */
5818*1f6eb021SLiane Praza 	if (ret == 1 && errs != NULL) {
5819*1f6eb021SLiane Praza 		if ((err_flag & 0x1) == 0x1) {
5820*1f6eb021SLiane Praza 			/*
5821*1f6eb021SLiane Praza 			 * Help make the error more human-friendly.  If
5822*1f6eb021SLiane Praza 			 * pg and prop are provided, we know we're
5823*1f6eb021SLiane Praza 			 * validating repository data.  If they're not,
5824*1f6eb021SLiane Praza 			 * we're validating a potentially hypothetical
5825*1f6eb021SLiane Praza 			 * value.
5826*1f6eb021SLiane Praza 			 */
5827*1f6eb021SLiane Praza 			if (pg == NULL && prop == NULL)
5828*1f6eb021SLiane Praza 				terr_type = SCF_TERR_VALUE_OUT_OF_RANGE;
5829*1f6eb021SLiane Praza 			else
5830*1f6eb021SLiane Praza 				terr_type = SCF_TERR_RANGE_VIOLATION;
5831*1f6eb021SLiane Praza 			if (_add_tmpl_count_error(errs, terr_type, pg, pt,
5832*1f6eb021SLiane Praza 			    prop, v_count, 0, 0) == -1)
5833*1f6eb021SLiane Praza 				ret = -1;
5834*1f6eb021SLiane Praza 		}
5835*1f6eb021SLiane Praza 		if ((err_flag & 0x2) == 0x2) {
5836*1f6eb021SLiane Praza 			if (pg == NULL && prop == NULL)
5837*1f6eb021SLiane Praza 				terr_type = SCF_TERR_VALUE_OUT_OF_RANGE;
5838*1f6eb021SLiane Praza 			else
5839*1f6eb021SLiane Praza 				terr_type = SCF_TERR_RANGE_VIOLATION;
5840*1f6eb021SLiane Praza 			if (_add_tmpl_int_error(errs, terr_type, pg, pt, prop,
5841*1f6eb021SLiane Praza 			    v_int, 0, 0) == -1)
5842*1f6eb021SLiane Praza 				ret = -1;
5843*1f6eb021SLiane Praza 		}
5844*1f6eb021SLiane Praza 		if ((err_flag & 0x4) == 0x4) {
5845*1f6eb021SLiane Praza 			if (pg == NULL && prop == NULL)
5846*1f6eb021SLiane Praza 				terr_type = SCF_TERR_INVALID_VALUE;
5847*1f6eb021SLiane Praza 			else
5848*1f6eb021SLiane Praza 				terr_type = SCF_TERR_VALUE_CONSTRAINT_VIOLATED;
5849*1f6eb021SLiane Praza 			if (_add_tmpl_constraint_error(errs, terr_type, pg,
5850*1f6eb021SLiane Praza 			    pt, prop, value) == -1)
5851*1f6eb021SLiane Praza 				ret = -1;
5852*1f6eb021SLiane Praza 		}
5853*1f6eb021SLiane Praza 	}
5854*1f6eb021SLiane Praza 	return (ret);
5855*1f6eb021SLiane Praza }
5856*1f6eb021SLiane Praza 
5857*1f6eb021SLiane Praza /*
5858*1f6eb021SLiane Praza  * Returns -1 on failure.  Sets scf_error():
5859*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
5860*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
5861*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
5862*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
5863*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
5864*1f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
5865*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
5866*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
5867*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
5868*1f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
5869*1f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
5870*1f6eb021SLiane Praza  */
5871*1f6eb021SLiane Praza int
5872*1f6eb021SLiane Praza scf_tmpl_value_in_constraint(const scf_prop_tmpl_t *pt, scf_value_t *value,
5873*1f6eb021SLiane Praza     scf_tmpl_errors_t **errs)
5874*1f6eb021SLiane Praza {
5875*1f6eb021SLiane Praza 	scf_tmpl_errors_t *e = NULL;
5876*1f6eb021SLiane Praza 
5877*1f6eb021SLiane Praza 	if (errs != NULL) {
5878*1f6eb021SLiane Praza 		char *fmri;
5879*1f6eb021SLiane Praza 
5880*1f6eb021SLiane Praza 		if ((fmri = _scf_tmpl_get_fmri(pt->prt_t)) == NULL)
5881*1f6eb021SLiane Praza 			return (-1);
5882*1f6eb021SLiane Praza 		*errs = _scf_create_errors(fmri, 1);
5883*1f6eb021SLiane Praza 		free(fmri);
5884*1f6eb021SLiane Praza 		if (*errs == NULL)
5885*1f6eb021SLiane Praza 			return (-1);
5886*1f6eb021SLiane Praza 		e = *errs;
5887*1f6eb021SLiane Praza 	}
5888*1f6eb021SLiane Praza 
5889*1f6eb021SLiane Praza 	return (_value_in_constraint(NULL, NULL, pt, value, e));
5890*1f6eb021SLiane Praza }
5891*1f6eb021SLiane Praza 
5892*1f6eb021SLiane Praza scf_tmpl_error_t *
5893*1f6eb021SLiane Praza scf_tmpl_next_error(scf_tmpl_errors_t *errs)
5894*1f6eb021SLiane Praza {
5895*1f6eb021SLiane Praza 	if (errs->tes_index < errs->tes_num_errs) {
5896*1f6eb021SLiane Praza 		assert(errs->tes_errs[errs->tes_index] != NULL);
5897*1f6eb021SLiane Praza 		return (errs->tes_errs[errs->tes_index++]);
5898*1f6eb021SLiane Praza 	} else {
5899*1f6eb021SLiane Praza 		return (NULL);
5900*1f6eb021SLiane Praza 	}
5901*1f6eb021SLiane Praza }
5902*1f6eb021SLiane Praza 
5903*1f6eb021SLiane Praza void
5904*1f6eb021SLiane Praza scf_tmpl_reset_errors(scf_tmpl_errors_t *errs)
5905*1f6eb021SLiane Praza {
5906*1f6eb021SLiane Praza 	errs->tes_index = 0;
5907*1f6eb021SLiane Praza }
5908*1f6eb021SLiane Praza 
5909*1f6eb021SLiane Praza int
5910*1f6eb021SLiane Praza scf_tmpl_strerror(scf_tmpl_error_t *err,  char *s, size_t n, int flag)
5911*1f6eb021SLiane Praza {
5912*1f6eb021SLiane Praza 	const char *str;
5913*1f6eb021SLiane Praza 	int i;
5914*1f6eb021SLiane Praza 	int ret = -1;
5915*1f6eb021SLiane Praza 	int nsz = 0;	/* err msg length */
5916*1f6eb021SLiane Praza 	int sz = n;	/* available buffer size */
5917*1f6eb021SLiane Praza 	char *buf = s;	/* where to append in buffer */
5918*1f6eb021SLiane Praza 	char *s0 = (flag == SCF_TMPL_STRERROR_HUMAN) ? ":\n\t" : ": ";
5919*1f6eb021SLiane Praza 	char *s1 = (flag == SCF_TMPL_STRERROR_HUMAN) ? "\n\t" : "; ";
5920*1f6eb021SLiane Praza 	char *sep = s0;
5921*1f6eb021SLiane Praza 	const char *val;
5922*1f6eb021SLiane Praza 
5923*1f6eb021SLiane Praza 	/* prefix */
5924*1f6eb021SLiane Praza 	if (err->te_errs->tes_prefix != NULL) {
5925*1f6eb021SLiane Praza 		ret = snprintf(buf, sz, "%s", dgettext(TEXT_DOMAIN,
5926*1f6eb021SLiane Praza 		    err->te_errs->tes_prefix));
5927*1f6eb021SLiane Praza 		nsz += ret;
5928*1f6eb021SLiane Praza 		sz = (sz - ret) > 0 ? sz - ret : 0;
5929*1f6eb021SLiane Praza 		buf = (sz > 0) ? s + nsz : NULL;
5930*1f6eb021SLiane Praza 	}
5931*1f6eb021SLiane Praza 	/* error message */
5932*1f6eb021SLiane Praza 	ret = snprintf(buf, sz, "%s", dgettext(TEXT_DOMAIN,
5933*1f6eb021SLiane Praza 	    em_desc[err->te_type].em_msg));
5934*1f6eb021SLiane Praza 	nsz += ret;
5935*1f6eb021SLiane Praza 	sz = (sz - ret) > 0 ? sz - ret : 0;
5936*1f6eb021SLiane Praza 	buf = (sz > 0) ? s + nsz : NULL;
5937*1f6eb021SLiane Praza 
5938*1f6eb021SLiane Praza 	for (i = 0; _tmpl_error_items[i].get_desc != NULL; ++i) {
5939*1f6eb021SLiane Praza 		if ((str = _tmpl_error_items[i].get_desc(err)) == NULL)
5940*1f6eb021SLiane Praza 			/* no item to print */
5941*1f6eb021SLiane Praza 			continue;
5942*1f6eb021SLiane Praza 		val = _tmpl_error_items[i].get_val(err);
5943*1f6eb021SLiane Praza 		ret = snprintf(buf, sz, "%s%s=\"%s\"", sep, str,
5944*1f6eb021SLiane Praza 		    (val == NULL) ? "" : val);
5945*1f6eb021SLiane Praza 		nsz += ret;
5946*1f6eb021SLiane Praza 		sz = (sz - ret) > 0 ? sz - ret : 0;
5947*1f6eb021SLiane Praza 		buf = (sz > 0) ? s + nsz : NULL;
5948*1f6eb021SLiane Praza 		sep = s1;
5949*1f6eb021SLiane Praza 	}
5950*1f6eb021SLiane Praza 	return (nsz);
5951*1f6eb021SLiane Praza }
5952*1f6eb021SLiane Praza 
5953*1f6eb021SLiane Praza /*
5954*1f6eb021SLiane Praza  * return 0 on success, -1 on failure.
5955*1f6eb021SLiane Praza  * set scf_error() to:
5956*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
5957*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
5958*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
5959*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
5960*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
5961*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
5962*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
5963*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
5964*1f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
5965*1f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
5966*1f6eb021SLiane Praza  */
5967*1f6eb021SLiane Praza static int
5968*1f6eb021SLiane Praza _validate_cardinality(scf_propertygroup_t *pg, scf_prop_tmpl_t *pt,
5969*1f6eb021SLiane Praza     scf_property_t *prop, scf_tmpl_errors_t *errs)
5970*1f6eb021SLiane Praza {
5971*1f6eb021SLiane Praza 	uint64_t min, max;
5972*1f6eb021SLiane Praza 	scf_handle_t *h;
5973*1f6eb021SLiane Praza 	scf_iter_t *iter = NULL;
5974*1f6eb021SLiane Praza 	scf_value_t *val = NULL;
5975*1f6eb021SLiane Praza 	int count = 0;
5976*1f6eb021SLiane Praza 	int ret = -1;
5977*1f6eb021SLiane Praza 	int r;
5978*1f6eb021SLiane Praza 
5979*1f6eb021SLiane Praza 	if (scf_tmpl_prop_cardinality(pt, &min, &max) != 0) {
5980*1f6eb021SLiane Praza 		if (scf_error() == SCF_ERROR_NOT_FOUND)
5981*1f6eb021SLiane Praza 			return (0);
5982*1f6eb021SLiane Praza 		else
5983*1f6eb021SLiane Praza 			return (-1);
5984*1f6eb021SLiane Praza 	}
5985*1f6eb021SLiane Praza 
5986*1f6eb021SLiane Praza 	/* Any number of values permitted.  Just return success. */
5987*1f6eb021SLiane Praza 	if (min == 0 && max == UINT64_MAX) {
5988*1f6eb021SLiane Praza 		return (0);
5989*1f6eb021SLiane Praza 	}
5990*1f6eb021SLiane Praza 
5991*1f6eb021SLiane Praza 	h = scf_property_handle(prop);
5992*1f6eb021SLiane Praza 	if (h == NULL) {
5993*1f6eb021SLiane Praza 		assert(scf_error() == SCF_ERROR_HANDLE_DESTROYED);
5994*1f6eb021SLiane Praza 		goto cleanup;
5995*1f6eb021SLiane Praza 	}
5996*1f6eb021SLiane Praza 
5997*1f6eb021SLiane Praza 	iter = scf_iter_create(h);
5998*1f6eb021SLiane Praza 	val = scf_value_create(h);
5999*1f6eb021SLiane Praza 	if (iter == NULL || val == NULL) {
6000*1f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
6001*1f6eb021SLiane Praza 			goto cleanup;
6002*1f6eb021SLiane Praza 		} else {
6003*1f6eb021SLiane Praza 			assert(0);
6004*1f6eb021SLiane Praza 			abort();
6005*1f6eb021SLiane Praza 		}
6006*1f6eb021SLiane Praza 	}
6007*1f6eb021SLiane Praza 
6008*1f6eb021SLiane Praza 	if (scf_iter_property_values(iter, prop) != 0) {
6009*1f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
6010*1f6eb021SLiane Praza 			goto cleanup;
6011*1f6eb021SLiane Praza 		} else {
6012*1f6eb021SLiane Praza 			assert(0);
6013*1f6eb021SLiane Praza 			abort();
6014*1f6eb021SLiane Praza 		}
6015*1f6eb021SLiane Praza 	}
6016*1f6eb021SLiane Praza 
6017*1f6eb021SLiane Praza 	while ((r = scf_iter_next_value(iter, val)) == 1)
6018*1f6eb021SLiane Praza 		count++;
6019*1f6eb021SLiane Praza 
6020*1f6eb021SLiane Praza 	if (r < 0) {
6021*1f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
6022*1f6eb021SLiane Praza 			goto cleanup;
6023*1f6eb021SLiane Praza 		} else {
6024*1f6eb021SLiane Praza 			assert(0);
6025*1f6eb021SLiane Praza 			abort();
6026*1f6eb021SLiane Praza 		}
6027*1f6eb021SLiane Praza 	}
6028*1f6eb021SLiane Praza 
6029*1f6eb021SLiane Praza 	if (count < min || count > max)
6030*1f6eb021SLiane Praza 		if (_add_tmpl_count_error(errs, SCF_TERR_CARDINALITY_VIOLATION,
6031*1f6eb021SLiane Praza 		    pg, pt, prop, (uint64_t)count, &min, &max) == -1)
6032*1f6eb021SLiane Praza 			goto cleanup;
6033*1f6eb021SLiane Praza 
6034*1f6eb021SLiane Praza 	ret = 0;
6035*1f6eb021SLiane Praza 
6036*1f6eb021SLiane Praza cleanup:
6037*1f6eb021SLiane Praza 	scf_iter_destroy(iter);
6038*1f6eb021SLiane Praza 	scf_value_destroy(val);
6039*1f6eb021SLiane Praza 	return (ret);
6040*1f6eb021SLiane Praza }
6041*1f6eb021SLiane Praza 
6042*1f6eb021SLiane Praza /*
6043*1f6eb021SLiane Praza  * Returns -1 on error.  Sets scf_error():
6044*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
6045*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
6046*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
6047*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
6048*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
6049*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
6050*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
6051*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
6052*1f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
6053*1f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
6054*1f6eb021SLiane Praza  */
6055*1f6eb021SLiane Praza static int
6056*1f6eb021SLiane Praza _check_property(scf_prop_tmpl_t *pt, scf_propertygroup_t *pg,
6057*1f6eb021SLiane Praza     scf_property_t *prop, scf_tmpl_errors_t *errs)
6058*1f6eb021SLiane Praza {
6059*1f6eb021SLiane Praza 	scf_type_t tmpl_type;
6060*1f6eb021SLiane Praza 	uint8_t required;
6061*1f6eb021SLiane Praza 	scf_handle_t *h;
6062*1f6eb021SLiane Praza 	scf_iter_t *iter = NULL;
6063*1f6eb021SLiane Praza 	scf_value_t *val = NULL;
6064*1f6eb021SLiane Praza 	int r;
6065*1f6eb021SLiane Praza 	int ret = -1;
6066*1f6eb021SLiane Praza 
6067*1f6eb021SLiane Praza 	h = scf_pg_handle(pg);
6068*1f6eb021SLiane Praza 	if (h == NULL) {
6069*1f6eb021SLiane Praza 		assert(scf_error() == SCF_ERROR_HANDLE_DESTROYED);
6070*1f6eb021SLiane Praza 		return (-1);
6071*1f6eb021SLiane Praza 	}
6072*1f6eb021SLiane Praza 
6073*1f6eb021SLiane Praza 	iter = scf_iter_create(h);
6074*1f6eb021SLiane Praza 	val = scf_value_create(h);
6075*1f6eb021SLiane Praza 	if (iter == NULL || val == NULL) {
6076*1f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
6077*1f6eb021SLiane Praza 			scf_iter_destroy(iter);
6078*1f6eb021SLiane Praza 			scf_value_destroy(val);
6079*1f6eb021SLiane Praza 			return (-1);
6080*1f6eb021SLiane Praza 		} else {
6081*1f6eb021SLiane Praza 			assert(0);
6082*1f6eb021SLiane Praza 			abort();
6083*1f6eb021SLiane Praza 		}
6084*1f6eb021SLiane Praza 	}
6085*1f6eb021SLiane Praza 
6086*1f6eb021SLiane Praza 	if (scf_tmpl_prop_required(pt, &required) != 0)
6087*1f6eb021SLiane Praza 		goto cleanup;
6088*1f6eb021SLiane Praza 
6089*1f6eb021SLiane Praza 	/* Check type */
6090*1f6eb021SLiane Praza 	if (scf_tmpl_prop_type(pt, &tmpl_type) == -1) {
6091*1f6eb021SLiane Praza 		if (scf_error() != SCF_ERROR_NOT_FOUND) {
6092*1f6eb021SLiane Praza 			goto cleanup;
6093*1f6eb021SLiane Praza 		} else if (required) {
6094*1f6eb021SLiane Praza 			/* If required, type must be specified. */
6095*1f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
6096*1f6eb021SLiane Praza 			goto cleanup;
6097*1f6eb021SLiane Praza 		}
6098*1f6eb021SLiane Praza 	} else if (scf_property_is_type(prop, tmpl_type) != 0) {
6099*1f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
6100*1f6eb021SLiane Praza 			goto cleanup;
6101*1f6eb021SLiane Praza 		} else switch (scf_error()) {
6102*1f6eb021SLiane Praza 		case SCF_ERROR_TYPE_MISMATCH:
6103*1f6eb021SLiane Praza 			if (_add_tmpl_wrong_prop_type_error(errs, pg, pt,
6104*1f6eb021SLiane Praza 			    prop) == -1)
6105*1f6eb021SLiane Praza 				goto cleanup;
6106*1f6eb021SLiane Praza 			break;
6107*1f6eb021SLiane Praza 
6108*1f6eb021SLiane Praza 		case SCF_ERROR_INVALID_ARGUMENT:
6109*1f6eb021SLiane Praza 			/*
6110*1f6eb021SLiane Praza 			 * tmpl_prop_type shouldn't have handed back
6111*1f6eb021SLiane Praza 			 * an invalid property type.
6112*1f6eb021SLiane Praza 			 */
6113*1f6eb021SLiane Praza 		case SCF_ERROR_NOT_SET:
6114*1f6eb021SLiane Praza 		default:
6115*1f6eb021SLiane Praza 			assert(0);
6116*1f6eb021SLiane Praza 			abort();
6117*1f6eb021SLiane Praza 		}
6118*1f6eb021SLiane Praza 	}
6119*1f6eb021SLiane Praza 
6120*1f6eb021SLiane Praza 
6121*1f6eb021SLiane Praza 	/* Cardinality */
6122*1f6eb021SLiane Praza 	if (_validate_cardinality(pg, pt, prop, errs) == -1)
6123*1f6eb021SLiane Praza 		goto cleanup;
6124*1f6eb021SLiane Praza 
6125*1f6eb021SLiane Praza 	/* Value constraints */
6126*1f6eb021SLiane Praza 	/*
6127*1f6eb021SLiane Praza 	 * Iterate through each value, and confirm it is defined as
6128*1f6eb021SLiane Praza 	 * constrained.
6129*1f6eb021SLiane Praza 	 */
6130*1f6eb021SLiane Praza 	if (scf_iter_property_values(iter, prop) != 0) {
6131*1f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_NOT_SET &&
6132*1f6eb021SLiane Praza 		    scf_error() != SCF_ERROR_HANDLE_MISMATCH);
6133*1f6eb021SLiane Praza 		goto cleanup;
6134*1f6eb021SLiane Praza 	}
6135*1f6eb021SLiane Praza 
6136*1f6eb021SLiane Praza 	while ((r = scf_iter_next_value(iter, val)) == 1) {
6137*1f6eb021SLiane Praza 		if (_value_in_constraint(pg, prop, pt, val, errs) == -1) {
6138*1f6eb021SLiane Praza 			if (ismember(scf_error(), errors_server)) {
6139*1f6eb021SLiane Praza 				goto cleanup;
6140*1f6eb021SLiane Praza 			} else switch (scf_error()) {
6141*1f6eb021SLiane Praza 			case SCF_ERROR_TEMPLATE_INVALID:
6142*1f6eb021SLiane Praza 				goto cleanup;
6143*1f6eb021SLiane Praza 
6144*1f6eb021SLiane Praza 			case SCF_ERROR_INVALID_ARGUMENT:
6145*1f6eb021SLiane Praza 			default:
6146*1f6eb021SLiane Praza 				assert(0);
6147*1f6eb021SLiane Praza 				abort();
6148*1f6eb021SLiane Praza 			}
6149*1f6eb021SLiane Praza 		}
6150*1f6eb021SLiane Praza 	}
6151*1f6eb021SLiane Praza 
6152*1f6eb021SLiane Praza 	if (r < 0) {
6153*1f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
6154*1f6eb021SLiane Praza 			goto cleanup;
6155*1f6eb021SLiane Praza 		} else {
6156*1f6eb021SLiane Praza 			assert(0);
6157*1f6eb021SLiane Praza 			abort();
6158*1f6eb021SLiane Praza 		}
6159*1f6eb021SLiane Praza 	}
6160*1f6eb021SLiane Praza 
6161*1f6eb021SLiane Praza 	ret = 0;
6162*1f6eb021SLiane Praza 
6163*1f6eb021SLiane Praza cleanup:
6164*1f6eb021SLiane Praza 	scf_iter_destroy(iter);
6165*1f6eb021SLiane Praza 	scf_value_destroy(val);
6166*1f6eb021SLiane Praza 	return (ret);
6167*1f6eb021SLiane Praza }
6168*1f6eb021SLiane Praza 
6169*1f6eb021SLiane Praza /*
6170*1f6eb021SLiane Praza  * Returns -1 on failure, sets scf_error() to:
6171*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
6172*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
6173*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
6174*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
6175*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
6176*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
6177*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
6178*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
6179*1f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
6180*1f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
6181*1f6eb021SLiane Praza  */
6182*1f6eb021SLiane Praza static int
6183*1f6eb021SLiane Praza _check_pg(scf_pg_tmpl_t *t, scf_propertygroup_t *pg, char *pg_name,
6184*1f6eb021SLiane Praza     char *type, scf_tmpl_errors_t *errs)
6185*1f6eb021SLiane Praza {
6186*1f6eb021SLiane Praza 	scf_prop_tmpl_t *pt = NULL;
6187*1f6eb021SLiane Praza 	char *pg_type = NULL;
6188*1f6eb021SLiane Praza 	scf_iter_t *iter = NULL;
6189*1f6eb021SLiane Praza 	uint8_t pg_required;
6190*1f6eb021SLiane Praza 	scf_property_t *prop = NULL;
6191*1f6eb021SLiane Praza 	scf_handle_t *h;
6192*1f6eb021SLiane Praza 	int r;
6193*1f6eb021SLiane Praza 	char *prop_name = NULL;
6194*1f6eb021SLiane Praza 	ssize_t nsize = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
6195*1f6eb021SLiane Praza 	int ret = -1;
6196*1f6eb021SLiane Praza 
6197*1f6eb021SLiane Praza 	assert(pg_name != NULL);
6198*1f6eb021SLiane Praza 	assert(t != NULL);
6199*1f6eb021SLiane Praza 	assert(pg != NULL);
6200*1f6eb021SLiane Praza 	assert(type != NULL);
6201*1f6eb021SLiane Praza 	assert(nsize != 0);
6202*1f6eb021SLiane Praza 
6203*1f6eb021SLiane Praza 	if ((h = scf_pg_handle(pg)) == NULL) {
6204*1f6eb021SLiane Praza 		assert(scf_error() == SCF_ERROR_HANDLE_DESTROYED);
6205*1f6eb021SLiane Praza 		return (-1);
6206*1f6eb021SLiane Praza 	}
6207*1f6eb021SLiane Praza 	if ((pt = scf_tmpl_prop_create(h)) == NULL) {
6208*1f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_INVALID_ARGUMENT);
6209*1f6eb021SLiane Praza 		return (-1);
6210*1f6eb021SLiane Praza 	}
6211*1f6eb021SLiane Praza 
6212*1f6eb021SLiane Praza 	if ((prop = scf_property_create(h)) == NULL) {
6213*1f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_INVALID_ARGUMENT);
6214*1f6eb021SLiane Praza 		goto cleanup;
6215*1f6eb021SLiane Praza 	}
6216*1f6eb021SLiane Praza 
6217*1f6eb021SLiane Praza 	if ((iter = scf_iter_create(h)) == NULL) {
6218*1f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_INVALID_ARGUMENT);
6219*1f6eb021SLiane Praza 		goto cleanup;
6220*1f6eb021SLiane Praza 	}
6221*1f6eb021SLiane Praza 	if ((prop_name = malloc(nsize)) == NULL) {
6222*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
6223*1f6eb021SLiane Praza 		goto cleanup;
6224*1f6eb021SLiane Praza 	}
6225*1f6eb021SLiane Praza 
6226*1f6eb021SLiane Praza 	if (scf_tmpl_pg_required(t, &pg_required) != 0)
6227*1f6eb021SLiane Praza 		goto cleanup;
6228*1f6eb021SLiane Praza 
6229*1f6eb021SLiane Praza 	if (scf_tmpl_pg_type(t, &pg_type) == -1) {
6230*1f6eb021SLiane Praza 		goto cleanup;
6231*1f6eb021SLiane Praza 	} else if (pg_required != 0 &&
6232*1f6eb021SLiane Praza 	    strcmp(SCF_TMPL_WILDCARD, pg_type) == 0) {
6233*1f6eb021SLiane Praza 		/* Type must be specified for required pgs. */
6234*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
6235*1f6eb021SLiane Praza 		goto cleanup;
6236*1f6eb021SLiane Praza 	}
6237*1f6eb021SLiane Praza 
6238*1f6eb021SLiane Praza 	if (pg_type != NULL) {
6239*1f6eb021SLiane Praza 		if (strcmp(pg_type, type) != 0 &&
6240*1f6eb021SLiane Praza 		    strcmp(pg_type, SCF_TMPL_WILDCARD) != 0) {
6241*1f6eb021SLiane Praza 			if (_add_tmpl_wrong_pg_type_error(errs, t, pg) == -1)
6242*1f6eb021SLiane Praza 				goto cleanup;
6243*1f6eb021SLiane Praza 		}
6244*1f6eb021SLiane Praza 	}
6245*1f6eb021SLiane Praza 
6246*1f6eb021SLiane Praza 
6247*1f6eb021SLiane Praza 	/* Iterate through properties in the repository and check them. */
6248*1f6eb021SLiane Praza 	if (scf_iter_pg_properties(iter, pg) != 0) {
6249*1f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
6250*1f6eb021SLiane Praza 			goto cleanup;
6251*1f6eb021SLiane Praza 		} else {
6252*1f6eb021SLiane Praza 			assert(0);
6253*1f6eb021SLiane Praza 			abort();
6254*1f6eb021SLiane Praza 		}
6255*1f6eb021SLiane Praza 	}
6256*1f6eb021SLiane Praza 
6257*1f6eb021SLiane Praza 	while ((r = scf_iter_next_property(iter, prop)) == 1) {
6258*1f6eb021SLiane Praza 		if (scf_property_get_name(prop, prop_name, nsize) == -1) {
6259*1f6eb021SLiane Praza 			assert(scf_error() != SCF_ERROR_NOT_SET);
6260*1f6eb021SLiane Praza 			goto cleanup;
6261*1f6eb021SLiane Praza 		}
6262*1f6eb021SLiane Praza 		if (scf_tmpl_get_by_prop(t, prop_name, pt, 0) != 0) {
6263*1f6eb021SLiane Praza 			if (ismember(scf_error(), errors_server)) {
6264*1f6eb021SLiane Praza 				goto cleanup;
6265*1f6eb021SLiane Praza 			} else switch (scf_error()) {
6266*1f6eb021SLiane Praza 			case SCF_ERROR_NOT_FOUND:
6267*1f6eb021SLiane Praza 				/* No template.  Continue. */
6268*1f6eb021SLiane Praza 				continue;
6269*1f6eb021SLiane Praza 
6270*1f6eb021SLiane Praza 			case SCF_ERROR_INVALID_ARGUMENT:
6271*1f6eb021SLiane Praza 			default:
6272*1f6eb021SLiane Praza 				assert(0);
6273*1f6eb021SLiane Praza 				abort();
6274*1f6eb021SLiane Praza 			}
6275*1f6eb021SLiane Praza 		}
6276*1f6eb021SLiane Praza 
6277*1f6eb021SLiane Praza 		if (_check_property(pt, pg, prop, errs) != 0)
6278*1f6eb021SLiane Praza 			goto cleanup;
6279*1f6eb021SLiane Praza 	}
6280*1f6eb021SLiane Praza 
6281*1f6eb021SLiane Praza 	if (r < 0) {
6282*1f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
6283*1f6eb021SLiane Praza 			goto cleanup;
6284*1f6eb021SLiane Praza 		} else {
6285*1f6eb021SLiane Praza 			assert(0);
6286*1f6eb021SLiane Praza 			abort();
6287*1f6eb021SLiane Praza 		}
6288*1f6eb021SLiane Praza 	}
6289*1f6eb021SLiane Praza 
6290*1f6eb021SLiane Praza 	scf_tmpl_prop_reset(pt);
6291*1f6eb021SLiane Praza 	free(prop_name);
6292*1f6eb021SLiane Praza 	prop_name = NULL;
6293*1f6eb021SLiane Praza 	/*
6294*1f6eb021SLiane Praza 	 * Confirm required properties are present.
6295*1f6eb021SLiane Praza 	 */
6296*1f6eb021SLiane Praza 	while ((r = scf_tmpl_iter_props(t, pt,
6297*1f6eb021SLiane Praza 	    SCF_PROP_TMPL_FLAG_REQUIRED)) == 0) {
6298*1f6eb021SLiane Praza 		scf_type_t prop_type;
6299*1f6eb021SLiane Praza 
6300*1f6eb021SLiane Praza 		if (scf_tmpl_prop_name(pt, &prop_name) == -1)
6301*1f6eb021SLiane Praza 			goto cleanup;
6302*1f6eb021SLiane Praza 
6303*1f6eb021SLiane Praza 		/* required properties cannot have type wildcarded */
6304*1f6eb021SLiane Praza 		if (scf_tmpl_prop_type(pt, &prop_type) == -1) {
6305*1f6eb021SLiane Praza 			if (scf_error() == SCF_ERROR_NOT_FOUND)
6306*1f6eb021SLiane Praza 				(void) scf_set_error(
6307*1f6eb021SLiane Praza 				    SCF_ERROR_TEMPLATE_INVALID);
6308*1f6eb021SLiane Praza 			goto cleanup;
6309*1f6eb021SLiane Praza 		}
6310*1f6eb021SLiane Praza 
6311*1f6eb021SLiane Praza 		if (scf_pg_get_property(pg, prop_name, prop) != 0) {
6312*1f6eb021SLiane Praza 			if (ismember(scf_error(), errors_server)) {
6313*1f6eb021SLiane Praza 				goto cleanup;
6314*1f6eb021SLiane Praza 			} else switch (scf_error()) {
6315*1f6eb021SLiane Praza 			case SCF_ERROR_NOT_FOUND:
6316*1f6eb021SLiane Praza 				if (_add_tmpl_missing_prop_error(errs, t, pg,
6317*1f6eb021SLiane Praza 				    pt) == -1)
6318*1f6eb021SLiane Praza 					goto cleanup;
6319*1f6eb021SLiane Praza 				break;
6320*1f6eb021SLiane Praza 
6321*1f6eb021SLiane Praza 			case SCF_ERROR_INVALID_ARGUMENT:
6322*1f6eb021SLiane Praza 				(void) scf_set_error(
6323*1f6eb021SLiane Praza 				    SCF_ERROR_TEMPLATE_INVALID);
6324*1f6eb021SLiane Praza 				goto cleanup;
6325*1f6eb021SLiane Praza 
6326*1f6eb021SLiane Praza 			case SCF_ERROR_HANDLE_MISMATCH:
6327*1f6eb021SLiane Praza 			case SCF_ERROR_NOT_SET:
6328*1f6eb021SLiane Praza 			default:
6329*1f6eb021SLiane Praza 				assert(0);
6330*1f6eb021SLiane Praza 				abort();
6331*1f6eb021SLiane Praza 			}
6332*1f6eb021SLiane Praza 		}
6333*1f6eb021SLiane Praza 		free(prop_name);
6334*1f6eb021SLiane Praza 		prop_name = NULL;
6335*1f6eb021SLiane Praza 	}
6336*1f6eb021SLiane Praza 	if (r < 0) {
6337*1f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
6338*1f6eb021SLiane Praza 			goto cleanup;
6339*1f6eb021SLiane Praza 		} else switch (scf_error()) {
6340*1f6eb021SLiane Praza 		case SCF_ERROR_NOT_FOUND:
6341*1f6eb021SLiane Praza 			break;
6342*1f6eb021SLiane Praza 
6343*1f6eb021SLiane Praza 		case SCF_ERROR_TEMPLATE_INVALID:
6344*1f6eb021SLiane Praza 			goto cleanup;
6345*1f6eb021SLiane Praza 
6346*1f6eb021SLiane Praza 		case SCF_ERROR_INVALID_ARGUMENT:
6347*1f6eb021SLiane Praza 		default:
6348*1f6eb021SLiane Praza 			assert(0);
6349*1f6eb021SLiane Praza 			abort();
6350*1f6eb021SLiane Praza 		}
6351*1f6eb021SLiane Praza 	}
6352*1f6eb021SLiane Praza 
6353*1f6eb021SLiane Praza 	ret = 0;
6354*1f6eb021SLiane Praza cleanup:
6355*1f6eb021SLiane Praza 	scf_tmpl_prop_destroy(pt);
6356*1f6eb021SLiane Praza 	scf_iter_destroy(iter);
6357*1f6eb021SLiane Praza 	scf_property_destroy(prop);
6358*1f6eb021SLiane Praza 	free(prop_name);
6359*1f6eb021SLiane Praza 	free(pg_type);
6360*1f6eb021SLiane Praza 	return (ret);
6361*1f6eb021SLiane Praza }
6362*1f6eb021SLiane Praza 
6363*1f6eb021SLiane Praza /*
6364*1f6eb021SLiane Praza  * Checks if instance fmri redefines any pgs defined in restarter or global
6365*1f6eb021SLiane Praza  * Return -1 on failure, sets scf_error() to:
6366*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
6367*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
6368*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
6369*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
6370*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
6371*1f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
6372*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
6373*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
6374*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
6375*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
6376*1f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
6377*1f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
6378*1f6eb021SLiane Praza  */
6379*1f6eb021SLiane Praza static int
6380*1f6eb021SLiane Praza _scf_tmpl_check_pg_redef(scf_handle_t *h, const char *fmri,
6381*1f6eb021SLiane Praza     const char *snapname, scf_tmpl_errors_t *errs)
6382*1f6eb021SLiane Praza {
6383*1f6eb021SLiane Praza 	scf_pg_tmpl_t *t = NULL;
6384*1f6eb021SLiane Praza 	scf_pg_tmpl_t *r = NULL;
6385*1f6eb021SLiane Praza 	char *pg_name = NULL;
6386*1f6eb021SLiane Praza 	char *pg_name_r = NULL;
6387*1f6eb021SLiane Praza 	char *pg_type = NULL;
6388*1f6eb021SLiane Praza 	char *pg_type_r = NULL;
6389*1f6eb021SLiane Praza 	char *target = NULL;
6390*1f6eb021SLiane Praza 	int ret_val = -1;
6391*1f6eb021SLiane Praza 	int ret;
6392*1f6eb021SLiane Praza 
6393*1f6eb021SLiane Praza 	t = scf_tmpl_pg_create(h);
6394*1f6eb021SLiane Praza 	r = scf_tmpl_pg_create(h);
6395*1f6eb021SLiane Praza 	if (t == NULL || r == NULL)
6396*1f6eb021SLiane Praza 		goto cleanup;
6397*1f6eb021SLiane Praza 
6398*1f6eb021SLiane Praza 	while ((ret = scf_tmpl_iter_pgs(t, fmri, snapname, NULL,
6399*1f6eb021SLiane Praza 	    SCF_PG_TMPL_FLAG_EXACT)) == 1) {
6400*1f6eb021SLiane Praza 		if (scf_tmpl_pg_name(t, &pg_name) == -1) {
6401*1f6eb021SLiane Praza 			goto cleanup;
6402*1f6eb021SLiane Praza 		}
6403*1f6eb021SLiane Praza 		if (scf_tmpl_pg_type(t, &pg_type) == -1) {
6404*1f6eb021SLiane Praza 			goto cleanup;
6405*1f6eb021SLiane Praza 		}
6406*1f6eb021SLiane Praza 		/* look for a redefinition of a global/restarter pg_pattern */
6407*1f6eb021SLiane Praza 		while ((ret = scf_tmpl_iter_pgs(r, fmri, snapname, pg_type,
6408*1f6eb021SLiane Praza 		    0)) == 1) {
6409*1f6eb021SLiane Praza 			if (scf_tmpl_pg_name(r, &pg_name_r) == -1) {
6410*1f6eb021SLiane Praza 				goto cleanup;
6411*1f6eb021SLiane Praza 			} else if (strcmp(pg_name_r, SCF_TMPL_WILDCARD) != 0 &&
6412*1f6eb021SLiane Praza 			    strcmp(pg_name, SCF_TMPL_WILDCARD) != 0 &&
6413*1f6eb021SLiane Praza 			    strcmp(pg_name, pg_name_r) != 0) {
6414*1f6eb021SLiane Praza 				/* not a match */
6415*1f6eb021SLiane Praza 				free(pg_name_r);
6416*1f6eb021SLiane Praza 				pg_name_r = NULL;
6417*1f6eb021SLiane Praza 				continue;
6418*1f6eb021SLiane Praza 			}
6419*1f6eb021SLiane Praza 			if (scf_tmpl_pg_type(r, &pg_type_r) == -1) {
6420*1f6eb021SLiane Praza 				goto cleanup;
6421*1f6eb021SLiane Praza 			} else if (strcmp(pg_type_r, SCF_TMPL_WILDCARD) != 0 &&
6422*1f6eb021SLiane Praza 			    strcmp(pg_type, SCF_TMPL_WILDCARD) != 0 &&
6423*1f6eb021SLiane Praza 			    strcmp(pg_type, pg_type_r) != 0) {
6424*1f6eb021SLiane Praza 				/* not a match */
6425*1f6eb021SLiane Praza 				free(pg_name_r);
6426*1f6eb021SLiane Praza 				pg_name_r = NULL;
6427*1f6eb021SLiane Praza 				free(pg_type_r);
6428*1f6eb021SLiane Praza 				pg_type_r = NULL;
6429*1f6eb021SLiane Praza 				continue;
6430*1f6eb021SLiane Praza 			}
6431*1f6eb021SLiane Praza 			if (scf_tmpl_pg_target(r, &target) == -1) {
6432*1f6eb021SLiane Praza 				target = NULL;
6433*1f6eb021SLiane Praza 				goto cleanup;
6434*1f6eb021SLiane Praza 			}
6435*1f6eb021SLiane Praza 			if (strcmp(target, SCF_TM_TARGET_ALL) == 0 ||
6436*1f6eb021SLiane Praza 			    strcmp(target, SCF_TM_TARGET_DELEGATE) == 0) {
6437*1f6eb021SLiane Praza 				/* found a pg_pattern redefinition */
6438*1f6eb021SLiane Praza 				if (_add_tmpl_pg_redefine_error(errs, t,
6439*1f6eb021SLiane Praza 				    r) == -1)
6440*1f6eb021SLiane Praza 					goto cleanup;
6441*1f6eb021SLiane Praza 				free(pg_name_r);
6442*1f6eb021SLiane Praza 				pg_name_r = NULL;
6443*1f6eb021SLiane Praza 				free(target);
6444*1f6eb021SLiane Praza 				target = NULL;
6445*1f6eb021SLiane Praza 				break;
6446*1f6eb021SLiane Praza 			}
6447*1f6eb021SLiane Praza 			free(pg_name_r);
6448*1f6eb021SLiane Praza 			pg_name_r = NULL;
6449*1f6eb021SLiane Praza 			free(target);
6450*1f6eb021SLiane Praza 			target = NULL;
6451*1f6eb021SLiane Praza 		}
6452*1f6eb021SLiane Praza 		if (ret == -1)
6453*1f6eb021SLiane Praza 			goto cleanup;
6454*1f6eb021SLiane Praza 		scf_tmpl_pg_reset(r);
6455*1f6eb021SLiane Praza 
6456*1f6eb021SLiane Praza 		free(pg_name);
6457*1f6eb021SLiane Praza 		free(pg_type);
6458*1f6eb021SLiane Praza 		pg_name = NULL;
6459*1f6eb021SLiane Praza 		pg_type = NULL;
6460*1f6eb021SLiane Praza 	}
6461*1f6eb021SLiane Praza 	if (ret == -1)
6462*1f6eb021SLiane Praza 		goto cleanup;
6463*1f6eb021SLiane Praza 
6464*1f6eb021SLiane Praza 	ret_val = 0;
6465*1f6eb021SLiane Praza 
6466*1f6eb021SLiane Praza cleanup:
6467*1f6eb021SLiane Praza 	scf_tmpl_pg_destroy(t);
6468*1f6eb021SLiane Praza 	scf_tmpl_pg_destroy(r);
6469*1f6eb021SLiane Praza 	free(pg_name);
6470*1f6eb021SLiane Praza 	free(pg_type);
6471*1f6eb021SLiane Praza 	free(pg_name_r);
6472*1f6eb021SLiane Praza 	free(pg_type_r);
6473*1f6eb021SLiane Praza 	free(target);
6474*1f6eb021SLiane Praza 
6475*1f6eb021SLiane Praza 	if (ret_val == -1) {
6476*1f6eb021SLiane Praza 		if (!ismember(scf_error(), errors_server)) {
6477*1f6eb021SLiane Praza 			switch (scf_error()) {
6478*1f6eb021SLiane Praza 			case SCF_ERROR_TYPE_MISMATCH:
6479*1f6eb021SLiane Praza 				(void) scf_set_error(
6480*1f6eb021SLiane Praza 				    SCF_ERROR_TEMPLATE_INVALID);
6481*1f6eb021SLiane Praza 				/*FALLTHROUGH*/
6482*1f6eb021SLiane Praza 
6483*1f6eb021SLiane Praza 			case SCF_ERROR_CONSTRAINT_VIOLATED:
6484*1f6eb021SLiane Praza 			case SCF_ERROR_INVALID_ARGUMENT:
6485*1f6eb021SLiane Praza 			case SCF_ERROR_NOT_FOUND:
6486*1f6eb021SLiane Praza 			case SCF_ERROR_TEMPLATE_INVALID:
6487*1f6eb021SLiane Praza 				break;
6488*1f6eb021SLiane Praza 
6489*1f6eb021SLiane Praza 			case SCF_ERROR_HANDLE_MISMATCH:
6490*1f6eb021SLiane Praza 			case SCF_ERROR_NOT_SET:
6491*1f6eb021SLiane Praza 			default:
6492*1f6eb021SLiane Praza 				assert(0);
6493*1f6eb021SLiane Praza 				abort();
6494*1f6eb021SLiane Praza 			}
6495*1f6eb021SLiane Praza 		}
6496*1f6eb021SLiane Praza 	}
6497*1f6eb021SLiane Praza 	return (ret_val);
6498*1f6eb021SLiane Praza }
6499*1f6eb021SLiane Praza 
6500*1f6eb021SLiane Praza /*
6501*1f6eb021SLiane Praza  * Returns -1 on failure, sets scf_error() to:
6502*1f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
6503*1f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
6504*1f6eb021SLiane Praza  *   SCF_ERROR_DELETED
6505*1f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
6506*1f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
6507*1f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
6508*1f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
6509*1f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
6510*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
6511*1f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
6512*1f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
6513*1f6eb021SLiane Praza  *   SCF_ERROR_TEMPLATE_INVALID
6514*1f6eb021SLiane Praza  */
6515*1f6eb021SLiane Praza int
6516*1f6eb021SLiane Praza scf_tmpl_validate_fmri(scf_handle_t *h, const char *fmri, const char *snapshot,
6517*1f6eb021SLiane Praza     scf_tmpl_errors_t **errs, int flags)
6518*1f6eb021SLiane Praza {
6519*1f6eb021SLiane Praza 	scf_pg_tmpl_t *t = NULL;
6520*1f6eb021SLiane Praza 	scf_iter_t *iter = NULL;
6521*1f6eb021SLiane Praza 	scf_propertygroup_t *pg = NULL;
6522*1f6eb021SLiane Praza 	scf_instance_t *inst = NULL;
6523*1f6eb021SLiane Praza 	scf_snapshot_t *snap = NULL;
6524*1f6eb021SLiane Praza 	char *type = NULL;
6525*1f6eb021SLiane Praza 	char *pg_name = NULL;
6526*1f6eb021SLiane Praza 	ssize_t rsize = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH) + 1;
6527*1f6eb021SLiane Praza 	ssize_t nsize = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
6528*1f6eb021SLiane Praza 	int ret = -1;
6529*1f6eb021SLiane Praza 	int r;
6530*1f6eb021SLiane Praza 
6531*1f6eb021SLiane Praza 	assert(errs != NULL);
6532*1f6eb021SLiane Praza 
6533*1f6eb021SLiane Praza 	if ((*errs = _scf_create_errors(fmri, 1)) == NULL)
6534*1f6eb021SLiane Praza 		return (-1);
6535*1f6eb021SLiane Praza 
6536*1f6eb021SLiane Praza 	if ((pg = scf_pg_create(h)) == NULL ||
6537*1f6eb021SLiane Praza 	    (iter = scf_iter_create(h)) == NULL ||
6538*1f6eb021SLiane Praza 	    (inst = scf_instance_create(h)) == NULL ||
6539*1f6eb021SLiane Praza 	    (t = scf_tmpl_pg_create(h)) == NULL) {
6540*1f6eb021SLiane Praza 		/*
6541*1f6eb021SLiane Praza 		 * Sets SCF_ERROR_INVALID_ARGUMENT, SCF_ERROR_NO_MEMORY,
6542*1f6eb021SLiane Praza 		 * SCF_ERROR_NO_RESOURCES, SCF_ERROR_INTERNAL or
6543*1f6eb021SLiane Praza 		 * SCF_ERROR_HANDLE_DESTROYED.
6544*1f6eb021SLiane Praza 		 */
6545*1f6eb021SLiane Praza 		goto cleanup;
6546*1f6eb021SLiane Praza 	}
6547*1f6eb021SLiane Praza 
6548*1f6eb021SLiane Praza 	if ((type = malloc(rsize)) == NULL ||
6549*1f6eb021SLiane Praza 	    (pg_name = malloc(nsize)) == NULL) {
6550*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
6551*1f6eb021SLiane Praza 		goto cleanup;
6552*1f6eb021SLiane Praza 	}
6553*1f6eb021SLiane Praza 
6554*1f6eb021SLiane Praza 	if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL, NULL,
6555*1f6eb021SLiane Praza 	    SCF_DECODE_FMRI_EXACT|SCF_DECODE_FMRI_REQUIRE_INSTANCE) != 0) {
6556*1f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
6557*1f6eb021SLiane Praza 			goto cleanup;
6558*1f6eb021SLiane Praza 		} else switch (scf_error()) {
6559*1f6eb021SLiane Praza 		case SCF_ERROR_CONSTRAINT_VIOLATED:
6560*1f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
6561*1f6eb021SLiane Praza 			/*FALLTHROUGH*/
6562*1f6eb021SLiane Praza 
6563*1f6eb021SLiane Praza 		case SCF_ERROR_INVALID_ARGUMENT:
6564*1f6eb021SLiane Praza 		case SCF_ERROR_NOT_FOUND:
6565*1f6eb021SLiane Praza 			goto cleanup;
6566*1f6eb021SLiane Praza 
6567*1f6eb021SLiane Praza 		case SCF_ERROR_HANDLE_MISMATCH:
6568*1f6eb021SLiane Praza 		case SCF_ERROR_NOT_SET:
6569*1f6eb021SLiane Praza 		default:
6570*1f6eb021SLiane Praza 			assert(0);
6571*1f6eb021SLiane Praza 			abort();
6572*1f6eb021SLiane Praza 		}
6573*1f6eb021SLiane Praza 	}
6574*1f6eb021SLiane Praza 
6575*1f6eb021SLiane Praza 	if (snapshot == NULL || strcmp(snapshot, "running") == 0 ||
6576*1f6eb021SLiane Praza 	    (flags & SCF_TMPL_VALIDATE_FLAG_CURRENT)) {
6577*1f6eb021SLiane Praza 		if (_get_snapshot(inst, NULL, &snap) == -1)
6578*1f6eb021SLiane Praza 			goto cleanup;
6579*1f6eb021SLiane Praza 	} else {
6580*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NONE);
6581*1f6eb021SLiane Praza 		if (_get_snapshot(inst, snapshot, &snap) == -1) {
6582*1f6eb021SLiane Praza 			goto cleanup;
6583*1f6eb021SLiane Praza 		} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
6584*1f6eb021SLiane Praza 			goto cleanup;
6585*1f6eb021SLiane Praza 		}
6586*1f6eb021SLiane Praza 	}
6587*1f6eb021SLiane Praza 	if (_scf_tmpl_check_pg_redef(h, fmri, snapshot, *errs) != 0) {
6588*1f6eb021SLiane Praza 		goto cleanup;
6589*1f6eb021SLiane Praza 	}
6590*1f6eb021SLiane Praza 
6591*1f6eb021SLiane Praza 	/*
6592*1f6eb021SLiane Praza 	 * Check that property groups on this instance conform to the template.
6593*1f6eb021SLiane Praza 	 */
6594*1f6eb021SLiane Praza 	if (scf_iter_instance_pgs_composed(iter, inst, snap) != 0) {
6595*1f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
6596*1f6eb021SLiane Praza 			goto cleanup;
6597*1f6eb021SLiane Praza 		} else {
6598*1f6eb021SLiane Praza 			assert(0);
6599*1f6eb021SLiane Praza 			abort();
6600*1f6eb021SLiane Praza 		}
6601*1f6eb021SLiane Praza 	}
6602*1f6eb021SLiane Praza 
6603*1f6eb021SLiane Praza 	while ((r = scf_iter_next_pg(iter, pg)) == 1) {
6604*1f6eb021SLiane Praza 		if (scf_pg_get_name(pg, pg_name, nsize) == -1) {
6605*1f6eb021SLiane Praza 			if (ismember(scf_error(), errors_server)) {
6606*1f6eb021SLiane Praza 				goto cleanup;
6607*1f6eb021SLiane Praza 			} else {
6608*1f6eb021SLiane Praza 				assert(0);
6609*1f6eb021SLiane Praza 				abort();
6610*1f6eb021SLiane Praza 			}
6611*1f6eb021SLiane Praza 		}
6612*1f6eb021SLiane Praza 
6613*1f6eb021SLiane Praza 		if (scf_pg_get_type(pg, type, rsize) == -1) {
6614*1f6eb021SLiane Praza 			if (ismember(scf_error(), errors_server)) {
6615*1f6eb021SLiane Praza 				goto cleanup;
6616*1f6eb021SLiane Praza 			} else {
6617*1f6eb021SLiane Praza 				assert(0);
6618*1f6eb021SLiane Praza 				abort();
6619*1f6eb021SLiane Praza 			}
6620*1f6eb021SLiane Praza 		}
6621*1f6eb021SLiane Praza 
6622*1f6eb021SLiane Praza 		if (scf_tmpl_get_by_pg_name(fmri, snapshot, pg_name, type, t,
6623*1f6eb021SLiane Praza 		    0) != 0) {
6624*1f6eb021SLiane Praza 			if (ismember(scf_error(), errors_server)) {
6625*1f6eb021SLiane Praza 				goto cleanup;
6626*1f6eb021SLiane Praza 			} else switch (scf_error()) {
6627*1f6eb021SLiane Praza 			case SCF_ERROR_NOT_FOUND:
6628*1f6eb021SLiane Praza 				continue;
6629*1f6eb021SLiane Praza 
6630*1f6eb021SLiane Praza 			case SCF_ERROR_INVALID_ARGUMENT:
6631*1f6eb021SLiane Praza 				goto cleanup;
6632*1f6eb021SLiane Praza 
6633*1f6eb021SLiane Praza 			default:
6634*1f6eb021SLiane Praza 				assert(0);
6635*1f6eb021SLiane Praza 				abort();
6636*1f6eb021SLiane Praza 			}
6637*1f6eb021SLiane Praza 		}
6638*1f6eb021SLiane Praza 
6639*1f6eb021SLiane Praza 		if (_check_pg(t, pg, pg_name, type, *errs) != 0)
6640*1f6eb021SLiane Praza 			goto cleanup;
6641*1f6eb021SLiane Praza 	}
6642*1f6eb021SLiane Praza 	if (r < 0) {
6643*1f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
6644*1f6eb021SLiane Praza 			goto cleanup;
6645*1f6eb021SLiane Praza 		} else {
6646*1f6eb021SLiane Praza 			assert(0);
6647*1f6eb021SLiane Praza 			abort();
6648*1f6eb021SLiane Praza 		}
6649*1f6eb021SLiane Praza 	}
6650*1f6eb021SLiane Praza 
6651*1f6eb021SLiane Praza 	scf_tmpl_pg_reset(t);
6652*1f6eb021SLiane Praza 
6653*1f6eb021SLiane Praza 	/*
6654*1f6eb021SLiane Praza 	 * Confirm required property groups are present.
6655*1f6eb021SLiane Praza 	 */
6656*1f6eb021SLiane Praza 	while ((r = scf_tmpl_iter_pgs(t, fmri, snapshot, NULL,
6657*1f6eb021SLiane Praza 	    SCF_PG_TMPL_FLAG_REQUIRED)) == 1) {
6658*1f6eb021SLiane Praza 		free(pg_name);
6659*1f6eb021SLiane Praza 		free(type);
6660*1f6eb021SLiane Praza 
6661*1f6eb021SLiane Praza 		if (scf_tmpl_pg_name(t, &pg_name) == -1)
6662*1f6eb021SLiane Praza 			goto cleanup;
6663*1f6eb021SLiane Praza 		if (scf_tmpl_pg_type(t, &type) == -1)
6664*1f6eb021SLiane Praza 			goto cleanup;
6665*1f6eb021SLiane Praza 		/*
6666*1f6eb021SLiane Praza 		 * required property group templates should not have
6667*1f6eb021SLiane Praza 		 * wildcarded name or type
6668*1f6eb021SLiane Praza 		 */
6669*1f6eb021SLiane Praza 		if (strcmp(pg_name, SCF_TMPL_WILDCARD) == 0 ||
6670*1f6eb021SLiane Praza 		    strcmp(type, SCF_TMPL_WILDCARD) == 0) {
6671*1f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
6672*1f6eb021SLiane Praza 			goto cleanup;
6673*1f6eb021SLiane Praza 		}
6674*1f6eb021SLiane Praza 
6675*1f6eb021SLiane Praza 		if (_get_pg(NULL, inst, snap, pg_name, pg) != 0) {
6676*1f6eb021SLiane Praza 			if (ismember(scf_error(), errors_server)) {
6677*1f6eb021SLiane Praza 				goto cleanup;
6678*1f6eb021SLiane Praza 			} else switch (scf_error()) {
6679*1f6eb021SLiane Praza 			case SCF_ERROR_NOT_FOUND:
6680*1f6eb021SLiane Praza 				if (_add_tmpl_missing_pg_error(*errs, t) == -1)
6681*1f6eb021SLiane Praza 					goto cleanup;
6682*1f6eb021SLiane Praza 				continue;
6683*1f6eb021SLiane Praza 
6684*1f6eb021SLiane Praza 			case SCF_ERROR_INVALID_ARGUMENT:
6685*1f6eb021SLiane Praza 			case SCF_ERROR_HANDLE_MISMATCH:
6686*1f6eb021SLiane Praza 			case SCF_ERROR_NOT_SET:
6687*1f6eb021SLiane Praza 			default:
6688*1f6eb021SLiane Praza 				assert(0);
6689*1f6eb021SLiane Praza 				abort();
6690*1f6eb021SLiane Praza 			}
6691*1f6eb021SLiane Praza 		}
6692*1f6eb021SLiane Praza 	}
6693*1f6eb021SLiane Praza 	if (r < 0) {
6694*1f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
6695*1f6eb021SLiane Praza 			goto cleanup;
6696*1f6eb021SLiane Praza 		} else switch (scf_error()) {
6697*1f6eb021SLiane Praza 		case SCF_ERROR_NOT_FOUND:
6698*1f6eb021SLiane Praza 			break;
6699*1f6eb021SLiane Praza 
6700*1f6eb021SLiane Praza 		case SCF_ERROR_INVALID_ARGUMENT:
6701*1f6eb021SLiane Praza 			goto cleanup;
6702*1f6eb021SLiane Praza 
6703*1f6eb021SLiane Praza 		default:
6704*1f6eb021SLiane Praza 			assert(0);
6705*1f6eb021SLiane Praza 			abort();
6706*1f6eb021SLiane Praza 		}
6707*1f6eb021SLiane Praza 	}
6708*1f6eb021SLiane Praza 
6709*1f6eb021SLiane Praza 	ret = 0;
6710*1f6eb021SLiane Praza 	if ((*errs)->tes_num_errs > 0)
6711*1f6eb021SLiane Praza 		ret = 1;
6712*1f6eb021SLiane Praza cleanup:
6713*1f6eb021SLiane Praza 	if (ret != 1) {
6714*1f6eb021SLiane Praza 		/* there are no errors to report */
6715*1f6eb021SLiane Praza 		scf_tmpl_errors_destroy(*errs);
6716*1f6eb021SLiane Praza 		*errs = NULL;
6717*1f6eb021SLiane Praza 	}
6718*1f6eb021SLiane Praza 	scf_tmpl_pg_destroy(t);
6719*1f6eb021SLiane Praza 	free(type);
6720*1f6eb021SLiane Praza 	free(pg_name);
6721*1f6eb021SLiane Praza 
6722*1f6eb021SLiane Praza 	scf_iter_destroy(iter);
6723*1f6eb021SLiane Praza 	scf_pg_destroy(pg);
6724*1f6eb021SLiane Praza 	scf_instance_destroy(inst);
6725*1f6eb021SLiane Praza 	scf_snapshot_destroy(snap);
6726*1f6eb021SLiane Praza 
6727*1f6eb021SLiane Praza 	return (ret);
6728*1f6eb021SLiane Praza }
6729*1f6eb021SLiane Praza 
6730*1f6eb021SLiane Praza void
6731*1f6eb021SLiane Praza scf_tmpl_errors_destroy(scf_tmpl_errors_t *errs)
6732*1f6eb021SLiane Praza {
6733*1f6eb021SLiane Praza 	int i;
6734*1f6eb021SLiane Praza 	scf_tmpl_error_t *e;
6735*1f6eb021SLiane Praza 
6736*1f6eb021SLiane Praza 	if (errs == NULL)
6737*1f6eb021SLiane Praza 		return;
6738*1f6eb021SLiane Praza 
6739*1f6eb021SLiane Praza 	for (i = 0; i < errs->tes_num_errs; ++i) {
6740*1f6eb021SLiane Praza 		e = errs->tes_errs[i];
6741*1f6eb021SLiane Praza 		if (errs->tes_flag != 0) {
6742*1f6eb021SLiane Praza 			free((char *)e->te_pg_name);
6743*1f6eb021SLiane Praza 			free((char *)e->te_prop_name);
6744*1f6eb021SLiane Praza 			free((char *)e->te_ev1);
6745*1f6eb021SLiane Praza 			free((char *)e->te_ev2);
6746*1f6eb021SLiane Praza 			free((char *)e->te_actual);
6747*1f6eb021SLiane Praza 			free((char *)e->te_tmpl_fmri);
6748*1f6eb021SLiane Praza 			free((char *)e->te_tmpl_pg_name);
6749*1f6eb021SLiane Praza 			free((char *)e->te_tmpl_pg_type);
6750*1f6eb021SLiane Praza 			free((char *)e->te_tmpl_prop_name);
6751*1f6eb021SLiane Praza 			free((char *)e->te_tmpl_prop_type);
6752*1f6eb021SLiane Praza 		}
6753*1f6eb021SLiane Praza 		free(e);
6754*1f6eb021SLiane Praza 	}
6755*1f6eb021SLiane Praza 	free((char *)errs->tes_fmri);
6756*1f6eb021SLiane Praza 	free((char *)errs->tes_prefix);
6757*1f6eb021SLiane Praza 	free(errs->tes_errs);
6758*1f6eb021SLiane Praza 	free(errs);
6759*1f6eb021SLiane Praza }
6760*1f6eb021SLiane Praza 
6761*1f6eb021SLiane Praza int
6762*1f6eb021SLiane Praza scf_tmpl_error_source_fmri(const scf_tmpl_error_t *err, char **fmri)
6763*1f6eb021SLiane Praza {
6764*1f6eb021SLiane Praza 	assert(err != NULL);
6765*1f6eb021SLiane Praza 	switch (err->te_type) {
6766*1f6eb021SLiane Praza 	case SCF_TERR_MISSING_PG:
6767*1f6eb021SLiane Praza 	case SCF_TERR_WRONG_PG_TYPE:
6768*1f6eb021SLiane Praza 	case SCF_TERR_MISSING_PROP:
6769*1f6eb021SLiane Praza 	case SCF_TERR_WRONG_PROP_TYPE:
6770*1f6eb021SLiane Praza 	case SCF_TERR_CARDINALITY_VIOLATION:
6771*1f6eb021SLiane Praza 	case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
6772*1f6eb021SLiane Praza 	case SCF_TERR_RANGE_VIOLATION:
6773*1f6eb021SLiane Praza 	case SCF_TERR_PROP_TYPE_MISMATCH:
6774*1f6eb021SLiane Praza 	case SCF_TERR_VALUE_OUT_OF_RANGE:
6775*1f6eb021SLiane Praza 	case SCF_TERR_INVALID_VALUE:
6776*1f6eb021SLiane Praza 	case SCF_TERR_PG_REDEFINE:
6777*1f6eb021SLiane Praza 		*fmri = (char *)err->te_tmpl_fmri;
6778*1f6eb021SLiane Praza 		return (0);
6779*1f6eb021SLiane Praza 		/*NOTREACHED*/
6780*1f6eb021SLiane Praza 	default:
6781*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
6782*1f6eb021SLiane Praza 	}
6783*1f6eb021SLiane Praza 	return (-1);
6784*1f6eb021SLiane Praza }
6785*1f6eb021SLiane Praza 
6786*1f6eb021SLiane Praza int
6787*1f6eb021SLiane Praza scf_tmpl_error_type(const scf_tmpl_error_t *err, scf_tmpl_error_type_t *type)
6788*1f6eb021SLiane Praza {
6789*1f6eb021SLiane Praza 	assert(err != NULL);
6790*1f6eb021SLiane Praza 	switch (err->te_type) {
6791*1f6eb021SLiane Praza 	case SCF_TERR_MISSING_PG:
6792*1f6eb021SLiane Praza 	case SCF_TERR_WRONG_PG_TYPE:
6793*1f6eb021SLiane Praza 	case SCF_TERR_MISSING_PROP:
6794*1f6eb021SLiane Praza 	case SCF_TERR_WRONG_PROP_TYPE:
6795*1f6eb021SLiane Praza 	case SCF_TERR_CARDINALITY_VIOLATION:
6796*1f6eb021SLiane Praza 	case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
6797*1f6eb021SLiane Praza 	case SCF_TERR_RANGE_VIOLATION:
6798*1f6eb021SLiane Praza 	case SCF_TERR_PROP_TYPE_MISMATCH:
6799*1f6eb021SLiane Praza 	case SCF_TERR_VALUE_OUT_OF_RANGE:
6800*1f6eb021SLiane Praza 	case SCF_TERR_INVALID_VALUE:
6801*1f6eb021SLiane Praza 	case SCF_TERR_PG_REDEFINE:
6802*1f6eb021SLiane Praza 		*type = err->te_type;
6803*1f6eb021SLiane Praza 		return (0);
6804*1f6eb021SLiane Praza 		/*NOTREACHED*/
6805*1f6eb021SLiane Praza 	default:
6806*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
6807*1f6eb021SLiane Praza 	}
6808*1f6eb021SLiane Praza 	return (-1);
6809*1f6eb021SLiane Praza }
6810*1f6eb021SLiane Praza 
6811*1f6eb021SLiane Praza int
6812*1f6eb021SLiane Praza scf_tmpl_error_pg_tmpl(const scf_tmpl_error_t *err, char **name, char **type)
6813*1f6eb021SLiane Praza {
6814*1f6eb021SLiane Praza 	assert(err != NULL);
6815*1f6eb021SLiane Praza 	switch (err->te_type) {
6816*1f6eb021SLiane Praza 	case SCF_TERR_MISSING_PG:
6817*1f6eb021SLiane Praza 	case SCF_TERR_WRONG_PG_TYPE:
6818*1f6eb021SLiane Praza 	case SCF_TERR_MISSING_PROP:
6819*1f6eb021SLiane Praza 	case SCF_TERR_WRONG_PROP_TYPE:
6820*1f6eb021SLiane Praza 	case SCF_TERR_CARDINALITY_VIOLATION:
6821*1f6eb021SLiane Praza 	case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
6822*1f6eb021SLiane Praza 	case SCF_TERR_RANGE_VIOLATION:
6823*1f6eb021SLiane Praza 	case SCF_TERR_PROP_TYPE_MISMATCH:
6824*1f6eb021SLiane Praza 	case SCF_TERR_VALUE_OUT_OF_RANGE:
6825*1f6eb021SLiane Praza 	case SCF_TERR_INVALID_VALUE:
6826*1f6eb021SLiane Praza 	case SCF_TERR_PG_REDEFINE:
6827*1f6eb021SLiane Praza 		if (err->te_tmpl_pg_name != NULL &&
6828*1f6eb021SLiane Praza 		    err->te_tmpl_pg_type != NULL) {
6829*1f6eb021SLiane Praza 			if (name != NULL)
6830*1f6eb021SLiane Praza 				*name = (char *)err->te_tmpl_pg_name;
6831*1f6eb021SLiane Praza 			if (type != NULL)
6832*1f6eb021SLiane Praza 				*type = (char *)err->te_tmpl_pg_type;
6833*1f6eb021SLiane Praza 			return (0);
6834*1f6eb021SLiane Praza 		}
6835*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NOT_FOUND);
6836*1f6eb021SLiane Praza 		break;
6837*1f6eb021SLiane Praza 	default:
6838*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
6839*1f6eb021SLiane Praza 	}
6840*1f6eb021SLiane Praza 	return (-1);
6841*1f6eb021SLiane Praza }
6842*1f6eb021SLiane Praza 
6843*1f6eb021SLiane Praza int
6844*1f6eb021SLiane Praza scf_tmpl_error_pg(const scf_tmpl_error_t *err, char **name, char **type)
6845*1f6eb021SLiane Praza {
6846*1f6eb021SLiane Praza 	assert(err != NULL);
6847*1f6eb021SLiane Praza 	switch (err->te_type) {
6848*1f6eb021SLiane Praza 	case SCF_TERR_WRONG_PG_TYPE:
6849*1f6eb021SLiane Praza 		if (err->te_pg_name != NULL &&
6850*1f6eb021SLiane Praza 		    err->te_actual != NULL) {
6851*1f6eb021SLiane Praza 			if (name != NULL)
6852*1f6eb021SLiane Praza 				*name = (char *)err->te_pg_name;
6853*1f6eb021SLiane Praza 			if (type != NULL)
6854*1f6eb021SLiane Praza 				*type = (char *)err->te_actual;
6855*1f6eb021SLiane Praza 			return (0);
6856*1f6eb021SLiane Praza 		}
6857*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NOT_FOUND);
6858*1f6eb021SLiane Praza 		break;
6859*1f6eb021SLiane Praza 	case SCF_TERR_WRONG_PROP_TYPE:
6860*1f6eb021SLiane Praza 	case SCF_TERR_CARDINALITY_VIOLATION:
6861*1f6eb021SLiane Praza 	case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
6862*1f6eb021SLiane Praza 	case SCF_TERR_RANGE_VIOLATION:
6863*1f6eb021SLiane Praza 		if (err->te_pg_name != NULL &&
6864*1f6eb021SLiane Praza 		    err->te_tmpl_pg_type != NULL) {
6865*1f6eb021SLiane Praza 			if (name != NULL)
6866*1f6eb021SLiane Praza 				*name = (char *)err->te_pg_name;
6867*1f6eb021SLiane Praza 			if (type != NULL)
6868*1f6eb021SLiane Praza 				*type = (char *)err->te_tmpl_pg_type;
6869*1f6eb021SLiane Praza 			return (0);
6870*1f6eb021SLiane Praza 		}
6871*1f6eb021SLiane Praza 		/*FALLTHROUGH*/
6872*1f6eb021SLiane Praza 	case SCF_TERR_MISSING_PROP:
6873*1f6eb021SLiane Praza 	case SCF_TERR_MISSING_PG:
6874*1f6eb021SLiane Praza 	case SCF_TERR_PROP_TYPE_MISMATCH:
6875*1f6eb021SLiane Praza 	case SCF_TERR_VALUE_OUT_OF_RANGE:
6876*1f6eb021SLiane Praza 	case SCF_TERR_INVALID_VALUE:
6877*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NOT_FOUND);
6878*1f6eb021SLiane Praza 		break;
6879*1f6eb021SLiane Praza 	case SCF_TERR_PG_REDEFINE:
6880*1f6eb021SLiane Praza 		if (err->te_ev1 != NULL && err->te_ev2 != NULL) {
6881*1f6eb021SLiane Praza 			if (name != NULL)
6882*1f6eb021SLiane Praza 				*name = (char *)err->te_ev1;
6883*1f6eb021SLiane Praza 			if (type != NULL)
6884*1f6eb021SLiane Praza 				*type = (char *)err->te_ev2;
6885*1f6eb021SLiane Praza 			return (0);
6886*1f6eb021SLiane Praza 		}
6887*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NOT_FOUND);
6888*1f6eb021SLiane Praza 		break;
6889*1f6eb021SLiane Praza 	default:
6890*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
6891*1f6eb021SLiane Praza 	}
6892*1f6eb021SLiane Praza 	return (-1);
6893*1f6eb021SLiane Praza }
6894*1f6eb021SLiane Praza 
6895*1f6eb021SLiane Praza int
6896*1f6eb021SLiane Praza scf_tmpl_error_prop_tmpl(const scf_tmpl_error_t *err, char **name, char **type)
6897*1f6eb021SLiane Praza {
6898*1f6eb021SLiane Praza 	assert(err != NULL);
6899*1f6eb021SLiane Praza 	switch (err->te_type) {
6900*1f6eb021SLiane Praza 	case SCF_TERR_MISSING_PROP:
6901*1f6eb021SLiane Praza 	case SCF_TERR_WRONG_PROP_TYPE:
6902*1f6eb021SLiane Praza 	case SCF_TERR_CARDINALITY_VIOLATION:
6903*1f6eb021SLiane Praza 	case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
6904*1f6eb021SLiane Praza 	case SCF_TERR_RANGE_VIOLATION:
6905*1f6eb021SLiane Praza 	case SCF_TERR_PROP_TYPE_MISMATCH:
6906*1f6eb021SLiane Praza 	case SCF_TERR_VALUE_OUT_OF_RANGE:
6907*1f6eb021SLiane Praza 	case SCF_TERR_INVALID_VALUE:
6908*1f6eb021SLiane Praza 		if (err->te_tmpl_prop_name != NULL &&
6909*1f6eb021SLiane Praza 		    err->te_tmpl_prop_type != NULL) {
6910*1f6eb021SLiane Praza 			if (name != NULL)
6911*1f6eb021SLiane Praza 				*name = (char *)err->te_tmpl_prop_name;
6912*1f6eb021SLiane Praza 			if (type != NULL)
6913*1f6eb021SLiane Praza 				*type = (char *)err->te_tmpl_prop_type;
6914*1f6eb021SLiane Praza 			return (0);
6915*1f6eb021SLiane Praza 		}
6916*1f6eb021SLiane Praza 		/*FALLTHROUGH*/
6917*1f6eb021SLiane Praza 	case SCF_TERR_MISSING_PG:
6918*1f6eb021SLiane Praza 	case SCF_TERR_WRONG_PG_TYPE:
6919*1f6eb021SLiane Praza 	case SCF_TERR_PG_REDEFINE:
6920*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NOT_FOUND);
6921*1f6eb021SLiane Praza 		break;
6922*1f6eb021SLiane Praza 	default:
6923*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
6924*1f6eb021SLiane Praza 	}
6925*1f6eb021SLiane Praza 	return (-1);
6926*1f6eb021SLiane Praza }
6927*1f6eb021SLiane Praza 
6928*1f6eb021SLiane Praza int
6929*1f6eb021SLiane Praza scf_tmpl_error_prop(const scf_tmpl_error_t *err, char **name, char **type)
6930*1f6eb021SLiane Praza {
6931*1f6eb021SLiane Praza 	assert(err != NULL);
6932*1f6eb021SLiane Praza 	switch (err->te_type) {
6933*1f6eb021SLiane Praza 	case SCF_TERR_WRONG_PROP_TYPE:
6934*1f6eb021SLiane Praza 	case SCF_TERR_CARDINALITY_VIOLATION:
6935*1f6eb021SLiane Praza 	case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
6936*1f6eb021SLiane Praza 	case SCF_TERR_RANGE_VIOLATION:
6937*1f6eb021SLiane Praza 		if (err->te_prop_name != NULL &&
6938*1f6eb021SLiane Praza 		    err->te_tmpl_prop_type != NULL) {
6939*1f6eb021SLiane Praza 			if (name != NULL)
6940*1f6eb021SLiane Praza 				*name = (char *)err->te_prop_name;
6941*1f6eb021SLiane Praza 			if (type != NULL)
6942*1f6eb021SLiane Praza 				*type = (char *)err->te_tmpl_prop_type;
6943*1f6eb021SLiane Praza 			return (0);
6944*1f6eb021SLiane Praza 		}
6945*1f6eb021SLiane Praza 		/*FALLTHROUGH*/
6946*1f6eb021SLiane Praza 	case SCF_TERR_MISSING_PG:
6947*1f6eb021SLiane Praza 	case SCF_TERR_WRONG_PG_TYPE:
6948*1f6eb021SLiane Praza 	case SCF_TERR_MISSING_PROP:
6949*1f6eb021SLiane Praza 	case SCF_TERR_PROP_TYPE_MISMATCH:
6950*1f6eb021SLiane Praza 	case SCF_TERR_VALUE_OUT_OF_RANGE:
6951*1f6eb021SLiane Praza 	case SCF_TERR_INVALID_VALUE:
6952*1f6eb021SLiane Praza 	case SCF_TERR_PG_REDEFINE:
6953*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NOT_FOUND);
6954*1f6eb021SLiane Praza 		break;
6955*1f6eb021SLiane Praza 	default:
6956*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
6957*1f6eb021SLiane Praza 	}
6958*1f6eb021SLiane Praza 	return (-1);
6959*1f6eb021SLiane Praza }
6960*1f6eb021SLiane Praza 
6961*1f6eb021SLiane Praza int
6962*1f6eb021SLiane Praza scf_tmpl_error_value(const scf_tmpl_error_t *err, char **val)
6963*1f6eb021SLiane Praza {
6964*1f6eb021SLiane Praza 	assert(err != NULL);
6965*1f6eb021SLiane Praza 	switch (err->te_type) {
6966*1f6eb021SLiane Praza 	case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
6967*1f6eb021SLiane Praza 	case SCF_TERR_RANGE_VIOLATION:
6968*1f6eb021SLiane Praza 	case SCF_TERR_VALUE_OUT_OF_RANGE:
6969*1f6eb021SLiane Praza 	case SCF_TERR_INVALID_VALUE:
6970*1f6eb021SLiane Praza 		if (err->te_actual != NULL) {
6971*1f6eb021SLiane Praza 			if (val != NULL)
6972*1f6eb021SLiane Praza 				*val = (char *)err->te_actual;
6973*1f6eb021SLiane Praza 			return (0);
6974*1f6eb021SLiane Praza 		}
6975*1f6eb021SLiane Praza 		/*FALLTHROUGH*/
6976*1f6eb021SLiane Praza 	case SCF_TERR_MISSING_PG:
6977*1f6eb021SLiane Praza 	case SCF_TERR_WRONG_PG_TYPE:
6978*1f6eb021SLiane Praza 	case SCF_TERR_MISSING_PROP:
6979*1f6eb021SLiane Praza 	case SCF_TERR_WRONG_PROP_TYPE:
6980*1f6eb021SLiane Praza 	case SCF_TERR_CARDINALITY_VIOLATION:
6981*1f6eb021SLiane Praza 	case SCF_TERR_PROP_TYPE_MISMATCH:
6982*1f6eb021SLiane Praza 	case SCF_TERR_PG_REDEFINE:
6983*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NOT_FOUND);
6984*1f6eb021SLiane Praza 		break;
6985*1f6eb021SLiane Praza 	default:
6986*1f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
6987*1f6eb021SLiane Praza 	}
6988*1f6eb021SLiane Praza 	return (-1);
6989*1f6eb021SLiane Praza }
6990*1f6eb021SLiane Praza 
6991*1f6eb021SLiane Praza const char *
6992*1f6eb021SLiane Praza scf_tmpl_visibility_to_string(uint8_t vis)
6993*1f6eb021SLiane Praza {
6994*1f6eb021SLiane Praza 	if (vis == SCF_TMPL_VISIBILITY_READONLY)
6995*1f6eb021SLiane Praza 		return (SCF_TM_VISIBILITY_READONLY);
6996*1f6eb021SLiane Praza 	else if (vis == SCF_TMPL_VISIBILITY_HIDDEN)
6997*1f6eb021SLiane Praza 		return (SCF_TM_VISIBILITY_HIDDEN);
6998*1f6eb021SLiane Praza 	else if (vis == SCF_TMPL_VISIBILITY_READWRITE)
6999*1f6eb021SLiane Praza 		return (SCF_TM_VISIBILITY_READWRITE);
7000*1f6eb021SLiane Praza 	else
7001*1f6eb021SLiane Praza 		return ("unknown");
7002*1f6eb021SLiane Praza }
7003