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