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