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