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