xref: /onnv-gate/usr/src/cmd/svc/svccfg/svccfg_internal.c (revision 12667:62bc4887874f)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
55040Swesolows  * Common Development and Distribution License (the "License").
65040Swesolows  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
215040Swesolows 
220Sstevel@tonic-gate /*
23*12667SSean.Wilcox@Sun.COM  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #include <assert.h>
270Sstevel@tonic-gate #include <errno.h>
280Sstevel@tonic-gate #include <libintl.h>
290Sstevel@tonic-gate #include <libuutil.h>
300Sstevel@tonic-gate #include <stdarg.h>
310Sstevel@tonic-gate #include <stddef.h>
320Sstevel@tonic-gate #include <string.h>
337887SLiane.Praza@Sun.COM #include <unistd.h>
347887SLiane.Praza@Sun.COM #include <libscf_priv.h>
350Sstevel@tonic-gate 
360Sstevel@tonic-gate #include "svccfg.h"
370Sstevel@tonic-gate 
380Sstevel@tonic-gate /*
390Sstevel@tonic-gate  * Internal representation manipulation routines for svccfg(1)
400Sstevel@tonic-gate  */
410Sstevel@tonic-gate 
420Sstevel@tonic-gate static uu_list_pool_t	*entity_pool;
430Sstevel@tonic-gate static uu_list_pool_t	*pgroup_pool;
440Sstevel@tonic-gate static uu_list_pool_t	*property_pool;
450Sstevel@tonic-gate static uu_list_pool_t	*value_pool;
460Sstevel@tonic-gate 
470Sstevel@tonic-gate /* ARGSUSED */
480Sstevel@tonic-gate static int
entity_cmp(const void * a,const void * b,void * p)490Sstevel@tonic-gate entity_cmp(const void *a, const void *b, void *p)
500Sstevel@tonic-gate {
510Sstevel@tonic-gate 	entity_t *A = (entity_t *)a;
520Sstevel@tonic-gate 	entity_t *B = (entity_t *)b;
530Sstevel@tonic-gate 
540Sstevel@tonic-gate 	return (strcmp(A->sc_name, B->sc_name));
550Sstevel@tonic-gate }
560Sstevel@tonic-gate 
570Sstevel@tonic-gate /*ARGSUSED*/
580Sstevel@tonic-gate static int
pgroup_cmp(const void * a,const void * b,void * p)590Sstevel@tonic-gate pgroup_cmp(const void *a, const void *b, void *p)
600Sstevel@tonic-gate {
610Sstevel@tonic-gate 	pgroup_t *A = (pgroup_t *)a;
620Sstevel@tonic-gate 	pgroup_t *B = (pgroup_t *)b;
630Sstevel@tonic-gate 
640Sstevel@tonic-gate 	return (strcmp(A->sc_pgroup_name, B->sc_pgroup_name));
650Sstevel@tonic-gate }
660Sstevel@tonic-gate 
670Sstevel@tonic-gate /* ARGSUSED */
680Sstevel@tonic-gate static int
property_cmp(const void * a,const void * b,void * p)690Sstevel@tonic-gate property_cmp(const void *a, const void *b, void *p)
700Sstevel@tonic-gate {
710Sstevel@tonic-gate 	property_t *A = (property_t *)a;
720Sstevel@tonic-gate 	property_t *B = (property_t *)b;
730Sstevel@tonic-gate 
740Sstevel@tonic-gate 	return (strcmp(A->sc_property_name, B->sc_property_name));
750Sstevel@tonic-gate }
760Sstevel@tonic-gate 
770Sstevel@tonic-gate /* ARGSUSED */
780Sstevel@tonic-gate int
value_cmp(const void * a,const void * b,void * p)790Sstevel@tonic-gate value_cmp(const void *a, const void *b, void *p)
800Sstevel@tonic-gate {
810Sstevel@tonic-gate 	const value_t *A = a;
820Sstevel@tonic-gate 	const value_t *B = b;
830Sstevel@tonic-gate 
840Sstevel@tonic-gate 	if (A->sc_type != B->sc_type)
850Sstevel@tonic-gate 		return (B->sc_type - A->sc_type);
860Sstevel@tonic-gate 
870Sstevel@tonic-gate 	switch (A->sc_type) {
880Sstevel@tonic-gate 	case SCF_TYPE_BOOLEAN:
890Sstevel@tonic-gate 	case SCF_TYPE_COUNT:
900Sstevel@tonic-gate 		return (B->sc_u.sc_count - A->sc_u.sc_count);
910Sstevel@tonic-gate 
920Sstevel@tonic-gate 	case SCF_TYPE_INTEGER:
930Sstevel@tonic-gate 		return (B->sc_u.sc_integer - A->sc_u.sc_integer);
940Sstevel@tonic-gate 
950Sstevel@tonic-gate 	default:
960Sstevel@tonic-gate 		return (strcmp(A->sc_u.sc_string, B->sc_u.sc_string));
970Sstevel@tonic-gate 	}
980Sstevel@tonic-gate }
990Sstevel@tonic-gate 
1000Sstevel@tonic-gate void
internal_init()1010Sstevel@tonic-gate internal_init()
1020Sstevel@tonic-gate {
1030Sstevel@tonic-gate 	if ((entity_pool = uu_list_pool_create("entities", sizeof (entity_t),
1040Sstevel@tonic-gate 	    offsetof(entity_t, sc_node), entity_cmp, 0)) == NULL)
1050Sstevel@tonic-gate 		uu_die(gettext("entity list pool creation failed: %s\n"),
1060Sstevel@tonic-gate 		    uu_strerror(uu_error()));
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate 	if ((pgroup_pool = uu_list_pool_create("property_groups",
1090Sstevel@tonic-gate 	    sizeof (pgroup_t), offsetof(pgroup_t, sc_node), pgroup_cmp, 0)) ==
1100Sstevel@tonic-gate 	    NULL)
1110Sstevel@tonic-gate 		uu_die(
1120Sstevel@tonic-gate 		    gettext("property group list pool creation failed: %s\n"),
1130Sstevel@tonic-gate 		    uu_strerror(uu_error()));
1140Sstevel@tonic-gate 
1150Sstevel@tonic-gate 	if ((property_pool = uu_list_pool_create("properties",
1160Sstevel@tonic-gate 	    sizeof (property_t), offsetof(property_t, sc_node), property_cmp,
1170Sstevel@tonic-gate 	    0)) == NULL)
1180Sstevel@tonic-gate 		uu_die(gettext("property list pool creation failed: %s\n"),
1190Sstevel@tonic-gate 		    uu_strerror(uu_error()));
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate 	if ((value_pool = uu_list_pool_create("property_values",
1220Sstevel@tonic-gate 	    sizeof (value_t), offsetof(value_t, sc_node), value_cmp, 0)) ==
1230Sstevel@tonic-gate 	    NULL)
1240Sstevel@tonic-gate 		uu_die(
1250Sstevel@tonic-gate 		    gettext("property value list pool creation failed: %s\n"),
1260Sstevel@tonic-gate 		    uu_strerror(uu_error()));
1270Sstevel@tonic-gate }
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate /*ARGSUSED*/
1300Sstevel@tonic-gate static int
internal_value_dump(void * v,void * pvt)1310Sstevel@tonic-gate internal_value_dump(void *v, void *pvt)
1320Sstevel@tonic-gate {
1330Sstevel@tonic-gate 	value_t *val = v;
1340Sstevel@tonic-gate 
1350Sstevel@tonic-gate 	switch (val->sc_type) {
1360Sstevel@tonic-gate 	case SCF_TYPE_BOOLEAN:
1370Sstevel@tonic-gate 		(void) printf("	value = %s\n",
1380Sstevel@tonic-gate 		    val->sc_u.sc_count ? "true" : "false");
1390Sstevel@tonic-gate 		break;
1400Sstevel@tonic-gate 	case SCF_TYPE_COUNT:
1410Sstevel@tonic-gate 		(void) printf("	value = %llu\n", val->sc_u.sc_count);
1420Sstevel@tonic-gate 		break;
1430Sstevel@tonic-gate 	case SCF_TYPE_INTEGER:
1440Sstevel@tonic-gate 		(void) printf("	value = %lld\n", val->sc_u.sc_integer);
1450Sstevel@tonic-gate 		break;
1460Sstevel@tonic-gate 	case SCF_TYPE_ASTRING:
1470Sstevel@tonic-gate 	case SCF_TYPE_FMRI:
1480Sstevel@tonic-gate 	case SCF_TYPE_HOST:
1490Sstevel@tonic-gate 	case SCF_TYPE_HOSTNAME:
1500Sstevel@tonic-gate 	case SCF_TYPE_NET_ADDR_V4:
1510Sstevel@tonic-gate 	case SCF_TYPE_NET_ADDR_V6:
1520Sstevel@tonic-gate 	case SCF_TYPE_OPAQUE:
1530Sstevel@tonic-gate 	case SCF_TYPE_TIME:
1540Sstevel@tonic-gate 	case SCF_TYPE_URI:
1550Sstevel@tonic-gate 	case SCF_TYPE_USTRING:
1560Sstevel@tonic-gate 		(void) printf("	value = %s\n",
1570Sstevel@tonic-gate 		    val->sc_u.sc_string ? val->sc_u.sc_string : "(nil)");
1580Sstevel@tonic-gate 		break;
1590Sstevel@tonic-gate 	default:
1600Sstevel@tonic-gate 		uu_die(gettext("unknown value type (%d)\n"), val->sc_type);
1610Sstevel@tonic-gate 		break;
1620Sstevel@tonic-gate 	}
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate 	return (UU_WALK_NEXT);
1650Sstevel@tonic-gate }
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate /*ARGSUSED*/
1680Sstevel@tonic-gate static int
internal_property_dump(void * v,void * pvt)1690Sstevel@tonic-gate internal_property_dump(void *v, void *pvt)
1700Sstevel@tonic-gate {
1710Sstevel@tonic-gate 	property_t *p = v;
1720Sstevel@tonic-gate 
1730Sstevel@tonic-gate 	(void) printf("property\n	name = %s\n", p->sc_property_name);
1740Sstevel@tonic-gate 	(void) printf("	type = %d\n", p->sc_value_type);
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate 	(void) uu_list_walk(p->sc_property_values, internal_value_dump,
1770Sstevel@tonic-gate 	    NULL, UU_DEFAULT);
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate 	return (UU_WALK_NEXT);
1800Sstevel@tonic-gate }
1810Sstevel@tonic-gate 
1820Sstevel@tonic-gate /*ARGSUSED*/
1830Sstevel@tonic-gate static int
internal_pgroup_dump(void * v,void * pvt)1840Sstevel@tonic-gate internal_pgroup_dump(void *v, void *pvt)
1850Sstevel@tonic-gate {
1860Sstevel@tonic-gate 	pgroup_t *pg = v;
1870Sstevel@tonic-gate 
1880Sstevel@tonic-gate 	(void) printf("pgroup	name = %s\n", pg->sc_pgroup_name);
1890Sstevel@tonic-gate 	(void) printf("	type = %s\n", pg->sc_pgroup_type);
1900Sstevel@tonic-gate 
1910Sstevel@tonic-gate 	(void) uu_list_walk(pg->sc_pgroup_props, internal_property_dump,
1920Sstevel@tonic-gate 	    NULL, UU_DEFAULT);
1930Sstevel@tonic-gate 
1940Sstevel@tonic-gate 	return (UU_WALK_NEXT);
1950Sstevel@tonic-gate }
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate /*ARGSUSED*/
1980Sstevel@tonic-gate static int
internal_instance_dump(void * v,void * pvt)1990Sstevel@tonic-gate internal_instance_dump(void *v, void *pvt)
2000Sstevel@tonic-gate {
2010Sstevel@tonic-gate 	entity_t *i = v;
2020Sstevel@tonic-gate 
2030Sstevel@tonic-gate 	(void) printf("instance	name = %s\n", i->sc_name);
2040Sstevel@tonic-gate 
2050Sstevel@tonic-gate 	(void) uu_list_walk(i->sc_pgroups, internal_pgroup_dump, NULL,
2060Sstevel@tonic-gate 	    UU_DEFAULT);
2070Sstevel@tonic-gate 
2080Sstevel@tonic-gate 	return (UU_WALK_NEXT);
2090Sstevel@tonic-gate }
2100Sstevel@tonic-gate 
2110Sstevel@tonic-gate /*ARGSUSED*/
2120Sstevel@tonic-gate static int
internal_service_dump(void * v,void * pvt)2130Sstevel@tonic-gate internal_service_dump(void *v, void *pvt)
2140Sstevel@tonic-gate {
2150Sstevel@tonic-gate 	entity_t *s = v;
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate 	(void) printf("service	name = %s\n", s->sc_name);
2180Sstevel@tonic-gate 	(void) printf("	type = %x\n", s->sc_u.sc_service.sc_service_type);
2190Sstevel@tonic-gate 	(void) printf("	version = %u\n", s->sc_u.sc_service.sc_service_version);
2200Sstevel@tonic-gate 
2210Sstevel@tonic-gate 	(void) uu_list_walk(s->sc_pgroups, internal_pgroup_dump, NULL,
2220Sstevel@tonic-gate 	    UU_DEFAULT);
2230Sstevel@tonic-gate 
2240Sstevel@tonic-gate 	(void) uu_list_walk(s->sc_u.sc_service.sc_service_instances,
2250Sstevel@tonic-gate 	    internal_instance_dump, NULL, UU_DEFAULT);
2260Sstevel@tonic-gate 
2270Sstevel@tonic-gate 	return (UU_WALK_NEXT);
2280Sstevel@tonic-gate }
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate void
internal_dump(bundle_t * b)2310Sstevel@tonic-gate internal_dump(bundle_t *b)
2320Sstevel@tonic-gate {
2330Sstevel@tonic-gate 	(void) printf("bundle	name = %s\n", b->sc_bundle_name);
2340Sstevel@tonic-gate 	(void) printf("	type = %x\n", b->sc_bundle_type);
2350Sstevel@tonic-gate 
2360Sstevel@tonic-gate 	(void) uu_list_walk(b->sc_bundle_services, internal_service_dump,
2370Sstevel@tonic-gate 	    NULL, UU_DEFAULT);
2380Sstevel@tonic-gate }
2390Sstevel@tonic-gate 
2400Sstevel@tonic-gate bundle_t *
internal_bundle_new()2410Sstevel@tonic-gate internal_bundle_new()
2420Sstevel@tonic-gate {
2430Sstevel@tonic-gate 	bundle_t	*b;
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate 	if ((b = uu_zalloc(sizeof (bundle_t))) == NULL)
2460Sstevel@tonic-gate 		uu_die(gettext("couldn't allocate memory"));
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate 	b->sc_bundle_type = SVCCFG_UNKNOWN_BUNDLE;
2490Sstevel@tonic-gate 	b->sc_bundle_services = uu_list_create(entity_pool, b, 0);
2507887SLiane.Praza@Sun.COM 	if (b->sc_bundle_services == NULL) {
2517887SLiane.Praza@Sun.COM 		uu_die(gettext("Unable to create list for bundle services.  "
2527887SLiane.Praza@Sun.COM 		    "%s\n"), uu_strerror(uu_error()));
2537887SLiane.Praza@Sun.COM 	}
2540Sstevel@tonic-gate 
2550Sstevel@tonic-gate 	return (b);
2560Sstevel@tonic-gate }
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate void
internal_bundle_free(bundle_t * b)2590Sstevel@tonic-gate internal_bundle_free(bundle_t *b)
2600Sstevel@tonic-gate {
2610Sstevel@tonic-gate 	void *cookie = NULL;
2620Sstevel@tonic-gate 	entity_t *service;
2630Sstevel@tonic-gate 
2640Sstevel@tonic-gate 	while ((service = uu_list_teardown(b->sc_bundle_services, &cookie)) !=
2650Sstevel@tonic-gate 	    NULL)
2660Sstevel@tonic-gate 		internal_service_free(service);
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate 	free(b);
2690Sstevel@tonic-gate }
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate entity_t *
internal_entity_new(entity_type_t entity)2727887SLiane.Praza@Sun.COM internal_entity_new(entity_type_t entity)
2737887SLiane.Praza@Sun.COM {
2747887SLiane.Praza@Sun.COM 	entity_t *e;
2757887SLiane.Praza@Sun.COM 
2767887SLiane.Praza@Sun.COM 	if ((e = uu_zalloc(sizeof (entity_t))) == NULL)
2777887SLiane.Praza@Sun.COM 		uu_die(gettext("couldn't allocate memory"));
2787887SLiane.Praza@Sun.COM 
2797887SLiane.Praza@Sun.COM 	uu_list_node_init(e, &e->sc_node, entity_pool);
2807887SLiane.Praza@Sun.COM 
2817887SLiane.Praza@Sun.COM 	e->sc_etype = entity;
2827887SLiane.Praza@Sun.COM 	e->sc_pgroups = uu_list_create(pgroup_pool, e, 0);
283*12667SSean.Wilcox@Sun.COM 	e->sc_op = SVCCFG_OP_NONE;
2847887SLiane.Praza@Sun.COM 	if (e->sc_pgroups == NULL) {
2857887SLiane.Praza@Sun.COM 		uu_die(gettext("Unable to create list for entity property "
2867887SLiane.Praza@Sun.COM 		    "groups.  %s\n"), uu_strerror(uu_error()));
2877887SLiane.Praza@Sun.COM 	}
2887887SLiane.Praza@Sun.COM 
2897887SLiane.Praza@Sun.COM 	return (e);
2907887SLiane.Praza@Sun.COM }
2917887SLiane.Praza@Sun.COM 
2927887SLiane.Praza@Sun.COM entity_t *
internal_service_new(const char * name)2930Sstevel@tonic-gate internal_service_new(const char *name)
2940Sstevel@tonic-gate {
2950Sstevel@tonic-gate 	entity_t *s;
2960Sstevel@tonic-gate 
2977887SLiane.Praza@Sun.COM 	s = internal_entity_new(SVCCFG_SERVICE_OBJECT);
2980Sstevel@tonic-gate 
2990Sstevel@tonic-gate 	s->sc_name = name;
3000Sstevel@tonic-gate 	s->sc_fmri = uu_msprintf("svc:/%s", name);
3010Sstevel@tonic-gate 	if (s->sc_fmri == NULL)
3020Sstevel@tonic-gate 		uu_die(gettext("couldn't allocate memory"));
3030Sstevel@tonic-gate 
3040Sstevel@tonic-gate 	s->sc_dependents = uu_list_create(pgroup_pool, s, 0);
3057887SLiane.Praza@Sun.COM 	if (s->sc_dependents == NULL) {
3067887SLiane.Praza@Sun.COM 		uu_die(gettext("Unable to create list for service dependents.  "
3077887SLiane.Praza@Sun.COM 		    "%s\n"), uu_strerror(uu_error()));
3087887SLiane.Praza@Sun.COM 	}
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate 	s->sc_u.sc_service.sc_service_type = SVCCFG_UNKNOWN_SERVICE;
3110Sstevel@tonic-gate 	s->sc_u.sc_service.sc_service_instances = uu_list_create(entity_pool, s,
3120Sstevel@tonic-gate 	    0);
3137887SLiane.Praza@Sun.COM 	if (s->sc_u.sc_service.sc_service_instances == NULL) {
3147887SLiane.Praza@Sun.COM 		uu_die(gettext("Unable to create list for service instances.  "
3157887SLiane.Praza@Sun.COM 		    "%s\n"), uu_strerror(uu_error()));
3167887SLiane.Praza@Sun.COM 	}
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate 	return (s);
3190Sstevel@tonic-gate }
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate void
internal_service_free(entity_t * s)3220Sstevel@tonic-gate internal_service_free(entity_t *s)
3230Sstevel@tonic-gate {
3240Sstevel@tonic-gate 	entity_t *inst;
3250Sstevel@tonic-gate 	pgroup_t *pg;
3260Sstevel@tonic-gate 	void *cookie;
3270Sstevel@tonic-gate 
3287887SLiane.Praza@Sun.COM 	if (s->sc_u.sc_service.sc_restarter != NULL)
3297887SLiane.Praza@Sun.COM 		internal_instance_free(s->sc_u.sc_service.sc_restarter);
3307887SLiane.Praza@Sun.COM 	if (s->sc_u.sc_service.sc_global != NULL)
3317887SLiane.Praza@Sun.COM 		internal_instance_free(s->sc_u.sc_service.sc_global);
3327887SLiane.Praza@Sun.COM 
3330Sstevel@tonic-gate 	cookie = NULL;
3340Sstevel@tonic-gate 	while ((pg = uu_list_teardown(s->sc_pgroups, &cookie)) != NULL)
3350Sstevel@tonic-gate 		internal_pgroup_free(pg);
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate 	cookie = NULL;
3380Sstevel@tonic-gate 	while ((pg = uu_list_teardown(s->sc_dependents, &cookie)) != NULL)
3390Sstevel@tonic-gate 		internal_pgroup_free(pg);
3400Sstevel@tonic-gate 
3410Sstevel@tonic-gate 	cookie = NULL;
3420Sstevel@tonic-gate 	while ((inst = uu_list_teardown(s->sc_u.sc_service.sc_service_instances,
3430Sstevel@tonic-gate 	    &cookie)) != NULL)
3440Sstevel@tonic-gate 		internal_instance_free(inst);
3457887SLiane.Praza@Sun.COM 	uu_free((void *)s->sc_fmri);
3460Sstevel@tonic-gate 
3470Sstevel@tonic-gate 	free(s);
3480Sstevel@tonic-gate }
3490Sstevel@tonic-gate 
3500Sstevel@tonic-gate entity_t *
internal_instance_new(const char * name)3510Sstevel@tonic-gate internal_instance_new(const char *name)
3520Sstevel@tonic-gate {
3530Sstevel@tonic-gate 	entity_t *i;
3540Sstevel@tonic-gate 
3557887SLiane.Praza@Sun.COM 	i = internal_entity_new(SVCCFG_INSTANCE_OBJECT);
3560Sstevel@tonic-gate 	i->sc_name = name;
3570Sstevel@tonic-gate 	/* Can't set i->sc_fmri until we're attached to a service. */
3580Sstevel@tonic-gate 	i->sc_dependents = uu_list_create(pgroup_pool, i, 0);
3597887SLiane.Praza@Sun.COM 	if (i->sc_dependents == NULL) {
3607887SLiane.Praza@Sun.COM 		uu_die(gettext("Unable to create list for instance "
3617887SLiane.Praza@Sun.COM 		    "dependents.  %s\n"), uu_strerror(uu_error()));
3627887SLiane.Praza@Sun.COM 	}
3630Sstevel@tonic-gate 
3640Sstevel@tonic-gate 	return (i);
3650Sstevel@tonic-gate }
3660Sstevel@tonic-gate 
3670Sstevel@tonic-gate void
internal_instance_free(entity_t * i)3680Sstevel@tonic-gate internal_instance_free(entity_t *i)
3690Sstevel@tonic-gate {
3700Sstevel@tonic-gate 	pgroup_t *pg;
3710Sstevel@tonic-gate 	void *cookie = NULL;
3727887SLiane.Praza@Sun.COM 	entity_t *rs;
3730Sstevel@tonic-gate 
3747887SLiane.Praza@Sun.COM 	rs = i->sc_u.sc_instance.sc_instance_restarter;
3757887SLiane.Praza@Sun.COM 	if (rs != NULL)
3767887SLiane.Praza@Sun.COM 		internal_instance_free(rs);
3770Sstevel@tonic-gate 	while ((pg = uu_list_teardown(i->sc_pgroups, &cookie)) != NULL)
3780Sstevel@tonic-gate 		internal_pgroup_free(pg);
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate 	cookie = NULL;
3810Sstevel@tonic-gate 	while ((pg = uu_list_teardown(i->sc_dependents, &cookie)) != NULL)
3820Sstevel@tonic-gate 		internal_pgroup_free(pg);
3837887SLiane.Praza@Sun.COM 	uu_free((void *)i->sc_fmri);
3840Sstevel@tonic-gate 
3850Sstevel@tonic-gate 	free(i);
3860Sstevel@tonic-gate }
3870Sstevel@tonic-gate 
3880Sstevel@tonic-gate pgroup_t *
internal_pgroup_new()3890Sstevel@tonic-gate internal_pgroup_new()
3900Sstevel@tonic-gate {
3910Sstevel@tonic-gate 	pgroup_t *p;
3920Sstevel@tonic-gate 
3930Sstevel@tonic-gate 	if ((p = uu_zalloc(sizeof (pgroup_t))) == NULL)
3940Sstevel@tonic-gate 		uu_die(gettext("couldn't allocate memory"));
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate 	uu_list_node_init(p, &p->sc_node, pgroup_pool);
3970Sstevel@tonic-gate 
3980Sstevel@tonic-gate 	p->sc_pgroup_props = uu_list_create(property_pool, p, UU_LIST_SORTED);
3997887SLiane.Praza@Sun.COM 	if (p->sc_pgroup_props == NULL) {
4007887SLiane.Praza@Sun.COM 		uu_die(gettext("Unable to create list for properties.  %s\n"),
4017887SLiane.Praza@Sun.COM 		    uu_strerror(uu_error()));
4027887SLiane.Praza@Sun.COM 	}
4030Sstevel@tonic-gate 	p->sc_pgroup_name = "<unset>";
4040Sstevel@tonic-gate 	p->sc_pgroup_type = "<unset>";
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate 	return (p);
4070Sstevel@tonic-gate }
4080Sstevel@tonic-gate 
4090Sstevel@tonic-gate void
internal_pgroup_free(pgroup_t * pg)4100Sstevel@tonic-gate internal_pgroup_free(pgroup_t *pg)
4110Sstevel@tonic-gate {
4120Sstevel@tonic-gate 	property_t *prop;
4130Sstevel@tonic-gate 	void *cookie = NULL;
4140Sstevel@tonic-gate 
4157887SLiane.Praza@Sun.COM 	/*
4167887SLiane.Praza@Sun.COM 	 * Templates validation code should clean up this reference when
4177887SLiane.Praza@Sun.COM 	 * the validation is finished.
4187887SLiane.Praza@Sun.COM 	 */
4197887SLiane.Praza@Sun.COM 	assert(pg->sc_pgroup_composed == NULL);
4207887SLiane.Praza@Sun.COM 
4210Sstevel@tonic-gate 	while ((prop = uu_list_teardown(pg->sc_pgroup_props, &cookie)) != NULL)
4220Sstevel@tonic-gate 		internal_property_free(prop);
4230Sstevel@tonic-gate 
424306Sbustos 	uu_free(pg);
4250Sstevel@tonic-gate }
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate static pgroup_t *
find_pgroup(uu_list_t * list,const char * name,const char * type)4280Sstevel@tonic-gate find_pgroup(uu_list_t *list, const char *name, const char *type)
4290Sstevel@tonic-gate {
4300Sstevel@tonic-gate 	pgroup_t *pg;
4310Sstevel@tonic-gate 
4320Sstevel@tonic-gate 	for (pg = uu_list_first(list);
4330Sstevel@tonic-gate 	    pg != NULL;
4340Sstevel@tonic-gate 	    pg = uu_list_next(list, pg)) {
4350Sstevel@tonic-gate 		if (strcmp(pg->sc_pgroup_name, name) != 0)
4360Sstevel@tonic-gate 			continue;
4370Sstevel@tonic-gate 
4380Sstevel@tonic-gate 		if (type == NULL)
4390Sstevel@tonic-gate 			return (pg);
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate 		if (strcmp(pg->sc_pgroup_type, type) == 0)
4420Sstevel@tonic-gate 			return (pg);
4430Sstevel@tonic-gate 	}
4440Sstevel@tonic-gate 
4450Sstevel@tonic-gate 	return (NULL);
4460Sstevel@tonic-gate }
4470Sstevel@tonic-gate 
4480Sstevel@tonic-gate pgroup_t *
internal_dependent_find(entity_t * e,const char * name)4490Sstevel@tonic-gate internal_dependent_find(entity_t *e, const char *name)
4500Sstevel@tonic-gate {
4510Sstevel@tonic-gate 	return (find_pgroup(e->sc_dependents, name, NULL));
4520Sstevel@tonic-gate }
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate pgroup_t *
internal_pgroup_find(entity_t * e,const char * name,const char * type)4550Sstevel@tonic-gate internal_pgroup_find(entity_t *e, const char *name, const char *type)
4560Sstevel@tonic-gate {
4570Sstevel@tonic-gate 	return (find_pgroup(e->sc_pgroups, name, type));
4580Sstevel@tonic-gate }
4590Sstevel@tonic-gate 
4607887SLiane.Praza@Sun.COM static pgroup_t *
internal_pgroup_create_common(entity_t * e,const char * name,const char * type,boolean_t unique)4617887SLiane.Praza@Sun.COM internal_pgroup_create_common(entity_t *e, const char *name, const char *type,
4627887SLiane.Praza@Sun.COM 	boolean_t unique)
4630Sstevel@tonic-gate {
4640Sstevel@tonic-gate 	pgroup_t *pg;
4650Sstevel@tonic-gate 
4660Sstevel@tonic-gate 	pg = internal_pgroup_find(e, name, type);
4677887SLiane.Praza@Sun.COM 	if (pg != NULL) {
4687887SLiane.Praza@Sun.COM 		if (unique == B_TRUE) {
4697887SLiane.Praza@Sun.COM 			return (NULL);
4707887SLiane.Praza@Sun.COM 		} else {
4717887SLiane.Praza@Sun.COM 			return (pg);
4727887SLiane.Praza@Sun.COM 		}
4737887SLiane.Praza@Sun.COM 	}
4740Sstevel@tonic-gate 
4750Sstevel@tonic-gate 	pg = internal_pgroup_new();
4760Sstevel@tonic-gate 	(void) internal_attach_pgroup(e, pg);
4770Sstevel@tonic-gate 	pg->sc_pgroup_name = strdup(name);
4780Sstevel@tonic-gate 	pg->sc_pgroup_flags = 0;
479*12667SSean.Wilcox@Sun.COM 	if (type != NULL) {
480*12667SSean.Wilcox@Sun.COM 		pg->sc_pgroup_type = strdup(type);
481*12667SSean.Wilcox@Sun.COM 	} else {
482*12667SSean.Wilcox@Sun.COM 		est->sc_miss_type = B_TRUE;
483*12667SSean.Wilcox@Sun.COM 		pg->sc_pgroup_type = NULL;
484*12667SSean.Wilcox@Sun.COM 	}
4850Sstevel@tonic-gate 
486*12667SSean.Wilcox@Sun.COM 	if (pg->sc_pgroup_name == NULL ||
487*12667SSean.Wilcox@Sun.COM 	    (e->sc_op != SVCCFG_OP_APPLY && pg->sc_pgroup_type == NULL))
4880Sstevel@tonic-gate 		uu_die(gettext("Could not duplicate string"));
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate 	return (pg);
4910Sstevel@tonic-gate }
4920Sstevel@tonic-gate 
4937887SLiane.Praza@Sun.COM pgroup_t *
internal_pgroup_find_or_create(entity_t * e,const char * name,const char * type)4947887SLiane.Praza@Sun.COM internal_pgroup_find_or_create(entity_t *e, const char *name, const char *type)
4957887SLiane.Praza@Sun.COM {
4967887SLiane.Praza@Sun.COM 	return (internal_pgroup_create_common(e, name, type, B_FALSE));
4977887SLiane.Praza@Sun.COM }
4987887SLiane.Praza@Sun.COM 
4997887SLiane.Praza@Sun.COM pgroup_t *
internal_pgroup_create_strict(entity_t * e,const char * name,const char * type)5007887SLiane.Praza@Sun.COM internal_pgroup_create_strict(entity_t *e, const char *name, const char *type)
5017887SLiane.Praza@Sun.COM {
5027887SLiane.Praza@Sun.COM 	return (internal_pgroup_create_common(e, name, type, B_TRUE));
5037887SLiane.Praza@Sun.COM }
5047887SLiane.Praza@Sun.COM 
5050Sstevel@tonic-gate property_t *
internal_property_new()5060Sstevel@tonic-gate internal_property_new()
5070Sstevel@tonic-gate {
5080Sstevel@tonic-gate 	property_t *p;
5090Sstevel@tonic-gate 
5100Sstevel@tonic-gate 	if ((p = uu_zalloc(sizeof (property_t))) == NULL)
5110Sstevel@tonic-gate 		uu_die(gettext("couldn't allocate memory"));
5120Sstevel@tonic-gate 
5130Sstevel@tonic-gate 	uu_list_node_init(p, &p->sc_node, property_pool);
5140Sstevel@tonic-gate 
5157128Samaguire 	p->sc_property_values = uu_list_create(value_pool, p, 0);
5167887SLiane.Praza@Sun.COM 	if (p->sc_property_values == NULL) {
5177887SLiane.Praza@Sun.COM 		uu_die(gettext("Unable to create list for property values.  "
5187887SLiane.Praza@Sun.COM 		    "%s\n"), uu_strerror(uu_error()));
5197887SLiane.Praza@Sun.COM 	}
5200Sstevel@tonic-gate 	p->sc_property_name = "<unset>";
5210Sstevel@tonic-gate 
5227887SLiane.Praza@Sun.COM 	tmpl_property_init(p);
5237887SLiane.Praza@Sun.COM 
5240Sstevel@tonic-gate 	return (p);
5250Sstevel@tonic-gate }
5260Sstevel@tonic-gate 
5270Sstevel@tonic-gate void
internal_property_free(property_t * p)5280Sstevel@tonic-gate internal_property_free(property_t *p)
5290Sstevel@tonic-gate {
5300Sstevel@tonic-gate 	value_t *val;
5310Sstevel@tonic-gate 	void *cookie = NULL;
5320Sstevel@tonic-gate 
5337887SLiane.Praza@Sun.COM 	tmpl_property_fini(p);
5347887SLiane.Praza@Sun.COM 
5350Sstevel@tonic-gate 	while ((val = uu_list_teardown(p->sc_property_values, &cookie)) !=
5360Sstevel@tonic-gate 	    NULL) {
5370Sstevel@tonic-gate 		if (val->sc_free != NULL)
5380Sstevel@tonic-gate 			val->sc_free(val);
5390Sstevel@tonic-gate 		free(val);
5400Sstevel@tonic-gate 	}
5410Sstevel@tonic-gate 
5420Sstevel@tonic-gate 	free(p);
5430Sstevel@tonic-gate }
5440Sstevel@tonic-gate 
5450Sstevel@tonic-gate property_t *
internal_property_find(pgroup_t * pg,const char * name)5460Sstevel@tonic-gate internal_property_find(pgroup_t *pg, const char *name)
5470Sstevel@tonic-gate {
5480Sstevel@tonic-gate 	property_t *p;
5490Sstevel@tonic-gate 
5500Sstevel@tonic-gate 	for (p = uu_list_first(pg->sc_pgroup_props);
5510Sstevel@tonic-gate 	    p != NULL;
5520Sstevel@tonic-gate 	    p = uu_list_next(pg->sc_pgroup_props, p))
5530Sstevel@tonic-gate 		if (strcmp(p->sc_property_name, name) == 0)
5540Sstevel@tonic-gate 			return (p);
5550Sstevel@tonic-gate 
5560Sstevel@tonic-gate 	return (NULL);
5570Sstevel@tonic-gate }
5580Sstevel@tonic-gate 
5590Sstevel@tonic-gate value_t *
internal_value_new()5600Sstevel@tonic-gate internal_value_new()
5610Sstevel@tonic-gate {
5620Sstevel@tonic-gate 	value_t *v;
5630Sstevel@tonic-gate 
5640Sstevel@tonic-gate 	if ((v = uu_zalloc(sizeof (value_t))) == NULL)
5650Sstevel@tonic-gate 		uu_die(gettext("couldn't allocate memory"));
5660Sstevel@tonic-gate 
5670Sstevel@tonic-gate 	uu_list_node_init(v, &v->sc_node, value_pool);
5680Sstevel@tonic-gate 
5690Sstevel@tonic-gate 	return (v);
5700Sstevel@tonic-gate }
5710Sstevel@tonic-gate 
5720Sstevel@tonic-gate static void
internal_value_free_str(value_t * v)5730Sstevel@tonic-gate internal_value_free_str(value_t *v)
5740Sstevel@tonic-gate {
5750Sstevel@tonic-gate 	free(v->sc_u.sc_string);
5760Sstevel@tonic-gate }
5770Sstevel@tonic-gate 
5780Sstevel@tonic-gate property_t *
internal_property_create(const char * name,scf_type_t vtype,uint_t nvals,...)5790Sstevel@tonic-gate internal_property_create(const char *name, scf_type_t vtype, uint_t nvals, ...)
5800Sstevel@tonic-gate {
5810Sstevel@tonic-gate 	va_list args;
5820Sstevel@tonic-gate 	property_t *p;
5830Sstevel@tonic-gate 	value_t *v;
5840Sstevel@tonic-gate 
5850Sstevel@tonic-gate 	p = internal_property_new();
5860Sstevel@tonic-gate 
5870Sstevel@tonic-gate 	p->sc_property_name = (char *)name;
5880Sstevel@tonic-gate 	p->sc_value_type = vtype;
5890Sstevel@tonic-gate 
5900Sstevel@tonic-gate 	va_start(args, nvals);
5910Sstevel@tonic-gate 	for (; nvals > 0; nvals--) {
5920Sstevel@tonic-gate 
5930Sstevel@tonic-gate 		v = internal_value_new();
5940Sstevel@tonic-gate 		v->sc_type = vtype;
5950Sstevel@tonic-gate 
5960Sstevel@tonic-gate 		switch (vtype) {
5970Sstevel@tonic-gate 		case SCF_TYPE_BOOLEAN:
5980Sstevel@tonic-gate 		case SCF_TYPE_COUNT:
5990Sstevel@tonic-gate 			v->sc_u.sc_count = va_arg(args, uint64_t);
6000Sstevel@tonic-gate 			break;
6010Sstevel@tonic-gate 		case SCF_TYPE_INTEGER:
6020Sstevel@tonic-gate 			v->sc_u.sc_integer = va_arg(args, int64_t);
6030Sstevel@tonic-gate 			break;
6040Sstevel@tonic-gate 		case SCF_TYPE_ASTRING:
6050Sstevel@tonic-gate 		case SCF_TYPE_FMRI:
6060Sstevel@tonic-gate 		case SCF_TYPE_HOST:
6070Sstevel@tonic-gate 		case SCF_TYPE_HOSTNAME:
6080Sstevel@tonic-gate 		case SCF_TYPE_NET_ADDR_V4:
6090Sstevel@tonic-gate 		case SCF_TYPE_NET_ADDR_V6:
6100Sstevel@tonic-gate 		case SCF_TYPE_OPAQUE:
6110Sstevel@tonic-gate 		case SCF_TYPE_TIME:
6120Sstevel@tonic-gate 		case SCF_TYPE_URI:
6130Sstevel@tonic-gate 		case SCF_TYPE_USTRING:
6140Sstevel@tonic-gate 			v->sc_u.sc_string = (char *)va_arg(args, uchar_t *);
6150Sstevel@tonic-gate 			break;
6160Sstevel@tonic-gate 		default:
6170Sstevel@tonic-gate 			va_end(args);
6180Sstevel@tonic-gate 			uu_die(gettext("unknown property type (%d)\n"), vtype);
6190Sstevel@tonic-gate 			break;
6200Sstevel@tonic-gate 		}
6210Sstevel@tonic-gate 
6220Sstevel@tonic-gate 		internal_attach_value(p, v);
6230Sstevel@tonic-gate 	}
6240Sstevel@tonic-gate 	va_end(args);
6250Sstevel@tonic-gate 
6260Sstevel@tonic-gate 	return (p);
6270Sstevel@tonic-gate }
6280Sstevel@tonic-gate 
6290Sstevel@tonic-gate /*
6300Sstevel@tonic-gate  * Some of these attach functions use uu_list_append() to maintain the
6310Sstevel@tonic-gate  * same order across import/export, whereas others are always sorted
6320Sstevel@tonic-gate  * anyway, or the order is irrelevant.
6330Sstevel@tonic-gate  */
6340Sstevel@tonic-gate 
6350Sstevel@tonic-gate int
internal_attach_service(bundle_t * bndl,entity_t * svc)6360Sstevel@tonic-gate internal_attach_service(bundle_t *bndl, entity_t *svc)
6370Sstevel@tonic-gate {
6380Sstevel@tonic-gate 	if (uu_list_find(bndl->sc_bundle_services, svc, NULL, NULL) != NULL) {
6390Sstevel@tonic-gate 		semerr(gettext("Multiple definitions for service %s in "
6400Sstevel@tonic-gate 		    "bundle %s.\n"), svc->sc_name, bndl->sc_bundle_name);
6410Sstevel@tonic-gate 		return (-1);
6420Sstevel@tonic-gate 	}
6430Sstevel@tonic-gate 
6440Sstevel@tonic-gate 	(void) uu_list_append(bndl->sc_bundle_services, svc);
6450Sstevel@tonic-gate 
6460Sstevel@tonic-gate 	return (0);
6470Sstevel@tonic-gate }
6480Sstevel@tonic-gate 
6490Sstevel@tonic-gate int
internal_attach_entity(entity_t * svc,entity_t * ent)6500Sstevel@tonic-gate internal_attach_entity(entity_t *svc, entity_t *ent)
6510Sstevel@tonic-gate {
6520Sstevel@tonic-gate 	if (svc->sc_etype != SVCCFG_SERVICE_OBJECT)
6530Sstevel@tonic-gate 		uu_die(gettext("bad entity attach: %s is not a service\n"),
6540Sstevel@tonic-gate 		    svc->sc_name);
6550Sstevel@tonic-gate 
6560Sstevel@tonic-gate 	if (uu_list_find(svc->sc_u.sc_service.sc_service_instances, ent, NULL,
6570Sstevel@tonic-gate 	    NULL) != NULL) {
6580Sstevel@tonic-gate 		semerr(gettext("Multiple definitions of entity %s in service "
6590Sstevel@tonic-gate 		    "%s.\n"), ent->sc_name, svc->sc_name);
6600Sstevel@tonic-gate 		return (-1);
6610Sstevel@tonic-gate 	}
6620Sstevel@tonic-gate 
6630Sstevel@tonic-gate 	(void) uu_list_prepend(svc->sc_u.sc_service.sc_service_instances, ent);
6640Sstevel@tonic-gate 	ent->sc_parent = svc;
665*12667SSean.Wilcox@Sun.COM 	ent->sc_op = svc->sc_op;
6660Sstevel@tonic-gate 	ent->sc_fmri = uu_msprintf("%s:%s", svc->sc_fmri, ent->sc_name);
6670Sstevel@tonic-gate 	if (ent->sc_fmri == NULL)
6680Sstevel@tonic-gate 		uu_die(gettext("couldn't allocate memory"));
6690Sstevel@tonic-gate 
6700Sstevel@tonic-gate 	return (0);
6710Sstevel@tonic-gate }
6720Sstevel@tonic-gate 
6730Sstevel@tonic-gate int
internal_attach_pgroup(entity_t * ent,pgroup_t * pgrp)6740Sstevel@tonic-gate internal_attach_pgroup(entity_t *ent, pgroup_t *pgrp)
6750Sstevel@tonic-gate {
6760Sstevel@tonic-gate 	if (uu_list_find(ent->sc_pgroups, pgrp, NULL, NULL) != NULL) {
6770Sstevel@tonic-gate 		semerr(gettext("Multiple definitions of property group %s in "
6780Sstevel@tonic-gate 		    "entity %s.\n"), pgrp->sc_pgroup_name, ent->sc_name);
6790Sstevel@tonic-gate 		return (-1);
6800Sstevel@tonic-gate 	}
6810Sstevel@tonic-gate 
6820Sstevel@tonic-gate 	(void) uu_list_append(ent->sc_pgroups, pgrp);
6830Sstevel@tonic-gate 
6840Sstevel@tonic-gate 	pgrp->sc_parent = ent;
6850Sstevel@tonic-gate 
6860Sstevel@tonic-gate 	return (0);
6870Sstevel@tonic-gate }
6880Sstevel@tonic-gate 
6897887SLiane.Praza@Sun.COM void
internal_detach_pgroup(entity_t * ent,pgroup_t * pgrp)6907887SLiane.Praza@Sun.COM internal_detach_pgroup(entity_t *ent, pgroup_t *pgrp)
6917887SLiane.Praza@Sun.COM {
6927887SLiane.Praza@Sun.COM 	uu_list_remove(ent->sc_pgroups, pgrp);
6937887SLiane.Praza@Sun.COM }
6947887SLiane.Praza@Sun.COM 
6950Sstevel@tonic-gate int
internal_attach_dependent(entity_t * ent,pgroup_t * pg)6960Sstevel@tonic-gate internal_attach_dependent(entity_t *ent, pgroup_t *pg)
6970Sstevel@tonic-gate {
6980Sstevel@tonic-gate 	if (uu_list_find(ent->sc_dependents, pg, NULL, NULL) != NULL) {
6990Sstevel@tonic-gate 		semerr(gettext("Multiple definitions of dependent %s in "
7000Sstevel@tonic-gate 		    "entity %s.\n"), pg->sc_pgroup_name, ent->sc_name);
7010Sstevel@tonic-gate 		return (-1);
7020Sstevel@tonic-gate 	}
7030Sstevel@tonic-gate 
7040Sstevel@tonic-gate 	(void) uu_list_append(ent->sc_dependents, pg);
7050Sstevel@tonic-gate 
7060Sstevel@tonic-gate 	pg->sc_parent = ent;
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate 	return (0);
7090Sstevel@tonic-gate }
7100Sstevel@tonic-gate 
7110Sstevel@tonic-gate /*
7120Sstevel@tonic-gate  * Returns
7130Sstevel@tonic-gate  *   0 - success
7140Sstevel@tonic-gate  *   -1 - prop already exists in pgrp
7150Sstevel@tonic-gate  */
7160Sstevel@tonic-gate int
internal_attach_property(pgroup_t * pgrp,property_t * prop)7170Sstevel@tonic-gate internal_attach_property(pgroup_t *pgrp, property_t *prop)
7180Sstevel@tonic-gate {
7190Sstevel@tonic-gate 	uu_list_index_t idx;
7200Sstevel@tonic-gate 
7210Sstevel@tonic-gate 	if (uu_list_find(pgrp->sc_pgroup_props, prop, NULL, &idx) != NULL) {
7220Sstevel@tonic-gate 		semerr(gettext("Multiple definitions for property %s in "
7230Sstevel@tonic-gate 		    "property group %s.\n"), prop->sc_property_name,
7240Sstevel@tonic-gate 		    pgrp->sc_pgroup_name);
7250Sstevel@tonic-gate 		return (-1);
7260Sstevel@tonic-gate 	}
7270Sstevel@tonic-gate 
7280Sstevel@tonic-gate 	uu_list_insert(pgrp->sc_pgroup_props, prop, idx);
7290Sstevel@tonic-gate 
7300Sstevel@tonic-gate 	return (0);
7310Sstevel@tonic-gate }
7320Sstevel@tonic-gate 
7330Sstevel@tonic-gate void
internal_detach_property(pgroup_t * pgrp,property_t * prop)7347887SLiane.Praza@Sun.COM internal_detach_property(pgroup_t *pgrp, property_t *prop)
7357887SLiane.Praza@Sun.COM {
7367887SLiane.Praza@Sun.COM 	uu_list_remove(pgrp->sc_pgroup_props, prop);
7377887SLiane.Praza@Sun.COM }
7387887SLiane.Praza@Sun.COM 
7397887SLiane.Praza@Sun.COM void
internal_attach_value(property_t * prop,value_t * val)7400Sstevel@tonic-gate internal_attach_value(property_t *prop, value_t *val)
7410Sstevel@tonic-gate {
7427128Samaguire 	(void) uu_list_append(prop->sc_property_values, val);
7430Sstevel@tonic-gate }
7440Sstevel@tonic-gate 
7450Sstevel@tonic-gate /*
7460Sstevel@tonic-gate  * These functions create an internal representation of a property group
7470Sstevel@tonic-gate  * (pgroup_t) from the repository (scf_propertygroup_t).  They are used by the
7480Sstevel@tonic-gate  * import functions in svccfg_libscf.c .
7490Sstevel@tonic-gate  *
7500Sstevel@tonic-gate  * load_init() must be called first to initialize these globals, and
7510Sstevel@tonic-gate  * load_fini() should be called afterwards to destroy them.
7520Sstevel@tonic-gate  */
7530Sstevel@tonic-gate 
7540Sstevel@tonic-gate static char *loadbuf = NULL;
7550Sstevel@tonic-gate static size_t loadbuf_sz;
7567887SLiane.Praza@Sun.COM static scf_propertygroup_t *load_pgroup = NULL;
7570Sstevel@tonic-gate static scf_property_t *load_prop = NULL;
7580Sstevel@tonic-gate static scf_value_t *load_val = NULL;
7590Sstevel@tonic-gate static scf_iter_t *load_propiter = NULL, *load_valiter = NULL;
7607887SLiane.Praza@Sun.COM static scf_iter_t *load_pgiter = NULL;
7610Sstevel@tonic-gate 
7620Sstevel@tonic-gate /*
7630Sstevel@tonic-gate  * Initialize the global state for the load_*() routines.
7640Sstevel@tonic-gate  * Returns
7650Sstevel@tonic-gate  *   0 - success
7660Sstevel@tonic-gate  *   ENOMEM - out of memory
7670Sstevel@tonic-gate  */
7680Sstevel@tonic-gate int
load_init(void)7690Sstevel@tonic-gate load_init(void)
7700Sstevel@tonic-gate {
7710Sstevel@tonic-gate 	loadbuf_sz = ((max_scf_value_len > max_scf_pg_type_len) ?
7720Sstevel@tonic-gate 	    max_scf_value_len : max_scf_pg_type_len) + 1;
7730Sstevel@tonic-gate 
7740Sstevel@tonic-gate 	loadbuf = malloc(loadbuf_sz);
7750Sstevel@tonic-gate 	if (loadbuf == NULL)
7760Sstevel@tonic-gate 		return (ENOMEM);
7770Sstevel@tonic-gate 
7780Sstevel@tonic-gate 	if ((load_prop = scf_property_create(g_hndl)) == NULL ||
7790Sstevel@tonic-gate 	    (load_val = scf_value_create(g_hndl)) == NULL ||
7807887SLiane.Praza@Sun.COM 	    (load_pgroup = scf_pg_create(g_hndl)) == NULL ||
7817887SLiane.Praza@Sun.COM 	    (load_pgiter = scf_iter_create(g_hndl)) == NULL ||
7820Sstevel@tonic-gate 	    (load_propiter = scf_iter_create(g_hndl)) == NULL ||
7830Sstevel@tonic-gate 	    (load_valiter = scf_iter_create(g_hndl)) == NULL) {
7840Sstevel@tonic-gate 		load_fini();
7850Sstevel@tonic-gate 		return (ENOMEM);
7860Sstevel@tonic-gate 	}
7870Sstevel@tonic-gate 
7880Sstevel@tonic-gate 	return (0);
7890Sstevel@tonic-gate }
7900Sstevel@tonic-gate 
7910Sstevel@tonic-gate void
load_fini(void)7920Sstevel@tonic-gate load_fini(void)
7930Sstevel@tonic-gate {
7940Sstevel@tonic-gate 	scf_iter_destroy(load_propiter);
7950Sstevel@tonic-gate 	load_propiter = NULL;
7960Sstevel@tonic-gate 	scf_iter_destroy(load_valiter);
7970Sstevel@tonic-gate 	load_valiter = NULL;
7987887SLiane.Praza@Sun.COM 	scf_iter_destroy(load_pgiter);
7997887SLiane.Praza@Sun.COM 	load_pgiter = NULL;
8007887SLiane.Praza@Sun.COM 	scf_pg_destroy(load_pgroup);
8017887SLiane.Praza@Sun.COM 	load_pgroup = NULL;
8020Sstevel@tonic-gate 	scf_value_destroy(load_val);
8030Sstevel@tonic-gate 	load_val = NULL;
8040Sstevel@tonic-gate 	scf_property_destroy(load_prop);
8050Sstevel@tonic-gate 	load_prop = NULL;
8060Sstevel@tonic-gate 	free(loadbuf);
8070Sstevel@tonic-gate 	loadbuf = NULL;
8080Sstevel@tonic-gate }
8090Sstevel@tonic-gate 
8100Sstevel@tonic-gate /*
8110Sstevel@tonic-gate  * Create a property_t which represents an scf_property_t.  Returns
8120Sstevel@tonic-gate  *   0 - success
8130Sstevel@tonic-gate  *   ECANCELED - prop's pg was deleted
8140Sstevel@tonic-gate  *   ECONNABORTED - repository disconnected
8150Sstevel@tonic-gate  *   ENOMEM - out of memory
8165040Swesolows  *   EACCES - permission denied when reading property
8170Sstevel@tonic-gate  */
8180Sstevel@tonic-gate static int
load_property(scf_property_t * prop,property_t ** ipp)8190Sstevel@tonic-gate load_property(scf_property_t *prop, property_t **ipp)
8200Sstevel@tonic-gate {
8210Sstevel@tonic-gate 	property_t *iprop;
8220Sstevel@tonic-gate 	int r;
8230Sstevel@tonic-gate 	ssize_t ssz;
8240Sstevel@tonic-gate 
8250Sstevel@tonic-gate 	/* get name */
8260Sstevel@tonic-gate 	if (scf_property_get_name(prop, loadbuf, loadbuf_sz) < 0) {
8270Sstevel@tonic-gate 		switch (scf_error()) {
8280Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
8290Sstevel@tonic-gate 			return (ECANCELED);
8300Sstevel@tonic-gate 
8310Sstevel@tonic-gate 		case SCF_ERROR_CONNECTION_BROKEN:
8320Sstevel@tonic-gate 			return (ECONNABORTED);
8330Sstevel@tonic-gate 
8340Sstevel@tonic-gate 		case SCF_ERROR_NOT_BOUND:
8350Sstevel@tonic-gate 		case SCF_ERROR_NOT_SET:
8360Sstevel@tonic-gate 		default:
8370Sstevel@tonic-gate 			bad_error("scf_property_get_name", scf_error());
8380Sstevel@tonic-gate 		}
8390Sstevel@tonic-gate 	}
8400Sstevel@tonic-gate 
8410Sstevel@tonic-gate 	iprop = internal_property_new();
8420Sstevel@tonic-gate 	iprop->sc_property_name = strdup(loadbuf);
8430Sstevel@tonic-gate 	if (iprop->sc_property_name == NULL) {
8440Sstevel@tonic-gate 		internal_property_free(iprop);
8450Sstevel@tonic-gate 		return (ENOMEM);
8460Sstevel@tonic-gate 	}
8470Sstevel@tonic-gate 
8480Sstevel@tonic-gate 	/* get type */
8490Sstevel@tonic-gate 	if (scf_property_type(prop, &iprop->sc_value_type) != 0) {
8500Sstevel@tonic-gate 		switch (scf_error()) {
8510Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
8520Sstevel@tonic-gate 			r = ECANCELED;
8530Sstevel@tonic-gate 			goto out;
8540Sstevel@tonic-gate 
8550Sstevel@tonic-gate 		case SCF_ERROR_CONNECTION_BROKEN:
8560Sstevel@tonic-gate 			r = ECONNABORTED;
8570Sstevel@tonic-gate 			goto out;
8580Sstevel@tonic-gate 
8590Sstevel@tonic-gate 		case SCF_ERROR_NOT_BOUND:
8600Sstevel@tonic-gate 		case SCF_ERROR_NOT_SET:
8610Sstevel@tonic-gate 		default:
8620Sstevel@tonic-gate 			bad_error("scf_property_type", scf_error());
8630Sstevel@tonic-gate 		}
8640Sstevel@tonic-gate 	}
8650Sstevel@tonic-gate 
8660Sstevel@tonic-gate 	/* get values */
8670Sstevel@tonic-gate 	if (scf_iter_property_values(load_valiter, prop) != 0) {
8680Sstevel@tonic-gate 		switch (scf_error()) {
8690Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
8700Sstevel@tonic-gate 			r = ECANCELED;
8710Sstevel@tonic-gate 			goto out;
8720Sstevel@tonic-gate 
8730Sstevel@tonic-gate 		case SCF_ERROR_CONNECTION_BROKEN:
8740Sstevel@tonic-gate 			r = ECONNABORTED;
8750Sstevel@tonic-gate 			goto out;
8760Sstevel@tonic-gate 
8770Sstevel@tonic-gate 		case SCF_ERROR_HANDLE_MISMATCH:
8780Sstevel@tonic-gate 		case SCF_ERROR_NOT_BOUND:
8790Sstevel@tonic-gate 		case SCF_ERROR_NOT_SET:
8800Sstevel@tonic-gate 		default:
8810Sstevel@tonic-gate 			bad_error("scf_iter_property_values", scf_error());
8820Sstevel@tonic-gate 		}
8830Sstevel@tonic-gate 	}
8840Sstevel@tonic-gate 
8850Sstevel@tonic-gate 	for (;;) {
8860Sstevel@tonic-gate 		value_t *ival;
8870Sstevel@tonic-gate 
8880Sstevel@tonic-gate 		r = scf_iter_next_value(load_valiter, load_val);
8890Sstevel@tonic-gate 		if (r == 0)
8900Sstevel@tonic-gate 			break;
8910Sstevel@tonic-gate 		if (r != 1) {
8920Sstevel@tonic-gate 			switch (scf_error()) {
8930Sstevel@tonic-gate 			case SCF_ERROR_DELETED:
8940Sstevel@tonic-gate 				r = ECANCELED;
8950Sstevel@tonic-gate 				goto out;
8960Sstevel@tonic-gate 
8970Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
8980Sstevel@tonic-gate 				r = ECONNABORTED;
8990Sstevel@tonic-gate 				goto out;
9000Sstevel@tonic-gate 
9015040Swesolows 			case SCF_ERROR_PERMISSION_DENIED:
9025040Swesolows 				r = EACCES;
9035040Swesolows 				goto out;
9045040Swesolows 
9050Sstevel@tonic-gate 			case SCF_ERROR_HANDLE_MISMATCH:
9060Sstevel@tonic-gate 			case SCF_ERROR_NOT_BOUND:
9070Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
9080Sstevel@tonic-gate 			case SCF_ERROR_INVALID_ARGUMENT:
9090Sstevel@tonic-gate 			default:
9100Sstevel@tonic-gate 				bad_error("scf_iter_next_value", scf_error());
9110Sstevel@tonic-gate 			}
9120Sstevel@tonic-gate 		}
9130Sstevel@tonic-gate 
9140Sstevel@tonic-gate 		ival = internal_value_new();
9150Sstevel@tonic-gate 		ival->sc_type = scf_value_type(load_val);
9160Sstevel@tonic-gate 		assert(ival->sc_type != SCF_TYPE_INVALID);
9170Sstevel@tonic-gate 
9180Sstevel@tonic-gate 		switch (ival->sc_type) {
9190Sstevel@tonic-gate 		case SCF_TYPE_BOOLEAN: {
9200Sstevel@tonic-gate 			uint8_t b;
9210Sstevel@tonic-gate 
9220Sstevel@tonic-gate 			r = scf_value_get_boolean(load_val, &b);
9230Sstevel@tonic-gate 			if (r != 0)
9240Sstevel@tonic-gate 				bad_error("scf_value_get_boolean", scf_error());
9250Sstevel@tonic-gate 			ival->sc_u.sc_count = b;
9260Sstevel@tonic-gate 			break;
9270Sstevel@tonic-gate 		}
9280Sstevel@tonic-gate 
9290Sstevel@tonic-gate 		case SCF_TYPE_COUNT:
9300Sstevel@tonic-gate 			r = scf_value_get_count(load_val, &ival->sc_u.sc_count);
9310Sstevel@tonic-gate 			if (r != 0)
9320Sstevel@tonic-gate 				bad_error("scf_value_get_count", scf_error());
9330Sstevel@tonic-gate 			break;
9340Sstevel@tonic-gate 
9350Sstevel@tonic-gate 		case SCF_TYPE_INTEGER:
9360Sstevel@tonic-gate 			r = scf_value_get_integer(load_val,
9370Sstevel@tonic-gate 			    &ival->sc_u.sc_integer);
9380Sstevel@tonic-gate 			if (r != 0)
9390Sstevel@tonic-gate 				bad_error("scf_value_get_integer", scf_error());
9400Sstevel@tonic-gate 			break;
9410Sstevel@tonic-gate 
9420Sstevel@tonic-gate 		default:
9430Sstevel@tonic-gate 			ssz = scf_value_get_as_string(load_val, loadbuf,
9440Sstevel@tonic-gate 			    loadbuf_sz);
9450Sstevel@tonic-gate 			if (ssz < 0)
9460Sstevel@tonic-gate 				bad_error("scf_value_get_as_string",
9470Sstevel@tonic-gate 				    scf_error());
9480Sstevel@tonic-gate 
9490Sstevel@tonic-gate 			ival->sc_u.sc_string = strdup(loadbuf);
9500Sstevel@tonic-gate 			if (ival->sc_u.sc_string == NULL) {
9510Sstevel@tonic-gate 				r = ENOMEM;
9520Sstevel@tonic-gate 				goto out;
9530Sstevel@tonic-gate 			}
9540Sstevel@tonic-gate 
9550Sstevel@tonic-gate 			ival->sc_free = internal_value_free_str;
9560Sstevel@tonic-gate 		}
9570Sstevel@tonic-gate 
9580Sstevel@tonic-gate 		internal_attach_value(iprop, ival);
9590Sstevel@tonic-gate 	}
9600Sstevel@tonic-gate 
9610Sstevel@tonic-gate 	*ipp = iprop;
9620Sstevel@tonic-gate 	return (0);
9630Sstevel@tonic-gate 
9640Sstevel@tonic-gate out:
9650Sstevel@tonic-gate 	free(iprop->sc_property_name);
9660Sstevel@tonic-gate 	internal_property_free(iprop);
9670Sstevel@tonic-gate 	return (r);
9680Sstevel@tonic-gate }
9690Sstevel@tonic-gate 
9700Sstevel@tonic-gate /*
9710Sstevel@tonic-gate  * Returns
9720Sstevel@tonic-gate  *   0 - success
9730Sstevel@tonic-gate  *   ECANCELED - pg was deleted
9740Sstevel@tonic-gate  *   ECONNABORTED - repository disconnected
9750Sstevel@tonic-gate  *   ENOMEM - out of memory
9760Sstevel@tonic-gate  */
9770Sstevel@tonic-gate int
load_pg_attrs(const scf_propertygroup_t * pg,pgroup_t ** ipgp)9780Sstevel@tonic-gate load_pg_attrs(const scf_propertygroup_t *pg, pgroup_t **ipgp)
9790Sstevel@tonic-gate {
9800Sstevel@tonic-gate 	pgroup_t *ipg;
9810Sstevel@tonic-gate 
9820Sstevel@tonic-gate 	ipg = internal_pgroup_new();
9830Sstevel@tonic-gate 
9840Sstevel@tonic-gate 	if (scf_pg_get_flags(pg, &ipg->sc_pgroup_flags) != 0) {
9850Sstevel@tonic-gate 		switch (scf_error()) {
9860Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
9870Sstevel@tonic-gate 			internal_pgroup_free(ipg);
9880Sstevel@tonic-gate 			return (ECANCELED);
9890Sstevel@tonic-gate 
9900Sstevel@tonic-gate 		case SCF_ERROR_CONNECTION_BROKEN:
9910Sstevel@tonic-gate 			internal_pgroup_free(ipg);
9920Sstevel@tonic-gate 			return (ECONNABORTED);
9930Sstevel@tonic-gate 
9940Sstevel@tonic-gate 		case SCF_ERROR_NOT_SET:
9950Sstevel@tonic-gate 		case SCF_ERROR_NOT_BOUND:
9960Sstevel@tonic-gate 		default:
9970Sstevel@tonic-gate 			bad_error("scf_pg_get_name", scf_error());
9980Sstevel@tonic-gate 		}
9990Sstevel@tonic-gate 	}
10000Sstevel@tonic-gate 
10010Sstevel@tonic-gate 	if (scf_pg_get_name(pg, loadbuf, loadbuf_sz) < 0) {
10020Sstevel@tonic-gate 		switch (scf_error()) {
10030Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
10040Sstevel@tonic-gate 			internal_pgroup_free(ipg);
10050Sstevel@tonic-gate 			return (ECANCELED);
10060Sstevel@tonic-gate 
10070Sstevel@tonic-gate 		case SCF_ERROR_CONNECTION_BROKEN:
10080Sstevel@tonic-gate 			internal_pgroup_free(ipg);
10090Sstevel@tonic-gate 			return (ECONNABORTED);
10100Sstevel@tonic-gate 
10110Sstevel@tonic-gate 		case SCF_ERROR_NOT_SET:
10120Sstevel@tonic-gate 		case SCF_ERROR_NOT_BOUND:
10130Sstevel@tonic-gate 		default:
10140Sstevel@tonic-gate 			bad_error("scf_pg_get_name", scf_error());
10150Sstevel@tonic-gate 		}
10160Sstevel@tonic-gate 	}
10170Sstevel@tonic-gate 
10180Sstevel@tonic-gate 	ipg->sc_pgroup_name = strdup(loadbuf);
10190Sstevel@tonic-gate 	if (ipg->sc_pgroup_name == NULL) {
10200Sstevel@tonic-gate 		internal_pgroup_free(ipg);
10210Sstevel@tonic-gate 		return (ENOMEM);
10220Sstevel@tonic-gate 	}
10230Sstevel@tonic-gate 
10240Sstevel@tonic-gate 	if (scf_pg_get_type(pg, loadbuf, loadbuf_sz) < 0) {
10250Sstevel@tonic-gate 		switch (scf_error()) {
10260Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
10270Sstevel@tonic-gate 			free((char *)ipg->sc_pgroup_name);
10280Sstevel@tonic-gate 			internal_pgroup_free(ipg);
10290Sstevel@tonic-gate 			return (ECANCELED);
10300Sstevel@tonic-gate 
10310Sstevel@tonic-gate 		case SCF_ERROR_CONNECTION_BROKEN:
10320Sstevel@tonic-gate 			free((char *)ipg->sc_pgroup_name);
10330Sstevel@tonic-gate 			internal_pgroup_free(ipg);
10340Sstevel@tonic-gate 			return (ECONNABORTED);
10350Sstevel@tonic-gate 
10360Sstevel@tonic-gate 		case SCF_ERROR_NOT_SET:
10370Sstevel@tonic-gate 		case SCF_ERROR_NOT_BOUND:
10380Sstevel@tonic-gate 		default:
10390Sstevel@tonic-gate 			bad_error("scf_pg_get_name", scf_error());
10400Sstevel@tonic-gate 		}
10410Sstevel@tonic-gate 	}
10420Sstevel@tonic-gate 
10430Sstevel@tonic-gate 	ipg->sc_pgroup_type = strdup(loadbuf);
10440Sstevel@tonic-gate 	if (ipg->sc_pgroup_type == NULL) {
10450Sstevel@tonic-gate 		free((char *)ipg->sc_pgroup_name);
10460Sstevel@tonic-gate 		internal_pgroup_free(ipg);
10470Sstevel@tonic-gate 		return (ENOMEM);
10480Sstevel@tonic-gate 	}
10490Sstevel@tonic-gate 
10500Sstevel@tonic-gate 	*ipgp = ipg;
10510Sstevel@tonic-gate 	return (0);
10520Sstevel@tonic-gate }
10530Sstevel@tonic-gate 
10540Sstevel@tonic-gate /*
10550Sstevel@tonic-gate  * Load a property group into a pgroup_t.  Returns
10560Sstevel@tonic-gate  *   0 - success
10570Sstevel@tonic-gate  *   ECANCELED - pg was deleted
10580Sstevel@tonic-gate  *   ECONNABORTED - repository disconnected
10590Sstevel@tonic-gate  *   EBADF - pg is corrupt (error printed if fmri is given)
10600Sstevel@tonic-gate  *   ENOMEM - out of memory
10615040Swesolows  *   EACCES - permission denied when reading property
10620Sstevel@tonic-gate  */
10630Sstevel@tonic-gate int
load_pg(const scf_propertygroup_t * pg,pgroup_t ** ipgp,const char * fmri,const char * snapname)10640Sstevel@tonic-gate load_pg(const scf_propertygroup_t *pg, pgroup_t **ipgp, const char *fmri,
10650Sstevel@tonic-gate     const char *snapname)
10660Sstevel@tonic-gate {
10670Sstevel@tonic-gate 	pgroup_t *ipg;
10680Sstevel@tonic-gate 	int r;
10690Sstevel@tonic-gate 
10700Sstevel@tonic-gate 	if (scf_iter_pg_properties(load_propiter, pg) != 0) {
10710Sstevel@tonic-gate 		switch (scf_error()) {
10720Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
10730Sstevel@tonic-gate 			return (ECANCELED);
10740Sstevel@tonic-gate 
10750Sstevel@tonic-gate 		case SCF_ERROR_CONNECTION_BROKEN:
10760Sstevel@tonic-gate 			return (ECONNABORTED);
10770Sstevel@tonic-gate 
10780Sstevel@tonic-gate 		case SCF_ERROR_HANDLE_MISMATCH:
10790Sstevel@tonic-gate 		case SCF_ERROR_NOT_SET:
10800Sstevel@tonic-gate 		case SCF_ERROR_NOT_BOUND:
10810Sstevel@tonic-gate 		default:
10820Sstevel@tonic-gate 			bad_error("scf_iter_pg_properties", scf_error());
10830Sstevel@tonic-gate 		}
10840Sstevel@tonic-gate 	}
10850Sstevel@tonic-gate 
10860Sstevel@tonic-gate 	r = load_pg_attrs(pg, &ipg);
10870Sstevel@tonic-gate 	switch (r) {
10880Sstevel@tonic-gate 	case 0:
10890Sstevel@tonic-gate 		break;
10900Sstevel@tonic-gate 
10910Sstevel@tonic-gate 	case ECANCELED:
10920Sstevel@tonic-gate 	case ECONNABORTED:
10930Sstevel@tonic-gate 	case ENOMEM:
10940Sstevel@tonic-gate 		return (r);
10950Sstevel@tonic-gate 
10960Sstevel@tonic-gate 	default:
10970Sstevel@tonic-gate 		bad_error("load_pg_attrs", r);
10980Sstevel@tonic-gate 	}
10990Sstevel@tonic-gate 
11000Sstevel@tonic-gate 	for (;;) {
11010Sstevel@tonic-gate 		property_t *iprop;
11020Sstevel@tonic-gate 
11030Sstevel@tonic-gate 		r = scf_iter_next_property(load_propiter, load_prop);
11040Sstevel@tonic-gate 		if (r == 0)
11050Sstevel@tonic-gate 			break;
11060Sstevel@tonic-gate 		if (r != 1) {
11070Sstevel@tonic-gate 			switch (scf_error()) {
11080Sstevel@tonic-gate 			case SCF_ERROR_DELETED:
11090Sstevel@tonic-gate 				r = ECANCELED;
11100Sstevel@tonic-gate 				goto out;
11110Sstevel@tonic-gate 
11120Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
11130Sstevel@tonic-gate 				r = ECONNABORTED;
11140Sstevel@tonic-gate 				goto out;
11150Sstevel@tonic-gate 
11160Sstevel@tonic-gate 			case SCF_ERROR_HANDLE_MISMATCH:
11170Sstevel@tonic-gate 			case SCF_ERROR_NOT_BOUND:
11180Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
11190Sstevel@tonic-gate 			case SCF_ERROR_INVALID_ARGUMENT:
11200Sstevel@tonic-gate 			default:
11210Sstevel@tonic-gate 				bad_error("scf_iter_next_property",
11220Sstevel@tonic-gate 				    scf_error());
11230Sstevel@tonic-gate 			}
11240Sstevel@tonic-gate 		}
11250Sstevel@tonic-gate 
11260Sstevel@tonic-gate 		r = load_property(load_prop, &iprop);
11270Sstevel@tonic-gate 		switch (r) {
11280Sstevel@tonic-gate 		case 0:
11290Sstevel@tonic-gate 			break;
11300Sstevel@tonic-gate 
11310Sstevel@tonic-gate 		case ECANCELED:
11320Sstevel@tonic-gate 		case ECONNABORTED:
11330Sstevel@tonic-gate 		case ENOMEM:
11345040Swesolows 		case EACCES:
11350Sstevel@tonic-gate 			goto out;
11360Sstevel@tonic-gate 
11370Sstevel@tonic-gate 		default:
11380Sstevel@tonic-gate 			bad_error("load_property", r);
11390Sstevel@tonic-gate 		}
11400Sstevel@tonic-gate 
11410Sstevel@tonic-gate 		r = internal_attach_property(ipg, iprop);
11420Sstevel@tonic-gate 		if (r != 0) {
11430Sstevel@tonic-gate 			if (fmri != NULL) {
11440Sstevel@tonic-gate 				if (snapname == NULL)
11450Sstevel@tonic-gate 					warn(gettext("Property group \"%s\" of "
11460Sstevel@tonic-gate 					    "%s has multiple definitions of "
11470Sstevel@tonic-gate 					    "property \"%s\".\n"),
11480Sstevel@tonic-gate 					    ipg->sc_pgroup_name, fmri,
11490Sstevel@tonic-gate 					    iprop->sc_property_name);
11500Sstevel@tonic-gate 				else
11510Sstevel@tonic-gate 					warn(gettext("Property group \"%s\" of "
11520Sstevel@tonic-gate 					    "the \"%s\" snapshot of %s has "
11530Sstevel@tonic-gate 					    "multiple definitions of property "
11540Sstevel@tonic-gate 					    "\"%s\".\n"),
11550Sstevel@tonic-gate 					    ipg->sc_pgroup_name, snapname, fmri,
11560Sstevel@tonic-gate 					    iprop->sc_property_name);
11570Sstevel@tonic-gate 			}
11580Sstevel@tonic-gate 			r = EBADF;
11590Sstevel@tonic-gate 			goto out;
11600Sstevel@tonic-gate 		}
11610Sstevel@tonic-gate 	}
11620Sstevel@tonic-gate 
11630Sstevel@tonic-gate 	*ipgp = ipg;
11640Sstevel@tonic-gate 	return (0);
11650Sstevel@tonic-gate 
11660Sstevel@tonic-gate out:
11670Sstevel@tonic-gate 	internal_pgroup_free(ipg);
11680Sstevel@tonic-gate 	return (r);
11690Sstevel@tonic-gate }
11700Sstevel@tonic-gate 
11710Sstevel@tonic-gate /*
11727887SLiane.Praza@Sun.COM  * Load the instance for fmri from the repository into memory.  The
11737887SLiane.Praza@Sun.COM  * property groups that define the instances pg_patterns and prop_patterns
11747887SLiane.Praza@Sun.COM  * are also loaded.
11757887SLiane.Praza@Sun.COM  *
11767887SLiane.Praza@Sun.COM  * Returns 0 on success and non-zero on failure.
11777887SLiane.Praza@Sun.COM  */
11787887SLiane.Praza@Sun.COM int
load_instance(const char * fmri,const char * name,entity_t ** inst_ptr)11797887SLiane.Praza@Sun.COM load_instance(const char *fmri, const char *name, entity_t **inst_ptr)
11807887SLiane.Praza@Sun.COM {
11817887SLiane.Praza@Sun.COM 	entity_t *e = NULL;
11827887SLiane.Praza@Sun.COM 	scf_instance_t *inst;
11837887SLiane.Praza@Sun.COM 	pgroup_t *ipg;
11847887SLiane.Praza@Sun.COM 	int rc;
11857887SLiane.Praza@Sun.COM 	char *type = NULL;
11867887SLiane.Praza@Sun.COM 	ssize_t tsize;
11877887SLiane.Praza@Sun.COM 
11887887SLiane.Praza@Sun.COM 	assert(inst_ptr != NULL);
11897887SLiane.Praza@Sun.COM 
11907887SLiane.Praza@Sun.COM 	if ((inst = scf_instance_create(g_hndl)) == NULL) {
11917887SLiane.Praza@Sun.COM 		switch (scf_error()) {
11927887SLiane.Praza@Sun.COM 		case SCF_ERROR_NO_MEMORY:
11937887SLiane.Praza@Sun.COM 		case SCF_ERROR_NO_RESOURCES:
11947887SLiane.Praza@Sun.COM 			rc = EAGAIN;
11957887SLiane.Praza@Sun.COM 			goto errout;
11967887SLiane.Praza@Sun.COM 		default:
11977887SLiane.Praza@Sun.COM 			bad_error("scf_instance_create", scf_error());
11987887SLiane.Praza@Sun.COM 		}
11997887SLiane.Praza@Sun.COM 	}
12007887SLiane.Praza@Sun.COM 	if (scf_handle_decode_fmri(g_hndl, fmri, NULL, NULL, inst, NULL, NULL,
12017887SLiane.Praza@Sun.COM 	    SCF_DECODE_FMRI_EXACT|SCF_DECODE_FMRI_REQUIRE_INSTANCE) != 0) {
12027887SLiane.Praza@Sun.COM 		switch (scf_error()) {
12037887SLiane.Praza@Sun.COM 		case SCF_ERROR_CONNECTION_BROKEN:
12047887SLiane.Praza@Sun.COM 			rc = ECONNABORTED;
12057887SLiane.Praza@Sun.COM 			goto errout;
12067887SLiane.Praza@Sun.COM 		case SCF_ERROR_DELETED:
12077887SLiane.Praza@Sun.COM 		case SCF_ERROR_NOT_FOUND:
12087887SLiane.Praza@Sun.COM 			rc = ENOENT;
12097887SLiane.Praza@Sun.COM 			goto errout;
12109765SSean.Wilcox@Sun.COM 		case SCF_ERROR_INVALID_ARGUMENT:
12119765SSean.Wilcox@Sun.COM 			rc = EINVAL;
12129765SSean.Wilcox@Sun.COM 			goto errout;
12139765SSean.Wilcox@Sun.COM 		case SCF_ERROR_CONSTRAINT_VIOLATED:
12149765SSean.Wilcox@Sun.COM 			rc = ENOTSUP;
12159765SSean.Wilcox@Sun.COM 			goto errout;
12167887SLiane.Praza@Sun.COM 		default:
12177887SLiane.Praza@Sun.COM 			bad_error("scf_handle_decode_fmri", scf_error());
12187887SLiane.Praza@Sun.COM 		}
12197887SLiane.Praza@Sun.COM 	}
12207887SLiane.Praza@Sun.COM 	if (scf_iter_instance_pgs_composed(load_pgiter, inst, NULL) != 0) {
12217887SLiane.Praza@Sun.COM 		switch (scf_error()) {
12227887SLiane.Praza@Sun.COM 		case SCF_ERROR_DELETED:
12237887SLiane.Praza@Sun.COM 			rc = ECANCELED;
12247887SLiane.Praza@Sun.COM 			goto errout;
12257887SLiane.Praza@Sun.COM 		case SCF_ERROR_CONNECTION_BROKEN:
12267887SLiane.Praza@Sun.COM 			rc = ECONNABORTED;
12277887SLiane.Praza@Sun.COM 			goto errout;
12287887SLiane.Praza@Sun.COM 		default:
12297887SLiane.Praza@Sun.COM 			bad_error("scf_iter_instance_pgs_composed",
12307887SLiane.Praza@Sun.COM 			    scf_error());
12317887SLiane.Praza@Sun.COM 		}
12327887SLiane.Praza@Sun.COM 	}
12337887SLiane.Praza@Sun.COM 
12347887SLiane.Praza@Sun.COM 	tsize = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH);
12357887SLiane.Praza@Sun.COM 	type = uu_zalloc(tsize);
12367887SLiane.Praza@Sun.COM 	if (type == NULL) {
12377887SLiane.Praza@Sun.COM 		rc = ENOMEM;
12387887SLiane.Praza@Sun.COM 		goto errout;
12397887SLiane.Praza@Sun.COM 	}
12407887SLiane.Praza@Sun.COM 
12417887SLiane.Praza@Sun.COM 	/*
12427887SLiane.Praza@Sun.COM 	 * Initialize our entity structure.
12437887SLiane.Praza@Sun.COM 	 */
12447887SLiane.Praza@Sun.COM 	e = internal_instance_new(name);
12457887SLiane.Praza@Sun.COM 	if (e == NULL) {
12467887SLiane.Praza@Sun.COM 		rc = ENOMEM;
12477887SLiane.Praza@Sun.COM 		goto errout;
12487887SLiane.Praza@Sun.COM 	}
12497887SLiane.Praza@Sun.COM 	e->sc_fmri = uu_strdup(fmri);
12507887SLiane.Praza@Sun.COM 	if (e->sc_fmri == NULL) {
12517887SLiane.Praza@Sun.COM 		rc = ENOMEM;
12527887SLiane.Praza@Sun.COM 		goto errout;
12537887SLiane.Praza@Sun.COM 	}
12547887SLiane.Praza@Sun.COM 
12557887SLiane.Praza@Sun.COM 	/*
12567887SLiane.Praza@Sun.COM 	 * Walk through the property group's of the instance and capture
12577887SLiane.Praza@Sun.COM 	 * the property groups that are of type
12587887SLiane.Praza@Sun.COM 	 * SCF_GROUP_TEMPLATE_PG_PATTERN and
12597887SLiane.Praza@Sun.COM 	 * SCF_GROUP_TEMPLATE_PROP_PATTERN.  In other words grab the
12607887SLiane.Praza@Sun.COM 	 * pg_pattern and prop_pattern property groups.
12617887SLiane.Praza@Sun.COM 	 */
12627887SLiane.Praza@Sun.COM 	while ((rc = scf_iter_next_pg(load_pgiter, load_pgroup)) == 1) {
12637887SLiane.Praza@Sun.COM 		if (scf_pg_get_type(load_pgroup, type, tsize) <= 0) {
12647887SLiane.Praza@Sun.COM 			switch (scf_error()) {
12657887SLiane.Praza@Sun.COM 			case SCF_ERROR_DELETED:
12667887SLiane.Praza@Sun.COM 				rc = ENOENT;
12677887SLiane.Praza@Sun.COM 				break;
12687887SLiane.Praza@Sun.COM 			case SCF_ERROR_CONNECTION_BROKEN:
12697887SLiane.Praza@Sun.COM 				rc = ECONNABORTED;
12707887SLiane.Praza@Sun.COM 				break;
12717887SLiane.Praza@Sun.COM 			default:
12727887SLiane.Praza@Sun.COM 				bad_error("scf_pg_get_type", scf_error());
12737887SLiane.Praza@Sun.COM 			}
12747887SLiane.Praza@Sun.COM 			goto errout;
12757887SLiane.Praza@Sun.COM 		}
12767887SLiane.Praza@Sun.COM 		if ((strcmp(type, SCF_GROUP_TEMPLATE_PG_PATTERN) != 0) &&
12777887SLiane.Praza@Sun.COM 		    (strcmp(type, SCF_GROUP_TEMPLATE_PROP_PATTERN) != 0)) {
12787887SLiane.Praza@Sun.COM 			continue;
12797887SLiane.Praza@Sun.COM 		}
12807887SLiane.Praza@Sun.COM 		if ((rc = load_pg(load_pgroup, &ipg, fmri, NULL)) != 0) {
12817887SLiane.Praza@Sun.COM 			switch (rc) {
12827887SLiane.Praza@Sun.COM 			case ECANCELED:
12837887SLiane.Praza@Sun.COM 			case ECONNABORTED:
12847887SLiane.Praza@Sun.COM 			case EACCES:
12857887SLiane.Praza@Sun.COM 			case ENOMEM:
12867887SLiane.Praza@Sun.COM 				break;
12877887SLiane.Praza@Sun.COM 			default:
12887887SLiane.Praza@Sun.COM 				bad_error("load_pg", rc);
12897887SLiane.Praza@Sun.COM 			}
12907887SLiane.Praza@Sun.COM 			goto errout;
12917887SLiane.Praza@Sun.COM 		}
12927887SLiane.Praza@Sun.COM 		if (internal_attach_pgroup(e, ipg) != 0) {
12937887SLiane.Praza@Sun.COM 			rc = EBADF;
12947887SLiane.Praza@Sun.COM 			goto errout;
12957887SLiane.Praza@Sun.COM 		}
12967887SLiane.Praza@Sun.COM 	}
12977887SLiane.Praza@Sun.COM 	if (rc == -1) {
12987887SLiane.Praza@Sun.COM 		/* Error in iteration. */
12997887SLiane.Praza@Sun.COM 		switch (scf_error()) {
13007887SLiane.Praza@Sun.COM 		case SCF_ERROR_CONNECTION_BROKEN:
13017887SLiane.Praza@Sun.COM 			rc = ECONNABORTED;
13027887SLiane.Praza@Sun.COM 			break;
13037887SLiane.Praza@Sun.COM 		case SCF_ERROR_DELETED:
13047887SLiane.Praza@Sun.COM 			rc = ENOENT;
13057887SLiane.Praza@Sun.COM 			break;
13067887SLiane.Praza@Sun.COM 		case SCF_ERROR_NO_RESOURCES:
13077887SLiane.Praza@Sun.COM 			rc = EAGAIN;
13087887SLiane.Praza@Sun.COM 			break;
13097887SLiane.Praza@Sun.COM 		default:
13107887SLiane.Praza@Sun.COM 			bad_error("scf_iter_next_pg", scf_error());
13117887SLiane.Praza@Sun.COM 		}
13127887SLiane.Praza@Sun.COM 		goto errout;
13137887SLiane.Praza@Sun.COM 	}
13147887SLiane.Praza@Sun.COM 
13157887SLiane.Praza@Sun.COM 	*inst_ptr = e;
13167887SLiane.Praza@Sun.COM 	scf_instance_destroy(inst);
13177887SLiane.Praza@Sun.COM 	return (0);
13187887SLiane.Praza@Sun.COM 
13197887SLiane.Praza@Sun.COM errout:
13207887SLiane.Praza@Sun.COM 	if (type != NULL)
13217887SLiane.Praza@Sun.COM 		uu_free(type);
13227887SLiane.Praza@Sun.COM 	if (inst != NULL)
13237887SLiane.Praza@Sun.COM 		scf_instance_destroy(inst);
13247887SLiane.Praza@Sun.COM 	if (e != NULL)
13257887SLiane.Praza@Sun.COM 		internal_instance_free(e);
13267887SLiane.Praza@Sun.COM 	return (rc);
13277887SLiane.Praza@Sun.COM }
13287887SLiane.Praza@Sun.COM 
13297887SLiane.Praza@Sun.COM /*
13300Sstevel@tonic-gate  * These functions compare internal property groups and properties (pgroup_t
13310Sstevel@tonic-gate  * & property_t).  They return 1 if the given structures are equal and
13320Sstevel@tonic-gate  * 0 otherwise.  Some will report the differences between the two structures.
13330Sstevel@tonic-gate  * They are used by the import functions in svccfg_libscf.c .
13340Sstevel@tonic-gate  */
13350Sstevel@tonic-gate 
13360Sstevel@tonic-gate int
prop_equal(property_t * p1,property_t * p2,const char * fmri,const char * pgname,int new)13370Sstevel@tonic-gate prop_equal(property_t *p1, property_t *p2, const char *fmri, const char *pgname,
13380Sstevel@tonic-gate     int new)
13390Sstevel@tonic-gate {
13400Sstevel@tonic-gate 	value_t *v1, *v2;
13410Sstevel@tonic-gate 
13420Sstevel@tonic-gate 	const char * const values_diff = gettext("Conflict upgrading %s "
13430Sstevel@tonic-gate 	    "(property \"%s/%s\" has different values).\n");
13440Sstevel@tonic-gate 	const char * const values_diff_new = gettext("Conflict upgrading %s "
13450Sstevel@tonic-gate 	    "(new property \"%s/%s\" has different values).\n");
13460Sstevel@tonic-gate 
13470Sstevel@tonic-gate 	assert((fmri == NULL) == (pgname == NULL));
13480Sstevel@tonic-gate 
13490Sstevel@tonic-gate 	if (fmri != NULL) {
13500Sstevel@tonic-gate 		/*
13510Sstevel@tonic-gate 		 * If we find any differences, we'll report conflicts.  But
13520Sstevel@tonic-gate 		 * conflict messages won't make any sense if the names don't
13530Sstevel@tonic-gate 		 * match.  If the caller supplied fmri, assert that the names
13540Sstevel@tonic-gate 		 * match.
13550Sstevel@tonic-gate 		 */
13560Sstevel@tonic-gate 		assert(strcmp(p1->sc_property_name, p2->sc_property_name) == 0);
13570Sstevel@tonic-gate 	} else {
13580Sstevel@tonic-gate 		if (strcmp(p1->sc_property_name, p2->sc_property_name) != 0)
13590Sstevel@tonic-gate 			return (0);
13600Sstevel@tonic-gate 	}
13610Sstevel@tonic-gate 
13620Sstevel@tonic-gate 	if (p1->sc_value_type != p2->sc_value_type) {
13630Sstevel@tonic-gate 		if (fmri != NULL) {
13640Sstevel@tonic-gate 			if (new)
13650Sstevel@tonic-gate 				warn(gettext("Conflict upgrading %s "
13660Sstevel@tonic-gate 				    "(new property \"%s/%s\" has different "
13670Sstevel@tonic-gate 				    "type).\n"), fmri, pgname,
13680Sstevel@tonic-gate 				    p1->sc_property_name);
13690Sstevel@tonic-gate 			else
13700Sstevel@tonic-gate 				warn(gettext("Conflict upgrading %s "
13710Sstevel@tonic-gate 				    "(property \"%s/%s\" has different "
13720Sstevel@tonic-gate 				    "type).\n"), fmri, pgname,
13730Sstevel@tonic-gate 				    p1->sc_property_name);
13740Sstevel@tonic-gate 		}
13750Sstevel@tonic-gate 		return (0);
13760Sstevel@tonic-gate 	}
13770Sstevel@tonic-gate 
13780Sstevel@tonic-gate 	if (uu_list_numnodes(p1->sc_property_values) !=
13790Sstevel@tonic-gate 	    uu_list_numnodes(p2->sc_property_values)) {
13800Sstevel@tonic-gate 		if (fmri != NULL)
13810Sstevel@tonic-gate 			warn(new ? values_diff_new : values_diff, fmri,
13820Sstevel@tonic-gate 			    pgname, p1->sc_property_name);
13830Sstevel@tonic-gate 		return (0);
13840Sstevel@tonic-gate 	}
13850Sstevel@tonic-gate 
13860Sstevel@tonic-gate 	v1 = uu_list_first(p1->sc_property_values);
13870Sstevel@tonic-gate 	v2 = uu_list_first(p2->sc_property_values);
13880Sstevel@tonic-gate 
13890Sstevel@tonic-gate 	while (v1 != NULL) {
13900Sstevel@tonic-gate 		assert(v2 != NULL);
13910Sstevel@tonic-gate 
13920Sstevel@tonic-gate 		if (value_cmp(v1, v2, NULL) != 0) {
13930Sstevel@tonic-gate 			if (fmri != NULL)
13940Sstevel@tonic-gate 				warn(new ? values_diff_new : values_diff,
13950Sstevel@tonic-gate 				    fmri, pgname, p1->sc_property_name);
13960Sstevel@tonic-gate 			return (0);
13970Sstevel@tonic-gate 		}
13980Sstevel@tonic-gate 
13990Sstevel@tonic-gate 		v1 = uu_list_next(p1->sc_property_values, v1);
14000Sstevel@tonic-gate 		v2 = uu_list_next(p2->sc_property_values, v2);
14010Sstevel@tonic-gate 	}
14020Sstevel@tonic-gate 
14030Sstevel@tonic-gate 	return (1);
14040Sstevel@tonic-gate }
14050Sstevel@tonic-gate 
14060Sstevel@tonic-gate int
pg_attrs_equal(const pgroup_t * pg1,const pgroup_t * pg2,const char * fmri,int new)1407306Sbustos pg_attrs_equal(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri,
1408306Sbustos     int new)
14090Sstevel@tonic-gate {
14100Sstevel@tonic-gate 	if (strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) != 0) {
14110Sstevel@tonic-gate 		assert(fmri == NULL);
14120Sstevel@tonic-gate 		return (0);
14130Sstevel@tonic-gate 	}
14140Sstevel@tonic-gate 
14150Sstevel@tonic-gate 	if (pg1->sc_pgroup_flags != pg2->sc_pgroup_flags) {
14160Sstevel@tonic-gate 		if (fmri) {
14170Sstevel@tonic-gate 			if (new)
14180Sstevel@tonic-gate 				warn(gettext("Conflict upgrading %s "
14190Sstevel@tonic-gate 				    "(new property group \"%s\" has different "
14200Sstevel@tonic-gate 				    "flags).\n"), fmri, pg1->sc_pgroup_name);
14210Sstevel@tonic-gate 			else
14220Sstevel@tonic-gate 				warn(gettext("Conflict upgrading %s "
14230Sstevel@tonic-gate 				    "(property group \"%s\" has different "
14240Sstevel@tonic-gate 				    "flags).\n"), fmri, pg1->sc_pgroup_name);
14250Sstevel@tonic-gate 		}
14260Sstevel@tonic-gate 		return (0);
14270Sstevel@tonic-gate 	}
14280Sstevel@tonic-gate 
14290Sstevel@tonic-gate 	if (strcmp(pg1->sc_pgroup_type, pg2->sc_pgroup_type) != 0) {
14300Sstevel@tonic-gate 		if (fmri) {
14310Sstevel@tonic-gate 			if (new)
14320Sstevel@tonic-gate 				warn(gettext("Conflict upgrading %s "
14330Sstevel@tonic-gate 				    "(new property group \"%s\" has different "
14340Sstevel@tonic-gate 				    "type).\n"), fmri, pg1->sc_pgroup_name);
14350Sstevel@tonic-gate 			else
14360Sstevel@tonic-gate 				warn(gettext("Conflict upgrading %s "
14370Sstevel@tonic-gate 				    "(property group \"%s\" has different "
14380Sstevel@tonic-gate 				    "type).\n"), fmri, pg1->sc_pgroup_name);
14390Sstevel@tonic-gate 		}
14400Sstevel@tonic-gate 		return (0);
14410Sstevel@tonic-gate 	}
14420Sstevel@tonic-gate 
14430Sstevel@tonic-gate 	return (1);
14440Sstevel@tonic-gate }
14450Sstevel@tonic-gate 
14460Sstevel@tonic-gate int
pg_equal(pgroup_t * pg1,pgroup_t * pg2)14470Sstevel@tonic-gate pg_equal(pgroup_t *pg1, pgroup_t *pg2)
14480Sstevel@tonic-gate {
14490Sstevel@tonic-gate 	property_t *p1, *p2;
14500Sstevel@tonic-gate 
14510Sstevel@tonic-gate 	if (!pg_attrs_equal(pg1, pg2, NULL, 0))
14520Sstevel@tonic-gate 		return (0);
14530Sstevel@tonic-gate 
14540Sstevel@tonic-gate 	if (uu_list_numnodes(pg1->sc_pgroup_props) !=
14550Sstevel@tonic-gate 	    uu_list_numnodes(pg2->sc_pgroup_props))
14560Sstevel@tonic-gate 		return (0);
14570Sstevel@tonic-gate 
14580Sstevel@tonic-gate 	p1 = uu_list_first(pg1->sc_pgroup_props);
14590Sstevel@tonic-gate 	p2 = uu_list_first(pg2->sc_pgroup_props);
14600Sstevel@tonic-gate 
14610Sstevel@tonic-gate 	while (p1 != NULL) {
14620Sstevel@tonic-gate 		assert(p2 != NULL);
14630Sstevel@tonic-gate 
14640Sstevel@tonic-gate 		if (!prop_equal(p1, p2, NULL, NULL, 0))
14650Sstevel@tonic-gate 			return (0);
14660Sstevel@tonic-gate 
14670Sstevel@tonic-gate 		p1 = uu_list_next(pg1->sc_pgroup_props, p1);
14680Sstevel@tonic-gate 		p2 = uu_list_next(pg2->sc_pgroup_props, p2);
14690Sstevel@tonic-gate 	}
14700Sstevel@tonic-gate 
14710Sstevel@tonic-gate 	return (1);
14720Sstevel@tonic-gate }
1473