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