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