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