Home | History | Annotate | Download | only in common
      1     0    stevel /*
      2     0    stevel  * CDDL HEADER START
      3     0    stevel  *
      4     0    stevel  * The contents of this file are subject to the terms of the
      5  1780       gww  * Common Development and Distribution License (the "License").
      6  1780       gww  * You may not use this file except in compliance with the License.
      7     0    stevel  *
      8     0    stevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9     0    stevel  * or http://www.opensolaris.org/os/licensing.
     10     0    stevel  * See the License for the specific language governing permissions
     11     0    stevel  * and limitations under the License.
     12     0    stevel  *
     13     0    stevel  * When distributing Covered Code, include this CDDL HEADER in each
     14     0    stevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15     0    stevel  * If applicable, add the following below this CDDL HEADER, with the
     16     0    stevel  * fields enclosed by brackets "[]" replaced with your own identifying
     17     0    stevel  * information: Portions Copyright [yyyy] [name of copyright owner]
     18     0    stevel  *
     19     0    stevel  * CDDL HEADER END
     20     0    stevel  */
     21  5891       raf 
     22     0    stevel /*
     23  8497    Thomas  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     24     0    stevel  * Use is subject to license terms.
     25     0    stevel  */
     26     0    stevel 
     27     0    stevel /*
     28     0    stevel  * This is the main implementation file for the low-level repository
     29     0    stevel  * interface.
     30     0    stevel  */
     31     0    stevel 
     32     0    stevel #include "lowlevel_impl.h"
     33     0    stevel 
     34     0    stevel #include "repcache_protocol.h"
     35     0    stevel #include "scf_type.h"
     36     0    stevel 
     37     0    stevel #include <assert.h>
     38     0    stevel #include <alloca.h>
     39     0    stevel #include <door.h>
     40     0    stevel #include <errno.h>
     41     0    stevel #include <fcntl.h>
     42     0    stevel #include <fnmatch.h>
     43     0    stevel #include <libuutil.h>
     44     0    stevel #include <poll.h>
     45     0    stevel #include <pthread.h>
     46     0    stevel #include <stddef.h>
     47     0    stevel #include <stdio.h>
     48     0    stevel #include <stdlib.h>
     49     0    stevel #include <string.h>
     50     0    stevel #include <sys/mman.h>
     51     0    stevel #include <sys/sysmacros.h>
     52     0    stevel #include <unistd.h>
     53     0    stevel 
     54     0    stevel #define	ENV_SCF_DEBUG		"LIBSCF_DEBUG"
     55     0    stevel #define	ENV_SCF_DOORPATH	"LIBSCF_DOORPATH"
     56     0    stevel 
     57     0    stevel static uint32_t default_debug = 0;
     58     0    stevel static const char *default_door_path = REPOSITORY_DOOR_NAME;
     59     0    stevel 
     60     0    stevel #define	CALL_FAILED		-1
     61     0    stevel #define	RESULT_TOO_BIG		-2
     62     0    stevel #define	NOT_BOUND		-3
     63     0    stevel 
     64     0    stevel static pthread_mutex_t	lowlevel_init_lock;
     65     0    stevel static int32_t		lowlevel_inited;
     66     0    stevel 
     67     0    stevel static uu_list_pool_t	*tran_entry_pool;
     68     0    stevel static uu_list_pool_t	*datael_pool;
     69     0    stevel static uu_list_pool_t	*iter_pool;
     70  7887     Liane 
     71  7887     Liane /*
     72  7887     Liane  * base32[] index32[] are used in base32 encoding and decoding.
     73  7887     Liane  */
     74  7887     Liane static char base32[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
     75  7887     Liane static char index32[128] = {
     76  7887     Liane 	-1, -1, -1, -1, -1, -1, -1, -1,	/* 0-7 */
     77  7887     Liane 	-1, -1, -1, -1, -1, -1, -1, -1,	/* 8-15 */
     78  7887     Liane 	-1, -1, -1, -1, -1, -1, -1, -1,	/* 16-23 */
     79  7887     Liane 	-1, -1, -1, -1, -1, -1, -1, -1,	/* 24-31 */
     80  7887     Liane 	-1, -1, -1, -1, -1, -1, -1, -1,	/* 32-39 */
     81  7887     Liane 	-1, -1, -1, -1, -1, -1, -1, -1,	/* 40-47 */
     82  7887     Liane 	-1, -1, 26, 27, 28, 29, 30, 31,	/* 48-55 */
     83  7887     Liane 	-1, -1, -1, -1, -1, -1, -1, -1,	/* 56-63 */
     84  7887     Liane 	-1, 0, 1, 2, 3, 4, 5, 6,	/* 64-71 */
     85  7887     Liane 	7, 8, 9, 10, 11, 12, 13, 14,	/* 72-79 */
     86  7887     Liane 	15, 16, 17, 18, 19, 20, 21, 22,	/* 80-87 */
     87  7887     Liane 	23, 24, 25, -1, -1, -1, -1, -1,	/* 88-95 */
     88  7887     Liane 	-1, -1, -1, -1, -1, -1, -1, -1,	/* 96-103 */
     89  7887     Liane 	-1, -1, -1, -1, -1, -1, -1, -1,	/* 104-111 */
     90  7887     Liane 	-1, -1, -1, -1, -1, -1, -1, -1,	/* 112-119 */
     91  7887     Liane 	-1, -1, -1, -1, -1, -1, -1, -1	/* 120-127 */
     92  7887     Liane };
     93  7887     Liane 
     94  7887     Liane #define	DECODE32_GS	(8)	/* scf_decode32 group size */
     95     0    stevel 
     96     0    stevel /*
     97     0    stevel  * We want MUTEX_HELD, but we also want pthreads.
     98     0    stevel  */
     99     0    stevel struct _lwp_mutex;
    100     0    stevel extern int _mutex_held(struct _lwp_mutex *);
    101     0    stevel #define	MUTEX_HELD(m)		_mutex_held((struct _lwp_mutex *)(m))
    102     0    stevel 
    103     0    stevel #ifdef lint
    104     0    stevel #define	assert_nolint(x) (void)0
    105     0    stevel #else
    106     0    stevel #define	assert_nolint(x) assert(x)
    107     0    stevel #endif
    108     0    stevel 
    109     0    stevel static void scf_iter_reset_locked(scf_iter_t *iter);
    110     0    stevel static void scf_value_reset_locked(scf_value_t *val, int and_destroy);
    111     0    stevel 
    112     0    stevel #define	TYPE_VALUE	(-100)
    113     0    stevel 
    114     0    stevel /*
    115     0    stevel  * Hold and release subhandles.  We only allow one thread access to the
    116     0    stevel  * subhandles at a time, and he can use any subset, grabbing and releasing
    117     0    stevel  * them in any order.  The only restrictions are that you cannot hold an
    118     0    stevel  * already-held subhandle, and all subhandles must be released before
    119     0    stevel  * returning to the original caller.
    120     0    stevel  */
    121     0    stevel static void
    122     0    stevel handle_hold_subhandles(scf_handle_t *h, int mask)
    123     0    stevel {
    124     0    stevel 	assert(mask != 0 && (mask & ~RH_HOLD_ALL) == 0);
    125     0    stevel 
    126     0    stevel 	(void) pthread_mutex_lock(&h->rh_lock);
    127  5891       raf 	while (h->rh_hold_flags != 0 && h->rh_holder != pthread_self()) {
    128  5891       raf 		int cancel_state;
    129  5891       raf 
    130  5891       raf 		(void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,
    131  5891       raf 		    &cancel_state);
    132  5891       raf 		(void) pthread_cond_wait(&h->rh_cv, &h->rh_lock);
    133  5891       raf 		(void) pthread_setcancelstate(cancel_state, NULL);
    134  5891       raf 	}
    135     0    stevel 	if (h->rh_hold_flags == 0)
    136     0    stevel 		h->rh_holder = pthread_self();
    137     0    stevel 	assert(!(h->rh_hold_flags & mask));
    138     0    stevel 	h->rh_hold_flags |= mask;
    139     0    stevel 	(void) pthread_mutex_unlock(&h->rh_lock);
    140     0    stevel }
    141     0    stevel 
    142     0    stevel static void
    143     0    stevel handle_rele_subhandles(scf_handle_t *h, int mask)
    144     0    stevel {
    145     0    stevel 	assert(mask != 0 && (mask & ~RH_HOLD_ALL) == 0);
    146     0    stevel 
    147     0    stevel 	(void) pthread_mutex_lock(&h->rh_lock);
    148     0    stevel 	assert(h->rh_holder == pthread_self());
    149     0    stevel 	assert((h->rh_hold_flags & mask));
    150     0    stevel 
    151     0    stevel 	h->rh_hold_flags &= ~mask;
    152     0    stevel 	if (h->rh_hold_flags == 0)
    153     0    stevel 		(void) pthread_cond_signal(&h->rh_cv);
    154     0    stevel 	(void) pthread_mutex_unlock(&h->rh_lock);
    155     0    stevel }
    156     0    stevel 
    157     0    stevel #define	HOLD_HANDLE(h, flag, field) \
    158     0    stevel 	(handle_hold_subhandles((h), (flag)), (h)->field)
    159     0    stevel 
    160     0    stevel #define	RELE_HANDLE(h, flag) \
    161     0    stevel 	(handle_rele_subhandles((h), (flag)))
    162     0    stevel 
    163     0    stevel /*
    164     0    stevel  * convenience macros, for functions that only need a one or two handles at
    165     0    stevel  * any given time
    166     0    stevel  */
    167     0    stevel #define	HANDLE_HOLD_ITER(h)	HOLD_HANDLE((h), RH_HOLD_ITER, rh_iter)
    168     0    stevel #define	HANDLE_HOLD_SCOPE(h)	HOLD_HANDLE((h), RH_HOLD_SCOPE, rh_scope)
    169     0    stevel #define	HANDLE_HOLD_SERVICE(h)	HOLD_HANDLE((h), RH_HOLD_SERVICE, rh_service)
    170     0    stevel #define	HANDLE_HOLD_INSTANCE(h)	HOLD_HANDLE((h), RH_HOLD_INSTANCE, rh_instance)
    171     0    stevel #define	HANDLE_HOLD_SNAPSHOT(h)	HOLD_HANDLE((h), RH_HOLD_SNAPSHOT, rh_snapshot)
    172     0    stevel #define	HANDLE_HOLD_SNAPLVL(h)	HOLD_HANDLE((h), RH_HOLD_SNAPLVL, rh_snaplvl)
    173     0    stevel #define	HANDLE_HOLD_PG(h)	HOLD_HANDLE((h), RH_HOLD_PG, rh_pg)
    174     0    stevel #define	HANDLE_HOLD_PROPERTY(h)	HOLD_HANDLE((h), RH_HOLD_PROPERTY, rh_property)
    175     0    stevel #define	HANDLE_HOLD_VALUE(h)	HOLD_HANDLE((h), RH_HOLD_VALUE, rh_value)
    176     0    stevel 
    177     0    stevel #define	HANDLE_RELE_ITER(h)	RELE_HANDLE((h), RH_HOLD_ITER)
    178     0    stevel #define	HANDLE_RELE_SCOPE(h)	RELE_HANDLE((h), RH_HOLD_SCOPE)
    179     0    stevel #define	HANDLE_RELE_SERVICE(h)	RELE_HANDLE((h), RH_HOLD_SERVICE)
    180     0    stevel #define	HANDLE_RELE_INSTANCE(h)	RELE_HANDLE((h), RH_HOLD_INSTANCE)
    181     0    stevel #define	HANDLE_RELE_SNAPSHOT(h)	RELE_HANDLE((h), RH_HOLD_SNAPSHOT)
    182     0    stevel #define	HANDLE_RELE_SNAPLVL(h)	RELE_HANDLE((h), RH_HOLD_SNAPLVL)
    183     0    stevel #define	HANDLE_RELE_PG(h)	RELE_HANDLE((h), RH_HOLD_PG)
    184     0    stevel #define	HANDLE_RELE_PROPERTY(h)	RELE_HANDLE((h), RH_HOLD_PROPERTY)
    185     0    stevel #define	HANDLE_RELE_VALUE(h)	RELE_HANDLE((h), RH_HOLD_VALUE)
    186     0    stevel 
    187     0    stevel /*ARGSUSED*/
    188     0    stevel static int
    189     0    stevel transaction_entry_compare(const void *l_arg, const void *r_arg, void *private)
    190     0    stevel {
    191     0    stevel 	const char *l_prop =
    192     0    stevel 	    ((scf_transaction_entry_t *)l_arg)->entry_property;
    193     0    stevel 	const char *r_prop =
    194     0    stevel 	    ((scf_transaction_entry_t *)r_arg)->entry_property;
    195     0    stevel 
    196     0    stevel 	int ret;
    197     0    stevel 
    198     0    stevel 	ret = strcmp(l_prop, r_prop);
    199     0    stevel 	if (ret > 0)
    200     0    stevel 		return (1);
    201   407   jwadams 	if (ret < 0)
    202   407   jwadams 		return (-1);
    203   407   jwadams 	return (0);
    204   407   jwadams }
    205   407   jwadams 
    206   407   jwadams static int
    207   407   jwadams datael_compare(const void *l_arg, const void *r_arg, void *private)
    208   407   jwadams {
    209   407   jwadams 	uint32_t l_id = ((scf_datael_t *)l_arg)->rd_entity;
    210   407   jwadams 	uint32_t r_id = (r_arg != NULL) ? ((scf_datael_t *)r_arg)->rd_entity :
    211   407   jwadams 	    *(uint32_t *)private;
    212   407   jwadams 
    213   407   jwadams 	if (l_id > r_id)
    214   407   jwadams 		return (1);
    215   407   jwadams 	if (l_id < r_id)
    216   407   jwadams 		return (-1);
    217   407   jwadams 	return (0);
    218   407   jwadams }
    219   407   jwadams 
    220   407   jwadams static int
    221   407   jwadams iter_compare(const void *l_arg, const void *r_arg, void *private)
    222   407   jwadams {
    223   407   jwadams 	uint32_t l_id = ((scf_iter_t *)l_arg)->iter_id;
    224   407   jwadams 	uint32_t r_id = (r_arg != NULL) ? ((scf_iter_t *)r_arg)->iter_id :
    225   407   jwadams 	    *(uint32_t *)private;
    226   407   jwadams 
    227   407   jwadams 	if (l_id > r_id)
    228   407   jwadams 		return (1);
    229   407   jwadams 	if (l_id < r_id)
    230     0    stevel 		return (-1);
    231     0    stevel 	return (0);
    232     0    stevel }
    233     0    stevel 
    234     0    stevel static int
    235     0    stevel lowlevel_init(void)
    236     0    stevel {
    237     0    stevel 	const char *debug;
    238     0    stevel 	const char *door_path;
    239     0    stevel 
    240     0    stevel 	(void) pthread_mutex_lock(&lowlevel_init_lock);
    241     0    stevel 	if (lowlevel_inited == 0) {
    242     0    stevel 		if (!issetugid() &&
    243     0    stevel 		    (debug = getenv(ENV_SCF_DEBUG)) != NULL && debug[0] != 0 &&
    244     0    stevel 		    uu_strtoint(debug, &default_debug, sizeof (default_debug),
    245     0    stevel 		    0, 0, 0) == -1) {
    246     0    stevel 			(void) fprintf(stderr, "LIBSCF: $%s (%s): %s",
    247     0    stevel 			    ENV_SCF_DEBUG, debug,
    248     0    stevel 			    uu_strerror(uu_error()));
    249     0    stevel 		}
    250     0    stevel 
    251     0    stevel 		if (!issetugid() &&
    252     0    stevel 		    (door_path = getenv(ENV_SCF_DOORPATH)) != NULL &&
    253     0    stevel 		    door_path[0] != 0) {
    254     0    stevel 			default_door_path = strdup(door_path);
    255     0    stevel 			if (default_door_path == NULL)
    256     0    stevel 				default_door_path = door_path;
    257     0    stevel 		}
    258     0    stevel 
    259     0    stevel 		datael_pool = uu_list_pool_create("SUNW,libscf_datael",
    260     0    stevel 		    sizeof (scf_datael_t), offsetof(scf_datael_t, rd_node),
    261   407   jwadams 		    datael_compare, UU_LIST_POOL_DEBUG);
    262     0    stevel 
    263     0    stevel 		iter_pool = uu_list_pool_create("SUNW,libscf_iter",
    264     0    stevel 		    sizeof (scf_iter_t), offsetof(scf_iter_t, iter_node),
    265   407   jwadams 		    iter_compare, UU_LIST_POOL_DEBUG);
    266     0    stevel 
    267     0    stevel 		assert_nolint(offsetof(scf_transaction_entry_t,
    268     0    stevel 		    entry_property) == 0);
    269     0    stevel 		tran_entry_pool = uu_list_pool_create(
    270     0    stevel 		    "SUNW,libscf_transaction_entity",
    271     0    stevel 		    sizeof (scf_transaction_entry_t),
    272     0    stevel 		    offsetof(scf_transaction_entry_t, entry_link),
    273     0    stevel 		    transaction_entry_compare, UU_LIST_POOL_DEBUG);
    274     0    stevel 
    275     0    stevel 		if (datael_pool == NULL || iter_pool == NULL ||
    276     0    stevel 		    tran_entry_pool == NULL) {
    277     0    stevel 			lowlevel_inited = -1;
    278     0    stevel 			goto end;
    279     0    stevel 		}
    280     0    stevel 
    281     0    stevel 		if (!scf_setup_error()) {
    282     0    stevel 			lowlevel_inited = -1;
    283     0    stevel 			goto end;
    284     0    stevel 		}
    285     0    stevel 		lowlevel_inited = 1;
    286     0    stevel 	}
    287     0    stevel end:
    288     0    stevel 	(void) pthread_mutex_unlock(&lowlevel_init_lock);
    289     0    stevel 	if (lowlevel_inited > 0)
    290     0    stevel 		return (1);
    291     0    stevel 	return (0);
    292     0    stevel }
    293     0    stevel 
    294     0    stevel static const struct {
    295     0    stevel 	scf_type_t ti_type;
    296     0    stevel 	rep_protocol_value_type_t ti_proto_type;
    297     0    stevel 	const char *ti_name;
    298     0    stevel } scf_type_info[] = {
    299     0    stevel 	{SCF_TYPE_BOOLEAN,	REP_PROTOCOL_TYPE_BOOLEAN,	"boolean"},
    300     0    stevel 	{SCF_TYPE_COUNT,	REP_PROTOCOL_TYPE_COUNT,	"count"},
    301     0    stevel 	{SCF_TYPE_INTEGER,	REP_PROTOCOL_TYPE_INTEGER,	"integer"},
    302     0    stevel 	{SCF_TYPE_TIME,		REP_PROTOCOL_TYPE_TIME,		"time"},
    303     0    stevel 	{SCF_TYPE_ASTRING,	REP_PROTOCOL_TYPE_STRING,	"astring"},
    304     0    stevel 	{SCF_TYPE_OPAQUE,	REP_PROTOCOL_TYPE_OPAQUE,	"opaque"},
    305     0    stevel 	{SCF_TYPE_USTRING,	REP_PROTOCOL_SUBTYPE_USTRING,	"ustring"},
    306     0    stevel 	{SCF_TYPE_URI,		REP_PROTOCOL_SUBTYPE_URI,	"uri"},
    307     0    stevel 	{SCF_TYPE_FMRI,		REP_PROTOCOL_SUBTYPE_FMRI,	"fmri"},
    308     0    stevel 	{SCF_TYPE_HOST,		REP_PROTOCOL_SUBTYPE_HOST,	"host"},
    309     0    stevel 	{SCF_TYPE_HOSTNAME,	REP_PROTOCOL_SUBTYPE_HOSTNAME,	"hostname"},
    310     0    stevel 	{SCF_TYPE_NET_ADDR_V4,	REP_PROTOCOL_SUBTYPE_NETADDR_V4,
    311     0    stevel 	    "net_address_v4"},
    312     0    stevel 	{SCF_TYPE_NET_ADDR_V6,	REP_PROTOCOL_SUBTYPE_NETADDR_V6,
    313     0    stevel 	    "net_address_v6"}
    314     0    stevel };
    315     0    stevel 
    316     0    stevel #define	SCF_TYPE_INFO_COUNT (sizeof (scf_type_info) / sizeof (*scf_type_info))
    317     0    stevel static rep_protocol_value_type_t
    318     0    stevel scf_type_to_protocol_type(scf_type_t t)
    319     0    stevel {
    320     0    stevel 	int i;
    321     0    stevel 
    322     0    stevel 	for (i = 0; i < SCF_TYPE_INFO_COUNT; i++)
    323     0    stevel 		if (scf_type_info[i].ti_type == t)
    324     0    stevel 			return (scf_type_info[i].ti_proto_type);
    325     0    stevel 
    326     0    stevel 	return (REP_PROTOCOL_TYPE_INVALID);
    327     0    stevel }
    328     0    stevel 
    329     0    stevel static scf_type_t
    330     0    stevel scf_protocol_type_to_type(rep_protocol_value_type_t t)
    331     0    stevel {
    332     0    stevel 	int i;
    333     0    stevel 
    334     0    stevel 	for (i = 0; i < SCF_TYPE_INFO_COUNT; i++)
    335     0    stevel 		if (scf_type_info[i].ti_proto_type == t)
    336     0    stevel 			return (scf_type_info[i].ti_type);
    337     0    stevel 
    338     0    stevel 	return (SCF_TYPE_INVALID);
    339     0    stevel }
    340     0    stevel 
    341     0    stevel const char *
    342     0    stevel scf_type_to_string(scf_type_t ty)
    343     0    stevel {
    344     0    stevel 	int i;
    345     0    stevel 
    346     0    stevel 	for (i = 0; i < SCF_TYPE_INFO_COUNT; i++)
    347     0    stevel 		if (scf_type_info[i].ti_type == ty)
    348     0    stevel 			return (scf_type_info[i].ti_name);
    349     0    stevel 
    350     0    stevel 	return ("unknown");
    351     0    stevel }
    352     0    stevel 
    353     0    stevel scf_type_t
    354     0    stevel scf_string_to_type(const char *name)
    355     0    stevel {
    356     0    stevel 	int i;
    357     0    stevel 
    358     0    stevel 	for (i = 0; i < sizeof (scf_type_info) / sizeof (*scf_type_info); i++)
    359     0    stevel 		if (strcmp(scf_type_info[i].ti_name, name) == 0)
    360     0    stevel 			return (scf_type_info[i].ti_type);
    361     0    stevel 
    362     0    stevel 	return (SCF_TYPE_INVALID);
    363     0    stevel }
    364     0    stevel 
    365     0    stevel int
    366     0    stevel scf_type_base_type(scf_type_t type, scf_type_t *out)
    367     0    stevel {
    368     0    stevel 	rep_protocol_value_type_t t = scf_type_to_protocol_type(type);
    369     0    stevel 	if (t == REP_PROTOCOL_TYPE_INVALID)
    370     0    stevel 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
    371     0    stevel 
    372     0    stevel 	*out = scf_protocol_type_to_type(scf_proto_underlying_type(t));
    373     0    stevel 	return (SCF_SUCCESS);
    374     0    stevel }
    375     0    stevel 
    376     0    stevel /*
    377     0    stevel  * Convert a protocol error code into an SCF_ERROR_* code.
    378     0    stevel  */
    379     0    stevel static scf_error_t
    380     0    stevel proto_error(rep_protocol_responseid_t e)
    381     0    stevel {
    382     0    stevel 	switch (e) {
    383     0    stevel 	case REP_PROTOCOL_FAIL_MISORDERED:
    384     0    stevel 	case REP_PROTOCOL_FAIL_UNKNOWN_ID:
    385     0    stevel 	case REP_PROTOCOL_FAIL_INVALID_TYPE:
    386     0    stevel 	case REP_PROTOCOL_FAIL_TRUNCATED:
    387     0    stevel 	case REP_PROTOCOL_FAIL_TYPE_MISMATCH:
    388     0    stevel 	case REP_PROTOCOL_FAIL_NOT_APPLICABLE:
    389     0    stevel 	case REP_PROTOCOL_FAIL_UNKNOWN:
    390     0    stevel 		return (SCF_ERROR_INTERNAL);
    391     0    stevel 
    392     0    stevel 	case REP_PROTOCOL_FAIL_BAD_TX:
    393     0    stevel 		return (SCF_ERROR_INVALID_ARGUMENT);
    394     0    stevel 	case REP_PROTOCOL_FAIL_BAD_REQUEST:
    395     0    stevel 		return (SCF_ERROR_INVALID_ARGUMENT);
    396     0    stevel 	case REP_PROTOCOL_FAIL_NO_RESOURCES:
    397     0    stevel 		return (SCF_ERROR_NO_RESOURCES);
    398     0    stevel 	case REP_PROTOCOL_FAIL_NOT_FOUND:
    399     0    stevel 		return (SCF_ERROR_NOT_FOUND);
    400     0    stevel 	case REP_PROTOCOL_FAIL_DELETED:
    401     0    stevel 		return (SCF_ERROR_DELETED);
    402     0    stevel 	case REP_PROTOCOL_FAIL_NOT_SET:
    403     0    stevel 		return (SCF_ERROR_NOT_SET);
    404     0    stevel 	case REP_PROTOCOL_FAIL_EXISTS:
    405     0    stevel 		return (SCF_ERROR_EXISTS);
    406     0    stevel 	case REP_PROTOCOL_FAIL_DUPLICATE_ID:
    407     0    stevel 		return (SCF_ERROR_EXISTS);
    408     0    stevel 	case REP_PROTOCOL_FAIL_PERMISSION_DENIED:
    409     0    stevel 		return (SCF_ERROR_PERMISSION_DENIED);
    410     0    stevel 	case REP_PROTOCOL_FAIL_BACKEND_ACCESS:
    411     0    stevel 		return (SCF_ERROR_BACKEND_ACCESS);
    412     0    stevel 	case REP_PROTOCOL_FAIL_BACKEND_READONLY:
    413     0    stevel 		return (SCF_ERROR_BACKEND_READONLY);
    414     0    stevel 
    415     0    stevel 	case REP_PROTOCOL_SUCCESS:
    416     0    stevel 	case REP_PROTOCOL_DONE:
    417     0    stevel 	case REP_PROTOCOL_FAIL_NOT_LATEST:	/* TX code should handle this */
    418     0    stevel 	default:
    419     0    stevel #ifndef NDEBUG
    420     0    stevel 		uu_warn("%s:%d: Bad error code %d passed to proto_error().\n",
    421     0    stevel 		    __FILE__, __LINE__, e);
    422     0    stevel #endif
    423     0    stevel 		abort();
    424     0    stevel 		/*NOTREACHED*/
    425     0    stevel 	}
    426     0    stevel }
    427     0    stevel 
    428     0    stevel ssize_t
    429     0    stevel scf_limit(uint32_t limit)
    430     0    stevel {
    431     0    stevel 	switch (limit) {
    432     0    stevel 	case SCF_LIMIT_MAX_NAME_LENGTH:
    433     0    stevel 	case SCF_LIMIT_MAX_PG_TYPE_LENGTH:
    434     0    stevel 		return (REP_PROTOCOL_NAME_LEN - 1);
    435     0    stevel 	case SCF_LIMIT_MAX_VALUE_LENGTH:
    436     0    stevel 		return (REP_PROTOCOL_VALUE_LEN - 1);
    437     0    stevel 	case SCF_LIMIT_MAX_FMRI_LENGTH:
    438     0    stevel 		return (SCF_FMRI_PREFIX_MAX_LEN +
    439     0    stevel 		    sizeof (SCF_FMRI_SCOPE_PREFIX) - 1 +
    440     0    stevel 		    sizeof (SCF_FMRI_SCOPE_SUFFIX) - 1 +
    441     0    stevel 		    sizeof (SCF_FMRI_SERVICE_PREFIX) - 1 +
    442     0    stevel 		    sizeof (SCF_FMRI_INSTANCE_PREFIX) - 1 +
    443     0    stevel 		    sizeof (SCF_FMRI_PROPERTYGRP_PREFIX) - 1 +
    444     0    stevel 		    sizeof (SCF_FMRI_PROPERTY_PREFIX) - 1 +
    445     0    stevel 		    5 * (REP_PROTOCOL_NAME_LEN - 1));
    446     0    stevel 	default:
    447     0    stevel 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
    448     0    stevel 	}
    449     0    stevel }
    450     0    stevel 
    451     0    stevel static size_t
    452     0    stevel scf_opaque_decode(char *out_arg, const char *in, size_t max_out)
    453     0    stevel {
    454     0    stevel 	char a, b;
    455     0    stevel 	char *out = out_arg;
    456     0    stevel 
    457     0    stevel 	while (max_out > 0 && (a = in[0]) != 0 && (b = in[1]) != 0) {
    458     0    stevel 		in += 2;
    459     0    stevel 
    460     0    stevel 		if (a >= '0' && a <= '9')
    461     0    stevel 			a -= '0';
    462     0    stevel 		else if (a >= 'a' && a <= 'f')
    463     0    stevel 			a = a - 'a' + 10;
    464     0    stevel 		else if (a >= 'A' && a <= 'F')
    465     0    stevel 			a = a - 'A' + 10;
    466     0    stevel 		else
    467     0    stevel 			break;
    468     0    stevel 
    469     0    stevel 		if (b >= '0' && b <= '9')
    470     0    stevel 			b -= '0';
    471     0    stevel 		else if (b >= 'a' && b <= 'f')
    472     0    stevel 			b = b - 'a' + 10;
    473     0    stevel 		else if (b >= 'A' && b <= 'F')
    474     0    stevel 			b = b - 'A' + 10;
    475     0    stevel 		else
    476     0    stevel 			break;
    477     0    stevel 
    478     0    stevel 		*out++ = (a << 4) | b;
    479     0    stevel 		max_out--;
    480     0    stevel 	}
    481     0    stevel 
    482     0    stevel 	return (out - out_arg);
    483     0    stevel }
    484     0    stevel 
    485     0    stevel static size_t
    486     0    stevel scf_opaque_encode(char *out_arg, const char *in_arg, size_t in_sz)
    487     0    stevel {
    488     0    stevel 	uint8_t *in = (uint8_t *)in_arg;
    489     0    stevel 	uint8_t *end = in + in_sz;
    490     0    stevel 	char *out = out_arg;
    491     0    stevel 
    492     0    stevel 	if (out == NULL)
    493     0    stevel 		return (2 * in_sz);
    494     0    stevel 
    495     0    stevel 	while (in < end) {
    496     0    stevel 		uint8_t c = *in++;
    497     0    stevel 
    498     0    stevel 		uint8_t a = (c & 0xf0) >> 4;
    499     0    stevel 		uint8_t b = (c & 0x0f);
    500     0    stevel 
    501     0    stevel 		if (a <= 9)
    502     0    stevel 			*out++ = a + '0';
    503     0    stevel 		else
    504     0    stevel 			*out++ = a + 'a' - 10;
    505     0    stevel 
    506     0    stevel 		if (b <= 9)
    507     0    stevel 			*out++ = b + '0';
    508     0    stevel 		else
    509     0    stevel 			*out++ = b + 'a' - 10;
    510     0    stevel 	}
    511     0    stevel 
    512     0    stevel 	*out = 0;
    513     0    stevel 
    514     0    stevel 	return (out - out_arg);
    515     0    stevel }
    516     0    stevel 
    517     0    stevel static void
    518     0    stevel handle_do_close(scf_handle_t *h)
    519     0    stevel {
    520     0    stevel 	assert(MUTEX_HELD(&h->rh_lock));
    521     0    stevel 	assert(h->rh_doorfd != -1);
    522     0    stevel 
    523     0    stevel 	/*
    524     0    stevel 	 * if there are any active FD users, we just move the FD over
    525     0    stevel 	 * to rh_doorfd_old -- they'll close it when they finish.
    526     0    stevel 	 */
    527     0    stevel 	if (h->rh_fd_users > 0) {
    528     0    stevel 		h->rh_doorfd_old = h->rh_doorfd;
    529     0    stevel 		h->rh_doorfd = -1;
    530     0    stevel 	} else {
    531     0    stevel 		assert(h->rh_doorfd_old == -1);
    532     0    stevel 		(void) close(h->rh_doorfd);
    533     0    stevel 		h->rh_doorfd = -1;
    534     0    stevel 	}
    535     0    stevel }
    536     0    stevel 
    537     0    stevel /*
    538     0    stevel  * Check if a handle is currently bound.  fork()ing implicitly unbinds
    539     0    stevel  * the handle in the child.
    540     0    stevel  */
    541     0    stevel static int
    542     0    stevel handle_is_bound(scf_handle_t *h)
    543     0    stevel {
    544     0    stevel 	assert(MUTEX_HELD(&h->rh_lock));
    545     0    stevel 
    546     0    stevel 	if (h->rh_doorfd == -1)
    547     0    stevel 		return (0);
    548     0    stevel 
    549     0    stevel 	if (getpid() == h->rh_doorpid)
    550     0    stevel 		return (1);
    551     0    stevel 
    552     0    stevel 	/* forked since our last bind -- initiate handle close */
    553     0    stevel 	handle_do_close(h);
    554     0    stevel 	return (0);
    555     0    stevel }
    556     0    stevel 
    557     0    stevel static int
    558   407   jwadams handle_has_server_locked(scf_handle_t *h)
    559   407   jwadams {
    560   407   jwadams 	door_info_t i;
    561   407   jwadams 	assert(MUTEX_HELD(&h->rh_lock));
    562   407   jwadams 
    563   407   jwadams 	return (handle_is_bound(h) && door_info(h->rh_doorfd, &i) != -1 &&
    564   407   jwadams 	    i.di_target != -1);
    565   407   jwadams }
    566   407   jwadams 
    567   407   jwadams static int
    568     0    stevel handle_has_server(scf_handle_t *h)
    569     0    stevel {
    570   407   jwadams 	int ret;
    571   407   jwadams 
    572   407   jwadams 	(void) pthread_mutex_lock(&h->rh_lock);
    573   407   jwadams 	ret = handle_has_server_locked(h);
    574     0    stevel 	(void) pthread_mutex_unlock(&h->rh_lock);
    575     0    stevel 
    576     0    stevel 	return (ret);
    577     0    stevel }
    578     0    stevel 
    579     0    stevel /*
    580     0    stevel  * This makes a door request on the client door associated with handle h.
    581     0    stevel  * It will automatically retry calls which fail on EINTR.  If h is not bound,
    582     0    stevel  * returns NOT_BOUND.  If the door call fails or the server response is too
    583     0    stevel  * small, returns CALL_FAILED.  If the server response is too big, truncates the
    584     0    stevel  * response and returns RESULT_TOO_BIG.  Otherwise, the size of the result is
    585     0    stevel  * returned.
    586     0    stevel  */
    587     0    stevel static ssize_t
    588     0    stevel make_door_call(scf_handle_t *h, const void *req, size_t req_sz,
    589     0    stevel     void *res, size_t res_sz)
    590     0    stevel {
    591     0    stevel 	door_arg_t arg;
    592     0    stevel 	int r;
    593     0    stevel 
    594     0    stevel 	assert(MUTEX_HELD(&h->rh_lock));
    595     0    stevel 
    596     0    stevel 	if (!handle_is_bound(h)) {
    597     0    stevel 		return (NOT_BOUND);
    598     0    stevel 	}
    599     0    stevel 
    600     0    stevel 	arg.data_ptr = (void *)req;
    601     0    stevel 	arg.data_size = req_sz;
    602     0    stevel 	arg.desc_ptr = NULL;
    603     0    stevel 	arg.desc_num = 0;
    604     0    stevel 	arg.rbuf = res;
    605     0    stevel 	arg.rsize = res_sz;
    606     0    stevel 
    607     0    stevel 	while ((r = door_call(h->rh_doorfd, &arg)) < 0) {
    608     0    stevel 		if (errno != EINTR)
    609     0    stevel 			break;
    610     0    stevel 	}
    611     0    stevel 
    612     0    stevel 	if (r < 0) {
    613     0    stevel 		return (CALL_FAILED);
    614     0    stevel 	}
    615     0    stevel 
    616     0    stevel 	if (arg.desc_num > 0) {
    617     0    stevel 		while (arg.desc_num > 0) {
    618     0    stevel 			if (arg.desc_ptr->d_attributes & DOOR_DESCRIPTOR) {
    619     0    stevel 				int cfd = arg.desc_ptr->d_data.d_desc.d_id;
    620     0    stevel 				(void) close(cfd);
    621     0    stevel 			}
    622     0    stevel 			arg.desc_ptr++;
    623     0    stevel 			arg.desc_num--;
    624     0    stevel 		}
    625     0    stevel 	}
    626     0    stevel 	if (arg.data_ptr != res && arg.data_size > 0)
    627     0    stevel 		(void) memmove(res, arg.data_ptr, MIN(arg.data_size, res_sz));
    628     0    stevel 
    629     0    stevel 	if (arg.rbuf != res)
    630     0    stevel 		(void) munmap(arg.rbuf, arg.rsize);
    631     0    stevel 
    632     0    stevel 	if (arg.data_size > res_sz)
    633     0    stevel 		return (RESULT_TOO_BIG);
    634     0    stevel 
    635     0    stevel 	if (arg.data_size < sizeof (uint32_t))
    636     0    stevel 		return (CALL_FAILED);
    637     0    stevel 
    638     0    stevel 	return (arg.data_size);
    639     0    stevel }
    640     0    stevel 
    641     0    stevel /*
    642     0    stevel  * Should only be used when r < 0.
    643     0    stevel  */
    644     0    stevel #define	DOOR_ERRORS_BLOCK(r)	{					\
    645     0    stevel 	switch (r) {							\
    646     0    stevel 	case NOT_BOUND:							\
    647     0    stevel 		return (scf_set_error(SCF_ERROR_NOT_BOUND));		\
    648     0    stevel 									\
    649     0    stevel 	case CALL_FAILED:						\
    650     0    stevel 		return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN));	\
    651     0    stevel 									\
    652     0    stevel 	case RESULT_TOO_BIG:						\
    653     0    stevel 		return (scf_set_error(SCF_ERROR_INTERNAL));		\
    654     0    stevel 									\
    655     0    stevel 	default:							\
    656     0    stevel 		assert(r == NOT_BOUND || r == CALL_FAILED ||		\
    657     0    stevel 		    r == RESULT_TOO_BIG);				\
    658     0    stevel 		abort();						\
    659     0    stevel 	}								\
    660     0    stevel }
    661     0    stevel 
    662     0    stevel /*
    663     0    stevel  * Like make_door_call(), but takes an fd instead of a handle, and expects
    664     0    stevel  * a single file descriptor, returned via res_fd.
    665     0    stevel  *
    666     0    stevel  * If no file descriptor is returned, *res_fd == -1.
    667     0    stevel  */
    668     0    stevel static int
    669     0    stevel make_door_call_retfd(int fd, const void *req, size_t req_sz, void *res,
    670     0    stevel     size_t res_sz, int *res_fd)
    671     0    stevel {
    672     0    stevel 	door_arg_t arg;
    673     0    stevel 	int r;
    674     0    stevel 	char rbuf[256];
    675     0    stevel 
    676     0    stevel 	*res_fd = -1;
    677     0    stevel 
    678     0    stevel 	if (fd == -1)
    679     0    stevel 		return (NOT_BOUND);
    680     0    stevel 
    681     0    stevel 	arg.data_ptr = (void *)req;
    682     0    stevel 	arg.data_size = req_sz;
    683     0    stevel 	arg.desc_ptr = NULL;
    684     0    stevel 	arg.desc_num = 0;
    685     0    stevel 	arg.rbuf = rbuf;
    686     0    stevel 	arg.rsize = sizeof (rbuf);
    687     0    stevel 
    688     0    stevel 	while ((r = door_call(fd, &arg)) < 0) {
    689     0    stevel 		if (errno != EINTR)
    690     0    stevel 			break;
    691     0    stevel 	}
    692     0    stevel 
    693     0    stevel 	if (r < 0)
    694     0    stevel 		return (CALL_FAILED);
    695     0    stevel 
    696     0    stevel 	if (arg.desc_num > 1) {
    697     0    stevel 		while (arg.desc_num > 0) {
    698     0    stevel 			if (arg.desc_ptr->d_attributes & DOOR_DESCRIPTOR) {
    699     0    stevel 				int cfd =
    700     0    stevel 				    arg.desc_ptr->d_data.d_desc.d_descriptor;
    701     0    stevel 				(void) close(cfd);
    702     0    stevel 			}
    703     0    stevel 			arg.desc_ptr++;
    704     0    stevel 			arg.desc_num--;
    705     0    stevel 		}
    706     0    stevel 	}
    707     0    stevel 	if (arg.desc_num == 1 && arg.desc_ptr->d_attributes & DOOR_DESCRIPTOR)
    708     0    stevel 		*res_fd = arg.desc_ptr->d_data.d_desc.d_descriptor;
    709     0    stevel 
    710     0    stevel 	if (arg.data_size > 0)
    711     0    stevel 		(void) memmove(res, arg.data_ptr, MIN(arg.data_size, res_sz));
    712     0    stevel 
    713     0    stevel 	if (arg.rbuf != rbuf)
    714     0    stevel 		(void) munmap(arg.rbuf, arg.rsize);
    715     0    stevel 
    716     0    stevel 	if (arg.data_size > res_sz)
    717     0    stevel 		return (RESULT_TOO_BIG);
    718     0    stevel 
    719     0    stevel 	if (arg.data_size < sizeof (uint32_t))
    720     0    stevel 		return (CALL_FAILED);
    721     0    stevel 
    722     0    stevel 	return (arg.data_size);
    723     0    stevel }
    724     0    stevel 
    725     0    stevel /*
    726     0    stevel  * Fails with
    727     0    stevel  *   _VERSION_MISMATCH
    728     0    stevel  *   _NO_MEMORY
    729     0    stevel  */
    730     0    stevel scf_handle_t *
    731     0    stevel scf_handle_create(scf_version_t v)
    732     0    stevel {
    733     0    stevel 	scf_handle_t *ret;
    734     0    stevel 	int failed;
    735     0    stevel 
    736     0    stevel 	/*
    737     0    stevel 	 * This will need to be revisited when we bump SCF_VERSION
    738     0    stevel 	 */
    739     0    stevel 	if (v != SCF_VERSION) {
    740     0    stevel 		(void) scf_set_error(SCF_ERROR_VERSION_MISMATCH);
    741     0    stevel 		return (NULL);
    742     0    stevel 	}
    743     0    stevel 
    744     0    stevel 	if (!lowlevel_init()) {
    745     0    stevel 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
    746     0    stevel 		return (NULL);
    747     0    stevel 	}
    748     0    stevel 
    749     0    stevel 	ret = uu_zalloc(sizeof (*ret));
    750     0    stevel 	if (ret == NULL) {
    751     0    stevel 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
    752     0    stevel 		return (NULL);
    753     0    stevel 	}
    754     0    stevel 
    755     0    stevel 	ret->rh_dataels = uu_list_create(datael_pool, ret, 0);
    756     0    stevel 	ret->rh_iters = uu_list_create(iter_pool, ret, 0);
    757     0    stevel 	if (ret->rh_dataels == NULL || ret->rh_iters == NULL) {
    758     0    stevel 		if (ret->rh_dataels != NULL)
    759     0    stevel 			uu_list_destroy(ret->rh_dataels);
    760     0    stevel 		if (ret->rh_iters != NULL)
    761     0    stevel 			uu_list_destroy(ret->rh_iters);
    762     0    stevel 		uu_free(ret);
    763     0    stevel 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
    764     0    stevel 		return (NULL);
    765     0    stevel 	}
    766     0    stevel 
    767     0    stevel 	ret->rh_doorfd = -1;
    768     0    stevel 	ret->rh_doorfd_old = -1;
    769     0    stevel 	(void) pthread_mutex_init(&ret->rh_lock, NULL);
    770     0    stevel 
    771     0    stevel 	handle_hold_subhandles(ret, RH_HOLD_ALL);
    772     0    stevel 
    773     0    stevel 	failed = ((ret->rh_iter = scf_iter_create(ret)) == NULL ||
    774     0    stevel 	    (ret->rh_scope = scf_scope_create(ret)) == NULL ||
    775     0    stevel 	    (ret->rh_service = scf_service_create(ret)) == NULL ||
    776     0    stevel 	    (ret->rh_instance = scf_instance_create(ret)) == NULL ||
    777     0    stevel 	    (ret->rh_snapshot = scf_snapshot_create(ret)) == NULL ||
    778     0    stevel 	    (ret->rh_snaplvl = scf_snaplevel_create(ret)) == NULL ||
    779     0    stevel 	    (ret->rh_pg = scf_pg_create(ret)) == NULL ||
    780     0    stevel 	    (ret->rh_property = scf_property_create(ret)) == NULL ||
    781     0    stevel 	    (ret->rh_value = scf_value_create(ret)) == NULL);
    782     0    stevel 
    783     0    stevel 	/*
    784     0    stevel 	 * these subhandles count as internal references, not external ones.
    785     0    stevel 	 */
    786     0    stevel 	ret->rh_intrefs = ret->rh_extrefs;
    787     0    stevel 	ret->rh_extrefs = 0;
    788     0    stevel 	handle_rele_subhandles(ret, RH_HOLD_ALL);
    789     0    stevel 
    790     0    stevel 	if (failed) {
    791     0    stevel 		scf_handle_destroy(ret);
    792     0    stevel 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
    793     0    stevel 		return (NULL);
    794     0    stevel 	}
    795     0    stevel 
    796     0    stevel 	scf_value_set_count(ret->rh_value, default_debug);
    797     0    stevel 	(void) scf_handle_decorate(ret, "debug", ret->rh_value);
    798     0    stevel 
    799     0    stevel 	return (ret);
    800     0    stevel }
    801     0    stevel 
    802     0    stevel int
    803     0    stevel scf_handle_decorate(scf_handle_t *handle, const char *name, scf_value_t *v)
    804     0    stevel {
    805     0    stevel 	if (v != SCF_DECORATE_CLEAR && handle != v->value_handle)
    806     0    stevel 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
    807     0    stevel 
    808     0    stevel 	(void) pthread_mutex_lock(&handle->rh_lock);
    809     0    stevel 	if (handle_is_bound(handle)) {
    810     0    stevel 		(void) pthread_mutex_unlock(&handle->rh_lock);
    811     0    stevel 		return (scf_set_error(SCF_ERROR_IN_USE));
    812     0    stevel 	}
    813     0    stevel 	(void) pthread_mutex_unlock(&handle->rh_lock);
    814     0    stevel 
    815     0    stevel 	if (strcmp(name, "debug") == 0) {
    816     0    stevel 		if (v == SCF_DECORATE_CLEAR) {
    817     0    stevel 			(void) pthread_mutex_lock(&handle->rh_lock);
    818     0    stevel 			handle->rh_debug = 0;
    819     0    stevel 			(void) pthread_mutex_unlock(&handle->rh_lock);
    820     0    stevel 		} else {
    821     0    stevel 			uint64_t val;
    822     0    stevel 			if (scf_value_get_count(v, &val) < 0)
    823     0    stevel 				return (-1);		/* error already set */
    824     0    stevel 
    825     0    stevel 			(void) pthread_mutex_lock(&handle->rh_lock);
    826     0    stevel 			handle->rh_debug = (uid_t)val;
    827     0    stevel 			(void) pthread_mutex_unlock(&handle->rh_lock);
    828     0    stevel 		}
    829     0    stevel 		return (0);
    830     0    stevel 	}
    831     0    stevel 	if (strcmp(name, "door_path") == 0) {
    832     0    stevel 		char name[sizeof (handle->rh_doorpath)];
    833     0    stevel 
    834     0    stevel 		if (v == SCF_DECORATE_CLEAR) {
    835     0    stevel 			(void) pthread_mutex_lock(&handle->rh_lock);
    836     0    stevel 			handle->rh_doorpath[0] = 0;
    837     0    stevel 			(void) pthread_mutex_unlock(&handle->rh_lock);
    838     0    stevel 		} else {
    839     0    stevel 			ssize_t len;
    840     0    stevel 
    841     0    stevel 			if ((len = scf_value_get_astring(v, name,
    842     0    stevel 			    sizeof (name))) < 0) {
    843     0    stevel 				return (-1);		/* error already set */
    844     0    stevel 			}
    845     0    stevel 			if (len == 0 || len >= sizeof (name)) {
    846     0    stevel 				return (scf_set_error(
    847     0    stevel 				    SCF_ERROR_INVALID_ARGUMENT));
    848     0    stevel 			}
    849     0    stevel 			(void) pthread_mutex_lock(&handle->rh_lock);
    850     0    stevel 			(void) strlcpy(handle->rh_doorpath, name,
    851     0    stevel 			    sizeof (handle->rh_doorpath));
    852     0    stevel 			(void) pthread_mutex_unlock(&handle->rh_lock);
    853     0    stevel 		}
    854     0    stevel 		return (0);
    855     0    stevel 	}
    856     0    stevel 	return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
    857     0    stevel }
    858     0    stevel 
    859     0    stevel /*
    860     0    stevel  * fails with INVALID_ARGUMENT and HANDLE_MISMATCH.
    861     0    stevel  */
    862     0    stevel int
    863     0    stevel _scf_handle_decorations(scf_handle_t *handle, scf_decoration_func *f,
    864     0    stevel     scf_value_t *v, void *data)
    865     0    stevel {
    866     0    stevel 	scf_decoration_info_t i;
    867     0    stevel 	char name[sizeof (handle->rh_doorpath)];
    868     0    stevel 	uint64_t debug;
    869     0    stevel 
    870     0    stevel 	if (f == NULL || v == NULL)
    871     0    stevel 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
    872     0    stevel 
    873     0    stevel 	if (v->value_handle != handle)
    874     0    stevel 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
    875     0    stevel 
    876     0    stevel 	i.sdi_name = (const char *)"debug";
    877     0    stevel 	i.sdi_type = SCF_TYPE_COUNT;
    878     0    stevel 	(void) pthread_mutex_lock(&handle->rh_lock);
    879     0    stevel 	debug = handle->rh_debug;
    880     0    stevel 	(void) pthread_mutex_unlock(&handle->rh_lock);
    881     0    stevel 	if (debug != 0) {
    882     0    stevel 		scf_value_set_count(v, debug);
    883     0    stevel 		i.sdi_value = v;
    884     0    stevel 	} else {
    885     0    stevel 		i.sdi_value = SCF_DECORATE_CLEAR;
    886     0    stevel 	}
    887     0    stevel 
    888     0    stevel 	if ((*f)(&i, data) == 0)
    889     0    stevel 		return (0);
    890     0    stevel 
    891     0    stevel 	i.sdi_name = (const char *)"door_path";
    892     0    stevel 	i.sdi_type = SCF_TYPE_ASTRING;
    893     0    stevel 	(void) pthread_mutex_lock(&handle->rh_lock);
    894     0    stevel 	(void) strlcpy(name, handle->rh_doorpath, sizeof (name));
    895     0    stevel 	(void) pthread_mutex_unlock(&handle->rh_lock);
    896     0    stevel 	if (name[0] != 0) {
    897     0    stevel 		(void) scf_value_set_astring(v, name);
    898     0    stevel 		i.sdi_value = v;
    899     0    stevel 	} else {
    900     0    stevel 		i.sdi_value = SCF_DECORATE_CLEAR;
    901     0    stevel 	}
    902     0    stevel 
    903     0    stevel 	if ((*f)(&i, data) == 0)
    904     0    stevel 		return (0);
    905     0    stevel 
    906     0    stevel 	return (1);
    907     0    stevel }
    908     0    stevel 
    909     0    stevel /*
    910     0    stevel  * Fails if handle is not bound.
    911     0    stevel  */
    912     0    stevel static int
    913     0    stevel handle_unbind_unlocked(scf_handle_t *handle)
    914     0    stevel {
    915     0    stevel 	rep_protocol_request_t request;
    916     0    stevel 	rep_protocol_response_t response;
    917     0    stevel 
    918     0    stevel 	if (!handle_is_bound(handle))
    919     0    stevel 		return (-1);
    920     0    stevel 
    921     0    stevel 	request.rpr_request = REP_PROTOCOL_CLOSE;
    922     0    stevel 
    923     0    stevel 	(void) make_door_call(handle, &request, sizeof (request),
    924     0    stevel 	    &response, sizeof (response));
    925     0    stevel 
    926     0    stevel 	handle_do_close(handle);
    927     0    stevel 
    928     0    stevel 	return (SCF_SUCCESS);
    929     0    stevel }
    930     0    stevel 
    931     0    stevel /*
    932     0    stevel  * Fails with
    933     0    stevel  *   _HANDLE_DESTROYED - dp's handle has been destroyed
    934     0    stevel  *   _INTERNAL - server response too big
    935     0    stevel  *		 entity already set up with different type
    936     0    stevel  *   _NO_RESOURCES - server out of memory
    937     0    stevel  */
    938     0    stevel static int
    939     0    stevel datael_attach(scf_datael_t *dp)
    940     0    stevel {
    941     0    stevel 	scf_handle_t *h = dp->rd_handle;
    942     0    stevel 
    943     0    stevel 	struct rep_protocol_entity_setup request;
    944     0    stevel 	rep_protocol_response_t response;
    945     0    stevel 	ssize_t r;
    946     0    stevel 
    947     0    stevel 	assert(MUTEX_HELD(&h->rh_lock));
    948     0    stevel 
    949     0    stevel 	dp->rd_reset = 0;		/* setup implicitly resets */
    950     0    stevel 
    951     0    stevel 	if (h->rh_flags & HANDLE_DEAD)
    952     0    stevel 		return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED));
    953     0    stevel 
    954     0    stevel 	if (!handle_is_bound(h))
    955     0    stevel 		return (SCF_SUCCESS);		/* nothing to do */
    956     0    stevel 
    957     0    stevel 	request.rpr_request = REP_PROTOCOL_ENTITY_SETUP;
    958     0    stevel 	request.rpr_entityid = dp->rd_entity;
    959     0    stevel 	request.rpr_entitytype = dp->rd_type;
    960     0    stevel 
    961     0    stevel 	r = make_door_call(h, &request, sizeof (request),
    962     0    stevel 	    &response, sizeof (response));
    963     0    stevel 
    964     0    stevel 	if (r == NOT_BOUND || r == CALL_FAILED)
    965     0    stevel 		return (SCF_SUCCESS);
    966     0    stevel 	if (r == RESULT_TOO_BIG)
    967     0    stevel 		return (scf_set_error(SCF_ERROR_INTERNAL));
    968     0    stevel 
    969     0    stevel 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
    970     0    stevel 		return (scf_set_error(proto_error(response.rpr_response)));
    971     0    stevel 
    972     0    stevel 	return (SCF_SUCCESS);
    973     0    stevel }
    974     0    stevel 
    975     0    stevel /*
    976     0    stevel  * Fails with
    977     0    stevel  *   _HANDLE_DESTROYED - iter's handle has been destroyed
    978     0    stevel  *   _INTERNAL - server response too big
    979     0    stevel  *		 iter already existed
    980     0    stevel  *   _NO_RESOURCES
    981     0    stevel  */
    982     0    stevel static int
    983     0    stevel iter_attach(scf_iter_t *iter)
    984     0    stevel {
    985     0    stevel 	scf_handle_t *h = iter->iter_handle;
    986     0    stevel 	struct rep_protocol_iter_request request;
    987     0    stevel 	struct rep_protocol_response response;
    988     0    stevel 	int r;
    989     0    stevel 
    990     0    stevel 	assert(MUTEX_HELD(&h->rh_lock));
    991     0    stevel 
    992     0    stevel 	if (h->rh_flags & HANDLE_DEAD)
    993     0    stevel 		return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED));
    994     0    stevel 
    995     0    stevel 	if (!handle_is_bound(h))
    996     0    stevel 		return (SCF_SUCCESS);		/* nothing to do */
    997     0    stevel 
    998     0    stevel 	request.rpr_request = REP_PROTOCOL_ITER_SETUP;
    999     0    stevel 	request.rpr_iterid = iter->iter_id;
   1000     0    stevel 
   1001     0    stevel 	r = make_door_call(h, &request, sizeof (request),
   1002     0    stevel 	    &response, sizeof (response));
   1003     0    stevel 
   1004     0    stevel 	if (r == NOT_BOUND || r == CALL_FAILED)
   1005     0    stevel 		return (SCF_SUCCESS);
   1006     0    stevel 	if (r == RESULT_TOO_BIG)
   1007     0    stevel 		return (scf_set_error(SCF_ERROR_INTERNAL));
   1008     0    stevel 
   1009     0    stevel 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
   1010     0    stevel 		return (scf_set_error(proto_error(response.rpr_response)));
   1011     0    stevel 
   1012     0    stevel 	return (SCF_SUCCESS);
   1013     0    stevel }
   1014     0    stevel 
   1015     0    stevel /*
   1016     0    stevel  * Fails with
   1017     0    stevel  *   _IN_USE - handle already bound
   1018     0    stevel  *   _NO_SERVER - server door could not be open()ed
   1019     0    stevel  *		  door call failed
   1020     0    stevel  *		  door_info() failed
   1021     0    stevel  *   _VERSION_MISMATCH - server returned bad file descriptor
   1022     0    stevel  *			 server claimed bad request
   1023     0    stevel  *			 server reported version mismatch
   1024     0    stevel  *			 server refused with unknown reason
   1025     0    stevel  *   _INVALID_ARGUMENT
   1026     0    stevel  *   _NO_RESOURCES - server is out of memory
   1027     0    stevel  *   _PERMISSION_DENIED
   1028     0    stevel  *   _INTERNAL - could not set up entities or iters
   1029     0    stevel  *		 server response too big
   1030     0    stevel  *
   1031     0    stevel  * perhaps this should try multiple times.
   1032     0    stevel  */
   1033     0    stevel int
   1034     0    stevel scf_handle_bind(scf_handle_t *handle)
   1035     0    stevel {
   1036     0    stevel 	scf_datael_t *el;
   1037     0    stevel 	scf_iter_t *iter;
   1038     0    stevel 
   1039     0    stevel 	pid_t pid;
   1040     0    stevel 	int fd;
   1041     0    stevel 	int res;
   1042     0    stevel 	door_info_t info;
   1043     0    stevel 	repository_door_request_t request;
   1044     0    stevel 	repository_door_response_t response;
   1045     0    stevel 	const char *door_name = default_door_path;
   1046     0    stevel 
   1047     0    stevel 	(void) pthread_mutex_lock(&handle->rh_lock);
   1048     0    stevel 	if (handle_is_bound(handle)) {
   1049     0    stevel 		(void) pthread_mutex_unlock(&handle->rh_lock);
   1050     0    stevel 		return (scf_set_error(SCF_ERROR_IN_USE));
   1051     0    stevel 	}
   1052     0    stevel 
   1053     0    stevel 	/* wait until any active fd users have cleared out */
   1054  5891       raf 	while (handle->rh_fd_users > 0) {
   1055  5891       raf 		int cancel_state;
   1056  5891       raf 
   1057  5891       raf 		(void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,
   1058  5891       raf 		    &cancel_state);
   1059  5891       raf 		(void) pthread_cond_wait(&handle->rh_cv, &handle->rh_lock);
   1060  5891       raf 		(void) pthread_setcancelstate(cancel_state, NULL);
   1061  5891       raf 	}
   1062     0    stevel 
   1063     0    stevel 	/* check again, since we had to drop the lock */
   1064     0    stevel 	if (handle_is_bound(handle)) {
   1065     0    stevel 		(void) pthread_mutex_unlock(&handle->rh_lock);
   1066     0    stevel 		return (scf_set_error(SCF_ERROR_IN_USE));
   1067     0    stevel 	}
   1068     0    stevel 
   1069     0    stevel 	assert(handle->rh_doorfd == -1 && handle->rh_doorfd_old == -1);
   1070     0    stevel 
   1071     0    stevel 	if (handle->rh_doorpath[0] != 0)
   1072     0    stevel 		door_name = handle->rh_doorpath;
   1073     0    stevel 
   1074     0    stevel 	fd = open(door_name, O_RDONLY, 0);
   1075     0    stevel 	if (fd == -1) {
   1076     0    stevel 		(void) pthread_mutex_unlock(&handle->rh_lock);
   1077     0    stevel 		return (scf_set_error(SCF_ERROR_NO_SERVER));
   1078     0    stevel 	}
   1079     0    stevel 
   1080     0    stevel 	request.rdr_version = REPOSITORY_DOOR_VERSION;
   1081     0    stevel 	request.rdr_request = REPOSITORY_DOOR_REQUEST_CONNECT;
   1082     0    stevel 	request.rdr_flags = handle->rh_flags;
   1083     0    stevel 	request.rdr_debug = handle->rh_debug;
   1084     0    stevel 
   1085     0    stevel 	pid = getpid();
   1086     0    stevel 
   1087     0    stevel 	res = make_door_call_retfd(fd, &request, sizeof (request),
   1088     0    stevel 	    &response, sizeof (response), &handle->rh_doorfd);
   1089     0    stevel 
   1090     0    stevel 	(void) close(fd);
   1091     0    stevel 
   1092     0    stevel 	if (res < 0) {
   1093     0    stevel 		(void) pthread_mutex_unlock(&handle->rh_lock);
   1094     0    stevel 
   1095     0    stevel 		assert(res != NOT_BOUND);
   1096     0    stevel 		if (res == CALL_FAILED)
   1097     0    stevel 			return (scf_set_error(SCF_ERROR_NO_SERVER));
   1098     0    stevel 		assert(res == RESULT_TOO_BIG);
   1099     0    stevel 		return (scf_set_error(SCF_ERROR_INTERNAL));
   1100     0    stevel 	}
   1101     0    stevel 
   1102     0    stevel 	if (handle->rh_doorfd < 0) {
   1103     0    stevel 		(void) pthread_mutex_unlock(&handle->rh_lock);
   1104     0    stevel 
   1105     0    stevel 		switch (response.rdr_status) {
   1106     0    stevel 		case REPOSITORY_DOOR_SUCCESS:
   1107     0    stevel 			return (scf_set_error(SCF_ERROR_VERSION_MISMATCH));
   1108     0    stevel 
   1109     0    stevel 		case REPOSITORY_DOOR_FAIL_BAD_REQUEST:
   1110     0    stevel 			return (scf_set_error(SCF_ERROR_VERSION_MISMATCH));
   1111     0    stevel 
   1112     0    stevel 		case REPOSITORY_DOOR_FAIL_VERSION_MISMATCH:
   1113     0    stevel 			return (scf_set_error(SCF_ERROR_VERSION_MISMATCH));
   1114     0    stevel 
   1115     0    stevel 		case REPOSITORY_DOOR_FAIL_BAD_FLAG:
   1116     0    stevel 			return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
   1117     0    stevel 
   1118     0    stevel 		case REPOSITORY_DOOR_FAIL_NO_RESOURCES:
   1119     0    stevel 			return (scf_set_error(SCF_ERROR_NO_RESOURCES));
   1120     0    stevel 
   1121     0    stevel 		case REPOSITORY_DOOR_FAIL_PERMISSION_DENIED:
   1122     0    stevel 			return (scf_set_error(SCF_ERROR_PERMISSION_DENIED));
   1123     0    stevel 
   1124     0    stevel 		default:
   1125     0    stevel 			return (scf_set_error(SCF_ERROR_VERSION_MISMATCH));
   1126     0    stevel 		}
   1127     0    stevel 	}
   1128     0    stevel 
   1129     0    stevel 	(void) fcntl(handle->rh_doorfd, F_SETFD, FD_CLOEXEC);
   1130     0    stevel 
   1131     0    stevel 	if (door_info(handle->rh_doorfd, &info) < 0) {
   1132     0    stevel 		(void) close(handle->rh_doorfd);
   1133     0    stevel 		handle->rh_doorfd = -1;
   1134     0    stevel 
   1135     0    stevel 		(void) pthread_mutex_unlock(&handle->rh_lock);
   1136     0    stevel 		return (scf_set_error(SCF_ERROR_NO_SERVER));
   1137     0    stevel 	}
   1138     0    stevel 
   1139     0    stevel 	handle->rh_doorpid = pid;
   1140     0    stevel 	handle->rh_doorid = info.di_uniquifier;
   1141     0    stevel 
   1142     0    stevel 	/*
   1143     0    stevel 	 * Now, re-attach everything
   1144     0    stevel 	 */
   1145     0    stevel 	for (el = uu_list_first(handle->rh_dataels); el != NULL;
   1146     0    stevel 	    el = uu_list_next(handle->rh_dataels, el)) {
   1147     0    stevel 		if (datael_attach(el) == -1) {
   1148     0    stevel 			assert(scf_error() != SCF_ERROR_HANDLE_DESTROYED);
   1149     0    stevel 			(void) handle_unbind_unlocked(handle);
   1150     0    stevel 			(void) pthread_mutex_unlock(&handle->rh_lock);
   1151     0    stevel 			return (-1);
   1152     0    stevel 		}
   1153     0    stevel 	}
   1154     0    stevel 
   1155     0    stevel 	for (iter = uu_list_first(handle->rh_iters); iter != NULL;
   1156     0    stevel 	    iter = uu_list_next(handle->rh_iters, iter)) {
   1157     0    stevel 		if (iter_attach(iter) == -1) {
   1158     0    stevel 			assert(scf_error() != SCF_ERROR_HANDLE_DESTROYED);
   1159     0    stevel 			(void) handle_unbind_unlocked(handle);
   1160     0    stevel 			(void) pthread_mutex_unlock(&handle->rh_lock);
   1161     0    stevel 			return (-1);
   1162     0    stevel 		}
   1163     0    stevel 	}
   1164     0    stevel 	(void) pthread_mutex_unlock(&handle->rh_lock);
   1165     0    stevel 	return (SCF_SUCCESS);
   1166     0    stevel }
   1167     0    stevel 
   1168     0    stevel int
   1169     0    stevel scf_handle_unbind(scf_handle_t *handle)
   1170     0    stevel {
   1171     0    stevel 	int ret;
   1172     0    stevel 	(void) pthread_mutex_lock(&handle->rh_lock);
   1173     0    stevel 	ret = handle_unbind_unlocked(handle);
   1174     0    stevel 	(void) pthread_mutex_unlock(&handle->rh_lock);
   1175     0    stevel 	return (ret == SCF_SUCCESS ? ret : scf_set_error(SCF_ERROR_NOT_BOUND));
   1176     0    stevel }
   1177     0    stevel 
   1178     0    stevel static scf_handle_t *
   1179     0    stevel handle_get(scf_handle_t *h)
   1180     0    stevel {
   1181     0    stevel 	(void) pthread_mutex_lock(&h->rh_lock);
   1182     0    stevel 	if (h->rh_flags & HANDLE_DEAD) {
   1183     0    stevel 		(void) pthread_mutex_unlock(&h->rh_lock);
   1184     0    stevel 		(void) scf_set_error(SCF_ERROR_HANDLE_DESTROYED);
   1185     0    stevel 		return (NULL);
   1186     0    stevel 	}
   1187     0    stevel 	(void) pthread_mutex_unlock(&h->rh_lock);
   1188     0    stevel 	return (h);
   1189     0    stevel }
   1190     0    stevel 
   1191     0    stevel /*
   1192     0    stevel  * Called when an object is removed from the handle.  On the last remove,
   1193     0    stevel  * cleans up and frees the handle.
   1194     0    stevel  */
   1195     0    stevel static void
   1196     0    stevel handle_unrefed(scf_handle_t *handle)
   1197     0    stevel {
   1198     0    stevel 	scf_iter_t *iter;
   1199     0    stevel 	scf_value_t *v;
   1200     0    stevel 	scf_scope_t *sc;
   1201     0    stevel 	scf_service_t *svc;
   1202     0    stevel 	scf_instance_t *inst;
   1203     0    stevel 	scf_snapshot_t *snap;
   1204     0    stevel 	scf_snaplevel_t *snaplvl;
   1205     0    stevel 	scf_propertygroup_t *pg;
   1206     0    stevel 	scf_property_t *prop;
   1207     0    stevel 
   1208     0    stevel 	assert(MUTEX_HELD(&handle->rh_lock));
   1209     0    stevel 
   1210     0    stevel 	/*
   1211     0    stevel 	 * Don't do anything if the handle has not yet been destroyed, there
   1212     0    stevel 	 * are still external references, or we're already doing unrefed
   1213     0    stevel 	 * handling.
   1214     0    stevel 	 */
   1215     0    stevel 	if (!(handle->rh_flags & HANDLE_DEAD) ||
   1216     0    stevel 	    handle->rh_extrefs > 0 ||
   1217     0    stevel 	    handle->rh_fd_users > 0 ||
   1218     0    stevel 	    (handle->rh_flags & HANDLE_UNREFED)) {
   1219     0    stevel 		(void) pthread_mutex_unlock(&handle->rh_lock);
   1220     0    stevel 		return;
   1221     0    stevel 	}
   1222     0    stevel 
   1223     0    stevel 	handle->rh_flags |= HANDLE_UNREFED;
   1224     0    stevel 
   1225     0    stevel 	/*
   1226     0    stevel 	 * Now that we know that there are no external references, and the
   1227     0    stevel 	 * HANDLE_DEAD flag keeps new ones from appearing, we can clean up
   1228     0    stevel 	 * our subhandles and destroy the handle completely.
   1229     0    stevel 	 */
   1230     0    stevel 	assert(handle->rh_intrefs >= 0);
   1231     0    stevel 	handle->rh_extrefs = handle->rh_intrefs;
   1232     0    stevel 	handle->rh_intrefs = 0;
   1233     0    stevel 	(void) pthread_mutex_unlock(&handle->rh_lock);
   1234     0    stevel 
   1235     0    stevel 	handle_hold_subhandles(handle, RH_HOLD_ALL);
   1236     0    stevel 
   1237     0    stevel 	iter = handle->rh_iter;
   1238     0    stevel 	sc = handle->rh_scope;
   1239     0    stevel 	svc = handle->rh_service;
   1240     0    stevel 	inst = handle->rh_instance;
   1241     0    stevel 	snap = handle->rh_snapshot;
   1242     0    stevel 	snaplvl = handle->rh_snaplvl;
   1243     0    stevel 	pg = handle->rh_pg;
   1244     0    stevel 	prop = handle->rh_property;
   1245     0    stevel 	v = handle->rh_value;
   1246     0    stevel 
   1247     0    stevel 	handle->rh_iter = NULL;
   1248     0    stevel 	handle->rh_scope = NULL;
   1249     0    stevel 	handle->rh_service = NULL;
   1250     0    stevel 	handle->rh_instance = NULL;
   1251     0    stevel 	handle->rh_snapshot = NULL;
   1252     0    stevel 	handle->rh_snaplvl = NULL;
   1253     0    stevel 	handle->rh_pg = NULL;
   1254     0    stevel 	handle->rh_property = NULL;
   1255     0    stevel 	handle->rh_value = NULL;
   1256     0    stevel 
   1257     0    stevel 	if (iter != NULL)
   1258     0    stevel 		scf_iter_destroy(iter);
   1259     0    stevel 	if (sc != NULL)
   1260     0    stevel 		scf_scope_destroy(sc);
   1261     0    stevel 	if (svc != NULL)
   1262     0    stevel 		scf_service_destroy(svc);
   1263     0    stevel 	if (inst != NULL)
   1264     0    stevel 		scf_instance_destroy(inst);
   1265     0    stevel 	if (snap != NULL)
   1266     0    stevel 		scf_snapshot_destroy(snap);
   1267     0    stevel 	if (snaplvl != NULL)
   1268     0    stevel 		scf_snaplevel_destroy(snaplvl);
   1269     0    stevel 	if (pg != NULL)
   1270     0    stevel 		scf_pg_destroy(pg);
   1271     0    stevel 	if (prop != NULL)
   1272     0    stevel 		scf_property_destroy(prop);
   1273     0    stevel 	if (v != NULL)
   1274     0    stevel 		scf_value_destroy(v);
   1275     0    stevel 
   1276     0    stevel 	(void) pthread_mutex_lock(&handle->rh_lock);
   1277     0    stevel 
   1278     0    stevel 	/* there should be no outstanding children at this point */
   1279     0    stevel 	assert(handle->rh_extrefs == 0);
   1280     0    stevel 	assert(handle->rh_intrefs == 0);
   1281     0    stevel 	assert(handle->rh_values == 0);
   1282     0    stevel 	assert(handle->rh_entries == 0);
   1283     0    stevel 	assert(uu_list_numnodes(handle->rh_dataels) == 0);
   1284     0    stevel 	assert(uu_list_numnodes(handle->rh_iters) == 0);
   1285     0    stevel 
   1286     0    stevel 	uu_list_destroy(handle->rh_dataels);
   1287     0    stevel 	uu_list_destroy(handle->rh_iters);
   1288     0    stevel 	handle->rh_dataels = NULL;
   1289     0    stevel 	handle->rh_iters = NULL;
   1290     0    stevel 	(void) pthread_mutex_unlock(&handle->rh_lock);
   1291     0    stevel 
   1292     0    stevel 	(void) pthread_mutex_destroy(&handle->rh_lock);
   1293     0    stevel 
   1294     0    stevel 	uu_free(handle);
   1295     0    stevel }
   1296     0    stevel 
   1297     0    stevel void
   1298     0    stevel scf_handle_destroy(scf_handle_t *handle)
   1299     0    stevel {
   1300     0    stevel 	if (handle == NULL)
   1301     0    stevel 		return;
   1302     0    stevel 
   1303     0    stevel 	(void) pthread_mutex_lock(&handle->rh_lock);
   1304     0    stevel 	if (handle->rh_flags & HANDLE_DEAD) {
   1305     0    stevel 		/*
   1306     0    stevel 		 * This is an error (you are not allowed to reference the
   1307     0    stevel 		 * handle after it is destroyed), but we can't report it.
   1308     0    stevel 		 */
   1309     0    stevel 		(void) pthread_mutex_unlock(&handle->rh_lock);
   1310     0    stevel 		return;
   1311     0    stevel 	}
   1312     0    stevel 	handle->rh_flags |= HANDLE_DEAD;
   1313     0    stevel 	(void) handle_unbind_unlocked(handle);
   1314     0    stevel 	handle_unrefed(handle);
   1315     0    stevel }
   1316     0    stevel 
   1317     0    stevel ssize_t
   1318     0    stevel scf_myname(scf_handle_t *h, char *out, size_t len)
   1319     0    stevel {
   1320     0    stevel 	char *cp;
   1321     0    stevel 
   1322     0    stevel 	if (!handle_has_server(h))
   1323     0    stevel 		return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN));
   1324     0    stevel 
   1325     0    stevel 	cp = getenv("SMF_FMRI");
   1326     0    stevel 	if (cp == NULL)
   1327     0    stevel 		return (scf_set_error(SCF_ERROR_NOT_SET));
   1328     0    stevel 
   1329     0    stevel 	return (strlcpy(out, cp, len));
   1330     0    stevel }
   1331     0    stevel 
   1332     0    stevel static uint32_t
   1333   407   jwadams handle_alloc_entityid(scf_handle_t *h)
   1334   407   jwadams {
   1335   407   jwadams 	uint32_t nextid;
   1336   407   jwadams 
   1337   407   jwadams 	assert(MUTEX_HELD(&h->rh_lock));
   1338   407   jwadams 
   1339   407   jwadams 	if (uu_list_numnodes(h->rh_dataels) == UINT32_MAX)
   1340   407   jwadams 		return (0);		/* no ids available */
   1341   407   jwadams 
   1342   407   jwadams 	/*
   1343   407   jwadams 	 * The following loop assumes that there are not a huge number of
   1344   407   jwadams 	 * outstanding entities when we've wrapped.  If that ends up not
   1345   407   jwadams 	 * being the case, the O(N^2) nature of this search will hurt a lot,
   1346   407   jwadams 	 * and the data structure should be switched to an AVL tree.
   1347   407   jwadams 	 */
   1348   407   jwadams 	nextid = h->rh_nextentity + 1;
   1349   407   jwadams 	for (;;) {
   1350   407   jwadams 		scf_datael_t *cur;
   1351   407   jwadams 
   1352   407   jwadams 		if (nextid == 0) {
   1353   407   jwadams 			nextid++;
   1354   407   jwadams 			h->rh_flags |= HANDLE_WRAPPED_ENTITY;
   1355   407   jwadams 		}
   1356   407   jwadams 		if (!(h->rh_flags & HANDLE_WRAPPED_ENTITY))
   1357   407   jwadams 			break;
   1358   407   jwadams 
   1359   407   jwadams 		cur = uu_list_find(h->rh_dataels, NULL, &nextid, NULL);
   1360   407   jwadams 		if (cur == NULL)
   1361   407   jwadams 			break;		/* not in use */
   1362   407   jwadams 
   1363   407   jwadams 		if (nextid == h->rh_nextentity)
   1364   407   jwadams 			return (0);	/* wrapped around; no ids available */
   1365   407   jwadams 		nextid++;
   1366   407   jwadams 	}
   1367   407   jwadams 
   1368   407   jwadams 	h->rh_nextentity = nextid;
   1369   407   jwadams 	return (nextid);
   1370   407   jwadams }
   1371   407   jwadams 
   1372   407   jwadams static uint32_t
   1373   407   jwadams handle_alloc_iterid(scf_handle_t *h)
   1374   407   jwadams {
   1375   407   jwadams 	uint32_t nextid;
   1376   407   jwadams 
   1377   407   jwadams 	assert(MUTEX_HELD(&h->rh_lock));
   1378   407   jwadams 
   1379   407   jwadams 	if (uu_list_numnodes(h->rh_iters) == UINT32_MAX)
   1380   407   jwadams 		return (0);		/* no ids available */
   1381   407   jwadams 
   1382   407   jwadams 	/* see the comment in handle_alloc_entityid */
   1383   407   jwadams 	nextid = h->rh_nextiter + 1;
   1384   407   jwadams 	for (;;) {
   1385   407   jwadams 		scf_iter_t *cur;
   1386   407   jwadams 
   1387   407   jwadams 		if (nextid == 0) {
   1388   407   jwadams 			nextid++;
   1389   407   jwadams 			h->rh_flags |= HANDLE_WRAPPED_ITER;
   1390   407   jwadams 		}
   1391   407   jwadams 		if (!(h->rh_flags & HANDLE_WRAPPED_ITER))
   1392   407   jwadams 			break;			/* not yet wrapped */
   1393   407   jwadams 
   1394   407   jwadams 		cur = uu_list_find(h->rh_iters, NULL, &nextid, NULL);
   1395   407   jwadams 		if (cur == NULL)
   1396   407   jwadams 			break;		/* not in use */
   1397   407   jwadams 
   1398   407   jwadams 		if (nextid == h->rh_nextiter)
   1399   407   jwadams 			return (0);	/* wrapped around; no ids available */
   1400   407   jwadams 		nextid++;
   1401   407   jwadams 	}
   1402   407   jwadams 
   1403   407   jwadams 	h->rh_nextiter = nextid;
   1404   407   jwadams 	return (nextid);
   1405   407   jwadams }
   1406   407   jwadams 
   1407   407   jwadams static uint32_t
   1408   407   jwadams handle_next_changeid(scf_handle_t *handle)
   1409   407   jwadams {
   1410   407   jwadams 	uint32_t nextid;
   1411   407   jwadams 
   1412     0    stevel 	assert(MUTEX_HELD(&handle->rh_lock));
   1413   407   jwadams 
   1414   407   jwadams 	nextid = ++handle->rh_nextchangeid;
   1415   407   jwadams 	if (nextid == 0)
   1416   407   jwadams 		nextid = ++handle->rh_nextchangeid;
   1417   407   jwadams 	return (nextid);
   1418     0    stevel }
   1419     0    stevel 
   1420     0    stevel /*
   1421     0    stevel  * Fails with
   1422     0    stevel  *   _INVALID_ARGUMENT - h is NULL
   1423     0    stevel  *   _HANDLE_DESTROYED
   1424     0    stevel  *   _INTERNAL - server response too big
   1425     0    stevel  *		 entity already set up with different type
   1426     0    stevel  *   _NO_RESOURCES
   1427     0    stevel  */
   1428     0    stevel static int
   1429     0    stevel datael_init(scf_datael_t *dp, scf_handle_t *h, uint32_t type)
   1430     0    stevel {
   1431     0    stevel 	int ret;
   1432     0    stevel 
   1433     0    stevel 	if (h == NULL)
   1434     0    stevel 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
   1435     0    stevel 
   1436     0    stevel 	uu_list_node_init(dp, &dp->rd_node, datael_pool);
   1437     0    stevel 
   1438     0    stevel 	dp->rd_handle = h;
   1439     0    stevel 	dp->rd_type = type;
   1440     0    stevel 	dp->rd_reset = 0;
   1441     0    stevel 
   1442     0    stevel 	(void) pthread_mutex_lock(&h->rh_lock);
   1443     0    stevel 	if (h->rh_flags & HANDLE_DEAD) {
   1444     0    stevel 		/*
   1445     0    stevel 		 * we're in undefined territory (the user cannot use a handle
   1446     0    stevel 		 * directly after it has been destroyed), but we don't want
   1447     0    stevel 		 * to allow any new references to happen, so we fail here.
   1448     0    stevel 		 */
   1449     0    stevel 		(void) pthread_mutex_unlock(&h->rh_lock);
   1450     0    stevel 		return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED));
   1451     0    stevel 	}
   1452     0    stevel 	dp->rd_entity = handle_alloc_entityid(h);
   1453   407   jwadams 	if (dp->rd_entity == 0) {
   1454   407   jwadams 		(void) pthread_mutex_unlock(&h->rh_lock);
   1455   407   jwadams 		uu_list_node_fini(dp, &dp->rd_node, datael_pool);
   1456   407   jwadams 		return (scf_set_error(SCF_ERROR_NO_MEMORY));
   1457   407   jwadams 	}
   1458     0    stevel 
   1459     0    stevel 	ret = datael_attach(dp);
   1460     0    stevel 	if (ret == 0) {
   1461     0    stevel 		(void) uu_list_insert_before(h->rh_dataels, NULL, dp);
   1462     0    stevel 		h->rh_extrefs++;
   1463     0    stevel 	} else {
   1464     0    stevel 		uu_list_node_fini(dp, &dp->rd_node, datael_pool);
   1465     0    stevel 	}
   1466     0    stevel 	(void) pthread_mutex_unlock(&h->rh_lock);
   1467     0    stevel 
   1468     0    stevel 	return (ret);
   1469     0    stevel }
   1470     0    stevel 
   1471     0    stevel static void
   1472     0    stevel datael_destroy(scf_datael_t *dp)
   1473     0    stevel {
   1474     0    stevel 	scf_handle_t *h = dp->rd_handle;
   1475     0    stevel 
   1476     0    stevel 	struct rep_protocol_entity_teardown request;
   1477     0    stevel 	rep_protocol_response_t response;
   1478     0    stevel 
   1479     0    stevel 	(void) pthread_mutex_lock(&h->rh_lock);
   1480     0    stevel 	uu_list_remove(h->rh_dataels, dp);
   1481     0    stevel 	--h->rh_extrefs;
   1482     0    stevel 
   1483     0    stevel 	if (handle_is_bound(h)) {
   1484     0    stevel 		request.rpr_request = REP_PROTOCOL_ENTITY_TEARDOWN;
   1485     0    stevel 		request.rpr_entityid = dp->rd_entity;
   1486     0    stevel 
   1487     0    stevel 		(void) make_door_call(h, &request, sizeof (request),
   1488     0    stevel 		    &response, sizeof (response));
   1489     0    stevel 	}
   1490     0    stevel 	handle_unrefed(h);			/* drops h->rh_lock */
   1491     0    stevel 
   1492     0    stevel 	dp->rd_handle = NULL;
   1493     0    stevel }
   1494     0    stevel 
   1495     0    stevel static scf_handle_t *
   1496     0    stevel datael_handle(const scf_datael_t *dp)
   1497     0    stevel {
   1498     0    stevel 	return (handle_get(dp->rd_handle));
   1499     0    stevel }
   1500     0    stevel 
   1501     0    stevel /*
   1502     0    stevel  * We delay ENTITY_RESETs until right before the entity is used.  By doing
   1503     0    stevel  * them lazily, we remove quite a few unnecessary calls.
   1504     0    stevel  */
   1505     0    stevel static void
   1506     0    stevel datael_do_reset_locked(scf_datael_t *dp)
   1507     0    stevel {
   1508     0    stevel 	scf_handle_t *h = dp->rd_handle;
   1509     0    stevel 
   1510     0    stevel 	struct rep_protocol_entity_reset request;
   1511     0    stevel 	rep_protocol_response_t response;
   1512     0    stevel 
   1513     0    stevel 	assert(MUTEX_HELD(&h->rh_lock));
   1514     0    stevel 
   1515     0    stevel 	request.rpr_request = REP_PROTOCOL_ENTITY_RESET;
   1516     0    stevel 	request.rpr_entityid = dp->rd_entity;
   1517     0    stevel 
   1518     0    stevel 	(void) make_door_call(h, &request, sizeof (request),
   1519     0    stevel 	    &response, sizeof (response));
   1520     0    stevel 
   1521     0    stevel 	dp->rd_reset = 0;
   1522     0    stevel }
   1523     0    stevel 
   1524     0    stevel static void
   1525     0    stevel datael_reset_locked(scf_datael_t *dp)
   1526     0    stevel {
   1527     0    stevel 	assert(MUTEX_HELD(&dp->rd_handle->rh_lock));
   1528     0    stevel 	dp->rd_reset = 1;
   1529     0    stevel }
   1530     0    stevel 
   1531     0    stevel static void
   1532     0    stevel datael_reset(scf_datael_t *dp)
   1533     0    stevel {
   1534     0    stevel 	scf_handle_t *h = dp->rd_handle;
   1535     0    stevel 
   1536     0    stevel 	(void) pthread_mutex_lock(&h->rh_lock);
   1537     0    stevel 	dp->rd_reset = 1;
   1538     0    stevel 	(void) pthread_mutex_unlock(&h->rh_lock);
   1539     0    stevel }
   1540     0    stevel 
   1541     0    stevel static void
   1542     0    stevel datael_finish_reset(const scf_datael_t *dp_arg)
   1543     0    stevel {
   1544     0    stevel 	scf_datael_t *dp = (scf_datael_t *)dp_arg;
   1545     0    stevel 
   1546     0    stevel 	if (dp->rd_reset)
   1547     0    stevel 		datael_do_reset_locked(dp);
   1548     0    stevel }
   1549     0    stevel 
   1550     0    stevel /*
   1551     0    stevel  * Fails with _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response too
   1552     0    stevel  * big, bad entity id, request not applicable to entity, name too long for
   1553     0    stevel  * buffer), _NOT_SET, _DELETED, or _CONSTRAINT_VIOLATED (snaplevel is not of an
   1554     0    stevel  * instance).
   1555     0    stevel  */
   1556     0    stevel static ssize_t
   1557     0    stevel datael_get_name(const scf_datael_t *dp, char *buf, size_t size, uint32_t type)
   1558     0    stevel {
   1559     0    stevel 	scf_handle_t *h = dp->rd_handle;
   1560     0    stevel 
   1561     0    stevel 	struct rep_protocol_entity_name request;
   1562     0    stevel 	struct rep_protocol_name_response response;
   1563     0    stevel 	ssize_t r;
   1564     0    stevel 
   1565     0    stevel 	(void) pthread_mutex_lock(&h->rh_lock);
   1566     0    stevel 	request.rpr_request = REP_PROTOCOL_ENTITY_NAME;
   1567     0    stevel 	request.rpr_entityid = dp->rd_entity;
   1568     0    stevel 	request.rpr_answertype = type;
   1569     0    stevel 
   1570     0    stevel 	datael_finish_reset(dp);
   1571     0    stevel 	r = make_door_call(h, &request, sizeof (request),
   1572     0    stevel 	    &response, sizeof (response));
   1573     0    stevel 	(void) pthread_mutex_unlock(&h->rh_lock);
   1574     0    stevel 
   1575     0    stevel 	if (r < 0)
   1576     0    stevel 		DOOR_ERRORS_BLOCK(r);
   1577     0    stevel 
   1578     0    stevel 	if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
   1579     0    stevel 		assert(response.rpr_response != REP_PROTOCOL_FAIL_BAD_REQUEST);
   1580     0    stevel 		if (response.rpr_response == REP_PROTOCOL_FAIL_NOT_FOUND)
   1581     0    stevel 			return (scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED));
   1582     0    stevel 		return (scf_set_error(proto_error(response.rpr_response)));
   1583     0    stevel 	}
   1584     0    stevel 	return (strlcpy(buf, response.rpr_name, size));
   1585     0    stevel }
   1586     0    stevel 
   1587     0    stevel /*
   1588     0    stevel  * Fails with _HANDLE_MISMATCH, _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL
   1589     0    stevel  * (server response too big, bad element id), _EXISTS (elements have same id),
   1590     0    stevel  * _NOT_SET, _DELETED, _CONSTRAINT_VIOLATED, _NOT_FOUND (scope has no parent),
   1591     0    stevel  * or _SUCCESS.
   1592     0    stevel  */
   1593     0    stevel static int
   1594     0    stevel datael_get_parent(const scf_datael_t *dp, scf_datael_t *pp)
   1595     0    stevel {
   1596     0    stevel 	scf_handle_t *h = dp->rd_handle;
   1597     0    stevel 
   1598     0    stevel 	struct rep_protocol_entity_parent request;
   1599     0    stevel 	struct rep_protocol_response response;
   1600     0    stevel 
   1601     0    stevel 	ssize_t r;
   1602     0    stevel 
   1603     0    stevel 	if (h != pp->rd_handle)
   1604     0    stevel 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
   1605     0    stevel 
   1606     0    stevel 	(void) pthread_mutex_lock(&h->rh_lock);
   1607     0    stevel 	request.rpr_request = REP_PROTOCOL_ENTITY_GET_PARENT;
   1608     0    stevel 	request.rpr_entityid = dp->rd_entity;
   1609     0    stevel 	request.rpr_outid = pp->rd_entity;
   1610     0    stevel 
   1611     0    stevel 	datael_finish_reset(dp);
   1612     0    stevel 	datael_finish_reset(pp);
   1613     0    stevel 	r = make_door_call(h, &request, sizeof (request),
   1614     0    stevel 	    &response, sizeof (response));
   1615     0    stevel 	(void) pthread_mutex_unlock(&h->rh_lock);
   1616     0    stevel 
   1617     0    stevel 	if (r < 0)
   1618     0    stevel 		DOOR_ERRORS_BLOCK(r);
   1619     0    stevel 
   1620     0    stevel 	if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
   1621     0    stevel 		if (response.rpr_response == REP_PROTOCOL_FAIL_TYPE_MISMATCH)
   1622     0    stevel 			return (scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED));
   1623     0    stevel 		return (scf_set_error(proto_error(response.rpr_response)));
   1624     0    stevel 	}
   1625     0    stevel 
   1626     0    stevel 	return (SCF_SUCCESS);
   1627     0    stevel }
   1628     0    stevel 
   1629     0    stevel /*
   1630     0    stevel  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT (out does not have type type,
   1631     0    stevel  * name is invalid), _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response
   1632     0    stevel  * too big, bad id, iter already exists, element cannot have children of type,
   1633     0    stevel  * type is invalid, iter was reset, sequence was bad, iter walks values, iter
   1634     0    stevel  * does not walk type entities), _NOT_SET, _DELETED, _NO_RESOURCES,
   1635  4740     jeanm  * _BACKEND_ACCESS, _NOT_FOUND.
   1636     0    stevel  */
   1637     0    stevel static int
   1638     0    stevel datael_get_child_composed_locked(const scf_datael_t *dp, const char *name,
   1639     0    stevel     uint32_t type, scf_datael_t *out, scf_iter_t *iter)
   1640     0    stevel {
   1641     0    stevel 	struct rep_protocol_iter_start request;
   1642     0    stevel 	struct rep_protocol_iter_read read_request;
   1643     0    stevel 	struct rep_protocol_response response;
   1644     0    stevel 
   1645     0    stevel 	scf_handle_t *h = dp->rd_handle;
   1646     0    stevel 	ssize_t r;
   1647     0    stevel 
   1648     0    stevel 	if (h != out->rd_handle)
   1649     0    stevel 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
   1650     0    stevel 
   1651     0    stevel 	if (out->rd_type != type)
   1652     0    stevel 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
   1653     0    stevel 
   1654     0    stevel 	assert(MUTEX_HELD(&h->rh_lock));
   1655     0    stevel 	assert(iter != NULL);
   1656     0    stevel 
   1657     0    stevel 	scf_iter_reset_locked(iter);
   1658     0    stevel 	iter->iter_type = type;
   1659     0    stevel 
   1660     0    stevel 	request.rpr_request = REP_PROTOCOL_ITER_START;
   1661     0    stevel 	request.rpr_iterid = iter->iter_id;
   1662     0    stevel 	request.rpr_entity = dp->rd_entity;
   1663     0    stevel 	request.rpr_itertype = type;
   1664     0    stevel 	request.rpr_flags = RP_ITER_START_EXACT | RP_ITER_START_COMPOSED;
   1665     0    stevel 
   1666     0    stevel 	if (name == NULL || strlcpy(request.rpr_pattern, name,
   1667     0    stevel 	    sizeof (request.rpr_pattern)) >= sizeof (request.rpr_pattern)) {
   1668     0    stevel 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
   1669     0    stevel 	}
   1670     0    stevel 
   1671     0    stevel 	datael_finish_reset(dp);
   1672     0    stevel 	datael_finish_reset(out);
   1673     0    stevel 
   1674     0    stevel 	/*
   1675     0    stevel 	 * We hold the handle lock across both door calls, so that they
   1676     0    stevel 	 * appear atomic.
   1677     0    stevel 	 */
   1678     0    stevel 	r = make_door_call(h, &request, sizeof (request),
   1679     0    stevel 	    &response, sizeof (response));
   1680     0    stevel 
   1681     0    stevel 	if (r < 0)
   1682     0    stevel 		DOOR_ERRORS_BLOCK(r);
   1683     0    stevel 
   1684     0    stevel 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
   1685     0    stevel 		return (scf_set_error(proto_error(response.rpr_response)));
   1686     0    stevel 
   1687     0    stevel 	iter->iter_sequence++;
   1688     0    stevel 
   1689     0    stevel 	read_request.rpr_request = REP_PROTOCOL_ITER_READ;
   1690     0    stevel 	read_request.rpr_iterid = iter->iter_id;
   1691     0    stevel 	read_request.rpr_sequence = iter->iter_sequence;
   1692     0    stevel 	read_request.rpr_entityid = out->rd_entity;
   1693     0    stevel 
   1694     0    stevel 	r = make_door_call(h, &read_request, sizeof (read_request),
   1695     0    stevel 	    &response, sizeof (response));
   1696     0    stevel 
   1697     0    stevel 	scf_iter_reset_locked(iter);
   1698     0    stevel 
   1699     0    stevel 	if (r < 0)
   1700     0    stevel 		DOOR_ERRORS_BLOCK(r);
   1701     0    stevel 
   1702     0    stevel 	if (response.rpr_response == REP_PROTOCOL_DONE) {
   1703     0    stevel 		return (scf_set_error(SCF_ERROR_NOT_FOUND));
   1704     0    stevel 	}
   1705     0    stevel 
   1706     0    stevel 	if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
   1707     0    stevel 		if (response.rpr_response == REP_PROTOCOL_FAIL_NOT_SET ||
   1708     0    stevel 		    response.rpr_response == REP_PROTOCOL_FAIL_BAD_REQUEST)
   1709     0    stevel 			return (scf_set_error(SCF_ERROR_INTERNAL));
   1710     0    stevel 		return (scf_set_error(proto_error(response.rpr_response)));
   1711     0    stevel 	}
   1712     0    stevel 
   1713     0    stevel 	return (0);
   1714     0    stevel }
   1715     0    stevel 
   1716     0    stevel /*
   1717     0    stevel  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT (out does not have type type,
   1718     0    stevel  * name is invalid), _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response
   1719     0    stevel  * too big, bad id, element cannot have children of type, type is invalid),
   1720     0    stevel  * _NOT_SET, _DELETED, _NO_RESOURCES, _BACKEND_ACCESS.
   1721     0    stevel  */
   1722     0    stevel static int
   1723     0    stevel datael_get_child_locked(const scf_datael_t *dp, const char *name,
   1724     0    stevel     uint32_t type, scf_datael_t *out)
   1725     0    stevel {
   1726     0    stevel 	struct rep_protocol_entity_get_child request;
   1727     0    stevel 	struct rep_protocol_response response;
   1728     0    stevel 
   1729     0    stevel 	scf_handle_t *h = dp->rd_handle;
   1730     0    stevel 	ssize_t r;
   1731     0    stevel 
   1732     0    stevel 	if (h != out->rd_handle)
   1733     0    stevel 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
   1734     0    stevel 
   1735     0    stevel 	if (out->rd_type != type)
   1736     0    stevel 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
   1737     0    stevel 
   1738     0    stevel 	assert(MUTEX_HELD(&h->rh_lock));
   1739     0    stevel 
   1740     0    stevel 	request.rpr_request = REP_PROTOCOL_ENTITY_GET_CHILD;
   1741     0    stevel 	request.rpr_entityid = dp->rd_entity;
   1742     0    stevel 	request.rpr_childid = out->rd_entity;
   1743     0    stevel 
   1744     0    stevel 	if (name == NULL || strlcpy(request.rpr_name, name,
   1745     0    stevel 	    sizeof (request.rpr_name)) >= sizeof (request.rpr_name)) {
   1746     0    stevel 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
   1747     0    stevel 	}
   1748     0    stevel 
   1749     0    stevel 	datael_finish_reset(dp);
   1750     0    stevel 	datael_finish_reset(out);
   1751     0    stevel 
   1752     0    stevel 	r = make_door_call(h, &request, sizeof (request),
   1753     0    stevel 	    &response, sizeof (response));
   1754     0    stevel 
   1755     0    stevel 	if (r < 0)
   1756     0    stevel 		DOOR_ERRORS_BLOCK(r);
   1757     0    stevel 
   1758     0    stevel 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
   1759     0    stevel 		return (scf_set_error(proto_error(response.rpr_response)));
   1760     0    stevel 	return (0);
   1761     0    stevel }
   1762     0    stevel 
   1763  4740     jeanm /*
   1764  4740     jeanm  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT (out does not have type type,
   1765  4740     jeanm  * name is invalid), _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response
   1766  4740     jeanm  * too big, bad id, iter already exists, element cannot have children of type,
   1767  4740     jeanm  * type is invalid, iter was reset, sequence was bad, iter walks values, iter
   1768  4740     jeanm  * does not walk type entities), _NOT_SET, _DELETED, _NO_RESOURCES,
   1769  4740     jeanm  * _BACKEND_ACCESS, _NOT_FOUND.
   1770  4740     jeanm  */
   1771     0    stevel static int
   1772     0    stevel datael_get_child(const scf_datael_t *dp, const char *name, uint32_t type,
   1773     0    stevel     scf_datael_t *out, boolean_t composed)
   1774     0    stevel {
   1775     0    stevel 	scf_handle_t *h = dp->rd_handle;
   1776     0    stevel 	uint32_t held = 0;
   1777     0    stevel 	int ret;
   1778     0    stevel 
   1779     0    stevel 	scf_iter_t *iter = NULL;
   1780     0    stevel 
   1781     0    stevel 	if (composed)
   1782     0    stevel 		iter = HANDLE_HOLD_ITER(h);
   1783     0    stevel 
   1784     0    stevel 	if (out == NULL) {
   1785     0    stevel 		switch (type) {
   1786     0    stevel 		case REP_PROTOCOL_ENTITY_SERVICE:
   1787     0    stevel 			out = &HANDLE_HOLD_SERVICE(h)->rd_d;
   1788     0    stevel 			held = RH_HOLD_SERVICE;
   1789     0    stevel 			break;
   1790     0    stevel 
   1791     0    stevel 		case REP_PROTOCOL_ENTITY_INSTANCE:
   1792     0    stevel 			out = &HANDLE_HOLD_INSTANCE(h)->rd_d;
   1793     0    stevel 			held = RH_HOLD_INSTANCE;
   1794     0    stevel 			break;
   1795     0    stevel 
   1796     0    stevel 		case REP_PROTOCOL_ENTITY_SNAPSHOT:
   1797     0    stevel 			out = &HANDLE_HOLD_SNAPSHOT(h)->rd_d;
   1798     0    stevel 			held = RH_HOLD_SNAPSHOT;
   1799     0    stevel 			break;
   1800     0    stevel 
   1801     0    stevel 		case REP_PROTOCOL_ENTITY_SNAPLEVEL:
   1802     0    stevel 			out = &HANDLE_HOLD_SNAPLVL(h)->rd_d;
   1803     0    stevel 			held = RH_HOLD_SNAPLVL;
   1804     0    stevel 			break;
   1805     0    stevel 
   1806     0    stevel 		case REP_PROTOCOL_ENTITY_PROPERTYGRP:
   1807     0    stevel 			out = &HANDLE_HOLD_PG(h)->rd_d;
   1808     0    stevel 			held = RH_HOLD_PG;
   1809     0    stevel 			break;
   1810     0    stevel 
   1811     0    stevel 		case REP_PROTOCOL_ENTITY_PROPERTY:
   1812     0    stevel 			out = &HANDLE_HOLD_PROPERTY(h)->rd_d;
   1813     0    stevel 			held = RH_HOLD_PROPERTY;
   1814     0    stevel 			break;
   1815     0    stevel 
   1816     0    stevel 		default:
   1817     0    stevel 			assert(0);
   1818     0    stevel 			abort();
   1819     0    stevel 		}
   1820     0    stevel 	}
   1821     0    stevel 
   1822     0    stevel 	(void) pthread_mutex_lock(&h->rh_lock);
   1823     0    stevel 	if (composed)
   1824     0    stevel 		ret = datael_get_child_composed_locked(dp, name, type, out,
   1825     0    stevel 		    iter);
   1826     0    stevel 	else
   1827     0    stevel 		ret = datael_get_child_locked(dp, name, type, out);
   1828     0    stevel 	(void) pthread_mutex_unlock(&h->rh_lock);
   1829     0    stevel 
   1830     0    stevel 	if (composed)
   1831     0    stevel 		HANDLE_RELE_ITER(h);
   1832     0    stevel 
   1833     0    stevel 	if (held)
   1834     0    stevel 		handle_rele_subhandles(h, held);
   1835     0    stevel 
   1836     0    stevel 	return (ret);
   1837     0    stevel }
   1838     0    stevel 
   1839     0    stevel /*
   1840     0    stevel  * Fails with
   1841     0    stevel  *   _HANDLE_MISMATCH
   1842     0    stevel  *   _INVALID_ARGUMENT - name is too long
   1843     0    stevel  *			 invalid changeid
   1844     0    stevel  *			 name is invalid
   1845     0    stevel  *			 cannot create children for dp's type of node
   1846     0    stevel  *   _NOT_BOUND - handle is not bound
   1847     0    stevel  *   _CONNECTION_BROKEN - server is not reachable
   1848     0    stevel  *   _INTERNAL - server response too big
   1849     0    stevel  *		 dp or cp has unknown id
   1850     0    stevel  *		 type is _PROPERTYGRP
   1851     0    stevel  *		 type is invalid
   1852     0    stevel  *		 dp cannot have children of type type
   1853     0    stevel  *		 database is corrupt
   1854     0    stevel  *   _EXISTS - dp & cp have the same id
   1855     0    stevel  *   _EXISTS - child already exists
   1856     0    stevel  *   _DELETED - dp has been deleted
   1857     0    stevel  *   _NOT_SET - dp is reset
   1858     0    stevel  *   _NO_RESOURCES
   1859     0    stevel  *   _PERMISSION_DENIED
   1860     0    stevel  *   _BACKEND_ACCESS
   1861     0    stevel  *   _BACKEND_READONLY
   1862     0    stevel  */
   1863     0    stevel static int
   1864     0    stevel datael_add_child(const scf_datael_t *dp, const char *name, uint32_t type,
   1865     0    stevel     scf_datael_t *cp)
   1866     0    stevel {
   1867     0    stevel 	scf_handle_t *h = dp->rd_handle;
   1868     0    stevel 
   1869     0    stevel 	struct rep_protocol_entity_create_child request;
   1870     0    stevel 	struct rep_protocol_response response;
   1871     0    stevel 	ssize_t r;
   1872     0    stevel 	uint32_t held = 0;
   1873     0    stevel 
   1874     0    stevel 	if (cp == NULL) {
   1875     0    stevel 		switch (type) {
   1876     0    stevel 		case REP_PROTOCOL_ENTITY_SCOPE:
   1877     0    stevel 			cp = &HANDLE_HOLD_SCOPE(h)->rd_d;
   1878     0    stevel 			held = RH_HOLD_SCOPE;
   1879     0    stevel 			break;
   1880     0    stevel 		case REP_PROTOCOL_ENTITY_SERVICE:
   1881     0    stevel 			cp = &HANDLE_HOLD_SERVICE(h)->rd_d;
   1882     0    stevel 			held = RH_HOLD_SERVICE;
   1883     0    stevel 			break;
   1884     0    stevel 		case REP_PROTOCOL_ENTITY_INSTANCE:
   1885     0    stevel 			cp = &HANDLE_HOLD_INSTANCE(h)->rd_d;
   1886     0    stevel 			held = RH_HOLD_INSTANCE;
   1887     0    stevel 			break;
   1888     0    stevel 		case REP_PROTOCOL_ENTITY_SNAPSHOT:
   1889     0    stevel 		default:
   1890     0    stevel 			assert(0);
   1891     0    stevel 			abort();
   1892     0    stevel 		}
   1893     0    stevel 		assert(h == cp->rd_handle);
   1894     0    stevel 
   1895     0    stevel 	} else if (h != cp->rd_handle) {
   1896     0    stevel 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
   1897     0    stevel 	}
   1898     0    stevel 
   1899     0    stevel 	if (strlcpy(request.rpr_name, name, sizeof (request.rpr_name)) >=
   1900     0    stevel 	    sizeof (request.rpr_name)) {
   1901     0    stevel 		r = scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
   1902     0    stevel 		goto err;
   1903     0    stevel 	}
   1904     0    stevel 
   1905     0    stevel 	(void) pthread_mutex_lock(&h->rh_lock);
   1906     0    stevel 	request.rpr_request = REP_PROTOCOL_ENTITY_CREATE_CHILD;
   1907     0    stevel 	request.rpr_entityid = dp->rd_entity;
   1908     0    stevel 	request.rpr_childtype = type;
   1909     0    stevel 	request.rpr_childid = cp->rd_entity;
   1910     0    stevel 
   1911     0    stevel 	datael_finish_reset(dp);
   1912   407   jwadams 	request.rpr_changeid = handle_next_changeid(h);
   1913     0    stevel 	r = make_door_call(h, &request, sizeof (request),
   1914     0    stevel 	    &response, sizeof (response));
   1915     0    stevel 	(void) pthread_mutex_unlock(&h->rh_lock);
   1916     0    stevel 
   1917     0    stevel 	if (held)
   1918     0    stevel 		handle_rele_subhandles(h, held);
   1919     0    stevel 
   1920     0    stevel 	if (r < 0)
   1921     0    stevel 		DOOR_ERRORS_BLOCK(r);
   1922     0    stevel 
   1923     0    stevel 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
   1924     0    stevel 		return (scf_set_error(proto_error(response.rpr_response)));
   1925     0    stevel 
   1926     0    stevel 	return (SCF_SUCCESS);
   1927     0    stevel 
   1928     0    stevel err:
   1929     0    stevel 	if (held)
   1930     0    stevel 		handle_rele_subhandles(h, held);
   1931     0    stevel 	return (r);
   1932     0    stevel }
   1933     0    stevel 
   1934     0    stevel static int
   1935     0    stevel datael_add_pg(const scf_datael_t *dp, const char *name, const char *type,
   1936     0    stevel     uint32_t flags, scf_datael_t *cp)
   1937     0    stevel {
   1938     0    stevel 	scf_handle_t *h = dp->rd_handle;
   1939     0    stevel 
   1940     0    stevel 	struct rep_protocol_entity_create_pg request;
   1941     0    stevel 	struct rep_protocol_response response;
   1942     0    stevel 	ssize_t r;
   1943     0    stevel 
   1944     0    stevel 	int holding_els = 0;
   1945     0    stevel 
   1946     0    stevel 	if (cp == NULL) {
   1947     0    stevel 		holding_els = 1;
   1948     0    stevel 		cp = &HANDLE_HOLD_PG(h)->rd_d;
   1949     0    stevel 		assert(h == cp->rd_handle);
   1950     0    stevel 
   1951     0    stevel 	} else if (h != cp->rd_handle) {
   1952     0    stevel 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
   1953     0    stevel 	}
   1954     0    stevel 
   1955     0    stevel 	request.rpr_request = REP_PROTOCOL_ENTITY_CREATE_PG;
   1956     0    stevel 
   1957     0    stevel 	if (name == NULL || strlcpy(request.rpr_name, name,
   1958     0    stevel 	    sizeof (request.rpr_name)) > sizeof (request.rpr_name)) {
   1959     0    stevel 		r = scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
   1960     0    stevel 		goto err;
   1961     0    stevel 	}
   1962     0    stevel 
   1963     0    stevel 	if (type == NULL || strlcpy(request.rpr_type, type,
   1964     0    stevel 	    sizeof (request.rpr_type)) > sizeof (request.rpr_type)) {
   1965     0    stevel 		r = scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
   1966     0    stevel 		goto err;
   1967     0    stevel 	}
   1968     0    stevel 
   1969     0    stevel 	(void) pthread_mutex_lock(&h->rh_lock);
   1970     0    stevel 	request.rpr_entityid = dp->rd_entity;
   1971     0    stevel 	request.rpr_childid = cp->rd_entity;
   1972     0    stevel 	request.rpr_flags = flags;
   1973     0    stevel 
   1974     0    stevel 	datael_finish_reset(dp);
   1975     0    stevel 	datael_finish_reset(cp);
   1976   407   jwadams 	request.rpr_changeid = handle_next_changeid(h);
   1977     0    stevel 	r = make_door_call(h, &request, sizeof (request),
   1978     0    stevel 	    &response, sizeof (response));
   1979     0    stevel 	(void) pthread_mutex_unlock(&h->rh_lock);
   1980     0    stevel 
   1981     0    stevel 	if (holding_els)
   1982     0    stevel 		HANDLE_RELE_PG(h);
   1983     0    stevel 
   1984     0    stevel 	if (r < 0)
   1985     0    stevel 		DOOR_ERRORS_BLOCK(r);
   1986     0    stevel 
   1987     0    stevel 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
   1988     0    stevel 		return (scf_set_error(proto_error(response.rpr_response)));
   1989     0    stevel 
   1990     0    stevel 	return (SCF_SUCCESS);
   1991     0    stevel 
   1992     0    stevel err:
   1993     0    stevel 	if (holding_els)
   1994     0    stevel 		HANDLE_RELE_PG(h);
   1995     0    stevel 	return (r);
   1996     0    stevel }
   1997     0    stevel 
   1998     0    stevel static int
   1999     0    stevel datael_delete(const scf_datael_t *dp)
   2000     0    stevel {
   2001     0    stevel 	scf_handle_t *h = dp->rd_handle;
   2002     0    stevel 
   2003     0    stevel 	struct rep_protocol_entity_delete request;
   2004     0    stevel 	struct rep_protocol_response response;
   2005     0    stevel 	ssize_t r;
   2006     0    stevel 
   2007     0    stevel 	(void) pthread_mutex_lock(&h->rh_lock);
   2008     0    stevel 	request.rpr_request = REP_PROTOCOL_ENTITY_DELETE;
   2009     0    stevel 	request.rpr_entityid = dp->rd_entity;
   2010     0    stevel 
   2011     0    stevel 	datael_finish_reset(dp);
   2012   407   jwadams 	request.rpr_changeid = handle_next_changeid(h);
   2013     0    stevel 	r = make_door_call(h, &request, sizeof (request),
   2014     0    stevel 	    &response, sizeof (response));
   2015     0    stevel 	(void) pthread_mutex_unlock(&h->rh_lock);
   2016     0    stevel 
   2017     0    stevel 	if (r < 0)
   2018     0    stevel 		DOOR_ERRORS_BLOCK(r);
   2019     0    stevel 
   2020     0    stevel 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
   2021     0    stevel 		return (scf_set_error(proto_error(response.rpr_response)));
   2022     0    stevel 
   2023     0    stevel 	return (SCF_SUCCESS);
   2024     0    stevel }
   2025     0    stevel 
   2026     0    stevel /*
   2027     0    stevel  * Fails with
   2028     0    stevel  *   _INVALID_ARGUMENT - h is NULL
   2029     0    stevel  *   _NO_MEMORY
   2030     0    stevel  *   _HANDLE_DESTROYED - h has been destroyed
   2031     0    stevel  *   _INTERNAL - server response too big
   2032     0    stevel  *		 iter already exists
   2033     0    stevel  *   _NO_RESOURCES
   2034     0    stevel  */
   2035     0    stevel scf_iter_t *
   2036     0    stevel scf_iter_create(scf_handle_t *h)
   2037     0    stevel {
   2038     0    stevel 	scf_iter_t *iter;
   2039     0    stevel 
   2040     0    stevel 	if (h == NULL) {
   2041     0    stevel 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
   2042     0    stevel 		return (NULL);
   2043     0    stevel 	}
   2044     0    stevel 
   2045     0    stevel 	iter = uu_zalloc(sizeof (*iter));
   2046     0    stevel 	if (iter == NULL) {
   2047     0    stevel 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
   2048     0    stevel 		return (NULL);
   2049     0    stevel 	}
   2050     0    stevel 
   2051     0    stevel 	uu_list_node_init(iter, &iter->iter_node, iter_pool);
   2052     0    stevel 	iter->iter_handle = h;
   2053     0    stevel 	iter->iter_sequence = 1;
   2054     0    stevel 	iter->iter_type = REP_PROTOCOL_ENTITY_NONE;
   2055     0    stevel 
   2056     0    stevel 	(void) pthread_mutex_lock(&h->rh_lock);
   2057     0    stevel 	iter->iter_id = handle_alloc_iterid(h);
   2058   407   jwadams 	if (iter->iter_id == 0) {
   2059   407   jwadams 		(void) pthread_mutex_unlock(&h->rh_lock);
   2060   407   jwadams 		uu_list_node_fini(iter, &iter->iter_node, iter_pool);
   2061   407   jwadams 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
   2062  7887     Liane 		uu_free(iter);
   2063   407   jwadams 		return (NULL);
   2064   407   jwadams 	}
   2065     0    stevel 	if (iter_attach(iter) == -1) {
   2066     0    stevel 		uu_list_node_fini(iter, &iter->iter_node, iter_pool);
   2067     0    stevel 		(void) pthread_mutex_unlock(&h->rh_lock);
   2068     0    stevel 		uu_free(iter);
   2069     0    stevel 		return (NULL);
   2070     0    stevel 	}
   2071     0    stevel 	(void) uu_list_insert_before(h->rh_iters, NULL, iter);
   2072     0    stevel 	h->rh_extrefs++;
   2073     0    stevel 	(void) pthread_mutex_unlock(&h->rh_lock);
   2074     0    stevel 	return (iter);
   2075     0    stevel }
   2076     0    stevel 
   2077     0    stevel scf_handle_t *
   2078     0    stevel scf_iter_handle(const scf_iter_t *iter)
   2079     0    stevel {
   2080     0    stevel 	return (handle_get(iter->iter_handle));
   2081     0    stevel }
   2082     0    stevel 
   2083     0    stevel static void
   2084     0    stevel scf_iter_reset_locked(scf_iter_t *iter)
   2085     0    stevel {
   2086     0    stevel 	struct rep_protocol_iter_request request;
   2087     0    stevel 	struct rep_protocol_response response;
   2088     0    stevel 
   2089     0    stevel 	request.rpr_request = REP_PROTOCOL_ITER_RESET;
   2090     0    stevel 	request.rpr_iterid = iter->iter_id;
   2091     0    stevel 
   2092     0    stevel 	assert(MUTEX_HELD(&iter->iter_handle->rh_lock));
   2093     0    stevel 
   2094     0    stevel 	(void) make_door_call(iter->iter_handle,
   2095     0    stevel 	    &request, sizeof (request), &response, sizeof (response));
   2096     0    stevel 
   2097     0    stevel 	iter->iter_type = REP_PROTOCOL_ENTITY_NONE;
   2098     0    stevel 	iter->iter_sequence = 1;
   2099     0    stevel }
   2100     0    stevel 
   2101     0    stevel void
   2102     0    stevel scf_iter_reset(scf_iter_t *iter)
   2103     0    stevel {
   2104     0    stevel 	(void) pthread_mutex_lock(&iter->iter_handle->rh_lock);
   2105     0    stevel 	scf_iter_reset_locked(iter);
   2106     0    stevel 	(void) pthread_mutex_unlock(&iter->iter_handle->rh_lock);
   2107     0    stevel }
   2108     0    stevel 
   2109     0    stevel void
   2110     0    stevel scf_iter_destroy(scf_iter_t *iter)
   2111     0    stevel {
   2112     0    stevel 	scf_handle_t *handle;
   2113     0    stevel 
   2114     0    stevel 	struct rep_protocol_iter_request request;
   2115     0    stevel 	struct rep_protocol_response response;
   2116     0    stevel 
   2117     0    stevel 	if (iter == NULL)
   2118     0    stevel 		return;
   2119     0    stevel 
   2120     0    stevel 	handle = iter->iter_handle;
   2121     0    stevel 
   2122     0    stevel 	(void) pthread_mutex_lock(&handle->rh_lock);
   2123     0    stevel 	request.rpr_request = REP_PROTOCOL_ITER_TEARDOWN;
   2124     0    stevel 	request.rpr_iterid = iter->iter_id;
   2125     0    stevel 
   2126     0    stevel 	(void) make_door_call(handle, &request, sizeof (request),
   2127     0    stevel 	    &response, sizeof (response));
   2128     0    stevel 
   2129     0    stevel 	uu_list_remove(handle->rh_iters, iter);
   2130     0    stevel 	--handle->rh_extrefs;
   2131     0    stevel 	handle_unrefed(handle);			/* drops h->rh_lock */
   2132     0    stevel 	iter->iter_handle = NULL;
   2133     0    stevel 
   2134     0    stevel 	uu_list_node_fini(iter, &iter->iter_node, iter_pool);
   2135     0    stevel 	uu_free(iter);
   2136     0    stevel }
   2137     0    stevel 
   2138     0    stevel static int
   2139     0    stevel handle_get_local_scope_locked(scf_handle_t *handle, scf_scope_t *out)
   2140     0    stevel {
   2141     0    stevel 	struct rep_protocol_entity_get request;
   2142     0    stevel 	struct rep_protocol_name_response response;
   2143     0    stevel 	ssize_t r;
   2144     0    stevel 
   2145     0    stevel 	assert(MUTEX_HELD(&handle->rh_lock));
   2146     0    stevel 
   2147     0    stevel 	if (handle != out->rd_d.rd_handle)
   2148     0    stevel 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
   2149     0    stevel 
   2150     0    stevel 	request.rpr_request = REP_PROTOCOL_ENTITY_GET;
   2151     0    stevel 	request.rpr_entityid = out->rd_d.rd_entity;
   2152     0    stevel 	request.rpr_object = RP_ENTITY_GET_MOST_LOCAL_SCOPE;
   2153     0    stevel 
   2154     0    stevel 	datael_finish_reset(&out->rd_d);
   2155     0    stevel 	r = make_door_call(handle, &request, sizeof (request),
   2156     0    stevel 	    &response, sizeof (response));
   2157     0    stevel 
   2158     0    stevel 	if (r < 0)
   2159     0    stevel 		DOOR_ERRORS_BLOCK(r);
   2160     0    stevel 
   2161     0    stevel 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
   2162     0    stevel 		return (scf_set_error(proto_error(response.rpr_response)));
   2163     0    stevel 
   2164     0    stevel 	return (SCF_SUCCESS);
   2165     0    stevel }
   2166     0    stevel 
   2167     0    stevel int
   2168     0    stevel scf_iter_handle_scopes(scf_iter_t *iter, const scf_handle_t *handle)
   2169     0    stevel {
   2170     0    stevel 	scf_handle_t *h = iter->iter_handle;
   2171     0    stevel 	if (h != handle)
   2172     0    stevel 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
   2173     0    stevel 
   2174     0    stevel 	(void) pthread_mutex_lock(&h->rh_lock);
   2175     0    stevel 	scf_iter_reset_locked(iter);
   2176     0    stevel 
   2177     0    stevel 	if (!handle_is_bound(h)) {
   2178     0    stevel 		(void) pthread_mutex_unlock(&h->rh_lock);
   2179     0    stevel 		return (scf_set_error(SCF_ERROR_NOT_BOUND));
   2180     0    stevel 	}
   2181     0    stevel 
   2182   407   jwadams 	if (!handle_has_server_locked(h)) {
   2183     0    stevel 		(void) pthread_mutex_unlock(&h->rh_lock);
   2184     0    stevel 		return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN));
   2185     0    stevel 	}
   2186     0    stevel 
   2187     0    stevel 	iter->iter_type = REP_PROTOCOL_ENTITY_SCOPE;
   2188     0    stevel 	iter->iter_sequence = 1;
   2189     0    stevel 	(void) pthread_mutex_unlock(&h->rh_lock);
   2190     0    stevel 	return (0);
   2191     0    stevel }
   2192     0    stevel 
   2193     0    stevel int
   2194     0    stevel scf_iter_next_scope(scf_iter_t *iter, scf_scope_t *out)
   2195     0    stevel {
   2196     0    stevel 	int ret;
   2197     0    stevel 	scf_handle_t *h = iter->iter_handle;
   2198     0    stevel 
   2199     0    stevel 	if (h != out->rd_d.rd_handle)
   2200     0    stevel 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
   2201     0    stevel 
   2202     0    stevel 	(void) pthread_mutex_lock(&h->rh_lock);
   2203     0    stevel 	if (iter->iter_type == REP_PROTOCOL_ENTITY_NONE) {
   2204     0    stevel 		(void) pthread_mutex_unlock(&h->rh_lock);
   2205     0    stevel 		return (scf_set_error(SCF_ERROR_NOT_SET));
   2206     0    stevel 	}
   2207     0    stevel 	if (iter->iter_type != REP_PROTOCOL_ENTITY_SCOPE) {
   2208     0    stevel 		(void) pthread_mutex_unlock(&h->rh_lock);
   2209     0    stevel 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
   2210     0    stevel 	}
   2211     0    stevel 	if (iter->iter_sequence == 1) {
   2212     0    stevel 		if ((ret = handle_get_local_scope_locked(h, out)) ==
   2213     0    stevel 		    SCF_SUCCESS) {
   2214     0    stevel 			iter->iter_sequence++;
   2215     0    stevel 			ret = 1;
   2216     0    stevel 		}
   2217     0    stevel 	} else {
   2218     0    stevel 		datael_reset_locked(&out->rd_d);
   2219     0    stevel 		ret = 0;
   2220     0    stevel 	}
   2221     0    stevel 	(void) pthread_mutex_unlock(&h->rh_lock);
   2222     0    stevel 	return (ret);
   2223     0    stevel }
   2224     0    stevel 
   2225     0    stevel int
   2226     0    stevel scf_handle_get_scope(scf_handle_t *h, const char *name, scf_scope_t *out)
   2227     0    stevel {
   2228     0    stevel 	int ret;
   2229     0    stevel 
   2230     0    stevel 	if (h != out->rd_d.rd_handle)
   2231     0    stevel 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
   2232     0    stevel 
   2233     0    stevel 	(void) pthread_mutex_lock(&h->rh_lock);
   2234     0    stevel 	if (strcmp(name, SCF_SCOPE_LOCAL) == 0) {
   2235     0    stevel 		ret = handle_get_local_scope_locked(h, out);
   2236     0    stevel 	} else {
   2237     0    stevel 		datael_reset_locked(&out->rd_d);
   2238     0    stevel 		if (uu_check_name(name, 0) == -1)
   2239     0    stevel 			ret = scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
   2240     0    stevel 		else
   2241     0    stevel 			ret = scf_set_error(SCF_ERROR_NOT_FOUND);
   2242     0    stevel 	}
   2243     0    stevel 	(void) pthread_mutex_unlock(&h->rh_lock);
   2244     0    stevel 	return (ret);
   2245     0    stevel }
   2246     0    stevel 
   2247     0    stevel static int
   2248     0    stevel datael_setup_iter(scf_iter_t *iter, const scf_datael_t *dp, uint32_t res_type,
   2249     0    stevel     boolean_t composed)
   2250     0    stevel {
   2251     0    stevel 	scf_handle_t *h = dp->rd_handle;
   2252     0    stevel 
   2253     0    stevel 	struct rep_protocol_iter_start request;
   2254     0    stevel 	struct rep_protocol_response response;
   2255     0    stevel 
   2256     0    stevel 	ssize_t r;
   2257     0    stevel 
   2258     0    stevel 	if (h != iter->iter_handle)
   2259     0    stevel 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
   2260     0    stevel 
   2261     0    stevel 	(void) pthread_mutex_lock(&h->rh_lock);
   2262     0    stevel 	scf_iter_reset_locked(iter);
   2263     0    stevel 	iter->iter_type = res_type;
   2264     0    stevel 
   2265     0    stevel 	request.rpr_request = REP_PROTOCOL_ITER_START;
   2266     0    stevel 	request.rpr_iterid = iter->iter_id;
   2267     0    stevel 	request.rpr_entity = dp->rd_entity;
   2268     0    stevel 	request.rpr_itertype = res_type;
   2269     0    stevel 	request.rpr_flags = RP_ITER_START_ALL |
   2270     0    stevel 	    (composed ? RP_ITER_START_COMPOSED : 0);
   2271     0    stevel 	request.rpr_pattern[0] = 0;
   2272     0    stevel 
   2273     0    stevel 	datael_finish_reset(dp);
   2274     0    stevel 	r = make_door_call(h, &request, sizeof (request),
   2275     0    stevel 	    &response, sizeof (response));
   2276     0    stevel 
   2277     0    stevel 	if (r < 0) {
   2278     0    stevel 		(void) pthread_mutex_unlock(&h->rh_lock);
   2279     0    stevel 		DOOR_ERRORS_BLOCK(r);
   2280     0    stevel 	}
   2281     0    stevel 	if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
   2282     0    stevel 		(void) pthread_mutex_unlock(&h->rh_lock);
   2283     0    stevel 		return (scf_set_error(proto_error(response.rpr_response)));
   2284     0    stevel 	}
   2285     0    stevel 	iter->iter_sequence++;
   2286     0    stevel 	(void) pthread_mutex_unlock(&h->rh_lock);
   2287     0    stevel 	return (SCF_SUCCESS);
   2288     0    stevel }
   2289     0    stevel 
   2290     0    stevel static int
   2291     0    stevel datael_setup_iter_pgtyped(scf_iter_t *iter, const scf_datael_t *dp,
   2292     0    stevel     const char *pgtype, boolean_t composed)
   2293     0    stevel {
   2294     0    stevel 	scf_handle_t *h = dp->rd_handle;
   2295     0    stevel 
   2296     0    stevel 	struct rep_protocol_iter_start request;
   2297     0    stevel 	struct rep_protocol_response response;
   2298     0    stevel 
   2299     0    stevel 	ssize_t r;
   2300     0    stevel 
   2301     0    stevel 	if (h != iter->iter_handle)
   2302     0    stevel 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
   2303     0    stevel 
   2304     0    stevel 	if (pgtype == NULL || strlcpy(request.rpr_pattern, pgtype,
   2305     0    stevel 	    sizeof (request.rpr_pattern)) >= sizeof (request.rpr_pattern)) {
   2306     0    stevel 		scf_iter_reset(iter);
   2307     0    stevel 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
   2308     0    stevel 	}
   2309     0    stevel 
   2310     0    stevel 	(void) pthread_mutex_lock(&h->rh_lock);
   2311     0    stevel 	request.rpr_request = REP_PROTOCOL_ITER_START;
   2312     0    stevel 	request.rpr_iterid = iter->iter_id;
   2313     0    stevel 	request.rpr_entity = dp->rd_entity;
   2314     0    stevel 	request.rpr_itertype = REP_PROTOCOL_ENTITY_PROPERTYGRP;
   2315     0    stevel 	request.rpr_flags = RP_ITER_START_PGTYPE |
   2316     0    stevel 	    (composed ? RP_ITER_START_COMPOSED : 0);
   2317     0    stevel 
   2318     0    stevel 	datael_finish_reset(dp);
   2319     0    stevel 	scf_iter_reset_locked(iter);
   2320     0    stevel 	iter->iter_type = REP_PROTOCOL_ENTITY_PROPERTYGRP;
   2321     0    stevel 
   2322     0    stevel 	r = make_door_call(h, &request, sizeof (request),
   2323     0    stevel 	    &response, sizeof (response));
   2324     0    stevel 
   2325     0    stevel 	if (r < 0) {
   2326     0    stevel 		(void) pthread_mutex_unlock(&h->rh_lock);
   2327     0    stevel 
   2328     0    stevel 		DOOR_ERRORS_BLOCK(r);
   2329     0    stevel 	}
   2330     0    stevel 	if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
   2331     0    stevel 		(void) pthread_mutex_unlock(&h->rh_lock);
   2332     0    stevel 		return (scf_set_error(proto_error(response.rpr_response)));
   2333     0    stevel 	}
   2334     0    stevel 	iter->iter_sequence++;
   2335     0    stevel 	(void) pthread_mutex_unlock(&h->rh_lock);
   2336     0    stevel 	return (SCF_SUCCESS);
   2337     0    stevel }
   2338     0    stevel 
   2339     0    stevel static int
   2340     0    stevel datael_iter_next(scf_iter_t *iter, scf_datael_t *out)
   2341     0    stevel {
   2342     0    stevel 	scf_handle_t *h = iter->iter_handle;
   2343     0    stevel 
   2344     0    stevel 	struct rep_protocol_iter_read request;
   2345     0    stevel 	struct rep_protocol_response response;
   2346     0    stevel 	ssize_t r;
   2347     0    stevel 
   2348     0    stevel 	if (h != out->rd_handle)
   2349     0    stevel 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
   2350     0    stevel 
   2351     0    stevel 	(void) pthread_mutex_lock(&h->rh_lock);
   2352     0    stevel 	if (iter->iter_type == REP_PROTOCOL_ENTITY_NONE ||
   2353     0    stevel 	    iter->iter_sequence == 1) {
   2354     0    stevel 		(void) pthread_mutex_unlock(&h->rh_lock);
   2355     0    stevel 		return (scf_set_error(SCF_ERROR_NOT_SET));
   2356     0    stevel 	}
   2357     0    stevel 
   2358     0    stevel 	if (out->rd_type != iter->iter_type) {
   2359     0    stevel 		(void) pthread_mutex_unlock(&h->rh_lock);
   2360     0    stevel 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
   2361     0    stevel 	}
   2362     0    stevel 
   2363     0    stevel 	request.rpr_request = REP_PROTOCOL_ITER_READ;
   2364     0    stevel 	request.rpr_iterid = iter->iter_id;
   2365     0    stevel 	request.rpr_sequence = iter->iter_sequence;
   2366     0    stevel 	request.rpr_entityid = out->rd_entity;
   2367     0    stevel 
   2368     0    stevel 	datael_finish_reset(out);
   2369     0    stevel 	r = make_door_call(h, &request, sizeof (request),
   2370     0    stevel 	    &response, sizeof (response));
   2371     0    stevel 
   2372     0    stevel 	if (r < 0) {
   2373     0    stevel 		(void) pthread_mutex_unlock(&h->rh_lock);
   2374     0    stevel 		DOOR_ERRORS_BLOCK(r);
   2375     0    stevel 	}
   2376     0    stevel 
   2377     0    stevel 	if (response.rpr_response == REP_PROTOCOL_DONE) {
   2378     0    stevel 		(void) pthread_mutex_unlock(&h->rh_lock);
   2379     0    stevel 		return (0);
   2380     0    stevel 	}
   2381     0    stevel 	if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
   2382     0    stevel 		(void) pthread_mutex_unlock(&h->rh_lock);
   2383     0    stevel 		return (scf_set_error(proto_error(response.rpr_response)));
   2384     0    stevel 	}
   2385     0    stevel 	iter->iter_sequence++;
   2386     0    stevel 	(void) pthread_mutex_unlock(&h->rh_lock);
   2387     0    stevel 
   2388     0    stevel 	return (1);
   2389     0    stevel }
   2390     0    stevel 
   2391     0    stevel int
   2392     0    stevel scf_iter_scope_services(scf_iter_t *iter, const scf_scope_t *s)
   2393     0    stevel {
   2394     0    stevel 	return (datael_setup_iter(iter, &s->rd_d,
   2395     0    stevel 	    REP_PROTOCOL_ENTITY_SERVICE, 0));
   2396     0    stevel }
   2397     0    stevel 
   2398     0    stevel int
   2399     0    stevel scf_iter_next_service(scf_iter_t *iter, scf_service_t *out)
   2400     0    stevel {
   2401     0    stevel 	return (datael_iter_next(iter, &out->rd_d));
   2402     0    stevel }
   2403     0    stevel 
   2404     0    stevel int
   2405     0    stevel scf_iter_service_instances(scf_iter_t *iter, const scf_service_t *svc)
   2406     0    stevel {
   2407     0    stevel 	return (datael_setup_iter(iter, &svc->rd_d,
   2408     0    stevel 	    REP_PROTOCOL_ENTITY_INSTANCE, 0));
   2409     0    stevel }
   2410     0    stevel 
   2411     0    stevel int
   2412     0    stevel scf_iter_next_instance(scf_iter_t *iter, scf_instance_t *out)
   2413     0    stevel {
   2414     0    stevel 	return (datael_iter_next(iter, &out->rd_d));
   2415     0    stevel }
   2416     0    stevel 
   2417     0    stevel int
   2418     0    stevel scf_iter_service_pgs(scf_iter_t *iter, const scf_service_t *svc)
   2419     0    stevel {
   2420     0    stevel 	return (datael_setup_iter(iter, &svc->rd_d,
   2421     0    stevel 	    REP_PROTOCOL_ENTITY_PROPERTYGRP, 0));
   2422     0    stevel }
   2423     0    stevel 
   2424     0    stevel int
   2425     0    stevel scf_iter_service_pgs_typed(scf_iter_t *iter, const scf_service_t *svc,
   2426     0    stevel     const char *type)
   2427     0    stevel {
   2428     0    stevel 	return (datael_setup_iter_pgtyped(iter, &svc->rd_d, type, 0));
   2429     0    stevel }
   2430     0    stevel 
   2431     0    stevel int
   2432     0    stevel scf_iter_instance_snapshots(scf_iter_t *iter, const scf_instance_t *inst)
   2433     0    stevel {
   2434     0    stevel 	return (datael_setup_iter(iter, &inst->rd_d,
   2435     0    stevel 	    REP_PROTOCOL_ENTITY_SNAPSHOT, 0));
   2436     0    stevel }
   2437     0    stevel 
   2438     0    stevel int
   2439     0    stevel scf_iter_next_snapshot(scf_iter_t *iter, scf_snapshot_t *out)
   2440     0    stevel {
   2441     0    stevel 	return (datael_iter_next(iter, &out->rd_d));
   2442     0    stevel }
   2443     0    stevel 
   2444     0    stevel int
   2445     0    stevel scf_iter_instance_pgs(scf_iter_t *iter, const scf_instance_t *inst)
   2446     0    stevel {
   2447     0    stevel 	return (datael_setup_iter(iter, &inst->rd_d,
   2448     0    stevel 	    REP_PROTOCOL_ENTITY_PROPERTYGRP, 0));
   2449     0    stevel }
   2450     0    stevel 
   2451     0    stevel int
   2452     0    stevel scf_iter_instance_pgs_typed(scf_iter_t *iter, const scf_instance_t *inst,
   2453     0    stevel     const char *type)
   2454     0    stevel {
   2455     0    stevel 	return (datael_setup_iter_pgtyped(iter, &inst->rd_d, type, 0));
   2456     0    stevel }
   2457     0    stevel 
   2458     0    stevel int
   2459     0    stevel scf_iter_instance_pgs_composed(scf_iter_t *iter, const scf_instance_t *inst,
   2460     0    stevel     const scf_snapshot_t *snap)
   2461     0    stevel {
   2462     0    stevel 	if (snap != NULL && inst->rd_d.rd_handle != snap->rd_d.rd_handle)
   2463     0    stevel 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
   2464     0    stevel 
   2465     0    stevel 	return (datael_setup_iter(iter, snap ? &snap->rd_d : &inst->rd_d,
   2466     0    stevel 	    REP_PROTOCOL_ENTITY_PROPERTYGRP, 1));
   2467     0    stevel }
   2468     0    stevel 
   2469     0    stevel int
   2470     0    stevel scf_iter_instance_pgs_typed_composed(scf_iter_t *iter,
   2471     0    stevel     const scf_instance_t *inst, const scf_snapshot_t *snap, const char *type)
   2472     0    stevel {
   2473     0    stevel 	if (snap != NULL && inst->rd_d.rd_handle != snap->rd_d.rd_handle)
   2474     0    stevel 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
   2475     0    stevel 
   2476     0    stevel 	return (datael_setup_iter_pgtyped(iter,
   2477     0    stevel 	    snap ? &snap->rd_d : &inst->rd_d, type, 1));
   2478     0    stevel }
   2479     0    stevel 
   2480     0    stevel int
   2481     0    stevel scf_iter_snaplevel_pgs(scf_iter_t *iter, const scf_snaplevel_t *inst)
   2482     0    stevel {
   2483     0    stevel 	return (datael_setup_iter(iter, &inst->rd_d,
   2484     0    stevel 	    REP_PROTOCOL_ENTITY_PROPERTYGRP, 0));
   2485     0    stevel }
   2486     0    stevel 
   2487     0    stevel int
   2488     0    stevel scf_iter_snaplevel_pgs_typed(scf_iter_t *iter, const scf_snaplevel_t *inst,
   2489     0    stevel     const char *type)
   2490     0    stevel {
   2491     0    stevel 	return (datael_setup_iter_pgtyped(iter, &inst->rd_d, type, 0));
   2492     0    stevel }
   2493     0    stevel 
   2494     0    stevel int
   2495     0    stevel scf_iter_next_pg(scf_iter_t *iter, scf_propertygroup_t *out)
   2496     0    stevel {
   2497     0    stevel 	return (datael_iter_next(iter, &out->rd_d));
   2498     0    stevel }
   2499     0    stevel 
   2500     0    stevel int
   2501     0    stevel scf_iter_pg_properties(scf_iter_t *iter, const scf_propertygroup_t *pg)
   2502     0    stevel {
   2503     0    stevel 	return (datael_setup_iter(iter, &pg->rd_d,
   2504     0    stevel 	    REP_PROTOCOL_ENTITY_PROPERTY, 0));
   2505     0    stevel }
   2506     0    stevel 
   2507     0    stevel int
   2508     0    stevel scf_iter_next_property(scf_iter_t *iter, scf_property_t *out)
   2509     0    stevel {
   2510     0    stevel 	return (datael_iter_next(iter, &out->rd_d));
   2511     0    stevel }
   2512     0    stevel 
   2513     0    stevel /*
   2514     0    stevel  * Fails with
   2515     0    stevel  *   _INVALID_ARGUMENT - handle is NULL
   2516     0    stevel  *   _INTERNAL - server response too big
   2517     0    stevel  *		 entity already set up with different type
   2518     0    stevel  *   _NO_RESOURCES
   2519     0    stevel  *   _NO_MEMORY
   2520     0    stevel  */
   2521     0    stevel scf_scope_t *
   2522     0    stevel scf_scope_create(scf_handle_t *handle)
   2523     0    stevel {
   2524     0    stevel 	scf_scope_t *ret;
   2525     0    stevel 
   2526     0    stevel 	ret = uu_zalloc(sizeof (*ret));
   2527     0    stevel 	if (ret != NULL) {
   2528     0    stevel 		if (datael_init(&ret->rd_d, handle,
   2529     0    stevel 		    REP_PROTOCOL_ENTITY_SCOPE) == -1) {
   2530     0    stevel 			uu_free(ret);
   2531     0    stevel 			return (NULL);
   2532     0    stevel 		}
   2533     0    stevel 	} else {
   2534     0    stevel 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
   2535     0    stevel 	}
   2536     0    stevel 
   2537     0    stevel 	return (ret);
   2538     0    stevel }
   2539     0    stevel 
   2540     0    stevel scf_handle_t *
   2541     0    stevel scf_scope_handle(const scf_scope_t *val)
   2542     0    stevel {
   2543     0    stevel 	return (datael_handle(&val->rd_d));
   2544     0    stevel }
   2545     0    stevel 
   2546     0    stevel void
   2547     0    stevel scf_scope_destroy(scf_scope_t *val)
   2548     0    stevel {
   2549     0    stevel 	if (val == NULL)
   2550     0    stevel 		return;
   2551     0    stevel 
   2552     0    stevel 	datael_destroy(&val->rd_d);
   2553     0    stevel 	uu_free(val);
   2554     0    stevel }
   2555     0    stevel 
   2556     0    stevel ssize_t
   2557     0    stevel scf_scope_get_name(const scf_scope_t *rep, char *out, size_t len)
   2558     0    stevel {
   2559     0    stevel 	return (datael_get_name(&rep->rd_d, out, len, RP_ENTITY_NAME_NAME));
   2560     0    stevel }
   2561     0    stevel 
   2562     0    stevel /*ARGSUSED*/
   2563     0    stevel int
   2564     0    stevel scf_scope_get_parent(const scf_scope_t *child, scf_scope_t *parent)
   2565     0    stevel {
   2566     0    stevel 	char name[1];
   2567     0    stevel 
   2568     0    stevel 	/* fake up the side-effects */
   2569     0    stevel 	datael_reset(&parent->rd_d);
   2570     0    stevel 	if (scf_scope_get_name(child, name, sizeof (name)) < 0)
   2571     0    stevel 		return (-1);
   2572     0    stevel 	return (scf_set_error(SCF_ERROR_NOT_FOUND));
   2573     0    stevel }
   2574     0    stevel 
   2575     0    stevel /*
   2576     0    stevel  * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
   2577     0    stevel  * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
   2578     0    stevel  */
   2579     0    stevel scf_service_t *
   2580     0    stevel scf_service_create(scf_handle_t *handle)
   2581     0    stevel {
   2582     0    stevel 	scf_service_t *ret;
   2583     0    stevel 	ret = uu_zalloc(sizeof (*ret));
   2584     0    stevel 	if (ret != NULL) {
   2585     0    stevel 		if (datael_init(&ret->rd_d, handle,
   2586     0    stevel 		    REP_PROTOCOL_ENTITY_SERVICE) == -1) {
   2587     0    stevel 			uu_free(ret);
   2588     0    stevel 			return (NULL);
   2589     0    stevel 		}
   2590     0    stevel 	} else {
   2591     0    stevel 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
   2592     0    stevel 	}
   2593     0    stevel 
   2594     0    stevel 	return (ret);
   2595     0    stevel }
   2596     0    stevel 
   2597  4740     jeanm 
   2598  4740     jeanm /*
   2599  4740     jeanm  * Fails with
   2600  4740     jeanm  *   _HANDLE_MISMATCH
   2601  4740     jeanm  *   _INVALID_ARGUMENT
   2602  4740     jeanm  *   _NOT_BOUND
   2603  4740     jeanm  *   _CONNECTION_BROKEN
   2604  4740     jeanm  *   _INTERNAL
   2605  4740     jeanm  *   _EXISTS
   2606  4740     jeanm  *   _DELETED
   2607  4740     jeanm  *   _NOT_SET
   2608  4740     jeanm  *   _NO_RESOURCES
   2609  4740     jeanm  *   _PERMISSION_DENIED
   2610  4740     jeanm  *   _BACKEND_ACCESS
   2611  4740     jeanm  *   _BACKEND_READONLY
   2612  4740     jeanm  */
   2613     0    stevel int
   2614     0    stevel scf_scope_add_service(const scf_scope_t *scope, const char *name,
   2615     0    stevel     scf_service_t *svc)
   2616     0    stevel {
   2617     0    stevel 	return (datael_add_child(&scope->rd_d, name,
   2618     0    stevel 	    REP_PROTOCOL_ENTITY_SERVICE, (svc != NULL)? &svc->rd_d : NULL));
   2619     0    stevel }
   2620     0    stevel 
   2621  4740     jeanm /*
   2622  4740     jeanm  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
   2623  4740     jeanm  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
   2624  4740     jeanm  * _BACKEND_ACCESS, _NOT_FOUND.
   2625  4740     jeanm  */
   2626     0    stevel int
   2627     0    stevel scf_scope_get_service(const scf_scope_t *s, const char *name,
   2628     0    stevel     scf_service_t *svc)
   2629     0    stevel {
   2630     0    stevel 	return (datael_get_child(&s->rd_d, name, REP_PROTOCOL_ENTITY_SERVICE,
   2631     0    stevel 	    svc ? &svc->rd_d : NULL, 0));
   2632     0    stevel }
   2633     0    stevel 
   2634     0    stevel scf_handle_t *
   2635     0    stevel scf_service_handle(const scf_service_t *val)
   2636     0    stevel {
   2637     0    stevel 	return (datael_handle(&val->rd_d));
   2638     0    stevel }
   2639     0    stevel 
   2640     0    stevel int
   2641     0    stevel scf_service_delete(scf_service_t *svc)
   2642     0    stevel {
   2643     0    stevel 	return (datael_delete(&svc->rd_d));
   2644     0    stevel }
   2645     0    stevel 
   2646     0    stevel int
   2647     0    stevel scf_instance_delete(scf_instance_t *inst)
   2648     0    stevel {
   2649     0    stevel 	return (datael_delete(&inst->rd_d));
   2650     0    stevel }
   2651     0    stevel 
   2652     0    stevel int
   2653     0    stevel scf_pg_delete(scf_propertygroup_t *pg)
   2654     0    stevel {
   2655     0    stevel 	return (datael_delete(&pg->rd_d));
   2656     0    stevel }
   2657     0    stevel 
   2658     0    stevel int
   2659     0    stevel _scf_snapshot_delete(scf_snapshot_t *snap)
   2660     0    stevel {
   2661     0    stevel 	return (datael_delete(&snap->rd_d));
   2662     0    stevel }
   2663     0    stevel 
   2664  4740     jeanm /*
   2665  4740     jeanm  * Fails with
   2666  4740     jeanm  *   _HANDLE_MISMATCH
   2667  4740     jeanm  *   _INVALID_ARGUMENT
   2668  4740     jeanm  *   _NOT_BOUND
   2669  4740     jeanm  *   _CONNECTION_BROKEN
   2670  4740     jeanm  *   _INTERNAL
   2671  4740     jeanm  *   _EXISTS
   2672  4740     jeanm  *   _DELETED
   2673  4740     jeanm  *   _NOT_SET
   2674  4740     jeanm  *   _NO_RESOURCES
   2675  4740     jeanm  *   _PERMISSION_DENIED
   2676  4740     jeanm  *   _BACKEND_ACCESS
   2677  4740     jeanm  *   _BACKEND_READONLY
   2678  4740     jeanm  */
   2679     0    stevel int
   2680     0    stevel scf_service_add_instance(const scf_service_t *svc, const char *name,
   2681     0    stevel     scf_instance_t *instance)
   2682     0    stevel {
   2683     0    stevel 	return (datael_add_child(&svc->rd_d, name,
   2684     0    stevel 	    REP_PROTOCOL_ENTITY_INSTANCE,
   2685     0    stevel 	    (instance != NULL)? &instance->rd_d : NULL));
   2686     0    stevel }
   2687     0    stevel 
   2688  4740     jeanm 
   2689  4740     jeanm /*
   2690  4740     jeanm  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
   2691  4740     jeanm  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
   2692  4740     jeanm  * _BACKEND_ACCESS, _NOT_FOUND.
   2693  4740     jeanm  */
   2694     0    stevel int
   2695     0    stevel scf_service_get_instance(const scf_service_t *svc, const char *name,
   2696     0    stevel     scf_instance_t *inst)
   2697     0    stevel {
   2698     0    stevel 	return (datael_get_child(&svc->rd_d, name, REP_PROTOCOL_ENTITY_INSTANCE,
   2699     0    stevel 	    inst ? &inst->rd_d : NULL, 0));
   2700     0    stevel }
   2701     0    stevel 
   2702     0    stevel int
   2703     0    stevel scf_service_add_pg(const scf_service_t *svc, const char *name,
   2704     0    stevel     const char *type, uint32_t flags, scf_propertygroup_t *pg)
   2705     0    stevel {
   2706     0    stevel 	return (datael_add_pg(&svc->rd_d, name, type, flags,
   2707     0    stevel 	    (pg != NULL)?&pg->rd_d : NULL));
   2708     0    stevel }
   2709     0    stevel 
   2710  4740     jeanm /*
   2711  4740     jeanm  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
   2712  4740     jeanm  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
   2713  4740     jeanm  * _BACKEND_ACCESS, _NOT_FOUND.
   2714  4740     jeanm  */
   2715     0    stevel int
   2716     0    stevel scf_service_get_pg(const scf_service_t *svc, const char *name,
   2717     0    stevel     scf_propertygroup_t *pg)
   2718     0    stevel {
   2719     0    stevel 	return (datael_get_child(&svc->rd_d, name,
   2720     0    stevel 	    REP_PROTOCOL_ENTITY_PROPERTYGRP, pg ? &pg->rd_d : NULL, 0));
   2721     0    stevel }
   2722     0    stevel 
   2723     0    stevel int
   2724     0    stevel scf_instance_add_pg(const scf_instance_t *inst, const char *name,
   2725     0    stevel     const char *type, uint32_t flags, scf_propertygroup_t *pg)
   2726     0    stevel {
   2727     0    stevel 	return (datael_add_pg(&inst->rd_d, name, type, flags,
   2728     0    stevel 	    (pg != NULL)?&pg->rd_d : NULL));
   2729     0    stevel }
   2730     0    stevel 
   2731  4740     jeanm /*
   2732  4740     jeanm  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
   2733  4740     jeanm  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
   2734  4740     jeanm  * _BACKEND_ACCESS, _NOT_FOUND.
   2735  4740     jeanm  */
   2736     0    stevel int
   2737     0    stevel scf_instance_get_snapshot(const scf_instance_t *inst, const char *name,
   2738     0    stevel     scf_snapshot_t *pg)
   2739     0    stevel {
   2740     0    stevel 	return (datael_get_child(&inst->rd_d, name,
   2741     0    stevel 	    REP_PROTOCOL_ENTITY_SNAPSHOT, pg ? &pg->rd_d : NULL, 0));
   2742     0    stevel }
   2743     0    stevel 
   2744  4740     jeanm /*
   2745  4740     jeanm  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
   2746  4740     jeanm  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
   2747  4740     jeanm  * _BACKEND_ACCESS, _NOT_FOUND.
   2748  4740     jeanm  */
   2749     0    stevel int
   2750     0    stevel scf_instance_get_pg(const scf_instance_t *inst, const char *name,
   2751     0    stevel     scf_propertygroup_t *pg)
   2752     0    stevel {
   2753     0    stevel 	return (datael_get_child(&inst->rd_d, name,
   2754     0    stevel 	    REP_PROTOCOL_ENTITY_PROPERTYGRP, pg ? &pg->rd_d : NULL, 0));
   2755     0    stevel }
   2756     0    stevel 
   2757  4740     jeanm /*
   2758  4740     jeanm  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
   2759  4740     jeanm  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
   2760  4740     jeanm  * _BACKEND_ACCESS, _NOT_FOUND.
   2761  4740     jeanm  */
   2762     0    stevel int
   2763     0    stevel scf_instance_get_pg_composed(const scf_instance_t *inst,
   2764     0    stevel     const scf_snapshot_t *snap, const char *name, scf_propertygroup_t *pg)
   2765     0    stevel {
   2766     0    stevel 	if (snap != NULL && inst->rd_d.rd_handle != snap->rd_d.rd_handle)
   2767     0    stevel 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
   2768     0    stevel 
   2769     0    stevel 	return (datael_get_child(snap ? &snap->rd_d : &inst->rd_d, name,
   2770     0    stevel 	    REP_PROTOCOL_ENTITY_PROPERTYGRP, pg ? &pg->rd_d : NULL, 1));
   2771     0    stevel }
   2772     0    stevel 
   2773  4740     jeanm /*
   2774  4740     jeanm  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
   2775  4740     jeanm  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
   2776  4740     jeanm  * _BACKEND_ACCESS, _NOT_FOUND.
   2777  4740     jeanm  */
   2778     0    stevel int
   2779     0    stevel scf_pg_get_property(const scf_propertygroup_t *pg, const char *name,
   2780     0    stevel     scf_property_t *prop)
   2781     0    stevel {
   2782     0    stevel 	return (datael_get_child(&pg->rd_d, name, REP_PROTOCOL_ENTITY_PROPERTY,
   2783     0    stevel 	    prop ? &prop->rd_d : NULL, 0));
   2784     0    stevel }
   2785     0    stevel 
   2786     0    stevel void
   2787     0    stevel scf_service_destroy(scf_service_t *val)
   2788     0    stevel {
   2789     0    stevel 	if (val == NULL)
   2790     0    stevel 		return;
   2791     0    stevel 
   2792     0    stevel 	datael_destroy(&val->rd_d);
   2793     0    stevel 	uu_free(val);
   2794     0    stevel }
   2795     0    stevel 
   2796     0    stevel ssize_t
   2797     0    stevel scf_service_get_name(const scf_service_t *rep, char *out, size_t len)
   2798     0    stevel {
   2799     0    stevel 	return (datael_get_name(&rep->rd_d, out, len, RP_ENTITY_NAME_NAME));
   2800     0    stevel }
   2801     0    stevel 
   2802     0    stevel /*
   2803     0    stevel  * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
   2804     0    stevel  * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
   2805     0    stevel  */
   2806     0    stevel scf_instance_t *
   2807     0    stevel scf_instance_create(scf_handle_t *handle)
   2808     0    stevel {
   2809     0    stevel 	scf_instance_t *ret;
   2810     0    stevel 
   2811     0    stevel 	ret = uu_zalloc(sizeof (*ret));
   2812     0    stevel 	if (ret != NULL) {
   2813     0    stevel 		if (datael_init(&ret->rd_d, handle,
   2814     0    stevel 		    REP_PROTOCOL_ENTITY_INSTANCE) == -1) {
   2815     0    stevel 			uu_free(ret);
   2816     0    stevel 			return (NULL);
   2817     0    stevel 		}
   2818     0    stevel 	} else {
   2819     0    stevel 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
   2820     0    stevel 	}
   2821     0    stevel 
   2822     0    stevel 	return (ret);
   2823     0    stevel }
   2824     0    stevel 
   2825     0    stevel scf_handle_t *
   2826     0    stevel scf_instance_handle(const scf_instance_t *val)
   2827     0    stevel {
   2828     0    stevel 	return (datael_handle(&val->rd_d));
   2829     0    stevel }
   2830     0    stevel 
   2831     0    stevel void
   2832     0    stevel scf_instance_destroy(scf_instance_t *val)
   2833     0    stevel {
   2834     0    stevel 	if (val == NULL)
   2835     0    stevel 		return;
   2836     0    stevel 
   2837     0    stevel 	datael_destroy(&val->rd_d);
   2838     0    stevel 	uu_free(val);
   2839     0    stevel }
   2840     0    stevel 
   2841     0    stevel ssize_t
   2842     0    stevel scf_instance_get_name(const scf_instance_t *rep, char *out, size_t len)
   2843     0    stevel {
   2844     0    stevel 	return (datael_get_name(&rep->rd_d, out, len, RP_ENTITY_NAME_NAME));
   2845     0    stevel }
   2846     0    stevel 
   2847     0    stevel /*
   2848     0    stevel  * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
   2849     0    stevel  * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
   2850     0    stevel  */
   2851     0    stevel scf_snapshot_t *
   2852     0    stevel scf_snapshot_create(scf_handle_t *handle)
   2853     0    stevel {
   2854     0    stevel 	scf_snapshot_t *ret;
   2855     0    stevel 
   2856     0    stevel 	ret = uu_zalloc(sizeof (*ret));
   2857     0    stevel 	if (ret != NULL) {
   2858     0    stevel 		if (datael_init(&ret->rd_d, handle,
   2859     0    stevel 		    REP_PROTOCOL_ENTITY_SNAPSHOT) == -1) {
   2860     0    stevel 			uu_free(ret);
   2861     0    stevel 			return (NULL);
   2862     0    stevel 		}
   2863     0    stevel 	} else {
   2864     0    stevel 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
   2865     0    stevel 	}
   2866     0    stevel 
   2867     0    stevel 	return (ret);
   2868     0    stevel }
   2869     0    stevel 
   2870     0    stevel scf_handle_t *
   2871     0    stevel scf_snapshot_handle(const scf_snapshot_t *val)
   2872     0    stevel {
   2873     0    stevel 	return (datael_handle(&val->rd_d));
   2874     0    stevel }
   2875     0    stevel 
   2876     0    stevel void
   2877     0    stevel scf_snapshot_destroy(scf_snapshot_t *val)
   2878     0    stevel {
   2879     0    stevel 	if (val == NULL)
   2880     0    stevel 		return;
   2881     0    stevel 
   2882     0    stevel 	datael_destroy(&val->rd_d);
   2883     0    stevel 	uu_free(val);
   2884     0    stevel }
   2885     0    stevel 
   2886     0    stevel ssize_t
   2887     0    stevel scf_snapshot_get_name(const scf_snapshot_t *rep, char *out, size_t len)
   2888     0    stevel {
   2889     0    stevel 	return (datael_get_name(&rep->rd_d, out, len, RP_ENTITY_NAME_NAME));
   2890     0    stevel }
   2891     0    stevel 
   2892     0    stevel /*
   2893     0    stevel  * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
   2894     0    stevel  * (bad server response or id in use), _NO_RESOURCES, _NO_MEMORY.
   2895     0    stevel  */
   2896     0    stevel scf_snaplevel_t *
   2897     0    stevel scf_snaplevel_create(scf_handle_t *handle)
   2898     0    stevel {
   2899     0    stevel 	scf_snaplevel_t *ret;
   2900     0    stevel 
   2901     0    stevel 	ret = uu_zalloc(sizeof (*ret));
   2902     0    stevel 	if (ret != NULL) {
   2903     0    stevel 		if (datael_init(&ret->rd_d, handle,
   2904     0    stevel 		    REP_PROTOCOL_ENTITY_SNAPLEVEL) == -1) {
   2905     0    stevel 			uu_free(ret);
   2906     0    stevel 			return (NULL);
   2907     0    stevel 		}
   2908     0    stevel 	} else {
   2909     0    stevel 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
   2910     0    stevel 	}
   2911     0    stevel 
   2912     0    stevel 	return (ret);
   2913     0    stevel }
   2914     0    stevel 
   2915     0    stevel scf_handle_t *
   2916     0    stevel scf_snaplevel_handle(const scf_snaplevel_t *val)
   2917     0    stevel {
   2918     0    stevel 	return (datael_handle(&val->rd_d));
   2919     0    stevel }
   2920     0    stevel 
   2921     0    stevel void
   2922     0    stevel scf_snaplevel_destroy(scf_snaplevel_t *val)
   2923     0    stevel {
   2924     0    stevel 	if (val == NULL)
   2925     0    stevel 		return;
   2926     0    stevel 
   2927     0    stevel 	datael_destroy(&val->rd_d);
   2928     0    stevel 	uu_free(val);
   2929     0    stevel }
   2930     0    stevel 
   2931     0    stevel ssize_t
   2932     0    stevel scf_snaplevel_get_scope_name(const scf_snaplevel_t *rep, char *out, size_t len)
   2933     0    stevel {
   2934     0    stevel 	return (datael_get_name(&rep->rd_d, out, len,
   2935     0    stevel 	    RP_ENTITY_NAME_SNAPLEVEL_SCOPE));
   2936     0    stevel }
   2937     0    stevel 
   2938     0    stevel ssize_t
   2939     0    stevel scf_snaplevel_get_service_name(const scf_snaplevel_t *rep, char *out,
   2940     0    stevel     size_t len)
   2941     0    stevel {
   2942     0    stevel 	return (datael_get_name(&rep->rd_d, out, len,
   2943     0    stevel 	    RP_ENTITY_NAME_SNAPLEVEL_SERVICE));
   2944     0    stevel }
   2945     0    stevel 
   2946     0    stevel ssize_t
   2947     0    stevel scf_snaplevel_get_instance_name(const scf_snaplevel_t *rep, char *out,
   2948     0    stevel     size_t len)
   2949     0    stevel {
   2950     0    stevel 	return (datael_get_name(&rep->rd_d, out, len,
   2951     0    stevel 	    RP_ENTITY_NAME_SNAPLEVEL_INSTANCE));
   2952     0    stevel }
   2953     0    stevel 
   2954  4740     jeanm /*
   2955  4740     jeanm  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
   2956  4740     jeanm  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
   2957  4740     jeanm  * _BACKEND_ACCESS, _NOT_FOUND.
   2958  4740     jeanm  */
   2959     0    stevel int
   2960     0    stevel scf_snaplevel_get_pg(const scf_snaplevel_t *snap, const char *name,
   2961     0    stevel     scf_propertygroup_t *pg)
   2962     0    stevel {
   2963     0    stevel 	return (datael_get_child(&snap->rd_d, name,
   2964     0    stevel 	    REP_PROTOCOL_ENTITY_PROPERTYGRP, pg ? &pg->rd_d : NULL, 0));
   2965     0    stevel }
   2966     0    stevel 
   2967     0    stevel static int
   2968     0    stevel snaplevel_next(const scf_datael_t *src, scf_snaplevel_t *dst_arg)
   2969     0    stevel {
   2970     0    stevel 	scf_handle_t *h = src->rd_handle;
   2971     0    stevel 	scf_snaplevel_t *dst = dst_arg;
   2972     0    stevel 	struct rep_protocol_entity_pair request;
   2973     0    stevel 	struct rep_protocol_response response;
   2974     0    stevel 	int r;
   2975     0    stevel 	int dups = 0;
   2976     0    stevel 
   2977     0    stevel 	if (h != dst->rd_d.rd_handle)
   2978     0    stevel 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
   2979     0    stevel 
   2980     0    stevel 	if (src == &dst->rd_d) {
   2981     0    stevel 		dups = 1;
   2982     0    stevel 		dst = HANDLE_HOLD_SNAPLVL(h);
   2983     0    stevel 	}
   2984     0    stevel 	(void) pthread_mutex_lock(&h->rh_lock);
   2985     0    stevel 	request.rpr_request = REP_PROTOCOL_NEXT_SNAPLEVEL;
   2986     0    stevel 	request.rpr_entity_src = src->rd_entity;
   2987     0    stevel 	request.rpr_entity_dst = dst->rd_d.rd_entity;
   2988     0    stevel 
   2989     0    stevel 	datael_finish_reset(src);
   2990     0    stevel 	datael_finish_reset(&dst->rd_d);
   2991     0    stevel 	r = make_door_call(h, &request, sizeof (request),
   2992     0    stevel 	    &response, sizeof (response));
   2993     0    stevel 	/*
   2994     0    stevel 	 * if we succeeded, we need to swap dst and dst_arg's identity.  We
   2995     0    stevel 	 * take advantage of the fact that the only in-library knowledge is
   2996     0    stevel 	 * their entity ids.
   2997     0    stevel 	 */
   2998     0    stevel 	if (dups && r >= 0 &&
   2999     0    stevel 	    (response.rpr_response == REP_PROTOCOL_SUCCESS ||
   3000     0    stevel 	    response.rpr_response == REP_PROTOCOL_DONE)) {
   3001     0    stevel 		int entity = dst->rd_d.rd_entity;
   3002     0    stevel 
   3003     0    stevel 		dst->rd_d.rd_entity = dst_arg->rd_d.rd_entity;
   3004     0    stevel 		dst_arg->rd_d.rd_entity = entity;
   3005     0    stevel 	}
   3006     0    stevel 	(void) pthread_mutex_unlock(&h->rh_lock);
   3007     0    stevel 
   3008     0    stevel 	if (dups)
   3009     0    stevel 		HANDLE_RELE_SNAPLVL(h);
   3010     0    stevel 
   3011     0    stevel 	if (r < 0)
   3012     0    stevel 		DOOR_ERRORS_BLOCK(r);
   3013     0    stevel 
   3014     0    stevel 	if (response.rpr_response != REP_PROTOCOL_SUCCESS &&
   3015     0    stevel 	    response.rpr_response != REP_PROTOCOL_DONE) {
   3016     0    stevel 		return (scf_set_error(proto_error(response.rpr_response)));
   3017     0    stevel 	}
   3018     0    stevel 
   3019     0    stevel 	return (response.rpr_response == REP_PROTOCOL_SUCCESS) ?
   3020     0    stevel 	    SCF_SUCCESS : SCF_COMPLETE;
   3021     0    stevel }
   3022     0    stevel 
   3023     0    stevel int scf_snapshot_get_base_snaplevel(const scf_snapshot_t *base,
   3024     0    stevel     scf_snaplevel_t *out)
   3025     0    stevel {
   3026     0    stevel 	return (snaplevel_next(&base->rd_d, out));
   3027     0    stevel }
   3028     0    stevel 
   3029     0    stevel int scf_snaplevel_get_next_snaplevel(const scf_snaplevel_t *base,
   3030     0    stevel     scf_snaplevel_t *out)
   3031     0    stevel {
   3032     0    stevel 	return (snaplevel_next(&base->rd_d, out));
   3033     0    stevel }
   3034     0    stevel 
   3035     0    stevel /*
   3036     0    stevel  * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
   3037     0    stevel  * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
   3038     0    stevel  */
   3039     0    stevel scf_propertygroup_t *
   3040     0    stevel scf_pg_create(scf_handle_t *handle)
   3041     0    stevel {
   3042     0    stevel 	scf_propertygroup_t *ret;
   3043     0    stevel 	ret = uu_zalloc(sizeof (*ret));
   3044     0    stevel 	if (ret != NULL) {
   3045     0    stevel 		if (datael_init(&ret->rd_d, handle,
   3046     0    stevel 		    REP_PROTOCOL_ENTITY_PROPERTYGRP) == -1) {
   3047     0    stevel 			uu_free(ret);
   3048     0    stevel 			return (NULL);
   3049     0    stevel 		}
   3050     0    stevel 	} else {
   3051     0    stevel 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
   3052     0    stevel 	}
   3053     0    stevel 
   3054     0    stevel 	return (ret);
   3055     0    stevel }
   3056     0    stevel 
   3057     0    stevel scf_handle_t *
   3058     0    stevel scf_pg_handle(const scf_propertygroup_t *val)
   3059     0    stevel {
   3060     0    stevel 	return (datael_handle(&val->rd_d));
   3061     0    stevel }
   3062     0    stevel 
   3063     0    stevel void
   3064     0    stevel scf_pg_destroy(scf_propertygroup_t *val)
   3065     0    stevel {
   3066     0    stevel 	if (val == NULL)
   3067     0    stevel 		return;
   3068     0    stevel 
   3069     0    stevel 	datael_destroy(&val->rd_d);
   3070     0    stevel 	uu_free(val);
   3071     0    stevel }
   3072     0    stevel 
   3073     0    stevel ssize_t
   3074     0    stevel scf_pg_get_name(const scf_propertygroup_t *pg,  char *out, size_t len)
   3075     0    stevel {
   3076     0    stevel 	return (datael_get_name(&pg->rd_d, out, len, RP_ENTITY_NAME_NAME));
   3077     0    stevel }
   3078     0    stevel 
   3079     0    stevel ssize_t
   3080     0    stevel scf_pg_get_type(const scf_propertygroup_t *pg,  char *out, size_t len)
   3081     0    stevel {
   3082     0    stevel <