xref: /onnv-gate/usr/src/cmd/svc/svccfg/svccfg_internal.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <assert.h>
30*0Sstevel@tonic-gate #include <errno.h>
31*0Sstevel@tonic-gate #include <libintl.h>
32*0Sstevel@tonic-gate #include <libuutil.h>
33*0Sstevel@tonic-gate #include <stdarg.h>
34*0Sstevel@tonic-gate #include <stddef.h>
35*0Sstevel@tonic-gate #include <string.h>
36*0Sstevel@tonic-gate 
37*0Sstevel@tonic-gate #include "svccfg.h"
38*0Sstevel@tonic-gate 
39*0Sstevel@tonic-gate /*
40*0Sstevel@tonic-gate  * Internal representation manipulation routines for svccfg(1)
41*0Sstevel@tonic-gate  */
42*0Sstevel@tonic-gate 
43*0Sstevel@tonic-gate static uu_list_pool_t	*entity_pool;
44*0Sstevel@tonic-gate static uu_list_pool_t	*pgroup_pool;
45*0Sstevel@tonic-gate static uu_list_pool_t	*property_pool;
46*0Sstevel@tonic-gate static uu_list_pool_t	*value_pool;
47*0Sstevel@tonic-gate 
48*0Sstevel@tonic-gate /* ARGSUSED */
49*0Sstevel@tonic-gate static int
50*0Sstevel@tonic-gate entity_cmp(const void *a, const void *b, void *p)
51*0Sstevel@tonic-gate {
52*0Sstevel@tonic-gate 	entity_t *A = (entity_t *)a;
53*0Sstevel@tonic-gate 	entity_t *B = (entity_t *)b;
54*0Sstevel@tonic-gate 
55*0Sstevel@tonic-gate 	return (strcmp(A->sc_name, B->sc_name));
56*0Sstevel@tonic-gate }
57*0Sstevel@tonic-gate 
58*0Sstevel@tonic-gate /*ARGSUSED*/
59*0Sstevel@tonic-gate static int
60*0Sstevel@tonic-gate pgroup_cmp(const void *a, const void *b, void *p)
61*0Sstevel@tonic-gate {
62*0Sstevel@tonic-gate 	pgroup_t *A = (pgroup_t *)a;
63*0Sstevel@tonic-gate 	pgroup_t *B = (pgroup_t *)b;
64*0Sstevel@tonic-gate 
65*0Sstevel@tonic-gate 	return (strcmp(A->sc_pgroup_name, B->sc_pgroup_name));
66*0Sstevel@tonic-gate }
67*0Sstevel@tonic-gate 
68*0Sstevel@tonic-gate /* ARGSUSED */
69*0Sstevel@tonic-gate static int
70*0Sstevel@tonic-gate property_cmp(const void *a, const void *b, void *p)
71*0Sstevel@tonic-gate {
72*0Sstevel@tonic-gate 	property_t *A = (property_t *)a;
73*0Sstevel@tonic-gate 	property_t *B = (property_t *)b;
74*0Sstevel@tonic-gate 
75*0Sstevel@tonic-gate 	return (strcmp(A->sc_property_name, B->sc_property_name));
76*0Sstevel@tonic-gate }
77*0Sstevel@tonic-gate 
78*0Sstevel@tonic-gate /* ARGSUSED */
79*0Sstevel@tonic-gate int
80*0Sstevel@tonic-gate value_cmp(const void *a, const void *b, void *p)
81*0Sstevel@tonic-gate {
82*0Sstevel@tonic-gate 	const value_t *A = a;
83*0Sstevel@tonic-gate 	const value_t *B = b;
84*0Sstevel@tonic-gate 
85*0Sstevel@tonic-gate 	if (A->sc_type != B->sc_type)
86*0Sstevel@tonic-gate 		return (B->sc_type - A->sc_type);
87*0Sstevel@tonic-gate 
88*0Sstevel@tonic-gate 	switch (A->sc_type) {
89*0Sstevel@tonic-gate 	case SCF_TYPE_BOOLEAN:
90*0Sstevel@tonic-gate 	case SCF_TYPE_COUNT:
91*0Sstevel@tonic-gate 		return (B->sc_u.sc_count - A->sc_u.sc_count);
92*0Sstevel@tonic-gate 
93*0Sstevel@tonic-gate 	case SCF_TYPE_INTEGER:
94*0Sstevel@tonic-gate 		return (B->sc_u.sc_integer - A->sc_u.sc_integer);
95*0Sstevel@tonic-gate 
96*0Sstevel@tonic-gate 	default:
97*0Sstevel@tonic-gate 		return (strcmp(A->sc_u.sc_string, B->sc_u.sc_string));
98*0Sstevel@tonic-gate 	}
99*0Sstevel@tonic-gate }
100*0Sstevel@tonic-gate 
101*0Sstevel@tonic-gate void
102*0Sstevel@tonic-gate internal_init()
103*0Sstevel@tonic-gate {
104*0Sstevel@tonic-gate 	if ((entity_pool = uu_list_pool_create("entities", sizeof (entity_t),
105*0Sstevel@tonic-gate 	    offsetof(entity_t, sc_node), entity_cmp, 0)) == NULL)
106*0Sstevel@tonic-gate 		uu_die(gettext("entity list pool creation failed: %s\n"),
107*0Sstevel@tonic-gate 		    uu_strerror(uu_error()));
108*0Sstevel@tonic-gate 
109*0Sstevel@tonic-gate 	if ((pgroup_pool = uu_list_pool_create("property_groups",
110*0Sstevel@tonic-gate 	    sizeof (pgroup_t), offsetof(pgroup_t, sc_node), pgroup_cmp, 0)) ==
111*0Sstevel@tonic-gate 	    NULL)
112*0Sstevel@tonic-gate 		uu_die(
113*0Sstevel@tonic-gate 		    gettext("property group list pool creation failed: %s\n"),
114*0Sstevel@tonic-gate 		    uu_strerror(uu_error()));
115*0Sstevel@tonic-gate 
116*0Sstevel@tonic-gate 	if ((property_pool = uu_list_pool_create("properties",
117*0Sstevel@tonic-gate 	    sizeof (property_t), offsetof(property_t, sc_node), property_cmp,
118*0Sstevel@tonic-gate 	    0)) == NULL)
119*0Sstevel@tonic-gate 		uu_die(gettext("property list pool creation failed: %s\n"),
120*0Sstevel@tonic-gate 		    uu_strerror(uu_error()));
121*0Sstevel@tonic-gate 
122*0Sstevel@tonic-gate 	if ((value_pool = uu_list_pool_create("property_values",
123*0Sstevel@tonic-gate 	    sizeof (value_t), offsetof(value_t, sc_node), value_cmp, 0)) ==
124*0Sstevel@tonic-gate 	    NULL)
125*0Sstevel@tonic-gate 		uu_die(
126*0Sstevel@tonic-gate 		    gettext("property value list pool creation failed: %s\n"),
127*0Sstevel@tonic-gate 		    uu_strerror(uu_error()));
128*0Sstevel@tonic-gate }
129*0Sstevel@tonic-gate 
130*0Sstevel@tonic-gate /*ARGSUSED*/
131*0Sstevel@tonic-gate static int
132*0Sstevel@tonic-gate internal_value_dump(void *v, void *pvt)
133*0Sstevel@tonic-gate {
134*0Sstevel@tonic-gate 	value_t *val = v;
135*0Sstevel@tonic-gate 
136*0Sstevel@tonic-gate 	switch (val->sc_type) {
137*0Sstevel@tonic-gate 	case SCF_TYPE_BOOLEAN:
138*0Sstevel@tonic-gate 		(void) printf("	value = %s\n",
139*0Sstevel@tonic-gate 		    val->sc_u.sc_count ? "true" : "false");
140*0Sstevel@tonic-gate 		break;
141*0Sstevel@tonic-gate 	case SCF_TYPE_COUNT:
142*0Sstevel@tonic-gate 		(void) printf("	value = %llu\n", val->sc_u.sc_count);
143*0Sstevel@tonic-gate 		break;
144*0Sstevel@tonic-gate 	case SCF_TYPE_INTEGER:
145*0Sstevel@tonic-gate 		(void) printf("	value = %lld\n", val->sc_u.sc_integer);
146*0Sstevel@tonic-gate 		break;
147*0Sstevel@tonic-gate 	case SCF_TYPE_ASTRING:
148*0Sstevel@tonic-gate 	case SCF_TYPE_FMRI:
149*0Sstevel@tonic-gate 	case SCF_TYPE_HOST:
150*0Sstevel@tonic-gate 	case SCF_TYPE_HOSTNAME:
151*0Sstevel@tonic-gate 	case SCF_TYPE_NET_ADDR_V4:
152*0Sstevel@tonic-gate 	case SCF_TYPE_NET_ADDR_V6:
153*0Sstevel@tonic-gate 	case SCF_TYPE_OPAQUE:
154*0Sstevel@tonic-gate 	case SCF_TYPE_TIME:
155*0Sstevel@tonic-gate 	case SCF_TYPE_URI:
156*0Sstevel@tonic-gate 	case SCF_TYPE_USTRING:
157*0Sstevel@tonic-gate 		(void) printf("	value = %s\n",
158*0Sstevel@tonic-gate 		    val->sc_u.sc_string ? val->sc_u.sc_string : "(nil)");
159*0Sstevel@tonic-gate 		break;
160*0Sstevel@tonic-gate 	default:
161*0Sstevel@tonic-gate 		uu_die(gettext("unknown value type (%d)\n"), val->sc_type);
162*0Sstevel@tonic-gate 		break;
163*0Sstevel@tonic-gate 	}
164*0Sstevel@tonic-gate 
165*0Sstevel@tonic-gate 	return (UU_WALK_NEXT);
166*0Sstevel@tonic-gate }
167*0Sstevel@tonic-gate 
168*0Sstevel@tonic-gate /*ARGSUSED*/
169*0Sstevel@tonic-gate static int
170*0Sstevel@tonic-gate internal_property_dump(void *v, void *pvt)
171*0Sstevel@tonic-gate {
172*0Sstevel@tonic-gate 	property_t *p = v;
173*0Sstevel@tonic-gate 
174*0Sstevel@tonic-gate 	(void) printf("property\n	name = %s\n", p->sc_property_name);
175*0Sstevel@tonic-gate 	(void) printf("	type = %d\n", p->sc_value_type);
176*0Sstevel@tonic-gate 
177*0Sstevel@tonic-gate 	(void) uu_list_walk(p->sc_property_values, internal_value_dump,
178*0Sstevel@tonic-gate 	    NULL, UU_DEFAULT);
179*0Sstevel@tonic-gate 
180*0Sstevel@tonic-gate 	return (UU_WALK_NEXT);
181*0Sstevel@tonic-gate }
182*0Sstevel@tonic-gate 
183*0Sstevel@tonic-gate /*ARGSUSED*/
184*0Sstevel@tonic-gate static int
185*0Sstevel@tonic-gate internal_pgroup_dump(void *v, void *pvt)
186*0Sstevel@tonic-gate {
187*0Sstevel@tonic-gate 	pgroup_t *pg = v;
188*0Sstevel@tonic-gate 
189*0Sstevel@tonic-gate 	(void) printf("pgroup	name = %s\n", pg->sc_pgroup_name);
190*0Sstevel@tonic-gate 	(void) printf("	type = %s\n", pg->sc_pgroup_type);
191*0Sstevel@tonic-gate 
192*0Sstevel@tonic-gate 	(void) uu_list_walk(pg->sc_pgroup_props, internal_property_dump,
193*0Sstevel@tonic-gate 	    NULL, UU_DEFAULT);
194*0Sstevel@tonic-gate 
195*0Sstevel@tonic-gate 	return (UU_WALK_NEXT);
196*0Sstevel@tonic-gate }
197*0Sstevel@tonic-gate 
198*0Sstevel@tonic-gate /*ARGSUSED*/
199*0Sstevel@tonic-gate static int
200*0Sstevel@tonic-gate internal_instance_dump(void *v, void *pvt)
201*0Sstevel@tonic-gate {
202*0Sstevel@tonic-gate 	entity_t *i = v;
203*0Sstevel@tonic-gate 
204*0Sstevel@tonic-gate 	(void) printf("instance	name = %s\n", i->sc_name);
205*0Sstevel@tonic-gate 
206*0Sstevel@tonic-gate 	(void) uu_list_walk(i->sc_pgroups, internal_pgroup_dump, NULL,
207*0Sstevel@tonic-gate 	    UU_DEFAULT);
208*0Sstevel@tonic-gate 
209*0Sstevel@tonic-gate 	return (UU_WALK_NEXT);
210*0Sstevel@tonic-gate }
211*0Sstevel@tonic-gate 
212*0Sstevel@tonic-gate /*ARGSUSED*/
213*0Sstevel@tonic-gate static int
214*0Sstevel@tonic-gate internal_service_dump(void *v, void *pvt)
215*0Sstevel@tonic-gate {
216*0Sstevel@tonic-gate 	entity_t *s = v;
217*0Sstevel@tonic-gate 
218*0Sstevel@tonic-gate 	(void) printf("service	name = %s\n", s->sc_name);
219*0Sstevel@tonic-gate 	(void) printf("	type = %x\n", s->sc_u.sc_service.sc_service_type);
220*0Sstevel@tonic-gate 	(void) printf("	version = %u\n", s->sc_u.sc_service.sc_service_version);
221*0Sstevel@tonic-gate 
222*0Sstevel@tonic-gate 	(void) uu_list_walk(s->sc_pgroups, internal_pgroup_dump, NULL,
223*0Sstevel@tonic-gate 	    UU_DEFAULT);
224*0Sstevel@tonic-gate 
225*0Sstevel@tonic-gate 	(void) uu_list_walk(s->sc_u.sc_service.sc_service_instances,
226*0Sstevel@tonic-gate 	    internal_instance_dump, NULL, UU_DEFAULT);
227*0Sstevel@tonic-gate 
228*0Sstevel@tonic-gate 	return (UU_WALK_NEXT);
229*0Sstevel@tonic-gate }
230*0Sstevel@tonic-gate 
231*0Sstevel@tonic-gate void
232*0Sstevel@tonic-gate internal_dump(bundle_t *b)
233*0Sstevel@tonic-gate {
234*0Sstevel@tonic-gate 	(void) printf("bundle	name = %s\n", b->sc_bundle_name);
235*0Sstevel@tonic-gate 	(void) printf("	type = %x\n", b->sc_bundle_type);
236*0Sstevel@tonic-gate 
237*0Sstevel@tonic-gate 	(void) uu_list_walk(b->sc_bundle_services, internal_service_dump,
238*0Sstevel@tonic-gate 	    NULL, UU_DEFAULT);
239*0Sstevel@tonic-gate }
240*0Sstevel@tonic-gate 
241*0Sstevel@tonic-gate bundle_t *
242*0Sstevel@tonic-gate internal_bundle_new()
243*0Sstevel@tonic-gate {
244*0Sstevel@tonic-gate 	bundle_t	*b;
245*0Sstevel@tonic-gate 
246*0Sstevel@tonic-gate 	if ((b = uu_zalloc(sizeof (bundle_t))) == NULL)
247*0Sstevel@tonic-gate 		uu_die(gettext("couldn't allocate memory"));
248*0Sstevel@tonic-gate 
249*0Sstevel@tonic-gate 	b->sc_bundle_type = SVCCFG_UNKNOWN_BUNDLE;
250*0Sstevel@tonic-gate 	b->sc_bundle_services = uu_list_create(entity_pool, b, 0);
251*0Sstevel@tonic-gate 
252*0Sstevel@tonic-gate 	return (b);
253*0Sstevel@tonic-gate }
254*0Sstevel@tonic-gate 
255*0Sstevel@tonic-gate void
256*0Sstevel@tonic-gate internal_bundle_free(bundle_t *b)
257*0Sstevel@tonic-gate {
258*0Sstevel@tonic-gate 	void *cookie = NULL;
259*0Sstevel@tonic-gate 	entity_t *service;
260*0Sstevel@tonic-gate 
261*0Sstevel@tonic-gate 	while ((service = uu_list_teardown(b->sc_bundle_services, &cookie)) !=
262*0Sstevel@tonic-gate 	    NULL)
263*0Sstevel@tonic-gate 		internal_service_free(service);
264*0Sstevel@tonic-gate 
265*0Sstevel@tonic-gate 	free(b);
266*0Sstevel@tonic-gate }
267*0Sstevel@tonic-gate 
268*0Sstevel@tonic-gate entity_t *
269*0Sstevel@tonic-gate internal_service_new(const char *name)
270*0Sstevel@tonic-gate {
271*0Sstevel@tonic-gate 	entity_t *s;
272*0Sstevel@tonic-gate 
273*0Sstevel@tonic-gate 	if ((s = uu_zalloc(sizeof (entity_t))) == NULL)
274*0Sstevel@tonic-gate 		uu_die(gettext("couldn't allocate memory"));
275*0Sstevel@tonic-gate 
276*0Sstevel@tonic-gate 	uu_list_node_init(s, &s->sc_node, entity_pool);
277*0Sstevel@tonic-gate 
278*0Sstevel@tonic-gate 	s->sc_name = name;
279*0Sstevel@tonic-gate 	s->sc_fmri = uu_msprintf("svc:/%s", name);
280*0Sstevel@tonic-gate 	if (s->sc_fmri == NULL)
281*0Sstevel@tonic-gate 		uu_die(gettext("couldn't allocate memory"));
282*0Sstevel@tonic-gate 
283*0Sstevel@tonic-gate 	s->sc_etype = SVCCFG_SERVICE_OBJECT;
284*0Sstevel@tonic-gate 	s->sc_pgroups = uu_list_create(pgroup_pool, s, 0);
285*0Sstevel@tonic-gate 	s->sc_dependents = uu_list_create(pgroup_pool, s, 0);
286*0Sstevel@tonic-gate 
287*0Sstevel@tonic-gate 	s->sc_u.sc_service.sc_service_type = SVCCFG_UNKNOWN_SERVICE;
288*0Sstevel@tonic-gate 	s->sc_u.sc_service.sc_service_instances = uu_list_create(entity_pool, s,
289*0Sstevel@tonic-gate 	    0);
290*0Sstevel@tonic-gate 
291*0Sstevel@tonic-gate 	return (s);
292*0Sstevel@tonic-gate }
293*0Sstevel@tonic-gate 
294*0Sstevel@tonic-gate void
295*0Sstevel@tonic-gate internal_service_free(entity_t *s)
296*0Sstevel@tonic-gate {
297*0Sstevel@tonic-gate 	entity_t *inst;
298*0Sstevel@tonic-gate 	pgroup_t *pg;
299*0Sstevel@tonic-gate 	void *cookie;
300*0Sstevel@tonic-gate 
301*0Sstevel@tonic-gate 	cookie = NULL;
302*0Sstevel@tonic-gate 	while ((pg = uu_list_teardown(s->sc_pgroups, &cookie)) != NULL)
303*0Sstevel@tonic-gate 		internal_pgroup_free(pg);
304*0Sstevel@tonic-gate 
305*0Sstevel@tonic-gate 	cookie = NULL;
306*0Sstevel@tonic-gate 	while ((pg = uu_list_teardown(s->sc_dependents, &cookie)) != NULL)
307*0Sstevel@tonic-gate 		internal_pgroup_free(pg);
308*0Sstevel@tonic-gate 
309*0Sstevel@tonic-gate 	cookie = NULL;
310*0Sstevel@tonic-gate 	while ((inst = uu_list_teardown(s->sc_u.sc_service.sc_service_instances,
311*0Sstevel@tonic-gate 	    &cookie)) != NULL)
312*0Sstevel@tonic-gate 		internal_instance_free(inst);
313*0Sstevel@tonic-gate 
314*0Sstevel@tonic-gate 	free(s);
315*0Sstevel@tonic-gate }
316*0Sstevel@tonic-gate 
317*0Sstevel@tonic-gate entity_t *
318*0Sstevel@tonic-gate internal_instance_new(const char *name)
319*0Sstevel@tonic-gate {
320*0Sstevel@tonic-gate 	entity_t *i;
321*0Sstevel@tonic-gate 
322*0Sstevel@tonic-gate 	if ((i = uu_zalloc(sizeof (entity_t))) == NULL)
323*0Sstevel@tonic-gate 		uu_die(gettext("couldn't allocate memory"));
324*0Sstevel@tonic-gate 
325*0Sstevel@tonic-gate 	uu_list_node_init(i, &i->sc_node, entity_pool);
326*0Sstevel@tonic-gate 
327*0Sstevel@tonic-gate 	i->sc_name = name;
328*0Sstevel@tonic-gate 	/* Can't set i->sc_fmri until we're attached to a service. */
329*0Sstevel@tonic-gate 	i->sc_etype = SVCCFG_INSTANCE_OBJECT;
330*0Sstevel@tonic-gate 	i->sc_pgroups = uu_list_create(pgroup_pool, i, 0);
331*0Sstevel@tonic-gate 	i->sc_dependents = uu_list_create(pgroup_pool, i, 0);
332*0Sstevel@tonic-gate 
333*0Sstevel@tonic-gate 	return (i);
334*0Sstevel@tonic-gate }
335*0Sstevel@tonic-gate 
336*0Sstevel@tonic-gate void
337*0Sstevel@tonic-gate internal_instance_free(entity_t *i)
338*0Sstevel@tonic-gate {
339*0Sstevel@tonic-gate 	pgroup_t *pg;
340*0Sstevel@tonic-gate 	void *cookie = NULL;
341*0Sstevel@tonic-gate 
342*0Sstevel@tonic-gate 	while ((pg = uu_list_teardown(i->sc_pgroups, &cookie)) != NULL)
343*0Sstevel@tonic-gate 		internal_pgroup_free(pg);
344*0Sstevel@tonic-gate 
345*0Sstevel@tonic-gate 	cookie = NULL;
346*0Sstevel@tonic-gate 	while ((pg = uu_list_teardown(i->sc_dependents, &cookie)) != NULL)
347*0Sstevel@tonic-gate 		internal_pgroup_free(pg);
348*0Sstevel@tonic-gate 
349*0Sstevel@tonic-gate 	free(i);
350*0Sstevel@tonic-gate }
351*0Sstevel@tonic-gate 
352*0Sstevel@tonic-gate entity_t *
353*0Sstevel@tonic-gate internal_template_new()
354*0Sstevel@tonic-gate {
355*0Sstevel@tonic-gate 	entity_t *t;
356*0Sstevel@tonic-gate 
357*0Sstevel@tonic-gate 	if ((t = uu_zalloc(sizeof (entity_t))) == NULL)
358*0Sstevel@tonic-gate 		uu_die(gettext("couldn't allocate memory"));
359*0Sstevel@tonic-gate 
360*0Sstevel@tonic-gate 	uu_list_node_init(t, &t->sc_node, entity_pool);
361*0Sstevel@tonic-gate 
362*0Sstevel@tonic-gate 	t->sc_etype = SVCCFG_TEMPLATE_OBJECT;
363*0Sstevel@tonic-gate 	t->sc_pgroups = uu_list_create(pgroup_pool, t, 0);
364*0Sstevel@tonic-gate 
365*0Sstevel@tonic-gate 	return (t);
366*0Sstevel@tonic-gate }
367*0Sstevel@tonic-gate 
368*0Sstevel@tonic-gate pgroup_t *
369*0Sstevel@tonic-gate internal_pgroup_new()
370*0Sstevel@tonic-gate {
371*0Sstevel@tonic-gate 	pgroup_t *p;
372*0Sstevel@tonic-gate 
373*0Sstevel@tonic-gate 	if ((p = uu_zalloc(sizeof (pgroup_t))) == NULL)
374*0Sstevel@tonic-gate 		uu_die(gettext("couldn't allocate memory"));
375*0Sstevel@tonic-gate 
376*0Sstevel@tonic-gate 	uu_list_node_init(p, &p->sc_node, pgroup_pool);
377*0Sstevel@tonic-gate 
378*0Sstevel@tonic-gate 	p->sc_pgroup_props = uu_list_create(property_pool, p, UU_LIST_SORTED);
379*0Sstevel@tonic-gate 	p->sc_pgroup_name = "<unset>";
380*0Sstevel@tonic-gate 	p->sc_pgroup_type = "<unset>";
381*0Sstevel@tonic-gate 
382*0Sstevel@tonic-gate 	return (p);
383*0Sstevel@tonic-gate }
384*0Sstevel@tonic-gate 
385*0Sstevel@tonic-gate void
386*0Sstevel@tonic-gate internal_pgroup_free(pgroup_t *pg)
387*0Sstevel@tonic-gate {
388*0Sstevel@tonic-gate 	property_t *prop;
389*0Sstevel@tonic-gate 	void *cookie = NULL;
390*0Sstevel@tonic-gate 
391*0Sstevel@tonic-gate 	while ((prop = uu_list_teardown(pg->sc_pgroup_props, &cookie)) != NULL)
392*0Sstevel@tonic-gate 		internal_property_free(prop);
393*0Sstevel@tonic-gate 
394*0Sstevel@tonic-gate 	free(pg);
395*0Sstevel@tonic-gate }
396*0Sstevel@tonic-gate 
397*0Sstevel@tonic-gate static pgroup_t *
398*0Sstevel@tonic-gate find_pgroup(uu_list_t *list, const char *name, const char *type)
399*0Sstevel@tonic-gate {
400*0Sstevel@tonic-gate 	pgroup_t *pg;
401*0Sstevel@tonic-gate 
402*0Sstevel@tonic-gate 	for (pg = uu_list_first(list);
403*0Sstevel@tonic-gate 	    pg != NULL;
404*0Sstevel@tonic-gate 	    pg = uu_list_next(list, pg)) {
405*0Sstevel@tonic-gate 		if (strcmp(pg->sc_pgroup_name, name) != 0)
406*0Sstevel@tonic-gate 			continue;
407*0Sstevel@tonic-gate 
408*0Sstevel@tonic-gate 		if (type == NULL)
409*0Sstevel@tonic-gate 			return (pg);
410*0Sstevel@tonic-gate 
411*0Sstevel@tonic-gate 		if (strcmp(pg->sc_pgroup_type, type) == 0)
412*0Sstevel@tonic-gate 			return (pg);
413*0Sstevel@tonic-gate 	}
414*0Sstevel@tonic-gate 
415*0Sstevel@tonic-gate 	return (NULL);
416*0Sstevel@tonic-gate }
417*0Sstevel@tonic-gate 
418*0Sstevel@tonic-gate pgroup_t *
419*0Sstevel@tonic-gate internal_dependent_find(entity_t *e, const char *name)
420*0Sstevel@tonic-gate {
421*0Sstevel@tonic-gate 	return (find_pgroup(e->sc_dependents, name, NULL));
422*0Sstevel@tonic-gate }
423*0Sstevel@tonic-gate 
424*0Sstevel@tonic-gate pgroup_t *
425*0Sstevel@tonic-gate internal_pgroup_find(entity_t *e, const char *name, const char *type)
426*0Sstevel@tonic-gate {
427*0Sstevel@tonic-gate 	return (find_pgroup(e->sc_pgroups, name, type));
428*0Sstevel@tonic-gate }
429*0Sstevel@tonic-gate 
430*0Sstevel@tonic-gate pgroup_t *
431*0Sstevel@tonic-gate internal_pgroup_find_or_create(entity_t *e, const char *name, const char *type)
432*0Sstevel@tonic-gate {
433*0Sstevel@tonic-gate 	pgroup_t *pg;
434*0Sstevel@tonic-gate 
435*0Sstevel@tonic-gate 	pg = internal_pgroup_find(e, name, type);
436*0Sstevel@tonic-gate 	if (pg != NULL)
437*0Sstevel@tonic-gate 		return (pg);
438*0Sstevel@tonic-gate 
439*0Sstevel@tonic-gate 	pg = internal_pgroup_new();
440*0Sstevel@tonic-gate 	(void) internal_attach_pgroup(e, pg);
441*0Sstevel@tonic-gate 	pg->sc_pgroup_name = strdup(name);
442*0Sstevel@tonic-gate 	pg->sc_pgroup_type = strdup(type);
443*0Sstevel@tonic-gate 	pg->sc_pgroup_flags = 0;
444*0Sstevel@tonic-gate 
445*0Sstevel@tonic-gate 	if (pg->sc_pgroup_name == NULL || pg->sc_pgroup_type == NULL)
446*0Sstevel@tonic-gate 		uu_die(gettext("Could not duplicate string"));
447*0Sstevel@tonic-gate 
448*0Sstevel@tonic-gate 	return (pg);
449*0Sstevel@tonic-gate }
450*0Sstevel@tonic-gate 
451*0Sstevel@tonic-gate property_t *
452*0Sstevel@tonic-gate internal_property_new()
453*0Sstevel@tonic-gate {
454*0Sstevel@tonic-gate 	property_t *p;
455*0Sstevel@tonic-gate 
456*0Sstevel@tonic-gate 	if ((p = uu_zalloc(sizeof (property_t))) == NULL)
457*0Sstevel@tonic-gate 		uu_die(gettext("couldn't allocate memory"));
458*0Sstevel@tonic-gate 
459*0Sstevel@tonic-gate 	uu_list_node_init(p, &p->sc_node, property_pool);
460*0Sstevel@tonic-gate 
461*0Sstevel@tonic-gate 	p->sc_property_values = uu_list_create(value_pool, p, UU_LIST_SORTED);
462*0Sstevel@tonic-gate 	p->sc_property_name = "<unset>";
463*0Sstevel@tonic-gate 
464*0Sstevel@tonic-gate 	return (p);
465*0Sstevel@tonic-gate }
466*0Sstevel@tonic-gate 
467*0Sstevel@tonic-gate void
468*0Sstevel@tonic-gate internal_property_free(property_t *p)
469*0Sstevel@tonic-gate {
470*0Sstevel@tonic-gate 	value_t *val;
471*0Sstevel@tonic-gate 	void *cookie = NULL;
472*0Sstevel@tonic-gate 
473*0Sstevel@tonic-gate 	while ((val = uu_list_teardown(p->sc_property_values, &cookie)) !=
474*0Sstevel@tonic-gate 	    NULL) {
475*0Sstevel@tonic-gate 		if (val->sc_free != NULL)
476*0Sstevel@tonic-gate 			val->sc_free(val);
477*0Sstevel@tonic-gate 		free(val);
478*0Sstevel@tonic-gate 	}
479*0Sstevel@tonic-gate 
480*0Sstevel@tonic-gate 	free(p);
481*0Sstevel@tonic-gate }
482*0Sstevel@tonic-gate 
483*0Sstevel@tonic-gate property_t *
484*0Sstevel@tonic-gate internal_property_find(pgroup_t *pg, const char *name)
485*0Sstevel@tonic-gate {
486*0Sstevel@tonic-gate 	property_t *p;
487*0Sstevel@tonic-gate 
488*0Sstevel@tonic-gate 	for (p = uu_list_first(pg->sc_pgroup_props);
489*0Sstevel@tonic-gate 	    p != NULL;
490*0Sstevel@tonic-gate 	    p = uu_list_next(pg->sc_pgroup_props, p))
491*0Sstevel@tonic-gate 		if (strcmp(p->sc_property_name, name) == 0)
492*0Sstevel@tonic-gate 			return (p);
493*0Sstevel@tonic-gate 
494*0Sstevel@tonic-gate 	return (NULL);
495*0Sstevel@tonic-gate }
496*0Sstevel@tonic-gate 
497*0Sstevel@tonic-gate value_t *
498*0Sstevel@tonic-gate internal_value_new()
499*0Sstevel@tonic-gate {
500*0Sstevel@tonic-gate 	value_t *v;
501*0Sstevel@tonic-gate 
502*0Sstevel@tonic-gate 	if ((v = uu_zalloc(sizeof (value_t))) == NULL)
503*0Sstevel@tonic-gate 		uu_die(gettext("couldn't allocate memory"));
504*0Sstevel@tonic-gate 
505*0Sstevel@tonic-gate 	uu_list_node_init(v, &v->sc_node, value_pool);
506*0Sstevel@tonic-gate 
507*0Sstevel@tonic-gate 	return (v);
508*0Sstevel@tonic-gate }
509*0Sstevel@tonic-gate 
510*0Sstevel@tonic-gate static void
511*0Sstevel@tonic-gate internal_value_free_str(value_t *v)
512*0Sstevel@tonic-gate {
513*0Sstevel@tonic-gate 	free(v->sc_u.sc_string);
514*0Sstevel@tonic-gate }
515*0Sstevel@tonic-gate 
516*0Sstevel@tonic-gate property_t *
517*0Sstevel@tonic-gate internal_property_create(const char *name, scf_type_t vtype, uint_t nvals, ...)
518*0Sstevel@tonic-gate {
519*0Sstevel@tonic-gate 	va_list args;
520*0Sstevel@tonic-gate 	property_t *p;
521*0Sstevel@tonic-gate 	value_t *v;
522*0Sstevel@tonic-gate 
523*0Sstevel@tonic-gate 	p = internal_property_new();
524*0Sstevel@tonic-gate 
525*0Sstevel@tonic-gate 	p->sc_property_name = (char *)name;
526*0Sstevel@tonic-gate 	p->sc_value_type = vtype;
527*0Sstevel@tonic-gate 
528*0Sstevel@tonic-gate 	va_start(args, nvals);
529*0Sstevel@tonic-gate 	for (; nvals > 0; nvals--) {
530*0Sstevel@tonic-gate 
531*0Sstevel@tonic-gate 		v = internal_value_new();
532*0Sstevel@tonic-gate 		v->sc_type = vtype;
533*0Sstevel@tonic-gate 
534*0Sstevel@tonic-gate 		switch (vtype) {
535*0Sstevel@tonic-gate 		case SCF_TYPE_BOOLEAN:
536*0Sstevel@tonic-gate 		case SCF_TYPE_COUNT:
537*0Sstevel@tonic-gate 			v->sc_u.sc_count = va_arg(args, uint64_t);
538*0Sstevel@tonic-gate 			break;
539*0Sstevel@tonic-gate 		case SCF_TYPE_INTEGER:
540*0Sstevel@tonic-gate 			v->sc_u.sc_integer = va_arg(args, int64_t);
541*0Sstevel@tonic-gate 			break;
542*0Sstevel@tonic-gate 		case SCF_TYPE_ASTRING:
543*0Sstevel@tonic-gate 		case SCF_TYPE_FMRI:
544*0Sstevel@tonic-gate 		case SCF_TYPE_HOST:
545*0Sstevel@tonic-gate 		case SCF_TYPE_HOSTNAME:
546*0Sstevel@tonic-gate 		case SCF_TYPE_NET_ADDR_V4:
547*0Sstevel@tonic-gate 		case SCF_TYPE_NET_ADDR_V6:
548*0Sstevel@tonic-gate 		case SCF_TYPE_OPAQUE:
549*0Sstevel@tonic-gate 		case SCF_TYPE_TIME:
550*0Sstevel@tonic-gate 		case SCF_TYPE_URI:
551*0Sstevel@tonic-gate 		case SCF_TYPE_USTRING:
552*0Sstevel@tonic-gate 			v->sc_u.sc_string = (char *)va_arg(args, uchar_t *);
553*0Sstevel@tonic-gate 			break;
554*0Sstevel@tonic-gate 		default:
555*0Sstevel@tonic-gate 			va_end(args);
556*0Sstevel@tonic-gate 			uu_die(gettext("unknown property type (%d)\n"), vtype);
557*0Sstevel@tonic-gate 			break;
558*0Sstevel@tonic-gate 		}
559*0Sstevel@tonic-gate 
560*0Sstevel@tonic-gate 		internal_attach_value(p, v);
561*0Sstevel@tonic-gate 	}
562*0Sstevel@tonic-gate 	va_end(args);
563*0Sstevel@tonic-gate 
564*0Sstevel@tonic-gate 	return (p);
565*0Sstevel@tonic-gate }
566*0Sstevel@tonic-gate 
567*0Sstevel@tonic-gate /*
568*0Sstevel@tonic-gate  * Some of these attach functions use uu_list_append() to maintain the
569*0Sstevel@tonic-gate  * same order across import/export, whereas others are always sorted
570*0Sstevel@tonic-gate  * anyway, or the order is irrelevant.
571*0Sstevel@tonic-gate  */
572*0Sstevel@tonic-gate 
573*0Sstevel@tonic-gate int
574*0Sstevel@tonic-gate internal_attach_service(bundle_t *bndl, entity_t *svc)
575*0Sstevel@tonic-gate {
576*0Sstevel@tonic-gate 	if (uu_list_find(bndl->sc_bundle_services, svc, NULL, NULL) != NULL) {
577*0Sstevel@tonic-gate 		semerr(gettext("Multiple definitions for service %s in "
578*0Sstevel@tonic-gate 		    "bundle %s.\n"), svc->sc_name, bndl->sc_bundle_name);
579*0Sstevel@tonic-gate 		return (-1);
580*0Sstevel@tonic-gate 	}
581*0Sstevel@tonic-gate 
582*0Sstevel@tonic-gate 	(void) uu_list_append(bndl->sc_bundle_services, svc);
583*0Sstevel@tonic-gate 
584*0Sstevel@tonic-gate 	return (0);
585*0Sstevel@tonic-gate }
586*0Sstevel@tonic-gate 
587*0Sstevel@tonic-gate int
588*0Sstevel@tonic-gate internal_attach_entity(entity_t *svc, entity_t *ent)
589*0Sstevel@tonic-gate {
590*0Sstevel@tonic-gate 	if (ent->sc_etype == SVCCFG_TEMPLATE_OBJECT) {
591*0Sstevel@tonic-gate 		svc->sc_u.sc_service.sc_service_template = ent;
592*0Sstevel@tonic-gate 		return (0);
593*0Sstevel@tonic-gate 	}
594*0Sstevel@tonic-gate 
595*0Sstevel@tonic-gate 	if (svc->sc_etype != SVCCFG_SERVICE_OBJECT)
596*0Sstevel@tonic-gate 		uu_die(gettext("bad entity attach: %s is not a service\n"),
597*0Sstevel@tonic-gate 		    svc->sc_name);
598*0Sstevel@tonic-gate 
599*0Sstevel@tonic-gate 	if (uu_list_find(svc->sc_u.sc_service.sc_service_instances, ent, NULL,
600*0Sstevel@tonic-gate 	    NULL) != NULL) {
601*0Sstevel@tonic-gate 		semerr(gettext("Multiple definitions of entity %s in service "
602*0Sstevel@tonic-gate 		    "%s.\n"), ent->sc_name, svc->sc_name);
603*0Sstevel@tonic-gate 		return (-1);
604*0Sstevel@tonic-gate 	}
605*0Sstevel@tonic-gate 
606*0Sstevel@tonic-gate 	(void) uu_list_prepend(svc->sc_u.sc_service.sc_service_instances, ent);
607*0Sstevel@tonic-gate 	ent->sc_parent = svc;
608*0Sstevel@tonic-gate 	ent->sc_fmri = uu_msprintf("%s:%s", svc->sc_fmri, ent->sc_name);
609*0Sstevel@tonic-gate 	if (ent->sc_fmri == NULL)
610*0Sstevel@tonic-gate 		uu_die(gettext("couldn't allocate memory"));
611*0Sstevel@tonic-gate 
612*0Sstevel@tonic-gate 	return (0);
613*0Sstevel@tonic-gate }
614*0Sstevel@tonic-gate 
615*0Sstevel@tonic-gate int
616*0Sstevel@tonic-gate internal_attach_pgroup(entity_t *ent, pgroup_t *pgrp)
617*0Sstevel@tonic-gate {
618*0Sstevel@tonic-gate 	if (uu_list_find(ent->sc_pgroups, pgrp, NULL, NULL) != NULL) {
619*0Sstevel@tonic-gate 		semerr(gettext("Multiple definitions of property group %s in "
620*0Sstevel@tonic-gate 		    "entity %s.\n"), pgrp->sc_pgroup_name, ent->sc_name);
621*0Sstevel@tonic-gate 		return (-1);
622*0Sstevel@tonic-gate 	}
623*0Sstevel@tonic-gate 
624*0Sstevel@tonic-gate 	(void) uu_list_append(ent->sc_pgroups, pgrp);
625*0Sstevel@tonic-gate 
626*0Sstevel@tonic-gate 	pgrp->sc_parent = ent;
627*0Sstevel@tonic-gate 
628*0Sstevel@tonic-gate 	return (0);
629*0Sstevel@tonic-gate }
630*0Sstevel@tonic-gate 
631*0Sstevel@tonic-gate int
632*0Sstevel@tonic-gate internal_attach_dependent(entity_t *ent, pgroup_t *pg)
633*0Sstevel@tonic-gate {
634*0Sstevel@tonic-gate 	if (uu_list_find(ent->sc_dependents, pg, NULL, NULL) != NULL) {
635*0Sstevel@tonic-gate 		semerr(gettext("Multiple definitions of dependent %s in "
636*0Sstevel@tonic-gate 		    "entity %s.\n"), pg->sc_pgroup_name, ent->sc_name);
637*0Sstevel@tonic-gate 		return (-1);
638*0Sstevel@tonic-gate 	}
639*0Sstevel@tonic-gate 
640*0Sstevel@tonic-gate 	(void) uu_list_append(ent->sc_dependents, pg);
641*0Sstevel@tonic-gate 
642*0Sstevel@tonic-gate 	pg->sc_parent = ent;
643*0Sstevel@tonic-gate 
644*0Sstevel@tonic-gate 	return (0);
645*0Sstevel@tonic-gate }
646*0Sstevel@tonic-gate 
647*0Sstevel@tonic-gate /*
648*0Sstevel@tonic-gate  * Returns
649*0Sstevel@tonic-gate  *   0 - success
650*0Sstevel@tonic-gate  *   -1 - prop already exists in pgrp
651*0Sstevel@tonic-gate  */
652*0Sstevel@tonic-gate int
653*0Sstevel@tonic-gate internal_attach_property(pgroup_t *pgrp, property_t *prop)
654*0Sstevel@tonic-gate {
655*0Sstevel@tonic-gate 	uu_list_index_t idx;
656*0Sstevel@tonic-gate 
657*0Sstevel@tonic-gate 	if (uu_list_find(pgrp->sc_pgroup_props, prop, NULL, &idx) != NULL) {
658*0Sstevel@tonic-gate 		semerr(gettext("Multiple definitions for property %s in "
659*0Sstevel@tonic-gate 		    "property group %s.\n"), prop->sc_property_name,
660*0Sstevel@tonic-gate 		    pgrp->sc_pgroup_name);
661*0Sstevel@tonic-gate 		return (-1);
662*0Sstevel@tonic-gate 	}
663*0Sstevel@tonic-gate 
664*0Sstevel@tonic-gate 	uu_list_insert(pgrp->sc_pgroup_props, prop, idx);
665*0Sstevel@tonic-gate 
666*0Sstevel@tonic-gate 	return (0);
667*0Sstevel@tonic-gate }
668*0Sstevel@tonic-gate 
669*0Sstevel@tonic-gate void
670*0Sstevel@tonic-gate internal_attach_value(property_t *prop, value_t *val)
671*0Sstevel@tonic-gate {
672*0Sstevel@tonic-gate 	uu_list_index_t idx;
673*0Sstevel@tonic-gate 
674*0Sstevel@tonic-gate 	(void) uu_list_find(prop->sc_property_values, val, NULL, &idx);
675*0Sstevel@tonic-gate 	uu_list_insert(prop->sc_property_values, val, idx);
676*0Sstevel@tonic-gate }
677*0Sstevel@tonic-gate 
678*0Sstevel@tonic-gate /*
679*0Sstevel@tonic-gate  * These functions create an internal representation of a property group
680*0Sstevel@tonic-gate  * (pgroup_t) from the repository (scf_propertygroup_t).  They are used by the
681*0Sstevel@tonic-gate  * import functions in svccfg_libscf.c .
682*0Sstevel@tonic-gate  *
683*0Sstevel@tonic-gate  * load_init() must be called first to initialize these globals, and
684*0Sstevel@tonic-gate  * load_fini() should be called afterwards to destroy them.
685*0Sstevel@tonic-gate  */
686*0Sstevel@tonic-gate 
687*0Sstevel@tonic-gate static char *loadbuf = NULL;
688*0Sstevel@tonic-gate static size_t loadbuf_sz;
689*0Sstevel@tonic-gate static scf_property_t *load_prop = NULL;
690*0Sstevel@tonic-gate static scf_value_t *load_val = NULL;
691*0Sstevel@tonic-gate static scf_iter_t *load_propiter = NULL, *load_valiter = NULL;
692*0Sstevel@tonic-gate 
693*0Sstevel@tonic-gate /*
694*0Sstevel@tonic-gate  * Initialize the global state for the load_*() routines.
695*0Sstevel@tonic-gate  * Returns
696*0Sstevel@tonic-gate  *   0 - success
697*0Sstevel@tonic-gate  *   ENOMEM - out of memory
698*0Sstevel@tonic-gate  */
699*0Sstevel@tonic-gate int
700*0Sstevel@tonic-gate load_init(void)
701*0Sstevel@tonic-gate {
702*0Sstevel@tonic-gate 	loadbuf_sz = ((max_scf_value_len > max_scf_pg_type_len) ?
703*0Sstevel@tonic-gate 	    max_scf_value_len : max_scf_pg_type_len) + 1;
704*0Sstevel@tonic-gate 
705*0Sstevel@tonic-gate 	loadbuf = malloc(loadbuf_sz);
706*0Sstevel@tonic-gate 	if (loadbuf == NULL)
707*0Sstevel@tonic-gate 		return (ENOMEM);
708*0Sstevel@tonic-gate 
709*0Sstevel@tonic-gate 	if ((load_prop = scf_property_create(g_hndl)) == NULL ||
710*0Sstevel@tonic-gate 	    (load_val = scf_value_create(g_hndl)) == NULL ||
711*0Sstevel@tonic-gate 	    (load_propiter = scf_iter_create(g_hndl)) == NULL ||
712*0Sstevel@tonic-gate 	    (load_valiter = scf_iter_create(g_hndl)) == NULL) {
713*0Sstevel@tonic-gate 		load_fini();
714*0Sstevel@tonic-gate 		return (ENOMEM);
715*0Sstevel@tonic-gate 	}
716*0Sstevel@tonic-gate 
717*0Sstevel@tonic-gate 	return (0);
718*0Sstevel@tonic-gate }
719*0Sstevel@tonic-gate 
720*0Sstevel@tonic-gate void
721*0Sstevel@tonic-gate load_fini(void)
722*0Sstevel@tonic-gate {
723*0Sstevel@tonic-gate 	scf_iter_destroy(load_propiter);
724*0Sstevel@tonic-gate 	load_propiter = NULL;
725*0Sstevel@tonic-gate 	scf_iter_destroy(load_valiter);
726*0Sstevel@tonic-gate 	load_valiter = NULL;
727*0Sstevel@tonic-gate 	scf_value_destroy(load_val);
728*0Sstevel@tonic-gate 	load_val = NULL;
729*0Sstevel@tonic-gate 	scf_property_destroy(load_prop);
730*0Sstevel@tonic-gate 	load_prop = NULL;
731*0Sstevel@tonic-gate 	free(loadbuf);
732*0Sstevel@tonic-gate 	loadbuf = NULL;
733*0Sstevel@tonic-gate }
734*0Sstevel@tonic-gate 
735*0Sstevel@tonic-gate /*
736*0Sstevel@tonic-gate  * Create a property_t which represents an scf_property_t.  Returns
737*0Sstevel@tonic-gate  *   0 - success
738*0Sstevel@tonic-gate  *   ECANCELED - prop's pg was deleted
739*0Sstevel@tonic-gate  *   ECONNABORTED - repository disconnected
740*0Sstevel@tonic-gate  *   ENOMEM - out of memory
741*0Sstevel@tonic-gate  */
742*0Sstevel@tonic-gate static int
743*0Sstevel@tonic-gate load_property(scf_property_t *prop, property_t **ipp)
744*0Sstevel@tonic-gate {
745*0Sstevel@tonic-gate 	property_t *iprop;
746*0Sstevel@tonic-gate 	int r;
747*0Sstevel@tonic-gate 	ssize_t ssz;
748*0Sstevel@tonic-gate 
749*0Sstevel@tonic-gate 	/* get name */
750*0Sstevel@tonic-gate 	if (scf_property_get_name(prop, loadbuf, loadbuf_sz) < 0) {
751*0Sstevel@tonic-gate 		switch (scf_error()) {
752*0Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
753*0Sstevel@tonic-gate 			return (ECANCELED);
754*0Sstevel@tonic-gate 
755*0Sstevel@tonic-gate 		case SCF_ERROR_CONNECTION_BROKEN:
756*0Sstevel@tonic-gate 			return (ECONNABORTED);
757*0Sstevel@tonic-gate 
758*0Sstevel@tonic-gate 		case SCF_ERROR_NOT_BOUND:
759*0Sstevel@tonic-gate 		case SCF_ERROR_NOT_SET:
760*0Sstevel@tonic-gate 		default:
761*0Sstevel@tonic-gate 			bad_error("scf_property_get_name", scf_error());
762*0Sstevel@tonic-gate 		}
763*0Sstevel@tonic-gate 	}
764*0Sstevel@tonic-gate 
765*0Sstevel@tonic-gate 	iprop = internal_property_new();
766*0Sstevel@tonic-gate 	iprop->sc_property_name = strdup(loadbuf);
767*0Sstevel@tonic-gate 	if (iprop->sc_property_name == NULL) {
768*0Sstevel@tonic-gate 		internal_property_free(iprop);
769*0Sstevel@tonic-gate 		return (ENOMEM);
770*0Sstevel@tonic-gate 	}
771*0Sstevel@tonic-gate 
772*0Sstevel@tonic-gate 	/* get type */
773*0Sstevel@tonic-gate 	if (scf_property_type(prop, &iprop->sc_value_type) != 0) {
774*0Sstevel@tonic-gate 		switch (scf_error()) {
775*0Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
776*0Sstevel@tonic-gate 			r = ECANCELED;
777*0Sstevel@tonic-gate 			goto out;
778*0Sstevel@tonic-gate 
779*0Sstevel@tonic-gate 		case SCF_ERROR_CONNECTION_BROKEN:
780*0Sstevel@tonic-gate 			r = ECONNABORTED;
781*0Sstevel@tonic-gate 			goto out;
782*0Sstevel@tonic-gate 
783*0Sstevel@tonic-gate 		case SCF_ERROR_NOT_BOUND:
784*0Sstevel@tonic-gate 		case SCF_ERROR_NOT_SET:
785*0Sstevel@tonic-gate 		default:
786*0Sstevel@tonic-gate 			bad_error("scf_property_type", scf_error());
787*0Sstevel@tonic-gate 		}
788*0Sstevel@tonic-gate 	}
789*0Sstevel@tonic-gate 
790*0Sstevel@tonic-gate 	/* get values */
791*0Sstevel@tonic-gate 	if (scf_iter_property_values(load_valiter, prop) != 0) {
792*0Sstevel@tonic-gate 		switch (scf_error()) {
793*0Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
794*0Sstevel@tonic-gate 			r = ECANCELED;
795*0Sstevel@tonic-gate 			goto out;
796*0Sstevel@tonic-gate 
797*0Sstevel@tonic-gate 		case SCF_ERROR_CONNECTION_BROKEN:
798*0Sstevel@tonic-gate 			r = ECONNABORTED;
799*0Sstevel@tonic-gate 			goto out;
800*0Sstevel@tonic-gate 
801*0Sstevel@tonic-gate 		case SCF_ERROR_HANDLE_MISMATCH:
802*0Sstevel@tonic-gate 		case SCF_ERROR_NOT_BOUND:
803*0Sstevel@tonic-gate 		case SCF_ERROR_NOT_SET:
804*0Sstevel@tonic-gate 		default:
805*0Sstevel@tonic-gate 			bad_error("scf_iter_property_values", scf_error());
806*0Sstevel@tonic-gate 		}
807*0Sstevel@tonic-gate 	}
808*0Sstevel@tonic-gate 
809*0Sstevel@tonic-gate 	for (;;) {
810*0Sstevel@tonic-gate 		value_t *ival;
811*0Sstevel@tonic-gate 
812*0Sstevel@tonic-gate 		r = scf_iter_next_value(load_valiter, load_val);
813*0Sstevel@tonic-gate 		if (r == 0)
814*0Sstevel@tonic-gate 			break;
815*0Sstevel@tonic-gate 		if (r != 1) {
816*0Sstevel@tonic-gate 			switch (scf_error()) {
817*0Sstevel@tonic-gate 			case SCF_ERROR_DELETED:
818*0Sstevel@tonic-gate 				r = ECANCELED;
819*0Sstevel@tonic-gate 				goto out;
820*0Sstevel@tonic-gate 
821*0Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
822*0Sstevel@tonic-gate 				r = ECONNABORTED;
823*0Sstevel@tonic-gate 				goto out;
824*0Sstevel@tonic-gate 
825*0Sstevel@tonic-gate 			case SCF_ERROR_HANDLE_MISMATCH:
826*0Sstevel@tonic-gate 			case SCF_ERROR_NOT_BOUND:
827*0Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
828*0Sstevel@tonic-gate 			case SCF_ERROR_INVALID_ARGUMENT:
829*0Sstevel@tonic-gate 			default:
830*0Sstevel@tonic-gate 				bad_error("scf_iter_next_value", scf_error());
831*0Sstevel@tonic-gate 			}
832*0Sstevel@tonic-gate 		}
833*0Sstevel@tonic-gate 
834*0Sstevel@tonic-gate 		ival = internal_value_new();
835*0Sstevel@tonic-gate 		ival->sc_type = scf_value_type(load_val);
836*0Sstevel@tonic-gate 		assert(ival->sc_type != SCF_TYPE_INVALID);
837*0Sstevel@tonic-gate 
838*0Sstevel@tonic-gate 		switch (ival->sc_type) {
839*0Sstevel@tonic-gate 		case SCF_TYPE_BOOLEAN: {
840*0Sstevel@tonic-gate 			uint8_t b;
841*0Sstevel@tonic-gate 
842*0Sstevel@tonic-gate 			r = scf_value_get_boolean(load_val, &b);
843*0Sstevel@tonic-gate 			if (r != 0)
844*0Sstevel@tonic-gate 				bad_error("scf_value_get_boolean", scf_error());
845*0Sstevel@tonic-gate 			ival->sc_u.sc_count = b;
846*0Sstevel@tonic-gate 			break;
847*0Sstevel@tonic-gate 		}
848*0Sstevel@tonic-gate 
849*0Sstevel@tonic-gate 		case SCF_TYPE_COUNT:
850*0Sstevel@tonic-gate 			r = scf_value_get_count(load_val, &ival->sc_u.sc_count);
851*0Sstevel@tonic-gate 			if (r != 0)
852*0Sstevel@tonic-gate 				bad_error("scf_value_get_count", scf_error());
853*0Sstevel@tonic-gate 			break;
854*0Sstevel@tonic-gate 
855*0Sstevel@tonic-gate 		case SCF_TYPE_INTEGER:
856*0Sstevel@tonic-gate 			r = scf_value_get_integer(load_val,
857*0Sstevel@tonic-gate 			    &ival->sc_u.sc_integer);
858*0Sstevel@tonic-gate 			if (r != 0)
859*0Sstevel@tonic-gate 				bad_error("scf_value_get_integer", scf_error());
860*0Sstevel@tonic-gate 			break;
861*0Sstevel@tonic-gate 
862*0Sstevel@tonic-gate 		default:
863*0Sstevel@tonic-gate 			ssz = scf_value_get_as_string(load_val, loadbuf,
864*0Sstevel@tonic-gate 			    loadbuf_sz);
865*0Sstevel@tonic-gate 			if (ssz < 0)
866*0Sstevel@tonic-gate 				bad_error("scf_value_get_as_string",
867*0Sstevel@tonic-gate 				    scf_error());
868*0Sstevel@tonic-gate 
869*0Sstevel@tonic-gate 			ival->sc_u.sc_string = strdup(loadbuf);
870*0Sstevel@tonic-gate 			if (ival->sc_u.sc_string == NULL) {
871*0Sstevel@tonic-gate 				r = ENOMEM;
872*0Sstevel@tonic-gate 				goto out;
873*0Sstevel@tonic-gate 			}
874*0Sstevel@tonic-gate 
875*0Sstevel@tonic-gate 			ival->sc_free = internal_value_free_str;
876*0Sstevel@tonic-gate 		}
877*0Sstevel@tonic-gate 
878*0Sstevel@tonic-gate 		internal_attach_value(iprop, ival);
879*0Sstevel@tonic-gate 	}
880*0Sstevel@tonic-gate 
881*0Sstevel@tonic-gate 	*ipp = iprop;
882*0Sstevel@tonic-gate 	return (0);
883*0Sstevel@tonic-gate 
884*0Sstevel@tonic-gate out:
885*0Sstevel@tonic-gate 	free(iprop->sc_property_name);
886*0Sstevel@tonic-gate 	internal_property_free(iprop);
887*0Sstevel@tonic-gate 	return (r);
888*0Sstevel@tonic-gate }
889*0Sstevel@tonic-gate 
890*0Sstevel@tonic-gate /*
891*0Sstevel@tonic-gate  * Returns
892*0Sstevel@tonic-gate  *   0 - success
893*0Sstevel@tonic-gate  *   ECANCELED - pg was deleted
894*0Sstevel@tonic-gate  *   ECONNABORTED - repository disconnected
895*0Sstevel@tonic-gate  *   ENOMEM - out of memory
896*0Sstevel@tonic-gate  */
897*0Sstevel@tonic-gate int
898*0Sstevel@tonic-gate load_pg_attrs(const scf_propertygroup_t *pg, pgroup_t **ipgp)
899*0Sstevel@tonic-gate {
900*0Sstevel@tonic-gate 	pgroup_t *ipg;
901*0Sstevel@tonic-gate 
902*0Sstevel@tonic-gate 	ipg = internal_pgroup_new();
903*0Sstevel@tonic-gate 
904*0Sstevel@tonic-gate 	if (scf_pg_get_flags(pg, &ipg->sc_pgroup_flags) != 0) {
905*0Sstevel@tonic-gate 		switch (scf_error()) {
906*0Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
907*0Sstevel@tonic-gate 			internal_pgroup_free(ipg);
908*0Sstevel@tonic-gate 			return (ECANCELED);
909*0Sstevel@tonic-gate 
910*0Sstevel@tonic-gate 		case SCF_ERROR_CONNECTION_BROKEN:
911*0Sstevel@tonic-gate 			internal_pgroup_free(ipg);
912*0Sstevel@tonic-gate 			return (ECONNABORTED);
913*0Sstevel@tonic-gate 
914*0Sstevel@tonic-gate 		case SCF_ERROR_NOT_SET:
915*0Sstevel@tonic-gate 		case SCF_ERROR_NOT_BOUND:
916*0Sstevel@tonic-gate 		default:
917*0Sstevel@tonic-gate 			bad_error("scf_pg_get_name", scf_error());
918*0Sstevel@tonic-gate 		}
919*0Sstevel@tonic-gate 	}
920*0Sstevel@tonic-gate 
921*0Sstevel@tonic-gate 	if (scf_pg_get_name(pg, loadbuf, loadbuf_sz) < 0) {
922*0Sstevel@tonic-gate 		switch (scf_error()) {
923*0Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
924*0Sstevel@tonic-gate 			internal_pgroup_free(ipg);
925*0Sstevel@tonic-gate 			return (ECANCELED);
926*0Sstevel@tonic-gate 
927*0Sstevel@tonic-gate 		case SCF_ERROR_CONNECTION_BROKEN:
928*0Sstevel@tonic-gate 			internal_pgroup_free(ipg);
929*0Sstevel@tonic-gate 			return (ECONNABORTED);
930*0Sstevel@tonic-gate 
931*0Sstevel@tonic-gate 		case SCF_ERROR_NOT_SET:
932*0Sstevel@tonic-gate 		case SCF_ERROR_NOT_BOUND:
933*0Sstevel@tonic-gate 		default:
934*0Sstevel@tonic-gate 			bad_error("scf_pg_get_name", scf_error());
935*0Sstevel@tonic-gate 		}
936*0Sstevel@tonic-gate 	}
937*0Sstevel@tonic-gate 
938*0Sstevel@tonic-gate 	ipg->sc_pgroup_name = strdup(loadbuf);
939*0Sstevel@tonic-gate 	if (ipg->sc_pgroup_name == NULL) {
940*0Sstevel@tonic-gate 		internal_pgroup_free(ipg);
941*0Sstevel@tonic-gate 		return (ENOMEM);
942*0Sstevel@tonic-gate 	}
943*0Sstevel@tonic-gate 
944*0Sstevel@tonic-gate 	if (scf_pg_get_type(pg, loadbuf, loadbuf_sz) < 0) {
945*0Sstevel@tonic-gate 		switch (scf_error()) {
946*0Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
947*0Sstevel@tonic-gate 			free((char *)ipg->sc_pgroup_name);
948*0Sstevel@tonic-gate 			internal_pgroup_free(ipg);
949*0Sstevel@tonic-gate 			return (ECANCELED);
950*0Sstevel@tonic-gate 
951*0Sstevel@tonic-gate 		case SCF_ERROR_CONNECTION_BROKEN:
952*0Sstevel@tonic-gate 			free((char *)ipg->sc_pgroup_name);
953*0Sstevel@tonic-gate 			internal_pgroup_free(ipg);
954*0Sstevel@tonic-gate 			return (ECONNABORTED);
955*0Sstevel@tonic-gate 
956*0Sstevel@tonic-gate 		case SCF_ERROR_NOT_SET:
957*0Sstevel@tonic-gate 		case SCF_ERROR_NOT_BOUND:
958*0Sstevel@tonic-gate 		default:
959*0Sstevel@tonic-gate 			bad_error("scf_pg_get_name", scf_error());
960*0Sstevel@tonic-gate 		}
961*0Sstevel@tonic-gate 	}
962*0Sstevel@tonic-gate 
963*0Sstevel@tonic-gate 	ipg->sc_pgroup_type = strdup(loadbuf);
964*0Sstevel@tonic-gate 	if (ipg->sc_pgroup_type == NULL) {
965*0Sstevel@tonic-gate 		free((char *)ipg->sc_pgroup_name);
966*0Sstevel@tonic-gate 		internal_pgroup_free(ipg);
967*0Sstevel@tonic-gate 		return (ENOMEM);
968*0Sstevel@tonic-gate 	}
969*0Sstevel@tonic-gate 
970*0Sstevel@tonic-gate 	*ipgp = ipg;
971*0Sstevel@tonic-gate 	return (0);
972*0Sstevel@tonic-gate }
973*0Sstevel@tonic-gate 
974*0Sstevel@tonic-gate /*
975*0Sstevel@tonic-gate  * Load a property group into a pgroup_t.  Returns
976*0Sstevel@tonic-gate  *   0 - success
977*0Sstevel@tonic-gate  *   ECANCELED - pg was deleted
978*0Sstevel@tonic-gate  *   ECONNABORTED - repository disconnected
979*0Sstevel@tonic-gate  *   EBADF - pg is corrupt (error printed if fmri is given)
980*0Sstevel@tonic-gate  *   ENOMEM - out of memory
981*0Sstevel@tonic-gate  */
982*0Sstevel@tonic-gate int
983*0Sstevel@tonic-gate load_pg(const scf_propertygroup_t *pg, pgroup_t **ipgp, const char *fmri,
984*0Sstevel@tonic-gate     const char *snapname)
985*0Sstevel@tonic-gate {
986*0Sstevel@tonic-gate 	pgroup_t *ipg;
987*0Sstevel@tonic-gate 	int r;
988*0Sstevel@tonic-gate 
989*0Sstevel@tonic-gate 	if (scf_iter_pg_properties(load_propiter, pg) != 0) {
990*0Sstevel@tonic-gate 		switch (scf_error()) {
991*0Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
992*0Sstevel@tonic-gate 			return (ECANCELED);
993*0Sstevel@tonic-gate 
994*0Sstevel@tonic-gate 		case SCF_ERROR_CONNECTION_BROKEN:
995*0Sstevel@tonic-gate 			return (ECONNABORTED);
996*0Sstevel@tonic-gate 
997*0Sstevel@tonic-gate 		case SCF_ERROR_HANDLE_MISMATCH:
998*0Sstevel@tonic-gate 		case SCF_ERROR_NOT_SET:
999*0Sstevel@tonic-gate 		case SCF_ERROR_NOT_BOUND:
1000*0Sstevel@tonic-gate 		default:
1001*0Sstevel@tonic-gate 			bad_error("scf_iter_pg_properties", scf_error());
1002*0Sstevel@tonic-gate 		}
1003*0Sstevel@tonic-gate 	}
1004*0Sstevel@tonic-gate 
1005*0Sstevel@tonic-gate 	r = load_pg_attrs(pg, &ipg);
1006*0Sstevel@tonic-gate 	switch (r) {
1007*0Sstevel@tonic-gate 	case 0:
1008*0Sstevel@tonic-gate 		break;
1009*0Sstevel@tonic-gate 
1010*0Sstevel@tonic-gate 	case ECANCELED:
1011*0Sstevel@tonic-gate 	case ECONNABORTED:
1012*0Sstevel@tonic-gate 	case ENOMEM:
1013*0Sstevel@tonic-gate 		return (r);
1014*0Sstevel@tonic-gate 
1015*0Sstevel@tonic-gate 	default:
1016*0Sstevel@tonic-gate 		bad_error("load_pg_attrs", r);
1017*0Sstevel@tonic-gate 	}
1018*0Sstevel@tonic-gate 
1019*0Sstevel@tonic-gate 	for (;;) {
1020*0Sstevel@tonic-gate 		property_t *iprop;
1021*0Sstevel@tonic-gate 
1022*0Sstevel@tonic-gate 		r = scf_iter_next_property(load_propiter, load_prop);
1023*0Sstevel@tonic-gate 		if (r == 0)
1024*0Sstevel@tonic-gate 			break;
1025*0Sstevel@tonic-gate 		if (r != 1) {
1026*0Sstevel@tonic-gate 			switch (scf_error()) {
1027*0Sstevel@tonic-gate 			case SCF_ERROR_DELETED:
1028*0Sstevel@tonic-gate 				r = ECANCELED;
1029*0Sstevel@tonic-gate 				goto out;
1030*0Sstevel@tonic-gate 
1031*0Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
1032*0Sstevel@tonic-gate 				r = ECONNABORTED;
1033*0Sstevel@tonic-gate 				goto out;
1034*0Sstevel@tonic-gate 
1035*0Sstevel@tonic-gate 			case SCF_ERROR_HANDLE_MISMATCH:
1036*0Sstevel@tonic-gate 			case SCF_ERROR_NOT_BOUND:
1037*0Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
1038*0Sstevel@tonic-gate 			case SCF_ERROR_INVALID_ARGUMENT:
1039*0Sstevel@tonic-gate 			default:
1040*0Sstevel@tonic-gate 				bad_error("scf_iter_next_property",
1041*0Sstevel@tonic-gate 				    scf_error());
1042*0Sstevel@tonic-gate 			}
1043*0Sstevel@tonic-gate 		}
1044*0Sstevel@tonic-gate 
1045*0Sstevel@tonic-gate 		r = load_property(load_prop, &iprop);
1046*0Sstevel@tonic-gate 		switch (r) {
1047*0Sstevel@tonic-gate 		case 0:
1048*0Sstevel@tonic-gate 			break;
1049*0Sstevel@tonic-gate 
1050*0Sstevel@tonic-gate 		case ECANCELED:
1051*0Sstevel@tonic-gate 		case ECONNABORTED:
1052*0Sstevel@tonic-gate 		case ENOMEM:
1053*0Sstevel@tonic-gate 			goto out;
1054*0Sstevel@tonic-gate 
1055*0Sstevel@tonic-gate 		default:
1056*0Sstevel@tonic-gate 			bad_error("load_property", r);
1057*0Sstevel@tonic-gate 		}
1058*0Sstevel@tonic-gate 
1059*0Sstevel@tonic-gate 		r = internal_attach_property(ipg, iprop);
1060*0Sstevel@tonic-gate 		if (r != 0) {
1061*0Sstevel@tonic-gate 			if (fmri != NULL) {
1062*0Sstevel@tonic-gate 				if (snapname == NULL)
1063*0Sstevel@tonic-gate 					warn(gettext("Property group \"%s\" of "
1064*0Sstevel@tonic-gate 					    "%s has multiple definitions of "
1065*0Sstevel@tonic-gate 					    "property \"%s\".\n"),
1066*0Sstevel@tonic-gate 					    ipg->sc_pgroup_name, fmri,
1067*0Sstevel@tonic-gate 					    iprop->sc_property_name);
1068*0Sstevel@tonic-gate 				else
1069*0Sstevel@tonic-gate 					warn(gettext("Property group \"%s\" of "
1070*0Sstevel@tonic-gate 					    "the \"%s\" snapshot of %s has "
1071*0Sstevel@tonic-gate 					    "multiple definitions of property "
1072*0Sstevel@tonic-gate 					    "\"%s\".\n"),
1073*0Sstevel@tonic-gate 					    ipg->sc_pgroup_name, snapname, fmri,
1074*0Sstevel@tonic-gate 					    iprop->sc_property_name);
1075*0Sstevel@tonic-gate 			}
1076*0Sstevel@tonic-gate 			r = EBADF;
1077*0Sstevel@tonic-gate 			goto out;
1078*0Sstevel@tonic-gate 		}
1079*0Sstevel@tonic-gate 	}
1080*0Sstevel@tonic-gate 
1081*0Sstevel@tonic-gate 	*ipgp = ipg;
1082*0Sstevel@tonic-gate 	return (0);
1083*0Sstevel@tonic-gate 
1084*0Sstevel@tonic-gate out:
1085*0Sstevel@tonic-gate 	internal_pgroup_free(ipg);
1086*0Sstevel@tonic-gate 	return (r);
1087*0Sstevel@tonic-gate }
1088*0Sstevel@tonic-gate 
1089*0Sstevel@tonic-gate /*
1090*0Sstevel@tonic-gate  * These functions compare internal property groups and properties (pgroup_t
1091*0Sstevel@tonic-gate  * & property_t).  They return 1 if the given structures are equal and
1092*0Sstevel@tonic-gate  * 0 otherwise.  Some will report the differences between the two structures.
1093*0Sstevel@tonic-gate  * They are used by the import functions in svccfg_libscf.c .
1094*0Sstevel@tonic-gate  */
1095*0Sstevel@tonic-gate 
1096*0Sstevel@tonic-gate int
1097*0Sstevel@tonic-gate prop_equal(property_t *p1, property_t *p2, const char *fmri, const char *pgname,
1098*0Sstevel@tonic-gate     int new)
1099*0Sstevel@tonic-gate {
1100*0Sstevel@tonic-gate 	value_t *v1, *v2;
1101*0Sstevel@tonic-gate 
1102*0Sstevel@tonic-gate 	const char * const values_diff = gettext("Conflict upgrading %s "
1103*0Sstevel@tonic-gate 	    "(property \"%s/%s\" has different values).\n");
1104*0Sstevel@tonic-gate 	const char * const values_diff_new = gettext("Conflict upgrading %s "
1105*0Sstevel@tonic-gate 	    "(new property \"%s/%s\" has different values).\n");
1106*0Sstevel@tonic-gate 
1107*0Sstevel@tonic-gate 	assert((fmri == NULL) == (pgname == NULL));
1108*0Sstevel@tonic-gate 
1109*0Sstevel@tonic-gate 	if (fmri != NULL) {
1110*0Sstevel@tonic-gate 		/*
1111*0Sstevel@tonic-gate 		 * If we find any differences, we'll report conflicts.  But
1112*0Sstevel@tonic-gate 		 * conflict messages won't make any sense if the names don't
1113*0Sstevel@tonic-gate 		 * match.  If the caller supplied fmri, assert that the names
1114*0Sstevel@tonic-gate 		 * match.
1115*0Sstevel@tonic-gate 		 */
1116*0Sstevel@tonic-gate 		assert(strcmp(p1->sc_property_name, p2->sc_property_name) == 0);
1117*0Sstevel@tonic-gate 	} else {
1118*0Sstevel@tonic-gate 		if (strcmp(p1->sc_property_name, p2->sc_property_name) != 0)
1119*0Sstevel@tonic-gate 			return (0);
1120*0Sstevel@tonic-gate 	}
1121*0Sstevel@tonic-gate 
1122*0Sstevel@tonic-gate 	if (p1->sc_value_type != p2->sc_value_type) {
1123*0Sstevel@tonic-gate 		if (fmri != NULL) {
1124*0Sstevel@tonic-gate 			if (new)
1125*0Sstevel@tonic-gate 				warn(gettext("Conflict upgrading %s "
1126*0Sstevel@tonic-gate 				    "(new property \"%s/%s\" has different "
1127*0Sstevel@tonic-gate 				    "type).\n"), fmri, pgname,
1128*0Sstevel@tonic-gate 				    p1->sc_property_name);
1129*0Sstevel@tonic-gate 			else
1130*0Sstevel@tonic-gate 				warn(gettext("Conflict upgrading %s "
1131*0Sstevel@tonic-gate 				    "(property \"%s/%s\" has different "
1132*0Sstevel@tonic-gate 				    "type).\n"), fmri, pgname,
1133*0Sstevel@tonic-gate 				    p1->sc_property_name);
1134*0Sstevel@tonic-gate 		}
1135*0Sstevel@tonic-gate 		return (0);
1136*0Sstevel@tonic-gate 	}
1137*0Sstevel@tonic-gate 
1138*0Sstevel@tonic-gate 	if (uu_list_numnodes(p1->sc_property_values) !=
1139*0Sstevel@tonic-gate 	    uu_list_numnodes(p2->sc_property_values)) {
1140*0Sstevel@tonic-gate 		if (fmri != NULL)
1141*0Sstevel@tonic-gate 			warn(new ? values_diff_new : values_diff, fmri,
1142*0Sstevel@tonic-gate 			    pgname, p1->sc_property_name);
1143*0Sstevel@tonic-gate 		return (0);
1144*0Sstevel@tonic-gate 	}
1145*0Sstevel@tonic-gate 
1146*0Sstevel@tonic-gate 	v1 = uu_list_first(p1->sc_property_values);
1147*0Sstevel@tonic-gate 	v2 = uu_list_first(p2->sc_property_values);
1148*0Sstevel@tonic-gate 
1149*0Sstevel@tonic-gate 	while (v1 != NULL) {
1150*0Sstevel@tonic-gate 		assert(v2 != NULL);
1151*0Sstevel@tonic-gate 
1152*0Sstevel@tonic-gate 		if (value_cmp(v1, v2, NULL) != 0) {
1153*0Sstevel@tonic-gate 			if (fmri != NULL)
1154*0Sstevel@tonic-gate 				warn(new ? values_diff_new : values_diff,
1155*0Sstevel@tonic-gate 				    fmri, pgname, p1->sc_property_name);
1156*0Sstevel@tonic-gate 			return (0);
1157*0Sstevel@tonic-gate 		}
1158*0Sstevel@tonic-gate 
1159*0Sstevel@tonic-gate 		v1 = uu_list_next(p1->sc_property_values, v1);
1160*0Sstevel@tonic-gate 		v2 = uu_list_next(p2->sc_property_values, v2);
1161*0Sstevel@tonic-gate 	}
1162*0Sstevel@tonic-gate 
1163*0Sstevel@tonic-gate 	return (1);
1164*0Sstevel@tonic-gate }
1165*0Sstevel@tonic-gate 
1166*0Sstevel@tonic-gate int
1167*0Sstevel@tonic-gate pg_attrs_equal(pgroup_t *pg1, pgroup_t *pg2, const char *fmri, int new)
1168*0Sstevel@tonic-gate {
1169*0Sstevel@tonic-gate 	if (strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) != 0) {
1170*0Sstevel@tonic-gate 		assert(fmri == NULL);
1171*0Sstevel@tonic-gate 		return (0);
1172*0Sstevel@tonic-gate 	}
1173*0Sstevel@tonic-gate 
1174*0Sstevel@tonic-gate 	if (pg1->sc_pgroup_flags != pg2->sc_pgroup_flags) {
1175*0Sstevel@tonic-gate 		if (fmri) {
1176*0Sstevel@tonic-gate 			if (new)
1177*0Sstevel@tonic-gate 				warn(gettext("Conflict upgrading %s "
1178*0Sstevel@tonic-gate 				    "(new property group \"%s\" has different "
1179*0Sstevel@tonic-gate 				    "flags).\n"), fmri, pg1->sc_pgroup_name);
1180*0Sstevel@tonic-gate 			else
1181*0Sstevel@tonic-gate 				warn(gettext("Conflict upgrading %s "
1182*0Sstevel@tonic-gate 				    "(property group \"%s\" has different "
1183*0Sstevel@tonic-gate 				    "flags).\n"), fmri, pg1->sc_pgroup_name);
1184*0Sstevel@tonic-gate 		}
1185*0Sstevel@tonic-gate 		return (0);
1186*0Sstevel@tonic-gate 	}
1187*0Sstevel@tonic-gate 
1188*0Sstevel@tonic-gate 	if (strcmp(pg1->sc_pgroup_type, pg2->sc_pgroup_type) != 0) {
1189*0Sstevel@tonic-gate 		if (fmri) {
1190*0Sstevel@tonic-gate 			if (new)
1191*0Sstevel@tonic-gate 				warn(gettext("Conflict upgrading %s "
1192*0Sstevel@tonic-gate 				    "(new property group \"%s\" has different "
1193*0Sstevel@tonic-gate 				    "type).\n"), fmri, pg1->sc_pgroup_name);
1194*0Sstevel@tonic-gate 			else
1195*0Sstevel@tonic-gate 				warn(gettext("Conflict upgrading %s "
1196*0Sstevel@tonic-gate 				    "(property group \"%s\" has different "
1197*0Sstevel@tonic-gate 				    "type).\n"), fmri, pg1->sc_pgroup_name);
1198*0Sstevel@tonic-gate 		}
1199*0Sstevel@tonic-gate 		return (0);
1200*0Sstevel@tonic-gate 	}
1201*0Sstevel@tonic-gate 
1202*0Sstevel@tonic-gate 	return (1);
1203*0Sstevel@tonic-gate }
1204*0Sstevel@tonic-gate 
1205*0Sstevel@tonic-gate int
1206*0Sstevel@tonic-gate pg_equal(pgroup_t *pg1, pgroup_t *pg2)
1207*0Sstevel@tonic-gate {
1208*0Sstevel@tonic-gate 	property_t *p1, *p2;
1209*0Sstevel@tonic-gate 
1210*0Sstevel@tonic-gate 	if (!pg_attrs_equal(pg1, pg2, NULL, 0))
1211*0Sstevel@tonic-gate 		return (0);
1212*0Sstevel@tonic-gate 
1213*0Sstevel@tonic-gate 	if (uu_list_numnodes(pg1->sc_pgroup_props) !=
1214*0Sstevel@tonic-gate 	    uu_list_numnodes(pg2->sc_pgroup_props))
1215*0Sstevel@tonic-gate 		return (0);
1216*0Sstevel@tonic-gate 
1217*0Sstevel@tonic-gate 	p1 = uu_list_first(pg1->sc_pgroup_props);
1218*0Sstevel@tonic-gate 	p2 = uu_list_first(pg2->sc_pgroup_props);
1219*0Sstevel@tonic-gate 
1220*0Sstevel@tonic-gate 	while (p1 != NULL) {
1221*0Sstevel@tonic-gate 		assert(p2 != NULL);
1222*0Sstevel@tonic-gate 
1223*0Sstevel@tonic-gate 		if (!prop_equal(p1, p2, NULL, NULL, 0))
1224*0Sstevel@tonic-gate 			return (0);
1225*0Sstevel@tonic-gate 
1226*0Sstevel@tonic-gate 		p1 = uu_list_next(pg1->sc_pgroup_props, p1);
1227*0Sstevel@tonic-gate 		p2 = uu_list_next(pg2->sc_pgroup_props, p2);
1228*0Sstevel@tonic-gate 	}
1229*0Sstevel@tonic-gate 
1230*0Sstevel@tonic-gate 	return (1);
1231*0Sstevel@tonic-gate }
1232