xref: /onnv-gate/usr/src/cmd/svc/svccfg/svccfg_xml.c (revision 306:925d8159e7e2)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
230Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include <libxml/parser.h>
300Sstevel@tonic-gate #include <libxml/xinclude.h>
310Sstevel@tonic-gate 
320Sstevel@tonic-gate #include <assert.h>
330Sstevel@tonic-gate #include <ctype.h>
340Sstevel@tonic-gate #include <errno.h>
350Sstevel@tonic-gate #include <libintl.h>
360Sstevel@tonic-gate #include <libuutil.h>
370Sstevel@tonic-gate #include <stdlib.h>
380Sstevel@tonic-gate #include <string.h>
390Sstevel@tonic-gate 
400Sstevel@tonic-gate #include "svccfg.h"
410Sstevel@tonic-gate 
420Sstevel@tonic-gate /*
430Sstevel@tonic-gate  * XML document manipulation routines
440Sstevel@tonic-gate  *
450Sstevel@tonic-gate  * These routines provide translation to and from the internal representation to
460Sstevel@tonic-gate  * XML.  Directionally-oriented verbs are with respect to the external source,
470Sstevel@tonic-gate  * so lxml_get_service() fetches a service from the XML file into the
480Sstevel@tonic-gate  * internal representation.
490Sstevel@tonic-gate  */
500Sstevel@tonic-gate 
510Sstevel@tonic-gate const char * const delete_attr = "delete";
520Sstevel@tonic-gate const char * const enabled_attr = "enabled";
530Sstevel@tonic-gate const char * const name_attr = "name";
540Sstevel@tonic-gate const char * const override_attr = "override";
550Sstevel@tonic-gate const char * const type_attr = "type";
560Sstevel@tonic-gate const char * const value_attr = "value";
570Sstevel@tonic-gate const char * const true = "true";
580Sstevel@tonic-gate const char * const false = "false";
590Sstevel@tonic-gate 
600Sstevel@tonic-gate /*
610Sstevel@tonic-gate  * The following list must be kept in the same order as that of
620Sstevel@tonic-gate  * element_t array
630Sstevel@tonic-gate  */
640Sstevel@tonic-gate static const char *lxml_elements[] = {
650Sstevel@tonic-gate 	"astring_list",			/* SC_ASTRING */
660Sstevel@tonic-gate 	"boolean_list",			/* SC_BOOLEAN */
670Sstevel@tonic-gate 	"common_name",			/* SC_COMMON_NAME */
680Sstevel@tonic-gate 	"count_list",			/* SC_COUNT */
690Sstevel@tonic-gate 	"create_default_instance",	/* SC_INSTANCE_CREATE_DEFAULT */
700Sstevel@tonic-gate 	"dependency",			/* SC_DEPENDENCY */
710Sstevel@tonic-gate 	"dependent",			/* SC_DEPENDENT */
720Sstevel@tonic-gate 	"description",			/* SC_DESCRIPTION */
730Sstevel@tonic-gate 	"doc_link",			/* SC_DOC_LINK */
740Sstevel@tonic-gate 	"documentation",		/* SC_DOCUMENTATION */
750Sstevel@tonic-gate 	"enabled",			/* SC_ENABLED */
760Sstevel@tonic-gate 	"exec_method",			/* SC_EXEC_METHOD */
770Sstevel@tonic-gate 	"fmri_list",			/* SC_FMRI */
780Sstevel@tonic-gate 	"host_list",			/* SC_HOST */
790Sstevel@tonic-gate 	"hostname_list",		/* SC_HOSTNAME */
800Sstevel@tonic-gate 	"instance",			/* SC_INSTANCE */
810Sstevel@tonic-gate 	"integer_list",			/* SC_INTEGER */
820Sstevel@tonic-gate 	"loctext",			/* SC_LOCTEXT */
830Sstevel@tonic-gate 	"manpage",			/* SC_MANPAGE */
840Sstevel@tonic-gate 	"method_context",		/* SC_METHOD_CONTEXT */
850Sstevel@tonic-gate 	"method_credential",		/* SC_METHOD_CREDENTIAL */
860Sstevel@tonic-gate 	"method_profile",		/* SC_METHOD_PROFILE */
870Sstevel@tonic-gate 	"method_environment",		/* SC_METHOD_ENVIRONMENT */
880Sstevel@tonic-gate 	"envvar",			/* SC_METHOD_ENVVAR */
890Sstevel@tonic-gate 	"net_address_v4_list",		/* SC_NET_ADDR_V4 */
900Sstevel@tonic-gate 	"net_address_v6_list",		/* SC_NET_ADDR_V6 */
910Sstevel@tonic-gate 	"opaque_list",			/* SC_OPAQUE */
920Sstevel@tonic-gate 	"property",			/* SC_PROPERTY */
930Sstevel@tonic-gate 	"property_group",		/* SC_PROPERTY_GROUP */
940Sstevel@tonic-gate 	"propval",			/* SC_PROPVAL */
950Sstevel@tonic-gate 	"restarter",			/* SC_RESTARTER */
960Sstevel@tonic-gate 	"service",			/* SC_SERVICE */
970Sstevel@tonic-gate 	"service_bundle",		/* SC_SERVICE_BUNDLE */
980Sstevel@tonic-gate 	"service_fmri",			/* SC_SERVICE_FMRI */
990Sstevel@tonic-gate 	"single_instance",		/* SC_INSTANCE_SINGLE */
1000Sstevel@tonic-gate 	"stability",			/* SC_STABILITY */
1010Sstevel@tonic-gate 	"template",			/* SC_TEMPLATE */
1020Sstevel@tonic-gate 	"time_list",			/* SC_TIME */
1030Sstevel@tonic-gate 	"uri_list",			/* SC_URI */
1040Sstevel@tonic-gate 	"ustring_list",			/* SC_USTRING */
1050Sstevel@tonic-gate 	"value_node",			/* SC_VALUE_NODE */
1060Sstevel@tonic-gate 	"xi:fallback",			/* SC_XI_FALLBACK */
1070Sstevel@tonic-gate 	"xi:include"			/* SC_XI_INCLUDE */
1080Sstevel@tonic-gate };
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate /*
1110Sstevel@tonic-gate  * The following list must be kept in the same order as that of
1120Sstevel@tonic-gate  * element_t array
1130Sstevel@tonic-gate  */
1140Sstevel@tonic-gate static const char *lxml_prop_types[] = {
1150Sstevel@tonic-gate 	"astring",			/* SC_ASTRING */
1160Sstevel@tonic-gate 	"boolean",			/* SC_BOOLEAN */
1170Sstevel@tonic-gate 	"",				/* SC_COMMON_NAME */
1180Sstevel@tonic-gate 	"count",			/* SC_COUNT */
1190Sstevel@tonic-gate 	"",				/* SC_INSTANCE_CREATE_DEFAULT */
1200Sstevel@tonic-gate 	"",				/* SC_DEPENDENCY */
1210Sstevel@tonic-gate 	"",				/* SC_DEPENDENT */
1220Sstevel@tonic-gate 	"",				/* SC_DESCRIPTION */
1230Sstevel@tonic-gate 	"",				/* SC_DOC_LINK */
1240Sstevel@tonic-gate 	"",				/* SC_DOCUMENTATION */
1250Sstevel@tonic-gate 	"",				/* SC_ENABLED */
1260Sstevel@tonic-gate 	"",				/* SC_EXEC_METHOD */
1270Sstevel@tonic-gate 	"fmri",				/* SC_FMRI */
1280Sstevel@tonic-gate 	"host",				/* SC_HOST */
1290Sstevel@tonic-gate 	"hostname",			/* SC_HOSTNAME */
1300Sstevel@tonic-gate 	"",				/* SC_INSTANCE */
1310Sstevel@tonic-gate 	"integer",			/* SC_INTEGER */
1320Sstevel@tonic-gate 	"",				/* SC_LOCTEXT */
1330Sstevel@tonic-gate 	"",				/* SC_MANPAGE */
1340Sstevel@tonic-gate 	"",				/* SC_METHOD_CONTEXT */
1350Sstevel@tonic-gate 	"",				/* SC_METHOD_CREDENTIAL */
1360Sstevel@tonic-gate 	"",				/* SC_METHOD_PROFILE */
1370Sstevel@tonic-gate 	"",				/* SC_METHOD_ENVIRONMENT */
1380Sstevel@tonic-gate 	"",				/* SC_METHOD_ENVVAR */
1390Sstevel@tonic-gate 	"net_address_v4",		/* SC_NET_ADDR_V4 */
1400Sstevel@tonic-gate 	"net_address_v6",		/* SC_NET_ADDR_V6 */
1410Sstevel@tonic-gate 	"opaque",			/* SC_OPAQUE */
1420Sstevel@tonic-gate 	"",				/* SC_PROPERTY */
1430Sstevel@tonic-gate 	"",				/* SC_PROPERTY_GROUP */
1440Sstevel@tonic-gate 	"",				/* SC_PROPVAL */
1450Sstevel@tonic-gate 	"",				/* SC_RESTARTER */
1460Sstevel@tonic-gate 	"",				/* SC_SERVICE */
1470Sstevel@tonic-gate 	"",				/* SC_SERVICE_BUNDLE */
1480Sstevel@tonic-gate 	"",				/* SC_SERVICE_FMRI */
1490Sstevel@tonic-gate 	"",				/* SC_INSTANCE_SINGLE */
1500Sstevel@tonic-gate 	"",				/* SC_STABILITY */
1510Sstevel@tonic-gate 	"",				/* SC_TEMPLATE */
1520Sstevel@tonic-gate 	"time",				/* SC_TIME */
1530Sstevel@tonic-gate 	"uri",				/* SC_URI */
1540Sstevel@tonic-gate 	"ustring",			/* SC_USTRING */
1550Sstevel@tonic-gate 	""				/* SC_VALUE_NODE */
1560Sstevel@tonic-gate 	""				/* SC_XI_FALLBACK */
1570Sstevel@tonic-gate 	""				/* SC_XI_INCLUDE */
1580Sstevel@tonic-gate };
1590Sstevel@tonic-gate 
1600Sstevel@tonic-gate int
1610Sstevel@tonic-gate lxml_init()
1620Sstevel@tonic-gate {
1630Sstevel@tonic-gate 	if (getenv("SVCCFG_NOVALIDATE") == NULL) {
1640Sstevel@tonic-gate 		/*
1650Sstevel@tonic-gate 		 * DTD validation, with line numbers.
1660Sstevel@tonic-gate 		 */
1670Sstevel@tonic-gate 		xmlLineNumbersDefault(1);
1680Sstevel@tonic-gate 		xmlLoadExtDtdDefaultValue |= XML_DETECT_IDS;
1690Sstevel@tonic-gate 		xmlLoadExtDtdDefaultValue |= XML_COMPLETE_ATTRS;
1700Sstevel@tonic-gate 	}
1710Sstevel@tonic-gate 
1720Sstevel@tonic-gate 	return (0);
1730Sstevel@tonic-gate }
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate static bundle_type_t
1760Sstevel@tonic-gate lxml_xlate_bundle_type(xmlChar *type)
1770Sstevel@tonic-gate {
1780Sstevel@tonic-gate 	if (xmlStrcmp(type, (const xmlChar *)"manifest") == 0)
1790Sstevel@tonic-gate 		return (SVCCFG_MANIFEST);
1800Sstevel@tonic-gate 
1810Sstevel@tonic-gate 	if (xmlStrcmp(type, (const xmlChar *)"profile") == 0)
1820Sstevel@tonic-gate 		return (SVCCFG_PROFILE);
1830Sstevel@tonic-gate 
1840Sstevel@tonic-gate 	if (xmlStrcmp(type, (const xmlChar *)"archive") == 0)
1850Sstevel@tonic-gate 		return (SVCCFG_ARCHIVE);
1860Sstevel@tonic-gate 
1870Sstevel@tonic-gate 	return (SVCCFG_UNKNOWN_BUNDLE);
1880Sstevel@tonic-gate }
1890Sstevel@tonic-gate 
1900Sstevel@tonic-gate static service_type_t
1910Sstevel@tonic-gate lxml_xlate_service_type(xmlChar *type)
1920Sstevel@tonic-gate {
1930Sstevel@tonic-gate 	if (xmlStrcmp(type, (const xmlChar *)"service") == 0)
1940Sstevel@tonic-gate 		return (SVCCFG_SERVICE);
1950Sstevel@tonic-gate 
1960Sstevel@tonic-gate 	if (xmlStrcmp(type, (const xmlChar *)"restarter") == 0)
1970Sstevel@tonic-gate 		return (SVCCFG_RESTARTER);
1980Sstevel@tonic-gate 
1990Sstevel@tonic-gate 	if (xmlStrcmp(type, (const xmlChar *)"milestone") == 0)
2000Sstevel@tonic-gate 		return (SVCCFG_MILESTONE);
2010Sstevel@tonic-gate 
2020Sstevel@tonic-gate 	return (SVCCFG_UNKNOWN_SERVICE);
2030Sstevel@tonic-gate }
2040Sstevel@tonic-gate 
2050Sstevel@tonic-gate static element_t
2060Sstevel@tonic-gate lxml_xlate_element(const xmlChar *tag)
2070Sstevel@tonic-gate {
2080Sstevel@tonic-gate 	int i;
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate 	for (i = 0; i < sizeof (lxml_elements) / sizeof (char *); i++)
2110Sstevel@tonic-gate 		if (xmlStrcmp(tag, (const xmlChar *)lxml_elements[i]) == 0)
2120Sstevel@tonic-gate 			return ((element_t)i);
2130Sstevel@tonic-gate 
2140Sstevel@tonic-gate 	return ((element_t)-1);
2150Sstevel@tonic-gate }
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate static uint_t
2180Sstevel@tonic-gate lxml_xlate_boolean(const xmlChar *value)
2190Sstevel@tonic-gate {
2200Sstevel@tonic-gate 	if (xmlStrcmp(value, (const xmlChar *)true) == 0)
2210Sstevel@tonic-gate 		return (1);
2220Sstevel@tonic-gate 
2230Sstevel@tonic-gate 	if (xmlStrcmp(value, (const xmlChar *)false) == 0)
2240Sstevel@tonic-gate 		return (0);
2250Sstevel@tonic-gate 
2260Sstevel@tonic-gate 	uu_die(gettext("illegal boolean value \"%s\"\n"), value);
2270Sstevel@tonic-gate 
2280Sstevel@tonic-gate 	/*NOTREACHED*/
2290Sstevel@tonic-gate }
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate static scf_type_t
2320Sstevel@tonic-gate lxml_element_to_type(element_t type)
2330Sstevel@tonic-gate {
2340Sstevel@tonic-gate 	switch (type) {
2350Sstevel@tonic-gate 	case SC_ASTRING:	return (SCF_TYPE_ASTRING);
2360Sstevel@tonic-gate 	case SC_BOOLEAN:	return (SCF_TYPE_BOOLEAN);
2370Sstevel@tonic-gate 	case SC_COUNT:		return (SCF_TYPE_COUNT);
2380Sstevel@tonic-gate 	case SC_FMRI:		return (SCF_TYPE_FMRI);
2390Sstevel@tonic-gate 	case SC_HOST:		return (SCF_TYPE_HOST);
2400Sstevel@tonic-gate 	case SC_HOSTNAME:	return (SCF_TYPE_HOSTNAME);
2410Sstevel@tonic-gate 	case SC_INTEGER:	return (SCF_TYPE_INTEGER);
2420Sstevel@tonic-gate 	case SC_NET_ADDR_V4:	return (SCF_TYPE_NET_ADDR_V4);
2430Sstevel@tonic-gate 	case SC_NET_ADDR_V6:	return (SCF_TYPE_NET_ADDR_V6);
2440Sstevel@tonic-gate 	case SC_OPAQUE:		return (SCF_TYPE_OPAQUE);
2450Sstevel@tonic-gate 	case SC_TIME:		return (SCF_TYPE_TIME);
2460Sstevel@tonic-gate 	case SC_URI:		return (SCF_TYPE_URI);
2470Sstevel@tonic-gate 	case SC_USTRING:	return (SCF_TYPE_USTRING);
2480Sstevel@tonic-gate 
2490Sstevel@tonic-gate 	default:
2500Sstevel@tonic-gate 		uu_die(gettext("unknown value type (%d)\n"), type);
2510Sstevel@tonic-gate 	}
2520Sstevel@tonic-gate 
2530Sstevel@tonic-gate 	/* NOTREACHED */
2540Sstevel@tonic-gate }
2550Sstevel@tonic-gate 
2560Sstevel@tonic-gate static scf_type_t
2570Sstevel@tonic-gate lxml_element_to_scf_type(element_t type)
2580Sstevel@tonic-gate {
2590Sstevel@tonic-gate 	switch (type) {
2600Sstevel@tonic-gate 	case SC_ASTRING:	return (SCF_TYPE_ASTRING);
2610Sstevel@tonic-gate 	case SC_BOOLEAN:	return (SCF_TYPE_BOOLEAN);
2620Sstevel@tonic-gate 	case SC_COUNT:		return (SCF_TYPE_COUNT);
2630Sstevel@tonic-gate 	case SC_FMRI:		return (SCF_TYPE_FMRI);
2640Sstevel@tonic-gate 	case SC_HOST:		return (SCF_TYPE_HOST);
2650Sstevel@tonic-gate 	case SC_HOSTNAME:	return (SCF_TYPE_HOSTNAME);
2660Sstevel@tonic-gate 	case SC_INTEGER:	return (SCF_TYPE_INTEGER);
2670Sstevel@tonic-gate 	case SC_NET_ADDR_V4:	return (SCF_TYPE_NET_ADDR_V4);
2680Sstevel@tonic-gate 	case SC_NET_ADDR_V6:	return (SCF_TYPE_NET_ADDR_V6);
2690Sstevel@tonic-gate 	case SC_OPAQUE:		return (SCF_TYPE_OPAQUE);
2700Sstevel@tonic-gate 	case SC_TIME:		return (SCF_TYPE_TIME);
2710Sstevel@tonic-gate 	case SC_URI:		return (SCF_TYPE_URI);
2720Sstevel@tonic-gate 	case SC_USTRING:	return (SCF_TYPE_USTRING);
2730Sstevel@tonic-gate 	default:
2740Sstevel@tonic-gate 		uu_die(gettext("unknown value type (%d)\n"), type);
2750Sstevel@tonic-gate 	}
2760Sstevel@tonic-gate 
2770Sstevel@tonic-gate 	/* NOTREACHED */
2780Sstevel@tonic-gate }
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate static int
2810Sstevel@tonic-gate new_str_prop_from_attr(pgroup_t *pgrp, const char *pname, scf_type_t ty,
2820Sstevel@tonic-gate     xmlNodePtr n, const char *attr)
2830Sstevel@tonic-gate {
2840Sstevel@tonic-gate 	xmlChar *val;
2850Sstevel@tonic-gate 	property_t *p;
2860Sstevel@tonic-gate 	int r;
2870Sstevel@tonic-gate 
2880Sstevel@tonic-gate 	val = xmlGetProp(n, (xmlChar *)attr);
2890Sstevel@tonic-gate 
2900Sstevel@tonic-gate 	p = internal_property_create(pname, ty, 1, val);
2910Sstevel@tonic-gate 	r = internal_attach_property(pgrp, p);
2920Sstevel@tonic-gate 
2930Sstevel@tonic-gate 	if (r != 0)
2940Sstevel@tonic-gate 		internal_property_free(p);
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate 	return (r);
2970Sstevel@tonic-gate }
2980Sstevel@tonic-gate 
2990Sstevel@tonic-gate static int
3000Sstevel@tonic-gate lxml_ignorable_block(xmlNodePtr n)
3010Sstevel@tonic-gate {
3020Sstevel@tonic-gate 	return ((xmlStrcmp(n->name, (xmlChar *)"text") == 0 ||
3030Sstevel@tonic-gate 	    xmlStrcmp(n->name, (xmlChar *)"comment") == 0) ? 1 : 0);
3040Sstevel@tonic-gate }
3050Sstevel@tonic-gate 
3060Sstevel@tonic-gate static int
3070Sstevel@tonic-gate lxml_validate_string_value(scf_type_t type, const char *v)
3080Sstevel@tonic-gate {
3090Sstevel@tonic-gate 	static scf_value_t *scf_value = NULL;
3100Sstevel@tonic-gate 	static scf_handle_t *scf_hndl = NULL;
3110Sstevel@tonic-gate 
3120Sstevel@tonic-gate 	if (scf_hndl == NULL && (scf_hndl = scf_handle_create(SCF_VERSION)) ==
3130Sstevel@tonic-gate 	    NULL)
3140Sstevel@tonic-gate 		return (-1);
3150Sstevel@tonic-gate 
3160Sstevel@tonic-gate 	if (scf_value == NULL && (scf_value = scf_value_create(scf_hndl)) ==
3170Sstevel@tonic-gate 	    NULL)
3180Sstevel@tonic-gate 		return (-1);
3190Sstevel@tonic-gate 
3200Sstevel@tonic-gate 	return (scf_value_set_from_string(scf_value, type, v));
3210Sstevel@tonic-gate }
3220Sstevel@tonic-gate 
3230Sstevel@tonic-gate static void
3240Sstevel@tonic-gate lxml_free_str(value_t *val)
3250Sstevel@tonic-gate {
3260Sstevel@tonic-gate 	free(val->sc_u.sc_string);
3270Sstevel@tonic-gate }
3280Sstevel@tonic-gate 
3290Sstevel@tonic-gate static value_t *
3300Sstevel@tonic-gate lxml_make_value(element_t type, const xmlChar *value)
3310Sstevel@tonic-gate {
3320Sstevel@tonic-gate 	value_t *v;
3330Sstevel@tonic-gate 	char *endptr;
3340Sstevel@tonic-gate 	scf_type_t scf_type = SCF_TYPE_INVALID;
3350Sstevel@tonic-gate 
3360Sstevel@tonic-gate 	v = internal_value_new();
3370Sstevel@tonic-gate 
3380Sstevel@tonic-gate 	v->sc_type = lxml_element_to_type(type);
3390Sstevel@tonic-gate 
3400Sstevel@tonic-gate 	switch (type) {
3410Sstevel@tonic-gate 	case SC_COUNT:
3420Sstevel@tonic-gate 		/*
3430Sstevel@tonic-gate 		 * Although an SC_COUNT represents a uint64_t the use
3440Sstevel@tonic-gate 		 * of a negative value is acceptable due to the usage
3450Sstevel@tonic-gate 		 * established by inetd(1M).
3460Sstevel@tonic-gate 		 */
3470Sstevel@tonic-gate 		errno = 0;
3480Sstevel@tonic-gate 		v->sc_u.sc_count = strtoull((char *)value, &endptr, 10);
3490Sstevel@tonic-gate 		if (errno != 0 || endptr == (char *)value || *endptr)
3500Sstevel@tonic-gate 			uu_die(gettext("illegal value \"%s\" for "
3510Sstevel@tonic-gate 			    "%s (%s)\n"), (char *)value,
3520Sstevel@tonic-gate 			    lxml_prop_types[type],
3530Sstevel@tonic-gate 			    (errno) ? strerror(errno) :
3540Sstevel@tonic-gate 			    gettext("Illegal character"));
3550Sstevel@tonic-gate 		break;
3560Sstevel@tonic-gate 	case SC_INTEGER:
3570Sstevel@tonic-gate 		errno = 0;
3580Sstevel@tonic-gate 		v->sc_u.sc_integer = strtoll((char *)value, &endptr, 10);
3590Sstevel@tonic-gate 		if (errno != 0 || *endptr)
3600Sstevel@tonic-gate 			uu_die(gettext("illegal value \"%s\" for "
3610Sstevel@tonic-gate 			    "%s (%s)\n"), (char *)value,
3620Sstevel@tonic-gate 			    lxml_prop_types[type],
3630Sstevel@tonic-gate 			    (errno) ? strerror(errno) : "Illegal character");
3640Sstevel@tonic-gate 		break;
3650Sstevel@tonic-gate 	case SC_OPAQUE:
3660Sstevel@tonic-gate 	case SC_HOST:
3670Sstevel@tonic-gate 	case SC_HOSTNAME:
3680Sstevel@tonic-gate 	case SC_NET_ADDR_V4:
3690Sstevel@tonic-gate 	case SC_NET_ADDR_V6:
3700Sstevel@tonic-gate 	case SC_FMRI:
3710Sstevel@tonic-gate 	case SC_URI:
3720Sstevel@tonic-gate 	case SC_TIME:
3730Sstevel@tonic-gate 	case SC_ASTRING:
3740Sstevel@tonic-gate 	case SC_USTRING:
3750Sstevel@tonic-gate 		scf_type = lxml_element_to_scf_type(type);
3760Sstevel@tonic-gate 
3770Sstevel@tonic-gate 		if ((v->sc_u.sc_string = strdup((char *)value)) == NULL)
3780Sstevel@tonic-gate 			uu_die(gettext("string duplication failed (%s)\n"),
3790Sstevel@tonic-gate 			    strerror(errno));
3800Sstevel@tonic-gate 		if (lxml_validate_string_value(scf_type,
3810Sstevel@tonic-gate 		    v->sc_u.sc_string) != 0)
3820Sstevel@tonic-gate 			uu_die(gettext("illegal value \"%s\" for "
3830Sstevel@tonic-gate 			    "%s (%s)\n"), (char *)value,
3840Sstevel@tonic-gate 			    lxml_prop_types[type],
3850Sstevel@tonic-gate 			    (scf_error()) ? scf_strerror(scf_error()) :
3860Sstevel@tonic-gate 			    gettext("Illegal format"));
3870Sstevel@tonic-gate 		v->sc_free = lxml_free_str;
3880Sstevel@tonic-gate 		break;
3890Sstevel@tonic-gate 	case SC_BOOLEAN:
3900Sstevel@tonic-gate 		v->sc_u.sc_count = lxml_xlate_boolean(value);
3910Sstevel@tonic-gate 		break;
3920Sstevel@tonic-gate 	default:
3930Sstevel@tonic-gate 		uu_die(gettext("unknown value type (%d)\n"), type);
3940Sstevel@tonic-gate 		break;
3950Sstevel@tonic-gate 	}
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate 	return (v);
3980Sstevel@tonic-gate }
3990Sstevel@tonic-gate 
4000Sstevel@tonic-gate static int
4010Sstevel@tonic-gate lxml_get_value(property_t *prop, element_t vtype, xmlNodePtr value)
4020Sstevel@tonic-gate {
4030Sstevel@tonic-gate 	xmlNodePtr cursor;
4040Sstevel@tonic-gate 
4050Sstevel@tonic-gate 	for (cursor = value->xmlChildrenNode; cursor != NULL;
4060Sstevel@tonic-gate 	    cursor = cursor->next) {
4070Sstevel@tonic-gate 		xmlChar *assigned_value;
4080Sstevel@tonic-gate 		value_t *v;
4090Sstevel@tonic-gate 
4100Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
4110Sstevel@tonic-gate 			continue;
4120Sstevel@tonic-gate 
4130Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
4140Sstevel@tonic-gate 		case SC_VALUE_NODE:
4150Sstevel@tonic-gate 			if ((assigned_value = xmlGetProp(cursor,
4160Sstevel@tonic-gate 			    (xmlChar *)value_attr)) == NULL)
4170Sstevel@tonic-gate 				uu_die(gettext("no value on value node?\n"));
4180Sstevel@tonic-gate 			break;
4190Sstevel@tonic-gate 		default:
4200Sstevel@tonic-gate 			uu_die(gettext("value list contains illegal element "
4210Sstevel@tonic-gate 			    "\'%s\'\n"), cursor->name);
4220Sstevel@tonic-gate 			break;
4230Sstevel@tonic-gate 		}
4240Sstevel@tonic-gate 
4250Sstevel@tonic-gate 		v = lxml_make_value(vtype, assigned_value);
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate 		xmlFree(assigned_value);
4280Sstevel@tonic-gate 
4290Sstevel@tonic-gate 		internal_attach_value(prop, v);
4300Sstevel@tonic-gate 	}
4310Sstevel@tonic-gate 
4320Sstevel@tonic-gate 	return (0);
4330Sstevel@tonic-gate }
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate static int
4360Sstevel@tonic-gate lxml_get_propval(pgroup_t *pgrp, xmlNodePtr propval)
4370Sstevel@tonic-gate {
4380Sstevel@tonic-gate 	property_t *p;
4390Sstevel@tonic-gate 	element_t r;
4400Sstevel@tonic-gate 	value_t *v;
4410Sstevel@tonic-gate 	xmlChar *type, *val, *override;
4420Sstevel@tonic-gate 
4430Sstevel@tonic-gate 	p = internal_property_new();
4440Sstevel@tonic-gate 
4450Sstevel@tonic-gate 	p->sc_property_name = (char *)xmlGetProp(propval, (xmlChar *)name_attr);
4460Sstevel@tonic-gate 	if (p->sc_property_name == NULL)
4470Sstevel@tonic-gate 		uu_die(gettext("property name missing in group '%s'\n"),
4480Sstevel@tonic-gate 		    pgrp->sc_pgroup_name);
4490Sstevel@tonic-gate 
4500Sstevel@tonic-gate 	type = xmlGetProp(propval, (xmlChar *)type_attr);
4510Sstevel@tonic-gate 	if (type == NULL)
4520Sstevel@tonic-gate 		uu_die(gettext("property type missing for property '%s/%s'\n"),
4530Sstevel@tonic-gate 		    pgrp->sc_pgroup_name, p->sc_property_name);
4540Sstevel@tonic-gate 
4550Sstevel@tonic-gate 	for (r = 0; r < sizeof (lxml_prop_types) / sizeof (char *); ++r) {
4560Sstevel@tonic-gate 		if (xmlStrcmp(type, (const xmlChar *)lxml_prop_types[r]) == 0)
4570Sstevel@tonic-gate 			break;
4580Sstevel@tonic-gate 	}
4590Sstevel@tonic-gate 	if (r >= sizeof (lxml_prop_types) / sizeof (char *))
4600Sstevel@tonic-gate 		uu_die(gettext("property type invalid for property '%s/%s'\n"),
4610Sstevel@tonic-gate 		    pgrp->sc_pgroup_name, p->sc_property_name);
4620Sstevel@tonic-gate 
4630Sstevel@tonic-gate 	p->sc_value_type = lxml_element_to_type(r);
4640Sstevel@tonic-gate 
4650Sstevel@tonic-gate 	val = xmlGetProp(propval, (xmlChar *)value_attr);
4660Sstevel@tonic-gate 	if (val == NULL)
4670Sstevel@tonic-gate 		uu_die(gettext("property value missing for property '%s/%s'\n"),
4680Sstevel@tonic-gate 		    pgrp->sc_pgroup_name, p->sc_property_name);
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate 	v = lxml_make_value(r, val);
4710Sstevel@tonic-gate 	internal_attach_value(p, v);
4720Sstevel@tonic-gate 
4730Sstevel@tonic-gate 	override = xmlGetProp(propval, (xmlChar *)override_attr);
4740Sstevel@tonic-gate 	p->sc_property_override = (xmlStrcmp(override, (xmlChar *)true) == 0);
4750Sstevel@tonic-gate 	xmlFree(override);
4760Sstevel@tonic-gate 
4770Sstevel@tonic-gate 	return (internal_attach_property(pgrp, p));
4780Sstevel@tonic-gate }
4790Sstevel@tonic-gate 
4800Sstevel@tonic-gate static int
4810Sstevel@tonic-gate lxml_get_property(pgroup_t *pgrp, xmlNodePtr property)
4820Sstevel@tonic-gate {
4830Sstevel@tonic-gate 	property_t *p;
4840Sstevel@tonic-gate 	xmlNodePtr cursor;
4850Sstevel@tonic-gate 	element_t r;
4860Sstevel@tonic-gate 	xmlChar *type, *override;
4870Sstevel@tonic-gate 
4880Sstevel@tonic-gate 	p = internal_property_new();
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate 	if ((p->sc_property_name = (char *)xmlGetProp(property,
4910Sstevel@tonic-gate 	    (xmlChar *)name_attr)) == NULL)
4920Sstevel@tonic-gate 		uu_die(gettext("property name missing in group \'%s\'\n"),
4930Sstevel@tonic-gate 		    pgrp->sc_pgroup_name);
4940Sstevel@tonic-gate 
4950Sstevel@tonic-gate 	if ((type = xmlGetProp(property, (xmlChar *)type_attr)) == NULL)
4960Sstevel@tonic-gate 		uu_die(gettext("property type missing for "
4970Sstevel@tonic-gate 		    "property \'%s/%s\'\n"), pgrp->sc_pgroup_name,
4980Sstevel@tonic-gate 		    p->sc_property_name);
4990Sstevel@tonic-gate 
5000Sstevel@tonic-gate 	for (cursor = property->xmlChildrenNode; cursor != NULL;
5010Sstevel@tonic-gate 	    cursor = cursor->next) {
5020Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
5030Sstevel@tonic-gate 			continue;
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate 		switch (r = lxml_xlate_element(cursor->name)) {
5060Sstevel@tonic-gate 		case SC_ASTRING:
5070Sstevel@tonic-gate 		case SC_BOOLEAN:
5080Sstevel@tonic-gate 		case SC_COUNT:
5090Sstevel@tonic-gate 		case SC_FMRI:
5100Sstevel@tonic-gate 		case SC_HOST:
5110Sstevel@tonic-gate 		case SC_HOSTNAME:
5120Sstevel@tonic-gate 		case SC_INTEGER:
5130Sstevel@tonic-gate 		case SC_NET_ADDR_V4:
5140Sstevel@tonic-gate 		case SC_NET_ADDR_V6:
5150Sstevel@tonic-gate 		case SC_OPAQUE:
5160Sstevel@tonic-gate 		case SC_TIME:
5170Sstevel@tonic-gate 		case SC_URI:
5180Sstevel@tonic-gate 		case SC_USTRING:
5190Sstevel@tonic-gate 			if (strcmp(lxml_prop_types[r], (const char *)type) != 0)
5200Sstevel@tonic-gate 				uu_die(gettext("property \'%s\' "
5210Sstevel@tonic-gate 				    "type-to-list mismatch\n"),
5220Sstevel@tonic-gate 				    p->sc_property_name);
5230Sstevel@tonic-gate 
5240Sstevel@tonic-gate 			p->sc_value_type = lxml_element_to_type(r);
5250Sstevel@tonic-gate 			(void) lxml_get_value(p, r, cursor);
5260Sstevel@tonic-gate 			break;
5270Sstevel@tonic-gate 		default:
5280Sstevel@tonic-gate 			uu_die(gettext("unknown value list type: %s\n"),
5290Sstevel@tonic-gate 			    cursor->name);
5300Sstevel@tonic-gate 			break;
5310Sstevel@tonic-gate 		}
5320Sstevel@tonic-gate 	}
5330Sstevel@tonic-gate 
5340Sstevel@tonic-gate 	xmlFree(type);
5350Sstevel@tonic-gate 
5360Sstevel@tonic-gate 	override = xmlGetProp(property, (xmlChar *)override_attr);
5370Sstevel@tonic-gate 	p->sc_property_override = (xmlStrcmp(override, (xmlChar *)true) == 0);
5380Sstevel@tonic-gate 	xmlFree(override);
5390Sstevel@tonic-gate 
5400Sstevel@tonic-gate 	return (internal_attach_property(pgrp, p));
5410Sstevel@tonic-gate }
5420Sstevel@tonic-gate 
5430Sstevel@tonic-gate static int
5440Sstevel@tonic-gate lxml_get_pgroup_stability(pgroup_t *pgrp, xmlNodePtr stab)
5450Sstevel@tonic-gate {
5460Sstevel@tonic-gate 	return (new_str_prop_from_attr(pgrp, SCF_PROPERTY_STABILITY,
5470Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, stab, value_attr));
5480Sstevel@tonic-gate }
5490Sstevel@tonic-gate 
5500Sstevel@tonic-gate /*
5510Sstevel@tonic-gate  * Property groups can go on any of a service, an instance, or a template.
5520Sstevel@tonic-gate  */
5530Sstevel@tonic-gate static int
5540Sstevel@tonic-gate lxml_get_pgroup(entity_t *entity, xmlNodePtr pgroup)
5550Sstevel@tonic-gate {
5560Sstevel@tonic-gate 	pgroup_t *pg;
5570Sstevel@tonic-gate 	xmlNodePtr cursor;
5580Sstevel@tonic-gate 	xmlChar *name, *type, *delete;
5590Sstevel@tonic-gate 
5600Sstevel@tonic-gate 	/*
5610Sstevel@tonic-gate 	 * property group attributes:
5620Sstevel@tonic-gate 	 * name: string
5630Sstevel@tonic-gate 	 * type: string | framework | application
5640Sstevel@tonic-gate 	 */
5650Sstevel@tonic-gate 	name = xmlGetProp(pgroup, (xmlChar *)name_attr);
5660Sstevel@tonic-gate 	type = xmlGetProp(pgroup, (xmlChar *)type_attr);
5670Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(entity, (char *)name, (char *)type);
5680Sstevel@tonic-gate 	xmlFree(name);
5690Sstevel@tonic-gate 	xmlFree(type);
5700Sstevel@tonic-gate 
5710Sstevel@tonic-gate 	/*
5720Sstevel@tonic-gate 	 * Walk the children of this lxml_elements, which are a stability
5730Sstevel@tonic-gate 	 * element, property elements, or propval elements.
5740Sstevel@tonic-gate 	 */
5750Sstevel@tonic-gate 	for (cursor = pgroup->xmlChildrenNode; cursor != NULL;
5760Sstevel@tonic-gate 	    cursor = cursor->next) {
5770Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
5780Sstevel@tonic-gate 			continue;
5790Sstevel@tonic-gate 
5800Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
5810Sstevel@tonic-gate 		case SC_STABILITY:
5820Sstevel@tonic-gate 			(void) lxml_get_pgroup_stability(pg, cursor);
5830Sstevel@tonic-gate 			break;
5840Sstevel@tonic-gate 		case SC_PROPERTY:
5850Sstevel@tonic-gate 			(void) lxml_get_property(pg, cursor);
5860Sstevel@tonic-gate 			break;
5870Sstevel@tonic-gate 		case SC_PROPVAL:
5880Sstevel@tonic-gate 			(void) lxml_get_propval(pg, cursor);
5890Sstevel@tonic-gate 			break;
5900Sstevel@tonic-gate 		default:
5910Sstevel@tonic-gate 			abort();
5920Sstevel@tonic-gate 			break;
5930Sstevel@tonic-gate 		}
5940Sstevel@tonic-gate 	}
5950Sstevel@tonic-gate 
5960Sstevel@tonic-gate 	delete = xmlGetProp(pgroup, (xmlChar *)delete_attr);
5970Sstevel@tonic-gate 	pg->sc_pgroup_delete = (xmlStrcmp(delete, (xmlChar *)true) == 0);
5980Sstevel@tonic-gate 	xmlFree(delete);
5990Sstevel@tonic-gate 
6000Sstevel@tonic-gate 	return (0);
6010Sstevel@tonic-gate }
6020Sstevel@tonic-gate 
6030Sstevel@tonic-gate 
6040Sstevel@tonic-gate /*
6050Sstevel@tonic-gate  * Dependency groups, execution methods can go on either a service or an
6060Sstevel@tonic-gate  * instance.
6070Sstevel@tonic-gate  */
6080Sstevel@tonic-gate 
6090Sstevel@tonic-gate static int
6100Sstevel@tonic-gate lxml_get_method_profile(pgroup_t *pg, xmlNodePtr profile)
6110Sstevel@tonic-gate {
6120Sstevel@tonic-gate 	property_t *p;
6130Sstevel@tonic-gate 
6140Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_USE_PROFILE, SCF_TYPE_BOOLEAN,
6150Sstevel@tonic-gate 	    1, (uint64_t)1);
6160Sstevel@tonic-gate 	if (internal_attach_property(pg, p) != 0)
6170Sstevel@tonic-gate 		return (-1);
6180Sstevel@tonic-gate 
6190Sstevel@tonic-gate 	return (new_str_prop_from_attr(pg, SCF_PROPERTY_PROFILE,
6200Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, profile, name_attr));
6210Sstevel@tonic-gate }
6220Sstevel@tonic-gate 
6230Sstevel@tonic-gate static int
6240Sstevel@tonic-gate lxml_get_method_credential(pgroup_t *pg, xmlNodePtr cred)
6250Sstevel@tonic-gate {
6260Sstevel@tonic-gate 	property_t *p;
6270Sstevel@tonic-gate 
6280Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_USE_PROFILE, SCF_TYPE_BOOLEAN,
6290Sstevel@tonic-gate 	    1, (uint64_t)0);
6300Sstevel@tonic-gate 	if (internal_attach_property(pg, p) != 0)
6310Sstevel@tonic-gate 		return (-1);
6320Sstevel@tonic-gate 
6330Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_USER, SCF_TYPE_ASTRING,
6340Sstevel@tonic-gate 	    cred, "user") != 0)
6350Sstevel@tonic-gate 		return (-1);
6360Sstevel@tonic-gate 
6370Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_GROUP, SCF_TYPE_ASTRING,
6380Sstevel@tonic-gate 	    cred, "group") != 0)
6390Sstevel@tonic-gate 		return (-1);
6400Sstevel@tonic-gate 
6410Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_SUPP_GROUPS,
6420Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, cred, "supp_groups") != 0)
6430Sstevel@tonic-gate 		return (-1);
6440Sstevel@tonic-gate 
6450Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_PRIVILEGES,
6460Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, cred, "privileges") != 0)
6470Sstevel@tonic-gate 		return (-1);
6480Sstevel@tonic-gate 
6490Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_LIMIT_PRIVILEGES,
6500Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, cred, "limit_privileges") != 0)
6510Sstevel@tonic-gate 		return (-1);
6520Sstevel@tonic-gate 
6530Sstevel@tonic-gate 	return (0);
6540Sstevel@tonic-gate }
6550Sstevel@tonic-gate 
6560Sstevel@tonic-gate static char *
6570Sstevel@tonic-gate lxml_get_envvar(xmlNodePtr envvar)
6580Sstevel@tonic-gate {
6590Sstevel@tonic-gate 	char *name;
6600Sstevel@tonic-gate 	char *value;
6610Sstevel@tonic-gate 	char *ret;
6620Sstevel@tonic-gate 
6630Sstevel@tonic-gate 	name = (char *)xmlGetProp(envvar, (xmlChar *)"name");
6640Sstevel@tonic-gate 	value = (char *)xmlGetProp(envvar, (xmlChar *)"value");
6650Sstevel@tonic-gate 
6660Sstevel@tonic-gate 	if (strlen(name) == 0 || strchr(name, '=') != NULL)
6670Sstevel@tonic-gate 		uu_die(gettext("Invalid environment variable "
6680Sstevel@tonic-gate 		    "\"%s\".\n"), name);
6690Sstevel@tonic-gate 	if (strstr(name, "SMF_") == name)
6700Sstevel@tonic-gate 		uu_die(gettext("Invalid environment variable "
6710Sstevel@tonic-gate 		    "\"%s\"; \"SMF_\" prefix is reserved.\n"), name);
6720Sstevel@tonic-gate 
6730Sstevel@tonic-gate 	ret = uu_msprintf("%s=%s", name, value);
6740Sstevel@tonic-gate 	xmlFree(name);
6750Sstevel@tonic-gate 	xmlFree(value);
6760Sstevel@tonic-gate 	return (ret);
6770Sstevel@tonic-gate }
6780Sstevel@tonic-gate 
6790Sstevel@tonic-gate static int
6800Sstevel@tonic-gate lxml_get_method_environment(pgroup_t *pg, xmlNodePtr environment)
6810Sstevel@tonic-gate {
6820Sstevel@tonic-gate 	property_t *p;
6830Sstevel@tonic-gate 	xmlNodePtr cursor;
6840Sstevel@tonic-gate 	value_t *val;
6850Sstevel@tonic-gate 
6860Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_ENVIRONMENT,
6870Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, 0);
6880Sstevel@tonic-gate 
6890Sstevel@tonic-gate 	for (cursor = environment->xmlChildrenNode; cursor != NULL;
6900Sstevel@tonic-gate 	    cursor = cursor->next) {
6910Sstevel@tonic-gate 		char *tmp;
6920Sstevel@tonic-gate 
6930Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
6940Sstevel@tonic-gate 			continue;
6950Sstevel@tonic-gate 
6960Sstevel@tonic-gate 		if (lxml_xlate_element(cursor->name) != SC_METHOD_ENVVAR)
6970Sstevel@tonic-gate 			uu_die(gettext("illegal element \"%s\" on "
6980Sstevel@tonic-gate 			    "method environment for \"%s\"\n"),
6990Sstevel@tonic-gate 			    cursor->name, pg->sc_pgroup_name);
7000Sstevel@tonic-gate 
7010Sstevel@tonic-gate 		if ((tmp = lxml_get_envvar(cursor)) == NULL)
7020Sstevel@tonic-gate 			uu_die(gettext("Out of memory\n"));
7030Sstevel@tonic-gate 
7040Sstevel@tonic-gate 		val = internal_value_new();
7050Sstevel@tonic-gate 		val->sc_u.sc_string = tmp;
7060Sstevel@tonic-gate 		val->sc_type = SCF_TYPE_ASTRING;
7070Sstevel@tonic-gate 		val->sc_free = lxml_free_str;
7080Sstevel@tonic-gate 		internal_attach_value(p, val);
7090Sstevel@tonic-gate 	}
7100Sstevel@tonic-gate 
7110Sstevel@tonic-gate 	if (internal_attach_property(pg, p) != 0) {
7120Sstevel@tonic-gate 		internal_property_free(p);
7130Sstevel@tonic-gate 		return (-1);
7140Sstevel@tonic-gate 	}
7150Sstevel@tonic-gate 
7160Sstevel@tonic-gate 	return (0);
7170Sstevel@tonic-gate }
7180Sstevel@tonic-gate 
7190Sstevel@tonic-gate static int
7200Sstevel@tonic-gate lxml_get_method_context(pgroup_t *pg, xmlNodePtr ctx)
7210Sstevel@tonic-gate {
7220Sstevel@tonic-gate 	xmlNodePtr cursor;
7230Sstevel@tonic-gate 
7240Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_WORKING_DIRECTORY,
7250Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, ctx, "working_directory") != 0)
7260Sstevel@tonic-gate 		return (-1);
7270Sstevel@tonic-gate 
7280Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_PROJECT, SCF_TYPE_ASTRING,
7290Sstevel@tonic-gate 	    ctx, "project") != 0)
7300Sstevel@tonic-gate 		return (-1);
7310Sstevel@tonic-gate 
7320Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_RESOURCE_POOL,
7330Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, ctx, "resource_pool") != 0)
7340Sstevel@tonic-gate 		return (-1);
7350Sstevel@tonic-gate 
7360Sstevel@tonic-gate 	for (cursor = ctx->xmlChildrenNode; cursor != NULL;
7370Sstevel@tonic-gate 	    cursor = cursor->next) {
7380Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
7390Sstevel@tonic-gate 			continue;
7400Sstevel@tonic-gate 
7410Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
7420Sstevel@tonic-gate 		case SC_METHOD_CREDENTIAL:
7430Sstevel@tonic-gate 			(void) lxml_get_method_credential(pg, cursor);
7440Sstevel@tonic-gate 			break;
7450Sstevel@tonic-gate 		case SC_METHOD_PROFILE:
7460Sstevel@tonic-gate 			(void) lxml_get_method_profile(pg, cursor);
7470Sstevel@tonic-gate 			break;
7480Sstevel@tonic-gate 		case SC_METHOD_ENVIRONMENT:
7490Sstevel@tonic-gate 			(void) lxml_get_method_environment(pg, cursor);
7500Sstevel@tonic-gate 			break;
7510Sstevel@tonic-gate 		default:
7520Sstevel@tonic-gate 			semerr(gettext("illegal element \'%s\' in method "
7530Sstevel@tonic-gate 			    "context\n"), (char *)cursor);
7540Sstevel@tonic-gate 			break;
7550Sstevel@tonic-gate 		}
7560Sstevel@tonic-gate 	}
7570Sstevel@tonic-gate 
7580Sstevel@tonic-gate 	return (0);
7590Sstevel@tonic-gate }
7600Sstevel@tonic-gate 
7610Sstevel@tonic-gate static int
7620Sstevel@tonic-gate lxml_get_entity_method_context(entity_t *entity, xmlNodePtr ctx)
7630Sstevel@tonic-gate {
7640Sstevel@tonic-gate 	pgroup_t *pg;
7650Sstevel@tonic-gate 
7660Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(entity, SCF_PG_METHOD_CONTEXT,
7670Sstevel@tonic-gate 	    (char *)scf_group_framework);
7680Sstevel@tonic-gate 
7690Sstevel@tonic-gate 	return (lxml_get_method_context(pg, ctx));
7700Sstevel@tonic-gate }
7710Sstevel@tonic-gate 
7720Sstevel@tonic-gate static int
7730Sstevel@tonic-gate lxml_get_exec_method(entity_t *entity, xmlNodePtr emeth)
7740Sstevel@tonic-gate {
7750Sstevel@tonic-gate 	pgroup_t *pg;
7760Sstevel@tonic-gate 	property_t *p;
7770Sstevel@tonic-gate 	xmlChar *name, *timeout, *delete;
7780Sstevel@tonic-gate 	xmlNodePtr cursor;
7790Sstevel@tonic-gate 	int r = 0;
7800Sstevel@tonic-gate 
7810Sstevel@tonic-gate 	name = xmlGetProp(emeth, (xmlChar *)name_attr);
7820Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(entity, (char *)name,
7830Sstevel@tonic-gate 	    (char *)SCF_GROUP_METHOD);
7840Sstevel@tonic-gate 	xmlFree(name);
7850Sstevel@tonic-gate 
7860Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_TYPE, SCF_TYPE_ASTRING,
7870Sstevel@tonic-gate 	    emeth, type_attr) != 0 ||
7880Sstevel@tonic-gate 	    new_str_prop_from_attr(pg, SCF_PROPERTY_EXEC, SCF_TYPE_ASTRING,
7890Sstevel@tonic-gate 	    emeth, "exec") != 0)
7900Sstevel@tonic-gate 		return (-1);
7910Sstevel@tonic-gate 
7920Sstevel@tonic-gate 	timeout = xmlGetProp(emeth, (xmlChar *)"timeout_seconds");
7930Sstevel@tonic-gate 	if (timeout != NULL) {
7940Sstevel@tonic-gate 		uint64_t u_timeout;
7950Sstevel@tonic-gate 		char *endptr;
7960Sstevel@tonic-gate 		/*
7970Sstevel@tonic-gate 		 * Although an SC_COUNT represents a uint64_t the use
7980Sstevel@tonic-gate 		 * of a negative value is acceptable due to the usage
7990Sstevel@tonic-gate 		 * established by inetd(1M).
8000Sstevel@tonic-gate 		 */
8010Sstevel@tonic-gate 		errno = 0;
8020Sstevel@tonic-gate 		u_timeout = strtoull((char *)timeout, &endptr, 10);
8030Sstevel@tonic-gate 		if (errno != 0 || endptr == (char *)timeout || *endptr)
8040Sstevel@tonic-gate 			uu_die(gettext("illegal value \"%s\" for "
8050Sstevel@tonic-gate 			    "timeout_seconds (%s)\n"),
8060Sstevel@tonic-gate 			    (char *)timeout, (errno) ? strerror(errno):
8070Sstevel@tonic-gate 			    gettext("Illegal character"));
8080Sstevel@tonic-gate 		p = internal_property_create(SCF_PROPERTY_TIMEOUT,
8090Sstevel@tonic-gate 		    SCF_TYPE_COUNT, 1, u_timeout);
8100Sstevel@tonic-gate 		r = internal_attach_property(pg, p);
8110Sstevel@tonic-gate 		xmlFree(timeout);
8120Sstevel@tonic-gate 	}
8130Sstevel@tonic-gate 	if (r != 0)
8140Sstevel@tonic-gate 		return (-1);
8150Sstevel@tonic-gate 
8160Sstevel@tonic-gate 	/*
8170Sstevel@tonic-gate 	 * There is a possibility that a method context also exists, in which
8180Sstevel@tonic-gate 	 * case the following attributes are defined: project, resource_pool,
8190Sstevel@tonic-gate 	 * working_directory, profile, user, group, privileges, limit_privileges
8200Sstevel@tonic-gate 	 */
8210Sstevel@tonic-gate 	for (cursor = emeth->xmlChildrenNode; cursor != NULL;
8220Sstevel@tonic-gate 	    cursor = cursor->next) {
8230Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
8240Sstevel@tonic-gate 			continue;
8250Sstevel@tonic-gate 
8260Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
8270Sstevel@tonic-gate 		case SC_STABILITY:
8280Sstevel@tonic-gate 			if (lxml_get_pgroup_stability(pg, cursor) != 0)
8290Sstevel@tonic-gate 				return (-1);
8300Sstevel@tonic-gate 			break;
8310Sstevel@tonic-gate 
8320Sstevel@tonic-gate 		case SC_METHOD_CONTEXT:
8330Sstevel@tonic-gate 			(void) lxml_get_method_context(pg, cursor);
8340Sstevel@tonic-gate 			break;
8350Sstevel@tonic-gate 
8360Sstevel@tonic-gate 		case SC_PROPVAL:
8370Sstevel@tonic-gate 			(void) lxml_get_propval(pg, cursor);
8380Sstevel@tonic-gate 			break;
8390Sstevel@tonic-gate 
8400Sstevel@tonic-gate 		case SC_PROPERTY:
8410Sstevel@tonic-gate 			(void) lxml_get_property(pg, cursor);
8420Sstevel@tonic-gate 			break;
8430Sstevel@tonic-gate 
8440Sstevel@tonic-gate 		default:
8450Sstevel@tonic-gate 			uu_die(gettext("illegal element \"%s\" on "
8460Sstevel@tonic-gate 			    "execution method \"%s\"\n"), cursor->name,
8470Sstevel@tonic-gate 			    pg->sc_pgroup_name);
8480Sstevel@tonic-gate 			break;
8490Sstevel@tonic-gate 		}
8500Sstevel@tonic-gate 	}
8510Sstevel@tonic-gate 
8520Sstevel@tonic-gate 	delete = xmlGetProp(emeth, (xmlChar *)delete_attr);
8530Sstevel@tonic-gate 	pg->sc_pgroup_delete = (xmlStrcmp(delete, (xmlChar *)true) == 0);
8540Sstevel@tonic-gate 	xmlFree(delete);
8550Sstevel@tonic-gate 
8560Sstevel@tonic-gate 	return (0);
8570Sstevel@tonic-gate }
8580Sstevel@tonic-gate 
8590Sstevel@tonic-gate static int
8600Sstevel@tonic-gate lxml_get_dependency(entity_t *entity, xmlNodePtr dependency)
8610Sstevel@tonic-gate {
8620Sstevel@tonic-gate 	pgroup_t *pg;
8630Sstevel@tonic-gate 	property_t *p;
8640Sstevel@tonic-gate 	xmlNodePtr cursor;
8650Sstevel@tonic-gate 	xmlChar *name;
8660Sstevel@tonic-gate 	xmlChar *delete;
8670Sstevel@tonic-gate 
8680Sstevel@tonic-gate 	/*
8690Sstevel@tonic-gate 	 * dependency attributes:
8700Sstevel@tonic-gate 	 * name: string
8710Sstevel@tonic-gate 	 * grouping: require_all | require_any | exclude_all | optional_all
8720Sstevel@tonic-gate 	 * reset_on: string (error | restart | refresh | none)
8730Sstevel@tonic-gate 	 * type:  service / path /host
8740Sstevel@tonic-gate 	 */
8750Sstevel@tonic-gate 
8760Sstevel@tonic-gate 	name = xmlGetProp(dependency, (xmlChar *)name_attr);
8770Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(entity, (char *)name,
8780Sstevel@tonic-gate 	    (char *)SCF_GROUP_DEPENDENCY);
8790Sstevel@tonic-gate 	xmlFree(name);
8800Sstevel@tonic-gate 
8810Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_TYPE, SCF_TYPE_ASTRING,
8820Sstevel@tonic-gate 	    dependency, type_attr) != 0)
8830Sstevel@tonic-gate 		return (-1);
8840Sstevel@tonic-gate 
8850Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_RESTART_ON,
8860Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, dependency, "restart_on") != 0)
8870Sstevel@tonic-gate 		return (-1);
8880Sstevel@tonic-gate 
8890Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_GROUPING, SCF_TYPE_ASTRING,
8900Sstevel@tonic-gate 	    dependency, "grouping") != 0)
8910Sstevel@tonic-gate 		return (-1);
8920Sstevel@tonic-gate 
8930Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_ENTITIES, SCF_TYPE_FMRI, 0);
8940Sstevel@tonic-gate 	if (internal_attach_property(pg, p) != 0)
8950Sstevel@tonic-gate 		return (-1);
8960Sstevel@tonic-gate 
8970Sstevel@tonic-gate 	for (cursor = dependency->xmlChildrenNode; cursor != NULL;
8980Sstevel@tonic-gate 	    cursor = cursor->next) {
8990Sstevel@tonic-gate 		xmlChar *value;
9000Sstevel@tonic-gate 		value_t *v;
9010Sstevel@tonic-gate 
9020Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
9030Sstevel@tonic-gate 			continue;
9040Sstevel@tonic-gate 
9050Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
9060Sstevel@tonic-gate 		case SC_STABILITY:
9070Sstevel@tonic-gate 			if (lxml_get_pgroup_stability(pg, cursor) != 0)
9080Sstevel@tonic-gate 				return (-1);
9090Sstevel@tonic-gate 			break;
9100Sstevel@tonic-gate 
9110Sstevel@tonic-gate 		case SC_SERVICE_FMRI:
9120Sstevel@tonic-gate 			value = xmlGetProp(cursor, (xmlChar *)value_attr);
9130Sstevel@tonic-gate 			if (value != NULL) {
9140Sstevel@tonic-gate 				if (lxml_validate_string_value(SCF_TYPE_FMRI,
9150Sstevel@tonic-gate 				    (char *)value) != 0)
9160Sstevel@tonic-gate 					uu_die(gettext("illegal value \"%s\" "
9170Sstevel@tonic-gate 					    "for %s (%s)\n"), (char *)value,
9180Sstevel@tonic-gate 					    lxml_prop_types[SC_FMRI],
9190Sstevel@tonic-gate 					    (scf_error()) ?
9200Sstevel@tonic-gate 					    scf_strerror(scf_error()) :
9210Sstevel@tonic-gate 					    gettext("Illegal format"));
9220Sstevel@tonic-gate 				v = internal_value_new();
9230Sstevel@tonic-gate 				v->sc_type = SCF_TYPE_FMRI;
9240Sstevel@tonic-gate 				v->sc_u.sc_string = (char *)value;
9250Sstevel@tonic-gate 				internal_attach_value(p, v);
9260Sstevel@tonic-gate 			}
9270Sstevel@tonic-gate 
9280Sstevel@tonic-gate 			break;
9290Sstevel@tonic-gate 
9300Sstevel@tonic-gate 		case SC_PROPVAL:
9310Sstevel@tonic-gate 			(void) lxml_get_propval(pg, cursor);
9320Sstevel@tonic-gate 			break;
9330Sstevel@tonic-gate 
9340Sstevel@tonic-gate 		case SC_PROPERTY:
9350Sstevel@tonic-gate 			(void) lxml_get_property(pg, cursor);
9360Sstevel@tonic-gate 			break;
9370Sstevel@tonic-gate 
9380Sstevel@tonic-gate 		default:
9390Sstevel@tonic-gate 			uu_die(gettext("illegal element \"%s\" on "
9400Sstevel@tonic-gate 			    "dependency group \"%s\"\n"), cursor->name, name);
9410Sstevel@tonic-gate 			break;
9420Sstevel@tonic-gate 		}
9430Sstevel@tonic-gate 	}
9440Sstevel@tonic-gate 
9450Sstevel@tonic-gate 	delete = xmlGetProp(dependency, (xmlChar *)delete_attr);
9460Sstevel@tonic-gate 	pg->sc_pgroup_delete = (xmlStrcmp(delete, (xmlChar *)true) == 0);
9470Sstevel@tonic-gate 	xmlFree(delete);
9480Sstevel@tonic-gate 
9490Sstevel@tonic-gate 	return (0);
9500Sstevel@tonic-gate }
9510Sstevel@tonic-gate 
9520Sstevel@tonic-gate /*
9530Sstevel@tonic-gate  * Dependents are hairy.  They should cause a dependency pg to be created in
9540Sstevel@tonic-gate  * another service, but we can't do that here; we'll have to wait until the
9550Sstevel@tonic-gate  * import routines.  So for now we'll add the dependency group that should go
9560Sstevel@tonic-gate  * in the other service to the entity's dependent list.
9570Sstevel@tonic-gate  */
9580Sstevel@tonic-gate static int
9590Sstevel@tonic-gate lxml_get_dependent(entity_t *entity, xmlNodePtr dependent)
9600Sstevel@tonic-gate {
9610Sstevel@tonic-gate 	xmlChar *name, *or;
9620Sstevel@tonic-gate 	xmlNodePtr sf;
9630Sstevel@tonic-gate 	xmlChar *fmri, *delete;
9640Sstevel@tonic-gate 	pgroup_t *pg;
9650Sstevel@tonic-gate 	property_t *p;
9660Sstevel@tonic-gate 	xmlNodePtr n;
9670Sstevel@tonic-gate 	char *myfmri;
9680Sstevel@tonic-gate 
9690Sstevel@tonic-gate 	name = xmlGetProp(dependent, (xmlChar *)name_attr);
9700Sstevel@tonic-gate 
9710Sstevel@tonic-gate 	if (internal_pgroup_find(entity, (char *)name, NULL) != NULL) {
9720Sstevel@tonic-gate 		semerr(gettext("Property group and dependent of entity %s "
9730Sstevel@tonic-gate 		    "have same name \"%s\".\n"), entity->sc_name, name);
9740Sstevel@tonic-gate 		xmlFree(name);
9750Sstevel@tonic-gate 		return (-1);
9760Sstevel@tonic-gate 	}
9770Sstevel@tonic-gate 
9780Sstevel@tonic-gate 	or = xmlGetProp(dependent, (xmlChar *)override_attr);
9790Sstevel@tonic-gate 
9800Sstevel@tonic-gate 	pg = internal_pgroup_new();
9810Sstevel@tonic-gate 	pg->sc_pgroup_name = (char *)name;
9820Sstevel@tonic-gate 	pg->sc_pgroup_type = (char *)SCF_GROUP_DEPENDENCY;
9830Sstevel@tonic-gate 	pg->sc_pgroup_override = (xmlStrcmp(or, (xmlChar *)true) == 0);
9840Sstevel@tonic-gate 	xmlFree(or);
9850Sstevel@tonic-gate 	if (internal_attach_dependent(entity, pg) != 0) {
9860Sstevel@tonic-gate 		xmlFree(name);
9870Sstevel@tonic-gate 		internal_pgroup_free(pg);
9880Sstevel@tonic-gate 		return (-1);
9890Sstevel@tonic-gate 	}
9900Sstevel@tonic-gate 
9910Sstevel@tonic-gate 	for (sf = dependent->children; sf != NULL; sf = sf->next)
9920Sstevel@tonic-gate 		if (xmlStrcmp(sf->name, (xmlChar *)"service_fmri") == 0)
9930Sstevel@tonic-gate 			break;
9940Sstevel@tonic-gate 	assert(sf != NULL);
9950Sstevel@tonic-gate 	fmri = xmlGetProp(sf, (xmlChar *)value_attr);
9960Sstevel@tonic-gate 	pg->sc_pgroup_fmri = (char *)fmri;
9970Sstevel@tonic-gate 
9980Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_RESTART_ON,
9990Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, dependent, "restart_on") != 0)
10000Sstevel@tonic-gate 		return (-1);
10010Sstevel@tonic-gate 
10020Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_GROUPING, SCF_TYPE_ASTRING,
10030Sstevel@tonic-gate 	    dependent, "grouping") != 0)
10040Sstevel@tonic-gate 		return (-1);
10050Sstevel@tonic-gate 
10060Sstevel@tonic-gate 	myfmri = safe_malloc(max_scf_fmri_len + 1);
10070Sstevel@tonic-gate 	if (entity->sc_etype == SVCCFG_SERVICE_OBJECT) {
10080Sstevel@tonic-gate 		if (snprintf(myfmri, max_scf_fmri_len + 1, "svc:/%s",
10090Sstevel@tonic-gate 		    entity->sc_name) < 0)
10100Sstevel@tonic-gate 			bad_error("snprintf", errno);
10110Sstevel@tonic-gate 	} else {
10120Sstevel@tonic-gate 		assert(entity->sc_etype == SVCCFG_INSTANCE_OBJECT);
10130Sstevel@tonic-gate 		if (snprintf(myfmri, max_scf_fmri_len + 1, "svc:/%s:%s",
10140Sstevel@tonic-gate 		    entity->sc_parent->sc_name, entity->sc_name) < 0)
10150Sstevel@tonic-gate 			bad_error("snprintf", errno);
10160Sstevel@tonic-gate 	}
10170Sstevel@tonic-gate 
10180Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_ENTITIES, SCF_TYPE_FMRI, 1,
10190Sstevel@tonic-gate 	    myfmri);
10200Sstevel@tonic-gate 	if (internal_attach_property(pg, p) != 0)
10210Sstevel@tonic-gate 		return (-1);
10220Sstevel@tonic-gate 
10230Sstevel@tonic-gate 	/* Create a property to serve as a do-not-export flag. */
10240Sstevel@tonic-gate 	p = internal_property_create("external", SCF_TYPE_BOOLEAN, 1,
10250Sstevel@tonic-gate 	    (uint64_t)1);
10260Sstevel@tonic-gate 	if (internal_attach_property(pg, p) != 0)
10270Sstevel@tonic-gate 		return (-1);
10280Sstevel@tonic-gate 
10290Sstevel@tonic-gate 	for (n = sf->next; n != NULL; n = n->next) {
10300Sstevel@tonic-gate 		if (lxml_ignorable_block(n))
10310Sstevel@tonic-gate 			continue;
10320Sstevel@tonic-gate 
10330Sstevel@tonic-gate 		switch (lxml_xlate_element(n->name)) {
10340Sstevel@tonic-gate 		case SC_STABILITY:
10350Sstevel@tonic-gate 			if (new_str_prop_from_attr(pg,
10360Sstevel@tonic-gate 			    SCF_PROPERTY_ENTITY_STABILITY, SCF_TYPE_ASTRING, n,
10370Sstevel@tonic-gate 			    value_attr) != 0)
10380Sstevel@tonic-gate 				return (-1);
10390Sstevel@tonic-gate 			break;
10400Sstevel@tonic-gate 
10410Sstevel@tonic-gate 		case SC_PROPVAL:
10420Sstevel@tonic-gate 			(void) lxml_get_propval(pg, n);
10430Sstevel@tonic-gate 			break;
10440Sstevel@tonic-gate 
10450Sstevel@tonic-gate 		case SC_PROPERTY:
10460Sstevel@tonic-gate 			(void) lxml_get_property(pg, n);
10470Sstevel@tonic-gate 			break;
10480Sstevel@tonic-gate 
10490Sstevel@tonic-gate 		default:
10500Sstevel@tonic-gate 			uu_die(gettext("unexpected element %s.\n"), n->name);
10510Sstevel@tonic-gate 		}
10520Sstevel@tonic-gate 	}
10530Sstevel@tonic-gate 
10540Sstevel@tonic-gate 	/* Go back and fill in defaults. */
10550Sstevel@tonic-gate 	if (internal_property_find(pg, SCF_PROPERTY_TYPE) == NULL) {
10560Sstevel@tonic-gate 		p = internal_property_create(SCF_PROPERTY_TYPE,
10570Sstevel@tonic-gate 		    SCF_TYPE_ASTRING, 1, "service");
10580Sstevel@tonic-gate 		if (internal_attach_property(pg, p) != 0)
10590Sstevel@tonic-gate 			return (-1);
10600Sstevel@tonic-gate 	}
10610Sstevel@tonic-gate 
10620Sstevel@tonic-gate 	delete = xmlGetProp(dependent, (xmlChar *)delete_attr);
10630Sstevel@tonic-gate 	pg->sc_pgroup_delete = (xmlStrcmp(delete, (xmlChar *)true) == 0);
10640Sstevel@tonic-gate 	xmlFree(delete);
10650Sstevel@tonic-gate 
10660Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(entity, "dependents",
10670Sstevel@tonic-gate 	    (char *)scf_group_framework);
1068*306Sbustos 	p = internal_property_create((char *)name, SCF_TYPE_FMRI, 1, fmri);
10690Sstevel@tonic-gate 	if (internal_attach_property(pg, p) != 0)
10700Sstevel@tonic-gate 		return (-1);
10710Sstevel@tonic-gate 
10720Sstevel@tonic-gate 	return (0);
10730Sstevel@tonic-gate }
10740Sstevel@tonic-gate 
10750Sstevel@tonic-gate static int
10760Sstevel@tonic-gate lxml_get_entity_stability(entity_t *entity, xmlNodePtr rstr)
10770Sstevel@tonic-gate {
10780Sstevel@tonic-gate 	pgroup_t *pg;
10790Sstevel@tonic-gate 	property_t *p;
10800Sstevel@tonic-gate 	xmlChar *stabval;
10810Sstevel@tonic-gate 
10820Sstevel@tonic-gate 	if ((stabval = xmlGetProp(rstr, (xmlChar *)value_attr)) == NULL) {
10830Sstevel@tonic-gate 		uu_warn(gettext("no stability value found\n"));
10840Sstevel@tonic-gate 		stabval = (xmlChar *)strdup("External");
10850Sstevel@tonic-gate 	}
10860Sstevel@tonic-gate 
10870Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(entity, (char *)scf_pg_general,
10880Sstevel@tonic-gate 	    (char *)scf_group_framework);
10890Sstevel@tonic-gate 
10900Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_ENTITY_STABILITY,
10910Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, 1, stabval);
10920Sstevel@tonic-gate 
10930Sstevel@tonic-gate 	return (internal_attach_property(pg, p));
10940Sstevel@tonic-gate }
10950Sstevel@tonic-gate 
10960Sstevel@tonic-gate static int
10970Sstevel@tonic-gate lxml_get_restarter(entity_t *entity, xmlNodePtr rstr)
10980Sstevel@tonic-gate {
10990Sstevel@tonic-gate 	pgroup_t *pg;
11000Sstevel@tonic-gate 	property_t *p;
11010Sstevel@tonic-gate 	xmlChar *restarter;
11020Sstevel@tonic-gate 	xmlNode *cursor;
11030Sstevel@tonic-gate 	int r;
11040Sstevel@tonic-gate 
11050Sstevel@tonic-gate 	/*
11060Sstevel@tonic-gate 	 * Go find child.  Child is a service_fmri element.  value attribute
11070Sstevel@tonic-gate 	 * contains restarter FMRI.
11080Sstevel@tonic-gate 	 */
11090Sstevel@tonic-gate 
11100Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(entity, (char *)scf_pg_general,
11110Sstevel@tonic-gate 	    (char *)scf_group_framework);
11120Sstevel@tonic-gate 
11130Sstevel@tonic-gate 	/*
11140Sstevel@tonic-gate 	 * Walk its child elements, as appropriate.
11150Sstevel@tonic-gate 	 */
11160Sstevel@tonic-gate 	for (cursor = rstr->xmlChildrenNode; cursor != NULL;
11170Sstevel@tonic-gate 	    cursor = cursor->next) {
11180Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
11190Sstevel@tonic-gate 			continue;
11200Sstevel@tonic-gate 
11210Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
11220Sstevel@tonic-gate 		case SC_SERVICE_FMRI:
11230Sstevel@tonic-gate 			restarter = xmlGetProp(cursor, (xmlChar *)value_attr);
11240Sstevel@tonic-gate 			break;
11250Sstevel@tonic-gate 		default:
11260Sstevel@tonic-gate 			uu_die(gettext("illegal element \"%s\" on restarter "
11270Sstevel@tonic-gate 			    "element for \"%s\"\n"), cursor->name,
11280Sstevel@tonic-gate 			    entity->sc_name);
11290Sstevel@tonic-gate 			break;
11300Sstevel@tonic-gate 		}
11310Sstevel@tonic-gate 	}
11320Sstevel@tonic-gate 
11330Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_RESTARTER, SCF_TYPE_FMRI, 1,
11340Sstevel@tonic-gate 	    restarter);
11350Sstevel@tonic-gate 
11360Sstevel@tonic-gate 	r = internal_attach_property(pg, p);
11370Sstevel@tonic-gate 	if (r != 0) {
11380Sstevel@tonic-gate 		internal_property_free(p);
11390Sstevel@tonic-gate 		return (-1);
11400Sstevel@tonic-gate 	}
11410Sstevel@tonic-gate 
11420Sstevel@tonic-gate 	return (0);
11430Sstevel@tonic-gate }
11440Sstevel@tonic-gate 
11450Sstevel@tonic-gate static void
11460Sstevel@tonic-gate sanitize_locale(uchar_t *locale)
11470Sstevel@tonic-gate {
11480Sstevel@tonic-gate 	for (; *locale != '\0'; locale++)
11490Sstevel@tonic-gate 		if (!isalnum(*locale) && *locale != '_')
11500Sstevel@tonic-gate 			*locale = '_';
11510Sstevel@tonic-gate }
11520Sstevel@tonic-gate 
11530Sstevel@tonic-gate static int
11540Sstevel@tonic-gate lxml_get_loctext(entity_t *service, pgroup_t *pg, xmlNodePtr loctext)
11550Sstevel@tonic-gate {
11560Sstevel@tonic-gate 	xmlNodePtr cursor;
11570Sstevel@tonic-gate 	xmlChar *val;
11580Sstevel@tonic-gate 	char *stripped, *cp;
11590Sstevel@tonic-gate 	property_t *p;
11600Sstevel@tonic-gate 	int r;
11610Sstevel@tonic-gate 
11620Sstevel@tonic-gate 	if ((val = xmlGetProp(loctext, (xmlChar *)"xml:lang")) == NULL)
11630Sstevel@tonic-gate 		if ((val = xmlGetProp(loctext, (xmlChar *)"lang")) == NULL)
11640Sstevel@tonic-gate 			val = (xmlChar *)"unknown";
11650Sstevel@tonic-gate 
11660Sstevel@tonic-gate 	sanitize_locale(val);
11670Sstevel@tonic-gate 
11680Sstevel@tonic-gate 	for (cursor = loctext->xmlChildrenNode; cursor != NULL;
11690Sstevel@tonic-gate 	    cursor = cursor->next) {
11700Sstevel@tonic-gate 		if (strcmp("text", (const char *)cursor->name) == 0) {
11710Sstevel@tonic-gate 			break;
11720Sstevel@tonic-gate 		} else if (strcmp("comment", (const char *)cursor->name) != 0) {
11730Sstevel@tonic-gate 			uu_die(gettext("illegal element \"%s\" on loctext "
11740Sstevel@tonic-gate 			    "element for \"%s\"\n"), cursor->name,
11750Sstevel@tonic-gate 			    service->sc_name);
11760Sstevel@tonic-gate 		}
11770Sstevel@tonic-gate 	}
11780Sstevel@tonic-gate 
11790Sstevel@tonic-gate 	if (cursor == NULL) {
11800Sstevel@tonic-gate 		uu_die(gettext("loctext element has no content for \"%s\"\n"),
11810Sstevel@tonic-gate 		    service->sc_name);
11820Sstevel@tonic-gate 	}
11830Sstevel@tonic-gate 
11840Sstevel@tonic-gate 	/*
11850Sstevel@tonic-gate 	 * Remove leading and trailing whitespace.
11860Sstevel@tonic-gate 	 */
11870Sstevel@tonic-gate 	if ((stripped = strdup((const char *)cursor->content)) == NULL)
11880Sstevel@tonic-gate 		uu_die(gettext("Out of memory\n"));
11890Sstevel@tonic-gate 
11900Sstevel@tonic-gate 	for (; isspace(*stripped); stripped++);
11910Sstevel@tonic-gate 	for (cp = stripped + strlen(stripped) - 1; isspace(*cp); cp--);
11920Sstevel@tonic-gate 	*(cp + 1) = '\0';
11930Sstevel@tonic-gate 
11940Sstevel@tonic-gate 	p = internal_property_create((const char *)val, SCF_TYPE_USTRING, 1,
11950Sstevel@tonic-gate 	    stripped);
11960Sstevel@tonic-gate 
11970Sstevel@tonic-gate 	r = internal_attach_property(pg, p);
11980Sstevel@tonic-gate 	if (r != 0)
11990Sstevel@tonic-gate 		internal_property_free(p);
12000Sstevel@tonic-gate 
12010Sstevel@tonic-gate 	return (r);
12020Sstevel@tonic-gate }
12030Sstevel@tonic-gate 
12040Sstevel@tonic-gate static int
12050Sstevel@tonic-gate lxml_get_tm_common_name(entity_t *service, xmlNodePtr common_name)
12060Sstevel@tonic-gate {
12070Sstevel@tonic-gate 	xmlNodePtr cursor;
12080Sstevel@tonic-gate 	pgroup_t *pg;
12090Sstevel@tonic-gate 
12100Sstevel@tonic-gate 	/*
12110Sstevel@tonic-gate 	 * Create the property group, if absent.
12120Sstevel@tonic-gate 	 */
12130Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(service,
12140Sstevel@tonic-gate 	    (char *)SCF_PG_TM_COMMON_NAME, (char *)SCF_GROUP_TEMPLATE);
12150Sstevel@tonic-gate 
12160Sstevel@tonic-gate 	/*
12170Sstevel@tonic-gate 	 * Iterate through one or more loctext elements.  The locale is the
12180Sstevel@tonic-gate 	 * property name; the contents are the ustring value for the property.
12190Sstevel@tonic-gate 	 */
12200Sstevel@tonic-gate 	for (cursor = common_name->xmlChildrenNode; cursor != NULL;
12210Sstevel@tonic-gate 	    cursor = cursor->next) {
12220Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
12230Sstevel@tonic-gate 			continue;
12240Sstevel@tonic-gate 
12250Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
12260Sstevel@tonic-gate 		case SC_LOCTEXT:
12270Sstevel@tonic-gate 			if (lxml_get_loctext(service, pg, cursor))
12280Sstevel@tonic-gate 				return (-1);
12290Sstevel@tonic-gate 			break;
12300Sstevel@tonic-gate 		default:
12310Sstevel@tonic-gate 			uu_die(gettext("illegal element \"%s\" on common_name "
12320Sstevel@tonic-gate 			    "element for \"%s\"\n"), cursor->name,
12330Sstevel@tonic-gate 			    service->sc_name);
12340Sstevel@tonic-gate 			break;
12350Sstevel@tonic-gate 		}
12360Sstevel@tonic-gate 	}
12370Sstevel@tonic-gate 
12380Sstevel@tonic-gate 	return (0);
12390Sstevel@tonic-gate }
12400Sstevel@tonic-gate 
12410Sstevel@tonic-gate static int
12420Sstevel@tonic-gate lxml_get_tm_description(entity_t *service, xmlNodePtr description)
12430Sstevel@tonic-gate {
12440Sstevel@tonic-gate 	xmlNodePtr cursor;
12450Sstevel@tonic-gate 	pgroup_t *pg;
12460Sstevel@tonic-gate 
12470Sstevel@tonic-gate 	/*
12480Sstevel@tonic-gate 	 * Create the property group, if absent.
12490Sstevel@tonic-gate 	 */
12500Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(service,
12510Sstevel@tonic-gate 	    (char *)SCF_PG_TM_DESCRIPTION, (char *)SCF_GROUP_TEMPLATE);
12520Sstevel@tonic-gate 
12530Sstevel@tonic-gate 	/*
12540Sstevel@tonic-gate 	 * Iterate through one or more loctext elements.  The locale is the
12550Sstevel@tonic-gate 	 * property name; the contents are the ustring value for the property.
12560Sstevel@tonic-gate 	 */
12570Sstevel@tonic-gate 	for (cursor = description->xmlChildrenNode; cursor != NULL;
12580Sstevel@tonic-gate 	    cursor = cursor->next) {
12590Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
12600Sstevel@tonic-gate 			continue;
12610Sstevel@tonic-gate 
12620Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
12630Sstevel@tonic-gate 		case SC_LOCTEXT:
12640Sstevel@tonic-gate 			if (lxml_get_loctext(service, pg, cursor))
12650Sstevel@tonic-gate 				return (-1);
12660Sstevel@tonic-gate 			break;
12670Sstevel@tonic-gate 		default:
12680Sstevel@tonic-gate 			uu_die(gettext("illegal element \"%s\" on description "
12690Sstevel@tonic-gate 			    "element for \"%s\"\n"), cursor->name,
12700Sstevel@tonic-gate 			    service->sc_name);
12710Sstevel@tonic-gate 			break;
12720Sstevel@tonic-gate 		}
12730Sstevel@tonic-gate 	}
12740Sstevel@tonic-gate 
12750Sstevel@tonic-gate 	return (0);
12760Sstevel@tonic-gate }
12770Sstevel@tonic-gate 
12780Sstevel@tonic-gate static char *
12790Sstevel@tonic-gate lxml_label_to_groupname(const char *prefix, const char *in)
12800Sstevel@tonic-gate {
12810Sstevel@tonic-gate 	char *out, *cp;
12820Sstevel@tonic-gate 	size_t len, piece_len;
12830Sstevel@tonic-gate 
12840Sstevel@tonic-gate 	out = uu_zalloc(2 * scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1);
12850Sstevel@tonic-gate 	if (out == NULL)
12860Sstevel@tonic-gate 		return (NULL);
12870Sstevel@tonic-gate 
12880Sstevel@tonic-gate 	(void) strcpy(out, prefix);
12890Sstevel@tonic-gate 	(void) strcat(out, in);
12900Sstevel@tonic-gate 
12910Sstevel@tonic-gate 	len = strlen(out);
12920Sstevel@tonic-gate 	if (len > max_scf_name_len) {
12930Sstevel@tonic-gate 		/* Use the first half and the second half. */
12940Sstevel@tonic-gate 		piece_len = (max_scf_name_len - 2) / 2;
12950Sstevel@tonic-gate 
12960Sstevel@tonic-gate 		(void) strncpy(out + piece_len, "..", 2);
12970Sstevel@tonic-gate 
12980Sstevel@tonic-gate 		(void) strcpy(out + piece_len + 2, out + (len - piece_len));
12990Sstevel@tonic-gate 
13000Sstevel@tonic-gate 		len = strlen(out);
13010Sstevel@tonic-gate 	}
13020Sstevel@tonic-gate 
13030Sstevel@tonic-gate 	/*
13040Sstevel@tonic-gate 	 * Translate non-property characters to '_'.
13050Sstevel@tonic-gate 	 */
13060Sstevel@tonic-gate 	for (cp = out; *cp != '\0'; ++cp) {
13070Sstevel@tonic-gate 		if (!(isalnum(*cp) || *cp == '_' || *cp == '-'))
13080Sstevel@tonic-gate 			*cp = '_';
13090Sstevel@tonic-gate 	}
13100Sstevel@tonic-gate 
13110Sstevel@tonic-gate 	*cp = '\0';
13120Sstevel@tonic-gate 
13130Sstevel@tonic-gate 	return (out);
13140Sstevel@tonic-gate }
13150Sstevel@tonic-gate 
13160Sstevel@tonic-gate static int
13170Sstevel@tonic-gate lxml_get_tm_manpage(entity_t *service, xmlNodePtr manpage)
13180Sstevel@tonic-gate {
13190Sstevel@tonic-gate 	pgroup_t *pg;
13200Sstevel@tonic-gate 	char *pgname;
13210Sstevel@tonic-gate 	xmlChar *title;
13220Sstevel@tonic-gate 
13230Sstevel@tonic-gate 	/*
13240Sstevel@tonic-gate 	 * Fetch title attribute, convert to something sanitized, and create
13250Sstevel@tonic-gate 	 * property group.
13260Sstevel@tonic-gate 	 */
13270Sstevel@tonic-gate 	title = xmlGetProp(manpage, (xmlChar *)"title");
13280Sstevel@tonic-gate 	pgname = (char *)lxml_label_to_groupname(SCF_PG_TM_MAN_PREFIX,
13290Sstevel@tonic-gate 	    (const char *)title);
13300Sstevel@tonic-gate 
13310Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(service, pgname,
13320Sstevel@tonic-gate 	    (char *)SCF_GROUP_TEMPLATE);
13330Sstevel@tonic-gate 
13340Sstevel@tonic-gate 	/*
13350Sstevel@tonic-gate 	 * Each attribute is an astring property within the group.
13360Sstevel@tonic-gate 	 */
13370Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, "title", SCF_TYPE_ASTRING, manpage,
13380Sstevel@tonic-gate 	    "title") != 0 ||
13390Sstevel@tonic-gate 	    new_str_prop_from_attr(pg, "section", SCF_TYPE_ASTRING, manpage,
13400Sstevel@tonic-gate 	    "section") != 0 ||
13410Sstevel@tonic-gate 	    new_str_prop_from_attr(pg, "manpath", SCF_TYPE_ASTRING, manpage,
13420Sstevel@tonic-gate 	    "manpath") != 0)
13430Sstevel@tonic-gate 		return (-1);
13440Sstevel@tonic-gate 
13450Sstevel@tonic-gate 	return (0);
13460Sstevel@tonic-gate }
13470Sstevel@tonic-gate 
13480Sstevel@tonic-gate static int
13490Sstevel@tonic-gate lxml_get_tm_doclink(entity_t *service, xmlNodePtr doc_link)
13500Sstevel@tonic-gate {
13510Sstevel@tonic-gate 	pgroup_t *pg;
13520Sstevel@tonic-gate 	char *pgname;
13530Sstevel@tonic-gate 	xmlChar *name;
13540Sstevel@tonic-gate 
13550Sstevel@tonic-gate 	/*
13560Sstevel@tonic-gate 	 * Fetch name attribute, convert name to something sanitized, and create
13570Sstevel@tonic-gate 	 * property group.
13580Sstevel@tonic-gate 	 */
13590Sstevel@tonic-gate 	name = xmlGetProp(doc_link, (xmlChar *)"name");
13600Sstevel@tonic-gate 
13610Sstevel@tonic-gate 	pgname = (char *)lxml_label_to_groupname(SCF_PG_TM_DOC_PREFIX,
13620Sstevel@tonic-gate 	    (const char *)name);
13630Sstevel@tonic-gate 
13640Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(service, pgname,
13650Sstevel@tonic-gate 	    (char *)SCF_GROUP_TEMPLATE);
13660Sstevel@tonic-gate 
13670Sstevel@tonic-gate 	/*
13680Sstevel@tonic-gate 	 * Each attribute is an astring property within the group.
13690Sstevel@tonic-gate 	 */
13700Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, "name", SCF_TYPE_ASTRING, doc_link,
13710Sstevel@tonic-gate 	    "name") != 0 ||
13720Sstevel@tonic-gate 	    new_str_prop_from_attr(pg, "uri", SCF_TYPE_ASTRING, doc_link,
13730Sstevel@tonic-gate 	    "uri") != 0)
13740Sstevel@tonic-gate 		return (-1);
13750Sstevel@tonic-gate 
13760Sstevel@tonic-gate 	return (0);
13770Sstevel@tonic-gate }
13780Sstevel@tonic-gate 
13790Sstevel@tonic-gate static int
13800Sstevel@tonic-gate lxml_get_tm_documentation(entity_t *service, xmlNodePtr documentation)
13810Sstevel@tonic-gate {
13820Sstevel@tonic-gate 	xmlNodePtr cursor;
13830Sstevel@tonic-gate 
13840Sstevel@tonic-gate 	for (cursor = documentation->xmlChildrenNode; cursor != NULL;
13850Sstevel@tonic-gate 	    cursor = cursor->next) {
13860Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
13870Sstevel@tonic-gate 			continue;
13880Sstevel@tonic-gate 
13890Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
13900Sstevel@tonic-gate 		case SC_MANPAGE:
13910Sstevel@tonic-gate 			(void) lxml_get_tm_manpage(service, cursor);
13920Sstevel@tonic-gate 			break;
13930Sstevel@tonic-gate 		case SC_DOC_LINK:
13940Sstevel@tonic-gate 			(void) lxml_get_tm_doclink(service, cursor);
13950Sstevel@tonic-gate 			break;
13960Sstevel@tonic-gate 		default:
13970Sstevel@tonic-gate 			uu_die(gettext("illegal element \"%s\" on template "
13980Sstevel@tonic-gate 			    "for service \"%s\"\n"),
13990Sstevel@tonic-gate 			    cursor->name, service->sc_name);
14000Sstevel@tonic-gate 		}
14010Sstevel@tonic-gate 	}
14020Sstevel@tonic-gate 
14030Sstevel@tonic-gate 	return (0);
14040Sstevel@tonic-gate }
14050Sstevel@tonic-gate 
14060Sstevel@tonic-gate static int
14070Sstevel@tonic-gate lxml_get_template(entity_t *service, xmlNodePtr templ)
14080Sstevel@tonic-gate {
14090Sstevel@tonic-gate 	xmlNodePtr cursor;
14100Sstevel@tonic-gate 
14110Sstevel@tonic-gate 	for (cursor = templ->xmlChildrenNode; cursor != NULL;
14120Sstevel@tonic-gate 	    cursor = cursor->next) {
14130Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
14140Sstevel@tonic-gate 			continue;
14150Sstevel@tonic-gate 
14160Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
14170Sstevel@tonic-gate 		case SC_COMMON_NAME:
14180Sstevel@tonic-gate 			(void) lxml_get_tm_common_name(service, cursor);
14190Sstevel@tonic-gate 			break;
14200Sstevel@tonic-gate 		case SC_DESCRIPTION:
14210Sstevel@tonic-gate 			(void) lxml_get_tm_description(service, cursor);
14220Sstevel@tonic-gate 			break;
14230Sstevel@tonic-gate 		case SC_DOCUMENTATION:
14240Sstevel@tonic-gate 			(void) lxml_get_tm_documentation(service, cursor);
14250Sstevel@tonic-gate 			break;
14260Sstevel@tonic-gate 		default:
14270Sstevel@tonic-gate 			uu_die(gettext("illegal element \"%s\" on template "
14280Sstevel@tonic-gate 			    "for service \"%s\"\n"),
14290Sstevel@tonic-gate 			    cursor->name, service->sc_name);
14300Sstevel@tonic-gate 		}
14310Sstevel@tonic-gate 	}
14320Sstevel@tonic-gate 
14330Sstevel@tonic-gate 	return (0);
14340Sstevel@tonic-gate }
14350Sstevel@tonic-gate 
14360Sstevel@tonic-gate static int
14370Sstevel@tonic-gate lxml_get_default_instance(entity_t *service, xmlNodePtr definst)
14380Sstevel@tonic-gate {
14390Sstevel@tonic-gate 	entity_t *i;
14400Sstevel@tonic-gate 	xmlChar *enabled;
14410Sstevel@tonic-gate 	pgroup_t *pg;
14420Sstevel@tonic-gate 	property_t *p;
14430Sstevel@tonic-gate 	char *package;
14440Sstevel@tonic-gate 	uint64_t enabled_val = 0;
14450Sstevel@tonic-gate 
14460Sstevel@tonic-gate 	i = internal_instance_new("default");
14470Sstevel@tonic-gate 
14480Sstevel@tonic-gate 	if ((enabled = xmlGetProp(definst, (xmlChar *)enabled_attr)) != NULL) {
14490Sstevel@tonic-gate 		enabled_val = (strcmp(true, (const char *)enabled) == 0) ?
14500Sstevel@tonic-gate 		    1 : 0;
14510Sstevel@tonic-gate 		xmlFree(enabled);
14520Sstevel@tonic-gate 	}
14530Sstevel@tonic-gate 
14540Sstevel@tonic-gate 	/*
14550Sstevel@tonic-gate 	 * New general property group with enabled boolean property set.
14560Sstevel@tonic-gate 	 */
14570Sstevel@tonic-gate 
14580Sstevel@tonic-gate 	pg = internal_pgroup_new();
14590Sstevel@tonic-gate 	(void) internal_attach_pgroup(i, pg);
14600Sstevel@tonic-gate 
14610Sstevel@tonic-gate 	pg->sc_pgroup_name = (char *)scf_pg_general;
14620Sstevel@tonic-gate 	pg->sc_pgroup_type = (char *)scf_group_framework;
14630Sstevel@tonic-gate 	pg->sc_pgroup_flags = 0;
14640Sstevel@tonic-gate 
14650Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_ENABLED, SCF_TYPE_BOOLEAN, 1,
14660Sstevel@tonic-gate 	    enabled_val);
14670Sstevel@tonic-gate 
14680Sstevel@tonic-gate 	(void) internal_attach_property(pg, p);
14690Sstevel@tonic-gate 
14700Sstevel@tonic-gate 	/*
14710Sstevel@tonic-gate 	 * Add general/package property if PKGINST is set.
14720Sstevel@tonic-gate 	 */
14730Sstevel@tonic-gate 	if ((package = getenv("PKGINST")) != NULL) {
14740Sstevel@tonic-gate 		p = internal_property_create(SCF_PROPERTY_PACKAGE,
14750Sstevel@tonic-gate 		    SCF_TYPE_ASTRING, 1, package);
14760Sstevel@tonic-gate 
14770Sstevel@tonic-gate 		(void) internal_attach_property(pg, p);
14780Sstevel@tonic-gate 	}
14790Sstevel@tonic-gate 
14800Sstevel@tonic-gate 	return (internal_attach_entity(service, i));
14810Sstevel@tonic-gate }
14820Sstevel@tonic-gate 
14830Sstevel@tonic-gate /*
14840Sstevel@tonic-gate  * Translate an instance element into an internal property tree, added to
14850Sstevel@tonic-gate  * service.  If apply is true, forbid subelements and set the enabled property
14860Sstevel@tonic-gate  * to override.
14870Sstevel@tonic-gate  */
14880Sstevel@tonic-gate static int
14890Sstevel@tonic-gate lxml_get_instance(entity_t *service, xmlNodePtr inst, int apply)
14900Sstevel@tonic-gate {
14910Sstevel@tonic-gate 	entity_t *i;
14920Sstevel@tonic-gate 	pgroup_t *pg;
14930Sstevel@tonic-gate 	property_t *p;
14940Sstevel@tonic-gate 	xmlNodePtr cursor;
14950Sstevel@tonic-gate 	xmlChar *enabled;
14960Sstevel@tonic-gate 	int r;
14970Sstevel@tonic-gate 
14980Sstevel@tonic-gate 	/*
14990Sstevel@tonic-gate 	 * Fetch its attributes, as appropriate.
15000Sstevel@tonic-gate 	 */
15010Sstevel@tonic-gate 	i = internal_instance_new((char *)xmlGetProp(inst,
15020Sstevel@tonic-gate 	    (xmlChar *)name_attr));
15030Sstevel@tonic-gate 
15040Sstevel@tonic-gate 	/*
15050Sstevel@tonic-gate 	 * Note that this must be done before walking the children so that
15060Sstevel@tonic-gate 	 * sc_fmri is set in case we enter lxml_get_dependent().
15070Sstevel@tonic-gate 	 */
15080Sstevel@tonic-gate 	r = internal_attach_entity(service, i);
15090Sstevel@tonic-gate 	if (r != 0)
15100Sstevel@tonic-gate 		return (r);
15110Sstevel@tonic-gate 
15120Sstevel@tonic-gate 	enabled = xmlGetProp(inst, (xmlChar *)enabled_attr);
15130Sstevel@tonic-gate 
15140Sstevel@tonic-gate 	/*
15150Sstevel@tonic-gate 	 * New general property group with enabled boolean property set.
15160Sstevel@tonic-gate 	 */
15170Sstevel@tonic-gate 	pg = internal_pgroup_new();
15180Sstevel@tonic-gate 	(void) internal_attach_pgroup(i, pg);
15190Sstevel@tonic-gate 
15200Sstevel@tonic-gate 	pg->sc_pgroup_name = (char *)scf_pg_general;
15210Sstevel@tonic-gate 	pg->sc_pgroup_type = (char *)scf_group_framework;
15220Sstevel@tonic-gate 	pg->sc_pgroup_flags = 0;
15230Sstevel@tonic-gate 
15240Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_ENABLED, SCF_TYPE_BOOLEAN, 1,
15250Sstevel@tonic-gate 	    (uint64_t)(strcmp(true, (const char *)enabled) == 0 ? 1 : 0));
15260Sstevel@tonic-gate 
15270Sstevel@tonic-gate 	p->sc_property_override = apply;
15280Sstevel@tonic-gate 
15290Sstevel@tonic-gate 	(void) internal_attach_property(pg, p);
15300Sstevel@tonic-gate 
15310Sstevel@tonic-gate 	xmlFree(enabled);
15320Sstevel@tonic-gate 
15330Sstevel@tonic-gate 	/*
15340Sstevel@tonic-gate 	 * Walk its child elements, as appropriate.
15350Sstevel@tonic-gate 	 */
15360Sstevel@tonic-gate 	for (cursor = inst->xmlChildrenNode; cursor != NULL;
15370Sstevel@tonic-gate 	    cursor = cursor->next) {
15380Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
15390Sstevel@tonic-gate 			continue;
15400Sstevel@tonic-gate 
15410Sstevel@tonic-gate 		if (apply) {
15420Sstevel@tonic-gate 			semerr(gettext("Instance \"%s\" may not contain "
15430Sstevel@tonic-gate 			    "elements in profiles.\n"), i->sc_name,
15440Sstevel@tonic-gate 			    cursor->name);
15450Sstevel@tonic-gate 			return (-1);
15460Sstevel@tonic-gate 		}
15470Sstevel@tonic-gate 
15480Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
15490Sstevel@tonic-gate 		case SC_RESTARTER:
15500Sstevel@tonic-gate 			(void) lxml_get_restarter(i, cursor);
15510Sstevel@tonic-gate 			break;
15520Sstevel@tonic-gate 		case SC_DEPENDENCY:
15530Sstevel@tonic-gate 			(void) lxml_get_dependency(i, cursor);
15540Sstevel@tonic-gate 			break;
15550Sstevel@tonic-gate 		case SC_DEPENDENT:
15560Sstevel@tonic-gate 			(void) lxml_get_dependent(i, cursor);
15570Sstevel@tonic-gate 			break;
15580Sstevel@tonic-gate 		case SC_METHOD_CONTEXT:
15590Sstevel@tonic-gate 			(void) lxml_get_entity_method_context(i, cursor);
15600Sstevel@tonic-gate 			break;
15610Sstevel@tonic-gate 		case SC_EXEC_METHOD:
15620Sstevel@tonic-gate 			(void) lxml_get_exec_method(i, cursor);
15630Sstevel@tonic-gate 			break;
15640Sstevel@tonic-gate 		case SC_PROPERTY_GROUP:
15650Sstevel@tonic-gate 			(void) lxml_get_pgroup(i, cursor);
15660Sstevel@tonic-gate 			break;
15670Sstevel@tonic-gate 		case SC_TEMPLATE:
15680Sstevel@tonic-gate 			(void) lxml_get_template(i, cursor);
15690Sstevel@tonic-gate 			break;
15700Sstevel@tonic-gate 		default:
15710Sstevel@tonic-gate 			uu_die(gettext(
15720Sstevel@tonic-gate 			    "illegal element \"%s\" on instance \"%s\"\n"),
15730Sstevel@tonic-gate 			    cursor->name, i->sc_name);
15740Sstevel@tonic-gate 			break;
15750Sstevel@tonic-gate 		}
15760Sstevel@tonic-gate 	}
15770Sstevel@tonic-gate 
15780Sstevel@tonic-gate 	return (0);
15790Sstevel@tonic-gate }
15800Sstevel@tonic-gate 
15810Sstevel@tonic-gate /* ARGSUSED1 */
15820Sstevel@tonic-gate static int
15830Sstevel@tonic-gate lxml_get_single_instance(entity_t *entity, xmlNodePtr si)
15840Sstevel@tonic-gate {
15850Sstevel@tonic-gate 	pgroup_t *pg;
15860Sstevel@tonic-gate 	property_t *p;
15870Sstevel@tonic-gate 	int r;
15880Sstevel@tonic-gate 
15890Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(entity, (char *)scf_pg_general,
15900Sstevel@tonic-gate 	    (char *)scf_group_framework);
15910Sstevel@tonic-gate 
15920Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_SINGLE_INSTANCE,
15930Sstevel@tonic-gate 	    SCF_TYPE_BOOLEAN, 1, (uint64_t)1);
15940Sstevel@tonic-gate 
15950Sstevel@tonic-gate 	r = internal_attach_property(pg, p);
15960Sstevel@tonic-gate 	if (r != 0) {
15970Sstevel@tonic-gate 		internal_property_free(p);
15980Sstevel@tonic-gate 		return (-1);
15990Sstevel@tonic-gate 	}
16000Sstevel@tonic-gate 
16010Sstevel@tonic-gate 	return (0);
16020Sstevel@tonic-gate }
16030Sstevel@tonic-gate 
16040Sstevel@tonic-gate /*
16050Sstevel@tonic-gate  * Translate a service element into an internal instance/property tree, added
16060Sstevel@tonic-gate  * to bundle.  If apply is true, allow only instance subelements.
16070Sstevel@tonic-gate  */
16080Sstevel@tonic-gate static int
16090Sstevel@tonic-gate lxml_get_service(bundle_t *bundle, xmlNodePtr svc, int apply)
16100Sstevel@tonic-gate {
16110Sstevel@tonic-gate 	entity_t *s;
16120Sstevel@tonic-gate 	xmlNodePtr cursor;
16130Sstevel@tonic-gate 	xmlChar *type;
16140Sstevel@tonic-gate 	xmlChar *version;
16150Sstevel@tonic-gate 	int e;
16160Sstevel@tonic-gate 
16170Sstevel@tonic-gate 	/*
16180Sstevel@tonic-gate 	 * Fetch attributes, as appropriate.
16190Sstevel@tonic-gate 	 */
16200Sstevel@tonic-gate 	s = internal_service_new((char *)xmlGetProp(svc,
16210Sstevel@tonic-gate 	    (xmlChar *)name_attr));
16220Sstevel@tonic-gate 
16230Sstevel@tonic-gate 	version = xmlGetProp(svc, (xmlChar *)"version");
16240Sstevel@tonic-gate 	s->sc_u.sc_service.sc_service_version = atol((const char *)version);
16250Sstevel@tonic-gate 	xmlFree(version);
16260Sstevel@tonic-gate 
16270Sstevel@tonic-gate 	type = xmlGetProp(svc, (xmlChar *)type_attr);
16280Sstevel@tonic-gate 	s->sc_u.sc_service.sc_service_type = lxml_xlate_service_type(type);
16290Sstevel@tonic-gate 	xmlFree(type);
16300Sstevel@tonic-gate 
16310Sstevel@tonic-gate 	/*
16320Sstevel@tonic-gate 	 * Walk its child elements, as appropriate.
16330Sstevel@tonic-gate 	 */
16340Sstevel@tonic-gate 	for (cursor = svc->xmlChildrenNode; cursor != NULL;
16350Sstevel@tonic-gate 	    cursor = cursor->next) {
16360Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
16370Sstevel@tonic-gate 			continue;
16380Sstevel@tonic-gate 
16390Sstevel@tonic-gate 		e = lxml_xlate_element(cursor->name);
16400Sstevel@tonic-gate 
16410Sstevel@tonic-gate 		if (apply && e != SC_INSTANCE) {
16420Sstevel@tonic-gate 			semerr(gettext("Service \"%s\" may not contain the "
16430Sstevel@tonic-gate 			    "non-instance element \"%s\" in a profile.\n"),
16440Sstevel@tonic-gate 			    s->sc_name, cursor->name);
16450Sstevel@tonic-gate 
16460Sstevel@tonic-gate 			return (-1);
16470Sstevel@tonic-gate 		}
16480Sstevel@tonic-gate 
16490Sstevel@tonic-gate 		switch (e) {
16500Sstevel@tonic-gate 		case SC_INSTANCE:
16510Sstevel@tonic-gate 			(void) lxml_get_instance(s, cursor, apply);
16520Sstevel@tonic-gate 			break;
16530Sstevel@tonic-gate 		case SC_TEMPLATE:
16540Sstevel@tonic-gate 			(void) lxml_get_template(s, cursor);
16550Sstevel@tonic-gate 			break;
16560Sstevel@tonic-gate 		case SC_STABILITY:
16570Sstevel@tonic-gate 			(void) lxml_get_entity_stability(s, cursor);
16580Sstevel@tonic-gate 			break;
16590Sstevel@tonic-gate 		case SC_DEPENDENCY:
16600Sstevel@tonic-gate 			(void) lxml_get_dependency(s, cursor);
16610Sstevel@tonic-gate 			break;
16620Sstevel@tonic-gate 		case SC_DEPENDENT:
16630Sstevel@tonic-gate 			(void) lxml_get_dependent(s, cursor);
16640Sstevel@tonic-gate 			break;
16650Sstevel@tonic-gate 		case SC_RESTARTER:
16660Sstevel@tonic-gate 			(void) lxml_get_restarter(s, cursor);
16670Sstevel@tonic-gate 			break;
16680Sstevel@tonic-gate 		case SC_EXEC_METHOD:
16690Sstevel@tonic-gate 			(void) lxml_get_exec_method(s, cursor);
16700Sstevel@tonic-gate 			break;
16710Sstevel@tonic-gate 		case SC_METHOD_CONTEXT:
16720Sstevel@tonic-gate 			(void) lxml_get_entity_method_context(s, cursor);
16730Sstevel@tonic-gate 			break;
16740Sstevel@tonic-gate 		case SC_PROPERTY_GROUP:
16750Sstevel@tonic-gate 			(void) lxml_get_pgroup(s, cursor);
16760Sstevel@tonic-gate 			break;
16770Sstevel@tonic-gate 		case SC_INSTANCE_CREATE_DEFAULT:
16780Sstevel@tonic-gate 			(void) lxml_get_default_instance(s, cursor);
16790Sstevel@tonic-gate 			break;
16800Sstevel@tonic-gate 		case SC_INSTANCE_SINGLE:
16810Sstevel@tonic-gate 			(void) lxml_get_single_instance(s, cursor);
16820Sstevel@tonic-gate 			break;
16830Sstevel@tonic-gate 		default:
16840Sstevel@tonic-gate 			uu_die(gettext(
16850Sstevel@tonic-gate 			    "illegal element \"%s\" on service \"%s\"\n"),
16860Sstevel@tonic-gate 			    cursor->name, s->sc_name);
16870Sstevel@tonic-gate 			break;
16880Sstevel@tonic-gate 		}
16890Sstevel@tonic-gate 	}
16900Sstevel@tonic-gate 
16910Sstevel@tonic-gate 	return (internal_attach_service(bundle, s));
16920Sstevel@tonic-gate }
16930Sstevel@tonic-gate 
16940Sstevel@tonic-gate #ifdef DEBUG
16950Sstevel@tonic-gate void
16960Sstevel@tonic-gate lxml_dump(int g, xmlNodePtr p)
16970Sstevel@tonic-gate {
16980Sstevel@tonic-gate 	if (p && p->name) {
16990Sstevel@tonic-gate 		printf("%d %s\n", g, p->name);
17000Sstevel@tonic-gate 
17010Sstevel@tonic-gate 		for (p = p->xmlChildrenNode; p != NULL; p = p->next)
17020Sstevel@tonic-gate 			lxml_dump(g + 1, p);
17030Sstevel@tonic-gate 	}
17040Sstevel@tonic-gate }
17050Sstevel@tonic-gate #endif /* DEBUG */
17060Sstevel@tonic-gate 
17070Sstevel@tonic-gate static int
17080Sstevel@tonic-gate lxml_is_known_dtd(const xmlChar *dtdname)
17090Sstevel@tonic-gate {
17100Sstevel@tonic-gate 	if (dtdname == NULL ||
17110Sstevel@tonic-gate 	    strcmp(MANIFEST_DTD_PATH, (const char *)dtdname) != 0)
17120Sstevel@tonic-gate 		return (0);
17130Sstevel@tonic-gate 
17140Sstevel@tonic-gate 	return (1);
17150Sstevel@tonic-gate }
17160Sstevel@tonic-gate 
17170Sstevel@tonic-gate static int
17180Sstevel@tonic-gate lxml_get_bundle(bundle_t *bundle, bundle_type_t bundle_type,
17190Sstevel@tonic-gate     xmlNodePtr subbundle, int apply)
17200Sstevel@tonic-gate {
17210Sstevel@tonic-gate 	xmlNodePtr cursor;
17220Sstevel@tonic-gate 	xmlChar *type;
17230Sstevel@tonic-gate 	int e;
17240Sstevel@tonic-gate 
17250Sstevel@tonic-gate 	/*
17260Sstevel@tonic-gate 	 * 1.  Get bundle attributes.
17270Sstevel@tonic-gate 	 */
17280Sstevel@tonic-gate 	type = xmlGetProp(subbundle, (xmlChar *)"type");
17290Sstevel@tonic-gate 	bundle->sc_bundle_type = lxml_xlate_bundle_type(type);
17300Sstevel@tonic-gate 	if (bundle->sc_bundle_type != bundle_type &&
17310Sstevel@tonic-gate 	    bundle_type != SVCCFG_UNKNOWN_BUNDLE) {
17320Sstevel@tonic-gate 		semerr(gettext("included bundle of different type.\n"));
17330Sstevel@tonic-gate 		return (-1);
17340Sstevel@tonic-gate 	}
17350Sstevel@tonic-gate 
17360Sstevel@tonic-gate 	xmlFree(type);
17370Sstevel@tonic-gate 
17380Sstevel@tonic-gate 	if (!apply) {
17390Sstevel@tonic-gate 		if (bundle->sc_bundle_type != SVCCFG_MANIFEST) {
17400Sstevel@tonic-gate 			semerr(gettext("document is not a manifest.\n"));
17410Sstevel@tonic-gate 			return (-1);
17420Sstevel@tonic-gate 		}
17430Sstevel@tonic-gate 	} else {
17440Sstevel@tonic-gate 		if (bundle->sc_bundle_type != SVCCFG_PROFILE) {
17450Sstevel@tonic-gate 			semerr(gettext("document is not a profile.\n"));
17460Sstevel@tonic-gate 			return (-1);
17470Sstevel@tonic-gate 		}
17480Sstevel@tonic-gate 	}
17490Sstevel@tonic-gate 
17500Sstevel@tonic-gate 	if ((bundle->sc_bundle_name = xmlGetProp(subbundle,
17510Sstevel@tonic-gate 	    (xmlChar *)"name")) == NULL) {
17520Sstevel@tonic-gate 		semerr(gettext("service bundle lacks name attribute\n"));
17530Sstevel@tonic-gate 		return (-1);
17540Sstevel@tonic-gate 	}
17550Sstevel@tonic-gate 
17560Sstevel@tonic-gate 	/*
17570Sstevel@tonic-gate 	 * 2.  Get services, descend into each one and build state.
17580Sstevel@tonic-gate 	 */
17590Sstevel@tonic-gate 	for (cursor = subbundle->xmlChildrenNode; cursor != NULL;
17600Sstevel@tonic-gate 	    cursor = cursor->next) {
17610Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
17620Sstevel@tonic-gate 			continue;
17630Sstevel@tonic-gate 
17640Sstevel@tonic-gate 		e = lxml_xlate_element(cursor->name);
17650Sstevel@tonic-gate 
17660Sstevel@tonic-gate 		switch (e) {
17670Sstevel@tonic-gate 		case SC_XI_INCLUDE:
17680Sstevel@tonic-gate 			continue;
17690Sstevel@tonic-gate 
17700Sstevel@tonic-gate 		case SC_SERVICE_BUNDLE:
17710Sstevel@tonic-gate 			if (lxml_get_bundle(bundle, bundle_type, cursor, apply))
17720Sstevel@tonic-gate 				return (-1);
17730Sstevel@tonic-gate 			break;
17740Sstevel@tonic-gate 		case SC_SERVICE:
17750Sstevel@tonic-gate 			(void) lxml_get_service(bundle, cursor, apply);
17760Sstevel@tonic-gate 			break;
17770Sstevel@tonic-gate 		}
17780Sstevel@tonic-gate 	}
17790Sstevel@tonic-gate 
17800Sstevel@tonic-gate 	return (0);
17810Sstevel@tonic-gate }
17820Sstevel@tonic-gate 
17830Sstevel@tonic-gate /*
17840Sstevel@tonic-gate  * Load an XML tree from filename and translate it into an internal service
17850Sstevel@tonic-gate  * tree bundle.  If apply is false, require that the the bundle be of type
17860Sstevel@tonic-gate  * manifest, or type profile otherwise.
17870Sstevel@tonic-gate  */
17880Sstevel@tonic-gate int
17890Sstevel@tonic-gate lxml_get_bundle_file(bundle_t *bundle, const char *filename, int apply)
17900Sstevel@tonic-gate {
17910Sstevel@tonic-gate 	xmlDocPtr document;
17920Sstevel@tonic-gate 	xmlNodePtr cursor;
17930Sstevel@tonic-gate 	xmlDtdPtr dtd = NULL;
17940Sstevel@tonic-gate 	xmlValidCtxtPtr vcp;
17950Sstevel@tonic-gate 	boolean_t do_validate;
17960Sstevel@tonic-gate 	char *dtdpath = NULL;
17970Sstevel@tonic-gate 	int r;
17980Sstevel@tonic-gate 
17990Sstevel@tonic-gate 	/*
18000Sstevel@tonic-gate 	 * Until libxml2 addresses DTD-based validation with XInclude, we don't
18010Sstevel@tonic-gate 	 * validate service profiles (i.e. the apply path).
18020Sstevel@tonic-gate 	 */
18030Sstevel@tonic-gate 	do_validate = (apply == 0) && (getenv("SVCCFG_NOVALIDATE") == NULL);
18040Sstevel@tonic-gate 	if (do_validate)
18050Sstevel@tonic-gate 		dtdpath = getenv("SVCCFG_DTD");
18060Sstevel@tonic-gate 
18070Sstevel@tonic-gate 	if (dtdpath != NULL)
18080Sstevel@tonic-gate 		xmlLoadExtDtdDefaultValue = 0;
18090Sstevel@tonic-gate 
18100Sstevel@tonic-gate 	if ((document = xmlReadFile(filename, NULL,
18110Sstevel@tonic-gate 	    XML_PARSE_NOERROR | XML_PARSE_NOWARNING)) == NULL) {
18120Sstevel@tonic-gate 		semerr(gettext("couldn't parse document\n"));
18130Sstevel@tonic-gate 		return (-1);
18140Sstevel@tonic-gate 	}
18150Sstevel@tonic-gate 
18160Sstevel@tonic-gate 	/*
18170Sstevel@tonic-gate 	 * Verify that this is a document type we understand.
18180Sstevel@tonic-gate 	 */
18190Sstevel@tonic-gate 	if ((dtd = xmlGetIntSubset(document)) == NULL) {
18200Sstevel@tonic-gate 		semerr(gettext("document has no DTD\n"));
18210Sstevel@tonic-gate 		return (-1);
18220Sstevel@tonic-gate 	}
18230Sstevel@tonic-gate 
18240Sstevel@tonic-gate 	if (!lxml_is_known_dtd(dtd->SystemID)) {
18250Sstevel@tonic-gate 		semerr(gettext("document DTD unknown; not service bundle?\n"));
18260Sstevel@tonic-gate 		return (-1);
18270Sstevel@tonic-gate 	}
18280Sstevel@tonic-gate 
18290Sstevel@tonic-gate 	if ((cursor = xmlDocGetRootElement(document)) == NULL) {
18300Sstevel@tonic-gate 		semerr(gettext("document is empty\n"));
18310Sstevel@tonic-gate 		xmlFreeDoc(document);
18320Sstevel@tonic-gate 		return (-1);
18330Sstevel@tonic-gate 	}
18340Sstevel@tonic-gate 
18350Sstevel@tonic-gate 	if (xmlStrcmp(cursor->name, (const xmlChar *)"service_bundle") != 0) {
18360Sstevel@tonic-gate 		semerr(gettext("document is not a service bundle\n"));
18370Sstevel@tonic-gate 		xmlFreeDoc(document);
18380Sstevel@tonic-gate 		return (-1);
18390Sstevel@tonic-gate 	}
18400Sstevel@tonic-gate 
18410Sstevel@tonic-gate 
18420Sstevel@tonic-gate 	if (dtdpath != NULL) {
18430Sstevel@tonic-gate 		dtd = xmlParseDTD(NULL, (xmlChar *)dtdpath);
18440Sstevel@tonic-gate 		if (dtd == NULL) {
18450Sstevel@tonic-gate 			semerr(gettext("Could not parse DTD \"%s\".\n"),
18460Sstevel@tonic-gate 			    dtdpath);
18470Sstevel@tonic-gate 			return (-1);
18480Sstevel@tonic-gate 		}
18490Sstevel@tonic-gate 
18500Sstevel@tonic-gate 		if (document->extSubset != NULL)
18510Sstevel@tonic-gate 			xmlFreeDtd(document->extSubset);
18520Sstevel@tonic-gate 
18530Sstevel@tonic-gate 		document->extSubset = dtd;
18540Sstevel@tonic-gate 	}
18550Sstevel@tonic-gate 
18560Sstevel@tonic-gate 	if (xmlXIncludeProcessFlags(document, XML_PARSE_XINCLUDE) == -1) {;
18570Sstevel@tonic-gate 		semerr(gettext("couldn't handle XInclude statements "
18580Sstevel@tonic-gate 			"in document\n"));
18590Sstevel@tonic-gate 		return (-1);
18600Sstevel@tonic-gate 	}
18610Sstevel@tonic-gate 
18620Sstevel@tonic-gate 	if (do_validate) {
18630Sstevel@tonic-gate 		vcp = xmlNewValidCtxt();
18640Sstevel@tonic-gate 		if (vcp == NULL)
18650Sstevel@tonic-gate 			uu_die(gettext("could not allocate memory"));
18660Sstevel@tonic-gate 		vcp->warning = xmlParserValidityWarning;
18670Sstevel@tonic-gate 		vcp->error = xmlParserValidityError;
18680Sstevel@tonic-gate 
18690Sstevel@tonic-gate 		r = xmlValidateDocument(vcp, document);
18700Sstevel@tonic-gate 
18710Sstevel@tonic-gate 		xmlFreeValidCtxt(vcp);
18720Sstevel@tonic-gate 
18730Sstevel@tonic-gate 		if (r == 0) {
18740Sstevel@tonic-gate 			semerr(gettext("Document is not valid.\n"));
18750Sstevel@tonic-gate 			xmlFreeDoc(document);
18760Sstevel@tonic-gate 			return (-1);
18770Sstevel@tonic-gate 		}
18780Sstevel@tonic-gate 	}
18790Sstevel@tonic-gate 
18800Sstevel@tonic-gate 
18810Sstevel@tonic-gate #ifdef DEBUG
18820Sstevel@tonic-gate 	lxml_dump(0, cursor);
18830Sstevel@tonic-gate #endif /* DEBUG */
18840Sstevel@tonic-gate 
18850Sstevel@tonic-gate 	r = lxml_get_bundle(bundle, SVCCFG_UNKNOWN_BUNDLE, cursor, apply);
18860Sstevel@tonic-gate 
18870Sstevel@tonic-gate 	xmlFreeDoc(document);
18880Sstevel@tonic-gate 
18890Sstevel@tonic-gate 	return (r);
18900Sstevel@tonic-gate }
18910Sstevel@tonic-gate 
18920Sstevel@tonic-gate int
18930Sstevel@tonic-gate lxml_inventory(const char *filename)
18940Sstevel@tonic-gate {
18950Sstevel@tonic-gate 	bundle_t *b;
18960Sstevel@tonic-gate 	uu_list_walk_t *svcs, *insts;
18970Sstevel@tonic-gate 	entity_t *svc, *inst;
18980Sstevel@tonic-gate 
18990Sstevel@tonic-gate 	b = internal_bundle_new();
19000Sstevel@tonic-gate 
19010Sstevel@tonic-gate 	if (lxml_get_bundle_file(b, filename, 0) != 0) {
19020Sstevel@tonic-gate 		internal_bundle_free(b);
19030Sstevel@tonic-gate 		return (-1);
19040Sstevel@tonic-gate 	}
19050Sstevel@tonic-gate 
19060Sstevel@tonic-gate 	svcs = uu_list_walk_start(b->sc_bundle_services, 0);
19070Sstevel@tonic-gate 	if (svcs == NULL)
19080Sstevel@tonic-gate 		uu_die(gettext("Couldn't walk services"));
19090Sstevel@tonic-gate 
19100Sstevel@tonic-gate 	while ((svc = uu_list_walk_next(svcs)) != NULL) {
19110Sstevel@tonic-gate 		uu_list_t *inst_list;
19120Sstevel@tonic-gate 
19130Sstevel@tonic-gate 		inst_list = svc->sc_u.sc_service.sc_service_instances;
19140Sstevel@tonic-gate 		insts = uu_list_walk_start(inst_list, 0);
19150Sstevel@tonic-gate 		if (insts == NULL)
19160Sstevel@tonic-gate 			uu_die(gettext("Couldn't walk instances"));
19170Sstevel@tonic-gate 
19180Sstevel@tonic-gate 		while ((inst = uu_list_walk_next(insts)) != NULL)
19190Sstevel@tonic-gate 			(void) printf("svc:/%s:%s\n", svc->sc_name,
19200Sstevel@tonic-gate 			    inst->sc_name);
19210Sstevel@tonic-gate 
19220Sstevel@tonic-gate 		uu_list_walk_end(insts);
19230Sstevel@tonic-gate 	}
19240Sstevel@tonic-gate 
19250Sstevel@tonic-gate 	uu_list_walk_end(svcs);
19260Sstevel@tonic-gate 
19270Sstevel@tonic-gate 	svcs = uu_list_walk_start(b->sc_bundle_services, 0);
19280Sstevel@tonic-gate 	while ((svc = uu_list_walk_next(svcs)) != NULL) {
19290Sstevel@tonic-gate 		(void) fputs("svc:/", stdout);
19300Sstevel@tonic-gate 		(void) puts(svc->sc_name);
19310Sstevel@tonic-gate 	}
19320Sstevel@tonic-gate 	uu_list_walk_end(svcs);
19330Sstevel@tonic-gate 
19340Sstevel@tonic-gate 	internal_bundle_free(b);
19350Sstevel@tonic-gate 
19360Sstevel@tonic-gate 	return (0);
19370Sstevel@tonic-gate }
1938