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