Home | History | Annotate | Download | only in common
      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 			}
   5713 		}
   5714 		return (1);
   5715 	}
   5716 
   5717 	/* Numeric values should be checked against any range constraints. */
   5718 	switch (type) {
   5719 	case SCF_TYPE_COUNT:
   5720 		r = scf_value_get_count(value, &v_count);
   5721 		assert(r == 0);
   5722 
   5723 		if (scf_tmpl_value_count_range_constraints(pt, &cr) != 0) {
   5724 			if (scf_error() == SCF_ERROR_NOT_FOUND)
   5725 				break;
   5726 			if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED)
   5727 				(void) scf_set_error(
   5728 				    SCF_ERROR_TEMPLATE_INVALID);
   5729 			return (-1);
   5730 		} else {
   5731 			if (_check_count_ranges(&cr, v_count) == 0) {
   5732 				/* value is within ranges constraint */
   5733 				scf_count_ranges_destroy(&cr);
   5734 				return (0);
   5735 			}
   5736 			scf_count_ranges_destroy(&cr);
   5737 		}
   5738 
   5739 		/*
   5740 		 * If we get here, we have a possible constraint
   5741 		 * violation.
   5742 		 */
   5743 		err_flag |= 0x1; /* RANGE_VIOLATION, count */
   5744 		break;
   5745 	case SCF_TYPE_INTEGER:
   5746 		if (scf_value_get_integer(value, &v_int) != 0)
   5747 			assert(0);
   5748 		if (scf_tmpl_value_int_range_constraints(pt, &ir) != 0) {
   5749 			if (scf_error() == SCF_ERROR_NOT_FOUND)
   5750 				break;
   5751 			if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED)
   5752 				(void) scf_set_error(
   5753 				    SCF_ERROR_TEMPLATE_INVALID);
   5754 			return (-1);
   5755 		} else {
   5756 			if (_check_int_ranges(&ir, v_int) == 0) {
   5757 				/* value is within ranges constraint */
   5758 				scf_int_ranges_destroy(&ir);
   5759 				return (0);
   5760 			}
   5761 			scf_int_ranges_destroy(&ir);
   5762 		}
   5763 		/*
   5764 		 * If we get here, we have a possible constraint
   5765 		 * violation.
   5766 		 */
   5767 		err_flag |= 0x2; /* RANGE_VIOLATION, integer */
   5768 		break;
   5769 	default:
   5770 		break;
   5771 	}
   5772 
   5773 	vstr = malloc(sz);
   5774 	if (vstr == NULL) {
   5775 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
   5776 		return (-1);
   5777 	}
   5778 
   5779 	/*
   5780 	 * If a set of names is provided, confirm value has one of
   5781 	 * those names.
   5782 	 */
   5783 	if (scf_tmpl_value_name_constraints(pt, &vals) != 0) {
   5784 		free(vstr);
   5785 		if (scf_error() != SCF_ERROR_NOT_FOUND) {
   5786 			return (-1);
   5787 		}
   5788 	} else {
   5789 		r = scf_value_get_as_string_typed(value, type, vstr, sz);
   5790 
   5791 		/*
   5792 		 * All errors (INVALID_ARGUMENT, NOT_SET, TYPE_MISMATCH)
   5793 		 * should be impossible or already caught above.
   5794 		 */
   5795 		assert(r > 0);
   5796 
   5797 		constraints = vals.values.v_astring;
   5798 		for (n = 0; constraints[n] != NULL; ++n) {
   5799 			if (strcmp(constraints[n], vstr) == 0) {
   5800 				/* value is within constraint */
   5801 				scf_values_destroy(&vals);
   5802 				free(vstr);
   5803 				return (0);
   5804 			}
   5805 		}
   5806 		/* if we get here, we have a constraint violation */
   5807 		err_flag |= 0x4; /* CONSTRAINT_VIOLATED */
   5808 		scf_values_destroy(&vals);
   5809 		free(vstr);
   5810 	}
   5811 	if (err_flag != 0)
   5812 		ret = 1;
   5813 	/* register the errors found */
   5814 	if (ret == 1 && errs != NULL) {
   5815 		if ((err_flag & 0x1) == 0x1) {
   5816 			/*
   5817 			 * Help make the error more human-friendly.  If
   5818 			 * pg and prop are provided, we know we're
   5819 			 * validating repository data.  If they're not,
   5820 			 * we're validating a potentially hypothetical
   5821 			 * value.
   5822 			 */
   5823 			if (pg == NULL && prop == NULL)
   5824 				terr_type = SCF_TERR_VALUE_OUT_OF_RANGE;
   5825 			else
   5826 				terr_type = SCF_TERR_RANGE_VIOLATION;
   5827 			if (_add_tmpl_count_error(errs, terr_type, pg, pt,
   5828 			    prop, v_count, 0, 0) == -1)
   5829 				ret = -1;
   5830 		}
   5831 		if ((err_flag & 0x2) == 0x2) {
   5832 			if (pg == NULL && prop == NULL)
   5833 				terr_type = SCF_TERR_VALUE_OUT_OF_RANGE;
   5834 			else
   5835 				terr_type = SCF_TERR_RANGE_VIOLATION;
   5836 			if (_add_tmpl_int_error(errs, terr_type, pg, pt, prop,
   5837 			    v_int, 0, 0) == -1)
   5838 				ret = -1;
   5839 		}
   5840 		if ((err_flag & 0x4) == 0x4) {
   5841 			if (pg == NULL && prop == NULL)
   5842 				terr_type = SCF_TERR_INVALID_VALUE;
   5843 			else
   5844 				terr_type = SCF_TERR_VALUE_CONSTRAINT_VIOLATED;
   5845 			if (_add_tmpl_constraint_error(errs, terr_type, pg,
   5846 			    pt, prop, value) == -1)
   5847 				ret = -1;
   5848 		}
   5849 	}
   5850 	return (ret);
   5851 }
   5852 
   5853 /*
   5854  * Returns -1 on failure.  Sets scf_error():
   5855  *   SCF_ERROR_BACKEND_ACCESS
   5856  *   SCF_ERROR_CONNECTION_BROKEN
   5857  *   SCF_ERROR_DELETED
   5858  *   SCF_ERROR_HANDLE_DESTROYED
   5859  *   SCF_ERROR_INTERNAL
   5860  *   SCF_ERROR_INVALID_ARGUMENT
   5861  *   SCF_ERROR_NO_MEMORY
   5862  *   SCF_ERROR_NO_RESOURCES
   5863  *   SCF_ERROR_NOT_BOUND
   5864  *   SCF_ERROR_PERMISSION_DENIED
   5865  *   SCF_ERROR_TEMPLATE_INVALID
   5866  */
   5867 int
   5868 scf_tmpl_value_in_constraint(const scf_prop_tmpl_t *pt, scf_value_t *value,
   5869     scf_tmpl_errors_t **errs)
   5870 {
   5871 	scf_tmpl_errors_t *e = NULL;
   5872 
   5873 	if (errs != NULL) {
   5874 		char *fmri;
   5875 
   5876 		if ((fmri = _scf_tmpl_get_fmri(pt->prt_t)) == NULL)
   5877 			return (-1);
   5878 		*errs = _scf_create_errors(fmri, 1);
   5879 		free(fmri);
   5880 		if (*errs == NULL)
   5881 			return (-1);
   5882 		e = *errs;
   5883 	}
   5884 
   5885 	return (_value_in_constraint(NULL, NULL, pt, value, e));
   5886 }
   5887 
   5888 scf_tmpl_error_t *
   5889 scf_tmpl_next_error(scf_tmpl_errors_t *errs)
   5890 {
   5891 	if (errs->tes_index < errs->tes_num_errs) {
   5892 		assert(errs->tes_errs[errs->tes_index] != NULL);
   5893 		return (errs->tes_errs[errs->tes_index++]);
   5894 	} else {
   5895 		return (NULL);
   5896 	}
   5897 }
   5898 
   5899 void
   5900 scf_tmpl_reset_errors(scf_tmpl_errors_t *errs)
   5901 {
   5902 	errs->tes_index = 0;
   5903 }
   5904 
   5905 int
   5906 scf_tmpl_strerror(scf_tmpl_error_t *err,  char *s, size_t n, int flag)
   5907 {
   5908 	const char *str;
   5909 	int i;
   5910 	int ret = -1;
   5911 	int nsz = 0;	/* err msg length */
   5912 	int sz = n;	/* available buffer size */
   5913 	char *buf = s;	/* where to append in buffer */
   5914 	char *s0 = (flag == SCF_TMPL_STRERROR_HUMAN) ? ":\n\t" : ": ";
   5915 	char *s1 = (flag == SCF_TMPL_STRERROR_HUMAN) ? "\n\t" : "; ";
   5916 	char *sep = s0;
   5917 	const char *val;
   5918 
   5919 	/* prefix */
   5920 	if (err->te_errs->tes_prefix != NULL) {
   5921 		ret = snprintf(buf, sz, "%s", dgettext(TEXT_DOMAIN,
   5922 		    err->te_errs->tes_prefix));
   5923 		nsz += ret;
   5924 		sz = (sz - ret) > 0 ? sz - ret : 0;
   5925 		buf = (sz > 0) ? s + nsz : NULL;
   5926 	}
   5927 	/* error message */
   5928 	ret = snprintf(buf, sz, "%s", dgettext(TEXT_DOMAIN,
   5929 	    em_desc[err->te_type].em_msg));
   5930 	nsz += ret;
   5931 	sz = (sz - ret) > 0 ? sz - ret : 0;
   5932 	buf = (sz > 0) ? s + nsz : NULL;
   5933 
   5934 	for (i = 0; _tmpl_error_items[i].get_desc != NULL; ++i) {
   5935 		if ((str = _tmpl_error_items[i].get_desc(err)) == NULL)
   5936 			/* no item to print */
   5937 			continue;
   5938 		val = _tmpl_error_items[i].get_val(err);
   5939 		ret = snprintf(buf, sz, "%s%s=\"%s\"", sep, str,
   5940 		    (val == NULL) ? "" : val);
   5941 		nsz += ret;
   5942 		sz = (sz - ret) > 0 ? sz - ret : 0;
   5943 		buf = (sz > 0) ? s + nsz : NULL;
   5944 		sep = s1;
   5945 	}
   5946 	return (nsz);
   5947 }
   5948 
   5949 /*
   5950  * return 0 on success, -1 on failure.
   5951  * set scf_error() to:
   5952  *   SCF_ERROR_BACKEND_ACCESS
   5953  *   SCF_ERROR_CONNECTION_BROKEN
   5954  *   SCF_ERROR_DELETED
   5955  *   SCF_ERROR_HANDLE_DESTROYED
   5956  *   SCF_ERROR_INTERNAL
   5957  *   SCF_ERROR_NO_MEMORY
   5958  *   SCF_ERROR_NO_RESOURCES
   5959  *   SCF_ERROR_NOT_BOUND
   5960  *   SCF_ERROR_PERMISSION_DENIED
   5961  *   SCF_ERROR_TEMPLATE_INVALID
   5962  */
   5963 static int
   5964 _validate_cardinality(scf_propertygroup_t *pg, scf_prop_tmpl_t *pt,
   5965     scf_property_t *prop, scf_tmpl_errors_t *errs)
   5966 {
   5967 	uint64_t min, max;
   5968 	scf_handle_t *h;
   5969 	scf_iter_t *iter = NULL;
   5970 	scf_value_t *val = NULL;
   5971 	int count = 0;
   5972 	int ret = -1;
   5973 	int r;
   5974 
   5975 	if (scf_tmpl_prop_cardinality(pt, &min, &max) != 0) {
   5976 		if (scf_error() == SCF_ERROR_NOT_FOUND)
   5977 			return (0);
   5978 		else
   5979 			return (-1);
   5980 	}
   5981 
   5982 	/* Any number of values permitted.  Just return success. */
   5983 	if (min == 0 && max == UINT64_MAX) {
   5984 		return (0);
   5985 	}
   5986 
   5987 	h = scf_property_handle(prop);
   5988 	if (h == NULL) {
   5989 		assert(scf_error() == SCF_ERROR_HANDLE_DESTROYED);
   5990 		goto cleanup;
   5991 	}
   5992 
   5993 	iter = scf_iter_create(h);
   5994 	val = scf_value_create(h);
   5995 	if (iter == NULL || val == NULL) {
   5996 		if (ismember(scf_error(), errors_server)) {
   5997 			goto cleanup;
   5998 		} else {
   5999 			assert(0);
   6000 			abort();
   6001 		}
   6002 	}
   6003 
   6004 	if (scf_iter_property_values(iter, prop) != 0) {
   6005 		if (ismember(scf_error(), errors_server)) {
   6006 			goto cleanup;
   6007 		} else {
   6008 			assert(0);
   6009 			abort();
   6010 		}
   6011 	}
   6012 
   6013 	while ((r = scf_iter_next_value(iter, val)) == 1)
   6014 		count++;
   6015 
   6016 	if (r < 0) {
   6017 		if (ismember(scf_error(), errors_server)) {
   6018 			goto cleanup;
   6019 		} else {
   6020 			assert(0);
   6021 			abort();
   6022 		}
   6023 	}
   6024 
   6025 	if (count < min || count > max)
   6026 		if (_add_tmpl_count_error(errs, SCF_TERR_CARDINALITY_VIOLATION,
   6027 		    pg, pt, prop, (uint64_t)count, &min, &max) == -1)
   6028 			goto cleanup;
   6029 
   6030 	ret = 0;
   6031 
   6032 cleanup:
   6033 	scf_iter_destroy(iter);
   6034 	scf_value_destroy(val);
   6035 	return (ret);
   6036 }
   6037 
   6038 /*
   6039  * Returns -1 on error.  Sets scf_error():
   6040  *   SCF_ERROR_BACKEND_ACCESS
   6041  *   SCF_ERROR_CONNECTION_BROKEN
   6042  *   SCF_ERROR_DELETED
   6043  *   SCF_ERROR_HANDLE_DESTROYED
   6044  *   SCF_ERROR_INTERNAL
   6045  *   SCF_ERROR_NO_MEMORY
   6046  *   SCF_ERROR_NO_RESOURCES
   6047  *   SCF_ERROR_NOT_BOUND
   6048  *   SCF_ERROR_PERMISSION_DENIED
   6049  *   SCF_ERROR_TEMPLATE_INVALID
   6050  */
   6051 static int
   6052 _check_property(scf_prop_tmpl_t *pt, scf_propertygroup_t *pg,
   6053     scf_property_t *prop, scf_tmpl_errors_t *errs)
   6054 {
   6055 	scf_type_t tmpl_type;
   6056 	uint8_t required;
   6057 	scf_handle_t *h;
   6058 	scf_iter_t *iter = NULL;
   6059 	scf_value_t *val = NULL;
   6060 	int r;
   6061 	int ret = -1;
   6062 
   6063 	h = scf_pg_handle(pg);
   6064 	if (h == NULL) {
   6065 		assert(scf_error() == SCF_ERROR_HANDLE_DESTROYED);
   6066 		return (-1);
   6067 	}
   6068 
   6069 	iter = scf_iter_create(h);
   6070 	val = scf_value_create(h);
   6071 	if (iter == NULL || val == NULL) {
   6072 		if (ismember(scf_error(), errors_server)) {
   6073 			scf_iter_destroy(iter);
   6074 			scf_value_destroy(val);
   6075 			return (-1);
   6076 		} else {
   6077 			assert(0);
   6078 			abort();
   6079 		}
   6080 	}
   6081 
   6082 	if (scf_tmpl_prop_required(pt, &required) != 0)
   6083 		goto cleanup;
   6084 
   6085 	/* Check type */
   6086 	if (scf_tmpl_prop_type(pt, &tmpl_type) == -1) {
   6087 		if (scf_error() != SCF_ERROR_NOT_FOUND) {
   6088 			goto cleanup;
   6089 		} else if (required) {
   6090 			/* If required, type must be specified. */
   6091 			(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
   6092 			goto cleanup;
   6093 		}
   6094 	} else if (scf_property_is_type(prop, tmpl_type) != 0) {
   6095 		if (ismember(scf_error(), errors_server)) {
   6096 			goto cleanup;
   6097 		} else switch (scf_error()) {
   6098 		case SCF_ERROR_TYPE_MISMATCH:
   6099 			if (_add_tmpl_wrong_prop_type_error(errs, pg, pt,
   6100 			    prop) == -1)
   6101 				goto cleanup;
   6102 			break;
   6103 
   6104 		case SCF_ERROR_INVALID_ARGUMENT:
   6105 			/*
   6106 			 * tmpl_prop_type shouldn't have handed back
   6107 			 * an invalid property type.
   6108 			 */
   6109 		case SCF_ERROR_NOT_SET:
   6110 		default:
   6111 			assert(0);
   6112 			abort();
   6113 		}
   6114 	}
   6115 
   6116 
   6117 	/* Cardinality */
   6118 	if (_validate_cardinality(pg, pt, prop, errs) == -1)
   6119 		goto cleanup;
   6120 
   6121 	/* Value constraints */
   6122 	/*
   6123 	 * Iterate through each value, and confirm it is defined as
   6124 	 * constrained.
   6125 	 */
   6126 	if (scf_iter_property_values(iter, prop) != 0) {
   6127 		assert(scf_error() != SCF_ERROR_NOT_SET &&
   6128 		    scf_error() != SCF_ERROR_HANDLE_MISMATCH);
   6129 		goto cleanup;
   6130 	}
   6131 
   6132 	while ((r = scf_iter_next_value(iter, val)) == 1) {
   6133 		if (_value_in_constraint(pg, prop, pt, val, errs) == -1) {
   6134 			if (ismember(scf_error(), errors_server)) {
   6135 				goto cleanup;
   6136 			} else switch (scf_error()) {
   6137 			case SCF_ERROR_TEMPLATE_INVALID:
   6138 				goto cleanup;
   6139 
   6140 			case SCF_ERROR_INVALID_ARGUMENT:
   6141 			default:
   6142 				assert(0);
   6143 				abort();
   6144 			}
   6145 		}
   6146 	}
   6147 
   6148 	if (r < 0) {
   6149 		if (ismember(scf_error(), errors_server)) {
   6150 			goto cleanup;
   6151 		} else {
   6152 			assert(0);
   6153 			abort();
   6154 		}
   6155 	}
   6156 
   6157 	ret = 0;
   6158 
   6159 cleanup:
   6160 	scf_iter_destroy(iter);
   6161 	scf_value_destroy(val);
   6162 	return (ret);
   6163 }
   6164 
   6165 /*
   6166  * Returns -1 on failure, sets scf_error() to:
   6167  *   SCF_ERROR_BACKEND_ACCESS
   6168  *   SCF_ERROR_CONNECTION_BROKEN
   6169  *   SCF_ERROR_DELETED
   6170  *   SCF_ERROR_HANDLE_DESTROYED
   6171  *   SCF_ERROR_INTERNAL
   6172  *   SCF_ERROR_NO_MEMORY
   6173  *   SCF_ERROR_NO_RESOURCES
   6174  *   SCF_ERROR_NOT_BOUND
   6175  *   SCF_ERROR_PERMISSION_DENIED
   6176  *   SCF_ERROR_TEMPLATE_INVALID
   6177  */
   6178 static int
   6179 _check_pg(scf_pg_tmpl_t *t, scf_propertygroup_t *pg, char *pg_name,
   6180     char *type, scf_tmpl_errors_t *errs)
   6181 {
   6182 	scf_prop_tmpl_t *pt = NULL;
   6183 	char *pg_type = NULL;
   6184 	scf_iter_t *iter = NULL;
   6185 	uint8_t pg_required;
   6186 	scf_property_t *prop = NULL;
   6187 	scf_handle_t *h;
   6188 	int r;
   6189 	char *prop_name = NULL;
   6190 	ssize_t nsize = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
   6191 	int ret = -1;
   6192 
   6193 	assert(pg_name != NULL);
   6194 	assert(t != NULL);
   6195 	assert(pg != NULL);
   6196 	assert(type != NULL);
   6197 	assert(nsize != 0);
   6198 
   6199 	if ((h = scf_pg_handle(pg)) == NULL) {
   6200 		assert(scf_error() == SCF_ERROR_HANDLE_DESTROYED);
   6201 		return (-1);
   6202 	}
   6203 	if ((pt = scf_tmpl_prop_create(h)) == NULL) {
   6204 		assert(scf_error() != SCF_ERROR_INVALID_ARGUMENT);
   6205 		return (-1);
   6206 	}
   6207 
   6208 	if ((prop = scf_property_create(h)) == NULL) {
   6209 		assert(scf_error() != SCF_ERROR_INVALID_ARGUMENT);
   6210 		goto cleanup;
   6211 	}
   6212 
   6213 	if ((iter = scf_iter_create(h)) == NULL) {
   6214 		assert(scf_error() != SCF_ERROR_INVALID_ARGUMENT);
   6215 		goto cleanup;
   6216 	}
   6217 	if ((prop_name = malloc(nsize)) == NULL) {
   6218 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
   6219 		goto cleanup;
   6220 	}
   6221 
   6222 	if (scf_tmpl_pg_required(t, &pg_required) != 0)
   6223 		goto cleanup;
   6224 
   6225 	if (scf_tmpl_pg_type(t, &pg_type) == -1) {
   6226 		goto cleanup;
   6227 	} else if (pg_required != 0 &&
   6228 	    strcmp(SCF_TMPL_WILDCARD, pg_type) == 0) {
   6229 		/* Type must be specified for required pgs. */
   6230 		(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
   6231 		goto cleanup;
   6232 	}
   6233 
   6234 	if (pg_type != NULL) {
   6235 		if (strcmp(pg_type, type) != 0 &&
   6236 		    strcmp(pg_type, SCF_TMPL_WILDCARD) != 0) {
   6237 			if (_add_tmpl_wrong_pg_type_error(errs, t, pg) == -1)
   6238 				goto cleanup;
   6239 		}
   6240 	}
   6241 
   6242 
   6243 	/* Iterate through properties in the repository and check them. */
   6244 	if (scf_iter_pg_properties(iter, pg) != 0) {
   6245 		if (ismember(scf_error(), errors_server)) {
   6246 			goto cleanup;
   6247 		} else {
   6248 			assert(0);
   6249 			abort();
   6250 		}
   6251 	}
   6252 
   6253 	while ((r = scf_iter_next_property(iter, prop)) == 1) {
   6254 		if (scf_property_get_name(prop, prop_name, nsize) == -1) {
   6255 			assert(scf_error() != SCF_ERROR_NOT_SET);
   6256 			goto cleanup;
   6257 		}
   6258 		if (scf_tmpl_get_by_prop(t, prop_name, pt, 0) != 0) {
   6259 			if (ismember(scf_error(), errors_server)) {
   6260 				goto cleanup;
   6261 			} else switch (scf_error()) {
   6262 			case SCF_ERROR_NOT_FOUND:
   6263 				/* No template.  Continue. */
   6264 				continue;
   6265 
   6266 			case SCF_ERROR_INVALID_ARGUMENT:
   6267 			default:
   6268 				assert(0);
   6269 				abort();
   6270 			}
   6271 		}
   6272 
   6273 		if (_check_property(pt, pg, prop, errs) != 0)
   6274 			goto cleanup;
   6275 	}
   6276 
   6277 	if (r < 0) {
   6278 		if (ismember(scf_error(), errors_server)) {
   6279 			goto cleanup;
   6280 		} else {
   6281 			assert(0);
   6282 			abort();
   6283 		}
   6284 	}
   6285 
   6286 	scf_tmpl_prop_reset(pt);
   6287 	free(prop_name);
   6288 	prop_name = NULL;
   6289 	/*
   6290 	 * Confirm required properties are present.
   6291 	 */
   6292 	while ((r = scf_tmpl_iter_props(t, pt,
   6293 	    SCF_PROP_TMPL_FLAG_REQUIRED)) == 0) {
   6294 		scf_type_t prop_type;
   6295 
   6296 		if (scf_tmpl_prop_name(pt, &prop_name) == -1)
   6297 			goto cleanup;
   6298 
   6299 		/* required properties cannot have type wildcarded */
   6300 		if (scf_tmpl_prop_type(pt, &prop_type) == -1) {
   6301 			if (scf_error() == SCF_ERROR_NOT_FOUND)
   6302 				(void) scf_set_error(
   6303 				    SCF_ERROR_TEMPLATE_INVALID);
   6304 			goto cleanup;
   6305 		}
   6306 
   6307 		if (scf_pg_get_property(pg, prop_name, prop) != 0) {
   6308 			if (ismember(scf_error(), errors_server)) {
   6309 				goto cleanup;
   6310 			} else switch (scf_error()) {
   6311 			case SCF_ERROR_NOT_FOUND:
   6312 				if (_add_tmpl_missing_prop_error(errs, t, pg,
   6313 				    pt) == -1)
   6314 					goto cleanup;
   6315 				break;
   6316 
   6317 			case SCF_ERROR_INVALID_ARGUMENT:
   6318 				(void) scf_set_error(
   6319 				    SCF_ERROR_TEMPLATE_INVALID);
   6320 				goto cleanup;
   6321 
   6322 			case SCF_ERROR_HANDLE_MISMATCH:
   6323 			case SCF_ERROR_NOT_SET:
   6324 			default:
   6325 				assert(0);
   6326 				abort();
   6327 			}
   6328 		}
   6329 		free(prop_name);
   6330 		prop_name = NULL;
   6331 	}
   6332 	if (r < 0) {
   6333 		if (ismember(scf_error(), errors_server)) {
   6334 			goto cleanup;
   6335 		} else switch (scf_error()) {
   6336 		case SCF_ERROR_NOT_FOUND:
   6337 			break;
   6338 
   6339 		case SCF_ERROR_TEMPLATE_INVALID:
   6340 			goto cleanup;
   6341 
   6342 		case SCF_ERROR_INVALID_ARGUMENT:
   6343 		default:
   6344 			assert(0);
   6345 			abort();
   6346 		}
   6347 	}
   6348 
   6349 	ret = 0;
   6350 cleanup:
   6351 	scf_tmpl_prop_destroy(pt);
   6352 	scf_iter_destroy(iter);
   6353 	scf_property_destroy(prop);
   6354 	free(prop_name);
   6355 	free(pg_type);
   6356 	return (ret);
   6357 }
   6358 
   6359 /*
   6360  * Checks if instance fmri redefines any pgs defined in restarter or global
   6361  * Return -1 on failure, sets scf_error() to:
   6362  *   SCF_ERROR_BACKEND_ACCESS
   6363  *   SCF_ERROR_CONNECTION_BROKEN
   6364  *   SCF_ERROR_DELETED
   6365  *   SCF_ERROR_HANDLE_DESTROYED
   6366  *   SCF_ERROR_INTERNAL
   6367  *   SCF_ERROR_INVALID_ARGUMENT
   6368  *   SCF_ERROR_NO_MEMORY
   6369  *   SCF_ERROR_NO_RESOURCES
   6370  *   SCF_ERROR_NOT_BOUND
   6371  *   SCF_ERROR_NOT_FOUND
   6372  *   SCF_ERROR_PERMISSION_DENIED
   6373  *   SCF_ERROR_TEMPLATE_INVALID
   6374  */
   6375 static int
   6376 _scf_tmpl_check_pg_redef(scf_handle_t *h, const char *fmri,
   6377     const char *snapname, scf_tmpl_errors_t *errs)
   6378 {
   6379 	scf_pg_tmpl_t *t = NULL;
   6380 	scf_pg_tmpl_t *r = NULL;
   6381 	char *pg_name = NULL;
   6382 	char *pg_name_r = NULL;
   6383 	char *pg_type = NULL;
   6384 	char *pg_type_r = NULL;
   6385 	char *target = NULL;
   6386 	int ret_val = -1;
   6387 	int ret;
   6388 
   6389 	t = scf_tmpl_pg_create(h);
   6390 	r = scf_tmpl_pg_create(h);
   6391 	if (t == NULL || r == NULL)
   6392 		goto cleanup;
   6393 
   6394 	while ((ret = scf_tmpl_iter_pgs(t, fmri, snapname, NULL,
   6395 	    SCF_PG_TMPL_FLAG_EXACT)) == 1) {
   6396 		if (scf_tmpl_pg_name(t, &pg_name) == -1) {
   6397 			goto cleanup;
   6398 		}
   6399 		if (scf_tmpl_pg_type(t, &pg_type) == -1) {
   6400 			goto cleanup;
   6401 		}
   6402 		/* look for a redefinition of a global/restarter pg_pattern */
   6403 		while ((ret = scf_tmpl_iter_pgs(r, fmri, snapname, pg_type,
   6404 		    0)) == 1) {
   6405 			if (scf_tmpl_pg_name(r, &pg_name_r) == -1) {
   6406 				goto cleanup;
   6407 			} else if (strcmp(pg_name_r, SCF_TMPL_WILDCARD) != 0 &&
   6408 			    strcmp(pg_name, SCF_TMPL_WILDCARD) != 0 &&
   6409 			    strcmp(pg_name, pg_name_r) != 0) {
   6410 				/* not a match */
   6411 				free(pg_name_r);
   6412 				pg_name_r = NULL;
   6413 				continue;
   6414 			}
   6415 			if (scf_tmpl_pg_type(r, &pg_type_r) == -1) {
   6416 				goto cleanup;
   6417 			} else if (strcmp(pg_type_r, SCF_TMPL_WILDCARD) != 0 &&
   6418 			    strcmp(pg_type, SCF_TMPL_WILDCARD) != 0 &&
   6419 			    strcmp(pg_type, pg_type_r) != 0) {
   6420 				/* not a match */
   6421 				free(pg_name_r);
   6422 				pg_name_r = NULL;
   6423 				free(pg_type_r);
   6424 				pg_type_r = NULL;
   6425 				continue;
   6426 			}
   6427 			if (scf_tmpl_pg_target(r, &target) == -1) {
   6428 				target = NULL;
   6429 				goto cleanup;
   6430 			}
   6431 			if (strcmp(target, SCF_TM_TARGET_ALL) == 0 ||
   6432 			    strcmp(target, SCF_TM_TARGET_DELEGATE) == 0) {
   6433 				/* found a pg_pattern redefinition */
   6434 				if (_add_tmpl_pg_redefine_error(errs, t,
   6435 				    r) == -1)
   6436 					goto cleanup;
   6437 				free(pg_name_r);
   6438 				pg_name_r = NULL;
   6439 				free(target);
   6440 				target = NULL;
   6441 				break;
   6442 			}
   6443 			free(pg_name_r);
   6444 			pg_name_r = NULL;
   6445 			free(target);
   6446 			target = NULL;
   6447 		}
   6448 		if (ret == -1)
   6449 			goto cleanup;
   6450 		scf_tmpl_pg_reset(r);
   6451 
   6452 		free(pg_name);
   6453 		free(pg_type);
   6454 		pg_name = NULL;
   6455 		pg_type = NULL;
   6456 	}
   6457 	if (ret == -1)
   6458 		goto cleanup;
   6459 
   6460 	ret_val = 0;
   6461 
   6462 cleanup:
   6463 	scf_tmpl_pg_destroy(t);
   6464 	scf_tmpl_pg_destroy(r);
   6465 	free(pg_name);
   6466 	free(pg_type);
   6467 	free(pg_name_r);
   6468 	free(pg_type_r);
   6469 	free(target);
   6470 
   6471 	if (ret_val == -1) {
   6472 		if (!ismember(scf_error(), errors_server)) {
   6473 			switch (scf_error()) {
   6474 			case SCF_ERROR_TYPE_MISMATCH:
   6475 				(void) scf_set_error(
   6476 				    SCF_ERROR_TEMPLATE_INVALID);
   6477 				/*FALLTHROUGH*/
   6478 
   6479 			case SCF_ERROR_CONSTRAINT_VIOLATED:
   6480 			case SCF_ERROR_INVALID_ARGUMENT:
   6481 			case SCF_ERROR_NOT_FOUND:
   6482 			case SCF_ERROR_TEMPLATE_INVALID:
   6483 				break;
   6484 
   6485 			case SCF_ERROR_HANDLE_MISMATCH:
   6486 			case SCF_ERROR_NOT_SET:
   6487 			default:
   6488 				assert(0);
   6489 				abort();
   6490 			}
   6491 		}
   6492 	}
   6493 	return (ret_val);
   6494 }
   6495 
   6496 /*
   6497  * Returns -1 on failure, sets scf_error() to:
   6498  *   SCF_ERROR_BACKEND_ACCESS
   6499  *   SCF_ERROR_CONNECTION_BROKEN
   6500  *   SCF_ERROR_DELETED
   6501  *   SCF_ERROR_HANDLE_DESTROYED
   6502  *   SCF_ERROR_INTERNAL
   6503  *   SCF_ERROR_INVALID_ARGUMENT
   6504  *   SCF_ERROR_NO_MEMORY
   6505  *   SCF_ERROR_NO_RESOURCES
   6506  *   SCF_ERROR_NOT_BOUND
   6507  *   SCF_ERROR_NOT_FOUND
   6508  *   SCF_ERROR_PERMISSION_DENIED
   6509  *   SCF_ERROR_TEMPLATE_INVALID
   6510  */
   6511 int
   6512 scf_tmpl_validate_fmri(scf_handle_t *h, const char *fmri, const char *snapshot,
   6513     scf_tmpl_errors_t **errs, int flags)
   6514 {
   6515 	scf_pg_tmpl_t *t = NULL;
   6516 	scf_iter_t *iter = NULL;
   6517 	scf_propertygroup_t *pg = NULL;
   6518 	scf_instance_t *inst = NULL;
   6519 	scf_snapshot_t *snap = NULL;
   6520 	char *type = NULL;
   6521 	char *pg_name = NULL;
   6522 	ssize_t rsize = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH) + 1;
   6523 	ssize_t nsize = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
   6524 	int ret = -1;
   6525 	int r;
   6526 
   6527 	assert(errs != NULL);
   6528 
   6529 	if ((*errs = _scf_create_errors(fmri, 1)) == NULL)
   6530 		return (-1);
   6531 
   6532 	if ((pg = scf_pg_create(h)) == NULL ||
   6533 	    (iter = scf_iter_create(h)) == NULL ||
   6534 	    (inst = scf_instance_create(h)) == NULL ||
   6535 	    (t = scf_tmpl_pg_create(h)) == NULL) {
   6536 		/*
   6537 		 * Sets SCF_ERROR_INVALID_ARGUMENT, SCF_ERROR_NO_MEMORY,
   6538 		 * SCF_ERROR_NO_RESOURCES, SCF_ERROR_INTERNAL or
   6539 		 * SCF_ERROR_HANDLE_DESTROYED.
   6540 		 */
   6541 		goto cleanup;
   6542 	}
   6543 
   6544 	if ((type = malloc(rsize)) == NULL ||
   6545 	    (pg_name = malloc(nsize)) == NULL) {
   6546 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
   6547 		goto cleanup;
   6548 	}
   6549 
   6550 	if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL, NULL,
   6551 	    SCF_DECODE_FMRI_EXACT|SCF_DECODE_FMRI_REQUIRE_INSTANCE) != 0) {
   6552 		if (ismember(scf_error(), errors_server)) {
   6553 			goto cleanup;
   6554 		} else switch (scf_error()) {
   6555 		case SCF_ERROR_CONSTRAINT_VIOLATED:
   6556 			(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
   6557 			/*FALLTHROUGH*/
   6558 
   6559 		case SCF_ERROR_INVALID_ARGUMENT:
   6560 		case SCF_ERROR_NOT_FOUND:
   6561 			goto cleanup;
   6562 
   6563 		case SCF_ERROR_HANDLE_MISMATCH:
   6564 		case SCF_ERROR_NOT_SET:
   6565 		default:
   6566 			assert(0);
   6567 			abort();
   6568 		}
   6569 	}
   6570 
   6571 	if (snapshot == NULL || strcmp(snapshot, "running") == 0 ||
   6572 	    (flags & SCF_TMPL_VALIDATE_FLAG_CURRENT)) {
   6573 		if (_get_snapshot(inst, NULL, &snap) == -1)
   6574 			goto cleanup;
   6575 	} else {
   6576 		(void) scf_set_error(SCF_ERROR_NONE);
   6577 		if (_get_snapshot(inst, snapshot, &snap) == -1) {
   6578 			goto cleanup;
   6579 		} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
   6580 			goto cleanup;
   6581 		}
   6582 	}
   6583 	if (_scf_tmpl_check_pg_redef(h, fmri, snapshot, *errs) != 0) {
   6584 		goto cleanup;
   6585 	}
   6586 
   6587 	/*
   6588 	 * Check that property groups on this instance conform to the template.
   6589 	 */
   6590 	if (scf_iter_instance_pgs_composed(iter, inst, snap) != 0) {
   6591 		if (ismember(scf_error(), errors_server)) {
   6592 			goto cleanup;
   6593 		} else {
   6594 			assert(0);
   6595 			abort();
   6596 		}
   6597 	}
   6598 
   6599 	while ((r = scf_iter_next_pg(iter, pg)) == 1) {
   6600 		if (scf_pg_get_name(pg, pg_name, nsize) == -1) {
   6601 			if (ismember(scf_error(), errors_server)) {
   6602 				goto cleanup;
   6603 			} else {
   6604 				assert(0);
   6605 				abort();
   6606 			}
   6607 		}
   6608 
   6609 		if (scf_pg_get_type(pg, type, rsize) == -1) {
   6610 			if (ismember(scf_error(), errors_server)) {
   6611 				goto cleanup;
   6612 			} else {
   6613 				assert(0);
   6614 				abort();
   6615 			}
   6616 		}
   6617 
   6618 		if (scf_tmpl_get_by_pg_name(fmri, snapshot, pg_name, type, t,
   6619 		    0) != 0) {
   6620 			if (ismember(scf_error(), errors_server)) {
   6621 				goto cleanup;
   6622 			} else switch (scf_error()) {
   6623 			case SCF_ERROR_NOT_FOUND:
   6624 				continue;
   6625 
   6626 			case SCF_ERROR_INVALID_ARGUMENT:
   6627 				goto cleanup;
   6628 
   6629 			default:
   6630 				assert(0);
   6631 				abort();
   6632 			}
   6633 		}
   6634 
   6635 		if (_check_pg(t, pg, pg_name, type, *errs) != 0)
   6636 			goto cleanup;
   6637 	}
   6638 	if (r < 0) {
   6639 		if (ismember(scf_error(), errors_server)) {
   6640 			goto cleanup;
   6641 		} else {
   6642 			assert(0);
   6643 			abort();
   6644 		}
   6645 	}
   6646 
   6647 	scf_tmpl_pg_reset(t);
   6648 
   6649 	/*
   6650 	 * Confirm required property groups are present.
   6651 	 */
   6652 	while ((r = scf_tmpl_iter_pgs(t, fmri, snapshot, NULL,
   6653 	    SCF_PG_TMPL_FLAG_REQUIRED)) == 1) {
   6654 		free(pg_name);
   6655 		free(type);
   6656 
   6657 		if (scf_tmpl_pg_name(t, &pg_name) == -1)
   6658 			goto cleanup;
   6659 		if (scf_tmpl_pg_type(t, &type) == -1)
   6660 			goto cleanup;
   6661 		/*
   6662 		 * required property group templates should not have
   6663 		 * wildcarded name or type
   6664 		 */
   6665 		if (strcmp(pg_name, SCF_TMPL_WILDCARD) == 0 ||
   6666 		    strcmp(type, SCF_TMPL_WILDCARD) == 0) {
   6667 			(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
   6668 			goto cleanup;
   6669 		}
   6670 
   6671 		if (_get_pg(NULL, inst, snap, pg_name, pg) != 0) {
   6672 			if (ismember(scf_error(), errors_server)) {
   6673 				goto cleanup;
   6674 			} else switch (scf_error()) {
   6675 			case SCF_ERROR_NOT_FOUND:
   6676 				if (_add_tmpl_missing_pg_error(*errs, t) == -1)
   6677 					goto cleanup;
   6678 				continue;
   6679 
   6680 			case SCF_ERROR_INVALID_ARGUMENT:
   6681 			case SCF_ERROR_HANDLE_MISMATCH:
   6682 			case SCF_ERROR_NOT_SET:
   6683 			default:
   6684 				assert(0);
   6685 				abort();
   6686 			}
   6687 		}
   6688 	}
   6689 	if (r < 0) {
   6690 		if (ismember(scf_error(), errors_server)) {
   6691 			goto cleanup;
   6692 		} else switch (scf_error()) {
   6693 		case SCF_ERROR_NOT_FOUND:
   6694 			break;
   6695 
   6696 		case SCF_ERROR_INVALID_ARGUMENT:
   6697 			goto cleanup;
   6698 
   6699 		default:
   6700 			assert(0);
   6701 			abort();
   6702 		}
   6703 	}
   6704 
   6705 	ret = 0;
   6706 	if ((*errs)->tes_num_errs > 0)
   6707 		ret = 1;
   6708 cleanup:
   6709 	if (ret != 1) {
   6710 		/* there are no errors to report */
   6711 		scf_tmpl_errors_destroy(*errs);
   6712 		*errs = NULL;
   6713 	}
   6714 	scf_tmpl_pg_destroy(t);
   6715 	free(type);
   6716 	free(pg_name);
   6717 
   6718 	scf_iter_destroy(iter);
   6719 	scf_pg_destroy(pg);
   6720 	scf_instance_destroy(inst);
   6721 	scf_snapshot_destroy(snap);
   6722 
   6723 	return (ret);
   6724 }
   6725 
   6726 void
   6727 scf_tmpl_errors_destroy(scf_tmpl_errors_t *errs)
   6728 {
   6729 	int i;
   6730 	scf_tmpl_error_t *e;
   6731 
   6732 	if (errs == NULL)
   6733 		return;
   6734 
   6735 	for (i = 0; i < errs->tes_num_errs; ++i) {
   6736 		e = errs->tes_errs[i];
   6737 		if (errs->tes_flag != 0) {
   6738 			free((char *)e->te_pg_name);
   6739 			free((char *)e->te_prop_name);
   6740 			free((char *)e->te_ev1);
   6741 			free((char *)e->te_ev2);
   6742 			free((char *)e->te_actual);
   6743 			free((char *)e->te_tmpl_fmri);
   6744 			free((char *)e->te_tmpl_pg_name);
   6745 			free((char *)e->te_tmpl_pg_type);
   6746 			free((char *)e->te_tmpl_prop_name);
   6747 			free((char *)e->te_tmpl_prop_type);
   6748 		}
   6749 		free(e);
   6750 	}
   6751 	free((char *)errs->tes_fmri);
   6752 	free((char *)errs->tes_prefix);
   6753 	free(errs->tes_errs);
   6754 	free(errs);
   6755 }
   6756 
   6757 int
   6758 scf_tmpl_error_source_fmri(const scf_tmpl_error_t *err, char **fmri)
   6759 {
   6760 	assert(err != NULL);
   6761 	switch (err->te_type) {
   6762 	case SCF_TERR_MISSING_PG:
   6763 	case SCF_TERR_WRONG_PG_TYPE:
   6764 	case SCF_TERR_MISSING_PROP:
   6765 	case SCF_TERR_WRONG_PROP_TYPE:
   6766 	case SCF_TERR_CARDINALITY_VIOLATION:
   6767 	case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
   6768 	case SCF_TERR_RANGE_VIOLATION:
   6769 	case SCF_TERR_PROP_TYPE_MISMATCH:
   6770 	case SCF_TERR_VALUE_OUT_OF_RANGE:
   6771 	case SCF_TERR_INVALID_VALUE:
   6772 	case SCF_TERR_PG_REDEFINE:
   6773 		*fmri = (char *)err->te_tmpl_fmri;
   6774 		return (0);
   6775 		/*NOTREACHED*/
   6776 	default:
   6777 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
   6778 	}
   6779 	return (-1);
   6780 }
   6781 
   6782 int
   6783 scf_tmpl_error_type(const scf_tmpl_error_t *err, scf_tmpl_error_type_t *type)
   6784 {
   6785 	assert(err != NULL);
   6786 	switch (err->te_type) {
   6787 	case SCF_TERR_MISSING_PG:
   6788 	case SCF_TERR_WRONG_PG_TYPE:
   6789 	case SCF_TERR_MISSING_PROP:
   6790 	case SCF_TERR_WRONG_PROP_TYPE:
   6791 	case SCF_TERR_CARDINALITY_VIOLATION:
   6792 	case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
   6793 	case SCF_TERR_RANGE_VIOLATION:
   6794 	case SCF_TERR_PROP_TYPE_MISMATCH:
   6795 	case SCF_TERR_VALUE_OUT_OF_RANGE:
   6796 	case SCF_TERR_INVALID_VALUE:
   6797 	case SCF_TERR_PG_REDEFINE:
   6798 		*type = err->te_type;
   6799 		return (0);
   6800 		/*NOTREACHED*/
   6801 	default:
   6802 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
   6803 	}
   6804 	return (-1);
   6805 }
   6806 
   6807 int
   6808 scf_tmpl_error_pg_tmpl(const scf_tmpl_error_t *err, char **name, char **type)
   6809 {
   6810 	assert(err != NULL);
   6811 	switch (err->te_type) {
   6812 	case SCF_TERR_MISSING_PG:
   6813 	case SCF_TERR_WRONG_PG_TYPE:
   6814 	case SCF_TERR_MISSING_PROP:
   6815 	case SCF_TERR_WRONG_PROP_TYPE:
   6816 	case SCF_TERR_CARDINALITY_VIOLATION:
   6817 	case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
   6818 	case SCF_TERR_RANGE_VIOLATION:
   6819 	case SCF_TERR_PROP_TYPE_MISMATCH:
   6820 	case SCF_TERR_VALUE_OUT_OF_RANGE:
   6821 	case SCF_TERR_INVALID_VALUE:
   6822 	case SCF_TERR_PG_REDEFINE:
   6823 		if (err->te_tmpl_pg_name != NULL &&
   6824 		    err->te_tmpl_pg_type != NULL) {
   6825 			if (name != NULL)
   6826 				*name = (char *)err->te_tmpl_pg_name;
   6827 			if (type != NULL)
   6828 				*type = (char *)err->te_tmpl_pg_type;
   6829 			return (0);
   6830 		}
   6831 		(void) scf_set_error(SCF_ERROR_NOT_FOUND);
   6832 		break;
   6833 	default:
   6834 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
   6835 	}
   6836 	return (-1);
   6837 }
   6838 
   6839 int
   6840 scf_tmpl_error_pg(const scf_tmpl_error_t *err, char **name, char **type)
   6841 {
   6842 	assert(err != NULL);
   6843 	switch (err->te_type) {
   6844 	case SCF_TERR_WRONG_PG_TYPE:
   6845 		if (err->te_pg_name != NULL &&
   6846 		    err->te_actual != NULL) {
   6847 			if (name != NULL)
   6848 				*name = (char *)err->te_pg_name;
   6849 			if (type != NULL)
   6850 				*type = (char *)err->te_actual;
   6851 			return (0);
   6852 		}
   6853 		(void) scf_set_error(SCF_ERROR_NOT_FOUND);
   6854 		break;
   6855 	case SCF_TERR_WRONG_PROP_TYPE:
   6856 	case SCF_TERR_CARDINALITY_VIOLATION:
   6857 	case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
   6858 	case SCF_TERR_RANGE_VIOLATION:
   6859 		if (err->te_pg_name != NULL &&
   6860 		    err->te_tmpl_pg_type != NULL) {
   6861 			if (name != NULL)
   6862 				*name = (char *)err->te_pg_name;
   6863 			if (type != NULL)
   6864 				*type = (char *)err->te_tmpl_pg_type;
   6865 			return (0);
   6866 		}
   6867 		/*FALLTHROUGH*/
   6868 	case SCF_TERR_MISSING_PROP:
   6869 	case SCF_TERR_MISSING_PG:
   6870 	case SCF_TERR_PROP_TYPE_MISMATCH:
   6871 	case SCF_TERR_VALUE_OUT_OF_RANGE:
   6872 	case SCF_TERR_INVALID_VALUE:
   6873 		(void) scf_set_error(SCF_ERROR_NOT_FOUND);
   6874 		break;
   6875 	case SCF_TERR_PG_REDEFINE:
   6876 		if (err->te_ev1 != NULL && err->te_ev2 != NULL) {
   6877 			if (name != NULL)
   6878 				*name = (char *)err->te_ev1;
   6879 			if (type != NULL)
   6880 				*type = (char *)err->te_ev2;
   6881 			return (0);
   6882 		}
   6883 		(void) scf_set_error(SCF_ERROR_NOT_FOUND);
   6884 		break;
   6885 	default:
   6886 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
   6887 	}
   6888 	return (-1);
   6889 }
   6890 
   6891 int
   6892 scf_tmpl_error_prop_tmpl(const scf_tmpl_error_t *err, char **name, char **type)
   6893 {
   6894 	assert(err != NULL);
   6895 	switch (err->te_type) {
   6896 	case SCF_TERR_MISSING_PROP:
   6897 	case SCF_TERR_WRONG_PROP_TYPE:
   6898 	case SCF_TERR_CARDINALITY_VIOLATION:
   6899 	case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
   6900 	case SCF_TERR_RANGE_VIOLATION:
   6901 	case SCF_TERR_PROP_TYPE_MISMATCH:
   6902 	case SCF_TERR_VALUE_OUT_OF_RANGE:
   6903 	case SCF_TERR_INVALID_VALUE:
   6904 		if (err->te_tmpl_prop_name != NULL &&
   6905 		    err->te_tmpl_prop_type != NULL) {
   6906 			if (name != NULL)
   6907 				*name = (char *)err->te_tmpl_prop_name;
   6908 			if (type != NULL)
   6909 				*type = (char *)err->te_tmpl_prop_type;
   6910 			return (0);
   6911 		}
   6912 		/*FALLTHROUGH*/
   6913 	case SCF_TERR_MISSING_PG:
   6914 	case SCF_TERR_WRONG_PG_TYPE:
   6915 	case SCF_TERR_PG_REDEFINE:
   6916 		(void) scf_set_error(SCF_ERROR_NOT_FOUND);
   6917 		break;
   6918 	default:
   6919 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
   6920 	}
   6921 	return (-1);
   6922 }
   6923 
   6924 int
   6925 scf_tmpl_error_prop(const scf_tmpl_error_t *err, char **name, char **type)
   6926 {
   6927 	assert(err != NULL);
   6928 	switch (err->te_type) {
   6929 	case SCF_TERR_WRONG_PROP_TYPE:
   6930 	case SCF_TERR_CARDINALITY_VIOLATION:
   6931 	case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
   6932 	case SCF_TERR_RANGE_VIOLATION:
   6933 		if (err->te_prop_name != NULL &&
   6934 		    err->te_tmpl_prop_type != NULL) {
   6935 			if (name != NULL)
   6936 				*name = (char *)err->te_prop_name;
   6937 			if (type != NULL)
   6938 				*type = (char *)err->te_tmpl_prop_type;
   6939 			return (0);
   6940 		}
   6941 		/*FALLTHROUGH*/
   6942 	case SCF_TERR_MISSING_PG:
   6943 	case SCF_TERR_WRONG_PG_TYPE:
   6944 	case SCF_TERR_MISSING_PROP:
   6945 	case SCF_TERR_PROP_TYPE_MISMATCH:
   6946 	case SCF_TERR_VALUE_OUT_OF_RANGE:
   6947 	case SCF_TERR_INVALID_VALUE:
   6948 	case SCF_TERR_PG_REDEFINE:
   6949 		(void) scf_set_error(SCF_ERROR_NOT_FOUND);
   6950 		break;
   6951 	default:
   6952 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
   6953 	}
   6954 	return (-1);
   6955 }
   6956 
   6957 int
   6958 scf_tmpl_error_value(const scf_tmpl_error_t *err, char **val)
   6959 {
   6960 	assert(err != NULL);
   6961 	switch (err->te_type) {
   6962 	case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
   6963 	case SCF_TERR_RANGE_VIOLATION:
   6964 	case SCF_TERR_VALUE_OUT_OF_RANGE:
   6965 	case SCF_TERR_INVALID_VALUE:
   6966 		if (err->te_actual != NULL) {
   6967 			if (val != NULL)
   6968 				*val = (char *)err->te_actual;
   6969 			return (0);
   6970 		}
   6971 		/*FALLTHROUGH*/
   6972 	case SCF_TERR_MISSING_PG:
   6973 	case SCF_TERR_WRONG_PG_TYPE:
   6974 	case SCF_TERR_MISSING_PROP:
   6975 	case SCF_TERR_WRONG_PROP_TYPE:
   6976 	case SCF_TERR_CARDINALITY_VIOLATION:
   6977 	case SCF_TERR_PROP_TYPE_MISMATCH:
   6978 	case SCF_TERR_PG_REDEFINE:
   6979 		(void) scf_set_error(SCF_ERROR_NOT_FOUND);
   6980 		break;
   6981 	default:
   6982 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
   6983 	}
   6984 	return (-1);
   6985 }
   6986 
   6987 const char *
   6988 scf_tmpl_visibility_to_string(uint8_t vis)
   6989 {
   6990 	if (vis == SCF_TMPL_VISIBILITY_READONLY)
   6991 		return (SCF_TM_VISIBILITY_READONLY);
   6992 	else if (vis == SCF_TMPL_VISIBILITY_HIDDEN)
   6993 		return (SCF_TM_VISIBILITY_HIDDEN);
   6994 	else if (vis == SCF_TMPL_VISIBILITY_READWRITE)
   6995 		return (SCF_TM_VISIBILITY_READWRITE);
   6996 	else
   6997 		return ("unknown");
   6998 }
   6999