xref: /onnv-gate/usr/src/cmd/svc/svccfg/svccfg_internal.c (revision 7128:66d3ca036e07)
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*7128Samaguire  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include <assert.h>
300Sstevel@tonic-gate #include <errno.h>
310Sstevel@tonic-gate #include <libintl.h>
320Sstevel@tonic-gate #include <libuutil.h>
330Sstevel@tonic-gate #include <stdarg.h>
340Sstevel@tonic-gate #include <stddef.h>
350Sstevel@tonic-gate #include <string.h>
360Sstevel@tonic-gate 
370Sstevel@tonic-gate #include "svccfg.h"
380Sstevel@tonic-gate 
390Sstevel@tonic-gate /*
400Sstevel@tonic-gate  * Internal representation manipulation routines for svccfg(1)
410Sstevel@tonic-gate  */
420Sstevel@tonic-gate 
430Sstevel@tonic-gate static uu_list_pool_t	*entity_pool;
440Sstevel@tonic-gate static uu_list_pool_t	*pgroup_pool;
450Sstevel@tonic-gate static uu_list_pool_t	*property_pool;
460Sstevel@tonic-gate static uu_list_pool_t	*value_pool;
470Sstevel@tonic-gate 
480Sstevel@tonic-gate /* ARGSUSED */
490Sstevel@tonic-gate static int
500Sstevel@tonic-gate entity_cmp(const void *a, const void *b, void *p)
510Sstevel@tonic-gate {
520Sstevel@tonic-gate 	entity_t *A = (entity_t *)a;
530Sstevel@tonic-gate 	entity_t *B = (entity_t *)b;
540Sstevel@tonic-gate 
550Sstevel@tonic-gate 	return (strcmp(A->sc_name, B->sc_name));
560Sstevel@tonic-gate }
570Sstevel@tonic-gate 
580Sstevel@tonic-gate /*ARGSUSED*/
590Sstevel@tonic-gate static int
600Sstevel@tonic-gate pgroup_cmp(const void *a, const void *b, void *p)
610Sstevel@tonic-gate {
620Sstevel@tonic-gate 	pgroup_t *A = (pgroup_t *)a;
630Sstevel@tonic-gate 	pgroup_t *B = (pgroup_t *)b;
640Sstevel@tonic-gate 
650Sstevel@tonic-gate 	return (strcmp(A->sc_pgroup_name, B->sc_pgroup_name));
660Sstevel@tonic-gate }
670Sstevel@tonic-gate 
680Sstevel@tonic-gate /* ARGSUSED */
690Sstevel@tonic-gate static int
700Sstevel@tonic-gate property_cmp(const void *a, const void *b, void *p)
710Sstevel@tonic-gate {
720Sstevel@tonic-gate 	property_t *A = (property_t *)a;
730Sstevel@tonic-gate 	property_t *B = (property_t *)b;
740Sstevel@tonic-gate 
750Sstevel@tonic-gate 	return (strcmp(A->sc_property_name, B->sc_property_name));
760Sstevel@tonic-gate }
770Sstevel@tonic-gate 
780Sstevel@tonic-gate /* ARGSUSED */
790Sstevel@tonic-gate int
800Sstevel@tonic-gate value_cmp(const void *a, const void *b, void *p)
810Sstevel@tonic-gate {
820Sstevel@tonic-gate 	const value_t *A = a;
830Sstevel@tonic-gate 	const value_t *B = b;
840Sstevel@tonic-gate 
850Sstevel@tonic-gate 	if (A->sc_type != B->sc_type)
860Sstevel@tonic-gate 		return (B->sc_type - A->sc_type);
870Sstevel@tonic-gate 
880Sstevel@tonic-gate 	switch (A->sc_type) {
890Sstevel@tonic-gate 	case SCF_TYPE_BOOLEAN:
900Sstevel@tonic-gate 	case SCF_TYPE_COUNT:
910Sstevel@tonic-gate 		return (B->sc_u.sc_count - A->sc_u.sc_count);
920Sstevel@tonic-gate 
930Sstevel@tonic-gate 	case SCF_TYPE_INTEGER:
940Sstevel@tonic-gate 		return (B->sc_u.sc_integer - A->sc_u.sc_integer);
950Sstevel@tonic-gate 
960Sstevel@tonic-gate 	default:
970Sstevel@tonic-gate 		return (strcmp(A->sc_u.sc_string, B->sc_u.sc_string));
980Sstevel@tonic-gate 	}
990Sstevel@tonic-gate }
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate void
1020Sstevel@tonic-gate internal_init()
1030Sstevel@tonic-gate {
1040Sstevel@tonic-gate 	if ((entity_pool = uu_list_pool_create("entities", sizeof (entity_t),
1050Sstevel@tonic-gate 	    offsetof(entity_t, sc_node), entity_cmp, 0)) == NULL)
1060Sstevel@tonic-gate 		uu_die(gettext("entity list pool creation failed: %s\n"),
1070Sstevel@tonic-gate 		    uu_strerror(uu_error()));
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate 	if ((pgroup_pool = uu_list_pool_create("property_groups",
1100Sstevel@tonic-gate 	    sizeof (pgroup_t), offsetof(pgroup_t, sc_node), pgroup_cmp, 0)) ==
1110Sstevel@tonic-gate 	    NULL)
1120Sstevel@tonic-gate 		uu_die(
1130Sstevel@tonic-gate 		    gettext("property group list pool creation failed: %s\n"),
1140Sstevel@tonic-gate 		    uu_strerror(uu_error()));
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate 	if ((property_pool = uu_list_pool_create("properties",
1170Sstevel@tonic-gate 	    sizeof (property_t), offsetof(property_t, sc_node), property_cmp,
1180Sstevel@tonic-gate 	    0)) == NULL)
1190Sstevel@tonic-gate 		uu_die(gettext("property list pool creation failed: %s\n"),
1200Sstevel@tonic-gate 		    uu_strerror(uu_error()));
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate 	if ((value_pool = uu_list_pool_create("property_values",
1230Sstevel@tonic-gate 	    sizeof (value_t), offsetof(value_t, sc_node), value_cmp, 0)) ==
1240Sstevel@tonic-gate 	    NULL)
1250Sstevel@tonic-gate 		uu_die(
1260Sstevel@tonic-gate 		    gettext("property value list pool creation failed: %s\n"),
1270Sstevel@tonic-gate 		    uu_strerror(uu_error()));
1280Sstevel@tonic-gate }
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate /*ARGSUSED*/
1310Sstevel@tonic-gate static int
1320Sstevel@tonic-gate internal_value_dump(void *v, void *pvt)
1330Sstevel@tonic-gate {
1340Sstevel@tonic-gate 	value_t *val = v;
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate 	switch (val->sc_type) {
1370Sstevel@tonic-gate 	case SCF_TYPE_BOOLEAN:
1380Sstevel@tonic-gate 		(void) printf("	value = %s\n",
1390Sstevel@tonic-gate 		    val->sc_u.sc_count ? "true" : "false");
1400Sstevel@tonic-gate 		break;
1410Sstevel@tonic-gate 	case SCF_TYPE_COUNT:
1420Sstevel@tonic-gate 		(void) printf("	value = %llu\n", val->sc_u.sc_count);
1430Sstevel@tonic-gate 		break;
1440Sstevel@tonic-gate 	case SCF_TYPE_INTEGER:
1450Sstevel@tonic-gate 		(void) printf("	value = %lld\n", val->sc_u.sc_integer);
1460Sstevel@tonic-gate 		break;
1470Sstevel@tonic-gate 	case SCF_TYPE_ASTRING:
1480Sstevel@tonic-gate 	case SCF_TYPE_FMRI:
1490Sstevel@tonic-gate 	case SCF_TYPE_HOST:
1500Sstevel@tonic-gate 	case SCF_TYPE_HOSTNAME:
1510Sstevel@tonic-gate 	case SCF_TYPE_NET_ADDR_V4:
1520Sstevel@tonic-gate 	case SCF_TYPE_NET_ADDR_V6:
1530Sstevel@tonic-gate 	case SCF_TYPE_OPAQUE:
1540Sstevel@tonic-gate 	case SCF_TYPE_TIME:
1550Sstevel@tonic-gate 	case SCF_TYPE_URI:
1560Sstevel@tonic-gate 	case SCF_TYPE_USTRING:
1570Sstevel@tonic-gate 		(void) printf("	value = %s\n",
1580Sstevel@tonic-gate 		    val->sc_u.sc_string ? val->sc_u.sc_string : "(nil)");
1590Sstevel@tonic-gate 		break;
1600Sstevel@tonic-gate 	default:
1610Sstevel@tonic-gate 		uu_die(gettext("unknown value type (%d)\n"), val->sc_type);
1620Sstevel@tonic-gate 		break;
1630Sstevel@tonic-gate 	}
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate 	return (UU_WALK_NEXT);
1660Sstevel@tonic-gate }
1670Sstevel@tonic-gate 
1680Sstevel@tonic-gate /*ARGSUSED*/
1690Sstevel@tonic-gate static int
1700Sstevel@tonic-gate internal_property_dump(void *v, void *pvt)
1710Sstevel@tonic-gate {
1720Sstevel@tonic-gate 	property_t *p = v;
1730Sstevel@tonic-gate 
1740Sstevel@tonic-gate 	(void) printf("property\n	name = %s\n", p->sc_property_name);
1750Sstevel@tonic-gate 	(void) printf("	type = %d\n", p->sc_value_type);
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate 	(void) uu_list_walk(p->sc_property_values, internal_value_dump,
1780Sstevel@tonic-gate 	    NULL, UU_DEFAULT);
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate 	return (UU_WALK_NEXT);
1810Sstevel@tonic-gate }
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate /*ARGSUSED*/
1840Sstevel@tonic-gate static int
1850Sstevel@tonic-gate internal_pgroup_dump(void *v, void *pvt)
1860Sstevel@tonic-gate {
1870Sstevel@tonic-gate 	pgroup_t *pg = v;
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate 	(void) printf("pgroup	name = %s\n", pg->sc_pgroup_name);
1900Sstevel@tonic-gate 	(void) printf("	type = %s\n", pg->sc_pgroup_type);
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate 	(void) uu_list_walk(pg->sc_pgroup_props, internal_property_dump,
1930Sstevel@tonic-gate 	    NULL, UU_DEFAULT);
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate 	return (UU_WALK_NEXT);
1960Sstevel@tonic-gate }
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate /*ARGSUSED*/
1990Sstevel@tonic-gate static int
2000Sstevel@tonic-gate internal_instance_dump(void *v, void *pvt)
2010Sstevel@tonic-gate {
2020Sstevel@tonic-gate 	entity_t *i = v;
2030Sstevel@tonic-gate 
2040Sstevel@tonic-gate 	(void) printf("instance	name = %s\n", i->sc_name);
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate 	(void) uu_list_walk(i->sc_pgroups, internal_pgroup_dump, NULL,
2070Sstevel@tonic-gate 	    UU_DEFAULT);
2080Sstevel@tonic-gate 
2090Sstevel@tonic-gate 	return (UU_WALK_NEXT);
2100Sstevel@tonic-gate }
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate /*ARGSUSED*/
2130Sstevel@tonic-gate static int
2140Sstevel@tonic-gate internal_service_dump(void *v, void *pvt)
2150Sstevel@tonic-gate {
2160Sstevel@tonic-gate 	entity_t *s = v;
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate 	(void) printf("service	name = %s\n", s->sc_name);
2190Sstevel@tonic-gate 	(void) printf("	type = %x\n", s->sc_u.sc_service.sc_service_type);
2200Sstevel@tonic-gate 	(void) printf("	version = %u\n", s->sc_u.sc_service.sc_service_version);
2210Sstevel@tonic-gate 
2220Sstevel@tonic-gate 	(void) uu_list_walk(s->sc_pgroups, internal_pgroup_dump, NULL,
2230Sstevel@tonic-gate 	    UU_DEFAULT);
2240Sstevel@tonic-gate 
2250Sstevel@tonic-gate 	(void) uu_list_walk(s->sc_u.sc_service.sc_service_instances,
2260Sstevel@tonic-gate 	    internal_instance_dump, NULL, UU_DEFAULT);
2270Sstevel@tonic-gate 
2280Sstevel@tonic-gate 	return (UU_WALK_NEXT);
2290Sstevel@tonic-gate }
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate void
2320Sstevel@tonic-gate internal_dump(bundle_t *b)
2330Sstevel@tonic-gate {
2340Sstevel@tonic-gate 	(void) printf("bundle	name = %s\n", b->sc_bundle_name);
2350Sstevel@tonic-gate 	(void) printf("	type = %x\n", b->sc_bundle_type);
2360Sstevel@tonic-gate 
2370Sstevel@tonic-gate 	(void) uu_list_walk(b->sc_bundle_services, internal_service_dump,
2380Sstevel@tonic-gate 	    NULL, UU_DEFAULT);
2390Sstevel@tonic-gate }
2400Sstevel@tonic-gate 
2410Sstevel@tonic-gate bundle_t *
2420Sstevel@tonic-gate internal_bundle_new()
2430Sstevel@tonic-gate {
2440Sstevel@tonic-gate 	bundle_t	*b;
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate 	if ((b = uu_zalloc(sizeof (bundle_t))) == NULL)
2470Sstevel@tonic-gate 		uu_die(gettext("couldn't allocate memory"));
2480Sstevel@tonic-gate 
2490Sstevel@tonic-gate 	b->sc_bundle_type = SVCCFG_UNKNOWN_BUNDLE;
2500Sstevel@tonic-gate 	b->sc_bundle_services = uu_list_create(entity_pool, b, 0);
2510Sstevel@tonic-gate 
2520Sstevel@tonic-gate 	return (b);
2530Sstevel@tonic-gate }
2540Sstevel@tonic-gate 
2550Sstevel@tonic-gate void
2560Sstevel@tonic-gate internal_bundle_free(bundle_t *b)
2570Sstevel@tonic-gate {
2580Sstevel@tonic-gate 	void *cookie = NULL;
2590Sstevel@tonic-gate 	entity_t *service;
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate 	while ((service = uu_list_teardown(b->sc_bundle_services, &cookie)) !=
2620Sstevel@tonic-gate 	    NULL)
2630Sstevel@tonic-gate 		internal_service_free(service);
2640Sstevel@tonic-gate 
2650Sstevel@tonic-gate 	free(b);
2660Sstevel@tonic-gate }
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate entity_t *
2690Sstevel@tonic-gate internal_service_new(const char *name)
2700Sstevel@tonic-gate {
2710Sstevel@tonic-gate 	entity_t *s;
2720Sstevel@tonic-gate 
2730Sstevel@tonic-gate 	if ((s = uu_zalloc(sizeof (entity_t))) == NULL)
2740Sstevel@tonic-gate 		uu_die(gettext("couldn't allocate memory"));
2750Sstevel@tonic-gate 
2760Sstevel@tonic-gate 	uu_list_node_init(s, &s->sc_node, entity_pool);
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate 	s->sc_name = name;
2790Sstevel@tonic-gate 	s->sc_fmri = uu_msprintf("svc:/%s", name);
2800Sstevel@tonic-gate 	if (s->sc_fmri == NULL)
2810Sstevel@tonic-gate 		uu_die(gettext("couldn't allocate memory"));
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate 	s->sc_etype = SVCCFG_SERVICE_OBJECT;
2840Sstevel@tonic-gate 	s->sc_pgroups = uu_list_create(pgroup_pool, s, 0);
2850Sstevel@tonic-gate 	s->sc_dependents = uu_list_create(pgroup_pool, s, 0);
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate 	s->sc_u.sc_service.sc_service_type = SVCCFG_UNKNOWN_SERVICE;
2880Sstevel@tonic-gate 	s->sc_u.sc_service.sc_service_instances = uu_list_create(entity_pool, s,
2890Sstevel@tonic-gate 	    0);
2900Sstevel@tonic-gate 
2910Sstevel@tonic-gate 	return (s);
2920Sstevel@tonic-gate }
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate void
2950Sstevel@tonic-gate internal_service_free(entity_t *s)
2960Sstevel@tonic-gate {
2970Sstevel@tonic-gate 	entity_t *inst;
2980Sstevel@tonic-gate 	pgroup_t *pg;
2990Sstevel@tonic-gate 	void *cookie;
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate 	cookie = NULL;
3020Sstevel@tonic-gate 	while ((pg = uu_list_teardown(s->sc_pgroups, &cookie)) != NULL)
3030Sstevel@tonic-gate 		internal_pgroup_free(pg);
3040Sstevel@tonic-gate 
3050Sstevel@tonic-gate 	cookie = NULL;
3060Sstevel@tonic-gate 	while ((pg = uu_list_teardown(s->sc_dependents, &cookie)) != NULL)
3070Sstevel@tonic-gate 		internal_pgroup_free(pg);
3080Sstevel@tonic-gate 
3090Sstevel@tonic-gate 	cookie = NULL;
3100Sstevel@tonic-gate 	while ((inst = uu_list_teardown(s->sc_u.sc_service.sc_service_instances,
3110Sstevel@tonic-gate 	    &cookie)) != NULL)
3120Sstevel@tonic-gate 		internal_instance_free(inst);
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate 	free(s);
3150Sstevel@tonic-gate }
3160Sstevel@tonic-gate 
3170Sstevel@tonic-gate entity_t *
3180Sstevel@tonic-gate internal_instance_new(const char *name)
3190Sstevel@tonic-gate {
3200Sstevel@tonic-gate 	entity_t *i;
3210Sstevel@tonic-gate 
3220Sstevel@tonic-gate 	if ((i = uu_zalloc(sizeof (entity_t))) == NULL)
3230Sstevel@tonic-gate 		uu_die(gettext("couldn't allocate memory"));
3240Sstevel@tonic-gate 
3250Sstevel@tonic-gate 	uu_list_node_init(i, &i->sc_node, entity_pool);
3260Sstevel@tonic-gate 
3270Sstevel@tonic-gate 	i->sc_name = name;
3280Sstevel@tonic-gate 	/* Can't set i->sc_fmri until we're attached to a service. */
3290Sstevel@tonic-gate 	i->sc_etype = SVCCFG_INSTANCE_OBJECT;
3300Sstevel@tonic-gate 	i->sc_pgroups = uu_list_create(pgroup_pool, i, 0);
3310Sstevel@tonic-gate 	i->sc_dependents = uu_list_create(pgroup_pool, i, 0);
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate 	return (i);
3340Sstevel@tonic-gate }
3350Sstevel@tonic-gate 
3360Sstevel@tonic-gate void
3370Sstevel@tonic-gate internal_instance_free(entity_t *i)
3380Sstevel@tonic-gate {
3390Sstevel@tonic-gate 	pgroup_t *pg;
3400Sstevel@tonic-gate 	void *cookie = NULL;
3410Sstevel@tonic-gate 
3420Sstevel@tonic-gate 	while ((pg = uu_list_teardown(i->sc_pgroups, &cookie)) != NULL)
3430Sstevel@tonic-gate 		internal_pgroup_free(pg);
3440Sstevel@tonic-gate 
3450Sstevel@tonic-gate 	cookie = NULL;
3460Sstevel@tonic-gate 	while ((pg = uu_list_teardown(i->sc_dependents, &cookie)) != NULL)
3470Sstevel@tonic-gate 		internal_pgroup_free(pg);
3480Sstevel@tonic-gate 
3490Sstevel@tonic-gate 	free(i);
3500Sstevel@tonic-gate }
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate entity_t *
3530Sstevel@tonic-gate internal_template_new()
3540Sstevel@tonic-gate {
3550Sstevel@tonic-gate 	entity_t *t;
3560Sstevel@tonic-gate 
3570Sstevel@tonic-gate 	if ((t = uu_zalloc(sizeof (entity_t))) == NULL)
3580Sstevel@tonic-gate 		uu_die(gettext("couldn't allocate memory"));
3590Sstevel@tonic-gate 
3600Sstevel@tonic-gate 	uu_list_node_init(t, &t->sc_node, entity_pool);
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate 	t->sc_etype = SVCCFG_TEMPLATE_OBJECT;
3630Sstevel@tonic-gate 	t->sc_pgroups = uu_list_create(pgroup_pool, t, 0);
3640Sstevel@tonic-gate 
3650Sstevel@tonic-gate 	return (t);
3660Sstevel@tonic-gate }
3670Sstevel@tonic-gate 
3680Sstevel@tonic-gate pgroup_t *
3690Sstevel@tonic-gate internal_pgroup_new()
3700Sstevel@tonic-gate {
3710Sstevel@tonic-gate 	pgroup_t *p;
3720Sstevel@tonic-gate 
3730Sstevel@tonic-gate 	if ((p = uu_zalloc(sizeof (pgroup_t))) == NULL)
3740Sstevel@tonic-gate 		uu_die(gettext("couldn't allocate memory"));
3750Sstevel@tonic-gate 
3760Sstevel@tonic-gate 	uu_list_node_init(p, &p->sc_node, pgroup_pool);
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate 	p->sc_pgroup_props = uu_list_create(property_pool, p, UU_LIST_SORTED);
3790Sstevel@tonic-gate 	p->sc_pgroup_name = "<unset>";
3800Sstevel@tonic-gate 	p->sc_pgroup_type = "<unset>";
3810Sstevel@tonic-gate 
3820Sstevel@tonic-gate 	return (p);
3830Sstevel@tonic-gate }
3840Sstevel@tonic-gate 
3850Sstevel@tonic-gate void
3860Sstevel@tonic-gate internal_pgroup_free(pgroup_t *pg)
3870Sstevel@tonic-gate {
3880Sstevel@tonic-gate 	property_t *prop;
3890Sstevel@tonic-gate 	void *cookie = NULL;
3900Sstevel@tonic-gate 
3910Sstevel@tonic-gate 	while ((prop = uu_list_teardown(pg->sc_pgroup_props, &cookie)) != NULL)
3920Sstevel@tonic-gate 		internal_property_free(prop);
3930Sstevel@tonic-gate 
394306Sbustos 	uu_free(pg);
3950Sstevel@tonic-gate }
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate static pgroup_t *
3980Sstevel@tonic-gate find_pgroup(uu_list_t *list, const char *name, const char *type)
3990Sstevel@tonic-gate {
4000Sstevel@tonic-gate 	pgroup_t *pg;
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate 	for (pg = uu_list_first(list);
4030Sstevel@tonic-gate 	    pg != NULL;
4040Sstevel@tonic-gate 	    pg = uu_list_next(list, pg)) {
4050Sstevel@tonic-gate 		if (strcmp(pg->sc_pgroup_name, name) != 0)
4060Sstevel@tonic-gate 			continue;
4070Sstevel@tonic-gate 
4080Sstevel@tonic-gate 		if (type == NULL)
4090Sstevel@tonic-gate 			return (pg);
4100Sstevel@tonic-gate 
4110Sstevel@tonic-gate 		if (strcmp(pg->sc_pgroup_type, type) == 0)
4120Sstevel@tonic-gate 			return (pg);
4130Sstevel@tonic-gate 	}
4140Sstevel@tonic-gate 
4150Sstevel@tonic-gate 	return (NULL);
4160Sstevel@tonic-gate }
4170Sstevel@tonic-gate 
4180Sstevel@tonic-gate pgroup_t *
4190Sstevel@tonic-gate internal_dependent_find(entity_t *e, const char *name)
4200Sstevel@tonic-gate {
4210Sstevel@tonic-gate 	return (find_pgroup(e->sc_dependents, name, NULL));
4220Sstevel@tonic-gate }
4230Sstevel@tonic-gate 
4240Sstevel@tonic-gate pgroup_t *
4250Sstevel@tonic-gate internal_pgroup_find(entity_t *e, const char *name, const char *type)
4260Sstevel@tonic-gate {
4270Sstevel@tonic-gate 	return (find_pgroup(e->sc_pgroups, name, type));
4280Sstevel@tonic-gate }
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate pgroup_t *
4310Sstevel@tonic-gate internal_pgroup_find_or_create(entity_t *e, const char *name, const char *type)
4320Sstevel@tonic-gate {
4330Sstevel@tonic-gate 	pgroup_t *pg;
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate 	pg = internal_pgroup_find(e, name, type);
4360Sstevel@tonic-gate 	if (pg != NULL)
4370Sstevel@tonic-gate 		return (pg);
4380Sstevel@tonic-gate 
4390Sstevel@tonic-gate 	pg = internal_pgroup_new();
4400Sstevel@tonic-gate 	(void) internal_attach_pgroup(e, pg);
4410Sstevel@tonic-gate 	pg->sc_pgroup_name = strdup(name);
4420Sstevel@tonic-gate 	pg->sc_pgroup_type = strdup(type);
4430Sstevel@tonic-gate 	pg->sc_pgroup_flags = 0;
4440Sstevel@tonic-gate 
4450Sstevel@tonic-gate 	if (pg->sc_pgroup_name == NULL || pg->sc_pgroup_type == NULL)
4460Sstevel@tonic-gate 		uu_die(gettext("Could not duplicate string"));
4470Sstevel@tonic-gate 
4480Sstevel@tonic-gate 	return (pg);
4490Sstevel@tonic-gate }
4500Sstevel@tonic-gate 
4510Sstevel@tonic-gate property_t *
4520Sstevel@tonic-gate internal_property_new()
4530Sstevel@tonic-gate {
4540Sstevel@tonic-gate 	property_t *p;
4550Sstevel@tonic-gate 
4560Sstevel@tonic-gate 	if ((p = uu_zalloc(sizeof (property_t))) == NULL)
4570Sstevel@tonic-gate 		uu_die(gettext("couldn't allocate memory"));
4580Sstevel@tonic-gate 
4590Sstevel@tonic-gate 	uu_list_node_init(p, &p->sc_node, property_pool);
4600Sstevel@tonic-gate 
461*7128Samaguire 	p->sc_property_values = uu_list_create(value_pool, p, 0);
4620Sstevel@tonic-gate 	p->sc_property_name = "<unset>";
4630Sstevel@tonic-gate 
4640Sstevel@tonic-gate 	return (p);
4650Sstevel@tonic-gate }
4660Sstevel@tonic-gate 
4670Sstevel@tonic-gate void
4680Sstevel@tonic-gate internal_property_free(property_t *p)
4690Sstevel@tonic-gate {
4700Sstevel@tonic-gate 	value_t *val;
4710Sstevel@tonic-gate 	void *cookie = NULL;
4720Sstevel@tonic-gate 
4730Sstevel@tonic-gate 	while ((val = uu_list_teardown(p->sc_property_values, &cookie)) !=
4740Sstevel@tonic-gate 	    NULL) {
4750Sstevel@tonic-gate 		if (val->sc_free != NULL)
4760Sstevel@tonic-gate 			val->sc_free(val);
4770Sstevel@tonic-gate 		free(val);
4780Sstevel@tonic-gate 	}
4790Sstevel@tonic-gate 
4800Sstevel@tonic-gate 	free(p);
4810Sstevel@tonic-gate }
4820Sstevel@tonic-gate 
4830Sstevel@tonic-gate property_t *
4840Sstevel@tonic-gate internal_property_find(pgroup_t *pg, const char *name)
4850Sstevel@tonic-gate {
4860Sstevel@tonic-gate 	property_t *p;
4870Sstevel@tonic-gate 
4880Sstevel@tonic-gate 	for (p = uu_list_first(pg->sc_pgroup_props);
4890Sstevel@tonic-gate 	    p != NULL;
4900Sstevel@tonic-gate 	    p = uu_list_next(pg->sc_pgroup_props, p))
4910Sstevel@tonic-gate 		if (strcmp(p->sc_property_name, name) == 0)
4920Sstevel@tonic-gate 			return (p);
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate 	return (NULL);
4950Sstevel@tonic-gate }
4960Sstevel@tonic-gate 
4970Sstevel@tonic-gate value_t *
4980Sstevel@tonic-gate internal_value_new()
4990Sstevel@tonic-gate {
5000Sstevel@tonic-gate 	value_t *v;
5010Sstevel@tonic-gate 
5020Sstevel@tonic-gate 	if ((v = uu_zalloc(sizeof (value_t))) == NULL)
5030Sstevel@tonic-gate 		uu_die(gettext("couldn't allocate memory"));
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate 	uu_list_node_init(v, &v->sc_node, value_pool);
5060Sstevel@tonic-gate 
5070Sstevel@tonic-gate 	return (v);
5080Sstevel@tonic-gate }
5090Sstevel@tonic-gate 
5100Sstevel@tonic-gate static void
5110Sstevel@tonic-gate internal_value_free_str(value_t *v)
5120Sstevel@tonic-gate {
5130Sstevel@tonic-gate 	free(v->sc_u.sc_string);
5140Sstevel@tonic-gate }
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate property_t *
5170Sstevel@tonic-gate internal_property_create(const char *name, scf_type_t vtype, uint_t nvals, ...)
5180Sstevel@tonic-gate {
5190Sstevel@tonic-gate 	va_list args;
5200Sstevel@tonic-gate 	property_t *p;
5210Sstevel@tonic-gate 	value_t *v;
5220Sstevel@tonic-gate 
5230Sstevel@tonic-gate 	p = internal_property_new();
5240Sstevel@tonic-gate 
5250Sstevel@tonic-gate 	p->sc_property_name = (char *)name;
5260Sstevel@tonic-gate 	p->sc_value_type = vtype;
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate 	va_start(args, nvals);
5290Sstevel@tonic-gate 	for (; nvals > 0; nvals--) {
5300Sstevel@tonic-gate 
5310Sstevel@tonic-gate 		v = internal_value_new();
5320Sstevel@tonic-gate 		v->sc_type = vtype;
5330Sstevel@tonic-gate 
5340Sstevel@tonic-gate 		switch (vtype) {
5350Sstevel@tonic-gate 		case SCF_TYPE_BOOLEAN:
5360Sstevel@tonic-gate 		case SCF_TYPE_COUNT:
5370Sstevel@tonic-gate 			v->sc_u.sc_count = va_arg(args, uint64_t);
5380Sstevel@tonic-gate 			break;
5390Sstevel@tonic-gate 		case SCF_TYPE_INTEGER:
5400Sstevel@tonic-gate 			v->sc_u.sc_integer = va_arg(args, int64_t);
5410Sstevel@tonic-gate 			break;
5420Sstevel@tonic-gate 		case SCF_TYPE_ASTRING:
5430Sstevel@tonic-gate 		case SCF_TYPE_FMRI:
5440Sstevel@tonic-gate 		case SCF_TYPE_HOST:
5450Sstevel@tonic-gate 		case SCF_TYPE_HOSTNAME:
5460Sstevel@tonic-gate 		case SCF_TYPE_NET_ADDR_V4:
5470Sstevel@tonic-gate 		case SCF_TYPE_NET_ADDR_V6:
5480Sstevel@tonic-gate 		case SCF_TYPE_OPAQUE:
5490Sstevel@tonic-gate 		case SCF_TYPE_TIME:
5500Sstevel@tonic-gate 		case SCF_TYPE_URI:
5510Sstevel@tonic-gate 		case SCF_TYPE_USTRING:
5520Sstevel@tonic-gate 			v->sc_u.sc_string = (char *)va_arg(args, uchar_t *);
5530Sstevel@tonic-gate 			break;
5540Sstevel@tonic-gate 		default:
5550Sstevel@tonic-gate 			va_end(args);
5560Sstevel@tonic-gate 			uu_die(gettext("unknown property type (%d)\n"), vtype);
5570Sstevel@tonic-gate 			break;
5580Sstevel@tonic-gate 		}
5590Sstevel@tonic-gate 
5600Sstevel@tonic-gate 		internal_attach_value(p, v);
5610Sstevel@tonic-gate 	}
5620Sstevel@tonic-gate 	va_end(args);
5630Sstevel@tonic-gate 
5640Sstevel@tonic-gate 	return (p);
5650Sstevel@tonic-gate }
5660Sstevel@tonic-gate 
5670Sstevel@tonic-gate /*
5680Sstevel@tonic-gate  * Some of these attach functions use uu_list_append() to maintain the
5690Sstevel@tonic-gate  * same order across import/export, whereas others are always sorted
5700Sstevel@tonic-gate  * anyway, or the order is irrelevant.
5710Sstevel@tonic-gate  */
5720Sstevel@tonic-gate 
5730Sstevel@tonic-gate int
5740Sstevel@tonic-gate internal_attach_service(bundle_t *bndl, entity_t *svc)
5750Sstevel@tonic-gate {
5760Sstevel@tonic-gate 	if (uu_list_find(bndl->sc_bundle_services, svc, NULL, NULL) != NULL) {
5770Sstevel@tonic-gate 		semerr(gettext("Multiple definitions for service %s in "
5780Sstevel@tonic-gate 		    "bundle %s.\n"), svc->sc_name, bndl->sc_bundle_name);
5790Sstevel@tonic-gate 		return (-1);
5800Sstevel@tonic-gate 	}
5810Sstevel@tonic-gate 
5820Sstevel@tonic-gate 	(void) uu_list_append(bndl->sc_bundle_services, svc);
5830Sstevel@tonic-gate 
5840Sstevel@tonic-gate 	return (0);
5850Sstevel@tonic-gate }
5860Sstevel@tonic-gate 
5870Sstevel@tonic-gate int
5880Sstevel@tonic-gate internal_attach_entity(entity_t *svc, entity_t *ent)
5890Sstevel@tonic-gate {
5900Sstevel@tonic-gate 	if (ent->sc_etype == SVCCFG_TEMPLATE_OBJECT) {
5910Sstevel@tonic-gate 		svc->sc_u.sc_service.sc_service_template = ent;
5920Sstevel@tonic-gate 		return (0);
5930Sstevel@tonic-gate 	}
5940Sstevel@tonic-gate 
5950Sstevel@tonic-gate 	if (svc->sc_etype != SVCCFG_SERVICE_OBJECT)
5960Sstevel@tonic-gate 		uu_die(gettext("bad entity attach: %s is not a service\n"),
5970Sstevel@tonic-gate 		    svc->sc_name);
5980Sstevel@tonic-gate 
5990Sstevel@tonic-gate 	if (uu_list_find(svc->sc_u.sc_service.sc_service_instances, ent, NULL,
6000Sstevel@tonic-gate 	    NULL) != NULL) {
6010Sstevel@tonic-gate 		semerr(gettext("Multiple definitions of entity %s in service "
6020Sstevel@tonic-gate 		    "%s.\n"), ent->sc_name, svc->sc_name);
6030Sstevel@tonic-gate 		return (-1);
6040Sstevel@tonic-gate 	}
6050Sstevel@tonic-gate 
6060Sstevel@tonic-gate 	(void) uu_list_prepend(svc->sc_u.sc_service.sc_service_instances, ent);
6070Sstevel@tonic-gate 	ent->sc_parent = svc;
6080Sstevel@tonic-gate 	ent->sc_fmri = uu_msprintf("%s:%s", svc->sc_fmri, ent->sc_name);
6090Sstevel@tonic-gate 	if (ent->sc_fmri == NULL)
6100Sstevel@tonic-gate 		uu_die(gettext("couldn't allocate memory"));
6110Sstevel@tonic-gate 
6120Sstevel@tonic-gate 	return (0);
6130Sstevel@tonic-gate }
6140Sstevel@tonic-gate 
6150Sstevel@tonic-gate int
6160Sstevel@tonic-gate internal_attach_pgroup(entity_t *ent, pgroup_t *pgrp)
6170Sstevel@tonic-gate {
6180Sstevel@tonic-gate 	if (uu_list_find(ent->sc_pgroups, pgrp, NULL, NULL) != NULL) {
6190Sstevel@tonic-gate 		semerr(gettext("Multiple definitions of property group %s in "
6200Sstevel@tonic-gate 		    "entity %s.\n"), pgrp->sc_pgroup_name, ent->sc_name);
6210Sstevel@tonic-gate 		return (-1);
6220Sstevel@tonic-gate 	}
6230Sstevel@tonic-gate 
6240Sstevel@tonic-gate 	(void) uu_list_append(ent->sc_pgroups, pgrp);
6250Sstevel@tonic-gate 
6260Sstevel@tonic-gate 	pgrp->sc_parent = ent;
6270Sstevel@tonic-gate 
6280Sstevel@tonic-gate 	return (0);
6290Sstevel@tonic-gate }
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate int
6320Sstevel@tonic-gate internal_attach_dependent(entity_t *ent, pgroup_t *pg)
6330Sstevel@tonic-gate {
6340Sstevel@tonic-gate 	if (uu_list_find(ent->sc_dependents, pg, NULL, NULL) != NULL) {
6350Sstevel@tonic-gate 		semerr(gettext("Multiple definitions of dependent %s in "
6360Sstevel@tonic-gate 		    "entity %s.\n"), pg->sc_pgroup_name, ent->sc_name);
6370Sstevel@tonic-gate 		return (-1);
6380Sstevel@tonic-gate 	}
6390Sstevel@tonic-gate 
6400Sstevel@tonic-gate 	(void) uu_list_append(ent->sc_dependents, pg);
6410Sstevel@tonic-gate 
6420Sstevel@tonic-gate 	pg->sc_parent = ent;
6430Sstevel@tonic-gate 
6440Sstevel@tonic-gate 	return (0);
6450Sstevel@tonic-gate }
6460Sstevel@tonic-gate 
6470Sstevel@tonic-gate /*
6480Sstevel@tonic-gate  * Returns
6490Sstevel@tonic-gate  *   0 - success
6500Sstevel@tonic-gate  *   -1 - prop already exists in pgrp
6510Sstevel@tonic-gate  */
6520Sstevel@tonic-gate int
6530Sstevel@tonic-gate internal_attach_property(pgroup_t *pgrp, property_t *prop)
6540Sstevel@tonic-gate {
6550Sstevel@tonic-gate 	uu_list_index_t idx;
6560Sstevel@tonic-gate 
6570Sstevel@tonic-gate 	if (uu_list_find(pgrp->sc_pgroup_props, prop, NULL, &idx) != NULL) {
6580Sstevel@tonic-gate 		semerr(gettext("Multiple definitions for property %s in "
6590Sstevel@tonic-gate 		    "property group %s.\n"), prop->sc_property_name,
6600Sstevel@tonic-gate 		    pgrp->sc_pgroup_name);
6610Sstevel@tonic-gate 		return (-1);
6620Sstevel@tonic-gate 	}
6630Sstevel@tonic-gate 
6640Sstevel@tonic-gate 	uu_list_insert(pgrp->sc_pgroup_props, prop, idx);
6650Sstevel@tonic-gate 
6660Sstevel@tonic-gate 	return (0);
6670Sstevel@tonic-gate }
6680Sstevel@tonic-gate 
6690Sstevel@tonic-gate void
6700Sstevel@tonic-gate internal_attach_value(property_t *prop, value_t *val)
6710Sstevel@tonic-gate {
672*7128Samaguire 	(void) uu_list_append(prop->sc_property_values, val);
6730Sstevel@tonic-gate }
6740Sstevel@tonic-gate 
6750Sstevel@tonic-gate /*
6760Sstevel@tonic-gate  * These functions create an internal representation of a property group
6770Sstevel@tonic-gate  * (pgroup_t) from the repository (scf_propertygroup_t).  They are used by the
6780Sstevel@tonic-gate  * import functions in svccfg_libscf.c .
6790Sstevel@tonic-gate  *
6800Sstevel@tonic-gate  * load_init() must be called first to initialize these globals, and
6810Sstevel@tonic-gate  * load_fini() should be called afterwards to destroy them.
6820Sstevel@tonic-gate  */
6830Sstevel@tonic-gate 
6840Sstevel@tonic-gate static char *loadbuf = NULL;
6850Sstevel@tonic-gate static size_t loadbuf_sz;
6860Sstevel@tonic-gate static scf_property_t *load_prop = NULL;
6870Sstevel@tonic-gate static scf_value_t *load_val = NULL;
6880Sstevel@tonic-gate static scf_iter_t *load_propiter = NULL, *load_valiter = NULL;
6890Sstevel@tonic-gate 
6900Sstevel@tonic-gate /*
6910Sstevel@tonic-gate  * Initialize the global state for the load_*() routines.
6920Sstevel@tonic-gate  * Returns
6930Sstevel@tonic-gate  *   0 - success
6940Sstevel@tonic-gate  *   ENOMEM - out of memory
6950Sstevel@tonic-gate  */
6960Sstevel@tonic-gate int
6970Sstevel@tonic-gate load_init(void)
6980Sstevel@tonic-gate {
6990Sstevel@tonic-gate 	loadbuf_sz = ((max_scf_value_len > max_scf_pg_type_len) ?
7000Sstevel@tonic-gate 	    max_scf_value_len : max_scf_pg_type_len) + 1;
7010Sstevel@tonic-gate 
7020Sstevel@tonic-gate 	loadbuf = malloc(loadbuf_sz);
7030Sstevel@tonic-gate 	if (loadbuf == NULL)
7040Sstevel@tonic-gate 		return (ENOMEM);
7050Sstevel@tonic-gate 
7060Sstevel@tonic-gate 	if ((load_prop = scf_property_create(g_hndl)) == NULL ||
7070Sstevel@tonic-gate 	    (load_val = scf_value_create(g_hndl)) == NULL ||
7080Sstevel@tonic-gate 	    (load_propiter = scf_iter_create(g_hndl)) == NULL ||
7090Sstevel@tonic-gate 	    (load_valiter = scf_iter_create(g_hndl)) == NULL) {
7100Sstevel@tonic-gate 		load_fini();
7110Sstevel@tonic-gate 		return (ENOMEM);
7120Sstevel@tonic-gate 	}
7130Sstevel@tonic-gate 
7140Sstevel@tonic-gate 	return (0);
7150Sstevel@tonic-gate }
7160Sstevel@tonic-gate 
7170Sstevel@tonic-gate void
7180Sstevel@tonic-gate load_fini(void)
7190Sstevel@tonic-gate {
7200Sstevel@tonic-gate 	scf_iter_destroy(load_propiter);
7210Sstevel@tonic-gate 	load_propiter = NULL;
7220Sstevel@tonic-gate 	scf_iter_destroy(load_valiter);
7230Sstevel@tonic-gate 	load_valiter = NULL;
7240Sstevel@tonic-gate 	scf_value_destroy(load_val);
7250Sstevel@tonic-gate 	load_val = NULL;
7260Sstevel@tonic-gate 	scf_property_destroy(load_prop);
7270Sstevel@tonic-gate 	load_prop = NULL;
7280Sstevel@tonic-gate 	free(loadbuf);
7290Sstevel@tonic-gate 	loadbuf = NULL;
7300Sstevel@tonic-gate }
7310Sstevel@tonic-gate 
7320Sstevel@tonic-gate /*
7330Sstevel@tonic-gate  * Create a property_t which represents an scf_property_t.  Returns
7340Sstevel@tonic-gate  *   0 - success
7350Sstevel@tonic-gate  *   ECANCELED - prop's pg was deleted
7360Sstevel@tonic-gate  *   ECONNABORTED - repository disconnected
7370Sstevel@tonic-gate  *   ENOMEM - out of memory
7385040Swesolows  *   EACCES - permission denied when reading property
7390Sstevel@tonic-gate  */
7400Sstevel@tonic-gate static int
7410Sstevel@tonic-gate load_property(scf_property_t *prop, property_t **ipp)
7420Sstevel@tonic-gate {
7430Sstevel@tonic-gate 	property_t *iprop;
7440Sstevel@tonic-gate 	int r;
7450Sstevel@tonic-gate 	ssize_t ssz;
7460Sstevel@tonic-gate 
7470Sstevel@tonic-gate 	/* get name */
7480Sstevel@tonic-gate 	if (scf_property_get_name(prop, loadbuf, loadbuf_sz) < 0) {
7490Sstevel@tonic-gate 		switch (scf_error()) {
7500Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
7510Sstevel@tonic-gate 			return (ECANCELED);
7520Sstevel@tonic-gate 
7530Sstevel@tonic-gate 		case SCF_ERROR_CONNECTION_BROKEN:
7540Sstevel@tonic-gate 			return (ECONNABORTED);
7550Sstevel@tonic-gate 
7560Sstevel@tonic-gate 		case SCF_ERROR_NOT_BOUND:
7570Sstevel@tonic-gate 		case SCF_ERROR_NOT_SET:
7580Sstevel@tonic-gate 		default:
7590Sstevel@tonic-gate 			bad_error("scf_property_get_name", scf_error());
7600Sstevel@tonic-gate 		}
7610Sstevel@tonic-gate 	}
7620Sstevel@tonic-gate 
7630Sstevel@tonic-gate 	iprop = internal_property_new();
7640Sstevel@tonic-gate 	iprop->sc_property_name = strdup(loadbuf);
7650Sstevel@tonic-gate 	if (iprop->sc_property_name == NULL) {
7660Sstevel@tonic-gate 		internal_property_free(iprop);
7670Sstevel@tonic-gate 		return (ENOMEM);
7680Sstevel@tonic-gate 	}
7690Sstevel@tonic-gate 
7700Sstevel@tonic-gate 	/* get type */
7710Sstevel@tonic-gate 	if (scf_property_type(prop, &iprop->sc_value_type) != 0) {
7720Sstevel@tonic-gate 		switch (scf_error()) {
7730Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
7740Sstevel@tonic-gate 			r = ECANCELED;
7750Sstevel@tonic-gate 			goto out;
7760Sstevel@tonic-gate 
7770Sstevel@tonic-gate 		case SCF_ERROR_CONNECTION_BROKEN:
7780Sstevel@tonic-gate 			r = ECONNABORTED;
7790Sstevel@tonic-gate 			goto out;
7800Sstevel@tonic-gate 
7810Sstevel@tonic-gate 		case SCF_ERROR_NOT_BOUND:
7820Sstevel@tonic-gate 		case SCF_ERROR_NOT_SET:
7830Sstevel@tonic-gate 		default:
7840Sstevel@tonic-gate 			bad_error("scf_property_type", scf_error());
7850Sstevel@tonic-gate 		}
7860Sstevel@tonic-gate 	}
7870Sstevel@tonic-gate 
7880Sstevel@tonic-gate 	/* get values */
7890Sstevel@tonic-gate 	if (scf_iter_property_values(load_valiter, prop) != 0) {
7900Sstevel@tonic-gate 		switch (scf_error()) {
7910Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
7920Sstevel@tonic-gate 			r = ECANCELED;
7930Sstevel@tonic-gate 			goto out;
7940Sstevel@tonic-gate 
7950Sstevel@tonic-gate 		case SCF_ERROR_CONNECTION_BROKEN:
7960Sstevel@tonic-gate 			r = ECONNABORTED;
7970Sstevel@tonic-gate 			goto out;
7980Sstevel@tonic-gate 
7990Sstevel@tonic-gate 		case SCF_ERROR_HANDLE_MISMATCH:
8000Sstevel@tonic-gate 		case SCF_ERROR_NOT_BOUND:
8010Sstevel@tonic-gate 		case SCF_ERROR_NOT_SET:
8020Sstevel@tonic-gate 		default:
8030Sstevel@tonic-gate 			bad_error("scf_iter_property_values", scf_error());
8040Sstevel@tonic-gate 		}
8050Sstevel@tonic-gate 	}
8060Sstevel@tonic-gate 
8070Sstevel@tonic-gate 	for (;;) {
8080Sstevel@tonic-gate 		value_t *ival;
8090Sstevel@tonic-gate 
8100Sstevel@tonic-gate 		r = scf_iter_next_value(load_valiter, load_val);
8110Sstevel@tonic-gate 		if (r == 0)
8120Sstevel@tonic-gate 			break;
8130Sstevel@tonic-gate 		if (r != 1) {
8140Sstevel@tonic-gate 			switch (scf_error()) {
8150Sstevel@tonic-gate 			case SCF_ERROR_DELETED:
8160Sstevel@tonic-gate 				r = ECANCELED;
8170Sstevel@tonic-gate 				goto out;
8180Sstevel@tonic-gate 
8190Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
8200Sstevel@tonic-gate 				r = ECONNABORTED;
8210Sstevel@tonic-gate 				goto out;
8220Sstevel@tonic-gate 
8235040Swesolows 			case SCF_ERROR_PERMISSION_DENIED:
8245040Swesolows 				r = EACCES;
8255040Swesolows 				goto out;
8265040Swesolows 
8270Sstevel@tonic-gate 			case SCF_ERROR_HANDLE_MISMATCH:
8280Sstevel@tonic-gate 			case SCF_ERROR_NOT_BOUND:
8290Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
8300Sstevel@tonic-gate 			case SCF_ERROR_INVALID_ARGUMENT:
8310Sstevel@tonic-gate 			default:
8320Sstevel@tonic-gate 				bad_error("scf_iter_next_value", scf_error());
8330Sstevel@tonic-gate 			}
8340Sstevel@tonic-gate 		}
8350Sstevel@tonic-gate 
8360Sstevel@tonic-gate 		ival = internal_value_new();
8370Sstevel@tonic-gate 		ival->sc_type = scf_value_type(load_val);
8380Sstevel@tonic-gate 		assert(ival->sc_type != SCF_TYPE_INVALID);
8390Sstevel@tonic-gate 
8400Sstevel@tonic-gate 		switch (ival->sc_type) {
8410Sstevel@tonic-gate 		case SCF_TYPE_BOOLEAN: {
8420Sstevel@tonic-gate 			uint8_t b;
8430Sstevel@tonic-gate 
8440Sstevel@tonic-gate 			r = scf_value_get_boolean(load_val, &b);
8450Sstevel@tonic-gate 			if (r != 0)
8460Sstevel@tonic-gate 				bad_error("scf_value_get_boolean", scf_error());
8470Sstevel@tonic-gate 			ival->sc_u.sc_count = b;
8480Sstevel@tonic-gate 			break;
8490Sstevel@tonic-gate 		}
8500Sstevel@tonic-gate 
8510Sstevel@tonic-gate 		case SCF_TYPE_COUNT:
8520Sstevel@tonic-gate 			r = scf_value_get_count(load_val, &ival->sc_u.sc_count);
8530Sstevel@tonic-gate 			if (r != 0)
8540Sstevel@tonic-gate 				bad_error("scf_value_get_count", scf_error());
8550Sstevel@tonic-gate 			break;
8560Sstevel@tonic-gate 
8570Sstevel@tonic-gate 		case SCF_TYPE_INTEGER:
8580Sstevel@tonic-gate 			r = scf_value_get_integer(load_val,
8590Sstevel@tonic-gate 			    &ival->sc_u.sc_integer);
8600Sstevel@tonic-gate 			if (r != 0)
8610Sstevel@tonic-gate 				bad_error("scf_value_get_integer", scf_error());
8620Sstevel@tonic-gate 			break;
8630Sstevel@tonic-gate 
8640Sstevel@tonic-gate 		default:
8650Sstevel@tonic-gate 			ssz = scf_value_get_as_string(load_val, loadbuf,
8660Sstevel@tonic-gate 			    loadbuf_sz);
8670Sstevel@tonic-gate 			if (ssz < 0)
8680Sstevel@tonic-gate 				bad_error("scf_value_get_as_string",
8690Sstevel@tonic-gate 				    scf_error());
8700Sstevel@tonic-gate 
8710Sstevel@tonic-gate 			ival->sc_u.sc_string = strdup(loadbuf);
8720Sstevel@tonic-gate 			if (ival->sc_u.sc_string == NULL) {
8730Sstevel@tonic-gate 				r = ENOMEM;
8740Sstevel@tonic-gate 				goto out;
8750Sstevel@tonic-gate 			}
8760Sstevel@tonic-gate 
8770Sstevel@tonic-gate 			ival->sc_free = internal_value_free_str;
8780Sstevel@tonic-gate 		}
8790Sstevel@tonic-gate 
8800Sstevel@tonic-gate 		internal_attach_value(iprop, ival);
8810Sstevel@tonic-gate 	}
8820Sstevel@tonic-gate 
8830Sstevel@tonic-gate 	*ipp = iprop;
8840Sstevel@tonic-gate 	return (0);
8850Sstevel@tonic-gate 
8860Sstevel@tonic-gate out:
8870Sstevel@tonic-gate 	free(iprop->sc_property_name);
8880Sstevel@tonic-gate 	internal_property_free(iprop);
8890Sstevel@tonic-gate 	return (r);
8900Sstevel@tonic-gate }
8910Sstevel@tonic-gate 
8920Sstevel@tonic-gate /*
8930Sstevel@tonic-gate  * Returns
8940Sstevel@tonic-gate  *   0 - success
8950Sstevel@tonic-gate  *   ECANCELED - pg was deleted
8960Sstevel@tonic-gate  *   ECONNABORTED - repository disconnected
8970Sstevel@tonic-gate  *   ENOMEM - out of memory
8980Sstevel@tonic-gate  */
8990Sstevel@tonic-gate int
9000Sstevel@tonic-gate load_pg_attrs(const scf_propertygroup_t *pg, pgroup_t **ipgp)
9010Sstevel@tonic-gate {
9020Sstevel@tonic-gate 	pgroup_t *ipg;
9030Sstevel@tonic-gate 
9040Sstevel@tonic-gate 	ipg = internal_pgroup_new();
9050Sstevel@tonic-gate 
9060Sstevel@tonic-gate 	if (scf_pg_get_flags(pg, &ipg->sc_pgroup_flags) != 0) {
9070Sstevel@tonic-gate 		switch (scf_error()) {
9080Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
9090Sstevel@tonic-gate 			internal_pgroup_free(ipg);
9100Sstevel@tonic-gate 			return (ECANCELED);
9110Sstevel@tonic-gate 
9120Sstevel@tonic-gate 		case SCF_ERROR_CONNECTION_BROKEN:
9130Sstevel@tonic-gate 			internal_pgroup_free(ipg);
9140Sstevel@tonic-gate 			return (ECONNABORTED);
9150Sstevel@tonic-gate 
9160Sstevel@tonic-gate 		case SCF_ERROR_NOT_SET:
9170Sstevel@tonic-gate 		case SCF_ERROR_NOT_BOUND:
9180Sstevel@tonic-gate 		default:
9190Sstevel@tonic-gate 			bad_error("scf_pg_get_name", scf_error());
9200Sstevel@tonic-gate 		}
9210Sstevel@tonic-gate 	}
9220Sstevel@tonic-gate 
9230Sstevel@tonic-gate 	if (scf_pg_get_name(pg, loadbuf, loadbuf_sz) < 0) {
9240Sstevel@tonic-gate 		switch (scf_error()) {
9250Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
9260Sstevel@tonic-gate 			internal_pgroup_free(ipg);
9270Sstevel@tonic-gate 			return (ECANCELED);
9280Sstevel@tonic-gate 
9290Sstevel@tonic-gate 		case SCF_ERROR_CONNECTION_BROKEN:
9300Sstevel@tonic-gate 			internal_pgroup_free(ipg);
9310Sstevel@tonic-gate 			return (ECONNABORTED);
9320Sstevel@tonic-gate 
9330Sstevel@tonic-gate 		case SCF_ERROR_NOT_SET:
9340Sstevel@tonic-gate 		case SCF_ERROR_NOT_BOUND:
9350Sstevel@tonic-gate 		default:
9360Sstevel@tonic-gate 			bad_error("scf_pg_get_name", scf_error());
9370Sstevel@tonic-gate 		}
9380Sstevel@tonic-gate 	}
9390Sstevel@tonic-gate 
9400Sstevel@tonic-gate 	ipg->sc_pgroup_name = strdup(loadbuf);
9410Sstevel@tonic-gate 	if (ipg->sc_pgroup_name == NULL) {
9420Sstevel@tonic-gate 		internal_pgroup_free(ipg);
9430Sstevel@tonic-gate 		return (ENOMEM);
9440Sstevel@tonic-gate 	}
9450Sstevel@tonic-gate 
9460Sstevel@tonic-gate 	if (scf_pg_get_type(pg, loadbuf, loadbuf_sz) < 0) {
9470Sstevel@tonic-gate 		switch (scf_error()) {
9480Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
9490Sstevel@tonic-gate 			free((char *)ipg->sc_pgroup_name);
9500Sstevel@tonic-gate 			internal_pgroup_free(ipg);
9510Sstevel@tonic-gate 			return (ECANCELED);
9520Sstevel@tonic-gate 
9530Sstevel@tonic-gate 		case SCF_ERROR_CONNECTION_BROKEN:
9540Sstevel@tonic-gate 			free((char *)ipg->sc_pgroup_name);
9550Sstevel@tonic-gate 			internal_pgroup_free(ipg);
9560Sstevel@tonic-gate 			return (ECONNABORTED);
9570Sstevel@tonic-gate 
9580Sstevel@tonic-gate 		case SCF_ERROR_NOT_SET:
9590Sstevel@tonic-gate 		case SCF_ERROR_NOT_BOUND:
9600Sstevel@tonic-gate 		default:
9610Sstevel@tonic-gate 			bad_error("scf_pg_get_name", scf_error());
9620Sstevel@tonic-gate 		}
9630Sstevel@tonic-gate 	}
9640Sstevel@tonic-gate 
9650Sstevel@tonic-gate 	ipg->sc_pgroup_type = strdup(loadbuf);
9660Sstevel@tonic-gate 	if (ipg->sc_pgroup_type == NULL) {
9670Sstevel@tonic-gate 		free((char *)ipg->sc_pgroup_name);
9680Sstevel@tonic-gate 		internal_pgroup_free(ipg);
9690Sstevel@tonic-gate 		return (ENOMEM);
9700Sstevel@tonic-gate 	}
9710Sstevel@tonic-gate 
9720Sstevel@tonic-gate 	*ipgp = ipg;
9730Sstevel@tonic-gate 	return (0);
9740Sstevel@tonic-gate }
9750Sstevel@tonic-gate 
9760Sstevel@tonic-gate /*
9770Sstevel@tonic-gate  * Load a property group into a pgroup_t.  Returns
9780Sstevel@tonic-gate  *   0 - success
9790Sstevel@tonic-gate  *   ECANCELED - pg was deleted
9800Sstevel@tonic-gate  *   ECONNABORTED - repository disconnected
9810Sstevel@tonic-gate  *   EBADF - pg is corrupt (error printed if fmri is given)
9820Sstevel@tonic-gate  *   ENOMEM - out of memory
9835040Swesolows  *   EACCES - permission denied when reading property
9840Sstevel@tonic-gate  */
9850Sstevel@tonic-gate int
9860Sstevel@tonic-gate load_pg(const scf_propertygroup_t *pg, pgroup_t **ipgp, const char *fmri,
9870Sstevel@tonic-gate     const char *snapname)
9880Sstevel@tonic-gate {
9890Sstevel@tonic-gate 	pgroup_t *ipg;
9900Sstevel@tonic-gate 	int r;
9910Sstevel@tonic-gate 
9920Sstevel@tonic-gate 	if (scf_iter_pg_properties(load_propiter, pg) != 0) {
9930Sstevel@tonic-gate 		switch (scf_error()) {
9940Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
9950Sstevel@tonic-gate 			return (ECANCELED);
9960Sstevel@tonic-gate 
9970Sstevel@tonic-gate 		case SCF_ERROR_CONNECTION_BROKEN:
9980Sstevel@tonic-gate 			return (ECONNABORTED);
9990Sstevel@tonic-gate 
10000Sstevel@tonic-gate 		case SCF_ERROR_HANDLE_MISMATCH:
10010Sstevel@tonic-gate 		case SCF_ERROR_NOT_SET:
10020Sstevel@tonic-gate 		case SCF_ERROR_NOT_BOUND:
10030Sstevel@tonic-gate 		default:
10040Sstevel@tonic-gate 			bad_error("scf_iter_pg_properties", scf_error());
10050Sstevel@tonic-gate 		}
10060Sstevel@tonic-gate 	}
10070Sstevel@tonic-gate 
10080Sstevel@tonic-gate 	r = load_pg_attrs(pg, &ipg);
10090Sstevel@tonic-gate 	switch (r) {
10100Sstevel@tonic-gate 	case 0:
10110Sstevel@tonic-gate 		break;
10120Sstevel@tonic-gate 
10130Sstevel@tonic-gate 	case ECANCELED:
10140Sstevel@tonic-gate 	case ECONNABORTED:
10150Sstevel@tonic-gate 	case ENOMEM:
10160Sstevel@tonic-gate 		return (r);
10170Sstevel@tonic-gate 
10180Sstevel@tonic-gate 	default:
10190Sstevel@tonic-gate 		bad_error("load_pg_attrs", r);
10200Sstevel@tonic-gate 	}
10210Sstevel@tonic-gate 
10220Sstevel@tonic-gate 	for (;;) {
10230Sstevel@tonic-gate 		property_t *iprop;
10240Sstevel@tonic-gate 
10250Sstevel@tonic-gate 		r = scf_iter_next_property(load_propiter, load_prop);
10260Sstevel@tonic-gate 		if (r == 0)
10270Sstevel@tonic-gate 			break;
10280Sstevel@tonic-gate 		if (r != 1) {
10290Sstevel@tonic-gate 			switch (scf_error()) {
10300Sstevel@tonic-gate 			case SCF_ERROR_DELETED:
10310Sstevel@tonic-gate 				r = ECANCELED;
10320Sstevel@tonic-gate 				goto out;
10330Sstevel@tonic-gate 
10340Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
10350Sstevel@tonic-gate 				r = ECONNABORTED;
10360Sstevel@tonic-gate 				goto out;
10370Sstevel@tonic-gate 
10380Sstevel@tonic-gate 			case SCF_ERROR_HANDLE_MISMATCH:
10390Sstevel@tonic-gate 			case SCF_ERROR_NOT_BOUND:
10400Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
10410Sstevel@tonic-gate 			case SCF_ERROR_INVALID_ARGUMENT:
10420Sstevel@tonic-gate 			default:
10430Sstevel@tonic-gate 				bad_error("scf_iter_next_property",
10440Sstevel@tonic-gate 				    scf_error());
10450Sstevel@tonic-gate 			}
10460Sstevel@tonic-gate 		}
10470Sstevel@tonic-gate 
10480Sstevel@tonic-gate 		r = load_property(load_prop, &iprop);
10490Sstevel@tonic-gate 		switch (r) {
10500Sstevel@tonic-gate 		case 0:
10510Sstevel@tonic-gate 			break;
10520Sstevel@tonic-gate 
10530Sstevel@tonic-gate 		case ECANCELED:
10540Sstevel@tonic-gate 		case ECONNABORTED:
10550Sstevel@tonic-gate 		case ENOMEM:
10565040Swesolows 		case EACCES:
10570Sstevel@tonic-gate 			goto out;
10580Sstevel@tonic-gate 
10590Sstevel@tonic-gate 		default:
10600Sstevel@tonic-gate 			bad_error("load_property", r);
10610Sstevel@tonic-gate 		}
10620Sstevel@tonic-gate 
10630Sstevel@tonic-gate 		r = internal_attach_property(ipg, iprop);
10640Sstevel@tonic-gate 		if (r != 0) {
10650Sstevel@tonic-gate 			if (fmri != NULL) {
10660Sstevel@tonic-gate 				if (snapname == NULL)
10670Sstevel@tonic-gate 					warn(gettext("Property group \"%s\" of "
10680Sstevel@tonic-gate 					    "%s has multiple definitions of "
10690Sstevel@tonic-gate 					    "property \"%s\".\n"),
10700Sstevel@tonic-gate 					    ipg->sc_pgroup_name, fmri,
10710Sstevel@tonic-gate 					    iprop->sc_property_name);
10720Sstevel@tonic-gate 				else
10730Sstevel@tonic-gate 					warn(gettext("Property group \"%s\" of "
10740Sstevel@tonic-gate 					    "the \"%s\" snapshot of %s has "
10750Sstevel@tonic-gate 					    "multiple definitions of property "
10760Sstevel@tonic-gate 					    "\"%s\".\n"),
10770Sstevel@tonic-gate 					    ipg->sc_pgroup_name, snapname, fmri,
10780Sstevel@tonic-gate 					    iprop->sc_property_name);
10790Sstevel@tonic-gate 			}
10800Sstevel@tonic-gate 			r = EBADF;
10810Sstevel@tonic-gate 			goto out;
10820Sstevel@tonic-gate 		}
10830Sstevel@tonic-gate 	}
10840Sstevel@tonic-gate 
10850Sstevel@tonic-gate 	*ipgp = ipg;
10860Sstevel@tonic-gate 	return (0);
10870Sstevel@tonic-gate 
10880Sstevel@tonic-gate out:
10890Sstevel@tonic-gate 	internal_pgroup_free(ipg);
10900Sstevel@tonic-gate 	return (r);
10910Sstevel@tonic-gate }
10920Sstevel@tonic-gate 
10930Sstevel@tonic-gate /*
10940Sstevel@tonic-gate  * These functions compare internal property groups and properties (pgroup_t
10950Sstevel@tonic-gate  * & property_t).  They return 1 if the given structures are equal and
10960Sstevel@tonic-gate  * 0 otherwise.  Some will report the differences between the two structures.
10970Sstevel@tonic-gate  * They are used by the import functions in svccfg_libscf.c .
10980Sstevel@tonic-gate  */
10990Sstevel@tonic-gate 
11000Sstevel@tonic-gate int
11010Sstevel@tonic-gate prop_equal(property_t *p1, property_t *p2, const char *fmri, const char *pgname,
11020Sstevel@tonic-gate     int new)
11030Sstevel@tonic-gate {
11040Sstevel@tonic-gate 	value_t *v1, *v2;
11050Sstevel@tonic-gate 
11060Sstevel@tonic-gate 	const char * const values_diff = gettext("Conflict upgrading %s "
11070Sstevel@tonic-gate 	    "(property \"%s/%s\" has different values).\n");
11080Sstevel@tonic-gate 	const char * const values_diff_new = gettext("Conflict upgrading %s "
11090Sstevel@tonic-gate 	    "(new property \"%s/%s\" has different values).\n");
11100Sstevel@tonic-gate 
11110Sstevel@tonic-gate 	assert((fmri == NULL) == (pgname == NULL));
11120Sstevel@tonic-gate 
11130Sstevel@tonic-gate 	if (fmri != NULL) {
11140Sstevel@tonic-gate 		/*
11150Sstevel@tonic-gate 		 * If we find any differences, we'll report conflicts.  But
11160Sstevel@tonic-gate 		 * conflict messages won't make any sense if the names don't
11170Sstevel@tonic-gate 		 * match.  If the caller supplied fmri, assert that the names
11180Sstevel@tonic-gate 		 * match.
11190Sstevel@tonic-gate 		 */
11200Sstevel@tonic-gate 		assert(strcmp(p1->sc_property_name, p2->sc_property_name) == 0);
11210Sstevel@tonic-gate 	} else {
11220Sstevel@tonic-gate 		if (strcmp(p1->sc_property_name, p2->sc_property_name) != 0)
11230Sstevel@tonic-gate 			return (0);
11240Sstevel@tonic-gate 	}
11250Sstevel@tonic-gate 
11260Sstevel@tonic-gate 	if (p1->sc_value_type != p2->sc_value_type) {
11270Sstevel@tonic-gate 		if (fmri != NULL) {
11280Sstevel@tonic-gate 			if (new)
11290Sstevel@tonic-gate 				warn(gettext("Conflict upgrading %s "
11300Sstevel@tonic-gate 				    "(new property \"%s/%s\" has different "
11310Sstevel@tonic-gate 				    "type).\n"), fmri, pgname,
11320Sstevel@tonic-gate 				    p1->sc_property_name);
11330Sstevel@tonic-gate 			else
11340Sstevel@tonic-gate 				warn(gettext("Conflict upgrading %s "
11350Sstevel@tonic-gate 				    "(property \"%s/%s\" has different "
11360Sstevel@tonic-gate 				    "type).\n"), fmri, pgname,
11370Sstevel@tonic-gate 				    p1->sc_property_name);
11380Sstevel@tonic-gate 		}
11390Sstevel@tonic-gate 		return (0);
11400Sstevel@tonic-gate 	}
11410Sstevel@tonic-gate 
11420Sstevel@tonic-gate 	if (uu_list_numnodes(p1->sc_property_values) !=
11430Sstevel@tonic-gate 	    uu_list_numnodes(p2->sc_property_values)) {
11440Sstevel@tonic-gate 		if (fmri != NULL)
11450Sstevel@tonic-gate 			warn(new ? values_diff_new : values_diff, fmri,
11460Sstevel@tonic-gate 			    pgname, p1->sc_property_name);
11470Sstevel@tonic-gate 		return (0);
11480Sstevel@tonic-gate 	}
11490Sstevel@tonic-gate 
11500Sstevel@tonic-gate 	v1 = uu_list_first(p1->sc_property_values);
11510Sstevel@tonic-gate 	v2 = uu_list_first(p2->sc_property_values);
11520Sstevel@tonic-gate 
11530Sstevel@tonic-gate 	while (v1 != NULL) {
11540Sstevel@tonic-gate 		assert(v2 != NULL);
11550Sstevel@tonic-gate 
11560Sstevel@tonic-gate 		if (value_cmp(v1, v2, NULL) != 0) {
11570Sstevel@tonic-gate 			if (fmri != NULL)
11580Sstevel@tonic-gate 				warn(new ? values_diff_new : values_diff,
11590Sstevel@tonic-gate 				    fmri, pgname, p1->sc_property_name);
11600Sstevel@tonic-gate 			return (0);
11610Sstevel@tonic-gate 		}
11620Sstevel@tonic-gate 
11630Sstevel@tonic-gate 		v1 = uu_list_next(p1->sc_property_values, v1);
11640Sstevel@tonic-gate 		v2 = uu_list_next(p2->sc_property_values, v2);
11650Sstevel@tonic-gate 	}
11660Sstevel@tonic-gate 
11670Sstevel@tonic-gate 	return (1);
11680Sstevel@tonic-gate }
11690Sstevel@tonic-gate 
11700Sstevel@tonic-gate int
1171306Sbustos pg_attrs_equal(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri,
1172306Sbustos     int new)
11730Sstevel@tonic-gate {
11740Sstevel@tonic-gate 	if (strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) != 0) {
11750Sstevel@tonic-gate 		assert(fmri == NULL);
11760Sstevel@tonic-gate 		return (0);
11770Sstevel@tonic-gate 	}
11780Sstevel@tonic-gate 
11790Sstevel@tonic-gate 	if (pg1->sc_pgroup_flags != pg2->sc_pgroup_flags) {
11800Sstevel@tonic-gate 		if (fmri) {
11810Sstevel@tonic-gate 			if (new)
11820Sstevel@tonic-gate 				warn(gettext("Conflict upgrading %s "
11830Sstevel@tonic-gate 				    "(new property group \"%s\" has different "
11840Sstevel@tonic-gate 				    "flags).\n"), fmri, pg1->sc_pgroup_name);
11850Sstevel@tonic-gate 			else
11860Sstevel@tonic-gate 				warn(gettext("Conflict upgrading %s "
11870Sstevel@tonic-gate 				    "(property group \"%s\" has different "
11880Sstevel@tonic-gate 				    "flags).\n"), fmri, pg1->sc_pgroup_name);
11890Sstevel@tonic-gate 		}
11900Sstevel@tonic-gate 		return (0);
11910Sstevel@tonic-gate 	}
11920Sstevel@tonic-gate 
11930Sstevel@tonic-gate 	if (strcmp(pg1->sc_pgroup_type, pg2->sc_pgroup_type) != 0) {
11940Sstevel@tonic-gate 		if (fmri) {
11950Sstevel@tonic-gate 			if (new)
11960Sstevel@tonic-gate 				warn(gettext("Conflict upgrading %s "
11970Sstevel@tonic-gate 				    "(new property group \"%s\" has different "
11980Sstevel@tonic-gate 				    "type).\n"), fmri, pg1->sc_pgroup_name);
11990Sstevel@tonic-gate 			else
12000Sstevel@tonic-gate 				warn(gettext("Conflict upgrading %s "
12010Sstevel@tonic-gate 				    "(property group \"%s\" has different "
12020Sstevel@tonic-gate 				    "type).\n"), fmri, pg1->sc_pgroup_name);
12030Sstevel@tonic-gate 		}
12040Sstevel@tonic-gate 		return (0);
12050Sstevel@tonic-gate 	}
12060Sstevel@tonic-gate 
12070Sstevel@tonic-gate 	return (1);
12080Sstevel@tonic-gate }
12090Sstevel@tonic-gate 
12100Sstevel@tonic-gate int
12110Sstevel@tonic-gate pg_equal(pgroup_t *pg1, pgroup_t *pg2)
12120Sstevel@tonic-gate {
12130Sstevel@tonic-gate 	property_t *p1, *p2;
12140Sstevel@tonic-gate 
12150Sstevel@tonic-gate 	if (!pg_attrs_equal(pg1, pg2, NULL, 0))
12160Sstevel@tonic-gate 		return (0);
12170Sstevel@tonic-gate 
12180Sstevel@tonic-gate 	if (uu_list_numnodes(pg1->sc_pgroup_props) !=
12190Sstevel@tonic-gate 	    uu_list_numnodes(pg2->sc_pgroup_props))
12200Sstevel@tonic-gate 		return (0);
12210Sstevel@tonic-gate 
12220Sstevel@tonic-gate 	p1 = uu_list_first(pg1->sc_pgroup_props);
12230Sstevel@tonic-gate 	p2 = uu_list_first(pg2->sc_pgroup_props);
12240Sstevel@tonic-gate 
12250Sstevel@tonic-gate 	while (p1 != NULL) {
12260Sstevel@tonic-gate 		assert(p2 != NULL);
12270Sstevel@tonic-gate 
12280Sstevel@tonic-gate 		if (!prop_equal(p1, p2, NULL, NULL, 0))
12290Sstevel@tonic-gate 			return (0);
12300Sstevel@tonic-gate 
12310Sstevel@tonic-gate 		p1 = uu_list_next(pg1->sc_pgroup_props, p1);
12320Sstevel@tonic-gate 		p2 = uu_list_next(pg2->sc_pgroup_props, p2);
12330Sstevel@tonic-gate 	}
12340Sstevel@tonic-gate 
12350Sstevel@tonic-gate 	return (1);
12360Sstevel@tonic-gate }
1237