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.
27*ad3ad82aSAndy Fiddaman  * Copyright 2017 OmniOS Community Edition (OmniOSce) Association.
287c478bd9Sstevel@tonic-gate  */
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate /*
317c478bd9Sstevel@tonic-gate  * This is the main implementation file for the low-level repository
327c478bd9Sstevel@tonic-gate  * interface.
337c478bd9Sstevel@tonic-gate  */
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate #include "lowlevel_impl.h"
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate #include "repcache_protocol.h"
387c478bd9Sstevel@tonic-gate #include "scf_type.h"
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate #include <assert.h>
417c478bd9Sstevel@tonic-gate #include <alloca.h>
427c478bd9Sstevel@tonic-gate #include <door.h>
437c478bd9Sstevel@tonic-gate #include <errno.h>
447c478bd9Sstevel@tonic-gate #include <fcntl.h>
457c478bd9Sstevel@tonic-gate #include <fnmatch.h>
467c478bd9Sstevel@tonic-gate #include <libuutil.h>
477c478bd9Sstevel@tonic-gate #include <poll.h>
487c478bd9Sstevel@tonic-gate #include <pthread.h>
4953f3aea0SRoger A. Faulkner #include <synch.h>
507c478bd9Sstevel@tonic-gate #include <stddef.h>
517c478bd9Sstevel@tonic-gate #include <stdio.h>
527c478bd9Sstevel@tonic-gate #include <stdlib.h>
537c478bd9Sstevel@tonic-gate #include <string.h>
547c478bd9Sstevel@tonic-gate #include <sys/mman.h>
557c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
56048b0279SBryan Cantrill #include <libzonecfg.h>
577c478bd9Sstevel@tonic-gate #include <unistd.h>
58048b0279SBryan Cantrill #include <dlfcn.h>
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate #define	ENV_SCF_DEBUG		"LIBSCF_DEBUG"
617c478bd9Sstevel@tonic-gate #define	ENV_SCF_DOORPATH	"LIBSCF_DOORPATH"
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate static uint32_t default_debug = 0;
647c478bd9Sstevel@tonic-gate static const char *default_door_path = REPOSITORY_DOOR_NAME;
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate #define	CALL_FAILED		-1
677c478bd9Sstevel@tonic-gate #define	RESULT_TOO_BIG		-2
687c478bd9Sstevel@tonic-gate #define	NOT_BOUND		-3
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate static pthread_mutex_t	lowlevel_init_lock;
717c478bd9Sstevel@tonic-gate static int32_t		lowlevel_inited;
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate static uu_list_pool_t	*tran_entry_pool;
747c478bd9Sstevel@tonic-gate static uu_list_pool_t	*datael_pool;
757c478bd9Sstevel@tonic-gate static uu_list_pool_t	*iter_pool;
767c478bd9Sstevel@tonic-gate 
771f6eb021SLiane Praza /*
781f6eb021SLiane Praza  * base32[] index32[] are used in base32 encoding and decoding.
791f6eb021SLiane Praza  */
801f6eb021SLiane Praza static char base32[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
811f6eb021SLiane Praza static char index32[128] = {
821f6eb021SLiane Praza 	-1, -1, -1, -1, -1, -1, -1, -1,	/* 0-7 */
831f6eb021SLiane Praza 	-1, -1, -1, -1, -1, -1, -1, -1,	/* 8-15 */
841f6eb021SLiane Praza 	-1, -1, -1, -1, -1, -1, -1, -1,	/* 16-23 */
851f6eb021SLiane Praza 	-1, -1, -1, -1, -1, -1, -1, -1,	/* 24-31 */
861f6eb021SLiane Praza 	-1, -1, -1, -1, -1, -1, -1, -1,	/* 32-39 */
871f6eb021SLiane Praza 	-1, -1, -1, -1, -1, -1, -1, -1,	/* 40-47 */
881f6eb021SLiane Praza 	-1, -1, 26, 27, 28, 29, 30, 31,	/* 48-55 */
891f6eb021SLiane Praza 	-1, -1, -1, -1, -1, -1, -1, -1,	/* 56-63 */
901f6eb021SLiane Praza 	-1, 0, 1, 2, 3, 4, 5, 6,	/* 64-71 */
911f6eb021SLiane Praza 	7, 8, 9, 10, 11, 12, 13, 14,	/* 72-79 */
921f6eb021SLiane Praza 	15, 16, 17, 18, 19, 20, 21, 22,	/* 80-87 */
931f6eb021SLiane Praza 	23, 24, 25, -1, -1, -1, -1, -1,	/* 88-95 */
941f6eb021SLiane Praza 	-1, -1, -1, -1, -1, -1, -1, -1,	/* 96-103 */
951f6eb021SLiane Praza 	-1, -1, -1, -1, -1, -1, -1, -1,	/* 104-111 */
961f6eb021SLiane Praza 	-1, -1, -1, -1, -1, -1, -1, -1,	/* 112-119 */
971f6eb021SLiane Praza 	-1, -1, -1, -1, -1, -1, -1, -1	/* 120-127 */
981f6eb021SLiane Praza };
991f6eb021SLiane Praza 
1001f6eb021SLiane Praza #define	DECODE32_GS	(8)	/* scf_decode32 group size */
1011f6eb021SLiane Praza 
1027c478bd9Sstevel@tonic-gate #ifdef lint
1037c478bd9Sstevel@tonic-gate #define	assert_nolint(x) (void)0
1047c478bd9Sstevel@tonic-gate #else
1057c478bd9Sstevel@tonic-gate #define	assert_nolint(x) assert(x)
1067c478bd9Sstevel@tonic-gate #endif
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate static void scf_iter_reset_locked(scf_iter_t *iter);
1097c478bd9Sstevel@tonic-gate static void scf_value_reset_locked(scf_value_t *val, int and_destroy);
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate #define	TYPE_VALUE	(-100)
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate /*
1147c478bd9Sstevel@tonic-gate  * Hold and release subhandles.  We only allow one thread access to the
11548bbca81SDaniel Hoffman  * subhandles at a time, and it can use any subset, grabbing and releasing
1167c478bd9Sstevel@tonic-gate  * them in any order.  The only restrictions are that you cannot hold an
1177c478bd9Sstevel@tonic-gate  * already-held subhandle, and all subhandles must be released before
1187c478bd9Sstevel@tonic-gate  * returning to the original caller.
1197c478bd9Sstevel@tonic-gate  */
1207c478bd9Sstevel@tonic-gate static void
handle_hold_subhandles(scf_handle_t * h,int mask)1217c478bd9Sstevel@tonic-gate handle_hold_subhandles(scf_handle_t *h, int mask)
1227c478bd9Sstevel@tonic-gate {
1237c478bd9Sstevel@tonic-gate 	assert(mask != 0 && (mask & ~RH_HOLD_ALL) == 0);
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
126a574db85Sraf 	while (h->rh_hold_flags != 0 && h->rh_holder != pthread_self()) {
127a574db85Sraf 		int cancel_state;
128a574db85Sraf 
129a574db85Sraf 		(void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,
130a574db85Sraf 		    &cancel_state);
131a574db85Sraf 		(void) pthread_cond_wait(&h->rh_cv, &h->rh_lock);
132a574db85Sraf 		(void) pthread_setcancelstate(cancel_state, NULL);
133a574db85Sraf 	}
1347c478bd9Sstevel@tonic-gate 	if (h->rh_hold_flags == 0)
1357c478bd9Sstevel@tonic-gate 		h->rh_holder = pthread_self();
1367c478bd9Sstevel@tonic-gate 	assert(!(h->rh_hold_flags & mask));
1377c478bd9Sstevel@tonic-gate 	h->rh_hold_flags |= mask;
1387c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
1397c478bd9Sstevel@tonic-gate }
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate static void
handle_rele_subhandles(scf_handle_t * h,int mask)1427c478bd9Sstevel@tonic-gate handle_rele_subhandles(scf_handle_t *h, int mask)
1437c478bd9Sstevel@tonic-gate {
1447c478bd9Sstevel@tonic-gate 	assert(mask != 0 && (mask & ~RH_HOLD_ALL) == 0);
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
1477c478bd9Sstevel@tonic-gate 	assert(h->rh_holder == pthread_self());
1487c478bd9Sstevel@tonic-gate 	assert((h->rh_hold_flags & mask));
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate 	h->rh_hold_flags &= ~mask;
1517c478bd9Sstevel@tonic-gate 	if (h->rh_hold_flags == 0)
1527c478bd9Sstevel@tonic-gate 		(void) pthread_cond_signal(&h->rh_cv);
1537c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
1547c478bd9Sstevel@tonic-gate }
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate #define	HOLD_HANDLE(h, flag, field) \
1577c478bd9Sstevel@tonic-gate 	(handle_hold_subhandles((h), (flag)), (h)->field)
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate #define	RELE_HANDLE(h, flag) \
1607c478bd9Sstevel@tonic-gate 	(handle_rele_subhandles((h), (flag)))
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate /*
1637c478bd9Sstevel@tonic-gate  * convenience macros, for functions that only need a one or two handles at
1647c478bd9Sstevel@tonic-gate  * any given time
1657c478bd9Sstevel@tonic-gate  */
1667c478bd9Sstevel@tonic-gate #define	HANDLE_HOLD_ITER(h)	HOLD_HANDLE((h), RH_HOLD_ITER, rh_iter)
1677c478bd9Sstevel@tonic-gate #define	HANDLE_HOLD_SCOPE(h)	HOLD_HANDLE((h), RH_HOLD_SCOPE, rh_scope)
1687c478bd9Sstevel@tonic-gate #define	HANDLE_HOLD_SERVICE(h)	HOLD_HANDLE((h), RH_HOLD_SERVICE, rh_service)
1697c478bd9Sstevel@tonic-gate #define	HANDLE_HOLD_INSTANCE(h)	HOLD_HANDLE((h), RH_HOLD_INSTANCE, rh_instance)
1707c478bd9Sstevel@tonic-gate #define	HANDLE_HOLD_SNAPSHOT(h)	HOLD_HANDLE((h), RH_HOLD_SNAPSHOT, rh_snapshot)
1717c478bd9Sstevel@tonic-gate #define	HANDLE_HOLD_SNAPLVL(h)	HOLD_HANDLE((h), RH_HOLD_SNAPLVL, rh_snaplvl)
1727c478bd9Sstevel@tonic-gate #define	HANDLE_HOLD_PG(h)	HOLD_HANDLE((h), RH_HOLD_PG, rh_pg)
1737c478bd9Sstevel@tonic-gate #define	HANDLE_HOLD_PROPERTY(h)	HOLD_HANDLE((h), RH_HOLD_PROPERTY, rh_property)
1747c478bd9Sstevel@tonic-gate #define	HANDLE_HOLD_VALUE(h)	HOLD_HANDLE((h), RH_HOLD_VALUE, rh_value)
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate #define	HANDLE_RELE_ITER(h)	RELE_HANDLE((h), RH_HOLD_ITER)
1777c478bd9Sstevel@tonic-gate #define	HANDLE_RELE_SCOPE(h)	RELE_HANDLE((h), RH_HOLD_SCOPE)
1787c478bd9Sstevel@tonic-gate #define	HANDLE_RELE_SERVICE(h)	RELE_HANDLE((h), RH_HOLD_SERVICE)
1797c478bd9Sstevel@tonic-gate #define	HANDLE_RELE_INSTANCE(h)	RELE_HANDLE((h), RH_HOLD_INSTANCE)
1807c478bd9Sstevel@tonic-gate #define	HANDLE_RELE_SNAPSHOT(h)	RELE_HANDLE((h), RH_HOLD_SNAPSHOT)
1817c478bd9Sstevel@tonic-gate #define	HANDLE_RELE_SNAPLVL(h)	RELE_HANDLE((h), RH_HOLD_SNAPLVL)
1827c478bd9Sstevel@tonic-gate #define	HANDLE_RELE_PG(h)	RELE_HANDLE((h), RH_HOLD_PG)
1837c478bd9Sstevel@tonic-gate #define	HANDLE_RELE_PROPERTY(h)	RELE_HANDLE((h), RH_HOLD_PROPERTY)
1847c478bd9Sstevel@tonic-gate #define	HANDLE_RELE_VALUE(h)	RELE_HANDLE((h), RH_HOLD_VALUE)
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1877c478bd9Sstevel@tonic-gate static int
transaction_entry_compare(const void * l_arg,const void * r_arg,void * private)1887c478bd9Sstevel@tonic-gate transaction_entry_compare(const void *l_arg, const void *r_arg, void *private)
1897c478bd9Sstevel@tonic-gate {
1907c478bd9Sstevel@tonic-gate 	const char *l_prop =
1917c478bd9Sstevel@tonic-gate 	    ((scf_transaction_entry_t *)l_arg)->entry_property;
1927c478bd9Sstevel@tonic-gate 	const char *r_prop =
1937c478bd9Sstevel@tonic-gate 	    ((scf_transaction_entry_t *)r_arg)->entry_property;
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate 	int ret;
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate 	ret = strcmp(l_prop, r_prop);
1987c478bd9Sstevel@tonic-gate 	if (ret > 0)
1997c478bd9Sstevel@tonic-gate 		return (1);
2008918dff3Sjwadams 	if (ret < 0)
2018918dff3Sjwadams 		return (-1);
2028918dff3Sjwadams 	return (0);
2038918dff3Sjwadams }
2048918dff3Sjwadams 
2058918dff3Sjwadams static int
datael_compare(const void * l_arg,const void * r_arg,void * private)2068918dff3Sjwadams datael_compare(const void *l_arg, const void *r_arg, void *private)
2078918dff3Sjwadams {
2088918dff3Sjwadams 	uint32_t l_id = ((scf_datael_t *)l_arg)->rd_entity;
2098918dff3Sjwadams 	uint32_t r_id = (r_arg != NULL) ? ((scf_datael_t *)r_arg)->rd_entity :
2108918dff3Sjwadams 	    *(uint32_t *)private;
2118918dff3Sjwadams 
2128918dff3Sjwadams 	if (l_id > r_id)
2138918dff3Sjwadams 		return (1);
2148918dff3Sjwadams 	if (l_id < r_id)
2158918dff3Sjwadams 		return (-1);
2168918dff3Sjwadams 	return (0);
2178918dff3Sjwadams }
2188918dff3Sjwadams 
2198918dff3Sjwadams static int
iter_compare(const void * l_arg,const void * r_arg,void * private)2208918dff3Sjwadams iter_compare(const void *l_arg, const void *r_arg, void *private)
2218918dff3Sjwadams {
2228918dff3Sjwadams 	uint32_t l_id = ((scf_iter_t *)l_arg)->iter_id;
2238918dff3Sjwadams 	uint32_t r_id = (r_arg != NULL) ? ((scf_iter_t *)r_arg)->iter_id :
2248918dff3Sjwadams 	    *(uint32_t *)private;
2258918dff3Sjwadams 
2268918dff3Sjwadams 	if (l_id > r_id)
2278918dff3Sjwadams 		return (1);
2288918dff3Sjwadams 	if (l_id < r_id)
2297c478bd9Sstevel@tonic-gate 		return (-1);
2307c478bd9Sstevel@tonic-gate 	return (0);
2317c478bd9Sstevel@tonic-gate }
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate static int
lowlevel_init(void)2347c478bd9Sstevel@tonic-gate lowlevel_init(void)
2357c478bd9Sstevel@tonic-gate {
2367c478bd9Sstevel@tonic-gate 	const char *debug;
2377c478bd9Sstevel@tonic-gate 	const char *door_path;
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&lowlevel_init_lock);
2407c478bd9Sstevel@tonic-gate 	if (lowlevel_inited == 0) {
2417c478bd9Sstevel@tonic-gate 		if (!issetugid() &&
2427c478bd9Sstevel@tonic-gate 		    (debug = getenv(ENV_SCF_DEBUG)) != NULL && debug[0] != 0 &&
2437c478bd9Sstevel@tonic-gate 		    uu_strtoint(debug, &default_debug, sizeof (default_debug),
2447c478bd9Sstevel@tonic-gate 		    0, 0, 0) == -1) {
2457c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "LIBSCF: $%s (%s): %s",
2467c478bd9Sstevel@tonic-gate 			    ENV_SCF_DEBUG, debug,
2477c478bd9Sstevel@tonic-gate 			    uu_strerror(uu_error()));
2487c478bd9Sstevel@tonic-gate 		}
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate 		if (!issetugid() &&
2517c478bd9Sstevel@tonic-gate 		    (door_path = getenv(ENV_SCF_DOORPATH)) != NULL &&
2527c478bd9Sstevel@tonic-gate 		    door_path[0] != 0) {
2537c478bd9Sstevel@tonic-gate 			default_door_path = strdup(door_path);
2547c478bd9Sstevel@tonic-gate 			if (default_door_path == NULL)
2557c478bd9Sstevel@tonic-gate 				default_door_path = door_path;
2567c478bd9Sstevel@tonic-gate 		}
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate 		datael_pool = uu_list_pool_create("SUNW,libscf_datael",
2597c478bd9Sstevel@tonic-gate 		    sizeof (scf_datael_t), offsetof(scf_datael_t, rd_node),
2608918dff3Sjwadams 		    datael_compare, UU_LIST_POOL_DEBUG);
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate 		iter_pool = uu_list_pool_create("SUNW,libscf_iter",
2637c478bd9Sstevel@tonic-gate 		    sizeof (scf_iter_t), offsetof(scf_iter_t, iter_node),
2648918dff3Sjwadams 		    iter_compare, UU_LIST_POOL_DEBUG);
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate 		assert_nolint(offsetof(scf_transaction_entry_t,
2677c478bd9Sstevel@tonic-gate 		    entry_property) == 0);
2687c478bd9Sstevel@tonic-gate 		tran_entry_pool = uu_list_pool_create(
2697c478bd9Sstevel@tonic-gate 		    "SUNW,libscf_transaction_entity",
2707c478bd9Sstevel@tonic-gate 		    sizeof (scf_transaction_entry_t),
2717c478bd9Sstevel@tonic-gate 		    offsetof(scf_transaction_entry_t, entry_link),
2727c478bd9Sstevel@tonic-gate 		    transaction_entry_compare, UU_LIST_POOL_DEBUG);
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate 		if (datael_pool == NULL || iter_pool == NULL ||
2757c478bd9Sstevel@tonic-gate 		    tran_entry_pool == NULL) {
2767c478bd9Sstevel@tonic-gate 			lowlevel_inited = -1;
2777c478bd9Sstevel@tonic-gate 			goto end;
2787c478bd9Sstevel@tonic-gate 		}
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate 		if (!scf_setup_error()) {
2817c478bd9Sstevel@tonic-gate 			lowlevel_inited = -1;
2827c478bd9Sstevel@tonic-gate 			goto end;
2837c478bd9Sstevel@tonic-gate 		}
2847c478bd9Sstevel@tonic-gate 		lowlevel_inited = 1;
2857c478bd9Sstevel@tonic-gate 	}
2867c478bd9Sstevel@tonic-gate end:
2877c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&lowlevel_init_lock);
2887c478bd9Sstevel@tonic-gate 	if (lowlevel_inited > 0)
2897c478bd9Sstevel@tonic-gate 		return (1);
2907c478bd9Sstevel@tonic-gate 	return (0);
2917c478bd9Sstevel@tonic-gate }
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate static const struct {
2947c478bd9Sstevel@tonic-gate 	scf_type_t ti_type;
2957c478bd9Sstevel@tonic-gate 	rep_protocol_value_type_t ti_proto_type;
2967c478bd9Sstevel@tonic-gate 	const char *ti_name;
2977c478bd9Sstevel@tonic-gate } scf_type_info[] = {
2984f5c6fa5SAndrew Stormont 	{SCF_TYPE_BOOLEAN,	REP_PROTOCOL_TYPE_BOOLEAN,
2994f5c6fa5SAndrew Stormont 	    SCF_TYPE_STRING_BOOLEAN},
3004f5c6fa5SAndrew Stormont 	{SCF_TYPE_COUNT,	REP_PROTOCOL_TYPE_COUNT,
3014f5c6fa5SAndrew Stormont 	    SCF_TYPE_STRING_COUNT},
3024f5c6fa5SAndrew Stormont 	{SCF_TYPE_INTEGER,	REP_PROTOCOL_TYPE_INTEGER,
3034f5c6fa5SAndrew Stormont 	    SCF_TYPE_STRING_INTEGER},
3044f5c6fa5SAndrew Stormont 	{SCF_TYPE_TIME,		REP_PROTOCOL_TYPE_TIME,
3054f5c6fa5SAndrew Stormont 	    SCF_TYPE_STRING_TIME},
3064f5c6fa5SAndrew Stormont 	{SCF_TYPE_ASTRING,	REP_PROTOCOL_TYPE_STRING,
3074f5c6fa5SAndrew Stormont 	    SCF_TYPE_STRING_ASTRING},
3084f5c6fa5SAndrew Stormont 	{SCF_TYPE_OPAQUE,	REP_PROTOCOL_TYPE_OPAQUE,
3094f5c6fa5SAndrew Stormont 	    SCF_TYPE_STRING_OPAQUE},
3104f5c6fa5SAndrew Stormont 	{SCF_TYPE_USTRING,	REP_PROTOCOL_SUBTYPE_USTRING,
3114f5c6fa5SAndrew Stormont 	    SCF_TYPE_STRING_USTRING},
3124f5c6fa5SAndrew Stormont 	{SCF_TYPE_URI,		REP_PROTOCOL_SUBTYPE_URI,
3134f5c6fa5SAndrew Stormont 	    SCF_TYPE_STRING_URI},
3144f5c6fa5SAndrew Stormont 	{SCF_TYPE_FMRI,		REP_PROTOCOL_SUBTYPE_FMRI,
3154f5c6fa5SAndrew Stormont 	    SCF_TYPE_STRING_FMRI},
3164f5c6fa5SAndrew Stormont 	{SCF_TYPE_HOST,		REP_PROTOCOL_SUBTYPE_HOST,
3174f5c6fa5SAndrew Stormont 	    SCF_TYPE_STRING_HOST},
3184f5c6fa5SAndrew Stormont 	{SCF_TYPE_HOSTNAME,	REP_PROTOCOL_SUBTYPE_HOSTNAME,
3194f5c6fa5SAndrew Stormont 	    SCF_TYPE_STRING_HOSTNAME},
3204f5c6fa5SAndrew Stormont 	{SCF_TYPE_NET_ADDR,	REP_PROTOCOL_SUBTYPE_NETADDR,
3214f5c6fa5SAndrew Stormont 	    SCF_TYPE_STRING_NET_ADDR},
3227c478bd9Sstevel@tonic-gate 	{SCF_TYPE_NET_ADDR_V4,	REP_PROTOCOL_SUBTYPE_NETADDR_V4,
3234f5c6fa5SAndrew Stormont 	    SCF_TYPE_STRING_NET_ADDR_V4},
3247c478bd9Sstevel@tonic-gate 	{SCF_TYPE_NET_ADDR_V6,	REP_PROTOCOL_SUBTYPE_NETADDR_V6,
3254f5c6fa5SAndrew Stormont 	    SCF_TYPE_STRING_NET_ADDR_V6}
3267c478bd9Sstevel@tonic-gate };
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate #define	SCF_TYPE_INFO_COUNT (sizeof (scf_type_info) / sizeof (*scf_type_info))
3297c478bd9Sstevel@tonic-gate static rep_protocol_value_type_t
scf_type_to_protocol_type(scf_type_t t)3307c478bd9Sstevel@tonic-gate scf_type_to_protocol_type(scf_type_t t)
3317c478bd9Sstevel@tonic-gate {
3327c478bd9Sstevel@tonic-gate 	int i;
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCF_TYPE_INFO_COUNT; i++)
3357c478bd9Sstevel@tonic-gate 		if (scf_type_info[i].ti_type == t)
3367c478bd9Sstevel@tonic-gate 			return (scf_type_info[i].ti_proto_type);
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate 	return (REP_PROTOCOL_TYPE_INVALID);
3397c478bd9Sstevel@tonic-gate }
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate static scf_type_t
scf_protocol_type_to_type(rep_protocol_value_type_t t)3427c478bd9Sstevel@tonic-gate scf_protocol_type_to_type(rep_protocol_value_type_t t)
3437c478bd9Sstevel@tonic-gate {
3447c478bd9Sstevel@tonic-gate 	int i;
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCF_TYPE_INFO_COUNT; i++)
3477c478bd9Sstevel@tonic-gate 		if (scf_type_info[i].ti_proto_type == t)
3487c478bd9Sstevel@tonic-gate 			return (scf_type_info[i].ti_type);
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate 	return (SCF_TYPE_INVALID);
3517c478bd9Sstevel@tonic-gate }
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate const char *
scf_type_to_string(scf_type_t ty)3547c478bd9Sstevel@tonic-gate scf_type_to_string(scf_type_t ty)
3557c478bd9Sstevel@tonic-gate {
3567c478bd9Sstevel@tonic-gate 	int i;
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCF_TYPE_INFO_COUNT; i++)
3597c478bd9Sstevel@tonic-gate 		if (scf_type_info[i].ti_type == ty)
3607c478bd9Sstevel@tonic-gate 			return (scf_type_info[i].ti_name);
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 	return ("unknown");
3637c478bd9Sstevel@tonic-gate }
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate scf_type_t
scf_string_to_type(const char * name)3667c478bd9Sstevel@tonic-gate scf_string_to_type(const char *name)
3677c478bd9Sstevel@tonic-gate {
3687c478bd9Sstevel@tonic-gate 	int i;
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate 	for (i = 0; i < sizeof (scf_type_info) / sizeof (*scf_type_info); i++)
3717c478bd9Sstevel@tonic-gate 		if (strcmp(scf_type_info[i].ti_name, name) == 0)
3727c478bd9Sstevel@tonic-gate 			return (scf_type_info[i].ti_type);
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate 	return (SCF_TYPE_INVALID);
3757c478bd9Sstevel@tonic-gate }
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate int
scf_type_base_type(scf_type_t type,scf_type_t * out)3787c478bd9Sstevel@tonic-gate scf_type_base_type(scf_type_t type, scf_type_t *out)
3797c478bd9Sstevel@tonic-gate {
3807c478bd9Sstevel@tonic-gate 	rep_protocol_value_type_t t = scf_type_to_protocol_type(type);
3817c478bd9Sstevel@tonic-gate 	if (t == REP_PROTOCOL_TYPE_INVALID)
3827c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate 	*out = scf_protocol_type_to_type(scf_proto_underlying_type(t));
3857c478bd9Sstevel@tonic-gate 	return (SCF_SUCCESS);
3867c478bd9Sstevel@tonic-gate }
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate /*
3897c478bd9Sstevel@tonic-gate  * Convert a protocol error code into an SCF_ERROR_* code.
3907c478bd9Sstevel@tonic-gate  */
3917c478bd9Sstevel@tonic-gate static scf_error_t
proto_error(rep_protocol_responseid_t e)3927c478bd9Sstevel@tonic-gate proto_error(rep_protocol_responseid_t e)
3937c478bd9Sstevel@tonic-gate {
3947c478bd9Sstevel@tonic-gate 	switch (e) {
3957c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_MISORDERED:
3967c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_UNKNOWN_ID:
3977c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_INVALID_TYPE:
3987c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_TRUNCATED:
3997c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_TYPE_MISMATCH:
4007c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_NOT_APPLICABLE:
4017c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_UNKNOWN:
4027c478bd9Sstevel@tonic-gate 		return (SCF_ERROR_INTERNAL);
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_BAD_TX:
4057c478bd9Sstevel@tonic-gate 		return (SCF_ERROR_INVALID_ARGUMENT);
4067c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_BAD_REQUEST:
4077c478bd9Sstevel@tonic-gate 		return (SCF_ERROR_INVALID_ARGUMENT);
4087c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_NO_RESOURCES:
4097c478bd9Sstevel@tonic-gate 		return (SCF_ERROR_NO_RESOURCES);
4107c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_NOT_FOUND:
4117c478bd9Sstevel@tonic-gate 		return (SCF_ERROR_NOT_FOUND);
4127c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_DELETED:
4137c478bd9Sstevel@tonic-gate 		return (SCF_ERROR_DELETED);
4147c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_NOT_SET:
4157c478bd9Sstevel@tonic-gate 		return (SCF_ERROR_NOT_SET);
4167c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_EXISTS:
4177c478bd9Sstevel@tonic-gate 		return (SCF_ERROR_EXISTS);
4187c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_DUPLICATE_ID:
4197c478bd9Sstevel@tonic-gate 		return (SCF_ERROR_EXISTS);
4207c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_PERMISSION_DENIED:
4217c478bd9Sstevel@tonic-gate 		return (SCF_ERROR_PERMISSION_DENIED);
4227c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_BACKEND_ACCESS:
4237c478bd9Sstevel@tonic-gate 		return (SCF_ERROR_BACKEND_ACCESS);
4247c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_BACKEND_READONLY:
4257c478bd9Sstevel@tonic-gate 		return (SCF_ERROR_BACKEND_READONLY);
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_SUCCESS:
4287c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_DONE:
4297c478bd9Sstevel@tonic-gate 	case REP_PROTOCOL_FAIL_NOT_LATEST:	/* TX code should handle this */
4307c478bd9Sstevel@tonic-gate 	default:
4317c478bd9Sstevel@tonic-gate #ifndef NDEBUG
4327c478bd9Sstevel@tonic-gate 		uu_warn("%s:%d: Bad error code %d passed to proto_error().\n",
4337c478bd9Sstevel@tonic-gate 		    __FILE__, __LINE__, e);
4347c478bd9Sstevel@tonic-gate #endif
4357c478bd9Sstevel@tonic-gate 		abort();
4367c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
4377c478bd9Sstevel@tonic-gate 	}
4387c478bd9Sstevel@tonic-gate }
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate ssize_t
scf_limit(uint32_t limit)4417c478bd9Sstevel@tonic-gate scf_limit(uint32_t limit)
4427c478bd9Sstevel@tonic-gate {
4437c478bd9Sstevel@tonic-gate 	switch (limit) {
4447c478bd9Sstevel@tonic-gate 	case SCF_LIMIT_MAX_NAME_LENGTH:
4457c478bd9Sstevel@tonic-gate 	case SCF_LIMIT_MAX_PG_TYPE_LENGTH:
4467c478bd9Sstevel@tonic-gate 		return (REP_PROTOCOL_NAME_LEN - 1);
4477c478bd9Sstevel@tonic-gate 	case SCF_LIMIT_MAX_VALUE_LENGTH:
4487c478bd9Sstevel@tonic-gate 		return (REP_PROTOCOL_VALUE_LEN - 1);
4497c478bd9Sstevel@tonic-gate 	case SCF_LIMIT_MAX_FMRI_LENGTH:
4507c478bd9Sstevel@tonic-gate 		return (SCF_FMRI_PREFIX_MAX_LEN +
4517c478bd9Sstevel@tonic-gate 		    sizeof (SCF_FMRI_SCOPE_PREFIX) - 1 +
4527c478bd9Sstevel@tonic-gate 		    sizeof (SCF_FMRI_SCOPE_SUFFIX) - 1 +
4537c478bd9Sstevel@tonic-gate 		    sizeof (SCF_FMRI_SERVICE_PREFIX) - 1 +
4547c478bd9Sstevel@tonic-gate 		    sizeof (SCF_FMRI_INSTANCE_PREFIX) - 1 +
4557c478bd9Sstevel@tonic-gate 		    sizeof (SCF_FMRI_PROPERTYGRP_PREFIX) - 1 +
4567c478bd9Sstevel@tonic-gate 		    sizeof (SCF_FMRI_PROPERTY_PREFIX) - 1 +
4577c478bd9Sstevel@tonic-gate 		    5 * (REP_PROTOCOL_NAME_LEN - 1));
4587c478bd9Sstevel@tonic-gate 	default:
4597c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4607c478bd9Sstevel@tonic-gate 	}
4617c478bd9Sstevel@tonic-gate }
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate static size_t
scf_opaque_decode(char * out_arg,const char * in,size_t max_out)4647c478bd9Sstevel@tonic-gate scf_opaque_decode(char *out_arg, const char *in, size_t max_out)
4657c478bd9Sstevel@tonic-gate {
4667c478bd9Sstevel@tonic-gate 	char a, b;
4677c478bd9Sstevel@tonic-gate 	char *out = out_arg;
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 	while (max_out > 0 && (a = in[0]) != 0 && (b = in[1]) != 0) {
4707c478bd9Sstevel@tonic-gate 		in += 2;
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 		if (a >= '0' && a <= '9')
4737c478bd9Sstevel@tonic-gate 			a -= '0';
4747c478bd9Sstevel@tonic-gate 		else if (a >= 'a' && a <= 'f')
4757c478bd9Sstevel@tonic-gate 			a = a - 'a' + 10;
4767c478bd9Sstevel@tonic-gate 		else if (a >= 'A' && a <= 'F')
4777c478bd9Sstevel@tonic-gate 			a = a - 'A' + 10;
4787c478bd9Sstevel@tonic-gate 		else
4797c478bd9Sstevel@tonic-gate 			break;
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate 		if (b >= '0' && b <= '9')
4827c478bd9Sstevel@tonic-gate 			b -= '0';
4837c478bd9Sstevel@tonic-gate 		else if (b >= 'a' && b <= 'f')
4847c478bd9Sstevel@tonic-gate 			b = b - 'a' + 10;
4857c478bd9Sstevel@tonic-gate 		else if (b >= 'A' && b <= 'F')
4867c478bd9Sstevel@tonic-gate 			b = b - 'A' + 10;
4877c478bd9Sstevel@tonic-gate 		else
4887c478bd9Sstevel@tonic-gate 			break;
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate 		*out++ = (a << 4) | b;
4917c478bd9Sstevel@tonic-gate 		max_out--;
4927c478bd9Sstevel@tonic-gate 	}
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate 	return (out - out_arg);
4957c478bd9Sstevel@tonic-gate }
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate static size_t
scf_opaque_encode(char * out_arg,const char * in_arg,size_t in_sz)4987c478bd9Sstevel@tonic-gate scf_opaque_encode(char *out_arg, const char *in_arg, size_t in_sz)
4997c478bd9Sstevel@tonic-gate {
5007c478bd9Sstevel@tonic-gate 	uint8_t *in = (uint8_t *)in_arg;
5017c478bd9Sstevel@tonic-gate 	uint8_t *end = in + in_sz;
5027c478bd9Sstevel@tonic-gate 	char *out = out_arg;
5037c478bd9Sstevel@tonic-gate 
5047c478bd9Sstevel@tonic-gate 	if (out == NULL)
5057c478bd9Sstevel@tonic-gate 		return (2 * in_sz);
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate 	while (in < end) {
5087c478bd9Sstevel@tonic-gate 		uint8_t c = *in++;
5097c478bd9Sstevel@tonic-gate 
5107c478bd9Sstevel@tonic-gate 		uint8_t a = (c & 0xf0) >> 4;
5117c478bd9Sstevel@tonic-gate 		uint8_t b = (c & 0x0f);
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate 		if (a <= 9)
5147c478bd9Sstevel@tonic-gate 			*out++ = a + '0';
5157c478bd9Sstevel@tonic-gate 		else
5167c478bd9Sstevel@tonic-gate 			*out++ = a + 'a' - 10;
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate 		if (b <= 9)
5197c478bd9Sstevel@tonic-gate 			*out++ = b + '0';
5207c478bd9Sstevel@tonic-gate 		else
5217c478bd9Sstevel@tonic-gate 			*out++ = b + 'a' - 10;
5227c478bd9Sstevel@tonic-gate 	}
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate 	*out = 0;
5257c478bd9Sstevel@tonic-gate 
5267c478bd9Sstevel@tonic-gate 	return (out - out_arg);
5277c478bd9Sstevel@tonic-gate }
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate static void
handle_do_close(scf_handle_t * h)5307c478bd9Sstevel@tonic-gate handle_do_close(scf_handle_t *h)
5317c478bd9Sstevel@tonic-gate {
5327c478bd9Sstevel@tonic-gate 	assert(MUTEX_HELD(&h->rh_lock));
5337c478bd9Sstevel@tonic-gate 	assert(h->rh_doorfd != -1);
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate 	/*
5367c478bd9Sstevel@tonic-gate 	 * if there are any active FD users, we just move the FD over
5377c478bd9Sstevel@tonic-gate 	 * to rh_doorfd_old -- they'll close it when they finish.
5387c478bd9Sstevel@tonic-gate 	 */
5397c478bd9Sstevel@tonic-gate 	if (h->rh_fd_users > 0) {
5407c478bd9Sstevel@tonic-gate 		h->rh_doorfd_old = h->rh_doorfd;
5417c478bd9Sstevel@tonic-gate 		h->rh_doorfd = -1;
5427c478bd9Sstevel@tonic-gate 	} else {
5437c478bd9Sstevel@tonic-gate 		assert(h->rh_doorfd_old == -1);
5447c478bd9Sstevel@tonic-gate 		(void) close(h->rh_doorfd);
5457c478bd9Sstevel@tonic-gate 		h->rh_doorfd = -1;
5467c478bd9Sstevel@tonic-gate 	}
5477c478bd9Sstevel@tonic-gate }
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate /*
5507c478bd9Sstevel@tonic-gate  * Check if a handle is currently bound.  fork()ing implicitly unbinds
5517c478bd9Sstevel@tonic-gate  * the handle in the child.
5527c478bd9Sstevel@tonic-gate  */
5537c478bd9Sstevel@tonic-gate static int
handle_is_bound(scf_handle_t * h)5547c478bd9Sstevel@tonic-gate handle_is_bound(scf_handle_t *h)
5557c478bd9Sstevel@tonic-gate {
5567c478bd9Sstevel@tonic-gate 	assert(MUTEX_HELD(&h->rh_lock));
5577c478bd9Sstevel@tonic-gate 
5587c478bd9Sstevel@tonic-gate 	if (h->rh_doorfd == -1)
5597c478bd9Sstevel@tonic-gate 		return (0);
5607c478bd9Sstevel@tonic-gate 
5617c478bd9Sstevel@tonic-gate 	if (getpid() == h->rh_doorpid)
5627c478bd9Sstevel@tonic-gate 		return (1);
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate 	/* forked since our last bind -- initiate handle close */
5657c478bd9Sstevel@tonic-gate 	handle_do_close(h);
5667c478bd9Sstevel@tonic-gate 	return (0);
5677c478bd9Sstevel@tonic-gate }
5687c478bd9Sstevel@tonic-gate 
5697c478bd9Sstevel@tonic-gate static int
handle_has_server_locked(scf_handle_t * h)5708918dff3Sjwadams handle_has_server_locked(scf_handle_t *h)
5717c478bd9Sstevel@tonic-gate {
5727c478bd9Sstevel@tonic-gate 	door_info_t i;
5738918dff3Sjwadams 	assert(MUTEX_HELD(&h->rh_lock));
5748918dff3Sjwadams 
5758918dff3Sjwadams 	return (handle_is_bound(h) && door_info(h->rh_doorfd, &i) != -1 &&
5768918dff3Sjwadams 	    i.di_target != -1);
5778918dff3Sjwadams }
5788918dff3Sjwadams 
5798918dff3Sjwadams static int
handle_has_server(scf_handle_t * h)5808918dff3Sjwadams handle_has_server(scf_handle_t *h)
5818918dff3Sjwadams {
5827c478bd9Sstevel@tonic-gate 	int ret;
5837c478bd9Sstevel@tonic-gate 
5847c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&h->rh_lock);
5858918dff3Sjwadams 	ret = handle_has_server_locked(h);
5867c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&h->rh_lock);
5877c478bd9Sstevel@tonic-gate 
5887c478bd9Sstevel@tonic-gate 	return (ret);
5897c478bd9Sstevel@tonic-gate }
5907c478bd9Sstevel@tonic-gate 
5917c478bd9Sstevel@tonic-gate /*
5927c478bd9Sstevel@tonic-gate  * This makes a door request on the client door associated with handle h.
5937c478bd9Sstevel@tonic-gate  * It will automatically retry calls which fail on EINTR.  If h is not bound,
5947c478bd9Sstevel@tonic-gate  * returns NOT_BOUND.  If the door call fails or the server response is too
5957c478bd9Sstevel@tonic-gate  * small, returns CALL_FAILED.  If the server response is too big, truncates the
5967c478bd9Sstevel@tonic-gate  * response and returns RESULT_TOO_BIG.  Otherwise, the size of the result is
5977c478bd9Sstevel@tonic-gate  * returned.
5987c478bd9Sstevel@tonic-gate  */
5997c478bd9Sstevel@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)6007c478bd9Sstevel@tonic-gate make_door_call(scf_handle_t *h, const void *req, size_t req_sz,
6017c478bd9Sstevel@tonic-gate     void *res, size_t res_sz)
6027c478bd9Sstevel@tonic-gate {
6037c478bd9Sstevel@tonic-gate 	door_arg_t arg;
6047c478bd9Sstevel@tonic-gate 	int r;
6057c478bd9Sstevel@tonic-gate 
6067c478bd9Sstevel@tonic-gate 	assert(MUTEX_HELD(&h->rh_lock));
6077c478bd9Sstevel@tonic-gate 
6087c478bd9Sstevel@tonic-gate 	if (!handle_is_bound(h)) {
6097c478bd9Sstevel@tonic-gate 		return (NOT_BOUND);
6107c478bd9Sstevel@tonic-gate 	}
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate 	arg.data_ptr = (void *)req;
6137c478bd9Sstevel@tonic-gate 	arg.data_size = req_sz;
6147c478bd9Sstevel@tonic-gate 	arg.desc_ptr = NULL;
6157c478bd9Sstevel@tonic-gate 	arg.desc_num = 0;
6167c478bd9Sstevel@tonic-gate 	arg.rbuf = res;
6177c478bd9Sstevel@tonic-gate 	arg.rsize = res_sz;
6187c478bd9Sstevel@tonic-gate 
6197c478bd9Sstevel@tonic-gate 	while ((r = door_call(h->rh_doorfd, &arg)) < 0) {
6207c478bd9Sstevel@tonic-gate 		if (errno != EINTR)
6217c478bd9Sstevel@tonic-gate 			break;
6227c478bd9Sstevel@tonic-gate 	}
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate 	if (r < 0) {
6257c478bd9Sstevel@tonic-gate 		return (CALL_FAILED);
6267c478bd9Sstevel@tonic-gate 	}
6277c478bd9Sstevel@tonic-gate 
6287c478bd9Sstevel@tonic-gate 	if (arg.desc_num > 0) {
6297c478bd9Sstevel@tonic-gate 		while (arg.desc_num > 0) {
6307c478bd9Sstevel@tonic-gate 			if (arg.desc_ptr->d_attributes & DOOR_DESCRIPTOR) {
6317c478bd9Sstevel@tonic-gate 				int cfd = arg.desc_ptr->d_data.d_desc.d_id;
6327c478bd9Sstevel@tonic-gate 				(void) close(cfd);
6337c478bd9Sstevel@tonic-gate 			}
6347c478bd9Sstevel@tonic-gate 			arg.desc_ptr++;
6357c478bd9Sstevel@tonic-gate 			arg.desc_num--;
6367c478bd9Sstevel@tonic-gate 		}
6377c478bd9Sstevel@tonic-gate 	}
6387c478bd9Sstevel@tonic-gate 	if (arg.data_ptr != res && arg.data_size > 0)
6397c478bd9Sstevel@tonic-gate 		(void) memmove(res, arg.data_ptr, MIN(arg.data_size, res_sz));
6407c478bd9Sstevel@tonic-gate 
6417c478bd9Sstevel@tonic-gate 	if (arg.rbuf != res)
6427c478bd9Sstevel@tonic-gate 		(void) munmap(arg.rbuf, arg.rsize);
6437c478bd9Sstevel@tonic-gate 
6447c478bd9Sstevel@tonic-gate 	if (arg.data_size > res_sz)
6457c478bd9Sstevel@tonic-gate 		return (RESULT_TOO_BIG);
6467c478bd9Sstevel@tonic-gate 
6477c478bd9Sstevel@tonic-gate 	if (arg.data_size < sizeof (uint32_t))
6487c478bd9Sstevel@tonic-gate 		return (CALL_FAILED);
6497c478bd9Sstevel@tonic-gate 
6507c478bd9Sstevel@tonic-gate 	return (arg.data_size);
6517c478bd9Sstevel@tonic-gate }
6527c478bd9Sstevel@tonic-gate 
6537c478bd9Sstevel@tonic-gate /*
6547c478bd9Sstevel@tonic-gate  * Should only be used when r < 0.
6557c478bd9Sstevel@tonic-gate  */
6567c478bd9Sstevel@tonic-gate #define	DOOR_ERRORS_BLOCK(r)	{					\
6577c478bd9Sstevel@tonic-gate 	switch (r) {							\
6587c478bd9Sstevel@tonic-gate 	case NOT_BOUND:							\
6597c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_NOT_BOUND));		\
6607c478bd9Sstevel@tonic-gate 									\
6617c478bd9Sstevel@tonic-gate 	case CALL_FAILED:						\
6627c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN));	\
6637c478bd9Sstevel@tonic-gate 									\
6647c478bd9Sstevel@tonic-gate 	case RESULT_TOO_BIG:						\
6657c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_INTERNAL));		\
6667c478bd9Sstevel@tonic-gate 									\
6677c478bd9Sstevel@tonic-gate 	default:							\
6687c478bd9Sstevel@tonic-gate 		assert(r == NOT_BOUND || r == CALL_FAILED ||		\
6697c478bd9Sstevel@tonic-gate 		    r == RESULT_TOO_BIG);				\
6707c478bd9Sstevel@tonic-gate 		abort();						\
6717c478bd9Sstevel@tonic-gate 	}								\
6727c478bd9Sstevel@tonic-gate }
6737c478bd9Sstevel@tonic-gate 
6747c478bd9Sstevel@tonic-gate /*
6757c478bd9Sstevel@tonic-gate  * Like make_door_call(), but takes an fd instead of a handle, and expects
6767c478bd9Sstevel@tonic-gate  * a single file descriptor, returned via res_fd.
6777c478bd9Sstevel@tonic-gate  *
6787c478bd9Sstevel@tonic-gate  * If no file descriptor is returned, *res_fd == -1.
6797c478bd9Sstevel@tonic-gate  */
6807c478bd9Sstevel@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)6817c478bd9Sstevel@tonic-gate make_door_call_retfd(int fd, const void *req, size_t req_sz, void *res,
6827c478bd9Sstevel@tonic-gate     size_t res_sz, int *res_fd)
6837c478bd9Sstevel@tonic-gate {
6847c478bd9Sstevel@tonic-gate 	door_arg_t arg;
6857c478bd9Sstevel@tonic-gate 	int r;
6867c478bd9Sstevel@tonic-gate 	char rbuf[256];
6877c478bd9Sstevel@tonic-gate 
6887c478bd9Sstevel@tonic-gate 	*res_fd = -1;
6897c478bd9Sstevel@tonic-gate 
6907c478bd9Sstevel@tonic-gate 	if (fd == -1)
6917c478bd9Sstevel@tonic-gate 		return (NOT_BOUND);
6927c478bd9Sstevel@tonic-gate 
6937c478bd9Sstevel@tonic-gate 	arg.data_ptr = (void *)req;
6947c478bd9Sstevel@tonic-gate 	arg.data_size = req_sz;
6957c478bd9Sstevel@tonic-gate 	arg.desc_ptr = NULL;
6967c478bd9Sstevel@tonic-gate 	arg.desc_num = 0;
6977c478bd9Sstevel@tonic-gate 	arg.rbuf = rbuf;
6987c478bd9Sstevel@tonic-gate 	arg.rsize = sizeof (rbuf);
6997c478bd9Sstevel@tonic-gate 
7007c478bd9Sstevel@tonic-gate 	while ((r = door_call(fd, &arg)) < 0) {
7017c478bd9Sstevel@tonic-gate 		if (errno != EINTR)
7027c478bd9Sstevel@tonic-gate 			break;
7037c478bd9Sstevel@tonic-gate 	}
7047c478bd9Sstevel@tonic-gate 
7057c478bd9Sstevel@tonic-gate 	if (r < 0)
7067c478bd9Sstevel@tonic-gate 		return (CALL_FAILED);
7077c478bd9Sstevel@tonic-gate 
7087c478bd9Sstevel@tonic-gate 	if (arg.desc_num > 1) {
7097c478bd9Sstevel@tonic-gate 		while (arg.desc_num > 0) {
7107c478bd9Sstevel@tonic-gate 			if (arg.desc_ptr->d_attributes & DOOR_DESCRIPTOR) {
7117c478bd9Sstevel@tonic-gate 				int cfd =
7127c478bd9Sstevel@tonic-gate 				    arg.desc_ptr->d_data.d_desc.d_descriptor;
7137c478bd9Sstevel@tonic-gate 				(void) close(cfd);
7147c478bd9Sstevel@tonic-gate 			}
7157c478bd9Sstevel@tonic-gate 			arg.desc_ptr++;
7167c478bd9Sstevel@tonic-gate 			arg.desc_num--;
7177c478bd9Sstevel@tonic-gate 		}
7187c478bd9Sstevel@tonic-gate 	}
7197c478bd9Sstevel@tonic-gate 	if (arg.desc_num == 1 && arg.desc_ptr->d_attributes & DOOR_DESCRIPTOR)
7207c478bd9Sstevel@tonic-gate 		*res_fd = arg.desc_ptr->d_data.d_desc.d_descriptor;
7217c478bd9Sstevel@tonic-gate 
7227c478bd9Sstevel@tonic-gate 	if (arg.data_size > 0)
7237c478bd9Sstevel@tonic-gate 		(void) memmove(res, arg.data_ptr, MIN(arg.data_size, res_sz));
7247c478bd9Sstevel@tonic-gate 
7257c478bd9Sstevel@tonic-gate 	if (arg.rbuf != rbuf)
7267c478bd9Sstevel@tonic-gate 		(void) munmap(arg.rbuf, arg.rsize);
7277c478bd9Sstevel@tonic-gate 
7287c478bd9Sstevel@tonic-gate 	if (arg.data_size > res_sz)
7297c478bd9Sstevel@tonic-gate 		return (RESULT_TOO_BIG);
7307c478bd9Sstevel@tonic-gate 
7317c478bd9Sstevel@tonic-gate 	if (arg.data_size < sizeof (uint32_t))
7327c478bd9Sstevel@tonic-gate 		return (CALL_FAILED);
7337c478bd9Sstevel@tonic-gate 
7347c478bd9Sstevel@tonic-gate 	return (arg.data_size);
7357c478bd9Sstevel@tonic-gate }
7367c478bd9Sstevel@tonic-gate 
7377c478bd9Sstevel@tonic-gate /*
7387c478bd9Sstevel@tonic-gate  * Fails with
7397c478bd9Sstevel@tonic-gate  *   _VERSION_MISMATCH
7407c478bd9Sstevel@tonic-gate  *   _NO_MEMORY
7417c478bd9Sstevel@tonic-gate  */
7427c478bd9Sstevel@tonic-gate scf_handle_t *
scf_handle_create(scf_version_t v)7437c478bd9Sstevel@tonic-gate scf_handle_create(scf_version_t v)
7447c478bd9Sstevel@tonic-gate {
7457c478bd9Sstevel@tonic-gate 	scf_handle_t *ret;
7467c478bd9Sstevel@tonic-gate 	int failed;
7477c478bd9Sstevel@tonic-gate 
7487c478bd9Sstevel@tonic-gate 	/*
7497c478bd9Sstevel@tonic-gate 	 * This will need to be revisited when we bump SCF_VERSION
7507c478bd9Sstevel@tonic-gate 	 */
7517c478bd9Sstevel@tonic-gate 	if (v != SCF_VERSION) {
7527c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_VERSION_MISMATCH);
7537c478bd9Sstevel@tonic-gate 		return (NULL);
7547c478bd9Sstevel@tonic-gate 	}
7557c478bd9Sstevel@tonic-gate 
7567c478bd9Sstevel@tonic-gate 	if (!lowlevel_init()) {
7577c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
7587c478bd9Sstevel@tonic-gate 		return (NULL);
7597c478bd9Sstevel@tonic-gate 	}
7607c478bd9Sstevel@tonic-gate 
7617c478bd9Sstevel@tonic-gate 	ret = uu_zalloc(sizeof (*ret));
7627c478bd9Sstevel@tonic-gate 	if (ret == NULL) {
7637c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
7647c478bd9Sstevel@tonic-gate 		return (NULL);
7657c478bd9Sstevel@tonic-gate 	}
7667c478bd9Sstevel@tonic-gate 
7677c478bd9Sstevel@tonic-gate 	ret->rh_dataels = uu_list_create(datael_pool, ret, 0);
7687c478bd9Sstevel@tonic-gate 	ret->rh_iters = uu_list_create(iter_pool, ret, 0);
7697c478bd9Sstevel@tonic-gate 	if (ret->rh_dataels == NULL || ret->rh_iters == NULL) {
7707c478bd9Sstevel@tonic-gate 		if (ret->rh_dataels != NULL)
7717c478bd9Sstevel@tonic-gate 			uu_list_destroy(ret->rh_dataels);
7727c478bd9Sstevel@tonic-gate 		if (ret->rh_iters != NULL)
7737c478bd9Sstevel@tonic-gate 			uu_list_destroy(ret->rh_iters);
7747c478bd9Sstevel@tonic-gate 		uu_free(ret);
7757c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
7767c478bd9Sstevel@tonic-gate 		return (NULL);
7777c478bd9Sstevel@tonic-gate 	}
7787c478bd9Sstevel@tonic-gate 
7797c478bd9Sstevel@tonic-gate 	ret->rh_doorfd = -1;
7807c478bd9Sstevel@tonic-gate 	ret->rh_doorfd_old = -1;
7817c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_init(&ret->rh_lock, NULL);
7827c478bd9Sstevel@tonic-gate 
7837c478bd9Sstevel@tonic-gate 	handle_hold_subhandles(ret, RH_HOLD_ALL);
7847c478bd9Sstevel@tonic-gate 
7857c478bd9Sstevel@tonic-gate 	failed = ((ret->rh_iter = scf_iter_create(ret)) == NULL ||
7867c478bd9Sstevel@tonic-gate 	    (ret->rh_scope = scf_scope_create(ret)) == NULL ||
7877c478bd9Sstevel@tonic-gate 	    (ret->rh_service = scf_service_create(ret)) == NULL ||
7887c478bd9Sstevel@tonic-gate 	    (ret->rh_instance = scf_instance_create(ret)) == NULL ||
7897c478bd9Sstevel@tonic-gate 	    (ret->rh_snapshot = scf_snapshot_create(ret)) == NULL ||
7907c478bd9Sstevel@tonic-gate 	    (ret->rh_snaplvl = scf_snaplevel_create(ret)) == NULL ||
7917c478bd9Sstevel@tonic-gate 	    (ret->rh_pg = scf_pg_create(ret)) == NULL ||
7927c478bd9Sstevel@tonic-gate 	    (ret->rh_property = scf_property_create(ret)) == NULL ||
7937c478bd9Sstevel@tonic-gate 	    (ret->rh_value = scf_value_create(ret)) == NULL);
7947c478bd9Sstevel@tonic-gate 
7957c478bd9Sstevel@tonic-gate 	/*
7967c478bd9Sstevel@tonic-gate 	 * these subhandles count as internal references, not external ones.
7977c478bd9Sstevel@tonic-gate 	 */
7987c478bd9Sstevel@tonic-gate 	ret->rh_intrefs = ret->rh_extrefs;
7997c478bd9Sstevel@tonic-gate 	ret->rh_extrefs = 0;
8007c478bd9Sstevel@tonic-gate 	handle_rele_subhandles(ret, RH_HOLD_ALL);
8017c478bd9Sstevel@tonic-gate 
8027c478bd9Sstevel@tonic-gate 	if (failed) {
8037c478bd9Sstevel@tonic-gate 		scf_handle_destroy(ret);
8047c478bd9Sstevel@tonic-gate 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
8057c478bd9Sstevel@tonic-gate 		return (NULL);
8067c478bd9Sstevel@tonic-gate 	}
8077c478bd9Sstevel@tonic-gate 
8087c478bd9Sstevel@tonic-gate 	scf_value_set_count(ret->rh_value, default_debug);
8097c478bd9Sstevel@tonic-gate 	(void) scf_handle_decorate(ret, "debug", ret->rh_value);
8107c478bd9Sstevel@tonic-gate 
8117c478bd9Sstevel@tonic-gate 	return (ret);
8127c478bd9Sstevel@tonic-gate }
8137c478bd9Sstevel@tonic-gate 
814f6e214c7SGavin Maltby /*
815f6e214c7SGavin Maltby  * Fails with
816f6e214c7SGavin Maltby  *   _NO_MEMORY
817f6e214c7SGavin Maltby  *   _NO_SERVER - server door could not be open()ed
818f6e214c7SGavin Maltby  *		  door call failed
819f6e214c7SGavin Maltby  *		  door_info() failed
820f6e214c7SGavin Maltby  *   _VERSION_MISMATCH - server returned bad file descriptor
821f6e214c7SGavin Maltby  *			 server claimed bad request
822f6e214c7SGavin Maltby  *			 server reported version mismatch
823f6e214c7SGavin Maltby  *			 server refused with unknown reason
824f6e214c7SGavin Maltby  *   _INVALID_ARGUMENT
825f6e214c7SGavin Maltby  *   _NO_RESOURCES - server is out of memory
826f6e214c7SGavin Maltby  *   _PERMISSION_DENIED
827f6e214c7SGavin Maltby  *   _INTERNAL - could not set up entities or iters
828f6e214c7SGavin Maltby  *		 server response too big
829f6e214c7SGavin Maltby  */
830f6e214c7SGavin Maltby scf_handle_t *
_scf_handle_create_and_bind(scf_version_t ver)831f6e214c7SGavin Maltby _scf_handle_create_and_bind(scf_version_t ver)
832f6e214c7SGavin Maltby {
833f6e214c7SGavin Maltby 	scf_handle_t *h;
834f6e214c7SGavin Maltby 
835f6e214c7SGavin Maltby 	h = scf_handle_create(ver);
836f6e214c7SGavin Maltby 	if (h == NULL)
837f6e214c7SGavin Maltby 		return (NULL);
838f6e214c7SGavin Maltby 
839f6e214c7SGavin Maltby 	if (scf_handle_bind(h) == -1) {
840f6e214c7SGavin Maltby 		scf_handle_destroy(h);
841f6e214c7SGavin Maltby 		return (NULL);
842f6e214c7SGavin Maltby 	}
843f6e214c7SGavin Maltby 	return (h);
844f6e214c7SGavin Maltby }
845f6e214c7SGavin Maltby 
8467c478bd9Sstevel@tonic-gate int
scf_handle_decorate(scf_handle_t * handle,const char * name,scf_value_t * v)8477c478bd9Sstevel@tonic-gate scf_handle_decorate(scf_handle_t *handle, const char *name, scf_value_t *v)
8487c478bd9Sstevel@tonic-gate {
8497c478bd9Sstevel@tonic-gate 	if (v != SCF_DECORATE_CLEAR && handle != v->value_handle)
8507c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
8517c478bd9Sstevel@tonic-gate 
8527c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&handle->rh_lock);
8537c478bd9Sstevel@tonic-gate 	if (handle_is_bound(handle)) {
8547c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&handle->rh_lock);
8557c478bd9Sstevel@tonic-gate 		return (scf_set_error(SCF_ERROR_IN_USE));
8567c478bd9Sstevel@tonic-gate 	}
8577c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&handle->rh_lock);
8587c478bd9Sstevel@tonic-gate 
8597c478bd9Sstevel@tonic-gate 	if (strcmp(name, "debug") == 0) {
8607c478bd9Sstevel@tonic-gate 		if (v == SCF_DECORATE_CLEAR) {
8617c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_lock(&handle->rh_lock);
8627c478bd9Sstevel@tonic-gate 			handle->rh_debug = 0;
8637c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&handle->rh_lock);
8647c478bd9Sstevel@tonic-gate 		} else {
8657c478bd9Sstevel@tonic-gate 			uint64_t val;
8667c478bd9Sstevel@tonic-gate 			if (scf_value_get_count(v, &val) < 0)
8677c478bd9Sstevel@tonic-gate 				return (-1);		/* error already set */
8687c478bd9Sstevel@tonic-gate 
8697c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_lock(&handle->rh_lock);
8707c478bd9Sstevel@tonic-gate 			handle->rh_debug = (uid_t)val;
8717c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&handle->rh_lock);
8727c478bd9Sstevel@tonic-gate 		}
8737c478bd9Sstevel@tonic-gate 		return (0);
8747c478bd9Sstevel@tonic-gate 	}
8757c478bd9Sstevel@tonic-gate 	if (strcmp(name, "door_path") == 0) {
8767c478bd9Sstevel@tonic-gate 		char name[sizeof (handle->rh_doorpath)];
8777c478bd9Sstevel@tonic-gate 
8787c478bd9Sstevel@tonic-gate 		if (v == SCF_DECORATE_CLEAR) {
8797c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_lock(&handle->rh_lock);
8807c478bd9Sstevel@tonic-gate 			handle->rh_doorpath[0] = 0;
8817c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&handle->rh_lock);
8827c478bd9Sstevel@tonic-gate 		} else {
8837c478bd9Sstevel@tonic-gate 			ssize_t len;
8847c478bd9Sstevel@tonic-gate 
8857c478bd9Sstevel@tonic-gate 			if ((len = scf_value_get_astring(v, name,
8867c478bd9Sstevel@tonic-gate 			    sizeof (name))) < 0) {
8877c478bd9Sstevel@tonic-gate 				return (-1);		/* error already set */
8887c478bd9Sstevel@tonic-gate 			}
8897c478bd9Sstevel@tonic-gate 			if (len == 0 || len >= sizeof (name)) {
8907c478bd9Sstevel@tonic-gate 				return (scf_set_error(
8917c478bd9Sstevel@tonic-gate 				    SCF_ERROR_INVALID_ARGUMENT));
8927c478bd9Sstevel@tonic-gate 			}
8937c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_lock(&handle->rh_lock);
8947c478bd9Sstevel@tonic-gate 			(void) strlcpy(handle->rh_doorpath, name,
8957c478bd9Sstevel@tonic-gate 			    sizeof (handle->rh_doorpath));
8967c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&handle->rh_lock);
8977c478bd9Sstevel@tonic-gate 		}
8987c478bd9Sstevel@tonic-gate 		return (0);
8997c478bd9Sstevel@tonic-gate 	}
900048b0279SBryan Cantrill 
901048b0279SBryan Cantrill 	if (strcmp(name, "zone") == 0) {
902048b0279SBryan Cantrill 		char zone[MAXPATHLEN], root[MAXPATHLEN], door[MAXPATHLEN];
903048b0279SBryan Cantrill 		static int (*zone_get_rootpath)(char *, char *, size_t);
904