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