xref: /onnv-gate/usr/src/cmd/svc/svccfg/svccfg_xml.c (revision 12967:ab9ae749152f)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
54740Sjeanm  * Common Development and Distribution License (the "License").
64740Sjeanm  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
2212172SSean.Wilcox@Sun.COM  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate  */
240Sstevel@tonic-gate 
257887SLiane.Praza@Sun.COM /*
267887SLiane.Praza@Sun.COM  * XML document manipulation routines
277887SLiane.Praza@Sun.COM  *
287887SLiane.Praza@Sun.COM  * These routines provide translation to and from the internal representation to
297887SLiane.Praza@Sun.COM  * XML.  Directionally-oriented verbs are with respect to the external source,
307887SLiane.Praza@Sun.COM  * so lxml_get_service() fetches a service from the XML file into the
317887SLiane.Praza@Sun.COM  * internal representation.
327887SLiane.Praza@Sun.COM  */
330Sstevel@tonic-gate 
340Sstevel@tonic-gate #include <libxml/parser.h>
350Sstevel@tonic-gate #include <libxml/xinclude.h>
360Sstevel@tonic-gate 
370Sstevel@tonic-gate #include <assert.h>
380Sstevel@tonic-gate #include <ctype.h>
390Sstevel@tonic-gate #include <errno.h>
400Sstevel@tonic-gate #include <libintl.h>
417887SLiane.Praza@Sun.COM #include <libscf.h>
427887SLiane.Praza@Sun.COM #include <libscf_priv.h>
430Sstevel@tonic-gate #include <libuutil.h>
447887SLiane.Praza@Sun.COM #include <sasl/saslutil.h>
450Sstevel@tonic-gate #include <stdlib.h>
460Sstevel@tonic-gate #include <string.h>
4712172SSean.Wilcox@Sun.COM #include <limits.h>
480Sstevel@tonic-gate 
494740Sjeanm #include <sys/types.h>
504740Sjeanm #include <sys/stat.h>
514740Sjeanm #include <unistd.h>
524740Sjeanm 
5310461SSean.Wilcox@Sun.COM #include <sys/param.h>
5410461SSean.Wilcox@Sun.COM #include "manifest_hash.h"
5510461SSean.Wilcox@Sun.COM 
560Sstevel@tonic-gate #include "svccfg.h"
57*12967Sgavin.maltby@oracle.com #include "notify_params.h"
580Sstevel@tonic-gate 
590Sstevel@tonic-gate /*
607887SLiane.Praza@Sun.COM  * snprintf(3C) format strings for constructing property names that include
617887SLiane.Praza@Sun.COM  * the locale designation.  Use %s to indicate where the locale should go.
620Sstevel@tonic-gate  *
637887SLiane.Praza@Sun.COM  * The VALUE_* symbols are an exception.  The firs %s will be replaced with
647887SLiane.Praza@Sun.COM  * "value_".  The second %s will be replaced by the name of the value and
657887SLiane.Praza@Sun.COM  * %%s will be replaced by the locale designation.  These formats are
667887SLiane.Praza@Sun.COM  * processed twice by snprintf(3C).  The first time captures the value name
677887SLiane.Praza@Sun.COM  * and the second time captures the locale.
680Sstevel@tonic-gate  */
697887SLiane.Praza@Sun.COM #define	LOCALE_ONLY_FMT		("%s")
707887SLiane.Praza@Sun.COM #define	COMMON_NAME_FMT		("common_name_%s")
717887SLiane.Praza@Sun.COM #define	DESCRIPTION_FMT		("description_%s")
727887SLiane.Praza@Sun.COM #define	UNITS_FMT		("units_%s")
737887SLiane.Praza@Sun.COM #define	VALUE_COMMON_NAME_FMT	("%s%s_common_name_%%s")
747887SLiane.Praza@Sun.COM #define	VALUE_DESCRIPTION_FMT	("%s%s_description_%%s")
757887SLiane.Praza@Sun.COM 
767887SLiane.Praza@Sun.COM /* Attribute names */
770Sstevel@tonic-gate const char * const delete_attr = "delete";
780Sstevel@tonic-gate const char * const enabled_attr = "enabled";
797887SLiane.Praza@Sun.COM const char * const lang_attr = "lang";
807887SLiane.Praza@Sun.COM const char * const manpath_attr = "manpath";
817887SLiane.Praza@Sun.COM const char * const max_attr = "max";
827887SLiane.Praza@Sun.COM const char * const min_attr = "min";
830Sstevel@tonic-gate const char * const name_attr = "name";
840Sstevel@tonic-gate const char * const override_attr = "override";
857887SLiane.Praza@Sun.COM const char * const required_attr = "required";
867887SLiane.Praza@Sun.COM const char * const section_attr = "section";
877887SLiane.Praza@Sun.COM const char * const set_attr = "set";
887887SLiane.Praza@Sun.COM const char * const target_attr = "target";
897887SLiane.Praza@Sun.COM const char * const timeout_seconds_attr = "timeout_seconds";
907887SLiane.Praza@Sun.COM const char * const title_attr = "title";
910Sstevel@tonic-gate const char * const type_attr = "type";
927887SLiane.Praza@Sun.COM const char * const uri_attr = "uri";
930Sstevel@tonic-gate const char * const value_attr = "value";
947887SLiane.Praza@Sun.COM const char * const version_attr = "version";
957887SLiane.Praza@Sun.COM const char * const xml_lang_attr = "xml:lang";
96*12967Sgavin.maltby@oracle.com const char * const active_attr = "active";
977887SLiane.Praza@Sun.COM 
987887SLiane.Praza@Sun.COM /* Attribute values */
997887SLiane.Praza@Sun.COM const char * const all_value = "all";
1007887SLiane.Praza@Sun.COM 
1010Sstevel@tonic-gate const char * const true = "true";
1020Sstevel@tonic-gate const char * const false = "false";
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate /*
1050Sstevel@tonic-gate  * The following list must be kept in the same order as that of
1060Sstevel@tonic-gate  * element_t array
1070Sstevel@tonic-gate  */
1080Sstevel@tonic-gate static const char *lxml_elements[] = {
1090Sstevel@tonic-gate 	"astring_list",			/* SC_ASTRING */
1100Sstevel@tonic-gate 	"boolean_list",			/* SC_BOOLEAN */
1117887SLiane.Praza@Sun.COM 	"cardinality",			/* SC_CARDINALITY */
1127887SLiane.Praza@Sun.COM 	"choices",			/* SC_CHOICES */
1130Sstevel@tonic-gate 	"common_name",			/* SC_COMMON_NAME */
1147887SLiane.Praza@Sun.COM 	"constraints",			/* SC_CONSTRAINTS */
1150Sstevel@tonic-gate 	"count_list",			/* SC_COUNT */
1160Sstevel@tonic-gate 	"create_default_instance",	/* SC_INSTANCE_CREATE_DEFAULT */
1170Sstevel@tonic-gate 	"dependency",			/* SC_DEPENDENCY */
1180Sstevel@tonic-gate 	"dependent",			/* SC_DEPENDENT */
1190Sstevel@tonic-gate 	"description",			/* SC_DESCRIPTION */
1200Sstevel@tonic-gate 	"doc_link",			/* SC_DOC_LINK */
1210Sstevel@tonic-gate 	"documentation",		/* SC_DOCUMENTATION */
1220Sstevel@tonic-gate 	"enabled",			/* SC_ENABLED */
123*12967Sgavin.maltby@oracle.com 	"event",			/* SC_EVENT */
1240Sstevel@tonic-gate 	"exec_method",			/* SC_EXEC_METHOD */
1250Sstevel@tonic-gate 	"fmri_list",			/* SC_FMRI */
1260Sstevel@tonic-gate 	"host_list",			/* SC_HOST */
1270Sstevel@tonic-gate 	"hostname_list",		/* SC_HOSTNAME */
1287887SLiane.Praza@Sun.COM 	"include_values",		/* SC_INCLUDE_VALUES */
1290Sstevel@tonic-gate 	"instance",			/* SC_INSTANCE */
1300Sstevel@tonic-gate 	"integer_list",			/* SC_INTEGER */
1317887SLiane.Praza@Sun.COM 	"internal_separators",		/* SC_INTERNAL_SEPARATORS */
1320Sstevel@tonic-gate 	"loctext",			/* SC_LOCTEXT */
1330Sstevel@tonic-gate 	"manpage",			/* SC_MANPAGE */
1340Sstevel@tonic-gate 	"method_context",		/* SC_METHOD_CONTEXT */
1350Sstevel@tonic-gate 	"method_credential",		/* SC_METHOD_CREDENTIAL */
1360Sstevel@tonic-gate 	"method_profile",		/* SC_METHOD_PROFILE */
1370Sstevel@tonic-gate 	"method_environment",		/* SC_METHOD_ENVIRONMENT */
1380Sstevel@tonic-gate 	"envvar",			/* SC_METHOD_ENVVAR */
13912691SAntonello.Cruz@Sun.COM 	"net_address_list",		/* SC_NET_ADDR */
1400Sstevel@tonic-gate 	"net_address_v4_list",		/* SC_NET_ADDR_V4 */
1410Sstevel@tonic-gate 	"net_address_v6_list",		/* SC_NET_ADDR_V6 */
142*12967Sgavin.maltby@oracle.com 	"notification_parameters",	/* SC_NOTIFICATION_PARAMETERS */
1430Sstevel@tonic-gate 	"opaque_list",			/* SC_OPAQUE */
144*12967Sgavin.maltby@oracle.com 	"parameter",			/* SC_PARAMETER */
145*12967Sgavin.maltby@oracle.com 	"paramval",			/* SC_PARAMVAL */
1467887SLiane.Praza@Sun.COM 	"pg_pattern",			/* SC_PG_PATTERN */
1477887SLiane.Praza@Sun.COM 	"prop_pattern",			/* SC_PROP_PATTERN */
1480Sstevel@tonic-gate 	"property",			/* SC_PROPERTY */
1490Sstevel@tonic-gate 	"property_group",		/* SC_PROPERTY_GROUP */
1500Sstevel@tonic-gate 	"propval",			/* SC_PROPVAL */
1517887SLiane.Praza@Sun.COM 	"range",			/* SC_RANGE */
1520Sstevel@tonic-gate 	"restarter",			/* SC_RESTARTER */
1530Sstevel@tonic-gate 	"service",			/* SC_SERVICE */
1540Sstevel@tonic-gate 	"service_bundle",		/* SC_SERVICE_BUNDLE */
1550Sstevel@tonic-gate 	"service_fmri",			/* SC_SERVICE_FMRI */
1560Sstevel@tonic-gate 	"single_instance",		/* SC_INSTANCE_SINGLE */
1570Sstevel@tonic-gate 	"stability",			/* SC_STABILITY */
1580Sstevel@tonic-gate 	"template",			/* SC_TEMPLATE */
1590Sstevel@tonic-gate 	"time_list",			/* SC_TIME */
160*12967Sgavin.maltby@oracle.com 	"type",				/* SC_TYPE */
1617887SLiane.Praza@Sun.COM 	"units",			/* SC_UNITS */
1620Sstevel@tonic-gate 	"uri_list",			/* SC_URI */
1630Sstevel@tonic-gate 	"ustring_list",			/* SC_USTRING */
1647887SLiane.Praza@Sun.COM 	"value",			/* SC_VALUE */
1650Sstevel@tonic-gate 	"value_node",			/* SC_VALUE_NODE */
1667887SLiane.Praza@Sun.COM 	"values",			/* SC_VALUES */
1677887SLiane.Praza@Sun.COM 	"visibility",			/* SC_VISIBILITY */
1680Sstevel@tonic-gate 	"xi:fallback",			/* SC_XI_FALLBACK */
1690Sstevel@tonic-gate 	"xi:include"			/* SC_XI_INCLUDE */
1700Sstevel@tonic-gate };
1710Sstevel@tonic-gate 
1720Sstevel@tonic-gate /*
1730Sstevel@tonic-gate  * The following list must be kept in the same order as that of
1740Sstevel@tonic-gate  * element_t array
1750Sstevel@tonic-gate  */
1760Sstevel@tonic-gate static const char *lxml_prop_types[] = {
1770Sstevel@tonic-gate 	"astring",			/* SC_ASTRING */
1780Sstevel@tonic-gate 	"boolean",			/* SC_BOOLEAN */
1797887SLiane.Praza@Sun.COM 	"",				/* SC_CARDINALITY */
1807887SLiane.Praza@Sun.COM 	"",				/* SC_CHOICES */
1810Sstevel@tonic-gate 	"",				/* SC_COMMON_NAME */
1827887SLiane.Praza@Sun.COM 	"",				/* SC_CONSTRAINTS */
1830Sstevel@tonic-gate 	"count",			/* SC_COUNT */
1840Sstevel@tonic-gate 	"",				/* SC_INSTANCE_CREATE_DEFAULT */
1850Sstevel@tonic-gate 	"",				/* SC_DEPENDENCY */
1860Sstevel@tonic-gate 	"",				/* SC_DEPENDENT */
1870Sstevel@tonic-gate 	"",				/* SC_DESCRIPTION */
1880Sstevel@tonic-gate 	"",				/* SC_DOC_LINK */
1890Sstevel@tonic-gate 	"",				/* SC_DOCUMENTATION */
1900Sstevel@tonic-gate 	"",				/* SC_ENABLED */
191*12967Sgavin.maltby@oracle.com 	"",				/* SC_EVENT */
1920Sstevel@tonic-gate 	"",				/* SC_EXEC_METHOD */
1930Sstevel@tonic-gate 	"fmri",				/* SC_FMRI */
1940Sstevel@tonic-gate 	"host",				/* SC_HOST */
1950Sstevel@tonic-gate 	"hostname",			/* SC_HOSTNAME */
1967887SLiane.Praza@Sun.COM 	"",				/* SC_INCLUDE_VALUES */
1970Sstevel@tonic-gate 	"",				/* SC_INSTANCE */
1980Sstevel@tonic-gate 	"integer",			/* SC_INTEGER */
1997887SLiane.Praza@Sun.COM 	"",				/* SC_INTERNAL_SEPARATORS */
2000Sstevel@tonic-gate 	"",				/* SC_LOCTEXT */
2010Sstevel@tonic-gate 	"",				/* SC_MANPAGE */
2020Sstevel@tonic-gate 	"",				/* SC_METHOD_CONTEXT */
2030Sstevel@tonic-gate 	"",				/* SC_METHOD_CREDENTIAL */
2040Sstevel@tonic-gate 	"",				/* SC_METHOD_PROFILE */
2050Sstevel@tonic-gate 	"",				/* SC_METHOD_ENVIRONMENT */
2060Sstevel@tonic-gate 	"",				/* SC_METHOD_ENVVAR */
20712691SAntonello.Cruz@Sun.COM 	"net_address",			/* SC_NET_ADDR */
2080Sstevel@tonic-gate 	"net_address_v4",		/* SC_NET_ADDR_V4 */
2090Sstevel@tonic-gate 	"net_address_v6",		/* SC_NET_ADDR_V6 */
210*12967Sgavin.maltby@oracle.com 	"",				/* SC_NOTIFICATION_PARAMETERS */
2110Sstevel@tonic-gate 	"opaque",			/* SC_OPAQUE */
212*12967Sgavin.maltby@oracle.com 	"",				/* SC_PARAMETER */
213*12967Sgavin.maltby@oracle.com 	"",				/* SC_PARAMVAL */
2147887SLiane.Praza@Sun.COM 	"",				/* SC_PG_PATTERN */
2157887SLiane.Praza@Sun.COM 	"",				/* SC_PROP_PATTERN */
2160Sstevel@tonic-gate 	"",				/* SC_PROPERTY */
2170Sstevel@tonic-gate 	"",				/* SC_PROPERTY_GROUP */
2180Sstevel@tonic-gate 	"",				/* SC_PROPVAL */
2197887SLiane.Praza@Sun.COM 	"",				/* SC_RANGE */
2200Sstevel@tonic-gate 	"",				/* SC_RESTARTER */
2210Sstevel@tonic-gate 	"",				/* SC_SERVICE */
2220Sstevel@tonic-gate 	"",				/* SC_SERVICE_BUNDLE */
2230Sstevel@tonic-gate 	"",				/* SC_SERVICE_FMRI */
2240Sstevel@tonic-gate 	"",				/* SC_INSTANCE_SINGLE */
2250Sstevel@tonic-gate 	"",				/* SC_STABILITY */
2260Sstevel@tonic-gate 	"",				/* SC_TEMPLATE */
2270Sstevel@tonic-gate 	"time",				/* SC_TIME */
228*12967Sgavin.maltby@oracle.com 	"",				/* SC_TYPE */
2297887SLiane.Praza@Sun.COM 	"",				/* SC_UNITS */
2300Sstevel@tonic-gate 	"uri",				/* SC_URI */
2310Sstevel@tonic-gate 	"ustring",			/* SC_USTRING */
2327887SLiane.Praza@Sun.COM 	"",				/* SC_VALUE */
2337887SLiane.Praza@Sun.COM 	"",				/* SC_VALUE_NODE */
2347887SLiane.Praza@Sun.COM 	"",				/* SC_VALUES */
2357887SLiane.Praza@Sun.COM 	"",				/* SC_VISIBILITY */
2367887SLiane.Praza@Sun.COM 	"",				/* SC_XI_FALLBACK */
2370Sstevel@tonic-gate 	""				/* SC_XI_INCLUDE */
2380Sstevel@tonic-gate };
2390Sstevel@tonic-gate 
2400Sstevel@tonic-gate int
lxml_init()2410Sstevel@tonic-gate lxml_init()
2420Sstevel@tonic-gate {
2430Sstevel@tonic-gate 	if (getenv("SVCCFG_NOVALIDATE") == NULL) {
2440Sstevel@tonic-gate 		/*
2450Sstevel@tonic-gate 		 * DTD validation, with line numbers.
2460Sstevel@tonic-gate 		 */
24711053SSurya.Prakki@Sun.COM 		(void) xmlLineNumbersDefault(1);
2480Sstevel@tonic-gate 		xmlLoadExtDtdDefaultValue |= XML_DETECT_IDS;
2490Sstevel@tonic-gate 		xmlLoadExtDtdDefaultValue |= XML_COMPLETE_ATTRS;
2500Sstevel@tonic-gate 	}
2510Sstevel@tonic-gate 
2520Sstevel@tonic-gate 	return (0);
2530Sstevel@tonic-gate }
2540Sstevel@tonic-gate 
2550Sstevel@tonic-gate static bundle_type_t
lxml_xlate_bundle_type(xmlChar * type)2560Sstevel@tonic-gate lxml_xlate_bundle_type(xmlChar *type)
2570Sstevel@tonic-gate {
2580Sstevel@tonic-gate 	if (xmlStrcmp(type, (const xmlChar *)"manifest") == 0)
2590Sstevel@tonic-gate 		return (SVCCFG_MANIFEST);
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate 	if (xmlStrcmp(type, (const xmlChar *)"profile") == 0)
2620Sstevel@tonic-gate 		return (SVCCFG_PROFILE);
2630Sstevel@tonic-gate 
2640Sstevel@tonic-gate 	if (xmlStrcmp(type, (const xmlChar *)"archive") == 0)
2650Sstevel@tonic-gate 		return (SVCCFG_ARCHIVE);
2660Sstevel@tonic-gate 
2670Sstevel@tonic-gate 	return (SVCCFG_UNKNOWN_BUNDLE);
2680Sstevel@tonic-gate }
2690Sstevel@tonic-gate 
2700Sstevel@tonic-gate static service_type_t
lxml_xlate_service_type(xmlChar * type)2710Sstevel@tonic-gate lxml_xlate_service_type(xmlChar *type)
2720Sstevel@tonic-gate {
2730Sstevel@tonic-gate 	if (xmlStrcmp(type, (const xmlChar *)"service") == 0)
2740Sstevel@tonic-gate 		return (SVCCFG_SERVICE);
2750Sstevel@tonic-gate 
2760Sstevel@tonic-gate 	if (xmlStrcmp(type, (const xmlChar *)"restarter") == 0)
2770Sstevel@tonic-gate 		return (SVCCFG_RESTARTER);
2780Sstevel@tonic-gate 
2790Sstevel@tonic-gate 	if (xmlStrcmp(type, (const xmlChar *)"milestone") == 0)
2800Sstevel@tonic-gate 		return (SVCCFG_MILESTONE);
2810Sstevel@tonic-gate 
2820Sstevel@tonic-gate 	return (SVCCFG_UNKNOWN_SERVICE);
2830Sstevel@tonic-gate }
2840Sstevel@tonic-gate 
2850Sstevel@tonic-gate static element_t
lxml_xlate_element(const xmlChar * tag)2860Sstevel@tonic-gate lxml_xlate_element(const xmlChar *tag)
2870Sstevel@tonic-gate {
2880Sstevel@tonic-gate 	int i;
2890Sstevel@tonic-gate 
2900Sstevel@tonic-gate 	for (i = 0; i < sizeof (lxml_elements) / sizeof (char *); i++)
2910Sstevel@tonic-gate 		if (xmlStrcmp(tag, (const xmlChar *)lxml_elements[i]) == 0)
2920Sstevel@tonic-gate 			return ((element_t)i);
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate 	return ((element_t)-1);
2950Sstevel@tonic-gate }
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate static uint_t
lxml_xlate_boolean(const xmlChar * value)2980Sstevel@tonic-gate lxml_xlate_boolean(const xmlChar *value)
2990Sstevel@tonic-gate {
3000Sstevel@tonic-gate 	if (xmlStrcmp(value, (const xmlChar *)true) == 0)
3010Sstevel@tonic-gate 		return (1);
3020Sstevel@tonic-gate 
3030Sstevel@tonic-gate 	if (xmlStrcmp(value, (const xmlChar *)false) == 0)
3040Sstevel@tonic-gate 		return (0);
3050Sstevel@tonic-gate 
3060Sstevel@tonic-gate 	uu_die(gettext("illegal boolean value \"%s\"\n"), value);
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate 	/*NOTREACHED*/
3090Sstevel@tonic-gate }
3100Sstevel@tonic-gate 
3110Sstevel@tonic-gate static scf_type_t
lxml_element_to_type(element_t type)3120Sstevel@tonic-gate lxml_element_to_type(element_t type)
3130Sstevel@tonic-gate {
3140Sstevel@tonic-gate 	switch (type) {
3150Sstevel@tonic-gate 	case SC_ASTRING:	return (SCF_TYPE_ASTRING);
3160Sstevel@tonic-gate 	case SC_BOOLEAN:	return (SCF_TYPE_BOOLEAN);
3170Sstevel@tonic-gate 	case SC_COUNT:		return (SCF_TYPE_COUNT);
3180Sstevel@tonic-gate 	case SC_FMRI:		return (SCF_TYPE_FMRI);
3190Sstevel@tonic-gate 	case SC_HOST:		return (SCF_TYPE_HOST);
3200Sstevel@tonic-gate 	case SC_HOSTNAME:	return (SCF_TYPE_HOSTNAME);
3210Sstevel@tonic-gate 	case SC_INTEGER:	return (SCF_TYPE_INTEGER);
32212691SAntonello.Cruz@Sun.COM 	case SC_NET_ADDR:	return (SCF_TYPE_NET_ADDR);
3230Sstevel@tonic-gate 	case SC_NET_ADDR_V4:	return (SCF_TYPE_NET_ADDR_V4);
3240Sstevel@tonic-gate 	case SC_NET_ADDR_V6:	return (SCF_TYPE_NET_ADDR_V6);
3250Sstevel@tonic-gate 	case SC_OPAQUE:		return (SCF_TYPE_OPAQUE);
3260Sstevel@tonic-gate 	case SC_TIME:		return (SCF_TYPE_TIME);
3270Sstevel@tonic-gate 	case SC_URI:		return (SCF_TYPE_URI);
3280Sstevel@tonic-gate 	case SC_USTRING:	return (SCF_TYPE_USTRING);
3290Sstevel@tonic-gate 
3300Sstevel@tonic-gate 	default:
3310Sstevel@tonic-gate 		uu_die(gettext("unknown value type (%d)\n"), type);
3320Sstevel@tonic-gate 	}
3330Sstevel@tonic-gate 
3340Sstevel@tonic-gate 	/* NOTREACHED */
3350Sstevel@tonic-gate }
3360Sstevel@tonic-gate 
33712667SSean.Wilcox@Sun.COM static element_t
lxml_type_to_element(scf_type_t type)33812667SSean.Wilcox@Sun.COM lxml_type_to_element(scf_type_t type)
3390Sstevel@tonic-gate {
3400Sstevel@tonic-gate 	switch (type) {
34112667SSean.Wilcox@Sun.COM 	case SCF_TYPE_ASTRING:		return (SC_ASTRING);
34212667SSean.Wilcox@Sun.COM 	case SCF_TYPE_BOOLEAN:		return (SC_BOOLEAN);
34312667SSean.Wilcox@Sun.COM 	case SCF_TYPE_COUNT:		return (SC_COUNT);
34412667SSean.Wilcox@Sun.COM 	case SCF_TYPE_FMRI:		return (SC_FMRI);
34512667SSean.Wilcox@Sun.COM 	case SCF_TYPE_HOST:		return (SC_HOST);
34612667SSean.Wilcox@Sun.COM 	case SCF_TYPE_HOSTNAME:		return (SC_HOSTNAME);
34712667SSean.Wilcox@Sun.COM 	case SCF_TYPE_INTEGER:		return (SC_INTEGER);
34812691SAntonello.Cruz@Sun.COM 	case SCF_TYPE_NET_ADDR:		return (SC_NET_ADDR);
34912667SSean.Wilcox@Sun.COM 	case SCF_TYPE_NET_ADDR_V4:	return (SC_NET_ADDR_V4);
35012667SSean.Wilcox@Sun.COM 	case SCF_TYPE_NET_ADDR_V6:	return (SC_NET_ADDR_V6);
35112667SSean.Wilcox@Sun.COM 	case SCF_TYPE_OPAQUE:		return (SC_OPAQUE);
35212667SSean.Wilcox@Sun.COM 	case SCF_TYPE_TIME:		return (SC_TIME);
35312667SSean.Wilcox@Sun.COM 	case SCF_TYPE_URI:		return (SC_URI);
35412667SSean.Wilcox@Sun.COM 	case SCF_TYPE_USTRING:		return (SC_USTRING);
35512667SSean.Wilcox@Sun.COM 
3560Sstevel@tonic-gate 	default:
3570Sstevel@tonic-gate 		uu_die(gettext("unknown value type (%d)\n"), type);
3580Sstevel@tonic-gate 	}
3590Sstevel@tonic-gate 
3600Sstevel@tonic-gate 	/* NOTREACHED */
3610Sstevel@tonic-gate }
3620Sstevel@tonic-gate 
3637887SLiane.Praza@Sun.COM /*
3647887SLiane.Praza@Sun.COM  * Create a SCF_TYPE_BOOLEAN property name pname and attach it to the
3657887SLiane.Praza@Sun.COM  * property group at pgrp.  The value of the property will be set from the
3667887SLiane.Praza@Sun.COM  * attribute named attr.  attr must have a value of 0, 1, true or false.
3677887SLiane.Praza@Sun.COM  *
3687887SLiane.Praza@Sun.COM  * Zero is returned on success.  An error is indicated by -1.  It indicates
3697887SLiane.Praza@Sun.COM  * that either the attribute had an invalid value or that we could not
3707887SLiane.Praza@Sun.COM  * attach the property to pgrp.  The attribute should not have an invalid
3717887SLiane.Praza@Sun.COM  * value if the DTD is correctly written.
3727887SLiane.Praza@Sun.COM  */
3737887SLiane.Praza@Sun.COM static int
new_bool_prop_from_attr(pgroup_t * pgrp,const char * pname,xmlNodePtr n,const char * attr)3747887SLiane.Praza@Sun.COM new_bool_prop_from_attr(pgroup_t *pgrp, const char *pname, xmlNodePtr n,
3757887SLiane.Praza@Sun.COM     const char *attr)
3767887SLiane.Praza@Sun.COM {
3777887SLiane.Praza@Sun.COM 	uint64_t bool;
3787887SLiane.Praza@Sun.COM 	xmlChar *val;
3797887SLiane.Praza@Sun.COM 	property_t *p;
3807887SLiane.Praza@Sun.COM 	int r;
3817887SLiane.Praza@Sun.COM 
3827887SLiane.Praza@Sun.COM 	val = xmlGetProp(n, (xmlChar *)attr);
3837887SLiane.Praza@Sun.COM 	if (val == NULL)
3847887SLiane.Praza@Sun.COM 		return (0);
3857887SLiane.Praza@Sun.COM 
3867887SLiane.Praza@Sun.COM 	if ((xmlStrcmp(val, (xmlChar *)"0") == 0) ||
3877887SLiane.Praza@Sun.COM 	    (xmlStrcmp(val, (xmlChar *)"false") == 0)) {
3887887SLiane.Praza@Sun.COM 		bool = 0;
3897887SLiane.Praza@Sun.COM 	} else if ((xmlStrcmp(val, (xmlChar *)"1") == 0) ||
3907887SLiane.Praza@Sun.COM 	    (xmlStrcmp(val, (xmlChar *)"true") == 0)) {
3917887SLiane.Praza@Sun.COM 		bool = 1;
3927887SLiane.Praza@Sun.COM 	} else {
3937887SLiane.Praza@Sun.COM 		xmlFree(val);
3947887SLiane.Praza@Sun.COM 		return (-1);
3957887SLiane.Praza@Sun.COM 	}
3967887SLiane.Praza@Sun.COM 	xmlFree(val);
3977887SLiane.Praza@Sun.COM 	p = internal_property_create(pname, SCF_TYPE_BOOLEAN, 1, bool);
3987887SLiane.Praza@Sun.COM 	r = internal_attach_property(pgrp, p);
3997887SLiane.Praza@Sun.COM 
4007887SLiane.Praza@Sun.COM 	if (r != 0)
4017887SLiane.Praza@Sun.COM 		internal_property_free(p);
4027887SLiane.Praza@Sun.COM 
4037887SLiane.Praza@Sun.COM 	return (r);
4047887SLiane.Praza@Sun.COM }
4057887SLiane.Praza@Sun.COM 
4060Sstevel@tonic-gate static int
new_str_prop_from_attr(pgroup_t * pgrp,const char * pname,scf_type_t ty,xmlNodePtr n,const char * attr)4070Sstevel@tonic-gate new_str_prop_from_attr(pgroup_t *pgrp, const char *pname, scf_type_t ty,
4080Sstevel@tonic-gate     xmlNodePtr n, const char *attr)
4090Sstevel@tonic-gate {
4100Sstevel@tonic-gate 	xmlChar *val;
4110Sstevel@tonic-gate 	property_t *p;
4120Sstevel@tonic-gate 	int r;
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate 	val = xmlGetProp(n, (xmlChar *)attr);
4150Sstevel@tonic-gate 
4160Sstevel@tonic-gate 	p = internal_property_create(pname, ty, 1, val);
4170Sstevel@tonic-gate 	r = internal_attach_property(pgrp, p);
4180Sstevel@tonic-gate 
4190Sstevel@tonic-gate 	if (r != 0)
4200Sstevel@tonic-gate 		internal_property_free(p);
4210Sstevel@tonic-gate 
4220Sstevel@tonic-gate 	return (r);
4230Sstevel@tonic-gate }
4240Sstevel@tonic-gate 
4250Sstevel@tonic-gate static int
new_opt_str_prop_from_attr(pgroup_t * pgrp,const char * pname,scf_type_t ty,xmlNodePtr n,const char * attr,const char * dflt)4267887SLiane.Praza@Sun.COM new_opt_str_prop_from_attr(pgroup_t *pgrp, const char *pname, scf_type_t ty,
4277887SLiane.Praza@Sun.COM     xmlNodePtr n, const char *attr, const char *dflt)
4287887SLiane.Praza@Sun.COM {
4297887SLiane.Praza@Sun.COM 	xmlChar *val;
4307887SLiane.Praza@Sun.COM 	property_t *p;
4317887SLiane.Praza@Sun.COM 	int r;
4327887SLiane.Praza@Sun.COM 
4337887SLiane.Praza@Sun.COM 	val = xmlGetProp(n, (xmlChar *)attr);
4347887SLiane.Praza@Sun.COM 	if (val == NULL) {
4357887SLiane.Praza@Sun.COM 		if (dflt == NULL) {
4367887SLiane.Praza@Sun.COM 			/*
4377887SLiane.Praza@Sun.COM 			 * A missing attribute is considered to be a
4387887SLiane.Praza@Sun.COM 			 * success in this function, because many of the
4397887SLiane.Praza@Sun.COM 			 * attributes are optional.  Missing non-optional
4407887SLiane.Praza@Sun.COM 			 * attributes will be detected later when template
4417887SLiane.Praza@Sun.COM 			 * validation is done.
4427887SLiane.Praza@Sun.COM 			 */
4437887SLiane.Praza@Sun.COM 			return (0);
4447887SLiane.Praza@Sun.COM 		} else {
4457887SLiane.Praza@Sun.COM 			val = (xmlChar *)dflt;
4467887SLiane.Praza@Sun.COM 		}
4477887SLiane.Praza@Sun.COM 	}
4487887SLiane.Praza@Sun.COM 
4497887SLiane.Praza@Sun.COM 	p = internal_property_create(pname, ty, 1, val);
4507887SLiane.Praza@Sun.COM 	r = internal_attach_property(pgrp, p);
4517887SLiane.Praza@Sun.COM 
4527887SLiane.Praza@Sun.COM 	if (r != 0)
4537887SLiane.Praza@Sun.COM 		internal_property_free(p);
4547887SLiane.Praza@Sun.COM 
4557887SLiane.Praza@Sun.COM 	return (r);
4567887SLiane.Praza@Sun.COM }
4577887SLiane.Praza@Sun.COM 
4587887SLiane.Praza@Sun.COM static int
lxml_ignorable_block(xmlNodePtr n)4590Sstevel@tonic-gate lxml_ignorable_block(xmlNodePtr n)
4600Sstevel@tonic-gate {
4610Sstevel@tonic-gate 	return ((xmlStrcmp(n->name, (xmlChar *)"text") == 0 ||
4620Sstevel@tonic-gate 	    xmlStrcmp(n->name, (xmlChar *)"comment") == 0) ? 1 : 0);
4630Sstevel@tonic-gate }
4640Sstevel@tonic-gate 
46512667SSean.Wilcox@Sun.COM static void
lxml_validate_element(xmlNodePtr n)46612667SSean.Wilcox@Sun.COM lxml_validate_element(xmlNodePtr n)
46712667SSean.Wilcox@Sun.COM {
46812667SSean.Wilcox@Sun.COM 	xmlValidCtxtPtr	vcp;
46912667SSean.Wilcox@Sun.COM 
47012667SSean.Wilcox@Sun.COM 	if (n->doc == NULL)
47112667SSean.Wilcox@Sun.COM 		uu_die(gettext("Could not validate element\n"));
47212667SSean.Wilcox@Sun.COM 
47312667SSean.Wilcox@Sun.COM 	if (n->doc->extSubset == NULL) {
47412667SSean.Wilcox@Sun.COM 		xmlDtdPtr dtd;
47512667SSean.Wilcox@Sun.COM 		dtd = xmlParseDTD(NULL, n->doc->intSubset->SystemID);
47612667SSean.Wilcox@Sun.COM 
47712667SSean.Wilcox@Sun.COM 		if (dtd == NULL) {
47812667SSean.Wilcox@Sun.COM 			uu_die(gettext("Could not parse DTD \"%s\".\n"),
47912667SSean.Wilcox@Sun.COM 			    n->doc->intSubset->SystemID);
48012667SSean.Wilcox@Sun.COM 		}
48112667SSean.Wilcox@Sun.COM 
48212667SSean.Wilcox@Sun.COM 		n->doc->extSubset = dtd;
48312667SSean.Wilcox@Sun.COM 	}
48412667SSean.Wilcox@Sun.COM 
48512667SSean.Wilcox@Sun.COM 	vcp = xmlNewValidCtxt();
48612667SSean.Wilcox@Sun.COM 	if (vcp == NULL)
48712667SSean.Wilcox@Sun.COM 		uu_die(gettext("could not allocate memory"));
48812667SSean.Wilcox@Sun.COM 
48912667SSean.Wilcox@Sun.COM 	vcp->warning = xmlParserValidityWarning;
49012667SSean.Wilcox@Sun.COM 	vcp->error = xmlParserValidityError;
49112667SSean.Wilcox@Sun.COM 
49212667SSean.Wilcox@Sun.COM 	if (xmlValidateElement(vcp, n->doc, n) == 0)
49312667SSean.Wilcox@Sun.COM 		uu_die(gettext("Document is not valid.\n"));
49412667SSean.Wilcox@Sun.COM 
49512667SSean.Wilcox@Sun.COM 	xmlFreeValidCtxt(vcp);
49612667SSean.Wilcox@Sun.COM }
49712667SSean.Wilcox@Sun.COM 
4980Sstevel@tonic-gate static int
lxml_validate_string_value(scf_type_t type,const char * v)4990Sstevel@tonic-gate lxml_validate_string_value(scf_type_t type, const char *v)
5000Sstevel@tonic-gate {
5010Sstevel@tonic-gate 	static scf_value_t *scf_value = NULL;
5020Sstevel@tonic-gate 	static scf_handle_t *scf_hndl = NULL;
5030Sstevel@tonic-gate 
5040Sstevel@tonic-gate 	if (scf_hndl == NULL && (scf_hndl = scf_handle_create(SCF_VERSION)) ==
5050Sstevel@tonic-gate 	    NULL)
5060Sstevel@tonic-gate 		return (-1);
5070Sstevel@tonic-gate 
5080Sstevel@tonic-gate 	if (scf_value == NULL && (scf_value = scf_value_create(scf_hndl)) ==
5090Sstevel@tonic-gate 	    NULL)
5100Sstevel@tonic-gate 		return (-1);
5110Sstevel@tonic-gate 
5120Sstevel@tonic-gate 	return (scf_value_set_from_string(scf_value, type, v));
5130Sstevel@tonic-gate }
5140Sstevel@tonic-gate 
5150Sstevel@tonic-gate static void
lxml_free_str(value_t * val)5160Sstevel@tonic-gate lxml_free_str(value_t *val)
5170Sstevel@tonic-gate {
5180Sstevel@tonic-gate 	free(val->sc_u.sc_string);
5190Sstevel@tonic-gate }
5200Sstevel@tonic-gate 
52112667SSean.Wilcox@Sun.COM /*
52212667SSean.Wilcox@Sun.COM  * Take a value_t structure and a type and value.  Based on the type
52312667SSean.Wilcox@Sun.COM  * ensure that the value is of that type.  If so store the value in
52412667SSean.Wilcox@Sun.COM  * the correct location of the value_t structure.
52512667SSean.Wilcox@Sun.COM  *
52612667SSean.Wilcox@Sun.COM  * If the value is NULL, the value_t structure will have been created
52712667SSean.Wilcox@Sun.COM  * and the value would have ultimately been stored as a string value
52812667SSean.Wilcox@Sun.COM  * but at the time the type was unknown.  Now the type should be known
52912667SSean.Wilcox@Sun.COM  * so take the type and value from value_t and validate and store
53012667SSean.Wilcox@Sun.COM  * the value correctly if the value is of the stated type.
53112667SSean.Wilcox@Sun.COM  */
53212667SSean.Wilcox@Sun.COM void
lxml_store_value(value_t * v,element_t type,const xmlChar * value)53312667SSean.Wilcox@Sun.COM lxml_store_value(value_t *v, element_t type, const xmlChar *value)
5340Sstevel@tonic-gate {
5350Sstevel@tonic-gate 	char *endptr;
53612667SSean.Wilcox@Sun.COM 	int fov = 0;
5370Sstevel@tonic-gate 	scf_type_t scf_type = SCF_TYPE_INVALID;
5380Sstevel@tonic-gate 
53912667SSean.Wilcox@Sun.COM 	if (value == NULL) {
54012667SSean.Wilcox@Sun.COM 		type = lxml_type_to_element(v->sc_type);
54112667SSean.Wilcox@Sun.COM 		value = (const xmlChar *)v->sc_u.sc_string;
54212667SSean.Wilcox@Sun.COM 		fov = 1;
54312667SSean.Wilcox@Sun.COM 	}
5440Sstevel@tonic-gate 
5450Sstevel@tonic-gate 	switch (type) {
5460Sstevel@tonic-gate 	case SC_COUNT:
5470Sstevel@tonic-gate 		/*
5480Sstevel@tonic-gate 		 * Although an SC_COUNT represents a uint64_t the use
5490Sstevel@tonic-gate 		 * of a negative value is acceptable due to the usage
5500Sstevel@tonic-gate 		 * established by inetd(1M).
5510Sstevel@tonic-gate 		 */
5520Sstevel@tonic-gate 		errno = 0;
5530Sstevel@tonic-gate 		v->sc_u.sc_count = strtoull((char *)value, &endptr, 10);
5540Sstevel@tonic-gate 		if (errno != 0 || endptr == (char *)value || *endptr)
5550Sstevel@tonic-gate 			uu_die(gettext("illegal value \"%s\" for "
5560Sstevel@tonic-gate 			    "%s (%s)\n"), (char *)value,
5570Sstevel@tonic-gate 			    lxml_prop_types[type],
5580Sstevel@tonic-gate 			    (errno) ? strerror(errno) :
5590Sstevel@tonic-gate 			    gettext("Illegal character"));
5600Sstevel@tonic-gate 		break;
5610Sstevel@tonic-gate 	case SC_INTEGER:
5620Sstevel@tonic-gate 		errno = 0;
5630Sstevel@tonic-gate 		v->sc_u.sc_integer = strtoll((char *)value, &endptr, 10);
5640Sstevel@tonic-gate 		if (errno != 0 || *endptr)
5650Sstevel@tonic-gate 			uu_die(gettext("illegal value \"%s\" for "
5660Sstevel@tonic-gate 			    "%s (%s)\n"), (char *)value,
5670Sstevel@tonic-gate 			    lxml_prop_types[type],
5680Sstevel@tonic-gate 			    (errno) ? strerror(errno) : "Illegal character");
5690Sstevel@tonic-gate 		break;
5700Sstevel@tonic-gate 	case SC_OPAQUE:
5710Sstevel@tonic-gate 	case SC_HOST:
5720Sstevel@tonic-gate 	case SC_HOSTNAME:
57312691SAntonello.Cruz@Sun.COM 	case SC_NET_ADDR:
5740Sstevel@tonic-gate 	case SC_NET_ADDR_V4:
5750Sstevel@tonic-gate 	case SC_NET_ADDR_V6:
5760Sstevel@tonic-gate 	case SC_FMRI:
5770Sstevel@tonic-gate 	case SC_URI:
5780Sstevel@tonic-gate 	case SC_TIME:
5790Sstevel@tonic-gate 	case SC_ASTRING:
5800Sstevel@tonic-gate 	case SC_USTRING:
58112667SSean.Wilcox@Sun.COM 		scf_type = lxml_element_to_type(type);
5820Sstevel@tonic-gate 
5830Sstevel@tonic-gate 		if ((v->sc_u.sc_string = strdup((char *)value)) == NULL)
5840Sstevel@tonic-gate 			uu_die(gettext("string duplication failed (%s)\n"),
5850Sstevel@tonic-gate 			    strerror(errno));
5860Sstevel@tonic-gate 		if (lxml_validate_string_value(scf_type,
5870Sstevel@tonic-gate 		    v->sc_u.sc_string) != 0)
5880Sstevel@tonic-gate 			uu_die(gettext("illegal value \"%s\" for "
5890Sstevel@tonic-gate 			    "%s (%s)\n"), (char *)value,
5900Sstevel@tonic-gate 			    lxml_prop_types[type],
5910Sstevel@tonic-gate 			    (scf_error()) ? scf_strerror(scf_error()) :
5920Sstevel@tonic-gate 			    gettext("Illegal format"));
5930Sstevel@tonic-gate 		v->sc_free = lxml_free_str;
5940Sstevel@tonic-gate 		break;
5950Sstevel@tonic-gate 	case SC_BOOLEAN:
5960Sstevel@tonic-gate 		v->sc_u.sc_count = lxml_xlate_boolean(value);
5970Sstevel@tonic-gate 		break;
5980Sstevel@tonic-gate 	default:
5990Sstevel@tonic-gate 		uu_die(gettext("unknown value type (%d)\n"), type);
6000Sstevel@tonic-gate 		break;
6010Sstevel@tonic-gate 	}
6020Sstevel@tonic-gate 
60312667SSean.Wilcox@Sun.COM 	/* Free the old value */
60412667SSean.Wilcox@Sun.COM 	if (fov && v->sc_free != NULL)
60512667SSean.Wilcox@Sun.COM 		free((char *)value);
60612667SSean.Wilcox@Sun.COM }
60712667SSean.Wilcox@Sun.COM 
60812667SSean.Wilcox@Sun.COM static value_t *
lxml_make_value(element_t type,const xmlChar * value)60912667SSean.Wilcox@Sun.COM lxml_make_value(element_t type, const xmlChar *value)
61012667SSean.Wilcox@Sun.COM {
61112667SSean.Wilcox@Sun.COM 	value_t *v;
61212667SSean.Wilcox@Sun.COM 
61312667SSean.Wilcox@Sun.COM 	v = internal_value_new();
61412667SSean.Wilcox@Sun.COM 
61512667SSean.Wilcox@Sun.COM 	v->sc_type = lxml_element_to_type(type);
61612667SSean.Wilcox@Sun.COM 
61712667SSean.Wilcox@Sun.COM 	lxml_store_value(v, type, value);
61812667SSean.Wilcox@Sun.COM 
6190Sstevel@tonic-gate 	return (v);
6200Sstevel@tonic-gate }
6210Sstevel@tonic-gate 
6220Sstevel@tonic-gate static int
lxml_get_value(property_t * prop,element_t vtype,xmlNodePtr value)6230Sstevel@tonic-gate lxml_get_value(property_t *prop, element_t vtype, xmlNodePtr value)
6240Sstevel@tonic-gate {
6250Sstevel@tonic-gate 	xmlNodePtr cursor;
6260Sstevel@tonic-gate 
6270Sstevel@tonic-gate 	for (cursor = value->xmlChildrenNode; cursor != NULL;
6280Sstevel@tonic-gate 	    cursor = cursor->next) {
6290Sstevel@tonic-gate 		xmlChar *assigned_value;
6300Sstevel@tonic-gate 		value_t *v;
6310Sstevel@tonic-gate 
6320Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
6330Sstevel@tonic-gate 			continue;
6340Sstevel@tonic-gate 
6350Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
6360Sstevel@tonic-gate 		case SC_VALUE_NODE:
6370Sstevel@tonic-gate 			if ((assigned_value = xmlGetProp(cursor,
6380Sstevel@tonic-gate 			    (xmlChar *)value_attr)) == NULL)
6390Sstevel@tonic-gate 				uu_die(gettext("no value on value node?\n"));
6400Sstevel@tonic-gate 			break;
6410Sstevel@tonic-gate 		default:
6420Sstevel@tonic-gate 			uu_die(gettext("value list contains illegal element "
6430Sstevel@tonic-gate 			    "\'%s\'\n"), cursor->name);
6440Sstevel@tonic-gate 			break;
6450Sstevel@tonic-gate 		}
6460Sstevel@tonic-gate 
6470Sstevel@tonic-gate 		v = lxml_make_value(vtype, assigned_value);
6480Sstevel@tonic-gate 
6490Sstevel@tonic-gate 		xmlFree(assigned_value);
6500Sstevel@tonic-gate 
6510Sstevel@tonic-gate 		internal_attach_value(prop, v);
6520Sstevel@tonic-gate 	}
6530Sstevel@tonic-gate 
6540Sstevel@tonic-gate 	return (0);
6550Sstevel@tonic-gate }
6560Sstevel@tonic-gate 
6570Sstevel@tonic-gate static int
lxml_get_propval(pgroup_t * pgrp,xmlNodePtr propval)6580Sstevel@tonic-gate lxml_get_propval(pgroup_t *pgrp, xmlNodePtr propval)
6590Sstevel@tonic-gate {
6600Sstevel@tonic-gate 	property_t *p;
6610Sstevel@tonic-gate 	element_t r;
6620Sstevel@tonic-gate 	value_t *v;
6630Sstevel@tonic-gate 	xmlChar *type, *val, *override;
66412667SSean.Wilcox@Sun.COM 	int op = pgrp->sc_parent->sc_op;
6650Sstevel@tonic-gate 
6660Sstevel@tonic-gate 	p = internal_property_new();
6670Sstevel@tonic-gate 
6680Sstevel@tonic-gate 	p->sc_property_name = (char *)xmlGetProp(propval, (xmlChar *)name_attr);
6697887SLiane.Praza@Sun.COM 	if ((p->sc_property_name == NULL) || (*p->sc_property_name == 0))
6700Sstevel@tonic-gate 		uu_die(gettext("property name missing in group '%s'\n"),
6710Sstevel@tonic-gate 		    pgrp->sc_pgroup_name);
6720Sstevel@tonic-gate 
6730Sstevel@tonic-gate 	type = xmlGetProp(propval, (xmlChar *)type_attr);
67412667SSean.Wilcox@Sun.COM 	if ((type != NULL) && (*type != 0)) {
67512667SSean.Wilcox@Sun.COM 		for (r = 0;
67612667SSean.Wilcox@Sun.COM 		    r < sizeof (lxml_prop_types) / sizeof (char *); ++r) {
67712667SSean.Wilcox@Sun.COM 			if (xmlStrcmp(type,
67812667SSean.Wilcox@Sun.COM 			    (const xmlChar *)lxml_prop_types[r]) == 0)
67912667SSean.Wilcox@Sun.COM 				break;
68012667SSean.Wilcox@Sun.COM 		}
68112667SSean.Wilcox@Sun.COM 
68212667SSean.Wilcox@Sun.COM 		if (r >= sizeof (lxml_prop_types) / sizeof (char *))
68312667SSean.Wilcox@Sun.COM 			uu_die(gettext("property type invalid for "
68412667SSean.Wilcox@Sun.COM 			    "property '%s/%s'\n"), pgrp->sc_pgroup_name,
68512667SSean.Wilcox@Sun.COM 			    p->sc_property_name);
68612667SSean.Wilcox@Sun.COM 
68712667SSean.Wilcox@Sun.COM 		p->sc_value_type = lxml_element_to_type(r);
68812667SSean.Wilcox@Sun.COM 	} else if (op == SVCCFG_OP_APPLY) {
68912667SSean.Wilcox@Sun.COM 		/*
69012667SSean.Wilcox@Sun.COM 		 * Store the property type as invalid, and the value
69112667SSean.Wilcox@Sun.COM 		 * as an ASTRING and let the bundle apply code validate
69212667SSean.Wilcox@Sun.COM 		 * the type/value once the type is found.
69312667SSean.Wilcox@Sun.COM 		 */
69412667SSean.Wilcox@Sun.COM 		est->sc_miss_type = B_TRUE;
69512667SSean.Wilcox@Sun.COM 		p->sc_value_type = SCF_TYPE_INVALID;
69612667SSean.Wilcox@Sun.COM 		r = SC_ASTRING;
69712667SSean.Wilcox@Sun.COM 	} else {
6980Sstevel@tonic-gate 		uu_die(gettext("property type missing for property '%s/%s'\n"),
6990Sstevel@tonic-gate 		    pgrp->sc_pgroup_name, p->sc_property_name);
7000Sstevel@tonic-gate 	}
7010Sstevel@tonic-gate 
7020Sstevel@tonic-gate 	val = xmlGetProp(propval, (xmlChar *)value_attr);
7030Sstevel@tonic-gate 	if (val == NULL)
7040Sstevel@tonic-gate 		uu_die(gettext("property value missing for property '%s/%s'\n"),
7050Sstevel@tonic-gate 		    pgrp->sc_pgroup_name, p->sc_property_name);
7060Sstevel@tonic-gate 
7070Sstevel@tonic-gate 	v = lxml_make_value(r, val);
7087887SLiane.Praza@Sun.COM 	xmlFree(val);
7090Sstevel@tonic-gate 	internal_attach_value(p, v);
7100Sstevel@tonic-gate 
71112667SSean.Wilcox@Sun.COM 	xmlFree(type);
71212667SSean.Wilcox@Sun.COM 
7130Sstevel@tonic-gate 	override = xmlGetProp(propval, (xmlChar *)override_attr);
7140Sstevel@tonic-gate 	p->sc_property_override = (xmlStrcmp(override, (xmlChar *)true) == 0);
7150Sstevel@tonic-gate 	xmlFree(override);
7160Sstevel@tonic-gate 
7170Sstevel@tonic-gate 	return (internal_attach_property(pgrp, p));
7180Sstevel@tonic-gate }
7190Sstevel@tonic-gate 
7200Sstevel@tonic-gate static int
lxml_get_property(pgroup_t * pgrp,xmlNodePtr property)7210Sstevel@tonic-gate lxml_get_property(pgroup_t *pgrp, xmlNodePtr property)
7220Sstevel@tonic-gate {
7230Sstevel@tonic-gate 	property_t *p;
7240Sstevel@tonic-gate 	xmlNodePtr cursor;
7250Sstevel@tonic-gate 	element_t r;
7260Sstevel@tonic-gate 	xmlChar *type, *override;
72712667SSean.Wilcox@Sun.COM 	int op = pgrp->sc_parent->sc_op;
7280Sstevel@tonic-gate 
7290Sstevel@tonic-gate 	p = internal_property_new();
7300Sstevel@tonic-gate 
7317887SLiane.Praza@Sun.COM 	if (((p->sc_property_name = (char *)xmlGetProp(property,
7327887SLiane.Praza@Sun.COM 	    (xmlChar *)name_attr)) == NULL) || (*p->sc_property_name == 0))
7330Sstevel@tonic-gate 		uu_die(gettext("property name missing in group \'%s\'\n"),
7340Sstevel@tonic-gate 		    pgrp->sc_pgroup_name);
7350Sstevel@tonic-gate 
73612667SSean.Wilcox@Sun.COM 	type = xmlGetProp(property, (xmlChar *)type_attr);
73712667SSean.Wilcox@Sun.COM 	if ((type != NULL) && (*type != 0)) {
73812667SSean.Wilcox@Sun.COM 		for (r = 0;
73912667SSean.Wilcox@Sun.COM 		    r < sizeof (lxml_prop_types) / sizeof (char *); r++) {
74012667SSean.Wilcox@Sun.COM 			if (xmlStrcmp(type,
74112667SSean.Wilcox@Sun.COM 			    (const xmlChar *)lxml_prop_types[r]) == 0)
74212667SSean.Wilcox@Sun.COM 				break;
74312667SSean.Wilcox@Sun.COM 		}
74412667SSean.Wilcox@Sun.COM 
74512667SSean.Wilcox@Sun.COM 		if (r >= sizeof (lxml_prop_types) / sizeof (char *))
74612667SSean.Wilcox@Sun.COM 			uu_die(gettext("property type invalid for "
74712667SSean.Wilcox@Sun.COM 			    "property '%s/%s'\n"), pgrp->sc_pgroup_name,
74812667SSean.Wilcox@Sun.COM 			    p->sc_property_name);
74912667SSean.Wilcox@Sun.COM 
75012667SSean.Wilcox@Sun.COM 		p->sc_value_type = lxml_element_to_type(r);
75112667SSean.Wilcox@Sun.COM 	} else if (op == SVCCFG_OP_APPLY) {
75212667SSean.Wilcox@Sun.COM 		/*
75312667SSean.Wilcox@Sun.COM 		 * Store the property type as invalid, and let the bundle apply
75412667SSean.Wilcox@Sun.COM 		 * code validate the type/value once the type is found.
75512667SSean.Wilcox@Sun.COM 		 */
75612667SSean.Wilcox@Sun.COM 		p->sc_value_type = SCF_TYPE_INVALID;
75712667SSean.Wilcox@Sun.COM 		est->sc_miss_type = B_TRUE;
75812667SSean.Wilcox@Sun.COM 	} else {
7590Sstevel@tonic-gate 		uu_die(gettext("property type missing for "
7600Sstevel@tonic-gate 		    "property \'%s/%s\'\n"), pgrp->sc_pgroup_name,
7610Sstevel@tonic-gate 		    p->sc_property_name);
7627887SLiane.Praza@Sun.COM 	}
7630Sstevel@tonic-gate 
7640Sstevel@tonic-gate 	for (cursor = property->xmlChildrenNode; cursor != NULL;
7650Sstevel@tonic-gate 	    cursor = cursor->next) {
7660Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
7670Sstevel@tonic-gate 			continue;
7680Sstevel@tonic-gate 
7690Sstevel@tonic-gate 		switch (r = lxml_xlate_element(cursor->name)) {
7700Sstevel@tonic-gate 		case SC_ASTRING:
7710Sstevel@tonic-gate 		case SC_BOOLEAN:
7720Sstevel@tonic-gate 		case SC_COUNT:
7730Sstevel@tonic-gate 		case SC_FMRI:
7740Sstevel@tonic-gate 		case SC_HOST:
7750Sstevel@tonic-gate 		case SC_HOSTNAME:
7760Sstevel@tonic-gate 		case SC_INTEGER:
77712691SAntonello.Cruz@Sun.COM 		case SC_NET_ADDR:
7780Sstevel@tonic-gate 		case SC_NET_ADDR_V4:
7790Sstevel@tonic-gate 		case SC_NET_ADDR_V6:
7800Sstevel@tonic-gate 		case SC_OPAQUE:
7810Sstevel@tonic-gate 		case SC_TIME:
7820Sstevel@tonic-gate 		case SC_URI:
7830Sstevel@tonic-gate 		case SC_USTRING:
78412667SSean.Wilcox@Sun.COM 			/*
78512667SSean.Wilcox@Sun.COM 			 * If the type is invalid then this is an apply
78612667SSean.Wilcox@Sun.COM 			 * operation and the type can be taken from the
78712667SSean.Wilcox@Sun.COM 			 * value list.
78812667SSean.Wilcox@Sun.COM 			 */
78912667SSean.Wilcox@Sun.COM 			if (p->sc_value_type == SCF_TYPE_INVALID) {
79012667SSean.Wilcox@Sun.COM 				p->sc_value_type = lxml_element_to_type(r);
79112667SSean.Wilcox@Sun.COM 				type = xmlStrdup((const
79212667SSean.Wilcox@Sun.COM 				    xmlChar *)lxml_prop_types[r]);
79312667SSean.Wilcox@Sun.COM 
79412667SSean.Wilcox@Sun.COM 			} else if (strcmp(lxml_prop_types[r],
79512667SSean.Wilcox@Sun.COM 			    (const char *)type) != 0) {
7960Sstevel@tonic-gate 				uu_die(gettext("property \'%s\' "
7970Sstevel@tonic-gate 				    "type-to-list mismatch\n"),
7980Sstevel@tonic-gate 				    p->sc_property_name);
79912667SSean.Wilcox@Sun.COM 			}
8000Sstevel@tonic-gate 
8010Sstevel@tonic-gate 			(void) lxml_get_value(p, r, cursor);
8020Sstevel@tonic-gate 			break;
8030Sstevel@tonic-gate 		default:
8040Sstevel@tonic-gate 			uu_die(gettext("unknown value list type: %s\n"),
8050Sstevel@tonic-gate 			    cursor->name);
8060Sstevel@tonic-gate 			break;
8070Sstevel@tonic-gate 		}
8080Sstevel@tonic-gate 	}
8090Sstevel@tonic-gate 
8100Sstevel@tonic-gate 	xmlFree(type);
8110Sstevel@tonic-gate 
8120Sstevel@tonic-gate 	override = xmlGetProp(property, (xmlChar *)override_attr);
8130Sstevel@tonic-gate 	p->sc_property_override = (xmlStrcmp(override, (xmlChar *)true) == 0);
8140Sstevel@tonic-gate 	xmlFree(override);
8150Sstevel@tonic-gate 
8160Sstevel@tonic-gate 	return (internal_attach_property(pgrp, p));
8170Sstevel@tonic-gate }
8180Sstevel@tonic-gate 
8190Sstevel@tonic-gate static int
lxml_get_pgroup_stability(pgroup_t * pgrp,xmlNodePtr stab)8200Sstevel@tonic-gate lxml_get_pgroup_stability(pgroup_t *pgrp, xmlNodePtr stab)
8210Sstevel@tonic-gate {
82212667SSean.Wilcox@Sun.COM 	if (pgrp->sc_parent->sc_op == SVCCFG_OP_APPLY)
82312667SSean.Wilcox@Sun.COM 		lxml_validate_element(stab);
82412667SSean.Wilcox@Sun.COM 
8250Sstevel@tonic-gate 	return (new_str_prop_from_attr(pgrp, SCF_PROPERTY_STABILITY,
8260Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, stab, value_attr));
8270Sstevel@tonic-gate }
8280Sstevel@tonic-gate 
8290Sstevel@tonic-gate /*
8300Sstevel@tonic-gate  * Property groups can go on any of a service, an instance, or a template.
8310Sstevel@tonic-gate  */
8320Sstevel@tonic-gate static int
lxml_get_pgroup(entity_t * entity,xmlNodePtr pgroup)8330Sstevel@tonic-gate lxml_get_pgroup(entity_t *entity, xmlNodePtr pgroup)
8340Sstevel@tonic-gate {
8350Sstevel@tonic-gate 	pgroup_t *pg;
8360Sstevel@tonic-gate 	xmlNodePtr cursor;
8370Sstevel@tonic-gate 	xmlChar *name, *type, *delete;
8380Sstevel@tonic-gate 
8390Sstevel@tonic-gate 	/*
8400Sstevel@tonic-gate 	 * property group attributes:
8410Sstevel@tonic-gate 	 * name: string
8420Sstevel@tonic-gate 	 * type: string | framework | application
8430Sstevel@tonic-gate 	 */
8440Sstevel@tonic-gate 	name = xmlGetProp(pgroup, (xmlChar *)name_attr);
8450Sstevel@tonic-gate 	type = xmlGetProp(pgroup, (xmlChar *)type_attr);
8460Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(entity, (char *)name, (char *)type);
8470Sstevel@tonic-gate 	xmlFree(name);
8480Sstevel@tonic-gate 	xmlFree(type);
8490Sstevel@tonic-gate 
8500Sstevel@tonic-gate 	/*
8510Sstevel@tonic-gate 	 * Walk the children of this lxml_elements, which are a stability
8520Sstevel@tonic-gate 	 * element, property elements, or propval elements.
8530Sstevel@tonic-gate 	 */
8540Sstevel@tonic-gate 	for (cursor = pgroup->xmlChildrenNode; cursor != NULL;
8550Sstevel@tonic-gate 	    cursor = cursor->next) {
8560Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
8570Sstevel@tonic-gate 			continue;
8580Sstevel@tonic-gate 
8590Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
8600Sstevel@tonic-gate 		case SC_STABILITY:
8610Sstevel@tonic-gate 			(void) lxml_get_pgroup_stability(pg, cursor);
8620Sstevel@tonic-gate 			break;
8630Sstevel@tonic-gate 		case SC_PROPERTY:
8640Sstevel@tonic-gate 			(void) lxml_get_property(pg, cursor);
8650Sstevel@tonic-gate 			break;
8660Sstevel@tonic-gate 		case SC_PROPVAL:
8670Sstevel@tonic-gate 			(void) lxml_get_propval(pg, cursor);
8680Sstevel@tonic-gate 			break;
8690Sstevel@tonic-gate 		default:
8700Sstevel@tonic-gate 			abort();
8710Sstevel@tonic-gate 			break;
8720Sstevel@tonic-gate 		}
8730Sstevel@tonic-gate 	}
8740Sstevel@tonic-gate 
8750Sstevel@tonic-gate 	delete = xmlGetProp(pgroup, (xmlChar *)delete_attr);
8760Sstevel@tonic-gate 	pg->sc_pgroup_delete = (xmlStrcmp(delete, (xmlChar *)true) == 0);
8770Sstevel@tonic-gate 	xmlFree(delete);
8780Sstevel@tonic-gate 
8790Sstevel@tonic-gate 	return (0);
8800Sstevel@tonic-gate }
8810Sstevel@tonic-gate 
8820Sstevel@tonic-gate 
8830Sstevel@tonic-gate /*
8840Sstevel@tonic-gate  * Dependency groups, execution methods can go on either a service or an
8850Sstevel@tonic-gate  * instance.
8860Sstevel@tonic-gate  */
8870Sstevel@tonic-gate 
8880Sstevel@tonic-gate static int
lxml_get_method_profile(pgroup_t * pg,xmlNodePtr profile)8890Sstevel@tonic-gate lxml_get_method_profile(pgroup_t *pg, xmlNodePtr profile)
8900Sstevel@tonic-gate {
8910Sstevel@tonic-gate 	property_t *p;
8920Sstevel@tonic-gate 
8930Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_USE_PROFILE, SCF_TYPE_BOOLEAN,
8940Sstevel@tonic-gate 	    1, (uint64_t)1);
8950Sstevel@tonic-gate 	if (internal_attach_property(pg, p) != 0)
8960Sstevel@tonic-gate 		return (-1);
8970Sstevel@tonic-gate 
8980Sstevel@tonic-gate 	return (new_str_prop_from_attr(pg, SCF_PROPERTY_PROFILE,
8990Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, profile, name_attr));
9000Sstevel@tonic-gate }
9010Sstevel@tonic-gate 
9020Sstevel@tonic-gate static int
lxml_get_method_credential(pgroup_t * pg,xmlNodePtr cred)9030Sstevel@tonic-gate lxml_get_method_credential(pgroup_t *pg, xmlNodePtr cred)
9040Sstevel@tonic-gate {
9050Sstevel@tonic-gate 	property_t *p;
9060Sstevel@tonic-gate 
9070Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_USE_PROFILE, SCF_TYPE_BOOLEAN,
9080Sstevel@tonic-gate 	    1, (uint64_t)0);
9090Sstevel@tonic-gate 	if (internal_attach_property(pg, p) != 0)
9100Sstevel@tonic-gate 		return (-1);
9110Sstevel@tonic-gate 
9129263SSean.Wilcox@Sun.COM 	if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_USER, SCF_TYPE_ASTRING,
9139263SSean.Wilcox@Sun.COM 	    cred, "user", NULL) != 0)
9140Sstevel@tonic-gate 		return (-1);
9150Sstevel@tonic-gate 
9169263SSean.Wilcox@Sun.COM 	if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_GROUP, SCF_TYPE_ASTRING,
9179263SSean.Wilcox@Sun.COM 	    cred, "group", NULL) != 0)
9180Sstevel@tonic-gate 		return (-1);
9190Sstevel@tonic-gate 
9209263SSean.Wilcox@Sun.COM 	if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_SUPP_GROUPS,
9219263SSean.Wilcox@Sun.COM 	    SCF_TYPE_ASTRING, cred, "supp_groups", NULL) != 0)
9220Sstevel@tonic-gate 		return (-1);
9230Sstevel@tonic-gate 
9249263SSean.Wilcox@Sun.COM 	if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_PRIVILEGES,
9259263SSean.Wilcox@Sun.COM 	    SCF_TYPE_ASTRING, cred, "privileges", NULL) != 0)
9260Sstevel@tonic-gate 		return (-1);
9270Sstevel@tonic-gate 
9289263SSean.Wilcox@Sun.COM 	if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_LIMIT_PRIVILEGES,
9299263SSean.Wilcox@Sun.COM 	    SCF_TYPE_ASTRING, cred, "limit_privileges", NULL) != 0)
9300Sstevel@tonic-gate 		return (-1);
9310Sstevel@tonic-gate 
9320Sstevel@tonic-gate 	return (0);
9330Sstevel@tonic-gate }
9340Sstevel@tonic-gate 
9350Sstevel@tonic-gate static char *
lxml_get_envvar(xmlNodePtr envvar)9360Sstevel@tonic-gate lxml_get_envvar(xmlNodePtr envvar)
9370Sstevel@tonic-gate {
9380Sstevel@tonic-gate 	char *name;
9390Sstevel@tonic-gate 	char *value;
9400Sstevel@tonic-gate 	char *ret;
9410Sstevel@tonic-gate 
9427887SLiane.Praza@Sun.COM 	name = (char *)xmlGetProp(envvar, (xmlChar *)name_attr);
9437887SLiane.Praza@Sun.COM 	value = (char *)xmlGetProp(envvar, (xmlChar *)value_attr);
9440Sstevel@tonic-gate 
9450Sstevel@tonic-gate 	if (strlen(name) == 0 || strchr(name, '=') != NULL)
9460Sstevel@tonic-gate 		uu_die(gettext("Invalid environment variable "
9470Sstevel@tonic-gate 		    "\"%s\".\n"), name);
9480Sstevel@tonic-gate 	if (strstr(name, "SMF_") == name)
9490Sstevel@tonic-gate 		uu_die(gettext("Invalid environment variable "
9500Sstevel@tonic-gate 		    "\"%s\"; \"SMF_\" prefix is reserved.\n"), name);
9510Sstevel@tonic-gate 
9520Sstevel@tonic-gate 	ret = uu_msprintf("%s=%s", name, value);
9530Sstevel@tonic-gate 	xmlFree(name);
9540Sstevel@tonic-gate 	xmlFree(value);
9550Sstevel@tonic-gate 	return (ret);
9560Sstevel@tonic-gate }
9570Sstevel@tonic-gate 
9580Sstevel@tonic-gate static int
lxml_get_method_environment(pgroup_t * pg,xmlNodePtr environment)9590Sstevel@tonic-gate lxml_get_method_environment(pgroup_t *pg, xmlNodePtr environment)
9600Sstevel@tonic-gate {
9610Sstevel@tonic-gate 	property_t *p;
9620Sstevel@tonic-gate 	xmlNodePtr cursor;
9630Sstevel@tonic-gate 	value_t *val;
9640Sstevel@tonic-gate 
9650Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_ENVIRONMENT,
9660Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, 0);
9670Sstevel@tonic-gate 
9680Sstevel@tonic-gate 	for (cursor = environment->xmlChildrenNode; cursor != NULL;
9690Sstevel@tonic-gate 	    cursor = cursor->next) {
9700Sstevel@tonic-gate 		char *tmp;
9710Sstevel@tonic-gate 
9720Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
9730Sstevel@tonic-gate 			continue;
9740Sstevel@tonic-gate 
9750Sstevel@tonic-gate 		if (lxml_xlate_element(cursor->name) != SC_METHOD_ENVVAR)
9760Sstevel@tonic-gate 			uu_die(gettext("illegal element \"%s\" on "
9770Sstevel@tonic-gate 			    "method environment for \"%s\"\n"),
9780Sstevel@tonic-gate 			    cursor->name, pg->sc_pgroup_name);
9790Sstevel@tonic-gate 
9800Sstevel@tonic-gate 		if ((tmp = lxml_get_envvar(cursor)) == NULL)
9810Sstevel@tonic-gate 			uu_die(gettext("Out of memory\n"));
9820Sstevel@tonic-gate 
9830Sstevel@tonic-gate 		val = internal_value_new();
9840Sstevel@tonic-gate 		val->sc_u.sc_string = tmp;
9850Sstevel@tonic-gate 		val->sc_type = SCF_TYPE_ASTRING;
9860Sstevel@tonic-gate 		val->sc_free = lxml_free_str;
9870Sstevel@tonic-gate 		internal_attach_value(p, val);
9880Sstevel@tonic-gate 	}
9890Sstevel@tonic-gate 
9900Sstevel@tonic-gate 	if (internal_attach_property(pg, p) != 0) {
9910Sstevel@tonic-gate 		internal_property_free(p);
9920Sstevel@tonic-gate 		return (-1);
9930Sstevel@tonic-gate 	}
9940Sstevel@tonic-gate 
9950Sstevel@tonic-gate 	return (0);
9960Sstevel@tonic-gate }
9970Sstevel@tonic-gate 
9980Sstevel@tonic-gate static int
lxml_get_method_context(pgroup_t * pg,xmlNodePtr ctx)9990Sstevel@tonic-gate lxml_get_method_context(pgroup_t *pg, xmlNodePtr ctx)
10000Sstevel@tonic-gate {
10010Sstevel@tonic-gate 	xmlNodePtr cursor;
10020Sstevel@tonic-gate 
10039263SSean.Wilcox@Sun.COM 	if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_WORKING_DIRECTORY,
10049263SSean.Wilcox@Sun.COM 	    SCF_TYPE_ASTRING, ctx, "working_directory", NULL) != 0)
10050Sstevel@tonic-gate 		return (-1);
10060Sstevel@tonic-gate 
10079263SSean.Wilcox@Sun.COM 	if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_PROJECT,
10089263SSean.Wilcox@Sun.COM 	    SCF_TYPE_ASTRING, ctx, "project", NULL) != 0)
10090Sstevel@tonic-gate 		return (-1);
10100Sstevel@tonic-gate 
10119263SSean.Wilcox@Sun.COM 	if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_RESOURCE_POOL,
10129263SSean.Wilcox@Sun.COM 	    SCF_TYPE_ASTRING, ctx, "resource_pool", NULL) != 0)
10130Sstevel@tonic-gate 		return (-1);
10140Sstevel@tonic-gate 
10150Sstevel@tonic-gate 	for (cursor = ctx->xmlChildrenNode; cursor != NULL;
10160Sstevel@tonic-gate 	    cursor = cursor->next) {
10170Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
10180Sstevel@tonic-gate 			continue;
10190Sstevel@tonic-gate 
10200Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
10210Sstevel@tonic-gate 		case SC_METHOD_CREDENTIAL:
10220Sstevel@tonic-gate 			(void) lxml_get_method_credential(pg, cursor);
10230Sstevel@tonic-gate 			break;
10240Sstevel@tonic-gate 		case SC_METHOD_PROFILE:
10250Sstevel@tonic-gate 			(void) lxml_get_method_profile(pg, cursor);
10260Sstevel@tonic-gate 			break;
10270Sstevel@tonic-gate 		case SC_METHOD_ENVIRONMENT:
10280Sstevel@tonic-gate 			(void) lxml_get_method_environment(pg, cursor);
10290Sstevel@tonic-gate 			break;
10300Sstevel@tonic-gate 		default:
10310Sstevel@tonic-gate 			semerr(gettext("illegal element \'%s\' in method "
10320Sstevel@tonic-gate 			    "context\n"), (char *)cursor);
10330Sstevel@tonic-gate 			break;
10340Sstevel@tonic-gate 		}
10350Sstevel@tonic-gate 	}
10360Sstevel@tonic-gate 
10370Sstevel@tonic-gate 	return (0);
10380Sstevel@tonic-gate }
10390Sstevel@tonic-gate 
10400Sstevel@tonic-gate static int
lxml_get_entity_method_context(entity_t * entity,xmlNodePtr ctx)10410Sstevel@tonic-gate lxml_get_entity_method_context(entity_t *entity, xmlNodePtr ctx)
10420Sstevel@tonic-gate {
10430Sstevel@tonic-gate 	pgroup_t *pg;
10440Sstevel@tonic-gate 
10450Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(entity, SCF_PG_METHOD_CONTEXT,
10460Sstevel@tonic-gate 	    (char *)scf_group_framework);
10470Sstevel@tonic-gate 
10480Sstevel@tonic-gate 	return (lxml_get_method_context(pg, ctx));
10490Sstevel@tonic-gate }
10500Sstevel@tonic-gate 
10510Sstevel@tonic-gate static int
lxml_get_exec_method(entity_t * entity,xmlNodePtr emeth)10520Sstevel@tonic-gate lxml_get_exec_method(entity_t *entity, xmlNodePtr emeth)
10530Sstevel@tonic-gate {
10540Sstevel@tonic-gate 	pgroup_t *pg;
10550Sstevel@tonic-gate 	property_t *p;
10560Sstevel@tonic-gate 	xmlChar *name, *timeout, *delete;
10570Sstevel@tonic-gate 	xmlNodePtr cursor;
10580Sstevel@tonic-gate 	int r = 0;
10590Sstevel@tonic-gate 
106012667SSean.Wilcox@Sun.COM 	if (entity->sc_op == SVCCFG_OP_APPLY)
106112667SSean.Wilcox@Sun.COM 		lxml_validate_element(emeth);
106212667SSean.Wilcox@Sun.COM 
10630Sstevel@tonic-gate 	name = xmlGetProp(emeth, (xmlChar *)name_attr);
10640Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(entity, (char *)name,
10650Sstevel@tonic-gate 	    (char *)SCF_GROUP_METHOD);
10660Sstevel@tonic-gate 	xmlFree(name);
10670Sstevel@tonic-gate 
10680Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_TYPE, SCF_TYPE_ASTRING,
10690Sstevel@tonic-gate 	    emeth, type_attr) != 0 ||
10700Sstevel@tonic-gate 	    new_str_prop_from_attr(pg, SCF_PROPERTY_EXEC, SCF_TYPE_ASTRING,
10710Sstevel@tonic-gate 	    emeth, "exec") != 0)
10720Sstevel@tonic-gate 		return (-1);
10730Sstevel@tonic-gate 
10747887SLiane.Praza@Sun.COM 	timeout = xmlGetProp(emeth, (xmlChar *)timeout_seconds_attr);
10750Sstevel@tonic-gate 	if (timeout != NULL) {
10760Sstevel@tonic-gate 		uint64_t u_timeout;
10770Sstevel@tonic-gate 		char *endptr;
10780Sstevel@tonic-gate 		/*
10790Sstevel@tonic-gate 		 * Although an SC_COUNT represents a uint64_t the use
10800Sstevel@tonic-gate 		 * of a negative value is acceptable due to the usage
10810Sstevel@tonic-gate 		 * established by inetd(1M).
10820Sstevel@tonic-gate 		 */
10830Sstevel@tonic-gate 		errno = 0;
10840Sstevel@tonic-gate 		u_timeout = strtoull((char *)timeout, &endptr, 10);
10850Sstevel@tonic-gate 		if (errno != 0 || endptr == (char *)timeout || *endptr)
10860Sstevel@tonic-gate 			uu_die(gettext("illegal value \"%s\" for "
10870Sstevel@tonic-gate 			    "timeout_seconds (%s)\n"),
10880Sstevel@tonic-gate 			    (char *)timeout, (errno) ? strerror(errno):
10890Sstevel@tonic-gate 			    gettext("Illegal character"));
10900Sstevel@tonic-gate 		p = internal_property_create(SCF_PROPERTY_TIMEOUT,
10910Sstevel@tonic-gate 		    SCF_TYPE_COUNT, 1, u_timeout);
10920Sstevel@tonic-gate 		r = internal_attach_property(pg, p);
10930Sstevel@tonic-gate 		xmlFree(timeout);
10940Sstevel@tonic-gate 	}
10950Sstevel@tonic-gate 	if (r != 0)
10960Sstevel@tonic-gate 		return (-1);
10970Sstevel@tonic-gate 
10980Sstevel@tonic-gate 	/*
10990Sstevel@tonic-gate 	 * There is a possibility that a method context also exists, in which
11000Sstevel@tonic-gate 	 * case the following attributes are defined: project, resource_pool,
11010Sstevel@tonic-gate 	 * working_directory, profile, user, group, privileges, limit_privileges
11020Sstevel@tonic-gate 	 */
11030Sstevel@tonic-gate 	for (cursor = emeth->xmlChildrenNode; cursor != NULL;
11040Sstevel@tonic-gate 	    cursor = cursor->next) {
11050Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
11060Sstevel@tonic-gate 			continue;
11070Sstevel@tonic-gate 
11080Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
11090Sstevel@tonic-gate 		case SC_STABILITY:
11100Sstevel@tonic-gate 			if (lxml_get_pgroup_stability(pg, cursor) != 0)
11110Sstevel@tonic-gate 				return (-1);
11120Sstevel@tonic-gate 			break;
11130Sstevel@tonic-gate 
11140Sstevel@tonic-gate 		case SC_METHOD_CONTEXT:
11150Sstevel@tonic-gate 			(void) lxml_get_method_context(pg, cursor);
11160Sstevel@tonic-gate 			break;
11170Sstevel@tonic-gate 
11180Sstevel@tonic-gate 		case SC_PROPVAL:
11190Sstevel@tonic-gate 			(void) lxml_get_propval(pg, cursor);
11200Sstevel@tonic-gate 			break;
11210Sstevel@tonic-gate 
11220Sstevel@tonic-gate 		case SC_PROPERTY:
11230Sstevel@tonic-gate 			(void) lxml_get_property(pg, cursor);
11240Sstevel@tonic-gate 			break;
11250Sstevel@tonic-gate 
11260Sstevel@tonic-gate 		default:
11270Sstevel@tonic-gate 			uu_die(gettext("illegal element \"%s\" on "
11280Sstevel@tonic-gate 			    "execution method \"%s\"\n"), cursor->name,
11290Sstevel@tonic-gate 			    pg->sc_pgroup_name);
11300Sstevel@tonic-gate 			break;
11310Sstevel@tonic-gate 		}
11320Sstevel@tonic-gate 	}
11330Sstevel@tonic-gate 
11340Sstevel@tonic-gate 	delete = xmlGetProp(emeth, (xmlChar *)delete_attr);
11350Sstevel@tonic-gate 	pg->sc_pgroup_delete = (xmlStrcmp(delete, (xmlChar *)true) == 0);
11360Sstevel@tonic-gate 	xmlFree(delete);
11370Sstevel@tonic-gate 
11380Sstevel@tonic-gate 	return (0);
11390Sstevel@tonic-gate }
11400Sstevel@tonic-gate 
11410Sstevel@tonic-gate static int
lxml_get_dependency(entity_t * entity,xmlNodePtr dependency)11420Sstevel@tonic-gate lxml_get_dependency(entity_t *entity, xmlNodePtr dependency)
11430Sstevel@tonic-gate {
11440Sstevel@tonic-gate 	pgroup_t *pg;
11450Sstevel@tonic-gate 	property_t *p;
11460Sstevel@tonic-gate 	xmlNodePtr cursor;
11470Sstevel@tonic-gate 	xmlChar *name;
11480Sstevel@tonic-gate 	xmlChar *delete;
11490Sstevel@tonic-gate 
11500Sstevel@tonic-gate 	/*
11510Sstevel@tonic-gate 	 * dependency attributes:
11520Sstevel@tonic-gate 	 * name: string
11530Sstevel@tonic-gate 	 * grouping: require_all | require_any | exclude_all | optional_all
11540Sstevel@tonic-gate 	 * reset_on: string (error | restart | refresh | none)
11550Sstevel@tonic-gate 	 * type:  service / path /host
11560Sstevel@tonic-gate 	 */
11570Sstevel@tonic-gate 
115812667SSean.Wilcox@Sun.COM 	if (entity->sc_op == SVCCFG_OP_APPLY)
115912667SSean.Wilcox@Sun.COM 		lxml_validate_element(dependency);
116012667SSean.Wilcox@Sun.COM 
11610Sstevel@tonic-gate 	name = xmlGetProp(dependency, (xmlChar *)name_attr);
11620Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(entity, (char *)name,
11630Sstevel@tonic-gate 	    (char *)SCF_GROUP_DEPENDENCY);
11640Sstevel@tonic-gate 	xmlFree(name);
11650Sstevel@tonic-gate 
11660Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_TYPE, SCF_TYPE_ASTRING,
11670Sstevel@tonic-gate 	    dependency, type_attr) != 0)
11680Sstevel@tonic-gate 		return (-1);
11690Sstevel@tonic-gate 
11700Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_RESTART_ON,
11710Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, dependency, "restart_on") != 0)
11720Sstevel@tonic-gate 		return (-1);
11730Sstevel@tonic-gate 
11740Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_GROUPING, SCF_TYPE_ASTRING,
11750Sstevel@tonic-gate 	    dependency, "grouping") != 0)
11760Sstevel@tonic-gate 		return (-1);
11770Sstevel@tonic-gate 
11780Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_ENTITIES, SCF_TYPE_FMRI, 0);
11790Sstevel@tonic-gate 	if (internal_attach_property(pg, p) != 0)
11800Sstevel@tonic-gate 		return (-1);
11810Sstevel@tonic-gate 
11820Sstevel@tonic-gate 	for (cursor = dependency->xmlChildrenNode; cursor != NULL;
11830Sstevel@tonic-gate 	    cursor = cursor->next) {
11840Sstevel@tonic-gate 		xmlChar *value;
11850Sstevel@tonic-gate 		value_t *v;
11860Sstevel@tonic-gate 
11870Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
11880Sstevel@tonic-gate 			continue;
11890Sstevel@tonic-gate 
11900Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
11910Sstevel@tonic-gate 		case SC_STABILITY:
11920Sstevel@tonic-gate 			if (lxml_get_pgroup_stability(pg, cursor) != 0)
11930Sstevel@tonic-gate 				return (-1);
11940Sstevel@tonic-gate 			break;
11950Sstevel@tonic-gate 
11960Sstevel@tonic-gate 		case SC_SERVICE_FMRI:
11970Sstevel@tonic-gate 			value = xmlGetProp(cursor, (xmlChar *)value_attr);
11980Sstevel@tonic-gate 			if (value != NULL) {
11990Sstevel@tonic-gate 				if (lxml_validate_string_value(SCF_TYPE_FMRI,
12000Sstevel@tonic-gate 				    (char *)value) != 0)
12010Sstevel@tonic-gate 					uu_die(gettext("illegal value \"%s\" "
12020Sstevel@tonic-gate 					    "for %s (%s)\n"), (char *)value,
12030Sstevel@tonic-gate 					    lxml_prop_types[SC_FMRI],
12040Sstevel@tonic-gate 					    (scf_error()) ?
12050Sstevel@tonic-gate 					    scf_strerror(scf_error()) :
12060Sstevel@tonic-gate 					    gettext("Illegal format"));
12070Sstevel@tonic-gate 				v = internal_value_new();
12080Sstevel@tonic-gate 				v->sc_type = SCF_TYPE_FMRI;
12090Sstevel@tonic-gate 				v->sc_u.sc_string = (char *)value;
12100Sstevel@tonic-gate 				internal_attach_value(p, v);
12110Sstevel@tonic-gate 			}
12120Sstevel@tonic-gate 
12130Sstevel@tonic-gate 			break;
12140Sstevel@tonic-gate 
12150Sstevel@tonic-gate 		case SC_PROPVAL:
12160Sstevel@tonic-gate 			(void) lxml_get_propval(pg, cursor);
12170Sstevel@tonic-gate 			break;
12180Sstevel@tonic-gate 
12190Sstevel@tonic-gate 		case SC_PROPERTY:
12200Sstevel@tonic-gate 			(void) lxml_get_property(pg, cursor);
12210Sstevel@tonic-gate 			break;
12220Sstevel@tonic-gate 
12230Sstevel@tonic-gate 		default:
12240Sstevel@tonic-gate 			uu_die(gettext("illegal element \"%s\" on "
12250Sstevel@tonic-gate 			    "dependency group \"%s\"\n"), cursor->name, name);
12260Sstevel@tonic-gate 			break;
12270Sstevel@tonic-gate 		}
12280Sstevel@tonic-gate 	}
12290Sstevel@tonic-gate 
12300Sstevel@tonic-gate 	delete = xmlGetProp(dependency, (xmlChar *)delete_attr);
12310Sstevel@tonic-gate 	pg->sc_pgroup_delete = (xmlStrcmp(delete, (xmlChar *)true) == 0);
12320Sstevel@tonic-gate 	xmlFree(delete);
12330Sstevel@tonic-gate 
12340Sstevel@tonic-gate 	return (0);
12350Sstevel@tonic-gate }
12360Sstevel@tonic-gate 
12370Sstevel@tonic-gate /*
12380Sstevel@tonic-gate  * Dependents are hairy.  They should cause a dependency pg to be created in
12390Sstevel@tonic-gate  * another service, but we can't do that here; we'll have to wait until the
12400Sstevel@tonic-gate  * import routines.  So for now we'll add the dependency group that should go
12410Sstevel@tonic-gate  * in the other service to the entity's dependent list.
12420Sstevel@tonic-gate  */
12430Sstevel@tonic-gate static int
lxml_get_dependent(entity_t * entity,xmlNodePtr dependent)12440Sstevel@tonic-gate lxml_get_dependent(entity_t *entity, xmlNodePtr dependent)
12450Sstevel@tonic-gate {
12460Sstevel@tonic-gate 	xmlChar *name, *or;
12470Sstevel@tonic-gate 	xmlNodePtr sf;
12480Sstevel@tonic-gate 	xmlChar *fmri, *delete;
12490Sstevel@tonic-gate 	pgroup_t *pg;
12500Sstevel@tonic-gate 	property_t *p;
12510Sstevel@tonic-gate 	xmlNodePtr n;
12520Sstevel@tonic-gate 	char *myfmri;
12530Sstevel@tonic-gate 
125412667SSean.Wilcox@Sun.COM 	if (entity->sc_op == SVCCFG_OP_APPLY)
125512667SSean.Wilcox@Sun.COM 		lxml_validate_element(dependent);
125612667SSean.Wilcox@Sun.COM 
12570Sstevel@tonic-gate 	name = xmlGetProp(dependent, (xmlChar *)name_attr);
12580Sstevel@tonic-gate 
12590Sstevel@tonic-gate 	if (internal_pgroup_find(entity, (char *)name, NULL) != NULL) {
12600Sstevel@tonic-gate 		semerr(gettext("Property group and dependent of entity %s "
12610Sstevel@tonic-gate 		    "have same name \"%s\".\n"), entity->sc_name, name);
12620Sstevel@tonic-gate 		xmlFree(name);
12630Sstevel@tonic-gate 		return (-1);
12640Sstevel@tonic-gate 	}
12650Sstevel@tonic-gate 
12660Sstevel@tonic-gate 	or = xmlGetProp(dependent, (xmlChar *)override_attr);
12670Sstevel@tonic-gate 
12680Sstevel@tonic-gate 	pg = internal_pgroup_new();
12690Sstevel@tonic-gate 	pg->sc_pgroup_name = (char *)name;
12700Sstevel@tonic-gate 	pg->sc_pgroup_type = (char *)SCF_GROUP_DEPENDENCY;
12710Sstevel@tonic-gate 	pg->sc_pgroup_override = (xmlStrcmp(or, (xmlChar *)true) == 0);
12720Sstevel@tonic-gate 	xmlFree(or);
12730Sstevel@tonic-gate 	if (internal_attach_dependent(entity, pg) != 0) {
12740Sstevel@tonic-gate 		xmlFree(name);
12750Sstevel@tonic-gate 		internal_pgroup_free(pg);
12760Sstevel@tonic-gate 		return (-1);
12770Sstevel@tonic-gate 	}
12780Sstevel@tonic-gate 
12790Sstevel@tonic-gate 	for (sf = dependent->children; sf != NULL; sf = sf->next)
12800Sstevel@tonic-gate 		if (xmlStrcmp(sf->name, (xmlChar *)"service_fmri") == 0)
12810Sstevel@tonic-gate 			break;
12820Sstevel@tonic-gate 	assert(sf != NULL);
12830Sstevel@tonic-gate 	fmri = xmlGetProp(sf, (xmlChar *)value_attr);
12840Sstevel@tonic-gate 	pg->sc_pgroup_fmri = (char *)fmri;
12850Sstevel@tonic-gate 
12860Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_RESTART_ON,
12870Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, dependent, "restart_on") != 0)
12880Sstevel@tonic-gate 		return (-1);
12890Sstevel@tonic-gate 
12900Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_GROUPING, SCF_TYPE_ASTRING,
12910Sstevel@tonic-gate 	    dependent, "grouping") != 0)
12920Sstevel@tonic-gate 		return (-1);
12930Sstevel@tonic-gate 
12940Sstevel@tonic-gate 	myfmri = safe_malloc(max_scf_fmri_len + 1);
12950Sstevel@tonic-gate 	if (entity->sc_etype == SVCCFG_SERVICE_OBJECT) {
12960Sstevel@tonic-gate 		if (snprintf(myfmri, max_scf_fmri_len + 1, "svc:/%s",
12970Sstevel@tonic-gate 		    entity->sc_name) < 0)
12980Sstevel@tonic-gate 			bad_error("snprintf", errno);
12990Sstevel@tonic-gate 	} else {
13000Sstevel@tonic-gate 		assert(entity->sc_etype == SVCCFG_INSTANCE_OBJECT);
13010Sstevel@tonic-gate 		if (snprintf(myfmri, max_scf_fmri_len + 1, "svc:/%s:%s",
13020Sstevel@tonic-gate 		    entity->sc_parent->sc_name, entity->sc_name) < 0)
13030Sstevel@tonic-gate 			bad_error("snprintf", errno);
13040Sstevel@tonic-gate 	}
13050Sstevel@tonic-gate 
13060Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_ENTITIES, SCF_TYPE_FMRI, 1,
13070Sstevel@tonic-gate 	    myfmri);
13080Sstevel@tonic-gate 	if (internal_attach_property(pg, p) != 0)
13090Sstevel@tonic-gate 		return (-1);
13100Sstevel@tonic-gate 
13110Sstevel@tonic-gate 	/* Create a property to serve as a do-not-export flag. */
13120Sstevel@tonic-gate 	p = internal_property_create("external", SCF_TYPE_BOOLEAN, 1,
13130Sstevel@tonic-gate 	    (uint64_t)1);
13140Sstevel@tonic-gate 	if (internal_attach_property(pg, p) != 0)
13150Sstevel@tonic-gate 		return (-1);
13160Sstevel@tonic-gate 
13170Sstevel@tonic-gate 	for (n = sf->next; n != NULL; n = n->next) {
13180Sstevel@tonic-gate 		if (lxml_ignorable_block(n))
13190Sstevel@tonic-gate 			continue;
13200Sstevel@tonic-gate 
13210Sstevel@tonic-gate 		switch (lxml_xlate_element(n->name)) {
13220Sstevel@tonic-gate 		case SC_STABILITY:
13230Sstevel@tonic-gate 			if (new_str_prop_from_attr(pg,
13240Sstevel@tonic-gate 			    SCF_PROPERTY_ENTITY_STABILITY, SCF_TYPE_ASTRING, n,
13250Sstevel@tonic-gate 			    value_attr) != 0)
13260Sstevel@tonic-gate 				return (-1);
13270Sstevel@tonic-gate 			break;
13280Sstevel@tonic-gate 
13290Sstevel@tonic-gate 		case SC_PROPVAL:
13300Sstevel@tonic-gate 			(void) lxml_get_propval(pg, n);
13310Sstevel@tonic-gate 			break;
13320Sstevel@tonic-gate 
13330Sstevel@tonic-gate 		case SC_PROPERTY:
13340Sstevel@tonic-gate 			(void) lxml_get_property(pg, n);
13350Sstevel@tonic-gate 			break;
13360Sstevel@tonic-gate 
13370Sstevel@tonic-gate 		default:
13380Sstevel@tonic-gate 			uu_die(gettext("unexpected element %s.\n"), n->name);
13390Sstevel@tonic-gate 		}
13400Sstevel@tonic-gate 	}
13410Sstevel@tonic-gate 
13420Sstevel@tonic-gate 	/* Go back and fill in defaults. */
13430Sstevel@tonic-gate 	if (internal_property_find(pg, SCF_PROPERTY_TYPE) == NULL) {
13440Sstevel@tonic-gate 		p = internal_property_create(SCF_PROPERTY_TYPE,
13450Sstevel@tonic-gate 		    SCF_TYPE_ASTRING, 1, "service");
13460Sstevel@tonic-gate 		if (internal_attach_property(pg, p) != 0)
13470Sstevel@tonic-gate 			return (-1);
13480Sstevel@tonic-gate 	}
13490Sstevel@tonic-gate 
13500Sstevel@tonic-gate 	delete = xmlGetProp(dependent, (xmlChar *)delete_attr);
13510Sstevel@tonic-gate 	pg->sc_pgroup_delete = (xmlStrcmp(delete, (xmlChar *)true) == 0);
13520Sstevel@tonic-gate 	xmlFree(delete);
13530Sstevel@tonic-gate 
13540Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(entity, "dependents",
13550Sstevel@tonic-gate 	    (char *)scf_group_framework);
1356306Sbustos 	p = internal_property_create((char *)name, SCF_TYPE_FMRI, 1, fmri);
13570Sstevel@tonic-gate 	if (internal_attach_property(pg, p) != 0)
13580Sstevel@tonic-gate 		return (-1);
13590Sstevel@tonic-gate 
13600Sstevel@tonic-gate 	return (0);
13610Sstevel@tonic-gate }
13620Sstevel@tonic-gate 
13630Sstevel@tonic-gate static int
lxml_get_entity_stability(entity_t * entity,xmlNodePtr rstr)13640Sstevel@tonic-gate lxml_get_entity_stability(entity_t *entity, xmlNodePtr rstr)
13650Sstevel@tonic-gate {
13660Sstevel@tonic-gate 	pgroup_t *pg;
13670Sstevel@tonic-gate 	property_t *p;
13680Sstevel@tonic-gate 	xmlChar *stabval;
13690Sstevel@tonic-gate 
13707887SLiane.Praza@Sun.COM 	if (((stabval = xmlGetProp(rstr, (xmlChar *)value_attr)) == NULL) ||
13717887SLiane.Praza@Sun.COM 	    (*stabval == 0)) {
13720Sstevel@tonic-gate 		uu_warn(gettext("no stability value found\n"));
13730Sstevel@tonic-gate 		stabval = (xmlChar *)strdup("External");
13740Sstevel@tonic-gate 	}
13750Sstevel@tonic-gate 
13760Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(entity, (char *)scf_pg_general,
13770Sstevel@tonic-gate 	    (char *)scf_group_framework);
13780Sstevel@tonic-gate 
13790Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_ENTITY_STABILITY,
13800Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, 1, stabval);
13810Sstevel@tonic-gate 
13820Sstevel@tonic-gate 	return (internal_attach_property(pg, p));
13830Sstevel@tonic-gate }
13840Sstevel@tonic-gate 
13850Sstevel@tonic-gate static int
lxml_get_restarter(entity_t * entity,xmlNodePtr rstr)13860Sstevel@tonic-gate lxml_get_restarter(entity_t *entity, xmlNodePtr rstr)
13870Sstevel@tonic-gate {
13880Sstevel@tonic-gate 	pgroup_t *pg;
13890Sstevel@tonic-gate 	property_t *p;
13900Sstevel@tonic-gate 	xmlChar *restarter;
13910Sstevel@tonic-gate 	xmlNode *cursor;
13920Sstevel@tonic-gate 	int r;
13930Sstevel@tonic-gate 
13940Sstevel@tonic-gate 	/*
13950Sstevel@tonic-gate 	 * Go find child.  Child is a service_fmri element.  value attribute
13960Sstevel@tonic-gate 	 * contains restarter FMRI.
13970Sstevel@tonic-gate 	 */
13980Sstevel@tonic-gate 
13990Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(entity, (char *)scf_pg_general,
14000Sstevel@tonic-gate 	    (char *)scf_group_framework);
14010Sstevel@tonic-gate 
14020Sstevel@tonic-gate 	/*
14030Sstevel@tonic-gate 	 * Walk its child elements, as appropriate.
14040Sstevel@tonic-gate 	 */
14050Sstevel@tonic-gate 	for (cursor = rstr->xmlChildrenNode; cursor != NULL;
14060Sstevel@tonic-gate 	    cursor = cursor->next) {
14070Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
14080Sstevel@tonic-gate 			continue;
14090Sstevel@tonic-gate 
14100Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
14110Sstevel@tonic-gate 		case SC_SERVICE_FMRI:
14120Sstevel@tonic-gate 			restarter = xmlGetProp(cursor, (xmlChar *)value_attr);
14130Sstevel@tonic-gate 			break;
14140Sstevel@tonic-gate 		default:
14150Sstevel@tonic-gate 			uu_die(gettext("illegal element \"%s\" on restarter "
14160Sstevel@tonic-gate 			    "element for \"%s\"\n"), cursor->name,
14170Sstevel@tonic-gate 			    entity->sc_name);
14180Sstevel@tonic-gate 			break;
14190Sstevel@tonic-gate 		}
14200Sstevel@tonic-gate 	}
14210Sstevel@tonic-gate 
14220Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_RESTARTER, SCF_TYPE_FMRI, 1,
14230Sstevel@tonic-gate 	    restarter);
14240Sstevel@tonic-gate 
14250Sstevel@tonic-gate 	r = internal_attach_property(pg, p);
14260Sstevel@tonic-gate 	if (r != 0) {
14270Sstevel@tonic-gate 		internal_property_free(p);
14280Sstevel@tonic-gate 		return (-1);
14290Sstevel@tonic-gate 	}
14300Sstevel@tonic-gate 
14310Sstevel@tonic-gate 	return (0);
14320Sstevel@tonic-gate }
14330Sstevel@tonic-gate 
1434*12967Sgavin.maltby@oracle.com static void
lxml_get_paramval(pgroup_t * pgrp,const char * propname,xmlNodePtr pval)1435*12967Sgavin.maltby@oracle.com lxml_get_paramval(pgroup_t *pgrp, const char *propname, xmlNodePtr pval)
1436*12967Sgavin.maltby@oracle.com {
1437*12967Sgavin.maltby@oracle.com 	property_t *p;
1438*12967Sgavin.maltby@oracle.com 	char *value;
1439*12967Sgavin.maltby@oracle.com 	char *prop;
1440*12967Sgavin.maltby@oracle.com 
1441*12967Sgavin.maltby@oracle.com 	if ((prop = strdup(propname)) == NULL)
1442*12967Sgavin.maltby@oracle.com 		uu_die(gettext("Out of memory.\n"));
1443*12967Sgavin.maltby@oracle.com 
1444*12967Sgavin.maltby@oracle.com 	value = (char *)xmlGetProp(pval, (xmlChar *)value_attr);
1445*12967Sgavin.maltby@oracle.com 	if (value == NULL || *value == '\0')
1446*12967Sgavin.maltby@oracle.com 		uu_die(gettext("property value missing for property '%s/%s'\n"),
1447*12967Sgavin.maltby@oracle.com 		    pgrp->sc_pgroup_name, propname);
1448*12967Sgavin.maltby@oracle.com 	p = internal_property_create(prop, SCF_TYPE_ASTRING, 1, value);
1449*12967Sgavin.maltby@oracle.com 
1450*12967Sgavin.maltby@oracle.com 	(void) internal_attach_property(pgrp, p);
1451*12967Sgavin.maltby@oracle.com }
1452*12967Sgavin.maltby@oracle.com 
1453*12967Sgavin.maltby@oracle.com static void
lxml_get_parameter(pgroup_t * pgrp,const char * propname,xmlNodePtr param)1454*12967Sgavin.maltby@oracle.com lxml_get_parameter(pgroup_t *pgrp, const char *propname, xmlNodePtr param)
1455*12967Sgavin.maltby@oracle.com {
1456*12967Sgavin.maltby@oracle.com 	property_t *p = internal_property_new();
1457*12967Sgavin.maltby@oracle.com 
1458*12967Sgavin.maltby@oracle.com 	if ((p->sc_property_name = strdup(propname)) == NULL)
1459*12967Sgavin.maltby@oracle.com 		uu_die(gettext("Out of memory.\n"));
1460*12967Sgavin.maltby@oracle.com 	p->sc_value_type = SCF_TYPE_ASTRING;
1461*12967Sgavin.maltby@oracle.com 
1462*12967Sgavin.maltby@oracle.com 	(void) lxml_get_value(p, SC_ASTRING, param);
1463*12967Sgavin.maltby@oracle.com 
1464*12967Sgavin.maltby@oracle.com 	(void) internal_attach_property(pgrp, p);
1465*12967Sgavin.maltby@oracle.com }
1466*12967Sgavin.maltby@oracle.com 
1467*12967Sgavin.maltby@oracle.com static void
lxml_get_type(pgroup_t * pgrp,xmlNodePtr type)1468*12967Sgavin.maltby@oracle.com lxml_get_type(pgroup_t *pgrp, xmlNodePtr type)
1469*12967Sgavin.maltby@oracle.com {
1470*12967Sgavin.maltby@oracle.com 	property_t *p;
1471*12967Sgavin.maltby@oracle.com 	xmlChar *name;
1472*12967Sgavin.maltby@oracle.com 	xmlChar *active;
1473*12967Sgavin.maltby@oracle.com 	xmlNodePtr cursor;
1474*12967Sgavin.maltby@oracle.com 	uint64_t active_val;
1475*12967Sgavin.maltby@oracle.com 	size_t sz = max_scf_name_len + 1;
1476*12967Sgavin.maltby@oracle.com 	char *propname = safe_malloc(sz);
1477*12967Sgavin.maltby@oracle.com 
1478*12967Sgavin.maltby@oracle.com 	if (pgrp->sc_parent->sc_op == SVCCFG_OP_APPLY)
1479*12967Sgavin.maltby@oracle.com 		lxml_validate_element(type);
1480*12967Sgavin.maltby@oracle.com 
1481*12967Sgavin.maltby@oracle.com 	name = xmlGetProp(type, (xmlChar *)name_attr);
1482*12967Sgavin.maltby@oracle.com 	if (name == NULL || *name == '\0')
1483*12967Sgavin.maltby@oracle.com 		uu_die(gettext("attribute name missing in element 'type'\n"));
1484*12967Sgavin.maltby@oracle.com 
1485*12967Sgavin.maltby@oracle.com 	for (cursor = type->xmlChildrenNode; cursor != NULL;
1486*12967Sgavin.maltby@oracle.com 	    cursor = cursor->next) {
1487*12967Sgavin.maltby@oracle.com 		xmlChar *pname;
1488*12967Sgavin.maltby@oracle.com 
1489*12967Sgavin.maltby@oracle.com 		if (lxml_ignorable_block(cursor))
1490*12967Sgavin.maltby@oracle.com 			continue;
1491*12967Sgavin.maltby@oracle.com 
1492*12967Sgavin.maltby@oracle.com 		pname = xmlGetProp(cursor, (xmlChar *)name_attr);
1493*12967Sgavin.maltby@oracle.com 		if (pname == NULL || *pname == '\0')
1494*12967Sgavin.maltby@oracle.com 			uu_die(gettext(
1495*12967Sgavin.maltby@oracle.com 			    "attribute name missing in sub-element of type\n"));
1496*12967Sgavin.maltby@oracle.com 
1497*12967Sgavin.maltby@oracle.com 		if (snprintf(propname, sz, "%s,%s", (char *)name,
1498*12967Sgavin.maltby@oracle.com 		    (char *)pname) >= sz)
1499*12967Sgavin.maltby@oracle.com 			uu_die(gettext("name '%s,%s' is too long\n"),
1500*12967Sgavin.maltby@oracle.com 			    (char *)name, (char *)pname);
1501*12967Sgavin.maltby@oracle.com 		xmlFree(pname);
1502*12967Sgavin.maltby@oracle.com 
1503*12967Sgavin.maltby@oracle.com 		switch (lxml_xlate_element(cursor->name)) {
1504*12967Sgavin.maltby@oracle.com 		case SC_PARAMETER:
1505*12967Sgavin.maltby@oracle.com 			lxml_get_parameter(pgrp, propname, cursor);
1506*12967Sgavin.maltby@oracle.com 			break;
1507*12967Sgavin.maltby@oracle.com 
1508*12967Sgavin.maltby@oracle.com 		case SC_PARAMVAL:
1509*12967Sgavin.maltby@oracle.com 			lxml_get_paramval(pgrp, propname, cursor);
1510*12967Sgavin.maltby@oracle.com 			break;
1511*12967Sgavin.maltby@oracle.com 
1512*12967Sgavin.maltby@oracle.com 		default:
1513*12967Sgavin.maltby@oracle.com 			uu_die(gettext("unknown element %s\n"), cursor->name);
1514*12967Sgavin.maltby@oracle.com 		}
1515*12967Sgavin.maltby@oracle.com 	}
1516*12967Sgavin.maltby@oracle.com 
1517*12967Sgavin.maltby@oracle.com 	active = xmlGetProp(type, (xmlChar *)active_attr);
1518*12967Sgavin.maltby@oracle.com 	if (active == NULL || strcmp(true, (const char *)active) == 0)
1519*12967Sgavin.maltby@oracle.com 		active_val = 1;
1520*12967Sgavin.maltby@oracle.com 	else
1521*12967Sgavin.maltby@oracle.com 		active_val = 0;
1522*12967Sgavin.maltby@oracle.com 	xmlFree(active);
1523*12967Sgavin.maltby@oracle.com 
1524*12967Sgavin.maltby@oracle.com 	if (snprintf(propname, sz, "%s,%s", (char *)name,
1525*12967Sgavin.maltby@oracle.com 	    SCF_PROPERTY_ACTIVE_POSTFIX) >= sz)
1526*12967Sgavin.maltby@oracle.com 		uu_die(gettext("name '%s,%s' is too long\n"),
1527*12967Sgavin.maltby@oracle.com 		    (char *)name, SCF_PROPERTY_ACTIVE_POSTFIX);
1528*12967Sgavin.maltby@oracle.com 
1529*12967Sgavin.maltby@oracle.com 	p = internal_property_create(propname, SCF_TYPE_BOOLEAN, 1, active_val);
1530*12967Sgavin.maltby@oracle.com 
1531*12967Sgavin.maltby@oracle.com 	(void) internal_attach_property(pgrp, p);
1532*12967Sgavin.maltby@oracle.com 
1533*12967Sgavin.maltby@oracle.com 	xmlFree(name);
1534*12967Sgavin.maltby@oracle.com }
1535*12967Sgavin.maltby@oracle.com 
1536*12967Sgavin.maltby@oracle.com static void
lxml_get_event(entity_t * entity,const char * pgname,xmlNodePtr np)1537*12967Sgavin.maltby@oracle.com lxml_get_event(entity_t *entity, const char *pgname, xmlNodePtr np)
1538*12967Sgavin.maltby@oracle.com {
1539*12967Sgavin.maltby@oracle.com 	xmlNodePtr cursor;
1540*12967Sgavin.maltby@oracle.com 	pgroup_t *pgrp;
1541*12967Sgavin.maltby@oracle.com 
1542*12967Sgavin.maltby@oracle.com 	pgrp = internal_pgroup_find_or_create(entity, pgname,
1543*12967Sgavin.maltby@oracle.com 	    SCF_NOTIFY_PARAMS_PG_TYPE);
1544*12967Sgavin.maltby@oracle.com 	for (cursor = np->xmlChildrenNode; cursor != NULL;
1545*12967Sgavin.maltby@oracle.com 	    cursor = cursor->next) {
1546*12967Sgavin.maltby@oracle.com 		if (lxml_ignorable_block(cursor))
1547*12967Sgavin.maltby@oracle.com 			continue;
1548*12967Sgavin.maltby@oracle.com 
1549*12967Sgavin.maltby@oracle.com 		switch (lxml_xlate_element(cursor->name)) {
1550*12967Sgavin.maltby@oracle.com 		case SC_EVENT:
1551*12967Sgavin.maltby@oracle.com 			continue;
1552*12967Sgavin.maltby@oracle.com 
1553*12967Sgavin.maltby@oracle.com 		case SC_TYPE:
1554*12967Sgavin.maltby@oracle.com 			lxml_get_type(pgrp, cursor);
1555*12967Sgavin.maltby@oracle.com 			break;
1556*12967Sgavin.maltby@oracle.com 
1557*12967Sgavin.maltby@oracle.com 		default:
1558*12967Sgavin.maltby@oracle.com 			uu_warn(gettext("illegal element '%s' on "
1559*12967Sgavin.maltby@oracle.com 			    "notification parameters\n"), cursor->name);
1560*12967Sgavin.maltby@oracle.com 		}
1561*12967Sgavin.maltby@oracle.com 	}
1562*12967Sgavin.maltby@oracle.com }
1563*12967Sgavin.maltby@oracle.com 
1564*12967Sgavin.maltby@oracle.com static int
lxml_get_notification_parameters(entity_t * entity,xmlNodePtr np)1565*12967Sgavin.maltby@oracle.com lxml_get_notification_parameters(entity_t *entity, xmlNodePtr np)
1566*12967Sgavin.maltby@oracle.com {
1567*12967Sgavin.maltby@oracle.com 	char *event = NULL;
1568*12967Sgavin.maltby@oracle.com 	char **pgs = NULL;
1569*12967Sgavin.maltby@oracle.com 	char **p;
1570*12967Sgavin.maltby@oracle.com 	char *pgname = NULL;
1571*12967Sgavin.maltby@oracle.com 	xmlNodePtr cursor;
1572*12967Sgavin.maltby@oracle.com 	int32_t tset, t;
1573*12967Sgavin.maltby@oracle.com 	size_t sz = max_scf_name_len + 1;
1574*12967Sgavin.maltby@oracle.com 	int count;
1575*12967Sgavin.maltby@oracle.com 	int r = -1;
1576*12967Sgavin.maltby@oracle.com 
1577*12967Sgavin.maltby@oracle.com 	for (count = 0, cursor = np->xmlChildrenNode; cursor != NULL;
1578*12967Sgavin.maltby@oracle.com 	    cursor = cursor->next) {
1579*12967Sgavin.maltby@oracle.com 		if (lxml_ignorable_block(cursor))
1580*12967Sgavin.maltby@oracle.com 			continue;
1581*12967Sgavin.maltby@oracle.com 
1582*12967Sgavin.maltby@oracle.com 		if (lxml_xlate_element(cursor->name) == SC_EVENT) {
1583*12967Sgavin.maltby@oracle.com 			xmlChar *s;
1584*12967Sgavin.maltby@oracle.com 
1585*12967Sgavin.maltby@oracle.com 			count++;
1586*12967Sgavin.maltby@oracle.com 			if (count > 1)
1587*12967Sgavin.maltby@oracle.com 				uu_die(gettext("Can't have more than 1 element "
1588*12967Sgavin.maltby@oracle.com 				    "event in a notification parameter\n"));
1589*12967Sgavin.maltby@oracle.com 			s = xmlGetProp(cursor, (xmlChar *)value_attr);
1590*12967Sgavin.maltby@oracle.com 			if (s == NULL || (event = strdup((char *)s)) == NULL)
1591*12967Sgavin.maltby@oracle.com 				uu_die(gettext("couldn't allocate memory"));
1592*12967Sgavin.maltby@oracle.com 			xmlFree(s);
1593*12967Sgavin.maltby@oracle.com 		}
1594*12967Sgavin.maltby@oracle.com 	}
1595*12967Sgavin.maltby@oracle.com 
1596*12967Sgavin.maltby@oracle.com 	pgs = tokenize(event, ",");
1597*12967Sgavin.maltby@oracle.com 
1598*12967Sgavin.maltby@oracle.com 	switch (tset = check_tokens(pgs)) {
1599*12967Sgavin.maltby@oracle.com 	case INVALID_TOKENS:
1600*12967Sgavin.maltby@oracle.com 		uu_die(gettext("Invalid input.\n"));
1601*12967Sgavin.maltby@oracle.com 		/*NOTREACHED*/
1602*12967Sgavin.maltby@oracle.com 	case MIXED_TOKENS:
1603*12967Sgavin.maltby@oracle.com 		semerr(gettext("Can't mix SMF and FMA event definitions\n"));
1604*12967Sgavin.maltby@oracle.com 		goto out;
1605*12967Sgavin.maltby@oracle.com 	case FMA_TOKENS:
1606*12967Sgavin.maltby@oracle.com 		/* make sure this is SCF_NOTIFY_PARAMS_INST */
1607*12967Sgavin.maltby@oracle.com 		if (entity->sc_etype != SVCCFG_INSTANCE_OBJECT ||
1608*12967Sgavin.maltby@oracle.com 		    strcmp(entity->sc_fmri, SCF_NOTIFY_PARAMS_INST) != 0) {
1609*12967Sgavin.maltby@oracle.com 			semerr(gettext(
1610*12967Sgavin.maltby@oracle.com 			    "Non-SMF transition evenst must go to %s\n"),
1611*12967Sgavin.maltby@oracle.com 			    SCF_NOTIFY_PARAMS_INST);
1612*12967Sgavin.maltby@oracle.com 			goto out;
1613*12967Sgavin.maltby@oracle.com 		}
1614*12967Sgavin.maltby@oracle.com 		pgname = safe_malloc(sz);
1615*12967Sgavin.maltby@oracle.com 		for (p = pgs; *p; ++p) {
1616*12967Sgavin.maltby@oracle.com 			if (snprintf(pgname, sz, "%s,%s", de_tag(*p),
1617*12967Sgavin.maltby@oracle.com 			    SCF_NOTIFY_PG_POSTFIX) >= sz)
1618*12967Sgavin.maltby@oracle.com 				uu_die(gettext("event name too long: %s\n"),
1619*12967Sgavin.maltby@oracle.com 				    *p);
1620*12967Sgavin.maltby@oracle.com 
1621*12967Sgavin.maltby@oracle.com 			lxml_get_event(entity, pgname, np);
1622*12967Sgavin.maltby@oracle.com 		}
1623*12967Sgavin.maltby@oracle.com 
1624*12967Sgavin.maltby@oracle.com 	default:	/* smf state transition tokens */
1625*12967Sgavin.maltby@oracle.com 		if (entity->sc_etype == SVCCFG_SERVICE_OBJECT &&
1626*12967Sgavin.maltby@oracle.com 		    strcmp(entity->sc_fmri, SCF_SERVICE_GLOBAL) == 0) {
1627*12967Sgavin.maltby@oracle.com 			semerr(gettext(
1628*12967Sgavin.maltby@oracle.com 			    "Can't set events for global service\n"));
1629*12967Sgavin.maltby@oracle.com 			goto out;
1630*12967Sgavin.maltby@oracle.com 		}
1631*12967Sgavin.maltby@oracle.com 		for (t = 0x1; t < SCF_STATE_ALL; t <<= 1) {
1632*12967Sgavin.maltby@oracle.com 			if (t & tset) {
1633*12967Sgavin.maltby@oracle.com 				lxml_get_event(entity, tset_to_string(t), np);
1634*12967Sgavin.maltby@oracle.com 			}
1635*12967Sgavin.maltby@oracle.com 			if ((t << 16) & tset) {
1636*12967Sgavin.maltby@oracle.com 				lxml_get_event(entity, tset_to_string(t << 16),
1637*12967Sgavin.maltby@oracle.com 				    np);
1638*12967Sgavin.maltby@oracle.com 			}
1639*12967Sgavin.maltby@oracle.com 		}
1640*12967Sgavin.maltby@oracle.com 	}
1641*12967Sgavin.maltby@oracle.com 
1642*12967Sgavin.maltby@oracle.com 	r = 0;
1643*12967Sgavin.maltby@oracle.com out:
1644*12967Sgavin.maltby@oracle.com 	free(pgname);
1645*12967Sgavin.maltby@oracle.com 	free(pgs);
1646*12967Sgavin.maltby@oracle.com 	free(event);
1647*12967Sgavin.maltby@oracle.com 
1648*12967Sgavin.maltby@oracle.com 	return (r);
1649*12967Sgavin.maltby@oracle.com }
1650*12967Sgavin.maltby@oracle.com 
16517887SLiane.Praza@Sun.COM /*
16527887SLiane.Praza@Sun.COM  * Add a property containing the localized text from the manifest.  The
16537887SLiane.Praza@Sun.COM  * property is added to the property group at pg.  The name of the created
16547887SLiane.Praza@Sun.COM  * property is based on the format at pn_format.  This is an snprintf(3C)
16557887SLiane.Praza@Sun.COM  * format containing a single %s conversion specification.  At conversion
16567887SLiane.Praza@Sun.COM  * time, the %s is replaced by the locale designation.
16577887SLiane.Praza@Sun.COM  *
16587887SLiane.Praza@Sun.COM  * source is the source element and it is only used for error messages.
16597887SLiane.Praza@Sun.COM  */
16607887SLiane.Praza@Sun.COM static int
lxml_get_loctext(entity_t * service,pgroup_t * pg,xmlNodePtr loctext,const char * pn_format,const char * source)16617887SLiane.Praza@Sun.COM lxml_get_loctext(entity_t *service, pgroup_t *pg, xmlNodePtr loctext,
16627887SLiane.Praza@Sun.COM     const char *pn_format, const char *source)
16630Sstevel@tonic-gate {
16647887SLiane.Praza@Sun.COM 	int extra;
16650Sstevel@tonic-gate 	xmlNodePtr cursor;
16660Sstevel@tonic-gate 	xmlChar *val;
16670Sstevel@tonic-gate 	char *stripped, *cp;
16680Sstevel@tonic-gate 	property_t *p;
16697887SLiane.Praza@Sun.COM 	char *prop_name;
16700Sstevel@tonic-gate 	int r;
16710Sstevel@tonic-gate 
16727887SLiane.Praza@Sun.COM 	if (((val = xmlGetProp(loctext, (xmlChar *)xml_lang_attr)) == NULL) ||
16737887SLiane.Praza@Sun.COM 	    (*val == 0)) {
16747887SLiane.Praza@Sun.COM 		if (((val = xmlGetProp(loctext,
16757887SLiane.Praza@Sun.COM 		    (xmlChar *)lang_attr)) == NULL) || (*val == 0)) {
16760Sstevel@tonic-gate 			val = (xmlChar *)"unknown";
16777887SLiane.Praza@Sun.COM 		}
16787887SLiane.Praza@Sun.COM 	}
16797887SLiane.Praza@Sun.COM 
16807887SLiane.Praza@Sun.COM 	_scf_sanitize_locale((char *)val);
16817887SLiane.Praza@Sun.COM 	prop_name = safe_malloc(max_scf_name_len + 1);
16827887SLiane.Praza@Sun.COM 	if ((extra = snprintf(prop_name, max_scf_name_len + 1, pn_format,
16837887SLiane.Praza@Sun.COM 	    val)) >= max_scf_name_len + 1) {
16847887SLiane.Praza@Sun.COM 		extra -= max_scf_name_len;
16857887SLiane.Praza@Sun.COM 		uu_die(gettext("%s attribute is %d characters too long for "
16867887SLiane.Praza@Sun.COM 		    "%s in %s\n"),
16877887SLiane.Praza@Sun.COM 		    xml_lang_attr, extra, source, service->sc_name);
16887887SLiane.Praza@Sun.COM 	}
16897887SLiane.Praza@Sun.COM 	xmlFree(val);
16900Sstevel@tonic-gate 
16910Sstevel@tonic-gate 	for (cursor = loctext->xmlChildrenNode; cursor != NULL;
16920Sstevel@tonic-gate 	    cursor = cursor->next) {
16930Sstevel@tonic-gate 		if (strcmp("text", (const char *)cursor->name) == 0) {
16940Sstevel@tonic-gate 			break;
16950Sstevel@tonic-gate 		} else if (strcmp("comment", (const char *)cursor->name) != 0) {
16960Sstevel@tonic-gate 			uu_die(gettext("illegal element \"%s\" on loctext "
16970Sstevel@tonic-gate 			    "element for \"%s\"\n"), cursor->name,
16980Sstevel@tonic-gate 			    service->sc_name);
16990Sstevel@tonic-gate 		}
17000Sstevel@tonic-gate 	}
17010Sstevel@tonic-gate 
17020Sstevel@tonic-gate 	if (cursor == NULL) {
17030Sstevel@tonic-gate 		uu_die(gettext("loctext element has no content for \"%s\"\n"),
17040Sstevel@tonic-gate 		    service->sc_name);
17050Sstevel@tonic-gate 	}
17060Sstevel@tonic-gate 
17070Sstevel@tonic-gate 	/*
17080Sstevel@tonic-gate 	 * Remove leading and trailing whitespace.
17090Sstevel@tonic-gate 	 */
17100Sstevel@tonic-gate 	if ((stripped = strdup((const char *)cursor->content)) == NULL)
17110Sstevel@tonic-gate 		uu_die(gettext("Out of memory\n"));
17120Sstevel@tonic-gate 
17134740Sjeanm 	for (; isspace(*stripped); stripped++)
17144740Sjeanm 		;
17154740Sjeanm 	for (cp = stripped + strlen(stripped) - 1; isspace(*cp); cp--)
17164740Sjeanm 		;
17170Sstevel@tonic-gate 	*(cp + 1) = '\0';
17180Sstevel@tonic-gate 
17197887SLiane.Praza@Sun.COM 	p = internal_property_create(prop_name, SCF_TYPE_USTRING, 1,
17200Sstevel@tonic-gate 	    stripped);
17210Sstevel@tonic-gate 
17220Sstevel@tonic-gate 	r = internal_attach_property(pg, p);
17237887SLiane.Praza@Sun.COM 	if (r != 0) {
17240Sstevel@tonic-gate 		internal_property_free(p);
17257887SLiane.Praza@Sun.COM 		free(prop_name);
17267887SLiane.Praza@Sun.COM 	}
17270Sstevel@tonic-gate 
17280Sstevel@tonic-gate 	return (r);
17290Sstevel@tonic-gate }
17300Sstevel@tonic-gate 
17317887SLiane.Praza@Sun.COM /*
17327887SLiane.Praza@Sun.COM  * This function processes all loctext elements in the current XML element
17337887SLiane.Praza@Sun.COM  * designated by container.  A property is created for each loctext element
17347887SLiane.Praza@Sun.COM  * and added to the property group at pg.  The name of the property is
17357887SLiane.Praza@Sun.COM  * derived from the loctext language designation using the format at
17367887SLiane.Praza@Sun.COM  * pn_format.  pn_format should be an snprintf format string containing one
17377887SLiane.Praza@Sun.COM  * %s which is replaced by the language designation.
17387887SLiane.Praza@Sun.COM  *
17397887SLiane.Praza@Sun.COM  * The function returns 0 on success and -1 if it is unable to attach the
17407887SLiane.Praza@Sun.COM  * newly created property to pg.
17417887SLiane.Praza@Sun.COM  */
17420Sstevel@tonic-gate static int
lxml_get_all_loctext(entity_t * service,pgroup_t * pg,xmlNodePtr container,const char * pn_format,const char * source)17437887SLiane.Praza@Sun.COM lxml_get_all_loctext(entity_t *service, pgroup_t *pg, xmlNodePtr container,
17447887SLiane.Praza@Sun.COM     const char *pn_format, const char *source)
17450Sstevel@tonic-gate {
17460Sstevel@tonic-gate 	xmlNodePtr cursor;
17470Sstevel@tonic-gate 
17480Sstevel@tonic-gate 	/*
17497887SLiane.Praza@Sun.COM 	 * Iterate through one or more loctext elements.  The locale is
17507887SLiane.Praza@Sun.COM 	 * used to generate the property name; the contents are the ustring
17517887SLiane.Praza@Sun.COM 	 * value for the property.
17520Sstevel@tonic-gate 	 */
17537887SLiane.Praza@Sun.COM 	for (cursor = container->xmlChildrenNode; cursor != NULL;
17540Sstevel@tonic-gate 	    cursor = cursor->next) {
17550Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
17560Sstevel@tonic-gate 			continue;
17570Sstevel@tonic-gate 
17580Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
17590Sstevel@tonic-gate 		case SC_LOCTEXT:
17607887SLiane.Praza@Sun.COM 			if (lxml_get_loctext(service, pg, cursor, pn_format,
17617887SLiane.Praza@Sun.COM 			    source))
17620Sstevel@tonic-gate 				return (-1);
17630Sstevel@tonic-gate 			break;
17640Sstevel@tonic-gate 		default:
17657887SLiane.Praza@Sun.COM 			uu_die(gettext("illegal element \"%s\" on %s element "
17667887SLiane.Praza@Sun.COM 			    "for \"%s\"\n"), cursor->name, container->name,
17670Sstevel@tonic-gate 			    service->sc_name);
17680Sstevel@tonic-gate 			break;
17690Sstevel@tonic-gate 		}
17700Sstevel@tonic-gate 	}
17710Sstevel@tonic-gate 
17720Sstevel@tonic-gate 	return (0);
17730Sstevel@tonic-gate }
17740Sstevel@tonic-gate 
17757887SLiane.Praza@Sun.COM /*
17767887SLiane.Praza@Sun.COM  * Obtain the specified cardinality attribute and place it in a property
17777887SLiane.Praza@Sun.COM  * named prop_name.  The converted attribute is placed at *value, and the
17787887SLiane.Praza@Sun.COM  * newly created property is returned to propp.  NULL is returned to propp
17797887SLiane.Praza@Sun.COM  * if the attribute is not provided in the manifest.
17807887SLiane.Praza@Sun.COM  *
17817887SLiane.Praza@Sun.COM  * 0 is returned upon success, and -1 indicates that the manifest contained
17827887SLiane.Praza@Sun.COM  * an invalid cardinality value.
17837887SLiane.Praza@Sun.COM  */
17840Sstevel@tonic-gate static int
lxml_get_cardinality_attribute(entity_t * service,xmlNodePtr cursor,const char * attr_name,const char * prop_name,uint64_t * value,property_t ** propp)17857887SLiane.Praza@Sun.COM lxml_get_cardinality_attribute(entity_t *service, xmlNodePtr cursor,
17867887SLiane.Praza@Sun.COM     const char *attr_name, const char *prop_name, uint64_t *value,
17877887SLiane.Praza@Sun.COM     property_t **propp)
17887887SLiane.Praza@Sun.COM {
17897887SLiane.Praza@Sun.COM 	char *c;
17907887SLiane.Praza@Sun.COM 	property_t *p;
17917887SLiane.Praza@Sun.COM 	xmlChar *val;
17927887SLiane.Praza@Sun.COM 	uint64_t count;
17937887SLiane.Praza@Sun.COM 	char *endptr;
17947887SLiane.Praza@Sun.COM 
17957887SLiane.Praza@Sun.COM 	*propp = NULL;
17967887SLiane.Praza@Sun.COM 	val = xmlGetProp(cursor, (xmlChar *)attr_name);
17977887SLiane.Praza@Sun.COM 	if (val == NULL)
17987887SLiane.Praza@Sun.COM 		return (0);
17997887SLiane.Praza@Sun.COM 	if (*val == 0) {
18007887SLiane.Praza@Sun.COM 		xmlFree(val);
18017887SLiane.Praza@Sun.COM 		return (0);
18027887SLiane.Praza@Sun.COM 	}
18037887SLiane.Praza@Sun.COM 
18047887SLiane.Praza@Sun.COM 	/*
18057887SLiane.Praza@Sun.COM 	 * Make sure that the string at val doesn't have a leading minus
18067887SLiane.Praza@Sun.COM 	 * sign.  The strtoull() call below does not catch this problem.
18077887SLiane.Praza@Sun.COM 	 */
18087887SLiane.Praza@Sun.COM 	for (c = (char *)val; *c != 0; c++) {
18097887SLiane.Praza@Sun.COM 		if (isspace(*c))
18107887SLiane.Praza@Sun.COM 			continue;
18117887SLiane.Praza@Sun.COM 		if (isdigit(*c))
18127887SLiane.Praza@Sun.COM 			break;
18137887SLiane.Praza@Sun.COM 		semerr(gettext("\"%c\" is not a legal character in the %s "
18147887SLiane.Praza@Sun.COM 		    "attribute of the %s element in %s.\n"), *c,
18157887SLiane.Praza@Sun.COM 		    attr_name, prop_name, service->sc_name);
18167887SLiane.Praza@Sun.COM 		xmlFree(val);
18177887SLiane.Praza@Sun.COM 		return (-1);
18187887SLiane.Praza@Sun.COM 	}
18197887SLiane.Praza@Sun.COM 	errno = 0;
18207887SLiane.Praza@Sun.COM 	count = strtoull((char *)val, &endptr, 10);
18217887SLiane.Praza@Sun.COM 	if (errno != 0 || endptr == (char *)val || *endptr) {
18227887SLiane.Praza@Sun.COM 		semerr(gettext("\"%s\" is not a legal number for the %s "
18237887SLiane.Praza@Sun.COM 		    "attribute of the %s element in %s.\n"), (char *)val,
18247887SLiane.Praza@Sun.COM 		    attr_name, prop_name, service->sc_name);
18257887SLiane.Praza@Sun.COM 		xmlFree(val);
18267887SLiane.Praza@Sun.COM 		return (-1);
18277887SLiane.Praza@Sun.COM 	}
18287887SLiane.Praza@Sun.COM 
18297887SLiane.Praza@Sun.COM 	xmlFree(val);
18307887SLiane.Praza@Sun.COM 
18317887SLiane.Praza@Sun.COM 	/* Value is valid.  Create the property. */
18327887SLiane.Praza@Sun.COM 	p = internal_property_create(prop_name, SCF_TYPE_COUNT, 1, count);
18337887SLiane.Praza@Sun.COM 	*value = count;
18347887SLiane.Praza@Sun.COM 	*propp = p;
18357887SLiane.Praza@Sun.COM 	return (0);
18367887SLiane.Praza@Sun.COM }
18377887SLiane.Praza@Sun.COM 
18387887SLiane.Praza@Sun.COM /*
18397887SLiane.Praza@Sun.COM  * The cardinality is specified by two attributes max and min at cursor.
18407887SLiane.Praza@Sun.COM  * Both are optional, but if present they must be unsigned integers.
18417887SLiane.Praza@Sun.COM  */
18427887SLiane.Praza@Sun.COM static int
lxml_get_tm_cardinality(entity_t * service,pgroup_t * pg,xmlNodePtr cursor)18437887SLiane.Praza@Sun.COM lxml_get_tm_cardinality(entity_t *service, pgroup_t *pg, xmlNodePtr cursor)
18440Sstevel@tonic-gate {
18457887SLiane.Praza@Sun.COM 	int min_attached = 0;
18467887SLiane.Praza@Sun.COM 	int compare = 1;
18477887SLiane.Praza@Sun.COM 	property_t *min_prop;
18487887SLiane.Praza@Sun.COM 	property_t *max_prop;
18497887SLiane.Praza@Sun.COM 	uint64_t max;
18507887SLiane.Praza@Sun.COM 	uint64_t min;
18517887SLiane.Praza@Sun.COM 	int r;
18527887SLiane.Praza@Sun.COM 
18537887SLiane.Praza@Sun.COM 	r = lxml_get_cardinality_attribute(service, cursor, min_attr,
18547887SLiane.Praza@Sun.COM 	    SCF_PROPERTY_TM_CARDINALITY_MIN, &min, &min_prop);
18557887SLiane.Praza@Sun.COM 	if (r != 0)
18567887SLiane.Praza@Sun.COM 		return (r);
18577887SLiane.Praza@Sun.COM 	if (min_prop == NULL)
18587887SLiane.Praza@Sun.COM 		compare = 0;
18597887SLiane.Praza@Sun.COM 	r = lxml_get_cardinality_attribute(service, cursor, max_attr,
18607887SLiane.Praza@Sun.COM 	    SCF_PROPERTY_TM_CARDINALITY_MAX, &max, &max_prop);
18617887SLiane.Praza@Sun.COM 	if (r != 0)
18627887SLiane.Praza@Sun.COM 		goto errout;
18637887SLiane.Praza@Sun.COM 	if ((max_prop != NULL) && (compare == 1)) {
18647887SLiane.Praza@Sun.COM 		if (max < min) {
18657887SLiane.Praza@Sun.COM 			semerr(gettext("Cardinality max is less than min for "
18667887SLiane.Praza@Sun.COM 			    "the %s element in %s.\n"), pg->sc_pgroup_name,
18677887SLiane.Praza@Sun.COM 			    service->sc_fmri);
18687887SLiane.Praza@Sun.COM 			goto errout;
18697887SLiane.Praza@Sun.COM 		}
18707887SLiane.Praza@Sun.COM 	}
18717887SLiane.Praza@Sun.COM 
18727887SLiane.Praza@Sun.COM 	/* Attach the properties to the property group. */
18737887SLiane.Praza@Sun.COM 	if (min_prop) {
18747887SLiane.Praza@Sun.COM 		if (internal_attach_property(pg, min_prop) == 0) {
18757887SLiane.Praza@Sun.COM 			min_attached = 1;
18767887SLiane.Praza@Sun.COM 		} else {
18777887SLiane.Praza@Sun.COM 			goto errout;
18787887SLiane.Praza@Sun.COM 		}
18797887SLiane.Praza@Sun.COM 	}
18807887SLiane.Praza@Sun.COM 	if (max_prop) {
18817887SLiane.Praza@Sun.COM 		if (internal_attach_property(pg, max_prop) != 0) {
18827887SLiane.Praza@Sun.COM 			if (min_attached)
18837887SLiane.Praza@Sun.COM 				internal_detach_property(pg, min_prop);
18847887SLiane.Praza@Sun.COM 			goto errout;
18857887SLiane.Praza@Sun.COM 		}
18867887SLiane.Praza@Sun.COM 	}
18877887SLiane.Praza@Sun.COM 	return (0);
18887887SLiane.Praza@Sun.COM 
18897887SLiane.Praza@Sun.COM errout:
18907887SLiane.Praza@Sun.COM 	if (min_prop)
18917887SLiane.Praza@Sun.COM 		internal_property_free(min_prop);
18927887SLiane.Praza@Sun.COM 	if (max_prop)
18937887SLiane.Praza@Sun.COM 		internal_property_free(max_prop);
18947887SLiane.Praza@Sun.COM 	return (-1);
18957887SLiane.Praza@Sun.COM }
18967887SLiane.Praza@Sun.COM 
18977887SLiane.Praza@Sun.COM /*
18987887SLiane.Praza@Sun.COM  * Get the common_name which is present as localized text at common_name in
18997887SLiane.Praza@Sun.COM  * the manifest.  The common_name is stored as the value of a property in
19007887SLiane.Praza@Sun.COM  * the property group whose name is SCF_PG_TM_COMMON_NAME and type is
19017887SLiane.Praza@Sun.COM  * SCF_GROUP_TEMPLATE.  This property group will be created in service if
19027887SLiane.Praza@Sun.COM  * it is not already there.
19037887SLiane.Praza@Sun.COM  */
19047887SLiane.Praza@Sun.COM static int
lxml_get_tm_common_name(entity_t * service,xmlNodePtr common_name)19057887SLiane.Praza@Sun.COM lxml_get_tm_common_name(entity_t *service, xmlNodePtr common_name)
19067887SLiane.Praza@Sun.COM {
19070Sstevel@tonic-gate 	pgroup_t *pg;
19080Sstevel@tonic-gate 
19090Sstevel@tonic-gate 	/*
19100Sstevel@tonic-gate 	 * Create the property group, if absent.
19110Sstevel@tonic-gate 	 */
19127887SLiane.Praza@Sun.COM 	pg = internal_pgroup_find_or_create(service, SCF_PG_TM_COMMON_NAME,
19137887SLiane.Praza@Sun.COM 	    SCF_GROUP_TEMPLATE);
19147887SLiane.Praza@Sun.COM 
19157887SLiane.Praza@Sun.COM 	return (lxml_get_all_loctext(service, pg, common_name, LOCALE_ONLY_FMT,
19167887SLiane.Praza@Sun.COM 	    "common_name"));
19177887SLiane.Praza@Sun.COM }
19187887SLiane.Praza@Sun.COM 
19197887SLiane.Praza@Sun.COM /*
19207887SLiane.Praza@Sun.COM  * Get the description which is present as localized text at description in
19217887SLiane.Praza@Sun.COM  * the manifest.  The description is stored as the value of a property in
19227887SLiane.Praza@Sun.COM  * the property group whose name is SCF_PG_TM_DESCRIPTION and type is
19237887SLiane.Praza@Sun.COM  * SCF_GROUP_TEMPLATE.  This property group will be created in service if
19247887SLiane.Praza@Sun.COM  * it is not already there.
19257887SLiane.Praza@Sun.COM  */
19267887SLiane.Praza@Sun.COM static int
lxml_get_tm_description(entity_t * service,xmlNodePtr description)19277887SLiane.Praza@Sun.COM lxml_get_tm_description(entity_t *service, xmlNodePtr description)
19287887SLiane.Praza@Sun.COM {
19297887SLiane.Praza@Sun.COM 	pgroup_t *pg;
19300Sstevel@tonic-gate 
19310Sstevel@tonic-gate 	/*
19327887SLiane.Praza@Sun.COM 	 * Create the property group, if absent.
19330Sstevel@tonic-gate 	 */
19347887SLiane.Praza@Sun.COM 	pg = internal_pgroup_find_or_create(service, SCF_PG_TM_DESCRIPTION,
19357887SLiane.Praza@Sun.COM 	    SCF_GROUP_TEMPLATE);
19367887SLiane.Praza@Sun.COM 
19377887SLiane.Praza@Sun.COM 	return (lxml_get_all_loctext(service, pg, description,
19387887SLiane.Praza@Sun.COM 	    LOCALE_ONLY_FMT, "description"));
19390Sstevel@tonic-gate }
19400Sstevel@tonic-gate 
19410Sstevel@tonic-gate static char *
lxml_label_to_groupname(const char * prefix,const char * in)19420Sstevel@tonic-gate lxml_label_to_groupname(const char *prefix, const char *in)
19430Sstevel@tonic-gate {
19440Sstevel@tonic-gate 	char *out, *cp;
19450Sstevel@tonic-gate 	size_t len, piece_len;
19460Sstevel@tonic-gate 
19470Sstevel@tonic-gate 	out = uu_zalloc(2 * scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1);
19480Sstevel@tonic-gate 	if (out == NULL)
19490Sstevel@tonic-gate 		return (NULL);
19500Sstevel@tonic-gate 
19510Sstevel@tonic-gate 	(void) strcpy(out, prefix);
19520Sstevel@tonic-gate 	(void) strcat(out, in);
19530Sstevel@tonic-gate 
19540Sstevel@tonic-gate 	len = strlen(out);
19550Sstevel@tonic-gate 	if (len > max_scf_name_len) {
19560Sstevel@tonic-gate 		/* Use the first half and the second half. */
19570Sstevel@tonic-gate 		piece_len = (max_scf_name_len - 2) / 2;
19580Sstevel@tonic-gate 
19590Sstevel@tonic-gate 		(void) strncpy(out + piece_len, "..", 2);
19600Sstevel@tonic-gate 
19610Sstevel@tonic-gate 		(void) strcpy(out + piece_len + 2, out + (len - piece_len));
19620Sstevel@tonic-gate 
19630Sstevel@tonic-gate 		len = strlen(out);
19640Sstevel@tonic-gate 	}
19650Sstevel@tonic-gate 
19660Sstevel@tonic-gate 	/*
19670Sstevel@tonic-gate 	 * Translate non-property characters to '_'.
19680Sstevel@tonic-gate 	 */
19690Sstevel@tonic-gate 	for (cp = out; *cp != '\0'; ++cp) {
19700Sstevel@tonic-gate 		if (!(isalnum(*cp) || *cp == '_' || *cp == '-'))
19710Sstevel@tonic-gate 			*cp = '_';
19720Sstevel@tonic-gate 	}
19730Sstevel@tonic-gate 
19740Sstevel@tonic-gate 	*cp = '\0';
19750Sstevel@tonic-gate 
19760Sstevel@tonic-gate 	return (out);
19770Sstevel@tonic-gate }
19780Sstevel@tonic-gate 
19797887SLiane.Praza@Sun.COM /*
19807887SLiane.Praza@Sun.COM  * If *p is NULL, astring_prop_value() first creates a property with the
19817887SLiane.Praza@Sun.COM  * name specified in prop_name.  The address of the newly created property
19827887SLiane.Praza@Sun.COM  * is placed in *p.
19837887SLiane.Praza@Sun.COM  *
19847887SLiane.Praza@Sun.COM  * In either case, newly created property or existing property, a new
19857887SLiane.Praza@Sun.COM  * SCF_TYPE_ASTRING value will created and attached to the property at *p.
19867887SLiane.Praza@Sun.COM  * The value of the newly created property is prop_value.
19877887SLiane.Praza@Sun.COM  *
19887887SLiane.Praza@Sun.COM  * free_flag is used to indicate whether or not the memory at prop_value
19897887SLiane.Praza@Sun.COM  * should be freed when the property is freed by a call to
19907887SLiane.Praza@Sun.COM  * internal_property_free().
19917887SLiane.Praza@Sun.COM  */
19927887SLiane.Praza@Sun.COM static void
astring_prop_value(property_t ** p,const char * prop_name,char * prop_value,boolean_t free_flag)19937887SLiane.Praza@Sun.COM astring_prop_value(property_t **p, const char *prop_name, char *prop_value,
19947887SLiane.Praza@Sun.COM     boolean_t free_flag)
19957887SLiane.Praza@Sun.COM {
19967887SLiane.Praza@Sun.COM 	value_t *v;
19977887SLiane.Praza@Sun.COM 
19987887SLiane.Praza@Sun.COM 	if (*p == NULL) {
19997887SLiane.Praza@Sun.COM 		/* Create the property */
20007887SLiane.Praza@Sun.COM 		*p = internal_property_new();
20017887SLiane.Praza@Sun.COM 		(*p)->sc_property_name = (char *)prop_name;
20027887SLiane.Praza@Sun.COM 		(*p)->sc_value_type = SCF_TYPE_ASTRING;
20037887SLiane.Praza@Sun.COM 	}
20047887SLiane.Praza@Sun.COM 
20057887SLiane.Praza@Sun.COM 	/* Add the property value to the property's list of values. */
20067887SLiane.Praza@Sun.COM 	v = internal_value_new();
20077887SLiane.Praza@Sun.COM 	v->sc_type = SCF_TYPE_ASTRING;
20087887SLiane.Praza@Sun.COM 	if (free_flag == B_TRUE)
20097887SLiane.Praza@Sun.COM 		v->sc_free = lxml_free_str;
20107887SLiane.Praza@Sun.COM 	v->sc_u.sc_string = prop_value;
20117887SLiane.Praza@Sun.COM 	internal_attach_value(*p, v);
20127887SLiane.Praza@Sun.COM }
20137887SLiane.Praza@Sun.COM 
20147887SLiane.Praza@Sun.COM /*
20157887SLiane.Praza@Sun.COM  * If p points to a null pointer, create an internal_separators property
20167887SLiane.Praza@Sun.COM  * saving the address at p.  For each character at seps create a property
20177887SLiane.Praza@Sun.COM  * value and attach it to the property at p.
20187887SLiane.Praza@Sun.COM  */
20197887SLiane.Praza@Sun.COM static void
seps_to_prop_values(property_t ** p,xmlChar * seps)20207887SLiane.Praza@Sun.COM seps_to_prop_values(property_t **p, xmlChar *seps)
20217887SLiane.Praza@Sun.COM {
20227887SLiane.Praza@Sun.COM 	value_t *v;
20237887SLiane.Praza@Sun.COM 	char val_str[2];
20247887SLiane.Praza@Sun.COM 
20257887SLiane.Praza@Sun.COM 	if (*p == NULL) {
20267887SLiane.Praza@Sun.COM 		*p = internal_property_new();
20277887SLiane.Praza@Sun.COM 		(*p)->sc_property_name =
20287887SLiane.Praza@Sun.COM 		    (char *)SCF_PROPERTY_INTERNAL_SEPARATORS;
20297887SLiane.Praza@Sun.COM 		(*p)->sc_value_type = SCF_TYPE_ASTRING;
20307887SLiane.Praza@Sun.COM 	}
20317887SLiane.Praza@Sun.COM 
20327887SLiane.Praza@Sun.COM 	/* Add the values to the property's list. */
20337887SLiane.Praza@Sun.COM 	val_str[1] = 0;		/* Terminate the string. */
20347887SLiane.Praza@Sun.COM 	for (; *seps != 0; seps++) {
20357887SLiane.Praza@Sun.COM 		v = internal_value_new();
20367887SLiane.Praza@Sun.COM 		v->sc_type = (*p)->sc_value_type;
20377887SLiane.Praza@Sun.COM 		v->sc_free = lxml_free_str;
20387887SLiane.Praza@Sun.COM 		val_str[0] = *seps;
20397887SLiane.Praza@Sun.COM 		v->sc_u.sc_string = strdup(val_str);
20407887SLiane.Praza@Sun.COM 		if (v->sc_u.sc_string == NULL)
20417887SLiane.Praza@Sun.COM 			uu_die(gettext("Out of memory\n"));
20427887SLiane.Praza@Sun.COM 		internal_attach_value(*p, v);
20437887SLiane.Praza@Sun.COM 	}
20447887SLiane.Praza@Sun.COM }
20457887SLiane.Praza@Sun.COM 
20467887SLiane.Praza@Sun.COM /*
20477887SLiane.Praza@Sun.COM  * Create an internal_separators property and attach it to the property
20487887SLiane.Praza@Sun.COM  * group at pg.  The separator characters are provided in the text nodes
20497887SLiane.Praza@Sun.COM  * that are the children of seps.  Each separator character is stored as a
20507887SLiane.Praza@Sun.COM  * property value in the internal_separators property.
20517887SLiane.Praza@Sun.COM  */
20527887SLiane.Praza@Sun.COM static int
lxml_get_tm_internal_seps(entity_t * service,pgroup_t * pg,xmlNodePtr seps)20537887SLiane.Praza@Sun.COM lxml_get_tm_internal_seps(entity_t *service, pgroup_t *pg, xmlNodePtr seps)
20547887SLiane.Praza@Sun.COM {
20557887SLiane.Praza@Sun.COM 	xmlNodePtr cursor;
20567887SLiane.Praza@Sun.COM 	property_t *prop = NULL;
20577887SLiane.Praza@Sun.COM 	int r;
20587887SLiane.Praza@Sun.COM 
20597887SLiane.Praza@Sun.COM 	for (cursor = seps->xmlChildrenNode; cursor != NULL;
20607887SLiane.Praza@Sun.COM 	    cursor = cursor->next) {
20617887SLiane.Praza@Sun.COM 		if (strcmp("text", (const char *)cursor->name) == 0) {
20627887SLiane.Praza@Sun.COM 			seps_to_prop_values(&prop, cursor->content);
20637887SLiane.Praza@Sun.COM 		} else if (strcmp("comment", (const char *)cursor->name) != 0) {
20647887SLiane.Praza@Sun.COM 			uu_die(gettext("illegal element \"%s\" on %s element "
20657887SLiane.Praza@Sun.COM 			    "for \"%s\"\n"), cursor->name, seps->name,
20667887SLiane.Praza@Sun.COM 			    service->sc_name);
20677887SLiane.Praza@Sun.COM 		}
20687887SLiane.Praza@Sun.COM 	}
20697887SLiane.Praza@Sun.COM 	if (prop == NULL) {
20707887SLiane.Praza@Sun.COM 		semerr(gettext("The %s element in %s had an empty list of "
20717887SLiane.Praza@Sun.COM 		    "separators.\n"), (const char *)seps->name,
20727887SLiane.Praza@Sun.COM 		    service->sc_name);
20737887SLiane.Praza@Sun.COM 		return (-1);
20747887SLiane.Praza@Sun.COM 	}
20757887SLiane.Praza@Sun.COM 	r = internal_attach_property(pg, prop);
20767887SLiane.Praza@Sun.COM 	if (r != 0)
20777887SLiane.Praza@Sun.COM 		internal_property_free(prop);
20787887SLiane.Praza@Sun.COM 	return (r);
20797887SLiane.Praza@Sun.COM }
20807887SLiane.Praza@Sun.COM 
20810Sstevel@tonic-gate static int
lxml_get_tm_manpage(entity_t * service,xmlNodePtr manpage)20820Sstevel@tonic-gate lxml_get_tm_manpage(entity_t *service, xmlNodePtr manpage)
20830Sstevel@tonic-gate {
20840Sstevel@tonic-gate 	pgroup_t *pg;
20850Sstevel@tonic-gate 	char *pgname;
20860Sstevel@tonic-gate 	xmlChar *title;
20870Sstevel@tonic-gate 
20880Sstevel@tonic-gate 	/*
20890Sstevel@tonic-gate 	 * Fetch title attribute, convert to something sanitized, and create
20900Sstevel@tonic-gate 	 * property group.
20910Sstevel@tonic-gate 	 */
20927887SLiane.Praza@Sun.COM 	title = xmlGetProp(manpage, (xmlChar *)title_attr);
20930Sstevel@tonic-gate 	pgname = (char *)lxml_label_to_groupname(SCF_PG_TM_MAN_PREFIX,
20940Sstevel@tonic-gate 	    (const char *)title);
20957887SLiane.Praza@Sun.COM 	xmlFree(title);
20960Sstevel@tonic-gate 
20970Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(service, pgname,
20980Sstevel@tonic-gate 	    (char *)SCF_GROUP_TEMPLATE);
20990Sstevel@tonic-gate 
21000Sstevel@tonic-gate 	/*
21010Sstevel@tonic-gate 	 * Each attribute is an astring property within the group.
21020Sstevel@tonic-gate 	 */
21037887SLiane.Praza@Sun.COM 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_TM_TITLE,
21047887SLiane.Praza@Sun.COM 	    SCF_TYPE_ASTRING, manpage, title_attr) != 0 ||
21057887SLiane.Praza@Sun.COM 	    new_str_prop_from_attr(pg, SCF_PROPERTY_TM_SECTION,
21067887SLiane.Praza@Sun.COM 	    SCF_TYPE_ASTRING, manpage, section_attr) != 0 ||
21077887SLiane.Praza@Sun.COM 	    new_str_prop_from_attr(pg, SCF_PROPERTY_TM_MANPATH,
21087887SLiane.Praza@Sun.COM 	    SCF_TYPE_ASTRING, manpage, manpath_attr) != 0)
21090Sstevel@tonic-gate 		return (-1);
21100Sstevel@tonic-gate 
21110Sstevel@tonic-gate 	return (0);
21120Sstevel@tonic-gate }
21130Sstevel@tonic-gate 
21140Sstevel@tonic-gate static int
lxml_get_tm_doclink(entity_t * service,xmlNodePtr doc_link)21150Sstevel@tonic-gate lxml_get_tm_doclink(entity_t *service, xmlNodePtr doc_link)
21160Sstevel@tonic-gate {
21170Sstevel@tonic-gate 	pgroup_t *pg;
21180Sstevel@tonic-gate 	char *pgname;
21190Sstevel@tonic-gate 	xmlChar *name;
21200Sstevel@tonic-gate 
21210Sstevel@tonic-gate 	/*
21220Sstevel@tonic-gate 	 * Fetch name attribute, convert name to something sanitized, and create
21230Sstevel@tonic-gate 	 * property group.
21240Sstevel@tonic-gate 	 */
21257887SLiane.Praza@Sun.COM 	name = xmlGetProp(doc_link, (xmlChar *)name_attr);
21260Sstevel@tonic-gate 
21270Sstevel@tonic-gate 	pgname = (char *)lxml_label_to_groupname(SCF_PG_TM_DOC_PREFIX,
21280Sstevel@tonic-gate 	    (const char *)name);
21290Sstevel@tonic-gate 
21300Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(service, pgname,
21310Sstevel@tonic-gate 	    (char *)SCF_GROUP_TEMPLATE);
21327887SLiane.Praza@Sun.COM 	xmlFree(name);
21330Sstevel@tonic-gate 
21340Sstevel@tonic-gate 	/*
21350Sstevel@tonic-gate 	 * Each attribute is an astring property within the group.
21360Sstevel@tonic-gate 	 */
21377887SLiane.Praza@Sun.COM 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_TM_NAME, SCF_TYPE_ASTRING,
21387887SLiane.Praza@Sun.COM 	    doc_link, name_attr) != 0 ||
21397887SLiane.Praza@Sun.COM 	    new_str_prop_from_attr(pg, SCF_PROPERTY_TM_URI, SCF_TYPE_ASTRING,
21407887SLiane.Praza@Sun.COM 	    doc_link, uri_attr) != 0)
21410Sstevel@tonic-gate 		return (-1);
21420Sstevel@tonic-gate 
21430Sstevel@tonic-gate 	return (0);
21440Sstevel@tonic-gate }
21450Sstevel@tonic-gate 
21460Sstevel@tonic-gate static int
lxml_get_tm_documentation(entity_t * service,xmlNodePtr documentation)21470Sstevel@tonic-gate lxml_get_tm_documentation(entity_t *service, xmlNodePtr documentation)
21480Sstevel@tonic-gate {
21490Sstevel@tonic-gate 	xmlNodePtr cursor;
21500Sstevel@tonic-gate 
21510Sstevel@tonic-gate 	for (cursor = documentation->xmlChildrenNode; cursor != NULL;
21520Sstevel@tonic-gate 	    cursor = cursor->next) {
21530Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
21540Sstevel@tonic-gate 			continue;
21550Sstevel@tonic-gate 
21560Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
21570Sstevel@tonic-gate 		case SC_MANPAGE:
21580Sstevel@tonic-gate 			(void) lxml_get_tm_manpage(service, cursor);
21590Sstevel@tonic-gate 			break;
21600Sstevel@tonic-gate 		case SC_DOC_LINK:
21610Sstevel@tonic-gate 			(void) lxml_get_tm_doclink(service, cursor);
21620Sstevel@tonic-gate 			break;
21630Sstevel@tonic-gate 		default:
21640Sstevel@tonic-gate 			uu_die(gettext("illegal element \"%s\" on template "
21650Sstevel@tonic-gate 			    "for service \"%s\"\n"),
21660Sstevel@tonic-gate 			    cursor->name, service->sc_name);
21670Sstevel@tonic-gate 		}
21680Sstevel@tonic-gate 	}
21690Sstevel@tonic-gate 
21700Sstevel@tonic-gate 	return (0);
21710Sstevel@tonic-gate }
21720Sstevel@tonic-gate 
21730Sstevel@tonic-gate static int
lxml_get_prop_pattern_attributes(pgroup_t * pg,xmlNodePtr cursor)21747887SLiane.Praza@Sun.COM lxml_get_prop_pattern_attributes(pgroup_t *pg, xmlNodePtr cursor)
21757887SLiane.Praza@Sun.COM {
21767887SLiane.Praza@Sun.COM 	if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_TM_NAME,
21777887SLiane.Praza@Sun.COM 	    SCF_TYPE_ASTRING, cursor, name_attr, NULL) != 0) {
21787887SLiane.Praza@Sun.COM 		return (-1);
21797887SLiane.Praza@Sun.COM 	}
21807887SLiane.Praza@Sun.COM 	if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_TM_TYPE,
21817887SLiane.Praza@Sun.COM 	    SCF_TYPE_ASTRING, cursor, type_attr, "") != 0) {
21827887SLiane.Praza@Sun.COM 		return (-1);
21837887SLiane.Praza@Sun.COM 	}
21847887SLiane.Praza@Sun.COM 	if (new_bool_prop_from_attr(pg, SCF_PROPERTY_TM_REQUIRED, cursor,
21857887SLiane.Praza@Sun.COM 	    required_attr) != 0)
21867887SLiane.Praza@Sun.COM 		return (-1);
21877887SLiane.Praza@Sun.COM 	return (0);
21887887SLiane.Praza@Sun.COM }
21897887SLiane.Praza@Sun.COM 
21907887SLiane.Praza@Sun.COM static int
lxml_get_tm_include_values(entity_t * service,pgroup_t * pg,xmlNodePtr include_values,const char * prop_name)21917887SLiane.Praza@Sun.COM lxml_get_tm_include_values(entity_t *service, pgroup_t *pg,
21927887SLiane.Praza@Sun.COM     xmlNodePtr include_values, const char *prop_name)
21937887SLiane.Praza@Sun.COM {
21947887SLiane.Praza@Sun.COM 	boolean_t attach_to_pg = B_FALSE;
21957887SLiane.Praza@Sun.COM 	property_t *p;
21967887SLiane.Praza@Sun.COM 	int r = 0;
21977887SLiane.Praza@Sun.COM 	char *type;
21987887SLiane.Praza@Sun.COM 
21997887SLiane.Praza@Sun.COM 	/* Get the type attribute of the include_values element. */
22007887SLiane.Praza@Sun.COM 	type = (char *)xmlGetProp(include_values, (const xmlChar *)type_attr);
22017887SLiane.Praza@Sun.COM 	if ((type == NULL) || (*type == 0)) {
22027887SLiane.Praza@Sun.COM 		uu_die(gettext("%s element requires a %s attribute in the %s "
22037887SLiane.Praza@Sun.COM 		    "service.\n"), include_values->name, type_attr,
22047887SLiane.Praza@Sun.COM 		    service->sc_name);
22057887SLiane.Praza@Sun.COM 	}
22067887SLiane.Praza@Sun.COM 
22077887SLiane.Praza@Sun.COM 	/* Add the type to the values of the prop_name property. */
22087887SLiane.Praza@Sun.COM 	p = internal_property_find(pg, prop_name);
22097887SLiane.Praza@Sun.COM 	if (p == NULL)
22107887SLiane.Praza@Sun.COM 		attach_to_pg = B_TRUE;
22117887SLiane.Praza@Sun.COM 	astring_prop_value(&p, prop_name, type, B_FALSE);
22127887SLiane.Praza@Sun.COM 	if (attach_to_pg == B_TRUE) {
22137887SLiane.Praza@Sun.COM 		r = internal_attach_property(pg, p);
22147887SLiane.Praza@Sun.COM 		if (r != 0)
22157887SLiane.Praza@Sun.COM 			internal_property_free(p);
22167887SLiane.Praza@Sun.COM 	}
22177887SLiane.Praza@Sun.COM 	return (r);
22187887SLiane.Praza@Sun.COM }
22197887SLiane.Praza@Sun.COM 
22207887SLiane.Praza@Sun.COM #define	RC_MIN		0
22217887SLiane.Praza@Sun.COM #define	RC_MAX		1
22227887SLiane.Praza@Sun.COM #define	RC_COUNT	2
22237887SLiane.Praza@Sun.COM 
22247887SLiane.Praza@Sun.COM /*
22257887SLiane.Praza@Sun.COM  * Verify that the strings at min and max are valid numeric strings.  Also
22267887SLiane.Praza@Sun.COM  * verify that max is numerically >= min.
22277887SLiane.Praza@Sun.COM  *
22287887SLiane.Praza@Sun.COM  * 0 is returned if the range is valid, and -1 is returned if it is not.
22297887SLiane.Praza@Sun.COM  */
22307887SLiane.Praza@Sun.COM static int
verify_range(entity_t * service,xmlNodePtr range,char * min,char * max)22317887SLiane.Praza@Sun.COM verify_range(entity_t *service, xmlNodePtr range, char *min, char *max)
22327887SLiane.Praza@Sun.COM {
22337887SLiane.Praza@Sun.COM 	char *c;
22347887SLiane.Praza@Sun.COM 	int i;
22357887SLiane.Praza@Sun.COM 	int is_signed = 0;
22367887SLiane.Praza@Sun.COM 	int inverted = 0;
22377887SLiane.Praza@Sun.COM 	const char *limit[RC_COUNT];
22387887SLiane.Praza@Sun.COM 	char *strings[RC_COUNT];
22397887SLiane.Praza@Sun.COM 	uint64_t urange[RC_COUNT];	/* unsigned range. */
22407887SLiane.Praza@Sun.COM 	int64_t srange[RC_COUNT];	/* signed range. */
22417887SLiane.Praza@Sun.COM 
22427887SLiane.Praza@Sun.COM 	strings[RC_MIN] = min;
22437887SLiane.Praza@Sun.COM 	strings[RC_MAX] = max;
22447887SLiane.Praza@Sun.COM 	limit[RC_MIN] = min_attr;
22457887SLiane.Praza@Sun.COM 	limit[RC_MAX] = max_attr;
22467887SLiane.Praza@Sun.COM 
22477887SLiane.Praza@Sun.COM 	/* See if the range is signed. */
22487887SLiane.Praza@Sun.COM 	for (i = 0; (i < RC_COUNT) && (is_signed == 0); i++) {
22497887SLiane.Praza@Sun.COM 		c = strings[i];
22507887SLiane.Praza@Sun.COM 		while (isspace(*c)) {
22517887SLiane.Praza@Sun.COM 			c++;
22527887SLiane.Praza@Sun.COM 		}
22537887SLiane.Praza@Sun.COM 		if (*c == '-')
22547887SLiane.Praza@Sun.COM 			is_signed = 1;
22557887SLiane.Praza@Sun.COM 	}
22567887SLiane.Praza@Sun.COM 
22577887SLiane.Praza@Sun.COM 	/* Attempt to convert the strings. */
22587887SLiane.Praza@Sun.COM 	for (i = 0; i < RC_COUNT; i++) {
22597887SLiane.Praza@Sun.COM 		errno = 0;
22607887SLiane.Praza@Sun.COM 		if (is_signed) {
22617887SLiane.Praza@Sun.COM 			srange[i] = strtoll(strings[i], &c, 0);
22627887SLiane.Praza@Sun.COM 		} else {
22637887SLiane.Praza@Sun.COM 			urange[i] = strtoull(strings[i], &c, 0);
22647887SLiane.Praza@Sun.COM 		}
22657887SLiane.Praza@Sun.COM 		if ((errno != 0) || (c == strings[i]) || (*c != 0)) {
22667887SLiane.Praza@Sun.COM 			/* Conversion failed. */
22677887SLiane.Praza@Sun.COM 			uu_die(gettext("Unable to convert %s for the %s "
22687887SLiane.Praza@Sun.COM 			    "element in service %s.\n"), limit[i],
22697887SLiane.Praza@Sun.COM 			    (char *)range->name, service->sc_name);
22707887SLiane.Praza@Sun.COM 		}
22717887SLiane.Praza@Sun.COM 	}
22727887SLiane.Praza@Sun.COM 
22737887SLiane.Praza@Sun.COM 	/* Make sure that min is <= max */
22747887SLiane.Praza@Sun.COM 	if (is_signed) {
22757887SLiane.Praza@Sun.COM 		if (srange[RC_MAX] < srange[RC_MIN])
22767887SLiane.Praza@Sun.COM 			inverted = 1;
22777887SLiane.Praza@Sun.COM 	} else {
22787887SLiane.Praza@Sun.COM 		if (urange[RC_MAX] < urange[RC_MIN])
22797887SLiane.Praza@Sun.COM 			inverted = 1;
22807887SLiane.Praza@Sun.COM 	}
22817887SLiane.Praza@Sun.COM 	if (inverted != 0) {
22827887SLiane.Praza@Sun.COM 		semerr(gettext("Maximum less than minimum for the %s element "
22837887SLiane.Praza@Sun.COM 		    "in service %s.\n"), (char *)range->name,
22847887SLiane.Praza@Sun.COM 		    service->sc_name);
22857887SLiane.Praza@Sun.COM 		return (-1);
22867887SLiane.Praza@Sun.COM 	}
22877887SLiane.Praza@Sun.COM 
22887887SLiane.Praza@Sun.COM 	return (0);
22897887SLiane.Praza@Sun.COM }
22907887SLiane.Praza@Sun.COM 
22917887SLiane.Praza@Sun.COM /*
22927887SLiane.Praza@Sun.COM  * This, function creates a property named prop_name.  The range element
22937887SLiane.Praza@Sun.COM  * should have two attributes -- min and max.  The property value then
22947887SLiane.Praza@Sun.COM  * becomes the concatenation of their value separated by a comma.  The
22957887SLiane.Praza@Sun.COM  * property is then attached to the property group at pg.
22967887SLiane.Praza@Sun.COM  *
22977887SLiane.Praza@Sun.COM  * If pg already contains a property with a name of prop_name, it is only
22987887SLiane.Praza@Sun.COM  * necessary to create a new value and attach it to the existing property.
22997887SLiane.Praza@Sun.COM  */
23007887SLiane.Praza@Sun.COM static int
lxml_get_tm_range(entity_t * service,pgroup_t * pg,xmlNodePtr range,const char * prop_name)23017887SLiane.Praza@Sun.COM lxml_get_tm_range(entity_t *service, pgroup_t *pg, xmlNodePtr range,
23027887SLiane.Praza@Sun.COM     const char *prop_name)
23037887SLiane.Praza@Sun.COM {
23047887SLiane.Praza@Sun.COM 	boolean_t attach_to_pg = B_FALSE;
23057887SLiane.Praza@Sun.COM 	char *max;
23067887SLiane.Praza@Sun.COM 	char *min;
23077887SLiane.Praza@Sun.COM 	property_t *p;
23087887SLiane.Praza@Sun.COM 	char *prop_value;
23097887SLiane.Praza@Sun.COM 	int r = 0;
23107887SLiane.Praza@Sun.COM 
23117887SLiane.Praza@Sun.COM 	/* Get max and min from the XML description. */
23127887SLiane.Praza@Sun.COM 	max = (char *)xmlGetProp(range, (xmlChar *)max_attr);
23137887SLiane.Praza@Sun.COM 	if ((max == NULL) || (*max == 0)) {
23147887SLiane.Praza@Sun.COM 		uu_die(gettext("%s element is missing the %s attribute in "
23157887SLiane.Praza@Sun.COM 		    "service %s.\n"), (char *)range->name, max_attr,
23167887SLiane.Praza@Sun.COM 		    service->sc_name);
23177887SLiane.Praza@Sun.COM 	}
23187887SLiane.Praza@Sun.COM 	min = (char *)xmlGetProp(range, (xmlChar *)min_attr);
23197887SLiane.Praza@Sun.COM 	if ((min == NULL) || (*min == 0)) {
23207887SLiane.Praza@Sun.COM 		uu_die(gettext("%s element is missing the %s attribute in "
23217887SLiane.Praza@Sun.COM 		    "service %s.\n"), (char *)range->name, min_attr,
23227887SLiane.Praza@Sun.COM 		    service->sc_name);
23237887SLiane.Praza@Sun.COM 	}
23247887SLiane.Praza@Sun.COM 	if (verify_range(service, range, min, max) != 0) {
23257887SLiane.Praza@Sun.COM 		xmlFree(min);
23267887SLiane.Praza@Sun.COM 		xmlFree(max);
23277887SLiane.Praza@Sun.COM 		return (-1);
23287887SLiane.Praza@Sun.COM 	}
23297887SLiane.Praza@Sun.COM 
23307887SLiane.Praza@Sun.COM 	/* Property value is concatenation of min and max. */
23317887SLiane.Praza@Sun.COM 	prop_value = safe_malloc(max_scf_value_len + 1);
23327887SLiane.Praza@Sun.COM 	if (snprintf(prop_value, max_scf_value_len + 1, "%s,%s", min, max) >=
23337887SLiane.Praza@Sun.COM 	    max_scf_value_len + 1) {
23347887SLiane.Praza@Sun.COM 		uu_die(gettext("min and max are too long for the %s element "
23357887SLiane.Praza@Sun.COM 		    "of %s.\n"), (char *)range->name, service->sc_name);
23367887SLiane.Praza@Sun.COM 	}
23377887SLiane.Praza@Sun.COM 	xmlFree(min);
23387887SLiane.Praza@Sun.COM 	xmlFree(max);
23397887SLiane.Praza@Sun.COM 
23407887SLiane.Praza@Sun.COM 	/*
23417887SLiane.Praza@Sun.COM 	 * If necessary create the property and attach it to the property
23427887SLiane.Praza@Sun.COM 	 * group.
23437887SLiane.Praza@Sun.COM 	 */
23447887SLiane.Praza@Sun.COM 	p = internal_property_find(pg, prop_name);
23457887SLiane.Praza@Sun.COM 	if (p == NULL)
23467887SLiane.Praza@Sun.COM 		attach_to_pg = B_TRUE;
23477887SLiane.Praza@Sun.COM 	astring_prop_value(&p, prop_name, prop_value, B_TRUE);
23487887SLiane.Praza@Sun.COM 	if (attach_to_pg == B_TRUE) {
23497887SLiane.Praza@Sun.COM 		r = internal_attach_property(pg, p);
23507887SLiane.Praza@Sun.COM 		if (r != 0) {
23517887SLiane.Praza@Sun.COM 			internal_property_free(p);
23527887SLiane.Praza@Sun.COM 		}
23537887SLiane.Praza@Sun.COM 	}
23547887SLiane.Praza@Sun.COM 	return (r);
23557887SLiane.Praza@Sun.COM }
23567887SLiane.Praza@Sun.COM 
23577887SLiane.Praza@Sun.COM /*
23587887SLiane.Praza@Sun.COM  * Determine how many plain characters are represented by count Base32
23597887SLiane.Praza@Sun.COM  * encoded characters.  5 plain text characters are converted to 8 Base32
23607887SLiane.Praza@Sun.COM  * characters.
23617887SLiane.Praza@Sun.COM  */
23627887SLiane.Praza@Sun.COM static size_t
encoded_count_to_plain(size_t count)23637887SLiane.Praza@Sun.COM encoded_count_to_plain(size_t count)
23647887SLiane.Praza@Sun.COM {
23657887SLiane.Praza@Sun.COM 	return (5 * ((count + 7) / 8));
23667887SLiane.Praza@Sun.COM }
23677887SLiane.Praza@Sun.COM 
23687887SLiane.Praza@Sun.COM /*
23697887SLiane.Praza@Sun.COM  * The value element contains 0 or 1 common_name element followed by 0 or 1
23707887SLiane.Praza@Sun.COM  * description element.  It also has a required attribute called "name".
23717887SLiane.Praza@Sun.COM  * The common_name and description are stored as property values in pg.
23727887SLiane.Praza@Sun.COM  * The property names are:
23737887SLiane.Praza@Sun.COM  *	value_<name>_common_name_<lang>
23747887SLiane.Praza@Sun.COM  *	value_<name>_description_<lang>
23757887SLiane.Praza@Sun.COM  *
23767887SLiane.Praza@Sun.COM  * The <name> portion of the preceeding proper names requires more
23777887SLiane.Praza@Sun.COM  * explanation.  Ideally it would just the name attribute of this value
23787887SLiane.Praza@Sun.COM  * element.  Unfortunately, the name attribute can contain characters that
23797887SLiane.Praza@Sun.COM  * are not legal in a property name.  Thus, we base 32 encode the name
23807887SLiane.Praza@Sun.COM  * attribute and use that for <name>.
23817887SLiane.Praza@Sun.COM  *
23827887SLiane.Praza@Sun.COM  * There are cases where the caller needs to know the name, so it is
23837887SLiane.Praza@Sun.COM  * returned through the name_value pointer if it is not NULL.
23847887SLiane.Praza@Sun.COM  *
23857887SLiane.Praza@Sun.COM  * Parameters:
23867887SLiane.Praza@Sun.COM  *	service -	Information about the service that is being
23877887SLiane.Praza@Sun.COM  *			processed.  This function only uses this parameter
23887887SLiane.Praza@Sun.COM  *			for producing error messages.
23897887SLiane.Praza@Sun.COM  *
23907887SLiane.Praza@Sun.COM  *	pg -		The property group to receive the newly created
23917887SLiane.Praza@Sun.COM  *			properties.
23927887SLiane.Praza@Sun.COM  *
23937887SLiane.Praza@Sun.COM  *	value -		Pointer to the value element in the XML tree.
23947887SLiane.Praza@Sun.COM  *
23957887SLiane.Praza@Sun.COM  *	name_value -	Address to receive the value of the name attribute.
23967887SLiane.Praza@Sun.COM  *			The caller must free the memory.
23977887SLiane.Praza@Sun.COM  */
23987887SLiane.Praza@Sun.COM static int
lxml_get_tm_value_element(entity_t * service,pgroup_t * pg,xmlNodePtr value,char ** name_value)23997887SLiane.Praza@Sun.COM lxml_get_tm_value_element(entity_t *service, pgroup_t *pg, xmlNodePtr value,
24007887SLiane.Praza@Sun.COM     char **name_value)
24017887SLiane.Praza@Sun.COM {
24027887SLiane.Praza@Sun.COM 	char *common_name_fmt;
24037887SLiane.Praza@Sun.COM 	xmlNodePtr cursor;
24047887SLiane.Praza@Sun.COM 	char *description_fmt;
24057887SLiane.Praza@Sun.COM 	char *encoded_value = NULL;
24067887SLiane.Praza@Sun.COM 	size_t extra;
24077887SLiane.Praza@Sun.COM 	char *value_name;
24087887SLiane.Praza@Sun.COM 	int r = 0;
24097887SLiane.Praza@Sun.COM 
24107887SLiane.Praza@Sun.COM 	common_name_fmt = safe_malloc(max_scf_name_len + 1);
24117887SLiane.Praza@Sun.COM 	description_fmt = safe_malloc(max_scf_name_len + 1);
24127887SLiane.Praza@Sun.COM 
24137887SLiane.Praza@Sun.COM 	/*
24147887SLiane.Praza@Sun.COM 	 * Get the value of our name attribute, so that we can use it to
24157887SLiane.Praza@Sun.COM 	 * construct property names.
24167887SLiane.Praza@Sun.COM 	 */
24177887SLiane.Praza@Sun.COM 	value_name = (char *)xmlGetProp(value, (xmlChar *)name_attr);
24187887SLiane.Praza@Sun.COM 	/* The value name must be present, but it can be empty. */
24197887SLiane.Praza@Sun.COM 	if (value_name == NULL) {
24207887SLiane.Praza@Sun.COM 		uu_die(gettext("%s element requires a %s attribute in the %s "
24217887SLiane.Praza@Sun.COM 		    "service.\n"), (char *)value->name, name_attr,
24227887SLiane.Praza@Sun.COM 		    service->sc_name);
24237887SLiane.Praza@Sun.COM 	}
24247887SLiane.Praza@Sun.COM 
24257887SLiane.Praza@Sun.COM 	/*
24267887SLiane.Praza@Sun.COM 	 * The value_name may contain characters that are not valid in in a
24277887SLiane.Praza@Sun.COM 	 * property name.  So we will encode value_name and then use the
24287887SLiane.Praza@Sun.COM 	 * encoded value in the property name.
24297887SLiane.Praza@Sun.COM 	 */
24307887SLiane.Praza@Sun.COM 	encoded_value = safe_malloc(max_scf_name_len + 1);
24317887SLiane.Praza@Sun.COM 	if (scf_encode32(value_name, strlen(value_name), encoded_value,
24327887SLiane.Praza@Sun.COM 	    max_scf_name_len + 1, &extra, SCF_ENCODE32_PAD) != 0) {
24337887SLiane.Praza@Sun.COM 		extra = encoded_count_to_plain(extra - max_scf_name_len);
24347887SLiane.Praza@Sun.COM 		uu_die(gettext("Constructed property name is %u characters "
24357887SLiane.Praza@Sun.COM 		    "too long for value \"%s\" in the %s service.\n"),
24367887SLiane.Praza@Sun.COM 		    extra, value_name, service->sc_name);
24377887SLiane.Praza@Sun.COM 	}
24387887SLiane.Praza@Sun.COM 	if ((extra = snprintf(common_name_fmt, max_scf_name_len + 1,
24397887SLiane.Praza@Sun.COM 	    VALUE_COMMON_NAME_FMT, SCF_PROPERTY_TM_VALUE_PREFIX,
24407887SLiane.Praza@Sun.COM 	    encoded_value)) >= max_scf_name_len + 1) {
24417887SLiane.Praza@Sun.COM 		extra = encoded_count_to_plain(extra - max_scf_name_len);
24427887SLiane.Praza@Sun.COM 		uu_die(gettext("Name attribute is "
24437887SLiane.Praza@Sun.COM 		    "%u characters too long for %s in service %s\n"),
24447887SLiane.Praza@Sun.COM 		    extra, (char *)value->name, service->sc_name);
24457887SLiane.Praza@Sun.COM 	}
24467887SLiane.Praza@Sun.COM 	if ((extra = snprintf(description_fmt, max_scf_name_len + 1,
24477887SLiane.Praza@Sun.COM 	    VALUE_DESCRIPTION_FMT, SCF_PROPERTY_TM_VALUE_PREFIX,
24487887SLiane.Praza@Sun.COM 	    encoded_value)) >= max_scf_name_len + 1) {
24497887SLiane.Praza@Sun.COM 		extra = encoded_count_to_plain(extra - max_scf_name_len);
24507887SLiane.Praza@Sun.COM 		uu_die(gettext("Name attribute is "
24517887SLiane.Praza@Sun.COM 		    "%u characters too long for %s in service %s\n"),
24527887SLiane.Praza@Sun.COM 		    extra, (char *)value->name, service->sc_name);
24537887SLiane.Praza@Sun.COM 	}
24547887SLiane.Praza@Sun.COM 
24557887SLiane.Praza@Sun.COM 	for (cursor = value->xmlChildrenNode;
24567887SLiane.Praza@Sun.COM 	    cursor != NULL;
24577887SLiane.Praza@Sun.COM 	    cursor = cursor->next) {
24587887SLiane.Praza@Sun.COM 		if (lxml_ignorable_block(cursor))
24597887SLiane.Praza@Sun.COM 			continue;
24607887SLiane.Praza@Sun.COM 		switch (lxml_xlate_element(cursor->name)) {
24617887SLiane.Praza@Sun.COM 		case SC_COMMON_NAME:
24627887SLiane.Praza@Sun.COM 			r = lxml_get_all_loctext(service, pg, cursor,
24637887SLiane.Praza@Sun.COM 			    common_name_fmt, (const char *)cursor->name);
24647887SLiane.Praza@Sun.COM 			break;
24657887SLiane.Praza@Sun.COM 		case SC_DESCRIPTION:
24667887SLiane.Praza@Sun.COM 			r = lxml_get_all_loctext(service, pg, cursor,
24677887SLiane.Praza@Sun.COM 			    description_fmt, (const char *)cursor->name);
24687887SLiane.Praza@Sun.COM 			break;
24697887SLiane.Praza@Sun.COM 		default:
24707887SLiane.Praza@Sun.COM 			uu_die(gettext("\"%s\" is an illegal element in %s "
24717887SLiane.Praza@Sun.COM 			    "of service %s\n"), (char *)cursor->name,
24727887SLiane.Praza@Sun.COM 			    (char *)value->name, service->sc_name);
24737887SLiane.Praza@Sun.COM 		}
24747887SLiane.Praza@Sun.COM 		if (r != 0)
24757887SLiane.Praza@Sun.COM 			break;
24767887SLiane.Praza@Sun.COM 	}
24777887SLiane.Praza@Sun.COM 
24787887SLiane.Praza@Sun.COM 	free(description_fmt);
24797887SLiane.Praza@Sun.COM 	free(common_name_fmt);
24807887SLiane.Praza@Sun.COM 	if (r == 0) {
24817887SLiane.Praza@Sun.COM 		*name_value = safe_strdup(value_name);
24827887SLiane.Praza@Sun.COM 	}
24837887SLiane.Praza@Sun.COM 	xmlFree(value_name);
24847887SLiane.Praza@Sun.COM 	free(encoded_value);
24857887SLiane.Praza@Sun.COM 	return (r);
24867887SLiane.Praza@Sun.COM }
24877887SLiane.Praza@Sun.COM 
24887887SLiane.Praza@Sun.COM static int
lxml_get_tm_choices(entity_t * service,pgroup_t * pg,xmlNodePtr choices)24897887SLiane.Praza@Sun.COM lxml_get_tm_choices(entity_t *service, pgroup_t *pg, xmlNodePtr choices)
24907887SLiane.Praza@Sun.COM {
24917887SLiane.Praza@Sun.COM 	xmlNodePtr cursor;
24927887SLiane.Praza@Sun.COM 	char *name_value;
24937887SLiane.Praza@Sun.COM 	property_t *name_prop = NULL;
24947887SLiane.Praza@Sun.COM 	int r = 0;
24957887SLiane.Praza@Sun.COM 
24967887SLiane.Praza@Sun.COM 	for (cursor = choices->xmlChildrenNode;
24977887SLiane.Praza@Sun.COM 	    (cursor != NULL) && (r == 0);
24987887SLiane.Praza@Sun.COM 	    cursor = cursor->next) {
24997887SLiane.Praza@Sun.COM 		if (lxml_ignorable_block(cursor))
25007887SLiane.Praza@Sun.COM 			continue;
25017887SLiane.Praza@Sun.COM 		switch (lxml_xlate_element(cursor->name)) {
25027887SLiane.Praza@Sun.COM 		case SC_INCLUDE_VALUES:
25037887SLiane.Praza@Sun.COM 			(void) lxml_get_tm_include_values(service, pg, cursor,
25047887SLiane.Praza@Sun.COM 			    SCF_PROPERTY_TM_CHOICES_INCLUDE_VALUES);
25057887SLiane.Praza@Sun.COM 			break;
25067887SLiane.Praza@Sun.COM 		case SC_RANGE:
25077887SLiane.Praza@Sun.COM 			r = lxml_get_tm_range(service, pg, cursor,
25087887SLiane.Praza@Sun.COM 			    SCF_PROPERTY_TM_CHOICES_RANGE);
25097887SLiane.Praza@Sun.COM 			if (r != 0)
25107887SLiane.Praza@Sun.COM 				goto out;
25117887SLiane.Praza@Sun.COM 			break;
25127887SLiane.Praza@Sun.COM 		case SC_VALUE:
25137887SLiane.Praza@Sun.COM 			r = lxml_get_tm_value_element(service, pg, cursor,
25147887SLiane.Praza@Sun.COM 			    &name_value);
25157887SLiane.Praza@Sun.COM 			if (r == 0) {
25167887SLiane.Praza@Sun.COM 				/*
25177887SLiane.Praza@Sun.COM 				 * There is no need to free the memory
25187887SLiane.Praza@Sun.COM 				 * associated with name_value, because the
25197887SLiane.Praza@Sun.COM 				 * property value will end up pointing to
25207887SLiane.Praza@Sun.COM 				 * the memory.
25217887SLiane.Praza@Sun.COM 				 */
25227887SLiane.Praza@Sun.COM 				astring_prop_value(&name_prop,
25237887SLiane.Praza@Sun.COM 				    SCF_PROPERTY_TM_CHOICES_NAME, name_value,
25247887SLiane.Praza@Sun.COM 				    B_TRUE);
25257887SLiane.Praza@Sun.COM 			} else {
25267887SLiane.Praza@Sun.COM 				goto out;
25277887SLiane.Praza@Sun.COM 			}
25287887SLiane.Praza@Sun.COM 			break;
25297887SLiane.Praza@Sun.COM 		default:
25307887SLiane.Praza@Sun.COM 			uu_die(gettext("%s is an invalid element of "
25317887SLiane.Praza@Sun.COM 			    "choices for service %s.\n"),  cursor->name,
25327887SLiane.Praza@Sun.COM 			    service->sc_name);
25337887SLiane.Praza@Sun.COM 		}
25347887SLiane.Praza@Sun.COM 	}
25357887SLiane.Praza@Sun.COM 
25367887SLiane.Praza@Sun.COM out:
25377887SLiane.Praza@Sun.COM 	/* Attach the name property if we created one. */
25387887SLiane.Praza@Sun.COM 	if ((r == 0) && (name_prop != NULL)) {
25397887SLiane.Praza@Sun.COM 		r = internal_attach_property(pg, name_prop);
25407887SLiane.Praza@Sun.COM 	}
25417887SLiane.Praza@Sun.COM 	if ((r != 0) && (name_prop != NULL)) {
25427887SLiane.Praza@Sun.COM 		internal_property_free(name_prop);
25437887SLiane.Praza@Sun.COM 	}
25447887SLiane.Praza@Sun.COM 
25457887SLiane.Praza@Sun.COM 	return (r);
25467887SLiane.Praza@Sun.COM }
25477887SLiane.Praza@Sun.COM 
25487887SLiane.Praza@Sun.COM static int
lxml_get_tm_constraints(entity_t * service,pgroup_t * pg,xmlNodePtr constraints)25497887SLiane.Praza@Sun.COM lxml_get_tm_constraints(entity_t *service, pgroup_t *pg, xmlNodePtr constraints)
25507887SLiane.Praza@Sun.COM {
25517887SLiane.Praza@Sun.COM 	xmlNodePtr cursor;
25527887SLiane.Praza@Sun.COM 	char *name_value;
25537887SLiane.Praza@Sun.COM 	property_t *name_prop = NULL;
25547887SLiane.Praza@Sun.COM 	int r = 0;
25557887SLiane.Praza@Sun.COM 
25567887SLiane.Praza@Sun.COM 	for (cursor = constraints->xmlChildrenNode;
25577887SLiane.Praza@Sun.COM 	    (cursor != NULL) && (r == 0);
25587887SLiane.Praza@Sun.COM 	    cursor = cursor->next) {
25597887SLiane.Praza@Sun.COM 		if (lxml_ignorable_block(cursor))
25607887SLiane.Praza@Sun.COM 			continue;
25617887SLiane.Praza@Sun.COM 		switch (lxml_xlate_element(cursor->name)) {
25627887SLiane.Praza@Sun.COM 		case SC_RANGE:
25637887SLiane.Praza@Sun.COM 			r = lxml_get_tm_range(service, pg, cursor,
25647887SLiane.Praza@Sun.COM 			    SCF_PROPERTY_TM_CONSTRAINT_RANGE);
25657887SLiane.Praza@Sun.COM 			if (r != 0)
25667887SLiane.Praza@Sun.COM 				goto out;
25677887SLiane.Praza@Sun.COM 			break;
25687887SLiane.Praza@Sun.COM 		case SC_VALUE:
25697887SLiane.Praza@Sun.COM 			r = lxml_get_tm_value_element(service, pg, cursor,
25707887SLiane.Praza@Sun.COM 			    &name_value);
25717887SLiane.Praza@Sun.COM 			if (r == 0) {
25727887SLiane.Praza@Sun.COM 				/*
25737887SLiane.Praza@Sun.COM 				 * There is no need to free the memory
25747887SLiane.Praza@Sun.COM 				 * associated with name_value, because the
25757887SLiane.Praza@Sun.COM 				 * property value will end up pointing to
25767887SLiane.Praza@Sun.COM 				 * the memory.
25777887SLiane.Praza@Sun.COM 				 */
25787887SLiane.Praza@Sun.COM 				astring_prop_value(&name_prop,
25797887SLiane.Praza@Sun.COM 				    SCF_PROPERTY_TM_CONSTRAINT_NAME, name_value,
25807887SLiane.Praza@Sun.COM 				    B_TRUE);
25817887SLiane.Praza@Sun.COM 			} else {
25827887SLiane.Praza@Sun.COM 				goto out;
25837887SLiane.Praza@Sun.COM 			}
25847887SLiane.Praza@Sun.COM 			break;
25857887SLiane.Praza@Sun.COM 		default:
25867887SLiane.Praza@Sun.COM 			uu_die(gettext("%s is an invalid element of "
25877887SLiane.Praza@Sun.COM 			    "constraints for service %s.\n"),  cursor->name,
25887887SLiane.Praza@Sun.COM 			    service->sc_name);
25897887SLiane.Praza@Sun.COM 		}
25907887SLiane.Praza@Sun.COM 	}
25917887SLiane.Praza@Sun.COM 
25927887SLiane.Praza@Sun.COM out:
25937887SLiane.Praza@Sun.COM 	/* Attach the name property if we created one. */
25947887SLiane.Praza@Sun.COM 	if ((r == 0) && (name_prop != NULL)) {
25957887SLiane.Praza@Sun.COM 		r = internal_attach_property(pg, name_prop);
25967887SLiane.Praza@Sun.COM 	}
25977887SLiane.Praza@Sun.COM 	if ((r != 0) && (name_prop != NULL)) {
25987887SLiane.Praza@Sun.COM 		internal_property_free(name_prop);
25997887SLiane.Praza@Sun.COM 	}
26007887SLiane.Praza@Sun.COM 
26017887SLiane.Praza@Sun.COM 	return (r);
26027887SLiane.Praza@Sun.COM }
26037887SLiane.Praza@Sun.COM 
26047887SLiane.Praza@Sun.COM /*
26057887SLiane.Praza@Sun.COM  * The values element contains one or more value elements.
26067887SLiane.Praza@Sun.COM  */
26077887SLiane.Praza@Sun.COM static int
lxml_get_tm_values(entity_t * service,pgroup_t * pg,xmlNodePtr values)26087887SLiane.Praza@Sun.COM lxml_get_tm_values(entity_t *service, pgroup_t *pg, xmlNodePtr values)
26097887SLiane.Praza@Sun.COM {
26107887SLiane.Praza@Sun.COM 	xmlNodePtr cursor;
26117887SLiane.Praza@Sun.COM 	char *name_value;
26127887SLiane.Praza@Sun.COM 	property_t *name_prop = NULL;
26137887SLiane.Praza@Sun.COM 	int r = 0;
26147887SLiane.Praza@Sun.COM 
26157887SLiane.Praza@Sun.COM 	for (cursor = values->xmlChildrenNode;
26167887SLiane.Praza@Sun.COM 	    (cursor != NULL) && (r == 0);
26177887SLiane.Praza@Sun.COM 	    cursor = cursor->next) {
26187887SLiane.Praza@Sun.COM 		if (lxml_ignorable_block(cursor))
26197887SLiane.Praza@Sun.COM 			continue;
26207887SLiane.Praza@Sun.COM 		if (lxml_xlate_element(cursor->name) != SC_VALUE) {
26217887SLiane.Praza@Sun.COM 			uu_die(gettext("\"%s\" is an illegal element in the "
26227887SLiane.Praza@Sun.COM 			    "%s element of %s\n"), (char *)cursor->name,
26237887SLiane.Praza@Sun.COM 			    (char *)values->name, service->sc_name);
26247887SLiane.Praza@Sun.COM 		}
26257887SLiane.Praza@Sun.COM 		r = lxml_get_tm_value_element(service, pg, cursor, &name_value);
26267887SLiane.Praza@Sun.COM 		if (r == 0) {
26277887SLiane.Praza@Sun.COM 			/*
26287887SLiane.Praza@Sun.COM 			 * There is no need to free the memory
26297887SLiane.Praza@Sun.COM 			 * associated with name_value, because the
26307887SLiane.Praza@Sun.COM 			 * property value will end up pointing to
26317887SLiane.Praza@Sun.COM 			 * the memory.
26327887SLiane.Praza@Sun.COM 			 */
26337887SLiane.Praza@Sun.COM 			astring_prop_value(&name_prop,
26347887SLiane.Praza@Sun.COM 			    SCF_PROPERTY_TM_VALUES_NAME, name_value,
26357887SLiane.Praza@Sun.COM 			    B_TRUE);
26367887SLiane.Praza@Sun.COM 		}
26377887SLiane.Praza@Sun.COM 	}
26387887SLiane.Praza@Sun.COM 
26397887SLiane.Praza@Sun.COM 	/* Attach the name property if we created one. */
26407887SLiane.Praza@Sun.COM 	if ((r == 0) && (name_prop != NULL)) {
26417887SLiane.Praza@Sun.COM 		r = internal_attach_property(pg, name_prop);
26427887SLiane.Praza@Sun.COM 	}
26437887SLiane.Praza@Sun.COM 	if ((r != 0) && (name_prop != NULL)) {
26447887SLiane.Praza@Sun.COM 		internal_property_free(name_prop);
26457887SLiane.Praza@Sun.COM 	}
26467887SLiane.Praza@Sun.COM 
26477887SLiane.Praza@Sun.COM 	return (r);
26487887SLiane.Praza@Sun.COM }
26497887SLiane.Praza@Sun.COM 
26507887SLiane.Praza@Sun.COM /*
26517887SLiane.Praza@Sun.COM  * This function processes a prop_pattern element within a pg_pattern XML
26527887SLiane.Praza@Sun.COM  * element.  First it creates a property group to hold the prop_pattern
26537887SLiane.Praza@Sun.COM  * information.  The name of this property group is the concatenation of:
26547887SLiane.Praza@Sun.COM  *	- SCF_PG_TM_PROP_PATTERN_PREFIX
26557887SLiane.Praza@Sun.COM  *	- The unique part of the property group name of the enclosing
26567887SLiane.Praza@Sun.COM  *	  pg_pattern.  The property group name of the enclosing pg_pattern
26577887SLiane.Praza@Sun.COM  *	  is passed to us in pgpat_name.  The unique part, is the part
26587887SLiane.Praza@Sun.COM  *	  following SCF_PG_TM_PG_PATTERN_PREFIX.
26597887SLiane.Praza@Sun.COM  *	- The name of this prop_pattern element.
26607887SLiane.Praza@Sun.COM  *
26617887SLiane.Praza@Sun.COM  * After creating the property group, the prop_pattern attributes are saved
26627887SLiane.Praza@Sun.COM  * as properties in the PG.  Finally, the prop_pattern elements are
26637887SLiane.Praza@Sun.COM  * processed and added to the PG.
26647887SLiane.Praza@Sun.COM  */
26657887SLiane.Praza@Sun.COM static int
lxml_get_tm_prop_pattern(entity_t * service,xmlNodePtr prop_pattern,const char * pgpat_name)26667887SLiane.Praza@Sun.COM lxml_get_tm_prop_pattern(entity_t *service, xmlNodePtr prop_pattern,
26677887SLiane.Praza@Sun.COM     const char *pgpat_name)
26687887SLiane.Praza@Sun.COM {
26697887SLiane.Praza@Sun.COM 	xmlNodePtr cursor;
26707887SLiane.Praza@Sun.COM 	int extra;
26717887SLiane.Praza@Sun.COM 	pgroup_t *pg;
26727887SLiane.Praza@Sun.COM 	property_t *p;
26737887SLiane.Praza@Sun.COM 	char *pg_name;
26747887SLiane.Praza@Sun.COM 	size_t prefix_len;
26757887SLiane.Praza@Sun.COM 	xmlChar *prop_pattern_name;
26767887SLiane.Praza@Sun.COM 	int r;
26777887SLiane.Praza@Sun.COM 	const char *unique;
26787887SLiane.Praza@Sun.COM 	value_t *v;
26797887SLiane.Praza@Sun.COM 
26807887SLiane.Praza@Sun.COM 	/* Find the unique part of the pg_pattern property group name. */
26817887SLiane.Praza@Sun.COM 	prefix_len = strlen(SCF_PG_TM_PG_PAT_BASE);
26827887SLiane.Praza@Sun.COM 	assert(strncmp(pgpat_name, SCF_PG_TM_PG_PAT_BASE, prefix_len) == 0);
26837887SLiane.Praza@Sun.COM 	unique = pgpat_name + prefix_len;
26847887SLiane.Praza@Sun.COM 
26857887SLiane.Praza@Sun.COM 	/*
26867887SLiane.Praza@Sun.COM 	 * We need to get the value of the name attribute first.  The
26877887SLiane.Praza@Sun.COM 	 * prop_pattern name as well as the name of the enclosing
26887887SLiane.Praza@Sun.COM 	 * pg_pattern both constitute part of the name of the property
26897887SLiane.Praza@Sun.COM 	 * group that we will create.
26907887SLiane.Praza@Sun.COM 	 */
26917887SLiane.Praza@Sun.COM 	prop_pattern_name = xmlGetProp(prop_pattern, (xmlChar *)name_attr);
26927887SLiane.Praza@Sun.COM 	if ((prop_pattern_name == NULL) || (*prop_pattern_name == 0)) {
26937887SLiane.Praza@Sun.COM 		semerr(gettext("prop_pattern name is missing for %s\n"),
26947887SLiane.Praza@Sun.COM 		    service->sc_name);
26957887SLiane.Praza@Sun.COM 		return (-1);
26967887SLiane.Praza@Sun.COM 	}
26977887SLiane.Praza@Sun.COM 	if (uu_check_name((const char *)prop_pattern_name,
26987887SLiane.Praza@Sun.COM 	    UU_NAME_DOMAIN) != 0) {
26997887SLiane.Praza@Sun.COM 		semerr(gettext("prop_pattern name, \"%s\", for %s is not "
27007887SLiane.Praza@Sun.COM 		    "valid.\n"), prop_pattern_name, service->sc_name);
27017887SLiane.Praza@Sun.COM 		xmlFree(prop_pattern_name);
27027887SLiane.Praza@Sun.COM 		return (-1);
27037887SLiane.Praza@Sun.COM 	}
27047887SLiane.Praza@Sun.COM 	pg_name = safe_malloc(max_scf_name_len + 1);
27057887SLiane.Praza@Sun.COM 	if ((extra = snprintf(pg_name, max_scf_name_len + 1, "%s%s_%s",
27067887SLiane.Praza@Sun.COM 	    SCF_PG_TM_PROP_PATTERN_PREFIX, unique,
27077887SLiane.Praza@Sun.COM 	    (char *)prop_pattern_name)) >= max_scf_name_len + 1) {
27087887SLiane.Praza@Sun.COM 		uu_die(gettext("prop_pattern name, \"%s\", for %s is %d "
27097887SLiane.Praza@Sun.COM 		    "characters too long\n"), (char *)prop_pattern_name,
27107887SLiane.Praza@Sun.COM 		    service->sc_name, extra - max_scf_name_len);
27117887SLiane.Praza@Sun.COM 	}
27127887SLiane.Praza@Sun.COM 
27137887SLiane.Praza@Sun.COM 	/*
27147887SLiane.Praza@Sun.COM 	 * Create the property group, the property referencing the pg_pattern
27157887SLiane.Praza@Sun.COM 	 * name, and add the prop_pattern attributes to the property group.
27167887SLiane.Praza@Sun.COM 	 */
27177887SLiane.Praza@Sun.COM 	pg = internal_pgroup_create_strict(service, pg_name,
27187887SLiane.Praza@Sun.COM 	    SCF_GROUP_TEMPLATE_PROP_PATTERN);
27197887SLiane.Praza@Sun.COM 	if (pg == NULL) {
27207887SLiane.Praza@Sun.COM 		uu_die(gettext("Property group for prop_pattern, \"%s\", "
27217887SLiane.Praza@Sun.COM 		    "already exists in %s\n"), prop_pattern_name,
27227887SLiane.Praza@Sun.COM 		    service->sc_name);
27237887SLiane.Praza@Sun.COM 	}
27247887SLiane.Praza@Sun.COM 
27257887SLiane.Praza@Sun.COM 	p = internal_property_create(SCF_PROPERTY_TM_PG_PATTERN,
27267887SLiane.Praza@Sun.COM 	    SCF_TYPE_ASTRING, 1, safe_strdup(pgpat_name));
27277887SLiane.Praza@Sun.COM 	/*
27287887SLiane.Praza@Sun.COM 	 * Unfortunately, internal_property_create() does not set the free
27297887SLiane.Praza@Sun.COM 	 * function for the value, so we'll set it now.
27307887SLiane.Praza@Sun.COM 	 */
27317887SLiane.Praza@Sun.COM 	v = uu_list_first(p->sc_property_values);
27327887SLiane.Praza@Sun.COM 	v->sc_free = lxml_free_str;
27337887SLiane.Praza@Sun.COM 	if (internal_attach_property(pg, p) != 0)
27347887SLiane.Praza@Sun.COM 		internal_property_free(p);
27357887SLiane.Praza@Sun.COM 
27367887SLiane.Praza@Sun.COM 
27377887SLiane.Praza@Sun.COM 	r = lxml_get_prop_pattern_attributes(pg, prop_pattern);
27387887SLiane.Praza@Sun.COM 	if (r != 0)
27397887SLiane.Praza@Sun.COM 		goto out;
27407887SLiane.Praza@Sun.COM 
27417887SLiane.Praza@Sun.COM 	/*
27427887SLiane.Praza@Sun.COM 	 * Now process the elements of prop_pattern
27437887SLiane.Praza@Sun.COM 	 */
27447887SLiane.Praza@Sun.COM 	for (cursor = prop_pattern->xmlChildrenNode;
27457887SLiane.Praza@Sun.COM 	    cursor != NULL;
27467887SLiane.Praza@Sun.COM 	    cursor = cursor->next) {
27477887SLiane.Praza@Sun.COM 		if (lxml_ignorable_block(cursor))
27487887SLiane.Praza@Sun.COM 			continue;
27497887SLiane.Praza@Sun.COM 
27507887SLiane.Praza@Sun.COM 		switch (lxml_xlate_element(cursor->name)) {
27517887SLiane.Praza@Sun.COM 		case SC_CARDINALITY:
27527887SLiane.Praza@Sun.COM 			r = lxml_get_tm_cardinality(service, pg, cursor);
27537887SLiane.Praza@Sun.COM 			if (r != 0)
27547887SLiane.Praza@Sun.COM 				goto out;
27557887SLiane.Praza@Sun.COM 			break;
27567887SLiane.Praza@Sun.COM 		case SC_CHOICES:
27577887SLiane.Praza@Sun.COM 			r = lxml_get_tm_choices(service, pg, cursor);
27587887SLiane.Praza@Sun.COM 			if (r != 0)
27597887SLiane.Praza@Sun.COM 				goto out;
27607887SLiane.Praza@Sun.COM 			break;
27617887SLiane.Praza@Sun.COM 		case SC_COMMON_NAME:
27627887SLiane.Praza@Sun.COM 			(void) lxml_get_all_loctext(service, pg, cursor,
27637887SLiane.Praza@Sun.COM 			    COMMON_NAME_FMT, (const char *)cursor->name);
27647887SLiane.Praza@Sun.COM 			break;
27657887SLiane.Praza@Sun.COM 		case SC_CONSTRAINTS:
27667887SLiane.Praza@Sun.COM 			r = lxml_get_tm_constraints(service, pg, cursor);
27677887SLiane.Praza@Sun.COM 			if (r != 0)
27687887SLiane.Praza@Sun.COM 				goto out;
27697887SLiane.Praza@Sun.COM 			break;
27707887SLiane.Praza@Sun.COM 		case SC_DESCRIPTION:
27717887SLiane.Praza@Sun.COM 			(void) lxml_get_all_loctext(service, pg, cursor,
27727887SLiane.Praza@Sun.COM 			    DESCRIPTION_FMT, (const char *)cursor->name);
27737887SLiane.Praza@Sun.COM 			break;
27747887SLiane.Praza@Sun.COM 		case SC_INTERNAL_SEPARATORS:
27757887SLiane.Praza@Sun.COM 			r = lxml_get_tm_internal_seps(service, pg, cursor);
27767887SLiane.Praza@Sun.COM 			if (r != 0)
27777887SLiane.Praza@Sun.COM 				goto out;
27787887SLiane.Praza@Sun.COM 			break;
27797887SLiane.Praza@Sun.COM 		case SC_UNITS:
27807887SLiane.Praza@Sun.COM 			(void) lxml_get_all_loctext(service, pg, cursor,
27817887SLiane.Praza@Sun.COM 			    UNITS_FMT, "units");
27827887SLiane.Praza@Sun.COM 			break;
27837887SLiane.Praza@Sun.COM 		case SC_VALUES:
27847887SLiane.Praza@Sun.COM 			(void) lxml_get_tm_values(service, pg, cursor);
27857887SLiane.Praza@Sun.COM 			break;
27867887SLiane.Praza@Sun.COM 		case SC_VISIBILITY:
27877887SLiane.Praza@Sun.COM 			/*
27887887SLiane.Praza@Sun.COM 			 * The visibility element is empty, so we only need
27897887SLiane.Praza@Sun.COM 			 * to proccess the value attribute.
27907887SLiane.Praza@Sun.COM 			 */
27917887SLiane.Praza@Sun.COM 			(void) new_str_prop_from_attr(pg,
27927887SLiane.Praza@Sun.COM 			    SCF_PROPERTY_TM_VISIBILITY, SCF_TYPE_ASTRING,
27937887SLiane.Praza@Sun.COM 			    cursor, value_attr);
27947887SLiane.Praza@Sun.COM 			break;
27957887SLiane.Praza@Sun.COM 		default:
27967887SLiane.Praza@Sun.COM 			uu_die(gettext("illegal element \"%s\" in prop_pattern "
27977887SLiane.Praza@Sun.COM 			    "for service \"%s\"\n"), cursor->name,
27987887SLiane.Praza@Sun.COM 			    service->sc_name);
27997887SLiane.Praza@Sun.COM 		}
28007887SLiane.Praza@Sun.COM 	}
28017887SLiane.Praza@Sun.COM 
28027887SLiane.Praza@Sun.COM out:
28037887SLiane.Praza@Sun.COM 	xmlFree(prop_pattern_name);
28047887SLiane.Praza@Sun.COM 	free(pg_name);
28057887SLiane.Praza@Sun.COM 	return (r);
28067887SLiane.Praza@Sun.COM }
28077887SLiane.Praza@Sun.COM 
28087887SLiane.Praza@Sun.COM /*
28097887SLiane.Praza@Sun.COM  * Get the pg_pattern attributes and save them as properties in the
28107887SLiane.Praza@Sun.COM  * property group at pg.  The pg_pattern element accepts four attributes --
28117887SLiane.Praza@Sun.COM  * name, type, required and target.
28127887SLiane.Praza@Sun.COM  */
28137887SLiane.Praza@Sun.COM static int
lxml_get_pg_pattern_attributes(pgroup_t * pg,xmlNodePtr cursor)28147887SLiane.Praza@Sun.COM lxml_get_pg_pattern_attributes(pgroup_t *pg, xmlNodePtr cursor)
28157887SLiane.Praza@Sun.COM {
28167887SLiane.Praza@Sun.COM 	if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_TM_NAME,
28177887SLiane.Praza@Sun.COM 	    SCF_TYPE_ASTRING, cursor, name_attr, NULL) != 0) {
28187887SLiane.Praza@Sun.COM 		return (-1);
28197887SLiane.Praza@Sun.COM 	}
28207887SLiane.Praza@Sun.COM 	if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_TM_TYPE,
28217887SLiane.Praza@Sun.COM 	    SCF_TYPE_ASTRING, cursor, type_attr, NULL) != 0) {
28227887SLiane.Praza@Sun.COM 		return (-1);
28237887SLiane.Praza@Sun.COM 	}
28247887SLiane.Praza@Sun.COM 	if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_TM_TARGET,
28257887SLiane.Praza@Sun.COM 	    SCF_TYPE_ASTRING, cursor, target_attr, NULL) != 0) {
28267887SLiane.Praza@Sun.COM 		return (-1);
28277887SLiane.Praza@Sun.COM 	}
28287887SLiane.Praza@Sun.COM 	if (new_bool_prop_from_attr(pg, SCF_PROPERTY_TM_REQUIRED, cursor,
28297887SLiane.Praza@Sun.COM 	    required_attr) != 0)
28307887SLiane.Praza@Sun.COM 		return (-1);
28317887SLiane.Praza@Sun.COM 	return (0);
28327887SLiane.Praza@Sun.COM }
28337887SLiane.Praza@Sun.COM 
28347887SLiane.Praza@Sun.COM /*
28357887SLiane.Praza@Sun.COM  * There are several restrictions on the pg_pattern attributes that cannot
28367887SLiane.Praza@Sun.COM  * be specifed in the service bundle DTD.  This function verifies that
28377887SLiane.Praza@Sun.COM  * those restrictions have been satisfied.  The restrictions are:
28387887SLiane.Praza@Sun.COM  *
28397887SLiane.Praza@Sun.COM  *	- The target attribute may have a value of "instance" only when the
28407887SLiane.Praza@Sun.COM  *	  template block is in a service declaration.
28417887SLiane.Praza@Sun.COM  *
28427887SLiane.Praza@Sun.COM  *	- The target attribute may have a value of "delegate" only when the
28437887SLiane.Praza@Sun.COM  *	  template block applies to a restarter.
28447887SLiane.Praza@Sun.COM  *
28457887SLiane.Praza@Sun.COM  *	- The target attribute may have a value of "all" only when the
28467887SLiane.Praza@Sun.COM  *	  template block applies to the master restarter.
28477887SLiane.Praza@Sun.COM  *
28487887SLiane.Praza@Sun.COM  * The function returns 0 on success and -1 on failure.
28497887SLiane.Praza@Sun.COM  */
28507887SLiane.Praza@Sun.COM static int
verify_pg_pattern_attributes(entity_t * s,pgroup_t * pg)28517887SLiane.Praza@Sun.COM verify_pg_pattern_attributes(entity_t *s, pgroup_t *pg)
28527887SLiane.Praza@Sun.COM {
28537887SLiane.Praza@Sun.COM 	int is_restarter;
28547887SLiane.Praza@Sun.COM 	property_t *target;
28557887SLiane.Praza@Sun.COM 	value_t *v;
28567887SLiane.Praza@Sun.COM 
28577887SLiane.Praza@Sun.COM 	/* Find the value of the target property. */
28587887SLiane.Praza@Sun.COM 	target = internal_property_find(pg, SCF_PROPERTY_TM_TARGET);
28597887SLiane.Praza@Sun.COM 	if (target == NULL) {
28607887SLiane.Praza@Sun.COM 		uu_die(gettext("pg_pattern is missing the %s attribute "
28617887SLiane.Praza@Sun.COM 		    "in %s\n"), target_attr, s->sc_name);
28627887SLiane.Praza@Sun.COM 		return (-1);
28637887SLiane.Praza@Sun.COM 	}
28647887SLiane.Praza@Sun.COM 	v = uu_list_first(target->sc_property_values);
28657887SLiane.Praza@Sun.COM 	assert(v != NULL);
28667887SLiane.Praza@Sun.COM 	assert(v->sc_type == SCF_TYPE_ASTRING);
28677887SLiane.Praza@Sun.COM 
28687887SLiane.Praza@Sun.COM 	/*
28697887SLiane.Praza@Sun.COM 	 * If target has a value of instance, the template must be in a
28707887SLiane.Praza@Sun.COM 	 * service object.
28717887SLiane.Praza@Sun.COM 	 */
28727887SLiane.Praza@Sun.COM 	if (strcmp(v->sc_u.sc_string, "instance") == 0) {
28737887SLiane.Praza@Sun.COM 		if (s->sc_etype != SVCCFG_SERVICE_OBJECT) {
28747887SLiane.Praza@Sun.COM 			uu_warn(gettext("pg_pattern %s attribute may only "
28757887SLiane.Praza@Sun.COM 			    "have a value of \"instance\" when it is in a "
28767887SLiane.Praza@Sun.COM 			    "service declaration.\n"), target_attr);
28777887SLiane.Praza@Sun.COM 			return (-1);
28787887SLiane.Praza@Sun.COM 		}
28797887SLiane.Praza@Sun.COM 	}
28807887SLiane.Praza@Sun.COM 
28817887SLiane.Praza@Sun.COM 	/*
28827887SLiane.Praza@Sun.COM 	 * If target has a value of "delegate", the template must be in a
28837887SLiane.Praza@Sun.COM 	 * restarter.
28847887SLiane.Praza@Sun.COM 	 */
28857887SLiane.Praza@Sun.COM 	if (strcmp(v->sc_u.sc_string, "delegate") == 0) {
28867887SLiane.Praza@Sun.COM 		is_restarter = 0;
28877887SLiane.Praza@Sun.COM 		if ((s->sc_etype == SVCCFG_SERVICE_OBJECT) &&
28887887SLiane.Praza@Sun.COM 		    (s->sc_u.sc_service.sc_service_type == SVCCFG_RESTARTER)) {
28897887SLiane.Praza@Sun.COM 			is_restarter = 1;
28907887SLiane.Praza@Sun.COM 		}
28917887SLiane.Praza@Sun.COM 		if ((s->sc_etype == SVCCFG_INSTANCE_OBJECT) &&
28927887SLiane.Praza@Sun.COM 		    (s->sc_parent->sc_u.sc_service.sc_service_type ==
28937887SLiane.Praza@Sun.COM 		    SVCCFG_RESTARTER)) {
28947887SLiane.Praza@Sun.COM 			is_restarter = 1;
28957887SLiane.Praza@Sun.COM 		}
28967887SLiane.Praza@Sun.COM 		if (is_restarter == 0) {
28977887SLiane.Praza@Sun.COM 			uu_warn(gettext("pg_pattern %s attribute has a "
28987887SLiane.Praza@Sun.COM 			    "value of \"delegate\" but is not in a "
28997887SLiane.Praza@Sun.COM 			    "restarter service\n"), target_attr);
29007887SLiane.Praza@Sun.COM 			return (-1);
29017887SLiane.Praza@Sun.COM 		}
29027887SLiane.Praza@Sun.COM 	}
29037887SLiane.Praza@Sun.COM 
29047887SLiane.Praza@Sun.COM 	/*
29057887SLiane.Praza@Sun.COM 	 * If target has a value of "all", the template must be in the
29067887SLiane.Praza@Sun.COM 	 * global (SCF_SERVICE_GLOBAL) service.
29077887SLiane.Praza@Sun.COM 	 */
29087887SLiane.Praza@Sun.COM 	if (strcmp(v->sc_u.sc_string, all_value) == 0) {
29097887SLiane.Praza@Sun.COM 		if (s->sc_etype != SVCCFG_SERVICE_OBJECT) {
29107887SLiane.Praza@Sun.COM 			uu_warn(gettext("pg_pattern %s attribute has a "
29117887SLiane.Praza@Sun.COM 			    "value of \"%s\" but is not in a "
29127887SLiane.Praza@Sun.COM 			    "service entity.\n"), target_attr, all_value);
29137887SLiane.Praza@Sun.COM 			return (-1);
29147887SLiane.Praza@Sun.COM 		}
29157887SLiane.Praza@Sun.COM 		if (strcmp(s->sc_fmri, SCF_SERVICE_GLOBAL) != 0) {
29167887SLiane.Praza@Sun.COM 			uu_warn(gettext("pg_pattern %s attribute has a "
29177887SLiane.Praza@Sun.COM 			    "value of \"%s\" but is in the \"%s\" service.  "
29187887SLiane.Praza@Sun.COM 			    "pg_patterns with target \"%s\" are only allowed "
29197887SLiane.Praza@Sun.COM 			    "in the global service.\n"),
29207887SLiane.Praza@Sun.COM 			    target_attr, all_value, s->sc_fmri, all_value);
29217887SLiane.Praza@Sun.COM 			return (-1);
29227887SLiane.Praza@Sun.COM 		}
29237887SLiane.Praza@Sun.COM 	}
29247887SLiane.Praza@Sun.COM 
29257887SLiane.Praza@Sun.COM 	return (0);
29267887SLiane.Praza@Sun.COM }
29277887SLiane.Praza@Sun.COM 
29287887SLiane.Praza@Sun.COM static int
lxml_get_tm_pg_pattern(entity_t * service,xmlNodePtr pg_pattern)29297887SLiane.Praza@Sun.COM lxml_get_tm_pg_pattern(entity_t *service, xmlNodePtr pg_pattern)
29307887SLiane.Praza@Sun.COM {
29317887SLiane.Praza@Sun.COM 	xmlNodePtr cursor;
29327887SLiane.Praza@Sun.COM 	int out_len;
29337887SLiane.Praza@Sun.COM 	xmlChar *name;
29347887SLiane.Praza@Sun.COM 	pgroup_t *pg = NULL;
29357887SLiane.Praza@Sun.COM 	char *pg_name;
29367887SLiane.Praza@Sun.COM 	int r = -1;
29377887SLiane.Praza@Sun.COM 	xmlChar *type;
29387887SLiane.Praza@Sun.COM 
29397887SLiane.Praza@Sun.COM 	pg_name = safe_malloc(max_scf_name_len + 1);
29407887SLiane.Praza@Sun.COM 
29417887SLiane.Praza@Sun.COM 	/*
29427887SLiane.Praza@Sun.COM 	 * Get the name and type attributes.  Their presence or absence
29437887SLiane.Praza@Sun.COM 	 * determines whcih prefix we will use for the property group name.
29447887SLiane.Praza@Sun.COM 	 * There are four cases -- neither attribute is present, both are
29457887SLiane.Praza@Sun.COM 	 * present, only name is present or only type is present.
29467887SLiane.Praza@Sun.COM 	 */
29477887SLiane.Praza@Sun.COM 	name = xmlGetProp(pg_pattern, (xmlChar *)name_attr);
29487887SLiane.Praza@Sun.COM 	type = xmlGetProp(pg_pattern, (xmlChar *)type_attr);
29497887SLiane.Praza@Sun.COM 	if ((name == NULL) || (*name == 0)) {
29507887SLiane.Praza@Sun.COM 		if ((type == NULL) || (*type == 0)) {
29517887SLiane.Praza@Sun.COM 			/* PG name contains only the prefix in this case */
29527887SLiane.Praza@Sun.COM 			if (strlcpy(pg_name, SCF_PG_TM_PG_PATTERN_PREFIX,
29537887SLiane.Praza@Sun.COM 			    max_scf_name_len + 1) >= max_scf_name_len + 1) {
29547887SLiane.Praza@Sun.COM 				uu_die(gettext("Unable to create pg_pattern "
29557887SLiane.Praza@Sun.COM 				    "property for %s\n"), service->sc_name);
29567887SLiane.Praza@Sun.COM 			}
29577887SLiane.Praza@Sun.COM 		} else {
29587887SLiane.Praza@Sun.COM 			/*
29597887SLiane.Praza@Sun.COM 			 * If we have a type and no name, the type becomes
29607887SLiane.Praza@Sun.COM 			 * part of the pg_pattern property group name.
29617887SLiane.Praza@Sun.COM 			 */
29627887SLiane.Praza@Sun.COM 			if ((out_len = snprintf(pg_name, max_scf_name_len + 1,
29637887SLiane.Praza@Sun.COM 			    "%s%s", SCF_PG_TM_PG_PATTERN_T_PREFIX, type)) >=
29647887SLiane.Praza@Sun.COM 			    max_scf_name_len + 1) {
29657887SLiane.Praza@Sun.COM 				uu_die(gettext("pg_pattern type is for %s is "
29667887SLiane.Praza@Sun.COM 				    "%d bytes too long\n"), service->sc_name,
29677887SLiane.Praza@Sun.COM 				    out_len - max_scf_name_len);
29687887SLiane.Praza@Sun.COM 			}
29697887SLiane.Praza@Sun.COM 		}
29707887SLiane.Praza@Sun.COM 	} else {
29717887SLiane.Praza@Sun.COM 		const char *prefix;
29727887SLiane.Praza@Sun.COM 
29737887SLiane.Praza@Sun.COM 		/* Make sure that the name is valid. */
29747887SLiane.Praza@Sun.COM 		if (uu_check_name((const char *)name, UU_NAME_DOMAIN) != 0) {
29757887SLiane.Praza@Sun.COM 			semerr(gettext("pg_pattern name attribute, \"%s\", "
29767887SLiane.Praza@Sun.COM 			    "for %s is invalid\n"), name, service->sc_name);
29777887SLiane.Praza@Sun.COM 			goto out;
29787887SLiane.Praza@Sun.COM 		}
29797887SLiane.Praza@Sun.COM 
29807887SLiane.Praza@Sun.COM 		/*
29817887SLiane.Praza@Sun.COM 		 * As long as the pg_pattern has a name, it becomes part of
29827887SLiane.Praza@Sun.COM 		 * the name of the pg_pattern property group name.  We
29837887SLiane.Praza@Sun.COM 		 * merely need to pick the appropriate prefix.
29847887SLiane.Praza@Sun.COM 		 */
29857887SLiane.Praza@Sun.COM 		if ((type == NULL) || (*type == 0)) {
29867887SLiane.Praza@Sun.COM 			prefix = SCF_PG_TM_PG_PATTERN_N_PREFIX;
29877887SLiane.Praza@Sun.COM 		} else {
29887887SLiane.Praza@Sun.COM 			prefix = SCF_PG_TM_PG_PATTERN_NT_PREFIX;
29897887SLiane.Praza@Sun.COM 		}
29907887SLiane.Praza@Sun.COM 		if ((out_len = snprintf(pg_name, max_scf_name_len + 1, "%s%s",
29917887SLiane.Praza@Sun.COM 		    prefix, name)) >= max_scf_name_len + 1) {
29927887SLiane.Praza@Sun.COM 			uu_die(gettext("pg_pattern property group name "
29937887SLiane.Praza@Sun.COM 			    "for %s is %d bytes too long\n"), service->sc_name,
29947887SLiane.Praza@Sun.COM 			    out_len - max_scf_name_len);
29957887SLiane.Praza@Sun.COM 		}
29967887SLiane.Praza@Sun.COM 	}
29977887SLiane.Praza@Sun.COM 
29987887SLiane.Praza@Sun.COM 	/*
29997887SLiane.Praza@Sun.COM 	 * Create the property group for holding this pg_pattern
30007887SLiane.Praza@Sun.COM 	 * information, and capture the pg_pattern attributes.
30017887SLiane.Praza@Sun.COM 	 */
30027887SLiane.Praza@Sun.COM 	pg = internal_pgroup_create_strict(service, pg_name,
30037887SLiane.Praza@Sun.COM 	    SCF_GROUP_TEMPLATE_PG_PATTERN);
30047887SLiane.Praza@Sun.COM 	if (pg == NULL) {
30057887SLiane.Praza@Sun.COM 		if ((name == NULL) || (*name == 0)) {
30067887SLiane.Praza@Sun.COM 			if ((type == NULL) ||(*type == 0)) {
30077887SLiane.Praza@Sun.COM 				semerr(gettext("pg_pattern with empty name and "
30087887SLiane.Praza@Sun.COM 				    "type is not unique in %s\n"),
30097887SLiane.Praza@Sun.COM 				    service->sc_name);
30107887SLiane.Praza@Sun.COM 			} else {
30117887SLiane.Praza@Sun.COM 				semerr(gettext("pg_pattern with empty name and "
30127887SLiane.Praza@Sun.COM 				    "type \"%s\" is not unique in %s\n"),
30137887SLiane.Praza@Sun.COM 				    type, service->sc_name);
30147887SLiane.Praza@Sun.COM 			}
30157887SLiane.Praza@Sun.COM 		} else {
30167887SLiane.Praza@Sun.COM 			if ((type == NULL) || (*type == 0)) {
30177887SLiane.Praza@Sun.COM 				semerr(gettext("pg_pattern with name \"%s\" "
30187887SLiane.Praza@Sun.COM 				    "and empty type is not unique in %s\n"),
30197887SLiane.Praza@Sun.COM 				    name, service->sc_name);
30207887SLiane.Praza@Sun.COM 			} else {
30217887SLiane.Praza@Sun.COM 				semerr(gettext("pg_pattern with name \"%s\" "
30227887SLiane.Praza@Sun.COM 				    "and type \"%s\" is not unique in %s\n"),
30237887SLiane.Praza@Sun.COM 				    name, type, service->sc_name);
30247887SLiane.Praza@Sun.COM 			}
30257887SLiane.Praza@Sun.COM 		}
30267887SLiane.Praza@Sun.COM 		goto out;
30277887SLiane.Praza@Sun.COM 	}
30287887SLiane.Praza@Sun.COM 
30297887SLiane.Praza@Sun.COM 	/*
30307887SLiane.Praza@Sun.COM 	 * Get the pg_pattern attributes from the manifest and verify
30317887SLiane.Praza@Sun.COM 	 * that they satisfy our restrictions.
30327887SLiane.Praza@Sun.COM 	 */
30337887SLiane.Praza@Sun.COM 	r = lxml_get_pg_pattern_attributes(pg, pg_pattern);
30347887SLiane.Praza@Sun.COM 	if (r != 0)
30357887SLiane.Praza@Sun.COM 		goto out;
30367887SLiane.Praza@Sun.COM 	if (verify_pg_pattern_attributes(service, pg) != 0) {
30377887SLiane.Praza@Sun.COM 		semerr(gettext("Invalid pg_pattern attributes in %s\n"),
30387887SLiane.Praza@Sun.COM 		    service->sc_name);
30397887SLiane.Praza@Sun.COM 		r = -1;
30407887SLiane.Praza@Sun.COM 		goto out;
30417887SLiane.Praza@Sun.COM 	}
30427887SLiane.Praza@Sun.COM 
30437887SLiane.Praza@Sun.COM 	/*
30447887SLiane.Praza@Sun.COM 	 * Now process all of the elements of pg_pattern.
30457887SLiane.Praza@Sun.COM 	 */
30467887SLiane.Praza@Sun.COM 	for (cursor = pg_pattern->xmlChildrenNode;
30477887SLiane.Praza@Sun.COM 	    cursor != NULL;
30487887SLiane.Praza@Sun.COM 	    cursor = cursor->next) {
30497887SLiane.Praza@Sun.COM 		if (lxml_ignorable_block(cursor))
30507887SLiane.Praza@Sun.COM 			continue;
30517887SLiane.Praza@Sun.COM 
30527887SLiane.Praza@Sun.COM 		switch (lxml_xlate_element(cursor->name)) {
30537887SLiane.Praza@Sun.COM 		case SC_COMMON_NAME:
30547887SLiane.Praza@Sun.COM 			(void) lxml_get_all_loctext(service, pg, cursor,
30557887SLiane.Praza@Sun.COM 			    COMMON_NAME_FMT, (const char *)cursor->name);
30567887SLiane.Praza@Sun.COM 			break;
30577887SLiane.Praza@Sun.COM 		case SC_DESCRIPTION:
30587887SLiane.Praza@Sun.COM 			(void) lxml_get_all_loctext(service, pg, cursor,
30597887SLiane.Praza@Sun.COM 			    DESCRIPTION_FMT, (const char *)cursor->name);
30607887SLiane.Praza@Sun.COM 			break;
30617887SLiane.Praza@Sun.COM 		case SC_PROP_PATTERN:
30627887SLiane.Praza@Sun.COM 			r = lxml_get_tm_prop_pattern(service, cursor,
30637887SLiane.Praza@Sun.COM 			    pg_name);
30647887SLiane.Praza@Sun.COM 			if (r != 0)
30657887SLiane.Praza@Sun.COM 				goto out;
30667887SLiane.Praza@Sun.COM 			break;
30677887SLiane.Praza@Sun.COM 		default:
30687887SLiane.Praza@Sun.COM 			uu_die(gettext("illegal element \"%s\" in pg_pattern "
30697887SLiane.Praza@Sun.COM 			    "for service \"%s\"\n"), cursor->name,
30707887SLiane.Praza@Sun.COM 			    service->sc_name);
30717887SLiane.Praza@Sun.COM 		}
30727887SLiane.Praza@Sun.COM 	}
30737887SLiane.Praza@Sun.COM 
30747887SLiane.Praza@Sun.COM out:
30757887SLiane.Praza@Sun.COM 	if ((r != 0) && (pg != NULL)) {
30767887SLiane.Praza@Sun.COM 		internal_detach_pgroup(service, pg);
30777887SLiane.Praza@Sun.COM 		internal_pgroup_free(pg);
30787887SLiane.Praza@Sun.COM 	}
30797887SLiane.Praza@Sun.COM 	free(pg_name);
30807887SLiane.Praza@Sun.COM 	xmlFree(name);
30817887SLiane.Praza@Sun.COM 	xmlFree(type);
30827887SLiane.Praza@Sun.COM 
30837887SLiane.Praza@Sun.COM 	return (r);
30847887SLiane.Praza@Sun.COM }
30857887SLiane.Praza@Sun.COM 
30867887SLiane.Praza@Sun.COM static int
lxml_get_template(entity_t * service,xmlNodePtr templ)30870Sstevel@tonic-gate lxml_get_template(entity_t *service, xmlNodePtr templ)
30880Sstevel@tonic-gate {
30890Sstevel@tonic-gate 	xmlNodePtr cursor;
30900Sstevel@tonic-gate 
30910Sstevel@tonic-gate 	for (cursor = templ->xmlChildrenNode; cursor != NULL;
30920Sstevel@tonic-gate 	    cursor = cursor->next) {
30930Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
30940Sstevel@tonic-gate 			continue;
30950Sstevel@tonic-gate 
30960Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
30970Sstevel@tonic-gate 		case SC_COMMON_NAME:
30980Sstevel@tonic-gate 			(void) lxml_get_tm_common_name(service, cursor);
30990Sstevel@tonic-gate 			break;
31000Sstevel@tonic-gate 		case SC_DESCRIPTION:
31010Sstevel@tonic-gate 			(void) lxml_get_tm_description(service, cursor);
31020Sstevel@tonic-gate 			break;
31030Sstevel@tonic-gate 		case SC_DOCUMENTATION:
31040Sstevel@tonic-gate 			(void) lxml_get_tm_documentation(service, cursor);
31050Sstevel@tonic-gate 			break;
31067887SLiane.Praza@Sun.COM 		case SC_PG_PATTERN:
31077887SLiane.Praza@Sun.COM 			if (lxml_get_tm_pg_pattern(service, cursor) != 0)
31087887SLiane.Praza@Sun.COM 				return (-1);
31097887SLiane.Praza@Sun.COM 			break;
31100Sstevel@tonic-gate 		default:
31110Sstevel@tonic-gate 			uu_die(gettext("illegal element \"%s\" on template "
31120Sstevel@tonic-gate 			    "for service \"%s\"\n"),
31130Sstevel@tonic-gate 			    cursor->name, service->sc_name);
31140Sstevel@tonic-gate 		}
31150Sstevel@tonic-gate 	}
31160Sstevel@tonic-gate 
31170Sstevel@tonic-gate 	return (0);
31180Sstevel@tonic-gate }
31190Sstevel@tonic-gate 
31200Sstevel@tonic-gate static int
lxml_get_default_instance(entity_t * service,xmlNodePtr definst)31210Sstevel@tonic-gate lxml_get_default_instance(entity_t *service, xmlNodePtr definst)
31220Sstevel@tonic-gate {
31230Sstevel@tonic-gate 	entity_t *i;
31240Sstevel@tonic-gate 	xmlChar *enabled;
31250Sstevel@tonic-gate 	pgroup_t *pg;
31260Sstevel@tonic-gate 	property_t *p;
31270Sstevel@tonic-gate 	char *package;
31280Sstevel@tonic-gate 	uint64_t enabled_val = 0;
31290Sstevel@tonic-gate 
31300Sstevel@tonic-gate 	i = internal_instance_new("default");
31310Sstevel@tonic-gate 
31320Sstevel@tonic-gate 	if ((enabled = xmlGetProp(definst, (xmlChar *)enabled_attr)) != NULL) {
31330Sstevel@tonic-gate 		enabled_val = (strcmp(true, (const char *)enabled) == 0) ?
31340Sstevel@tonic-gate 		    1 : 0;
31350Sstevel@tonic-gate 		xmlFree(enabled);
31360Sstevel@tonic-gate 	}
31370Sstevel@tonic-gate 
31380Sstevel@tonic-gate 	/*
31390Sstevel@tonic-gate 	 * New general property group with enabled boolean property set.
31400Sstevel@tonic-gate 	 */
31410Sstevel@tonic-gate 
314212667SSean.Wilcox@Sun.COM 	i->sc_op = service->sc_op;
31430Sstevel@tonic-gate 	pg = internal_pgroup_new();
31440Sstevel@tonic-gate 	(void) internal_attach_pgroup(i, pg);
31450Sstevel@tonic-gate 
31460Sstevel@tonic-gate 	pg->sc_pgroup_name = (char *)scf_pg_general;
31470Sstevel@tonic-gate 	pg->sc_pgroup_type = (char *)scf_group_framework;
31480Sstevel@tonic-gate 	pg->sc_pgroup_flags = 0;
31490Sstevel@tonic-gate 
31500Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_ENABLED, SCF_TYPE_BOOLEAN, 1,
31510Sstevel@tonic-gate 	    enabled_val);
31520Sstevel@tonic-gate 
31530Sstevel@tonic-gate 	(void) internal_attach_property(pg, p);
31540Sstevel@tonic-gate 
31550Sstevel@tonic-gate 	/*
31560Sstevel@tonic-gate 	 * Add general/package property if PKGINST is set.
31570Sstevel@tonic-gate 	 */
31580Sstevel@tonic-gate 	if ((package = getenv("PKGINST")) != NULL) {
31590Sstevel@tonic-gate 		p = internal_property_create(SCF_PROPERTY_PACKAGE,
31600Sstevel@tonic-gate 		    SCF_TYPE_ASTRING, 1, package);
31610Sstevel@tonic-gate 
31620Sstevel@tonic-gate 		(void) internal_attach_property(pg, p);
31630Sstevel@tonic-gate 	}
31640Sstevel@tonic-gate 
31650Sstevel@tonic-gate 	return (internal_attach_entity(service, i));
31660Sstevel@tonic-gate }
31670Sstevel@tonic-gate 
31680Sstevel@tonic-gate /*
31690Sstevel@tonic-gate  * Translate an instance element into an internal property tree, added to
317010029SAntonello.Cruz@Sun.COM  * service.  If op is SVCCFG_OP_APPLY (i.e., apply a profile), set the
317110029SAntonello.Cruz@Sun.COM  * enabled property to override.
317212667SSean.Wilcox@Sun.COM  *
317312667SSean.Wilcox@Sun.COM  * If op is SVCCFG_OP_APPLY (i.e., apply a profile), do not allow for
317412667SSean.Wilcox@Sun.COM  * modification of template data.
31750Sstevel@tonic-gate  */
31760Sstevel@tonic-gate static int
lxml_get_instance(entity_t * service,xmlNodePtr inst,bundle_type_t bt,svccfg_op_t op)317710029SAntonello.Cruz@Sun.COM lxml_get_instance(entity_t *service, xmlNodePtr inst, bundle_type_t bt,
317810029SAntonello.Cruz@Sun.COM     svccfg_op_t op)
31790Sstevel@tonic-gate {
31800Sstevel@tonic-gate 	entity_t *i;
31810Sstevel@tonic-gate 	pgroup_t *pg;
31820Sstevel@tonic-gate 	property_t *p;
31830Sstevel@tonic-gate 	xmlNodePtr cursor;
31840Sstevel@tonic-gate 	xmlChar *enabled;
318510029SAntonello.Cruz@Sun.COM 	int r, e_val;
31860Sstevel@tonic-gate 
31870Sstevel@tonic-gate 	/*
31880Sstevel@tonic-gate 	 * Fetch its attributes, as appropriate.
31890Sstevel@tonic-gate 	 */
31900Sstevel@tonic-gate 	i = internal_instance_new((char *)xmlGetProp(inst,
31910Sstevel@tonic-gate 	    (xmlChar *)name_attr));
31920Sstevel@tonic-gate 
31930Sstevel@tonic-gate 	/*
31940Sstevel@tonic-gate 	 * Note that this must be done before walking the children so that
31950Sstevel@tonic-gate 	 * sc_fmri is set in case we enter lxml_get_dependent().
31960Sstevel@tonic-gate 	 */
31970Sstevel@tonic-gate 	r = internal_attach_entity(service, i);
31980Sstevel@tonic-gate 	if (r != 0)
31990Sstevel@tonic-gate 		return (r);
32000Sstevel@tonic-gate 
320112667SSean.Wilcox@Sun.COM 	i->sc_op = op;
32020Sstevel@tonic-gate 	enabled = xmlGetProp(inst, (xmlChar *)enabled_attr);
32030Sstevel@tonic-gate 
320410029SAntonello.Cruz@Sun.COM 	if (enabled == NULL) {
320510029SAntonello.Cruz@Sun.COM 		if (bt == SVCCFG_MANIFEST) {
320610029SAntonello.Cruz@Sun.COM 			semerr(gettext("Instance \"%s\" missing attribute "
320710029SAntonello.Cruz@Sun.COM 			    "\"%s\".\n"), i->sc_name, enabled_attr);
320810029SAntonello.Cruz@Sun.COM 			return (-1);
320910029SAntonello.Cruz@Sun.COM 		}
321010029SAntonello.Cruz@Sun.COM 	} else {	/* enabled != NULL */
321110029SAntonello.Cruz@Sun.COM 		if (strcmp(true, (const char *)enabled) != 0 &&
321210029SAntonello.Cruz@Sun.COM 		    strcmp(false, (const char *)enabled) != 0) {
321310029SAntonello.Cruz@Sun.COM 			xmlFree(enabled);
321410029SAntonello.Cruz@Sun.COM 			semerr(gettext("Invalid enabled value\n"));
321510029SAntonello.Cruz@Sun.COM 			return (-1);
321610029SAntonello.Cruz@Sun.COM 		}
321710029SAntonello.Cruz@Sun.COM 		pg = internal_pgroup_new();
321810029SAntonello.Cruz@Sun.COM 		(void) internal_attach_pgroup(i, pg);
321910029SAntonello.Cruz@Sun.COM 
322010029SAntonello.Cruz@Sun.COM 		pg->sc_pgroup_name = (char *)scf_pg_general;
322110029SAntonello.Cruz@Sun.COM 		pg->sc_pgroup_type = (char *)scf_group_framework;
322210029SAntonello.Cruz@Sun.COM 		pg->sc_pgroup_flags = 0;
322310029SAntonello.Cruz@Sun.COM 
322410029SAntonello.Cruz@Sun.COM 		e_val = (strcmp(true, (const char *)enabled) == 0);
322510029SAntonello.Cruz@Sun.COM 		p = internal_property_create(SCF_PROPERTY_ENABLED,
322610029SAntonello.Cruz@Sun.COM 		    SCF_TYPE_BOOLEAN, 1, (uint64_t)e_val);
322710029SAntonello.Cruz@Sun.COM 
322810029SAntonello.Cruz@Sun.COM 		p->sc_property_override = (op == SVCCFG_OP_APPLY);
322910029SAntonello.Cruz@Sun.COM 
323010029SAntonello.Cruz@Sun.COM 		(void) internal_attach_property(pg, p);
323110029SAntonello.Cruz@Sun.COM 
323210029SAntonello.Cruz@Sun.COM 		xmlFree(enabled);
323310029SAntonello.Cruz@Sun.COM 	}
32340Sstevel@tonic-gate 
32350Sstevel@tonic-gate 	/*
32360Sstevel@tonic-gate 	 * Walk its child elements, as appropriate.
32370Sstevel@tonic-gate 	 */
32380Sstevel@tonic-gate 	for (cursor = inst->xmlChildrenNode; cursor != NULL;
32390Sstevel@tonic-gate 	    cursor = cursor->next) {
32400Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
32410Sstevel@tonic-gate 			continue;
32420Sstevel@tonic-gate 
32430Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
32440Sstevel@tonic-gate 		case SC_RESTARTER:
32450Sstevel@tonic-gate 			(void) lxml_get_restarter(i, cursor);
32460Sstevel@tonic-gate 			break;
32470Sstevel@tonic-gate 		case SC_DEPENDENCY:
32480Sstevel@tonic-gate 			(void) lxml_get_dependency(i, cursor);
32490Sstevel@tonic-gate 			break;
32500Sstevel@tonic-gate 		case SC_DEPENDENT:
32510Sstevel@tonic-gate 			(void) lxml_get_dependent(i, cursor);
32520Sstevel@tonic-gate 			break;
32530Sstevel@tonic-gate 		case SC_METHOD_CONTEXT:
32540Sstevel@tonic-gate 			(void) lxml_get_entity_method_context(i, cursor);
32550Sstevel@tonic-gate 			break;
32560Sstevel@tonic-gate 		case SC_EXEC_METHOD:
32570Sstevel@tonic-gate 			(void) lxml_get_exec_method(i, cursor);
32580Sstevel@tonic-gate 			break;
32590Sstevel@tonic-gate 		case SC_PROPERTY_GROUP:
32600Sstevel@tonic-gate 			(void) lxml_get_pgroup(i, cursor);
32610Sstevel@tonic-gate 			break;
32620Sstevel@tonic-gate 		case SC_TEMPLATE:
326312667SSean.Wilcox@Sun.COM 			if (op == SVCCFG_OP_APPLY) {
326412667SSean.Wilcox@Sun.COM 				semerr(gettext("Template data for \"%s\" may "
326512667SSean.Wilcox@Sun.COM 				    "not be modified in a profile.\n"),
326612667SSean.Wilcox@Sun.COM 				    i->sc_name);
326712667SSean.Wilcox@Sun.COM 
326812667SSean.Wilcox@Sun.COM 				return (-1);
326912667SSean.Wilcox@Sun.COM 			}
327012667SSean.Wilcox@Sun.COM 
32717887SLiane.Praza@Sun.COM 			if (lxml_get_template(i, cursor) != 0)
32727887SLiane.Praza@Sun.COM 				return (-1);
32730Sstevel@tonic-gate 			break;
3274*12967Sgavin.maltby@oracle.com 		case SC_NOTIFICATION_PARAMETERS:
3275*12967Sgavin.maltby@oracle.com 			if (lxml_get_notification_parameters(i, cursor) != 0)
3276*12967Sgavin.maltby@oracle.com 				return (-1);
3277*12967Sgavin.maltby@oracle.com 			break;
32780Sstevel@tonic-gate 		default:
32790Sstevel@tonic-gate 			uu_die(gettext(
32800Sstevel@tonic-gate 			    "illegal element \"%s\" on instance \"%s\"\n"),
32810Sstevel@tonic-gate 			    cursor->name, i->sc_name);
32820Sstevel@tonic-gate 			break;
32830Sstevel@tonic-gate 		}
32840Sstevel@tonic-gate 	}
32850Sstevel@tonic-gate 
32860Sstevel@tonic-gate 	return (0);
32870Sstevel@tonic-gate }
32880Sstevel@tonic-gate 
32890Sstevel@tonic-gate /* ARGSUSED1 */
32900Sstevel@tonic-gate static int
lxml_get_single_instance(entity_t * entity,xmlNodePtr si)32910Sstevel@tonic-gate lxml_get_single_instance(entity_t *entity, xmlNodePtr si)
32920Sstevel@tonic-gate {
32930Sstevel@tonic-gate 	pgroup_t *pg;
32940Sstevel@tonic-gate 	property_t *p;
32950Sstevel@tonic-gate 	int r;
32960Sstevel@tonic-gate 
32970Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(entity, (char *)scf_pg_general,
32980Sstevel@tonic-gate 	    (char *)scf_group_framework);
32990Sstevel@tonic-gate 
33000Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_SINGLE_INSTANCE,
33010Sstevel@tonic-gate 	    SCF_TYPE_BOOLEAN, 1, (uint64_t)1);
33020Sstevel@tonic-gate 
33030Sstevel@tonic-gate 	r = internal_attach_property(pg, p);
33040Sstevel@tonic-gate 	if (r != 0) {
33050Sstevel@tonic-gate 		internal_property_free(p);
33060Sstevel@tonic-gate 		return (-1);
33070Sstevel@tonic-gate 	}
33080Sstevel@tonic-gate 
33090Sstevel@tonic-gate 	return (0);
33100Sstevel@tonic-gate }
33110Sstevel@tonic-gate 
33120Sstevel@tonic-gate /*
331311996SThomas.Whitten@Sun.COM  * Check to see if the service should allow the upgrade
331411996SThomas.Whitten@Sun.COM  * process to handle adding of the manifestfiles linkage.
331511996SThomas.Whitten@Sun.COM  *
331611996SThomas.Whitten@Sun.COM  * If the service exists and does not have a manifestfiles
331711996SThomas.Whitten@Sun.COM  * property group then the upgrade process should handle
331811996SThomas.Whitten@Sun.COM  * the service.
331911996SThomas.Whitten@Sun.COM  *
332011996SThomas.Whitten@Sun.COM  * If the service doesn't exist or the service exists
332111996SThomas.Whitten@Sun.COM  * and has a manifestfiles property group then the import
332211996SThomas.Whitten@Sun.COM  * process can handle the manifestfiles property group
332311996SThomas.Whitten@Sun.COM  * work.
332411996SThomas.Whitten@Sun.COM  *
332511996SThomas.Whitten@Sun.COM  * This prevents potential cleanup of unaccounted for instances
332611996SThomas.Whitten@Sun.COM  * in early manifest import due to upgrade process needing
332711996SThomas.Whitten@Sun.COM  * information that has not yet been supplied by manifests
332811996SThomas.Whitten@Sun.COM  * that are still located in the /var/svc manifests directory.
332911996SThomas.Whitten@Sun.COM  */
333011996SThomas.Whitten@Sun.COM static int
lxml_check_upgrade(const char * service)333111996SThomas.Whitten@Sun.COM lxml_check_upgrade(const char *service) {
333211996SThomas.Whitten@Sun.COM 	scf_handle_t	*h = NULL;
333311996SThomas.Whitten@Sun.COM 	scf_scope_t	*sc = NULL;
333411996SThomas.Whitten@Sun.COM 	scf_service_t	*svc = NULL;
333511996SThomas.Whitten@Sun.COM 	scf_propertygroup_t	*pg = NULL;
333611996SThomas.Whitten@Sun.COM 	int rc = SCF_FAILED;
333711996SThomas.Whitten@Sun.COM 
333811996SThomas.Whitten@Sun.COM 	if ((h = scf_handle_create(SCF_VERSION)) == NULL ||
333911996SThomas.Whitten@Sun.COM 	    (sc = scf_scope_create(h)) == NULL ||
334011996SThomas.Whitten@Sun.COM 	    (svc = scf_service_create(h)) == NULL ||
334111996SThomas.Whitten@Sun.COM 	    (pg = scf_pg_create(h)) == NULL)
334211996SThomas.Whitten@Sun.COM 		goto out;
334311996SThomas.Whitten@Sun.COM 
334411996SThomas.Whitten@Sun.COM 	if (scf_handle_bind(h) != 0)
334511996SThomas.Whitten@Sun.COM 		goto out;
334611996SThomas.Whitten@Sun.COM 
334711996SThomas.Whitten@Sun.COM 	if (scf_handle_get_scope(h, SCF_FMRI_LOCAL_SCOPE, sc) == -1)
334811996SThomas.Whitten@Sun.COM 		goto out;
334911996SThomas.Whitten@Sun.COM 
335011996SThomas.Whitten@Sun.COM 	if (scf_scope_get_service(sc, service, svc) != SCF_SUCCESS) {
335111996SThomas.Whitten@Sun.COM 		if (scf_error() == SCF_ERROR_NOT_FOUND)
335211996SThomas.Whitten@Sun.COM 			rc = SCF_SUCCESS;
335311996SThomas.Whitten@Sun.COM 
335411996SThomas.Whitten@Sun.COM 		goto out;
335511996SThomas.Whitten@Sun.COM 	}
335611996SThomas.Whitten@Sun.COM 
335711996SThomas.Whitten@Sun.COM 	if (scf_service_get_pg(svc, SCF_PG_MANIFESTFILES, pg) != SCF_SUCCESS)
335811996SThomas.Whitten@Sun.COM 		goto out;
335911996SThomas.Whitten@Sun.COM 
336011996SThomas.Whitten@Sun.COM 	rc = SCF_SUCCESS;
336111996SThomas.Whitten@Sun.COM out:
336211996SThomas.Whitten@Sun.COM 	scf_pg_destroy(pg);
336311996SThomas.Whitten@Sun.COM 	scf_service_destroy(svc);
336411996SThomas.Whitten@Sun.COM 	scf_scope_destroy(sc);
336511996SThomas.Whitten@Sun.COM 	scf_handle_destroy(h);
336611996SThomas.Whitten@Sun.COM 
336711996SThomas.Whitten@Sun.COM 	return (rc);
336811996SThomas.Whitten@Sun.COM }
336911996SThomas.Whitten@Sun.COM 
337011996SThomas.Whitten@Sun.COM /*
33710Sstevel@tonic-gate  * Translate a service element into an internal instance/property tree, added
337212667SSean.Wilcox@Sun.COM  * to bundle.
337312667SSean.Wilcox@Sun.COM  *
337412667SSean.Wilcox@Sun.COM  * If op is SVCCFG_OP_APPLY (i.e., apply a profile), do not allow for
337512667SSean.Wilcox@Sun.COM  * modification of template data.
33760Sstevel@tonic-gate  */
33770Sstevel@tonic-gate static int
lxml_get_service(bundle_t * bundle,xmlNodePtr svc,svccfg_op_t op)33785040Swesolows lxml_get_service(bundle_t *bundle, xmlNodePtr svc, svccfg_op_t op)
33790Sstevel@tonic-gate {
338010461SSean.Wilcox@Sun.COM 	pgroup_t *pg;
338110461SSean.Wilcox@Sun.COM 	property_t *p;
33820Sstevel@tonic-gate 	entity_t *s;
33830Sstevel@tonic-gate 	xmlNodePtr cursor;
33840Sstevel@tonic-gate 	xmlChar *type;
33850Sstevel@tonic-gate 	xmlChar *version;
33860Sstevel@tonic-gate 	int e;
33870Sstevel@tonic-gate 
33880Sstevel@tonic-gate 	/*
33890Sstevel@tonic-gate 	 * Fetch attributes, as appropriate.
33900Sstevel@tonic-gate 	 */
33910Sstevel@tonic-gate 	s = internal_service_new((char *)xmlGetProp(svc,
33920Sstevel@tonic-gate 	    (xmlChar *)name_attr));
33930Sstevel@tonic-gate 
33947887SLiane.Praza@Sun.COM 	version = xmlGetProp(svc, (xmlChar *)version_attr);
33950Sstevel@tonic-gate 	s->sc_u.sc_service.sc_service_version = atol((const char *)version);
33960Sstevel@tonic-gate 	xmlFree(version);
33970Sstevel@tonic-gate 
33980Sstevel@tonic-gate 	type = xmlGetProp(svc, (xmlChar *)type_attr);
33990Sstevel@tonic-gate 	s->sc_u.sc_service.sc_service_type = lxml_xlate_service_type(type);
34000Sstevel@tonic-gate 	xmlFree(type);
34010Sstevel@tonic-gate 
34020Sstevel@tonic-gate 	/*
340312667SSean.Wilcox@Sun.COM 	 * Set the global missing type to false before processing the service
340412667SSean.Wilcox@Sun.COM 	 */
340512667SSean.Wilcox@Sun.COM 	est->sc_miss_type = B_FALSE;
340612667SSean.Wilcox@Sun.COM 	s->sc_op = op;
340712667SSean.Wilcox@Sun.COM 
340812667SSean.Wilcox@Sun.COM 	/*
340910461SSean.Wilcox@Sun.COM 	 * Now that the service is created create the manifest
341010461SSean.Wilcox@Sun.COM 	 * property group and add the property value of the service.
341110461SSean.Wilcox@Sun.COM 	 */
341211996SThomas.Whitten@Sun.COM 	if (lxml_check_upgrade(s->sc_name) == SCF_SUCCESS &&
341311996SThomas.Whitten@Sun.COM 	    svc->doc->name != NULL &&
341410461SSean.Wilcox@Sun.COM 	    bundle->sc_bundle_type == SVCCFG_MANIFEST) {
341512172SSean.Wilcox@Sun.COM 		char *buf, *base, *fname, *bname;
341612172SSean.Wilcox@Sun.COM 		size_t	base_sz = 0;
341712172SSean.Wilcox@Sun.COM 
341812172SSean.Wilcox@Sun.COM 		/*
341912172SSean.Wilcox@Sun.COM 		 * Must remove the PKG_INSTALL_ROOT, point to the correct
342012172SSean.Wilcox@Sun.COM 		 * directory after install
342112172SSean.Wilcox@Sun.COM 		 */
342212172SSean.Wilcox@Sun.COM 		bname = uu_zalloc(PATH_MAX + 1);
342312172SSean.Wilcox@Sun.COM 		if (realpath(svc->doc->name, bname) == NULL) {
342412172SSean.Wilcox@Sun.COM 			uu_die(gettext("Unable to create the real path of the "
342512172SSean.Wilcox@Sun.COM 			    "manifest file \"%s\" : %d\n"), svc->doc->name,
342612172SSean.Wilcox@Sun.COM 			    errno);
342712172SSean.Wilcox@Sun.COM 		}
342812172SSean.Wilcox@Sun.COM 
342912172SSean.Wilcox@Sun.COM 		base = getenv("PKG_INSTALL_ROOT");
343012172SSean.Wilcox@Sun.COM 		if (base != NULL && strncmp(bname, base, strlen(base)) == 0) {
343112172SSean.Wilcox@Sun.COM 			base_sz = strlen(base);
343212172SSean.Wilcox@Sun.COM 		}
343312172SSean.Wilcox@Sun.COM 		fname = safe_strdup(bname + base_sz);
343412172SSean.Wilcox@Sun.COM 
343512172SSean.Wilcox@Sun.COM 		uu_free(bname);
343612172SSean.Wilcox@Sun.COM 		buf = mhash_filename_to_propname(svc->doc->name, B_FALSE);
343710461SSean.Wilcox@Sun.COM 
343810461SSean.Wilcox@Sun.COM 		pg = internal_pgroup_create_strict(s, SCF_PG_MANIFESTFILES,
343910461SSean.Wilcox@Sun.COM 		    SCF_GROUP_FRAMEWORK);
344010461SSean.Wilcox@Sun.COM 
344110461SSean.Wilcox@Sun.COM 		if (pg == NULL) {
344210461SSean.Wilcox@Sun.COM 			uu_die(gettext("Property group for prop_pattern, "
344310461SSean.Wilcox@Sun.COM 			    "\"%s\", already exists in %s\n"),
344410461SSean.Wilcox@Sun.COM 			    SCF_PG_MANIFESTFILES, s->sc_name);
344510461SSean.Wilcox@Sun.COM 		}
344610461SSean.Wilcox@Sun.COM 
344710461SSean.Wilcox@Sun.COM 		p = internal_property_create(buf, SCF_TYPE_ASTRING, 1, fname);
344810461SSean.Wilcox@Sun.COM 
344910461SSean.Wilcox@Sun.COM 		(void) internal_attach_property(pg, p);
345010461SSean.Wilcox@Sun.COM 	}
345110461SSean.Wilcox@Sun.COM 
345210461SSean.Wilcox@Sun.COM 	/*
34530Sstevel@tonic-gate 	 * Walk its child elements, as appropriate.
34540Sstevel@tonic-gate 	 */
34550Sstevel@tonic-gate 	for (cursor = svc->xmlChildrenNode; cursor != NULL;
34560Sstevel@tonic-gate 	    cursor = cursor->next) {
34570Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
34580Sstevel@tonic-gate 			continue;
34590Sstevel@tonic-gate 
34600Sstevel@tonic-gate 		e = lxml_xlate_element(cursor->name);
34610Sstevel@tonic-gate 
34620Sstevel@tonic-gate 		switch (e) {
34630Sstevel@tonic-gate 		case SC_INSTANCE:
346410029SAntonello.Cruz@Sun.COM 			if (lxml_get_instance(s, cursor,
346510029SAntonello.Cruz@Sun.COM 			    bundle->sc_bundle_type, op) != 0)
34667887SLiane.Praza@Sun.COM 				return (-1);
34670Sstevel@tonic-gate 			break;
34680Sstevel@tonic-gate 		case SC_TEMPLATE:
346912667SSean.Wilcox@Sun.COM 			if (op == SVCCFG_OP_APPLY) {
347012667SSean.Wilcox@Sun.COM 				semerr(gettext("Template data for \"%s\" may "
347112667SSean.Wilcox@Sun.COM 				    "not be modified in a profile.\n"),
347212667SSean.Wilcox@Sun.COM 				    s->sc_name);
347312667SSean.Wilcox@Sun.COM 
347412667SSean.Wilcox@Sun.COM 				return (-1);
347512667SSean.Wilcox@Sun.COM 			}
347612667SSean.Wilcox@Sun.COM 
34777887SLiane.Praza@Sun.COM 			if (lxml_get_template(s, cursor) != 0)
34787887SLiane.Praza@Sun.COM 				return (-1);
34790Sstevel@tonic-gate 			break;
3480*12967Sgavin.maltby@oracle.com 		case SC_NOTIFICATION_PARAMETERS:
3481*12967Sgavin.maltby@oracle.com 			if (lxml_get_notification_parameters(s, cursor) != 0)
3482*12967Sgavin.maltby@oracle.com 				return (-1);
3483*12967Sgavin.maltby@oracle.com 			break;
34840Sstevel@tonic-gate 		case SC_STABILITY:
34850Sstevel@tonic-gate 			(void) lxml_get_entity_stability(s, cursor);
34860Sstevel@tonic-gate 			break;
34870Sstevel@tonic-gate 		case SC_DEPENDENCY:
34880Sstevel@tonic-gate 			(void) lxml_get_dependency(s, cursor);
34890Sstevel@tonic-gate 			break;
34900Sstevel@tonic-gate 		case SC_DEPENDENT:
34910Sstevel@tonic-gate 			(void) lxml_get_dependent(s, cursor);
34920Sstevel@tonic-gate 			break;
34930Sstevel@tonic-gate 		case SC_RESTARTER:
34940Sstevel@tonic-gate 			(void) lxml_get_restarter(s, cursor);
34950Sstevel@tonic-gate 			break;
34960Sstevel@tonic-gate 		case SC_EXEC_METHOD:
34970Sstevel@tonic-gate 			(void) lxml_get_exec_method(s, cursor);
34980Sstevel@tonic-gate 			break;
34990Sstevel@tonic-gate 		case SC_METHOD_CONTEXT:
35000Sstevel@tonic-gate 			(void) lxml_get_entity_method_context(s, cursor);
35010Sstevel@tonic-gate 			break;
35020Sstevel@tonic-gate 		case SC_PROPERTY_GROUP:
35030Sstevel@tonic-gate 			(void) lxml_get_pgroup(s, cursor);
35040Sstevel@tonic-gate 			break;
35050Sstevel@tonic-gate 		case SC_INSTANCE_CREATE_DEFAULT:
35060Sstevel@tonic-gate 			(void) lxml_get_default_instance(s, cursor);
35070Sstevel@tonic-gate 			break;
35080Sstevel@tonic-gate 		case SC_INSTANCE_SINGLE:
35090Sstevel@tonic-gate 			(void) lxml_get_single_instance(s, cursor);
35100Sstevel@tonic-gate 			break;
35110Sstevel@tonic-gate 		default:
35120Sstevel@tonic-gate 			uu_die(gettext(
35130Sstevel@tonic-gate 			    "illegal element \"%s\" on service \"%s\"\n"),
35140Sstevel@tonic-gate 			    cursor->name, s->sc_name);
35150Sstevel@tonic-gate 			break;
35160Sstevel@tonic-gate 		}
35170Sstevel@tonic-gate 	}
35180Sstevel@tonic-gate 
351912667SSean.Wilcox@Sun.COM 	/*
352012667SSean.Wilcox@Sun.COM 	 * Now that the service has been processed set the missing type
352112667SSean.Wilcox@Sun.COM 	 * for the service.  So that only the services with missing
352212667SSean.Wilcox@Sun.COM 	 * types are processed.
352312667SSean.Wilcox@Sun.COM 	 */
352412667SSean.Wilcox@Sun.COM 	s->sc_miss_type = est->sc_miss_type;
352512667SSean.Wilcox@Sun.COM 	if (est->sc_miss_type)
352612667SSean.Wilcox@Sun.COM 		est->sc_miss_type = B_FALSE;
352712667SSean.Wilcox@Sun.COM 
35280Sstevel@tonic-gate 	return (internal_attach_service(bundle, s));
35290Sstevel@tonic-gate }
35300Sstevel@tonic-gate 
35310Sstevel@tonic-gate #ifdef DEBUG
35320Sstevel@tonic-gate void
lxml_dump(int g,xmlNodePtr p)35330Sstevel@tonic-gate lxml_dump(int g, xmlNodePtr p)
35340Sstevel@tonic-gate {
35350Sstevel@tonic-gate 	if (p && p->name) {
353612667SSean.Wilcox@Sun.COM 		(void) printf("%d %s\n", g, p->name);
35370Sstevel@tonic-gate 
35380Sstevel@tonic-gate 		for (p = p->xmlChildrenNode; p != NULL; p = p->next)
35390Sstevel@tonic-gate 			lxml_dump(g + 1, p);
35400Sstevel@tonic-gate 	}
35410Sstevel@tonic-gate }
35420Sstevel@tonic-gate #endif /* DEBUG */
35430Sstevel@tonic-gate 
35440Sstevel@tonic-gate static int
lxml_is_known_dtd(const xmlChar * dtdname)35450Sstevel@tonic-gate lxml_is_known_dtd(const xmlChar *dtdname)
35460Sstevel@tonic-gate {
35470Sstevel@tonic-gate 	if (dtdname == NULL ||
35480Sstevel@tonic-gate 	    strcmp(MANIFEST_DTD_PATH, (const char *)dtdname) != 0)
35490Sstevel@tonic-gate 		return (0);
35500Sstevel@tonic-gate 
35510Sstevel@tonic-gate 	return (1);
35520Sstevel@tonic-gate }
35530Sstevel@tonic-gate 
35540Sstevel@tonic-gate static int
lxml_get_bundle(bundle_t * bundle,bundle_type_t bundle_type,xmlNodePtr subbundle,svccfg_op_t op)35550Sstevel@tonic-gate lxml_get_bundle(bundle_t *bundle, bundle_type_t bundle_type,
35565040Swesolows     xmlNodePtr subbundle, svccfg_op_t op)
35570Sstevel@tonic-gate {
35580Sstevel@tonic-gate 	xmlNodePtr cursor;
35590Sstevel@tonic-gate 	xmlChar *type;
35600Sstevel@tonic-gate 	int e;
35610Sstevel@tonic-gate 
35620Sstevel@tonic-gate 	/*
35630Sstevel@tonic-gate 	 * 1.  Get bundle attributes.
35640Sstevel@tonic-gate 	 */
35657887SLiane.Praza@Sun.COM 	type = xmlGetProp(subbundle, (xmlChar *)type_attr);
35660Sstevel@tonic-gate 	bundle->sc_bundle_type = lxml_xlate_bundle_type(type);
35670Sstevel@tonic-gate 	if (bundle->sc_bundle_type != bundle_type &&
35680Sstevel@tonic-gate 	    bundle_type != SVCCFG_UNKNOWN_BUNDLE) {
35690Sstevel@tonic-gate 		semerr(gettext("included bundle of different type.\n"));
35700Sstevel@tonic-gate 		return (-1);
35710Sstevel@tonic-gate 	}
35720Sstevel@tonic-gate 
35730Sstevel@tonic-gate 	xmlFree(type);
35740Sstevel@tonic-gate 
35755040Swesolows 	switch (op) {
35765040Swesolows 	case SVCCFG_OP_IMPORT:
35770Sstevel@tonic-gate 		if (bundle->sc_bundle_type != SVCCFG_MANIFEST) {
35780Sstevel@tonic-gate 			semerr(gettext("document is not a manifest.\n"));
35790Sstevel@tonic-gate 			return (-1);
35800Sstevel@tonic-gate 		}
35815040Swesolows 		break;
35825040Swesolows 	case SVCCFG_OP_APPLY:
35830Sstevel@tonic-gate 		if (bundle->sc_bundle_type != SVCCFG_PROFILE) {
35840Sstevel@tonic-gate 			semerr(gettext("document is not a profile.\n"));
35850Sstevel@tonic-gate 			return (-1);
35860Sstevel@tonic-gate 		}
35875040Swesolows 		break;
35885040Swesolows 	case SVCCFG_OP_RESTORE:
35895040Swesolows 		if (bundle->sc_bundle_type != SVCCFG_ARCHIVE) {
35905040Swesolows 			semerr(gettext("document is not an archive.\n"));
35915040Swesolows 			return (-1);
35925040Swesolows 		}
35935040Swesolows 		break;
35940Sstevel@tonic-gate 	}
35950Sstevel@tonic-gate 
35967887SLiane.Praza@Sun.COM 	if (((bundle->sc_bundle_name = xmlGetProp(subbundle,
35977887SLiane.Praza@Sun.COM 	    (xmlChar *)name_attr)) == NULL) || (*bundle->sc_bundle_name == 0)) {
35980Sstevel@tonic-gate 		semerr(gettext("service bundle lacks name attribute\n"));
35990Sstevel@tonic-gate 		return (-1);
36000Sstevel@tonic-gate 	}
36010Sstevel@tonic-gate 
36020Sstevel@tonic-gate 	/*
36030Sstevel@tonic-gate 	 * 2.  Get services, descend into each one and build state.
36040Sstevel@tonic-gate 	 */
36050Sstevel@tonic-gate 	for (cursor = subbundle->xmlChildrenNode; cursor != NULL;
36060Sstevel@tonic-gate 	    cursor = cursor->next) {
36070Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
36080Sstevel@tonic-gate 			continue;
36090Sstevel@tonic-gate 
36100Sstevel@tonic-gate 		e = lxml_xlate_element(cursor->name);
36110Sstevel@tonic-gate 
36120Sstevel@tonic-gate 		switch (e) {
36130Sstevel@tonic-gate 		case SC_XI_INCLUDE:
36140Sstevel@tonic-gate 			continue;
36150Sstevel@tonic-gate 
36160Sstevel@tonic-gate 		case SC_SERVICE_BUNDLE:
36175040Swesolows 			if (lxml_get_bundle(bundle, bundle_type, cursor, op))
36180Sstevel@tonic-gate 				return (-1);
36190Sstevel@tonic-gate 			break;
36200Sstevel@tonic-gate 		case SC_SERVICE:
36217887SLiane.Praza@Sun.COM 			if (lxml_get_service(bundle, cursor, op) != 0)
36227887SLiane.Praza@Sun.COM 				return (-1);
36230Sstevel@tonic-gate 			break;
36240Sstevel@tonic-gate 		}
36250Sstevel@tonic-gate 	}
36260Sstevel@tonic-gate 
36270Sstevel@tonic-gate 	return (0);
36280Sstevel@tonic-gate }
36290Sstevel@tonic-gate 
36300Sstevel@tonic-gate /*
36310Sstevel@tonic-gate  * Load an XML tree from filename and translate it into an internal service
36325040Swesolows  * tree bundle.  Require that the bundle be of appropriate type for the
36335040Swesolows  * operation: archive for RESTORE, manifest for IMPORT, profile for APPLY.
36340Sstevel@tonic-gate  */
36350Sstevel@tonic-gate int
lxml_get_bundle_file(bundle_t * bundle,const char * filename,svccfg_op_t op)36365040Swesolows lxml_get_bundle_file(bundle_t *bundle, const char *filename, svccfg_op_t op)
36370Sstevel@tonic-gate {
36380Sstevel@tonic-gate 	xmlDocPtr document;
36390Sstevel@tonic-gate 	xmlNodePtr cursor;
36400Sstevel@tonic-gate 	xmlDtdPtr dtd = NULL;
36410Sstevel@tonic-gate 	xmlValidCtxtPtr vcp;
36420Sstevel@tonic-gate 	boolean_t do_validate;
36430Sstevel@tonic-gate 	char *dtdpath = NULL;
36440Sstevel@tonic-gate 	int r;
36450Sstevel@tonic-gate 
36460Sstevel@tonic-gate 	/*
36474740Sjeanm 	 * Verify we can read the file before we try to parse it.
36484740Sjeanm 	 */
36494740Sjeanm 	if (access(filename, R_OK | F_OK) == -1) {
36504740Sjeanm 		semerr(gettext("unable to open file: %s\n"), strerror(errno));
36514740Sjeanm 		return (-1);
36524740Sjeanm 	}
36534740Sjeanm 
36544740Sjeanm 	/*
36550Sstevel@tonic-gate 	 * Until libxml2 addresses DTD-based validation with XInclude, we don't
36560Sstevel@tonic-gate 	 * validate service profiles (i.e. the apply path).
36570Sstevel@tonic-gate 	 */
36585040Swesolows 	do_validate = (op != SVCCFG_OP_APPLY) &&
36595040Swesolows 	    (getenv("SVCCFG_NOVALIDATE") == NULL);
36600Sstevel@tonic-gate 	if (do_validate)
36610Sstevel@tonic-gate 		dtdpath = getenv("SVCCFG_DTD");
36620Sstevel@tonic-gate 
36630Sstevel@tonic-gate 	if (dtdpath != NULL)
36640Sstevel@tonic-gate 		xmlLoadExtDtdDefaultValue = 0;
36650Sstevel@tonic-gate 
36664740Sjeanm 	if ((document = xmlReadFile(filename, NULL, 0)) == NULL) {
36670Sstevel@tonic-gate 		semerr(gettext("couldn't parse document\n"));
36680Sstevel@tonic-gate 		return (-1);
36690Sstevel@tonic-gate 	}
36700Sstevel@tonic-gate 
367110461SSean.Wilcox@Sun.COM 	document->name = strdup(filename);
367210461SSean.Wilcox@Sun.COM 
36730Sstevel@tonic-gate 	/*
36740Sstevel@tonic-gate 	 * Verify that this is a document type we understand.
36750Sstevel@tonic-gate 	 */
36760Sstevel@tonic-gate 	if ((dtd = xmlGetIntSubset(document)) == NULL) {
36770Sstevel@tonic-gate 		semerr(gettext("document has no DTD\n"));
36780Sstevel@tonic-gate 		return (-1);
367912667SSean.Wilcox@Sun.COM 	} else if (dtdpath == NULL && !do_validate) {
368012667SSean.Wilcox@Sun.COM 		/*
368112667SSean.Wilcox@Sun.COM 		 * If apply then setup so that some validation
368212667SSean.Wilcox@Sun.COM 		 * for specific elements can be done.
368312667SSean.Wilcox@Sun.COM 		 */
368412667SSean.Wilcox@Sun.COM 		dtdpath = (char *)document->intSubset->SystemID;
36850Sstevel@tonic-gate 	}
36860Sstevel@tonic-gate 
36870Sstevel@tonic-gate 	if (!lxml_is_known_dtd(dtd->SystemID)) {
36880Sstevel@tonic-gate 		semerr(gettext("document DTD unknown; not service bundle?\n"));
36890Sstevel@tonic-gate 		return (-1);
36900Sstevel@tonic-gate 	}
36910Sstevel@tonic-gate 
36920Sstevel@tonic-gate 	if ((cursor = xmlDocGetRootElement(document)) == NULL) {
36930Sstevel@tonic-gate 		semerr(gettext("document is empty\n"));
36940Sstevel@tonic-gate 		xmlFreeDoc(document);
36950Sstevel@tonic-gate 		return (-1);
36960Sstevel@tonic-gate 	}
36970Sstevel@tonic-gate 
36980Sstevel@tonic-gate 	if (xmlStrcmp(cursor->name, (const xmlChar *)"service_bundle") != 0) {
36990Sstevel@tonic-gate 		semerr(gettext("document is not a service bundle\n"));
37000Sstevel@tonic-gate 		xmlFreeDoc(document);
37010Sstevel@tonic-gate 		return (-1);
37020Sstevel@tonic-gate 	}
37030Sstevel@tonic-gate 
37040Sstevel@tonic-gate 
37050Sstevel@tonic-gate 	if (dtdpath != NULL) {
37060Sstevel@tonic-gate 		dtd = xmlParseDTD(NULL, (xmlChar *)dtdpath);
37070Sstevel@tonic-gate 		if (dtd == NULL) {
37080Sstevel@tonic-gate 			semerr(gettext("Could not parse DTD \"%s\".\n"),
37090Sstevel@tonic-gate 			    dtdpath);
37100Sstevel@tonic-gate 			return (-1);
37110Sstevel@tonic-gate 		}
37120Sstevel@tonic-gate 
37130Sstevel@tonic-gate 		if (document->extSubset != NULL)
37140Sstevel@tonic-gate 			xmlFreeDtd(document->extSubset);
37150Sstevel@tonic-gate 
37160Sstevel@tonic-gate 		document->extSubset = dtd;
37170Sstevel@tonic-gate 	}
37180Sstevel@tonic-gate 
37194740Sjeanm 	if (xmlXIncludeProcessFlags(document, XML_PARSE_XINCLUDE) == -1) {
37200Sstevel@tonic-gate 		semerr(gettext("couldn't handle XInclude statements "
37214740Sjeanm 		    "in document\n"));
37220Sstevel@tonic-gate 		return (-1);
37230Sstevel@tonic-gate 	}
37240Sstevel@tonic-gate 
37250Sstevel@tonic-gate 	if (do_validate) {
37260Sstevel@tonic-gate 		vcp = xmlNewValidCtxt();
37270Sstevel@tonic-gate 		if (vcp == NULL)
37280Sstevel@tonic-gate 			uu_die(gettext("could not allocate memory"));
37290Sstevel@tonic-gate 		vcp->warning = xmlParserValidityWarning;
37300Sstevel@tonic-gate 		vcp->error = xmlParserValidityError;
37310Sstevel@tonic-gate 
37320Sstevel@tonic-gate 		r = xmlValidateDocument(vcp, document);
37330Sstevel@tonic-gate 
37340Sstevel@tonic-gate 		xmlFreeValidCtxt(vcp);
37350Sstevel@tonic-gate 
37360Sstevel@tonic-gate 		if (r == 0) {
37370Sstevel@tonic-gate 			semerr(gettext("Document is not valid.\n"));
37380Sstevel@tonic-gate 			xmlFreeDoc(document);
37390Sstevel@tonic-gate 			return (-1);
37400Sstevel@tonic-gate 		}
37410Sstevel@tonic-gate 	}
37420Sstevel@tonic-gate 
37430Sstevel@tonic-gate #ifdef DEBUG
37440Sstevel@tonic-gate 	lxml_dump(0, cursor);
37450Sstevel@tonic-gate #endif /* DEBUG */
37460Sstevel@tonic-gate 
37475040Swesolows 	r = lxml_get_bundle(bundle, SVCCFG_UNKNOWN_BUNDLE, cursor, op);
37480Sstevel@tonic-gate 
37490Sstevel@tonic-gate 	xmlFreeDoc(document);
37500Sstevel@tonic-gate 
37510Sstevel@tonic-gate 	return (r);
37520Sstevel@tonic-gate }
37530Sstevel@tonic-gate 
37540Sstevel@tonic-gate int
lxml_inventory(const char * filename)37550Sstevel@tonic-gate lxml_inventory(const char *filename)
37560Sstevel@tonic-gate {
37570Sstevel@tonic-gate 	bundle_t *b;
37580Sstevel@tonic-gate 	uu_list_walk_t *svcs, *insts;
37590Sstevel@tonic-gate 	entity_t *svc, *inst;
37600Sstevel@tonic-gate 
37610Sstevel@tonic-gate 	b = internal_bundle_new();
37620Sstevel@tonic-gate 
37635040Swesolows 	if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) != 0) {
37640Sstevel@tonic-gate 		internal_bundle_free(b);
37650Sstevel@tonic-gate 		return (-1);
37660Sstevel@tonic-gate 	}
37670Sstevel@tonic-gate 
37680Sstevel@tonic-gate 	svcs = uu_list_walk_start(b->sc_bundle_services, 0);
37690Sstevel@tonic-gate 	if (svcs == NULL)
37700Sstevel@tonic-gate 		uu_die(gettext("Couldn't walk services"));
37710Sstevel@tonic-gate 
37720Sstevel@tonic-gate 	while ((svc = uu_list_walk_next(svcs)) != NULL) {
37730Sstevel@tonic-gate 		uu_list_t *inst_list;
37740Sstevel@tonic-gate 
37750Sstevel@tonic-gate 		inst_list = svc->sc_u.sc_service.sc_service_instances;
37760Sstevel@tonic-gate 		insts = uu_list_walk_start(inst_list, 0);
37770Sstevel@tonic-gate 		if (insts == NULL)
37780Sstevel@tonic-gate 			uu_die(gettext("Couldn't walk instances"));
37790Sstevel@tonic-gate 
37800Sstevel@tonic-gate 		while ((inst = uu_list_walk_next(insts)) != NULL)
37810Sstevel@tonic-gate 			(void) printf("svc:/%s:%s\n", svc->sc_name,
37820Sstevel@tonic-gate 			    inst->sc_name);
37830Sstevel@tonic-gate 
37840Sstevel@tonic-gate 		uu_list_walk_end(insts);
37850Sstevel@tonic-gate 	}
37860Sstevel@tonic-gate 
37870Sstevel@tonic-gate 	uu_list_walk_end(svcs);
37880Sstevel@tonic-gate 
37890Sstevel@tonic-gate 	svcs = uu_list_walk_start(b->sc_bundle_services, 0);
37900Sstevel@tonic-gate 	while ((svc = uu_list_walk_next(svcs)) != NULL) {
37910Sstevel@tonic-gate 		(void) fputs("svc:/", stdout);
37920Sstevel@tonic-gate 		(void) puts(svc->sc_name);
37930Sstevel@tonic-gate 	}
37940Sstevel@tonic-gate 	uu_list_walk_end(svcs);
37950Sstevel@tonic-gate 
37960Sstevel@tonic-gate 	internal_bundle_free(b);
37970Sstevel@tonic-gate 
37980Sstevel@tonic-gate 	return (0);
37990Sstevel@tonic-gate }
3800