17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5103b2b15Sgww  * Common Development and Distribution License (the "License").
6103b2b15Sgww  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21a574db85Sraf 
227c478bd9Sstevel@tonic-gate /*
23b56bf881SAntonello Cruz  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
246c7c876cSJerry Jelinek  * Copyright 2013, Joyent, Inc. All rights reserved.
254f5c6fa5SAndrew Stormont  * Copyright 2016 RackTop Systems.
2648bbca81SDaniel Hoffman  * Copyright (c) 2016 by Delphix. All rights reserved.
27ad3ad82aSAndy Fiddaman  * Copyright 2017 OmniOS Community Edition (OmniOSce) Association.
28*29267a9dSAndy Fiddaman  * Copyright 2023 Oxide Computer Company
297c478bd9Sstevel@tonic-gate  */
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate /*
327c478bd9Sstevel@tonic-gate  * This is the main implementation file for the low-level repository
337c478bd9Sstevel@tonic-gate  * interface.
347c478bd9Sstevel@tonic-gate  */
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate #include "lowlevel_impl.h"
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate #include "repcache_protocol.h"
397c478bd9Sstevel@tonic-gate #include "scf_type.h"
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate #include <assert.h>
427c478bd9Sstevel@tonic-gate #include <alloca.h>
437c478bd9Sstevel@tonic-gate #include <door.h>
447c478bd9Sstevel@tonic-gate #include <errno.h>
457c478bd9Sstevel@tonic-gate #include <fcntl.h>
467c478bd9Sstevel@tonic-gate #include <fnmatch.h>
477c478bd9Sstevel@tonic-gate #include <libuutil.h>
487c478bd9Sstevel@tonic-gate #include <poll.h>
497c478bd9Sstevel@tonic-gate #include <pthread.h>
5053f3aea0SRoger A. Faulkner #include <synch.h>
517c478bd9Sstevel@tonic-gate #include <stddef.h>
527c478bd9Sstevel@tonic-gate #include <stdio.h>
537c478bd9Sstevel@tonic-gate #include <stdlib.h>
547c478bd9Sstevel@tonic-gate #include <string.h>
557c478bd9Sstevel@tonic-gate #include <sys/mman.h>
567c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
57048b0279SBryan Cantrill #include <libzonecfg.h>
587c478bd9Sstevel@tonic-gate #include <unistd.h>
59048b0279SBryan Cantrill #include <dlfcn.h>
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate #define	ENV_SCF_DEBUG		"LIBSCF_DEBUG"
627c478bd9Sstevel@tonic-gate #define	ENV_SCF_DOORPATH	"LIBSCF_DOORPATH"
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate static uint32_t default_debug = 0;
657c478bd9Sstevel@tonic-gate static const char *default_door_path = REPOSITORY_DOOR_NAME;
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate #define	CALL_FAILED		-1
687c478bd9Sstevel@tonic-gate #define	RESULT_TOO_BIG		-2
697c478bd9Sstevel@tonic-gate #define	NOT_BOUND		-3
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate static pthread_mutex_t	lowlevel_init_lock;
727c478bd9Sstevel@tonic-gate static int32_t		lowlevel_inited;
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate static uu_list_pool_t	*tran_entry_pool;
757c478bd9Sstevel@tonic-gate static uu_list_pool_t	*datael_pool;
767c478bd9Sstevel@tonic-gate static uu_list_pool_t	*iter_pool;
777c478bd9Sstevel@tonic-gate 
781f6eb021SLiane Praza /*
791f6eb021SLiane Praza  * base32[] index32[] are used in base32 encoding and decoding.
801f6eb021SLiane Praza  */
811f6eb021SLiane Praza static char base32[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
821f6eb021SLiane Praza static char index32[128] = {
831f6eb021SLiane Praza 	-1, -1, -1, -1, -1, -1, -1, -1,	/* 0-7 */
841f6eb021SLiane Praza 	-1, -1, -1, -1, -1, -1, -1, -1,	/* 8-15 */
851f6eb021SLiane Praza 	-1, -1, -1, -1, -1, -1, -1, -1,	/* 16-23 */
861f6eb021SLiane Praza 	-1, -1, -1, -1, -1, -1, -1, -1,	/* 24-31 */
871f6eb021SLiane Praza 	-1, -1, -1, -1, -1, -1, -1, -1,	/* 32-39 */
881f6eb021SLiane Praza 	-1, -1, -1, -1, -1, -1, -1, -1,	/* 40-47 */
891f6eb021SLiane Praza 	-1, -1, 26, 27, 28, 29, 30, 31,	/* 48-55 */
901f6eb021SLiane Praza 	-1, -1, -1, -1, -1, -1, -1, -1,	/* 56-63 */
911f6eb021SLiane Praza 	-1, 0, 1, 2, 3, 4, 5, 6,	/* 64-71 */
921f6eb021SLiane Praza 	7, 8, 9, 10, 11, 12, 13, 14,	/* 72-79 */
931f6eb021SLiane Praza 	15, 16, 17, 18, 19, 20, 21, 22,	/* 80-87 */
941f6eb021SLiane Praza 	23, 24, 25, -1, -1, -1, -1, -1,	/* 88-95 */
951f6eb021SLiane Praza 	-1, -1, -1, -1, -1, -1, -1, -1,	/* 96-103 */
961f6eb021SLiane Praza 	-1, -1, -1, -1, -1, -1, -1, -1,	/* 104-111 */
971f6eb021SLiane Praza 	-1, -1, -1, -1, -1, -1, -1, -1,	/* 112-119 */
981f6eb021SLiane Praza 	-1, -1, -1, -1, -1, -1, -1, -1	/* 120-127 */
991f6eb021SLiane Praza };
1001f6eb021SLiane Praza 
1011f6eb021SLiane Praza #define	DECODE32_GS	(8)	/* scf_decode32 group size */
1021f6eb021SLiane Praza 
1037c478bd9Sstevel@tonic-gate #ifdef lint
1047c478bd9Sstevel@tonic-gate #define	assert_nolint(x) (void)0
1057c478bd9Sstevel@tonic-gate #else
1067c478bd9Sstevel@tonic-gate #define	assert_nolint(x) assert(x)
1077c478bd9Sstevel@tonic-gate #endif
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate static void scf_iter_reset_locked(scf_iter_t *iter);
1107c478bd9Sstevel@tonic-gate static void scf_value_reset_locked(scf_value_t *val, int and_destroy);
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate #define	TYPE_VALUE	(-100)
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate /*
1157c478bd9Sstevel@tonic-gate  * Hold and release subhandles.  We only allow one thread access to the
11648bbca81SDaniel Hoffman  * subhandles at a time, and it can use any subset, grabbing and releasing
1177c478bd9Sstevel@tonic-gate  * them in any order.  The only restrictions are that you cannot hold an
1187c478bd9Sstevel@tonic-gate  * already-held subhandle, and all subhandles must be released before
1197c478bd9Sstevel@tonic-gate  * returning to the original caller.
1207c478bd9Sstevel@tonic-gate  */
1217c478bd9Sstevel@tonic-gate static void
handle_hold_subhandles(scf_handle_t * h,int mask)1227c478bd9Sstevel@tonic-gate handle_hold_subhandles(scf_handle_t *h, int mask)
1237c478bd9Sstevel@tonic-gate {
1247c478bd9Sstevel@tonic-gate 	assert(mask != 0 && (mask & ~RH_HOLD_ALL) == 0);
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
127a574db85Sraf 	while (h->rh_hold_flags != 0 && h->rh_holder != pthread_self()) {
128a574db85Sraf 		int cancel_state;
129a574db85Sraf 
130a574db85Sraf 		(void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,
131a574db85Sraf 		    &cancel_state);
132a574db85Sraf 		(void) pthread_cond_wait(&h->rh_cv, &h->rh_lock);
133a574db85Sraf 		(void) pthread_setcancelstate(cancel_state, NULL);
134a574db85Sraf 	}
1357c478bd9Sstevel@tonic-gate 	if (h->rh_hold_flags == 0)
1367c478bd9Sstevel@tonic-gate 		h->rh_holder = pthread_self();
1377c478bd9Sstevel@tonic-gate 	assert(!(h->rh_hold_flags & mask));
1387c478bd9Sstevel@tonic-gate 	h->rh_hold_flags |= mask;
1397c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
1407c478bd9Sstevel@tonic-gate }
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate static void
handle_rele_subhandles(scf_handle_t * h,int mask)1437c478bd9Sstevel@tonic-gate handle_rele_subhandles(scf_handle_t *h, int mask)
1447c478bd9Sstevel@tonic-gate {
1457c478bd9Sstevel@tonic-gate 	assert(mask != 0 && (mask & ~RH_HOLD_ALL) == 0);
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
1487c478bd9Sstevel@tonic-gate 	assert(h->rh_holder == pthread_self());
1497c478bd9Sstevel@tonic-gate 	assert((h->rh_hold_flags & mask));
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate 	h->rh_hold_flags &= ~mask;
1527c478bd9Sstevel@tonic-gate 	if (h->rh_hold_flags == 0)
1537c478bd9Sstevel@tonic-gate 		(void) pthread_cond_signal(&h->rh_cv);
1547c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
1557c478bd9Sstevel@tonic-gate }
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate #define	HOLD_HANDLE(h, flag, field) \
1587c478bd9Sstevel@tonic-gate 	(handle_hold_subhandles((h), (flag)), (h)->field)
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate #define	RELE_HANDLE(h, flag) \
1617c478bd9Sstevel@tonic-gate 	(handle_rele_subhandles((h), (flag)))
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate /*
1647c478bd9Sstevel@tonic-gate  * convenience macros, for functions that only need a one or two handles at
1657c478bd9Sstevel@tonic-gate  * any given time
1667c478bd9Sstevel@tonic-gate  */
1677c478bd9Sstevel@tonic-gate #define	HANDLE_HOLD_ITER(h)	HOLD_HANDLE((h), RH_HOLD_ITER, rh_iter)
1687c478bd9Sstevel@tonic-gate #define	HANDLE_HOLD_SCOPE(h)	HOLD_HANDLE((h), RH_HOLD_SCOPE, rh_scope)
1697c478bd9Sstevel@tonic-gate #define	HANDLE_HOLD_SERVICE(h)	HOLD_HANDLE((h), RH_HOLD_SERVICE, rh_service)
1707c478bd9Sstevel@tonic-gate #define	HANDLE_HOLD_INSTANCE(h)	HOLD_HANDLE((h), RH_HOLD_INSTANCE, rh_instance)
1717c478bd9Sstevel@tonic-gate #define	HANDLE_HOLD_SNAPSHOT(h)	HOLD_HANDLE((h), RH_HOLD_SNAPSHOT, rh_snapshot)
1727c478bd9Sstevel@tonic-gate #define	HANDLE_HOLD_SNAPLVL(h)	HOLD_HANDLE((h), RH_HOLD_SNAPLVL, rh_snaplvl)
1737c478bd9Sstevel@tonic-gate #define	HANDLE_HOLD_PG(h)	HOLD_HANDLE((h), RH_HOLD_PG, rh_pg)
1747c478bd9Sstevel@tonic-gate #define	HANDLE_HOLD_PROPERTY(h)	HOLD_HANDLE((h), RH_HOLD_PROPERTY, rh_property)
1757c478bd9Sstevel@tonic-gate #define	HANDLE_HOLD_VALUE(h)	HOLD_HANDLE((h), RH_HOLD_VALUE, rh_value)
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate #define	HANDLE_RELE_ITER(h)	RELE_HANDLE((h), RH_HOLD_ITER)
1787c478bd9Sstevel@tonic-gate #define	HANDLE_RELE_SCOPE(h)	RELE_HANDLE((h), RH_HOLD_SCOPE)
1797c478bd9Sstevel@tonic-gate #define	HANDLE_RELE_SERVICE(h)	RELE_HANDLE((h), RH_HOLD_SERVICE)
1807c478bd9Sstevel@tonic-gate #define	HANDLE_RELE_INSTANCE(h)	RELE_HANDLE((h), RH_HOLD_INSTANCE)
1817c478bd9Sstevel@tonic-gate #define	HANDLE_RELE_SNAPSHOT(h)	RELE_HANDLE((h), RH_HOLD_SNAPSHOT)
1827c478bd9Sstevel@tonic-gate #define	HANDLE_RELE_SNAPLVL(h)	RELE_HANDLE((h), RH_HOLD_SNAPLVL)
1837c478bd9Sstevel@tonic-gate #define	HANDLE_RELE_PG(h)	RELE_HANDLE((h), RH_HOLD_PG)
1847c478bd9Sstevel@tonic-gate #define	HANDLE_RELE_PROPERTY(h)	RELE_HANDLE((h), RH_HOLD_PROPERTY)
1857c478bd9Sstevel@tonic-gate #define	HANDLE_RELE_VALUE(h)	RELE_HANDLE((h), RH_HOLD_VALUE)
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1887c478bd9Sstevel@tonic-gate static int
transaction_entry_compare(const void * l_arg,const void * r_arg,void * private)1897c478bd9Sstevel@tonic-gate transaction_entry_compare(const void *l_arg, const void *r_arg, void *private)
1907c478bd9Sstevel@tonic-gate {
1917c478bd9Sstevel@tonic-gate 	const char *l_prop =
1927c478bd9Sstevel@tonic-gate 	    ((scf_transaction_entry_t *)l_arg)->entry_property;
1937c478bd9Sstevel@tonic-gate 	const char *r_prop =
1947c478bd9Sstevel@tonic-gate 	    ((scf_transaction_entry_t *)r_arg)->entry_property;
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate 	int ret;
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate 	ret = strcmp(l_prop, r_prop);
1997c478bd9Sstevel@tonic-gate 	if (ret > 0)
2007c478bd9Sstevel@tonic-gate 		return (1);
2018918dff3Sjwadams 	if (ret < 0)
2028918dff3Sjwadams 		return (-1);
2038918dff3Sjwadams 	return (0);
2048918dff3Sjwadams }
2058918dff3Sjwadams 
2068918dff3Sjwadams static int
datael_compare(const void * l_arg,const void * r_arg,void * private)2078918dff3Sjwadams datael_compare(const void *l_arg, const void *r_arg, void *private)
2088918dff3Sjwadams {
2098918dff3Sjwadams 	uint32_t l_id = ((scf_datael_t *)l_arg)->rd_entity;
2108918dff3Sjwadams 	uint32_t r_id = (r_arg != NULL) ? ((scf_datael_t *)r_arg)->rd_entity :
2118918dff3Sjwadams 	    *(uint32_t *)private;
2128918dff3Sjwadams 
2138918dff3Sjwadams 	if (l_id > r_id)
2148918dff3Sjwadams 		return (1);
2158918dff3Sjwadams 	if (l_id < r_id)
2168918dff3Sjwadams 		return (-1);
2178918dff3Sjwadams 	return (0);
2188918dff3Sjwadams }
2198918dff3Sjwadams 
2208918dff3Sjwadams static int
iter_compare(const void * l_arg,const void * r_arg,void * private)2218918dff3Sjwadams iter_compare(const void *l_arg, const void *r_arg, void *private)
2228918dff3Sjwadams {
2238918dff3Sjwadams 	uint32_t l_id = ((scf_iter_t *)l_arg)->iter_id;
2248918dff3Sjwadams 	uint32_t r_id = (r_arg != NULL) ? ((scf_iter_t *)r_arg)->iter_id :
2258918dff3Sjwadams 	    *(uint32_t *)private;
2268918dff3Sjwadams 
2278918dff3Sjwadams 	if (l_id > r_id)
2288918dff3Sjwadams 		return (1);
2298918dff3Sjwadams 	if (l_id < r_id)
2307c478bd9Sstevel@tonic-gate 		return (-1);
2317c478bd9Sstevel@tonic-gate 	return (0);
2327c478bd9Sstevel@tonic-gate }
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate static int
lowlevel_init(void)2357c478bd9Sstevel@tonic-gate lowlevel_init(void)
2367c478bd9Sstevel@tonic-gate {
2377c478bd9Sstevel@tonic-gate 	const char *debug;
2387c478bd9Sstevel@tonic-gate 	const char *door_path;
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&lowlevel_init_lock);
2417c478bd9Sstevel@tonic-gate 	if (lowlevel_inited == 0) {
2427c478bd9Sstevel@tonic-gate 		if (!issetugid() &&
2437c478bd9Sstevel@tonic-gate 		    (debug = getenv(ENV_SCF_DEBUG)) != NULL && debug[0] != 0 &&
2447c478bd9Sstevel@tonic-gate 		    uu_strtoint(debug, &default_debug, sizeof (default_debug),
2457c478bd9Sstevel@tonic-gate 		    0, 0, 0) == -1) {
2467c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "LIBSCF: $%s (%s): %s",
2477c478bd9Sstevel@tonic-gate 			    ENV_SCF_DEBUG, debug,
2487c478bd9Sstevel@tonic-gate 			    uu_strerror(uu_error()));
2497c478bd9Sstevel@tonic-gate 		}
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate 		if (!issetugid() &&
2527c478bd9Sstevel@tonic-gate 		    (door_path = getenv(ENV_SCF_DOORPATH)) != NULL &&
2537c478bd9Sstevel@tonic-gate 		    door_path[0] != 0) {
2547c478bd9Sstevel@tonic-gate 			default_door_path = strdup(door_path);
2557c478bd9Sstevel@tonic-gate 			if (default_door_path == NULL)
2567c478bd9Sstevel@tonic-gate 				default_door_path = door_path;
2577c478bd9Sstevel@tonic-gate 		}
2587c478bd9Sstevel@tonic-gate 
2597c478bd9Sstevel@tonic-gate 		datael_pool = uu_list_pool_create("SUNW,libscf_datael",
2607c478bd9Sstevel@tonic-gate 		    sizeof (scf_datael_t), offsetof(scf_datael_t, rd_node),
2618918dff3Sjwadams 		    datael_compare, UU_LIST_POOL_DEBUG);
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate 		iter_pool = uu_list_pool_create("SUNW,libscf_iter",
2647c478bd9Sstevel@tonic-gate 		    sizeof (scf_iter_t), offsetof(scf_iter_t, iter_node),
2658918dff3Sjwadams 		    iter_compare, UU_LIST_POOL_DEBUG);
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate 		assert_nolint(offsetof(scf_transaction_entry_t,
2687c478bd9Sstevel@tonic-gate 		    entry_property) == 0);
2697c478bd9Sstevel@tonic-gate 		tran_entry_pool = uu_list_pool_create(
2707c478bd9Sstevel@tonic-gate 		    "SUNW,libscf_transaction_entity",
2717c478bd9Sstevel@tonic-gate 		    sizeof (scf_transaction_entry_t),
2727c478bd9Sstevel@tonic-gate 		    offsetof(scf_transaction_entry_t, entry_link),
2737c478bd9Sstevel@tonic-gate 		    transaction_entry_compare, UU_LIST_POOL_DEBUG);
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate 		if (datael_pool == NULL || iter_pool == NULL ||
2767c478bd9Sstevel@tonic-gate 		    tran_entry_pool == NULL) {
2777c478bd9Sstevel@tonic-gate 			lowlevel_inited = -1;
2787c478bd9Sstevel@tonic-gate 			goto end;
2797c478bd9Sstevel@tonic-gate 		}
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate 		if (!scf_setup_error()) {
2827c478bd9Sstevel@tonic-gate 			lowlevel_inited = -1;
2837c478bd9Sstevel@tonic-gate 			goto end;
2847c478bd9Sstevel@tonic-gate 		}
2857c478bd9Sstevel@tonic-gate 		lowlevel_inited = 1;
2867c478bd9Sstevel@tonic-gate 	}
2877c478bd9Sstevel@tonic-gate end:
2887c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&lowlevel_init_lock);
2897c478bd9Sstevel@tonic-gate 	if (lowlevel_inited > 0)
2907c478bd9Sstevel@tonic-gate 		return (1);
2917c478bd9Sstevel@tonic-gate 	return (0);
2927c478bd9Sstevel@tonic-gate }
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate static const struct {
2957c478bd9Sstevel@tonic-gate 	scf_type_t ti_type;
2967c478bd9Sstevel@tonic-gate 	rep_protocol_value_type_t ti_proto_type;
2977c478bd9Sstevel@tonic-gate 	const char *ti_name;
2987c478bd9Sstevel@tonic-gate } scf_type_info[] = {
2994f5c6fa5SAndrew Stormont 	{SCF_TYPE_BOOLEAN,	REP_PROTOCOL_TYPE_BOOLEAN,
3004f5c6fa5SAndrew Stormont 	    SCF_TYPE_STRING_BOOLEAN},
3014f5c6fa5SAndrew Stormont 	{SCF_TYPE_COUNT,	REP_PROTOCOL_TYPE_COUNT,
3024f5c6fa5SAndrew Stormont 	    SCF_TYPE_STRING_COUNT},
3034f5c6fa5SAndrew Stormont 	{SCF_TYPE_INTEGER,	REP_PROTOCOL_TYPE_INTEGER,
3044f5c6fa5SAndrew Stormont 	    SCF_TYPE_STRING_INTEGER},
3054f5c6fa5SAndrew Stormont 	{SCF_TYPE_TIME,		REP_PROTOCOL_TYPE_TIME,
3064f5c6fa5SAndrew Stormont 	    SCF_TYPE_STRING_TIME},
3074f5c6fa5SAndrew Stormont 	{SCF_TYPE_ASTRING,	REP_PROTOCOL_TYPE_STRING,
3084f5c6fa5SAndrew Stormont 	    SCF_TYPE_STRING_ASTRING},
3094f5c6fa5SAndrew Stormont 	{SCF_TYPE_OPAQUE,	REP_PROTOCOL_TYPE_OPAQUE,
3104f5c6fa5SAndrew Stormont 	    SCF_TYPE_STRING_OPAQUE},
3114f5c6fa5SAndrew Stormont 	{SCF_TYPE_USTRING,	REP_PROTOCOL_SUBTYPE_USTRING,
3124f5c6fa5SAndrew Stormont 	    SCF_TYPE_STRING_USTRING},
3134f5c6fa5SAndrew Stormont 	{SCF_TYPE_URI,		REP_PROTOCOL_SUBTYPE_URI,
3144f5c6fa5SAndrew Stormont 	    SCF_TYPE_STRING_URI},
3154f5c6fa5SAndrew Stormont 	{SCF_TYPE_FMRI,		REP_PROTOCOL_SUBTYPE_FMRI,
3164f5c6fa5SAndrew Stormont 	    SCF_TYPE_STRING_FMRI},
3174f5c6fa5SAndrew Stormont 	{SCF_TYPE_HOST,		REP_PROTOCOL_SUBTYPE_HOST,
3184f5c6fa5SAndrew Stormont 	    SCF_TYPE_STRING_HOST},
3194f5c6fa5SAndrew Stormont 	{SCF_TYPE_HOSTNAME,	REP_PROTOCOL_SUBTYPE_HOSTNAME,
3204f5c6fa5SAndrew Stormont 	    SCF_TYPE_STRING_HOSTNAME},
3214f5c6fa5SAndrew Stormont 	{SCF_TYPE_NET_ADDR,	REP_PROTOCOL_SUBTYPE_NETADDR,
3224f5c6fa5SAndrew Stormont 	    SCF_TYPE_STRING_NET_ADDR},
3237c478bd9Sstevel@tonic-gate 	{SCF_TYPE_NET_ADDR_V4,	REP_PROTOCOL_SUBTYPE_NETADDR_V4,
3244f5c6fa5SAndrew Stormont 	    SCF_TYPE_STRING_NET_ADDR_V4},
3257c478bd9Sstevel@tonic-gate 	{SCF_TYPE_NET_ADDR_V6,	REP_PROTOCOL_SUBTYPE_NETADDR_V6,
3264f5c6fa5SAndrew Stormont 	    SCF_TYPE_STRING_NET_ADDR_V6}
3277c478bd9Sstevel@tonic-gate };
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate #define	SCF_TYPE_INFO_COUNT (sizeof (scf_type_info) / sizeof (*scf_type_info))
3307c478bd9Sstevel@tonic-gate static rep_protocol_value_type_t
scf_type_to_protocol_type(scf_type_t t)3317c478bd9Sstevel@tonic-gate scf_type_to_protocol_type(scf_type_t t)
3327c478bd9Sstevel@tonic-gate {
3337c478bd9Sstevel@tonic-gate 	int i;
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCF_TYPE_INFO_COUNT; i++)
3367c478bd9Sstevel@tonic-gate 		if (scf_type_info[i].ti_type == t)
3377c478bd9Sstevel@tonic-gate 			return (scf_type_info[i].ti_proto_type);
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 	return (REP_PROTOCOL_TYPE_INVALID);
3407c478bd9Sstevel@tonic-gate }
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate static scf_type_t
scf_protocol_type_to_type(rep_protocol_value_type_t t)3437c478bd9Sstevel@tonic-gate scf_protocol_type_to_type(rep_protocol_value_type_t t)
3447c478bd9Sstevel@tonic-gate {
3457c478bd9Sstevel@tonic-gate 	int i;
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCF_TYPE_INFO_COUNT; i++)
3487c478bd9Sstevel@tonic-gate 		if (scf_type_info[i].ti_proto_type == t)
3497c478bd9Sstevel@tonic-gate 			return (scf_type_info[i].ti_type);
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate 	return (SCF_TYPE_INVALID);
3527c478bd9Sstevel@tonic-gate }
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate const char *
scf_type_to_string(scf_type_t ty)3557c478bd9Sstevel@tonic-gate scf_type_to_string(scf_type_t ty)
3567c478bd9Sstevel@tonic-gate {
3577c478bd9Sstevel@tonic-gate 	int i;
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCF_TYPE_INFO_COUNT; i++)
3607c478bd9Sstevel@tonic-gate 		if (scf_type_info[i].ti_type == ty)
3617c478bd9Sstevel@tonic-gate 			return (scf_type_info[i].ti_name);
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 	return ("unknown");
3647c478bd9Sstevel@tonic-gate }
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate scf_type_t
scf_string_to_type(const char * name)3677c478bd9Sstevel@tonic-gate scf_string_to_type(const char *name)
3687c478bd9Sstevel@tonic-gate {
3697c478bd9Sstevel@tonic-gate 	int i;
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate 	for (i = 0; i < sizeof (scf_type_info) / sizeof (*scf_type_info); i++)
3727c478bd9Sstevel@tonic-gate 		if (strcmp(scf_type_info[i].ti_name, name) == 0)
3737c478bd9Sstevel@tonic-gate 			return (scf_type_info[i].ti_type);
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate 	return (SCF_TYPE_INVALID);
3767c478bd9Sstevel@tonic-gate }
3777c478bd9Sstevel@tonic-gate 
3787c478bd9Sstevel@tonic-gate int
scf_type_base_type(scf_type_t type,scf_type_t * out)3797c478bd9Sstevel@tonic-gate scf_type_base_type(scf_type_t type, scf_type_t *out)
3807c478bd9Sstevel@tonic-gate {
3817c478bd9Sstevel@tonic-gate 	rep_protocol_value_type_t t = scf_type_to_protocol_type(type);
3827c478bd9Sstevel@tonic-gate 	if (t == REP_PROTOCOL_TYPE_INVALID)
3837c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate 	*out = scf_protocol_type_to_type(scf_proto_underlying_type(t));
3867c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
3877c478bd9Sstevel@tonic-gate }
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate /*
3907c478bd9Sstevel@tonic-gate  * Convert a protocol error code into an SCF_ERROR_* code.
3917c478bd9Sstevel@tonic-gate  */
3927c478bd9Sstevel@tonic-gate static scf_error_t
proto_error(rep_protocol_responseid_t e)3937c478bd9Sstevel@tonic-gate proto_error(rep_protocol_responseid_t e)
3947c478bd9Sstevel@tonic-gate {
3957c478bd9Sstevel@tonic-gate 	switch (e) {
3967c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_MISORDERED:
3977c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_UNKNOWN_ID:
3987c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_INVALID_TYPE:
3997c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_TRUNCATED:
4007c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_TYPE_MISMATCH:
4017c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_NOT_APPLICABLE:
4027c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_UNKNOWN:
4037c478bd9Sstevel@tonic-gate 		return (SCF_ERROR_INTERNAL);
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_BAD_TX:
4067c478bd9Sstevel@tonic-gate 		return (SCF_ERROR_INVALID_ARGUMENT);
4077c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_BAD_REQUEST:
4087c478bd9Sstevel@tonic-gate 		return (SCF_ERROR_INVALID_ARGUMENT);
4097c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_NO_RESOURCES:
4107c478bd9Sstevel@tonic-gate 		return (SCF_ERROR_NO_RESOURCES);
4117c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_NOT_FOUND:
4127c478bd9Sstevel@tonic-gate 		return (SCF_ERROR_NOT_FOUND);
4137c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_DELETED:
4147c478bd9Sstevel@tonic-gate 		return (SCF_ERROR_DELETED);
4157c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_NOT_SET:
4167c478bd9Sstevel@tonic-gate 		return (SCF_ERROR_NOT_SET);
4177c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_EXISTS:
4187c478bd9Sstevel@tonic-gate 		return (SCF_ERROR_EXISTS);
4197c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_DUPLICATE_ID:
4207c478bd9Sstevel@tonic-gate 		return (SCF_ERROR_EXISTS);
4217c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_PERMISSION_DENIED:
4227c478bd9Sstevel@tonic-gate 		return (SCF_ERROR_PERMISSION_DENIED);
4237c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_BACKEND_ACCESS:
4247c478bd9Sstevel@tonic-gate 		return (SCF_ERROR_BACKEND_ACCESS);
4257c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_BACKEND_READONLY:
4267c478bd9Sstevel@tonic-gate 		return (SCF_ERROR_BACKEND_READONLY);
4277c478bd9Sstevel@tonic-gate 
4287c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_SUCCESS:
4297c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_DONE:
4307c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_NOT_LATEST:	/* TX code should handle this */
4317c478bd9Sstevel@tonic-gate 	default:
4327c478bd9Sstevel@tonic-gate #ifndef NDEBUG
4337c478bd9Sstevel@tonic-gate 		uu_warn("%s:%d: Bad error code %d passed to proto_error().\n",
4347c478bd9Sstevel@tonic-gate 		    __FILE__, __LINE__, e);
4357c478bd9Sstevel@tonic-gate #endif
4367c478bd9Sstevel@tonic-gate 		abort();
4377c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
4387c478bd9Sstevel@tonic-gate 	}
4397c478bd9Sstevel@tonic-gate }
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate ssize_t
scf_limit(uint32_t limit)4427c478bd9Sstevel@tonic-gate scf_limit(uint32_t limit)
4437c478bd9Sstevel@tonic-gate {
4447c478bd9Sstevel@tonic-gate 	switch (limit) {
4457c478bd9Sstevel@tonic-gate 	case SCF_LIMIT_MAX_NAME_LENGTH:
4467c478bd9Sstevel@tonic-gate 	case SCF_LIMIT_MAX_PG_TYPE_LENGTH:
4477c478bd9Sstevel@tonic-gate 		return (REP_PROTOCOL_NAME_LEN - 1);
4487c478bd9Sstevel@tonic-gate 	case SCF_LIMIT_MAX_VALUE_LENGTH:
4497c478bd9Sstevel@tonic-gate 		return (REP_PROTOCOL_VALUE_LEN - 1);
4507c478bd9Sstevel@tonic-gate 	case SCF_LIMIT_MAX_FMRI_LENGTH:
4517c478bd9Sstevel@tonic-gate 		return (SCF_FMRI_PREFIX_MAX_LEN +
4527c478bd9Sstevel@tonic-gate 		    sizeof (SCF_FMRI_SCOPE_PREFIX) - 1 +
4537c478bd9Sstevel@tonic-gate 		    sizeof (SCF_FMRI_SCOPE_SUFFIX) - 1 +
4547c478bd9Sstevel@tonic-gate 		    sizeof (SCF_FMRI_SERVICE_PREFIX) - 1 +
4557c478bd9Sstevel@tonic-gate 		    sizeof (SCF_FMRI_INSTANCE_PREFIX) - 1 +
4567c478bd9Sstevel@tonic-gate 		    sizeof (SCF_FMRI_PROPERTYGRP_PREFIX) - 1 +
4577c478bd9Sstevel@tonic-gate 		    sizeof (SCF_FMRI_PROPERTY_PREFIX) - 1 +
4587c478bd9Sstevel@tonic-gate 		    5 * (REP_PROTOCOL_NAME_LEN - 1));
4597c478bd9Sstevel@tonic-gate 	default:
4607c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4617c478bd9Sstevel@tonic-gate 	}
4627c478bd9Sstevel@tonic-gate }
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate static size_t
scf_opaque_decode(char * out_arg,const char * in,size_t max_out)4657c478bd9Sstevel@tonic-gate scf_opaque_decode(char *out_arg, const char *in, size_t max_out)
4667c478bd9Sstevel@tonic-gate {
4677c478bd9Sstevel@tonic-gate 	char a, b;
4687c478bd9Sstevel@tonic-gate 	char *out = out_arg;
4697c478bd9Sstevel@tonic-gate 
4707c478bd9Sstevel@tonic-gate 	while (max_out > 0 && (a = in[0]) != 0 && (b = in[1]) != 0) {
4717c478bd9Sstevel@tonic-gate 		in += 2;
4727c478bd9Sstevel@tonic-gate 
4737c478bd9Sstevel@tonic-gate 		if (a >= '0' && a <= '9')
4747c478bd9Sstevel@tonic-gate 			a -= '0';
4757c478bd9Sstevel@tonic-gate 		else if (a >= 'a' && a <= 'f')
4767c478bd9Sstevel@tonic-gate 			a = a - 'a' + 10;
4777c478bd9Sstevel@tonic-gate 		else if (a >= 'A' && a <= 'F')
4787c478bd9Sstevel@tonic-gate 			a = a - 'A' + 10;
4797c478bd9Sstevel@tonic-gate 		else
4807c478bd9Sstevel@tonic-gate 			break;
4817c478bd9Sstevel@tonic-gate 
4827c478bd9Sstevel@tonic-gate 		if (b >= '0' && b <= '9')
4837c478bd9Sstevel@tonic-gate 			b -= '0';
4847c478bd9Sstevel@tonic-gate 		else if (b >= 'a' && b <= 'f')
4857c478bd9Sstevel@tonic-gate 			b = b - 'a' + 10;
4867c478bd9Sstevel@tonic-gate 		else if (b >= 'A' && b <= 'F')
4877c478bd9Sstevel@tonic-gate 			b = b - 'A' + 10;
4887c478bd9Sstevel@tonic-gate 		else
4897c478bd9Sstevel@tonic-gate 			break;
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate 		*out++ = (a << 4) | b;
4927c478bd9Sstevel@tonic-gate 		max_out--;
4937c478bd9Sstevel@tonic-gate 	}
4947c478bd9Sstevel@tonic-gate 
4957c478bd9Sstevel@tonic-gate 	return (out - out_arg);
4967c478bd9Sstevel@tonic-gate }
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate static size_t
scf_opaque_encode(char * out_arg,const char * in_arg,size_t in_sz)4997c478bd9Sstevel@tonic-gate scf_opaque_encode(char *out_arg, const char *in_arg, size_t in_sz)
5007c478bd9Sstevel@tonic-gate {
5017c478bd9Sstevel@tonic-gate 	uint8_t *in = (uint8_t *)in_arg;
5027c478bd9Sstevel@tonic-gate 	uint8_t *end = in + in_sz;
5037c478bd9Sstevel@tonic-gate 	char *out = out_arg;
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate 	if (out == NULL)
5067c478bd9Sstevel@tonic-gate 		return (2 * in_sz);
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate 	while (in < end) {
5097c478bd9Sstevel@tonic-gate 		uint8_t c = *in++;
5107c478bd9Sstevel@tonic-gate 
5117c478bd9Sstevel@tonic-gate 		uint8_t a = (c & 0xf0) >> 4;
5127c478bd9Sstevel@tonic-gate 		uint8_t b = (c & 0x0f);
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate 		if (a <= 9)
5157c478bd9Sstevel@tonic-gate 			*out++ = a + '0';
5167c478bd9Sstevel@tonic-gate 		else
5177c478bd9Sstevel@tonic-gate 			*out++ = a + 'a' - 10;
5187c478bd9Sstevel@tonic-gate 
5197c478bd9Sstevel@tonic-gate 		if (b <= 9)
5207c478bd9Sstevel@tonic-gate 			*out++ = b + '0';
5217c478bd9Sstevel@tonic-gate 		else
5227c478bd9Sstevel@tonic-gate 			*out++ = b + 'a' - 10;
5237c478bd9Sstevel@tonic-gate 	}
5247c478bd9Sstevel@tonic-gate 
5257c478bd9Sstevel@tonic-gate 	*out = 0;
5267c478bd9Sstevel@tonic-gate 
5277c478bd9Sstevel@tonic-gate 	return (out - out_arg);
5287c478bd9Sstevel@tonic-gate }
5297c478bd9Sstevel@tonic-gate 
5307c478bd9Sstevel@tonic-gate static void
handle_do_close(scf_handle_t * h)5317c478bd9Sstevel@tonic-gate handle_do_close(scf_handle_t *h)
5327c478bd9Sstevel@tonic-gate {
5337c478bd9Sstevel@tonic-gate 	assert(MUTEX_HELD(&h->rh_lock));
5347c478bd9Sstevel@tonic-gate 	assert(h->rh_doorfd != -1);
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate 	/*
5377c478bd9Sstevel@tonic-gate 	 * if there are any active FD users, we just move the FD over
5387c478bd9Sstevel@tonic-gate 	 * to rh_doorfd_old -- they'll close it when they finish.
5397c478bd9Sstevel@tonic-gate 	 */
5407c478bd9Sstevel@tonic-gate 	if (h->rh_fd_users > 0) {
5417c478bd9Sstevel@tonic-gate 		h->rh_doorfd_old = h->rh_doorfd;
5427c478bd9Sstevel@tonic-gate 		h->rh_doorfd = -1;
5437c478bd9Sstevel@tonic-gate 	} else {
5447c478bd9Sstevel@tonic-gate 		assert(h->rh_doorfd_old == -1);
5457c478bd9Sstevel@tonic-gate 		(void) close(h->rh_doorfd);
5467c478bd9Sstevel@tonic-gate 		h->rh_doorfd = -1;
5477c478bd9Sstevel@tonic-gate 	}
5487c478bd9Sstevel@tonic-gate }
5497c478bd9Sstevel@tonic-gate 
5507c478bd9Sstevel@tonic-gate /*
5517c478bd9Sstevel@tonic-gate  * Check if a handle is currently bound.  fork()ing implicitly unbinds
5527c478bd9Sstevel@tonic-gate  * the handle in the child.
5537c478bd9Sstevel@tonic-gate  */
5547c478bd9Sstevel@tonic-gate static int
handle_is_bound(scf_handle_t * h)5557c478bd9Sstevel@tonic-gate handle_is_bound(scf_handle_t *h)
5567c478bd9Sstevel@tonic-gate {
5577c478bd9Sstevel@tonic-gate 	assert(MUTEX_HELD(&h->rh_lock));
5587c478bd9Sstevel@tonic-gate 
5597c478bd9Sstevel@tonic-gate 	if (h->rh_doorfd == -1)
5607c478bd9Sstevel@tonic-gate 		return (0);
5617c478bd9Sstevel@tonic-gate 
5627c478bd9Sstevel@tonic-gate 	if (getpid() == h->rh_doorpid)
5637c478bd9Sstevel@tonic-gate 		return (1);
5647c478bd9Sstevel@tonic-gate 
5657c478bd9Sstevel@tonic-gate 	/* forked since our last bind -- initiate handle close */
5667c478bd9Sstevel@tonic-gate 	handle_do_close(h);
5677c478bd9Sstevel@tonic-gate 	return (0);
5687c478bd9Sstevel@tonic-gate }
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate static int
handle_has_server_locked(scf_handle_t * h)5718918dff3Sjwadams handle_has_server_locked(scf_handle_t *h)
5727c478bd9Sstevel@tonic-gate {
5737c478bd9Sstevel@tonic-gate 	door_info_t i;
5748918dff3Sjwadams 	assert(MUTEX_HELD(&h->rh_lock));
5758918dff3Sjwadams 
5768918dff3Sjwadams 	return (handle_is_bound(h) && door_info(h->rh_doorfd, &i) != -1 &&
5778918dff3Sjwadams 	    i.di_target != -1);
5788918dff3Sjwadams }
5798918dff3Sjwadams 
5808918dff3Sjwadams static int
handle_has_server(scf_handle_t * h)5818918dff3Sjwadams handle_has_server(scf_handle_t *h)
5828918dff3Sjwadams {
5837c478bd9Sstevel@tonic-gate 	int ret;
5847c478bd9Sstevel@tonic-gate 
5857c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
5868918dff3Sjwadams 	ret = handle_has_server_locked(h);
5877c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate 	return (ret);
5907c478bd9Sstevel@tonic-gate }
5917c478bd9Sstevel@tonic-gate 
5927c478bd9Sstevel@tonic-gate /*
5937c478bd9Sstevel@tonic-gate  * This makes a door request on the client door associated with handle h.
5947c478bd9Sstevel@tonic-gate  * It will automatically retry calls which fail on EINTR.  If h is not bound,
5957c478bd9Sstevel@tonic-gate  * returns NOT_BOUND.  If the door call fails or the server response is too
5967c478bd9Sstevel@tonic-gate  * small, returns CALL_FAILED.  If the server response is too big, truncates the
5977c478bd9Sstevel@tonic-gate  * response and returns RESULT_TOO_BIG.  Otherwise, the size of the result is
5987c478bd9Sstevel@tonic-gate  * returned.
5997c478bd9Sstevel@tonic-gate  */
6007c478bd9Sstevel@tonic-gate static ssize_t
make_door_call(scf_handle_t * h,const void * req,size_t req_sz,void * res,size_t res_sz)6017c478bd9Sstevel@tonic-gate make_door_call(scf_handle_t *h, const void *req, size_t req_sz,
6027c478bd9Sstevel@tonic-gate     void *res, size_t res_sz)
6037c478bd9Sstevel@tonic-gate {
6047c478bd9Sstevel@tonic-gate 	door_arg_t arg;
6057c478bd9Sstevel@tonic-gate 	int r;
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate 	assert(MUTEX_HELD(&h->rh_lock));
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate 	if (!handle_is_bound(h)) {
6107c478bd9Sstevel@tonic-gate 		return (NOT_BOUND);
6117c478bd9Sstevel@tonic-gate 	}
6127c478bd9Sstevel@tonic-gate 
6137c478bd9Sstevel@tonic-gate 	arg.data_ptr = (void *)req;
6147c478bd9Sstevel@tonic-gate 	arg.data_size = req_sz;
6157c478bd9Sstevel@tonic-gate 	arg.desc_ptr = NULL;
6167c478bd9Sstevel@tonic-gate 	arg.desc_num = 0;
6177c478bd9Sstevel@tonic-gate 	arg.rbuf = res;
6187c478bd9Sstevel@tonic-gate 	arg.rsize = res_sz;
6197c478bd9Sstevel@tonic-gate 
6207c478bd9Sstevel@tonic-gate 	while ((r = door_call(h->rh_doorfd, &arg)) < 0) {
6217c478bd9Sstevel@tonic-gate 		if (errno != EINTR)
6227c478bd9Sstevel@tonic-gate 			break;
6237c478bd9Sstevel@tonic-gate 	}
6247c478bd9Sstevel@tonic-gate 
6257c478bd9Sstevel@tonic-gate 	if (r < 0) {
6267c478bd9Sstevel@tonic-gate 		return (CALL_FAILED);
6277c478bd9Sstevel@tonic-gate 	}
6287c478bd9Sstevel@tonic-gate 
6297c478bd9Sstevel@tonic-gate 	if (arg.desc_num > 0) {
6307c478bd9Sstevel@tonic-gate 		while (arg.desc_num > 0) {
6317c478bd9Sstevel@tonic-gate 			if (arg.desc_ptr->d_attributes & DOOR_DESCRIPTOR) {
6327c478bd9Sstevel@tonic-gate 				int cfd = arg.desc_ptr->d_data.d_desc.d_id;
6337c478bd9Sstevel@tonic-gate 				(void) close(cfd);
6347c478bd9Sstevel@tonic-gate 			}
6357c478bd9Sstevel@tonic-gate 			arg.desc_ptr++;
6367c478bd9Sstevel@tonic-gate 			arg.desc_num--;
6377c478bd9Sstevel@tonic-gate 		}
6387c478bd9Sstevel@tonic-gate 	}
6397c478bd9Sstevel@tonic-gate 	if (arg.data_ptr != res && arg.data_size > 0)
6407c478bd9Sstevel@tonic-gate 		(void) memmove(res, arg.data_ptr, MIN(arg.data_size, res_sz));
6417c478bd9Sstevel@tonic-gate 
6427c478bd9Sstevel@tonic-gate 	if (arg.rbuf != res)
6437c478bd9Sstevel@tonic-gate 		(void) munmap(arg.rbuf, arg.rsize);
6447c478bd9Sstevel@tonic-gate 
6457c478bd9Sstevel@tonic-gate 	if (arg.data_size > res_sz)
6467c478bd9Sstevel@tonic-gate 		return (RESULT_TOO_BIG);
6477c478bd9Sstevel@tonic-gate 
6487c478bd9Sstevel@tonic-gate 	if (arg.data_size < sizeof (uint32_t))
6497c478bd9Sstevel@tonic-gate 		return (CALL_FAILED);
6507c478bd9Sstevel@tonic-gate 
6517c478bd9Sstevel@tonic-gate 	return (arg.data_size);
6527c478bd9Sstevel@tonic-gate }
6537c478bd9Sstevel@tonic-gate 
6547c478bd9Sstevel@tonic-gate /*
6557c478bd9Sstevel@tonic-gate  * Should only be used when r < 0.
6567c478bd9Sstevel@tonic-gate  */
6577c478bd9Sstevel@tonic-gate #define	DOOR_ERRORS_BLOCK(r)	{					\
6587c478bd9Sstevel@tonic-gate 	switch (r) {							\
6597c478bd9Sstevel@tonic-gate 	case NOT_BOUND:							\
6607c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_NOT_BOUND));		\
6617c478bd9Sstevel@tonic-gate 									\
6627c478bd9Sstevel@tonic-gate 	case CALL_FAILED:						\
6637c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN));	\
6647c478bd9Sstevel@tonic-gate 									\
6657c478bd9Sstevel@tonic-gate 	case RESULT_TOO_BIG:						\
6667c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INTERNAL));		\
6677c478bd9Sstevel@tonic-gate 									\
6687c478bd9Sstevel@tonic-gate 	default:							\
6697c478bd9Sstevel@tonic-gate 		assert(r == NOT_BOUND || r == CALL_FAILED ||		\
6707c478bd9Sstevel@tonic-gate 		    r == RESULT_TOO_BIG);				\
6717c478bd9Sstevel@tonic-gate 		abort();						\
6727c478bd9Sstevel@tonic-gate 	}								\
6737c478bd9Sstevel@tonic-gate }
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate /*
6767c478bd9Sstevel@tonic-gate  * Like make_door_call(), but takes an fd instead of a handle, and expects
6777c478bd9Sstevel@tonic-gate  * a single file descriptor, returned via res_fd.
6787c478bd9Sstevel@tonic-gate  *
6797c478bd9Sstevel@tonic-gate  * If no file descriptor is returned, *res_fd == -1.
6807c478bd9Sstevel@tonic-gate  */
6817c478bd9Sstevel@tonic-gate static int
make_door_call_retfd(int fd,const void * req,size_t req_sz,void * res,size_t res_sz,int * res_fd)6827c478bd9Sstevel@tonic-gate make_door_call_retfd(int fd, const void *req, size_t req_sz, void *res,
6837c478bd9Sstevel@tonic-gate     size_t res_sz, int *res_fd)
6847c478bd9Sstevel@tonic-gate {
6857c478bd9Sstevel@tonic-gate 	door_arg_t arg;
6867c478bd9Sstevel@tonic-gate 	int r;
6877c478bd9Sstevel@tonic-gate 	char rbuf[256];
6887c478bd9Sstevel@tonic-gate 
6897c478bd9Sstevel@tonic-gate 	*res_fd = -1;
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate 	if (fd == -1)
6927c478bd9Sstevel@tonic-gate 		return (NOT_BOUND);
6937c478bd9Sstevel@tonic-gate 
6947c478bd9Sstevel@tonic-gate 	arg.data_ptr = (void *)req;
6957c478bd9Sstevel@tonic-gate 	arg.data_size = req_sz;
6967c478bd9Sstevel@tonic-gate 	arg.desc_ptr = NULL;
6977c478bd9Sstevel@tonic-gate 	arg.desc_num = 0;
6987c478bd9Sstevel@tonic-gate 	arg.rbuf = rbuf;
6997c478bd9Sstevel@tonic-gate 	arg.rsize = sizeof (rbuf);
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate 	while ((r = door_call(fd, &arg)) < 0) {
7027c478bd9Sstevel@tonic-gate 		if (errno != EINTR)
7037c478bd9Sstevel@tonic-gate 			break;
7047c478bd9Sstevel@tonic-gate 	}
7057c478bd9Sstevel@tonic-gate 
7067c478bd9Sstevel@tonic-gate 	if (r < 0)
7077c478bd9Sstevel@tonic-gate 		return (CALL_FAILED);
7087c478bd9Sstevel@tonic-gate 
7097c478bd9Sstevel@tonic-gate 	if (arg.desc_num > 1) {
7107c478bd9Sstevel@tonic-gate 		while (arg.desc_num > 0) {
7117c478bd9Sstevel@tonic-gate 			if (arg.desc_ptr->d_attributes & DOOR_DESCRIPTOR) {
7127c478bd9Sstevel@tonic-gate 				int cfd =
7137c478bd9Sstevel@tonic-gate 				    arg.desc_ptr->d_data.d_desc.d_descriptor;
7147c478bd9Sstevel@tonic-gate 				(void) close(cfd);
7157c478bd9Sstevel@tonic-gate 			}
7167c478bd9Sstevel@tonic-gate 			arg.desc_ptr++;
7177c478bd9Sstevel@tonic-gate 			arg.desc_num--;
7187c478bd9Sstevel@tonic-gate 		}
7197c478bd9Sstevel@tonic-gate 	}
7207c478bd9Sstevel@tonic-gate 	if (arg.desc_num == 1 && arg.desc_ptr->d_attributes & DOOR_DESCRIPTOR)
7217c478bd9Sstevel@tonic-gate 		*res_fd = arg.desc_ptr->d_data.d_desc.d_descriptor;
7227c478bd9Sstevel@tonic-gate 
7237c478bd9Sstevel@tonic-gate 	if (arg.data_size > 0)
7247c478bd9Sstevel@tonic-gate 		(void) memmove(res, arg.data_ptr, MIN(arg.data_size, res_sz));
7257c478bd9Sstevel@tonic-gate 
7267c478bd9Sstevel@tonic-gate 	if (arg.rbuf != rbuf)
7277c478bd9Sstevel@tonic-gate 		(void) munmap(arg.rbuf, arg.rsize);
7287c478bd9Sstevel@tonic-gate 
7297c478bd9Sstevel@tonic-gate 	if (arg.data_size > res_sz)
7307c478bd9Sstevel@tonic-gate 		return (RESULT_TOO_BIG);
7317c478bd9Sstevel@tonic-gate 
7327c478bd9Sstevel@tonic-gate 	if (arg.data_size < sizeof (uint32_t))
7337c478bd9Sstevel@tonic-gate 		return (CALL_FAILED);
7347c478bd9Sstevel@tonic-gate 
7357c478bd9Sstevel@tonic-gate 	return (arg.data_size);
7367c478bd9Sstevel@tonic-gate }
7377c478bd9Sstevel@tonic-gate 
7387c478bd9Sstevel@tonic-gate /*
7397c478bd9Sstevel@tonic-gate  * Fails with
7407c478bd9Sstevel@tonic-gate  *   _VERSION_MISMATCH
7417c478bd9Sstevel@tonic-gate  *   _NO_MEMORY
7427c478bd9Sstevel@tonic-gate  */
7437c478bd9Sstevel@tonic-gate scf_handle_t *
scf_handle_create(scf_version_t v)7447c478bd9Sstevel@tonic-gate scf_handle_create(scf_version_t v)
7457c478bd9Sstevel@tonic-gate {
7467c478bd9Sstevel@tonic-gate 	scf_handle_t *ret;
7477c478bd9Sstevel@tonic-gate 	int failed;
7487c478bd9Sstevel@tonic-gate 
7497c478bd9Sstevel@tonic-gate 	/*
7507c478bd9Sstevel@tonic-gate 	 * This will need to be revisited when we bump SCF_VERSION
7517c478bd9Sstevel@tonic-gate 	 */
7527c478bd9Sstevel@tonic-gate 	if (v != SCF_VERSION) {
7537c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_VERSION_MISMATCH);
7547c478bd9Sstevel@tonic-gate 		return (NULL);
7557c478bd9Sstevel@tonic-gate 	}
7567c478bd9Sstevel@tonic-gate 
7577c478bd9Sstevel@tonic-gate 	if (!lowlevel_init()) {
7587c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
7597c478bd9Sstevel@tonic-gate 		return (NULL);
7607c478bd9Sstevel@tonic-gate 	}
7617c478bd9Sstevel@tonic-gate 
7627c478bd9Sstevel@tonic-gate 	ret = uu_zalloc(sizeof (*ret));
7637c478bd9Sstevel@tonic-gate 	if (ret == NULL) {
7647c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
7657c478bd9Sstevel@tonic-gate 		return (NULL);
7667c478bd9Sstevel@tonic-gate 	}
7677c478bd9Sstevel@tonic-gate 
7687c478bd9Sstevel@tonic-gate 	ret->rh_dataels = uu_list_create(datael_pool, ret, 0);
7697c478bd9Sstevel@tonic-gate 	ret->rh_iters = uu_list_create(iter_pool, ret, 0);
7707c478bd9Sstevel@tonic-gate 	if (ret->rh_dataels == NULL || ret->rh_iters == NULL) {
7717c478bd9Sstevel@tonic-gate 		if (ret->rh_dataels != NULL)
7727c478bd9Sstevel@tonic-gate 			uu_list_destroy(ret->rh_dataels);
7737c478bd9Sstevel@tonic-gate 		if (ret->rh_iters != NULL)
7747c478bd9Sstevel@tonic-gate 			uu_list_destroy(ret->rh_iters);
7757c478bd9Sstevel@tonic-gate 		uu_free(ret);
7767c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
7777c478bd9Sstevel@tonic-gate 		return (NULL);
7787c478bd9Sstevel@tonic-gate 	}
7797c478bd9Sstevel@tonic-gate 
7807c478bd9Sstevel@tonic-gate 	ret->rh_doorfd = -1;
7817c478bd9Sstevel@tonic-gate 	ret->rh_doorfd_old = -1;
782*29267a9dSAndy Fiddaman 	ret->rh_zoneid = -1;
7837c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_init(&ret->rh_lock, NULL);
7847c478bd9Sstevel@tonic-gate 
7857c478bd9Sstevel@tonic-gate 	handle_hold_subhandles(ret, RH_HOLD_ALL);
7867c478bd9Sstevel@tonic-gate 
7877c478bd9Sstevel@tonic-gate 	failed = ((ret->rh_iter = scf_iter_create(ret)) == NULL ||
7887c478bd9Sstevel@tonic-gate 	    (ret->rh_scope = scf_scope_create(ret)) == NULL ||
7897c478bd9Sstevel@tonic-gate 	    (ret->rh_service = scf_service_create(ret)) == NULL ||
7907c478bd9Sstevel@tonic-gate 	    (ret->rh_instance = scf_instance_create(ret)) == NULL ||
7917c478bd9Sstevel@tonic-gate 	    (ret->rh_snapshot = scf_snapshot_create(ret)) == NULL ||
7927c478bd9Sstevel@tonic-gate 	    (ret->rh_snaplvl = scf_snaplevel_create(ret)) == NULL ||
7937c478bd9Sstevel@tonic-gate 	    (ret->rh_pg = scf_pg_create(ret)) == NULL ||
7947c478bd9Sstevel@tonic-gate 	    (ret->rh_property = scf_property_create(ret)) == NULL ||
7957c478bd9Sstevel@tonic-gate 	    (ret->rh_value = scf_value_create(ret)) == NULL);
7967c478bd9Sstevel@tonic-gate 
7977c478bd9Sstevel@tonic-gate 	/*
7987c478bd9Sstevel@tonic-gate 	 * these subhandles count as internal references, not external ones.
7997c478bd9Sstevel@tonic-gate 	 */
8007c478bd9Sstevel@tonic-gate 	ret->rh_intrefs = ret->rh_extrefs;
8017c478bd9Sstevel@tonic-gate 	ret->rh_extrefs = 0;
8027c478bd9Sstevel@tonic-gate 	handle_rele_subhandles(ret, RH_HOLD_ALL);
8037c478bd9Sstevel@tonic-gate 
8047c478bd9Sstevel@tonic-gate 	if (failed) {
8057c478bd9Sstevel@tonic-gate 		scf_handle_destroy(ret);
8067c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
8077c478bd9Sstevel@tonic-gate 		return (NULL);
8087c478bd9Sstevel@tonic-gate 	}
8097c478bd9Sstevel@tonic-gate 
8107c478bd9Sstevel@tonic-gate 	scf_value_set_count(ret->rh_value, default_debug);
8117c478bd9Sstevel@tonic-gate 	(void) scf_handle_decorate(ret, "debug", ret->rh_value);
8127c478bd9Sstevel@tonic-gate 
8137c478bd9Sstevel@tonic-gate 	return (ret);
8147c478bd9Sstevel@tonic-gate }
8157c478bd9Sstevel@tonic-gate 
816f6e214c7SGavin Maltby /*
817f6e214c7SGavin Maltby  * Fails with
818f6e214c7SGavin Maltby  *   _NO_MEMORY
819f6e214c7SGavin Maltby  *   _NO_SERVER - server door could not be open()ed
820f6e214c7SGavin Maltby  *		  door call failed
821f6e214c7SGavin Maltby  *		  door_info() failed
822f6e214c7SGavin Maltby  *   _VERSION_MISMATCH - server returned bad file descriptor
823f6e214c7SGavin Maltby  *			 server claimed bad request
824f6e214c7SGavin Maltby  *			 server reported version mismatch
825f6e214c7SGavin Maltby  *			 server refused with unknown reason
826f6e214c7SGavin Maltby  *   _INVALID_ARGUMENT
827f6e214c7SGavin Maltby  *   _NO_RESOURCES - server is out of memory
828f6e214c7SGavin Maltby  *   _PERMISSION_DENIED
829f6e214c7SGavin Maltby  *   _INTERNAL - could not set up entities or iters
830f6e214c7SGavin Maltby  *		 server response too big
831f6e214c7SGavin Maltby  */
832f6e214c7SGavin Maltby scf_handle_t *
_scf_handle_create_and_bind(scf_version_t ver)833f6e214c7SGavin Maltby _scf_handle_create_and_bind(scf_version_t ver)
834f6e214c7SGavin Maltby {
835f6e214c7SGavin Maltby 	scf_handle_t *h;
836f6e214c7SGavin Maltby 
837f6e214c7SGavin Maltby 	h = scf_handle_create(ver);
838f6e214c7SGavin Maltby 	if (h == NULL)
839f6e214c7SGavin Maltby 		return (NULL);
840f6e214c7SGavin Maltby 
841f6e214c7SGavin Maltby 	if (scf_handle_bind(h) == -1) {
842f6e214c7SGavin Maltby 		scf_handle_destroy(h);
843f6e214c7SGavin Maltby 		return (NULL);
844f6e214c7SGavin Maltby 	}
845f6e214c7SGavin Maltby 	return (h);
846f6e214c7SGavin Maltby }
847f6e214c7SGavin Maltby 
8487c478bd9Sstevel@tonic-gate int
scf_handle_decorate(scf_handle_t * handle,const char * name,scf_value_t * v)8497c478bd9Sstevel@tonic-gate scf_handle_decorate(scf_handle_t *handle, const char *name, scf_value_t *v)
8507c478bd9Sstevel@tonic-gate {
8517c478bd9Sstevel@tonic-gate 	if (v != SCF_DECORATE_CLEAR && handle != v->value_handle)
8527c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
8537c478bd9Sstevel@tonic-gate 
8547c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&handle->rh_lock);
8557c478bd9Sstevel@tonic-gate 	if (handle_is_bound(handle)) {
8567c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&handle->rh_lock);
8577c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_IN_USE));
8587c478bd9Sstevel@tonic-gate 	}
8597c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&handle->rh_lock);
8607c478bd9Sstevel@tonic-gate 
8617c478bd9Sstevel@tonic-gate 	if (strcmp(name, "debug") == 0) {
8627c478bd9Sstevel@tonic-gate 		if (v == SCF_DECORATE_CLEAR) {
8637c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_lock(&handle->rh_lock);
8647c478bd9Sstevel@tonic-gate 			handle->rh_debug = 0;
8657c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&handle->rh_lock);
8667c478bd9Sstevel@tonic-gate 		} else {
8677c478bd9Sstevel@tonic-gate 			uint64_t val;
8687c478bd9Sstevel@tonic-gate 			if (scf_value_get_count(v, &val) < 0)
8697c478bd9Sstevel@tonic-gate 				return (-1);		/* error already set */
8707c478bd9Sstevel@tonic-gate 
8717c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_lock(&handle->rh_lock);
8727c478bd9Sstevel@tonic-gate 			handle->rh_debug = (uid_t)val;
8737c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&handle->rh_lock);
8747c478bd9Sstevel@tonic-gate 		}
8757c478bd9Sstevel@tonic-gate 		return (0);
8767c478bd9Sstevel@tonic-gate 	}
8777c478bd9Sstevel@tonic-gate 	if (strcmp(name, "door_path") == 0) {
8787c478bd9Sstevel@tonic-gate 		char name[sizeof (handle->rh_doorpath)];
8797c478bd9Sstevel@tonic-gate 
8807c478bd9Sstevel@tonic-gate 		if (v == SCF_DECORATE_CLEAR) {
8817c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_lock(&handle->rh_lock);
8827c478bd9Sstevel@tonic-gate 			handle->rh_doorpath[0] = 0;
8837c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&handle->rh_lock);
8847c478bd9Sstevel@tonic-gate 		} else {
8857c478bd9Sstevel@tonic-gate 			ssize_t len;
8867c478bd9Sstevel@tonic-gate 
8877c478bd9Sstevel@tonic-gate 			if ((len = scf_value_get_astring(v, name,
8887c478bd9Sstevel@tonic-gate 			    sizeof (name))) < 0) {
8897c478bd9Sstevel@tonic-gate 				return (-1);		/* error already set */
8907c478bd9Sstevel@tonic-gate 			}
8917c478bd9Sstevel@tonic-gate 			if (len == 0 || len >= sizeof (name)) {
8927c478bd9Sstevel@tonic-gate 				return (scf_set_error(
8937c478bd9Sstevel@tonic-gate 				    SCF_ERROR_INVALID_ARGUMENT));
8947c478bd9Sstevel@tonic-gate 			}
8957c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_lock(&handle->rh_lock);
8967c478bd9Sstevel@tonic-gate 			(void) strlcpy(handle->rh_doorpath, name,
8977c478bd9Sstevel@tonic-gate 			    sizeof (handle->rh_doorpath));
8987c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&handle->rh_lock);
8997c478bd9Sstevel@tonic-gate 		}
9007c478bd9Sstevel@tonic-gate 		return (0);
9017c478bd9Sstevel@tonic-gate 	}
902048b0279SBryan Cantrill 
903048b0279SBryan Cantrill 	if (strcmp(name, "zone") == 0) {
904048b0279SBryan Cantrill 		char zone[MAXPATHLEN], root[MAXPATHLEN], door[MAXPATHLEN];
905048b0279SBryan Cantrill 		static int (*zone_get_rootpath)(char *, char *, size_t);
906*29267a9dSAndy Fiddaman 		zoneid_t zid;
907048b0279SBryan Cantrill 		ssize_t len;
908048b0279SBryan Cantrill 
909048b0279SBryan Cantrill 		/*
910048b0279SBryan Cantrill 		 * In order to be able to set the zone on a handle, we want
911048b0279SBryan Cantrill 		 * to determine the zone's path, which requires us to call into
912048b0279SBryan Cantrill 		 * libzonecfg -- but libzonecfg.so links against libscf.so so
913048b0279SBryan Cantrill 		 * we must not explicitly link to it.  To circumvent the
914048b0279SBryan Cantrill 		 * circular dependency, we will pull it in here via dlopen().
915048b0279SBryan Cantrill 		 */
916048b0279SBryan Cantrill 		if (zone_get_rootpath == NULL) {
917048b0279SBryan Cantrill 			void *dl = dlopen("libzonecfg.so.1", RTLD_LAZY), *sym;
918048b0279SBryan Cantrill 
919048b0279SBryan Cantrill 			if (dl == NULL)
920048b0279SBryan Cantrill 				return (scf_set_error(SCF_ERROR_NOT_FOUND));
921048b0279SBryan Cantrill 
922048b0279SBryan Cantrill 			if ((sym = dlsym(dl, "zone_get_rootpath")) == NULL) {
923048b0279SBryan Cantrill 				(void) dlclose(dl);
924048b0279SBryan Cantrill 				return (scf_set_error(SCF_ERROR_INTERNAL));
925048b0279SBryan Cantrill 			}
926048b0279SBryan Cantrill 
927048b0279SBryan Cantrill 			zone_get_rootpath = (int(*)(char *, char *, size_t))sym;
928048b0279SBryan Cantrill 		}
929048b0279SBryan Cantrill 
930048b0279SBryan Cantrill 		if (v == SCF_DECORATE_CLEAR) {
931048b0279SBryan Cantrill 			(void) pthread_mutex_lock(&handle->rh_lock);
932048b0279SBryan Cantrill 			handle->rh_doorpath[0] = 0;
933048b0279SBryan Cantrill 			(void) pthread_mutex_unlock(&handle->rh_lock);
934048b0279SBryan Cantrill 
935048b0279SBryan Cantrill 			return (0);
936048b0279SBryan Cantrill 		}
937048b0279SBryan Cantrill 
938048b0279SBryan Cantrill 		if ((len = scf_value_get_astring(v, zone, sizeof (zone))) < 0)
939048b0279SBryan Cantrill 			return (-1);
940048b0279SBryan Cantrill 
941048b0279SBryan Cantrill 		if (len == 0 || len >= sizeof (zone))
942048b0279SBryan Cantrill 			return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
943048b0279SBryan Cantrill 
944048b0279SBryan Cantrill 		if (zone_get_rootpath(zone, root, sizeof (root)) != Z_OK) {
945048b0279SBryan Cantrill 			if (strcmp(zone, GLOBAL_ZONENAME) == 0) {
946048b0279SBryan Cantrill 				root[0] = '\0';
947048b0279SBryan Cantrill 			} else {
948048b0279SBryan Cantrill 				return (scf_set_error(SCF_ERROR_NOT_FOUND));
949048b0279SBryan Cantrill 			}
950048b0279SBryan Cantrill 		}
951048b0279SBryan Cantrill 
952*29267a9dSAndy Fiddaman 		if ((zid = getzoneidbyname(zone)) == -1) {
953*29267a9dSAndy Fiddaman 			/* The zone is not active. */
954*29267a9dSAndy Fiddaman 			return (scf_set_error(SCF_ERROR_NOT_FOUND));
955*29267a9dSAndy Fiddaman 		}
956*29267a9dSAndy Fiddaman 
957048b0279SBryan Cantrill 		if (snprintf(door, sizeof (door), "%s/%s", root,
958048b0279SBryan Cantrill 		    default_door_path) >= sizeof (door))
959048b0279SBryan Cantrill 			return (scf_set_error(SCF_ERROR_INTERNAL));
960048b0279SBryan Cantrill 
961048b0279SBryan Cantrill 		(void) pthread_mutex_lock(&handle->rh_lock);
962048b0279SBryan Cantrill 		(void) strlcpy(handle->rh_doorpath, door,
963048b0279SBryan Cantrill 		    sizeof (handle->rh_doorpath));
964*29267a9dSAndy Fiddaman 		handle->rh_zoneid = zid;
965048b0279SBryan Cantrill 		(void) pthread_mutex_unlock(&handle->rh_lock);
966048b0279SBryan Cantrill 
967048b0279SBryan Cantrill 		return (0);
968048b0279SBryan Cantrill 	}
969048b0279SBryan Cantrill 
9707c478bd9Sstevel@tonic-gate 	return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
9717c478bd9Sstevel@tonic-gate }
9727c478bd9Sstevel@tonic-gate 
9737c478bd9Sstevel@tonic-gate /*
9747c478bd9Sstevel@tonic-gate  * fails with INVALID_ARGUMENT and HANDLE_MISMATCH.
9757c478bd9Sstevel@tonic-gate  */
9767c478bd9Sstevel@tonic-gate int
_scf_handle_decorations(scf_handle_t * handle,scf_decoration_func * f,scf_value_t * v,void * data)9777c478bd9Sstevel@tonic-gate _scf_handle_decorations(scf_handle_t *handle, scf_decoration_func *f,
9787c478bd9Sstevel@tonic-gate     scf_value_t *v, void *data)
9797c478bd9Sstevel@tonic-gate {
9807c478bd9Sstevel@tonic-gate 	scf_decoration_info_t i;
9817c478bd9Sstevel@tonic-gate 	char name[sizeof (handle->rh_doorpath)];
9827c478bd9Sstevel@tonic-gate 	uint64_t debug;
9837c478bd9Sstevel@tonic-gate 
9847c478bd9Sstevel@tonic-gate 	if (f == NULL || v == NULL)
9857c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
9867c478bd9Sstevel@tonic-gate 
9877c478bd9Sstevel@tonic-gate 	if (v->value_handle != handle)
9887c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
9897c478bd9Sstevel@tonic-gate 
9907c478bd9Sstevel@tonic-gate 	i.sdi_name = (const char *)"debug";
9917c478bd9Sstevel@tonic-gate 	i.sdi_type = SCF_TYPE_COUNT;
9927c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&handle->rh_lock);
9937c478bd9Sstevel@tonic-gate 	debug = handle->rh_debug;
9947c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&handle->rh_lock);
9957c478bd9Sstevel@tonic-gate 	if (debug != 0) {
9967c478bd9Sstevel@tonic-gate 		scf_value_set_count(v, debug);
9977c478bd9Sstevel@tonic-gate 		i.sdi_value = v;
9987c478bd9Sstevel@tonic-gate 	} else {
9997c478bd9Sstevel@tonic-gate 		i.sdi_value = SCF_DECORATE_CLEAR;
10007c478bd9Sstevel@tonic-gate 	}
10017c478bd9Sstevel@tonic-gate 
10027c478bd9Sstevel@tonic-gate 	if ((*f)(&i, data) == 0)
10037c478bd9Sstevel@tonic-gate 		return (0);
10047c478bd9Sstevel@tonic-gate 
10057c478bd9Sstevel@tonic-gate 	i.sdi_name = (const char *)"door_path";
10067c478bd9Sstevel@tonic-gate 	i.sdi_type = SCF_TYPE_ASTRING;
10077c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&handle->rh_lock);
10087c478bd9Sstevel@tonic-gate 	(void) strlcpy(name, handle->rh_doorpath, sizeof (name));
10097c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&handle->rh_lock);
10107c478bd9Sstevel@tonic-gate 	if (name[0] != 0) {
10117c478bd9Sstevel@tonic-gate 		(void) scf_value_set_astring(v, name);
10127c478bd9Sstevel@tonic-gate 		i.sdi_value = v;
10137c478bd9Sstevel@tonic-gate 	} else {
10147c478bd9Sstevel@tonic-gate 		i.sdi_value = SCF_DECORATE_CLEAR;
10157c478bd9Sstevel@tonic-gate 	}
10167c478bd9Sstevel@tonic-gate 
10177c478bd9Sstevel@tonic-gate 	if ((*f)(&i, data) == 0)
10187c478bd9Sstevel@tonic-gate 		return (0);
10197c478bd9Sstevel@tonic-gate 
10207c478bd9Sstevel@tonic-gate 	return (1);
10217c478bd9Sstevel@tonic-gate }
10227c478bd9Sstevel@tonic-gate 
10237c478bd9Sstevel@tonic-gate /*
10247c478bd9Sstevel@tonic-gate  * Fails if handle is not bound.
10257c478bd9Sstevel@tonic-gate  */
10267c478bd9Sstevel@tonic-gate static int
handle_unbind_unlocked(scf_handle_t * handle)10277c478bd9Sstevel@tonic-gate handle_unbind_unlocked(scf_handle_t *handle)
10287c478bd9Sstevel@tonic-gate {
10297c478bd9Sstevel@tonic-gate 	rep_protocol_request_t request;
10307c478bd9Sstevel@tonic-gate 	rep_protocol_response_t response;
10317c478bd9Sstevel@tonic-gate 
10327c478bd9Sstevel@tonic-gate 	if (!handle_is_bound(handle))
10337c478bd9Sstevel@tonic-gate 		return (-1);
10347c478bd9Sstevel@tonic-gate 
10357c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_CLOSE;
10367c478bd9Sstevel@tonic-gate 
10377c478bd9Sstevel@tonic-gate 	(void) make_door_call(handle, &request, sizeof (request),
10387c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
10397c478bd9Sstevel@tonic-gate 
10407c478bd9Sstevel@tonic-gate 	handle_do_close(handle);
10417c478bd9Sstevel@tonic-gate 
10427c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
10437c478bd9Sstevel@tonic-gate }
10447c478bd9Sstevel@tonic-gate 
10457c478bd9Sstevel@tonic-gate /*
10467c478bd9Sstevel@tonic-gate  * Fails with
10477c478bd9Sstevel@tonic-gate  *   _HANDLE_DESTROYED - dp's handle has been destroyed
10487c478bd9Sstevel@tonic-gate  *   _INTERNAL - server response too big
10497c478bd9Sstevel@tonic-gate  *		 entity already set up with different type
10507c478bd9Sstevel@tonic-gate  *   _NO_RESOURCES - server out of memory
10517c478bd9Sstevel@tonic-gate  */
10527c478bd9Sstevel@tonic-gate static int
datael_attach(scf_datael_t * dp)10537c478bd9Sstevel@tonic-gate datael_attach(scf_datael_t *dp)
10547c478bd9Sstevel@tonic-gate {
10557c478bd9Sstevel@tonic-gate 	scf_handle_t *h = dp->rd_handle;
10567c478bd9Sstevel@tonic-gate 
10577c478bd9Sstevel@tonic-gate 	struct rep_protocol_entity_setup request;
10587c478bd9Sstevel@tonic-gate 	rep_protocol_response_t response;
10597c478bd9Sstevel@tonic-gate 	ssize_t r;
10607c478bd9Sstevel@tonic-gate 
10617c478bd9Sstevel@tonic-gate 	assert(MUTEX_HELD(&h->rh_lock));
10627c478bd9Sstevel@tonic-gate 
10637c478bd9Sstevel@tonic-gate 	dp->rd_reset = 0;		/* setup implicitly resets */
10647c478bd9Sstevel@tonic-gate 
10657c478bd9Sstevel@tonic-gate 	if (h->rh_flags & HANDLE_DEAD)
10667c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED));
10677c478bd9Sstevel@tonic-gate 
10687c478bd9Sstevel@tonic-gate 	if (!handle_is_bound(h))
10697c478bd9Sstevel@tonic-gate 		return (SCF_SUCCESS);		/* nothing to do */
10707c478bd9Sstevel@tonic-gate 
10717c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ENTITY_SETUP;
10727c478bd9Sstevel@tonic-gate 	request.rpr_entityid = dp->rd_entity;
10737c478bd9Sstevel@tonic-gate 	request.rpr_entitytype = dp->rd_type;
10747c478bd9Sstevel@tonic-gate 
10757c478bd9Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
10767c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
10777c478bd9Sstevel@tonic-gate 
10787c478bd9Sstevel@tonic-gate 	if (r == NOT_BOUND || r == CALL_FAILED)
10797c478bd9Sstevel@tonic-gate 		return (SCF_SUCCESS);
10807c478bd9Sstevel@tonic-gate 	if (r == RESULT_TOO_BIG)
10817c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INTERNAL));
10827c478bd9Sstevel@tonic-gate 
10837c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
10847c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
10857c478bd9Sstevel@tonic-gate 
10867c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
10877c478bd9Sstevel@tonic-gate }
10887c478bd9Sstevel@tonic-gate 
10897c478bd9Sstevel@tonic-gate /*
10907c478bd9Sstevel@tonic-gate  * Fails with
10917c478bd9Sstevel@tonic-gate  *   _HANDLE_DESTROYED - iter's handle has been destroyed
10927c478bd9Sstevel@tonic-gate  *   _INTERNAL - server response too big
10937c478bd9Sstevel@tonic-gate  *		 iter already existed
10947c478bd9Sstevel@tonic-gate  *   _NO_RESOURCES
10957c478bd9Sstevel@tonic-gate  */
10967c478bd9Sstevel@tonic-gate static int
iter_attach(scf_iter_t * iter)10977c478bd9Sstevel@tonic-gate iter_attach(scf_iter_t *iter)
10987c478bd9Sstevel@tonic-gate {
10997c478bd9Sstevel@tonic-gate 	scf_handle_t *h = iter->iter_handle;
11007c478bd9Sstevel@tonic-gate 	struct rep_protocol_iter_request request;
11017c478bd9Sstevel@tonic-gate 	struct rep_protocol_response response;
11027c478bd9Sstevel@tonic-gate 	int r;
11037c478bd9Sstevel@tonic-gate 
11047c478bd9Sstevel@tonic-gate 	assert(MUTEX_HELD(&h->rh_lock));
11057c478bd9Sstevel@tonic-gate 
11067c478bd9Sstevel@tonic-gate 	if (h->rh_flags & HANDLE_DEAD)
11077c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED));
11087c478bd9Sstevel@tonic-gate 
11097c478bd9Sstevel@tonic-gate 	if (!handle_is_bound(h))
11107c478bd9Sstevel@tonic-gate 		return (SCF_SUCCESS);		/* nothing to do */
11117c478bd9Sstevel@tonic-gate 
11127c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ITER_SETUP;
11137c478bd9Sstevel@tonic-gate 	request.rpr_iterid = iter->iter_id;
11147c478bd9Sstevel@tonic-gate 
11157c478bd9Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
11167c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
11177c478bd9Sstevel@tonic-gate 
11187c478bd9Sstevel@tonic-gate 	if (r == NOT_BOUND || r == CALL_FAILED)
11197c478bd9Sstevel@tonic-gate 		return (SCF_SUCCESS);
11207c478bd9Sstevel@tonic-gate 	if (r == RESULT_TOO_BIG)
11217c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INTERNAL));
11227c478bd9Sstevel@tonic-gate 
11237c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
11247c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
11257c478bd9Sstevel@tonic-gate 
11267c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
11277c478bd9Sstevel@tonic-gate }
11287c478bd9Sstevel@tonic-gate 
11297c478bd9Sstevel@tonic-gate /*
11307c478bd9Sstevel@tonic-gate  * Fails with
11317c478bd9Sstevel@tonic-gate  *   _IN_USE - handle already bound
11327c478bd9Sstevel@tonic-gate  *   _NO_SERVER - server door could not be open()ed
11337c478bd9Sstevel@tonic-gate  *		  door call failed
11347c478bd9Sstevel@tonic-gate  *		  door_info() failed
11357c478bd9Sstevel@tonic-gate  *   _VERSION_MISMATCH - server returned bad file descriptor
11367c478bd9Sstevel@tonic-gate  *			 server claimed bad request
11377c478bd9Sstevel@tonic-gate  *			 server reported version mismatch
11387c478bd9Sstevel@tonic-gate  *			 server refused with unknown reason
11397c478bd9Sstevel@tonic-gate  *   _INVALID_ARGUMENT
11407c478bd9Sstevel@tonic-gate  *   _NO_RESOURCES - server is out of memory
11417c478bd9Sstevel@tonic-gate  *   _PERMISSION_DENIED
11427c478bd9Sstevel@tonic-gate  *   _INTERNAL - could not set up entities or iters
11437c478bd9Sstevel@tonic-gate  *		 server response too big
11447c478bd9Sstevel@tonic-gate  *
11457c478bd9Sstevel@tonic-gate  * perhaps this should try multiple times.
11467c478bd9Sstevel@tonic-gate  */
11477c478bd9Sstevel@tonic-gate int
scf_handle_bind(scf_handle_t * handle)11487c478bd9Sstevel@tonic-gate scf_handle_bind(scf_handle_t *handle)
11497c478bd9Sstevel@tonic-gate {
11507c478bd9Sstevel@tonic-gate 	scf_datael_t *el;
11517c478bd9Sstevel@tonic-gate 	scf_iter_t *iter;
11527c478bd9Sstevel@tonic-gate 
11537c478bd9Sstevel@tonic-gate 	pid_t pid;
11547c478bd9Sstevel@tonic-gate 	int fd;
11557c478bd9Sstevel@tonic-gate 	int res;
11567c478bd9Sstevel@tonic-gate 	door_info_t info;
11577c478bd9Sstevel@tonic-gate 	repository_door_request_t request;
11587c478bd9Sstevel@tonic-gate 	repository_door_response_t response;
11597c478bd9Sstevel@tonic-gate 	const char *door_name = default_door_path;
11607c478bd9Sstevel@tonic-gate 
11617c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&handle->rh_lock);
11627c478bd9Sstevel@tonic-gate 	if (handle_is_bound(handle)) {
11637c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&handle->rh_lock);
11647c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_IN_USE));
11657c478bd9Sstevel@tonic-gate 	}
11667c478bd9Sstevel@tonic-gate 
11677c478bd9Sstevel@tonic-gate 	/* wait until any active fd users have cleared out */
1168a574db85Sraf 	while (handle->rh_fd_users > 0) {
1169a574db85Sraf 		int cancel_state;
1170a574db85Sraf 
1171a574db85Sraf 		(void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,
1172a574db85Sraf 		    &cancel_state);
1173a574db85Sraf 		(void) pthread_cond_wait(&handle->rh_cv, &handle->rh_lock);
1174a574db85Sraf 		(void) pthread_setcancelstate(cancel_state, NULL);
1175a574db85Sraf 	}
11767c478bd9Sstevel@tonic-gate 
11777c478bd9Sstevel@tonic-gate 	/* check again, since we had to drop the lock */
11787c478bd9Sstevel@tonic-gate 	if (handle_is_bound(handle)) {
11797c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&handle->rh_lock);
11807c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_IN_USE));
11817c478bd9Sstevel@tonic-gate 	}
11827c478bd9Sstevel@tonic-gate 
11837c478bd9Sstevel@tonic-gate 	assert(handle->rh_doorfd == -1 && handle->rh_doorfd_old == -1);
11847c478bd9Sstevel@tonic-gate 
11857c478bd9Sstevel@tonic-gate 	if (handle->rh_doorpath[0] != 0)
11867c478bd9Sstevel@tonic-gate 		door_name = handle->rh_doorpath;
11877c478bd9Sstevel@tonic-gate 
1188*29267a9dSAndy Fiddaman 	fd = open(door_name, O_RDONLY | O_NOFOLLOW, 0);
11897c478bd9Sstevel@tonic-gate 	if (fd == -1) {
11907c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&handle->rh_lock);
11917c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_NO_SERVER));
11927c478bd9Sstevel@tonic-gate 	}
11937c478bd9Sstevel@tonic-gate 
1194*29267a9dSAndy Fiddaman 	/*
1195*29267a9dSAndy Fiddaman 	 * If the handle has been decorated with a "zone", indicating that
1196*29267a9dSAndy Fiddaman 	 * the door path should point to a door inside a zone, check that the
1197*29267a9dSAndy Fiddaman 	 * server process is actually inside that zone. This helps to guard
1198*29267a9dSAndy Fiddaman 	 * against symlink attacks.
1199*29267a9dSAndy Fiddaman 	 */
1200*29267a9dSAndy Fiddaman 	if (handle->rh_zoneid != -1) {
1201*29267a9dSAndy Fiddaman 		scf_error_t err = SCF_ERROR_NONE;
1202*29267a9dSAndy Fiddaman 		ucred_t *cr = NULL;
1203*29267a9dSAndy Fiddaman 
1204*29267a9dSAndy Fiddaman 		if (door_info(fd, &info) < 0) {
1205*29267a9dSAndy Fiddaman 			err = SCF_ERROR_NO_SERVER;
1206*29267a9dSAndy Fiddaman 		} else if ((cr = ucred_get(info.di_target)) == NULL) {
1207*29267a9dSAndy Fiddaman 			err = SCF_ERROR_PERMISSION_DENIED;
1208*29267a9dSAndy Fiddaman 		} else if (ucred_getzoneid(cr) != handle->rh_zoneid) {
1209*29267a9dSAndy Fiddaman 			err = SCF_ERROR_NO_SERVER;
1210*29267a9dSAndy Fiddaman 		}
1211*29267a9dSAndy Fiddaman 
1212*29267a9dSAndy Fiddaman 		ucred_free(cr);
1213*29267a9dSAndy Fiddaman 
1214*29267a9dSAndy Fiddaman 		if (err != SCF_ERROR_NONE) {
1215*29267a9dSAndy Fiddaman 			(void) pthread_mutex_unlock(&handle->rh_lock);
1216*29267a9dSAndy Fiddaman 			(void) close(fd);
1217*29267a9dSAndy Fiddaman 			return (scf_set_error(err));
1218*29267a9dSAndy Fiddaman 		}
1219*29267a9dSAndy Fiddaman 	}
1220*29267a9dSAndy Fiddaman 
12217c478bd9Sstevel@tonic-gate 	request.rdr_version = REPOSITORY_DOOR_VERSION;
12227c478bd9Sstevel@tonic-gate 	request.rdr_request = REPOSITORY_DOOR_REQUEST_CONNECT;
12237c478bd9Sstevel@tonic-gate 	request.rdr_flags = handle->rh_flags;
12247c478bd9Sstevel@tonic-gate 	request.rdr_debug = handle->rh_debug;
12257c478bd9Sstevel@tonic-gate 
12267c478bd9Sstevel@tonic-gate 	pid = getpid();
12277c478bd9Sstevel@tonic-gate 
12287c478bd9Sstevel@tonic-gate 	res = make_door_call_retfd(fd, &request, sizeof (request),
12297c478bd9Sstevel@tonic-gate 	    &response, sizeof (response), &handle->rh_doorfd);
12307c478bd9Sstevel@tonic-gate 
12317c478bd9Sstevel@tonic-gate 	(void) close(fd);
12327c478bd9Sstevel@tonic-gate 
12337c478bd9Sstevel@tonic-gate 	if (res < 0) {
12347c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&handle->rh_lock);
12357c478bd9Sstevel@tonic-gate 
12367c478bd9Sstevel@tonic-gate 		assert(res != NOT_BOUND);
12377c478bd9Sstevel@tonic-gate 		if (res == CALL_FAILED)
12387c478bd9Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_NO_SERVER));
12397c478bd9Sstevel@tonic-gate 		assert(res == RESULT_TOO_BIG);
12407c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INTERNAL));
12417c478bd9Sstevel@tonic-gate 	}
12427c478bd9Sstevel@tonic-gate 
12437c478bd9Sstevel@tonic-gate 	if (handle->rh_doorfd < 0) {
12447c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&handle->rh_lock);
12457c478bd9Sstevel@tonic-gate 
12467c478bd9Sstevel@tonic-gate 		switch (response.rdr_status) {
12477c478bd9Sstevel@tonic-gate 		case REPOSITORY_DOOR_SUCCESS:
12487c478bd9Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_VERSION_MISMATCH));
12497c478bd9Sstevel@tonic-gate 
12507c478bd9Sstevel@tonic-gate 		case REPOSITORY_DOOR_FAIL_BAD_REQUEST:
12517c478bd9Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_VERSION_MISMATCH));
12527c478bd9Sstevel@tonic-gate 
12537c478bd9Sstevel@tonic-gate 		case REPOSITORY_DOOR_FAIL_VERSION_MISMATCH:
12547c478bd9Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_VERSION_MISMATCH));
12557c478bd9Sstevel@tonic-gate 
12567c478bd9Sstevel@tonic-gate 		case REPOSITORY_DOOR_FAIL_BAD_FLAG:
12577c478bd9Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
12587c478bd9Sstevel@tonic-gate 
12597c478bd9Sstevel@tonic-gate 		case REPOSITORY_DOOR_FAIL_NO_RESOURCES:
12607c478bd9Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_NO_RESOURCES));
12617c478bd9Sstevel@tonic-gate 
12627c478bd9Sstevel@tonic-gate 		case REPOSITORY_DOOR_FAIL_PERMISSION_DENIED:
12637c478bd9Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_PERMISSION_DENIED));
12647c478bd9Sstevel@tonic-gate 
12657c478bd9Sstevel@tonic-gate 		default:
12667c478bd9Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_VERSION_MISMATCH));
12677c478bd9Sstevel@tonic-gate 		}
12687c478bd9Sstevel@tonic-gate 	}
12697c478bd9Sstevel@tonic-gate 
12707c478bd9Sstevel@tonic-gate 	(void) fcntl(handle->rh_doorfd, F_SETFD, FD_CLOEXEC);
12717c478bd9Sstevel@tonic-gate 
12727c478bd9Sstevel@tonic-gate 	if (door_info(handle->rh_doorfd, &info) < 0) {
12737c478bd9Sstevel@tonic-gate 		(void) close(handle->rh_doorfd);
12747c478bd9Sstevel@tonic-gate 		handle->rh_doorfd = -1;
12757c478bd9Sstevel@tonic-gate 
12767c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&handle->rh_lock);
12777c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_NO_SERVER));
12787c478bd9Sstevel@tonic-gate 	}
12797c478bd9Sstevel@tonic-gate 
12807c478bd9Sstevel@tonic-gate 	handle->rh_doorpid = pid;
12817c478bd9Sstevel@tonic-gate 	handle->rh_doorid = info.di_uniquifier;
12827c478bd9Sstevel@tonic-gate 
12837c478bd9Sstevel@tonic-gate 	/*
12847c478bd9Sstevel@tonic-gate 	 * Now, re-attach everything
12857c478bd9Sstevel@tonic-gate 	 */
12867c478bd9Sstevel@tonic-gate 	for (el = uu_list_first(handle->rh_dataels); el != NULL;
12877c478bd9Sstevel@tonic-gate 	    el = uu_list_next(handle->rh_dataels, el)) {
12887c478bd9Sstevel@tonic-gate 		if (datael_attach(el) == -1) {
12897c478bd9Sstevel@tonic-gate 			assert(scf_error() != SCF_ERROR_HANDLE_DESTROYED);
12907c478bd9Sstevel@tonic-gate 			(void) handle_unbind_unlocked(handle);
12917c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&handle->rh_lock);
12927c478bd9Sstevel@tonic-gate 			return (-1);
12937c478bd9Sstevel@tonic-gate 		}
12947c478bd9Sstevel@tonic-gate 	}
12957c478bd9Sstevel@tonic-gate 
12967c478bd9Sstevel@tonic-gate 	for (iter = uu_list_first(handle->rh_iters); iter != NULL;
12977c478bd9Sstevel@tonic-gate 	    iter = uu_list_next(handle->rh_iters, iter)) {
12987c478bd9Sstevel@tonic-gate 		if (iter_attach(iter) == -1) {
12997c478bd9Sstevel@tonic-gate 			assert(scf_error() != SCF_ERROR_HANDLE_DESTROYED);
13007c478bd9Sstevel@tonic-gate 			(void) handle_unbind_unlocked(handle);
13017c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&handle->rh_lock);
13027c478bd9Sstevel@tonic-gate 			return (-1);
13037c478bd9Sstevel@tonic-gate 		}
13047c478bd9Sstevel@tonic-gate 	}
13057c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&handle->rh_lock);
13067c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
13077c478bd9Sstevel@tonic-gate }
13087c478bd9Sstevel@tonic-gate 
13097c478bd9Sstevel@tonic-gate int
scf_handle_unbind(scf_handle_t * handle)13107c478bd9Sstevel@tonic-gate scf_handle_unbind(scf_handle_t *handle)
13117c478bd9Sstevel@tonic-gate {
13127c478bd9Sstevel@tonic-gate 	int ret;
13137c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&handle->rh_lock);
13147c478bd9Sstevel@tonic-gate 	ret = handle_unbind_unlocked(handle);
13157c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&handle->rh_lock);
13167c478bd9Sstevel@tonic-gate 	return (ret == SCF_SUCCESS ? ret : scf_set_error(SCF_ERROR_NOT_BOUND));
13177c478bd9Sstevel@tonic-gate }
13187c478bd9Sstevel@tonic-gate 
13197c478bd9Sstevel@tonic-gate static scf_handle_t *
handle_get(scf_handle_t * h)13207c478bd9Sstevel@tonic-gate handle_get(scf_handle_t *h)
13217c478bd9Sstevel@tonic-gate {
13227c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
13237c478bd9Sstevel@tonic-gate 	if (h->rh_flags & HANDLE_DEAD) {
13247c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
13257c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_HANDLE_DESTROYED);
13267c478bd9Sstevel@tonic-gate 		return (NULL);
13277c478bd9Sstevel@tonic-gate 	}
13287c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
13297c478bd9Sstevel@tonic-gate 	return (h);
13307c478bd9Sstevel@tonic-gate }
13317c478bd9Sstevel@tonic-gate 
13327c478bd9Sstevel@tonic-gate /*
13337c478bd9Sstevel@tonic-gate  * Called when an object is removed from the handle.  On the last remove,
13347c478bd9Sstevel@tonic-gate  * cleans up and frees the handle.
13357c478bd9Sstevel@tonic-gate  */
13367c478bd9Sstevel@tonic-gate static void
handle_unrefed(scf_handle_t * handle)13377c478bd9Sstevel@tonic-gate handle_unrefed(scf_handle_t *handle)
13387c478bd9Sstevel@tonic-gate {
13397c478bd9Sstevel@tonic-gate 	scf_iter_t *iter;
13407c478bd9Sstevel@tonic-gate 	scf_value_t *v;
13417c478bd9Sstevel@tonic-gate 	scf_scope_t *sc;
13427c478bd9Sstevel@tonic-gate 	scf_service_t *svc;
13437c478bd9Sstevel@tonic-gate 	scf_instance_t *inst;
13447c478bd9Sstevel@tonic-gate 	scf_snapshot_t *snap;
13457c478bd9Sstevel@tonic-gate 	scf_snaplevel_t *snaplvl;
13467c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *pg;
13477c478bd9Sstevel@tonic-gate 	scf_property_t *prop;
13487c478bd9Sstevel@tonic-gate 
13497c478bd9Sstevel@tonic-gate 	assert(MUTEX_HELD(&handle->rh_lock));
13507c478bd9Sstevel@tonic-gate 
13517c478bd9Sstevel@tonic-gate 	/*
13527c478bd9Sstevel@tonic-gate 	 * Don't do anything if the handle has not yet been destroyed, there
13537c478bd9Sstevel@tonic-gate 	 * are still external references, or we're already doing unrefed
13547c478bd9Sstevel@tonic-gate 	 * handling.
13557c478bd9Sstevel@tonic-gate 	 */
13567c478bd9Sstevel@tonic-gate 	if (!(handle->rh_flags & HANDLE_DEAD) ||
13577c478bd9Sstevel@tonic-gate 	    handle->rh_extrefs > 0 ||
13587c478bd9Sstevel@tonic-gate 	    handle->rh_fd_users > 0 ||
13597c478bd9Sstevel@tonic-gate 	    (handle->rh_flags & HANDLE_UNREFED)) {
13607c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&handle->rh_lock);
13617c478bd9Sstevel@tonic-gate 		return;
13627c478bd9Sstevel@tonic-gate 	}
13637c478bd9Sstevel@tonic-gate 
13647c478bd9Sstevel@tonic-gate 	handle->rh_flags |= HANDLE_UNREFED;
13657c478bd9Sstevel@tonic-gate 
13667c478bd9Sstevel@tonic-gate 	/*
13677c478bd9Sstevel@tonic-gate 	 * Now that we know that there are no external references, and the
13687c478bd9Sstevel@tonic-gate 	 * HANDLE_DEAD flag keeps new ones from appearing, we can clean up
13697c478bd9Sstevel@tonic-gate 	 * our subhandles and destroy the handle completely.
13707c478bd9Sstevel@tonic-gate 	 */
13717c478bd9Sstevel@tonic-gate 	assert(handle->rh_intrefs >= 0);
13727c478bd9Sstevel@tonic-gate 	handle->rh_extrefs = handle->rh_intrefs;
13737c478bd9Sstevel@tonic-gate 	handle->rh_intrefs = 0;
13747c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&handle->rh_lock);
13757c478bd9Sstevel@tonic-gate 
13767c478bd9Sstevel@tonic-gate 	handle_hold_subhandles(handle, RH_HOLD_ALL);
13777c478bd9Sstevel@tonic-gate 
13787c478bd9Sstevel@tonic-gate 	iter = handle->rh_iter;
13797c478bd9Sstevel@tonic-gate 	sc = handle->rh_scope;
13807c478bd9Sstevel@tonic-gate 	svc = handle->rh_service;
13817c478bd9Sstevel@tonic-gate 	inst = handle->rh_instance;
13827c478bd9Sstevel@tonic-gate 	snap = handle->rh_snapshot;
13837c478bd9Sstevel@tonic-gate 	snaplvl = handle->rh_snaplvl;
13847c478bd9Sstevel@tonic-gate 	pg = handle->rh_pg;
13857c478bd9Sstevel@tonic-gate 	prop = handle->rh_property;
13867c478bd9Sstevel@tonic-gate 	v = handle->rh_value;
13877c478bd9Sstevel@tonic-gate 
13887c478bd9Sstevel@tonic-gate 	handle->rh_iter = NULL;
13897c478bd9Sstevel@tonic-gate 	handle->rh_scope = NULL;
13907c478bd9Sstevel@tonic-gate 	handle->rh_service = NULL;
13917c478bd9Sstevel@tonic-gate 	handle->rh_instance = NULL;
13927c478bd9Sstevel@tonic-gate 	handle->rh_snapshot = NULL;
13937c478bd9Sstevel@tonic-gate 	handle->rh_snaplvl = NULL;
13947c478bd9Sstevel@tonic-gate 	handle->rh_pg = NULL;
13957c478bd9Sstevel@tonic-gate 	handle->rh_property = NULL;
13967c478bd9Sstevel@tonic-gate 	handle->rh_value = NULL;
13977c478bd9Sstevel@tonic-gate 
13987c478bd9Sstevel@tonic-gate 	if (iter != NULL)
13997c478bd9Sstevel@tonic-gate 		scf_iter_destroy(iter);
14007c478bd9Sstevel@tonic-gate 	if (sc != NULL)
14017c478bd9Sstevel@tonic-gate 		scf_scope_destroy(sc);
14027c478bd9Sstevel@tonic-gate 	if (svc != NULL)
14037c478bd9Sstevel@tonic-gate 		scf_service_destroy(svc);
14047c478bd9Sstevel@tonic-gate 	if (inst != NULL)
14057c478bd9Sstevel@tonic-gate 		scf_instance_destroy(inst);
14067c478bd9Sstevel@tonic-gate 	if (snap != NULL)
14077c478bd9Sstevel@tonic-gate 		scf_snapshot_destroy(snap);
14087c478bd9Sstevel@tonic-gate 	if (snaplvl != NULL)
14097c478bd9Sstevel@tonic-gate 		scf_snaplevel_destroy(snaplvl);
14107c478bd9Sstevel@tonic-gate 	if (pg != NULL)
14117c478bd9Sstevel@tonic-gate 		scf_pg_destroy(pg);
14127c478bd9Sstevel@tonic-gate 	if (prop != NULL)
14137c478bd9Sstevel@tonic-gate 		scf_property_destroy(prop);
14147c478bd9Sstevel@tonic-gate 	if (v != NULL)
14157c478bd9Sstevel@tonic-gate 		scf_value_destroy(v);
14167c478bd9Sstevel@tonic-gate 
14177c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&handle->rh_lock);
14187c478bd9Sstevel@tonic-gate 
14197c478bd9Sstevel@tonic-gate 	/* there should be no outstanding children at this point */
14207c478bd9Sstevel@tonic-gate 	assert(handle->rh_extrefs == 0);
14217c478bd9Sstevel@tonic-gate 	assert(handle->rh_intrefs == 0);
14227c478bd9Sstevel@tonic-gate 	assert(handle->rh_values == 0);
14237c478bd9Sstevel@tonic-gate 	assert(handle->rh_entries == 0);
14247c478bd9Sstevel@tonic-gate 	assert(uu_list_numnodes(handle->rh_dataels) == 0);
14257c478bd9Sstevel@tonic-gate 	assert(uu_list_numnodes(handle->rh_iters) == 0);
14267c478bd9Sstevel@tonic-gate 
14277c478bd9Sstevel@tonic-gate 	uu_list_destroy(handle->rh_dataels);
14287c478bd9Sstevel@tonic-gate 	uu_list_destroy(handle->rh_iters);
14297c478bd9Sstevel@tonic-gate 	handle->rh_dataels = NULL;
14307c478bd9Sstevel@tonic-gate 	handle->rh_iters = NULL;
14317c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&handle->rh_lock);
14327c478bd9Sstevel@tonic-gate 
14337c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_destroy(&handle->rh_lock);
14347c478bd9Sstevel@tonic-gate 
14357c478bd9Sstevel@tonic-gate 	uu_free(handle);
14367c478bd9Sstevel@tonic-gate }
14377c478bd9Sstevel@tonic-gate 
14387c478bd9Sstevel@tonic-gate void
scf_handle_destroy(scf_handle_t * handle)14397c478bd9Sstevel@tonic-gate scf_handle_destroy(scf_handle_t *handle)
14407c478bd9Sstevel@tonic-gate {
14417c478bd9Sstevel@tonic-gate 	if (handle == NULL)
14427c478bd9Sstevel@tonic-gate 		return;
14437c478bd9Sstevel@tonic-gate 
14447c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&handle->rh_lock);
14457c478bd9Sstevel@tonic-gate 	if (handle->rh_flags & HANDLE_DEAD) {
14467c478bd9Sstevel@tonic-gate 		/*
14477c478bd9Sstevel@tonic-gate 		 * This is an error (you are not allowed to reference the
14487c478bd9Sstevel@tonic-gate 		 * handle after it is destroyed), but we can't report it.
14497c478bd9Sstevel@tonic-gate 		 */
14507c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&handle->rh_lock);
14517c478bd9Sstevel@tonic-gate 		return;
14527c478bd9Sstevel@tonic-gate 	}
14537c478bd9Sstevel@tonic-gate 	handle->rh_flags |= HANDLE_DEAD;
14547c478bd9Sstevel@tonic-gate 	(void) handle_unbind_unlocked(handle);
14557c478bd9Sstevel@tonic-gate 	handle_unrefed(handle);
14567c478bd9Sstevel@tonic-gate }
14577c478bd9Sstevel@tonic-gate 
14587c478bd9Sstevel@tonic-gate ssize_t
scf_myname(scf_handle_t * h,char * out,size_t len)14597c478bd9Sstevel@tonic-gate scf_myname(scf_handle_t *h, char *out, size_t len)
14607c478bd9Sstevel@tonic-gate {
14617c478bd9Sstevel@tonic-gate 	char *cp;
14627c478bd9Sstevel@tonic-gate 
14637c478bd9Sstevel@tonic-gate 	if (!handle_has_server(h))
14647c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN));
14657c478bd9Sstevel@tonic-gate 
14667c478bd9Sstevel@tonic-gate 	cp = getenv("SMF_FMRI");
14677c478bd9Sstevel@tonic-gate 	if (cp == NULL)
14687c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_NOT_SET));
14697c478bd9Sstevel@tonic-gate 
14707c478bd9Sstevel@tonic-gate 	return (strlcpy(out, cp, len));
14717c478bd9Sstevel@tonic-gate }
14727c478bd9Sstevel@tonic-gate 
14737c478bd9Sstevel@tonic-gate static uint32_t
handle_alloc_entityid(scf_handle_t * h)14748918dff3Sjwadams handle_alloc_entityid(scf_handle_t *h)
14757c478bd9Sstevel@tonic-gate {
14768918dff3Sjwadams 	uint32_t nextid;
14778918dff3Sjwadams 
14788918dff3Sjwadams 	assert(MUTEX_HELD(&h->rh_lock));
14798918dff3Sjwadams 
14808918dff3Sjwadams 	if (uu_list_numnodes(h->rh_dataels) == UINT32_MAX)
14818918dff3Sjwadams 		return (0);		/* no ids available */
14828918dff3Sjwadams 
14838918dff3Sjwadams 	/*
14848918dff3Sjwadams 	 * The following loop assumes that there are not a huge number of
14858918dff3Sjwadams 	 * outstanding entities when we've wrapped.  If that ends up not
14868918dff3Sjwadams 	 * being the case, the O(N^2) nature of this search will hurt a lot,
14878918dff3Sjwadams 	 * and the data structure should be switched to an AVL tree.
14888918dff3Sjwadams 	 */
14898918dff3Sjwadams 	nextid = h->rh_nextentity + 1;
14908918dff3Sjwadams 	for (;;) {
14918918dff3Sjwadams 		scf_datael_t *cur;
14928918dff3Sjwadams 
14938918dff3Sjwadams 		if (nextid == 0) {
14948918dff3Sjwadams 			nextid++;
14958918dff3Sjwadams 			h->rh_flags |= HANDLE_WRAPPED_ENTITY;
14968918dff3Sjwadams 		}
14978918dff3Sjwadams 		if (!(h->rh_flags & HANDLE_WRAPPED_ENTITY))
14988918dff3Sjwadams 			break;
14998918dff3Sjwadams 
15008918dff3Sjwadams 		cur = uu_list_find(h->rh_dataels, NULL, &nextid, NULL);
15018918dff3Sjwadams 		if (cur == NULL)
15028918dff3Sjwadams 			break;		/* not in use */
15038918dff3Sjwadams 
15048918dff3Sjwadams 		if (nextid == h->rh_nextentity)
15058918dff3Sjwadams 			return (0);	/* wrapped around; no ids available */
15068918dff3Sjwadams 		nextid++;
15078918dff3Sjwadams 	}
15088918dff3Sjwadams 
15098918dff3Sjwadams 	h->rh_nextentity = nextid;
15108918dff3Sjwadams 	return (nextid);
15117c478bd9Sstevel@tonic-gate }
15127c478bd9Sstevel@tonic-gate 
15137c478bd9Sstevel@tonic-gate static uint32_t
handle_alloc_iterid(scf_handle_t * h)15148918dff3Sjwadams handle_alloc_iterid(scf_handle_t *h)
15157c478bd9Sstevel@tonic-gate {
15168918dff3Sjwadams 	uint32_t nextid;
15178918dff3Sjwadams 
15188918dff3Sjwadams 	assert(MUTEX_HELD(&h->rh_lock));
15198918dff3Sjwadams 
15208918dff3Sjwadams 	if (uu_list_numnodes(h->rh_iters) == UINT32_MAX)
15218918dff3Sjwadams 		return (0);		/* no ids available */
15228918dff3Sjwadams 
15238918dff3Sjwadams 	/* see the comment in handle_alloc_entityid */
15248918dff3Sjwadams 	nextid = h->rh_nextiter + 1;
15258918dff3Sjwadams 	for (;;) {
15268918dff3Sjwadams 		scf_iter_t *cur;
15278918dff3Sjwadams 
15288918dff3Sjwadams 		if (nextid == 0) {
15298918dff3Sjwadams 			nextid++;
15308918dff3Sjwadams 			h->rh_flags |= HANDLE_WRAPPED_ITER;
15318918dff3Sjwadams 		}
15328918dff3Sjwadams 		if (!(h->rh_flags & HANDLE_WRAPPED_ITER))
15338918dff3Sjwadams 			break;			/* not yet wrapped */
15348918dff3Sjwadams 
15358918dff3Sjwadams 		cur = uu_list_find(h->rh_iters, NULL, &nextid, NULL);
15368918dff3Sjwadams 		if (cur == NULL)
15378918dff3Sjwadams 			break;		/* not in use */
15388918dff3Sjwadams 
15398918dff3Sjwadams 		if (nextid == h->rh_nextiter)
15408918dff3Sjwadams 			return (0);	/* wrapped around; no ids available */
15418918dff3Sjwadams 		nextid++;
15428918dff3Sjwadams 	}
15438918dff3Sjwadams 
15448918dff3Sjwadams 	h->rh_nextiter = nextid;
15458918dff3Sjwadams 	return (nextid);
15467c478bd9Sstevel@tonic-gate }
15477c478bd9Sstevel@tonic-gate 
15487c478bd9Sstevel@tonic-gate static uint32_t
handle_next_changeid(scf_handle_t * handle)15498918dff3Sjwadams handle_next_changeid(scf_handle_t *handle)
15507c478bd9Sstevel@tonic-gate {
15518918dff3Sjwadams 	uint32_t nextid;
15528918dff3Sjwadams 
15537c478bd9Sstevel@tonic-gate 	assert(MUTEX_HELD(&handle->rh_lock));
15548918dff3Sjwadams 
15558918dff3Sjwadams 	nextid = ++handle->rh_nextchangeid;
15568918dff3Sjwadams 	if (nextid == 0)
15578918dff3Sjwadams 		nextid = ++handle->rh_nextchangeid;
15588918dff3Sjwadams 	return (nextid);
15597c478bd9Sstevel@tonic-gate }
15607c478bd9Sstevel@tonic-gate 
15617c478bd9Sstevel@tonic-gate /*
15627c478bd9Sstevel@tonic-gate  * Fails with
15637c478bd9Sstevel@tonic-gate  *   _INVALID_ARGUMENT - h is NULL
15647c478bd9Sstevel@tonic-gate  *   _HANDLE_DESTROYED
15657c478bd9Sstevel@tonic-gate  *   _INTERNAL - server response too big
15667c478bd9Sstevel@tonic-gate  *		 entity already set up with different type
15677c478bd9Sstevel@tonic-gate  *   _NO_RESOURCES
15687c478bd9Sstevel@tonic-gate  */
15697c478bd9Sstevel@tonic-gate static int
datael_init(scf_datael_t * dp,scf_handle_t * h,uint32_t type)15707c478bd9Sstevel@tonic-gate datael_init(scf_datael_t *dp, scf_handle_t *h, uint32_t type)
15717c478bd9Sstevel@tonic-gate {
15727c478bd9Sstevel@tonic-gate 	int ret;
15737c478bd9Sstevel@tonic-gate 
15747c478bd9Sstevel@tonic-gate 	if (h == NULL)
15757c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
15767c478bd9Sstevel@tonic-gate 
15777c478bd9Sstevel@tonic-gate 	uu_list_node_init(dp, &dp->rd_node, datael_pool);
15787c478bd9Sstevel@tonic-gate 
15797c478bd9Sstevel@tonic-gate 	dp->rd_handle = h;
15807c478bd9Sstevel@tonic-gate 	dp->rd_type = type;
15817c478bd9Sstevel@tonic-gate 	dp->rd_reset = 0;
15827c478bd9Sstevel@tonic-gate 
15837c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
15847c478bd9Sstevel@tonic-gate 	if (h->rh_flags & HANDLE_DEAD) {
15857c478bd9Sstevel@tonic-gate 		/*
15867c478bd9Sstevel@tonic-gate 		 * we're in undefined territory (the user cannot use a handle
15877c478bd9Sstevel@tonic-gate 		 * directly after it has been destroyed), but we don't want
15887c478bd9Sstevel@tonic-gate 		 * to allow any new references to happen, so we fail here.
15897c478bd9Sstevel@tonic-gate 		 */
15907c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
15917c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED));
15927c478bd9Sstevel@tonic-gate 	}
15937c478bd9Sstevel@tonic-gate 	dp->rd_entity = handle_alloc_entityid(h);
15948918dff3Sjwadams 	if (dp->rd_entity == 0) {
15958918dff3Sjwadams 		(void) pthread_mutex_unlock(&h->rh_lock);
15968918dff3Sjwadams 		uu_list_node_fini(dp, &dp->rd_node, datael_pool);
15978918dff3Sjwadams 		return (scf_set_error(SCF_ERROR_NO_MEMORY));
15988918dff3Sjwadams 	}
15997c478bd9Sstevel@tonic-gate 
16007c478bd9Sstevel@tonic-gate 	ret = datael_attach(dp);
16017c478bd9Sstevel@tonic-gate 	if (ret == 0) {
16027c478bd9Sstevel@tonic-gate 		(void) uu_list_insert_before(h->rh_dataels, NULL, dp);
16037c478bd9Sstevel@tonic-gate 		h->rh_extrefs++;
16047c478bd9Sstevel@tonic-gate 	} else {
16057c478bd9Sstevel@tonic-gate 		uu_list_node_fini(dp, &dp->rd_node, datael_pool);
16067c478bd9Sstevel@tonic-gate 	}
16077c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
16087c478bd9Sstevel@tonic-gate 
16097c478bd9Sstevel@tonic-gate 	return (ret);
16107c478bd9Sstevel@tonic-gate }
16117c478bd9Sstevel@tonic-gate 
16127c478bd9Sstevel@tonic-gate static void
datael_destroy(scf_datael_t * dp)16137c478bd9Sstevel@tonic-gate datael_destroy(scf_datael_t *dp)
16147c478bd9Sstevel@tonic-gate {
16157c478bd9Sstevel@tonic-gate 	scf_handle_t *h = dp->rd_handle;
16167c478bd9Sstevel@tonic-gate 
16177c478bd9Sstevel@tonic-gate 	struct rep_protocol_entity_teardown request;
16187c478bd9Sstevel@tonic-gate 	rep_protocol_response_t response;
16197c478bd9Sstevel@tonic-gate 
16207c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
16217c478bd9Sstevel@tonic-gate 	uu_list_remove(h->rh_dataels, dp);
16227c478bd9Sstevel@tonic-gate 	--h->rh_extrefs;
16237c478bd9Sstevel@tonic-gate 
16247c478bd9Sstevel@tonic-gate 	if (handle_is_bound(h)) {
16257c478bd9Sstevel@tonic-gate 		request.rpr_request = REP_PROTOCOL_ENTITY_TEARDOWN;
16267c478bd9Sstevel@tonic-gate 		request.rpr_entityid = dp->rd_entity;
16277c478bd9Sstevel@tonic-gate 
16287c478bd9Sstevel@tonic-gate 		(void) make_door_call(h, &request, sizeof (request),
16297c478bd9Sstevel@tonic-gate 		    &response, sizeof (response));
16307c478bd9Sstevel@tonic-gate 	}
16317c478bd9Sstevel@tonic-gate 	handle_unrefed(h);			/* drops h->rh_lock */
16327c478bd9Sstevel@tonic-gate 
16337c478bd9Sstevel@tonic-gate 	dp->rd_handle = NULL;
16347c478bd9Sstevel@tonic-gate }
16357c478bd9Sstevel@tonic-gate 
16367c478bd9Sstevel@tonic-gate static scf_handle_t *
datael_handle(const scf_datael_t * dp)16377c478bd9Sstevel@tonic-gate datael_handle(const scf_datael_t *dp)
16387c478bd9Sstevel@tonic-gate {
16397c478bd9Sstevel@tonic-gate 	return (handle_get(dp->rd_handle));
16407c478bd9Sstevel@tonic-gate }
16417c478bd9Sstevel@tonic-gate 
16427c478bd9Sstevel@tonic-gate /*
16437c478bd9Sstevel@tonic-gate  * We delay ENTITY_RESETs until right before the entity is used.  By doing
16447c478bd9Sstevel@tonic-gate  * them lazily, we remove quite a few unnecessary calls.
16457c478bd9Sstevel@tonic-gate  */
16467c478bd9Sstevel@tonic-gate static void
datael_do_reset_locked(scf_datael_t * dp)16477c478bd9Sstevel@tonic-gate datael_do_reset_locked(scf_datael_t *dp)
16487c478bd9Sstevel@tonic-gate {
16497c478bd9Sstevel@tonic-gate 	scf_handle_t *h = dp->rd_handle;
16507c478bd9Sstevel@tonic-gate 
16517c478bd9Sstevel@tonic-gate 	struct rep_protocol_entity_reset request;
16527c478bd9Sstevel@tonic-gate 	rep_protocol_response_t response;
16537c478bd9Sstevel@tonic-gate 
16547c478bd9Sstevel@tonic-gate 	assert(MUTEX_HELD(&h->rh_lock));
16557c478bd9Sstevel@tonic-gate 
16567c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ENTITY_RESET;
16577c478bd9Sstevel@tonic-gate 	request.rpr_entityid = dp->rd_entity;
16587c478bd9Sstevel@tonic-gate 
16597c478bd9Sstevel@tonic-gate 	(void) make_door_call(h, &request, sizeof (request),
16607c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
16617c478bd9Sstevel@tonic-gate 
16627c478bd9Sstevel@tonic-gate 	dp->rd_reset = 0;
16637c478bd9Sstevel@tonic-gate }
16647c478bd9Sstevel@tonic-gate 
16657c478bd9Sstevel@tonic-gate static void
datael_reset_locked(scf_datael_t * dp)16667c478bd9Sstevel@tonic-gate datael_reset_locked(scf_datael_t *dp)
16677c478bd9Sstevel@tonic-gate {
16687c478bd9Sstevel@tonic-gate 	assert(MUTEX_HELD(&dp->rd_handle->rh_lock));
16697c478bd9Sstevel@tonic-gate 	dp->rd_reset = 1;
16707c478bd9Sstevel@tonic-gate }
16717c478bd9Sstevel@tonic-gate 
16727c478bd9Sstevel@tonic-gate static void
datael_reset(scf_datael_t * dp)16737c478bd9Sstevel@tonic-gate datael_reset(scf_datael_t *dp)
16747c478bd9Sstevel@tonic-gate {
16757c478bd9Sstevel@tonic-gate 	scf_handle_t *h = dp->rd_handle;
16767c478bd9Sstevel@tonic-gate 
16777c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
16787c478bd9Sstevel@tonic-gate 	dp->rd_reset = 1;
16797c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
16807c478bd9Sstevel@tonic-gate }
16817c478bd9Sstevel@tonic-gate 
16827c478bd9Sstevel@tonic-gate static void
datael_finish_reset(const scf_datael_t * dp_arg)16837c478bd9Sstevel@tonic-gate datael_finish_reset(const scf_datael_t *dp_arg)
16847c478bd9Sstevel@tonic-gate {
16857c478bd9Sstevel@tonic-gate 	scf_datael_t *dp = (scf_datael_t *)dp_arg;
16867c478bd9Sstevel@tonic-gate 
16877c478bd9Sstevel@tonic-gate 	if (dp->rd_reset)
16887c478bd9Sstevel@tonic-gate 		datael_do_reset_locked(dp);
16897c478bd9Sstevel@tonic-gate }
16907c478bd9Sstevel@tonic-gate 
16917c478bd9Sstevel@tonic-gate /*
16927c478bd9Sstevel@tonic-gate  * Fails with _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response too
16937c478bd9Sstevel@tonic-gate  * big, bad entity id, request not applicable to entity, name too long for
16947c478bd9Sstevel@tonic-gate  * buffer), _NOT_SET, _DELETED, or _CONSTRAINT_VIOLATED (snaplevel is not of an
16957c478bd9Sstevel@tonic-gate  * instance).
16967c478bd9Sstevel@tonic-gate  */
16977c478bd9Sstevel@tonic-gate static ssize_t
datael_get_name(const scf_datael_t * dp,char * buf,size_t size,uint32_t type)16987c478bd9Sstevel@tonic-gate datael_get_name(const scf_datael_t *dp, char *buf, size_t size, uint32_t type)
16997c478bd9Sstevel@tonic-gate {
17007c478bd9Sstevel@tonic-gate 	scf_handle_t *h = dp->rd_handle;
17017c478bd9Sstevel@tonic-gate 
17027c478bd9Sstevel@tonic-gate 	struct rep_protocol_entity_name request;
17037c478bd9Sstevel@tonic-gate 	struct rep_protocol_name_response response;
17047c478bd9Sstevel@tonic-gate 	ssize_t r;
17057c478bd9Sstevel@tonic-gate 
17067c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
17077c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ENTITY_NAME;
17087c478bd9Sstevel@tonic-gate 	request.rpr_entityid = dp->rd_entity;
17097c478bd9Sstevel@tonic-gate 	request.rpr_answertype = type;
17107c478bd9Sstevel@tonic-gate 
17117c478bd9Sstevel@tonic-gate 	datael_finish_reset(dp);
17127c478bd9Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
17137c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
17147c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
17157c478bd9Sstevel@tonic-gate 
17167c478bd9Sstevel@tonic-gate 	if (r < 0)
17177c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
17187c478bd9Sstevel@tonic-gate 
17197c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
17207c478bd9Sstevel@tonic-gate 		assert(response.rpr_response != REP_PROTOCOL_FAIL_BAD_REQUEST);
17217c478bd9Sstevel@tonic-gate 		if (response.rpr_response == REP_PROTOCOL_FAIL_NOT_FOUND)
17227c478bd9Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED));
17237c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
17247c478bd9Sstevel@tonic-gate 	}
17257c478bd9Sstevel@tonic-gate 	return (strlcpy(buf, response.rpr_name, size));
17267c478bd9Sstevel@tonic-gate }
17277c478bd9Sstevel@tonic-gate 
17287c478bd9Sstevel@tonic-gate /*
17297c478bd9Sstevel@tonic-gate  * Fails with _HANDLE_MISMATCH, _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL
17307c478bd9Sstevel@tonic-gate  * (server response too big, bad element id), _EXISTS (elements have same id),
17317c478bd9Sstevel@tonic-gate  * _NOT_SET, _DELETED, _CONSTRAINT_VIOLATED, _NOT_FOUND (scope has no parent),
17327c478bd9Sstevel@tonic-gate  * or _SUCCESS.
17337c478bd9Sstevel@tonic-gate  */
17347c478bd9Sstevel@tonic-gate static int
datael_get_parent(const scf_datael_t * dp,scf_datael_t * pp)17357c478bd9Sstevel@tonic-gate datael_get_parent(const scf_datael_t *dp, scf_datael_t *pp)
17367c478bd9Sstevel@tonic-gate {
17377c478bd9Sstevel@tonic-gate 	scf_handle_t *h = dp->rd_handle;
17387c478bd9Sstevel@tonic-gate 
17397c478bd9Sstevel@tonic-gate 	struct rep_protocol_entity_parent request;
17407c478bd9Sstevel@tonic-gate 	struct rep_protocol_response response;
17417c478bd9Sstevel@tonic-gate 
17427c478bd9Sstevel@tonic-gate 	ssize_t r;
17437c478bd9Sstevel@tonic-gate 
17447c478bd9Sstevel@tonic-gate 	if (h != pp->rd_handle)
17457c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
17467c478bd9Sstevel@tonic-gate 
17477c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
17487c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ENTITY_GET_PARENT;
17497c478bd9Sstevel@tonic-gate 	request.rpr_entityid = dp->rd_entity;
17507c478bd9Sstevel@tonic-gate 	request.rpr_outid = pp->rd_entity;
17517c478bd9Sstevel@tonic-gate 
17527c478bd9Sstevel@tonic-gate 	datael_finish_reset(dp);
17537c478bd9Sstevel@tonic-gate 	datael_finish_reset(pp);
17547c478bd9Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
17557c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
17567c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
17577c478bd9Sstevel@tonic-gate 
17587c478bd9Sstevel@tonic-gate 	if (r < 0)
17597c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
17607c478bd9Sstevel@tonic-gate 
17617c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
17627c478bd9Sstevel@tonic-gate 		if (response.rpr_response == REP_PROTOCOL_FAIL_TYPE_MISMATCH)
17637c478bd9Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED));
17647c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
17657c478bd9Sstevel@tonic-gate 	}
17667c478bd9Sstevel@tonic-gate 
17677c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
17687c478bd9Sstevel@tonic-gate }
17697c478bd9Sstevel@tonic-gate 
17707c478bd9Sstevel@tonic-gate /*
17717c478bd9Sstevel@tonic-gate  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT (out does not have type type,
17727c478bd9Sstevel@tonic-gate  * name is invalid), _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response
17737c478bd9Sstevel@tonic-gate  * too big, bad id, iter already exists, element cannot have children of type,
17747c478bd9Sstevel@tonic-gate  * type is invalid, iter was reset, sequence was bad, iter walks values, iter
17757c478bd9Sstevel@tonic-gate  * does not walk type entities), _NOT_SET, _DELETED, _NO_RESOURCES,
177676cf44abSjeanm  * _BACKEND_ACCESS, _NOT_FOUND.
17777c478bd9Sstevel@tonic-gate  */
17787c478bd9Sstevel@tonic-gate static int
datael_get_child_composed_locked(const scf_datael_t * dp,const char * name,uint32_t type,scf_datael_t * out,scf_iter_t * iter)17797c478bd9Sstevel@tonic-gate datael_get_child_composed_locked(const scf_datael_t *dp, const char *name,
17807c478bd9Sstevel@tonic-gate     uint32_t type, scf_datael_t *out, scf_iter_t *iter)
17817c478bd9Sstevel@tonic-gate {
17827c478bd9Sstevel@tonic-gate 	struct rep_protocol_iter_start request;
17837c478bd9Sstevel@tonic-gate 	struct rep_protocol_iter_read read_request;
17847c478bd9Sstevel@tonic-gate 	struct rep_protocol_response response;
17857c478bd9Sstevel@tonic-gate 
17867c478bd9Sstevel@tonic-gate 	scf_handle_t *h = dp->rd_handle;
17877c478bd9Sstevel@tonic-gate 	ssize_t r;
17887c478bd9Sstevel@tonic-gate 
17897c478bd9Sstevel@tonic-gate 	if (h != out->rd_handle)
17907c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
17917c478bd9Sstevel@tonic-gate 
17927c478bd9Sstevel@tonic-gate 	if (out->rd_type != type)
17937c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
17947c478bd9Sstevel@tonic-gate 
17957c478bd9Sstevel@tonic-gate 	assert(MUTEX_HELD(&h->rh_lock));
17967c478bd9Sstevel@tonic-gate 	assert(iter != NULL);
17977c478bd9Sstevel@tonic-gate 
17987c478bd9Sstevel@tonic-gate 	scf_iter_reset_locked(iter);
17997c478bd9Sstevel@tonic-gate 	iter->iter_type = type;
18007c478bd9Sstevel@tonic-gate 
18017c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ITER_START;
18027c478bd9Sstevel@tonic-gate 	request.rpr_iterid = iter->iter_id;
18037c478bd9Sstevel@tonic-gate 	request.rpr_entity = dp->rd_entity;
18047c478bd9Sstevel@tonic-gate 	request.rpr_itertype = type;
18057c478bd9Sstevel@tonic-gate 	request.rpr_flags = RP_ITER_START_EXACT | RP_ITER_START_COMPOSED;
18067c478bd9Sstevel@tonic-gate 
18077c478bd9Sstevel@tonic-gate 	if (name == NULL || strlcpy(request.rpr_pattern, name,
18087c478bd9Sstevel@tonic-gate 	    sizeof (request.rpr_pattern)) >= sizeof (request.rpr_pattern)) {
18097c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
18107c478bd9Sstevel@tonic-gate 	}
18117c478bd9Sstevel@tonic-gate 
18127c478bd9Sstevel@tonic-gate 	datael_finish_reset(dp);
18137c478bd9Sstevel@tonic-gate 	datael_finish_reset(out);
18147c478bd9Sstevel@tonic-gate 
18157c478bd9Sstevel@tonic-gate 	/*
18167c478bd9Sstevel@tonic-gate 	 * We hold the handle lock across both door calls, so that they
18177c478bd9Sstevel@tonic-gate 	 * appear atomic.
18187c478bd9Sstevel@tonic-gate 	 */
18197c478bd9Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
18207c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
18217c478bd9Sstevel@tonic-gate 
18227c478bd9Sstevel@tonic-gate 	if (r < 0)
18237c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
18247c478bd9Sstevel@tonic-gate 
18257c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
18267c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
18277c478bd9Sstevel@tonic-gate 
18287c478bd9Sstevel@tonic-gate 	iter->iter_sequence++;
18297c478bd9Sstevel@tonic-gate 
18307c478bd9Sstevel@tonic-gate 	read_request.rpr_request = REP_PROTOCOL_ITER_READ;
18317c478bd9Sstevel@tonic-gate 	read_request.rpr_iterid = iter->iter_id;
18327c478bd9Sstevel@tonic-gate 	read_request.rpr_sequence = iter->iter_sequence;
18337c478bd9Sstevel@tonic-gate 	read_request.rpr_entityid = out->rd_entity;
18347c478bd9Sstevel@tonic-gate 
18357c478bd9Sstevel@tonic-gate 	r = make_door_call(h, &read_request, sizeof (read_request),
18367c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
18377c478bd9Sstevel@tonic-gate 
18387c478bd9Sstevel@tonic-gate 	scf_iter_reset_locked(iter);
18397c478bd9Sstevel@tonic-gate 
18407c478bd9Sstevel@tonic-gate 	if (r < 0)
18417c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
18427c478bd9Sstevel@tonic-gate 
18437c478bd9Sstevel@tonic-gate 	if (response.rpr_response == REP_PROTOCOL_DONE) {
18447c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_NOT_FOUND));
18457c478bd9Sstevel@tonic-gate 	}
18467c478bd9Sstevel@tonic-gate 
18477c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
18487c478bd9Sstevel@tonic-gate 		if (response.rpr_response == REP_PROTOCOL_FAIL_NOT_SET ||
18497c478bd9Sstevel@tonic-gate 		    response.rpr_response == REP_PROTOCOL_FAIL_BAD_REQUEST)
18507c478bd9Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_INTERNAL));
18517c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
18527c478bd9Sstevel@tonic-gate 	}
18537c478bd9Sstevel@tonic-gate 
18547c478bd9Sstevel@tonic-gate 	return (0);
18557c478bd9Sstevel@tonic-gate }
18567c478bd9Sstevel@tonic-gate 
18577c478bd9Sstevel@tonic-gate /*
18587c478bd9Sstevel@tonic-gate  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT (out does not have type type,
18597c478bd9Sstevel@tonic-gate  * name is invalid), _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response
18607c478bd9Sstevel@tonic-gate  * too big, bad id, element cannot have children of type, type is invalid),
18617c478bd9Sstevel@tonic-gate  * _NOT_SET, _DELETED, _NO_RESOURCES, _BACKEND_ACCESS.
18627c478bd9Sstevel@tonic-gate  */
18637c478bd9Sstevel@tonic-gate static int
datael_get_child_locked(const scf_datael_t * dp,const char * name,uint32_t type,scf_datael_t * out)18647c478bd9Sstevel@tonic-gate datael_get_child_locked(const scf_datael_t *dp, const char *name,
18657c478bd9Sstevel@tonic-gate     uint32_t type, scf_datael_t *out)
18667c478bd9Sstevel@tonic-gate {
18677c478bd9Sstevel@tonic-gate 	struct rep_protocol_entity_get_child request;
18687c478bd9Sstevel@tonic-gate 	struct rep_protocol_response response;
18697c478bd9Sstevel@tonic-gate 
18707c478bd9Sstevel@tonic-gate 	scf_handle_t *h = dp->rd_handle;
18717c478bd9Sstevel@tonic-gate 	ssize_t r;
18727c478bd9Sstevel@tonic-gate 
18737c478bd9Sstevel@tonic-gate 	if (h != out->rd_handle)
18747c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
18757c478bd9Sstevel@tonic-gate 
18767c478bd9Sstevel@tonic-gate 	if (out->rd_type != type)
18777c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
18787c478bd9Sstevel@tonic-gate 
18797c478bd9Sstevel@tonic-gate 	assert(MUTEX_HELD(&h->rh_lock));
18807c478bd9Sstevel@tonic-gate 
18817c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ENTITY_GET_CHILD;
18827c478bd9Sstevel@tonic-gate 	request.rpr_entityid = dp->rd_entity;
18837c478bd9Sstevel@tonic-gate 	request.rpr_childid = out->rd_entity;
18847c478bd9Sstevel@tonic-gate 
18857c478bd9Sstevel@tonic-gate 	if (name == NULL || strlcpy(request.rpr_name, name,
18867c478bd9Sstevel@tonic-gate 	    sizeof (request.rpr_name)) >= sizeof (request.rpr_name)) {
18877c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
18887c478bd9Sstevel@tonic-gate 	}
18897c478bd9Sstevel@tonic-gate 
18907c478bd9Sstevel@tonic-gate 	datael_finish_reset(dp);
18917c478bd9Sstevel@tonic-gate 	datael_finish_reset(out);
18927c478bd9Sstevel@tonic-gate 
18937c478bd9Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
18947c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
18957c478bd9Sstevel@tonic-gate 
18967c478bd9Sstevel@tonic-gate 	if (r < 0)
18977c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
18987c478bd9Sstevel@tonic-gate 
18997c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
19007c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
19017c478bd9Sstevel@tonic-gate 	return (0);
19027c478bd9Sstevel@tonic-gate }
19037c478bd9Sstevel@tonic-gate 
190476cf44abSjeanm /*
190576cf44abSjeanm  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT (out does not have type type,
190676cf44abSjeanm  * name is invalid), _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response
190776cf44abSjeanm  * too big, bad id, iter already exists, element cannot have children of type,
190876cf44abSjeanm  * type is invalid, iter was reset, sequence was bad, iter walks values, iter
190976cf44abSjeanm  * does not walk type entities), _NOT_SET, _DELETED, _NO_RESOURCES,
191076cf44abSjeanm  * _BACKEND_ACCESS, _NOT_FOUND.
191176cf44abSjeanm  */
19127c478bd9Sstevel@tonic-gate static int
datael_get_child(const scf_datael_t * dp,const char * name,uint32_t type,scf_datael_t * out,boolean_t composed)19137c478bd9Sstevel@tonic-gate datael_get_child(const scf_datael_t *dp, const char *name, uint32_t type,
19147c478bd9Sstevel@tonic-gate     scf_datael_t *out, boolean_t composed)
19157c478bd9Sstevel@tonic-gate {
19167c478bd9Sstevel@tonic-gate 	scf_handle_t *h = dp->rd_handle;
19177c478bd9Sstevel@tonic-gate 	uint32_t held = 0;
19187c478bd9Sstevel@tonic-gate 	int ret;
19197c478bd9Sstevel@tonic-gate 
19207c478bd9Sstevel@tonic-gate 	scf_iter_t *iter = NULL;
19217c478bd9Sstevel@tonic-gate 
19227c478bd9Sstevel@tonic-gate 	if (composed)
19237c478bd9Sstevel@tonic-gate 		iter = HANDLE_HOLD_ITER(h);
19247c478bd9Sstevel@tonic-gate 
19257c478bd9Sstevel@tonic-gate 	if (out == NULL) {
19267c478bd9Sstevel@tonic-gate 		switch (type) {
19277c478bd9Sstevel@tonic-gate 		case REP_PROTOCOL_ENTITY_SERVICE:
19287c478bd9Sstevel@tonic-gate 			out = &HANDLE_HOLD_SERVICE(h)->rd_d;
19297c478bd9Sstevel@tonic-gate 			held = RH_HOLD_SERVICE;
19307c478bd9Sstevel@tonic-gate 			break;
19317c478bd9Sstevel@tonic-gate 
19327c478bd9Sstevel@tonic-gate 		case REP_PROTOCOL_ENTITY_INSTANCE:
19337c478bd9Sstevel@tonic-gate 			out = &HANDLE_HOLD_INSTANCE(h)->rd_d;
19347c478bd9Sstevel@tonic-gate 			held = RH_HOLD_INSTANCE;
19357c478bd9Sstevel@tonic-gate 			break;
19367c478bd9Sstevel@tonic-gate 
19377c478bd9Sstevel@tonic-gate 		case REP_PROTOCOL_ENTITY_SNAPSHOT:
19387c478bd9Sstevel@tonic-gate 			out = &HANDLE_HOLD_SNAPSHOT(h)->rd_d;
19397c478bd9Sstevel@tonic-gate 			held = RH_HOLD_SNAPSHOT;
19407c478bd9Sstevel@tonic-gate 			break;
19417c478bd9Sstevel@tonic-gate 
19427c478bd9Sstevel@tonic-gate 		case REP_PROTOCOL_ENTITY_SNAPLEVEL:
19437c478bd9Sstevel@tonic-gate 			out = &HANDLE_HOLD_SNAPLVL(h)->rd_d;
19447c478bd9Sstevel@tonic-gate 			held = RH_HOLD_SNAPLVL;
19457c478bd9Sstevel@tonic-gate 			break;
19467c478bd9Sstevel@tonic-gate 
19477c478bd9Sstevel@tonic-gate 		case REP_PROTOCOL_ENTITY_PROPERTYGRP:
19487c478bd9Sstevel@tonic-gate 			out = &HANDLE_HOLD_PG(h)->rd_d;
19497c478bd9Sstevel@tonic-gate 			held = RH_HOLD_PG;
19507c478bd9Sstevel@tonic-gate 			break;
19517c478bd9Sstevel@tonic-gate 
19527c478bd9Sstevel@tonic-gate 		case REP_PROTOCOL_ENTITY_PROPERTY:
19537c478bd9Sstevel@tonic-gate 			out = &HANDLE_HOLD_PROPERTY(h)->rd_d;
19547c478bd9Sstevel@tonic-gate 			held = RH_HOLD_PROPERTY;
19557c478bd9Sstevel@tonic-gate 			break;
19567c478bd9Sstevel@tonic-gate 
19577c478bd9Sstevel@tonic-gate 		default:
19587c478bd9Sstevel@tonic-gate 			assert(0);
19597c478bd9Sstevel@tonic-gate 			abort();
19607c478bd9Sstevel@tonic-gate 		}
19617c478bd9Sstevel@tonic-gate 	}
19627c478bd9Sstevel@tonic-gate 
19637c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
19647c478bd9Sstevel@tonic-gate 	if (composed)
19657c478bd9Sstevel@tonic-gate 		ret = datael_get_child_composed_locked(dp, name, type, out,
19667c478bd9Sstevel@tonic-gate 		    iter);
19677c478bd9Sstevel@tonic-gate 	else
19687c478bd9Sstevel@tonic-gate 		ret = datael_get_child_locked(dp, name, type, out);
19697c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
19707c478bd9Sstevel@tonic-gate 
19717c478bd9Sstevel@tonic-gate 	if (composed)
19727c478bd9Sstevel@tonic-gate 		HANDLE_RELE_ITER(h);
19737c478bd9Sstevel@tonic-gate 
19747c478bd9Sstevel@tonic-gate 	if (held)
19757c478bd9Sstevel@tonic-gate 		handle_rele_subhandles(h, held);
19767c478bd9Sstevel@tonic-gate 
19777c478bd9Sstevel@tonic-gate 	return (ret);
19787c478bd9Sstevel@tonic-gate }
19797c478bd9Sstevel@tonic-gate 
19807c478bd9Sstevel@tonic-gate /*
19817c478bd9Sstevel@tonic-gate  * Fails with
19827c478bd9Sstevel@tonic-gate  *   _HANDLE_MISMATCH
19837c478bd9Sstevel@tonic-gate  *   _INVALID_ARGUMENT - name is too long
19847c478bd9Sstevel@tonic-gate  *			 invalid changeid
19857c478bd9Sstevel@tonic-gate  *			 name is invalid
19867c478bd9Sstevel@tonic-gate  *			 cannot create children for dp's type of node
19877c478bd9Sstevel@tonic-gate  *   _NOT_BOUND - handle is not bound
19887c478bd9Sstevel@tonic-gate  *   _CONNECTION_BROKEN - server is not reachable
19897c478bd9Sstevel@tonic-gate  *   _INTERNAL - server response too big
19907c478bd9Sstevel@tonic-gate  *		 dp or cp has unknown id
19917c478bd9Sstevel@tonic-gate  *		 type is _PROPERTYGRP
19927c478bd9Sstevel@tonic-gate  *		 type is invalid
19937c478bd9Sstevel@tonic-gate  *		 dp cannot have children of type type
19947c478bd9Sstevel@tonic-gate  *		 database is corrupt
19957c478bd9Sstevel@tonic-gate  *   _EXISTS - dp & cp have the same id
19967c478bd9Sstevel@tonic-gate  *   _EXISTS - child already exists
19977c478bd9Sstevel@tonic-gate  *   _DELETED - dp has been deleted
19987c478bd9Sstevel@tonic-gate  *   _NOT_SET - dp is reset
19997c478bd9Sstevel@tonic-gate  *   _NO_RESOURCES
20007c478bd9Sstevel@tonic-gate  *   _PERMISSION_DENIED
20017c478bd9Sstevel@tonic-gate  *   _BACKEND_ACCESS
20027c478bd9Sstevel@tonic-gate  *   _BACKEND_READONLY
20037c478bd9Sstevel@tonic-gate  */
20047c478bd9Sstevel@tonic-gate static int
datael_add_child(const scf_datael_t * dp,const char * name,uint32_t type,scf_datael_t * cp)20057c478bd9Sstevel@tonic-gate datael_add_child(const scf_datael_t *dp, const char *name, uint32_t type,
20067c478bd9Sstevel@tonic-gate     scf_datael_t *cp)
20077c478bd9Sstevel@tonic-gate {
20087c478bd9Sstevel@tonic-gate 	scf_handle_t *h = dp->rd_handle;
20097c478bd9Sstevel@tonic-gate 
20107c478bd9Sstevel@tonic-gate 	struct rep_protocol_entity_create_child request;
20117c478bd9Sstevel@tonic-gate 	struct rep_protocol_response response;
20127c478bd9Sstevel@tonic-gate 	ssize_t r;
20137c478bd9Sstevel@tonic-gate 	uint32_t held = 0;
20147c478bd9Sstevel@tonic-gate 
20157c478bd9Sstevel@tonic-gate 	if (cp == NULL) {
20167c478bd9Sstevel@tonic-gate 		switch (type) {
20177c478bd9Sstevel@tonic-gate 		case REP_PROTOCOL_ENTITY_SCOPE:
20187c478bd9Sstevel@tonic-gate 			cp = &HANDLE_HOLD_SCOPE(h)->rd_d;
20197c478bd9Sstevel@tonic-gate 			held = RH_HOLD_SCOPE;
20207c478bd9Sstevel@tonic-gate 			break;
20217c478bd9Sstevel@tonic-gate 		case REP_PROTOCOL_ENTITY_SERVICE:
20227c478bd9Sstevel@tonic-gate 			cp = &HANDLE_HOLD_SERVICE(h)->rd_d;
20237c478bd9Sstevel@tonic-gate 			held = RH_HOLD_SERVICE;
20247c478bd9Sstevel@tonic-gate 			break;
20257c478bd9Sstevel@tonic-gate 		case REP_PROTOCOL_ENTITY_INSTANCE:
20267c478bd9Sstevel@tonic-gate 			cp = &HANDLE_HOLD_INSTANCE(h)->rd_d;
20277c478bd9Sstevel@tonic-gate 			held = RH_HOLD_INSTANCE;
20287c478bd9Sstevel@tonic-gate 			break;
20297c478bd9Sstevel@tonic-gate 		case REP_PROTOCOL_ENTITY_SNAPSHOT:
20307c478bd9Sstevel@tonic-gate 		default:
20317c478bd9Sstevel@tonic-gate 			assert(0);
20327c478bd9Sstevel@tonic-gate 			abort();
20337c478bd9Sstevel@tonic-gate 		}
20347c478bd9Sstevel@tonic-gate 		assert(h == cp->rd_handle);
20357c478bd9Sstevel@tonic-gate 
20367c478bd9Sstevel@tonic-gate 	} else if (h != cp->rd_handle) {
20377c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
20387c478bd9Sstevel@tonic-gate 	}
20397c478bd9Sstevel@tonic-gate 
20407c478bd9Sstevel@tonic-gate 	if (strlcpy(request.rpr_name, name, sizeof (request.rpr_name)) >=
20417c478bd9Sstevel@tonic-gate 	    sizeof (request.rpr_name)) {
20427c478bd9Sstevel@tonic-gate 		r = scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
20437c478bd9Sstevel@tonic-gate 		goto err;
20447c478bd9Sstevel@tonic-gate 	}
20457c478bd9Sstevel@tonic-gate 
20467c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
20477c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ENTITY_CREATE_CHILD;
20487c478bd9Sstevel@tonic-gate 	request.rpr_entityid = dp->rd_entity;
20497c478bd9Sstevel@tonic-gate 	request.rpr_childtype = type;
20507c478bd9Sstevel@tonic-gate 	request.rpr_childid = cp->rd_entity;
20517c478bd9Sstevel@tonic-gate 
20527c478bd9Sstevel@tonic-gate 	datael_finish_reset(dp);
20538918dff3Sjwadams 	request.rpr_changeid = handle_next_changeid(h);
20547c478bd9Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
20557c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
20567c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
20577c478bd9Sstevel@tonic-gate 
20587c478bd9Sstevel@tonic-gate 	if (held)
20597c478bd9Sstevel@tonic-gate 		handle_rele_subhandles(h, held);
20607c478bd9Sstevel@tonic-gate 
20617c478bd9Sstevel@tonic-gate 	if (r < 0)
20627c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
20637c478bd9Sstevel@tonic-gate 
20647c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
20657c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
20667c478bd9Sstevel@tonic-gate 
20677c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
20687c478bd9Sstevel@tonic-gate 
20697c478bd9Sstevel@tonic-gate err:
20707c478bd9Sstevel@tonic-gate 	if (held)
20717c478bd9Sstevel@tonic-gate 		handle_rele_subhandles(h, held);
20727c478bd9Sstevel@tonic-gate 	return (r);
20737c478bd9Sstevel@tonic-gate }
20747c478bd9Sstevel@tonic-gate 
20757c478bd9Sstevel@tonic-gate static int
datael_add_pg(const scf_datael_t * dp,const char * name,const char * type,uint32_t flags,scf_datael_t * cp)20767c478bd9Sstevel@tonic-gate datael_add_pg(const scf_datael_t *dp, const char *name, const char *type,
20777c478bd9Sstevel@tonic-gate     uint32_t flags, scf_datael_t *cp)
20787c478bd9Sstevel@tonic-gate {
20797c478bd9Sstevel@tonic-gate 	scf_handle_t *h = dp->rd_handle;
20807c478bd9Sstevel@tonic-gate 
20817c478bd9Sstevel@tonic-gate 	struct rep_protocol_entity_create_pg request;
20827c478bd9Sstevel@tonic-gate 	struct rep_protocol_response response;
20837c478bd9Sstevel@tonic-gate 	ssize_t r;
20847c478bd9Sstevel@tonic-gate 
20857c478bd9Sstevel@tonic-gate 	int holding_els = 0;
20867c478bd9Sstevel@tonic-gate 
20877c478bd9Sstevel@tonic-gate 	if (cp == NULL) {
20887c478bd9Sstevel@tonic-gate 		holding_els = 1;
20897c478bd9Sstevel@tonic-gate 		cp = &HANDLE_HOLD_PG(h)->rd_d;
20907c478bd9Sstevel@tonic-gate 		assert(h == cp->rd_handle);
20917c478bd9Sstevel@tonic-gate 
20927c478bd9Sstevel@tonic-gate 	} else if (h != cp->rd_handle) {
20937c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
20947c478bd9Sstevel@tonic-gate 	}
20957c478bd9Sstevel@tonic-gate 
20967c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ENTITY_CREATE_PG;
20977c478bd9Sstevel@tonic-gate 
20987c478bd9Sstevel@tonic-gate 	if (name == NULL || strlcpy(request.rpr_name, name,
20997c478bd9Sstevel@tonic-gate 	    sizeof (request.rpr_name)) > sizeof (request.rpr_name)) {
21007c478bd9Sstevel@tonic-gate 		r = scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
21017c478bd9Sstevel@tonic-gate 		goto err;
21027c478bd9Sstevel@tonic-gate 	}
21037c478bd9Sstevel@tonic-gate 
21047c478bd9Sstevel@tonic-gate 	if (type == NULL || strlcpy(request.rpr_type, type,
21057c478bd9Sstevel@tonic-gate 	    sizeof (request.rpr_type)) > sizeof (request.rpr_type)) {
21067c478bd9Sstevel@tonic-gate 		r = scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
21077c478bd9Sstevel@tonic-gate 		goto err;
21087c478bd9Sstevel@tonic-gate 	}
21097c478bd9Sstevel@tonic-gate 
21107c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
21117c478bd9Sstevel@tonic-gate 	request.rpr_entityid = dp->rd_entity;
21127c478bd9Sstevel@tonic-gate 	request.rpr_childid = cp->rd_entity;
21137c478bd9Sstevel@tonic-gate 	request.rpr_flags = flags;
21147c478bd9Sstevel@tonic-gate 
21157c478bd9Sstevel@tonic-gate 	datael_finish_reset(dp);
21167c478bd9Sstevel@tonic-gate 	datael_finish_reset(cp);
21178918dff3Sjwadams 	request.rpr_changeid = handle_next_changeid(h);
21187c478bd9Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
21197c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
21207c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
21217c478bd9Sstevel@tonic-gate 
21227c478bd9Sstevel@tonic-gate 	if (holding_els)
21237c478bd9Sstevel@tonic-gate 		HANDLE_RELE_PG(h);
21247c478bd9Sstevel@tonic-gate 
21257c478bd9Sstevel@tonic-gate 	if (r < 0)
21267c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
21277c478bd9Sstevel@tonic-gate 
21287c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
21297c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
21307c478bd9Sstevel@tonic-gate 
21317c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
21327c478bd9Sstevel@tonic-gate 
21337c478bd9Sstevel@tonic-gate err:
21347c478bd9Sstevel@tonic-gate 	if (holding_els)
21357c478bd9Sstevel@tonic-gate 		HANDLE_RELE_PG(h);
21367c478bd9Sstevel@tonic-gate 	return (r);
21377c478bd9Sstevel@tonic-gate }
21387c478bd9Sstevel@tonic-gate 
21397c478bd9Sstevel@tonic-gate static int
datael_delete(const scf_datael_t * dp)21407c478bd9Sstevel@tonic-gate datael_delete(const scf_datael_t *dp)
21417c478bd9Sstevel@tonic-gate {
21427c478bd9Sstevel@tonic-gate 	scf_handle_t *h = dp->rd_handle;
21437c478bd9Sstevel@tonic-gate 
21447c478bd9Sstevel@tonic-gate 	struct rep_protocol_entity_delete request;
21457c478bd9Sstevel@tonic-gate 	struct rep_protocol_response response;
21467c478bd9Sstevel@tonic-gate 	ssize_t r;
21477c478bd9Sstevel@tonic-gate 
21487c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
21497c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ENTITY_DELETE;
21507c478bd9Sstevel@tonic-gate 	request.rpr_entityid = dp->rd_entity;
21517c478bd9Sstevel@tonic-gate 
21527c478bd9Sstevel@tonic-gate 	datael_finish_reset(dp);
21538918dff3Sjwadams 	request.rpr_changeid = handle_next_changeid(h);
21547c478bd9Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
21557c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
21567c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
21577c478bd9Sstevel@tonic-gate 
21587c478bd9Sstevel@tonic-gate 	if (r < 0)
21597c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
21607c478bd9Sstevel@tonic-gate 
21617c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
21627c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
21637c478bd9Sstevel@tonic-gate 
21647c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
21657c478bd9Sstevel@tonic-gate }
21667c478bd9Sstevel@tonic-gate 
21677c478bd9Sstevel@tonic-gate /*
21687c478bd9Sstevel@tonic-gate  * Fails with
21697c478bd9Sstevel@tonic-gate  *   _INVALID_ARGUMENT - h is NULL
21707c478bd9Sstevel@tonic-gate  *   _NO_MEMORY
21717c478bd9Sstevel@tonic-gate  *   _HANDLE_DESTROYED - h has been destroyed
21727c478bd9Sstevel@tonic-gate  *   _INTERNAL - server response too big
21737c478bd9Sstevel@tonic-gate  *		 iter already exists
21747c478bd9Sstevel@tonic-gate  *   _NO_RESOURCES
21757c478bd9Sstevel@tonic-gate  */
21767c478bd9Sstevel@tonic-gate scf_iter_t *
scf_iter_create(scf_handle_t * h)21777c478bd9Sstevel@tonic-gate scf_iter_create(scf_handle_t *h)
21787c478bd9Sstevel@tonic-gate {
21797c478bd9Sstevel@tonic-gate 	scf_iter_t *iter;
21807c478bd9Sstevel@tonic-gate 
21817c478bd9Sstevel@tonic-gate 	if (h == NULL) {
21827c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
21837c478bd9Sstevel@tonic-gate 		return (NULL);
21847c478bd9Sstevel@tonic-gate 	}
21857c478bd9Sstevel@tonic-gate 
21867c478bd9Sstevel@tonic-gate 	iter = uu_zalloc(sizeof (*iter));
21877c478bd9Sstevel@tonic-gate 	if (iter == NULL) {
21887c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
21897c478bd9Sstevel@tonic-gate 		return (NULL);
21907c478bd9Sstevel@tonic-gate 	}
21917c478bd9Sstevel@tonic-gate 
21927c478bd9Sstevel@tonic-gate 	uu_list_node_init(iter, &iter->iter_node, iter_pool);
21937c478bd9Sstevel@tonic-gate 	iter->iter_handle = h;
21947c478bd9Sstevel@tonic-gate 	iter->iter_sequence = 1;
21957c478bd9Sstevel@tonic-gate 	iter->iter_type = REP_PROTOCOL_ENTITY_NONE;
21967c478bd9Sstevel@tonic-gate 
21977c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
21987c478bd9Sstevel@tonic-gate 	iter->iter_id = handle_alloc_iterid(h);
21998918dff3Sjwadams 	if (iter->iter_id == 0) {
22008918dff3Sjwadams 		(void) pthread_mutex_unlock(&h->rh_lock);
22018918dff3Sjwadams 		uu_list_node_fini(iter, &iter->iter_node, iter_pool);
22028918dff3Sjwadams 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
22031f6eb021SLiane Praza 		uu_free(iter);
22048918dff3Sjwadams 		return (NULL);
22058918dff3Sjwadams 	}
22067c478bd9Sstevel@tonic-gate 	if (iter_attach(iter) == -1) {
22077c478bd9Sstevel@tonic-gate 		uu_list_node_fini(iter, &iter->iter_node, iter_pool);
22087c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
22097c478bd9Sstevel@tonic-gate 		uu_free(iter);
22107c478bd9Sstevel@tonic-gate 		return (NULL);
22117c478bd9Sstevel@tonic-gate 	}
22127c478bd9Sstevel@tonic-gate 	(void) uu_list_insert_before(h->rh_iters, NULL, iter);
22137c478bd9Sstevel@tonic-gate 	h->rh_extrefs++;
22147c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
22157c478bd9Sstevel@tonic-gate 	return (iter);
22167c478bd9Sstevel@tonic-gate }
22177c478bd9Sstevel@tonic-gate 
22187c478bd9Sstevel@tonic-gate scf_handle_t *
scf_iter_handle(const scf_iter_t * iter)22197c478bd9Sstevel@tonic-gate scf_iter_handle(const scf_iter_t *iter)
22207c478bd9Sstevel@tonic-gate {
22217c478bd9Sstevel@tonic-gate 	return (handle_get(iter->iter_handle));
22227c478bd9Sstevel@tonic-gate }
22237c478bd9Sstevel@tonic-gate 
22247c478bd9Sstevel@tonic-gate static void
scf_iter_reset_locked(scf_iter_t * iter)22257c478bd9Sstevel@tonic-gate scf_iter_reset_locked(scf_iter_t *iter)
22267c478bd9Sstevel@tonic-gate {
22277c478bd9Sstevel@tonic-gate 	struct rep_protocol_iter_request request;
22287c478bd9Sstevel@tonic-gate 	struct rep_protocol_response response;
22297c478bd9Sstevel@tonic-gate 
22307c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ITER_RESET;
22317c478bd9Sstevel@tonic-gate 	request.rpr_iterid = iter->iter_id;
22327c478bd9Sstevel@tonic-gate 
22337c478bd9Sstevel@tonic-gate 	assert(MUTEX_HELD(&iter->iter_handle->rh_lock));
22347c478bd9Sstevel@tonic-gate 
22357c478bd9Sstevel@tonic-gate 	(void) make_door_call(iter->iter_handle,
22367c478bd9Sstevel@tonic-gate 	    &request, sizeof (request), &response, sizeof (response));
22377c478bd9Sstevel@tonic-gate 
22387c478bd9Sstevel@tonic-gate 	iter->iter_type = REP_PROTOCOL_ENTITY_NONE;
22397c478bd9Sstevel@tonic-gate 	iter->iter_sequence = 1;
22407c478bd9Sstevel@tonic-gate }
22417c478bd9Sstevel@tonic-gate 
22427c478bd9Sstevel@tonic-gate void
scf_iter_reset(scf_iter_t * iter)22437c478bd9Sstevel@tonic-gate scf_iter_reset(scf_iter_t *iter)
22447c478bd9Sstevel@tonic-gate {
22457c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&iter->iter_handle->rh_lock);
22467c478bd9Sstevel@tonic-gate 	scf_iter_reset_locked(iter);
22477c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&iter->iter_handle->rh_lock);
22487c478bd9Sstevel@tonic-gate }
22497c478bd9Sstevel@tonic-gate 
22507c478bd9Sstevel@tonic-gate void
scf_iter_destroy(scf_iter_t * iter)22517c478bd9Sstevel@tonic-gate scf_iter_destroy(scf_iter_t *iter)
22527c478bd9Sstevel@tonic-gate {
22537c478bd9Sstevel@tonic-gate 	scf_handle_t *handle;
22547c478bd9Sstevel@tonic-gate 
22557c478bd9Sstevel@tonic-gate 	struct rep_protocol_iter_request request;
22567c478bd9Sstevel@tonic-gate 	struct rep_protocol_response response;
22577c478bd9Sstevel@tonic-gate 
22587c478bd9Sstevel@tonic-gate 	if (iter == NULL)
22597c478bd9Sstevel@tonic-gate 		return;
22607c478bd9Sstevel@tonic-gate 
22617c478bd9Sstevel@tonic-gate 	handle = iter->iter_handle;
22627c478bd9Sstevel@tonic-gate 
22637c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&handle->rh_lock);
22647c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ITER_TEARDOWN;
22657c478bd9Sstevel@tonic-gate 	request.rpr_iterid = iter->iter_id;
22667c478bd9Sstevel@tonic-gate 
22677c478bd9Sstevel@tonic-gate 	(void) make_door_call(handle, &request, sizeof (request),
22687c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
22697c478bd9Sstevel@tonic-gate 
22707c478bd9Sstevel@tonic-gate 	uu_list_remove(handle->rh_iters, iter);
22717c478bd9Sstevel@tonic-gate 	--handle->rh_extrefs;
22727c478bd9Sstevel@tonic-gate 	handle_unrefed(handle);			/* drops h->rh_lock */
22737c478bd9Sstevel@tonic-gate 	iter->iter_handle = NULL;
22747c478bd9Sstevel@tonic-gate 
22757c478bd9Sstevel@tonic-gate 	uu_list_node_fini(iter, &iter->iter_node, iter_pool);
22767c478bd9Sstevel@tonic-gate 	uu_free(iter);
22777c478bd9Sstevel@tonic-gate }
22787c478bd9Sstevel@tonic-gate 
22797c478bd9Sstevel@tonic-gate static int
handle_get_local_scope_locked(scf_handle_t * handle,scf_scope_t * out)22807c478bd9Sstevel@tonic-gate handle_get_local_scope_locked(scf_handle_t *handle, scf_scope_t *out)
22817c478bd9Sstevel@tonic-gate {
22827c478bd9Sstevel@tonic-gate 	struct rep_protocol_entity_get request;
22837c478bd9Sstevel@tonic-gate 	struct rep_protocol_name_response response;
22847c478bd9Sstevel@tonic-gate 	ssize_t r;
22857c478bd9Sstevel@tonic-gate 
22867c478bd9Sstevel@tonic-gate 	assert(MUTEX_HELD(&handle->rh_lock));
22877c478bd9Sstevel@tonic-gate 
22887c478bd9Sstevel@tonic-gate 	if (handle != out->rd_d.rd_handle)
22897c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
22907c478bd9Sstevel@tonic-gate 
22917c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ENTITY_GET;
22927c478bd9Sstevel@tonic-gate 	request.rpr_entityid = out->rd_d.rd_entity;
22937c478bd9Sstevel@tonic-gate 	request.rpr_object = RP_ENTITY_GET_MOST_LOCAL_SCOPE;
22947c478bd9Sstevel@tonic-gate 
22957c478bd9Sstevel@tonic-gate 	datael_finish_reset(&out->rd_d);
22967c478bd9Sstevel@tonic-gate 	r = make_door_call(handle, &request, sizeof (request),
22977c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
22987c478bd9Sstevel@tonic-gate 
22997c478bd9Sstevel@tonic-gate 	if (r < 0)
23007c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
23017c478bd9Sstevel@tonic-gate 
23027c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
23037c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
23047c478bd9Sstevel@tonic-gate 
23057c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
23067c478bd9Sstevel@tonic-gate }
23077c478bd9Sstevel@tonic-gate 
23087c478bd9Sstevel@tonic-gate int
scf_iter_handle_scopes(scf_iter_t * iter,const scf_handle_t * handle)23097c478bd9Sstevel@tonic-gate scf_iter_handle_scopes(scf_iter_t *iter, const scf_handle_t *handle)
23107c478bd9Sstevel@tonic-gate {
23117c478bd9Sstevel@tonic-gate 	scf_handle_t *h = iter->iter_handle;
23127c478bd9Sstevel@tonic-gate 	if (h != handle)
23137c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
23147c478bd9Sstevel@tonic-gate 
23157c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
23167c478bd9Sstevel@tonic-gate 	scf_iter_reset_locked(iter);
23177c478bd9Sstevel@tonic-gate 
23187c478bd9Sstevel@tonic-gate 	if (!handle_is_bound(h)) {
23197c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
23207c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_NOT_BOUND));
23217c478bd9Sstevel@tonic-gate 	}
23227c478bd9Sstevel@tonic-gate 
23238918dff3Sjwadams 	if (!handle_has_server_locked(h)) {
23247c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
23257c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN));
23267c478bd9Sstevel@tonic-gate 	}
23277c478bd9Sstevel@tonic-gate 
23287c478bd9Sstevel@tonic-gate 	iter->iter_type = REP_PROTOCOL_ENTITY_SCOPE;
23297c478bd9Sstevel@tonic-gate 	iter->iter_sequence = 1;
23307c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
23317c478bd9Sstevel@tonic-gate 	return (0);
23327c478bd9Sstevel@tonic-gate }
23337c478bd9Sstevel@tonic-gate 
23347c478bd9Sstevel@tonic-gate int
scf_iter_next_scope(scf_iter_t * iter,scf_scope_t * out)23357c478bd9Sstevel@tonic-gate scf_iter_next_scope(scf_iter_t *iter, scf_scope_t *out)
23367c478bd9Sstevel@tonic-gate {
23377c478bd9Sstevel@tonic-gate 	int ret;
23387c478bd9Sstevel@tonic-gate 	scf_handle_t *h = iter->iter_handle;
23397c478bd9Sstevel@tonic-gate 
23407c478bd9Sstevel@tonic-gate 	if (h != out->rd_d.rd_handle)
23417c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
23427c478bd9Sstevel@tonic-gate 
23437c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
23447c478bd9Sstevel@tonic-gate 	if (iter->iter_type == REP_PROTOCOL_ENTITY_NONE) {
23457c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
23467c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_NOT_SET));
23477c478bd9Sstevel@tonic-gate 	}
23487c478bd9Sstevel@tonic-gate 	if (iter->iter_type != REP_PROTOCOL_ENTITY_SCOPE) {
23497c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
23507c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
23517c478bd9Sstevel@tonic-gate 	}
23527c478bd9Sstevel@tonic-gate 	if (iter->iter_sequence == 1) {
23537c478bd9Sstevel@tonic-gate 		if ((ret = handle_get_local_scope_locked(h, out)) ==
23547c478bd9Sstevel@tonic-gate 		    SCF_SUCCESS) {
23557c478bd9Sstevel@tonic-gate 			iter->iter_sequence++;
23567c478bd9Sstevel@tonic-gate 			ret = 1;
23577c478bd9Sstevel@tonic-gate 		}
23587c478bd9Sstevel@tonic-gate 	} else {
23597c478bd9Sstevel@tonic-gate 		datael_reset_locked(&out->rd_d);
23607c478bd9Sstevel@tonic-gate 		ret = 0;
23617c478bd9Sstevel@tonic-gate 	}
23627c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
23637c478bd9Sstevel@tonic-gate 	return (ret);
23647c478bd9Sstevel@tonic-gate }
23657c478bd9Sstevel@tonic-gate 
23667c478bd9Sstevel@tonic-gate int
scf_handle_get_scope(scf_handle_t * h,const char * name,scf_scope_t * out)23677c478bd9Sstevel@tonic-gate scf_handle_get_scope(scf_handle_t *h, const char *name, scf_scope_t *out)
23687c478bd9Sstevel@tonic-gate {
23697c478bd9Sstevel@tonic-gate 	int ret;
23707c478bd9Sstevel@tonic-gate 
23717c478bd9Sstevel@tonic-gate 	if (h != out->rd_d.rd_handle)
23727c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
23737c478bd9Sstevel@tonic-gate 
23747c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
23757c478bd9Sstevel@tonic-gate 	if (strcmp(name, SCF_SCOPE_LOCAL) == 0) {
23767c478bd9Sstevel@tonic-gate 		ret = handle_get_local_scope_locked(h, out);
23777c478bd9Sstevel@tonic-gate 	} else {
23787c478bd9Sstevel@tonic-gate 		datael_reset_locked(&out->rd_d);
23797c478bd9Sstevel@tonic-gate 		if (uu_check_name(name, 0) == -1)
23807c478bd9Sstevel@tonic-gate 			ret = scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
23817c478bd9Sstevel@tonic-gate 		else
23827c478bd9Sstevel@tonic-gate 			ret = scf_set_error(SCF_ERROR_NOT_FOUND);
23837c478bd9Sstevel@tonic-gate 	}
23847c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
23857c478bd9Sstevel@tonic-gate 	return (ret);
23867c478bd9Sstevel@tonic-gate }
23877c478bd9Sstevel@tonic-gate 
23887c478bd9Sstevel@tonic-gate static int
datael_setup_iter(scf_iter_t * iter,const scf_datael_t * dp,uint32_t res_type,boolean_t composed)23897c478bd9Sstevel@tonic-gate datael_setup_iter(scf_iter_t *iter, const scf_datael_t *dp, uint32_t res_type,
23907c478bd9Sstevel@tonic-gate     boolean_t composed)
23917c478bd9Sstevel@tonic-gate {
23927c478bd9Sstevel@tonic-gate 	scf_handle_t *h = dp->rd_handle;
23937c478bd9Sstevel@tonic-gate 
23947c478bd9Sstevel@tonic-gate 	struct rep_protocol_iter_start request;
23957c478bd9Sstevel@tonic-gate 	struct rep_protocol_response response;
23967c478bd9Sstevel@tonic-gate 
23977c478bd9Sstevel@tonic-gate 	ssize_t r;
23987c478bd9Sstevel@tonic-gate 
23997c478bd9Sstevel@tonic-gate 	if (h != iter->iter_handle)
24007c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
24017c478bd9Sstevel@tonic-gate 
24027c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
24037c478bd9Sstevel@tonic-gate 	scf_iter_reset_locked(iter);
24047c478bd9Sstevel@tonic-gate 	iter->iter_type = res_type;
24057c478bd9Sstevel@tonic-gate 
24067c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ITER_START;
24077c478bd9Sstevel@tonic-gate 	request.rpr_iterid = iter->iter_id;
24087c478bd9Sstevel@tonic-gate 	request.rpr_entity = dp->rd_entity;
24097c478bd9Sstevel@tonic-gate 	request.rpr_itertype = res_type;
24107c478bd9Sstevel@tonic-gate 	request.rpr_flags = RP_ITER_START_ALL |
24117c478bd9Sstevel@tonic-gate 	    (composed ? RP_ITER_START_COMPOSED : 0);
24127c478bd9Sstevel@tonic-gate 	request.rpr_pattern[0] = 0;
24137c478bd9Sstevel@tonic-gate 
24147c478bd9Sstevel@tonic-gate 	datael_finish_reset(dp);
24157c478bd9Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
24167c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
24177c478bd9Sstevel@tonic-gate 
24187c478bd9Sstevel@tonic-gate 	if (r < 0) {
24197c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
24207c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
24217c478bd9Sstevel@tonic-gate 	}
24227c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
24237c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
24247c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
24257c478bd9Sstevel@tonic-gate 	}
24267c478bd9Sstevel@tonic-gate 	iter->iter_sequence++;
24277c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
24287c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
24297c478bd9Sstevel@tonic-gate }
24307c478bd9Sstevel@tonic-gate 
24317c478bd9Sstevel@tonic-gate static int
datael_setup_iter_pgtyped(scf_iter_t * iter,const scf_datael_t * dp,const char * pgtype,boolean_t composed)24327c478bd9Sstevel@tonic-gate datael_setup_iter_pgtyped(scf_iter_t *iter, const scf_datael_t *dp,
24337c478bd9Sstevel@tonic-gate     const char *pgtype, boolean_t composed)
24347c478bd9Sstevel@tonic-gate {
24357c478bd9Sstevel@tonic-gate 	scf_handle_t *h = dp->rd_handle;
24367c478bd9Sstevel@tonic-gate 
24377c478bd9Sstevel@tonic-gate 	struct rep_protocol_iter_start request;
24387c478bd9Sstevel@tonic-gate 	struct rep_protocol_response response;
24397c478bd9Sstevel@tonic-gate 
24407c478bd9Sstevel@tonic-gate 	ssize_t r;
24417c478bd9Sstevel@tonic-gate 
24427c478bd9Sstevel@tonic-gate 	if (h != iter->iter_handle)
24437c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
24447c478bd9Sstevel@tonic-gate 
24457c478bd9Sstevel@tonic-gate 	if (pgtype == NULL || strlcpy(request.rpr_pattern, pgtype,
24467c478bd9Sstevel@tonic-gate 	    sizeof (request.rpr_pattern)) >= sizeof (request.rpr_pattern)) {
24477c478bd9Sstevel@tonic-gate 		scf_iter_reset(iter);
24487c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
24497c478bd9Sstevel@tonic-gate 	}
24507c478bd9Sstevel@tonic-gate 
24517c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
24527c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ITER_START;
24537c478bd9Sstevel@tonic-gate 	request.rpr_iterid = iter->iter_id;
24547c478bd9Sstevel@tonic-gate 	request.rpr_entity = dp->rd_entity;
24557c478bd9Sstevel@tonic-gate 	request.rpr_itertype = REP_PROTOCOL_ENTITY_PROPERTYGRP;
24567c478bd9Sstevel@tonic-gate 	request.rpr_flags = RP_ITER_START_PGTYPE |
24577c478bd9Sstevel@tonic-gate 	    (composed ? RP_ITER_START_COMPOSED : 0);
24587c478bd9Sstevel@tonic-gate 
24597c478bd9Sstevel@tonic-gate 	datael_finish_reset(dp);
24607c478bd9Sstevel@tonic-gate 	scf_iter_reset_locked(iter);
24617c478bd9Sstevel@tonic-gate 	iter->iter_type = REP_PROTOCOL_ENTITY_PROPERTYGRP;
24627c478bd9Sstevel@tonic-gate 
24637c478bd9Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
24647c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
24657c478bd9Sstevel@tonic-gate 
24667c478bd9Sstevel@tonic-gate 	if (r < 0) {
24677c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
24687c478bd9Sstevel@tonic-gate 
24697c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
24707c478bd9Sstevel@tonic-gate 	}
24717c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
24727c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
24737c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
24747c478bd9Sstevel@tonic-gate 	}
24757c478bd9Sstevel@tonic-gate 	iter->iter_sequence++;
24767c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
24777c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
24787c478bd9Sstevel@tonic-gate }
24797c478bd9Sstevel@tonic-gate 
24807c478bd9Sstevel@tonic-gate static int
datael_iter_next(scf_iter_t * iter,scf_datael_t * out)24817c478bd9Sstevel@tonic-gate datael_iter_next(scf_iter_t *iter, scf_datael_t *out)
24827c478bd9Sstevel@tonic-gate {
24837c478bd9Sstevel@tonic-gate 	scf_handle_t *h = iter->iter_handle;
24847c478bd9Sstevel@tonic-gate 
24857c478bd9Sstevel@tonic-gate 	struct rep_protocol_iter_read request;
24867c478bd9Sstevel@tonic-gate 	struct rep_protocol_response response;
24877c478bd9Sstevel@tonic-gate 	ssize_t r;
24887c478bd9Sstevel@tonic-gate 
24897c478bd9Sstevel@tonic-gate 	if (h != out->rd_handle)
24907c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
24917c478bd9Sstevel@tonic-gate 
24927c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
24937c478bd9Sstevel@tonic-gate 	if (iter->iter_type == REP_PROTOCOL_ENTITY_NONE ||
24947c478bd9Sstevel@tonic-gate 	    iter->iter_sequence == 1) {
24957c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
24967c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_NOT_SET));
24977c478bd9Sstevel@tonic-gate 	}
24987c478bd9Sstevel@tonic-gate 
24997c478bd9Sstevel@tonic-gate 	if (out->rd_type != iter->iter_type) {
25007c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
25017c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
25027c478bd9Sstevel@tonic-gate 	}
25037c478bd9Sstevel@tonic-gate 
25047c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ITER_READ;
25057c478bd9Sstevel@tonic-gate 	request.rpr_iterid = iter->iter_id;
25067c478bd9Sstevel@tonic-gate 	request.rpr_sequence = iter->iter_sequence;
25077c478bd9Sstevel@tonic-gate 	request.rpr_entityid = out->rd_entity;
25087c478bd9Sstevel@tonic-gate 
25097c478bd9Sstevel@tonic-gate 	datael_finish_reset(out);
25107c478bd9Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
25117c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
25127c478bd9Sstevel@tonic-gate 
25137c478bd9Sstevel@tonic-gate 	if (r < 0) {
25147c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
25157c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
25167c478bd9Sstevel@tonic-gate 	}
25177c478bd9Sstevel@tonic-gate 
25187c478bd9Sstevel@tonic-gate 	if (response.rpr_response == REP_PROTOCOL_DONE) {
25197c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
25207c478bd9Sstevel@tonic-gate 		return (0);
25217c478bd9Sstevel@tonic-gate 	}
25227c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
25237c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
25247c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
25257c478bd9Sstevel@tonic-gate 	}
25267c478bd9Sstevel@tonic-gate 	iter->iter_sequence++;
25277c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
25287c478bd9Sstevel@tonic-gate 
25297c478bd9Sstevel@tonic-gate 	return (1);
25307c478bd9Sstevel@tonic-gate }
25317c478bd9Sstevel@tonic-gate 
25327c478bd9Sstevel@tonic-gate int
scf_iter_scope_services(scf_iter_t * iter,const scf_scope_t * s)25337c478bd9Sstevel@tonic-gate scf_iter_scope_services(scf_iter_t *iter, const scf_scope_t *s)
25347c478bd9Sstevel@tonic-gate {
25357c478bd9Sstevel@tonic-gate 	return (datael_setup_iter(iter, &s->rd_d,
25367c478bd9Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_SERVICE, 0));
25377c478bd9Sstevel@tonic-gate }
25387c478bd9Sstevel@tonic-gate 
25397c478bd9Sstevel@tonic-gate int
scf_iter_next_service(scf_iter_t * iter,scf_service_t * out)25407c478bd9Sstevel@tonic-gate scf_iter_next_service(scf_iter_t *iter, scf_service_t *out)
25417c478bd9Sstevel@tonic-gate {
25427c478bd9Sstevel@tonic-gate 	return (datael_iter_next(iter, &out->rd_d));
25437c478bd9Sstevel@tonic-gate }
25447c478bd9Sstevel@tonic-gate 
25457c478bd9Sstevel@tonic-gate int
scf_iter_service_instances(scf_iter_t * iter,const scf_service_t * svc)25467c478bd9Sstevel@tonic-gate scf_iter_service_instances(scf_iter_t *iter, const scf_service_t *svc)
25477c478bd9Sstevel@tonic-gate {
25487c478bd9Sstevel@tonic-gate 	return (datael_setup_iter(iter, &svc->rd_d,
25497c478bd9Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_INSTANCE, 0));
25507c478bd9Sstevel@tonic-gate }
25517c478bd9Sstevel@tonic-gate 
25527c478bd9Sstevel@tonic-gate int
scf_iter_next_instance(scf_iter_t * iter,scf_instance_t * out)25537c478bd9Sstevel@tonic-gate scf_iter_next_instance(scf_iter_t *iter, scf_instance_t *out)
25547c478bd9Sstevel@tonic-gate {
25557c478bd9Sstevel@tonic-gate 	return (datael_iter_next(iter, &out->rd_d));
25567c478bd9Sstevel@tonic-gate }
25577c478bd9Sstevel@tonic-gate 
25587c478bd9Sstevel@tonic-gate int
scf_iter_service_pgs(scf_iter_t * iter,const scf_service_t * svc)25597c478bd9Sstevel@tonic-gate scf_iter_service_pgs(scf_iter_t *iter, const scf_service_t *svc)
25607c478bd9Sstevel@tonic-gate {
25617c478bd9Sstevel@tonic-gate 	return (datael_setup_iter(iter, &svc->rd_d,
25627c478bd9Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_PROPERTYGRP, 0));
25637c478bd9Sstevel@tonic-gate }
25647c478bd9Sstevel@tonic-gate 
25657c478bd9Sstevel@tonic-gate int
scf_iter_service_pgs_typed(scf_iter_t * iter,const scf_service_t * svc,const char * type)25667c478bd9Sstevel@tonic-gate scf_iter_service_pgs_typed(scf_iter_t *iter, const scf_service_t *svc,
25677c478bd9Sstevel@tonic-gate     const char *type)
25687c478bd9Sstevel@tonic-gate {
25697c478bd9Sstevel@tonic-gate 	return (datael_setup_iter_pgtyped(iter, &svc->rd_d, type, 0));
25707c478bd9Sstevel@tonic-gate }
25717c478bd9Sstevel@tonic-gate 
25727c478bd9Sstevel@tonic-gate int
scf_iter_instance_snapshots(scf_iter_t * iter,const scf_instance_t * inst)25737c478bd9Sstevel@tonic-gate scf_iter_instance_snapshots(scf_iter_t *iter, const scf_instance_t *inst)
25747c478bd9Sstevel@tonic-gate {
25757c478bd9Sstevel@tonic-gate 	return (datael_setup_iter(iter, &inst->rd_d,
25767c478bd9Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_SNAPSHOT, 0));
25777c478bd9Sstevel@tonic-gate }
25787c478bd9Sstevel@tonic-gate 
25797c478bd9Sstevel@tonic-gate int
scf_iter_next_snapshot(scf_iter_t * iter,scf_snapshot_t * out)25807c478bd9Sstevel@tonic-gate scf_iter_next_snapshot(scf_iter_t *iter, scf_snapshot_t *out)
25817c478bd9Sstevel@tonic-gate {
25827c478bd9Sstevel@tonic-gate 	return (datael_iter_next(iter, &out->rd_d));
25837c478bd9Sstevel@tonic-gate }
25847c478bd9Sstevel@tonic-gate 
25857c478bd9Sstevel@tonic-gate int
scf_iter_instance_pgs(scf_iter_t * iter,const scf_instance_t * inst)25867c478bd9Sstevel@tonic-gate scf_iter_instance_pgs(scf_iter_t *iter, const scf_instance_t *inst)
25877c478bd9Sstevel@tonic-gate {
25887c478bd9Sstevel@tonic-gate 	return (datael_setup_iter(iter, &inst->rd_d,
25897c478bd9Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_PROPERTYGRP, 0));
25907c478bd9Sstevel@tonic-gate }
25917c478bd9Sstevel@tonic-gate 
25927c478bd9Sstevel@tonic-gate int
scf_iter_instance_pgs_typed(scf_iter_t * iter,const scf_instance_t * inst,const char * type)25937c478bd9Sstevel@tonic-gate scf_iter_instance_pgs_typed(scf_iter_t *iter, const scf_instance_t *inst,
25947c478bd9Sstevel@tonic-gate     const char *type)
25957c478bd9Sstevel@tonic-gate {
25967c478bd9Sstevel@tonic-gate 	return (datael_setup_iter_pgtyped(iter, &inst->rd_d, type, 0));
25977c478bd9Sstevel@tonic-gate }
25987c478bd9Sstevel@tonic-gate 
25997c478bd9Sstevel@tonic-gate int
scf_iter_instance_pgs_composed(scf_iter_t * iter,const scf_instance_t * inst,const scf_snapshot_t * snap)26007c478bd9Sstevel@tonic-gate scf_iter_instance_pgs_composed(scf_iter_t *iter, const scf_instance_t *inst,
26017c478bd9Sstevel@tonic-gate     const scf_snapshot_t *snap)
26027c478bd9Sstevel@tonic-gate {
26037c478bd9Sstevel@tonic-gate 	if (snap != NULL && inst->rd_d.rd_handle != snap->rd_d.rd_handle)
26047c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
26057c478bd9Sstevel@tonic-gate 
26067c478bd9Sstevel@tonic-gate 	return (datael_setup_iter(iter, snap ? &snap->rd_d : &inst->rd_d,
26077c478bd9Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_PROPERTYGRP, 1));
26087c478bd9Sstevel@tonic-gate }
26097c478bd9Sstevel@tonic-gate 
26107c478bd9Sstevel@tonic-gate int
scf_iter_instance_pgs_typed_composed(scf_iter_t * iter,const scf_instance_t * inst,const scf_snapshot_t * snap,const char * type)26117c478bd9Sstevel@tonic-gate scf_iter_instance_pgs_typed_composed(scf_iter_t *iter,
26127c478bd9Sstevel@tonic-gate     const scf_instance_t *inst, const scf_snapshot_t *snap, const char *type)
26137c478bd9Sstevel@tonic-gate {
26147c478bd9Sstevel@tonic-gate 	if (snap != NULL && inst->rd_d.rd_handle != snap->rd_d.rd_handle)
26157c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
26167c478bd9Sstevel@tonic-gate 
26177c478bd9Sstevel@tonic-gate 	return (datael_setup_iter_pgtyped(iter,
26187c478bd9Sstevel@tonic-gate 	    snap ? &snap->rd_d : &inst->rd_d, type, 1));
26197c478bd9Sstevel@tonic-gate }
26207c478bd9Sstevel@tonic-gate 
26217c478bd9Sstevel@tonic-gate int
scf_iter_snaplevel_pgs(scf_iter_t * iter,const scf_snaplevel_t * inst)26227c478bd9Sstevel@tonic-gate scf_iter_snaplevel_pgs(scf_iter_t *iter, const scf_snaplevel_t *inst)
26237c478bd9Sstevel@tonic-gate {
26247c478bd9Sstevel@tonic-gate 	return (datael_setup_iter(iter, &inst->rd_d,
26257c478bd9Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_PROPERTYGRP, 0));
26267c478bd9Sstevel@tonic-gate }
26277c478bd9Sstevel@tonic-gate 
26287c478bd9Sstevel@tonic-gate int
scf_iter_snaplevel_pgs_typed(scf_iter_t * iter,const scf_snaplevel_t * inst,const char * type)26297c478bd9Sstevel@tonic-gate scf_iter_snaplevel_pgs_typed(scf_iter_t *iter, const scf_snaplevel_t *inst,
26307c478bd9Sstevel@tonic-gate     const char *type)
26317c478bd9Sstevel@tonic-gate {
26327c478bd9Sstevel@tonic-gate 	return (datael_setup_iter_pgtyped(iter, &inst->rd_d, type, 0));
26337c478bd9Sstevel@tonic-gate }
26347c478bd9Sstevel@tonic-gate 
26357c478bd9Sstevel@tonic-gate int
scf_iter_next_pg(scf_iter_t * iter,scf_propertygroup_t * out)26367c478bd9Sstevel@tonic-gate scf_iter_next_pg(scf_iter_t *iter, scf_propertygroup_t *out)
26377c478bd9Sstevel@tonic-gate {
26387c478bd9Sstevel@tonic-gate 	return (datael_iter_next(iter, &out->rd_d));
26397c478bd9Sstevel@tonic-gate }
26407c478bd9Sstevel@tonic-gate 
26417c478bd9Sstevel@tonic-gate int
scf_iter_pg_properties(scf_iter_t * iter,const scf_propertygroup_t * pg)26427c478bd9Sstevel@tonic-gate scf_iter_pg_properties(scf_iter_t *iter, const scf_propertygroup_t *pg)
26437c478bd9Sstevel@tonic-gate {
26447c478bd9Sstevel@tonic-gate 	return (datael_setup_iter(iter, &pg->rd_d,
26457c478bd9Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_PROPERTY, 0));
26467c478bd9Sstevel@tonic-gate }
26477c478bd9Sstevel@tonic-gate 
26487c478bd9Sstevel@tonic-gate int
scf_iter_next_property(scf_iter_t * iter,scf_property_t * out)26497c478bd9Sstevel@tonic-gate scf_iter_next_property(scf_iter_t *iter, scf_property_t *out)
26507c478bd9Sstevel@tonic-gate {
26517c478bd9Sstevel@tonic-gate 	return (datael_iter_next(iter, &out->rd_d));
26527c478bd9Sstevel@tonic-gate }
26537c478bd9Sstevel@tonic-gate 
26547c478bd9Sstevel@tonic-gate /*
26557c478bd9Sstevel@tonic-gate  * Fails with
26567c478bd9Sstevel@tonic-gate  *   _INVALID_ARGUMENT - handle is NULL
26577c478bd9Sstevel@tonic-gate  *   _INTERNAL - server response too big
26587c478bd9Sstevel@tonic-gate  *		 entity already set up with different type
26597c478bd9Sstevel@tonic-gate  *   _NO_RESOURCES
26607c478bd9Sstevel@tonic-gate  *   _NO_MEMORY
26617c478bd9Sstevel@tonic-gate  */
26627c478bd9Sstevel@tonic-gate scf_scope_t *
scf_scope_create(scf_handle_t * handle)26637c478bd9Sstevel@tonic-gate scf_scope_create(scf_handle_t *handle)
26647c478bd9Sstevel@tonic-gate {
26657c478bd9Sstevel@tonic-gate 	scf_scope_t *ret;
26667c478bd9Sstevel@tonic-gate 
26677c478bd9Sstevel@tonic-gate 	ret = uu_zalloc(sizeof (*ret));
26687c478bd9Sstevel@tonic-gate 	if (ret != NULL) {
26697c478bd9Sstevel@tonic-gate 		if (datael_init(&ret->rd_d, handle,
26707c478bd9Sstevel@tonic-gate 		    REP_PROTOCOL_ENTITY_SCOPE) == -1) {
26717c478bd9Sstevel@tonic-gate 			uu_free(ret);
26727c478bd9Sstevel@tonic-gate 			return (NULL);
26737c478bd9Sstevel@tonic-gate 		}
26747c478bd9Sstevel@tonic-gate 	} else {
26757c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
26767c478bd9Sstevel@tonic-gate 	}
26777c478bd9Sstevel@tonic-gate 
26787c478bd9Sstevel@tonic-gate 	return (ret);
26797c478bd9Sstevel@tonic-gate }
26807c478bd9Sstevel@tonic-gate 
26817c478bd9Sstevel@tonic-gate scf_handle_t *
scf_scope_handle(const scf_scope_t * val)26827c478bd9Sstevel@tonic-gate scf_scope_handle(const scf_scope_t *val)
26837c478bd9Sstevel@tonic-gate {
26847c478bd9Sstevel@tonic-gate 	return (datael_handle(&val->rd_d));
26857c478bd9Sstevel@tonic-gate }
26867c478bd9Sstevel@tonic-gate 
26877c478bd9Sstevel@tonic-gate void
scf_scope_destroy(scf_scope_t * val)26887c478bd9Sstevel@tonic-gate scf_scope_destroy(scf_scope_t *val)
26897c478bd9Sstevel@tonic-gate {
26907c478bd9Sstevel@tonic-gate 	if (val == NULL)
26917c478bd9Sstevel@tonic-gate 		return;
26927c478bd9Sstevel@tonic-gate 
26937c478bd9Sstevel@tonic-gate 	datael_destroy(&val->rd_d);
26947c478bd9Sstevel@tonic-gate 	uu_free(val);
26957c478bd9Sstevel@tonic-gate }
26967c478bd9Sstevel@tonic-gate 
26977c478bd9Sstevel@tonic-gate ssize_t
scf_scope_get_name(const scf_scope_t * rep,char * out,size_t len)26987c478bd9Sstevel@tonic-gate scf_scope_get_name(const scf_scope_t *rep, char *out, size_t len)
26997c478bd9Sstevel@tonic-gate {
27007c478bd9Sstevel@tonic-gate 	return (datael_get_name(&rep->rd_d, out, len, RP_ENTITY_NAME_NAME));
27017c478bd9Sstevel@tonic-gate }
27027c478bd9Sstevel@tonic-gate 
27037c478bd9Sstevel@tonic-gate /*ARGSUSED*/
27047c478bd9Sstevel@tonic-gate int
scf_scope_get_parent(const scf_scope_t * child,scf_scope_t * parent)27057c478bd9Sstevel@tonic-gate scf_scope_get_parent(const scf_scope_t *child, scf_scope_t *parent)
27067c478bd9Sstevel@tonic-gate {
27077c478bd9Sstevel@tonic-gate 	char name[1];
27087c478bd9Sstevel@tonic-gate 
27097c478bd9Sstevel@tonic-gate 	/* fake up the side-effects */
27107c478bd9Sstevel@tonic-gate 	datael_reset(&parent->rd_d);
27117c478bd9Sstevel@tonic-gate 	if (scf_scope_get_name(child, name, sizeof (name)) < 0)
27127c478bd9Sstevel@tonic-gate 		return (-1);
27137c478bd9Sstevel@tonic-gate 	return (scf_set_error(SCF_ERROR_NOT_FOUND));
27147c478bd9Sstevel@tonic-gate }
27157c478bd9Sstevel@tonic-gate 
27167c478bd9Sstevel@tonic-gate /*
27177c478bd9Sstevel@tonic-gate  * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
27187c478bd9Sstevel@tonic-gate  * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
27197c478bd9Sstevel@tonic-gate  */
27207c478bd9Sstevel@tonic-gate scf_service_t *
scf_service_create(scf_handle_t * handle)27217c478bd9Sstevel@tonic-gate scf_service_create(scf_handle_t *handle)
27227c478bd9Sstevel@tonic-gate {
27237c478bd9Sstevel@tonic-gate 	scf_service_t *ret;
27247c478bd9Sstevel@tonic-gate 	ret = uu_zalloc(sizeof (*ret));
27257c478bd9Sstevel@tonic-gate 	if (ret != NULL) {
27267c478bd9Sstevel@tonic-gate 		if (datael_init(&ret->rd_d, handle,
27277c478bd9Sstevel@tonic-gate 		    REP_PROTOCOL_ENTITY_SERVICE) == -1) {
27287c478bd9Sstevel@tonic-gate 			uu_free(ret);
27297c478bd9Sstevel@tonic-gate 			return (NULL);
27307c478bd9Sstevel@tonic-gate 		}
27317c478bd9Sstevel@tonic-gate 	} else {
27327c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
27337c478bd9Sstevel@tonic-gate 	}
27347c478bd9Sstevel@tonic-gate 
27357c478bd9Sstevel@tonic-gate 	return (ret);
27367c478bd9Sstevel@tonic-gate }
27377c478bd9Sstevel@tonic-gate 
273876cf44abSjeanm 
273976cf44abSjeanm /*
274076cf44abSjeanm  * Fails with
274176cf44abSjeanm  *   _HANDLE_MISMATCH
274276cf44abSjeanm  *   _INVALID_ARGUMENT
274376cf44abSjeanm  *   _NOT_BOUND
274476cf44abSjeanm  *   _CONNECTION_BROKEN
274576cf44abSjeanm  *   _INTERNAL
274676cf44abSjeanm  *   _EXISTS
274776cf44abSjeanm  *   _DELETED
274876cf44abSjeanm  *   _NOT_SET
274976cf44abSjeanm  *   _NO_RESOURCES
275076cf44abSjeanm  *   _PERMISSION_DENIED
275176cf44abSjeanm  *   _BACKEND_ACCESS
275276cf44abSjeanm  *   _BACKEND_READONLY
275376cf44abSjeanm  */
27547c478bd9Sstevel@tonic-gate int
scf_scope_add_service(const scf_scope_t * scope,const char * name,scf_service_t * svc)27557c478bd9Sstevel@tonic-gate scf_scope_add_service(const scf_scope_t *scope, const char *name,
27567c478bd9Sstevel@tonic-gate     scf_service_t *svc)
27577c478bd9Sstevel@tonic-gate {
27587c478bd9Sstevel@tonic-gate 	return (datael_add_child(&scope->rd_d, name,
27597c478bd9Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_SERVICE, (svc != NULL)? &svc->rd_d : NULL));
27607c478bd9Sstevel@tonic-gate }
27617c478bd9Sstevel@tonic-gate 
276276cf44abSjeanm /*
276376cf44abSjeanm  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
276476cf44abSjeanm  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
276576cf44abSjeanm  * _BACKEND_ACCESS, _NOT_FOUND.
276676cf44abSjeanm  */
27677c478bd9Sstevel@tonic-gate int
scf_scope_get_service(const scf_scope_t * s,const char * name,scf_service_t * svc)27687c478bd9Sstevel@tonic-gate scf_scope_get_service(const scf_scope_t *s, const char *name,
27697c478bd9Sstevel@tonic-gate     scf_service_t *svc)
27707c478bd9Sstevel@tonic-gate {
27717c478bd9Sstevel@tonic-gate 	return (datael_get_child(&s->rd_d, name, REP_PROTOCOL_ENTITY_SERVICE,
27727c478bd9Sstevel@tonic-gate 	    svc ? &svc->rd_d : NULL, 0));
27737c478bd9Sstevel@tonic-gate }
27747c478bd9Sstevel@tonic-gate 
27757c478bd9Sstevel@tonic-gate scf_handle_t *
scf_service_handle(const scf_service_t * val)27767c478bd9Sstevel@tonic-gate scf_service_handle(const scf_service_t *val)
27777c478bd9Sstevel@tonic-gate {
27787c478bd9Sstevel@tonic-gate 	return (datael_handle(&val->rd_d));
27797c478bd9Sstevel@tonic-gate }
27807c478bd9Sstevel@tonic-gate 
27817c478bd9Sstevel@tonic-gate int
scf_service_delete(scf_service_t * svc)27827c478bd9Sstevel@tonic-gate scf_service_delete(scf_service_t *svc)
27837c478bd9Sstevel@tonic-gate {
27847c478bd9Sstevel@tonic-gate 	return (datael_delete(&svc->rd_d));
27857c478bd9Sstevel@tonic-gate }
27867c478bd9Sstevel@tonic-gate 
27877c478bd9Sstevel@tonic-gate int
scf_instance_delete(scf_instance_t * inst)27887c478bd9Sstevel@tonic-gate scf_instance_delete(scf_instance_t *inst)
27897c478bd9Sstevel@tonic-gate {
27907c478bd9Sstevel@tonic-gate 	return (datael_delete(&inst->rd_d));
27917c478bd9Sstevel@tonic-gate }
27927c478bd9Sstevel@tonic-gate 
27937c478bd9Sstevel@tonic-gate int
scf_pg_delete(scf_propertygroup_t * pg)27947c478bd9Sstevel@tonic-gate scf_pg_delete(scf_propertygroup_t *pg)
27957c478bd9Sstevel@tonic-gate {
27967c478bd9Sstevel@tonic-gate 	return (datael_delete(&pg->rd_d));
27977c478bd9Sstevel@tonic-gate }
27987c478bd9Sstevel@tonic-gate 
27997c478bd9Sstevel@tonic-gate int
_scf_snapshot_delete(scf_snapshot_t * snap)28007c478bd9Sstevel@tonic-gate _scf_snapshot_delete(scf_snapshot_t *snap)
28017c478bd9Sstevel@tonic-gate {
28027c478bd9Sstevel@tonic-gate 	return (datael_delete(&snap->rd_d));
28037c478bd9Sstevel@tonic-gate }
28047c478bd9Sstevel@tonic-gate 
280576cf44abSjeanm /*
280676cf44abSjeanm  * Fails with
280776cf44abSjeanm  *   _HANDLE_MISMATCH
280876cf44abSjeanm  *   _INVALID_ARGUMENT
280976cf44abSjeanm  *   _NOT_BOUND
281076cf44abSjeanm  *   _CONNECTION_BROKEN
281176cf44abSjeanm  *   _INTERNAL
281276cf44abSjeanm  *   _EXISTS
281376cf44abSjeanm  *   _DELETED
281476cf44abSjeanm  *   _NOT_SET
281576cf44abSjeanm  *   _NO_RESOURCES
281676cf44abSjeanm  *   _PERMISSION_DENIED
281776cf44abSjeanm  *   _BACKEND_ACCESS
281876cf44abSjeanm  *   _BACKEND_READONLY
281976cf44abSjeanm  */
28207c478bd9Sstevel@tonic-gate int
scf_service_add_instance(const scf_service_t * svc,const char * name,scf_instance_t * instance)28217c478bd9Sstevel@tonic-gate scf_service_add_instance(const scf_service_t *svc, const char *name,
28227c478bd9Sstevel@tonic-gate     scf_instance_t *instance)
28237c478bd9Sstevel@tonic-gate {
28247c478bd9Sstevel@tonic-gate 	return (datael_add_child(&svc->rd_d, name,
28257c478bd9Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_INSTANCE,
28267c478bd9Sstevel@tonic-gate 	    (instance != NULL)? &instance->rd_d : NULL));
28277c478bd9Sstevel@tonic-gate }
28287c478bd9Sstevel@tonic-gate 
282976cf44abSjeanm 
283076cf44abSjeanm /*
283176cf44abSjeanm  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
283276cf44abSjeanm  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
283376cf44abSjeanm  * _BACKEND_ACCESS, _NOT_FOUND.
283476cf44abSjeanm  */
28357c478bd9Sstevel@tonic-gate int
scf_service_get_instance(const scf_service_t * svc,const char * name,scf_instance_t * inst)28367c478bd9Sstevel@tonic-gate scf_service_get_instance(const scf_service_t *svc, const char *name,
28377c478bd9Sstevel@tonic-gate     scf_instance_t *inst)
28387c478bd9Sstevel@tonic-gate {
28397c478bd9Sstevel@tonic-gate 	return (datael_get_child(&svc->rd_d, name, REP_PROTOCOL_ENTITY_INSTANCE,
28407c478bd9Sstevel@tonic-gate 	    inst ? &inst->rd_d : NULL, 0));
28417c478bd9Sstevel@tonic-gate }
28427c478bd9Sstevel@tonic-gate 
28437c478bd9Sstevel@tonic-gate int
scf_service_add_pg(const scf_service_t * svc,const char * name,const char * type,uint32_t flags,scf_propertygroup_t * pg)28447c478bd9Sstevel@tonic-gate scf_service_add_pg(const scf_service_t *svc, const char *name,
28457c478bd9Sstevel@tonic-gate     const char *type, uint32_t flags, scf_propertygroup_t *pg)
28467c478bd9Sstevel@tonic-gate {
28477c478bd9Sstevel@tonic-gate 	return (datael_add_pg(&svc->rd_d, name, type, flags,
28487c478bd9Sstevel@tonic-gate 	    (pg != NULL)?&pg->rd_d : NULL));
28497c478bd9Sstevel@tonic-gate }
28507c478bd9Sstevel@tonic-gate 
285176cf44abSjeanm /*
285276cf44abSjeanm  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
285376cf44abSjeanm  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
285476cf44abSjeanm  * _BACKEND_ACCESS, _NOT_FOUND.
285576cf44abSjeanm  */
28567c478bd9Sstevel@tonic-gate int
scf_service_get_pg(const scf_service_t * svc,const char * name,scf_propertygroup_t * pg)28577c478bd9Sstevel@tonic-gate scf_service_get_pg(const scf_service_t *svc, const char *name,
28587c478bd9Sstevel@tonic-gate     scf_propertygroup_t *pg)
28597c478bd9Sstevel@tonic-gate {
28607c478bd9Sstevel@tonic-gate 	return (datael_get_child(&svc->rd_d, name,
28617c478bd9Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_PROPERTYGRP, pg ? &pg->rd_d : NULL, 0));
28627c478bd9Sstevel@tonic-gate }
28637c478bd9Sstevel@tonic-gate 
28647c478bd9Sstevel@tonic-gate int
scf_instance_add_pg(const scf_instance_t * inst,const char * name,const char * type,uint32_t flags,scf_propertygroup_t * pg)28657c478bd9Sstevel@tonic-gate scf_instance_add_pg(const scf_instance_t *inst, const char *name,
28667c478bd9Sstevel@tonic-gate     const char *type, uint32_t flags, scf_propertygroup_t *pg)
28677c478bd9Sstevel@tonic-gate {
28687c478bd9Sstevel@tonic-gate 	return (datael_add_pg(&inst->rd_d, name, type, flags,
28697c478bd9Sstevel@tonic-gate 	    (pg != NULL)?&pg->rd_d : NULL));
28707c478bd9Sstevel@tonic-gate }
28717c478bd9Sstevel@tonic-gate 
287276cf44abSjeanm /*
287376cf44abSjeanm  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
287476cf44abSjeanm  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
287576cf44abSjeanm  * _BACKEND_ACCESS, _NOT_FOUND.
287676cf44abSjeanm  */
28777c478bd9Sstevel@tonic-gate int
scf_instance_get_snapshot(const scf_instance_t * inst,const char * name,scf_snapshot_t * pg)28787c478bd9Sstevel@tonic-gate scf_instance_get_snapshot(const scf_instance_t *inst, const char *name,
28797c478bd9Sstevel@tonic-gate     scf_snapshot_t *pg)
28807c478bd9Sstevel@tonic-gate {
28817c478bd9Sstevel@tonic-gate 	return (datael_get_child(&inst->rd_d, name,
28827c478bd9Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_SNAPSHOT, pg ? &pg->rd_d : NULL, 0));
28837c478bd9Sstevel@tonic-gate }
28847c478bd9Sstevel@tonic-gate 
288576cf44abSjeanm /*
288676cf44abSjeanm  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
288776cf44abSjeanm  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
288876cf44abSjeanm  * _BACKEND_ACCESS, _NOT_FOUND.
288976cf44abSjeanm  */
28907c478bd9Sstevel@tonic-gate int
scf_instance_get_pg(const scf_instance_t * inst,const char * name,scf_propertygroup_t * pg)28917c478bd9Sstevel@tonic-gate scf_instance_get_pg(const scf_instance_t *inst, const char *name,
28927c478bd9Sstevel@tonic-gate     scf_propertygroup_t *pg)
28937c478bd9Sstevel@tonic-gate {
28947c478bd9Sstevel@tonic-gate 	return (datael_get_child(&inst->rd_d, name,
28957c478bd9Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_PROPERTYGRP, pg ? &pg->rd_d : NULL, 0));
28967c478bd9Sstevel@tonic-gate }
28977c478bd9Sstevel@tonic-gate 
289876cf44abSjeanm /*
289976cf44abSjeanm  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
290076cf44abSjeanm  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
290176cf44abSjeanm  * _BACKEND_ACCESS, _NOT_FOUND.
290276cf44abSjeanm  */
29037c478bd9Sstevel@tonic-gate int
scf_instance_get_pg_composed(const scf_instance_t * inst,const scf_snapshot_t * snap,const char * name,scf_propertygroup_t * pg)29047c478bd9Sstevel@tonic-gate scf_instance_get_pg_composed(const scf_instance_t *inst,
29057c478bd9Sstevel@tonic-gate     const scf_snapshot_t *snap, const char *name, scf_propertygroup_t *pg)
29067c478bd9Sstevel@tonic-gate {
29077c478bd9Sstevel@tonic-gate 	if (snap != NULL && inst->rd_d.rd_handle != snap->rd_d.rd_handle)
29087c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
29097c478bd9Sstevel@tonic-gate 
29107c478bd9Sstevel@tonic-gate 	return (datael_get_child(snap ? &snap->rd_d : &inst->rd_d, name,
29117c478bd9Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_PROPERTYGRP, pg ? &pg->rd_d : NULL, 1));
29127c478bd9Sstevel@tonic-gate }
29137c478bd9Sstevel@tonic-gate 
291476cf44abSjeanm /*
291576cf44abSjeanm  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
291676cf44abSjeanm  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
291776cf44abSjeanm  * _BACKEND_ACCESS, _NOT_FOUND.
291876cf44abSjeanm  */
29197c478bd9Sstevel@tonic-gate int
scf_pg_get_property(const scf_propertygroup_t * pg,const char * name,scf_property_t * prop)29207c478bd9Sstevel@tonic-gate scf_pg_get_property(const scf_propertygroup_t *pg, const char *name,
29217c478bd9Sstevel@tonic-gate     scf_property_t *prop)
29227c478bd9Sstevel@tonic-gate {
29237c478bd9Sstevel@tonic-gate 	return (datael_get_child(&pg->rd_d, name, REP_PROTOCOL_ENTITY_PROPERTY,
29247c478bd9Sstevel@tonic-gate 	    prop ? &prop->rd_d : NULL, 0));
29257c478bd9Sstevel@tonic-gate }
29267c478bd9Sstevel@tonic-gate 
29277c478bd9Sstevel@tonic-gate void
scf_service_destroy(scf_service_t * val)29287c478bd9Sstevel@tonic-gate scf_service_destroy(scf_service_t *val)
29297c478bd9Sstevel@tonic-gate {
29307c478bd9Sstevel@tonic-gate 	if (val == NULL)
29317c478bd9Sstevel@tonic-gate 		return;
29327c478bd9Sstevel@tonic-gate 
29337c478bd9Sstevel@tonic-gate 	datael_destroy(&val->rd_d);
29347c478bd9Sstevel@tonic-gate 	uu_free(val);
29357c478bd9Sstevel@tonic-gate }
29367c478bd9Sstevel@tonic-gate 
29377c478bd9Sstevel@tonic-gate ssize_t
scf_service_get_name(const scf_service_t * rep,char * out,size_t len)29387c478bd9Sstevel@tonic-gate scf_service_get_name(const scf_service_t *rep, char *out, size_t len)
29397c478bd9Sstevel@tonic-gate {
29407c478bd9Sstevel@tonic-gate 	return (datael_get_name(&rep->rd_d, out, len, RP_ENTITY_NAME_NAME));
29417c478bd9Sstevel@tonic-gate }
29427c478bd9Sstevel@tonic-gate 
29437c478bd9Sstevel@tonic-gate /*
29447c478bd9Sstevel@tonic-gate  * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
29457c478bd9Sstevel@tonic-gate  * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
29467c478bd9Sstevel@tonic-gate  */
29477c478bd9Sstevel@tonic-gate scf_instance_t *
scf_instance_create(scf_handle_t * handle)29487c478bd9Sstevel@tonic-gate scf_instance_create(scf_handle_t *handle)
29497c478bd9Sstevel@tonic-gate {
29507c478bd9Sstevel@tonic-gate 	scf_instance_t *ret;
29517c478bd9Sstevel@tonic-gate 
29527c478bd9Sstevel@tonic-gate 	ret = uu_zalloc(sizeof (*ret));
29537c478bd9Sstevel@tonic-gate 	if (ret != NULL) {
29547c478bd9Sstevel@tonic-gate 		if (datael_init(&ret->rd_d, handle,
29557c478bd9Sstevel@tonic-gate 		    REP_PROTOCOL_ENTITY_INSTANCE) == -1) {
29567c478bd9Sstevel@tonic-gate 			uu_free(ret);
29577c478bd9Sstevel@tonic-gate 			return (NULL);
29587c478bd9Sstevel@tonic-gate 		}
29597c478bd9Sstevel@tonic-gate 	} else {
29607c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
29617c478bd9Sstevel@tonic-gate 	}
29627c478bd9Sstevel@tonic-gate 
29637c478bd9Sstevel@tonic-gate 	return (ret);
29647c478bd9Sstevel@tonic-gate }
29657c478bd9Sstevel@tonic-gate 
29667c478bd9Sstevel@tonic-gate scf_handle_t *
scf_instance_handle(const scf_instance_t * val)29677c478bd9Sstevel@tonic-gate scf_instance_handle(const scf_instance_t *val)
29687c478bd9Sstevel@tonic-gate {
29697c478bd9Sstevel@tonic-gate 	return (datael_handle(&val->rd_d));
29707c478bd9Sstevel@tonic-gate }
29717c478bd9Sstevel@tonic-gate 
29727c478bd9Sstevel@tonic-gate void
scf_instance_destroy(scf_instance_t * val)29737c478bd9Sstevel@tonic-gate scf_instance_destroy(scf_instance_t *val)
29747c478bd9Sstevel@tonic-gate {
29757c478bd9Sstevel@tonic-gate 	if (val == NULL)
29767c478bd9Sstevel@tonic-gate 		return;
29777c478bd9Sstevel@tonic-gate 
29787c478bd9Sstevel@tonic-gate 	datael_destroy(&val->rd_d);
29797c478bd9Sstevel@tonic-gate 	uu_free(val);
29807c478bd9Sstevel@tonic-gate }
29817c478bd9Sstevel@tonic-gate 
29827c478bd9Sstevel@tonic-gate ssize_t
scf_instance_get_name(const scf_instance_t * rep,char * out,size_t len)29837c478bd9Sstevel@tonic-gate scf_instance_get_name(const scf_instance_t *rep, char *out, size_t len)
29847c478bd9Sstevel@tonic-gate {
29857c478bd9Sstevel@tonic-gate 	return (datael_get_name(&rep->rd_d, out, len, RP_ENTITY_NAME_NAME));
29867c478bd9Sstevel@tonic-gate }
29877c478bd9Sstevel@tonic-gate 
29887c478bd9Sstevel@tonic-gate /*
29897c478bd9Sstevel@tonic-gate  * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
29907c478bd9Sstevel@tonic-gate  * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
29917c478bd9Sstevel@tonic-gate  */
29927c478bd9Sstevel@tonic-gate scf_snapshot_t *
scf_snapshot_create(scf_handle_t * handle)29937c478bd9Sstevel@tonic-gate scf_snapshot_create(scf_handle_t *handle)
29947c478bd9Sstevel@tonic-gate {
29957c478bd9Sstevel@tonic-gate 	scf_snapshot_t *ret;
29967c478bd9Sstevel@tonic-gate 
29977c478bd9Sstevel@tonic-gate 	ret = uu_zalloc(sizeof (*ret));
29987c478bd9Sstevel@tonic-gate 	if (ret != NULL) {
29997c478bd9Sstevel@tonic-gate 		if (datael_init(&ret->rd_d, handle,
30007c478bd9Sstevel@tonic-gate 		    REP_PROTOCOL_ENTITY_SNAPSHOT) == -1) {
30017c478bd9Sstevel@tonic-gate 			uu_free(ret);
30027c478bd9Sstevel@tonic-gate 			return (NULL);
30037c478bd9Sstevel@tonic-gate 		}
30047c478bd9Sstevel@tonic-gate 	} else {
30057c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
30067c478bd9Sstevel@tonic-gate 	}
30077c478bd9Sstevel@tonic-gate 
30087c478bd9Sstevel@tonic-gate 	return (ret);
30097c478bd9Sstevel@tonic-gate }
30107c478bd9Sstevel@tonic-gate 
30117c478bd9Sstevel@tonic-gate scf_handle_t *
scf_snapshot_handle(const scf_snapshot_t * val)30127c478bd9Sstevel@tonic-gate scf_snapshot_handle(const scf_snapshot_t *val)
30137c478bd9Sstevel@tonic-gate {
30147c478bd9Sstevel@tonic-gate 	return (datael_handle(&val->rd_d));
30157c478bd9Sstevel@tonic-gate }
30167c478bd9Sstevel@tonic-gate 
30177c478bd9Sstevel@tonic-gate void
scf_snapshot_destroy(scf_snapshot_t * val)30187c478bd9Sstevel@tonic-gate scf_snapshot_destroy(scf_snapshot_t *val)
30197c478bd9Sstevel@tonic-gate {
30207c478bd9Sstevel@tonic-gate 	if (val == NULL)
30217c478bd9Sstevel@tonic-gate 		return;
30227c478bd9Sstevel@tonic-gate 
30237c478bd9Sstevel@tonic-gate 	datael_destroy(&val->rd_d);
30247c478bd9Sstevel@tonic-gate 	uu_free(val);
30257c478bd9Sstevel@tonic-gate }
30267c478bd9Sstevel@tonic-gate 
30277c478bd9Sstevel@tonic-gate ssize_t
scf_snapshot_get_name(const scf_snapshot_t * rep,char * out,size_t len)30287c478bd9Sstevel@tonic-gate scf_snapshot_get_name(const scf_snapshot_t *rep, char *out, size_t len)
30297c478bd9Sstevel@tonic-gate {
30307c478bd9Sstevel@tonic-gate 	return (datael_get_name(&rep->rd_d, out, len, RP_ENTITY_NAME_NAME));
30317c478bd9Sstevel@tonic-gate }
30327c478bd9Sstevel@tonic-gate 
30337c478bd9Sstevel@tonic-gate /*
30347c478bd9Sstevel@tonic-gate  * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
30357c478bd9Sstevel@tonic-gate  * (bad server response or id in use), _NO_RESOURCES, _NO_MEMORY.
30367c478bd9Sstevel@tonic-gate  */
30377c478bd9Sstevel@tonic-gate scf_snaplevel_t *
scf_snaplevel_create(scf_handle_t * handle)30387c478bd9Sstevel@tonic-gate scf_snaplevel_create(scf_handle_t *handle)
30397c478bd9Sstevel@tonic-gate {
30407c478bd9Sstevel@tonic-gate 	scf_snaplevel_t *ret;
30417c478bd9Sstevel@tonic-gate 
30427c478bd9Sstevel@tonic-gate 	ret = uu_zalloc(sizeof (*ret));
30437c478bd9Sstevel@tonic-gate 	if (ret != NULL) {
30447c478bd9Sstevel@tonic-gate 		if (datael_init(&ret->rd_d, handle,
30457c478bd9Sstevel@tonic-gate 		    REP_PROTOCOL_ENTITY_SNAPLEVEL) == -1) {
30467c478bd9Sstevel@tonic-gate 			uu_free(ret);
30477c478bd9Sstevel@tonic-gate 			return (NULL);
30487c478bd9Sstevel@tonic-gate 		}
30497c478bd9Sstevel@tonic-gate 	} else {
30507c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
30517c478bd9Sstevel@tonic-gate 	}
30527c478bd9Sstevel@tonic-gate 
30537c478bd9Sstevel@tonic-gate 	return (ret);
30547c478bd9Sstevel@tonic-gate }
30557c478bd9Sstevel@tonic-gate 
30567c478bd9Sstevel@tonic-gate scf_handle_t *
scf_snaplevel_handle(const scf_snaplevel_t * val)30577c478bd9Sstevel@tonic-gate scf_snaplevel_handle(const scf_snaplevel_t *val)
30587c478bd9Sstevel@tonic-gate {
30597c478bd9Sstevel@tonic-gate 	return (datael_handle(&val->rd_d));
30607c478bd9Sstevel@tonic-gate }
30617c478bd9Sstevel@tonic-gate 
30627c478bd9Sstevel@tonic-gate void
scf_snaplevel_destroy(scf_snaplevel_t * val)30637c478bd9Sstevel@tonic-gate scf_snaplevel_destroy(scf_snaplevel_t *val)
30647c478bd9Sstevel@tonic-gate {
30657c478bd9Sstevel@tonic-gate 	if (val == NULL)
30667c478bd9Sstevel@tonic-gate 		return;
30677c478bd9Sstevel@tonic-gate 
30687c478bd9Sstevel@tonic-gate 	datael_destroy(&val->rd_d);
30697c478bd9Sstevel@tonic-gate 	uu_free(val);
30707c478bd9Sstevel@tonic-gate }
30717c478bd9Sstevel@tonic-gate 
30727c478bd9Sstevel@tonic-gate ssize_t
scf_snaplevel_get_scope_name(const scf_snaplevel_t * rep,char * out,size_t len)30737c478bd9Sstevel@tonic-gate scf_snaplevel_get_scope_name(const scf_snaplevel_t *rep, char *out, size_t len)
30747c478bd9Sstevel@tonic-gate {
30757c478bd9Sstevel@tonic-gate 	return (datael_get_name(&rep->rd_d, out, len,
30767c478bd9Sstevel@tonic-gate 	    RP_ENTITY_NAME_SNAPLEVEL_SCOPE));
30777c478bd9Sstevel@tonic-gate }
30787c478bd9Sstevel@tonic-gate 
30797c478bd9Sstevel@tonic-gate ssize_t
scf_snaplevel_get_service_name(const scf_snaplevel_t * rep,char * out,size_t len)30807c478bd9Sstevel@tonic-gate scf_snaplevel_get_service_name(const scf_snaplevel_t *rep, char *out,
30817c478bd9Sstevel@tonic-gate     size_t len)
30827c478bd9Sstevel@tonic-gate {
30837c478bd9Sstevel@tonic-gate 	return (datael_get_name(&rep->rd_d, out, len,
30847c478bd9Sstevel@tonic-gate 	    RP_ENTITY_NAME_SNAPLEVEL_SERVICE));
30857c478bd9Sstevel@tonic-gate }
30867c478bd9Sstevel@tonic-gate 
30877c478bd9Sstevel@tonic-gate ssize_t
scf_snaplevel_get_instance_name(const scf_snaplevel_t * rep,char * out,size_t len)30887c478bd9Sstevel@tonic-gate scf_snaplevel_get_instance_name(const scf_snaplevel_t *rep, char *out,
30897c478bd9Sstevel@tonic-gate     size_t len)
30907c478bd9Sstevel@tonic-gate {
30917c478bd9Sstevel@tonic-gate 	return (datael_get_name(&rep->rd_d, out, len,
30927c478bd9Sstevel@tonic-gate 	    RP_ENTITY_NAME_SNAPLEVEL_INSTANCE));
30937c478bd9Sstevel@tonic-gate }
30947c478bd9Sstevel@tonic-gate 
309576cf44abSjeanm /*
309676cf44abSjeanm  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
309776cf44abSjeanm  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
309876cf44abSjeanm  * _BACKEND_ACCESS, _NOT_FOUND.
309976cf44abSjeanm  */
31007c478bd9Sstevel@tonic-gate int
scf_snaplevel_get_pg(const scf_snaplevel_t * snap,const char * name,scf_propertygroup_t * pg)31017c478bd9Sstevel@tonic-gate scf_snaplevel_get_pg(const scf_snaplevel_t *snap, const char *name,
31027c478bd9Sstevel@tonic-gate     scf_propertygroup_t *pg)
31037c478bd9Sstevel@tonic-gate {
31047c478bd9Sstevel@tonic-gate 	return (datael_get_child(&snap->rd_d, name,
31057c478bd9Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_PROPERTYGRP, pg ? &pg->rd_d : NULL, 0));
31067c478bd9Sstevel@tonic-gate }
31077c478bd9Sstevel@tonic-gate 
31087c478bd9Sstevel@tonic-gate static int
snaplevel_next(const scf_datael_t * src,scf_snaplevel_t * dst_arg)31097c478bd9Sstevel@tonic-gate snaplevel_next(const scf_datael_t *src, scf_snaplevel_t *dst_arg)
31107c478bd9Sstevel@tonic-gate {
31117c478bd9Sstevel@tonic-gate 	scf_handle_t *h = src->rd_handle;
31127c478bd9Sstevel@tonic-gate 	scf_snaplevel_t *dst = dst_arg;
31137c478bd9Sstevel@tonic-gate 	struct rep_protocol_entity_pair request;
31147c478bd9Sstevel@tonic-gate 	struct rep_protocol_response response;
31157c478bd9Sstevel@tonic-gate 	int r;
31167c478bd9Sstevel@tonic-gate 	int dups = 0;
31177c478bd9Sstevel@tonic-gate 
31187c478bd9Sstevel@tonic-gate 	if (h != dst->rd_d.rd_handle)
31197c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
31207c478bd9Sstevel@tonic-gate 
31217c478bd9Sstevel@tonic-gate 	if (src == &dst->rd_d) {
31227c478bd9Sstevel@tonic-gate 		dups = 1;
31237c478bd9Sstevel@tonic-gate 		dst = HANDLE_HOLD_SNAPLVL(h);
31247c478bd9Sstevel@tonic-gate 	}
31257c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
31267c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_NEXT_SNAPLEVEL;
31277c478bd9Sstevel@tonic-gate 	request.rpr_entity_src = src->rd_entity;
31287c478bd9Sstevel@tonic-gate 	request.rpr_entity_dst = dst->rd_d.rd_entity;
31297c478bd9Sstevel@tonic-gate 
31307c478bd9Sstevel@tonic-gate 	datael_finish_reset(src);
31317c478bd9Sstevel@tonic-gate 	datael_finish_reset(&dst->rd_d);
31327c478bd9Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
31337c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
31347c478bd9Sstevel@tonic-gate 	/*
31357c478bd9Sstevel@tonic-gate 	 * if we succeeded, we need to swap dst and dst_arg's identity.  We
31367c478bd9Sstevel@tonic-gate 	 * take advantage of the fact that the only in-library knowledge is
31377c478bd9Sstevel@tonic-gate 	 * their entity ids.
31387c478bd9Sstevel@tonic-gate 	 */
31397c478bd9Sstevel@tonic-gate 	if (dups && r >= 0 &&
31407c478bd9Sstevel@tonic-gate 	    (response.rpr_response == REP_PROTOCOL_SUCCESS ||
31417c478bd9Sstevel@tonic-gate 	    response.rpr_response == REP_PROTOCOL_DONE)) {
31427c478bd9Sstevel@tonic-gate 		int entity = dst->rd_d.rd_entity;
31437c478bd9Sstevel@tonic-gate 
31447c478bd9Sstevel@tonic-gate 		dst->rd_d.rd_entity = dst_arg->rd_d.rd_entity;
31457c478bd9Sstevel@tonic-gate 		dst_arg->rd_d.rd_entity = entity;
31467c478bd9Sstevel@tonic-gate 	}
31477c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
31487c478bd9Sstevel@tonic-gate 
31497c478bd9Sstevel@tonic-gate 	if (dups)
31507c478bd9Sstevel@tonic-gate 		HANDLE_RELE_SNAPLVL(h);
31517c478bd9Sstevel@tonic-gate 
31527c478bd9Sstevel@tonic-gate 	if (r < 0)
31537c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
31547c478bd9Sstevel@tonic-gate 
31557c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS &&
31567c478bd9Sstevel@tonic-gate 	    response.rpr_response != REP_PROTOCOL_DONE) {
31577c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
31587c478bd9Sstevel@tonic-gate 	}
31597c478bd9Sstevel@tonic-gate 
31607c478bd9Sstevel@tonic-gate 	return (response.rpr_response == REP_PROTOCOL_SUCCESS) ?
31617c478bd9Sstevel@tonic-gate 	    SCF_SUCCESS : SCF_COMPLETE;
31627c478bd9Sstevel@tonic-gate }
31637c478bd9Sstevel@tonic-gate 
scf_snapshot_get_base_snaplevel(const scf_snapshot_t * base,scf_snaplevel_t * out)31647c478bd9Sstevel@tonic-gate int scf_snapshot_get_base_snaplevel(const scf_snapshot_t *base,
31657c478bd9Sstevel@tonic-gate     scf_snaplevel_t *out)
31667c478bd9Sstevel@tonic-gate {
31677c478bd9Sstevel@tonic-gate 	return (snaplevel_next(&base->rd_d, out));
31687c478bd9Sstevel@tonic-gate }
31697c478bd9Sstevel@tonic-gate 
scf_snaplevel_get_next_snaplevel(const scf_snaplevel_t * base,scf_snaplevel_t * out)31707c478bd9Sstevel@tonic-gate int scf_snaplevel_get_next_snaplevel(const scf_snaplevel_t *base,
31717c478bd9Sstevel@tonic-gate     scf_snaplevel_t *out)
31727c478bd9Sstevel@tonic-gate {
31737c478bd9Sstevel@tonic-gate 	return (snaplevel_next(&base->rd_d, out));
31747c478bd9Sstevel@tonic-gate }
31757c478bd9Sstevel@tonic-gate 
31767c478bd9Sstevel@tonic-gate /*
31777c478bd9Sstevel@tonic-gate  * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
31787c478bd9Sstevel@tonic-gate  * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
31797c478bd9Sstevel@tonic-gate  */
31807c478bd9Sstevel@tonic-gate scf_propertygroup_t *
scf_pg_create(scf_handle_t * handle)31817c478bd9Sstevel@tonic-gate scf_pg_create(scf_handle_t *handle)
31827c478bd9Sstevel@tonic-gate {
31837c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *ret;
31847c478bd9Sstevel@tonic-gate 	ret = uu_zalloc(sizeof (*ret));
31857c478bd9Sstevel@tonic-gate 	if (ret != NULL) {
31867c478bd9Sstevel@tonic-gate 		if (datael_init(&ret->rd_d, handle,
31877c478bd9Sstevel@tonic-gate 		    REP_PROTOCOL_ENTITY_PROPERTYGRP) == -1) {
31887c478bd9Sstevel@tonic-gate 			uu_free(ret);
31897c478bd9Sstevel@tonic-gate 			return (NULL);
31907c478bd9Sstevel@tonic-gate 		}
31917c478bd9Sstevel@tonic-gate 	} else {
31927c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
31937c478bd9Sstevel@tonic-gate 	}
31947c478bd9Sstevel@tonic-gate 
31957c478bd9Sstevel@tonic-gate 	return (ret);
31967c478bd9Sstevel@tonic-gate }
31977c478bd9Sstevel@tonic-gate 
31987c478bd9Sstevel@tonic-gate scf_handle_t *
scf_pg_handle(const scf_propertygroup_t * val)31997c478bd9Sstevel@tonic-gate scf_pg_handle(const scf_propertygroup_t *val)
32007c478bd9Sstevel@tonic-gate {
32017c478bd9Sstevel@tonic-gate 	return (datael_handle(&val->rd_d));
32027c478bd9Sstevel@tonic-gate }
32037c478bd9Sstevel@tonic-gate 
32047c478bd9Sstevel@tonic-gate void
scf_pg_destroy(scf_propertygroup_t * val)32057c478bd9Sstevel@tonic-gate scf_pg_destroy(scf_propertygroup_t *val)
32067c478bd9Sstevel@tonic-gate {
32077c478bd9Sstevel@tonic-gate 	if (val == NULL)
32087c478bd9Sstevel@tonic-gate 		return;
32097c478bd9Sstevel@tonic-gate 
32107c478bd9Sstevel@tonic-gate 	datael_destroy(&val->rd_d);
32117c478bd9Sstevel@tonic-gate 	uu_free(val);
32127c478bd9Sstevel@tonic-gate }
32137c478bd9Sstevel@tonic-gate 
32147c478bd9Sstevel@tonic-gate ssize_t
scf_pg_get_name(const scf_propertygroup_t * pg,char * out,size_t len)32157c478bd9Sstevel@tonic-gate scf_pg_get_name(const scf_propertygroup_t *pg,  char *out, size_t len)
32167c478bd9Sstevel@tonic-gate {
32177c478bd9Sstevel@tonic-gate 	return (datael_get_name(&pg->rd_d, out, len, RP_ENTITY_NAME_NAME));
32187c478bd9Sstevel@tonic-gate }
32197c478bd9Sstevel@tonic-gate 
32207c478bd9Sstevel@tonic-gate ssize_t
scf_pg_get_type(const scf_propertygroup_t * pg,char * out,size_t len)32217c478bd9Sstevel@tonic-gate scf_pg_get_type(const scf_propertygroup_t *pg,  char *out, size_t len)
32227c478bd9Sstevel@tonic-gate {
32237c478bd9Sstevel@tonic-gate 	return (datael_get_name(&pg->rd_d, out, len, RP_ENTITY_NAME_PGTYPE));
32247c478bd9Sstevel@tonic-gate }
32257c478bd9Sstevel@tonic-gate 
32267c478bd9Sstevel@tonic-gate int
scf_pg_get_flags(const scf_propertygroup_t * pg,uint32_t * out)32277c478bd9Sstevel@tonic-gate scf_pg_get_flags(const scf_propertygroup_t *pg, uint32_t *out)
32287c478bd9Sstevel@tonic-gate {
32297c478bd9Sstevel@tonic-gate 	char buf[REP_PROTOCOL_NAME_LEN];
32307c478bd9Sstevel@tonic-gate 	ssize_t res;
32317c478bd9Sstevel@tonic-gate 
32327c478bd9Sstevel@tonic-gate 	res = datael_get_name(&pg->rd_d, buf, sizeof (buf),
32337c478bd9Sstevel@tonic-gate 	    RP_ENTITY_NAME_PGFLAGS);
32347c478bd9Sstevel@tonic-gate 
32357c478bd9Sstevel@tonic-gate 	if (res == -1)
32367c478bd9Sstevel@tonic-gate 		return (-1);
32377c478bd9Sstevel@tonic-gate 
32387c478bd9Sstevel@tonic-gate 	if (uu_strtouint(buf, out, sizeof (*out), 0, 0, UINT32_MAX) == -1)
32397c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INTERNAL));
32407c478bd9Sstevel@tonic-gate 
32417c478bd9Sstevel@tonic-gate 	return (0);
32427c478bd9Sstevel@tonic-gate }
32437c478bd9Sstevel@tonic-gate 
32447c478bd9Sstevel@tonic-gate static int
datael_update(scf_datael_t * dp)32457c478bd9Sstevel@tonic-gate datael_update(scf_datael_t *dp)
32467c478bd9Sstevel@tonic-gate {
32477c478bd9Sstevel@tonic-gate 	scf_handle_t *h = dp->rd_handle;
32487c478bd9Sstevel@tonic-gate 
32497c478bd9Sstevel@tonic-gate 	struct rep_protocol_entity_update request;
32507c478bd9Sstevel@tonic-gate 	struct rep_protocol_response response;
32517c478bd9Sstevel@tonic-gate 
32527c478bd9Sstevel@tonic-gate 	int r;
32537c478bd9Sstevel@tonic-gate 
32547c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
32557c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ENTITY_UPDATE;
32567c478bd9Sstevel@tonic-gate 	request.rpr_entityid = dp->rd_entity;
32577c478bd9Sstevel@tonic-gate 
32587c478bd9Sstevel@tonic-gate 	datael_finish_reset(dp);
32598918dff3Sjwadams 	request.rpr_changeid = handle_next_changeid(h);
32607c478bd9Sstevel@tonic-gate 
32617c478bd9Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
32627c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
32637c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
32647c478bd9Sstevel@tonic-gate 
32657c478bd9Sstevel@tonic-gate 	if (r < 0)
32667c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
32677c478bd9Sstevel@tonic-gate 
326876cf44abSjeanm 	/*
326976cf44abSjeanm 	 * This should never happen but if it does something has
327076cf44abSjeanm 	 * gone terribly wrong and we should abort.
327176cf44abSjeanm 	 */
327276cf44abSjeanm 	if (response.rpr_response == REP_PROTOCOL_FAIL_BAD_REQUEST)
327376cf44abSjeanm 		abort();
327476cf44abSjeanm 
32757c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS &&
32767c478bd9Sstevel@tonic-gate 	    response.rpr_response != REP_PROTOCOL_DONE) {
32777c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
32787c478bd9Sstevel@tonic-gate 	}
32797c478bd9Sstevel@tonic-gate 
32807c478bd9Sstevel@tonic-gate 	return (response.rpr_response == REP_PROTOCOL_SUCCESS) ?
32817c478bd9Sstevel@tonic-gate 	    SCF_SUCCESS : SCF_COMPLETE;
32827c478bd9Sstevel@tonic-gate }
32837c478bd9Sstevel@tonic-gate 
32847c478bd9Sstevel@tonic-gate int
scf_pg_update(scf_propertygroup_t * pg)32857c478bd9Sstevel@tonic-gate scf_pg_update(scf_propertygroup_t *pg)
32867c478bd9Sstevel@tonic-gate {
32877c478bd9Sstevel@tonic-gate 	return (datael_update(&pg->rd_d));
32887c478bd9Sstevel@tonic-gate }
32897c478bd9Sstevel@tonic-gate 
32907c478bd9Sstevel@tonic-gate int
scf_snapshot_update(scf_snapshot_t * snap)32917c478bd9Sstevel@tonic-gate scf_snapshot_update(scf_snapshot_t *snap)
32927c478bd9Sstevel@tonic-gate {
32937c478bd9Sstevel@tonic-gate 	return (datael_update(&snap->rd_d));
32947c478bd9Sstevel@tonic-gate }
32957c478bd9Sstevel@tonic-gate 
32967c478bd9Sstevel@tonic-gate int
_scf_pg_wait(scf_propertygroup_t * pg,int timeout)32977c478bd9Sstevel@tonic-gate _scf_pg_wait(scf_propertygroup_t *pg, int timeout)
32987c478bd9Sstevel@tonic-gate {
32997c478bd9Sstevel@tonic-gate 	scf_handle_t *h = pg->rd_d.rd_handle;
33007c478bd9Sstevel@tonic-gate 
33017c478bd9Sstevel@tonic-gate 	struct rep_protocol_propertygrp_request request;
33027c478bd9Sstevel@tonic-gate 	struct rep_protocol_response response;
33037c478bd9Sstevel@tonic-gate 
33047c478bd9Sstevel@tonic-gate 	struct pollfd pollfd;
33057c478bd9Sstevel@tonic-gate 
33067c478bd9Sstevel@tonic-gate 	int r;
33077c478bd9Sstevel@tonic-gate 
33087c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
33097c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_PROPERTYGRP_SETUP_WAIT;
33107c478bd9Sstevel@tonic-gate 	request.rpr_entityid = pg->rd_d.rd_entity;
33117c478bd9Sstevel@tonic-gate 
33127c478bd9Sstevel@tonic-gate 	datael_finish_reset(&pg->rd_d);
33137c478bd9Sstevel@tonic-gate 	if (!handle_is_bound(h)) {
33147c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
33157c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN));
33167c478bd9Sstevel@tonic-gate 	}
33177c478bd9Sstevel@tonic-gate 	r = make_door_call_retfd(h->rh_doorfd, &request, sizeof (request),
33187c478bd9Sstevel@tonic-gate 	    &response, sizeof (response), &pollfd.fd);
33197c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
33207c478bd9Sstevel@tonic-gate 
33217c478bd9Sstevel@tonic-gate 	if (r < 0)
33227c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
33237c478bd9Sstevel@tonic-gate 
33247c478bd9Sstevel@tonic-gate 	assert((response.rpr_response == REP_PROTOCOL_SUCCESS) ==
33257c478bd9Sstevel@tonic-gate 	    (pollfd.fd != -1));
33267c478bd9Sstevel@tonic-gate 
33277c478bd9Sstevel@tonic-gate 	if (response.rpr_response == REP_PROTOCOL_FAIL_NOT_LATEST)
33287c478bd9Sstevel@tonic-gate 		return (SCF_SUCCESS);
33297c478bd9Sstevel@tonic-gate 
33307c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
33317c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
33327c478bd9Sstevel@tonic-gate 
33337c478bd9Sstevel@tonic-gate 	pollfd.events = 0;
33347c478bd9Sstevel@tonic-gate 	pollfd.revents = 0;
33357c478bd9Sstevel@tonic-gate 
33367c478bd9Sstevel@tonic-gate 	r = poll(&pollfd, 1, timeout * MILLISEC);
33377c478bd9Sstevel@tonic-gate 
33387c478bd9Sstevel@tonic-gate 	(void) close(pollfd.fd);
33397c478bd9Sstevel@tonic-gate 	return (pollfd.revents ? SCF_SUCCESS : SCF_COMPLETE);
33407c478bd9Sstevel@tonic-gate }
33417c478bd9Sstevel@tonic-gate 
33427c478bd9Sstevel@tonic-gate static int
scf_notify_add_pattern(scf_handle_t * h,int type,const char * name)33437c478bd9Sstevel@tonic-gate scf_notify_add_pattern(scf_handle_t *h, int type, const char *name)
33447c478bd9Sstevel@tonic-gate {
33457c478bd9Sstevel@tonic-gate 	struct rep_protocol_notify_request request;
33467c478bd9Sstevel@tonic-gate 	struct rep_protocol_response response;
33477c478bd9Sstevel@tonic-gate 	int r;
33487c478bd9Sstevel@tonic-gate 
33497c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
33507c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_CLIENT_ADD_NOTIFY;
33517c478bd9Sstevel@tonic-gate 	request.rpr_type = type;
33527c478bd9Sstevel@tonic-gate 	(void) strlcpy(request.rpr_pattern, name, sizeof (request.rpr_pattern));
33537c478bd9Sstevel@tonic-gate 
33547c478bd9Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
33557c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
33567c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
33577c478bd9Sstevel@tonic-gate 
33587c478bd9Sstevel@tonic-gate 	if (r < 0)
33597c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
33607c478bd9Sstevel@tonic-gate 
33617c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
33627c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
33637c478bd9Sstevel@tonic-gate 
33647c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
33657c478bd9Sstevel@tonic-gate }
33667c478bd9Sstevel@tonic-gate 
33677c478bd9Sstevel@tonic-gate int
_scf_notify_add_pgname(scf_handle_t * h,const char * name)33687c478bd9Sstevel@tonic-gate _scf_notify_add_pgname(scf_handle_t *h, const char *name)
33697c478bd9Sstevel@tonic-gate {
33707c478bd9Sstevel@tonic-gate 	return (scf_notify_add_pattern(h, REP_PROTOCOL_NOTIFY_PGNAME, name));
33717c478bd9Sstevel@tonic-gate }
33727c478bd9Sstevel@tonic-gate 
33737c478bd9Sstevel@tonic-gate int
_scf_notify_add_pgtype(scf_handle_t * h,const char * type)33747c478bd9Sstevel@tonic-gate _scf_notify_add_pgtype(scf_handle_t *h, const char *type)
33757c478bd9Sstevel@tonic-gate {
33767c478bd9Sstevel@tonic-gate 	return (scf_notify_add_pattern(h, REP_PROTOCOL_NOTIFY_PGTYPE, type));
33777c478bd9Sstevel@tonic-gate }
33787c478bd9Sstevel@tonic-gate 
33797c478bd9Sstevel@tonic-gate int
_scf_notify_wait(scf_propertygroup_t * pg,char * out,size_t sz)33807c478bd9Sstevel@tonic-gate _scf_notify_wait(scf_propertygroup_t *pg, char *out, size_t sz)
33817c478bd9Sstevel@tonic-gate {
33827c478bd9Sstevel@tonic-gate 	struct rep_protocol_wait_request request;
33837c478bd9Sstevel@tonic-gate 	struct rep_protocol_fmri_response response;
33847c478bd9Sstevel@tonic-gate 
33857c478bd9Sstevel@tonic-gate 	scf_handle_t *h = pg->rd_d.rd_handle;
33867c478bd9Sstevel@tonic-gate 	int dummy;
33877c478bd9Sstevel@tonic-gate 	int fd;
33887c478bd9Sstevel@tonic-gate 	int r;
33897c478bd9Sstevel@tonic-gate 
33907c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
33917c478bd9Sstevel@tonic-gate 	datael_finish_reset(&pg->rd_d);
33927c478bd9Sstevel@tonic-gate 	if (!handle_is_bound(h)) {
33937c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
33947c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN));
33957c478bd9Sstevel@tonic-gate 	}
33967c478bd9Sstevel@tonic-gate 	fd = h->rh_doorfd;
33977c478bd9Sstevel@tonic-gate 	++h->rh_fd_users;
33987c478bd9Sstevel@tonic-gate 	assert(h->rh_fd_users > 0);
33997c478bd9Sstevel@tonic-gate 
34007c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_CLIENT_WAIT;
34017c478bd9Sstevel@tonic-gate 	request.rpr_entityid = pg->rd_d.rd_entity;
34027c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
34037c478bd9Sstevel@tonic-gate 
34047c478bd9Sstevel@tonic-gate 	r = make_door_call_retfd(fd, &request, sizeof (request),
34057c478bd9Sstevel@tonic-gate 	    &response, sizeof (response), &dummy);
34067c478bd9Sstevel@tonic-gate 
34077c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
34087c478bd9Sstevel@tonic-gate 	assert(h->rh_fd_users > 0);
34097c478bd9Sstevel@tonic-gate 	if (--h->rh_fd_users == 0) {
34107c478bd9Sstevel@tonic-gate 		(void) pthread_cond_broadcast(&h->rh_cv);
34117c478bd9Sstevel@tonic-gate 		/*
34127c478bd9Sstevel@tonic-gate 		 * check for a delayed close, now that there are no other
34137c478bd9Sstevel@tonic-gate 		 * users.
34147c478bd9Sstevel@tonic-gate 		 */
34157c478bd9Sstevel@tonic-gate 		if (h->rh_doorfd_old != -1) {
34167c478bd9Sstevel@tonic-gate 			assert(h->rh_doorfd == -1);
34177c478bd9Sstevel@tonic-gate 			assert(fd == h->rh_doorfd_old);
34187c478bd9Sstevel@tonic-gate 			(void) close(h->rh_doorfd_old);
34197c478bd9Sstevel@tonic-gate 			h->rh_doorfd_old = -1;
34207c478bd9Sstevel@tonic-gate 		}
34217c478bd9Sstevel@tonic-gate 	}
34227c478bd9Sstevel@tonic-gate 	handle_unrefed(h);			/* drops h->rh_lock */
34237c478bd9Sstevel@tonic-gate 
34247c478bd9Sstevel@tonic-gate 	if (r < 0)
34257c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
34267c478bd9Sstevel@tonic-gate 
34277c478bd9Sstevel@tonic-gate 	if (response.rpr_response == REP_PROTOCOL_DONE)
34287c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_NOT_SET));
34297c478bd9Sstevel@tonic-gate 
34307c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
34317c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
34327c478bd9Sstevel@tonic-gate 
34337c478bd9Sstevel@tonic-gate 	/* the following will be non-zero for delete notifications */
34347c478bd9Sstevel@tonic-gate 	return (strlcpy(out, response.rpr_fmri, sz));
34357c478bd9Sstevel@tonic-gate }
34367c478bd9Sstevel@tonic-gate 
34377c478bd9Sstevel@tonic-gate static int
_scf_snapshot_take(scf_instance_t * inst,const char * name,scf_snapshot_t * snap,int flags)34387c478bd9Sstevel@tonic-gate _scf_snapshot_take(scf_instance_t *inst, const char *name,
34397c478bd9Sstevel@tonic-gate     scf_snapshot_t *snap, int flags)
34407c478bd9Sstevel@tonic-gate {
34417c478bd9Sstevel@tonic-gate 	scf_handle_t *h = inst->rd_d.rd_handle;
34427c478bd9Sstevel@tonic-gate 
34437c478bd9Sstevel@tonic-gate 	struct rep_protocol_snapshot_take request;
34447c478bd9Sstevel@tonic-gate 	struct rep_protocol_response response;
34457c478bd9Sstevel@tonic-gate 
34467c478bd9Sstevel@tonic-gate 	int r;
34477c478bd9Sstevel@tonic-gate 
34487c478bd9Sstevel@tonic-gate 	if (h != snap->rd_d.rd_handle)
34497c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
34507c478bd9Sstevel@tonic-gate 
34517c478bd9Sstevel@tonic-gate 	if (strlcpy(request.rpr_name, (name != NULL)? name : "",
34527c478bd9Sstevel@tonic-gate 	    sizeof (request.rpr_name)) >= sizeof (request.rpr_name))
34537c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
34547c478bd9Sstevel@tonic-gate 
34557c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
34567c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_SNAPSHOT_TAKE;
34577c478bd9Sstevel@tonic-gate 	request.rpr_entityid_src = inst->rd_d.rd_entity;
34587c478bd9Sstevel@tonic-gate 	request.rpr_entityid_dest = snap->rd_d.rd_entity;
34597c478bd9Sstevel@tonic-gate 	request.rpr_flags = flags;
34607c478bd9Sstevel@tonic-gate 
34617c478bd9Sstevel@tonic-gate 	datael_finish_reset(&inst->rd_d);
34627c478bd9Sstevel@tonic-gate 	datael_finish_reset(&snap->rd_d);
34637c478bd9Sstevel@tonic-gate 
34647c478bd9Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
34657c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
34667c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
34677c478bd9Sstevel@tonic-gate 
34687c478bd9Sstevel@tonic-gate 	if (r < 0)
34697c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
34707c478bd9Sstevel@tonic-gate 
34717c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
34727c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
34737c478bd9Sstevel@tonic-gate 
34747c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
34757c478bd9Sstevel@tonic-gate }
34767c478bd9Sstevel@tonic-gate 
34777c478bd9Sstevel@tonic-gate int
_scf_snapshot_take_new_named(scf_instance_t * inst,const char * svcname,const char * instname,const char * snapname,scf_snapshot_t * snap)34787c478bd9Sstevel@tonic-gate _scf_snapshot_take_new_named(scf_instance_t *inst,
34797c478bd9Sstevel@tonic-gate     const char *svcname, const char *instname, const char *snapname,
34807c478bd9Sstevel@tonic-gate     scf_snapshot_t *snap)
34817c478bd9Sstevel@tonic-gate {
34827c478bd9Sstevel@tonic-gate 	scf_handle_t *h = inst->rd_d.rd_handle;
34837c478bd9Sstevel@tonic-gate 
34847c478bd9Sstevel@tonic-gate 	struct rep_protocol_snapshot_take_named request;
34857c478bd9Sstevel@tonic-gate 	struct rep_protocol_response response;
34867c478bd9Sstevel@tonic-gate 
34877c478bd9Sstevel@tonic-gate 	int r;
34887c478bd9Sstevel@tonic-gate 
34897c478bd9Sstevel@tonic-gate 	if (h != snap->rd_d.rd_handle)
34907c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
34917c478bd9Sstevel@tonic-gate 
34927c478bd9Sstevel@tonic-gate 	if (strlcpy(request.rpr_svcname, svcname,
34937c478bd9Sstevel@tonic-gate 	    sizeof (request.rpr_svcname)) >= sizeof (request.rpr_svcname))
34947c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
34957c478bd9Sstevel@tonic-gate 
34967c478bd9Sstevel@tonic-gate 	if (strlcpy(request.rpr_instname, instname,
34977c478bd9Sstevel@tonic-gate 	    sizeof (request.rpr_instname)) >= sizeof (request.rpr_instname))
34987c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
34997c478bd9Sstevel@tonic-gate 
35007c478bd9Sstevel@tonic-gate 	if (strlcpy(request.rpr_name, snapname,
35017c478bd9Sstevel@tonic-gate 	    sizeof (request.rpr_name)) >= sizeof (request.rpr_name))
35027c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
35037c478bd9Sstevel@tonic-gate 
35047c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
35057c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_SNAPSHOT_TAKE_NAMED;
35067c478bd9Sstevel@tonic-gate 	request.rpr_entityid_src = inst->rd_d.rd_entity;
35077c478bd9Sstevel@tonic-gate 	request.rpr_entityid_dest = snap->rd_d.rd_entity;
35087c478bd9Sstevel@tonic-gate 
35097c478bd9Sstevel@tonic-gate 	datael_finish_reset(&inst->rd_d);
35107c478bd9Sstevel@tonic-gate 	datael_finish_reset(&snap->rd_d);
35117c478bd9Sstevel@tonic-gate 
35127c478bd9Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
35137c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
35147c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
35157c478bd9Sstevel@tonic-gate 
35167c478bd9Sstevel@tonic-gate 	if (r < 0)
35177c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
35187c478bd9Sstevel@tonic-gate 
35197c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
35207c478bd9Sstevel@tonic-gate 		assert(response.rpr_response !=
35217c478bd9Sstevel@tonic-gate 		    REP_PROTOCOL_FAIL_TYPE_MISMATCH);
35227c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
35237c478bd9Sstevel@tonic-gate 	}
35247c478bd9Sstevel@tonic-gate 
35257c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
35267c478bd9Sstevel@tonic-gate }
35277c478bd9Sstevel@tonic-gate 
35287c478bd9Sstevel@tonic-gate int
_scf_snapshot_take_new(scf_instance_t * inst,const char * name,scf_snapshot_t * snap)35297c478bd9Sstevel@tonic-gate _scf_snapshot_take_new(scf_instance_t *inst, const char *name,
35307c478bd9Sstevel@tonic-gate     scf_snapshot_t *snap)
35317c478bd9Sstevel@tonic-gate {
35327c478bd9Sstevel@tonic-gate 	return (_scf_snapshot_take(inst, name, snap, REP_SNAPSHOT_NEW));
35337c478bd9Sstevel@tonic-gate }
35347c478bd9Sstevel@tonic-gate 
35357c478bd9Sstevel@tonic-gate int
_scf_snapshot_take_attach(scf_instance_t * inst,scf_snapshot_t * snap)35367c478bd9Sstevel@tonic-gate _scf_snapshot_take_attach(scf_instance_t *inst, scf_snapshot_t *snap)
35377c478bd9Sstevel@tonic-gate {
35387c478bd9Sstevel@tonic-gate 	return (_scf_snapshot_take(inst, NULL, snap, REP_SNAPSHOT_ATTACH));
35397c478bd9Sstevel@tonic-gate }
35407c478bd9Sstevel@tonic-gate 
35417c478bd9Sstevel@tonic-gate int
_scf_snapshot_attach(scf_snapshot_t * src,scf_snapshot_t * dest)35427c478bd9Sstevel@tonic-gate _scf_snapshot_attach(scf_snapshot_t *src, scf_snapshot_t *dest)
35437c478bd9Sstevel@tonic-gate {
35447c478bd9Sstevel@tonic-gate 	scf_handle_t *h = dest->rd_d.rd_handle;
35457c478bd9Sstevel@tonic-gate 
35467c478bd9Sstevel@tonic-gate 	struct rep_protocol_snapshot_attach request;
35477c478bd9Sstevel@tonic-gate 	struct rep_protocol_response response;
35487c478bd9Sstevel@tonic-gate 
35497c478bd9Sstevel@tonic-gate 	int r;
35507c478bd9Sstevel@tonic-gate 
35517c478bd9Sstevel@tonic-gate 	if (h != src->rd_d.rd_handle)
35527c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
35537c478bd9Sstevel@tonic-gate 
35547c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
35557c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_SNAPSHOT_ATTACH;
35567c478bd9Sstevel@tonic-gate 	request.rpr_entityid_src = src->rd_d.rd_entity;
35577c478bd9Sstevel@tonic-gate 	request.rpr_entityid_dest = dest->rd_d.rd_entity;
35587c478bd9Sstevel@tonic-gate 
35597c478bd9Sstevel@tonic-gate 	datael_finish_reset(&src->rd_d);
35607c478bd9Sstevel@tonic-gate 	datael_finish_reset(&dest->rd_d);
35617c478bd9Sstevel@tonic-gate 
35627c478bd9Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
35637c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
35647c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
35657c478bd9Sstevel@tonic-gate 
35667c478bd9Sstevel@tonic-gate 	if (r < 0)
35677c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
35687c478bd9Sstevel@tonic-gate 
35697c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
35707c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
35717c478bd9Sstevel@tonic-gate 
35727c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
35737c478bd9Sstevel@tonic-gate }
35747c478bd9Sstevel@tonic-gate 
35757c478bd9Sstevel@tonic-gate /*
35767c478bd9Sstevel@tonic-gate  * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
35777c478bd9Sstevel@tonic-gate  * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
35787c478bd9Sstevel@tonic-gate  */
35797c478bd9Sstevel@tonic-gate scf_property_t *
scf_property_create(scf_handle_t * handle)35807c478bd9Sstevel@tonic-gate scf_property_create(scf_handle_t *handle)
35817c478bd9Sstevel@tonic-gate {
35827c478bd9Sstevel@tonic-gate 	scf_property_t *ret;
35837c478bd9Sstevel@tonic-gate 	ret = uu_zalloc(sizeof (*ret));
35847c478bd9Sstevel@tonic-gate 	if (ret != NULL) {
35857c478bd9Sstevel@tonic-gate 		if (datael_init(&ret->rd_d, handle,
35867c478bd9Sstevel@tonic-gate 		    REP_PROTOCOL_ENTITY_PROPERTY) == -1) {
35877c478bd9Sstevel@tonic-gate 			uu_free(ret);
35887c478bd9Sstevel@tonic-gate 			return (NULL);
35897c478bd9Sstevel@tonic-gate 		}
35907c478bd9Sstevel@tonic-gate 	} else {
35917c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
35927c478bd9Sstevel@tonic-gate 	}
35937c478bd9Sstevel@tonic-gate 
35947c478bd9Sstevel@tonic-gate 	return (ret);
35957c478bd9Sstevel@tonic-gate }
35967c478bd9Sstevel@tonic-gate 
35977c478bd9Sstevel@tonic-gate scf_handle_t *
scf_property_handle(const scf_property_t * val)35987c478bd9Sstevel@tonic-gate scf_property_handle(const scf_property_t *val)
35997c478bd9Sstevel@tonic-gate {
36007c478bd9Sstevel@tonic-gate 	return (datael_handle(&val->rd_d));
36017c478bd9Sstevel@tonic-gate }
36027c478bd9Sstevel@tonic-gate 
36037c478bd9Sstevel@tonic-gate void
scf_property_destroy(scf_property_t * val)36047c478bd9Sstevel@tonic-gate scf_property_destroy(scf_property_t *val)
36057c478bd9Sstevel@tonic-gate {
36067c478bd9Sstevel@tonic-gate 	if (val == NULL)
36077c478bd9Sstevel@tonic-gate 		return;
36087c478bd9Sstevel@tonic-gate 
36097c478bd9Sstevel@tonic-gate 	datael_destroy(&val->rd_d);
36107c478bd9Sstevel@tonic-gate 	uu_free(val);
36117c478bd9Sstevel@tonic-gate }
36127c478bd9Sstevel@tonic-gate 
36137c478bd9Sstevel@tonic-gate static int
property_type_locked(const scf_property_t * prop,rep_protocol_value_type_t * out)36147c478bd9Sstevel@tonic-gate property_type_locked(const scf_property_t *prop,
36157c478bd9Sstevel@tonic-gate     rep_protocol_value_type_t *out)
36167c478bd9Sstevel@tonic-gate {
36177c478bd9Sstevel@tonic-gate 	scf_handle_t *h = prop->rd_d.rd_handle;
36187c478bd9Sstevel@tonic-gate 
36197c478bd9Sstevel@tonic-gate 	struct rep_protocol_property_request request;
36207c478bd9Sstevel@tonic-gate 	struct rep_protocol_integer_response response;
36217c478bd9Sstevel@tonic-gate 
36227c478bd9Sstevel@tonic-gate 	int r;
36237c478bd9Sstevel@tonic-gate 
36247c478bd9Sstevel@tonic-gate 	assert(MUTEX_HELD(&h->rh_lock));
36257c478bd9Sstevel@tonic-gate 
36267c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_PROPERTY_GET_TYPE;
36277c478bd9Sstevel@tonic-gate 	request.rpr_entityid = prop->rd_d.rd_entity;
36287c478bd9Sstevel@tonic-gate 
36297c478bd9Sstevel@tonic-gate 	datael_finish_reset(&prop->rd_d);
36307c478bd9Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
36317c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
36327c478bd9Sstevel@tonic-gate 
36337c478bd9Sstevel@tonic-gate 	if (r < 0)
36347c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
36357c478bd9Sstevel@tonic-gate 
36367c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS ||
36377c478bd9Sstevel@tonic-gate 	    r < sizeof (response)) {
36387c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
36397c478bd9Sstevel@tonic-gate 	}
36407c478bd9Sstevel@tonic-gate 	*out = response.rpr_value;
36417c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
36427c478bd9Sstevel@tonic-gate }
36437c478bd9Sstevel@tonic-gate 
36447c478bd9Sstevel@tonic-gate int
scf_property_type(const scf_property_t * prop,scf_type_t * out)36457c478bd9Sstevel@tonic-gate scf_property_type(const scf_property_t *prop, scf_type_t *out)
36467c478bd9Sstevel@tonic-gate {
36477c478bd9Sstevel@tonic-gate 	scf_handle_t *h = prop->rd_d.rd_handle;
36487c478bd9Sstevel@tonic-gate 	rep_protocol_value_type_t out_raw;
36497c478bd9Sstevel@tonic-gate 	int ret;
36507c478bd9Sstevel@tonic-gate 
36517c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
36527c478bd9Sstevel@tonic-gate 	ret = property_type_locked(prop, &out_raw);
36537c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
36547c478bd9Sstevel@tonic-gate 
36557c478bd9Sstevel@tonic-gate 	if (ret == SCF_SUCCESS)
36567c478bd9Sstevel@tonic-gate 		*out = scf_protocol_type_to_type(out_raw);
36577c478bd9Sstevel@tonic-gate 
36587c478bd9Sstevel@tonic-gate 	return (ret);
36597c478bd9Sstevel@tonic-gate }
36607c478bd9Sstevel@tonic-gate 
36617c478bd9Sstevel@tonic-gate int
scf_property_is_type(const scf_property_t * prop,scf_type_t base_arg)36627c478bd9Sstevel@tonic-gate scf_property_is_type(const scf_property_t *prop, scf_type_t base_arg)
36637c478bd9Sstevel@tonic-gate {
36647c478bd9Sstevel@tonic-gate 	scf_handle_t *h = prop->rd_d.rd_handle;
36657c478bd9Sstevel@tonic-gate 	rep_protocol_value_type_t base = scf_type_to_protocol_type(base_arg);
36667c478bd9Sstevel@tonic-gate 	rep_protocol_value_type_t type;
36677c478bd9Sstevel@tonic-gate 	int ret;
36687c478bd9Sstevel@tonic-gate 
36697c478bd9Sstevel@tonic-gate 	if (base == REP_PROTOCOL_TYPE_INVALID)
36707c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
36717c478bd9Sstevel@tonic-gate 
36727c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
36737c478bd9Sstevel@tonic-gate 	ret = property_type_locked(prop, &type);
36747c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
36757c478bd9Sstevel@tonic-gate 
36767c478bd9Sstevel@tonic-gate 	if (ret == SCF_SUCCESS) {
3677870ad75aSSean Wilcox 		if (!scf_is_compatible_protocol_type(base, type))
36787c478bd9Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_TYPE_MISMATCH));
36797c478bd9Sstevel@tonic-gate 	}
36807c478bd9Sstevel@tonic-gate 	return (ret);
36817c478bd9Sstevel@tonic-gate }
36827c478bd9Sstevel@tonic-gate 
3683870ad75aSSean Wilcox int
scf_is_compatible_type(scf_type_t base_arg,scf_type_t type_arg)3684870ad75aSSean Wilcox scf_is_compatible_type(scf_type_t base_arg, scf_type_t type_arg)
3685870ad75aSSean Wilcox {
3686870ad75aSSean Wilcox 	rep_protocol_value_type_t base = scf_type_to_protocol_type(base_arg);
3687870ad75aSSean Wilcox 	rep_protocol_value_type_t type = scf_type_to_protocol_type(type_arg);
3688870ad75aSSean Wilcox 
3689870ad75aSSean Wilcox 	if (base == REP_PROTOCOL_TYPE_INVALID ||
3690870ad75aSSean Wilcox 	    type == REP_PROTOCOL_TYPE_INVALID)
3691870ad75aSSean Wilcox 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
3692870ad75aSSean Wilcox 
3693870ad75aSSean Wilcox 	if (!scf_is_compatible_protocol_type(base, type))
3694870ad75aSSean Wilcox 		return (scf_set_error(SCF_ERROR_TYPE_MISMATCH));
3695870ad75aSSean Wilcox 
3696870ad75aSSean Wilcox 	return (SCF_SUCCESS);
3697870ad75aSSean Wilcox }
3698870ad75aSSean Wilcox 
36997c478bd9Sstevel@tonic-gate ssize_t
scf_property_get_name(const scf_property_t * prop,char * out,size_t len)37007c478bd9Sstevel@tonic-gate scf_property_get_name(const scf_property_t *prop, char *out, size_t len)
37017c478bd9Sstevel@tonic-gate {
37027c478bd9Sstevel@tonic-gate 	return (datael_get_name(&prop->rd_d, out, len, RP_ENTITY_NAME_NAME));
37037c478bd9Sstevel@tonic-gate }
37047c478bd9Sstevel@tonic-gate 
37057c478bd9Sstevel@tonic-gate /*
37067c478bd9Sstevel@tonic-gate  * transaction functions
37077c478bd9Sstevel@tonic-gate  */
37087c478bd9Sstevel@tonic-gate 
37097c478bd9Sstevel@tonic-gate /*
37107c478bd9Sstevel@tonic-gate  * Fails with _NO_MEMORY, _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED,
37117c478bd9Sstevel@tonic-gate  * _INTERNAL (bad server response or id in use), or _NO_RESOURCES.
37127c478bd9Sstevel@tonic-gate  */
37137c478bd9Sstevel@tonic-gate scf_transaction_t *
scf_transaction_create(scf_handle_t * handle)37147c478bd9Sstevel@tonic-gate scf_transaction_create(scf_handle_t *handle)
37157c478bd9Sstevel@tonic-gate {
37167c478bd9Sstevel@tonic-gate 	scf_transaction_t *ret;
37177c478bd9Sstevel@tonic-gate 
37187c478bd9Sstevel@tonic-gate 	ret = uu_zalloc(sizeof (scf_transaction_t));
37197c478bd9Sstevel@tonic-gate 	if (ret == NULL) {
37207c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
37217c478bd9Sstevel@tonic-gate 		return (NULL);
37227c478bd9Sstevel@tonic-gate 	}
37237c478bd9Sstevel@tonic-gate 	if (datael_init(&ret->tran_pg.rd_d, handle,
37247c478bd9Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_PROPERTYGRP) == -1) {
37257c478bd9Sstevel@tonic-gate 		uu_free(ret);
37267c478bd9Sstevel@tonic-gate 		return (NULL);			/* error already set */
37277c478bd9Sstevel@tonic-gate 	}
37287c478bd9Sstevel@tonic-gate 	ret->tran_state = TRAN_STATE_NEW;
37297c478bd9Sstevel@tonic-gate 	ret->tran_props = uu_list_create(tran_entry_pool, ret, UU_LIST_SORTED);
37307c478bd9Sstevel@tonic-gate 	if (ret->tran_props == NULL) {
37317c478bd9Sstevel@tonic-gate 		datael_destroy(&ret->tran_pg.rd_d);
37327c478bd9Sstevel@tonic-gate 		uu_free(ret);
37337c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
37347c478bd9Sstevel@tonic-gate 		return (NULL);
37357c478bd9Sstevel@tonic-gate 	}
37367c478bd9Sstevel@tonic-gate 
37377c478bd9Sstevel@tonic-gate 	return (ret);
37387c478bd9Sstevel@tonic-gate }
37397c478bd9Sstevel@tonic-gate 
37407c478bd9Sstevel@tonic-gate scf_handle_t *
scf_transaction_handle(const scf_transaction_t * val)37417c478bd9Sstevel@tonic-gate scf_transaction_handle(const scf_transaction_t *val)
37427c478bd9Sstevel@tonic-gate {
37437c478bd9Sstevel@tonic-gate 	return (handle_get(val->tran_pg.rd_d.rd_handle));
37447c478bd9Sstevel@tonic-gate }
37457c478bd9Sstevel@tonic-gate 
37467c478bd9Sstevel@tonic-gate int
scf_transaction_start(scf_transaction_t * tran,scf_propertygroup_t * pg)37477c478bd9Sstevel@tonic-gate scf_transaction_start(scf_transaction_t *tran, scf_propertygroup_t *pg)
37487c478bd9Sstevel@tonic-gate {
37497c478bd9Sstevel@tonic-gate 	scf_handle_t *h = tran->tran_pg.rd_d.rd_handle;
37507c478bd9Sstevel@tonic-gate 
37517c478bd9Sstevel@tonic-gate 	struct rep_protocol_transaction_start request;
37527c478bd9Sstevel@tonic-gate 	struct rep_protocol_response response;
37537c478bd9Sstevel@tonic-gate 	int r;
37547c478bd9Sstevel@tonic-gate 
37557c478bd9Sstevel@tonic-gate 	if (h != pg->rd_d.rd_handle)
37567c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
37577c478bd9Sstevel@tonic-gate 
37587c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
37597c478bd9Sstevel@tonic-gate 	if (tran->tran_state != TRAN_STATE_NEW) {
37607c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
37617c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_IN_USE));
37627c478bd9Sstevel@tonic-gate 	}
37637c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_PROPERTYGRP_TX_START;
37647c478bd9Sstevel@tonic-gate 	request.rpr_entityid_tx = tran->tran_pg.rd_d.rd_entity;
37657c478bd9Sstevel@tonic-gate 	request.rpr_entityid = pg->rd_d.rd_entity;
37667c478bd9Sstevel@tonic-gate 
37677c478bd9Sstevel@tonic-gate 	datael_finish_reset(&tran->tran_pg.rd_d);
37687c478bd9Sstevel@tonic-gate 	datael_finish_reset(&pg->rd_d);
37697c478bd9Sstevel@tonic-gate 
37707c478bd9Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
37717c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
37727c478bd9Sstevel@tonic-gate 
37737c478bd9Sstevel@tonic-gate 	if (r < 0) {
37747c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
37757c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
37767c478bd9Sstevel@tonic-gate 	}
37777c478bd9Sstevel@tonic-gate 
37787c478bd9Sstevel@tonic-gate 	/* r < sizeof (response) cannot happen because sizeof (response) == 4 */
37797c478bd9Sstevel@tonic-gate 
37807c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS ||
37817c478bd9Sstevel@tonic-gate 	    r < sizeof (response)) {
37827c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
37837c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
37847c478bd9Sstevel@tonic-gate 	}
37857c478bd9Sstevel@tonic-gate 
37867c478bd9Sstevel@tonic-gate 	tran->tran_state = TRAN_STATE_SETUP;
37877c478bd9Sstevel@tonic-gate 	tran->tran_invalid = 0;
37887c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
37897c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
37907c478bd9Sstevel@tonic-gate }
37917c478bd9Sstevel@tonic-gate 
37927c478bd9Sstevel@tonic-gate static void
entry_invalidate(scf_transaction_entry_t * cur,int and_destroy,int and_reset_value)37937c478bd9Sstevel@tonic-gate entry_invalidate(scf_transaction_entry_t *cur, int and_destroy,
37947c478bd9Sstevel@tonic-gate     int and_reset_value)
37957c478bd9Sstevel@tonic-gate {
37967c478bd9Sstevel@tonic-gate 	scf_value_t *v, *next;
37977c478bd9Sstevel@tonic-gate 	scf_transaction_t *tx;
37987c478bd9Sstevel@tonic-gate 	scf_handle_t *h = cur->entry_handle;
37997c478bd9Sstevel@tonic-gate 
38007c478bd9Sstevel@tonic-gate 	assert(MUTEX_HELD(&h->rh_lock));
38017c478bd9Sstevel@tonic-gate 
38027c478bd9Sstevel@tonic-gate 	if ((tx = cur->entry_tx) != NULL) {
38037c478bd9Sstevel@tonic-gate 		tx->tran_invalid = 1;
38047c478bd9Sstevel@tonic-gate 		uu_list_remove(tx->tran_props, cur);
38057c478bd9Sstevel@tonic-gate 		cur->entry_tx = NULL;
38067c478bd9Sstevel@tonic-gate 	}
38077c478bd9Sstevel@tonic-gate 
38087c478bd9Sstevel@tonic-gate 	cur->entry_property = NULL;
38097c478bd9Sstevel@tonic-gate 	cur->entry_state = ENTRY_STATE_INVALID;
38107c478bd9Sstevel@tonic-gate 	cur->entry_action = REP_PROTOCOL_TX_ENTRY_INVALID;
38117c478bd9Sstevel@tonic-gate 	cur->entry_type = REP_PROTOCOL_TYPE_INVALID;
38127c478bd9Sstevel@tonic-gate 
38137c478bd9Sstevel@tonic-gate 	for (v = cur->entry_head; v != NULL; v = next) {
38147c478bd9Sstevel@tonic-gate 		next = v->value_next;
38157c478bd9Sstevel@tonic-gate 		v->value_tx = NULL;
38167c478bd9Sstevel@tonic-gate 		v->value_next = NULL;
38177c478bd9Sstevel@tonic-gate 		if (and_destroy || and_reset_value)
38187c478bd9Sstevel@tonic-gate 			scf_value_reset_locked(v, and_destroy);
38197c478bd9Sstevel@tonic-gate 	}
38207c478bd9Sstevel@tonic-gate 	cur->entry_head = NULL;
38216e1d2b42Samaguire 	cur->entry_tail = NULL;
38227c478bd9Sstevel@tonic-gate }
38237c478bd9Sstevel@tonic-gate 
38247c478bd9Sstevel@tonic-gate static void
entry_destroy_locked(scf_transaction_entry_t * entry)38257c478bd9Sstevel@tonic-gate entry_destroy_locked(scf_transaction_entry_t *entry)
38267c478bd9Sstevel@tonic-gate {
38277c478bd9Sstevel@tonic-gate 	scf_handle_t *h = entry->entry_handle;
38287c478bd9Sstevel@tonic-gate 
38297c478bd9Sstevel@tonic-gate 	assert(MUTEX_HELD(&h->rh_lock));
38307c478bd9Sstevel@tonic-gate 
38317c478bd9Sstevel@tonic-gate 	entry_invalidate(entry, 0, 0);
38327c478bd9Sstevel@tonic-gate 
38337c478bd9Sstevel@tonic-gate 	entry->entry_handle = NULL;
38347c478bd9Sstevel@tonic-gate 	assert(h->rh_entries > 0);
38357c478bd9Sstevel@tonic-gate 	--h->rh_entries;
38367c478bd9Sstevel@tonic-gate 	--h->rh_extrefs;
38377c478bd9Sstevel@tonic-gate 	uu_list_node_fini(entry, &entry->entry_link, tran_entry_pool);
38387c478bd9Sstevel@tonic-gate 	uu_free(entry);
38397c478bd9Sstevel@tonic-gate }
38407c478bd9Sstevel@tonic-gate 
384176cf44abSjeanm /*
384276cf44abSjeanm  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
384376cf44abSjeanm  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
384476cf44abSjeanm  * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
384576cf44abSjeanm  */
38467c478bd9Sstevel@tonic-gate static int
transaction_add(scf_transaction_t * tran,scf_transaction_entry_t * entry,enum rep_protocol_transaction_action action,const char * prop,rep_protocol_value_type_t type)38477c478bd9Sstevel@tonic-gate transaction_add(scf_transaction_t *tran, scf_transaction_entry_t *entry,
38487c478bd9Sstevel@tonic-gate     enum rep_protocol_transaction_action action,
38497c478bd9Sstevel@tonic-gate     const char *prop, rep_protocol_value_type_t type)
38507c478bd9Sstevel@tonic-gate {
38517c478bd9Sstevel@tonic-gate 	scf_handle_t *h = tran->tran_pg.rd_d.rd_handle;
38527c478bd9Sstevel@tonic-gate 	scf_transaction_entry_t *old;
38537c478bd9Sstevel@tonic-gate 	scf_property_t *prop_p;
38547c478bd9Sstevel@tonic-gate 	rep_protocol_value_type_t oldtype;
38557c478bd9Sstevel@tonic-gate 	scf_error_t error = SCF_ERROR_NONE;
38567c478bd9Sstevel@tonic-gate 	int ret;
38577c478bd9Sstevel@tonic-gate 	uu_list_index_t idx;
38587c478bd9Sstevel@tonic-gate 
38597c478bd9Sstevel@tonic-gate 	if (h != entry->entry_handle)
38607c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
38617c478bd9Sstevel@tonic-gate 
38627c478bd9Sstevel@tonic-gate 	if (action == REP_PROTOCOL_TX_ENTRY_DELETE)
38637c478bd9Sstevel@tonic-gate 		assert(type == REP_PROTOCOL_TYPE_INVALID);
38647c478bd9Sstevel@tonic-gate 	else if (type == REP_PROTOCOL_TYPE_INVALID)
38657c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
38667c478bd9Sstevel@tonic-gate 
38677c478bd9Sstevel@tonic-gate 	prop_p = HANDLE_HOLD_PROPERTY(h);
38687c478bd9Sstevel@tonic-gate 
38697c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
38707c478bd9Sstevel@tonic-gate 	if (tran->tran_state != TRAN_STATE_SETUP) {
38717c478bd9Sstevel@tonic-gate 		error = SCF_ERROR_NOT_SET;
38727c478bd9Sstevel@tonic-gate 		goto error;
38737c478bd9Sstevel@tonic-gate 	}
38747c478bd9Sstevel@tonic-gate 	if (tran->tran_invalid) {
38757c478bd9Sstevel@tonic-gate 		error = SCF_ERROR_NOT_SET;
38767c478bd9Sstevel@tonic-gate 		goto error;
38777c478bd9Sstevel@tonic-gate 	}
38787c478bd9Sstevel@tonic-gate 
38797c478bd9Sstevel@tonic-gate 	if (entry->entry_state != ENTRY_STATE_INVALID)
38807c478bd9Sstevel@tonic-gate 		entry_invalidate(entry, 0, 0);
38817c478bd9Sstevel@tonic-gate 
38827c478bd9Sstevel@tonic-gate 	old = uu_list_find(tran->tran_props, &prop, NULL, &idx);
38837c478bd9Sstevel@tonic-gate 	if (old != NULL) {
38847c478bd9Sstevel@tonic-gate 		error = SCF_ERROR_IN_USE;
38857c478bd9Sstevel@tonic-gate 		goto error;
38867c478bd9Sstevel@tonic-gate 	}
38877c478bd9Sstevel@tonic-gate 
38887c478bd9Sstevel@tonic-gate 	ret = datael_get_child_locked(&tran->tran_pg.rd_d, prop,
38897c478bd9Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_PROPERTY, &prop_p->rd_d);
38907c478bd9Sstevel@tonic-gate 	if (ret == -1 && (error = scf_error()) != SCF_ERROR_NOT_FOUND) {
38917c478bd9Sstevel@tonic-gate 		goto error;
38927c478bd9Sstevel@tonic-gate 	}
38937c478bd9Sstevel@tonic-gate 
38947c478bd9Sstevel@tonic-gate 	switch (action) {
38957c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_TX_ENTRY_DELETE:
38967c478bd9Sstevel@tonic-gate 		if (ret == -1) {
38977c478bd9Sstevel@tonic-gate 			error = SCF_ERROR_NOT_FOUND;
38987c478bd9Sstevel@tonic-gate 			goto error;
38997c478bd9Sstevel@tonic-gate 		}
39007c478bd9Sstevel@tonic-gate 		break;
39017c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_TX_ENTRY_NEW:
39027c478bd9Sstevel@tonic-gate 		if (ret != -1) {
39037c478bd9Sstevel@tonic-gate 			error = SCF_ERROR_EXISTS;
39047c478bd9Sstevel@tonic-gate 			goto error;
39057c478bd9Sstevel@tonic-gate 		}
39067c478bd9Sstevel@tonic-gate 		break;
39077c478bd9Sstevel@tonic-gate 
39087c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_TX_ENTRY_CLEAR:
39097c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_TX_ENTRY_REPLACE:
39107c478bd9Sstevel@tonic-gate 		if (ret == -1) {
39117c478bd9Sstevel@tonic-gate 			error = SCF_ERROR_NOT_FOUND;
39127c478bd9Sstevel@tonic-gate 			goto error;
39137c478bd9Sstevel@tonic-gate 		}
39147c478bd9Sstevel@tonic-gate 		if (action == REP_PROTOCOL_TX_ENTRY_CLEAR) {
39157c478bd9Sstevel@tonic-gate 			if (property_type_locked(prop_p, &oldtype) == -1) {
39167c478bd9Sstevel@tonic-gate 				error = scf_error();
39177c478bd9Sstevel@tonic-gate 				goto error;
39187c478bd9Sstevel@tonic-gate 			}
39197c478bd9Sstevel@tonic-gate 			if (oldtype != type) {
39207c478bd9Sstevel@tonic-gate 				error = SCF_ERROR_TYPE_MISMATCH;
39217c478bd9Sstevel@tonic-gate 				goto error;
39227c478bd9Sstevel@tonic-gate 			}
39237c478bd9Sstevel@tonic-gate 		}
39247c478bd9Sstevel@tonic-gate 		break;
39257c478bd9Sstevel@tonic-gate 	default:
39267c478bd9Sstevel@tonic-gate 		assert(0);
39277c478bd9Sstevel@tonic-gate 		abort();
39287c478bd9Sstevel@tonic-gate 	}
39297c478bd9Sstevel@tonic-gate 
39307c478bd9Sstevel@tonic-gate 	(void) strlcpy(entry->entry_namebuf, prop,
39317c478bd9Sstevel@tonic-gate 	    sizeof (entry->entry_namebuf));
39327c478bd9Sstevel@tonic-gate 	entry->entry_property = entry->entry_namebuf;
39337c478bd9Sstevel@tonic-gate 	entry->entry_action = action;
39347c478bd9Sstevel@tonic-gate 	entry->entry_type = type;
39357c478bd9Sstevel@tonic-gate 
39367c478bd9Sstevel@tonic-gate 	entry->entry_state = ENTRY_STATE_IN_TX_ACTION;
39377c478bd9Sstevel@tonic-gate 	entry->entry_tx = tran;
39387c478bd9Sstevel@tonic-gate 	uu_list_insert(tran->tran_props, entry, idx);
39397c478bd9Sstevel@tonic-gate 
39407c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
39417c478bd9Sstevel@tonic-gate 
39427c478bd9Sstevel@tonic-gate 	HANDLE_RELE_PROPERTY(h);
39437c478bd9Sstevel@tonic-gate 
39447c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
39457c478bd9Sstevel@tonic-gate 
39467c478bd9Sstevel@tonic-gate error:
39477c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
39487c478bd9Sstevel@tonic-gate 
39497c478bd9Sstevel@tonic-gate 	HANDLE_RELE_PROPERTY(h);
39507c478bd9Sstevel@tonic-gate 
39517c478bd9Sstevel@tonic-gate 	return (scf_set_error(error));
39527c478bd9Sstevel@tonic-gate }
39537c478bd9Sstevel@tonic-gate 
395476cf44abSjeanm /*
395576cf44abSjeanm  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
395676cf44abSjeanm  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
395776cf44abSjeanm  * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
395876cf44abSjeanm  */
39597c478bd9Sstevel@tonic-gate int
scf_transaction_property_new(scf_transaction_t * tx,scf_transaction_entry_t * entry,const char * prop,scf_type_t type)39607c478bd9Sstevel@tonic-gate scf_transaction_property_new(scf_transaction_t *tx,
39617c478bd9Sstevel@tonic-gate     scf_transaction_entry_t *entry, const char *prop, scf_type_t type)
39627c478bd9Sstevel@tonic-gate {
39637c478bd9Sstevel@tonic-gate 	return (transaction_add(tx, entry, REP_PROTOCOL_TX_ENTRY_NEW,
39647c478bd9Sstevel@tonic-gate 	    prop, scf_type_to_protocol_type(type)));
39657c478bd9Sstevel@tonic-gate }
39667c478bd9Sstevel@tonic-gate 
396776cf44abSjeanm /*
396876cf44abSjeanm  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
396976cf44abSjeanm  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
397076cf44abSjeanm  * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
397176cf44abSjeanm  */
39727c478bd9Sstevel@tonic-gate int
scf_transaction_property_change(scf_transaction_t * tx,scf_transaction_entry_t * entry,const char * prop,scf_type_t type)39737c478bd9Sstevel@tonic-gate scf_transaction_property_change(scf_transaction_t *tx,
39747c478bd9Sstevel@tonic-gate     scf_transaction_entry_t *entry, const char *prop, scf_type_t type)
39757c478bd9Sstevel@tonic-gate {
39767c478bd9Sstevel@tonic-gate 	return (transaction_add(tx, entry, REP_PROTOCOL_TX_ENTRY_CLEAR,
39777c478bd9Sstevel@tonic-gate 	    prop, scf_type_to_protocol_type(type)));
39787c478bd9Sstevel@tonic-gate }
39797c478bd9Sstevel@tonic-gate 
398076cf44abSjeanm /*
398176cf44abSjeanm  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
398276cf44abSjeanm  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
398376cf44abSjeanm  * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
398476cf44abSjeanm  */
39857c478bd9Sstevel@tonic-gate int
scf_transaction_property_change_type(scf_transaction_t * tx,scf_transaction_entry_t * entry,const char * prop,scf_type_t type)39867c478bd9Sstevel@tonic-gate scf_transaction_property_change_type(scf_transaction_t *tx,
39877c478bd9Sstevel@tonic-gate     scf_transaction_entry_t *entry, const char *prop, scf_type_t type)
39887c478bd9Sstevel@tonic-gate {
39897c478bd9Sstevel@tonic-gate 	return (transaction_add(tx, entry, REP_PROTOCOL_TX_ENTRY_REPLACE,
39907c478bd9Sstevel@tonic-gate 	    prop, scf_type_to_protocol_type(type)));
39917c478bd9Sstevel@tonic-gate }
39927c478bd9Sstevel@tonic-gate 
399376cf44abSjeanm /*
399476cf44abSjeanm  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
399576cf44abSjeanm  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
399676cf44abSjeanm  * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
399776cf44abSjeanm  */
39987c478bd9Sstevel@tonic-gate int
scf_transaction_property_delete(scf_transaction_t * tx,scf_transaction_entry_t * entry,const char * prop)39997c478bd9Sstevel@tonic-gate scf_transaction_property_delete(scf_transaction_t *tx,
40007c478bd9Sstevel@tonic-gate     scf_transaction_entry_t *entry, const char *prop)
40017c478bd9Sstevel@tonic-gate {
40027c478bd9Sstevel@tonic-gate 	return (transaction_add(tx, entry, REP_PROTOCOL_TX_ENTRY_DELETE,
40037c478bd9Sstevel@tonic-gate 	    prop, REP_PROTOCOL_TYPE_INVALID));
40047c478bd9Sstevel@tonic-gate }
40057c478bd9Sstevel@tonic-gate 
40067c478bd9Sstevel@tonic-gate #define	BAD_SIZE (-1UL)
40077c478bd9Sstevel@tonic-gate 
40087c478bd9Sstevel@tonic-gate static size_t
commit_value(caddr_t data,scf_value_t * val,rep_protocol_value_type_t t)40097c478bd9Sstevel@tonic-gate commit_value(caddr_t data, scf_value_t *val, rep_protocol_value_type_t t)
40107c478bd9Sstevel@tonic-gate {
40117c478bd9Sstevel@tonic-gate 	size_t len;
40127c478bd9Sstevel@tonic-gate 
40137c478bd9Sstevel@tonic-gate 	assert(val->value_type == t);
40147c478bd9Sstevel@tonic-gate 
40157c478bd9Sstevel@tonic-gate 	if (t == REP_PROTOCOL_TYPE_OPAQUE) {
40167c478bd9Sstevel@tonic-gate 		len = scf_opaque_encode(data, val->value_value,
40177c478bd9Sstevel@tonic-gate 		    val->value_size);
40187c478bd9Sstevel@tonic-gate 	} else {
40197c478bd9Sstevel@tonic-gate 		if (data != NULL)
40207c478bd9Sstevel@tonic-gate 			len = strlcpy(data, val->value_value,
40217c478bd9Sstevel@tonic-gate 			    REP_PROTOCOL_VALUE_LEN);
40227c478bd9Sstevel@tonic-gate 		else
40237c478bd9Sstevel@tonic-gate 			len = strlen(val->value_value);
40247c478bd9Sstevel@tonic-gate 		if (len >= REP_PROTOCOL_VALUE_LEN)
40257c478bd9Sstevel@tonic-gate 			return (BAD_SIZE);
40267c478bd9Sstevel@tonic-gate 	}
40277c478bd9Sstevel@tonic-gate 	return (len + 1);	/* count the '\0' */
40287c478bd9Sstevel@tonic-gate }
40297c478bd9Sstevel@tonic-gate 
40307c478bd9Sstevel@tonic-gate static size_t
commit_process(scf_transaction_entry_t * cur,struct rep_protocol_transaction_cmd * out)40317c478bd9Sstevel@tonic-gate commit_process(scf_transaction_entry_t *cur,
40327c478bd9Sstevel@tonic-gate     struct rep_protocol_transaction_cmd *out)
40337c478bd9Sstevel@tonic-gate {
40347c478bd9Sstevel@tonic-gate 	scf_value_t *child;
40357c478bd9Sstevel@tonic-gate 	size_t sz = 0;
40367c478bd9Sstevel@tonic-gate 	size_t len;
40377c478bd9Sstevel@tonic-gate 	caddr_t data = (caddr_t)out->rptc_data;
40387c478bd9Sstevel@tonic-gate 	caddr_t val_data;
40397c478bd9Sstevel@tonic-gate 
40407c478bd9Sstevel@tonic-gate 	if (out != NULL) {
40417c478bd9Sstevel@tonic-gate 		len = strlcpy(data, cur->entry_property, REP_PROTOCOL_NAME_LEN);
40427c478bd9Sstevel@tonic-gate 
40437c478bd9Sstevel@tonic-gate 		out->rptc_action = cur->entry_action;
40447c478bd9Sstevel@tonic-gate 		out->rptc_type = cur->entry_type;
40457c478bd9Sstevel@tonic-gate 		out->rptc_name_len = len + 1;
40467c478bd9Sstevel@tonic-gate 	} else {
40477c478bd9Sstevel@tonic-gate 		len = strlen(cur->entry_property);
40487c478bd9Sstevel@tonic-gate 	}
40497c478bd9Sstevel@tonic-gate 
40507c478bd9Sstevel@tonic-gate 	if (len >= REP_PROTOCOL_NAME_LEN)
40517c478bd9Sstevel@tonic-gate 		return (BAD_SIZE);
40527c478bd9Sstevel@tonic-gate 
40537c478bd9Sstevel@tonic-gate 	len = TX_SIZE(len + 1);
40547c478bd9Sstevel@tonic-gate 
40557c478bd9Sstevel@tonic-gate 	sz += len;
40567c478bd9Sstevel@tonic-gate 	val_data = data + len;
40577c478bd9Sstevel@tonic-gate 
40587c478bd9Sstevel@tonic-gate 	for (child = cur->entry_head; child != NULL;
40597c478bd9Sstevel@tonic-gate 	    child = child->value_next) {
40607c478bd9Sstevel@tonic-gate 		assert(cur->entry_action != REP_PROTOCOL_TX_ENTRY_DELETE);
40617c478bd9Sstevel@tonic-gate 		if (out != NULL) {
40627c478bd9Sstevel@tonic-gate 			len = commit_value(val_data + sizeof (uint32_t), child,
40637c478bd9Sstevel@tonic-gate 			    cur->entry_type);
40647c478bd9Sstevel@tonic-gate 			/* LINTED alignment */
40657c478bd9Sstevel@tonic-gate 			*(uint32_t *)val_data = len;
40667c478bd9Sstevel@tonic-gate 		} else
40677c478bd9Sstevel@tonic-gate 			len = commit_value(NULL, child, cur->entry_type);
40687c478bd9Sstevel@tonic-gate 
40697c478bd9Sstevel@tonic-gate 		if (len == BAD_SIZE)
40707c478bd9Sstevel@tonic-gate 			return (BAD_SIZE);
40717c478bd9Sstevel@tonic-gate 
40727c478bd9Sstevel@tonic-gate 		len += sizeof (uint32_t);
40737c478bd9Sstevel@tonic-gate 		len = TX_SIZE(len);
40747c478bd9Sstevel@tonic-gate 
40757c478bd9Sstevel@tonic-gate 		sz += len;
40767c478bd9Sstevel@tonic-gate 		val_data += len;
40777c478bd9Sstevel@tonic-gate 	}
40787c478bd9Sstevel@tonic-gate 
40797c478bd9Sstevel@tonic-gate 	assert(val_data - data == sz);
40807c478bd9Sstevel@tonic-gate 
40817c478bd9Sstevel@tonic-gate 	if (out != NULL)
40827c478bd9Sstevel@tonic-gate 		out->rptc_size = REP_PROTOCOL_TRANSACTION_CMD_SIZE(sz);
40837c478bd9Sstevel@tonic-gate 
40847c478bd9Sstevel@tonic-gate 	return (REP_PROTOCOL_TRANSACTION_CMD_SIZE(sz));
40857c478bd9Sstevel@tonic-gate }
40867c478bd9Sstevel@tonic-gate 
40877c478bd9Sstevel@tonic-gate int
scf_transaction_commit(scf_transaction_t * tran)40887c478bd9Sstevel@tonic-gate scf_transaction_commit(scf_transaction_t *tran)
40897c478bd9Sstevel@tonic-gate {
40907c478bd9Sstevel@tonic-gate 	scf_handle_t *h = tran->tran_pg.rd_d.rd_handle;
40917c478bd9Sstevel@tonic-gate 
40927c478bd9Sstevel@tonic-gate 	struct rep_protocol_transaction_commit *request;
40937c478bd9Sstevel@tonic-gate 	struct rep_protocol_response response;
40947c478bd9Sstevel@tonic-gate 	uintptr_t cmd;
40957c478bd9Sstevel@tonic-gate 	scf_transaction_entry_t *cur;
40967c478bd9Sstevel@tonic-gate 	size_t total, size;
40977c478bd9Sstevel@tonic-gate 	size_t request_size;
40987c478bd9Sstevel@tonic-gate 	size_t new_total;
40997c478bd9Sstevel@tonic-gate 	int r;
41007c478bd9Sstevel@tonic-gate 
41017c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
41027c478bd9Sstevel@tonic-gate 	if (tran->tran_state != TRAN_STATE_SETUP ||
41037c478bd9Sstevel@tonic-gate 	    tran->tran_invalid) {
41047c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
41057c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
41067c478bd9Sstevel@tonic-gate 	}
41077c478bd9Sstevel@tonic-gate 
41087c478bd9Sstevel@tonic-gate 	total = 0;
41097c478bd9Sstevel@tonic-gate 	for (cur = uu_list_first(tran->tran_props); cur != NULL;
41107c478bd9Sstevel@tonic-gate 	    cur = uu_list_next(tran->tran_props, cur)) {
41117c478bd9Sstevel@tonic-gate 		size = commit_process(cur, NULL);
41127c478bd9Sstevel@tonic-gate 		if (size == BAD_SIZE) {
41137c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&h->rh_lock);
41147c478bd9Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_INTERNAL));
41157c478bd9Sstevel@tonic-gate 		}
41167c478bd9Sstevel@tonic-gate 		assert(TX_SIZE(size) == size);
41177c478bd9Sstevel@tonic-gate 		total += size;
41187c478bd9Sstevel@tonic-gate 	}
41197c478bd9Sstevel@tonic-gate 
41207c478bd9Sstevel@tonic-gate 	request_size = REP_PROTOCOL_TRANSACTION_COMMIT_SIZE(total);
41217c478bd9Sstevel@tonic-gate 	request = alloca(request_size);
41227c478bd9Sstevel@tonic-gate 	(void) memset(request, '\0', request_size);
41237c478bd9Sstevel@tonic-gate 	request->rpr_request = REP_PROTOCOL_PROPERTYGRP_TX_COMMIT;
41247c478bd9Sstevel@tonic-gate 	request->rpr_entityid = tran->tran_pg.rd_d.rd_entity;
41257c478bd9Sstevel@tonic-gate 	request->rpr_size = request_size;
41267c478bd9Sstevel@tonic-gate 	cmd = (uintptr_t)request->rpr_cmd;
41277c478bd9Sstevel@tonic-gate 
41287c478bd9Sstevel@tonic-gate 	datael_finish_reset(&tran->tran_pg.rd_d);
41297c478bd9Sstevel@tonic-gate 
41307c478bd9Sstevel@tonic-gate 	new_total = 0;
41317c478bd9Sstevel@tonic-gate 	for (cur = uu_list_first(tran->tran_props); cur != NULL;
41327c478bd9Sstevel@tonic-gate 	    cur = uu_list_next(tran->tran_props, cur)) {
41337c478bd9Sstevel@tonic-gate 		size = commit_process(cur, (void *)cmd);
41347c478bd9Sstevel@tonic-gate 		if (size == BAD_SIZE) {
41357c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&h->rh_lock);
41367c478bd9Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_INTERNAL));
41377c478bd9Sstevel@tonic-gate 		}
41387c478bd9Sstevel@tonic-gate 		cmd += size;
41397c478bd9Sstevel@tonic-gate 		new_total += size;
41407c478bd9Sstevel@tonic-gate 	}
41417c478bd9Sstevel@tonic-gate 	assert(new_total == total);
41427c478bd9Sstevel@tonic-gate 
41437c478bd9Sstevel@tonic-gate 	r = make_door_call(h, request, request_size,
41447c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
41457c478bd9Sstevel@tonic-gate 
41467c478bd9Sstevel@tonic-gate 	if (r < 0) {
41477c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
41487c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
41497c478bd9Sstevel@tonic-gate 	}
41507c478bd9Sstevel@tonic-gate 
41517c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS &&
41527c478bd9Sstevel@tonic-gate 	    response.rpr_response != REP_PROTOCOL_FAIL_NOT_LATEST) {
41537c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
41547c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
41557c478bd9Sstevel@tonic-gate 	}
41567c478bd9Sstevel@tonic-gate 
41577c478bd9Sstevel@tonic-gate 	tran->tran_state = TRAN_STATE_COMMITTED;
41587c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
41597c478bd9Sstevel@tonic-gate 	return (response.rpr_response == REP_PROTOCOL_SUCCESS);
41607c478bd9Sstevel@tonic-gate }
41617c478bd9Sstevel@tonic-gate 
41627c478bd9Sstevel@tonic-gate static void
transaction_reset(scf_transaction_t * tran)41637c478bd9Sstevel@tonic-gate transaction_reset(scf_transaction_t *tran)
41647c478bd9Sstevel@tonic-gate {
41657c478bd9Sstevel@tonic-gate 	assert(MUTEX_HELD(&tran->tran_pg.rd_d.rd_handle->rh_lock));
41667c478bd9Sstevel@tonic-gate 
41677c478bd9Sstevel@tonic-gate 	tran->tran_state = TRAN_STATE_NEW;
41687c478bd9Sstevel@tonic-gate 	datael_reset_locked(&tran->tran_pg.rd_d);
41697c478bd9Sstevel@tonic-gate }
41707c478bd9Sstevel@tonic-gate 
41717c478bd9Sstevel@tonic-gate static void
scf_transaction_reset_impl(scf_transaction_t * tran,int and_destroy,int and_reset_value)41727c478bd9Sstevel@tonic-gate scf_transaction_reset_impl(scf_transaction_t *tran, int and_destroy,
41737c478bd9Sstevel@tonic-gate     int and_reset_value)
41747c478bd9Sstevel@tonic-gate {
41757c478bd9Sstevel@tonic-gate 	scf_transaction_entry_t *cur;
41767c478bd9Sstevel@tonic-gate 	void *cookie;
41777c478bd9Sstevel@tonic-gate 
41787c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&tran->tran_pg.rd_d.rd_handle->rh_lock);
41797c478bd9Sstevel@tonic-gate 	cookie = NULL;
41807c478bd9Sstevel@tonic-gate 	while ((cur = uu_list_teardown(tran->tran_props, &cookie)) != NULL) {
41817c478bd9Sstevel@tonic-gate 		cur->entry_tx = NULL;
41827c478bd9Sstevel@tonic-gate 
41837c478bd9Sstevel@tonic-gate 		assert(cur->entry_state == ENTRY_STATE_IN_TX_ACTION);
41847c478bd9Sstevel@tonic-gate 		cur->entry_state = ENTRY_STATE_INVALID;
41857c478bd9Sstevel@tonic-gate 
41867c478bd9Sstevel@tonic-gate 		entry_invalidate(cur, and_destroy, and_reset_value);
41877c478bd9Sstevel@tonic-gate 		if (and_destroy)
41887c478bd9Sstevel@tonic-gate 			entry_destroy_locked(cur);
41897c478bd9Sstevel@tonic-gate 	}
41907c478bd9Sstevel@tonic-gate 	transaction_reset(tran);
41917c478bd9Sstevel@tonic-gate 	handle_unrefed(tran->tran_pg.rd_d.rd_handle);
41927c478bd9Sstevel@tonic-gate }
41937c478bd9Sstevel@tonic-gate 
41947c478bd9Sstevel@tonic-gate void
scf_transaction_reset(scf_transaction_t * tran)41957c478bd9Sstevel@tonic-gate scf_transaction_reset(scf_transaction_t *tran)
41967c478bd9Sstevel@tonic-gate {
41977c478bd9Sstevel@tonic-gate 	scf_transaction_reset_impl(tran, 0, 0);
41987c478bd9Sstevel@tonic-gate }
41997c478bd9Sstevel@tonic-gate 
42007c478bd9Sstevel@tonic-gate void
scf_transaction_reset_all(scf_transaction_t * tran)42017c478bd9Sstevel@tonic-gate scf_transaction_reset_all(scf_transaction_t *tran)
42027c478bd9Sstevel@tonic-gate {
42037c478bd9Sstevel@tonic-gate 	scf_transaction_reset_impl(tran, 0, 1);
42047c478bd9Sstevel@tonic-gate }
42057c478bd9Sstevel@tonic-gate 
42067c478bd9Sstevel@tonic-gate void
scf_transaction_destroy(scf_transaction_t * val)42077c478bd9Sstevel@tonic-gate scf_transaction_destroy(scf_transaction_t *val)
42087c478bd9Sstevel@tonic-gate {
42097c478bd9Sstevel@tonic-gate 	if (val == NULL)
42107c478bd9Sstevel@tonic-gate 		return;
42117c478bd9Sstevel@tonic-gate 
42127c478bd9Sstevel@tonic-gate 	scf_transaction_reset(val);
42137c478bd9Sstevel@tonic-gate 
42147c478bd9Sstevel@tonic-gate 	datael_destroy(&val->tran_pg.rd_d);
42157c478bd9Sstevel@tonic-gate 
42167c478bd9Sstevel@tonic-gate 	uu_list_destroy(val->tran_props);
42177c478bd9Sstevel@tonic-gate 	uu_free(val);
42187c478bd9Sstevel@tonic-gate }
42197c478bd9Sstevel@tonic-gate 
42207c478bd9Sstevel@tonic-gate void
scf_transaction_destroy_children(scf_transaction_t * tran)42217c478bd9Sstevel@tonic-gate scf_transaction_destroy_children(scf_transaction_t *tran)
42227c478bd9Sstevel@tonic-gate {
4223f6e214c7SGavin Maltby 	if (tran == NULL)
4224f6e214c7SGavin Maltby 		return;
4225f6e214c7SGavin Maltby 
42267c478bd9Sstevel@tonic-gate 	scf_transaction_reset_impl(tran, 1, 0);
42277c478bd9Sstevel@tonic-gate }
42287c478bd9Sstevel@tonic-gate 
42297c478bd9Sstevel@tonic-gate scf_transaction_entry_t *
scf_entry_create(scf_handle_t * h)42307c478bd9Sstevel@tonic-gate scf_entry_create(scf_handle_t *h)
42317c478bd9Sstevel@tonic-gate {
42327c478bd9Sstevel@tonic-gate 	scf_transaction_entry_t *ret;
42337c478bd9Sstevel@tonic-gate 
42347c478bd9Sstevel@tonic-gate 	if (h == NULL) {
42357c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
42367c478bd9Sstevel@tonic-gate 		return (NULL);
42377c478bd9Sstevel@tonic-gate 	}
42387c478bd9Sstevel@tonic-gate 
42397c478bd9Sstevel@tonic-gate 	ret = uu_zalloc(sizeof (scf_transaction_entry_t));
42407c478bd9Sstevel@tonic-gate 	if (ret == NULL) {
42417c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
42427c478bd9Sstevel@tonic-gate 		return (NULL);
42437c478bd9Sstevel@tonic-gate 	}
42447c478bd9Sstevel@tonic-gate 	ret->entry_action = REP_PROTOCOL_TX_ENTRY_INVALID;
42457c478bd9Sstevel@tonic-gate 	ret->entry_handle = h;
42467c478bd9Sstevel@tonic-gate 
42477c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
42487c478bd9Sstevel@tonic-gate 	if (h->rh_flags & HANDLE_DEAD) {
42497c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
42507c478bd9Sstevel@tonic-gate 		uu_free(ret);
42517c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_HANDLE_DESTROYED);
42527c478bd9Sstevel@tonic-gate 		return (NULL);
42537c478bd9Sstevel@tonic-gate 	}
42547c478bd9Sstevel@tonic-gate 	h->rh_entries++;
42557c478bd9Sstevel@tonic-gate 	h->rh_extrefs++;
42567c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
42577c478bd9Sstevel@tonic-gate 
42587c478bd9Sstevel@tonic-gate 	uu_list_node_init(ret, &ret->entry_link, tran_entry_pool);
42597c478bd9Sstevel@tonic-gate 
42607c478bd9Sstevel@tonic-gate 	return (ret);
42617c478bd9Sstevel@tonic-gate }
42627c478bd9Sstevel@tonic-gate 
42637c478bd9Sstevel@tonic-gate scf_handle_t *
scf_entry_handle(const scf_transaction_entry_t * val)42647c478bd9Sstevel@tonic-gate scf_entry_handle(const scf_transaction_entry_t *val)
42657c478bd9Sstevel@tonic-gate {
42667c478bd9Sstevel@tonic-gate 	return (handle_get(val->entry_handle));
42677c478bd9Sstevel@tonic-gate }
42687c478bd9Sstevel@tonic-gate 
42697c478bd9Sstevel@tonic-gate void
scf_entry_reset(scf_transaction_entry_t * entry)42707c478bd9Sstevel@tonic-gate scf_entry_reset(scf_transaction_entry_t *entry)
42717c478bd9Sstevel@tonic-gate {
42727c478bd9Sstevel@tonic-gate 	scf_handle_t *h = entry->entry_handle;
42737c478bd9Sstevel@tonic-gate 
42747c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
42757c478bd9Sstevel@tonic-gate 	entry_invalidate(entry, 0, 0);
42767c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
42777c478bd9Sstevel@tonic-gate }
42787c478bd9Sstevel@tonic-gate 
42797c478bd9Sstevel@tonic-gate void
scf_entry_destroy_children(scf_transaction_entry_t * entry)42807c478bd9Sstevel@tonic-gate scf_entry_destroy_children(scf_transaction_entry_t *entry)
42817c478bd9Sstevel@tonic-gate {
42827c478bd9Sstevel@tonic-gate 	scf_handle_t *h = entry->entry_handle;
42837c478bd9Sstevel@tonic-gate 
42847c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
42857c478bd9Sstevel@tonic-gate 	entry_invalidate(entry, 1, 0);
42867c478bd9Sstevel@tonic-gate 	handle_unrefed(h);			/* drops h->rh_lock */
42877c478bd9Sstevel@tonic-gate }
42887c478bd9Sstevel@tonic-gate 
42897c478bd9Sstevel@tonic-gate void
scf_entry_destroy(scf_transaction_entry_t * entry)42907c478bd9Sstevel@tonic-gate scf_entry_destroy(scf_transaction_entry_t *entry)
42917c478bd9Sstevel@tonic-gate {
42927c478bd9Sstevel@tonic-gate 	scf_handle_t *h;
42937c478bd9Sstevel@tonic-gate 
42947c478bd9Sstevel@tonic-gate 	if (entry == NULL)
42957c478bd9Sstevel@tonic-gate 		return;
42967c478bd9Sstevel@tonic-gate 
42977c478bd9Sstevel@tonic-gate 	h = entry->entry_handle;
42987c478bd9Sstevel@tonic-gate 
42997c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
43007c478bd9Sstevel@tonic-gate 	entry_destroy_locked(entry);
43017c478bd9Sstevel@tonic-gate 	handle_unrefed(h);			/* drops h->rh_lock */
43027c478bd9Sstevel@tonic-gate }
43037c478bd9Sstevel@tonic-gate 
43047c478bd9Sstevel@tonic-gate /*
43057c478bd9Sstevel@tonic-gate  * Fails with
43067c478bd9Sstevel@tonic-gate  *   _HANDLE_MISMATCH
43077c478bd9Sstevel@tonic-gate  *   _NOT_SET - has not been added to a transaction
43087c478bd9Sstevel@tonic-gate  *   _INTERNAL - entry is corrupt
43097c478bd9Sstevel@tonic-gate  *   _INVALID_ARGUMENT - entry's transaction is not started or corrupt
43107c478bd9Sstevel@tonic-gate  *			 entry is set to delete a property
43117c478bd9Sstevel@tonic-gate  *			 v is reset or corrupt
43127c478bd9Sstevel@tonic-gate  *   _TYPE_MISMATCH - entry & v's types aren't compatible
43137c478bd9Sstevel@tonic-gate  *   _IN_USE - v has been added to another entry
43147c478bd9Sstevel@tonic-gate  */
43157c478bd9Sstevel@tonic-gate int
scf_entry_add_value(scf_transaction_entry_t * entry,scf_value_t * v)43167c478bd9Sstevel@tonic-gate scf_entry_add_value(scf_transaction_entry_t *entry, scf_value_t *v)
43177c478bd9Sstevel@tonic-gate {
43187c478bd9Sstevel@tonic-gate 	scf_handle_t *h = entry->entry_handle;
43197c478bd9Sstevel@tonic-gate 
43207c478bd9Sstevel@tonic-gate 	if (h != v->value_handle)
43217c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
43227c478bd9Sstevel@tonic-gate 
43237c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
43247c478bd9Sstevel@tonic-gate 
43257c478bd9Sstevel@tonic-gate 	if (entry->entry_state == ENTRY_STATE_INVALID) {
43267c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
43277c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_NOT_SET));
43287c478bd9Sstevel@tonic-gate 	}
4329f2fa366aSjeanm 
4330f2fa366aSjeanm 	if (entry->entry_state != ENTRY_STATE_IN_TX_ACTION) {
4331f2fa366aSjeanm 		(void) pthread_mutex_unlock(&h->rh_lock);
4332f2fa366aSjeanm 		return (scf_set_error(SCF_ERROR_INTERNAL));
4333f2fa366aSjeanm 	}
43347c478bd9Sstevel@tonic-gate 
43357c478bd9Sstevel@tonic-gate 	if (entry->entry_tx->tran_state != TRAN_STATE_SETUP) {
43367c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
43377c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
43387c478bd9Sstevel@tonic-gate 	}
43397c478bd9Sstevel@tonic-gate 
43407c478bd9Sstevel@tonic-gate 	if (entry->entry_action == REP_PROTOCOL_TX_ENTRY_DELETE) {
43417c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
43427c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
43437c478bd9Sstevel@tonic-gate 	}
43447c478bd9Sstevel@tonic-gate 
43457c478bd9Sstevel@tonic-gate 	if (v->value_type == REP_PROTOCOL_TYPE_INVALID) {
43467c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
43477c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
43487c478bd9Sstevel@tonic-gate 	}
43497c478bd9Sstevel@tonic-gate 
4350870ad75aSSean Wilcox 	if (!scf_is_compatible_protocol_type(entry->entry_type,
4351870ad75aSSean Wilcox 	    v->value_type)) {
43527c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
43537c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_TYPE_MISMATCH));
43547c478bd9Sstevel@tonic-gate 	}
43557c478bd9Sstevel@tonic-gate 
43567c478bd9Sstevel@tonic-gate 	if (v->value_tx != NULL) {
43577c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
43587c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_IN_USE));
43597c478bd9Sstevel@tonic-gate 	}
43607c478bd9Sstevel@tonic-gate 
43617c478bd9Sstevel@tonic-gate 	v->value_tx = entry;
43626e1d2b42Samaguire 	v->value_next = NULL;
43636e1d2b42Samaguire 	if (entry->entry_head == NULL) {
43646e1d2b42Samaguire 		entry->entry_head = v;
43656e1d2b42Samaguire 		entry->entry_tail = v;
43666e1d2b42Samaguire 	} else {
43676e1d2b42Samaguire 		entry->entry_tail->value_next = v;
43686e1d2b42Samaguire 		entry->entry_tail = v;
43696e1d2b42Samaguire 	}
43706e1d2b42Samaguire 
43717c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
43727c478bd9Sstevel@tonic-gate 
43737c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
43747c478bd9Sstevel@tonic-gate }
43757c478bd9Sstevel@tonic-gate 
43767c478bd9Sstevel@tonic-gate /*
43777c478bd9Sstevel@tonic-gate  * value functions
43787c478bd9Sstevel@tonic-gate  */
43797c478bd9Sstevel@tonic-gate scf_value_t *
scf_value_create(scf_handle_t * h)43807c478bd9Sstevel@tonic-gate scf_value_create(scf_handle_t *h)
43817c478bd9Sstevel@tonic-gate {
43827c478bd9Sstevel@tonic-gate 	scf_value_t *ret;
43837c478bd9Sstevel@tonic-gate 
43847c478bd9Sstevel@tonic-gate 	if (h == NULL) {
43857c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
43867c478bd9Sstevel@tonic-gate 		return (NULL);
43877c478bd9Sstevel@tonic-gate 	}
43887c478bd9Sstevel@tonic-gate 
43897c478bd9Sstevel@tonic-gate 	ret = uu_zalloc(sizeof (*ret));
43907c478bd9Sstevel@tonic-gate 	if (ret != NULL) {
43917c478bd9Sstevel@tonic-gate 		ret->value_type = REP_PROTOCOL_TYPE_INVALID;
43927c478bd9Sstevel@tonic-gate 		ret->value_handle = h;
43937c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_lock(&h->rh_lock);
43947c478bd9Sstevel@tonic-gate 		if (h->rh_flags & HANDLE_DEAD) {
43957c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&h->rh_lock);
43967c478bd9Sstevel@tonic-gate 			uu_free(ret);
43971f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_HANDLE_DESTROYED);
43987c478bd9Sstevel@tonic-gate 			return (NULL);
43997c478bd9Sstevel@tonic-gate 		}
44007c478bd9Sstevel@tonic-gate 		h->rh_values++;
44017c478bd9Sstevel@tonic-gate 		h->rh_extrefs++;
44027c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
44037c478bd9Sstevel@tonic-gate 	} else {
44047c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
44057c478bd9Sstevel@tonic-gate 	}
44067c478bd9Sstevel@tonic-gate 
44077c478bd9Sstevel@tonic-gate 	return (ret);
44087c478bd9Sstevel@tonic-gate }
44097c478bd9Sstevel@tonic-gate 
44107c478bd9Sstevel@tonic-gate static void
scf_value_reset_locked(scf_value_t * val,int and_destroy)44117c478bd9Sstevel@tonic-gate scf_value_reset_locked(scf_value_t *val, int and_destroy)
44127c478bd9Sstevel@tonic-gate {
44137c478bd9Sstevel@tonic-gate 	scf_value_t **curp;
44147c478bd9Sstevel@tonic-gate 	scf_transaction_entry_t *te;
44157c478bd9Sstevel@tonic-gate 
44167c478bd9Sstevel@tonic-gate 	scf_handle_t *h = val->value_handle;
44177c478bd9Sstevel@tonic-gate 	assert(MUTEX_HELD(&h->rh_lock));
44187c478bd9Sstevel@tonic-gate 	if (val->value_tx != NULL) {
44197c478bd9Sstevel@tonic-gate 		te = val->value_tx;
44207c478bd9Sstevel@tonic-gate 		te->entry_tx->tran_invalid = 1;
44217c478bd9Sstevel@tonic-gate 
44227c478bd9Sstevel@tonic-gate 		val->value_tx = NULL;
44237c478bd9Sstevel@tonic-gate 
44247c478bd9Sstevel@tonic-gate 		for (curp = &te->entry_head; *curp != NULL;
44257c478bd9Sstevel@tonic-gate 		    curp = &(*curp)->value_next) {
44267c478bd9Sstevel@tonic-gate 			if (*curp == val) {
44277c478bd9Sstevel@tonic-gate 				*curp = val->value_next;
44287c478bd9Sstevel@tonic-gate 				curp = NULL;
44297c478bd9Sstevel@tonic-gate 				break;
44307c478bd9Sstevel@tonic-gate 			}
44317c478bd9Sstevel@tonic-gate 		}
44327c478bd9Sstevel@tonic-gate 		assert(curp == NULL);
44337c478bd9Sstevel@tonic-gate 	}
44347c478bd9Sstevel@tonic-gate 	val->value_type = REP_PROTOCOL_TYPE_INVALID;
44357c478bd9Sstevel@tonic-gate 
44367c478bd9Sstevel@tonic-gate 	if (and_destroy) {
44377c478bd9Sstevel@tonic-gate 		val->value_handle = NULL;
44387c478bd9Sstevel@tonic-gate 		assert(h->rh_values > 0);
44397c478bd9Sstevel@tonic-gate 		--h->rh_values;
44407c478bd9Sstevel@tonic-gate 		--h->rh_extrefs;
44417c478bd9Sstevel@tonic-gate 		uu_free(val);
44427c478bd9Sstevel@tonic-gate 	}
44437c478bd9Sstevel@tonic-gate }
44447c478bd9Sstevel@tonic-gate 
44457c478bd9Sstevel@tonic-gate void
scf_value_reset(scf_value_t * val)44467c478bd9Sstevel@tonic-gate scf_value_reset(scf_value_t *val)
44477c478bd9Sstevel@tonic-gate {
44487c478bd9Sstevel@tonic-gate 	scf_handle_t *h = val->value_handle;
44497c478bd9Sstevel@tonic-gate 
44507c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
44517c478bd9Sstevel@tonic-gate 	scf_value_reset_locked(val, 0);
44527c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
44537c478bd9Sstevel@tonic-gate }
44547c478bd9Sstevel@tonic-gate 
44557c478bd9Sstevel@tonic-gate scf_handle_t *
scf_value_handle(const scf_value_t * val)44567c478bd9Sstevel@tonic-gate scf_value_handle(const scf_value_t *val)
44577c478bd9Sstevel@tonic-gate {
44587c478bd9Sstevel@tonic-gate 	return (handle_get(val->value_handle));
44597c478bd9Sstevel@tonic-gate }
44607c478bd9Sstevel@tonic-gate 
44617c478bd9Sstevel@tonic-gate void
scf_value_destroy(scf_value_t * val)44627c478bd9Sstevel@tonic-gate scf_value_destroy(scf_value_t *val)
44637c478bd9Sstevel@tonic-gate {
44647c478bd9Sstevel@tonic-gate 	scf_handle_t *h;
44657c478bd9Sstevel@tonic-gate 
44667c478bd9Sstevel@tonic-gate 	if (val == NULL)
44677c478bd9Sstevel@tonic-gate 		return;
44687c478bd9Sstevel@tonic-gate 
44697c478bd9Sstevel@tonic-gate 	h = val->value_handle;
44707c478bd9Sstevel@tonic-gate 
44717c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
44727c478bd9Sstevel@tonic-gate 	scf_value_reset_locked(val, 1);
44737c478bd9Sstevel@tonic-gate 	handle_unrefed(h);			/* drops h->rh_lock */
44747c478bd9Sstevel@tonic-gate }
44757c478bd9Sstevel@tonic-gate 
44767c478bd9Sstevel@tonic-gate scf_type_t
scf_value_base_type(const scf_value_t * val)44777c478bd9Sstevel@tonic-gate scf_value_base_type(const scf_value_t *val)
44787c478bd9Sstevel@tonic-gate {
44797c478bd9Sstevel@tonic-gate 	rep_protocol_value_type_t t, cur;
44807c478bd9Sstevel@tonic-gate 	scf_handle_t *h = val->value_handle;
44817c478bd9Sstevel@tonic-gate 
44827c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
44837c478bd9Sstevel@tonic-gate 	t = val->value_type;
44847c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
44857c478bd9Sstevel@tonic-gate 
44867c478bd9Sstevel@tonic-gate 	for (;;) {
44877c478bd9Sstevel@tonic-gate 		cur = scf_proto_underlying_type(t);
44887c478bd9Sstevel@tonic-gate 		if (cur == t)
44897c478bd9Sstevel@tonic-gate 			break;
44907c478bd9Sstevel@tonic-gate 		t = cur;
44917c478bd9Sstevel@tonic-gate 	}
44927c478bd9Sstevel@tonic-gate 
44937c478bd9Sstevel@tonic-gate 	return (scf_protocol_type_to_type(t));
44947c478bd9Sstevel@tonic-gate }
44957c478bd9Sstevel@tonic-gate 
44967c478bd9Sstevel@tonic-gate scf_type_t
scf_value_type(const scf_value_t * val)44977c478bd9Sstevel@tonic-gate scf_value_type(const scf_value_t *val)
44987c478bd9Sstevel@tonic-gate {
44997c478bd9Sstevel@tonic-gate 	rep_protocol_value_type_t t;
45007c478bd9Sstevel@tonic-gate 	scf_handle_t *h = val->value_handle;
45017c478bd9Sstevel@tonic-gate 
45027c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
45037c478bd9Sstevel@tonic-gate 	t = val->value_type;
45047c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
45057c478bd9Sstevel@tonic-gate 
45067c478bd9Sstevel@tonic-gate 	return (scf_protocol_type_to_type(t));
45077c478bd9Sstevel@tonic-gate }
45087c478bd9Sstevel@tonic-gate 
45097c478bd9Sstevel@tonic-gate int
scf_value_is_type(const scf_value_t * val,scf_type_t base_arg)45107c478bd9Sstevel@tonic-gate scf_value_is_type(const scf_value_t *val, scf_type_t base_arg)
45117c478bd9Sstevel@tonic-gate {
45127c478bd9Sstevel@tonic-gate 	rep_protocol_value_type_t t;
45137c478bd9Sstevel@tonic-gate 	rep_protocol_value_type_t base = scf_type_to_protocol_type(base_arg);
45147c478bd9Sstevel@tonic-gate 	scf_handle_t *h = val->value_handle;
45157c478bd9Sstevel@tonic-gate 
45167c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
45177c478bd9Sstevel@tonic-gate 	t = val->value_type;
45187c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
45197c478bd9Sstevel@tonic-gate 
45207c478bd9Sstevel@tonic-gate 	if (t == REP_PROTOCOL_TYPE_INVALID)
45217c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_NOT_SET));
45227c478bd9Sstevel@tonic-gate 	if (base == REP_PROTOCOL_TYPE_INVALID)
45237c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4524870ad75aSSean Wilcox 	if (!scf_is_compatible_protocol_type(base, t))
45257c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_TYPE_MISMATCH));
45267c478bd9Sstevel@tonic-gate 
45277c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
45287c478bd9Sstevel@tonic-gate }
45297c478bd9Sstevel@tonic-gate 
45307c478bd9Sstevel@tonic-gate /*
45317c478bd9Sstevel@tonic-gate  * Fails with
45327c478bd9Sstevel@tonic-gate  *   _NOT_SET - val is reset
45337c478bd9Sstevel@tonic-gate  *   _TYPE_MISMATCH - val's type is not compatible with t
45347c478bd9Sstevel@tonic-gate  */
45357c478bd9Sstevel@tonic-gate static int
scf_value_check_type(const scf_value_t * val,rep_protocol_value_type_t t)45367c478bd9Sstevel@tonic-gate scf_value_check_type(const scf_value_t *val, rep_protocol_value_type_t t)
45377c478bd9Sstevel@tonic-gate {
45387c478bd9Sstevel@tonic-gate 	if (val->value_type == REP_PROTOCOL_TYPE_INVALID) {
45397c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NOT_SET);
45407c478bd9Sstevel@tonic-gate 		return (0);
45417c478bd9Sstevel@tonic-gate 	}
4542870ad75aSSean Wilcox 	if (!scf_is_compatible_protocol_type(t, val->value_type)) {
45437c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_TYPE_MISMATCH);
45447c478bd9Sstevel@tonic-gate 		return (0);
45457c478bd9Sstevel@tonic-gate 	}
45467c478bd9Sstevel@tonic-gate 	return (1);
45477c478bd9Sstevel@tonic-gate }
45487c478bd9Sstevel@tonic-gate 
45497c478bd9Sstevel@tonic-gate /*
45507c478bd9Sstevel@tonic-gate  * Fails with
45517c478bd9Sstevel@tonic-gate  *   _NOT_SET - val is reset
45527c478bd9Sstevel@tonic-gate  *   _TYPE_MISMATCH - val is not _TYPE_BOOLEAN
45537c478bd9Sstevel@tonic-gate  */
45547c478bd9Sstevel@tonic-gate int
scf_value_get_boolean(const scf_value_t * val,uint8_t * out)45557c478bd9Sstevel@tonic-gate scf_value_get_boolean(const scf_value_t *val, uint8_t *out)
45567c478bd9Sstevel@tonic-gate {
45577c478bd9Sstevel@tonic-gate 	char c;
45587c478bd9Sstevel@tonic-gate 	scf_handle_t *h = val->value_handle;
45597c478bd9Sstevel@tonic-gate 	uint8_t o;
45607c478bd9Sstevel@tonic-gate 
45617c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
45627c478bd9Sstevel@tonic-gate 	if (!scf_value_check_type(val, REP_PROTOCOL_TYPE_BOOLEAN)) {
45637c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
45647c478bd9Sstevel@tonic-gate 		return (-1);
45657c478bd9Sstevel@tonic-gate 	}
45667c478bd9Sstevel@tonic-gate 
45677c478bd9Sstevel@tonic-gate 	c = val->value_value[0];
45687c478bd9Sstevel@tonic-gate 	assert((c == '0' || c == '1') && val->value_value[1] == 0);
45697c478bd9Sstevel@tonic-gate 
45707c478bd9Sstevel@tonic-gate 	o = (c != '0');
45717c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
45727c478bd9Sstevel@tonic-gate 	if (out != NULL)
45737c478bd9Sstevel@tonic-gate 		*out = o;
45747c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
45757c478bd9Sstevel@tonic-gate }
45767c478bd9Sstevel@tonic-gate 
45777c478bd9Sstevel@tonic-gate int
scf_value_get_count(const scf_value_t * val,uint64_t * out)45787c478bd9Sstevel@tonic-gate scf_value_get_count(const scf_value_t *val, uint64_t *out)
45797c478bd9Sstevel@tonic-gate {
45807c478bd9Sstevel@tonic-gate 	scf_handle_t *h = val->value_handle;
45817c478bd9Sstevel@tonic-gate 	uint64_t o;
45827c478bd9Sstevel@tonic-gate 
45837c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
45847c478bd9Sstevel@tonic-gate 	if (!scf_value_check_type(val, REP_PROTOCOL_TYPE_COUNT)) {
45857c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
45867c478bd9Sstevel@tonic-gate 		return (-1);
45877c478bd9Sstevel@tonic-gate 	}
45887c478bd9Sstevel@tonic-gate 
45897c478bd9Sstevel@tonic-gate 	o = strtoull(val->value_value, NULL, 10);
45907c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
45917c478bd9Sstevel@tonic-gate 	if (out != NULL)
45927c478bd9Sstevel@tonic-gate 		*out = o;
45937c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
45947c478bd9Sstevel@tonic-gate }
45957c478bd9Sstevel@tonic-gate 
45967c478bd9Sstevel@tonic-gate int
scf_value_get_integer(const scf_value_t * val,int64_t * out)45977c478bd9Sstevel@tonic-gate scf_value_get_integer(const scf_value_t *val, int64_t *out)
45987c478bd9Sstevel@tonic-gate {
45997c478bd9Sstevel@tonic-gate 	scf_handle_t *h = val->value_handle;
46007c478bd9Sstevel@tonic-gate 	int64_t o;
46017c478bd9Sstevel@tonic-gate 
46027c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
46037c478bd9Sstevel@tonic-gate 	if (!scf_value_check_type(val, REP_PROTOCOL_TYPE_INTEGER)) {
46047c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
46057c478bd9Sstevel@tonic-gate 		return (-1);
46067c478bd9Sstevel@tonic-gate 	}
46077c478bd9Sstevel@tonic-gate 
46087c478bd9Sstevel@tonic-gate 	o = strtoll(val->value_value, NULL, 10);
46097c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
46107c478bd9Sstevel@tonic-gate 	if (out != NULL)
46117c478bd9Sstevel@tonic-gate 		*out = o;
46127c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
46137c478bd9Sstevel@tonic-gate }
46147c478bd9Sstevel@tonic-gate 
46157c478bd9Sstevel@tonic-gate int
scf_value_get_time(const scf_value_t * val,int64_t * sec_out,int32_t * nsec_out)46167c478bd9Sstevel@tonic-gate scf_value_get_time(const scf_value_t *val, int64_t *sec_out, int32_t *nsec_out)
46177c478bd9Sstevel@tonic-gate {
46187c478bd9Sstevel@tonic-gate 	scf_handle_t *h = val->value_handle;
46197c478bd9Sstevel@tonic-gate 	char *p;
46207c478bd9Sstevel@tonic-gate 	int64_t os;
46217c478bd9Sstevel@tonic-gate 	int32_t ons;
46227c478bd9Sstevel@tonic-gate 
46237c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
46247c478bd9Sstevel@tonic-gate 	if (!scf_value_check_type(val, REP_PROTOCOL_TYPE_TIME)) {
46257c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
46267c478bd9Sstevel@tonic-gate 		return (-1);
46277c478bd9Sstevel@tonic-gate 	}
46287c478bd9Sstevel@tonic-gate 
46297c478bd9Sstevel@tonic-gate 	os = strtoll(val->value_value, &p, 10);
46307c478bd9Sstevel@tonic-gate 	if (*p == '.')
46317c478bd9Sstevel@tonic-gate 		ons = strtoul(p + 1, NULL, 10);
46327c478bd9Sstevel@tonic-gate 	else
46337c478bd9Sstevel@tonic-gate 		ons = 0;
46347c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
46357c478bd9Sstevel@tonic-gate 	if (sec_out != NULL)
46367c478bd9Sstevel@tonic-gate 		*sec_out = os;
46377c478bd9Sstevel@tonic-gate 	if (nsec_out != NULL)
46387c478bd9Sstevel@tonic-gate 		*nsec_out = ons;
46397c478bd9Sstevel@tonic-gate 
46407c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
46417c478bd9Sstevel@tonic-gate }
46427c478bd9Sstevel@tonic-gate 
46437c478bd9Sstevel@tonic-gate /*
46447c478bd9Sstevel@tonic-gate  * Fails with
46457c478bd9Sstevel@tonic-gate  *   _NOT_SET - val is reset
46467c478bd9Sstevel@tonic-gate  *   _TYPE_MISMATCH - val's type is not compatible with _TYPE_STRING.
46477c478bd9Sstevel@tonic-gate  */
46487c478bd9Sstevel@tonic-gate ssize_t
scf_value_get_astring(const scf_value_t * val,char * out,size_t len)46497c478bd9Sstevel@tonic-gate scf_value_get_astring(const scf_value_t *val, char *out, size_t len)
46507c478bd9Sstevel@tonic-gate {
46517c478bd9Sstevel@tonic-gate 	ssize_t ret;
46527c478bd9Sstevel@tonic-gate 	scf_handle_t *h = val->value_handle;
46537c478bd9Sstevel@tonic-gate 
46547c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
46557c478bd9Sstevel@tonic-gate 	if (!scf_value_check_type(val, REP_PROTOCOL_TYPE_STRING)) {
46567c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
46577c478bd9Sstevel@tonic-gate 		return ((ssize_t)-1);
46587c478bd9Sstevel@tonic-gate 	}
46597c478bd9Sstevel@tonic-gate 	ret = (ssize_t)strlcpy(out, val->value_value, len);
46607c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
46617c478bd9Sstevel@tonic-gate 	return (ret);
46627c478bd9Sstevel@tonic-gate }
46637c478bd9Sstevel@tonic-gate 
46647c478bd9Sstevel@tonic-gate ssize_t
scf_value_get_ustring(const scf_value_t * val,char * out,size_t len)46657c478bd9Sstevel@tonic-gate scf_value_get_ustring(const scf_value_t *val, char *out, size_t len)
46667c478bd9Sstevel@tonic-gate {
46677c478bd9Sstevel@tonic-gate 	ssize_t ret;
46687c478bd9Sstevel@tonic-gate 	scf_handle_t *h = val->value_handle;
46697c478bd9Sstevel@tonic-gate 
46707c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
46717c478bd9Sstevel@tonic-gate 	if (!scf_value_check_type(val, REP_PROTOCOL_SUBTYPE_USTRING)) {
46727c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
46737c478bd9Sstevel@tonic-gate 		return ((ssize_t)-1);
46747c478bd9Sstevel@tonic-gate 	}
46757c478bd9Sstevel@tonic-gate 	ret = (ssize_t)strlcpy(out, val->value_value, len);
46767c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
46777c478bd9Sstevel@tonic-gate 	return (ret);
46787c478bd9Sstevel@tonic-gate }
46797c478bd9Sstevel@tonic-gate 
46807c478bd9Sstevel@tonic-gate ssize_t
scf_value_get_opaque(const scf_value_t * v,void * out,size_t len)46817c478bd9Sstevel@tonic-gate scf_value_get_opaque(const scf_value_t *v, void *out, size_t len)
46827c478bd9Sstevel@tonic-gate {
46837c478bd9Sstevel@tonic-gate 	ssize_t ret;
46847c478bd9Sstevel@tonic-gate 	scf_handle_t *h = v->value_handle;
46857c478bd9Sstevel@tonic-gate 
46867c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
46877c478bd9Sstevel@tonic-gate 	if (!scf_value_check_type(v, REP_PROTOCOL_TYPE_OPAQUE)) {
46887c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
46897c478bd9Sstevel@tonic-gate 		return ((ssize_t)-1);
46907c478bd9Sstevel@tonic-gate 	}
46917c478bd9Sstevel@tonic-gate 	if (len > v->value_size)
46927c478bd9Sstevel@tonic-gate 		len = v->value_size;
46937c478bd9Sstevel@tonic-gate 	ret = len;
46947c478bd9Sstevel@tonic-gate 
46957c478bd9Sstevel@tonic-gate 	(void) memcpy(out, v->value_value, len);
46967c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
46977c478bd9Sstevel@tonic-gate 	return (ret);
46987c478bd9Sstevel@tonic-gate }
46997c478bd9Sstevel@tonic-gate 
47007c478bd9Sstevel@tonic-gate void
scf_value_set_boolean(scf_value_t * v,uint8_t new)47017c478bd9Sstevel@tonic-gate scf_value_set_boolean(scf_value_t *v, uint8_t new)
47027c478bd9Sstevel@tonic-gate {
47037c478bd9Sstevel@tonic-gate 	scf_handle_t *h = v->value_handle;
47047c478bd9Sstevel@tonic-gate 
47057c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
47067c478bd9Sstevel@tonic-gate 	scf_value_reset_locked(v, 0);
47077c478bd9Sstevel@tonic-gate 	v->value_type = REP_PROTOCOL_TYPE_BOOLEAN;
47087c478bd9Sstevel@tonic-gate 	(void) sprintf(v->value_value, "%d", (new != 0));
47097c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
47107c478bd9Sstevel@tonic-gate }
47117c478bd9Sstevel@tonic-gate 
47127c478bd9Sstevel@tonic-gate void
scf_value_set_count(scf_value_t * v,uint64_t new)47137c478bd9Sstevel@tonic-gate scf_value_set_count(scf_value_t *v, uint64_t new)
47147c478bd9Sstevel@tonic-gate {
47157c478bd9Sstevel@tonic-gate 	scf_handle_t *h = v->value_handle;
47167c478bd9Sstevel@tonic-gate 
47177c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
47187c478bd9Sstevel@tonic-gate 	scf_value_reset_locked(v, 0);
47197c478bd9Sstevel@tonic-gate 	v->value_type = REP_PROTOCOL_TYPE_COUNT;
47207c478bd9Sstevel@tonic-gate 	(void) sprintf(v->value_value, "%llu", (unsigned long long)new);
47217c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
47227c478bd9Sstevel@tonic-gate }
47237c478bd9Sstevel@tonic-gate 
47247c478bd9Sstevel@tonic-gate void
scf_value_set_integer(scf_value_t * v,int64_t new)47257c478bd9Sstevel@tonic-gate scf_value_set_integer(scf_value_t *v, int64_t new)
47267c478bd9Sstevel@tonic-gate {
47277c478bd9Sstevel@tonic-gate 	scf_handle_t *h = v->value_handle;
47287c478bd9Sstevel@tonic-gate 
47297c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
47307c478bd9Sstevel@tonic-gate 	scf_value_reset_locked(v, 0);
47317c478bd9Sstevel@tonic-gate 	v->value_type = REP_PROTOCOL_TYPE_INTEGER;
47327c478bd9Sstevel@tonic-gate 	(void) sprintf(v->value_value, "%lld", (long long)new);
47337c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
47347c478bd9Sstevel@tonic-gate }
47357c478bd9Sstevel@tonic-gate 
47367c478bd9Sstevel@tonic-gate int
scf_value_set_time(scf_value_t * v,int64_t new_sec,int32_t new_nsec)47377c478bd9Sstevel@tonic-gate scf_value_set_time(scf_value_t *v, int64_t new_sec, int32_t new_nsec)
47387c478bd9Sstevel@tonic-gate {
47397c478bd9Sstevel@tonic-gate 	scf_handle_t *h = v->value_handle;
47407c478bd9Sstevel@tonic-gate 
47417c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
47427c478bd9Sstevel@tonic-gate 	scf_value_reset_locked(v, 0);
47437c478bd9Sstevel@tonic-gate 	if (new_nsec < 0 || new_nsec >= NANOSEC) {
47447c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
47457c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
47467c478bd9Sstevel@tonic-gate 	}
47477c478bd9Sstevel@tonic-gate 	v->value_type = REP_PROTOCOL_TYPE_TIME;
47487c478bd9Sstevel@tonic-gate 	if (new_nsec == 0)
47497c478bd9Sstevel@tonic-gate 		(void) sprintf(v->value_value, "%lld", (long long)new_sec);
47507c478bd9Sstevel@tonic-gate 	else
47517c478bd9Sstevel@tonic-gate 		(void) sprintf(v->value_value, "%lld.%09u", (long long)new_sec,
47527c478bd9Sstevel@tonic-gate 		    (unsigned)new_nsec);
47537c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
47547c478bd9Sstevel@tonic-gate 	return (0);
47557c478bd9Sstevel@tonic-gate }
47567c478bd9Sstevel@tonic-gate 
47577c478bd9Sstevel@tonic-gate int
scf_value_set_astring(scf_value_t * v,const char * new)47587c478bd9Sstevel@tonic-gate scf_value_set_astring(scf_value_t *v, const char *new)
47597c478bd9Sstevel@tonic-gate {
47607c478bd9Sstevel@tonic-gate 	scf_handle_t *h = v->value_handle;
47617c478bd9Sstevel@tonic-gate 
47627c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
47637c478bd9Sstevel@tonic-gate 	scf_value_reset_locked(v, 0);
47647c478bd9Sstevel@tonic-gate 	if (!scf_validate_encoded_value(REP_PROTOCOL_TYPE_STRING, new)) {
47657c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
47667c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
47677c478bd9Sstevel@tonic-gate 	}
47687c478bd9Sstevel@tonic-gate 	if (strlcpy(v->value_value, new, sizeof (v->value_value)) >=
47697c478bd9Sstevel@tonic-gate 	    sizeof (v->value_value)) {
47707c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
47717c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
47727c478bd9Sstevel@tonic-gate 	}
47737c478bd9Sstevel@tonic-gate 	v->value_type = REP_PROTOCOL_TYPE_STRING;
47747c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
47757c478bd9Sstevel@tonic-gate 	return (0);
47767c478bd9Sstevel@tonic-gate }
47777c478bd9Sstevel@tonic-gate 
47787c478bd9Sstevel@tonic-gate int
scf_value_set_ustring(scf_value_t * v,const char * new)47797c478bd9Sstevel@tonic-gate scf_value_set_ustring(scf_value_t *v, const char *new)
47807c478bd9Sstevel@tonic-gate {
47817c478bd9Sstevel@tonic-gate 	scf_handle_t *h = v->value_handle;
47827c478bd9Sstevel@tonic-gate 
47837c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
47847c478bd9Sstevel@tonic-gate 	scf_value_reset_locked(v, 0);
47857c478bd9Sstevel@tonic-gate 	if (!scf_validate_encoded_value(REP_PROTOCOL_SUBTYPE_USTRING, new)) {
47867c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
47877c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
47887c478bd9Sstevel@tonic-gate 	}
47897c478bd9Sstevel@tonic-gate 	if (strlcpy(v->value_value, new, sizeof (v->value_value)) >=
47907c478bd9Sstevel@tonic-gate 	    sizeof (v->value_value)) {
47917c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
47927c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
47937c478bd9Sstevel@tonic-gate 	}
47947c478bd9Sstevel@tonic-gate 	v->value_type = REP_PROTOCOL_SUBTYPE_USTRING;
47957c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
47967c478bd9Sstevel@tonic-gate 	return (0);
47977c478bd9Sstevel@tonic-gate }
47987c478bd9Sstevel@tonic-gate 
47997c478bd9Sstevel@tonic-gate int
scf_value_set_opaque(scf_value_t * v,const void * new,size_t len)48007c478bd9Sstevel@tonic-gate scf_value_set_opaque(scf_value_t *v, const void *new, size_t len)
48017c478bd9Sstevel@tonic-gate {
48027c478bd9Sstevel@tonic-gate 	scf_handle_t *h = v->value_handle;
48037c478bd9Sstevel@tonic-gate 
48047c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
48057c478bd9Sstevel@tonic-gate 	scf_value_reset_locked(v, 0);
48067c478bd9Sstevel@tonic-gate 	if (len > sizeof (v->value_value)) {
48077c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
48087c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
48097c478bd9Sstevel@tonic-gate 	}
48107c478bd9Sstevel@tonic-gate 	(void) memcpy(v->value_value, new, len);
48117c478bd9Sstevel@tonic-gate 	v->value_size = len;
48127c478bd9Sstevel@tonic-gate 	v->value_type = REP_PROTOCOL_TYPE_OPAQUE;
48137c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
48147c478bd9Sstevel@tonic-gate 	return (0);
48157c478bd9Sstevel@tonic-gate }
48167c478bd9Sstevel@tonic-gate 
48177c478bd9Sstevel@tonic-gate /*
48187c478bd9Sstevel@tonic-gate  * Fails with
48197c478bd9Sstevel@tonic-gate  *   _NOT_SET - v_arg is reset
48207c478bd9Sstevel@tonic-gate  *   _INTERNAL - v_arg is corrupt
48217c478bd9Sstevel@tonic-gate  *
48227c478bd9Sstevel@tonic-gate  * If t is not _TYPE_INVALID, fails with
48237c478bd9Sstevel@tonic-gate  *   _TYPE_MISMATCH - v_arg's type is not compatible with t
48247c478bd9Sstevel@tonic-gate  */
48257c478bd9Sstevel@tonic-gate static ssize_t
scf_value_get_as_string_common(const scf_value_t * v_arg,rep_protocol_value_type_t t,char * buf,size_t bufsz)48267c478bd9Sstevel@tonic-gate scf_value_get_as_string_common(const scf_value_t *v_arg,
48277c478bd9Sstevel@tonic-gate     rep_protocol_value_type_t t, char *buf, size_t bufsz)
48287c478bd9Sstevel@tonic-gate {
48297c478bd9Sstevel@tonic-gate 	scf_handle_t *h = v_arg->value_handle;
48307c478bd9Sstevel@tonic-gate 	scf_value_t v_s;
48317c478bd9Sstevel@tonic-gate 	scf_value_t *v = &v_s;
48327c478bd9Sstevel@tonic-gate 	ssize_t r;
48337c478bd9Sstevel@tonic-gate 	uint8_t b;
48347c478bd9Sstevel@tonic-gate 
48357c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
48367c478bd9Sstevel@tonic-gate 	if (t != REP_PROTOCOL_TYPE_INVALID && !scf_value_check_type(v_arg, t)) {
48377c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
48387c478bd9Sstevel@tonic-gate 		return (-1);
48397c478bd9Sstevel@tonic-gate 	}
48407c478bd9Sstevel@tonic-gate 
48417c478bd9Sstevel@tonic-gate 	v_s = *v_arg;			/* copy locally so we can unlock */
48427c478bd9Sstevel@tonic-gate 	h->rh_values++;			/* keep the handle from going away */
48437c478bd9Sstevel@tonic-gate 	h->rh_extrefs++;
48447c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
48457c478bd9Sstevel@tonic-gate 
48467c478bd9Sstevel@tonic-gate 
48477c478bd9Sstevel@tonic-gate 	switch (REP_PROTOCOL_BASE_TYPE(v->value_type)) {
48487c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_TYPE_BOOLEAN:
48497c478bd9Sstevel@tonic-gate 		r = scf_value_get_boolean(v, &b);
48507c478bd9Sstevel@tonic-gate 		assert(r == SCF_SUCCESS);
48517c478bd9Sstevel@tonic-gate 
48527c478bd9Sstevel@tonic-gate 		r = strlcpy(buf, b ? "true" : "false", bufsz);
48537c478bd9Sstevel@tonic-gate 		break;
48547c478bd9Sstevel@tonic-gate 
48557c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_TYPE_COUNT:
48567c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_TYPE_INTEGER:
48577c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_TYPE_TIME:
48587c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_TYPE_STRING:
48597c478bd9Sstevel@tonic-gate 		r = strlcpy(buf, v->value_value, bufsz);
48607c478bd9Sstevel@tonic-gate 		break;
48617c478bd9Sstevel@tonic-gate 
48627c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_TYPE_OPAQUE:
48637c478bd9Sstevel@tonic-gate 		/*
48647c478bd9Sstevel@tonic-gate 		 * Note that we only write out full hex bytes -- if they're
48657c478bd9Sstevel@tonic-gate 		 * short, and bufsz is even, we'll only fill (bufsz - 2) bytes
48667c478bd9Sstevel@tonic-gate 		 * with data.
48677c478bd9Sstevel@tonic-gate 		 */
48687c478bd9Sstevel@tonic-gate 		if (bufsz > 0)
48697c478bd9Sstevel@tonic-gate 			(void) scf_opaque_encode(buf, v->value_value,
48707c478bd9Sstevel@tonic-gate 			    MIN(v->value_size, (bufsz - 1)/2));
48717c478bd9Sstevel@tonic-gate 		r = (v->value_size * 2);
48727c478bd9Sstevel@tonic-gate 		break;
48737c478bd9Sstevel@tonic-gate 
48747c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_TYPE_INVALID:
48757c478bd9Sstevel@tonic-gate 		r = scf_set_error(SCF_ERROR_NOT_SET);
48767c478bd9Sstevel@tonic-gate 		break;
48777c478bd9Sstevel@tonic-gate 
48787c478bd9Sstevel@tonic-gate 	default:
48797c478bd9Sstevel@tonic-gate 		r = (scf_set_error(SCF_ERROR_INTERNAL));
48807c478bd9Sstevel@tonic-gate 		break;
48817c478bd9Sstevel@tonic-gate 	}
48827c478bd9Sstevel@tonic-gate 
48837c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
48847c478bd9Sstevel@tonic-gate 	h->rh_values--;
48857c478bd9Sstevel@tonic-gate 	h->rh_extrefs--;
48867c478bd9Sstevel@tonic-gate 	handle_unrefed(h);
48877c478bd9Sstevel@tonic-gate 
48887c478bd9Sstevel@tonic-gate 	return (r);
48897c478bd9Sstevel@tonic-gate }
48907c478bd9Sstevel@tonic-gate 
48917c478bd9Sstevel@tonic-gate ssize_t
scf_value_get_as_string(const scf_value_t * v,char * buf,size_t bufsz)48927c478bd9Sstevel@tonic-gate scf_value_get_as_string(const scf_value_t *v, char *buf, size_t bufsz)
48937c478bd9Sstevel@tonic-gate {
48947c478bd9Sstevel@tonic-gate 	return (scf_value_get_as_string_common(v, REP_PROTOCOL_TYPE_INVALID,
48957c478bd9Sstevel@tonic-gate 	    buf, bufsz));
48967c478bd9Sstevel@tonic-gate }
48977c478bd9Sstevel@tonic-gate 
48987c478bd9Sstevel@tonic-gate ssize_t
scf_value_get_as_string_typed(const scf_value_t * v,scf_type_t type,char * buf,size_t bufsz)48997c478bd9Sstevel@tonic-gate scf_value_get_as_string_typed(const scf_value_t *v, scf_type_t type,
49007c478bd9Sstevel@tonic-gate     char *buf, size_t bufsz)
49017c478bd9Sstevel@tonic-gate {
49027c478bd9Sstevel@tonic-gate 	rep_protocol_value_type_t ty = scf_type_to_protocol_type(type);
49037c478bd9Sstevel@tonic-gate 	if (ty == REP_PROTOCOL_TYPE_INVALID)
49047c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
49057c478bd9Sstevel@tonic-gate 
49067c478bd9Sstevel@tonic-gate 	return (scf_value_get_as_string_common(v, ty, buf, bufsz));
49077c478bd9Sstevel@tonic-gate }
49087c478bd9Sstevel@tonic-gate 
49097c478bd9Sstevel@tonic-gate int
scf_value_set_from_string(scf_value_t * v,scf_type_t type,const char * str)49107c478bd9Sstevel@tonic-gate scf_value_set_from_string(scf_value_t *v, scf_type_t type, const char *str)
49117c478bd9Sstevel@tonic-gate {
49127c478bd9Sstevel@tonic-gate 	scf_handle_t *h = v->value_handle;
49137c478bd9Sstevel@tonic-gate 	rep_protocol_value_type_t ty;
49147c478bd9Sstevel@tonic-gate 
49157c478bd9Sstevel@tonic-gate 	switch (type) {
49167c478bd9Sstevel@tonic-gate 	case SCF_TYPE_BOOLEAN: {
49177c478bd9Sstevel@tonic-gate 		uint8_t b;
49187c478bd9Sstevel@tonic-gate 
49197c478bd9Sstevel@tonic-gate 		if (strcmp(str, "true") == 0 || strcmp(str, "t") == 0 ||
49207c478bd9Sstevel@tonic-gate 		    strcmp(str, "1") == 0)
49217c478bd9Sstevel@tonic-gate 			b = 1;
49227c478bd9Sstevel@tonic-gate 		else if (strcmp(str, "false") == 0 ||
49237c478bd9Sstevel@tonic-gate 		    strcmp(str, "f") == 0 || strcmp(str, "0") == 0)
49247c478bd9Sstevel@tonic-gate 			b = 0;
49257c478bd9Sstevel@tonic-gate 		else {
49267c478bd9Sstevel@tonic-gate 			goto bad;
49277c478bd9Sstevel@tonic-gate 		}
49287c478bd9Sstevel@tonic-gate 
49297c478bd9Sstevel@tonic-gate 		scf_value_set_boolean(v, b);
49307c478bd9Sstevel@tonic-gate 		return (0);
49317c478bd9Sstevel@tonic-gate 	}
49327c478bd9Sstevel@tonic-gate 
49337c478bd9Sstevel@tonic-gate 	case SCF_TYPE_COUNT: {
49347c478bd9Sstevel@tonic-gate 		uint64_t c;
49357c478bd9Sstevel@tonic-gate 		char *endp;
49367c478bd9Sstevel@tonic-gate 
49377c478bd9Sstevel@tonic-gate 		errno = 0;
4938f2fa366aSjeanm 		c = strtoull(str, &endp, 0);
49397c478bd9Sstevel@tonic-gate 
49407c478bd9Sstevel@tonic-gate 		if (errno != 0 || endp == str || *endp != '\0')
49417c478bd9Sstevel@tonic-gate 			goto bad;
49427c478bd9Sstevel@tonic-gate 
49437c478bd9Sstevel@tonic-gate 		scf_value_set_count(v, c);
49447c478bd9Sstevel@tonic-gate 		return (0);
49457c478bd9Sstevel@tonic-gate 	}
49467c478bd9Sstevel@tonic-gate 
49477c478bd9Sstevel@tonic-gate 	case SCF_TYPE_INTEGER: {
49487c478bd9Sstevel@tonic-gate 		int64_t i;
49497c478bd9Sstevel@tonic-gate 		char *endp;
49507c478bd9Sstevel@tonic-gate 
49517c478bd9Sstevel@tonic-gate 		errno = 0;
4952f2fa366aSjeanm 		i = strtoll(str, &endp, 0);
49537c478bd9Sstevel@tonic-gate 
49547c478bd9Sstevel@tonic-gate 		if (errno != 0 || endp == str || *endp != '\0')
49557c478bd9Sstevel@tonic-gate 			goto bad;
49567c478bd9Sstevel@tonic-gate 
49577c478bd9Sstevel@tonic-gate 		scf_value_set_integer(v, i);
49587c478bd9Sstevel@tonic-gate 		return (0);
49597c478bd9Sstevel@tonic-gate 	}
49607c478bd9Sstevel@tonic-gate 
49617c478bd9Sstevel@tonic-gate 	case SCF_TYPE_TIME: {
49627c478bd9Sstevel@tonic-gate 		int64_t s;
49637c478bd9Sstevel@tonic-gate 		uint32_t ns = 0;
49647c478bd9Sstevel@tonic-gate 		char *endp, *ns_str;
49657c478bd9Sstevel@tonic-gate 		size_t len;
49667c478bd9Sstevel@tonic-gate 
49677c478bd9Sstevel@tonic-gate 		errno = 0;
49687c478bd9Sstevel@tonic-gate 		s = strtoll(str, &endp, 10);
49697c478bd9Sstevel@tonic-gate 		if (errno != 0 || endp == str ||
49707c478bd9Sstevel@tonic-gate 		    (*endp != '\0' && *endp != '.'))
49717c478bd9Sstevel@tonic-gate 			goto bad;
49727c478bd9Sstevel@tonic-gate 
49737c478bd9Sstevel@tonic-gate 		if (*endp == '.') {
49747c478bd9Sstevel@tonic-gate 			ns_str = endp + 1;
49757c478bd9Sstevel@tonic-gate 			len = strlen(ns_str);
49767c478bd9Sstevel@tonic-gate 			if (len == 0 || len > 9)
49777c478bd9Sstevel@tonic-gate 				goto bad;
49787c478bd9Sstevel@tonic-gate 
49797c478bd9Sstevel@tonic-gate 			ns = strtoul(ns_str, &endp, 10);
49807c478bd9Sstevel@tonic-gate 			if (errno != 0 || endp == ns_str || *endp != '\0')
49817c478bd9Sstevel@tonic-gate 				goto bad;
49827c478bd9Sstevel@tonic-gate 
49837c478bd9Sstevel@tonic-gate 			while (len++ < 9)
49847c478bd9Sstevel@tonic-gate 				ns *= 10;
49857c478bd9Sstevel@tonic-gate 			assert(ns < NANOSEC);
49867c478bd9Sstevel@tonic-gate 		}
49877c478bd9Sstevel@tonic-gate 
49887c478bd9Sstevel@tonic-gate 		return (scf_value_set_time(v, s, ns));
49897c478bd9Sstevel@tonic-gate 	}
49907c478bd9Sstevel@tonic-gate 
49917c478bd9Sstevel@tonic-gate 	case SCF_TYPE_ASTRING:
49927c478bd9Sstevel@tonic-gate 	case SCF_TYPE_USTRING:
49937c478bd9Sstevel@tonic-gate 	case SCF_TYPE_OPAQUE:
49947c478bd9Sstevel@tonic-gate 	case SCF_TYPE_URI:
49957c478bd9Sstevel@tonic-gate 	case SCF_TYPE_FMRI:
49967c478bd9Sstevel@tonic-gate 	case SCF_TYPE_HOST:
49977c478bd9Sstevel@tonic-gate 	case SCF_TYPE_HOSTNAME:
4998b56bf881SAntonello Cruz 	case SCF_TYPE_NET_ADDR:
49997c478bd9Sstevel@tonic-gate 	case SCF_TYPE_NET_ADDR_V4:
50007c478bd9Sstevel@tonic-gate 	case SCF_TYPE_NET_ADDR_V6:
50017c478bd9Sstevel@tonic-gate 		ty = scf_type_to_protocol_type(type);
50027c478bd9Sstevel@tonic-gate 
50037c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_lock(&h->rh_lock);
50047c478bd9Sstevel@tonic-gate 		scf_value_reset_locked(v, 0);
50057c478bd9Sstevel@tonic-gate 		if (type == SCF_TYPE_OPAQUE) {
50067c478bd9Sstevel@tonic-gate 			v->value_size = scf_opaque_decode(v->value_value,
50077c478bd9Sstevel@tonic-gate 			    str, sizeof (v->value_value));
50087c478bd9Sstevel@tonic-gate 			if (!scf_validate_encoded_value(ty, str)) {
50097c478bd9Sstevel@tonic-gate 				(void) pthread_mutex_lock(&h->rh_lock);
50107c478bd9Sstevel@tonic-gate 				goto bad;
50117c478bd9Sstevel@tonic-gate 			}
50127c478bd9Sstevel@tonic-gate 		} else {
50137c478bd9Sstevel@tonic-gate 			(void) strlcpy(v->value_value, str,
50147c478bd9Sstevel@tonic-gate 			    sizeof (v->value_value));
50157c478bd9Sstevel@tonic-gate 			if (!scf_validate_encoded_value(ty, v->value_value)) {
50167c478bd9Sstevel@tonic-gate 				(void) pthread_mutex_lock(&h->rh_lock);
50177c478bd9Sstevel@tonic-gate 				goto bad;
50187c478bd9Sstevel@tonic-gate 			}
50197c478bd9Sstevel@tonic-gate 		}
50207c478bd9Sstevel@tonic-gate 		v->value_type = ty;
50217c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
50227c478bd9Sstevel@tonic-gate 		return (SCF_SUCCESS);
50237c478bd9Sstevel@tonic-gate 
50247c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_TYPE_INVALID:
50257c478bd9Sstevel@tonic-gate 	default:
50267c478bd9Sstevel@tonic-gate 		scf_value_reset(v);
50277c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_TYPE_MISMATCH));
50287c478bd9Sstevel@tonic-gate 	}
50297c478bd9Sstevel@tonic-gate bad:
50307c478bd9Sstevel@tonic-gate 	scf_value_reset(v);
50317c478bd9Sstevel@tonic-gate 	return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
50327c478bd9Sstevel@tonic-gate }
50337c478bd9Sstevel@tonic-gate 
50347c478bd9Sstevel@tonic-gate int
scf_iter_property_values(scf_iter_t * iter,const scf_property_t * prop)50357c478bd9Sstevel@tonic-gate scf_iter_property_values(scf_iter_t *iter, const scf_property_t *prop)
50367c478bd9Sstevel@tonic-gate {
50377c478bd9Sstevel@tonic-gate 	return (datael_setup_iter(iter, &prop->rd_d,
50387c478bd9Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_VALUE, 0));
50397c478bd9Sstevel@tonic-gate }
50407c478bd9Sstevel@tonic-gate 
50417c478bd9Sstevel@tonic-gate int
scf_iter_next_value(scf_iter_t * iter,scf_value_t * v)50427c478bd9Sstevel@tonic-gate scf_iter_next_value(scf_iter_t *iter, scf_value_t *v)
50437c478bd9Sstevel@tonic-gate {
50447c478bd9Sstevel@tonic-gate 	scf_handle_t *h = iter->iter_handle;
50457c478bd9Sstevel@tonic-gate 
50467c478bd9Sstevel@tonic-gate 	struct rep_protocol_iter_read_value request;
50477c478bd9Sstevel@tonic-gate 	struct rep_protocol_value_response response;
50487c478bd9Sstevel@tonic-gate 
50497c478bd9Sstevel@tonic-gate 	int r;
50507c478bd9Sstevel@tonic-gate 
50517c478bd9Sstevel@tonic-gate 	if (h != v->value_handle)
50527c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
50537c478bd9Sstevel@tonic-gate 
50547c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
50557c478bd9Sstevel@tonic-gate 
50567c478bd9Sstevel@tonic-gate 	scf_value_reset_locked(v, 0);
50577c478bd9Sstevel@tonic-gate 
50587c478bd9Sstevel@tonic-gate 	if (iter->iter_type == REP_PROTOCOL_ENTITY_NONE) {
50597c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
50607c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_NOT_SET));
50617c478bd9Sstevel@tonic-gate 	}
50627c478bd9Sstevel@tonic-gate 
50637c478bd9Sstevel@tonic-gate 	if (iter->iter_type != REP_PROTOCOL_ENTITY_VALUE) {
50647c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
50657c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
50667c478bd9Sstevel@tonic-gate 	}
50677c478bd9Sstevel@tonic-gate 
50687c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ITER_READ_VALUE;
50697c478bd9Sstevel@tonic-gate 	request.rpr_iterid = iter->iter_id;
50707c478bd9Sstevel@tonic-gate 	request.rpr_sequence = iter->iter_sequence;
50717c478bd9Sstevel@tonic-gate 
50727c478bd9Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
50737c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
50747c478bd9Sstevel@tonic-gate 
50757c478bd9Sstevel@tonic-gate 	if (r < 0) {
50767c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
50777c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
50787c478bd9Sstevel@tonic-gate 	}
50797c478bd9Sstevel@tonic-gate 
50807c478bd9Sstevel@tonic-gate 	if (response.rpr_response == REP_PROTOCOL_DONE) {
50817c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
50827c478bd9Sstevel@tonic-gate 		return (0);
50837c478bd9Sstevel@tonic-gate 	}
50847c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
50857c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
50867c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
50877c478bd9Sstevel@tonic-gate 	}
50887c478bd9Sstevel@tonic-gate 	iter->iter_sequence++;
50897c478bd9Sstevel@tonic-gate 
50907c478bd9Sstevel@tonic-gate 	v->value_type = response.rpr_type;
50917c478bd9Sstevel@tonic-gate 
50927c478bd9Sstevel@tonic-gate 	assert(scf_validate_encoded_value(response.rpr_type,
50937c478bd9Sstevel@tonic-gate 	    response.rpr_value));
50947c478bd9Sstevel@tonic-gate 
50957c478bd9Sstevel@tonic-gate 	if (v->value_type != REP_PROTOCOL_TYPE_OPAQUE) {
50967c478bd9Sstevel@tonic-gate 		(void) strlcpy(v->value_value, response.rpr_value,
50977c478bd9Sstevel@tonic-gate 		    sizeof (v->value_value));
50987c478bd9Sstevel@tonic-gate 	} else {
50997c478bd9Sstevel@tonic-gate 		v->value_size = scf_opaque_decode(v->value_value,
51007c478bd9Sstevel@tonic-gate 		    response.rpr_value, sizeof (v->value_value));
51017c478bd9Sstevel@tonic-gate 	}
51027c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
51037c478bd9Sstevel@tonic-gate 
51047c478bd9Sstevel@tonic-gate 	return (1);
51057c478bd9Sstevel@tonic-gate }
51067c478bd9Sstevel@tonic-gate 
51077c478bd9Sstevel@tonic-gate int
scf_property_get_value(const scf_property_t * prop,scf_value_t * v)51087c478bd9Sstevel@tonic-gate scf_property_get_value(const scf_property_t *prop, scf_value_t *v)
51097c478bd9Sstevel@tonic-gate {
51107c478bd9Sstevel@tonic-gate 	scf_handle_t *h = prop->rd_d.rd_handle;
51117c478bd9Sstevel@tonic-gate 	struct rep_protocol_property_request request;
51127c478bd9Sstevel@tonic-gate 	struct rep_protocol_value_response response;
51137c478bd9Sstevel@tonic-gate 	int r;
51147c478bd9Sstevel@tonic-gate 
51157c478bd9Sstevel@tonic-gate 	if (h != v->value_handle)
51167c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
51177c478bd9Sstevel@tonic-gate 
51187c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
51197c478bd9Sstevel@tonic-gate 
51207c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_PROPERTY_GET_VALUE;
51217c478bd9Sstevel@tonic-gate 	request.rpr_entityid = prop->rd_d.rd_entity;
51227c478bd9Sstevel@tonic-gate 
51237c478bd9Sstevel@tonic-gate 	scf_value_reset_locked(v, 0);
51247c478bd9Sstevel@tonic-gate 	datael_finish_reset(&prop->rd_d);
51257c478bd9Sstevel@tonic-gate 
51267c478bd9Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
51277c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
51287c478bd9Sstevel@tonic-gate 
51297c478bd9Sstevel@tonic-gate 	if (r < 0) {
51307c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
51317c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
51327c478bd9Sstevel@tonic-gate 	}
51337c478bd9Sstevel@tonic-gate 
51347c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS &&
51357c478bd9Sstevel@tonic-gate 	    response.rpr_response != REP_PROTOCOL_FAIL_TRUNCATED) {
51367c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&h->rh_lock);
51377c478bd9Sstevel@tonic-gate 		assert(response.rpr_response !=
51387c478bd9Sstevel@tonic-gate 		    REP_PROTOCOL_FAIL_TYPE_MISMATCH);
51397c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
51407c478bd9Sstevel@tonic-gate 	}
51417c478bd9Sstevel@tonic-gate 
51427c478bd9Sstevel@tonic-gate 	v->value_type = response.rpr_type;
51437c478bd9Sstevel@tonic-gate 	if (v->value_type != REP_PROTOCOL_TYPE_OPAQUE) {
51447c478bd9Sstevel@tonic-gate 		(void) strlcpy(v->value_value, response.rpr_value,
51457c478bd9Sstevel@tonic-gate 		    sizeof (v->value_value));
51467c478bd9Sstevel@tonic-gate 	} else {
51477c478bd9Sstevel@tonic-gate 		v->value_size = scf_opaque_decode(v->value_value,
51487c478bd9Sstevel@tonic-gate 		    response.rpr_value, sizeof (v->value_value));
51497c478bd9Sstevel@tonic-gate 	}
51507c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
51517c478bd9Sstevel@tonic-gate 	return ((response.rpr_response == REP_PROTOCOL_SUCCESS)?
51527c478bd9Sstevel@tonic-gate 	    SCF_SUCCESS : scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED));
51537c478bd9Sstevel@tonic-gate }
51547c478bd9Sstevel@tonic-gate 
51557c478bd9Sstevel@tonic-gate int
scf_pg_get_parent_service(const scf_propertygroup_t * pg,scf_service_t * svc)51567c478bd9Sstevel@tonic-gate scf_pg_get_parent_service(const scf_propertygroup_t *pg, scf_service_t *svc)
51577c478bd9Sstevel@tonic-gate {
51587c478bd9Sstevel@tonic-gate 	return (datael_get_parent(&pg->rd_d, &svc->rd_d));
51597c478bd9Sstevel@tonic-gate }
51607c478bd9Sstevel@tonic-gate 
51617c478bd9Sstevel@tonic-gate int
scf_pg_get_parent_instance(const scf_propertygroup_t * pg,scf_instance_t * inst)51627c478bd9Sstevel@tonic-gate scf_pg_get_parent_instance(const scf_propertygroup_t *pg, scf_instance_t *inst)
51637c478bd9Sstevel@tonic-gate {
51647c478bd9Sstevel@tonic-gate 	return (datael_get_parent(&pg->rd_d, &inst->rd_d));
51657c478bd9Sstevel@tonic-gate }
51667c478bd9Sstevel@tonic-gate 
51677c478bd9Sstevel@tonic-gate int
scf_pg_get_parent_snaplevel(const scf_propertygroup_t * pg,scf_snaplevel_t * level)51687c478bd9Sstevel@tonic-gate scf_pg_get_parent_snaplevel(const scf_propertygroup_t *pg,
51697c478bd9Sstevel@tonic-gate     scf_snaplevel_t *level)
51707c478bd9Sstevel@tonic-gate {
51717c478bd9Sstevel@tonic-gate 	return (datael_get_parent(&pg->rd_d, &level->rd_d));
51727c478bd9Sstevel@tonic-gate }
51737c478bd9Sstevel@tonic-gate 
51747c478bd9Sstevel@tonic-gate int
scf_service_get_parent(const scf_service_t * svc,scf_scope_t * s)51757c478bd9Sstevel@tonic-gate scf_service_get_parent(const scf_service_t *svc, scf_scope_t *s)
51767c478bd9Sstevel@tonic-gate {
51777c478bd9Sstevel@tonic-gate 	return (datael_get_parent(&svc->rd_d, &s->rd_d));
51787c478bd9Sstevel@tonic-gate }
51797c478bd9Sstevel@tonic-gate 
51807c478bd9Sstevel@tonic-gate int
scf_instance_get_parent(const scf_instance_t * inst,scf_service_t * svc)51817c478bd9Sstevel@tonic-gate scf_instance_get_parent(const scf_instance_t *inst, scf_service_t *svc)
51827c478bd9Sstevel@tonic-gate {
51837c478bd9Sstevel@tonic-gate 	return (datael_get_parent(&inst->rd_d, &svc->rd_d));
51847c478bd9Sstevel@tonic-gate }
51857c478bd9Sstevel@tonic-gate 
51867c478bd9Sstevel@tonic-gate int
scf_snapshot_get_parent(const scf_snapshot_t * inst,scf_instance_t * svc)51877c478bd9Sstevel@tonic-gate scf_snapshot_get_parent(const scf_snapshot_t *inst, scf_instance_t *svc)
51887c478bd9Sstevel@tonic-gate {
51897c478bd9Sstevel@tonic-gate 	return (datael_get_parent(&inst->rd_d, &svc->rd_d));
51907c478bd9Sstevel@tonic-gate }
51917c478bd9Sstevel@tonic-gate 
51927c478bd9Sstevel@tonic-gate int
scf_snaplevel_get_parent(const scf_snaplevel_t * inst,scf_snapshot_t * svc)51937c478bd9Sstevel@tonic-gate scf_snaplevel_get_parent(const scf_snaplevel_t *inst, scf_snapshot_t *svc)
51947c478bd9Sstevel@tonic-gate {
51957c478bd9Sstevel@tonic-gate 	return (datael_get_parent(&inst->rd_d, &svc->rd_d));
51967c478bd9Sstevel@tonic-gate }
51977c478bd9Sstevel@tonic-gate 
51987c478bd9Sstevel@tonic-gate /*
51997c478bd9Sstevel@tonic-gate  * FMRI functions
52007c478bd9Sstevel@tonic-gate  *
52017c478bd9Sstevel@tonic-gate  * Note: In the scf_parse_svc_fmri(), scf_parse_file_fmri() and
52027c478bd9Sstevel@tonic-gate  * scf_parse_fmri(), fmri isn't const because that would require
52037c478bd9Sstevel@tonic-gate  * allocating memory. Also, note that scope, at least, is not necessarily
52047c478bd9Sstevel@tonic-gate  * in the passed in fmri.
52057c478bd9Sstevel@tonic-gate  */
52067c478bd9Sstevel@tonic-gate 
52077c478bd9Sstevel@tonic-gate int
scf_parse_svc_fmri(char * fmri,const char ** scope,const char ** service,const char ** instance,const char ** propertygroup,const char ** property)52087c478bd9Sstevel@tonic-gate scf_parse_svc_fmri(char *fmri, const char **scope, const char **service,
52097c478bd9Sstevel@tonic-gate     const char **instance, const char **propertygroup, const char **property)
52107c478bd9Sstevel@tonic-gate {
52117c478bd9Sstevel@tonic-gate 	char *s, *e, *te, *tpg;
52127c478bd9Sstevel@tonic-gate 	char *my_s = NULL, *my_i = NULL, *my_pg = NULL, *my_p = NULL;
52137c478bd9Sstevel@tonic-gate 
52147c478bd9Sstevel@tonic-gate 	if (scope != NULL)
52157c478bd9Sstevel@tonic-gate 		*scope = NULL;
52167c478bd9Sstevel@tonic-gate 	if (service != NULL)
52177c478bd9Sstevel@tonic-gate 		*service = NULL;
52187c478bd9Sstevel@tonic-gate 	if (instance != NULL)
52197c478bd9Sstevel@tonic-gate 		*instance = NULL;
52207c478bd9Sstevel@tonic-gate 	if (propertygroup != NULL)
52217c478bd9Sstevel@tonic-gate 		*propertygroup = NULL;
52227c478bd9Sstevel@tonic-gate 	if (property != NULL)
52237c478bd9Sstevel@tonic-gate 		*property = NULL;
52247c478bd9Sstevel@tonic-gate 
52257c478bd9Sstevel@tonic-gate 	s = fmri;
52267c478bd9Sstevel@tonic-gate 	e = strchr(s, '\0');
52277c478bd9Sstevel@tonic-gate 
52287c478bd9Sstevel@tonic-gate 	if (strncmp(s, SCF_FMRI_SVC_PREFIX,
52297c478bd9Sstevel@tonic-gate 	    sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0)
52307c478bd9Sstevel@tonic-gate 		s += sizeof (SCF_FMRI_SVC_PREFIX) - 1;
52317c478bd9Sstevel@tonic-gate 
52327c478bd9Sstevel@tonic-gate 	if (strncmp(s, SCF_FMRI_SCOPE_PREFIX,
52337c478bd9Sstevel@tonic-gate 	    sizeof (SCF_FMRI_SCOPE_PREFIX) - 1) == 0) {
52347c478bd9Sstevel@tonic-gate 		char *my_scope;
52357c478bd9Sstevel@tonic-gate 
52367c478bd9Sstevel@tonic-gate 		s += sizeof (SCF_FMRI_SCOPE_PREFIX) - 1;
52377c478bd9Sstevel@tonic-gate 		te = strstr(s, SCF_FMRI_SERVICE_PREFIX);
52387c478bd9Sstevel@tonic-gate 		if (te == NULL)
52397c478bd9Sstevel@tonic-gate 			te = e;
52407c478bd9Sstevel@tonic-gate 
52417c478bd9Sstevel@tonic-gate 		*te = 0;
52427c478bd9Sstevel@tonic-gate 		my_scope = s;
52437c478bd9Sstevel@tonic-gate 
52447c478bd9Sstevel@tonic-gate 		s = te;
52457c478bd9Sstevel@tonic-gate 		if (s < e)
52467c478bd9Sstevel@tonic-gate 			s += sizeof (SCF_FMRI_SERVICE_PREFIX) - 1;
52477c478bd9Sstevel@tonic-gate 
52487c478bd9Sstevel@tonic-gate 		/* If the scope ends with the suffix, remove it. */
52497c478bd9Sstevel@tonic-gate 		te = strstr(my_scope, SCF_FMRI_SCOPE_SUFFIX);
52507c478bd9Sstevel@tonic-gate 		if (te != NULL && te[sizeof (SCF_FMRI_SCOPE_SUFFIX) - 1] == 0)
52517c478bd9Sstevel@tonic-gate 			*te = 0;
52527c478bd9Sstevel@tonic-gate 
52537c478bd9Sstevel@tonic-gate 		/* Validate the scope. */
52547c478bd9Sstevel@tonic-gate 		if (my_scope[0] == '\0')
52557c478bd9Sstevel@tonic-gate 			my_scope = SCF_FMRI_LOCAL_SCOPE;
52567c478bd9Sstevel@tonic-gate 		else if (uu_check_name(my_scope, 0) == -1) {
52577c478bd9Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
52587c478bd9Sstevel@tonic-gate 		}
52597c478bd9Sstevel@tonic-gate 
52607c478bd9Sstevel@tonic-gate 		if (scope != NULL)
52617c478bd9Sstevel@tonic-gate 			*scope = my_scope;
52627c478bd9Sstevel@tonic-gate 	} else {
52637c478bd9Sstevel@tonic-gate 		if (scope != NULL)
52647c478bd9Sstevel@tonic-gate 			*scope = SCF_FMRI_LOCAL_SCOPE;
52657c478bd9Sstevel@tonic-gate 	}
52667c478bd9Sstevel@tonic-gate 
52677c478bd9Sstevel@tonic-gate 	if (s[0] != 0) {
52687c478bd9Sstevel@tonic-gate 		if (strncmp(s, SCF_FMRI_SERVICE_PREFIX,
52697c478bd9Sstevel@tonic-gate 		    sizeof (SCF_FMRI_SERVICE_PREFIX) - 1) == 0)
52707c478bd9Sstevel@tonic-gate 			s += sizeof (SCF_FMRI_SERVICE_PREFIX) - 1;
52717c478bd9Sstevel@tonic-gate 
52727c478bd9Sstevel@tonic-gate 		/*
52737c478bd9Sstevel@tonic-gate 		 * Can't validate service here because it might not be null
52747c478bd9Sstevel@tonic-gate 		 * terminated.
52757c478bd9Sstevel@tonic-gate 		 */
52767c478bd9Sstevel@tonic-gate 		my_s = s;
52777c478bd9Sstevel@tonic-gate 	}
52787c478bd9Sstevel@tonic-gate 
52797c478bd9Sstevel@tonic-gate 	tpg = strstr(s, SCF_FMRI_PROPERTYGRP_PREFIX);
52807c478bd9Sstevel@tonic-gate 	te = strstr(s, SCF_FMRI_INSTANCE_PREFIX);
52817c478bd9Sstevel@tonic-gate 	if (te != NULL && (tpg == NULL || te < tpg)) {
52827c478bd9Sstevel@tonic-gate 		*te = 0;
52837c478bd9Sstevel@tonic-gate 		te += sizeof (SCF_FMRI_INSTANCE_PREFIX) - 1;
52847c478bd9Sstevel@tonic-gate 
52857c478bd9Sstevel@tonic-gate 		/* Can't validate instance here either. */
52867c478bd9Sstevel@tonic-gate 		my_i = s = te;
52877c478bd9Sstevel@tonic-gate 
52887c478bd9Sstevel@tonic-gate 		te = strstr(s, SCF_FMRI_PROPERTYGRP_PREFIX);
52897c478bd9Sstevel@tonic-gate 	} else {
52907c478bd9Sstevel@tonic-gate 		te = tpg;
52917c478bd9Sstevel@tonic-gate 	}
52927c478bd9Sstevel@tonic-gate 
52937c478bd9Sstevel@tonic-gate 	if (te != NULL) {
52947c478bd9Sstevel@tonic-gate 		*te = 0;
52957c478bd9Sstevel@tonic-gate 		te += sizeof (SCF_FMRI_PROPERTYGRP_PREFIX) - 1;
52967c478bd9Sstevel@tonic-gate 
52977c478bd9Sstevel@tonic-gate 		my_pg = s = te;
52987c478bd9Sstevel@tonic-gate 		te = strstr(s, SCF_FMRI_PROPERTY_PREFIX);
52997c478bd9Sstevel@tonic-gate 		if (te != NULL) {
53007c478bd9Sstevel@tonic-gate 			*te = 0;
53017c478bd9Sstevel@tonic-gate 			te += sizeof (SCF_FMRI_PROPERTY_PREFIX) - 1;
53027c478bd9Sstevel@tonic-gate 
53037c478bd9Sstevel@tonic-gate 			my_p = te;
53047c478bd9Sstevel@tonic-gate 			s = te;
53057c478bd9Sstevel@tonic-gate 		}
53067c478bd9Sstevel@tonic-gate 	}
53077c478bd9Sstevel@tonic-gate 
53087c478bd9Sstevel@tonic-gate 	if (my_s != NULL) {
53097c478bd9Sstevel@tonic-gate 		if (uu_check_name(my_s, UU_NAME_DOMAIN | UU_NAME_PATH) == -1)
53107c478bd9Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
53117c478bd9Sstevel@tonic-gate 
53127c478bd9Sstevel@tonic-gate 		if (service != NULL)
53137c478bd9Sstevel@tonic-gate 			*service = my_s;
53147c478bd9Sstevel@tonic-gate 	}
53157c478bd9Sstevel@tonic-gate 
53167c478bd9Sstevel@tonic-gate 	if (my_i != NULL) {
53177c478bd9Sstevel@tonic-gate 		if (uu_check_name(my_i, UU_NAME_DOMAIN) == -1)
53187c478bd9Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
53197c478bd9Sstevel@tonic-gate 
53207c478bd9Sstevel@tonic-gate 		if (instance != NULL)
53217c478bd9Sstevel@tonic-gate 			*instance = my_i;
53227c478bd9Sstevel@tonic-gate 	}
53237c478bd9Sstevel@tonic-gate 
53247c478bd9Sstevel@tonic-gate 	if (my_pg != NULL) {
53257c478bd9Sstevel@tonic-gate 		if (uu_check_name(my_pg, UU_NAME_DOMAIN) == -1)
53267c478bd9Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
53277c478bd9Sstevel@tonic-gate 
53287c478bd9Sstevel@tonic-gate 		if (propertygroup != NULL)
53297c478bd9Sstevel@tonic-gate 			*propertygroup = my_pg;
53307c478bd9Sstevel@tonic-gate 	}
53317c478bd9Sstevel@tonic-gate 
53327c478bd9Sstevel@tonic-gate 	if (my_p != NULL) {
53337c478bd9Sstevel@tonic-gate 		if (uu_check_name(my_p, UU_NAME_DOMAIN) == -1)
53347c478bd9Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
53357c478bd9Sstevel@tonic-gate 
53367c478bd9Sstevel@tonic-gate 		if (property != NULL)
53377c478bd9Sstevel@tonic-gate 			*property = my_p;
53387c478bd9Sstevel@tonic-gate 	}
53397c478bd9Sstevel@tonic-gate 
53407c478bd9Sstevel@tonic-gate 	return (0);
53417c478bd9Sstevel@tonic-gate }
53427c478bd9Sstevel@tonic-gate 
53437c478bd9Sstevel@tonic-gate int
scf_parse_file_fmri(char * fmri,const char ** scope,const char ** path)53447c478bd9Sstevel@tonic-gate scf_parse_file_fmri(char *fmri, const char **scope, const char **path)
53457c478bd9Sstevel@tonic-gate {
53467c478bd9Sstevel@tonic-gate 	char *s, *e, *te;
53477c478bd9Sstevel@tonic-gate 
53487c478bd9Sstevel@tonic-gate 	if (scope != NULL)
53497c478bd9Sstevel@tonic-gate 		*scope = NULL;
53507c478bd9Sstevel@tonic-gate 
53517c478bd9Sstevel@tonic-gate 	s = fmri;
53527c478bd9Sstevel@tonic-gate 	e = strchr(s, '\0');
53537c478bd9Sstevel@tonic-gate 
53547c478bd9Sstevel@tonic-gate 	if (strncmp(s, SCF_FMRI_FILE_PREFIX,
53557c478bd9Sstevel@tonic-gate 	    sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0)
53567c478bd9Sstevel@tonic-gate 		s += sizeof (SCF_FMRI_FILE_PREFIX) - 1;
53577c478bd9Sstevel@tonic-gate 
53587c478bd9Sstevel@tonic-gate 	if (strncmp(s, SCF_FMRI_SCOPE_PREFIX,
53597c478bd9Sstevel@tonic-gate 	    sizeof (SCF_FMRI_SCOPE_PREFIX) - 1) == 0) {
53607c478bd9Sstevel@tonic-gate 		char *my_scope;
53617c478bd9Sstevel@tonic-gate 
53627c478bd9Sstevel@tonic-gate 		s += sizeof (SCF_FMRI_SCOPE_PREFIX) - 1;
53637c478bd9Sstevel@tonic-gate 		te = strstr(s, SCF_FMRI_SERVICE_PREFIX);
53647c478bd9Sstevel@tonic-gate 		if (te == NULL)
53657c478bd9Sstevel@tonic-gate 			te = e;
53667c478bd9Sstevel@tonic-gate 
53677c478bd9Sstevel@tonic-gate 		*te = 0;
53687c478bd9Sstevel@tonic-gate 		my_scope = s;
53697c478bd9Sstevel@tonic-gate 
53707c478bd9Sstevel@tonic-gate 		s = te;
53717c478bd9Sstevel@tonic-gate 
53727c478bd9Sstevel@tonic-gate 		/* Validate the scope. */
53737c478bd9Sstevel@tonic-gate 		if (my_scope[0] != '\0' &&
53747c478bd9Sstevel@tonic-gate 		    strcmp(my_scope, SCF_FMRI_LOCAL_SCOPE) != 0) {
53757c478bd9Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
53767c478bd9Sstevel@tonic-gate 		}
53777c478bd9Sstevel@tonic-gate 
53787c478bd9Sstevel@tonic-gate 		if (scope != NULL)
53797c478bd9Sstevel@tonic-gate 			*scope = my_scope;
53807c478bd9Sstevel@tonic-gate 	} else {
53817c478bd9Sstevel@tonic-gate 		/*
53827c478bd9Sstevel@tonic-gate 		 * FMRI paths must be absolute
53837c478bd9Sstevel@tonic-gate 		 */
53847c478bd9Sstevel@tonic-gate 		if (s[0] != '/')
53857c478bd9Sstevel@tonic-gate 			return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
53867c478bd9Sstevel@tonic-gate 	}
53877c478bd9Sstevel@tonic-gate 
53887c478bd9Sstevel@tonic-gate 	s += sizeof (SCF_FMRI_SERVICE_PREFIX) - 1;
53897c478bd9Sstevel@tonic-gate 
53907c478bd9Sstevel@tonic-gate 	if (s >= e)
53917c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
53927c478bd9Sstevel@tonic-gate 
53937c478bd9Sstevel@tonic-gate 	/*
53947c478bd9Sstevel@tonic-gate 	 * If the user requests it, return the full path of the file.
53957c478bd9Sstevel@tonic-gate 	 */
53967c478bd9Sstevel@tonic-gate 	if (path != NULL) {
53977c478bd9Sstevel@tonic-gate 		assert(s > fmri);
53987c478bd9Sstevel@tonic-gate 		s[-1] = '/';
53997c478bd9Sstevel@tonic-gate 		*path = s - 1;
54007c478bd9Sstevel@tonic-gate 	}
54017c478bd9Sstevel@tonic-gate 
54027c478bd9Sstevel@tonic-gate 	return (0);
54037c478bd9Sstevel@tonic-gate }
54047c478bd9Sstevel@tonic-gate 
54057c478bd9Sstevel@tonic-gate int
scf_parse_fmri(char * fmri,int * type,const char ** scope,const char ** service,const char ** instance,const char ** propertygroup,const char ** property)54067c478bd9Sstevel@tonic-gate scf_parse_fmri(char *fmri, int *type, const char **scope, const char **service,
54077c478bd9Sstevel@tonic-gate     const char **instance, const char **propertygroup, const char **property)
54087c478bd9Sstevel@tonic-gate {
54097c478bd9Sstevel@tonic-gate 	if (strncmp(fmri, SCF_FMRI_SVC_PREFIX,
54107c478bd9Sstevel@tonic-gate 	    sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) {
54117c478bd9Sstevel@tonic-gate 		if (type)
54127c478bd9Sstevel@tonic-gate 			*type = SCF_FMRI_TYPE_SVC;
54137c478bd9Sstevel@tonic-gate 		return (scf_parse_svc_fmri(fmri, scope, service, instance,
541476cf44abSjeanm 		    propertygroup, property));
54157c478bd9Sstevel@tonic-gate 	} else if (strncmp(fmri, SCF_FMRI_FILE_PREFIX,
54167c478bd9Sstevel@tonic-gate 	    sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) {
54177c478bd9Sstevel@tonic-gate 		if (type)
54187c478bd9Sstevel@tonic-gate 			*type = SCF_FMRI_TYPE_FILE;
54197c478bd9Sstevel@tonic-gate 		return (scf_parse_file_fmri(fmri, scope, NULL));
54207c478bd9Sstevel@tonic-gate 	} else {
54217c478bd9Sstevel@tonic-gate 		/*
54227c478bd9Sstevel@tonic-gate 		 * Parse as a svc if the fmri type is not explicitly
54237c478bd9Sstevel@tonic-gate 		 * specified.
54247c478bd9Sstevel@tonic-gate 		 */
54257c478bd9Sstevel@tonic-gate 		if (type)
54267c478bd9Sstevel@tonic-gate 			*type = SCF_FMRI_TYPE_SVC;
54277c478bd9Sstevel@tonic-gate 		return (scf_parse_svc_fmri(fmri, scope, service, instance,
54287c478bd9Sstevel@tonic-gate 		    propertygroup, property));
54297c478bd9Sstevel@tonic-gate 	}
54307c478bd9Sstevel@tonic-gate }
54317c478bd9Sstevel@tonic-gate 
54327c478bd9Sstevel@tonic-gate /*
54337c478bd9Sstevel@tonic-gate  * Fails with _INVALID_ARGUMENT.  fmri and buf may be equal.
54347c478bd9Sstevel@tonic-gate  */
54357c478bd9Sstevel@tonic-gate ssize_t
scf_canonify_fmri(const char * fmri,char * buf,size_t bufsz)54367c478bd9Sstevel@tonic-gate scf_canonify_fmri(const char *fmri, char *buf, size_t bufsz)
54377c478bd9Sstevel@tonic-gate {
54387c478bd9Sstevel@tonic-gate 	const char *scope, *service, *instance, *pg, *property;
54397c478bd9Sstevel@tonic-gate 	char local[6 * REP_PROTOCOL_NAME_LEN];
54407c478bd9Sstevel@tonic-gate 	int r;
54417c478bd9Sstevel@tonic-gate 	size_t len;
54427c478bd9Sstevel@tonic-gate 
54437c478bd9Sstevel@tonic-gate 	if (strlcpy(local, fmri, sizeof (local)) >= sizeof (local)) {
54447c478bd9Sstevel@tonic-gate 		/* Should this be CONSTRAINT_VIOLATED? */
54457c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
54467c478bd9Sstevel@tonic-gate 		return (-1);
54477c478bd9Sstevel@tonic-gate 	}
54487c478bd9Sstevel@tonic-gate 
54497c478bd9Sstevel@tonic-gate 
54507c478bd9Sstevel@tonic-gate 	r = scf_parse_svc_fmri(local, &scope, &service, &instance, &pg,
54517c478bd9Sstevel@tonic-gate 	    &property);
54527c478bd9Sstevel@tonic-gate 	if (r != 0)
54537c478bd9Sstevel@tonic-gate 		return (-1);
54547c478bd9Sstevel@tonic-gate 
54557c478bd9Sstevel@tonic-gate 	len = strlcpy(buf, "svc:/", bufsz);
54567c478bd9Sstevel@tonic-gate 
54577c478bd9Sstevel@tonic-gate 	if (scope != NULL && strcmp(scope, SCF_SCOPE_LOCAL) != 0) {
54587c478bd9Sstevel@tonic-gate 		len += strlcat(buf, "/", bufsz);
54597c478bd9Sstevel@tonic-gate 		len += strlcat(buf, scope, bufsz);
54607c478bd9Sstevel@tonic-gate 	}
54617c478bd9Sstevel@tonic-gate 
54627c478bd9Sstevel@tonic-gate 	if (service)
54637c478bd9Sstevel@tonic-gate 		len += strlcat(buf, service, bufsz);
54647c478bd9Sstevel@tonic-gate 
54657c478bd9Sstevel@tonic-gate 	if (instance) {
54667c478bd9Sstevel@tonic-gate 		len += strlcat(buf, ":", bufsz);
54677c478bd9Sstevel@tonic-gate 		len += strlcat(buf, instance, bufsz);
54687c478bd9Sstevel@tonic-gate 	}
54697c478bd9Sstevel@tonic-gate 
54707c478bd9Sstevel@tonic-gate 	if (pg) {
54717c478bd9Sstevel@tonic-gate 		len += strlcat(buf, "/:properties/", bufsz);
54727c478bd9Sstevel@tonic-gate 		len += strlcat(buf, pg, bufsz);
54737c478bd9Sstevel@tonic-gate 	}
54747c478bd9Sstevel@tonic-gate 
54757c478bd9Sstevel@tonic-gate 	if (property) {
54767c478bd9Sstevel@tonic-gate 		len += strlcat(buf, "/", bufsz);
54777c478bd9Sstevel@tonic-gate 		len += strlcat(buf, property, bufsz);
54787c478bd9Sstevel@tonic-gate 	}
54797c478bd9Sstevel@tonic-gate 
54807c478bd9Sstevel@tonic-gate 	return (len);
54817c478bd9Sstevel@tonic-gate }
54827c478bd9Sstevel@tonic-gate 
548376cf44abSjeanm /*
548476cf44abSjeanm  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _CONSTRAINT_VIOLATED,
548576cf44abSjeanm  * _NOT_FOUND, _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED,
548676cf44abSjeanm  * _NO_RESOURCES, _BACKEND_ACCESS.
548776cf44abSjeanm  */
54887c478bd9Sstevel@tonic-gate int
scf_handle_decode_fmri(scf_handle_t * h,const char * fmri,scf_scope_t * sc,scf_service_t * svc,scf_instance_t * inst,scf_propertygroup_t * pg,scf_property_t * prop,int flags)54897c478bd9Sstevel@tonic-gate scf_handle_decode_fmri(scf_handle_t *h, const char *fmri, scf_scope_t *sc,
54907c478bd9Sstevel@tonic-gate     scf_service_t *svc, scf_instance_t *inst, scf_propertygroup_t *pg,
54917c478bd9Sstevel@tonic-gate     scf_property_t *prop, int flags)
54927c478bd9Sstevel@tonic-gate {
54937c478bd9Sstevel@tonic-gate 	const char *scope, *service, *instance, *propertygroup, *property;
54947c478bd9Sstevel@tonic-gate 	int last;
54957c478bd9Sstevel@tonic-gate 	char local[6 * REP_PROTOCOL_NAME_LEN];
54967c478bd9Sstevel@tonic-gate 	int ret;
54977c478bd9Sstevel@tonic-gate 	const uint32_t holds = RH_HOLD_SCOPE | RH_HOLD_SERVICE |
54987c478bd9Sstevel@tonic-gate 	    RH_HOLD_INSTANCE | RH_HOLD_PG | RH_HOLD_PROPERTY;
54997c478bd9Sstevel@tonic-gate 
55007c478bd9Sstevel@tonic-gate 	/*
55017c478bd9Sstevel@tonic-gate 	 * verify that all handles match
55027c478bd9Sstevel@tonic-gate 	 */
55037c478bd9Sstevel@tonic-gate 	if ((sc != NULL && h != sc->rd_d.rd_handle) ||
55047c478bd9Sstevel@tonic-gate 	    (svc != NULL && h != svc->rd_d.rd_handle) ||
55057c478bd9Sstevel@tonic-gate 	    (inst != NULL && h != inst->rd_d.rd_handle) ||
55067c478bd9Sstevel@tonic-gate 	    (pg != NULL && h != pg->rd_d.rd_handle) ||
55077c478bd9Sstevel@tonic-gate 	    (prop != NULL && h != prop->rd_d.rd_handle))
55087c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
55097c478bd9Sstevel@tonic-gate 
55107c478bd9Sstevel@tonic-gate 	if (strlcpy(local, fmri, sizeof (local)) >= sizeof (local)) {
55117c478bd9Sstevel@tonic-gate 		ret = scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
55127c478bd9Sstevel@tonic-gate 		goto reset_args;
55137c478bd9Sstevel@tonic-gate 	}
55147c478bd9Sstevel@tonic-gate 
55157c478bd9Sstevel@tonic-gate 	/*
55167c478bd9Sstevel@tonic-gate 	 * We can simply return from an error in parsing, because
55177c478bd9Sstevel@tonic-gate 	 * scf_parse_fmri sets the error code correctly.
55187c478bd9Sstevel@tonic-gate 	 */
55197c478bd9Sstevel@tonic-gate 	if (scf_parse_svc_fmri(local, &scope, &service, &instance,
55207c478bd9Sstevel@tonic-gate 	    &propertygroup, &property) == -1) {
55217c478bd9Sstevel@tonic-gate 		ret = -1;
55227c478bd9Sstevel@tonic-gate 		goto reset_args;
55237c478bd9Sstevel@tonic-gate 	}
55247c478bd9Sstevel@tonic-gate 
55257c478bd9Sstevel@tonic-gate 	/*
55267c478bd9Sstevel@tonic-gate 	 * the FMRI looks valid at this point -- do constraint checks.
55277c478bd9Sstevel@tonic-gate 	 */
55287c478bd9Sstevel@tonic-gate 
55297c478bd9Sstevel@tonic-gate 	if (instance != NULL && (flags & SCF_DECODE_FMRI_REQUIRE_NO_INSTANCE)) {
55307c478bd9Sstevel@tonic-gate 		ret = scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED);
55317c478bd9Sstevel@tonic-gate 		goto reset_args;
55327c478bd9Sstevel@tonic-gate 	}
55337c478bd9Sstevel@tonic-gate 	if (instance == NULL && (flags & SCF_DECODE_FMRI_REQUIRE_INSTANCE)) {
55347c478bd9Sstevel@tonic-gate 		ret = scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED);
55357c478bd9Sstevel@tonic-gate 		goto reset_args;
55367c478bd9Sstevel@tonic-gate 	}
55377c478bd9Sstevel@tonic-gate 
55387c478bd9Sstevel@tonic-gate 	if (prop != NULL)
55397c478bd9Sstevel@tonic-gate 		last = REP_PROTOCOL_ENTITY_PROPERTY;
55407c478bd9Sstevel@tonic-gate 	else if (pg != NULL)
55417c478bd9Sstevel@tonic-gate 		last = REP_PROTOCOL_ENTITY_PROPERTYGRP;
55427c478bd9Sstevel@tonic-gate 	else if (inst != NULL)
55437c478bd9Sstevel@tonic-gate 		last = REP_PROTOCOL_ENTITY_INSTANCE;
55447c478bd9Sstevel@tonic-gate 	else if (svc != NULL)
55457c478bd9Sstevel@tonic-gate 		last = REP_PROTOCOL_ENTITY_SERVICE;
55467c478bd9Sstevel@tonic-gate 	else if (sc != NULL)
55477c478bd9Sstevel@tonic-gate 		last = REP_PROTOCOL_ENTITY_SCOPE;
55487c478bd9Sstevel@tonic-gate 	else
55497c478bd9Sstevel@tonic-gate 		last = REP_PROTOCOL_ENTITY_NONE;
55507c478bd9Sstevel@tonic-gate 
55517c478bd9Sstevel@tonic-gate 	if (flags & SCF_DECODE_FMRI_EXACT) {
55527c478bd9Sstevel@tonic-gate 		int last_fmri;
55537c478bd9Sstevel@tonic-gate 
55547c478bd9Sstevel@tonic-gate 		if (property != NULL)
55557c478bd9Sstevel@tonic-gate 			last_fmri = REP_PROTOCOL_ENTITY_PROPERTY;
55567c478bd9Sstevel@tonic-gate 		else if (propertygroup != NULL)
55577c478bd9Sstevel@tonic-gate 			last_fmri = REP_PROTOCOL_ENTITY_PROPERTYGRP;
55587c478bd9Sstevel@tonic-gate 		else if (instance != NULL)
55597c478bd9Sstevel@tonic-gate 			last_fmri = REP_PROTOCOL_ENTITY_INSTANCE;
55607c478bd9Sstevel@tonic-gate 		else if (service != NULL)
55617c478bd9Sstevel@tonic-gate 			last_fmri = REP_PROTOCOL_ENTITY_SERVICE;
55627c478bd9Sstevel@tonic-gate 		else if (scope != NULL)
55637c478bd9Sstevel@tonic-gate 			last_fmri = REP_PROTOCOL_ENTITY_SCOPE;
55647c478bd9Sstevel@tonic-gate 		else
55657c478bd9Sstevel@tonic-gate 			last_fmri = REP_PROTOCOL_ENTITY_NONE;
55667c478bd9Sstevel@tonic-gate 
55677c478bd9Sstevel@tonic-gate 		if (last != last_fmri) {
55687c478bd9Sstevel@tonic-gate 			ret = scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED);
55697c478bd9Sstevel@tonic-gate 			goto reset_args;
55707c478bd9Sstevel@tonic-gate 		}
55717c478bd9Sstevel@tonic-gate 	}
55727c478bd9Sstevel@tonic-gate 
55737c478bd9Sstevel@tonic-gate 	if ((flags & SCF_DECODE_FMRI_TRUNCATE) &&
55747c478bd9Sstevel@tonic-gate 	    last == REP_PROTOCOL_ENTITY_NONE) {
55757c478bd9Sstevel@tonic-gate 		ret = 0;				/* nothing to do */
55767c478bd9Sstevel@tonic-gate 		goto reset_args;
55777c478bd9Sstevel@tonic-gate 	}
55787c478bd9Sstevel@tonic-gate 
55797c478bd9Sstevel@tonic-gate 	if (!(flags & SCF_DECODE_FMRI_TRUNCATE))
55807c478bd9Sstevel@tonic-gate 		last = REP_PROTOCOL_ENTITY_NONE;	/* never stop */
55817c478bd9Sstevel@tonic-gate 
55827c478bd9Sstevel@tonic-gate 	/*
55837c478bd9Sstevel@tonic-gate 	 * passed the constraint checks -- try to grab the thing itself.
55847c478bd9Sstevel@tonic-gate 	 */
55857c478bd9Sstevel@tonic-gate 
55867c478bd9Sstevel@tonic-gate 	handle_hold_subhandles(h, holds);
55877c478bd9Sstevel@tonic-gate 	if (sc == NULL)
55887c478bd9Sstevel@tonic-gate 		sc = h->rh_scope;
55897c478bd9Sstevel@tonic-gate 	else
55907c478bd9Sstevel@tonic-gate 		datael_reset(&sc->rd_d);
55917c478bd9Sstevel@tonic-gate 
55927c478bd9Sstevel@tonic-gate 	if (svc == NULL)
55937c478bd9Sstevel@tonic-gate 		svc = h->rh_service;
55947c478bd9Sstevel@tonic-gate 	else
55957c478bd9Sstevel@tonic-gate 		datael_reset(&svc->rd_d);
55967c478bd9Sstevel@tonic-gate 
55977c478bd9Sstevel@tonic-gate 	if (inst == NULL)
55987c478bd9Sstevel@tonic-gate 		inst = h->rh_instance;
55997c478bd9Sstevel@tonic-gate 	else
56007c478bd9Sstevel@tonic-gate 		datael_reset(&inst->rd_d);
56017c478bd9Sstevel@tonic-gate 
56027c478bd9Sstevel@tonic-gate 	if (pg == NULL)
56037c478bd9Sstevel@tonic-gate 		pg = h->rh_pg;
56047c478bd9Sstevel@tonic-gate 	else
56057c478bd9Sstevel@tonic-gate 		datael_reset(&pg->rd_d);
56067c478bd9Sstevel@tonic-gate 
56077c478bd9Sstevel@tonic-gate 	if (prop == NULL)
56087c478bd9Sstevel@tonic-gate 		prop = h->rh_property;
56097c478bd9Sstevel@tonic-gate 	else
56107c478bd9Sstevel@tonic-gate 		datael_reset(&prop->rd_d);
56117c478bd9Sstevel@tonic-gate 
56127c478bd9Sstevel@tonic-gate 	/*
56137c478bd9Sstevel@tonic-gate 	 * We only support local scopes, but we check *after* getting
56147c478bd9Sstevel@tonic-gate 	 * the local scope, so that any repository-related errors take
56157c478bd9Sstevel@tonic-gate 	 * precedence.
56167c478bd9Sstevel@tonic-gate 	 */
56177c478bd9Sstevel@tonic-gate 	if (scf_handle_get_scope(h, SCF_SCOPE_LOCAL, sc) == -1) {
56187c478bd9Sstevel@tonic-gate 		handle_rele_subhandles(h, holds);
56197c478bd9Sstevel@tonic-gate 		ret = -1;
56207c478bd9Sstevel@tonic-gate 		goto reset_args;
56217c478bd9Sstevel@tonic-gate 	}
56227c478bd9Sstevel@tonic-gate 
56237c478bd9Sstevel@tonic-gate 	if (scope != NULL && strcmp(scope, SCF_FMRI_LOCAL_SCOPE) != 0) {
56247c478bd9Sstevel@tonic-gate 		handle_rele_subhandles(h, holds);
56257c478bd9Sstevel@tonic-gate 		ret = scf_set_error(SCF_ERROR_NOT_FOUND);
56267c478bd9Sstevel@tonic-gate 		goto reset_args;
56277c478bd9Sstevel@tonic-gate 	}
56287c478bd9Sstevel@tonic-gate 
56297c478bd9Sstevel@tonic-gate 
56307c478bd9Sstevel@tonic-gate 	if (service == NULL || last == REP_PROTOCOL_ENTITY_SCOPE) {
56317c478bd9Sstevel@tonic-gate 		handle_rele_subhandles(h, holds);
56327c478bd9Sstevel@tonic-gate 		return (0);
56337c478bd9Sstevel@tonic-gate 	}
56347c478bd9Sstevel@tonic-gate 
56357c478bd9Sstevel@tonic-gate 	if (scf_scope_get_service(sc, service, svc) == -1) {
56367c478bd9Sstevel@tonic-gate 		handle_rele_subhandles(h, holds);
56377c478bd9Sstevel@tonic-gate 		ret = -1;
56387c478bd9Sstevel@tonic-gate 		assert(scf_error() != SCF_ERROR_NOT_SET);
56397c478bd9Sstevel@tonic-gate 		if (scf_error() == SCF_ERROR_DELETED)
56407c478bd9Sstevel@tonic-gate 			(void) scf_set_error(SCF_ERROR_NOT_FOUND);
56417c478bd9Sstevel@tonic-gate 		goto reset_args;
56427c478bd9Sstevel@tonic-gate 	}
56437c478bd9Sstevel@tonic-gate 
56447c478bd9Sstevel@tonic-gate 	if (last == REP_PROTOCOL_ENTITY_SERVICE) {
56457c478bd9Sstevel@tonic-gate 		handle_rele_subhandles(h, holds);
56467c478bd9Sstevel@tonic-gate 		return (0);
56477c478bd9Sstevel@tonic-gate 	}
56487c478bd9Sstevel@tonic-gate 
56497c478bd9Sstevel@tonic-gate 	if (instance == NULL) {
56507c478bd9Sstevel@tonic-gate 		if (propertygroup == NULL ||
56517c478bd9Sstevel@tonic-gate 		    last == REP_PROTOCOL_ENTITY_INSTANCE) {
56527c478bd9Sstevel@tonic-gate 			handle_rele_subhandles(h, holds);
56537c478bd9Sstevel@tonic-gate 			return (0);
56547c478bd9Sstevel@tonic-gate 		}
56557c478bd9Sstevel@tonic-gate 
56567c478bd9Sstevel@tonic-gate 		if (scf_service_get_pg(svc, propertygroup, pg) == -1) {
56577c478bd9Sstevel@tonic-gate 			handle_rele_subhandles(h, holds);
56587c478bd9Sstevel@tonic-gate 			ret = -1;
56597c478bd9Sstevel@tonic-gate 			assert(scf_error() != SCF_ERROR_NOT_SET);
56607c478bd9Sstevel@tonic-gate 			if (scf_error() == SCF_ERROR_DELETED)
56617c478bd9Sstevel@tonic-gate 				(void) scf_set_error(SCF_ERROR_NOT_FOUND);
56627c478bd9Sstevel@tonic-gate 			goto reset_args;
56637c478bd9Sstevel@tonic-gate 		}
56647c478bd9Sstevel@tonic-gate 	} else {
56657c478bd9Sstevel@tonic-gate 		if (scf_service_get_instance(svc, instance, inst) == -1) {
56667c478bd9Sstevel@tonic-gate 			handle_rele_subhandles(h, holds);
56677c478bd9Sstevel@tonic-gate 			ret = -1;
56687c478bd9Sstevel@tonic-gate 			assert(scf_error() != SCF_ERROR_NOT_SET);
56697c478bd9Sstevel@tonic-gate 			if (scf_error() == SCF_ERROR_DELETED)
56707c478bd9Sstevel@tonic-gate 				(void) scf_set_error(SCF_ERROR_NOT_FOUND);
56717c478bd9Sstevel@tonic-gate 			goto reset_args;
56727c478bd9Sstevel@tonic-gate 		}
56737c478bd9Sstevel@tonic-gate 
56747c478bd9Sstevel@tonic-gate 		if (propertygroup == NULL ||
56757c478bd9Sstevel@tonic-gate 		    last == REP_PROTOCOL_ENTITY_INSTANCE) {
56767c478bd9Sstevel@tonic-gate 			handle_rele_subhandles(h, holds);
56777c478bd9Sstevel@tonic-gate 			return (0);
56787c478bd9Sstevel@tonic-gate 		}
56797c478bd9Sstevel@tonic-gate 
56807c478bd9Sstevel@tonic-gate 		if (scf_instance_get_pg(inst, propertygroup, pg) == -1) {
56817c478bd9Sstevel@tonic-gate 			handle_rele_subhandles(h, holds);
56827c478bd9Sstevel@tonic-gate 			ret = -1;
56837c478bd9Sstevel@tonic-gate 			assert(scf_error() != SCF_ERROR_NOT_SET);
56847c478bd9Sstevel@tonic-gate 			if (scf_error() == SCF_ERROR_DELETED)
56857c478bd9Sstevel@tonic-gate 				(void) scf_set_error(SCF_ERROR_NOT_FOUND);
56867c478bd9Sstevel@tonic-gate 			goto reset_args;
56877c478bd9Sstevel@tonic-gate 		}
56887c478bd9Sstevel@tonic-gate 	}
56897c478bd9Sstevel@tonic-gate 
56907c478bd9Sstevel@tonic-gate 	if (property == NULL || last == REP_PROTOCOL_ENTITY_PROPERTYGRP) {
56917c478bd9Sstevel@tonic-gate 		handle_rele_subhandles(h, holds);
56927c478bd9Sstevel@tonic-gate 		return (0);
56937c478bd9Sstevel@tonic-gate 	}
56947c478bd9Sstevel@tonic-gate 
56957c478bd9Sstevel@tonic-gate 	if (scf_pg_get_property(pg, property, prop) == -1) {
56967c478bd9Sstevel@tonic-gate 		handle_rele_subhandles(h, holds);
56977c478bd9Sstevel@tonic-gate 		ret = -1;
56987c478bd9Sstevel@tonic-gate 		assert(scf_error() != SCF_ERROR_NOT_SET);
56997c478bd9Sstevel@tonic-gate 		if (scf_error() == SCF_ERROR_DELETED)
57007c478bd9Sstevel@tonic-gate 			(void) scf_set_error(SCF_ERROR_NOT_FOUND);
57017c478bd9Sstevel@tonic-gate 		goto reset_args;
57027c478bd9Sstevel@tonic-gate 	}
57037c478bd9Sstevel@tonic-gate 
57047c478bd9Sstevel@tonic-gate 	handle_rele_subhandles(h, holds);
57057c478bd9Sstevel@tonic-gate 	return (0);
57067c478bd9Sstevel@tonic-gate 
57077c478bd9Sstevel@tonic-gate reset_args:
57087c478bd9Sstevel@tonic-gate 	if (sc != NULL)
57097c478bd9Sstevel@tonic-gate 		datael_reset(&sc->rd_d);
57107c478bd9Sstevel@tonic-gate 	if (svc != NULL)
57117c478bd9Sstevel@tonic-gate 		datael_reset(&svc->rd_d);
57127c478bd9Sstevel@tonic-gate 	if (inst != NULL)
57137c478bd9Sstevel@tonic-gate 		datael_reset(&inst->rd_d);
57147c478bd9Sstevel@tonic-gate 	if (pg != NULL)
57157c478bd9Sstevel@tonic-gate 		datael_reset(&pg->rd_d);
57167c478bd9Sstevel@tonic-gate 	if (prop != NULL)
57177c478bd9Sstevel@tonic-gate 		datael_reset(&prop->rd_d);
57187c478bd9Sstevel@tonic-gate 
57197c478bd9Sstevel@tonic-gate 	return (ret);
57207c478bd9Sstevel@tonic-gate }
57217c478bd9Sstevel@tonic-gate 
57227c478bd9Sstevel@tonic-gate /*
57237c478bd9Sstevel@tonic-gate  * Fails with _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response too
57247c478bd9Sstevel@tonic-gate  * big, bad entity id, request not applicable to entity, name too long for
57257c478bd9Sstevel@tonic-gate  * buffer), _NOT_SET, or _DELETED.
57267c478bd9Sstevel@tonic-gate  */
57277c478bd9Sstevel@tonic-gate ssize_t
scf_scope_to_fmri(const scf_scope_t * scope,char * out,size_t sz)57287c478bd9Sstevel@tonic-gate scf_scope_to_fmri(const scf_scope_t *scope, char *out, size_t sz)
57297c478bd9Sstevel@tonic-gate {
57307c478bd9Sstevel@tonic-gate 	ssize_t r, len;
57317c478bd9Sstevel@tonic-gate 
57327c478bd9Sstevel@tonic-gate 	char tmp[REP_PROTOCOL_NAME_LEN];
57337c478bd9Sstevel@tonic-gate 
57347c478bd9Sstevel@tonic-gate 	r = scf_scope_get_name(scope, tmp, sizeof (tmp));
57357c478bd9Sstevel@tonic-gate 
57367c478bd9Sstevel@tonic-gate 	if (r <= 0)
57377c478bd9Sstevel@tonic-gate 		return (r);
57387c478bd9Sstevel@tonic-gate 
57397c478bd9Sstevel@tonic-gate 	len = strlcpy(out, SCF_FMRI_SVC_PREFIX, sz);
57407c478bd9Sstevel@tonic-gate 	if (strcmp(tmp, SCF_FMRI_LOCAL_SCOPE) != 0) {
57417c478bd9Sstevel@tonic-gate 		if (len >= sz)
57427c478bd9Sstevel@tonic-gate 			return (len + r + sizeof (SCF_FMRI_SCOPE_SUFFIX) - 1);
57437c478bd9Sstevel@tonic-gate 
57447c478bd9Sstevel@tonic-gate 		len = strlcat(out, tmp, sz);
57457c478bd9Sstevel@tonic-gate 		if (len >= sz)
57467c478bd9Sstevel@tonic-gate 			return (len + sizeof (SCF_FMRI_SCOPE_SUFFIX) - 1);
57477c478bd9Sstevel@tonic-gate 		len = strlcat(out,
57487c478bd9Sstevel@tonic-gate 		    SCF_FMRI_SCOPE_SUFFIX SCF_FMRI_SERVICE_PREFIX, sz);
57497c478bd9Sstevel@tonic-gate 	}
57507c478bd9Sstevel@tonic-gate 
57517c478bd9Sstevel@tonic-gate 	return (len);
57527c478bd9Sstevel@tonic-gate }
57537c478bd9Sstevel@tonic-gate 
57547c478bd9Sstevel@tonic-gate /*
57557c478bd9Sstevel@tonic-gate  * Fails with _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response too
57567c478bd9Sstevel@tonic-gate  * big, bad element id, bad ids, bad types, scope has no parent, request not
57577c478bd9Sstevel@tonic-gate  * applicable to entity, name too long), _NOT_SET, _DELETED,
57587c478bd9Sstevel@tonic-gate  */
57597c478bd9Sstevel@tonic-gate ssize_t
scf_service_to_fmri(const scf_service_t * svc,char * out,size_t sz)57607c478bd9Sstevel@tonic-gate scf_service_to_fmri(const scf_service_t *svc, char *out, size_t sz)
57617c478bd9Sstevel@tonic-gate {
57627c478bd9Sstevel@tonic-gate 	scf_handle_t *h = svc->rd_d.rd_handle;
57637c478bd9Sstevel@tonic-gate 	scf_scope_t *scope = HANDLE_HOLD_SCOPE(h);
57647c478bd9Sstevel@tonic-gate 	ssize_t r, len;
57657c478bd9Sstevel@tonic-gate 
57667c478bd9Sstevel@tonic-gate 	char tmp[REP_PROTOCOL_NAME_LEN];
57677c478bd9Sstevel@tonic-gate 
57687c478bd9Sstevel@tonic-gate 	r = datael_get_parent(&svc->rd_d, &scope->rd_d);
57697c478bd9Sstevel@tonic-gate 	if (r != SCF_SUCCESS) {
57707c478bd9Sstevel@tonic-gate 		HANDLE_RELE_SCOPE(h);
57717c478bd9Sstevel@tonic-gate 
57727c478bd9Sstevel@tonic-gate 		assert(scf_error() != SCF_ERROR_HANDLE_MISMATCH);
57737c478bd9Sstevel@tonic-gate 		return (-1);
57747c478bd9Sstevel@tonic-gate 	}
57757c478bd9Sstevel@tonic-gate 	if (out != NULL && sz > 0)
57767c478bd9Sstevel@tonic-gate 		len = scf_scope_to_fmri(scope, out, sz);
57777c478bd9Sstevel@tonic-gate 	else
57787c478bd9Sstevel@tonic-gate 		len = scf_scope_to_fmri(scope, tmp, 2);
57797c478bd9Sstevel@tonic-gate 
57807c478bd9Sstevel@tonic-gate 	HANDLE_RELE_SCOPE(h);
57817c478bd9Sstevel@tonic-gate 
57827c478bd9Sstevel@tonic-gate 	if (len < 0)
57837c478bd9Sstevel@tonic-gate 		return (-1);
57847c478bd9Sstevel@tonic-gate 
57857c478bd9Sstevel@tonic-gate 	if (out == NULL || len >= sz)
57867c478bd9Sstevel@tonic-gate 		len += sizeof (SCF_FMRI_SERVICE_PREFIX) - 1;
57877c478bd9Sstevel@tonic-gate 	else
57887c478bd9Sstevel@tonic-gate 		len = strlcat(out, SCF_FMRI_SERVICE_PREFIX, sz);
57897c478bd9Sstevel@tonic-gate 
57907c478bd9Sstevel@tonic-gate 	r = scf_service_get_name(svc, tmp, sizeof (tmp));
57917c478bd9Sstevel@tonic-gate 	if (r < 0)
57927c478bd9Sstevel@tonic-gate 		return (r);
57937c478bd9Sstevel@tonic-gate 
57947c478bd9Sstevel@tonic-gate 	if (out == NULL || len >= sz)
57957c478bd9Sstevel@tonic-gate 		len += r;
57967c478bd9Sstevel@tonic-gate 	else
57977c478bd9Sstevel@tonic-gate 		len = strlcat(out, tmp, sz);
57987c478bd9Sstevel@tonic-gate 
57997c478bd9Sstevel@tonic-gate 	return (len);
58007c478bd9Sstevel@tonic-gate }
58017c478bd9Sstevel@tonic-gate 
58027c478bd9Sstevel@tonic-gate ssize_t
scf_instance_to_fmri(const scf_instance_t * inst,char * out,size_t sz)58037c478bd9Sstevel@tonic-gate scf_instance_to_fmri(const scf_instance_t *inst, char *out, size_t sz)
58047c478bd9Sstevel@tonic-gate {
58057c478bd9Sstevel@tonic-gate 	scf_handle_t *h = inst->rd_d.rd_handle;
58067c478bd9Sstevel@tonic-gate 	scf_service_t *svc = HANDLE_HOLD_SERVICE(h);
58077c478bd9Sstevel@tonic-gate 	ssize_t r, len;
58087c478bd9Sstevel@tonic-gate 
58097c478bd9Sstevel@tonic-gate 	char tmp[REP_PROTOCOL_NAME_LEN];
58107c478bd9Sstevel@tonic-gate 
58117c478bd9Sstevel@tonic-gate 	r = datael_get_parent(&inst->rd_d, &svc->rd_d);
58127c478bd9Sstevel@tonic-gate 	if (r != SCF_SUCCESS) {
58137c478bd9Sstevel@tonic-gate 		HANDLE_RELE_SERVICE(h);
58147c478bd9Sstevel@tonic-gate 		return (-1);
58157c478bd9Sstevel@tonic-gate 	}
58167c478bd9Sstevel@tonic-gate 
58177c478bd9Sstevel@tonic-gate 	len = scf_service_to_fmri(svc, out, sz);
58187c478bd9Sstevel@tonic-gate 
58197c478bd9Sstevel@tonic-gate 	HANDLE_RELE_SERVICE(h);
58207c478bd9Sstevel@tonic-gate 
58217c478bd9Sstevel@tonic-gate 	if (len < 0)
58227c478bd9Sstevel@tonic-gate 		return (len);
58237c478bd9Sstevel@tonic-gate 
58247c478bd9Sstevel@tonic-gate 	if (len >= sz)
58257c478bd9Sstevel@tonic-gate 		len += sizeof (SCF_FMRI_INSTANCE_PREFIX) - 1;
58267c478bd9Sstevel@tonic-gate 	else
58277c478bd9Sstevel@tonic-gate 		len = strlcat(out, SCF_FMRI_INSTANCE_PREFIX, sz);
58287c478bd9Sstevel@tonic-gate 
58297c478bd9Sstevel@tonic-gate 	r = scf_instance_get_name(inst, tmp, sizeof (tmp));
58307c478bd9Sstevel@tonic-gate 	if (r < 0)
58317c478bd9Sstevel@tonic-gate 		return (r);
58327c478bd9Sstevel@tonic-gate 
58337c478bd9Sstevel@tonic-gate 	if (len >= sz)
58347c478bd9Sstevel@tonic-gate 		len += r;
58357c478bd9Sstevel@tonic-gate 	else
58367c478bd9Sstevel@tonic-gate 		len = strlcat(out, tmp, sz);
58377c478bd9Sstevel@tonic-gate 
58387c478bd9Sstevel@tonic-gate 	return (len);
58397c478bd9Sstevel@tonic-gate }
58407c478bd9Sstevel@tonic-gate 
58417c478bd9Sstevel@tonic-gate ssize_t
scf_pg_to_fmri(const scf_propertygroup_t * pg,char * out,size_t sz)58427c478bd9Sstevel@tonic-gate scf_pg_to_fmri(const scf_propertygroup_t *pg, char *out, size_t sz)
58437c478bd9Sstevel@tonic-gate {
58447c478bd9Sstevel@tonic-gate 	scf_handle_t *h = pg->rd_d.rd_handle;
58457c478bd9Sstevel@tonic-gate 
58467c478bd9Sstevel@tonic-gate 	struct rep_protocol_entity_parent_type request;
58477c478bd9Sstevel@tonic-gate 	struct rep_protocol_integer_response response;
58487c478bd9Sstevel@tonic-gate 
58497c478bd9Sstevel@tonic-gate 	char tmp[REP_PROTOCOL_NAME_LEN];
58507c478bd9Sstevel@tonic-gate 	ssize_t len, r;
58517c478bd9Sstevel@tonic-gate 
58527c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
58537c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_ENTITY_PARENT_TYPE;
58547c478bd9Sstevel@tonic-gate 	request.rpr_entityid = pg->rd_d.rd_entity;
58557c478bd9Sstevel@tonic-gate 
58567c478bd9Sstevel@tonic-gate 	datael_finish_reset(&pg->rd_d);
58577c478bd9Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
58587c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
58597c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
58607c478bd9Sstevel@tonic-gate 
58617c478bd9Sstevel@tonic-gate 	if (r < 0)
58627c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
58637c478bd9Sstevel@tonic-gate 
58647c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS ||
58657c478bd9Sstevel@tonic-gate 	    r < sizeof (response)) {
58667c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
58677c478bd9Sstevel@tonic-gate 	}
58687c478bd9Sstevel@tonic-gate 
58697c478bd9Sstevel@tonic-gate 	switch (response.rpr_value) {
58707c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_ENTITY_SERVICE: {
58717c478bd9Sstevel@tonic-gate 		scf_service_t *svc;
58727c478bd9Sstevel@tonic-gate 
58737c478bd9Sstevel@tonic-gate 		svc = HANDLE_HOLD_SERVICE(h);
58747c478bd9Sstevel@tonic-gate 
58757c478bd9Sstevel@tonic-gate 		r = datael_get_parent(&pg->rd_d, &svc->rd_d);
58767c478bd9Sstevel@tonic-gate 
58777c478bd9Sstevel@tonic-gate 		if (r == SCF_SUCCESS)
58787c478bd9Sstevel@tonic-gate 			len = scf_service_to_fmri(svc, out, sz);
58797c478bd9Sstevel@tonic-gate 
58807c478bd9Sstevel@tonic-gate 		HANDLE_RELE_SERVICE(h);
58817c478bd9Sstevel@tonic-gate 		break;
58827c478bd9Sstevel@tonic-gate 	}
58837c478bd9Sstevel@tonic-gate 
58847c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_ENTITY_INSTANCE: {
58857c478bd9Sstevel@tonic-gate 		scf_instance_t *inst;
58867c478bd9Sstevel@tonic-gate 
58877c478bd9Sstevel@tonic-gate 		inst = HANDLE_HOLD_INSTANCE(h);
58887c478bd9Sstevel@tonic-gate 
58897c478bd9Sstevel@tonic-gate 		r = datael_get_parent(&pg->rd_d, &inst->rd_d);
58907c478bd9Sstevel@tonic-gate 
58917c478bd9Sstevel@tonic-gate 		if (r == SCF_SUCCESS)
58927c478bd9Sstevel@tonic-gate 			len = scf_instance_to_fmri(inst, out, sz);
58937c478bd9Sstevel@tonic-gate 
58947c478bd9Sstevel@tonic-gate 		HANDLE_RELE_INSTANCE(h);
58957c478bd9Sstevel@tonic-gate 		break;
58967c478bd9Sstevel@tonic-gate 	}
58977c478bd9Sstevel@tonic-gate 
58987c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_ENTITY_SNAPLEVEL: {
58997c478bd9Sstevel@tonic-gate 		scf_instance_t *inst = HANDLE_HOLD_INSTANCE(h);
59007c478bd9Sstevel@tonic-gate 		scf_snapshot_t *snap = HANDLE_HOLD_SNAPSHOT(h);
59017c478bd9Sstevel@tonic-gate 		scf_snaplevel_t *level = HANDLE_HOLD_SNAPLVL(h);
59027c478bd9Sstevel@tonic-gate 
59037c478bd9Sstevel@tonic-gate 		r = datael_get_parent(&pg->rd_d, &level->rd_d);
59047c478bd9Sstevel@tonic-gate 
59057c478bd9Sstevel@tonic-gate 		if (r == SCF_SUCCESS)
59067c478bd9Sstevel@tonic-gate 			r = datael_get_parent(&level->rd_d, &snap->rd_d);
59077c478bd9Sstevel@tonic-gate 
59087c478bd9Sstevel@tonic-gate 		if (r == SCF_SUCCESS)
59097c478bd9Sstevel@tonic-gate 			r = datael_get_parent(&snap->rd_d, &inst->rd_d);
59107c478bd9Sstevel@tonic-gate 
59117c478bd9Sstevel@tonic-gate 		if (r == SCF_SUCCESS)
59127c478bd9Sstevel@tonic-gate 			len = scf_instance_to_fmri(inst, out, sz);
59137c478bd9Sstevel@tonic-gate 
59147c478bd9Sstevel@tonic-gate 		HANDLE_RELE_INSTANCE(h);
59157c478bd9Sstevel@tonic-gate 		HANDLE_RELE_SNAPSHOT(h);
59167c478bd9Sstevel@tonic-gate 		HANDLE_RELE_SNAPLVL(h);
59177c478bd9Sstevel@tonic-gate 		break;
59187c478bd9Sstevel@tonic-gate 	}
59197c478bd9Sstevel@tonic-gate 
59207c478bd9Sstevel@tonic-gate 	default:
59217c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INTERNAL));
59227c478bd9Sstevel@tonic-gate 	}
59237c478bd9Sstevel@tonic-gate 
59247c478bd9Sstevel@tonic-gate 	if (r != SCF_SUCCESS)
59257c478bd9Sstevel@tonic-gate 		return (r);
59267c478bd9Sstevel@tonic-gate 
59277c478bd9Sstevel@tonic-gate 	if (len >= sz)
59287c478bd9Sstevel@tonic-gate 		len += sizeof (SCF_FMRI_PROPERTYGRP_PREFIX) - 1;
59297c478bd9Sstevel@tonic-gate 	else
59307c478bd9Sstevel@tonic-gate 		len = strlcat(out, SCF_FMRI_PROPERTYGRP_PREFIX, sz);
59317c478bd9Sstevel@tonic-gate 
59327c478bd9Sstevel@tonic-gate 	r = scf_pg_get_name(pg, tmp, sizeof (tmp));
59337c478bd9Sstevel@tonic-gate 
59347c478bd9Sstevel@tonic-gate 	if (r < 0)
59357c478bd9Sstevel@tonic-gate 		return (r);
59367c478bd9Sstevel@tonic-gate 
59377c478bd9Sstevel@tonic-gate 	if (len >= sz)
59387c478bd9Sstevel@tonic-gate 		len += r;
59397c478bd9Sstevel@tonic-gate 	else
59407c478bd9Sstevel@tonic-gate 		len = strlcat(out, tmp, sz);
59417c478bd9Sstevel@tonic-gate 
59427c478bd9Sstevel@tonic-gate 	return (len);
59437c478bd9Sstevel@tonic-gate }
59447c478bd9Sstevel@tonic-gate 
59457c478bd9Sstevel@tonic-gate ssize_t
scf_property_to_fmri(const scf_property_t * prop,char * out,size_t sz)59467c478bd9Sstevel@tonic-gate scf_property_to_fmri(const scf_property_t *prop, char *out, size_t sz)
59477c478bd9Sstevel@tonic-gate {
59487c478bd9Sstevel@tonic-gate 	scf_handle_t *h = prop->rd_d.rd_handle;
59497c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *pg = HANDLE_HOLD_PG(h);
59507c478bd9Sstevel@tonic-gate 
59517c478bd9Sstevel@tonic-gate 	char tmp[REP_PROTOCOL_NAME_LEN];
59527c478bd9Sstevel@tonic-gate 	ssize_t len;
59537c478bd9Sstevel@tonic-gate 	int r;
59547c478bd9Sstevel@tonic-gate 
59557c478bd9Sstevel@tonic-gate 	r = datael_get_parent(&prop->rd_d, &pg->rd_d);
59567c478bd9Sstevel@tonic-gate 	if (r != SCF_SUCCESS) {
59577c478bd9Sstevel@tonic-gate 		HANDLE_RELE_PG(h);
59587c478bd9Sstevel@tonic-gate 		return (-1);
59597c478bd9Sstevel@tonic-gate 	}
59607c478bd9Sstevel@tonic-gate 
59617c478bd9Sstevel@tonic-gate 	len = scf_pg_to_fmri(pg, out, sz);
59627c478bd9Sstevel@tonic-gate 
59637c478bd9Sstevel@tonic-gate 	HANDLE_RELE_PG(h);
59647c478bd9Sstevel@tonic-gate 
59657c478bd9Sstevel@tonic-gate 	if (len >= sz)
59667c478bd9Sstevel@tonic-gate 		len += sizeof (SCF_FMRI_PROPERTY_PREFIX) - 1;
59677c478bd9Sstevel@tonic-gate 	else
59687c478bd9Sstevel@tonic-gate 		len = strlcat(out, SCF_FMRI_PROPERTY_PREFIX, sz);
59697c478bd9Sstevel@tonic-gate 
59707c478bd9Sstevel@tonic-gate 	r = scf_property_get_name(prop, tmp, sizeof (tmp));
59717c478bd9Sstevel@tonic-gate 
59727c478bd9Sstevel@tonic-gate 	if (r < 0)
59737c478bd9Sstevel@tonic-gate 		return (r);
59747c478bd9Sstevel@tonic-gate 
59757c478bd9Sstevel@tonic-gate 	if (len >= sz)
59767c478bd9Sstevel@tonic-gate 		len += r;
59777c478bd9Sstevel@tonic-gate 	else
59787c478bd9Sstevel@tonic-gate 		len = strlcat(out, tmp, sz);
59797c478bd9Sstevel@tonic-gate 
59807c478bd9Sstevel@tonic-gate 	return (len);
59817c478bd9Sstevel@tonic-gate }
59827c478bd9Sstevel@tonic-gate 
598376cf44abSjeanm /*
598476cf44abSjeanm  * Fails with _HANDLE_MISMATCH, _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL
598576cf44abSjeanm  * (server response too big, bad entity id, request not applicable to entity,
598676cf44abSjeanm  * name too long for buffer, bad element id, iter already exists, element
598776cf44abSjeanm  * cannot have children of type, type is invalid, iter was reset, sequence
598876cf44abSjeanm  * was bad, iter walks values, iter does not walk type entities),
598976cf44abSjeanm  * _NOT_SET, _DELETED, or _CONSTRAINT_VIOLATED,
599076cf44abSjeanm  * _NOT_FOUND (scope has no parent),  _INVALID_ARGUMENT, _NO_RESOURCES,
599176cf44abSjeanm  * _BACKEND_ACCESS.
599276cf44abSjeanm  */
59937c478bd9Sstevel@tonic-gate int
scf_pg_get_underlying_pg(const scf_propertygroup_t * pg,scf_propertygroup_t * out)59947c478bd9Sstevel@tonic-gate scf_pg_get_underlying_pg(const scf_propertygroup_t *pg,
59957c478bd9Sstevel@tonic-gate     scf_propertygroup_t *out)
59967c478bd9Sstevel@tonic-gate {
59977c478bd9Sstevel@tonic-gate 	scf_handle_t *h = pg->rd_d.rd_handle;
59987c478bd9Sstevel@tonic-gate 	scf_service_t *svc;
59997c478bd9Sstevel@tonic-gate 	scf_instance_t *inst;
60007c478bd9Sstevel@tonic-gate 
60017c478bd9Sstevel@tonic-gate 	char me[REP_PROTOCOL_NAME_LEN];
60027c478bd9Sstevel@tonic-gate 	int r;
60037c478bd9Sstevel@tonic-gate 
60047c478bd9Sstevel@tonic-gate 	if (h != out->rd_d.rd_handle)
60057c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
60067c478bd9Sstevel@tonic-gate 
60077c478bd9Sstevel@tonic-gate 	r = scf_pg_get_name(pg, me, sizeof (me));
60087c478bd9Sstevel@tonic-gate 
60097c478bd9Sstevel@tonic-gate 	if (r < 0)
60107c478bd9Sstevel@tonic-gate 		return (r);
60117c478bd9Sstevel@tonic-gate 
60127c478bd9Sstevel@tonic-gate 	svc = HANDLE_HOLD_SERVICE(h);
60137c478bd9Sstevel@tonic-gate 	inst = HANDLE_HOLD_INSTANCE(h);
60147c478bd9Sstevel@tonic-gate 
60157c478bd9Sstevel@tonic-gate 	r = datael_get_parent(&pg->rd_d, &inst->rd_d);
60167c478bd9Sstevel@tonic-gate 
60177c478bd9Sstevel@tonic-gate 	if (r == SCF_SUCCESS) {
60187c478bd9Sstevel@tonic-gate 		r = datael_get_parent(&inst->rd_d, &svc->rd_d);
60197c478bd9Sstevel@tonic-gate 		if (r != SCF_SUCCESS) {
60207c478bd9Sstevel@tonic-gate 			goto out;
60217c478bd9Sstevel@tonic-gate 		}
60227c478bd9Sstevel@tonic-gate 		r = scf_service_get_pg(svc, me, out);
60237c478bd9Sstevel@tonic-gate 	} else {
60247c478bd9Sstevel@tonic-gate 		r = scf_set_error(SCF_ERROR_NOT_FOUND);
60257c478bd9Sstevel@tonic-gate 	}
60267c478bd9Sstevel@tonic-gate 
60277c478bd9Sstevel@tonic-gate out:
60287c478bd9Sstevel@tonic-gate 	HANDLE_RELE_SERVICE(h);
60297c478bd9Sstevel@tonic-gate 	HANDLE_RELE_INSTANCE(h);
60307c478bd9Sstevel@tonic-gate 	return (r);
60317c478bd9Sstevel@tonic-gate }
60327c478bd9Sstevel@tonic-gate 
60337c478bd9Sstevel@tonic-gate #define	LEGACY_SCHEME	"lrc:"
60347c478bd9Sstevel@tonic-gate #define	LEGACY_UNKNOWN	"unknown"
60357c478bd9Sstevel@tonic-gate 
60367c478bd9Sstevel@tonic-gate /*
60377c478bd9Sstevel@tonic-gate  * Implementation of scf_walk_fmri()
60387c478bd9Sstevel@tonic-gate  *
60397c478bd9Sstevel@tonic-gate  * This is a little tricky due to the many-to-many relationship between patterns
60407c478bd9Sstevel@tonic-gate  * and matches.  We need to be able to satisfy the following requirements:
60417c478bd9Sstevel@tonic-gate  *
6042*29267a9dSAndy Fiddaman  *	1) Detect patterns which match more than one FMRI, and be able to
60437c478bd9Sstevel@tonic-gate  *         report which FMRIs have been matched.
6044*29267a9dSAndy Fiddaman  *	2) Detect patterns which have not matched any FMRIs
6045*29267a9dSAndy Fiddaman  *	3) Visit each matching FMRI exactly once across all patterns
6046*29267a9dSAndy Fiddaman  *	4) Ignore FMRIs which have only been matched due to multiply-matching
60477c478bd9Sstevel@tonic-gate  *         patterns.
60487c478bd9Sstevel@tonic-gate  *
60497c478bd9Sstevel@tonic-gate  * We maintain an array of scf_pattern_t structures, one for each argument, and
60507c478bd9Sstevel@tonic-gate  * maintain a linked list of scf_match_t structures for each one.  We first
60517c478bd9Sstevel@tonic-gate  * qualify each pattern's type:
60527c478bd9Sstevel@tonic-gate  *
60537c478bd9Sstevel@tonic-gate  *	PATTERN_INVALID		The argument is invalid (too long).
60547c478bd9Sstevel@tonic-gate  *
60557c478bd9Sstevel@tonic-gate  *	PATTERN_EXACT		The pattern is a complete FMRI.  The list of
60567c478bd9Sstevel@tonic-gate  *				matches contains only a single entry.
60577c478bd9Sstevel@tonic-gate  *
6058*29267a9dSAndy Fiddaman  *	PATTERN_GLOB		The pattern will be matched against all
6059*29267a9dSAndy Fiddaman  *				FMRIs via fnmatch() in the second phase.
6060*29267a9dSAndy Fiddaman  *				Matches will be added to the pattern's list
6061*29267a9dSAndy Fiddaman  *				as they are found.
60627c478bd9Sstevel@tonic-gate  *
6063*29267a9dSAndy Fiddaman  *	PATTERN_PARTIAL		Everything else.  We will assume that this is
6064*29267a9dSAndy Fiddaman  *				an abbreviated FMRI, and match according to
6065*29267a9dSAndy Fiddaman  *				our abbreviated FMRI rules.  Matches will be
6066*29267a9dSAndy Fiddaman  *				added to the pattern's list as they are found.
60677c478bd9Sstevel@tonic-gate  *
60687c478bd9Sstevel@tonic-gate  * The first pass searches for arguments that are complete FMRIs.  These are
60697c478bd9Sstevel@tonic-gate  * classified as EXACT patterns and do not necessitate searching the entire
60707c478bd9Sstevel@tonic-gate  * tree.
60717c478bd9Sstevel@tonic-gate  *
60727c478bd9Sstevel@tonic-gate  * Once this is done, if we have any GLOB or PARTIAL patterns (or if no
60737c478bd9Sstevel@tonic-gate  * arguments were given), we iterate over all services and instances in the
60747c478bd9Sstevel@tonic-gate  * repository, looking for matches.
60757c478bd9Sstevel@tonic-gate  *
60767c478bd9Sstevel@tonic-gate  * When a match is found, we add the match to the pattern's list.  We also enter
60777c478bd9Sstevel@tonic-gate  * the match into a hash table, resulting in something like this:
60787c478bd9Sstevel@tonic-gate  *
60797c478bd9Sstevel@tonic-gate  *       scf_pattern_t       scf_match_t
60807c478bd9Sstevel@tonic-gate  *     +---------------+      +-------+     +-------+
60817c478bd9Sstevel@tonic-gate  *     | pattern 'foo' |----->| match |---->| match |
60827c478bd9Sstevel@tonic-gate  *     +---------------+      +-------+     +-------+
60837c478bd9Sstevel@tonic-gate  *                                |             |
60847c478bd9Sstevel@tonic-gate  *           scf_match_key_t      |             |
60857c478bd9Sstevel@tonic-gate  *           +--------------+     |             |
60867c478bd9Sstevel@tonic-gate  *           | FMRI bar/foo |<----+             |
60877c478bd9Sstevel@tonic-gate  *           +--------------+                   |
60887c478bd9Sstevel@tonic-gate  *           | FMRI baz/foo |<------------------+
60897c478bd9Sstevel@tonic-gate  *           +--------------+
60907c478bd9Sstevel@tonic-gate  *
60917c478bd9Sstevel@tonic-gate  * Once we have all of this set up, we do one pass to report patterns matching
60927c478bd9Sstevel@tonic-gate  * multiple FMRIs (if SCF_WALK_MULTIPLE is not set) and patterns for which no
60937c478bd9Sstevel@tonic-gate  * match was found.
60947c478bd9Sstevel@tonic-gate  *
60957c478bd9Sstevel@tonic-gate  * Finally, we walk through all valid patterns, and for each match, if we
60967c478bd9Sstevel@tonic-gate  * haven't already seen the match (as recorded in the hash table), then we
60977c478bd9Sstevel@tonic-gate  * execute the callback.
60987c478bd9Sstevel@tonic-gate  */
60997c478bd9Sstevel@tonic-gate 
61007c478bd9Sstevel@tonic-gate struct scf_matchkey;
61017c478bd9Sstevel@tonic-gate struct scf_match;
61027c478bd9Sstevel@tonic-gate 
61037c478bd9Sstevel@tonic-gate /*
61047c478bd9Sstevel@tonic-gate  * scf_matchkey_t
61057c478bd9Sstevel@tonic-gate  */
61067c478bd9Sstevel@tonic-gate typedef struct scf_matchkey {
61077c478bd9Sstevel@tonic-gate 	char			*sk_fmri;	/* Matching FMRI */
61087c478bd9Sstevel@tonic-gate 	char			*sk_legacy;	/* Legacy name */
61097c478bd9Sstevel@tonic-gate 	int			sk_seen;	/* If we've been seen */
61107c478bd9Sstevel@tonic-gate 	struct scf_matchkey	*sk_next;	/* Next in hash chain */
61117c478bd9Sstevel@tonic-gate } scf_matchkey_t;
61127c478bd9Sstevel@tonic-gate 
61137c478bd9Sstevel@tonic-gate /*
61147c478bd9Sstevel@tonic-gate  * scf_match_t
61157c478bd9Sstevel@tonic-gate  */
61167c478bd9Sstevel@tonic-gate typedef struct scf_match {
61177c478bd9Sstevel@tonic-gate 	scf_matchkey_t		*sm_key;
61187c478bd9Sstevel@tonic-gate 	struct scf_match	*sm_next;
61197c478bd9Sstevel@tonic-gate } scf_match_t;
61207c478bd9Sstevel@tonic-gate 
61217c478bd9Sstevel@tonic-gate #define	WALK_HTABLE_SIZE	123
61227c478bd9Sstevel@tonic-gate 
61237c478bd9Sstevel@tonic-gate /*
61247c478bd9Sstevel@tonic-gate  * scf_get_key()
61257c478bd9Sstevel@tonic-gate  *
61267c478bd9Sstevel@tonic-gate  * Given an FMRI and a hash table, returns the scf_matchkey_t corresponding to
61277c478bd9Sstevel@tonic-gate  * this FMRI.  If the FMRI does not exist, it is added to the hash table.  If a
61287c478bd9Sstevel@tonic-gate  * new entry cannot be allocated due to lack of memory, NULL is returned.
61297c478bd9Sstevel@tonic-gate  */
61307c478bd9Sstevel@tonic-gate static scf_matchkey_t *
scf_get_key(scf_matchkey_t ** htable,const char * fmri,const char * legacy)61317c478bd9Sstevel@tonic-gate scf_get_key(scf_matchkey_t **htable, const char *fmri, const char *legacy)
61327c478bd9Sstevel@tonic-gate {
61337c478bd9Sstevel@tonic-gate 	uint_t h = 0, g;
61347c478bd9Sstevel@tonic-gate 	const char *p, *k;
61357c478bd9Sstevel@tonic-gate 	scf_matchkey_t *key;
61367c478bd9Sstevel@tonic-gate 
61377c478bd9Sstevel@tonic-gate 	k = strstr(fmri, ":/");
61387c478bd9Sstevel@tonic-gate 	assert(k != NULL);
61397c478bd9Sstevel@tonic-gate 	k += 2;
61407c478bd9Sstevel@tonic-gate 
61417c478bd9Sstevel@tonic-gate 	/*
61427c478bd9Sstevel@tonic-gate 	 * Generic hash function from uts/common/os/modhash.c.
61437c478bd9Sstevel@tonic-gate 	 */
61447c478bd9Sstevel@tonic-gate 	for (p = k; *p != '\0'; ++p) {
61457c478bd9Sstevel@tonic-gate 		h = (h << 4) + *p;
61467c478bd9Sstevel@tonic-gate 		if ((g = (h & 0xf0000000)) != 0) {
61477c478bd9Sstevel@tonic-gate 			h ^= (g >> 24);
61487c478bd9Sstevel@tonic-gate 			h ^= g;
61497c478bd9Sstevel@tonic-gate 		}
61507c478bd9Sstevel@tonic-gate 	}
61517c478bd9Sstevel@tonic-gate 
61527c478bd9Sstevel@tonic-gate 	h %= WALK_HTABLE_SIZE;
61537c478bd9Sstevel@tonic-gate 
61547c478bd9Sstevel@tonic-gate 	/*
61557c478bd9Sstevel@tonic-gate 	 * Search for an existing key
61567c478bd9Sstevel@tonic-gate 	 */
61577c478bd9Sstevel@tonic-gate 	for (key = htable[h]; key != NULL; key = key->sk_next) {
61587c478bd9Sstevel@tonic-gate 		if (strcmp(key->sk_fmri, fmri) == 0)
61597c478bd9Sstevel@tonic-gate 			return (key);
61607c478bd9Sstevel@tonic-gate 	}
61617c478bd9Sstevel@tonic-gate 
61627c478bd9Sstevel@tonic-gate 	if ((key = calloc(sizeof (scf_matchkey_t), 1)) == NULL)
61637c478bd9Sstevel@tonic-gate 		return (NULL);
61647c478bd9Sstevel@tonic-gate 
61657c478bd9Sstevel@tonic-gate 	/*
61667c478bd9Sstevel@tonic-gate 	 * Add new key to hash table.
61677c478bd9Sstevel@tonic-gate 	 */
61687c478bd9Sstevel@tonic-gate 	if ((key->sk_fmri = strdup(fmri)) == NULL) {
61697c478bd9Sstevel@tonic-gate 		free(key);
61707c478bd9Sstevel@tonic-gate 		return (NULL);
61717c478bd9Sstevel@tonic-gate 	}
61727c478bd9Sstevel@tonic-gate 
61737c478bd9Sstevel@tonic-gate 	if (legacy == NULL) {
61747c478bd9Sstevel@tonic-gate 		key->sk_legacy = NULL;
61757c478bd9Sstevel@tonic-gate 	} else if ((key->sk_legacy = strdup(legacy)) == NULL) {
61767c478bd9Sstevel@tonic-gate 		free(key->sk_fmri);
61777c478bd9Sstevel@tonic-gate 		free(key);
61787c478bd9Sstevel@tonic-gate 		return (NULL);
61797c478bd9Sstevel@tonic-gate 	}
61807c478bd9Sstevel@tonic-gate 
61817c478bd9Sstevel@tonic-gate 	key->sk_next = htable[h];
61827c478bd9Sstevel@tonic-gate 	htable[h] = key;
61837c478bd9Sstevel@tonic-gate 
61847c478bd9Sstevel@tonic-gate 	return (key);
61857c478bd9Sstevel@tonic-gate }
61867c478bd9Sstevel@tonic-gate 
61877c478bd9Sstevel@tonic-gate /*
61887c478bd9Sstevel@tonic-gate  * Given an FMRI, insert it into the pattern's list appropriately.
61897c478bd9Sstevel@tonic-gate  * svc_explicit indicates whether matching services should take
61907c478bd9Sstevel@tonic-gate  * precedence over matching instances.
61917c478bd9Sstevel@tonic-gate  */
61927c478bd9Sstevel@tonic-gate static scf_error_t
scf_add_match(scf_matchkey_t ** htable,const char * fmri,const char * legacy,scf_pattern_t * pattern,int svc_explicit)61937c478bd9Sstevel@tonic-gate scf_add_match(scf_matchkey_t **htable, const char *fmri, const char *legacy,
61947c478bd9Sstevel@tonic-gate     scf_pattern_t *pattern, int svc_explicit)
61957c478bd9Sstevel@tonic-gate {
61967c478bd9Sstevel@tonic-gate 	scf_match_t *match;
61977c478bd9Sstevel@tonic-gate 
61987c478bd9Sstevel@tonic-gate 	/*
61997c478bd9Sstevel@tonic-gate 	 * If svc_explicit is set, enforce the constaint that matching
62007c478bd9Sstevel@tonic-gate 	 * instances take precedence over matching services. Otherwise,
62017c478bd9Sstevel@tonic-gate 	 * matching services take precedence over matching instances.
62027c478bd9Sstevel@tonic-gate 	 */
62037c478bd9Sstevel@tonic-gate 	if (svc_explicit) {
62047c478bd9Sstevel@tonic-gate 		scf_match_t *next, *prev;
62057c478bd9Sstevel@tonic-gate 		/*
62067c478bd9Sstevel@tonic-gate 		 * If we match an instance, check to see if we must remove
62077c478bd9Sstevel@tonic-gate 		 * any matching services (for SCF_WALK_EXPLICIT).
62087c478bd9Sstevel@tonic-gate 		 */
62097c478bd9Sstevel@tonic-gate 		for (prev = match = pattern->sp_matches; match != NULL;
62107c478bd9Sstevel@tonic-gate 		    match = next) {
62117c478bd9Sstevel@tonic-gate 			size_t len = strlen(match->sm_key->sk_fmri);
62127c478bd9Sstevel@tonic-gate 			next = match->sm_next;
62137c478bd9Sstevel@tonic-gate 			if (strncmp(match->sm_key->sk_fmri, fmri, len) == 0 &&
62147c478bd9Sstevel@tonic-gate 			    fmri[len] == ':') {
62157c478bd9Sstevel@tonic-gate 				if (prev == match)
62167c478bd9Sstevel@tonic-gate 					pattern->sp_matches = match->sm_next;
62177c478bd9Sstevel@tonic-gate 				else
62187c478bd9Sstevel@tonic-gate 					prev->sm_next = match->sm_next;
62197c478bd9Sstevel@tonic-gate 				pattern->sp_matchcount--;
62207c478bd9Sstevel@tonic-gate 				free(match);
62217c478bd9Sstevel@tonic-gate 			} else
62227c478bd9Sstevel@tonic-gate 				prev = match;
62237c478bd9Sstevel@tonic-gate 		}
62247c478bd9Sstevel@tonic-gate 	} else {
62257c478bd9Sstevel@tonic-gate 		/*
62267c478bd9Sstevel@tonic-gate 		 * If we've matched a service don't add any instances (for
62277c478bd9Sstevel@tonic-gate 		 * SCF_WALK_SERVICE).
62287c478bd9Sstevel@tonic-gate 		 */
62297c478bd9Sstevel@tonic-gate 		for (match = pattern->sp_matches; match != NULL;
62307c478bd9Sstevel@tonic-gate 		    match = match->sm_next) {
62317c478bd9Sstevel@tonic-gate 			size_t len = strlen(match->sm_key->sk_fmri);
62327c478bd9Sstevel@tonic-gate 			if (strncmp(match->sm_key->sk_fmri, fmri, len) == 0 &&
62337c478bd9Sstevel@tonic-gate 			    fmri[len] == ':')
62347c478bd9Sstevel@tonic-gate 				return (0);
62357c478bd9Sstevel@tonic-gate 		}
62367c478bd9Sstevel@tonic-gate 	}
62377c478bd9Sstevel@tonic-gate 
62387c478bd9Sstevel@tonic-gate 	if ((match = malloc(sizeof (scf_match_t))) == NULL)
62397c478bd9Sstevel@tonic-gate 		return (SCF_ERROR_NO_MEMORY);
62407c478bd9Sstevel@tonic-gate 
62417c478bd9Sstevel@tonic-gate 	if ((match->sm_key = scf_get_key(htable, fmri, legacy)) == NULL) {
62427c478bd9Sstevel@tonic-gate 		free(match);
62437c478bd9Sstevel@tonic-gate 		return (SCF_ERROR_NO_MEMORY);
62447c478bd9Sstevel@tonic-gate 	}
62457c478bd9Sstevel@tonic-gate 
62467c478bd9Sstevel@tonic-gate 	match->sm_next = pattern->sp_matches;
62477c478bd9Sstevel@tonic-gate 	pattern->sp_matches = match;
62487c478bd9Sstevel@tonic-gate 	pattern->sp_matchcount++;
62497c478bd9Sstevel@tonic-gate 
62507c478bd9Sstevel@tonic-gate 	return (0);
62517c478bd9Sstevel@tonic-gate }
62527c478bd9Sstevel@tonic-gate 
62537c478bd9Sstevel@tonic-gate /*
62547c478bd9Sstevel@tonic-gate  * Returns 1 if the fmri matches the given pattern, 0 otherwise.
62557c478bd9Sstevel@tonic-gate  */
6256103b2b15Sgww int
scf_cmp_pattern(char * fmri,scf_pattern_t * pattern)62577c478bd9Sstevel@tonic-gate scf_cmp_pattern(char *fmri, scf_pattern_t *pattern)
62587c478bd9Sstevel@tonic-gate {
62597c478bd9Sstevel@tonic-gate 	char *tmp;
62607c478bd9Sstevel@tonic-gate 
62617c478bd9Sstevel@tonic-gate 	if (pattern->sp_type == PATTERN_GLOB) {
62627c478bd9Sstevel@tonic-gate 		if (fnmatch(pattern->sp_arg, fmri, 0) == 0)
62637c478bd9Sstevel@tonic-gate 			return (1);
62647c478bd9Sstevel@tonic-gate 	} else if (pattern->sp_type == PATTERN_PARTIAL &&
62657c478bd9Sstevel@tonic-gate 	    (tmp = strstr(fmri, pattern->sp_arg)) != NULL) {
62667c478bd9Sstevel@tonic-gate 		/*
62677c478bd9Sstevel@tonic-gate 		 * We only allow partial matches anchored on the end of
62687c478bd9Sstevel@tonic-gate 		 * a service or instance, and beginning on an element
62697c478bd9Sstevel@tonic-gate 		 * boundary.
62707c478bd9Sstevel@tonic-gate 		 */
62717c478bd9Sstevel@tonic-gate 		if (tmp != fmri && tmp[-1] != '/' && tmp[-1] != ':' &&
62727c478bd9Sstevel@tonic-gate 		    tmp[0] != ':')
62737c478bd9Sstevel@tonic-gate 			return (0);
62747c478bd9Sstevel@tonic-gate 		tmp += strlen(pattern->sp_arg);
62757c478bd9Sstevel@tonic-gate 		if (tmp != fmri + strlen(fmri) && tmp[0] != ':' &&
62767c478bd9Sstevel@tonic-gate 		    tmp[-1] != ':')
62777c478bd9Sstevel@tonic-gate 			return (0);
62787c478bd9Sstevel@tonic-gate 
62797c478bd9Sstevel@tonic-gate 		/*
62807c478bd9Sstevel@tonic-gate 		 * If the user has supplied a short pattern that matches
62817c478bd9Sstevel@tonic-gate 		 * 'svc:/' or 'lrc:/', ignore it.
62827c478bd9Sstevel@tonic-gate 		 */
62837c478bd9Sstevel@tonic-gate 		if (tmp <= fmri + 4)
62847c478bd9Sstevel@tonic-gate 			return (0);
62857c478bd9Sstevel@tonic-gate 
62867c478bd9Sstevel@tonic-gate 		return (1);
62877c478bd9Sstevel@tonic-gate 	}
62887c478bd9Sstevel@tonic-gate 
62897c478bd9Sstevel@tonic-gate 	return (0);
62907c478bd9Sstevel@tonic-gate }
62917c478bd9Sstevel@tonic-gate 
62927c478bd9Sstevel@tonic-gate /*
62937c478bd9Sstevel@tonic-gate  * Attempts to match the given FMRI against a set of patterns, keeping track of
62947c478bd9Sstevel@tonic-gate  * the results.
62957c478bd9Sstevel@tonic-gate  */
62967c478bd9Sstevel@tonic-gate static scf_error_t
scf_pattern_match(scf_matchkey_t ** htable,char * fmri,const char * legacy,int npattern,scf_pattern_t * pattern,int svc_explicit)62977c478bd9Sstevel@tonic-gate scf_pattern_match(scf_matchkey_t **htable, char *fmri, const char *legacy,
62987c478bd9Sstevel@tonic-gate     int npattern, scf_pattern_t *pattern, int svc_explicit)
62997c478bd9Sstevel@tonic-gate {
63007c478bd9Sstevel@tonic-gate 	int i;
63017c478bd9Sstevel@tonic-gate 	int ret = 0;
63027c478bd9Sstevel@tonic-gate 
63037c478bd9Sstevel@tonic-gate 	for (i = 0; i < npattern; i++) {
63047c478bd9Sstevel@tonic-gate 		if (scf_cmp_pattern(fmri, &pattern[i]) &&
63057c478bd9Sstevel@tonic-gate 		    (ret = scf_add_match(htable, fmri,
63067c478bd9Sstevel@tonic-gate 		    legacy, &pattern[i], svc_explicit)) != 0)
63077c478bd9Sstevel@tonic-gate 			return (ret);
63087c478bd9Sstevel@tonic-gate 	}
63097c478bd9Sstevel@tonic-gate 
63107c478bd9Sstevel@tonic-gate 	return (0);
63117c478bd9Sstevel@tonic-gate }
63127c478bd9Sstevel@tonic-gate 
6313ad3ad82aSAndy Fiddaman /*
6314ad3ad82aSAndy Fiddaman  * Construct an error message from a provided format string and include all
6315ad3ad82aSAndy Fiddaman  * of the matched FMRIs.
6316ad3ad82aSAndy Fiddaman  */
6317ad3ad82aSAndy Fiddaman static char *
scf_multiple_match_error(scf_pattern_t * pattern,const char * format)6318ad3ad82aSAndy Fiddaman scf_multiple_match_error(scf_pattern_t *pattern, const char *format)
6319ad3ad82aSAndy Fiddaman {
6320ad3ad82aSAndy Fiddaman 	scf_match_t *match;
6321ad3ad82aSAndy Fiddaman 	size_t len, off;
6322ad3ad82aSAndy Fiddaman 	char *msg;
6323ad3ad82aSAndy Fiddaman 
6324ad3ad82aSAndy Fiddaman 	/*
6325ad3ad82aSAndy Fiddaman 	 * Note that strlen(format) includes the length of '%s', which
6326ad3ad82aSAndy Fiddaman 	 * accounts for the terminating null byte.
6327ad3ad82aSAndy Fiddaman 	 */
6328ad3ad82aSAndy Fiddaman 	assert(strstr(format, "%s") != NULL);
6329ad3ad82aSAndy Fiddaman 	len = strlen(format) + strlen(pattern->sp_arg);
6330ad3ad82aSAndy Fiddaman 	for (match = pattern->sp_matches; match != NULL;
6331ad3ad82aSAndy Fiddaman 	    match = match->sm_next)
6332ad3ad82aSAndy Fiddaman 		len += strlen(match->sm_key->sk_fmri) + 2;
6333ad3ad82aSAndy Fiddaman 
6334ad3ad82aSAndy Fiddaman 	if ((msg = malloc(len)) == NULL)
6335ad3ad82aSAndy Fiddaman 		return (NULL);
6336ad3ad82aSAndy Fiddaman 
6337ad3ad82aSAndy Fiddaman 	(void) snprintf(msg, len, format, pattern->sp_arg);
6338ad3ad82aSAndy Fiddaman 	off = strlen(msg);
6339ad3ad82aSAndy Fiddaman 	for (match = pattern->sp_matches; match != NULL;
6340ad3ad82aSAndy Fiddaman 	    match = match->sm_next) {
6341ad3ad82aSAndy Fiddaman 		assert(off < len);
6342ad3ad82aSAndy Fiddaman 		off += snprintf(msg + off, len - off, "\t%s\n",
6343ad3ad82aSAndy Fiddaman 		    match->sm_key->sk_fmri);
6344ad3ad82aSAndy Fiddaman 	}
6345ad3ad82aSAndy Fiddaman 
6346ad3ad82aSAndy Fiddaman 	return (msg);
6347ad3ad82aSAndy Fiddaman }
6348ad3ad82aSAndy Fiddaman 
634976cf44abSjeanm /*
635076cf44abSjeanm  * Fails with _INVALID_ARGUMENT, _HANDLE_DESTROYED, _INTERNAL (bad server
635176cf44abSjeanm  * response or id in use), _NO_MEMORY, _HANDLE_MISMATCH, _CONSTRAINT_VIOLATED,
635276cf44abSjeanm  * _NOT_FOUND, _NOT_BOUND, _CONNECTION_BROKEN, _NOT_SET, _DELETED,
635376cf44abSjeanm  * _NO_RESOURCES, _BACKEND_ACCESS, _TYPE_MISMATCH.
635476cf44abSjeanm  */
63557c478bd9Sstevel@tonic-gate scf_error_t
scf_walk_fmri(scf_handle_t * h,int argc,char ** argv,int flags,scf_walk_callback callback,void * data,int * err,void (* errfunc)(const char *,...))63567c478bd9Sstevel@tonic-gate scf_walk_fmri(scf_handle_t *h, int argc, char **argv, int flags,
63577c478bd9Sstevel@tonic-gate     scf_walk_callback callback, void *data, int *err,
63587c478bd9Sstevel@tonic-gate     void (*errfunc)(const char *, ...))
63597c478bd9Sstevel@tonic-gate {
63607c478bd9Sstevel@tonic-gate 	scf_pattern_t *pattern = NULL;
63617c478bd9Sstevel@tonic-gate 	int i;
63627c478bd9Sstevel@tonic-gate 	char *fmri = NULL;
63637c478bd9Sstevel@tonic-gate 	ssize_t max_fmri_length;
63647c478bd9Sstevel@tonic-gate 	scf_service_t *svc = NULL;
63657c478bd9Sstevel@tonic-gate 	scf_instance_t *inst = NULL;
63667c478bd9Sstevel@tonic-gate 	scf_iter_t *iter = NULL, *sciter = NULL, *siter = NULL;
63677c478bd9Sstevel@tonic-gate 	scf_scope_t *scope = NULL;
63687c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *pg = NULL;
63697c478bd9Sstevel@tonic-gate 	scf_property_t *prop = NULL;
63707c478bd9Sstevel@tonic-gate 	scf_value_t *value = NULL;
63717c478bd9Sstevel@tonic-gate 	int ret = 0;
63727c478bd9Sstevel@tonic-gate 	scf_matchkey_t **htable = NULL;
63737c478bd9Sstevel@tonic-gate 	int pattern_search = 0;
63747c478bd9Sstevel@tonic-gate 	ssize_t max_name_length;
63757c478bd9Sstevel@tonic-gate 	char *pgname = NULL;
63767c478bd9Sstevel@tonic-gate 	scf_walkinfo_t info;
63777c478bd9Sstevel@tonic-gate 
63787c478bd9Sstevel@tonic-gate #ifndef NDEBUG
63797c478bd9Sstevel@tonic-gate 	if (flags & SCF_WALK_EXPLICIT)
63807c478bd9Sstevel@tonic-gate 		assert(flags & SCF_WALK_SERVICE);
63817c478bd9Sstevel@tonic-gate 	if (flags & SCF_WALK_NOINSTANCE)
63827c478bd9Sstevel@tonic-gate 		assert(flags & SCF_WALK_SERVICE);
63837c478bd9Sstevel@tonic-gate 	if (flags & SCF_WALK_PROPERTY)
63847c478bd9Sstevel@tonic-gate 		assert(!(flags & SCF_WALK_LEGACY));
63857c478bd9Sstevel@tonic-gate #endif
63867c478bd9Sstevel@tonic-gate 
63877c478bd9Sstevel@tonic-gate 	/*
63887c478bd9Sstevel@tonic-gate 	 * Setup initial variables
63897c478bd9Sstevel@tonic-gate 	 */
63901f6eb021SLiane Praza 	max_fmri_length = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH);
63911f6eb021SLiane Praza 	assert(max_fmri_length != -1);
63921f6eb021SLiane Praza 	max_name_length = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH);
63931f6eb021SLiane Praza 	assert(max_name_length != -1);
63947c478bd9Sstevel@tonic-gate 
63957c478bd9Sstevel@tonic-gate 	if ((fmri = malloc(max_fmri_length + 1)) == NULL ||
63967c478bd9Sstevel@tonic-gate 	    (pgname = malloc(max_name_length + 1)) == NULL) {
63977c478bd9Sstevel@tonic-gate 		ret = SCF_ERROR_NO_MEMORY;
63987c478bd9Sstevel@tonic-gate 		goto error;
63997c478bd9Sstevel@tonic-gate 	}
64007c478bd9Sstevel@tonic-gate 
64017c478bd9Sstevel@tonic-gate 	if (argc == 0) {
64027c478bd9Sstevel@tonic-gate 		pattern = NULL;
64037c478bd9Sstevel@tonic-gate 	} else if ((pattern = calloc(argc, sizeof (scf_pattern_t)))
64047c478bd9Sstevel@tonic-gate 	    == NULL) {
64057c478bd9Sstevel@tonic-gate 		ret = SCF_ERROR_NO_MEMORY;
64067c478bd9Sstevel@tonic-gate 		goto error;
64077c478bd9Sstevel@tonic-gate 	}
64087c478bd9Sstevel@tonic-gate 
64097c478bd9Sstevel@tonic-gate 	if ((htable = calloc(WALK_HTABLE_SIZE, sizeof (void *))) == NULL) {
64107c478bd9Sstevel@tonic-gate 		ret = SCF_ERROR_NO_MEMORY;
64117c478bd9Sstevel@tonic-gate 		goto error;
64127c478bd9Sstevel@tonic-gate 	}
64137c478bd9Sstevel@tonic-gate 
64147c478bd9Sstevel@tonic-gate 	if ((inst = scf_instance_create(h)) == NULL ||
64157c478bd9Sstevel@tonic-gate 	    (svc = scf_service_create(h)) == NULL ||
64167c478bd9Sstevel@tonic-gate 	    (iter = scf_iter_create(h)) == NULL ||
64177c478bd9Sstevel@tonic-gate 	    (sciter = scf_iter_create(h)) == NULL ||
64187c478bd9Sstevel@tonic-gate 	    (siter = scf_iter_create(h)) == NULL ||
64197c478bd9Sstevel@tonic-gate 	    (scope = scf_scope_create(h)) == NULL ||
64207c478bd9Sstevel@tonic-gate 	    (pg = scf_pg_create(h)) == NULL ||
64217c478bd9Sstevel@tonic-gate 	    (prop = scf_property_create(h)) == NULL ||
64227c478bd9Sstevel@tonic-gate 	    (value = scf_value_create(h)) == NULL) {
64237c478bd9Sstevel@tonic-gate 		ret = scf_error();
64247c478bd9Sstevel@tonic-gate 		goto error;
64257c478bd9Sstevel@tonic-gate 	}
64267c478bd9Sstevel@tonic-gate 
64277c478bd9Sstevel@tonic-gate 	/*
64287c478bd9Sstevel@tonic-gate 	 * For each fmri given, we first check to see if it's a full service,
64297c478bd9Sstevel@tonic-gate 	 * instance, property group, or property FMRI.  This avoids having to do
64307c478bd9Sstevel@tonic-gate 	 * the (rather expensive) walk of all instances.  Any element which does
64317c478bd9Sstevel@tonic-gate 	 * not match a full fmri is identified as a globbed pattern or a partial
64327c478bd9Sstevel@tonic-gate 	 * fmri and stored in a private array when walking instances.
64337c478bd9Sstevel@tonic-gate 	 */
64347c478bd9Sstevel@tonic-gate 	for (i = 0; i < argc; i++) {
64357c478bd9Sstevel@tonic-gate 		const char *scope_name, *svc_name, *inst_name, *pg_name;
64367c478bd9Sstevel@tonic-gate 		const char *prop_name;
64377c478bd9Sstevel@tonic-gate 
64387c478bd9Sstevel@tonic-gate 		if (strlen(argv[i]) > max_fmri_length) {
64397c478bd9Sstevel@tonic-gate 			errfunc(scf_get_msg(SCF_MSG_ARGTOOLONG), argv[i]);
64407c478bd9Sstevel@tonic-gate 			if (err != NULL)
64417c478bd9Sstevel@tonic-gate 				*err = UU_EXIT_FATAL;
64427c478bd9Sstevel@tonic-gate 			continue;
64437c478bd9Sstevel@tonic-gate 		}
64447c478bd9Sstevel@tonic-gate 
64457c478bd9Sstevel@tonic-gate 		(void) strcpy(fmri, argv[i]);
64467c478bd9Sstevel@tonic-gate 		if (scf_parse_svc_fmri(fmri, &scope_name, &svc_name, &inst_name,
64477c478bd9Sstevel@tonic-gate 		    &pg_name, &prop_name) != SCF_SUCCESS)
64487c478bd9Sstevel@tonic-gate 			goto badfmri;
64497c478bd9Sstevel@tonic-gate 
64507c478bd9Sstevel@tonic-gate 		/*
64517c478bd9Sstevel@tonic-gate 		 * If the user has specified SCF_WALK_PROPERTY, allow property
64527c478bd9Sstevel@tonic-gate 		 * groups and properties.
64537c478bd9Sstevel@tonic-gate 		 */
64547c478bd9Sstevel@tonic-gate 		if (pg_name != NULL || prop_name != NULL) {
64557c478bd9Sstevel@tonic-gate 			if (!(flags & SCF_WALK_PROPERTY))
64567c478bd9Sstevel@tonic-gate 				goto badfmri;
64577c478bd9Sstevel@tonic-gate 
64587c478bd9Sstevel@tonic-gate 			if (scf_handle_decode_fmri(h, argv[i], NULL, NULL,
64597c478bd9Sstevel@tonic-gate 			    NULL, pg, prop, 0) != 0)
64607c478bd9Sstevel@tonic-gate 				goto badfmri;
64617c478bd9Sstevel@tonic-gate 
64627c478bd9Sstevel@tonic-gate 			if (scf_pg_get_name(pg, NULL, 0) < 0 &&
64637c478bd9Sstevel@tonic-gate 			    scf_property_get_name(prop, NULL, 0) < 0)
64647c478bd9Sstevel@tonic-gate 				goto badfmri;
64657c478bd9Sstevel@tonic-gate 
64667c478bd9Sstevel@tonic-gate 			if (scf_canonify_fmri(argv[i], fmri, max_fmri_length)
64677c478bd9Sstevel@tonic-gate 			    <= 0) {
64687c478bd9Sstevel@tonic-gate 				/*
64697c478bd9Sstevel@tonic-gate 				 * scf_parse_fmri() should have caught this.
64707c478bd9Sstevel@tonic-gate 				 */
64717c478bd9Sstevel@tonic-gate 				abort();
64727c478bd9Sstevel@tonic-gate 			}
64737c478bd9Sstevel@tonic-gate 
64747c478bd9Sstevel@tonic-gate 			if ((ret = scf_add_match(htable, fmri, NULL,
64757c478bd9Sstevel@tonic-gate 			    &pattern[i], flags & SCF_WALK_EXPLICIT)) != 0)
64767c478bd9Sstevel@tonic-gate 				goto error;
64777c478bd9Sstevel@tonic-gate 
64787c478bd9Sstevel@tonic-gate 			if ((pattern[i].sp_arg = strdup(argv[i])) == NULL) {
64797c478bd9Sstevel@tonic-gate 				ret = SCF_ERROR_NO_MEMORY;
64807c478bd9Sstevel@tonic-gate 				goto error;
64817c478bd9Sstevel@tonic-gate 			}
64827c478bd9Sstevel@tonic-gate 			pattern[i].sp_type = PATTERN_EXACT;
64837c478bd9Sstevel@tonic-gate 		}
64847c478bd9Sstevel@tonic-gate 
64857c478bd9Sstevel@tonic-gate 		/*
64867c478bd9Sstevel@tonic-gate 		 * We need at least a service name
64877c478bd9Sstevel@tonic-gate 		 */
64887c478bd9Sstevel@tonic-gate 		if (scope_name == NULL || svc_name == NULL)
64897c478bd9Sstevel@tonic-gate 			goto badfmri;
64907c478bd9Sstevel@tonic-gate 
64917c478bd9Sstevel@tonic-gate 		/*
64927c478bd9Sstevel@tonic-gate 		 * If we have a fully qualified instance, add it to our list of
64937c478bd9Sstevel@tonic-gate 		 * fmris to watch.
64947c478bd9Sstevel@tonic-gate 		 */
64957c478bd9Sstevel@tonic-gate 		if (inst_name != NULL) {
64967c478bd9Sstevel@tonic-gate 			if (flags & SCF_WALK_NOINSTANCE)
64977c478bd9Sstevel@tonic-gate 				goto badfmri;
64987c478bd9Sstevel@tonic-gate 
64997c478bd9Sstevel@tonic-gate 			if (scf_handle_decode_fmri(h, argv[i], NULL, NULL,
65007c478bd9Sstevel@tonic-gate 			    inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != 0)
65017c478bd9Sstevel@tonic-gate 				goto badfmri;
65027c478bd9Sstevel@tonic-gate 
65037c478bd9Sstevel@tonic-gate 			if (scf_canonify_fmri(argv[i], fmri, max_fmri_length)
65047c478bd9Sstevel@tonic-gate 			    <= 0)
65057c478bd9Sstevel@tonic-gate 				goto badfmri;
65067c478bd9Sstevel@tonic-gate 
65077c478bd9Sstevel@tonic-gate 			if ((ret = scf_add_match(htable, fmri, NULL,
65087c478bd9Sstevel@tonic-gate 			    &pattern[i], flags & SCF_WALK_EXPLICIT)) != 0)
65097c478bd9Sstevel@tonic-gate 				goto error;
65107c478bd9Sstevel@tonic-gate 
65117c478bd9Sstevel@tonic-gate 			if ((pattern[i].sp_arg = strdup(argv[i])) == NULL) {
65127c478bd9Sstevel@tonic-gate 				ret = SCF_ERROR_NO_MEMORY;
65137c478bd9Sstevel@tonic-gate 				goto error;
65147c478bd9Sstevel@tonic-gate 			}
65157c478bd9Sstevel@tonic-gate 			pattern[i].sp_type = PATTERN_EXACT;
65167c478bd9Sstevel@tonic-gate 
65177c478bd9Sstevel@tonic-gate 			continue;
65187c478bd9Sstevel@tonic-gate 		}
65197c478bd9Sstevel@tonic-gate 
65207c478bd9Sstevel@tonic-gate 		if (scf_handle_decode_fmri(h, argv[i], NULL, svc,
65217c478bd9Sstevel@tonic-gate 		    NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) !=
65227c478bd9Sstevel@tonic-gate 		    SCF_SUCCESS)
65237c478bd9Sstevel@tonic-gate 			goto badfmri;
65247c478bd9Sstevel@tonic-gate 
65257c478bd9Sstevel@tonic-gate 		/*
65267c478bd9Sstevel@tonic-gate 		 * If the user allows for bare services, then simply
65277c478bd9Sstevel@tonic-gate 		 * pass this service on.
65287c478bd9Sstevel@tonic-gate 		 */
65297c478bd9Sstevel@tonic-gate 		if (flags & SCF_WALK_SERVICE) {
65307c478bd9Sstevel@tonic-gate 			if (scf_service_to_fmri(svc, fmri,
65317c478bd9Sstevel@tonic-gate 			    max_fmri_length + 1) <= 0) {
65327c478bd9Sstevel@tonic-gate 				ret = scf_error();
65337c478bd9Sstevel@tonic-gate 				goto error;
65347c478bd9Sstevel@tonic-gate 			}
65357c478bd9Sstevel@tonic-gate 
65367c478bd9Sstevel@tonic-gate 			if ((ret = scf_add_match(htable, fmri, NULL,
65377c478bd9Sstevel@tonic-gate 			    &pattern[i], flags & SCF_WALK_EXPLICIT)) != 0)
65387c478bd9Sstevel@tonic-gate 				goto error;
65397c478bd9Sstevel@tonic-gate 
65407c478bd9Sstevel@tonic-gate 			if ((pattern[i].sp_arg = strdup(argv[i]))
65417c478bd9Sstevel@tonic-gate 			    == NULL) {
65427c478bd9Sstevel@tonic-gate 				ret = SCF_ERROR_NO_MEMORY;
65437c478bd9Sstevel@tonic-gate 				goto error;
65447c478bd9Sstevel@tonic-gate 			}
65457c478bd9Sstevel@tonic-gate 			pattern[i].sp_type = PATTERN_EXACT;
65467c478bd9Sstevel@tonic-gate 			continue;
65477c478bd9Sstevel@tonic-gate 		}
65487c478bd9Sstevel@tonic-gate 
65497c478bd9Sstevel@tonic-gate 		if (flags & SCF_WALK_NOINSTANCE)
65507c478bd9Sstevel@tonic-gate 			goto badfmri;
65517c478bd9Sstevel@tonic-gate 
65527c478bd9Sstevel@tonic-gate 		/*
65537c478bd9Sstevel@tonic-gate 		 * Otherwise, iterate over all instances in the service.
65547c478bd9Sstevel@tonic-gate 		 */
65557c478bd9Sstevel@tonic-gate 		if (scf_iter_service_instances(iter, svc) !=
65567c478bd9Sstevel@tonic-gate 		    SCF_SUCCESS) {
65577c478bd9Sstevel@tonic-gate 			ret = scf_error();
65587c478bd9Sstevel@tonic-gate 			goto error;
65597c478bd9Sstevel@tonic-gate 		}
65607c478bd9Sstevel@tonic-gate 
65617c478bd9Sstevel@tonic-gate 		for (;;) {
65627c478bd9Sstevel@tonic-gate 			ret = scf_iter_next_instance(iter, inst);
65637c478bd9Sstevel@tonic-gate 			if (ret == 0)
65647c478bd9Sstevel@tonic-gate 				break;
65657c478bd9Sstevel@tonic-gate 			if (ret != 1) {
65667c478bd9Sstevel@tonic-gate 				ret = scf_error();
65677c478bd9Sstevel@tonic-gate 				goto error;
65687c478bd9Sstevel@tonic-gate 			}
65697c478bd9Sstevel@tonic-gate 
65707c478bd9Sstevel@tonic-gate 			if (scf_instance_to_fmri(inst, fmri,
65717c478bd9Sstevel@tonic-gate 			    max_fmri_length + 1) == -1)
65727c478bd9Sstevel@tonic-gate 				goto badfmri;
65737c478bd9Sstevel@tonic-gate 
65747c478bd9Sstevel@tonic-gate 			if ((ret = scf_add_match(htable, fmri, NULL,
65757c478bd9Sstevel@tonic-gate 			    &pattern[i], flags & SCF_WALK_EXPLICIT)) != 0)
65767c478bd9Sstevel@tonic-gate 				goto error;
65777c478bd9Sstevel@tonic-gate 		}
65787c478bd9Sstevel@tonic-gate 
65797c478bd9Sstevel@tonic-gate 		if ((pattern[i].sp_arg = strdup(argv[i])) == NULL) {
65807c478bd9Sstevel@tonic-gate 			ret = SCF_ERROR_NO_MEMORY;
65817c478bd9Sstevel@tonic-gate 			goto error;
65827c478bd9Sstevel@tonic-gate 		}
65837c478bd9Sstevel@tonic-gate 		pattern[i].sp_type = PATTERN_EXACT;
65847c478bd9Sstevel@tonic-gate 
65857c478bd9Sstevel@tonic-gate 		continue;
65867c478bd9Sstevel@tonic-gate 
65877c478bd9Sstevel@tonic-gate badfmri:
65887c478bd9Sstevel@tonic-gate 
65897c478bd9Sstevel@tonic-gate 		/*
65907c478bd9Sstevel@tonic-gate 		 * If we got here because of a fatal error, bail out
65917c478bd9Sstevel@tonic-gate 		 * immediately.
65927c478bd9Sstevel@tonic-gate 		 */
65937c478bd9Sstevel@tonic-gate 		if (scf_error() == SCF_ERROR_CONNECTION_BROKEN) {
65947c478bd9Sstevel@tonic-gate 			ret = scf_error();
65957c478bd9Sstevel@tonic-gate 			goto error;
65967c478bd9Sstevel@tonic-gate 		}
65977c478bd9Sstevel@tonic-gate 
65987c478bd9Sstevel@tonic-gate 		/*
65997c478bd9Sstevel@tonic-gate 		 * At this point we failed to interpret the argument as a
66007c478bd9Sstevel@tonic-gate 		 * complete fmri, so mark it as a partial or globbed FMRI for
66017c478bd9Sstevel@tonic-gate 		 * later processing.
66027c478bd9Sstevel@tonic-gate 		 */
66037c478bd9Sstevel@tonic-gate 		if (strpbrk(argv[i], "*?[") != NULL) {
66047c478bd9Sstevel@tonic-gate 			/*
66057c478bd9Sstevel@tonic-gate 			 * Prepend svc:/ to patterns which don't begin with * or
66067c478bd9Sstevel@tonic-gate 			 * svc: or lrc:.
66077c478bd9Sstevel@tonic-gate 			 */
66087c478bd9Sstevel@tonic-gate 			pattern[i].sp_type = PATTERN_GLOB;
66097c478bd9Sstevel@tonic-gate 			if (argv[i][0] == '*' ||
66107c478bd9Sstevel@tonic-gate 			    (strlen(argv[i]) >= 4 && argv[i][3] == ':'))
66117c478bd9Sstevel@tonic-gate 				pattern[i].sp_arg = strdup(argv[i]);
66127c478bd9Sstevel@tonic-gate 			else {
66137c478bd9Sstevel@tonic-gate 				pattern[i].sp_arg = malloc(strlen(argv[i]) + 6);
66147c478bd9Sstevel@tonic-gate 				if (pattern[i].sp_arg != NULL)
66157c478bd9Sstevel@tonic-gate 					(void) snprintf(pattern[i].sp_arg,
66167c478bd9Sstevel@tonic-gate 					    strlen(argv[i]) + 6, "svc:/%s",
66177c478bd9Sstevel@tonic-gate 					    argv[i]);
66187c478bd9Sstevel@tonic-gate 			}
66197c478bd9Sstevel@tonic-gate 		} else {
66207c478bd9Sstevel@tonic-gate 			pattern[i].sp_type = PATTERN_PARTIAL;
66217c478bd9Sstevel@tonic-gate 			pattern[i].sp_arg = strdup(argv[i]);
66227c478bd9Sstevel@tonic-gate 		}
66237c478bd9Sstevel@tonic-gate 		pattern_search = 1;
66247c478bd9Sstevel@tonic-gate 		if (pattern[i].sp_arg == NULL) {
66257c478bd9Sstevel@tonic-gate 			ret = SCF_ERROR_NO_MEMORY;
66267c478bd9Sstevel@tonic-gate 			goto error;
66277c478bd9Sstevel@tonic-gate 		}
66287c478bd9Sstevel@tonic-gate 	}
66297c478bd9Sstevel@tonic-gate 
66307c478bd9Sstevel@tonic-gate 	if (pattern_search || argc == 0) {
66317c478bd9Sstevel@tonic-gate 		/*
66327c478bd9Sstevel@tonic-gate 		 * We have a set of patterns to search for.  Iterate over all
66337c478bd9Sstevel@tonic-gate 		 * instances and legacy services searching for matches.
66347c478bd9Sstevel@tonic-gate 		 */
66357c478bd9Sstevel@tonic-gate 		if (scf_handle_get_local_scope(h, scope) != 0) {
66367c478bd9Sstevel@tonic-gate 			ret = scf_error();
66377c478bd9Sstevel@tonic-gate 			goto error;
66387c478bd9Sstevel@tonic-gate 		}
66397c478bd9Sstevel@tonic-gate 
66407c478bd9Sstevel@tonic-gate 		if (scf_iter_scope_services(sciter, scope) != 0) {
66417c478bd9Sstevel@tonic-gate 			ret = scf_error();
66427c478bd9Sstevel@tonic-gate 			goto error;
66437c478bd9Sstevel@tonic-gate 		}
66447c478bd9Sstevel@tonic-gate 
66457c478bd9Sstevel@tonic-gate 		for (;;) {
66467c478bd9Sstevel@tonic-gate 			ret = scf_iter_next_service(sciter, svc);
66477c478bd9Sstevel@tonic-gate 			if (ret == 0)
66487c478bd9Sstevel@tonic-gate 				break;
66497c478bd9Sstevel@tonic-gate 			if (ret != 1) {
66507c478bd9Sstevel@tonic-gate 				ret = scf_error();
66517c478bd9Sstevel@tonic-gate 				goto error;
66527c478bd9Sstevel@tonic-gate 			}
66537c478bd9Sstevel@tonic-gate 
66547c478bd9Sstevel@tonic-gate 			if (flags & SCF_WALK_SERVICE) {
66557c478bd9Sstevel@tonic-gate 				/*
66567c478bd9Sstevel@tonic-gate 				 * If the user is requesting bare services, try
66577c478bd9Sstevel@tonic-gate 				 * to match the service first.
66587c478bd9Sstevel@tonic-gate 				 */
66597c478bd9Sstevel@tonic-gate 				if (scf_service_to_fmri(svc, fmri,
66607c478bd9Sstevel@tonic-gate 				    max_fmri_length + 1) < 0) {
66617c478bd9Sstevel@tonic-gate 					ret = scf_error();
66627c478bd9Sstevel@tonic-gate 					goto error;
66637c478bd9Sstevel@tonic-gate 				}
66647c478bd9Sstevel@tonic-gate 
66657c478bd9Sstevel@tonic-gate 				if (argc == 0) {
66667c478bd9Sstevel@tonic-gate 					info.fmri = fmri;
66677c478bd9Sstevel@tonic-gate 					info.scope = scope;
66687c478bd9Sstevel@tonic-gate 					info.svc = svc;
66697c478bd9Sstevel@tonic-gate 					info.inst = NULL;
66707c478bd9Sstevel@tonic-gate 					info.pg = NULL;
66717c478bd9Sstevel@tonic-gate 					info.prop = NULL;
66727c478bd9Sstevel@tonic-gate 					if ((ret = callback(data, &info)) != 0)
66737c478bd9Sstevel@tonic-gate 						goto error;
66747c478bd9Sstevel@tonic-gate 					continue;
66757c478bd9Sstevel@tonic-gate 				} else if ((ret = scf_pattern_match(htable,
66767c478bd9Sstevel@tonic-gate 				    fmri, NULL, argc, pattern,
66777c478bd9Sstevel@tonic-gate 				    flags & SCF_WALK_EXPLICIT)) != 0) {
66787c478bd9Sstevel@tonic-gate 					goto error;
66797c478bd9Sstevel@tonic-gate 				}
66807c478bd9Sstevel@tonic-gate 			}
66817c478bd9Sstevel@tonic-gate 
66827c478bd9Sstevel@tonic-gate 			if (flags & SCF_WALK_NOINSTANCE)
66837c478bd9Sstevel@tonic-gate 				continue;
66847c478bd9Sstevel@tonic-gate 
66857c478bd9Sstevel@tonic-gate 			/*
66867c478bd9Sstevel@tonic-gate 			 * Iterate over all instances in the service.
66877c478bd9Sstevel@tonic-gate 			 */
66887c478bd9Sstevel@tonic-gate 			if (scf_iter_service_instances(siter, svc) != 0) {
66897c478bd9Sstevel@tonic-gate 				if (scf_error() != SCF_ERROR_DELETED) {
66907c478bd9Sstevel@tonic-gate 					ret = scf_error();
66917c478bd9Sstevel@tonic-gate 					goto error;
66927c478bd9Sstevel@tonic-gate 				}
66937c478bd9Sstevel@tonic-gate 				continue;
66947c478bd9Sstevel@tonic-gate 			}
66957c478bd9Sstevel@tonic-gate 
66967c478bd9Sstevel@tonic-gate 			for (;;) {
66977c478bd9Sstevel@tonic-gate 				ret = scf_iter_next_instance(siter, inst);
66987c478bd9Sstevel@tonic-gate 				if (ret == 0)
66997c478bd9Sstevel@tonic-gate 					break;
67007c478bd9Sstevel@tonic-gate 				if (ret != 1) {
67017c478bd9Sstevel@tonic-gate 					if (scf_error() != SCF_ERROR_DELETED) {
67027c478bd9Sstevel@tonic-gate 						ret = scf_error();
67037c478bd9Sstevel@tonic-gate 						goto error;
67047c478bd9Sstevel@tonic-gate 					}
67057c478bd9Sstevel@tonic-gate 					break;
67067c478bd9Sstevel@tonic-gate 				}
67077c478bd9Sstevel@tonic-gate 
67087c478bd9Sstevel@tonic-gate 				if (scf_instance_to_fmri(inst, fmri,
67097c478bd9Sstevel@tonic-gate 				    max_fmri_length + 1) < 0) {
67107c478bd9Sstevel@tonic-gate 					ret = scf_error();
67117c478bd9Sstevel@tonic-gate 					goto error;
67127c478bd9Sstevel@tonic-gate 				}
67137c478bd9Sstevel@tonic-gate 
67147c478bd9Sstevel@tonic-gate 				/*
67157c478bd9Sstevel@tonic-gate 				 * Without arguments, execute the callback
67167c478bd9Sstevel@tonic-gate 				 * immediately.
67177c478bd9Sstevel@tonic-gate 				 */
67187c478bd9Sstevel@tonic-gate 				if (argc == 0) {
67197c478bd9Sstevel@tonic-gate 					info.fmri = fmri;
67207c478bd9Sstevel@tonic-gate 					info.scope = scope;
67217c478bd9Sstevel@tonic-gate 					info.svc = svc;
67227c478bd9Sstevel@tonic-gate 					info.inst = inst;
67237c478bd9Sstevel@tonic-gate 					info.pg = NULL;
67247c478bd9Sstevel@tonic-gate 					info.prop = NULL;
67257c478bd9Sstevel@tonic-gate 					if ((ret = callback(data, &info)) != 0)
67267c478bd9Sstevel@tonic-gate 						goto error;
67277c478bd9Sstevel@tonic-gate 				} else if ((ret = scf_pattern_match(htable,
67287c478bd9Sstevel@tonic-gate 				    fmri, NULL, argc, pattern,
67297c478bd9Sstevel@tonic-gate 				    flags & SCF_WALK_EXPLICIT)) != 0) {
67307c478bd9Sstevel@tonic-gate 					goto error;
67317c478bd9Sstevel@tonic-gate 				}
67327c478bd9Sstevel@tonic-gate 			}
67337c478bd9Sstevel@tonic-gate 		}
67347c478bd9Sstevel@tonic-gate 
67357c478bd9Sstevel@tonic-gate 		/*
67367c478bd9Sstevel@tonic-gate 		 * Search legacy services
67377c478bd9Sstevel@tonic-gate 		 */
67387c478bd9Sstevel@tonic-gate 		if ((flags & SCF_WALK_LEGACY)) {
67397c478bd9Sstevel@tonic-gate 			if (scf_scope_get_service(scope, SCF_LEGACY_SERVICE,
67407c478bd9Sstevel@tonic-gate 			    svc) != 0) {
67417c478bd9Sstevel@tonic-gate 				if (scf_error() != SCF_ERROR_NOT_FOUND) {
67427c478bd9Sstevel@tonic-gate 					ret = scf_error();
67437c478bd9Sstevel@tonic-gate 					goto error;
67447c478bd9Sstevel@tonic-gate 				}
67457c478bd9Sstevel@tonic-gate 
67467c478bd9Sstevel@tonic-gate 				goto nolegacy;
67477c478bd9Sstevel@tonic-gate 			}
67487c478bd9Sstevel@tonic-gate 
67497c478bd9Sstevel@tonic-gate 			if (scf_iter_service_pgs_typed(iter, svc,
67507c478bd9Sstevel@tonic-gate 			    SCF_GROUP_FRAMEWORK) != SCF_SUCCESS) {
67517c478bd9Sstevel@tonic-gate 				ret = scf_error();
67527c478bd9Sstevel@tonic-gate 				goto error;
67537c478bd9Sstevel@tonic-gate 			}
67547c478bd9Sstevel@tonic-gate 
67557c478bd9Sstevel@tonic-gate 			(void) strcpy(fmri, LEGACY_SCHEME);
67567c478bd9Sstevel@tonic-gate 
67577c478bd9Sstevel@tonic-gate 			for (;;) {
67587c478bd9Sstevel@tonic-gate 				ret = scf_iter_next_pg(iter, pg);
67597c478bd9Sstevel@tonic-gate 				if (ret == -1) {
67607c478bd9Sstevel@tonic-gate 					ret = scf_error();
67617c478bd9Sstevel@tonic-gate 					goto error;
67627c478bd9Sstevel@tonic-gate 				}
67637c478bd9Sstevel@tonic-gate 				if (ret == 0)
67647c478bd9Sstevel@tonic-gate 					break;
67657c478bd9Sstevel@tonic-gate 
67667c478bd9Sstevel@tonic-gate 				if (scf_pg_get_property(pg,
67677c478bd9Sstevel@tonic-gate 				    SCF_LEGACY_PROPERTY_NAME, prop) == -1) {
67687c478bd9Sstevel@tonic-gate 					ret = scf_error();
67697c478bd9Sstevel@tonic-gate 					if (ret == SCF_ERROR_DELETED ||
67707c478bd9Sstevel@tonic-gate 					    ret == SCF_ERROR_NOT_FOUND) {
67717c478bd9Sstevel@tonic-gate 						ret = 0;
67727c478bd9Sstevel@tonic-gate 						continue;
67737c478bd9Sstevel@tonic-gate 					}
67747c478bd9Sstevel@tonic-gate 					goto error;
67757c478bd9Sstevel@tonic-gate 				}
67767c478bd9Sstevel@tonic-gate 
67777c478bd9Sstevel@tonic-gate 				if (scf_property_is_type(prop, SCF_TYPE_ASTRING)
67787c478bd9Sstevel@tonic-gate 				    != SCF_SUCCESS) {
67797c478bd9Sstevel@tonic-gate 					if (scf_error() == SCF_ERROR_DELETED)
67807c478bd9Sstevel@tonic-gate 						continue;
67817c478bd9Sstevel@tonic-gate 					ret = scf_error();
67827c478bd9Sstevel@tonic-gate 					goto error;
67837c478bd9Sstevel@tonic-gate 				}
67847c478bd9Sstevel@tonic-gate 
67857c478bd9Sstevel@tonic-gate 				if (scf_property_get_value(prop, value) !=
67867c478bd9Sstevel@tonic-gate 				    SCF_SUCCESS)
67877c478bd9Sstevel@tonic-gate 					continue;
67887c478bd9Sstevel@tonic-gate 
67897c478bd9Sstevel@tonic-gate 				if (scf_value_get_astring(value,
67907c478bd9Sstevel@tonic-gate 				    fmri + sizeof (LEGACY_SCHEME) - 1,
67917c478bd9Sstevel@tonic-gate 				    max_fmri_length + 2 -
67927c478bd9Sstevel@tonic-gate 				    sizeof (LEGACY_SCHEME)) <= 0)
67937c478bd9Sstevel@tonic-gate 					continue;
67947c478bd9Sstevel@tonic-gate 
67957c478bd9Sstevel@tonic-gate 				if (scf_pg_get_name(pg, pgname,
67967c478bd9Sstevel@tonic-gate 				    max_name_length + 1) <= 0) {
67977c478bd9Sstevel@tonic-gate 					if (scf_error() == SCF_ERROR_DELETED)
67987c478bd9Sstevel@tonic-gate 						continue;
67997c478bd9Sstevel@tonic-gate 					ret = scf_error();
68007c478bd9Sstevel@tonic-gate 					goto error;
68017c478bd9Sstevel@tonic-gate 				}
68027c478bd9Sstevel@tonic-gate 
68037c478bd9Sstevel@tonic-gate 				if (argc == 0) {
68047c478bd9Sstevel@tonic-gate 					info.fmri = fmri;
68057c478bd9Sstevel@tonic-gate 					info.scope = scope;
68067c478bd9Sstevel@tonic-gate 					info.svc = NULL;
68077c478bd9Sstevel@tonic-gate 					info.inst = NULL;
68087c478bd9Sstevel@tonic-gate 					info.pg = pg;
68097c478bd9Sstevel@tonic-gate 					info.prop = NULL;
68107c478bd9Sstevel@tonic-gate 					if ((ret = callback(data, &info)) != 0)
68117c478bd9Sstevel@tonic-gate 						goto error;
68127c478bd9Sstevel@tonic-gate 				} else if ((ret = scf_pattern_match(htable,
68137c478bd9Sstevel@tonic-gate 				    fmri, pgname, argc, pattern,
68147c478bd9Sstevel@tonic-gate 				    flags & SCF_WALK_EXPLICIT)) != 0)
68157c478bd9Sstevel@tonic-gate 					goto error;
68167c478bd9Sstevel@tonic-gate 			}
68177c478bd9Sstevel@tonic-gate 
68187c478bd9Sstevel@tonic-gate 		}
68197c478bd9Sstevel@tonic-gate 	}
68207c478bd9Sstevel@tonic-gate nolegacy:
68217c478bd9Sstevel@tonic-gate 	ret = 0;
68227c478bd9Sstevel@tonic-gate 
68237c478bd9Sstevel@tonic-gate 	if (argc == 0)
68247c478bd9Sstevel@tonic-gate 		goto error;
68257c478bd9Sstevel@tonic-gate 
68267c478bd9Sstevel@tonic-gate 	/*
68277c478bd9Sstevel@tonic-gate 	 * Check all patterns, and see if we have that any that didn't match
68287c478bd9Sstevel@tonic-gate 	 * or any that matched multiple instances.  For svcprop, add up the
68297c478bd9Sstevel@tonic-gate 	 * total number of matching keys.
68307c478bd9Sstevel@tonic-gate 	 */
68317c478bd9Sstevel@tonic-gate 	info.count = 0;
68327c478bd9Sstevel@tonic-gate 	for (i = 0; i < argc; i++) {
68337c478bd9Sstevel@tonic-gate 		scf_match_t *match;
68347c478bd9Sstevel@tonic-gate 
68357c478bd9Sstevel@tonic-gate 		if (pattern[i].sp_type == PATTERN_INVALID)
68367c478bd9Sstevel@tonic-gate 			continue;
68377c478bd9Sstevel@tonic-gate 		if (pattern[i].sp_matchcount == 0) {
68387c478bd9Sstevel@tonic-gate 			scf_msg_t msgid;
68397c478bd9Sstevel@tonic-gate 			/*
68407c478bd9Sstevel@tonic-gate 			 * Provide a useful error message based on the argument
68417c478bd9Sstevel@tonic-gate 			 * and the type of entity requested.
68427c478bd9Sstevel@tonic-gate 			 */
68437c478bd9Sstevel@tonic-gate 			if (!(flags & SCF_WALK_LEGACY) &&
68447c478bd9Sstevel@tonic-gate 			    strncmp(pattern[i].sp_arg, "lrc:/", 5) == 0)
68457c478bd9Sstevel@tonic-gate 				msgid = SCF_MSG_PATTERN_LEGACY;
68467c478bd9Sstevel@tonic-gate 			else if (flags & SCF_WALK_PROPERTY)
68477c478bd9Sstevel@tonic-gate 				msgid = SCF_MSG_PATTERN_NOENTITY;
68487c478bd9Sstevel@tonic-gate 			else if (flags & SCF_WALK_NOINSTANCE)
68497c478bd9Sstevel@tonic-gate 				msgid = SCF_MSG_PATTERN_NOSERVICE;
68507c478bd9Sstevel@tonic-gate 			else if (flags & SCF_WALK_SERVICE)
68517c478bd9Sstevel@tonic-gate 				msgid = SCF_MSG_PATTERN_NOINSTSVC;
68527c478bd9Sstevel@tonic-gate 			else
68537c478bd9Sstevel@tonic-gate 				msgid = SCF_MSG_PATTERN_NOINSTANCE;
68547c478bd9Sstevel@tonic-gate 
68557c478bd9Sstevel@tonic-gate 			errfunc(scf_get_msg(msgid), pattern[i].sp_arg);
68567c478bd9Sstevel@tonic-gate 			if (err)
68577c478bd9Sstevel@tonic-gate 				*err = UU_EXIT_FATAL;
68587c478bd9Sstevel@tonic-gate 		} else if (!(flags & SCF_WALK_MULTIPLE) &&
68597c478bd9Sstevel@tonic-gate 		    pattern[i].sp_matchcount > 1) {
68607c478bd9Sstevel@tonic-gate 			char *msg;
68617c478bd9Sstevel@tonic-gate 
6862ad3ad82aSAndy Fiddaman 			msg = scf_multiple_match_error(&pattern[i],
6863ad3ad82aSAndy Fiddaman 			    scf_get_msg(SCF_MSG_PATTERN_MULTIMATCH));
6864ad3ad82aSAndy Fiddaman 
6865ad3ad82aSAndy Fiddaman 			if (msg == NULL) {
68667c478bd9Sstevel@tonic-gate 				ret = SCF_ERROR_NO_MEMORY;
68677c478bd9Sstevel@tonic-gate 				goto error;
68687c478bd9Sstevel@tonic-gate 			}
68697c478bd9Sstevel@tonic-gate 
6870ad3ad82aSAndy Fiddaman 			errfunc(msg);
6871ad3ad82aSAndy Fiddaman 
6872ad3ad82aSAndy Fiddaman 			if (err != NULL)
6873ad3ad82aSAndy Fiddaman 				*err = UU_EXIT_FATAL;
6874ad3ad82aSAndy Fiddaman 
6875ad3ad82aSAndy Fiddaman 			free(msg);
6876ad3ad82aSAndy Fiddaman 
6877ad3ad82aSAndy Fiddaman 			/*
6878ad3ad82aSAndy Fiddaman 			 * Set matchcount to 0 so the callback is not
6879ad3ad82aSAndy Fiddaman 			 * performed for this pattern.
6880ad3ad82aSAndy Fiddaman 			 */
6881ad3ad82aSAndy Fiddaman 			pattern[i].sp_matchcount = 0;
6882ad3ad82aSAndy Fiddaman 
6883ad3ad82aSAndy Fiddaman 		} else if ((flags & SCF_WALK_UNIPARTIAL) &&
6884ad3ad82aSAndy Fiddaman 		    pattern[i].sp_type == PATTERN_PARTIAL &&
6885ad3ad82aSAndy Fiddaman 		    pattern[i].sp_matchcount > 1) {
6886ad3ad82aSAndy Fiddaman 			char *msg;
6887ad3ad82aSAndy Fiddaman 
6888ad3ad82aSAndy Fiddaman 			msg = scf_multiple_match_error(&pattern[i],
6889ad3ad82aSAndy Fiddaman 			    scf_get_msg(SCF_MSG_PATTERN_MULTIPARTIAL));
6890ad3ad82aSAndy Fiddaman 
6891ad3ad82aSAndy Fiddaman 			if (msg == NULL) {
6892ad3ad82aSAndy Fiddaman 				ret = SCF_ERROR_NO_MEMORY;
6893ad3ad82aSAndy Fiddaman 				goto error;
68947c478bd9Sstevel@tonic-gate 			}
68957c478bd9Sstevel@tonic-gate 
68967c478bd9Sstevel@tonic-gate 			errfunc(msg);
6897ad3ad82aSAndy Fiddaman 
68987c478bd9Sstevel@tonic-gate 			if (err != NULL)
68997c478bd9Sstevel@tonic-gate 				*err = UU_EXIT_FATAL;
69007c478bd9Sstevel@tonic-gate 
69017c478bd9Sstevel@tonic-gate 			free(msg);
6902ad3ad82aSAndy Fiddaman 
6903ad3ad82aSAndy Fiddaman 			/*
6904ad3ad82aSAndy Fiddaman 			 * Set matchcount to 0 so the callback is not
6905ad3ad82aSAndy Fiddaman 			 * performed for this pattern.
6906ad3ad82aSAndy Fiddaman 			 */
6907ad3ad82aSAndy Fiddaman 			pattern[i].sp_matchcount = 0;
6908ad3ad82aSAndy Fiddaman 
69097c478bd9Sstevel@tonic-gate 		} else {
69107c478bd9Sstevel@tonic-gate 			for (match = pattern[i].sp_matches; match != NULL;
69117c478bd9Sstevel@tonic-gate 			    match = match->sm_next) {
69127c478bd9Sstevel@tonic-gate 				if (!match->sm_key->sk_seen)
69137c478bd9Sstevel@tonic-gate 					info.count++;
69147c478bd9Sstevel@tonic-gate 				match->sm_key->sk_seen = 1;
69157c478bd9Sstevel@tonic-gate 			}
69167c478bd9Sstevel@tonic-gate 		}
69177c478bd9Sstevel@tonic-gate 	}
69187c478bd9Sstevel@tonic-gate 
69197c478bd9Sstevel@tonic-gate 	/*
69207c478bd9Sstevel@tonic-gate 	 * Clear 'sk_seen' for all keys.
69217c478bd9Sstevel@tonic-gate 	 */
69227c478bd9Sstevel@tonic-gate 	for (i = 0; i < WALK_HTABLE_SIZE; i++) {
69237c478bd9Sstevel@tonic-gate 		scf_matchkey_t *key;
69247c478bd9Sstevel@tonic-gate 		for (key = htable[i]; key != NULL; key = key->sk_next)
69257c478bd9Sstevel@tonic-gate 			key->sk_seen = 0;
69267c478bd9Sstevel@tonic-gate 	}
69277c478bd9Sstevel@tonic-gate 
69287c478bd9Sstevel@tonic-gate 	/*
69297c478bd9Sstevel@tonic-gate 	 * Iterate over all the FMRIs in our hash table and execute the
69307c478bd9Sstevel@tonic-gate 	 * callback.
69317c478bd9Sstevel@tonic-gate 	 */
69327c478bd9Sstevel@tonic-gate 	for (i = 0; i < argc; i++) {
69337c478bd9Sstevel@tonic-gate 		scf_match_t *match;
69347c478bd9Sstevel@tonic-gate 		scf_matchkey_t *key;
69357c478bd9Sstevel@tonic-gate 
69367c478bd9Sstevel@tonic-gate 		/*
6937ad3ad82aSAndy Fiddaman 		 * Ignore patterns which didn't match anything or
6938ad3ad82aSAndy Fiddaman 		 * for which the matchcount has been set to 0 due to an
6939ad3ad82aSAndy Fiddaman 		 * error detected above.
69407c478bd9Sstevel@tonic-gate 		 */
6941ad3ad82aSAndy Fiddaman 		if (pattern[i].sp_matchcount == 0)
69427c478bd9Sstevel@tonic-gate 			continue;
69437c478bd9Sstevel@tonic-gate 
69447c478bd9Sstevel@tonic-gate 		for (match = pattern[i].sp_matches; match != NULL;
69457c478bd9Sstevel@tonic-gate 		    match = match->sm_next) {
69467c478bd9Sstevel@tonic-gate 
69477c478bd9Sstevel@tonic-gate 			key = match->sm_key;
69487c478bd9Sstevel@tonic-gate 			if (key->sk_seen)
69497c478bd9Sstevel@tonic-gate 				continue;
69507c478bd9Sstevel@tonic-gate 
69517c478bd9Sstevel@tonic-gate 			key->sk_seen = 1;
69527c478bd9Sstevel@tonic-gate 
69537c478bd9Sstevel@tonic-gate 			if (key->sk_legacy != NULL) {
69547c478bd9Sstevel@tonic-gate 				if (scf_scope_get_service(scope,
69557c478bd9Sstevel@tonic-gate 				    "smf/legacy_run", svc) != 0) {
69567c478bd9Sstevel@tonic-gate 					ret = scf_error();
69577c478bd9Sstevel@tonic-gate 					goto error;
69587c478bd9Sstevel@tonic-gate 				}
69597c478bd9Sstevel@tonic-gate 
69607c478bd9Sstevel@tonic-gate 				if (scf_service_get_pg(svc, key->sk_legacy,
69617c478bd9Sstevel@tonic-gate 				    pg) != 0)
69627c478bd9Sstevel@tonic-gate 					continue;
69637c478bd9Sstevel@tonic-gate 
69647c478bd9Sstevel@tonic-gate 				info.fmri = key->sk_fmri;
69657c478bd9Sstevel@tonic-gate 				info.scope = scope;
69667c478bd9Sstevel@tonic-gate 				info.svc = NULL;
69677c478bd9Sstevel@tonic-gate 				info.inst = NULL;
69687c478bd9Sstevel@tonic-gate 				info.pg = pg;
69697c478bd9Sstevel@tonic-gate 				info.prop = NULL;
69707c478bd9Sstevel@tonic-gate 				if ((ret = callback(data, &info)) != 0)
69717c478bd9Sstevel@tonic-gate 					goto error;
69727c478bd9Sstevel@tonic-gate 			} else {
69737c478bd9Sstevel@tonic-gate 				if (scf_handle_decode_fmri(h, key->sk_fmri,
69747c478bd9Sstevel@tonic-gate 				    scope, svc, inst, pg, prop, 0) !=
69757c478bd9Sstevel@tonic-gate 				    SCF_SUCCESS)
69767c478bd9Sstevel@tonic-gate 					continue;
69777c478bd9Sstevel@tonic-gate 
69787c478bd9Sstevel@tonic-gate 				info.fmri = key->sk_fmri;
69797c478bd9Sstevel@tonic-gate 				info.scope = scope;
69807c478bd9Sstevel@tonic-gate 				info.svc = svc;
69817c478bd9Sstevel@tonic-gate 				if (scf_instance_get_name(inst, NULL, 0) < 0) {
69827c478bd9Sstevel@tonic-gate 					if (scf_error() ==
69837c478bd9Sstevel@tonic-gate 					    SCF_ERROR_CONNECTION_BROKEN) {
69847c478bd9Sstevel@tonic-gate 						ret = scf_error();
69857c478bd9Sstevel@tonic-gate 						goto error;
69867c478bd9Sstevel@tonic-gate 					}
69877c478bd9Sstevel@tonic-gate 					info.inst = NULL;
69887c478bd9Sstevel@tonic-gate 				} else {
69897c478bd9Sstevel@tonic-gate 					info.inst = inst;
69907c478bd9Sstevel@tonic-gate 				}
69917c478bd9Sstevel@tonic-gate 				if (scf_pg_get_name(pg, NULL, 0) < 0) {
69927c478bd9Sstevel@tonic-gate 					if (scf_error() ==
69937c478bd9Sstevel@tonic-gate 					    SCF_ERROR_CONNECTION_BROKEN) {
69947c478bd9Sstevel@tonic-gate 						ret = scf_error();
69957c478bd9Sstevel@tonic-gate 						goto error;
69967c478bd9Sstevel@tonic-gate 					}
69977c478bd9Sstevel@tonic-gate 					info.pg = NULL;
69987c478bd9Sstevel@tonic-gate 				} else {
69997c478bd9Sstevel@tonic-gate 					info.pg = pg;
70007c478bd9Sstevel@tonic-gate 				}
70017c478bd9Sstevel@tonic-gate 				if (scf_property_get_name(prop, NULL, 0) < 0) {
70027c478bd9Sstevel@tonic-gate 					if (scf_error() ==
70037c478bd9Sstevel@tonic-gate 					    SCF_ERROR_CONNECTION_BROKEN) {
70047c478bd9Sstevel@tonic-gate 						ret = scf_error();
70057c478bd9Sstevel@tonic-gate 						goto error;
70067c478bd9Sstevel@tonic-gate 					}
70077c478bd9Sstevel@tonic-gate 					info.prop = NULL;
70087c478bd9Sstevel@tonic-gate 				} else {
70097c478bd9Sstevel@tonic-gate 					info.prop = prop;
70107c478bd9Sstevel@tonic-gate 				}
70117c478bd9Sstevel@tonic-gate 
70127c478bd9Sstevel@tonic-gate 				if ((ret = callback(data, &info)) != 0)
70137c478bd9Sstevel@tonic-gate 					goto error;
70147c478bd9Sstevel@tonic-gate 			}
70157c478bd9Sstevel@tonic-gate 		}
70167c478bd9Sstevel@tonic-gate 	}
70177c478bd9Sstevel@tonic-gate 
70187c478bd9Sstevel@tonic-gate error:
70197c478bd9Sstevel@tonic-gate 	if (htable) {
70207c478bd9Sstevel@tonic-gate 		scf_matchkey_t *key, *next;
70217c478bd9Sstevel@tonic-gate 
70227c478bd9Sstevel@tonic-gate 		for (i = 0; i < WALK_HTABLE_SIZE; i++) {
70237c478bd9Sstevel@tonic-gate 
70247c478bd9Sstevel@tonic-gate 			for (key = htable[i]; key != NULL;
70257c478bd9Sstevel@tonic-gate 			    key = next) {
70267c478bd9Sstevel@tonic-gate 
70277c478bd9Sstevel@tonic-gate 				next = key->sk_next;
70287c478bd9Sstevel@tonic-gate 
70297c478bd9Sstevel@tonic-gate 				if (key->sk_fmri != NULL)
70307c478bd9Sstevel@tonic-gate 					free(key->sk_fmri);
70317c478bd9Sstevel@tonic-gate 				if (key->sk_legacy != NULL)
70327c478bd9Sstevel@tonic-gate 					free(key->sk_legacy);
70337c478bd9Sstevel@tonic-gate 				free(key);
70347c478bd9Sstevel@tonic-gate 			}
70357c478bd9Sstevel@tonic-gate 		}
70367c478bd9Sstevel@tonic-gate 		free(htable);
70377c478bd9Sstevel@tonic-gate 	}
70387c478bd9Sstevel@tonic-gate 	if (pattern != NULL) {
70397c478bd9Sstevel@tonic-gate 		for (i = 0; i < argc; i++) {
70407c478bd9Sstevel@tonic-gate 			scf_match_t *match, *next;
70417c478bd9Sstevel@tonic-gate 
70427c478bd9Sstevel@tonic-gate 			if (pattern[i].sp_arg != NULL)
70437c478bd9Sstevel@tonic-gate 				free(pattern[i].sp_arg);
70447c478bd9Sstevel@tonic-gate 
70457c478bd9Sstevel@tonic-gate 			for (match = pattern[i].sp_matches; match != NULL;
70467c478bd9Sstevel@tonic-gate 			    match = next) {
70477c478bd9Sstevel@tonic-gate 
70487c478bd9Sstevel@tonic-gate 				next = match->sm_next;
70497c478bd9Sstevel@tonic-gate 
70507c478bd9Sstevel@tonic-gate 				free(match);
70517c478bd9Sstevel@tonic-gate 			}
70527c478bd9Sstevel@tonic-gate 		}
70537c478bd9Sstevel@tonic-gate 		free(pattern);
70547c478bd9Sstevel@tonic-gate 	}
70557c478bd9Sstevel@tonic-gate 
70567c478bd9Sstevel@tonic-gate 	free(fmri);
70577c478bd9Sstevel@tonic-gate 	free(pgname);
70587c478bd9Sstevel@tonic-gate 
70597c478bd9Sstevel@tonic-gate 	scf_value_destroy(value);
70607c478bd9Sstevel@tonic-gate 	scf_property_destroy(prop);
70617c478bd9Sstevel@tonic-gate 	scf_pg_destroy(pg);
70627c478bd9Sstevel@tonic-gate 	scf_scope_destroy(scope);
70637c478bd9Sstevel@tonic-gate 	scf_iter_destroy(siter);
70647c478bd9Sstevel@tonic-gate 	scf_iter_destroy(sciter);
70657c478bd9Sstevel@tonic-gate 	scf_iter_destroy(iter);
70667c478bd9Sstevel@tonic-gate 	scf_instance_destroy(inst);
70677c478bd9Sstevel@tonic-gate 	scf_service_destroy(svc);
70687c478bd9Sstevel@tonic-gate 
70697c478bd9Sstevel@tonic-gate 	return (ret);
70707c478bd9Sstevel@tonic-gate }
70717c478bd9Sstevel@tonic-gate 
70721f6eb021SLiane Praza /*
70731f6eb021SLiane Praza  * scf_encode32() is an implementation of Base32 encoding as described in
70741f6eb021SLiane Praza  * section 6 of RFC 4648 - "The Base16, Base32, and Base64 Data
70751f6eb021SLiane Praza  * Encodings". See http://www.ietf.org/rfc/rfc4648.txt?number=4648.  The
70761f6eb021SLiane Praza  * input stream is divided into groups of 5 characters (40 bits).  Each
70771f6eb021SLiane Praza  * group is encoded into 8 output characters where each output character
70781f6eb021SLiane Praza  * represents 5 bits of input.
70791f6eb021SLiane Praza  *
70801f6eb021SLiane Praza  * If the input is not an even multiple of 5 characters, the output will be
70811f6eb021SLiane Praza  * padded so that the output is an even multiple of 8 characters.  The
70821f6eb021SLiane Praza  * standard specifies that the pad character is '='.  Unfortunately, '=' is
70831f6eb021SLiane Praza  * not a legal character in SMF property names.  Thus, the caller can
70841f6eb021SLiane Praza  * specify an alternate pad character with the pad argument.  If pad is 0,
70851f6eb021SLiane Praza  * scf_encode32() will use '='.  Note that use of anything other than '='
70861f6eb021SLiane Praza  * produces output that is not in conformance with RFC 4648.  It is
70871f6eb021SLiane Praza  * suitable, however, for internal use of SMF software.  When the encoded
70881f6eb021SLiane Praza  * data is used as part of an SMF property name, SCF_ENCODE32_PAD should be
70891f6eb021SLiane Praza  * used as the pad character.
70901f6eb021SLiane Praza  *
70911f6eb021SLiane Praza  * Arguments:
70921f6eb021SLiane Praza  *	input -		Address of the buffer to be encoded.
70931f6eb021SLiane Praza  *	inlen -		Number of characters at input.
70941f6eb021SLiane Praza  *	output -	Address of the buffer to receive the encoded data.
70951f6eb021SLiane Praza  *	outmax -	Size of the buffer at output.
70961f6eb021SLiane Praza  *	outlen -	If it is not NULL, outlen receives the number of
70971f6eb021SLiane Praza  *			bytes placed in output.
70981f6eb021SLiane Praza  *	pad -		Alternate padding character.
70991f6eb021SLiane Praza  *
71001f6eb021SLiane Praza  * Returns:
71011f6eb021SLiane Praza  *	0	Buffer was successfully encoded.
71021f6eb021SLiane Praza  *	-1	Indicates output buffer too small, or pad is one of the
71031f6eb021SLiane Praza  *		standard encoding characters.
71041f6eb021SLiane Praza  */
71051f6eb021SLiane Praza int
scf_encode32(const char * input,size_t inlen,char * output,size_t outmax,size_t * outlen,char pad)71061f6eb021SLiane Praza scf_encode32(const char *input, size_t inlen, char *output, size_t outmax,
71071f6eb021SLiane Praza     size_t *outlen, char pad)
71081f6eb021SLiane Praza {
71091f6eb021SLiane Praza 	uint_t group_size = 5;
71101f6eb021SLiane Praza 	uint_t i;
71111f6eb021SLiane Praza 	const unsigned char *in = (const unsigned char *)input;
71121f6eb021SLiane Praza 	size_t olen;
71131f6eb021SLiane Praza 	uchar_t *out = (uchar_t *)output;
71141f6eb021SLiane Praza 	uint_t oval;
71151f6eb021SLiane Praza 	uint_t pad_count;
71161f6eb021SLiane Praza 
71171f6eb021SLiane Praza 	/* Verify that there is enough room for the output. */
71181f6eb021SLiane Praza 	olen = ((inlen + (group_size - 1)) / group_size) * 8;
71191f6eb021SLiane Praza 	if (outlen)
71201f6eb021SLiane Praza 		*outlen = olen;
71211f6eb021SLiane Praza 	if (olen > outmax)
71221f6eb021SLiane Praza 		return (-1);
71231f6eb021SLiane Praza 
71241f6eb021SLiane Praza 	/* If caller did not provide pad character, use the default. */
71251f6eb021SLiane Praza 	if (pad == 0) {
71261f6eb021SLiane Praza 		pad = '=';
71271f6eb021SLiane Praza 	} else {
71281f6eb021SLiane Praza 		/*
71291f6eb021SLiane Praza 		 * Make sure that caller's pad is not one of the encoding
71301f6eb021SLiane Praza 		 * characters.
71311f6eb021SLiane Praza 		 */
71321f6eb021SLiane Praza 		for (i = 0; i < sizeof (base32) - 1; i++) {
71331f6eb021SLiane Praza 			if (pad == base32[i])
71341f6eb021SLiane Praza 				return (-1);
71351f6eb021SLiane Praza 		}
71361f6eb021SLiane Praza 	}
71371f6eb021SLiane Praza 
71381f6eb021SLiane Praza 	/* Process full groups capturing 5 bits per output character. */
71391f6eb021SLiane Praza 	for (; inlen >= group_size; in += group_size, inlen -= group_size) {
71401f6eb021SLiane Praza 		/*
71411f6eb021SLiane Praza 		 * The comments in this section number the bits in an
71421f6eb021SLiane Praza 		 * 8 bit byte 0 to 7.  The high order bit is bit 7 and
71431f6eb021SLiane Praza 		 * the low order bit is bit 0.
71441f6eb021SLiane Praza 		 */
71451f6eb021SLiane Praza 
71461f6eb021SLiane Praza 		/* top 5 bits (7-3) from in[0] */
71471f6eb021SLiane Praza 		*out++ = base32[in[0] >> 3];
71481f6eb021SLiane Praza 		/* bits 2-0 from in[0] and top 2 (7-6) from in[1] */
71491f6eb021SLiane Praza 		*out++ = base32[((in[0] << 2) & 0x1c) | (in[1] >> 6)];
71501f6eb021SLiane Praza 		/* 5 bits (5-1) from in[1] */
71511f6eb021SLiane Praza 		*out++ = base32[(in[1] >> 1) & 0x1f];
71521f6eb021SLiane Praza 		/* low bit (0) from in[1] and top 4 (7-4) from in[2] */
71531f6eb021SLiane Praza 		*out++ = base32[((in[1] << 4) & 0x10) | ((in[2] >> 4) & 0xf)];
71541f6eb021SLiane Praza 		/* low 4 (3-0) from in[2] and top bit (7) from in[3] */
71551f6eb021SLiane Praza 		*out++ = base32[((in[2] << 1) & 0x1e) | (in[3] >> 7)];
71561f6eb021SLiane Praza 		/* 5 bits (6-2) from in[3] */
71571f6eb021SLiane Praza 		*out++ = base32[(in[3] >> 2) & 0x1f];
71581f6eb021SLiane Praza 		/* low 2 (1-0) from in[3] and top 3 (7-5) from in[4] */
71591f6eb021SLiane Praza 		*out++ = base32[((in[3] << 3) & 0x18) | (in[4] >> 5)];
71601f6eb021SLiane Praza 		/* low 5 (4-0) from in[4] */
71611f6eb021SLiane Praza 		*out++ = base32[in[4] & 0x1f];
71621f6eb021SLiane Praza 	}
71631f6eb021SLiane Praza 
71641f6eb021SLiane Praza 	/* Take care of final input bytes. */
71651f6eb021SLiane Praza 	pad_count = 0;
71661f6eb021SLiane Praza 	if (inlen) {
71671f6eb021SLiane Praza 		/* top 5 bits (7-3) from in[0] */
71681f6eb021SLiane Praza 		*out++ = base32[in[0] >> 3];
71691f6eb021SLiane Praza 		/*
71701f6eb021SLiane Praza 		 * low 3 (2-0) from in[0] and top 2 (7-6) from in[1] if
71711f6eb021SLiane Praza 		 * available.
71721f6eb021SLiane Praza 		 */
71731f6eb021SLiane Praza 		oval = (in[0] << 2) & 0x1c;
71741f6eb021SLiane Praza 		if (inlen == 1) {
71751f6eb021SLiane Praza 			*out++ = base32[oval];
71761f6eb021SLiane Praza 			pad_count = 6;
71771f6eb021SLiane Praza 			goto padout;
71781f6eb021SLiane Praza 		}
71791f6eb021SLiane Praza 		oval |= in[1] >> 6;
71801f6eb021SLiane Praza 		*out++ = base32[oval];
71811f6eb021SLiane Praza 		/* 5 bits (5-1) from in[1] */
71821f6eb021SLiane Praza 		*out++ = base32[(in[1] >> 1) & 0x1f];
71831f6eb021SLiane Praza 		/*
71841f6eb021SLiane Praza 		 * low bit (0) from in[1] and top 4 (7-4) from in[2] if
71851f6eb021SLiane Praza 		 * available.
71861f6eb021SLiane Praza 		 */
71871f6eb021SLiane Praza 		oval = (in[1] << 4) & 0x10;
71881f6eb021SLiane Praza 		if (inlen == 2) {
71891f6eb021SLiane Praza 			*out++ = base32[oval];
71901f6eb021SLiane Praza 			pad_count = 4;
71911f6eb021SLiane Praza 			goto padout;
71921f6eb021SLiane Praza 		}
71931f6eb021SLiane Praza 		oval |= in[2] >> 4;
71941f6eb021SLiane Praza 		*out++ = base32[oval];
71951f6eb021SLiane Praza 		/*
71961f6eb021SLiane Praza 		 * low 4 (3-0) from in[2] and top 1 (7) from in[3] if
71971f6eb021SLiane Praza 		 * available.
71981f6eb021SLiane Praza 		 */
71991f6eb021SLiane Praza 		oval = (in[2] << 1) & 0x1e;
72001f6eb021SLiane Praza 		if (inlen == 3) {
72011f6eb021SLiane Praza 			*out++ = base32[oval];
72021f6eb021SLiane Praza 			pad_count = 3;
72031f6eb021SLiane Praza 			goto padout;
72041f6eb021SLiane Praza 		}
72051f6eb021SLiane Praza 		oval |= in[3] >> 7;
72061f6eb021SLiane Praza 		*out++ = base32[oval];
72071f6eb021SLiane Praza 		/* 5 bits (6-2) from in[3] */
72081f6eb021SLiane Praza 		*out++ = base32[(in[3] >> 2) & 0x1f];
72091f6eb021SLiane Praza 		/* low 2 bits (1-0) from in[3] */
72101f6eb021SLiane Praza 		*out++ = base32[(in[3] << 3) & 0x18];
72111f6eb021SLiane Praza 		pad_count = 1;
72121f6eb021SLiane Praza 	}
72131f6eb021SLiane Praza padout:
72141f6eb021SLiane Praza 	/*
72151f6eb021SLiane Praza 	 * Pad the output so that it is a multiple of 8 bytes.
72161f6eb021SLiane Praza 	 */
72171f6eb021SLiane Praza 	for (; pad_count > 0; pad_count--) {
72181f6eb021SLiane Praza 		*out++ = pad;
72191f6eb021SLiane Praza 	}
72201f6eb021SLiane Praza 
72211f6eb021SLiane Praza 	/*
72221f6eb021SLiane Praza 	 * Null terminate the output if there is enough room.
72231f6eb021SLiane Praza 	 */
72241f6eb021SLiane Praza 	if (olen < outmax)
72251f6eb021SLiane Praza 		*out = 0;
72261f6eb021SLiane Praza 
72271f6eb021SLiane Praza 	return (0);
72281f6eb021SLiane Praza }
72291f6eb021SLiane Praza 
72301f6eb021SLiane Praza /*
72311f6eb021SLiane Praza  * scf_decode32() is an implementation of Base32 decoding as described in
72321f6eb021SLiane Praza  * section 6 of RFC 4648 - "The Base16, Base32, and Base64 Data
72331f6eb021SLiane Praza  * Encodings". See http://www.ietf.org/rfc/rfc4648.txt?number=4648.  The
72341f6eb021SLiane Praza  * input stream is divided into groups of 8 encoded characters.  Each
72351f6eb021SLiane Praza  * encoded character represents 5 bits of data.  Thus, the 8 encoded
72361f6eb021SLiane Praza  * characters are used to produce 40 bits or 5 bytes of unencoded data in
72371f6eb021SLiane Praza  * outbuf.
72381f6eb021SLiane Praza  *
72391f6eb021SLiane Praza  * If the encoder did not have enough data to generate a mulitple of 8
72401f6eb021SLiane Praza  * characters of encoded data, it used a pad character to get to the 8
72411f6eb021SLiane Praza  * character boundry. The standard specifies that the pad character is '='.
72421f6eb021SLiane Praza  * Unfortunately, '=' is not a legal character in SMF property names.
72431f6eb021SLiane Praza  * Thus, the caller can specify an alternate pad character with the pad
72441f6eb021SLiane Praza  * argument.  If pad is 0, scf_decode32() will use '='.  Note that use of
72451f6eb021SLiane Praza  * anything other than '=' is not in conformance with RFC 4648.  It is
72461f6eb021SLiane Praza  * suitable, however, for internal use of SMF software.  When the encoded
72471f6eb021SLiane Praza  * data is used in SMF property names, SCF_ENCODE32_PAD should be used as
72481f6eb021SLiane Praza  * the pad character.
72491f6eb021SLiane Praza  *
72501f6eb021SLiane Praza  * Arguments:
72511f6eb021SLiane Praza  *	in -		Buffer of encoded characters.
72521f6eb021SLiane Praza  *	inlen -		Number of characters at in.
72531f6eb021SLiane Praza  *	outbuf -	Buffer to receive the decoded bytes.  It can be the
72541f6eb021SLiane Praza  *			same buffer as in.
72551f6eb021SLiane Praza  *	outmax -	Size of the buffer at outbuf.
72561f6eb021SLiane Praza  *	outlen -	If it is not NULL, outlen receives the number of
72571f6eb021SLiane Praza  *			bytes placed in output.
72581f6eb021SLiane Praza  *	pad -		Alternate padding character.
72591f6eb021SLiane Praza  *
72601f6eb021SLiane Praza  * Returns:
72611f6eb021SLiane Praza  *	0	Buffer was successfully decoded.
72621f6eb021SLiane Praza  *	-1	Indicates an invalid input character, output buffer too
72631f6eb021SLiane Praza  *		small, or pad is one of the standard encoding characters.
72641f6eb021SLiane Praza  */
72651f6eb021SLiane Praza int
scf_decode32(const char * in,size_t inlen,char * outbuf,size_t outmax,size_t * outlen,char pad)72661f6eb021SLiane Praza scf_decode32(const char *in, size_t inlen, char *outbuf, size_t outmax,
72671f6eb021SLiane Praza     size_t *outlen, char pad)
72681f6eb021SLiane Praza {
72691f6eb021SLiane Praza 	char *bufend = outbuf + outmax;
72701f6eb021SLiane Praza 	char c;
72711f6eb021SLiane Praza 	uint_t count;
72721f6eb021SLiane Praza 	uint32_t g[DECODE32_GS];
72731f6eb021SLiane Praza 	size_t i;
72741f6eb021SLiane Praza 	uint_t j;
72751f6eb021SLiane Praza 	char *out = outbuf;
72761f6eb021SLiane Praza 	boolean_t pad_seen = B_FALSE;
72771f6eb021SLiane Praza 
72781f6eb021SLiane Praza 	/* If caller did not provide pad character, use the default. */
72791f6eb021SLiane Praza 	if (pad == 0) {
72801f6eb021SLiane Praza 		pad = '=';
72811f6eb021SLiane Praza 	} else {
72821f6eb021SLiane Praza 		/*
72831f6eb021SLiane Praza 		 * Make sure that caller's pad is not one of the encoding
72841f6eb021SLiane Praza 		 * characters.
72851f6eb021SLiane Praza 		 */
72861f6eb021SLiane Praza 		for (i = 0; i < sizeof (base32) - 1; i++) {
72871f6eb021SLiane Praza 			if (pad == base32[i])
72881f6eb021SLiane Praza 				return (-1);
72891f6eb021SLiane Praza 		}
72901f6eb021SLiane Praza 	}
72911f6eb021SLiane Praza 
72921f6eb021SLiane Praza 	i = 0;
72931f6eb021SLiane Praza 	while ((i < inlen) && (out < bufend)) {
72941f6eb021SLiane Praza 		/* Get a group of input characters. */
72951f6eb021SLiane Praza 		for (j = 0, count = 0;
72961f6eb021SLiane Praza 		    (j < DECODE32_GS) && (i < inlen);
72971f6eb021SLiane Praza 		    i++) {
72981f6eb021SLiane Praza 			c = in[i];
72991f6eb021SLiane Praza 			/*
73001f6eb021SLiane Praza 			 * RFC 4648 allows for the encoded data to be split
73011f6eb021SLiane Praza 			 * into multiple lines, so skip carriage returns
73021f6eb021SLiane Praza 			 * and new lines.
73031f6eb021SLiane Praza 			 */
73041f6eb021SLiane Praza 			if ((c == '\r') || (c == '\n'))
73051f6eb021SLiane Praza 				continue;
73061f6eb021SLiane Praza 			if ((pad_seen == B_TRUE) && (c != pad)) {
73071f6eb021SLiane Praza 				/* Group not completed by pads */
73081f6eb021SLiane Praza 				return (-1);
73091f6eb021SLiane Praza 			}
73101f6eb021SLiane Praza 			if ((c < 0) || (c >= sizeof (index32))) {
73111f6eb021SLiane Praza 				/* Illegal character. */
73121f6eb021SLiane Praza 				return (-1);
73131f6eb021SLiane Praza 			}
73141f6eb021SLiane Praza 			if (c == pad) {
73151f6eb021SLiane Praza 				pad_seen = B_TRUE;
73161f6eb021SLiane Praza 				continue;
73171f6eb021SLiane Praza 			}
73181f6eb021SLiane Praza 			if ((g[j++] = index32[c]) == 0xff) {
73191f6eb021SLiane Praza 				/* Illegal character */
73201f6eb021SLiane Praza 				return (-1);
73211f6eb021SLiane Praza 			}
73221f6eb021SLiane Praza 			count++;
73231f6eb021SLiane Praza 		}
73241f6eb021SLiane Praza 
73251f6eb021SLiane Praza 		/* Pack the group into five 8 bit bytes. */
73261f6eb021SLiane Praza 		if ((count >= 2) && (out < bufend)) {
73271f6eb021SLiane Praza 			/*
73281f6eb021SLiane Praza 			 * Output byte 0:
73291f6eb021SLiane Praza 			 *	5 bits (7-3) from g[0]
73301f6eb021SLiane Praza 			 *	3 bits (2-0) from g[1] (4-2)
73311f6eb021SLiane Praza 			 */
73321f6eb021SLiane Praza 			*out++ = (g[0] << 3) | ((g[1] >> 2) & 0x7);
73331f6eb021SLiane Praza 		}
73341f6eb021SLiane Praza 		if ((count >= 4) && (out < bufend)) {
73351f6eb021SLiane Praza 			/*
73361f6eb021SLiane Praza 			 * Output byte 1:
73371f6eb021SLiane Praza 			 *	2 bits (7-6) from g[1] (1-0)
73381f6eb021SLiane Praza 			 *	5 bits (5-1) from g[2] (4-0)
73391f6eb021SLiane Praza 			 *	1 bit (0) from g[3] (4)
73401f6eb021SLiane Praza 			 */
73411f6eb021SLiane Praza 			*out++ = (g[1] << 6) | (g[2] << 1) | \
73421f6eb021SLiane Praza 			    ((g[3] >> 4) & 0x1);
73431f6eb021SLiane Praza 		}
73441f6eb021SLiane Praza 		if ((count >= 5) && (out < bufend)) {
73451f6eb021SLiane Praza 			/*
73461f6eb021SLiane Praza 			 * Output byte 2:
73471f6eb021SLiane Praza 			 *	4 bits (7-4) from g[3] (3-0)
73481f6eb021SLiane Praza 			 *	4 bits (3-0) from g[4] (4-1)
73491f6eb021SLiane Praza 			 */
73501f6eb021SLiane Praza 			*out++ = (g[3] << 4) | ((g[4] >> 1) & 0xf);
73511f6eb021SLiane Praza 		}
73521f6eb021SLiane Praza 		if ((count >= 7) && (out < bufend)) {
73531f6eb021SLiane Praza 			/*
73541f6eb021SLiane Praza 			 * Output byte 3:
73551f6eb021SLiane Praza 			 *	1 bit (7) from g[4] (0)
73561f6eb021SLiane Praza 			 *	5 bits (6-2) from g[5] (4-0)
73571f6eb021SLiane Praza 			 *	2 bits (0-1) from g[6] (4-3)
73581f6eb021SLiane Praza 			 */
73591f6eb021SLiane Praza 			*out++ = (g[4] << 7) | (g[5] << 2) |
73601f6eb021SLiane Praza 			    ((g[6] >> 3) & 0x3);
73611f6eb021SLiane Praza 		}
73621f6eb021SLiane Praza 		if ((count == 8) && (out < bufend)) {
73631f6eb021SLiane Praza 			/*
73641f6eb021SLiane Praza 			 * Output byte 4;
73651f6eb021SLiane Praza 			 *	3 bits (7-5) from g[6] (2-0)
73661f6eb021SLiane Praza 			 *	5 bits (4-0) from g[7] (4-0)
73671f6eb021SLiane Praza 			 */
73681f6eb021SLiane Praza 			*out++ = (g[6] << 5) | g[7];
73691f6eb021SLiane Praza 		}
73701f6eb021SLiane Praza 	}
73711f6eb021SLiane Praza 	if (i < inlen) {
73721f6eb021SLiane Praza 		/* Did not process all input characters. */
73731f6eb021SLiane Praza 		return (-1);
73741f6eb021SLiane Praza 	}
73751f6eb021SLiane Praza 	if (outlen)
73761f6eb021SLiane Praza 		*outlen = out - outbuf;
73771f6eb021SLiane Praza 	/* Null terminate the output if there is room. */
73781f6eb021SLiane Praza 	if (out < bufend)
73791f6eb021SLiane Praza 		*out = 0;
73801f6eb021SLiane Praza 	return (0);
73811f6eb021SLiane Praza }
73821f6eb021SLiane Praza 
73831f6eb021SLiane Praza 
73847c478bd9Sstevel@tonic-gate /*
73857c478bd9Sstevel@tonic-gate  * _scf_request_backup:  a simple wrapper routine
73867c478bd9Sstevel@tonic-gate  */
73877c478bd9Sstevel@tonic-gate int
_scf_request_backup(scf_handle_t * h,const char * name)73887c478bd9Sstevel@tonic-gate _scf_request_backup(scf_handle_t *h, const char *name)
73897c478bd9Sstevel@tonic-gate {
73907c478bd9Sstevel@tonic-gate 	struct rep_protocol_backup_request request;
73917c478bd9Sstevel@tonic-gate 	struct rep_protocol_response response;
73927c478bd9Sstevel@tonic-gate 
73937c478bd9Sstevel@tonic-gate 	int r;
73947c478bd9Sstevel@tonic-gate 
73957c478bd9Sstevel@tonic-gate 	if (strlcpy(request.rpr_name, name, sizeof (request.rpr_name)) >=
73967c478bd9Sstevel@tonic-gate 	    sizeof (request.rpr_name))
73977c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
73987c478bd9Sstevel@tonic-gate 
73997c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
74007c478bd9Sstevel@tonic-gate 	request.rpr_request = REP_PROTOCOL_BACKUP;
74018918dff3Sjwadams 	request.rpr_changeid = handle_next_changeid(h);
74027c478bd9Sstevel@tonic-gate 
74037c478bd9Sstevel@tonic-gate 	r = make_door_call(h, &request, sizeof (request),
74047c478bd9Sstevel@tonic-gate 	    &response, sizeof (response));
74057c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
74067c478bd9Sstevel@tonic-gate 
74077c478bd9Sstevel@tonic-gate 	if (r < 0) {
74087c478bd9Sstevel@tonic-gate 		DOOR_ERRORS_BLOCK(r);
74097c478bd9Sstevel@tonic-gate 	}
74107c478bd9Sstevel@tonic-gate 
74117c478bd9Sstevel@tonic-gate 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
74127c478bd9Sstevel@tonic-gate 		return (scf_set_error(proto_error(response.rpr_response)));
74137c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
74147c478bd9Sstevel@tonic-gate }
74153eae19d9Swesolows 
7416c0889d7aSstevep /*
7417c0889d7aSstevep  * Request svc.configd daemon to switch repository database.
7418c0889d7aSstevep  *
7419c0889d7aSstevep  * Can fail:
7420c0889d7aSstevep  *
7421c0889d7aSstevep  *	_NOT_BOUND		handle is not bound
7422c0889d7aSstevep  *	_CONNECTION_BROKEN	server is not reachable
7423c0889d7aSstevep  *	_INTERNAL		file operation error
7424c0889d7aSstevep  *				the server response is too big
7425c0889d7aSstevep  *	_PERMISSION_DENIED	not enough privileges to do request
7426c0889d7aSstevep  *	_BACKEND_READONLY	backend is not writable
7427c0889d7aSstevep  *	_BACKEND_ACCESS		backend access fails
7428c0889d7aSstevep  *	_NO_RESOURCES		svc.configd is out of memory
7429c0889d7aSstevep  */
7430c0889d7aSstevep int
_scf_repository_switch(scf_handle_t * h,int scf_sw)7431c0889d7aSstevep _scf_repository_switch(scf_handle_t *h, int scf_sw)
7432c0889d7aSstevep {
7433c0889d7aSstevep 	struct rep_protocol_switch_request request;
7434c0889d7aSstevep 	struct rep_protocol_response response;
7435c0889d7aSstevep 	int	r;
7436c0889d7aSstevep 
7437c0889d7aSstevep 	/*
7438c0889d7aSstevep 	 * Setup request protocol and make door call
7439c0889d7aSstevep 	 * Hold rh_lock lock before handle_next_changeid call
7440c0889d7aSstevep 	 */
7441c0889d7aSstevep 	(void) pthread_mutex_lock(&h->rh_lock);
7442c0889d7aSstevep 
7443c0889d7aSstevep 	request.rpr_flag = scf_sw;
7444c0889d7aSstevep 	request.rpr_request = REP_PROTOCOL_SWITCH;
7445c0889d7aSstevep 	request.rpr_changeid = handle_next_changeid(h);
7446c0889d7aSstevep 
7447c0889d7aSstevep 	r = make_door_call(h, &request, sizeof (request),
7448c0889d7aSstevep 	    &response, sizeof (response));
7449c0889d7aSstevep 
7450c0889d7aSstevep 	(void) pthread_mutex_unlock(&h->rh_lock);
7451c0889d7aSstevep 
7452c0889d7aSstevep 	if (r < 0) {
7453c0889d7aSstevep 		DOOR_ERRORS_BLOCK(r);
7454c0889d7aSstevep 	}
7455c0889d7aSstevep 
7456c0889d7aSstevep 	/*
7457c0889d7aSstevep 	 * Pass protocol error up
7458c0889d7aSstevep 	 */
7459c0889d7aSstevep 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
7460c0889d7aSstevep 		return (scf_set_error(proto_error(response.rpr_response)));
7461c0889d7aSstevep 
7462c0889d7aSstevep 	return (SCF_SUCCESS);
7463c0889d7aSstevep }
7464c0889d7aSstevep 
74653eae19d9Swesolows int
_scf_pg_is_read_protected(const scf_propertygroup_t * pg,boolean_t * out)74663eae19d9Swesolows _scf_pg_is_read_protected(const scf_propertygroup_t *pg, boolean_t *out)
74673eae19d9Swesolows {
74683eae19d9Swesolows 	char buf[REP_PROTOCOL_NAME_LEN];
74693eae19d9Swesolows 	ssize_t res;
74703eae19d9Swesolows 
74713eae19d9Swesolows 	res = datael_get_name(&pg->rd_d, buf, sizeof (buf),
74723eae19d9Swesolows 	    RP_ENTITY_NAME_PGREADPROT);
74733eae19d9Swesolows 
74743eae19d9Swesolows 	if (res == -1)
74753eae19d9Swesolows 		return (-1);
74763eae19d9Swesolows 
74773eae19d9Swesolows 	if (uu_strtouint(buf, out, sizeof (*out), 0, 0, 1) == -1)
74783eae19d9Swesolows 		return (scf_set_error(SCF_ERROR_INTERNAL));
74793eae19d9Swesolows 	return (SCF_SUCCESS);
74803eae19d9Swesolows }
74815b7f77adStw 
74825b7f77adStw /*
74835b7f77adStw  * _scf_set_annotation: a wrapper to set the annotation fields for SMF
74845b7f77adStw  * security auditing.
74855b7f77adStw  *
74865b7f77adStw  * Fails with following in scf_error_key thread specific data:
74875b7f77adStw  *	_INVALID_ARGUMENT - operation or file too large
74885b7f77adStw  *	_NOT_BOUND
74895b7f77adStw  *	_CONNECTION_BROKEN
74905b7f77adStw  *	_INTERNAL
74915b7f77adStw  *	_NO_RESOURCES
74925b7f77adStw  */
74935b7f77adStw int
_scf_set_annotation(scf_handle_t * h,const char * operation,const char * file)74945b7f77adStw _scf_set_annotation(scf_handle_t *h, const char *operation, const char *file)
74955b7f77adStw {
74965b7f77adStw 	struct rep_protocol_annotation request;
74975b7f77adStw 	struct rep_protocol_response response;
74985b7f77adStw 	size_t copied;
74995b7f77adStw 	int r;
75005b7f77adStw 
7501a4dc1477STom Whitten 	if (h == NULL) {
7502a4dc1477STom Whitten 		/* We can't do anything if the handle is destroyed. */
7503a4dc1477STom Whitten 		return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED));
7504a4dc1477STom Whitten 	}
7505a4dc1477STom Whitten 
75065b7f77adStw 	request.rpr_request = REP_PROTOCOL_SET_AUDIT_ANNOTATION;
75075b7f77adStw 	copied = strlcpy(request.rpr_operation,
75085b7f77adStw 	    (operation == NULL) ? "" : operation,
75095b7f77adStw 	    sizeof (request.rpr_operation));
75105b7f77adStw 	if (copied >= sizeof (request.rpr_operation))
75115b7f77adStw 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
75125b7f77adStw 
75135b7f77adStw 	copied = strlcpy(request.rpr_file,
75145b7f77adStw 	    (file == NULL) ? "" : file,
75155b7f77adStw 	    sizeof (request.rpr_file));
7516a4dc1477STom Whitten 	if (copied >= sizeof (request.rpr_file))
75175b7f77adStw 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
75185b7f77adStw 
75195b7f77adStw 	(void) pthread_mutex_lock(&h->rh_lock);
75205b7f77adStw 	r = make_door_call(h, &request, sizeof (request),
75215b7f77adStw 	    &response, sizeof (response));
75225b7f77adStw 	(void) pthread_mutex_unlock(&h->rh_lock);
75235b7f77adStw 
75245b7f77adStw 	if (r < 0) {
75255b7f77adStw 		DOOR_ERRORS_BLOCK(r);
75265b7f77adStw 	}
75275b7f77adStw 
75285b7f77adStw 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
75295b7f77adStw 		return (scf_set_error(proto_error(response.rpr_response)));
75305b7f77adStw 	return (0);
75315b7f77adStw }
7532