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