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