xref: /onnv-gate/usr/src/cmd/svc/svccfg/svccfg_xml.c (revision 7887:b6618727fabf)
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 /*
22*7887SLiane.Praza@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
26*7887SLiane.Praza@Sun.COM /*
27*7887SLiane.Praza@Sun.COM  * XML document manipulation routines
28*7887SLiane.Praza@Sun.COM  *
29*7887SLiane.Praza@Sun.COM  * These routines provide translation to and from the internal representation to
30*7887SLiane.Praza@Sun.COM  * XML.  Directionally-oriented verbs are with respect to the external source,
31*7887SLiane.Praza@Sun.COM  * so lxml_get_service() fetches a service from the XML file into the
32*7887SLiane.Praza@Sun.COM  * internal representation.
33*7887SLiane.Praza@Sun.COM  */
340Sstevel@tonic-gate 
350Sstevel@tonic-gate #include <libxml/parser.h>
360Sstevel@tonic-gate #include <libxml/xinclude.h>
370Sstevel@tonic-gate 
380Sstevel@tonic-gate #include <assert.h>
390Sstevel@tonic-gate #include <ctype.h>
400Sstevel@tonic-gate #include <errno.h>
410Sstevel@tonic-gate #include <libintl.h>
42*7887SLiane.Praza@Sun.COM #include <libscf.h>
43*7887SLiane.Praza@Sun.COM #include <libscf_priv.h>
440Sstevel@tonic-gate #include <libuutil.h>
45*7887SLiane.Praza@Sun.COM #include <sasl/saslutil.h>
460Sstevel@tonic-gate #include <stdlib.h>
470Sstevel@tonic-gate #include <string.h>
480Sstevel@tonic-gate 
494740Sjeanm #include <sys/types.h>
504740Sjeanm #include <sys/stat.h>
514740Sjeanm #include <unistd.h>
524740Sjeanm 
530Sstevel@tonic-gate #include "svccfg.h"
540Sstevel@tonic-gate 
550Sstevel@tonic-gate /*
56*7887SLiane.Praza@Sun.COM  * snprintf(3C) format strings for constructing property names that include
57*7887SLiane.Praza@Sun.COM  * the locale designation.  Use %s to indicate where the locale should go.
580Sstevel@tonic-gate  *
59*7887SLiane.Praza@Sun.COM  * The VALUE_* symbols are an exception.  The firs %s will be replaced with
60*7887SLiane.Praza@Sun.COM  * "value_".  The second %s will be replaced by the name of the value and
61*7887SLiane.Praza@Sun.COM  * %%s will be replaced by the locale designation.  These formats are
62*7887SLiane.Praza@Sun.COM  * processed twice by snprintf(3C).  The first time captures the value name
63*7887SLiane.Praza@Sun.COM  * and the second time captures the locale.
640Sstevel@tonic-gate  */
65*7887SLiane.Praza@Sun.COM #define	LOCALE_ONLY_FMT		("%s")
66*7887SLiane.Praza@Sun.COM #define	COMMON_NAME_FMT		("common_name_%s")
67*7887SLiane.Praza@Sun.COM #define	DESCRIPTION_FMT		("description_%s")
68*7887SLiane.Praza@Sun.COM #define	UNITS_FMT		("units_%s")
69*7887SLiane.Praza@Sun.COM #define	VALUE_COMMON_NAME_FMT	("%s%s_common_name_%%s")
70*7887SLiane.Praza@Sun.COM #define	VALUE_DESCRIPTION_FMT	("%s%s_description_%%s")
71*7887SLiane.Praza@Sun.COM 
72*7887SLiane.Praza@Sun.COM /* Attribute names */
730Sstevel@tonic-gate const char * const delete_attr = "delete";
740Sstevel@tonic-gate const char * const enabled_attr = "enabled";
75*7887SLiane.Praza@Sun.COM const char * const lang_attr = "lang";
76*7887SLiane.Praza@Sun.COM const char * const manpath_attr = "manpath";
77*7887SLiane.Praza@Sun.COM const char * const max_attr = "max";
78*7887SLiane.Praza@Sun.COM const char * const min_attr = "min";
790Sstevel@tonic-gate const char * const name_attr = "name";
800Sstevel@tonic-gate const char * const override_attr = "override";
81*7887SLiane.Praza@Sun.COM const char * const required_attr = "required";
82*7887SLiane.Praza@Sun.COM const char * const section_attr = "section";
83*7887SLiane.Praza@Sun.COM const char * const set_attr = "set";
84*7887SLiane.Praza@Sun.COM const char * const target_attr = "target";
85*7887SLiane.Praza@Sun.COM const char * const timeout_seconds_attr = "timeout_seconds";
86*7887SLiane.Praza@Sun.COM const char * const title_attr = "title";
870Sstevel@tonic-gate const char * const type_attr = "type";
88*7887SLiane.Praza@Sun.COM const char * const uri_attr = "uri";
890Sstevel@tonic-gate const char * const value_attr = "value";
90*7887SLiane.Praza@Sun.COM const char * const version_attr = "version";
91*7887SLiane.Praza@Sun.COM const char * const xml_lang_attr = "xml:lang";
92*7887SLiane.Praza@Sun.COM 
93*7887SLiane.Praza@Sun.COM /* Attribute values */
94*7887SLiane.Praza@Sun.COM const char * const all_value = "all";
95*7887SLiane.Praza@Sun.COM 
960Sstevel@tonic-gate const char * const true = "true";
970Sstevel@tonic-gate const char * const false = "false";
980Sstevel@tonic-gate 
990Sstevel@tonic-gate /*
1000Sstevel@tonic-gate  * The following list must be kept in the same order as that of
1010Sstevel@tonic-gate  * element_t array
1020Sstevel@tonic-gate  */
1030Sstevel@tonic-gate static const char *lxml_elements[] = {
1040Sstevel@tonic-gate 	"astring_list",			/* SC_ASTRING */
1050Sstevel@tonic-gate 	"boolean_list",			/* SC_BOOLEAN */
106*7887SLiane.Praza@Sun.COM 	"cardinality",			/* SC_CARDINALITY */
107*7887SLiane.Praza@Sun.COM 	"choices",			/* SC_CHOICES */
1080Sstevel@tonic-gate 	"common_name",			/* SC_COMMON_NAME */
109*7887SLiane.Praza@Sun.COM 	"constraints",			/* SC_CONSTRAINTS */
1100Sstevel@tonic-gate 	"count_list",			/* SC_COUNT */
1110Sstevel@tonic-gate 	"create_default_instance",	/* SC_INSTANCE_CREATE_DEFAULT */
1120Sstevel@tonic-gate 	"dependency",			/* SC_DEPENDENCY */
1130Sstevel@tonic-gate 	"dependent",			/* SC_DEPENDENT */
1140Sstevel@tonic-gate 	"description",			/* SC_DESCRIPTION */
1150Sstevel@tonic-gate 	"doc_link",			/* SC_DOC_LINK */
1160Sstevel@tonic-gate 	"documentation",		/* SC_DOCUMENTATION */
1170Sstevel@tonic-gate 	"enabled",			/* SC_ENABLED */
1180Sstevel@tonic-gate 	"exec_method",			/* SC_EXEC_METHOD */
1190Sstevel@tonic-gate 	"fmri_list",			/* SC_FMRI */
1200Sstevel@tonic-gate 	"host_list",			/* SC_HOST */
1210Sstevel@tonic-gate 	"hostname_list",		/* SC_HOSTNAME */
122*7887SLiane.Praza@Sun.COM 	"include_values",		/* SC_INCLUDE_VALUES */
1230Sstevel@tonic-gate 	"instance",			/* SC_INSTANCE */
1240Sstevel@tonic-gate 	"integer_list",			/* SC_INTEGER */
125*7887SLiane.Praza@Sun.COM 	"internal_separators",		/* SC_INTERNAL_SEPARATORS */
1260Sstevel@tonic-gate 	"loctext",			/* SC_LOCTEXT */
1270Sstevel@tonic-gate 	"manpage",			/* SC_MANPAGE */
1280Sstevel@tonic-gate 	"method_context",		/* SC_METHOD_CONTEXT */
1290Sstevel@tonic-gate 	"method_credential",		/* SC_METHOD_CREDENTIAL */
1300Sstevel@tonic-gate 	"method_profile",		/* SC_METHOD_PROFILE */
1310Sstevel@tonic-gate 	"method_environment",		/* SC_METHOD_ENVIRONMENT */
1320Sstevel@tonic-gate 	"envvar",			/* SC_METHOD_ENVVAR */
1330Sstevel@tonic-gate 	"net_address_v4_list",		/* SC_NET_ADDR_V4 */
1340Sstevel@tonic-gate 	"net_address_v6_list",		/* SC_NET_ADDR_V6 */
1350Sstevel@tonic-gate 	"opaque_list",			/* SC_OPAQUE */
136*7887SLiane.Praza@Sun.COM 	"pg_pattern",			/* SC_PG_PATTERN */
137*7887SLiane.Praza@Sun.COM 	"prop_pattern",			/* SC_PROP_PATTERN */
1380Sstevel@tonic-gate 	"property",			/* SC_PROPERTY */
1390Sstevel@tonic-gate 	"property_group",		/* SC_PROPERTY_GROUP */
1400Sstevel@tonic-gate 	"propval",			/* SC_PROPVAL */
141*7887SLiane.Praza@Sun.COM 	"range",			/* SC_RANGE */
1420Sstevel@tonic-gate 	"restarter",			/* SC_RESTARTER */
1430Sstevel@tonic-gate 	"service",			/* SC_SERVICE */
1440Sstevel@tonic-gate 	"service_bundle",		/* SC_SERVICE_BUNDLE */
1450Sstevel@tonic-gate 	"service_fmri",			/* SC_SERVICE_FMRI */
1460Sstevel@tonic-gate 	"single_instance",		/* SC_INSTANCE_SINGLE */
1470Sstevel@tonic-gate 	"stability",			/* SC_STABILITY */
1480Sstevel@tonic-gate 	"template",			/* SC_TEMPLATE */
1490Sstevel@tonic-gate 	"time_list",			/* SC_TIME */
150*7887SLiane.Praza@Sun.COM 	"units",			/* SC_UNITS */
1510Sstevel@tonic-gate 	"uri_list",			/* SC_URI */
1520Sstevel@tonic-gate 	"ustring_list",			/* SC_USTRING */
153*7887SLiane.Praza@Sun.COM 	"value",			/* SC_VALUE */
1540Sstevel@tonic-gate 	"value_node",			/* SC_VALUE_NODE */
155*7887SLiane.Praza@Sun.COM 	"values",			/* SC_VALUES */
156*7887SLiane.Praza@Sun.COM 	"visibility",			/* SC_VISIBILITY */
1570Sstevel@tonic-gate 	"xi:fallback",			/* SC_XI_FALLBACK */
1580Sstevel@tonic-gate 	"xi:include"			/* SC_XI_INCLUDE */
1590Sstevel@tonic-gate };
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate /*
1620Sstevel@tonic-gate  * The following list must be kept in the same order as that of
1630Sstevel@tonic-gate  * element_t array
1640Sstevel@tonic-gate  */
1650Sstevel@tonic-gate static const char *lxml_prop_types[] = {
1660Sstevel@tonic-gate 	"astring",			/* SC_ASTRING */
1670Sstevel@tonic-gate 	"boolean",			/* SC_BOOLEAN */
168*7887SLiane.Praza@Sun.COM 	"",				/* SC_CARDINALITY */
169*7887SLiane.Praza@Sun.COM 	"",				/* SC_CHOICES */
1700Sstevel@tonic-gate 	"",				/* SC_COMMON_NAME */
171*7887SLiane.Praza@Sun.COM 	"",				/* SC_CONSTRAINTS */
1720Sstevel@tonic-gate 	"count",			/* SC_COUNT */
1730Sstevel@tonic-gate 	"",				/* SC_INSTANCE_CREATE_DEFAULT */
1740Sstevel@tonic-gate 	"",				/* SC_DEPENDENCY */
1750Sstevel@tonic-gate 	"",				/* SC_DEPENDENT */
1760Sstevel@tonic-gate 	"",				/* SC_DESCRIPTION */
1770Sstevel@tonic-gate 	"",				/* SC_DOC_LINK */
1780Sstevel@tonic-gate 	"",				/* SC_DOCUMENTATION */
1790Sstevel@tonic-gate 	"",				/* SC_ENABLED */
1800Sstevel@tonic-gate 	"",				/* SC_EXEC_METHOD */
1810Sstevel@tonic-gate 	"fmri",				/* SC_FMRI */
1820Sstevel@tonic-gate 	"host",				/* SC_HOST */
1830Sstevel@tonic-gate 	"hostname",			/* SC_HOSTNAME */
184*7887SLiane.Praza@Sun.COM 	"",				/* SC_INCLUDE_VALUES */
1850Sstevel@tonic-gate 	"",				/* SC_INSTANCE */
1860Sstevel@tonic-gate 	"integer",			/* SC_INTEGER */
187*7887SLiane.Praza@Sun.COM 	"",				/* SC_INTERNAL_SEPARATORS */
1880Sstevel@tonic-gate 	"",				/* SC_LOCTEXT */
1890Sstevel@tonic-gate 	"",				/* SC_MANPAGE */
1900Sstevel@tonic-gate 	"",				/* SC_METHOD_CONTEXT */
1910Sstevel@tonic-gate 	"",				/* SC_METHOD_CREDENTIAL */
1920Sstevel@tonic-gate 	"",				/* SC_METHOD_PROFILE */
1930Sstevel@tonic-gate 	"",				/* SC_METHOD_ENVIRONMENT */
1940Sstevel@tonic-gate 	"",				/* SC_METHOD_ENVVAR */
1950Sstevel@tonic-gate 	"net_address_v4",		/* SC_NET_ADDR_V4 */
1960Sstevel@tonic-gate 	"net_address_v6",		/* SC_NET_ADDR_V6 */
1970Sstevel@tonic-gate 	"opaque",			/* SC_OPAQUE */
198*7887SLiane.Praza@Sun.COM 	"",				/* SC_PG_PATTERN */
199*7887SLiane.Praza@Sun.COM 	"",				/* SC_PROP_PATTERN */
2000Sstevel@tonic-gate 	"",				/* SC_PROPERTY */
2010Sstevel@tonic-gate 	"",				/* SC_PROPERTY_GROUP */
2020Sstevel@tonic-gate 	"",				/* SC_PROPVAL */
203*7887SLiane.Praza@Sun.COM 	"",				/* SC_RANGE */
2040Sstevel@tonic-gate 	"",				/* SC_RESTARTER */
2050Sstevel@tonic-gate 	"",				/* SC_SERVICE */
2060Sstevel@tonic-gate 	"",				/* SC_SERVICE_BUNDLE */
2070Sstevel@tonic-gate 	"",				/* SC_SERVICE_FMRI */
2080Sstevel@tonic-gate 	"",				/* SC_INSTANCE_SINGLE */
2090Sstevel@tonic-gate 	"",				/* SC_STABILITY */
2100Sstevel@tonic-gate 	"",				/* SC_TEMPLATE */
2110Sstevel@tonic-gate 	"time",				/* SC_TIME */
212*7887SLiane.Praza@Sun.COM 	"",				/* SC_UNITS */
2130Sstevel@tonic-gate 	"uri",				/* SC_URI */
2140Sstevel@tonic-gate 	"ustring",			/* SC_USTRING */
215*7887SLiane.Praza@Sun.COM 	"",				/* SC_VALUE */
216*7887SLiane.Praza@Sun.COM 	"",				/* SC_VALUE_NODE */
217*7887SLiane.Praza@Sun.COM 	"",				/* SC_VALUES */
218*7887SLiane.Praza@Sun.COM 	"",				/* SC_VISIBILITY */
219*7887SLiane.Praza@Sun.COM 	"",				/* SC_XI_FALLBACK */
2200Sstevel@tonic-gate 	""				/* SC_XI_INCLUDE */
2210Sstevel@tonic-gate };
2220Sstevel@tonic-gate 
2230Sstevel@tonic-gate int
2240Sstevel@tonic-gate lxml_init()
2250Sstevel@tonic-gate {
2260Sstevel@tonic-gate 	if (getenv("SVCCFG_NOVALIDATE") == NULL) {
2270Sstevel@tonic-gate 		/*
2280Sstevel@tonic-gate 		 * DTD validation, with line numbers.
2290Sstevel@tonic-gate 		 */
2300Sstevel@tonic-gate 		xmlLineNumbersDefault(1);
2310Sstevel@tonic-gate 		xmlLoadExtDtdDefaultValue |= XML_DETECT_IDS;
2320Sstevel@tonic-gate 		xmlLoadExtDtdDefaultValue |= XML_COMPLETE_ATTRS;
2330Sstevel@tonic-gate 	}
2340Sstevel@tonic-gate 
2350Sstevel@tonic-gate 	return (0);
2360Sstevel@tonic-gate }
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate static bundle_type_t
2390Sstevel@tonic-gate lxml_xlate_bundle_type(xmlChar *type)
2400Sstevel@tonic-gate {
2410Sstevel@tonic-gate 	if (xmlStrcmp(type, (const xmlChar *)"manifest") == 0)
2420Sstevel@tonic-gate 		return (SVCCFG_MANIFEST);
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate 	if (xmlStrcmp(type, (const xmlChar *)"profile") == 0)
2450Sstevel@tonic-gate 		return (SVCCFG_PROFILE);
2460Sstevel@tonic-gate 
2470Sstevel@tonic-gate 	if (xmlStrcmp(type, (const xmlChar *)"archive") == 0)
2480Sstevel@tonic-gate 		return (SVCCFG_ARCHIVE);
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate 	return (SVCCFG_UNKNOWN_BUNDLE);
2510Sstevel@tonic-gate }
2520Sstevel@tonic-gate 
2530Sstevel@tonic-gate static service_type_t
2540Sstevel@tonic-gate lxml_xlate_service_type(xmlChar *type)
2550Sstevel@tonic-gate {
2560Sstevel@tonic-gate 	if (xmlStrcmp(type, (const xmlChar *)"service") == 0)
2570Sstevel@tonic-gate 		return (SVCCFG_SERVICE);
2580Sstevel@tonic-gate 
2590Sstevel@tonic-gate 	if (xmlStrcmp(type, (const xmlChar *)"restarter") == 0)
2600Sstevel@tonic-gate 		return (SVCCFG_RESTARTER);
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate 	if (xmlStrcmp(type, (const xmlChar *)"milestone") == 0)
2630Sstevel@tonic-gate 		return (SVCCFG_MILESTONE);
2640Sstevel@tonic-gate 
2650Sstevel@tonic-gate 	return (SVCCFG_UNKNOWN_SERVICE);
2660Sstevel@tonic-gate }
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate static element_t
2690Sstevel@tonic-gate lxml_xlate_element(const xmlChar *tag)
2700Sstevel@tonic-gate {
2710Sstevel@tonic-gate 	int i;
2720Sstevel@tonic-gate 
2730Sstevel@tonic-gate 	for (i = 0; i < sizeof (lxml_elements) / sizeof (char *); i++)
2740Sstevel@tonic-gate 		if (xmlStrcmp(tag, (const xmlChar *)lxml_elements[i]) == 0)
2750Sstevel@tonic-gate 			return ((element_t)i);
2760Sstevel@tonic-gate 
2770Sstevel@tonic-gate 	return ((element_t)-1);
2780Sstevel@tonic-gate }
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate static uint_t
2810Sstevel@tonic-gate lxml_xlate_boolean(const xmlChar *value)
2820Sstevel@tonic-gate {
2830Sstevel@tonic-gate 	if (xmlStrcmp(value, (const xmlChar *)true) == 0)
2840Sstevel@tonic-gate 		return (1);
2850Sstevel@tonic-gate 
2860Sstevel@tonic-gate 	if (xmlStrcmp(value, (const xmlChar *)false) == 0)
2870Sstevel@tonic-gate 		return (0);
2880Sstevel@tonic-gate 
2890Sstevel@tonic-gate 	uu_die(gettext("illegal boolean value \"%s\"\n"), value);
2900Sstevel@tonic-gate 
2910Sstevel@tonic-gate 	/*NOTREACHED*/
2920Sstevel@tonic-gate }
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate static scf_type_t
2950Sstevel@tonic-gate lxml_element_to_type(element_t type)
2960Sstevel@tonic-gate {
2970Sstevel@tonic-gate 	switch (type) {
2980Sstevel@tonic-gate 	case SC_ASTRING:	return (SCF_TYPE_ASTRING);
2990Sstevel@tonic-gate 	case SC_BOOLEAN:	return (SCF_TYPE_BOOLEAN);
3000Sstevel@tonic-gate 	case SC_COUNT:		return (SCF_TYPE_COUNT);
3010Sstevel@tonic-gate 	case SC_FMRI:		return (SCF_TYPE_FMRI);
3020Sstevel@tonic-gate 	case SC_HOST:		return (SCF_TYPE_HOST);
3030Sstevel@tonic-gate 	case SC_HOSTNAME:	return (SCF_TYPE_HOSTNAME);
3040Sstevel@tonic-gate 	case SC_INTEGER:	return (SCF_TYPE_INTEGER);
3050Sstevel@tonic-gate 	case SC_NET_ADDR_V4:	return (SCF_TYPE_NET_ADDR_V4);
3060Sstevel@tonic-gate 	case SC_NET_ADDR_V6:	return (SCF_TYPE_NET_ADDR_V6);
3070Sstevel@tonic-gate 	case SC_OPAQUE:		return (SCF_TYPE_OPAQUE);
3080Sstevel@tonic-gate 	case SC_TIME:		return (SCF_TYPE_TIME);
3090Sstevel@tonic-gate 	case SC_URI:		return (SCF_TYPE_URI);
3100Sstevel@tonic-gate 	case SC_USTRING:	return (SCF_TYPE_USTRING);
3110Sstevel@tonic-gate 
3120Sstevel@tonic-gate 	default:
3130Sstevel@tonic-gate 		uu_die(gettext("unknown value type (%d)\n"), type);
3140Sstevel@tonic-gate 	}
3150Sstevel@tonic-gate 
3160Sstevel@tonic-gate 	/* NOTREACHED */
3170Sstevel@tonic-gate }
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate static scf_type_t
3200Sstevel@tonic-gate lxml_element_to_scf_type(element_t type)
3210Sstevel@tonic-gate {
3220Sstevel@tonic-gate 	switch (type) {
3230Sstevel@tonic-gate 	case SC_ASTRING:	return (SCF_TYPE_ASTRING);
3240Sstevel@tonic-gate 	case SC_BOOLEAN:	return (SCF_TYPE_BOOLEAN);
3250Sstevel@tonic-gate 	case SC_COUNT:		return (SCF_TYPE_COUNT);
3260Sstevel@tonic-gate 	case SC_FMRI:		return (SCF_TYPE_FMRI);
3270Sstevel@tonic-gate 	case SC_HOST:		return (SCF_TYPE_HOST);
3280Sstevel@tonic-gate 	case SC_HOSTNAME:	return (SCF_TYPE_HOSTNAME);
3290Sstevel@tonic-gate 	case SC_INTEGER:	return (SCF_TYPE_INTEGER);
3300Sstevel@tonic-gate 	case SC_NET_ADDR_V4:	return (SCF_TYPE_NET_ADDR_V4);
3310Sstevel@tonic-gate 	case SC_NET_ADDR_V6:	return (SCF_TYPE_NET_ADDR_V6);
3320Sstevel@tonic-gate 	case SC_OPAQUE:		return (SCF_TYPE_OPAQUE);
3330Sstevel@tonic-gate 	case SC_TIME:		return (SCF_TYPE_TIME);
3340Sstevel@tonic-gate 	case SC_URI:		return (SCF_TYPE_URI);
3350Sstevel@tonic-gate 	case SC_USTRING:	return (SCF_TYPE_USTRING);
3360Sstevel@tonic-gate 	default:
3370Sstevel@tonic-gate 		uu_die(gettext("unknown value type (%d)\n"), type);
3380Sstevel@tonic-gate 	}
3390Sstevel@tonic-gate 
3400Sstevel@tonic-gate 	/* NOTREACHED */
3410Sstevel@tonic-gate }
3420Sstevel@tonic-gate 
343*7887SLiane.Praza@Sun.COM /*
344*7887SLiane.Praza@Sun.COM  * Create a SCF_TYPE_BOOLEAN property name pname and attach it to the
345*7887SLiane.Praza@Sun.COM  * property group at pgrp.  The value of the property will be set from the
346*7887SLiane.Praza@Sun.COM  * attribute named attr.  attr must have a value of 0, 1, true or false.
347*7887SLiane.Praza@Sun.COM  *
348*7887SLiane.Praza@Sun.COM  * Zero is returned on success.  An error is indicated by -1.  It indicates
349*7887SLiane.Praza@Sun.COM  * that either the attribute had an invalid value or that we could not
350*7887SLiane.Praza@Sun.COM  * attach the property to pgrp.  The attribute should not have an invalid
351*7887SLiane.Praza@Sun.COM  * value if the DTD is correctly written.
352*7887SLiane.Praza@Sun.COM  */
353*7887SLiane.Praza@Sun.COM static int
354*7887SLiane.Praza@Sun.COM new_bool_prop_from_attr(pgroup_t *pgrp, const char *pname, xmlNodePtr n,
355*7887SLiane.Praza@Sun.COM     const char *attr)
356*7887SLiane.Praza@Sun.COM {
357*7887SLiane.Praza@Sun.COM 	uint64_t bool;
358*7887SLiane.Praza@Sun.COM 	xmlChar *val;
359*7887SLiane.Praza@Sun.COM 	property_t *p;
360*7887SLiane.Praza@Sun.COM 	int r;
361*7887SLiane.Praza@Sun.COM 
362*7887SLiane.Praza@Sun.COM 	val = xmlGetProp(n, (xmlChar *)attr);
363*7887SLiane.Praza@Sun.COM 	if (val == NULL)
364*7887SLiane.Praza@Sun.COM 		return (0);
365*7887SLiane.Praza@Sun.COM 
366*7887SLiane.Praza@Sun.COM 	if ((xmlStrcmp(val, (xmlChar *)"0") == 0) ||
367*7887SLiane.Praza@Sun.COM 	    (xmlStrcmp(val, (xmlChar *)"false") == 0)) {
368*7887SLiane.Praza@Sun.COM 		bool = 0;
369*7887SLiane.Praza@Sun.COM 	} else if ((xmlStrcmp(val, (xmlChar *)"1") == 0) ||
370*7887SLiane.Praza@Sun.COM 	    (xmlStrcmp(val, (xmlChar *)"true") == 0)) {
371*7887SLiane.Praza@Sun.COM 		bool = 1;
372*7887SLiane.Praza@Sun.COM 	} else {
373*7887SLiane.Praza@Sun.COM 		xmlFree(val);
374*7887SLiane.Praza@Sun.COM 		return (-1);
375*7887SLiane.Praza@Sun.COM 	}
376*7887SLiane.Praza@Sun.COM 	xmlFree(val);
377*7887SLiane.Praza@Sun.COM 	p = internal_property_create(pname, SCF_TYPE_BOOLEAN, 1, bool);
378*7887SLiane.Praza@Sun.COM 	r = internal_attach_property(pgrp, p);
379*7887SLiane.Praza@Sun.COM 
380*7887SLiane.Praza@Sun.COM 	if (r != 0)
381*7887SLiane.Praza@Sun.COM 		internal_property_free(p);
382*7887SLiane.Praza@Sun.COM 
383*7887SLiane.Praza@Sun.COM 	return (r);
384*7887SLiane.Praza@Sun.COM }
385*7887SLiane.Praza@Sun.COM 
3860Sstevel@tonic-gate static int
3870Sstevel@tonic-gate new_str_prop_from_attr(pgroup_t *pgrp, const char *pname, scf_type_t ty,
3880Sstevel@tonic-gate     xmlNodePtr n, const char *attr)
3890Sstevel@tonic-gate {
3900Sstevel@tonic-gate 	xmlChar *val;
3910Sstevel@tonic-gate 	property_t *p;
3920Sstevel@tonic-gate 	int r;
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate 	val = xmlGetProp(n, (xmlChar *)attr);
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate 	p = internal_property_create(pname, ty, 1, val);
3970Sstevel@tonic-gate 	r = internal_attach_property(pgrp, p);
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate 	if (r != 0)
4000Sstevel@tonic-gate 		internal_property_free(p);
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate 	return (r);
4030Sstevel@tonic-gate }
4040Sstevel@tonic-gate 
4050Sstevel@tonic-gate static int
406*7887SLiane.Praza@Sun.COM new_opt_str_prop_from_attr(pgroup_t *pgrp, const char *pname, scf_type_t ty,
407*7887SLiane.Praza@Sun.COM     xmlNodePtr n, const char *attr, const char *dflt)
408*7887SLiane.Praza@Sun.COM {
409*7887SLiane.Praza@Sun.COM 	xmlChar *val;
410*7887SLiane.Praza@Sun.COM 	property_t *p;
411*7887SLiane.Praza@Sun.COM 	int r;
412*7887SLiane.Praza@Sun.COM 
413*7887SLiane.Praza@Sun.COM 	val = xmlGetProp(n, (xmlChar *)attr);
414*7887SLiane.Praza@Sun.COM 	if (val == NULL) {
415*7887SLiane.Praza@Sun.COM 		if (dflt == NULL) {
416*7887SLiane.Praza@Sun.COM 			/*
417*7887SLiane.Praza@Sun.COM 			 * A missing attribute is considered to be a
418*7887SLiane.Praza@Sun.COM 			 * success in this function, because many of the
419*7887SLiane.Praza@Sun.COM 			 * attributes are optional.  Missing non-optional
420*7887SLiane.Praza@Sun.COM 			 * attributes will be detected later when template
421*7887SLiane.Praza@Sun.COM 			 * validation is done.
422*7887SLiane.Praza@Sun.COM 			 */
423*7887SLiane.Praza@Sun.COM 			return (0);
424*7887SLiane.Praza@Sun.COM 		} else {
425*7887SLiane.Praza@Sun.COM 			val = (xmlChar *)dflt;
426*7887SLiane.Praza@Sun.COM 		}
427*7887SLiane.Praza@Sun.COM 	}
428*7887SLiane.Praza@Sun.COM 
429*7887SLiane.Praza@Sun.COM 	p = internal_property_create(pname, ty, 1, val);
430*7887SLiane.Praza@Sun.COM 	r = internal_attach_property(pgrp, p);
431*7887SLiane.Praza@Sun.COM 
432*7887SLiane.Praza@Sun.COM 	if (r != 0)
433*7887SLiane.Praza@Sun.COM 		internal_property_free(p);
434*7887SLiane.Praza@Sun.COM 
435*7887SLiane.Praza@Sun.COM 	return (r);
436*7887SLiane.Praza@Sun.COM }
437*7887SLiane.Praza@Sun.COM 
438*7887SLiane.Praza@Sun.COM static int
4390Sstevel@tonic-gate lxml_ignorable_block(xmlNodePtr n)
4400Sstevel@tonic-gate {
4410Sstevel@tonic-gate 	return ((xmlStrcmp(n->name, (xmlChar *)"text") == 0 ||
4420Sstevel@tonic-gate 	    xmlStrcmp(n->name, (xmlChar *)"comment") == 0) ? 1 : 0);
4430Sstevel@tonic-gate }
4440Sstevel@tonic-gate 
4450Sstevel@tonic-gate static int
4460Sstevel@tonic-gate lxml_validate_string_value(scf_type_t type, const char *v)
4470Sstevel@tonic-gate {
4480Sstevel@tonic-gate 	static scf_value_t *scf_value = NULL;
4490Sstevel@tonic-gate 	static scf_handle_t *scf_hndl = NULL;
4500Sstevel@tonic-gate 
4510Sstevel@tonic-gate 	if (scf_hndl == NULL && (scf_hndl = scf_handle_create(SCF_VERSION)) ==
4520Sstevel@tonic-gate 	    NULL)
4530Sstevel@tonic-gate 		return (-1);
4540Sstevel@tonic-gate 
4550Sstevel@tonic-gate 	if (scf_value == NULL && (scf_value = scf_value_create(scf_hndl)) ==
4560Sstevel@tonic-gate 	    NULL)
4570Sstevel@tonic-gate 		return (-1);
4580Sstevel@tonic-gate 
4590Sstevel@tonic-gate 	return (scf_value_set_from_string(scf_value, type, v));
4600Sstevel@tonic-gate }
4610Sstevel@tonic-gate 
4620Sstevel@tonic-gate static void
4630Sstevel@tonic-gate lxml_free_str(value_t *val)
4640Sstevel@tonic-gate {
4650Sstevel@tonic-gate 	free(val->sc_u.sc_string);
4660Sstevel@tonic-gate }
4670Sstevel@tonic-gate 
4680Sstevel@tonic-gate static value_t *
4690Sstevel@tonic-gate lxml_make_value(element_t type, const xmlChar *value)
4700Sstevel@tonic-gate {
4710Sstevel@tonic-gate 	value_t *v;
4720Sstevel@tonic-gate 	char *endptr;
4730Sstevel@tonic-gate 	scf_type_t scf_type = SCF_TYPE_INVALID;
4740Sstevel@tonic-gate 
4750Sstevel@tonic-gate 	v = internal_value_new();
4760Sstevel@tonic-gate 
4770Sstevel@tonic-gate 	v->sc_type = lxml_element_to_type(type);
4780Sstevel@tonic-gate 
4790Sstevel@tonic-gate 	switch (type) {
4800Sstevel@tonic-gate 	case SC_COUNT:
4810Sstevel@tonic-gate 		/*
4820Sstevel@tonic-gate 		 * Although an SC_COUNT represents a uint64_t the use
4830Sstevel@tonic-gate 		 * of a negative value is acceptable due to the usage
4840Sstevel@tonic-gate 		 * established by inetd(1M).
4850Sstevel@tonic-gate 		 */
4860Sstevel@tonic-gate 		errno = 0;
4870Sstevel@tonic-gate 		v->sc_u.sc_count = strtoull((char *)value, &endptr, 10);
4880Sstevel@tonic-gate 		if (errno != 0 || endptr == (char *)value || *endptr)
4890Sstevel@tonic-gate 			uu_die(gettext("illegal value \"%s\" for "
4900Sstevel@tonic-gate 			    "%s (%s)\n"), (char *)value,
4910Sstevel@tonic-gate 			    lxml_prop_types[type],
4920Sstevel@tonic-gate 			    (errno) ? strerror(errno) :
4930Sstevel@tonic-gate 			    gettext("Illegal character"));
4940Sstevel@tonic-gate 		break;
4950Sstevel@tonic-gate 	case SC_INTEGER:
4960Sstevel@tonic-gate 		errno = 0;
4970Sstevel@tonic-gate 		v->sc_u.sc_integer = strtoll((char *)value, &endptr, 10);
4980Sstevel@tonic-gate 		if (errno != 0 || *endptr)
4990Sstevel@tonic-gate 			uu_die(gettext("illegal value \"%s\" for "
5000Sstevel@tonic-gate 			    "%s (%s)\n"), (char *)value,
5010Sstevel@tonic-gate 			    lxml_prop_types[type],
5020Sstevel@tonic-gate 			    (errno) ? strerror(errno) : "Illegal character");
5030Sstevel@tonic-gate 		break;
5040Sstevel@tonic-gate 	case SC_OPAQUE:
5050Sstevel@tonic-gate 	case SC_HOST:
5060Sstevel@tonic-gate 	case SC_HOSTNAME:
5070Sstevel@tonic-gate 	case SC_NET_ADDR_V4:
5080Sstevel@tonic-gate 	case SC_NET_ADDR_V6:
5090Sstevel@tonic-gate 	case SC_FMRI:
5100Sstevel@tonic-gate 	case SC_URI:
5110Sstevel@tonic-gate 	case SC_TIME:
5120Sstevel@tonic-gate 	case SC_ASTRING:
5130Sstevel@tonic-gate 	case SC_USTRING:
5140Sstevel@tonic-gate 		scf_type = lxml_element_to_scf_type(type);
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate 		if ((v->sc_u.sc_string = strdup((char *)value)) == NULL)
5170Sstevel@tonic-gate 			uu_die(gettext("string duplication failed (%s)\n"),
5180Sstevel@tonic-gate 			    strerror(errno));
5190Sstevel@tonic-gate 		if (lxml_validate_string_value(scf_type,
5200Sstevel@tonic-gate 		    v->sc_u.sc_string) != 0)
5210Sstevel@tonic-gate 			uu_die(gettext("illegal value \"%s\" for "
5220Sstevel@tonic-gate 			    "%s (%s)\n"), (char *)value,
5230Sstevel@tonic-gate 			    lxml_prop_types[type],
5240Sstevel@tonic-gate 			    (scf_error()) ? scf_strerror(scf_error()) :
5250Sstevel@tonic-gate 			    gettext("Illegal format"));
5260Sstevel@tonic-gate 		v->sc_free = lxml_free_str;
5270Sstevel@tonic-gate 		break;
5280Sstevel@tonic-gate 	case SC_BOOLEAN:
5290Sstevel@tonic-gate 		v->sc_u.sc_count = lxml_xlate_boolean(value);
5300Sstevel@tonic-gate 		break;
5310Sstevel@tonic-gate 	default:
5320Sstevel@tonic-gate 		uu_die(gettext("unknown value type (%d)\n"), type);
5330Sstevel@tonic-gate 		break;
5340Sstevel@tonic-gate 	}
5350Sstevel@tonic-gate 
5360Sstevel@tonic-gate 	return (v);
5370Sstevel@tonic-gate }
5380Sstevel@tonic-gate 
5390Sstevel@tonic-gate static int
5400Sstevel@tonic-gate lxml_get_value(property_t *prop, element_t vtype, xmlNodePtr value)
5410Sstevel@tonic-gate {
5420Sstevel@tonic-gate 	xmlNodePtr cursor;
5430Sstevel@tonic-gate 
5440Sstevel@tonic-gate 	for (cursor = value->xmlChildrenNode; cursor != NULL;
5450Sstevel@tonic-gate 	    cursor = cursor->next) {
5460Sstevel@tonic-gate 		xmlChar *assigned_value;
5470Sstevel@tonic-gate 		value_t *v;
5480Sstevel@tonic-gate 
5490Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
5500Sstevel@tonic-gate 			continue;
5510Sstevel@tonic-gate 
5520Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
5530Sstevel@tonic-gate 		case SC_VALUE_NODE:
5540Sstevel@tonic-gate 			if ((assigned_value = xmlGetProp(cursor,
5550Sstevel@tonic-gate 			    (xmlChar *)value_attr)) == NULL)
5560Sstevel@tonic-gate 				uu_die(gettext("no value on value node?\n"));
5570Sstevel@tonic-gate 			break;
5580Sstevel@tonic-gate 		default:
5590Sstevel@tonic-gate 			uu_die(gettext("value list contains illegal element "
5600Sstevel@tonic-gate 			    "\'%s\'\n"), cursor->name);
5610Sstevel@tonic-gate 			break;
5620Sstevel@tonic-gate 		}
5630Sstevel@tonic-gate 
5640Sstevel@tonic-gate 		v = lxml_make_value(vtype, assigned_value);
5650Sstevel@tonic-gate 
5660Sstevel@tonic-gate 		xmlFree(assigned_value);
5670Sstevel@tonic-gate 
5680Sstevel@tonic-gate 		internal_attach_value(prop, v);
5690Sstevel@tonic-gate 	}
5700Sstevel@tonic-gate 
5710Sstevel@tonic-gate 	return (0);
5720Sstevel@tonic-gate }
5730Sstevel@tonic-gate 
5740Sstevel@tonic-gate static int
5750Sstevel@tonic-gate lxml_get_propval(pgroup_t *pgrp, xmlNodePtr propval)
5760Sstevel@tonic-gate {
5770Sstevel@tonic-gate 	property_t *p;
5780Sstevel@tonic-gate 	element_t r;
5790Sstevel@tonic-gate 	value_t *v;
5800Sstevel@tonic-gate 	xmlChar *type, *val, *override;
5810Sstevel@tonic-gate 
5820Sstevel@tonic-gate 	p = internal_property_new();
5830Sstevel@tonic-gate 
5840Sstevel@tonic-gate 	p->sc_property_name = (char *)xmlGetProp(propval, (xmlChar *)name_attr);
585*7887SLiane.Praza@Sun.COM 	if ((p->sc_property_name == NULL) || (*p->sc_property_name == 0))
5860Sstevel@tonic-gate 		uu_die(gettext("property name missing in group '%s'\n"),
5870Sstevel@tonic-gate 		    pgrp->sc_pgroup_name);
5880Sstevel@tonic-gate 
5890Sstevel@tonic-gate 	type = xmlGetProp(propval, (xmlChar *)type_attr);
590*7887SLiane.Praza@Sun.COM 	if ((type == NULL) || (*type == 0))
5910Sstevel@tonic-gate 		uu_die(gettext("property type missing for property '%s/%s'\n"),
5920Sstevel@tonic-gate 		    pgrp->sc_pgroup_name, p->sc_property_name);
5930Sstevel@tonic-gate 
5940Sstevel@tonic-gate 	for (r = 0; r < sizeof (lxml_prop_types) / sizeof (char *); ++r) {
5950Sstevel@tonic-gate 		if (xmlStrcmp(type, (const xmlChar *)lxml_prop_types[r]) == 0)
5960Sstevel@tonic-gate 			break;
5970Sstevel@tonic-gate 	}
598*7887SLiane.Praza@Sun.COM 	xmlFree(type);
5990Sstevel@tonic-gate 	if (r >= sizeof (lxml_prop_types) / sizeof (char *))
6000Sstevel@tonic-gate 		uu_die(gettext("property type invalid for property '%s/%s'\n"),
6010Sstevel@tonic-gate 		    pgrp->sc_pgroup_name, p->sc_property_name);
6020Sstevel@tonic-gate 
6030Sstevel@tonic-gate 	p->sc_value_type = lxml_element_to_type(r);
6040Sstevel@tonic-gate 
6050Sstevel@tonic-gate 	val = xmlGetProp(propval, (xmlChar *)value_attr);
6060Sstevel@tonic-gate 	if (val == NULL)
6070Sstevel@tonic-gate 		uu_die(gettext("property value missing for property '%s/%s'\n"),
6080Sstevel@tonic-gate 		    pgrp->sc_pgroup_name, p->sc_property_name);
6090Sstevel@tonic-gate 
6100Sstevel@tonic-gate 	v = lxml_make_value(r, val);
611*7887SLiane.Praza@Sun.COM 	xmlFree(val);
6120Sstevel@tonic-gate 	internal_attach_value(p, v);
6130Sstevel@tonic-gate 
6140Sstevel@tonic-gate 	override = xmlGetProp(propval, (xmlChar *)override_attr);
6150Sstevel@tonic-gate 	p->sc_property_override = (xmlStrcmp(override, (xmlChar *)true) == 0);
6160Sstevel@tonic-gate 	xmlFree(override);
6170Sstevel@tonic-gate 
6180Sstevel@tonic-gate 	return (internal_attach_property(pgrp, p));
6190Sstevel@tonic-gate }
6200Sstevel@tonic-gate 
6210Sstevel@tonic-gate static int
6220Sstevel@tonic-gate lxml_get_property(pgroup_t *pgrp, xmlNodePtr property)
6230Sstevel@tonic-gate {
6240Sstevel@tonic-gate 	property_t *p;
6250Sstevel@tonic-gate 	xmlNodePtr cursor;
6260Sstevel@tonic-gate 	element_t r;
6270Sstevel@tonic-gate 	xmlChar *type, *override;
6280Sstevel@tonic-gate 
6290Sstevel@tonic-gate 	p = internal_property_new();
6300Sstevel@tonic-gate 
631*7887SLiane.Praza@Sun.COM 	if (((p->sc_property_name = (char *)xmlGetProp(property,
632*7887SLiane.Praza@Sun.COM 	    (xmlChar *)name_attr)) == NULL) || (*p->sc_property_name == 0))
6330Sstevel@tonic-gate 		uu_die(gettext("property name missing in group \'%s\'\n"),
6340Sstevel@tonic-gate 		    pgrp->sc_pgroup_name);
6350Sstevel@tonic-gate 
636*7887SLiane.Praza@Sun.COM 	if (((type = xmlGetProp(property, (xmlChar *)type_attr)) == NULL) ||
637*7887SLiane.Praza@Sun.COM 	    (*type == 0)) {
6380Sstevel@tonic-gate 		uu_die(gettext("property type missing for "
6390Sstevel@tonic-gate 		    "property \'%s/%s\'\n"), pgrp->sc_pgroup_name,
6400Sstevel@tonic-gate 		    p->sc_property_name);
641*7887SLiane.Praza@Sun.COM 	}
6420Sstevel@tonic-gate 
6435040Swesolows 	for (r = 0; r < sizeof (lxml_prop_types) / sizeof (char *); r++) {
6445040Swesolows 		if (xmlStrcmp(type, (const xmlChar *)lxml_prop_types[r]) == 0)
6455040Swesolows 			break;
6465040Swesolows 	}
6475040Swesolows 
6485040Swesolows 	if (r >= sizeof (lxml_prop_types) / sizeof (char *)) {
6495040Swesolows 		uu_die(gettext("property type invalid for property '%s/%s'\n"),
6505040Swesolows 		    pgrp->sc_pgroup_name, p->sc_property_name);
6515040Swesolows 	}
6525040Swesolows 
6535040Swesolows 	p->sc_value_type = lxml_element_to_type(r);
6545040Swesolows 
6550Sstevel@tonic-gate 	for (cursor = property->xmlChildrenNode; cursor != NULL;
6560Sstevel@tonic-gate 	    cursor = cursor->next) {
6570Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
6580Sstevel@tonic-gate 			continue;
6590Sstevel@tonic-gate 
6600Sstevel@tonic-gate 		switch (r = lxml_xlate_element(cursor->name)) {
6610Sstevel@tonic-gate 		case SC_ASTRING:
6620Sstevel@tonic-gate 		case SC_BOOLEAN:
6630Sstevel@tonic-gate 		case SC_COUNT:
6640Sstevel@tonic-gate 		case SC_FMRI:
6650Sstevel@tonic-gate 		case SC_HOST:
6660Sstevel@tonic-gate 		case SC_HOSTNAME:
6670Sstevel@tonic-gate 		case SC_INTEGER:
6680Sstevel@tonic-gate 		case SC_NET_ADDR_V4:
6690Sstevel@tonic-gate 		case SC_NET_ADDR_V6:
6700Sstevel@tonic-gate 		case SC_OPAQUE:
6710Sstevel@tonic-gate 		case SC_TIME:
6720Sstevel@tonic-gate 		case SC_URI:
6730Sstevel@tonic-gate 		case SC_USTRING:
6740Sstevel@tonic-gate 			if (strcmp(lxml_prop_types[r], (const char *)type) != 0)
6750Sstevel@tonic-gate 				uu_die(gettext("property \'%s\' "
6760Sstevel@tonic-gate 				    "type-to-list mismatch\n"),
6770Sstevel@tonic-gate 				    p->sc_property_name);
6780Sstevel@tonic-gate 
6790Sstevel@tonic-gate 			(void) lxml_get_value(p, r, cursor);
6800Sstevel@tonic-gate 			break;
6810Sstevel@tonic-gate 		default:
6820Sstevel@tonic-gate 			uu_die(gettext("unknown value list type: %s\n"),
6830Sstevel@tonic-gate 			    cursor->name);
6840Sstevel@tonic-gate 			break;
6850Sstevel@tonic-gate 		}
6860Sstevel@tonic-gate 	}
6870Sstevel@tonic-gate 
6880Sstevel@tonic-gate 	xmlFree(type);
6890Sstevel@tonic-gate 
6900Sstevel@tonic-gate 	override = xmlGetProp(property, (xmlChar *)override_attr);
6910Sstevel@tonic-gate 	p->sc_property_override = (xmlStrcmp(override, (xmlChar *)true) == 0);
6920Sstevel@tonic-gate 	xmlFree(override);
6930Sstevel@tonic-gate 
6940Sstevel@tonic-gate 	return (internal_attach_property(pgrp, p));
6950Sstevel@tonic-gate }
6960Sstevel@tonic-gate 
6970Sstevel@tonic-gate static int
6980Sstevel@tonic-gate lxml_get_pgroup_stability(pgroup_t *pgrp, xmlNodePtr stab)
6990Sstevel@tonic-gate {
7000Sstevel@tonic-gate 	return (new_str_prop_from_attr(pgrp, SCF_PROPERTY_STABILITY,
7010Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, stab, value_attr));
7020Sstevel@tonic-gate }
7030Sstevel@tonic-gate 
7040Sstevel@tonic-gate /*
7050Sstevel@tonic-gate  * Property groups can go on any of a service, an instance, or a template.
7060Sstevel@tonic-gate  */
7070Sstevel@tonic-gate static int
7080Sstevel@tonic-gate lxml_get_pgroup(entity_t *entity, xmlNodePtr pgroup)
7090Sstevel@tonic-gate {
7100Sstevel@tonic-gate 	pgroup_t *pg;
7110Sstevel@tonic-gate 	xmlNodePtr cursor;
7120Sstevel@tonic-gate 	xmlChar *name, *type, *delete;
7130Sstevel@tonic-gate 
7140Sstevel@tonic-gate 	/*
7150Sstevel@tonic-gate 	 * property group attributes:
7160Sstevel@tonic-gate 	 * name: string
7170Sstevel@tonic-gate 	 * type: string | framework | application
7180Sstevel@tonic-gate 	 */
7190Sstevel@tonic-gate 	name = xmlGetProp(pgroup, (xmlChar *)name_attr);
7200Sstevel@tonic-gate 	type = xmlGetProp(pgroup, (xmlChar *)type_attr);
7210Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(entity, (char *)name, (char *)type);
7220Sstevel@tonic-gate 	xmlFree(name);
7230Sstevel@tonic-gate 	xmlFree(type);
7240Sstevel@tonic-gate 
7250Sstevel@tonic-gate 	/*
7260Sstevel@tonic-gate 	 * Walk the children of this lxml_elements, which are a stability
7270Sstevel@tonic-gate 	 * element, property elements, or propval elements.
7280Sstevel@tonic-gate 	 */
7290Sstevel@tonic-gate 	for (cursor = pgroup->xmlChildrenNode; cursor != NULL;
7300Sstevel@tonic-gate 	    cursor = cursor->next) {
7310Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
7320Sstevel@tonic-gate 			continue;
7330Sstevel@tonic-gate 
7340Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
7350Sstevel@tonic-gate 		case SC_STABILITY:
7360Sstevel@tonic-gate 			(void) lxml_get_pgroup_stability(pg, cursor);
7370Sstevel@tonic-gate 			break;
7380Sstevel@tonic-gate 		case SC_PROPERTY:
7390Sstevel@tonic-gate 			(void) lxml_get_property(pg, cursor);
7400Sstevel@tonic-gate 			break;
7410Sstevel@tonic-gate 		case SC_PROPVAL:
7420Sstevel@tonic-gate 			(void) lxml_get_propval(pg, cursor);
7430Sstevel@tonic-gate 			break;
7440Sstevel@tonic-gate 		default:
7450Sstevel@tonic-gate 			abort();
7460Sstevel@tonic-gate 			break;
7470Sstevel@tonic-gate 		}
7480Sstevel@tonic-gate 	}
7490Sstevel@tonic-gate 
7500Sstevel@tonic-gate 	delete = xmlGetProp(pgroup, (xmlChar *)delete_attr);
7510Sstevel@tonic-gate 	pg->sc_pgroup_delete = (xmlStrcmp(delete, (xmlChar *)true) == 0);
7520Sstevel@tonic-gate 	xmlFree(delete);
7530Sstevel@tonic-gate 
7540Sstevel@tonic-gate 	return (0);
7550Sstevel@tonic-gate }
7560Sstevel@tonic-gate 
7570Sstevel@tonic-gate 
7580Sstevel@tonic-gate /*
7590Sstevel@tonic-gate  * Dependency groups, execution methods can go on either a service or an
7600Sstevel@tonic-gate  * instance.
7610Sstevel@tonic-gate  */
7620Sstevel@tonic-gate 
7630Sstevel@tonic-gate static int
7640Sstevel@tonic-gate lxml_get_method_profile(pgroup_t *pg, xmlNodePtr profile)
7650Sstevel@tonic-gate {
7660Sstevel@tonic-gate 	property_t *p;
7670Sstevel@tonic-gate 
7680Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_USE_PROFILE, SCF_TYPE_BOOLEAN,
7690Sstevel@tonic-gate 	    1, (uint64_t)1);
7700Sstevel@tonic-gate 	if (internal_attach_property(pg, p) != 0)
7710Sstevel@tonic-gate 		return (-1);
7720Sstevel@tonic-gate 
7730Sstevel@tonic-gate 	return (new_str_prop_from_attr(pg, SCF_PROPERTY_PROFILE,
7740Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, profile, name_attr));
7750Sstevel@tonic-gate }
7760Sstevel@tonic-gate 
7770Sstevel@tonic-gate static int
7780Sstevel@tonic-gate lxml_get_method_credential(pgroup_t *pg, xmlNodePtr cred)
7790Sstevel@tonic-gate {
7800Sstevel@tonic-gate 	property_t *p;
7810Sstevel@tonic-gate 
7820Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_USE_PROFILE, SCF_TYPE_BOOLEAN,
7830Sstevel@tonic-gate 	    1, (uint64_t)0);
7840Sstevel@tonic-gate 	if (internal_attach_property(pg, p) != 0)
7850Sstevel@tonic-gate 		return (-1);
7860Sstevel@tonic-gate 
7870Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_USER, SCF_TYPE_ASTRING,
7880Sstevel@tonic-gate 	    cred, "user") != 0)
7890Sstevel@tonic-gate 		return (-1);
7900Sstevel@tonic-gate 
7910Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_GROUP, SCF_TYPE_ASTRING,
7920Sstevel@tonic-gate 	    cred, "group") != 0)
7930Sstevel@tonic-gate 		return (-1);
7940Sstevel@tonic-gate 
7950Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_SUPP_GROUPS,
7960Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, cred, "supp_groups") != 0)
7970Sstevel@tonic-gate 		return (-1);
7980Sstevel@tonic-gate 
7990Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_PRIVILEGES,
8000Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, cred, "privileges") != 0)
8010Sstevel@tonic-gate 		return (-1);
8020Sstevel@tonic-gate 
8030Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_LIMIT_PRIVILEGES,
8040Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, cred, "limit_privileges") != 0)
8050Sstevel@tonic-gate 		return (-1);
8060Sstevel@tonic-gate 
8070Sstevel@tonic-gate 	return (0);
8080Sstevel@tonic-gate }
8090Sstevel@tonic-gate 
8100Sstevel@tonic-gate static char *
8110Sstevel@tonic-gate lxml_get_envvar(xmlNodePtr envvar)
8120Sstevel@tonic-gate {
8130Sstevel@tonic-gate 	char *name;
8140Sstevel@tonic-gate 	char *value;
8150Sstevel@tonic-gate 	char *ret;
8160Sstevel@tonic-gate 
817*7887SLiane.Praza@Sun.COM 	name = (char *)xmlGetProp(envvar, (xmlChar *)name_attr);
818*7887SLiane.Praza@Sun.COM 	value = (char *)xmlGetProp(envvar, (xmlChar *)value_attr);
8190Sstevel@tonic-gate 
8200Sstevel@tonic-gate 	if (strlen(name) == 0 || strchr(name, '=') != NULL)
8210Sstevel@tonic-gate 		uu_die(gettext("Invalid environment variable "
8220Sstevel@tonic-gate 		    "\"%s\".\n"), name);
8230Sstevel@tonic-gate 	if (strstr(name, "SMF_") == name)
8240Sstevel@tonic-gate 		uu_die(gettext("Invalid environment variable "
8250Sstevel@tonic-gate 		    "\"%s\"; \"SMF_\" prefix is reserved.\n"), name);
8260Sstevel@tonic-gate 
8270Sstevel@tonic-gate 	ret = uu_msprintf("%s=%s", name, value);
8280Sstevel@tonic-gate 	xmlFree(name);
8290Sstevel@tonic-gate 	xmlFree(value);
8300Sstevel@tonic-gate 	return (ret);
8310Sstevel@tonic-gate }
8320Sstevel@tonic-gate 
8330Sstevel@tonic-gate static int
8340Sstevel@tonic-gate lxml_get_method_environment(pgroup_t *pg, xmlNodePtr environment)
8350Sstevel@tonic-gate {
8360Sstevel@tonic-gate 	property_t *p;
8370Sstevel@tonic-gate 	xmlNodePtr cursor;
8380Sstevel@tonic-gate 	value_t *val;
8390Sstevel@tonic-gate 
8400Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_ENVIRONMENT,
8410Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, 0);
8420Sstevel@tonic-gate 
8430Sstevel@tonic-gate 	for (cursor = environment->xmlChildrenNode; cursor != NULL;
8440Sstevel@tonic-gate 	    cursor = cursor->next) {
8450Sstevel@tonic-gate 		char *tmp;
8460Sstevel@tonic-gate 
8470Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
8480Sstevel@tonic-gate 			continue;
8490Sstevel@tonic-gate 
8500Sstevel@tonic-gate 		if (lxml_xlate_element(cursor->name) != SC_METHOD_ENVVAR)
8510Sstevel@tonic-gate 			uu_die(gettext("illegal element \"%s\" on "
8520Sstevel@tonic-gate 			    "method environment for \"%s\"\n"),
8530Sstevel@tonic-gate 			    cursor->name, pg->sc_pgroup_name);
8540Sstevel@tonic-gate 
8550Sstevel@tonic-gate 		if ((tmp = lxml_get_envvar(cursor)) == NULL)
8560Sstevel@tonic-gate 			uu_die(gettext("Out of memory\n"));
8570Sstevel@tonic-gate 
8580Sstevel@tonic-gate 		val = internal_value_new();
8590Sstevel@tonic-gate 		val->sc_u.sc_string = tmp;
8600Sstevel@tonic-gate 		val->sc_type = SCF_TYPE_ASTRING;
8610Sstevel@tonic-gate 		val->sc_free = lxml_free_str;
8620Sstevel@tonic-gate 		internal_attach_value(p, val);
8630Sstevel@tonic-gate 	}
8640Sstevel@tonic-gate 
8650Sstevel@tonic-gate 	if (internal_attach_property(pg, p) != 0) {
8660Sstevel@tonic-gate 		internal_property_free(p);
8670Sstevel@tonic-gate 		return (-1);
8680Sstevel@tonic-gate 	}
8690Sstevel@tonic-gate 
8700Sstevel@tonic-gate 	return (0);
8710Sstevel@tonic-gate }
8720Sstevel@tonic-gate 
8730Sstevel@tonic-gate static int
8740Sstevel@tonic-gate lxml_get_method_context(pgroup_t *pg, xmlNodePtr ctx)
8750Sstevel@tonic-gate {
8760Sstevel@tonic-gate 	xmlNodePtr cursor;
8770Sstevel@tonic-gate 
8780Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_WORKING_DIRECTORY,
8790Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, ctx, "working_directory") != 0)
8800Sstevel@tonic-gate 		return (-1);
8810Sstevel@tonic-gate 
8820Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_PROJECT, SCF_TYPE_ASTRING,
8830Sstevel@tonic-gate 	    ctx, "project") != 0)
8840Sstevel@tonic-gate 		return (-1);
8850Sstevel@tonic-gate 
8860Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_RESOURCE_POOL,
8870Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, ctx, "resource_pool") != 0)
8880Sstevel@tonic-gate 		return (-1);
8890Sstevel@tonic-gate 
8900Sstevel@tonic-gate 	for (cursor = ctx->xmlChildrenNode; cursor != NULL;
8910Sstevel@tonic-gate 	    cursor = cursor->next) {
8920Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
8930Sstevel@tonic-gate 			continue;
8940Sstevel@tonic-gate 
8950Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
8960Sstevel@tonic-gate 		case SC_METHOD_CREDENTIAL:
8970Sstevel@tonic-gate 			(void) lxml_get_method_credential(pg, cursor);
8980Sstevel@tonic-gate 			break;
8990Sstevel@tonic-gate 		case SC_METHOD_PROFILE:
9000Sstevel@tonic-gate 			(void) lxml_get_method_profile(pg, cursor);
9010Sstevel@tonic-gate 			break;
9020Sstevel@tonic-gate 		case SC_METHOD_ENVIRONMENT:
9030Sstevel@tonic-gate 			(void) lxml_get_method_environment(pg, cursor);
9040Sstevel@tonic-gate 			break;
9050Sstevel@tonic-gate 		default:
9060Sstevel@tonic-gate 			semerr(gettext("illegal element \'%s\' in method "
9070Sstevel@tonic-gate 			    "context\n"), (char *)cursor);
9080Sstevel@tonic-gate 			break;
9090Sstevel@tonic-gate 		}
9100Sstevel@tonic-gate 	}
9110Sstevel@tonic-gate 
9120Sstevel@tonic-gate 	return (0);
9130Sstevel@tonic-gate }
9140Sstevel@tonic-gate 
9150Sstevel@tonic-gate static int
9160Sstevel@tonic-gate lxml_get_entity_method_context(entity_t *entity, xmlNodePtr ctx)
9170Sstevel@tonic-gate {
9180Sstevel@tonic-gate 	pgroup_t *pg;
9190Sstevel@tonic-gate 
9200Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(entity, SCF_PG_METHOD_CONTEXT,
9210Sstevel@tonic-gate 	    (char *)scf_group_framework);
9220Sstevel@tonic-gate 
9230Sstevel@tonic-gate 	return (lxml_get_method_context(pg, ctx));
9240Sstevel@tonic-gate }
9250Sstevel@tonic-gate 
9260Sstevel@tonic-gate static int
9270Sstevel@tonic-gate lxml_get_exec_method(entity_t *entity, xmlNodePtr emeth)
9280Sstevel@tonic-gate {
9290Sstevel@tonic-gate 	pgroup_t *pg;
9300Sstevel@tonic-gate 	property_t *p;
9310Sstevel@tonic-gate 	xmlChar *name, *timeout, *delete;
9320Sstevel@tonic-gate 	xmlNodePtr cursor;
9330Sstevel@tonic-gate 	int r = 0;
9340Sstevel@tonic-gate 
9350Sstevel@tonic-gate 	name = xmlGetProp(emeth, (xmlChar *)name_attr);
9360Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(entity, (char *)name,
9370Sstevel@tonic-gate 	    (char *)SCF_GROUP_METHOD);
9380Sstevel@tonic-gate 	xmlFree(name);
9390Sstevel@tonic-gate 
9400Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_TYPE, SCF_TYPE_ASTRING,
9410Sstevel@tonic-gate 	    emeth, type_attr) != 0 ||
9420Sstevel@tonic-gate 	    new_str_prop_from_attr(pg, SCF_PROPERTY_EXEC, SCF_TYPE_ASTRING,
9430Sstevel@tonic-gate 	    emeth, "exec") != 0)
9440Sstevel@tonic-gate 		return (-1);
9450Sstevel@tonic-gate 
946*7887SLiane.Praza@Sun.COM 	timeout = xmlGetProp(emeth, (xmlChar *)timeout_seconds_attr);
9470Sstevel@tonic-gate 	if (timeout != NULL) {
9480Sstevel@tonic-gate 		uint64_t u_timeout;
9490Sstevel@tonic-gate 		char *endptr;
9500Sstevel@tonic-gate 		/*
9510Sstevel@tonic-gate 		 * Although an SC_COUNT represents a uint64_t the use
9520Sstevel@tonic-gate 		 * of a negative value is acceptable due to the usage
9530Sstevel@tonic-gate 		 * established by inetd(1M).
9540Sstevel@tonic-gate 		 */
9550Sstevel@tonic-gate 		errno = 0;
9560Sstevel@tonic-gate 		u_timeout = strtoull((char *)timeout, &endptr, 10);
9570Sstevel@tonic-gate 		if (errno != 0 || endptr == (char *)timeout || *endptr)
9580Sstevel@tonic-gate 			uu_die(gettext("illegal value \"%s\" for "
9590Sstevel@tonic-gate 			    "timeout_seconds (%s)\n"),
9600Sstevel@tonic-gate 			    (char *)timeout, (errno) ? strerror(errno):
9610Sstevel@tonic-gate 			    gettext("Illegal character"));
9620Sstevel@tonic-gate 		p = internal_property_create(SCF_PROPERTY_TIMEOUT,
9630Sstevel@tonic-gate 		    SCF_TYPE_COUNT, 1, u_timeout);
9640Sstevel@tonic-gate 		r = internal_attach_property(pg, p);
9650Sstevel@tonic-gate 		xmlFree(timeout);
9660Sstevel@tonic-gate 	}
9670Sstevel@tonic-gate 	if (r != 0)
9680Sstevel@tonic-gate 		return (-1);
9690Sstevel@tonic-gate 
9700Sstevel@tonic-gate 	/*
9710Sstevel@tonic-gate 	 * There is a possibility that a method context also exists, in which
9720Sstevel@tonic-gate 	 * case the following attributes are defined: project, resource_pool,
9730Sstevel@tonic-gate 	 * working_directory, profile, user, group, privileges, limit_privileges
9740Sstevel@tonic-gate 	 */
9750Sstevel@tonic-gate 	for (cursor = emeth->xmlChildrenNode; cursor != NULL;
9760Sstevel@tonic-gate 	    cursor = cursor->next) {
9770Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
9780Sstevel@tonic-gate 			continue;
9790Sstevel@tonic-gate 
9800Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
9810Sstevel@tonic-gate 		case SC_STABILITY:
9820Sstevel@tonic-gate 			if (lxml_get_pgroup_stability(pg, cursor) != 0)
9830Sstevel@tonic-gate 				return (-1);
9840Sstevel@tonic-gate 			break;
9850Sstevel@tonic-gate 
9860Sstevel@tonic-gate 		case SC_METHOD_CONTEXT:
9870Sstevel@tonic-gate 			(void) lxml_get_method_context(pg, cursor);
9880Sstevel@tonic-gate 			break;
9890Sstevel@tonic-gate 
9900Sstevel@tonic-gate 		case SC_PROPVAL:
9910Sstevel@tonic-gate 			(void) lxml_get_propval(pg, cursor);
9920Sstevel@tonic-gate 			break;
9930Sstevel@tonic-gate 
9940Sstevel@tonic-gate 		case SC_PROPERTY:
9950Sstevel@tonic-gate 			(void) lxml_get_property(pg, cursor);
9960Sstevel@tonic-gate 			break;
9970Sstevel@tonic-gate 
9980Sstevel@tonic-gate 		default:
9990Sstevel@tonic-gate 			uu_die(gettext("illegal element \"%s\" on "
10000Sstevel@tonic-gate 			    "execution method \"%s\"\n"), cursor->name,
10010Sstevel@tonic-gate 			    pg->sc_pgroup_name);
10020Sstevel@tonic-gate 			break;
10030Sstevel@tonic-gate 		}
10040Sstevel@tonic-gate 	}
10050Sstevel@tonic-gate 
10060Sstevel@tonic-gate 	delete = xmlGetProp(emeth, (xmlChar *)delete_attr);
10070Sstevel@tonic-gate 	pg->sc_pgroup_delete = (xmlStrcmp(delete, (xmlChar *)true) == 0);
10080Sstevel@tonic-gate 	xmlFree(delete);
10090Sstevel@tonic-gate 
10100Sstevel@tonic-gate 	return (0);
10110Sstevel@tonic-gate }
10120Sstevel@tonic-gate 
10130Sstevel@tonic-gate static int
10140Sstevel@tonic-gate lxml_get_dependency(entity_t *entity, xmlNodePtr dependency)
10150Sstevel@tonic-gate {
10160Sstevel@tonic-gate 	pgroup_t *pg;
10170Sstevel@tonic-gate 	property_t *p;
10180Sstevel@tonic-gate 	xmlNodePtr cursor;
10190Sstevel@tonic-gate 	xmlChar *name;
10200Sstevel@tonic-gate 	xmlChar *delete;
10210Sstevel@tonic-gate 
10220Sstevel@tonic-gate 	/*
10230Sstevel@tonic-gate 	 * dependency attributes:
10240Sstevel@tonic-gate 	 * name: string
10250Sstevel@tonic-gate 	 * grouping: require_all | require_any | exclude_all | optional_all
10260Sstevel@tonic-gate 	 * reset_on: string (error | restart | refresh | none)
10270Sstevel@tonic-gate 	 * type:  service / path /host
10280Sstevel@tonic-gate 	 */
10290Sstevel@tonic-gate 
10300Sstevel@tonic-gate 	name = xmlGetProp(dependency, (xmlChar *)name_attr);
10310Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(entity, (char *)name,
10320Sstevel@tonic-gate 	    (char *)SCF_GROUP_DEPENDENCY);
10330Sstevel@tonic-gate 	xmlFree(name);
10340Sstevel@tonic-gate 
10350Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_TYPE, SCF_TYPE_ASTRING,
10360Sstevel@tonic-gate 	    dependency, type_attr) != 0)
10370Sstevel@tonic-gate 		return (-1);
10380Sstevel@tonic-gate 
10390Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_RESTART_ON,
10400Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, dependency, "restart_on") != 0)
10410Sstevel@tonic-gate 		return (-1);
10420Sstevel@tonic-gate 
10430Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_GROUPING, SCF_TYPE_ASTRING,
10440Sstevel@tonic-gate 	    dependency, "grouping") != 0)
10450Sstevel@tonic-gate 		return (-1);
10460Sstevel@tonic-gate 
10470Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_ENTITIES, SCF_TYPE_FMRI, 0);
10480Sstevel@tonic-gate 	if (internal_attach_property(pg, p) != 0)
10490Sstevel@tonic-gate 		return (-1);
10500Sstevel@tonic-gate 
10510Sstevel@tonic-gate 	for (cursor = dependency->xmlChildrenNode; cursor != NULL;
10520Sstevel@tonic-gate 	    cursor = cursor->next) {
10530Sstevel@tonic-gate 		xmlChar *value;
10540Sstevel@tonic-gate 		value_t *v;
10550Sstevel@tonic-gate 
10560Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
10570Sstevel@tonic-gate 			continue;
10580Sstevel@tonic-gate 
10590Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
10600Sstevel@tonic-gate 		case SC_STABILITY:
10610Sstevel@tonic-gate 			if (lxml_get_pgroup_stability(pg, cursor) != 0)
10620Sstevel@tonic-gate 				return (-1);
10630Sstevel@tonic-gate 			break;
10640Sstevel@tonic-gate 
10650Sstevel@tonic-gate 		case SC_SERVICE_FMRI:
10660Sstevel@tonic-gate 			value = xmlGetProp(cursor, (xmlChar *)value_attr);
10670Sstevel@tonic-gate 			if (value != NULL) {
10680Sstevel@tonic-gate 				if (lxml_validate_string_value(SCF_TYPE_FMRI,
10690Sstevel@tonic-gate 				    (char *)value) != 0)
10700Sstevel@tonic-gate 					uu_die(gettext("illegal value \"%s\" "
10710Sstevel@tonic-gate 					    "for %s (%s)\n"), (char *)value,
10720Sstevel@tonic-gate 					    lxml_prop_types[SC_FMRI],
10730Sstevel@tonic-gate 					    (scf_error()) ?
10740Sstevel@tonic-gate 					    scf_strerror(scf_error()) :
10750Sstevel@tonic-gate 					    gettext("Illegal format"));
10760Sstevel@tonic-gate 				v = internal_value_new();
10770Sstevel@tonic-gate 				v->sc_type = SCF_TYPE_FMRI;
10780Sstevel@tonic-gate 				v->sc_u.sc_string = (char *)value;
10790Sstevel@tonic-gate 				internal_attach_value(p, v);
10800Sstevel@tonic-gate 			}
10810Sstevel@tonic-gate 
10820Sstevel@tonic-gate 			break;
10830Sstevel@tonic-gate 
10840Sstevel@tonic-gate 		case SC_PROPVAL:
10850Sstevel@tonic-gate 			(void) lxml_get_propval(pg, cursor);
10860Sstevel@tonic-gate 			break;
10870Sstevel@tonic-gate 
10880Sstevel@tonic-gate 		case SC_PROPERTY:
10890Sstevel@tonic-gate 			(void) lxml_get_property(pg, cursor);
10900Sstevel@tonic-gate 			break;
10910Sstevel@tonic-gate 
10920Sstevel@tonic-gate 		default:
10930Sstevel@tonic-gate 			uu_die(gettext("illegal element \"%s\" on "
10940Sstevel@tonic-gate 			    "dependency group \"%s\"\n"), cursor->name, name);
10950Sstevel@tonic-gate 			break;
10960Sstevel@tonic-gate 		}
10970Sstevel@tonic-gate 	}
10980Sstevel@tonic-gate 
10990Sstevel@tonic-gate 	delete = xmlGetProp(dependency, (xmlChar *)delete_attr);
11000Sstevel@tonic-gate 	pg->sc_pgroup_delete = (xmlStrcmp(delete, (xmlChar *)true) == 0);
11010Sstevel@tonic-gate 	xmlFree(delete);
11020Sstevel@tonic-gate 
11030Sstevel@tonic-gate 	return (0);
11040Sstevel@tonic-gate }
11050Sstevel@tonic-gate 
11060Sstevel@tonic-gate /*
11070Sstevel@tonic-gate  * Dependents are hairy.  They should cause a dependency pg to be created in
11080Sstevel@tonic-gate  * another service, but we can't do that here; we'll have to wait until the
11090Sstevel@tonic-gate  * import routines.  So for now we'll add the dependency group that should go
11100Sstevel@tonic-gate  * in the other service to the entity's dependent list.
11110Sstevel@tonic-gate  */
11120Sstevel@tonic-gate static int
11130Sstevel@tonic-gate lxml_get_dependent(entity_t *entity, xmlNodePtr dependent)
11140Sstevel@tonic-gate {
11150Sstevel@tonic-gate 	xmlChar *name, *or;
11160Sstevel@tonic-gate 	xmlNodePtr sf;
11170Sstevel@tonic-gate 	xmlChar *fmri, *delete;
11180Sstevel@tonic-gate 	pgroup_t *pg;
11190Sstevel@tonic-gate 	property_t *p;
11200Sstevel@tonic-gate 	xmlNodePtr n;
11210Sstevel@tonic-gate 	char *myfmri;
11220Sstevel@tonic-gate 
11230Sstevel@tonic-gate 	name = xmlGetProp(dependent, (xmlChar *)name_attr);
11240Sstevel@tonic-gate 
11250Sstevel@tonic-gate 	if (internal_pgroup_find(entity, (char *)name, NULL) != NULL) {
11260Sstevel@tonic-gate 		semerr(gettext("Property group and dependent of entity %s "
11270Sstevel@tonic-gate 		    "have same name \"%s\".\n"), entity->sc_name, name);
11280Sstevel@tonic-gate 		xmlFree(name);
11290Sstevel@tonic-gate 		return (-1);
11300Sstevel@tonic-gate 	}
11310Sstevel@tonic-gate 
11320Sstevel@tonic-gate 	or = xmlGetProp(dependent, (xmlChar *)override_attr);
11330Sstevel@tonic-gate 
11340Sstevel@tonic-gate 	pg = internal_pgroup_new();
11350Sstevel@tonic-gate 	pg->sc_pgroup_name = (char *)name;
11360Sstevel@tonic-gate 	pg->sc_pgroup_type = (char *)SCF_GROUP_DEPENDENCY;
11370Sstevel@tonic-gate 	pg->sc_pgroup_override = (xmlStrcmp(or, (xmlChar *)true) == 0);
11380Sstevel@tonic-gate 	xmlFree(or);
11390Sstevel@tonic-gate 	if (internal_attach_dependent(entity, pg) != 0) {
11400Sstevel@tonic-gate 		xmlFree(name);
11410Sstevel@tonic-gate 		internal_pgroup_free(pg);
11420Sstevel@tonic-gate 		return (-1);
11430Sstevel@tonic-gate 	}
11440Sstevel@tonic-gate 
11450Sstevel@tonic-gate 	for (sf = dependent->children; sf != NULL; sf = sf->next)
11460Sstevel@tonic-gate 		if (xmlStrcmp(sf->name, (xmlChar *)"service_fmri") == 0)
11470Sstevel@tonic-gate 			break;
11480Sstevel@tonic-gate 	assert(sf != NULL);
11490Sstevel@tonic-gate 	fmri = xmlGetProp(sf, (xmlChar *)value_attr);
11500Sstevel@tonic-gate 	pg->sc_pgroup_fmri = (char *)fmri;
11510Sstevel@tonic-gate 
11520Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_RESTART_ON,
11530Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, dependent, "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 	    dependent, "grouping") != 0)
11580Sstevel@tonic-gate 		return (-1);
11590Sstevel@tonic-gate 
11600Sstevel@tonic-gate 	myfmri = safe_malloc(max_scf_fmri_len + 1);
11610Sstevel@tonic-gate 	if (entity->sc_etype == SVCCFG_SERVICE_OBJECT) {
11620Sstevel@tonic-gate 		if (snprintf(myfmri, max_scf_fmri_len + 1, "svc:/%s",
11630Sstevel@tonic-gate 		    entity->sc_name) < 0)
11640Sstevel@tonic-gate 			bad_error("snprintf", errno);
11650Sstevel@tonic-gate 	} else {
11660Sstevel@tonic-gate 		assert(entity->sc_etype == SVCCFG_INSTANCE_OBJECT);
11670Sstevel@tonic-gate 		if (snprintf(myfmri, max_scf_fmri_len + 1, "svc:/%s:%s",
11680Sstevel@tonic-gate 		    entity->sc_parent->sc_name, entity->sc_name) < 0)
11690Sstevel@tonic-gate 			bad_error("snprintf", errno);
11700Sstevel@tonic-gate 	}
11710Sstevel@tonic-gate 
11720Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_ENTITIES, SCF_TYPE_FMRI, 1,
11730Sstevel@tonic-gate 	    myfmri);
11740Sstevel@tonic-gate 	if (internal_attach_property(pg, p) != 0)
11750Sstevel@tonic-gate 		return (-1);
11760Sstevel@tonic-gate 
11770Sstevel@tonic-gate 	/* Create a property to serve as a do-not-export flag. */
11780Sstevel@tonic-gate 	p = internal_property_create("external", SCF_TYPE_BOOLEAN, 1,
11790Sstevel@tonic-gate 	    (uint64_t)1);
11800Sstevel@tonic-gate 	if (internal_attach_property(pg, p) != 0)
11810Sstevel@tonic-gate 		return (-1);
11820Sstevel@tonic-gate 
11830Sstevel@tonic-gate 	for (n = sf->next; n != NULL; n = n->next) {
11840Sstevel@tonic-gate 		if (lxml_ignorable_block(n))
11850Sstevel@tonic-gate 			continue;
11860Sstevel@tonic-gate 
11870Sstevel@tonic-gate 		switch (lxml_xlate_element(n->name)) {
11880Sstevel@tonic-gate 		case SC_STABILITY:
11890Sstevel@tonic-gate 			if (new_str_prop_from_attr(pg,
11900Sstevel@tonic-gate 			    SCF_PROPERTY_ENTITY_STABILITY, SCF_TYPE_ASTRING, n,
11910Sstevel@tonic-gate 			    value_attr) != 0)
11920Sstevel@tonic-gate 				return (-1);
11930Sstevel@tonic-gate 			break;
11940Sstevel@tonic-gate 
11950Sstevel@tonic-gate 		case SC_PROPVAL:
11960Sstevel@tonic-gate 			(void) lxml_get_propval(pg, n);
11970Sstevel@tonic-gate 			break;
11980Sstevel@tonic-gate 
11990Sstevel@tonic-gate 		case SC_PROPERTY:
12000Sstevel@tonic-gate 			(void) lxml_get_property(pg, n);
12010Sstevel@tonic-gate 			break;
12020Sstevel@tonic-gate 
12030Sstevel@tonic-gate 		default:
12040Sstevel@tonic-gate 			uu_die(gettext("unexpected element %s.\n"), n->name);
12050Sstevel@tonic-gate 		}
12060Sstevel@tonic-gate 	}
12070Sstevel@tonic-gate 
12080Sstevel@tonic-gate 	/* Go back and fill in defaults. */
12090Sstevel@tonic-gate 	if (internal_property_find(pg, SCF_PROPERTY_TYPE) == NULL) {
12100Sstevel@tonic-gate 		p = internal_property_create(SCF_PROPERTY_TYPE,
12110Sstevel@tonic-gate 		    SCF_TYPE_ASTRING, 1, "service");
12120Sstevel@tonic-gate 		if (internal_attach_property(pg, p) != 0)
12130Sstevel@tonic-gate 			return (-1);
12140Sstevel@tonic-gate 	}
12150Sstevel@tonic-gate 
12160Sstevel@tonic-gate 	delete = xmlGetProp(dependent, (xmlChar *)delete_attr);
12170Sstevel@tonic-gate 	pg->sc_pgroup_delete = (xmlStrcmp(delete, (xmlChar *)true) == 0);
12180Sstevel@tonic-gate 	xmlFree(delete);
12190Sstevel@tonic-gate 
12200Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(entity, "dependents",
12210Sstevel@tonic-gate 	    (char *)scf_group_framework);
1222306Sbustos 	p = internal_property_create((char *)name, SCF_TYPE_FMRI, 1, fmri);
12230Sstevel@tonic-gate 	if (internal_attach_property(pg, p) != 0)
12240Sstevel@tonic-gate 		return (-1);
12250Sstevel@tonic-gate 
12260Sstevel@tonic-gate 	return (0);
12270Sstevel@tonic-gate }
12280Sstevel@tonic-gate 
12290Sstevel@tonic-gate static int
12300Sstevel@tonic-gate lxml_get_entity_stability(entity_t *entity, xmlNodePtr rstr)
12310Sstevel@tonic-gate {
12320Sstevel@tonic-gate 	pgroup_t *pg;
12330Sstevel@tonic-gate 	property_t *p;
12340Sstevel@tonic-gate 	xmlChar *stabval;
12350Sstevel@tonic-gate 
1236*7887SLiane.Praza@Sun.COM 	if (((stabval = xmlGetProp(rstr, (xmlChar *)value_attr)) == NULL) ||
1237*7887SLiane.Praza@Sun.COM 	    (*stabval == 0)) {
12380Sstevel@tonic-gate 		uu_warn(gettext("no stability value found\n"));
12390Sstevel@tonic-gate 		stabval = (xmlChar *)strdup("External");
12400Sstevel@tonic-gate 	}
12410Sstevel@tonic-gate 
12420Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(entity, (char *)scf_pg_general,
12430Sstevel@tonic-gate 	    (char *)scf_group_framework);
12440Sstevel@tonic-gate 
12450Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_ENTITY_STABILITY,
12460Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, 1, stabval);
12470Sstevel@tonic-gate 
12480Sstevel@tonic-gate 	return (internal_attach_property(pg, p));
12490Sstevel@tonic-gate }
12500Sstevel@tonic-gate 
12510Sstevel@tonic-gate static int
12520Sstevel@tonic-gate lxml_get_restarter(entity_t *entity, xmlNodePtr rstr)
12530Sstevel@tonic-gate {
12540Sstevel@tonic-gate 	pgroup_t *pg;
12550Sstevel@tonic-gate 	property_t *p;
12560Sstevel@tonic-gate 	xmlChar *restarter;
12570Sstevel@tonic-gate 	xmlNode *cursor;
12580Sstevel@tonic-gate 	int r;
12590Sstevel@tonic-gate 
12600Sstevel@tonic-gate 	/*
12610Sstevel@tonic-gate 	 * Go find child.  Child is a service_fmri element.  value attribute
12620Sstevel@tonic-gate 	 * contains restarter FMRI.
12630Sstevel@tonic-gate 	 */
12640Sstevel@tonic-gate 
12650Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(entity, (char *)scf_pg_general,
12660Sstevel@tonic-gate 	    (char *)scf_group_framework);
12670Sstevel@tonic-gate 
12680Sstevel@tonic-gate 	/*
12690Sstevel@tonic-gate 	 * Walk its child elements, as appropriate.
12700Sstevel@tonic-gate 	 */
12710Sstevel@tonic-gate 	for (cursor = rstr->xmlChildrenNode; cursor != NULL;
12720Sstevel@tonic-gate 	    cursor = cursor->next) {
12730Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
12740Sstevel@tonic-gate 			continue;
12750Sstevel@tonic-gate 
12760Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
12770Sstevel@tonic-gate 		case SC_SERVICE_FMRI:
12780Sstevel@tonic-gate 			restarter = xmlGetProp(cursor, (xmlChar *)value_attr);
12790Sstevel@tonic-gate 			break;
12800Sstevel@tonic-gate 		default:
12810Sstevel@tonic-gate 			uu_die(gettext("illegal element \"%s\" on restarter "
12820Sstevel@tonic-gate 			    "element for \"%s\"\n"), cursor->name,
12830Sstevel@tonic-gate 			    entity->sc_name);
12840Sstevel@tonic-gate 			break;
12850Sstevel@tonic-gate 		}
12860Sstevel@tonic-gate 	}
12870Sstevel@tonic-gate 
12880Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_RESTARTER, SCF_TYPE_FMRI, 1,
12890Sstevel@tonic-gate 	    restarter);
12900Sstevel@tonic-gate 
12910Sstevel@tonic-gate 	r = internal_attach_property(pg, p);
12920Sstevel@tonic-gate 	if (r != 0) {
12930Sstevel@tonic-gate 		internal_property_free(p);
12940Sstevel@tonic-gate 		return (-1);
12950Sstevel@tonic-gate 	}
12960Sstevel@tonic-gate 
12970Sstevel@tonic-gate 	return (0);
12980Sstevel@tonic-gate }
12990Sstevel@tonic-gate 
1300*7887SLiane.Praza@Sun.COM /*
1301*7887SLiane.Praza@Sun.COM  * Add a property containing the localized text from the manifest.  The
1302*7887SLiane.Praza@Sun.COM  * property is added to the property group at pg.  The name of the created
1303*7887SLiane.Praza@Sun.COM  * property is based on the format at pn_format.  This is an snprintf(3C)
1304*7887SLiane.Praza@Sun.COM  * format containing a single %s conversion specification.  At conversion
1305*7887SLiane.Praza@Sun.COM  * time, the %s is replaced by the locale designation.
1306*7887SLiane.Praza@Sun.COM  *
1307*7887SLiane.Praza@Sun.COM  * source is the source element and it is only used for error messages.
1308*7887SLiane.Praza@Sun.COM  */
1309*7887SLiane.Praza@Sun.COM static int
1310*7887SLiane.Praza@Sun.COM lxml_get_loctext(entity_t *service, pgroup_t *pg, xmlNodePtr loctext,
1311*7887SLiane.Praza@Sun.COM     const char *pn_format, const char *source)
13120Sstevel@tonic-gate {
1313*7887SLiane.Praza@Sun.COM 	int extra;
13140Sstevel@tonic-gate 	xmlNodePtr cursor;
13150Sstevel@tonic-gate 	xmlChar *val;
13160Sstevel@tonic-gate 	char *stripped, *cp;
13170Sstevel@tonic-gate 	property_t *p;
1318*7887SLiane.Praza@Sun.COM 	char *prop_name;
13190Sstevel@tonic-gate 	int r;
13200Sstevel@tonic-gate 
1321*7887SLiane.Praza@Sun.COM 	if (((val = xmlGetProp(loctext, (xmlChar *)xml_lang_attr)) == NULL) ||
1322*7887SLiane.Praza@Sun.COM 	    (*val == 0)) {
1323*7887SLiane.Praza@Sun.COM 		if (((val = xmlGetProp(loctext,
1324*7887SLiane.Praza@Sun.COM 		    (xmlChar *)lang_attr)) == NULL) || (*val == 0)) {
13250Sstevel@tonic-gate 			val = (xmlChar *)"unknown";
1326*7887SLiane.Praza@Sun.COM 		}
1327*7887SLiane.Praza@Sun.COM 	}
1328*7887SLiane.Praza@Sun.COM 
1329*7887SLiane.Praza@Sun.COM 	_scf_sanitize_locale((char *)val);
1330*7887SLiane.Praza@Sun.COM 	prop_name = safe_malloc(max_scf_name_len + 1);
1331*7887SLiane.Praza@Sun.COM 	if ((extra = snprintf(prop_name, max_scf_name_len + 1, pn_format,
1332*7887SLiane.Praza@Sun.COM 	    val)) >= max_scf_name_len + 1) {
1333*7887SLiane.Praza@Sun.COM 		extra -= max_scf_name_len;
1334*7887SLiane.Praza@Sun.COM 		uu_die(gettext("%s attribute is %d characters too long for "
1335*7887SLiane.Praza@Sun.COM 		    "%s in %s\n"),
1336*7887SLiane.Praza@Sun.COM 		    xml_lang_attr, extra, source, service->sc_name);
1337*7887SLiane.Praza@Sun.COM 	}
1338*7887SLiane.Praza@Sun.COM 	xmlFree(val);
13390Sstevel@tonic-gate 
13400Sstevel@tonic-gate 	for (cursor = loctext->xmlChildrenNode; cursor != NULL;
13410Sstevel@tonic-gate 	    cursor = cursor->next) {
13420Sstevel@tonic-gate 		if (strcmp("text", (const char *)cursor->name) == 0) {
13430Sstevel@tonic-gate 			break;
13440Sstevel@tonic-gate 		} else if (strcmp("comment", (const char *)cursor->name) != 0) {
13450Sstevel@tonic-gate 			uu_die(gettext("illegal element \"%s\" on loctext "
13460Sstevel@tonic-gate 			    "element for \"%s\"\n"), cursor->name,
13470Sstevel@tonic-gate 			    service->sc_name);
13480Sstevel@tonic-gate 		}
13490Sstevel@tonic-gate 	}
13500Sstevel@tonic-gate 
13510Sstevel@tonic-gate 	if (cursor == NULL) {
13520Sstevel@tonic-gate 		uu_die(gettext("loctext element has no content for \"%s\"\n"),
13530Sstevel@tonic-gate 		    service->sc_name);
13540Sstevel@tonic-gate 	}
13550Sstevel@tonic-gate 
13560Sstevel@tonic-gate 	/*
13570Sstevel@tonic-gate 	 * Remove leading and trailing whitespace.
13580Sstevel@tonic-gate 	 */
13590Sstevel@tonic-gate 	if ((stripped = strdup((const char *)cursor->content)) == NULL)
13600Sstevel@tonic-gate 		uu_die(gettext("Out of memory\n"));
13610Sstevel@tonic-gate 
13624740Sjeanm 	for (; isspace(*stripped); stripped++)
13634740Sjeanm 		;
13644740Sjeanm 	for (cp = stripped + strlen(stripped) - 1; isspace(*cp); cp--)
13654740Sjeanm 		;
13660Sstevel@tonic-gate 	*(cp + 1) = '\0';
13670Sstevel@tonic-gate 
1368*7887SLiane.Praza@Sun.COM 	p = internal_property_create(prop_name, SCF_TYPE_USTRING, 1,
13690Sstevel@tonic-gate 	    stripped);
13700Sstevel@tonic-gate 
13710Sstevel@tonic-gate 	r = internal_attach_property(pg, p);
1372*7887SLiane.Praza@Sun.COM 	if (r != 0) {
13730Sstevel@tonic-gate 		internal_property_free(p);
1374*7887SLiane.Praza@Sun.COM 		free(prop_name);
1375*7887SLiane.Praza@Sun.COM 	}
13760Sstevel@tonic-gate 
13770Sstevel@tonic-gate 	return (r);
13780Sstevel@tonic-gate }
13790Sstevel@tonic-gate 
1380*7887SLiane.Praza@Sun.COM /*
1381*7887SLiane.Praza@Sun.COM  * This function processes all loctext elements in the current XML element
1382*7887SLiane.Praza@Sun.COM  * designated by container.  A property is created for each loctext element
1383*7887SLiane.Praza@Sun.COM  * and added to the property group at pg.  The name of the property is
1384*7887SLiane.Praza@Sun.COM  * derived from the loctext language designation using the format at
1385*7887SLiane.Praza@Sun.COM  * pn_format.  pn_format should be an snprintf format string containing one
1386*7887SLiane.Praza@Sun.COM  * %s which is replaced by the language designation.
1387*7887SLiane.Praza@Sun.COM  *
1388*7887SLiane.Praza@Sun.COM  * The function returns 0 on success and -1 if it is unable to attach the
1389*7887SLiane.Praza@Sun.COM  * newly created property to pg.
1390*7887SLiane.Praza@Sun.COM  */
13910Sstevel@tonic-gate static int
1392*7887SLiane.Praza@Sun.COM lxml_get_all_loctext(entity_t *service, pgroup_t *pg, xmlNodePtr container,
1393*7887SLiane.Praza@Sun.COM     const char *pn_format, const char *source)
13940Sstevel@tonic-gate {
13950Sstevel@tonic-gate 	xmlNodePtr cursor;
13960Sstevel@tonic-gate 
13970Sstevel@tonic-gate 	/*
1398*7887SLiane.Praza@Sun.COM 	 * Iterate through one or more loctext elements.  The locale is
1399*7887SLiane.Praza@Sun.COM 	 * used to generate the property name; the contents are the ustring
1400*7887SLiane.Praza@Sun.COM 	 * value for the property.
14010Sstevel@tonic-gate 	 */
1402*7887SLiane.Praza@Sun.COM 	for (cursor = container->xmlChildrenNode; cursor != NULL;
14030Sstevel@tonic-gate 	    cursor = cursor->next) {
14040Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
14050Sstevel@tonic-gate 			continue;
14060Sstevel@tonic-gate 
14070Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
14080Sstevel@tonic-gate 		case SC_LOCTEXT:
1409*7887SLiane.Praza@Sun.COM 			if (lxml_get_loctext(service, pg, cursor, pn_format,
1410*7887SLiane.Praza@Sun.COM 			    source))
14110Sstevel@tonic-gate 				return (-1);
14120Sstevel@tonic-gate 			break;
14130Sstevel@tonic-gate 		default:
1414*7887SLiane.Praza@Sun.COM 			uu_die(gettext("illegal element \"%s\" on %s element "
1415*7887SLiane.Praza@Sun.COM 			    "for \"%s\"\n"), cursor->name, container->name,
14160Sstevel@tonic-gate 			    service->sc_name);
14170Sstevel@tonic-gate 			break;
14180Sstevel@tonic-gate 		}
14190Sstevel@tonic-gate 	}
14200Sstevel@tonic-gate 
14210Sstevel@tonic-gate 	return (0);
14220Sstevel@tonic-gate }
14230Sstevel@tonic-gate 
1424*7887SLiane.Praza@Sun.COM /*
1425*7887SLiane.Praza@Sun.COM  * Obtain the specified cardinality attribute and place it in a property
1426*7887SLiane.Praza@Sun.COM  * named prop_name.  The converted attribute is placed at *value, and the
1427*7887SLiane.Praza@Sun.COM  * newly created property is returned to propp.  NULL is returned to propp
1428*7887SLiane.Praza@Sun.COM  * if the attribute is not provided in the manifest.
1429*7887SLiane.Praza@Sun.COM  *
1430*7887SLiane.Praza@Sun.COM  * 0 is returned upon success, and -1 indicates that the manifest contained
1431*7887SLiane.Praza@Sun.COM  * an invalid cardinality value.
1432*7887SLiane.Praza@Sun.COM  */
14330Sstevel@tonic-gate static int
1434*7887SLiane.Praza@Sun.COM lxml_get_cardinality_attribute(entity_t *service, xmlNodePtr cursor,
1435*7887SLiane.Praza@Sun.COM     const char *attr_name, const char *prop_name, uint64_t *value,
1436*7887SLiane.Praza@Sun.COM     property_t **propp)
1437*7887SLiane.Praza@Sun.COM {
1438*7887SLiane.Praza@Sun.COM 	char *c;
1439*7887SLiane.Praza@Sun.COM 	property_t *p;
1440*7887SLiane.Praza@Sun.COM 	xmlChar *val;
1441*7887SLiane.Praza@Sun.COM 	uint64_t count;
1442*7887SLiane.Praza@Sun.COM 	char *endptr;
1443*7887SLiane.Praza@Sun.COM 
1444*7887SLiane.Praza@Sun.COM 	*propp = NULL;
1445*7887SLiane.Praza@Sun.COM 	val = xmlGetProp(cursor, (xmlChar *)attr_name);
1446*7887SLiane.Praza@Sun.COM 	if (val == NULL)
1447*7887SLiane.Praza@Sun.COM 		return (0);
1448*7887SLiane.Praza@Sun.COM 	if (*val == 0) {
1449*7887SLiane.Praza@Sun.COM 		xmlFree(val);
1450*7887SLiane.Praza@Sun.COM 		return (0);
1451*7887SLiane.Praza@Sun.COM 	}
1452*7887SLiane.Praza@Sun.COM 
1453*7887SLiane.Praza@Sun.COM 	/*
1454*7887SLiane.Praza@Sun.COM 	 * Make sure that the string at val doesn't have a leading minus
1455*7887SLiane.Praza@Sun.COM 	 * sign.  The strtoull() call below does not catch this problem.
1456*7887SLiane.Praza@Sun.COM 	 */
1457*7887SLiane.Praza@Sun.COM 	for (c = (char *)val; *c != 0; c++) {
1458*7887SLiane.Praza@Sun.COM 		if (isspace(*c))
1459*7887SLiane.Praza@Sun.COM 			continue;
1460*7887SLiane.Praza@Sun.COM 		if (isdigit(*c))
1461*7887SLiane.Praza@Sun.COM 			break;
1462*7887SLiane.Praza@Sun.COM 		semerr(gettext("\"%c\" is not a legal character in the %s "
1463*7887SLiane.Praza@Sun.COM 		    "attribute of the %s element in %s.\n"), *c,
1464*7887SLiane.Praza@Sun.COM 		    attr_name, prop_name, service->sc_name);
1465*7887SLiane.Praza@Sun.COM 		xmlFree(val);
1466*7887SLiane.Praza@Sun.COM 		return (-1);
1467*7887SLiane.Praza@Sun.COM 	}
1468*7887SLiane.Praza@Sun.COM 	errno = 0;
1469*7887SLiane.Praza@Sun.COM 	count = strtoull((char *)val, &endptr, 10);
1470*7887SLiane.Praza@Sun.COM 	if (errno != 0 || endptr == (char *)val || *endptr) {
1471*7887SLiane.Praza@Sun.COM 		semerr(gettext("\"%s\" is not a legal number for the %s "
1472*7887SLiane.Praza@Sun.COM 		    "attribute of the %s element in %s.\n"), (char *)val,
1473*7887SLiane.Praza@Sun.COM 		    attr_name, prop_name, service->sc_name);
1474*7887SLiane.Praza@Sun.COM 		xmlFree(val);
1475*7887SLiane.Praza@Sun.COM 		return (-1);
1476*7887SLiane.Praza@Sun.COM 	}
1477*7887SLiane.Praza@Sun.COM 
1478*7887SLiane.Praza@Sun.COM 	xmlFree(val);
1479*7887SLiane.Praza@Sun.COM 
1480*7887SLiane.Praza@Sun.COM 	/* Value is valid.  Create the property. */
1481*7887SLiane.Praza@Sun.COM 	p = internal_property_create(prop_name, SCF_TYPE_COUNT, 1, count);
1482*7887SLiane.Praza@Sun.COM 	*value = count;
1483*7887SLiane.Praza@Sun.COM 	*propp = p;
1484*7887SLiane.Praza@Sun.COM 	return (0);
1485*7887SLiane.Praza@Sun.COM }
1486*7887SLiane.Praza@Sun.COM 
1487*7887SLiane.Praza@Sun.COM /*
1488*7887SLiane.Praza@Sun.COM  * The cardinality is specified by two attributes max and min at cursor.
1489*7887SLiane.Praza@Sun.COM  * Both are optional, but if present they must be unsigned integers.
1490*7887SLiane.Praza@Sun.COM  */
1491*7887SLiane.Praza@Sun.COM static int
1492*7887SLiane.Praza@Sun.COM lxml_get_tm_cardinality(entity_t *service, pgroup_t *pg, xmlNodePtr cursor)
14930Sstevel@tonic-gate {
1494*7887SLiane.Praza@Sun.COM 	int min_attached = 0;
1495*7887SLiane.Praza@Sun.COM 	int compare = 1;
1496*7887SLiane.Praza@Sun.COM 	property_t *min_prop;
1497*7887SLiane.Praza@Sun.COM 	property_t *max_prop;
1498*7887SLiane.Praza@Sun.COM 	uint64_t max;
1499*7887SLiane.Praza@Sun.COM 	uint64_t min;
1500*7887SLiane.Praza@Sun.COM 	int r;
1501*7887SLiane.Praza@Sun.COM 
1502*7887SLiane.Praza@Sun.COM 	r = lxml_get_cardinality_attribute(service, cursor, min_attr,
1503*7887SLiane.Praza@Sun.COM 	    SCF_PROPERTY_TM_CARDINALITY_MIN, &min, &min_prop);
1504*7887SLiane.Praza@Sun.COM 	if (r != 0)
1505*7887SLiane.Praza@Sun.COM 		return (r);
1506*7887SLiane.Praza@Sun.COM 	if (min_prop == NULL)
1507*7887SLiane.Praza@Sun.COM 		compare = 0;
1508*7887SLiane.Praza@Sun.COM 	r = lxml_get_cardinality_attribute(service, cursor, max_attr,
1509*7887SLiane.Praza@Sun.COM 	    SCF_PROPERTY_TM_CARDINALITY_MAX, &max, &max_prop);
1510*7887SLiane.Praza@Sun.COM 	if (r != 0)
1511*7887SLiane.Praza@Sun.COM 		goto errout;
1512*7887SLiane.Praza@Sun.COM 	if ((max_prop != NULL) && (compare == 1)) {
1513*7887SLiane.Praza@Sun.COM 		if (max < min) {
1514*7887SLiane.Praza@Sun.COM 			semerr(gettext("Cardinality max is less than min for "
1515*7887SLiane.Praza@Sun.COM 			    "the %s element in %s.\n"), pg->sc_pgroup_name,
1516*7887SLiane.Praza@Sun.COM 			    service->sc_fmri);
1517*7887SLiane.Praza@Sun.COM 			goto errout;
1518*7887SLiane.Praza@Sun.COM 		}
1519*7887SLiane.Praza@Sun.COM 	}
1520*7887SLiane.Praza@Sun.COM 
1521*7887SLiane.Praza@Sun.COM 	/* Attach the properties to the property group. */
1522*7887SLiane.Praza@Sun.COM 	if (min_prop) {
1523*7887SLiane.Praza@Sun.COM 		if (internal_attach_property(pg, min_prop) == 0) {
1524*7887SLiane.Praza@Sun.COM 			min_attached = 1;
1525*7887SLiane.Praza@Sun.COM 		} else {
1526*7887SLiane.Praza@Sun.COM 			goto errout;
1527*7887SLiane.Praza@Sun.COM 		}
1528*7887SLiane.Praza@Sun.COM 	}
1529*7887SLiane.Praza@Sun.COM 	if (max_prop) {
1530*7887SLiane.Praza@Sun.COM 		if (internal_attach_property(pg, max_prop) != 0) {
1531*7887SLiane.Praza@Sun.COM 			if (min_attached)
1532*7887SLiane.Praza@Sun.COM 				internal_detach_property(pg, min_prop);
1533*7887SLiane.Praza@Sun.COM 			goto errout;
1534*7887SLiane.Praza@Sun.COM 		}
1535*7887SLiane.Praza@Sun.COM 	}
1536*7887SLiane.Praza@Sun.COM 	return (0);
1537*7887SLiane.Praza@Sun.COM 
1538*7887SLiane.Praza@Sun.COM errout:
1539*7887SLiane.Praza@Sun.COM 	if (min_prop)
1540*7887SLiane.Praza@Sun.COM 		internal_property_free(min_prop);
1541*7887SLiane.Praza@Sun.COM 	if (max_prop)
1542*7887SLiane.Praza@Sun.COM 		internal_property_free(max_prop);
1543*7887SLiane.Praza@Sun.COM 	return (-1);
1544*7887SLiane.Praza@Sun.COM }
1545*7887SLiane.Praza@Sun.COM 
1546*7887SLiane.Praza@Sun.COM /*
1547*7887SLiane.Praza@Sun.COM  * Get the common_name which is present as localized text at common_name in
1548*7887SLiane.Praza@Sun.COM  * the manifest.  The common_name is stored as the value of a property in
1549*7887SLiane.Praza@Sun.COM  * the property group whose name is SCF_PG_TM_COMMON_NAME and type is
1550*7887SLiane.Praza@Sun.COM  * SCF_GROUP_TEMPLATE.  This property group will be created in service if
1551*7887SLiane.Praza@Sun.COM  * it is not already there.
1552*7887SLiane.Praza@Sun.COM  */
1553*7887SLiane.Praza@Sun.COM static int
1554*7887SLiane.Praza@Sun.COM lxml_get_tm_common_name(entity_t *service, xmlNodePtr common_name)
1555*7887SLiane.Praza@Sun.COM {
15560Sstevel@tonic-gate 	pgroup_t *pg;
15570Sstevel@tonic-gate 
15580Sstevel@tonic-gate 	/*
15590Sstevel@tonic-gate 	 * Create the property group, if absent.
15600Sstevel@tonic-gate 	 */
1561*7887SLiane.Praza@Sun.COM 	pg = internal_pgroup_find_or_create(service, SCF_PG_TM_COMMON_NAME,
1562*7887SLiane.Praza@Sun.COM 	    SCF_GROUP_TEMPLATE);
1563*7887SLiane.Praza@Sun.COM 
1564*7887SLiane.Praza@Sun.COM 	return (lxml_get_all_loctext(service, pg, common_name, LOCALE_ONLY_FMT,
1565*7887SLiane.Praza@Sun.COM 	    "common_name"));
1566*7887SLiane.Praza@Sun.COM }
1567*7887SLiane.Praza@Sun.COM 
1568*7887SLiane.Praza@Sun.COM /*
1569*7887SLiane.Praza@Sun.COM  * Get the description which is present as localized text at description in
1570*7887SLiane.Praza@Sun.COM  * the manifest.  The description is stored as the value of a property in
1571*7887SLiane.Praza@Sun.COM  * the property group whose name is SCF_PG_TM_DESCRIPTION and type is
1572*7887SLiane.Praza@Sun.COM  * SCF_GROUP_TEMPLATE.  This property group will be created in service if
1573*7887SLiane.Praza@Sun.COM  * it is not already there.
1574*7887SLiane.Praza@Sun.COM  */
1575*7887SLiane.Praza@Sun.COM static int
1576*7887SLiane.Praza@Sun.COM lxml_get_tm_description(entity_t *service, xmlNodePtr description)
1577*7887SLiane.Praza@Sun.COM {
1578*7887SLiane.Praza@Sun.COM 	pgroup_t *pg;
15790Sstevel@tonic-gate 
15800Sstevel@tonic-gate 	/*
1581*7887SLiane.Praza@Sun.COM 	 * Create the property group, if absent.
15820Sstevel@tonic-gate 	 */
1583*7887SLiane.Praza@Sun.COM 	pg = internal_pgroup_find_or_create(service, SCF_PG_TM_DESCRIPTION,
1584*7887SLiane.Praza@Sun.COM 	    SCF_GROUP_TEMPLATE);
1585*7887SLiane.Praza@Sun.COM 
1586*7887SLiane.Praza@Sun.COM 	return (lxml_get_all_loctext(service, pg, description,
1587*7887SLiane.Praza@Sun.COM 	    LOCALE_ONLY_FMT, "description"));
15880Sstevel@tonic-gate }
15890Sstevel@tonic-gate 
15900Sstevel@tonic-gate static char *
15910Sstevel@tonic-gate lxml_label_to_groupname(const char *prefix, const char *in)
15920Sstevel@tonic-gate {
15930Sstevel@tonic-gate 	char *out, *cp;
15940Sstevel@tonic-gate 	size_t len, piece_len;
15950Sstevel@tonic-gate 
15960Sstevel@tonic-gate 	out = uu_zalloc(2 * scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1);
15970Sstevel@tonic-gate 	if (out == NULL)
15980Sstevel@tonic-gate 		return (NULL);
15990Sstevel@tonic-gate 
16000Sstevel@tonic-gate 	(void) strcpy(out, prefix);
16010Sstevel@tonic-gate 	(void) strcat(out, in);
16020Sstevel@tonic-gate 
16030Sstevel@tonic-gate 	len = strlen(out);
16040Sstevel@tonic-gate 	if (len > max_scf_name_len) {
16050Sstevel@tonic-gate 		/* Use the first half and the second half. */
16060Sstevel@tonic-gate 		piece_len = (max_scf_name_len - 2) / 2;
16070Sstevel@tonic-gate 
16080Sstevel@tonic-gate 		(void) strncpy(out + piece_len, "..", 2);
16090Sstevel@tonic-gate 
16100Sstevel@tonic-gate 		(void) strcpy(out + piece_len + 2, out + (len - piece_len));
16110Sstevel@tonic-gate 
16120Sstevel@tonic-gate 		len = strlen(out);
16130Sstevel@tonic-gate 	}
16140Sstevel@tonic-gate 
16150Sstevel@tonic-gate 	/*
16160Sstevel@tonic-gate 	 * Translate non-property characters to '_'.
16170Sstevel@tonic-gate 	 */
16180Sstevel@tonic-gate 	for (cp = out; *cp != '\0'; ++cp) {
16190Sstevel@tonic-gate 		if (!(isalnum(*cp) || *cp == '_' || *cp == '-'))
16200Sstevel@tonic-gate 			*cp = '_';
16210Sstevel@tonic-gate 	}
16220Sstevel@tonic-gate 
16230Sstevel@tonic-gate 	*cp = '\0';
16240Sstevel@tonic-gate 
16250Sstevel@tonic-gate 	return (out);
16260Sstevel@tonic-gate }
16270Sstevel@tonic-gate 
1628*7887SLiane.Praza@Sun.COM /*
1629*7887SLiane.Praza@Sun.COM  * If *p is NULL, astring_prop_value() first creates a property with the
1630*7887SLiane.Praza@Sun.COM  * name specified in prop_name.  The address of the newly created property
1631*7887SLiane.Praza@Sun.COM  * is placed in *p.
1632*7887SLiane.Praza@Sun.COM  *
1633*7887SLiane.Praza@Sun.COM  * In either case, newly created property or existing property, a new
1634*7887SLiane.Praza@Sun.COM  * SCF_TYPE_ASTRING value will created and attached to the property at *p.
1635*7887SLiane.Praza@Sun.COM  * The value of the newly created property is prop_value.
1636*7887SLiane.Praza@Sun.COM  *
1637*7887SLiane.Praza@Sun.COM  * free_flag is used to indicate whether or not the memory at prop_value
1638*7887SLiane.Praza@Sun.COM  * should be freed when the property is freed by a call to
1639*7887SLiane.Praza@Sun.COM  * internal_property_free().
1640*7887SLiane.Praza@Sun.COM  */
1641*7887SLiane.Praza@Sun.COM static void
1642*7887SLiane.Praza@Sun.COM astring_prop_value(property_t **p, const char *prop_name, char *prop_value,
1643*7887SLiane.Praza@Sun.COM     boolean_t free_flag)
1644*7887SLiane.Praza@Sun.COM {
1645*7887SLiane.Praza@Sun.COM 	value_t *v;
1646*7887SLiane.Praza@Sun.COM 
1647*7887SLiane.Praza@Sun.COM 	if (*p == NULL) {
1648*7887SLiane.Praza@Sun.COM 		/* Create the property */
1649*7887SLiane.Praza@Sun.COM 		*p = internal_property_new();
1650*7887SLiane.Praza@Sun.COM 		(*p)->sc_property_name = (char *)prop_name;
1651*7887SLiane.Praza@Sun.COM 		(*p)->sc_value_type = SCF_TYPE_ASTRING;
1652*7887SLiane.Praza@Sun.COM 	}
1653*7887SLiane.Praza@Sun.COM 
1654*7887SLiane.Praza@Sun.COM 	/* Add the property value to the property's list of values. */
1655*7887SLiane.Praza@Sun.COM 	v = internal_value_new();
1656*7887SLiane.Praza@Sun.COM 	v->sc_type = SCF_TYPE_ASTRING;
1657*7887SLiane.Praza@Sun.COM 	if (free_flag == B_TRUE)
1658*7887SLiane.Praza@Sun.COM 		v->sc_free = lxml_free_str;
1659*7887SLiane.Praza@Sun.COM 	v->sc_u.sc_string = prop_value;
1660*7887SLiane.Praza@Sun.COM 	internal_attach_value(*p, v);
1661*7887SLiane.Praza@Sun.COM }
1662*7887SLiane.Praza@Sun.COM 
1663*7887SLiane.Praza@Sun.COM /*
1664*7887SLiane.Praza@Sun.COM  * If p points to a null pointer, create an internal_separators property
1665*7887SLiane.Praza@Sun.COM  * saving the address at p.  For each character at seps create a property
1666*7887SLiane.Praza@Sun.COM  * value and attach it to the property at p.
1667*7887SLiane.Praza@Sun.COM  */
1668*7887SLiane.Praza@Sun.COM static void
1669*7887SLiane.Praza@Sun.COM seps_to_prop_values(property_t **p, xmlChar *seps)
1670*7887SLiane.Praza@Sun.COM {
1671*7887SLiane.Praza@Sun.COM 	value_t *v;
1672*7887SLiane.Praza@Sun.COM 	char val_str[2];
1673*7887SLiane.Praza@Sun.COM 
1674*7887SLiane.Praza@Sun.COM 	if (*p == NULL) {
1675*7887SLiane.Praza@Sun.COM 		*p = internal_property_new();
1676*7887SLiane.Praza@Sun.COM 		(*p)->sc_property_name =
1677*7887SLiane.Praza@Sun.COM 		    (char *)SCF_PROPERTY_INTERNAL_SEPARATORS;
1678*7887SLiane.Praza@Sun.COM 		(*p)->sc_value_type = SCF_TYPE_ASTRING;
1679*7887SLiane.Praza@Sun.COM 	}
1680*7887SLiane.Praza@Sun.COM 
1681*7887SLiane.Praza@Sun.COM 	/* Add the values to the property's list. */
1682*7887SLiane.Praza@Sun.COM 	val_str[1] = 0;		/* Terminate the string. */
1683*7887SLiane.Praza@Sun.COM 	for (; *seps != 0; seps++) {
1684*7887SLiane.Praza@Sun.COM 		v = internal_value_new();
1685*7887SLiane.Praza@Sun.COM 		v->sc_type = (*p)->sc_value_type;
1686*7887SLiane.Praza@Sun.COM 		v->sc_free = lxml_free_str;
1687*7887SLiane.Praza@Sun.COM 		val_str[0] = *seps;
1688*7887SLiane.Praza@Sun.COM 		v->sc_u.sc_string = strdup(val_str);
1689*7887SLiane.Praza@Sun.COM 		if (v->sc_u.sc_string == NULL)
1690*7887SLiane.Praza@Sun.COM 			uu_die(gettext("Out of memory\n"));
1691*7887SLiane.Praza@Sun.COM 		internal_attach_value(*p, v);
1692*7887SLiane.Praza@Sun.COM 	}
1693*7887SLiane.Praza@Sun.COM }
1694*7887SLiane.Praza@Sun.COM 
1695*7887SLiane.Praza@Sun.COM /*
1696*7887SLiane.Praza@Sun.COM  * Create an internal_separators property and attach it to the property
1697*7887SLiane.Praza@Sun.COM  * group at pg.  The separator characters are provided in the text nodes
1698*7887SLiane.Praza@Sun.COM  * that are the children of seps.  Each separator character is stored as a
1699*7887SLiane.Praza@Sun.COM  * property value in the internal_separators property.
1700*7887SLiane.Praza@Sun.COM  */
1701*7887SLiane.Praza@Sun.COM static int
1702*7887SLiane.Praza@Sun.COM lxml_get_tm_internal_seps(entity_t *service, pgroup_t *pg, xmlNodePtr seps)
1703*7887SLiane.Praza@Sun.COM {
1704*7887SLiane.Praza@Sun.COM 	xmlNodePtr cursor;
1705*7887SLiane.Praza@Sun.COM 	property_t *prop = NULL;
1706*7887SLiane.Praza@Sun.COM 	int r;
1707*7887SLiane.Praza@Sun.COM 
1708*7887SLiane.Praza@Sun.COM 	for (cursor = seps->xmlChildrenNode; cursor != NULL;
1709*7887SLiane.Praza@Sun.COM 	    cursor = cursor->next) {
1710*7887SLiane.Praza@Sun.COM 		if (strcmp("text", (const char *)cursor->name) == 0) {
1711*7887SLiane.Praza@Sun.COM 			seps_to_prop_values(&prop, cursor->content);
1712*7887SLiane.Praza@Sun.COM 		} else if (strcmp("comment", (const char *)cursor->name) != 0) {
1713*7887SLiane.Praza@Sun.COM 			uu_die(gettext("illegal element \"%s\" on %s element "
1714*7887SLiane.Praza@Sun.COM 			    "for \"%s\"\n"), cursor->name, seps->name,
1715*7887SLiane.Praza@Sun.COM 			    service->sc_name);
1716*7887SLiane.Praza@Sun.COM 		}
1717*7887SLiane.Praza@Sun.COM 	}
1718*7887SLiane.Praza@Sun.COM 	if (prop == NULL) {
1719*7887SLiane.Praza@Sun.COM 		semerr(gettext("The %s element in %s had an empty list of "
1720*7887SLiane.Praza@Sun.COM 		    "separators.\n"), (const char *)seps->name,
1721*7887SLiane.Praza@Sun.COM 		    service->sc_name);
1722*7887SLiane.Praza@Sun.COM 		return (-1);
1723*7887SLiane.Praza@Sun.COM 	}
1724*7887SLiane.Praza@Sun.COM 	r = internal_attach_property(pg, prop);
1725*7887SLiane.Praza@Sun.COM 	if (r != 0)
1726*7887SLiane.Praza@Sun.COM 		internal_property_free(prop);
1727*7887SLiane.Praza@Sun.COM 	return (r);
1728*7887SLiane.Praza@Sun.COM }
1729*7887SLiane.Praza@Sun.COM 
17300Sstevel@tonic-gate static int
17310Sstevel@tonic-gate lxml_get_tm_manpage(entity_t *service, xmlNodePtr manpage)
17320Sstevel@tonic-gate {
17330Sstevel@tonic-gate 	pgroup_t *pg;
17340Sstevel@tonic-gate 	char *pgname;
17350Sstevel@tonic-gate 	xmlChar *title;
17360Sstevel@tonic-gate 
17370Sstevel@tonic-gate 	/*
17380Sstevel@tonic-gate 	 * Fetch title attribute, convert to something sanitized, and create
17390Sstevel@tonic-gate 	 * property group.
17400Sstevel@tonic-gate 	 */
1741*7887SLiane.Praza@Sun.COM 	title = xmlGetProp(manpage, (xmlChar *)title_attr);
17420Sstevel@tonic-gate 	pgname = (char *)lxml_label_to_groupname(SCF_PG_TM_MAN_PREFIX,
17430Sstevel@tonic-gate 	    (const char *)title);
1744*7887SLiane.Praza@Sun.COM 	xmlFree(title);
17450Sstevel@tonic-gate 
17460Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(service, pgname,
17470Sstevel@tonic-gate 	    (char *)SCF_GROUP_TEMPLATE);
17480Sstevel@tonic-gate 
17490Sstevel@tonic-gate 	/*
17500Sstevel@tonic-gate 	 * Each attribute is an astring property within the group.
17510Sstevel@tonic-gate 	 */
1752*7887SLiane.Praza@Sun.COM 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_TM_TITLE,
1753*7887SLiane.Praza@Sun.COM 	    SCF_TYPE_ASTRING, manpage, title_attr) != 0 ||
1754*7887SLiane.Praza@Sun.COM 	    new_str_prop_from_attr(pg, SCF_PROPERTY_TM_SECTION,
1755*7887SLiane.Praza@Sun.COM 	    SCF_TYPE_ASTRING, manpage, section_attr) != 0 ||
1756*7887SLiane.Praza@Sun.COM 	    new_str_prop_from_attr(pg, SCF_PROPERTY_TM_MANPATH,
1757*7887SLiane.Praza@Sun.COM 	    SCF_TYPE_ASTRING, manpage, manpath_attr) != 0)
17580Sstevel@tonic-gate 		return (-1);
17590Sstevel@tonic-gate 
17600Sstevel@tonic-gate 	return (0);
17610Sstevel@tonic-gate }
17620Sstevel@tonic-gate 
17630Sstevel@tonic-gate static int
17640Sstevel@tonic-gate lxml_get_tm_doclink(entity_t *service, xmlNodePtr doc_link)
17650Sstevel@tonic-gate {
17660Sstevel@tonic-gate 	pgroup_t *pg;
17670Sstevel@tonic-gate 	char *pgname;
17680Sstevel@tonic-gate 	xmlChar *name;
17690Sstevel@tonic-gate 
17700Sstevel@tonic-gate 	/*
17710Sstevel@tonic-gate 	 * Fetch name attribute, convert name to something sanitized, and create
17720Sstevel@tonic-gate 	 * property group.
17730Sstevel@tonic-gate 	 */
1774*7887SLiane.Praza@Sun.COM 	name = xmlGetProp(doc_link, (xmlChar *)name_attr);
17750Sstevel@tonic-gate 
17760Sstevel@tonic-gate 	pgname = (char *)lxml_label_to_groupname(SCF_PG_TM_DOC_PREFIX,
17770Sstevel@tonic-gate 	    (const char *)name);
17780Sstevel@tonic-gate 
17790Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(service, pgname,
17800Sstevel@tonic-gate 	    (char *)SCF_GROUP_TEMPLATE);
1781*7887SLiane.Praza@Sun.COM 	xmlFree(name);
17820Sstevel@tonic-gate 
17830Sstevel@tonic-gate 	/*
17840Sstevel@tonic-gate 	 * Each attribute is an astring property within the group.
17850Sstevel@tonic-gate 	 */
1786*7887SLiane.Praza@Sun.COM 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_TM_NAME, SCF_TYPE_ASTRING,
1787*7887SLiane.Praza@Sun.COM 	    doc_link, name_attr) != 0 ||
1788*7887SLiane.Praza@Sun.COM 	    new_str_prop_from_attr(pg, SCF_PROPERTY_TM_URI, SCF_TYPE_ASTRING,
1789*7887SLiane.Praza@Sun.COM 	    doc_link, uri_attr) != 0)
17900Sstevel@tonic-gate 		return (-1);
17910Sstevel@tonic-gate 
17920Sstevel@tonic-gate 	return (0);
17930Sstevel@tonic-gate }
17940Sstevel@tonic-gate 
17950Sstevel@tonic-gate static int
17960Sstevel@tonic-gate lxml_get_tm_documentation(entity_t *service, xmlNodePtr documentation)
17970Sstevel@tonic-gate {
17980Sstevel@tonic-gate 	xmlNodePtr cursor;
17990Sstevel@tonic-gate 
18000Sstevel@tonic-gate 	for (cursor = documentation->xmlChildrenNode; cursor != NULL;
18010Sstevel@tonic-gate 	    cursor = cursor->next) {
18020Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
18030Sstevel@tonic-gate 			continue;
18040Sstevel@tonic-gate 
18050Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
18060Sstevel@tonic-gate 		case SC_MANPAGE:
18070Sstevel@tonic-gate 			(void) lxml_get_tm_manpage(service, cursor);
18080Sstevel@tonic-gate 			break;
18090Sstevel@tonic-gate 		case SC_DOC_LINK:
18100Sstevel@tonic-gate 			(void) lxml_get_tm_doclink(service, cursor);
18110Sstevel@tonic-gate 			break;
18120Sstevel@tonic-gate 		default:
18130Sstevel@tonic-gate 			uu_die(gettext("illegal element \"%s\" on template "
18140Sstevel@tonic-gate 			    "for service \"%s\"\n"),
18150Sstevel@tonic-gate 			    cursor->name, service->sc_name);
18160Sstevel@tonic-gate 		}
18170Sstevel@tonic-gate 	}
18180Sstevel@tonic-gate 
18190Sstevel@tonic-gate 	return (0);
18200Sstevel@tonic-gate }
18210Sstevel@tonic-gate 
18220Sstevel@tonic-gate static int
1823*7887SLiane.Praza@Sun.COM lxml_get_prop_pattern_attributes(pgroup_t *pg, xmlNodePtr cursor)
1824*7887SLiane.Praza@Sun.COM {
1825*7887SLiane.Praza@Sun.COM 	if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_TM_NAME,
1826*7887SLiane.Praza@Sun.COM 	    SCF_TYPE_ASTRING, cursor, name_attr, NULL) != 0) {
1827*7887SLiane.Praza@Sun.COM 		return (-1);
1828*7887SLiane.Praza@Sun.COM 	}
1829*7887SLiane.Praza@Sun.COM 	if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_TM_TYPE,
1830*7887SLiane.Praza@Sun.COM 	    SCF_TYPE_ASTRING, cursor, type_attr, "") != 0) {
1831*7887SLiane.Praza@Sun.COM 		return (-1);
1832*7887SLiane.Praza@Sun.COM 	}
1833*7887SLiane.Praza@Sun.COM 	if (new_bool_prop_from_attr(pg, SCF_PROPERTY_TM_REQUIRED, cursor,
1834*7887SLiane.Praza@Sun.COM 	    required_attr) != 0)
1835*7887SLiane.Praza@Sun.COM 		return (-1);
1836*7887SLiane.Praza@Sun.COM 	return (0);
1837*7887SLiane.Praza@Sun.COM }
1838*7887SLiane.Praza@Sun.COM 
1839*7887SLiane.Praza@Sun.COM static int
1840*7887SLiane.Praza@Sun.COM lxml_get_tm_include_values(entity_t *service, pgroup_t *pg,
1841*7887SLiane.Praza@Sun.COM     xmlNodePtr include_values, const char *prop_name)
1842*7887SLiane.Praza@Sun.COM {
1843*7887SLiane.Praza@Sun.COM 	boolean_t attach_to_pg = B_FALSE;
1844*7887SLiane.Praza@Sun.COM 	property_t *p;
1845*7887SLiane.Praza@Sun.COM 	int r = 0;
1846*7887SLiane.Praza@Sun.COM 	char *type;
1847*7887SLiane.Praza@Sun.COM 
1848*7887SLiane.Praza@Sun.COM 	/* Get the type attribute of the include_values element. */
1849*7887SLiane.Praza@Sun.COM 	type = (char *)xmlGetProp(include_values, (const xmlChar *)type_attr);
1850*7887SLiane.Praza@Sun.COM 	if ((type == NULL) || (*type == 0)) {
1851*7887SLiane.Praza@Sun.COM 		uu_die(gettext("%s element requires a %s attribute in the %s "
1852*7887SLiane.Praza@Sun.COM 		    "service.\n"), include_values->name, type_attr,
1853*7887SLiane.Praza@Sun.COM 		    service->sc_name);
1854*7887SLiane.Praza@Sun.COM 	}
1855*7887SLiane.Praza@Sun.COM 
1856*7887SLiane.Praza@Sun.COM 	/* Add the type to the values of the prop_name property. */
1857*7887SLiane.Praza@Sun.COM 	p = internal_property_find(pg, prop_name);
1858*7887SLiane.Praza@Sun.COM 	if (p == NULL)
1859*7887SLiane.Praza@Sun.COM 		attach_to_pg = B_TRUE;
1860*7887SLiane.Praza@Sun.COM 	astring_prop_value(&p, prop_name, type, B_FALSE);
1861*7887SLiane.Praza@Sun.COM 	if (attach_to_pg == B_TRUE) {
1862*7887SLiane.Praza@Sun.COM 		r = internal_attach_property(pg, p);
1863*7887SLiane.Praza@Sun.COM 		if (r != 0)
1864*7887SLiane.Praza@Sun.COM 			internal_property_free(p);
1865*7887SLiane.Praza@Sun.COM 	}
1866*7887SLiane.Praza@Sun.COM 	return (r);
1867*7887SLiane.Praza@Sun.COM }
1868*7887SLiane.Praza@Sun.COM 
1869*7887SLiane.Praza@Sun.COM #define	RC_MIN		0
1870*7887SLiane.Praza@Sun.COM #define	RC_MAX		1
1871*7887SLiane.Praza@Sun.COM #define	RC_COUNT	2
1872*7887SLiane.Praza@Sun.COM 
1873*7887SLiane.Praza@Sun.COM /*
1874*7887SLiane.Praza@Sun.COM  * Verify that the strings at min and max are valid numeric strings.  Also
1875*7887SLiane.Praza@Sun.COM  * verify that max is numerically >= min.
1876*7887SLiane.Praza@Sun.COM  *
1877*7887SLiane.Praza@Sun.COM  * 0 is returned if the range is valid, and -1 is returned if it is not.
1878*7887SLiane.Praza@Sun.COM  */
1879*7887SLiane.Praza@Sun.COM static int
1880*7887SLiane.Praza@Sun.COM verify_range(entity_t *service, xmlNodePtr range, char *min, char *max)
1881*7887SLiane.Praza@Sun.COM {
1882*7887SLiane.Praza@Sun.COM 	char *c;
1883*7887SLiane.Praza@Sun.COM 	int i;
1884*7887SLiane.Praza@Sun.COM 	int is_signed = 0;
1885*7887SLiane.Praza@Sun.COM 	int inverted = 0;
1886*7887SLiane.Praza@Sun.COM 	const char *limit[RC_COUNT];
1887*7887SLiane.Praza@Sun.COM 	char *strings[RC_COUNT];
1888*7887SLiane.Praza@Sun.COM 	uint64_t urange[RC_COUNT];	/* unsigned range. */
1889*7887SLiane.Praza@Sun.COM 	int64_t srange[RC_COUNT];	/* signed range. */
1890*7887SLiane.Praza@Sun.COM 
1891*7887SLiane.Praza@Sun.COM 	strings[RC_MIN] = min;
1892*7887SLiane.Praza@Sun.COM 	strings[RC_MAX] = max;
1893*7887SLiane.Praza@Sun.COM 	limit[RC_MIN] = min_attr;
1894*7887SLiane.Praza@Sun.COM 	limit[RC_MAX] = max_attr;
1895*7887SLiane.Praza@Sun.COM 
1896*7887SLiane.Praza@Sun.COM 	/* See if the range is signed. */
1897*7887SLiane.Praza@Sun.COM 	for (i = 0; (i < RC_COUNT) && (is_signed == 0); i++) {
1898*7887SLiane.Praza@Sun.COM 		c = strings[i];
1899*7887SLiane.Praza@Sun.COM 		while (isspace(*c)) {
1900*7887SLiane.Praza@Sun.COM 			c++;
1901*7887SLiane.Praza@Sun.COM 		}
1902*7887SLiane.Praza@Sun.COM 		if (*c == '-')
1903*7887SLiane.Praza@Sun.COM 			is_signed = 1;
1904*7887SLiane.Praza@Sun.COM 	}
1905*7887SLiane.Praza@Sun.COM 
1906*7887SLiane.Praza@Sun.COM 	/* Attempt to convert the strings. */
1907*7887SLiane.Praza@Sun.COM 	for (i = 0; i < RC_COUNT; i++) {
1908*7887SLiane.Praza@Sun.COM 		errno = 0;
1909*7887SLiane.Praza@Sun.COM 		if (is_signed) {
1910*7887SLiane.Praza@Sun.COM 			srange[i] = strtoll(strings[i], &c, 0);
1911*7887SLiane.Praza@Sun.COM 		} else {
1912*7887SLiane.Praza@Sun.COM 			urange[i] = strtoull(strings[i], &c, 0);
1913*7887SLiane.Praza@Sun.COM 		}
1914*7887SLiane.Praza@Sun.COM 		if ((errno != 0) || (c == strings[i]) || (*c != 0)) {
1915*7887SLiane.Praza@Sun.COM 			/* Conversion failed. */
1916*7887SLiane.Praza@Sun.COM 			uu_die(gettext("Unable to convert %s for the %s "
1917*7887SLiane.Praza@Sun.COM 			    "element in service %s.\n"), limit[i],
1918*7887SLiane.Praza@Sun.COM 			    (char *)range->name, service->sc_name);
1919*7887SLiane.Praza@Sun.COM 		}
1920*7887SLiane.Praza@Sun.COM 	}
1921*7887SLiane.Praza@Sun.COM 
1922*7887SLiane.Praza@Sun.COM 	/* Make sure that min is <= max */
1923*7887SLiane.Praza@Sun.COM 	if (is_signed) {
1924*7887SLiane.Praza@Sun.COM 		if (srange[RC_MAX] < srange[RC_MIN])
1925*7887SLiane.Praza@Sun.COM 			inverted = 1;
1926*7887SLiane.Praza@Sun.COM 	} else {
1927*7887SLiane.Praza@Sun.COM 		if (urange[RC_MAX] < urange[RC_MIN])
1928*7887SLiane.Praza@Sun.COM 			inverted = 1;
1929*7887SLiane.Praza@Sun.COM 	}
1930*7887SLiane.Praza@Sun.COM 	if (inverted != 0) {
1931*7887SLiane.Praza@Sun.COM 		semerr(gettext("Maximum less than minimum for the %s element "
1932*7887SLiane.Praza@Sun.COM 		    "in service %s.\n"), (char *)range->name,
1933*7887SLiane.Praza@Sun.COM 		    service->sc_name);
1934*7887SLiane.Praza@Sun.COM 		return (-1);
1935*7887SLiane.Praza@Sun.COM 	}
1936*7887SLiane.Praza@Sun.COM 
1937*7887SLiane.Praza@Sun.COM 	return (0);
1938*7887SLiane.Praza@Sun.COM }
1939*7887SLiane.Praza@Sun.COM 
1940*7887SLiane.Praza@Sun.COM /*
1941*7887SLiane.Praza@Sun.COM  * This, function creates a property named prop_name.  The range element
1942*7887SLiane.Praza@Sun.COM  * should have two attributes -- min and max.  The property value then
1943*7887SLiane.Praza@Sun.COM  * becomes the concatenation of their value separated by a comma.  The
1944*7887SLiane.Praza@Sun.COM  * property is then attached to the property group at pg.
1945*7887SLiane.Praza@Sun.COM  *
1946*7887SLiane.Praza@Sun.COM  * If pg already contains a property with a name of prop_name, it is only
1947*7887SLiane.Praza@Sun.COM  * necessary to create a new value and attach it to the existing property.
1948*7887SLiane.Praza@Sun.COM  */
1949*7887SLiane.Praza@Sun.COM static int
1950*7887SLiane.Praza@Sun.COM lxml_get_tm_range(entity_t *service, pgroup_t *pg, xmlNodePtr range,
1951*7887SLiane.Praza@Sun.COM     const char *prop_name)
1952*7887SLiane.Praza@Sun.COM {
1953*7887SLiane.Praza@Sun.COM 	boolean_t attach_to_pg = B_FALSE;
1954*7887SLiane.Praza@Sun.COM 	char *max;
1955*7887SLiane.Praza@Sun.COM 	char *min;
1956*7887SLiane.Praza@Sun.COM 	property_t *p;
1957*7887SLiane.Praza@Sun.COM 	char *prop_value;
1958*7887SLiane.Praza@Sun.COM 	int r = 0;
1959*7887SLiane.Praza@Sun.COM 
1960*7887SLiane.Praza@Sun.COM 	/* Get max and min from the XML description. */
1961*7887SLiane.Praza@Sun.COM 	max = (char *)xmlGetProp(range, (xmlChar *)max_attr);
1962*7887SLiane.Praza@Sun.COM 	if ((max == NULL) || (*max == 0)) {
1963*7887SLiane.Praza@Sun.COM 		uu_die(gettext("%s element is missing the %s attribute in "
1964*7887SLiane.Praza@Sun.COM 		    "service %s.\n"), (char *)range->name, max_attr,
1965*7887SLiane.Praza@Sun.COM 		    service->sc_name);
1966*7887SLiane.Praza@Sun.COM 	}
1967*7887SLiane.Praza@Sun.COM 	min = (char *)xmlGetProp(range, (xmlChar *)min_attr);
1968*7887SLiane.Praza@Sun.COM 	if ((min == NULL) || (*min == 0)) {
1969*7887SLiane.Praza@Sun.COM 		uu_die(gettext("%s element is missing the %s attribute in "
1970*7887SLiane.Praza@Sun.COM 		    "service %s.\n"), (char *)range->name, min_attr,
1971*7887SLiane.Praza@Sun.COM 		    service->sc_name);
1972*7887SLiane.Praza@Sun.COM 	}
1973*7887SLiane.Praza@Sun.COM 	if (verify_range(service, range, min, max) != 0) {
1974*7887SLiane.Praza@Sun.COM 		xmlFree(min);
1975*7887SLiane.Praza@Sun.COM 		xmlFree(max);
1976*7887SLiane.Praza@Sun.COM 		return (-1);
1977*7887SLiane.Praza@Sun.COM 	}
1978*7887SLiane.Praza@Sun.COM 
1979*7887SLiane.Praza@Sun.COM 	/* Property value is concatenation of min and max. */
1980*7887SLiane.Praza@Sun.COM 	prop_value = safe_malloc(max_scf_value_len + 1);
1981*7887SLiane.Praza@Sun.COM 	if (snprintf(prop_value, max_scf_value_len + 1, "%s,%s", min, max) >=
1982*7887SLiane.Praza@Sun.COM 	    max_scf_value_len + 1) {
1983*7887SLiane.Praza@Sun.COM 		uu_die(gettext("min and max are too long for the %s element "
1984*7887SLiane.Praza@Sun.COM 		    "of %s.\n"), (char *)range->name, service->sc_name);
1985*7887SLiane.Praza@Sun.COM 	}
1986*7887SLiane.Praza@Sun.COM 	xmlFree(min);
1987*7887SLiane.Praza@Sun.COM 	xmlFree(max);
1988*7887SLiane.Praza@Sun.COM 
1989*7887SLiane.Praza@Sun.COM 	/*
1990*7887SLiane.Praza@Sun.COM 	 * If necessary create the property and attach it to the property
1991*7887SLiane.Praza@Sun.COM 	 * group.
1992*7887SLiane.Praza@Sun.COM 	 */
1993*7887SLiane.Praza@Sun.COM 	p = internal_property_find(pg, prop_name);
1994*7887SLiane.Praza@Sun.COM 	if (p == NULL)
1995*7887SLiane.Praza@Sun.COM 		attach_to_pg = B_TRUE;
1996*7887SLiane.Praza@Sun.COM 	astring_prop_value(&p, prop_name, prop_value, B_TRUE);
1997*7887SLiane.Praza@Sun.COM 	if (attach_to_pg == B_TRUE) {
1998*7887SLiane.Praza@Sun.COM 		r = internal_attach_property(pg, p);
1999*7887SLiane.Praza@Sun.COM 		if (r != 0) {
2000*7887SLiane.Praza@Sun.COM 			internal_property_free(p);
2001*7887SLiane.Praza@Sun.COM 		}
2002*7887SLiane.Praza@Sun.COM 	}
2003*7887SLiane.Praza@Sun.COM 	return (r);
2004*7887SLiane.Praza@Sun.COM }
2005*7887SLiane.Praza@Sun.COM 
2006*7887SLiane.Praza@Sun.COM /*
2007*7887SLiane.Praza@Sun.COM  * Determine how many plain characters are represented by count Base32
2008*7887SLiane.Praza@Sun.COM  * encoded characters.  5 plain text characters are converted to 8 Base32
2009*7887SLiane.Praza@Sun.COM  * characters.
2010*7887SLiane.Praza@Sun.COM  */
2011*7887SLiane.Praza@Sun.COM static size_t
2012*7887SLiane.Praza@Sun.COM encoded_count_to_plain(size_t count)
2013*7887SLiane.Praza@Sun.COM {
2014*7887SLiane.Praza@Sun.COM 	return (5 * ((count + 7) / 8));
2015*7887SLiane.Praza@Sun.COM }
2016*7887SLiane.Praza@Sun.COM 
2017*7887SLiane.Praza@Sun.COM /*
2018*7887SLiane.Praza@Sun.COM  * The value element contains 0 or 1 common_name element followed by 0 or 1
2019*7887SLiane.Praza@Sun.COM  * description element.  It also has a required attribute called "name".
2020*7887SLiane.Praza@Sun.COM  * The common_name and description are stored as property values in pg.
2021*7887SLiane.Praza@Sun.COM  * The property names are:
2022*7887SLiane.Praza@Sun.COM  *	value_<name>_common_name_<lang>
2023*7887SLiane.Praza@Sun.COM  *	value_<name>_description_<lang>
2024*7887SLiane.Praza@Sun.COM  *
2025*7887SLiane.Praza@Sun.COM  * The <name> portion of the preceeding proper names requires more
2026*7887SLiane.Praza@Sun.COM  * explanation.  Ideally it would just the name attribute of this value
2027*7887SLiane.Praza@Sun.COM  * element.  Unfortunately, the name attribute can contain characters that
2028*7887SLiane.Praza@Sun.COM  * are not legal in a property name.  Thus, we base 32 encode the name
2029*7887SLiane.Praza@Sun.COM  * attribute and use that for <name>.
2030*7887SLiane.Praza@Sun.COM  *
2031*7887SLiane.Praza@Sun.COM  * There are cases where the caller needs to know the name, so it is
2032*7887SLiane.Praza@Sun.COM  * returned through the name_value pointer if it is not NULL.
2033*7887SLiane.Praza@Sun.COM  *
2034*7887SLiane.Praza@Sun.COM  * Parameters:
2035*7887SLiane.Praza@Sun.COM  *	service -	Information about the service that is being
2036*7887SLiane.Praza@Sun.COM  *			processed.  This function only uses this parameter
2037*7887SLiane.Praza@Sun.COM  *			for producing error messages.
2038*7887SLiane.Praza@Sun.COM  *
2039*7887SLiane.Praza@Sun.COM  *	pg -		The property group to receive the newly created
2040*7887SLiane.Praza@Sun.COM  *			properties.
2041*7887SLiane.Praza@Sun.COM  *
2042*7887SLiane.Praza@Sun.COM  *	value -		Pointer to the value element in the XML tree.
2043*7887SLiane.Praza@Sun.COM  *
2044*7887SLiane.Praza@Sun.COM  *	name_value -	Address to receive the value of the name attribute.
2045*7887SLiane.Praza@Sun.COM  *			The caller must free the memory.
2046*7887SLiane.Praza@Sun.COM  */
2047*7887SLiane.Praza@Sun.COM static int
2048*7887SLiane.Praza@Sun.COM lxml_get_tm_value_element(entity_t *service, pgroup_t *pg, xmlNodePtr value,
2049*7887SLiane.Praza@Sun.COM     char **name_value)
2050*7887SLiane.Praza@Sun.COM {
2051*7887SLiane.Praza@Sun.COM 	char *common_name_fmt;
2052*7887SLiane.Praza@Sun.COM 	xmlNodePtr cursor;
2053*7887SLiane.Praza@Sun.COM 	char *description_fmt;
2054*7887SLiane.Praza@Sun.COM 	char *encoded_value = NULL;
2055*7887SLiane.Praza@Sun.COM 	size_t extra;
2056*7887SLiane.Praza@Sun.COM 	char *value_name;
2057*7887SLiane.Praza@Sun.COM 	int r = 0;
2058*7887SLiane.Praza@Sun.COM 
2059*7887SLiane.Praza@Sun.COM 	common_name_fmt = safe_malloc(max_scf_name_len + 1);
2060*7887SLiane.Praza@Sun.COM 	description_fmt = safe_malloc(max_scf_name_len + 1);
2061*7887SLiane.Praza@Sun.COM 
2062*7887SLiane.Praza@Sun.COM 	/*
2063*7887SLiane.Praza@Sun.COM 	 * Get the value of our name attribute, so that we can use it to
2064*7887SLiane.Praza@Sun.COM 	 * construct property names.
2065*7887SLiane.Praza@Sun.COM 	 */
2066*7887SLiane.Praza@Sun.COM 	value_name = (char *)xmlGetProp(value, (xmlChar *)name_attr);
2067*7887SLiane.Praza@Sun.COM 	/* The value name must be present, but it can be empty. */
2068*7887SLiane.Praza@Sun.COM 	if (value_name == NULL) {
2069*7887SLiane.Praza@Sun.COM 		uu_die(gettext("%s element requires a %s attribute in the %s "
2070*7887SLiane.Praza@Sun.COM 		    "service.\n"), (char *)value->name, name_attr,
2071*7887SLiane.Praza@Sun.COM 		    service->sc_name);
2072*7887SLiane.Praza@Sun.COM 	}
2073*7887SLiane.Praza@Sun.COM 
2074*7887SLiane.Praza@Sun.COM 	/*
2075*7887SLiane.Praza@Sun.COM 	 * The value_name may contain characters that are not valid in in a
2076*7887SLiane.Praza@Sun.COM 	 * property name.  So we will encode value_name and then use the
2077*7887SLiane.Praza@Sun.COM 	 * encoded value in the property name.
2078*7887SLiane.Praza@Sun.COM 	 */
2079*7887SLiane.Praza@Sun.COM 	encoded_value = safe_malloc(max_scf_name_len + 1);
2080*7887SLiane.Praza@Sun.COM 	if (scf_encode32(value_name, strlen(value_name), encoded_value,
2081*7887SLiane.Praza@Sun.COM 	    max_scf_name_len + 1, &extra, SCF_ENCODE32_PAD) != 0) {
2082*7887SLiane.Praza@Sun.COM 		extra = encoded_count_to_plain(extra - max_scf_name_len);
2083*7887SLiane.Praza@Sun.COM 		uu_die(gettext("Constructed property name is %u characters "
2084*7887SLiane.Praza@Sun.COM 		    "too long for value \"%s\" in the %s service.\n"),
2085*7887SLiane.Praza@Sun.COM 		    extra, value_name, service->sc_name);
2086*7887SLiane.Praza@Sun.COM 	}
2087*7887SLiane.Praza@Sun.COM 	if ((extra = snprintf(common_name_fmt, max_scf_name_len + 1,
2088*7887SLiane.Praza@Sun.COM 	    VALUE_COMMON_NAME_FMT, SCF_PROPERTY_TM_VALUE_PREFIX,
2089*7887SLiane.Praza@Sun.COM 	    encoded_value)) >= max_scf_name_len + 1) {
2090*7887SLiane.Praza@Sun.COM 		extra = encoded_count_to_plain(extra - max_scf_name_len);
2091*7887SLiane.Praza@Sun.COM 		uu_die(gettext("Name attribute is "
2092*7887SLiane.Praza@Sun.COM 		    "%u characters too long for %s in service %s\n"),
2093*7887SLiane.Praza@Sun.COM 		    extra, (char *)value->name, service->sc_name);
2094*7887SLiane.Praza@Sun.COM 	}
2095*7887SLiane.Praza@Sun.COM 	if ((extra = snprintf(description_fmt, max_scf_name_len + 1,
2096*7887SLiane.Praza@Sun.COM 	    VALUE_DESCRIPTION_FMT, SCF_PROPERTY_TM_VALUE_PREFIX,
2097*7887SLiane.Praza@Sun.COM 	    encoded_value)) >= max_scf_name_len + 1) {
2098*7887SLiane.Praza@Sun.COM 		extra = encoded_count_to_plain(extra - max_scf_name_len);
2099*7887SLiane.Praza@Sun.COM 		uu_die(gettext("Name attribute is "
2100*7887SLiane.Praza@Sun.COM 		    "%u characters too long for %s in service %s\n"),
2101*7887SLiane.Praza@Sun.COM 		    extra, (char *)value->name, service->sc_name);
2102*7887SLiane.Praza@Sun.COM 	}
2103*7887SLiane.Praza@Sun.COM 
2104*7887SLiane.Praza@Sun.COM 	for (cursor = value->xmlChildrenNode;
2105*7887SLiane.Praza@Sun.COM 	    cursor != NULL;
2106*7887SLiane.Praza@Sun.COM 	    cursor = cursor->next) {
2107*7887SLiane.Praza@Sun.COM 		if (lxml_ignorable_block(cursor))
2108*7887SLiane.Praza@Sun.COM 			continue;
2109*7887SLiane.Praza@Sun.COM 		switch (lxml_xlate_element(cursor->name)) {
2110*7887SLiane.Praza@Sun.COM 		case SC_COMMON_NAME:
2111*7887SLiane.Praza@Sun.COM 			r = lxml_get_all_loctext(service, pg, cursor,
2112*7887SLiane.Praza@Sun.COM 			    common_name_fmt, (const char *)cursor->name);
2113*7887SLiane.Praza@Sun.COM 			break;
2114*7887SLiane.Praza@Sun.COM 		case SC_DESCRIPTION:
2115*7887SLiane.Praza@Sun.COM 			r = lxml_get_all_loctext(service, pg, cursor,
2116*7887SLiane.Praza@Sun.COM 			    description_fmt, (const char *)cursor->name);
2117*7887SLiane.Praza@Sun.COM 			break;
2118*7887SLiane.Praza@Sun.COM 		default:
2119*7887SLiane.Praza@Sun.COM 			uu_die(gettext("\"%s\" is an illegal element in %s "
2120*7887SLiane.Praza@Sun.COM 			    "of service %s\n"), (char *)cursor->name,
2121*7887SLiane.Praza@Sun.COM 			    (char *)value->name, service->sc_name);
2122*7887SLiane.Praza@Sun.COM 		}
2123*7887SLiane.Praza@Sun.COM 		if (r != 0)
2124*7887SLiane.Praza@Sun.COM 			break;
2125*7887SLiane.Praza@Sun.COM 	}
2126*7887SLiane.Praza@Sun.COM 
2127*7887SLiane.Praza@Sun.COM 	free(description_fmt);
2128*7887SLiane.Praza@Sun.COM 	free(common_name_fmt);
2129*7887SLiane.Praza@Sun.COM 	if (r == 0) {
2130*7887SLiane.Praza@Sun.COM 		*name_value = safe_strdup(value_name);
2131*7887SLiane.Praza@Sun.COM 	}
2132*7887SLiane.Praza@Sun.COM 	xmlFree(value_name);
2133*7887SLiane.Praza@Sun.COM 	free(encoded_value);
2134*7887SLiane.Praza@Sun.COM 	return (r);
2135*7887SLiane.Praza@Sun.COM }
2136*7887SLiane.Praza@Sun.COM 
2137*7887SLiane.Praza@Sun.COM static int
2138*7887SLiane.Praza@Sun.COM lxml_get_tm_choices(entity_t *service, pgroup_t *pg, xmlNodePtr choices)
2139*7887SLiane.Praza@Sun.COM {
2140*7887SLiane.Praza@Sun.COM 	xmlNodePtr cursor;
2141*7887SLiane.Praza@Sun.COM 	char *name_value;
2142*7887SLiane.Praza@Sun.COM 	property_t *name_prop = NULL;
2143*7887SLiane.Praza@Sun.COM 	int r = 0;
2144*7887SLiane.Praza@Sun.COM 
2145*7887SLiane.Praza@Sun.COM 	for (cursor = choices->xmlChildrenNode;
2146*7887SLiane.Praza@Sun.COM 	    (cursor != NULL) && (r == 0);
2147*7887SLiane.Praza@Sun.COM 	    cursor = cursor->next) {
2148*7887SLiane.Praza@Sun.COM 		if (lxml_ignorable_block(cursor))
2149*7887SLiane.Praza@Sun.COM 			continue;
2150*7887SLiane.Praza@Sun.COM 		switch (lxml_xlate_element(cursor->name)) {
2151*7887SLiane.Praza@Sun.COM 		case SC_INCLUDE_VALUES:
2152*7887SLiane.Praza@Sun.COM 			(void) lxml_get_tm_include_values(service, pg, cursor,
2153*7887SLiane.Praza@Sun.COM 			    SCF_PROPERTY_TM_CHOICES_INCLUDE_VALUES);
2154*7887SLiane.Praza@Sun.COM 			break;
2155*7887SLiane.Praza@Sun.COM 		case SC_RANGE:
2156*7887SLiane.Praza@Sun.COM 			r = lxml_get_tm_range(service, pg, cursor,
2157*7887SLiane.Praza@Sun.COM 			    SCF_PROPERTY_TM_CHOICES_RANGE);
2158*7887SLiane.Praza@Sun.COM 			if (r != 0)
2159*7887SLiane.Praza@Sun.COM 				goto out;
2160*7887SLiane.Praza@Sun.COM 			break;
2161*7887SLiane.Praza@Sun.COM 		case SC_VALUE:
2162*7887SLiane.Praza@Sun.COM 			r = lxml_get_tm_value_element(service, pg, cursor,
2163*7887SLiane.Praza@Sun.COM 			    &name_value);
2164*7887SLiane.Praza@Sun.COM 			if (r == 0) {
2165*7887SLiane.Praza@Sun.COM 				/*
2166*7887SLiane.Praza@Sun.COM 				 * There is no need to free the memory
2167*7887SLiane.Praza@Sun.COM 				 * associated with name_value, because the
2168*7887SLiane.Praza@Sun.COM 				 * property value will end up pointing to
2169*7887SLiane.Praza@Sun.COM 				 * the memory.
2170*7887SLiane.Praza@Sun.COM 				 */
2171*7887SLiane.Praza@Sun.COM 				astring_prop_value(&name_prop,
2172*7887SLiane.Praza@Sun.COM 				    SCF_PROPERTY_TM_CHOICES_NAME, name_value,
2173*7887SLiane.Praza@Sun.COM 				    B_TRUE);
2174*7887SLiane.Praza@Sun.COM 			} else {
2175*7887SLiane.Praza@Sun.COM 				goto out;
2176*7887SLiane.Praza@Sun.COM 			}
2177*7887SLiane.Praza@Sun.COM 			break;
2178*7887SLiane.Praza@Sun.COM 		default:
2179*7887SLiane.Praza@Sun.COM 			uu_die(gettext("%s is an invalid element of "
2180*7887SLiane.Praza@Sun.COM 			    "choices for service %s.\n"),  cursor->name,
2181*7887SLiane.Praza@Sun.COM 			    service->sc_name);
2182*7887SLiane.Praza@Sun.COM 		}
2183*7887SLiane.Praza@Sun.COM 	}
2184*7887SLiane.Praza@Sun.COM 
2185*7887SLiane.Praza@Sun.COM out:
2186*7887SLiane.Praza@Sun.COM 	/* Attach the name property if we created one. */
2187*7887SLiane.Praza@Sun.COM 	if ((r == 0) && (name_prop != NULL)) {
2188*7887SLiane.Praza@Sun.COM 		r = internal_attach_property(pg, name_prop);
2189*7887SLiane.Praza@Sun.COM 	}
2190*7887SLiane.Praza@Sun.COM 	if ((r != 0) && (name_prop != NULL)) {
2191*7887SLiane.Praza@Sun.COM 		internal_property_free(name_prop);
2192*7887SLiane.Praza@Sun.COM 	}
2193*7887SLiane.Praza@Sun.COM 
2194*7887SLiane.Praza@Sun.COM 	return (r);
2195*7887SLiane.Praza@Sun.COM }
2196*7887SLiane.Praza@Sun.COM 
2197*7887SLiane.Praza@Sun.COM static int
2198*7887SLiane.Praza@Sun.COM lxml_get_tm_constraints(entity_t *service, pgroup_t *pg, xmlNodePtr constraints)
2199*7887SLiane.Praza@Sun.COM {
2200*7887SLiane.Praza@Sun.COM 	xmlNodePtr cursor;
2201*7887SLiane.Praza@Sun.COM 	char *name_value;
2202*7887SLiane.Praza@Sun.COM 	property_t *name_prop = NULL;
2203*7887SLiane.Praza@Sun.COM 	int r = 0;
2204*7887SLiane.Praza@Sun.COM 
2205*7887SLiane.Praza@Sun.COM 	for (cursor = constraints->xmlChildrenNode;
2206*7887SLiane.Praza@Sun.COM 	    (cursor != NULL) && (r == 0);
2207*7887SLiane.Praza@Sun.COM 	    cursor = cursor->next) {
2208*7887SLiane.Praza@Sun.COM 		if (lxml_ignorable_block(cursor))
2209*7887SLiane.Praza@Sun.COM 			continue;
2210*7887SLiane.Praza@Sun.COM 		switch (lxml_xlate_element(cursor->name)) {
2211*7887SLiane.Praza@Sun.COM 		case SC_RANGE:
2212*7887SLiane.Praza@Sun.COM 			r = lxml_get_tm_range(service, pg, cursor,
2213*7887SLiane.Praza@Sun.COM 			    SCF_PROPERTY_TM_CONSTRAINT_RANGE);
2214*7887SLiane.Praza@Sun.COM 			if (r != 0)
2215*7887SLiane.Praza@Sun.COM 				goto out;
2216*7887SLiane.Praza@Sun.COM 			break;
2217*7887SLiane.Praza@Sun.COM 		case SC_VALUE:
2218*7887SLiane.Praza@Sun.COM 			r = lxml_get_tm_value_element(service, pg, cursor,
2219*7887SLiane.Praza@Sun.COM 			    &name_value);
2220*7887SLiane.Praza@Sun.COM 			if (r == 0) {
2221*7887SLiane.Praza@Sun.COM 				/*
2222*7887SLiane.Praza@Sun.COM 				 * There is no need to free the memory
2223*7887SLiane.Praza@Sun.COM 				 * associated with name_value, because the
2224*7887SLiane.Praza@Sun.COM 				 * property value will end up pointing to
2225*7887SLiane.Praza@Sun.COM 				 * the memory.
2226*7887SLiane.Praza@Sun.COM 				 */
2227*7887SLiane.Praza@Sun.COM 				astring_prop_value(&name_prop,
2228*7887SLiane.Praza@Sun.COM 				    SCF_PROPERTY_TM_CONSTRAINT_NAME, name_value,
2229*7887SLiane.Praza@Sun.COM 				    B_TRUE);
2230*7887SLiane.Praza@Sun.COM 			} else {
2231*7887SLiane.Praza@Sun.COM 				goto out;
2232*7887SLiane.Praza@Sun.COM 			}
2233*7887SLiane.Praza@Sun.COM 			break;
2234*7887SLiane.Praza@Sun.COM 		default:
2235*7887SLiane.Praza@Sun.COM 			uu_die(gettext("%s is an invalid element of "
2236*7887SLiane.Praza@Sun.COM 			    "constraints for service %s.\n"),  cursor->name,
2237*7887SLiane.Praza@Sun.COM 			    service->sc_name);
2238*7887SLiane.Praza@Sun.COM 		}
2239*7887SLiane.Praza@Sun.COM 	}
2240*7887SLiane.Praza@Sun.COM 
2241*7887SLiane.Praza@Sun.COM out:
2242*7887SLiane.Praza@Sun.COM 	/* Attach the name property if we created one. */
2243*7887SLiane.Praza@Sun.COM 	if ((r == 0) && (name_prop != NULL)) {
2244*7887SLiane.Praza@Sun.COM 		r = internal_attach_property(pg, name_prop);
2245*7887SLiane.Praza@Sun.COM 	}
2246*7887SLiane.Praza@Sun.COM 	if ((r != 0) && (name_prop != NULL)) {
2247*7887SLiane.Praza@Sun.COM 		internal_property_free(name_prop);
2248*7887SLiane.Praza@Sun.COM 	}
2249*7887SLiane.Praza@Sun.COM 
2250*7887SLiane.Praza@Sun.COM 	return (r);
2251*7887SLiane.Praza@Sun.COM }
2252*7887SLiane.Praza@Sun.COM 
2253*7887SLiane.Praza@Sun.COM /*
2254*7887SLiane.Praza@Sun.COM  * The values element contains one or more value elements.
2255*7887SLiane.Praza@Sun.COM  */
2256*7887SLiane.Praza@Sun.COM static int
2257*7887SLiane.Praza@Sun.COM lxml_get_tm_values(entity_t *service, pgroup_t *pg, xmlNodePtr values)
2258*7887SLiane.Praza@Sun.COM {
2259*7887SLiane.Praza@Sun.COM 	xmlNodePtr cursor;
2260*7887SLiane.Praza@Sun.COM 	char *name_value;
2261*7887SLiane.Praza@Sun.COM 	property_t *name_prop = NULL;
2262*7887SLiane.Praza@Sun.COM 	int r = 0;
2263*7887SLiane.Praza@Sun.COM 
2264*7887SLiane.Praza@Sun.COM 	for (cursor = values->xmlChildrenNode;
2265*7887SLiane.Praza@Sun.COM 	    (cursor != NULL) && (r == 0);
2266*7887SLiane.Praza@Sun.COM 	    cursor = cursor->next) {
2267*7887SLiane.Praza@Sun.COM 		if (lxml_ignorable_block(cursor))
2268*7887SLiane.Praza@Sun.COM 			continue;
2269*7887SLiane.Praza@Sun.COM 		if (lxml_xlate_element(cursor->name) != SC_VALUE) {
2270*7887SLiane.Praza@Sun.COM 			uu_die(gettext("\"%s\" is an illegal element in the "
2271*7887SLiane.Praza@Sun.COM 			    "%s element of %s\n"), (char *)cursor->name,
2272*7887SLiane.Praza@Sun.COM 			    (char *)values->name, service->sc_name);
2273*7887SLiane.Praza@Sun.COM 		}
2274*7887SLiane.Praza@Sun.COM 		r = lxml_get_tm_value_element(service, pg, cursor, &name_value);
2275*7887SLiane.Praza@Sun.COM 		if (r == 0) {
2276*7887SLiane.Praza@Sun.COM 			/*
2277*7887SLiane.Praza@Sun.COM 			 * There is no need to free the memory
2278*7887SLiane.Praza@Sun.COM 			 * associated with name_value, because the
2279*7887SLiane.Praza@Sun.COM 			 * property value will end up pointing to
2280*7887SLiane.Praza@Sun.COM 			 * the memory.
2281*7887SLiane.Praza@Sun.COM 			 */
2282*7887SLiane.Praza@Sun.COM 			astring_prop_value(&name_prop,
2283*7887SLiane.Praza@Sun.COM 			    SCF_PROPERTY_TM_VALUES_NAME, name_value,
2284*7887SLiane.Praza@Sun.COM 			    B_TRUE);
2285*7887SLiane.Praza@Sun.COM 		}
2286*7887SLiane.Praza@Sun.COM 	}
2287*7887SLiane.Praza@Sun.COM 
2288*7887SLiane.Praza@Sun.COM 	/* Attach the name property if we created one. */
2289*7887SLiane.Praza@Sun.COM 	if ((r == 0) && (name_prop != NULL)) {
2290*7887SLiane.Praza@Sun.COM 		r = internal_attach_property(pg, name_prop);
2291*7887SLiane.Praza@Sun.COM 	}
2292*7887SLiane.Praza@Sun.COM 	if ((r != 0) && (name_prop != NULL)) {
2293*7887SLiane.Praza@Sun.COM 		internal_property_free(name_prop);
2294*7887SLiane.Praza@Sun.COM 	}
2295*7887SLiane.Praza@Sun.COM 
2296*7887SLiane.Praza@Sun.COM 	return (r);
2297*7887SLiane.Praza@Sun.COM }
2298*7887SLiane.Praza@Sun.COM 
2299*7887SLiane.Praza@Sun.COM /*
2300*7887SLiane.Praza@Sun.COM  * This function processes a prop_pattern element within a pg_pattern XML
2301*7887SLiane.Praza@Sun.COM  * element.  First it creates a property group to hold the prop_pattern
2302*7887SLiane.Praza@Sun.COM  * information.  The name of this property group is the concatenation of:
2303*7887SLiane.Praza@Sun.COM  *	- SCF_PG_TM_PROP_PATTERN_PREFIX
2304*7887SLiane.Praza@Sun.COM  *	- The unique part of the property group name of the enclosing
2305*7887SLiane.Praza@Sun.COM  *	  pg_pattern.  The property group name of the enclosing pg_pattern
2306*7887SLiane.Praza@Sun.COM  *	  is passed to us in pgpat_name.  The unique part, is the part
2307*7887SLiane.Praza@Sun.COM  *	  following SCF_PG_TM_PG_PATTERN_PREFIX.
2308*7887SLiane.Praza@Sun.COM  *	- The name of this prop_pattern element.
2309*7887SLiane.Praza@Sun.COM  *
2310*7887SLiane.Praza@Sun.COM  * After creating the property group, the prop_pattern attributes are saved
2311*7887SLiane.Praza@Sun.COM  * as properties in the PG.  Finally, the prop_pattern elements are
2312*7887SLiane.Praza@Sun.COM  * processed and added to the PG.
2313*7887SLiane.Praza@Sun.COM  */
2314*7887SLiane.Praza@Sun.COM static int
2315*7887SLiane.Praza@Sun.COM lxml_get_tm_prop_pattern(entity_t *service, xmlNodePtr prop_pattern,
2316*7887SLiane.Praza@Sun.COM     const char *pgpat_name)
2317*7887SLiane.Praza@Sun.COM {
2318*7887SLiane.Praza@Sun.COM 	xmlNodePtr cursor;
2319*7887SLiane.Praza@Sun.COM 	int extra;
2320*7887SLiane.Praza@Sun.COM 	pgroup_t *pg;
2321*7887SLiane.Praza@Sun.COM 	property_t *p;
2322*7887SLiane.Praza@Sun.COM 	char *pg_name;
2323*7887SLiane.Praza@Sun.COM 	size_t prefix_len;
2324*7887SLiane.Praza@Sun.COM 	xmlChar *prop_pattern_name;
2325*7887SLiane.Praza@Sun.COM 	int r;
2326*7887SLiane.Praza@Sun.COM 	const char *unique;
2327*7887SLiane.Praza@Sun.COM 	value_t *v;
2328*7887SLiane.Praza@Sun.COM 
2329*7887SLiane.Praza@Sun.COM 	/* Find the unique part of the pg_pattern property group name. */
2330*7887SLiane.Praza@Sun.COM 	prefix_len = strlen(SCF_PG_TM_PG_PAT_BASE);
2331*7887SLiane.Praza@Sun.COM 	assert(strncmp(pgpat_name, SCF_PG_TM_PG_PAT_BASE, prefix_len) == 0);
2332*7887SLiane.Praza@Sun.COM 	unique = pgpat_name + prefix_len;
2333*7887SLiane.Praza@Sun.COM 
2334*7887SLiane.Praza@Sun.COM 	/*
2335*7887SLiane.Praza@Sun.COM 	 * We need to get the value of the name attribute first.  The
2336*7887SLiane.Praza@Sun.COM 	 * prop_pattern name as well as the name of the enclosing
2337*7887SLiane.Praza@Sun.COM 	 * pg_pattern both constitute part of the name of the property
2338*7887SLiane.Praza@Sun.COM 	 * group that we will create.
2339*7887SLiane.Praza@Sun.COM 	 */
2340*7887SLiane.Praza@Sun.COM 	prop_pattern_name = xmlGetProp(prop_pattern, (xmlChar *)name_attr);
2341*7887SLiane.Praza@Sun.COM 	if ((prop_pattern_name == NULL) || (*prop_pattern_name == 0)) {
2342*7887SLiane.Praza@Sun.COM 		semerr(gettext("prop_pattern name is missing for %s\n"),
2343*7887SLiane.Praza@Sun.COM 		    service->sc_name);
2344*7887SLiane.Praza@Sun.COM 		return (-1);
2345*7887SLiane.Praza@Sun.COM 	}
2346*7887SLiane.Praza@Sun.COM 	if (uu_check_name((const char *)prop_pattern_name,
2347*7887SLiane.Praza@Sun.COM 	    UU_NAME_DOMAIN) != 0) {
2348*7887SLiane.Praza@Sun.COM 		semerr(gettext("prop_pattern name, \"%s\", for %s is not "
2349*7887SLiane.Praza@Sun.COM 		    "valid.\n"), prop_pattern_name, service->sc_name);
2350*7887SLiane.Praza@Sun.COM 		xmlFree(prop_pattern_name);
2351*7887SLiane.Praza@Sun.COM 		return (-1);
2352*7887SLiane.Praza@Sun.COM 	}
2353*7887SLiane.Praza@Sun.COM 	pg_name = safe_malloc(max_scf_name_len + 1);
2354*7887SLiane.Praza@Sun.COM 	if ((extra = snprintf(pg_name, max_scf_name_len + 1, "%s%s_%s",
2355*7887SLiane.Praza@Sun.COM 	    SCF_PG_TM_PROP_PATTERN_PREFIX, unique,
2356*7887SLiane.Praza@Sun.COM 	    (char *)prop_pattern_name)) >= max_scf_name_len + 1) {
2357*7887SLiane.Praza@Sun.COM 		uu_die(gettext("prop_pattern name, \"%s\", for %s is %d "
2358*7887SLiane.Praza@Sun.COM 		    "characters too long\n"), (char *)prop_pattern_name,
2359*7887SLiane.Praza@Sun.COM 		    service->sc_name, extra - max_scf_name_len);
2360*7887SLiane.Praza@Sun.COM 	}
2361*7887SLiane.Praza@Sun.COM 
2362*7887SLiane.Praza@Sun.COM 	/*
2363*7887SLiane.Praza@Sun.COM 	 * Create the property group, the property referencing the pg_pattern
2364*7887SLiane.Praza@Sun.COM 	 * name, and add the prop_pattern attributes to the property group.
2365*7887SLiane.Praza@Sun.COM 	 */
2366*7887SLiane.Praza@Sun.COM 	pg = internal_pgroup_create_strict(service, pg_name,
2367*7887SLiane.Praza@Sun.COM 	    SCF_GROUP_TEMPLATE_PROP_PATTERN);
2368*7887SLiane.Praza@Sun.COM 	if (pg == NULL) {
2369*7887SLiane.Praza@Sun.COM 		uu_die(gettext("Property group for prop_pattern, \"%s\", "
2370*7887SLiane.Praza@Sun.COM 		    "already exists in %s\n"), prop_pattern_name,
2371*7887SLiane.Praza@Sun.COM 		    service->sc_name);
2372*7887SLiane.Praza@Sun.COM 	}
2373*7887SLiane.Praza@Sun.COM 
2374*7887SLiane.Praza@Sun.COM 	p = internal_property_create(SCF_PROPERTY_TM_PG_PATTERN,
2375*7887SLiane.Praza@Sun.COM 	    SCF_TYPE_ASTRING, 1, safe_strdup(pgpat_name));
2376*7887SLiane.Praza@Sun.COM 	/*
2377*7887SLiane.Praza@Sun.COM 	 * Unfortunately, internal_property_create() does not set the free
2378*7887SLiane.Praza@Sun.COM 	 * function for the value, so we'll set it now.
2379*7887SLiane.Praza@Sun.COM 	 */
2380*7887SLiane.Praza@Sun.COM 	v = uu_list_first(p->sc_property_values);
2381*7887SLiane.Praza@Sun.COM 	v->sc_free = lxml_free_str;
2382*7887SLiane.Praza@Sun.COM 	if (internal_attach_property(pg, p) != 0)
2383*7887SLiane.Praza@Sun.COM 		internal_property_free(p);
2384*7887SLiane.Praza@Sun.COM 
2385*7887SLiane.Praza@Sun.COM 
2386*7887SLiane.Praza@Sun.COM 	r = lxml_get_prop_pattern_attributes(pg, prop_pattern);
2387*7887SLiane.Praza@Sun.COM 	if (r != 0)
2388*7887SLiane.Praza@Sun.COM 		goto out;
2389*7887SLiane.Praza@Sun.COM 
2390*7887SLiane.Praza@Sun.COM 	/*
2391*7887SLiane.Praza@Sun.COM 	 * Now process the elements of prop_pattern
2392*7887SLiane.Praza@Sun.COM 	 */
2393*7887SLiane.Praza@Sun.COM 	for (cursor = prop_pattern->xmlChildrenNode;
2394*7887SLiane.Praza@Sun.COM 	    cursor != NULL;
2395*7887SLiane.Praza@Sun.COM 	    cursor = cursor->next) {
2396*7887SLiane.Praza@Sun.COM 		if (lxml_ignorable_block(cursor))
2397*7887SLiane.Praza@Sun.COM 			continue;
2398*7887SLiane.Praza@Sun.COM 
2399*7887SLiane.Praza@Sun.COM 		switch (lxml_xlate_element(cursor->name)) {
2400*7887SLiane.Praza@Sun.COM 		case SC_CARDINALITY:
2401*7887SLiane.Praza@Sun.COM 			r = lxml_get_tm_cardinality(service, pg, cursor);
2402*7887SLiane.Praza@Sun.COM 			if (r != 0)
2403*7887SLiane.Praza@Sun.COM 				goto out;
2404*7887SLiane.Praza@Sun.COM 			break;
2405*7887SLiane.Praza@Sun.COM 		case SC_CHOICES:
2406*7887SLiane.Praza@Sun.COM 			r = lxml_get_tm_choices(service, pg, cursor);
2407*7887SLiane.Praza@Sun.COM 			if (r != 0)
2408*7887SLiane.Praza@Sun.COM 				goto out;
2409*7887SLiane.Praza@Sun.COM 			break;
2410*7887SLiane.Praza@Sun.COM 		case SC_COMMON_NAME:
2411*7887SLiane.Praza@Sun.COM 			(void) lxml_get_all_loctext(service, pg, cursor,
2412*7887SLiane.Praza@Sun.COM 			    COMMON_NAME_FMT, (const char *)cursor->name);
2413*7887SLiane.Praza@Sun.COM 			break;
2414*7887SLiane.Praza@Sun.COM 		case SC_CONSTRAINTS:
2415*7887SLiane.Praza@Sun.COM 			r = lxml_get_tm_constraints(service, pg, cursor);
2416*7887SLiane.Praza@Sun.COM 			if (r != 0)
2417*7887SLiane.Praza@Sun.COM 				goto out;
2418*7887SLiane.Praza@Sun.COM 			break;
2419*7887SLiane.Praza@Sun.COM 		case SC_DESCRIPTION:
2420*7887SLiane.Praza@Sun.COM 			(void) lxml_get_all_loctext(service, pg, cursor,
2421*7887SLiane.Praza@Sun.COM 			    DESCRIPTION_FMT, (const char *)cursor->name);
2422*7887SLiane.Praza@Sun.COM 			break;
2423*7887SLiane.Praza@Sun.COM 		case SC_INTERNAL_SEPARATORS:
2424*7887SLiane.Praza@Sun.COM 			r = lxml_get_tm_internal_seps(service, pg, cursor);
2425*7887SLiane.Praza@Sun.COM 			if (r != 0)
2426*7887SLiane.Praza@Sun.COM 				goto out;
2427*7887SLiane.Praza@Sun.COM 			break;
2428*7887SLiane.Praza@Sun.COM 		case SC_UNITS:
2429*7887SLiane.Praza@Sun.COM 			(void) lxml_get_all_loctext(service, pg, cursor,
2430*7887SLiane.Praza@Sun.COM 			    UNITS_FMT, "units");
2431*7887SLiane.Praza@Sun.COM 			break;
2432*7887SLiane.Praza@Sun.COM 		case SC_VALUES:
2433*7887SLiane.Praza@Sun.COM 			(void) lxml_get_tm_values(service, pg, cursor);
2434*7887SLiane.Praza@Sun.COM 			break;
2435*7887SLiane.Praza@Sun.COM 		case SC_VISIBILITY:
2436*7887SLiane.Praza@Sun.COM 			/*
2437*7887SLiane.Praza@Sun.COM 			 * The visibility element is empty, so we only need
2438*7887SLiane.Praza@Sun.COM 			 * to proccess the value attribute.
2439*7887SLiane.Praza@Sun.COM 			 */
2440*7887SLiane.Praza@Sun.COM 			(void) new_str_prop_from_attr(pg,
2441*7887SLiane.Praza@Sun.COM 			    SCF_PROPERTY_TM_VISIBILITY, SCF_TYPE_ASTRING,
2442*7887SLiane.Praza@Sun.COM 			    cursor, value_attr);
2443*7887SLiane.Praza@Sun.COM 			break;
2444*7887SLiane.Praza@Sun.COM 		default:
2445*7887SLiane.Praza@Sun.COM 			uu_die(gettext("illegal element \"%s\" in prop_pattern "
2446*7887SLiane.Praza@Sun.COM 			    "for service \"%s\"\n"), cursor->name,
2447*7887SLiane.Praza@Sun.COM 			    service->sc_name);
2448*7887SLiane.Praza@Sun.COM 		}
2449*7887SLiane.Praza@Sun.COM 	}
2450*7887SLiane.Praza@Sun.COM 
2451*7887SLiane.Praza@Sun.COM out:
2452*7887SLiane.Praza@Sun.COM 	xmlFree(prop_pattern_name);
2453*7887SLiane.Praza@Sun.COM 	free(pg_name);
2454*7887SLiane.Praza@Sun.COM 	return (r);
2455*7887SLiane.Praza@Sun.COM }
2456*7887SLiane.Praza@Sun.COM 
2457*7887SLiane.Praza@Sun.COM /*
2458*7887SLiane.Praza@Sun.COM  * Get the pg_pattern attributes and save them as properties in the
2459*7887SLiane.Praza@Sun.COM  * property group at pg.  The pg_pattern element accepts four attributes --
2460*7887SLiane.Praza@Sun.COM  * name, type, required and target.
2461*7887SLiane.Praza@Sun.COM  */
2462*7887SLiane.Praza@Sun.COM static int
2463*7887SLiane.Praza@Sun.COM lxml_get_pg_pattern_attributes(pgroup_t *pg, xmlNodePtr cursor)
2464*7887SLiane.Praza@Sun.COM {
2465*7887SLiane.Praza@Sun.COM 	if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_TM_NAME,
2466*7887SLiane.Praza@Sun.COM 	    SCF_TYPE_ASTRING, cursor, name_attr, NULL) != 0) {
2467*7887SLiane.Praza@Sun.COM 		return (-1);
2468*7887SLiane.Praza@Sun.COM 	}
2469*7887SLiane.Praza@Sun.COM 	if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_TM_TYPE,
2470*7887SLiane.Praza@Sun.COM 	    SCF_TYPE_ASTRING, cursor, type_attr, NULL) != 0) {
2471*7887SLiane.Praza@Sun.COM 		return (-1);
2472*7887SLiane.Praza@Sun.COM 	}
2473*7887SLiane.Praza@Sun.COM 	if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_TM_TARGET,
2474*7887SLiane.Praza@Sun.COM 	    SCF_TYPE_ASTRING, cursor, target_attr, NULL) != 0) {
2475*7887SLiane.Praza@Sun.COM 		return (-1);
2476*7887SLiane.Praza@Sun.COM 	}
2477*7887SLiane.Praza@Sun.COM 	if (new_bool_prop_from_attr(pg, SCF_PROPERTY_TM_REQUIRED, cursor,
2478*7887SLiane.Praza@Sun.COM 	    required_attr) != 0)
2479*7887SLiane.Praza@Sun.COM 		return (-1);
2480*7887SLiane.Praza@Sun.COM 	return (0);
2481*7887SLiane.Praza@Sun.COM }
2482*7887SLiane.Praza@Sun.COM 
2483*7887SLiane.Praza@Sun.COM /*
2484*7887SLiane.Praza@Sun.COM  * There are several restrictions on the pg_pattern attributes that cannot
2485*7887SLiane.Praza@Sun.COM  * be specifed in the service bundle DTD.  This function verifies that
2486*7887SLiane.Praza@Sun.COM  * those restrictions have been satisfied.  The restrictions are:
2487*7887SLiane.Praza@Sun.COM  *
2488*7887SLiane.Praza@Sun.COM  *	- The target attribute may have a value of "instance" only when the
2489*7887SLiane.Praza@Sun.COM  *	  template block is in a service declaration.
2490*7887SLiane.Praza@Sun.COM  *
2491*7887SLiane.Praza@Sun.COM  *	- The target attribute may have a value of "delegate" only when the
2492*7887SLiane.Praza@Sun.COM  *	  template block applies to a restarter.
2493*7887SLiane.Praza@Sun.COM  *
2494*7887SLiane.Praza@Sun.COM  *	- The target attribute may have a value of "all" only when the
2495*7887SLiane.Praza@Sun.COM  *	  template block applies to the master restarter.
2496*7887SLiane.Praza@Sun.COM  *
2497*7887SLiane.Praza@Sun.COM  * The function returns 0 on success and -1 on failure.
2498*7887SLiane.Praza@Sun.COM  */
2499*7887SLiane.Praza@Sun.COM static int
2500*7887SLiane.Praza@Sun.COM verify_pg_pattern_attributes(entity_t *s, pgroup_t *pg)
2501*7887SLiane.Praza@Sun.COM {
2502*7887SLiane.Praza@Sun.COM 	int is_restarter;
2503*7887SLiane.Praza@Sun.COM 	property_t *target;
2504*7887SLiane.Praza@Sun.COM 	value_t *v;
2505*7887SLiane.Praza@Sun.COM 
2506*7887SLiane.Praza@Sun.COM 	/* Find the value of the target property. */
2507*7887SLiane.Praza@Sun.COM 	target = internal_property_find(pg, SCF_PROPERTY_TM_TARGET);
2508*7887SLiane.Praza@Sun.COM 	if (target == NULL) {
2509*7887SLiane.Praza@Sun.COM 		uu_die(gettext("pg_pattern is missing the %s attribute "
2510*7887SLiane.Praza@Sun.COM 		    "in %s\n"), target_attr, s->sc_name);
2511*7887SLiane.Praza@Sun.COM 		return (-1);
2512*7887SLiane.Praza@Sun.COM 	}
2513*7887SLiane.Praza@Sun.COM 	v = uu_list_first(target->sc_property_values);
2514*7887SLiane.Praza@Sun.COM 	assert(v != NULL);
2515*7887SLiane.Praza@Sun.COM 	assert(v->sc_type == SCF_TYPE_ASTRING);
2516*7887SLiane.Praza@Sun.COM 
2517*7887SLiane.Praza@Sun.COM 	/*
2518*7887SLiane.Praza@Sun.COM 	 * If target has a value of instance, the template must be in a
2519*7887SLiane.Praza@Sun.COM 	 * service object.
2520*7887SLiane.Praza@Sun.COM 	 */
2521*7887SLiane.Praza@Sun.COM 	if (strcmp(v->sc_u.sc_string, "instance") == 0) {
2522*7887SLiane.Praza@Sun.COM 		if (s->sc_etype != SVCCFG_SERVICE_OBJECT) {
2523*7887SLiane.Praza@Sun.COM 			uu_warn(gettext("pg_pattern %s attribute may only "
2524*7887SLiane.Praza@Sun.COM 			    "have a value of \"instance\" when it is in a "
2525*7887SLiane.Praza@Sun.COM 			    "service declaration.\n"), target_attr);
2526*7887SLiane.Praza@Sun.COM 			return (-1);
2527*7887SLiane.Praza@Sun.COM 		}
2528*7887SLiane.Praza@Sun.COM 	}
2529*7887SLiane.Praza@Sun.COM 
2530*7887SLiane.Praza@Sun.COM 	/*
2531*7887SLiane.Praza@Sun.COM 	 * If target has a value of "delegate", the template must be in a
2532*7887SLiane.Praza@Sun.COM 	 * restarter.
2533*7887SLiane.Praza@Sun.COM 	 */
2534*7887SLiane.Praza@Sun.COM 	if (strcmp(v->sc_u.sc_string, "delegate") == 0) {
2535*7887SLiane.Praza@Sun.COM 		is_restarter = 0;
2536*7887SLiane.Praza@Sun.COM 		if ((s->sc_etype == SVCCFG_SERVICE_OBJECT) &&
2537*7887SLiane.Praza@Sun.COM 		    (s->sc_u.sc_service.sc_service_type == SVCCFG_RESTARTER)) {
2538*7887SLiane.Praza@Sun.COM 			is_restarter = 1;
2539*7887SLiane.Praza@Sun.COM 		}
2540*7887SLiane.Praza@Sun.COM 		if ((s->sc_etype == SVCCFG_INSTANCE_OBJECT) &&
2541*7887SLiane.Praza@Sun.COM 		    (s->sc_parent->sc_u.sc_service.sc_service_type ==
2542*7887SLiane.Praza@Sun.COM 		    SVCCFG_RESTARTER)) {
2543*7887SLiane.Praza@Sun.COM 			is_restarter = 1;
2544*7887SLiane.Praza@Sun.COM 		}
2545*7887SLiane.Praza@Sun.COM 		if (is_restarter == 0) {
2546*7887SLiane.Praza@Sun.COM 			uu_warn(gettext("pg_pattern %s attribute has a "
2547*7887SLiane.Praza@Sun.COM 			    "value of \"delegate\" but is not in a "
2548*7887SLiane.Praza@Sun.COM 			    "restarter service\n"), target_attr);
2549*7887SLiane.Praza@Sun.COM 			return (-1);
2550*7887SLiane.Praza@Sun.COM 		}
2551*7887SLiane.Praza@Sun.COM 	}
2552*7887SLiane.Praza@Sun.COM 
2553*7887SLiane.Praza@Sun.COM 	/*
2554*7887SLiane.Praza@Sun.COM 	 * If target has a value of "all", the template must be in the
2555*7887SLiane.Praza@Sun.COM 	 * global (SCF_SERVICE_GLOBAL) service.
2556*7887SLiane.Praza@Sun.COM 	 */
2557*7887SLiane.Praza@Sun.COM 	if (strcmp(v->sc_u.sc_string, all_value) == 0) {
2558*7887SLiane.Praza@Sun.COM 		if (s->sc_etype != SVCCFG_SERVICE_OBJECT) {
2559*7887SLiane.Praza@Sun.COM 			uu_warn(gettext("pg_pattern %s attribute has a "
2560*7887SLiane.Praza@Sun.COM 			    "value of \"%s\" but is not in a "
2561*7887SLiane.Praza@Sun.COM 			    "service entity.\n"), target_attr, all_value);
2562*7887SLiane.Praza@Sun.COM 			return (-1);
2563*7887SLiane.Praza@Sun.COM 		}
2564*7887SLiane.Praza@Sun.COM 		if (strcmp(s->sc_fmri, SCF_SERVICE_GLOBAL) != 0) {
2565*7887SLiane.Praza@Sun.COM 			uu_warn(gettext("pg_pattern %s attribute has a "
2566*7887SLiane.Praza@Sun.COM 			    "value of \"%s\" but is in the \"%s\" service.  "
2567*7887SLiane.Praza@Sun.COM 			    "pg_patterns with target \"%s\" are only allowed "
2568*7887SLiane.Praza@Sun.COM 			    "in the global service.\n"),
2569*7887SLiane.Praza@Sun.COM 			    target_attr, all_value, s->sc_fmri, all_value);
2570*7887SLiane.Praza@Sun.COM 			return (-1);
2571*7887SLiane.Praza@Sun.COM 		}
2572*7887SLiane.Praza@Sun.COM 	}
2573*7887SLiane.Praza@Sun.COM 
2574*7887SLiane.Praza@Sun.COM 	return (0);
2575*7887SLiane.Praza@Sun.COM }
2576*7887SLiane.Praza@Sun.COM 
2577*7887SLiane.Praza@Sun.COM static int
2578*7887SLiane.Praza@Sun.COM lxml_get_tm_pg_pattern(entity_t *service, xmlNodePtr pg_pattern)
2579*7887SLiane.Praza@Sun.COM {
2580*7887SLiane.Praza@Sun.COM 	xmlNodePtr cursor;
2581*7887SLiane.Praza@Sun.COM 	int out_len;
2582*7887SLiane.Praza@Sun.COM 	xmlChar *name;
2583*7887SLiane.Praza@Sun.COM 	pgroup_t *pg = NULL;
2584*7887SLiane.Praza@Sun.COM 	char *pg_name;
2585*7887SLiane.Praza@Sun.COM 	int r = -1;
2586*7887SLiane.Praza@Sun.COM 	xmlChar *type;
2587*7887SLiane.Praza@Sun.COM 
2588*7887SLiane.Praza@Sun.COM 	pg_name = safe_malloc(max_scf_name_len + 1);
2589*7887SLiane.Praza@Sun.COM 
2590*7887SLiane.Praza@Sun.COM 	/*
2591*7887SLiane.Praza@Sun.COM 	 * Get the name and type attributes.  Their presence or absence
2592*7887SLiane.Praza@Sun.COM 	 * determines whcih prefix we will use for the property group name.
2593*7887SLiane.Praza@Sun.COM 	 * There are four cases -- neither attribute is present, both are
2594*7887SLiane.Praza@Sun.COM 	 * present, only name is present or only type is present.
2595*7887SLiane.Praza@Sun.COM 	 */
2596*7887SLiane.Praza@Sun.COM 	name = xmlGetProp(pg_pattern, (xmlChar *)name_attr);
2597*7887SLiane.Praza@Sun.COM 	type = xmlGetProp(pg_pattern, (xmlChar *)type_attr);
2598*7887SLiane.Praza@Sun.COM 	if ((name == NULL) || (*name == 0)) {
2599*7887SLiane.Praza@Sun.COM 		if ((type == NULL) || (*type == 0)) {
2600*7887SLiane.Praza@Sun.COM 			/* PG name contains only the prefix in this case */
2601*7887SLiane.Praza@Sun.COM 			if (strlcpy(pg_name, SCF_PG_TM_PG_PATTERN_PREFIX,
2602*7887SLiane.Praza@Sun.COM 			    max_scf_name_len + 1) >= max_scf_name_len + 1) {
2603*7887SLiane.Praza@Sun.COM 				uu_die(gettext("Unable to create pg_pattern "
2604*7887SLiane.Praza@Sun.COM 				    "property for %s\n"), service->sc_name);
2605*7887SLiane.Praza@Sun.COM 			}
2606*7887SLiane.Praza@Sun.COM 		} else {
2607*7887SLiane.Praza@Sun.COM 			/*
2608*7887SLiane.Praza@Sun.COM 			 * If we have a type and no name, the type becomes
2609*7887SLiane.Praza@Sun.COM 			 * part of the pg_pattern property group name.
2610*7887SLiane.Praza@Sun.COM 			 */
2611*7887SLiane.Praza@Sun.COM 			if ((out_len = snprintf(pg_name, max_scf_name_len + 1,
2612*7887SLiane.Praza@Sun.COM 			    "%s%s", SCF_PG_TM_PG_PATTERN_T_PREFIX, type)) >=
2613*7887SLiane.Praza@Sun.COM 			    max_scf_name_len + 1) {
2614*7887SLiane.Praza@Sun.COM 				uu_die(gettext("pg_pattern type is for %s is "
2615*7887SLiane.Praza@Sun.COM 				    "%d bytes too long\n"), service->sc_name,
2616*7887SLiane.Praza@Sun.COM 				    out_len - max_scf_name_len);
2617*7887SLiane.Praza@Sun.COM 			}
2618*7887SLiane.Praza@Sun.COM 		}
2619*7887SLiane.Praza@Sun.COM 	} else {
2620*7887SLiane.Praza@Sun.COM 		const char *prefix;
2621*7887SLiane.Praza@Sun.COM 
2622*7887SLiane.Praza@Sun.COM 		/* Make sure that the name is valid. */
2623*7887SLiane.Praza@Sun.COM 		if (uu_check_name((const char *)name, UU_NAME_DOMAIN) != 0) {
2624*7887SLiane.Praza@Sun.COM 			semerr(gettext("pg_pattern name attribute, \"%s\", "
2625*7887SLiane.Praza@Sun.COM 			    "for %s is invalid\n"), name, service->sc_name);
2626*7887SLiane.Praza@Sun.COM 			goto out;
2627*7887SLiane.Praza@Sun.COM 		}
2628*7887SLiane.Praza@Sun.COM 
2629*7887SLiane.Praza@Sun.COM 		/*
2630*7887SLiane.Praza@Sun.COM 		 * As long as the pg_pattern has a name, it becomes part of
2631*7887SLiane.Praza@Sun.COM 		 * the name of the pg_pattern property group name.  We
2632*7887SLiane.Praza@Sun.COM 		 * merely need to pick the appropriate prefix.
2633*7887SLiane.Praza@Sun.COM 		 */
2634*7887SLiane.Praza@Sun.COM 		if ((type == NULL) || (*type == 0)) {
2635*7887SLiane.Praza@Sun.COM 			prefix = SCF_PG_TM_PG_PATTERN_N_PREFIX;
2636*7887SLiane.Praza@Sun.COM 		} else {
2637*7887SLiane.Praza@Sun.COM 			prefix = SCF_PG_TM_PG_PATTERN_NT_PREFIX;
2638*7887SLiane.Praza@Sun.COM 		}
2639*7887SLiane.Praza@Sun.COM 		if ((out_len = snprintf(pg_name, max_scf_name_len + 1, "%s%s",
2640*7887SLiane.Praza@Sun.COM 		    prefix, name)) >= max_scf_name_len + 1) {
2641*7887SLiane.Praza@Sun.COM 			uu_die(gettext("pg_pattern property group name "
2642*7887SLiane.Praza@Sun.COM 			    "for %s is %d bytes too long\n"), service->sc_name,
2643*7887SLiane.Praza@Sun.COM 			    out_len - max_scf_name_len);
2644*7887SLiane.Praza@Sun.COM 		}
2645*7887SLiane.Praza@Sun.COM 	}
2646*7887SLiane.Praza@Sun.COM 
2647*7887SLiane.Praza@Sun.COM 	/*
2648*7887SLiane.Praza@Sun.COM 	 * Create the property group for holding this pg_pattern
2649*7887SLiane.Praza@Sun.COM 	 * information, and capture the pg_pattern attributes.
2650*7887SLiane.Praza@Sun.COM 	 */
2651*7887SLiane.Praza@Sun.COM 	pg = internal_pgroup_create_strict(service, pg_name,
2652*7887SLiane.Praza@Sun.COM 	    SCF_GROUP_TEMPLATE_PG_PATTERN);
2653*7887SLiane.Praza@Sun.COM 	if (pg == NULL) {
2654*7887SLiane.Praza@Sun.COM 		if ((name == NULL) || (*name == 0)) {
2655*7887SLiane.Praza@Sun.COM 			if ((type == NULL) ||(*type == 0)) {
2656*7887SLiane.Praza@Sun.COM 				semerr(gettext("pg_pattern with empty name and "
2657*7887SLiane.Praza@Sun.COM 				    "type is not unique in %s\n"),
2658*7887SLiane.Praza@Sun.COM 				    service->sc_name);
2659*7887SLiane.Praza@Sun.COM 			} else {
2660*7887SLiane.Praza@Sun.COM 				semerr(gettext("pg_pattern with empty name and "
2661*7887SLiane.Praza@Sun.COM 				    "type \"%s\" is not unique in %s\n"),
2662*7887SLiane.Praza@Sun.COM 				    type, service->sc_name);
2663*7887SLiane.Praza@Sun.COM 			}
2664*7887SLiane.Praza@Sun.COM 		} else {
2665*7887SLiane.Praza@Sun.COM 			if ((type == NULL) || (*type == 0)) {
2666*7887SLiane.Praza@Sun.COM 				semerr(gettext("pg_pattern with name \"%s\" "
2667*7887SLiane.Praza@Sun.COM 				    "and empty type is not unique in %s\n"),
2668*7887SLiane.Praza@Sun.COM 				    name, service->sc_name);
2669*7887SLiane.Praza@Sun.COM 			} else {
2670*7887SLiane.Praza@Sun.COM 				semerr(gettext("pg_pattern with name \"%s\" "
2671*7887SLiane.Praza@Sun.COM 				    "and type \"%s\" is not unique in %s\n"),
2672*7887SLiane.Praza@Sun.COM 				    name, type, service->sc_name);
2673*7887SLiane.Praza@Sun.COM 			}
2674*7887SLiane.Praza@Sun.COM 		}
2675*7887SLiane.Praza@Sun.COM 		goto out;
2676*7887SLiane.Praza@Sun.COM 	}
2677*7887SLiane.Praza@Sun.COM 
2678*7887SLiane.Praza@Sun.COM 	/*
2679*7887SLiane.Praza@Sun.COM 	 * Get the pg_pattern attributes from the manifest and verify
2680*7887SLiane.Praza@Sun.COM 	 * that they satisfy our restrictions.
2681*7887SLiane.Praza@Sun.COM 	 */
2682*7887SLiane.Praza@Sun.COM 	r = lxml_get_pg_pattern_attributes(pg, pg_pattern);
2683*7887SLiane.Praza@Sun.COM 	if (r != 0)
2684*7887SLiane.Praza@Sun.COM 		goto out;
2685*7887SLiane.Praza@Sun.COM 	if (verify_pg_pattern_attributes(service, pg) != 0) {
2686*7887SLiane.Praza@Sun.COM 		semerr(gettext("Invalid pg_pattern attributes in %s\n"),
2687*7887SLiane.Praza@Sun.COM 		    service->sc_name);
2688*7887SLiane.Praza@Sun.COM 		r = -1;
2689*7887SLiane.Praza@Sun.COM 		goto out;
2690*7887SLiane.Praza@Sun.COM 	}
2691*7887SLiane.Praza@Sun.COM 
2692*7887SLiane.Praza@Sun.COM 	/*
2693*7887SLiane.Praza@Sun.COM 	 * Now process all of the elements of pg_pattern.
2694*7887SLiane.Praza@Sun.COM 	 */
2695*7887SLiane.Praza@Sun.COM 	for (cursor = pg_pattern->xmlChildrenNode;
2696*7887SLiane.Praza@Sun.COM 	    cursor != NULL;
2697*7887SLiane.Praza@Sun.COM 	    cursor = cursor->next) {
2698*7887SLiane.Praza@Sun.COM 		if (lxml_ignorable_block(cursor))
2699*7887SLiane.Praza@Sun.COM 			continue;
2700*7887SLiane.Praza@Sun.COM 
2701*7887SLiane.Praza@Sun.COM 		switch (lxml_xlate_element(cursor->name)) {
2702*7887SLiane.Praza@Sun.COM 		case SC_COMMON_NAME:
2703*7887SLiane.Praza@Sun.COM 			(void) lxml_get_all_loctext(service, pg, cursor,
2704*7887SLiane.Praza@Sun.COM 			    COMMON_NAME_FMT, (const char *)cursor->name);
2705*7887SLiane.Praza@Sun.COM 			break;
2706*7887SLiane.Praza@Sun.COM 		case SC_DESCRIPTION:
2707*7887SLiane.Praza@Sun.COM 			(void) lxml_get_all_loctext(service, pg, cursor,
2708*7887SLiane.Praza@Sun.COM 			    DESCRIPTION_FMT, (const char *)cursor->name);
2709*7887SLiane.Praza@Sun.COM 			break;
2710*7887SLiane.Praza@Sun.COM 		case SC_PROP_PATTERN:
2711*7887SLiane.Praza@Sun.COM 			r = lxml_get_tm_prop_pattern(service, cursor,
2712*7887SLiane.Praza@Sun.COM 			    pg_name);
2713*7887SLiane.Praza@Sun.COM 			if (r != 0)
2714*7887SLiane.Praza@Sun.COM 				goto out;
2715*7887SLiane.Praza@Sun.COM 			break;
2716*7887SLiane.Praza@Sun.COM 		default:
2717*7887SLiane.Praza@Sun.COM 			uu_die(gettext("illegal element \"%s\" in pg_pattern "
2718*7887SLiane.Praza@Sun.COM 			    "for service \"%s\"\n"), cursor->name,
2719*7887SLiane.Praza@Sun.COM 			    service->sc_name);
2720*7887SLiane.Praza@Sun.COM 		}
2721*7887SLiane.Praza@Sun.COM 	}
2722*7887SLiane.Praza@Sun.COM 
2723*7887SLiane.Praza@Sun.COM out:
2724*7887SLiane.Praza@Sun.COM 	if ((r != 0) && (pg != NULL)) {
2725*7887SLiane.Praza@Sun.COM 		internal_detach_pgroup(service, pg);
2726*7887SLiane.Praza@Sun.COM 		internal_pgroup_free(pg);
2727*7887SLiane.Praza@Sun.COM 	}
2728*7887SLiane.Praza@Sun.COM 	free(pg_name);
2729*7887SLiane.Praza@Sun.COM 	xmlFree(name);
2730*7887SLiane.Praza@Sun.COM 	xmlFree(type);
2731*7887SLiane.Praza@Sun.COM 
2732*7887SLiane.Praza@Sun.COM 	return (r);
2733*7887SLiane.Praza@Sun.COM }
2734*7887SLiane.Praza@Sun.COM 
2735*7887SLiane.Praza@Sun.COM static int
27360Sstevel@tonic-gate lxml_get_template(entity_t *service, xmlNodePtr templ)
27370Sstevel@tonic-gate {
27380Sstevel@tonic-gate 	xmlNodePtr cursor;
27390Sstevel@tonic-gate 
27400Sstevel@tonic-gate 	for (cursor = templ->xmlChildrenNode; cursor != NULL;
27410Sstevel@tonic-gate 	    cursor = cursor->next) {
27420Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
27430Sstevel@tonic-gate 			continue;
27440Sstevel@tonic-gate 
27450Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
27460Sstevel@tonic-gate 		case SC_COMMON_NAME:
27470Sstevel@tonic-gate 			(void) lxml_get_tm_common_name(service, cursor);
27480Sstevel@tonic-gate 			break;
27490Sstevel@tonic-gate 		case SC_DESCRIPTION:
27500Sstevel@tonic-gate 			(void) lxml_get_tm_description(service, cursor);
27510Sstevel@tonic-gate 			break;
27520Sstevel@tonic-gate 		case SC_DOCUMENTATION:
27530Sstevel@tonic-gate 			(void) lxml_get_tm_documentation(service, cursor);
27540Sstevel@tonic-gate 			break;
2755*7887SLiane.Praza@Sun.COM 		case SC_PG_PATTERN:
2756*7887SLiane.Praza@Sun.COM 			if (lxml_get_tm_pg_pattern(service, cursor) != 0)
2757*7887SLiane.Praza@Sun.COM 				return (-1);
2758*7887SLiane.Praza@Sun.COM 			break;
27590Sstevel@tonic-gate 		default:
27600Sstevel@tonic-gate 			uu_die(gettext("illegal element \"%s\" on template "
27610Sstevel@tonic-gate 			    "for service \"%s\"\n"),
27620Sstevel@tonic-gate 			    cursor->name, service->sc_name);
27630Sstevel@tonic-gate 		}
27640Sstevel@tonic-gate 	}
27650Sstevel@tonic-gate 
27660Sstevel@tonic-gate 	return (0);
27670Sstevel@tonic-gate }
27680Sstevel@tonic-gate 
27690Sstevel@tonic-gate static int
27700Sstevel@tonic-gate lxml_get_default_instance(entity_t *service, xmlNodePtr definst)
27710Sstevel@tonic-gate {
27720Sstevel@tonic-gate 	entity_t *i;
27730Sstevel@tonic-gate 	xmlChar *enabled;
27740Sstevel@tonic-gate 	pgroup_t *pg;
27750Sstevel@tonic-gate 	property_t *p;
27760Sstevel@tonic-gate 	char *package;
27770Sstevel@tonic-gate 	uint64_t enabled_val = 0;
27780Sstevel@tonic-gate 
27790Sstevel@tonic-gate 	i = internal_instance_new("default");
27800Sstevel@tonic-gate 
27810Sstevel@tonic-gate 	if ((enabled = xmlGetProp(definst, (xmlChar *)enabled_attr)) != NULL) {
27820Sstevel@tonic-gate 		enabled_val = (strcmp(true, (const char *)enabled) == 0) ?
27830Sstevel@tonic-gate 		    1 : 0;
27840Sstevel@tonic-gate 		xmlFree(enabled);
27850Sstevel@tonic-gate 	}
27860Sstevel@tonic-gate 
27870Sstevel@tonic-gate 	/*
27880Sstevel@tonic-gate 	 * New general property group with enabled boolean property set.
27890Sstevel@tonic-gate 	 */
27900Sstevel@tonic-gate 
27910Sstevel@tonic-gate 	pg = internal_pgroup_new();
27920Sstevel@tonic-gate 	(void) internal_attach_pgroup(i, pg);
27930Sstevel@tonic-gate 
27940Sstevel@tonic-gate 	pg->sc_pgroup_name = (char *)scf_pg_general;
27950Sstevel@tonic-gate 	pg->sc_pgroup_type = (char *)scf_group_framework;
27960Sstevel@tonic-gate 	pg->sc_pgroup_flags = 0;
27970Sstevel@tonic-gate 
27980Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_ENABLED, SCF_TYPE_BOOLEAN, 1,
27990Sstevel@tonic-gate 	    enabled_val);
28000Sstevel@tonic-gate 
28010Sstevel@tonic-gate 	(void) internal_attach_property(pg, p);
28020Sstevel@tonic-gate 
28030Sstevel@tonic-gate 	/*
28040Sstevel@tonic-gate 	 * Add general/package property if PKGINST is set.
28050Sstevel@tonic-gate 	 */
28060Sstevel@tonic-gate 	if ((package = getenv("PKGINST")) != NULL) {
28070Sstevel@tonic-gate 		p = internal_property_create(SCF_PROPERTY_PACKAGE,
28080Sstevel@tonic-gate 		    SCF_TYPE_ASTRING, 1, package);
28090Sstevel@tonic-gate 
28100Sstevel@tonic-gate 		(void) internal_attach_property(pg, p);
28110Sstevel@tonic-gate 	}
28120Sstevel@tonic-gate 
28130Sstevel@tonic-gate 	return (internal_attach_entity(service, i));
28140Sstevel@tonic-gate }
28150Sstevel@tonic-gate 
28160Sstevel@tonic-gate /*
28170Sstevel@tonic-gate  * Translate an instance element into an internal property tree, added to
28185040Swesolows  * service.  If op is SVCCFG_OP_APPLY (i.e., apply a profile), forbid
28195040Swesolows  * subelements and set the enabled property to override.
28200Sstevel@tonic-gate  */
28210Sstevel@tonic-gate static int
28225040Swesolows lxml_get_instance(entity_t *service, xmlNodePtr inst, svccfg_op_t op)
28230Sstevel@tonic-gate {
28240Sstevel@tonic-gate 	entity_t *i;
28250Sstevel@tonic-gate 	pgroup_t *pg;
28260Sstevel@tonic-gate 	property_t *p;
28270Sstevel@tonic-gate 	xmlNodePtr cursor;
28280Sstevel@tonic-gate 	xmlChar *enabled;
28290Sstevel@tonic-gate 	int r;
28300Sstevel@tonic-gate 
28310Sstevel@tonic-gate 	/*
28320Sstevel@tonic-gate 	 * Fetch its attributes, as appropriate.
28330Sstevel@tonic-gate 	 */
28340Sstevel@tonic-gate 	i = internal_instance_new((char *)xmlGetProp(inst,
28350Sstevel@tonic-gate 	    (xmlChar *)name_attr));
28360Sstevel@tonic-gate 
28370Sstevel@tonic-gate 	/*
28380Sstevel@tonic-gate 	 * Note that this must be done before walking the children so that
28390Sstevel@tonic-gate 	 * sc_fmri is set in case we enter lxml_get_dependent().
28400Sstevel@tonic-gate 	 */
28410Sstevel@tonic-gate 	r = internal_attach_entity(service, i);
28420Sstevel@tonic-gate 	if (r != 0)
28430Sstevel@tonic-gate 		return (r);
28440Sstevel@tonic-gate 
28450Sstevel@tonic-gate 	enabled = xmlGetProp(inst, (xmlChar *)enabled_attr);
28460Sstevel@tonic-gate 
28470Sstevel@tonic-gate 	/*
28480Sstevel@tonic-gate 	 * New general property group with enabled boolean property set.
28490Sstevel@tonic-gate 	 */
28500Sstevel@tonic-gate 	pg = internal_pgroup_new();
28510Sstevel@tonic-gate 	(void) internal_attach_pgroup(i, pg);
28520Sstevel@tonic-gate 
28530Sstevel@tonic-gate 	pg->sc_pgroup_name = (char *)scf_pg_general;
28540Sstevel@tonic-gate 	pg->sc_pgroup_type = (char *)scf_group_framework;
28550Sstevel@tonic-gate 	pg->sc_pgroup_flags = 0;
28560Sstevel@tonic-gate 
28570Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_ENABLED, SCF_TYPE_BOOLEAN, 1,
28580Sstevel@tonic-gate 	    (uint64_t)(strcmp(true, (const char *)enabled) == 0 ? 1 : 0));
28590Sstevel@tonic-gate 
28605040Swesolows 	p->sc_property_override = (op == SVCCFG_OP_APPLY);
28610Sstevel@tonic-gate 
28620Sstevel@tonic-gate 	(void) internal_attach_property(pg, p);
28630Sstevel@tonic-gate 
28640Sstevel@tonic-gate 	xmlFree(enabled);
28650Sstevel@tonic-gate 
28660Sstevel@tonic-gate 	/*
28670Sstevel@tonic-gate 	 * Walk its child elements, as appropriate.
28680Sstevel@tonic-gate 	 */
28690Sstevel@tonic-gate 	for (cursor = inst->xmlChildrenNode; cursor != NULL;
28700Sstevel@tonic-gate 	    cursor = cursor->next) {
28710Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
28720Sstevel@tonic-gate 			continue;
28730Sstevel@tonic-gate 
28745040Swesolows 		if (op == SVCCFG_OP_APPLY) {
28750Sstevel@tonic-gate 			semerr(gettext("Instance \"%s\" may not contain "
28760Sstevel@tonic-gate 			    "elements in profiles.\n"), i->sc_name,
28770Sstevel@tonic-gate 			    cursor->name);
28780Sstevel@tonic-gate 			return (-1);
28790Sstevel@tonic-gate 		}
28800Sstevel@tonic-gate 
28810Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
28820Sstevel@tonic-gate 		case SC_RESTARTER:
28830Sstevel@tonic-gate 			(void) lxml_get_restarter(i, cursor);
28840Sstevel@tonic-gate 			break;
28850Sstevel@tonic-gate 		case SC_DEPENDENCY:
28860Sstevel@tonic-gate 			(void) lxml_get_dependency(i, cursor);
28870Sstevel@tonic-gate 			break;
28880Sstevel@tonic-gate 		case SC_DEPENDENT:
28890Sstevel@tonic-gate 			(void) lxml_get_dependent(i, cursor);
28900Sstevel@tonic-gate 			break;
28910Sstevel@tonic-gate 		case SC_METHOD_CONTEXT:
28920Sstevel@tonic-gate 			(void) lxml_get_entity_method_context(i, cursor);
28930Sstevel@tonic-gate 			break;
28940Sstevel@tonic-gate 		case SC_EXEC_METHOD:
28950Sstevel@tonic-gate 			(void) lxml_get_exec_method(i, cursor);
28960Sstevel@tonic-gate 			break;
28970Sstevel@tonic-gate 		case SC_PROPERTY_GROUP:
28980Sstevel@tonic-gate 			(void) lxml_get_pgroup(i, cursor);
28990Sstevel@tonic-gate 			break;
29000Sstevel@tonic-gate 		case SC_TEMPLATE:
2901*7887SLiane.Praza@Sun.COM 			if (lxml_get_template(i, cursor) != 0)
2902*7887SLiane.Praza@Sun.COM 				return (-1);
29030Sstevel@tonic-gate 			break;
29040Sstevel@tonic-gate 		default:
29050Sstevel@tonic-gate 			uu_die(gettext(
29060Sstevel@tonic-gate 			    "illegal element \"%s\" on instance \"%s\"\n"),
29070Sstevel@tonic-gate 			    cursor->name, i->sc_name);
29080Sstevel@tonic-gate 			break;
29090Sstevel@tonic-gate 		}
29100Sstevel@tonic-gate 	}
29110Sstevel@tonic-gate 
29120Sstevel@tonic-gate 	return (0);
29130Sstevel@tonic-gate }
29140Sstevel@tonic-gate 
29150Sstevel@tonic-gate /* ARGSUSED1 */
29160Sstevel@tonic-gate static int
29170Sstevel@tonic-gate lxml_get_single_instance(entity_t *entity, xmlNodePtr si)
29180Sstevel@tonic-gate {
29190Sstevel@tonic-gate 	pgroup_t *pg;
29200Sstevel@tonic-gate 	property_t *p;
29210Sstevel@tonic-gate 	int r;
29220Sstevel@tonic-gate 
29230Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(entity, (char *)scf_pg_general,
29240Sstevel@tonic-gate 	    (char *)scf_group_framework);
29250Sstevel@tonic-gate 
29260Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_SINGLE_INSTANCE,
29270Sstevel@tonic-gate 	    SCF_TYPE_BOOLEAN, 1, (uint64_t)1);
29280Sstevel@tonic-gate 
29290Sstevel@tonic-gate 	r = internal_attach_property(pg, p);
29300Sstevel@tonic-gate 	if (r != 0) {
29310Sstevel@tonic-gate 		internal_property_free(p);
29320Sstevel@tonic-gate 		return (-1);
29330Sstevel@tonic-gate 	}
29340Sstevel@tonic-gate 
29350Sstevel@tonic-gate 	return (0);
29360Sstevel@tonic-gate }
29370Sstevel@tonic-gate 
29380Sstevel@tonic-gate /*
29390Sstevel@tonic-gate  * Translate a service element into an internal instance/property tree, added
29405040Swesolows  * to bundle.  If op is SVCCFG_OP_APPLY, allow only instance subelements.
29410Sstevel@tonic-gate  */
29420Sstevel@tonic-gate static int
29435040Swesolows lxml_get_service(bundle_t *bundle, xmlNodePtr svc, svccfg_op_t op)
29440Sstevel@tonic-gate {
29450Sstevel@tonic-gate 	entity_t *s;
29460Sstevel@tonic-gate 	xmlNodePtr cursor;
29470Sstevel@tonic-gate 	xmlChar *type;
29480Sstevel@tonic-gate 	xmlChar *version;
29490Sstevel@tonic-gate 	int e;
29500Sstevel@tonic-gate 
29510Sstevel@tonic-gate 	/*
29520Sstevel@tonic-gate 	 * Fetch attributes, as appropriate.
29530Sstevel@tonic-gate 	 */
29540Sstevel@tonic-gate 	s = internal_service_new((char *)xmlGetProp(svc,
29550Sstevel@tonic-gate 	    (xmlChar *)name_attr));
29560Sstevel@tonic-gate 
2957*7887SLiane.Praza@Sun.COM 	version = xmlGetProp(svc, (xmlChar *)version_attr);
29580Sstevel@tonic-gate 	s->sc_u.sc_service.sc_service_version = atol((const char *)version);
29590Sstevel@tonic-gate 	xmlFree(version);
29600Sstevel@tonic-gate 
29610Sstevel@tonic-gate 	type = xmlGetProp(svc, (xmlChar *)type_attr);
29620Sstevel@tonic-gate 	s->sc_u.sc_service.sc_service_type = lxml_xlate_service_type(type);
29630Sstevel@tonic-gate 	xmlFree(type);
29640Sstevel@tonic-gate 
29650Sstevel@tonic-gate 	/*
29660Sstevel@tonic-gate 	 * Walk its child elements, as appropriate.
29670Sstevel@tonic-gate 	 */
29680Sstevel@tonic-gate 	for (cursor = svc->xmlChildrenNode; cursor != NULL;
29690Sstevel@tonic-gate 	    cursor = cursor->next) {
29700Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
29710Sstevel@tonic-gate 			continue;
29720Sstevel@tonic-gate 
29730Sstevel@tonic-gate 		e = lxml_xlate_element(cursor->name);
29740Sstevel@tonic-gate 
29755040Swesolows 		if (op == SVCCFG_OP_APPLY && e != SC_INSTANCE) {
29760Sstevel@tonic-gate 			semerr(gettext("Service \"%s\" may not contain the "
29770Sstevel@tonic-gate 			    "non-instance element \"%s\" in a profile.\n"),
29780Sstevel@tonic-gate 			    s->sc_name, cursor->name);
29790Sstevel@tonic-gate 
29800Sstevel@tonic-gate 			return (-1);
29810Sstevel@tonic-gate 		}
29820Sstevel@tonic-gate 
29830Sstevel@tonic-gate 		switch (e) {
29840Sstevel@tonic-gate 		case SC_INSTANCE:
2985*7887SLiane.Praza@Sun.COM 			if (lxml_get_instance(s, cursor, op) != 0)
2986*7887SLiane.Praza@Sun.COM 				return (-1);
29870Sstevel@tonic-gate 			break;
29880Sstevel@tonic-gate 		case SC_TEMPLATE:
2989*7887SLiane.Praza@Sun.COM 			if (lxml_get_template(s, cursor) != 0)
2990*7887SLiane.Praza@Sun.COM 				return (-1);
29910Sstevel@tonic-gate 			break;
29920Sstevel@tonic-gate 		case SC_STABILITY:
29930Sstevel@tonic-gate 			(void) lxml_get_entity_stability(s, cursor);
29940Sstevel@tonic-gate 			break;
29950Sstevel@tonic-gate 		case SC_DEPENDENCY:
29960Sstevel@tonic-gate 			(void) lxml_get_dependency(s, cursor);
29970Sstevel@tonic-gate 			break;
29980Sstevel@tonic-gate 		case SC_DEPENDENT:
29990Sstevel@tonic-gate 			(void) lxml_get_dependent(s, cursor);
30000Sstevel@tonic-gate 			break;
30010Sstevel@tonic-gate 		case SC_RESTARTER:
30020Sstevel@tonic-gate 			(void) lxml_get_restarter(s, cursor);
30030Sstevel@tonic-gate 			break;
30040Sstevel@tonic-gate 		case SC_EXEC_METHOD:
30050Sstevel@tonic-gate 			(void) lxml_get_exec_method(s, cursor);
30060Sstevel@tonic-gate 			break;
30070Sstevel@tonic-gate 		case SC_METHOD_CONTEXT:
30080Sstevel@tonic-gate 			(void) lxml_get_entity_method_context(s, cursor);
30090Sstevel@tonic-gate 			break;
30100Sstevel@tonic-gate 		case SC_PROPERTY_GROUP:
30110Sstevel@tonic-gate 			(void) lxml_get_pgroup(s, cursor);
30120Sstevel@tonic-gate 			break;
30130Sstevel@tonic-gate 		case SC_INSTANCE_CREATE_DEFAULT:
30140Sstevel@tonic-gate 			(void) lxml_get_default_instance(s, cursor);
30150Sstevel@tonic-gate 			break;
30160Sstevel@tonic-gate 		case SC_INSTANCE_SINGLE:
30170Sstevel@tonic-gate 			(void) lxml_get_single_instance(s, cursor);
30180Sstevel@tonic-gate 			break;
30190Sstevel@tonic-gate 		default:
30200Sstevel@tonic-gate 			uu_die(gettext(
30210Sstevel@tonic-gate 			    "illegal element \"%s\" on service \"%s\"\n"),
30220Sstevel@tonic-gate 			    cursor->name, s->sc_name);
30230Sstevel@tonic-gate 			break;
30240Sstevel@tonic-gate 		}
30250Sstevel@tonic-gate 	}
30260Sstevel@tonic-gate 
30270Sstevel@tonic-gate 	return (internal_attach_service(bundle, s));
30280Sstevel@tonic-gate }
30290Sstevel@tonic-gate 
30300Sstevel@tonic-gate #ifdef DEBUG
30310Sstevel@tonic-gate void
30320Sstevel@tonic-gate lxml_dump(int g, xmlNodePtr p)
30330Sstevel@tonic-gate {
30340Sstevel@tonic-gate 	if (p && p->name) {
30350Sstevel@tonic-gate 		printf("%d %s\n", g, p->name);
30360Sstevel@tonic-gate 
30370Sstevel@tonic-gate 		for (p = p->xmlChildrenNode; p != NULL; p = p->next)
30380Sstevel@tonic-gate 			lxml_dump(g + 1, p);
30390Sstevel@tonic-gate 	}
30400Sstevel@tonic-gate }
30410Sstevel@tonic-gate #endif /* DEBUG */
30420Sstevel@tonic-gate 
30430Sstevel@tonic-gate static int
30440Sstevel@tonic-gate lxml_is_known_dtd(const xmlChar *dtdname)
30450Sstevel@tonic-gate {
30460Sstevel@tonic-gate 	if (dtdname == NULL ||
30470Sstevel@tonic-gate 	    strcmp(MANIFEST_DTD_PATH, (const char *)dtdname) != 0)
30480Sstevel@tonic-gate 		return (0);
30490Sstevel@tonic-gate 
30500Sstevel@tonic-gate 	return (1);
30510Sstevel@tonic-gate }
30520Sstevel@tonic-gate 
30530Sstevel@tonic-gate static int
30540Sstevel@tonic-gate lxml_get_bundle(bundle_t *bundle, bundle_type_t bundle_type,
30555040Swesolows     xmlNodePtr subbundle, svccfg_op_t op)
30560Sstevel@tonic-gate {
30570Sstevel@tonic-gate 	xmlNodePtr cursor;
30580Sstevel@tonic-gate 	xmlChar *type;
30590Sstevel@tonic-gate 	int e;
30600Sstevel@tonic-gate 
30610Sstevel@tonic-gate 	/*
30620Sstevel@tonic-gate 	 * 1.  Get bundle attributes.
30630Sstevel@tonic-gate 	 */
3064*7887SLiane.Praza@Sun.COM 	type = xmlGetProp(subbundle, (xmlChar *)type_attr);
30650Sstevel@tonic-gate 	bundle->sc_bundle_type = lxml_xlate_bundle_type(type);
30660Sstevel@tonic-gate 	if (bundle->sc_bundle_type != bundle_type &&
30670Sstevel@tonic-gate 	    bundle_type != SVCCFG_UNKNOWN_BUNDLE) {
30680Sstevel@tonic-gate 		semerr(gettext("included bundle of different type.\n"));
30690Sstevel@tonic-gate 		return (-1);
30700Sstevel@tonic-gate 	}
30710Sstevel@tonic-gate 
30720Sstevel@tonic-gate 	xmlFree(type);
30730Sstevel@tonic-gate 
30745040Swesolows 	switch (op) {
30755040Swesolows 	case SVCCFG_OP_IMPORT:
30760Sstevel@tonic-gate 		if (bundle->sc_bundle_type != SVCCFG_MANIFEST) {
30770Sstevel@tonic-gate 			semerr(gettext("document is not a manifest.\n"));
30780Sstevel@tonic-gate 			return (-1);
30790Sstevel@tonic-gate 		}
30805040Swesolows 		break;
30815040Swesolows 	case SVCCFG_OP_APPLY:
30820Sstevel@tonic-gate 		if (bundle->sc_bundle_type != SVCCFG_PROFILE) {
30830Sstevel@tonic-gate 			semerr(gettext("document is not a profile.\n"));
30840Sstevel@tonic-gate 			return (-1);
30850Sstevel@tonic-gate 		}
30865040Swesolows 		break;
30875040Swesolows 	case SVCCFG_OP_RESTORE:
30885040Swesolows 		if (bundle->sc_bundle_type != SVCCFG_ARCHIVE) {
30895040Swesolows 			semerr(gettext("document is not an archive.\n"));
30905040Swesolows 			return (-1);
30915040Swesolows 		}
30925040Swesolows 		break;
30930Sstevel@tonic-gate 	}
30940Sstevel@tonic-gate 
3095*7887SLiane.Praza@Sun.COM 	if (((bundle->sc_bundle_name = xmlGetProp(subbundle,
3096*7887SLiane.Praza@Sun.COM 	    (xmlChar *)name_attr)) == NULL) || (*bundle->sc_bundle_name == 0)) {
30970Sstevel@tonic-gate 		semerr(gettext("service bundle lacks name attribute\n"));
30980Sstevel@tonic-gate 		return (-1);
30990Sstevel@tonic-gate 	}
31000Sstevel@tonic-gate 
31010Sstevel@tonic-gate 	/*
31020Sstevel@tonic-gate 	 * 2.  Get services, descend into each one and build state.
31030Sstevel@tonic-gate 	 */
31040Sstevel@tonic-gate 	for (cursor = subbundle->xmlChildrenNode; cursor != NULL;
31050Sstevel@tonic-gate 	    cursor = cursor->next) {
31060Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
31070Sstevel@tonic-gate 			continue;
31080Sstevel@tonic-gate 
31090Sstevel@tonic-gate 		e = lxml_xlate_element(cursor->name);
31100Sstevel@tonic-gate 
31110Sstevel@tonic-gate 		switch (e) {
31120Sstevel@tonic-gate 		case SC_XI_INCLUDE:
31130Sstevel@tonic-gate 			continue;
31140Sstevel@tonic-gate 
31150Sstevel@tonic-gate 		case SC_SERVICE_BUNDLE:
31165040Swesolows 			if (lxml_get_bundle(bundle, bundle_type, cursor, op))
31170Sstevel@tonic-gate 				return (-1);
31180Sstevel@tonic-gate 			break;
31190Sstevel@tonic-gate 		case SC_SERVICE:
3120*7887SLiane.Praza@Sun.COM 			if (lxml_get_service(bundle, cursor, op) != 0)
3121*7887SLiane.Praza@Sun.COM 				return (-1);
31220Sstevel@tonic-gate 			break;
31230Sstevel@tonic-gate 		}
31240Sstevel@tonic-gate 	}
31250Sstevel@tonic-gate 
31260Sstevel@tonic-gate 	return (0);
31270Sstevel@tonic-gate }
31280Sstevel@tonic-gate 
31290Sstevel@tonic-gate /*
31300Sstevel@tonic-gate  * Load an XML tree from filename and translate it into an internal service
31315040Swesolows  * tree bundle.  Require that the bundle be of appropriate type for the
31325040Swesolows  * operation: archive for RESTORE, manifest for IMPORT, profile for APPLY.
31330Sstevel@tonic-gate  */
31340Sstevel@tonic-gate int
31355040Swesolows lxml_get_bundle_file(bundle_t *bundle, const char *filename, svccfg_op_t op)
31360Sstevel@tonic-gate {
31370Sstevel@tonic-gate 	xmlDocPtr document;
31380Sstevel@tonic-gate 	xmlNodePtr cursor;
31390Sstevel@tonic-gate 	xmlDtdPtr dtd = NULL;
31400Sstevel@tonic-gate 	xmlValidCtxtPtr vcp;
31410Sstevel@tonic-gate 	boolean_t do_validate;
31420Sstevel@tonic-gate 	char *dtdpath = NULL;
31430Sstevel@tonic-gate 	int r;
31440Sstevel@tonic-gate 
31450Sstevel@tonic-gate 	/*
31464740Sjeanm 	 * Verify we can read the file before we try to parse it.
31474740Sjeanm 	 */
31484740Sjeanm 	if (access(filename, R_OK | F_OK) == -1) {
31494740Sjeanm 		semerr(gettext("unable to open file: %s\n"), strerror(errno));
31504740Sjeanm 		return (-1);
31514740Sjeanm 	}
31524740Sjeanm 
31534740Sjeanm 	/*
31540Sstevel@tonic-gate 	 * Until libxml2 addresses DTD-based validation with XInclude, we don't
31550Sstevel@tonic-gate 	 * validate service profiles (i.e. the apply path).
31560Sstevel@tonic-gate 	 */
31575040Swesolows 	do_validate = (op != SVCCFG_OP_APPLY) &&
31585040Swesolows 	    (getenv("SVCCFG_NOVALIDATE") == NULL);
31590Sstevel@tonic-gate 	if (do_validate)
31600Sstevel@tonic-gate 		dtdpath = getenv("SVCCFG_DTD");
31610Sstevel@tonic-gate 
31620Sstevel@tonic-gate 	if (dtdpath != NULL)
31630Sstevel@tonic-gate 		xmlLoadExtDtdDefaultValue = 0;
31640Sstevel@tonic-gate 
31654740Sjeanm 	if ((document = xmlReadFile(filename, NULL, 0)) == NULL) {
31660Sstevel@tonic-gate 		semerr(gettext("couldn't parse document\n"));
31670Sstevel@tonic-gate 		return (-1);
31680Sstevel@tonic-gate 	}
31690Sstevel@tonic-gate 
31700Sstevel@tonic-gate 	/*
31710Sstevel@tonic-gate 	 * Verify that this is a document type we understand.
31720Sstevel@tonic-gate 	 */
31730Sstevel@tonic-gate 	if ((dtd = xmlGetIntSubset(document)) == NULL) {
31740Sstevel@tonic-gate 		semerr(gettext("document has no DTD\n"));
31750Sstevel@tonic-gate 		return (-1);
31760Sstevel@tonic-gate 	}
31770Sstevel@tonic-gate 
31780Sstevel@tonic-gate 	if (!lxml_is_known_dtd(dtd->SystemID)) {
31790Sstevel@tonic-gate 		semerr(gettext("document DTD unknown; not service bundle?\n"));
31800Sstevel@tonic-gate 		return (-1);
31810Sstevel@tonic-gate 	}
31820Sstevel@tonic-gate 
31830Sstevel@tonic-gate 	if ((cursor = xmlDocGetRootElement(document)) == NULL) {
31840Sstevel@tonic-gate 		semerr(gettext("document is empty\n"));
31850Sstevel@tonic-gate 		xmlFreeDoc(document);
31860Sstevel@tonic-gate 		return (-1);
31870Sstevel@tonic-gate 	}
31880Sstevel@tonic-gate 
31890Sstevel@tonic-gate 	if (xmlStrcmp(cursor->name, (const xmlChar *)"service_bundle") != 0) {
31900Sstevel@tonic-gate 		semerr(gettext("document is not a service bundle\n"));
31910Sstevel@tonic-gate 		xmlFreeDoc(document);
31920Sstevel@tonic-gate 		return (-1);
31930Sstevel@tonic-gate 	}
31940Sstevel@tonic-gate 
31950Sstevel@tonic-gate 
31960Sstevel@tonic-gate 	if (dtdpath != NULL) {
31970Sstevel@tonic-gate 		dtd = xmlParseDTD(NULL, (xmlChar *)dtdpath);
31980Sstevel@tonic-gate 		if (dtd == NULL) {
31990Sstevel@tonic-gate 			semerr(gettext("Could not parse DTD \"%s\".\n"),
32000Sstevel@tonic-gate 			    dtdpath);
32010Sstevel@tonic-gate 			return (-1);
32020Sstevel@tonic-gate 		}
32030Sstevel@tonic-gate 
32040Sstevel@tonic-gate 		if (document->extSubset != NULL)
32050Sstevel@tonic-gate 			xmlFreeDtd(document->extSubset);
32060Sstevel@tonic-gate 
32070Sstevel@tonic-gate 		document->extSubset = dtd;
32080Sstevel@tonic-gate 	}
32090Sstevel@tonic-gate 
32104740Sjeanm 	if (xmlXIncludeProcessFlags(document, XML_PARSE_XINCLUDE) == -1) {
32110Sstevel@tonic-gate 		semerr(gettext("couldn't handle XInclude statements "
32124740Sjeanm 		    "in document\n"));
32130Sstevel@tonic-gate 		return (-1);
32140Sstevel@tonic-gate 	}
32150Sstevel@tonic-gate 
32160Sstevel@tonic-gate 	if (do_validate) {
32170Sstevel@tonic-gate 		vcp = xmlNewValidCtxt();
32180Sstevel@tonic-gate 		if (vcp == NULL)
32190Sstevel@tonic-gate 			uu_die(gettext("could not allocate memory"));
32200Sstevel@tonic-gate 		vcp->warning = xmlParserValidityWarning;
32210Sstevel@tonic-gate 		vcp->error = xmlParserValidityError;
32220Sstevel@tonic-gate 
32230Sstevel@tonic-gate 		r = xmlValidateDocument(vcp, document);
32240Sstevel@tonic-gate 
32250Sstevel@tonic-gate 		xmlFreeValidCtxt(vcp);
32260Sstevel@tonic-gate 
32270Sstevel@tonic-gate 		if (r == 0) {
32280Sstevel@tonic-gate 			semerr(gettext("Document is not valid.\n"));
32290Sstevel@tonic-gate 			xmlFreeDoc(document);
32300Sstevel@tonic-gate 			return (-1);
32310Sstevel@tonic-gate 		}
32320Sstevel@tonic-gate 	}
32330Sstevel@tonic-gate 
32340Sstevel@tonic-gate 
32350Sstevel@tonic-gate #ifdef DEBUG
32360Sstevel@tonic-gate 	lxml_dump(0, cursor);
32370Sstevel@tonic-gate #endif /* DEBUG */
32380Sstevel@tonic-gate 
32395040Swesolows 	r = lxml_get_bundle(bundle, SVCCFG_UNKNOWN_BUNDLE, cursor, op);
32400Sstevel@tonic-gate 
32410Sstevel@tonic-gate 	xmlFreeDoc(document);
32420Sstevel@tonic-gate 
32430Sstevel@tonic-gate 	return (r);
32440Sstevel@tonic-gate }
32450Sstevel@tonic-gate 
32460Sstevel@tonic-gate int
32470Sstevel@tonic-gate lxml_inventory(const char *filename)
32480Sstevel@tonic-gate {
32490Sstevel@tonic-gate 	bundle_t *b;
32500Sstevel@tonic-gate 	uu_list_walk_t *svcs, *insts;
32510Sstevel@tonic-gate 	entity_t *svc, *inst;
32520Sstevel@tonic-gate 
32530Sstevel@tonic-gate 	b = internal_bundle_new();
32540Sstevel@tonic-gate 
32555040Swesolows 	if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) != 0) {
32560Sstevel@tonic-gate 		internal_bundle_free(b);
32570Sstevel@tonic-gate 		return (-1);
32580Sstevel@tonic-gate 	}
32590Sstevel@tonic-gate 
32600Sstevel@tonic-gate 	svcs = uu_list_walk_start(b->sc_bundle_services, 0);
32610Sstevel@tonic-gate 	if (svcs == NULL)
32620Sstevel@tonic-gate 		uu_die(gettext("Couldn't walk services"));
32630Sstevel@tonic-gate 
32640Sstevel@tonic-gate 	while ((svc = uu_list_walk_next(svcs)) != NULL) {
32650Sstevel@tonic-gate 		uu_list_t *inst_list;
32660Sstevel@tonic-gate 
32670Sstevel@tonic-gate 		inst_list = svc->sc_u.sc_service.sc_service_instances;
32680Sstevel@tonic-gate 		insts = uu_list_walk_start(inst_list, 0);
32690Sstevel@tonic-gate 		if (insts == NULL)
32700Sstevel@tonic-gate 			uu_die(gettext("Couldn't walk instances"));
32710Sstevel@tonic-gate 
32720Sstevel@tonic-gate 		while ((inst = uu_list_walk_next(insts)) != NULL)
32730Sstevel@tonic-gate 			(void) printf("svc:/%s:%s\n", svc->sc_name,
32740Sstevel@tonic-gate 			    inst->sc_name);
32750Sstevel@tonic-gate 
32760Sstevel@tonic-gate 		uu_list_walk_end(insts);
32770Sstevel@tonic-gate 	}
32780Sstevel@tonic-gate 
32790Sstevel@tonic-gate 	uu_list_walk_end(svcs);
32800Sstevel@tonic-gate 
32810Sstevel@tonic-gate 	svcs = uu_list_walk_start(b->sc_bundle_services, 0);
32820Sstevel@tonic-gate 	while ((svc = uu_list_walk_next(svcs)) != NULL) {
32830Sstevel@tonic-gate 		(void) fputs("svc:/", stdout);
32840Sstevel@tonic-gate 		(void) puts(svc->sc_name);
32850Sstevel@tonic-gate 	}
32860Sstevel@tonic-gate 	uu_list_walk_end(svcs);
32870Sstevel@tonic-gate 
32880Sstevel@tonic-gate 	internal_bundle_free(b);
32890Sstevel@tonic-gate 
32900Sstevel@tonic-gate 	return (0);
32910Sstevel@tonic-gate }
3292