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