xref: /illumos-gate/usr/src/cmd/svc/svccfg/svccfg_xml.c (revision b0709259)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
576cf44abSjeanm  * Common Development and Distribution License (the "License").
676cf44abSjeanm  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
2285bcc4e5SSean Wilcox  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
237c478bd9Sstevel@tonic-gate  */
2467b0e063SAlbert Lee /*
2567b0e063SAlbert Lee  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
262f602de3SJohn Levon  * Copyright 2020 Joyent, Inc.
2767b0e063SAlbert Lee  */
2867b0e063SAlbert Lee 
297c478bd9Sstevel@tonic-gate 
301f6eb021SLiane Praza /*
311f6eb021SLiane Praza  * XML document manipulation routines
321f6eb021SLiane Praza  *
331f6eb021SLiane Praza  * These routines provide translation to and from the internal representation to
341f6eb021SLiane Praza  * XML.  Directionally-oriented verbs are with respect to the external source,
351f6eb021SLiane Praza  * so lxml_get_service() fetches a service from the XML file into the
361f6eb021SLiane Praza  * internal representation.
371f6eb021SLiane Praza  */
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate #include <libxml/parser.h>
407c478bd9Sstevel@tonic-gate #include <libxml/xinclude.h>
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate #include <assert.h>
437c478bd9Sstevel@tonic-gate #include <ctype.h>
447c478bd9Sstevel@tonic-gate #include <errno.h>
457c478bd9Sstevel@tonic-gate #include <libintl.h>
461f6eb021SLiane Praza #include <libscf.h>
471f6eb021SLiane Praza #include <libscf_priv.h>
487c478bd9Sstevel@tonic-gate #include <libuutil.h>
491f6eb021SLiane Praza #include <sasl/saslutil.h>
507c478bd9Sstevel@tonic-gate #include <stdlib.h>
517c478bd9Sstevel@tonic-gate #include <string.h>
5285bcc4e5SSean Wilcox #include <limits.h>
537c478bd9Sstevel@tonic-gate 
5476cf44abSjeanm #include <sys/types.h>
5576cf44abSjeanm #include <sys/stat.h>
5676cf44abSjeanm #include <unistd.h>
5776cf44abSjeanm 
5823294c7dSSean Wilcox #include <sys/param.h>
5923294c7dSSean Wilcox #include "manifest_hash.h"
6023294c7dSSean Wilcox 
617c478bd9Sstevel@tonic-gate #include "svccfg.h"
62f6e214c7SGavin Maltby #include "notify_params.h"
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate /*
651f6eb021SLiane Praza  * snprintf(3C) format strings for constructing property names that include
661f6eb021SLiane Praza  * the locale designation.  Use %s to indicate where the locale should go.
677c478bd9Sstevel@tonic-gate  *
681f6eb021SLiane Praza  * The VALUE_* symbols are an exception.  The firs %s will be replaced with
691f6eb021SLiane Praza  * "value_".  The second %s will be replaced by the name of the value and
701f6eb021SLiane Praza  * %%s will be replaced by the locale designation.  These formats are
711f6eb021SLiane Praza  * processed twice by snprintf(3C).  The first time captures the value name
721f6eb021SLiane Praza  * and the second time captures the locale.
737c478bd9Sstevel@tonic-gate  */
741f6eb021SLiane Praza #define	LOCALE_ONLY_FMT		("%s")
751f6eb021SLiane Praza #define	COMMON_NAME_FMT		("common_name_%s")
761f6eb021SLiane Praza #define	DESCRIPTION_FMT		("description_%s")
771f6eb021SLiane Praza #define	UNITS_FMT		("units_%s")
781f6eb021SLiane Praza #define	VALUE_COMMON_NAME_FMT	("%s%s_common_name_%%s")
791f6eb021SLiane Praza #define	VALUE_DESCRIPTION_FMT	("%s%s_description_%%s")
801f6eb021SLiane Praza 
811f6eb021SLiane Praza /* Attribute names */
827c478bd9Sstevel@tonic-gate const char * const delete_attr = "delete";
837c478bd9Sstevel@tonic-gate const char * const enabled_attr = "enabled";
841f6eb021SLiane Praza const char * const lang_attr = "lang";
851f6eb021SLiane Praza const char * const manpath_attr = "manpath";
861f6eb021SLiane Praza const char * const max_attr = "max";
871f6eb021SLiane Praza const char * const min_attr = "min";
887c478bd9Sstevel@tonic-gate const char * const name_attr = "name";
897c478bd9Sstevel@tonic-gate const char * const override_attr = "override";
901f6eb021SLiane Praza const char * const required_attr = "required";
911f6eb021SLiane Praza const char * const section_attr = "section";
921f6eb021SLiane Praza const char * const set_attr = "set";
931f6eb021SLiane Praza const char * const target_attr = "target";
941f6eb021SLiane Praza const char * const timeout_seconds_attr = "timeout_seconds";
951f6eb021SLiane Praza const char * const title_attr = "title";
967c478bd9Sstevel@tonic-gate const char * const type_attr = "type";
971f6eb021SLiane Praza const char * const uri_attr = "uri";
987c478bd9Sstevel@tonic-gate const char * const value_attr = "value";
991f6eb021SLiane Praza const char * const version_attr = "version";
1001f6eb021SLiane Praza const char * const xml_lang_attr = "xml:lang";
101f6e214c7SGavin Maltby const char * const active_attr = "active";
1021f6eb021SLiane Praza 
1031f6eb021SLiane Praza /* Attribute values */
1041f6eb021SLiane Praza const char * const all_value = "all";
1051f6eb021SLiane Praza 
1067c478bd9Sstevel@tonic-gate const char * const true = "true";
1077c478bd9Sstevel@tonic-gate const char * const false = "false";
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate /*
1107c478bd9Sstevel@tonic-gate  * The following list must be kept in the same order as that of
1117c478bd9Sstevel@tonic-gate  * element_t array
1127c478bd9Sstevel@tonic-gate  */
1137c478bd9Sstevel@tonic-gate static const char *lxml_elements[] = {
1147c478bd9Sstevel@tonic-gate 	"astring_list",			/* SC_ASTRING */
1157c478bd9Sstevel@tonic-gate 	"boolean_list",			/* SC_BOOLEAN */
1161f6eb021SLiane Praza 	"cardinality",			/* SC_CARDINALITY */
1171f6eb021SLiane Praza 	"choices",			/* SC_CHOICES */
1187c478bd9Sstevel@tonic-gate 	"common_name",			/* SC_COMMON_NAME */
1191f6eb021SLiane Praza 	"constraints",			/* SC_CONSTRAINTS */
1207c478bd9Sstevel@tonic-gate 	"count_list",			/* SC_COUNT */
1217c478bd9Sstevel@tonic-gate 	"create_default_instance",	/* SC_INSTANCE_CREATE_DEFAULT */
1227c478bd9Sstevel@tonic-gate 	"dependency",			/* SC_DEPENDENCY */
1237c478bd9Sstevel@tonic-gate 	"dependent",			/* SC_DEPENDENT */
1247c478bd9Sstevel@tonic-gate 	"description",			/* SC_DESCRIPTION */
1257c478bd9Sstevel@tonic-gate 	"doc_link",			/* SC_DOC_LINK */
1267c478bd9Sstevel@tonic-gate 	"documentation",		/* SC_DOCUMENTATION */
1277c478bd9Sstevel@tonic-gate 	"enabled",			/* SC_ENABLED */
128f6e214c7SGavin Maltby 	"event",			/* SC_EVENT */
1297c478bd9Sstevel@tonic-gate 	"exec_method",			/* SC_EXEC_METHOD */
1307c478bd9Sstevel@tonic-gate 	"fmri_list",			/* SC_FMRI */
1317c478bd9Sstevel@tonic-gate 	"host_list",			/* SC_HOST */
1327c478bd9Sstevel@tonic-gate 	"hostname_list",		/* SC_HOSTNAME */
1331f6eb021SLiane Praza 	"include_values",		/* SC_INCLUDE_VALUES */
1347c478bd9Sstevel@tonic-gate 	"instance",			/* SC_INSTANCE */
1357c478bd9Sstevel@tonic-gate 	"integer_list",			/* SC_INTEGER */
1361f6eb021SLiane Praza 	"internal_separators",		/* SC_INTERNAL_SEPARATORS */
1377c478bd9Sstevel@tonic-gate 	"loctext",			/* SC_LOCTEXT */
1387c478bd9Sstevel@tonic-gate 	"manpage",			/* SC_MANPAGE */
1397c478bd9Sstevel@tonic-gate 	"method_context",		/* SC_METHOD_CONTEXT */
1407c478bd9Sstevel@tonic-gate 	"method_credential",		/* SC_METHOD_CREDENTIAL */
1417c478bd9Sstevel@tonic-gate 	"method_profile",		/* SC_METHOD_PROFILE */
1427c478bd9Sstevel@tonic-gate 	"method_environment",		/* SC_METHOD_ENVIRONMENT */
1437c478bd9Sstevel@tonic-gate 	"envvar",			/* SC_METHOD_ENVVAR */
144f6f041a2SAntonello Cruz 	"net_address_list",		/* SC_NET_ADDR */
1457c478bd9Sstevel@tonic-gate 	"net_address_v4_list",		/* SC_NET_ADDR_V4 */
1467c478bd9Sstevel@tonic-gate 	"net_address_v6_list",		/* SC_NET_ADDR_V6 */
147f6e214c7SGavin Maltby 	"notification_parameters",	/* SC_NOTIFICATION_PARAMETERS */
1487c478bd9Sstevel@tonic-gate 	"opaque_list",			/* SC_OPAQUE */
149f6e214c7SGavin Maltby 	"parameter",			/* SC_PARAMETER */
150f6e214c7SGavin Maltby 	"paramval",			/* SC_PARAMVAL */
1511f6eb021SLiane Praza 	"pg_pattern",			/* SC_PG_PATTERN */
1521f6eb021SLiane Praza 	"prop_pattern",			/* SC_PROP_PATTERN */
1537c478bd9Sstevel@tonic-gate 	"property",			/* SC_PROPERTY */
1547c478bd9Sstevel@tonic-gate 	"property_group",		/* SC_PROPERTY_GROUP */
1557c478bd9Sstevel@tonic-gate 	"propval",			/* SC_PROPVAL */
1561f6eb021SLiane Praza 	"range",			/* SC_RANGE */
1577c478bd9Sstevel@tonic-gate 	"restarter",			/* SC_RESTARTER */
1587c478bd9Sstevel@tonic-gate 	"service",			/* SC_SERVICE */
1597c478bd9Sstevel@tonic-gate 	"service_bundle",		/* SC_SERVICE_BUNDLE */
1607c478bd9Sstevel@tonic-gate 	"service_fmri",			/* SC_SERVICE_FMRI */
1617c478bd9Sstevel@tonic-gate 	"single_instance",		/* SC_INSTANCE_SINGLE */
1627c478bd9Sstevel@tonic-gate 	"stability",			/* SC_STABILITY */
1637c478bd9Sstevel@tonic-gate 	"template",			/* SC_TEMPLATE */
1647c478bd9Sstevel@tonic-gate 	"time_list",			/* SC_TIME */
165f6e214c7SGavin Maltby 	"type",				/* SC_TYPE */
1661f6eb021SLiane Praza 	"units",			/* SC_UNITS */
1677c478bd9Sstevel@tonic-gate 	"uri_list",			/* SC_URI */
1687c478bd9Sstevel@tonic-gate 	"ustring_list",			/* SC_USTRING */
1691f6eb021SLiane Praza 	"value",			/* SC_VALUE */
1707c478bd9Sstevel@tonic-gate 	"value_node",			/* SC_VALUE_NODE */
1711f6eb021SLiane Praza 	"values",			/* SC_VALUES */
1721f6eb021SLiane Praza 	"visibility",			/* SC_VISIBILITY */
1737c478bd9Sstevel@tonic-gate 	"xi:fallback",			/* SC_XI_FALLBACK */
1747c478bd9Sstevel@tonic-gate 	"xi:include"			/* SC_XI_INCLUDE */
1757c478bd9Sstevel@tonic-gate };
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate /*
1787c478bd9Sstevel@tonic-gate  * The following list must be kept in the same order as that of
1797c478bd9Sstevel@tonic-gate  * element_t array
1807c478bd9Sstevel@tonic-gate  */
1817c478bd9Sstevel@tonic-gate static const char *lxml_prop_types[] = {
1827c478bd9Sstevel@tonic-gate 	"astring",			/* SC_ASTRING */
1837c478bd9Sstevel@tonic-gate 	"boolean",			/* SC_BOOLEAN */
1841f6eb021SLiane Praza 	"",				/* SC_CARDINALITY */
1851f6eb021SLiane Praza 	"",				/* SC_CHOICES */
1867c478bd9Sstevel@tonic-gate 	"",				/* SC_COMMON_NAME */
1871f6eb021SLiane Praza 	"",				/* SC_CONSTRAINTS */
1887c478bd9Sstevel@tonic-gate 	"count",			/* SC_COUNT */
1897c478bd9Sstevel@tonic-gate 	"",				/* SC_INSTANCE_CREATE_DEFAULT */
1907c478bd9Sstevel@tonic-gate 	"",				/* SC_DEPENDENCY */
1917c478bd9Sstevel@tonic-gate 	"",				/* SC_DEPENDENT */
1927c478bd9Sstevel@tonic-gate 	"",				/* SC_DESCRIPTION */
1937c478bd9Sstevel@tonic-gate 	"",				/* SC_DOC_LINK */
1947c478bd9Sstevel@tonic-gate 	"",				/* SC_DOCUMENTATION */
1957c478bd9Sstevel@tonic-gate 	"",				/* SC_ENABLED */
196f6e214c7SGavin Maltby 	"",				/* SC_EVENT */
1977c478bd9Sstevel@tonic-gate 	"",				/* SC_EXEC_METHOD */
1987c478bd9Sstevel@tonic-gate 	"fmri",				/* SC_FMRI */
1997c478bd9Sstevel@tonic-gate 	"host",				/* SC_HOST */
2007c478bd9Sstevel@tonic-gate 	"hostname",			/* SC_HOSTNAME */
2011f6eb021SLiane Praza 	"",				/* SC_INCLUDE_VALUES */
2027c478bd9Sstevel@tonic-gate 	"",				/* SC_INSTANCE */
2037c478bd9Sstevel@tonic-gate 	"integer",			/* SC_INTEGER */
2041f6eb021SLiane Praza 	"",				/* SC_INTERNAL_SEPARATORS */
2057c478bd9Sstevel@tonic-gate 	"",				/* SC_LOCTEXT */
2067c478bd9Sstevel@tonic-gate 	"",				/* SC_MANPAGE */
2077c478bd9Sstevel@tonic-gate 	"",				/* SC_METHOD_CONTEXT */
2087c478bd9Sstevel@tonic-gate 	"",				/* SC_METHOD_CREDENTIAL */
2097c478bd9Sstevel@tonic-gate 	"",				/* SC_METHOD_PROFILE */
2107c478bd9Sstevel@tonic-gate 	"",				/* SC_METHOD_ENVIRONMENT */
2117c478bd9Sstevel@tonic-gate 	"",				/* SC_METHOD_ENVVAR */
212f6f041a2SAntonello Cruz 	"net_address",			/* SC_NET_ADDR */
2137c478bd9Sstevel@tonic-gate 	"net_address_v4",		/* SC_NET_ADDR_V4 */
2147c478bd9Sstevel@tonic-gate 	"net_address_v6",		/* SC_NET_ADDR_V6 */
215f6e214c7SGavin Maltby 	"",				/* SC_NOTIFICATION_PARAMETERS */
2167c478bd9Sstevel@tonic-gate 	"opaque",			/* SC_OPAQUE */
217f6e214c7SGavin Maltby 	"",				/* SC_PARAMETER */
218f6e214c7SGavin Maltby 	"",				/* SC_PARAMVAL */
2191f6eb021SLiane Praza 	"",				/* SC_PG_PATTERN */
2201f6eb021SLiane Praza 	"",				/* SC_PROP_PATTERN */
2217c478bd9Sstevel@tonic-gate 	"",				/* SC_PROPERTY */
2227c478bd9Sstevel@tonic-gate 	"",				/* SC_PROPERTY_GROUP */
2237c478bd9Sstevel@tonic-gate 	"",				/* SC_PROPVAL */
2241f6eb021SLiane Praza 	"",				/* SC_RANGE */
2257c478bd9Sstevel@tonic-gate 	"",				/* SC_RESTARTER */
2267c478bd9Sstevel@tonic-gate 	"",				/* SC_SERVICE */
2277c478bd9Sstevel@tonic-gate 	"",				/* SC_SERVICE_BUNDLE */
2287c478bd9Sstevel@tonic-gate 	"",				/* SC_SERVICE_FMRI */
2297c478bd9Sstevel@tonic-gate 	"",				/* SC_INSTANCE_SINGLE */
2307c478bd9Sstevel@tonic-gate 	"",				/* SC_STABILITY */
2317c478bd9Sstevel@tonic-gate 	"",				/* SC_TEMPLATE */
2327c478bd9Sstevel@tonic-gate 	"time",				/* SC_TIME */
233f6e214c7SGavin Maltby 	"",				/* SC_TYPE */
2341f6eb021SLiane Praza 	"",				/* SC_UNITS */
2357c478bd9Sstevel@tonic-gate 	"uri",				/* SC_URI */
2367c478bd9Sstevel@tonic-gate 	"ustring",			/* SC_USTRING */
2371f6eb021SLiane Praza 	"",				/* SC_VALUE */
2381f6eb021SLiane Praza 	"",				/* SC_VALUE_NODE */
2391f6eb021SLiane Praza 	"",				/* SC_VALUES */
2401f6eb021SLiane Praza 	"",				/* SC_VISIBILITY */
2411f6eb021SLiane Praza 	"",				/* SC_XI_FALLBACK */
2427c478bd9Sstevel@tonic-gate 	""				/* SC_XI_INCLUDE */
2437c478bd9Sstevel@tonic-gate };
2447c478bd9Sstevel@tonic-gate 
245*b0709259SAndy Fiddaman static int xml_read_options = 0;
246*b0709259SAndy Fiddaman 
2477c478bd9Sstevel@tonic-gate int
lxml_init()2487c478bd9Sstevel@tonic-gate lxml_init()
2497c478bd9Sstevel@tonic-gate {
2507c478bd9Sstevel@tonic-gate 	if (getenv("SVCCFG_NOVALIDATE") == NULL) {
2517c478bd9Sstevel@tonic-gate 		/*
252*b0709259SAndy Fiddaman 		 * DTD validation.
2537c478bd9Sstevel@tonic-gate 		 */
254*b0709259SAndy Fiddaman 		xml_read_options |= XML_PARSE_DTDLOAD | XML_PARSE_DTDATTR;
2557c478bd9Sstevel@tonic-gate 	}
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate 	return (0);
2587c478bd9Sstevel@tonic-gate }
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate static bundle_type_t
lxml_xlate_bundle_type(xmlChar * type)2617c478bd9Sstevel@tonic-gate lxml_xlate_bundle_type(xmlChar *type)
2627c478bd9Sstevel@tonic-gate {
2637c478bd9Sstevel@tonic-gate 	if (xmlStrcmp(type, (const xmlChar *)"manifest") == 0)
2647c478bd9Sstevel@tonic-gate 		return (SVCCFG_MANIFEST);
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate 	if (xmlStrcmp(type, (const xmlChar *)"profile") == 0)
2677c478bd9Sstevel@tonic-gate 		return (SVCCFG_PROFILE);
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate 	if (xmlStrcmp(type, (const xmlChar *)"archive") == 0)
2707c478bd9Sstevel@tonic-gate 		return (SVCCFG_ARCHIVE);
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate 	return (SVCCFG_UNKNOWN_BUNDLE);
2737c478bd9Sstevel@tonic-gate }
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate static service_type_t
lxml_xlate_service_type(xmlChar * type)2767c478bd9Sstevel@tonic-gate lxml_xlate_service_type(xmlChar *type)
2777c478bd9Sstevel@tonic-gate {
2787c478bd9Sstevel@tonic-gate 	if (xmlStrcmp(type, (const xmlChar *)"service") == 0)
2797c478bd9Sstevel@tonic-gate 		return (SVCCFG_SERVICE);
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate 	if (xmlStrcmp(type, (const xmlChar *)"restarter") == 0)
2827c478bd9Sstevel@tonic-gate 		return (SVCCFG_RESTARTER);
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate 	if (xmlStrcmp(type, (const xmlChar *)"milestone") == 0)
2857c478bd9Sstevel@tonic-gate 		return (SVCCFG_MILESTONE);
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate 	return (SVCCFG_UNKNOWN_SERVICE);
2887c478bd9Sstevel@tonic-gate }
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate static element_t
lxml_xlate_element(const xmlChar * tag)2917c478bd9Sstevel@tonic-gate lxml_xlate_element(const xmlChar *tag)
2927c478bd9Sstevel@tonic-gate {
2937c478bd9Sstevel@tonic-gate 	int i;
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate 	for (i = 0; i < sizeof (lxml_elements) / sizeof (char *); i++)
2967c478bd9Sstevel@tonic-gate 		if (xmlStrcmp(tag, (const xmlChar *)lxml_elements[i]) == 0)
2977c478bd9Sstevel@tonic-gate 			return ((element_t)i);
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate 	return ((element_t)-1);
3007c478bd9Sstevel@tonic-gate }
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate static uint_t
lxml_xlate_boolean(const xmlChar * value)3037c478bd9Sstevel@tonic-gate lxml_xlate_boolean(const xmlChar *value)
3047c478bd9Sstevel@tonic-gate {
3057c478bd9Sstevel@tonic-gate 	if (xmlStrcmp(value, (const xmlChar *)true) == 0)
3067c478bd9Sstevel@tonic-gate 		return (1);
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate 	if (xmlStrcmp(value, (const xmlChar *)false) == 0)
3097c478bd9Sstevel@tonic-gate 		return (0);
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate 	uu_die(gettext("illegal boolean value \"%s\"\n"), value);
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
3147c478bd9Sstevel@tonic-gate }
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate static scf_type_t
lxml_element_to_type(element_t type)3177c478bd9Sstevel@tonic-gate lxml_element_to_type(element_t type)
3187c478bd9Sstevel@tonic-gate {
3197c478bd9Sstevel@tonic-gate 	switch (type) {
3207c478bd9Sstevel@tonic-gate 	case SC_ASTRING:	return (SCF_TYPE_ASTRING);
3217c478bd9Sstevel@tonic-gate 	case SC_BOOLEAN:	return (SCF_TYPE_BOOLEAN);
3227c478bd9Sstevel@tonic-gate 	case SC_COUNT:		return (SCF_TYPE_COUNT);
3237c478bd9Sstevel@tonic-gate 	case SC_FMRI:		return (SCF_TYPE_FMRI);
3247c478bd9Sstevel@tonic-gate 	case SC_HOST:		return (SCF_TYPE_HOST);
3257c478bd9Sstevel@tonic-gate 	case SC_HOSTNAME:	return (SCF_TYPE_HOSTNAME);
3267c478bd9Sstevel@tonic-gate 	case SC_INTEGER:	return (SCF_TYPE_INTEGER);
327f6f041a2SAntonello Cruz 	case SC_NET_ADDR:	return (SCF_TYPE_NET_ADDR);
3287c478bd9Sstevel@tonic-gate 	case SC_NET_ADDR_V4:	return (SCF_TYPE_NET_ADDR_V4);
3297c478bd9Sstevel@tonic-gate 	case SC_NET_ADDR_V6:	return (SCF_TYPE_NET_ADDR_V6);
3307c478bd9Sstevel@tonic-gate 	case SC_OPAQUE:		return (SCF_TYPE_OPAQUE);
3317c478bd9Sstevel@tonic-gate 	case SC_TIME:		return (SCF_TYPE_TIME);
3327c478bd9Sstevel@tonic-gate 	case SC_URI:		return (SCF_TYPE_URI);
3337c478bd9Sstevel@tonic-gate 	case SC_USTRING:	return (SCF_TYPE_USTRING);
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate 	default:
3367c478bd9Sstevel@tonic-gate 		uu_die(gettext("unknown value type (%d)\n"), type);
3377c478bd9Sstevel@tonic-gate 	}
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
3407c478bd9Sstevel@tonic-gate }
3417c478bd9Sstevel@tonic-gate 
342f329b923SSean Wilcox static element_t
lxml_type_to_element(scf_type_t type)343f329b923SSean Wilcox lxml_type_to_element(scf_type_t type)
3447c478bd9Sstevel@tonic-gate {
3457c478bd9Sstevel@tonic-gate 	switch (type) {
346f329b923SSean Wilcox 	case SCF_TYPE_ASTRING:		return (SC_ASTRING);
347f329b923SSean Wilcox 	case SCF_TYPE_BOOLEAN:		return (SC_BOOLEAN);
348f329b923SSean Wilcox 	case SCF_TYPE_COUNT:		return (SC_COUNT);
349f329b923SSean Wilcox 	case SCF_TYPE_FMRI:		return (SC_FMRI);
350f329b923SSean Wilcox 	case SCF_TYPE_HOST:		return (SC_HOST);
351f329b923SSean Wilcox 	case SCF_TYPE_HOSTNAME:		return (SC_HOSTNAME);
352f329b923SSean Wilcox 	case SCF_TYPE_INTEGER:		return (SC_INTEGER);
353f6f041a2SAntonello Cruz 	case SCF_TYPE_NET_ADDR:		return (SC_NET_ADDR);
354f329b923SSean Wilcox 	case SCF_TYPE_NET_ADDR_V4:	return (SC_NET_ADDR_V4);
355f329b923SSean Wilcox 	case SCF_TYPE_NET_ADDR_V6:	return (SC_NET_ADDR_V6);
356f329b923SSean Wilcox 	case SCF_TYPE_OPAQUE:		return (SC_OPAQUE);
357f329b923SSean Wilcox 	case SCF_TYPE_TIME:		return (SC_TIME);
358f329b923SSean Wilcox 	case SCF_TYPE_URI:		return (SC_URI);
359f329b923SSean Wilcox 	case SCF_TYPE_USTRING:		return (SC_USTRING);
360f329b923SSean Wilcox 
3617c478bd9Sstevel@tonic-gate 	default:
3627c478bd9Sstevel@tonic-gate 		uu_die(gettext("unknown value type (%d)\n"), type);
3637c478bd9Sstevel@tonic-gate 	}
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
3667c478bd9Sstevel@tonic-gate }
3677c478bd9Sstevel@tonic-gate 
3681f6eb021SLiane Praza /*
3691f6eb021SLiane Praza  * Create a SCF_TYPE_BOOLEAN property name pname and attach it to the
3701f6eb021SLiane Praza  * property group at pgrp.  The value of the property will be set from the
3711f6eb021SLiane Praza  * attribute named attr.  attr must have a value of 0, 1, true or false.
3721f6eb021SLiane Praza  *
3731f6eb021SLiane Praza  * Zero is returned on success.  An error is indicated by -1.  It indicates
3741f6eb021SLiane Praza  * that either the attribute had an invalid value or that we could not
3751f6eb021SLiane Praza  * attach the property to pgrp.  The attribute should not have an invalid
3761f6eb021SLiane Praza  * value if the DTD is correctly written.
3771f6eb021SLiane Praza  */
3781f6eb021SLiane Praza static int
new_bool_prop_from_attr(pgroup_t * pgrp,const char * pname,xmlNodePtr n,const char * attr)3791f6eb021SLiane Praza new_bool_prop_from_attr(pgroup_t *pgrp, const char *pname, xmlNodePtr n,
3801f6eb021SLiane Praza     const char *attr)
3811f6eb021SLiane Praza {
3821f6eb021SLiane Praza 	uint64_t bool;
3831f6eb021SLiane Praza 	xmlChar *val;
3841f6eb021SLiane Praza 	property_t *p;
3851f6eb021SLiane Praza 	int r;
3861f6eb021SLiane Praza 
3871f6eb021SLiane Praza 	val = xmlGetProp(n, (xmlChar *)attr);
3881f6eb021SLiane Praza 	if (val == NULL)
3891f6eb021SLiane Praza 		return (0);
3901f6eb021SLiane Praza 
3911f6eb021SLiane Praza 	if ((xmlStrcmp(val, (xmlChar *)"0") == 0) ||
3921f6eb021SLiane Praza 	    (xmlStrcmp(val, (xmlChar *)"false") == 0)) {
3931f6eb021SLiane Praza 		bool = 0;
3941f6eb021SLiane Praza 	} else if ((xmlStrcmp(val, (xmlChar *)"1") == 0) ||
3951f6eb021SLiane Praza 	    (xmlStrcmp(val, (xmlChar *)"true") == 0)) {
3961f6eb021SLiane Praza 		bool = 1;
3971f6eb021SLiane Praza 	} else {
3981f6eb021SLiane Praza 		xmlFree(val);
3991f6eb021SLiane Praza 		return (-1);
4001f6eb021SLiane Praza 	}
4011f6eb021SLiane Praza 	xmlFree(val);
4021f6eb021SLiane Praza 	p = internal_property_create(pname, SCF_TYPE_BOOLEAN, 1, bool);
4031f6eb021SLiane Praza 	r = internal_attach_property(pgrp, p);
4041f6eb021SLiane Praza 
4051f6eb021SLiane Praza 	if (r != 0)
4061f6eb021SLiane Praza 		internal_property_free(p);
4071f6eb021SLiane Praza 
4081f6eb021SLiane Praza 	return (r);
4091f6eb021SLiane Praza }
4101f6eb021SLiane Praza 
4117c478bd9Sstevel@tonic-gate static int
new_str_prop_from_attr(pgroup_t * pgrp,const char * pname,scf_type_t ty,xmlNodePtr n,const char * attr)4127c478bd9Sstevel@tonic-gate new_str_prop_from_attr(pgroup_t *pgrp, const char *pname, scf_type_t ty,
4137c478bd9Sstevel@tonic-gate     xmlNodePtr n, const char *attr)
4147c478bd9Sstevel@tonic-gate {
4157c478bd9Sstevel@tonic-gate 	xmlChar *val;
4167c478bd9Sstevel@tonic-gate 	property_t *p;
4177c478bd9Sstevel@tonic-gate 	int r;
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate 	val = xmlGetProp(n, (xmlChar *)attr);
4207c478bd9Sstevel@tonic-gate 
4217c478bd9Sstevel@tonic-gate 	p = internal_property_create(pname, ty, 1, val);
4227c478bd9Sstevel@tonic-gate 	r = internal_attach_property(pgrp, p);
4237c478bd9Sstevel@tonic-gate 
4247c478bd9Sstevel@tonic-gate 	if (r != 0)
4257c478bd9Sstevel@tonic-gate 		internal_property_free(p);
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate 	return (r);
4287c478bd9Sstevel@tonic-gate }
4297c478bd9Sstevel@tonic-gate 
4301f6eb021SLiane Praza 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)4311f6eb021SLiane Praza new_opt_str_prop_from_attr(pgroup_t *pgrp, const char *pname, scf_type_t ty,
4321f6eb021SLiane Praza     xmlNodePtr n, const char *attr, const char *dflt)
4331f6eb021SLiane Praza {
4341f6eb021SLiane Praza 	xmlChar *val;
4351f6eb021SLiane Praza 	property_t *p;
4361f6eb021SLiane Praza 	int r;
4371f6eb021SLiane Praza 
4381f6eb021SLiane Praza 	val = xmlGetProp(n, (xmlChar *)attr);
4391f6eb021SLiane Praza 	if (val == NULL) {
4401f6eb021SLiane Praza 		if (dflt == NULL) {
4411f6eb021SLiane Praza 			/*
4421f6eb021SLiane Praza 			 * A missing attribute is considered to be a
4431f6eb021SLiane Praza 			 * success in this function, because many of the
4441f6eb021SLiane Praza 			 * attributes are optional.  Missing non-optional
4451f6eb021SLiane Praza 			 * attributes will be detected later when template
4461f6eb021SLiane Praza 			 * validation is done.
4471f6eb021SLiane Praza 			 */
4481f6eb021SLiane Praza 			return (0);
4491f6eb021SLiane Praza 		} else {
4501f6eb021SLiane Praza 			val = (xmlChar *)dflt;
4511f6eb021SLiane Praza 		}
4521f6eb021SLiane Praza 	}
4531f6eb021SLiane Praza 
4541f6eb021SLiane Praza 	p = internal_property_create(pname, ty, 1, val);
4551f6eb021SLiane Praza 	r = internal_attach_property(pgrp, p);
4561f6eb021SLiane Praza 
4571f6eb021SLiane Praza 	if (r != 0)
4581f6eb021SLiane Praza 		internal_property_free(p);
4591f6eb021SLiane Praza 
4601f6eb021SLiane Praza 	return (r);
4611f6eb021SLiane Praza }
4621f6eb021SLiane Praza 
4637c478bd9Sstevel@tonic-gate static int
lxml_ignorable_block(xmlNodePtr n)4647c478bd9Sstevel@tonic-gate lxml_ignorable_block(xmlNodePtr n)
4657c478bd9Sstevel@tonic-gate {
4667c478bd9Sstevel@tonic-gate 	return ((xmlStrcmp(n->name, (xmlChar *)"text") == 0 ||
4677c478bd9Sstevel@tonic-gate 	    xmlStrcmp(n->name, (xmlChar *)"comment") == 0) ? 1 : 0);
4687c478bd9Sstevel@tonic-gate }
4697c478bd9Sstevel@tonic-gate 
470f329b923SSean Wilcox static void
lxml_validate_element(xmlNodePtr n)471f329b923SSean Wilcox lxml_validate_element(xmlNodePtr n)
472f329b923SSean Wilcox {
473f329b923SSean Wilcox 	xmlValidCtxtPtr	vcp;
474f329b923SSean Wilcox 
475f329b923SSean Wilcox 	if (n->doc == NULL)
476f329b923SSean Wilcox 		uu_die(gettext("Could not validate element\n"));
477f329b923SSean Wilcox 
478f329b923SSean Wilcox 	if (n->doc->extSubset == NULL) {
479f329b923SSean Wilcox 		xmlDtdPtr dtd;
480f329b923SSean Wilcox 		dtd = xmlParseDTD(NULL, n->doc->intSubset->SystemID);
481f329b923SSean Wilcox 
482f329b923SSean Wilcox 		if (dtd == NULL) {
483f329b923SSean Wilcox 			uu_die(gettext("Could not parse DTD \"%s\".\n"),
484f329b923SSean Wilcox 			    n->doc->intSubset->SystemID);
485f329b923SSean Wilcox 		}
486f329b923SSean Wilcox 
487f329b923SSean Wilcox 		n->doc->extSubset = dtd;
488f329b923SSean Wilcox 	}
489f329b923SSean Wilcox 
490f329b923SSean Wilcox 	vcp = xmlNewValidCtxt();
491f329b923SSean Wilcox 	if (vcp == NULL)
492f329b923SSean Wilcox 		uu_die(gettext("could not allocate memory"));
493f329b923SSean Wilcox 
494f329b923SSean Wilcox 	vcp->warning = xmlParserValidityWarning;
495f329b923SSean Wilcox 	vcp->error = xmlParserValidityError;
496f329b923SSean Wilcox 
497f329b923SSean Wilcox 	if (xmlValidateElement(vcp, n->doc, n) == 0)
498f329b923SSean Wilcox 		uu_die(gettext("Document is not valid.\n"));
499f329b923SSean Wilcox 
500f329b923SSean Wilcox 	xmlFreeValidCtxt(vcp);
501f329b923SSean Wilcox }
502f329b923SSean Wilcox 
5037c478bd9Sstevel@tonic-gate static int
lxml_validate_string_value(scf_type_t type,const char * v)5047c478bd9Sstevel@tonic-gate lxml_validate_string_value(scf_type_t type, const char *v)
5057c478bd9Sstevel@tonic-gate {
5067c478bd9Sstevel@tonic-gate 	static scf_value_t *scf_value = NULL;
5077c478bd9Sstevel@tonic-gate 	static scf_handle_t *scf_hndl = NULL;
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate 	if (scf_hndl == NULL && (scf_hndl = scf_handle_create(SCF_VERSION)) ==
5107c478bd9Sstevel@tonic-gate 	    NULL)
5117c478bd9Sstevel@tonic-gate 		return (-1);
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate 	if (scf_value == NULL && (scf_value = scf_value_create(scf_hndl)) ==
5147c478bd9Sstevel@tonic-gate 	    NULL)
5157c478bd9Sstevel@tonic-gate 		return (-1);
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate 	return (scf_value_set_from_string(scf_value, type, v));
5187c478bd9Sstevel@tonic-gate }
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate static void
lxml_free_str(value_t * val)5217c478bd9Sstevel@tonic-gate lxml_free_str(value_t *val)
5227c478bd9Sstevel@tonic-gate {
5237c478bd9Sstevel@tonic-gate 	free(val->sc_u.sc_string);
5247c478bd9Sstevel@tonic-gate }
5257c478bd9Sstevel@tonic-gate 
526f329b923SSean Wilcox /*
527f329b923SSean Wilcox  * Take a value_t structure and a type and value.  Based on the type
528f329b923SSean Wilcox  * ensure that the value is of that type.  If so store the value in
529f329b923SSean Wilcox  * the correct location of the value_t structure.
530f329b923SSean Wilcox  *
531f329b923SSean Wilcox  * If the value is NULL, the value_t structure will have been created
532f329b923SSean Wilcox  * and the value would have ultimately been stored as a string value
533f329b923SSean Wilcox  * but at the time the type was unknown.  Now the type should be known
534f329b923SSean Wilcox  * so take the type and value from value_t and validate and store
535f329b923SSean Wilcox  * the value correctly if the value is of the stated type.
536f329b923SSean Wilcox  */
537f329b923SSean Wilcox void
lxml_store_value(value_t * v,element_t type,const xmlChar * value)538f329b923SSean Wilcox lxml_store_value(value_t *v, element_t type, const xmlChar *value)
5397c478bd9Sstevel@tonic-gate {
5407c478bd9Sstevel@tonic-gate 	char *endptr;
541f329b923SSean Wilcox 	int fov = 0;
5427c478bd9Sstevel@tonic-gate 	scf_type_t scf_type = SCF_TYPE_INVALID;
5437c478bd9Sstevel@tonic-gate 
544f329b923SSean Wilcox 	if (value == NULL) {
545f329b923SSean Wilcox 		type = lxml_type_to_element(v->sc_type);
546f329b923SSean Wilcox 		value = (const xmlChar *)v->sc_u.sc_string;
547f329b923SSean Wilcox 		fov = 1;
548f329b923SSean Wilcox 	}
5497c478bd9Sstevel@tonic-gate 
5507c478bd9Sstevel@tonic-gate 	switch (type) {
5517c478bd9Sstevel@tonic-gate 	case SC_COUNT:
5527c478bd9Sstevel@tonic-gate 		/*
5537c478bd9Sstevel@tonic-gate 		 * Although an SC_COUNT represents a uint64_t the use
5547c478bd9Sstevel@tonic-gate 		 * of a negative value is acceptable due to the usage
555bbf21555SRichard Lowe 		 * established by inetd(8).
5567c478bd9Sstevel@tonic-gate 		 */
5577c478bd9Sstevel@tonic-gate 		errno = 0;
5587c478bd9Sstevel@tonic-gate 		v->sc_u.sc_count = strtoull((char *)value, &endptr, 10);
5597c478bd9Sstevel@tonic-gate 		if (errno != 0 || endptr == (char *)value || *endptr)
5607c478bd9Sstevel@tonic-gate 			uu_die(gettext("illegal value \"%s\" for "
5617c478bd9Sstevel@tonic-gate 			    "%s (%s)\n"), (char *)value,
5627c478bd9Sstevel@tonic-gate 			    lxml_prop_types[type],
5637c478bd9Sstevel@tonic-gate 			    (errno) ? strerror(errno) :
5647c478bd9Sstevel@tonic-gate 			    gettext("Illegal character"));
5657c478bd9Sstevel@tonic-gate 		break;
5667c478bd9Sstevel@tonic-gate 	case SC_INTEGER:
5677c478bd9Sstevel@tonic-gate 		errno = 0;
5687c478bd9Sstevel@tonic-gate 		v->sc_u.sc_integer = strtoll((char *)value, &endptr, 10);
5697c478bd9Sstevel@tonic-gate 		if (errno != 0 || *endptr)
5707c478bd9Sstevel@tonic-gate 			uu_die(gettext("illegal value \"%s\" for "
5717c478bd9Sstevel@tonic-gate 			    "%s (%s)\n"), (char *)value,
5727c478bd9Sstevel@tonic-gate 			    lxml_prop_types[type],
5737c478bd9Sstevel@tonic-gate 			    (errno) ? strerror(errno) : "Illegal character");
5747c478bd9Sstevel@tonic-gate 		break;
5757c478bd9Sstevel@tonic-gate 	case SC_OPAQUE:
5767c478bd9Sstevel@tonic-gate 	case SC_HOST:
5777c478bd9Sstevel@tonic-gate 	case SC_HOSTNAME:
578f6f041a2SAntonello Cruz 	case SC_NET_ADDR:
5797c478bd9Sstevel@tonic-gate 	case SC_NET_ADDR_V4:
5807c478bd9Sstevel@tonic-gate 	case SC_NET_ADDR_V6:
5817c478bd9Sstevel@tonic-gate 	case SC_FMRI:
5827c478bd9Sstevel@tonic-gate 	case SC_URI:
5837c478bd9Sstevel@tonic-gate 	case SC_TIME:
5847c478bd9Sstevel@tonic-gate 	case SC_ASTRING:
5857c478bd9Sstevel@tonic-gate 	case SC_USTRING:
586f329b923SSean Wilcox 		scf_type = lxml_element_to_type(type);
5877c478bd9Sstevel@tonic-gate 
58867b0e063SAlbert Lee 		v->sc_u.sc_string = safe_strdup((const char *)value);
5897c478bd9Sstevel@tonic-gate 		if (lxml_validate_string_value(scf_type,
5907c478bd9Sstevel@tonic-gate 		    v->sc_u.sc_string) != 0)
5917c478bd9Sstevel@tonic-gate 			uu_die(gettext("illegal value \"%s\" for "
5927c478bd9Sstevel@tonic-gate 			    "%s (%s)\n"), (char *)value,
5937c478bd9Sstevel@tonic-gate 			    lxml_prop_types[type],
5947c478bd9Sstevel@tonic-gate 			    (scf_error()) ? scf_strerror(scf_error()) :
5957c478bd9Sstevel@tonic-gate 			    gettext("Illegal format"));
5967c478bd9Sstevel@tonic-gate 		v->sc_free = lxml_free_str;
5977c478bd9Sstevel@tonic-gate 		break;
5987c478bd9Sstevel@tonic-gate 	case SC_BOOLEAN:
5997c478bd9Sstevel@tonic-gate 		v->sc_u.sc_count = lxml_xlate_boolean(value);
6007c478bd9Sstevel@tonic-gate 		break;
6017c478bd9Sstevel@tonic-gate 	default:
6027c478bd9Sstevel@tonic-gate 		uu_die(gettext("unknown value type (%d)\n"), type);
6037c478bd9Sstevel@tonic-gate 		break;
6047c478bd9Sstevel@tonic-gate 	}
6057c478bd9Sstevel@tonic-gate 
606f329b923SSean Wilcox 	/* Free the old value */
607f329b923SSean Wilcox 	if (fov && v->sc_free != NULL)
608f329b923SSean Wilcox 		free((char *)value);
609f329b923SSean Wilcox }
610f329b923SSean Wilcox 
611f329b923SSean Wilcox static value_t *
lxml_make_value(element_t type,const xmlChar * value)612f329b923SSean Wilcox lxml_make_value(element_t type, const xmlChar *value)
613f329b923SSean Wilcox {
614f329b923SSean Wilcox 	value_t *v;
615f329b923SSean Wilcox 
616f329b923SSean Wilcox 	v = internal_value_new();
617f329b923SSean Wilcox 
618f329b923SSean Wilcox 	v->sc_type = lxml_element_to_type(type);
619f329b923SSean Wilcox 
620f329b923SSean Wilcox 	lxml_store_value(v, type, value);
621f329b923SSean Wilcox 
6227c478bd9Sstevel@tonic-gate 	return (v);
6237c478bd9Sstevel@tonic-gate }
6247c478bd9Sstevel@tonic-gate 
6257c478bd9Sstevel@tonic-gate static int
lxml_get_value(property_t * prop,element_t vtype,xmlNodePtr value)6267c478bd9Sstevel@tonic-gate lxml_get_value(property_t *prop, element_t vtype, xmlNodePtr value)
6277c478bd9Sstevel@tonic-gate {
6287c478bd9Sstevel@tonic-gate 	xmlNodePtr cursor;
6297c478bd9Sstevel@tonic-gate 
6307c478bd9Sstevel@tonic-gate 	for (cursor = value->xmlChildrenNode; cursor != NULL;
6317c478bd9Sstevel@tonic-gate 	    cursor = cursor->next) {
6327c478bd9Sstevel@tonic-gate 		xmlChar *assigned_value;
6337c478bd9Sstevel@tonic-gate 		value_t *v;
6347c478bd9Sstevel@tonic-gate 
6357c478bd9Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
6367c478bd9Sstevel@tonic-gate 			continue;
6377c478bd9Sstevel@tonic-gate 
6387c478bd9Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
6397c478bd9Sstevel@tonic-gate 		case SC_VALUE_NODE:
6407c478bd9Sstevel@tonic-gate 			if ((assigned_value = xmlGetProp(cursor,
6417c478bd9Sstevel@tonic-gate 			    (xmlChar *)value_attr)) == NULL)
6427c478bd9Sstevel@tonic-gate 				uu_die(gettext("no value on value node?\n"));
6437c478bd9Sstevel@tonic-gate 			break;
6447c478bd9Sstevel@tonic-gate 		default:
6457c478bd9Sstevel@tonic-gate 			uu_die(gettext("value list contains illegal element "
6467c478bd9Sstevel@tonic-gate 			    "\'%s\'\n"), cursor->name);
6477c478bd9Sstevel@tonic-gate 			break;
6487c478bd9Sstevel@tonic-gate 		}
6497c478bd9Sstevel@tonic-gate 
6507c478bd9Sstevel@tonic-gate 		v = lxml_make_value(vtype, assigned_value);
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate 		xmlFree(assigned_value);
6537c478bd9Sstevel@tonic-gate 
6547c478bd9Sstevel@tonic-gate 		internal_attach_value(prop, v);
6557c478bd9Sstevel@tonic-gate 	}
6567c478bd9Sstevel@tonic-gate 
6577c478bd9Sstevel@tonic-gate 	return (0);
6587c478bd9Sstevel@tonic-gate }
6597c478bd9Sstevel@tonic-gate 
6607c478bd9Sstevel@tonic-gate static int
lxml_get_propval(pgroup_t * pgrp,xmlNodePtr propval)6617c478bd9Sstevel@tonic-gate lxml_get_propval(pgroup_t *pgrp, xmlNodePtr propval)
6627c478bd9Sstevel@tonic-gate {
6637c478bd9Sstevel@tonic-gate 	property_t *p;
6647c478bd9Sstevel@tonic-gate 	element_t r;
6657c478bd9Sstevel@tonic-gate 	value_t *v;
6667c478bd9Sstevel@tonic-gate 	xmlChar *type, *val, *override;
667f329b923SSean Wilcox 	int op = pgrp->sc_parent->sc_op;
6687c478bd9Sstevel@tonic-gate 
6697c478bd9Sstevel@tonic-gate 	p = internal_property_new();
6707c478bd9Sstevel@tonic-gate 
6717c478bd9Sstevel@tonic-gate 	p->sc_property_name = (char *)xmlGetProp(propval, (xmlChar *)name_attr);
6721f6eb021SLiane Praza 	if ((p->sc_property_name == NULL) || (*p->sc_property_name == 0))
6737c478bd9Sstevel@tonic-gate 		uu_die(gettext("property name missing in group '%s'\n"),
6747c478bd9Sstevel@tonic-gate 		    pgrp->sc_pgroup_name);
6757c478bd9Sstevel@tonic-gate 
6767c478bd9Sstevel@tonic-gate 	type = xmlGetProp(propval, (xmlChar *)type_attr);
677f329b923SSean Wilcox 	if ((type != NULL) && (*type != 0)) {
678f329b923SSean Wilcox 		for (r = 0;
679f329b923SSean Wilcox 		    r < sizeof (lxml_prop_types) / sizeof (char *); ++r) {
680f329b923SSean Wilcox 			if (xmlStrcmp(type,
681f329b923SSean Wilcox 			    (const xmlChar *)lxml_prop_types[r]) == 0)
682f329b923SSean Wilcox 				break;
683f329b923SSean Wilcox 		}
684f329b923SSean Wilcox 
685f329b923SSean Wilcox 		if (r >= sizeof (lxml_prop_types) / sizeof (char *))
686f329b923SSean Wilcox 			uu_die(gettext("property type invalid for "
687f329b923SSean Wilcox 			    "property '%s/%s'\n"), pgrp->sc_pgroup_name,
688f329b923SSean Wilcox 			    p->sc_property_name);
689f329b923SSean Wilcox 
690f329b923SSean Wilcox 		p->sc_value_type = lxml_element_to_type(r);
691f329b923SSean Wilcox 	} else if (op == SVCCFG_OP_APPLY) {
692f329b923SSean Wilcox 		/*
693f329b923SSean Wilcox 		 * Store the property type as invalid, and the value
694f329b923SSean Wilcox 		 * as an ASTRING and let the bundle apply code validate
695f329b923SSean Wilcox 		 * the type/value once the type is found.
696f329b923SSean Wilcox 		 */
697f329b923SSean Wilcox 		est->sc_miss_type = B_TRUE;
698f329b923SSean Wilcox 		p->sc_value_type = SCF_TYPE_INVALID;
699f329b923SSean Wilcox 		r = SC_ASTRING;
700f329b923SSean Wilcox 	} else {
7017c478bd9Sstevel@tonic-gate 		uu_die(gettext("property type missing for property '%s/%s'\n"),
7027c478bd9Sstevel@tonic-gate 		    pgrp->sc_pgroup_name, p->sc_property_name);
7037c478bd9Sstevel@tonic-gate 	}
7047c478bd9Sstevel@tonic-gate 
7057c478bd9Sstevel@tonic-gate 	val = xmlGetProp(propval, (xmlChar *)value_attr);
7067c478bd9Sstevel@tonic-gate 	if (val == NULL)
7077c478bd9Sstevel@tonic-gate 		uu_die(gettext("property value missing for property '%s/%s'\n"),
7087c478bd9Sstevel@tonic-gate 		    pgrp->sc_pgroup_name, p->sc_property_name);
7097c478bd9Sstevel@tonic-gate 
7107c478bd9Sstevel@tonic-gate 	v = lxml_make_value(r, val);
7111f6eb021SLiane Praza 	xmlFree(val);
7127c478bd9Sstevel@tonic-gate 	internal_attach_value(p, v);
7137c478bd9Sstevel@tonic-gate 
714f329b923SSean Wilcox 	xmlFree(type);
715f329b923SSean Wilcox 
7167c478bd9Sstevel@tonic-gate 	override = xmlGetProp(propval, (xmlChar *)override_attr);
7177c478bd9Sstevel@tonic-gate 	p->sc_property_override = (xmlStrcmp(override, (xmlChar *)true) == 0);
7187c478bd9Sstevel@tonic-gate 	xmlFree(override);
7197c478bd9Sstevel@tonic-gate 
7207c478bd9Sstevel@tonic-gate 	return (internal_attach_property(pgrp, p));
7217c478bd9Sstevel@tonic-gate }
7227c478bd9Sstevel@tonic-gate 
7237c478bd9Sstevel@tonic-gate static int
lxml_get_property(pgroup_t * pgrp,xmlNodePtr property)7247c478bd9Sstevel@tonic-gate lxml_get_property(pgroup_t *pgrp, xmlNodePtr property)
7257c478bd9Sstevel@tonic-gate {
7267c478bd9Sstevel@tonic-gate 	property_t *p;
7277c478bd9Sstevel@tonic-gate 	xmlNodePtr cursor;
7287c478bd9Sstevel@tonic-gate 	element_t r;
7297c478bd9Sstevel@tonic-gate 	xmlChar *type, *override;
730f329b923SSean Wilcox 	int op = pgrp->sc_parent->sc_op;
7317c478bd9Sstevel@tonic-gate 
7327c478bd9Sstevel@tonic-gate 	p = internal_property_new();
7337c478bd9Sstevel@tonic-gate 
7341f6eb021SLiane Praza 	if (((p->sc_property_name = (char *)xmlGetProp(property,
7351f6eb021SLiane Praza 	    (xmlChar *)name_attr)) == NULL) || (*p->sc_property_name == 0))
7367c478bd9Sstevel@tonic-gate 		uu_die(gettext("property name missing in group \'%s\'\n"),
7377c478bd9Sstevel@tonic-gate 		    pgrp->sc_pgroup_name);
7387c478bd9Sstevel@tonic-gate 
739f329b923SSean Wilcox 	type = xmlGetProp(property, (xmlChar *)type_attr);
740f329b923SSean Wilcox 	if ((type != NULL) && (*type != 0)) {
741f329b923SSean Wilcox 		for (r = 0;
742f329b923SSean Wilcox 		    r < sizeof (lxml_prop_types) / sizeof (char *); r++) {
743f329b923SSean Wilcox 			if (xmlStrcmp(type,
744f329b923SSean Wilcox 			    (const xmlChar *)lxml_prop_types[r]) == 0)
745f329b923SSean Wilcox 				break;
746f329b923SSean Wilcox 		}
747f329b923SSean Wilcox 
748f329b923SSean Wilcox 		if (r >= sizeof (lxml_prop_types) / sizeof (char *))
749f329b923SSean Wilcox 			uu_die(gettext("property type invalid for "
750f329b923SSean Wilcox 			    "property '%s/%s'\n"), pgrp->sc_pgroup_name,
751f329b923SSean Wilcox 			    p->sc_property_name);
752f329b923SSean Wilcox 
753f329b923SSean Wilcox 		p->sc_value_type = lxml_element_to_type(r);
754f329b923SSean Wilcox 	} else if (op == SVCCFG_OP_APPLY) {
755f329b923SSean Wilcox 		/*
756f329b923SSean Wilcox 		 * Store the property type as invalid, and let the bundle apply
757f329b923SSean Wilcox 		 * code validate the type/value once the type is found.
758f329b923SSean Wilcox 		 */
759f329b923SSean Wilcox 		p->sc_value_type = SCF_TYPE_INVALID;
760f329b923SSean Wilcox 		est->sc_miss_type = B_TRUE;
761f329b923SSean Wilcox 	} else {
7627c478bd9Sstevel@tonic-gate 		uu_die(gettext("property type missing for "
7637c478bd9Sstevel@tonic-gate 		    "property \'%s/%s\'\n"), pgrp->sc_pgroup_name,
7647c478bd9Sstevel@tonic-gate 		    p->sc_property_name);
7651f6eb021SLiane Praza 	}
7667c478bd9Sstevel@tonic-gate 
7677c478bd9Sstevel@tonic-gate 	for (cursor = property->xmlChildrenNode; cursor != NULL;
7687c478bd9Sstevel@tonic-gate 	    cursor = cursor->next) {
7697c478bd9Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
7707c478bd9Sstevel@tonic-gate 			continue;
7717c478bd9Sstevel@tonic-gate 
7727c478bd9Sstevel@tonic-gate 		switch (r = lxml_xlate_element(cursor->name)) {
7737c478bd9Sstevel@tonic-gate 		case SC_ASTRING:
7747c478bd9Sstevel@tonic-gate 		case SC_BOOLEAN:
7757c478bd9Sstevel@tonic-gate 		case SC_COUNT:
7767c478bd9Sstevel@tonic-gate 		case SC_FMRI:
7777c478bd9Sstevel@tonic-gate 		case SC_HOST:
7787c478bd9Sstevel@tonic-gate 		case SC_HOSTNAME:
7797c478bd9Sstevel@tonic-gate 		case SC_INTEGER:
780f6f041a2SAntonello Cruz 		case SC_NET_ADDR:
7817c478bd9Sstevel@tonic-gate 		case SC_NET_ADDR_V4:
7827c478bd9Sstevel@tonic-gate 		case SC_NET_ADDR_V6:
7837c478bd9Sstevel@tonic-gate 		case SC_OPAQUE:
7847c478bd9Sstevel@tonic-gate 		case SC_TIME:
7857c478bd9Sstevel@tonic-gate 		case SC_URI:
7867c478bd9Sstevel@tonic-gate 		case SC_USTRING:
787f329b923SSean Wilcox 			/*
788f329b923SSean Wilcox 			 * If the type is invalid then this is an apply
789f329b923SSean Wilcox 			 * operation and the type can be taken from the
790f329b923SSean Wilcox 			 * value list.
791f329b923SSean Wilcox 			 */
792f329b923SSean Wilcox 			if (p->sc_value_type == SCF_TYPE_INVALID) {
793f329b923SSean Wilcox 				p->sc_value_type = lxml_element_to_type(r);
794f329b923SSean Wilcox 				type = xmlStrdup((const
795f329b923SSean Wilcox 				    xmlChar *)lxml_prop_types[r]);
796f329b923SSean Wilcox 
797f329b923SSean Wilcox 			} else if (strcmp(lxml_prop_types[r],
798f329b923SSean Wilcox 			    (const char *)type) != 0) {
7997c478bd9Sstevel@tonic-gate 				uu_die(gettext("property \'%s\' "
8007c478bd9Sstevel@tonic-gate 				    "type-to-list mismatch\n"),
8017c478bd9Sstevel@tonic-gate 				    p->sc_property_name);
802f329b923SSean Wilcox 			}
8037c478bd9Sstevel@tonic-gate 
8047c478bd9Sstevel@tonic-gate 			(void) lxml_get_value(p, r, cursor);
8057c478bd9Sstevel@tonic-gate 			break;
8067c478bd9Sstevel@tonic-gate 		default:
8077c478bd9Sstevel@tonic-gate 			uu_die(gettext("unknown value list type: %s\n"),
8087c478bd9Sstevel@tonic-gate 			    cursor->name);
8097c478bd9Sstevel@tonic-gate 			break;
8107c478bd9Sstevel@tonic-gate 		}
8117c478bd9Sstevel@tonic-gate 	}
8127c478bd9Sstevel@tonic-gate 
8137c478bd9Sstevel@tonic-gate 	xmlFree(type);
8147c478bd9Sstevel@tonic-gate 
8157c478bd9Sstevel@tonic-gate 	override = xmlGetProp(property, (xmlChar *)override_attr);
8167c478bd9Sstevel@tonic-gate 	p->sc_property_override = (xmlStrcmp(override, (xmlChar *)true) == 0);
8177c478bd9Sstevel@tonic-gate 	xmlFree(override);
8187c478bd9Sstevel@tonic-gate 
8197c478bd9Sstevel@tonic-gate 	return (internal_attach_property(pgrp, p));
8207c478bd9Sstevel@tonic-gate }
8217c478bd9Sstevel@tonic-gate 
8227c478bd9Sstevel@tonic-gate static int
lxml_get_pgroup_stability(pgroup_t * pgrp,xmlNodePtr stab)8237c478bd9Sstevel@tonic-gate lxml_get_pgroup_stability(pgroup_t *pgrp, xmlNodePtr stab)
8247c478bd9Sstevel@tonic-gate {
825f329b923SSean Wilcox 	if (pgrp->sc_parent->sc_op == SVCCFG_OP_APPLY)
826f329b923SSean Wilcox 		lxml_validate_element(stab);
827f329b923SSean Wilcox 
8287c478bd9Sstevel@tonic-gate 	return (new_str_prop_from_attr(pgrp, SCF_PROPERTY_STABILITY,
8297c478bd9Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, stab, value_attr));
8307c478bd9Sstevel@tonic-gate }
8317c478bd9Sstevel@tonic-gate 
8327c478bd9Sstevel@tonic-gate /*
8337c478bd9Sstevel@tonic-gate  * Property groups can go on any of a service, an instance, or a template.
8347c478bd9Sstevel@tonic-gate  */
8357c478bd9Sstevel@tonic-gate static int
lxml_get_pgroup(entity_t * entity,xmlNodePtr pgroup)8367c478bd9Sstevel@tonic-gate lxml_get_pgroup(entity_t *entity, xmlNodePtr pgroup)
8377c478bd9Sstevel@tonic-gate {
8387c478bd9Sstevel@tonic-gate 	pgroup_t *pg;
8397c478bd9Sstevel@tonic-gate 	xmlNodePtr cursor;
8407c478bd9Sstevel@tonic-gate 	xmlChar *name, *type, *delete;
8417c478bd9Sstevel@tonic-gate 
8427c478bd9Sstevel@tonic-gate 	/*
8437c478bd9Sstevel@tonic-gate 	 * property group attributes:
8447c478bd9Sstevel@tonic-gate 	 * name: string
8457c478bd9Sstevel@tonic-gate 	 * type: string | framework | application
8467c478bd9Sstevel@tonic-gate 	 */
8477c478bd9Sstevel@tonic-gate 	name = xmlGetProp(pgroup, (xmlChar *)name_attr);
8487c478bd9Sstevel@tonic-gate 	type = xmlGetProp(pgroup, (xmlChar *)type_attr);
8497c478bd9Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(entity, (char *)name, (char *)type);
8507c478bd9Sstevel@tonic-gate 	xmlFree(name);
8517c478bd9Sstevel@tonic-gate 	xmlFree(type);
8527c478bd9Sstevel@tonic-gate 
8537c478bd9Sstevel@tonic-gate 	/*
8547c478bd9Sstevel@tonic-gate 	 * Walk the children of this lxml_elements, which are a stability
8557c478bd9Sstevel@tonic-gate 	 * element, property elements, or propval elements.
8567c478bd9Sstevel@tonic-gate 	 */
8577c478bd9Sstevel@tonic-gate 	for (cursor = pgroup->xmlChildrenNode; cursor != NULL;
8587c478bd9Sstevel@tonic-gate 	    cursor = cursor->next) {
8597c478bd9Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
8607c478bd9Sstevel@tonic-gate 			continue;
8617c478bd9Sstevel@tonic-gate 
8627c478bd9Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
8637c478bd9Sstevel@tonic-gate 		case SC_STABILITY:
8647c478bd9Sstevel@tonic-gate 			(void) lxml_get_pgroup_stability(pg, cursor);
8657c478bd9Sstevel@tonic-gate 			break;
8667c478bd9Sstevel@tonic-gate 		case SC_PROPERTY:
8677c478bd9Sstevel@tonic-gate 			(void) lxml_get_property(pg, cursor);
8687c478bd9Sstevel@tonic-gate 			break;
8697c478bd9Sstevel@tonic-gate 		case SC_PROPVAL:
8707c478bd9Sstevel@tonic-gate 			(void) lxml_get_propval(pg, cursor);
8717c478bd9Sstevel@tonic-gate 			break;
8727c478bd9Sstevel@tonic-gate 		default:
8737c478bd9Sstevel@tonic-gate 			abort();
8747c478bd9Sstevel@tonic-gate 			break;
8757c478bd9Sstevel@tonic-gate 		}
8767c478bd9Sstevel@tonic-gate 	}
8777c478bd9Sstevel@tonic-gate 
8787c478bd9Sstevel@tonic-gate 	delete = xmlGetProp(pgroup, (xmlChar *)delete_attr);
8797c478bd9Sstevel@tonic-gate 	pg->sc_pgroup_delete = (xmlStrcmp(delete, (xmlChar *)true) == 0);
8807c478bd9Sstevel@tonic-gate 	xmlFree(delete);
8817c478bd9Sstevel@tonic-gate 
8827c478bd9Sstevel@tonic-gate 	return (0);
8837c478bd9Sstevel@tonic-gate }
8847c478bd9Sstevel@tonic-gate 
8857c478bd9Sstevel@tonic-gate 
8867c478bd9Sstevel@tonic-gate /*
8877c478bd9Sstevel@tonic-gate  * Dependency groups, execution methods can go on either a service or an
8887c478bd9Sstevel@tonic-gate  * instance.
8897c478bd9Sstevel@tonic-gate  */
8907c478bd9Sstevel@tonic-gate 
8917c478bd9Sstevel@tonic-gate static int
lxml_get_method_profile(pgroup_t * pg,xmlNodePtr profile)8927c478bd9Sstevel@tonic-gate lxml_get_method_profile(pgroup_t *pg, xmlNodePtr profile)
8937c478bd9Sstevel@tonic-gate {
8947c478bd9Sstevel@tonic-gate 	property_t *p;
8957c478bd9Sstevel@tonic-gate 
8967c478bd9Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_USE_PROFILE, SCF_TYPE_BOOLEAN,
8977c478bd9Sstevel@tonic-gate 	    1, (uint64_t)1);
8987c478bd9Sstevel@tonic-gate 	if (internal_attach_property(pg, p) != 0)
8997c478bd9Sstevel@tonic-gate 		return (-1);
9007c478bd9Sstevel@tonic-gate 
9017c478bd9Sstevel@tonic-gate 	return (new_str_prop_from_attr(pg, SCF_PROPERTY_PROFILE,
9027c478bd9Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, profile, name_attr));
9037c478bd9Sstevel@tonic-gate }
9047c478bd9Sstevel@tonic-gate 
9057c478bd9Sstevel@tonic-gate static int
lxml_get_method_credential(pgroup_t * pg,xmlNodePtr cred)9067c478bd9Sstevel@tonic-gate lxml_get_method_credential(pgroup_t *pg, xmlNodePtr cred)
9077c478bd9Sstevel@tonic-gate {
9087c478bd9Sstevel@tonic-gate 	property_t *p;
9097c478bd9Sstevel@tonic-gate 
9107c478bd9Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_USE_PROFILE, SCF_TYPE_BOOLEAN,
9117c478bd9Sstevel@tonic-gate 	    1, (uint64_t)0);
9127c478bd9Sstevel@tonic-gate 	if (internal_attach_property(pg, p) != 0)
9137c478bd9Sstevel@tonic-gate 		return (-1);
9147c478bd9Sstevel@tonic-gate 
91513d8aaa1SSean Wilcox 	if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_USER, SCF_TYPE_ASTRING,
91613d8aaa1SSean Wilcox 	    cred, "user", NULL) != 0)
9177c478bd9Sstevel@tonic-gate 		return (-1);
9187c478bd9Sstevel@tonic-gate 
91913d8aaa1SSean Wilcox 	if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_GROUP, SCF_TYPE_ASTRING,
92013d8aaa1SSean Wilcox 	    cred, "group", NULL) != 0)
9217c478bd9Sstevel@tonic-gate 		return (-1);
9227c478bd9Sstevel@tonic-gate 
92313d8aaa1SSean Wilcox 	if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_SUPP_GROUPS,
92413d8aaa1SSean Wilcox 	    SCF_TYPE_ASTRING, cred, "supp_groups", NULL) != 0)
9257c478bd9Sstevel@tonic-gate 		return (-1);
9267c478bd9Sstevel@tonic-gate 
92713d8aaa1SSean Wilcox 	if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_PRIVILEGES,
92813d8aaa1SSean Wilcox 	    SCF_TYPE_ASTRING, cred, "privileges", NULL) != 0)
9297c478bd9Sstevel@tonic-gate 		return (-1);
9307c478bd9Sstevel@tonic-gate 
93113d8aaa1SSean Wilcox 	if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_LIMIT_PRIVILEGES,
93213d8aaa1SSean Wilcox 	    SCF_TYPE_ASTRING, cred, "limit_privileges", NULL) != 0)
9337c478bd9Sstevel@tonic-gate 		return (-1);
9347c478bd9Sstevel@tonic-gate 
9357c478bd9Sstevel@tonic-gate 	return (0);
9367c478bd9Sstevel@tonic-gate }
9377c478bd9Sstevel@tonic-gate 
9387c478bd9Sstevel@tonic-gate static char *
lxml_get_envvar(xmlNodePtr envvar)9397c478bd9Sstevel@tonic-gate lxml_get_envvar(xmlNodePtr envvar)
9407c478bd9Sstevel@tonic-gate {
9417c478bd9Sstevel@tonic-gate 	char *name;
9427c478bd9Sstevel@tonic-gate 	char *value;
9437c478bd9Sstevel@tonic-gate 	char *ret;
9447c478bd9Sstevel@tonic-gate 
9451f6eb021SLiane Praza 	name = (char *)xmlGetProp(envvar, (xmlChar *)name_attr);
9461f6eb021SLiane Praza 	value = (char *)xmlGetProp(envvar, (xmlChar *)value_attr);
9477c478bd9Sstevel@tonic-gate 
9487c478bd9Sstevel@tonic-gate 	if (strlen(name) == 0 || strchr(name, '=') != NULL)
9497c478bd9Sstevel@tonic-gate 		uu_die(gettext("Invalid environment variable "
9507c478bd9Sstevel@tonic-gate 		    "\"%s\".\n"), name);
9517c478bd9Sstevel@tonic-gate 	if (strstr(name, "SMF_") == name)
9527c478bd9Sstevel@tonic-gate 		uu_die(gettext("Invalid environment variable "
9537c478bd9Sstevel@tonic-gate 		    "\"%s\"; \"SMF_\" prefix is reserved.\n"), name);
9547c478bd9Sstevel@tonic-gate 
9557c478bd9Sstevel@tonic-gate 	ret = uu_msprintf("%s=%s", name, value);
9567c478bd9Sstevel@tonic-gate 	xmlFree(name);
9577c478bd9Sstevel@tonic-gate 	xmlFree(value);
9587c478bd9Sstevel@tonic-gate 	return (ret);
9597c478bd9Sstevel@tonic-gate }
9607c478bd9Sstevel@tonic-gate 
9617c478bd9Sstevel@tonic-gate static int
lxml_get_method_environment(pgroup_t * pg,xmlNodePtr environment)9627c478bd9Sstevel@tonic-gate lxml_get_method_environment(pgroup_t *pg, xmlNodePtr environment)
9637c478bd9Sstevel@tonic-gate {
9647c478bd9Sstevel@tonic-gate 	property_t *p;
9657c478bd9Sstevel@tonic-gate 	xmlNodePtr cursor;
9667c478bd9Sstevel@tonic-gate 	value_t *val;
9677c478bd9Sstevel@tonic-gate 
9687c478bd9Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_ENVIRONMENT,
9697c478bd9Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, 0);
9707c478bd9Sstevel@tonic-gate 
9717c478bd9Sstevel@tonic-gate 	for (cursor = environment->xmlChildrenNode; cursor != NULL;
9727c478bd9Sstevel@tonic-gate 	    cursor = cursor->next) {
9737c478bd9Sstevel@tonic-gate 		char *tmp;
9747c478bd9Sstevel@tonic-gate 
9757c478bd9Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
9767c478bd9Sstevel@tonic-gate 			continue;
9777c478bd9Sstevel@tonic-gate 
9787c478bd9Sstevel@tonic-gate 		if (lxml_xlate_element(cursor->name) != SC_METHOD_ENVVAR)
9797c478bd9Sstevel@tonic-gate 			uu_die(gettext("illegal element \"%s\" on "
9807c478bd9Sstevel@tonic-gate 			    "method environment for \"%s\"\n"),
9817c478bd9Sstevel@tonic-gate 			    cursor->name, pg->sc_pgroup_name);
9827c478bd9Sstevel@tonic-gate 
9837c478bd9Sstevel@tonic-gate 		if ((tmp = lxml_get_envvar(cursor)) == NULL)
9847c478bd9Sstevel@tonic-gate 			uu_die(gettext("Out of memory\n"));
9857c478bd9Sstevel@tonic-gate 
9867c478bd9Sstevel@tonic-gate 		val = internal_value_new();
9877c478bd9Sstevel@tonic-gate 		val->sc_u.sc_string = tmp;
9887c478bd9Sstevel@tonic-gate 		val->sc_type = SCF_TYPE_ASTRING;
9897c478bd9Sstevel@tonic-gate 		val->sc_free = lxml_free_str;
9907c478bd9Sstevel@tonic-gate 		internal_attach_value(p, val);
9917c478bd9Sstevel@tonic-gate 	}
9927c478bd9Sstevel@tonic-gate 
9937c478bd9Sstevel@tonic-gate 	if (internal_attach_property(pg, p) != 0) {
9947c478bd9Sstevel@tonic-gate 		internal_property_free(p);
9957c478bd9Sstevel@tonic-gate 		return (-1);
9967c478bd9Sstevel@tonic-gate 	}
9977c478bd9Sstevel@tonic-gate 
9987c478bd9Sstevel@tonic-gate 	return (0);
9997c478bd9Sstevel@tonic-gate }
10007c478bd9Sstevel@tonic-gate 
10017c478bd9Sstevel@tonic-gate static int
lxml_get_method_context(pgroup_t * pg,xmlNodePtr ctx)10027c478bd9Sstevel@tonic-gate lxml_get_method_context(pgroup_t *pg, xmlNodePtr ctx)
10037c478bd9Sstevel@tonic-gate {
10047c478bd9Sstevel@tonic-gate 	xmlNodePtr cursor;
10057c478bd9Sstevel@tonic-gate 
100613d8aaa1SSean Wilcox 	if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_WORKING_DIRECTORY,
100713d8aaa1SSean Wilcox 	    SCF_TYPE_ASTRING, ctx, "working_directory", NULL) != 0)
10087c478bd9Sstevel@tonic-gate 		return (-1);
10097c478bd9Sstevel@tonic-gate 
101013d8aaa1SSean Wilcox 	if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_PROJECT,
101113d8aaa1SSean Wilcox 	    SCF_TYPE_ASTRING, ctx, "project", NULL) != 0)
10127c478bd9Sstevel@tonic-gate 		return (-1);
10137c478bd9Sstevel@tonic-gate 
101413d8aaa1SSean Wilcox 	if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_RESOURCE_POOL,
101513d8aaa1SSean Wilcox 	    SCF_TYPE_ASTRING, ctx, "resource_pool", NULL) != 0)
10167c478bd9Sstevel@tonic-gate 		return (-1);
10177c478bd9Sstevel@tonic-gate 
1018d2a70789SRichard Lowe 	if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_SECFLAGS,
1019d2a70789SRichard Lowe 	    SCF_TYPE_ASTRING, ctx, "security_flags", NULL) != 0)
1020d2a70789SRichard Lowe 		return (-1);
1021d2a70789SRichard Lowe 
10227c478bd9Sstevel@tonic-gate 	for (cursor = ctx->xmlChildrenNode; cursor != NULL;
10237c478bd9Sstevel@tonic-gate 	    cursor = cursor->next) {
10247c478bd9Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
10257c478bd9Sstevel@tonic-gate 			continue;
10267c478bd9Sstevel@tonic-gate 
10277c478bd9Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
10287c478bd9Sstevel@tonic-gate 		case SC_METHOD_CREDENTIAL:
10297c478bd9Sstevel@tonic-gate 			(void) lxml_get_method_credential(pg, cursor);
10307c478bd9Sstevel@tonic-gate 			break;
10317c478bd9Sstevel@tonic-gate 		case SC_METHOD_PROFILE:
10327c478bd9Sstevel@tonic-gate 			(void) lxml_get_method_profile(pg, cursor);
10337c478bd9Sstevel@tonic-gate 			break;
10347c478bd9Sstevel@tonic-gate 		case SC_METHOD_ENVIRONMENT:
10357c478bd9Sstevel@tonic-gate 			(void) lxml_get_method_environment(pg, cursor);
10367c478bd9Sstevel@tonic-gate 			break;
10377c478bd9Sstevel@tonic-gate 		default:
10387c478bd9Sstevel@tonic-gate 			semerr(gettext("illegal element \'%s\' in method "
10397c478bd9Sstevel@tonic-gate 			    "context\n"), (char *)cursor);
10407c478bd9Sstevel@tonic-gate 			break;
10417c478bd9Sstevel@tonic-gate 		}
10427c478bd9Sstevel@tonic-gate 	}
10437c478bd9Sstevel@tonic-gate 
10447c478bd9Sstevel@tonic-gate 	return (0);
10457c478bd9Sstevel@tonic-gate }
10467c478bd9Sstevel@tonic-gate 
10477c478bd9Sstevel@tonic-gate static int
lxml_get_entity_method_context(entity_t * entity,xmlNodePtr ctx)10487c478bd9Sstevel@tonic-gate lxml_get_entity_method_context(entity_t *entity, xmlNodePtr ctx)
10497c478bd9Sstevel@tonic-gate {
10507c478bd9Sstevel@tonic-gate 	pgroup_t *pg;
10517c478bd9Sstevel@tonic-gate 
10527c478bd9Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(entity, SCF_PG_METHOD_CONTEXT,
10537c478bd9Sstevel@tonic-gate 	    (char *)scf_group_framework);
10547c478bd9Sstevel@tonic-gate 
10557c478bd9Sstevel@tonic-gate 	return (lxml_get_method_context(pg, ctx));
10567c478bd9Sstevel@tonic-gate }
10577c478bd9Sstevel@tonic-gate 
10587c478bd9Sstevel@tonic-gate static int
lxml_get_exec_method(entity_t * entity,xmlNodePtr emeth)10597c478bd9Sstevel@tonic-gate lxml_get_exec_method(entity_t *entity, xmlNodePtr emeth)
10607c478bd9Sstevel@tonic-gate {
10617c478bd9Sstevel@tonic-gate 	pgroup_t *pg;
10627c478bd9Sstevel@tonic-gate 	property_t *p;
10637c478bd9Sstevel@tonic-gate 	xmlChar *name, *timeout, *delete;
10647c478bd9Sstevel@tonic-gate 	xmlNodePtr cursor;
10657c478bd9Sstevel@tonic-gate 	int r = 0;
10667c478bd9Sstevel@tonic-gate 
1067f329b923SSean Wilcox 	if (entity->sc_op == SVCCFG_OP_APPLY)
1068f329b923SSean Wilcox 		lxml_validate_element(emeth);
1069f329b923SSean Wilcox 
10707c478bd9Sstevel@tonic-gate 	name = xmlGetProp(emeth, (xmlChar *)name_attr);
10717c478bd9Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(entity, (char *)name,
10727c478bd9Sstevel@tonic-gate 	    (char *)SCF_GROUP_METHOD);
10737c478bd9Sstevel@tonic-gate 	xmlFree(name);
10747c478bd9Sstevel@tonic-gate 
10757c478bd9Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_TYPE, SCF_TYPE_ASTRING,
10767c478bd9Sstevel@tonic-gate 	    emeth, type_attr) != 0 ||
10777c478bd9Sstevel@tonic-gate 	    new_str_prop_from_attr(pg, SCF_PROPERTY_EXEC, SCF_TYPE_ASTRING,
10787c478bd9Sstevel@tonic-gate 	    emeth, "exec") != 0)
10797c478bd9Sstevel@tonic-gate 		return (-1);
10807c478bd9Sstevel@tonic-gate 
10811f6eb021SLiane Praza 	timeout = xmlGetProp(emeth, (xmlChar *)timeout_seconds_attr);
10827c478bd9Sstevel@tonic-gate 	if (timeout != NULL) {
10837c478bd9Sstevel@tonic-gate 		uint64_t u_timeout;
10847c478bd9Sstevel@tonic-gate 		char *endptr;
10857c478bd9Sstevel@tonic-gate 		/*
10867c478bd9Sstevel@tonic-gate 		 * Although an SC_COUNT represents a uint64_t the use
10877c478bd9Sstevel@tonic-gate 		 * of a negative value is acceptable due to the usage
1088bbf21555SRichard Lowe 		 * established by inetd(8).
10897c478bd9Sstevel@tonic-gate 		 */
10907c478bd9Sstevel@tonic-gate 		errno = 0;
10917c478bd9Sstevel@tonic-gate 		u_timeout = strtoull((char *)timeout, &endptr, 10);
10927c478bd9Sstevel@tonic-gate 		if (errno != 0 || endptr == (char *)timeout || *endptr)
10937c478bd9Sstevel@tonic-gate 			uu_die(gettext("illegal value \"%s\" for "
10947c478bd9Sstevel@tonic-gate 			    "timeout_seconds (%s)\n"),
10957c478bd9Sstevel@tonic-gate 			    (char *)timeout, (errno) ? strerror(errno):
10967c478bd9Sstevel@tonic-gate 			    gettext("Illegal character"));
10977c478bd9Sstevel@tonic-gate 		p = internal_property_create(SCF_PROPERTY_TIMEOUT,
10987c478bd9Sstevel@tonic-gate 		    SCF_TYPE_COUNT, 1, u_timeout);
10997c478bd9Sstevel@tonic-gate 		r = internal_attach_property(pg, p);
11007c478bd9Sstevel@tonic-gate 		xmlFree(timeout);
11017c478bd9Sstevel@tonic-gate 	}
11027c478bd9Sstevel@tonic-gate 	if (r != 0)
11037c478bd9Sstevel@tonic-gate 		return (-1);
11047c478bd9Sstevel@tonic-gate 
11057c478bd9Sstevel@tonic-gate 	/*
11067c478bd9Sstevel@tonic-gate 	 * There is a possibility that a method context also exists, in which
11077c478bd9Sstevel@tonic-gate 	 * case the following attributes are defined: project, resource_pool,
1108d2a70789SRichard Lowe 	 * working_directory, profile, user, group, privileges,
1109d2a70789SRichard Lowe 	 * limit_privileges, security_flags
11107c478bd9Sstevel@tonic-gate 	 */
11117c478bd9Sstevel@tonic-gate 	for (cursor = emeth->xmlChildrenNode; cursor != NULL;
11127c478bd9Sstevel@tonic-gate 	    cursor = cursor->next) {
11137c478bd9Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
11147c478bd9Sstevel@tonic-gate 			continue;
11157c478bd9Sstevel@tonic-gate 
11167c478bd9Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
11177c478bd9Sstevel@tonic-gate 		case SC_STABILITY:
11187c478bd9Sstevel@tonic-gate 			if (lxml_get_pgroup_stability(pg, cursor) != 0)
11197c478bd9Sstevel@tonic-gate 				return (-1);
11207c478bd9Sstevel@tonic-gate 			break;
11217c478bd9Sstevel@tonic-gate 
11227c478bd9Sstevel@tonic-gate 		case SC_METHOD_CONTEXT:
11237c478bd9Sstevel@tonic-gate 			(void) lxml_get_method_context(pg, cursor);
11247c478bd9Sstevel@tonic-gate 			break;
11257c478bd9Sstevel@tonic-gate 
11267c478bd9Sstevel@tonic-gate 		case SC_PROPVAL:
11277c478bd9Sstevel@tonic-gate 			(void) lxml_get_propval(pg, cursor);
11287c478bd9Sstevel@tonic-gate 			break;
11297c478bd9Sstevel@tonic-gate 
11307c478bd9Sstevel@tonic-gate 		case SC_PROPERTY:
11317c478bd9Sstevel@tonic-gate 			(void) lxml_get_property(pg, cursor);
11327c478bd9Sstevel@tonic-gate 			break;
11337c478bd9Sstevel@tonic-gate 
11347c478bd9Sstevel@tonic-gate 		default:
11357c478bd9Sstevel@tonic-gate 			uu_die(gettext("illegal element \"%s\" on "
11367c478bd9Sstevel@tonic-gate 			    "execution method \"%s\"\n"), cursor->name,
11377c478bd9Sstevel@tonic-gate 			    pg->sc_pgroup_name);
11387c478bd9Sstevel@tonic-gate 			break;
11397c478bd9Sstevel@tonic-gate 		}
11407c478bd9Sstevel@tonic-gate 	}
11417c478bd9Sstevel@tonic-gate 
11427c478bd9Sstevel@tonic-gate 	delete = xmlGetProp(emeth, (xmlChar *)delete_attr);
11437c478bd9Sstevel@tonic-gate 	pg->sc_pgroup_delete = (xmlStrcmp(delete, (xmlChar *)true) == 0);
11447c478bd9Sstevel@tonic-gate 	xmlFree(delete);
11457c478bd9Sstevel@tonic-gate 
11467c478bd9Sstevel@tonic-gate 	return (0);
11477c478bd9Sstevel@tonic-gate }
11487c478bd9Sstevel@tonic-gate 
11497c478bd9Sstevel@tonic-gate static int
lxml_get_dependency(entity_t * entity,xmlNodePtr dependency)11507c478bd9Sstevel@tonic-gate lxml_get_dependency(entity_t *entity, xmlNodePtr dependency)
11517c478bd9Sstevel@tonic-gate {
11527c478bd9Sstevel@tonic-gate 	pgroup_t *pg;
11537c478bd9Sstevel@tonic-gate 	property_t *p;
11547c478bd9Sstevel@tonic-gate 	xmlNodePtr cursor;
11557c478bd9Sstevel@tonic-gate 	xmlChar *name;
11567c478bd9Sstevel@tonic-gate 	xmlChar *delete;
11577c478bd9Sstevel@tonic-gate 
11587c478bd9Sstevel@tonic-gate 	/*
11597c478bd9Sstevel@tonic-gate 	 * dependency attributes:
11607c478bd9Sstevel@tonic-gate 	 * name: string
11617c478bd9Sstevel@tonic-gate 	 * grouping: require_all | require_any | exclude_all | optional_all
11627c478bd9Sstevel@tonic-gate 	 * reset_on: string (error | restart | refresh | none)
11637c478bd9Sstevel@tonic-gate 	 * type:  service / path /host
11647c478bd9Sstevel@tonic-gate 	 */
11657c478bd9Sstevel@tonic-gate 
1166f329b923SSean Wilcox 	if (entity->sc_op == SVCCFG_OP_APPLY)
1167f329b923SSean Wilcox 		lxml_validate_element(dependency);
1168f329b923SSean Wilcox 
11697c478bd9Sstevel@tonic-gate 	name = xmlGetProp(dependency, (xmlChar *)name_attr);
11707c478bd9Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(entity, (char *)name,
11717c478bd9Sstevel@tonic-gate 	    (char *)SCF_GROUP_DEPENDENCY);
11727c478bd9Sstevel@tonic-gate 	xmlFree(name);
11737c478bd9Sstevel@tonic-gate 
11747c478bd9Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_TYPE, SCF_TYPE_ASTRING,
11757c478bd9Sstevel@tonic-gate 	    dependency, type_attr) != 0)
11767c478bd9Sstevel@tonic-gate 		return (-1);
11777c478bd9Sstevel@tonic-gate 
11787c478bd9Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_RESTART_ON,
11797c478bd9Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, dependency, "restart_on") != 0)
11807c478bd9Sstevel@tonic-gate 		return (-1);
11817c478bd9Sstevel@tonic-gate 
11827c478bd9Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_GROUPING, SCF_TYPE_ASTRING,
11837c478bd9Sstevel@tonic-gate 	    dependency, "grouping") != 0)
11847c478bd9Sstevel@tonic-gate 		return (-1);
11857c478bd9Sstevel@tonic-gate 
11867c478bd9Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_ENTITIES, SCF_TYPE_FMRI, 0);
11877c478bd9Sstevel@tonic-gate 	if (internal_attach_property(pg, p) != 0)
11887c478bd9Sstevel@tonic-gate 		return (-1);
11897c478bd9Sstevel@tonic-gate 
11907c478bd9Sstevel@tonic-gate 	for (cursor = dependency->xmlChildrenNode; cursor != NULL;
11917c478bd9Sstevel@tonic-gate 	    cursor = cursor->next) {
11927c478bd9Sstevel@tonic-gate 		xmlChar *value;
11937c478bd9Sstevel@tonic-gate 		value_t *v;
11947c478bd9Sstevel@tonic-gate 
11957c478bd9Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
11967c478bd9Sstevel@tonic-gate 			continue;
11977c478bd9Sstevel@tonic-gate 
11987c478bd9Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
11997c478bd9Sstevel@tonic-gate 		case SC_STABILITY:
12007c478bd9Sstevel@tonic-gate 			if (lxml_get_pgroup_stability(pg, cursor) != 0)
12017c478bd9Sstevel@tonic-gate 				return (-1);
12027c478bd9Sstevel@tonic-gate 			break;
12037c478bd9Sstevel@tonic-gate 
12047c478bd9Sstevel@tonic-gate 		case SC_SERVICE_FMRI:
12057c478bd9Sstevel@tonic-gate 			value = xmlGetProp(cursor, (xmlChar *)value_attr);
12067c478bd9Sstevel@tonic-gate 			if (value != NULL) {
12077c478bd9Sstevel@tonic-gate 				if (lxml_validate_string_value(SCF_TYPE_FMRI,
12087c478bd9Sstevel@tonic-gate 				    (char *)value) != 0)
12097c478bd9Sstevel@tonic-gate 					uu_die(gettext("illegal value \"%s\" "
12107c478bd9Sstevel@tonic-gate 					    "for %s (%s)\n"), (char *)value,
12117c478bd9Sstevel@tonic-gate 					    lxml_prop_types[SC_FMRI],
12127c478bd9Sstevel@tonic-gate 					    (scf_error()) ?
12137c478bd9Sstevel@tonic-gate 					    scf_strerror(scf_error()) :
12147c478bd9Sstevel@tonic-gate 					    gettext("Illegal format"));
12157c478bd9Sstevel@tonic-gate 				v = internal_value_new();
12167c478bd9Sstevel@tonic-gate 				v->sc_type = SCF_TYPE_FMRI;
12177c478bd9Sstevel@tonic-gate 				v->sc_u.sc_string = (char *)value;
12187c478bd9Sstevel@tonic-gate 				internal_attach_value(p, v);
12197c478bd9Sstevel@tonic-gate 			}
12207c478bd9Sstevel@tonic-gate 
12217c478bd9Sstevel@tonic-gate 			break;
12227c478bd9Sstevel@tonic-gate 
12237c478bd9Sstevel@tonic-gate 		case SC_PROPVAL:
12247c478bd9Sstevel@tonic-gate 			(void) lxml_get_propval(pg, cursor);
12257c478bd9Sstevel@tonic-gate 			break;
12267c478bd9Sstevel@tonic-gate 
12277c478bd9Sstevel@tonic-gate 		case SC_PROPERTY:
12287c478bd9Sstevel@tonic-gate 			(void) lxml_get_property(pg, cursor);
12297c478bd9Sstevel@tonic-gate 			break;
12307c478bd9Sstevel@tonic-gate 
12317c478bd9Sstevel@tonic-gate 		default:
12327c478bd9Sstevel@tonic-gate 			uu_die(gettext("illegal element \"%s\" on "
12337c478bd9Sstevel@tonic-gate 			    "dependency group \"%s\"\n"), cursor->name, name);
12347c478bd9Sstevel@tonic-gate 			break;
12357c478bd9Sstevel@tonic-gate 		}
12367c478bd9Sstevel@tonic-gate 	}
12377c478bd9Sstevel@tonic-gate 
12387c478bd9Sstevel@tonic-gate 	delete = xmlGetProp(dependency, (xmlChar *)delete_attr);
12397c478bd9Sstevel@tonic-gate 	pg->sc_pgroup_delete = (xmlStrcmp(delete, (xmlChar *)true) == 0);
12407c478bd9Sstevel@tonic-gate 	xmlFree(delete);
12417c478bd9Sstevel@tonic-gate 
12427c478bd9Sstevel@tonic-gate 	return (0);
12437c478bd9Sstevel@tonic-gate }
12447c478bd9Sstevel@tonic-gate 
12457c478bd9Sstevel@tonic-gate /*
12467c478bd9Sstevel@tonic-gate  * Dependents are hairy.  They should cause a dependency pg to be created in
12477c478bd9Sstevel@tonic-gate  * another service, but we can't do that here; we'll have to wait until the
12487c478bd9Sstevel@tonic-gate  * import routines.  So for now we'll add the dependency group that should go
12497c478bd9Sstevel@tonic-gate  * in the other service to the entity's dependent list.
12507c478bd9Sstevel@tonic-gate  */
12517c478bd9Sstevel@tonic-gate static int
lxml_get_dependent(entity_t * entity,xmlNodePtr dependent)12527c478bd9Sstevel@tonic-gate lxml_get_dependent(entity_t *entity, xmlNodePtr dependent)
12537c478bd9Sstevel@tonic-gate {
12547c478bd9Sstevel@tonic-gate 	xmlChar *name, *or;
12557c478bd9Sstevel@tonic-gate 	xmlNodePtr sf;
12567c478bd9Sstevel@tonic-gate 	xmlChar *fmri, *delete;
12577c478bd9Sstevel@tonic-gate 	pgroup_t *pg;
12587c478bd9Sstevel@tonic-gate 	property_t *p;
12597c478bd9Sstevel@tonic-gate 	xmlNodePtr n;
12607c478bd9Sstevel@tonic-gate 	char *myfmri;
12617c478bd9Sstevel@tonic-gate 
1262f329b923SSean Wilcox 	if (entity->sc_op == SVCCFG_OP_APPLY)
1263f329b923SSean Wilcox 		lxml_validate_element(dependent);
1264f329b923SSean Wilcox 
12657c478bd9Sstevel@tonic-gate 	name = xmlGetProp(dependent, (xmlChar *)name_attr);
12667c478bd9Sstevel@tonic-gate 
12677c478bd9Sstevel@tonic-gate 	if (internal_pgroup_find(entity, (char *)name, NULL) != NULL) {
12687c478bd9Sstevel@tonic-gate 		semerr(gettext("Property group and dependent of entity %s "
12697c478bd9Sstevel@tonic-gate 		    "have same name \"%s\".\n"), entity->sc_name, name);
12707c478bd9Sstevel@tonic-gate 		xmlFree(name);
12717c478bd9Sstevel@tonic-gate 		return (-1);
12727c478bd9Sstevel@tonic-gate 	}
12737c478bd9Sstevel@tonic-gate 
12747c478bd9Sstevel@tonic-gate 	or = xmlGetProp(dependent, (xmlChar *)override_attr);
12757c478bd9Sstevel@tonic-gate 
12767c478bd9Sstevel@tonic-gate 	pg = internal_pgroup_new();
12777c478bd9Sstevel@tonic-gate 	pg->sc_pgroup_name = (char *)name;
12787c478bd9Sstevel@tonic-gate 	pg->sc_pgroup_type = (char *)SCF_GROUP_DEPENDENCY;
12797c478bd9Sstevel@tonic-gate 	pg->sc_pgroup_override = (xmlStrcmp(or, (xmlChar *)true) == 0);
12807c478bd9Sstevel@tonic-gate 	xmlFree(or);
12817c478bd9Sstevel@tonic-gate 	if (internal_attach_dependent(entity, pg) != 0) {
12827c478bd9Sstevel@tonic-gate 		xmlFree(name);
12837c478bd9Sstevel@tonic-gate 		internal_pgroup_free(pg);
12847c478bd9Sstevel@tonic-gate 		return (-1);
12857c478bd9Sstevel@tonic-gate 	}
12867c478bd9Sstevel@tonic-gate 
12877c478bd9Sstevel@tonic-gate 	for (sf = dependent->children; sf != NULL; sf = sf->next)
12887c478bd9Sstevel@tonic-gate 		if (xmlStrcmp(sf->name, (xmlChar *)"service_fmri") == 0)
12897c478bd9Sstevel@tonic-gate 			break;
12907c478bd9Sstevel@tonic-gate 	assert(sf != NULL);
12917c478bd9Sstevel@tonic-gate 	fmri = xmlGetProp(sf, (xmlChar *)value_attr);
12927c478bd9Sstevel@tonic-gate 	pg->sc_pgroup_fmri = (char *)fmri;
12937c478bd9Sstevel@tonic-gate 
12947c478bd9Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_RESTART_ON,
12957c478bd9Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, dependent, "restart_on") != 0)
12967c478bd9Sstevel@tonic-gate 		return (-1);
12977c478bd9Sstevel@tonic-gate 
12987c478bd9Sstevel@tonic-gate 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_GROUPING, SCF_TYPE_ASTRING,
12997c478bd9Sstevel@tonic-gate 	    dependent, "grouping") != 0)
13007c478bd9Sstevel@tonic-gate 		return (-1);
13017c478bd9Sstevel@tonic-gate 
13027c478bd9Sstevel@tonic-gate 	myfmri = safe_malloc(max_scf_fmri_len + 1);
13037c478bd9Sstevel@tonic-gate 	if (entity->sc_etype == SVCCFG_SERVICE_OBJECT) {
13047c478bd9Sstevel@tonic-gate 		if (snprintf(myfmri, max_scf_fmri_len + 1, "svc:/%s",
13057c478bd9Sstevel@tonic-gate 		    entity->sc_name) < 0)
13067c478bd9Sstevel@tonic-gate 			bad_error("snprintf", errno);
13077c478bd9Sstevel@tonic-gate 	} else {
13087c478bd9Sstevel@tonic-gate 		assert(entity->sc_etype == SVCCFG_INSTANCE_OBJECT);
13097c478bd9Sstevel@tonic-gate 		if (snprintf(myfmri, max_scf_fmri_len + 1, "svc:/%s:%s",
13107c478bd9Sstevel@tonic-gate 		    entity->sc_parent->sc_name, entity->sc_name) < 0)
13117c478bd9Sstevel@tonic-gate 			bad_error("snprintf", errno);
13127c478bd9Sstevel@tonic-gate 	}
13137c478bd9Sstevel@tonic-gate 
13147c478bd9Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_ENTITIES, SCF_TYPE_FMRI, 1,
13157c478bd9Sstevel@tonic-gate 	    myfmri);
13167c478bd9Sstevel@tonic-gate 	if (internal_attach_property(pg, p) != 0)
13177c478bd9Sstevel@tonic-gate 		return (-1);
13187c478bd9Sstevel@tonic-gate 
13197c478bd9Sstevel@tonic-gate 	/* Create a property to serve as a do-not-export flag. */
13207c478bd9Sstevel@tonic-gate 	p = internal_property_create("external", SCF_TYPE_BOOLEAN, 1,
13217c478bd9Sstevel@tonic-gate 	    (uint64_t)1);
13227c478bd9Sstevel@tonic-gate 	if (internal_attach_property(pg, p) != 0)
13237c478bd9Sstevel@tonic-gate 		return (-1);
13247c478bd9Sstevel@tonic-gate 
13257c478bd9Sstevel@tonic-gate 	for (n = sf->next; n != NULL; n = n->next) {
13267c478bd9Sstevel@tonic-gate 		if (lxml_ignorable_block(n))
13277c478bd9Sstevel@tonic-gate 			continue;
13287c478bd9Sstevel@tonic-gate 
13297c478bd9Sstevel@tonic-gate 		switch (lxml_xlate_element(n->name)) {
13307c478bd9Sstevel@tonic-gate 		case SC_STABILITY:
13317c478bd9Sstevel@tonic-gate 			if (new_str_prop_from_attr(pg,
13327c478bd9Sstevel@tonic-gate 			    SCF_PROPERTY_ENTITY_STABILITY, SCF_TYPE_ASTRING, n,
13337c478bd9Sstevel@tonic-gate 			    value_attr) != 0)
13347c478bd9Sstevel@tonic-gate 				return (-1);
13357c478bd9Sstevel@tonic-gate 			break;
13367c478bd9Sstevel@tonic-gate 
13377c478bd9Sstevel@tonic-gate 		case SC_PROPVAL:
13387c478bd9Sstevel@tonic-gate 			(void) lxml_get_propval(pg, n);
13397c478bd9Sstevel@tonic-gate 			break;
13407c478bd9Sstevel@tonic-gate 
13417c478bd9Sstevel@tonic-gate 		case SC_PROPERTY:
13427c478bd9Sstevel@tonic-gate 			(void) lxml_get_property(pg, n);
13437c478bd9Sstevel@tonic-gate 			break;
13447c478bd9Sstevel@tonic-gate 
13457c478bd9Sstevel@tonic-gate 		default:
13467c478bd9Sstevel@tonic-gate 			uu_die(gettext("unexpected element %s.\n"), n->name);
13477c478bd9Sstevel@tonic-gate 		}
13487c478bd9Sstevel@tonic-gate 	}
13497c478bd9Sstevel@tonic-gate 
13507c478bd9Sstevel@tonic-gate 	/* Go back and fill in defaults. */
13517c478bd9Sstevel@tonic-gate 	if (internal_property_find(pg, SCF_PROPERTY_TYPE) == NULL) {
13527c478bd9Sstevel@tonic-gate 		p = internal_property_create(SCF_PROPERTY_TYPE,
13537c478bd9Sstevel@tonic-gate 		    SCF_TYPE_ASTRING, 1, "service");
13547c478bd9Sstevel@tonic-gate 		if (internal_attach_property(pg, p) != 0)
13557c478bd9Sstevel@tonic-gate 			return (-1);
13567c478bd9Sstevel@tonic-gate 	}
13577c478bd9Sstevel@tonic-gate 
13587c478bd9Sstevel@tonic-gate 	delete = xmlGetProp(dependent, (xmlChar *)delete_attr);
13597c478bd9Sstevel@tonic-gate 	pg->sc_pgroup_delete = (xmlStrcmp(delete, (xmlChar *)true) == 0);
13607c478bd9Sstevel@tonic-gate 	xmlFree(delete);
13617c478bd9Sstevel@tonic-gate 
13627c478bd9Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(entity, "dependents",
13637c478bd9Sstevel@tonic-gate 	    (char *)scf_group_framework);
13649e9ae1fcSbustos 	p = internal_property_create((char *)name, SCF_TYPE_FMRI, 1, fmri);
13657c478bd9Sstevel@tonic-gate 	if (internal_attach_property(pg, p) != 0)
13667c478bd9Sstevel@tonic-gate 		return (-1);
13677c478bd9Sstevel@tonic-gate 
13687c478bd9Sstevel@tonic-gate 	return (0);
13697c478bd9Sstevel@tonic-gate }
13707c478bd9Sstevel@tonic-gate 
13717c478bd9Sstevel@tonic-gate static int
lxml_get_entity_stability(entity_t * entity,xmlNodePtr rstr)13727c478bd9Sstevel@tonic-gate lxml_get_entity_stability(entity_t *entity, xmlNodePtr rstr)
13737c478bd9Sstevel@tonic-gate {
13747c478bd9Sstevel@tonic-gate 	pgroup_t *pg;
13757c478bd9Sstevel@tonic-gate 	property_t *p;
13767c478bd9Sstevel@tonic-gate 	xmlChar *stabval;
13777c478bd9Sstevel@tonic-gate 
13781f6eb021SLiane Praza 	if (((stabval = xmlGetProp(rstr, (xmlChar *)value_attr)) == NULL) ||
13791f6eb021SLiane Praza 	    (*stabval == 0)) {
13807c478bd9Sstevel@tonic-gate 		uu_warn(gettext("no stability value found\n"));
138167b0e063SAlbert Lee 		stabval = (xmlChar *)safe_strdup("External");
13827c478bd9Sstevel@tonic-gate 	}
13837c478bd9Sstevel@tonic-gate 
13847c478bd9Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(entity, (char *)scf_pg_general,
13857c478bd9Sstevel@tonic-gate 	    (char *)scf_group_framework);
13867c478bd9Sstevel@tonic-gate 
13877c478bd9Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_ENTITY_STABILITY,
13887c478bd9Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, 1, stabval);
13897c478bd9Sstevel@tonic-gate 
13907c478bd9Sstevel@tonic-gate 	return (internal_attach_property(pg, p));
13917c478bd9Sstevel@tonic-gate }
13927c478bd9Sstevel@tonic-gate 
13937c478bd9Sstevel@tonic-gate static int
lxml_get_restarter(entity_t * entity,xmlNodePtr rstr)13947c478bd9Sstevel@tonic-gate lxml_get_restarter(entity_t *entity, xmlNodePtr rstr)
13957c478bd9Sstevel@tonic-gate {
13967c478bd9Sstevel@tonic-gate 	pgroup_t *pg;
13977c478bd9Sstevel@tonic-gate 	property_t *p;
13987c478bd9Sstevel@tonic-gate 	xmlChar *restarter;
13997c478bd9Sstevel@tonic-gate 	xmlNode *cursor;
14007c478bd9Sstevel@tonic-gate 	int r;
14017c478bd9Sstevel@tonic-gate 
14027c478bd9Sstevel@tonic-gate 	/*
14037c478bd9Sstevel@tonic-gate 	 * Go find child.  Child is a service_fmri element.  value attribute
14047c478bd9Sstevel@tonic-gate 	 * contains restarter FMRI.
14057c478bd9Sstevel@tonic-gate 	 */
14067c478bd9Sstevel@tonic-gate 
14077c478bd9Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(entity, (char *)scf_pg_general,
14087c478bd9Sstevel@tonic-gate 	    (char *)scf_group_framework);
14097c478bd9Sstevel@tonic-gate 
14107c478bd9Sstevel@tonic-gate 	/*
14117c478bd9Sstevel@tonic-gate 	 * Walk its child elements, as appropriate.
14127c478bd9Sstevel@tonic-gate 	 */
14137c478bd9Sstevel@tonic-gate 	for (cursor = rstr->xmlChildrenNode; cursor != NULL;
14147c478bd9Sstevel@tonic-gate 	    cursor = cursor->next) {
14157c478bd9Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
14167c478bd9Sstevel@tonic-gate 			continue;
14177c478bd9Sstevel@tonic-gate 
14187c478bd9Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
14197c478bd9Sstevel@tonic-gate 		case SC_SERVICE_FMRI:
14207c478bd9Sstevel@tonic-gate 			restarter = xmlGetProp(cursor, (xmlChar *)value_attr);
14217c478bd9Sstevel@tonic-gate 			break;
14227c478bd9Sstevel@tonic-gate 		default:
14237c478bd9Sstevel@tonic-gate 			uu_die(gettext("illegal element \"%s\" on restarter "
14247c478bd9Sstevel@tonic-gate 			    "element for \"%s\"\n"), cursor->name,
14257c478bd9Sstevel@tonic-gate 			    entity->sc_name);
14267c478bd9Sstevel@tonic-gate 			break;
14277c478bd9Sstevel@tonic-gate 		}
14287c478bd9Sstevel@tonic-gate 	}
14297c478bd9Sstevel@tonic-gate 
14307c478bd9Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_RESTARTER, SCF_TYPE_FMRI, 1,
14317c478bd9Sstevel@tonic-gate 	    restarter);
14327c478bd9Sstevel@tonic-gate 
14337c478bd9Sstevel@tonic-gate 	r = internal_attach_property(pg, p);
14347c478bd9Sstevel@tonic-gate 	if (r != 0) {
14357c478bd9Sstevel@tonic-gate 		internal_property_free(p);
14367c478bd9Sstevel@tonic-gate 		return (-1);
14377c478bd9Sstevel@tonic-gate 	}
14387c478bd9Sstevel@tonic-gate 
14397c478bd9Sstevel@tonic-gate 	return (0);
14407c478bd9Sstevel@tonic-gate }
14417c478bd9Sstevel@tonic-gate 
1442f6e214c7SGavin Maltby static void
lxml_get_paramval(pgroup_t * pgrp,const char * propname,xmlNodePtr pval)1443f6e214c7SGavin Maltby lxml_get_paramval(pgroup_t *pgrp, const char *propname, xmlNodePtr pval)
1444f6e214c7SGavin Maltby {
1445f6e214c7SGavin Maltby 	property_t *p;
1446f6e214c7SGavin Maltby 	char *value;
1447f6e214c7SGavin Maltby 	char *prop;
1448f6e214c7SGavin Maltby 
144967b0e063SAlbert Lee 	prop = safe_strdup(propname);
1450f6e214c7SGavin Maltby 
1451f6e214c7SGavin Maltby 	value = (char *)xmlGetProp(pval, (xmlChar *)value_attr);
1452f6e214c7SGavin Maltby 	if (value == NULL || *value == '\0')
1453f6e214c7SGavin Maltby 		uu_die(gettext("property value missing for property '%s/%s'\n"),
1454f6e214c7SGavin Maltby 		    pgrp->sc_pgroup_name, propname);
1455f6e214c7SGavin Maltby 	p = internal_property_create(prop, SCF_TYPE_ASTRING, 1, value);
1456f6e214c7SGavin Maltby 
1457f6e214c7SGavin Maltby 	(void) internal_attach_property(pgrp, p);
1458f6e214c7SGavin Maltby }
1459f6e214c7SGavin Maltby 
1460f6e214c7SGavin Maltby static void
lxml_get_parameter(pgroup_t * pgrp,const char * propname,xmlNodePtr param)1461f6e214c7SGavin Maltby lxml_get_parameter(pgroup_t *pgrp, const char *propname, xmlNodePtr param)
1462f6e214c7SGavin Maltby {
1463f6e214c7SGavin Maltby 	property_t *p = internal_property_new();
1464f6e214c7SGavin Maltby 
146567b0e063SAlbert Lee 	p->sc_property_name = safe_strdup(propname);
1466f6e214c7SGavin Maltby 	p->sc_value_type = SCF_TYPE_ASTRING;
1467f6e214c7SGavin Maltby 
1468f6e214c7SGavin Maltby 	(void) lxml_get_value(p, SC_ASTRING, param);
1469f6e214c7SGavin Maltby 
1470f6e214c7SGavin Maltby 	(void) internal_attach_property(pgrp, p);
1471f6e214c7SGavin Maltby }
1472f6e214c7SGavin Maltby 
1473f6e214c7SGavin Maltby static void
lxml_get_type(pgroup_t * pgrp,xmlNodePtr type)1474f6e214c7SGavin Maltby lxml_get_type(pgroup_t *pgrp, xmlNodePtr type)
1475f6e214c7SGavin Maltby {
1476f6e214c7SGavin Maltby 	property_t *p;
1477f6e214c7SGavin Maltby 	xmlChar *name;
1478f6e214c7SGavin Maltby 	xmlChar *active;
1479f6e214c7SGavin Maltby 	xmlNodePtr cursor;
1480f6e214c7SGavin Maltby 	uint64_t active_val;
1481f6e214c7SGavin Maltby 	size_t sz = max_scf_name_len + 1;
1482f6e214c7SGavin Maltby 	char *propname = safe_malloc(sz);
1483f6e214c7SGavin Maltby 
1484f6e214c7SGavin Maltby 	if (pgrp->sc_parent->sc_op == SVCCFG_OP_APPLY)
1485f6e214c7SGavin Maltby 		lxml_validate_element(type);
1486f6e214c7SGavin Maltby 
1487f6e214c7SGavin Maltby 	name = xmlGetProp(type, (xmlChar *)name_attr);
1488f6e214c7SGavin Maltby 	if (name == NULL || *name == '\0')
1489f6e214c7SGavin Maltby 		uu_die(gettext("attribute name missing in element 'type'\n"));
1490f6e214c7SGavin Maltby 
1491f6e214c7SGavin Maltby 	for (cursor = type->xmlChildrenNode; cursor != NULL;
1492f6e214c7SGavin Maltby 	    cursor = cursor->next) {
1493f6e214c7SGavin Maltby 		xmlChar *pname;
1494f6e214c7SGavin Maltby 
1495f6e214c7SGavin Maltby 		if (lxml_ignorable_block(cursor))
1496f6e214c7SGavin Maltby 			continue;
1497f6e214c7SGavin Maltby 
1498f6e214c7SGavin Maltby 		pname = xmlGetProp(cursor, (xmlChar *)name_attr);
1499f6e214c7SGavin Maltby 		if (pname == NULL || *pname == '\0')
1500f6e214c7SGavin Maltby 			uu_die(gettext(
1501f6e214c7SGavin Maltby 			    "attribute name missing in sub-element of type\n"));
1502f6e214c7SGavin Maltby 
1503f6e214c7SGavin Maltby 		if (snprintf(propname, sz, "%s,%s", (char *)name,
1504f6e214c7SGavin Maltby 		    (char *)pname) >= sz)
1505f6e214c7SGavin Maltby 			uu_die(gettext("name '%s,%s' is too long\n"),
1506f6e214c7SGavin Maltby 			    (char *)name, (char *)pname);
1507f6e214c7SGavin Maltby 		xmlFree(pname);
1508f6e214c7SGavin Maltby 
1509f6e214c7SGavin Maltby 		switch (lxml_xlate_element(cursor->name)) {
1510f6e214c7SGavin Maltby 		case SC_PARAMETER:
1511f6e214c7SGavin Maltby 			lxml_get_parameter(pgrp, propname, cursor);
1512f6e214c7SGavin Maltby 			break;
1513f6e214c7SGavin Maltby 
1514f6e214c7SGavin Maltby 		case SC_PARAMVAL:
1515f6e214c7SGavin Maltby 			lxml_get_paramval(pgrp, propname, cursor);
1516f6e214c7SGavin Maltby 			break;
1517f6e214c7SGavin Maltby 
1518f6e214c7SGavin Maltby 		default:
1519f6e214c7SGavin Maltby 			uu_die(gettext("unknown element %s\n"), cursor->name);
1520f6e214c7SGavin Maltby 		}
1521f6e214c7SGavin Maltby 	}
1522f6e214c7SGavin Maltby 
1523f6e214c7SGavin Maltby 	active = xmlGetProp(type, (xmlChar *)active_attr);
1524f6e214c7SGavin Maltby 	if (active == NULL || strcmp(true, (const char *)active) == 0)
1525f6e214c7SGavin Maltby 		active_val = 1;
1526f6e214c7SGavin Maltby 	else
1527f6e214c7SGavin Maltby 		active_val = 0;
1528f6e214c7SGavin Maltby 	xmlFree(active);
1529f6e214c7SGavin Maltby 
1530f6e214c7SGavin Maltby 	if (snprintf(propname, sz, "%s,%s", (char *)name,
1531f6e214c7SGavin Maltby 	    SCF_PROPERTY_ACTIVE_POSTFIX) >= sz)
1532f6e214c7SGavin Maltby 		uu_die(gettext("name '%s,%s' is too long\n"),
1533f6e214c7SGavin Maltby 		    (char *)name, SCF_PROPERTY_ACTIVE_POSTFIX);
1534f6e214c7SGavin Maltby 
1535f6e214c7SGavin Maltby 	p = internal_property_create(propname, SCF_TYPE_BOOLEAN, 1, active_val);
1536f6e214c7SGavin Maltby 
1537f6e214c7SGavin Maltby 	(void) internal_attach_property(pgrp, p);
1538f6e214c7SGavin Maltby 
1539f6e214c7SGavin Maltby 	xmlFree(name);
1540f6e214c7SGavin Maltby }
1541f6e214c7SGavin Maltby 
1542f6e214c7SGavin Maltby static void
lxml_get_event(entity_t * entity,const char * pgname,xmlNodePtr np)1543f6e214c7SGavin Maltby lxml_get_event(entity_t *entity, const char *pgname, xmlNodePtr np)
1544f6e214c7SGavin Maltby {
1545f6e214c7SGavin Maltby 	xmlNodePtr cursor;
1546f6e214c7SGavin Maltby 	pgroup_t *pgrp;
1547f6e214c7SGavin Maltby 
1548f6e214c7SGavin Maltby 	pgrp = internal_pgroup_find_or_create(entity, pgname,
1549f6e214c7SGavin Maltby 	    SCF_NOTIFY_PARAMS_PG_TYPE);
1550f6e214c7SGavin Maltby 	for (cursor = np->xmlChildrenNode; cursor != NULL;
1551f6e214c7SGavin Maltby 	    cursor = cursor->next) {
1552f6e214c7SGavin Maltby 		if (lxml_ignorable_block(cursor))
1553f6e214c7SGavin Maltby 			continue;
1554f6e214c7SGavin Maltby 
1555f6e214c7SGavin Maltby 		switch (lxml_xlate_element(cursor->name)) {
1556f6e214c7SGavin Maltby 		case SC_EVENT:
1557f6e214c7SGavin Maltby 			continue;
1558f6e214c7SGavin Maltby 
1559f6e214c7SGavin Maltby 		case SC_TYPE:
1560f6e214c7SGavin Maltby 			lxml_get_type(pgrp, cursor);
1561f6e214c7SGavin Maltby 			break;
1562f6e214c7SGavin Maltby 
1563f6e214c7SGavin Maltby 		default:
1564f6e214c7SGavin Maltby 			uu_warn(gettext("illegal element '%s' on "
1565f6e214c7SGavin Maltby 			    "notification parameters\n"), cursor->name);
1566f6e214c7SGavin Maltby 		}
1567f6e214c7SGavin Maltby 	}
1568f6e214c7SGavin Maltby }
1569f6e214c7SGavin Maltby 
1570f6e214c7SGavin Maltby static int
lxml_get_notification_parameters(entity_t * entity,xmlNodePtr np)1571f6e214c7SGavin Maltby lxml_get_notification_parameters(entity_t *entity, xmlNodePtr np)
1572f6e214c7SGavin Maltby {
1573f6e214c7SGavin Maltby 	char *event = NULL;
1574f6e214c7SGavin Maltby 	char **pgs = NULL;
1575f6e214c7SGavin Maltby 	char **p;
1576f6e214c7SGavin Maltby 	char *pgname = NULL;
1577f6e214c7SGavin Maltby 	xmlNodePtr cursor;
1578f6e214c7SGavin Maltby 	int32_t tset, t;
1579f6e214c7SGavin Maltby 	size_t sz = max_scf_name_len + 1;
1580f6e214c7SGavin Maltby 	int count;
1581f6e214c7SGavin Maltby 	int r = -1;
1582f6e214c7SGavin Maltby 
1583f6e214c7SGavin Maltby 	for (count = 0, cursor = np->xmlChildrenNode; cursor != NULL;
1584f6e214c7SGavin Maltby 	    cursor = cursor->next) {
1585f6e214c7SGavin Maltby 		if (lxml_ignorable_block(cursor))
1586f6e214c7SGavin Maltby 			continue;
1587f6e214c7SGavin Maltby 
1588f6e214c7SGavin Maltby 		if (lxml_xlate_element(cursor->name) == SC_EVENT) {
1589f6e214c7SGavin Maltby 			xmlChar *s;
1590f6e214c7SGavin Maltby 
1591f6e214c7SGavin Maltby 			count++;
1592f6e214c7SGavin Maltby 			if (count > 1)
1593f6e214c7SGavin Maltby 				uu_die(gettext("Can't have more than 1 element "
1594f6e214c7SGavin Maltby 				    "event in a notification parameter\n"));
1595f6e214c7SGavin Maltby 			s = xmlGetProp(cursor, (xmlChar *)value_attr);
1596f6e214c7SGavin Maltby 			if (s == NULL || (event = strdup((char *)s)) == NULL)
1597f6e214c7SGavin Maltby 				uu_die(gettext("couldn't allocate memory"));
1598f6e214c7SGavin Maltby 			xmlFree(s);
1599f6e214c7SGavin Maltby 		}
1600f6e214c7SGavin Maltby 	}
1601f6e214c7SGavin Maltby 
1602f6e214c7SGavin Maltby 	pgs = tokenize(event, ",");
1603f6e214c7SGavin Maltby 
1604f6e214c7SGavin Maltby 	switch (tset = check_tokens(pgs)) {
1605f6e214c7SGavin Maltby 	case INVALID_TOKENS:
1606f6e214c7SGavin Maltby 		uu_die(gettext("Invalid input.\n"));
1607f6e214c7SGavin Maltby 		/*NOTREACHED*/
1608f6e214c7SGavin Maltby 	case MIXED_TOKENS:
1609f6e214c7SGavin Maltby 		semerr(gettext("Can't mix SMF and FMA event definitions\n"));
1610f6e214c7SGavin Maltby 		goto out;
1611f6e214c7SGavin Maltby 	case FMA_TOKENS:
1612f6e214c7SGavin Maltby 		/* make sure this is SCF_NOTIFY_PARAMS_INST */
1613f6e214c7SGavin Maltby 		if (entity->sc_etype != SVCCFG_INSTANCE_OBJECT ||
1614f6e214c7SGavin Maltby 		    strcmp(entity->sc_fmri, SCF_NOTIFY_PARAMS_INST) != 0) {
1615f6e214c7SGavin Maltby 			semerr(gettext(
1616a5f0d1fcSToomas Soome 			    "Non-SMF transition events must go to %s\n"),
1617f6e214c7SGavin Maltby 			    SCF_NOTIFY_PARAMS_INST);
1618f6e214c7SGavin Maltby 			goto out;
1619f6e214c7SGavin Maltby 		}
1620f6e214c7SGavin Maltby 		pgname = safe_malloc(sz);
1621f6e214c7SGavin Maltby 		for (p = pgs; *p; ++p) {
1622f6e214c7SGavin Maltby 			if (snprintf(pgname, sz, "%s,%s", de_tag(*p),
1623f6e214c7SGavin Maltby 			    SCF_NOTIFY_PG_POSTFIX) >= sz)
1624f6e214c7SGavin Maltby 				uu_die(gettext("event name too long: %s\n"),
1625f6e214c7SGavin Maltby 				    *p);
1626f6e214c7SGavin Maltby 
1627f6e214c7SGavin Maltby 			lxml_get_event(entity, pgname, np);
1628f6e214c7SGavin Maltby 		}
1629a5f0d1fcSToomas Soome 		break;
1630f6e214c7SGavin Maltby 
1631f6e214c7SGavin Maltby 	default:	/* smf state transition tokens */
1632f6e214c7SGavin Maltby 		if (entity->sc_etype == SVCCFG_SERVICE_OBJECT &&
1633f6e214c7SGavin Maltby 		    strcmp(entity->sc_fmri, SCF_SERVICE_GLOBAL) == 0) {
1634f6e214c7SGavin Maltby 			semerr(gettext(
1635f6e214c7SGavin Maltby 			    "Can't set events for global service\n"));
1636f6e214c7SGavin Maltby 			goto out;
1637f6e214c7SGavin Maltby 		}
1638f6e214c7SGavin Maltby 		for (t = 0x1; t < SCF_STATE_ALL; t <<= 1) {
1639f6e214c7SGavin Maltby 			if (t & tset) {
1640f6e214c7SGavin Maltby 				lxml_get_event(entity, tset_to_string(t), np);
1641f6e214c7SGavin Maltby 			}
1642f6e214c7SGavin Maltby 			if ((t << 16) & tset) {
1643f6e214c7SGavin Maltby 				lxml_get_event(entity, tset_to_string(t << 16),
1644f6e214c7SGavin Maltby 				    np);
1645f6e214c7SGavin Maltby 			}
1646f6e214c7SGavin Maltby 		}
1647f6e214c7SGavin Maltby 	}
1648f6e214c7SGavin Maltby 
1649f6e214c7SGavin Maltby 	r = 0;
1650f6e214c7SGavin Maltby out:
1651f6e214c7SGavin Maltby 	free(pgname);
1652f6e214c7SGavin Maltby 	free(pgs);
1653f6e214c7SGavin Maltby 	free(event);
1654f6e214c7SGavin Maltby 
1655f6e214c7SGavin Maltby 	return (r);
1656f6e214c7SGavin Maltby }
1657f6e214c7SGavin Maltby 
16581f6eb021SLiane Praza /*
16591f6eb021SLiane Praza  * Add a property containing the localized text from the manifest.  The
16601f6eb021SLiane Praza  * property is added to the property group at pg.  The name of the created
16611f6eb021SLiane Praza  * property is based on the format at pn_format.  This is an snprintf(3C)
16621f6eb021SLiane Praza  * format containing a single %s conversion specification.  At conversion
16631f6eb021SLiane Praza  * time, the %s is replaced by the locale designation.
16641f6eb021SLiane Praza  *
16651f6eb021SLiane Praza  * source is the source element and it is only used for error messages.
16661f6eb021SLiane Praza  */
16677c478bd9Sstevel@tonic-gate static int
lxml_get_loctext(entity_t * service,pgroup_t * pg,xmlNodePtr loctext,const char * pn_format,const char * source)16681f6eb021SLiane Praza lxml_get_loctext(entity_t *service, pgroup_t *pg, xmlNodePtr loctext,
16691f6eb021SLiane Praza     const char *pn_format, const char *source)
16707c478bd9Sstevel@tonic-gate {
16711f6eb021SLiane Praza 	int extra;
16727c478bd9Sstevel@tonic-gate 	xmlNodePtr cursor;
16737c478bd9Sstevel@tonic-gate 	xmlChar *val;
16747c478bd9Sstevel@tonic-gate 	char *stripped, *cp;
16757c478bd9Sstevel@tonic-gate 	property_t *p;
16761f6eb021SLiane Praza 	char *prop_name;
16777c478bd9Sstevel@tonic-gate 	int r;
16787c478bd9Sstevel@tonic-gate 
16791f6eb021SLiane Praza 	if (((val = xmlGetProp(loctext, (xmlChar *)xml_lang_attr)) == NULL) ||
16801f6eb021SLiane Praza 	    (*val == 0)) {
16811f6eb021SLiane Praza 		if (((val = xmlGetProp(loctext,
16821f6eb021SLiane Praza 		    (xmlChar *)lang_attr)) == NULL) || (*val == 0)) {
16837c478bd9Sstevel@tonic-gate 			val = (xmlChar *)"unknown";
16841f6eb021SLiane Praza 		}
16851f6eb021SLiane Praza 	}
16867c478bd9Sstevel@tonic-gate 
16871f6eb021SLiane Praza 	_scf_sanitize_locale((char *)val);
16881f6eb021SLiane Praza 	prop_name = safe_malloc(max_scf_name_len + 1);
16891f6eb021SLiane Praza 	if ((extra = snprintf(prop_name, max_scf_name_len + 1, pn_format,
16901f6eb021SLiane Praza 	    val)) >= max_scf_name_len + 1) {
16911f6eb021SLiane Praza 		extra -= max_scf_name_len;
16921f6eb021SLiane Praza 		uu_die(gettext("%s attribute is %d characters too long for "
16931f6eb021SLiane Praza 		    "%s in %s\n"),
16941f6eb021SLiane Praza 		    xml_lang_attr, extra, source, service->sc_name);
16951f6eb021SLiane Praza 	}
16961f6eb021SLiane Praza 	xmlFree(val);
16977c478bd9Sstevel@tonic-gate 
16987c478bd9Sstevel@tonic-gate 	for (cursor = loctext->xmlChildrenNode; cursor != NULL;
16997c478bd9Sstevel@tonic-gate 	    cursor = cursor->next) {
17007c478bd9Sstevel@tonic-gate 		if (strcmp("text", (const char *)cursor->name) == 0) {
17017c478bd9Sstevel@tonic-gate 			break;
17027c478bd9Sstevel@tonic-gate 		} else if (strcmp("comment", (const char *)cursor->name) != 0) {
17037c478bd9Sstevel@tonic-gate 			uu_die(gettext("illegal element \"%s\" on loctext "
17047c478bd9Sstevel@tonic-gate 			    "element for \"%s\"\n"), cursor->name,
17057c478bd9Sstevel@tonic-gate 			    service->sc_name);
17067c478bd9Sstevel@tonic-gate 		}
17077c478bd9Sstevel@tonic-gate 	}
17087c478bd9Sstevel@tonic-gate 
17097c478bd9Sstevel@tonic-gate 	if (cursor == NULL) {
17107c478bd9Sstevel@tonic-gate 		uu_die(gettext("loctext element has no content for \"%s\"\n"),
17117c478bd9Sstevel@tonic-gate 		    service->sc_name);
17127c478bd9Sstevel@tonic-gate 	}
17137c478bd9Sstevel@tonic-gate 
17147c478bd9Sstevel@tonic-gate 	/*
17157c478bd9Sstevel@tonic-gate 	 * Remove leading and trailing whitespace.
17167c478bd9Sstevel@tonic-gate 	 */
171767b0e063SAlbert Lee 	stripped = safe_strdup((const char *)cursor->content);
17187c478bd9Sstevel@tonic-gate 
171976cf44abSjeanm 	for (; isspace(*stripped); stripped++)
172076cf44abSjeanm 		;
172176cf44abSjeanm 	for (cp = stripped + strlen(stripped) - 1; isspace(*cp); cp--)
172276cf44abSjeanm 		;
17237c478bd9Sstevel@tonic-gate 	*(cp + 1) = '\0';
17247c478bd9Sstevel@tonic-gate 
17251f6eb021SLiane Praza 	p = internal_property_create(prop_name, SCF_TYPE_USTRING, 1,
17267c478bd9Sstevel@tonic-gate 	    stripped);
17277c478bd9Sstevel@tonic-gate 
17287c478bd9Sstevel@tonic-gate 	r = internal_attach_property(pg, p);
17291f6eb021SLiane Praza 	if (r != 0) {
17307c478bd9Sstevel@tonic-gate 		internal_property_free(p);
17311f6eb021SLiane Praza 		free(prop_name);
17321f6eb021SLiane Praza 	}
17337c478bd9Sstevel@tonic-gate 
17347c478bd9Sstevel@tonic-gate 	return (r);
17357c478bd9Sstevel@tonic-gate }
17367c478bd9Sstevel@tonic-gate 
17371f6eb021SLiane Praza /*
17381f6eb021SLiane Praza  * This function processes all loctext elements in the current XML element
17391f6eb021SLiane Praza  * designated by container.  A property is created for each loctext element
17401f6eb021SLiane Praza  * and added to the property group at pg.  The name of the property is
17411f6eb021SLiane Praza  * derived from the loctext language designation using the format at
17421f6eb021SLiane Praza  * pn_format.  pn_format should be an snprintf format string containing one
17431f6eb021SLiane Praza  * %s which is replaced by the language designation.
17441f6eb021SLiane Praza  *
17451f6eb021SLiane Praza  * The function returns 0 on success and -1 if it is unable to attach the
17461f6eb021SLiane Praza  * newly created property to pg.
17471f6eb021SLiane Praza  */
17487c478bd9Sstevel@tonic-gate static int
lxml_get_all_loctext(entity_t * service,pgroup_t * pg,xmlNodePtr container,const char * pn_format,const char * source)17491f6eb021SLiane Praza lxml_get_all_loctext(entity_t *service, pgroup_t *pg, xmlNodePtr container,
17501f6eb021SLiane Praza     const char *pn_format, const char *source)
17517c478bd9Sstevel@tonic-gate {
17527c478bd9Sstevel@tonic-gate 	xmlNodePtr cursor;
17537c478bd9Sstevel@tonic-gate 
17547c478bd9Sstevel@tonic-gate 	/*
17551f6eb021SLiane Praza 	 * Iterate through one or more loctext elements.  The locale is
17561f6eb021SLiane Praza 	 * used to generate the property name; the contents are the ustring
17571f6eb021SLiane Praza 	 * value for the property.
17587c478bd9Sstevel@tonic-gate 	 */
17591f6eb021SLiane Praza 	for (cursor = container->xmlChildrenNode; cursor != NULL;
17607c478bd9Sstevel@tonic-gate 	    cursor = cursor->next) {
17617c478bd9Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
17627c478bd9Sstevel@tonic-gate 			continue;
17637c478bd9Sstevel@tonic-gate 
17647c478bd9Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
17657c478bd9Sstevel@tonic-gate 		case SC_LOCTEXT:
17661f6eb021SLiane Praza 			if (lxml_get_loctext(service, pg, cursor, pn_format,
17671f6eb021SLiane Praza 			    source))
17687c478bd9Sstevel@tonic-gate 				return (-1);
17697c478bd9Sstevel@tonic-gate 			break;
17707c478bd9Sstevel@tonic-gate 		default:
17711f6eb021SLiane Praza 			uu_die(gettext("illegal element \"%s\" on %s element "
17721f6eb021SLiane Praza 			    "for \"%s\"\n"), cursor->name, container->name,
17737c478bd9Sstevel@tonic-gate 			    service->sc_name);
17747c478bd9Sstevel@tonic-gate 			break;
17757c478bd9Sstevel@tonic-gate 		}
17767c478bd9Sstevel@tonic-gate 	}
17777c478bd9Sstevel@tonic-gate 
17787c478bd9Sstevel@tonic-gate 	return (0);
17797c478bd9Sstevel@tonic-gate }
17807c478bd9Sstevel@tonic-gate 
17811f6eb021SLiane Praza /*
17821f6eb021SLiane Praza  * Obtain the specified cardinality attribute and place it in a property
17831f6eb021SLiane Praza  * named prop_name.  The converted attribute is placed at *value, and the
17841f6eb021SLiane Praza  * newly created property is returned to propp.  NULL is returned to propp
17851f6eb021SLiane Praza  * if the attribute is not provided in the manifest.
17861f6eb021SLiane Praza  *
17871f6eb021SLiane Praza  * 0 is returned upon success, and -1 indicates that the manifest contained
17881f6eb021SLiane Praza  * an invalid cardinality value.
17891f6eb021SLiane Praza  */
17907c478bd9Sstevel@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)17911f6eb021SLiane Praza lxml_get_cardinality_attribute(entity_t *service, xmlNodePtr cursor,
17921f6eb021SLiane Praza     const char *attr_name, const char *prop_name, uint64_t *value,
17931f6eb021SLiane Praza     property_t **propp)
17947c478bd9Sstevel@tonic-gate {
17951f6eb021SLiane Praza 	char *c;
17961f6eb021SLiane Praza 	property_t *p;
17971f6eb021SLiane Praza 	xmlChar *val;
17981f6eb021SLiane Praza 	uint64_t count;
17991f6eb021SLiane Praza 	char *endptr;
18007c478bd9Sstevel@tonic-gate 
18011f6eb021SLiane Praza 	*propp = NULL;
18021f6eb021SLiane Praza 	val = xmlGetProp(cursor, (xmlChar *)attr_name);
18031f6eb021SLiane Praza 	if (val == NULL)
18041f6eb021SLiane Praza 		return (0);
18051f6eb021SLiane Praza 	if (*val == 0) {
18061f6eb021SLiane Praza 		xmlFree(val);
18071f6eb021SLiane Praza 		return (0);
18081f6eb021SLiane Praza 	}
18097c478bd9Sstevel@tonic-gate 
18107c478bd9Sstevel@tonic-gate 	/*
18111f6eb021SLiane Praza 	 * Make sure that the string at val doesn't have a leading minus
18121f6eb021SLiane Praza 	 * sign.  The strtoull() call below does not catch this problem.
18137c478bd9Sstevel@tonic-gate 	 */
18141f6eb021SLiane Praza 	for (c = (char *)val; *c != 0; c++) {
18151f6eb021SLiane Praza 		if (isspace(*c))
18167c478bd9Sstevel@tonic-gate 			continue;
18171f6eb021SLiane Praza 		if (isdigit(*c))
18187c478bd9Sstevel@tonic-gate 			break;
18191f6eb021SLiane Praza 		semerr(gettext("\"%c\" is not a legal character in the %s "
18201f6eb021SLiane Praza 		    "attribute of the %s element in %s.\n"), *c,
18211f6eb021SLiane Praza 		    attr_name, prop_name, service->sc_name);
18221f6eb021SLiane Praza 		xmlFree(val);
18231f6eb021SLiane Praza 		return (-1);
18241f6eb021SLiane Praza 	}
18251f6eb021SLiane Praza 	errno = 0;
18261f6eb021SLiane Praza 	count = strtoull((char *)val, &endptr, 10);
18271f6eb021SLiane Praza 	if (errno != 0 || endptr == (char *)val || *endptr) {
18281f6eb021SLiane Praza 		semerr(gettext("\"%s\" is not a legal number for the %s "
18291f6eb021SLiane Praza 		    "attribute of the %s element in %s.\n"), (char *)val,
18301f6eb021SLiane Praza 		    attr_name, prop_name, service->sc_name);
18311f6eb021SLiane Praza 		xmlFree(val);
18321f6eb021SLiane Praza 		return (-1);
18331f6eb021SLiane Praza 	}
18341f6eb021SLiane Praza 
18351f6eb021SLiane Praza 	xmlFree(val);
18361f6eb021SLiane Praza 
18371f6eb021SLiane Praza 	/* Value is valid.  Create the property. */
18381f6eb021SLiane Praza 	p = internal_property_create(prop_name, SCF_TYPE_COUNT, 1, count);
18391f6eb021SLiane Praza 	*value = count;
18401f6eb021SLiane Praza 	*propp = p;
18411f6eb021SLiane Praza 	return (0);
18421f6eb021SLiane Praza }
18431f6eb021SLiane Praza 
18441f6eb021SLiane Praza /*
18451f6eb021SLiane Praza  * The cardinality is specified by two attributes max and min at cursor.
18461f6eb021SLiane Praza  * Both are optional, but if present they must be unsigned integers.
18471f6eb021SLiane Praza  */
18481f6eb021SLiane Praza static int
lxml_get_tm_cardinality(entity_t * service,pgroup_t * pg,xmlNodePtr cursor)18491f6eb021SLiane Praza lxml_get_tm_cardinality(entity_t *service, pgroup_t *pg, xmlNodePtr cursor)
18501f6eb021SLiane Praza {
18511f6eb021SLiane Praza 	int min_attached = 0;
18521f6eb021SLiane Praza 	int compare = 1;
18531f6eb021SLiane Praza 	property_t *min_prop;
18541f6eb021SLiane Praza 	property_t *max_prop;
18551f6eb021SLiane Praza 	uint64_t max;
18561f6eb021SLiane Praza 	uint64_t min;
18571f6eb021SLiane Praza 	int r;
18581f6eb021SLiane Praza 
18591f6eb021SLiane Praza 	r = lxml_get_cardinality_attribute(service, cursor, min_attr,
18601f6eb021SLiane Praza 	    SCF_PROPERTY_TM_CARDINALITY_MIN, &min, &min_prop);
18611f6eb021SLiane Praza 	if (r != 0)
18621f6eb021SLiane Praza 		return (r);
18631f6eb021SLiane Praza 	if (min_prop == NULL)
18641f6eb021SLiane Praza 		compare = 0;
18651f6eb021SLiane Praza 	r = lxml_get_cardinality_attribute(service, cursor, max_attr,
18661f6eb021SLiane Praza 	    SCF_PROPERTY_TM_CARDINALITY_MAX, &max, &max_prop);
18671f6eb021SLiane Praza 	if (r != 0)
18681f6eb021SLiane Praza 		goto errout;
18691f6eb021SLiane Praza 	if ((max_prop != NULL) && (compare == 1)) {
18701f6eb021SLiane Praza 		if (max < min) {
18711f6eb021SLiane Praza 			semerr(gettext("Cardinality max is less than min for "
18721f6eb021SLiane Praza 			    "the %s element in %s.\n"), pg->sc_pgroup_name,
18731f6eb021SLiane Praza 			    service->sc_fmri);
18741f6eb021SLiane Praza 			goto errout;
18757c478bd9Sstevel@tonic-gate 		}
18767c478bd9Sstevel@tonic-gate 	}
18777c478bd9Sstevel@tonic-gate 
18781f6eb021SLiane Praza 	/* Attach the properties to the property group. */
18791f6eb021SLiane Praza 	if (min_prop) {
18801f6eb021SLiane Praza 		if (internal_attach_property(pg, min_prop) == 0) {
18811f6eb021SLiane Praza 			min_attached = 1;
18821f6eb021SLiane Praza 		} else {
18831f6eb021SLiane Praza 			goto errout;
18841f6eb021SLiane Praza 		}
18851f6eb021SLiane Praza 	}
18861f6eb021SLiane Praza 	if (max_prop) {
18871f6eb021SLiane Praza 		if (internal_attach_property(pg, max_prop) != 0) {
18881f6eb021SLiane Praza 			if (min_attached)
18891f6eb021SLiane Praza 				internal_detach_property(pg, min_prop);
18901f6eb021SLiane Praza 			goto errout;
18911f6eb021SLiane Praza 		}
18921f6eb021SLiane Praza 	}
18937c478bd9Sstevel@tonic-gate 	return (0);
18941f6eb021SLiane Praza 
18951f6eb021SLiane Praza errout:
18961f6eb021SLiane Praza 	if (min_prop)
18971f6eb021SLiane Praza 		internal_property_free(min_prop);
18981f6eb021SLiane Praza 	if (max_prop)
18991f6eb021SLiane Praza 		internal_property_free(max_prop);
19001f6eb021SLiane Praza 	return (-1);
19011f6eb021SLiane Praza }
19021f6eb021SLiane Praza 
19031f6eb021SLiane Praza /*
19041f6eb021SLiane Praza  * Get the common_name which is present as localized text at common_name in
19051f6eb021SLiane Praza  * the manifest.  The common_name is stored as the value of a property in
19061f6eb021SLiane Praza  * the property group whose name is SCF_PG_TM_COMMON_NAME and type is
19071f6eb021SLiane Praza  * SCF_GROUP_TEMPLATE.  This property group will be created in service if
19081f6eb021SLiane Praza  * it is not already there.
19091f6eb021SLiane Praza  */
19101f6eb021SLiane Praza static int
lxml_get_tm_common_name(entity_t * service,xmlNodePtr common_name)19111f6eb021SLiane Praza lxml_get_tm_common_name(entity_t *service, xmlNodePtr common_name)
19121f6eb021SLiane Praza {
19131f6eb021SLiane Praza 	pgroup_t *pg;
19141f6eb021SLiane Praza 
19151f6eb021SLiane Praza 	/*
19161f6eb021SLiane Praza 	 * Create the property group, if absent.
19171f6eb021SLiane Praza 	 */
19181f6eb021SLiane Praza 	pg = internal_pgroup_find_or_create(service, SCF_PG_TM_COMMON_NAME,
19191f6eb021SLiane Praza 	    SCF_GROUP_TEMPLATE);
19201f6eb021SLiane Praza 
19211f6eb021SLiane Praza 	return (lxml_get_all_loctext(service, pg, common_name, LOCALE_ONLY_FMT,
19221f6eb021SLiane Praza 	    "common_name"));
19231f6eb021SLiane Praza }
19241f6eb021SLiane Praza 
19251f6eb021SLiane Praza /*
19261f6eb021SLiane Praza  * Get the description which is present as localized text at description in
19271f6eb021SLiane Praza  * the manifest.  The description is stored as the value of a property in
19281f6eb021SLiane Praza  * the property group whose name is SCF_PG_TM_DESCRIPTION and type is
19291f6eb021SLiane Praza  * SCF_GROUP_TEMPLATE.  This property group will be created in service if
19301f6eb021SLiane Praza  * it is not already there.
19311f6eb021SLiane Praza  */
19321f6eb021SLiane Praza static int
lxml_get_tm_description(entity_t * service,xmlNodePtr description)19331f6eb021SLiane Praza lxml_get_tm_description(entity_t *service, xmlNodePtr description)
19341f6eb021SLiane Praza {
19351f6eb021SLiane Praza 	pgroup_t *pg;
19361f6eb021SLiane Praza 
19371f6eb021SLiane Praza 	/*
19381f6eb021SLiane Praza 	 * Create the property group, if absent.
19391f6eb021SLiane Praza 	 */
19401f6eb021SLiane Praza 	pg = internal_pgroup_find_or_create(service, SCF_PG_TM_DESCRIPTION,
19411f6eb021SLiane Praza 	    SCF_GROUP_TEMPLATE);
19421f6eb021SLiane Praza 
19431f6eb021SLiane Praza 	return (lxml_get_all_loctext(service, pg, description,
19441f6eb021SLiane Praza 	    LOCALE_ONLY_FMT, "description"));
19457c478bd9Sstevel@tonic-gate }
19467c478bd9Sstevel@tonic-gate 
19477c478bd9Sstevel@tonic-gate static char *
lxml_label_to_groupname(const char * prefix,const char * in)19487c478bd9Sstevel@tonic-gate lxml_label_to_groupname(const char *prefix, const char *in)
19497c478bd9Sstevel@tonic-gate {
19507c478bd9Sstevel@tonic-gate 	char *out, *cp;
19517c478bd9Sstevel@tonic-gate 	size_t len, piece_len;
19527c478bd9Sstevel@tonic-gate 
195367b0e063SAlbert Lee 	out = uu_zalloc(2 * max_scf_name_len + 1);
19547c478bd9Sstevel@tonic-gate 	if (out == NULL)
19557c478bd9Sstevel@tonic-gate 		return (NULL);
19567c478bd9Sstevel@tonic-gate 
195767b0e063SAlbert Lee 	(void) strlcpy(out, prefix, 2 * max_scf_name_len + 1);
19587c478bd9Sstevel@tonic-gate 
195967b0e063SAlbert Lee 	len = strlcat(out, in, 2 * max_scf_name_len + 1);
19607c478bd9Sstevel@tonic-gate 	if (len > max_scf_name_len) {
19617c478bd9Sstevel@tonic-gate 		/* Use the first half and the second half. */
19627c478bd9Sstevel@tonic-gate 		piece_len = (max_scf_name_len - 2) / 2;
19637c478bd9Sstevel@tonic-gate 
19647c478bd9Sstevel@tonic-gate 		(void) strncpy(out + piece_len, "..", 2);
19657c478bd9Sstevel@tonic-gate 
19667c478bd9Sstevel@tonic-gate 		(void) strcpy(out + piece_len + 2, out + (len - piece_len));
19677c478bd9Sstevel@tonic-gate 	}
19687c478bd9Sstevel@tonic-gate 
19697c478bd9Sstevel@tonic-gate 	/*
19707c478bd9Sstevel@tonic-gate 	 * Translate non-property characters to '_'.
19717c478bd9Sstevel@tonic-gate 	 */
19727c478bd9Sstevel@tonic-gate 	for (cp = out; *cp != '\0'; ++cp) {
19737c478bd9Sstevel@tonic-gate 		if (!(isalnum(*cp) || *cp == '_' || *cp == '-'))
19747c478bd9Sstevel@tonic-gate 			*cp = '_';
19757c478bd9Sstevel@tonic-gate 	}
19767c478bd9Sstevel@tonic-gate 
19777c478bd9Sstevel@tonic-gate 	return (out);
19787c478bd9Sstevel@tonic-gate }
19797c478bd9Sstevel@tonic-gate 
19801f6eb021SLiane Praza /*
19811f6eb021SLiane Praza  * If *p is NULL, astring_prop_value() first creates a property with the
19821f6eb021SLiane Praza  * name specified in prop_name.  The address of the newly created property
19831f6eb021SLiane Praza  * is placed in *p.
19841f6eb021SLiane Praza  *
19851f6eb021SLiane Praza  * In either case, newly created property or existing property, a new
19861f6eb021SLiane Praza  * SCF_TYPE_ASTRING value will created and attached to the property at *p.
19871f6eb021SLiane Praza  * The value of the newly created property is prop_value.
19881f6eb021SLiane Praza  *
19891f6eb021SLiane Praza  * free_flag is used to indicate whether or not the memory at prop_value
19901f6eb021SLiane Praza  * should be freed when the property is freed by a call to
19911f6eb021SLiane Praza  * internal_property_free().
19921f6eb021SLiane Praza  */
19931f6eb021SLiane Praza static void
astring_prop_value(property_t ** p,const char * prop_name,char * prop_value,boolean_t free_flag)19941f6eb021SLiane Praza astring_prop_value(property_t **p, const char *prop_name, char *prop_value,
19951f6eb021SLiane Praza     boolean_t free_flag)
19961f6eb021SLiane Praza {
19971f6eb021SLiane Praza 	value_t *v;
19981f6eb021SLiane Praza 
19991f6eb021SLiane Praza 	if (*p == NULL) {
20001f6eb021SLiane Praza 		/* Create the property */
20011f6eb021SLiane Praza 		*p = internal_property_new();
20021f6eb021SLiane Praza 		(*p)->sc_property_name = (char *)prop_name;
20031f6eb021SLiane Praza 		(*p)->sc_value_type = SCF_TYPE_ASTRING;
20041f6eb021SLiane Praza 	}
20051f6eb021SLiane Praza 
20061f6eb021SLiane Praza 	/* Add the property value to the property's list of values. */
20071f6eb021SLiane Praza 	v = internal_value_new();
20081f6eb021SLiane Praza 	v->sc_type = SCF_TYPE_ASTRING;
20091f6eb021SLiane Praza 	if (free_flag == B_TRUE)
20101f6eb021SLiane Praza 		v->sc_free = lxml_free_str;
20111f6eb021SLiane Praza 	v->sc_u.sc_string = prop_value;
20121f6eb021SLiane Praza 	internal_attach_value(*p, v);
20131f6eb021SLiane Praza }
20141f6eb021SLiane Praza 
20151f6eb021SLiane Praza /*
20161f6eb021SLiane Praza  * If p points to a null pointer, create an internal_separators property
20171f6eb021SLiane Praza  * saving the address at p.  For each character at seps create a property
20181f6eb021SLiane Praza  * value and attach it to the property at p.
20191f6eb021SLiane Praza  */
20201f6eb021SLiane Praza static void
seps_to_prop_values(property_t ** p,xmlChar * seps)20211f6eb021SLiane Praza seps_to_prop_values(property_t **p, xmlChar *seps)
20221f6eb021SLiane Praza {
20231f6eb021SLiane Praza 	value_t *v;
20241f6eb021SLiane Praza 	char val_str[2];
20251f6eb021SLiane Praza 
20261f6eb021SLiane Praza 	if (*p == NULL) {
20271f6eb021SLiane Praza 		*p = internal_property_new();
20281f6eb021SLiane Praza 		(*p)->sc_property_name =
20291f6eb021SLiane Praza 		    (char *)SCF_PROPERTY_INTERNAL_SEPARATORS;
20301f6eb021SLiane Praza 		(*p)->sc_value_type = SCF_TYPE_ASTRING;
20311f6eb021SLiane Praza 	}
20321f6eb021SLiane Praza 
20331f6eb021SLiane Praza 	/* Add the values to the property's list. */
20341f6eb021SLiane Praza 	val_str[1] = 0;		/* Terminate the string. */
20351f6eb021SLiane Praza 	for (; *seps != 0; seps++) {
20361f6eb021SLiane Praza 		v = internal_value_new();
20371f6eb021SLiane Praza 		v->sc_type = (*p)->sc_value_type;
20381f6eb021SLiane Praza 		v->sc_free = lxml_free_str;
20391f6eb021SLiane Praza 		val_str[0] = *seps;
204067b0e063SAlbert Lee 		v->sc_u.sc_string = safe_strdup(val_str);
20411f6eb021SLiane Praza 		internal_attach_value(*p, v);
20421f6eb021SLiane Praza 	}
20431f6eb021SLiane Praza }
20441f6eb021SLiane Praza 
20451f6eb021SLiane Praza /*
20461f6eb021SLiane Praza  * Create an internal_separators property and attach it to the property
20471f6eb021SLiane Praza  * group at pg.  The separator characters are provided in the text nodes
20481f6eb021SLiane Praza  * that are the children of seps.  Each separator character is stored as a
20491f6eb021SLiane Praza  * property value in the internal_separators property.
20501f6eb021SLiane Praza  */
20511f6eb021SLiane Praza static int
lxml_get_tm_internal_seps(entity_t * service,pgroup_t * pg,xmlNodePtr seps)20521f6eb021SLiane Praza lxml_get_tm_internal_seps(entity_t *service, pgroup_t *pg, xmlNodePtr seps)
20531f6eb021SLiane Praza {
20541f6eb021SLiane Praza 	xmlNodePtr cursor;
20551f6eb021SLiane Praza 	property_t *prop = NULL;
20561f6eb021SLiane Praza 	int r;
20571f6eb021SLiane Praza 
20581f6eb021SLiane Praza 	for (cursor = seps->xmlChildrenNode; cursor != NULL;
20591f6eb021SLiane Praza 	    cursor = cursor->next) {
20601f6eb021SLiane Praza 		if (strcmp("text", (const char *)cursor->name) == 0) {
20611f6eb021SLiane Praza 			seps_to_prop_values(&prop, cursor->content);
20621f6eb021SLiane Praza 		} else if (strcmp("comment", (const char *)cursor->name) != 0) {
20631f6eb021SLiane Praza 			uu_die(gettext("illegal element \"%s\" on %s element "
20641f6eb021SLiane Praza 			    "for \"%s\"\n"), cursor->name, seps->name,
20651f6eb021SLiane Praza 			    service->sc_name);
20661f6eb021SLiane Praza 		}
20671f6eb021SLiane Praza 	}
20681f6eb021SLiane Praza 	if (prop == NULL) {
20691f6eb021SLiane Praza 		semerr(gettext("The %s element in %s had an empty list of "
20701f6eb021SLiane Praza 		    "separators.\n"), (const char *)seps->name,
20711f6eb021SLiane Praza 		    service->sc_name);
20721f6eb021SLiane Praza 		return (-1);
20731f6eb021SLiane Praza 	}
20741f6eb021SLiane Praza 	r = internal_attach_property(pg, prop);
20751f6eb021SLiane Praza 	if (r != 0)
20761f6eb021SLiane Praza 		internal_property_free(prop);
20771f6eb021SLiane Praza 	return (r);
20781f6eb021SLiane Praza }
20791f6eb021SLiane Praza 
20807c478bd9Sstevel@tonic-gate static int
lxml_get_tm_manpage(entity_t * service,xmlNodePtr manpage)20817c478bd9Sstevel@tonic-gate lxml_get_tm_manpage(entity_t *service, xmlNodePtr manpage)
20827c478bd9Sstevel@tonic-gate {
20837c478bd9Sstevel@tonic-gate 	pgroup_t *pg;
20847c478bd9Sstevel@tonic-gate 	char *pgname;
208567b0e063SAlbert Lee 	char *name;
20867c478bd9Sstevel@tonic-gate 	xmlChar *title;
208767b0e063SAlbert Lee 	xmlChar *section;
20887c478bd9Sstevel@tonic-gate 
20897c478bd9Sstevel@tonic-gate 	/*
209067b0e063SAlbert Lee 	 * Fetch title and section attributes, convert to something sanitized,
209167b0e063SAlbert Lee 	 * and create property group.
20927c478bd9Sstevel@tonic-gate 	 */
20931f6eb021SLiane Praza 	title = xmlGetProp(manpage, (xmlChar *)title_attr);
209467b0e063SAlbert Lee 	if (title == NULL)
209567b0e063SAlbert Lee 		return (-1);
209667b0e063SAlbert Lee 	section = xmlGetProp(manpage, (xmlChar *)section_attr);
209767b0e063SAlbert Lee 	if (section == NULL) {
209867b0e063SAlbert Lee 		xmlFree(title);
209967b0e063SAlbert Lee 		return (-1);
210067b0e063SAlbert Lee 	}
210167b0e063SAlbert Lee 
210267b0e063SAlbert Lee 	name = safe_malloc(max_scf_name_len + 1);
210367b0e063SAlbert Lee 
210467b0e063SAlbert Lee 	/* Find existing property group with underscore separators */
210567b0e063SAlbert Lee 	(void) snprintf(name, max_scf_name_len + 1, "%s_%s", title, section);
210667b0e063SAlbert Lee 	pgname = lxml_label_to_groupname(SCF_PG_TM_MAN_PREFIX, name);
210767b0e063SAlbert Lee 	pg = internal_pgroup_find(service, pgname, SCF_GROUP_TEMPLATE);
210867b0e063SAlbert Lee 
210967b0e063SAlbert Lee 	uu_free(pgname);
211067b0e063SAlbert Lee 	(void) snprintf(name, max_scf_name_len + 1, "%s%s", title, section);
211167b0e063SAlbert Lee 	pgname = lxml_label_to_groupname(SCF_PG_TM_MAN_PREFIX, name);
211267b0e063SAlbert Lee 
211367b0e063SAlbert Lee 	if (pg == NULL) {
211467b0e063SAlbert Lee 		pg = internal_pgroup_find_or_create(service, pgname,
211567b0e063SAlbert Lee 		    SCF_GROUP_TEMPLATE);
211667b0e063SAlbert Lee 	} else {
211767b0e063SAlbert Lee 		/* Rename property group */
211867b0e063SAlbert Lee 		free((char *)pg->sc_pgroup_name);
211967b0e063SAlbert Lee 		pg->sc_pgroup_name = safe_strdup(pgname);
212067b0e063SAlbert Lee 	}
212167b0e063SAlbert Lee 
212267b0e063SAlbert Lee 	uu_free(pgname);
212367b0e063SAlbert Lee 	free(name);
212467b0e063SAlbert Lee 	xmlFree(section);
21251f6eb021SLiane Praza 	xmlFree(title);
21267c478bd9Sstevel@tonic-gate 
21277c478bd9Sstevel@tonic-gate 
21287c478bd9Sstevel@tonic-gate 	/*
21297c478bd9Sstevel@tonic-gate 	 * Each attribute is an astring property within the group.
21307c478bd9Sstevel@tonic-gate 	 */
21311f6eb021SLiane Praza 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_TM_TITLE,
21321f6eb021SLiane Praza 	    SCF_TYPE_ASTRING, manpage, title_attr) != 0 ||
21331f6eb021SLiane Praza 	    new_str_prop_from_attr(pg, SCF_PROPERTY_TM_SECTION,
21341f6eb021SLiane Praza 	    SCF_TYPE_ASTRING, manpage, section_attr) != 0 ||
21351f6eb021SLiane Praza 	    new_str_prop_from_attr(pg, SCF_PROPERTY_TM_MANPATH,
21361f6eb021SLiane Praza 	    SCF_TYPE_ASTRING, manpage, manpath_attr) != 0)
21377c478bd9Sstevel@tonic-gate 		return (-1);
21387c478bd9Sstevel@tonic-gate 
21397c478bd9Sstevel@tonic-gate 	return (0);
21407c478bd9Sstevel@tonic-gate }
21417c478bd9Sstevel@tonic-gate 
21427c478bd9Sstevel@tonic-gate static int
lxml_get_tm_doclink(entity_t * service,xmlNodePtr doc_link)21437c478bd9Sstevel@tonic-gate lxml_get_tm_doclink(entity_t *service, xmlNodePtr doc_link)
21447c478bd9Sstevel@tonic-gate {
21457c478bd9Sstevel@tonic-gate 	pgroup_t *pg;
21467c478bd9Sstevel@tonic-gate 	char *pgname;
21477c478bd9Sstevel@tonic-gate 	xmlChar *name;
21487c478bd9Sstevel@tonic-gate 
21497c478bd9Sstevel@tonic-gate 	/*
21507c478bd9Sstevel@tonic-gate 	 * Fetch name attribute, convert name to something sanitized, and create
21517c478bd9Sstevel@tonic-gate 	 * property group.
21527c478bd9Sstevel@tonic-gate 	 */
21531f6eb021SLiane Praza 	name = xmlGetProp(doc_link, (xmlChar *)name_attr);
215467b0e063SAlbert Lee 	if (name == NULL)
215567b0e063SAlbert Lee 		return (-1);
21567c478bd9Sstevel@tonic-gate 
21577c478bd9Sstevel@tonic-gate 	pgname = (char *)lxml_label_to_groupname(SCF_PG_TM_DOC_PREFIX,
21587c478bd9Sstevel@tonic-gate 	    (const char *)name);
21597c478bd9Sstevel@tonic-gate 
21607c478bd9Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(service, pgname,
21617c478bd9Sstevel@tonic-gate 	    (char *)SCF_GROUP_TEMPLATE);
216267b0e063SAlbert Lee 
216367b0e063SAlbert Lee 	uu_free(pgname);
21641f6eb021SLiane Praza 	xmlFree(name);
21657c478bd9Sstevel@tonic-gate 
21667c478bd9Sstevel@tonic-gate 	/*
21677c478bd9Sstevel@tonic-gate 	 * Each attribute is an astring property within the group.
21687c478bd9Sstevel@tonic-gate 	 */
21691f6eb021SLiane Praza 	if (new_str_prop_from_attr(pg, SCF_PROPERTY_TM_NAME, SCF_TYPE_ASTRING,
21701f6eb021SLiane Praza 	    doc_link, name_attr) != 0 ||
21711f6eb021SLiane Praza 	    new_str_prop_from_attr(pg, SCF_PROPERTY_TM_URI, SCF_TYPE_ASTRING,
21721f6eb021SLiane Praza 	    doc_link, uri_attr) != 0)
21737c478bd9Sstevel@tonic-gate 		return (-1);
21747c478bd9Sstevel@tonic-gate 
21757c478bd9Sstevel@tonic-gate 	return (0);
21767c478bd9Sstevel@tonic-gate }
21777c478bd9Sstevel@tonic-gate 
21787c478bd9Sstevel@tonic-gate static int
lxml_get_tm_documentation(entity_t * service,xmlNodePtr documentation)21797c478bd9Sstevel@tonic-gate lxml_get_tm_documentation(entity_t *service, xmlNodePtr documentation)
21807c478bd9Sstevel@tonic-gate {
21817c478bd9Sstevel@tonic-gate 	xmlNodePtr cursor;
21827c478bd9Sstevel@tonic-gate 
21837c478bd9Sstevel@tonic-gate 	for (cursor = documentation->xmlChildrenNode; cursor != NULL;
21847c478bd9Sstevel@tonic-gate 	    cursor = cursor->next) {
21857c478bd9Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
21867c478bd9Sstevel@tonic-gate 			continue;
21877c478bd9Sstevel@tonic-gate 
21887c478bd9Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
21897c478bd9Sstevel@tonic-gate 		case SC_MANPAGE:
21907c478bd9Sstevel@tonic-gate 			(void) lxml_get_tm_manpage(service, cursor);
21917c478bd9Sstevel@tonic-gate 			break;
21927c478bd9Sstevel@tonic-gate 		case SC_DOC_LINK:
21937c478bd9Sstevel@tonic-gate 			(void) lxml_get_tm_doclink(service, cursor);
21947c478bd9Sstevel@tonic-gate 			break;
21957c478bd9Sstevel@tonic-gate 		default:
21967c478bd9Sstevel@tonic-gate 			uu_die(gettext("illegal element \"%s\" on template "
21977c478bd9Sstevel@tonic-gate 			    "for service \"%s\"\n"),
21987c478bd9Sstevel@tonic-gate 			    cursor->name, service->sc_name);
21997c478bd9Sstevel@tonic-gate 		}
22007c478bd9Sstevel@tonic-gate 	}
22017c478bd9Sstevel@tonic-gate 
22027c478bd9Sstevel@tonic-gate 	return (0);
22037c478bd9Sstevel@tonic-gate }
22047c478bd9Sstevel@tonic-gate 
22057c478bd9Sstevel@tonic-gate static int
lxml_get_prop_pattern_attributes(pgroup_t * pg,xmlNodePtr cursor)22061f6eb021SLiane Praza lxml_get_prop_pattern_attributes(pgroup_t *pg, xmlNodePtr cursor)
22077c478bd9Sstevel@tonic-gate {
22081f6eb021SLiane Praza 	if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_TM_NAME,
22091f6eb021SLiane Praza 	    SCF_TYPE_ASTRING, cursor, name_attr, NULL) != 0) {
22101f6eb021SLiane Praza 		return (-1);
22117c478bd9Sstevel@tonic-gate 	}
22121f6eb021SLiane Praza 	if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_TM_TYPE,
22131f6eb021SLiane Praza 	    SCF_TYPE_ASTRING, cursor, type_attr, "") != 0) {
22141f6eb021SLiane Praza 		return (-1);
22151f6eb021SLiane Praza 	}
22161f6eb021SLiane Praza 	if (new_bool_prop_from_attr(pg, SCF_PROPERTY_TM_REQUIRED, cursor,
22171f6eb021SLiane Praza 	    required_attr) != 0)
22181f6eb021SLiane Praza 		return (-1);
22197c478bd9Sstevel@tonic-gate 	return (0);
22207c478bd9Sstevel@tonic-gate }
22217c478bd9Sstevel@tonic-gate 
22227c478bd9Sstevel@tonic-gate static int
lxml_get_tm_include_values(entity_t * service,pgroup_t * pg,xmlNodePtr include_values,const char * prop_name)22231f6eb021SLiane Praza lxml_get_tm_include_values(entity_t *service, pgroup_t *pg,
22241f6eb021SLiane Praza     xmlNodePtr include_values, const char *prop_name)
22257c478bd9Sstevel@tonic-gate {
22261f6eb021SLiane Praza 	boolean_t attach_to_pg = B_FALSE;
22277c478bd9Sstevel@tonic-gate 	property_t *p;
22281f6eb021SLiane Praza 	int r = 0;
22291f6eb021SLiane Praza 	char *type;
22307c478bd9Sstevel@tonic-gate 
22311f6eb021SLiane Praza 	/* Get the type attribute of the include_values element. */
22321f6eb021SLiane Praza 	type = (char *)xmlGetProp(include_values, (const xmlChar *)type_attr);
22331f6eb021SLiane Praza 	if ((type == NULL) || (*type == 0)) {
22341f6eb021SLiane Praza 		uu_die(gettext("%s element requires a %s attribute in the %s "
22351f6eb021SLiane Praza 		    "service.\n"), include_values->name, type_attr,
22361f6eb021SLiane Praza 		    service->sc_name);
22371f6eb021SLiane Praza 	}
22387c478bd9Sstevel@tonic-gate 
22391f6eb021SLiane Praza 	/* Add the type to the values of the prop_name property. */
22401f6eb021SLiane Praza 	p = internal_property_find(pg, prop_name);
22411f6eb021SLiane Praza 	if (p == NULL)
22421f6eb021SLiane Praza 		attach_to_pg = B_TRUE;
22431f6eb021SLiane Praza 	astring_prop_value(&p, prop_name, type, B_FALSE);
22441f6eb021SLiane Praza 	if (attach_to_pg == B_TRUE) {
22451f6eb021SLiane Praza 		r = internal_attach_property(pg, p);
22461f6eb021SLiane Praza 		if (r != 0)
22471f6eb021SLiane Praza 			internal_property_free(p);
22487c478bd9Sstevel@tonic-gate 	}
22491f6eb021SLiane Praza 	return (r);
22501f6eb021SLiane Praza }
22517c478bd9Sstevel@tonic-gate 
22521f6eb021SLiane Praza #define	RC_MIN		0
22531f6eb021SLiane Praza #define	RC_MAX		1
22541f6eb021SLiane Praza #define	RC_COUNT	2
22557c478bd9Sstevel@tonic-gate 
22561f6eb021SLiane Praza /*
22571f6eb021SLiane Praza  * Verify that the strings at min and max are valid numeric strings.  Also
22581f6eb021SLiane Praza  * verify that max is numerically >= min.
22591f6eb021SLiane Praza  *
22601f6eb021SLiane Praza  * 0 is returned if the range is valid, and -1 is returned if it is not.
22611f6eb021SLiane Praza  */
22621f6eb021SLiane Praza static int
verify_range(entity_t * service,xmlNodePtr range,char * min,char * max)22631f6eb021SLiane Praza verify_range(entity_t *service, xmlNodePtr range, char *min, char *max)
22641f6eb021SLiane Praza {
22651f6eb021SLiane Praza 	char *c;
22661f6eb021SLiane Praza 	int i;
22671f6eb021SLiane Praza 	int is_signed = 0;
22681f6eb021SLiane Praza 	int inverted = 0;
22691f6eb021SLiane Praza 	const char *limit[RC_COUNT];
22701f6eb021SLiane Praza 	char *strings[RC_COUNT];
22711f6eb021SLiane Praza 	uint64_t urange[RC_COUNT];	/* unsigned range. */
22721f6eb021SLiane Praza 	int64_t srange[RC_COUNT];	/* signed range. */
22731f6eb021SLiane Praza 
22741f6eb021SLiane Praza 	strings[RC_MIN] = min;
22751f6eb021SLiane Praza 	strings[RC_MAX] = max;
22761f6eb021SLiane Praza 	limit[RC_MIN] = min_attr;
22771f6eb021SLiane Praza 	limit[RC_MAX] = max_attr;
22781f6eb021SLiane Praza 
22791f6eb021SLiane Praza 	/* See if the range is signed. */
22801f6eb021SLiane Praza 	for (i = 0; (i < RC_COUNT) && (is_signed == 0); i++) {
22811f6eb021SLiane Praza 		c = strings[i];
22821f6eb021SLiane Praza 		while (isspace(*c)) {
22831f6eb021SLiane Praza 			c++;
22841f6eb021SLiane Praza 		}
22851f6eb021SLiane Praza 		if (*c == '-')
22861f6eb021SLiane Praza 			is_signed = 1;
22871f6eb021SLiane Praza 	}
22881f6eb021SLiane Praza 
22891f6eb021SLiane Praza 	/* Attempt to convert the strings. */
22901f6eb021SLiane Praza 	for (i = 0; i < RC_COUNT; i++) {
22911f6eb021SLiane Praza 		errno = 0;
22921f6eb021SLiane Praza 		if (is_signed) {
22931f6eb021SLiane Praza 			srange[i] = strtoll(strings[i], &c, 0);
22941f6eb021SLiane Praza 		} else {
22951f6eb021SLiane Praza 			urange[i] = strtoull(strings[i], &c, 0);
22961f6eb021SLiane Praza 		}
22971f6eb021SLiane Praza 		if ((errno != 0) || (c == strings[i]) || (*c != 0)) {
22981f6eb021SLiane Praza 			/* Conversion failed. */
22991f6eb021SLiane Praza 			uu_die(gettext("Unable to convert %s for the %s "
23001f6eb021SLiane Praza 			    "element in service %s.\n"), limit[i],
23011f6eb021SLiane Praza 			    (char *)range->name, service->sc_name);
23021f6eb021SLiane Praza 		}
23031f6eb021SLiane Praza 	}
23041f6eb021SLiane Praza 
23051f6eb021SLiane Praza 	/* Make sure that min is <= max */
23061f6eb021SLiane Praza 	if (is_signed) {
23071f6eb021SLiane Praza 		if (srange[RC_MAX] < srange[RC_MIN])
23081f6eb021SLiane Praza 			inverted = 1;
23091f6eb021SLiane Praza 	} else {
23101f6eb021SLiane Praza 		if (urange[RC_MAX] < urange[RC_MIN])
23111f6eb021SLiane Praza 			inverted = 1;
23121f6eb021SLiane Praza 	}
23131f6eb021SLiane Praza 	if (inverted != 0) {
23141f6eb021SLiane Praza 		semerr(gettext("Maximum less than minimum for the %s element "
23151f6eb021SLiane Praza 		    "in service %s.\n"), (char *)range->name,
23161f6eb021SLiane Praza 		    service->sc_name);
23171f6eb021SLiane Praza 		return (-1);
23181f6eb021SLiane Praza 	}
23191f6eb021SLiane Praza 
23201f6eb021SLiane Praza 	return (0);
23211f6eb021SLiane Praza }
23221f6eb021SLiane Praza 
23231f6eb021SLiane Praza /*
23241f6eb021SLiane Praza  * This, function creates a property named prop_name.  The range element
23251f6eb021SLiane Praza  * should have two attributes -- min and max.  The property value then
23261f6eb021SLiane Praza  * becomes the concatenation of their value separated by a comma.  The
23271f6eb021SLiane Praza  * property is then attached to the property group at pg.
23281f6eb021SLiane Praza  *
23291f6eb021SLiane Praza  * If pg already contains a property with a name of prop_name, it is only
23301f6eb021SLiane Praza  * necessary to create a new value and attach it to the existing property.
23311f6eb021SLiane Praza  */
23321f6eb021SLiane Praza static int
lxml_get_tm_range(entity_t * service,pgroup_t * pg,xmlNodePtr range,const char * prop_name)23331f6eb021SLiane Praza lxml_get_tm_range(entity_t *service, pgroup_t *pg, xmlNodePtr range,
23341f6eb021SLiane Praza     const char *prop_name)
23351f6eb021SLiane Praza {
23361f6eb021SLiane Praza 	boolean_t attach_to_pg = B_FALSE;
23371f6eb021SLiane Praza 	char *max;
23381f6eb021SLiane Praza 	char *min;
23391f6eb021SLiane Praza 	property_t *p;
23401f6eb021SLiane Praza 	char *prop_value;
23411f6eb021SLiane Praza 	int r = 0;
23421f6eb021SLiane Praza 
23431f6eb021SLiane Praza 	/* Get max and min from the XML description. */
23441f6eb021SLiane Praza 	max = (char *)xmlGetProp(range, (xmlChar *)max_attr);
23451f6eb021SLiane Praza 	if ((max == NULL) || (*max == 0)) {
23461f6eb021SLiane Praza 		uu_die(gettext("%s element is missing the %s attribute in "
23471f6eb021SLiane Praza 		    "service %s.\n"), (char *)range->name, max_attr,
23481f6eb021SLiane Praza 		    service->sc_name);
23491f6eb021SLiane Praza 	}
23501f6eb021SLiane Praza 	min = (char *)xmlGetProp(range, (xmlChar *)min_attr);
23511f6eb021SLiane Praza 	if ((min == NULL) || (*min == 0)) {
23521f6eb021SLiane Praza 		uu_die(gettext("%s element is missing the %s attribute in "
23531f6eb021SLiane Praza 		    "service %s.\n"), (char *)range->name, min_attr,
23541f6eb021SLiane Praza 		    service->sc_name);
23551f6eb021SLiane Praza 	}
23561f6eb021SLiane Praza 	if (verify_range(service, range, min, max) != 0) {
23571f6eb021SLiane Praza 		xmlFree(min);
23581f6eb021SLiane Praza 		xmlFree(max);
23591f6eb021SLiane Praza 		return (-1);
23601f6eb021SLiane Praza 	}
23611f6eb021SLiane Praza 
23621f6eb021SLiane Praza 	/* Property value is concatenation of min and max. */
23631f6eb021SLiane Praza 	prop_value = safe_malloc(max_scf_value_len + 1);
23641f6eb021SLiane Praza 	if (snprintf(prop_value, max_scf_value_len + 1, "%s,%s", min, max) >=
23651f6eb021SLiane Praza 	    max_scf_value_len + 1) {
23661f6eb021SLiane Praza 		uu_die(gettext("min and max are too long for the %s element "
23671f6eb021SLiane Praza 		    "of %s.\n"), (char *)range->name, service->sc_name);
23681f6eb021SLiane Praza 	}
23691f6eb021SLiane Praza 	xmlFree(min);
23701f6eb021SLiane Praza 	xmlFree(max);
23711f6eb021SLiane Praza 
23721f6eb021SLiane Praza 	/*
23731f6eb021SLiane Praza 	 * If necessary create the property and attach it to the property
23741f6eb021SLiane Praza 	 * group.
23751f6eb021SLiane Praza 	 */
23761f6eb021SLiane Praza 	p = internal_property_find(pg, prop_name);
23771f6eb021SLiane Praza 	if (p == NULL)
23781f6eb021SLiane Praza 		attach_to_pg = B_TRUE;
23791f6eb021SLiane Praza 	astring_prop_value(&p, prop_name, prop_value, B_TRUE);
23801f6eb021SLiane Praza 	if (attach_to_pg == B_TRUE) {
23811f6eb021SLiane Praza 		r = internal_attach_property(pg, p);
23821f6eb021SLiane Praza 		if (r != 0) {
23831f6eb021SLiane Praza 			internal_property_free(p);
23841f6eb021SLiane Praza 		}
23851f6eb021SLiane Praza 	}
23861f6eb021SLiane Praza 	return (r);
23871f6eb021SLiane Praza }
23881f6eb021SLiane Praza 
23891f6eb021SLiane Praza /*
23901f6eb021SLiane Praza  * Determine how many plain characters are represented by count Base32
23911f6eb021SLiane Praza  * encoded characters.  5 plain text characters are converted to 8 Base32
23921f6eb021SLiane Praza  * characters.
23931f6eb021SLiane Praza  */
23941f6eb021SLiane Praza static size_t
encoded_count_to_plain(size_t count)23951f6eb021SLiane Praza encoded_count_to_plain(size_t count)
23961f6eb021SLiane Praza {
23971f6eb021SLiane Praza 	return (5 * ((count + 7) / 8));
23981f6eb021SLiane Praza }
23991f6eb021SLiane Praza 
24001f6eb021SLiane Praza /*
24011f6eb021SLiane Praza  * The value element contains 0 or 1 common_name element followed by 0 or 1
24021f6eb021SLiane Praza  * description element.  It also has a required attribute called "name".
24031f6eb021SLiane Praza  * The common_name and description are stored as property values in pg.
24041f6eb021SLiane Praza  * The property names are:
24051f6eb021SLiane Praza  *	value_<name>_common_name_<lang>
24061f6eb021SLiane Praza  *	value_<name>_description_<lang>
24071f6eb021SLiane Praza  *
24081f6eb021SLiane Praza  * The <name> portion of the preceeding proper names requires more
24091f6eb021SLiane Praza  * explanation.  Ideally it would just the name attribute of this value
24101f6eb021SLiane Praza  * element.  Unfortunately, the name attribute can contain characters that
24111f6eb021SLiane Praza  * are not legal in a property name.  Thus, we base 32 encode the name
24121f6eb021SLiane Praza  * attribute and use that for <name>.
24131f6eb021SLiane Praza  *
24141f6eb021SLiane Praza  * There are cases where the caller needs to know the name, so it is
24151f6eb021SLiane Praza  * returned through the name_value pointer if it is not NULL.
24161f6eb021SLiane Praza  *
24171f6eb021SLiane Praza  * Parameters:
24181f6eb021SLiane Praza  *	service -	Information about the service that is being
24191f6eb021SLiane Praza  *			processed.  This function only uses this parameter
24201f6eb021SLiane Praza  *			for producing error messages.
24211f6eb021SLiane Praza  *
24221f6eb021SLiane Praza  *	pg -		The property group to receive the newly created
24231f6eb021SLiane Praza  *			properties.
24241f6eb021SLiane Praza  *
24251f6eb021SLiane Praza  *	value -		Pointer to the value element in the XML tree.
24261f6eb021SLiane Praza  *
24271f6eb021SLiane Praza  *	name_value -	Address to receive the value of the name attribute.
24281f6eb021SLiane Praza  *			The caller must free the memory.
24291f6eb021SLiane Praza  */
24301f6eb021SLiane Praza static int
lxml_get_tm_value_element(entity_t * service,pgroup_t * pg,xmlNodePtr value,char ** name_value)24311f6eb021SLiane Praza lxml_get_tm_value_element(entity_t *service, pgroup_t *pg, xmlNodePtr value,
24321f6eb021SLiane Praza     char **name_value)
24331f6eb021SLiane Praza {
24341f6eb021SLiane Praza 	char *common_name_fmt;
24351f6eb021SLiane Praza 	xmlNodePtr cursor;
24361f6eb021SLiane Praza 	char *description_fmt;
24371f6eb021SLiane Praza 	char *encoded_value = NULL;
24381f6eb021SLiane Praza 	size_t extra;
24391f6eb021SLiane Praza 	char *value_name;
24401f6eb021SLiane Praza 	int r = 0;
24411f6eb021SLiane Praza 
24421f6eb021SLiane Praza 	common_name_fmt = safe_malloc(max_scf_name_len + 1);
24431f6eb021SLiane Praza 	description_fmt = safe_malloc(max_scf_name_len + 1);
24441f6eb021SLiane Praza 
24451f6eb021SLiane Praza 	/*
24461f6eb021SLiane Praza 	 * Get the value of our name attribute, so that we can use it to
24471f6eb021SLiane Praza 	 * construct property names.
24481f6eb021SLiane Praza 	 */
24491f6eb021SLiane Praza 	value_name = (char *)xmlGetProp(value, (xmlChar *)name_attr);
24501f6eb021SLiane Praza 	/* The value name must be present, but it can be empty. */
24511f6eb021SLiane Praza 	if (value_name == NULL) {
24521f6eb021SLiane Praza 		uu_die(gettext("%s element requires a %s attribute in the %s "
24531f6eb021SLiane Praza 		    "service.\n"), (char *)value->name, name_attr,
24541f6eb021SLiane Praza 		    service->sc_name);
24551f6eb021SLiane Praza 	}
24561f6eb021SLiane Praza 
24571f6eb021SLiane Praza 	/*
24581f6eb021SLiane Praza 	 * The value_name may contain characters that are not valid in in a
24591f6eb021SLiane Praza 	 * property name.  So we will encode value_name and then use the
24601f6eb021SLiane Praza 	 * encoded value in the property name.
24611f6eb021SLiane Praza 	 */
24621f6eb021SLiane Praza 	encoded_value = safe_malloc(max_scf_name_len + 1);
24631f6eb021SLiane Praza 	if (scf_encode32(value_name, strlen(value_name), encoded_value,
24641f6eb021SLiane Praza 	    max_scf_name_len + 1, &extra, SCF_ENCODE32_PAD) != 0) {
24651f6eb021SLiane Praza 		extra = encoded_count_to_plain(extra - max_scf_name_len);
24661f6eb021SLiane Praza 		uu_die(gettext("Constructed property name is %u characters "
24671f6eb021SLiane Praza 		    "too long for value \"%s\" in the %s service.\n"),
24681f6eb021SLiane Praza 		    extra, value_name, service->sc_name);
24691f6eb021SLiane Praza 	}
24701f6eb021SLiane Praza 	if ((extra = snprintf(common_name_fmt, max_scf_name_len + 1,
24711f6eb021SLiane Praza 	    VALUE_COMMON_NAME_FMT, SCF_PROPERTY_TM_VALUE_PREFIX,
24721f6eb021SLiane Praza 	    encoded_value)) >= max_scf_name_len + 1) {
24731f6eb021SLiane Praza 		extra = encoded_count_to_plain(extra - max_scf_name_len);
24741f6eb021SLiane Praza 		uu_die(gettext("Name attribute is "
24751f6eb021SLiane Praza 		    "%u characters too long for %s in service %s\n"),
24761f6eb021SLiane Praza 		    extra, (char *)value->name, service->sc_name);
24771f6eb021SLiane Praza 	}
24781f6eb021SLiane Praza 	if ((extra = snprintf(description_fmt, max_scf_name_len + 1,
24791f6eb021SLiane Praza 	    VALUE_DESCRIPTION_FMT, SCF_PROPERTY_TM_VALUE_PREFIX,
24801f6eb021SLiane Praza 	    encoded_value)) >= max_scf_name_len + 1) {
24811f6eb021SLiane Praza 		extra = encoded_count_to_plain(extra - max_scf_name_len);
24821f6eb021SLiane Praza 		uu_die(gettext("Name attribute is "
24831f6eb021SLiane Praza 		    "%u characters too long for %s in service %s\n"),
24841f6eb021SLiane Praza 		    extra, (char *)value->name, service->sc_name);
24851f6eb021SLiane Praza 	}
24861f6eb021SLiane Praza 
24871f6eb021SLiane Praza 	for (cursor = value->xmlChildrenNode;
24881f6eb021SLiane Praza 	    cursor != NULL;
24891f6eb021SLiane Praza 	    cursor = cursor->next) {
24901f6eb021SLiane Praza 		if (lxml_ignorable_block(cursor))
24911f6eb021SLiane Praza 			continue;
24921f6eb021SLiane Praza 		switch (lxml_xlate_element(cursor->name)) {
24931f6eb021SLiane Praza 		case SC_COMMON_NAME:
24941f6eb021SLiane Praza 			r = lxml_get_all_loctext(service, pg, cursor,
24951f6eb021SLiane Praza 			    common_name_fmt, (const char *)cursor->name);
24961f6eb021SLiane Praza 			break;
24971f6eb021SLiane Praza 		case SC_DESCRIPTION:
24981f6eb021SLiane Praza 			r = lxml_get_all_loctext(service, pg, cursor,
24991f6eb021SLiane Praza 			    description_fmt, (const char *)cursor->name);
25001f6eb021SLiane Praza 			break;
25011f6eb021SLiane Praza 		default:
25021f6eb021SLiane Praza 			uu_die(gettext("\"%s\" is an illegal element in %s "
25031f6eb021SLiane Praza 			    "of service %s\n"), (char *)cursor->name,
25041f6eb021SLiane Praza 			    (char *)value->name, service->sc_name);
25051f6eb021SLiane Praza 		}
25061f6eb021SLiane Praza 		if (r != 0)
25071f6eb021SLiane Praza 			break;
25081f6eb021SLiane Praza 	}
25091f6eb021SLiane Praza 
25101f6eb021SLiane Praza 	free(description_fmt);
25111f6eb021SLiane Praza 	free(common_name_fmt);
25121f6eb021SLiane Praza 	if (r == 0) {
25131f6eb021SLiane Praza 		*name_value = safe_strdup(value_name);
25141f6eb021SLiane Praza 	}
25151f6eb021SLiane Praza 	xmlFree(value_name);
25161f6eb021SLiane Praza 	free(encoded_value);
25171f6eb021SLiane Praza 	return (r);
25181f6eb021SLiane Praza }
25191f6eb021SLiane Praza 
25201f6eb021SLiane Praza static int
lxml_get_tm_choices(entity_t * service,pgroup_t * pg,xmlNodePtr choices)25211f6eb021SLiane Praza lxml_get_tm_choices(entity_t *service, pgroup_t *pg, xmlNodePtr choices)
25221f6eb021SLiane Praza {
25231f6eb021SLiane Praza 	xmlNodePtr cursor;
25241f6eb021SLiane Praza 	char *name_value;
25251f6eb021SLiane Praza 	property_t *name_prop = NULL;
25261f6eb021SLiane Praza 	int r = 0;
25271f6eb021SLiane Praza 
25281f6eb021SLiane Praza 	for (cursor = choices->xmlChildrenNode;
25291f6eb021SLiane Praza 	    (cursor != NULL) && (r == 0);
25301f6eb021SLiane Praza 	    cursor = cursor->next) {
25311f6eb021SLiane Praza 		if (lxml_ignorable_block(cursor))
25321f6eb021SLiane Praza 			continue;
25331f6eb021SLiane Praza 		switch (lxml_xlate_element(cursor->name)) {
25341f6eb021SLiane Praza 		case SC_INCLUDE_VALUES:
25351f6eb021SLiane Praza 			(void) lxml_get_tm_include_values(service, pg, cursor,
25361f6eb021SLiane Praza 			    SCF_PROPERTY_TM_CHOICES_INCLUDE_VALUES);
25371f6eb021SLiane Praza 			break;
25381f6eb021SLiane Praza 		case SC_RANGE:
25391f6eb021SLiane Praza 			r = lxml_get_tm_range(service, pg, cursor,
25401f6eb021SLiane Praza 			    SCF_PROPERTY_TM_CHOICES_RANGE);
25411f6eb021SLiane Praza 			if (r != 0)
25421f6eb021SLiane Praza 				goto out;
25431f6eb021SLiane Praza 			break;
25441f6eb021SLiane Praza 		case SC_VALUE:
25451f6eb021SLiane Praza 			r = lxml_get_tm_value_element(service, pg, cursor,
25461f6eb021SLiane Praza 			    &name_value);
25471f6eb021SLiane Praza 			if (r == 0) {
25481f6eb021SLiane Praza 				/*
25491f6eb021SLiane Praza 				 * There is no need to free the memory
25501f6eb021SLiane Praza 				 * associated with name_value, because the
25511f6eb021SLiane Praza 				 * property value will end up pointing to
25521f6eb021SLiane Praza 				 * the memory.
25531f6eb021SLiane Praza 				 */
25541f6eb021SLiane Praza 				astring_prop_value(&name_prop,
25551f6eb021SLiane Praza 				    SCF_PROPERTY_TM_CHOICES_NAME, name_value,
25561f6eb021SLiane Praza 				    B_TRUE);
25571f6eb021SLiane Praza 			} else {
25581f6eb021SLiane Praza 				goto out;
25591f6eb021SLiane Praza 			}
25601f6eb021SLiane Praza 			break;
25611f6eb021SLiane Praza 		default:
25621f6eb021SLiane Praza 			uu_die(gettext("%s is an invalid element of "
25631f6eb021SLiane Praza 			    "choices for service %s.\n"),  cursor->name,
25641f6eb021SLiane Praza 			    service->sc_name);
25651f6eb021SLiane Praza 		}
25661f6eb021SLiane Praza 	}
25671f6eb021SLiane Praza 
25681f6eb021SLiane Praza out:
25691f6eb021SLiane Praza 	/* Attach the name property if we created one. */
25701f6eb021SLiane Praza 	if ((r == 0) && (name_prop != NULL)) {
25711f6eb021SLiane Praza 		r = internal_attach_property(pg, name_prop);
25721f6eb021SLiane Praza 	}
25731f6eb021SLiane Praza 	if ((r != 0) && (name_prop != NULL)) {
25741f6eb021SLiane Praza 		internal_property_free(name_prop);
25751f6eb021SLiane Praza 	}
25761f6eb021SLiane Praza 
25771f6eb021SLiane Praza 	return (r);
25781f6eb021SLiane Praza }
25791f6eb021SLiane Praza 
25801f6eb021SLiane Praza static int
lxml_get_tm_constraints(entity_t * service,pgroup_t * pg,xmlNodePtr constraints)25811f6eb021SLiane Praza lxml_get_tm_constraints(entity_t *service, pgroup_t *pg, xmlNodePtr constraints)
25821f6eb021SLiane Praza {
25831f6eb021SLiane Praza 	xmlNodePtr cursor;
25841f6eb021SLiane Praza 	char *name_value;
25851f6eb021SLiane Praza 	property_t *name_prop = NULL;
25861f6eb021SLiane Praza 	int r = 0;
25871f6eb021SLiane Praza 
25881f6eb021SLiane Praza 	for (cursor = constraints->xmlChildrenNode;
25891f6eb021SLiane Praza 	    (cursor != NULL) && (r == 0);
25901f6eb021SLiane Praza 	    cursor = cursor->next) {
25911f6eb021SLiane Praza 		if (lxml_ignorable_block(cursor))
25921f6eb021SLiane Praza 			continue;
25931f6eb021SLiane Praza 		switch (lxml_xlate_element(cursor->name)) {
25941f6eb021SLiane Praza 		case SC_RANGE:
25951f6eb021SLiane Praza 			r = lxml_get_tm_range(service, pg, cursor,
25961f6eb021SLiane Praza 			    SCF_PROPERTY_TM_CONSTRAINT_RANGE);
25971f6eb021SLiane Praza 			if (r != 0)
25981f6eb021SLiane Praza 				goto out;
25991f6eb021SLiane Praza 			break;
26001f6eb021SLiane Praza 		case SC_VALUE:
26011f6eb021SLiane Praza 			r = lxml_get_tm_value_element(service, pg, cursor,
26021f6eb021SLiane Praza 			    &name_value);
26031f6eb021SLiane Praza 			if (r == 0) {
26041f6eb021SLiane Praza 				/*
26051f6eb021SLiane Praza 				 * There is no need to free the memory
26061f6eb021SLiane Praza 				 * associated with name_value, because the
26071f6eb021SLiane Praza 				 * property value will end up pointing to
26081f6eb021SLiane Praza 				 * the memory.
26091f6eb021SLiane Praza 				 */
26101f6eb021SLiane Praza 				astring_prop_value(&name_prop,
26111f6eb021SLiane Praza 				    SCF_PROPERTY_TM_CONSTRAINT_NAME, name_value,
26121f6eb021SLiane Praza 				    B_TRUE);
26131f6eb021SLiane Praza 			} else {
26141f6eb021SLiane Praza 				goto out;
26151f6eb021SLiane Praza 			}
26161f6eb021SLiane Praza 			break;
26171f6eb021SLiane Praza 		default:
26181f6eb021SLiane Praza 			uu_die(gettext("%s is an invalid element of "
26191f6eb021SLiane Praza 			    "constraints for service %s.\n"),  cursor->name,
26201f6eb021SLiane Praza 			    service->sc_name);
26211f6eb021SLiane Praza 		}
26221f6eb021SLiane Praza 	}
26231f6eb021SLiane Praza 
26241f6eb021SLiane Praza out:
26251f6eb021SLiane Praza 	/* Attach the name property if we created one. */
26261f6eb021SLiane Praza 	if ((r == 0) && (name_prop != NULL)) {
26271f6eb021SLiane Praza 		r = internal_attach_property(pg, name_prop);
26281f6eb021SLiane Praza 	}
26291f6eb021SLiane Praza 	if ((r != 0) && (name_prop != NULL)) {
26301f6eb021SLiane Praza 		internal_property_free(name_prop);
26311f6eb021SLiane Praza 	}
26321f6eb021SLiane Praza 
26331f6eb021SLiane Praza 	return (r);
26341f6eb021SLiane Praza }
26351f6eb021SLiane Praza 
26361f6eb021SLiane Praza /*
26371f6eb021SLiane Praza  * The values element contains one or more value elements.
26381f6eb021SLiane Praza  */
26391f6eb021SLiane Praza static int
lxml_get_tm_values(entity_t * service,pgroup_t * pg,xmlNodePtr values)26401f6eb021SLiane Praza lxml_get_tm_values(entity_t *service, pgroup_t *pg, xmlNodePtr values)
26411f6eb021SLiane Praza {
26421f6eb021SLiane Praza 	xmlNodePtr cursor;
26431f6eb021SLiane Praza 	char *name_value;
26441f6eb021SLiane Praza 	property_t *name_prop = NULL;
26451f6eb021SLiane Praza 	int r = 0;
26461f6eb021SLiane Praza 
26471f6eb021SLiane Praza 	for (cursor = values->xmlChildrenNode;
26481f6eb021SLiane Praza 	    (cursor != NULL) && (r == 0);
26491f6eb021SLiane Praza 	    cursor = cursor->next) {
26501f6eb021SLiane Praza 		if (lxml_ignorable_block(cursor))
26511f6eb021SLiane Praza 			continue;
26521f6eb021SLiane Praza 		if (lxml_xlate_element(cursor->name) != SC_VALUE) {
26531f6eb021SLiane Praza 			uu_die(gettext("\"%s\" is an illegal element in the "
26541f6eb021SLiane Praza 			    "%s element of %s\n"), (char *)cursor->name,
26551f6eb021SLiane Praza 			    (char *)values->name, service->sc_name);
26561f6eb021SLiane Praza 		}
26571f6eb021SLiane Praza 		r = lxml_get_tm_value_element(service, pg, cursor, &name_value);
26581f6eb021SLiane Praza 		if (r == 0) {
26591f6eb021SLiane Praza 			/*
26601f6eb021SLiane Praza 			 * There is no need to free the memory
26611f6eb021SLiane Praza 			 * associated with name_value, because the
26621f6eb021SLiane Praza 			 * property value will end up pointing to
26631f6eb021SLiane Praza 			 * the memory.
26641f6eb021SLiane Praza 			 */
26651f6eb021SLiane Praza 			astring_prop_value(&name_prop,
26661f6eb021SLiane Praza 			    SCF_PROPERTY_TM_VALUES_NAME, name_value,
26671f6eb021SLiane Praza 			    B_TRUE);
26681f6eb021SLiane Praza 		}
26691f6eb021SLiane Praza 	}
26701f6eb021SLiane Praza 
26711f6eb021SLiane Praza 	/* Attach the name property if we created one. */
26721f6eb021SLiane Praza 	if ((r == 0) && (name_prop != NULL)) {
26731f6eb021SLiane Praza 		r = internal_attach_property(pg, name_prop);
26741f6eb021SLiane Praza 	}
26751f6eb021SLiane Praza 	if ((r != 0) && (name_prop != NULL)) {
26761f6eb021SLiane Praza 		internal_property_free(name_prop);
26771f6eb021SLiane Praza 	}
26781f6eb021SLiane Praza 
26791f6eb021SLiane Praza 	return (r);
26801f6eb021SLiane Praza }
26811f6eb021SLiane Praza 
26821f6eb021SLiane Praza /*
26831f6eb021SLiane Praza  * This function processes a prop_pattern element within a pg_pattern XML
26841f6eb021SLiane Praza  * element.  First it creates a property group to hold the prop_pattern
26851f6eb021SLiane Praza  * information.  The name of this property group is the concatenation of:
26861f6eb021SLiane Praza  *	- SCF_PG_TM_PROP_PATTERN_PREFIX
26871f6eb021SLiane Praza  *	- The unique part of the property group name of the enclosing
26881f6eb021SLiane Praza  *	  pg_pattern.  The property group name of the enclosing pg_pattern
26891f6eb021SLiane Praza  *	  is passed to us in pgpat_name.  The unique part, is the part
26901f6eb021SLiane Praza  *	  following SCF_PG_TM_PG_PATTERN_PREFIX.
26911f6eb021SLiane Praza  *	- The name of this prop_pattern element.
26921f6eb021SLiane Praza  *
26931f6eb021SLiane Praza  * After creating the property group, the prop_pattern attributes are saved
26941f6eb021SLiane Praza  * as properties in the PG.  Finally, the prop_pattern elements are
26951f6eb021SLiane Praza  * processed and added to the PG.
26961f6eb021SLiane Praza  */
26971f6eb021SLiane Praza static int
lxml_get_tm_prop_pattern(entity_t * service,xmlNodePtr prop_pattern,const char * pgpat_name)26981f6eb021SLiane Praza lxml_get_tm_prop_pattern(entity_t *service, xmlNodePtr prop_pattern,
26991f6eb021SLiane Praza     const char *pgpat_name)
27001f6eb021SLiane Praza {
27011f6eb021SLiane Praza 	xmlNodePtr cursor;
27021f6eb021SLiane Praza 	int extra;
27031f6eb021SLiane Praza 	pgroup_t *pg;
27041f6eb021SLiane Praza 	property_t *p;
27051f6eb021SLiane Praza 	char *pg_name;
27061f6eb021SLiane Praza 	size_t prefix_len;
27071f6eb021SLiane Praza 	xmlChar *prop_pattern_name;
27081f6eb021SLiane Praza 	int r;
27091f6eb021SLiane Praza 	const char *unique;
27101f6eb021SLiane Praza 	value_t *v;
27111f6eb021SLiane Praza 
27121f6eb021SLiane Praza 	/* Find the unique part of the pg_pattern property group name. */
27131f6eb021SLiane Praza 	prefix_len = strlen(SCF_PG_TM_PG_PAT_BASE);
27141f6eb021SLiane Praza 	assert(strncmp(pgpat_name, SCF_PG_TM_PG_PAT_BASE, prefix_len) == 0);
27151f6eb021SLiane Praza 	unique = pgpat_name + prefix_len;
27161f6eb021SLiane Praza 
27171f6eb021SLiane Praza 	/*
27181f6eb021SLiane Praza 	 * We need to get the value of the name attribute first.  The
27191f6eb021SLiane Praza 	 * prop_pattern name as well as the name of the enclosing
27201f6eb021SLiane Praza 	 * pg_pattern both constitute part of the name of the property
27211f6eb021SLiane Praza 	 * group that we will create.
27221f6eb021SLiane Praza 	 */
27231f6eb021SLiane Praza 	prop_pattern_name = xmlGetProp(prop_pattern, (xmlChar *)name_attr);
27241f6eb021SLiane Praza 	if ((prop_pattern_name == NULL) || (*prop_pattern_name == 0)) {
27251f6eb021SLiane Praza 		semerr(gettext("prop_pattern name is missing for %s\n"),
27261f6eb021SLiane Praza 		    service->sc_name);
27271f6eb021SLiane Praza 		return (-1);
27281f6eb021SLiane Praza 	}
27291f6eb021SLiane Praza 	if (uu_check_name((const char *)prop_pattern_name,
27301f6eb021SLiane Praza 	    UU_NAME_DOMAIN) != 0) {
27311f6eb021SLiane Praza 		semerr(gettext("prop_pattern name, \"%s\", for %s is not "
27321f6eb021SLiane Praza 		    "valid.\n"), prop_pattern_name, service->sc_name);
27331f6eb021SLiane Praza 		xmlFree(prop_pattern_name);
27341f6eb021SLiane Praza 		return (-1);
27351f6eb021SLiane Praza 	}
27361f6eb021SLiane Praza 	pg_name = safe_malloc(max_scf_name_len + 1);
27371f6eb021SLiane Praza 	if ((extra = snprintf(pg_name, max_scf_name_len + 1, "%s%s_%s",
27381f6eb021SLiane Praza 	    SCF_PG_TM_PROP_PATTERN_PREFIX, unique,
27391f6eb021SLiane Praza 	    (char *)prop_pattern_name)) >= max_scf_name_len + 1) {
27401f6eb021SLiane Praza 		uu_die(gettext("prop_pattern name, \"%s\", for %s is %d "
27411f6eb021SLiane Praza 		    "characters too long\n"), (char *)prop_pattern_name,
27421f6eb021SLiane Praza 		    service->sc_name, extra - max_scf_name_len);
27431f6eb021SLiane Praza 	}
27441f6eb021SLiane Praza 
27451f6eb021SLiane Praza 	/*
27461f6eb021SLiane Praza 	 * Create the property group, the property referencing the pg_pattern
27471f6eb021SLiane Praza 	 * name, and add the prop_pattern attributes to the property group.
27481f6eb021SLiane Praza 	 */
27491f6eb021SLiane Praza 	pg = internal_pgroup_create_strict(service, pg_name,
27501f6eb021SLiane Praza 	    SCF_GROUP_TEMPLATE_PROP_PATTERN);
27511f6eb021SLiane Praza 	if (pg == NULL) {
27521f6eb021SLiane Praza 		uu_die(gettext("Property group for prop_pattern, \"%s\", "
27531f6eb021SLiane Praza 		    "already exists in %s\n"), prop_pattern_name,
27541f6eb021SLiane Praza 		    service->sc_name);
27551f6eb021SLiane Praza 	}
27561f6eb021SLiane Praza 
27571f6eb021SLiane Praza 	p = internal_property_create(SCF_PROPERTY_TM_PG_PATTERN,
27581f6eb021SLiane Praza 	    SCF_TYPE_ASTRING, 1, safe_strdup(pgpat_name));
27591f6eb021SLiane Praza 	/*
27601f6eb021SLiane Praza 	 * Unfortunately, internal_property_create() does not set the free
27611f6eb021SLiane Praza 	 * function for the value, so we'll set it now.
27621f6eb021SLiane Praza 	 */
27631f6eb021SLiane Praza 	v = uu_list_first(p->sc_property_values);
27641f6eb021SLiane Praza 	v->sc_free = lxml_free_str;
27651f6eb021SLiane Praza 	if (internal_attach_property(pg, p) != 0)
27661f6eb021SLiane Praza 		internal_property_free(p);
27671f6eb021SLiane Praza 
27681f6eb021SLiane Praza 
27691f6eb021SLiane Praza 	r = lxml_get_prop_pattern_attributes(pg, prop_pattern);
27701f6eb021SLiane Praza 	if (r != 0)
27711f6eb021SLiane Praza 		goto out;
27721f6eb021SLiane Praza 
27731f6eb021SLiane Praza 	/*
27741f6eb021SLiane Praza 	 * Now process the elements of prop_pattern
27751f6eb021SLiane Praza 	 */
27761f6eb021SLiane Praza 	for (cursor = prop_pattern->xmlChildrenNode;
27771f6eb021SLiane Praza 	    cursor != NULL;
27781f6eb021SLiane Praza 	    cursor = cursor->next) {
27791f6eb021SLiane Praza 		if (lxml_ignorable_block(cursor))
27801f6eb021SLiane Praza 			continue;
27811f6eb021SLiane Praza 
27821f6eb021SLiane Praza 		switch (lxml_xlate_element(cursor->name)) {
27831f6eb021SLiane Praza 		case SC_CARDINALITY:
27841f6eb021SLiane Praza 			r = lxml_get_tm_cardinality(service, pg, cursor);
27851f6eb021SLiane Praza 			if (r != 0)
27861f6eb021SLiane Praza 				goto out;
27871f6eb021SLiane Praza 			break;
27881f6eb021SLiane Praza 		case SC_CHOICES:
27891f6eb021SLiane Praza 			r = lxml_get_tm_choices(service, pg, cursor);
27901f6eb021SLiane Praza 			if (r != 0)
27911f6eb021SLiane Praza 				goto out;
27921f6eb021SLiane Praza 			break;
27931f6eb021SLiane Praza 		case SC_COMMON_NAME:
27941f6eb021SLiane Praza 			(void) lxml_get_all_loctext(service, pg, cursor,
27951f6eb021SLiane Praza 			    COMMON_NAME_FMT, (const char *)cursor->name);
27961f6eb021SLiane Praza 			break;
27971f6eb021SLiane Praza 		case SC_CONSTRAINTS:
27981f6eb021SLiane Praza 			r = lxml_get_tm_constraints(service, pg, cursor);
27991f6eb021SLiane Praza 			if (r != 0)
28001f6eb021SLiane Praza 				goto out;
28011f6eb021SLiane Praza 			break;
28021f6eb021SLiane Praza 		case SC_DESCRIPTION:
28031f6eb021SLiane Praza 			(void) lxml_get_all_loctext(service, pg, cursor,
28041f6eb021SLiane Praza 			    DESCRIPTION_FMT, (const char *)cursor->name);
28051f6eb021SLiane Praza 			break;
28061f6eb021SLiane Praza 		case SC_INTERNAL_SEPARATORS:
28071f6eb021SLiane Praza 			r = lxml_get_tm_internal_seps(service, pg, cursor);
28081f6eb021SLiane Praza 			if (r != 0)
28091f6eb021SLiane Praza 				goto out;
28101f6eb021SLiane Praza 			break;
28111f6eb021SLiane Praza 		case SC_UNITS:
28121f6eb021SLiane Praza 			(void) lxml_get_all_loctext(service, pg, cursor,
28131f6eb021SLiane Praza 			    UNITS_FMT, "units");
28141f6eb021SLiane Praza 			break;
28151f6eb021SLiane Praza 		case SC_VALUES:
28161f6eb021SLiane Praza 			(void) lxml_get_tm_values(service, pg, cursor);
28171f6eb021SLiane Praza 			break;
28181f6eb021SLiane Praza 		case SC_VISIBILITY:
28191f6eb021SLiane Praza 			/*
28201f6eb021SLiane Praza 			 * The visibility element is empty, so we only need
28211f6eb021SLiane Praza 			 * to proccess the value attribute.
28221f6eb021SLiane Praza 			 */
28231f6eb021SLiane Praza 			(void) new_str_prop_from_attr(pg,
28241f6eb021SLiane Praza 			    SCF_PROPERTY_TM_VISIBILITY, SCF_TYPE_ASTRING,
28251f6eb021SLiane Praza 			    cursor, value_attr);
28261f6eb021SLiane Praza 			break;
28271f6eb021SLiane Praza 		default:
28281f6eb021SLiane Praza 			uu_die(gettext("illegal element \"%s\" in prop_pattern "
28291f6eb021SLiane Praza 			    "for service \"%s\"\n"), cursor->name,
28301f6eb021SLiane Praza 			    service->sc_name);
28311f6eb021SLiane Praza 		}
28321f6eb021SLiane Praza 	}
28331f6eb021SLiane Praza 
28341f6eb021SLiane Praza out:
28351f6eb021SLiane Praza 	xmlFree(prop_pattern_name);
28361f6eb021SLiane Praza 	free(pg_name);
28371f6eb021SLiane Praza 	return (r);
28381f6eb021SLiane Praza }
28391f6eb021SLiane Praza 
28401f6eb021SLiane Praza /*
28411f6eb021SLiane Praza  * Get the pg_pattern attributes and save them as properties in the
28421f6eb021SLiane Praza  * property group at pg.  The pg_pattern element accepts four attributes --
28431f6eb021SLiane Praza  * name, type, required and target.
28441f6eb021SLiane Praza  */
28451f6eb021SLiane Praza static int
lxml_get_pg_pattern_attributes(pgroup_t * pg,xmlNodePtr cursor)28461f6eb021SLiane Praza lxml_get_pg_pattern_attributes(pgroup_t *pg, xmlNodePtr cursor)
28471f6eb021SLiane Praza {
28481f6eb021SLiane Praza 	if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_TM_NAME,
28491f6eb021SLiane Praza 	    SCF_TYPE_ASTRING, cursor, name_attr, NULL) != 0) {
28501f6eb021SLiane Praza 		return (-1);
28511f6eb021SLiane Praza 	}
28521f6eb021SLiane Praza 	if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_TM_TYPE,
28531f6eb021SLiane Praza 	    SCF_TYPE_ASTRING, cursor, type_attr, NULL) != 0) {
28541f6eb021SLiane Praza 		return (-1);
28551f6eb021SLiane Praza 	}
28561f6eb021SLiane Praza 	if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_TM_TARGET,
28571f6eb021SLiane Praza 	    SCF_TYPE_ASTRING, cursor, target_attr, NULL) != 0) {
28581f6eb021SLiane Praza 		return (-1);
28591f6eb021SLiane Praza 	}
28601f6eb021SLiane Praza 	if (new_bool_prop_from_attr(pg, SCF_PROPERTY_TM_REQUIRED, cursor,
28611f6eb021SLiane Praza 	    required_attr) != 0)
28621f6eb021SLiane Praza 		return (-1);
28631f6eb021SLiane Praza 	return (0);
28641f6eb021SLiane Praza }
28651f6eb021SLiane Praza 
28661f6eb021SLiane Praza /*
28671f6eb021SLiane Praza  * There are several restrictions on the pg_pattern attributes that cannot
28681f6eb021SLiane Praza  * be specifed in the service bundle DTD.  This function verifies that
28691f6eb021SLiane Praza  * those restrictions have been satisfied.  The restrictions are:
28701f6eb021SLiane Praza  *
28711f6eb021SLiane Praza  *	- The target attribute may have a value of "instance" only when the
28721f6eb021SLiane Praza  *	  template block is in a service declaration.
28731f6eb021SLiane Praza  *
28741f6eb021SLiane Praza  *	- The target attribute may have a value of "delegate" only when the
28751f6eb021SLiane Praza  *	  template block applies to a restarter.
28761f6eb021SLiane Praza  *
28771f6eb021SLiane Praza  *	- The target attribute may have a value of "all" only when the
28781f6eb021SLiane Praza  *	  template block applies to the master restarter.
28791f6eb021SLiane Praza  *
28801f6eb021SLiane Praza  * The function returns 0 on success and -1 on failure.
28811f6eb021SLiane Praza  */
28821f6eb021SLiane Praza static int
verify_pg_pattern_attributes(entity_t * s,pgroup_t * pg)28831f6eb021SLiane Praza verify_pg_pattern_attributes(entity_t *s, pgroup_t *pg)
28841f6eb021SLiane Praza {
28851f6eb021SLiane Praza 	int is_restarter;
28861f6eb021SLiane Praza 	property_t *target;
28871f6eb021SLiane Praza 	value_t *v;
28881f6eb021SLiane Praza 
28891f6eb021SLiane Praza 	/* Find the value of the target property. */
28901f6eb021SLiane Praza 	target = internal_property_find(pg, SCF_PROPERTY_TM_TARGET);
28911f6eb021SLiane Praza 	if (target == NULL) {
28921f6eb021SLiane Praza 		uu_die(gettext("pg_pattern is missing the %s attribute "
28931f6eb021SLiane Praza 		    "in %s\n"), target_attr, s->sc_name);
28941f6eb021SLiane Praza 		return (-1);
28951f6eb021SLiane Praza 	}
28961f6eb021SLiane Praza 	v = uu_list_first(target->sc_property_values);
28971f6eb021SLiane Praza 	assert(v != NULL);
28981f6eb021SLiane Praza 	assert(v->sc_type == SCF_TYPE_ASTRING);
28991f6eb021SLiane Praza 
29001f6eb021SLiane Praza 	/*
29011f6eb021SLiane Praza 	 * If target has a value of instance, the template must be in a
29021f6eb021SLiane Praza 	 * service object.
29031f6eb021SLiane Praza 	 */
29041f6eb021SLiane Praza 	if (strcmp(v->sc_u.sc_string, "instance") == 0) {
29051f6eb021SLiane Praza 		if (s->sc_etype != SVCCFG_SERVICE_OBJECT) {
29061f6eb021SLiane Praza 			uu_warn(gettext("pg_pattern %s attribute may only "
29071f6eb021SLiane Praza 			    "have a value of \"instance\" when it is in a "
29081f6eb021SLiane Praza 			    "service declaration.\n"), target_attr);
29091f6eb021SLiane Praza 			return (-1);
29101f6eb021SLiane Praza 		}
29111f6eb021SLiane Praza 	}
29121f6eb021SLiane Praza 
29131f6eb021SLiane Praza 	/*
29141f6eb021SLiane Praza 	 * If target has a value of "delegate", the template must be in a
29151f6eb021SLiane Praza 	 * restarter.
29161f6eb021SLiane Praza 	 */
29171f6eb021SLiane Praza 	if (strcmp(v->sc_u.sc_string, "delegate") == 0) {
29181f6eb021SLiane Praza 		is_restarter = 0;
29191f6eb021SLiane Praza 		if ((s->sc_etype == SVCCFG_SERVICE_OBJECT) &&
29201f6eb021SLiane Praza 		    (s->sc_u.sc_service.sc_service_type == SVCCFG_RESTARTER)) {
29211f6eb021SLiane Praza 			is_restarter = 1;
29221f6eb021SLiane Praza 		}
29231f6eb021SLiane Praza 		if ((s->sc_etype == SVCCFG_INSTANCE_OBJECT) &&
29241f6eb021SLiane Praza 		    (s->sc_parent->sc_u.sc_service.sc_service_type ==
29251f6eb021SLiane Praza 		    SVCCFG_RESTARTER)) {
29261f6eb021SLiane Praza 			is_restarter = 1;
29271f6eb021SLiane Praza 		}
29281f6eb021SLiane Praza 		if (is_restarter == 0) {
29291f6eb021SLiane Praza 			uu_warn(gettext("pg_pattern %s attribute has a "
29301f6eb021SLiane Praza 			    "value of \"delegate\" but is not in a "
29311f6eb021SLiane Praza 			    "restarter service\n"), target_attr);
29321f6eb021SLiane Praza 			return (-1);
29331f6eb021SLiane Praza 		}
29341f6eb021SLiane Praza 	}
29351f6eb021SLiane Praza 
29361f6eb021SLiane Praza 	/*
29371f6eb021SLiane Praza 	 * If target has a value of "all", the template must be in the
29381f6eb021SLiane Praza 	 * global (SCF_SERVICE_GLOBAL) service.
29391f6eb021SLiane Praza 	 */
29401f6eb021SLiane Praza 	if (strcmp(v->sc_u.sc_string, all_value) == 0) {
29411f6eb021SLiane Praza 		if (s->sc_etype != SVCCFG_SERVICE_OBJECT) {
29421f6eb021SLiane Praza 			uu_warn(gettext("pg_pattern %s attribute has a "
29431f6eb021SLiane Praza 			    "value of \"%s\" but is not in a "
29441f6eb021SLiane Praza 			    "service entity.\n"), target_attr, all_value);
29451f6eb021SLiane Praza 			return (-1);
29461f6eb021SLiane Praza 		}
29471f6eb021SLiane Praza 		if (strcmp(s->sc_fmri, SCF_SERVICE_GLOBAL) != 0) {
29481f6eb021SLiane Praza 			uu_warn(gettext("pg_pattern %s attribute has a "
29491f6eb021SLiane Praza 			    "value of \"%s\" but is in the \"%s\" service.  "
29501f6eb021SLiane Praza 			    "pg_patterns with target \"%s\" are only allowed "
29511f6eb021SLiane Praza 			    "in the global service.\n"),
29521f6eb021SLiane Praza 			    target_attr, all_value, s->sc_fmri, all_value);
29531f6eb021SLiane Praza 			return (-1);
29541f6eb021SLiane Praza 		}
29551f6eb021SLiane Praza 	}
29561f6eb021SLiane Praza 
29571f6eb021SLiane Praza 	return (0);
29581f6eb021SLiane Praza }
29591f6eb021SLiane Praza 
29601f6eb021SLiane Praza static int
lxml_get_tm_pg_pattern(entity_t * service,xmlNodePtr pg_pattern)29611f6eb021SLiane Praza lxml_get_tm_pg_pattern(entity_t *service, xmlNodePtr pg_pattern)
29621f6eb021SLiane Praza {
29631f6eb021SLiane Praza 	xmlNodePtr cursor;
29641f6eb021SLiane Praza 	int out_len;
29651f6eb021SLiane Praza 	xmlChar *name;
29661f6eb021SLiane Praza 	pgroup_t *pg = NULL;
29671f6eb021SLiane Praza 	char *pg_name;
29681f6eb021SLiane Praza 	int r = -1;
29691f6eb021SLiane Praza 	xmlChar *type;
29701f6eb021SLiane Praza 
29711f6eb021SLiane Praza 	pg_name = safe_malloc(max_scf_name_len + 1);
29721f6eb021SLiane Praza 
29731f6eb021SLiane Praza 	/*
29741f6eb021SLiane Praza 	 * Get the name and type attributes.  Their presence or absence
29751f6eb021SLiane Praza 	 * determines whcih prefix we will use for the property group name.
29761f6eb021SLiane Praza 	 * There are four cases -- neither attribute is present, both are
29771f6eb021SLiane Praza 	 * present, only name is present or only type is present.
29781f6eb021SLiane Praza 	 */
29791f6eb021SLiane Praza 	name = xmlGetProp(pg_pattern, (xmlChar *)name_attr);
29801f6eb021SLiane Praza 	type = xmlGetProp(pg_pattern, (xmlChar *)type_attr);
29811f6eb021SLiane Praza 	if ((name == NULL) || (*name == 0)) {
29821f6eb021SLiane Praza 		if ((type == NULL) || (*type == 0)) {
29831f6eb021SLiane Praza 			/* PG name contains only the prefix in this case */
29841f6eb021SLiane Praza 			if (strlcpy(pg_name, SCF_PG_TM_PG_PATTERN_PREFIX,
29851f6eb021SLiane Praza 			    max_scf_name_len + 1) >= max_scf_name_len + 1) {
29861f6eb021SLiane Praza 				uu_die(gettext("Unable to create pg_pattern "
29871f6eb021SLiane Praza 				    "property for %s\n"), service->sc_name);
29881f6eb021SLiane Praza 			}
29891f6eb021SLiane Praza 		} else {
29901f6eb021SLiane Praza 			/*
29911f6eb021SLiane Praza 			 * If we have a type and no name, the type becomes
29921f6eb021SLiane Praza 			 * part of the pg_pattern property group name.
29931f6eb021SLiane Praza 			 */
29941f6eb021SLiane Praza 			if ((out_len = snprintf(pg_name, max_scf_name_len + 1,
29951f6eb021SLiane Praza 			    "%s%s", SCF_PG_TM_PG_PATTERN_T_PREFIX, type)) >=
29961f6eb021SLiane Praza 			    max_scf_name_len + 1) {
29971f6eb021SLiane Praza 				uu_die(gettext("pg_pattern type is for %s is "
29981f6eb021SLiane Praza 				    "%d bytes too long\n"), service->sc_name,
29991f6eb021SLiane Praza 				    out_len - max_scf_name_len);
30001f6eb021SLiane Praza 			}
30011f6eb021SLiane Praza 		}
30021f6eb021SLiane Praza 	} else {
30031f6eb021SLiane Praza 		const char *prefix;
30041f6eb021SLiane Praza 
30051f6eb021SLiane Praza 		/* Make sure that the name is valid. */
30061f6eb021SLiane Praza 		if (uu_check_name((const char *)name, UU_NAME_DOMAIN) != 0) {
30071f6eb021SLiane Praza 			semerr(gettext("pg_pattern name attribute, \"%s\", "
30081f6eb021SLiane Praza 			    "for %s is invalid\n"), name, service->sc_name);
30091f6eb021SLiane Praza 			goto out;
30101f6eb021SLiane Praza 		}
30111f6eb021SLiane Praza 
30121f6eb021SLiane Praza 		/*
30131f6eb021SLiane Praza 		 * As long as the pg_pattern has a name, it becomes part of
30141f6eb021SLiane Praza 		 * the name of the pg_pattern property group name.  We
30151f6eb021SLiane Praza 		 * merely need to pick the appropriate prefix.
30161f6eb021SLiane Praza 		 */
30171f6eb021SLiane Praza 		if ((type == NULL) || (*type == 0)) {
30181f6eb021SLiane Praza 			prefix = SCF_PG_TM_PG_PATTERN_N_PREFIX;
30191f6eb021SLiane Praza 		} else {
30201f6eb021SLiane Praza 			prefix = SCF_PG_TM_PG_PATTERN_NT_PREFIX;
30211f6eb021SLiane Praza 		}
30221f6eb021SLiane Praza 		if ((out_len = snprintf(pg_name, max_scf_name_len + 1, "%s%s",
30231f6eb021SLiane Praza 		    prefix, name)) >= max_scf_name_len + 1) {
30241f6eb021SLiane Praza 			uu_die(gettext("pg_pattern property group name "
30251f6eb021SLiane Praza 			    "for %s is %d bytes too long\n"), service->sc_name,
30261f6eb021SLiane Praza 			    out_len - max_scf_name_len);
30271f6eb021SLiane Praza 		}
30281f6eb021SLiane Praza 	}
30291f6eb021SLiane Praza 
30301f6eb021SLiane Praza 	/*
30311f6eb021SLiane Praza 	 * Create the property group for holding this pg_pattern
30321f6eb021SLiane Praza 	 * information, and capture the pg_pattern attributes.
30331f6eb021SLiane Praza 	 */
30341f6eb021SLiane Praza 	pg = internal_pgroup_create_strict(service, pg_name,
30351f6eb021SLiane Praza 	    SCF_GROUP_TEMPLATE_PG_PATTERN);
30361f6eb021SLiane Praza 	if (pg == NULL) {
30371f6eb021SLiane Praza 		if ((name == NULL) || (*name == 0)) {
30381f6eb021SLiane Praza 			if ((type == NULL) ||(*type == 0)) {
30391f6eb021SLiane Praza 				semerr(gettext("pg_pattern with empty name and "
30401f6eb021SLiane Praza 				    "type is not unique in %s\n"),
30411f6eb021SLiane Praza 				    service->sc_name);
30421f6eb021SLiane Praza 			} else {
30431f6eb021SLiane Praza 				semerr(gettext("pg_pattern with empty name and "
30441f6eb021SLiane Praza 				    "type \"%s\" is not unique in %s\n"),
30451f6eb021SLiane Praza 				    type, service->sc_name);
30461f6eb021SLiane Praza 			}
30471f6eb021SLiane Praza 		} else {
30481f6eb021SLiane Praza 			if ((type == NULL) || (*type == 0)) {
30491f6eb021SLiane Praza 				semerr(gettext("pg_pattern with name \"%s\" "
30501f6eb021SLiane Praza 				    "and empty type is not unique in %s\n"),
30511f6eb021SLiane Praza 				    name, service->sc_name);
30521f6eb021SLiane Praza 			} else {
30531f6eb021SLiane Praza 				semerr(gettext("pg_pattern with name \"%s\" "
30541f6eb021SLiane Praza 				    "and type \"%s\" is not unique in %s\n"),
30551f6eb021SLiane Praza 				    name, type, service->sc_name);
30561f6eb021SLiane Praza 			}
30571f6eb021SLiane Praza 		}
30581f6eb021SLiane Praza 		goto out;
30591f6eb021SLiane Praza 	}
30601f6eb021SLiane Praza 
30611f6eb021SLiane Praza 	/*
30621f6eb021SLiane Praza 	 * Get the pg_pattern attributes from the manifest and verify
30631f6eb021SLiane Praza 	 * that they satisfy our restrictions.
30641f6eb021SLiane Praza 	 */
30651f6eb021SLiane Praza 	r = lxml_get_pg_pattern_attributes(pg, pg_pattern);
30661f6eb021SLiane Praza 	if (r != 0)
30671f6eb021SLiane Praza 		goto out;
30681f6eb021SLiane Praza 	if (verify_pg_pattern_attributes(service, pg) != 0) {
30691f6eb021SLiane Praza 		semerr(gettext("Invalid pg_pattern attributes in %s\n"),
30701f6eb021SLiane Praza 		    service->sc_name);
30711f6eb021SLiane Praza 		r = -1;
30721f6eb021SLiane Praza 		goto out;
30731f6eb021SLiane Praza 	}
30741f6eb021SLiane Praza 
30751f6eb021SLiane Praza 	/*
30761f6eb021SLiane Praza 	 * Now process all of the elements of pg_pattern.
30771f6eb021SLiane Praza 	 */
30781f6eb021SLiane Praza 	for (cursor = pg_pattern->xmlChildrenNode;
30791f6eb021SLiane Praza 	    cursor != NULL;
30801f6eb021SLiane Praza 	    cursor = cursor->next) {
30811f6eb021SLiane Praza 		if (lxml_ignorable_block(cursor))
30821f6eb021SLiane Praza 			continue;
30831f6eb021SLiane Praza 
30841f6eb021SLiane Praza 		switch (lxml_xlate_element(cursor->name)) {
30851f6eb021SLiane Praza 		case SC_COMMON_NAME:
30861f6eb021SLiane Praza 			(void) lxml_get_all_loctext(service, pg, cursor,
30871f6eb021SLiane Praza 			    COMMON_NAME_FMT, (const char *)cursor->name);
30881f6eb021SLiane Praza 			break;
30891f6eb021SLiane Praza 		case SC_DESCRIPTION:
30901f6eb021SLiane Praza 			(void) lxml_get_all_loctext(service, pg, cursor,
30911f6eb021SLiane Praza 			    DESCRIPTION_FMT, (const char *)cursor->name);
30921f6eb021SLiane Praza 			break;
30931f6eb021SLiane Praza 		case SC_PROP_PATTERN:
30941f6eb021SLiane Praza 			r = lxml_get_tm_prop_pattern(service, cursor,
30951f6eb021SLiane Praza 			    pg_name);
30961f6eb021SLiane Praza 			if (r != 0)
30971f6eb021SLiane Praza 				goto out;
30981f6eb021SLiane Praza 			break;
30991f6eb021SLiane Praza 		default:
31001f6eb021SLiane Praza 			uu_die(gettext("illegal element \"%s\" in pg_pattern "
31011f6eb021SLiane Praza 			    "for service \"%s\"\n"), cursor->name,
31021f6eb021SLiane Praza 			    service->sc_name);
31031f6eb021SLiane Praza 		}
31041f6eb021SLiane Praza 	}
31051f6eb021SLiane Praza 
31061f6eb021SLiane Praza out:
31071f6eb021SLiane Praza 	if ((r != 0) && (pg != NULL)) {
31081f6eb021SLiane Praza 		internal_detach_pgroup(service, pg);
31091f6eb021SLiane Praza 		internal_pgroup_free(pg);
31101f6eb021SLiane Praza 	}
31111f6eb021SLiane Praza 	free(pg_name);
31121f6eb021SLiane Praza 	xmlFree(name);
31131f6eb021SLiane Praza 	xmlFree(type);
31141f6eb021SLiane Praza 
31151f6eb021SLiane Praza 	return (r);
31161f6eb021SLiane Praza }
31171f6eb021SLiane Praza 
31181f6eb021SLiane Praza static int
lxml_get_template(entity_t * service,xmlNodePtr templ)31191f6eb021SLiane Praza lxml_get_template(entity_t *service, xmlNodePtr templ)
31201f6eb021SLiane Praza {
31211f6eb021SLiane Praza 	xmlNodePtr cursor;
31221f6eb021SLiane Praza 
31231f6eb021SLiane Praza 	for (cursor = templ->xmlChildrenNode; cursor != NULL;
31241f6eb021SLiane Praza 	    cursor = cursor->next) {
31251f6eb021SLiane Praza 		if (lxml_ignorable_block(cursor))
31261f6eb021SLiane Praza 			continue;
31271f6eb021SLiane Praza 
31281f6eb021SLiane Praza 		switch (lxml_xlate_element(cursor->name)) {
31291f6eb021SLiane Praza 		case SC_COMMON_NAME:
31301f6eb021SLiane Praza 			(void) lxml_get_tm_common_name(service, cursor);
31311f6eb021SLiane Praza 			break;
31321f6eb021SLiane Praza 		case SC_DESCRIPTION:
31331f6eb021SLiane Praza 			(void) lxml_get_tm_description(service, cursor);
31341f6eb021SLiane Praza 			break;
31351f6eb021SLiane Praza 		case SC_DOCUMENTATION:
31361f6eb021SLiane Praza 			(void) lxml_get_tm_documentation(service, cursor);
31371f6eb021SLiane Praza 			break;
31381f6eb021SLiane Praza 		case SC_PG_PATTERN:
31391f6eb021SLiane Praza 			if (lxml_get_tm_pg_pattern(service, cursor) != 0)
31401f6eb021SLiane Praza 				return (-1);
31411f6eb021SLiane Praza 			break;
31421f6eb021SLiane Praza 		default:
31431f6eb021SLiane Praza 			uu_die(gettext("illegal element \"%s\" on template "
31441f6eb021SLiane Praza 			    "for service \"%s\"\n"),
31451f6eb021SLiane Praza 			    cursor->name, service->sc_name);
31461f6eb021SLiane Praza 		}
31471f6eb021SLiane Praza 	}
31481f6eb021SLiane Praza 
31491f6eb021SLiane Praza 	return (0);
31501f6eb021SLiane Praza }
31511f6eb021SLiane Praza 
31521f6eb021SLiane Praza static int
lxml_get_default_instance(entity_t * service,xmlNodePtr definst)31531f6eb021SLiane Praza lxml_get_default_instance(entity_t *service, xmlNodePtr definst)
31541f6eb021SLiane Praza {
31551f6eb021SLiane Praza 	entity_t *i;
31561f6eb021SLiane Praza 	xmlChar *enabled;
31571f6eb021SLiane Praza 	pgroup_t *pg;
31581f6eb021SLiane Praza 	property_t *p;
31591f6eb021SLiane Praza 	char *package;
31601f6eb021SLiane Praza 	uint64_t enabled_val = 0;
31611f6eb021SLiane Praza 
31621f6eb021SLiane Praza 	i = internal_instance_new("default");
31631f6eb021SLiane Praza 
31641f6eb021SLiane Praza 	if ((enabled = xmlGetProp(definst, (xmlChar *)enabled_attr)) != NULL) {
31651f6eb021SLiane Praza 		enabled_val = (strcmp(true, (const char *)enabled) == 0) ?
31661f6eb021SLiane Praza 		    1 : 0;
31671f6eb021SLiane Praza 		xmlFree(enabled);
31681f6eb021SLiane Praza 	}
31691f6eb021SLiane Praza 
31701f6eb021SLiane Praza 	/*
31711f6eb021SLiane Praza 	 * New general property group with enabled boolean property set.
31721f6eb021SLiane Praza 	 */
31731f6eb021SLiane Praza 
3174f329b923SSean Wilcox 	i->sc_op = service->sc_op;
31751f6eb021SLiane Praza 	pg = internal_pgroup_new();
31767c478bd9Sstevel@tonic-gate 	(void) internal_attach_pgroup(i, pg);
31777c478bd9Sstevel@tonic-gate 
31787c478bd9Sstevel@tonic-gate 	pg->sc_pgroup_name = (char *)scf_pg_general;
31797c478bd9Sstevel@tonic-gate 	pg->sc_pgroup_type = (char *)scf_group_framework;
31807c478bd9Sstevel@tonic-gate 	pg->sc_pgroup_flags = 0;
31817c478bd9Sstevel@tonic-gate 
31827c478bd9Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_ENABLED, SCF_TYPE_BOOLEAN, 1,
31837c478bd9Sstevel@tonic-gate 	    enabled_val);
31847c478bd9Sstevel@tonic-gate 
31857c478bd9Sstevel@tonic-gate 	(void) internal_attach_property(pg, p);
31867c478bd9Sstevel@tonic-gate 
31877c478bd9Sstevel@tonic-gate 	/*
31887c478bd9Sstevel@tonic-gate 	 * Add general/package property if PKGINST is set.
31897c478bd9Sstevel@tonic-gate 	 */
31907c478bd9Sstevel@tonic-gate 	if ((package = getenv("PKGINST")) != NULL) {
31917c478bd9Sstevel@tonic-gate 		p = internal_property_create(SCF_PROPERTY_PACKAGE,
31927c478bd9Sstevel@tonic-gate 		    SCF_TYPE_ASTRING, 1, package);
31937c478bd9Sstevel@tonic-gate 
31947c478bd9Sstevel@tonic-gate 		(void) internal_attach_property(pg, p);
31957c478bd9Sstevel@tonic-gate 	}
31967c478bd9Sstevel@tonic-gate 
31977c478bd9Sstevel@tonic-gate 	return (internal_attach_entity(service, i));
31987c478bd9Sstevel@tonic-gate }
31997c478bd9Sstevel@tonic-gate 
32007c478bd9Sstevel@tonic-gate /*
32017c478bd9Sstevel@tonic-gate  * Translate an instance element into an internal property tree, added to
3202687293e1SAntonello Cruz  * service.  If op is SVCCFG_OP_APPLY (i.e., apply a profile), set the
3203687293e1SAntonello Cruz  * enabled property to override.
3204f329b923SSean Wilcox  *
3205f329b923SSean Wilcox  * If op is SVCCFG_OP_APPLY (i.e., apply a profile), do not allow for
3206f329b923SSean Wilcox  * modification of template data.
32077c478bd9Sstevel@tonic-gate  */
32087c478bd9Sstevel@tonic-gate static int
lxml_get_instance(entity_t * service,xmlNodePtr inst,bundle_type_t bt,svccfg_op_t op)3209687293e1SAntonello Cruz lxml_get_instance(entity_t *service, xmlNodePtr inst, bundle_type_t bt,
3210687293e1SAntonello Cruz     svccfg_op_t op)
32117c478bd9Sstevel@tonic-gate {
32127c478bd9Sstevel@tonic-gate 	entity_t *i;
32137c478bd9Sstevel@tonic-gate 	pgroup_t *pg;
32147c478bd9Sstevel@tonic-gate 	property_t *p;
32157c478bd9Sstevel@tonic-gate 	xmlNodePtr cursor;
32167c478bd9Sstevel@tonic-gate 	xmlChar *enabled;
3217687293e1SAntonello Cruz 	int r, e_val;
32187c478bd9Sstevel@tonic-gate 
32197c478bd9Sstevel@tonic-gate 	/*
32207c478bd9Sstevel@tonic-gate 	 * Fetch its attributes, as appropriate.
32217c478bd9Sstevel@tonic-gate 	 */
32227c478bd9Sstevel@tonic-gate 	i = internal_instance_new((char *)xmlGetProp(inst,
32237c478bd9Sstevel@tonic-gate 	    (xmlChar *)name_attr));
32247c478bd9Sstevel@tonic-gate 
32257c478bd9Sstevel@tonic-gate 	/*
32267c478bd9Sstevel@tonic-gate 	 * Note that this must be done before walking the children so that
32277c478bd9Sstevel@tonic-gate 	 * sc_fmri is set in case we enter lxml_get_dependent().
32287c478bd9Sstevel@tonic-gate 	 */
32297c478bd9Sstevel@tonic-gate 	r = internal_attach_entity(service, i);
32307c478bd9Sstevel@tonic-gate 	if (r != 0)
32317c478bd9Sstevel@tonic-gate 		return (r);
32327c478bd9Sstevel@tonic-gate 
3233f329b923SSean Wilcox 	i->sc_op = op;
32347c478bd9Sstevel@tonic-gate 	enabled = xmlGetProp(inst, (xmlChar *)enabled_attr);
32357c478bd9Sstevel@tonic-gate 
3236687293e1SAntonello Cruz 	if (enabled == NULL) {
3237687293e1SAntonello Cruz 		if (bt == SVCCFG_MANIFEST) {
3238687293e1SAntonello Cruz 			semerr(gettext("Instance \"%s\" missing attribute "
3239687293e1SAntonello Cruz 			    "\"%s\".\n"), i->sc_name, enabled_attr);
3240687293e1SAntonello Cruz 			return (-1);
3241687293e1SAntonello Cruz 		}
3242687293e1SAntonello Cruz 	} else {	/* enabled != NULL */
3243687293e1SAntonello Cruz 		if (strcmp(true, (const char *)enabled) != 0 &&
3244687293e1SAntonello Cruz 		    strcmp(false, (const char *)enabled) != 0) {
3245687293e1SAntonello Cruz 			xmlFree(enabled);
3246687293e1SAntonello Cruz 			semerr(gettext("Invalid enabled value\n"));
3247687293e1SAntonello Cruz 			return (-1);
3248687293e1SAntonello Cruz 		}
3249687293e1SAntonello Cruz 		pg = internal_pgroup_new();
3250687293e1SAntonello Cruz 		(void) internal_attach_pgroup(i, pg);
32517c478bd9Sstevel@tonic-gate 
3252687293e1SAntonello Cruz 		pg->sc_pgroup_name = (char *)scf_pg_general;
3253687293e1SAntonello Cruz 		pg->sc_pgroup_type = (char *)scf_group_framework;
3254687293e1SAntonello Cruz 		pg->sc_pgroup_flags = 0;
32557c478bd9Sstevel@tonic-gate 
3256687293e1SAntonello Cruz 		e_val = (strcmp(true, (const char *)enabled) == 0);
3257687293e1SAntonello Cruz 		p = internal_property_create(SCF_PROPERTY_ENABLED,
3258687293e1SAntonello Cruz 		    SCF_TYPE_BOOLEAN, 1, (uint64_t)e_val);
32597c478bd9Sstevel@tonic-gate 
3260687293e1SAntonello Cruz 		p->sc_property_override = (op == SVCCFG_OP_APPLY);
32617c478bd9Sstevel@tonic-gate 
3262687293e1SAntonello Cruz 		(void) internal_attach_property(pg, p);
32637c478bd9Sstevel@tonic-gate 
3264687293e1SAntonello Cruz 		xmlFree(enabled);
3265687293e1SAntonello Cruz 	}
32667c478bd9Sstevel@tonic-gate 
32677c478bd9Sstevel@tonic-gate 	/*
32687c478bd9Sstevel@tonic-gate 	 * Walk its child elements, as appropriate.
32697c478bd9Sstevel@tonic-gate 	 */
32707c478bd9Sstevel@tonic-gate 	for (cursor = inst->xmlChildrenNode; cursor != NULL;
32717c478bd9Sstevel@tonic-gate 	    cursor = cursor->next) {
32727c478bd9Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
32737c478bd9Sstevel@tonic-gate 			continue;
32747c478bd9Sstevel@tonic-gate 
32757c478bd9Sstevel@tonic-gate 		switch (lxml_xlate_element(cursor->name)) {
32767c478bd9Sstevel@tonic-gate 		case SC_RESTARTER:
32777c478bd9Sstevel@tonic-gate 			(void) lxml_get_restarter(i, cursor);
32787c478bd9Sstevel@tonic-gate 			break;
32797c478bd9Sstevel@tonic-gate 		case SC_DEPENDENCY:
32807c478bd9Sstevel@tonic-gate 			(void) lxml_get_dependency(i, cursor);
32817c478bd9Sstevel@tonic-gate 			break;
32827c478bd9Sstevel@tonic-gate 		case SC_DEPENDENT:
32837c478bd9Sstevel@tonic-gate 			(void) lxml_get_dependent(i, cursor);
32847c478bd9Sstevel@tonic-gate 			break;
32857c478bd9Sstevel@tonic-gate 		case SC_METHOD_CONTEXT:
32867c478bd9Sstevel@tonic-gate 			(void) lxml_get_entity_method_context(i, cursor);
32877c478bd9Sstevel@tonic-gate 			break;
32887c478bd9Sstevel@tonic-gate 		case SC_EXEC_METHOD:
32897c478bd9Sstevel@tonic-gate 			(void) lxml_get_exec_method(i, cursor);
32907c478bd9Sstevel@tonic-gate 			break;
32917c478bd9Sstevel@tonic-gate 		case SC_PROPERTY_GROUP:
32927c478bd9Sstevel@tonic-gate 			(void) lxml_get_pgroup(i, cursor);
32937c478bd9Sstevel@tonic-gate 			break;
32947c478bd9Sstevel@tonic-gate 		case SC_TEMPLATE:
3295f329b923SSean Wilcox 			if (op == SVCCFG_OP_APPLY) {
3296f329b923SSean Wilcox 				semerr(gettext("Template data for \"%s\" may "
3297f329b923SSean Wilcox 				    "not be modified in a profile.\n"),
3298f329b923SSean Wilcox 				    i->sc_name);
3299f329b923SSean Wilcox 
3300f329b923SSean Wilcox 				return (-1);
3301f329b923SSean Wilcox 			}
3302f329b923SSean Wilcox 
33031f6eb021SLiane Praza 			if (lxml_get_template(i, cursor) != 0)
33041f6eb021SLiane Praza 				return (-1);
33057c478bd9Sstevel@tonic-gate 			break;
3306f6e214c7SGavin Maltby 		case SC_NOTIFICATION_PARAMETERS:
3307f6e214c7SGavin Maltby 			if (lxml_get_notification_parameters(i, cursor) != 0)
3308f6e214c7SGavin Maltby 				return (-1);
3309f6e214c7SGavin Maltby 			break;
33107c478bd9Sstevel@tonic-gate 		default:
33117c478bd9Sstevel@tonic-gate 			uu_die(gettext(
33127c478bd9Sstevel@tonic-gate 			    "illegal element \"%s\" on instance \"%s\"\n"),
33137c478bd9Sstevel@tonic-gate 			    cursor->name, i->sc_name);
33147c478bd9Sstevel@tonic-gate 			break;
33157c478bd9Sstevel@tonic-gate 		}
33167c478bd9Sstevel@tonic-gate 	}
33177c478bd9Sstevel@tonic-gate 
33187c478bd9Sstevel@tonic-gate 	return (0);
33197c478bd9Sstevel@tonic-gate }
33207c478bd9Sstevel@tonic-gate 
33218047359fSJohn Levon /*
33228047359fSJohn Levon  * Unimplemented and obsolete, but we still process it for compatibility
33238047359fSJohn Levon  * purposes.
33248047359fSJohn Levon  */
33257c478bd9Sstevel@tonic-gate static int
lxml_get_single_instance(entity_t * entity,xmlNodePtr si __unused)33268047359fSJohn Levon lxml_get_single_instance(entity_t *entity, xmlNodePtr si __unused)
33277c478bd9Sstevel@tonic-gate {
33287c478bd9Sstevel@tonic-gate 	pgroup_t *pg;
33297c478bd9Sstevel@tonic-gate 	property_t *p;
33307c478bd9Sstevel@tonic-gate 	int r;
33317c478bd9Sstevel@tonic-gate 
33327c478bd9Sstevel@tonic-gate 	pg = internal_pgroup_find_or_create(entity, (char *)scf_pg_general,
33337c478bd9Sstevel@tonic-gate 	    (char *)scf_group_framework);
33347c478bd9Sstevel@tonic-gate 
33357c478bd9Sstevel@tonic-gate 	p = internal_property_create(SCF_PROPERTY_SINGLE_INSTANCE,
33367c478bd9Sstevel@tonic-gate 	    SCF_TYPE_BOOLEAN, 1, (uint64_t)1);
33377c478bd9Sstevel@tonic-gate 
33387c478bd9Sstevel@tonic-gate 	r = internal_attach_property(pg, p);
33397c478bd9Sstevel@tonic-gate 	if (r != 0) {
33407c478bd9Sstevel@tonic-gate 		internal_property_free(p);
33417c478bd9Sstevel@tonic-gate 		return (-1);
33427c478bd9Sstevel@tonic-gate 	}
33437c478bd9Sstevel@tonic-gate 
33447c478bd9Sstevel@tonic-gate 	return (0);
33457c478bd9Sstevel@tonic-gate }
33467c478bd9Sstevel@tonic-gate 
33479444c26fSTom Whitten /*
33489444c26fSTom Whitten  * Check to see if the service should allow the upgrade
33499444c26fSTom Whitten  * process to handle adding of the manifestfiles linkage.
33509444c26fSTom Whitten  *
33519444c26fSTom Whitten  * If the service exists and does not have a manifestfiles
33529444c26fSTom Whitten  * property group then the upgrade process should handle
33539444c26fSTom Whitten  * the service.
33549444c26fSTom Whitten  *
33559444c26fSTom Whitten  * If the service doesn't exist or the service exists
33569444c26fSTom Whitten  * and has a manifestfiles property group then the import
33579444c26fSTom Whitten  * process can handle the manifestfiles property group
33589444c26fSTom Whitten  * work.
33599444c26fSTom Whitten  *
33609444c26fSTom Whitten  * This prevents potential cleanup of unaccounted for instances
33619444c26fSTom Whitten  * in early manifest import due to upgrade process needing
33629444c26fSTom Whitten  * information that has not yet been supplied by manifests
33639444c26fSTom Whitten  * that are still located in the /var/svc manifests directory.
33649444c26fSTom Whitten  */
33659444c26fSTom Whitten static int
lxml_check_upgrade(const char * service)3366d2a70789SRichard Lowe lxml_check_upgrade(const char *service)
3367d2a70789SRichard Lowe {
33689444c26fSTom Whitten 	scf_handle_t	*h = NULL;
33699444c26fSTom Whitten 	scf_scope_t	*sc = NULL;
33709444c26fSTom Whitten 	scf_service_t	*svc = NULL;
33719444c26fSTom Whitten 	scf_propertygroup_t	*pg = NULL;
33729444c26fSTom Whitten 	int rc = SCF_FAILED;
33739444c26fSTom Whitten 
33749444c26fSTom Whitten 	if ((h = scf_handle_create(SCF_VERSION)) == NULL ||
33759444c26fSTom Whitten 	    (sc = scf_scope_create(h)) == NULL ||
33769444c26fSTom Whitten 	    (svc = scf_service_create(h)) == NULL ||
33779444c26fSTom Whitten 	    (pg = scf_pg_create(h)) == NULL)
33789444c26fSTom Whitten 		goto out;
33799444c26fSTom Whitten 
33809444c26fSTom Whitten 	if (scf_handle_bind(h) != 0)
33819444c26fSTom Whitten 		goto out;
33829444c26fSTom Whitten 
33839444c26fSTom Whitten 	if (scf_handle_get_scope(h, SCF_FMRI_LOCAL_SCOPE, sc) == -1)
33849444c26fSTom Whitten 		goto out;
33859444c26fSTom Whitten 
33869444c26fSTom Whitten 	if (scf_scope_get_service(sc, service, svc) != SCF_SUCCESS) {
33879444c26fSTom Whitten 		if (scf_error() == SCF_ERROR_NOT_FOUND)
33889444c26fSTom Whitten 			rc = SCF_SUCCESS;
33899444c26fSTom Whitten 
33909444c26fSTom Whitten 		goto out;
33919444c26fSTom Whitten 	}
33929444c26fSTom Whitten 
33939444c26fSTom Whitten 	if (scf_service_get_pg(svc, SCF_PG_MANIFESTFILES, pg) != SCF_SUCCESS)
33949444c26fSTom Whitten 		goto out;
33959444c26fSTom Whitten 
33969444c26fSTom Whitten 	rc = SCF_SUCCESS;
33979444c26fSTom Whitten out:
33989444c26fSTom Whitten 	scf_pg_destroy(pg);
33999444c26fSTom Whitten 	scf_service_destroy(svc);
34009444c26fSTom Whitten 	scf_scope_destroy(sc);
34019444c26fSTom Whitten 	scf_handle_destroy(h);
34029444c26fSTom Whitten 
34039444c26fSTom Whitten 	return (rc);
34049444c26fSTom Whitten }
34059444c26fSTom Whitten 
34062f602de3SJohn Levon /*
34072f602de3SJohn Levon  * Validate the svc:/-prefixed FMRI generated from the service name.
34082f602de3SJohn Levon  */
34092f602de3SJohn Levon static void
validate_service_name(const entity_t * s)34102f602de3SJohn Levon validate_service_name(const entity_t *s)
34112f602de3SJohn Levon {
34122f602de3SJohn Levon 	char *fmri;
34132f602de3SJohn Levon 	int ftype;
34142f602de3SJohn Levon 	const char *finst;
34152f602de3SJohn Levon 
34162f602de3SJohn Levon 	if ((fmri = uu_strdup(s->sc_fmri)) == NULL)
34172f602de3SJohn Levon 		uu_die(gettext("couldn't allocate memory"));
34182f602de3SJohn Levon 
34192f602de3SJohn Levon 	if (scf_parse_fmri(fmri, &ftype, NULL, NULL, &finst, NULL, NULL) != 0 ||
34202f602de3SJohn Levon 	    finst != NULL || ftype != SCF_FMRI_TYPE_SVC) {
34212f602de3SJohn Levon 		uu_die(gettext("invalid value \"%s\": should be a bare "
34222f602de3SJohn Levon 		    "service name\n"), s->sc_name);
34232f602de3SJohn Levon 	}
34242f602de3SJohn Levon 
34252f602de3SJohn Levon 	uu_free(fmri);
34262f602de3SJohn Levon }
34272f602de3SJohn Levon 
34287c478bd9Sstevel@tonic-gate /*
34297c478bd9Sstevel@tonic-gate  * Translate a service element into an internal instance/property tree, added
3430f329b923SSean Wilcox  * to bundle.
3431f329b923SSean Wilcox  *
3432f329b923SSean Wilcox  * If op is SVCCFG_OP_APPLY (i.e., apply a profile), do not allow for
3433f329b923SSean Wilcox  * modification of template data.
34347c478bd9Sstevel@tonic-gate  */
34357c478bd9Sstevel@tonic-gate static int
lxml_get_service(bundle_t * bundle,xmlNodePtr svc,svccfg_op_t op)34363eae19d9Swesolows lxml_get_service(bundle_t *bundle, xmlNodePtr svc, svccfg_op_t op)
34377c478bd9Sstevel@tonic-gate {
343823294c7dSSean Wilcox 	pgroup_t *pg;
343923294c7dSSean Wilcox 	property_t *p;
34407c478bd9Sstevel@tonic-gate 	entity_t *s;
34417c478bd9Sstevel@tonic-gate 	xmlNodePtr cursor;
34427c478bd9Sstevel@tonic-gate 	xmlChar *type;
34437c478bd9Sstevel@tonic-gate 	xmlChar *version;
34447c478bd9Sstevel@tonic-gate 	int e;
34457c478bd9Sstevel@tonic-gate 
34467c478bd9Sstevel@tonic-gate 	/*
34477c478bd9Sstevel@tonic-gate 	 * Fetch attributes, as appropriate.
34487c478bd9Sstevel@tonic-gate 	 */
34497c478bd9Sstevel@tonic-gate 	s = internal_service_new((char *)xmlGetProp(svc,
34507c478bd9Sstevel@tonic-gate 	    (xmlChar *)name_attr));
34517c478bd9Sstevel@tonic-gate 
34522f602de3SJohn Levon 	validate_service_name(s);
34532f602de3SJohn Levon 
34541f6eb021SLiane Praza 	version = xmlGetProp(svc, (xmlChar *)version_attr);
34557c478bd9Sstevel@tonic-gate 	s->sc_u.sc_service.sc_service_version = atol((const char *)version);
34567c478bd9Sstevel@tonic-gate 	xmlFree(version);
34577c478bd9Sstevel@tonic-gate 
34587c478bd9Sstevel@tonic-gate 	type = xmlGetProp(svc, (xmlChar *)type_attr);
34597c478bd9Sstevel@tonic-gate 	s->sc_u.sc_service.sc_service_type = lxml_xlate_service_type(type);
34607c478bd9Sstevel@tonic-gate 	xmlFree(type);
34617c478bd9Sstevel@tonic-gate 
3462f329b923SSean Wilcox 	/*
3463f329b923SSean Wilcox 	 * Set the global missing type to false before processing the service
3464f329b923SSean Wilcox 	 */
3465f329b923SSean Wilcox 	est->sc_miss_type = B_FALSE;
3466f329b923SSean Wilcox 	s->sc_op = op;
3467f329b923SSean Wilcox 
346823294c7dSSean Wilcox 	/*
346923294c7dSSean Wilcox 	 * Now that the service is created create the manifest
347023294c7dSSean Wilcox 	 * property group and add the property value of the service.
347123294c7dSSean Wilcox 	 */
34729444c26fSTom Whitten 	if (lxml_check_upgrade(s->sc_name) == SCF_SUCCESS &&
34739444c26fSTom Whitten 	    svc->doc->name != NULL &&
347423294c7dSSean Wilcox 	    bundle->sc_bundle_type == SVCCFG_MANIFEST) {
347585bcc4e5SSean Wilcox 		char *buf, *base, *fname, *bname;
347685bcc4e5SSean Wilcox 		size_t	base_sz = 0;
347785bcc4e5SSean Wilcox 
347885bcc4e5SSean Wilcox 		/*
347985bcc4e5SSean Wilcox 		 * Must remove the PKG_INSTALL_ROOT, point to the correct
348085bcc4e5SSean Wilcox 		 * directory after install
348185bcc4e5SSean Wilcox 		 */
348285bcc4e5SSean Wilcox 		bname = uu_zalloc(PATH_MAX + 1);
348385bcc4e5SSean Wilcox 		if (realpath(svc->doc->name, bname) == NULL) {
348485bcc4e5SSean Wilcox 			uu_die(gettext("Unable to create the real path of the "
348585bcc4e5SSean Wilcox 			    "manifest file \"%s\" : %d\n"), svc->doc->name,
348685bcc4e5SSean Wilcox 			    errno);
348785bcc4e5SSean Wilcox 		}
348885bcc4e5SSean Wilcox 
348985bcc4e5SSean Wilcox 		base = getenv("PKG_INSTALL_ROOT");
349085bcc4e5SSean Wilcox 		if (base != NULL && strncmp(bname, base, strlen(base)) == 0) {
349185bcc4e5SSean Wilcox 			base_sz = strlen(base);
349285bcc4e5SSean Wilcox 		}
349385bcc4e5SSean Wilcox 		fname = safe_strdup(bname + base_sz);
349485bcc4e5SSean Wilcox 
349585bcc4e5SSean Wilcox 		uu_free(bname);
349685bcc4e5SSean Wilcox 		buf = mhash_filename_to_propname(svc->doc->name, B_FALSE);
349723294c7dSSean Wilcox 
349823294c7dSSean Wilcox 		pg = internal_pgroup_create_strict(s, SCF_PG_MANIFESTFILES,
349923294c7dSSean Wilcox 		    SCF_GROUP_FRAMEWORK);
350023294c7dSSean Wilcox 
350123294c7dSSean Wilcox 		if (pg == NULL) {
350223294c7dSSean Wilcox 			uu_die(gettext("Property group for prop_pattern, "
350323294c7dSSean Wilcox 			    "\"%s\", already exists in %s\n"),
350423294c7dSSean Wilcox 			    SCF_PG_MANIFESTFILES, s->sc_name);
350523294c7dSSean Wilcox 		}
350623294c7dSSean Wilcox 
350723294c7dSSean Wilcox 		p = internal_property_create(buf, SCF_TYPE_ASTRING, 1, fname);
350823294c7dSSean Wilcox 
350923294c7dSSean Wilcox 		(void) internal_attach_property(pg, p);
351023294c7dSSean Wilcox 	}
351123294c7dSSean Wilcox 
35127c478bd9Sstevel@tonic-gate 	/*
35137c478bd9Sstevel@tonic-gate 	 * Walk its child elements, as appropriate.
35147c478bd9Sstevel@tonic-gate 	 */
35157c478bd9Sstevel@tonic-gate 	for (cursor = svc->xmlChildrenNode; cursor != NULL;
35167c478bd9Sstevel@tonic-gate 	    cursor = cursor->next) {
35177c478bd9Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
35187c478bd9Sstevel@tonic-gate 			continue;
35197c478bd9Sstevel@tonic-gate 
35207c478bd9Sstevel@tonic-gate 		e = lxml_xlate_element(cursor->name);
35217c478bd9Sstevel@tonic-gate 
35227c478bd9Sstevel@tonic-gate 		switch (e) {
35237c478bd9Sstevel@tonic-gate 		case SC_INSTANCE:
3524687293e1SAntonello Cruz 			if (lxml_get_instance(s, cursor,
3525687293e1SAntonello Cruz 			    bundle->sc_bundle_type, op) != 0)
35261f6eb021SLiane Praza 				return (-1);
35277c478bd9Sstevel@tonic-gate 			break;
35287c478bd9Sstevel@tonic-gate 		case SC_TEMPLATE:
3529f329b923SSean Wilcox 			if (op == SVCCFG_OP_APPLY) {
3530f329b923SSean Wilcox 				semerr(gettext("Template data for \"%s\" may "
3531f329b923SSean Wilcox 				    "not be modified in a profile.\n"),
3532f329b923SSean Wilcox 				    s->sc_name);
3533f329b923SSean Wilcox 
3534f329b923SSean Wilcox 				return (-1);
3535f329b923SSean Wilcox 			}
3536f329b923SSean Wilcox 
35371f6eb021SLiane Praza 			if (lxml_get_template(s, cursor) != 0)
35381f6eb021SLiane Praza 				return (-1);
35397c478bd9Sstevel@tonic-gate 			break;
3540f6e214c7SGavin Maltby 		case SC_NOTIFICATION_PARAMETERS:
3541f6e214c7SGavin Maltby 			if (lxml_get_notification_parameters(s, cursor) != 0)
3542f6e214c7SGavin Maltby 				return (-1);
3543f6e214c7SGavin Maltby 			break;
35447c478bd9Sstevel@tonic-gate 		case SC_STABILITY:
35457c478bd9Sstevel@tonic-gate 			(void) lxml_get_entity_stability(s, cursor);
35467c478bd9Sstevel@tonic-gate 			break;
35477c478bd9Sstevel@tonic-gate 		case SC_DEPENDENCY:
35487c478bd9Sstevel@tonic-gate 			(void) lxml_get_dependency(s, cursor);
35497c478bd9Sstevel@tonic-gate 			break;
35507c478bd9Sstevel@tonic-gate 		case SC_DEPENDENT:
35517c478bd9Sstevel@tonic-gate 			(void) lxml_get_dependent(s, cursor);
35527c478bd9Sstevel@tonic-gate 			break;
35537c478bd9Sstevel@tonic-gate 		case SC_RESTARTER:
35547c478bd9Sstevel@tonic-gate 			(void) lxml_get_restarter(s, cursor);
35557c478bd9Sstevel@tonic-gate 			break;
35567c478bd9Sstevel@tonic-gate 		case SC_EXEC_METHOD:
35577c478bd9Sstevel@tonic-gate 			(void) lxml_get_exec_method(s, cursor);
35587c478bd9Sstevel@tonic-gate 			break;
35597c478bd9Sstevel@tonic-gate 		case SC_METHOD_CONTEXT:
35607c478bd9Sstevel@tonic-gate 			(void) lxml_get_entity_method_context(s, cursor);
35617c478bd9Sstevel@tonic-gate 			break;
35627c478bd9Sstevel@tonic-gate 		case SC_PROPERTY_GROUP:
35637c478bd9Sstevel@tonic-gate 			(void) lxml_get_pgroup(s, cursor);
35647c478bd9Sstevel@tonic-gate 			break;
35657c478bd9Sstevel@tonic-gate 		case SC_INSTANCE_CREATE_DEFAULT:
35667c478bd9Sstevel@tonic-gate 			(void) lxml_get_default_instance(s, cursor);
35677c478bd9Sstevel@tonic-gate 			break;
35687c478bd9Sstevel@tonic-gate 		case SC_INSTANCE_SINGLE:
35697c478bd9Sstevel@tonic-gate 			(void) lxml_get_single_instance(s, cursor);
35707c478bd9Sstevel@tonic-gate 			break;
35717c478bd9Sstevel@tonic-gate 		default:
35727c478bd9Sstevel@tonic-gate 			uu_die(gettext(
35737c478bd9Sstevel@tonic-gate 			    "illegal element \"%s\" on service \"%s\"\n"),
35747c478bd9Sstevel@tonic-gate 			    cursor->name, s->sc_name);
35757c478bd9Sstevel@tonic-gate 			break;
35767c478bd9Sstevel@tonic-gate 		}
35777c478bd9Sstevel@tonic-gate 	}
35787c478bd9Sstevel@tonic-gate 
3579f329b923SSean Wilcox 	/*
3580f329b923SSean Wilcox 	 * Now that the service has been processed set the missing type
3581f329b923SSean Wilcox 	 * for the service.  So that only the services with missing
3582f329b923SSean Wilcox 	 * types are processed.
3583f329b923SSean Wilcox 	 */
3584f329b923SSean Wilcox 	s->sc_miss_type = est->sc_miss_type;
3585f329b923SSean Wilcox 	if (est->sc_miss_type)
3586f329b923SSean Wilcox 		est->sc_miss_type = B_FALSE;
3587f329b923SSean Wilcox 
35887c478bd9Sstevel@tonic-gate 	return (internal_attach_service(bundle, s));
35897c478bd9Sstevel@tonic-gate }
35907c478bd9Sstevel@tonic-gate 
35917c478bd9Sstevel@tonic-gate #ifdef DEBUG
35927c478bd9Sstevel@tonic-gate void
lxml_dump(int g,xmlNodePtr p)35937c478bd9Sstevel@tonic-gate lxml_dump(int g, xmlNodePtr p)
35947c478bd9Sstevel@tonic-gate {
35957c478bd9Sstevel@tonic-gate 	if (p && p->name) {
3596f329b923SSean Wilcox 		(void) printf("%d %s\n", g, p->name);
35977c478bd9Sstevel@tonic-gate 
35987c478bd9Sstevel@tonic-gate 		for (p = p->xmlChildrenNode; p != NULL; p = p->next)
35997c478bd9Sstevel@tonic-gate 			lxml_dump(g + 1, p);
36007c478bd9Sstevel@tonic-gate 	}
36017c478bd9Sstevel@tonic-gate }
36027c478bd9Sstevel@tonic-gate #endif /* DEBUG */
36037c478bd9Sstevel@tonic-gate 
36047c478bd9Sstevel@tonic-gate static int
lxml_is_known_dtd(const xmlChar * dtdname)36057c478bd9Sstevel@tonic-gate lxml_is_known_dtd(const xmlChar *dtdname)
36067c478bd9Sstevel@tonic-gate {
36077c478bd9Sstevel@tonic-gate 	if (dtdname == NULL ||
36087c478bd9Sstevel@tonic-gate 	    strcmp(MANIFEST_DTD_PATH, (const char *)dtdname) != 0)
36097c478bd9Sstevel@tonic-gate 		return (0);
36107c478bd9Sstevel@tonic-gate 
36117c478bd9Sstevel@tonic-gate 	return (1);
36127c478bd9Sstevel@tonic-gate }
36137c478bd9Sstevel@tonic-gate 
36147c478bd9Sstevel@tonic-gate static int
lxml_get_bundle(bundle_t * bundle,bundle_type_t bundle_type,xmlNodePtr subbundle,svccfg_op_t op)36157c478bd9Sstevel@tonic-gate lxml_get_bundle(bundle_t *bundle, bundle_type_t bundle_type,
36163eae19d9Swesolows     xmlNodePtr subbundle, svccfg_op_t op)
36177c478bd9Sstevel@tonic-gate {
36187c478bd9Sstevel@tonic-gate 	xmlNodePtr cursor;
36197c478bd9Sstevel@tonic-gate 	xmlChar *type;
36207c478bd9Sstevel@tonic-gate 	int e;
36217c478bd9Sstevel@tonic-gate 
36227c478bd9Sstevel@tonic-gate 	/*
36237c478bd9Sstevel@tonic-gate 	 * 1.  Get bundle attributes.
36247c478bd9Sstevel@tonic-gate 	 */
36251f6eb021SLiane Praza 	type = xmlGetProp(subbundle, (xmlChar *)type_attr);
36267c478bd9Sstevel@tonic-gate 	bundle->sc_bundle_type = lxml_xlate_bundle_type(type);
36277c478bd9Sstevel@tonic-gate 	if (bundle->sc_bundle_type != bundle_type &&
36287c478bd9Sstevel@tonic-gate 	    bundle_type != SVCCFG_UNKNOWN_BUNDLE) {
36297c478bd9Sstevel@tonic-gate 		semerr(gettext("included bundle of different type.\n"));
36307c478bd9Sstevel@tonic-gate 		return (-1);
36317c478bd9Sstevel@tonic-gate 	}
36327c478bd9Sstevel@tonic-gate 
36337c478bd9Sstevel@tonic-gate 	xmlFree(type);
36347c478bd9Sstevel@tonic-gate 
36353eae19d9Swesolows 	switch (op) {
36363eae19d9Swesolows 	case SVCCFG_OP_IMPORT:
36377c478bd9Sstevel@tonic-gate 		if (bundle->sc_bundle_type != SVCCFG_MANIFEST) {
36387c478bd9Sstevel@tonic-gate 			semerr(gettext("document is not a manifest.\n"));
36397c478bd9Sstevel@tonic-gate 			return (-1);
36407c478bd9Sstevel@tonic-gate 		}
36413eae19d9Swesolows 		break;
36423eae19d9Swesolows 	case SVCCFG_OP_APPLY:
36437c478bd9Sstevel@tonic-gate 		if (bundle->sc_bundle_type != SVCCFG_PROFILE) {
36447c478bd9Sstevel@tonic-gate 			semerr(gettext("document is not a profile.\n"));
36457c478bd9Sstevel@tonic-gate 			return (-1);
36467c478bd9Sstevel@tonic-gate 		}
36473eae19d9Swesolows 		break;
36483eae19d9Swesolows 	case SVCCFG_OP_RESTORE:
36493eae19d9Swesolows 		if (bundle->sc_bundle_type != SVCCFG_ARCHIVE) {
36503eae19d9Swesolows 			semerr(gettext("document is not an archive.\n"));
36513eae19d9Swesolows 			return (-1);
36523eae19d9Swesolows 		}
36533eae19d9Swesolows 		break;
36547c478bd9Sstevel@tonic-gate 	}
36557c478bd9Sstevel@tonic-gate 
36561f6eb021SLiane Praza 	if (((bundle->sc_bundle_name = xmlGetProp(subbundle,
36571f6eb021SLiane Praza 	    (xmlChar *)name_attr)) == NULL) || (*bundle->sc_bundle_name == 0)) {
36587c478bd9Sstevel@tonic-gate 		semerr(gettext("service bundle lacks name attribute\n"));
36597c478bd9Sstevel@tonic-gate 		return (-1);
36607c478bd9Sstevel@tonic-gate 	}
36617c478bd9Sstevel@tonic-gate 
36627c478bd9Sstevel@tonic-gate 	/*
36637c478bd9Sstevel@tonic-gate 	 * 2.  Get services, descend into each one and build state.
36647c478bd9Sstevel@tonic-gate 	 */
36657c478bd9Sstevel@tonic-gate 	for (cursor = subbundle->xmlChildrenNode; cursor != NULL;
36667c478bd9Sstevel@tonic-gate 	    cursor = cursor->next) {
36677c478bd9Sstevel@tonic-gate 		if (lxml_ignorable_block(cursor))
36687c478bd9Sstevel@tonic-gate 			continue;
36697c478bd9Sstevel@tonic-gate 
36707c478bd9Sstevel@tonic-gate 		e = lxml_xlate_element(cursor->name);
36717c478bd9Sstevel@tonic-gate 
36727c478bd9Sstevel@tonic-gate 		switch (e) {
36737c478bd9Sstevel@tonic-gate 		case SC_XI_INCLUDE:
36747c478bd9Sstevel@tonic-gate 			continue;
36757c478bd9Sstevel@tonic-gate 
36767c478bd9Sstevel@tonic-gate 		case SC_SERVICE_BUNDLE:
36773eae19d9Swesolows 			if (lxml_get_bundle(bundle, bundle_type, cursor, op))
36787c478bd9Sstevel@tonic-gate 				return (-1);
36797c478bd9Sstevel@tonic-gate 			break;
36807c478bd9Sstevel@tonic-gate 		case SC_SERVICE:
36811f6eb021SLiane Praza 			if (lxml_get_service(bundle, cursor, op) != 0)
36821f6eb021SLiane Praza 				return (-1);
36837c478bd9Sstevel@tonic-gate 			break;
36847c478bd9Sstevel@tonic-gate 		}
36857c478bd9Sstevel@tonic-gate 	}
36867c478bd9Sstevel@tonic-gate 
36877c478bd9Sstevel@tonic-gate 	return (0);
36887c478bd9Sstevel@tonic-gate }
36897c478bd9Sstevel@tonic-gate 
36907c478bd9Sstevel@tonic-gate /*
36917c478bd9Sstevel@tonic-gate  * Load an XML tree from filename and translate it into an internal service
36923eae19d9Swesolows  * tree bundle.  Require that the bundle be of appropriate type for the
36933eae19d9Swesolows  * operation: archive for RESTORE, manifest for IMPORT, profile for APPLY.
36947c478bd9Sstevel@tonic-gate  */
36957c478bd9Sstevel@tonic-gate int
lxml_get_bundle_file(bundle_t * bundle,const char * filename,svccfg_op_t op)36963eae19d9Swesolows lxml_get_bundle_file(bundle_t *bundle, const char *filename, svccfg_op_t op)
36977c478bd9Sstevel@tonic-gate {
36987c478bd9Sstevel@tonic-gate 	xmlDocPtr document;
36997c478bd9Sstevel@tonic-gate 	xmlNodePtr cursor;
37007c478bd9Sstevel@tonic-gate 	xmlDtdPtr dtd = NULL;
37017c478bd9Sstevel@tonic-gate 	xmlValidCtxtPtr vcp;
37027c478bd9Sstevel@tonic-gate 	boolean_t do_validate;
37037c478bd9Sstevel@tonic-gate 	char *dtdpath = NULL;
37047c478bd9Sstevel@tonic-gate 	int r;
37057c478bd9Sstevel@tonic-gate 
370676cf44abSjeanm 	/*
370776cf44abSjeanm 	 * Verify we can read the file before we try to parse it.
370876cf44abSjeanm 	 */
370976cf44abSjeanm 	if (access(filename, R_OK | F_OK) == -1) {
371076cf44abSjeanm 		semerr(gettext("unable to open file: %s\n"), strerror(errno));
371176cf44abSjeanm 		return (-1);
371276cf44abSjeanm 	}
371376cf44abSjeanm 
37147c478bd9Sstevel@tonic-gate 	/*
37157c478bd9Sstevel@tonic-gate 	 * Until libxml2 addresses DTD-based validation with XInclude, we don't
37167c478bd9Sstevel@tonic-gate 	 * validate service profiles (i.e. the apply path).
37177c478bd9Sstevel@tonic-gate 	 */
37183eae19d9Swesolows 	do_validate = (op != SVCCFG_OP_APPLY) &&
37193eae19d9Swesolows 	    (getenv("SVCCFG_NOVALIDATE") == NULL);
37207c478bd9Sstevel@tonic-gate 	if (do_validate)
37217c478bd9Sstevel@tonic-gate 		dtdpath = getenv("SVCCFG_DTD");
37227c478bd9Sstevel@tonic-gate 
3723*b0709259SAndy Fiddaman 	document = xmlReadFile(filename, NULL, xml_read_options);
3724*b0709259SAndy Fiddaman 	if (document == NULL) {
37257c478bd9Sstevel@tonic-gate 		semerr(gettext("couldn't parse document\n"));
37267c478bd9Sstevel@tonic-gate 		return (-1);
37277c478bd9Sstevel@tonic-gate 	}
37287c478bd9Sstevel@tonic-gate 
372967b0e063SAlbert Lee 	document->name = safe_strdup(filename);
373023294c7dSSean Wilcox 
37317c478bd9Sstevel@tonic-gate 	/*
37327c478bd9Sstevel@tonic-gate 	 * Verify that this is a document type we understand.
37337c478bd9Sstevel@tonic-gate 	 */
37347c478bd9Sstevel@tonic-gate 	if ((dtd = xmlGetIntSubset(document)) == NULL) {
37357c478bd9Sstevel@tonic-gate 		semerr(gettext("document has no DTD\n"));
37367c478bd9Sstevel@tonic-gate 		return (-1);
3737f329b923SSean Wilcox 	} else if (dtdpath == NULL && !do_validate) {
3738f329b923SSean Wilcox 		/*
3739f329b923SSean Wilcox 		 * If apply then setup so that some validation
3740f329b923SSean Wilcox 		 * for specific elements can be done.
3741f329b923SSean Wilcox 		 */
3742f329b923SSean Wilcox 		dtdpath = (char *)document->intSubset->SystemID;
37437c478bd9Sstevel@tonic-gate 	}
37447c478bd9Sstevel@tonic-gate 
37457c478bd9Sstevel@tonic-gate 	if (!lxml_is_known_dtd(dtd->SystemID)) {
37467c478bd9Sstevel@tonic-gate 		semerr(gettext("document DTD unknown; not service bundle?\n"));
37477c478bd9Sstevel@tonic-gate 		return (-1);
37487c478bd9Sstevel@tonic-gate 	}
37497c478bd9Sstevel@tonic-gate 
37507c478bd9Sstevel@tonic-gate 	if ((cursor = xmlDocGetRootElement(document)) == NULL) {
37517c478bd9Sstevel@tonic-gate 		semerr(gettext("document is empty\n"));
37527c478bd9Sstevel@tonic-gate 		xmlFreeDoc(document);
37537c478bd9Sstevel@tonic-gate 		return (-1);
37547c478bd9Sstevel@tonic-gate 	}
37557c478bd9Sstevel@tonic-gate 
37567c478bd9Sstevel@tonic-gate 	if (xmlStrcmp(cursor->name, (const xmlChar *)"service_bundle") != 0) {
37577c478bd9Sstevel@tonic-gate 		semerr(gettext("document is not a service bundle\n"));
37587c478bd9Sstevel@tonic-gate 		xmlFreeDoc(document);
37597c478bd9Sstevel@tonic-gate 		return (-1);
37607c478bd9Sstevel@tonic-gate 	}
37617c478bd9Sstevel@tonic-gate 
37627c478bd9Sstevel@tonic-gate 
37637c478bd9Sstevel@tonic-gate 	if (dtdpath != NULL) {
37647c478bd9Sstevel@tonic-gate 		dtd = xmlParseDTD(NULL, (xmlChar *)dtdpath);
37657c478bd9Sstevel@tonic-gate 		if (dtd == NULL) {
37667c478bd9Sstevel@tonic-gate 			semerr(gettext("Could not parse DTD \"%s\".\n"),
37677c478bd9Sstevel@tonic-gate 			    dtdpath);
37687c478bd9Sstevel@tonic-gate 			return (-1);
37697c478bd9Sstevel@tonic-gate 		}
37707c478bd9Sstevel@tonic-gate 
37717c478bd9Sstevel@tonic-gate 		if (document->extSubset != NULL)
37727c478bd9Sstevel@tonic-gate 			xmlFreeDtd(document->extSubset);
37737c478bd9Sstevel@tonic-gate 
37747c478bd9Sstevel@tonic-gate 		document->extSubset = dtd;
37757c478bd9Sstevel@tonic-gate 	}
37767c478bd9Sstevel@tonic-gate 
377776cf44abSjeanm 	if (xmlXIncludeProcessFlags(document, XML_PARSE_XINCLUDE) == -1) {
37787c478bd9Sstevel@tonic-gate 		semerr(gettext("couldn't handle XInclude statements "
377976cf44abSjeanm 		    "in document\n"));
37807c478bd9Sstevel@tonic-gate 		return (-1);
37817c478bd9Sstevel@tonic-gate 	}
37827c478bd9Sstevel@tonic-gate 
37837c478bd9Sstevel@tonic-gate 	if (do_validate) {
37847c478bd9Sstevel@tonic-gate 		vcp = xmlNewValidCtxt();
37857c478bd9Sstevel@tonic-gate 		if (vcp == NULL)
37867c478bd9Sstevel@tonic-gate 			uu_die(gettext("could not allocate memory"));
37877c478bd9Sstevel@tonic-gate 		vcp->warning = xmlParserValidityWarning;
37887c478bd9Sstevel@tonic-gate 		vcp->error = xmlParserValidityError;
37897c478bd9Sstevel@tonic-gate 
37907c478bd9Sstevel@tonic-gate 		r = xmlValidateDocument(vcp, document);
37917c478bd9Sstevel@tonic-gate 
37927c478bd9Sstevel@tonic-gate 		xmlFreeValidCtxt(vcp);
37937c478bd9Sstevel@tonic-gate 
37947c478bd9Sstevel@tonic-gate 		if (r == 0) {
37957c478bd9Sstevel@tonic-gate 			semerr(gettext("Document is not valid.\n"));
37967c478bd9Sstevel@tonic-gate 			xmlFreeDoc(document);
37977c478bd9Sstevel@tonic-gate 			return (-1);
37987c478bd9Sstevel@tonic-gate 		}
37997c478bd9Sstevel@tonic-gate 	}
38007c478bd9Sstevel@tonic-gate 
38017c478bd9Sstevel@tonic-gate #ifdef DEBUG
38027c478bd9Sstevel@tonic-gate 	lxml_dump(0, cursor);
38037c478bd9Sstevel@tonic-gate #endif /* DEBUG */
38047c478bd9Sstevel@tonic-gate 
38053eae19d9Swesolows 	r = lxml_get_bundle(bundle, SVCCFG_UNKNOWN_BUNDLE, cursor, op);
38067c478bd9Sstevel@tonic-gate 
38077c478bd9Sstevel@tonic-gate 	xmlFreeDoc(document);
38087c478bd9Sstevel@tonic-gate 
38097c478bd9Sstevel@tonic-gate 	return (r);
38107c478bd9Sstevel@tonic-gate }
38117c478bd9Sstevel@tonic-gate 
38127c478bd9Sstevel@tonic-gate int
lxml_inventory(const char * filename)38137c478bd9Sstevel@tonic-gate lxml_inventory(const char *filename)
38147c478bd9Sstevel@tonic-gate {
38157c478bd9Sstevel@tonic-gate 	bundle_t *b;
38167c478bd9Sstevel@tonic-gate 	uu_list_walk_t *svcs, *insts;
38177c478bd9Sstevel@tonic-gate 	entity_t *svc, *inst;
38187c478bd9Sstevel@tonic-gate 
38197c478bd9Sstevel@tonic-gate 	b = internal_bundle_new();
38207c478bd9Sstevel@tonic-gate 
38213eae19d9Swesolows 	if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) != 0) {
38227c478bd9Sstevel@tonic-gate 		internal_bundle_free(b);
38237c478bd9Sstevel@tonic-gate 		return (-1);
38247c478bd9Sstevel@tonic-gate 	}
38257c478bd9Sstevel@tonic-gate 
38267c478bd9Sstevel@tonic-gate 	svcs = uu_list_walk_start(b->sc_bundle_services, 0);
38277c478bd9Sstevel@tonic-gate 	if (svcs == NULL)
38287c478bd9Sstevel@tonic-gate 		uu_die(gettext("Couldn't walk services"));
38297c478bd9Sstevel@tonic-gate 
38307c478bd9Sstevel@tonic-gate 	while ((svc = uu_list_walk_next(svcs)) != NULL) {
38317c478bd9Sstevel@tonic-gate 		uu_list_t *inst_list;
38327c478bd9Sstevel@tonic-gate 
38337c478bd9Sstevel@tonic-gate 		inst_list = svc->sc_u.sc_service.sc_service_instances;
38347c478bd9Sstevel@tonic-gate 		insts = uu_list_walk_start(inst_list, 0);
38357c478bd9Sstevel@tonic-gate 		if (insts == NULL)
38367c478bd9Sstevel@tonic-gate 			uu_die(gettext("Couldn't walk instances"));
38377c478bd9Sstevel@tonic-gate 
38387c478bd9Sstevel@tonic-gate 		while ((inst = uu_list_walk_next(insts)) != NULL)
38397c478bd9Sstevel@tonic-gate 			(void) printf("svc:/%s:%s\n", svc->sc_name,
38407c478bd9Sstevel@tonic-gate 			    inst->sc_name);
38417c478bd9Sstevel@tonic-gate 
38427c478bd9Sstevel@tonic-gate 		uu_list_walk_end(insts);
38437c478bd9Sstevel@tonic-gate 	}
38447c478bd9Sstevel@tonic-gate 
38457c478bd9Sstevel@tonic-gate 	uu_list_walk_end(svcs);
38467c478bd9Sstevel@tonic-gate 
38477c478bd9Sstevel@tonic-gate 	svcs = uu_list_walk_start(b->sc_bundle_services, 0);
38487c478bd9Sstevel@tonic-gate 	while ((svc = uu_list_walk_next(svcs)) != NULL) {
38497c478bd9Sstevel@tonic-gate 		(void) fputs("svc:/", stdout);
38507c478bd9Sstevel@tonic-gate 		(void) puts(svc->sc_name);
38517c478bd9Sstevel@tonic-gate 	}
38527c478bd9Sstevel@tonic-gate 	uu_list_walk_end(svcs);
38537c478bd9Sstevel@tonic-gate 
38547c478bd9Sstevel@tonic-gate 	internal_bundle_free(b);
38557c478bd9Sstevel@tonic-gate 
38567c478bd9Sstevel@tonic-gate 	return (0);
38577c478bd9Sstevel@tonic-gate }
3858