xref: /onnv-gate/usr/src/cmd/svc/svccfg/svccfg_xml.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 <libxml/parser.h>
30*0Sstevel@tonic-gate #include <libxml/xinclude.h>
31*0Sstevel@tonic-gate 
32*0Sstevel@tonic-gate #include <assert.h>
33*0Sstevel@tonic-gate #include <ctype.h>
34*0Sstevel@tonic-gate #include <errno.h>
35*0Sstevel@tonic-gate #include <libintl.h>
36*0Sstevel@tonic-gate #include <libuutil.h>
37*0Sstevel@tonic-gate #include <stdlib.h>
38*0Sstevel@tonic-gate #include <string.h>
39*0Sstevel@tonic-gate 
40*0Sstevel@tonic-gate #include "svccfg.h"
41*0Sstevel@tonic-gate 
42*0Sstevel@tonic-gate /*
43*0Sstevel@tonic-gate  * XML document manipulation routines
44*0Sstevel@tonic-gate  *
45*0Sstevel@tonic-gate  * These routines provide translation to and from the internal representation to
46*0Sstevel@tonic-gate  * XML.  Directionally-oriented verbs are with respect to the external source,
47*0Sstevel@tonic-gate  * so lxml_get_service() fetches a service from the XML file into the
48*0Sstevel@tonic-gate  * internal representation.
49*0Sstevel@tonic-gate  */
50*0Sstevel@tonic-gate 
51*0Sstevel@tonic-gate const char * const delete_attr = "delete";
52*0Sstevel@tonic-gate const char * const enabled_attr = "enabled";
53*0Sstevel@tonic-gate const char * const name_attr = "name";
54*0Sstevel@tonic-gate const char * const override_attr = "override";
55*0Sstevel@tonic-gate const char * const type_attr = "type";
56*0Sstevel@tonic-gate const char * const value_attr = "value";
57*0Sstevel@tonic-gate const char * const true = "true";
58*0Sstevel@tonic-gate const char * const false = "false";
59*0Sstevel@tonic-gate 
60*0Sstevel@tonic-gate /*
61*0Sstevel@tonic-gate  * The following list must be kept in the same order as that of
62*0Sstevel@tonic-gate  * element_t array
63*0Sstevel@tonic-gate  */
64*0Sstevel@tonic-gate static const char *lxml_elements[] = {
65*0Sstevel@tonic-gate 	"astring_list",			/* SC_ASTRING */
66*0Sstevel@tonic-gate 	"boolean_list",			/* SC_BOOLEAN */
67*0Sstevel@tonic-gate 	"common_name",			/* SC_COMMON_NAME */
68*0Sstevel@tonic-gate 	"count_list",			/* SC_COUNT */
69*0Sstevel@tonic-gate 	"create_default_instance",	/* SC_INSTANCE_CREATE_DEFAULT */
70*0Sstevel@tonic-gate 	"dependency",			/* SC_DEPENDENCY */
71*0Sstevel@tonic-gate 	"dependent",			/* SC_DEPENDENT */
72*0Sstevel@tonic-gate 	"description",			/* SC_DESCRIPTION */
73*0Sstevel@tonic-gate 	"doc_link",			/* SC_DOC_LINK */
74*0Sstevel@tonic-gate 	"documentation",		/* SC_DOCUMENTATION */
75*0Sstevel@tonic-gate 	"enabled",			/* SC_ENABLED */
76*0Sstevel@tonic-gate 	"exec_method",			/* SC_EXEC_METHOD */
77*0Sstevel@tonic-gate 	"fmri_list",			/* SC_FMRI */
78*0Sstevel@tonic-gate 	"host_list",			/* SC_HOST */
79*0Sstevel@tonic-gate 	"hostname_list",		/* SC_HOSTNAME */
80*0Sstevel@tonic-gate 	"instance",			/* SC_INSTANCE */
81*0Sstevel@tonic-gate 	"integer_list",			/* SC_INTEGER */
82*0Sstevel@tonic-gate 	"loctext",			/* SC_LOCTEXT */
83*0Sstevel@tonic-gate 	"manpage",			/* SC_MANPAGE */
84*0Sstevel@tonic-gate 	"method_context",		/* SC_METHOD_CONTEXT */
85*0Sstevel@tonic-gate 	"method_credential",		/* SC_METHOD_CREDENTIAL */
86*0Sstevel@tonic-gate 	"method_profile",		/* SC_METHOD_PROFILE */
87*0Sstevel@tonic-gate 	"method_environment",		/* SC_METHOD_ENVIRONMENT */
88*0Sstevel@tonic-gate 	"envvar",			/* SC_METHOD_ENVVAR */
89*0Sstevel@tonic-gate 	"net_address_v4_list",		/* SC_NET_ADDR_V4 */
90*0Sstevel@tonic-gate 	"net_address_v6_list",		/* SC_NET_ADDR_V6 */
91*0Sstevel@tonic-gate 	"opaque_list",			/* SC_OPAQUE */
92*0Sstevel@tonic-gate 	"property",			/* SC_PROPERTY */
93*0Sstevel@tonic-gate 	"property_group",		/* SC_PROPERTY_GROUP */
94*0Sstevel@tonic-gate 	"propval",			/* SC_PROPVAL */
95*0Sstevel@tonic-gate 	"restarter",			/* SC_RESTARTER */
96*0Sstevel@tonic-gate 	"service",			/* SC_SERVICE */
97*0Sstevel@tonic-gate 	"service_bundle",		/* SC_SERVICE_BUNDLE */
98*0Sstevel@tonic-gate 	"service_fmri",			/* SC_SERVICE_FMRI */
99*0Sstevel@tonic-gate 	"single_instance",		/* SC_INSTANCE_SINGLE */
100*0Sstevel@tonic-gate 	"stability",			/* SC_STABILITY */
101*0Sstevel@tonic-gate 	"template",			/* SC_TEMPLATE */
102*0Sstevel@tonic-gate 	"time_list",			/* SC_TIME */
103*0Sstevel@tonic-gate 	"uri_list",			/* SC_URI */
104*0Sstevel@tonic-gate 	"ustring_list",			/* SC_USTRING */
105*0Sstevel@tonic-gate 	"value_node",			/* SC_VALUE_NODE */
106*0Sstevel@tonic-gate 	"xi:fallback",			/* SC_XI_FALLBACK */
107*0Sstevel@tonic-gate 	"xi:include"			/* SC_XI_INCLUDE */
108*0Sstevel@tonic-gate };
109*0Sstevel@tonic-gate 
110*0Sstevel@tonic-gate /*
111*0Sstevel@tonic-gate  * The following list must be kept in the same order as that of
112*0Sstevel@tonic-gate  * element_t array
113*0Sstevel@tonic-gate  */
114*0Sstevel@tonic-gate static const char *lxml_prop_types[] = {
115*0Sstevel@tonic-gate 	"astring",			/* SC_ASTRING */
116*0Sstevel@tonic-gate 	"boolean",			/* SC_BOOLEAN */
117*0Sstevel@tonic-gate 	"",				/* SC_COMMON_NAME */
118*0Sstevel@tonic-gate 	"count",			/* SC_COUNT */
119*0Sstevel@tonic-gate 	"",				/* SC_INSTANCE_CREATE_DEFAULT */
120*0Sstevel@tonic-gate 	"",				/* SC_DEPENDENCY */
121*0Sstevel@tonic-gate 	"",				/* SC_DEPENDENT */
122*0Sstevel@tonic-gate 	"",				/* SC_DESCRIPTION */
123*0Sstevel@tonic-gate 	"",				/* SC_DOC_LINK */
124*0Sstevel@tonic-gate 	"",				/* SC_DOCUMENTATION */
125*0Sstevel@tonic-gate 	"",				/* SC_ENABLED */
126*0Sstevel@tonic-gate 	"",				/* SC_EXEC_METHOD */
127*0Sstevel@tonic-gate 	"fmri",				/* SC_FMRI */
128*0Sstevel@tonic-gate 	"host",				/* SC_HOST */
129*0Sstevel@tonic-gate 	"hostname",			/* SC_HOSTNAME */
130*0Sstevel@tonic-gate 	"",				/* SC_INSTANCE */
131*0Sstevel@tonic-gate 	"integer",			/* SC_INTEGER */
132*0Sstevel@tonic-gate 	"",				/* SC_LOCTEXT */
133*0Sstevel@tonic-gate 	"",				/* SC_MANPAGE */
134*0Sstevel@tonic-gate 	"",				/* SC_METHOD_CONTEXT */
135*0Sstevel@tonic-gate 	"",				/* SC_METHOD_CREDENTIAL */
136*0Sstevel@tonic-gate 	"",				/* SC_METHOD_PROFILE */
137*0Sstevel@tonic-gate 	"",				/* SC_METHOD_ENVIRONMENT */
138*0Sstevel@tonic-gate 	"",				/* SC_METHOD_ENVVAR */
139*0Sstevel@tonic-gate 	"net_address_v4",		/* SC_NET_ADDR_V4 */
140*0Sstevel@tonic-gate 	"net_address_v6",		/* SC_NET_ADDR_V6 */
141*0Sstevel@tonic-gate 	"opaque",			/* SC_OPAQUE */
142*0Sstevel@tonic-gate 	"",				/* SC_PROPERTY */
143*0Sstevel@tonic-gate 	"",				/* SC_PROPERTY_GROUP */
144*0Sstevel@tonic-gate 	"",				/* SC_PROPVAL */
145*0Sstevel@tonic-gate 	"",				/* SC_RESTARTER */
146*0Sstevel@tonic-gate 	"",				/* SC_SERVICE */
147*0Sstevel@tonic-gate 	"",				/* SC_SERVICE_BUNDLE */
148*0Sstevel@tonic-gate 	"",				/* SC_SERVICE_FMRI */
149*0Sstevel@tonic-gate 	"",				/* SC_INSTANCE_SINGLE */
150*0Sstevel@tonic-gate 	"",				/* SC_STABILITY */
151*0Sstevel@tonic-gate 	"",				/* SC_TEMPLATE */
152*0Sstevel@tonic-gate 	"time",				/* SC_TIME */
153*0Sstevel@tonic-gate 	"uri",				/* SC_URI */
154*0Sstevel@tonic-gate 	"ustring",			/* SC_USTRING */
155*0Sstevel@tonic-gate 	""				/* SC_VALUE_NODE */
156*0Sstevel@tonic-gate 	""				/* SC_XI_FALLBACK */
157*0Sstevel@tonic-gate 	""				/* SC_XI_INCLUDE */
158*0Sstevel@tonic-gate };
159*0Sstevel@tonic-gate 
160*0Sstevel@tonic-gate int
161*0Sstevel@tonic-gate lxml_init()
162*0Sstevel@tonic-gate {
163*0Sstevel@tonic-gate 	if (getenv("SVCCFG_NOVALIDATE") == NULL) {
164*0Sstevel@tonic-gate 		/*
165*0Sstevel@tonic-gate 		 * DTD validation, with line numbers.
166*0Sstevel@tonic-gate 		 */
167*0Sstevel@tonic-gate 		xmlLineNumbersDefault(1);
168*0Sstevel@tonic-gate 		xmlLoadExtDtdDefaultValue |= XML_DETECT_IDS;
169*0Sstevel@tonic-gate 		xmlLoadExtDtdDefaultValue |= XML_COMPLETE_ATTRS;
170*0Sstevel@tonic-gate 	}
171*0Sstevel@tonic-gate 
172*0Sstevel@tonic-gate 	return (0);
173*0Sstevel@tonic-gate }
174*0Sstevel@tonic-gate 
175*0Sstevel@tonic-gate static bundle_type_t
176*0Sstevel@tonic-gate lxml_xlate_bundle_type(xmlChar *type)
177*0Sstevel@tonic-gate {
178*0Sstevel@tonic-gate 	if (xmlStrcmp(type, (const xmlChar *)"manifest") == 0)
179*0Sstevel@tonic-gate 		return (SVCCFG_MANIFEST);
180*0Sstevel@tonic-gate 
181*0Sstevel@tonic-gate 	if (xmlStrcmp(type, (const xmlChar *)"profile") == 0)
182*0Sstevel@tonic-gate 		return (SVCCFG_PROFILE);
183*0Sstevel@tonic-gate 
184*0Sstevel@tonic-gate 	if (xmlStrcmp(type, (const xmlChar *)"archive") == 0)
185*0Sstevel@tonic-gate 		return (SVCCFG_ARCHIVE);
186*0Sstevel@tonic-gate 
187*0Sstevel@tonic-gate 	return (SVCCFG_UNKNOWN_BUNDLE);
188*0Sstevel@tonic-gate }
189*0Sstevel@tonic-gate 
190*0Sstevel@tonic-gate static service_type_t
191*0Sstevel@tonic-gate lxml_xlate_service_type(xmlChar *type)
192*0Sstevel@tonic-gate {
193*0Sstevel@tonic-gate 	if (xmlStrcmp(type, (const xmlChar *)"service") == 0)
194*0Sstevel@tonic-gate 		return (SVCCFG_SERVICE);
195*0Sstevel@tonic-gate 
196*0Sstevel@tonic-gate 	if (xmlStrcmp(type, (const xmlChar *)"restarter") == 0)
197*0Sstevel@tonic-gate 		return (SVCCFG_RESTARTER);
198*0Sstevel@tonic-gate 
199*0Sstevel@tonic-gate 	if (xmlStrcmp(type, (const xmlChar *)"milestone") == 0)
200*0Sstevel@tonic-gate 		return (SVCCFG_MILESTONE);
201*0Sstevel@tonic-gate 
202*0Sstevel@tonic-gate 	return (SVCCFG_UNKNOWN_SERVICE);
203*0Sstevel@tonic-gate }
204*0Sstevel@tonic-gate 
205*0Sstevel@tonic-gate static element_t
206*0Sstevel@tonic-gate lxml_xlate_element(const xmlChar *tag)
207*0Sstevel@tonic-gate {
208*0Sstevel@tonic-gate 	int i;
209*0Sstevel@tonic-gate 
210*0Sstevel@tonic-gate 	for (i = 0; i < sizeof (lxml_elements) / sizeof (char *); i++)
211*0Sstevel@tonic-gate 		if (xmlStrcmp(tag, (const xmlChar *)lxml_elements[i]) == 0)
212*0Sstevel@tonic-gate 			return ((element_t)i);
213*0Sstevel@tonic-gate 
214*0Sstevel@tonic-gate 	return ((element_t)-1);
215*0Sstevel@tonic-gate }
216*0Sstevel@tonic-gate 
217*0Sstevel@tonic-gate static uint_t
218*0Sstevel@tonic-gate lxml_xlate_boolean(const xmlChar *value)
219*0Sstevel@tonic-gate {
220*0Sstevel@tonic-gate 	if (xmlStrcmp(value, (const xmlChar *)true) == 0)
221*0Sstevel@tonic-gate 		return (1);
222*0Sstevel@tonic-gate 
223*0Sstevel@tonic-gate 	if (xmlStrcmp(value, (const xmlChar *)false) == 0)
224*0Sstevel@tonic-gate 		return (0);
225*0Sstevel@tonic-gate 
226*0Sstevel@tonic-gate 	uu_die(gettext("illegal boolean value \"%s\"\n"), value);
227*0Sstevel@tonic-gate 
228*0Sstevel@tonic-gate 	/*NOTREACHED*/
229*0Sstevel@tonic-gate }
230*0Sstevel@tonic-gate 
231*0Sstevel@tonic-gate static scf_type_t
232*0Sstevel@tonic-gate lxml_element_to_type(element_t type)
233*0Sstevel@tonic-gate {
234*0Sstevel@tonic-gate 	switch (type) {
235*0Sstevel@tonic-gate 	case SC_ASTRING:	return (SCF_TYPE_ASTRING);
236*0Sstevel@tonic-gate 	case SC_BOOLEAN:	return (SCF_TYPE_BOOLEAN);
237*0Sstevel@tonic-gate 	case SC_COUNT:		return (SCF_TYPE_COUNT);
238*0Sstevel@tonic-gate 	case SC_FMRI:		return (SCF_TYPE_FMRI);
239*0Sstevel@tonic-gate 	case SC_HOST:		return (SCF_TYPE_HOST);
240*0Sstevel@tonic-gate 	case SC_HOSTNAME:	return (SCF_TYPE_HOSTNAME);
241*0Sstevel@tonic-gate 	case SC_INTEGER:	return (SCF_TYPE_INTEGER);
242*0Sstevel@tonic-gate 	case SC_NET_ADDR_V4:	return (SCF_TYPE_NET_ADDR_V4);
243*0Sstevel@tonic-gate 	case SC_NET_ADDR_V6:	return (SCF_TYPE_NET_ADDR_V6);
244*0Sstevel@tonic-gate 	case SC_OPAQUE:		return (SCF_TYPE_OPAQUE);
245*0Sstevel@tonic-gate 	case SC_TIME:		return (SCF_TYPE_TIME);
246*0Sstevel@tonic-gate 	case SC_URI:		return (SCF_TYPE_URI);
247*0Sstevel@tonic-gate 	case SC_USTRING:	return (SCF_TYPE_USTRING);
248*0Sstevel@tonic-gate 
249*0Sstevel@tonic-gate 	default:
250*0Sstevel@tonic-gate 		uu_die(gettext("unknown value type (%d)\n"), type);
251*0Sstevel@tonic-gate 	}
252*0Sstevel@tonic-gate 
253*0Sstevel@tonic-gate 	/* NOTREACHED */
254*0Sstevel@tonic-gate }
255*0Sstevel@tonic-gate 
256*0Sstevel@tonic-gate static scf_type_t
257*0Sstevel@tonic-gate lxml_element_to_scf_type(element_t type)
258*0Sstevel@tonic-gate {
259*0Sstevel@tonic-gate 	switch (type) {
260*0Sstevel@tonic-gate 	case SC_ASTRING:	return (SCF_TYPE_ASTRING);
261*0Sstevel@tonic-gate 	case SC_BOOLEAN:	return (SCF_TYPE_BOOLEAN);
262*0Sstevel@tonic-gate 	case SC_COUNT:		return (SCF_TYPE_COUNT);
263*0Sstevel@tonic-gate 	case SC_FMRI:		return (SCF_TYPE_FMRI);
264*0Sstevel@tonic-gate 	case SC_HOST:		return (SCF_TYPE_HOST);
265*0Sstevel@tonic-gate 	case SC_HOSTNAME:	return (SCF_TYPE_HOSTNAME);
266*0Sstevel@tonic-gate 	case SC_INTEGER:	return (SCF_TYPE_INTEGER);
267*0Sstevel@tonic-gate 	case SC_NET_ADDR_V4:	return (SCF_TYPE_NET_ADDR_V4);
268*0Sstevel@tonic-gate 	case SC_NET_ADDR_V6:	return (SCF_TYPE_NET_ADDR_V6);
269*0Sstevel@tonic-gate 	case SC_OPAQUE:		return (SCF_TYPE_OPAQUE);
270*0Sstevel@tonic-gate 	case SC_TIME:		return (SCF_TYPE_TIME);
271*0Sstevel@tonic-gate 	case SC_URI:		return (SCF_TYPE_URI);
272*0Sstevel@tonic-gate 	case SC_USTRING:	return (SCF_TYPE_USTRING);
273*0Sstevel@tonic-gate 	default:
274*0Sstevel@tonic-gate 		uu_die(gettext("unknown value type (%d)\n"), type);
275*0Sstevel@tonic-gate 	}
276*0Sstevel@tonic-gate 
277*0Sstevel@tonic-gate 	/* NOTREACHED */
278*0Sstevel@tonic-gate }
279*0Sstevel@tonic-gate 
280*0Sstevel@tonic-gate static int
281*0Sstevel@tonic-gate new_str_prop_from_attr(pgroup_t *pgrp, const char *pname, scf_type_t ty,
282*0Sstevel@tonic-gate     xmlNodePtr n, const char *attr)
283*0Sstevel@tonic-gate {
284*0Sstevel@tonic-gate 	xmlChar *val;
285*0Sstevel@tonic-gate 	property_t *p;
286*0Sstevel@tonic-gate 	int r;
287*0Sstevel@tonic-gate 
288*0Sstevel@tonic-gate 	val = xmlGetProp(n, (xmlChar *)attr);
289*0Sstevel@tonic-gate 
290*0Sstevel@tonic-gate 	p = internal_property_create(pname, ty, 1, val);
291*0Sstevel@tonic-gate 	r = internal_attach_property(pgrp, p);
292*0Sstevel@tonic-gate 
293*0Sstevel@tonic-gate 	if (r != 0)
294*0Sstevel@tonic-gate 		internal_property_free(p);
295*0Sstevel@tonic-gate 
296*0Sstevel@tonic-gate 	return (r);
297*0Sstevel@tonic-gate }
298*0Sstevel@tonic-gate 
299*0Sstevel@tonic-gate static int
300*0Sstevel@tonic-gate lxml_ignorable_block(xmlNodePtr n)
301*0Sstevel@tonic-gate {
302*0Sstevel@tonic-gate 	return ((xmlStrcmp(n->name, (xmlChar *)"text") == 0 ||
303*0Sstevel@tonic-gate 	    xmlStrcmp(n->name, (xmlChar *)"comment") == 0) ? 1 : 0);
304*0Sstevel@tonic-gate }
305*0Sstevel@tonic-gate 
306*0Sstevel@tonic-gate static int
307*0Sstevel@tonic-gate lxml_validate_string_value(scf_type_t type, const char *v)
308*0Sstevel@tonic-gate {
309*0Sstevel@tonic-gate 	static scf_value_t *scf_value = NULL;
310*0Sstevel@tonic-gate 	static scf_handle_t *scf_hndl = NULL;
311*0Sstevel@tonic-gate 
312*0Sstevel@tonic-gate 	if (scf_hndl == NULL && (scf_hndl = scf_handle_create(SCF_VERSION)) ==
313*0Sstevel@tonic-gate 	    NULL)
314*0Sstevel@tonic-gate 		return (-1);
315*0Sstevel@tonic-gate 
316*0Sstevel@tonic-gate 	if (scf_value == NULL && (scf_value = scf_value_create(scf_hndl)) ==
317*0Sstevel@tonic-gate 	    NULL)
318*0Sstevel@tonic-gate 		return (-1);
319*0Sstevel@tonic-gate 
320*0Sstevel@tonic-gate 	return (scf_value_set_from_string(scf_value, type, v));
321*0Sstevel@tonic-gate }
322*0Sstevel@tonic-gate 
323*0Sstevel@tonic-gate static void
324*0Sstevel@tonic-gate lxml_free_str(value_t *val)
325*0Sstevel@tonic-gate {
326*0Sstevel@tonic-gate 	free(val->sc_u.sc_string);
327*0Sstevel@tonic-gate }
328*0Sstevel@tonic-gate 
329*0Sstevel@tonic-gate static value_t *
330*0Sstevel@tonic-gate lxml_make_value(element_t type, const xmlChar *value)
331*0Sstevel@tonic-gate {
332*0Sstevel@tonic-gate 	value_t *v;
333*0Sstevel@tonic-gate 	char *endptr;
334*0Sstevel@tonic-gate 	scf_type_t scf_type = SCF_TYPE_INVALID;
335*0Sstevel@tonic-gate 
336*0Sstevel@tonic-gate 	v = internal_value_new();
337*0Sstevel@tonic-gate 
338*0Sstevel@tonic-gate 	v->sc_type = lxml_element_to_type(type);
339*0Sstevel@tonic-gate 
340*0Sstevel@tonic-gate 	switch (type) {
341*0Sstevel@tonic-gate 	case SC_COUNT:
342*0Sstevel@tonic-gate 		/*
343*0Sstevel@tonic-gate 		 * Although an SC_COUNT represents a uint64_t the use
344*0Sstevel@tonic-gate 		 * of a negative value is acceptable due to the usage
345*0Sstevel@tonic-gate 		 * established by inetd(1M).
346*0Sstevel@tonic-gate 		 */
347*0Sstevel@tonic-gate 		errno = 0;
348*0Sstevel@tonic-gate 		v->sc_u.sc_count = strtoull((char *)value, &endptr, 10);
349*0Sstevel@tonic-gate 		if (errno != 0 || endptr == (char *)value || *endptr)
350*0Sstevel@tonic-gate 			uu_die(gettext("illegal value \"%s\" for "
351*0Sstevel@tonic-gate 			    "%s (%s)\n"), (char *)value,
352*0Sstevel@tonic-gate 			    lxml_prop_types[type],
353*0Sstevel@tonic-gate 			    (errno) ? strerror(errno) :
354*0Sstevel@tonic-gate 			    gettext("Illegal character"));
355*0Sstevel@tonic-gate 		break;
356*0Sstevel@tonic-gate 	case SC_INTEGER:
357*0Sstevel@tonic-gate 		errno = 0;
358*0Sstevel@tonic-gate 		v->sc_u.sc_integer = strtoll((char *)value, &endptr, 10);
359*0Sstevel@tonic-gate 		if (errno != 0 || *endptr)
360*0Sstevel@tonic-gate 			uu_die(gettext("illegal value \"%s\" for "
361*0Sstevel@tonic-gate 			    "%s (%s)\n"), (char *)value,
362*0Sstevel@tonic-gate 			    lxml_prop_types[type],
363*0Sstevel@tonic-gate 			    (errno) ? strerror(errno) : "Illegal character");
364*0Sstevel@tonic-gate 		break;
365*0Sstevel@tonic-gate 	case SC_OPAQUE:
366*0Sstevel@tonic-gate 	case SC_HOST:
367*0Sstevel@tonic-gate 	case SC_HOSTNAME:
368*0Sstevel@tonic-gate 	case SC_NET_ADDR_V4:
369*0Sstevel@tonic-gate 	case SC_NET_ADDR_V6:
370*0Sstevel@tonic-gate 	case SC_FMRI:
371*0Sstevel@tonic-gate 	case SC_URI:
372*0Sstevel@tonic-gate 	case SC_TIME:
373*0Sstevel@tonic-gate 	case SC_ASTRING:
374*0Sstevel@tonic-gate 	case SC_USTRING:
375*0Sstevel@tonic-gate 		scf_type = lxml_element_to_scf_type(type);
376*0Sstevel@tonic-gate 
377*0Sstevel@tonic-gate 		if ((v->sc_u.sc_string = strdup((char *)value)) == NULL)
378*0Sstevel@tonic-gate 			uu_die(gettext("string duplication failed (%s)\n"),
379*0Sstevel@tonic-gate 			    strerror(errno));
380*0Sstevel@tonic-gate 		if (lxml_validate_string_value(scf_type,
381*0Sstevel@tonic-gate 		    v->sc_u.sc_string) != 0)
382*0Sstevel@tonic-gate 			uu_die(gettext("illegal value \"%s\" for "
383*0Sstevel@tonic-gate 			    "%s (%s)\n"), (char *)value,
384*0Sstevel@tonic-gate 			    lxml_prop_types[type],
385*0Sstevel@tonic-gate 			    (scf_error()) ? scf_strerror(scf_error()) :
386*0Sstevel@tonic-gate 			    gettext("Illegal format"));
387*0Sstevel@tonic-gate 		v->sc_free = lxml_free_str;
388*0Sstevel@tonic-gate 		break;
389*0Sstevel@tonic-gate 	case SC_BOOLEAN:
390*0Sstevel@tonic-gate 		v->sc_u.sc_count = lxml_xlate_boolean(value);
391*0Sstevel@tonic-gate 		break;
392*0Sstevel@tonic-gate 	default:
393*0Sstevel@tonic-gate 		uu_die(gettext("unknown value type (%d)\n"), type);
394*0Sstevel@tonic-gate 		break;
395*0Sstevel@tonic-gate 	}
396*0Sstevel@tonic-gate 
397*0Sstevel@tonic-gate 	return (v);
398*0Sstevel@tonic-gate }
399*0Sstevel@tonic-gate 
400*0Sstevel@tonic-gate static int
401*0Sstevel@tonic-gate lxml_get_value(property_t *prop, element_t vtype, xmlNodePtr value)
402*0Sstevel@tonic-gate {
403*0Sstevel@tonic-gate 	xmlNodePtr cursor;
404*0Sstevel@tonic-gate 
405*0Sstevel@tonic-gate 	for (cursor = value->xmlChildrenNode; cursor != NULL;
406*0Sstevel@tonic-gate 	    cursor = cursor->next) {
407*0Sstevel@tonic-gate 		xmlChar *assigned_value;
408*0Sstevel@tonic-gate 		value_t *v;
409*0Sstevel@tonic-gate 
410*0Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
411*0Sstevel@tonic-gate 			continue;
412*0Sstevel@tonic-gate 
413*0Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
414*0Sstevel@tonic-gate 		case SC_VALUE_NODE:
415*0Sstevel@tonic-gate 			if ((assigned_value = xmlGetProp(cursor,
416*0Sstevel@tonic-gate 			    (xmlChar *)value_attr)) == NULL)
417*0Sstevel@tonic-gate 				uu_die(gettext("no value on value node?\n"));
418*0Sstevel@tonic-gate 			break;
419*0Sstevel@tonic-gate 		default:
420*0Sstevel@tonic-gate 			uu_die(gettext("value list contains illegal element "
421*0Sstevel@tonic-gate 			    "\'%s\'\n"), cursor->name);
422*0Sstevel@tonic-gate 			break;
423*0Sstevel@tonic-gate 		}
424*0Sstevel@tonic-gate 
425*0Sstevel@tonic-gate 		v = lxml_make_value(vtype, assigned_value);
426*0Sstevel@tonic-gate 
427*0Sstevel@tonic-gate 		xmlFree(assigned_value);
428*0Sstevel@tonic-gate 
429*0Sstevel@tonic-gate 		internal_attach_value(prop, v);
430*0Sstevel@tonic-gate 	}
431*0Sstevel@tonic-gate 
432*0Sstevel@tonic-gate 	return (0);
433*0Sstevel@tonic-gate }
434*0Sstevel@tonic-gate 
435*0Sstevel@tonic-gate static int
436*0Sstevel@tonic-gate lxml_get_propval(pgroup_t *pgrp, xmlNodePtr propval)
437*0Sstevel@tonic-gate {
438*0Sstevel@tonic-gate 	property_t *p;
439*0Sstevel@tonic-gate 	element_t r;
440*0Sstevel@tonic-gate 	value_t *v;
441*0Sstevel@tonic-gate 	xmlChar *type, *val, *override;
442*0Sstevel@tonic-gate 
443*0Sstevel@tonic-gate 	p = internal_property_new();
444*0Sstevel@tonic-gate 
445*0Sstevel@tonic-gate 	p->sc_property_name = (char *)xmlGetProp(propval, (xmlChar *)name_attr);
446*0Sstevel@tonic-gate 	if (p->sc_property_name == NULL)
447*0Sstevel@tonic-gate 		uu_die(gettext("property name missing in group '%s'\n"),
448*0Sstevel@tonic-gate 		    pgrp->sc_pgroup_name);
449*0Sstevel@tonic-gate 
450*0Sstevel@tonic-gate 	type = xmlGetProp(propval, (xmlChar *)type_attr);
451*0Sstevel@tonic-gate 	if (type == NULL)
452*0Sstevel@tonic-gate 		uu_die(gettext("property type missing for property '%s/%s'\n"),
453*0Sstevel@tonic-gate 		    pgrp->sc_pgroup_name, p->sc_property_name);
454*0Sstevel@tonic-gate 
455*0Sstevel@tonic-gate 	for (r = 0; r < sizeof (lxml_prop_types) / sizeof (char *); ++r) {
456*0Sstevel@tonic-gate 		if (xmlStrcmp(type, (const xmlChar *)lxml_prop_types[r]) == 0)
457*0Sstevel@tonic-gate 			break;
458*0Sstevel@tonic-gate 	}
459*0Sstevel@tonic-gate 	if (r >= sizeof (lxml_prop_types) / sizeof (char *))
460*0Sstevel@tonic-gate 		uu_die(gettext("property type invalid for property '%s/%s'\n"),
461*0Sstevel@tonic-gate 		    pgrp->sc_pgroup_name, p->sc_property_name);
462*0Sstevel@tonic-gate 
463*0Sstevel@tonic-gate 	p->sc_value_type = lxml_element_to_type(r);
464*0Sstevel@tonic-gate 
465*0Sstevel@tonic-gate 	val = xmlGetProp(propval, (xmlChar *)value_attr);
466*0Sstevel@tonic-gate 	if (val == NULL)
467*0Sstevel@tonic-gate 		uu_die(gettext("property value missing for property '%s/%s'\n"),
468*0Sstevel@tonic-gate 		    pgrp->sc_pgroup_name, p->sc_property_name);
469*0Sstevel@tonic-gate 
470*0Sstevel@tonic-gate 	v = lxml_make_value(r, val);
471*0Sstevel@tonic-gate 	internal_attach_value(p, v);
472*0Sstevel@tonic-gate 
473*0Sstevel@tonic-gate 	override = xmlGetProp(propval, (xmlChar *)override_attr);
474*0Sstevel@tonic-gate 	p->sc_property_override = (xmlStrcmp(override, (xmlChar *)true) == 0);
475*0Sstevel@tonic-gate 	xmlFree(override);
476*0Sstevel@tonic-gate 
477*0Sstevel@tonic-gate 	return (internal_attach_property(pgrp, p));
478*0Sstevel@tonic-gate }
479*0Sstevel@tonic-gate 
480*0Sstevel@tonic-gate static int
481*0Sstevel@tonic-gate lxml_get_property(pgroup_t *pgrp, xmlNodePtr property)
482*0Sstevel@tonic-gate {
483*0Sstevel@tonic-gate 	property_t *p;
484*0Sstevel@tonic-gate 	xmlNodePtr cursor;
485*0Sstevel@tonic-gate 	element_t r;
486*0Sstevel@tonic-gate 	xmlChar *type, *override;
487*0Sstevel@tonic-gate 
488*0Sstevel@tonic-gate 	p = internal_property_new();
489*0Sstevel@tonic-gate 
490*0Sstevel@tonic-gate 	if ((p->sc_property_name = (char *)xmlGetProp(property,
491*0Sstevel@tonic-gate 	    (xmlChar *)name_attr)) == NULL)
492*0Sstevel@tonic-gate 		uu_die(gettext("property name missing in group \'%s\'\n"),
493*0Sstevel@tonic-gate 		    pgrp->sc_pgroup_name);
494*0Sstevel@tonic-gate 
495*0Sstevel@tonic-gate 	if ((type = xmlGetProp(property, (xmlChar *)type_attr)) == NULL)
496*0Sstevel@tonic-gate 		uu_die(gettext("property type missing for "
497*0Sstevel@tonic-gate 		    "property \'%s/%s\'\n"), pgrp->sc_pgroup_name,
498*0Sstevel@tonic-gate 		    p->sc_property_name);
499*0Sstevel@tonic-gate 
500*0Sstevel@tonic-gate 	for (cursor = property->xmlChildrenNode; cursor != NULL;
501*0Sstevel@tonic-gate 	    cursor = cursor->next) {
502*0Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
503*0Sstevel@tonic-gate 			continue;
504*0Sstevel@tonic-gate 
505*0Sstevel@tonic-gate 		switch (r = lxml_xlate_element(cursor->name)) {
506*0Sstevel@tonic-gate 		case SC_ASTRING:
507*0Sstevel@tonic-gate 		case SC_BOOLEAN:
508*0Sstevel@tonic-gate 		case SC_COUNT:
509*0Sstevel@tonic-gate 		case SC_FMRI:
510*0Sstevel@tonic-gate 		case SC_HOST:
511*0Sstevel@tonic-gate 		case SC_HOSTNAME:
512*0Sstevel@tonic-gate 		case SC_INTEGER:
513*0Sstevel@tonic-gate 		case SC_NET_ADDR_V4:
514*0Sstevel@tonic-gate 		case SC_NET_ADDR_V6:
515*0Sstevel@tonic-gate 		case SC_OPAQUE:
516*0Sstevel@tonic-gate 		case SC_TIME:
517*0Sstevel@tonic-gate 		case SC_URI:
518*0Sstevel@tonic-gate 		case SC_USTRING:
519*0Sstevel@tonic-gate 			if (strcmp(lxml_prop_types[r], (const char *)type) != 0)
520*0Sstevel@tonic-gate 				uu_die(gettext("property \'%s\' "
521*0Sstevel@tonic-gate 				    "type-to-list mismatch\n"),
522*0Sstevel@tonic-gate 				    p->sc_property_name);
523*0Sstevel@tonic-gate 
524*0Sstevel@tonic-gate 			p->sc_value_type = lxml_element_to_type(r);
525*0Sstevel@tonic-gate 			(void) lxml_get_value(p, r, cursor);
526*0Sstevel@tonic-gate 			break;
527*0Sstevel@tonic-gate 		default:
528*0Sstevel@tonic-gate 			uu_die(gettext("unknown value list type: %s\n"),
529*0Sstevel@tonic-gate 			    cursor->name);
530*0Sstevel@tonic-gate 			break;
531*0Sstevel@tonic-gate 		}
532*0Sstevel@tonic-gate 	}
533*0Sstevel@tonic-gate 
534*0Sstevel@tonic-gate 	xmlFree(type);
535*0Sstevel@tonic-gate 
536*0Sstevel@tonic-gate 	override = xmlGetProp(property, (xmlChar *)override_attr);
537*0Sstevel@tonic-gate 	p->sc_property_override = (xmlStrcmp(override, (xmlChar *)true) == 0);
538*0Sstevel@tonic-gate 	xmlFree(override);
539*0Sstevel@tonic-gate 
540*0Sstevel@tonic-gate 	return (internal_attach_property(pgrp, p));
541*0Sstevel@tonic-gate }
542*0Sstevel@tonic-gate 
543*0Sstevel@tonic-gate static int
544*0Sstevel@tonic-gate lxml_get_pgroup_stability(pgroup_t *pgrp, xmlNodePtr stab)
545*0Sstevel@tonic-gate {
546*0Sstevel@tonic-gate 	return (new_str_prop_from_attr(pgrp, SCF_PROPERTY_STABILITY,
547*0Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, stab, value_attr));
548*0Sstevel@tonic-gate }
549*0Sstevel@tonic-gate 
550*0Sstevel@tonic-gate /*
551*0Sstevel@tonic-gate  * Property groups can go on any of a service, an instance, or a template.
552*0Sstevel@tonic-gate  */
553*0Sstevel@tonic-gate static int
554*0Sstevel@tonic-gate lxml_get_pgroup(entity_t *entity, xmlNodePtr pgroup)
555*0Sstevel@tonic-gate {
556*0Sstevel@tonic-gate 	pgroup_t *pg;
557*0Sstevel@tonic-gate 	xmlNodePtr cursor;
558*0Sstevel@tonic-gate 	xmlChar *name, *type, *delete;
559*0Sstevel@tonic-gate 
560*0Sstevel@tonic-gate 	/*
561*0Sstevel@tonic-gate 	 * property group attributes:
562*0Sstevel@tonic-gate 	 * name: string
563*0Sstevel@tonic-gate 	 * type: string | framework | application
564*0Sstevel@tonic-gate 	 */
565*0Sstevel@tonic-gate 	name = xmlGetProp(pgroup, (xmlChar *)name_attr);
566*0Sstevel@tonic-gate 	type = xmlGetProp(pgroup, (xmlChar *)type_attr);
567*0Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(entity, (char *)name, (char *)type);
568*0Sstevel@tonic-gate 	xmlFree(name);
569*0Sstevel@tonic-gate 	xmlFree(type);
570*0Sstevel@tonic-gate 
571*0Sstevel@tonic-gate 	/*
572*0Sstevel@tonic-gate 	 * Walk the children of this lxml_elements, which are a stability
573*0Sstevel@tonic-gate 	 * element, property elements, or propval elements.
574*0Sstevel@tonic-gate 	 */
575*0Sstevel@tonic-gate 	for (cursor = pgroup->xmlChildrenNode; cursor != NULL;
576*0Sstevel@tonic-gate 	    cursor = cursor->next) {
577*0Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
578*0Sstevel@tonic-gate 			continue;
579*0Sstevel@tonic-gate 
580*0Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
581*0Sstevel@tonic-gate 		case SC_STABILITY:
582*0Sstevel@tonic-gate 			(void) lxml_get_pgroup_stability(pg, cursor);
583*0Sstevel@tonic-gate 			break;
584*0Sstevel@tonic-gate 		case SC_PROPERTY:
585*0Sstevel@tonic-gate 			(void) lxml_get_property(pg, cursor);
586*0Sstevel@tonic-gate 			break;
587*0Sstevel@tonic-gate 		case SC_PROPVAL:
588*0Sstevel@tonic-gate 			(void) lxml_get_propval(pg, cursor);
589*0Sstevel@tonic-gate 			break;
590*0Sstevel@tonic-gate 		default:
591*0Sstevel@tonic-gate 			abort();
592*0Sstevel@tonic-gate 			break;
593*0Sstevel@tonic-gate 		}
594*0Sstevel@tonic-gate 	}
595*0Sstevel@tonic-gate 
596*0Sstevel@tonic-gate 	delete = xmlGetProp(pgroup, (xmlChar *)delete_attr);
597*0Sstevel@tonic-gate 	pg->sc_pgroup_delete = (xmlStrcmp(delete, (xmlChar *)true) == 0);
598*0Sstevel@tonic-gate 	xmlFree(delete);
599*0Sstevel@tonic-gate 
600*0Sstevel@tonic-gate 	return (0);
601*0Sstevel@tonic-gate }
602*0Sstevel@tonic-gate 
603*0Sstevel@tonic-gate 
604*0Sstevel@tonic-gate /*
605*0Sstevel@tonic-gate  * Dependency groups, execution methods can go on either a service or an
606*0Sstevel@tonic-gate  * instance.
607*0Sstevel@tonic-gate  */
608*0Sstevel@tonic-gate 
609*0Sstevel@tonic-gate static int
610*0Sstevel@tonic-gate lxml_get_method_profile(pgroup_t *pg, xmlNodePtr profile)
611*0Sstevel@tonic-gate {
612*0Sstevel@tonic-gate 	property_t *p;
613*0Sstevel@tonic-gate 
614*0Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_USE_PROFILE, SCF_TYPE_BOOLEAN,
615*0Sstevel@tonic-gate 	    1, (uint64_t)1);
616*0Sstevel@tonic-gate 	if (internal_attach_property(pg, p) != 0)
617*0Sstevel@tonic-gate 		return (-1);
618*0Sstevel@tonic-gate 
619*0Sstevel@tonic-gate 	return (new_str_prop_from_attr(pg, SCF_PROPERTY_PROFILE,
620*0Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, profile, name_attr));
621*0Sstevel@tonic-gate }
622*0Sstevel@tonic-gate 
623*0Sstevel@tonic-gate static int
624*0Sstevel@tonic-gate lxml_get_method_credential(pgroup_t *pg, xmlNodePtr cred)
625*0Sstevel@tonic-gate {
626*0Sstevel@tonic-gate 	property_t *p;
627*0Sstevel@tonic-gate 
628*0Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_USE_PROFILE, SCF_TYPE_BOOLEAN,
629*0Sstevel@tonic-gate 	    1, (uint64_t)0);
630*0Sstevel@tonic-gate 	if (internal_attach_property(pg, p) != 0)
631*0Sstevel@tonic-gate 		return (-1);
632*0Sstevel@tonic-gate 
633*0Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_USER, SCF_TYPE_ASTRING,
634*0Sstevel@tonic-gate 	    cred, "user") != 0)
635*0Sstevel@tonic-gate 		return (-1);
636*0Sstevel@tonic-gate 
637*0Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_GROUP, SCF_TYPE_ASTRING,
638*0Sstevel@tonic-gate 	    cred, "group") != 0)
639*0Sstevel@tonic-gate 		return (-1);
640*0Sstevel@tonic-gate 
641*0Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_SUPP_GROUPS,
642*0Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, cred, "supp_groups") != 0)
643*0Sstevel@tonic-gate 		return (-1);
644*0Sstevel@tonic-gate 
645*0Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_PRIVILEGES,
646*0Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, cred, "privileges") != 0)
647*0Sstevel@tonic-gate 		return (-1);
648*0Sstevel@tonic-gate 
649*0Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_LIMIT_PRIVILEGES,
650*0Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, cred, "limit_privileges") != 0)
651*0Sstevel@tonic-gate 		return (-1);
652*0Sstevel@tonic-gate 
653*0Sstevel@tonic-gate 	return (0);
654*0Sstevel@tonic-gate }
655*0Sstevel@tonic-gate 
656*0Sstevel@tonic-gate static char *
657*0Sstevel@tonic-gate lxml_get_envvar(xmlNodePtr envvar)
658*0Sstevel@tonic-gate {
659*0Sstevel@tonic-gate 	char *name;
660*0Sstevel@tonic-gate 	char *value;
661*0Sstevel@tonic-gate 	char *ret;
662*0Sstevel@tonic-gate 
663*0Sstevel@tonic-gate 	name = (char *)xmlGetProp(envvar, (xmlChar *)"name");
664*0Sstevel@tonic-gate 	value = (char *)xmlGetProp(envvar, (xmlChar *)"value");
665*0Sstevel@tonic-gate 
666*0Sstevel@tonic-gate 	if (strlen(name) == 0 || strchr(name, '=') != NULL)
667*0Sstevel@tonic-gate 		uu_die(gettext("Invalid environment variable "
668*0Sstevel@tonic-gate 		    "\"%s\".\n"), name);
669*0Sstevel@tonic-gate 	if (strstr(name, "SMF_") == name)
670*0Sstevel@tonic-gate 		uu_die(gettext("Invalid environment variable "
671*0Sstevel@tonic-gate 		    "\"%s\"; \"SMF_\" prefix is reserved.\n"), name);
672*0Sstevel@tonic-gate 
673*0Sstevel@tonic-gate 	ret = uu_msprintf("%s=%s", name, value);
674*0Sstevel@tonic-gate 	xmlFree(name);
675*0Sstevel@tonic-gate 	xmlFree(value);
676*0Sstevel@tonic-gate 	return (ret);
677*0Sstevel@tonic-gate }
678*0Sstevel@tonic-gate 
679*0Sstevel@tonic-gate static int
680*0Sstevel@tonic-gate lxml_get_method_environment(pgroup_t *pg, xmlNodePtr environment)
681*0Sstevel@tonic-gate {
682*0Sstevel@tonic-gate 	property_t *p;
683*0Sstevel@tonic-gate 	xmlNodePtr cursor;
684*0Sstevel@tonic-gate 	value_t *val;
685*0Sstevel@tonic-gate 
686*0Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_ENVIRONMENT,
687*0Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, 0);
688*0Sstevel@tonic-gate 
689*0Sstevel@tonic-gate 	for (cursor = environment->xmlChildrenNode; cursor != NULL;
690*0Sstevel@tonic-gate 	    cursor = cursor->next) {
691*0Sstevel@tonic-gate 		char *tmp;
692*0Sstevel@tonic-gate 
693*0Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
694*0Sstevel@tonic-gate 			continue;
695*0Sstevel@tonic-gate 
696*0Sstevel@tonic-gate 		if (lxml_xlate_element(cursor->name) != SC_METHOD_ENVVAR)
697*0Sstevel@tonic-gate 			uu_die(gettext("illegal element \"%s\" on "
698*0Sstevel@tonic-gate 			    "method environment for \"%s\"\n"),
699*0Sstevel@tonic-gate 			    cursor->name, pg->sc_pgroup_name);
700*0Sstevel@tonic-gate 
701*0Sstevel@tonic-gate 		if ((tmp = lxml_get_envvar(cursor)) == NULL)
702*0Sstevel@tonic-gate 			uu_die(gettext("Out of memory\n"));
703*0Sstevel@tonic-gate 
704*0Sstevel@tonic-gate 		val = internal_value_new();
705*0Sstevel@tonic-gate 		val->sc_u.sc_string = tmp;
706*0Sstevel@tonic-gate 		val->sc_type = SCF_TYPE_ASTRING;
707*0Sstevel@tonic-gate 		val->sc_free = lxml_free_str;
708*0Sstevel@tonic-gate 		internal_attach_value(p, val);
709*0Sstevel@tonic-gate 	}
710*0Sstevel@tonic-gate 
711*0Sstevel@tonic-gate 	if (internal_attach_property(pg, p) != 0) {
712*0Sstevel@tonic-gate 		internal_property_free(p);
713*0Sstevel@tonic-gate 		return (-1);
714*0Sstevel@tonic-gate 	}
715*0Sstevel@tonic-gate 
716*0Sstevel@tonic-gate 	return (0);
717*0Sstevel@tonic-gate }
718*0Sstevel@tonic-gate 
719*0Sstevel@tonic-gate static int
720*0Sstevel@tonic-gate lxml_get_method_context(pgroup_t *pg, xmlNodePtr ctx)
721*0Sstevel@tonic-gate {
722*0Sstevel@tonic-gate 	xmlNodePtr cursor;
723*0Sstevel@tonic-gate 
724*0Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_WORKING_DIRECTORY,
725*0Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, ctx, "working_directory") != 0)
726*0Sstevel@tonic-gate 		return (-1);
727*0Sstevel@tonic-gate 
728*0Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_PROJECT, SCF_TYPE_ASTRING,
729*0Sstevel@tonic-gate 	    ctx, "project") != 0)
730*0Sstevel@tonic-gate 		return (-1);
731*0Sstevel@tonic-gate 
732*0Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_RESOURCE_POOL,
733*0Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, ctx, "resource_pool") != 0)
734*0Sstevel@tonic-gate 		return (-1);
735*0Sstevel@tonic-gate 
736*0Sstevel@tonic-gate 	for (cursor = ctx->xmlChildrenNode; cursor != NULL;
737*0Sstevel@tonic-gate 	    cursor = cursor->next) {
738*0Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
739*0Sstevel@tonic-gate 			continue;
740*0Sstevel@tonic-gate 
741*0Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
742*0Sstevel@tonic-gate 		case SC_METHOD_CREDENTIAL:
743*0Sstevel@tonic-gate 			(void) lxml_get_method_credential(pg, cursor);
744*0Sstevel@tonic-gate 			break;
745*0Sstevel@tonic-gate 		case SC_METHOD_PROFILE:
746*0Sstevel@tonic-gate 			(void) lxml_get_method_profile(pg, cursor);
747*0Sstevel@tonic-gate 			break;
748*0Sstevel@tonic-gate 		case SC_METHOD_ENVIRONMENT:
749*0Sstevel@tonic-gate 			(void) lxml_get_method_environment(pg, cursor);
750*0Sstevel@tonic-gate 			break;
751*0Sstevel@tonic-gate 		default:
752*0Sstevel@tonic-gate 			semerr(gettext("illegal element \'%s\' in method "
753*0Sstevel@tonic-gate 			    "context\n"), (char *)cursor);
754*0Sstevel@tonic-gate 			break;
755*0Sstevel@tonic-gate 		}
756*0Sstevel@tonic-gate 	}
757*0Sstevel@tonic-gate 
758*0Sstevel@tonic-gate 	return (0);
759*0Sstevel@tonic-gate }
760*0Sstevel@tonic-gate 
761*0Sstevel@tonic-gate static int
762*0Sstevel@tonic-gate lxml_get_entity_method_context(entity_t *entity, xmlNodePtr ctx)
763*0Sstevel@tonic-gate {
764*0Sstevel@tonic-gate 	pgroup_t *pg;
765*0Sstevel@tonic-gate 
766*0Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(entity, SCF_PG_METHOD_CONTEXT,
767*0Sstevel@tonic-gate 	    (char *)scf_group_framework);
768*0Sstevel@tonic-gate 
769*0Sstevel@tonic-gate 	return (lxml_get_method_context(pg, ctx));
770*0Sstevel@tonic-gate }
771*0Sstevel@tonic-gate 
772*0Sstevel@tonic-gate static int
773*0Sstevel@tonic-gate lxml_get_exec_method(entity_t *entity, xmlNodePtr emeth)
774*0Sstevel@tonic-gate {
775*0Sstevel@tonic-gate 	pgroup_t *pg;
776*0Sstevel@tonic-gate 	property_t *p;
777*0Sstevel@tonic-gate 	xmlChar *name, *timeout, *delete;
778*0Sstevel@tonic-gate 	xmlNodePtr cursor;
779*0Sstevel@tonic-gate 	int r = 0;
780*0Sstevel@tonic-gate 
781*0Sstevel@tonic-gate 	name = xmlGetProp(emeth, (xmlChar *)name_attr);
782*0Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(entity, (char *)name,
783*0Sstevel@tonic-gate 	    (char *)SCF_GROUP_METHOD);
784*0Sstevel@tonic-gate 	xmlFree(name);
785*0Sstevel@tonic-gate 
786*0Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_TYPE, SCF_TYPE_ASTRING,
787*0Sstevel@tonic-gate 	    emeth, type_attr) != 0 ||
788*0Sstevel@tonic-gate 	    new_str_prop_from_attr(pg, SCF_PROPERTY_EXEC, SCF_TYPE_ASTRING,
789*0Sstevel@tonic-gate 	    emeth, "exec") != 0)
790*0Sstevel@tonic-gate 		return (-1);
791*0Sstevel@tonic-gate 
792*0Sstevel@tonic-gate 	timeout = xmlGetProp(emeth, (xmlChar *)"timeout_seconds");
793*0Sstevel@tonic-gate 	if (timeout != NULL) {
794*0Sstevel@tonic-gate 		uint64_t u_timeout;
795*0Sstevel@tonic-gate 		char *endptr;
796*0Sstevel@tonic-gate 		/*
797*0Sstevel@tonic-gate 		 * Although an SC_COUNT represents a uint64_t the use
798*0Sstevel@tonic-gate 		 * of a negative value is acceptable due to the usage
799*0Sstevel@tonic-gate 		 * established by inetd(1M).
800*0Sstevel@tonic-gate 		 */
801*0Sstevel@tonic-gate 		errno = 0;
802*0Sstevel@tonic-gate 		u_timeout = strtoull((char *)timeout, &endptr, 10);
803*0Sstevel@tonic-gate 		if (errno != 0 || endptr == (char *)timeout || *endptr)
804*0Sstevel@tonic-gate 			uu_die(gettext("illegal value \"%s\" for "
805*0Sstevel@tonic-gate 			    "timeout_seconds (%s)\n"),
806*0Sstevel@tonic-gate 			    (char *)timeout, (errno) ? strerror(errno):
807*0Sstevel@tonic-gate 			    gettext("Illegal character"));
808*0Sstevel@tonic-gate 		p = internal_property_create(SCF_PROPERTY_TIMEOUT,
809*0Sstevel@tonic-gate 		    SCF_TYPE_COUNT, 1, u_timeout);
810*0Sstevel@tonic-gate 		r = internal_attach_property(pg, p);
811*0Sstevel@tonic-gate 		xmlFree(timeout);
812*0Sstevel@tonic-gate 	}
813*0Sstevel@tonic-gate 	if (r != 0)
814*0Sstevel@tonic-gate 		return (-1);
815*0Sstevel@tonic-gate 
816*0Sstevel@tonic-gate 	/*
817*0Sstevel@tonic-gate 	 * There is a possibility that a method context also exists, in which
818*0Sstevel@tonic-gate 	 * case the following attributes are defined: project, resource_pool,
819*0Sstevel@tonic-gate 	 * working_directory, profile, user, group, privileges, limit_privileges
820*0Sstevel@tonic-gate 	 */
821*0Sstevel@tonic-gate 	for (cursor = emeth->xmlChildrenNode; cursor != NULL;
822*0Sstevel@tonic-gate 	    cursor = cursor->next) {
823*0Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
824*0Sstevel@tonic-gate 			continue;
825*0Sstevel@tonic-gate 
826*0Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
827*0Sstevel@tonic-gate 		case SC_STABILITY:
828*0Sstevel@tonic-gate 			if (lxml_get_pgroup_stability(pg, cursor) != 0)
829*0Sstevel@tonic-gate 				return (-1);
830*0Sstevel@tonic-gate 			break;
831*0Sstevel@tonic-gate 
832*0Sstevel@tonic-gate 		case SC_METHOD_CONTEXT:
833*0Sstevel@tonic-gate 			(void) lxml_get_method_context(pg, cursor);
834*0Sstevel@tonic-gate 			break;
835*0Sstevel@tonic-gate 
836*0Sstevel@tonic-gate 		case SC_PROPVAL:
837*0Sstevel@tonic-gate 			(void) lxml_get_propval(pg, cursor);
838*0Sstevel@tonic-gate 			break;
839*0Sstevel@tonic-gate 
840*0Sstevel@tonic-gate 		case SC_PROPERTY:
841*0Sstevel@tonic-gate 			(void) lxml_get_property(pg, cursor);
842*0Sstevel@tonic-gate 			break;
843*0Sstevel@tonic-gate 
844*0Sstevel@tonic-gate 		default:
845*0Sstevel@tonic-gate 			uu_die(gettext("illegal element \"%s\" on "
846*0Sstevel@tonic-gate 			    "execution method \"%s\"\n"), cursor->name,
847*0Sstevel@tonic-gate 			    pg->sc_pgroup_name);
848*0Sstevel@tonic-gate 			break;
849*0Sstevel@tonic-gate 		}
850*0Sstevel@tonic-gate 	}
851*0Sstevel@tonic-gate 
852*0Sstevel@tonic-gate 	delete = xmlGetProp(emeth, (xmlChar *)delete_attr);
853*0Sstevel@tonic-gate 	pg->sc_pgroup_delete = (xmlStrcmp(delete, (xmlChar *)true) == 0);
854*0Sstevel@tonic-gate 	xmlFree(delete);
855*0Sstevel@tonic-gate 
856*0Sstevel@tonic-gate 	return (0);
857*0Sstevel@tonic-gate }
858*0Sstevel@tonic-gate 
859*0Sstevel@tonic-gate static int
860*0Sstevel@tonic-gate lxml_get_dependency(entity_t *entity, xmlNodePtr dependency)
861*0Sstevel@tonic-gate {
862*0Sstevel@tonic-gate 	pgroup_t *pg;
863*0Sstevel@tonic-gate 	property_t *p;
864*0Sstevel@tonic-gate 	xmlNodePtr cursor;
865*0Sstevel@tonic-gate 	xmlChar *name;
866*0Sstevel@tonic-gate 	xmlChar *delete;
867*0Sstevel@tonic-gate 
868*0Sstevel@tonic-gate 	/*
869*0Sstevel@tonic-gate 	 * dependency attributes:
870*0Sstevel@tonic-gate 	 * name: string
871*0Sstevel@tonic-gate 	 * grouping: require_all | require_any | exclude_all | optional_all
872*0Sstevel@tonic-gate 	 * reset_on: string (error | restart | refresh | none)
873*0Sstevel@tonic-gate 	 * type:  service / path /host
874*0Sstevel@tonic-gate 	 */
875*0Sstevel@tonic-gate 
876*0Sstevel@tonic-gate 	name = xmlGetProp(dependency, (xmlChar *)name_attr);
877*0Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(entity, (char *)name,
878*0Sstevel@tonic-gate 	    (char *)SCF_GROUP_DEPENDENCY);
879*0Sstevel@tonic-gate 	xmlFree(name);
880*0Sstevel@tonic-gate 
881*0Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_TYPE, SCF_TYPE_ASTRING,
882*0Sstevel@tonic-gate 	    dependency, type_attr) != 0)
883*0Sstevel@tonic-gate 		return (-1);
884*0Sstevel@tonic-gate 
885*0Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_RESTART_ON,
886*0Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, dependency, "restart_on") != 0)
887*0Sstevel@tonic-gate 		return (-1);
888*0Sstevel@tonic-gate 
889*0Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_GROUPING, SCF_TYPE_ASTRING,
890*0Sstevel@tonic-gate 	    dependency, "grouping") != 0)
891*0Sstevel@tonic-gate 		return (-1);
892*0Sstevel@tonic-gate 
893*0Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_ENTITIES, SCF_TYPE_FMRI, 0);
894*0Sstevel@tonic-gate 	if (internal_attach_property(pg, p) != 0)
895*0Sstevel@tonic-gate 		return (-1);
896*0Sstevel@tonic-gate 
897*0Sstevel@tonic-gate 	for (cursor = dependency->xmlChildrenNode; cursor != NULL;
898*0Sstevel@tonic-gate 	    cursor = cursor->next) {
899*0Sstevel@tonic-gate 		xmlChar *value;
900*0Sstevel@tonic-gate 		value_t *v;
901*0Sstevel@tonic-gate 
902*0Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
903*0Sstevel@tonic-gate 			continue;
904*0Sstevel@tonic-gate 
905*0Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
906*0Sstevel@tonic-gate 		case SC_STABILITY:
907*0Sstevel@tonic-gate 			if (lxml_get_pgroup_stability(pg, cursor) != 0)
908*0Sstevel@tonic-gate 				return (-1);
909*0Sstevel@tonic-gate 			break;
910*0Sstevel@tonic-gate 
911*0Sstevel@tonic-gate 		case SC_SERVICE_FMRI:
912*0Sstevel@tonic-gate 			value = xmlGetProp(cursor, (xmlChar *)value_attr);
913*0Sstevel@tonic-gate 			if (value != NULL) {
914*0Sstevel@tonic-gate 				if (lxml_validate_string_value(SCF_TYPE_FMRI,
915*0Sstevel@tonic-gate 				    (char *)value) != 0)
916*0Sstevel@tonic-gate 					uu_die(gettext("illegal value \"%s\" "
917*0Sstevel@tonic-gate 					    "for %s (%s)\n"), (char *)value,
918*0Sstevel@tonic-gate 					    lxml_prop_types[SC_FMRI],
919*0Sstevel@tonic-gate 					    (scf_error()) ?
920*0Sstevel@tonic-gate 					    scf_strerror(scf_error()) :
921*0Sstevel@tonic-gate 					    gettext("Illegal format"));
922*0Sstevel@tonic-gate 				v = internal_value_new();
923*0Sstevel@tonic-gate 				v->sc_type = SCF_TYPE_FMRI;
924*0Sstevel@tonic-gate 				v->sc_u.sc_string = (char *)value;
925*0Sstevel@tonic-gate 				internal_attach_value(p, v);
926*0Sstevel@tonic-gate 			}
927*0Sstevel@tonic-gate 
928*0Sstevel@tonic-gate 			break;
929*0Sstevel@tonic-gate 
930*0Sstevel@tonic-gate 		case SC_PROPVAL:
931*0Sstevel@tonic-gate 			(void) lxml_get_propval(pg, cursor);
932*0Sstevel@tonic-gate 			break;
933*0Sstevel@tonic-gate 
934*0Sstevel@tonic-gate 		case SC_PROPERTY:
935*0Sstevel@tonic-gate 			(void) lxml_get_property(pg, cursor);
936*0Sstevel@tonic-gate 			break;
937*0Sstevel@tonic-gate 
938*0Sstevel@tonic-gate 		default:
939*0Sstevel@tonic-gate 			uu_die(gettext("illegal element \"%s\" on "
940*0Sstevel@tonic-gate 			    "dependency group \"%s\"\n"), cursor->name, name);
941*0Sstevel@tonic-gate 			break;
942*0Sstevel@tonic-gate 		}
943*0Sstevel@tonic-gate 	}
944*0Sstevel@tonic-gate 
945*0Sstevel@tonic-gate 	delete = xmlGetProp(dependency, (xmlChar *)delete_attr);
946*0Sstevel@tonic-gate 	pg->sc_pgroup_delete = (xmlStrcmp(delete, (xmlChar *)true) == 0);
947*0Sstevel@tonic-gate 	xmlFree(delete);
948*0Sstevel@tonic-gate 
949*0Sstevel@tonic-gate 	return (0);
950*0Sstevel@tonic-gate }
951*0Sstevel@tonic-gate 
952*0Sstevel@tonic-gate /*
953*0Sstevel@tonic-gate  * Dependents are hairy.  They should cause a dependency pg to be created in
954*0Sstevel@tonic-gate  * another service, but we can't do that here; we'll have to wait until the
955*0Sstevel@tonic-gate  * import routines.  So for now we'll add the dependency group that should go
956*0Sstevel@tonic-gate  * in the other service to the entity's dependent list.
957*0Sstevel@tonic-gate  */
958*0Sstevel@tonic-gate static int
959*0Sstevel@tonic-gate lxml_get_dependent(entity_t *entity, xmlNodePtr dependent)
960*0Sstevel@tonic-gate {
961*0Sstevel@tonic-gate 	xmlChar *name, *or;
962*0Sstevel@tonic-gate 	xmlNodePtr sf;
963*0Sstevel@tonic-gate 	xmlChar *fmri, *delete;
964*0Sstevel@tonic-gate 	pgroup_t *pg;
965*0Sstevel@tonic-gate 	property_t *p;
966*0Sstevel@tonic-gate 	xmlNodePtr n;
967*0Sstevel@tonic-gate 	char *myfmri;
968*0Sstevel@tonic-gate 
969*0Sstevel@tonic-gate 	name = xmlGetProp(dependent, (xmlChar *)name_attr);
970*0Sstevel@tonic-gate 
971*0Sstevel@tonic-gate 	if (internal_pgroup_find(entity, (char *)name, NULL) != NULL) {
972*0Sstevel@tonic-gate 		semerr(gettext("Property group and dependent of entity %s "
973*0Sstevel@tonic-gate 		    "have same name \"%s\".\n"), entity->sc_name, name);
974*0Sstevel@tonic-gate 		xmlFree(name);
975*0Sstevel@tonic-gate 		return (-1);
976*0Sstevel@tonic-gate 	}
977*0Sstevel@tonic-gate 
978*0Sstevel@tonic-gate 	or = xmlGetProp(dependent, (xmlChar *)override_attr);
979*0Sstevel@tonic-gate 
980*0Sstevel@tonic-gate 	pg = internal_pgroup_new();
981*0Sstevel@tonic-gate 	pg->sc_pgroup_name = (char *)name;
982*0Sstevel@tonic-gate 	pg->sc_pgroup_type = (char *)SCF_GROUP_DEPENDENCY;
983*0Sstevel@tonic-gate 	pg->sc_pgroup_override = (xmlStrcmp(or, (xmlChar *)true) == 0);
984*0Sstevel@tonic-gate 	xmlFree(or);
985*0Sstevel@tonic-gate 	if (internal_attach_dependent(entity, pg) != 0) {
986*0Sstevel@tonic-gate 		xmlFree(name);
987*0Sstevel@tonic-gate 		internal_pgroup_free(pg);
988*0Sstevel@tonic-gate 		return (-1);
989*0Sstevel@tonic-gate 	}
990*0Sstevel@tonic-gate 
991*0Sstevel@tonic-gate 	for (sf = dependent->children; sf != NULL; sf = sf->next)
992*0Sstevel@tonic-gate 		if (xmlStrcmp(sf->name, (xmlChar *)"service_fmri") == 0)
993*0Sstevel@tonic-gate 			break;
994*0Sstevel@tonic-gate 	assert(sf != NULL);
995*0Sstevel@tonic-gate 	fmri = xmlGetProp(sf, (xmlChar *)value_attr);
996*0Sstevel@tonic-gate 	pg->sc_pgroup_fmri = (char *)fmri;
997*0Sstevel@tonic-gate 
998*0Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_RESTART_ON,
999*0Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, dependent, "restart_on") != 0)
1000*0Sstevel@tonic-gate 		return (-1);
1001*0Sstevel@tonic-gate 
1002*0Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_GROUPING, SCF_TYPE_ASTRING,
1003*0Sstevel@tonic-gate 	    dependent, "grouping") != 0)
1004*0Sstevel@tonic-gate 		return (-1);
1005*0Sstevel@tonic-gate 
1006*0Sstevel@tonic-gate 	myfmri = safe_malloc(max_scf_fmri_len + 1);
1007*0Sstevel@tonic-gate 	if (entity->sc_etype == SVCCFG_SERVICE_OBJECT) {
1008*0Sstevel@tonic-gate 		if (snprintf(myfmri, max_scf_fmri_len + 1, "svc:/%s",
1009*0Sstevel@tonic-gate 		    entity->sc_name) < 0)
1010*0Sstevel@tonic-gate 			bad_error("snprintf", errno);
1011*0Sstevel@tonic-gate 	} else {
1012*0Sstevel@tonic-gate 		assert(entity->sc_etype == SVCCFG_INSTANCE_OBJECT);
1013*0Sstevel@tonic-gate 		if (snprintf(myfmri, max_scf_fmri_len + 1, "svc:/%s:%s",
1014*0Sstevel@tonic-gate 		    entity->sc_parent->sc_name, entity->sc_name) < 0)
1015*0Sstevel@tonic-gate 			bad_error("snprintf", errno);
1016*0Sstevel@tonic-gate 	}
1017*0Sstevel@tonic-gate 
1018*0Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_ENTITIES, SCF_TYPE_FMRI, 1,
1019*0Sstevel@tonic-gate 	    myfmri);
1020*0Sstevel@tonic-gate 	if (internal_attach_property(pg, p) != 0)
1021*0Sstevel@tonic-gate 		return (-1);
1022*0Sstevel@tonic-gate 
1023*0Sstevel@tonic-gate 	/* Create a property to serve as a do-not-export flag. */
1024*0Sstevel@tonic-gate 	p = internal_property_create("external", SCF_TYPE_BOOLEAN, 1,
1025*0Sstevel@tonic-gate 	    (uint64_t)1);
1026*0Sstevel@tonic-gate 	if (internal_attach_property(pg, p) != 0)
1027*0Sstevel@tonic-gate 		return (-1);
1028*0Sstevel@tonic-gate 
1029*0Sstevel@tonic-gate 	for (n = sf->next; n != NULL; n = n->next) {
1030*0Sstevel@tonic-gate 		if (lxml_ignorable_block(n))
1031*0Sstevel@tonic-gate 			continue;
1032*0Sstevel@tonic-gate 
1033*0Sstevel@tonic-gate 		switch (lxml_xlate_element(n->name)) {
1034*0Sstevel@tonic-gate 		case SC_STABILITY:
1035*0Sstevel@tonic-gate 			if (new_str_prop_from_attr(pg,
1036*0Sstevel@tonic-gate 			    SCF_PROPERTY_ENTITY_STABILITY, SCF_TYPE_ASTRING, n,
1037*0Sstevel@tonic-gate 			    value_attr) != 0)
1038*0Sstevel@tonic-gate 				return (-1);
1039*0Sstevel@tonic-gate 			break;
1040*0Sstevel@tonic-gate 
1041*0Sstevel@tonic-gate 		case SC_PROPVAL:
1042*0Sstevel@tonic-gate 			(void) lxml_get_propval(pg, n);
1043*0Sstevel@tonic-gate 			break;
1044*0Sstevel@tonic-gate 
1045*0Sstevel@tonic-gate 		case SC_PROPERTY:
1046*0Sstevel@tonic-gate 			(void) lxml_get_property(pg, n);
1047*0Sstevel@tonic-gate 			break;
1048*0Sstevel@tonic-gate 
1049*0Sstevel@tonic-gate 		default:
1050*0Sstevel@tonic-gate 			uu_die(gettext("unexpected element %s.\n"), n->name);
1051*0Sstevel@tonic-gate 		}
1052*0Sstevel@tonic-gate 	}
1053*0Sstevel@tonic-gate 
1054*0Sstevel@tonic-gate 	/* Go back and fill in defaults. */
1055*0Sstevel@tonic-gate 	if (internal_property_find(pg, SCF_PROPERTY_TYPE) == NULL) {
1056*0Sstevel@tonic-gate 		p = internal_property_create(SCF_PROPERTY_TYPE,
1057*0Sstevel@tonic-gate 		    SCF_TYPE_ASTRING, 1, "service");
1058*0Sstevel@tonic-gate 		if (internal_attach_property(pg, p) != 0)
1059*0Sstevel@tonic-gate 			return (-1);
1060*0Sstevel@tonic-gate 	}
1061*0Sstevel@tonic-gate 
1062*0Sstevel@tonic-gate 	delete = xmlGetProp(dependent, (xmlChar *)delete_attr);
1063*0Sstevel@tonic-gate 	pg->sc_pgroup_delete = (xmlStrcmp(delete, (xmlChar *)true) == 0);
1064*0Sstevel@tonic-gate 	xmlFree(delete);
1065*0Sstevel@tonic-gate 
1066*0Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(entity, "dependents",
1067*0Sstevel@tonic-gate 	    (char *)scf_group_framework);
1068*0Sstevel@tonic-gate 	p = internal_property_create((char *)name, SCF_TYPE_ASTRING, 1, fmri);
1069*0Sstevel@tonic-gate 	if (internal_attach_property(pg, p) != 0)
1070*0Sstevel@tonic-gate 		return (-1);
1071*0Sstevel@tonic-gate 
1072*0Sstevel@tonic-gate 	return (0);
1073*0Sstevel@tonic-gate }
1074*0Sstevel@tonic-gate 
1075*0Sstevel@tonic-gate static int
1076*0Sstevel@tonic-gate lxml_get_entity_stability(entity_t *entity, xmlNodePtr rstr)
1077*0Sstevel@tonic-gate {
1078*0Sstevel@tonic-gate 	pgroup_t *pg;
1079*0Sstevel@tonic-gate 	property_t *p;
1080*0Sstevel@tonic-gate 	xmlChar *stabval;
1081*0Sstevel@tonic-gate 
1082*0Sstevel@tonic-gate 	if ((stabval = xmlGetProp(rstr, (xmlChar *)value_attr)) == NULL) {
1083*0Sstevel@tonic-gate 		uu_warn(gettext("no stability value found\n"));
1084*0Sstevel@tonic-gate 		stabval = (xmlChar *)strdup("External");
1085*0Sstevel@tonic-gate 	}
1086*0Sstevel@tonic-gate 
1087*0Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(entity, (char *)scf_pg_general,
1088*0Sstevel@tonic-gate 	    (char *)scf_group_framework);
1089*0Sstevel@tonic-gate 
1090*0Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_ENTITY_STABILITY,
1091*0Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, 1, stabval);
1092*0Sstevel@tonic-gate 
1093*0Sstevel@tonic-gate 	return (internal_attach_property(pg, p));
1094*0Sstevel@tonic-gate }
1095*0Sstevel@tonic-gate 
1096*0Sstevel@tonic-gate static int
1097*0Sstevel@tonic-gate lxml_get_restarter(entity_t *entity, xmlNodePtr rstr)
1098*0Sstevel@tonic-gate {
1099*0Sstevel@tonic-gate 	pgroup_t *pg;
1100*0Sstevel@tonic-gate 	property_t *p;
1101*0Sstevel@tonic-gate 	xmlChar *restarter;
1102*0Sstevel@tonic-gate 	xmlNode *cursor;
1103*0Sstevel@tonic-gate 	int r;
1104*0Sstevel@tonic-gate 
1105*0Sstevel@tonic-gate 	/*
1106*0Sstevel@tonic-gate 	 * Go find child.  Child is a service_fmri element.  value attribute
1107*0Sstevel@tonic-gate 	 * contains restarter FMRI.
1108*0Sstevel@tonic-gate 	 */
1109*0Sstevel@tonic-gate 
1110*0Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(entity, (char *)scf_pg_general,
1111*0Sstevel@tonic-gate 	    (char *)scf_group_framework);
1112*0Sstevel@tonic-gate 
1113*0Sstevel@tonic-gate 	/*
1114*0Sstevel@tonic-gate 	 * Walk its child elements, as appropriate.
1115*0Sstevel@tonic-gate 	 */
1116*0Sstevel@tonic-gate 	for (cursor = rstr->xmlChildrenNode; cursor != NULL;
1117*0Sstevel@tonic-gate 	    cursor = cursor->next) {
1118*0Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
1119*0Sstevel@tonic-gate 			continue;
1120*0Sstevel@tonic-gate 
1121*0Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
1122*0Sstevel@tonic-gate 		case SC_SERVICE_FMRI:
1123*0Sstevel@tonic-gate 			restarter = xmlGetProp(cursor, (xmlChar *)value_attr);
1124*0Sstevel@tonic-gate 			break;
1125*0Sstevel@tonic-gate 		default:
1126*0Sstevel@tonic-gate 			uu_die(gettext("illegal element \"%s\" on restarter "
1127*0Sstevel@tonic-gate 			    "element for \"%s\"\n"), cursor->name,
1128*0Sstevel@tonic-gate 			    entity->sc_name);
1129*0Sstevel@tonic-gate 			break;
1130*0Sstevel@tonic-gate 		}
1131*0Sstevel@tonic-gate 	}
1132*0Sstevel@tonic-gate 
1133*0Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_RESTARTER, SCF_TYPE_FMRI, 1,
1134*0Sstevel@tonic-gate 	    restarter);
1135*0Sstevel@tonic-gate 
1136*0Sstevel@tonic-gate 	r = internal_attach_property(pg, p);
1137*0Sstevel@tonic-gate 	if (r != 0) {
1138*0Sstevel@tonic-gate 		internal_property_free(p);
1139*0Sstevel@tonic-gate 		return (-1);
1140*0Sstevel@tonic-gate 	}
1141*0Sstevel@tonic-gate 
1142*0Sstevel@tonic-gate 	return (0);
1143*0Sstevel@tonic-gate }
1144*0Sstevel@tonic-gate 
1145*0Sstevel@tonic-gate static void
1146*0Sstevel@tonic-gate sanitize_locale(uchar_t *locale)
1147*0Sstevel@tonic-gate {
1148*0Sstevel@tonic-gate 	for (; *locale != '\0'; locale++)
1149*0Sstevel@tonic-gate 		if (!isalnum(*locale) && *locale != '_')
1150*0Sstevel@tonic-gate 			*locale = '_';
1151*0Sstevel@tonic-gate }
1152*0Sstevel@tonic-gate 
1153*0Sstevel@tonic-gate static int
1154*0Sstevel@tonic-gate lxml_get_loctext(entity_t *service, pgroup_t *pg, xmlNodePtr loctext)
1155*0Sstevel@tonic-gate {
1156*0Sstevel@tonic-gate 	xmlNodePtr cursor;
1157*0Sstevel@tonic-gate 	xmlChar *val;
1158*0Sstevel@tonic-gate 	char *stripped, *cp;
1159*0Sstevel@tonic-gate 	property_t *p;
1160*0Sstevel@tonic-gate 	int r;
1161*0Sstevel@tonic-gate 
1162*0Sstevel@tonic-gate 	if ((val = xmlGetProp(loctext, (xmlChar *)"xml:lang")) == NULL)
1163*0Sstevel@tonic-gate 		if ((val = xmlGetProp(loctext, (xmlChar *)"lang")) == NULL)
1164*0Sstevel@tonic-gate 			val = (xmlChar *)"unknown";
1165*0Sstevel@tonic-gate 
1166*0Sstevel@tonic-gate 	sanitize_locale(val);
1167*0Sstevel@tonic-gate 
1168*0Sstevel@tonic-gate 	for (cursor = loctext->xmlChildrenNode; cursor != NULL;
1169*0Sstevel@tonic-gate 	    cursor = cursor->next) {
1170*0Sstevel@tonic-gate 		if (strcmp("text", (const char *)cursor->name) == 0) {
1171*0Sstevel@tonic-gate 			break;
1172*0Sstevel@tonic-gate 		} else if (strcmp("comment", (const char *)cursor->name) != 0) {
1173*0Sstevel@tonic-gate 			uu_die(gettext("illegal element \"%s\" on loctext "
1174*0Sstevel@tonic-gate 			    "element for \"%s\"\n"), cursor->name,
1175*0Sstevel@tonic-gate 			    service->sc_name);
1176*0Sstevel@tonic-gate 		}
1177*0Sstevel@tonic-gate 	}
1178*0Sstevel@tonic-gate 
1179*0Sstevel@tonic-gate 	if (cursor == NULL) {
1180*0Sstevel@tonic-gate 		uu_die(gettext("loctext element has no content for \"%s\"\n"),
1181*0Sstevel@tonic-gate 		    service->sc_name);
1182*0Sstevel@tonic-gate 	}
1183*0Sstevel@tonic-gate 
1184*0Sstevel@tonic-gate 	/*
1185*0Sstevel@tonic-gate 	 * Remove leading and trailing whitespace.
1186*0Sstevel@tonic-gate 	 */
1187*0Sstevel@tonic-gate 	if ((stripped = strdup((const char *)cursor->content)) == NULL)
1188*0Sstevel@tonic-gate 		uu_die(gettext("Out of memory\n"));
1189*0Sstevel@tonic-gate 
1190*0Sstevel@tonic-gate 	for (; isspace(*stripped); stripped++);
1191*0Sstevel@tonic-gate 	for (cp = stripped + strlen(stripped) - 1; isspace(*cp); cp--);
1192*0Sstevel@tonic-gate 	*(cp + 1) = '\0';
1193*0Sstevel@tonic-gate 
1194*0Sstevel@tonic-gate 	p = internal_property_create((const char *)val, SCF_TYPE_USTRING, 1,
1195*0Sstevel@tonic-gate 	    stripped);
1196*0Sstevel@tonic-gate 
1197*0Sstevel@tonic-gate 	r = internal_attach_property(pg, p);
1198*0Sstevel@tonic-gate 	if (r != 0)
1199*0Sstevel@tonic-gate 		internal_property_free(p);
1200*0Sstevel@tonic-gate 
1201*0Sstevel@tonic-gate 	return (r);
1202*0Sstevel@tonic-gate }
1203*0Sstevel@tonic-gate 
1204*0Sstevel@tonic-gate static int
1205*0Sstevel@tonic-gate lxml_get_tm_common_name(entity_t *service, xmlNodePtr common_name)
1206*0Sstevel@tonic-gate {
1207*0Sstevel@tonic-gate 	xmlNodePtr cursor;
1208*0Sstevel@tonic-gate 	pgroup_t *pg;
1209*0Sstevel@tonic-gate 
1210*0Sstevel@tonic-gate 	/*
1211*0Sstevel@tonic-gate 	 * Create the property group, if absent.
1212*0Sstevel@tonic-gate 	 */
1213*0Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(service,
1214*0Sstevel@tonic-gate 	    (char *)SCF_PG_TM_COMMON_NAME, (char *)SCF_GROUP_TEMPLATE);
1215*0Sstevel@tonic-gate 
1216*0Sstevel@tonic-gate 	/*
1217*0Sstevel@tonic-gate 	 * Iterate through one or more loctext elements.  The locale is the
1218*0Sstevel@tonic-gate 	 * property name; the contents are the ustring value for the property.
1219*0Sstevel@tonic-gate 	 */
1220*0Sstevel@tonic-gate 	for (cursor = common_name->xmlChildrenNode; cursor != NULL;
1221*0Sstevel@tonic-gate 	    cursor = cursor->next) {
1222*0Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
1223*0Sstevel@tonic-gate 			continue;
1224*0Sstevel@tonic-gate 
1225*0Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
1226*0Sstevel@tonic-gate 		case SC_LOCTEXT:
1227*0Sstevel@tonic-gate 			if (lxml_get_loctext(service, pg, cursor))
1228*0Sstevel@tonic-gate 				return (-1);
1229*0Sstevel@tonic-gate 			break;
1230*0Sstevel@tonic-gate 		default:
1231*0Sstevel@tonic-gate 			uu_die(gettext("illegal element \"%s\" on common_name "
1232*0Sstevel@tonic-gate 			    "element for \"%s\"\n"), cursor->name,
1233*0Sstevel@tonic-gate 			    service->sc_name);
1234*0Sstevel@tonic-gate 			break;
1235*0Sstevel@tonic-gate 		}
1236*0Sstevel@tonic-gate 	}
1237*0Sstevel@tonic-gate 
1238*0Sstevel@tonic-gate 	return (0);
1239*0Sstevel@tonic-gate }
1240*0Sstevel@tonic-gate 
1241*0Sstevel@tonic-gate static int
1242*0Sstevel@tonic-gate lxml_get_tm_description(entity_t *service, xmlNodePtr description)
1243*0Sstevel@tonic-gate {
1244*0Sstevel@tonic-gate 	xmlNodePtr cursor;
1245*0Sstevel@tonic-gate 	pgroup_t *pg;
1246*0Sstevel@tonic-gate 
1247*0Sstevel@tonic-gate 	/*
1248*0Sstevel@tonic-gate 	 * Create the property group, if absent.
1249*0Sstevel@tonic-gate 	 */
1250*0Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(service,
1251*0Sstevel@tonic-gate 	    (char *)SCF_PG_TM_DESCRIPTION, (char *)SCF_GROUP_TEMPLATE);
1252*0Sstevel@tonic-gate 
1253*0Sstevel@tonic-gate 	/*
1254*0Sstevel@tonic-gate 	 * Iterate through one or more loctext elements.  The locale is the
1255*0Sstevel@tonic-gate 	 * property name; the contents are the ustring value for the property.
1256*0Sstevel@tonic-gate 	 */
1257*0Sstevel@tonic-gate 	for (cursor = description->xmlChildrenNode; cursor != NULL;
1258*0Sstevel@tonic-gate 	    cursor = cursor->next) {
1259*0Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
1260*0Sstevel@tonic-gate 			continue;
1261*0Sstevel@tonic-gate 
1262*0Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
1263*0Sstevel@tonic-gate 		case SC_LOCTEXT:
1264*0Sstevel@tonic-gate 			if (lxml_get_loctext(service, pg, cursor))
1265*0Sstevel@tonic-gate 				return (-1);
1266*0Sstevel@tonic-gate 			break;
1267*0Sstevel@tonic-gate 		default:
1268*0Sstevel@tonic-gate 			uu_die(gettext("illegal element \"%s\" on description "
1269*0Sstevel@tonic-gate 			    "element for \"%s\"\n"), cursor->name,
1270*0Sstevel@tonic-gate 			    service->sc_name);
1271*0Sstevel@tonic-gate 			break;
1272*0Sstevel@tonic-gate 		}
1273*0Sstevel@tonic-gate 	}
1274*0Sstevel@tonic-gate 
1275*0Sstevel@tonic-gate 	return (0);
1276*0Sstevel@tonic-gate }
1277*0Sstevel@tonic-gate 
1278*0Sstevel@tonic-gate static char *
1279*0Sstevel@tonic-gate lxml_label_to_groupname(const char *prefix, const char *in)
1280*0Sstevel@tonic-gate {
1281*0Sstevel@tonic-gate 	char *out, *cp;
1282*0Sstevel@tonic-gate 	size_t len, piece_len;
1283*0Sstevel@tonic-gate 
1284*0Sstevel@tonic-gate 	out = uu_zalloc(2 * scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1);
1285*0Sstevel@tonic-gate 	if (out == NULL)
1286*0Sstevel@tonic-gate 		return (NULL);
1287*0Sstevel@tonic-gate 
1288*0Sstevel@tonic-gate 	(void) strcpy(out, prefix);
1289*0Sstevel@tonic-gate 	(void) strcat(out, in);
1290*0Sstevel@tonic-gate 
1291*0Sstevel@tonic-gate 	len = strlen(out);
1292*0Sstevel@tonic-gate 	if (len > max_scf_name_len) {
1293*0Sstevel@tonic-gate 		/* Use the first half and the second half. */
1294*0Sstevel@tonic-gate 		piece_len = (max_scf_name_len - 2) / 2;
1295*0Sstevel@tonic-gate 
1296*0Sstevel@tonic-gate 		(void) strncpy(out + piece_len, "..", 2);
1297*0Sstevel@tonic-gate 
1298*0Sstevel@tonic-gate 		(void) strcpy(out + piece_len + 2, out + (len - piece_len));
1299*0Sstevel@tonic-gate 
1300*0Sstevel@tonic-gate 		len = strlen(out);
1301*0Sstevel@tonic-gate 	}
1302*0Sstevel@tonic-gate 
1303*0Sstevel@tonic-gate 	/*
1304*0Sstevel@tonic-gate 	 * Translate non-property characters to '_'.
1305*0Sstevel@tonic-gate 	 */
1306*0Sstevel@tonic-gate 	for (cp = out; *cp != '\0'; ++cp) {
1307*0Sstevel@tonic-gate 		if (!(isalnum(*cp) || *cp == '_' || *cp == '-'))
1308*0Sstevel@tonic-gate 			*cp = '_';
1309*0Sstevel@tonic-gate 	}
1310*0Sstevel@tonic-gate 
1311*0Sstevel@tonic-gate 	*cp = '\0';
1312*0Sstevel@tonic-gate 
1313*0Sstevel@tonic-gate 	return (out);
1314*0Sstevel@tonic-gate }
1315*0Sstevel@tonic-gate 
1316*0Sstevel@tonic-gate static int
1317*0Sstevel@tonic-gate lxml_get_tm_manpage(entity_t *service, xmlNodePtr manpage)
1318*0Sstevel@tonic-gate {
1319*0Sstevel@tonic-gate 	pgroup_t *pg;
1320*0Sstevel@tonic-gate 	char *pgname;
1321*0Sstevel@tonic-gate 	xmlChar *title;
1322*0Sstevel@tonic-gate 
1323*0Sstevel@tonic-gate 	/*
1324*0Sstevel@tonic-gate 	 * Fetch title attribute, convert to something sanitized, and create
1325*0Sstevel@tonic-gate 	 * property group.
1326*0Sstevel@tonic-gate 	 */
1327*0Sstevel@tonic-gate 	title = xmlGetProp(manpage, (xmlChar *)"title");
1328*0Sstevel@tonic-gate 	pgname = (char *)lxml_label_to_groupname(SCF_PG_TM_MAN_PREFIX,
1329*0Sstevel@tonic-gate 	    (const char *)title);
1330*0Sstevel@tonic-gate 
1331*0Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(service, pgname,
1332*0Sstevel@tonic-gate 	    (char *)SCF_GROUP_TEMPLATE);
1333*0Sstevel@tonic-gate 
1334*0Sstevel@tonic-gate 	/*
1335*0Sstevel@tonic-gate 	 * Each attribute is an astring property within the group.
1336*0Sstevel@tonic-gate 	 */
1337*0Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, "title", SCF_TYPE_ASTRING, manpage,
1338*0Sstevel@tonic-gate 	    "title") != 0 ||
1339*0Sstevel@tonic-gate 	    new_str_prop_from_attr(pg, "section", SCF_TYPE_ASTRING, manpage,
1340*0Sstevel@tonic-gate 	    "section") != 0 ||
1341*0Sstevel@tonic-gate 	    new_str_prop_from_attr(pg, "manpath", SCF_TYPE_ASTRING, manpage,
1342*0Sstevel@tonic-gate 	    "manpath") != 0)
1343*0Sstevel@tonic-gate 		return (-1);
1344*0Sstevel@tonic-gate 
1345*0Sstevel@tonic-gate 	return (0);
1346*0Sstevel@tonic-gate }
1347*0Sstevel@tonic-gate 
1348*0Sstevel@tonic-gate static int
1349*0Sstevel@tonic-gate lxml_get_tm_doclink(entity_t *service, xmlNodePtr doc_link)
1350*0Sstevel@tonic-gate {
1351*0Sstevel@tonic-gate 	pgroup_t *pg;
1352*0Sstevel@tonic-gate 	char *pgname;
1353*0Sstevel@tonic-gate 	xmlChar *name;
1354*0Sstevel@tonic-gate 
1355*0Sstevel@tonic-gate 	/*
1356*0Sstevel@tonic-gate 	 * Fetch name attribute, convert name to something sanitized, and create
1357*0Sstevel@tonic-gate 	 * property group.
1358*0Sstevel@tonic-gate 	 */
1359*0Sstevel@tonic-gate 	name = xmlGetProp(doc_link, (xmlChar *)"name");
1360*0Sstevel@tonic-gate 
1361*0Sstevel@tonic-gate 	pgname = (char *)lxml_label_to_groupname(SCF_PG_TM_DOC_PREFIX,
1362*0Sstevel@tonic-gate 	    (const char *)name);
1363*0Sstevel@tonic-gate 
1364*0Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(service, pgname,
1365*0Sstevel@tonic-gate 	    (char *)SCF_GROUP_TEMPLATE);
1366*0Sstevel@tonic-gate 
1367*0Sstevel@tonic-gate 	/*
1368*0Sstevel@tonic-gate 	 * Each attribute is an astring property within the group.
1369*0Sstevel@tonic-gate 	 */
1370*0Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, "name", SCF_TYPE_ASTRING, doc_link,
1371*0Sstevel@tonic-gate 	    "name") != 0 ||
1372*0Sstevel@tonic-gate 	    new_str_prop_from_attr(pg, "uri", SCF_TYPE_ASTRING, doc_link,
1373*0Sstevel@tonic-gate 	    "uri") != 0)
1374*0Sstevel@tonic-gate 		return (-1);
1375*0Sstevel@tonic-gate 
1376*0Sstevel@tonic-gate 	return (0);
1377*0Sstevel@tonic-gate }
1378*0Sstevel@tonic-gate 
1379*0Sstevel@tonic-gate static int
1380*0Sstevel@tonic-gate lxml_get_tm_documentation(entity_t *service, xmlNodePtr documentation)
1381*0Sstevel@tonic-gate {
1382*0Sstevel@tonic-gate 	xmlNodePtr cursor;
1383*0Sstevel@tonic-gate 
1384*0Sstevel@tonic-gate 	for (cursor = documentation->xmlChildrenNode; cursor != NULL;
1385*0Sstevel@tonic-gate 	    cursor = cursor->next) {
1386*0Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
1387*0Sstevel@tonic-gate 			continue;
1388*0Sstevel@tonic-gate 
1389*0Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
1390*0Sstevel@tonic-gate 		case SC_MANPAGE:
1391*0Sstevel@tonic-gate 			(void) lxml_get_tm_manpage(service, cursor);
1392*0Sstevel@tonic-gate 			break;
1393*0Sstevel@tonic-gate 		case SC_DOC_LINK:
1394*0Sstevel@tonic-gate 			(void) lxml_get_tm_doclink(service, cursor);
1395*0Sstevel@tonic-gate 			break;
1396*0Sstevel@tonic-gate 		default:
1397*0Sstevel@tonic-gate 			uu_die(gettext("illegal element \"%s\" on template "
1398*0Sstevel@tonic-gate 			    "for service \"%s\"\n"),
1399*0Sstevel@tonic-gate 			    cursor->name, service->sc_name);
1400*0Sstevel@tonic-gate 		}
1401*0Sstevel@tonic-gate 	}
1402*0Sstevel@tonic-gate 
1403*0Sstevel@tonic-gate 	return (0);
1404*0Sstevel@tonic-gate }
1405*0Sstevel@tonic-gate 
1406*0Sstevel@tonic-gate static int
1407*0Sstevel@tonic-gate lxml_get_template(entity_t *service, xmlNodePtr templ)
1408*0Sstevel@tonic-gate {
1409*0Sstevel@tonic-gate 	xmlNodePtr cursor;
1410*0Sstevel@tonic-gate 
1411*0Sstevel@tonic-gate 	for (cursor = templ->xmlChildrenNode; cursor != NULL;
1412*0Sstevel@tonic-gate 	    cursor = cursor->next) {
1413*0Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
1414*0Sstevel@tonic-gate 			continue;
1415*0Sstevel@tonic-gate 
1416*0Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
1417*0Sstevel@tonic-gate 		case SC_COMMON_NAME:
1418*0Sstevel@tonic-gate 			(void) lxml_get_tm_common_name(service, cursor);
1419*0Sstevel@tonic-gate 			break;
1420*0Sstevel@tonic-gate 		case SC_DESCRIPTION:
1421*0Sstevel@tonic-gate 			(void) lxml_get_tm_description(service, cursor);
1422*0Sstevel@tonic-gate 			break;
1423*0Sstevel@tonic-gate 		case SC_DOCUMENTATION:
1424*0Sstevel@tonic-gate 			(void) lxml_get_tm_documentation(service, cursor);
1425*0Sstevel@tonic-gate 			break;
1426*0Sstevel@tonic-gate 		default:
1427*0Sstevel@tonic-gate 			uu_die(gettext("illegal element \"%s\" on template "
1428*0Sstevel@tonic-gate 			    "for service \"%s\"\n"),
1429*0Sstevel@tonic-gate 			    cursor->name, service->sc_name);
1430*0Sstevel@tonic-gate 		}
1431*0Sstevel@tonic-gate 	}
1432*0Sstevel@tonic-gate 
1433*0Sstevel@tonic-gate 	return (0);
1434*0Sstevel@tonic-gate }
1435*0Sstevel@tonic-gate 
1436*0Sstevel@tonic-gate static int
1437*0Sstevel@tonic-gate lxml_get_default_instance(entity_t *service, xmlNodePtr definst)
1438*0Sstevel@tonic-gate {
1439*0Sstevel@tonic-gate 	entity_t *i;
1440*0Sstevel@tonic-gate 	xmlChar *enabled;
1441*0Sstevel@tonic-gate 	pgroup_t *pg;
1442*0Sstevel@tonic-gate 	property_t *p;
1443*0Sstevel@tonic-gate 	char *package;
1444*0Sstevel@tonic-gate 	uint64_t enabled_val = 0;
1445*0Sstevel@tonic-gate 
1446*0Sstevel@tonic-gate 	i = internal_instance_new("default");
1447*0Sstevel@tonic-gate 
1448*0Sstevel@tonic-gate 	if ((enabled = xmlGetProp(definst, (xmlChar *)enabled_attr)) != NULL) {
1449*0Sstevel@tonic-gate 		enabled_val = (strcmp(true, (const char *)enabled) == 0) ?
1450*0Sstevel@tonic-gate 		    1 : 0;
1451*0Sstevel@tonic-gate 		xmlFree(enabled);
1452*0Sstevel@tonic-gate 	}
1453*0Sstevel@tonic-gate 
1454*0Sstevel@tonic-gate 	/*
1455*0Sstevel@tonic-gate 	 * New general property group with enabled boolean property set.
1456*0Sstevel@tonic-gate 	 */
1457*0Sstevel@tonic-gate 
1458*0Sstevel@tonic-gate 	pg = internal_pgroup_new();
1459*0Sstevel@tonic-gate 	(void) internal_attach_pgroup(i, pg);
1460*0Sstevel@tonic-gate 
1461*0Sstevel@tonic-gate 	pg->sc_pgroup_name = (char *)scf_pg_general;
1462*0Sstevel@tonic-gate 	pg->sc_pgroup_type = (char *)scf_group_framework;
1463*0Sstevel@tonic-gate 	pg->sc_pgroup_flags = 0;
1464*0Sstevel@tonic-gate 
1465*0Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_ENABLED, SCF_TYPE_BOOLEAN, 1,
1466*0Sstevel@tonic-gate 	    enabled_val);
1467*0Sstevel@tonic-gate 
1468*0Sstevel@tonic-gate 	(void) internal_attach_property(pg, p);
1469*0Sstevel@tonic-gate 
1470*0Sstevel@tonic-gate 	/*
1471*0Sstevel@tonic-gate 	 * Add general/package property if PKGINST is set.
1472*0Sstevel@tonic-gate 	 */
1473*0Sstevel@tonic-gate 	if ((package = getenv("PKGINST")) != NULL) {
1474*0Sstevel@tonic-gate 		p = internal_property_create(SCF_PROPERTY_PACKAGE,
1475*0Sstevel@tonic-gate 		    SCF_TYPE_ASTRING, 1, package);
1476*0Sstevel@tonic-gate 
1477*0Sstevel@tonic-gate 		(void) internal_attach_property(pg, p);
1478*0Sstevel@tonic-gate 	}
1479*0Sstevel@tonic-gate 
1480*0Sstevel@tonic-gate 	return (internal_attach_entity(service, i));
1481*0Sstevel@tonic-gate }
1482*0Sstevel@tonic-gate 
1483*0Sstevel@tonic-gate /*
1484*0Sstevel@tonic-gate  * Translate an instance element into an internal property tree, added to
1485*0Sstevel@tonic-gate  * service.  If apply is true, forbid subelements and set the enabled property
1486*0Sstevel@tonic-gate  * to override.
1487*0Sstevel@tonic-gate  */
1488*0Sstevel@tonic-gate static int
1489*0Sstevel@tonic-gate lxml_get_instance(entity_t *service, xmlNodePtr inst, int apply)
1490*0Sstevel@tonic-gate {
1491*0Sstevel@tonic-gate 	entity_t *i;
1492*0Sstevel@tonic-gate 	pgroup_t *pg;
1493*0Sstevel@tonic-gate 	property_t *p;
1494*0Sstevel@tonic-gate 	xmlNodePtr cursor;
1495*0Sstevel@tonic-gate 	xmlChar *enabled;
1496*0Sstevel@tonic-gate 	int r;
1497*0Sstevel@tonic-gate 
1498*0Sstevel@tonic-gate 	/*
1499*0Sstevel@tonic-gate 	 * Fetch its attributes, as appropriate.
1500*0Sstevel@tonic-gate 	 */
1501*0Sstevel@tonic-gate 	i = internal_instance_new((char *)xmlGetProp(inst,
1502*0Sstevel@tonic-gate 	    (xmlChar *)name_attr));
1503*0Sstevel@tonic-gate 
1504*0Sstevel@tonic-gate 	/*
1505*0Sstevel@tonic-gate 	 * Note that this must be done before walking the children so that
1506*0Sstevel@tonic-gate 	 * sc_fmri is set in case we enter lxml_get_dependent().
1507*0Sstevel@tonic-gate 	 */
1508*0Sstevel@tonic-gate 	r = internal_attach_entity(service, i);
1509*0Sstevel@tonic-gate 	if (r != 0)
1510*0Sstevel@tonic-gate 		return (r);
1511*0Sstevel@tonic-gate 
1512*0Sstevel@tonic-gate 	enabled = xmlGetProp(inst, (xmlChar *)enabled_attr);
1513*0Sstevel@tonic-gate 
1514*0Sstevel@tonic-gate 	/*
1515*0Sstevel@tonic-gate 	 * New general property group with enabled boolean property set.
1516*0Sstevel@tonic-gate 	 */
1517*0Sstevel@tonic-gate 	pg = internal_pgroup_new();
1518*0Sstevel@tonic-gate 	(void) internal_attach_pgroup(i, pg);
1519*0Sstevel@tonic-gate 
1520*0Sstevel@tonic-gate 	pg->sc_pgroup_name = (char *)scf_pg_general;
1521*0Sstevel@tonic-gate 	pg->sc_pgroup_type = (char *)scf_group_framework;
1522*0Sstevel@tonic-gate 	pg->sc_pgroup_flags = 0;
1523*0Sstevel@tonic-gate 
1524*0Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_ENABLED, SCF_TYPE_BOOLEAN, 1,
1525*0Sstevel@tonic-gate 	    (uint64_t)(strcmp(true, (const char *)enabled) == 0 ? 1 : 0));
1526*0Sstevel@tonic-gate 
1527*0Sstevel@tonic-gate 	p->sc_property_override = apply;
1528*0Sstevel@tonic-gate 
1529*0Sstevel@tonic-gate 	(void) internal_attach_property(pg, p);
1530*0Sstevel@tonic-gate 
1531*0Sstevel@tonic-gate 	xmlFree(enabled);
1532*0Sstevel@tonic-gate 
1533*0Sstevel@tonic-gate 	/*
1534*0Sstevel@tonic-gate 	 * Walk its child elements, as appropriate.
1535*0Sstevel@tonic-gate 	 */
1536*0Sstevel@tonic-gate 	for (cursor = inst->xmlChildrenNode; cursor != NULL;
1537*0Sstevel@tonic-gate 	    cursor = cursor->next) {
1538*0Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
1539*0Sstevel@tonic-gate 			continue;
1540*0Sstevel@tonic-gate 
1541*0Sstevel@tonic-gate 		if (apply) {
1542*0Sstevel@tonic-gate 			semerr(gettext("Instance \"%s\" may not contain "
1543*0Sstevel@tonic-gate 			    "elements in profiles.\n"), i->sc_name,
1544*0Sstevel@tonic-gate 			    cursor->name);
1545*0Sstevel@tonic-gate 			return (-1);
1546*0Sstevel@tonic-gate 		}
1547*0Sstevel@tonic-gate 
1548*0Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
1549*0Sstevel@tonic-gate 		case SC_RESTARTER:
1550*0Sstevel@tonic-gate 			(void) lxml_get_restarter(i, cursor);
1551*0Sstevel@tonic-gate 			break;
1552*0Sstevel@tonic-gate 		case SC_DEPENDENCY:
1553*0Sstevel@tonic-gate 			(void) lxml_get_dependency(i, cursor);
1554*0Sstevel@tonic-gate 			break;
1555*0Sstevel@tonic-gate 		case SC_DEPENDENT:
1556*0Sstevel@tonic-gate 			(void) lxml_get_dependent(i, cursor);
1557*0Sstevel@tonic-gate 			break;
1558*0Sstevel@tonic-gate 		case SC_METHOD_CONTEXT:
1559*0Sstevel@tonic-gate 			(void) lxml_get_entity_method_context(i, cursor);
1560*0Sstevel@tonic-gate 			break;
1561*0Sstevel@tonic-gate 		case SC_EXEC_METHOD:
1562*0Sstevel@tonic-gate 			(void) lxml_get_exec_method(i, cursor);
1563*0Sstevel@tonic-gate 			break;
1564*0Sstevel@tonic-gate 		case SC_PROPERTY_GROUP:
1565*0Sstevel@tonic-gate 			(void) lxml_get_pgroup(i, cursor);
1566*0Sstevel@tonic-gate 			break;
1567*0Sstevel@tonic-gate 		case SC_TEMPLATE:
1568*0Sstevel@tonic-gate 			(void) lxml_get_template(i, cursor);
1569*0Sstevel@tonic-gate 			break;
1570*0Sstevel@tonic-gate 		default:
1571*0Sstevel@tonic-gate 			uu_die(gettext(
1572*0Sstevel@tonic-gate 			    "illegal element \"%s\" on instance \"%s\"\n"),
1573*0Sstevel@tonic-gate 			    cursor->name, i->sc_name);
1574*0Sstevel@tonic-gate 			break;
1575*0Sstevel@tonic-gate 		}
1576*0Sstevel@tonic-gate 	}
1577*0Sstevel@tonic-gate 
1578*0Sstevel@tonic-gate 	return (0);
1579*0Sstevel@tonic-gate }
1580*0Sstevel@tonic-gate 
1581*0Sstevel@tonic-gate /* ARGSUSED1 */
1582*0Sstevel@tonic-gate static int
1583*0Sstevel@tonic-gate lxml_get_single_instance(entity_t *entity, xmlNodePtr si)
1584*0Sstevel@tonic-gate {
1585*0Sstevel@tonic-gate 	pgroup_t *pg;
1586*0Sstevel@tonic-gate 	property_t *p;
1587*0Sstevel@tonic-gate 	int r;
1588*0Sstevel@tonic-gate 
1589*0Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(entity, (char *)scf_pg_general,
1590*0Sstevel@tonic-gate 	    (char *)scf_group_framework);
1591*0Sstevel@tonic-gate 
1592*0Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_SINGLE_INSTANCE,
1593*0Sstevel@tonic-gate 	    SCF_TYPE_BOOLEAN, 1, (uint64_t)1);
1594*0Sstevel@tonic-gate 
1595*0Sstevel@tonic-gate 	r = internal_attach_property(pg, p);
1596*0Sstevel@tonic-gate 	if (r != 0) {
1597*0Sstevel@tonic-gate 		internal_property_free(p);
1598*0Sstevel@tonic-gate 		return (-1);
1599*0Sstevel@tonic-gate 	}
1600*0Sstevel@tonic-gate 
1601*0Sstevel@tonic-gate 	return (0);
1602*0Sstevel@tonic-gate }
1603*0Sstevel@tonic-gate 
1604*0Sstevel@tonic-gate /*
1605*0Sstevel@tonic-gate  * Translate a service element into an internal instance/property tree, added
1606*0Sstevel@tonic-gate  * to bundle.  If apply is true, allow only instance subelements.
1607*0Sstevel@tonic-gate  */
1608*0Sstevel@tonic-gate static int
1609*0Sstevel@tonic-gate lxml_get_service(bundle_t *bundle, xmlNodePtr svc, int apply)
1610*0Sstevel@tonic-gate {
1611*0Sstevel@tonic-gate 	entity_t *s;
1612*0Sstevel@tonic-gate 	xmlNodePtr cursor;
1613*0Sstevel@tonic-gate 	xmlChar *type;
1614*0Sstevel@tonic-gate 	xmlChar *version;
1615*0Sstevel@tonic-gate 	int e;
1616*0Sstevel@tonic-gate 
1617*0Sstevel@tonic-gate 	/*
1618*0Sstevel@tonic-gate 	 * Fetch attributes, as appropriate.
1619*0Sstevel@tonic-gate 	 */
1620*0Sstevel@tonic-gate 	s = internal_service_new((char *)xmlGetProp(svc,
1621*0Sstevel@tonic-gate 	    (xmlChar *)name_attr));
1622*0Sstevel@tonic-gate 
1623*0Sstevel@tonic-gate 	version = xmlGetProp(svc, (xmlChar *)"version");
1624*0Sstevel@tonic-gate 	s->sc_u.sc_service.sc_service_version = atol((const char *)version);
1625*0Sstevel@tonic-gate 	xmlFree(version);
1626*0Sstevel@tonic-gate 
1627*0Sstevel@tonic-gate 	type = xmlGetProp(svc, (xmlChar *)type_attr);
1628*0Sstevel@tonic-gate 	s->sc_u.sc_service.sc_service_type = lxml_xlate_service_type(type);
1629*0Sstevel@tonic-gate 	xmlFree(type);
1630*0Sstevel@tonic-gate 
1631*0Sstevel@tonic-gate 	/*
1632*0Sstevel@tonic-gate 	 * Walk its child elements, as appropriate.
1633*0Sstevel@tonic-gate 	 */
1634*0Sstevel@tonic-gate 	for (cursor = svc->xmlChildrenNode; cursor != NULL;
1635*0Sstevel@tonic-gate 	    cursor = cursor->next) {
1636*0Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
1637*0Sstevel@tonic-gate 			continue;
1638*0Sstevel@tonic-gate 
1639*0Sstevel@tonic-gate 		e = lxml_xlate_element(cursor->name);
1640*0Sstevel@tonic-gate 
1641*0Sstevel@tonic-gate 		if (apply && e != SC_INSTANCE) {
1642*0Sstevel@tonic-gate 			semerr(gettext("Service \"%s\" may not contain the "
1643*0Sstevel@tonic-gate 			    "non-instance element \"%s\" in a profile.\n"),
1644*0Sstevel@tonic-gate 			    s->sc_name, cursor->name);
1645*0Sstevel@tonic-gate 
1646*0Sstevel@tonic-gate 			return (-1);
1647*0Sstevel@tonic-gate 		}
1648*0Sstevel@tonic-gate 
1649*0Sstevel@tonic-gate 		switch (e) {
1650*0Sstevel@tonic-gate 		case SC_INSTANCE:
1651*0Sstevel@tonic-gate 			(void) lxml_get_instance(s, cursor, apply);
1652*0Sstevel@tonic-gate 			break;
1653*0Sstevel@tonic-gate 		case SC_TEMPLATE:
1654*0Sstevel@tonic-gate 			(void) lxml_get_template(s, cursor);
1655*0Sstevel@tonic-gate 			break;
1656*0Sstevel@tonic-gate 		case SC_STABILITY:
1657*0Sstevel@tonic-gate 			(void) lxml_get_entity_stability(s, cursor);
1658*0Sstevel@tonic-gate 			break;
1659*0Sstevel@tonic-gate 		case SC_DEPENDENCY:
1660*0Sstevel@tonic-gate 			(void) lxml_get_dependency(s, cursor);
1661*0Sstevel@tonic-gate 			break;
1662*0Sstevel@tonic-gate 		case SC_DEPENDENT:
1663*0Sstevel@tonic-gate 			(void) lxml_get_dependent(s, cursor);
1664*0Sstevel@tonic-gate 			break;
1665*0Sstevel@tonic-gate 		case SC_RESTARTER:
1666*0Sstevel@tonic-gate 			(void) lxml_get_restarter(s, cursor);
1667*0Sstevel@tonic-gate 			break;
1668*0Sstevel@tonic-gate 		case SC_EXEC_METHOD:
1669*0Sstevel@tonic-gate 			(void) lxml_get_exec_method(s, cursor);
1670*0Sstevel@tonic-gate 			break;
1671*0Sstevel@tonic-gate 		case SC_METHOD_CONTEXT:
1672*0Sstevel@tonic-gate 			(void) lxml_get_entity_method_context(s, cursor);
1673*0Sstevel@tonic-gate 			break;
1674*0Sstevel@tonic-gate 		case SC_PROPERTY_GROUP:
1675*0Sstevel@tonic-gate 			(void) lxml_get_pgroup(s, cursor);
1676*0Sstevel@tonic-gate 			break;
1677*0Sstevel@tonic-gate 		case SC_INSTANCE_CREATE_DEFAULT:
1678*0Sstevel@tonic-gate 			(void) lxml_get_default_instance(s, cursor);
1679*0Sstevel@tonic-gate 			break;
1680*0Sstevel@tonic-gate 		case SC_INSTANCE_SINGLE:
1681*0Sstevel@tonic-gate 			(void) lxml_get_single_instance(s, cursor);
1682*0Sstevel@tonic-gate 			break;
1683*0Sstevel@tonic-gate 		default:
1684*0Sstevel@tonic-gate 			uu_die(gettext(
1685*0Sstevel@tonic-gate 			    "illegal element \"%s\" on service \"%s\"\n"),
1686*0Sstevel@tonic-gate 			    cursor->name, s->sc_name);
1687*0Sstevel@tonic-gate 			break;
1688*0Sstevel@tonic-gate 		}
1689*0Sstevel@tonic-gate 	}
1690*0Sstevel@tonic-gate 
1691*0Sstevel@tonic-gate 	return (internal_attach_service(bundle, s));
1692*0Sstevel@tonic-gate }
1693*0Sstevel@tonic-gate 
1694*0Sstevel@tonic-gate #ifdef DEBUG
1695*0Sstevel@tonic-gate void
1696*0Sstevel@tonic-gate lxml_dump(int g, xmlNodePtr p)
1697*0Sstevel@tonic-gate {
1698*0Sstevel@tonic-gate 	if (p && p->name) {
1699*0Sstevel@tonic-gate 		printf("%d %s\n", g, p->name);
1700*0Sstevel@tonic-gate 
1701*0Sstevel@tonic-gate 		for (p = p->xmlChildrenNode; p != NULL; p = p->next)
1702*0Sstevel@tonic-gate 			lxml_dump(g + 1, p);
1703*0Sstevel@tonic-gate 	}
1704*0Sstevel@tonic-gate }
1705*0Sstevel@tonic-gate #endif /* DEBUG */
1706*0Sstevel@tonic-gate 
1707*0Sstevel@tonic-gate static int
1708*0Sstevel@tonic-gate lxml_is_known_dtd(const xmlChar *dtdname)
1709*0Sstevel@tonic-gate {
1710*0Sstevel@tonic-gate 	if (dtdname == NULL ||
1711*0Sstevel@tonic-gate 	    strcmp(MANIFEST_DTD_PATH, (const char *)dtdname) != 0)
1712*0Sstevel@tonic-gate 		return (0);
1713*0Sstevel@tonic-gate 
1714*0Sstevel@tonic-gate 	return (1);
1715*0Sstevel@tonic-gate }
1716*0Sstevel@tonic-gate 
1717*0Sstevel@tonic-gate static int
1718*0Sstevel@tonic-gate lxml_get_bundle(bundle_t *bundle, bundle_type_t bundle_type,
1719*0Sstevel@tonic-gate     xmlNodePtr subbundle, int apply)
1720*0Sstevel@tonic-gate {
1721*0Sstevel@tonic-gate 	xmlNodePtr cursor;
1722*0Sstevel@tonic-gate 	xmlChar *type;
1723*0Sstevel@tonic-gate 	int e;
1724*0Sstevel@tonic-gate 
1725*0Sstevel@tonic-gate 	/*
1726*0Sstevel@tonic-gate 	 * 1.  Get bundle attributes.
1727*0Sstevel@tonic-gate 	 */
1728*0Sstevel@tonic-gate 	type = xmlGetProp(subbundle, (xmlChar *)"type");
1729*0Sstevel@tonic-gate 	bundle->sc_bundle_type = lxml_xlate_bundle_type(type);
1730*0Sstevel@tonic-gate 	if (bundle->sc_bundle_type != bundle_type &&
1731*0Sstevel@tonic-gate 	    bundle_type != SVCCFG_UNKNOWN_BUNDLE) {
1732*0Sstevel@tonic-gate 		semerr(gettext("included bundle of different type.\n"));
1733*0Sstevel@tonic-gate 		return (-1);
1734*0Sstevel@tonic-gate 	}
1735*0Sstevel@tonic-gate 
1736*0Sstevel@tonic-gate 	xmlFree(type);
1737*0Sstevel@tonic-gate 
1738*0Sstevel@tonic-gate 	if (!apply) {
1739*0Sstevel@tonic-gate 		if (bundle->sc_bundle_type != SVCCFG_MANIFEST) {
1740*0Sstevel@tonic-gate 			semerr(gettext("document is not a manifest.\n"));
1741*0Sstevel@tonic-gate 			return (-1);
1742*0Sstevel@tonic-gate 		}
1743*0Sstevel@tonic-gate 	} else {
1744*0Sstevel@tonic-gate 		if (bundle->sc_bundle_type != SVCCFG_PROFILE) {
1745*0Sstevel@tonic-gate 			semerr(gettext("document is not a profile.\n"));
1746*0Sstevel@tonic-gate 			return (-1);
1747*0Sstevel@tonic-gate 		}
1748*0Sstevel@tonic-gate 	}
1749*0Sstevel@tonic-gate 
1750*0Sstevel@tonic-gate 	if ((bundle->sc_bundle_name = xmlGetProp(subbundle,
1751*0Sstevel@tonic-gate 	    (xmlChar *)"name")) == NULL) {
1752*0Sstevel@tonic-gate 		semerr(gettext("service bundle lacks name attribute\n"));
1753*0Sstevel@tonic-gate 		return (-1);
1754*0Sstevel@tonic-gate 	}
1755*0Sstevel@tonic-gate 
1756*0Sstevel@tonic-gate 	/*
1757*0Sstevel@tonic-gate 	 * 2.  Get services, descend into each one and build state.
1758*0Sstevel@tonic-gate 	 */
1759*0Sstevel@tonic-gate 	for (cursor = subbundle->xmlChildrenNode; cursor != NULL;
1760*0Sstevel@tonic-gate 	    cursor = cursor->next) {
1761*0Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
1762*0Sstevel@tonic-gate 			continue;
1763*0Sstevel@tonic-gate 
1764*0Sstevel@tonic-gate 		e = lxml_xlate_element(cursor->name);
1765*0Sstevel@tonic-gate 
1766*0Sstevel@tonic-gate 		switch (e) {
1767*0Sstevel@tonic-gate 		case SC_XI_INCLUDE:
1768*0Sstevel@tonic-gate 			continue;
1769*0Sstevel@tonic-gate 
1770*0Sstevel@tonic-gate 		case SC_SERVICE_BUNDLE:
1771*0Sstevel@tonic-gate 			if (lxml_get_bundle(bundle, bundle_type, cursor, apply))
1772*0Sstevel@tonic-gate 				return (-1);
1773*0Sstevel@tonic-gate 			break;
1774*0Sstevel@tonic-gate 		case SC_SERVICE:
1775*0Sstevel@tonic-gate 			(void) lxml_get_service(bundle, cursor, apply);
1776*0Sstevel@tonic-gate 			break;
1777*0Sstevel@tonic-gate 		}
1778*0Sstevel@tonic-gate 	}
1779*0Sstevel@tonic-gate 
1780*0Sstevel@tonic-gate 	return (0);
1781*0Sstevel@tonic-gate }
1782*0Sstevel@tonic-gate 
1783*0Sstevel@tonic-gate /*
1784*0Sstevel@tonic-gate  * Load an XML tree from filename and translate it into an internal service
1785*0Sstevel@tonic-gate  * tree bundle.  If apply is false, require that the the bundle be of type
1786*0Sstevel@tonic-gate  * manifest, or type profile otherwise.
1787*0Sstevel@tonic-gate  */
1788*0Sstevel@tonic-gate int
1789*0Sstevel@tonic-gate lxml_get_bundle_file(bundle_t *bundle, const char *filename, int apply)
1790*0Sstevel@tonic-gate {
1791*0Sstevel@tonic-gate 	xmlDocPtr document;
1792*0Sstevel@tonic-gate 	xmlNodePtr cursor;
1793*0Sstevel@tonic-gate 	xmlDtdPtr dtd = NULL;
1794*0Sstevel@tonic-gate 	xmlValidCtxtPtr vcp;
1795*0Sstevel@tonic-gate 	boolean_t do_validate;
1796*0Sstevel@tonic-gate 	char *dtdpath = NULL;
1797*0Sstevel@tonic-gate 	int r;
1798*0Sstevel@tonic-gate 
1799*0Sstevel@tonic-gate 	/*
1800*0Sstevel@tonic-gate 	 * Until libxml2 addresses DTD-based validation with XInclude, we don't
1801*0Sstevel@tonic-gate 	 * validate service profiles (i.e. the apply path).
1802*0Sstevel@tonic-gate 	 */
1803*0Sstevel@tonic-gate 	do_validate = (apply == 0) && (getenv("SVCCFG_NOVALIDATE") == NULL);
1804*0Sstevel@tonic-gate 	if (do_validate)
1805*0Sstevel@tonic-gate 		dtdpath = getenv("SVCCFG_DTD");
1806*0Sstevel@tonic-gate 
1807*0Sstevel@tonic-gate 	if (dtdpath != NULL)
1808*0Sstevel@tonic-gate 		xmlLoadExtDtdDefaultValue = 0;
1809*0Sstevel@tonic-gate 
1810*0Sstevel@tonic-gate 	if ((document = xmlReadFile(filename, NULL,
1811*0Sstevel@tonic-gate 	    XML_PARSE_NOERROR | XML_PARSE_NOWARNING)) == NULL) {
1812*0Sstevel@tonic-gate 		semerr(gettext("couldn't parse document\n"));
1813*0Sstevel@tonic-gate 		return (-1);
1814*0Sstevel@tonic-gate 	}
1815*0Sstevel@tonic-gate 
1816*0Sstevel@tonic-gate 	/*
1817*0Sstevel@tonic-gate 	 * Verify that this is a document type we understand.
1818*0Sstevel@tonic-gate 	 */
1819*0Sstevel@tonic-gate 	if ((dtd = xmlGetIntSubset(document)) == NULL) {
1820*0Sstevel@tonic-gate 		semerr(gettext("document has no DTD\n"));
1821*0Sstevel@tonic-gate 		return (-1);
1822*0Sstevel@tonic-gate 	}
1823*0Sstevel@tonic-gate 
1824*0Sstevel@tonic-gate 	if (!lxml_is_known_dtd(dtd->SystemID)) {
1825*0Sstevel@tonic-gate 		semerr(gettext("document DTD unknown; not service bundle?\n"));
1826*0Sstevel@tonic-gate 		return (-1);
1827*0Sstevel@tonic-gate 	}
1828*0Sstevel@tonic-gate 
1829*0Sstevel@tonic-gate 	if ((cursor = xmlDocGetRootElement(document)) == NULL) {
1830*0Sstevel@tonic-gate 		semerr(gettext("document is empty\n"));
1831*0Sstevel@tonic-gate 		xmlFreeDoc(document);
1832*0Sstevel@tonic-gate 		return (-1);
1833*0Sstevel@tonic-gate 	}
1834*0Sstevel@tonic-gate 
1835*0Sstevel@tonic-gate 	if (xmlStrcmp(cursor->name, (const xmlChar *)"service_bundle") != 0) {
1836*0Sstevel@tonic-gate 		semerr(gettext("document is not a service bundle\n"));
1837*0Sstevel@tonic-gate 		xmlFreeDoc(document);
1838*0Sstevel@tonic-gate 		return (-1);
1839*0Sstevel@tonic-gate 	}
1840*0Sstevel@tonic-gate 
1841*0Sstevel@tonic-gate 
1842*0Sstevel@tonic-gate 	if (dtdpath != NULL) {
1843*0Sstevel@tonic-gate 		dtd = xmlParseDTD(NULL, (xmlChar *)dtdpath);
1844*0Sstevel@tonic-gate 		if (dtd == NULL) {
1845*0Sstevel@tonic-gate 			semerr(gettext("Could not parse DTD \"%s\".\n"),
1846*0Sstevel@tonic-gate 			    dtdpath);
1847*0Sstevel@tonic-gate 			return (-1);
1848*0Sstevel@tonic-gate 		}
1849*0Sstevel@tonic-gate 
1850*0Sstevel@tonic-gate 		if (document->extSubset != NULL)
1851*0Sstevel@tonic-gate 			xmlFreeDtd(document->extSubset);
1852*0Sstevel@tonic-gate 
1853*0Sstevel@tonic-gate 		document->extSubset = dtd;
1854*0Sstevel@tonic-gate 	}
1855*0Sstevel@tonic-gate 
1856*0Sstevel@tonic-gate 	if (xmlXIncludeProcessFlags(document, XML_PARSE_XINCLUDE) == -1) {;
1857*0Sstevel@tonic-gate 		semerr(gettext("couldn't handle XInclude statements "
1858*0Sstevel@tonic-gate 			"in document\n"));
1859*0Sstevel@tonic-gate 		return (-1);
1860*0Sstevel@tonic-gate 	}
1861*0Sstevel@tonic-gate 
1862*0Sstevel@tonic-gate 	if (do_validate) {
1863*0Sstevel@tonic-gate 		vcp = xmlNewValidCtxt();
1864*0Sstevel@tonic-gate 		if (vcp == NULL)
1865*0Sstevel@tonic-gate 			uu_die(gettext("could not allocate memory"));
1866*0Sstevel@tonic-gate 		vcp->warning = xmlParserValidityWarning;
1867*0Sstevel@tonic-gate 		vcp->error = xmlParserValidityError;
1868*0Sstevel@tonic-gate 
1869*0Sstevel@tonic-gate 		r = xmlValidateDocument(vcp, document);
1870*0Sstevel@tonic-gate 
1871*0Sstevel@tonic-gate 		xmlFreeValidCtxt(vcp);
1872*0Sstevel@tonic-gate 
1873*0Sstevel@tonic-gate 		if (r == 0) {
1874*0Sstevel@tonic-gate 			semerr(gettext("Document is not valid.\n"));
1875*0Sstevel@tonic-gate 			xmlFreeDoc(document);
1876*0Sstevel@tonic-gate 			return (-1);
1877*0Sstevel@tonic-gate 		}
1878*0Sstevel@tonic-gate 	}
1879*0Sstevel@tonic-gate 
1880*0Sstevel@tonic-gate 
1881*0Sstevel@tonic-gate #ifdef DEBUG
1882*0Sstevel@tonic-gate 	lxml_dump(0, cursor);
1883*0Sstevel@tonic-gate #endif /* DEBUG */
1884*0Sstevel@tonic-gate 
1885*0Sstevel@tonic-gate 	r = lxml_get_bundle(bundle, SVCCFG_UNKNOWN_BUNDLE, cursor, apply);
1886*0Sstevel@tonic-gate 
1887*0Sstevel@tonic-gate 	xmlFreeDoc(document);
1888*0Sstevel@tonic-gate 
1889*0Sstevel@tonic-gate 	return (r);
1890*0Sstevel@tonic-gate }
1891*0Sstevel@tonic-gate 
1892*0Sstevel@tonic-gate int
1893*0Sstevel@tonic-gate lxml_inventory(const char *filename)
1894*0Sstevel@tonic-gate {
1895*0Sstevel@tonic-gate 	bundle_t *b;
1896*0Sstevel@tonic-gate 	uu_list_walk_t *svcs, *insts;
1897*0Sstevel@tonic-gate 	entity_t *svc, *inst;
1898*0Sstevel@tonic-gate 
1899*0Sstevel@tonic-gate 	b = internal_bundle_new();
1900*0Sstevel@tonic-gate 
1901*0Sstevel@tonic-gate 	if (lxml_get_bundle_file(b, filename, 0) != 0) {
1902*0Sstevel@tonic-gate 		internal_bundle_free(b);
1903*0Sstevel@tonic-gate 		return (-1);
1904*0Sstevel@tonic-gate 	}
1905*0Sstevel@tonic-gate 
1906*0Sstevel@tonic-gate 	svcs = uu_list_walk_start(b->sc_bundle_services, 0);
1907*0Sstevel@tonic-gate 	if (svcs == NULL)
1908*0Sstevel@tonic-gate 		uu_die(gettext("Couldn't walk services"));
1909*0Sstevel@tonic-gate 
1910*0Sstevel@tonic-gate 	while ((svc = uu_list_walk_next(svcs)) != NULL) {
1911*0Sstevel@tonic-gate 		uu_list_t *inst_list;
1912*0Sstevel@tonic-gate 
1913*0Sstevel@tonic-gate 		inst_list = svc->sc_u.sc_service.sc_service_instances;
1914*0Sstevel@tonic-gate 		insts = uu_list_walk_start(inst_list, 0);
1915*0Sstevel@tonic-gate 		if (insts == NULL)
1916*0Sstevel@tonic-gate 			uu_die(gettext("Couldn't walk instances"));
1917*0Sstevel@tonic-gate 
1918*0Sstevel@tonic-gate 		while ((inst = uu_list_walk_next(insts)) != NULL)
1919*0Sstevel@tonic-gate 			(void) printf("svc:/%s:%s\n", svc->sc_name,
1920*0Sstevel@tonic-gate 			    inst->sc_name);
1921*0Sstevel@tonic-gate 
1922*0Sstevel@tonic-gate 		uu_list_walk_end(insts);
1923*0Sstevel@tonic-gate 	}
1924*0Sstevel@tonic-gate 
1925*0Sstevel@tonic-gate 	uu_list_walk_end(svcs);
1926*0Sstevel@tonic-gate 
1927*0Sstevel@tonic-gate 	svcs = uu_list_walk_start(b->sc_bundle_services, 0);
1928*0Sstevel@tonic-gate 	while ((svc = uu_list_walk_next(svcs)) != NULL) {
1929*0Sstevel@tonic-gate 		(void) fputs("svc:/", stdout);
1930*0Sstevel@tonic-gate 		(void) puts(svc->sc_name);
1931*0Sstevel@tonic-gate 	}
1932*0Sstevel@tonic-gate 	uu_list_walk_end(svcs);
1933*0Sstevel@tonic-gate 
1934*0Sstevel@tonic-gate 	internal_bundle_free(b);
1935*0Sstevel@tonic-gate 
1936*0Sstevel@tonic-gate 	return (0);
1937*0Sstevel@tonic-gate }
1938