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 /*
     23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 /*
     28  * This is the main implementation file for the low-level repository
     29  * interface.
     30  */
     31 
     32 #include "lowlevel_impl.h"
     33 
     34 #include "repcache_protocol.h"
     35 #include "scf_type.h"
     36 
     37 #include <assert.h>
     38 #include <alloca.h>
     39 #include <door.h>
     40 #include <errno.h>
     41 #include <fcntl.h>
     42 #include <fnmatch.h>
     43 #include <libuutil.h>
     44 #include <poll.h>
     45 #include <pthread.h>
     46 #include <stddef.h>
     47 #include <stdio.h>
     48 #include <stdlib.h>
     49 #include <string.h>
     50 #include <sys/mman.h>
     51 #include <sys/sysmacros.h>
     52 #include <unistd.h>
     53 
     54 #define	ENV_SCF_DEBUG		"LIBSCF_DEBUG"
     55 #define	ENV_SCF_DOORPATH	"LIBSCF_DOORPATH"
     56 
     57 static uint32_t default_debug = 0;
     58 static const char *default_door_path = REPOSITORY_DOOR_NAME;
     59 
     60 #define	CALL_FAILED		-1
     61 #define	RESULT_TOO_BIG		-2
     62 #define	NOT_BOUND		-3
     63 
     64 static pthread_mutex_t	lowlevel_init_lock;
     65 static int32_t		lowlevel_inited;
     66 
     67 static uu_list_pool_t	*tran_entry_pool;
     68 static uu_list_pool_t	*datael_pool;
     69 static uu_list_pool_t	*iter_pool;
     70 
     71 /*
     72  * base32[] index32[] are used in base32 encoding and decoding.
     73  */
     74 static char base32[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
     75 static char index32[128] = {
     76 	-1, -1, -1, -1, -1, -1, -1, -1,	/* 0-7 */
     77 	-1, -1, -1, -1, -1, -1, -1, -1,	/* 8-15 */
     78 	-1, -1, -1, -1, -1, -1, -1, -1,	/* 16-23 */
     79 	-1, -1, -1, -1, -1, -1, -1, -1,	/* 24-31 */
     80 	-1, -1, -1, -1, -1, -1, -1, -1,	/* 32-39 */
     81 	-1, -1, -1, -1, -1, -1, -1, -1,	/* 40-47 */
     82 	-1, -1, 26, 27, 28, 29, 30, 31,	/* 48-55 */
     83 	-1, -1, -1, -1, -1, -1, -1, -1,	/* 56-63 */
     84 	-1, 0, 1, 2, 3, 4, 5, 6,	/* 64-71 */
     85 	7, 8, 9, 10, 11, 12, 13, 14,	/* 72-79 */
     86 	15, 16, 17, 18, 19, 20, 21, 22,	/* 80-87 */
     87 	23, 24, 25, -1, -1, -1, -1, -1,	/* 88-95 */
     88 	-1, -1, -1, -1, -1, -1, -1, -1,	/* 96-103 */
     89 	-1, -1, -1, -1, -1, -1, -1, -1,	/* 104-111 */
     90 	-1, -1, -1, -1, -1, -1, -1, -1,	/* 112-119 */
     91 	-1, -1, -1, -1, -1, -1, -1, -1	/* 120-127 */
     92 };
     93 
     94 #define	DECODE32_GS	(8)	/* scf_decode32 group size */
     95 
     96 /*
     97  * We want MUTEX_HELD, but we also want pthreads.
     98  */
     99 struct _lwp_mutex;
    100 extern int _mutex_held(struct _lwp_mutex *);
    101 #define	MUTEX_HELD(m)		_mutex_held((struct _lwp_mutex *)(m))
    102 
    103 #ifdef lint
    104 #define	assert_nolint(x) (void)0
    105 #else
    106 #define	assert_nolint(x) assert(x)
    107 #endif
    108 
    109 static void scf_iter_reset_locked(scf_iter_t *iter);
    110 static void scf_value_reset_locked(scf_value_t *val, int and_destroy);
    111 
    112 #define	TYPE_VALUE	(-100)
    113 
    114 /*
    115  * Hold and release subhandles.  We only allow one thread access to the
    116  * subhandles at a time, and he can use any subset, grabbing and releasing
    117  * them in any order.  The only restrictions are that you cannot hold an
    118  * already-held subhandle, and all subhandles must be released before
    119  * returning to the original caller.
    120  */
    121 static void
    122 handle_hold_subhandles(scf_handle_t *h, int mask)
    123 {
    124 	assert(mask != 0 && (mask & ~RH_HOLD_ALL) == 0);
    125 
    126 	(void) pthread_mutex_lock(&h->rh_lock);
    127 	while (h->rh_hold_flags != 0 && h->rh_holder != pthread_self()) {
    128 		int cancel_state;
    129 
    130 		(void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,
    131 		    &cancel_state);
    132 		(void) pthread_cond_wait(&h->rh_cv, &h->rh_lock);
    133 		(void) pthread_setcancelstate(cancel_state, NULL);
    134 	}
    135 	if (h->rh_hold_flags == 0)
    136 		h->rh_holder = pthread_self();
    137 	assert(!(h->rh_hold_flags & mask));
    138 	h->rh_hold_flags |= mask;
    139 	(void) pthread_mutex_unlock(&h->rh_lock);
    140 }
    141 
    142 static void
    143 handle_rele_subhandles(scf_handle_t *h, int mask)
    144 {
    145 	assert(mask != 0 && (mask & ~RH_HOLD_ALL) == 0);
    146 
    147 	(void) pthread_mutex_lock(&h->rh_lock);
    148 	assert(h->rh_holder == pthread_self());
    149 	assert((h->rh_hold_flags & mask));
    150 
    151 	h->rh_hold_flags &= ~mask;
    152 	if (h->rh_hold_flags == 0)
    153 		(void) pthread_cond_signal(&h->rh_cv);
    154 	(void) pthread_mutex_unlock(&h->rh_lock);
    155 }
    156 
    157 #define	HOLD_HANDLE(h, flag, field) \
    158 	(handle_hold_subhandles((h), (flag)), (h)->field)
    159 
    160 #define	RELE_HANDLE(h, flag) \
    161 	(handle_rele_subhandles((h), (flag)))
    162 
    163 /*
    164  * convenience macros, for functions that only need a one or two handles at
    165  * any given time
    166  */
    167 #define	HANDLE_HOLD_ITER(h)	HOLD_HANDLE((h), RH_HOLD_ITER, rh_iter)
    168 #define	HANDLE_HOLD_SCOPE(h)	HOLD_HANDLE((h), RH_HOLD_SCOPE, rh_scope)
    169 #define	HANDLE_HOLD_SERVICE(h)	HOLD_HANDLE((h), RH_HOLD_SERVICE, rh_service)
    170 #define	HANDLE_HOLD_INSTANCE(h)	HOLD_HANDLE((h), RH_HOLD_INSTANCE, rh_instance)
    171 #define	HANDLE_HOLD_SNAPSHOT(h)	HOLD_HANDLE((h), RH_HOLD_SNAPSHOT, rh_snapshot)
    172 #define	HANDLE_HOLD_SNAPLVL(h)	HOLD_HANDLE((h), RH_HOLD_SNAPLVL, rh_snaplvl)
    173 #define	HANDLE_HOLD_PG(h)	HOLD_HANDLE((h), RH_HOLD_PG, rh_pg)
    174 #define	HANDLE_HOLD_PROPERTY(h)	HOLD_HANDLE((h), RH_HOLD_PROPERTY, rh_property)
    175 #define	HANDLE_HOLD_VALUE(h)	HOLD_HANDLE((h), RH_HOLD_VALUE, rh_value)
    176 
    177 #define	HANDLE_RELE_ITER(h)	RELE_HANDLE((h), RH_HOLD_ITER)
    178 #define	HANDLE_RELE_SCOPE(h)	RELE_HANDLE((h), RH_HOLD_SCOPE)
    179 #define	HANDLE_RELE_SERVICE(h)	RELE_HANDLE((h), RH_HOLD_SERVICE)
    180 #define	HANDLE_RELE_INSTANCE(h)	RELE_HANDLE((h), RH_HOLD_INSTANCE)
    181 #define	HANDLE_RELE_SNAPSHOT(h)	RELE_HANDLE((h), RH_HOLD_SNAPSHOT)
    182 #define	HANDLE_RELE_SNAPLVL(h)	RELE_HANDLE((h), RH_HOLD_SNAPLVL)
    183 #define	HANDLE_RELE_PG(h)	RELE_HANDLE((h), RH_HOLD_PG)
    184 #define	HANDLE_RELE_PROPERTY(h)	RELE_HANDLE((h), RH_HOLD_PROPERTY)
    185 #define	HANDLE_RELE_VALUE(h)	RELE_HANDLE((h), RH_HOLD_VALUE)
    186 
    187 /*ARGSUSED*/
    188 static int
    189 transaction_entry_compare(const void *l_arg, const void *r_arg, void *private)
    190 {
    191 	const char *l_prop =
    192 	    ((scf_transaction_entry_t *)l_arg)->entry_property;
    193 	const char *r_prop =
    194 	    ((scf_transaction_entry_t *)r_arg)->entry_property;
    195 
    196 	int ret;
    197 
    198 	ret = strcmp(l_prop, r_prop);
    199 	if (ret > 0)
    200 		return (1);
    201 	if (ret < 0)
    202 		return (-1);
    203 	return (0);
    204 }
    205 
    206 static int
    207 datael_compare(const void *l_arg, const void *r_arg, void *private)
    208 {
    209 	uint32_t l_id = ((scf_datael_t *)l_arg)->rd_entity;
    210 	uint32_t r_id = (r_arg != NULL) ? ((scf_datael_t *)r_arg)->rd_entity :
    211 	    *(uint32_t *)private;
    212 
    213 	if (l_id > r_id)
    214 		return (1);
    215 	if (l_id < r_id)
    216 		return (-1);
    217 	return (0);
    218 }
    219 
    220 static int
    221 iter_compare(const void *l_arg, const void *r_arg, void *private)
    222 {
    223 	uint32_t l_id = ((scf_iter_t *)l_arg)->iter_id;
    224 	uint32_t r_id = (r_arg != NULL) ? ((scf_iter_t *)r_arg)->iter_id :
    225 	    *(uint32_t *)private;
    226 
    227 	if (l_id > r_id)
    228 		return (1);
    229 	if (l_id < r_id)
    230 		return (-1);
    231 	return (0);
    232 }
    233 
    234 static int
    235 lowlevel_init(void)
    236 {
    237 	const char *debug;
    238 	const char *door_path;
    239 
    240 	(void) pthread_mutex_lock(&lowlevel_init_lock);
    241 	if (lowlevel_inited == 0) {
    242 		if (!issetugid() &&
    243 		    (debug = getenv(ENV_SCF_DEBUG)) != NULL && debug[0] != 0 &&
    244 		    uu_strtoint(debug, &default_debug, sizeof (default_debug),
    245 		    0, 0, 0) == -1) {
    246 			(void) fprintf(stderr, "LIBSCF: $%s (%s): %s",
    247 			    ENV_SCF_DEBUG, debug,
    248 			    uu_strerror(uu_error()));
    249 		}
    250 
    251 		if (!issetugid() &&
    252 		    (door_path = getenv(ENV_SCF_DOORPATH)) != NULL &&
    253 		    door_path[0] != 0) {
    254 			default_door_path = strdup(door_path);
    255 			if (default_door_path == NULL)
    256 				default_door_path = door_path;
    257 		}
    258 
    259 		datael_pool = uu_list_pool_create("SUNW,libscf_datael",
    260 		    sizeof (scf_datael_t), offsetof(scf_datael_t, rd_node),
    261 		    datael_compare, UU_LIST_POOL_DEBUG);
    262 
    263 		iter_pool = uu_list_pool_create("SUNW,libscf_iter",
    264 		    sizeof (scf_iter_t), offsetof(scf_iter_t, iter_node),
    265 		    iter_compare, UU_LIST_POOL_DEBUG);
    266 
    267 		assert_nolint(offsetof(scf_transaction_entry_t,
    268 		    entry_property) == 0);
    269 		tran_entry_pool = uu_list_pool_create(
    270 		    "SUNW,libscf_transaction_entity",
    271 		    sizeof (scf_transaction_entry_t),
    272 		    offsetof(scf_transaction_entry_t, entry_link),
    273 		    transaction_entry_compare, UU_LIST_POOL_DEBUG);
    274 
    275 		if (datael_pool == NULL || iter_pool == NULL ||
    276 		    tran_entry_pool == NULL) {
    277 			lowlevel_inited = -1;
    278 			goto end;
    279 		}
    280 
    281 		if (!scf_setup_error()) {
    282 			lowlevel_inited = -1;
    283 			goto end;
    284 		}
    285 		lowlevel_inited = 1;
    286 	}
    287 end:
    288 	(void) pthread_mutex_unlock(&lowlevel_init_lock);
    289 	if (lowlevel_inited > 0)
    290 		return (1);
    291 	return (0);
    292 }
    293 
    294 static const struct {
    295 	scf_type_t ti_type;
    296 	rep_protocol_value_type_t ti_proto_type;
    297 	const char *ti_name;
    298 } scf_type_info[] = {
    299 	{SCF_TYPE_BOOLEAN,	REP_PROTOCOL_TYPE_BOOLEAN,	"boolean"},
    300 	{SCF_TYPE_COUNT,	REP_PROTOCOL_TYPE_COUNT,	"count"},
    301 	{SCF_TYPE_INTEGER,	REP_PROTOCOL_TYPE_INTEGER,	"integer"},
    302 	{SCF_TYPE_TIME,		REP_PROTOCOL_TYPE_TIME,		"time"},
    303 	{SCF_TYPE_ASTRING,	REP_PROTOCOL_TYPE_STRING,	"astring"},
    304 	{SCF_TYPE_OPAQUE,	REP_PROTOCOL_TYPE_OPAQUE,	"opaque"},
    305 	{SCF_TYPE_USTRING,	REP_PROTOCOL_SUBTYPE_USTRING,	"ustring"},
    306 	{SCF_TYPE_URI,		REP_PROTOCOL_SUBTYPE_URI,	"uri"},
    307 	{SCF_TYPE_FMRI,		REP_PROTOCOL_SUBTYPE_FMRI,	"fmri"},
    308 	{SCF_TYPE_HOST,		REP_PROTOCOL_SUBTYPE_HOST,	"host"},
    309 	{SCF_TYPE_HOSTNAME,	REP_PROTOCOL_SUBTYPE_HOSTNAME,	"hostname"},
    310 	{SCF_TYPE_NET_ADDR_V4,	REP_PROTOCOL_SUBTYPE_NETADDR_V4,
    311 	    "net_address_v4"},
    312 	{SCF_TYPE_NET_ADDR_V6,	REP_PROTOCOL_SUBTYPE_NETADDR_V6,
    313 	    "net_address_v6"}
    314 };
    315 
    316 #define	SCF_TYPE_INFO_COUNT (sizeof (scf_type_info) / sizeof (*scf_type_info))
    317 static rep_protocol_value_type_t
    318 scf_type_to_protocol_type(scf_type_t t)
    319 {
    320 	int i;
    321 
    322 	for (i = 0; i < SCF_TYPE_INFO_COUNT; i++)
    323 		if (scf_type_info[i].ti_type == t)
    324 			return (scf_type_info[i].ti_proto_type);
    325 
    326 	return (REP_PROTOCOL_TYPE_INVALID);
    327 }
    328 
    329 static scf_type_t
    330 scf_protocol_type_to_type(rep_protocol_value_type_t t)
    331 {
    332 	int i;
    333 
    334 	for (i = 0; i < SCF_TYPE_INFO_COUNT; i++)
    335 		if (scf_type_info[i].ti_proto_type == t)
    336 			return (scf_type_info[i].ti_type);
    337 
    338 	return (SCF_TYPE_INVALID);
    339 }
    340 
    341 const char *
    342 scf_type_to_string(scf_type_t ty)
    343 {
    344 	int i;
    345 
    346 	for (i = 0; i < SCF_TYPE_INFO_COUNT; i++)
    347 		if (scf_type_info[i].ti_type == ty)
    348 			return (scf_type_info[i].ti_name);
    349 
    350 	return ("unknown");
    351 }
    352 
    353 scf_type_t
    354 scf_string_to_type(const char *name)
    355 {
    356 	int i;
    357 
    358 	for (i = 0; i < sizeof (scf_type_info) / sizeof (*scf_type_info); i++)
    359 		if (strcmp(scf_type_info[i].ti_name, name) == 0)
    360 			return (scf_type_info[i].ti_type);
    361 
    362 	return (SCF_TYPE_INVALID);
    363 }
    364 
    365 int
    366 scf_type_base_type(scf_type_t type, scf_type_t *out)
    367 {
    368 	rep_protocol_value_type_t t = scf_type_to_protocol_type(type);
    369 	if (t == REP_PROTOCOL_TYPE_INVALID)
    370 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
    371 
    372 	*out = scf_protocol_type_to_type(scf_proto_underlying_type(t));
    373 	return (SCF_SUCCESS);
    374 }
    375 
    376 /*
    377  * Convert a protocol error code into an SCF_ERROR_* code.
    378  */
    379 static scf_error_t
    380 proto_error(rep_protocol_responseid_t e)
    381 {
    382 	switch (e) {
    383 	case REP_PROTOCOL_FAIL_MISORDERED:
    384 	case REP_PROTOCOL_FAIL_UNKNOWN_ID:
    385 	case REP_PROTOCOL_FAIL_INVALID_TYPE:
    386 	case REP_PROTOCOL_FAIL_TRUNCATED:
    387 	case REP_PROTOCOL_FAIL_TYPE_MISMATCH:
    388 	case REP_PROTOCOL_FAIL_NOT_APPLICABLE:
    389 	case REP_PROTOCOL_FAIL_UNKNOWN:
    390 		return (SCF_ERROR_INTERNAL);
    391 
    392 	case REP_PROTOCOL_FAIL_BAD_TX:
    393 		return (SCF_ERROR_INVALID_ARGUMENT);
    394 	case REP_PROTOCOL_FAIL_BAD_REQUEST:
    395 		return (SCF_ERROR_INVALID_ARGUMENT);
    396 	case REP_PROTOCOL_FAIL_NO_RESOURCES:
    397 		return (SCF_ERROR_NO_RESOURCES);
    398 	case REP_PROTOCOL_FAIL_NOT_FOUND:
    399 		return (SCF_ERROR_NOT_FOUND);
    400 	case REP_PROTOCOL_FAIL_DELETED:
    401 		return (SCF_ERROR_DELETED);
    402 	case REP_PROTOCOL_FAIL_NOT_SET:
    403 		return (SCF_ERROR_NOT_SET);
    404 	case REP_PROTOCOL_FAIL_EXISTS:
    405 		return (SCF_ERROR_EXISTS);
    406 	case REP_PROTOCOL_FAIL_DUPLICATE_ID:
    407 		return (SCF_ERROR_EXISTS);
    408 	case REP_PROTOCOL_FAIL_PERMISSION_DENIED:
    409 		return (SCF_ERROR_PERMISSION_DENIED);
    410 	case REP_PROTOCOL_FAIL_BACKEND_ACCESS:
    411 		return (SCF_ERROR_BACKEND_ACCESS);
    412 	case REP_PROTOCOL_FAIL_BACKEND_READONLY:
    413 		return (SCF_ERROR_BACKEND_READONLY);
    414 
    415 	case REP_PROTOCOL_SUCCESS:
    416 	case REP_PROTOCOL_DONE:
    417 	case REP_PROTOCOL_FAIL_NOT_LATEST:	/* TX code should handle this */
    418 	default:
    419 #ifndef NDEBUG
    420 		uu_warn("%s:%d: Bad error code %d passed to proto_error().\n",
    421 		    __FILE__, __LINE__, e);
    422 #endif
    423 		abort();
    424 		/*NOTREACHED*/
    425 	}
    426 }
    427 
    428 ssize_t
    429 scf_limit(uint32_t limit)
    430 {
    431 	switch (limit) {
    432 	case SCF_LIMIT_MAX_NAME_LENGTH:
    433 	case SCF_LIMIT_MAX_PG_TYPE_LENGTH:
    434 		return (REP_PROTOCOL_NAME_LEN - 1);
    435 	case SCF_LIMIT_MAX_VALUE_LENGTH:
    436 		return (REP_PROTOCOL_VALUE_LEN - 1);
    437 	case SCF_LIMIT_MAX_FMRI_LENGTH:
    438 		return (SCF_FMRI_PREFIX_MAX_LEN +
    439 		    sizeof (SCF_FMRI_SCOPE_PREFIX) - 1 +
    440 		    sizeof (SCF_FMRI_SCOPE_SUFFIX) - 1 +
    441 		    sizeof (SCF_FMRI_SERVICE_PREFIX) - 1 +
    442 		    sizeof (SCF_FMRI_INSTANCE_PREFIX) - 1 +
    443 		    sizeof (SCF_FMRI_PROPERTYGRP_PREFIX) - 1 +
    444 		    sizeof (SCF_FMRI_PROPERTY_PREFIX) - 1 +
    445 		    5 * (REP_PROTOCOL_NAME_LEN - 1));
    446 	default:
    447 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
    448 	}
    449 }
    450 
    451 static size_t
    452 scf_opaque_decode(char *out_arg, const char *in, size_t max_out)
    453 {
    454 	char a, b;
    455 	char *out = out_arg;
    456 
    457 	while (max_out > 0 && (a = in[0]) != 0 && (b = in[1]) != 0) {
    458 		in += 2;
    459 
    460 		if (a >= '0' && a <= '9')
    461 			a -= '0';
    462 		else if (a >= 'a' && a <= 'f')
    463 			a = a - 'a' + 10;
    464 		else if (a >= 'A' && a <= 'F')
    465 			a = a - 'A' + 10;
    466 		else
    467 			break;
    468 
    469 		if (b >= '0' && b <= '9')
    470 			b -= '0';
    471 		else if (b >= 'a' && b <= 'f')
    472 			b = b - 'a' + 10;
    473 		else if (b >= 'A' && b <= 'F')
    474 			b = b - 'A' + 10;
    475 		else
    476 			break;
    477 
    478 		*out++ = (a << 4) | b;
    479 		max_out--;
    480 	}
    481 
    482 	return (out - out_arg);
    483 }
    484 
    485 static size_t
    486 scf_opaque_encode(char *out_arg, const char *in_arg, size_t in_sz)
    487 {
    488 	uint8_t *in = (uint8_t *)in_arg;
    489 	uint8_t *end = in + in_sz;
    490 	char *out = out_arg;
    491 
    492 	if (out == NULL)
    493 		return (2 * in_sz);
    494 
    495 	while (in < end) {
    496 		uint8_t c = *in++;
    497 
    498 		uint8_t a = (c & 0xf0) >> 4;
    499 		uint8_t b = (c & 0x0f);
    500 
    501 		if (a <= 9)
    502 			*out++ = a + '0';
    503 		else
    504 			*out++ = a + 'a' - 10;
    505 
    506 		if (b <= 9)
    507 			*out++ = b + '0';
    508 		else
    509 			*out++ = b + 'a' - 10;
    510 	}
    511 
    512 	*out = 0;
    513 
    514 	return (out - out_arg);
    515 }
    516 
    517 static void
    518 handle_do_close(scf_handle_t *h)
    519 {
    520 	assert(MUTEX_HELD(&h->rh_lock));
    521 	assert(h->rh_doorfd != -1);
    522 
    523 	/*
    524 	 * if there are any active FD users, we just move the FD over
    525 	 * to rh_doorfd_old -- they'll close it when they finish.
    526 	 */
    527 	if (h->rh_fd_users > 0) {
    528 		h->rh_doorfd_old = h->rh_doorfd;
    529 		h->rh_doorfd = -1;
    530 	} else {
    531 		assert(h->rh_doorfd_old == -1);
    532 		(void) close(h->rh_doorfd);
    533 		h->rh_doorfd = -1;
    534 	}
    535 }
    536 
    537 /*
    538  * Check if a handle is currently bound.  fork()ing implicitly unbinds
    539  * the handle in the child.
    540  */
    541 static int
    542 handle_is_bound(scf_handle_t *h)
    543 {
    544 	assert(MUTEX_HELD(&h->rh_lock));
    545 
    546 	if (h->rh_doorfd == -1)
    547 		return (0);
    548 
    549 	if (getpid() == h->rh_doorpid)
    550 		return (1);
    551 
    552 	/* forked since our last bind -- initiate handle close */
    553 	handle_do_close(h);
    554 	return (0);
    555 }
    556 
    557 static int
    558 handle_has_server_locked(scf_handle_t *h)
    559 {
    560 	door_info_t i;
    561 	assert(MUTEX_HELD(&h->rh_lock));
    562 
    563 	return (handle_is_bound(h) && door_info(h->rh_doorfd, &i) != -1 &&
    564 	    i.di_target != -1);
    565 }
    566 
    567 static int
    568 handle_has_server(scf_handle_t *h)
    569 {
    570 	int ret;
    571 
    572 	(void) pthread_mutex_lock(&h->rh_lock);
    573 	ret = handle_has_server_locked(h);
    574 	(void) pthread_mutex_unlock(&h->rh_lock);
    575 
    576 	return (ret);
    577 }
    578 
    579 /*
    580  * This makes a door request on the client door associated with handle h.
    581  * It will automatically retry calls which fail on EINTR.  If h is not bound,
    582  * returns NOT_BOUND.  If the door call fails or the server response is too
    583  * small, returns CALL_FAILED.  If the server response is too big, truncates the
    584  * response and returns RESULT_TOO_BIG.  Otherwise, the size of the result is
    585  * returned.
    586  */
    587 static ssize_t
    588 make_door_call(scf_handle_t *h, const void *req, size_t req_sz,
    589     void *res, size_t res_sz)
    590 {
    591 	door_arg_t arg;
    592 	int r;
    593 
    594 	assert(MUTEX_HELD(&h->rh_lock));
    595 
    596 	if (!handle_is_bound(h)) {
    597 		return (NOT_BOUND);
    598 	}
    599 
    600 	arg.data_ptr = (void *)req;
    601 	arg.data_size = req_sz;
    602 	arg.desc_ptr = NULL;
    603 	arg.desc_num = 0;
    604 	arg.rbuf = res;
    605 	arg.rsize = res_sz;
    606 
    607 	while ((r = door_call(h->rh_doorfd, &arg)) < 0) {
    608 		if (errno != EINTR)
    609 			break;
    610 	}
    611 
    612 	if (r < 0) {
    613 		return (CALL_FAILED);
    614 	}
    615 
    616 	if (arg.desc_num > 0) {
    617 		while (arg.desc_num > 0) {
    618 			if (arg.desc_ptr->d_attributes & DOOR_DESCRIPTOR) {
    619 				int cfd = arg.desc_ptr->d_data.d_desc.d_id;
    620 				(void) close(cfd);
    621 			}
    622 			arg.desc_ptr++;
    623 			arg.desc_num--;
    624 		}
    625 	}
    626 	if (arg.data_ptr != res && arg.data_size > 0)
    627 		(void) memmove(res, arg.data_ptr, MIN(arg.data_size, res_sz));
    628 
    629 	if (arg.rbuf != res)
    630 		(void) munmap(arg.rbuf, arg.rsize);
    631 
    632 	if (arg.data_size > res_sz)
    633 		return (RESULT_TOO_BIG);
    634 
    635 	if (arg.data_size < sizeof (uint32_t))
    636 		return (CALL_FAILED);
    637 
    638 	return (arg.data_size);
    639 }
    640 
    641 /*
    642  * Should only be used when r < 0.
    643  */
    644 #define	DOOR_ERRORS_BLOCK(r)	{					\
    645 	switch (r) {							\
    646 	case NOT_BOUND:							\
    647 		return (scf_set_error(SCF_ERROR_NOT_BOUND));		\
    648 									\
    649 	case CALL_FAILED:						\
    650 		return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN));	\
    651 									\
    652 	case RESULT_TOO_BIG:						\
    653 		return (scf_set_error(SCF_ERROR_INTERNAL));		\
    654 									\
    655 	default:							\
    656 		assert(r == NOT_BOUND || r == CALL_FAILED ||		\
    657 		    r == RESULT_TOO_BIG);				\
    658 		abort();						\
    659 	}								\
    660 }
    661 
    662 /*
    663  * Like make_door_call(), but takes an fd instead of a handle, and expects
    664  * a single file descriptor, returned via res_fd.
    665  *
    666  * If no file descriptor is returned, *res_fd == -1.
    667  */
    668 static int
    669 make_door_call_retfd(int fd, const void *req, size_t req_sz, void *res,
    670     size_t res_sz, int *res_fd)
    671 {
    672 	door_arg_t arg;
    673 	int r;
    674 	char rbuf[256];
    675 
    676 	*res_fd = -1;
    677 
    678 	if (fd == -1)
    679 		return (NOT_BOUND);
    680 
    681 	arg.data_ptr = (void *)req;
    682 	arg.data_size = req_sz;
    683 	arg.desc_ptr = NULL;
    684 	arg.desc_num = 0;
    685 	arg.rbuf = rbuf;
    686 	arg.rsize = sizeof (rbuf);
    687 
    688 	while ((r = door_call(fd, &arg)) < 0) {
    689 		if (errno != EINTR)
    690 			break;
    691 	}
    692 
    693 	if (r < 0)
    694 		return (CALL_FAILED);
    695 
    696 	if (arg.desc_num > 1) {
    697 		while (arg.desc_num > 0) {
    698 			if (arg.desc_ptr->d_attributes & DOOR_DESCRIPTOR) {
    699 				int cfd =
    700 				    arg.desc_ptr->d_data.d_desc.d_descriptor;
    701 				(void) close(cfd);
    702 			}
    703 			arg.desc_ptr++;
    704 			arg.desc_num--;
    705 		}
    706 	}
    707 	if (arg.desc_num == 1 && arg.desc_ptr->d_attributes & DOOR_DESCRIPTOR)
    708 		*res_fd = arg.desc_ptr->d_data.d_desc.d_descriptor;
    709 
    710 	if (arg.data_size > 0)
    711 		(void) memmove(res, arg.data_ptr, MIN(arg.data_size, res_sz));
    712 
    713 	if (arg.rbuf != rbuf)
    714 		(void) munmap(arg.rbuf, arg.rsize);
    715 
    716 	if (arg.data_size > res_sz)
    717 		return (RESULT_TOO_BIG);
    718 
    719 	if (arg.data_size < sizeof (uint32_t))
    720 		return (CALL_FAILED);
    721 
    722 	return (arg.data_size);
    723 }
    724 
    725 /*
    726  * Fails with
    727  *   _VERSION_MISMATCH
    728  *   _NO_MEMORY
    729  */
    730 scf_handle_t *
    731 scf_handle_create(scf_version_t v)
    732 {
    733 	scf_handle_t *ret;
    734 	int failed;
    735 
    736 	/*
    737 	 * This will need to be revisited when we bump SCF_VERSION
    738 	 */
    739 	if (v != SCF_VERSION) {
    740 		(void) scf_set_error(SCF_ERROR_VERSION_MISMATCH);
    741 		return (NULL);
    742 	}
    743 
    744 	if (!lowlevel_init()) {
    745 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
    746 		return (NULL);
    747 	}
    748 
    749 	ret = uu_zalloc(sizeof (*ret));
    750 	if (ret == NULL) {
    751 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
    752 		return (NULL);
    753 	}
    754 
    755 	ret->rh_dataels = uu_list_create(datael_pool, ret, 0);
    756 	ret->rh_iters = uu_list_create(iter_pool, ret, 0);
    757 	if (ret->rh_dataels == NULL || ret->rh_iters == NULL) {
    758 		if (ret->rh_dataels != NULL)
    759 			uu_list_destroy(ret->rh_dataels);
    760 		if (ret->rh_iters != NULL)
    761 			uu_list_destroy(ret->rh_iters);
    762 		uu_free(ret);
    763 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
    764 		return (NULL);
    765 	}
    766 
    767 	ret->rh_doorfd = -1;
    768 	ret->rh_doorfd_old = -1;
    769 	(void) pthread_mutex_init(&ret->rh_lock, NULL);
    770 
    771 	handle_hold_subhandles(ret, RH_HOLD_ALL);
    772 
    773 	failed = ((ret->rh_iter = scf_iter_create(ret)) == NULL ||
    774 	    (ret->rh_scope = scf_scope_create(ret)) == NULL ||
    775 	    (ret->rh_service = scf_service_create(ret)) == NULL ||
    776 	    (ret->rh_instance = scf_instance_create(ret)) == NULL ||
    777 	    (ret->rh_snapshot = scf_snapshot_create(ret)) == NULL ||
    778 	    (ret->rh_snaplvl = scf_snaplevel_create(ret)) == NULL ||
    779 	    (ret->rh_pg = scf_pg_create(ret)) == NULL ||
    780 	    (ret->rh_property = scf_property_create(ret)) == NULL ||
    781 	    (ret->rh_value = scf_value_create(ret)) == NULL);
    782 
    783 	/*
    784 	 * these subhandles count as internal references, not external ones.
    785 	 */
    786 	ret->rh_intrefs = ret->rh_extrefs;
    787 	ret->rh_extrefs = 0;
    788 	handle_rele_subhandles(ret, RH_HOLD_ALL);
    789 
    790 	if (failed) {
    791 		scf_handle_destroy(ret);
    792 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
    793 		return (NULL);
    794 	}
    795 
    796 	scf_value_set_count(ret->rh_value, default_debug);
    797 	(void) scf_handle_decorate(ret, "debug", ret->rh_value);
    798 
    799 	return (ret);
    800 }
    801 
    802 int
    803 scf_handle_decorate(scf_handle_t *handle, const char *name, scf_value_t *v)
    804 {
    805 	if (v != SCF_DECORATE_CLEAR && handle != v->value_handle)
    806 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
    807 
    808 	(void) pthread_mutex_lock(&handle->rh_lock);
    809 	if (handle_is_bound(handle)) {
    810 		(void) pthread_mutex_unlock(&handle->rh_lock);
    811 		return (scf_set_error(SCF_ERROR_IN_USE));
    812 	}
    813 	(void) pthread_mutex_unlock(&handle->rh_lock);
    814 
    815 	if (strcmp(name, "debug") == 0) {
    816 		if (v == SCF_DECORATE_CLEAR) {
    817 			(void) pthread_mutex_lock(&handle->rh_lock);
    818 			handle->rh_debug = 0;
    819 			(void) pthread_mutex_unlock(&handle->rh_lock);
    820 		} else {
    821 			uint64_t val;
    822 			if (scf_value_get_count(v, &val) < 0)
    823 				return (-1);		/* error already set */
    824 
    825 			(void) pthread_mutex_lock(&handle->rh_lock);
    826 			handle->rh_debug = (uid_t)val;
    827 			(void) pthread_mutex_unlock(&handle->rh_lock);
    828 		}
    829 		return (0);
    830 	}
    831 	if (strcmp(name, "door_path") == 0) {
    832 		char name[sizeof (handle->rh_doorpath)];
    833 
    834 		if (v == SCF_DECORATE_CLEAR) {
    835 			(void) pthread_mutex_lock(&handle->rh_lock);
    836 			handle->rh_doorpath[0] = 0;
    837 			(void) pthread_mutex_unlock(&handle->rh_lock);
    838 		} else {
    839 			ssize_t len;
    840 
    841 			if ((len = scf_value_get_astring(v, name,
    842 			    sizeof (name))) < 0) {
    843 				return (-1);		/* error already set */
    844 			}
    845 			if (len == 0 || len >= sizeof (name)) {
    846 				return (scf_set_error(
    847 				    SCF_ERROR_INVALID_ARGUMENT));
    848 			}
    849 			(void) pthread_mutex_lock(&handle->rh_lock);
    850 			(void) strlcpy(handle->rh_doorpath, name,
    851 			    sizeof (handle->rh_doorpath));
    852 			(void) pthread_mutex_unlock(&handle->rh_lock);
    853 		}
    854 		return (0);
    855 	}
    856 	return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
    857 }
    858 
    859 /*
    860  * fails with INVALID_ARGUMENT and HANDLE_MISMATCH.
    861  */
    862 int
    863 _scf_handle_decorations(scf_handle_t *handle, scf_decoration_func *f,
    864     scf_value_t *v, void *data)
    865 {
    866 	scf_decoration_info_t i;
    867 	char name[sizeof (handle->rh_doorpath)];
    868 	uint64_t debug;
    869 
    870 	if (f == NULL || v == NULL)
    871 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
    872 
    873 	if (v->value_handle != handle)
    874 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
    875 
    876 	i.sdi_name = (const char *)"debug";
    877 	i.sdi_type = SCF_TYPE_COUNT;
    878 	(void) pthread_mutex_lock(&handle->rh_lock);
    879 	debug = handle->rh_debug;
    880 	(void) pthread_mutex_unlock(&handle->rh_lock);
    881 	if (debug != 0) {
    882 		scf_value_set_count(v, debug);
    883 		i.sdi_value = v;
    884 	} else {
    885 		i.sdi_value = SCF_DECORATE_CLEAR;
    886 	}
    887 
    888 	if ((*f)(&i, data) == 0)
    889 		return (0);
    890 
    891 	i.sdi_name = (const char *)"door_path";
    892 	i.sdi_type = SCF_TYPE_ASTRING;
    893 	(void) pthread_mutex_lock(&handle->rh_lock);
    894 	(void) strlcpy(name, handle->rh_doorpath, sizeof (name));
    895 	(void) pthread_mutex_unlock(&handle->rh_lock);
    896 	if (name[0] != 0) {
    897 		(void) scf_value_set_astring(v, name);
    898 		i.sdi_value = v;
    899 	} else {
    900 		i.sdi_value = SCF_DECORATE_CLEAR;
    901 	}
    902 
    903 	if ((*f)(&i, data) == 0)
    904 		return (0);
    905 
    906 	return (1);
    907 }
    908 
    909 /*
    910  * Fails if handle is not bound.
    911  */
    912 static int
    913 handle_unbind_unlocked(scf_handle_t *handle)
    914 {
    915 	rep_protocol_request_t request;
    916 	rep_protocol_response_t response;
    917 
    918 	if (!handle_is_bound(handle))
    919 		return (-1);
    920 
    921 	request.rpr_request = REP_PROTOCOL_CLOSE;
    922 
    923 	(void) make_door_call(handle, &request, sizeof (request),
    924 	    &response, sizeof (response));
    925 
    926 	handle_do_close(handle);
    927 
    928 	return (SCF_SUCCESS);
    929 }
    930 
    931 /*
    932  * Fails with
    933  *   _HANDLE_DESTROYED - dp's handle has been destroyed
    934  *   _INTERNAL - server response too big
    935  *		 entity already set up with different type
    936  *   _NO_RESOURCES - server out of memory
    937  */
    938 static int
    939 datael_attach(scf_datael_t *dp)
    940 {
    941 	scf_handle_t *h = dp->rd_handle;
    942 
    943 	struct rep_protocol_entity_setup request;
    944 	rep_protocol_response_t response;
    945 	ssize_t r;
    946 
    947 	assert(MUTEX_HELD(&h->rh_lock));
    948 
    949 	dp->rd_reset = 0;		/* setup implicitly resets */
    950 
    951 	if (h->rh_flags & HANDLE_DEAD)
    952 		return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED));
    953 
    954 	if (!handle_is_bound(h))
    955 		return (SCF_SUCCESS);		/* nothing to do */
    956 
    957 	request.rpr_request = REP_PROTOCOL_ENTITY_SETUP;
    958 	request.rpr_entityid = dp->rd_entity;
    959 	request.rpr_entitytype = dp->rd_type;
    960 
    961 	r = make_door_call(h, &request, sizeof (request),
    962 	    &response, sizeof (response));
    963 
    964 	if (r == NOT_BOUND || r == CALL_FAILED)
    965 		return (SCF_SUCCESS);
    966 	if (r == RESULT_TOO_BIG)
    967 		return (scf_set_error(SCF_ERROR_INTERNAL));
    968 
    969 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
    970 		return (scf_set_error(proto_error(response.rpr_response)));
    971 
    972 	return (SCF_SUCCESS);
    973 }
    974 
    975 /*
    976  * Fails with
    977  *   _HANDLE_DESTROYED - iter's handle has been destroyed
    978  *   _INTERNAL - server response too big
    979  *		 iter already existed
    980  *   _NO_RESOURCES
    981  */
    982 static int
    983 iter_attach(scf_iter_t *iter)
    984 {
    985 	scf_handle_t *h = iter->iter_handle;
    986 	struct rep_protocol_iter_request request;
    987 	struct rep_protocol_response response;
    988 	int r;
    989 
    990 	assert(MUTEX_HELD(&h->rh_lock));
    991 
    992 	if (h->rh_flags & HANDLE_DEAD)
    993 		return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED));
    994 
    995 	if (!handle_is_bound(h))
    996 		return (SCF_SUCCESS);		/* nothing to do */
    997 
    998 	request.rpr_request = REP_PROTOCOL_ITER_SETUP;
    999 	request.rpr_iterid = iter->iter_id;
   1000 
   1001 	r = make_door_call(h, &request, sizeof (request),
   1002 	    &response, sizeof (response));
   1003 
   1004 	if (r == NOT_BOUND || r == CALL_FAILED)
   1005 		return (SCF_SUCCESS);
   1006 	if (r == RESULT_TOO_BIG)
   1007 		return (scf_set_error(SCF_ERROR_INTERNAL));
   1008 
   1009 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
   1010 		return (scf_set_error(proto_error(response.rpr_response)));
   1011 
   1012 	return (SCF_SUCCESS);
   1013 }
   1014 
   1015 /*
   1016  * Fails with
   1017  *   _IN_USE - handle already bound
   1018  *   _NO_SERVER - server door could not be open()ed
   1019  *		  door call failed
   1020  *		  door_info() failed
   1021  *   _VERSION_MISMATCH - server returned bad file descriptor
   1022  *			 server claimed bad request
   1023  *			 server reported version mismatch
   1024  *			 server refused with unknown reason
   1025  *   _INVALID_ARGUMENT
   1026  *   _NO_RESOURCES - server is out of memory
   1027  *   _PERMISSION_DENIED
   1028  *   _INTERNAL - could not set up entities or iters
   1029  *		 server response too big
   1030  *
   1031  * perhaps this should try multiple times.
   1032  */
   1033 int
   1034 scf_handle_bind(scf_handle_t *handle)
   1035 {
   1036 	scf_datael_t *el;
   1037 	scf_iter_t *iter;
   1038 
   1039 	pid_t pid;
   1040 	int fd;
   1041 	int res;
   1042 	door_info_t info;
   1043 	repository_door_request_t request;
   1044 	repository_door_response_t response;
   1045 	const char *door_name = default_door_path;
   1046 
   1047 	(void) pthread_mutex_lock(&handle->rh_lock);
   1048 	if (handle_is_bound(handle)) {
   1049 		(void) pthread_mutex_unlock(&handle->rh_lock);
   1050 		return (scf_set_error(SCF_ERROR_IN_USE));
   1051 	}
   1052 
   1053 	/* wait until any active fd users have cleared out */
   1054 	while (handle->rh_fd_users > 0) {
   1055 		int cancel_state;
   1056 
   1057 		(void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,
   1058 		    &cancel_state);
   1059 		(void) pthread_cond_wait(&handle->rh_cv, &handle->rh_lock);
   1060 		(void) pthread_setcancelstate(cancel_state, NULL);
   1061 	}
   1062 
   1063 	/* check again, since we had to drop the lock */
   1064 	if (handle_is_bound(handle)) {
   1065 		(void) pthread_mutex_unlock(&handle->rh_lock);
   1066 		return (scf_set_error(SCF_ERROR_IN_USE));
   1067 	}
   1068 
   1069 	assert(handle->rh_doorfd == -1 && handle->rh_doorfd_old == -1);
   1070 
   1071 	if (handle->rh_doorpath[0] != 0)
   1072 		door_name = handle->rh_doorpath;
   1073 
   1074 	fd = open(door_name, O_RDONLY, 0);
   1075 	if (fd == -1) {
   1076 		(void) pthread_mutex_unlock(&handle->rh_lock);
   1077 		return (scf_set_error(SCF_ERROR_NO_SERVER));
   1078 	}
   1079 
   1080 	request.rdr_version = REPOSITORY_DOOR_VERSION;
   1081 	request.rdr_request = REPOSITORY_DOOR_REQUEST_CONNECT;
   1082 	request.rdr_flags = handle->rh_flags;
   1083 	request.rdr_debug = handle->rh_debug;
   1084 
   1085 	pid = getpid();
   1086 
   1087 	res = make_door_call_retfd(fd, &request, sizeof (request),
   1088 	    &response, sizeof (response), &handle->rh_doorfd);
   1089 
   1090 	(void) close(fd);
   1091 
   1092 	if (res < 0) {
   1093 		(void) pthread_mutex_unlock(&handle->rh_lock);
   1094 
   1095 		assert(res != NOT_BOUND);
   1096 		if (res == CALL_FAILED)
   1097 			return (scf_set_error(SCF_ERROR_NO_SERVER));
   1098 		assert(res == RESULT_TOO_BIG);
   1099 		return (scf_set_error(SCF_ERROR_INTERNAL));
   1100 	}
   1101 
   1102 	if (handle->rh_doorfd < 0) {
   1103 		(void) pthread_mutex_unlock(&handle->rh_lock);
   1104 
   1105 		switch (response.rdr_status) {
   1106 		case REPOSITORY_DOOR_SUCCESS:
   1107 			return (scf_set_error(SCF_ERROR_VERSION_MISMATCH));
   1108 
   1109 		case REPOSITORY_DOOR_FAIL_BAD_REQUEST:
   1110 			return (scf_set_error(SCF_ERROR_VERSION_MISMATCH));
   1111 
   1112 		case REPOSITORY_DOOR_FAIL_VERSION_MISMATCH:
   1113 			return (scf_set_error(SCF_ERROR_VERSION_MISMATCH));
   1114 
   1115 		case REPOSITORY_DOOR_FAIL_BAD_FLAG:
   1116 			return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
   1117 
   1118 		case REPOSITORY_DOOR_FAIL_NO_RESOURCES:
   1119 			return (scf_set_error(SCF_ERROR_NO_RESOURCES));
   1120 
   1121 		case REPOSITORY_DOOR_FAIL_PERMISSION_DENIED:
   1122 			return (scf_set_error(SCF_ERROR_PERMISSION_DENIED));
   1123 
   1124 		default:
   1125 			return (scf_set_error(SCF_ERROR_VERSION_MISMATCH));
   1126 		}
   1127 	}
   1128 
   1129 	(void) fcntl(handle->rh_doorfd, F_SETFD, FD_CLOEXEC);
   1130 
   1131 	if (door_info(handle->rh_doorfd, &info) < 0) {
   1132 		(void) close(handle->rh_doorfd);
   1133 		handle->rh_doorfd = -1;
   1134 
   1135 		(void) pthread_mutex_unlock(&handle->rh_lock);
   1136 		return (scf_set_error(SCF_ERROR_NO_SERVER));
   1137 	}
   1138 
   1139 	handle->rh_doorpid = pid;
   1140 	handle->rh_doorid = info.di_uniquifier;
   1141 
   1142 	/*
   1143 	 * Now, re-attach everything
   1144 	 */
   1145 	for (el = uu_list_first(handle->rh_dataels); el != NULL;
   1146 	    el = uu_list_next(handle->rh_dataels, el)) {
   1147 		if (datael_attach(el) == -1) {
   1148 			assert(scf_error() != SCF_ERROR_HANDLE_DESTROYED);
   1149 			(void) handle_unbind_unlocked(handle);
   1150 			(void) pthread_mutex_unlock(&handle->rh_lock);
   1151 			return (-1);
   1152 		}
   1153 	}
   1154 
   1155 	for (iter = uu_list_first(handle->rh_iters); iter != NULL;
   1156 	    iter = uu_list_next(handle->rh_iters, iter)) {
   1157 		if (iter_attach(iter) == -1) {
   1158 			assert(scf_error() != SCF_ERROR_HANDLE_DESTROYED);
   1159 			(void) handle_unbind_unlocked(handle);
   1160 			(void) pthread_mutex_unlock(&handle->rh_lock);
   1161 			return (-1);
   1162 		}
   1163 	}
   1164 	(void) pthread_mutex_unlock(&handle->rh_lock);
   1165 	return (SCF_SUCCESS);
   1166 }
   1167 
   1168 int
   1169 scf_handle_unbind(scf_handle_t *handle)
   1170 {
   1171 	int ret;
   1172 	(void) pthread_mutex_lock(&handle->rh_lock);
   1173 	ret = handle_unbind_unlocked(handle);
   1174 	(void) pthread_mutex_unlock(&handle->rh_lock);
   1175 	return (ret == SCF_SUCCESS ? ret : scf_set_error(SCF_ERROR_NOT_BOUND));
   1176 }
   1177 
   1178 static scf_handle_t *
   1179 handle_get(scf_handle_t *h)
   1180 {
   1181 	(void) pthread_mutex_lock(&h->rh_lock);
   1182 	if (h->rh_flags & HANDLE_DEAD) {
   1183 		(void) pthread_mutex_unlock(&h->rh_lock);
   1184 		(void) scf_set_error(SCF_ERROR_HANDLE_DESTROYED);
   1185 		return (NULL);
   1186 	}
   1187 	(void) pthread_mutex_unlock(&h->rh_lock);
   1188 	return (h);
   1189 }
   1190 
   1191 /*
   1192  * Called when an object is removed from the handle.  On the last remove,
   1193  * cleans up and frees the handle.
   1194  */
   1195 static void
   1196 handle_unrefed(scf_handle_t *handle)
   1197 {
   1198 	scf_iter_t *iter;
   1199 	scf_value_t *v;
   1200 	scf_scope_t *sc;
   1201 	scf_service_t *svc;
   1202 	scf_instance_t *inst;
   1203 	scf_snapshot_t *snap;
   1204 	scf_snaplevel_t *snaplvl;
   1205 	scf_propertygroup_t *pg;
   1206 	scf_property_t *prop;
   1207 
   1208 	assert(MUTEX_HELD(&handle->rh_lock));
   1209 
   1210 	/*
   1211 	 * Don't do anything if the handle has not yet been destroyed, there
   1212 	 * are still external references, or we're already doing unrefed
   1213 	 * handling.
   1214 	 */
   1215 	if (!(handle->rh_flags & HANDLE_DEAD) ||
   1216 	    handle->rh_extrefs > 0 ||
   1217 	    handle->rh_fd_users > 0 ||
   1218 	    (handle->rh_flags & HANDLE_UNREFED)) {
   1219 		(void) pthread_mutex_unlock(&handle->rh_lock);
   1220 		return;
   1221 	}
   1222 
   1223 	handle->rh_flags |= HANDLE_UNREFED;
   1224 
   1225 	/*
   1226 	 * Now that we know that there are no external references, and the
   1227 	 * HANDLE_DEAD flag keeps new ones from appearing, we can clean up
   1228 	 * our subhandles and destroy the handle completely.
   1229 	 */
   1230 	assert(handle->rh_intrefs >= 0);
   1231 	handle->rh_extrefs = handle->rh_intrefs;
   1232 	handle->rh_intrefs = 0;
   1233 	(void) pthread_mutex_unlock(&handle->rh_lock);
   1234 
   1235 	handle_hold_subhandles(handle, RH_HOLD_ALL);
   1236 
   1237 	iter = handle->rh_iter;
   1238 	sc = handle->rh_scope;
   1239 	svc = handle->rh_service;
   1240 	inst = handle->rh_instance;
   1241 	snap = handle->rh_snapshot;
   1242 	snaplvl = handle->rh_snaplvl;
   1243 	pg = handle->rh_pg;
   1244 	prop = handle->rh_property;
   1245 	v = handle->rh_value;
   1246 
   1247 	handle->rh_iter = NULL;
   1248 	handle->rh_scope = NULL;
   1249 	handle->rh_service = NULL;
   1250 	handle->rh_instance = NULL;
   1251 	handle->rh_snapshot = NULL;
   1252 	handle->rh_snaplvl = NULL;
   1253 	handle->rh_pg = NULL;
   1254 	handle->rh_property = NULL;
   1255 	handle->rh_value = NULL;
   1256 
   1257 	if (iter != NULL)
   1258 		scf_iter_destroy(iter);
   1259 	if (sc != NULL)
   1260 		scf_scope_destroy(sc);
   1261 	if (svc != NULL)
   1262 		scf_service_destroy(svc);
   1263 	if (inst != NULL)
   1264 		scf_instance_destroy(inst);
   1265 	if (snap != NULL)
   1266 		scf_snapshot_destroy(snap);
   1267 	if (snaplvl != NULL)
   1268 		scf_snaplevel_destroy(snaplvl);
   1269 	if (pg != NULL)
   1270 		scf_pg_destroy(pg);
   1271 	if (prop != NULL)
   1272 		scf_property_destroy(prop);
   1273 	if (v != NULL)
   1274 		scf_value_destroy(v);
   1275 
   1276 	(void) pthread_mutex_lock(&handle->rh_lock);
   1277 
   1278 	/* there should be no outstanding children at this point */
   1279 	assert(handle->rh_extrefs == 0);
   1280 	assert(handle->rh_intrefs == 0);
   1281 	assert(handle->rh_values == 0);
   1282 	assert(handle->rh_entries == 0);
   1283 	assert(uu_list_numnodes(handle->rh_dataels) == 0);
   1284 	assert(uu_list_numnodes(handle->rh_iters) == 0);
   1285 
   1286 	uu_list_destroy(handle->rh_dataels);
   1287 	uu_list_destroy(handle->rh_iters);
   1288 	handle->rh_dataels = NULL;
   1289 	handle->rh_iters = NULL;
   1290 	(void) pthread_mutex_unlock(&handle->rh_lock);
   1291 
   1292 	(void) pthread_mutex_destroy(&handle->rh_lock);
   1293 
   1294 	uu_free(handle);
   1295 }
   1296 
   1297 void
   1298 scf_handle_destroy(scf_handle_t *handle)
   1299 {
   1300 	if (handle == NULL)
   1301 		return;
   1302 
   1303 	(void) pthread_mutex_lock(&handle->rh_lock);
   1304 	if (handle->rh_flags & HANDLE_DEAD) {
   1305 		/*
   1306 		 * This is an error (you are not allowed to reference the
   1307 		 * handle after it is destroyed), but we can't report it.
   1308 		 */
   1309 		(void) pthread_mutex_unlock(&handle->rh_lock);
   1310 		return;
   1311 	}
   1312 	handle->rh_flags |= HANDLE_DEAD;
   1313 	(void) handle_unbind_unlocked(handle);
   1314 	handle_unrefed(handle);
   1315 }
   1316 
   1317 ssize_t
   1318 scf_myname(scf_handle_t *h, char *out, size_t len)
   1319 {
   1320 	char *cp;
   1321 
   1322 	if (!handle_has_server(h))
   1323 		return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN));
   1324 
   1325 	cp = getenv("SMF_FMRI");
   1326 	if (cp == NULL)
   1327 		return (scf_set_error(SCF_ERROR_NOT_SET));
   1328 
   1329 	return (strlcpy(out, cp, len));
   1330 }
   1331 
   1332 static uint32_t
   1333 handle_alloc_entityid(scf_handle_t *h)
   1334 {
   1335 	uint32_t nextid;
   1336 
   1337 	assert(MUTEX_HELD(&h->rh_lock));
   1338 
   1339 	if (uu_list_numnodes(h->rh_dataels) == UINT32_MAX)
   1340 		return (0);		/* no ids available */
   1341 
   1342 	/*
   1343 	 * The following loop assumes that there are not a huge number of
   1344 	 * outstanding entities when we've wrapped.  If that ends up not
   1345 	 * being the case, the O(N^2) nature of this search will hurt a lot,
   1346 	 * and the data structure should be switched to an AVL tree.
   1347 	 */
   1348 	nextid = h->rh_nextentity + 1;
   1349 	for (;;) {
   1350 		scf_datael_t *cur;
   1351 
   1352 		if (nextid == 0) {
   1353 			nextid++;
   1354 			h->rh_flags |= HANDLE_WRAPPED_ENTITY;
   1355 		}
   1356 		if (!(h->rh_flags & HANDLE_WRAPPED_ENTITY))
   1357 			break;
   1358 
   1359 		cur = uu_list_find(h->rh_dataels, NULL, &nextid, NULL);
   1360 		if (cur == NULL)
   1361 			break;		/* not in use */
   1362 
   1363 		if (nextid == h->rh_nextentity)
   1364 			return (0);	/* wrapped around; no ids available */
   1365 		nextid++;
   1366 	}
   1367 
   1368 	h->rh_nextentity = nextid;
   1369 	return (nextid);
   1370 }
   1371 
   1372 static uint32_t
   1373 handle_alloc_iterid(scf_handle_t *h)
   1374 {
   1375 	uint32_t nextid;
   1376 
   1377 	assert(MUTEX_HELD(&h->rh_lock));
   1378 
   1379 	if (uu_list_numnodes(h->rh_iters) == UINT32_MAX)
   1380 		return (0);		/* no ids available */
   1381 
   1382 	/* see the comment in handle_alloc_entityid */
   1383 	nextid = h->rh_nextiter + 1;
   1384 	for (;;) {
   1385 		scf_iter_t *cur;
   1386 
   1387 		if (nextid == 0) {
   1388 			nextid++;
   1389 			h->rh_flags |= HANDLE_WRAPPED_ITER;
   1390 		}
   1391 		if (!(h->rh_flags & HANDLE_WRAPPED_ITER))
   1392 			break;			/* not yet wrapped */
   1393 
   1394 		cur = uu_list_find(h->rh_iters, NULL, &nextid, NULL);
   1395 		if (cur == NULL)
   1396 			break;		/* not in use */
   1397 
   1398 		if (nextid == h->rh_nextiter)
   1399 			return (0);	/* wrapped around; no ids available */
   1400 		nextid++;
   1401 	}
   1402 
   1403 	h->rh_nextiter = nextid;
   1404 	return (nextid);
   1405 }
   1406 
   1407 static uint32_t
   1408 handle_next_changeid(scf_handle_t *handle)
   1409 {
   1410 	uint32_t nextid;
   1411 
   1412 	assert(MUTEX_HELD(&handle->rh_lock));
   1413 
   1414 	nextid = ++handle->rh_nextchangeid;
   1415 	if (nextid == 0)
   1416 		nextid = ++handle->rh_nextchangeid;
   1417 	return (nextid);
   1418 }
   1419 
   1420 /*
   1421  * Fails with
   1422  *   _INVALID_ARGUMENT - h is NULL
   1423  *   _HANDLE_DESTROYED
   1424  *   _INTERNAL - server response too big
   1425  *		 entity already set up with different type
   1426  *   _NO_RESOURCES
   1427  */
   1428 static int
   1429 datael_init(scf_datael_t *dp, scf_handle_t *h, uint32_t type)
   1430 {
   1431 	int ret;
   1432 
   1433 	if (h == NULL)
   1434 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
   1435 
   1436 	uu_list_node_init(dp, &dp->rd_node, datael_pool);
   1437 
   1438 	dp->rd_handle = h;
   1439 	dp->rd_type = type;
   1440 	dp->rd_reset = 0;
   1441 
   1442 	(void) pthread_mutex_lock(&h->rh_lock);
   1443 	if (h->rh_flags & HANDLE_DEAD) {
   1444 		/*
   1445 		 * we're in undefined territory (the user cannot use a handle
   1446 		 * directly after it has been destroyed), but we don't want
   1447 		 * to allow any new references to happen, so we fail here.
   1448 		 */
   1449 		(void) pthread_mutex_unlock(&h->rh_lock);
   1450 		return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED));
   1451 	}
   1452 	dp->rd_entity = handle_alloc_entityid(h);
   1453 	if (dp->rd_entity == 0) {
   1454 		(void) pthread_mutex_unlock(&h->rh_lock);
   1455 		uu_list_node_fini(dp, &dp->rd_node, datael_pool);
   1456 		return (scf_set_error(SCF_ERROR_NO_MEMORY));
   1457 	}
   1458 
   1459 	ret = datael_attach(dp);
   1460 	if (ret == 0) {
   1461 		(void) uu_list_insert_before(h->rh_dataels, NULL, dp);
   1462 		h->rh_extrefs++;
   1463 	} else {
   1464 		uu_list_node_fini(dp, &dp->rd_node, datael_pool);
   1465 	}
   1466 	(void) pthread_mutex_unlock(&h->rh_lock);
   1467 
   1468 	return (ret);
   1469 }
   1470 
   1471 static void
   1472 datael_destroy(scf_datael_t *dp)
   1473 {
   1474 	scf_handle_t *h = dp->rd_handle;
   1475 
   1476 	struct rep_protocol_entity_teardown request;
   1477 	rep_protocol_response_t response;
   1478 
   1479 	(void) pthread_mutex_lock(&h->rh_lock);
   1480 	uu_list_remove(h->rh_dataels, dp);
   1481 	--h->rh_extrefs;
   1482 
   1483 	if (handle_is_bound(h)) {
   1484 		request.rpr_request = REP_PROTOCOL_ENTITY_TEARDOWN;
   1485 		request.rpr_entityid = dp->rd_entity;
   1486 
   1487 		(void) make_door_call(h, &request, sizeof (request),
   1488 		    &response, sizeof (response));
   1489 	}
   1490 	handle_unrefed(h);			/* drops h->rh_lock */
   1491 
   1492 	dp->rd_handle = NULL;
   1493 }
   1494 
   1495 static scf_handle_t *
   1496 datael_handle(const scf_datael_t *dp)
   1497 {
   1498 	return (handle_get(dp->rd_handle));
   1499 }
   1500 
   1501 /*
   1502  * We delay ENTITY_RESETs until right before the entity is used.  By doing
   1503  * them lazily, we remove quite a few unnecessary calls.
   1504  */
   1505 static void
   1506 datael_do_reset_locked(scf_datael_t *dp)
   1507 {
   1508 	scf_handle_t *h = dp->rd_handle;
   1509 
   1510 	struct rep_protocol_entity_reset request;
   1511 	rep_protocol_response_t response;
   1512 
   1513 	assert(MUTEX_HELD(&h->rh_lock));
   1514 
   1515 	request.rpr_request = REP_PROTOCOL_ENTITY_RESET;
   1516 	request.rpr_entityid = dp->rd_entity;
   1517 
   1518 	(void) make_door_call(h, &request, sizeof (request),
   1519 	    &response, sizeof (response));
   1520 
   1521 	dp->rd_reset = 0;
   1522 }
   1523 
   1524 static void
   1525 datael_reset_locked(scf_datael_t *dp)
   1526 {
   1527 	assert(MUTEX_HELD(&dp->rd_handle->rh_lock));
   1528 	dp->rd_reset = 1;
   1529 }
   1530 
   1531 static void
   1532 datael_reset(scf_datael_t *dp)
   1533 {
   1534 	scf_handle_t *h = dp->rd_handle;
   1535 
   1536 	(void) pthread_mutex_lock(&h->rh_lock);
   1537 	dp->rd_reset = 1;
   1538 	(void) pthread_mutex_unlock(&h->rh_lock);
   1539 }
   1540 
   1541 static void
   1542 datael_finish_reset(const scf_datael_t *dp_arg)
   1543 {
   1544 	scf_datael_t *dp = (scf_datael_t *)dp_arg;
   1545 
   1546 	if (dp->rd_reset)
   1547 		datael_do_reset_locked(dp);
   1548 }
   1549 
   1550 /*
   1551  * Fails with _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response too
   1552  * big, bad entity id, request not applicable to entity, name too long for
   1553  * buffer), _NOT_SET, _DELETED, or _CONSTRAINT_VIOLATED (snaplevel is not of an
   1554  * instance).
   1555  */
   1556 static ssize_t
   1557 datael_get_name(const scf_datael_t *dp, char *buf, size_t size, uint32_t type)
   1558 {
   1559 	scf_handle_t *h = dp->rd_handle;
   1560 
   1561 	struct rep_protocol_entity_name request;
   1562 	struct rep_protocol_name_response response;
   1563 	ssize_t r;
   1564 
   1565 	(void) pthread_mutex_lock(&h->rh_lock);
   1566 	request.rpr_request = REP_PROTOCOL_ENTITY_NAME;
   1567 	request.rpr_entityid = dp->rd_entity;
   1568 	request.rpr_answertype = type;
   1569 
   1570 	datael_finish_reset(dp);
   1571 	r = make_door_call(h, &request, sizeof (request),
   1572 	    &response, sizeof (response));
   1573 	(void) pthread_mutex_unlock(&h->rh_lock);
   1574 
   1575 	if (r < 0)
   1576 		DOOR_ERRORS_BLOCK(r);
   1577 
   1578 	if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
   1579 		assert(response.rpr_response != REP_PROTOCOL_FAIL_BAD_REQUEST);
   1580 		if (response.rpr_response == REP_PROTOCOL_FAIL_NOT_FOUND)
   1581 			return (scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED));
   1582 		return (scf_set_error(proto_error(response.rpr_response)));
   1583 	}
   1584 	return (strlcpy(buf, response.rpr_name, size));
   1585 }
   1586 
   1587 /*
   1588  * Fails with _HANDLE_MISMATCH, _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL
   1589  * (server response too big, bad element id), _EXISTS (elements have same id),
   1590  * _NOT_SET, _DELETED, _CONSTRAINT_VIOLATED, _NOT_FOUND (scope has no parent),
   1591  * or _SUCCESS.
   1592  */
   1593 static int
   1594 datael_get_parent(const scf_datael_t *dp, scf_datael_t *pp)
   1595 {
   1596 	scf_handle_t *h = dp->rd_handle;
   1597 
   1598 	struct rep_protocol_entity_parent request;
   1599 	struct rep_protocol_response response;
   1600 
   1601 	ssize_t r;
   1602 
   1603 	if (h != pp->rd_handle)
   1604 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
   1605 
   1606 	(void) pthread_mutex_lock(&h->rh_lock);
   1607 	request.rpr_request = REP_PROTOCOL_ENTITY_GET_PARENT;
   1608 	request.rpr_entityid = dp->rd_entity;
   1609 	request.rpr_outid = pp->rd_entity;
   1610 
   1611 	datael_finish_reset(dp);
   1612 	datael_finish_reset(pp);
   1613 	r = make_door_call(h, &request, sizeof (request),
   1614 	    &response, sizeof (response));
   1615 	(void) pthread_mutex_unlock(&h->rh_lock);
   1616 
   1617 	if (r < 0)
   1618 		DOOR_ERRORS_BLOCK(r);
   1619 
   1620 	if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
   1621 		if (response.rpr_response == REP_PROTOCOL_FAIL_TYPE_MISMATCH)
   1622 			return (scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED));
   1623 		return (scf_set_error(proto_error(response.rpr_response)));
   1624 	}
   1625 
   1626 	return (SCF_SUCCESS);
   1627 }
   1628 
   1629 /*
   1630  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT (out does not have type type,
   1631  * name is invalid), _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response
   1632  * too big, bad id, iter already exists, element cannot have children of type,
   1633  * type is invalid, iter was reset, sequence was bad, iter walks values, iter
   1634  * does not walk type entities), _NOT_SET, _DELETED, _NO_RESOURCES,
   1635  * _BACKEND_ACCESS, _NOT_FOUND.
   1636  */
   1637 static int
   1638 datael_get_child_composed_locked(const scf_datael_t *dp, const char *name,
   1639     uint32_t type, scf_datael_t *out, scf_iter_t *iter)
   1640 {
   1641 	struct rep_protocol_iter_start request;
   1642 	struct rep_protocol_iter_read read_request;
   1643 	struct rep_protocol_response response;
   1644 
   1645 	scf_handle_t *h = dp->rd_handle;
   1646 	ssize_t r;
   1647 
   1648 	if (h != out->rd_handle)
   1649 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
   1650 
   1651 	if (out->rd_type != type)
   1652 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
   1653 
   1654 	assert(MUTEX_HELD(&h->rh_lock));
   1655 	assert(iter != NULL);
   1656 
   1657 	scf_iter_reset_locked(iter);
   1658 	iter->iter_type = type;
   1659 
   1660 	request.rpr_request = REP_PROTOCOL_ITER_START;
   1661 	request.rpr_iterid = iter->iter_id;
   1662 	request.rpr_entity = dp->rd_entity;
   1663 	request.rpr_itertype = type;
   1664 	request.rpr_flags = RP_ITER_START_EXACT | RP_ITER_START_COMPOSED;
   1665 
   1666 	if (name == NULL || strlcpy(request.rpr_pattern, name,
   1667 	    sizeof (request.rpr_pattern)) >= sizeof (request.rpr_pattern)) {
   1668 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
   1669 	}
   1670 
   1671 	datael_finish_reset(dp);
   1672 	datael_finish_reset(out);
   1673 
   1674 	/*
   1675 	 * We hold the handle lock across both door calls, so that they
   1676 	 * appear atomic.
   1677 	 */
   1678 	r = make_door_call(h, &request, sizeof (request),
   1679 	    &response, sizeof (response));
   1680 
   1681 	if (r < 0)
   1682 		DOOR_ERRORS_BLOCK(r);
   1683 
   1684 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
   1685 		return (scf_set_error(proto_error(response.rpr_response)));
   1686 
   1687 	iter->iter_sequence++;
   1688 
   1689 	read_request.rpr_request = REP_PROTOCOL_ITER_READ;
   1690 	read_request.rpr_iterid = iter->iter_id;
   1691 	read_request.rpr_sequence = iter->iter_sequence;
   1692 	read_request.rpr_entityid = out->rd_entity;
   1693 
   1694 	r = make_door_call(h, &read_request, sizeof (read_request),
   1695 	    &response, sizeof (response));
   1696 
   1697 	scf_iter_reset_locked(iter);
   1698 
   1699 	if (r < 0)
   1700 		DOOR_ERRORS_BLOCK(r);
   1701 
   1702 	if (response.rpr_response == REP_PROTOCOL_DONE) {
   1703 		return (scf_set_error(SCF_ERROR_NOT_FOUND));
   1704 	}
   1705 
   1706 	if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
   1707 		if (response.rpr_response == REP_PROTOCOL_FAIL_NOT_SET ||
   1708 		    response.rpr_response == REP_PROTOCOL_FAIL_BAD_REQUEST)
   1709 			return (scf_set_error(SCF_ERROR_INTERNAL));
   1710 		return (scf_set_error(proto_error(response.rpr_response)));
   1711 	}
   1712 
   1713 	return (0);
   1714 }
   1715 
   1716 /*
   1717  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT (out does not have type type,
   1718  * name is invalid), _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response
   1719  * too big, bad id, element cannot have children of type, type is invalid),
   1720  * _NOT_SET, _DELETED, _NO_RESOURCES, _BACKEND_ACCESS.
   1721  */
   1722 static int
   1723 datael_get_child_locked(const scf_datael_t *dp, const char *name,
   1724     uint32_t type, scf_datael_t *out)
   1725 {
   1726 	struct rep_protocol_entity_get_child request;
   1727 	struct rep_protocol_response response;
   1728 
   1729 	scf_handle_t *h = dp->rd_handle;
   1730 	ssize_t r;
   1731 
   1732 	if (h != out->rd_handle)
   1733 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
   1734 
   1735 	if (out->rd_type != type)
   1736 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
   1737 
   1738 	assert(MUTEX_HELD(&h->rh_lock));
   1739 
   1740 	request.rpr_request = REP_PROTOCOL_ENTITY_GET_CHILD;
   1741 	request.rpr_entityid = dp->rd_entity;
   1742 	request.rpr_childid = out->rd_entity;
   1743 
   1744 	if (name == NULL || strlcpy(request.rpr_name, name,
   1745 	    sizeof (request.rpr_name)) >= sizeof (request.rpr_name)) {
   1746 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
   1747 	}
   1748 
   1749 	datael_finish_reset(dp);
   1750 	datael_finish_reset(out);
   1751 
   1752 	r = make_door_call(h, &request, sizeof (request),
   1753 	    &response, sizeof (response));
   1754 
   1755 	if (r < 0)
   1756 		DOOR_ERRORS_BLOCK(r);
   1757 
   1758 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
   1759 		return (scf_set_error(proto_error(response.rpr_response)));
   1760 	return (0);
   1761 }
   1762 
   1763 /*
   1764  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT (out does not have type type,
   1765  * name is invalid), _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response
   1766  * too big, bad id, iter already exists, element cannot have children of type,
   1767  * type is invalid, iter was reset, sequence was bad, iter walks values, iter
   1768  * does not walk type entities), _NOT_SET, _DELETED, _NO_RESOURCES,
   1769  * _BACKEND_ACCESS, _NOT_FOUND.
   1770  */
   1771 static int
   1772 datael_get_child(const scf_datael_t *dp, const char *name, uint32_t type,
   1773     scf_datael_t *out, boolean_t composed)
   1774 {
   1775 	scf_handle_t *h = dp->rd_handle;
   1776 	uint32_t held = 0;
   1777 	int ret;
   1778 
   1779 	scf_iter_t *iter = NULL;
   1780 
   1781 	if (composed)
   1782 		iter = HANDLE_HOLD_ITER(h);
   1783 
   1784 	if (out == NULL) {
   1785 		switch (type) {
   1786 		case REP_PROTOCOL_ENTITY_SERVICE:
   1787 			out = &HANDLE_HOLD_SERVICE(h)->rd_d;
   1788 			held = RH_HOLD_SERVICE;
   1789 			break;
   1790 
   1791 		case REP_PROTOCOL_ENTITY_INSTANCE:
   1792 			out = &HANDLE_HOLD_INSTANCE(h)->rd_d;
   1793 			held = RH_HOLD_INSTANCE;
   1794 			break;
   1795 
   1796 		case REP_PROTOCOL_ENTITY_SNAPSHOT:
   1797 			out = &HANDLE_HOLD_SNAPSHOT(h)->rd_d;
   1798 			held = RH_HOLD_SNAPSHOT;
   1799 			break;
   1800 
   1801 		case REP_PROTOCOL_ENTITY_SNAPLEVEL:
   1802 			out = &HANDLE_HOLD_SNAPLVL(h)->rd_d;
   1803 			held = RH_HOLD_SNAPLVL;
   1804 			break;
   1805 
   1806 		case REP_PROTOCOL_ENTITY_PROPERTYGRP:
   1807 			out = &HANDLE_HOLD_PG(h)->rd_d;
   1808 			held = RH_HOLD_PG;
   1809 			break;
   1810 
   1811 		case REP_PROTOCOL_ENTITY_PROPERTY:
   1812 			out = &HANDLE_HOLD_PROPERTY(h)->rd_d;
   1813 			held = RH_HOLD_PROPERTY;
   1814 			break;
   1815 
   1816 		default:
   1817 			assert(0);
   1818 			abort();
   1819 		}
   1820 	}
   1821 
   1822 	(void) pthread_mutex_lock(&h->rh_lock);
   1823 	if (composed)
   1824 		ret = datael_get_child_composed_locked(dp, name, type, out,
   1825 		    iter);
   1826 	else
   1827 		ret = datael_get_child_locked(dp, name, type, out);
   1828 	(void) pthread_mutex_unlock(&h->rh_lock);
   1829 
   1830 	if (composed)
   1831 		HANDLE_RELE_ITER(h);
   1832 
   1833 	if (held)
   1834 		handle_rele_subhandles(h, held);
   1835 
   1836 	return (ret);
   1837 }
   1838 
   1839 /*
   1840  * Fails with
   1841  *   _HANDLE_MISMATCH
   1842  *   _INVALID_ARGUMENT - name is too long
   1843  *			 invalid changeid
   1844  *			 name is invalid
   1845  *			 cannot create children for dp's type of node
   1846  *   _NOT_BOUND - handle is not bound
   1847  *   _CONNECTION_BROKEN - server is not reachable
   1848  *   _INTERNAL - server response too big
   1849  *		 dp or cp has unknown id
   1850  *		 type is _PROPERTYGRP
   1851  *		 type is invalid
   1852  *		 dp cannot have children of type type
   1853  *		 database is corrupt
   1854  *   _EXISTS - dp & cp have the same id
   1855  *   _EXISTS - child already exists
   1856  *   _DELETED - dp has been deleted
   1857  *   _NOT_SET - dp is reset
   1858  *   _NO_RESOURCES
   1859  *   _PERMISSION_DENIED
   1860  *   _BACKEND_ACCESS
   1861  *   _BACKEND_READONLY
   1862  */
   1863 static int
   1864 datael_add_child(const scf_datael_t *dp, const char *name, uint32_t type,
   1865     scf_datael_t *cp)
   1866 {
   1867 	scf_handle_t *h = dp->rd_handle;
   1868 
   1869 	struct rep_protocol_entity_create_child request;
   1870 	struct rep_protocol_response response;
   1871 	ssize_t r;
   1872 	uint32_t held = 0;
   1873 
   1874 	if (cp == NULL) {
   1875 		switch (type) {
   1876 		case REP_PROTOCOL_ENTITY_SCOPE:
   1877 			cp = &HANDLE_HOLD_SCOPE(h)->rd_d;
   1878 			held = RH_HOLD_SCOPE;
   1879 			break;
   1880 		case REP_PROTOCOL_ENTITY_SERVICE:
   1881 			cp = &HANDLE_HOLD_SERVICE(h)->rd_d;
   1882 			held = RH_HOLD_SERVICE;
   1883 			break;
   1884 		case REP_PROTOCOL_ENTITY_INSTANCE:
   1885 			cp = &HANDLE_HOLD_INSTANCE(h)->rd_d;
   1886 			held = RH_HOLD_INSTANCE;
   1887 			break;
   1888 		case REP_PROTOCOL_ENTITY_SNAPSHOT:
   1889 		default:
   1890 			assert(0);
   1891 			abort();
   1892 		}
   1893 		assert(h == cp->rd_handle);
   1894 
   1895 	} else if (h != cp->rd_handle) {
   1896 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
   1897 	}
   1898 
   1899 	if (strlcpy(request.rpr_name, name, sizeof (request.rpr_name)) >=
   1900 	    sizeof (request.rpr_name)) {
   1901 		r = scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
   1902 		goto err;
   1903 	}
   1904 
   1905 	(void) pthread_mutex_lock(&h->rh_lock);
   1906 	request.rpr_request = REP_PROTOCOL_ENTITY_CREATE_CHILD;
   1907 	request.rpr_entityid = dp->rd_entity;
   1908 	request.rpr_childtype = type;
   1909 	request.rpr_childid = cp->rd_entity;
   1910 
   1911 	datael_finish_reset(dp);
   1912 	request.rpr_changeid = handle_next_changeid(h);
   1913 	r = make_door_call(h, &request, sizeof (request),
   1914 	    &response, sizeof (response));
   1915 	(void) pthread_mutex_unlock(&h->rh_lock);
   1916 
   1917 	if (held)
   1918 		handle_rele_subhandles(h, held);
   1919 
   1920 	if (r < 0)
   1921 		DOOR_ERRORS_BLOCK(r);
   1922 
   1923 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
   1924 		return (scf_set_error(proto_error(response.rpr_response)));
   1925 
   1926 	return (SCF_SUCCESS);
   1927 
   1928 err:
   1929 	if (held)
   1930 		handle_rele_subhandles(h, held);
   1931 	return (r);
   1932 }
   1933 
   1934 static int
   1935 datael_add_pg(const scf_datael_t *dp, const char *name, const char *type,
   1936     uint32_t flags, scf_datael_t *cp)
   1937 {
   1938 	scf_handle_t *h = dp->rd_handle;
   1939 
   1940 	struct rep_protocol_entity_create_pg request;
   1941 	struct rep_protocol_response response;
   1942 	ssize_t r;
   1943 
   1944 	int holding_els = 0;
   1945 
   1946 	if (cp == NULL) {
   1947 		holding_els = 1;
   1948 		cp = &HANDLE_HOLD_PG(h)->rd_d;
   1949 		assert(h == cp->rd_handle);
   1950 
   1951 	} else if (h != cp->rd_handle) {
   1952 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
   1953 	}
   1954 
   1955 	request.rpr_request = REP_PROTOCOL_ENTITY_CREATE_PG;
   1956 
   1957 	if (name == NULL || strlcpy(request.rpr_name, name,
   1958 	    sizeof (request.rpr_name)) > sizeof (request.rpr_name)) {
   1959 		r = scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
   1960 		goto err;
   1961 	}
   1962 
   1963 	if (type == NULL || strlcpy(request.rpr_type, type,
   1964 	    sizeof (request.rpr_type)) > sizeof (request.rpr_type)) {
   1965 		r = scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
   1966 		goto err;
   1967 	}
   1968 
   1969 	(void) pthread_mutex_lock(&h->rh_lock);
   1970 	request.rpr_entityid = dp->rd_entity;
   1971 	request.rpr_childid = cp->rd_entity;
   1972 	request.rpr_flags = flags;
   1973 
   1974 	datael_finish_reset(dp);
   1975 	datael_finish_reset(cp);
   1976 	request.rpr_changeid = handle_next_changeid(h);
   1977 	r = make_door_call(h, &request, sizeof (request),
   1978 	    &response, sizeof (response));
   1979 	(void) pthread_mutex_unlock(&h->rh_lock);
   1980 
   1981 	if (holding_els)
   1982 		HANDLE_RELE_PG(h);
   1983 
   1984 	if (r < 0)
   1985 		DOOR_ERRORS_BLOCK(r);
   1986 
   1987 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
   1988 		return (scf_set_error(proto_error(response.rpr_response)));
   1989 
   1990 	return (SCF_SUCCESS);
   1991 
   1992 err:
   1993 	if (holding_els)
   1994 		HANDLE_RELE_PG(h);
   1995 	return (r);
   1996 }
   1997 
   1998 static int
   1999 datael_delete(const scf_datael_t *dp)
   2000 {
   2001 	scf_handle_t *h = dp->rd_handle;
   2002 
   2003 	struct rep_protocol_entity_delete request;
   2004 	struct rep_protocol_response response;
   2005 	ssize_t r;
   2006 
   2007 	(void) pthread_mutex_lock(&h->rh_lock);
   2008 	request.rpr_request = REP_PROTOCOL_ENTITY_DELETE;
   2009 	request.rpr_entityid = dp->rd_entity;
   2010 
   2011 	datael_finish_reset(dp);
   2012 	request.rpr_changeid = handle_next_changeid(h);
   2013 	r = make_door_call(h, &request, sizeof (request),
   2014 	    &response, sizeof (response));
   2015 	(void) pthread_mutex_unlock(&h->rh_lock);
   2016 
   2017 	if (r < 0)
   2018 		DOOR_ERRORS_BLOCK(r);
   2019 
   2020 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
   2021 		return (scf_set_error(proto_error(response.rpr_response)));
   2022 
   2023 	return (SCF_SUCCESS);
   2024 }
   2025 
   2026 /*
   2027  * Fails with
   2028  *   _INVALID_ARGUMENT - h is NULL
   2029  *   _NO_MEMORY
   2030  *   _HANDLE_DESTROYED - h has been destroyed
   2031  *   _INTERNAL - server response too big
   2032  *		 iter already exists
   2033  *   _NO_RESOURCES
   2034  */
   2035 scf_iter_t *
   2036 scf_iter_create(scf_handle_t *h)
   2037 {
   2038 	scf_iter_t *iter;
   2039 
   2040 	if (h == NULL) {
   2041 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
   2042 		return (NULL);
   2043 	}
   2044 
   2045 	iter = uu_zalloc(sizeof (*iter));
   2046 	if (iter == NULL) {
   2047 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
   2048 		return (NULL);
   2049 	}
   2050 
   2051 	uu_list_node_init(iter, &iter->iter_node, iter_pool);
   2052 	iter->iter_handle = h;
   2053 	iter->iter_sequence = 1;
   2054 	iter->iter_type = REP_PROTOCOL_ENTITY_NONE;
   2055 
   2056 	(void) pthread_mutex_lock(&h->rh_lock);
   2057 	iter->iter_id = handle_alloc_iterid(h);
   2058 	if (iter->iter_id == 0) {
   2059 		(void) pthread_mutex_unlock(&h->rh_lock);
   2060 		uu_list_node_fini(iter, &iter->iter_node, iter_pool);
   2061 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
   2062 		uu_free(iter);
   2063 		return (NULL);
   2064 	}
   2065 	if (iter_attach(iter) == -1) {
   2066 		uu_list_node_fini(iter, &iter->iter_node, iter_pool);
   2067 		(void) pthread_mutex_unlock(&h->rh_lock);
   2068 		uu_free(iter);
   2069 		return (NULL);
   2070 	}
   2071 	(void) uu_list_insert_before(h->rh_iters, NULL, iter);
   2072 	h->rh_extrefs++;
   2073 	(void) pthread_mutex_unlock(&h->rh_lock);
   2074 	return (iter);
   2075 }
   2076 
   2077 scf_handle_t *
   2078 scf_iter_handle(const scf_iter_t *iter)
   2079 {
   2080 	return (handle_get(iter->iter_handle));
   2081 }
   2082 
   2083 static void
   2084 scf_iter_reset_locked(scf_iter_t *iter)
   2085 {
   2086 	struct rep_protocol_iter_request request;
   2087 	struct rep_protocol_response response;
   2088 
   2089 	request.rpr_request = REP_PROTOCOL_ITER_RESET;
   2090 	request.rpr_iterid = iter->iter_id;
   2091 
   2092 	assert(MUTEX_HELD(&iter->iter_handle->rh_lock));
   2093 
   2094 	(void) make_door_call(iter->iter_handle,
   2095 	    &request, sizeof (request), &response, sizeof (response));
   2096 
   2097 	iter->iter_type = REP_PROTOCOL_ENTITY_NONE;
   2098 	iter->iter_sequence = 1;
   2099 }
   2100 
   2101 void
   2102 scf_iter_reset(scf_iter_t *iter)
   2103 {
   2104 	(void) pthread_mutex_lock(&iter->iter_handle->rh_lock);
   2105 	scf_iter_reset_locked(iter);
   2106 	(void) pthread_mutex_unlock(&iter->iter_handle->rh_lock);
   2107 }
   2108 
   2109 void
   2110 scf_iter_destroy(scf_iter_t *iter)
   2111 {
   2112 	scf_handle_t *handle;
   2113 
   2114 	struct rep_protocol_iter_request request;
   2115 	struct rep_protocol_response response;
   2116 
   2117 	if (iter == NULL)
   2118 		return;
   2119 
   2120 	handle = iter->iter_handle;
   2121 
   2122 	(void) pthread_mutex_lock(&handle->rh_lock);
   2123 	request.rpr_request = REP_PROTOCOL_ITER_TEARDOWN;
   2124 	request.rpr_iterid = iter->iter_id;
   2125 
   2126 	(void) make_door_call(handle, &request, sizeof (request),
   2127 	    &response, sizeof (response));
   2128 
   2129 	uu_list_remove(handle->rh_iters, iter);
   2130 	--handle->rh_extrefs;
   2131 	handle_unrefed(handle);			/* drops h->rh_lock */
   2132 	iter->iter_handle = NULL;
   2133 
   2134 	uu_list_node_fini(iter, &iter->iter_node, iter_pool);
   2135 	uu_free(iter);
   2136 }
   2137 
   2138 static int
   2139 handle_get_local_scope_locked(scf_handle_t *handle, scf_scope_t *out)
   2140 {
   2141 	struct rep_protocol_entity_get request;
   2142 	struct rep_protocol_name_response response;
   2143 	ssize_t r;
   2144 
   2145 	assert(MUTEX_HELD(&handle->rh_lock));
   2146 
   2147 	if (handle != out->rd_d.rd_handle)
   2148 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
   2149 
   2150 	request.rpr_request = REP_PROTOCOL_ENTITY_GET;
   2151 	request.rpr_entityid = out->rd_d.rd_entity;
   2152 	request.rpr_object = RP_ENTITY_GET_MOST_LOCAL_SCOPE;
   2153 
   2154 	datael_finish_reset(&out->rd_d);
   2155 	r = make_door_call(handle, &request, sizeof (request),
   2156 	    &response, sizeof (response));
   2157 
   2158 	if (r < 0)
   2159 		DOOR_ERRORS_BLOCK(r);
   2160 
   2161 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
   2162 		return (scf_set_error(proto_error(response.rpr_response)));
   2163 
   2164 	return (SCF_SUCCESS);
   2165 }
   2166 
   2167 int
   2168 scf_iter_handle_scopes(scf_iter_t *iter, const scf_handle_t *handle)
   2169 {
   2170 	scf_handle_t *h = iter->iter_handle;
   2171 	if (h != handle)
   2172 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
   2173 
   2174 	(void) pthread_mutex_lock(&h->rh_lock);
   2175 	scf_iter_reset_locked(iter);
   2176 
   2177 	if (!handle_is_bound(h)) {
   2178 		(void) pthread_mutex_unlock(&h->rh_lock);
   2179 		return (scf_set_error(SCF_ERROR_NOT_BOUND));
   2180 	}
   2181 
   2182 	if (!handle_has_server_locked(h)) {
   2183 		(void) pthread_mutex_unlock(&h->rh_lock);
   2184 		return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN));
   2185 	}
   2186 
   2187 	iter->iter_type = REP_PROTOCOL_ENTITY_SCOPE;
   2188 	iter->iter_sequence = 1;
   2189 	(void) pthread_mutex_unlock(&h->rh_lock);
   2190 	return (0);
   2191 }
   2192 
   2193 int
   2194 scf_iter_next_scope(scf_iter_t *iter, scf_scope_t *out)
   2195 {
   2196 	int ret;
   2197 	scf_handle_t *h = iter->iter_handle;
   2198 
   2199 	if (h != out->rd_d.rd_handle)
   2200 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
   2201 
   2202 	(void) pthread_mutex_lock(&h->rh_lock);
   2203 	if (iter->iter_type == REP_PROTOCOL_ENTITY_NONE) {
   2204 		(void) pthread_mutex_unlock(&h->rh_lock);
   2205 		return (scf_set_error(SCF_ERROR_NOT_SET));
   2206 	}
   2207 	if (iter->iter_type != REP_PROTOCOL_ENTITY_SCOPE) {
   2208 		(void) pthread_mutex_unlock(&h->rh_lock);
   2209 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
   2210 	}
   2211 	if (iter->iter_sequence == 1) {
   2212 		if ((ret = handle_get_local_scope_locked(h, out)) ==
   2213 		    SCF_SUCCESS) {
   2214 			iter->iter_sequence++;
   2215 			ret = 1;
   2216 		}
   2217 	} else {
   2218 		datael_reset_locked(&out->rd_d);
   2219 		ret = 0;
   2220 	}
   2221 	(void) pthread_mutex_unlock(&h->rh_lock);
   2222 	return (ret);
   2223 }
   2224 
   2225 int
   2226 scf_handle_get_scope(scf_handle_t *h, const char *name, scf_scope_t *out)
   2227 {
   2228 	int ret;
   2229 
   2230 	if (h != out->rd_d.rd_handle)
   2231 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
   2232 
   2233 	(void) pthread_mutex_lock(&h->rh_lock);
   2234 	if (strcmp(name, SCF_SCOPE_LOCAL) == 0) {
   2235 		ret = handle_get_local_scope_locked(h, out);
   2236 	} else {
   2237 		datael_reset_locked(&out->rd_d);
   2238 		if (uu_check_name(name, 0) == -1)
   2239 			ret = scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
   2240 		else
   2241 			ret = scf_set_error(SCF_ERROR_NOT_FOUND);
   2242 	}
   2243 	(void) pthread_mutex_unlock(&h->rh_lock);
   2244 	return (ret);
   2245 }
   2246 
   2247 static int
   2248 datael_setup_iter(scf_iter_t *iter, const scf_datael_t *dp, uint32_t res_type,
   2249     boolean_t composed)
   2250 {
   2251 	scf_handle_t *h = dp->rd_handle;
   2252 
   2253 	struct rep_protocol_iter_start request;
   2254 	struct rep_protocol_response response;
   2255 
   2256 	ssize_t r;
   2257 
   2258 	if (h != iter->iter_handle)
   2259 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
   2260 
   2261 	(void) pthread_mutex_lock(&h->rh_lock);
   2262 	scf_iter_reset_locked(iter);
   2263 	iter->iter_type = res_type;
   2264 
   2265 	request.rpr_request = REP_PROTOCOL_ITER_START;
   2266 	request.rpr_iterid = iter->iter_id;
   2267 	request.rpr_entity = dp->rd_entity;
   2268 	request.rpr_itertype = res_type;
   2269 	request.rpr_flags = RP_ITER_START_ALL |
   2270 	    (composed ? RP_ITER_START_COMPOSED : 0);
   2271 	request.rpr_pattern[0] = 0;
   2272 
   2273 	datael_finish_reset(dp);
   2274 	r = make_door_call(h, &request, sizeof (request),
   2275 	    &response, sizeof (response));
   2276 
   2277 	if (r < 0) {
   2278 		(void) pthread_mutex_unlock(&h->rh_lock);
   2279 		DOOR_ERRORS_BLOCK(r);
   2280 	}
   2281 	if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
   2282 		(void) pthread_mutex_unlock(&h->rh_lock);
   2283 		return (scf_set_error(proto_error(response.rpr_response)));
   2284 	}
   2285 	iter->iter_sequence++;
   2286 	(void) pthread_mutex_unlock(&h->rh_lock);
   2287 	return (SCF_SUCCESS);
   2288 }
   2289 
   2290 static int
   2291 datael_setup_iter_pgtyped(scf_iter_t *iter, const scf_datael_t *dp,
   2292     const char *pgtype, boolean_t composed)
   2293 {
   2294 	scf_handle_t *h = dp->rd_handle;
   2295 
   2296 	struct rep_protocol_iter_start request;
   2297 	struct rep_protocol_response response;
   2298 
   2299 	ssize_t r;
   2300 
   2301 	if (h != iter->iter_handle)
   2302 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
   2303 
   2304 	if (pgtype == NULL || strlcpy(request.rpr_pattern, pgtype,
   2305 	    sizeof (request.rpr_pattern)) >= sizeof (request.rpr_pattern)) {
   2306 		scf_iter_reset(iter);
   2307 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
   2308 	}
   2309 
   2310 	(void) pthread_mutex_lock(&h->rh_lock);
   2311 	request.rpr_request = REP_PROTOCOL_ITER_START;
   2312 	request.rpr_iterid = iter->iter_id;
   2313 	request.rpr_entity = dp->rd_entity;
   2314 	request.rpr_itertype = REP_PROTOCOL_ENTITY_PROPERTYGRP;
   2315 	request.rpr_flags = RP_ITER_START_PGTYPE |
   2316 	    (composed ? RP_ITER_START_COMPOSED : 0);
   2317 
   2318 	datael_finish_reset(dp);
   2319 	scf_iter_reset_locked(iter);
   2320 	iter->iter_type = REP_PROTOCOL_ENTITY_PROPERTYGRP;
   2321 
   2322 	r = make_door_call(h, &request, sizeof (request),
   2323 	    &response, sizeof (response));
   2324 
   2325 	if (r < 0) {
   2326 		(void) pthread_mutex_unlock(&h->rh_lock);
   2327 
   2328 		DOOR_ERRORS_BLOCK(r);
   2329 	}
   2330 	if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
   2331 		(void) pthread_mutex_unlock(&h->rh_lock);
   2332 		return (scf_set_error(proto_error(response.rpr_response)));
   2333 	}
   2334 	iter->iter_sequence++;
   2335 	(void) pthread_mutex_unlock(&h->rh_lock);
   2336 	return (SCF_SUCCESS);
   2337 }
   2338 
   2339 static int
   2340 datael_iter_next(scf_iter_t *iter, scf_datael_t *out)
   2341 {
   2342 	scf_handle_t *h = iter->iter_handle;
   2343 
   2344 	struct rep_protocol_iter_read request;
   2345 	struct rep_protocol_response response;
   2346 	ssize_t r;
   2347 
   2348 	if (h != out->rd_handle)
   2349 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
   2350 
   2351 	(void) pthread_mutex_lock(&h->rh_lock);
   2352 	if (iter->iter_type == REP_PROTOCOL_ENTITY_NONE ||
   2353 	    iter->iter_sequence == 1) {
   2354 		(void) pthread_mutex_unlock(&h->rh_lock);
   2355 		return (scf_set_error(SCF_ERROR_NOT_SET));
   2356 	}
   2357 
   2358 	if (out->rd_type != iter->iter_type) {
   2359 		(void) pthread_mutex_unlock(&h->rh_lock);
   2360 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
   2361 	}
   2362 
   2363 	request.rpr_request = REP_PROTOCOL_ITER_READ;
   2364 	request.rpr_iterid = iter->iter_id;
   2365 	request.rpr_sequence = iter->iter_sequence;
   2366 	request.rpr_entityid = out->rd_entity;
   2367 
   2368 	datael_finish_reset(out);
   2369 	r = make_door_call(h, &request, sizeof (request),
   2370 	    &response, sizeof (response));
   2371 
   2372 	if (r < 0) {
   2373 		(void) pthread_mutex_unlock(&h->rh_lock);
   2374 		DOOR_ERRORS_BLOCK(r);
   2375 	}
   2376 
   2377 	if (response.rpr_response == REP_PROTOCOL_DONE) {
   2378 		(void) pthread_mutex_unlock(&h->rh_lock);
   2379 		return (0);
   2380 	}
   2381 	if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
   2382 		(void) pthread_mutex_unlock(&h->rh_lock);
   2383 		return (scf_set_error(proto_error(response.rpr_response)));
   2384 	}
   2385 	iter->iter_sequence++;
   2386 	(void) pthread_mutex_unlock(&h->rh_lock);
   2387 
   2388 	return (1);
   2389 }
   2390 
   2391 int
   2392 scf_iter_scope_services(scf_iter_t *iter, const scf_scope_t *s)
   2393 {
   2394 	return (datael_setup_iter(iter, &s->rd_d,
   2395 	    REP_PROTOCOL_ENTITY_SERVICE, 0));
   2396 }
   2397 
   2398 int
   2399 scf_iter_next_service(scf_iter_t *iter, scf_service_t *out)
   2400 {
   2401 	return (datael_iter_next(iter, &out->rd_d));
   2402 }
   2403 
   2404 int
   2405 scf_iter_service_instances(scf_iter_t *iter, const scf_service_t *svc)
   2406 {
   2407 	return (datael_setup_iter(iter, &svc->rd_d,
   2408 	    REP_PROTOCOL_ENTITY_INSTANCE, 0));
   2409 }
   2410 
   2411 int
   2412 scf_iter_next_instance(scf_iter_t *iter, scf_instance_t *out)
   2413 {
   2414 	return (datael_iter_next(iter, &out->rd_d));
   2415 }
   2416 
   2417 int
   2418 scf_iter_service_pgs(scf_iter_t *iter, const scf_service_t *svc)
   2419 {
   2420 	return (datael_setup_iter(iter, &svc->rd_d,
   2421 	    REP_PROTOCOL_ENTITY_PROPERTYGRP, 0));
   2422 }
   2423 
   2424 int
   2425 scf_iter_service_pgs_typed(scf_iter_t *iter, const scf_service_t *svc,
   2426     const char *type)
   2427 {
   2428 	return (datael_setup_iter_pgtyped(iter, &svc->rd_d, type, 0));
   2429 }
   2430 
   2431 int
   2432 scf_iter_instance_snapshots(scf_iter_t *iter, const scf_instance_t *inst)
   2433 {
   2434 	return (datael_setup_iter(iter, &inst->rd_d,
   2435 	    REP_PROTOCOL_ENTITY_SNAPSHOT, 0));
   2436 }
   2437 
   2438 int
   2439 scf_iter_next_snapshot(scf_iter_t *iter, scf_snapshot_t *out)
   2440 {
   2441 	return (datael_iter_next(iter, &out->rd_d));
   2442 }
   2443 
   2444 int
   2445 scf_iter_instance_pgs(scf_iter_t *iter, const scf_instance_t *inst)
   2446 {
   2447 	return (datael_setup_iter(iter, &inst->rd_d,
   2448 	    REP_PROTOCOL_ENTITY_PROPERTYGRP, 0));
   2449 }
   2450 
   2451 int
   2452 scf_iter_instance_pgs_typed(scf_iter_t *iter, const scf_instance_t *inst,
   2453     const char *type)
   2454 {
   2455 	return (datael_setup_iter_pgtyped(iter, &inst->rd_d, type, 0));
   2456 }
   2457 
   2458 int
   2459 scf_iter_instance_pgs_composed(scf_iter_t *iter, const scf_instance_t *inst,
   2460     const scf_snapshot_t *snap)
   2461 {
   2462 	if (snap != NULL && inst->rd_d.rd_handle != snap->rd_d.rd_handle)
   2463 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
   2464 
   2465 	return (datael_setup_iter(iter, snap ? &snap->rd_d : &inst->rd_d,
   2466 	    REP_PROTOCOL_ENTITY_PROPERTYGRP, 1));
   2467 }
   2468 
   2469 int
   2470 scf_iter_instance_pgs_typed_composed(scf_iter_t *iter,
   2471     const scf_instance_t *inst, const scf_snapshot_t *snap, const char *type)
   2472 {
   2473 	if (snap != NULL && inst->rd_d.rd_handle != snap->rd_d.rd_handle)
   2474 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
   2475 
   2476 	return (datael_setup_iter_pgtyped(iter,
   2477 	    snap ? &snap->rd_d : &inst->rd_d, type, 1));
   2478 }
   2479 
   2480 int
   2481 scf_iter_snaplevel_pgs(scf_iter_t *iter, const scf_snaplevel_t *inst)
   2482 {
   2483 	return (datael_setup_iter(iter, &inst->rd_d,
   2484 	    REP_PROTOCOL_ENTITY_PROPERTYGRP, 0));
   2485 }
   2486 
   2487 int
   2488 scf_iter_snaplevel_pgs_typed(scf_iter_t *iter, const scf_snaplevel_t *inst,
   2489     const char *type)
   2490 {
   2491 	return (datael_setup_iter_pgtyped(iter, &inst->rd_d, type, 0));
   2492 }
   2493 
   2494 int
   2495 scf_iter_next_pg(scf_iter_t *iter, scf_propertygroup_t *out)
   2496 {
   2497 	return (datael_iter_next(iter, &out->rd_d));
   2498 }
   2499 
   2500 int
   2501 scf_iter_pg_properties(scf_iter_t *iter, const scf_propertygroup_t *pg)
   2502 {
   2503 	return (datael_setup_iter(iter, &pg->rd_d,
   2504 	    REP_PROTOCOL_ENTITY_PROPERTY, 0));
   2505 }
   2506 
   2507 int
   2508 scf_iter_next_property(scf_iter_t *iter, scf_property_t *out)
   2509 {
   2510 	return (datael_iter_next(iter, &out->rd_d));
   2511 }
   2512 
   2513 /*
   2514  * Fails with
   2515  *   _INVALID_ARGUMENT - handle is NULL
   2516  *   _INTERNAL - server response too big
   2517  *		 entity already set up with different type
   2518  *   _NO_RESOURCES
   2519  *   _NO_MEMORY
   2520  */
   2521 scf_scope_t *
   2522 scf_scope_create(scf_handle_t *handle)
   2523 {
   2524 	scf_scope_t *ret;
   2525 
   2526 	ret = uu_zalloc(sizeof (*ret));
   2527 	if (ret != NULL) {
   2528 		if (datael_init(&ret->rd_d, handle,
   2529 		    REP_PROTOCOL_ENTITY_SCOPE) == -1) {
   2530 			uu_free(ret);
   2531 			return (NULL);
   2532 		}
   2533 	} else {
   2534 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
   2535 	}
   2536 
   2537 	return (ret);
   2538 }
   2539 
   2540 scf_handle_t *
   2541 scf_scope_handle(const scf_scope_t *val)
   2542 {
   2543 	return (datael_handle(&val->rd_d));
   2544 }
   2545 
   2546 void
   2547 scf_scope_destroy(scf_scope_t *val)
   2548 {
   2549 	if (val == NULL)
   2550 		return;
   2551 
   2552 	datael_destroy(&val->rd_d);
   2553 	uu_free(val);
   2554 }
   2555 
   2556 ssize_t
   2557 scf_scope_get_name(const scf_scope_t *rep, char *out, size_t len)
   2558 {
   2559 	return (datael_get_name(&rep->rd_d, out, len, RP_ENTITY_NAME_NAME));
   2560 }
   2561 
   2562 /*ARGSUSED*/
   2563 int
   2564 scf_scope_get_parent(const scf_scope_t *child, scf_scope_t *parent)
   2565 {
   2566 	char name[1];
   2567 
   2568 	/* fake up the side-effects */
   2569 	datael_reset(&parent->rd_d);
   2570 	if (scf_scope_get_name(child, name, sizeof (name)) < 0)
   2571 		return (-1);
   2572 	return (scf_set_error(SCF_ERROR_NOT_FOUND));
   2573 }
   2574 
   2575 /*
   2576  * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
   2577  * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
   2578  */
   2579 scf_service_t *
   2580 scf_service_create(scf_handle_t *handle)
   2581 {
   2582 	scf_service_t *ret;
   2583 	ret = uu_zalloc(sizeof (*ret));
   2584 	if (ret != NULL) {
   2585 		if (datael_init(&ret->rd_d, handle,
   2586 		    REP_PROTOCOL_ENTITY_SERVICE) == -1) {
   2587 			uu_free(ret);
   2588 			return (NULL);
   2589 		}
   2590 	} else {
   2591 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
   2592 	}
   2593 
   2594 	return (ret);
   2595 }
   2596 
   2597 
   2598 /*
   2599  * Fails with
   2600  *   _HANDLE_MISMATCH
   2601  *   _INVALID_ARGUMENT
   2602  *   _NOT_BOUND
   2603  *   _CONNECTION_BROKEN
   2604  *   _INTERNAL
   2605  *   _EXISTS
   2606  *   _DELETED
   2607  *   _NOT_SET
   2608  *   _NO_RESOURCES
   2609  *   _PERMISSION_DENIED
   2610  *   _BACKEND_ACCESS
   2611  *   _BACKEND_READONLY
   2612  */
   2613 int
   2614 scf_scope_add_service(const scf_scope_t *scope, const char *name,
   2615     scf_service_t *svc)
   2616 {
   2617 	return (datael_add_child(&scope->rd_d, name,
   2618 	    REP_PROTOCOL_ENTITY_SERVICE, (svc != NULL)? &svc->rd_d : NULL));
   2619 }
   2620 
   2621 /*
   2622  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
   2623  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
   2624  * _BACKEND_ACCESS, _NOT_FOUND.
   2625  */
   2626 int
   2627 scf_scope_get_service(const scf_scope_t *s, const char *name,
   2628     scf_service_t *svc)
   2629 {
   2630 	return (datael_get_child(&s->rd_d, name, REP_PROTOCOL_ENTITY_SERVICE,
   2631 	    svc ? &svc->rd_d : NULL, 0));
   2632 }
   2633 
   2634 scf_handle_t *
   2635 scf_service_handle(const scf_service_t *val)
   2636 {
   2637 	return (datael_handle(&val->rd_d));
   2638 }
   2639 
   2640 int
   2641 scf_service_delete(scf_service_t *svc)
   2642 {
   2643 	return (datael_delete(&svc->rd_d));
   2644 }
   2645 
   2646 int
   2647 scf_instance_delete(scf_instance_t *inst)
   2648 {
   2649 	return (datael_delete(&inst->rd_d));
   2650 }
   2651 
   2652 int
   2653 scf_pg_delete(scf_propertygroup_t *pg)
   2654 {
   2655 	return (datael_delete(&pg->rd_d));
   2656 }
   2657 
   2658 int
   2659 _scf_snapshot_delete(scf_snapshot_t *snap)
   2660 {
   2661 	return (datael_delete(&snap->rd_d));
   2662 }
   2663 
   2664 /*
   2665  * Fails with
   2666  *   _HANDLE_MISMATCH
   2667  *   _INVALID_ARGUMENT
   2668  *   _NOT_BOUND
   2669  *   _CONNECTION_BROKEN
   2670  *   _INTERNAL
   2671  *   _EXISTS
   2672  *   _DELETED
   2673  *   _NOT_SET
   2674  *   _NO_RESOURCES
   2675  *   _PERMISSION_DENIED
   2676  *   _BACKEND_ACCESS
   2677  *   _BACKEND_READONLY
   2678  */
   2679 int
   2680 scf_service_add_instance(const scf_service_t *svc, const char *name,
   2681     scf_instance_t *instance)
   2682 {
   2683 	return (datael_add_child(&svc->rd_d, name,
   2684 	    REP_PROTOCOL_ENTITY_INSTANCE,
   2685 	    (instance != NULL)? &instance->rd_d : NULL));
   2686 }
   2687 
   2688 
   2689 /*
   2690  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
   2691  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
   2692  * _BACKEND_ACCESS, _NOT_FOUND.
   2693  */
   2694 int
   2695 scf_service_get_instance(const scf_service_t *svc, const char *name,
   2696     scf_instance_t *inst)
   2697 {
   2698 	return (datael_get_child(&svc->rd_d, name, REP_PROTOCOL_ENTITY_INSTANCE,
   2699 	    inst ? &inst->rd_d : NULL, 0));
   2700 }
   2701 
   2702 int
   2703 scf_service_add_pg(const scf_service_t *svc, const char *name,
   2704     const char *type, uint32_t flags, scf_propertygroup_t *pg)
   2705 {
   2706 	return (datael_add_pg(&svc->rd_d, name, type, flags,
   2707 	    (pg != NULL)?&pg->rd_d : NULL));
   2708 }
   2709 
   2710 /*
   2711  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
   2712  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
   2713  * _BACKEND_ACCESS, _NOT_FOUND.
   2714  */
   2715 int
   2716 scf_service_get_pg(const scf_service_t *svc, const char *name,
   2717     scf_propertygroup_t *pg)
   2718 {
   2719 	return (datael_get_child(&svc->rd_d, name,
   2720 	    REP_PROTOCOL_ENTITY_PROPERTYGRP, pg ? &pg->rd_d : NULL, 0));
   2721 }
   2722 
   2723 int
   2724 scf_instance_add_pg(const scf_instance_t *inst, const char *name,
   2725     const char *type, uint32_t flags, scf_propertygroup_t *pg)
   2726 {
   2727 	return (datael_add_pg(&inst->rd_d, name, type, flags,
   2728 	    (pg != NULL)?&pg->rd_d : NULL));
   2729 }
   2730 
   2731 /*
   2732  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
   2733  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
   2734  * _BACKEND_ACCESS, _NOT_FOUND.
   2735  */
   2736 int
   2737 scf_instance_get_snapshot(const scf_instance_t *inst, const char *name,
   2738     scf_snapshot_t *pg)
   2739 {
   2740 	return (datael_get_child(&inst->rd_d, name,
   2741 	    REP_PROTOCOL_ENTITY_SNAPSHOT, pg ? &pg->rd_d : NULL, 0));
   2742 }
   2743 
   2744 /*
   2745  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
   2746  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
   2747  * _BACKEND_ACCESS, _NOT_FOUND.
   2748  */
   2749 int
   2750 scf_instance_get_pg(const scf_instance_t *inst, const char *name,
   2751     scf_propertygroup_t *pg)
   2752 {
   2753 	return (datael_get_child(&inst->rd_d, name,
   2754 	    REP_PROTOCOL_ENTITY_PROPERTYGRP, pg ? &pg->rd_d : NULL, 0));
   2755 }
   2756 
   2757 /*
   2758  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
   2759  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
   2760  * _BACKEND_ACCESS, _NOT_FOUND.
   2761  */
   2762 int
   2763 scf_instance_get_pg_composed(const scf_instance_t *inst,
   2764     const scf_snapshot_t *snap, const char *name, scf_propertygroup_t *pg)
   2765 {
   2766 	if (snap != NULL && inst->rd_d.rd_handle != snap->rd_d.rd_handle)
   2767 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
   2768 
   2769 	return (datael_get_child(snap ? &snap->rd_d : &inst->rd_d, name,
   2770 	    REP_PROTOCOL_ENTITY_PROPERTYGRP, pg ? &pg->rd_d : NULL, 1));
   2771 }
   2772 
   2773 /*
   2774  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
   2775  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
   2776  * _BACKEND_ACCESS, _NOT_FOUND.
   2777  */
   2778 int
   2779 scf_pg_get_property(const scf_propertygroup_t *pg, const char *name,
   2780     scf_property_t *prop)
   2781 {
   2782 	return (datael_get_child(&pg->rd_d, name, REP_PROTOCOL_ENTITY_PROPERTY,
   2783 	    prop ? &prop->rd_d : NULL, 0));
   2784 }
   2785 
   2786 void
   2787 scf_service_destroy(scf_service_t *val)
   2788 {
   2789 	if (val == NULL)
   2790 		return;
   2791 
   2792 	datael_destroy(&val->rd_d);
   2793 	uu_free(val);
   2794 }
   2795 
   2796 ssize_t
   2797 scf_service_get_name(const scf_service_t *rep, char *out, size_t len)
   2798 {
   2799 	return (datael_get_name(&rep->rd_d, out, len, RP_ENTITY_NAME_NAME));
   2800 }
   2801 
   2802 /*
   2803  * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
   2804  * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
   2805  */
   2806 scf_instance_t *
   2807 scf_instance_create(scf_handle_t *handle)
   2808 {
   2809 	scf_instance_t *ret;
   2810 
   2811 	ret = uu_zalloc(sizeof (*ret));
   2812 	if (ret != NULL) {
   2813 		if (datael_init(&ret->rd_d, handle,
   2814 		    REP_PROTOCOL_ENTITY_INSTANCE) == -1) {
   2815 			uu_free(ret);
   2816 			return (NULL);
   2817 		}
   2818 	} else {
   2819 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
   2820 	}
   2821 
   2822 	return (ret);
   2823 }
   2824 
   2825 scf_handle_t *
   2826 scf_instance_handle(const scf_instance_t *val)
   2827 {
   2828 	return (datael_handle(&val->rd_d));
   2829 }
   2830 
   2831 void
   2832 scf_instance_destroy(scf_instance_t *val)
   2833 {
   2834 	if (val == NULL)
   2835 		return;
   2836 
   2837 	datael_destroy(&val->rd_d);
   2838 	uu_free(val);
   2839 }
   2840 
   2841 ssize_t
   2842 scf_instance_get_name(const scf_instance_t *rep, char *out, size_t len)
   2843 {
   2844 	return (datael_get_name(&rep->rd_d, out, len, RP_ENTITY_NAME_NAME));
   2845 }
   2846 
   2847 /*
   2848  * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
   2849  * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
   2850  */
   2851 scf_snapshot_t *
   2852 scf_snapshot_create(scf_handle_t *handle)
   2853 {
   2854 	scf_snapshot_t *ret;
   2855 
   2856 	ret = uu_zalloc(sizeof (*ret));
   2857 	if (ret != NULL) {
   2858 		if (datael_init(&ret->rd_d, handle,
   2859 		    REP_PROTOCOL_ENTITY_SNAPSHOT) == -1) {
   2860 			uu_free(ret);
   2861 			return (NULL);
   2862 		}
   2863 	} else {
   2864 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
   2865 	}
   2866 
   2867 	return (ret);
   2868 }
   2869 
   2870 scf_handle_t *
   2871 scf_snapshot_handle(const scf_snapshot_t *val)
   2872 {
   2873 	return (datael_handle(&val->rd_d));
   2874 }
   2875 
   2876 void
   2877 scf_snapshot_destroy(scf_snapshot_t *val)
   2878 {
   2879 	if (val == NULL)
   2880 		return;
   2881 
   2882 	datael_destroy(&val->rd_d);
   2883 	uu_free(val);
   2884 }
   2885 
   2886 ssize_t
   2887 scf_snapshot_get_name(const scf_snapshot_t *rep, char *out, size_t len)
   2888 {
   2889 	return (datael_get_name(&rep->rd_d, out, len, RP_ENTITY_NAME_NAME));
   2890 }
   2891 
   2892 /*
   2893  * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
   2894  * (bad server response or id in use), _NO_RESOURCES, _NO_MEMORY.
   2895  */
   2896 scf_snaplevel_t *
   2897 scf_snaplevel_create(scf_handle_t *handle)
   2898 {
   2899 	scf_snaplevel_t *ret;
   2900 
   2901 	ret = uu_zalloc(sizeof (*ret));
   2902 	if (ret != NULL) {
   2903 		if (datael_init(&ret->rd_d, handle,
   2904 		    REP_PROTOCOL_ENTITY_SNAPLEVEL) == -1) {
   2905 			uu_free(ret);
   2906 			return (NULL);
   2907 		}
   2908 	} else {
   2909 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
   2910 	}
   2911 
   2912 	return (ret);
   2913 }
   2914 
   2915 scf_handle_t *
   2916 scf_snaplevel_handle(const scf_snaplevel_t *val)
   2917 {
   2918 	return (datael_handle(&val->rd_d));
   2919 }
   2920 
   2921 void
   2922 scf_snaplevel_destroy(scf_snaplevel_t *val)
   2923 {
   2924 	if (val == NULL)
   2925 		return;
   2926 
   2927 	datael_destroy(&val->rd_d);
   2928 	uu_free(val);
   2929 }
   2930 
   2931 ssize_t
   2932 scf_snaplevel_get_scope_name(const scf_snaplevel_t *rep, char *out, size_t len)
   2933 {
   2934 	return (datael_get_name(&rep->rd_d, out, len,
   2935 	    RP_ENTITY_NAME_SNAPLEVEL_SCOPE));
   2936 }
   2937 
   2938 ssize_t
   2939 scf_snaplevel_get_service_name(const scf_snaplevel_t *rep, char *out,
   2940     size_t len)
   2941 {
   2942 	return (datael_get_name(&rep->rd_d, out, len,
   2943 	    RP_ENTITY_NAME_SNAPLEVEL_SERVICE));
   2944 }
   2945 
   2946 ssize_t
   2947 scf_snaplevel_get_instance_name(const scf_snaplevel_t *rep, char *out,
   2948     size_t len)
   2949 {
   2950 	return (datael_get_name(&rep->rd_d, out, len,
   2951 	    RP_ENTITY_NAME_SNAPLEVEL_INSTANCE));
   2952 }
   2953 
   2954 /*
   2955  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
   2956  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
   2957  * _BACKEND_ACCESS, _NOT_FOUND.
   2958  */
   2959 int
   2960 scf_snaplevel_get_pg(const scf_snaplevel_t *snap, const char *name,
   2961     scf_propertygroup_t *pg)
   2962 {
   2963 	return (datael_get_child(&snap->rd_d, name,
   2964 	    REP_PROTOCOL_ENTITY_PROPERTYGRP, pg ? &pg->rd_d : NULL, 0));
   2965 }
   2966 
   2967 static int
   2968 snaplevel_next(const scf_datael_t *src, scf_snaplevel_t *dst_arg)
   2969 {
   2970 	scf_handle_t *h = src->rd_handle;
   2971 	scf_snaplevel_t *dst = dst_arg;
   2972 	struct rep_protocol_entity_pair request;
   2973 	struct rep_protocol_response response;
   2974 	int r;
   2975 	int dups = 0;
   2976 
   2977 	if (h != dst->rd_d.rd_handle)
   2978 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
   2979 
   2980 	if (src == &dst->rd_d) {
   2981 		dups = 1;
   2982 		dst = HANDLE_HOLD_SNAPLVL(h);
   2983 	}
   2984 	(void) pthread_mutex_lock(&h->rh_lock);
   2985 	request.rpr_request = REP_PROTOCOL_NEXT_SNAPLEVEL;
   2986 	request.rpr_entity_src = src->rd_entity;
   2987 	request.rpr_entity_dst = dst->rd_d.rd_entity;
   2988 
   2989 	datael_finish_reset(src);
   2990 	datael_finish_reset(&dst->rd_d);
   2991 	r = make_door_call(h, &request, sizeof (request),
   2992 	    &response, sizeof (response));
   2993 	/*
   2994 	 * if we succeeded, we need to swap dst and dst_arg's identity.  We
   2995 	 * take advantage of the fact that the only in-library knowledge is
   2996 	 * their entity ids.
   2997 	 */
   2998 	if (dups && r >= 0 &&
   2999 	    (response.rpr_response == REP_PROTOCOL_SUCCESS ||
   3000 	    response.rpr_response == REP_PROTOCOL_DONE)) {
   3001 		int entity = dst->rd_d.rd_entity;
   3002 
   3003 		dst->rd_d.rd_entity = dst_arg->rd_d.rd_entity;
   3004 		dst_arg->rd_d.rd_entity = entity;
   3005 	}
   3006 	(void) pthread_mutex_unlock(&h->rh_lock);
   3007 
   3008 	if (dups)
   3009 		HANDLE_RELE_SNAPLVL(h);
   3010 
   3011 	if (r < 0)
   3012 		DOOR_ERRORS_BLOCK(r);
   3013 
   3014 	if (response.rpr_response != REP_PROTOCOL_SUCCESS &&
   3015 	    response.rpr_response != REP_PROTOCOL_DONE) {
   3016 		return (scf_set_error(proto_error(response.rpr_response)));
   3017 	}
   3018 
   3019 	return (response.rpr_response == REP_PROTOCOL_SUCCESS) ?
   3020 	    SCF_SUCCESS : SCF_COMPLETE;
   3021 }
   3022 
   3023 int scf_snapshot_get_base_snaplevel(const scf_snapshot_t *base,
   3024     scf_snaplevel_t *out)
   3025 {
   3026 	return (snaplevel_next(&base->rd_d, out));
   3027 }
   3028 
   3029 int scf_snaplevel_get_next_snaplevel(const scf_snaplevel_t *base,
   3030     scf_snaplevel_t *out)
   3031 {
   3032 	return (snaplevel_next(&base->rd_d, out));
   3033 }
   3034 
   3035 /*
   3036  * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
   3037  * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
   3038  */
   3039 scf_propertygroup_t *
   3040 scf_pg_create(scf_handle_t *handle)
   3041 {
   3042 	scf_propertygroup_t *ret;
   3043 	ret = uu_zalloc(sizeof (*ret));
   3044 	if (ret != NULL) {
   3045 		if (datael_init(&ret->rd_d, handle,
   3046 		    REP_PROTOCOL_ENTITY_PROPERTYGRP) == -1) {
   3047 			uu_free(ret);
   3048 			return (NULL);
   3049 		}
   3050 	} else {
   3051 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
   3052 	}
   3053 
   3054 	return (ret);
   3055 }
   3056 
   3057 scf_handle_t *
   3058 scf_pg_handle(const scf_propertygroup_t *val)
   3059 {
   3060 	return (datael_handle(&val->rd_d));
   3061 }
   3062 
   3063 void
   3064 scf_pg_destroy(scf_propertygroup_t *val)
   3065 {
   3066 	if (val == NULL)
   3067 		return;
   3068 
   3069 	datael_destroy(&val->rd_d);
   3070 	uu_free(val);
   3071 }
   3072 
   3073 ssize_t
   3074 scf_pg_get_name(const scf_propertygroup_t *pg,  char *out, size_t len)
   3075 {
   3076 	return (datael_get_name(&pg->rd_d, out, len, RP_ENTITY_NAME_NAME));
   3077 }
   3078 
   3079 ssize_t
   3080 scf_pg_get_type(const scf_propertygroup_t *pg,  char *out, size_t len)
   3081 {
   3082 	return (datael_get_name(&pg->rd_d, out, len, RP_ENTITY_NAME_PGTYPE));
   3083 }
   3084 
   3085 int
   3086 scf_pg_get_flags(const scf_propertygroup_t *pg, uint32_t *out)
   3087 {
   3088 	char buf[REP_PROTOCOL_NAME_LEN];
   3089 	ssize_t res;
   3090 
   3091 	res = datael_get_name(&pg->rd_d, buf, sizeof (buf),
   3092 	    RP_ENTITY_NAME_PGFLAGS);
   3093 
   3094 	if (res == -1)
   3095 		return (-1);
   3096 
   3097 	if (uu_strtouint(buf, out, sizeof (*out), 0, 0, UINT32_MAX) == -1)
   3098 		return (scf_set_error(SCF_ERROR_INTERNAL));
   3099 
   3100 	return (0);
   3101 }
   3102 
   3103 static int
   3104 datael_update(scf_datael_t *dp)
   3105 {
   3106 	scf_handle_t *h = dp->rd_handle;
   3107 
   3108 	struct rep_protocol_entity_update request;
   3109 	struct rep_protocol_response response;
   3110 
   3111 	int r;
   3112 
   3113 	(void) pthread_mutex_lock(&h->rh_lock);
   3114 	request.rpr_request = REP_PROTOCOL_ENTITY_UPDATE;
   3115 	request.rpr_entityid = dp->rd_entity;
   3116 
   3117 	datael_finish_reset(dp);
   3118 	request.rpr_changeid = handle_next_changeid(h);
   3119 
   3120 	r = make_door_call(h, &request, sizeof (request),
   3121 	    &response, sizeof (response));
   3122 	(void) pthread_mutex_unlock(&h->rh_lock);
   3123 
   3124 	if (r < 0)
   3125 		DOOR_ERRORS_BLOCK(r);
   3126 
   3127 	/*
   3128 	 * This should never happen but if it does something has
   3129 	 * gone terribly wrong and we should abort.
   3130 	 */
   3131 	if (response.rpr_response == REP_PROTOCOL_FAIL_BAD_REQUEST)
   3132 		abort();
   3133 
   3134 	if (response.rpr_response != REP_PROTOCOL_SUCCESS &&
   3135 	    response.rpr_response != REP_PROTOCOL_DONE) {
   3136 		return (scf_set_error(proto_error(response.rpr_response)));
   3137 	}
   3138 
   3139 	return (response.rpr_response == REP_PROTOCOL_SUCCESS) ?
   3140 	    SCF_SUCCESS : SCF_COMPLETE;
   3141 }
   3142 
   3143 int
   3144 scf_pg_update(scf_propertygroup_t *pg)
   3145 {
   3146 	return (datael_update(&pg->rd_d));
   3147 }
   3148 
   3149 int
   3150 scf_snapshot_update(scf_snapshot_t *snap)
   3151 {
   3152 	return (datael_update(&snap->rd_d));
   3153 }
   3154 
   3155 int
   3156 _scf_pg_wait(scf_propertygroup_t *pg, int timeout)
   3157 {
   3158 	scf_handle_t *h = pg->rd_d.rd_handle;
   3159 
   3160 	struct rep_protocol_propertygrp_request request;
   3161 	struct rep_protocol_response response;
   3162 
   3163 	struct pollfd pollfd;
   3164 
   3165 	int r;
   3166 
   3167 	(void) pthread_mutex_lock(&h->rh_lock);
   3168 	request.rpr_request = REP_PROTOCOL_PROPERTYGRP_SETUP_WAIT;
   3169 	request.rpr_entityid = pg->rd_d.rd_entity;
   3170 
   3171 	datael_finish_reset(&pg->rd_d);
   3172 	if (!handle_is_bound(h)) {
   3173 		(void) pthread_mutex_unlock(&h->rh_lock);
   3174 		return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN));
   3175 	}
   3176 	r = make_door_call_retfd(h->rh_doorfd, &request, sizeof (request),
   3177 	    &response, sizeof (response), &pollfd.fd);
   3178 	(void) pthread_mutex_unlock(&h->rh_lock);
   3179 
   3180 	if (r < 0)
   3181 		DOOR_ERRORS_BLOCK(r);
   3182 
   3183 	assert((response.rpr_response == REP_PROTOCOL_SUCCESS) ==
   3184 	    (pollfd.fd != -1));
   3185 
   3186 	if (response.rpr_response == REP_PROTOCOL_FAIL_NOT_LATEST)
   3187 		return (SCF_SUCCESS);
   3188 
   3189 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
   3190 		return (scf_set_error(proto_error(response.rpr_response)));
   3191 
   3192 	pollfd.events = 0;
   3193 	pollfd.revents = 0;
   3194 
   3195 	r = poll(&pollfd, 1, timeout * MILLISEC);
   3196 
   3197 	(void) close(pollfd.fd);
   3198 	return (pollfd.revents ? SCF_SUCCESS : SCF_COMPLETE);
   3199 }
   3200 
   3201 static int
   3202 scf_notify_add_pattern(scf_handle_t *h, int type, const char *name)
   3203 {
   3204 	struct rep_protocol_notify_request request;
   3205 	struct rep_protocol_response response;
   3206 	int r;
   3207 
   3208 	(void) pthread_mutex_lock(&h->rh_lock);
   3209 	request.rpr_request = REP_PROTOCOL_CLIENT_ADD_NOTIFY;
   3210 	request.rpr_type = type;
   3211 	(void) strlcpy(request.rpr_pattern, name, sizeof (request.rpr_pattern));
   3212 
   3213 	r = make_door_call(h, &request, sizeof (request),
   3214 	    &response, sizeof (response));
   3215 	(void) pthread_mutex_unlock(&h->rh_lock);
   3216 
   3217 	if (r < 0)
   3218 		DOOR_ERRORS_BLOCK(r);
   3219 
   3220 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
   3221 		return (scf_set_error(proto_error(response.rpr_response)));
   3222 
   3223 	return (SCF_SUCCESS);
   3224 }
   3225 
   3226 int
   3227 _scf_notify_add_pgname(scf_handle_t *h, const char *name)
   3228 {
   3229 	return (scf_notify_add_pattern(h, REP_PROTOCOL_NOTIFY_PGNAME, name));
   3230 }
   3231 
   3232 int
   3233 _scf_notify_add_pgtype(scf_handle_t *h, const char *type)
   3234 {
   3235 	return (scf_notify_add_pattern(h, REP_PROTOCOL_NOTIFY_PGTYPE, type));
   3236 }
   3237 
   3238 int
   3239 _scf_notify_wait(scf_propertygroup_t *pg, char *out, size_t sz)
   3240 {
   3241 	struct rep_protocol_wait_request request;
   3242 	struct rep_protocol_fmri_response response;
   3243 
   3244 	scf_handle_t *h = pg->rd_d.rd_handle;
   3245 	int dummy;
   3246 	int fd;
   3247 	int r;
   3248 
   3249 	(void) pthread_mutex_lock(&h->rh_lock);
   3250 	datael_finish_reset(&pg->rd_d);
   3251 	if (!handle_is_bound(h)) {
   3252 		(void) pthread_mutex_unlock(&h->rh_lock);
   3253 		return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN));
   3254 	}
   3255 	fd = h->rh_doorfd;
   3256 	++h->rh_fd_users;
   3257 	assert(h->rh_fd_users > 0);
   3258 
   3259 	request.rpr_request = REP_PROTOCOL_CLIENT_WAIT;
   3260 	request.rpr_entityid = pg->rd_d.rd_entity;
   3261 	(void) pthread_mutex_unlock(&h->rh_lock);
   3262 
   3263 	r = make_door_call_retfd(fd, &request, sizeof (request),
   3264 	    &response, sizeof (response), &dummy);
   3265 
   3266 	(void) pthread_mutex_lock(&h->rh_lock);
   3267 	assert(h->rh_fd_users > 0);
   3268 	if (--h->rh_fd_users == 0) {
   3269 		(void) pthread_cond_broadcast(&h->rh_cv);
   3270 		/*
   3271 		 * check for a delayed close, now that there are no other
   3272 		 * users.
   3273 		 */
   3274 		if (h->rh_doorfd_old != -1) {
   3275 			assert(h->rh_doorfd == -1);
   3276 			assert(fd == h->rh_doorfd_old);
   3277 			(void) close(h->rh_doorfd_old);
   3278 			h->rh_doorfd_old = -1;
   3279 		}
   3280 	}
   3281 	handle_unrefed(h);			/* drops h->rh_lock */
   3282 
   3283 	if (r < 0)
   3284 		DOOR_ERRORS_BLOCK(r);
   3285 
   3286 	if (response.rpr_response == REP_PROTOCOL_DONE)
   3287 		return (scf_set_error(SCF_ERROR_NOT_SET));
   3288 
   3289 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
   3290 		return (scf_set_error(proto_error(response.rpr_response)));
   3291 
   3292 	/* the following will be non-zero for delete notifications */
   3293 	return (strlcpy(out, response.rpr_fmri, sz));
   3294 }
   3295 
   3296 static int
   3297 _scf_snapshot_take(scf_instance_t *inst, const char *name,
   3298     scf_snapshot_t *snap, int flags)
   3299 {
   3300 	scf_handle_t *h = inst->rd_d.rd_handle;
   3301 
   3302 	struct rep_protocol_snapshot_take request;
   3303 	struct rep_protocol_response response;
   3304 
   3305 	int r;
   3306 
   3307 	if (h != snap->rd_d.rd_handle)
   3308 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
   3309 
   3310 	if (strlcpy(request.rpr_name, (name != NULL)? name : "",
   3311 	    sizeof (request.rpr_name)) >= sizeof (request.rpr_name))
   3312 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
   3313 
   3314 	(void) pthread_mutex_lock(&h->rh_lock);
   3315 	request.rpr_request = REP_PROTOCOL_SNAPSHOT_TAKE;
   3316 	request.rpr_entityid_src = inst->rd_d.rd_entity;
   3317 	request.rpr_entityid_dest = snap->rd_d.rd_entity;
   3318 	request.rpr_flags = flags;
   3319 
   3320 	datael_finish_reset(&inst->rd_d);
   3321 	datael_finish_reset(&snap->rd_d);
   3322 
   3323 	r = make_door_call(h, &request, sizeof (request),
   3324 	    &response, sizeof (response));
   3325 	(void) pthread_mutex_unlock(&h->rh_lock);
   3326 
   3327 	if (r < 0)
   3328 		DOOR_ERRORS_BLOCK(r);
   3329 
   3330 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
   3331 		return (scf_set_error(proto_error(response.rpr_response)));
   3332 
   3333 	return (SCF_SUCCESS);
   3334 }
   3335 
   3336 int
   3337 _scf_snapshot_take_new_named(scf_instance_t *inst,
   3338     const char *svcname, const char *instname, const char *snapname,
   3339     scf_snapshot_t *snap)
   3340 {
   3341 	scf_handle_t *h = inst->rd_d.rd_handle;
   3342 
   3343 	struct rep_protocol_snapshot_take_named request;
   3344 	struct rep_protocol_response response;
   3345 
   3346 	int r;
   3347 
   3348 	if (h != snap->rd_d.rd_handle)
   3349 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
   3350 
   3351 	if (strlcpy(request.rpr_svcname, svcname,
   3352 	    sizeof (request.rpr_svcname)) >= sizeof (request.rpr_svcname))
   3353 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
   3354 
   3355 	if (strlcpy(request.rpr_instname, instname,
   3356 	    sizeof (request.rpr_instname)) >= sizeof (request.rpr_instname))
   3357 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
   3358 
   3359 	if (strlcpy(request.rpr_name, snapname,
   3360 	    sizeof (request.rpr_name)) >= sizeof (request.rpr_name))
   3361 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
   3362 
   3363 	(void) pthread_mutex_lock(&h->rh_lock);
   3364 	request.rpr_request = REP_PROTOCOL_SNAPSHOT_TAKE_NAMED;
   3365 	request.rpr_entityid_src = inst->rd_d.rd_entity;
   3366 	request.rpr_entityid_dest = snap->rd_d.rd_entity;
   3367 
   3368 	datael_finish_reset(&inst->rd_d);
   3369 	datael_finish_reset(&snap->rd_d);
   3370 
   3371 	r = make_door_call(h, &request, sizeof (request),
   3372 	    &response, sizeof (response));
   3373 	(void) pthread_mutex_unlock(&h->rh_lock);
   3374 
   3375 	if (r < 0)
   3376 		DOOR_ERRORS_BLOCK(r);
   3377 
   3378 	if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
   3379 		assert(response.rpr_response !=
   3380 		    REP_PROTOCOL_FAIL_TYPE_MISMATCH);
   3381 		return (scf_set_error(proto_error(response.rpr_response)));
   3382 	}
   3383 
   3384 	return (SCF_SUCCESS);
   3385 }
   3386 
   3387 int
   3388 _scf_snapshot_take_new(scf_instance_t *inst, const char *name,
   3389     scf_snapshot_t *snap)
   3390 {
   3391 	return (_scf_snapshot_take(inst, name, snap, REP_SNAPSHOT_NEW));
   3392 }
   3393 
   3394 int
   3395 _scf_snapshot_take_attach(scf_instance_t *inst, scf_snapshot_t *snap)
   3396 {
   3397 	return (_scf_snapshot_take(inst, NULL, snap, REP_SNAPSHOT_ATTACH));
   3398 }
   3399 
   3400 int
   3401 _scf_snapshot_attach(scf_snapshot_t *src, scf_snapshot_t *dest)
   3402 {
   3403 	scf_handle_t *h = dest->rd_d.rd_handle;
   3404 
   3405 	struct rep_protocol_snapshot_attach request;
   3406 	struct rep_protocol_response response;
   3407 
   3408 	int r;
   3409 
   3410 	if (h != src->rd_d.rd_handle)
   3411 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
   3412 
   3413 	(void) pthread_mutex_lock(&h->rh_lock);
   3414 	request.rpr_request = REP_PROTOCOL_SNAPSHOT_ATTACH;
   3415 	request.rpr_entityid_src = src->rd_d.rd_entity;
   3416 	request.rpr_entityid_dest = dest->rd_d.rd_entity;
   3417 
   3418 	datael_finish_reset(&src->rd_d);
   3419 	datael_finish_reset(&dest->rd_d);
   3420 
   3421 	r = make_door_call(h, &request, sizeof (request),
   3422 	    &response, sizeof (response));
   3423 	(void) pthread_mutex_unlock(&h->rh_lock);
   3424 
   3425 	if (r < 0)
   3426 		DOOR_ERRORS_BLOCK(r);
   3427 
   3428 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
   3429 		return (scf_set_error(proto_error(response.rpr_response)));
   3430 
   3431 	return (SCF_SUCCESS);
   3432 }
   3433 
   3434 /*
   3435  * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
   3436  * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
   3437  */
   3438 scf_property_t *
   3439 scf_property_create(scf_handle_t *handle)
   3440 {
   3441 	scf_property_t *ret;
   3442 	ret = uu_zalloc(sizeof (*ret));
   3443 	if (ret != NULL) {
   3444 		if (datael_init(&ret->rd_d, handle,
   3445 		    REP_PROTOCOL_ENTITY_PROPERTY) == -1) {
   3446 			uu_free(ret);
   3447 			return (NULL);
   3448 		}
   3449 	} else {
   3450 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
   3451 	}
   3452 
   3453 	return (ret);
   3454 }
   3455 
   3456 scf_handle_t *
   3457 scf_property_handle(const scf_property_t *val)
   3458 {
   3459 	return (datael_handle(&val->rd_d));
   3460 }
   3461 
   3462 void
   3463 scf_property_destroy(scf_property_t *val)
   3464 {
   3465 	if (val == NULL)
   3466 		return;
   3467 
   3468 	datael_destroy(&val->rd_d);
   3469 	uu_free(val);
   3470 }
   3471 
   3472 static int
   3473 property_type_locked(const scf_property_t *prop,
   3474     rep_protocol_value_type_t *out)
   3475 {
   3476 	scf_handle_t *h = prop->rd_d.rd_handle;
   3477 
   3478 	struct rep_protocol_property_request request;
   3479 	struct rep_protocol_integer_response response;
   3480 
   3481 	int r;
   3482 
   3483 	assert(MUTEX_HELD(&h->rh_lock));
   3484 
   3485 	request.rpr_request = REP_PROTOCOL_PROPERTY_GET_TYPE;
   3486 	request.rpr_entityid = prop->rd_d.rd_entity;
   3487 
   3488 	datael_finish_reset(&prop->rd_d);
   3489 	r = make_door_call(h, &request, sizeof (request),
   3490 	    &response, sizeof (response));
   3491 
   3492 	if (r < 0)
   3493 		DOOR_ERRORS_BLOCK(r);
   3494 
   3495 	if (response.rpr_response != REP_PROTOCOL_SUCCESS ||
   3496 	    r < sizeof (response)) {
   3497 		return (scf_set_error(proto_error(response.rpr_response)));
   3498 	}
   3499 	*out = response.rpr_value;
   3500 	return (SCF_SUCCESS);
   3501 }
   3502 
   3503 int
   3504 scf_property_type(const scf_property_t *prop, scf_type_t *out)
   3505 {
   3506 	scf_handle_t *h = prop->rd_d.rd_handle;
   3507 	rep_protocol_value_type_t out_raw;
   3508 	int ret;
   3509 
   3510 	(void) pthread_mutex_lock(&h->rh_lock);
   3511 	ret = property_type_locked(prop, &out_raw);
   3512 	(void) pthread_mutex_unlock(&h->rh_lock);
   3513 
   3514 	if (ret == SCF_SUCCESS)
   3515 		*out = scf_protocol_type_to_type(out_raw);
   3516 
   3517 	return (ret);
   3518 }
   3519 
   3520 int
   3521 scf_property_is_type(const scf_property_t *prop, scf_type_t base_arg)
   3522 {
   3523 	scf_handle_t *h = prop->rd_d.rd_handle;
   3524 	rep_protocol_value_type_t base = scf_type_to_protocol_type(base_arg);
   3525 	rep_protocol_value_type_t type;
   3526 	int ret;
   3527 
   3528 	if (base == REP_PROTOCOL_TYPE_INVALID)
   3529 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
   3530 
   3531 	(void) pthread_mutex_lock(&h->rh_lock);
   3532 	ret = property_type_locked(prop, &type);
   3533 	(void) pthread_mutex_unlock(&h->rh_lock);
   3534 
   3535 	if (ret == SCF_SUCCESS) {
   3536 		if (!scf_is_compatible_protocol_type(base, type))
   3537 			return (scf_set_error(SCF_ERROR_TYPE_MISMATCH));
   3538 	}
   3539 	return (ret);
   3540 }
   3541 
   3542 int
   3543 scf_is_compatible_type(scf_type_t base_arg, scf_type_t type_arg)
   3544 {
   3545 	rep_protocol_value_type_t base = scf_type_to_protocol_type(base_arg);
   3546 	rep_protocol_value_type_t type = scf_type_to_protocol_type(type_arg);
   3547 
   3548 	if (base == REP_PROTOCOL_TYPE_INVALID ||
   3549 	    type == REP_PROTOCOL_TYPE_INVALID)
   3550 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
   3551 
   3552 	if (!scf_is_compatible_protocol_type(base, type))
   3553 		return (scf_set_error(SCF_ERROR_TYPE_MISMATCH));
   3554 
   3555 	return (SCF_SUCCESS);
   3556 }
   3557 
   3558 ssize_t
   3559 scf_property_get_name(const scf_property_t *prop, char *out, size_t len)
   3560 {
   3561 	return (datael_get_name(&prop->rd_d, out, len, RP_ENTITY_NAME_NAME));
   3562 }
   3563 
   3564 /*
   3565  * transaction functions
   3566  */
   3567 
   3568 /*
   3569  * Fails with _NO_MEMORY, _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED,
   3570  * _INTERNAL (bad server response or id in use), or _NO_RESOURCES.
   3571  */
   3572 scf_transaction_t *
   3573 scf_transaction_create(scf_handle_t *handle)
   3574 {
   3575 	scf_transaction_t *ret;
   3576 
   3577 	ret = uu_zalloc(sizeof (scf_transaction_t));
   3578 	if (ret == NULL) {
   3579 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
   3580 		return (NULL);
   3581 	}
   3582 	if (datael_init(&ret->tran_pg.rd_d, handle,
   3583 	    REP_PROTOCOL_ENTITY_PROPERTYGRP) == -1) {
   3584 		uu_free(ret);
   3585 		return (NULL);			/* error already set */
   3586 	}
   3587 	ret->tran_state = TRAN_STATE_NEW;
   3588 	ret->tran_props = uu_list_create(tran_entry_pool, ret, UU_LIST_SORTED);
   3589 	if (ret->tran_props == NULL) {
   3590 		datael_destroy(&ret->tran_pg.rd_d);
   3591 		uu_free(ret);
   3592 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
   3593 		return (NULL);
   3594 	}
   3595 
   3596 	return (ret);
   3597 }
   3598 
   3599 scf_handle_t *
   3600 scf_transaction_handle(const scf_transaction_t *val)
   3601 {
   3602 	return (handle_get(val->tran_pg.rd_d.rd_handle));
   3603 }
   3604 
   3605 int
   3606 scf_transaction_start(scf_transaction_t *tran, scf_propertygroup_t *pg)
   3607 {
   3608 	scf_handle_t *h = tran->tran_pg.rd_d.rd_handle;
   3609 
   3610 	struct rep_protocol_transaction_start request;
   3611 	struct rep_protocol_response response;
   3612 	int r;
   3613 
   3614 	if (h != pg->rd_d.rd_handle)
   3615 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
   3616 
   3617 	(void) pthread_mutex_lock(&h->rh_lock);
   3618 	if (tran->tran_state != TRAN_STATE_NEW) {
   3619 		(void) pthread_mutex_unlock(&h->rh_lock);
   3620 		return (scf_set_error(SCF_ERROR_IN_USE));
   3621 	}
   3622 	request.rpr_request = REP_PROTOCOL_PROPERTYGRP_TX_START;
   3623 	request.rpr_entityid_tx = tran->tran_pg.rd_d.rd_entity;
   3624 	request.rpr_entityid = pg->rd_d.rd_entity;
   3625 
   3626 	datael_finish_reset(&tran->tran_pg.rd_d);
   3627 	datael_finish_reset(&pg->rd_d);
   3628 
   3629 	r = make_door_call(h, &request, sizeof (request),
   3630 	    &response, sizeof (response));
   3631 
   3632 	if (r < 0) {
   3633 		(void) pthread_mutex_unlock(&h->rh_lock);
   3634 		DOOR_ERRORS_BLOCK(r);
   3635 	}
   3636 
   3637 	/* r < sizeof (response) cannot happen because sizeof (response) == 4 */
   3638 
   3639 	if (response.rpr_response != REP_PROTOCOL_SUCCESS ||
   3640 	    r < sizeof (response)) {
   3641 		(void) pthread_mutex_unlock(&h->rh_lock);
   3642 		return (scf_set_error(proto_error(response.rpr_response)));
   3643 	}
   3644 
   3645 	tran->tran_state = TRAN_STATE_SETUP;
   3646 	tran->tran_invalid = 0;
   3647 	(void) pthread_mutex_unlock(&h->rh_lock);
   3648 	return (SCF_SUCCESS);
   3649 }
   3650 
   3651 static void
   3652 entry_invalidate(scf_transaction_entry_t *cur, int and_destroy,
   3653     int and_reset_value)
   3654 {
   3655 	scf_value_t *v, *next;
   3656 	scf_transaction_t *tx;
   3657 	scf_handle_t *h = cur->entry_handle;
   3658 
   3659 	assert(MUTEX_HELD(&h->rh_lock));
   3660 
   3661 	if ((tx = cur->entry_tx) != NULL) {
   3662 		tx->tran_invalid = 1;
   3663 		uu_list_remove(tx->tran_props, cur);
   3664 		cur->entry_tx = NULL;
   3665 	}
   3666 
   3667 	cur->entry_property = NULL;
   3668 	cur->entry_state = ENTRY_STATE_INVALID;
   3669 	cur->entry_action = REP_PROTOCOL_TX_ENTRY_INVALID;
   3670 	cur->entry_type = REP_PROTOCOL_TYPE_INVALID;
   3671 
   3672 	for (v = cur->entry_head; v != NULL; v = next) {
   3673 		next = v->value_next;
   3674 		v->value_tx = NULL;
   3675 		v->value_next = NULL;
   3676 		if (and_destroy || and_reset_value)
   3677 			scf_value_reset_locked(v, and_destroy);
   3678 	}
   3679 	cur->entry_head = NULL;
   3680 	cur->entry_tail = NULL;
   3681 }
   3682 
   3683 static void
   3684 entry_destroy_locked(scf_transaction_entry_t *entry)
   3685 {
   3686 	scf_handle_t *h = entry->entry_handle;
   3687 
   3688 	assert(MUTEX_HELD(&h->rh_lock));
   3689 
   3690 	entry_invalidate(entry, 0, 0);
   3691 
   3692 	entry->entry_handle = NULL;
   3693 	assert(h->rh_entries > 0);
   3694 	--h->rh_entries;
   3695 	--h->rh_extrefs;
   3696 	uu_list_node_fini(entry, &entry->entry_link, tran_entry_pool);
   3697 	uu_free(entry);
   3698 }
   3699 
   3700 /*
   3701  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
   3702  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
   3703  * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
   3704  */
   3705 static int
   3706 transaction_add(scf_transaction_t *tran, scf_transaction_entry_t *entry,
   3707     enum rep_protocol_transaction_action action,
   3708     const char *prop, rep_protocol_value_type_t type)
   3709 {
   3710 	scf_handle_t *h = tran->tran_pg.rd_d.rd_handle;
   3711 	scf_transaction_entry_t *old;
   3712 	scf_property_t *prop_p;
   3713 	rep_protocol_value_type_t oldtype;
   3714 	scf_error_t error = SCF_ERROR_NONE;
   3715 	int ret;
   3716 	uu_list_index_t idx;
   3717 
   3718 	if (h != entry->entry_handle)
   3719 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
   3720 
   3721 	if (action == REP_PROTOCOL_TX_ENTRY_DELETE)
   3722 		assert(type == REP_PROTOCOL_TYPE_INVALID);
   3723 	else if (type == REP_PROTOCOL_TYPE_INVALID)
   3724 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
   3725 
   3726 	prop_p = HANDLE_HOLD_PROPERTY(h);
   3727 
   3728 	(void) pthread_mutex_lock(&h->rh_lock);
   3729 	if (tran->tran_state != TRAN_STATE_SETUP) {
   3730 		error = SCF_ERROR_NOT_SET;
   3731 		goto error;
   3732 	}
   3733 	if (tran->tran_invalid) {
   3734 		error = SCF_ERROR_NOT_SET;
   3735 		goto error;
   3736 	}
   3737 
   3738 	if (entry->entry_state != ENTRY_STATE_INVALID)
   3739 		entry_invalidate(entry, 0, 0);
   3740 
   3741 	old = uu_list_find(tran->tran_props, &prop, NULL, &idx);
   3742 	if (old != NULL) {
   3743 		error = SCF_ERROR_IN_USE;
   3744 		goto error;
   3745 	}
   3746 
   3747 	ret = datael_get_child_locked(&tran->tran_pg.rd_d, prop,
   3748 	    REP_PROTOCOL_ENTITY_PROPERTY, &prop_p->rd_d);
   3749 	if (ret == -1 && (error = scf_error()) != SCF_ERROR_NOT_FOUND) {
   3750 		goto error;
   3751 	}
   3752 
   3753 	switch (action) {
   3754 	case REP_PROTOCOL_TX_ENTRY_DELETE:
   3755 		if (ret == -1) {
   3756 			error = SCF_ERROR_NOT_FOUND;
   3757 			goto error;
   3758 		}
   3759 		break;
   3760 	case REP_PROTOCOL_TX_ENTRY_NEW:
   3761 		if (ret != -1) {
   3762 			error = SCF_ERROR_EXISTS;
   3763 			goto error;
   3764 		}
   3765 		break;
   3766 
   3767 	case REP_PROTOCOL_TX_ENTRY_CLEAR:
   3768 	case REP_PROTOCOL_TX_ENTRY_REPLACE:
   3769 		if (ret == -1) {
   3770 			error = SCF_ERROR_NOT_FOUND;
   3771 			goto error;
   3772 		}
   3773 		if (action == REP_PROTOCOL_TX_ENTRY_CLEAR) {
   3774 			if (property_type_locked(prop_p, &oldtype) == -1) {
   3775 				error = scf_error();
   3776 				goto error;
   3777 			}
   3778 			if (oldtype != type) {
   3779 				error = SCF_ERROR_TYPE_MISMATCH;
   3780 				goto error;
   3781 			}
   3782 		}
   3783 		break;
   3784 	default:
   3785 		assert(0);
   3786 		abort();
   3787 	}
   3788 
   3789 	(void) strlcpy(entry->entry_namebuf, prop,
   3790 	    sizeof (entry->entry_namebuf));
   3791 	entry->entry_property = entry->entry_namebuf;
   3792 	entry->entry_action = action;
   3793 	entry->entry_type = type;
   3794 
   3795 	entry->entry_state = ENTRY_STATE_IN_TX_ACTION;
   3796 	entry->entry_tx = tran;
   3797 	uu_list_insert(tran->tran_props, entry, idx);
   3798 
   3799 	(void) pthread_mutex_unlock(&h->rh_lock);
   3800 
   3801 	HANDLE_RELE_PROPERTY(h);
   3802 
   3803 	return (SCF_SUCCESS);
   3804 
   3805 error:
   3806 	(void) pthread_mutex_unlock(&h->rh_lock);
   3807 
   3808 	HANDLE_RELE_PROPERTY(h);
   3809 
   3810 	return (scf_set_error(error));
   3811 }
   3812 
   3813 /*
   3814  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
   3815  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
   3816  * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
   3817  */
   3818 int
   3819 scf_transaction_property_new(scf_transaction_t *tx,
   3820     scf_transaction_entry_t *entry, const char *prop, scf_type_t type)
   3821 {
   3822 	return (transaction_add(tx, entry, REP_PROTOCOL_TX_ENTRY_NEW,
   3823 	    prop, scf_type_to_protocol_type(type)));
   3824 }
   3825 
   3826 /*
   3827  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
   3828  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
   3829  * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
   3830  */
   3831 int
   3832 scf_transaction_property_change(scf_transaction_t *tx,
   3833     scf_transaction_entry_t *entry, const char *prop, scf_type_t type)
   3834 {
   3835 	return (transaction_add(tx, entry, REP_PROTOCOL_TX_ENTRY_CLEAR,
   3836 	    prop, scf_type_to_protocol_type(type)));
   3837 }
   3838 
   3839 /*
   3840  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
   3841  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
   3842  * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
   3843  */
   3844 int
   3845 scf_transaction_property_change_type(scf_transaction_t *tx,
   3846     scf_transaction_entry_t *entry, const char *prop, scf_type_t type)
   3847 {
   3848 	return (transaction_add(tx, entry, REP_PROTOCOL_TX_ENTRY_REPLACE,
   3849 	    prop, scf_type_to_protocol_type(type)));
   3850 }
   3851 
   3852 /*
   3853  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
   3854  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
   3855  * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
   3856  */
   3857 int
   3858 scf_transaction_property_delete(scf_transaction_t *tx,
   3859     scf_transaction_entry_t *entry, const char *prop)
   3860 {
   3861 	return (transaction_add(tx, entry, REP_PROTOCOL_TX_ENTRY_DELETE,
   3862 	    prop, REP_PROTOCOL_TYPE_INVALID));
   3863 }
   3864 
   3865 #define	BAD_SIZE (-1UL)
   3866 
   3867 static size_t
   3868 commit_value(caddr_t data, scf_value_t *val, rep_protocol_value_type_t t)
   3869 {
   3870 	size_t len;
   3871 
   3872 	assert(val->value_type == t);
   3873 
   3874 	if (t == REP_PROTOCOL_TYPE_OPAQUE) {
   3875 		len = scf_opaque_encode(data, val->value_value,
   3876 		    val->value_size);
   3877 	} else {
   3878 		if (data != NULL)
   3879 			len = strlcpy(data, val->value_value,
   3880 			    REP_PROTOCOL_VALUE_LEN);
   3881 		else
   3882 			len = strlen(val->value_value);
   3883 		if (len >= REP_PROTOCOL_VALUE_LEN)
   3884 			return (BAD_SIZE);
   3885 	}
   3886 	return (len + 1);	/* count the '\0' */
   3887 }
   3888 
   3889 static size_t
   3890 commit_process(scf_transaction_entry_t *cur,
   3891     struct rep_protocol_transaction_cmd *out)
   3892 {
   3893 	scf_value_t *child;
   3894 	size_t sz = 0;
   3895 	size_t len;
   3896 	caddr_t data = (caddr_t)out->rptc_data;
   3897 	caddr_t val_data;
   3898 
   3899 	if (out != NULL) {
   3900 		len = strlcpy(data, cur->entry_property, REP_PROTOCOL_NAME_LEN);
   3901 
   3902 		out->rptc_action = cur->entry_action;
   3903 		out->rptc_type = cur->entry_type;
   3904 		out->rptc_name_len = len + 1;
   3905 	} else {
   3906 		len = strlen(cur->entry_property);
   3907 	}
   3908 
   3909 	if (len >= REP_PROTOCOL_NAME_LEN)
   3910 		return (BAD_SIZE);
   3911 
   3912 	len = TX_SIZE(len + 1);
   3913 
   3914 	sz += len;
   3915 	val_data = data + len;
   3916 
   3917 	for (child = cur->entry_head; child != NULL;
   3918 	    child = child->value_next) {
   3919 		assert(cur->entry_action != REP_PROTOCOL_TX_ENTRY_DELETE);
   3920 		if (out != NULL) {
   3921 			len = commit_value(val_data + sizeof (uint32_t), child,
   3922 			    cur->entry_type);
   3923 			/* LINTED alignment */
   3924 			*(uint32_t *)val_data = len;
   3925 		} else
   3926 			len = commit_value(NULL, child, cur->entry_type);
   3927 
   3928 		if (len == BAD_SIZE)
   3929 			return (BAD_SIZE);
   3930 
   3931 		len += sizeof (uint32_t);
   3932 		len = TX_SIZE(len);
   3933 
   3934 		sz += len;
   3935 		val_data += len;
   3936 	}
   3937 
   3938 	assert(val_data - data == sz);
   3939 
   3940 	if (out != NULL)
   3941 		out->rptc_size = REP_PROTOCOL_TRANSACTION_CMD_SIZE(sz);
   3942 
   3943 	return (REP_PROTOCOL_TRANSACTION_CMD_SIZE(sz));
   3944 }
   3945 
   3946 int
   3947 scf_transaction_commit(scf_transaction_t *tran)
   3948 {
   3949 	scf_handle_t *h = tran->tran_pg.rd_d.rd_handle;
   3950 
   3951 	struct rep_protocol_transaction_commit *request;
   3952 	struct rep_protocol_response response;
   3953 	uintptr_t cmd;
   3954 	scf_transaction_entry_t *cur;
   3955 	size_t total, size;
   3956 	size_t request_size;
   3957 	size_t new_total;
   3958 	int r;
   3959 
   3960 	(void) pthread_mutex_lock(&h->rh_lock);
   3961 	if (tran->tran_state != TRAN_STATE_SETUP ||
   3962 	    tran->tran_invalid) {
   3963 		(void) pthread_mutex_unlock(&h->rh_lock);
   3964 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
   3965 	}
   3966 
   3967 	total = 0;
   3968 	for (cur = uu_list_first(tran->tran_props); cur != NULL;
   3969 	    cur = uu_list_next(tran->tran_props, cur)) {
   3970 		size = commit_process(cur, NULL);
   3971 		if (size == BAD_SIZE) {
   3972 			(void) pthread_mutex_unlock(&h->rh_lock);
   3973 			return (scf_set_error(SCF_ERROR_INTERNAL));
   3974 		}
   3975 		assert(TX_SIZE(size) == size);
   3976 		total += size;
   3977 	}
   3978 
   3979 	request_size = REP_PROTOCOL_TRANSACTION_COMMIT_SIZE(total);
   3980 	request = alloca(request_size);
   3981 	(void) memset(request, '\0', request_size);
   3982 	request->rpr_request = REP_PROTOCOL_PROPERTYGRP_TX_COMMIT;
   3983 	request->rpr_entityid = tran->tran_pg.rd_d.rd_entity;
   3984 	request->rpr_size = request_size;
   3985 	cmd = (uintptr_t)request->rpr_cmd;
   3986 
   3987 	datael_finish_reset(&tran->tran_pg.rd_d);
   3988 
   3989 	new_total = 0;
   3990 	for (cur = uu_list_first(tran->tran_props); cur != NULL;
   3991 	    cur = uu_list_next(tran->tran_props, cur)) {
   3992 		size = commit_process(cur, (void *)cmd);
   3993 		if (size == BAD_SIZE) {
   3994 			(void) pthread_mutex_unlock(&h->rh_lock);
   3995 			return (scf_set_error(SCF_ERROR_INTERNAL));
   3996 		}
   3997 		cmd += size;
   3998 		new_total += size;
   3999 	}
   4000 	assert(new_total == total);
   4001 
   4002 	r = make_door_call(h, request, request_size,
   4003 	    &response, sizeof (response));
   4004 
   4005 	if (r < 0) {
   4006 		(void) pthread_mutex_unlock(&h->rh_lock);
   4007 		DOOR_ERRORS_BLOCK(r);
   4008 	}
   4009 
   4010 	if (response.rpr_response != REP_PROTOCOL_SUCCESS &&
   4011 	    response.rpr_response != REP_PROTOCOL_FAIL_NOT_LATEST) {
   4012 		(void) pthread_mutex_unlock(&h->rh_lock);
   4013 		return (scf_set_error(proto_error(response.rpr_response)));
   4014 	}
   4015 
   4016 	tran->tran_state = TRAN_STATE_COMMITTED;
   4017 	(void) pthread_mutex_unlock(&h->rh_lock);
   4018 	return (response.rpr_response == REP_PROTOCOL_SUCCESS);
   4019 }
   4020 
   4021 static void
   4022 transaction_reset(scf_transaction_t *tran)
   4023 {
   4024 	assert(MUTEX_HELD(&tran->tran_pg.rd_d.rd_handle->rh_lock));
   4025 
   4026 	tran->tran_state = TRAN_STATE_NEW;
   4027 	datael_reset_locked(&tran->tran_pg.rd_d);
   4028 }
   4029 
   4030 static void
   4031 scf_transaction_reset_impl(scf_transaction_t *tran, int and_destroy,
   4032     int and_reset_value)
   4033 {
   4034 	scf_transaction_entry_t *cur;
   4035 	void *cookie;
   4036 
   4037 	(void) pthread_mutex_lock(&tran->tran_pg.rd_d.rd_handle->rh_lock);
   4038 	cookie = NULL;
   4039 	while ((cur = uu_list_teardown(tran->tran_props, &cookie)) != NULL) {
   4040 		cur->entry_tx = NULL;
   4041 
   4042 		assert(cur->entry_state == ENTRY_STATE_IN_TX_ACTION);
   4043 		cur->entry_state = ENTRY_STATE_INVALID;
   4044 
   4045 		entry_invalidate(cur, and_destroy, and_reset_value);
   4046 		if (and_destroy)
   4047 			entry_destroy_locked(cur);
   4048 	}
   4049 	transaction_reset(tran);
   4050 	handle_unrefed(tran->tran_pg.rd_d.rd_handle);
   4051 }
   4052 
   4053 void
   4054 scf_transaction_reset(scf_transaction_t *tran)
   4055 {
   4056 	scf_transaction_reset_impl(tran, 0, 0);
   4057 }
   4058 
   4059 void
   4060 scf_transaction_reset_all(scf_transaction_t *tran)
   4061 {
   4062 	scf_transaction_reset_impl(tran, 0, 1);
   4063 }
   4064 
   4065 void
   4066 scf_transaction_destroy(scf_transaction_t *val)
   4067 {
   4068 	if (val == NULL)
   4069 		return;
   4070 
   4071 	scf_transaction_reset(val);
   4072 
   4073 	datael_destroy(&val->tran_pg.rd_d);
   4074 
   4075 	uu_list_destroy(val->tran_props);
   4076 	uu_free(val);
   4077 }
   4078 
   4079 void
   4080 scf_transaction_destroy_children(scf_transaction_t *tran)
   4081 {
   4082 	scf_transaction_reset_impl(tran, 1, 0);
   4083 }
   4084 
   4085 scf_transaction_entry_t *
   4086 scf_entry_create(scf_handle_t *h)
   4087 {
   4088 	scf_transaction_entry_t *ret;
   4089 
   4090 	if (h == NULL) {
   4091 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
   4092 		return (NULL);
   4093 	}
   4094 
   4095 	ret = uu_zalloc(sizeof (scf_transaction_entry_t));
   4096 	if (ret == NULL) {
   4097 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
   4098 		return (NULL);
   4099 	}
   4100 	ret->entry_action = REP_PROTOCOL_TX_ENTRY_INVALID;
   4101 	ret->entry_handle = h;
   4102 
   4103 	(void) pthread_mutex_lock(&h->rh_lock);
   4104 	if (h->rh_flags & HANDLE_DEAD) {
   4105 		(void) pthread_mutex_unlock(&h->rh_lock);
   4106 		uu_free(ret);
   4107 		(void) scf_set_error(SCF_ERROR_HANDLE_DESTROYED);
   4108 		return (NULL);
   4109 	}
   4110 	h->rh_entries++;
   4111 	h->rh_extrefs++;
   4112 	(void) pthread_mutex_unlock(&h->rh_lock);
   4113 
   4114 	uu_list_node_init(ret, &ret->entry_link, tran_entry_pool);
   4115 
   4116 	return (ret);
   4117 }
   4118 
   4119 scf_handle_t *
   4120 scf_entry_handle(const scf_transaction_entry_t *val)
   4121 {
   4122 	return (handle_get(val->entry_handle));
   4123 }
   4124 
   4125 void
   4126 scf_entry_reset(scf_transaction_entry_t *entry)
   4127 {
   4128 	scf_handle_t *h = entry->entry_handle;
   4129 
   4130 	(void) pthread_mutex_lock(&h->rh_lock);
   4131 	entry_invalidate(entry, 0, 0);
   4132 	(void) pthread_mutex_unlock(&h->rh_lock);
   4133 }
   4134 
   4135 void
   4136 scf_entry_destroy_children(scf_transaction_entry_t *entry)
   4137 {
   4138 	scf_handle_t *h = entry->entry_handle;
   4139 
   4140 	(void) pthread_mutex_lock(&h->rh_lock);
   4141 	entry_invalidate(entry, 1, 0);
   4142 	handle_unrefed(h);			/* drops h->rh_lock */
   4143 }
   4144 
   4145 void
   4146 scf_entry_destroy(scf_transaction_entry_t *entry)
   4147 {
   4148 	scf_handle_t *h;
   4149 
   4150 	if (entry == NULL)
   4151 		return;
   4152 
   4153 	h = entry->entry_handle;
   4154 
   4155 	(void) pthread_mutex_lock(&h->rh_lock);
   4156 	entry_destroy_locked(entry);
   4157 	handle_unrefed(h);			/* drops h->rh_lock */
   4158 }
   4159 
   4160 /*
   4161  * Fails with
   4162  *   _HANDLE_MISMATCH
   4163  *   _NOT_SET - has not been added to a transaction
   4164  *   _INTERNAL - entry is corrupt
   4165  *   _INVALID_ARGUMENT - entry's transaction is not started or corrupt
   4166  *			 entry is set to delete a property
   4167  *			 v is reset or corrupt
   4168  *   _TYPE_MISMATCH - entry & v's types aren't compatible
   4169  *   _IN_USE - v has been added to another entry
   4170  */
   4171 int
   4172 scf_entry_add_value(scf_transaction_entry_t *entry, scf_value_t *v)
   4173 {
   4174 	scf_handle_t *h = entry->entry_handle;
   4175 
   4176 	if (h != v->value_handle)
   4177 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
   4178 
   4179 	(void) pthread_mutex_lock(&h->rh_lock);
   4180 
   4181 	if (entry->entry_state == ENTRY_STATE_INVALID) {
   4182 		(void) pthread_mutex_unlock(&h->rh_lock);
   4183 		return (scf_set_error(SCF_ERROR_NOT_SET));
   4184 	}
   4185 
   4186 	if (entry->entry_state != ENTRY_STATE_IN_TX_ACTION) {
   4187 		(void) pthread_mutex_unlock(&h->rh_lock);
   4188 		return (scf_set_error(SCF_ERROR_INTERNAL));
   4189 	}
   4190 
   4191 	if (entry->entry_tx->tran_state != TRAN_STATE_SETUP) {
   4192 		(void) pthread_mutex_unlock(&h->rh_lock);
   4193 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
   4194 	}
   4195 
   4196 	if (entry->entry_action == REP_PROTOCOL_TX_ENTRY_DELETE) {
   4197 		(void) pthread_mutex_unlock(&h->rh_lock);
   4198 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
   4199 	}
   4200 
   4201 	if (v->value_type == REP_PROTOCOL_TYPE_INVALID) {
   4202 		(void) pthread_mutex_unlock(&h->rh_lock);
   4203 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
   4204 	}
   4205 
   4206 	if (!scf_is_compatible_protocol_type(entry->entry_type,
   4207 	    v->value_type)) {
   4208 		(void) pthread_mutex_unlock(&h->rh_lock);
   4209 		return (scf_set_error(SCF_ERROR_TYPE_MISMATCH));
   4210 	}
   4211 
   4212 	if (v->value_tx != NULL) {
   4213 		(void) pthread_mutex_unlock(&h->rh_lock);
   4214 		return (scf_set_error(SCF_ERROR_IN_USE));
   4215 	}
   4216 
   4217 	v->value_tx = entry;
   4218 	v->value_next = NULL;
   4219 	if (entry->entry_head == NULL) {
   4220 		entry->entry_head = v;
   4221 		entry->entry_tail = v;
   4222 	} else {
   4223 		entry->entry_tail->value_next = v;
   4224 		entry->entry_tail = v;
   4225 	}
   4226 
   4227 	(void) pthread_mutex_unlock(&h->rh_lock);
   4228 
   4229 	return (SCF_SUCCESS);
   4230 }
   4231 
   4232 /*
   4233  * value functions
   4234  */
   4235 scf_value_t *
   4236 scf_value_create(scf_handle_t *h)
   4237 {
   4238 	scf_value_t *ret;
   4239 
   4240 	if (h == NULL) {
   4241 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
   4242 		return (NULL);
   4243 	}
   4244 
   4245 	ret = uu_zalloc(sizeof (*ret));
   4246 	if (ret != NULL) {
   4247 		ret->value_type = REP_PROTOCOL_TYPE_INVALID;
   4248 		ret->value_handle = h;
   4249 		(void) pthread_mutex_lock(&h->rh_lock);
   4250 		if (h->rh_flags & HANDLE_DEAD) {
   4251 			(void) pthread_mutex_unlock(&h->rh_lock);
   4252 			uu_free(ret);
   4253 			(void) scf_set_error(SCF_ERROR_HANDLE_DESTROYED);
   4254 			return (NULL);
   4255 		}
   4256 		h->rh_values++;
   4257 		h->rh_extrefs++;
   4258 		(void) pthread_mutex_unlock(&h->rh_lock);
   4259 	} else {
   4260 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
   4261 	}
   4262 
   4263 	return (ret);
   4264 }
   4265 
   4266 static void
   4267 scf_value_reset_locked(scf_value_t *val, int and_destroy)
   4268 {
   4269 	scf_value_t **curp;
   4270 	scf_transaction_entry_t *te;
   4271 
   4272 	scf_handle_t *h = val->value_handle;
   4273 	assert(MUTEX_HELD(&h->rh_lock));
   4274 	if (val->value_tx != NULL) {
   4275 		te = val->value_tx;
   4276 		te->entry_tx->tran_invalid = 1;
   4277 
   4278 		val->value_tx = NULL;
   4279 
   4280 		for (curp = &te->entry_head; *curp != NULL;
   4281 		    curp = &(*curp)->value_next) {
   4282 			if (*curp == val) {
   4283 				*curp = val->value_next;
   4284 				curp = NULL;
   4285 				break;
   4286 			}
   4287 		}
   4288 		assert(curp == NULL);
   4289 	}
   4290 	val->value_type = REP_PROTOCOL_TYPE_INVALID;
   4291 
   4292 	if (and_destroy) {
   4293 		val->value_handle = NULL;
   4294 		assert(h->rh_values > 0);
   4295 		--h->rh_values;
   4296 		--h->rh_extrefs;
   4297 		uu_free(val);
   4298 	}
   4299 }
   4300 
   4301 void
   4302 scf_value_reset(scf_value_t *val)
   4303 {
   4304 	scf_handle_t *h = val->value_handle;
   4305 
   4306 	(void) pthread_mutex_lock(&h->rh_lock);
   4307 	scf_value_reset_locked(val, 0);
   4308 	(void) pthread_mutex_unlock(&h->rh_lock);
   4309 }
   4310 
   4311 scf_handle_t *
   4312 scf_value_handle(const scf_value_t *val)
   4313 {
   4314 	return (handle_get(val->value_handle));
   4315 }
   4316 
   4317 void
   4318 scf_value_destroy(scf_value_t *val)
   4319 {
   4320 	scf_handle_t *h;
   4321 
   4322 	if (val == NULL)
   4323 		return;
   4324 
   4325 	h = val->value_handle;
   4326 
   4327 	(void) pthread_mutex_lock(&h->rh_lock);
   4328 	scf_value_reset_locked(val, 1);
   4329 	handle_unrefed(h);			/* drops h->rh_lock */
   4330 }
   4331 
   4332 scf_type_t
   4333 scf_value_base_type(const scf_value_t *val)
   4334 {
   4335 	rep_protocol_value_type_t t, cur;
   4336 	scf_handle_t *h = val->value_handle;
   4337 
   4338 	(void) pthread_mutex_lock(&h->rh_lock);
   4339 	t = val->value_type;
   4340 	(void) pthread_mutex_unlock(&h->rh_lock);
   4341 
   4342 	for (;;) {
   4343 		cur = scf_proto_underlying_type(t);
   4344 		if (cur == t)
   4345 			break;
   4346 		t = cur;
   4347 	}
   4348 
   4349 	return (scf_protocol_type_to_type(t));
   4350 }
   4351 
   4352 scf_type_t
   4353 scf_value_type(const scf_value_t *val)
   4354 {
   4355 	rep_protocol_value_type_t t;
   4356 	scf_handle_t *h = val->value_handle;
   4357 
   4358 	(void) pthread_mutex_lock(&h->rh_lock);
   4359 	t = val->value_type;
   4360 	(void) pthread_mutex_unlock(&h->rh_lock);
   4361 
   4362 	return (scf_protocol_type_to_type(t));
   4363 }
   4364 
   4365 int
   4366 scf_value_is_type(const scf_value_t *val, scf_type_t base_arg)
   4367 {
   4368 	rep_protocol_value_type_t t;
   4369 	rep_protocol_value_type_t base = scf_type_to_protocol_type(base_arg);
   4370 	scf_handle_t *h = val->value_handle;
   4371 
   4372 	(void) pthread_mutex_lock(&h->rh_lock);
   4373 	t = val->value_type;
   4374 	(void) pthread_mutex_unlock(&h->rh_lock);
   4375 
   4376 	if (t == REP_PROTOCOL_TYPE_INVALID)
   4377 		return (scf_set_error(SCF_ERROR_NOT_SET));
   4378 	if (base == REP_PROTOCOL_TYPE_INVALID)
   4379 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
   4380 	if (!scf_is_compatible_protocol_type(base, t))
   4381 		return (scf_set_error(SCF_ERROR_TYPE_MISMATCH));
   4382 
   4383 	return (SCF_SUCCESS);
   4384 }
   4385 
   4386 /*
   4387  * Fails with
   4388  *   _NOT_SET - val is reset
   4389  *   _TYPE_MISMATCH - val's type is not compatible with t
   4390  */
   4391 static int
   4392 scf_value_check_type(const scf_value_t *val, rep_protocol_value_type_t t)
   4393 {
   4394 	if (val->value_type == REP_PROTOCOL_TYPE_INVALID) {
   4395 		(void) scf_set_error(SCF_ERROR_NOT_SET);
   4396 		return (0);
   4397 	}
   4398 	if (!scf_is_compatible_protocol_type(t, val->value_type)) {
   4399 		(void) scf_set_error(SCF_ERROR_TYPE_MISMATCH);
   4400 		return (0);
   4401 	}
   4402 	return (1);
   4403 }
   4404 
   4405 /*
   4406  * Fails with
   4407  *   _NOT_SET - val is reset
   4408  *   _TYPE_MISMATCH - val is not _TYPE_BOOLEAN
   4409  */
   4410 int
   4411 scf_value_get_boolean(const scf_value_t *val, uint8_t *out)
   4412 {
   4413 	char c;
   4414 	scf_handle_t *h = val->value_handle;
   4415 	uint8_t o;
   4416 
   4417 	(void) pthread_mutex_lock(&h->rh_lock);
   4418 	if (!scf_value_check_type(val, REP_PROTOCOL_TYPE_BOOLEAN)) {
   4419 		(void) pthread_mutex_unlock(&h->rh_lock);
   4420 		return (-1);
   4421 	}
   4422 
   4423 	c = val->value_value[0];
   4424 	assert((c == '0' || c == '1') && val->value_value[1] == 0);
   4425 
   4426 	o = (c != '0');
   4427 	(void) pthread_mutex_unlock(&h->rh_lock);
   4428 	if (out != NULL)
   4429 		*out = o;
   4430 	return (SCF_SUCCESS);
   4431 }
   4432 
   4433 int
   4434 scf_value_get_count(const scf_value_t *val, uint64_t *out)
   4435 {
   4436 	scf_handle_t *h = val->value_handle;
   4437 	uint64_t o;
   4438 
   4439 	(void) pthread_mutex_lock(&h->rh_lock);
   4440 	if (!scf_value_check_type(val, REP_PROTOCOL_TYPE_COUNT)) {
   4441 		(void) pthread_mutex_unlock(&h->rh_lock);
   4442 		return (-1);
   4443 	}
   4444 
   4445 	o = strtoull(val->value_value, NULL, 10);
   4446 	(void) pthread_mutex_unlock(&h->rh_lock);
   4447 	if (out != NULL)
   4448 		*out = o;
   4449 	return (SCF_SUCCESS);
   4450 }
   4451 
   4452 int
   4453 scf_value_get_integer(const scf_value_t *val, int64_t *out)
   4454 {
   4455 	scf_handle_t *h = val->value_handle;
   4456 	int64_t o;
   4457 
   4458 	(void) pthread_mutex_lock(&h->rh_lock);
   4459 	if (!scf_value_check_type(val, REP_PROTOCOL_TYPE_INTEGER)) {
   4460 		(void) pthread_mutex_unlock(&h->rh_lock);
   4461 		return (-1);
   4462 	}
   4463 
   4464 	o = strtoll(val->value_value, NULL, 10);
   4465 	(void) pthread_mutex_unlock(&h->rh_lock);
   4466 	if (out != NULL)
   4467 		*out = o;
   4468 	return (SCF_SUCCESS);
   4469 }
   4470 
   4471 int
   4472 scf_value_get_time(const scf_value_t *val, int64_t *sec_out, int32_t *nsec_out)
   4473 {
   4474 	scf_handle_t *h = val->value_handle;
   4475 	char *p;
   4476 	int64_t os;
   4477 	int32_t ons;
   4478 
   4479 	(void) pthread_mutex_lock(&h->rh_lock);
   4480 	if (!scf_value_check_type(val, REP_PROTOCOL_TYPE_TIME)) {
   4481 		(void) pthread_mutex_unlock(&h->rh_lock);
   4482 		return (-1);
   4483 	}
   4484 
   4485 	os = strtoll(val->value_value, &p, 10);
   4486 	if (*p == '.')
   4487 		ons = strtoul(p + 1, NULL, 10);
   4488 	else
   4489 		ons = 0;
   4490 	(void) pthread_mutex_unlock(&h->rh_lock);
   4491 	if (sec_out != NULL)
   4492 		*sec_out = os;
   4493 	if (nsec_out != NULL)
   4494 		*nsec_out = ons;
   4495 
   4496 	return (SCF_SUCCESS);
   4497 }
   4498 
   4499 /*
   4500  * Fails with
   4501  *   _NOT_SET - val is reset
   4502  *   _TYPE_MISMATCH - val's type is not compatible with _TYPE_STRING.
   4503  */
   4504 ssize_t
   4505 scf_value_get_astring(const scf_value_t *val, char *out, size_t len)
   4506 {
   4507 	ssize_t ret;
   4508 	scf_handle_t *h = val->value_handle;
   4509 
   4510 	(void) pthread_mutex_lock(&h->rh_lock);
   4511 	if (!scf_value_check_type(val, REP_PROTOCOL_TYPE_STRING)) {
   4512 		(void) pthread_mutex_unlock(&h->rh_lock);
   4513 		return ((ssize_t)-1);
   4514 	}
   4515 	ret = (ssize_t)strlcpy(out, val->value_value, len);
   4516 	(void) pthread_mutex_unlock(&h->rh_lock);
   4517 	return (ret);
   4518 }
   4519 
   4520 ssize_t
   4521 scf_value_get_ustring(const scf_value_t *val, char *out, size_t len)
   4522 {
   4523 	ssize_t ret;
   4524 	scf_handle_t *h = val->value_handle;
   4525 
   4526 	(void) pthread_mutex_lock(&h->rh_lock);
   4527 	if (!scf_value_check_type(val, REP_PROTOCOL_SUBTYPE_USTRING)) {
   4528 		(void) pthread_mutex_unlock(&h->rh_lock);
   4529 		return ((ssize_t)-1);
   4530 	}
   4531 	ret = (ssize_t)strlcpy(out, val->value_value, len);
   4532 	(void) pthread_mutex_unlock(&h->rh_lock);
   4533 	return (ret);
   4534 }
   4535 
   4536 ssize_t
   4537 scf_value_get_opaque(const scf_value_t *v, void *out, size_t len)
   4538 {
   4539 	ssize_t ret;
   4540 	scf_handle_t *h = v->value_handle;
   4541 
   4542 	(void) pthread_mutex_lock(&h->rh_lock);
   4543 	if (!scf_value_check_type(v, REP_PROTOCOL_TYPE_OPAQUE)) {
   4544 		(void) pthread_mutex_unlock(&h->rh_lock);
   4545 		return ((ssize_t)-1);
   4546 	}
   4547 	if (len > v->value_size)
   4548 		len = v->value_size;
   4549 	ret = len;
   4550 
   4551 	(void) memcpy(out, v->value_value, len);
   4552 	(void) pthread_mutex_unlock(&h->rh_lock);
   4553 	return (ret);
   4554 }
   4555 
   4556 void
   4557 scf_value_set_boolean(scf_value_t *v, uint8_t new)
   4558 {
   4559 	scf_handle_t *h = v->value_handle;
   4560 
   4561 	(void) pthread_mutex_lock(&h->rh_lock);
   4562 	scf_value_reset_locked(v, 0);
   4563 	v->value_type = REP_PROTOCOL_TYPE_BOOLEAN;
   4564 	(void) sprintf(v->value_value, "%d", (new != 0));
   4565 	(void) pthread_mutex_unlock(&h->rh_lock);
   4566 }
   4567 
   4568 void
   4569 scf_value_set_count(scf_value_t *v, uint64_t new)
   4570 {
   4571 	scf_handle_t *h = v->value_handle;
   4572 
   4573 	(void) pthread_mutex_lock(&h->rh_lock);
   4574 	scf_value_reset_locked(v, 0);
   4575 	v->value_type = REP_PROTOCOL_TYPE_COUNT;
   4576 	(void) sprintf(v->value_value, "%llu", (unsigned long long)new);
   4577 	(void) pthread_mutex_unlock(&h->rh_lock);
   4578 }
   4579 
   4580 void
   4581 scf_value_set_integer(scf_value_t *v, int64_t new)
   4582 {
   4583 	scf_handle_t *h = v->value_handle;
   4584 
   4585 	(void) pthread_mutex_lock(&h->rh_lock);
   4586 	scf_value_reset_locked(v, 0);
   4587 	v->value_type = REP_PROTOCOL_TYPE_INTEGER;
   4588 	(void) sprintf(v->value_value, "%lld", (long long)new);
   4589 	(void) pthread_mutex_unlock(&h->rh_lock);
   4590 }
   4591 
   4592 int
   4593 scf_value_set_time(scf_value_t *v, int64_t new_sec, int32_t new_nsec)
   4594 {
   4595 	scf_handle_t *h = v->value_handle;
   4596 
   4597 	(void) pthread_mutex_lock(&h->rh_lock);
   4598 	scf_value_reset_locked(v, 0);
   4599 	if (new_nsec < 0 || new_nsec >= NANOSEC) {
   4600 		(void) pthread_mutex_unlock(&h->rh_lock);
   4601 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
   4602 	}
   4603 	v->value_type = REP_PROTOCOL_TYPE_TIME;
   4604 	if (new_nsec == 0)
   4605 		(void) sprintf(v->value_value, "%lld", (long long)new_sec);
   4606 	else
   4607 		(void) sprintf(v->value_value, "%lld.%09u", (long long)new_sec,
   4608 		    (unsigned)new_nsec);
   4609 	(void) pthread_mutex_unlock(&h->rh_lock);
   4610 	return (0);
   4611 }
   4612 
   4613 int
   4614 scf_value_set_astring(scf_value_t *v, const char *new)
   4615 {
   4616 	scf_handle_t *h = v->value_handle;
   4617 
   4618 	(void) pthread_mutex_lock(&h->rh_lock);
   4619 	scf_value_reset_locked(v, 0);
   4620 	if (!scf_validate_encoded_value(REP_PROTOCOL_TYPE_STRING, new)) {
   4621 		(void) pthread_mutex_unlock(&h->rh_lock);
   4622 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
   4623 	}
   4624 	if (strlcpy(v->value_value, new, sizeof (v->value_value)) >=
   4625 	    sizeof (v->value_value)) {
   4626 		(void) pthread_mutex_unlock(&h->rh_lock);
   4627 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
   4628 	}
   4629 	v->value_type = REP_PROTOCOL_TYPE_STRING;
   4630 	(void) pthread_mutex_unlock(&h->rh_lock);
   4631 	return (0);
   4632 }
   4633 
   4634 int
   4635 scf_value_set_ustring(scf_value_t *v, const char *new)
   4636 {
   4637 	scf_handle_t *h = v->value_handle;
   4638 
   4639 	(void) pthread_mutex_lock(&h->rh_lock);
   4640 	scf_value_reset_locked(v, 0);
   4641 	if (!scf_validate_encoded_value(REP_PROTOCOL_SUBTYPE_USTRING, new)) {
   4642 		(void) pthread_mutex_unlock(&h->rh_lock);
   4643 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
   4644 	}
   4645 	if (strlcpy(v->value_value, new, sizeof (v->value_value)) >=
   4646 	    sizeof (v->value_value)) {
   4647 		(void) pthread_mutex_unlock(&h->rh_lock);
   4648 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
   4649 	}
   4650 	v->value_type = REP_PROTOCOL_SUBTYPE_USTRING;
   4651 	(void) pthread_mutex_unlock(&h->rh_lock);
   4652 	return (0);
   4653 }
   4654 
   4655 int
   4656 scf_value_set_opaque(scf_value_t *v, const void *new, size_t len)
   4657 {
   4658 	scf_handle_t *h = v->value_handle;
   4659 
   4660 	(void) pthread_mutex_lock(&h->rh_lock);
   4661 	scf_value_reset_locked(v, 0);
   4662 	if (len > sizeof (v->value_value)) {
   4663 		(void) pthread_mutex_unlock(&h->rh_lock);
   4664 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
   4665 	}
   4666 	(void) memcpy(v->value_value, new, len);
   4667 	v->value_size = len;
   4668 	v->value_type = REP_PROTOCOL_TYPE_OPAQUE;
   4669 	(void) pthread_mutex_unlock(&h->rh_lock);
   4670 	return (0);
   4671 }
   4672 
   4673 /*
   4674  * Fails with
   4675  *   _NOT_SET - v_arg is reset
   4676  *   _INTERNAL - v_arg is corrupt
   4677  *
   4678  * If t is not _TYPE_INVALID, fails with
   4679  *   _TYPE_MISMATCH - v_arg's type is not compatible with t
   4680  */
   4681 static ssize_t
   4682 scf_value_get_as_string_common(const scf_value_t *v_arg,
   4683     rep_protocol_value_type_t t, char *buf, size_t bufsz)
   4684 {
   4685 	scf_handle_t *h = v_arg->value_handle;
   4686 	scf_value_t v_s;
   4687 	scf_value_t *v = &v_s;
   4688 	ssize_t r;
   4689 	uint8_t b;
   4690 
   4691 	(void) pthread_mutex_lock(&h->rh_lock);
   4692 	if (t != REP_PROTOCOL_TYPE_INVALID && !scf_value_check_type(v_arg, t)) {
   4693 		(void) pthread_mutex_unlock(&h->rh_lock);
   4694 		return (-1);
   4695 	}
   4696 
   4697 	v_s = *v_arg;			/* copy locally so we can unlock */
   4698 	h->rh_values++;			/* keep the handle from going away */
   4699 	h->rh_extrefs++;
   4700 	(void) pthread_mutex_unlock(&h->rh_lock);
   4701 
   4702 
   4703 	switch (REP_PROTOCOL_BASE_TYPE(v->value_type)) {
   4704 	case REP_PROTOCOL_TYPE_BOOLEAN:
   4705 		r = scf_value_get_boolean(v, &b);
   4706 		assert(r == SCF_SUCCESS);
   4707 
   4708 		r = strlcpy(buf, b ? "true" : "false", bufsz);
   4709 		break;
   4710 
   4711 	case REP_PROTOCOL_TYPE_COUNT:
   4712 	case REP_PROTOCOL_TYPE_INTEGER:
   4713 	case REP_PROTOCOL_TYPE_TIME:
   4714 	case REP_PROTOCOL_TYPE_STRING:
   4715 		r = strlcpy(buf, v->value_value, bufsz);
   4716 		break;
   4717 
   4718 	case REP_PROTOCOL_TYPE_OPAQUE:
   4719 		/*
   4720 		 * Note that we only write out full hex bytes -- if they're
   4721 		 * short, and bufsz is even, we'll only fill (bufsz - 2) bytes
   4722 		 * with data.
   4723 		 */
   4724 		if (bufsz > 0)
   4725 			(void) scf_opaque_encode(buf, v->value_value,
   4726 			    MIN(v->value_size, (bufsz - 1)/2));
   4727 		r = (v->value_size * 2);
   4728 		break;
   4729 
   4730 	case REP_PROTOCOL_TYPE_INVALID:
   4731 		r = scf_set_error(SCF_ERROR_NOT_SET);
   4732 		break;
   4733 
   4734 	default:
   4735 		r = (scf_set_error(SCF_ERROR_INTERNAL));
   4736 		break;
   4737 	}
   4738 
   4739 	(void) pthread_mutex_lock(&h->rh_lock);
   4740 	h->rh_values--;
   4741 	h->rh_extrefs--;
   4742 	handle_unrefed(h);
   4743 
   4744 	return (r);
   4745 }
   4746 
   4747 ssize_t
   4748 scf_value_get_as_string(const scf_value_t *v, char *buf, size_t bufsz)
   4749 {
   4750 	return (scf_value_get_as_string_common(v, REP_PROTOCOL_TYPE_INVALID,
   4751 	    buf, bufsz));
   4752 }
   4753 
   4754 ssize_t
   4755 scf_value_get_as_string_typed(const scf_value_t *v, scf_type_t type,
   4756     char *buf, size_t bufsz)
   4757 {
   4758 	rep_protocol_value_type_t ty = scf_type_to_protocol_type(type);
   4759 	if (ty == REP_PROTOCOL_TYPE_INVALID)
   4760 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
   4761 
   4762 	return (scf_value_get_as_string_common(v, ty, buf, bufsz));
   4763 }
   4764 
   4765 int
   4766 scf_value_set_from_string(scf_value_t *v, scf_type_t type, const char *str)
   4767 {
   4768 	scf_handle_t *h = v->value_handle;
   4769 	rep_protocol_value_type_t ty;
   4770 
   4771 	switch (type) {
   4772 	case SCF_TYPE_BOOLEAN: {
   4773 		uint8_t b;
   4774 
   4775 		if (strcmp(str, "true") == 0 || strcmp(str, "t") == 0 ||
   4776 		    strcmp(str, "1") == 0)
   4777 			b = 1;
   4778 		else if (strcmp(str, "false") == 0 ||
   4779 		    strcmp(str, "f") == 0 || strcmp(str, "0") == 0)
   4780 			b = 0;
   4781 		else {
   4782 			goto bad;
   4783 		}
   4784 
   4785 		scf_value_set_boolean(v, b);
   4786 		return (0);
   4787 	}
   4788 
   4789 	case SCF_TYPE_COUNT: {
   4790 		uint64_t c;
   4791 		char *endp;
   4792 
   4793 		errno = 0;
   4794 		c = strtoull(str, &endp, 0);
   4795 
   4796 		if (errno != 0 || endp == str || *endp != '\0')
   4797 			goto bad;
   4798 
   4799 		scf_value_set_count(v, c);
   4800 		return (0);
   4801 	}
   4802 
   4803 	case SCF_TYPE_INTEGER: {
   4804 		int64_t i;
   4805 		char *endp;
   4806 
   4807 		errno = 0;
   4808 		i = strtoll(str, &endp, 0);
   4809 
   4810 		if (errno != 0 || endp == str || *endp != '\0')
   4811 			goto bad;
   4812 
   4813 		scf_value_set_integer(v, i);
   4814 		return (0);
   4815 	}
   4816 
   4817 	case SCF_TYPE_TIME: {
   4818 		int64_t s;
   4819 		uint32_t ns = 0;
   4820 		char *endp, *ns_str;
   4821 		size_t len;
   4822 
   4823 		errno = 0;
   4824 		s = strtoll(str, &endp, 10);
   4825 		if (errno != 0 || endp == str ||
   4826 		    (*endp != '\0' && *endp != '.'))
   4827 			goto bad;
   4828 
   4829 		if (*endp == '.') {
   4830 			ns_str = endp + 1;
   4831 			len = strlen(ns_str);
   4832 			if (len == 0 || len > 9)
   4833 				goto bad;
   4834 
   4835 			ns = strtoul(ns_str, &endp, 10);
   4836 			if (errno != 0 || endp == ns_str || *endp != '\0')
   4837 				goto bad;
   4838 
   4839 			while (len++ < 9)
   4840 				ns *= 10;
   4841 			assert(ns < NANOSEC);
   4842 		}
   4843 
   4844 		return (scf_value_set_time(v, s, ns));
   4845 	}
   4846 
   4847 	case SCF_TYPE_ASTRING:
   4848 	case SCF_TYPE_USTRING:
   4849 	case SCF_TYPE_OPAQUE:
   4850 	case SCF_TYPE_URI:
   4851 	case SCF_TYPE_FMRI:
   4852 	case SCF_TYPE_HOST:
   4853 	case SCF_TYPE_HOSTNAME:
   4854 	case SCF_TYPE_NET_ADDR_V4:
   4855 	case SCF_TYPE_NET_ADDR_V6:
   4856 		ty = scf_type_to_protocol_type(type);
   4857 
   4858 		(void) pthread_mutex_lock(&h->rh_lock);
   4859 		scf_value_reset_locked(v, 0);
   4860 		if (type == SCF_TYPE_OPAQUE) {
   4861 			v->value_size = scf_opaque_decode(v->value_value,
   4862 			    str, sizeof (v->value_value));
   4863 			if (!scf_validate_encoded_value(ty, str)) {
   4864 				(void) pthread_mutex_lock(&h->rh_lock);
   4865 				goto bad;
   4866 			}
   4867 		} else {
   4868 			(void) strlcpy(v->value_value, str,
   4869 			    sizeof (v->value_value));
   4870 			if (!scf_validate_encoded_value(ty, v->value_value)) {
   4871 				(void) pthread_mutex_lock(&h->rh_lock);
   4872 				goto bad;
   4873 			}
   4874 		}
   4875 		v->value_type = ty;
   4876 		(void) pthread_mutex_unlock(&h->rh_lock);
   4877 		return (SCF_SUCCESS);
   4878 
   4879 	case REP_PROTOCOL_TYPE_INVALID:
   4880 	default:
   4881 		scf_value_reset(v);
   4882 		return (scf_set_error(SCF_ERROR_TYPE_MISMATCH));
   4883 	}
   4884 bad:
   4885 	scf_value_reset(v);
   4886 	return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
   4887 }
   4888 
   4889 int
   4890 scf_iter_property_values(scf_iter_t *iter, const scf_property_t *prop)
   4891 {
   4892 	return (datael_setup_iter(iter, &prop->rd_d,
   4893 	    REP_PROTOCOL_ENTITY_VALUE, 0));
   4894 }
   4895 
   4896 int
   4897 scf_iter_next_value(scf_iter_t *iter, scf_value_t *v)
   4898 {
   4899 	scf_handle_t *h = iter->iter_handle;
   4900 
   4901 	struct rep_protocol_iter_read_value request;
   4902 	struct rep_protocol_value_response response;
   4903 
   4904 	int r;
   4905 
   4906 	if (h != v->value_handle)
   4907 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
   4908 
   4909 	(void) pthread_mutex_lock(&h->rh_lock);
   4910 
   4911 	scf_value_reset_locked(v, 0);
   4912 
   4913 	if (iter->iter_type == REP_PROTOCOL_ENTITY_NONE) {
   4914 		(void) pthread_mutex_unlock(&h->rh_lock);
   4915 		return (scf_set_error(SCF_ERROR_NOT_SET));
   4916 	}
   4917 
   4918 	if (iter->iter_type != REP_PROTOCOL_ENTITY_VALUE) {
   4919 		(void) pthread_mutex_unlock(&h->rh_lock);
   4920 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
   4921 	}
   4922 
   4923 	request.rpr_request = REP_PROTOCOL_ITER_READ_VALUE;
   4924 	request.rpr_iterid = iter->iter_id;
   4925 	request.rpr_sequence = iter->iter_sequence;
   4926 
   4927 	r = make_door_call(h, &request, sizeof (request),
   4928 	    &response, sizeof (response));
   4929 
   4930 	if (r < 0) {
   4931 		(void) pthread_mutex_unlock(&h->rh_lock);
   4932 		DOOR_ERRORS_BLOCK(r);
   4933 	}
   4934 
   4935 	if (response.rpr_response == REP_PROTOCOL_DONE) {
   4936 		(void) pthread_mutex_unlock(&h->rh_lock);
   4937 		return (0);
   4938 	}
   4939 	if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
   4940 		(void) pthread_mutex_unlock(&h->rh_lock);
   4941 		return (scf_set_error(proto_error(response.rpr_response)));
   4942 	}
   4943 	iter->iter_sequence++;
   4944 
   4945 	v->value_type = response.rpr_type;
   4946 
   4947 	assert(scf_validate_encoded_value(response.rpr_type,
   4948 	    response.rpr_value));
   4949 
   4950 	if (v->value_type != REP_PROTOCOL_TYPE_OPAQUE) {
   4951 		(void) strlcpy(v->value_value, response.rpr_value,
   4952 		    sizeof (v->value_value));
   4953 	} else {
   4954 		v->value_size = scf_opaque_decode(v->value_value,
   4955 		    response.rpr_value, sizeof (v->value_value));
   4956 	}
   4957 	(void) pthread_mutex_unlock(&h->rh_lock);
   4958 
   4959 	return (1);
   4960 }
   4961 
   4962 int
   4963 scf_property_get_value(const scf_property_t *prop, scf_value_t *v)
   4964 {
   4965 	scf_handle_t *h = prop->rd_d.rd_handle;
   4966 	struct rep_protocol_property_request request;
   4967 	struct rep_protocol_value_response response;
   4968 	int r;
   4969 
   4970 	if (h != v->value_handle)
   4971 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
   4972 
   4973 	(void) pthread_mutex_lock(&h->rh_lock);
   4974 
   4975 	request.rpr_request = REP_PROTOCOL_PROPERTY_GET_VALUE;
   4976 	request.rpr_entityid = prop->rd_d.rd_entity;
   4977 
   4978 	scf_value_reset_locked(v, 0);
   4979 	datael_finish_reset(&prop->rd_d);
   4980 
   4981 	r = make_door_call(h, &request, sizeof (request),
   4982 	    &response, sizeof (response));
   4983 
   4984 	if (r < 0) {
   4985 		(void) pthread_mutex_unlock(&h->rh_lock);
   4986 		DOOR_ERRORS_BLOCK(r);
   4987 	}
   4988 
   4989 	if (response.rpr_response != REP_PROTOCOL_SUCCESS &&
   4990 	    response.rpr_response != REP_PROTOCOL_FAIL_TRUNCATED) {
   4991 		(void) pthread_mutex_unlock(&h->rh_lock);
   4992 		assert(response.rpr_response !=
   4993 		    REP_PROTOCOL_FAIL_TYPE_MISMATCH);
   4994 		return (scf_set_error(proto_error(response.rpr_response)));
   4995 	}
   4996 
   4997 	v->value_type = response.rpr_type;
   4998 	if (v->value_type != REP_PROTOCOL_TYPE_OPAQUE) {
   4999 		(void) strlcpy(v->value_value, response.rpr_value,
   5000 		    sizeof (v->value_value));
   5001 	} else {
   5002 		v->value_size = scf_opaque_decode(v->value_value,
   5003 		    response.rpr_value, sizeof (v->value_value));
   5004 	}
   5005 	(void) pthread_mutex_unlock(&h->rh_lock);
   5006 	return ((response.rpr_response == REP_PROTOCOL_SUCCESS)?
   5007 	    SCF_SUCCESS : scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED));
   5008 }
   5009 
   5010 int
   5011 scf_pg_get_parent_service(const scf_propertygroup_t *pg, scf_service_t *svc)
   5012 {
   5013 	return (datael_get_parent(&pg->rd_d, &svc->rd_d));
   5014 }
   5015 
   5016 int
   5017 scf_pg_get_parent_instance(const scf_propertygroup_t *pg, scf_instance_t *inst)
   5018 {
   5019 	return (datael_get_parent(&pg->rd_d, &inst->rd_d));
   5020 }
   5021 
   5022 int
   5023 scf_pg_get_parent_snaplevel(const scf_propertygroup_t *pg,
   5024     scf_snaplevel_t *level)
   5025 {
   5026 	return (datael_get_parent(&pg->rd_d, &level->rd_d));
   5027 }
   5028 
   5029 int
   5030 scf_service_get_parent(const scf_service_t *svc, scf_scope_t *s)
   5031 {
   5032 	return (datael_get_parent(&svc->rd_d, &s->rd_d));
   5033 }
   5034 
   5035 int
   5036 scf_instance_get_parent(const scf_instance_t *inst, scf_service_t *svc)
   5037 {
   5038 	return (datael_get_parent(&inst->rd_d, &svc->rd_d));
   5039 }
   5040 
   5041 int
   5042 scf_snapshot_get_parent(const scf_snapshot_t *inst, scf_instance_t *svc)
   5043 {
   5044 	return (datael_get_parent(&inst->rd_d, &svc->rd_d));
   5045 }
   5046 
   5047 int
   5048 scf_snaplevel_get_parent(const scf_snaplevel_t *inst, scf_snapshot_t *svc)
   5049 {
   5050 	return (datael_get_parent(&inst->rd_d, &svc->rd_d));
   5051 }
   5052 
   5053 /*
   5054  * FMRI functions
   5055  *
   5056  * Note: In the scf_parse_svc_fmri(), scf_parse_file_fmri() and
   5057  * scf_parse_fmri(), fmri isn't const because that would require
   5058  * allocating memory. Also, note that scope, at least, is not necessarily
   5059  * in the passed in fmri.
   5060  */
   5061 
   5062 int
   5063 scf_parse_svc_fmri(char *fmri, const char **scope, const char **service,
   5064     const char **instance, const char **propertygroup, const char **property)
   5065 {
   5066 	char *s, *e, *te, *tpg;
   5067 	char *my_s = NULL, *my_i = NULL, *my_pg = NULL, *my_p = NULL;
   5068 
   5069 	if (scope != NULL)
   5070 		*scope = NULL;
   5071 	if (service != NULL)
   5072 		*service = NULL;
   5073 	if (instance != NULL)
   5074 		*instance = NULL;
   5075 	if (propertygroup != NULL)
   5076 		*propertygroup = NULL;
   5077 	if (property != NULL)
   5078 		*property = NULL;
   5079 
   5080 	s = fmri;
   5081 	e = strchr(s, '\0');
   5082 
   5083 	if (strncmp(s, SCF_FMRI_SVC_PREFIX,
   5084 	    sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0)
   5085 		s += sizeof (SCF_FMRI_SVC_PREFIX) - 1;
   5086 
   5087 	if (strncmp(s, SCF_FMRI_SCOPE_PREFIX,
   5088 	    sizeof (SCF_FMRI_SCOPE_PREFIX) - 1) == 0) {
   5089 		char *my_scope;
   5090 
   5091 		s += sizeof (SCF_FMRI_SCOPE_PREFIX) - 1;
   5092 		te = strstr(s, SCF_FMRI_SERVICE_PREFIX);
   5093 		if (te == NULL)
   5094 			te = e;
   5095 
   5096 		*te = 0;
   5097 		my_scope = s;
   5098 
   5099 		s = te;
   5100 		if (s < e)
   5101 			s += sizeof (SCF_FMRI_SERVICE_PREFIX) - 1;
   5102 
   5103 		/* If the scope ends with the suffix, remove it. */
   5104 		te = strstr(my_scope, SCF_FMRI_SCOPE_SUFFIX);
   5105 		if (te != NULL && te[sizeof (SCF_FMRI_SCOPE_SUFFIX) - 1] == 0)
   5106 			*te = 0;
   5107 
   5108 		/* Validate the scope. */
   5109 		if (my_scope[0] == '\0')
   5110 			my_scope = SCF_FMRI_LOCAL_SCOPE;
   5111 		else if (uu_check_name(my_scope, 0) == -1) {
   5112 			return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
   5113 		}
   5114 
   5115 		if (scope != NULL)
   5116 			*scope = my_scope;
   5117 	} else {
   5118 		if (scope != NULL)
   5119 			*scope = SCF_FMRI_LOCAL_SCOPE;
   5120 	}
   5121 
   5122 	if (s[0] != 0) {
   5123 		if (strncmp(s, SCF_FMRI_SERVICE_PREFIX,
   5124 		    sizeof (SCF_FMRI_SERVICE_PREFIX) - 1) == 0)
   5125 			s += sizeof (SCF_FMRI_SERVICE_PREFIX) - 1;
   5126 
   5127 		/*
   5128 		 * Can't validate service here because it might not be null
   5129 		 * terminated.
   5130 		 */
   5131 		my_s = s;
   5132 	}
   5133 
   5134 	tpg = strstr(s, SCF_FMRI_PROPERTYGRP_PREFIX);
   5135 	te = strstr(s, SCF_FMRI_INSTANCE_PREFIX);
   5136 	if (te != NULL && (tpg == NULL || te < tpg)) {
   5137 		*te = 0;
   5138 		te += sizeof (SCF_FMRI_INSTANCE_PREFIX) - 1;
   5139 
   5140 		/* Can't validate instance here either. */
   5141 		my_i = s = te;
   5142 
   5143 		te = strstr(s, SCF_FMRI_PROPERTYGRP_PREFIX);
   5144 	} else {
   5145 		te = tpg;
   5146 	}
   5147 
   5148 	if (te != NULL) {
   5149 		*te = 0;
   5150 		te += sizeof (SCF_FMRI_PROPERTYGRP_PREFIX) - 1;
   5151 
   5152 		my_pg = s = te;
   5153 		te = strstr(s, SCF_FMRI_PROPERTY_PREFIX);
   5154 		if (te != NULL) {
   5155 			*te = 0;
   5156 			te += sizeof (SCF_FMRI_PROPERTY_PREFIX) - 1;
   5157 
   5158 			my_p = te;
   5159 			s = te;
   5160 		}
   5161 	}
   5162 
   5163 	if (my_s != NULL) {
   5164 		if (uu_check_name(my_s, UU_NAME_DOMAIN | UU_NAME_PATH) == -1)
   5165 			return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
   5166 
   5167 		if (service != NULL)
   5168 			*service = my_s;
   5169 	}
   5170 
   5171 	if (my_i != NULL) {
   5172 		if (uu_check_name(my_i, UU_NAME_DOMAIN) == -1)
   5173 			return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
   5174 
   5175 		if (instance != NULL)
   5176 			*instance = my_i;
   5177 	}
   5178 
   5179 	if (my_pg != NULL) {
   5180 		if (uu_check_name(my_pg, UU_NAME_DOMAIN) == -1)
   5181 			return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
   5182 
   5183 		if (propertygroup != NULL)
   5184 			*propertygroup = my_pg;
   5185 	}
   5186 
   5187 	if (my_p != NULL) {
   5188 		if (uu_check_name(my_p, UU_NAME_DOMAIN) == -1)
   5189 			return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
   5190 
   5191 		if (property != NULL)
   5192 			*property = my_p;
   5193 	}
   5194 
   5195 	return (0);
   5196 }
   5197 
   5198 int
   5199 scf_parse_file_fmri(char *fmri, const char **scope, const char **path)
   5200 {
   5201 	char *s, *e, *te;
   5202 
   5203 	if (scope != NULL)
   5204 		*scope = NULL;
   5205 
   5206 	s = fmri;
   5207 	e = strchr(s, '\0');
   5208 
   5209 	if (strncmp(s, SCF_FMRI_FILE_PREFIX,
   5210 	    sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0)
   5211 		s += sizeof (SCF_FMRI_FILE_PREFIX) - 1;
   5212 
   5213 	if (strncmp(s, SCF_FMRI_SCOPE_PREFIX,
   5214 	    sizeof (SCF_FMRI_SCOPE_PREFIX) - 1) == 0) {
   5215 		char *my_scope;
   5216 
   5217 		s += sizeof (SCF_FMRI_SCOPE_PREFIX) - 1;
   5218 		te = strstr(s, SCF_FMRI_SERVICE_PREFIX);
   5219 		if (te == NULL)
   5220 			te = e;
   5221 
   5222 		*te = 0;
   5223 		my_scope = s;
   5224 
   5225 		s = te;
   5226 
   5227 		/* Validate the scope. */
   5228 		if (my_scope[0] != '\0' &&
   5229 		    strcmp(my_scope, SCF_FMRI_LOCAL_SCOPE) != 0) {
   5230 			return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
   5231 		}
   5232 
   5233 		if (scope != NULL)
   5234 			*scope = my_scope;
   5235 	} else {
   5236 		/*
   5237 		 * FMRI paths must be absolute
   5238 		 */
   5239 		if (s[0] != '/')
   5240 			return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
   5241 	}
   5242 
   5243 	s += sizeof (SCF_FMRI_SERVICE_PREFIX) - 1;
   5244 
   5245 	if (s >= e)
   5246 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
   5247 
   5248 	/*
   5249 	 * If the user requests it, return the full path of the file.
   5250 	 */
   5251 	if (path != NULL) {
   5252 		assert(s > fmri);
   5253 		s[-1] = '/';
   5254 		*path = s - 1;
   5255 	}
   5256 
   5257 	return (0);
   5258 }
   5259 
   5260 int
   5261 scf_parse_fmri(char *fmri, int *type, const char **scope, const char **service,
   5262     const char **instance, const char **propertygroup, const char **property)
   5263 {
   5264 	if (strncmp(fmri, SCF_FMRI_SVC_PREFIX,
   5265 	    sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) {
   5266 		if (type)
   5267 			*type = SCF_FMRI_TYPE_SVC;
   5268 		return (scf_parse_svc_fmri(fmri, scope, service, instance,
   5269 		    propertygroup, property));
   5270 	} else if (strncmp(fmri, SCF_FMRI_FILE_PREFIX,
   5271 	    sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) {
   5272 		if (type)
   5273 			*type = SCF_FMRI_TYPE_FILE;
   5274 		return (scf_parse_file_fmri(fmri, scope, NULL));
   5275 	} else {
   5276 		/*
   5277 		 * Parse as a svc if the fmri type is not explicitly
   5278 		 * specified.
   5279 		 */
   5280 		if (type)
   5281 			*type = SCF_FMRI_TYPE_SVC;
   5282 		return (scf_parse_svc_fmri(fmri, scope, service, instance,
   5283 		    propertygroup, property));
   5284 	}
   5285 }
   5286 
   5287 /*
   5288  * Fails with _INVALID_ARGUMENT.  fmri and buf may be equal.
   5289  */
   5290 ssize_t
   5291 scf_canonify_fmri(const char *fmri, char *buf, size_t bufsz)
   5292 {
   5293 	const char *scope, *service, *instance, *pg, *property;
   5294 	char local[6 * REP_PROTOCOL_NAME_LEN];
   5295 	int r;
   5296 	size_t len;
   5297 
   5298 	if (strlcpy(local, fmri, sizeof (local)) >= sizeof (local)) {
   5299 		/* Should this be CONSTRAINT_VIOLATED? */
   5300 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
   5301 		return (-1);
   5302 	}
   5303 
   5304 
   5305 	r = scf_parse_svc_fmri(local, &scope, &service, &instance, &pg,
   5306 	    &property);
   5307 	if (r != 0)
   5308 		return (-1);
   5309 
   5310 	len = strlcpy(buf, "svc:/", bufsz);
   5311 
   5312 	if (scope != NULL && strcmp(scope, SCF_SCOPE_LOCAL) != 0) {
   5313 		len += strlcat(buf, "/", bufsz);
   5314 		len += strlcat(buf, scope, bufsz);
   5315 	}
   5316 
   5317 	if (service)
   5318 		len += strlcat(buf, service, bufsz);
   5319 
   5320 	if (instance) {
   5321 		len += strlcat(buf, ":", bufsz);
   5322 		len += strlcat(buf, instance, bufsz);
   5323 	}
   5324 
   5325 	if (pg) {
   5326 		len += strlcat(buf, "/:properties/", bufsz);
   5327 		len += strlcat(buf, pg, bufsz);
   5328 	}
   5329 
   5330 	if (property) {
   5331 		len += strlcat(buf, "/", bufsz);
   5332 		len += strlcat(buf, property, bufsz);
   5333 	}
   5334 
   5335 	return (len);
   5336 }
   5337 
   5338 /*
   5339  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _CONSTRAINT_VIOLATED,
   5340  * _NOT_FOUND, _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED,
   5341  * _NO_RESOURCES, _BACKEND_ACCESS.
   5342  */
   5343 int
   5344 scf_handle_decode_fmri(scf_handle_t *h, const char *fmri, scf_scope_t *sc,
   5345     scf_service_t *svc, scf_instance_t *inst, scf_propertygroup_t *pg,
   5346     scf_property_t *prop, int flags)
   5347 {
   5348 	const char *scope, *service, *instance, *propertygroup, *property;
   5349 	int last;
   5350 	char local[6 * REP_PROTOCOL_NAME_LEN];
   5351 	int ret;
   5352 	const uint32_t holds = RH_HOLD_SCOPE | RH_HOLD_SERVICE |
   5353 	    RH_HOLD_INSTANCE | RH_HOLD_PG | RH_HOLD_PROPERTY;
   5354 
   5355 	/*
   5356 	 * verify that all handles match
   5357 	 */
   5358 	if ((sc != NULL && h != sc->rd_d.rd_handle) ||
   5359 	    (svc != NULL && h != svc->rd_d.rd_handle) ||
   5360 	    (inst != NULL && h != inst->rd_d.rd_handle) ||
   5361 	    (pg != NULL && h != pg->rd_d.rd_handle) ||
   5362 	    (prop != NULL && h != prop->rd_d.rd_handle))
   5363 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
   5364 
   5365 	if (strlcpy(local, fmri, sizeof (local)) >= sizeof (local)) {
   5366 		ret = scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
   5367 		goto reset_args;
   5368 	}
   5369 
   5370 	/*
   5371 	 * We can simply return from an error in parsing, because
   5372 	 * scf_parse_fmri sets the error code correctly.
   5373 	 */
   5374 	if (scf_parse_svc_fmri(local, &scope, &service, &instance,
   5375 	    &propertygroup, &property) == -1) {
   5376 		ret = -1;
   5377 		goto reset_args;
   5378 	}
   5379 
   5380 	/*
   5381 	 * the FMRI looks valid at this point -- do constraint checks.
   5382 	 */
   5383 
   5384 	if (instance != NULL && (flags & SCF_DECODE_FMRI_REQUIRE_NO_INSTANCE)) {
   5385 		ret = scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED);
   5386 		goto reset_args;
   5387 	}
   5388 	if (instance == NULL && (flags & SCF_DECODE_FMRI_REQUIRE_INSTANCE)) {
   5389 		ret = scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED);
   5390 		goto reset_args;
   5391 	}
   5392 
   5393 	if (prop != NULL)
   5394 		last = REP_PROTOCOL_ENTITY_PROPERTY;
   5395 	else if (pg != NULL)
   5396 		last = REP_PROTOCOL_ENTITY_PROPERTYGRP;
   5397 	else if (inst != NULL)
   5398 		last = REP_PROTOCOL_ENTITY_INSTANCE;
   5399 	else if (svc != NULL)
   5400 		last = REP_PROTOCOL_ENTITY_SERVICE;
   5401 	else if (sc != NULL)
   5402 		last = REP_PROTOCOL_ENTITY_SCOPE;
   5403 	else
   5404 		last = REP_PROTOCOL_ENTITY_NONE;
   5405 
   5406 	if (flags & SCF_DECODE_FMRI_EXACT) {
   5407 		int last_fmri;
   5408 
   5409 		if (property != NULL)
   5410 			last_fmri = REP_PROTOCOL_ENTITY_PROPERTY;
   5411 		else if (propertygroup != NULL)
   5412 			last_fmri = REP_PROTOCOL_ENTITY_PROPERTYGRP;
   5413 		else if (instance != NULL)
   5414 			last_fmri = REP_PROTOCOL_ENTITY_INSTANCE;
   5415 		else if (service != NULL)
   5416 			last_fmri = REP_PROTOCOL_ENTITY_SERVICE;
   5417 		else if (scope != NULL)
   5418 			last_fmri = REP_PROTOCOL_ENTITY_SCOPE;
   5419 		else
   5420 			last_fmri = REP_PROTOCOL_ENTITY_NONE;
   5421 
   5422 		if (last != last_fmri) {
   5423 			ret = scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED);
   5424 			goto reset_args;
   5425 		}
   5426 	}
   5427 
   5428 	if ((flags & SCF_DECODE_FMRI_TRUNCATE) &&
   5429 	    last == REP_PROTOCOL_ENTITY_NONE) {
   5430 		ret = 0;				/* nothing to do */
   5431 		goto reset_args;
   5432 	}
   5433 
   5434 	if (!(flags & SCF_DECODE_FMRI_TRUNCATE))
   5435 		last = REP_PROTOCOL_ENTITY_NONE;	/* never stop */
   5436 
   5437 	/*
   5438 	 * passed the constraint checks -- try to grab the thing itself.
   5439 	 */
   5440 
   5441 	handle_hold_subhandles(h, holds);
   5442 	if (sc == NULL)
   5443 		sc = h->rh_scope;
   5444 	else
   5445 		datael_reset(&sc->rd_d);
   5446 
   5447 	if (svc == NULL)
   5448 		svc = h->rh_service;
   5449 	else
   5450 		datael_reset(&svc->rd_d);
   5451 
   5452 	if (inst == NULL)
   5453 		inst = h->rh_instance;
   5454 	else
   5455 		datael_reset(&inst->rd_d);
   5456 
   5457 	if (pg == NULL)
   5458 		pg = h->rh_pg;
   5459 	else
   5460 		datael_reset(&pg->rd_d);
   5461 
   5462 	if (prop == NULL)
   5463 		prop = h->rh_property;
   5464 	else
   5465 		datael_reset(&prop->rd_d);
   5466 
   5467 	/*
   5468 	 * We only support local scopes, but we check *after* getting
   5469 	 * the local scope, so that any repository-related errors take
   5470 	 * precedence.
   5471 	 */
   5472 	if (scf_handle_get_scope(h, SCF_SCOPE_LOCAL, sc) == -1) {
   5473 		handle_rele_subhandles(h, holds);
   5474 		ret = -1;
   5475 		goto reset_args;
   5476 	}
   5477 
   5478 	if (scope != NULL && strcmp(scope, SCF_FMRI_LOCAL_SCOPE) != 0) {
   5479 		handle_rele_subhandles(h, holds);
   5480 		ret = scf_set_error(SCF_ERROR_NOT_FOUND);
   5481 		goto reset_args;
   5482 	}
   5483 
   5484 
   5485 	if (service == NULL || last == REP_PROTOCOL_ENTITY_SCOPE) {
   5486 		handle_rele_subhandles(h, holds);
   5487 		return (0);
   5488 	}
   5489 
   5490 	if (scf_scope_get_service(sc, service, svc) == -1) {
   5491 		handle_rele_subhandles(h, holds);
   5492 		ret = -1;
   5493 		assert(scf_error() != SCF_ERROR_NOT_SET);
   5494 		if (scf_error() == SCF_ERROR_DELETED)
   5495 			(void) scf_set_error(SCF_ERROR_NOT_FOUND);
   5496 		goto reset_args;
   5497 	}
   5498 
   5499 	if (last == REP_PROTOCOL_ENTITY_SERVICE) {
   5500 		handle_rele_subhandles(h, holds);
   5501 		return (0);
   5502 	}
   5503 
   5504 	if (instance == NULL) {
   5505 		if (propertygroup == NULL ||
   5506 		    last == REP_PROTOCOL_ENTITY_INSTANCE) {
   5507 			handle_rele_subhandles(h, holds);
   5508 			return (0);
   5509 		}
   5510 
   5511 		if (scf_service_get_pg(svc, propertygroup, pg) == -1) {
   5512 			handle_rele_subhandles(h, holds);
   5513 			ret = -1;
   5514 			assert(scf_error() != SCF_ERROR_NOT_SET);
   5515 			if (scf_error() == SCF_ERROR_DELETED)
   5516 				(void) scf_set_error(SCF_ERROR_NOT_FOUND);
   5517 			goto reset_args;
   5518 		}
   5519 	} else {
   5520 		if (scf_service_get_instance(svc, instance, inst) == -1) {
   5521 			handle_rele_subhandles(h, holds);
   5522 			ret = -1;
   5523 			assert(scf_error() != SCF_ERROR_NOT_SET);
   5524 			if (scf_error() == SCF_ERROR_DELETED)
   5525 				(void) scf_set_error(SCF_ERROR_NOT_FOUND);
   5526 			goto reset_args;
   5527 		}
   5528 
   5529 		if (propertygroup == NULL ||
   5530 		    last == REP_PROTOCOL_ENTITY_INSTANCE) {
   5531 			handle_rele_subhandles(h, holds);
   5532 			return (0);
   5533 		}
   5534 
   5535 		if (scf_instance_get_pg(inst, propertygroup, pg) == -1) {
   5536 			handle_rele_subhandles(h, holds);
   5537 			ret = -1;
   5538 			assert(scf_error() != SCF_ERROR_NOT_SET);
   5539 			if (scf_error() == SCF_ERROR_DELETED)
   5540 				(void) scf_set_error(SCF_ERROR_NOT_FOUND);
   5541 			goto reset_args;
   5542 		}
   5543 	}
   5544 
   5545 	if (property == NULL || last == REP_PROTOCOL_ENTITY_PROPERTYGRP) {
   5546 		handle_rele_subhandles(h, holds);
   5547 		return (0);
   5548 	}
   5549 
   5550 	if (scf_pg_get_property(pg, property, prop) == -1) {
   5551 		handle_rele_subhandles(h, holds);
   5552 		ret = -1;
   5553 		assert(scf_error() != SCF_ERROR_NOT_SET);
   5554 		if (scf_error() == SCF_ERROR_DELETED)
   5555 			(void) scf_set_error(SCF_ERROR_NOT_FOUND);
   5556 		goto reset_args;
   5557 	}
   5558 
   5559 	handle_rele_subhandles(h, holds);
   5560 	return (0);
   5561 
   5562 reset_args:
   5563 	if (sc != NULL)
   5564 		datael_reset(&sc->rd_d);
   5565 	if (svc != NULL)
   5566 		datael_reset(&svc->rd_d);
   5567 	if (inst != NULL)
   5568 		datael_reset(&inst->rd_d);
   5569 	if (pg != NULL)
   5570 		datael_reset(&pg->rd_d);
   5571 	if (prop != NULL)
   5572 		datael_reset(&prop->rd_d);
   5573 
   5574 	return (ret);
   5575 }
   5576 
   5577 /*
   5578  * Fails with _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response too
   5579  * big, bad entity id, request not applicable to entity, name too long for
   5580  * buffer), _NOT_SET, or _DELETED.
   5581  */
   5582 ssize_t
   5583 scf_scope_to_fmri(const scf_scope_t *scope, char *out, size_t sz)
   5584 {
   5585 	ssize_t r, len;
   5586 
   5587 	char tmp[REP_PROTOCOL_NAME_LEN];
   5588 
   5589 	r = scf_scope_get_name(scope, tmp, sizeof (tmp));
   5590 
   5591 	if (r <= 0)
   5592 		return (r);
   5593 
   5594 	len = strlcpy(out, SCF_FMRI_SVC_PREFIX, sz);
   5595 	if (strcmp(tmp, SCF_FMRI_LOCAL_SCOPE) != 0) {
   5596 		if (len >= sz)
   5597 			return (len + r + sizeof (SCF_FMRI_SCOPE_SUFFIX) - 1);
   5598 
   5599 		len = strlcat(out, tmp, sz);
   5600 		if (len >= sz)
   5601 			return (len + sizeof (SCF_FMRI_SCOPE_SUFFIX) - 1);
   5602 		len = strlcat(out,
   5603 		    SCF_FMRI_SCOPE_SUFFIX SCF_FMRI_SERVICE_PREFIX, sz);
   5604 	}
   5605 
   5606 	return (len);
   5607 }
   5608 
   5609 /*
   5610  * Fails with _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response too
   5611  * big, bad element id, bad ids, bad types, scope has no parent, request not
   5612  * applicable to entity, name too long), _NOT_SET, _DELETED,
   5613  */
   5614 ssize_t
   5615 scf_service_to_fmri(const scf_service_t *svc, char *out, size_t sz)
   5616 {
   5617 	scf_handle_t *h = svc->rd_d.rd_handle;
   5618 	scf_scope_t *scope = HANDLE_HOLD_SCOPE(h);
   5619 	ssize_t r, len;
   5620 
   5621 	char tmp[REP_PROTOCOL_NAME_LEN];
   5622 
   5623 	r = datael_get_parent(&svc->rd_d, &scope->rd_d);
   5624 	if (r != SCF_SUCCESS) {
   5625 		HANDLE_RELE_SCOPE(h);
   5626 
   5627 		assert(scf_error() != SCF_ERROR_HANDLE_MISMATCH);
   5628 		return (-1);
   5629 	}
   5630 	if (out != NULL && sz > 0)
   5631 		len = scf_scope_to_fmri(scope, out, sz);
   5632 	else
   5633 		len = scf_scope_to_fmri(scope, tmp, 2);
   5634 
   5635 	HANDLE_RELE_SCOPE(h);
   5636 
   5637 	if (len < 0)
   5638 		return (-1);
   5639 
   5640 	if (out == NULL || len >= sz)
   5641 		len += sizeof (SCF_FMRI_SERVICE_PREFIX) - 1;
   5642 	else
   5643 		len = strlcat(out, SCF_FMRI_SERVICE_PREFIX, sz);
   5644 
   5645 	r = scf_service_get_name(svc, tmp, sizeof (tmp));
   5646 	if (r < 0)
   5647 		return (r);
   5648 
   5649 	if (out == NULL || len >= sz)
   5650 		len += r;
   5651 	else
   5652 		len = strlcat(out, tmp, sz);
   5653 
   5654 	return (len);
   5655 }
   5656 
   5657 ssize_t
   5658 scf_instance_to_fmri(const scf_instance_t *inst, char *out, size_t sz)
   5659 {
   5660 	scf_handle_t *h = inst->rd_d.rd_handle;
   5661 	scf_service_t *svc = HANDLE_HOLD_SERVICE(h);
   5662 	ssize_t r, len;
   5663 
   5664 	char tmp[REP_PROTOCOL_NAME_LEN];
   5665 
   5666 	r = datael_get_parent(&inst->rd_d, &svc->rd_d);
   5667 	if (r != SCF_SUCCESS) {
   5668 		HANDLE_RELE_SERVICE(h);
   5669 		return (-1);
   5670 	}
   5671 
   5672 	len = scf_service_to_fmri(svc, out, sz);
   5673 
   5674 	HANDLE_RELE_SERVICE(h);
   5675 
   5676 	if (len < 0)
   5677 		return (len);
   5678 
   5679 	if (len >= sz)
   5680 		len += sizeof (SCF_FMRI_INSTANCE_PREFIX) - 1;
   5681 	else
   5682 		len = strlcat(out, SCF_FMRI_INSTANCE_PREFIX, sz);
   5683 
   5684 	r = scf_instance_get_name(inst, tmp, sizeof (tmp));
   5685 	if (r < 0)
   5686 		return (r);
   5687 
   5688 	if (len >= sz)
   5689 		len += r;
   5690 	else
   5691 		len = strlcat(out, tmp, sz);
   5692 
   5693 	return (len);
   5694 }
   5695 
   5696 ssize_t
   5697 scf_pg_to_fmri(const scf_propertygroup_t *pg, char *out, size_t sz)
   5698 {
   5699 	scf_handle_t *h = pg->rd_d.rd_handle;
   5700 
   5701 	struct rep_protocol_entity_parent_type request;
   5702 	struct rep_protocol_integer_response response;
   5703 
   5704 	char tmp[REP_PROTOCOL_NAME_LEN];
   5705 	ssize_t len, r;
   5706 
   5707 	(void) pthread_mutex_lock(&h->rh_lock);
   5708 	request.rpr_request = REP_PROTOCOL_ENTITY_PARENT_TYPE;
   5709 	request.rpr_entityid = pg->rd_d.rd_entity;
   5710 
   5711 	datael_finish_reset(&pg->rd_d);
   5712 	r = make_door_call(h, &request, sizeof (request),
   5713 	    &response, sizeof (response));
   5714 	(void) pthread_mutex_unlock(&h->rh_lock);
   5715 
   5716 	if (r < 0)
   5717 		DOOR_ERRORS_BLOCK(r);
   5718 
   5719 	if (response.rpr_response != REP_PROTOCOL_SUCCESS ||
   5720 	    r < sizeof (response)) {
   5721 		return (scf_set_error(proto_error(response.rpr_response)));
   5722 	}
   5723 
   5724 	switch (response.rpr_value) {
   5725 	case REP_PROTOCOL_ENTITY_SERVICE: {
   5726 		scf_service_t *svc;
   5727 
   5728 		svc = HANDLE_HOLD_SERVICE(h);
   5729 
   5730 		r = datael_get_parent(&pg->rd_d, &svc->rd_d);
   5731 
   5732 		if (r == SCF_SUCCESS)
   5733 			len = scf_service_to_fmri(svc, out, sz);
   5734 
   5735 		HANDLE_RELE_SERVICE(h);
   5736 		break;
   5737 	}
   5738 
   5739 	case REP_PROTOCOL_ENTITY_INSTANCE: {
   5740 		scf_instance_t *inst;
   5741 
   5742 		inst = HANDLE_HOLD_INSTANCE(h);
   5743 
   5744 		r = datael_get_parent(&pg->rd_d, &inst->rd_d);
   5745 
   5746 		if (r == SCF_SUCCESS)
   5747 			len = scf_instance_to_fmri(inst, out, sz);
   5748 
   5749 		HANDLE_RELE_INSTANCE(h);
   5750 		break;
   5751 	}
   5752 
   5753 	case REP_PROTOCOL_ENTITY_SNAPLEVEL: {
   5754 		scf_instance_t *inst = HANDLE_HOLD_INSTANCE(h);
   5755 		scf_snapshot_t *snap = HANDLE_HOLD_SNAPSHOT(h);
   5756 		scf_snaplevel_t *level = HANDLE_HOLD_SNAPLVL(h);
   5757 
   5758 		r = datael_get_parent(&pg->rd_d, &level->rd_d);
   5759 
   5760 		if (r == SCF_SUCCESS)
   5761 			r = datael_get_parent(&level->rd_d, &snap->rd_d);
   5762 
   5763 		if (r == SCF_SUCCESS)
   5764 			r = datael_get_parent(&snap->rd_d, &inst->rd_d);
   5765 
   5766 		if (r == SCF_SUCCESS)
   5767 			len = scf_instance_to_fmri(inst, out, sz);
   5768 
   5769 		HANDLE_RELE_INSTANCE(h);
   5770 		HANDLE_RELE_SNAPSHOT(h);
   5771 		HANDLE_RELE_SNAPLVL(h);
   5772 		break;
   5773 	}
   5774 
   5775 	default:
   5776 		return (scf_set_error(SCF_ERROR_INTERNAL));
   5777 	}
   5778 
   5779 	if (r != SCF_SUCCESS)
   5780 		return (r);
   5781 
   5782 	if (len >= sz)
   5783 		len += sizeof (SCF_FMRI_PROPERTYGRP_PREFIX) - 1;
   5784 	else
   5785 		len = strlcat(out, SCF_FMRI_PROPERTYGRP_PREFIX, sz);
   5786 
   5787 	r = scf_pg_get_name(pg, tmp, sizeof (tmp));
   5788 
   5789 	if (r < 0)
   5790 		return (r);
   5791 
   5792 	if (len >= sz)
   5793 		len += r;
   5794 	else
   5795 		len = strlcat(out, tmp, sz);
   5796 
   5797 	return (len);
   5798 }
   5799 
   5800 ssize_t
   5801 scf_property_to_fmri(const scf_property_t *prop, char *out, size_t sz)
   5802 {
   5803 	scf_handle_t *h = prop->rd_d.rd_handle;
   5804 	scf_propertygroup_t *pg = HANDLE_HOLD_PG(h);
   5805 
   5806 	char tmp[REP_PROTOCOL_NAME_LEN];
   5807 	ssize_t len;
   5808 	int r;
   5809 
   5810 	r = datael_get_parent(&prop->rd_d, &pg->rd_d);
   5811 	if (r != SCF_SUCCESS) {
   5812 		HANDLE_RELE_PG(h);
   5813 		return (-1);
   5814 	}
   5815 
   5816 	len = scf_pg_to_fmri(pg, out, sz);
   5817 
   5818 	HANDLE_RELE_PG(h);
   5819 
   5820 	if (len >= sz)
   5821 		len += sizeof (SCF_FMRI_PROPERTY_PREFIX) - 1;
   5822 	else
   5823 		len = strlcat(out, SCF_FMRI_PROPERTY_PREFIX, sz);
   5824 
   5825 	r = scf_property_get_name(prop, tmp, sizeof (tmp));
   5826 
   5827 	if (r < 0)
   5828 		return (r);
   5829 
   5830 	if (len >= sz)
   5831 		len += r;
   5832 	else
   5833 		len = strlcat(out, tmp, sz);
   5834 
   5835 	return (len);
   5836 }
   5837 
   5838 /*
   5839  * Fails with _HANDLE_MISMATCH, _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL
   5840  * (server response too big, bad entity id, request not applicable to entity,
   5841  * name too long for buffer, bad element id, iter already exists, element
   5842  * cannot have children of type, type is invalid, iter was reset, sequence
   5843  * was bad, iter walks values, iter does not walk type entities),
   5844  * _NOT_SET, _DELETED, or _CONSTRAINT_VIOLATED,
   5845  * _NOT_FOUND (scope has no parent),  _INVALID_ARGUMENT, _NO_RESOURCES,
   5846  * _BACKEND_ACCESS.
   5847  */
   5848 int
   5849 scf_pg_get_underlying_pg(const scf_propertygroup_t *pg,
   5850     scf_propertygroup_t *out)
   5851 {
   5852 	scf_handle_t *h = pg->rd_d.rd_handle;
   5853 	scf_service_t *svc;
   5854 	scf_instance_t *inst;
   5855 
   5856 	char me[REP_PROTOCOL_NAME_LEN];
   5857 	int r;
   5858 
   5859 	if (h != out->rd_d.rd_handle)
   5860 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
   5861 
   5862 	r = scf_pg_get_name(pg, me, sizeof (me));
   5863 
   5864 	if (r < 0)
   5865 		return (r);
   5866 
   5867 	svc = HANDLE_HOLD_SERVICE(h);
   5868 	inst = HANDLE_HOLD_INSTANCE(h);
   5869 
   5870 	r = datael_get_parent(&pg->rd_d, &inst->rd_d);
   5871 
   5872 	if (r == SCF_SUCCESS) {
   5873 		r = datael_get_parent(&inst->rd_d, &svc->rd_d);
   5874 		if (r != SCF_SUCCESS) {
   5875 			goto out;
   5876 		}
   5877 		r = scf_service_get_pg(svc, me, out);
   5878 	} else {
   5879 		r = scf_set_error(SCF_ERROR_NOT_FOUND);
   5880 	}
   5881 
   5882 out:
   5883 	HANDLE_RELE_SERVICE(h);
   5884 	HANDLE_RELE_INSTANCE(h);
   5885 	return (r);
   5886 }
   5887 
   5888 #define	LEGACY_SCHEME	"lrc:"
   5889 #define	LEGACY_UNKNOWN	"unknown"
   5890 
   5891 /*
   5892  * Implementation of scf_walk_fmri()
   5893  *
   5894  * This is a little tricky due to the many-to-many relationship between patterns
   5895  * and matches.  We need to be able to satisfy the following requirements:
   5896  *
   5897  * 	1) Detect patterns which match more than one FMRI, and be able to
   5898  *         report which FMRIs have been matched.
   5899  * 	2) Detect patterns which have not matched any FMRIs
   5900  * 	3) Visit each matching FMRI exactly once across all patterns
   5901  * 	4) Ignore FMRIs which have only been matched due to multiply-matching
   5902  *         patterns.
   5903  *
   5904  * We maintain an array of scf_pattern_t structures, one for each argument, and
   5905  * maintain a linked list of scf_match_t structures for each one.  We first
   5906  * qualify each pattern's type:
   5907  *
   5908  *	PATTERN_INVALID		The argument is invalid (too long).
   5909  *
   5910  *	PATTERN_EXACT		The pattern is a complete FMRI.  The list of
   5911  *				matches contains only a single entry.
   5912  *
   5913  * 	PATTERN_GLOB		The pattern will be matched against all
   5914  * 				FMRIs via fnmatch() in the second phase.
   5915  * 				Matches will be added to the pattern's list
   5916  * 				as they are found.
   5917  *
   5918  * 	PATTERN_PARTIAL		Everything else.  We will assume that this is
   5919  * 				an abbreviated FMRI, and match according to
   5920  * 				our abbreviated FMRI rules.  Matches will be
   5921  * 				added to the pattern's list as they are found.
   5922  *
   5923  * The first pass searches for arguments that are complete FMRIs.  These are
   5924  * classified as EXACT patterns and do not necessitate searching the entire
   5925  * tree.
   5926  *
   5927  * Once this is done, if we have any GLOB or PARTIAL patterns (or if no
   5928  * arguments were given), we iterate over all services and instances in the
   5929  * repository, looking for matches.
   5930  *
   5931  * When a match is found, we add the match to the pattern's list.  We also enter
   5932  * the match into a hash table, resulting in something like this:
   5933  *
   5934  *       scf_pattern_t       scf_match_t
   5935  *     +---------------+      +-------+     +-------+
   5936  *     | pattern 'foo' |----->| match |---->| match |
   5937  *     +---------------+      +-------+     +-------+
   5938  *                                |             |
   5939  *           scf_match_key_t      |             |
   5940  *           +--------------+     |             |
   5941  *           | FMRI bar/foo |<----+             |
   5942  *           +--------------+                   |
   5943  *           | FMRI baz/foo |<------------------+
   5944  *           +--------------+
   5945  *
   5946  * Once we have all of this set up, we do one pass to report patterns matching
   5947  * multiple FMRIs (if SCF_WALK_MULTIPLE is not set) and patterns for which no
   5948  * match was found.
   5949  *
   5950  * Finally, we walk through all valid patterns, and for each match, if we
   5951  * haven't already seen the match (as recorded in the hash table), then we
   5952  * execute the callback.
   5953  */
   5954 
   5955 struct scf_matchkey;
   5956 struct scf_match;
   5957 
   5958 /*
   5959  * scf_matchkey_t
   5960  */
   5961 typedef struct scf_matchkey {
   5962 	char			*sk_fmri;	/* Matching FMRI */
   5963 	char			*sk_legacy;	/* Legacy name */
   5964 	int			sk_seen;	/* If we've been seen */
   5965 	struct scf_matchkey	*sk_next;	/* Next in hash chain */
   5966 } scf_matchkey_t;
   5967 
   5968 /*
   5969  * scf_match_t
   5970  */
   5971 typedef struct scf_match {
   5972 	scf_matchkey_t		*sm_key;
   5973 	struct scf_match	*sm_next;
   5974 } scf_match_t;
   5975 
   5976 #define	WALK_HTABLE_SIZE	123
   5977 
   5978 /*
   5979  * scf_get_key()
   5980  *
   5981  * Given an FMRI and a hash table, returns the scf_matchkey_t corresponding to
   5982  * this FMRI.  If the FMRI does not exist, it is added to the hash table.  If a
   5983  * new entry cannot be allocated due to lack of memory, NULL is returned.
   5984  */
   5985 static scf_matchkey_t *
   5986 scf_get_key(scf_matchkey_t **htable, const char *fmri, const char *legacy)
   5987 {
   5988 	uint_t h = 0, g;
   5989 	const char *p, *k;
   5990 	scf_matchkey_t *key;
   5991 
   5992 	k = strstr(fmri, ":/");
   5993 	assert(k != NULL);
   5994 	k += 2;
   5995 
   5996 	/*
   5997 	 * Generic hash function from uts/common/os/modhash.c.
   5998 	 */
   5999 	for (p = k; *p != '\0'; ++p) {
   6000 		h = (h << 4) + *p;
   6001 		if ((g = (h & 0xf0000000)) != 0) {
   6002 			h ^= (g >> 24);
   6003 			h ^= g;
   6004 		}
   6005 	}
   6006 
   6007 	h %= WALK_HTABLE_SIZE;
   6008 
   6009 	/*
   6010 	 * Search for an existing key
   6011 	 */
   6012 	for (key = htable[h]; key != NULL; key = key->sk_next) {
   6013 		if (strcmp(key->sk_fmri, fmri) == 0)
   6014 			return (key);
   6015 	}
   6016 
   6017 	if ((key = calloc(sizeof (scf_matchkey_t), 1)) == NULL)
   6018 		return (NULL);
   6019 
   6020 	/*
   6021 	 * Add new key to hash table.
   6022 	 */
   6023 	if ((key->sk_fmri = strdup(fmri)) == NULL) {
   6024 		free(key);
   6025 		return (NULL);
   6026 	}
   6027 
   6028 	if (legacy == NULL) {
   6029 		key->sk_legacy = NULL;
   6030 	} else if ((key->sk_legacy = strdup(legacy)) == NULL) {
   6031 		free(key->sk_fmri);
   6032 		free(key);
   6033 		return (NULL);
   6034 	}
   6035 
   6036 	key->sk_next = htable[h];
   6037 	htable[h] = key;
   6038 
   6039 	return (key);
   6040 }
   6041 
   6042 /*
   6043  * Given an FMRI, insert it into the pattern's list appropriately.
   6044  * svc_explicit indicates whether matching services should take
   6045  * precedence over matching instances.
   6046  */
   6047 static scf_error_t
   6048 scf_add_match(scf_matchkey_t **htable, const char *fmri, const char *legacy,
   6049     scf_pattern_t *pattern, int svc_explicit)
   6050 {
   6051 	scf_match_t *match;
   6052 
   6053 	/*
   6054 	 * If svc_explicit is set, enforce the constaint that matching
   6055 	 * instances take precedence over matching services. Otherwise,
   6056 	 * matching services take precedence over matching instances.
   6057 	 */
   6058 	if (svc_explicit) {
   6059 		scf_match_t *next, *prev;
   6060 		/*
   6061 		 * If we match an instance, check to see if we must remove
   6062 		 * any matching services (for SCF_WALK_EXPLICIT).
   6063 		 */
   6064 		for (prev = match = pattern->sp_matches; match != NULL;
   6065 		    match = next) {
   6066 			size_t len = strlen(match->sm_key->sk_fmri);
   6067 			next = match->sm_next;
   6068 			if (strncmp(match->sm_key->sk_fmri, fmri, len) == 0 &&
   6069 			    fmri[len] == ':') {
   6070 				if (prev == match)
   6071 					pattern->sp_matches = match->sm_next;
   6072 				else
   6073 					prev->sm_next = match->sm_next;
   6074 				pattern->sp_matchcount--;
   6075 				free(match);
   6076 			} else
   6077 				prev = match;
   6078 		}
   6079 	} else {
   6080 		/*
   6081 		 * If we've matched a service don't add any instances (for
   6082 		 * SCF_WALK_SERVICE).
   6083 		 */
   6084 		for (match = pattern->sp_matches; match != NULL;
   6085 		    match = match->sm_next) {
   6086 			size_t len = strlen(match->sm_key->sk_fmri);
   6087 			if (strncmp(match->sm_key->sk_fmri, fmri, len) == 0 &&
   6088 			    fmri[len] == ':')
   6089 				return (0);
   6090 		}
   6091 	}
   6092 
   6093 	if ((match = malloc(sizeof (scf_match_t))) == NULL)
   6094 		return (SCF_ERROR_NO_MEMORY);
   6095 
   6096 	if ((match->sm_key = scf_get_key(htable, fmri, legacy)) == NULL) {
   6097 		free(match);
   6098 		return (SCF_ERROR_NO_MEMORY);
   6099 	}
   6100 
   6101 	match->sm_next = pattern->sp_matches;
   6102 	pattern->sp_matches = match;
   6103 	pattern->sp_matchcount++;
   6104 
   6105 	return (0);
   6106 }
   6107 
   6108 /*
   6109  * Returns 1 if the fmri matches the given pattern, 0 otherwise.
   6110  */
   6111 int
   6112 scf_cmp_pattern(char *fmri, scf_pattern_t *pattern)
   6113 {
   6114 	char *tmp;
   6115 
   6116 	if (pattern->sp_type == PATTERN_GLOB) {
   6117 		if (fnmatch(pattern->sp_arg, fmri, 0) == 0)
   6118 			return (1);
   6119 	} else if (pattern->sp_type == PATTERN_PARTIAL &&
   6120 	    (tmp = strstr(fmri, pattern->sp_arg)) != NULL) {
   6121 		/*
   6122 		 * We only allow partial matches anchored on the end of
   6123 		 * a service or instance, and beginning on an element
   6124 		 * boundary.
   6125 		 */
   6126 		if (tmp != fmri && tmp[-1] != '/' && tmp[-1] != ':' &&
   6127 		    tmp[0] != ':')
   6128 			return (0);
   6129 		tmp += strlen(pattern->sp_arg);
   6130 		if (tmp != fmri + strlen(fmri) && tmp[0] != ':' &&
   6131 		    tmp[-1] != ':')
   6132 			return (0);
   6133 
   6134 		/*
   6135 		 * If the user has supplied a short pattern that matches
   6136 		 * 'svc:/' or 'lrc:/', ignore it.
   6137 		 */
   6138 		if (tmp <= fmri + 4)
   6139 			return (0);
   6140 
   6141 		return (1);
   6142 	}
   6143 
   6144 	return (0);
   6145 }
   6146 
   6147 /*
   6148  * Attempts to match the given FMRI against a set of patterns, keeping track of
   6149  * the results.
   6150  */
   6151 static scf_error_t
   6152 scf_pattern_match(scf_matchkey_t **htable, char *fmri, const char *legacy,
   6153     int npattern, scf_pattern_t *pattern, int svc_explicit)
   6154 {
   6155 	int i;
   6156 	int ret = 0;
   6157 
   6158 	for (i = 0; i < npattern; i++) {
   6159 		if (scf_cmp_pattern(fmri, &pattern[i]) &&
   6160 		    (ret = scf_add_match(htable, fmri,
   6161 		    legacy, &pattern[i], svc_explicit)) != 0)
   6162 			return (ret);
   6163 	}
   6164 
   6165 	return (0);
   6166 }
   6167 
   6168 /*
   6169  * Fails with _INVALID_ARGUMENT, _HANDLE_DESTROYED, _INTERNAL (bad server
   6170  * response or id in use), _NO_MEMORY, _HANDLE_MISMATCH, _CONSTRAINT_VIOLATED,
   6171  * _NOT_FOUND, _NOT_BOUND, _CONNECTION_BROKEN, _NOT_SET, _DELETED,
   6172  * _NO_RESOURCES, _BACKEND_ACCESS, _TYPE_MISMATCH.
   6173  */
   6174 scf_error_t
   6175 scf_walk_fmri(scf_handle_t *h, int argc, char **argv, int flags,
   6176     scf_walk_callback callback, void *data, int *err,
   6177     void (*errfunc)(const char *, ...))
   6178 {
   6179 	scf_pattern_t *pattern = NULL;
   6180 	int i;
   6181 	char *fmri = NULL;
   6182 	ssize_t max_fmri_length;
   6183 	scf_service_t *svc = NULL;
   6184 	scf_instance_t *inst = NULL;
   6185 	scf_iter_t *iter = NULL, *sciter = NULL, *siter = NULL;
   6186 	scf_scope_t *scope = NULL;
   6187 	scf_propertygroup_t *pg = NULL;
   6188 	scf_property_t *prop = NULL;
   6189 	scf_value_t *value = NULL;
   6190 	int ret = 0;
   6191 	scf_matchkey_t **htable = NULL;
   6192 	int pattern_search = 0;
   6193 	ssize_t max_name_length;
   6194 	char *pgname = NULL;
   6195 	scf_walkinfo_t info;
   6196 
   6197 #ifndef NDEBUG
   6198 	if (flags & SCF_WALK_EXPLICIT)
   6199 		assert(flags & SCF_WALK_SERVICE);
   6200 	if (flags & SCF_WALK_NOINSTANCE)
   6201 		assert(flags & SCF_WALK_SERVICE);
   6202 	if (flags & SCF_WALK_PROPERTY)
   6203 		assert(!(flags & SCF_WALK_LEGACY));
   6204 #endif
   6205 
   6206 	/*
   6207 	 * Setup initial variables
   6208 	 */
   6209 	max_fmri_length = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH);
   6210 	assert(max_fmri_length != -1);
   6211 	max_name_length = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH);
   6212 	assert(max_name_length != -1);
   6213 
   6214 	if ((fmri = malloc(max_fmri_length + 1)) == NULL ||
   6215 	    (pgname = malloc(max_name_length + 1)) == NULL) {
   6216 		ret = SCF_ERROR_NO_MEMORY;
   6217 		goto error;
   6218 	}
   6219 
   6220 	if (argc == 0) {
   6221 		pattern = NULL;
   6222 	} else if ((pattern = calloc(argc, sizeof (scf_pattern_t)))
   6223 	    == NULL) {
   6224 		ret = SCF_ERROR_NO_MEMORY;
   6225 		goto error;
   6226 	}
   6227 
   6228 	if ((htable = calloc(WALK_HTABLE_SIZE, sizeof (void *))) == NULL) {
   6229 		ret = SCF_ERROR_NO_MEMORY;
   6230 		goto error;
   6231 	}
   6232 
   6233 	if ((inst = scf_instance_create(h)) == NULL ||
   6234 	    (svc = scf_service_create(h)) == NULL ||
   6235 	    (iter = scf_iter_create(h)) == NULL ||
   6236 	    (sciter = scf_iter_create(h)) == NULL ||
   6237 	    (siter = scf_iter_create(h)) == NULL ||
   6238 	    (scope = scf_scope_create(h)) == NULL ||
   6239 	    (pg = scf_pg_create(h)) == NULL ||
   6240 	    (prop = scf_property_create(h)) == NULL ||
   6241 	    (value = scf_value_create(h)) == NULL) {
   6242 		ret = scf_error();
   6243 		goto error;
   6244 	}
   6245 
   6246 	/*
   6247 	 * For each fmri given, we first check to see if it's a full service,
   6248 	 * instance, property group, or property FMRI.  This avoids having to do
   6249 	 * the (rather expensive) walk of all instances.  Any element which does
   6250 	 * not match a full fmri is identified as a globbed pattern or a partial
   6251 	 * fmri and stored in a private array when walking instances.
   6252 	 */
   6253 	for (i = 0; i < argc; i++) {
   6254 		const char *scope_name, *svc_name, *inst_name, *pg_name;
   6255 		const char *prop_name;
   6256 
   6257 		if (strlen(argv[i]) > max_fmri_length) {
   6258 			errfunc(scf_get_msg(SCF_MSG_ARGTOOLONG), argv[i]);
   6259 			if (err != NULL)
   6260 				*err = UU_EXIT_FATAL;
   6261 			continue;
   6262 		}
   6263 
   6264 		(void) strcpy(fmri, argv[i]);
   6265 		if (scf_parse_svc_fmri(fmri, &scope_name, &svc_name, &inst_name,
   6266 		    &pg_name, &prop_name) != SCF_SUCCESS)
   6267 			goto badfmri;
   6268 
   6269 		/*
   6270 		 * If the user has specified SCF_WALK_PROPERTY, allow property
   6271 		 * groups and properties.
   6272 		 */
   6273 		if (pg_name != NULL || prop_name != NULL) {
   6274 			if (!(flags & SCF_WALK_PROPERTY))
   6275 				goto badfmri;
   6276 
   6277 			if (scf_handle_decode_fmri(h, argv[i], NULL, NULL,
   6278 			    NULL, pg, prop, 0) != 0)
   6279 				goto badfmri;
   6280 
   6281 			if (scf_pg_get_name(pg, NULL, 0) < 0 &&
   6282 			    scf_property_get_name(prop, NULL, 0) < 0)
   6283 				goto badfmri;
   6284 
   6285 			if (scf_canonify_fmri(argv[i], fmri, max_fmri_length)
   6286 			    <= 0) {
   6287 				/*
   6288 				 * scf_parse_fmri() should have caught this.
   6289 				 */
   6290 				abort();
   6291 			}
   6292 
   6293 			if ((ret = scf_add_match(htable, fmri, NULL,
   6294 			    &pattern[i], flags & SCF_WALK_EXPLICIT)) != 0)
   6295 				goto error;
   6296 
   6297 			if ((pattern[i].sp_arg = strdup(argv[i])) == NULL) {
   6298 				ret = SCF_ERROR_NO_MEMORY;
   6299 				goto error;
   6300 			}
   6301 			pattern[i].sp_type = PATTERN_EXACT;
   6302 		}
   6303 
   6304 		/*
   6305 		 * We need at least a service name
   6306 		 */
   6307 		if (scope_name == NULL || svc_name == NULL)
   6308 			goto badfmri;
   6309 
   6310 		/*
   6311 		 * If we have a fully qualified instance, add it to our list of
   6312 		 * fmris to watch.
   6313 		 */
   6314 		if (inst_name != NULL) {
   6315 			if (flags & SCF_WALK_NOINSTANCE)
   6316 				goto badfmri;
   6317 
   6318 			if (scf_handle_decode_fmri(h, argv[i], NULL, NULL,
   6319 			    inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != 0)
   6320 				goto badfmri;
   6321 
   6322 			if (scf_canonify_fmri(argv[i], fmri, max_fmri_length)
   6323 			    <= 0)
   6324 				goto badfmri;
   6325 
   6326 			if ((ret = scf_add_match(htable, fmri, NULL,
   6327 			    &pattern[i], flags & SCF_WALK_EXPLICIT)) != 0)
   6328 				goto error;
   6329 
   6330 			if ((pattern[i].sp_arg = strdup(argv[i])) == NULL) {
   6331 				ret = SCF_ERROR_NO_MEMORY;
   6332 				goto error;
   6333 			}
   6334 			pattern[i].sp_type = PATTERN_EXACT;
   6335 
   6336 			continue;
   6337 		}
   6338 
   6339 		if (scf_handle_decode_fmri(h, argv[i], NULL, svc,
   6340 		    NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) !=
   6341 		    SCF_SUCCESS)
   6342 			goto badfmri;
   6343 
   6344 		/*
   6345 		 * If the user allows for bare services, then simply
   6346 		 * pass this service on.
   6347 		 */
   6348 		if (flags & SCF_WALK_SERVICE) {
   6349 			if (scf_service_to_fmri(svc, fmri,
   6350 			    max_fmri_length + 1) <= 0) {
   6351 				ret = scf_error();
   6352 				goto error;
   6353 			}
   6354 
   6355 			if ((ret = scf_add_match(htable, fmri, NULL,
   6356 			    &pattern[i], flags & SCF_WALK_EXPLICIT)) != 0)
   6357 				goto error;
   6358 
   6359 			if ((pattern[i].sp_arg = strdup(argv[i]))
   6360 			    == NULL) {
   6361 				ret = SCF_ERROR_NO_MEMORY;
   6362 				goto error;
   6363 			}
   6364 			pattern[i].sp_type = PATTERN_EXACT;
   6365 			continue;
   6366 		}
   6367 
   6368 		if (flags & SCF_WALK_NOINSTANCE)
   6369 			goto badfmri;
   6370 
   6371 		/*
   6372 		 * Otherwise, iterate over all instances in the service.
   6373 		 */
   6374 		if (scf_iter_service_instances(iter, svc) !=
   6375 		    SCF_SUCCESS) {
   6376 			ret = scf_error();
   6377 			goto error;
   6378 		}
   6379 
   6380 		for (;;) {
   6381 			ret = scf_iter_next_instance(iter, inst);
   6382 			if (ret == 0)
   6383 				break;
   6384 			if (ret != 1) {
   6385 				ret = scf_error();
   6386 				goto error;
   6387 			}
   6388 
   6389 			if (scf_instance_to_fmri(inst, fmri,
   6390 			    max_fmri_length + 1) == -1)
   6391 				goto badfmri;
   6392 
   6393 			if ((ret = scf_add_match(htable, fmri, NULL,
   6394 			    &pattern[i], flags & SCF_WALK_EXPLICIT)) != 0)
   6395 				goto error;
   6396 		}
   6397 
   6398 		if ((pattern[i].sp_arg = strdup(argv[i])) == NULL) {
   6399 			ret = SCF_ERROR_NO_MEMORY;
   6400 			goto error;
   6401 		}
   6402 		pattern[i].sp_type = PATTERN_EXACT;
   6403 
   6404 		continue;
   6405 
   6406 badfmri:
   6407 
   6408 		/*
   6409 		 * If we got here because of a fatal error, bail out
   6410 		 * immediately.
   6411 		 */
   6412 		if (scf_error() == SCF_ERROR_CONNECTION_BROKEN) {
   6413 			ret = scf_error();
   6414 			goto error;
   6415 		}
   6416 
   6417 		/*
   6418 		 * At this point we failed to interpret the argument as a
   6419 		 * complete fmri, so mark it as a partial or globbed FMRI for
   6420 		 * later processing.
   6421 		 */
   6422 		if (strpbrk(argv[i], "*?[") != NULL) {
   6423 			/*
   6424 			 * Prepend svc:/ to patterns which don't begin with * or
   6425 			 * svc: or lrc:.
   6426 			 */
   6427 			pattern[i].sp_type = PATTERN_GLOB;
   6428 			if (argv[i][0] == '*' ||
   6429 			    (strlen(argv[i]) >= 4 && argv[i][3] == ':'))
   6430 				pattern[i].sp_arg = strdup(argv[i]);
   6431 			else {
   6432 				pattern[i].sp_arg = malloc(strlen(argv[i]) + 6);
   6433 				if (pattern[i].sp_arg != NULL)
   6434 					(void) snprintf(pattern[i].sp_arg,
   6435 					    strlen(argv[i]) + 6, "svc:/%s",
   6436 					    argv[i]);
   6437 			}
   6438 		} else {
   6439 			pattern[i].sp_type = PATTERN_PARTIAL;
   6440 			pattern[i].sp_arg = strdup(argv[i]);
   6441 		}
   6442 		pattern_search = 1;
   6443 		if (pattern[i].sp_arg == NULL) {
   6444 			ret = SCF_ERROR_NO_MEMORY;
   6445 			goto error;
   6446 		}
   6447 	}
   6448 
   6449 	if (pattern_search || argc == 0) {
   6450 		/*
   6451 		 * We have a set of patterns to search for.  Iterate over all
   6452 		 * instances and legacy services searching for matches.
   6453 		 */
   6454 		if (scf_handle_get_local_scope(h, scope) != 0) {
   6455 			ret = scf_error();
   6456 			goto error;
   6457 		}
   6458 
   6459 		if (scf_iter_scope_services(sciter, scope) != 0) {
   6460 			ret = scf_error();
   6461 			goto error;
   6462 		}
   6463 
   6464 		for (;;) {
   6465 			ret = scf_iter_next_service(sciter, svc);
   6466 			if (ret == 0)
   6467 				break;
   6468 			if (ret != 1) {
   6469 				ret = scf_error();
   6470 				goto error;
   6471 			}
   6472 
   6473 			if (flags & SCF_WALK_SERVICE) {
   6474 				/*
   6475 				 * If the user is requesting bare services, try
   6476 				 * to match the service first.
   6477 				 */
   6478 				if (scf_service_to_fmri(svc, fmri,
   6479 				    max_fmri_length + 1) < 0) {
   6480 					ret = scf_error();
   6481 					goto error;
   6482 				}
   6483 
   6484 				if (argc == 0) {
   6485 					info.fmri = fmri;
   6486 					info.scope = scope;
   6487 					info.svc = svc;
   6488 					info.inst = NULL;
   6489 					info.pg = NULL;
   6490 					info.prop = NULL;
   6491 					if ((ret = callback(data, &info)) != 0)
   6492 						goto error;
   6493 					continue;
   6494 				} else if ((ret = scf_pattern_match(htable,
   6495 				    fmri, NULL, argc, pattern,
   6496 				    flags & SCF_WALK_EXPLICIT)) != 0) {
   6497 					goto error;
   6498 				}
   6499 			}
   6500 
   6501 			if (flags & SCF_WALK_NOINSTANCE)
   6502 				continue;
   6503 
   6504 			/*
   6505 			 * Iterate over all instances in the service.
   6506 			 */
   6507 			if (scf_iter_service_instances(siter, svc) != 0) {
   6508 				if (scf_error() != SCF_ERROR_DELETED) {
   6509 					ret = scf_error();
   6510 					goto error;
   6511 				}
   6512 				continue;
   6513 			}
   6514 
   6515 			for (;;) {
   6516 				ret = scf_iter_next_instance(siter, inst);
   6517 				if (ret == 0)
   6518 					break;
   6519 				if (ret != 1) {
   6520 					if (scf_error() != SCF_ERROR_DELETED) {
   6521 						ret = scf_error();
   6522 						goto error;
   6523 					}
   6524 					break;
   6525 				}
   6526 
   6527 				if (scf_instance_to_fmri(inst, fmri,
   6528 				    max_fmri_length + 1) < 0) {
   6529 					ret = scf_error();
   6530 					goto error;
   6531 				}
   6532 
   6533 				/*
   6534 				 * Without arguments, execute the callback
   6535 				 * immediately.
   6536 				 */
   6537 				if (argc == 0) {
   6538 					info.fmri = fmri;
   6539 					info.scope = scope;
   6540 					info.svc = svc;
   6541 					info.inst = inst;
   6542 					info.pg = NULL;
   6543 					info.prop = NULL;
   6544 					if ((ret = callback(data, &info)) != 0)
   6545 						goto error;
   6546 				} else if ((ret = scf_pattern_match(htable,
   6547 				    fmri, NULL, argc, pattern,
   6548 				    flags & SCF_WALK_EXPLICIT)) != 0) {
   6549 					goto error;
   6550 				}
   6551 			}
   6552 		}
   6553 
   6554 		/*
   6555 		 * Search legacy services
   6556 		 */
   6557 		if ((flags & SCF_WALK_LEGACY)) {
   6558 			if (scf_scope_get_service(scope, SCF_LEGACY_SERVICE,
   6559 			    svc) != 0) {
   6560 				if (scf_error() != SCF_ERROR_NOT_FOUND) {
   6561 					ret = scf_error();
   6562 					goto error;
   6563 				}
   6564 
   6565 				goto nolegacy;
   6566 			}
   6567 
   6568 			if (scf_iter_service_pgs_typed(iter, svc,
   6569 			    SCF_GROUP_FRAMEWORK) != SCF_SUCCESS) {
   6570 				ret = scf_error();
   6571 				goto error;
   6572 			}
   6573 
   6574 			(void) strcpy(fmri, LEGACY_SCHEME);
   6575 
   6576 			for (;;) {
   6577 				ret = scf_iter_next_pg(iter, pg);
   6578 				if (ret == -1) {
   6579 					ret = scf_error();
   6580 					goto error;
   6581 				}
   6582 				if (ret == 0)
   6583 					break;
   6584 
   6585 				if (scf_pg_get_property(pg,
   6586 				    SCF_LEGACY_PROPERTY_NAME, prop) == -1) {
   6587 					ret = scf_error();
   6588 					if (ret == SCF_ERROR_DELETED ||
   6589 					    ret == SCF_ERROR_NOT_FOUND) {
   6590 						ret = 0;
   6591 						continue;
   6592 					}
   6593 					goto error;
   6594 				}
   6595 
   6596 				if (scf_property_is_type(prop, SCF_TYPE_ASTRING)
   6597 				    != SCF_SUCCESS) {
   6598 					if (scf_error() == SCF_ERROR_DELETED)
   6599 						continue;
   6600 					ret = scf_error();
   6601 					goto error;
   6602 				}
   6603 
   6604 				if (scf_property_get_value(prop, value) !=
   6605 				    SCF_SUCCESS)
   6606 					continue;
   6607 
   6608 				if (scf_value_get_astring(value,
   6609 				    fmri + sizeof (LEGACY_SCHEME) - 1,
   6610 				    max_fmri_length + 2 -
   6611 				    sizeof (LEGACY_SCHEME)) <= 0)
   6612 					continue;
   6613 
   6614 				if (scf_pg_get_name(pg, pgname,
   6615 				    max_name_length + 1) <= 0) {
   6616 					if (scf_error() == SCF_ERROR_DELETED)
   6617 						continue;
   6618 					ret = scf_error();
   6619 					goto error;
   6620 				}
   6621 
   6622 				if (argc == 0) {
   6623 					info.fmri = fmri;
   6624 					info.scope = scope;
   6625 					info.svc = NULL;
   6626 					info.inst = NULL;
   6627 					info.pg = pg;
   6628 					info.prop = NULL;
   6629 					if ((ret = callback(data, &info)) != 0)
   6630 						goto error;
   6631 				} else if ((ret = scf_pattern_match(htable,
   6632 				    fmri, pgname, argc, pattern,
   6633 				    flags & SCF_WALK_EXPLICIT)) != 0)
   6634 					goto error;
   6635 			}
   6636 
   6637 		}
   6638 	}
   6639 nolegacy:
   6640 	ret = 0;
   6641 
   6642 	if (argc == 0)
   6643 		goto error;
   6644 
   6645 	/*
   6646 	 * Check all patterns, and see if we have that any that didn't match
   6647 	 * or any that matched multiple instances.  For svcprop, add up the
   6648 	 * total number of matching keys.
   6649 	 */
   6650 	info.count = 0;
   6651 	for (i = 0; i < argc; i++) {
   6652 		scf_match_t *match;
   6653 
   6654 		if (pattern[i].sp_type == PATTERN_INVALID)
   6655 			continue;
   6656 		if (pattern[i].sp_matchcount == 0) {
   6657 			scf_msg_t msgid;
   6658 			/*
   6659 			 * Provide a useful error message based on the argument
   6660 			 * and the type of entity requested.
   6661 			 */
   6662 			if (!(flags & SCF_WALK_LEGACY) &&
   6663 			    strncmp(pattern[i].sp_arg, "lrc:/", 5) == 0)
   6664 				msgid = SCF_MSG_PATTERN_LEGACY;
   6665 			else if (flags & SCF_WALK_PROPERTY)
   6666 				msgid = SCF_MSG_PATTERN_NOENTITY;
   6667 			else if (flags & SCF_WALK_NOINSTANCE)
   6668 				msgid = SCF_MSG_PATTERN_NOSERVICE;
   6669 			else if (flags & SCF_WALK_SERVICE)
   6670 				msgid = SCF_MSG_PATTERN_NOINSTSVC;
   6671 			else
   6672 				msgid = SCF_MSG_PATTERN_NOINSTANCE;
   6673 
   6674 			errfunc(scf_get_msg(msgid), pattern[i].sp_arg);
   6675 			if (err)
   6676 				*err = UU_EXIT_FATAL;
   6677 		} else if (!(flags & SCF_WALK_MULTIPLE) &&
   6678 		    pattern[i].sp_matchcount > 1) {
   6679 			size_t len, off;
   6680 			char *msg;
   6681 
   6682 			/*
   6683 			 * Construct a message with all possible FMRIs before
   6684 			 * passing off to error handling function.
   6685 			 *
   6686 			 * Note that strlen(scf_get_msg(...)) includes the
   6687 			 * length of '%s', which accounts for the terminating
   6688 			 * null byte.
   6689 			 */
   6690 			len = strlen(scf_get_msg(SCF_MSG_PATTERN_MULTIMATCH)) +
   6691 			    strlen(pattern[i].sp_arg);
   6692 			for (match = pattern[i].sp_matches; match != NULL;
   6693 			    match = match->sm_next) {
   6694 				len += strlen(match->sm_key->sk_fmri) + 2;
   6695 			}
   6696 			if ((msg = malloc(len)) == NULL) {
   6697 				ret = SCF_ERROR_NO_MEMORY;
   6698 				goto error;
   6699 			}
   6700 
   6701 			/* LINTED - format argument */
   6702 			(void) snprintf(msg, len,
   6703 			    scf_get_msg(SCF_MSG_PATTERN_MULTIMATCH),
   6704 			    pattern[i].sp_arg);
   6705 			off = strlen(msg);
   6706 			for (match = pattern[i].sp_matches; match != NULL;
   6707 			    match = match->sm_next) {
   6708 				off += snprintf(msg + off, len - off, "\t%s\n",
   6709 				    match->sm_key->sk_fmri);
   6710 			}
   6711 
   6712 			errfunc(msg);
   6713 			if (err != NULL)
   6714 				*err = UU_EXIT_FATAL;
   6715 
   6716 			free(msg);
   6717 		} else {
   6718 			for (match = pattern[i].sp_matches; match != NULL;
   6719 			    match = match->sm_next) {
   6720 				if (!match->sm_key->sk_seen)
   6721 					info.count++;
   6722 				match->sm_key->sk_seen = 1;
   6723 			}
   6724 		}
   6725 	}
   6726 
   6727 	/*
   6728 	 * Clear 'sk_seen' for all keys.
   6729 	 */
   6730 	for (i = 0; i < WALK_HTABLE_SIZE; i++) {
   6731 		scf_matchkey_t *key;
   6732 		for (key = htable[i]; key != NULL; key = key->sk_next)
   6733 			key->sk_seen = 0;
   6734 	}
   6735 
   6736 	/*
   6737 	 * Iterate over all the FMRIs in our hash table and execute the
   6738 	 * callback.
   6739 	 */
   6740 	for (i = 0; i < argc; i++) {
   6741 		scf_match_t *match;
   6742 		scf_matchkey_t *key;
   6743 
   6744 		/*
   6745 		 * Ignore patterns which didn't match anything or matched too
   6746 		 * many FMRIs.
   6747 		 */
   6748 		if (pattern[i].sp_matchcount == 0 ||
   6749 		    (!(flags & SCF_WALK_MULTIPLE) &&
   6750 		    pattern[i].sp_matchcount > 1))
   6751 			continue;
   6752 
   6753 		for (match = pattern[i].sp_matches; match != NULL;
   6754 		    match = match->sm_next) {
   6755 
   6756 			key = match->sm_key;
   6757 			if (key->sk_seen)
   6758 				continue;
   6759 
   6760 			key->sk_seen = 1;
   6761 
   6762 			if (key->sk_legacy != NULL) {
   6763 				if (scf_scope_get_service(scope,
   6764 				    "smf/legacy_run", svc) != 0) {
   6765 					ret = scf_error();
   6766 					goto error;
   6767 				}
   6768 
   6769 				if (scf_service_get_pg(svc, key->sk_legacy,
   6770 				    pg) != 0)
   6771 					continue;
   6772 
   6773 				info.fmri = key->sk_fmri;
   6774 				info.scope = scope;
   6775 				info.svc = NULL;
   6776 				info.inst = NULL;
   6777 				info.pg = pg;
   6778 				info.prop = NULL;
   6779 				if ((ret = callback(data, &info)) != 0)
   6780 					goto error;
   6781 			} else {
   6782 				if (scf_handle_decode_fmri(h, key->sk_fmri,
   6783 				    scope, svc, inst, pg, prop, 0) !=
   6784 				    SCF_SUCCESS)
   6785 					continue;
   6786 
   6787 				info.fmri = key->sk_fmri;
   6788 				info.scope = scope;
   6789 				info.svc = svc;
   6790 				if (scf_instance_get_name(inst, NULL, 0) < 0) {
   6791 					if (scf_error() ==
   6792 					    SCF_ERROR_CONNECTION_BROKEN) {
   6793 						ret = scf_error();
   6794 						goto error;
   6795 					}
   6796 					info.inst = NULL;
   6797 				} else {
   6798 					info.inst = inst;
   6799 				}
   6800 				if (scf_pg_get_name(pg, NULL, 0) < 0) {
   6801 					if (scf_error() ==
   6802 					    SCF_ERROR_CONNECTION_BROKEN) {
   6803 						ret = scf_error();
   6804 						goto error;
   6805 					}
   6806 					info.pg = NULL;
   6807 				} else {
   6808 					info.pg = pg;
   6809 				}
   6810 				if (scf_property_get_name(prop, NULL, 0) < 0) {
   6811 					if (scf_error() ==
   6812 					    SCF_ERROR_CONNECTION_BROKEN) {
   6813 						ret = scf_error();
   6814 						goto error;
   6815 					}
   6816 					info.prop = NULL;
   6817 				} else {
   6818 					info.prop = prop;
   6819 				}
   6820 
   6821 				if ((ret = callback(data, &info)) != 0)
   6822 					goto error;
   6823 			}
   6824 		}
   6825 	}
   6826 
   6827 error:
   6828 	if (htable) {
   6829 		scf_matchkey_t *key, *next;
   6830 
   6831 		for (i = 0; i < WALK_HTABLE_SIZE; i++) {
   6832 
   6833 			for (key = htable[i]; key != NULL;
   6834 			    key = next) {
   6835 
   6836 				next = key->sk_next;
   6837 
   6838 				if (key->sk_fmri != NULL)
   6839 					free(key->sk_fmri);
   6840 				if (key->sk_legacy != NULL)
   6841 					free(key->sk_legacy);
   6842 				free(key);
   6843 			}
   6844 		}
   6845 		free(htable);
   6846 	}
   6847 	if (pattern != NULL) {
   6848 		for (i = 0; i < argc; i++) {
   6849 			scf_match_t *match, *next;
   6850 
   6851 			if (pattern[i].sp_arg != NULL)
   6852 				free(pattern[i].sp_arg);
   6853 
   6854 			for (match = pattern[i].sp_matches; match != NULL;
   6855 			    match = next) {
   6856 
   6857 				next = match->sm_next;
   6858 
   6859 				free(match);
   6860 			}
   6861 		}
   6862 		free(pattern);
   6863 	}
   6864 
   6865 	free(fmri);
   6866 	free(pgname);
   6867 
   6868 	scf_value_destroy(value);
   6869 	scf_property_destroy(prop);
   6870 	scf_pg_destroy(pg);
   6871 	scf_scope_destroy(scope);
   6872 	scf_iter_destroy(siter);
   6873 	scf_iter_destroy(sciter);
   6874 	scf_iter_destroy(iter);
   6875 	scf_instance_destroy(inst);
   6876 	scf_service_destroy(svc);
   6877 
   6878 	return (ret);
   6879 }
   6880 
   6881 /*
   6882  * scf_encode32() is an implementation of Base32 encoding as described in
   6883  * section 6 of RFC 4648 - "The Base16, Base32, and Base64 Data
   6884  * Encodings". See http://www.ietf.org/rfc/rfc4648.txt?number=4648.  The
   6885  * input stream is divided into groups of 5 characters (40 bits).  Each
   6886  * group is encoded into 8 output characters where each output character
   6887  * represents 5 bits of input.
   6888  *
   6889  * If the input is not an even multiple of 5 characters, the output will be
   6890  * padded so that the output is an even multiple of 8 characters.  The
   6891  * standard specifies that the pad character is '='.  Unfortunately, '=' is
   6892  * not a legal character in SMF property names.  Thus, the caller can
   6893  * specify an alternate pad character with the pad argument.  If pad is 0,
   6894  * scf_encode32() will use '='.  Note that use of anything other than '='
   6895  * produces output that is not in conformance with RFC 4648.  It is
   6896  * suitable, however, for internal use of SMF software.  When the encoded
   6897  * data is used as part of an SMF property name, SCF_ENCODE32_PAD should be
   6898  * used as the pad character.
   6899  *
   6900  * Arguments:
   6901  *	input -		Address of the buffer to be encoded.
   6902  *	inlen -		Number of characters at input.
   6903  *	output -	Address of the buffer to receive the encoded data.
   6904  *	outmax -	Size of the buffer at output.
   6905  *	outlen -	If it is not NULL, outlen receives the number of
   6906  *			bytes placed in output.
   6907  *	pad -		Alternate padding character.
   6908  *
   6909  * Returns:
   6910  *	0	Buffer was successfully encoded.
   6911  *	-1	Indicates output buffer too small, or pad is one of the
   6912  *		standard encoding characters.
   6913  */
   6914 int
   6915 scf_encode32(const char *input, size_t inlen, char *output, size_t outmax,
   6916     size_t *outlen, char pad)
   6917 {
   6918 	uint_t group_size = 5;
   6919 	uint_t i;
   6920 	const unsigned char *in = (const unsigned char *)input;
   6921 	size_t olen;
   6922 	uchar_t *out = (uchar_t *)output;
   6923 	uint_t oval;
   6924 	uint_t pad_count;
   6925 
   6926 	/* Verify that there is enough room for the output. */
   6927 	olen = ((inlen + (group_size - 1)) / group_size) * 8;
   6928 	if (outlen)
   6929 		*outlen = olen;
   6930 	if (olen > outmax)
   6931 		return (-1);
   6932 
   6933 	/* If caller did not provide pad character, use the default. */
   6934 	if (pad == 0) {
   6935 		pad = '=';
   6936 	} else {
   6937 		/*
   6938 		 * Make sure that caller's pad is not one of the encoding
   6939 		 * characters.
   6940 		 */
   6941 		for (i = 0; i < sizeof (base32) - 1; i++) {
   6942 			if (pad == base32[i])
   6943 				return (-1);
   6944 		}
   6945 	}
   6946 
   6947 	/* Process full groups capturing 5 bits per output character. */
   6948 	for (; inlen >= group_size; in += group_size, inlen -= group_size) {
   6949 		/*
   6950 		 * The comments in this section number the bits in an
   6951 		 * 8 bit byte 0 to 7.  The high order bit is bit 7 and
   6952 		 * the low order bit is bit 0.
   6953 		 */
   6954 
   6955 		/* top 5 bits (7-3) from in[0] */
   6956 		*out++ = base32[in[0] >> 3];
   6957 		/* bits 2-0 from in[0] and top 2 (7-6) from in[1] */
   6958 		*out++ = base32[((in[0] << 2) & 0x1c) | (in[1] >> 6)];
   6959 		/* 5 bits (5-1) from in[1] */
   6960 		*out++ = base32[(in[1] >> 1) & 0x1f];
   6961 		/* low bit (0) from in[1] and top 4 (7-4) from in[2] */
   6962 		*out++ = base32[((in[1] << 4) & 0x10) | ((in[2] >> 4) & 0xf)];
   6963 		/* low 4 (3-0) from in[2] and top bit (7) from in[3] */
   6964 		*out++ = base32[((in[2] << 1) & 0x1e) | (in[3] >> 7)];
   6965 		/* 5 bits (6-2) from in[3] */
   6966 		*out++ = base32[(in[3] >> 2) & 0x1f];
   6967 		/* low 2 (1-0) from in[3] and top 3 (7-5) from in[4] */
   6968 		*out++ = base32[((in[3] << 3) & 0x18) | (in[4] >> 5)];
   6969 		/* low 5 (4-0) from in[4] */
   6970 		*out++ = base32[in[4] & 0x1f];
   6971 	}
   6972 
   6973 	/* Take care of final input bytes. */
   6974 	pad_count = 0;
   6975 	if (inlen) {
   6976 		/* top 5 bits (7-3) from in[0] */
   6977 		*out++ = base32[in[0] >> 3];
   6978 		/*
   6979 		 * low 3 (2-0) from in[0] and top 2 (7-6) from in[1] if
   6980 		 * available.
   6981 		 */
   6982 		oval = (in[0] << 2) & 0x1c;
   6983 		if (inlen == 1) {
   6984 			*out++ = base32[oval];
   6985 			pad_count = 6;
   6986 			goto padout;
   6987 		}
   6988 		oval |= in[1] >> 6;
   6989 		*out++ = base32[oval];
   6990 		/* 5 bits (5-1) from in[1] */
   6991 		*out++ = base32[(in[1] >> 1) & 0x1f];
   6992 		/*
   6993 		 * low bit (0) from in[1] and top 4 (7-4) from in[2] if
   6994 		 * available.
   6995 		 */
   6996 		oval = (in[1] << 4) & 0x10;
   6997 		if (inlen == 2) {
   6998 			*out++ = base32[oval];
   6999 			pad_count = 4;
   7000 			goto padout;
   7001 		}
   7002 		oval |= in[2] >> 4;
   7003 		*out++ = base32[oval];
   7004 		/*
   7005 		 * low 4 (3-0) from in[2] and top 1 (7) from in[3] if
   7006 		 * available.
   7007 		 */
   7008 		oval = (in[2] << 1) & 0x1e;
   7009 		if (inlen == 3) {
   7010 			*out++ = base32[oval];
   7011 			pad_count = 3;
   7012 			goto padout;
   7013 		}
   7014 		oval |= in[3] >> 7;
   7015 		*out++ = base32[oval];
   7016 		/* 5 bits (6-2) from in[3] */
   7017 		*out++ = base32[(in[3] >> 2) & 0x1f];
   7018 		/* low 2 bits (1-0) from in[3] */
   7019 		*out++ = base32[(in[3] << 3) & 0x18];
   7020 		pad_count = 1;
   7021 	}
   7022 padout:
   7023 	/*
   7024 	 * Pad the output so that it is a multiple of 8 bytes.
   7025 	 */
   7026 	for (; pad_count > 0; pad_count--) {
   7027 		*out++ = pad;
   7028 	}
   7029 
   7030 	/*
   7031 	 * Null terminate the output if there is enough room.
   7032 	 */
   7033 	if (olen < outmax)
   7034 		*out = 0;
   7035 
   7036 	return (0);
   7037 }
   7038 
   7039 /*
   7040  * scf_decode32() is an implementation of Base32 decoding as described in
   7041  * section 6 of RFC 4648 - "The Base16, Base32, and Base64 Data
   7042  * Encodings". See http://www.ietf.org/rfc/rfc4648.txt?number=4648.  The
   7043  * input stream is divided into groups of 8 encoded characters.  Each
   7044  * encoded character represents 5 bits of data.  Thus, the 8 encoded
   7045  * characters are used to produce 40 bits or 5 bytes of unencoded data in
   7046  * outbuf.
   7047  *
   7048  * If the encoder did not have enough data to generate a mulitple of 8
   7049  * characters of encoded data, it used a pad character to get to the 8
   7050  * character boundry. The standard specifies that the pad character is '='.
   7051  * Unfortunately, '=' is not a legal character in SMF property names.
   7052  * Thus, the caller can specify an alternate pad character with the pad
   7053  * argument.  If pad is 0, scf_decode32() will use '='.  Note that use of
   7054  * anything other than '=' is not in conformance with RFC 4648.  It is
   7055  * suitable, however, for internal use of SMF software.  When the encoded
   7056  * data is used in SMF property names, SCF_ENCODE32_PAD should be used as
   7057  * the pad character.
   7058  *
   7059  * Arguments:
   7060  *	in -		Buffer of encoded characters.
   7061  *	inlen -		Number of characters at in.
   7062  *	outbuf -	Buffer to receive the decoded bytes.  It can be the
   7063  *			same buffer as in.
   7064  *	outmax -	Size of the buffer at outbuf.
   7065  *	outlen -	If it is not NULL, outlen receives the number of
   7066  *			bytes placed in output.
   7067  *	pad -		Alternate padding character.
   7068  *
   7069  * Returns:
   7070  *	0	Buffer was successfully decoded.
   7071  *	-1	Indicates an invalid input character, output buffer too
   7072  *		small, or pad is one of the standard encoding characters.
   7073  */
   7074 int
   7075 scf_decode32(const char *in, size_t inlen, char *outbuf, size_t outmax,
   7076     size_t *outlen, char pad)
   7077 {
   7078 	char *bufend = outbuf + outmax;
   7079 	char c;
   7080 	uint_t count;
   7081 	uint32_t g[DECODE32_GS];
   7082 	size_t i;
   7083 	uint_t j;
   7084 	char *out = outbuf;
   7085 	boolean_t pad_seen = B_FALSE;
   7086 
   7087 	/* If caller did not provide pad character, use the default. */
   7088 	if (pad == 0) {
   7089 		pad = '=';
   7090 	} else {
   7091 		/*
   7092 		 * Make sure that caller's pad is not one of the encoding
   7093 		 * characters.
   7094 		 */
   7095 		for (i = 0; i < sizeof (base32) - 1; i++) {
   7096 			if (pad == base32[i])
   7097 				return (-1);
   7098 		}
   7099 	}
   7100 
   7101 	i = 0;
   7102 	while ((i < inlen) && (out < bufend)) {
   7103 		/* Get a group of input characters. */
   7104 		for (j = 0, count = 0;
   7105 		    (j < DECODE32_GS) && (i < inlen);
   7106 		    i++) {
   7107 			c = in[i];
   7108 			/*
   7109 			 * RFC 4648 allows for the encoded data to be split
   7110 			 * into multiple lines, so skip carriage returns
   7111 			 * and new lines.
   7112 			 */
   7113 			if ((c == '\r') || (c == '\n'))
   7114 				continue;
   7115 			if ((pad_seen == B_TRUE) && (c != pad)) {
   7116 				/* Group not completed by pads */
   7117 				return (-1);
   7118 			}
   7119 			if ((c < 0) || (c >= sizeof (index32))) {
   7120 				/* Illegal character. */
   7121 				return (-1);
   7122 			}
   7123 			if (c == pad) {
   7124 				pad_seen = B_TRUE;
   7125 				continue;
   7126 			}
   7127 			if ((g[j++] = index32[c]) == 0xff) {
   7128 				/* Illegal character */
   7129 				return (-1);
   7130 			}
   7131 			count++;
   7132 		}
   7133 
   7134 		/* Pack the group into five 8 bit bytes. */
   7135 		if ((count >= 2) && (out < bufend)) {
   7136 			/*
   7137 			 * Output byte 0:
   7138 			 *	5 bits (7-3) from g[0]
   7139 			 *	3 bits (2-0) from g[1] (4-2)
   7140 			 */
   7141 			*out++ = (g[0] << 3) | ((g[1] >> 2) & 0x7);
   7142 		}
   7143 		if ((count >= 4) && (out < bufend)) {
   7144 			/*
   7145 			 * Output byte 1:
   7146 			 *	2 bits (7-6) from g[1] (1-0)
   7147 			 *	5 bits (5-1) from g[2] (4-0)
   7148 			 *	1 bit (0) from g[3] (4)
   7149 			 */
   7150 			*out++ = (g[1] << 6) | (g[2] << 1) | \
   7151 			    ((g[3] >> 4) & 0x1);
   7152 		}
   7153 		if ((count >= 5) && (out < bufend)) {
   7154 			/*
   7155 			 * Output byte 2:
   7156 			 *	4 bits (7-4) from g[3] (3-0)
   7157 			 *	4 bits (3-0) from g[4] (4-1)
   7158 			 */
   7159 			*out++ = (g[3] << 4) | ((g[4] >> 1) & 0xf);
   7160 		}
   7161 		if ((count >= 7) && (out < bufend)) {
   7162 			/*
   7163 			 * Output byte 3:
   7164 			 *	1 bit (7) from g[4] (0)
   7165 			 *	5 bits (6-2) from g[5] (4-0)
   7166 			 *	2 bits (0-1) from g[6] (4-3)
   7167 			 */
   7168 			*out++ = (g[4] << 7) | (g[5] << 2) |
   7169 			    ((g[6] >> 3) & 0x3);
   7170 		}
   7171 		if ((count == 8) && (out < bufend)) {
   7172 			/*
   7173 			 * Output byte 4;
   7174 			 *	3 bits (7-5) from g[6] (2-0)
   7175 			 *	5 bits (4-0) from g[7] (4-0)
   7176 			 */
   7177 			*out++ = (g[6] << 5) | g[7];
   7178 		}
   7179 	}
   7180 	if (i < inlen) {
   7181 		/* Did not process all input characters. */
   7182 		return (-1);
   7183 	}
   7184 	if (outlen)
   7185 		*outlen = out - outbuf;
   7186 	/* Null terminate the output if there is room. */
   7187 	if (out < bufend)
   7188 		*out = 0;
   7189 	return (0);
   7190 }
   7191 
   7192 
   7193 /*
   7194  * _scf_request_backup:  a simple wrapper routine
   7195  */
   7196 int
   7197 _scf_request_backup(scf_handle_t *h, const char *name)
   7198 {
   7199 	struct rep_protocol_backup_request request;
   7200 	struct rep_protocol_response response;
   7201 
   7202 	int r;
   7203 
   7204 	if (strlcpy(request.rpr_name, name, sizeof (request.rpr_name)) >=
   7205 	    sizeof (request.rpr_name))
   7206 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
   7207 
   7208 	(void) pthread_mutex_lock(&h->rh_lock);
   7209 	request.rpr_request = REP_PROTOCOL_BACKUP;
   7210 	request.rpr_changeid = handle_next_changeid(h);
   7211 
   7212 	r = make_door_call(h, &request, sizeof (request),
   7213 	    &response, sizeof (response));
   7214 	(void) pthread_mutex_unlock(&h->rh_lock);
   7215 
   7216 	if (r < 0) {
   7217 		DOOR_ERRORS_BLOCK(r);
   7218 	}
   7219 
   7220 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
   7221 		return (scf_set_error(proto_error(response.rpr_response)));
   7222 	return (SCF_SUCCESS);
   7223 }
   7224 
   7225 /*
   7226  * Request svc.configd daemon to switch repository database.
   7227  *
   7228  * Can fail:
   7229  *
   7230  *	_NOT_BOUND		handle is not bound
   7231  *	_CONNECTION_BROKEN	server is not reachable
   7232  *	_INTERNAL		file operation error
   7233  *				the server response is too big
   7234  *	_PERMISSION_DENIED	not enough privileges to do request
   7235  *	_BACKEND_READONLY	backend is not writable
   7236  *	_BACKEND_ACCESS		backend access fails
   7237  *	_NO_RESOURCES		svc.configd is out of memory
   7238  */
   7239 int
   7240 _scf_repository_switch(scf_handle_t *h, int scf_sw)
   7241 {
   7242 	struct rep_protocol_switch_request request;
   7243 	struct rep_protocol_response response;
   7244 	int	r;
   7245 
   7246 	/*
   7247 	 * Setup request protocol and make door call
   7248 	 * Hold rh_lock lock before handle_next_changeid call
   7249 	 */
   7250 	(void) pthread_mutex_lock(&h->rh_lock);
   7251 
   7252 	request.rpr_flag = scf_sw;
   7253 	request.rpr_request = REP_PROTOCOL_SWITCH;
   7254 	request.rpr_changeid = handle_next_changeid(h);
   7255 
   7256 	r = make_door_call(h, &request, sizeof (request),
   7257 	    &response, sizeof (response));
   7258 
   7259 	(void) pthread_mutex_unlock(&h->rh_lock);
   7260 
   7261 	if (r < 0) {
   7262 		DOOR_ERRORS_BLOCK(r);
   7263 	}
   7264 
   7265 	/*
   7266 	 * Pass protocol error up
   7267 	 */
   7268 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
   7269 		return (scf_set_error(proto_error(response.rpr_response)));
   7270 
   7271 	return (SCF_SUCCESS);
   7272 }
   7273 
   7274 int
   7275 _scf_pg_is_read_protected(const scf_propertygroup_t *pg, boolean_t *out)
   7276 {
   7277 	char buf[REP_PROTOCOL_NAME_LEN];
   7278 	ssize_t res;
   7279 
   7280 	res = datael_get_name(&pg->rd_d, buf, sizeof (buf),
   7281 	    RP_ENTITY_NAME_PGREADPROT);
   7282 
   7283 	if (res == -1)
   7284 		return (-1);
   7285 
   7286 	if (uu_strtouint(buf, out, sizeof (*out), 0, 0, 1) == -1)
   7287 		return (scf_set_error(SCF_ERROR_INTERNAL));
   7288 	return (SCF_SUCCESS);
   7289 }
   7290 
   7291 /*
   7292  * _scf_set_annotation: a wrapper to set the annotation fields for SMF
   7293  * security auditing.
   7294  *
   7295  * Fails with following in scf_error_key thread specific data:
   7296  *	_INVALID_ARGUMENT - operation or file too large
   7297  *	_NOT_BOUND
   7298  *	_CONNECTION_BROKEN
   7299  *	_INTERNAL
   7300  *	_NO_RESOURCES
   7301  */
   7302 int
   7303 _scf_set_annotation(scf_handle_t *h, const char *operation, const char *file)
   7304 {
   7305 	struct rep_protocol_annotation request;
   7306 	struct rep_protocol_response response;
   7307 	size_t copied;
   7308 	int r;
   7309 
   7310 	if (h == NULL) {
   7311 		/* We can't do anything if the handle is destroyed. */
   7312 		return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED));
   7313 	}
   7314 
   7315 	request.rpr_request = REP_PROTOCOL_SET_AUDIT_ANNOTATION;
   7316 	copied = strlcpy(request.rpr_operation,
   7317 	    (operation == NULL) ? "" : operation,
   7318 	    sizeof (request.rpr_operation));
   7319 	if (copied >= sizeof (request.rpr_operation))
   7320 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
   7321 
   7322 	copied = strlcpy(request.rpr_file,
   7323 	    (file == NULL) ? "" : file,
   7324 	    sizeof (request.rpr_file));
   7325 	if (copied >= sizeof (request.rpr_file))
   7326 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
   7327 
   7328 	(void) pthread_mutex_lock(&h->rh_lock);
   7329 	r = make_door_call(h, &request, sizeof (request),
   7330 	    &response, sizeof (response));
   7331 	(void) pthread_mutex_unlock(&h->rh_lock);
   7332 
   7333 	if (r < 0) {
   7334 		DOOR_ERRORS_BLOCK(r);
   7335 	}
   7336 
   7337 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
   7338 		return (scf_set_error(proto_error(response.rpr_response)));
   7339 	return (0);
   7340 }
   7341