xref: /onnv-gate/usr/src/cmd/svc/svccfg/svccfg_xml.c (revision 12667:62bc4887874f)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
54740Sjeanm  * Common Development and Distribution License (the "License").
64740Sjeanm  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
2212172SSean.Wilcox@Sun.COM  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate  */
240Sstevel@tonic-gate 
257887SLiane.Praza@Sun.COM /*
267887SLiane.Praza@Sun.COM  * XML document manipulation routines
277887SLiane.Praza@Sun.COM  *
287887SLiane.Praza@Sun.COM  * These routines provide translation to and from the internal representation to
297887SLiane.Praza@Sun.COM  * XML.  Directionally-oriented verbs are with respect to the external source,
307887SLiane.Praza@Sun.COM  * so lxml_get_service() fetches a service from the XML file into the
317887SLiane.Praza@Sun.COM  * internal representation.
327887SLiane.Praza@Sun.COM  */
330Sstevel@tonic-gate 
340Sstevel@tonic-gate #include <libxml/parser.h>
350Sstevel@tonic-gate #include <libxml/xinclude.h>
360Sstevel@tonic-gate 
370Sstevel@tonic-gate #include <assert.h>
380Sstevel@tonic-gate #include <ctype.h>
390Sstevel@tonic-gate #include <errno.h>
400Sstevel@tonic-gate #include <libintl.h>
417887SLiane.Praza@Sun.COM #include <libscf.h>
427887SLiane.Praza@Sun.COM #include <libscf_priv.h>
430Sstevel@tonic-gate #include <libuutil.h>
447887SLiane.Praza@Sun.COM #include <sasl/saslutil.h>
450Sstevel@tonic-gate #include <stdlib.h>
460Sstevel@tonic-gate #include <string.h>
4712172SSean.Wilcox@Sun.COM #include <limits.h>
480Sstevel@tonic-gate 
494740Sjeanm #include <sys/types.h>
504740Sjeanm #include <sys/stat.h>
514740Sjeanm #include <unistd.h>
524740Sjeanm 
5310461SSean.Wilcox@Sun.COM #include <sys/param.h>
5410461SSean.Wilcox@Sun.COM #include "manifest_hash.h"
5510461SSean.Wilcox@Sun.COM 
560Sstevel@tonic-gate #include "svccfg.h"
570Sstevel@tonic-gate 
580Sstevel@tonic-gate /*
597887SLiane.Praza@Sun.COM  * snprintf(3C) format strings for constructing property names that include
607887SLiane.Praza@Sun.COM  * the locale designation.  Use %s to indicate where the locale should go.
610Sstevel@tonic-gate  *
627887SLiane.Praza@Sun.COM  * The VALUE_* symbols are an exception.  The firs %s will be replaced with
637887SLiane.Praza@Sun.COM  * "value_".  The second %s will be replaced by the name of the value and
647887SLiane.Praza@Sun.COM  * %%s will be replaced by the locale designation.  These formats are
657887SLiane.Praza@Sun.COM  * processed twice by snprintf(3C).  The first time captures the value name
667887SLiane.Praza@Sun.COM  * and the second time captures the locale.
670Sstevel@tonic-gate  */
687887SLiane.Praza@Sun.COM #define	LOCALE_ONLY_FMT		("%s")
697887SLiane.Praza@Sun.COM #define	COMMON_NAME_FMT		("common_name_%s")
707887SLiane.Praza@Sun.COM #define	DESCRIPTION_FMT		("description_%s")
717887SLiane.Praza@Sun.COM #define	UNITS_FMT		("units_%s")
727887SLiane.Praza@Sun.COM #define	VALUE_COMMON_NAME_FMT	("%s%s_common_name_%%s")
737887SLiane.Praza@Sun.COM #define	VALUE_DESCRIPTION_FMT	("%s%s_description_%%s")
747887SLiane.Praza@Sun.COM 
757887SLiane.Praza@Sun.COM /* Attribute names */
760Sstevel@tonic-gate const char * const delete_attr = "delete";
770Sstevel@tonic-gate const char * const enabled_attr = "enabled";
787887SLiane.Praza@Sun.COM const char * const lang_attr = "lang";
797887SLiane.Praza@Sun.COM const char * const manpath_attr = "manpath";
807887SLiane.Praza@Sun.COM const char * const max_attr = "max";
817887SLiane.Praza@Sun.COM const char * const min_attr = "min";
820Sstevel@tonic-gate const char * const name_attr = "name";
830Sstevel@tonic-gate const char * const override_attr = "override";
847887SLiane.Praza@Sun.COM const char * const required_attr = "required";
857887SLiane.Praza@Sun.COM const char * const section_attr = "section";
867887SLiane.Praza@Sun.COM const char * const set_attr = "set";
877887SLiane.Praza@Sun.COM const char * const target_attr = "target";
887887SLiane.Praza@Sun.COM const char * const timeout_seconds_attr = "timeout_seconds";
897887SLiane.Praza@Sun.COM const char * const title_attr = "title";
900Sstevel@tonic-gate const char * const type_attr = "type";
917887SLiane.Praza@Sun.COM const char * const uri_attr = "uri";
920Sstevel@tonic-gate const char * const value_attr = "value";
937887SLiane.Praza@Sun.COM const char * const version_attr = "version";
947887SLiane.Praza@Sun.COM const char * const xml_lang_attr = "xml:lang";
957887SLiane.Praza@Sun.COM 
967887SLiane.Praza@Sun.COM /* Attribute values */
977887SLiane.Praza@Sun.COM const char * const all_value = "all";
987887SLiane.Praza@Sun.COM 
990Sstevel@tonic-gate const char * const true = "true";
1000Sstevel@tonic-gate const char * const false = "false";
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate /*
1030Sstevel@tonic-gate  * The following list must be kept in the same order as that of
1040Sstevel@tonic-gate  * element_t array
1050Sstevel@tonic-gate  */
1060Sstevel@tonic-gate static const char *lxml_elements[] = {
1070Sstevel@tonic-gate 	"astring_list",			/* SC_ASTRING */
1080Sstevel@tonic-gate 	"boolean_list",			/* SC_BOOLEAN */
1097887SLiane.Praza@Sun.COM 	"cardinality",			/* SC_CARDINALITY */
1107887SLiane.Praza@Sun.COM 	"choices",			/* SC_CHOICES */
1110Sstevel@tonic-gate 	"common_name",			/* SC_COMMON_NAME */
1127887SLiane.Praza@Sun.COM 	"constraints",			/* SC_CONSTRAINTS */
1130Sstevel@tonic-gate 	"count_list",			/* SC_COUNT */
1140Sstevel@tonic-gate 	"create_default_instance",	/* SC_INSTANCE_CREATE_DEFAULT */
1150Sstevel@tonic-gate 	"dependency",			/* SC_DEPENDENCY */
1160Sstevel@tonic-gate 	"dependent",			/* SC_DEPENDENT */
1170Sstevel@tonic-gate 	"description",			/* SC_DESCRIPTION */
1180Sstevel@tonic-gate 	"doc_link",			/* SC_DOC_LINK */
1190Sstevel@tonic-gate 	"documentation",		/* SC_DOCUMENTATION */
1200Sstevel@tonic-gate 	"enabled",			/* SC_ENABLED */
1210Sstevel@tonic-gate 	"exec_method",			/* SC_EXEC_METHOD */
1220Sstevel@tonic-gate 	"fmri_list",			/* SC_FMRI */
1230Sstevel@tonic-gate 	"host_list",			/* SC_HOST */
1240Sstevel@tonic-gate 	"hostname_list",		/* SC_HOSTNAME */
1257887SLiane.Praza@Sun.COM 	"include_values",		/* SC_INCLUDE_VALUES */
1260Sstevel@tonic-gate 	"instance",			/* SC_INSTANCE */
1270Sstevel@tonic-gate 	"integer_list",			/* SC_INTEGER */
1287887SLiane.Praza@Sun.COM 	"internal_separators",		/* SC_INTERNAL_SEPARATORS */
1290Sstevel@tonic-gate 	"loctext",			/* SC_LOCTEXT */
1300Sstevel@tonic-gate 	"manpage",			/* SC_MANPAGE */
1310Sstevel@tonic-gate 	"method_context",		/* SC_METHOD_CONTEXT */
1320Sstevel@tonic-gate 	"method_credential",		/* SC_METHOD_CREDENTIAL */
1330Sstevel@tonic-gate 	"method_profile",		/* SC_METHOD_PROFILE */
1340Sstevel@tonic-gate 	"method_environment",		/* SC_METHOD_ENVIRONMENT */
1350Sstevel@tonic-gate 	"envvar",			/* SC_METHOD_ENVVAR */
1360Sstevel@tonic-gate 	"net_address_v4_list",		/* SC_NET_ADDR_V4 */
1370Sstevel@tonic-gate 	"net_address_v6_list",		/* SC_NET_ADDR_V6 */
1380Sstevel@tonic-gate 	"opaque_list",			/* SC_OPAQUE */
1397887SLiane.Praza@Sun.COM 	"pg_pattern",			/* SC_PG_PATTERN */
1407887SLiane.Praza@Sun.COM 	"prop_pattern",			/* SC_PROP_PATTERN */
1410Sstevel@tonic-gate 	"property",			/* SC_PROPERTY */
1420Sstevel@tonic-gate 	"property_group",		/* SC_PROPERTY_GROUP */
1430Sstevel@tonic-gate 	"propval",			/* SC_PROPVAL */
1447887SLiane.Praza@Sun.COM 	"range",			/* SC_RANGE */
1450Sstevel@tonic-gate 	"restarter",			/* SC_RESTARTER */
1460Sstevel@tonic-gate 	"service",			/* SC_SERVICE */
1470Sstevel@tonic-gate 	"service_bundle",		/* SC_SERVICE_BUNDLE */
1480Sstevel@tonic-gate 	"service_fmri",			/* SC_SERVICE_FMRI */
1490Sstevel@tonic-gate 	"single_instance",		/* SC_INSTANCE_SINGLE */
1500Sstevel@tonic-gate 	"stability",			/* SC_STABILITY */
1510Sstevel@tonic-gate 	"template",			/* SC_TEMPLATE */
1520Sstevel@tonic-gate 	"time_list",			/* SC_TIME */
1537887SLiane.Praza@Sun.COM 	"units",			/* SC_UNITS */
1540Sstevel@tonic-gate 	"uri_list",			/* SC_URI */
1550Sstevel@tonic-gate 	"ustring_list",			/* SC_USTRING */
1567887SLiane.Praza@Sun.COM 	"value",			/* SC_VALUE */
1570Sstevel@tonic-gate 	"value_node",			/* SC_VALUE_NODE */
1587887SLiane.Praza@Sun.COM 	"values",			/* SC_VALUES */
1597887SLiane.Praza@Sun.COM 	"visibility",			/* SC_VISIBILITY */
1600Sstevel@tonic-gate 	"xi:fallback",			/* SC_XI_FALLBACK */
1610Sstevel@tonic-gate 	"xi:include"			/* SC_XI_INCLUDE */
1620Sstevel@tonic-gate };
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate /*
1650Sstevel@tonic-gate  * The following list must be kept in the same order as that of
1660Sstevel@tonic-gate  * element_t array
1670Sstevel@tonic-gate  */
1680Sstevel@tonic-gate static const char *lxml_prop_types[] = {
1690Sstevel@tonic-gate 	"astring",			/* SC_ASTRING */
1700Sstevel@tonic-gate 	"boolean",			/* SC_BOOLEAN */
1717887SLiane.Praza@Sun.COM 	"",				/* SC_CARDINALITY */
1727887SLiane.Praza@Sun.COM 	"",				/* SC_CHOICES */
1730Sstevel@tonic-gate 	"",				/* SC_COMMON_NAME */
1747887SLiane.Praza@Sun.COM 	"",				/* SC_CONSTRAINTS */
1750Sstevel@tonic-gate 	"count",			/* SC_COUNT */
1760Sstevel@tonic-gate 	"",				/* SC_INSTANCE_CREATE_DEFAULT */
1770Sstevel@tonic-gate 	"",				/* SC_DEPENDENCY */
1780Sstevel@tonic-gate 	"",				/* SC_DEPENDENT */
1790Sstevel@tonic-gate 	"",				/* SC_DESCRIPTION */
1800Sstevel@tonic-gate 	"",				/* SC_DOC_LINK */
1810Sstevel@tonic-gate 	"",				/* SC_DOCUMENTATION */
1820Sstevel@tonic-gate 	"",				/* SC_ENABLED */
1830Sstevel@tonic-gate 	"",				/* SC_EXEC_METHOD */
1840Sstevel@tonic-gate 	"fmri",				/* SC_FMRI */
1850Sstevel@tonic-gate 	"host",				/* SC_HOST */
1860Sstevel@tonic-gate 	"hostname",			/* SC_HOSTNAME */
1877887SLiane.Praza@Sun.COM 	"",				/* SC_INCLUDE_VALUES */
1880Sstevel@tonic-gate 	"",				/* SC_INSTANCE */
1890Sstevel@tonic-gate 	"integer",			/* SC_INTEGER */
1907887SLiane.Praza@Sun.COM 	"",				/* SC_INTERNAL_SEPARATORS */
1910Sstevel@tonic-gate 	"",				/* SC_LOCTEXT */
1920Sstevel@tonic-gate 	"",				/* SC_MANPAGE */
1930Sstevel@tonic-gate 	"",				/* SC_METHOD_CONTEXT */
1940Sstevel@tonic-gate 	"",				/* SC_METHOD_CREDENTIAL */
1950Sstevel@tonic-gate 	"",				/* SC_METHOD_PROFILE */
1960Sstevel@tonic-gate 	"",				/* SC_METHOD_ENVIRONMENT */
1970Sstevel@tonic-gate 	"",				/* SC_METHOD_ENVVAR */
1980Sstevel@tonic-gate 	"net_address_v4",		/* SC_NET_ADDR_V4 */
1990Sstevel@tonic-gate 	"net_address_v6",		/* SC_NET_ADDR_V6 */
2000Sstevel@tonic-gate 	"opaque",			/* SC_OPAQUE */
2017887SLiane.Praza@Sun.COM 	"",				/* SC_PG_PATTERN */
2027887SLiane.Praza@Sun.COM 	"",				/* SC_PROP_PATTERN */
2030Sstevel@tonic-gate 	"",				/* SC_PROPERTY */
2040Sstevel@tonic-gate 	"",				/* SC_PROPERTY_GROUP */
2050Sstevel@tonic-gate 	"",				/* SC_PROPVAL */
2067887SLiane.Praza@Sun.COM 	"",				/* SC_RANGE */
2070Sstevel@tonic-gate 	"",				/* SC_RESTARTER */
2080Sstevel@tonic-gate 	"",				/* SC_SERVICE */
2090Sstevel@tonic-gate 	"",				/* SC_SERVICE_BUNDLE */
2100Sstevel@tonic-gate 	"",				/* SC_SERVICE_FMRI */
2110Sstevel@tonic-gate 	"",				/* SC_INSTANCE_SINGLE */
2120Sstevel@tonic-gate 	"",				/* SC_STABILITY */
2130Sstevel@tonic-gate 	"",				/* SC_TEMPLATE */
2140Sstevel@tonic-gate 	"time",				/* SC_TIME */
2157887SLiane.Praza@Sun.COM 	"",				/* SC_UNITS */
2160Sstevel@tonic-gate 	"uri",				/* SC_URI */
2170Sstevel@tonic-gate 	"ustring",			/* SC_USTRING */
2187887SLiane.Praza@Sun.COM 	"",				/* SC_VALUE */
2197887SLiane.Praza@Sun.COM 	"",				/* SC_VALUE_NODE */
2207887SLiane.Praza@Sun.COM 	"",				/* SC_VALUES */
2217887SLiane.Praza@Sun.COM 	"",				/* SC_VISIBILITY */
2227887SLiane.Praza@Sun.COM 	"",				/* SC_XI_FALLBACK */
2230Sstevel@tonic-gate 	""				/* SC_XI_INCLUDE */
2240Sstevel@tonic-gate };
2250Sstevel@tonic-gate 
2260Sstevel@tonic-gate int
2270Sstevel@tonic-gate lxml_init()
2280Sstevel@tonic-gate {
2290Sstevel@tonic-gate 	if (getenv("SVCCFG_NOVALIDATE") == NULL) {
2300Sstevel@tonic-gate 		/*
2310Sstevel@tonic-gate 		 * DTD validation, with line numbers.
2320Sstevel@tonic-gate 		 */
23311053SSurya.Prakki@Sun.COM 		(void) xmlLineNumbersDefault(1);
2340Sstevel@tonic-gate 		xmlLoadExtDtdDefaultValue |= XML_DETECT_IDS;
2350Sstevel@tonic-gate 		xmlLoadExtDtdDefaultValue |= XML_COMPLETE_ATTRS;
2360Sstevel@tonic-gate 	}
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate 	return (0);
2390Sstevel@tonic-gate }
2400Sstevel@tonic-gate 
2410Sstevel@tonic-gate static bundle_type_t
2420Sstevel@tonic-gate lxml_xlate_bundle_type(xmlChar *type)
2430Sstevel@tonic-gate {
2440Sstevel@tonic-gate 	if (xmlStrcmp(type, (const xmlChar *)"manifest") == 0)
2450Sstevel@tonic-gate 		return (SVCCFG_MANIFEST);
2460Sstevel@tonic-gate 
2470Sstevel@tonic-gate 	if (xmlStrcmp(type, (const xmlChar *)"profile") == 0)
2480Sstevel@tonic-gate 		return (SVCCFG_PROFILE);
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate 	if (xmlStrcmp(type, (const xmlChar *)"archive") == 0)
2510Sstevel@tonic-gate 		return (SVCCFG_ARCHIVE);
2520Sstevel@tonic-gate 
2530Sstevel@tonic-gate 	return (SVCCFG_UNKNOWN_BUNDLE);
2540Sstevel@tonic-gate }
2550Sstevel@tonic-gate 
2560Sstevel@tonic-gate static service_type_t
2570Sstevel@tonic-gate lxml_xlate_service_type(xmlChar *type)
2580Sstevel@tonic-gate {
2590Sstevel@tonic-gate 	if (xmlStrcmp(type, (const xmlChar *)"service") == 0)
2600Sstevel@tonic-gate 		return (SVCCFG_SERVICE);
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate 	if (xmlStrcmp(type, (const xmlChar *)"restarter") == 0)
2630Sstevel@tonic-gate 		return (SVCCFG_RESTARTER);
2640Sstevel@tonic-gate 
2650Sstevel@tonic-gate 	if (xmlStrcmp(type, (const xmlChar *)"milestone") == 0)
2660Sstevel@tonic-gate 		return (SVCCFG_MILESTONE);
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate 	return (SVCCFG_UNKNOWN_SERVICE);
2690Sstevel@tonic-gate }
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate static element_t
2720Sstevel@tonic-gate lxml_xlate_element(const xmlChar *tag)
2730Sstevel@tonic-gate {
2740Sstevel@tonic-gate 	int i;
2750Sstevel@tonic-gate 
2760Sstevel@tonic-gate 	for (i = 0; i < sizeof (lxml_elements) / sizeof (char *); i++)
2770Sstevel@tonic-gate 		if (xmlStrcmp(tag, (const xmlChar *)lxml_elements[i]) == 0)
2780Sstevel@tonic-gate 			return ((element_t)i);
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate 	return ((element_t)-1);
2810Sstevel@tonic-gate }
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate static uint_t
2840Sstevel@tonic-gate lxml_xlate_boolean(const xmlChar *value)
2850Sstevel@tonic-gate {
2860Sstevel@tonic-gate 	if (xmlStrcmp(value, (const xmlChar *)true) == 0)
2870Sstevel@tonic-gate 		return (1);
2880Sstevel@tonic-gate 
2890Sstevel@tonic-gate 	if (xmlStrcmp(value, (const xmlChar *)false) == 0)
2900Sstevel@tonic-gate 		return (0);
2910Sstevel@tonic-gate 
2920Sstevel@tonic-gate 	uu_die(gettext("illegal boolean value \"%s\"\n"), value);
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate 	/*NOTREACHED*/
2950Sstevel@tonic-gate }
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate static scf_type_t
2980Sstevel@tonic-gate lxml_element_to_type(element_t type)
2990Sstevel@tonic-gate {
3000Sstevel@tonic-gate 	switch (type) {
3010Sstevel@tonic-gate 	case SC_ASTRING:	return (SCF_TYPE_ASTRING);
3020Sstevel@tonic-gate 	case SC_BOOLEAN:	return (SCF_TYPE_BOOLEAN);
3030Sstevel@tonic-gate 	case SC_COUNT:		return (SCF_TYPE_COUNT);
3040Sstevel@tonic-gate 	case SC_FMRI:		return (SCF_TYPE_FMRI);
3050Sstevel@tonic-gate 	case SC_HOST:		return (SCF_TYPE_HOST);
3060Sstevel@tonic-gate 	case SC_HOSTNAME:	return (SCF_TYPE_HOSTNAME);
3070Sstevel@tonic-gate 	case SC_INTEGER:	return (SCF_TYPE_INTEGER);
3080Sstevel@tonic-gate 	case SC_NET_ADDR_V4:	return (SCF_TYPE_NET_ADDR_V4);
3090Sstevel@tonic-gate 	case SC_NET_ADDR_V6:	return (SCF_TYPE_NET_ADDR_V6);
3100Sstevel@tonic-gate 	case SC_OPAQUE:		return (SCF_TYPE_OPAQUE);
3110Sstevel@tonic-gate 	case SC_TIME:		return (SCF_TYPE_TIME);
3120Sstevel@tonic-gate 	case SC_URI:		return (SCF_TYPE_URI);
3130Sstevel@tonic-gate 	case SC_USTRING:	return (SCF_TYPE_USTRING);
3140Sstevel@tonic-gate 
3150Sstevel@tonic-gate 	default:
3160Sstevel@tonic-gate 		uu_die(gettext("unknown value type (%d)\n"), type);
3170Sstevel@tonic-gate 	}
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate 	/* NOTREACHED */
3200Sstevel@tonic-gate }
3210Sstevel@tonic-gate 
322*12667SSean.Wilcox@Sun.COM static element_t
323*12667SSean.Wilcox@Sun.COM lxml_type_to_element(scf_type_t type)
3240Sstevel@tonic-gate {
3250Sstevel@tonic-gate 	switch (type) {
326*12667SSean.Wilcox@Sun.COM 	case SCF_TYPE_ASTRING:		return (SC_ASTRING);
327*12667SSean.Wilcox@Sun.COM 	case SCF_TYPE_BOOLEAN:		return (SC_BOOLEAN);
328*12667SSean.Wilcox@Sun.COM 	case SCF_TYPE_COUNT:		return (SC_COUNT);
329*12667SSean.Wilcox@Sun.COM 	case SCF_TYPE_FMRI:		return (SC_FMRI);
330*12667SSean.Wilcox@Sun.COM 	case SCF_TYPE_HOST:		return (SC_HOST);
331*12667SSean.Wilcox@Sun.COM 	case SCF_TYPE_HOSTNAME:		return (SC_HOSTNAME);
332*12667SSean.Wilcox@Sun.COM 	case SCF_TYPE_INTEGER:		return (SC_INTEGER);
333*12667SSean.Wilcox@Sun.COM 	case SCF_TYPE_NET_ADDR_V4:	return (SC_NET_ADDR_V4);
334*12667SSean.Wilcox@Sun.COM 	case SCF_TYPE_NET_ADDR_V6:	return (SC_NET_ADDR_V6);
335*12667SSean.Wilcox@Sun.COM 	case SCF_TYPE_OPAQUE:		return (SC_OPAQUE);
336*12667SSean.Wilcox@Sun.COM 	case SCF_TYPE_TIME:		return (SC_TIME);
337*12667SSean.Wilcox@Sun.COM 	case SCF_TYPE_URI:		return (SC_URI);
338*12667SSean.Wilcox@Sun.COM 	case SCF_TYPE_USTRING:		return (SC_USTRING);
339*12667SSean.Wilcox@Sun.COM 
3400Sstevel@tonic-gate 	default:
3410Sstevel@tonic-gate 		uu_die(gettext("unknown value type (%d)\n"), type);
3420Sstevel@tonic-gate 	}
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate 	/* NOTREACHED */
3450Sstevel@tonic-gate }
3460Sstevel@tonic-gate 
3477887SLiane.Praza@Sun.COM /*
3487887SLiane.Praza@Sun.COM  * Create a SCF_TYPE_BOOLEAN property name pname and attach it to the
3497887SLiane.Praza@Sun.COM  * property group at pgrp.  The value of the property will be set from the
3507887SLiane.Praza@Sun.COM  * attribute named attr.  attr must have a value of 0, 1, true or false.
3517887SLiane.Praza@Sun.COM  *
3527887SLiane.Praza@Sun.COM  * Zero is returned on success.  An error is indicated by -1.  It indicates
3537887SLiane.Praza@Sun.COM  * that either the attribute had an invalid value or that we could not
3547887SLiane.Praza@Sun.COM  * attach the property to pgrp.  The attribute should not have an invalid
3557887SLiane.Praza@Sun.COM  * value if the DTD is correctly written.
3567887SLiane.Praza@Sun.COM  */
3577887SLiane.Praza@Sun.COM static int
3587887SLiane.Praza@Sun.COM new_bool_prop_from_attr(pgroup_t *pgrp, const char *pname, xmlNodePtr n,
3597887SLiane.Praza@Sun.COM     const char *attr)
3607887SLiane.Praza@Sun.COM {
3617887SLiane.Praza@Sun.COM 	uint64_t bool;
3627887SLiane.Praza@Sun.COM 	xmlChar *val;
3637887SLiane.Praza@Sun.COM 	property_t *p;
3647887SLiane.Praza@Sun.COM 	int r;
3657887SLiane.Praza@Sun.COM 
3667887SLiane.Praza@Sun.COM 	val = xmlGetProp(n, (xmlChar *)attr);
3677887SLiane.Praza@Sun.COM 	if (val == NULL)
3687887SLiane.Praza@Sun.COM 		return (0);
3697887SLiane.Praza@Sun.COM 
3707887SLiane.Praza@Sun.COM 	if ((xmlStrcmp(val, (xmlChar *)"0") == 0) ||
3717887SLiane.Praza@Sun.COM 	    (xmlStrcmp(val, (xmlChar *)"false") == 0)) {
3727887SLiane.Praza@Sun.COM 		bool = 0;
3737887SLiane.Praza@Sun.COM 	} else if ((xmlStrcmp(val, (xmlChar *)"1") == 0) ||
3747887SLiane.Praza@Sun.COM 	    (xmlStrcmp(val, (xmlChar *)"true") == 0)) {
3757887SLiane.Praza@Sun.COM 		bool = 1;
3767887SLiane.Praza@Sun.COM 	} else {
3777887SLiane.Praza@Sun.COM 		xmlFree(val);
3787887SLiane.Praza@Sun.COM 		return (-1);
3797887SLiane.Praza@Sun.COM 	}
3807887SLiane.Praza@Sun.COM 	xmlFree(val);
3817887SLiane.Praza@Sun.COM 	p = internal_property_create(pname, SCF_TYPE_BOOLEAN, 1, bool);
3827887SLiane.Praza@Sun.COM 	r = internal_attach_property(pgrp, p);
3837887SLiane.Praza@Sun.COM 
3847887SLiane.Praza@Sun.COM 	if (r != 0)
3857887SLiane.Praza@Sun.COM 		internal_property_free(p);
3867887SLiane.Praza@Sun.COM 
3877887SLiane.Praza@Sun.COM 	return (r);
3887887SLiane.Praza@Sun.COM }
3897887SLiane.Praza@Sun.COM 
3900Sstevel@tonic-gate static int
3910Sstevel@tonic-gate new_str_prop_from_attr(pgroup_t *pgrp, const char *pname, scf_type_t ty,
3920Sstevel@tonic-gate     xmlNodePtr n, const char *attr)
3930Sstevel@tonic-gate {
3940Sstevel@tonic-gate 	xmlChar *val;
3950Sstevel@tonic-gate 	property_t *p;
3960Sstevel@tonic-gate 	int r;
3970Sstevel@tonic-gate 
3980Sstevel@tonic-gate 	val = xmlGetProp(n, (xmlChar *)attr);
3990Sstevel@tonic-gate 
4000Sstevel@tonic-gate 	p = internal_property_create(pname, ty, 1, val);
4010Sstevel@tonic-gate 	r = internal_attach_property(pgrp, p);
4020Sstevel@tonic-gate 
4030Sstevel@tonic-gate 	if (r != 0)
4040Sstevel@tonic-gate 		internal_property_free(p);
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate 	return (r);
4070Sstevel@tonic-gate }
4080Sstevel@tonic-gate 
4090Sstevel@tonic-gate static int
4107887SLiane.Praza@Sun.COM new_opt_str_prop_from_attr(pgroup_t *pgrp, const char *pname, scf_type_t ty,
4117887SLiane.Praza@Sun.COM     xmlNodePtr n, const char *attr, const char *dflt)
4127887SLiane.Praza@Sun.COM {
4137887SLiane.Praza@Sun.COM 	xmlChar *val;
4147887SLiane.Praza@Sun.COM 	property_t *p;
4157887SLiane.Praza@Sun.COM 	int r;
4167887SLiane.Praza@Sun.COM 
4177887SLiane.Praza@Sun.COM 	val = xmlGetProp(n, (xmlChar *)attr);
4187887SLiane.Praza@Sun.COM 	if (val == NULL) {
4197887SLiane.Praza@Sun.COM 		if (dflt == NULL) {
4207887SLiane.Praza@Sun.COM 			/*
4217887SLiane.Praza@Sun.COM 			 * A missing attribute is considered to be a
4227887SLiane.Praza@Sun.COM 			 * success in this function, because many of the
4237887SLiane.Praza@Sun.COM 			 * attributes are optional.  Missing non-optional
4247887SLiane.Praza@Sun.COM 			 * attributes will be detected later when template
4257887SLiane.Praza@Sun.COM 			 * validation is done.
4267887SLiane.Praza@Sun.COM 			 */
4277887SLiane.Praza@Sun.COM 			return (0);
4287887SLiane.Praza@Sun.COM 		} else {
4297887SLiane.Praza@Sun.COM 			val = (xmlChar *)dflt;
4307887SLiane.Praza@Sun.COM 		}
4317887SLiane.Praza@Sun.COM 	}
4327887SLiane.Praza@Sun.COM 
4337887SLiane.Praza@Sun.COM 	p = internal_property_create(pname, ty, 1, val);
4347887SLiane.Praza@Sun.COM 	r = internal_attach_property(pgrp, p);
4357887SLiane.Praza@Sun.COM 
4367887SLiane.Praza@Sun.COM 	if (r != 0)
4377887SLiane.Praza@Sun.COM 		internal_property_free(p);
4387887SLiane.Praza@Sun.COM 
4397887SLiane.Praza@Sun.COM 	return (r);
4407887SLiane.Praza@Sun.COM }
4417887SLiane.Praza@Sun.COM 
4427887SLiane.Praza@Sun.COM static int
4430Sstevel@tonic-gate lxml_ignorable_block(xmlNodePtr n)
4440Sstevel@tonic-gate {
4450Sstevel@tonic-gate 	return ((xmlStrcmp(n->name, (xmlChar *)"text") == 0 ||
4460Sstevel@tonic-gate 	    xmlStrcmp(n->name, (xmlChar *)"comment") == 0) ? 1 : 0);
4470Sstevel@tonic-gate }
4480Sstevel@tonic-gate 
449*12667SSean.Wilcox@Sun.COM static void
450*12667SSean.Wilcox@Sun.COM lxml_validate_element(xmlNodePtr n)
451*12667SSean.Wilcox@Sun.COM {
452*12667SSean.Wilcox@Sun.COM 	xmlValidCtxtPtr	vcp;
453*12667SSean.Wilcox@Sun.COM 
454*12667SSean.Wilcox@Sun.COM 	if (n->doc == NULL)
455*12667SSean.Wilcox@Sun.COM 		uu_die(gettext("Could not validate element\n"));
456*12667SSean.Wilcox@Sun.COM 
457*12667SSean.Wilcox@Sun.COM 	if (n->doc->extSubset == NULL) {
458*12667SSean.Wilcox@Sun.COM 		xmlDtdPtr dtd;
459*12667SSean.Wilcox@Sun.COM 		dtd = xmlParseDTD(NULL, n->doc->intSubset->SystemID);
460*12667SSean.Wilcox@Sun.COM 
461*12667SSean.Wilcox@Sun.COM 		if (dtd == NULL) {
462*12667SSean.Wilcox@Sun.COM 			uu_die(gettext("Could not parse DTD \"%s\".\n"),
463*12667SSean.Wilcox@Sun.COM 			    n->doc->intSubset->SystemID);
464*12667SSean.Wilcox@Sun.COM 		}
465*12667SSean.Wilcox@Sun.COM 
466*12667SSean.Wilcox@Sun.COM 		n->doc->extSubset = dtd;
467*12667SSean.Wilcox@Sun.COM 	}
468*12667SSean.Wilcox@Sun.COM 
469*12667SSean.Wilcox@Sun.COM 	vcp = xmlNewValidCtxt();
470*12667SSean.Wilcox@Sun.COM 	if (vcp == NULL)
471*12667SSean.Wilcox@Sun.COM 		uu_die(gettext("could not allocate memory"));
472*12667SSean.Wilcox@Sun.COM 
473*12667SSean.Wilcox@Sun.COM 	vcp->warning = xmlParserValidityWarning;
474*12667SSean.Wilcox@Sun.COM 	vcp->error = xmlParserValidityError;
475*12667SSean.Wilcox@Sun.COM 
476*12667SSean.Wilcox@Sun.COM 	if (xmlValidateElement(vcp, n->doc, n) == 0)
477*12667SSean.Wilcox@Sun.COM 		uu_die(gettext("Document is not valid.\n"));
478*12667SSean.Wilcox@Sun.COM 
479*12667SSean.Wilcox@Sun.COM 	xmlFreeValidCtxt(vcp);
480*12667SSean.Wilcox@Sun.COM }
481*12667SSean.Wilcox@Sun.COM 
4820Sstevel@tonic-gate static int
4830Sstevel@tonic-gate lxml_validate_string_value(scf_type_t type, const char *v)
4840Sstevel@tonic-gate {
4850Sstevel@tonic-gate 	static scf_value_t *scf_value = NULL;
4860Sstevel@tonic-gate 	static scf_handle_t *scf_hndl = NULL;
4870Sstevel@tonic-gate 
4880Sstevel@tonic-gate 	if (scf_hndl == NULL && (scf_hndl = scf_handle_create(SCF_VERSION)) ==
4890Sstevel@tonic-gate 	    NULL)
4900Sstevel@tonic-gate 		return (-1);
4910Sstevel@tonic-gate 
4920Sstevel@tonic-gate 	if (scf_value == NULL && (scf_value = scf_value_create(scf_hndl)) ==
4930Sstevel@tonic-gate 	    NULL)
4940Sstevel@tonic-gate 		return (-1);
4950Sstevel@tonic-gate 
4960Sstevel@tonic-gate 	return (scf_value_set_from_string(scf_value, type, v));
4970Sstevel@tonic-gate }
4980Sstevel@tonic-gate 
4990Sstevel@tonic-gate static void
5000Sstevel@tonic-gate lxml_free_str(value_t *val)
5010Sstevel@tonic-gate {
5020Sstevel@tonic-gate 	free(val->sc_u.sc_string);
5030Sstevel@tonic-gate }
5040Sstevel@tonic-gate 
505*12667SSean.Wilcox@Sun.COM /*
506*12667SSean.Wilcox@Sun.COM  * Take a value_t structure and a type and value.  Based on the type
507*12667SSean.Wilcox@Sun.COM  * ensure that the value is of that type.  If so store the value in
508*12667SSean.Wilcox@Sun.COM  * the correct location of the value_t structure.
509*12667SSean.Wilcox@Sun.COM  *
510*12667SSean.Wilcox@Sun.COM  * If the value is NULL, the value_t structure will have been created
511*12667SSean.Wilcox@Sun.COM  * and the value would have ultimately been stored as a string value
512*12667SSean.Wilcox@Sun.COM  * but at the time the type was unknown.  Now the type should be known
513*12667SSean.Wilcox@Sun.COM  * so take the type and value from value_t and validate and store
514*12667SSean.Wilcox@Sun.COM  * the value correctly if the value is of the stated type.
515*12667SSean.Wilcox@Sun.COM  */
516*12667SSean.Wilcox@Sun.COM void
517*12667SSean.Wilcox@Sun.COM lxml_store_value(value_t *v, element_t type, const xmlChar *value)
5180Sstevel@tonic-gate {
5190Sstevel@tonic-gate 	char *endptr;
520*12667SSean.Wilcox@Sun.COM 	int fov = 0;
5210Sstevel@tonic-gate 	scf_type_t scf_type = SCF_TYPE_INVALID;
5220Sstevel@tonic-gate 
523*12667SSean.Wilcox@Sun.COM 	if (value == NULL) {
524*12667SSean.Wilcox@Sun.COM 		type = lxml_type_to_element(v->sc_type);
525*12667SSean.Wilcox@Sun.COM 		value = (const xmlChar *)v->sc_u.sc_string;
526*12667SSean.Wilcox@Sun.COM 		fov = 1;
527*12667SSean.Wilcox@Sun.COM 	}
5280Sstevel@tonic-gate 
5290Sstevel@tonic-gate 	switch (type) {
5300Sstevel@tonic-gate 	case SC_COUNT:
5310Sstevel@tonic-gate 		/*
5320Sstevel@tonic-gate 		 * Although an SC_COUNT represents a uint64_t the use
5330Sstevel@tonic-gate 		 * of a negative value is acceptable due to the usage
5340Sstevel@tonic-gate 		 * established by inetd(1M).
5350Sstevel@tonic-gate 		 */
5360Sstevel@tonic-gate 		errno = 0;
5370Sstevel@tonic-gate 		v->sc_u.sc_count = strtoull((char *)value, &endptr, 10);
5380Sstevel@tonic-gate 		if (errno != 0 || endptr == (char *)value || *endptr)
5390Sstevel@tonic-gate 			uu_die(gettext("illegal value \"%s\" for "
5400Sstevel@tonic-gate 			    "%s (%s)\n"), (char *)value,
5410Sstevel@tonic-gate 			    lxml_prop_types[type],
5420Sstevel@tonic-gate 			    (errno) ? strerror(errno) :
5430Sstevel@tonic-gate 			    gettext("Illegal character"));
5440Sstevel@tonic-gate 		break;
5450Sstevel@tonic-gate 	case SC_INTEGER:
5460Sstevel@tonic-gate 		errno = 0;
5470Sstevel@tonic-gate 		v->sc_u.sc_integer = strtoll((char *)value, &endptr, 10);
5480Sstevel@tonic-gate 		if (errno != 0 || *endptr)
5490Sstevel@tonic-gate 			uu_die(gettext("illegal value \"%s\" for "
5500Sstevel@tonic-gate 			    "%s (%s)\n"), (char *)value,
5510Sstevel@tonic-gate 			    lxml_prop_types[type],
5520Sstevel@tonic-gate 			    (errno) ? strerror(errno) : "Illegal character");
5530Sstevel@tonic-gate 		break;
5540Sstevel@tonic-gate 	case SC_OPAQUE:
5550Sstevel@tonic-gate 	case SC_HOST:
5560Sstevel@tonic-gate 	case SC_HOSTNAME:
5570Sstevel@tonic-gate 	case SC_NET_ADDR_V4:
5580Sstevel@tonic-gate 	case SC_NET_ADDR_V6:
5590Sstevel@tonic-gate 	case SC_FMRI:
5600Sstevel@tonic-gate 	case SC_URI:
5610Sstevel@tonic-gate 	case SC_TIME:
5620Sstevel@tonic-gate 	case SC_ASTRING:
5630Sstevel@tonic-gate 	case SC_USTRING:
564*12667SSean.Wilcox@Sun.COM 		scf_type = lxml_element_to_type(type);
5650Sstevel@tonic-gate 
5660Sstevel@tonic-gate 		if ((v->sc_u.sc_string = strdup((char *)value)) == NULL)
5670Sstevel@tonic-gate 			uu_die(gettext("string duplication failed (%s)\n"),
5680Sstevel@tonic-gate 			    strerror(errno));
5690Sstevel@tonic-gate 		if (lxml_validate_string_value(scf_type,
5700Sstevel@tonic-gate 		    v->sc_u.sc_string) != 0)
5710Sstevel@tonic-gate 			uu_die(gettext("illegal value \"%s\" for "
5720Sstevel@tonic-gate 			    "%s (%s)\n"), (char *)value,
5730Sstevel@tonic-gate 			    lxml_prop_types[type],
5740Sstevel@tonic-gate 			    (scf_error()) ? scf_strerror(scf_error()) :
5750Sstevel@tonic-gate 			    gettext("Illegal format"));
5760Sstevel@tonic-gate 		v->sc_free = lxml_free_str;
5770Sstevel@tonic-gate 		break;
5780Sstevel@tonic-gate 	case SC_BOOLEAN:
5790Sstevel@tonic-gate 		v->sc_u.sc_count = lxml_xlate_boolean(value);
5800Sstevel@tonic-gate 		break;
5810Sstevel@tonic-gate 	default:
5820Sstevel@tonic-gate 		uu_die(gettext("unknown value type (%d)\n"), type);
5830Sstevel@tonic-gate 		break;
5840Sstevel@tonic-gate 	}
5850Sstevel@tonic-gate 
586*12667SSean.Wilcox@Sun.COM 	/* Free the old value */
587*12667SSean.Wilcox@Sun.COM 	if (fov && v->sc_free != NULL)
588*12667SSean.Wilcox@Sun.COM 		free((char *)value);
589*12667SSean.Wilcox@Sun.COM }
590*12667SSean.Wilcox@Sun.COM 
591*12667SSean.Wilcox@Sun.COM static value_t *
592*12667SSean.Wilcox@Sun.COM lxml_make_value(element_t type, const xmlChar *value)
593*12667SSean.Wilcox@Sun.COM {
594*12667SSean.Wilcox@Sun.COM 	value_t *v;
595*12667SSean.Wilcox@Sun.COM 
596*12667SSean.Wilcox@Sun.COM 	v = internal_value_new();
597*12667SSean.Wilcox@Sun.COM 
598*12667SSean.Wilcox@Sun.COM 	v->sc_type = lxml_element_to_type(type);
599*12667SSean.Wilcox@Sun.COM 
600*12667SSean.Wilcox@Sun.COM 	lxml_store_value(v, type, value);
601*12667SSean.Wilcox@Sun.COM 
6020Sstevel@tonic-gate 	return (v);
6030Sstevel@tonic-gate }
6040Sstevel@tonic-gate 
6050Sstevel@tonic-gate static int
6060Sstevel@tonic-gate lxml_get_value(property_t *prop, element_t vtype, xmlNodePtr value)
6070Sstevel@tonic-gate {
6080Sstevel@tonic-gate 	xmlNodePtr cursor;
6090Sstevel@tonic-gate 
6100Sstevel@tonic-gate 	for (cursor = value->xmlChildrenNode; cursor != NULL;
6110Sstevel@tonic-gate 	    cursor = cursor->next) {
6120Sstevel@tonic-gate 		xmlChar *assigned_value;
6130Sstevel@tonic-gate 		value_t *v;
6140Sstevel@tonic-gate 
6150Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
6160Sstevel@tonic-gate 			continue;
6170Sstevel@tonic-gate 
6180Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
6190Sstevel@tonic-gate 		case SC_VALUE_NODE:
6200Sstevel@tonic-gate 			if ((assigned_value = xmlGetProp(cursor,
6210Sstevel@tonic-gate 			    (xmlChar *)value_attr)) == NULL)
6220Sstevel@tonic-gate 				uu_die(gettext("no value on value node?\n"));
6230Sstevel@tonic-gate 			break;
6240Sstevel@tonic-gate 		default:
6250Sstevel@tonic-gate 			uu_die(gettext("value list contains illegal element "
6260Sstevel@tonic-gate 			    "\'%s\'\n"), cursor->name);
6270Sstevel@tonic-gate 			break;
6280Sstevel@tonic-gate 		}
6290Sstevel@tonic-gate 
6300Sstevel@tonic-gate 		v = lxml_make_value(vtype, assigned_value);
6310Sstevel@tonic-gate 
6320Sstevel@tonic-gate 		xmlFree(assigned_value);
6330Sstevel@tonic-gate 
6340Sstevel@tonic-gate 		internal_attach_value(prop, v);
6350Sstevel@tonic-gate 	}
6360Sstevel@tonic-gate 
6370Sstevel@tonic-gate 	return (0);
6380Sstevel@tonic-gate }
6390Sstevel@tonic-gate 
6400Sstevel@tonic-gate static int
6410Sstevel@tonic-gate lxml_get_propval(pgroup_t *pgrp, xmlNodePtr propval)
6420Sstevel@tonic-gate {
6430Sstevel@tonic-gate 	property_t *p;
6440Sstevel@tonic-gate 	element_t r;
6450Sstevel@tonic-gate 	value_t *v;
6460Sstevel@tonic-gate 	xmlChar *type, *val, *override;
647*12667SSean.Wilcox@Sun.COM 	int op = pgrp->sc_parent->sc_op;
6480Sstevel@tonic-gate 
6490Sstevel@tonic-gate 	p = internal_property_new();
6500Sstevel@tonic-gate 
6510Sstevel@tonic-gate 	p->sc_property_name = (char *)xmlGetProp(propval, (xmlChar *)name_attr);
6527887SLiane.Praza@Sun.COM 	if ((p->sc_property_name == NULL) || (*p->sc_property_name == 0))
6530Sstevel@tonic-gate 		uu_die(gettext("property name missing in group '%s'\n"),
6540Sstevel@tonic-gate 		    pgrp->sc_pgroup_name);
6550Sstevel@tonic-gate 
6560Sstevel@tonic-gate 	type = xmlGetProp(propval, (xmlChar *)type_attr);
657*12667SSean.Wilcox@Sun.COM 	if ((type != NULL) && (*type != 0)) {
658*12667SSean.Wilcox@Sun.COM 		for (r = 0;
659*12667SSean.Wilcox@Sun.COM 		    r < sizeof (lxml_prop_types) / sizeof (char *); ++r) {
660*12667SSean.Wilcox@Sun.COM 			if (xmlStrcmp(type,
661*12667SSean.Wilcox@Sun.COM 			    (const xmlChar *)lxml_prop_types[r]) == 0)
662*12667SSean.Wilcox@Sun.COM 				break;
663*12667SSean.Wilcox@Sun.COM 		}
664*12667SSean.Wilcox@Sun.COM 
665*12667SSean.Wilcox@Sun.COM 		if (r >= sizeof (lxml_prop_types) / sizeof (char *))
666*12667SSean.Wilcox@Sun.COM 			uu_die(gettext("property type invalid for "
667*12667SSean.Wilcox@Sun.COM 			    "property '%s/%s'\n"), pgrp->sc_pgroup_name,
668*12667SSean.Wilcox@Sun.COM 			    p->sc_property_name);
669*12667SSean.Wilcox@Sun.COM 
670*12667SSean.Wilcox@Sun.COM 		p->sc_value_type = lxml_element_to_type(r);
671*12667SSean.Wilcox@Sun.COM 	} else if (op == SVCCFG_OP_APPLY) {
672*12667SSean.Wilcox@Sun.COM 		/*
673*12667SSean.Wilcox@Sun.COM 		 * Store the property type as invalid, and the value
674*12667SSean.Wilcox@Sun.COM 		 * as an ASTRING and let the bundle apply code validate
675*12667SSean.Wilcox@Sun.COM 		 * the type/value once the type is found.
676*12667SSean.Wilcox@Sun.COM 		 */
677*12667SSean.Wilcox@Sun.COM 		est->sc_miss_type = B_TRUE;
678*12667SSean.Wilcox@Sun.COM 		p->sc_value_type = SCF_TYPE_INVALID;
679*12667SSean.Wilcox@Sun.COM 		r = SC_ASTRING;
680*12667SSean.Wilcox@Sun.COM 	} else {
6810Sstevel@tonic-gate 		uu_die(gettext("property type missing for property '%s/%s'\n"),
6820Sstevel@tonic-gate 		    pgrp->sc_pgroup_name, p->sc_property_name);
6830Sstevel@tonic-gate 	}
6840Sstevel@tonic-gate 
6850Sstevel@tonic-gate 	val = xmlGetProp(propval, (xmlChar *)value_attr);
6860Sstevel@tonic-gate 	if (val == NULL)
6870Sstevel@tonic-gate 		uu_die(gettext("property value missing for property '%s/%s'\n"),
6880Sstevel@tonic-gate 		    pgrp->sc_pgroup_name, p->sc_property_name);
6890Sstevel@tonic-gate 
6900Sstevel@tonic-gate 	v = lxml_make_value(r, val);
6917887SLiane.Praza@Sun.COM 	xmlFree(val);
6920Sstevel@tonic-gate 	internal_attach_value(p, v);
6930Sstevel@tonic-gate 
694*12667SSean.Wilcox@Sun.COM 	xmlFree(type);
695*12667SSean.Wilcox@Sun.COM 
6960Sstevel@tonic-gate 	override = xmlGetProp(propval, (xmlChar *)override_attr);
6970Sstevel@tonic-gate 	p->sc_property_override = (xmlStrcmp(override, (xmlChar *)true) == 0);
6980Sstevel@tonic-gate 	xmlFree(override);
6990Sstevel@tonic-gate 
7000Sstevel@tonic-gate 	return (internal_attach_property(pgrp, p));
7010Sstevel@tonic-gate }
7020Sstevel@tonic-gate 
7030Sstevel@tonic-gate static int
7040Sstevel@tonic-gate lxml_get_property(pgroup_t *pgrp, xmlNodePtr property)
7050Sstevel@tonic-gate {
7060Sstevel@tonic-gate 	property_t *p;
7070Sstevel@tonic-gate 	xmlNodePtr cursor;
7080Sstevel@tonic-gate 	element_t r;
7090Sstevel@tonic-gate 	xmlChar *type, *override;
710*12667SSean.Wilcox@Sun.COM 	int op = pgrp->sc_parent->sc_op;
7110Sstevel@tonic-gate 
7120Sstevel@tonic-gate 	p = internal_property_new();
7130Sstevel@tonic-gate 
7147887SLiane.Praza@Sun.COM 	if (((p->sc_property_name = (char *)xmlGetProp(property,
7157887SLiane.Praza@Sun.COM 	    (xmlChar *)name_attr)) == NULL) || (*p->sc_property_name == 0))
7160Sstevel@tonic-gate 		uu_die(gettext("property name missing in group \'%s\'\n"),
7170Sstevel@tonic-gate 		    pgrp->sc_pgroup_name);
7180Sstevel@tonic-gate 
719*12667SSean.Wilcox@Sun.COM 	type = xmlGetProp(property, (xmlChar *)type_attr);
720*12667SSean.Wilcox@Sun.COM 	if ((type != NULL) && (*type != 0)) {
721*12667SSean.Wilcox@Sun.COM 		for (r = 0;
722*12667SSean.Wilcox@Sun.COM 		    r < sizeof (lxml_prop_types) / sizeof (char *); r++) {
723*12667SSean.Wilcox@Sun.COM 			if (xmlStrcmp(type,
724*12667SSean.Wilcox@Sun.COM 			    (const xmlChar *)lxml_prop_types[r]) == 0)
725*12667SSean.Wilcox@Sun.COM 				break;
726*12667SSean.Wilcox@Sun.COM 		}
727*12667SSean.Wilcox@Sun.COM 
728*12667SSean.Wilcox@Sun.COM 		if (r >= sizeof (lxml_prop_types) / sizeof (char *))
729*12667SSean.Wilcox@Sun.COM 			uu_die(gettext("property type invalid for "
730*12667SSean.Wilcox@Sun.COM 			    "property '%s/%s'\n"), pgrp->sc_pgroup_name,
731*12667SSean.Wilcox@Sun.COM 			    p->sc_property_name);
732*12667SSean.Wilcox@Sun.COM 
733*12667SSean.Wilcox@Sun.COM 		p->sc_value_type = lxml_element_to_type(r);
734*12667SSean.Wilcox@Sun.COM 	} else if (op == SVCCFG_OP_APPLY) {
735*12667SSean.Wilcox@Sun.COM 		/*
736*12667SSean.Wilcox@Sun.COM 		 * Store the property type as invalid, and let the bundle apply
737*12667SSean.Wilcox@Sun.COM 		 * code validate the type/value once the type is found.
738*12667SSean.Wilcox@Sun.COM 		 */
739*12667SSean.Wilcox@Sun.COM 		p->sc_value_type = SCF_TYPE_INVALID;
740*12667SSean.Wilcox@Sun.COM 		est->sc_miss_type = B_TRUE;
741*12667SSean.Wilcox@Sun.COM 	} else {
7420Sstevel@tonic-gate 		uu_die(gettext("property type missing for "
7430Sstevel@tonic-gate 		    "property \'%s/%s\'\n"), pgrp->sc_pgroup_name,
7440Sstevel@tonic-gate 		    p->sc_property_name);
7457887SLiane.Praza@Sun.COM 	}
7460Sstevel@tonic-gate 
7470Sstevel@tonic-gate 	for (cursor = property->xmlChildrenNode; cursor != NULL;
7480Sstevel@tonic-gate 	    cursor = cursor->next) {
7490Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
7500Sstevel@tonic-gate 			continue;
7510Sstevel@tonic-gate 
7520Sstevel@tonic-gate 		switch (r = lxml_xlate_element(cursor->name)) {
7530Sstevel@tonic-gate 		case SC_ASTRING:
7540Sstevel@tonic-gate 		case SC_BOOLEAN:
7550Sstevel@tonic-gate 		case SC_COUNT:
7560Sstevel@tonic-gate 		case SC_FMRI:
7570Sstevel@tonic-gate 		case SC_HOST:
7580Sstevel@tonic-gate 		case SC_HOSTNAME:
7590Sstevel@tonic-gate 		case SC_INTEGER:
7600Sstevel@tonic-gate 		case SC_NET_ADDR_V4:
7610Sstevel@tonic-gate 		case SC_NET_ADDR_V6:
7620Sstevel@tonic-gate 		case SC_OPAQUE:
7630Sstevel@tonic-gate 		case SC_TIME:
7640Sstevel@tonic-gate 		case SC_URI:
7650Sstevel@tonic-gate 		case SC_USTRING:
766*12667SSean.Wilcox@Sun.COM 			/*
767*12667SSean.Wilcox@Sun.COM 			 * If the type is invalid then this is an apply
768*12667SSean.Wilcox@Sun.COM 			 * operation and the type can be taken from the
769*12667SSean.Wilcox@Sun.COM 			 * value list.
770*12667SSean.Wilcox@Sun.COM 			 */
771*12667SSean.Wilcox@Sun.COM 			if (p->sc_value_type == SCF_TYPE_INVALID) {
772*12667SSean.Wilcox@Sun.COM 				p->sc_value_type = lxml_element_to_type(r);
773*12667SSean.Wilcox@Sun.COM 				type = xmlStrdup((const
774*12667SSean.Wilcox@Sun.COM 				    xmlChar *)lxml_prop_types[r]);
775*12667SSean.Wilcox@Sun.COM 
776*12667SSean.Wilcox@Sun.COM 			} else if (strcmp(lxml_prop_types[r],
777*12667SSean.Wilcox@Sun.COM 			    (const char *)type) != 0) {
7780Sstevel@tonic-gate 				uu_die(gettext("property \'%s\' "
7790Sstevel@tonic-gate 				    "type-to-list mismatch\n"),
7800Sstevel@tonic-gate 				    p->sc_property_name);
781*12667SSean.Wilcox@Sun.COM 			}
7820Sstevel@tonic-gate 
7830Sstevel@tonic-gate 			(void) lxml_get_value(p, r, cursor);
7840Sstevel@tonic-gate 			break;
7850Sstevel@tonic-gate 		default:
7860Sstevel@tonic-gate 			uu_die(gettext("unknown value list type: %s\n"),
7870Sstevel@tonic-gate 			    cursor->name);
7880Sstevel@tonic-gate 			break;
7890Sstevel@tonic-gate 		}
7900Sstevel@tonic-gate 	}
7910Sstevel@tonic-gate 
7920Sstevel@tonic-gate 	xmlFree(type);
7930Sstevel@tonic-gate 
7940Sstevel@tonic-gate 	override = xmlGetProp(property, (xmlChar *)override_attr);
7950Sstevel@tonic-gate 	p->sc_property_override = (xmlStrcmp(override, (xmlChar *)true) == 0);
7960Sstevel@tonic-gate 	xmlFree(override);
7970Sstevel@tonic-gate 
7980Sstevel@tonic-gate 	return (internal_attach_property(pgrp, p));
7990Sstevel@tonic-gate }
8000Sstevel@tonic-gate 
8010Sstevel@tonic-gate static int
8020Sstevel@tonic-gate lxml_get_pgroup_stability(pgroup_t *pgrp, xmlNodePtr stab)
8030Sstevel@tonic-gate {
804*12667SSean.Wilcox@Sun.COM 	if (pgrp->sc_parent->sc_op == SVCCFG_OP_APPLY)
805*12667SSean.Wilcox@Sun.COM 		lxml_validate_element(stab);
806*12667SSean.Wilcox@Sun.COM 
8070Sstevel@tonic-gate 	return (new_str_prop_from_attr(pgrp, SCF_PROPERTY_STABILITY,
8080Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, stab, value_attr));
8090Sstevel@tonic-gate }
8100Sstevel@tonic-gate 
8110Sstevel@tonic-gate /*
8120Sstevel@tonic-gate  * Property groups can go on any of a service, an instance, or a template.
8130Sstevel@tonic-gate  */
8140Sstevel@tonic-gate static int
8150Sstevel@tonic-gate lxml_get_pgroup(entity_t *entity, xmlNodePtr pgroup)
8160Sstevel@tonic-gate {
8170Sstevel@tonic-gate 	pgroup_t *pg;
8180Sstevel@tonic-gate 	xmlNodePtr cursor;
8190Sstevel@tonic-gate 	xmlChar *name, *type, *delete;
8200Sstevel@tonic-gate 
8210Sstevel@tonic-gate 	/*
8220Sstevel@tonic-gate 	 * property group attributes:
8230Sstevel@tonic-gate 	 * name: string
8240Sstevel@tonic-gate 	 * type: string | framework | application
8250Sstevel@tonic-gate 	 */
8260Sstevel@tonic-gate 	name = xmlGetProp(pgroup, (xmlChar *)name_attr);
8270Sstevel@tonic-gate 	type = xmlGetProp(pgroup, (xmlChar *)type_attr);
8280Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(entity, (char *)name, (char *)type);
8290Sstevel@tonic-gate 	xmlFree(name);
8300Sstevel@tonic-gate 	xmlFree(type);
8310Sstevel@tonic-gate 
8320Sstevel@tonic-gate 	/*
8330Sstevel@tonic-gate 	 * Walk the children of this lxml_elements, which are a stability
8340Sstevel@tonic-gate 	 * element, property elements, or propval elements.
8350Sstevel@tonic-gate 	 */
8360Sstevel@tonic-gate 	for (cursor = pgroup->xmlChildrenNode; cursor != NULL;
8370Sstevel@tonic-gate 	    cursor = cursor->next) {
8380Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
8390Sstevel@tonic-gate 			continue;
8400Sstevel@tonic-gate 
8410Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
8420Sstevel@tonic-gate 		case SC_STABILITY:
8430Sstevel@tonic-gate 			(void) lxml_get_pgroup_stability(pg, cursor);
8440Sstevel@tonic-gate 			break;
8450Sstevel@tonic-gate 		case SC_PROPERTY:
8460Sstevel@tonic-gate 			(void) lxml_get_property(pg, cursor);
8470Sstevel@tonic-gate 			break;
8480Sstevel@tonic-gate 		case SC_PROPVAL:
8490Sstevel@tonic-gate 			(void) lxml_get_propval(pg, cursor);
8500Sstevel@tonic-gate 			break;
8510Sstevel@tonic-gate 		default:
8520Sstevel@tonic-gate 			abort();
8530Sstevel@tonic-gate 			break;
8540Sstevel@tonic-gate 		}
8550Sstevel@tonic-gate 	}
8560Sstevel@tonic-gate 
8570Sstevel@tonic-gate 	delete = xmlGetProp(pgroup, (xmlChar *)delete_attr);
8580Sstevel@tonic-gate 	pg->sc_pgroup_delete = (xmlStrcmp(delete, (xmlChar *)true) == 0);
8590Sstevel@tonic-gate 	xmlFree(delete);
8600Sstevel@tonic-gate 
8610Sstevel@tonic-gate 	return (0);
8620Sstevel@tonic-gate }
8630Sstevel@tonic-gate 
8640Sstevel@tonic-gate 
8650Sstevel@tonic-gate /*
8660Sstevel@tonic-gate  * Dependency groups, execution methods can go on either a service or an
8670Sstevel@tonic-gate  * instance.
8680Sstevel@tonic-gate  */
8690Sstevel@tonic-gate 
8700Sstevel@tonic-gate static int
8710Sstevel@tonic-gate lxml_get_method_profile(pgroup_t *pg, xmlNodePtr profile)
8720Sstevel@tonic-gate {
8730Sstevel@tonic-gate 	property_t *p;
8740Sstevel@tonic-gate 
8750Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_USE_PROFILE, SCF_TYPE_BOOLEAN,
8760Sstevel@tonic-gate 	    1, (uint64_t)1);
8770Sstevel@tonic-gate 	if (internal_attach_property(pg, p) != 0)
8780Sstevel@tonic-gate 		return (-1);
8790Sstevel@tonic-gate 
8800Sstevel@tonic-gate 	return (new_str_prop_from_attr(pg, SCF_PROPERTY_PROFILE,
8810Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, profile, name_attr));
8820Sstevel@tonic-gate }
8830Sstevel@tonic-gate 
8840Sstevel@tonic-gate static int
8850Sstevel@tonic-gate lxml_get_method_credential(pgroup_t *pg, xmlNodePtr cred)
8860Sstevel@tonic-gate {
8870Sstevel@tonic-gate 	property_t *p;
8880Sstevel@tonic-gate 
8890Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_USE_PROFILE, SCF_TYPE_BOOLEAN,
8900Sstevel@tonic-gate 	    1, (uint64_t)0);
8910Sstevel@tonic-gate 	if (internal_attach_property(pg, p) != 0)
8920Sstevel@tonic-gate 		return (-1);
8930Sstevel@tonic-gate 
8949263SSean.Wilcox@Sun.COM 	if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_USER, SCF_TYPE_ASTRING,
8959263SSean.Wilcox@Sun.COM 	    cred, "user", NULL) != 0)
8960Sstevel@tonic-gate 		return (-1);
8970Sstevel@tonic-gate 
8989263SSean.Wilcox@Sun.COM 	if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_GROUP, SCF_TYPE_ASTRING,
8999263SSean.Wilcox@Sun.COM 	    cred, "group", NULL) != 0)
9000Sstevel@tonic-gate 		return (-1);
9010Sstevel@tonic-gate 
9029263SSean.Wilcox@Sun.COM 	if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_SUPP_GROUPS,
9039263SSean.Wilcox@Sun.COM 	    SCF_TYPE_ASTRING, cred, "supp_groups", NULL) != 0)
9040Sstevel@tonic-gate 		return (-1);
9050Sstevel@tonic-gate 
9069263SSean.Wilcox@Sun.COM 	if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_PRIVILEGES,
9079263SSean.Wilcox@Sun.COM 	    SCF_TYPE_ASTRING, cred, "privileges", NULL) != 0)
9080Sstevel@tonic-gate 		return (-1);
9090Sstevel@tonic-gate 
9109263SSean.Wilcox@Sun.COM 	if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_LIMIT_PRIVILEGES,
9119263SSean.Wilcox@Sun.COM 	    SCF_TYPE_ASTRING, cred, "limit_privileges", NULL) != 0)
9120Sstevel@tonic-gate 		return (-1);
9130Sstevel@tonic-gate 
9140Sstevel@tonic-gate 	return (0);
9150Sstevel@tonic-gate }
9160Sstevel@tonic-gate 
9170Sstevel@tonic-gate static char *
9180Sstevel@tonic-gate lxml_get_envvar(xmlNodePtr envvar)
9190Sstevel@tonic-gate {
9200Sstevel@tonic-gate 	char *name;
9210Sstevel@tonic-gate 	char *value;
9220Sstevel@tonic-gate 	char *ret;
9230Sstevel@tonic-gate 
9247887SLiane.Praza@Sun.COM 	name = (char *)xmlGetProp(envvar, (xmlChar *)name_attr);
9257887SLiane.Praza@Sun.COM 	value = (char *)xmlGetProp(envvar, (xmlChar *)value_attr);
9260Sstevel@tonic-gate 
9270Sstevel@tonic-gate 	if (strlen(name) == 0 || strchr(name, '=') != NULL)
9280Sstevel@tonic-gate 		uu_die(gettext("Invalid environment variable "
9290Sstevel@tonic-gate 		    "\"%s\".\n"), name);
9300Sstevel@tonic-gate 	if (strstr(name, "SMF_") == name)
9310Sstevel@tonic-gate 		uu_die(gettext("Invalid environment variable "
9320Sstevel@tonic-gate 		    "\"%s\"; \"SMF_\" prefix is reserved.\n"), name);
9330Sstevel@tonic-gate 
9340Sstevel@tonic-gate 	ret = uu_msprintf("%s=%s", name, value);
9350Sstevel@tonic-gate 	xmlFree(name);
9360Sstevel@tonic-gate 	xmlFree(value);
9370Sstevel@tonic-gate 	return (ret);
9380Sstevel@tonic-gate }
9390Sstevel@tonic-gate 
9400Sstevel@tonic-gate static int
9410Sstevel@tonic-gate lxml_get_method_environment(pgroup_t *pg, xmlNodePtr environment)
9420Sstevel@tonic-gate {
9430Sstevel@tonic-gate 	property_t *p;
9440Sstevel@tonic-gate 	xmlNodePtr cursor;
9450Sstevel@tonic-gate 	value_t *val;
9460Sstevel@tonic-gate 
9470Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_ENVIRONMENT,
9480Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, 0);
9490Sstevel@tonic-gate 
9500Sstevel@tonic-gate 	for (cursor = environment->xmlChildrenNode; cursor != NULL;
9510Sstevel@tonic-gate 	    cursor = cursor->next) {
9520Sstevel@tonic-gate 		char *tmp;
9530Sstevel@tonic-gate 
9540Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
9550Sstevel@tonic-gate 			continue;
9560Sstevel@tonic-gate 
9570Sstevel@tonic-gate 		if (lxml_xlate_element(cursor->name) != SC_METHOD_ENVVAR)
9580Sstevel@tonic-gate 			uu_die(gettext("illegal element \"%s\" on "
9590Sstevel@tonic-gate 			    "method environment for \"%s\"\n"),
9600Sstevel@tonic-gate 			    cursor->name, pg->sc_pgroup_name);
9610Sstevel@tonic-gate 
9620Sstevel@tonic-gate 		if ((tmp = lxml_get_envvar(cursor)) == NULL)
9630Sstevel@tonic-gate 			uu_die(gettext("Out of memory\n"));
9640Sstevel@tonic-gate 
9650Sstevel@tonic-gate 		val = internal_value_new();
9660Sstevel@tonic-gate 		val->sc_u.sc_string = tmp;
9670Sstevel@tonic-gate 		val->sc_type = SCF_TYPE_ASTRING;
9680Sstevel@tonic-gate 		val->sc_free = lxml_free_str;
9690Sstevel@tonic-gate 		internal_attach_value(p, val);
9700Sstevel@tonic-gate 	}
9710Sstevel@tonic-gate 
9720Sstevel@tonic-gate 	if (internal_attach_property(pg, p) != 0) {
9730Sstevel@tonic-gate 		internal_property_free(p);
9740Sstevel@tonic-gate 		return (-1);
9750Sstevel@tonic-gate 	}
9760Sstevel@tonic-gate 
9770Sstevel@tonic-gate 	return (0);
9780Sstevel@tonic-gate }
9790Sstevel@tonic-gate 
9800Sstevel@tonic-gate static int
9810Sstevel@tonic-gate lxml_get_method_context(pgroup_t *pg, xmlNodePtr ctx)
9820Sstevel@tonic-gate {
9830Sstevel@tonic-gate 	xmlNodePtr cursor;
9840Sstevel@tonic-gate 
9859263SSean.Wilcox@Sun.COM 	if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_WORKING_DIRECTORY,
9869263SSean.Wilcox@Sun.COM 	    SCF_TYPE_ASTRING, ctx, "working_directory", NULL) != 0)
9870Sstevel@tonic-gate 		return (-1);
9880Sstevel@tonic-gate 
9899263SSean.Wilcox@Sun.COM 	if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_PROJECT,
9909263SSean.Wilcox@Sun.COM 	    SCF_TYPE_ASTRING, ctx, "project", NULL) != 0)
9910Sstevel@tonic-gate 		return (-1);
9920Sstevel@tonic-gate 
9939263SSean.Wilcox@Sun.COM 	if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_RESOURCE_POOL,
9949263SSean.Wilcox@Sun.COM 	    SCF_TYPE_ASTRING, ctx, "resource_pool", NULL) != 0)
9950Sstevel@tonic-gate 		return (-1);
9960Sstevel@tonic-gate 
9970Sstevel@tonic-gate 	for (cursor = ctx->xmlChildrenNode; cursor != NULL;
9980Sstevel@tonic-gate 	    cursor = cursor->next) {
9990Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
10000Sstevel@tonic-gate 			continue;
10010Sstevel@tonic-gate 
10020Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
10030Sstevel@tonic-gate 		case SC_METHOD_CREDENTIAL:
10040Sstevel@tonic-gate 			(void) lxml_get_method_credential(pg, cursor);
10050Sstevel@tonic-gate 			break;
10060Sstevel@tonic-gate 		case SC_METHOD_PROFILE:
10070Sstevel@tonic-gate 			(void) lxml_get_method_profile(pg, cursor);
10080Sstevel@tonic-gate 			break;
10090Sstevel@tonic-gate 		case SC_METHOD_ENVIRONMENT:
10100Sstevel@tonic-gate 			(void) lxml_get_method_environment(pg, cursor);
10110Sstevel@tonic-gate 			break;
10120Sstevel@tonic-gate 		default:
10130Sstevel@tonic-gate 			semerr(gettext("illegal element \'%s\' in method "
10140Sstevel@tonic-gate 			    "context\n"), (char *)cursor);
10150Sstevel@tonic-gate 			break;
10160Sstevel@tonic-gate 		}
10170Sstevel@tonic-gate 	}
10180Sstevel@tonic-gate 
10190Sstevel@tonic-gate 	return (0);
10200Sstevel@tonic-gate }
10210Sstevel@tonic-gate 
10220Sstevel@tonic-gate static int
10230Sstevel@tonic-gate lxml_get_entity_method_context(entity_t *entity, xmlNodePtr ctx)
10240Sstevel@tonic-gate {
10250Sstevel@tonic-gate 	pgroup_t *pg;
10260Sstevel@tonic-gate 
10270Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(entity, SCF_PG_METHOD_CONTEXT,
10280Sstevel@tonic-gate 	    (char *)scf_group_framework);
10290Sstevel@tonic-gate 
10300Sstevel@tonic-gate 	return (lxml_get_method_context(pg, ctx));
10310Sstevel@tonic-gate }
10320Sstevel@tonic-gate 
10330Sstevel@tonic-gate static int
10340Sstevel@tonic-gate lxml_get_exec_method(entity_t *entity, xmlNodePtr emeth)
10350Sstevel@tonic-gate {
10360Sstevel@tonic-gate 	pgroup_t *pg;
10370Sstevel@tonic-gate 	property_t *p;
10380Sstevel@tonic-gate 	xmlChar *name, *timeout, *delete;
10390Sstevel@tonic-gate 	xmlNodePtr cursor;
10400Sstevel@tonic-gate 	int r = 0;
10410Sstevel@tonic-gate 
1042*12667SSean.Wilcox@Sun.COM 	if (entity->sc_op == SVCCFG_OP_APPLY)
1043*12667SSean.Wilcox@Sun.COM 		lxml_validate_element(emeth);
1044*12667SSean.Wilcox@Sun.COM 
10450Sstevel@tonic-gate 	name = xmlGetProp(emeth, (xmlChar *)name_attr);
10460Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(entity, (char *)name,
10470Sstevel@tonic-gate 	    (char *)SCF_GROUP_METHOD);
10480Sstevel@tonic-gate 	xmlFree(name);
10490Sstevel@tonic-gate 
10500Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_TYPE, SCF_TYPE_ASTRING,
10510Sstevel@tonic-gate 	    emeth, type_attr) != 0 ||
10520Sstevel@tonic-gate 	    new_str_prop_from_attr(pg, SCF_PROPERTY_EXEC, SCF_TYPE_ASTRING,
10530Sstevel@tonic-gate 	    emeth, "exec") != 0)
10540Sstevel@tonic-gate 		return (-1);
10550Sstevel@tonic-gate 
10567887SLiane.Praza@Sun.COM 	timeout = xmlGetProp(emeth, (xmlChar *)timeout_seconds_attr);
10570Sstevel@tonic-gate 	if (timeout != NULL) {
10580Sstevel@tonic-gate 		uint64_t u_timeout;
10590Sstevel@tonic-gate 		char *endptr;
10600Sstevel@tonic-gate 		/*
10610Sstevel@tonic-gate 		 * Although an SC_COUNT represents a uint64_t the use
10620Sstevel@tonic-gate 		 * of a negative value is acceptable due to the usage
10630Sstevel@tonic-gate 		 * established by inetd(1M).
10640Sstevel@tonic-gate 		 */
10650Sstevel@tonic-gate 		errno = 0;
10660Sstevel@tonic-gate 		u_timeout = strtoull((char *)timeout, &endptr, 10);
10670Sstevel@tonic-gate 		if (errno != 0 || endptr == (char *)timeout || *endptr)
10680Sstevel@tonic-gate 			uu_die(gettext("illegal value \"%s\" for "
10690Sstevel@tonic-gate 			    "timeout_seconds (%s)\n"),
10700Sstevel@tonic-gate 			    (char *)timeout, (errno) ? strerror(errno):
10710Sstevel@tonic-gate 			    gettext("Illegal character"));
10720Sstevel@tonic-gate 		p = internal_property_create(SCF_PROPERTY_TIMEOUT,
10730Sstevel@tonic-gate 		    SCF_TYPE_COUNT, 1, u_timeout);
10740Sstevel@tonic-gate 		r = internal_attach_property(pg, p);
10750Sstevel@tonic-gate 		xmlFree(timeout);
10760Sstevel@tonic-gate 	}
10770Sstevel@tonic-gate 	if (r != 0)
10780Sstevel@tonic-gate 		return (-1);
10790Sstevel@tonic-gate 
10800Sstevel@tonic-gate 	/*
10810Sstevel@tonic-gate 	 * There is a possibility that a method context also exists, in which
10820Sstevel@tonic-gate 	 * case the following attributes are defined: project, resource_pool,
10830Sstevel@tonic-gate 	 * working_directory, profile, user, group, privileges, limit_privileges
10840Sstevel@tonic-gate 	 */
10850Sstevel@tonic-gate 	for (cursor = emeth->xmlChildrenNode; cursor != NULL;
10860Sstevel@tonic-gate 	    cursor = cursor->next) {
10870Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
10880Sstevel@tonic-gate 			continue;
10890Sstevel@tonic-gate 
10900Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
10910Sstevel@tonic-gate 		case SC_STABILITY:
10920Sstevel@tonic-gate 			if (lxml_get_pgroup_stability(pg, cursor) != 0)
10930Sstevel@tonic-gate 				return (-1);
10940Sstevel@tonic-gate 			break;
10950Sstevel@tonic-gate 
10960Sstevel@tonic-gate 		case SC_METHOD_CONTEXT:
10970Sstevel@tonic-gate 			(void) lxml_get_method_context(pg, cursor);
10980Sstevel@tonic-gate 			break;
10990Sstevel@tonic-gate 
11000Sstevel@tonic-gate 		case SC_PROPVAL:
11010Sstevel@tonic-gate 			(void) lxml_get_propval(pg, cursor);
11020Sstevel@tonic-gate 			break;
11030Sstevel@tonic-gate 
11040Sstevel@tonic-gate 		case SC_PROPERTY:
11050Sstevel@tonic-gate 			(void) lxml_get_property(pg, cursor);
11060Sstevel@tonic-gate 			break;
11070Sstevel@tonic-gate 
11080Sstevel@tonic-gate 		default:
11090Sstevel@tonic-gate 			uu_die(gettext("illegal element \"%s\" on "
11100Sstevel@tonic-gate 			    "execution method \"%s\"\n"), cursor->name,
11110Sstevel@tonic-gate 			    pg->sc_pgroup_name);
11120Sstevel@tonic-gate 			break;
11130Sstevel@tonic-gate 		}
11140Sstevel@tonic-gate 	}
11150Sstevel@tonic-gate 
11160Sstevel@tonic-gate 	delete = xmlGetProp(emeth, (xmlChar *)delete_attr);
11170Sstevel@tonic-gate 	pg->sc_pgroup_delete = (xmlStrcmp(delete, (xmlChar *)true) == 0);
11180Sstevel@tonic-gate 	xmlFree(delete);
11190Sstevel@tonic-gate 
11200Sstevel@tonic-gate 	return (0);
11210Sstevel@tonic-gate }
11220Sstevel@tonic-gate 
11230Sstevel@tonic-gate static int
11240Sstevel@tonic-gate lxml_get_dependency(entity_t *entity, xmlNodePtr dependency)
11250Sstevel@tonic-gate {
11260Sstevel@tonic-gate 	pgroup_t *pg;
11270Sstevel@tonic-gate 	property_t *p;
11280Sstevel@tonic-gate 	xmlNodePtr cursor;
11290Sstevel@tonic-gate 	xmlChar *name;
11300Sstevel@tonic-gate 	xmlChar *delete;
11310Sstevel@tonic-gate 
11320Sstevel@tonic-gate 	/*
11330Sstevel@tonic-gate 	 * dependency attributes:
11340Sstevel@tonic-gate 	 * name: string
11350Sstevel@tonic-gate 	 * grouping: require_all | require_any | exclude_all | optional_all
11360Sstevel@tonic-gate 	 * reset_on: string (error | restart | refresh | none)
11370Sstevel@tonic-gate 	 * type:  service / path /host
11380Sstevel@tonic-gate 	 */
11390Sstevel@tonic-gate 
1140*12667SSean.Wilcox@Sun.COM 	if (entity->sc_op == SVCCFG_OP_APPLY)
1141*12667SSean.Wilcox@Sun.COM 		lxml_validate_element(dependency);
1142*12667SSean.Wilcox@Sun.COM 
11430Sstevel@tonic-gate 	name = xmlGetProp(dependency, (xmlChar *)name_attr);
11440Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(entity, (char *)name,
11450Sstevel@tonic-gate 	    (char *)SCF_GROUP_DEPENDENCY);
11460Sstevel@tonic-gate 	xmlFree(name);
11470Sstevel@tonic-gate 
11480Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_TYPE, SCF_TYPE_ASTRING,
11490Sstevel@tonic-gate 	    dependency, type_attr) != 0)
11500Sstevel@tonic-gate 		return (-1);
11510Sstevel@tonic-gate 
11520Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_RESTART_ON,
11530Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, dependency, "restart_on") != 0)
11540Sstevel@tonic-gate 		return (-1);
11550Sstevel@tonic-gate 
11560Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_GROUPING, SCF_TYPE_ASTRING,
11570Sstevel@tonic-gate 	    dependency, "grouping") != 0)
11580Sstevel@tonic-gate 		return (-1);
11590Sstevel@tonic-gate 
11600Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_ENTITIES, SCF_TYPE_FMRI, 0);
11610Sstevel@tonic-gate 	if (internal_attach_property(pg, p) != 0)
11620Sstevel@tonic-gate 		return (-1);
11630Sstevel@tonic-gate 
11640Sstevel@tonic-gate 	for (cursor = dependency->xmlChildrenNode; cursor != NULL;
11650Sstevel@tonic-gate 	    cursor = cursor->next) {
11660Sstevel@tonic-gate 		xmlChar *value;
11670Sstevel@tonic-gate 		value_t *v;
11680Sstevel@tonic-gate 
11690Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
11700Sstevel@tonic-gate 			continue;
11710Sstevel@tonic-gate 
11720Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
11730Sstevel@tonic-gate 		case SC_STABILITY:
11740Sstevel@tonic-gate 			if (lxml_get_pgroup_stability(pg, cursor) != 0)
11750Sstevel@tonic-gate 				return (-1);
11760Sstevel@tonic-gate 			break;
11770Sstevel@tonic-gate 
11780Sstevel@tonic-gate 		case SC_SERVICE_FMRI:
11790Sstevel@tonic-gate 			value = xmlGetProp(cursor, (xmlChar *)value_attr);
11800Sstevel@tonic-gate 			if (value != NULL) {
11810Sstevel@tonic-gate 				if (lxml_validate_string_value(SCF_TYPE_FMRI,
11820Sstevel@tonic-gate 				    (char *)value) != 0)
11830Sstevel@tonic-gate 					uu_die(gettext("illegal value \"%s\" "
11840Sstevel@tonic-gate 					    "for %s (%s)\n"), (char *)value,
11850Sstevel@tonic-gate 					    lxml_prop_types[SC_FMRI],
11860Sstevel@tonic-gate 					    (scf_error()) ?
11870Sstevel@tonic-gate 					    scf_strerror(scf_error()) :
11880Sstevel@tonic-gate 					    gettext("Illegal format"));
11890Sstevel@tonic-gate 				v = internal_value_new();
11900Sstevel@tonic-gate 				v->sc_type = SCF_TYPE_FMRI;
11910Sstevel@tonic-gate 				v->sc_u.sc_string = (char *)value;
11920Sstevel@tonic-gate 				internal_attach_value(p, v);
11930Sstevel@tonic-gate 			}
11940Sstevel@tonic-gate 
11950Sstevel@tonic-gate 			break;
11960Sstevel@tonic-gate 
11970Sstevel@tonic-gate 		case SC_PROPVAL:
11980Sstevel@tonic-gate 			(void) lxml_get_propval(pg, cursor);
11990Sstevel@tonic-gate 			break;
12000Sstevel@tonic-gate 
12010Sstevel@tonic-gate 		case SC_PROPERTY:
12020Sstevel@tonic-gate 			(void) lxml_get_property(pg, cursor);
12030Sstevel@tonic-gate 			break;
12040Sstevel@tonic-gate 
12050Sstevel@tonic-gate 		default:
12060Sstevel@tonic-gate 			uu_die(gettext("illegal element \"%s\" on "
12070Sstevel@tonic-gate 			    "dependency group \"%s\"\n"), cursor->name, name);
12080Sstevel@tonic-gate 			break;
12090Sstevel@tonic-gate 		}
12100Sstevel@tonic-gate 	}
12110Sstevel@tonic-gate 
12120Sstevel@tonic-gate 	delete = xmlGetProp(dependency, (xmlChar *)delete_attr);
12130Sstevel@tonic-gate 	pg->sc_pgroup_delete = (xmlStrcmp(delete, (xmlChar *)true) == 0);
12140Sstevel@tonic-gate 	xmlFree(delete);
12150Sstevel@tonic-gate 
12160Sstevel@tonic-gate 	return (0);
12170Sstevel@tonic-gate }
12180Sstevel@tonic-gate 
12190Sstevel@tonic-gate /*
12200Sstevel@tonic-gate  * Dependents are hairy.  They should cause a dependency pg to be created in
12210Sstevel@tonic-gate  * another service, but we can't do that here; we'll have to wait until the
12220Sstevel@tonic-gate  * import routines.  So for now we'll add the dependency group that should go
12230Sstevel@tonic-gate  * in the other service to the entity's dependent list.
12240Sstevel@tonic-gate  */
12250Sstevel@tonic-gate static int
12260Sstevel@tonic-gate lxml_get_dependent(entity_t *entity, xmlNodePtr dependent)
12270Sstevel@tonic-gate {
12280Sstevel@tonic-gate 	xmlChar *name, *or;
12290Sstevel@tonic-gate 	xmlNodePtr sf;
12300Sstevel@tonic-gate 	xmlChar *fmri, *delete;
12310Sstevel@tonic-gate 	pgroup_t *pg;
12320Sstevel@tonic-gate 	property_t *p;
12330Sstevel@tonic-gate 	xmlNodePtr n;
12340Sstevel@tonic-gate 	char *myfmri;
12350Sstevel@tonic-gate 
1236*12667SSean.Wilcox@Sun.COM 	if (entity->sc_op == SVCCFG_OP_APPLY)
1237*12667SSean.Wilcox@Sun.COM 		lxml_validate_element(dependent);
1238*12667SSean.Wilcox@Sun.COM 
12390Sstevel@tonic-gate 	name = xmlGetProp(dependent, (xmlChar *)name_attr);
12400Sstevel@tonic-gate 
12410Sstevel@tonic-gate 	if (internal_pgroup_find(entity, (char *)name, NULL) != NULL) {
12420Sstevel@tonic-gate 		semerr(gettext("Property group and dependent of entity %s "
12430Sstevel@tonic-gate 		    "have same name \"%s\".\n"), entity->sc_name, name);
12440Sstevel@tonic-gate 		xmlFree(name);
12450Sstevel@tonic-gate 		return (-1);
12460Sstevel@tonic-gate 	}
12470Sstevel@tonic-gate 
12480Sstevel@tonic-gate 	or = xmlGetProp(dependent, (xmlChar *)override_attr);
12490Sstevel@tonic-gate 
12500Sstevel@tonic-gate 	pg = internal_pgroup_new();
12510Sstevel@tonic-gate 	pg->sc_pgroup_name = (char *)name;
12520Sstevel@tonic-gate 	pg->sc_pgroup_type = (char *)SCF_GROUP_DEPENDENCY;
12530Sstevel@tonic-gate 	pg->sc_pgroup_override = (xmlStrcmp(or, (xmlChar *)true) == 0);
12540Sstevel@tonic-gate 	xmlFree(or);
12550Sstevel@tonic-gate 	if (internal_attach_dependent(entity, pg) != 0) {
12560Sstevel@tonic-gate 		xmlFree(name);
12570Sstevel@tonic-gate 		internal_pgroup_free(pg);
12580Sstevel@tonic-gate 		return (-1);
12590Sstevel@tonic-gate 	}
12600Sstevel@tonic-gate 
12610Sstevel@tonic-gate 	for (sf = dependent->children; sf != NULL; sf = sf->next)
12620Sstevel@tonic-gate 		if (xmlStrcmp(sf->name, (xmlChar *)"service_fmri") == 0)
12630Sstevel@tonic-gate 			break;
12640Sstevel@tonic-gate 	assert(sf != NULL);
12650Sstevel@tonic-gate 	fmri = xmlGetProp(sf, (xmlChar *)value_attr);
12660Sstevel@tonic-gate 	pg->sc_pgroup_fmri = (char *)fmri;
12670Sstevel@tonic-gate 
12680Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_RESTART_ON,
12690Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, dependent, "restart_on") != 0)
12700Sstevel@tonic-gate 		return (-1);
12710Sstevel@tonic-gate 
12720Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_GROUPING, SCF_TYPE_ASTRING,
12730Sstevel@tonic-gate 	    dependent, "grouping") != 0)
12740Sstevel@tonic-gate 		return (-1);
12750Sstevel@tonic-gate 
12760Sstevel@tonic-gate 	myfmri = safe_malloc(max_scf_fmri_len + 1);
12770Sstevel@tonic-gate 	if (entity->sc_etype == SVCCFG_SERVICE_OBJECT) {
12780Sstevel@tonic-gate 		if (snprintf(myfmri, max_scf_fmri_len + 1, "svc:/%s",
12790Sstevel@tonic-gate 		    entity->sc_name) < 0)
12800Sstevel@tonic-gate 			bad_error("snprintf", errno);
12810Sstevel@tonic-gate 	} else {
12820Sstevel@tonic-gate 		assert(entity->sc_etype == SVCCFG_INSTANCE_OBJECT);
12830Sstevel@tonic-gate 		if (snprintf(myfmri, max_scf_fmri_len + 1, "svc:/%s:%s",
12840Sstevel@tonic-gate 		    entity->sc_parent->sc_name, entity->sc_name) < 0)
12850Sstevel@tonic-gate 			bad_error("snprintf", errno);
12860Sstevel@tonic-gate 	}
12870Sstevel@tonic-gate 
12880Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_ENTITIES, SCF_TYPE_FMRI, 1,
12890Sstevel@tonic-gate 	    myfmri);
12900Sstevel@tonic-gate 	if (internal_attach_property(pg, p) != 0)
12910Sstevel@tonic-gate 		return (-1);
12920Sstevel@tonic-gate 
12930Sstevel@tonic-gate 	/* Create a property to serve as a do-not-export flag. */
12940Sstevel@tonic-gate 	p = internal_property_create("external", SCF_TYPE_BOOLEAN, 1,
12950Sstevel@tonic-gate 	    (uint64_t)1);
12960Sstevel@tonic-gate 	if (internal_attach_property(pg, p) != 0)
12970Sstevel@tonic-gate 		return (-1);
12980Sstevel@tonic-gate 
12990Sstevel@tonic-gate 	for (n = sf->next; n != NULL; n = n->next) {
13000Sstevel@tonic-gate 		if (lxml_ignorable_block(n))
13010Sstevel@tonic-gate 			continue;
13020Sstevel@tonic-gate 
13030Sstevel@tonic-gate 		switch (lxml_xlate_element(n->name)) {
13040Sstevel@tonic-gate 		case SC_STABILITY:
13050Sstevel@tonic-gate 			if (new_str_prop_from_attr(pg,
13060Sstevel@tonic-gate 			    SCF_PROPERTY_ENTITY_STABILITY, SCF_TYPE_ASTRING, n,
13070Sstevel@tonic-gate 			    value_attr) != 0)
13080Sstevel@tonic-gate 				return (-1);
13090Sstevel@tonic-gate 			break;
13100Sstevel@tonic-gate 
13110Sstevel@tonic-gate 		case SC_PROPVAL:
13120Sstevel@tonic-gate 			(void) lxml_get_propval(pg, n);
13130Sstevel@tonic-gate 			break;
13140Sstevel@tonic-gate 
13150Sstevel@tonic-gate 		case SC_PROPERTY:
13160Sstevel@tonic-gate 			(void) lxml_get_property(pg, n);
13170Sstevel@tonic-gate 			break;
13180Sstevel@tonic-gate 
13190Sstevel@tonic-gate 		default:
13200Sstevel@tonic-gate 			uu_die(gettext("unexpected element %s.\n"), n->name);
13210Sstevel@tonic-gate 		}
13220Sstevel@tonic-gate 	}
13230Sstevel@tonic-gate 
13240Sstevel@tonic-gate 	/* Go back and fill in defaults. */
13250Sstevel@tonic-gate 	if (internal_property_find(pg, SCF_PROPERTY_TYPE) == NULL) {
13260Sstevel@tonic-gate 		p = internal_property_create(SCF_PROPERTY_TYPE,
13270Sstevel@tonic-gate 		    SCF_TYPE_ASTRING, 1, "service");
13280Sstevel@tonic-gate 		if (internal_attach_property(pg, p) != 0)
13290Sstevel@tonic-gate 			return (-1);
13300Sstevel@tonic-gate 	}
13310Sstevel@tonic-gate 
13320Sstevel@tonic-gate 	delete = xmlGetProp(dependent, (xmlChar *)delete_attr);
13330Sstevel@tonic-gate 	pg->sc_pgroup_delete = (xmlStrcmp(delete, (xmlChar *)true) == 0);
13340Sstevel@tonic-gate 	xmlFree(delete);
13350Sstevel@tonic-gate 
13360Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(entity, "dependents",
13370Sstevel@tonic-gate 	    (char *)scf_group_framework);
1338306Sbustos 	p = internal_property_create((char *)name, SCF_TYPE_FMRI, 1, fmri);
13390Sstevel@tonic-gate 	if (internal_attach_property(pg, p) != 0)
13400Sstevel@tonic-gate 		return (-1);
13410Sstevel@tonic-gate 
13420Sstevel@tonic-gate 	return (0);
13430Sstevel@tonic-gate }
13440Sstevel@tonic-gate 
13450Sstevel@tonic-gate static int
13460Sstevel@tonic-gate lxml_get_entity_stability(entity_t *entity, xmlNodePtr rstr)
13470Sstevel@tonic-gate {
13480Sstevel@tonic-gate 	pgroup_t *pg;
13490Sstevel@tonic-gate 	property_t *p;
13500Sstevel@tonic-gate 	xmlChar *stabval;
13510Sstevel@tonic-gate 
13527887SLiane.Praza@Sun.COM 	if (((stabval = xmlGetProp(rstr, (xmlChar *)value_attr)) == NULL) ||
13537887SLiane.Praza@Sun.COM 	    (*stabval == 0)) {
13540Sstevel@tonic-gate 		uu_warn(gettext("no stability value found\n"));
13550Sstevel@tonic-gate 		stabval = (xmlChar *)strdup("External");
13560Sstevel@tonic-gate 	}
13570Sstevel@tonic-gate 
13580Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(entity, (char *)scf_pg_general,
13590Sstevel@tonic-gate 	    (char *)scf_group_framework);
13600Sstevel@tonic-gate 
13610Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_ENTITY_STABILITY,
13620Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, 1, stabval);
13630Sstevel@tonic-gate 
13640Sstevel@tonic-gate 	return (internal_attach_property(pg, p));
13650Sstevel@tonic-gate }
13660Sstevel@tonic-gate 
13670Sstevel@tonic-gate static int
13680Sstevel@tonic-gate lxml_get_restarter(entity_t *entity, xmlNodePtr rstr)
13690Sstevel@tonic-gate {
13700Sstevel@tonic-gate 	pgroup_t *pg;
13710Sstevel@tonic-gate 	property_t *p;
13720Sstevel@tonic-gate 	xmlChar *restarter;
13730Sstevel@tonic-gate 	xmlNode *cursor;
13740Sstevel@tonic-gate 	int r;
13750Sstevel@tonic-gate 
13760Sstevel@tonic-gate 	/*
13770Sstevel@tonic-gate 	 * Go find child.  Child is a service_fmri element.  value attribute
13780Sstevel@tonic-gate 	 * contains restarter FMRI.
13790Sstevel@tonic-gate 	 */
13800Sstevel@tonic-gate 
13810Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(entity, (char *)scf_pg_general,
13820Sstevel@tonic-gate 	    (char *)scf_group_framework);
13830Sstevel@tonic-gate 
13840Sstevel@tonic-gate 	/*
13850Sstevel@tonic-gate 	 * Walk its child elements, as appropriate.
13860Sstevel@tonic-gate 	 */
13870Sstevel@tonic-gate 	for (cursor = rstr->xmlChildrenNode; cursor != NULL;
13880Sstevel@tonic-gate 	    cursor = cursor->next) {
13890Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
13900Sstevel@tonic-gate 			continue;
13910Sstevel@tonic-gate 
13920Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
13930Sstevel@tonic-gate 		case SC_SERVICE_FMRI:
13940Sstevel@tonic-gate 			restarter = xmlGetProp(cursor, (xmlChar *)value_attr);
13950Sstevel@tonic-gate 			break;
13960Sstevel@tonic-gate 		default:
13970Sstevel@tonic-gate 			uu_die(gettext("illegal element \"%s\" on restarter "
13980Sstevel@tonic-gate 			    "element for \"%s\"\n"), cursor->name,
13990Sstevel@tonic-gate 			    entity->sc_name);
14000Sstevel@tonic-gate 			break;
14010Sstevel@tonic-gate 		}
14020Sstevel@tonic-gate 	}
14030Sstevel@tonic-gate 
14040Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_RESTARTER, SCF_TYPE_FMRI, 1,
14050Sstevel@tonic-gate 	    restarter);
14060Sstevel@tonic-gate 
14070Sstevel@tonic-gate 	r = internal_attach_property(pg, p);
14080Sstevel@tonic-gate 	if (r != 0) {
14090Sstevel@tonic-gate 		internal_property_free(p);
14100Sstevel@tonic-gate 		return (-1);
14110Sstevel@tonic-gate 	}
14120Sstevel@tonic-gate 
14130Sstevel@tonic-gate 	return (0);
14140Sstevel@tonic-gate }
14150Sstevel@tonic-gate 
14167887SLiane.Praza@Sun.COM /*
14177887SLiane.Praza@Sun.COM  * Add a property containing the localized text from the manifest.  The
14187887SLiane.Praza@Sun.COM  * property is added to the property group at pg.  The name of the created
14197887SLiane.Praza@Sun.COM  * property is based on the format at pn_format.  This is an snprintf(3C)
14207887SLiane.Praza@Sun.COM  * format containing a single %s conversion specification.  At conversion
14217887SLiane.Praza@Sun.COM  * time, the %s is replaced by the locale designation.
14227887SLiane.Praza@Sun.COM  *
14237887SLiane.Praza@Sun.COM  * source is the source element and it is only used for error messages.
14247887SLiane.Praza@Sun.COM  */
14257887SLiane.Praza@Sun.COM static int
14267887SLiane.Praza@Sun.COM lxml_get_loctext(entity_t *service, pgroup_t *pg, xmlNodePtr loctext,
14277887SLiane.Praza@Sun.COM     const char *pn_format, const char *source)
14280Sstevel@tonic-gate {
14297887SLiane.Praza@Sun.COM 	int extra;
14300Sstevel@tonic-gate 	xmlNodePtr cursor;
14310Sstevel@tonic-gate 	xmlChar *val;
14320Sstevel@tonic-gate 	char *stripped, *cp;
14330Sstevel@tonic-gate 	property_t *p;
14347887SLiane.Praza@Sun.COM 	char *prop_name;
14350Sstevel@tonic-gate 	int r;
14360Sstevel@tonic-gate 
14377887SLiane.Praza@Sun.COM 	if (((val = xmlGetProp(loctext, (xmlChar *)xml_lang_attr)) == NULL) ||
14387887SLiane.Praza@Sun.COM 	    (*val == 0)) {
14397887SLiane.Praza@Sun.COM 		if (((val = xmlGetProp(loctext,
14407887SLiane.Praza@Sun.COM 		    (xmlChar *)lang_attr)) == NULL) || (*val == 0)) {
14410Sstevel@tonic-gate 			val = (xmlChar *)"unknown";
14427887SLiane.Praza@Sun.COM 		}
14437887SLiane.Praza@Sun.COM 	}
14447887SLiane.Praza@Sun.COM 
14457887SLiane.Praza@Sun.COM 	_scf_sanitize_locale((char *)val);
14467887SLiane.Praza@Sun.COM 	prop_name = safe_malloc(max_scf_name_len + 1);
14477887SLiane.Praza@Sun.COM 	if ((extra = snprintf(prop_name, max_scf_name_len + 1, pn_format,
14487887SLiane.Praza@Sun.COM 	    val)) >= max_scf_name_len + 1) {
14497887SLiane.Praza@Sun.COM 		extra -= max_scf_name_len;
14507887SLiane.Praza@Sun.COM 		uu_die(gettext("%s attribute is %d characters too long for "
14517887SLiane.Praza@Sun.COM 		    "%s in %s\n"),
14527887SLiane.Praza@Sun.COM 		    xml_lang_attr, extra, source, service->sc_name);
14537887SLiane.Praza@Sun.COM 	}
14547887SLiane.Praza@Sun.COM 	xmlFree(val);
14550Sstevel@tonic-gate 
14560Sstevel@tonic-gate 	for (cursor = loctext->xmlChildrenNode; cursor != NULL;
14570Sstevel@tonic-gate 	    cursor = cursor->next) {
14580Sstevel@tonic-gate 		if (strcmp("text", (const char *)cursor->name) == 0) {
14590Sstevel@tonic-gate 			break;
14600Sstevel@tonic-gate 		} else if (strcmp("comment", (const char *)cursor->name) != 0) {
14610Sstevel@tonic-gate 			uu_die(gettext("illegal element \"%s\" on loctext "
14620Sstevel@tonic-gate 			    "element for \"%s\"\n"), cursor->name,
14630Sstevel@tonic-gate 			    service->sc_name);
14640Sstevel@tonic-gate 		}
14650Sstevel@tonic-gate 	}
14660Sstevel@tonic-gate 
14670Sstevel@tonic-gate 	if (cursor == NULL) {
14680Sstevel@tonic-gate 		uu_die(gettext("loctext element has no content for \"%s\"\n"),
14690Sstevel@tonic-gate 		    service->sc_name);
14700Sstevel@tonic-gate 	}
14710Sstevel@tonic-gate 
14720Sstevel@tonic-gate 	/*
14730Sstevel@tonic-gate 	 * Remove leading and trailing whitespace.
14740Sstevel@tonic-gate 	 */
14750Sstevel@tonic-gate 	if ((stripped = strdup((const char *)cursor->content)) == NULL)
14760Sstevel@tonic-gate 		uu_die(gettext("Out of memory\n"));
14770Sstevel@tonic-gate 
14784740Sjeanm 	for (; isspace(*stripped); stripped++)
14794740Sjeanm 		;
14804740Sjeanm 	for (cp = stripped + strlen(stripped) - 1; isspace(*cp); cp--)
14814740Sjeanm 		;
14820Sstevel@tonic-gate 	*(cp + 1) = '\0';
14830Sstevel@tonic-gate 
14847887SLiane.Praza@Sun.COM 	p = internal_property_create(prop_name, SCF_TYPE_USTRING, 1,
14850Sstevel@tonic-gate 	    stripped);
14860Sstevel@tonic-gate 
14870Sstevel@tonic-gate 	r = internal_attach_property(pg, p);
14887887SLiane.Praza@Sun.COM 	if (r != 0) {
14890Sstevel@tonic-gate 		internal_property_free(p);
14907887SLiane.Praza@Sun.COM 		free(prop_name);
14917887SLiane.Praza@Sun.COM 	}
14920Sstevel@tonic-gate 
14930Sstevel@tonic-gate 	return (r);
14940Sstevel@tonic-gate }
14950Sstevel@tonic-gate 
14967887SLiane.Praza@Sun.COM /*
14977887SLiane.Praza@Sun.COM  * This function processes all loctext elements in the current XML element
14987887SLiane.Praza@Sun.COM  * designated by container.  A property is created for each loctext element
14997887SLiane.Praza@Sun.COM  * and added to the property group at pg.  The name of the property is
15007887SLiane.Praza@Sun.COM  * derived from the loctext language designation using the format at
15017887SLiane.Praza@Sun.COM  * pn_format.  pn_format should be an snprintf format string containing one
15027887SLiane.Praza@Sun.COM  * %s which is replaced by the language designation.
15037887SLiane.Praza@Sun.COM  *
15047887SLiane.Praza@Sun.COM  * The function returns 0 on success and -1 if it is unable to attach the
15057887SLiane.Praza@Sun.COM  * newly created property to pg.
15067887SLiane.Praza@Sun.COM  */
15070Sstevel@tonic-gate static int
15087887SLiane.Praza@Sun.COM lxml_get_all_loctext(entity_t *service, pgroup_t *pg, xmlNodePtr container,
15097887SLiane.Praza@Sun.COM     const char *pn_format, const char *source)
15100Sstevel@tonic-gate {
15110Sstevel@tonic-gate 	xmlNodePtr cursor;
15120Sstevel@tonic-gate 
15130Sstevel@tonic-gate 	/*
15147887SLiane.Praza@Sun.COM 	 * Iterate through one or more loctext elements.  The locale is
15157887SLiane.Praza@Sun.COM 	 * used to generate the property name; the contents are the ustring
15167887SLiane.Praza@Sun.COM 	 * value for the property.
15170Sstevel@tonic-gate 	 */
15187887SLiane.Praza@Sun.COM 	for (cursor = container->xmlChildrenNode; cursor != NULL;
15190Sstevel@tonic-gate 	    cursor = cursor->next) {
15200Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
15210Sstevel@tonic-gate 			continue;
15220Sstevel@tonic-gate 
15230Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
15240Sstevel@tonic-gate 		case SC_LOCTEXT:
15257887SLiane.Praza@Sun.COM 			if (lxml_get_loctext(service, pg, cursor, pn_format,
15267887SLiane.Praza@Sun.COM 			    source))
15270Sstevel@tonic-gate 				return (-1);
15280Sstevel@tonic-gate 			break;
15290Sstevel@tonic-gate 		default:
15307887SLiane.Praza@Sun.COM 			uu_die(gettext("illegal element \"%s\" on %s element "
15317887SLiane.Praza@Sun.COM 			    "for \"%s\"\n"), cursor->name, container->name,
15320Sstevel@tonic-gate 			    service->sc_name);
15330Sstevel@tonic-gate 			break;
15340Sstevel@tonic-gate 		}
15350Sstevel@tonic-gate 	}
15360Sstevel@tonic-gate 
15370Sstevel@tonic-gate 	return (0);
15380Sstevel@tonic-gate }
15390Sstevel@tonic-gate 
15407887SLiane.Praza@Sun.COM /*
15417887SLiane.Praza@Sun.COM  * Obtain the specified cardinality attribute and place it in a property
15427887SLiane.Praza@Sun.COM  * named prop_name.  The converted attribute is placed at *value, and the
15437887SLiane.Praza@Sun.COM  * newly created property is returned to propp.  NULL is returned to propp
15447887SLiane.Praza@Sun.COM  * if the attribute is not provided in the manifest.
15457887SLiane.Praza@Sun.COM  *
15467887SLiane.Praza@Sun.COM  * 0 is returned upon success, and -1 indicates that the manifest contained
15477887SLiane.Praza@Sun.COM  * an invalid cardinality value.
15487887SLiane.Praza@Sun.COM  */
15490Sstevel@tonic-gate static int
15507887SLiane.Praza@Sun.COM lxml_get_cardinality_attribute(entity_t *service, xmlNodePtr cursor,
15517887SLiane.Praza@Sun.COM     const char *attr_name, const char *prop_name, uint64_t *value,
15527887SLiane.Praza@Sun.COM     property_t **propp)
15537887SLiane.Praza@Sun.COM {
15547887SLiane.Praza@Sun.COM 	char *c;
15557887SLiane.Praza@Sun.COM 	property_t *p;
15567887SLiane.Praza@Sun.COM 	xmlChar *val;
15577887SLiane.Praza@Sun.COM 	uint64_t count;
15587887SLiane.Praza@Sun.COM 	char *endptr;
15597887SLiane.Praza@Sun.COM 
15607887SLiane.Praza@Sun.COM 	*propp = NULL;
15617887SLiane.Praza@Sun.COM 	val = xmlGetProp(cursor, (xmlChar *)attr_name);
15627887SLiane.Praza@Sun.COM 	if (val == NULL)
15637887SLiane.Praza@Sun.COM 		return (0);
15647887SLiane.Praza@Sun.COM 	if (*val == 0) {
15657887SLiane.Praza@Sun.COM 		xmlFree(val);
15667887SLiane.Praza@Sun.COM 		return (0);
15677887SLiane.Praza@Sun.COM 	}
15687887SLiane.Praza@Sun.COM 
15697887SLiane.Praza@Sun.COM 	/*
15707887SLiane.Praza@Sun.COM 	 * Make sure that the string at val doesn't have a leading minus
15717887SLiane.Praza@Sun.COM 	 * sign.  The strtoull() call below does not catch this problem.
15727887SLiane.Praza@Sun.COM 	 */
15737887SLiane.Praza@Sun.COM 	for (c = (char *)val; *c != 0; c++) {
15747887SLiane.Praza@Sun.COM 		if (isspace(*c))
15757887SLiane.Praza@Sun.COM 			continue;
15767887SLiane.Praza@Sun.COM 		if (isdigit(*c))
15777887SLiane.Praza@Sun.COM 			break;
15787887SLiane.Praza@Sun.COM 		semerr(gettext("\"%c\" is not a legal character in the %s "
15797887SLiane.Praza@Sun.COM 		    "attribute of the %s element in %s.\n"), *c,
15807887SLiane.Praza@Sun.COM 		    attr_name, prop_name, service->sc_name);
15817887SLiane.Praza@Sun.COM 		xmlFree(val);
15827887SLiane.Praza@Sun.COM 		return (-1);
15837887SLiane.Praza@Sun.COM 	}
15847887SLiane.Praza@Sun.COM 	errno = 0;
15857887SLiane.Praza@Sun.COM 	count = strtoull((char *)val, &endptr, 10);
15867887SLiane.Praza@Sun.COM 	if (errno != 0 || endptr == (char *)val || *endptr) {
15877887SLiane.Praza@Sun.COM 		semerr(gettext("\"%s\" is not a legal number for the %s "
15887887SLiane.Praza@Sun.COM 		    "attribute of the %s element in %s.\n"), (char *)val,
15897887SLiane.Praza@Sun.COM 		    attr_name, prop_name, service->sc_name);
15907887SLiane.Praza@Sun.COM 		xmlFree(val);
15917887SLiane.Praza@Sun.COM 		return (-1);
15927887SLiane.Praza@Sun.COM 	}
15937887SLiane.Praza@Sun.COM 
15947887SLiane.Praza@Sun.COM 	xmlFree(val);
15957887SLiane.Praza@Sun.COM 
15967887SLiane.Praza@Sun.COM 	/* Value is valid.  Create the property. */
15977887SLiane.Praza@Sun.COM 	p = internal_property_create(prop_name, SCF_TYPE_COUNT, 1, count);
15987887SLiane.Praza@Sun.COM 	*value = count;
15997887SLiane.Praza@Sun.COM 	*propp = p;
16007887SLiane.Praza@Sun.COM 	return (0);
16017887SLiane.Praza@Sun.COM }
16027887SLiane.Praza@Sun.COM 
16037887SLiane.Praza@Sun.COM /*
16047887SLiane.Praza@Sun.COM  * The cardinality is specified by two attributes max and min at cursor.
16057887SLiane.Praza@Sun.COM  * Both are optional, but if present they must be unsigned integers.
16067887SLiane.Praza@Sun.COM  */
16077887SLiane.Praza@Sun.COM static int
16087887SLiane.Praza@Sun.COM lxml_get_tm_cardinality(entity_t *service, pgroup_t *pg, xmlNodePtr cursor)
16090Sstevel@tonic-gate {
16107887SLiane.Praza@Sun.COM 	int min_attached = 0;
16117887SLiane.Praza@Sun.COM 	int compare = 1;
16127887SLiane.Praza@Sun.COM 	property_t *min_prop;
16137887SLiane.Praza@Sun.COM 	property_t *max_prop;
16147887SLiane.Praza@Sun.COM 	uint64_t max;
16157887SLiane.Praza@Sun.COM 	uint64_t min;
16167887SLiane.Praza@Sun.COM 	int r;
16177887SLiane.Praza@Sun.COM 
16187887SLiane.Praza@Sun.COM 	r = lxml_get_cardinality_attribute(service, cursor, min_attr,
16197887SLiane.Praza@Sun.COM 	    SCF_PROPERTY_TM_CARDINALITY_MIN, &min, &min_prop);
16207887SLiane.Praza@Sun.COM 	if (r != 0)
16217887SLiane.Praza@Sun.COM 		return (r);
16227887SLiane.Praza@Sun.COM 	if (min_prop == NULL)
16237887SLiane.Praza@Sun.COM 		compare = 0;
16247887SLiane.Praza@Sun.COM 	r = lxml_get_cardinality_attribute(service, cursor, max_attr,
16257887SLiane.Praza@Sun.COM 	    SCF_PROPERTY_TM_CARDINALITY_MAX, &max, &max_prop);
16267887SLiane.Praza@Sun.COM 	if (r != 0)
16277887SLiane.Praza@Sun.COM 		goto errout;
16287887SLiane.Praza@Sun.COM 	if ((max_prop != NULL) && (compare == 1)) {
16297887SLiane.Praza@Sun.COM 		if (max < min) {
16307887SLiane.Praza@Sun.COM 			semerr(gettext("Cardinality max is less than min for "
16317887SLiane.Praza@Sun.COM 			    "the %s element in %s.\n"), pg->sc_pgroup_name,
16327887SLiane.Praza@Sun.COM 			    service->sc_fmri);
16337887SLiane.Praza@Sun.COM 			goto errout;
16347887SLiane.Praza@Sun.COM 		}
16357887SLiane.Praza@Sun.COM 	}
16367887SLiane.Praza@Sun.COM 
16377887SLiane.Praza@Sun.COM 	/* Attach the properties to the property group. */
16387887SLiane.Praza@Sun.COM 	if (min_prop) {
16397887SLiane.Praza@Sun.COM 		if (internal_attach_property(pg, min_prop) == 0) {
16407887SLiane.Praza@Sun.COM 			min_attached = 1;
16417887SLiane.Praza@Sun.COM 		} else {
16427887SLiane.Praza@Sun.COM 			goto errout;
16437887SLiane.Praza@Sun.COM 		}
16447887SLiane.Praza@Sun.COM 	}
16457887SLiane.Praza@Sun.COM 	if (max_prop) {
16467887SLiane.Praza@Sun.COM 		if (internal_attach_property(pg, max_prop) != 0) {
16477887SLiane.Praza@Sun.COM 			if (min_attached)
16487887SLiane.Praza@Sun.COM 				internal_detach_property(pg, min_prop);
16497887SLiane.Praza@Sun.COM 			goto errout;
16507887SLiane.Praza@Sun.COM 		}
16517887SLiane.Praza@Sun.COM 	}
16527887SLiane.Praza@Sun.COM 	return (0);
16537887SLiane.Praza@Sun.COM 
16547887SLiane.Praza@Sun.COM errout:
16557887SLiane.Praza@Sun.COM 	if (min_prop)
16567887SLiane.Praza@Sun.COM 		internal_property_free(min_prop);
16577887SLiane.Praza@Sun.COM 	if (max_prop)
16587887SLiane.Praza@Sun.COM 		internal_property_free(max_prop);
16597887SLiane.Praza@Sun.COM 	return (-1);
16607887SLiane.Praza@Sun.COM }
16617887SLiane.Praza@Sun.COM 
16627887SLiane.Praza@Sun.COM /*
16637887SLiane.Praza@Sun.COM  * Get the common_name which is present as localized text at common_name in
16647887SLiane.Praza@Sun.COM  * the manifest.  The common_name is stored as the value of a property in
16657887SLiane.Praza@Sun.COM  * the property group whose name is SCF_PG_TM_COMMON_NAME and type is
16667887SLiane.Praza@Sun.COM  * SCF_GROUP_TEMPLATE.  This property group will be created in service if
16677887SLiane.Praza@Sun.COM  * it is not already there.
16687887SLiane.Praza@Sun.COM  */
16697887SLiane.Praza@Sun.COM static int
16707887SLiane.Praza@Sun.COM lxml_get_tm_common_name(entity_t *service, xmlNodePtr common_name)
16717887SLiane.Praza@Sun.COM {
16720Sstevel@tonic-gate 	pgroup_t *pg;
16730Sstevel@tonic-gate 
16740Sstevel@tonic-gate 	/*
16750Sstevel@tonic-gate 	 * Create the property group, if absent.
16760Sstevel@tonic-gate 	 */
16777887SLiane.Praza@Sun.COM 	pg = internal_pgroup_find_or_create(service, SCF_PG_TM_COMMON_NAME,
16787887SLiane.Praza@Sun.COM 	    SCF_GROUP_TEMPLATE);
16797887SLiane.Praza@Sun.COM 
16807887SLiane.Praza@Sun.COM 	return (lxml_get_all_loctext(service, pg, common_name, LOCALE_ONLY_FMT,
16817887SLiane.Praza@Sun.COM 	    "common_name"));
16827887SLiane.Praza@Sun.COM }
16837887SLiane.Praza@Sun.COM 
16847887SLiane.Praza@Sun.COM /*
16857887SLiane.Praza@Sun.COM  * Get the description which is present as localized text at description in
16867887SLiane.Praza@Sun.COM  * the manifest.  The description is stored as the value of a property in
16877887SLiane.Praza@Sun.COM  * the property group whose name is SCF_PG_TM_DESCRIPTION and type is
16887887SLiane.Praza@Sun.COM  * SCF_GROUP_TEMPLATE.  This property group will be created in service if
16897887SLiane.Praza@Sun.COM  * it is not already there.
16907887SLiane.Praza@Sun.COM  */
16917887SLiane.Praza@Sun.COM static int
16927887SLiane.Praza@Sun.COM lxml_get_tm_description(entity_t *service, xmlNodePtr description)
16937887SLiane.Praza@Sun.COM {
16947887SLiane.Praza@Sun.COM 	pgroup_t *pg;
16950Sstevel@tonic-gate 
16960Sstevel@tonic-gate 	/*
16977887SLiane.Praza@Sun.COM 	 * Create the property group, if absent.
16980Sstevel@tonic-gate 	 */
16997887SLiane.Praza@Sun.COM 	pg = internal_pgroup_find_or_create(service, SCF_PG_TM_DESCRIPTION,
17007887SLiane.Praza@Sun.COM 	    SCF_GROUP_TEMPLATE);
17017887SLiane.Praza@Sun.COM 
17027887SLiane.Praza@Sun.COM 	return (lxml_get_all_loctext(service, pg, description,
17037887SLiane.Praza@Sun.COM 	    LOCALE_ONLY_FMT, "description"));
17040Sstevel@tonic-gate }
17050Sstevel@tonic-gate 
17060Sstevel@tonic-gate static char *
17070Sstevel@tonic-gate lxml_label_to_groupname(const char *prefix, const char *in)
17080Sstevel@tonic-gate {
17090Sstevel@tonic-gate 	char *out, *cp;
17100Sstevel@tonic-gate 	size_t len, piece_len;
17110Sstevel@tonic-gate 
17120Sstevel@tonic-gate 	out = uu_zalloc(2 * scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1);
17130Sstevel@tonic-gate 	if (out == NULL)
17140Sstevel@tonic-gate 		return (NULL);
17150Sstevel@tonic-gate 
17160Sstevel@tonic-gate 	(void) strcpy(out, prefix);
17170Sstevel@tonic-gate 	(void) strcat(out, in);
17180Sstevel@tonic-gate 
17190Sstevel@tonic-gate 	len = strlen(out);
17200Sstevel@tonic-gate 	if (len > max_scf_name_len) {
17210Sstevel@tonic-gate 		/* Use the first half and the second half. */
17220Sstevel@tonic-gate 		piece_len = (max_scf_name_len - 2) / 2;
17230Sstevel@tonic-gate 
17240Sstevel@tonic-gate 		(void) strncpy(out + piece_len, "..", 2);
17250Sstevel@tonic-gate 
17260Sstevel@tonic-gate 		(void) strcpy(out + piece_len + 2, out + (len - piece_len));
17270Sstevel@tonic-gate 
17280Sstevel@tonic-gate 		len = strlen(out);
17290Sstevel@tonic-gate 	}
17300Sstevel@tonic-gate 
17310Sstevel@tonic-gate 	/*
17320Sstevel@tonic-gate 	 * Translate non-property characters to '_'.
17330Sstevel@tonic-gate 	 */
17340Sstevel@tonic-gate 	for (cp = out; *cp != '\0'; ++cp) {
17350Sstevel@tonic-gate 		if (!(isalnum(*cp) || *cp == '_' || *cp == '-'))
17360Sstevel@tonic-gate 			*cp = '_';
17370Sstevel@tonic-gate 	}
17380Sstevel@tonic-gate 
17390Sstevel@tonic-gate 	*cp = '\0';
17400Sstevel@tonic-gate 
17410Sstevel@tonic-gate 	return (out);
17420Sstevel@tonic-gate }
17430Sstevel@tonic-gate 
17447887SLiane.Praza@Sun.COM /*
17457887SLiane.Praza@Sun.COM  * If *p is NULL, astring_prop_value() first creates a property with the
17467887SLiane.Praza@Sun.COM  * name specified in prop_name.  The address of the newly created property
17477887SLiane.Praza@Sun.COM  * is placed in *p.
17487887SLiane.Praza@Sun.COM  *
17497887SLiane.Praza@Sun.COM  * In either case, newly created property or existing property, a new
17507887SLiane.Praza@Sun.COM  * SCF_TYPE_ASTRING value will created and attached to the property at *p.
17517887SLiane.Praza@Sun.COM  * The value of the newly created property is prop_value.
17527887SLiane.Praza@Sun.COM  *
17537887SLiane.Praza@Sun.COM  * free_flag is used to indicate whether or not the memory at prop_value
17547887SLiane.Praza@Sun.COM  * should be freed when the property is freed by a call to
17557887SLiane.Praza@Sun.COM  * internal_property_free().
17567887SLiane.Praza@Sun.COM  */
17577887SLiane.Praza@Sun.COM static void
17587887SLiane.Praza@Sun.COM astring_prop_value(property_t **p, const char *prop_name, char *prop_value,
17597887SLiane.Praza@Sun.COM     boolean_t free_flag)
17607887SLiane.Praza@Sun.COM {
17617887SLiane.Praza@Sun.COM 	value_t *v;
17627887SLiane.Praza@Sun.COM 
17637887SLiane.Praza@Sun.COM 	if (*p == NULL) {
17647887SLiane.Praza@Sun.COM 		/* Create the property */
17657887SLiane.Praza@Sun.COM 		*p = internal_property_new();
17667887SLiane.Praza@Sun.COM 		(*p)->sc_property_name = (char *)prop_name;
17677887SLiane.Praza@Sun.COM 		(*p)->sc_value_type = SCF_TYPE_ASTRING;
17687887SLiane.Praza@Sun.COM 	}
17697887SLiane.Praza@Sun.COM 
17707887SLiane.Praza@Sun.COM 	/* Add the property value to the property's list of values. */
17717887SLiane.Praza@Sun.COM 	v = internal_value_new();
17727887SLiane.Praza@Sun.COM 	v->sc_type = SCF_TYPE_ASTRING;
17737887SLiane.Praza@Sun.COM 	if (free_flag == B_TRUE)
17747887SLiane.Praza@Sun.COM 		v->sc_free = lxml_free_str;
17757887SLiane.Praza@Sun.COM 	v->sc_u.sc_string = prop_value;
17767887SLiane.Praza@Sun.COM 	internal_attach_value(*p, v);
17777887SLiane.Praza@Sun.COM }
17787887SLiane.Praza@Sun.COM 
17797887SLiane.Praza@Sun.COM /*
17807887SLiane.Praza@Sun.COM  * If p points to a null pointer, create an internal_separators property
17817887SLiane.Praza@Sun.COM  * saving the address at p.  For each character at seps create a property
17827887SLiane.Praza@Sun.COM  * value and attach it to the property at p.
17837887SLiane.Praza@Sun.COM  */
17847887SLiane.Praza@Sun.COM static void
17857887SLiane.Praza@Sun.COM seps_to_prop_values(property_t **p, xmlChar *seps)
17867887SLiane.Praza@Sun.COM {
17877887SLiane.Praza@Sun.COM 	value_t *v;
17887887SLiane.Praza@Sun.COM 	char val_str[2];
17897887SLiane.Praza@Sun.COM 
17907887SLiane.Praza@Sun.COM 	if (*p == NULL) {
17917887SLiane.Praza@Sun.COM 		*p = internal_property_new();
17927887SLiane.Praza@Sun.COM 		(*p)->sc_property_name =
17937887SLiane.Praza@Sun.COM 		    (char *)SCF_PROPERTY_INTERNAL_SEPARATORS;
17947887SLiane.Praza@Sun.COM 		(*p)->sc_value_type = SCF_TYPE_ASTRING;
17957887SLiane.Praza@Sun.COM 	}
17967887SLiane.Praza@Sun.COM 
17977887SLiane.Praza@Sun.COM 	/* Add the values to the property's list. */
17987887SLiane.Praza@Sun.COM 	val_str[1] = 0;		/* Terminate the string. */
17997887SLiane.Praza@Sun.COM 	for (; *seps != 0; seps++) {
18007887SLiane.Praza@Sun.COM 		v = internal_value_new();
18017887SLiane.Praza@Sun.COM 		v->sc_type = (*p)->sc_value_type;
18027887SLiane.Praza@Sun.COM 		v->sc_free = lxml_free_str;
18037887SLiane.Praza@Sun.COM 		val_str[0] = *seps;
18047887SLiane.Praza@Sun.COM 		v->sc_u.sc_string = strdup(val_str);
18057887SLiane.Praza@Sun.COM 		if (v->sc_u.sc_string == NULL)
18067887SLiane.Praza@Sun.COM 			uu_die(gettext("Out of memory\n"));
18077887SLiane.Praza@Sun.COM 		internal_attach_value(*p, v);
18087887SLiane.Praza@Sun.COM 	}
18097887SLiane.Praza@Sun.COM }
18107887SLiane.Praza@Sun.COM 
18117887SLiane.Praza@Sun.COM /*
18127887SLiane.Praza@Sun.COM  * Create an internal_separators property and attach it to the property
18137887SLiane.Praza@Sun.COM  * group at pg.  The separator characters are provided in the text nodes
18147887SLiane.Praza@Sun.COM  * that are the children of seps.  Each separator character is stored as a
18157887SLiane.Praza@Sun.COM  * property value in the internal_separators property.
18167887SLiane.Praza@Sun.COM  */
18177887SLiane.Praza@Sun.COM static int
18187887SLiane.Praza@Sun.COM lxml_get_tm_internal_seps(entity_t *service, pgroup_t *pg, xmlNodePtr seps)
18197887SLiane.Praza@Sun.COM {
18207887SLiane.Praza@Sun.COM 	xmlNodePtr cursor;
18217887SLiane.Praza@Sun.COM 	property_t *prop = NULL;
18227887SLiane.Praza@Sun.COM 	int r;
18237887SLiane.Praza@Sun.COM 
18247887SLiane.Praza@Sun.COM 	for (cursor = seps->xmlChildrenNode; cursor != NULL;
18257887SLiane.Praza@Sun.COM 	    cursor = cursor->next) {
18267887SLiane.Praza@Sun.COM 		if (strcmp("text", (const char *)cursor->name) == 0) {
18277887SLiane.Praza@Sun.COM 			seps_to_prop_values(&prop, cursor->content);
18287887SLiane.Praza@Sun.COM 		} else if (strcmp("comment", (const char *)cursor->name) != 0) {
18297887SLiane.Praza@Sun.COM 			uu_die(gettext("illegal element \"%s\" on %s element "
18307887SLiane.Praza@Sun.COM 			    "for \"%s\"\n"), cursor->name, seps->name,
18317887SLiane.Praza@Sun.COM 			    service->sc_name);
18327887SLiane.Praza@Sun.COM 		}
18337887SLiane.Praza@Sun.COM 	}
18347887SLiane.Praza@Sun.COM 	if (prop == NULL) {
18357887SLiane.Praza@Sun.COM 		semerr(gettext("The %s element in %s had an empty list of "
18367887SLiane.Praza@Sun.COM 		    "separators.\n"), (const char *)seps->name,
18377887SLiane.Praza@Sun.COM 		    service->sc_name);
18387887SLiane.Praza@Sun.COM 		return (-1);
18397887SLiane.Praza@Sun.COM 	}
18407887SLiane.Praza@Sun.COM 	r = internal_attach_property(pg, prop);
18417887SLiane.Praza@Sun.COM 	if (r != 0)
18427887SLiane.Praza@Sun.COM 		internal_property_free(prop);
18437887SLiane.Praza@Sun.COM 	return (r);
18447887SLiane.Praza@Sun.COM }
18457887SLiane.Praza@Sun.COM 
18460Sstevel@tonic-gate static int
18470Sstevel@tonic-gate lxml_get_tm_manpage(entity_t *service, xmlNodePtr manpage)
18480Sstevel@tonic-gate {
18490Sstevel@tonic-gate 	pgroup_t *pg;
18500Sstevel@tonic-gate 	char *pgname;
18510Sstevel@tonic-gate 	xmlChar *title;
18520Sstevel@tonic-gate 
18530Sstevel@tonic-gate 	/*
18540Sstevel@tonic-gate 	 * Fetch title attribute, convert to something sanitized, and create
18550Sstevel@tonic-gate 	 * property group.
18560Sstevel@tonic-gate 	 */
18577887SLiane.Praza@Sun.COM 	title = xmlGetProp(manpage, (xmlChar *)title_attr);
18580Sstevel@tonic-gate 	pgname = (char *)lxml_label_to_groupname(SCF_PG_TM_MAN_PREFIX,
18590Sstevel@tonic-gate 	    (const char *)title);
18607887SLiane.Praza@Sun.COM 	xmlFree(title);
18610Sstevel@tonic-gate 
18620Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(service, pgname,
18630Sstevel@tonic-gate 	    (char *)SCF_GROUP_TEMPLATE);
18640Sstevel@tonic-gate 
18650Sstevel@tonic-gate 	/*
18660Sstevel@tonic-gate 	 * Each attribute is an astring property within the group.
18670Sstevel@tonic-gate 	 */
18687887SLiane.Praza@Sun.COM 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_TM_TITLE,
18697887SLiane.Praza@Sun.COM 	    SCF_TYPE_ASTRING, manpage, title_attr) != 0 ||
18707887SLiane.Praza@Sun.COM 	    new_str_prop_from_attr(pg, SCF_PROPERTY_TM_SECTION,
18717887SLiane.Praza@Sun.COM 	    SCF_TYPE_ASTRING, manpage, section_attr) != 0 ||
18727887SLiane.Praza@Sun.COM 	    new_str_prop_from_attr(pg, SCF_PROPERTY_TM_MANPATH,
18737887SLiane.Praza@Sun.COM 	    SCF_TYPE_ASTRING, manpage, manpath_attr) != 0)
18740Sstevel@tonic-gate 		return (-1);
18750Sstevel@tonic-gate 
18760Sstevel@tonic-gate 	return (0);
18770Sstevel@tonic-gate }
18780Sstevel@tonic-gate 
18790Sstevel@tonic-gate static int
18800Sstevel@tonic-gate lxml_get_tm_doclink(entity_t *service, xmlNodePtr doc_link)
18810Sstevel@tonic-gate {
18820Sstevel@tonic-gate 	pgroup_t *pg;
18830Sstevel@tonic-gate 	char *pgname;
18840Sstevel@tonic-gate 	xmlChar *name;
18850Sstevel@tonic-gate 
18860Sstevel@tonic-gate 	/*
18870Sstevel@tonic-gate 	 * Fetch name attribute, convert name to something sanitized, and create
18880Sstevel@tonic-gate 	 * property group.
18890Sstevel@tonic-gate 	 */
18907887SLiane.Praza@Sun.COM 	name = xmlGetProp(doc_link, (xmlChar *)name_attr);
18910Sstevel@tonic-gate 
18920Sstevel@tonic-gate 	pgname = (char *)lxml_label_to_groupname(SCF_PG_TM_DOC_PREFIX,
18930Sstevel@tonic-gate 	    (const char *)name);
18940Sstevel@tonic-gate 
18950Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(service, pgname,
18960Sstevel@tonic-gate 	    (char *)SCF_GROUP_TEMPLATE);
18977887SLiane.Praza@Sun.COM 	xmlFree(name);
18980Sstevel@tonic-gate 
18990Sstevel@tonic-gate 	/*
19000Sstevel@tonic-gate 	 * Each attribute is an astring property within the group.
19010Sstevel@tonic-gate 	 */
19027887SLiane.Praza@Sun.COM 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_TM_NAME, SCF_TYPE_ASTRING,
19037887SLiane.Praza@Sun.COM 	    doc_link, name_attr) != 0 ||
19047887SLiane.Praza@Sun.COM 	    new_str_prop_from_attr(pg, SCF_PROPERTY_TM_URI, SCF_TYPE_ASTRING,
19057887SLiane.Praza@Sun.COM 	    doc_link, uri_attr) != 0)
19060Sstevel@tonic-gate 		return (-1);
19070Sstevel@tonic-gate 
19080Sstevel@tonic-gate 	return (0);
19090Sstevel@tonic-gate }
19100Sstevel@tonic-gate 
19110Sstevel@tonic-gate static int
19120Sstevel@tonic-gate lxml_get_tm_documentation(entity_t *service, xmlNodePtr documentation)
19130Sstevel@tonic-gate {
19140Sstevel@tonic-gate 	xmlNodePtr cursor;
19150Sstevel@tonic-gate 
19160Sstevel@tonic-gate 	for (cursor = documentation->xmlChildrenNode; cursor != NULL;
19170Sstevel@tonic-gate 	    cursor = cursor->next) {
19180Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
19190Sstevel@tonic-gate 			continue;
19200Sstevel@tonic-gate 
19210Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
19220Sstevel@tonic-gate 		case SC_MANPAGE:
19230Sstevel@tonic-gate 			(void) lxml_get_tm_manpage(service, cursor);
19240Sstevel@tonic-gate 			break;
19250Sstevel@tonic-gate 		case SC_DOC_LINK:
19260Sstevel@tonic-gate 			(void) lxml_get_tm_doclink(service, cursor);
19270Sstevel@tonic-gate 			break;
19280Sstevel@tonic-gate 		default:
19290Sstevel@tonic-gate 			uu_die(gettext("illegal element \"%s\" on template "
19300Sstevel@tonic-gate 			    "for service \"%s\"\n"),
19310Sstevel@tonic-gate 			    cursor->name, service->sc_name);
19320Sstevel@tonic-gate 		}
19330Sstevel@tonic-gate 	}
19340Sstevel@tonic-gate 
19350Sstevel@tonic-gate 	return (0);
19360Sstevel@tonic-gate }
19370Sstevel@tonic-gate 
19380Sstevel@tonic-gate static int
19397887SLiane.Praza@Sun.COM lxml_get_prop_pattern_attributes(pgroup_t *pg, xmlNodePtr cursor)
19407887SLiane.Praza@Sun.COM {
19417887SLiane.Praza@Sun.COM 	if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_TM_NAME,
19427887SLiane.Praza@Sun.COM 	    SCF_TYPE_ASTRING, cursor, name_attr, NULL) != 0) {
19437887SLiane.Praza@Sun.COM 		return (-1);
19447887SLiane.Praza@Sun.COM 	}
19457887SLiane.Praza@Sun.COM 	if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_TM_TYPE,
19467887SLiane.Praza@Sun.COM 	    SCF_TYPE_ASTRING, cursor, type_attr, "") != 0) {
19477887SLiane.Praza@Sun.COM 		return (-1);
19487887SLiane.Praza@Sun.COM 	}
19497887SLiane.Praza@Sun.COM 	if (new_bool_prop_from_attr(pg, SCF_PROPERTY_TM_REQUIRED, cursor,
19507887SLiane.Praza@Sun.COM 	    required_attr) != 0)
19517887SLiane.Praza@Sun.COM 		return (-1);
19527887SLiane.Praza@Sun.COM 	return (0);
19537887SLiane.Praza@Sun.COM }
19547887SLiane.Praza@Sun.COM 
19557887SLiane.Praza@Sun.COM static int
19567887SLiane.Praza@Sun.COM lxml_get_tm_include_values(entity_t *service, pgroup_t *pg,
19577887SLiane.Praza@Sun.COM     xmlNodePtr include_values, const char *prop_name)
19587887SLiane.Praza@Sun.COM {
19597887SLiane.Praza@Sun.COM 	boolean_t attach_to_pg = B_FALSE;
19607887SLiane.Praza@Sun.COM 	property_t *p;
19617887SLiane.Praza@Sun.COM 	int r = 0;
19627887SLiane.Praza@Sun.COM 	char *type;
19637887SLiane.Praza@Sun.COM 
19647887SLiane.Praza@Sun.COM 	/* Get the type attribute of the include_values element. */
19657887SLiane.Praza@Sun.COM 	type = (char *)xmlGetProp(include_values, (const xmlChar *)type_attr);
19667887SLiane.Praza@Sun.COM 	if ((type == NULL) || (*type == 0)) {
19677887SLiane.Praza@Sun.COM 		uu_die(gettext("%s element requires a %s attribute in the %s "
19687887SLiane.Praza@Sun.COM 		    "service.\n"), include_values->name, type_attr,
19697887SLiane.Praza@Sun.COM 		    service->sc_name);
19707887SLiane.Praza@Sun.COM 	}
19717887SLiane.Praza@Sun.COM 
19727887SLiane.Praza@Sun.COM 	/* Add the type to the values of the prop_name property. */
19737887SLiane.Praza@Sun.COM 	p = internal_property_find(pg, prop_name);
19747887SLiane.Praza@Sun.COM 	if (p == NULL)
19757887SLiane.Praza@Sun.COM 		attach_to_pg = B_TRUE;
19767887SLiane.Praza@Sun.COM 	astring_prop_value(&p, prop_name, type, B_FALSE);
19777887SLiane.Praza@Sun.COM 	if (attach_to_pg == B_TRUE) {
19787887SLiane.Praza@Sun.COM 		r = internal_attach_property(pg, p);
19797887SLiane.Praza@Sun.COM 		if (r != 0)
19807887SLiane.Praza@Sun.COM 			internal_property_free(p);
19817887SLiane.Praza@Sun.COM 	}
19827887SLiane.Praza@Sun.COM 	return (r);
19837887SLiane.Praza@Sun.COM }
19847887SLiane.Praza@Sun.COM 
19857887SLiane.Praza@Sun.COM #define	RC_MIN		0
19867887SLiane.Praza@Sun.COM #define	RC_MAX		1
19877887SLiane.Praza@Sun.COM #define	RC_COUNT	2
19887887SLiane.Praza@Sun.COM 
19897887SLiane.Praza@Sun.COM /*
19907887SLiane.Praza@Sun.COM  * Verify that the strings at min and max are valid numeric strings.  Also
19917887SLiane.Praza@Sun.COM  * verify that max is numerically >= min.
19927887SLiane.Praza@Sun.COM  *
19937887SLiane.Praza@Sun.COM  * 0 is returned if the range is valid, and -1 is returned if it is not.
19947887SLiane.Praza@Sun.COM  */
19957887SLiane.Praza@Sun.COM static int
19967887SLiane.Praza@Sun.COM verify_range(entity_t *service, xmlNodePtr range, char *min, char *max)
19977887SLiane.Praza@Sun.COM {
19987887SLiane.Praza@Sun.COM 	char *c;
19997887SLiane.Praza@Sun.COM 	int i;
20007887SLiane.Praza@Sun.COM 	int is_signed = 0;
20017887SLiane.Praza@Sun.COM 	int inverted = 0;
20027887SLiane.Praza@Sun.COM 	const char *limit[RC_COUNT];
20037887SLiane.Praza@Sun.COM 	char *strings[RC_COUNT];
20047887SLiane.Praza@Sun.COM 	uint64_t urange[RC_COUNT];	/* unsigned range. */
20057887SLiane.Praza@Sun.COM 	int64_t srange[RC_COUNT];	/* signed range. */
20067887SLiane.Praza@Sun.COM 
20077887SLiane.Praza@Sun.COM 	strings[RC_MIN] = min;
20087887SLiane.Praza@Sun.COM 	strings[RC_MAX] = max;
20097887SLiane.Praza@Sun.COM 	limit[RC_MIN] = min_attr;
20107887SLiane.Praza@Sun.COM 	limit[RC_MAX] = max_attr;
20117887SLiane.Praza@Sun.COM 
20127887SLiane.Praza@Sun.COM 	/* See if the range is signed. */
20137887SLiane.Praza@Sun.COM 	for (i = 0; (i < RC_COUNT) && (is_signed == 0); i++) {
20147887SLiane.Praza@Sun.COM 		c = strings[i];
20157887SLiane.Praza@Sun.COM 		while (isspace(*c)) {
20167887SLiane.Praza@Sun.COM 			c++;
20177887SLiane.Praza@Sun.COM 		}
20187887SLiane.Praza@Sun.COM 		if (*c == '-')
20197887SLiane.Praza@Sun.COM 			is_signed = 1;
20207887SLiane.Praza@Sun.COM 	}
20217887SLiane.Praza@Sun.COM 
20227887SLiane.Praza@Sun.COM 	/* Attempt to convert the strings. */
20237887SLiane.Praza@Sun.COM 	for (i = 0; i < RC_COUNT; i++) {
20247887SLiane.Praza@Sun.COM 		errno = 0;
20257887SLiane.Praza@Sun.COM 		if (is_signed) {
20267887SLiane.Praza@Sun.COM 			srange[i] = strtoll(strings[i], &c, 0);
20277887SLiane.Praza@Sun.COM 		} else {
20287887SLiane.Praza@Sun.COM 			urange[i] = strtoull(strings[i], &c, 0);
20297887SLiane.Praza@Sun.COM 		}
20307887SLiane.Praza@Sun.COM 		if ((errno != 0) || (c == strings[i]) || (*c != 0)) {
20317887SLiane.Praza@Sun.COM 			/* Conversion failed. */
20327887SLiane.Praza@Sun.COM 			uu_die(gettext("Unable to convert %s for the %s "
20337887SLiane.Praza@Sun.COM 			    "element in service %s.\n"), limit[i],
20347887SLiane.Praza@Sun.COM 			    (char *)range->name, service->sc_name);
20357887SLiane.Praza@Sun.COM 		}
20367887SLiane.Praza@Sun.COM 	}
20377887SLiane.Praza@Sun.COM 
20387887SLiane.Praza@Sun.COM 	/* Make sure that min is <= max */
20397887SLiane.Praza@Sun.COM 	if (is_signed) {
20407887SLiane.Praza@Sun.COM 		if (srange[RC_MAX] < srange[RC_MIN])
20417887SLiane.Praza@Sun.COM 			inverted = 1;
20427887SLiane.Praza@Sun.COM 	} else {
20437887SLiane.Praza@Sun.COM 		if (urange[RC_MAX] < urange[RC_MIN])
20447887SLiane.Praza@Sun.COM 			inverted = 1;
20457887SLiane.Praza@Sun.COM 	}
20467887SLiane.Praza@Sun.COM 	if (inverted != 0) {
20477887SLiane.Praza@Sun.COM 		semerr(gettext("Maximum less than minimum for the %s element "
20487887SLiane.Praza@Sun.COM 		    "in service %s.\n"), (char *)range->name,
20497887SLiane.Praza@Sun.COM 		    service->sc_name);
20507887SLiane.Praza@Sun.COM 		return (-1);
20517887SLiane.Praza@Sun.COM 	}
20527887SLiane.Praza@Sun.COM 
20537887SLiane.Praza@Sun.COM 	return (0);
20547887SLiane.Praza@Sun.COM }
20557887SLiane.Praza@Sun.COM 
20567887SLiane.Praza@Sun.COM /*
20577887SLiane.Praza@Sun.COM  * This, function creates a property named prop_name.  The range element
20587887SLiane.Praza@Sun.COM  * should have two attributes -- min and max.  The property value then
20597887SLiane.Praza@Sun.COM  * becomes the concatenation of their value separated by a comma.  The
20607887SLiane.Praza@Sun.COM  * property is then attached to the property group at pg.
20617887SLiane.Praza@Sun.COM  *
20627887SLiane.Praza@Sun.COM  * If pg already contains a property with a name of prop_name, it is only
20637887SLiane.Praza@Sun.COM  * necessary to create a new value and attach it to the existing property.
20647887SLiane.Praza@Sun.COM  */
20657887SLiane.Praza@Sun.COM static int
20667887SLiane.Praza@Sun.COM lxml_get_tm_range(entity_t *service, pgroup_t *pg, xmlNodePtr range,
20677887SLiane.Praza@Sun.COM     const char *prop_name)
20687887SLiane.Praza@Sun.COM {
20697887SLiane.Praza@Sun.COM 	boolean_t attach_to_pg = B_FALSE;
20707887SLiane.Praza@Sun.COM 	char *max;
20717887SLiane.Praza@Sun.COM 	char *min;
20727887SLiane.Praza@Sun.COM 	property_t *p;
20737887SLiane.Praza@Sun.COM 	char *prop_value;
20747887SLiane.Praza@Sun.COM 	int r = 0;
20757887SLiane.Praza@Sun.COM 
20767887SLiane.Praza@Sun.COM 	/* Get max and min from the XML description. */
20777887SLiane.Praza@Sun.COM 	max = (char *)xmlGetProp(range, (xmlChar *)max_attr);
20787887SLiane.Praza@Sun.COM 	if ((max == NULL) || (*max == 0)) {
20797887SLiane.Praza@Sun.COM 		uu_die(gettext("%s element is missing the %s attribute in "
20807887SLiane.Praza@Sun.COM 		    "service %s.\n"), (char *)range->name, max_attr,
20817887SLiane.Praza@Sun.COM 		    service->sc_name);
20827887SLiane.Praza@Sun.COM 	}
20837887SLiane.Praza@Sun.COM 	min = (char *)xmlGetProp(range, (xmlChar *)min_attr);
20847887SLiane.Praza@Sun.COM 	if ((min == NULL) || (*min == 0)) {
20857887SLiane.Praza@Sun.COM 		uu_die(gettext("%s element is missing the %s attribute in "
20867887SLiane.Praza@Sun.COM 		    "service %s.\n"), (char *)range->name, min_attr,
20877887SLiane.Praza@Sun.COM 		    service->sc_name);
20887887SLiane.Praza@Sun.COM 	}
20897887SLiane.Praza@Sun.COM 	if (verify_range(service, range, min, max) != 0) {
20907887SLiane.Praza@Sun.COM 		xmlFree(min);
20917887SLiane.Praza@Sun.COM 		xmlFree(max);
20927887SLiane.Praza@Sun.COM 		return (-1);
20937887SLiane.Praza@Sun.COM 	}
20947887SLiane.Praza@Sun.COM 
20957887SLiane.Praza@Sun.COM 	/* Property value is concatenation of min and max. */
20967887SLiane.Praza@Sun.COM 	prop_value = safe_malloc(max_scf_value_len + 1);
20977887SLiane.Praza@Sun.COM 	if (snprintf(prop_value, max_scf_value_len + 1, "%s,%s", min, max) >=
20987887SLiane.Praza@Sun.COM 	    max_scf_value_len + 1) {
20997887SLiane.Praza@Sun.COM 		uu_die(gettext("min and max are too long for the %s element "
21007887SLiane.Praza@Sun.COM 		    "of %s.\n"), (char *)range->name, service->sc_name);
21017887SLiane.Praza@Sun.COM 	}
21027887SLiane.Praza@Sun.COM 	xmlFree(min);
21037887SLiane.Praza@Sun.COM 	xmlFree(max);
21047887SLiane.Praza@Sun.COM 
21057887SLiane.Praza@Sun.COM 	/*
21067887SLiane.Praza@Sun.COM 	 * If necessary create the property and attach it to the property
21077887SLiane.Praza@Sun.COM 	 * group.
21087887SLiane.Praza@Sun.COM 	 */
21097887SLiane.Praza@Sun.COM 	p = internal_property_find(pg, prop_name);
21107887SLiane.Praza@Sun.COM 	if (p == NULL)
21117887SLiane.Praza@Sun.COM 		attach_to_pg = B_TRUE;
21127887SLiane.Praza@Sun.COM 	astring_prop_value(&p, prop_name, prop_value, B_TRUE);
21137887SLiane.Praza@Sun.COM 	if (attach_to_pg == B_TRUE) {
21147887SLiane.Praza@Sun.COM 		r = internal_attach_property(pg, p);
21157887SLiane.Praza@Sun.COM 		if (r != 0) {
21167887SLiane.Praza@Sun.COM 			internal_property_free(p);
21177887SLiane.Praza@Sun.COM 		}
21187887SLiane.Praza@Sun.COM 	}
21197887SLiane.Praza@Sun.COM 	return (r);
21207887SLiane.Praza@Sun.COM }
21217887SLiane.Praza@Sun.COM 
21227887SLiane.Praza@Sun.COM /*
21237887SLiane.Praza@Sun.COM  * Determine how many plain characters are represented by count Base32
21247887SLiane.Praza@Sun.COM  * encoded characters.  5 plain text characters are converted to 8 Base32
21257887SLiane.Praza@Sun.COM  * characters.
21267887SLiane.Praza@Sun.COM  */
21277887SLiane.Praza@Sun.COM static size_t
21287887SLiane.Praza@Sun.COM encoded_count_to_plain(size_t count)
21297887SLiane.Praza@Sun.COM {
21307887SLiane.Praza@Sun.COM 	return (5 * ((count + 7) / 8));
21317887SLiane.Praza@Sun.COM }
21327887SLiane.Praza@Sun.COM 
21337887SLiane.Praza@Sun.COM /*
21347887SLiane.Praza@Sun.COM  * The value element contains 0 or 1 common_name element followed by 0 or 1
21357887SLiane.Praza@Sun.COM  * description element.  It also has a required attribute called "name".
21367887SLiane.Praza@Sun.COM  * The common_name and description are stored as property values in pg.
21377887SLiane.Praza@Sun.COM  * The property names are:
21387887SLiane.Praza@Sun.COM  *	value_<name>_common_name_<lang>
21397887SLiane.Praza@Sun.COM  *	value_<name>_description_<lang>
21407887SLiane.Praza@Sun.COM  *
21417887SLiane.Praza@Sun.COM  * The <name> portion of the preceeding proper names requires more
21427887SLiane.Praza@Sun.COM  * explanation.  Ideally it would just the name attribute of this value
21437887SLiane.Praza@Sun.COM  * element.  Unfortunately, the name attribute can contain characters that
21447887SLiane.Praza@Sun.COM  * are not legal in a property name.  Thus, we base 32 encode the name
21457887SLiane.Praza@Sun.COM  * attribute and use that for <name>.
21467887SLiane.Praza@Sun.COM  *
21477887SLiane.Praza@Sun.COM  * There are cases where the caller needs to know the name, so it is
21487887SLiane.Praza@Sun.COM  * returned through the name_value pointer if it is not NULL.
21497887SLiane.Praza@Sun.COM  *
21507887SLiane.Praza@Sun.COM  * Parameters:
21517887SLiane.Praza@Sun.COM  *	service -	Information about the service that is being
21527887SLiane.Praza@Sun.COM  *			processed.  This function only uses this parameter
21537887SLiane.Praza@Sun.COM  *			for producing error messages.
21547887SLiane.Praza@Sun.COM  *
21557887SLiane.Praza@Sun.COM  *	pg -		The property group to receive the newly created
21567887SLiane.Praza@Sun.COM  *			properties.
21577887SLiane.Praza@Sun.COM  *
21587887SLiane.Praza@Sun.COM  *	value -		Pointer to the value element in the XML tree.
21597887SLiane.Praza@Sun.COM  *
21607887SLiane.Praza@Sun.COM  *	name_value -	Address to receive the value of the name attribute.
21617887SLiane.Praza@Sun.COM  *			The caller must free the memory.
21627887SLiane.Praza@Sun.COM  */
21637887SLiane.Praza@Sun.COM static int
21647887SLiane.Praza@Sun.COM lxml_get_tm_value_element(entity_t *service, pgroup_t *pg, xmlNodePtr value,
21657887SLiane.Praza@Sun.COM     char **name_value)
21667887SLiane.Praza@Sun.COM {
21677887SLiane.Praza@Sun.COM 	char *common_name_fmt;
21687887SLiane.Praza@Sun.COM 	xmlNodePtr cursor;
21697887SLiane.Praza@Sun.COM 	char *description_fmt;
21707887SLiane.Praza@Sun.COM 	char *encoded_value = NULL;
21717887SLiane.Praza@Sun.COM 	size_t extra;
21727887SLiane.Praza@Sun.COM 	char *value_name;
21737887SLiane.Praza@Sun.COM 	int r = 0;
21747887SLiane.Praza@Sun.COM 
21757887SLiane.Praza@Sun.COM 	common_name_fmt = safe_malloc(max_scf_name_len + 1);
21767887SLiane.Praza@Sun.COM 	description_fmt = safe_malloc(max_scf_name_len + 1);
21777887SLiane.Praza@Sun.COM 
21787887SLiane.Praza@Sun.COM 	/*
21797887SLiane.Praza@Sun.COM 	 * Get the value of our name attribute, so that we can use it to
21807887SLiane.Praza@Sun.COM 	 * construct property names.
21817887SLiane.Praza@Sun.COM 	 */
21827887SLiane.Praza@Sun.COM 	value_name = (char *)xmlGetProp(value, (xmlChar *)name_attr);
21837887SLiane.Praza@Sun.COM 	/* The value name must be present, but it can be empty. */
21847887SLiane.Praza@Sun.COM 	if (value_name == NULL) {
21857887SLiane.Praza@Sun.COM 		uu_die(gettext("%s element requires a %s attribute in the %s "
21867887SLiane.Praza@Sun.COM 		    "service.\n"), (char *)value->name, name_attr,
21877887SLiane.Praza@Sun.COM 		    service->sc_name);
21887887SLiane.Praza@Sun.COM 	}
21897887SLiane.Praza@Sun.COM 
21907887SLiane.Praza@Sun.COM 	/*
21917887SLiane.Praza@Sun.COM 	 * The value_name may contain characters that are not valid in in a
21927887SLiane.Praza@Sun.COM 	 * property name.  So we will encode value_name and then use the
21937887SLiane.Praza@Sun.COM 	 * encoded value in the property name.
21947887SLiane.Praza@Sun.COM 	 */
21957887SLiane.Praza@Sun.COM 	encoded_value = safe_malloc(max_scf_name_len + 1);
21967887SLiane.Praza@Sun.COM 	if (scf_encode32(value_name, strlen(value_name), encoded_value,
21977887SLiane.Praza@Sun.COM 	    max_scf_name_len + 1, &extra, SCF_ENCODE32_PAD) != 0) {
21987887SLiane.Praza@Sun.COM 		extra = encoded_count_to_plain(extra - max_scf_name_len);
21997887SLiane.Praza@Sun.COM 		uu_die(gettext("Constructed property name is %u characters "
22007887SLiane.Praza@Sun.COM 		    "too long for value \"%s\" in the %s service.\n"),
22017887SLiane.Praza@Sun.COM 		    extra, value_name, service->sc_name);
22027887SLiane.Praza@Sun.COM 	}
22037887SLiane.Praza@Sun.COM 	if ((extra = snprintf(common_name_fmt, max_scf_name_len + 1,
22047887SLiane.Praza@Sun.COM 	    VALUE_COMMON_NAME_FMT, SCF_PROPERTY_TM_VALUE_PREFIX,
22057887SLiane.Praza@Sun.COM 	    encoded_value)) >= max_scf_name_len + 1) {
22067887SLiane.Praza@Sun.COM 		extra = encoded_count_to_plain(extra - max_scf_name_len);
22077887SLiane.Praza@Sun.COM 		uu_die(gettext("Name attribute is "
22087887SLiane.Praza@Sun.COM 		    "%u characters too long for %s in service %s\n"),
22097887SLiane.Praza@Sun.COM 		    extra, (char *)value->name, service->sc_name);
22107887SLiane.Praza@Sun.COM 	}
22117887SLiane.Praza@Sun.COM 	if ((extra = snprintf(description_fmt, max_scf_name_len + 1,
22127887SLiane.Praza@Sun.COM 	    VALUE_DESCRIPTION_FMT, SCF_PROPERTY_TM_VALUE_PREFIX,
22137887SLiane.Praza@Sun.COM 	    encoded_value)) >= max_scf_name_len + 1) {
22147887SLiane.Praza@Sun.COM 		extra = encoded_count_to_plain(extra - max_scf_name_len);
22157887SLiane.Praza@Sun.COM 		uu_die(gettext("Name attribute is "
22167887SLiane.Praza@Sun.COM 		    "%u characters too long for %s in service %s\n"),
22177887SLiane.Praza@Sun.COM 		    extra, (char *)value->name, service->sc_name);
22187887SLiane.Praza@Sun.COM 	}
22197887SLiane.Praza@Sun.COM 
22207887SLiane.Praza@Sun.COM 	for (cursor = value->xmlChildrenNode;
22217887SLiane.Praza@Sun.COM 	    cursor != NULL;
22227887SLiane.Praza@Sun.COM 	    cursor = cursor->next) {
22237887SLiane.Praza@Sun.COM 		if (lxml_ignorable_block(cursor))
22247887SLiane.Praza@Sun.COM 			continue;
22257887SLiane.Praza@Sun.COM 		switch (lxml_xlate_element(cursor->name)) {
22267887SLiane.Praza@Sun.COM 		case SC_COMMON_NAME:
22277887SLiane.Praza@Sun.COM 			r = lxml_get_all_loctext(service, pg, cursor,
22287887SLiane.Praza@Sun.COM 			    common_name_fmt, (const char *)cursor->name);
22297887SLiane.Praza@Sun.COM 			break;
22307887SLiane.Praza@Sun.COM 		case SC_DESCRIPTION:
22317887SLiane.Praza@Sun.COM 			r = lxml_get_all_loctext(service, pg, cursor,
22327887SLiane.Praza@Sun.COM 			    description_fmt, (const char *)cursor->name);
22337887SLiane.Praza@Sun.COM 			break;
22347887SLiane.Praza@Sun.COM 		default:
22357887SLiane.Praza@Sun.COM 			uu_die(gettext("\"%s\" is an illegal element in %s "
22367887SLiane.Praza@Sun.COM 			    "of service %s\n"), (char *)cursor->name,
22377887SLiane.Praza@Sun.COM 			    (char *)value->name, service->sc_name);
22387887SLiane.Praza@Sun.COM 		}
22397887SLiane.Praza@Sun.COM 		if (r != 0)
22407887SLiane.Praza@Sun.COM 			break;
22417887SLiane.Praza@Sun.COM 	}
22427887SLiane.Praza@Sun.COM 
22437887SLiane.Praza@Sun.COM 	free(description_fmt);
22447887SLiane.Praza@Sun.COM 	free(common_name_fmt);
22457887SLiane.Praza@Sun.COM 	if (r == 0) {
22467887SLiane.Praza@Sun.COM 		*name_value = safe_strdup(value_name);
22477887SLiane.Praza@Sun.COM 	}
22487887SLiane.Praza@Sun.COM 	xmlFree(value_name);
22497887SLiane.Praza@Sun.COM 	free(encoded_value);
22507887SLiane.Praza@Sun.COM 	return (r);
22517887SLiane.Praza@Sun.COM }
22527887SLiane.Praza@Sun.COM 
22537887SLiane.Praza@Sun.COM static int
22547887SLiane.Praza@Sun.COM lxml_get_tm_choices(entity_t *service, pgroup_t *pg, xmlNodePtr choices)
22557887SLiane.Praza@Sun.COM {
22567887SLiane.Praza@Sun.COM 	xmlNodePtr cursor;
22577887SLiane.Praza@Sun.COM 	char *name_value;
22587887SLiane.Praza@Sun.COM 	property_t *name_prop = NULL;
22597887SLiane.Praza@Sun.COM 	int r = 0;
22607887SLiane.Praza@Sun.COM 
22617887SLiane.Praza@Sun.COM 	for (cursor = choices->xmlChildrenNode;
22627887SLiane.Praza@Sun.COM 	    (cursor != NULL) && (r == 0);
22637887SLiane.Praza@Sun.COM 	    cursor = cursor->next) {
22647887SLiane.Praza@Sun.COM 		if (lxml_ignorable_block(cursor))
22657887SLiane.Praza@Sun.COM 			continue;
22667887SLiane.Praza@Sun.COM 		switch (lxml_xlate_element(cursor->name)) {
22677887SLiane.Praza@Sun.COM 		case SC_INCLUDE_VALUES:
22687887SLiane.Praza@Sun.COM 			(void) lxml_get_tm_include_values(service, pg, cursor,
22697887SLiane.Praza@Sun.COM 			    SCF_PROPERTY_TM_CHOICES_INCLUDE_VALUES);
22707887SLiane.Praza@Sun.COM 			break;
22717887SLiane.Praza@Sun.COM 		case SC_RANGE:
22727887SLiane.Praza@Sun.COM 			r = lxml_get_tm_range(service, pg, cursor,
22737887SLiane.Praza@Sun.COM 			    SCF_PROPERTY_TM_CHOICES_RANGE);
22747887SLiane.Praza@Sun.COM 			if (r != 0)
22757887SLiane.Praza@Sun.COM 				goto out;
22767887SLiane.Praza@Sun.COM 			break;
22777887SLiane.Praza@Sun.COM 		case SC_VALUE:
22787887SLiane.Praza@Sun.COM 			r = lxml_get_tm_value_element(service, pg, cursor,
22797887SLiane.Praza@Sun.COM 			    &name_value);
22807887SLiane.Praza@Sun.COM 			if (r == 0) {
22817887SLiane.Praza@Sun.COM 				/*
22827887SLiane.Praza@Sun.COM 				 * There is no need to free the memory
22837887SLiane.Praza@Sun.COM 				 * associated with name_value, because the
22847887SLiane.Praza@Sun.COM 				 * property value will end up pointing to
22857887SLiane.Praza@Sun.COM 				 * the memory.
22867887SLiane.Praza@Sun.COM 				 */
22877887SLiane.Praza@Sun.COM 				astring_prop_value(&name_prop,
22887887SLiane.Praza@Sun.COM 				    SCF_PROPERTY_TM_CHOICES_NAME, name_value,
22897887SLiane.Praza@Sun.COM 				    B_TRUE);
22907887SLiane.Praza@Sun.COM 			} else {
22917887SLiane.Praza@Sun.COM 				goto out;
22927887SLiane.Praza@Sun.COM 			}
22937887SLiane.Praza@Sun.COM 			break;
22947887SLiane.Praza@Sun.COM 		default:
22957887SLiane.Praza@Sun.COM 			uu_die(gettext("%s is an invalid element of "
22967887SLiane.Praza@Sun.COM 			    "choices for service %s.\n"),  cursor->name,
22977887SLiane.Praza@Sun.COM 			    service->sc_name);
22987887SLiane.Praza@Sun.COM 		}
22997887SLiane.Praza@Sun.COM 	}
23007887SLiane.Praza@Sun.COM 
23017887SLiane.Praza@Sun.COM out:
23027887SLiane.Praza@Sun.COM 	/* Attach the name property if we created one. */
23037887SLiane.Praza@Sun.COM 	if ((r == 0) && (name_prop != NULL)) {
23047887SLiane.Praza@Sun.COM 		r = internal_attach_property(pg, name_prop);
23057887SLiane.Praza@Sun.COM 	}
23067887SLiane.Praza@Sun.COM 	if ((r != 0) && (name_prop != NULL)) {
23077887SLiane.Praza@Sun.COM 		internal_property_free(name_prop);
23087887SLiane.Praza@Sun.COM 	}
23097887SLiane.Praza@Sun.COM 
23107887SLiane.Praza@Sun.COM 	return (r);
23117887SLiane.Praza@Sun.COM }
23127887SLiane.Praza@Sun.COM 
23137887SLiane.Praza@Sun.COM static int
23147887SLiane.Praza@Sun.COM lxml_get_tm_constraints(entity_t *service, pgroup_t *pg, xmlNodePtr constraints)
23157887SLiane.Praza@Sun.COM {
23167887SLiane.Praza@Sun.COM 	xmlNodePtr cursor;
23177887SLiane.Praza@Sun.COM 	char *name_value;
23187887SLiane.Praza@Sun.COM 	property_t *name_prop = NULL;
23197887SLiane.Praza@Sun.COM 	int r = 0;
23207887SLiane.Praza@Sun.COM 
23217887SLiane.Praza@Sun.COM 	for (cursor = constraints->xmlChildrenNode;
23227887SLiane.Praza@Sun.COM 	    (cursor != NULL) && (r == 0);
23237887SLiane.Praza@Sun.COM 	    cursor = cursor->next) {
23247887SLiane.Praza@Sun.COM 		if (lxml_ignorable_block(cursor))
23257887SLiane.Praza@Sun.COM 			continue;
23267887SLiane.Praza@Sun.COM 		switch (lxml_xlate_element(cursor->name)) {
23277887SLiane.Praza@Sun.COM 		case SC_RANGE:
23287887SLiane.Praza@Sun.COM 			r = lxml_get_tm_range(service, pg, cursor,
23297887SLiane.Praza@Sun.COM 			    SCF_PROPERTY_TM_CONSTRAINT_RANGE);
23307887SLiane.Praza@Sun.COM 			if (r != 0)
23317887SLiane.Praza@Sun.COM 				goto out;
23327887SLiane.Praza@Sun.COM 			break;
23337887SLiane.Praza@Sun.COM 		case SC_VALUE:
23347887SLiane.Praza@Sun.COM 			r = lxml_get_tm_value_element(service, pg, cursor,
23357887SLiane.Praza@Sun.COM 			    &name_value);
23367887SLiane.Praza@Sun.COM 			if (r == 0) {
23377887SLiane.Praza@Sun.COM 				/*
23387887SLiane.Praza@Sun.COM 				 * There is no need to free the memory
23397887SLiane.Praza@Sun.COM 				 * associated with name_value, because the
23407887SLiane.Praza@Sun.COM 				 * property value will end up pointing to
23417887SLiane.Praza@Sun.COM 				 * the memory.
23427887SLiane.Praza@Sun.COM 				 */
23437887SLiane.Praza@Sun.COM 				astring_prop_value(&name_prop,
23447887SLiane.Praza@Sun.COM 				    SCF_PROPERTY_TM_CONSTRAINT_NAME, name_value,
23457887SLiane.Praza@Sun.COM 				    B_TRUE);
23467887SLiane.Praza@Sun.COM 			} else {
23477887SLiane.Praza@Sun.COM 				goto out;
23487887SLiane.Praza@Sun.COM 			}
23497887SLiane.Praza@Sun.COM 			break;
23507887SLiane.Praza@Sun.COM 		default:
23517887SLiane.Praza@Sun.COM 			uu_die(gettext("%s is an invalid element of "
23527887SLiane.Praza@Sun.COM 			    "constraints for service %s.\n"),  cursor->name,
23537887SLiane.Praza@Sun.COM 			    service->sc_name);
23547887SLiane.Praza@Sun.COM 		}
23557887SLiane.Praza@Sun.COM 	}
23567887SLiane.Praza@Sun.COM 
23577887SLiane.Praza@Sun.COM out:
23587887SLiane.Praza@Sun.COM 	/* Attach the name property if we created one. */
23597887SLiane.Praza@Sun.COM 	if ((r == 0) && (name_prop != NULL)) {
23607887SLiane.Praza@Sun.COM 		r = internal_attach_property(pg, name_prop);
23617887SLiane.Praza@Sun.COM 	}
23627887SLiane.Praza@Sun.COM 	if ((r != 0) && (name_prop != NULL)) {
23637887SLiane.Praza@Sun.COM 		internal_property_free(name_prop);
23647887SLiane.Praza@Sun.COM 	}
23657887SLiane.Praza@Sun.COM 
23667887SLiane.Praza@Sun.COM 	return (r);
23677887SLiane.Praza@Sun.COM }
23687887SLiane.Praza@Sun.COM 
23697887SLiane.Praza@Sun.COM /*
23707887SLiane.Praza@Sun.COM  * The values element contains one or more value elements.
23717887SLiane.Praza@Sun.COM  */
23727887SLiane.Praza@Sun.COM static int
23737887SLiane.Praza@Sun.COM lxml_get_tm_values(entity_t *service, pgroup_t *pg, xmlNodePtr values)
23747887SLiane.Praza@Sun.COM {
23757887SLiane.Praza@Sun.COM 	xmlNodePtr cursor;
23767887SLiane.Praza@Sun.COM 	char *name_value;
23777887SLiane.Praza@Sun.COM 	property_t *name_prop = NULL;
23787887SLiane.Praza@Sun.COM 	int r = 0;
23797887SLiane.Praza@Sun.COM 
23807887SLiane.Praza@Sun.COM 	for (cursor = values->xmlChildrenNode;
23817887SLiane.Praza@Sun.COM 	    (cursor != NULL) && (r == 0);
23827887SLiane.Praza@Sun.COM 	    cursor = cursor->next) {
23837887SLiane.Praza@Sun.COM 		if (lxml_ignorable_block(cursor))
23847887SLiane.Praza@Sun.COM 			continue;
23857887SLiane.Praza@Sun.COM 		if (lxml_xlate_element(cursor->name) != SC_VALUE) {
23867887SLiane.Praza@Sun.COM 			uu_die(gettext("\"%s\" is an illegal element in the "
23877887SLiane.Praza@Sun.COM 			    "%s element of %s\n"), (char *)cursor->name,
23887887SLiane.Praza@Sun.COM 			    (char *)values->name, service->sc_name);
23897887SLiane.Praza@Sun.COM 		}
23907887SLiane.Praza@Sun.COM 		r = lxml_get_tm_value_element(service, pg, cursor, &name_value);
23917887SLiane.Praza@Sun.COM 		if (r == 0) {
23927887SLiane.Praza@Sun.COM 			/*
23937887SLiane.Praza@Sun.COM 			 * There is no need to free the memory
23947887SLiane.Praza@Sun.COM 			 * associated with name_value, because the
23957887SLiane.Praza@Sun.COM 			 * property value will end up pointing to
23967887SLiane.Praza@Sun.COM 			 * the memory.
23977887SLiane.Praza@Sun.COM 			 */
23987887SLiane.Praza@Sun.COM 			astring_prop_value(&name_prop,
23997887SLiane.Praza@Sun.COM 			    SCF_PROPERTY_TM_VALUES_NAME, name_value,
24007887SLiane.Praza@Sun.COM 			    B_TRUE);
24017887SLiane.Praza@Sun.COM 		}
24027887SLiane.Praza@Sun.COM 	}
24037887SLiane.Praza@Sun.COM 
24047887SLiane.Praza@Sun.COM 	/* Attach the name property if we created one. */
24057887SLiane.Praza@Sun.COM 	if ((r == 0) && (name_prop != NULL)) {
24067887SLiane.Praza@Sun.COM 		r = internal_attach_property(pg, name_prop);
24077887SLiane.Praza@Sun.COM 	}
24087887SLiane.Praza@Sun.COM 	if ((r != 0) && (name_prop != NULL)) {
24097887SLiane.Praza@Sun.COM 		internal_property_free(name_prop);
24107887SLiane.Praza@Sun.COM 	}
24117887SLiane.Praza@Sun.COM 
24127887SLiane.Praza@Sun.COM 	return (r);
24137887SLiane.Praza@Sun.COM }
24147887SLiane.Praza@Sun.COM 
24157887SLiane.Praza@Sun.COM /*
24167887SLiane.Praza@Sun.COM  * This function processes a prop_pattern element within a pg_pattern XML
24177887SLiane.Praza@Sun.COM  * element.  First it creates a property group to hold the prop_pattern
24187887SLiane.Praza@Sun.COM  * information.  The name of this property group is the concatenation of:
24197887SLiane.Praza@Sun.COM  *	- SCF_PG_TM_PROP_PATTERN_PREFIX
24207887SLiane.Praza@Sun.COM  *	- The unique part of the property group name of the enclosing
24217887SLiane.Praza@Sun.COM  *	  pg_pattern.  The property group name of the enclosing pg_pattern
24227887SLiane.Praza@Sun.COM  *	  is passed to us in pgpat_name.  The unique part, is the part
24237887SLiane.Praza@Sun.COM  *	  following SCF_PG_TM_PG_PATTERN_PREFIX.
24247887SLiane.Praza@Sun.COM  *	- The name of this prop_pattern element.
24257887SLiane.Praza@Sun.COM  *
24267887SLiane.Praza@Sun.COM  * After creating the property group, the prop_pattern attributes are saved
24277887SLiane.Praza@Sun.COM  * as properties in the PG.  Finally, the prop_pattern elements are
24287887SLiane.Praza@Sun.COM  * processed and added to the PG.
24297887SLiane.Praza@Sun.COM  */
24307887SLiane.Praza@Sun.COM static int
24317887SLiane.Praza@Sun.COM lxml_get_tm_prop_pattern(entity_t *service, xmlNodePtr prop_pattern,
24327887SLiane.Praza@Sun.COM     const char *pgpat_name)
24337887SLiane.Praza@Sun.COM {
24347887SLiane.Praza@Sun.COM 	xmlNodePtr cursor;
24357887SLiane.Praza@Sun.COM 	int extra;
24367887SLiane.Praza@Sun.COM 	pgroup_t *pg;
24377887SLiane.Praza@Sun.COM 	property_t *p;
24387887SLiane.Praza@Sun.COM 	char *pg_name;
24397887SLiane.Praza@Sun.COM 	size_t prefix_len;
24407887SLiane.Praza@Sun.COM 	xmlChar *prop_pattern_name;
24417887SLiane.Praza@Sun.COM 	int r;
24427887SLiane.Praza@Sun.COM 	const char *unique;
24437887SLiane.Praza@Sun.COM 	value_t *v;
24447887SLiane.Praza@Sun.COM 
24457887SLiane.Praza@Sun.COM 	/* Find the unique part of the pg_pattern property group name. */
24467887SLiane.Praza@Sun.COM 	prefix_len = strlen(SCF_PG_TM_PG_PAT_BASE);
24477887SLiane.Praza@Sun.COM 	assert(strncmp(pgpat_name, SCF_PG_TM_PG_PAT_BASE, prefix_len) == 0);
24487887SLiane.Praza@Sun.COM 	unique = pgpat_name + prefix_len;
24497887SLiane.Praza@Sun.COM 
24507887SLiane.Praza@Sun.COM 	/*
24517887SLiane.Praza@Sun.COM 	 * We need to get the value of the name attribute first.  The
24527887SLiane.Praza@Sun.COM 	 * prop_pattern name as well as the name of the enclosing
24537887SLiane.Praza@Sun.COM 	 * pg_pattern both constitute part of the name of the property
24547887SLiane.Praza@Sun.COM 	 * group that we will create.
24557887SLiane.Praza@Sun.COM 	 */
24567887SLiane.Praza@Sun.COM 	prop_pattern_name = xmlGetProp(prop_pattern, (xmlChar *)name_attr);
24577887SLiane.Praza@Sun.COM 	if ((prop_pattern_name == NULL) || (*prop_pattern_name == 0)) {
24587887SLiane.Praza@Sun.COM 		semerr(gettext("prop_pattern name is missing for %s\n"),
24597887SLiane.Praza@Sun.COM 		    service->sc_name);
24607887SLiane.Praza@Sun.COM 		return (-1);
24617887SLiane.Praza@Sun.COM 	}
24627887SLiane.Praza@Sun.COM 	if (uu_check_name((const char *)prop_pattern_name,
24637887SLiane.Praza@Sun.COM 	    UU_NAME_DOMAIN) != 0) {
24647887SLiane.Praza@Sun.COM 		semerr(gettext("prop_pattern name, \"%s\", for %s is not "
24657887SLiane.Praza@Sun.COM 		    "valid.\n"), prop_pattern_name, service->sc_name);
24667887SLiane.Praza@Sun.COM 		xmlFree(prop_pattern_name);
24677887SLiane.Praza@Sun.COM 		return (-1);
24687887SLiane.Praza@Sun.COM 	}
24697887SLiane.Praza@Sun.COM 	pg_name = safe_malloc(max_scf_name_len + 1);
24707887SLiane.Praza@Sun.COM 	if ((extra = snprintf(pg_name, max_scf_name_len + 1, "%s%s_%s",
24717887SLiane.Praza@Sun.COM 	    SCF_PG_TM_PROP_PATTERN_PREFIX, unique,
24727887SLiane.Praza@Sun.COM 	    (char *)prop_pattern_name)) >= max_scf_name_len + 1) {
24737887SLiane.Praza@Sun.COM 		uu_die(gettext("prop_pattern name, \"%s\", for %s is %d "
24747887SLiane.Praza@Sun.COM 		    "characters too long\n"), (char *)prop_pattern_name,
24757887SLiane.Praza@Sun.COM 		    service->sc_name, extra - max_scf_name_len);
24767887SLiane.Praza@Sun.COM 	}
24777887SLiane.Praza@Sun.COM 
24787887SLiane.Praza@Sun.COM 	/*
24797887SLiane.Praza@Sun.COM 	 * Create the property group, the property referencing the pg_pattern
24807887SLiane.Praza@Sun.COM 	 * name, and add the prop_pattern attributes to the property group.
24817887SLiane.Praza@Sun.COM 	 */
24827887SLiane.Praza@Sun.COM 	pg = internal_pgroup_create_strict(service, pg_name,
24837887SLiane.Praza@Sun.COM 	    SCF_GROUP_TEMPLATE_PROP_PATTERN);
24847887SLiane.Praza@Sun.COM 	if (pg == NULL) {
24857887SLiane.Praza@Sun.COM 		uu_die(gettext("Property group for prop_pattern, \"%s\", "
24867887SLiane.Praza@Sun.COM 		    "already exists in %s\n"), prop_pattern_name,
24877887SLiane.Praza@Sun.COM 		    service->sc_name);
24887887SLiane.Praza@Sun.COM 	}
24897887SLiane.Praza@Sun.COM 
24907887SLiane.Praza@Sun.COM 	p = internal_property_create(SCF_PROPERTY_TM_PG_PATTERN,
24917887SLiane.Praza@Sun.COM 	    SCF_TYPE_ASTRING, 1, safe_strdup(pgpat_name));
24927887SLiane.Praza@Sun.COM 	/*
24937887SLiane.Praza@Sun.COM 	 * Unfortunately, internal_property_create() does not set the free
24947887SLiane.Praza@Sun.COM 	 * function for the value, so we'll set it now.
24957887SLiane.Praza@Sun.COM 	 */
24967887SLiane.Praza@Sun.COM 	v = uu_list_first(p->sc_property_values);
24977887SLiane.Praza@Sun.COM 	v->sc_free = lxml_free_str;
24987887SLiane.Praza@Sun.COM 	if (internal_attach_property(pg, p) != 0)
24997887SLiane.Praza@Sun.COM 		internal_property_free(p);
25007887SLiane.Praza@Sun.COM 
25017887SLiane.Praza@Sun.COM 
25027887SLiane.Praza@Sun.COM 	r = lxml_get_prop_pattern_attributes(pg, prop_pattern);
25037887SLiane.Praza@Sun.COM 	if (r != 0)
25047887SLiane.Praza@Sun.COM 		goto out;
25057887SLiane.Praza@Sun.COM 
25067887SLiane.Praza@Sun.COM 	/*
25077887SLiane.Praza@Sun.COM 	 * Now process the elements of prop_pattern
25087887SLiane.Praza@Sun.COM 	 */
25097887SLiane.Praza@Sun.COM 	for (cursor = prop_pattern->xmlChildrenNode;
25107887SLiane.Praza@Sun.COM 	    cursor != NULL;
25117887SLiane.Praza@Sun.COM 	    cursor = cursor->next) {
25127887SLiane.Praza@Sun.COM 		if (lxml_ignorable_block(cursor))
25137887SLiane.Praza@Sun.COM 			continue;
25147887SLiane.Praza@Sun.COM 
25157887SLiane.Praza@Sun.COM 		switch (lxml_xlate_element(cursor->name)) {
25167887SLiane.Praza@Sun.COM 		case SC_CARDINALITY:
25177887SLiane.Praza@Sun.COM 			r = lxml_get_tm_cardinality(service, pg, cursor);
25187887SLiane.Praza@Sun.COM 			if (r != 0)
25197887SLiane.Praza@Sun.COM 				goto out;
25207887SLiane.Praza@Sun.COM 			break;
25217887SLiane.Praza@Sun.COM 		case SC_CHOICES:
25227887SLiane.Praza@Sun.COM 			r = lxml_get_tm_choices(service, pg, cursor);
25237887SLiane.Praza@Sun.COM 			if (r != 0)
25247887SLiane.Praza@Sun.COM 				goto out;
25257887SLiane.Praza@Sun.COM 			break;
25267887SLiane.Praza@Sun.COM 		case SC_COMMON_NAME:
25277887SLiane.Praza@Sun.COM 			(void) lxml_get_all_loctext(service, pg, cursor,
25287887SLiane.Praza@Sun.COM 			    COMMON_NAME_FMT, (const char *)cursor->name);
25297887SLiane.Praza@Sun.COM 			break;
25307887SLiane.Praza@Sun.COM 		case SC_CONSTRAINTS:
25317887SLiane.Praza@Sun.COM 			r = lxml_get_tm_constraints(service, pg, cursor);
25327887SLiane.Praza@Sun.COM 			if (r != 0)
25337887SLiane.Praza@Sun.COM 				goto out;
25347887SLiane.Praza@Sun.COM 			break;
25357887SLiane.Praza@Sun.COM 		case SC_DESCRIPTION:
25367887SLiane.Praza@Sun.COM 			(void) lxml_get_all_loctext(service, pg, cursor,
25377887SLiane.Praza@Sun.COM 			    DESCRIPTION_FMT, (const char *)cursor->name);
25387887SLiane.Praza@Sun.COM 			break;
25397887SLiane.Praza@Sun.COM 		case SC_INTERNAL_SEPARATORS:
25407887SLiane.Praza@Sun.COM 			r = lxml_get_tm_internal_seps(service, pg, cursor);
25417887SLiane.Praza@Sun.COM 			if (r != 0)
25427887SLiane.Praza@Sun.COM 				goto out;
25437887SLiane.Praza@Sun.COM 			break;
25447887SLiane.Praza@Sun.COM 		case SC_UNITS:
25457887SLiane.Praza@Sun.COM 			(void) lxml_get_all_loctext(service, pg, cursor,
25467887SLiane.Praza@Sun.COM 			    UNITS_FMT, "units");
25477887SLiane.Praza@Sun.COM 			break;
25487887SLiane.Praza@Sun.COM 		case SC_VALUES:
25497887SLiane.Praza@Sun.COM 			(void) lxml_get_tm_values(service, pg, cursor);
25507887SLiane.Praza@Sun.COM 			break;
25517887SLiane.Praza@Sun.COM 		case SC_VISIBILITY:
25527887SLiane.Praza@Sun.COM 			/*
25537887SLiane.Praza@Sun.COM 			 * The visibility element is empty, so we only need
25547887SLiane.Praza@Sun.COM 			 * to proccess the value attribute.
25557887SLiane.Praza@Sun.COM 			 */
25567887SLiane.Praza@Sun.COM 			(void) new_str_prop_from_attr(pg,
25577887SLiane.Praza@Sun.COM 			    SCF_PROPERTY_TM_VISIBILITY, SCF_TYPE_ASTRING,
25587887SLiane.Praza@Sun.COM 			    cursor, value_attr);
25597887SLiane.Praza@Sun.COM 			break;
25607887SLiane.Praza@Sun.COM 		default:
25617887SLiane.Praza@Sun.COM 			uu_die(gettext("illegal element \"%s\" in prop_pattern "
25627887SLiane.Praza@Sun.COM 			    "for service \"%s\"\n"), cursor->name,
25637887SLiane.Praza@Sun.COM 			    service->sc_name);
25647887SLiane.Praza@Sun.COM 		}
25657887SLiane.Praza@Sun.COM 	}
25667887SLiane.Praza@Sun.COM 
25677887SLiane.Praza@Sun.COM out:
25687887SLiane.Praza@Sun.COM 	xmlFree(prop_pattern_name);
25697887SLiane.Praza@Sun.COM 	free(pg_name);
25707887SLiane.Praza@Sun.COM 	return (r);
25717887SLiane.Praza@Sun.COM }
25727887SLiane.Praza@Sun.COM 
25737887SLiane.Praza@Sun.COM /*
25747887SLiane.Praza@Sun.COM  * Get the pg_pattern attributes and save them as properties in the
25757887SLiane.Praza@Sun.COM  * property group at pg.  The pg_pattern element accepts four attributes --
25767887SLiane.Praza@Sun.COM  * name, type, required and target.
25777887SLiane.Praza@Sun.COM  */
25787887SLiane.Praza@Sun.COM static int
25797887SLiane.Praza@Sun.COM lxml_get_pg_pattern_attributes(pgroup_t *pg, xmlNodePtr cursor)
25807887SLiane.Praza@Sun.COM {
25817887SLiane.Praza@Sun.COM 	if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_TM_NAME,
25827887SLiane.Praza@Sun.COM 	    SCF_TYPE_ASTRING, cursor, name_attr, NULL) != 0) {
25837887SLiane.Praza@Sun.COM 		return (-1);
25847887SLiane.Praza@Sun.COM 	}
25857887SLiane.Praza@Sun.COM 	if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_TM_TYPE,
25867887SLiane.Praza@Sun.COM 	    SCF_TYPE_ASTRING, cursor, type_attr, NULL) != 0) {
25877887SLiane.Praza@Sun.COM 		return (-1);
25887887SLiane.Praza@Sun.COM 	}
25897887SLiane.Praza@Sun.COM 	if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_TM_TARGET,
25907887SLiane.Praza@Sun.COM 	    SCF_TYPE_ASTRING, cursor, target_attr, NULL) != 0) {
25917887SLiane.Praza@Sun.COM 		return (-1);
25927887SLiane.Praza@Sun.COM 	}
25937887SLiane.Praza@Sun.COM 	if (new_bool_prop_from_attr(pg, SCF_PROPERTY_TM_REQUIRED, cursor,
25947887SLiane.Praza@Sun.COM 	    required_attr) != 0)
25957887SLiane.Praza@Sun.COM 		return (-1);
25967887SLiane.Praza@Sun.COM 	return (0);
25977887SLiane.Praza@Sun.COM }
25987887SLiane.Praza@Sun.COM 
25997887SLiane.Praza@Sun.COM /*
26007887SLiane.Praza@Sun.COM  * There are several restrictions on the pg_pattern attributes that cannot
26017887SLiane.Praza@Sun.COM  * be specifed in the service bundle DTD.  This function verifies that
26027887SLiane.Praza@Sun.COM  * those restrictions have been satisfied.  The restrictions are:
26037887SLiane.Praza@Sun.COM  *
26047887SLiane.Praza@Sun.COM  *	- The target attribute may have a value of "instance" only when the
26057887SLiane.Praza@Sun.COM  *	  template block is in a service declaration.
26067887SLiane.Praza@Sun.COM  *
26077887SLiane.Praza@Sun.COM  *	- The target attribute may have a value of "delegate" only when the
26087887SLiane.Praza@Sun.COM  *	  template block applies to a restarter.
26097887SLiane.Praza@Sun.COM  *
26107887SLiane.Praza@Sun.COM  *	- The target attribute may have a value of "all" only when the
26117887SLiane.Praza@Sun.COM  *	  template block applies to the master restarter.
26127887SLiane.Praza@Sun.COM  *
26137887SLiane.Praza@Sun.COM  * The function returns 0 on success and -1 on failure.
26147887SLiane.Praza@Sun.COM  */
26157887SLiane.Praza@Sun.COM static int
26167887SLiane.Praza@Sun.COM verify_pg_pattern_attributes(entity_t *s, pgroup_t *pg)
26177887SLiane.Praza@Sun.COM {
26187887SLiane.Praza@Sun.COM 	int is_restarter;
26197887SLiane.Praza@Sun.COM 	property_t *target;
26207887SLiane.Praza@Sun.COM 	value_t *v;
26217887SLiane.Praza@Sun.COM 
26227887SLiane.Praza@Sun.COM 	/* Find the value of the target property. */
26237887SLiane.Praza@Sun.COM 	target = internal_property_find(pg, SCF_PROPERTY_TM_TARGET);
26247887SLiane.Praza@Sun.COM 	if (target == NULL) {
26257887SLiane.Praza@Sun.COM 		uu_die(gettext("pg_pattern is missing the %s attribute "
26267887SLiane.Praza@Sun.COM 		    "in %s\n"), target_attr, s->sc_name);
26277887SLiane.Praza@Sun.COM 		return (-1);
26287887SLiane.Praza@Sun.COM 	}
26297887SLiane.Praza@Sun.COM 	v = uu_list_first(target->sc_property_values);
26307887SLiane.Praza@Sun.COM 	assert(v != NULL);
26317887SLiane.Praza@Sun.COM 	assert(v->sc_type == SCF_TYPE_ASTRING);
26327887SLiane.Praza@Sun.COM 
26337887SLiane.Praza@Sun.COM 	/*
26347887SLiane.Praza@Sun.COM 	 * If target has a value of instance, the template must be in a
26357887SLiane.Praza@Sun.COM 	 * service object.
26367887SLiane.Praza@Sun.COM 	 */
26377887SLiane.Praza@Sun.COM 	if (strcmp(v->sc_u.sc_string, "instance") == 0) {
26387887SLiane.Praza@Sun.COM 		if (s->sc_etype != SVCCFG_SERVICE_OBJECT) {
26397887SLiane.Praza@Sun.COM 			uu_warn(gettext("pg_pattern %s attribute may only "
26407887SLiane.Praza@Sun.COM 			    "have a value of \"instance\" when it is in a "
26417887SLiane.Praza@Sun.COM 			    "service declaration.\n"), target_attr);
26427887SLiane.Praza@Sun.COM 			return (-1);
26437887SLiane.Praza@Sun.COM 		}
26447887SLiane.Praza@Sun.COM 	}
26457887SLiane.Praza@Sun.COM 
26467887SLiane.Praza@Sun.COM 	/*
26477887SLiane.Praza@Sun.COM 	 * If target has a value of "delegate", the template must be in a
26487887SLiane.Praza@Sun.COM 	 * restarter.
26497887SLiane.Praza@Sun.COM 	 */
26507887SLiane.Praza@Sun.COM 	if (strcmp(v->sc_u.sc_string, "delegate") == 0) {
26517887SLiane.Praza@Sun.COM 		is_restarter = 0;
26527887SLiane.Praza@Sun.COM 		if ((s->sc_etype == SVCCFG_SERVICE_OBJECT) &&
26537887SLiane.Praza@Sun.COM 		    (s->sc_u.sc_service.sc_service_type == SVCCFG_RESTARTER)) {
26547887SLiane.Praza@Sun.COM 			is_restarter = 1;
26557887SLiane.Praza@Sun.COM 		}
26567887SLiane.Praza@Sun.COM 		if ((s->sc_etype == SVCCFG_INSTANCE_OBJECT) &&
26577887SLiane.Praza@Sun.COM 		    (s->sc_parent->sc_u.sc_service.sc_service_type ==
26587887SLiane.Praza@Sun.COM 		    SVCCFG_RESTARTER)) {
26597887SLiane.Praza@Sun.COM 			is_restarter = 1;
26607887SLiane.Praza@Sun.COM 		}
26617887SLiane.Praza@Sun.COM 		if (is_restarter == 0) {
26627887SLiane.Praza@Sun.COM 			uu_warn(gettext("pg_pattern %s attribute has a "
26637887SLiane.Praza@Sun.COM 			    "value of \"delegate\" but is not in a "
26647887SLiane.Praza@Sun.COM 			    "restarter service\n"), target_attr);
26657887SLiane.Praza@Sun.COM 			return (-1);
26667887SLiane.Praza@Sun.COM 		}
26677887SLiane.Praza@Sun.COM 	}
26687887SLiane.Praza@Sun.COM 
26697887SLiane.Praza@Sun.COM 	/*
26707887SLiane.Praza@Sun.COM 	 * If target has a value of "all", the template must be in the
26717887SLiane.Praza@Sun.COM 	 * global (SCF_SERVICE_GLOBAL) service.
26727887SLiane.Praza@Sun.COM 	 */
26737887SLiane.Praza@Sun.COM 	if (strcmp(v->sc_u.sc_string, all_value) == 0) {
26747887SLiane.Praza@Sun.COM 		if (s->sc_etype != SVCCFG_SERVICE_OBJECT) {
26757887SLiane.Praza@Sun.COM 			uu_warn(gettext("pg_pattern %s attribute has a "
26767887SLiane.Praza@Sun.COM 			    "value of \"%s\" but is not in a "
26777887SLiane.Praza@Sun.COM 			    "service entity.\n"), target_attr, all_value);
26787887SLiane.Praza@Sun.COM 			return (-1);
26797887SLiane.Praza@Sun.COM 		}
26807887SLiane.Praza@Sun.COM 		if (strcmp(s->sc_fmri, SCF_SERVICE_GLOBAL) != 0) {
26817887SLiane.Praza@Sun.COM 			uu_warn(gettext("pg_pattern %s attribute has a "
26827887SLiane.Praza@Sun.COM 			    "value of \"%s\" but is in the \"%s\" service.  "
26837887SLiane.Praza@Sun.COM 			    "pg_patterns with target \"%s\" are only allowed "
26847887SLiane.Praza@Sun.COM 			    "in the global service.\n"),
26857887SLiane.Praza@Sun.COM 			    target_attr, all_value, s->sc_fmri, all_value);
26867887SLiane.Praza@Sun.COM 			return (-1);
26877887SLiane.Praza@Sun.COM 		}
26887887SLiane.Praza@Sun.COM 	}
26897887SLiane.Praza@Sun.COM 
26907887SLiane.Praza@Sun.COM 	return (0);
26917887SLiane.Praza@Sun.COM }
26927887SLiane.Praza@Sun.COM 
26937887SLiane.Praza@Sun.COM static int
26947887SLiane.Praza@Sun.COM lxml_get_tm_pg_pattern(entity_t *service, xmlNodePtr pg_pattern)
26957887SLiane.Praza@Sun.COM {
26967887SLiane.Praza@Sun.COM 	xmlNodePtr cursor;
26977887SLiane.Praza@Sun.COM 	int out_len;
26987887SLiane.Praza@Sun.COM 	xmlChar *name;
26997887SLiane.Praza@Sun.COM 	pgroup_t *pg = NULL;
27007887SLiane.Praza@Sun.COM 	char *pg_name;
27017887SLiane.Praza@Sun.COM 	int r = -1;
27027887SLiane.Praza@Sun.COM 	xmlChar *type;
27037887SLiane.Praza@Sun.COM 
27047887SLiane.Praza@Sun.COM 	pg_name = safe_malloc(max_scf_name_len + 1);
27057887SLiane.Praza@Sun.COM 
27067887SLiane.Praza@Sun.COM 	/*
27077887SLiane.Praza@Sun.COM 	 * Get the name and type attributes.  Their presence or absence
27087887SLiane.Praza@Sun.COM 	 * determines whcih prefix we will use for the property group name.
27097887SLiane.Praza@Sun.COM 	 * There are four cases -- neither attribute is present, both are
27107887SLiane.Praza@Sun.COM 	 * present, only name is present or only type is present.
27117887SLiane.Praza@Sun.COM 	 */
27127887SLiane.Praza@Sun.COM 	name = xmlGetProp(pg_pattern, (xmlChar *)name_attr);
27137887SLiane.Praza@Sun.COM 	type = xmlGetProp(pg_pattern, (xmlChar *)type_attr);
27147887SLiane.Praza@Sun.COM 	if ((name == NULL) || (*name == 0)) {
27157887SLiane.Praza@Sun.COM 		if ((type == NULL) || (*type == 0)) {
27167887SLiane.Praza@Sun.COM 			/* PG name contains only the prefix in this case */
27177887SLiane.Praza@Sun.COM 			if (strlcpy(pg_name, SCF_PG_TM_PG_PATTERN_PREFIX,
27187887SLiane.Praza@Sun.COM 			    max_scf_name_len + 1) >= max_scf_name_len + 1) {
27197887SLiane.Praza@Sun.COM 				uu_die(gettext("Unable to create pg_pattern "
27207887SLiane.Praza@Sun.COM 				    "property for %s\n"), service->sc_name);
27217887SLiane.Praza@Sun.COM 			}
27227887SLiane.Praza@Sun.COM 		} else {
27237887SLiane.Praza@Sun.COM 			/*
27247887SLiane.Praza@Sun.COM 			 * If we have a type and no name, the type becomes
27257887SLiane.Praza@Sun.COM 			 * part of the pg_pattern property group name.
27267887SLiane.Praza@Sun.COM 			 */
27277887SLiane.Praza@Sun.COM 			if ((out_len = snprintf(pg_name, max_scf_name_len + 1,
27287887SLiane.Praza@Sun.COM 			    "%s%s", SCF_PG_TM_PG_PATTERN_T_PREFIX, type)) >=
27297887SLiane.Praza@Sun.COM 			    max_scf_name_len + 1) {
27307887SLiane.Praza@Sun.COM 				uu_die(gettext("pg_pattern type is for %s is "
27317887SLiane.Praza@Sun.COM 				    "%d bytes too long\n"), service->sc_name,
27327887SLiane.Praza@Sun.COM 				    out_len - max_scf_name_len);
27337887SLiane.Praza@Sun.COM 			}
27347887SLiane.Praza@Sun.COM 		}
27357887SLiane.Praza@Sun.COM 	} else {
27367887SLiane.Praza@Sun.COM 		const char *prefix;
27377887SLiane.Praza@Sun.COM 
27387887SLiane.Praza@Sun.COM 		/* Make sure that the name is valid. */
27397887SLiane.Praza@Sun.COM 		if (uu_check_name((const char *)name, UU_NAME_DOMAIN) != 0) {
27407887SLiane.Praza@Sun.COM 			semerr(gettext("pg_pattern name attribute, \"%s\", "
27417887SLiane.Praza@Sun.COM 			    "for %s is invalid\n"), name, service->sc_name);
27427887SLiane.Praza@Sun.COM 			goto out;
27437887SLiane.Praza@Sun.COM 		}
27447887SLiane.Praza@Sun.COM 
27457887SLiane.Praza@Sun.COM 		/*
27467887SLiane.Praza@Sun.COM 		 * As long as the pg_pattern has a name, it becomes part of
27477887SLiane.Praza@Sun.COM 		 * the name of the pg_pattern property group name.  We
27487887SLiane.Praza@Sun.COM 		 * merely need to pick the appropriate prefix.
27497887SLiane.Praza@Sun.COM 		 */
27507887SLiane.Praza@Sun.COM 		if ((type == NULL) || (*type == 0)) {
27517887SLiane.Praza@Sun.COM 			prefix = SCF_PG_TM_PG_PATTERN_N_PREFIX;
27527887SLiane.Praza@Sun.COM 		} else {
27537887SLiane.Praza@Sun.COM 			prefix = SCF_PG_TM_PG_PATTERN_NT_PREFIX;
27547887SLiane.Praza@Sun.COM 		}
27557887SLiane.Praza@Sun.COM 		if ((out_len = snprintf(pg_name, max_scf_name_len + 1, "%s%s",
27567887SLiane.Praza@Sun.COM 		    prefix, name)) >= max_scf_name_len + 1) {
27577887SLiane.Praza@Sun.COM 			uu_die(gettext("pg_pattern property group name "
27587887SLiane.Praza@Sun.COM 			    "for %s is %d bytes too long\n"), service->sc_name,
27597887SLiane.Praza@Sun.COM 			    out_len - max_scf_name_len);
27607887SLiane.Praza@Sun.COM 		}
27617887SLiane.Praza@Sun.COM 	}
27627887SLiane.Praza@Sun.COM 
27637887SLiane.Praza@Sun.COM 	/*
27647887SLiane.Praza@Sun.COM 	 * Create the property group for holding this pg_pattern
27657887SLiane.Praza@Sun.COM 	 * information, and capture the pg_pattern attributes.
27667887SLiane.Praza@Sun.COM 	 */
27677887SLiane.Praza@Sun.COM 	pg = internal_pgroup_create_strict(service, pg_name,
27687887SLiane.Praza@Sun.COM 	    SCF_GROUP_TEMPLATE_PG_PATTERN);
27697887SLiane.Praza@Sun.COM 	if (pg == NULL) {
27707887SLiane.Praza@Sun.COM 		if ((name == NULL) || (*name == 0)) {
27717887SLiane.Praza@Sun.COM 			if ((type == NULL) ||(*type == 0)) {
27727887SLiane.Praza@Sun.COM 				semerr(gettext("pg_pattern with empty name and "
27737887SLiane.Praza@Sun.COM 				    "type is not unique in %s\n"),
27747887SLiane.Praza@Sun.COM 				    service->sc_name);
27757887SLiane.Praza@Sun.COM 			} else {
27767887SLiane.Praza@Sun.COM 				semerr(gettext("pg_pattern with empty name and "
27777887SLiane.Praza@Sun.COM 				    "type \"%s\" is not unique in %s\n"),
27787887SLiane.Praza@Sun.COM 				    type, service->sc_name);
27797887SLiane.Praza@Sun.COM 			}
27807887SLiane.Praza@Sun.COM 		} else {
27817887SLiane.Praza@Sun.COM 			if ((type == NULL) || (*type == 0)) {
27827887SLiane.Praza@Sun.COM 				semerr(gettext("pg_pattern with name \"%s\" "
27837887SLiane.Praza@Sun.COM 				    "and empty type is not unique in %s\n"),
27847887SLiane.Praza@Sun.COM 				    name, service->sc_name);
27857887SLiane.Praza@Sun.COM 			} else {
27867887SLiane.Praza@Sun.COM 				semerr(gettext("pg_pattern with name \"%s\" "
27877887SLiane.Praza@Sun.COM 				    "and type \"%s\" is not unique in %s\n"),
27887887SLiane.Praza@Sun.COM 				    name, type, service->sc_name);
27897887SLiane.Praza@Sun.COM 			}
27907887SLiane.Praza@Sun.COM 		}
27917887SLiane.Praza@Sun.COM 		goto out;
27927887SLiane.Praza@Sun.COM 	}
27937887SLiane.Praza@Sun.COM 
27947887SLiane.Praza@Sun.COM 	/*
27957887SLiane.Praza@Sun.COM 	 * Get the pg_pattern attributes from the manifest and verify
27967887SLiane.Praza@Sun.COM 	 * that they satisfy our restrictions.
27977887SLiane.Praza@Sun.COM 	 */
27987887SLiane.Praza@Sun.COM 	r = lxml_get_pg_pattern_attributes(pg, pg_pattern);
27997887SLiane.Praza@Sun.COM 	if (r != 0)
28007887SLiane.Praza@Sun.COM 		goto out;
28017887SLiane.Praza@Sun.COM 	if (verify_pg_pattern_attributes(service, pg) != 0) {
28027887SLiane.Praza@Sun.COM 		semerr(gettext("Invalid pg_pattern attributes in %s\n"),
28037887SLiane.Praza@Sun.COM 		    service->sc_name);
28047887SLiane.Praza@Sun.COM 		r = -1;
28057887SLiane.Praza@Sun.COM 		goto out;
28067887SLiane.Praza@Sun.COM 	}
28077887SLiane.Praza@Sun.COM 
28087887SLiane.Praza@Sun.COM 	/*
28097887SLiane.Praza@Sun.COM 	 * Now process all of the elements of pg_pattern.
28107887SLiane.Praza@Sun.COM 	 */
28117887SLiane.Praza@Sun.COM 	for (cursor = pg_pattern->xmlChildrenNode;
28127887SLiane.Praza@Sun.COM 	    cursor != NULL;
28137887SLiane.Praza@Sun.COM 	    cursor = cursor->next) {
28147887SLiane.Praza@Sun.COM 		if (lxml_ignorable_block(cursor))
28157887SLiane.Praza@Sun.COM 			continue;
28167887SLiane.Praza@Sun.COM 
28177887SLiane.Praza@Sun.COM 		switch (lxml_xlate_element(cursor->name)) {
28187887SLiane.Praza@Sun.COM 		case SC_COMMON_NAME:
28197887SLiane.Praza@Sun.COM 			(void) lxml_get_all_loctext(service, pg, cursor,
28207887SLiane.Praza@Sun.COM 			    COMMON_NAME_FMT, (const char *)cursor->name);
28217887SLiane.Praza@Sun.COM 			break;
28227887SLiane.Praza@Sun.COM 		case SC_DESCRIPTION:
28237887SLiane.Praza@Sun.COM 			(void) lxml_get_all_loctext(service, pg, cursor,
28247887SLiane.Praza@Sun.COM 			    DESCRIPTION_FMT, (const char *)cursor->name);
28257887SLiane.Praza@Sun.COM 			break;
28267887SLiane.Praza@Sun.COM 		case SC_PROP_PATTERN:
28277887SLiane.Praza@Sun.COM 			r = lxml_get_tm_prop_pattern(service, cursor,
28287887SLiane.Praza@Sun.COM 			    pg_name);
28297887SLiane.Praza@Sun.COM 			if (r != 0)
28307887SLiane.Praza@Sun.COM 				goto out;
28317887SLiane.Praza@Sun.COM 			break;
28327887SLiane.Praza@Sun.COM 		default:
28337887SLiane.Praza@Sun.COM 			uu_die(gettext("illegal element \"%s\" in pg_pattern "
28347887SLiane.Praza@Sun.COM 			    "for service \"%s\"\n"), cursor->name,
28357887SLiane.Praza@Sun.COM 			    service->sc_name);
28367887SLiane.Praza@Sun.COM 		}
28377887SLiane.Praza@Sun.COM 	}
28387887SLiane.Praza@Sun.COM 
28397887SLiane.Praza@Sun.COM out:
28407887SLiane.Praza@Sun.COM 	if ((r != 0) && (pg != NULL)) {
28417887SLiane.Praza@Sun.COM 		internal_detach_pgroup(service, pg);
28427887SLiane.Praza@Sun.COM 		internal_pgroup_free(pg);
28437887SLiane.Praza@Sun.COM 	}
28447887SLiane.Praza@Sun.COM 	free(pg_name);
28457887SLiane.Praza@Sun.COM 	xmlFree(name);
28467887SLiane.Praza@Sun.COM 	xmlFree(type);
28477887SLiane.Praza@Sun.COM 
28487887SLiane.Praza@Sun.COM 	return (r);
28497887SLiane.Praza@Sun.COM }
28507887SLiane.Praza@Sun.COM 
28517887SLiane.Praza@Sun.COM static int
28520Sstevel@tonic-gate lxml_get_template(entity_t *service, xmlNodePtr templ)
28530Sstevel@tonic-gate {
28540Sstevel@tonic-gate 	xmlNodePtr cursor;
28550Sstevel@tonic-gate 
28560Sstevel@tonic-gate 	for (cursor = templ->xmlChildrenNode; cursor != NULL;
28570Sstevel@tonic-gate 	    cursor = cursor->next) {
28580Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
28590Sstevel@tonic-gate 			continue;
28600Sstevel@tonic-gate 
28610Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
28620Sstevel@tonic-gate 		case SC_COMMON_NAME:
28630Sstevel@tonic-gate 			(void) lxml_get_tm_common_name(service, cursor);
28640Sstevel@tonic-gate 			break;
28650Sstevel@tonic-gate 		case SC_DESCRIPTION:
28660Sstevel@tonic-gate 			(void) lxml_get_tm_description(service, cursor);
28670Sstevel@tonic-gate 			break;
28680Sstevel@tonic-gate 		case SC_DOCUMENTATION:
28690Sstevel@tonic-gate 			(void) lxml_get_tm_documentation(service, cursor);
28700Sstevel@tonic-gate 			break;
28717887SLiane.Praza@Sun.COM 		case SC_PG_PATTERN:
28727887SLiane.Praza@Sun.COM 			if (lxml_get_tm_pg_pattern(service, cursor) != 0)
28737887SLiane.Praza@Sun.COM 				return (-1);
28747887SLiane.Praza@Sun.COM 			break;
28750Sstevel@tonic-gate 		default:
28760Sstevel@tonic-gate 			uu_die(gettext("illegal element \"%s\" on template "
28770Sstevel@tonic-gate 			    "for service \"%s\"\n"),
28780Sstevel@tonic-gate 			    cursor->name, service->sc_name);
28790Sstevel@tonic-gate 		}
28800Sstevel@tonic-gate 	}
28810Sstevel@tonic-gate 
28820Sstevel@tonic-gate 	return (0);
28830Sstevel@tonic-gate }
28840Sstevel@tonic-gate 
28850Sstevel@tonic-gate static int
28860Sstevel@tonic-gate lxml_get_default_instance(entity_t *service, xmlNodePtr definst)
28870Sstevel@tonic-gate {
28880Sstevel@tonic-gate 	entity_t *i;
28890Sstevel@tonic-gate 	xmlChar *enabled;
28900Sstevel@tonic-gate 	pgroup_t *pg;
28910Sstevel@tonic-gate 	property_t *p;
28920Sstevel@tonic-gate 	char *package;
28930Sstevel@tonic-gate 	uint64_t enabled_val = 0;
28940Sstevel@tonic-gate 
28950Sstevel@tonic-gate 	i = internal_instance_new("default");
28960Sstevel@tonic-gate 
28970Sstevel@tonic-gate 	if ((enabled = xmlGetProp(definst, (xmlChar *)enabled_attr)) != NULL) {
28980Sstevel@tonic-gate 		enabled_val = (strcmp(true, (const char *)enabled) == 0) ?
28990Sstevel@tonic-gate 		    1 : 0;
29000Sstevel@tonic-gate 		xmlFree(enabled);
29010Sstevel@tonic-gate 	}
29020Sstevel@tonic-gate 
29030Sstevel@tonic-gate 	/*
29040Sstevel@tonic-gate 	 * New general property group with enabled boolean property set.
29050Sstevel@tonic-gate 	 */
29060Sstevel@tonic-gate 
2907*12667SSean.Wilcox@Sun.COM 	i->sc_op = service->sc_op;
29080Sstevel@tonic-gate 	pg = internal_pgroup_new();
29090Sstevel@tonic-gate 	(void) internal_attach_pgroup(i, pg);
29100Sstevel@tonic-gate 
29110Sstevel@tonic-gate 	pg->sc_pgroup_name = (char *)scf_pg_general;
29120Sstevel@tonic-gate 	pg->sc_pgroup_type = (char *)scf_group_framework;
29130Sstevel@tonic-gate 	pg->sc_pgroup_flags = 0;
29140Sstevel@tonic-gate 
29150Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_ENABLED, SCF_TYPE_BOOLEAN, 1,
29160Sstevel@tonic-gate 	    enabled_val);
29170Sstevel@tonic-gate 
29180Sstevel@tonic-gate 	(void) internal_attach_property(pg, p);
29190Sstevel@tonic-gate 
29200Sstevel@tonic-gate 	/*
29210Sstevel@tonic-gate 	 * Add general/package property if PKGINST is set.
29220Sstevel@tonic-gate 	 */
29230Sstevel@tonic-gate 	if ((package = getenv("PKGINST")) != NULL) {
29240Sstevel@tonic-gate 		p = internal_property_create(SCF_PROPERTY_PACKAGE,
29250Sstevel@tonic-gate 		    SCF_TYPE_ASTRING, 1, package);
29260Sstevel@tonic-gate 
29270Sstevel@tonic-gate 		(void) internal_attach_property(pg, p);
29280Sstevel@tonic-gate 	}
29290Sstevel@tonic-gate 
29300Sstevel@tonic-gate 	return (internal_attach_entity(service, i));
29310Sstevel@tonic-gate }
29320Sstevel@tonic-gate 
29330Sstevel@tonic-gate /*
29340Sstevel@tonic-gate  * Translate an instance element into an internal property tree, added to
293510029SAntonello.Cruz@Sun.COM  * service.  If op is SVCCFG_OP_APPLY (i.e., apply a profile), set the
293610029SAntonello.Cruz@Sun.COM  * enabled property to override.
2937*12667SSean.Wilcox@Sun.COM  *
2938*12667SSean.Wilcox@Sun.COM  * If op is SVCCFG_OP_APPLY (i.e., apply a profile), do not allow for
2939*12667SSean.Wilcox@Sun.COM  * modification of template data.
29400Sstevel@tonic-gate  */
29410Sstevel@tonic-gate static int
294210029SAntonello.Cruz@Sun.COM lxml_get_instance(entity_t *service, xmlNodePtr inst, bundle_type_t bt,
294310029SAntonello.Cruz@Sun.COM     svccfg_op_t op)
29440Sstevel@tonic-gate {
29450Sstevel@tonic-gate 	entity_t *i;
29460Sstevel@tonic-gate 	pgroup_t *pg;
29470Sstevel@tonic-gate 	property_t *p;
29480Sstevel@tonic-gate 	xmlNodePtr cursor;
29490Sstevel@tonic-gate 	xmlChar *enabled;
295010029SAntonello.Cruz@Sun.COM 	int r, e_val;
29510Sstevel@tonic-gate 
29520Sstevel@tonic-gate 	/*
29530Sstevel@tonic-gate 	 * Fetch its attributes, as appropriate.
29540Sstevel@tonic-gate 	 */
29550Sstevel@tonic-gate 	i = internal_instance_new((char *)xmlGetProp(inst,
29560Sstevel@tonic-gate 	    (xmlChar *)name_attr));
29570Sstevel@tonic-gate 
29580Sstevel@tonic-gate 	/*
29590Sstevel@tonic-gate 	 * Note that this must be done before walking the children so that
29600Sstevel@tonic-gate 	 * sc_fmri is set in case we enter lxml_get_dependent().
29610Sstevel@tonic-gate 	 */
29620Sstevel@tonic-gate 	r = internal_attach_entity(service, i);
29630Sstevel@tonic-gate 	if (r != 0)
29640Sstevel@tonic-gate 		return (r);
29650Sstevel@tonic-gate 
2966*12667SSean.Wilcox@Sun.COM 	i->sc_op = op;
29670Sstevel@tonic-gate 	enabled = xmlGetProp(inst, (xmlChar *)enabled_attr);
29680Sstevel@tonic-gate 
296910029SAntonello.Cruz@Sun.COM 	if (enabled == NULL) {
297010029SAntonello.Cruz@Sun.COM 		if (bt == SVCCFG_MANIFEST) {
297110029SAntonello.Cruz@Sun.COM 			semerr(gettext("Instance \"%s\" missing attribute "
297210029SAntonello.Cruz@Sun.COM 			    "\"%s\".\n"), i->sc_name, enabled_attr);
297310029SAntonello.Cruz@Sun.COM 			return (-1);
297410029SAntonello.Cruz@Sun.COM 		}
297510029SAntonello.Cruz@Sun.COM 	} else {	/* enabled != NULL */
297610029SAntonello.Cruz@Sun.COM 		if (strcmp(true, (const char *)enabled) != 0 &&
297710029SAntonello.Cruz@Sun.COM 		    strcmp(false, (const char *)enabled) != 0) {
297810029SAntonello.Cruz@Sun.COM 			xmlFree(enabled);
297910029SAntonello.Cruz@Sun.COM 			semerr(gettext("Invalid enabled value\n"));
298010029SAntonello.Cruz@Sun.COM 			return (-1);
298110029SAntonello.Cruz@Sun.COM 		}
298210029SAntonello.Cruz@Sun.COM 		pg = internal_pgroup_new();
298310029SAntonello.Cruz@Sun.COM 		(void) internal_attach_pgroup(i, pg);
298410029SAntonello.Cruz@Sun.COM 
298510029SAntonello.Cruz@Sun.COM 		pg->sc_pgroup_name = (char *)scf_pg_general;
298610029SAntonello.Cruz@Sun.COM 		pg->sc_pgroup_type = (char *)scf_group_framework;
298710029SAntonello.Cruz@Sun.COM 		pg->sc_pgroup_flags = 0;
298810029SAntonello.Cruz@Sun.COM 
298910029SAntonello.Cruz@Sun.COM 		e_val = (strcmp(true, (const char *)enabled) == 0);
299010029SAntonello.Cruz@Sun.COM 		p = internal_property_create(SCF_PROPERTY_ENABLED,
299110029SAntonello.Cruz@Sun.COM 		    SCF_TYPE_BOOLEAN, 1, (uint64_t)e_val);
299210029SAntonello.Cruz@Sun.COM 
299310029SAntonello.Cruz@Sun.COM 		p->sc_property_override = (op == SVCCFG_OP_APPLY);
299410029SAntonello.Cruz@Sun.COM 
299510029SAntonello.Cruz@Sun.COM 		(void) internal_attach_property(pg, p);
299610029SAntonello.Cruz@Sun.COM 
299710029SAntonello.Cruz@Sun.COM 		xmlFree(enabled);
299810029SAntonello.Cruz@Sun.COM 	}
29990Sstevel@tonic-gate 
30000Sstevel@tonic-gate 	/*
30010Sstevel@tonic-gate 	 * Walk its child elements, as appropriate.
30020Sstevel@tonic-gate 	 */
30030Sstevel@tonic-gate 	for (cursor = inst->xmlChildrenNode; cursor != NULL;
30040Sstevel@tonic-gate 	    cursor = cursor->next) {
30050Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
30060Sstevel@tonic-gate 			continue;
30070Sstevel@tonic-gate 
30080Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
30090Sstevel@tonic-gate 		case SC_RESTARTER:
30100Sstevel@tonic-gate 			(void) lxml_get_restarter(i, cursor);
30110Sstevel@tonic-gate 			break;
30120Sstevel@tonic-gate 		case SC_DEPENDENCY:
30130Sstevel@tonic-gate 			(void) lxml_get_dependency(i, cursor);
30140Sstevel@tonic-gate 			break;
30150Sstevel@tonic-gate 		case SC_DEPENDENT:
30160Sstevel@tonic-gate 			(void) lxml_get_dependent(i, cursor);
30170Sstevel@tonic-gate 			break;
30180Sstevel@tonic-gate 		case SC_METHOD_CONTEXT:
30190Sstevel@tonic-gate 			(void) lxml_get_entity_method_context(i, cursor);
30200Sstevel@tonic-gate 			break;
30210Sstevel@tonic-gate 		case SC_EXEC_METHOD:
30220Sstevel@tonic-gate 			(void) lxml_get_exec_method(i, cursor);
30230Sstevel@tonic-gate 			break;
30240Sstevel@tonic-gate 		case SC_PROPERTY_GROUP:
30250Sstevel@tonic-gate 			(void) lxml_get_pgroup(i, cursor);
30260Sstevel@tonic-gate 			break;
30270Sstevel@tonic-gate 		case SC_TEMPLATE:
3028*12667SSean.Wilcox@Sun.COM 			if (op == SVCCFG_OP_APPLY) {
3029*12667SSean.Wilcox@Sun.COM 				semerr(gettext("Template data for \"%s\" may "
3030*12667SSean.Wilcox@Sun.COM 				    "not be modified in a profile.\n"),
3031*12667SSean.Wilcox@Sun.COM 				    i->sc_name);
3032*12667SSean.Wilcox@Sun.COM 
3033*12667SSean.Wilcox@Sun.COM 				return (-1);
3034*12667SSean.Wilcox@Sun.COM 			}
3035*12667SSean.Wilcox@Sun.COM 
30367887SLiane.Praza@Sun.COM 			if (lxml_get_template(i, cursor) != 0)
30377887SLiane.Praza@Sun.COM 				return (-1);
30380Sstevel@tonic-gate 			break;
30390Sstevel@tonic-gate 		default:
30400Sstevel@tonic-gate 			uu_die(gettext(
30410Sstevel@tonic-gate 			    "illegal element \"%s\" on instance \"%s\"\n"),
30420Sstevel@tonic-gate 			    cursor->name, i->sc_name);
30430Sstevel@tonic-gate 			break;
30440Sstevel@tonic-gate 		}
30450Sstevel@tonic-gate 	}
30460Sstevel@tonic-gate 
30470Sstevel@tonic-gate 	return (0);
30480Sstevel@tonic-gate }
30490Sstevel@tonic-gate 
30500Sstevel@tonic-gate /* ARGSUSED1 */
30510Sstevel@tonic-gate static int
30520Sstevel@tonic-gate lxml_get_single_instance(entity_t *entity, xmlNodePtr si)
30530Sstevel@tonic-gate {
30540Sstevel@tonic-gate 	pgroup_t *pg;
30550Sstevel@tonic-gate 	property_t *p;
30560Sstevel@tonic-gate 	int r;
30570Sstevel@tonic-gate 
30580Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(entity, (char *)scf_pg_general,
30590Sstevel@tonic-gate 	    (char *)scf_group_framework);
30600Sstevel@tonic-gate 
30610Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_SINGLE_INSTANCE,
30620Sstevel@tonic-gate 	    SCF_TYPE_BOOLEAN, 1, (uint64_t)1);
30630Sstevel@tonic-gate 
30640Sstevel@tonic-gate 	r = internal_attach_property(pg, p);
30650Sstevel@tonic-gate 	if (r != 0) {
30660Sstevel@tonic-gate 		internal_property_free(p);
30670Sstevel@tonic-gate 		return (-1);
30680Sstevel@tonic-gate 	}
30690Sstevel@tonic-gate 
30700Sstevel@tonic-gate 	return (0);
30710Sstevel@tonic-gate }
30720Sstevel@tonic-gate 
30730Sstevel@tonic-gate /*
307411996SThomas.Whitten@Sun.COM  * Check to see if the service should allow the upgrade
307511996SThomas.Whitten@Sun.COM  * process to handle adding of the manifestfiles linkage.
307611996SThomas.Whitten@Sun.COM  *
307711996SThomas.Whitten@Sun.COM  * If the service exists and does not have a manifestfiles
307811996SThomas.Whitten@Sun.COM  * property group then the upgrade process should handle
307911996SThomas.Whitten@Sun.COM  * the service.
308011996SThomas.Whitten@Sun.COM  *
308111996SThomas.Whitten@Sun.COM  * If the service doesn't exist or the service exists
308211996SThomas.Whitten@Sun.COM  * and has a manifestfiles property group then the import
308311996SThomas.Whitten@Sun.COM  * process can handle the manifestfiles property group
308411996SThomas.Whitten@Sun.COM  * work.
308511996SThomas.Whitten@Sun.COM  *
308611996SThomas.Whitten@Sun.COM  * This prevents potential cleanup of unaccounted for instances
308711996SThomas.Whitten@Sun.COM  * in early manifest import due to upgrade process needing
308811996SThomas.Whitten@Sun.COM  * information that has not yet been supplied by manifests
308911996SThomas.Whitten@Sun.COM  * that are still located in the /var/svc manifests directory.
309011996SThomas.Whitten@Sun.COM  */
309111996SThomas.Whitten@Sun.COM static int
309211996SThomas.Whitten@Sun.COM lxml_check_upgrade(const char *service) {
309311996SThomas.Whitten@Sun.COM 	scf_handle_t	*h = NULL;
309411996SThomas.Whitten@Sun.COM 	scf_scope_t	*sc = NULL;
309511996SThomas.Whitten@Sun.COM 	scf_service_t	*svc = NULL;
309611996SThomas.Whitten@Sun.COM 	scf_propertygroup_t	*pg = NULL;
309711996SThomas.Whitten@Sun.COM 	int rc = SCF_FAILED;
309811996SThomas.Whitten@Sun.COM 
309911996SThomas.Whitten@Sun.COM 	if ((h = scf_handle_create(SCF_VERSION)) == NULL ||
310011996SThomas.Whitten@Sun.COM 	    (sc = scf_scope_create(h)) == NULL ||
310111996SThomas.Whitten@Sun.COM 	    (svc = scf_service_create(h)) == NULL ||
310211996SThomas.Whitten@Sun.COM 	    (pg = scf_pg_create(h)) == NULL)
310311996SThomas.Whitten@Sun.COM 		goto out;
310411996SThomas.Whitten@Sun.COM 
310511996SThomas.Whitten@Sun.COM 	if (scf_handle_bind(h) != 0)
310611996SThomas.Whitten@Sun.COM 		goto out;
310711996SThomas.Whitten@Sun.COM 
310811996SThomas.Whitten@Sun.COM 	if (scf_handle_get_scope(h, SCF_FMRI_LOCAL_SCOPE, sc) == -1)
310911996SThomas.Whitten@Sun.COM 		goto out;
311011996SThomas.Whitten@Sun.COM 
311111996SThomas.Whitten@Sun.COM 	if (scf_scope_get_service(sc, service, svc) != SCF_SUCCESS) {
311211996SThomas.Whitten@Sun.COM 		if (scf_error() == SCF_ERROR_NOT_FOUND)
311311996SThomas.Whitten@Sun.COM 			rc = SCF_SUCCESS;
311411996SThomas.Whitten@Sun.COM 
311511996SThomas.Whitten@Sun.COM 		goto out;
311611996SThomas.Whitten@Sun.COM 	}
311711996SThomas.Whitten@Sun.COM 
311811996SThomas.Whitten@Sun.COM 	if (scf_service_get_pg(svc, SCF_PG_MANIFESTFILES, pg) != SCF_SUCCESS)
311911996SThomas.Whitten@Sun.COM 		goto out;
312011996SThomas.Whitten@Sun.COM 
312111996SThomas.Whitten@Sun.COM 	rc = SCF_SUCCESS;
312211996SThomas.Whitten@Sun.COM out:
312311996SThomas.Whitten@Sun.COM 	scf_pg_destroy(pg);
312411996SThomas.Whitten@Sun.COM 	scf_service_destroy(svc);
312511996SThomas.Whitten@Sun.COM 	scf_scope_destroy(sc);
312611996SThomas.Whitten@Sun.COM 	scf_handle_destroy(h);
312711996SThomas.Whitten@Sun.COM 
312811996SThomas.Whitten@Sun.COM 	return (rc);
312911996SThomas.Whitten@Sun.COM }
313011996SThomas.Whitten@Sun.COM 
313111996SThomas.Whitten@Sun.COM /*
31320Sstevel@tonic-gate  * Translate a service element into an internal instance/property tree, added
3133*12667SSean.Wilcox@Sun.COM  * to bundle.
3134*12667SSean.Wilcox@Sun.COM  *
3135*12667SSean.Wilcox@Sun.COM  * If op is SVCCFG_OP_APPLY (i.e., apply a profile), do not allow for
3136*12667SSean.Wilcox@Sun.COM  * modification of template data.
31370Sstevel@tonic-gate  */
31380Sstevel@tonic-gate static int
31395040Swesolows lxml_get_service(bundle_t *bundle, xmlNodePtr svc, svccfg_op_t op)
31400Sstevel@tonic-gate {
314110461SSean.Wilcox@Sun.COM 	pgroup_t *pg;
314210461SSean.Wilcox@Sun.COM 	property_t *p;
31430Sstevel@tonic-gate 	entity_t *s;
31440Sstevel@tonic-gate 	xmlNodePtr cursor;
31450Sstevel@tonic-gate 	xmlChar *type;
31460Sstevel@tonic-gate 	xmlChar *version;
31470Sstevel@tonic-gate 	int e;
31480Sstevel@tonic-gate 
31490Sstevel@tonic-gate 	/*
31500Sstevel@tonic-gate 	 * Fetch attributes, as appropriate.
31510Sstevel@tonic-gate 	 */
31520Sstevel@tonic-gate 	s = internal_service_new((char *)xmlGetProp(svc,
31530Sstevel@tonic-gate 	    (xmlChar *)name_attr));
31540Sstevel@tonic-gate 
31557887SLiane.Praza@Sun.COM 	version = xmlGetProp(svc, (xmlChar *)version_attr);
31560Sstevel@tonic-gate 	s->sc_u.sc_service.sc_service_version = atol((const char *)version);
31570Sstevel@tonic-gate 	xmlFree(version);
31580Sstevel@tonic-gate 
31590Sstevel@tonic-gate 	type = xmlGetProp(svc, (xmlChar *)type_attr);
31600Sstevel@tonic-gate 	s->sc_u.sc_service.sc_service_type = lxml_xlate_service_type(type);
31610Sstevel@tonic-gate 	xmlFree(type);
31620Sstevel@tonic-gate 
31630Sstevel@tonic-gate 	/*
3164*12667SSean.Wilcox@Sun.COM 	 * Set the global missing type to false before processing the service
3165*12667SSean.Wilcox@Sun.COM 	 */
3166*12667SSean.Wilcox@Sun.COM 	est->sc_miss_type = B_FALSE;
3167*12667SSean.Wilcox@Sun.COM 	s->sc_op = op;
3168*12667SSean.Wilcox@Sun.COM 
3169*12667SSean.Wilcox@Sun.COM 	/*
317010461SSean.Wilcox@Sun.COM 	 * Now that the service is created create the manifest
317110461SSean.Wilcox@Sun.COM 	 * property group and add the property value of the service.
317210461SSean.Wilcox@Sun.COM 	 */
317311996SThomas.Whitten@Sun.COM 	if (lxml_check_upgrade(s->sc_name) == SCF_SUCCESS &&
317411996SThomas.Whitten@Sun.COM 	    svc->doc->name != NULL &&
317510461SSean.Wilcox@Sun.COM 	    bundle->sc_bundle_type == SVCCFG_MANIFEST) {
317612172SSean.Wilcox@Sun.COM 		char *buf, *base, *fname, *bname;
317712172SSean.Wilcox@Sun.COM 		size_t	base_sz = 0;
317812172SSean.Wilcox@Sun.COM 
317912172SSean.Wilcox@Sun.COM 		/*
318012172SSean.Wilcox@Sun.COM 		 * Must remove the PKG_INSTALL_ROOT, point to the correct
318112172SSean.Wilcox@Sun.COM 		 * directory after install
318212172SSean.Wilcox@Sun.COM 		 */
318312172SSean.Wilcox@Sun.COM 		bname = uu_zalloc(PATH_MAX + 1);
318412172SSean.Wilcox@Sun.COM 		if (realpath(svc->doc->name, bname) == NULL) {
318512172SSean.Wilcox@Sun.COM 			uu_die(gettext("Unable to create the real path of the "
318612172SSean.Wilcox@Sun.COM 			    "manifest file \"%s\" : %d\n"), svc->doc->name,
318712172SSean.Wilcox@Sun.COM 			    errno);
318812172SSean.Wilcox@Sun.COM 		}
318912172SSean.Wilcox@Sun.COM 
319012172SSean.Wilcox@Sun.COM 		base = getenv("PKG_INSTALL_ROOT");
319112172SSean.Wilcox@Sun.COM 		if (base != NULL && strncmp(bname, base, strlen(base)) == 0) {
319212172SSean.Wilcox@Sun.COM 			base_sz = strlen(base);
319312172SSean.Wilcox@Sun.COM 		}
319412172SSean.Wilcox@Sun.COM 		fname = safe_strdup(bname + base_sz);
319512172SSean.Wilcox@Sun.COM 
319612172SSean.Wilcox@Sun.COM 		uu_free(bname);
319712172SSean.Wilcox@Sun.COM 		buf = mhash_filename_to_propname(svc->doc->name, B_FALSE);
319810461SSean.Wilcox@Sun.COM 
319910461SSean.Wilcox@Sun.COM 		pg = internal_pgroup_create_strict(s, SCF_PG_MANIFESTFILES,
320010461SSean.Wilcox@Sun.COM 		    SCF_GROUP_FRAMEWORK);
320110461SSean.Wilcox@Sun.COM 
320210461SSean.Wilcox@Sun.COM 		if (pg == NULL) {
320310461SSean.Wilcox@Sun.COM 			uu_die(gettext("Property group for prop_pattern, "
320410461SSean.Wilcox@Sun.COM 			    "\"%s\", already exists in %s\n"),
320510461SSean.Wilcox@Sun.COM 			    SCF_PG_MANIFESTFILES, s->sc_name);
320610461SSean.Wilcox@Sun.COM 		}
320710461SSean.Wilcox@Sun.COM 
320810461SSean.Wilcox@Sun.COM 		p = internal_property_create(buf, SCF_TYPE_ASTRING, 1, fname);
320910461SSean.Wilcox@Sun.COM 
321010461SSean.Wilcox@Sun.COM 		(void) internal_attach_property(pg, p);
321110461SSean.Wilcox@Sun.COM 	}
321210461SSean.Wilcox@Sun.COM 
321310461SSean.Wilcox@Sun.COM 	/*
32140Sstevel@tonic-gate 	 * Walk its child elements, as appropriate.
32150Sstevel@tonic-gate 	 */
32160Sstevel@tonic-gate 	for (cursor = svc->xmlChildrenNode; cursor != NULL;
32170Sstevel@tonic-gate 	    cursor = cursor->next) {
32180Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
32190Sstevel@tonic-gate 			continue;
32200Sstevel@tonic-gate 
32210Sstevel@tonic-gate 		e = lxml_xlate_element(cursor->name);
32220Sstevel@tonic-gate 
32230Sstevel@tonic-gate 		switch (e) {
32240Sstevel@tonic-gate 		case SC_INSTANCE:
322510029SAntonello.Cruz@Sun.COM 			if (lxml_get_instance(s, cursor,
322610029SAntonello.Cruz@Sun.COM 			    bundle->sc_bundle_type, op) != 0)
32277887SLiane.Praza@Sun.COM 				return (-1);
32280Sstevel@tonic-gate 			break;
32290Sstevel@tonic-gate 		case SC_TEMPLATE:
3230*12667SSean.Wilcox@Sun.COM 			if (op == SVCCFG_OP_APPLY) {
3231*12667SSean.Wilcox@Sun.COM 				semerr(gettext("Template data for \"%s\" may "
3232*12667SSean.Wilcox@Sun.COM 				    "not be modified in a profile.\n"),
3233*12667SSean.Wilcox@Sun.COM 				    s->sc_name);
3234*12667SSean.Wilcox@Sun.COM 
3235*12667SSean.Wilcox@Sun.COM 				return (-1);
3236*12667SSean.Wilcox@Sun.COM 			}
3237*12667SSean.Wilcox@Sun.COM 
32387887SLiane.Praza@Sun.COM 			if (lxml_get_template(s, cursor) != 0)
32397887SLiane.Praza@Sun.COM 				return (-1);
32400Sstevel@tonic-gate 			break;
32410Sstevel@tonic-gate 		case SC_STABILITY:
32420Sstevel@tonic-gate 			(void) lxml_get_entity_stability(s, cursor);
32430Sstevel@tonic-gate 			break;
32440Sstevel@tonic-gate 		case SC_DEPENDENCY:
32450Sstevel@tonic-gate 			(void) lxml_get_dependency(s, cursor);
32460Sstevel@tonic-gate 			break;
32470Sstevel@tonic-gate 		case SC_DEPENDENT:
32480Sstevel@tonic-gate 			(void) lxml_get_dependent(s, cursor);
32490Sstevel@tonic-gate 			break;
32500Sstevel@tonic-gate 		case SC_RESTARTER:
32510Sstevel@tonic-gate 			(void) lxml_get_restarter(s, cursor);
32520Sstevel@tonic-gate 			break;
32530Sstevel@tonic-gate 		case SC_EXEC_METHOD:
32540Sstevel@tonic-gate 			(void) lxml_get_exec_method(s, cursor);
32550Sstevel@tonic-gate 			break;
32560Sstevel@tonic-gate 		case SC_METHOD_CONTEXT:
32570Sstevel@tonic-gate 			(void) lxml_get_entity_method_context(s, cursor);
32580Sstevel@tonic-gate 			break;
32590Sstevel@tonic-gate 		case SC_PROPERTY_GROUP:
32600Sstevel@tonic-gate 			(void) lxml_get_pgroup(s, cursor);
32610Sstevel@tonic-gate 			break;
32620Sstevel@tonic-gate 		case SC_INSTANCE_CREATE_DEFAULT:
32630Sstevel@tonic-gate 			(void) lxml_get_default_instance(s, cursor);
32640Sstevel@tonic-gate 			break;
32650Sstevel@tonic-gate 		case SC_INSTANCE_SINGLE:
32660Sstevel@tonic-gate 			(void) lxml_get_single_instance(s, cursor);
32670Sstevel@tonic-gate 			break;
32680Sstevel@tonic-gate 		default:
32690Sstevel@tonic-gate 			uu_die(gettext(
32700Sstevel@tonic-gate 			    "illegal element \"%s\" on service \"%s\"\n"),
32710Sstevel@tonic-gate 			    cursor->name, s->sc_name);
32720Sstevel@tonic-gate 			break;
32730Sstevel@tonic-gate 		}
32740Sstevel@tonic-gate 	}
32750Sstevel@tonic-gate 
3276*12667SSean.Wilcox@Sun.COM 	/*
3277*12667SSean.Wilcox@Sun.COM 	 * Now that the service has been processed set the missing type
3278*12667SSean.Wilcox@Sun.COM 	 * for the service.  So that only the services with missing
3279*12667SSean.Wilcox@Sun.COM 	 * types are processed.
3280*12667SSean.Wilcox@Sun.COM 	 */
3281*12667SSean.Wilcox@Sun.COM 	s->sc_miss_type = est->sc_miss_type;
3282*12667SSean.Wilcox@Sun.COM 	if (est->sc_miss_type)
3283*12667SSean.Wilcox@Sun.COM 		est->sc_miss_type = B_FALSE;
3284*12667SSean.Wilcox@Sun.COM 
32850Sstevel@tonic-gate 	return (internal_attach_service(bundle, s));
32860Sstevel@tonic-gate }
32870Sstevel@tonic-gate 
32880Sstevel@tonic-gate #ifdef DEBUG
32890Sstevel@tonic-gate void
32900Sstevel@tonic-gate lxml_dump(int g, xmlNodePtr p)
32910Sstevel@tonic-gate {
32920Sstevel@tonic-gate 	if (p && p->name) {
3293*12667SSean.Wilcox@Sun.COM 		(void) printf("%d %s\n", g, p->name);
32940Sstevel@tonic-gate 
32950Sstevel@tonic-gate 		for (p = p->xmlChildrenNode; p != NULL; p = p->next)
32960Sstevel@tonic-gate 			lxml_dump(g + 1, p);
32970Sstevel@tonic-gate 	}
32980Sstevel@tonic-gate }
32990Sstevel@tonic-gate #endif /* DEBUG */
33000Sstevel@tonic-gate 
33010Sstevel@tonic-gate static int
33020Sstevel@tonic-gate lxml_is_known_dtd(const xmlChar *dtdname)
33030Sstevel@tonic-gate {
33040Sstevel@tonic-gate 	if (dtdname == NULL ||
33050Sstevel@tonic-gate 	    strcmp(MANIFEST_DTD_PATH, (const char *)dtdname) != 0)
33060Sstevel@tonic-gate 		return (0);
33070Sstevel@tonic-gate 
33080Sstevel@tonic-gate 	return (1);
33090Sstevel@tonic-gate }
33100Sstevel@tonic-gate 
33110Sstevel@tonic-gate static int
33120Sstevel@tonic-gate lxml_get_bundle(bundle_t *bundle, bundle_type_t bundle_type,
33135040Swesolows     xmlNodePtr subbundle, svccfg_op_t op)
33140Sstevel@tonic-gate {
33150Sstevel@tonic-gate 	xmlNodePtr cursor;
33160Sstevel@tonic-gate 	xmlChar *type;
33170Sstevel@tonic-gate 	int e;
33180Sstevel@tonic-gate 
33190Sstevel@tonic-gate 	/*
33200Sstevel@tonic-gate 	 * 1.  Get bundle attributes.
33210Sstevel@tonic-gate 	 */
33227887SLiane.Praza@Sun.COM 	type = xmlGetProp(subbundle, (xmlChar *)type_attr);
33230Sstevel@tonic-gate 	bundle->sc_bundle_type = lxml_xlate_bundle_type(type);
33240Sstevel@tonic-gate 	if (bundle->sc_bundle_type != bundle_type &&
33250Sstevel@tonic-gate 	    bundle_type != SVCCFG_UNKNOWN_BUNDLE) {
33260Sstevel@tonic-gate 		semerr(gettext("included bundle of different type.\n"));
33270Sstevel@tonic-gate 		return (-1);
33280Sstevel@tonic-gate 	}
33290Sstevel@tonic-gate 
33300Sstevel@tonic-gate 	xmlFree(type);
33310Sstevel@tonic-gate 
33325040Swesolows 	switch (op) {
33335040Swesolows 	case SVCCFG_OP_IMPORT:
33340Sstevel@tonic-gate 		if (bundle->sc_bundle_type != SVCCFG_MANIFEST) {
33350Sstevel@tonic-gate 			semerr(gettext("document is not a manifest.\n"));
33360Sstevel@tonic-gate 			return (-1);
33370Sstevel@tonic-gate 		}
33385040Swesolows 		break;
33395040Swesolows 	case SVCCFG_OP_APPLY:
33400Sstevel@tonic-gate 		if (bundle->sc_bundle_type != SVCCFG_PROFILE) {
33410Sstevel@tonic-gate 			semerr(gettext("document is not a profile.\n"));
33420Sstevel@tonic-gate 			return (-1);
33430Sstevel@tonic-gate 		}
33445040Swesolows 		break;
33455040Swesolows 	case SVCCFG_OP_RESTORE:
33465040Swesolows 		if (bundle->sc_bundle_type != SVCCFG_ARCHIVE) {
33475040Swesolows 			semerr(gettext("document is not an archive.\n"));
33485040Swesolows 			return (-1);
33495040Swesolows 		}
33505040Swesolows 		break;
33510Sstevel@tonic-gate 	}
33520Sstevel@tonic-gate 
33537887SLiane.Praza@Sun.COM 	if (((bundle->sc_bundle_name = xmlGetProp(subbundle,
33547887SLiane.Praza@Sun.COM 	    (xmlChar *)name_attr)) == NULL) || (*bundle->sc_bundle_name == 0)) {
33550Sstevel@tonic-gate 		semerr(gettext("service bundle lacks name attribute\n"));
33560Sstevel@tonic-gate 		return (-1);
33570Sstevel@tonic-gate 	}
33580Sstevel@tonic-gate 
33590Sstevel@tonic-gate 	/*
33600Sstevel@tonic-gate 	 * 2.  Get services, descend into each one and build state.
33610Sstevel@tonic-gate 	 */
33620Sstevel@tonic-gate 	for (cursor = subbundle->xmlChildrenNode; cursor != NULL;
33630Sstevel@tonic-gate 	    cursor = cursor->next) {
33640Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
33650Sstevel@tonic-gate 			continue;
33660Sstevel@tonic-gate 
33670Sstevel@tonic-gate 		e = lxml_xlate_element(cursor->name);
33680Sstevel@tonic-gate 
33690Sstevel@tonic-gate 		switch (e) {
33700Sstevel@tonic-gate 		case SC_XI_INCLUDE:
33710Sstevel@tonic-gate 			continue;
33720Sstevel@tonic-gate 
33730Sstevel@tonic-gate 		case SC_SERVICE_BUNDLE:
33745040Swesolows 			if (lxml_get_bundle(bundle, bundle_type, cursor, op))
33750Sstevel@tonic-gate 				return (-1);
33760Sstevel@tonic-gate 			break;
33770Sstevel@tonic-gate 		case SC_SERVICE:
33787887SLiane.Praza@Sun.COM 			if (lxml_get_service(bundle, cursor, op) != 0)
33797887SLiane.Praza@Sun.COM 				return (-1);
33800Sstevel@tonic-gate 			break;
33810Sstevel@tonic-gate 		}
33820Sstevel@tonic-gate 	}
33830Sstevel@tonic-gate 
33840Sstevel@tonic-gate 	return (0);
33850Sstevel@tonic-gate }
33860Sstevel@tonic-gate 
33870Sstevel@tonic-gate /*
33880Sstevel@tonic-gate  * Load an XML tree from filename and translate it into an internal service
33895040Swesolows  * tree bundle.  Require that the bundle be of appropriate type for the
33905040Swesolows  * operation: archive for RESTORE, manifest for IMPORT, profile for APPLY.
33910Sstevel@tonic-gate  */
33920Sstevel@tonic-gate int
33935040Swesolows lxml_get_bundle_file(bundle_t *bundle, const char *filename, svccfg_op_t op)
33940Sstevel@tonic-gate {
33950Sstevel@tonic-gate 	xmlDocPtr document;
33960Sstevel@tonic-gate 	xmlNodePtr cursor;
33970Sstevel@tonic-gate 	xmlDtdPtr dtd = NULL;
33980Sstevel@tonic-gate 	xmlValidCtxtPtr vcp;
33990Sstevel@tonic-gate 	boolean_t do_validate;
34000Sstevel@tonic-gate 	char *dtdpath = NULL;
34010Sstevel@tonic-gate 	int r;
34020Sstevel@tonic-gate 
34030Sstevel@tonic-gate 	/*
34044740Sjeanm 	 * Verify we can read the file before we try to parse it.
34054740Sjeanm 	 */
34064740Sjeanm 	if (access(filename, R_OK | F_OK) == -1) {
34074740Sjeanm 		semerr(gettext("unable to open file: %s\n"), strerror(errno));
34084740Sjeanm 		return (-1);
34094740Sjeanm 	}
34104740Sjeanm 
34114740Sjeanm 	/*
34120Sstevel@tonic-gate 	 * Until libxml2 addresses DTD-based validation with XInclude, we don't
34130Sstevel@tonic-gate 	 * validate service profiles (i.e. the apply path).
34140Sstevel@tonic-gate 	 */
34155040Swesolows 	do_validate = (op != SVCCFG_OP_APPLY) &&
34165040Swesolows 	    (getenv("SVCCFG_NOVALIDATE") == NULL);
34170Sstevel@tonic-gate 	if (do_validate)
34180Sstevel@tonic-gate 		dtdpath = getenv("SVCCFG_DTD");
34190Sstevel@tonic-gate 
34200Sstevel@tonic-gate 	if (dtdpath != NULL)
34210Sstevel@tonic-gate 		xmlLoadExtDtdDefaultValue = 0;
34220Sstevel@tonic-gate 
34234740Sjeanm 	if ((document = xmlReadFile(filename, NULL, 0)) == NULL) {
34240Sstevel@tonic-gate 		semerr(gettext("couldn't parse document\n"));
34250Sstevel@tonic-gate 		return (-1);
34260Sstevel@tonic-gate 	}
34270Sstevel@tonic-gate 
342810461SSean.Wilcox@Sun.COM 	document->name = strdup(filename);
342910461SSean.Wilcox@Sun.COM 
34300Sstevel@tonic-gate 	/*
34310Sstevel@tonic-gate 	 * Verify that this is a document type we understand.
34320Sstevel@tonic-gate 	 */
34330Sstevel@tonic-gate 	if ((dtd = xmlGetIntSubset(document)) == NULL) {
34340Sstevel@tonic-gate 		semerr(gettext("document has no DTD\n"));
34350Sstevel@tonic-gate 		return (-1);
3436*12667SSean.Wilcox@Sun.COM 	} else if (dtdpath == NULL && !do_validate) {
3437*12667SSean.Wilcox@Sun.COM 		/*
3438*12667SSean.Wilcox@Sun.COM 		 * If apply then setup so that some validation
3439*12667SSean.Wilcox@Sun.COM 		 * for specific elements can be done.
3440*12667SSean.Wilcox@Sun.COM 		 */
3441*12667SSean.Wilcox@Sun.COM 		dtdpath = (char *)document->intSubset->SystemID;
34420Sstevel@tonic-gate 	}
34430Sstevel@tonic-gate 
34440Sstevel@tonic-gate 	if (!lxml_is_known_dtd(dtd->SystemID)) {
34450Sstevel@tonic-gate 		semerr(gettext("document DTD unknown; not service bundle?\n"));
34460Sstevel@tonic-gate 		return (-1);
34470Sstevel@tonic-gate 	}
34480Sstevel@tonic-gate 
34490Sstevel@tonic-gate 	if ((cursor = xmlDocGetRootElement(document)) == NULL) {
34500Sstevel@tonic-gate 		semerr(gettext("document is empty\n"));
34510Sstevel@tonic-gate 		xmlFreeDoc(document);
34520Sstevel@tonic-gate 		return (-1);
34530Sstevel@tonic-gate 	}
34540Sstevel@tonic-gate 
34550Sstevel@tonic-gate 	if (xmlStrcmp(cursor->name, (const xmlChar *)"service_bundle") != 0) {
34560Sstevel@tonic-gate 		semerr(gettext("document is not a service bundle\n"));
34570Sstevel@tonic-gate 		xmlFreeDoc(document);
34580Sstevel@tonic-gate 		return (-1);
34590Sstevel@tonic-gate 	}
34600Sstevel@tonic-gate 
34610Sstevel@tonic-gate 
34620Sstevel@tonic-gate 	if (dtdpath != NULL) {
34630Sstevel@tonic-gate 		dtd = xmlParseDTD(NULL, (xmlChar *)dtdpath);
34640Sstevel@tonic-gate 		if (dtd == NULL) {
34650Sstevel@tonic-gate 			semerr(gettext("Could not parse DTD \"%s\".\n"),
34660Sstevel@tonic-gate 			    dtdpath);
34670Sstevel@tonic-gate 			return (-1);
34680Sstevel@tonic-gate 		}
34690Sstevel@tonic-gate 
34700Sstevel@tonic-gate 		if (document->extSubset != NULL)
34710Sstevel@tonic-gate 			xmlFreeDtd(document->extSubset);
34720Sstevel@tonic-gate 
34730Sstevel@tonic-gate 		document->extSubset = dtd;
34740Sstevel@tonic-gate 	}
34750Sstevel@tonic-gate 
34764740Sjeanm 	if (xmlXIncludeProcessFlags(document, XML_PARSE_XINCLUDE) == -1) {
34770Sstevel@tonic-gate 		semerr(gettext("couldn't handle XInclude statements "
34784740Sjeanm 		    "in document\n"));
34790Sstevel@tonic-gate 		return (-1);
34800Sstevel@tonic-gate 	}
34810Sstevel@tonic-gate 
34820Sstevel@tonic-gate 	if (do_validate) {
34830Sstevel@tonic-gate 		vcp = xmlNewValidCtxt();
34840Sstevel@tonic-gate 		if (vcp == NULL)
34850Sstevel@tonic-gate 			uu_die(gettext("could not allocate memory"));
34860Sstevel@tonic-gate 		vcp->warning = xmlParserValidityWarning;
34870Sstevel@tonic-gate 		vcp->error = xmlParserValidityError;
34880Sstevel@tonic-gate 
34890Sstevel@tonic-gate 		r = xmlValidateDocument(vcp, document);
34900Sstevel@tonic-gate 
34910Sstevel@tonic-gate 		xmlFreeValidCtxt(vcp);
34920Sstevel@tonic-gate 
34930Sstevel@tonic-gate 		if (r == 0) {
34940Sstevel@tonic-gate 			semerr(gettext("Document is not valid.\n"));
34950Sstevel@tonic-gate 			xmlFreeDoc(document);
34960Sstevel@tonic-gate 			return (-1);
34970Sstevel@tonic-gate 		}
34980Sstevel@tonic-gate 	}
34990Sstevel@tonic-gate 
35000Sstevel@tonic-gate #ifdef DEBUG
35010Sstevel@tonic-gate 	lxml_dump(0, cursor);
35020Sstevel@tonic-gate #endif /* DEBUG */
35030Sstevel@tonic-gate 
35045040Swesolows 	r = lxml_get_bundle(bundle, SVCCFG_UNKNOWN_BUNDLE, cursor, op);
35050Sstevel@tonic-gate 
35060Sstevel@tonic-gate 	xmlFreeDoc(document);
35070Sstevel@tonic-gate 
35080Sstevel@tonic-gate 	return (r);
35090Sstevel@tonic-gate }
35100Sstevel@tonic-gate 
35110Sstevel@tonic-gate int
35120Sstevel@tonic-gate lxml_inventory(const char *filename)
35130Sstevel@tonic-gate {
35140Sstevel@tonic-gate 	bundle_t *b;
35150Sstevel@tonic-gate 	uu_list_walk_t *svcs, *insts;
35160Sstevel@tonic-gate 	entity_t *svc, *inst;
35170Sstevel@tonic-gate 
35180Sstevel@tonic-gate 	b = internal_bundle_new();
35190Sstevel@tonic-gate 
35205040Swesolows 	if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) != 0) {
35210Sstevel@tonic-gate 		internal_bundle_free(b);
35220Sstevel@tonic-gate 		return (-1);
35230Sstevel@tonic-gate 	}
35240Sstevel@tonic-gate 
35250Sstevel@tonic-gate 	svcs = uu_list_walk_start(b->sc_bundle_services, 0);
35260Sstevel@tonic-gate 	if (svcs == NULL)
35270Sstevel@tonic-gate 		uu_die(gettext("Couldn't walk services"));
35280Sstevel@tonic-gate 
35290Sstevel@tonic-gate 	while ((svc = uu_list_walk_next(svcs)) != NULL) {
35300Sstevel@tonic-gate 		uu_list_t *inst_list;
35310Sstevel@tonic-gate 
35320Sstevel@tonic-gate 		inst_list = svc->sc_u.sc_service.sc_service_instances;
35330Sstevel@tonic-gate 		insts = uu_list_walk_start(inst_list, 0);
35340Sstevel@tonic-gate 		if (insts == NULL)
35350Sstevel@tonic-gate 			uu_die(gettext("Couldn't walk instances"));
35360Sstevel@tonic-gate 
35370Sstevel@tonic-gate 		while ((inst = uu_list_walk_next(insts)) != NULL)
35380Sstevel@tonic-gate 			(void) printf("svc:/%s:%s\n", svc->sc_name,
35390Sstevel@tonic-gate 			    inst->sc_name);
35400Sstevel@tonic-gate 
35410Sstevel@tonic-gate 		uu_list_walk_end(insts);
35420Sstevel@tonic-gate 	}
35430Sstevel@tonic-gate 
35440Sstevel@tonic-gate 	uu_list_walk_end(svcs);
35450Sstevel@tonic-gate 
35460Sstevel@tonic-gate 	svcs = uu_list_walk_start(b->sc_bundle_services, 0);
35470Sstevel@tonic-gate 	while ((svc = uu_list_walk_next(svcs)) != NULL) {
35480Sstevel@tonic-gate 		(void) fputs("svc:/", stdout);
35490Sstevel@tonic-gate 		(void) puts(svc->sc_name);
35500Sstevel@tonic-gate 	}
35510Sstevel@tonic-gate 	uu_list_walk_end(svcs);
35520Sstevel@tonic-gate 
35530Sstevel@tonic-gate 	internal_bundle_free(b);
35540Sstevel@tonic-gate 
35550Sstevel@tonic-gate 	return (0);
35560Sstevel@tonic-gate }
3557