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 */ 24*67b0e063SAlbert Lee /* 25*67b0e063SAlbert Lee * Copyright 2011 Nexenta Systems, Inc. All rights reserved. 26*67b0e063SAlbert Lee */ 27*67b0e063SAlbert Lee 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate /* 307c478bd9Sstevel@tonic-gate * XML document manipulation routines 317c478bd9Sstevel@tonic-gate * 327c478bd9Sstevel@tonic-gate * These routines provide translation to and from the internal representation to 337c478bd9Sstevel@tonic-gate * XML. Directionally-oriented verbs are with respect to the external source, 347c478bd9Sstevel@tonic-gate * so lxml_get_service() fetches a service from the XML file into the 357c478bd9Sstevel@tonic-gate * internal representation. 367c478bd9Sstevel@tonic-gate */ 377c478bd9Sstevel@tonic-gate 381f6eb021SLiane Praza #include <libxml/parser.h> 391f6eb021SLiane Praza #include <libxml/xinclude.h> 401f6eb021SLiane Praza 411f6eb021SLiane Praza #include <assert.h> 421f6eb021SLiane Praza #include <ctype.h> 431f6eb021SLiane Praza #include <errno.h> 441f6eb021SLiane Praza #include <libintl.h> 451f6eb021SLiane Praza #include <libscf.h> 461f6eb021SLiane Praza #include <libscf_priv.h> 471f6eb021SLiane Praza #include <libuutil.h> 481f6eb021SLiane Praza #include <sasl/saslutil.h> 491f6eb021SLiane Praza #include <stdlib.h> 501f6eb021SLiane Praza #include <string.h> 5185bcc4e5SSean Wilcox #include <limits.h> 521f6eb021SLiane Praza 531f6eb021SLiane Praza #include <sys/types.h> 541f6eb021SLiane Praza #include <sys/stat.h> 551f6eb021SLiane Praza #include <unistd.h> 561f6eb021SLiane Praza 5723294c7dSSean Wilcox #include <sys/param.h> 5823294c7dSSean Wilcox #include "manifest_hash.h" 5923294c7dSSean Wilcox 601f6eb021SLiane Praza #include "svccfg.h" 61f6e214c7SGavin Maltby #include "notify_params.h" 621f6eb021SLiane Praza 631f6eb021SLiane Praza /* 641f6eb021SLiane Praza * snprintf(3C) format strings for constructing property names that include 651f6eb021SLiane Praza * the locale designation. Use %s to indicate where the locale should go. 661f6eb021SLiane Praza * 671f6eb021SLiane Praza * The VALUE_* symbols are an exception. The firs %s will be replaced with 681f6eb021SLiane Praza * "value_". The second %s will be replaced by the name of the value and 691f6eb021SLiane Praza * %%s will be replaced by the locale designation. These formats are 701f6eb021SLiane Praza * processed twice by snprintf(3C). The first time captures the value name 711f6eb021SLiane Praza * and the second time captures the locale. 721f6eb021SLiane Praza */ 731f6eb021SLiane Praza #define LOCALE_ONLY_FMT ("%s") 741f6eb021SLiane Praza #define COMMON_NAME_FMT ("common_name_%s") 751f6eb021SLiane Praza #define DESCRIPTION_FMT ("description_%s") 761f6eb021SLiane Praza #define UNITS_FMT ("units_%s") 771f6eb021SLiane Praza #define VALUE_COMMON_NAME_FMT ("%s%s_common_name_%%s") 781f6eb021SLiane Praza #define VALUE_DESCRIPTION_FMT ("%s%s_description_%%s") 791f6eb021SLiane Praza 801f6eb021SLiane Praza /* Attribute names */ 817c478bd9Sstevel@tonic-gate const char * const delete_attr = "delete"; 827c478bd9Sstevel@tonic-gate const char * const enabled_attr = "enabled"; 831f6eb021SLiane Praza const char * const lang_attr = "lang"; 841f6eb021SLiane Praza const char * const manpath_attr = "manpath"; 851f6eb021SLiane Praza const char * const max_attr = "max"; 861f6eb021SLiane Praza const char * const min_attr = "min"; 877c478bd9Sstevel@tonic-gate const char * const name_attr = "name"; 887c478bd9Sstevel@tonic-gate const char * const override_attr = "override"; 891f6eb021SLiane Praza const char * const required_attr = "required"; 901f6eb021SLiane Praza const char * const section_attr = "section"; 911f6eb021SLiane Praza const char * const set_attr = "set"; 921f6eb021SLiane Praza const char * const target_attr = "target"; 931f6eb021SLiane Praza const char * const timeout_seconds_attr = "timeout_seconds"; 941f6eb021SLiane Praza const char * const title_attr = "title"; 957c478bd9Sstevel@tonic-gate const char * const type_attr = "type"; 961f6eb021SLiane Praza const char * const uri_attr = "uri"; 977c478bd9Sstevel@tonic-gate const char * const value_attr = "value"; 981f6eb021SLiane Praza const char * const version_attr = "version"; 991f6eb021SLiane Praza const char * const xml_lang_attr = "xml:lang"; 100f6e214c7SGavin Maltby const char * const active_attr = "active"; 1011f6eb021SLiane Praza 1021f6eb021SLiane Praza /* Attribute values */ 1031f6eb021SLiane Praza const char * const all_value = "all"; 1041f6eb021SLiane Praza 1057c478bd9Sstevel@tonic-gate const char * const true = "true"; 1067c478bd9Sstevel@tonic-gate const char * const false = "false"; 1077c478bd9Sstevel@tonic-gate 1087c478bd9Sstevel@tonic-gate /* 1097c478bd9Sstevel@tonic-gate * The following list must be kept in the same order as that of 1107c478bd9Sstevel@tonic-gate * element_t array 1117c478bd9Sstevel@tonic-gate */ 1127c478bd9Sstevel@tonic-gate static const char *lxml_elements[] = { 1137c478bd9Sstevel@tonic-gate "astring_list", /* SC_ASTRING */ 1147c478bd9Sstevel@tonic-gate "boolean_list", /* SC_BOOLEAN */ 1151f6eb021SLiane Praza "cardinality", /* SC_CARDINALITY */ 1161f6eb021SLiane Praza "choices", /* SC_CHOICES */ 1177c478bd9Sstevel@tonic-gate "common_name", /* SC_COMMON_NAME */ 1181f6eb021SLiane Praza "constraints", /* SC_CONSTRAINTS */ 1197c478bd9Sstevel@tonic-gate "count_list", /* SC_COUNT */ 1207c478bd9Sstevel@tonic-gate "create_default_instance", /* SC_INSTANCE_CREATE_DEFAULT */ 1217c478bd9Sstevel@tonic-gate "dependency", /* SC_DEPENDENCY */ 1227c478bd9Sstevel@tonic-gate "dependent", /* SC_DEPENDENT */ 1237c478bd9Sstevel@tonic-gate "description", /* SC_DESCRIPTION */ 1247c478bd9Sstevel@tonic-gate "doc_link", /* SC_DOC_LINK */ 1257c478bd9Sstevel@tonic-gate "documentation", /* SC_DOCUMENTATION */ 1267c478bd9Sstevel@tonic-gate "enabled", /* SC_ENABLED */ 127f6e214c7SGavin Maltby "event", /* SC_EVENT */ 1287c478bd9Sstevel@tonic-gate "exec_method", /* SC_EXEC_METHOD */ 1297c478bd9Sstevel@tonic-gate "fmri_list", /* SC_FMRI */ 1307c478bd9Sstevel@tonic-gate "host_list", /* SC_HOST */ 1317c478bd9Sstevel@tonic-gate "hostname_list", /* SC_HOSTNAME */ 1321f6eb021SLiane Praza "include_values", /* SC_INCLUDE_VALUES */ 1337c478bd9Sstevel@tonic-gate "instance", /* SC_INSTANCE */ 1347c478bd9Sstevel@tonic-gate "integer_list", /* SC_INTEGER */ 1351f6eb021SLiane Praza "internal_separators", /* SC_INTERNAL_SEPARATORS */ 1367c478bd9Sstevel@tonic-gate "loctext", /* SC_LOCTEXT */ 1377c478bd9Sstevel@tonic-gate "manpage", /* SC_MANPAGE */ 1387c478bd9Sstevel@tonic-gate "method_context", /* SC_METHOD_CONTEXT */ 1397c478bd9Sstevel@tonic-gate "method_credential", /* SC_METHOD_CREDENTIAL */ 1407c478bd9Sstevel@tonic-gate "method_profile", /* SC_METHOD_PROFILE */ 1417c478bd9Sstevel@tonic-gate "method_environment", /* SC_METHOD_ENVIRONMENT */ 1427c478bd9Sstevel@tonic-gate "envvar", /* SC_METHOD_ENVVAR */ 143f6f041a2SAntonello Cruz "net_address_list", /* SC_NET_ADDR */ 1447c478bd9Sstevel@tonic-gate "net_address_v4_list", /* SC_NET_ADDR_V4 */ 1457c478bd9Sstevel@tonic-gate "net_address_v6_list", /* SC_NET_ADDR_V6 */ 146f6e214c7SGavin Maltby "notification_parameters", /* SC_NOTIFICATION_PARAMETERS */ 1477c478bd9Sstevel@tonic-gate "opaque_list", /* SC_OPAQUE */ 148f6e214c7SGavin Maltby "parameter", /* SC_PARAMETER */ 149f6e214c7SGavin Maltby "paramval", /* SC_PARAMVAL */ 1501f6eb021SLiane Praza "pg_pattern", /* SC_PG_PATTERN */ 1511f6eb021SLiane Praza "prop_pattern", /* SC_PROP_PATTERN */ 1527c478bd9Sstevel@tonic-gate "property", /* SC_PROPERTY */ 1537c478bd9Sstevel@tonic-gate "property_group", /* SC_PROPERTY_GROUP */ 1547c478bd9Sstevel@tonic-gate "propval", /* SC_PROPVAL */ 1551f6eb021SLiane Praza "range", /* SC_RANGE */ 1567c478bd9Sstevel@tonic-gate "restarter", /* SC_RESTARTER */ 1577c478bd9Sstevel@tonic-gate "service", /* SC_SERVICE */ 1587c478bd9Sstevel@tonic-gate "service_bundle", /* SC_SERVICE_BUNDLE */ 1597c478bd9Sstevel@tonic-gate "service_fmri", /* SC_SERVICE_FMRI */ 1607c478bd9Sstevel@tonic-gate "single_instance", /* SC_INSTANCE_SINGLE */ 1617c478bd9Sstevel@tonic-gate "stability", /* SC_STABILITY */ 1627c478bd9Sstevel@tonic-gate "template", /* SC_TEMPLATE */ 1637c478bd9Sstevel@tonic-gate "time_list", /* SC_TIME */ 164f6e214c7SGavin Maltby "type", /* SC_TYPE */ 1651f6eb021SLiane Praza "units", /* SC_UNITS */ 1667c478bd9Sstevel@tonic-gate "uri_list", /* SC_URI */ 1677c478bd9Sstevel@tonic-gate "ustring_list", /* SC_USTRING */ 1681f6eb021SLiane Praza "value", /* SC_VALUE */ 1697c478bd9Sstevel@tonic-gate "value_node", /* SC_VALUE_NODE */ 1701f6eb021SLiane Praza "values", /* SC_VALUES */ 1711f6eb021SLiane Praza "visibility", /* SC_VISIBILITY */ 1727c478bd9Sstevel@tonic-gate "xi:fallback", /* SC_XI_FALLBACK */ 1737c478bd9Sstevel@tonic-gate "xi:include" /* SC_XI_INCLUDE */ 1747c478bd9Sstevel@tonic-gate }; 1757c478bd9Sstevel@tonic-gate 1767c478bd9Sstevel@tonic-gate /* 1777c478bd9Sstevel@tonic-gate * The following list must be kept in the same order as that of 1787c478bd9Sstevel@tonic-gate * element_t array 1797c478bd9Sstevel@tonic-gate */ 1807c478bd9Sstevel@tonic-gate static const char *lxml_prop_types[] = { 1817c478bd9Sstevel@tonic-gate "astring", /* SC_ASTRING */ 1827c478bd9Sstevel@tonic-gate "boolean", /* SC_BOOLEAN */ 1831f6eb021SLiane Praza "", /* SC_CARDINALITY */ 1841f6eb021SLiane Praza "", /* SC_CHOICES */ 1857c478bd9Sstevel@tonic-gate "", /* SC_COMMON_NAME */ 1861f6eb021SLiane Praza "", /* SC_CONSTRAINTS */ 1877c478bd9Sstevel@tonic-gate "count", /* SC_COUNT */ 1887c478bd9Sstevel@tonic-gate "", /* SC_INSTANCE_CREATE_DEFAULT */ 1897c478bd9Sstevel@tonic-gate "", /* SC_DEPENDENCY */ 1907c478bd9Sstevel@tonic-gate "", /* SC_DEPENDENT */ 1917c478bd9Sstevel@tonic-gate "", /* SC_DESCRIPTION */ 1927c478bd9Sstevel@tonic-gate "", /* SC_DOC_LINK */ 1937c478bd9Sstevel@tonic-gate "", /* SC_DOCUMENTATION */ 1947c478bd9Sstevel@tonic-gate "", /* SC_ENABLED */ 195f6e214c7SGavin Maltby "", /* SC_EVENT */ 1967c478bd9Sstevel@tonic-gate "", /* SC_EXEC_METHOD */ 1977c478bd9Sstevel@tonic-gate "fmri", /* SC_FMRI */ 1987c478bd9Sstevel@tonic-gate "host", /* SC_HOST */ 1997c478bd9Sstevel@tonic-gate "hostname", /* SC_HOSTNAME */ 2001f6eb021SLiane Praza "", /* SC_INCLUDE_VALUES */ 2017c478bd9Sstevel@tonic-gate "", /* SC_INSTANCE */ 2027c478bd9Sstevel@tonic-gate "integer", /* SC_INTEGER */ 2031f6eb021SLiane Praza "", /* SC_INTERNAL_SEPARATORS */ 2047c478bd9Sstevel@tonic-gate "", /* SC_LOCTEXT */ 2057c478bd9Sstevel@tonic-gate "", /* SC_MANPAGE */ 2067c478bd9Sstevel@tonic-gate "", /* SC_METHOD_CONTEXT */ 2077c478bd9Sstevel@tonic-gate "", /* SC_METHOD_CREDENTIAL */ 2087c478bd9Sstevel@tonic-gate "", /* SC_METHOD_PROFILE */ 2097c478bd9Sstevel@tonic-gate "", /* SC_METHOD_ENVIRONMENT */ 2107c478bd9Sstevel@tonic-gate "", /* SC_METHOD_ENVVAR */ 211f6f041a2SAntonello Cruz "net_address", /* SC_NET_ADDR */ 2127c478bd9Sstevel@tonic-gate "net_address_v4", /* SC_NET_ADDR_V4 */ 2137c478bd9Sstevel@tonic-gate "net_address_v6", /* SC_NET_ADDR_V6 */ 214f6e214c7SGavin Maltby "", /* SC_NOTIFICATION_PARAMETERS */ 2157c478bd9Sstevel@tonic-gate "opaque", /* SC_OPAQUE */ 216f6e214c7SGavin Maltby "", /* SC_PARAMETER */ 217f6e214c7SGavin Maltby "", /* SC_PARAMVAL */ 2181f6eb021SLiane Praza "", /* SC_PG_PATTERN */ 2191f6eb021SLiane Praza "", /* SC_PROP_PATTERN */ 2207c478bd9Sstevel@tonic-gate "", /* SC_PROPERTY */ 2217c478bd9Sstevel@tonic-gate "", /* SC_PROPERTY_GROUP */ 2227c478bd9Sstevel@tonic-gate "", /* SC_PROPVAL */ 2231f6eb021SLiane Praza "", /* SC_RANGE */ 2247c478bd9Sstevel@tonic-gate "", /* SC_RESTARTER */ 2257c478bd9Sstevel@tonic-gate "", /* SC_SERVICE */ 2267c478bd9Sstevel@tonic-gate "", /* SC_SERVICE_BUNDLE */ 2277c478bd9Sstevel@tonic-gate "", /* SC_SERVICE_FMRI */ 2287c478bd9Sstevel@tonic-gate "", /* SC_INSTANCE_SINGLE */ 2297c478bd9Sstevel@tonic-gate "", /* SC_STABILITY */ 2307c478bd9Sstevel@tonic-gate "", /* SC_TEMPLATE */ 2317c478bd9Sstevel@tonic-gate "time", /* SC_TIME */ 232f6e214c7SGavin Maltby "", /* SC_TYPE */ 2331f6eb021SLiane Praza "", /* SC_UNITS */ 2347c478bd9Sstevel@tonic-gate "uri", /* SC_URI */ 2357c478bd9Sstevel@tonic-gate "ustring", /* SC_USTRING */ 2361f6eb021SLiane Praza "", /* SC_VALUE */ 2371f6eb021SLiane Praza "", /* SC_VALUE_NODE */ 2381f6eb021SLiane Praza "", /* SC_VALUES */ 2391f6eb021SLiane Praza "", /* SC_VISIBILITY */ 2401f6eb021SLiane Praza "", /* SC_XI_FALLBACK */ 2417c478bd9Sstevel@tonic-gate "" /* SC_XI_INCLUDE */ 2427c478bd9Sstevel@tonic-gate }; 2437c478bd9Sstevel@tonic-gate 2447c478bd9Sstevel@tonic-gate int 2457c478bd9Sstevel@tonic-gate lxml_init() 2467c478bd9Sstevel@tonic-gate { 2477c478bd9Sstevel@tonic-gate if (getenv("SVCCFG_NOVALIDATE") == NULL) { 2487c478bd9Sstevel@tonic-gate /* 2497c478bd9Sstevel@tonic-gate * DTD validation, with line numbers. 2507c478bd9Sstevel@tonic-gate */ 25180148899SSurya Prakki (void) xmlLineNumbersDefault(1); 2527c478bd9Sstevel@tonic-gate xmlLoadExtDtdDefaultValue |= XML_DETECT_IDS; 2537c478bd9Sstevel@tonic-gate xmlLoadExtDtdDefaultValue |= XML_COMPLETE_ATTRS; 2547c478bd9Sstevel@tonic-gate } 2557c478bd9Sstevel@tonic-gate 2567c478bd9Sstevel@tonic-gate return (0); 2577c478bd9Sstevel@tonic-gate } 2587c478bd9Sstevel@tonic-gate 2597c478bd9Sstevel@tonic-gate static bundle_type_t 2607c478bd9Sstevel@tonic-gate lxml_xlate_bundle_type(xmlChar *type) 2617c478bd9Sstevel@tonic-gate { 2627c478bd9Sstevel@tonic-gate if (xmlStrcmp(type, (const xmlChar *)"manifest") == 0) 2637c478bd9Sstevel@tonic-gate return (SVCCFG_MANIFEST); 2647c478bd9Sstevel@tonic-gate 2657c478bd9Sstevel@tonic-gate if (xmlStrcmp(type, (const xmlChar *)"profile") == 0) 2667c478bd9Sstevel@tonic-gate return (SVCCFG_PROFILE); 2677c478bd9Sstevel@tonic-gate 2687c478bd9Sstevel@tonic-gate if (xmlStrcmp(type, (const xmlChar *)"archive") == 0) 2697c478bd9Sstevel@tonic-gate return (SVCCFG_ARCHIVE); 2707c478bd9Sstevel@tonic-gate 2717c478bd9Sstevel@tonic-gate return (SVCCFG_UNKNOWN_BUNDLE); 2727c478bd9Sstevel@tonic-gate } 2737c478bd9Sstevel@tonic-gate 2747c478bd9Sstevel@tonic-gate static service_type_t 2757c478bd9Sstevel@tonic-gate lxml_xlate_service_type(xmlChar *type) 2767c478bd9Sstevel@tonic-gate { 2777c478bd9Sstevel@tonic-gate if (xmlStrcmp(type, (const xmlChar *)"service") == 0) 2787c478bd9Sstevel@tonic-gate return (SVCCFG_SERVICE); 2797c478bd9Sstevel@tonic-gate 2807c478bd9Sstevel@tonic-gate if (xmlStrcmp(type, (const xmlChar *)"restarter") == 0) 2817c478bd9Sstevel@tonic-gate return (SVCCFG_RESTARTER); 2827c478bd9Sstevel@tonic-gate 2837c478bd9Sstevel@tonic-gate if (xmlStrcmp(type, (const xmlChar *)"milestone") == 0) 2847c478bd9Sstevel@tonic-gate return (SVCCFG_MILESTONE); 2857c478bd9Sstevel@tonic-gate 2867c478bd9Sstevel@tonic-gate return (SVCCFG_UNKNOWN_SERVICE); 2877c478bd9Sstevel@tonic-gate } 2887c478bd9Sstevel@tonic-gate 2897c478bd9Sstevel@tonic-gate static element_t 2907c478bd9Sstevel@tonic-gate lxml_xlate_element(const xmlChar *tag) 2917c478bd9Sstevel@tonic-gate { 2927c478bd9Sstevel@tonic-gate int i; 2937c478bd9Sstevel@tonic-gate 2947c478bd9Sstevel@tonic-gate for (i = 0; i < sizeof (lxml_elements) / sizeof (char *); i++) 2957c478bd9Sstevel@tonic-gate if (xmlStrcmp(tag, (const xmlChar *)lxml_elements[i]) == 0) 2967c478bd9Sstevel@tonic-gate return ((element_t)i); 2977c478bd9Sstevel@tonic-gate 2987c478bd9Sstevel@tonic-gate return ((element_t)-1); 2997c478bd9Sstevel@tonic-gate } 3007c478bd9Sstevel@tonic-gate 3017c478bd9Sstevel@tonic-gate static uint_t 3027c478bd9Sstevel@tonic-gate lxml_xlate_boolean(const xmlChar *value) 3037c478bd9Sstevel@tonic-gate { 3047c478bd9Sstevel@tonic-gate if (xmlStrcmp(value, (const xmlChar *)true) == 0) 3057c478bd9Sstevel@tonic-gate return (1); 3067c478bd9Sstevel@tonic-gate 3077c478bd9Sstevel@tonic-gate if (xmlStrcmp(value, (const xmlChar *)false) == 0) 3087c478bd9Sstevel@tonic-gate return (0); 3097c478bd9Sstevel@tonic-gate 3107c478bd9Sstevel@tonic-gate uu_die(gettext("illegal boolean value \"%s\"\n"), value); 3117c478bd9Sstevel@tonic-gate 3127c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 3137c478bd9Sstevel@tonic-gate } 3147c478bd9Sstevel@tonic-gate 3157c478bd9Sstevel@tonic-gate static scf_type_t 3167c478bd9Sstevel@tonic-gate lxml_element_to_type(element_t type) 3177c478bd9Sstevel@tonic-gate { 3187c478bd9Sstevel@tonic-gate switch (type) { 3197c478bd9Sstevel@tonic-gate case SC_ASTRING: return (SCF_TYPE_ASTRING); 3207c478bd9Sstevel@tonic-gate case SC_BOOLEAN: return (SCF_TYPE_BOOLEAN); 3217c478bd9Sstevel@tonic-gate case SC_COUNT: return (SCF_TYPE_COUNT); 3227c478bd9Sstevel@tonic-gate case SC_FMRI: return (SCF_TYPE_FMRI); 3237c478bd9Sstevel@tonic-gate case SC_HOST: return (SCF_TYPE_HOST); 3247c478bd9Sstevel@tonic-gate case SC_HOSTNAME: return (SCF_TYPE_HOSTNAME); 3257c478bd9Sstevel@tonic-gate case SC_INTEGER: return (SCF_TYPE_INTEGER); 326f6f041a2SAntonello Cruz case SC_NET_ADDR: return (SCF_TYPE_NET_ADDR); 3277c478bd9Sstevel@tonic-gate case SC_NET_ADDR_V4: return (SCF_TYPE_NET_ADDR_V4); 3287c478bd9Sstevel@tonic-gate case SC_NET_ADDR_V6: return (SCF_TYPE_NET_ADDR_V6); 3297c478bd9Sstevel@tonic-gate case SC_OPAQUE: return (SCF_TYPE_OPAQUE); 3307c478bd9Sstevel@tonic-gate case SC_TIME: return (SCF_TYPE_TIME); 3317c478bd9Sstevel@tonic-gate case SC_URI: return (SCF_TYPE_URI); 3327c478bd9Sstevel@tonic-gate case SC_USTRING: return (SCF_TYPE_USTRING); 3337c478bd9Sstevel@tonic-gate 3347c478bd9Sstevel@tonic-gate default: 3357c478bd9Sstevel@tonic-gate uu_die(gettext("unknown value type (%d)\n"), type); 3367c478bd9Sstevel@tonic-gate } 3377c478bd9Sstevel@tonic-gate 3387c478bd9Sstevel@tonic-gate /* NOTREACHED */ 3397c478bd9Sstevel@tonic-gate } 3407c478bd9Sstevel@tonic-gate 341f329b923SSean Wilcox static element_t 342f329b923SSean Wilcox lxml_type_to_element(scf_type_t type) 3437c478bd9Sstevel@tonic-gate { 3447c478bd9Sstevel@tonic-gate switch (type) { 345f329b923SSean Wilcox case SCF_TYPE_ASTRING: return (SC_ASTRING); 346f329b923SSean Wilcox case SCF_TYPE_BOOLEAN: return (SC_BOOLEAN); 347f329b923SSean Wilcox case SCF_TYPE_COUNT: return (SC_COUNT); 348f329b923SSean Wilcox case SCF_TYPE_FMRI: return (SC_FMRI); 349f329b923SSean Wilcox case SCF_TYPE_HOST: return (SC_HOST); 350f329b923SSean Wilcox case SCF_TYPE_HOSTNAME: return (SC_HOSTNAME); 351f329b923SSean Wilcox case SCF_TYPE_INTEGER: return (SC_INTEGER); 352f6f041a2SAntonello Cruz case SCF_TYPE_NET_ADDR: return (SC_NET_ADDR); 353f329b923SSean Wilcox case SCF_TYPE_NET_ADDR_V4: return (SC_NET_ADDR_V4); 354f329b923SSean Wilcox case SCF_TYPE_NET_ADDR_V6: return (SC_NET_ADDR_V6); 355f329b923SSean Wilcox case SCF_TYPE_OPAQUE: return (SC_OPAQUE); 356f329b923SSean Wilcox case SCF_TYPE_TIME: return (SC_TIME); 357f329b923SSean Wilcox case SCF_TYPE_URI: return (SC_URI); 358f329b923SSean Wilcox case SCF_TYPE_USTRING: return (SC_USTRING); 359f329b923SSean Wilcox 3607c478bd9Sstevel@tonic-gate default: 3617c478bd9Sstevel@tonic-gate uu_die(gettext("unknown value type (%d)\n"), type); 3627c478bd9Sstevel@tonic-gate } 3637c478bd9Sstevel@tonic-gate 3647c478bd9Sstevel@tonic-gate /* NOTREACHED */ 3657c478bd9Sstevel@tonic-gate } 3667c478bd9Sstevel@tonic-gate 3671f6eb021SLiane Praza /* 3681f6eb021SLiane Praza * Create a SCF_TYPE_BOOLEAN property name pname and attach it to the 3691f6eb021SLiane Praza * property group at pgrp. The value of the property will be set from the 3701f6eb021SLiane Praza * attribute named attr. attr must have a value of 0, 1, true or false. 3711f6eb021SLiane Praza * 3721f6eb021SLiane Praza * Zero is returned on success. An error is indicated by -1. It indicates 3731f6eb021SLiane Praza * that either the attribute had an invalid value or that we could not 3741f6eb021SLiane Praza * attach the property to pgrp. The attribute should not have an invalid 3751f6eb021SLiane Praza * value if the DTD is correctly written. 3761f6eb021SLiane Praza */ 3771f6eb021SLiane Praza static int 3781f6eb021SLiane Praza new_bool_prop_from_attr(pgroup_t *pgrp, const char *pname, xmlNodePtr n, 3791f6eb021SLiane Praza const char *attr) 3801f6eb021SLiane Praza { 3811f6eb021SLiane Praza uint64_t bool; 3821f6eb021SLiane Praza xmlChar *val; 3831f6eb021SLiane Praza property_t *p; 3841f6eb021SLiane Praza int r; 3851f6eb021SLiane Praza 3861f6eb021SLiane Praza val = xmlGetProp(n, (xmlChar *)attr); 3871f6eb021SLiane Praza if (val == NULL) 3881f6eb021SLiane Praza return (0); 3891f6eb021SLiane Praza 3901f6eb021SLiane Praza if ((xmlStrcmp(val, (xmlChar *)"0") == 0) || 3911f6eb021SLiane Praza (xmlStrcmp(val, (xmlChar *)"false") == 0)) { 3921f6eb021SLiane Praza bool = 0; 3931f6eb021SLiane Praza } else if ((xmlStrcmp(val, (xmlChar *)"1") == 0) || 3941f6eb021SLiane Praza (xmlStrcmp(val, (xmlChar *)"true") == 0)) { 3951f6eb021SLiane Praza bool = 1; 3961f6eb021SLiane Praza } else { 3971f6eb021SLiane Praza xmlFree(val); 3981f6eb021SLiane Praza return (-1); 3991f6eb021SLiane Praza } 4001f6eb021SLiane Praza xmlFree(val); 4011f6eb021SLiane Praza p = internal_property_create(pname, SCF_TYPE_BOOLEAN, 1, bool); 4021f6eb021SLiane Praza r = internal_attach_property(pgrp, p); 4031f6eb021SLiane Praza 4041f6eb021SLiane Praza if (r != 0) 4051f6eb021SLiane Praza internal_property_free(p); 4061f6eb021SLiane Praza 4071f6eb021SLiane Praza return (r); 4081f6eb021SLiane Praza } 4091f6eb021SLiane Praza 4107c478bd9Sstevel@tonic-gate static int 4117c478bd9Sstevel@tonic-gate new_str_prop_from_attr(pgroup_t *pgrp, const char *pname, scf_type_t ty, 4127c478bd9Sstevel@tonic-gate xmlNodePtr n, const char *attr) 4137c478bd9Sstevel@tonic-gate { 4147c478bd9Sstevel@tonic-gate xmlChar *val; 4157c478bd9Sstevel@tonic-gate property_t *p; 4167c478bd9Sstevel@tonic-gate int r; 4177c478bd9Sstevel@tonic-gate 4187c478bd9Sstevel@tonic-gate val = xmlGetProp(n, (xmlChar *)attr); 4197c478bd9Sstevel@tonic-gate 4207c478bd9Sstevel@tonic-gate p = internal_property_create(pname, ty, 1, val); 4217c478bd9Sstevel@tonic-gate r = internal_attach_property(pgrp, p); 4227c478bd9Sstevel@tonic-gate 4237c478bd9Sstevel@tonic-gate if (r != 0) 4247c478bd9Sstevel@tonic-gate internal_property_free(p); 4257c478bd9Sstevel@tonic-gate 4267c478bd9Sstevel@tonic-gate return (r); 4277c478bd9Sstevel@tonic-gate } 4287c478bd9Sstevel@tonic-gate 4297c478bd9Sstevel@tonic-gate static int 4301f6eb021SLiane Praza new_opt_str_prop_from_attr(pgroup_t *pgrp, const char *pname, scf_type_t ty, 4311f6eb021SLiane Praza xmlNodePtr n, const char *attr, const char *dflt) 4321f6eb021SLiane Praza { 4331f6eb021SLiane Praza xmlChar *val; 4341f6eb021SLiane Praza property_t *p; 4351f6eb021SLiane Praza int r; 4361f6eb021SLiane Praza 4371f6eb021SLiane Praza val = xmlGetProp(n, (xmlChar *)attr); 4381f6eb021SLiane Praza if (val == NULL) { 4391f6eb021SLiane Praza if (dflt == NULL) { 4401f6eb021SLiane Praza /* 4411f6eb021SLiane Praza * A missing attribute is considered to be a 4421f6eb021SLiane Praza * success in this function, because many of the 4431f6eb021SLiane Praza * attributes are optional. Missing non-optional 4441f6eb021SLiane Praza * attributes will be detected later when template 4451f6eb021SLiane Praza * validation is done. 4461f6eb021SLiane Praza */ 4471f6eb021SLiane Praza return (0); 4481f6eb021SLiane Praza } else { 4491f6eb021SLiane Praza val = (xmlChar *)dflt; 4501f6eb021SLiane Praza } 4511f6eb021SLiane Praza } 4521f6eb021SLiane Praza 4531f6eb021SLiane Praza p = internal_property_create(pname, ty, 1, val); 4541f6eb021SLiane Praza r = internal_attach_property(pgrp, p); 4551f6eb021SLiane Praza 4561f6eb021SLiane Praza if (r != 0) 4571f6eb021SLiane Praza internal_property_free(p); 4581f6eb021SLiane Praza 4591f6eb021SLiane Praza return (r); 4601f6eb021SLiane Praza } 4611f6eb021SLiane Praza 4621f6eb021SLiane Praza static int 4637c478bd9Sstevel@tonic-gate lxml_ignorable_block(xmlNodePtr n) 4647c478bd9Sstevel@tonic-gate { 4657c478bd9Sstevel@tonic-gate return ((xmlStrcmp(n->name, (xmlChar *)"text") == 0 || 4667c478bd9Sstevel@tonic-gate xmlStrcmp(n->name, (xmlChar *)"comment") == 0) ? 1 : 0); 4677c478bd9Sstevel@tonic-gate } 4687c478bd9Sstevel@tonic-gate 469f329b923SSean Wilcox static void 470f329b923SSean Wilcox lxml_validate_element(xmlNodePtr n) 471f329b923SSean Wilcox { 472f329b923SSean Wilcox xmlValidCtxtPtr vcp; 473f329b923SSean Wilcox 474f329b923SSean Wilcox if (n->doc == NULL) 475f329b923SSean Wilcox uu_die(gettext("Could not validate element\n")); 476f329b923SSean Wilcox 477f329b923SSean Wilcox if (n->doc->extSubset == NULL) { 478f329b923SSean Wilcox xmlDtdPtr dtd; 479f329b923SSean Wilcox dtd = xmlParseDTD(NULL, n->doc->intSubset->SystemID); 480f329b923SSean Wilcox 481f329b923SSean Wilcox if (dtd == NULL) { 482f329b923SSean Wilcox uu_die(gettext("Could not parse DTD \"%s\".\n"), 483f329b923SSean Wilcox n->doc->intSubset->SystemID); 484f329b923SSean Wilcox } 485f329b923SSean Wilcox 486f329b923SSean Wilcox n->doc->extSubset = dtd; 487f329b923SSean Wilcox } 488f329b923SSean Wilcox 489f329b923SSean Wilcox vcp = xmlNewValidCtxt(); 490f329b923SSean Wilcox if (vcp == NULL) 491f329b923SSean Wilcox uu_die(gettext("could not allocate memory")); 492f329b923SSean Wilcox 493f329b923SSean Wilcox vcp->warning = xmlParserValidityWarning; 494f329b923SSean Wilcox vcp->error = xmlParserValidityError; 495f329b923SSean Wilcox 496f329b923SSean Wilcox if (xmlValidateElement(vcp, n->doc, n) == 0) 497f329b923SSean Wilcox uu_die(gettext("Document is not valid.\n")); 498f329b923SSean Wilcox 499f329b923SSean Wilcox xmlFreeValidCtxt(vcp); 500f329b923SSean Wilcox } 501f329b923SSean Wilcox 5027c478bd9Sstevel@tonic-gate static int 5037c478bd9Sstevel@tonic-gate lxml_validate_string_value(scf_type_t type, const char *v) 5047c478bd9Sstevel@tonic-gate { 5057c478bd9Sstevel@tonic-gate static scf_value_t *scf_value = NULL; 5067c478bd9Sstevel@tonic-gate static scf_handle_t *scf_hndl = NULL; 5077c478bd9Sstevel@tonic-gate 5087c478bd9Sstevel@tonic-gate if (scf_hndl == NULL && (scf_hndl = scf_handle_create(SCF_VERSION)) == 5097c478bd9Sstevel@tonic-gate NULL) 5107c478bd9Sstevel@tonic-gate return (-1); 5117c478bd9Sstevel@tonic-gate 5127c478bd9Sstevel@tonic-gate if (scf_value == NULL && (scf_value = scf_value_create(scf_hndl)) == 5137c478bd9Sstevel@tonic-gate NULL) 5147c478bd9Sstevel@tonic-gate return (-1); 5157c478bd9Sstevel@tonic-gate 5167c478bd9Sstevel@tonic-gate return (scf_value_set_from_string(scf_value, type, v)); 5177c478bd9Sstevel@tonic-gate } 5187c478bd9Sstevel@tonic-gate 5197c478bd9Sstevel@tonic-gate static void 5207c478bd9Sstevel@tonic-gate lxml_free_str(value_t *val) 5217c478bd9Sstevel@tonic-gate { 5227c478bd9Sstevel@tonic-gate free(val->sc_u.sc_string); 5237c478bd9Sstevel@tonic-gate } 5247c478bd9Sstevel@tonic-gate 525f329b923SSean Wilcox /* 526f329b923SSean Wilcox * Take a value_t structure and a type and value. Based on the type 527f329b923SSean Wilcox * ensure that the value is of that type. If so store the value in 528f329b923SSean Wilcox * the correct location of the value_t structure. 529f329b923SSean Wilcox * 530f329b923SSean Wilcox * If the value is NULL, the value_t structure will have been created 531f329b923SSean Wilcox * and the value would have ultimately been stored as a string value 532f329b923SSean Wilcox * but at the time the type was unknown. Now the type should be known 533f329b923SSean Wilcox * so take the type and value from value_t and validate and store 534f329b923SSean Wilcox * the value correctly if the value is of the stated type. 535f329b923SSean Wilcox */ 536f329b923SSean Wilcox void 537f329b923SSean Wilcox lxml_store_value(value_t *v, element_t type, const xmlChar *value) 5387c478bd9Sstevel@tonic-gate { 5397c478bd9Sstevel@tonic-gate char *endptr; 540f329b923SSean Wilcox int fov = 0; 5417c478bd9Sstevel@tonic-gate scf_type_t scf_type = SCF_TYPE_INVALID; 5427c478bd9Sstevel@tonic-gate 543f329b923SSean Wilcox if (value == NULL) { 544f329b923SSean Wilcox type = lxml_type_to_element(v->sc_type); 545f329b923SSean Wilcox value = (const xmlChar *)v->sc_u.sc_string; 546f329b923SSean Wilcox fov = 1; 547f329b923SSean Wilcox } 5487c478bd9Sstevel@tonic-gate 5497c478bd9Sstevel@tonic-gate switch (type) { 5507c478bd9Sstevel@tonic-gate case SC_COUNT: 5517c478bd9Sstevel@tonic-gate /* 5527c478bd9Sstevel@tonic-gate * Although an SC_COUNT represents a uint64_t the use 5537c478bd9Sstevel@tonic-gate * of a negative value is acceptable due to the usage 5547c478bd9Sstevel@tonic-gate * established by inetd(1M). 5557c478bd9Sstevel@tonic-gate */ 5567c478bd9Sstevel@tonic-gate errno = 0; 5577c478bd9Sstevel@tonic-gate v->sc_u.sc_count = strtoull((char *)value, &endptr, 10); 5587c478bd9Sstevel@tonic-gate if (errno != 0 || endptr == (char *)value || *endptr) 5597c478bd9Sstevel@tonic-gate uu_die(gettext("illegal value \"%s\" for " 5607c478bd9Sstevel@tonic-gate "%s (%s)\n"), (char *)value, 5617c478bd9Sstevel@tonic-gate lxml_prop_types[type], 5627c478bd9Sstevel@tonic-gate (errno) ? strerror(errno) : 5637c478bd9Sstevel@tonic-gate gettext("Illegal character")); 5647c478bd9Sstevel@tonic-gate break; 5657c478bd9Sstevel@tonic-gate case SC_INTEGER: 5667c478bd9Sstevel@tonic-gate errno = 0; 5677c478bd9Sstevel@tonic-gate v->sc_u.sc_integer = strtoll((char *)value, &endptr, 10); 5687c478bd9Sstevel@tonic-gate if (errno != 0 || *endptr) 5697c478bd9Sstevel@tonic-gate uu_die(gettext("illegal value \"%s\" for " 5707c478bd9Sstevel@tonic-gate "%s (%s)\n"), (char *)value, 5717c478bd9Sstevel@tonic-gate lxml_prop_types[type], 5727c478bd9Sstevel@tonic-gate (errno) ? strerror(errno) : "Illegal character"); 5737c478bd9Sstevel@tonic-gate break; 5747c478bd9Sstevel@tonic-gate case SC_OPAQUE: 5757c478bd9Sstevel@tonic-gate case SC_HOST: 5767c478bd9Sstevel@tonic-gate case SC_HOSTNAME: 577f6f041a2SAntonello Cruz case SC_NET_ADDR: 5787c478bd9Sstevel@tonic-gate case SC_NET_ADDR_V4: 5797c478bd9Sstevel@tonic-gate case SC_NET_ADDR_V6: 5807c478bd9Sstevel@tonic-gate case SC_FMRI: 5817c478bd9Sstevel@tonic-gate case SC_URI: 5827c478bd9Sstevel@tonic-gate case SC_TIME: 5837c478bd9Sstevel@tonic-gate case SC_ASTRING: 5847c478bd9Sstevel@tonic-gate case SC_USTRING: 585f329b923SSean Wilcox scf_type = lxml_element_to_type(type); 5867c478bd9Sstevel@tonic-gate 587*67b0e063SAlbert Lee v->sc_u.sc_string = safe_strdup((const char *)value); 5887c478bd9Sstevel@tonic-gate if (lxml_validate_string_value(scf_type, 5897c478bd9Sstevel@tonic-gate v->sc_u.sc_string) != 0) 5907c478bd9Sstevel@tonic-gate uu_die(gettext("illegal value \"%s\" for " 5917c478bd9Sstevel@tonic-gate "%s (%s)\n"), (char *)value, 5927c478bd9Sstevel@tonic-gate lxml_prop_types[type], 5937c478bd9Sstevel@tonic-gate (scf_error()) ? scf_strerror(scf_error()) : 5947c478bd9Sstevel@tonic-gate gettext("Illegal format")); 5957c478bd9Sstevel@tonic-gate v->sc_free = lxml_free_str; 5967c478bd9Sstevel@tonic-gate break; 5977c478bd9Sstevel@tonic-gate case SC_BOOLEAN: 5987c478bd9Sstevel@tonic-gate v->sc_u.sc_count = lxml_xlate_boolean(value); 5997c478bd9Sstevel@tonic-gate break; 6007c478bd9Sstevel@tonic-gate default: 6017c478bd9Sstevel@tonic-gate uu_die(gettext("unknown value type (%d)\n"), type); 6027c478bd9Sstevel@tonic-gate break; 6037c478bd9Sstevel@tonic-gate } 6047c478bd9Sstevel@tonic-gate 605f329b923SSean Wilcox /* Free the old value */ 606f329b923SSean Wilcox if (fov && v->sc_free != NULL) 607f329b923SSean Wilcox free((char *)value); 608f329b923SSean Wilcox } 609f329b923SSean Wilcox 610f329b923SSean Wilcox static value_t * 611f329b923SSean Wilcox lxml_make_value(element_t type, const xmlChar *value) 612f329b923SSean Wilcox { 613f329b923SSean Wilcox value_t *v; 614f329b923SSean Wilcox 615f329b923SSean Wilcox v = internal_value_new(); 616f329b923SSean Wilcox 617f329b923SSean Wilcox v->sc_type = lxml_element_to_type(type); 618f329b923SSean Wilcox 619f329b923SSean Wilcox lxml_store_value(v, type, value); 620f329b923SSean Wilcox 6217c478bd9Sstevel@tonic-gate return (v); 6227c478bd9Sstevel@tonic-gate } 6237c478bd9Sstevel@tonic-gate 6247c478bd9Sstevel@tonic-gate static int 6257c478bd9Sstevel@tonic-gate lxml_get_value(property_t *prop, element_t vtype, xmlNodePtr value) 6267c478bd9Sstevel@tonic-gate { 6277c478bd9Sstevel@tonic-gate xmlNodePtr cursor; 6287c478bd9Sstevel@tonic-gate 6297c478bd9Sstevel@tonic-gate for (cursor = value->xmlChildrenNode; cursor != NULL; 6307c478bd9Sstevel@tonic-gate cursor = cursor->next) { 6317c478bd9Sstevel@tonic-gate xmlChar *assigned_value; 6327c478bd9Sstevel@tonic-gate value_t *v; 6337c478bd9Sstevel@tonic-gate 6347c478bd9Sstevel@tonic-gate if (lxml_ignorable_block(cursor)) 6357c478bd9Sstevel@tonic-gate continue; 6367c478bd9Sstevel@tonic-gate 6377c478bd9Sstevel@tonic-gate switch (lxml_xlate_element(cursor->name)) { 6387c478bd9Sstevel@tonic-gate case SC_VALUE_NODE: 6397c478bd9Sstevel@tonic-gate if ((assigned_value = xmlGetProp(cursor, 6407c478bd9Sstevel@tonic-gate (xmlChar *)value_attr)) == NULL) 6417c478bd9Sstevel@tonic-gate uu_die(gettext("no value on value node?\n")); 6427c478bd9Sstevel@tonic-gate break; 6437c478bd9Sstevel@tonic-gate default: 6447c478bd9Sstevel@tonic-gate uu_die(gettext("value list contains illegal element " 6457c478bd9Sstevel@tonic-gate "\'%s\'\n"), cursor->name); 6467c478bd9Sstevel@tonic-gate break; 6477c478bd9Sstevel@tonic-gate } 6487c478bd9Sstevel@tonic-gate 6497c478bd9Sstevel@tonic-gate v = lxml_make_value(vtype, assigned_value); 6507c478bd9Sstevel@tonic-gate 6517c478bd9Sstevel@tonic-gate xmlFree(assigned_value); 6527c478bd9Sstevel@tonic-gate 6537c478bd9Sstevel@tonic-gate internal_attach_value(prop, v); 6547c478bd9Sstevel@tonic-gate } 6557c478bd9Sstevel@tonic-gate 6567c478bd9Sstevel@tonic-gate return (0); 6577c478bd9Sstevel@tonic-gate } 6587c478bd9Sstevel@tonic-gate 6597c478bd9Sstevel@tonic-gate static int 6607c478bd9Sstevel@tonic-gate lxml_get_propval(pgroup_t *pgrp, xmlNodePtr propval) 6617c478bd9Sstevel@tonic-gate { 6627c478bd9Sstevel@tonic-gate property_t *p; 6637c478bd9Sstevel@tonic-gate element_t r; 6647c478bd9Sstevel@tonic-gate value_t *v; 6657c478bd9Sstevel@tonic-gate xmlChar *type, *val, *override; 666f329b923SSean Wilcox int op = pgrp->sc_parent->sc_op; 6677c478bd9Sstevel@tonic-gate 6687c478bd9Sstevel@tonic-gate p = internal_property_new(); 6697c478bd9Sstevel@tonic-gate 6707c478bd9Sstevel@tonic-gate p->sc_property_name = (char *)xmlGetProp(propval, (xmlChar *)name_attr); 6711f6eb021SLiane Praza if ((p->sc_property_name == NULL) || (*p->sc_property_name == 0)) 6727c478bd9Sstevel@tonic-gate uu_die(gettext("property name missing in group '%s'\n"), 6737c478bd9Sstevel@tonic-gate pgrp->sc_pgroup_name); 6747c478bd9Sstevel@tonic-gate 6757c478bd9Sstevel@tonic-gate type = xmlGetProp(propval, (xmlChar *)type_attr); 676f329b923SSean Wilcox if ((type != NULL) && (*type != 0)) { 677f329b923SSean Wilcox for (r = 0; 678f329b923SSean Wilcox r < sizeof (lxml_prop_types) / sizeof (char *); ++r) { 679f329b923SSean Wilcox if (xmlStrcmp(type, 680f329b923SSean Wilcox (const xmlChar *)lxml_prop_types[r]) == 0) 6817c478bd9Sstevel@tonic-gate break; 6827c478bd9Sstevel@tonic-gate } 683f329b923SSean Wilcox 6847c478bd9Sstevel@tonic-gate if (r >= sizeof (lxml_prop_types) / sizeof (char *)) 685f329b923SSean Wilcox uu_die(gettext("property type invalid for " 686f329b923SSean Wilcox "property '%s/%s'\n"), pgrp->sc_pgroup_name, 687f329b923SSean Wilcox p->sc_property_name); 6887c478bd9Sstevel@tonic-gate 6897c478bd9Sstevel@tonic-gate p->sc_value_type = lxml_element_to_type(r); 690f329b923SSean Wilcox } else if (op == SVCCFG_OP_APPLY) { 691f329b923SSean Wilcox /* 692f329b923SSean Wilcox * Store the property type as invalid, and the value 693f329b923SSean Wilcox * as an ASTRING and let the bundle apply code validate 694f329b923SSean Wilcox * the type/value once the type is found. 695f329b923SSean Wilcox */ 696f329b923SSean Wilcox est->sc_miss_type = B_TRUE; 697f329b923SSean Wilcox p->sc_value_type = SCF_TYPE_INVALID; 698f329b923SSean Wilcox r = SC_ASTRING; 699f329b923SSean Wilcox } else { 700f329b923SSean Wilcox uu_die(gettext("property type missing for property '%s/%s'\n"), 701f329b923SSean Wilcox pgrp->sc_pgroup_name, p->sc_property_name); 702f329b923SSean Wilcox } 7037c478bd9Sstevel@tonic-gate 7047c478bd9Sstevel@tonic-gate val = xmlGetProp(propval, (xmlChar *)value_attr); 7057c478bd9Sstevel@tonic-gate if (val == NULL) 7067c478bd9Sstevel@tonic-gate uu_die(gettext("property value missing for property '%s/%s'\n"), 7077c478bd9Sstevel@tonic-gate pgrp->sc_pgroup_name, p->sc_property_name); 7087c478bd9Sstevel@tonic-gate 7097c478bd9Sstevel@tonic-gate v = lxml_make_value(r, val); 7101f6eb021SLiane Praza xmlFree(val); 7117c478bd9Sstevel@tonic-gate internal_attach_value(p, v); 7127c478bd9Sstevel@tonic-gate 713f329b923SSean Wilcox xmlFree(type); 714f329b923SSean Wilcox 7157c478bd9Sstevel@tonic-gate override = xmlGetProp(propval, (xmlChar *)override_attr); 7167c478bd9Sstevel@tonic-gate p->sc_property_override = (xmlStrcmp(override, (xmlChar *)true) == 0); 7177c478bd9Sstevel@tonic-gate xmlFree(override); 7187c478bd9Sstevel@tonic-gate 7197c478bd9Sstevel@tonic-gate return (internal_attach_property(pgrp, p)); 7207c478bd9Sstevel@tonic-gate } 7217c478bd9Sstevel@tonic-gate 7227c478bd9Sstevel@tonic-gate static int 7237c478bd9Sstevel@tonic-gate lxml_get_property(pgroup_t *pgrp, xmlNodePtr property) 7247c478bd9Sstevel@tonic-gate { 7257c478bd9Sstevel@tonic-gate property_t *p; 7267c478bd9Sstevel@tonic-gate xmlNodePtr cursor; 7277c478bd9Sstevel@tonic-gate element_t r; 7287c478bd9Sstevel@tonic-gate xmlChar *type, *override; 729f329b923SSean Wilcox int op = pgrp->sc_parent->sc_op; 7307c478bd9Sstevel@tonic-gate 7317c478bd9Sstevel@tonic-gate p = internal_property_new(); 7327c478bd9Sstevel@tonic-gate 7331f6eb021SLiane Praza if (((p->sc_property_name = (char *)xmlGetProp(property, 7341f6eb021SLiane Praza (xmlChar *)name_attr)) == NULL) || (*p->sc_property_name == 0)) 7357c478bd9Sstevel@tonic-gate uu_die(gettext("property name missing in group \'%s\'\n"), 7367c478bd9Sstevel@tonic-gate pgrp->sc_pgroup_name); 7377c478bd9Sstevel@tonic-gate 738f329b923SSean Wilcox type = xmlGetProp(property, (xmlChar *)type_attr); 739f329b923SSean Wilcox if ((type != NULL) && (*type != 0)) { 740f329b923SSean Wilcox for (r = 0; 741f329b923SSean Wilcox r < sizeof (lxml_prop_types) / sizeof (char *); r++) { 742f329b923SSean Wilcox if (xmlStrcmp(type, 743f329b923SSean Wilcox (const xmlChar *)lxml_prop_types[r]) == 0) 744f329b923SSean Wilcox break; 745f329b923SSean Wilcox } 746f329b923SSean Wilcox 747f329b923SSean Wilcox if (r >= sizeof (lxml_prop_types) / sizeof (char *)) 748f329b923SSean Wilcox uu_die(gettext("property type invalid for " 749f329b923SSean Wilcox "property '%s/%s'\n"), pgrp->sc_pgroup_name, 750f329b923SSean Wilcox p->sc_property_name); 751f329b923SSean Wilcox 752f329b923SSean Wilcox p->sc_value_type = lxml_element_to_type(r); 753f329b923SSean Wilcox } else if (op == SVCCFG_OP_APPLY) { 754f329b923SSean Wilcox /* 755f329b923SSean Wilcox * Store the property type as invalid, and let the bundle apply 756f329b923SSean Wilcox * code validate the type/value once the type is found. 757f329b923SSean Wilcox */ 758f329b923SSean Wilcox p->sc_value_type = SCF_TYPE_INVALID; 759f329b923SSean Wilcox est->sc_miss_type = B_TRUE; 760f329b923SSean Wilcox } else { 7617c478bd9Sstevel@tonic-gate uu_die(gettext("property type missing for " 7627c478bd9Sstevel@tonic-gate "property \'%s/%s\'\n"), pgrp->sc_pgroup_name, 7637c478bd9Sstevel@tonic-gate p->sc_property_name); 7641f6eb021SLiane Praza } 7657c478bd9Sstevel@tonic-gate 7667c478bd9Sstevel@tonic-gate for (cursor = property->xmlChildrenNode; cursor != NULL; 7677c478bd9Sstevel@tonic-gate cursor = cursor->next) { 7687c478bd9Sstevel@tonic-gate if (lxml_ignorable_block(cursor)) 7697c478bd9Sstevel@tonic-gate continue; 7707c478bd9Sstevel@tonic-gate 7717c478bd9Sstevel@tonic-gate switch (r = lxml_xlate_element(cursor->name)) { 7727c478bd9Sstevel@tonic-gate case SC_ASTRING: 7737c478bd9Sstevel@tonic-gate case SC_BOOLEAN: 7747c478bd9Sstevel@tonic-gate case SC_COUNT: 7757c478bd9Sstevel@tonic-gate case SC_FMRI: 7767c478bd9Sstevel@tonic-gate case SC_HOST: 7777c478bd9Sstevel@tonic-gate case SC_HOSTNAME: 7787c478bd9Sstevel@tonic-gate case SC_INTEGER: 779f6f041a2SAntonello Cruz case SC_NET_ADDR: 7807c478bd9Sstevel@tonic-gate case SC_NET_ADDR_V4: 7817c478bd9Sstevel@tonic-gate case SC_NET_ADDR_V6: 7827c478bd9Sstevel@tonic-gate case SC_OPAQUE: 7837c478bd9Sstevel@tonic-gate case SC_TIME: 7847c478bd9Sstevel@tonic-gate case SC_URI: 7857c478bd9Sstevel@tonic-gate case SC_USTRING: 786f329b923SSean Wilcox /* 787f329b923SSean Wilcox * If the type is invalid then this is an apply 788f329b923SSean Wilcox * operation and the type can be taken from the 789f329b923SSean Wilcox * value list. 790f329b923SSean Wilcox */ 791f329b923SSean Wilcox if (p->sc_value_type == SCF_TYPE_INVALID) { 792f329b923SSean Wilcox p->sc_value_type = lxml_element_to_type(r); 793f329b923SSean Wilcox type = xmlStrdup((const 794f329b923SSean Wilcox xmlChar *)lxml_prop_types[r]); 795f329b923SSean Wilcox 796f329b923SSean Wilcox } else if (strcmp(lxml_prop_types[r], 797f329b923SSean Wilcox (const char *)type) != 0) { 7987c478bd9Sstevel@tonic-gate uu_die(gettext("property \'%s\' " 7997c478bd9Sstevel@tonic-gate "type-to-list mismatch\n"), 8007c478bd9Sstevel@tonic-gate p->sc_property_name); 801f329b923SSean Wilcox } 8027c478bd9Sstevel@tonic-gate 8037c478bd9Sstevel@tonic-gate (void) lxml_get_value(p, r, cursor); 8047c478bd9Sstevel@tonic-gate break; 8057c478bd9Sstevel@tonic-gate default: 8067c478bd9Sstevel@tonic-gate uu_die(gettext("unknown value list type: %s\n"), 8077c478bd9Sstevel@tonic-gate cursor->name); 8087c478bd9Sstevel@tonic-gate break; 8097c478bd9Sstevel@tonic-gate } 8107c478bd9Sstevel@tonic-gate } 8117c478bd9Sstevel@tonic-gate 8127c478bd9Sstevel@tonic-gate xmlFree(type); 8137c478bd9Sstevel@tonic-gate 8147c478bd9Sstevel@tonic-gate override = xmlGetProp(property, (xmlChar *)override_attr); 8157c478bd9Sstevel@tonic-gate p->sc_property_override = (xmlStrcmp(override, (xmlChar *)true) == 0); 8167c478bd9Sstevel@tonic-gate xmlFree(override); 8177c478bd9Sstevel@tonic-gate 8187c478bd9Sstevel@tonic-gate return (internal_attach_property(pgrp, p)); 8197c478bd9Sstevel@tonic-gate } 8207c478bd9Sstevel@tonic-gate 8217c478bd9Sstevel@tonic-gate static int 8227c478bd9Sstevel@tonic-gate lxml_get_pgroup_stability(pgroup_t *pgrp, xmlNodePtr stab) 8237c478bd9Sstevel@tonic-gate { 824f329b923SSean Wilcox if (pgrp->sc_parent->sc_op == SVCCFG_OP_APPLY) 825f329b923SSean Wilcox lxml_validate_element(stab); 826f329b923SSean Wilcox 8277c478bd9Sstevel@tonic-gate return (new_str_prop_from_attr(pgrp, SCF_PROPERTY_STABILITY, 8287c478bd9Sstevel@tonic-gate SCF_TYPE_ASTRING, stab, value_attr)); 8297c478bd9Sstevel@tonic-gate } 8307c478bd9Sstevel@tonic-gate 8317c478bd9Sstevel@tonic-gate /* 8327c478bd9Sstevel@tonic-gate * Property groups can go on any of a service, an instance, or a template. 8337c478bd9Sstevel@tonic-gate */ 8347c478bd9Sstevel@tonic-gate static int 8357c478bd9Sstevel@tonic-gate lxml_get_pgroup(entity_t *entity, xmlNodePtr pgroup) 8367c478bd9Sstevel@tonic-gate { 8377c478bd9Sstevel@tonic-gate pgroup_t *pg; 8387c478bd9Sstevel@tonic-gate xmlNodePtr cursor; 8397c478bd9Sstevel@tonic-gate xmlChar *name, *type, *delete; 8407c478bd9Sstevel@tonic-gate 8417c478bd9Sstevel@tonic-gate /* 8427c478bd9Sstevel@tonic-gate * property group attributes: 8437c478bd9Sstevel@tonic-gate * name: string 8447c478bd9Sstevel@tonic-gate * type: string | framework | application 8457c478bd9Sstevel@tonic-gate */ 8467c478bd9Sstevel@tonic-gate name = xmlGetProp(pgroup, (xmlChar *)name_attr); 8477c478bd9Sstevel@tonic-gate type = xmlGetProp(pgroup, (xmlChar *)type_attr); 8487c478bd9Sstevel@tonic-gate pg = internal_pgroup_find_or_create(entity, (char *)name, (char *)type); 8497c478bd9Sstevel@tonic-gate xmlFree(name); 8507c478bd9Sstevel@tonic-gate xmlFree(type); 8517c478bd9Sstevel@tonic-gate 8527c478bd9Sstevel@tonic-gate /* 8537c478bd9Sstevel@tonic-gate * Walk the children of this lxml_elements, which are a stability 8547c478bd9Sstevel@tonic-gate * element, property elements, or propval elements. 8557c478bd9Sstevel@tonic-gate */ 8567c478bd9Sstevel@tonic-gate for (cursor = pgroup->xmlChildrenNode; cursor != NULL; 8577c478bd9Sstevel@tonic-gate cursor = cursor->next) { 8587c478bd9Sstevel@tonic-gate if (lxml_ignorable_block(cursor)) 8597c478bd9Sstevel@tonic-gate continue; 8607c478bd9Sstevel@tonic-gate 8617c478bd9Sstevel@tonic-gate switch (lxml_xlate_element(cursor->name)) { 8627c478bd9Sstevel@tonic-gate case SC_STABILITY: 8637c478bd9Sstevel@tonic-gate (void) lxml_get_pgroup_stability(pg, cursor); 8647c478bd9Sstevel@tonic-gate break; 8657c478bd9Sstevel@tonic-gate case SC_PROPERTY: 8667c478bd9Sstevel@tonic-gate (void) lxml_get_property(pg, cursor); 8677c478bd9Sstevel@tonic-gate break; 8687c478bd9Sstevel@tonic-gate case SC_PROPVAL: 8697c478bd9Sstevel@tonic-gate (void) lxml_get_propval(pg, cursor); 8707c478bd9Sstevel@tonic-gate break; 8717c478bd9Sstevel@tonic-gate default: 8727c478bd9Sstevel@tonic-gate abort(); 8737c478bd9Sstevel@tonic-gate break; 8747c478bd9Sstevel@tonic-gate } 8757c478bd9Sstevel@tonic-gate } 8767c478bd9Sstevel@tonic-gate 8777c478bd9Sstevel@tonic-gate delete = xmlGetProp(pgroup, (xmlChar *)delete_attr); 8787c478bd9Sstevel@tonic-gate pg->sc_pgroup_delete = (xmlStrcmp(delete, (xmlChar *)true) == 0); 8797c478bd9Sstevel@tonic-gate xmlFree(delete); 8807c478bd9Sstevel@tonic-gate 8817c478bd9Sstevel@tonic-gate return (0); 8827c478bd9Sstevel@tonic-gate } 8837c478bd9Sstevel@tonic-gate 8847c478bd9Sstevel@tonic-gate 8857c478bd9Sstevel@tonic-gate /* 8867c478bd9Sstevel@tonic-gate * Dependency groups, execution methods can go on either a service or an 8877c478bd9Sstevel@tonic-gate * instance. 8887c478bd9Sstevel@tonic-gate */ 8897c478bd9Sstevel@tonic-gate 8907c478bd9Sstevel@tonic-gate static int 8917c478bd9Sstevel@tonic-gate lxml_get_method_profile(pgroup_t *pg, xmlNodePtr profile) 8927c478bd9Sstevel@tonic-gate { 8937c478bd9Sstevel@tonic-gate property_t *p; 8947c478bd9Sstevel@tonic-gate 8957c478bd9Sstevel@tonic-gate p = internal_property_create(SCF_PROPERTY_USE_PROFILE, SCF_TYPE_BOOLEAN, 8967c478bd9Sstevel@tonic-gate 1, (uint64_t)1); 8977c478bd9Sstevel@tonic-gate if (internal_attach_property(pg, p) != 0) 8987c478bd9Sstevel@tonic-gate return (-1); 8997c478bd9Sstevel@tonic-gate 9007c478bd9Sstevel@tonic-gate return (new_str_prop_from_attr(pg, SCF_PROPERTY_PROFILE, 9017c478bd9Sstevel@tonic-gate SCF_TYPE_ASTRING, profile, name_attr)); 9027c478bd9Sstevel@tonic-gate } 9037c478bd9Sstevel@tonic-gate 9047c478bd9Sstevel@tonic-gate static int 9057c478bd9Sstevel@tonic-gate lxml_get_method_credential(pgroup_t *pg, xmlNodePtr cred) 9067c478bd9Sstevel@tonic-gate { 9077c478bd9Sstevel@tonic-gate property_t *p; 9087c478bd9Sstevel@tonic-gate 9097c478bd9Sstevel@tonic-gate p = internal_property_create(SCF_PROPERTY_USE_PROFILE, SCF_TYPE_BOOLEAN, 9107c478bd9Sstevel@tonic-gate 1, (uint64_t)0); 9117c478bd9Sstevel@tonic-gate if (internal_attach_property(pg, p) != 0) 9127c478bd9Sstevel@tonic-gate return (-1); 9137c478bd9Sstevel@tonic-gate 91413d8aaa1SSean Wilcox if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_USER, SCF_TYPE_ASTRING, 91513d8aaa1SSean Wilcox cred, "user", NULL) != 0) 9167c478bd9Sstevel@tonic-gate return (-1); 9177c478bd9Sstevel@tonic-gate 91813d8aaa1SSean Wilcox if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_GROUP, SCF_TYPE_ASTRING, 91913d8aaa1SSean Wilcox cred, "group", NULL) != 0) 9207c478bd9Sstevel@tonic-gate return (-1); 9217c478bd9Sstevel@tonic-gate 92213d8aaa1SSean Wilcox if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_SUPP_GROUPS, 92313d8aaa1SSean Wilcox SCF_TYPE_ASTRING, cred, "supp_groups", NULL) != 0) 9247c478bd9Sstevel@tonic-gate return (-1); 9257c478bd9Sstevel@tonic-gate 92613d8aaa1SSean Wilcox if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_PRIVILEGES, 92713d8aaa1SSean Wilcox SCF_TYPE_ASTRING, cred, "privileges", NULL) != 0) 9287c478bd9Sstevel@tonic-gate return (-1); 9297c478bd9Sstevel@tonic-gate 93013d8aaa1SSean Wilcox if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_LIMIT_PRIVILEGES, 93113d8aaa1SSean Wilcox SCF_TYPE_ASTRING, cred, "limit_privileges", NULL) != 0) 9327c478bd9Sstevel@tonic-gate return (-1); 9337c478bd9Sstevel@tonic-gate 9347c478bd9Sstevel@tonic-gate return (0); 9357c478bd9Sstevel@tonic-gate } 9367c478bd9Sstevel@tonic-gate 9377c478bd9Sstevel@tonic-gate static char * 9387c478bd9Sstevel@tonic-gate lxml_get_envvar(xmlNodePtr envvar) 9397c478bd9Sstevel@tonic-gate { 9407c478bd9Sstevel@tonic-gate char *name; 9417c478bd9Sstevel@tonic-gate char *value; 9427c478bd9Sstevel@tonic-gate char *ret; 9437c478bd9Sstevel@tonic-gate 9441f6eb021SLiane Praza name = (char *)xmlGetProp(envvar, (xmlChar *)name_attr); 9451f6eb021SLiane Praza value = (char *)xmlGetProp(envvar, (xmlChar *)value_attr); 9467c478bd9Sstevel@tonic-gate 9477c478bd9Sstevel@tonic-gate if (strlen(name) == 0 || strchr(name, '=') != NULL) 9487c478bd9Sstevel@tonic-gate uu_die(gettext("Invalid environment variable " 9497c478bd9Sstevel@tonic-gate "\"%s\".\n"), name); 9507c478bd9Sstevel@tonic-gate if (strstr(name, "SMF_") == name) 9517c478bd9Sstevel@tonic-gate uu_die(gettext("Invalid environment variable " 9527c478bd9Sstevel@tonic-gate "\"%s\"; \"SMF_\" prefix is reserved.\n"), name); 9537c478bd9Sstevel@tonic-gate 9547c478bd9Sstevel@tonic-gate ret = uu_msprintf("%s=%s", name, value); 9557c478bd9Sstevel@tonic-gate xmlFree(name); 9567c478bd9Sstevel@tonic-gate xmlFree(value); 9577c478bd9Sstevel@tonic-gate return (ret); 9587c478bd9Sstevel@tonic-gate } 9597c478bd9Sstevel@tonic-gate 9607c478bd9Sstevel@tonic-gate static int 9617c478bd9Sstevel@tonic-gate lxml_get_method_environment(pgroup_t *pg, xmlNodePtr environment) 9627c478bd9Sstevel@tonic-gate { 9637c478bd9Sstevel@tonic-gate property_t *p; 9647c478bd9Sstevel@tonic-gate xmlNodePtr cursor; 9657c478bd9Sstevel@tonic-gate value_t *val; 9667c478bd9Sstevel@tonic-gate 9677c478bd9Sstevel@tonic-gate p = internal_property_create(SCF_PROPERTY_ENVIRONMENT, 9687c478bd9Sstevel@tonic-gate SCF_TYPE_ASTRING, 0); 9697c478bd9Sstevel@tonic-gate 9707c478bd9Sstevel@tonic-gate for (cursor = environment->xmlChildrenNode; cursor != NULL; 9717c478bd9Sstevel@tonic-gate cursor = cursor->next) { 9727c478bd9Sstevel@tonic-gate char *tmp; 9737c478bd9Sstevel@tonic-gate 9747c478bd9Sstevel@tonic-gate if (lxml_ignorable_block(cursor)) 9757c478bd9Sstevel@tonic-gate continue; 9767c478bd9Sstevel@tonic-gate 9777c478bd9Sstevel@tonic-gate if (lxml_xlate_element(cursor->name) != SC_METHOD_ENVVAR) 9787c478bd9Sstevel@tonic-gate uu_die(gettext("illegal element \"%s\" on " 9797c478bd9Sstevel@tonic-gate "method environment for \"%s\"\n"), 9807c478bd9Sstevel@tonic-gate cursor->name, pg->sc_pgroup_name); 9817c478bd9Sstevel@tonic-gate 9827c478bd9Sstevel@tonic-gate if ((tmp = lxml_get_envvar(cursor)) == NULL) 9837c478bd9Sstevel@tonic-gate uu_die(gettext("Out of memory\n")); 9847c478bd9Sstevel@tonic-gate 9857c478bd9Sstevel@tonic-gate val = internal_value_new(); 9867c478bd9Sstevel@tonic-gate val->sc_u.sc_string = tmp; 9877c478bd9Sstevel@tonic-gate val->sc_type = SCF_TYPE_ASTRING; 9887c478bd9Sstevel@tonic-gate val->sc_free = lxml_free_str; 9897c478bd9Sstevel@tonic-gate internal_attach_value(p, val); 9907c478bd9Sstevel@tonic-gate } 9917c478bd9Sstevel@tonic-gate 9927c478bd9Sstevel@tonic-gate if (internal_attach_property(pg, p) != 0) { 9937c478bd9Sstevel@tonic-gate internal_property_free(p); 9947c478bd9Sstevel@tonic-gate return (-1); 9957c478bd9Sstevel@tonic-gate } 9967c478bd9Sstevel@tonic-gate 9977c478bd9Sstevel@tonic-gate return (0); 9987c478bd9Sstevel@tonic-gate } 9997c478bd9Sstevel@tonic-gate 10007c478bd9Sstevel@tonic-gate static int 10017c478bd9Sstevel@tonic-gate lxml_get_method_context(pgroup_t *pg, xmlNodePtr ctx) 10027c478bd9Sstevel@tonic-gate { 10037c478bd9Sstevel@tonic-gate xmlNodePtr cursor; 10047c478bd9Sstevel@tonic-gate 100513d8aaa1SSean Wilcox if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_WORKING_DIRECTORY, 100613d8aaa1SSean Wilcox SCF_TYPE_ASTRING, ctx, "working_directory", NULL) != 0) 10077c478bd9Sstevel@tonic-gate return (-1); 10087c478bd9Sstevel@tonic-gate 100913d8aaa1SSean Wilcox if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_PROJECT, 101013d8aaa1SSean Wilcox SCF_TYPE_ASTRING, ctx, "project", NULL) != 0) 10117c478bd9Sstevel@tonic-gate return (-1); 10127c478bd9Sstevel@tonic-gate 101313d8aaa1SSean Wilcox if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_RESOURCE_POOL, 101413d8aaa1SSean Wilcox SCF_TYPE_ASTRING, ctx, "resource_pool", NULL) != 0) 10157c478bd9Sstevel@tonic-gate return (-1); 10167c478bd9Sstevel@tonic-gate 10177c478bd9Sstevel@tonic-gate for (cursor = ctx->xmlChildrenNode; cursor != NULL; 10187c478bd9Sstevel@tonic-gate cursor = cursor->next) { 10197c478bd9Sstevel@tonic-gate if (lxml_ignorable_block(cursor)) 10207c478bd9Sstevel@tonic-gate continue; 10217c478bd9Sstevel@tonic-gate 10227c478bd9Sstevel@tonic-gate switch (lxml_xlate_element(cursor->name)) { 10237c478bd9Sstevel@tonic-gate case SC_METHOD_CREDENTIAL: 10247c478bd9Sstevel@tonic-gate (void) lxml_get_method_credential(pg, cursor); 10257c478bd9Sstevel@tonic-gate break; 10267c478bd9Sstevel@tonic-gate case SC_METHOD_PROFILE: 10277c478bd9Sstevel@tonic-gate (void) lxml_get_method_profile(pg, cursor); 10287c478bd9Sstevel@tonic-gate break; 10297c478bd9Sstevel@tonic-gate case SC_METHOD_ENVIRONMENT: 10307c478bd9Sstevel@tonic-gate (void) lxml_get_method_environment(pg, cursor); 10317c478bd9Sstevel@tonic-gate break; 10327c478bd9Sstevel@tonic-gate default: 10337c478bd9Sstevel@tonic-gate semerr(gettext("illegal element \'%s\' in method " 10347c478bd9Sstevel@tonic-gate "context\n"), (char *)cursor); 10357c478bd9Sstevel@tonic-gate break; 10367c478bd9Sstevel@tonic-gate } 10377c478bd9Sstevel@tonic-gate } 10387c478bd9Sstevel@tonic-gate 10397c478bd9Sstevel@tonic-gate return (0); 10407c478bd9Sstevel@tonic-gate } 10417c478bd9Sstevel@tonic-gate 10427c478bd9Sstevel@tonic-gate static int 10437c478bd9Sstevel@tonic-gate lxml_get_entity_method_context(entity_t *entity, xmlNodePtr ctx) 10447c478bd9Sstevel@tonic-gate { 10457c478bd9Sstevel@tonic-gate pgroup_t *pg; 10467c478bd9Sstevel@tonic-gate 10477c478bd9Sstevel@tonic-gate pg = internal_pgroup_find_or_create(entity, SCF_PG_METHOD_CONTEXT, 10487c478bd9Sstevel@tonic-gate (char *)scf_group_framework); 10497c478bd9Sstevel@tonic-gate 10507c478bd9Sstevel@tonic-gate return (lxml_get_method_context(pg, ctx)); 10517c478bd9Sstevel@tonic-gate } 10527c478bd9Sstevel@tonic-gate 10537c478bd9Sstevel@tonic-gate static int 10547c478bd9Sstevel@tonic-gate lxml_get_exec_method(entity_t *entity, xmlNodePtr emeth) 10557c478bd9Sstevel@tonic-gate { 10567c478bd9Sstevel@tonic-gate pgroup_t *pg; 10577c478bd9Sstevel@tonic-gate property_t *p; 10587c478bd9Sstevel@tonic-gate xmlChar *name, *timeout, *delete; 10597c478bd9Sstevel@tonic-gate xmlNodePtr cursor; 10607c478bd9Sstevel@tonic-gate int r = 0; 10617c478bd9Sstevel@tonic-gate 1062f329b923SSean Wilcox if (entity->sc_op == SVCCFG_OP_APPLY) 1063f329b923SSean Wilcox lxml_validate_element(emeth); 1064f329b923SSean Wilcox 10657c478bd9Sstevel@tonic-gate name = xmlGetProp(emeth, (xmlChar *)name_attr); 10667c478bd9Sstevel@tonic-gate pg = internal_pgroup_find_or_create(entity, (char *)name, 10677c478bd9Sstevel@tonic-gate (char *)SCF_GROUP_METHOD); 10687c478bd9Sstevel@tonic-gate xmlFree(name); 10697c478bd9Sstevel@tonic-gate 10707c478bd9Sstevel@tonic-gate if (new_str_prop_from_attr(pg, SCF_PROPERTY_TYPE, SCF_TYPE_ASTRING, 10717c478bd9Sstevel@tonic-gate emeth, type_attr) != 0 || 10727c478bd9Sstevel@tonic-gate new_str_prop_from_attr(pg, SCF_PROPERTY_EXEC, SCF_TYPE_ASTRING, 10737c478bd9Sstevel@tonic-gate emeth, "exec") != 0) 10747c478bd9Sstevel@tonic-gate return (-1); 10757c478bd9Sstevel@tonic-gate 10761f6eb021SLiane Praza timeout = xmlGetProp(emeth, (xmlChar *)timeout_seconds_attr); 10777c478bd9Sstevel@tonic-gate if (timeout != NULL) { 10787c478bd9Sstevel@tonic-gate uint64_t u_timeout; 10797c478bd9Sstevel@tonic-gate char *endptr; 10807c478bd9Sstevel@tonic-gate /* 10817c478bd9Sstevel@tonic-gate * Although an SC_COUNT represents a uint64_t the use 10827c478bd9Sstevel@tonic-gate * of a negative value is acceptable due to the usage 10837c478bd9Sstevel@tonic-gate * established by inetd(1M). 10847c478bd9Sstevel@tonic-gate */ 10857c478bd9Sstevel@tonic-gate errno = 0; 10867c478bd9Sstevel@tonic-gate u_timeout = strtoull((char *)timeout, &endptr, 10); 10877c478bd9Sstevel@tonic-gate if (errno != 0 || endptr == (char *)timeout || *endptr) 10887c478bd9Sstevel@tonic-gate uu_die(gettext("illegal value \"%s\" for " 10897c478bd9Sstevel@tonic-gate "timeout_seconds (%s)\n"), 10907c478bd9Sstevel@tonic-gate (char *)timeout, (errno) ? strerror(errno): 10917c478bd9Sstevel@tonic-gate gettext("Illegal character")); 10927c478bd9Sstevel@tonic-gate p = internal_property_create(SCF_PROPERTY_TIMEOUT, 10937c478bd9Sstevel@tonic-gate SCF_TYPE_COUNT, 1, u_timeout); 10947c478bd9Sstevel@tonic-gate r = internal_attach_property(pg, p); 10957c478bd9Sstevel@tonic-gate xmlFree(timeout); 10967c478bd9Sstevel@tonic-gate } 10977c478bd9Sstevel@tonic-gate if (r != 0) 10987c478bd9Sstevel@tonic-gate return (-1); 10997c478bd9Sstevel@tonic-gate 11007c478bd9Sstevel@tonic-gate /* 11017c478bd9Sstevel@tonic-gate * There is a possibility that a method context also exists, in which 11027c478bd9Sstevel@tonic-gate * case the following attributes are defined: project, resource_pool, 11037c478bd9Sstevel@tonic-gate * working_directory, profile, user, group, privileges, limit_privileges 11047c478bd9Sstevel@tonic-gate */ 11057c478bd9Sstevel@tonic-gate for (cursor = emeth->xmlChildrenNode; cursor != NULL; 11067c478bd9Sstevel@tonic-gate cursor = cursor->next) { 11077c478bd9Sstevel@tonic-gate if (lxml_ignorable_block(cursor)) 11087c478bd9Sstevel@tonic-gate continue; 11097c478bd9Sstevel@tonic-gate 11107c478bd9Sstevel@tonic-gate switch (lxml_xlate_element(cursor->name)) { 11117c478bd9Sstevel@tonic-gate case SC_STABILITY: 11127c478bd9Sstevel@tonic-gate if (lxml_get_pgroup_stability(pg, cursor) != 0) 11137c478bd9Sstevel@tonic-gate return (-1); 11147c478bd9Sstevel@tonic-gate break; 11157c478bd9Sstevel@tonic-gate 11167c478bd9Sstevel@tonic-gate case SC_METHOD_CONTEXT: 11177c478bd9Sstevel@tonic-gate (void) lxml_get_method_context(pg, cursor); 11187c478bd9Sstevel@tonic-gate break; 11197c478bd9Sstevel@tonic-gate 11207c478bd9Sstevel@tonic-gate case SC_PROPVAL: 11217c478bd9Sstevel@tonic-gate (void) lxml_get_propval(pg, cursor); 11227c478bd9Sstevel@tonic-gate break; 11237c478bd9Sstevel@tonic-gate 11247c478bd9Sstevel@tonic-gate case SC_PROPERTY: 11257c478bd9Sstevel@tonic-gate (void) lxml_get_property(pg, cursor); 11267c478bd9Sstevel@tonic-gate break; 11277c478bd9Sstevel@tonic-gate 11287c478bd9Sstevel@tonic-gate default: 11297c478bd9Sstevel@tonic-gate uu_die(gettext("illegal element \"%s\" on " 11307c478bd9Sstevel@tonic-gate "execution method \"%s\"\n"), cursor->name, 11317c478bd9Sstevel@tonic-gate pg->sc_pgroup_name); 11327c478bd9Sstevel@tonic-gate break; 11337c478bd9Sstevel@tonic-gate } 11347c478bd9Sstevel@tonic-gate } 11357c478bd9Sstevel@tonic-gate 11367c478bd9Sstevel@tonic-gate delete = xmlGetProp(emeth, (xmlChar *)delete_attr); 11377c478bd9Sstevel@tonic-gate pg->sc_pgroup_delete = (xmlStrcmp(delete, (xmlChar *)true) == 0); 11387c478bd9Sstevel@tonic-gate xmlFree(delete); 11397c478bd9Sstevel@tonic-gate 11407c478bd9Sstevel@tonic-gate return (0); 11417c478bd9Sstevel@tonic-gate } 11427c478bd9Sstevel@tonic-gate 11437c478bd9Sstevel@tonic-gate static int 11447c478bd9Sstevel@tonic-gate lxml_get_dependency(entity_t *entity, xmlNodePtr dependency) 11457c478bd9Sstevel@tonic-gate { 11467c478bd9Sstevel@tonic-gate pgroup_t *pg; 11477c478bd9Sstevel@tonic-gate property_t *p; 11487c478bd9Sstevel@tonic-gate xmlNodePtr cursor; 11497c478bd9Sstevel@tonic-gate xmlChar *name; 11507c478bd9Sstevel@tonic-gate xmlChar *delete; 11517c478bd9Sstevel@tonic-gate 11527c478bd9Sstevel@tonic-gate /* 11537c478bd9Sstevel@tonic-gate * dependency attributes: 11547c478bd9Sstevel@tonic-gate * name: string 11557c478bd9Sstevel@tonic-gate * grouping: require_all | require_any | exclude_all | optional_all 11567c478bd9Sstevel@tonic-gate * reset_on: string (error | restart | refresh | none) 11577c478bd9Sstevel@tonic-gate * type: service / path /host 11587c478bd9Sstevel@tonic-gate */ 11597c478bd9Sstevel@tonic-gate 1160f329b923SSean Wilcox if (entity->sc_op == SVCCFG_OP_APPLY) 1161f329b923SSean Wilcox lxml_validate_element(dependency); 1162f329b923SSean Wilcox 11637c478bd9Sstevel@tonic-gate name = xmlGetProp(dependency, (xmlChar *)name_attr); 11647c478bd9Sstevel@tonic-gate pg = internal_pgroup_find_or_create(entity, (char *)name, 11657c478bd9Sstevel@tonic-gate (char *)SCF_GROUP_DEPENDENCY); 11667c478bd9Sstevel@tonic-gate xmlFree(name); 11677c478bd9Sstevel@tonic-gate 11687c478bd9Sstevel@tonic-gate if (new_str_prop_from_attr(pg, SCF_PROPERTY_TYPE, SCF_TYPE_ASTRING, 11697c478bd9Sstevel@tonic-gate dependency, type_attr) != 0) 11707c478bd9Sstevel@tonic-gate return (-1); 11717c478bd9Sstevel@tonic-gate 11727c478bd9Sstevel@tonic-gate if (new_str_prop_from_attr(pg, SCF_PROPERTY_RESTART_ON, 11737c478bd9Sstevel@tonic-gate SCF_TYPE_ASTRING, dependency, "restart_on") != 0) 11747c478bd9Sstevel@tonic-gate return (-1); 11757c478bd9Sstevel@tonic-gate 11767c478bd9Sstevel@tonic-gate if (new_str_prop_from_attr(pg, SCF_PROPERTY_GROUPING, SCF_TYPE_ASTRING, 11777c478bd9Sstevel@tonic-gate dependency, "grouping") != 0) 11787c478bd9Sstevel@tonic-gate return (-1); 11797c478bd9Sstevel@tonic-gate 11807c478bd9Sstevel@tonic-gate p = internal_property_create(SCF_PROPERTY_ENTITIES, SCF_TYPE_FMRI, 0); 11817c478bd9Sstevel@tonic-gate if (internal_attach_property(pg, p) != 0) 11827c478bd9Sstevel@tonic-gate return (-1); 11837c478bd9Sstevel@tonic-gate 11847c478bd9Sstevel@tonic-gate for (cursor = dependency->xmlChildrenNode; cursor != NULL; 11857c478bd9Sstevel@tonic-gate cursor = cursor->next) { 11867c478bd9Sstevel@tonic-gate xmlChar *value; 11877c478bd9Sstevel@tonic-gate value_t *v; 11887c478bd9Sstevel@tonic-gate 11897c478bd9Sstevel@tonic-gate if (lxml_ignorable_block(cursor)) 11907c478bd9Sstevel@tonic-gate continue; 11917c478bd9Sstevel@tonic-gate 11927c478bd9Sstevel@tonic-gate switch (lxml_xlate_element(cursor->name)) { 11937c478bd9Sstevel@tonic-gate case SC_STABILITY: 11947c478bd9Sstevel@tonic-gate if (lxml_get_pgroup_stability(pg, cursor) != 0) 11957c478bd9Sstevel@tonic-gate return (-1); 11967c478bd9Sstevel@tonic-gate break; 11977c478bd9Sstevel@tonic-gate 11987c478bd9Sstevel@tonic-gate case SC_SERVICE_FMRI: 11997c478bd9Sstevel@tonic-gate value = xmlGetProp(cursor, (xmlChar *)value_attr); 12007c478bd9Sstevel@tonic-gate if (value != NULL) { 12017c478bd9Sstevel@tonic-gate if (lxml_validate_string_value(SCF_TYPE_FMRI, 12027c478bd9Sstevel@tonic-gate (char *)value) != 0) 12037c478bd9Sstevel@tonic-gate uu_die(gettext("illegal value \"%s\" " 12047c478bd9Sstevel@tonic-gate "for %s (%s)\n"), (char *)value, 12057c478bd9Sstevel@tonic-gate lxml_prop_types[SC_FMRI], 12067c478bd9Sstevel@tonic-gate (scf_error()) ? 12077c478bd9Sstevel@tonic-gate scf_strerror(scf_error()) : 12087c478bd9Sstevel@tonic-gate gettext("Illegal format")); 12097c478bd9Sstevel@tonic-gate v = internal_value_new(); 12107c478bd9Sstevel@tonic-gate v->sc_type = SCF_TYPE_FMRI; 12117c478bd9Sstevel@tonic-gate v->sc_u.sc_string = (char *)value; 12127c478bd9Sstevel@tonic-gate internal_attach_value(p, v); 12137c478bd9Sstevel@tonic-gate } 12147c478bd9Sstevel@tonic-gate 12157c478bd9Sstevel@tonic-gate break; 12167c478bd9Sstevel@tonic-gate 12177c478bd9Sstevel@tonic-gate case SC_PROPVAL: 12187c478bd9Sstevel@tonic-gate (void) lxml_get_propval(pg, cursor); 12197c478bd9Sstevel@tonic-gate break; 12207c478bd9Sstevel@tonic-gate 12217c478bd9Sstevel@tonic-gate case SC_PROPERTY: 12227c478bd9Sstevel@tonic-gate (void) lxml_get_property(pg, cursor); 12237c478bd9Sstevel@tonic-gate break; 12247c478bd9Sstevel@tonic-gate 12257c478bd9Sstevel@tonic-gate default: 12267c478bd9Sstevel@tonic-gate uu_die(gettext("illegal element \"%s\" on " 12277c478bd9Sstevel@tonic-gate "dependency group \"%s\"\n"), cursor->name, name); 12287c478bd9Sstevel@tonic-gate break; 12297c478bd9Sstevel@tonic-gate } 12307c478bd9Sstevel@tonic-gate } 12317c478bd9Sstevel@tonic-gate 12327c478bd9Sstevel@tonic-gate delete = xmlGetProp(dependency, (xmlChar *)delete_attr); 12337c478bd9Sstevel@tonic-gate pg->sc_pgroup_delete = (xmlStrcmp(delete, (xmlChar *)true) == 0); 12347c478bd9Sstevel@tonic-gate xmlFree(delete); 12357c478bd9Sstevel@tonic-gate 12367c478bd9Sstevel@tonic-gate return (0); 12377c478bd9Sstevel@tonic-gate } 12387c478bd9Sstevel@tonic-gate 12397c478bd9Sstevel@tonic-gate /* 12407c478bd9Sstevel@tonic-gate * Dependents are hairy. They should cause a dependency pg to be created in 12417c478bd9Sstevel@tonic-gate * another service, but we can't do that here; we'll have to wait until the 12427c478bd9Sstevel@tonic-gate * import routines. So for now we'll add the dependency group that should go 12437c478bd9Sstevel@tonic-gate * in the other service to the entity's dependent list. 12447c478bd9Sstevel@tonic-gate */ 12457c478bd9Sstevel@tonic-gate static int 12467c478bd9Sstevel@tonic-gate lxml_get_dependent(entity_t *entity, xmlNodePtr dependent) 12477c478bd9Sstevel@tonic-gate { 12487c478bd9Sstevel@tonic-gate xmlChar *name, *or; 12497c478bd9Sstevel@tonic-gate xmlNodePtr sf; 12507c478bd9Sstevel@tonic-gate xmlChar *fmri, *delete; 12517c478bd9Sstevel@tonic-gate pgroup_t *pg; 12527c478bd9Sstevel@tonic-gate property_t *p; 12537c478bd9Sstevel@tonic-gate xmlNodePtr n; 12547c478bd9Sstevel@tonic-gate char *myfmri; 12557c478bd9Sstevel@tonic-gate 1256f329b923SSean Wilcox if (entity->sc_op == SVCCFG_OP_APPLY) 1257f329b923SSean Wilcox lxml_validate_element(dependent); 1258f329b923SSean Wilcox 12597c478bd9Sstevel@tonic-gate name = xmlGetProp(dependent, (xmlChar *)name_attr); 12607c478bd9Sstevel@tonic-gate 12617c478bd9Sstevel@tonic-gate if (internal_pgroup_find(entity, (char *)name, NULL) != NULL) { 12627c478bd9Sstevel@tonic-gate semerr(gettext("Property group and dependent of entity %s " 12637c478bd9Sstevel@tonic-gate "have same name \"%s\".\n"), entity->sc_name, name); 12647c478bd9Sstevel@tonic-gate xmlFree(name); 12657c478bd9Sstevel@tonic-gate return (-1); 12667c478bd9Sstevel@tonic-gate } 12677c478bd9Sstevel@tonic-gate 12687c478bd9Sstevel@tonic-gate or = xmlGetProp(dependent, (xmlChar *)override_attr); 12697c478bd9Sstevel@tonic-gate 12707c478bd9Sstevel@tonic-gate pg = internal_pgroup_new(); 12717c478bd9Sstevel@tonic-gate pg->sc_pgroup_name = (char *)name; 12727c478bd9Sstevel@tonic-gate pg->sc_pgroup_type = (char *)SCF_GROUP_DEPENDENCY; 12737c478bd9Sstevel@tonic-gate pg->sc_pgroup_override = (xmlStrcmp(or, (xmlChar *)true) == 0); 12747c478bd9Sstevel@tonic-gate xmlFree(or); 12757c478bd9Sstevel@tonic-gate if (internal_attach_dependent(entity, pg) != 0) { 12767c478bd9Sstevel@tonic-gate xmlFree(name); 12777c478bd9Sstevel@tonic-gate internal_pgroup_free(pg); 12787c478bd9Sstevel@tonic-gate return (-1); 12797c478bd9Sstevel@tonic-gate } 12807c478bd9Sstevel@tonic-gate 12817c478bd9Sstevel@tonic-gate for (sf = dependent->children; sf != NULL; sf = sf->next) 12827c478bd9Sstevel@tonic-gate if (xmlStrcmp(sf->name, (xmlChar *)"service_fmri") == 0) 12837c478bd9Sstevel@tonic-gate break; 12847c478bd9Sstevel@tonic-gate assert(sf != NULL); 12857c478bd9Sstevel@tonic-gate fmri = xmlGetProp(sf, (xmlChar *)value_attr); 12867c478bd9Sstevel@tonic-gate pg->sc_pgroup_fmri = (char *)fmri; 12877c478bd9Sstevel@tonic-gate 12887c478bd9Sstevel@tonic-gate if (new_str_prop_from_attr(pg, SCF_PROPERTY_RESTART_ON, 12897c478bd9Sstevel@tonic-gate SCF_TYPE_ASTRING, dependent, "restart_on") != 0) 12907c478bd9Sstevel@tonic-gate return (-1); 12917c478bd9Sstevel@tonic-gate 12927c478bd9Sstevel@tonic-gate if (new_str_prop_from_attr(pg, SCF_PROPERTY_GROUPING, SCF_TYPE_ASTRING, 12937c478bd9Sstevel@tonic-gate dependent, "grouping") != 0) 12947c478bd9Sstevel@tonic-gate return (-1); 12957c478bd9Sstevel@tonic-gate 12967c478bd9Sstevel@tonic-gate myfmri = safe_malloc(max_scf_fmri_len + 1); 12977c478bd9Sstevel@tonic-gate if (entity->sc_etype == SVCCFG_SERVICE_OBJECT) { 12987c478bd9Sstevel@tonic-gate if (snprintf(myfmri, max_scf_fmri_len + 1, "svc:/%s", 12997c478bd9Sstevel@tonic-gate entity->sc_name) < 0) 13007c478bd9Sstevel@tonic-gate bad_error("snprintf", errno); 13017c478bd9Sstevel@tonic-gate } else { 13027c478bd9Sstevel@tonic-gate assert(entity->sc_etype == SVCCFG_INSTANCE_OBJECT); 13037c478bd9Sstevel@tonic-gate if (snprintf(myfmri, max_scf_fmri_len + 1, "svc:/%s:%s", 13047c478bd9Sstevel@tonic-gate entity->sc_parent->sc_name, entity->sc_name) < 0) 13057c478bd9Sstevel@tonic-gate bad_error("snprintf", errno); 13067c478bd9Sstevel@tonic-gate } 13077c478bd9Sstevel@tonic-gate 13087c478bd9Sstevel@tonic-gate p = internal_property_create(SCF_PROPERTY_ENTITIES, SCF_TYPE_FMRI, 1, 13097c478bd9Sstevel@tonic-gate myfmri); 13107c478bd9Sstevel@tonic-gate if (internal_attach_property(pg, p) != 0) 13117c478bd9Sstevel@tonic-gate return (-1); 13127c478bd9Sstevel@tonic-gate 13137c478bd9Sstevel@tonic-gate /* Create a property to serve as a do-not-export flag. */ 13147c478bd9Sstevel@tonic-gate p = internal_property_create("external", SCF_TYPE_BOOLEAN, 1, 13157c478bd9Sstevel@tonic-gate (uint64_t)1); 13167c478bd9Sstevel@tonic-gate if (internal_attach_property(pg, p) != 0) 13177c478bd9Sstevel@tonic-gate return (-1); 13187c478bd9Sstevel@tonic-gate 13197c478bd9Sstevel@tonic-gate for (n = sf->next; n != NULL; n = n->next) { 13207c478bd9Sstevel@tonic-gate if (lxml_ignorable_block(n)) 13217c478bd9Sstevel@tonic-gate continue; 13227c478bd9Sstevel@tonic-gate 13237c478bd9Sstevel@tonic-gate switch (lxml_xlate_element(n->name)) { 13247c478bd9Sstevel@tonic-gate case SC_STABILITY: 13257c478bd9Sstevel@tonic-gate if (new_str_prop_from_attr(pg, 13267c478bd9Sstevel@tonic-gate SCF_PROPERTY_ENTITY_STABILITY, SCF_TYPE_ASTRING, n, 13277c478bd9Sstevel@tonic-gate value_attr) != 0) 13287c478bd9Sstevel@tonic-gate return (-1); 13297c478bd9Sstevel@tonic-gate break; 13307c478bd9Sstevel@tonic-gate 13317c478bd9Sstevel@tonic-gate case SC_PROPVAL: 13327c478bd9Sstevel@tonic-gate (void) lxml_get_propval(pg, n); 13337c478bd9Sstevel@tonic-gate break; 13347c478bd9Sstevel@tonic-gate 13357c478bd9Sstevel@tonic-gate case SC_PROPERTY: 13367c478bd9Sstevel@tonic-gate (void) lxml_get_property(pg, n); 13377c478bd9Sstevel@tonic-gate break; 13387c478bd9Sstevel@tonic-gate 13397c478bd9Sstevel@tonic-gate default: 13407c478bd9Sstevel@tonic-gate uu_die(gettext("unexpected element %s.\n"), n->name); 13417c478bd9Sstevel@tonic-gate } 13427c478bd9Sstevel@tonic-gate } 13437c478bd9Sstevel@tonic-gate 13447c478bd9Sstevel@tonic-gate /* Go back and fill in defaults. */ 13457c478bd9Sstevel@tonic-gate if (internal_property_find(pg, SCF_PROPERTY_TYPE) == NULL) { 13467c478bd9Sstevel@tonic-gate p = internal_property_create(SCF_PROPERTY_TYPE, 13477c478bd9Sstevel@tonic-gate SCF_TYPE_ASTRING, 1, "service"); 13487c478bd9Sstevel@tonic-gate if (internal_attach_property(pg, p) != 0) 13497c478bd9Sstevel@tonic-gate return (-1); 13507c478bd9Sstevel@tonic-gate } 13517c478bd9Sstevel@tonic-gate 13527c478bd9Sstevel@tonic-gate delete = xmlGetProp(dependent, (xmlChar *)delete_attr); 13537c478bd9Sstevel@tonic-gate pg->sc_pgroup_delete = (xmlStrcmp(delete, (xmlChar *)true) == 0); 13547c478bd9Sstevel@tonic-gate xmlFree(delete); 13557c478bd9Sstevel@tonic-gate 13567c478bd9Sstevel@tonic-gate pg = internal_pgroup_find_or_create(entity, "dependents", 13577c478bd9Sstevel@tonic-gate (char *)scf_group_framework); 13589e9ae1fcSbustos p = internal_property_create((char *)name, SCF_TYPE_FMRI, 1, fmri); 13597c478bd9Sstevel@tonic-gate if (internal_attach_property(pg, p) != 0) 13607c478bd9Sstevel@tonic-gate return (-1); 13617c478bd9Sstevel@tonic-gate 13627c478bd9Sstevel@tonic-gate return (0); 13637c478bd9Sstevel@tonic-gate } 13647c478bd9Sstevel@tonic-gate 13657c478bd9Sstevel@tonic-gate static int 13667c478bd9Sstevel@tonic-gate lxml_get_entity_stability(entity_t *entity, xmlNodePtr rstr) 13677c478bd9Sstevel@tonic-gate { 13687c478bd9Sstevel@tonic-gate pgroup_t *pg; 13697c478bd9Sstevel@tonic-gate property_t *p; 13707c478bd9Sstevel@tonic-gate xmlChar *stabval; 13717c478bd9Sstevel@tonic-gate 13721f6eb021SLiane Praza if (((stabval = xmlGetProp(rstr, (xmlChar *)value_attr)) == NULL) || 13731f6eb021SLiane Praza (*stabval == 0)) { 13747c478bd9Sstevel@tonic-gate uu_warn(gettext("no stability value found\n")); 1375*67b0e063SAlbert Lee stabval = (xmlChar *)safe_strdup("External"); 13767c478bd9Sstevel@tonic-gate } 13777c478bd9Sstevel@tonic-gate 13787c478bd9Sstevel@tonic-gate pg = internal_pgroup_find_or_create(entity, (char *)scf_pg_general, 13797c478bd9Sstevel@tonic-gate (char *)scf_group_framework); 13807c478bd9Sstevel@tonic-gate 13817c478bd9Sstevel@tonic-gate p = internal_property_create(SCF_PROPERTY_ENTITY_STABILITY, 13827c478bd9Sstevel@tonic-gate SCF_TYPE_ASTRING, 1, stabval); 13837c478bd9Sstevel@tonic-gate 13847c478bd9Sstevel@tonic-gate return (internal_attach_property(pg, p)); 13857c478bd9Sstevel@tonic-gate } 13867c478bd9Sstevel@tonic-gate 13877c478bd9Sstevel@tonic-gate static int 13887c478bd9Sstevel@tonic-gate lxml_get_restarter(entity_t *entity, xmlNodePtr rstr) 13897c478bd9Sstevel@tonic-gate { 13907c478bd9Sstevel@tonic-gate pgroup_t *pg; 13917c478bd9Sstevel@tonic-gate property_t *p; 13927c478bd9Sstevel@tonic-gate xmlChar *restarter; 13937c478bd9Sstevel@tonic-gate xmlNode *cursor; 13947c478bd9Sstevel@tonic-gate int r; 13957c478bd9Sstevel@tonic-gate 13967c478bd9Sstevel@tonic-gate /* 13977c478bd9Sstevel@tonic-gate * Go find child. Child is a service_fmri element. value attribute 13987c478bd9Sstevel@tonic-gate * contains restarter FMRI. 13997c478bd9Sstevel@tonic-gate */ 14007c478bd9Sstevel@tonic-gate 14017c478bd9Sstevel@tonic-gate pg = internal_pgroup_find_or_create(entity, (char *)scf_pg_general, 14027c478bd9Sstevel@tonic-gate (char *)scf_group_framework); 14037c478bd9Sstevel@tonic-gate 14047c478bd9Sstevel@tonic-gate /* 14057c478bd9Sstevel@tonic-gate * Walk its child elements, as appropriate. 14067c478bd9Sstevel@tonic-gate */ 14077c478bd9Sstevel@tonic-gate for (cursor = rstr->xmlChildrenNode; cursor != NULL; 14087c478bd9Sstevel@tonic-gate cursor = cursor->next) { 14097c478bd9Sstevel@tonic-gate if (lxml_ignorable_block(cursor)) 14107c478bd9Sstevel@tonic-gate continue; 14117c478bd9Sstevel@tonic-gate 14127c478bd9Sstevel@tonic-gate switch (lxml_xlate_element(cursor->name)) { 14137c478bd9Sstevel@tonic-gate case SC_SERVICE_FMRI: 14147c478bd9Sstevel@tonic-gate restarter = xmlGetProp(cursor, (xmlChar *)value_attr); 14157c478bd9Sstevel@tonic-gate break; 14167c478bd9Sstevel@tonic-gate default: 14177c478bd9Sstevel@tonic-gate uu_die(gettext("illegal element \"%s\" on restarter " 14187c478bd9Sstevel@tonic-gate "element for \"%s\"\n"), cursor->name, 14197c478bd9Sstevel@tonic-gate entity->sc_name); 14207c478bd9Sstevel@tonic-gate break; 14217c478bd9Sstevel@tonic-gate } 14227c478bd9Sstevel@tonic-gate } 14237c478bd9Sstevel@tonic-gate 14247c478bd9Sstevel@tonic-gate p = internal_property_create(SCF_PROPERTY_RESTARTER, SCF_TYPE_FMRI, 1, 14257c478bd9Sstevel@tonic-gate restarter); 14267c478bd9Sstevel@tonic-gate 14277c478bd9Sstevel@tonic-gate r = internal_attach_property(pg, p); 14287c478bd9Sstevel@tonic-gate if (r != 0) { 14297c478bd9Sstevel@tonic-gate internal_property_free(p); 14307c478bd9Sstevel@tonic-gate return (-1); 14317c478bd9Sstevel@tonic-gate } 14327c478bd9Sstevel@tonic-gate 14337c478bd9Sstevel@tonic-gate return (0); 14347c478bd9Sstevel@tonic-gate } 14357c478bd9Sstevel@tonic-gate 1436f6e214c7SGavin Maltby static void 1437f6e214c7SGavin Maltby lxml_get_paramval(pgroup_t *pgrp, const char *propname, xmlNodePtr pval) 1438f6e214c7SGavin Maltby { 1439f6e214c7SGavin Maltby property_t *p; 1440f6e214c7SGavin Maltby char *value; 1441f6e214c7SGavin Maltby char *prop; 1442f6e214c7SGavin Maltby 1443*67b0e063SAlbert Lee prop = safe_strdup(propname); 1444f6e214c7SGavin Maltby 1445f6e214c7SGavin Maltby value = (char *)xmlGetProp(pval, (xmlChar *)value_attr); 1446f6e214c7SGavin Maltby if (value == NULL || *value == '\0') 1447f6e214c7SGavin Maltby uu_die(gettext("property value missing for property '%s/%s'\n"), 1448f6e214c7SGavin Maltby pgrp->sc_pgroup_name, propname); 1449f6e214c7SGavin Maltby p = internal_property_create(prop, SCF_TYPE_ASTRING, 1, value); 1450f6e214c7SGavin Maltby 1451f6e214c7SGavin Maltby (void) internal_attach_property(pgrp, p); 1452f6e214c7SGavin Maltby } 1453f6e214c7SGavin Maltby 1454f6e214c7SGavin Maltby static void 1455f6e214c7SGavin Maltby lxml_get_parameter(pgroup_t *pgrp, const char *propname, xmlNodePtr param) 1456f6e214c7SGavin Maltby { 1457f6e214c7SGavin Maltby property_t *p = internal_property_new(); 1458f6e214c7SGavin Maltby 1459*67b0e063SAlbert Lee p->sc_property_name = safe_strdup(propname); 1460f6e214c7SGavin Maltby p->sc_value_type = SCF_TYPE_ASTRING; 1461f6e214c7SGavin Maltby 1462f6e214c7SGavin Maltby (void) lxml_get_value(p, SC_ASTRING, param); 1463f6e214c7SGavin Maltby 1464f6e214c7SGavin Maltby (void) internal_attach_property(pgrp, p); 1465f6e214c7SGavin Maltby } 1466f6e214c7SGavin Maltby 1467f6e214c7SGavin Maltby static void 1468f6e214c7SGavin Maltby lxml_get_type(pgroup_t *pgrp, xmlNodePtr type) 1469f6e214c7SGavin Maltby { 1470f6e214c7SGavin Maltby property_t *p; 1471f6e214c7SGavin Maltby xmlChar *name; 1472f6e214c7SGavin Maltby xmlChar *active; 1473f6e214c7SGavin Maltby xmlNodePtr cursor; 1474f6e214c7SGavin Maltby uint64_t active_val; 1475f6e214c7SGavin Maltby size_t sz = max_scf_name_len + 1; 1476f6e214c7SGavin Maltby char *propname = safe_malloc(sz); 1477f6e214c7SGavin Maltby 1478f6e214c7SGavin Maltby if (pgrp->sc_parent->sc_op == SVCCFG_OP_APPLY) 1479f6e214c7SGavin Maltby lxml_validate_element(type); 1480f6e214c7SGavin Maltby 1481f6e214c7SGavin Maltby name = xmlGetProp(type, (xmlChar *)name_attr); 1482f6e214c7SGavin Maltby if (name == NULL || *name == '\0') 1483f6e214c7SGavin Maltby uu_die(gettext("attribute name missing in element 'type'\n")); 1484f6e214c7SGavin Maltby 1485f6e214c7SGavin Maltby for (cursor = type->xmlChildrenNode; cursor != NULL; 1486f6e214c7SGavin Maltby cursor = cursor->next) { 1487f6e214c7SGavin Maltby xmlChar *pname; 1488f6e214c7SGavin Maltby 1489f6e214c7SGavin Maltby if (lxml_ignorable_block(cursor)) 1490f6e214c7SGavin Maltby continue; 1491f6e214c7SGavin Maltby 1492f6e214c7SGavin Maltby pname = xmlGetProp(cursor, (xmlChar *)name_attr); 1493f6e214c7SGavin Maltby if (pname == NULL || *pname == '\0') 1494f6e214c7SGavin Maltby uu_die(gettext( 1495f6e214c7SGavin Maltby "attribute name missing in sub-element of type\n")); 1496f6e214c7SGavin Maltby 1497f6e214c7SGavin Maltby if (snprintf(propname, sz, "%s,%s", (char *)name, 1498f6e214c7SGavin Maltby (char *)pname) >= sz) 1499f6e214c7SGavin Maltby uu_die(gettext("name '%s,%s' is too long\n"), 1500f6e214c7SGavin Maltby (char *)name, (char *)pname); 1501f6e214c7SGavin Maltby xmlFree(pname); 1502f6e214c7SGavin Maltby 1503f6e214c7SGavin Maltby switch (lxml_xlate_element(cursor->name)) { 1504f6e214c7SGavin Maltby case SC_PARAMETER: 1505f6e214c7SGavin Maltby lxml_get_parameter(pgrp, propname, cursor); 1506f6e214c7SGavin Maltby break; 1507f6e214c7SGavin Maltby 1508f6e214c7SGavin Maltby case SC_PARAMVAL: 1509f6e214c7SGavin Maltby lxml_get_paramval(pgrp, propname, cursor); 1510f6e214c7SGavin Maltby break; 1511f6e214c7SGavin Maltby 1512f6e214c7SGavin Maltby default: 1513f6e214c7SGavin Maltby uu_die(gettext("unknown element %s\n"), cursor->name); 1514f6e214c7SGavin Maltby } 1515f6e214c7SGavin Maltby } 1516f6e214c7SGavin Maltby 1517f6e214c7SGavin Maltby active = xmlGetProp(type, (xmlChar *)active_attr); 1518f6e214c7SGavin Maltby if (active == NULL || strcmp(true, (const char *)active) == 0) 1519f6e214c7SGavin Maltby active_val = 1; 1520f6e214c7SGavin Maltby else 1521f6e214c7SGavin Maltby active_val = 0; 1522f6e214c7SGavin Maltby xmlFree(active); 1523f6e214c7SGavin Maltby 1524f6e214c7SGavin Maltby if (snprintf(propname, sz, "%s,%s", (char *)name, 1525f6e214c7SGavin Maltby SCF_PROPERTY_ACTIVE_POSTFIX) >= sz) 1526f6e214c7SGavin Maltby uu_die(gettext("name '%s,%s' is too long\n"), 1527f6e214c7SGavin Maltby (char *)name, SCF_PROPERTY_ACTIVE_POSTFIX); 1528f6e214c7SGavin Maltby 1529f6e214c7SGavin Maltby p = internal_property_create(propname, SCF_TYPE_BOOLEAN, 1, active_val); 1530f6e214c7SGavin Maltby 1531f6e214c7SGavin Maltby (void) internal_attach_property(pgrp, p); 1532f6e214c7SGavin Maltby 1533f6e214c7SGavin Maltby xmlFree(name); 1534f6e214c7SGavin Maltby } 1535f6e214c7SGavin Maltby 1536f6e214c7SGavin Maltby static void 1537f6e214c7SGavin Maltby lxml_get_event(entity_t *entity, const char *pgname, xmlNodePtr np) 1538f6e214c7SGavin Maltby { 1539f6e214c7SGavin Maltby xmlNodePtr cursor; 1540f6e214c7SGavin Maltby pgroup_t *pgrp; 1541f6e214c7SGavin Maltby 1542f6e214c7SGavin Maltby pgrp = internal_pgroup_find_or_create(entity, pgname, 1543f6e214c7SGavin Maltby SCF_NOTIFY_PARAMS_PG_TYPE); 1544f6e214c7SGavin Maltby for (cursor = np->xmlChildrenNode; cursor != NULL; 1545f6e214c7SGavin Maltby cursor = cursor->next) { 1546f6e214c7SGavin Maltby if (lxml_ignorable_block(cursor)) 1547f6e214c7SGavin Maltby continue; 1548f6e214c7SGavin Maltby 1549f6e214c7SGavin Maltby switch (lxml_xlate_element(cursor->name)) { 1550f6e214c7SGavin Maltby case SC_EVENT: 1551f6e214c7SGavin Maltby continue; 1552f6e214c7SGavin Maltby 1553f6e214c7SGavin Maltby case SC_TYPE: 1554f6e214c7SGavin Maltby lxml_get_type(pgrp, cursor); 1555f6e214c7SGavin Maltby break; 1556f6e214c7SGavin Maltby 1557f6e214c7SGavin Maltby default: 1558f6e214c7SGavin Maltby uu_warn(gettext("illegal element '%s' on " 1559f6e214c7SGavin Maltby "notification parameters\n"), cursor->name); 1560f6e214c7SGavin Maltby } 1561f6e214c7SGavin Maltby } 1562f6e214c7SGavin Maltby } 1563f6e214c7SGavin Maltby 1564f6e214c7SGavin Maltby static int 1565f6e214c7SGavin Maltby lxml_get_notification_parameters(entity_t *entity, xmlNodePtr np) 1566f6e214c7SGavin Maltby { 1567f6e214c7SGavin Maltby char *event = NULL; 1568f6e214c7SGavin Maltby char **pgs = NULL; 1569f6e214c7SGavin Maltby char **p; 1570f6e214c7SGavin Maltby char *pgname = NULL; 1571f6e214c7SGavin Maltby xmlNodePtr cursor; 1572f6e214c7SGavin Maltby int32_t tset, t; 1573f6e214c7SGavin Maltby size_t sz = max_scf_name_len + 1; 1574f6e214c7SGavin Maltby int count; 1575f6e214c7SGavin Maltby int r = -1; 1576f6e214c7SGavin Maltby 1577f6e214c7SGavin Maltby for (count = 0, cursor = np->xmlChildrenNode; cursor != NULL; 1578f6e214c7SGavin Maltby cursor = cursor->next) { 1579f6e214c7SGavin Maltby if (lxml_ignorable_block(cursor)) 1580f6e214c7SGavin Maltby continue; 1581f6e214c7SGavin Maltby 1582f6e214c7SGavin Maltby if (lxml_xlate_element(cursor->name) == SC_EVENT) { 1583f6e214c7SGavin Maltby xmlChar *s; 1584f6e214c7SGavin Maltby 1585f6e214c7SGavin Maltby count++; 1586f6e214c7SGavin Maltby if (count > 1) 1587f6e214c7SGavin Maltby uu_die(gettext("Can't have more than 1 element " 1588f6e214c7SGavin Maltby "event in a notification parameter\n")); 1589f6e214c7SGavin Maltby s = xmlGetProp(cursor, (xmlChar *)value_attr); 1590f6e214c7SGavin Maltby if (s == NULL || (event = strdup((char *)s)) == NULL) 1591f6e214c7SGavin Maltby uu_die(gettext("couldn't allocate memory")); 1592f6e214c7SGavin Maltby xmlFree(s); 1593f6e214c7SGavin Maltby } 1594f6e214c7SGavin Maltby } 1595f6e214c7SGavin Maltby 1596f6e214c7SGavin Maltby pgs = tokenize(event, ","); 1597f6e214c7SGavin Maltby 1598f6e214c7SGavin Maltby switch (tset = check_tokens(pgs)) { 1599f6e214c7SGavin Maltby case INVALID_TOKENS: 1600f6e214c7SGavin Maltby uu_die(gettext("Invalid input.\n")); 1601f6e214c7SGavin Maltby /*NOTREACHED*/ 1602f6e214c7SGavin Maltby case MIXED_TOKENS: 1603f6e214c7SGavin Maltby semerr(gettext("Can't mix SMF and FMA event definitions\n")); 1604f6e214c7SGavin Maltby goto out; 1605f6e214c7SGavin Maltby case FMA_TOKENS: 1606f6e214c7SGavin Maltby /* make sure this is SCF_NOTIFY_PARAMS_INST */ 1607f6e214c7SGavin Maltby if (entity->sc_etype != SVCCFG_INSTANCE_OBJECT || 1608f6e214c7SGavin Maltby strcmp(entity->sc_fmri, SCF_NOTIFY_PARAMS_INST) != 0) { 1609f6e214c7SGavin Maltby semerr(gettext( 1610f6e214c7SGavin Maltby "Non-SMF transition evenst must go to %s\n"), 1611f6e214c7SGavin Maltby SCF_NOTIFY_PARAMS_INST); 1612f6e214c7SGavin Maltby goto out; 1613f6e214c7SGavin Maltby } 1614f6e214c7SGavin Maltby pgname = safe_malloc(sz); 1615f6e214c7SGavin Maltby for (p = pgs; *p; ++p) { 1616f6e214c7SGavin Maltby if (snprintf(pgname, sz, "%s,%s", de_tag(*p), 1617f6e214c7SGavin Maltby SCF_NOTIFY_PG_POSTFIX) >= sz) 1618f6e214c7SGavin Maltby uu_die(gettext("event name too long: %s\n"), 1619f6e214c7SGavin Maltby *p); 1620f6e214c7SGavin Maltby 1621f6e214c7SGavin Maltby lxml_get_event(entity, pgname, np); 1622f6e214c7SGavin Maltby } 1623f6e214c7SGavin Maltby 1624f6e214c7SGavin Maltby default: /* smf state transition tokens */ 1625f6e214c7SGavin Maltby if (entity->sc_etype == SVCCFG_SERVICE_OBJECT && 1626f6e214c7SGavin Maltby strcmp(entity->sc_fmri, SCF_SERVICE_GLOBAL) == 0) { 1627f6e214c7SGavin Maltby semerr(gettext( 1628f6e214c7SGavin Maltby "Can't set events for global service\n")); 1629f6e214c7SGavin Maltby goto out; 1630f6e214c7SGavin Maltby } 1631f6e214c7SGavin Maltby for (t = 0x1; t < SCF_STATE_ALL; t <<= 1) { 1632f6e214c7SGavin Maltby if (t & tset) { 1633f6e214c7SGavin Maltby lxml_get_event(entity, tset_to_string(t), np); 1634f6e214c7SGavin Maltby } 1635f6e214c7SGavin Maltby if ((t << 16) & tset) { 1636f6e214c7SGavin Maltby lxml_get_event(entity, tset_to_string(t << 16), 1637f6e214c7SGavin Maltby np); 1638f6e214c7SGavin Maltby } 1639f6e214c7SGavin Maltby } 1640f6e214c7SGavin Maltby } 1641f6e214c7SGavin Maltby 1642f6e214c7SGavin Maltby r = 0; 1643f6e214c7SGavin Maltby out: 1644f6e214c7SGavin Maltby free(pgname); 1645f6e214c7SGavin Maltby free(pgs); 1646f6e214c7SGavin Maltby free(event); 1647f6e214c7SGavin Maltby 1648f6e214c7SGavin Maltby return (r); 1649f6e214c7SGavin Maltby } 1650f6e214c7SGavin Maltby 16511f6eb021SLiane Praza /* 16521f6eb021SLiane Praza * Add a property containing the localized text from the manifest. The 16531f6eb021SLiane Praza * property is added to the property group at pg. The name of the created 16541f6eb021SLiane Praza * property is based on the format at pn_format. This is an snprintf(3C) 16551f6eb021SLiane Praza * format containing a single %s conversion specification. At conversion 16561f6eb021SLiane Praza * time, the %s is replaced by the locale designation. 16571f6eb021SLiane Praza * 16581f6eb021SLiane Praza * source is the source element and it is only used for error messages. 16591f6eb021SLiane Praza */ 16607c478bd9Sstevel@tonic-gate static int 16611f6eb021SLiane Praza lxml_get_loctext(entity_t *service, pgroup_t *pg, xmlNodePtr loctext, 16621f6eb021SLiane Praza const char *pn_format, const char *source) 16637c478bd9Sstevel@tonic-gate { 16641f6eb021SLiane Praza int extra; 16657c478bd9Sstevel@tonic-gate xmlNodePtr cursor; 16667c478bd9Sstevel@tonic-gate xmlChar *val; 16677c478bd9Sstevel@tonic-gate char *stripped, *cp; 16687c478bd9Sstevel@tonic-gate property_t *p; 16691f6eb021SLiane Praza char *prop_name; 16707c478bd9Sstevel@tonic-gate int r; 16717c478bd9Sstevel@tonic-gate 16721f6eb021SLiane Praza if (((val = xmlGetProp(loctext, (xmlChar *)xml_lang_attr)) == NULL) || 16731f6eb021SLiane Praza (*val == 0)) { 16741f6eb021SLiane Praza if (((val = xmlGetProp(loctext, 16751f6eb021SLiane Praza (xmlChar *)lang_attr)) == NULL) || (*val == 0)) { 16767c478bd9Sstevel@tonic-gate val = (xmlChar *)"unknown"; 16771f6eb021SLiane Praza } 16781f6eb021SLiane Praza } 16797c478bd9Sstevel@tonic-gate 16801f6eb021SLiane Praza _scf_sanitize_locale((char *)val); 16811f6eb021SLiane Praza prop_name = safe_malloc(max_scf_name_len + 1); 16821f6eb021SLiane Praza if ((extra = snprintf(prop_name, max_scf_name_len + 1, pn_format, 16831f6eb021SLiane Praza val)) >= max_scf_name_len + 1) { 16841f6eb021SLiane Praza extra -= max_scf_name_len; 16851f6eb021SLiane Praza uu_die(gettext("%s attribute is %d characters too long for " 16861f6eb021SLiane Praza "%s in %s\n"), 16871f6eb021SLiane Praza xml_lang_attr, extra, source, service->sc_name); 16881f6eb021SLiane Praza } 16891f6eb021SLiane Praza xmlFree(val); 16907c478bd9Sstevel@tonic-gate 16917c478bd9Sstevel@tonic-gate for (cursor = loctext->xmlChildrenNode; cursor != NULL; 16927c478bd9Sstevel@tonic-gate cursor = cursor->next) { 16937c478bd9Sstevel@tonic-gate if (strcmp("text", (const char *)cursor->name) == 0) { 16947c478bd9Sstevel@tonic-gate break; 16957c478bd9Sstevel@tonic-gate } else if (strcmp("comment", (const char *)cursor->name) != 0) { 16967c478bd9Sstevel@tonic-gate uu_die(gettext("illegal element \"%s\" on loctext " 16977c478bd9Sstevel@tonic-gate "element for \"%s\"\n"), cursor->name, 16987c478bd9Sstevel@tonic-gate service->sc_name); 16997c478bd9Sstevel@tonic-gate } 17007c478bd9Sstevel@tonic-gate } 17017c478bd9Sstevel@tonic-gate 17027c478bd9Sstevel@tonic-gate if (cursor == NULL) { 17037c478bd9Sstevel@tonic-gate uu_die(gettext("loctext element has no content for \"%s\"\n"), 17047c478bd9Sstevel@tonic-gate service->sc_name); 17057c478bd9Sstevel@tonic-gate } 17067c478bd9Sstevel@tonic-gate 17077c478bd9Sstevel@tonic-gate /* 17087c478bd9Sstevel@tonic-gate * Remove leading and trailing whitespace. 17097c478bd9Sstevel@tonic-gate */ 1710*67b0e063SAlbert Lee stripped = safe_strdup((const char *)cursor->content); 17117c478bd9Sstevel@tonic-gate 171276cf44abSjeanm for (; isspace(*stripped); stripped++) 171376cf44abSjeanm ; 171476cf44abSjeanm for (cp = stripped + strlen(stripped) - 1; isspace(*cp); cp--) 171576cf44abSjeanm ; 17167c478bd9Sstevel@tonic-gate *(cp + 1) = '\0'; 17177c478bd9Sstevel@tonic-gate 17181f6eb021SLiane Praza p = internal_property_create(prop_name, SCF_TYPE_USTRING, 1, 17197c478bd9Sstevel@tonic-gate stripped); 17207c478bd9Sstevel@tonic-gate 17217c478bd9Sstevel@tonic-gate r = internal_attach_property(pg, p); 17221f6eb021SLiane Praza if (r != 0) { 17237c478bd9Sstevel@tonic-gate internal_property_free(p); 17241f6eb021SLiane Praza free(prop_name); 17251f6eb021SLiane Praza } 17267c478bd9Sstevel@tonic-gate 17277c478bd9Sstevel@tonic-gate return (r); 17287c478bd9Sstevel@tonic-gate } 17297c478bd9Sstevel@tonic-gate 17301f6eb021SLiane Praza /* 17311f6eb021SLiane Praza * This function processes all loctext elements in the current XML element 17321f6eb021SLiane Praza * designated by container. A property is created for each loctext element 17331f6eb021SLiane Praza * and added to the property group at pg. The name of the property is 17341f6eb021SLiane Praza * derived from the loctext language designation using the format at 17351f6eb021SLiane Praza * pn_format. pn_format should be an snprintf format string containing one 17361f6eb021SLiane Praza * %s which is replaced by the language designation. 17371f6eb021SLiane Praza * 17381f6eb021SLiane Praza * The function returns 0 on success and -1 if it is unable to attach the 17391f6eb021SLiane Praza * newly created property to pg. 17401f6eb021SLiane Praza */ 17411f6eb021SLiane Praza static int 17421f6eb021SLiane Praza lxml_get_all_loctext(entity_t *service, pgroup_t *pg, xmlNodePtr container, 17431f6eb021SLiane Praza const char *pn_format, const char *source) 17441f6eb021SLiane Praza { 17451f6eb021SLiane Praza xmlNodePtr cursor; 17461f6eb021SLiane Praza 17471f6eb021SLiane Praza /* 17481f6eb021SLiane Praza * Iterate through one or more loctext elements. The locale is 17491f6eb021SLiane Praza * used to generate the property name; the contents are the ustring 17501f6eb021SLiane Praza * value for the property. 17511f6eb021SLiane Praza */ 17521f6eb021SLiane Praza for (cursor = container->xmlChildrenNode; cursor != NULL; 17531f6eb021SLiane Praza cursor = cursor->next) { 17541f6eb021SLiane Praza if (lxml_ignorable_block(cursor)) 17551f6eb021SLiane Praza continue; 17561f6eb021SLiane Praza 17571f6eb021SLiane Praza switch (lxml_xlate_element(cursor->name)) { 17581f6eb021SLiane Praza case SC_LOCTEXT: 17591f6eb021SLiane Praza if (lxml_get_loctext(service, pg, cursor, pn_format, 17601f6eb021SLiane Praza source)) 17611f6eb021SLiane Praza return (-1); 17621f6eb021SLiane Praza break; 17631f6eb021SLiane Praza default: 17641f6eb021SLiane Praza uu_die(gettext("illegal element \"%s\" on %s element " 17651f6eb021SLiane Praza "for \"%s\"\n"), cursor->name, container->name, 17661f6eb021SLiane Praza service->sc_name); 17671f6eb021SLiane Praza break; 17681f6eb021SLiane Praza } 17691f6eb021SLiane Praza } 17701f6eb021SLiane Praza 17711f6eb021SLiane Praza return (0); 17721f6eb021SLiane Praza } 17731f6eb021SLiane Praza 17741f6eb021SLiane Praza /* 17751f6eb021SLiane Praza * Obtain the specified cardinality attribute and place it in a property 17761f6eb021SLiane Praza * named prop_name. The converted attribute is placed at *value, and the 17771f6eb021SLiane Praza * newly created property is returned to propp. NULL is returned to propp 17781f6eb021SLiane Praza * if the attribute is not provided in the manifest. 17791f6eb021SLiane Praza * 17801f6eb021SLiane Praza * 0 is returned upon success, and -1 indicates that the manifest contained 17811f6eb021SLiane Praza * an invalid cardinality value. 17821f6eb021SLiane Praza */ 17831f6eb021SLiane Praza static int 17841f6eb021SLiane Praza lxml_get_cardinality_attribute(entity_t *service, xmlNodePtr cursor, 17851f6eb021SLiane Praza const char *attr_name, const char *prop_name, uint64_t *value, 17861f6eb021SLiane Praza property_t **propp) 17871f6eb021SLiane Praza { 17881f6eb021SLiane Praza char *c; 17891f6eb021SLiane Praza property_t *p; 17901f6eb021SLiane Praza xmlChar *val; 17911f6eb021SLiane Praza uint64_t count; 17921f6eb021SLiane Praza char *endptr; 17931f6eb021SLiane Praza 17941f6eb021SLiane Praza *propp = NULL; 17951f6eb021SLiane Praza val = xmlGetProp(cursor, (xmlChar *)attr_name); 17961f6eb021SLiane Praza if (val == NULL) 17971f6eb021SLiane Praza return (0); 17981f6eb021SLiane Praza if (*val == 0) { 17991f6eb021SLiane Praza xmlFree(val); 18001f6eb021SLiane Praza return (0); 18011f6eb021SLiane Praza } 18021f6eb021SLiane Praza 18031f6eb021SLiane Praza /* 18041f6eb021SLiane Praza * Make sure that the string at val doesn't have a leading minus 18051f6eb021SLiane Praza * sign. The strtoull() call below does not catch this problem. 18061f6eb021SLiane Praza */ 18071f6eb021SLiane Praza for (c = (char *)val; *c != 0; c++) { 18081f6eb021SLiane Praza if (isspace(*c)) 18091f6eb021SLiane Praza continue; 18101f6eb021SLiane Praza if (isdigit(*c)) 18111f6eb021SLiane Praza break; 18121f6eb021SLiane Praza semerr(gettext("\"%c\" is not a legal character in the %s " 18131f6eb021SLiane Praza "attribute of the %s element in %s.\n"), *c, 18141f6eb021SLiane Praza attr_name, prop_name, service->sc_name); 18151f6eb021SLiane Praza xmlFree(val); 18161f6eb021SLiane Praza return (-1); 18171f6eb021SLiane Praza } 18181f6eb021SLiane Praza errno = 0; 18191f6eb021SLiane Praza count = strtoull((char *)val, &endptr, 10); 18201f6eb021SLiane Praza if (errno != 0 || endptr == (char *)val || *endptr) { 18211f6eb021SLiane Praza semerr(gettext("\"%s\" is not a legal number for the %s " 18221f6eb021SLiane Praza "attribute of the %s element in %s.\n"), (char *)val, 18231f6eb021SLiane Praza attr_name, prop_name, service->sc_name); 18241f6eb021SLiane Praza xmlFree(val); 18251f6eb021SLiane Praza return (-1); 18261f6eb021SLiane Praza } 18271f6eb021SLiane Praza 18281f6eb021SLiane Praza xmlFree(val); 18291f6eb021SLiane Praza 18301f6eb021SLiane Praza /* Value is valid. Create the property. */ 18311f6eb021SLiane Praza p = internal_property_create(prop_name, SCF_TYPE_COUNT, 1, count); 18321f6eb021SLiane Praza *value = count; 18331f6eb021SLiane Praza *propp = p; 18341f6eb021SLiane Praza return (0); 18351f6eb021SLiane Praza } 18361f6eb021SLiane Praza 18371f6eb021SLiane Praza /* 18381f6eb021SLiane Praza * The cardinality is specified by two attributes max and min at cursor. 18391f6eb021SLiane Praza * Both are optional, but if present they must be unsigned integers. 18401f6eb021SLiane Praza */ 18411f6eb021SLiane Praza static int 18421f6eb021SLiane Praza lxml_get_tm_cardinality(entity_t *service, pgroup_t *pg, xmlNodePtr cursor) 18431f6eb021SLiane Praza { 18441f6eb021SLiane Praza int min_attached = 0; 18451f6eb021SLiane Praza int compare = 1; 18461f6eb021SLiane Praza property_t *min_prop; 18471f6eb021SLiane Praza property_t *max_prop; 18481f6eb021SLiane Praza uint64_t max; 18491f6eb021SLiane Praza uint64_t min; 18501f6eb021SLiane Praza int r; 18511f6eb021SLiane Praza 18521f6eb021SLiane Praza r = lxml_get_cardinality_attribute(service, cursor, min_attr, 18531f6eb021SLiane Praza SCF_PROPERTY_TM_CARDINALITY_MIN, &min, &min_prop); 18541f6eb021SLiane Praza if (r != 0) 18551f6eb021SLiane Praza return (r); 18561f6eb021SLiane Praza if (min_prop == NULL) 18571f6eb021SLiane Praza compare = 0; 18581f6eb021SLiane Praza r = lxml_get_cardinality_attribute(service, cursor, max_attr, 18591f6eb021SLiane Praza SCF_PROPERTY_TM_CARDINALITY_MAX, &max, &max_prop); 18601f6eb021SLiane Praza if (r != 0) 18611f6eb021SLiane Praza goto errout; 18621f6eb021SLiane Praza if ((max_prop != NULL) && (compare == 1)) { 18631f6eb021SLiane Praza if (max < min) { 18641f6eb021SLiane Praza semerr(gettext("Cardinality max is less than min for " 18651f6eb021SLiane Praza "the %s element in %s.\n"), pg->sc_pgroup_name, 18661f6eb021SLiane Praza service->sc_fmri); 18671f6eb021SLiane Praza goto errout; 18681f6eb021SLiane Praza } 18691f6eb021SLiane Praza } 18701f6eb021SLiane Praza 18711f6eb021SLiane Praza /* Attach the properties to the property group. */ 18721f6eb021SLiane Praza if (min_prop) { 18731f6eb021SLiane Praza if (internal_attach_property(pg, min_prop) == 0) { 18741f6eb021SLiane Praza min_attached = 1; 18751f6eb021SLiane Praza } else { 18761f6eb021SLiane Praza goto errout; 18771f6eb021SLiane Praza } 18781f6eb021SLiane Praza } 18791f6eb021SLiane Praza if (max_prop) { 18801f6eb021SLiane Praza if (internal_attach_property(pg, max_prop) != 0) { 18811f6eb021SLiane Praza if (min_attached) 18821f6eb021SLiane Praza internal_detach_property(pg, min_prop); 18831f6eb021SLiane Praza goto errout; 18841f6eb021SLiane Praza } 18851f6eb021SLiane Praza } 18861f6eb021SLiane Praza return (0); 18871f6eb021SLiane Praza 18881f6eb021SLiane Praza errout: 18891f6eb021SLiane Praza if (min_prop) 18901f6eb021SLiane Praza internal_property_free(min_prop); 18911f6eb021SLiane Praza if (max_prop) 18921f6eb021SLiane Praza internal_property_free(max_prop); 18931f6eb021SLiane Praza return (-1); 18941f6eb021SLiane Praza } 18951f6eb021SLiane Praza 18961f6eb021SLiane Praza /* 18971f6eb021SLiane Praza * Get the common_name which is present as localized text at common_name in 18981f6eb021SLiane Praza * the manifest. The common_name is stored as the value of a property in 18991f6eb021SLiane Praza * the property group whose name is SCF_PG_TM_COMMON_NAME and type is 19001f6eb021SLiane Praza * SCF_GROUP_TEMPLATE. This property group will be created in service if 19011f6eb021SLiane Praza * it is not already there. 19021f6eb021SLiane Praza */ 19037c478bd9Sstevel@tonic-gate static int 19047c478bd9Sstevel@tonic-gate lxml_get_tm_common_name(entity_t *service, xmlNodePtr common_name) 19057c478bd9Sstevel@tonic-gate { 19067c478bd9Sstevel@tonic-gate pgroup_t *pg; 19077c478bd9Sstevel@tonic-gate 19087c478bd9Sstevel@tonic-gate /* 19097c478bd9Sstevel@tonic-gate * Create the property group, if absent. 19107c478bd9Sstevel@tonic-gate */ 19111f6eb021SLiane Praza pg = internal_pgroup_find_or_create(service, SCF_PG_TM_COMMON_NAME, 19121f6eb021SLiane Praza SCF_GROUP_TEMPLATE); 19131f6eb021SLiane Praza 19141f6eb021SLiane Praza return (lxml_get_all_loctext(service, pg, common_name, LOCALE_ONLY_FMT, 19151f6eb021SLiane Praza "common_name")); 19161f6eb021SLiane Praza } 19177c478bd9Sstevel@tonic-gate 19187c478bd9Sstevel@tonic-gate /* 19191f6eb021SLiane Praza * Get the description which is present as localized text at description in 19201f6eb021SLiane Praza * the manifest. The description is stored as the value of a property in 19211f6eb021SLiane Praza * the property group whose name is SCF_PG_TM_DESCRIPTION and type is 19221f6eb021SLiane Praza * SCF_GROUP_TEMPLATE. This property group will be created in service if 19231f6eb021SLiane Praza * it is not already there. 19247c478bd9Sstevel@tonic-gate */ 19257c478bd9Sstevel@tonic-gate static int 19267c478bd9Sstevel@tonic-gate lxml_get_tm_description(entity_t *service, xmlNodePtr description) 19277c478bd9Sstevel@tonic-gate { 19287c478bd9Sstevel@tonic-gate pgroup_t *pg; 19297c478bd9Sstevel@tonic-gate 19307c478bd9Sstevel@tonic-gate /* 19317c478bd9Sstevel@tonic-gate * Create the property group, if absent. 19327c478bd9Sstevel@tonic-gate */ 19331f6eb021SLiane Praza pg = internal_pgroup_find_or_create(service, SCF_PG_TM_DESCRIPTION, 19341f6eb021SLiane Praza SCF_GROUP_TEMPLATE); 19357c478bd9Sstevel@tonic-gate 19361f6eb021SLiane Praza return (lxml_get_all_loctext(service, pg, description, 19371f6eb021SLiane Praza LOCALE_ONLY_FMT, "description")); 19387c478bd9Sstevel@tonic-gate } 19397c478bd9Sstevel@tonic-gate 19407c478bd9Sstevel@tonic-gate static char * 19417c478bd9Sstevel@tonic-gate lxml_label_to_groupname(const char *prefix, const char *in) 19427c478bd9Sstevel@tonic-gate { 19437c478bd9Sstevel@tonic-gate char *out, *cp; 19447c478bd9Sstevel@tonic-gate size_t len, piece_len; 19457c478bd9Sstevel@tonic-gate 1946*67b0e063SAlbert Lee out = uu_zalloc(2 * max_scf_name_len + 1); 19477c478bd9Sstevel@tonic-gate if (out == NULL) 19487c478bd9Sstevel@tonic-gate return (NULL); 19497c478bd9Sstevel@tonic-gate 1950*67b0e063SAlbert Lee (void) strlcpy(out, prefix, 2 * max_scf_name_len + 1); 19517c478bd9Sstevel@tonic-gate 1952*67b0e063SAlbert Lee len = strlcat(out, in, 2 * max_scf_name_len + 1); 19537c478bd9Sstevel@tonic-gate if (len > max_scf_name_len) { 19547c478bd9Sstevel@tonic-gate /* Use the first half and the second half. */ 19557c478bd9Sstevel@tonic-gate piece_len = (max_scf_name_len - 2) / 2; 19567c478bd9Sstevel@tonic-gate 19577c478bd9Sstevel@tonic-gate (void) strncpy(out + piece_len, "..", 2); 19587c478bd9Sstevel@tonic-gate 19597c478bd9Sstevel@tonic-gate (void) strcpy(out + piece_len + 2, out + (len - piece_len)); 19607c478bd9Sstevel@tonic-gate } 19617c478bd9Sstevel@tonic-gate 19627c478bd9Sstevel@tonic-gate /* 19637c478bd9Sstevel@tonic-gate * Translate non-property characters to '_'. 19647c478bd9Sstevel@tonic-gate */ 19657c478bd9Sstevel@tonic-gate for (cp = out; *cp != '\0'; ++cp) { 19667c478bd9Sstevel@tonic-gate if (!(isalnum(*cp) || *cp == '_' || *cp == '-')) 19677c478bd9Sstevel@tonic-gate *cp = '_'; 19687c478bd9Sstevel@tonic-gate } 19697c478bd9Sstevel@tonic-gate 19707c478bd9Sstevel@tonic-gate return (out); 19717c478bd9Sstevel@tonic-gate } 19727c478bd9Sstevel@tonic-gate 19731f6eb021SLiane Praza /* 19741f6eb021SLiane Praza * If *p is NULL, astring_prop_value() first creates a property with the 19751f6eb021SLiane Praza * name specified in prop_name. The address of the newly created property 19761f6eb021SLiane Praza * is placed in *p. 19771f6eb021SLiane Praza * 19781f6eb021SLiane Praza * In either case, newly created property or existing property, a new 19791f6eb021SLiane Praza * SCF_TYPE_ASTRING value will created and attached to the property at *p. 19801f6eb021SLiane Praza * The value of the newly created property is prop_value. 19811f6eb021SLiane Praza * 19821f6eb021SLiane Praza * free_flag is used to indicate whether or not the memory at prop_value 19831f6eb021SLiane Praza * should be freed when the property is freed by a call to 19841f6eb021SLiane Praza * internal_property_free(). 19851f6eb021SLiane Praza */ 19861f6eb021SLiane Praza static void 19871f6eb021SLiane Praza astring_prop_value(property_t **p, const char *prop_name, char *prop_value, 19881f6eb021SLiane Praza boolean_t free_flag) 19891f6eb021SLiane Praza { 19901f6eb021SLiane Praza value_t *v; 19911f6eb021SLiane Praza 19921f6eb021SLiane Praza if (*p == NULL) { 19931f6eb021SLiane Praza /* Create the property */ 19941f6eb021SLiane Praza *p = internal_property_new(); 19951f6eb021SLiane Praza (*p)->sc_property_name = (char *)prop_name; 19961f6eb021SLiane Praza (*p)->sc_value_type = SCF_TYPE_ASTRING; 19971f6eb021SLiane Praza } 19981f6eb021SLiane Praza 19991f6eb021SLiane Praza /* Add the property value to the property's list of values. */ 20001f6eb021SLiane Praza v = internal_value_new(); 20011f6eb021SLiane Praza v->sc_type = SCF_TYPE_ASTRING; 20021f6eb021SLiane Praza if (free_flag == B_TRUE) 20031f6eb021SLiane Praza v->sc_free = lxml_free_str; 20041f6eb021SLiane Praza v->sc_u.sc_string = prop_value; 20051f6eb021SLiane Praza internal_attach_value(*p, v); 20061f6eb021SLiane Praza } 20071f6eb021SLiane Praza 20081f6eb021SLiane Praza /* 20091f6eb021SLiane Praza * If p points to a null pointer, create an internal_separators property 20101f6eb021SLiane Praza * saving the address at p. For each character at seps create a property 20111f6eb021SLiane Praza * value and attach it to the property at p. 20121f6eb021SLiane Praza */ 20131f6eb021SLiane Praza static void 20141f6eb021SLiane Praza seps_to_prop_values(property_t **p, xmlChar *seps) 20151f6eb021SLiane Praza { 20161f6eb021SLiane Praza value_t *v; 20171f6eb021SLiane Praza char val_str[2]; 20181f6eb021SLiane Praza 20191f6eb021SLiane Praza if (*p == NULL) { 20201f6eb021SLiane Praza *p = internal_property_new(); 20211f6eb021SLiane Praza (*p)->sc_property_name = 20221f6eb021SLiane Praza (char *)SCF_PROPERTY_INTERNAL_SEPARATORS; 20231f6eb021SLiane Praza (*p)->sc_value_type = SCF_TYPE_ASTRING; 20241f6eb021SLiane Praza } 20251f6eb021SLiane Praza 20261f6eb021SLiane Praza /* Add the values to the property's list. */ 20271f6eb021SLiane Praza val_str[1] = 0; /* Terminate the string. */ 20281f6eb021SLiane Praza for (; *seps != 0; seps++) { 20291f6eb021SLiane Praza v = internal_value_new(); 20301f6eb021SLiane Praza v->sc_type = (*p)->sc_value_type; 20311f6eb021SLiane Praza v->sc_free = lxml_free_str; 20321f6eb021SLiane Praza val_str[0] = *seps; 2033*67b0e063SAlbert Lee v->sc_u.sc_string = safe_strdup(val_str); 20341f6eb021SLiane Praza internal_attach_value(*p, v); 20351f6eb021SLiane Praza } 20361f6eb021SLiane Praza } 20371f6eb021SLiane Praza 20381f6eb021SLiane Praza /* 20391f6eb021SLiane Praza * Create an internal_separators property and attach it to the property 20401f6eb021SLiane Praza * group at pg. The separator characters are provided in the text nodes 20411f6eb021SLiane Praza * that are the children of seps. Each separator character is stored as a 20421f6eb021SLiane Praza * property value in the internal_separators property. 20431f6eb021SLiane Praza */ 20441f6eb021SLiane Praza static int 20451f6eb021SLiane Praza lxml_get_tm_internal_seps(entity_t *service, pgroup_t *pg, xmlNodePtr seps) 20461f6eb021SLiane Praza { 20471f6eb021SLiane Praza xmlNodePtr cursor; 20481f6eb021SLiane Praza property_t *prop = NULL; 20491f6eb021SLiane Praza int r; 20501f6eb021SLiane Praza 20511f6eb021SLiane Praza for (cursor = seps->xmlChildrenNode; cursor != NULL; 20521f6eb021SLiane Praza cursor = cursor->next) { 20531f6eb021SLiane Praza if (strcmp("text", (const char *)cursor->name) == 0) { 20541f6eb021SLiane Praza seps_to_prop_values(&prop, cursor->content); 20551f6eb021SLiane Praza } else if (strcmp("comment", (const char *)cursor->name) != 0) { 20561f6eb021SLiane Praza uu_die(gettext("illegal element \"%s\" on %s element " 20571f6eb021SLiane Praza "for \"%s\"\n"), cursor->name, seps->name, 20581f6eb021SLiane Praza service->sc_name); 20591f6eb021SLiane Praza } 20601f6eb021SLiane Praza } 20611f6eb021SLiane Praza if (prop == NULL) { 20621f6eb021SLiane Praza semerr(gettext("The %s element in %s had an empty list of " 20631f6eb021SLiane Praza "separators.\n"), (const char *)seps->name, 20641f6eb021SLiane Praza service->sc_name); 20651f6eb021SLiane Praza return (-1); 20661f6eb021SLiane Praza } 20671f6eb021SLiane Praza r = internal_attach_property(pg, prop); 20681f6eb021SLiane Praza if (r != 0) 20691f6eb021SLiane Praza internal_property_free(prop); 20701f6eb021SLiane Praza return (r); 20711f6eb021SLiane Praza } 20721f6eb021SLiane Praza 20737c478bd9Sstevel@tonic-gate static int 20747c478bd9Sstevel@tonic-gate lxml_get_tm_manpage(entity_t *service, xmlNodePtr manpage) 20757c478bd9Sstevel@tonic-gate { 20767c478bd9Sstevel@tonic-gate pgroup_t *pg; 20777c478bd9Sstevel@tonic-gate char *pgname; 2078*67b0e063SAlbert Lee char *name; 20797c478bd9Sstevel@tonic-gate xmlChar *title; 2080*67b0e063SAlbert Lee xmlChar *section; 20817c478bd9Sstevel@tonic-gate 20827c478bd9Sstevel@tonic-gate /* 2083*67b0e063SAlbert Lee * Fetch title and section attributes, convert to something sanitized, 2084*67b0e063SAlbert Lee * and create property group. 20857c478bd9Sstevel@tonic-gate */ 20861f6eb021SLiane Praza title = xmlGetProp(manpage, (xmlChar *)title_attr); 2087*67b0e063SAlbert Lee if (title == NULL) 2088*67b0e063SAlbert Lee return (-1); 2089*67b0e063SAlbert Lee section = xmlGetProp(manpage, (xmlChar *)section_attr); 2090*67b0e063SAlbert Lee if (section == NULL) { 2091*67b0e063SAlbert Lee xmlFree(title); 2092*67b0e063SAlbert Lee return (-1); 2093*67b0e063SAlbert Lee } 2094*67b0e063SAlbert Lee 2095*67b0e063SAlbert Lee name = safe_malloc(max_scf_name_len + 1); 2096*67b0e063SAlbert Lee 2097*67b0e063SAlbert Lee /* Find existing property group with underscore separators */ 2098*67b0e063SAlbert Lee (void) snprintf(name, max_scf_name_len + 1, "%s_%s", title, section); 2099*67b0e063SAlbert Lee pgname = lxml_label_to_groupname(SCF_PG_TM_MAN_PREFIX, name); 2100*67b0e063SAlbert Lee pg = internal_pgroup_find(service, pgname, SCF_GROUP_TEMPLATE); 2101*67b0e063SAlbert Lee 2102*67b0e063SAlbert Lee uu_free(pgname); 2103*67b0e063SAlbert Lee (void) snprintf(name, max_scf_name_len + 1, "%s%s", title, section); 2104*67b0e063SAlbert Lee pgname = lxml_label_to_groupname(SCF_PG_TM_MAN_PREFIX, name); 2105*67b0e063SAlbert Lee 2106*67b0e063SAlbert Lee if (pg == NULL) { 2107*67b0e063SAlbert Lee pg = internal_pgroup_find_or_create(service, pgname, 2108*67b0e063SAlbert Lee SCF_GROUP_TEMPLATE); 2109*67b0e063SAlbert Lee } else { 2110*67b0e063SAlbert Lee /* Rename property group */ 2111*67b0e063SAlbert Lee free((char *)pg->sc_pgroup_name); 2112*67b0e063SAlbert Lee pg->sc_pgroup_name = safe_strdup(pgname); 2113*67b0e063SAlbert Lee } 2114*67b0e063SAlbert Lee 2115*67b0e063SAlbert Lee uu_free(pgname); 2116*67b0e063SAlbert Lee free(name); 2117*67b0e063SAlbert Lee xmlFree(section); 21181f6eb021SLiane Praza xmlFree(title); 21197c478bd9Sstevel@tonic-gate 21207c478bd9Sstevel@tonic-gate 21217c478bd9Sstevel@tonic-gate /* 21227c478bd9Sstevel@tonic-gate * Each attribute is an astring property within the group. 21237c478bd9Sstevel@tonic-gate */ 21241f6eb021SLiane Praza if (new_str_prop_from_attr(pg, SCF_PROPERTY_TM_TITLE, 21251f6eb021SLiane Praza SCF_TYPE_ASTRING, manpage, title_attr) != 0 || 21261f6eb021SLiane Praza new_str_prop_from_attr(pg, SCF_PROPERTY_TM_SECTION, 21271f6eb021SLiane Praza SCF_TYPE_ASTRING, manpage, section_attr) != 0 || 21281f6eb021SLiane Praza new_str_prop_from_attr(pg, SCF_PROPERTY_TM_MANPATH, 21291f6eb021SLiane Praza SCF_TYPE_ASTRING, manpage, manpath_attr) != 0) 21307c478bd9Sstevel@tonic-gate return (-1); 21317c478bd9Sstevel@tonic-gate 21327c478bd9Sstevel@tonic-gate return (0); 21337c478bd9Sstevel@tonic-gate } 21347c478bd9Sstevel@tonic-gate 21357c478bd9Sstevel@tonic-gate static int 21367c478bd9Sstevel@tonic-gate lxml_get_tm_doclink(entity_t *service, xmlNodePtr doc_link) 21377c478bd9Sstevel@tonic-gate { 21387c478bd9Sstevel@tonic-gate pgroup_t *pg; 21397c478bd9Sstevel@tonic-gate char *pgname; 21407c478bd9Sstevel@tonic-gate xmlChar *name; 21417c478bd9Sstevel@tonic-gate 21427c478bd9Sstevel@tonic-gate /* 21437c478bd9Sstevel@tonic-gate * Fetch name attribute, convert name to something sanitized, and create 21447c478bd9Sstevel@tonic-gate * property group. 21457c478bd9Sstevel@tonic-gate */ 21461f6eb021SLiane Praza name = xmlGetProp(doc_link, (xmlChar *)name_attr); 2147*67b0e063SAlbert Lee if (name == NULL) 2148*67b0e063SAlbert Lee return (-1); 21497c478bd9Sstevel@tonic-gate 21507c478bd9Sstevel@tonic-gate pgname = (char *)lxml_label_to_groupname(SCF_PG_TM_DOC_PREFIX, 21517c478bd9Sstevel@tonic-gate (const char *)name); 21527c478bd9Sstevel@tonic-gate 21537c478bd9Sstevel@tonic-gate pg = internal_pgroup_find_or_create(service, pgname, 21547c478bd9Sstevel@tonic-gate (char *)SCF_GROUP_TEMPLATE); 2155*67b0e063SAlbert Lee 2156*67b0e063SAlbert Lee uu_free(pgname); 21571f6eb021SLiane Praza xmlFree(name); 21587c478bd9Sstevel@tonic-gate 21597c478bd9Sstevel@tonic-gate /* 21607c478bd9Sstevel@tonic-gate * Each attribute is an astring property within the group. 21617c478bd9Sstevel@tonic-gate */ 21621f6eb021SLiane Praza if (new_str_prop_from_attr(pg, SCF_PROPERTY_TM_NAME, SCF_TYPE_ASTRING, 21631f6eb021SLiane Praza doc_link, name_attr) != 0 || 21641f6eb021SLiane Praza new_str_prop_from_attr(pg, SCF_PROPERTY_TM_URI, SCF_TYPE_ASTRING, 21651f6eb021SLiane Praza doc_link, uri_attr) != 0) 21667c478bd9Sstevel@tonic-gate return (-1); 21677c478bd9Sstevel@tonic-gate 21687c478bd9Sstevel@tonic-gate return (0); 21697c478bd9Sstevel@tonic-gate } 21707c478bd9Sstevel@tonic-gate 21717c478bd9Sstevel@tonic-gate static int 21727c478bd9Sstevel@tonic-gate lxml_get_tm_documentation(entity_t *service, xmlNodePtr documentation) 21737c478bd9Sstevel@tonic-gate { 21747c478bd9Sstevel@tonic-gate xmlNodePtr cursor; 21757c478bd9Sstevel@tonic-gate 21767c478bd9Sstevel@tonic-gate for (cursor = documentation->xmlChildrenNode; cursor != NULL; 21777c478bd9Sstevel@tonic-gate cursor = cursor->next) { 21787c478bd9Sstevel@tonic-gate if (lxml_ignorable_block(cursor)) 21797c478bd9Sstevel@tonic-gate continue; 21807c478bd9Sstevel@tonic-gate 21817c478bd9Sstevel@tonic-gate switch (lxml_xlate_element(cursor->name)) { 21827c478bd9Sstevel@tonic-gate case SC_MANPAGE: 21837c478bd9Sstevel@tonic-gate (void) lxml_get_tm_manpage(service, cursor); 21847c478bd9Sstevel@tonic-gate break; 21857c478bd9Sstevel@tonic-gate case SC_DOC_LINK: 21867c478bd9Sstevel@tonic-gate (void) lxml_get_tm_doclink(service, cursor); 21877c478bd9Sstevel@tonic-gate break; 21887c478bd9Sstevel@tonic-gate default: 21897c478bd9Sstevel@tonic-gate uu_die(gettext("illegal element \"%s\" on template " 21907c478bd9Sstevel@tonic-gate "for service \"%s\"\n"), 21917c478bd9Sstevel@tonic-gate cursor->name, service->sc_name); 21927c478bd9Sstevel@tonic-gate } 21937c478bd9Sstevel@tonic-gate } 21947c478bd9Sstevel@tonic-gate 21957c478bd9Sstevel@tonic-gate return (0); 21967c478bd9Sstevel@tonic-gate } 21977c478bd9Sstevel@tonic-gate 21987c478bd9Sstevel@tonic-gate static int 21991f6eb021SLiane Praza lxml_get_prop_pattern_attributes(pgroup_t *pg, xmlNodePtr cursor) 22001f6eb021SLiane Praza { 22011f6eb021SLiane Praza if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_TM_NAME, 22021f6eb021SLiane Praza SCF_TYPE_ASTRING, cursor, name_attr, NULL) != 0) { 22031f6eb021SLiane Praza return (-1); 22041f6eb021SLiane Praza } 22051f6eb021SLiane Praza if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_TM_TYPE, 22061f6eb021SLiane Praza SCF_TYPE_ASTRING, cursor, type_attr, "") != 0) { 22071f6eb021SLiane Praza return (-1); 22081f6eb021SLiane Praza } 22091f6eb021SLiane Praza if (new_bool_prop_from_attr(pg, SCF_PROPERTY_TM_REQUIRED, cursor, 22101f6eb021SLiane Praza required_attr) != 0) 22111f6eb021SLiane Praza return (-1); 22121f6eb021SLiane Praza return (0); 22131f6eb021SLiane Praza } 22141f6eb021SLiane Praza 22151f6eb021SLiane Praza static int 22161f6eb021SLiane Praza lxml_get_tm_include_values(entity_t *service, pgroup_t *pg, 22171f6eb021SLiane Praza xmlNodePtr include_values, const char *prop_name) 22181f6eb021SLiane Praza { 22191f6eb021SLiane Praza boolean_t attach_to_pg = B_FALSE; 22201f6eb021SLiane Praza property_t *p; 22211f6eb021SLiane Praza int r = 0; 22221f6eb021SLiane Praza char *type; 22231f6eb021SLiane Praza 22241f6eb021SLiane Praza /* Get the type attribute of the include_values element. */ 22251f6eb021SLiane Praza type = (char *)xmlGetProp(include_values, (const xmlChar *)type_attr); 22261f6eb021SLiane Praza if ((type == NULL) || (*type == 0)) { 22271f6eb021SLiane Praza uu_die(gettext("%s element requires a %s attribute in the %s " 22281f6eb021SLiane Praza "service.\n"), include_values->name, type_attr, 22291f6eb021SLiane Praza service->sc_name); 22301f6eb021SLiane Praza } 22311f6eb021SLiane Praza 22321f6eb021SLiane Praza /* Add the type to the values of the prop_name property. */ 22331f6eb021SLiane Praza p = internal_property_find(pg, prop_name); 22341f6eb021SLiane Praza if (p == NULL) 22351f6eb021SLiane Praza attach_to_pg = B_TRUE; 22361f6eb021SLiane Praza astring_prop_value(&p, prop_name, type, B_FALSE); 22371f6eb021SLiane Praza if (attach_to_pg == B_TRUE) { 22381f6eb021SLiane Praza r = internal_attach_property(pg, p); 22391f6eb021SLiane Praza if (r != 0) 22401f6eb021SLiane Praza internal_property_free(p); 22411f6eb021SLiane Praza } 22421f6eb021SLiane Praza return (r); 22431f6eb021SLiane Praza } 22441f6eb021SLiane Praza 22451f6eb021SLiane Praza #define RC_MIN 0 22461f6eb021SLiane Praza #define RC_MAX 1 22471f6eb021SLiane Praza #define RC_COUNT 2 22481f6eb021SLiane Praza 22491f6eb021SLiane Praza /* 22501f6eb021SLiane Praza * Verify that the strings at min and max are valid numeric strings. Also 22511f6eb021SLiane Praza * verify that max is numerically >= min. 22521f6eb021SLiane Praza * 22531f6eb021SLiane Praza * 0 is returned if the range is valid, and -1 is returned if it is not. 22541f6eb021SLiane Praza */ 22551f6eb021SLiane Praza static int 22561f6eb021SLiane Praza verify_range(entity_t *service, xmlNodePtr range, char *min, char *max) 22571f6eb021SLiane Praza { 22581f6eb021SLiane Praza char *c; 22591f6eb021SLiane Praza int i; 22601f6eb021SLiane Praza int is_signed = 0; 22611f6eb021SLiane Praza int inverted = 0; 22621f6eb021SLiane Praza const char *limit[RC_COUNT]; 22631f6eb021SLiane Praza char *strings[RC_COUNT]; 22641f6eb021SLiane Praza uint64_t urange[RC_COUNT]; /* unsigned range. */ 22651f6eb021SLiane Praza int64_t srange[RC_COUNT]; /* signed range. */ 22661f6eb021SLiane Praza 22671f6eb021SLiane Praza strings[RC_MIN] = min; 22681f6eb021SLiane Praza strings[RC_MAX] = max; 22691f6eb021SLiane Praza limit[RC_MIN] = min_attr; 22701f6eb021SLiane Praza limit[RC_MAX] = max_attr; 22711f6eb021SLiane Praza 22721f6eb021SLiane Praza /* See if the range is signed. */ 22731f6eb021SLiane Praza for (i = 0; (i < RC_COUNT) && (is_signed == 0); i++) { 22741f6eb021SLiane Praza c = strings[i]; 22751f6eb021SLiane Praza while (isspace(*c)) { 22761f6eb021SLiane Praza c++; 22771f6eb021SLiane Praza } 22781f6eb021SLiane Praza if (*c == '-') 22791f6eb021SLiane Praza is_signed = 1; 22801f6eb021SLiane Praza } 22811f6eb021SLiane Praza 22821f6eb021SLiane Praza /* Attempt to convert the strings. */ 22831f6eb021SLiane Praza for (i = 0; i < RC_COUNT; i++) { 22841f6eb021SLiane Praza errno = 0; 22851f6eb021SLiane Praza if (is_signed) { 22861f6eb021SLiane Praza srange[i] = strtoll(strings[i], &c, 0); 22871f6eb021SLiane Praza } else { 22881f6eb021SLiane Praza urange[i] = strtoull(strings[i], &c, 0); 22891f6eb021SLiane Praza } 22901f6eb021SLiane Praza if ((errno != 0) || (c == strings[i]) || (*c != 0)) { 22911f6eb021SLiane Praza /* Conversion failed. */ 22921f6eb021SLiane Praza uu_die(gettext("Unable to convert %s for the %s " 22931f6eb021SLiane Praza "element in service %s.\n"), limit[i], 22941f6eb021SLiane Praza (char *)range->name, service->sc_name); 22951f6eb021SLiane Praza } 22961f6eb021SLiane Praza } 22971f6eb021SLiane Praza 22981f6eb021SLiane Praza /* Make sure that min is <= max */ 22991f6eb021SLiane Praza if (is_signed) { 23001f6eb021SLiane Praza if (srange[RC_MAX] < srange[RC_MIN]) 23011f6eb021SLiane Praza inverted = 1; 23021f6eb021SLiane Praza } else { 23031f6eb021SLiane Praza if (urange[RC_MAX] < urange[RC_MIN]) 23041f6eb021SLiane Praza inverted = 1; 23051f6eb021SLiane Praza } 23061f6eb021SLiane Praza if (inverted != 0) { 23071f6eb021SLiane Praza semerr(gettext("Maximum less than minimum for the %s element " 23081f6eb021SLiane Praza "in service %s.\n"), (char *)range->name, 23091f6eb021SLiane Praza service->sc_name); 23101f6eb021SLiane Praza return (-1); 23111f6eb021SLiane Praza } 23121f6eb021SLiane Praza 23131f6eb021SLiane Praza return (0); 23141f6eb021SLiane Praza } 23151f6eb021SLiane Praza 23161f6eb021SLiane Praza /* 23171f6eb021SLiane Praza * This, function creates a property named prop_name. The range element 23181f6eb021SLiane Praza * should have two attributes -- min and max. The property value then 23191f6eb021SLiane Praza * becomes the concatenation of their value separated by a comma. The 23201f6eb021SLiane Praza * property is then attached to the property group at pg. 23211f6eb021SLiane Praza * 23221f6eb021SLiane Praza * If pg already contains a property with a name of prop_name, it is only 23231f6eb021SLiane Praza * necessary to create a new value and attach it to the existing property. 23241f6eb021SLiane Praza */ 23251f6eb021SLiane Praza static int 23261f6eb021SLiane Praza lxml_get_tm_range(entity_t *service, pgroup_t *pg, xmlNodePtr range, 23271f6eb021SLiane Praza const char *prop_name) 23281f6eb021SLiane Praza { 23291f6eb021SLiane Praza boolean_t attach_to_pg = B_FALSE; 23301f6eb021SLiane Praza char *max; 23311f6eb021SLiane Praza char *min; 23321f6eb021SLiane Praza property_t *p; 23331f6eb021SLiane Praza char *prop_value; 23341f6eb021SLiane Praza int r = 0; 23351f6eb021SLiane Praza 23361f6eb021SLiane Praza /* Get max and min from the XML description. */ 23371f6eb021SLiane Praza max = (char *)xmlGetProp(range, (xmlChar *)max_attr); 23381f6eb021SLiane Praza if ((max == NULL) || (*max == 0)) { 23391f6eb021SLiane Praza uu_die(gettext("%s element is missing the %s attribute in " 23401f6eb021SLiane Praza "service %s.\n"), (char *)range->name, max_attr, 23411f6eb021SLiane Praza service->sc_name); 23421f6eb021SLiane Praza } 23431f6eb021SLiane Praza min = (char *)xmlGetProp(range, (xmlChar *)min_attr); 23441f6eb021SLiane Praza if ((min == NULL) || (*min == 0)) { 23451f6eb021SLiane Praza uu_die(gettext("%s element is missing the %s attribute in " 23461f6eb021SLiane Praza "service %s.\n"), (char *)range->name, min_attr, 23471f6eb021SLiane Praza service->sc_name); 23481f6eb021SLiane Praza } 23491f6eb021SLiane Praza if (verify_range(service, range, min, max) != 0) { 23501f6eb021SLiane Praza xmlFree(min); 23511f6eb021SLiane Praza xmlFree(max); 23521f6eb021SLiane Praza return (-1); 23531f6eb021SLiane Praza } 23541f6eb021SLiane Praza 23551f6eb021SLiane Praza /* Property value is concatenation of min and max. */ 23561f6eb021SLiane Praza prop_value = safe_malloc(max_scf_value_len + 1); 23571f6eb021SLiane Praza if (snprintf(prop_value, max_scf_value_len + 1, "%s,%s", min, max) >= 23581f6eb021SLiane Praza max_scf_value_len + 1) { 23591f6eb021SLiane Praza uu_die(gettext("min and max are too long for the %s element " 23601f6eb021SLiane Praza "of %s.\n"), (char *)range->name, service->sc_name); 23611f6eb021SLiane Praza } 23621f6eb021SLiane Praza xmlFree(min); 23631f6eb021SLiane Praza xmlFree(max); 23641f6eb021SLiane Praza 23651f6eb021SLiane Praza /* 23661f6eb021SLiane Praza * If necessary create the property and attach it to the property 23671f6eb021SLiane Praza * group. 23681f6eb021SLiane Praza */ 23691f6eb021SLiane Praza p = internal_property_find(pg, prop_name); 23701f6eb021SLiane Praza if (p == NULL) 23711f6eb021SLiane Praza attach_to_pg = B_TRUE; 23721f6eb021SLiane Praza astring_prop_value(&p, prop_name, prop_value, B_TRUE); 23731f6eb021SLiane Praza if (attach_to_pg == B_TRUE) { 23741f6eb021SLiane Praza r = internal_attach_property(pg, p); 23751f6eb021SLiane Praza if (r != 0) { 23761f6eb021SLiane Praza internal_property_free(p); 23771f6eb021SLiane Praza } 23781f6eb021SLiane Praza } 23791f6eb021SLiane Praza return (r); 23801f6eb021SLiane Praza } 23811f6eb021SLiane Praza 23821f6eb021SLiane Praza /* 23831f6eb021SLiane Praza * Determine how many plain characters are represented by count Base32 23841f6eb021SLiane Praza * encoded characters. 5 plain text characters are converted to 8 Base32 23851f6eb021SLiane Praza * characters. 23861f6eb021SLiane Praza */ 23871f6eb021SLiane Praza static size_t 23881f6eb021SLiane Praza encoded_count_to_plain(size_t count) 23891f6eb021SLiane Praza { 23901f6eb021SLiane Praza return (5 * ((count + 7) / 8)); 23911f6eb021SLiane Praza } 23921f6eb021SLiane Praza 23931f6eb021SLiane Praza /* 23941f6eb021SLiane Praza * The value element contains 0 or 1 common_name element followed by 0 or 1 23951f6eb021SLiane Praza * description element. It also has a required attribute called "name". 23961f6eb021SLiane Praza * The common_name and description are stored as property values in pg. 23971f6eb021SLiane Praza * The property names are: 23981f6eb021SLiane Praza * value_<name>_common_name_<lang> 23991f6eb021SLiane Praza * value_<name>_description_<lang> 24001f6eb021SLiane Praza * 24011f6eb021SLiane Praza * The <name> portion of the preceeding proper names requires more 24021f6eb021SLiane Praza * explanation. Ideally it would just the name attribute of this value 24031f6eb021SLiane Praza * element. Unfortunately, the name attribute can contain characters that 24041f6eb021SLiane Praza * are not legal in a property name. Thus, we base 32 encode the name 24051f6eb021SLiane Praza * attribute and use that for <name>. 24061f6eb021SLiane Praza * 24071f6eb021SLiane Praza * There are cases where the caller needs to know the name, so it is 24081f6eb021SLiane Praza * returned through the name_value pointer if it is not NULL. 24091f6eb021SLiane Praza * 24101f6eb021SLiane Praza * Parameters: 24111f6eb021SLiane Praza * service - Information about the service that is being 24121f6eb021SLiane Praza * processed. This function only uses this parameter 24131f6eb021SLiane Praza * for producing error messages. 24141f6eb021SLiane Praza * 24151f6eb021SLiane Praza * pg - The property group to receive the newly created 24161f6eb021SLiane Praza * properties. 24171f6eb021SLiane Praza * 24181f6eb021SLiane Praza * value - Pointer to the value element in the XML tree. 24191f6eb021SLiane Praza * 24201f6eb021SLiane Praza * name_value - Address to receive the value of the name attribute. 24211f6eb021SLiane Praza * The caller must free the memory. 24221f6eb021SLiane Praza */ 24231f6eb021SLiane Praza static int 24241f6eb021SLiane Praza lxml_get_tm_value_element(entity_t *service, pgroup_t *pg, xmlNodePtr value, 24251f6eb021SLiane Praza char **name_value) 24261f6eb021SLiane Praza { 24271f6eb021SLiane Praza char *common_name_fmt; 24281f6eb021SLiane Praza xmlNodePtr cursor; 24291f6eb021SLiane Praza char *description_fmt; 24301f6eb021SLiane Praza char *encoded_value = NULL; 24311f6eb021SLiane Praza size_t extra; 24321f6eb021SLiane Praza char *value_name; 24331f6eb021SLiane Praza int r = 0; 24341f6eb021SLiane Praza 24351f6eb021SLiane Praza common_name_fmt = safe_malloc(max_scf_name_len + 1); 24361f6eb021SLiane Praza description_fmt = safe_malloc(max_scf_name_len + 1); 24371f6eb021SLiane Praza 24381f6eb021SLiane Praza /* 24391f6eb021SLiane Praza * Get the value of our name attribute, so that we can use it to 24401f6eb021SLiane Praza * construct property names. 24411f6eb021SLiane Praza */ 24421f6eb021SLiane Praza value_name = (char *)xmlGetProp(value, (xmlChar *)name_attr); 24431f6eb021SLiane Praza /* The value name must be present, but it can be empty. */ 24441f6eb021SLiane Praza if (value_name == NULL) { 24451f6eb021SLiane Praza uu_die(gettext("%s element requires a %s attribute in the %s " 24461f6eb021SLiane Praza "service.\n"), (char *)value->name, name_attr, 24471f6eb021SLiane Praza service->sc_name); 24481f6eb021SLiane Praza } 24491f6eb021SLiane Praza 24501f6eb021SLiane Praza /* 24511f6eb021SLiane Praza * The value_name may contain characters that are not valid in in a 24521f6eb021SLiane Praza * property name. So we will encode value_name and then use the 24531f6eb021SLiane Praza * encoded value in the property name. 24541f6eb021SLiane Praza */ 24551f6eb021SLiane Praza encoded_value = safe_malloc(max_scf_name_len + 1); 24561f6eb021SLiane Praza if (scf_encode32(value_name, strlen(value_name), encoded_value, 24571f6eb021SLiane Praza max_scf_name_len + 1, &extra, SCF_ENCODE32_PAD) != 0) { 24581f6eb021SLiane Praza extra = encoded_count_to_plain(extra - max_scf_name_len); 24591f6eb021SLiane Praza uu_die(gettext("Constructed property name is %u characters " 24601f6eb021SLiane Praza "too long for value \"%s\" in the %s service.\n"), 24611f6eb021SLiane Praza extra, value_name, service->sc_name); 24621f6eb021SLiane Praza } 24631f6eb021SLiane Praza if ((extra = snprintf(common_name_fmt, max_scf_name_len + 1, 24641f6eb021SLiane Praza VALUE_COMMON_NAME_FMT, SCF_PROPERTY_TM_VALUE_PREFIX, 24651f6eb021SLiane Praza encoded_value)) >= max_scf_name_len + 1) { 24661f6eb021SLiane Praza extra = encoded_count_to_plain(extra - max_scf_name_len); 24671f6eb021SLiane Praza uu_die(gettext("Name attribute is " 24681f6eb021SLiane Praza "%u characters too long for %s in service %s\n"), 24691f6eb021SLiane Praza extra, (char *)value->name, service->sc_name); 24701f6eb021SLiane Praza } 24711f6eb021SLiane Praza if ((extra = snprintf(description_fmt, max_scf_name_len + 1, 24721f6eb021SLiane Praza VALUE_DESCRIPTION_FMT, SCF_PROPERTY_TM_VALUE_PREFIX, 24731f6eb021SLiane Praza encoded_value)) >= max_scf_name_len + 1) { 24741f6eb021SLiane Praza extra = encoded_count_to_plain(extra - max_scf_name_len); 24751f6eb021SLiane Praza uu_die(gettext("Name attribute is " 24761f6eb021SLiane Praza "%u characters too long for %s in service %s\n"), 24771f6eb021SLiane Praza extra, (char *)value->name, service->sc_name); 24781f6eb021SLiane Praza } 24791f6eb021SLiane Praza 24801f6eb021SLiane Praza for (cursor = value->xmlChildrenNode; 24811f6eb021SLiane Praza cursor != NULL; 24821f6eb021SLiane Praza cursor = cursor->next) { 24831f6eb021SLiane Praza if (lxml_ignorable_block(cursor)) 24841f6eb021SLiane Praza continue; 24851f6eb021SLiane Praza switch (lxml_xlate_element(cursor->name)) { 24861f6eb021SLiane Praza case SC_COMMON_NAME: 24871f6eb021SLiane Praza r = lxml_get_all_loctext(service, pg, cursor, 24881f6eb021SLiane Praza common_name_fmt, (const char *)cursor->name); 24891f6eb021SLiane Praza break; 24901f6eb021SLiane Praza case SC_DESCRIPTION: 24911f6eb021SLiane Praza r = lxml_get_all_loctext(service, pg, cursor, 24921f6eb021SLiane Praza description_fmt, (const char *)cursor->name); 24931f6eb021SLiane Praza break; 24941f6eb021SLiane Praza default: 24951f6eb021SLiane Praza uu_die(gettext("\"%s\" is an illegal element in %s " 24961f6eb021SLiane Praza "of service %s\n"), (char *)cursor->name, 24971f6eb021SLiane Praza (char *)value->name, service->sc_name); 24981f6eb021SLiane Praza } 24991f6eb021SLiane Praza if (r != 0) 25001f6eb021SLiane Praza break; 25011f6eb021SLiane Praza } 25021f6eb021SLiane Praza 25031f6eb021SLiane Praza free(description_fmt); 25041f6eb021SLiane Praza free(common_name_fmt); 25051f6eb021SLiane Praza if (r == 0) { 25061f6eb021SLiane Praza *name_value = safe_strdup(value_name); 25071f6eb021SLiane Praza } 25081f6eb021SLiane Praza xmlFree(value_name); 25091f6eb021SLiane Praza free(encoded_value); 25101f6eb021SLiane Praza return (r); 25111f6eb021SLiane Praza } 25121f6eb021SLiane Praza 25131f6eb021SLiane Praza static int 25141f6eb021SLiane Praza lxml_get_tm_choices(entity_t *service, pgroup_t *pg, xmlNodePtr choices) 25151f6eb021SLiane Praza { 25161f6eb021SLiane Praza xmlNodePtr cursor; 25171f6eb021SLiane Praza char *name_value; 25181f6eb021SLiane Praza property_t *name_prop = NULL; 25191f6eb021SLiane Praza int r = 0; 25201f6eb021SLiane Praza 25211f6eb021SLiane Praza for (cursor = choices->xmlChildrenNode; 25221f6eb021SLiane Praza (cursor != NULL) && (r == 0); 25231f6eb021SLiane Praza cursor = cursor->next) { 25241f6eb021SLiane Praza if (lxml_ignorable_block(cursor)) 25251f6eb021SLiane Praza continue; 25261f6eb021SLiane Praza switch (lxml_xlate_element(cursor->name)) { 25271f6eb021SLiane Praza case SC_INCLUDE_VALUES: 25281f6eb021SLiane Praza (void) lxml_get_tm_include_values(service, pg, cursor, 25291f6eb021SLiane Praza SCF_PROPERTY_TM_CHOICES_INCLUDE_VALUES); 25301f6eb021SLiane Praza break; 25311f6eb021SLiane Praza case SC_RANGE: 25321f6eb021SLiane Praza r = lxml_get_tm_range(service, pg, cursor, 25331f6eb021SLiane Praza SCF_PROPERTY_TM_CHOICES_RANGE); 25341f6eb021SLiane Praza if (r != 0) 25351f6eb021SLiane Praza goto out; 25361f6eb021SLiane Praza break; 25371f6eb021SLiane Praza case SC_VALUE: 25381f6eb021SLiane Praza r = lxml_get_tm_value_element(service, pg, cursor, 25391f6eb021SLiane Praza &name_value); 25401f6eb021SLiane Praza if (r == 0) { 25411f6eb021SLiane Praza /* 25421f6eb021SLiane Praza * There is no need to free the memory 25431f6eb021SLiane Praza * associated with name_value, because the 25441f6eb021SLiane Praza * property value will end up pointing to 25451f6eb021SLiane Praza * the memory. 25461f6eb021SLiane Praza */ 25471f6eb021SLiane Praza astring_prop_value(&name_prop, 25481f6eb021SLiane Praza SCF_PROPERTY_TM_CHOICES_NAME, name_value, 25491f6eb021SLiane Praza B_TRUE); 25501f6eb021SLiane Praza } else { 25511f6eb021SLiane Praza goto out; 25521f6eb021SLiane Praza } 25531f6eb021SLiane Praza break; 25541f6eb021SLiane Praza default: 25551f6eb021SLiane Praza uu_die(gettext("%s is an invalid element of " 25561f6eb021SLiane Praza "choices for service %s.\n"), cursor->name, 25571f6eb021SLiane Praza service->sc_name); 25581f6eb021SLiane Praza } 25591f6eb021SLiane Praza } 25601f6eb021SLiane Praza 25611f6eb021SLiane Praza out: 25621f6eb021SLiane Praza /* Attach the name property if we created one. */ 25631f6eb021SLiane Praza if ((r == 0) && (name_prop != NULL)) { 25641f6eb021SLiane Praza r = internal_attach_property(pg, name_prop); 25651f6eb021SLiane Praza } 25661f6eb021SLiane Praza if ((r != 0) && (name_prop != NULL)) { 25671f6eb021SLiane Praza internal_property_free(name_prop); 25681f6eb021SLiane Praza } 25691f6eb021SLiane Praza 25701f6eb021SLiane Praza return (r); 25711f6eb021SLiane Praza } 25721f6eb021SLiane Praza 25731f6eb021SLiane Praza static int 25741f6eb021SLiane Praza lxml_get_tm_constraints(entity_t *service, pgroup_t *pg, xmlNodePtr constraints) 25751f6eb021SLiane Praza { 25761f6eb021SLiane Praza xmlNodePtr cursor; 25771f6eb021SLiane Praza char *name_value; 25781f6eb021SLiane Praza property_t *name_prop = NULL; 25791f6eb021SLiane Praza int r = 0; 25801f6eb021SLiane Praza 25811f6eb021SLiane Praza for (cursor = constraints->xmlChildrenNode; 25821f6eb021SLiane Praza (cursor != NULL) && (r == 0); 25831f6eb021SLiane Praza cursor = cursor->next) { 25841f6eb021SLiane Praza if (lxml_ignorable_block(cursor)) 25851f6eb021SLiane Praza continue; 25861f6eb021SLiane Praza switch (lxml_xlate_element(cursor->name)) { 25871f6eb021SLiane Praza case SC_RANGE: 25881f6eb021SLiane Praza r = lxml_get_tm_range(service, pg, cursor, 25891f6eb021SLiane Praza SCF_PROPERTY_TM_CONSTRAINT_RANGE); 25901f6eb021SLiane Praza if (r != 0) 25911f6eb021SLiane Praza goto out; 25921f6eb021SLiane Praza break; 25931f6eb021SLiane Praza case SC_VALUE: 25941f6eb021SLiane Praza r = lxml_get_tm_value_element(service, pg, cursor, 25951f6eb021SLiane Praza &name_value); 25961f6eb021SLiane Praza if (r == 0) { 25971f6eb021SLiane Praza /* 25981f6eb021SLiane Praza * There is no need to free the memory 25991f6eb021SLiane Praza * associated with name_value, because the 26001f6eb021SLiane Praza * property value will end up pointing to 26011f6eb021SLiane Praza * the memory. 26021f6eb021SLiane Praza */ 26031f6eb021SLiane Praza astring_prop_value(&name_prop, 26041f6eb021SLiane Praza SCF_PROPERTY_TM_CONSTRAINT_NAME, name_value, 26051f6eb021SLiane Praza B_TRUE); 26061f6eb021SLiane Praza } else { 26071f6eb021SLiane Praza goto out; 26081f6eb021SLiane Praza } 26091f6eb021SLiane Praza break; 26101f6eb021SLiane Praza default: 26111f6eb021SLiane Praza uu_die(gettext("%s is an invalid element of " 26121f6eb021SLiane Praza "constraints for service %s.\n"), cursor->name, 26131f6eb021SLiane Praza service->sc_name); 26141f6eb021SLiane Praza } 26151f6eb021SLiane Praza } 26161f6eb021SLiane Praza 26171f6eb021SLiane Praza out: 26181f6eb021SLiane Praza /* Attach the name property if we created one. */ 26191f6eb021SLiane Praza if ((r == 0) && (name_prop != NULL)) { 26201f6eb021SLiane Praza r = internal_attach_property(pg, name_prop); 26211f6eb021SLiane Praza } 26221f6eb021SLiane Praza if ((r != 0) && (name_prop != NULL)) { 26231f6eb021SLiane Praza internal_property_free(name_prop); 26241f6eb021SLiane Praza } 26251f6eb021SLiane Praza 26261f6eb021SLiane Praza return (r); 26271f6eb021SLiane Praza } 26281f6eb021SLiane Praza 26291f6eb021SLiane Praza /* 26301f6eb021SLiane Praza * The values element contains one or more value elements. 26311f6eb021SLiane Praza */ 26321f6eb021SLiane Praza static int 26331f6eb021SLiane Praza lxml_get_tm_values(entity_t *service, pgroup_t *pg, xmlNodePtr values) 26341f6eb021SLiane Praza { 26351f6eb021SLiane Praza xmlNodePtr cursor; 26361f6eb021SLiane Praza char *name_value; 26371f6eb021SLiane Praza property_t *name_prop = NULL; 26381f6eb021SLiane Praza int r = 0; 26391f6eb021SLiane Praza 26401f6eb021SLiane Praza for (cursor = values->xmlChildrenNode; 26411f6eb021SLiane Praza (cursor != NULL) && (r == 0); 26421f6eb021SLiane Praza cursor = cursor->next) { 26431f6eb021SLiane Praza if (lxml_ignorable_block(cursor)) 26441f6eb021SLiane Praza continue; 26451f6eb021SLiane Praza if (lxml_xlate_element(cursor->name) != SC_VALUE) { 26461f6eb021SLiane Praza uu_die(gettext("\"%s\" is an illegal element in the " 26471f6eb021SLiane Praza "%s element of %s\n"), (char *)cursor->name, 26481f6eb021SLiane Praza (char *)values->name, service->sc_name); 26491f6eb021SLiane Praza } 26501f6eb021SLiane Praza r = lxml_get_tm_value_element(service, pg, cursor, &name_value); 26511f6eb021SLiane Praza if (r == 0) { 26521f6eb021SLiane Praza /* 26531f6eb021SLiane Praza * There is no need to free the memory 26541f6eb021SLiane Praza * associated with name_value, because the 26551f6eb021SLiane Praza * property value will end up pointing to 26561f6eb021SLiane Praza * the memory. 26571f6eb021SLiane Praza */ 26581f6eb021SLiane Praza astring_prop_value(&name_prop, 26591f6eb021SLiane Praza SCF_PROPERTY_TM_VALUES_NAME, name_value, 26601f6eb021SLiane Praza B_TRUE); 26611f6eb021SLiane Praza } 26621f6eb021SLiane Praza } 26631f6eb021SLiane Praza 26641f6eb021SLiane Praza /* Attach the name property if we created one. */ 26651f6eb021SLiane Praza if ((r == 0) && (name_prop != NULL)) { 26661f6eb021SLiane Praza r = internal_attach_property(pg, name_prop); 26671f6eb021SLiane Praza } 26681f6eb021SLiane Praza if ((r != 0) && (name_prop != NULL)) { 26691f6eb021SLiane Praza internal_property_free(name_prop); 26701f6eb021SLiane Praza } 26711f6eb021SLiane Praza 26721f6eb021SLiane Praza return (r); 26731f6eb021SLiane Praza } 26741f6eb021SLiane Praza 26751f6eb021SLiane Praza /* 26761f6eb021SLiane Praza * This function processes a prop_pattern element within a pg_pattern XML 26771f6eb021SLiane Praza * element. First it creates a property group to hold the prop_pattern 26781f6eb021SLiane Praza * information. The name of this property group is the concatenation of: 26791f6eb021SLiane Praza * - SCF_PG_TM_PROP_PATTERN_PREFIX 26801f6eb021SLiane Praza * - The unique part of the property group name of the enclosing 26811f6eb021SLiane Praza * pg_pattern. The property group name of the enclosing pg_pattern 26821f6eb021SLiane Praza * is passed to us in pgpat_name. The unique part, is the part 26831f6eb021SLiane Praza * following SCF_PG_TM_PG_PATTERN_PREFIX. 26841f6eb021SLiane Praza * - The name of this prop_pattern element. 26851f6eb021SLiane Praza * 26861f6eb021SLiane Praza * After creating the property group, the prop_pattern attributes are saved 26871f6eb021SLiane Praza * as properties in the PG. Finally, the prop_pattern elements are 26881f6eb021SLiane Praza * processed and added to the PG. 26891f6eb021SLiane Praza */ 26901f6eb021SLiane Praza static int 26911f6eb021SLiane Praza lxml_get_tm_prop_pattern(entity_t *service, xmlNodePtr prop_pattern, 26921f6eb021SLiane Praza const char *pgpat_name) 26931f6eb021SLiane Praza { 26941f6eb021SLiane Praza xmlNodePtr cursor; 26951f6eb021SLiane Praza int extra; 26961f6eb021SLiane Praza pgroup_t *pg; 26971f6eb021SLiane Praza property_t *p; 26981f6eb021SLiane Praza char *pg_name; 26991f6eb021SLiane Praza size_t prefix_len; 27001f6eb021SLiane Praza xmlChar *prop_pattern_name; 27011f6eb021SLiane Praza int r; 27021f6eb021SLiane Praza const char *unique; 27031f6eb021SLiane Praza value_t *v; 27041f6eb021SLiane Praza 27051f6eb021SLiane Praza /* Find the unique part of the pg_pattern property group name. */ 27061f6eb021SLiane Praza prefix_len = strlen(SCF_PG_TM_PG_PAT_BASE); 27071f6eb021SLiane Praza assert(strncmp(pgpat_name, SCF_PG_TM_PG_PAT_BASE, prefix_len) == 0); 27081f6eb021SLiane Praza unique = pgpat_name + prefix_len; 27091f6eb021SLiane Praza 27101f6eb021SLiane Praza /* 27111f6eb021SLiane Praza * We need to get the value of the name attribute first. The 27121f6eb021SLiane Praza * prop_pattern name as well as the name of the enclosing 27131f6eb021SLiane Praza * pg_pattern both constitute part of the name of the property 27141f6eb021SLiane Praza * group that we will create. 27151f6eb021SLiane Praza */ 27161f6eb021SLiane Praza prop_pattern_name = xmlGetProp(prop_pattern, (xmlChar *)name_attr); 27171f6eb021SLiane Praza if ((prop_pattern_name == NULL) || (*prop_pattern_name == 0)) { 27181f6eb021SLiane Praza semerr(gettext("prop_pattern name is missing for %s\n"), 27191f6eb021SLiane Praza service->sc_name); 27201f6eb021SLiane Praza return (-1); 27211f6eb021SLiane Praza } 27221f6eb021SLiane Praza if (uu_check_name((const char *)prop_pattern_name, 27231f6eb021SLiane Praza UU_NAME_DOMAIN) != 0) { 27241f6eb021SLiane Praza semerr(gettext("prop_pattern name, \"%s\", for %s is not " 27251f6eb021SLiane Praza "valid.\n"), prop_pattern_name, service->sc_name); 27261f6eb021SLiane Praza xmlFree(prop_pattern_name); 27271f6eb021SLiane Praza return (-1); 27281f6eb021SLiane Praza } 27291f6eb021SLiane Praza pg_name = safe_malloc(max_scf_name_len + 1); 27301f6eb021SLiane Praza if ((extra = snprintf(pg_name, max_scf_name_len + 1, "%s%s_%s", 27311f6eb021SLiane Praza SCF_PG_TM_PROP_PATTERN_PREFIX, unique, 27321f6eb021SLiane Praza (char *)prop_pattern_name)) >= max_scf_name_len + 1) { 27331f6eb021SLiane Praza uu_die(gettext("prop_pattern name, \"%s\", for %s is %d " 27341f6eb021SLiane Praza "characters too long\n"), (char *)prop_pattern_name, 27351f6eb021SLiane Praza service->sc_name, extra - max_scf_name_len); 27361f6eb021SLiane Praza } 27371f6eb021SLiane Praza 27381f6eb021SLiane Praza /* 27391f6eb021SLiane Praza * Create the property group, the property referencing the pg_pattern 27401f6eb021SLiane Praza * name, and add the prop_pattern attributes to the property group. 27411f6eb021SLiane Praza */ 27421f6eb021SLiane Praza pg = internal_pgroup_create_strict(service, pg_name, 27431f6eb021SLiane Praza SCF_GROUP_TEMPLATE_PROP_PATTERN); 27441f6eb021SLiane Praza if (pg == NULL) { 27451f6eb021SLiane Praza uu_die(gettext("Property group for prop_pattern, \"%s\", " 27461f6eb021SLiane Praza "already exists in %s\n"), prop_pattern_name, 27471f6eb021SLiane Praza service->sc_name); 27481f6eb021SLiane Praza } 27491f6eb021SLiane Praza 27501f6eb021SLiane Praza p = internal_property_create(SCF_PROPERTY_TM_PG_PATTERN, 27511f6eb021SLiane Praza SCF_TYPE_ASTRING, 1, safe_strdup(pgpat_name)); 27521f6eb021SLiane Praza /* 27531f6eb021SLiane Praza * Unfortunately, internal_property_create() does not set the free 27541f6eb021SLiane Praza * function for the value, so we'll set it now. 27551f6eb021SLiane Praza */ 27561f6eb021SLiane Praza v = uu_list_first(p->sc_property_values); 27571f6eb021SLiane Praza v->sc_free = lxml_free_str; 27581f6eb021SLiane Praza if (internal_attach_property(pg, p) != 0) 27591f6eb021SLiane Praza internal_property_free(p); 27601f6eb021SLiane Praza 27611f6eb021SLiane Praza 27621f6eb021SLiane Praza r = lxml_get_prop_pattern_attributes(pg, prop_pattern); 27631f6eb021SLiane Praza if (r != 0) 27641f6eb021SLiane Praza goto out; 27651f6eb021SLiane Praza 27661f6eb021SLiane Praza /* 27671f6eb021SLiane Praza * Now process the elements of prop_pattern 27681f6eb021SLiane Praza */ 27691f6eb021SLiane Praza for (cursor = prop_pattern->xmlChildrenNode; 27701f6eb021SLiane Praza cursor != NULL; 27711f6eb021SLiane Praza cursor = cursor->next) { 27721f6eb021SLiane Praza if (lxml_ignorable_block(cursor)) 27731f6eb021SLiane Praza continue; 27741f6eb021SLiane Praza 27751f6eb021SLiane Praza switch (lxml_xlate_element(cursor->name)) { 27761f6eb021SLiane Praza case SC_CARDINALITY: 27771f6eb021SLiane Praza r = lxml_get_tm_cardinality(service, pg, cursor); 27781f6eb021SLiane Praza if (r != 0) 27791f6eb021SLiane Praza goto out; 27801f6eb021SLiane Praza break; 27811f6eb021SLiane Praza case SC_CHOICES: 27821f6eb021SLiane Praza r = lxml_get_tm_choices(service, pg, cursor); 27831f6eb021SLiane Praza if (r != 0) 27841f6eb021SLiane Praza goto out; 27851f6eb021SLiane Praza break; 27861f6eb021SLiane Praza case SC_COMMON_NAME: 27871f6eb021SLiane Praza (void) lxml_get_all_loctext(service, pg, cursor, 27881f6eb021SLiane Praza COMMON_NAME_FMT, (const char *)cursor->name); 27891f6eb021SLiane Praza break; 27901f6eb021SLiane Praza case SC_CONSTRAINTS: 27911f6eb021SLiane Praza r = lxml_get_tm_constraints(service, pg, cursor); 27921f6eb021SLiane Praza if (r != 0) 27931f6eb021SLiane Praza goto out; 27941f6eb021SLiane Praza break; 27951f6eb021SLiane Praza case SC_DESCRIPTION: 27961f6eb021SLiane Praza (void) lxml_get_all_loctext(service, pg, cursor, 27971f6eb021SLiane Praza DESCRIPTION_FMT, (const char *)cursor->name); 27981f6eb021SLiane Praza break; 27991f6eb021SLiane Praza case SC_INTERNAL_SEPARATORS: 28001f6eb021SLiane Praza r = lxml_get_tm_internal_seps(service, pg, cursor); 28011f6eb021SLiane Praza if (r != 0) 28021f6eb021SLiane Praza goto out; 28031f6eb021SLiane Praza break; 28041f6eb021SLiane Praza case SC_UNITS: 28051f6eb021SLiane Praza (void) lxml_get_all_loctext(service, pg, cursor, 28061f6eb021SLiane Praza UNITS_FMT, "units"); 28071f6eb021SLiane Praza break; 28081f6eb021SLiane Praza case SC_VALUES: 28091f6eb021SLiane Praza (void) lxml_get_tm_values(service, pg, cursor); 28101f6eb021SLiane Praza break; 28111f6eb021SLiane Praza case SC_VISIBILITY: 28121f6eb021SLiane Praza /* 28131f6eb021SLiane Praza * The visibility element is empty, so we only need 28141f6eb021SLiane Praza * to proccess the value attribute. 28151f6eb021SLiane Praza */ 28161f6eb021SLiane Praza (void) new_str_prop_from_attr(pg, 28171f6eb021SLiane Praza SCF_PROPERTY_TM_VISIBILITY, SCF_TYPE_ASTRING, 28181f6eb021SLiane Praza cursor, value_attr); 28191f6eb021SLiane Praza break; 28201f6eb021SLiane Praza default: 28211f6eb021SLiane Praza uu_die(gettext("illegal element \"%s\" in prop_pattern " 28221f6eb021SLiane Praza "for service \"%s\"\n"), cursor->name, 28231f6eb021SLiane Praza service->sc_name); 28241f6eb021SLiane Praza } 28251f6eb021SLiane Praza } 28261f6eb021SLiane Praza 28271f6eb021SLiane Praza out: 28281f6eb021SLiane Praza xmlFree(prop_pattern_name); 28291f6eb021SLiane Praza free(pg_name); 28301f6eb021SLiane Praza return (r); 28311f6eb021SLiane Praza } 28321f6eb021SLiane Praza 28331f6eb021SLiane Praza /* 28341f6eb021SLiane Praza * Get the pg_pattern attributes and save them as properties in the 28351f6eb021SLiane Praza * property group at pg. The pg_pattern element accepts four attributes -- 28361f6eb021SLiane Praza * name, type, required and target. 28371f6eb021SLiane Praza */ 28381f6eb021SLiane Praza static int 28391f6eb021SLiane Praza lxml_get_pg_pattern_attributes(pgroup_t *pg, xmlNodePtr cursor) 28401f6eb021SLiane Praza { 28411f6eb021SLiane Praza if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_TM_NAME, 28421f6eb021SLiane Praza SCF_TYPE_ASTRING, cursor, name_attr, NULL) != 0) { 28431f6eb021SLiane Praza return (-1); 28441f6eb021SLiane Praza } 28451f6eb021SLiane Praza if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_TM_TYPE, 28461f6eb021SLiane Praza SCF_TYPE_ASTRING, cursor, type_attr, NULL) != 0) { 28471f6eb021SLiane Praza return (-1); 28481f6eb021SLiane Praza } 28491f6eb021SLiane Praza if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_TM_TARGET, 28501f6eb021SLiane Praza SCF_TYPE_ASTRING, cursor, target_attr, NULL) != 0) { 28511f6eb021SLiane Praza return (-1); 28521f6eb021SLiane Praza } 28531f6eb021SLiane Praza if (new_bool_prop_from_attr(pg, SCF_PROPERTY_TM_REQUIRED, cursor, 28541f6eb021SLiane Praza required_attr) != 0) 28551f6eb021SLiane Praza return (-1); 28561f6eb021SLiane Praza return (0); 28571f6eb021SLiane Praza } 28581f6eb021SLiane Praza 28591f6eb021SLiane Praza /* 28601f6eb021SLiane Praza * There are several restrictions on the pg_pattern attributes that cannot 28611f6eb021SLiane Praza * be specifed in the service bundle DTD. This function verifies that 28621f6eb021SLiane Praza * those restrictions have been satisfied. The restrictions are: 28631f6eb021SLiane Praza * 28641f6eb021SLiane Praza * - The target attribute may have a value of "instance" only when the 28651f6eb021SLiane Praza * template block is in a service declaration. 28661f6eb021SLiane Praza * 28671f6eb021SLiane Praza * - The target attribute may have a value of "delegate" only when the 28681f6eb021SLiane Praza * template block applies to a restarter. 28691f6eb021SLiane Praza * 28701f6eb021SLiane Praza * - The target attribute may have a value of "all" only when the 28711f6eb021SLiane Praza * template block applies to the master restarter. 28721f6eb021SLiane Praza * 28731f6eb021SLiane Praza * The function returns 0 on success and -1 on failure. 28741f6eb021SLiane Praza */ 28751f6eb021SLiane Praza static int 28761f6eb021SLiane Praza verify_pg_pattern_attributes(entity_t *s, pgroup_t *pg) 28771f6eb021SLiane Praza { 28781f6eb021SLiane Praza int is_restarter; 28791f6eb021SLiane Praza property_t *target; 28801f6eb021SLiane Praza value_t *v; 28811f6eb021SLiane Praza 28821f6eb021SLiane Praza /* Find the value of the target property. */ 28831f6eb021SLiane Praza target = internal_property_find(pg, SCF_PROPERTY_TM_TARGET); 28841f6eb021SLiane Praza if (target == NULL) { 28851f6eb021SLiane Praza uu_die(gettext("pg_pattern is missing the %s attribute " 28861f6eb021SLiane Praza "in %s\n"), target_attr, s->sc_name); 28871f6eb021SLiane Praza return (-1); 28881f6eb021SLiane Praza } 28891f6eb021SLiane Praza v = uu_list_first(target->sc_property_values); 28901f6eb021SLiane Praza assert(v != NULL); 28911f6eb021SLiane Praza assert(v->sc_type == SCF_TYPE_ASTRING); 28921f6eb021SLiane Praza 28931f6eb021SLiane Praza /* 28941f6eb021SLiane Praza * If target has a value of instance, the template must be in a 28951f6eb021SLiane Praza * service object. 28961f6eb021SLiane Praza */ 28971f6eb021SLiane Praza if (strcmp(v->sc_u.sc_string, "instance") == 0) { 28981f6eb021SLiane Praza if (s->sc_etype != SVCCFG_SERVICE_OBJECT) { 28991f6eb021SLiane Praza uu_warn(gettext("pg_pattern %s attribute may only " 29001f6eb021SLiane Praza "have a value of \"instance\" when it is in a " 29011f6eb021SLiane Praza "service declaration.\n"), target_attr); 29021f6eb021SLiane Praza return (-1); 29031f6eb021SLiane Praza } 29041f6eb021SLiane Praza } 29051f6eb021SLiane Praza 29061f6eb021SLiane Praza /* 29071f6eb021SLiane Praza * If target has a value of "delegate", the template must be in a 29081f6eb021SLiane Praza * restarter. 29091f6eb021SLiane Praza */ 29101f6eb021SLiane Praza if (strcmp(v->sc_u.sc_string, "delegate") == 0) { 29111f6eb021SLiane Praza is_restarter = 0; 29121f6eb021SLiane Praza if ((s->sc_etype == SVCCFG_SERVICE_OBJECT) && 29131f6eb021SLiane Praza (s->sc_u.sc_service.sc_service_type == SVCCFG_RESTARTER)) { 29141f6eb021SLiane Praza is_restarter = 1; 29151f6eb021SLiane Praza } 29161f6eb021SLiane Praza if ((s->sc_etype == SVCCFG_INSTANCE_OBJECT) && 29171f6eb021SLiane Praza (s->sc_parent->sc_u.sc_service.sc_service_type == 29181f6eb021SLiane Praza SVCCFG_RESTARTER)) { 29191f6eb021SLiane Praza is_restarter = 1; 29201f6eb021SLiane Praza } 29211f6eb021SLiane Praza if (is_restarter == 0) { 29221f6eb021SLiane Praza uu_warn(gettext("pg_pattern %s attribute has a " 29231f6eb021SLiane Praza "value of \"delegate\" but is not in a " 29241f6eb021SLiane Praza "restarter service\n"), target_attr); 29251f6eb021SLiane Praza return (-1); 29261f6eb021SLiane Praza } 29271f6eb021SLiane Praza } 29281f6eb021SLiane Praza 29291f6eb021SLiane Praza /* 29301f6eb021SLiane Praza * If target has a value of "all", the template must be in the 29311f6eb021SLiane Praza * global (SCF_SERVICE_GLOBAL) service. 29321f6eb021SLiane Praza */ 29331f6eb021SLiane Praza if (strcmp(v->sc_u.sc_string, all_value) == 0) { 29341f6eb021SLiane Praza if (s->sc_etype != SVCCFG_SERVICE_OBJECT) { 29351f6eb021SLiane Praza uu_warn(gettext("pg_pattern %s attribute has a " 29361f6eb021SLiane Praza "value of \"%s\" but is not in a " 29371f6eb021SLiane Praza "service entity.\n"), target_attr, all_value); 29381f6eb021SLiane Praza return (-1); 29391f6eb021SLiane Praza } 29401f6eb021SLiane Praza if (strcmp(s->sc_fmri, SCF_SERVICE_GLOBAL) != 0) { 29411f6eb021SLiane Praza uu_warn(gettext("pg_pattern %s attribute has a " 29421f6eb021SLiane Praza "value of \"%s\" but is in the \"%s\" service. " 29431f6eb021SLiane Praza "pg_patterns with target \"%s\" are only allowed " 29441f6eb021SLiane Praza "in the global service.\n"), 29451f6eb021SLiane Praza target_attr, all_value, s->sc_fmri, all_value); 29461f6eb021SLiane Praza return (-1); 29471f6eb021SLiane Praza } 29481f6eb021SLiane Praza } 29491f6eb021SLiane Praza 29501f6eb021SLiane Praza return (0); 29511f6eb021SLiane Praza } 29521f6eb021SLiane Praza 29531f6eb021SLiane Praza static int 29541f6eb021SLiane Praza lxml_get_tm_pg_pattern(entity_t *service, xmlNodePtr pg_pattern) 29551f6eb021SLiane Praza { 29561f6eb021SLiane Praza xmlNodePtr cursor; 29571f6eb021SLiane Praza int out_len; 29581f6eb021SLiane Praza xmlChar *name; 29591f6eb021SLiane Praza pgroup_t *pg = NULL; 29601f6eb021SLiane Praza char *pg_name; 29611f6eb021SLiane Praza int r = -1; 29621f6eb021SLiane Praza xmlChar *type; 29631f6eb021SLiane Praza 29641f6eb021SLiane Praza pg_name = safe_malloc(max_scf_name_len + 1); 29651f6eb021SLiane Praza 29661f6eb021SLiane Praza /* 29671f6eb021SLiane Praza * Get the name and type attributes. Their presence or absence 29681f6eb021SLiane Praza * determines whcih prefix we will use for the property group name. 29691f6eb021SLiane Praza * There are four cases -- neither attribute is present, both are 29701f6eb021SLiane Praza * present, only name is present or only type is present. 29711f6eb021SLiane Praza */ 29721f6eb021SLiane Praza name = xmlGetProp(pg_pattern, (xmlChar *)name_attr); 29731f6eb021SLiane Praza type = xmlGetProp(pg_pattern, (xmlChar *)type_attr); 29741f6eb021SLiane Praza if ((name == NULL) || (*name == 0)) { 29751f6eb021SLiane Praza if ((type == NULL) || (*type == 0)) { 29761f6eb021SLiane Praza /* PG name contains only the prefix in this case */ 29771f6eb021SLiane Praza if (strlcpy(pg_name, SCF_PG_TM_PG_PATTERN_PREFIX, 29781f6eb021SLiane Praza max_scf_name_len + 1) >= max_scf_name_len + 1) { 29791f6eb021SLiane Praza uu_die(gettext("Unable to create pg_pattern " 29801f6eb021SLiane Praza "property for %s\n"), service->sc_name); 29811f6eb021SLiane Praza } 29821f6eb021SLiane Praza } else { 29831f6eb021SLiane Praza /* 29841f6eb021SLiane Praza * If we have a type and no name, the type becomes 29851f6eb021SLiane Praza * part of the pg_pattern property group name. 29861f6eb021SLiane Praza */ 29871f6eb021SLiane Praza if ((out_len = snprintf(pg_name, max_scf_name_len + 1, 29881f6eb021SLiane Praza "%s%s", SCF_PG_TM_PG_PATTERN_T_PREFIX, type)) >= 29891f6eb021SLiane Praza max_scf_name_len + 1) { 29901f6eb021SLiane Praza uu_die(gettext("pg_pattern type is for %s is " 29911f6eb021SLiane Praza "%d bytes too long\n"), service->sc_name, 29921f6eb021SLiane Praza out_len - max_scf_name_len); 29931f6eb021SLiane Praza } 29941f6eb021SLiane Praza } 29951f6eb021SLiane Praza } else { 29961f6eb021SLiane Praza const char *prefix; 29971f6eb021SLiane Praza 29981f6eb021SLiane Praza /* Make sure that the name is valid. */ 29991f6eb021SLiane Praza if (uu_check_name((const char *)name, UU_NAME_DOMAIN) != 0) { 30001f6eb021SLiane Praza semerr(gettext("pg_pattern name attribute, \"%s\", " 30011f6eb021SLiane Praza "for %s is invalid\n"), name, service->sc_name); 30021f6eb021SLiane Praza goto out; 30031f6eb021SLiane Praza } 30041f6eb021SLiane Praza 30051f6eb021SLiane Praza /* 30061f6eb021SLiane Praza * As long as the pg_pattern has a name, it becomes part of 30071f6eb021SLiane Praza * the name of the pg_pattern property group name. We 30081f6eb021SLiane Praza * merely need to pick the appropriate prefix. 30091f6eb021SLiane Praza */ 30101f6eb021SLiane Praza if ((type == NULL) || (*type == 0)) { 30111f6eb021SLiane Praza prefix = SCF_PG_TM_PG_PATTERN_N_PREFIX; 30121f6eb021SLiane Praza } else { 30131f6eb021SLiane Praza prefix = SCF_PG_TM_PG_PATTERN_NT_PREFIX; 30141f6eb021SLiane Praza } 30151f6eb021SLiane Praza if ((out_len = snprintf(pg_name, max_scf_name_len + 1, "%s%s", 30161f6eb021SLiane Praza prefix, name)) >= max_scf_name_len + 1) { 30171f6eb021SLiane Praza uu_die(gettext("pg_pattern property group name " 30181f6eb021SLiane Praza "for %s is %d bytes too long\n"), service->sc_name, 30191f6eb021SLiane Praza out_len - max_scf_name_len); 30201f6eb021SLiane Praza } 30211f6eb021SLiane Praza } 30221f6eb021SLiane Praza 30231f6eb021SLiane Praza /* 30241f6eb021SLiane Praza * Create the property group for holding this pg_pattern 30251f6eb021SLiane Praza * information, and capture the pg_pattern attributes. 30261f6eb021SLiane Praza */ 30271f6eb021SLiane Praza pg = internal_pgroup_create_strict(service, pg_name, 30281f6eb021SLiane Praza SCF_GROUP_TEMPLATE_PG_PATTERN); 30291f6eb021SLiane Praza if (pg == NULL) { 30301f6eb021SLiane Praza if ((name == NULL) || (*name == 0)) { 30311f6eb021SLiane Praza if ((type == NULL) ||(*type == 0)) { 30321f6eb021SLiane Praza semerr(gettext("pg_pattern with empty name and " 30331f6eb021SLiane Praza "type is not unique in %s\n"), 30341f6eb021SLiane Praza service->sc_name); 30351f6eb021SLiane Praza } else { 30361f6eb021SLiane Praza semerr(gettext("pg_pattern with empty name and " 30371f6eb021SLiane Praza "type \"%s\" is not unique in %s\n"), 30381f6eb021SLiane Praza type, service->sc_name); 30391f6eb021SLiane Praza } 30401f6eb021SLiane Praza } else { 30411f6eb021SLiane Praza if ((type == NULL) || (*type == 0)) { 30421f6eb021SLiane Praza semerr(gettext("pg_pattern with name \"%s\" " 30431f6eb021SLiane Praza "and empty type is not unique in %s\n"), 30441f6eb021SLiane Praza name, service->sc_name); 30451f6eb021SLiane Praza } else { 30461f6eb021SLiane Praza semerr(gettext("pg_pattern with name \"%s\" " 30471f6eb021SLiane Praza "and type \"%s\" is not unique in %s\n"), 30481f6eb021SLiane Praza name, type, service->sc_name); 30491f6eb021SLiane Praza } 30501f6eb021SLiane Praza } 30511f6eb021SLiane Praza goto out; 30521f6eb021SLiane Praza } 30531f6eb021SLiane Praza 30541f6eb021SLiane Praza /* 30551f6eb021SLiane Praza * Get the pg_pattern attributes from the manifest and verify 30561f6eb021SLiane Praza * that they satisfy our restrictions. 30571f6eb021SLiane Praza */ 30581f6eb021SLiane Praza r = lxml_get_pg_pattern_attributes(pg, pg_pattern); 30591f6eb021SLiane Praza if (r != 0) 30601f6eb021SLiane Praza goto out; 30611f6eb021SLiane Praza if (verify_pg_pattern_attributes(service, pg) != 0) { 30621f6eb021SLiane Praza semerr(gettext("Invalid pg_pattern attributes in %s\n"), 30631f6eb021SLiane Praza service->sc_name); 30641f6eb021SLiane Praza r = -1; 30651f6eb021SLiane Praza goto out; 30661f6eb021SLiane Praza } 30671f6eb021SLiane Praza 30681f6eb021SLiane Praza /* 30691f6eb021SLiane Praza * Now process all of the elements of pg_pattern. 30701f6eb021SLiane Praza */ 30711f6eb021SLiane Praza for (cursor = pg_pattern->xmlChildrenNode; 30721f6eb021SLiane Praza cursor != NULL; 30731f6eb021SLiane Praza cursor = cursor->next) { 30741f6eb021SLiane Praza if (lxml_ignorable_block(cursor)) 30751f6eb021SLiane Praza continue; 30761f6eb021SLiane Praza 30771f6eb021SLiane Praza switch (lxml_xlate_element(cursor->name)) { 30781f6eb021SLiane Praza case SC_COMMON_NAME: 30791f6eb021SLiane Praza (void) lxml_get_all_loctext(service, pg, cursor, 30801f6eb021SLiane Praza COMMON_NAME_FMT, (const char *)cursor->name); 30811f6eb021SLiane Praza break; 30821f6eb021SLiane Praza case SC_DESCRIPTION: 30831f6eb021SLiane Praza (void) lxml_get_all_loctext(service, pg, cursor, 30841f6eb021SLiane Praza DESCRIPTION_FMT, (const char *)cursor->name); 30851f6eb021SLiane Praza break; 30861f6eb021SLiane Praza case SC_PROP_PATTERN: 30871f6eb021SLiane Praza r = lxml_get_tm_prop_pattern(service, cursor, 30881f6eb021SLiane Praza pg_name); 30891f6eb021SLiane Praza if (r != 0) 30901f6eb021SLiane Praza goto out; 30911f6eb021SLiane Praza break; 30921f6eb021SLiane Praza default: 30931f6eb021SLiane Praza uu_die(gettext("illegal element \"%s\" in pg_pattern " 30941f6eb021SLiane Praza "for service \"%s\"\n"), cursor->name, 30951f6eb021SLiane Praza service->sc_name); 30961f6eb021SLiane Praza } 30971f6eb021SLiane Praza } 30981f6eb021SLiane Praza 30991f6eb021SLiane Praza out: 31001f6eb021SLiane Praza if ((r != 0) && (pg != NULL)) { 31011f6eb021SLiane Praza internal_detach_pgroup(service, pg); 31021f6eb021SLiane Praza internal_pgroup_free(pg); 31031f6eb021SLiane Praza } 31041f6eb021SLiane Praza free(pg_name); 31051f6eb021SLiane Praza xmlFree(name); 31061f6eb021SLiane Praza xmlFree(type); 31071f6eb021SLiane Praza 31081f6eb021SLiane Praza return (r); 31091f6eb021SLiane Praza } 31101f6eb021SLiane Praza 31111f6eb021SLiane Praza static int 31127c478bd9Sstevel@tonic-gate lxml_get_template(entity_t *service, xmlNodePtr templ) 31137c478bd9Sstevel@tonic-gate { 31147c478bd9Sstevel@tonic-gate xmlNodePtr cursor; 31157c478bd9Sstevel@tonic-gate 31167c478bd9Sstevel@tonic-gate for (cursor = templ->xmlChildrenNode; cursor != NULL; 31177c478bd9Sstevel@tonic-gate cursor = cursor->next) { 31187c478bd9Sstevel@tonic-gate if (lxml_ignorable_block(cursor)) 31197c478bd9Sstevel@tonic-gate continue; 31207c478bd9Sstevel@tonic-gate 31217c478bd9Sstevel@tonic-gate switch (lxml_xlate_element(cursor->name)) { 31227c478bd9Sstevel@tonic-gate case SC_COMMON_NAME: 31237c478bd9Sstevel@tonic-gate (void) lxml_get_tm_common_name(service, cursor); 31247c478bd9Sstevel@tonic-gate break; 31257c478bd9Sstevel@tonic-gate case SC_DESCRIPTION: 31267c478bd9Sstevel@tonic-gate (void) lxml_get_tm_description(service, cursor); 31277c478bd9Sstevel@tonic-gate break; 31287c478bd9Sstevel@tonic-gate case SC_DOCUMENTATION: 31297c478bd9Sstevel@tonic-gate (void) lxml_get_tm_documentation(service, cursor); 31307c478bd9Sstevel@tonic-gate break; 31311f6eb021SLiane Praza case SC_PG_PATTERN: 31321f6eb021SLiane Praza if (lxml_get_tm_pg_pattern(service, cursor) != 0) 31331f6eb021SLiane Praza return (-1); 31341f6eb021SLiane Praza break; 31357c478bd9Sstevel@tonic-gate default: 31367c478bd9Sstevel@tonic-gate uu_die(gettext("illegal element \"%s\" on template " 31377c478bd9Sstevel@tonic-gate "for service \"%s\"\n"), 31387c478bd9Sstevel@tonic-gate cursor->name, service->sc_name); 31397c478bd9Sstevel@tonic-gate } 31407c478bd9Sstevel@tonic-gate } 31417c478bd9Sstevel@tonic-gate 31427c478bd9Sstevel@tonic-gate return (0); 31437c478bd9Sstevel@tonic-gate } 31447c478bd9Sstevel@tonic-gate 31457c478bd9Sstevel@tonic-gate static int 31467c478bd9Sstevel@tonic-gate lxml_get_default_instance(entity_t *service, xmlNodePtr definst) 31477c478bd9Sstevel@tonic-gate { 31487c478bd9Sstevel@tonic-gate entity_t *i; 31497c478bd9Sstevel@tonic-gate xmlChar *enabled; 31507c478bd9Sstevel@tonic-gate pgroup_t *pg; 31517c478bd9Sstevel@tonic-gate property_t *p; 31527c478bd9Sstevel@tonic-gate char *package; 31537c478bd9Sstevel@tonic-gate uint64_t enabled_val = 0; 31547c478bd9Sstevel@tonic-gate 31557c478bd9Sstevel@tonic-gate i = internal_instance_new("default"); 31567c478bd9Sstevel@tonic-gate 31577c478bd9Sstevel@tonic-gate if ((enabled = xmlGetProp(definst, (xmlChar *)enabled_attr)) != NULL) { 31587c478bd9Sstevel@tonic-gate enabled_val = (strcmp(true, (const char *)enabled) == 0) ? 31597c478bd9Sstevel@tonic-gate 1 : 0; 31607c478bd9Sstevel@tonic-gate xmlFree(enabled); 31617c478bd9Sstevel@tonic-gate } 31627c478bd9Sstevel@tonic-gate 31637c478bd9Sstevel@tonic-gate /* 31647c478bd9Sstevel@tonic-gate * New general property group with enabled boolean property set. 31657c478bd9Sstevel@tonic-gate */ 31667c478bd9Sstevel@tonic-gate 3167f329b923SSean Wilcox i->sc_op = service->sc_op; 31687c478bd9Sstevel@tonic-gate pg = internal_pgroup_new(); 31697c478bd9Sstevel@tonic-gate (void) internal_attach_pgroup(i, pg); 31707c478bd9Sstevel@tonic-gate 31717c478bd9Sstevel@tonic-gate pg->sc_pgroup_name = (char *)scf_pg_general; 31727c478bd9Sstevel@tonic-gate pg->sc_pgroup_type = (char *)scf_group_framework; 31737c478bd9Sstevel@tonic-gate pg->sc_pgroup_flags = 0; 31747c478bd9Sstevel@tonic-gate 31757c478bd9Sstevel@tonic-gate p = internal_property_create(SCF_PROPERTY_ENABLED, SCF_TYPE_BOOLEAN, 1, 31767c478bd9Sstevel@tonic-gate enabled_val); 31777c478bd9Sstevel@tonic-gate 31787c478bd9Sstevel@tonic-gate (void) internal_attach_property(pg, p); 31797c478bd9Sstevel@tonic-gate 31807c478bd9Sstevel@tonic-gate /* 31817c478bd9Sstevel@tonic-gate * Add general/package property if PKGINST is set. 31827c478bd9Sstevel@tonic-gate */ 31837c478bd9Sstevel@tonic-gate if ((package = getenv("PKGINST")) != NULL) { 31847c478bd9Sstevel@tonic-gate p = internal_property_create(SCF_PROPERTY_PACKAGE, 31857c478bd9Sstevel@tonic-gate SCF_TYPE_ASTRING, 1, package); 31867c478bd9Sstevel@tonic-gate 31877c478bd9Sstevel@tonic-gate (void) internal_attach_property(pg, p); 31887c478bd9Sstevel@tonic-gate } 31897c478bd9Sstevel@tonic-gate 31907c478bd9Sstevel@tonic-gate return (internal_attach_entity(service, i)); 31917c478bd9Sstevel@tonic-gate } 31927c478bd9Sstevel@tonic-gate 31937c478bd9Sstevel@tonic-gate /* 31947c478bd9Sstevel@tonic-gate * Translate an instance element into an internal property tree, added to 3195687293e1SAntonello Cruz * service. If op is SVCCFG_OP_APPLY (i.e., apply a profile), set the 3196687293e1SAntonello Cruz * enabled property to override. 3197f329b923SSean Wilcox * 3198f329b923SSean Wilcox * If op is SVCCFG_OP_APPLY (i.e., apply a profile), do not allow for 3199f329b923SSean Wilcox * modification of template data. 32007c478bd9Sstevel@tonic-gate */ 32017c478bd9Sstevel@tonic-gate static int 3202687293e1SAntonello Cruz lxml_get_instance(entity_t *service, xmlNodePtr inst, bundle_type_t bt, 3203687293e1SAntonello Cruz svccfg_op_t op) 32047c478bd9Sstevel@tonic-gate { 32057c478bd9Sstevel@tonic-gate entity_t *i; 32067c478bd9Sstevel@tonic-gate pgroup_t *pg; 32077c478bd9Sstevel@tonic-gate property_t *p; 32087c478bd9Sstevel@tonic-gate xmlNodePtr cursor; 32097c478bd9Sstevel@tonic-gate xmlChar *enabled; 3210687293e1SAntonello Cruz int r, e_val; 32117c478bd9Sstevel@tonic-gate 32127c478bd9Sstevel@tonic-gate /* 32137c478bd9Sstevel@tonic-gate * Fetch its attributes, as appropriate. 32147c478bd9Sstevel@tonic-gate */ 32157c478bd9Sstevel@tonic-gate i = internal_instance_new((char *)xmlGetProp(inst, 32167c478bd9Sstevel@tonic-gate (xmlChar *)name_attr)); 32177c478bd9Sstevel@tonic-gate 32187c478bd9Sstevel@tonic-gate /* 32197c478bd9Sstevel@tonic-gate * Note that this must be done before walking the children so that 32207c478bd9Sstevel@tonic-gate * sc_fmri is set in case we enter lxml_get_dependent(). 32217c478bd9Sstevel@tonic-gate */ 32227c478bd9Sstevel@tonic-gate r = internal_attach_entity(service, i); 32237c478bd9Sstevel@tonic-gate if (r != 0) 32247c478bd9Sstevel@tonic-gate return (r); 32257c478bd9Sstevel@tonic-gate 3226f329b923SSean Wilcox i->sc_op = op; 32277c478bd9Sstevel@tonic-gate enabled = xmlGetProp(inst, (xmlChar *)enabled_attr); 32287c478bd9Sstevel@tonic-gate 3229687293e1SAntonello Cruz if (enabled == NULL) { 3230687293e1SAntonello Cruz if (bt == SVCCFG_MANIFEST) { 3231687293e1SAntonello Cruz semerr(gettext("Instance \"%s\" missing attribute " 3232687293e1SAntonello Cruz "\"%s\".\n"), i->sc_name, enabled_attr); 3233687293e1SAntonello Cruz return (-1); 3234687293e1SAntonello Cruz } 3235687293e1SAntonello Cruz } else { /* enabled != NULL */ 3236687293e1SAntonello Cruz if (strcmp(true, (const char *)enabled) != 0 && 3237687293e1SAntonello Cruz strcmp(false, (const char *)enabled) != 0) { 3238687293e1SAntonello Cruz xmlFree(enabled); 3239687293e1SAntonello Cruz semerr(gettext("Invalid enabled value\n")); 3240687293e1SAntonello Cruz return (-1); 3241687293e1SAntonello Cruz } 32427c478bd9Sstevel@tonic-gate pg = internal_pgroup_new(); 32437c478bd9Sstevel@tonic-gate (void) internal_attach_pgroup(i, pg); 32447c478bd9Sstevel@tonic-gate 32457c478bd9Sstevel@tonic-gate pg->sc_pgroup_name = (char *)scf_pg_general; 32467c478bd9Sstevel@tonic-gate pg->sc_pgroup_type = (char *)scf_group_framework; 32477c478bd9Sstevel@tonic-gate pg->sc_pgroup_flags = 0; 32487c478bd9Sstevel@tonic-gate 3249687293e1SAntonello Cruz e_val = (strcmp(true, (const char *)enabled) == 0); 3250687293e1SAntonello Cruz p = internal_property_create(SCF_PROPERTY_ENABLED, 3251687293e1SAntonello Cruz SCF_TYPE_BOOLEAN, 1, (uint64_t)e_val); 32527c478bd9Sstevel@tonic-gate 32533eae19d9Swesolows p->sc_property_override = (op == SVCCFG_OP_APPLY); 32547c478bd9Sstevel@tonic-gate 32557c478bd9Sstevel@tonic-gate (void) internal_attach_property(pg, p); 32567c478bd9Sstevel@tonic-gate 32577c478bd9Sstevel@tonic-gate xmlFree(enabled); 3258687293e1SAntonello Cruz } 32597c478bd9Sstevel@tonic-gate 32607c478bd9Sstevel@tonic-gate /* 32617c478bd9Sstevel@tonic-gate * Walk its child elements, as appropriate. 32627c478bd9Sstevel@tonic-gate */ 32637c478bd9Sstevel@tonic-gate for (cursor = inst->xmlChildrenNode; cursor != NULL; 32647c478bd9Sstevel@tonic-gate cursor = cursor->next) { 32657c478bd9Sstevel@tonic-gate if (lxml_ignorable_block(cursor)) 32667c478bd9Sstevel@tonic-gate continue; 32677c478bd9Sstevel@tonic-gate 32687c478bd9Sstevel@tonic-gate switch (lxml_xlate_element(cursor->name)) { 32697c478bd9Sstevel@tonic-gate case SC_RESTARTER: 32707c478bd9Sstevel@tonic-gate (void) lxml_get_restarter(i, cursor); 32717c478bd9Sstevel@tonic-gate break; 32727c478bd9Sstevel@tonic-gate case SC_DEPENDENCY: 32737c478bd9Sstevel@tonic-gate (void) lxml_get_dependency(i, cursor); 32747c478bd9Sstevel@tonic-gate break; 32757c478bd9Sstevel@tonic-gate case SC_DEPENDENT: 32767c478bd9Sstevel@tonic-gate (void) lxml_get_dependent(i, cursor); 32777c478bd9Sstevel@tonic-gate break; 32787c478bd9Sstevel@tonic-gate case SC_METHOD_CONTEXT: 32797c478bd9Sstevel@tonic-gate (void) lxml_get_entity_method_context(i, cursor); 32807c478bd9Sstevel@tonic-gate break; 32817c478bd9Sstevel@tonic-gate case SC_EXEC_METHOD: 32827c478bd9Sstevel@tonic-gate (void) lxml_get_exec_method(i, cursor); 32837c478bd9Sstevel@tonic-gate break; 32847c478bd9Sstevel@tonic-gate case SC_PROPERTY_GROUP: 32857c478bd9Sstevel@tonic-gate (void) lxml_get_pgroup(i, cursor); 32867c478bd9Sstevel@tonic-gate break; 32877c478bd9Sstevel@tonic-gate case SC_TEMPLATE: 3288f329b923SSean Wilcox if (op == SVCCFG_OP_APPLY) { 3289f329b923SSean Wilcox semerr(gettext("Template data for \"%s\" may " 3290f329b923SSean Wilcox "not be modified in a profile.\n"), 3291f329b923SSean Wilcox i->sc_name); 3292f329b923SSean Wilcox 3293f329b923SSean Wilcox return (-1); 3294f329b923SSean Wilcox } 3295f329b923SSean Wilcox 32961f6eb021SLiane Praza if (lxml_get_template(i, cursor) != 0) 32971f6eb021SLiane Praza return (-1); 32987c478bd9Sstevel@tonic-gate break; 3299f6e214c7SGavin Maltby case SC_NOTIFICATION_PARAMETERS: 3300f6e214c7SGavin Maltby if (lxml_get_notification_parameters(i, cursor) != 0) 3301f6e214c7SGavin Maltby return (-1); 3302f6e214c7SGavin Maltby break; 33037c478bd9Sstevel@tonic-gate default: 33047c478bd9Sstevel@tonic-gate uu_die(gettext( 33057c478bd9Sstevel@tonic-gate "illegal element \"%s\" on instance \"%s\"\n"), 33067c478bd9Sstevel@tonic-gate cursor->name, i->sc_name); 33077c478bd9Sstevel@tonic-gate break; 33087c478bd9Sstevel@tonic-gate } 33097c478bd9Sstevel@tonic-gate } 33107c478bd9Sstevel@tonic-gate 33117c478bd9Sstevel@tonic-gate return (0); 33127c478bd9Sstevel@tonic-gate } 33137c478bd9Sstevel@tonic-gate 33147c478bd9Sstevel@tonic-gate /* ARGSUSED1 */ 33157c478bd9Sstevel@tonic-gate static int 33167c478bd9Sstevel@tonic-gate lxml_get_single_instance(entity_t *entity, xmlNodePtr si) 33177c478bd9Sstevel@tonic-gate { 33187c478bd9Sstevel@tonic-gate pgroup_t *pg; 33197c478bd9Sstevel@tonic-gate property_t *p; 33207c478bd9Sstevel@tonic-gate int r; 33217c478bd9Sstevel@tonic-gate 33227c478bd9Sstevel@tonic-gate pg = internal_pgroup_find_or_create(entity, (char *)scf_pg_general, 33237c478bd9Sstevel@tonic-gate (char *)scf_group_framework); 33247c478bd9Sstevel@tonic-gate 33257c478bd9Sstevel@tonic-gate p = internal_property_create(SCF_PROPERTY_SINGLE_INSTANCE, 33267c478bd9Sstevel@tonic-gate SCF_TYPE_BOOLEAN, 1, (uint64_t)1); 33277c478bd9Sstevel@tonic-gate 33287c478bd9Sstevel@tonic-gate r = internal_attach_property(pg, p); 33297c478bd9Sstevel@tonic-gate if (r != 0) { 33307c478bd9Sstevel@tonic-gate internal_property_free(p); 33317c478bd9Sstevel@tonic-gate return (-1); 33327c478bd9Sstevel@tonic-gate } 33337c478bd9Sstevel@tonic-gate 33347c478bd9Sstevel@tonic-gate return (0); 33357c478bd9Sstevel@tonic-gate } 33367c478bd9Sstevel@tonic-gate 33377c478bd9Sstevel@tonic-gate /* 33389444c26fSTom Whitten * Check to see if the service should allow the upgrade 33399444c26fSTom Whitten * process to handle adding of the manifestfiles linkage. 33409444c26fSTom Whitten * 33419444c26fSTom Whitten * If the service exists and does not have a manifestfiles 33429444c26fSTom Whitten * property group then the upgrade process should handle 33439444c26fSTom Whitten * the service. 33449444c26fSTom Whitten * 33459444c26fSTom Whitten * If the service doesn't exist or the service exists 33469444c26fSTom Whitten * and has a manifestfiles property group then the import 33479444c26fSTom Whitten * process can handle the manifestfiles property group 33489444c26fSTom Whitten * work. 33499444c26fSTom Whitten * 33509444c26fSTom Whitten * This prevents potential cleanup of unaccounted for instances 33519444c26fSTom Whitten * in early manifest import due to upgrade process needing 33529444c26fSTom Whitten * information that has not yet been supplied by manifests 33539444c26fSTom Whitten * that are still located in the /var/svc manifests directory. 33549444c26fSTom Whitten */ 33559444c26fSTom Whitten static int 33569444c26fSTom Whitten lxml_check_upgrade(const char *service) { 33579444c26fSTom Whitten scf_handle_t *h = NULL; 33589444c26fSTom Whitten scf_scope_t *sc = NULL; 33599444c26fSTom Whitten scf_service_t *svc = NULL; 33609444c26fSTom Whitten scf_propertygroup_t *pg = NULL; 33619444c26fSTom Whitten int rc = SCF_FAILED; 33629444c26fSTom Whitten 33639444c26fSTom Whitten if ((h = scf_handle_create(SCF_VERSION)) == NULL || 33649444c26fSTom Whitten (sc = scf_scope_create(h)) == NULL || 33659444c26fSTom Whitten (svc = scf_service_create(h)) == NULL || 33669444c26fSTom Whitten (pg = scf_pg_create(h)) == NULL) 33679444c26fSTom Whitten goto out; 33689444c26fSTom Whitten 33699444c26fSTom Whitten if (scf_handle_bind(h) != 0) 33709444c26fSTom Whitten goto out; 33719444c26fSTom Whitten 33729444c26fSTom Whitten if (scf_handle_get_scope(h, SCF_FMRI_LOCAL_SCOPE, sc) == -1) 33739444c26fSTom Whitten goto out; 33749444c26fSTom Whitten 33759444c26fSTom Whitten if (scf_scope_get_service(sc, service, svc) != SCF_SUCCESS) { 33769444c26fSTom Whitten if (scf_error() == SCF_ERROR_NOT_FOUND) 33779444c26fSTom Whitten rc = SCF_SUCCESS; 33789444c26fSTom Whitten 33799444c26fSTom Whitten goto out; 33809444c26fSTom Whitten } 33819444c26fSTom Whitten 33829444c26fSTom Whitten if (scf_service_get_pg(svc, SCF_PG_MANIFESTFILES, pg) != SCF_SUCCESS) 33839444c26fSTom Whitten goto out; 33849444c26fSTom Whitten 33859444c26fSTom Whitten rc = SCF_SUCCESS; 33869444c26fSTom Whitten out: 33879444c26fSTom Whitten scf_pg_destroy(pg); 33889444c26fSTom Whitten scf_service_destroy(svc); 33899444c26fSTom Whitten scf_scope_destroy(sc); 33909444c26fSTom Whitten scf_handle_destroy(h); 33919444c26fSTom Whitten 33929444c26fSTom Whitten return (rc); 33939444c26fSTom Whitten } 33949444c26fSTom Whitten 33959444c26fSTom Whitten /* 33967c478bd9Sstevel@tonic-gate * Translate a service element into an internal instance/property tree, added 3397f329b923SSean Wilcox * to bundle. 3398f329b923SSean Wilcox * 3399f329b923SSean Wilcox * If op is SVCCFG_OP_APPLY (i.e., apply a profile), do not allow for 3400f329b923SSean Wilcox * modification of template data. 34017c478bd9Sstevel@tonic-gate */ 34027c478bd9Sstevel@tonic-gate static int 34033eae19d9Swesolows lxml_get_service(bundle_t *bundle, xmlNodePtr svc, svccfg_op_t op) 34047c478bd9Sstevel@tonic-gate { 340523294c7dSSean Wilcox pgroup_t *pg; 340623294c7dSSean Wilcox property_t *p; 34077c478bd9Sstevel@tonic-gate entity_t *s; 34087c478bd9Sstevel@tonic-gate xmlNodePtr cursor; 34097c478bd9Sstevel@tonic-gate xmlChar *type; 34107c478bd9Sstevel@tonic-gate xmlChar *version; 34117c478bd9Sstevel@tonic-gate int e; 34127c478bd9Sstevel@tonic-gate 34137c478bd9Sstevel@tonic-gate /* 34147c478bd9Sstevel@tonic-gate * Fetch attributes, as appropriate. 34157c478bd9Sstevel@tonic-gate */ 34167c478bd9Sstevel@tonic-gate s = internal_service_new((char *)xmlGetProp(svc, 34177c478bd9Sstevel@tonic-gate (xmlChar *)name_attr)); 34187c478bd9Sstevel@tonic-gate 34191f6eb021SLiane Praza version = xmlGetProp(svc, (xmlChar *)version_attr); 34207c478bd9Sstevel@tonic-gate s->sc_u.sc_service.sc_service_version = atol((const char *)version); 34217c478bd9Sstevel@tonic-gate xmlFree(version); 34227c478bd9Sstevel@tonic-gate 34237c478bd9Sstevel@tonic-gate type = xmlGetProp(svc, (xmlChar *)type_attr); 34247c478bd9Sstevel@tonic-gate s->sc_u.sc_service.sc_service_type = lxml_xlate_service_type(type); 34257c478bd9Sstevel@tonic-gate xmlFree(type); 34267c478bd9Sstevel@tonic-gate 34277c478bd9Sstevel@tonic-gate /* 3428f329b923SSean Wilcox * Set the global missing type to false before processing the service 3429f329b923SSean Wilcox */ 3430f329b923SSean Wilcox est->sc_miss_type = B_FALSE; 3431f329b923SSean Wilcox s->sc_op = op; 3432f329b923SSean Wilcox 3433f329b923SSean Wilcox /* 343423294c7dSSean Wilcox * Now that the service is created create the manifest 343523294c7dSSean Wilcox * property group and add the property value of the service. 343623294c7dSSean Wilcox */ 34379444c26fSTom Whitten if (lxml_check_upgrade(s->sc_name) == SCF_SUCCESS && 34389444c26fSTom Whitten svc->doc->name != NULL && 343923294c7dSSean Wilcox bundle->sc_bundle_type == SVCCFG_MANIFEST) { 344085bcc4e5SSean Wilcox char *buf, *base, *fname, *bname; 344185bcc4e5SSean Wilcox size_t base_sz = 0; 344285bcc4e5SSean Wilcox 344385bcc4e5SSean Wilcox /* 344485bcc4e5SSean Wilcox * Must remove the PKG_INSTALL_ROOT, point to the correct 344585bcc4e5SSean Wilcox * directory after install 344685bcc4e5SSean Wilcox */ 344785bcc4e5SSean Wilcox bname = uu_zalloc(PATH_MAX + 1); 344885bcc4e5SSean Wilcox if (realpath(svc->doc->name, bname) == NULL) { 344985bcc4e5SSean Wilcox uu_die(gettext("Unable to create the real path of the " 345085bcc4e5SSean Wilcox "manifest file \"%s\" : %d\n"), svc->doc->name, 345185bcc4e5SSean Wilcox errno); 345285bcc4e5SSean Wilcox } 345385bcc4e5SSean Wilcox 345485bcc4e5SSean Wilcox base = getenv("PKG_INSTALL_ROOT"); 345585bcc4e5SSean Wilcox if (base != NULL && strncmp(bname, base, strlen(base)) == 0) { 345685bcc4e5SSean Wilcox base_sz = strlen(base); 345785bcc4e5SSean Wilcox } 345885bcc4e5SSean Wilcox fname = safe_strdup(bname + base_sz); 345985bcc4e5SSean Wilcox 346085bcc4e5SSean Wilcox uu_free(bname); 346185bcc4e5SSean Wilcox buf = mhash_filename_to_propname(svc->doc->name, B_FALSE); 346223294c7dSSean Wilcox 346323294c7dSSean Wilcox pg = internal_pgroup_create_strict(s, SCF_PG_MANIFESTFILES, 346423294c7dSSean Wilcox SCF_GROUP_FRAMEWORK); 346523294c7dSSean Wilcox 346623294c7dSSean Wilcox if (pg == NULL) { 346723294c7dSSean Wilcox uu_die(gettext("Property group for prop_pattern, " 346823294c7dSSean Wilcox "\"%s\", already exists in %s\n"), 346923294c7dSSean Wilcox SCF_PG_MANIFESTFILES, s->sc_name); 347023294c7dSSean Wilcox } 347123294c7dSSean Wilcox 347223294c7dSSean Wilcox p = internal_property_create(buf, SCF_TYPE_ASTRING, 1, fname); 347323294c7dSSean Wilcox 347423294c7dSSean Wilcox (void) internal_attach_property(pg, p); 347523294c7dSSean Wilcox } 347623294c7dSSean Wilcox 347723294c7dSSean Wilcox /* 34787c478bd9Sstevel@tonic-gate * Walk its child elements, as appropriate. 34797c478bd9Sstevel@tonic-gate */ 34807c478bd9Sstevel@tonic-gate for (cursor = svc->xmlChildrenNode; cursor != NULL; 34817c478bd9Sstevel@tonic-gate cursor = cursor->next) { 34827c478bd9Sstevel@tonic-gate if (lxml_ignorable_block(cursor)) 34837c478bd9Sstevel@tonic-gate continue; 34847c478bd9Sstevel@tonic-gate 34857c478bd9Sstevel@tonic-gate e = lxml_xlate_element(cursor->name); 34867c478bd9Sstevel@tonic-gate 34877c478bd9Sstevel@tonic-gate switch (e) { 34887c478bd9Sstevel@tonic-gate case SC_INSTANCE: 3489687293e1SAntonello Cruz if (lxml_get_instance(s, cursor, 3490687293e1SAntonello Cruz bundle->sc_bundle_type, op) != 0) 34911f6eb021SLiane Praza return (-1); 34927c478bd9Sstevel@tonic-gate break; 34937c478bd9Sstevel@tonic-gate case SC_TEMPLATE: 3494f329b923SSean Wilcox if (op == SVCCFG_OP_APPLY) { 3495f329b923SSean Wilcox semerr(gettext("Template data for \"%s\" may " 3496f329b923SSean Wilcox "not be modified in a profile.\n"), 3497f329b923SSean Wilcox s->sc_name); 3498f329b923SSean Wilcox 3499f329b923SSean Wilcox return (-1); 3500f329b923SSean Wilcox } 3501f329b923SSean Wilcox 35021f6eb021SLiane Praza if (lxml_get_template(s, cursor) != 0) 35031f6eb021SLiane Praza return (-1); 35047c478bd9Sstevel@tonic-gate break; 3505f6e214c7SGavin Maltby case SC_NOTIFICATION_PARAMETERS: 3506f6e214c7SGavin Maltby if (lxml_get_notification_parameters(s, cursor) != 0) 3507f6e214c7SGavin Maltby return (-1); 3508f6e214c7SGavin Maltby break; 35097c478bd9Sstevel@tonic-gate case SC_STABILITY: 35107c478bd9Sstevel@tonic-gate (void) lxml_get_entity_stability(s, cursor); 35117c478bd9Sstevel@tonic-gate break; 35127c478bd9Sstevel@tonic-gate case SC_DEPENDENCY: 35137c478bd9Sstevel@tonic-gate (void) lxml_get_dependency(s, cursor); 35147c478bd9Sstevel@tonic-gate break; 35157c478bd9Sstevel@tonic-gate case SC_DEPENDENT: 35167c478bd9Sstevel@tonic-gate (void) lxml_get_dependent(s, cursor); 35177c478bd9Sstevel@tonic-gate break; 35187c478bd9Sstevel@tonic-gate case SC_RESTARTER: 35197c478bd9Sstevel@tonic-gate (void) lxml_get_restarter(s, cursor); 35207c478bd9Sstevel@tonic-gate break; 35217c478bd9Sstevel@tonic-gate case SC_EXEC_METHOD: 35227c478bd9Sstevel@tonic-gate (void) lxml_get_exec_method(s, cursor); 35237c478bd9Sstevel@tonic-gate break; 35247c478bd9Sstevel@tonic-gate case SC_METHOD_CONTEXT: 35257c478bd9Sstevel@tonic-gate (void) lxml_get_entity_method_context(s, cursor); 35267c478bd9Sstevel@tonic-gate break; 35277c478bd9Sstevel@tonic-gate case SC_PROPERTY_GROUP: 35287c478bd9Sstevel@tonic-gate (void) lxml_get_pgroup(s, cursor); 35297c478bd9Sstevel@tonic-gate break; 35307c478bd9Sstevel@tonic-gate case SC_INSTANCE_CREATE_DEFAULT: 35317c478bd9Sstevel@tonic-gate (void) lxml_get_default_instance(s, cursor); 35327c478bd9Sstevel@tonic-gate break; 35337c478bd9Sstevel@tonic-gate case SC_INSTANCE_SINGLE: 35347c478bd9Sstevel@tonic-gate (void) lxml_get_single_instance(s, cursor); 35357c478bd9Sstevel@tonic-gate break; 35367c478bd9Sstevel@tonic-gate default: 35377c478bd9Sstevel@tonic-gate uu_die(gettext( 35387c478bd9Sstevel@tonic-gate "illegal element \"%s\" on service \"%s\"\n"), 35397c478bd9Sstevel@tonic-gate cursor->name, s->sc_name); 35407c478bd9Sstevel@tonic-gate break; 35417c478bd9Sstevel@tonic-gate } 35427c478bd9Sstevel@tonic-gate } 35437c478bd9Sstevel@tonic-gate 3544f329b923SSean Wilcox /* 3545f329b923SSean Wilcox * Now that the service has been processed set the missing type 3546f329b923SSean Wilcox * for the service. So that only the services with missing 3547f329b923SSean Wilcox * types are processed. 3548f329b923SSean Wilcox */ 3549f329b923SSean Wilcox s->sc_miss_type = est->sc_miss_type; 3550f329b923SSean Wilcox if (est->sc_miss_type) 3551f329b923SSean Wilcox est->sc_miss_type = B_FALSE; 3552f329b923SSean Wilcox 35537c478bd9Sstevel@tonic-gate return (internal_attach_service(bundle, s)); 35547c478bd9Sstevel@tonic-gate } 35557c478bd9Sstevel@tonic-gate 35567c478bd9Sstevel@tonic-gate #ifdef DEBUG 35577c478bd9Sstevel@tonic-gate void 35587c478bd9Sstevel@tonic-gate lxml_dump(int g, xmlNodePtr p) 35597c478bd9Sstevel@tonic-gate { 35607c478bd9Sstevel@tonic-gate if (p && p->name) { 3561f329b923SSean Wilcox (void) printf("%d %s\n", g, p->name); 35627c478bd9Sstevel@tonic-gate 35637c478bd9Sstevel@tonic-gate for (p = p->xmlChildrenNode; p != NULL; p = p->next) 35647c478bd9Sstevel@tonic-gate lxml_dump(g + 1, p); 35657c478bd9Sstevel@tonic-gate } 35667c478bd9Sstevel@tonic-gate } 35677c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 35687c478bd9Sstevel@tonic-gate 35697c478bd9Sstevel@tonic-gate static int 35707c478bd9Sstevel@tonic-gate lxml_is_known_dtd(const xmlChar *dtdname) 35717c478bd9Sstevel@tonic-gate { 35727c478bd9Sstevel@tonic-gate if (dtdname == NULL || 35737c478bd9Sstevel@tonic-gate strcmp(MANIFEST_DTD_PATH, (const char *)dtdname) != 0) 35747c478bd9Sstevel@tonic-gate return (0); 35757c478bd9Sstevel@tonic-gate 35767c478bd9Sstevel@tonic-gate return (1); 35777c478bd9Sstevel@tonic-gate } 35787c478bd9Sstevel@tonic-gate 35797c478bd9Sstevel@tonic-gate static int 35807c478bd9Sstevel@tonic-gate lxml_get_bundle(bundle_t *bundle, bundle_type_t bundle_type, 35813eae19d9Swesolows xmlNodePtr subbundle, svccfg_op_t op) 35827c478bd9Sstevel@tonic-gate { 35837c478bd9Sstevel@tonic-gate xmlNodePtr cursor; 35847c478bd9Sstevel@tonic-gate xmlChar *type; 35857c478bd9Sstevel@tonic-gate int e; 35867c478bd9Sstevel@tonic-gate 35877c478bd9Sstevel@tonic-gate /* 35887c478bd9Sstevel@tonic-gate * 1. Get bundle attributes. 35897c478bd9Sstevel@tonic-gate */ 35901f6eb021SLiane Praza type = xmlGetProp(subbundle, (xmlChar *)type_attr); 35917c478bd9Sstevel@tonic-gate bundle->sc_bundle_type = lxml_xlate_bundle_type(type); 35927c478bd9Sstevel@tonic-gate if (bundle->sc_bundle_type != bundle_type && 35937c478bd9Sstevel@tonic-gate bundle_type != SVCCFG_UNKNOWN_BUNDLE) { 35947c478bd9Sstevel@tonic-gate semerr(gettext("included bundle of different type.\n")); 35957c478bd9Sstevel@tonic-gate return (-1); 35967c478bd9Sstevel@tonic-gate } 35977c478bd9Sstevel@tonic-gate 35987c478bd9Sstevel@tonic-gate xmlFree(type); 35997c478bd9Sstevel@tonic-gate 36003eae19d9Swesolows switch (op) { 36013eae19d9Swesolows case SVCCFG_OP_IMPORT: 36027c478bd9Sstevel@tonic-gate if (bundle->sc_bundle_type != SVCCFG_MANIFEST) { 36037c478bd9Sstevel@tonic-gate semerr(gettext("document is not a manifest.\n")); 36047c478bd9Sstevel@tonic-gate return (-1); 36057c478bd9Sstevel@tonic-gate } 36063eae19d9Swesolows break; 36073eae19d9Swesolows case SVCCFG_OP_APPLY: 36087c478bd9Sstevel@tonic-gate if (bundle->sc_bundle_type != SVCCFG_PROFILE) { 36097c478bd9Sstevel@tonic-gate semerr(gettext("document is not a profile.\n")); 36107c478bd9Sstevel@tonic-gate return (-1); 36117c478bd9Sstevel@tonic-gate } 36123eae19d9Swesolows break; 36133eae19d9Swesolows case SVCCFG_OP_RESTORE: 36143eae19d9Swesolows if (bundle->sc_bundle_type != SVCCFG_ARCHIVE) { 36153eae19d9Swesolows semerr(gettext("document is not an archive.\n")); 36163eae19d9Swesolows return (-1); 36173eae19d9Swesolows } 36183eae19d9Swesolows break; 36197c478bd9Sstevel@tonic-gate } 36207c478bd9Sstevel@tonic-gate 36211f6eb021SLiane Praza if (((bundle->sc_bundle_name = xmlGetProp(subbundle, 36221f6eb021SLiane Praza (xmlChar *)name_attr)) == NULL) || (*bundle->sc_bundle_name == 0)) { 36237c478bd9Sstevel@tonic-gate semerr(gettext("service bundle lacks name attribute\n")); 36247c478bd9Sstevel@tonic-gate return (-1); 36257c478bd9Sstevel@tonic-gate } 36267c478bd9Sstevel@tonic-gate 36277c478bd9Sstevel@tonic-gate /* 36287c478bd9Sstevel@tonic-gate * 2. Get services, descend into each one and build state. 36297c478bd9Sstevel@tonic-gate */ 36307c478bd9Sstevel@tonic-gate for (cursor = subbundle->xmlChildrenNode; cursor != NULL; 36317c478bd9Sstevel@tonic-gate cursor = cursor->next) { 36327c478bd9Sstevel@tonic-gate if (lxml_ignorable_block(cursor)) 36337c478bd9Sstevel@tonic-gate continue; 36347c478bd9Sstevel@tonic-gate 36357c478bd9Sstevel@tonic-gate e = lxml_xlate_element(cursor->name); 36367c478bd9Sstevel@tonic-gate 36377c478bd9Sstevel@tonic-gate switch (e) { 36387c478bd9Sstevel@tonic-gate case SC_XI_INCLUDE: 36397c478bd9Sstevel@tonic-gate continue; 36407c478bd9Sstevel@tonic-gate 36417c478bd9Sstevel@tonic-gate case SC_SERVICE_BUNDLE: 36423eae19d9Swesolows if (lxml_get_bundle(bundle, bundle_type, cursor, op)) 36437c478bd9Sstevel@tonic-gate return (-1); 36447c478bd9Sstevel@tonic-gate break; 36457c478bd9Sstevel@tonic-gate case SC_SERVICE: 36461f6eb021SLiane Praza if (lxml_get_service(bundle, cursor, op) != 0) 36471f6eb021SLiane Praza return (-1); 36487c478bd9Sstevel@tonic-gate break; 36497c478bd9Sstevel@tonic-gate } 36507c478bd9Sstevel@tonic-gate } 36517c478bd9Sstevel@tonic-gate 36527c478bd9Sstevel@tonic-gate return (0); 36537c478bd9Sstevel@tonic-gate } 36547c478bd9Sstevel@tonic-gate 36557c478bd9Sstevel@tonic-gate /* 36567c478bd9Sstevel@tonic-gate * Load an XML tree from filename and translate it into an internal service 36573eae19d9Swesolows * tree bundle. Require that the bundle be of appropriate type for the 36583eae19d9Swesolows * operation: archive for RESTORE, manifest for IMPORT, profile for APPLY. 36597c478bd9Sstevel@tonic-gate */ 36607c478bd9Sstevel@tonic-gate int 36613eae19d9Swesolows lxml_get_bundle_file(bundle_t *bundle, const char *filename, svccfg_op_t op) 36627c478bd9Sstevel@tonic-gate { 36637c478bd9Sstevel@tonic-gate xmlDocPtr document; 36647c478bd9Sstevel@tonic-gate xmlNodePtr cursor; 36657c478bd9Sstevel@tonic-gate xmlDtdPtr dtd = NULL; 36667c478bd9Sstevel@tonic-gate xmlValidCtxtPtr vcp; 36677c478bd9Sstevel@tonic-gate boolean_t do_validate; 36687c478bd9Sstevel@tonic-gate char *dtdpath = NULL; 36697c478bd9Sstevel@tonic-gate int r; 36707c478bd9Sstevel@tonic-gate 36717c478bd9Sstevel@tonic-gate /* 367276cf44abSjeanm * Verify we can read the file before we try to parse it. 367376cf44abSjeanm */ 367476cf44abSjeanm if (access(filename, R_OK | F_OK) == -1) { 367576cf44abSjeanm semerr(gettext("unable to open file: %s\n"), strerror(errno)); 367676cf44abSjeanm return (-1); 367776cf44abSjeanm } 367876cf44abSjeanm 367976cf44abSjeanm /* 36807c478bd9Sstevel@tonic-gate * Until libxml2 addresses DTD-based validation with XInclude, we don't 36817c478bd9Sstevel@tonic-gate * validate service profiles (i.e. the apply path). 36827c478bd9Sstevel@tonic-gate */ 36833eae19d9Swesolows do_validate = (op != SVCCFG_OP_APPLY) && 36843eae19d9Swesolows (getenv("SVCCFG_NOVALIDATE") == NULL); 36857c478bd9Sstevel@tonic-gate if (do_validate) 36867c478bd9Sstevel@tonic-gate dtdpath = getenv("SVCCFG_DTD"); 36877c478bd9Sstevel@tonic-gate 36887c478bd9Sstevel@tonic-gate if (dtdpath != NULL) 36897c478bd9Sstevel@tonic-gate xmlLoadExtDtdDefaultValue = 0; 36907c478bd9Sstevel@tonic-gate 369176cf44abSjeanm if ((document = xmlReadFile(filename, NULL, 0)) == NULL) { 36927c478bd9Sstevel@tonic-gate semerr(gettext("couldn't parse document\n")); 36937c478bd9Sstevel@tonic-gate return (-1); 36947c478bd9Sstevel@tonic-gate } 36957c478bd9Sstevel@tonic-gate 3696*67b0e063SAlbert Lee document->name = safe_strdup(filename); 369723294c7dSSean Wilcox 36987c478bd9Sstevel@tonic-gate /* 36997c478bd9Sstevel@tonic-gate * Verify that this is a document type we understand. 37007c478bd9Sstevel@tonic-gate */ 37017c478bd9Sstevel@tonic-gate if ((dtd = xmlGetIntSubset(document)) == NULL) { 37027c478bd9Sstevel@tonic-gate semerr(gettext("document has no DTD\n")); 37037c478bd9Sstevel@tonic-gate return (-1); 3704f329b923SSean Wilcox } else if (dtdpath == NULL && !do_validate) { 3705f329b923SSean Wilcox /* 3706f329b923SSean Wilcox * If apply then setup so that some validation 3707f329b923SSean Wilcox * for specific elements can be done. 3708f329b923SSean Wilcox */ 3709f329b923SSean Wilcox dtdpath = (char *)document->intSubset->SystemID; 37107c478bd9Sstevel@tonic-gate } 37117c478bd9Sstevel@tonic-gate 37127c478bd9Sstevel@tonic-gate if (!lxml_is_known_dtd(dtd->SystemID)) { 37137c478bd9Sstevel@tonic-gate semerr(gettext("document DTD unknown; not service bundle?\n")); 37147c478bd9Sstevel@tonic-gate return (-1); 37157c478bd9Sstevel@tonic-gate } 37167c478bd9Sstevel@tonic-gate 37177c478bd9Sstevel@tonic-gate if ((cursor = xmlDocGetRootElement(document)) == NULL) { 37187c478bd9Sstevel@tonic-gate semerr(gettext("document is empty\n")); 37197c478bd9Sstevel@tonic-gate xmlFreeDoc(document); 37207c478bd9Sstevel@tonic-gate return (-1); 37217c478bd9Sstevel@tonic-gate } 37227c478bd9Sstevel@tonic-gate 37237c478bd9Sstevel@tonic-gate if (xmlStrcmp(cursor->name, (const xmlChar *)"service_bundle") != 0) { 37247c478bd9Sstevel@tonic-gate semerr(gettext("document is not a service bundle\n")); 37257c478bd9Sstevel@tonic-gate xmlFreeDoc(document); 37267c478bd9Sstevel@tonic-gate return (-1); 37277c478bd9Sstevel@tonic-gate } 37287c478bd9Sstevel@tonic-gate 37297c478bd9Sstevel@tonic-gate 37307c478bd9Sstevel@tonic-gate if (dtdpath != NULL) { 37317c478bd9Sstevel@tonic-gate dtd = xmlParseDTD(NULL, (xmlChar *)dtdpath); 37327c478bd9Sstevel@tonic-gate if (dtd == NULL) { 37337c478bd9Sstevel@tonic-gate semerr(gettext("Could not parse DTD \"%s\".\n"), 37347c478bd9Sstevel@tonic-gate dtdpath); 37357c478bd9Sstevel@tonic-gate return (-1); 37367c478bd9Sstevel@tonic-gate } 37377c478bd9Sstevel@tonic-gate 37387c478bd9Sstevel@tonic-gate if (document->extSubset != NULL) 37397c478bd9Sstevel@tonic-gate xmlFreeDtd(document->extSubset); 37407c478bd9Sstevel@tonic-gate 37417c478bd9Sstevel@tonic-gate document->extSubset = dtd; 37427c478bd9Sstevel@tonic-gate } 37437c478bd9Sstevel@tonic-gate 374476cf44abSjeanm if (xmlXIncludeProcessFlags(document, XML_PARSE_XINCLUDE) == -1) { 37457c478bd9Sstevel@tonic-gate semerr(gettext("couldn't handle XInclude statements " 37467c478bd9Sstevel@tonic-gate "in document\n")); 37477c478bd9Sstevel@tonic-gate return (-1); 37487c478bd9Sstevel@tonic-gate } 37497c478bd9Sstevel@tonic-gate 37507c478bd9Sstevel@tonic-gate if (do_validate) { 37517c478bd9Sstevel@tonic-gate vcp = xmlNewValidCtxt(); 37527c478bd9Sstevel@tonic-gate if (vcp == NULL) 37537c478bd9Sstevel@tonic-gate uu_die(gettext("could not allocate memory")); 37547c478bd9Sstevel@tonic-gate vcp->warning = xmlParserValidityWarning; 37557c478bd9Sstevel@tonic-gate vcp->error = xmlParserValidityError; 37567c478bd9Sstevel@tonic-gate 37577c478bd9Sstevel@tonic-gate r = xmlValidateDocument(vcp, document); 37587c478bd9Sstevel@tonic-gate 37597c478bd9Sstevel@tonic-gate xmlFreeValidCtxt(vcp); 37607c478bd9Sstevel@tonic-gate 37617c478bd9Sstevel@tonic-gate if (r == 0) { 37627c478bd9Sstevel@tonic-gate semerr(gettext("Document is not valid.\n")); 37637c478bd9Sstevel@tonic-gate xmlFreeDoc(document); 37647c478bd9Sstevel@tonic-gate return (-1); 37657c478bd9Sstevel@tonic-gate } 37667c478bd9Sstevel@tonic-gate } 37677c478bd9Sstevel@tonic-gate 37687c478bd9Sstevel@tonic-gate #ifdef DEBUG 37697c478bd9Sstevel@tonic-gate lxml_dump(0, cursor); 37707c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 37717c478bd9Sstevel@tonic-gate 37723eae19d9Swesolows r = lxml_get_bundle(bundle, SVCCFG_UNKNOWN_BUNDLE, cursor, op); 37737c478bd9Sstevel@tonic-gate 37747c478bd9Sstevel@tonic-gate xmlFreeDoc(document); 37757c478bd9Sstevel@tonic-gate 37767c478bd9Sstevel@tonic-gate return (r); 37777c478bd9Sstevel@tonic-gate } 37787c478bd9Sstevel@tonic-gate 37797c478bd9Sstevel@tonic-gate int 37807c478bd9Sstevel@tonic-gate lxml_inventory(const char *filename) 37817c478bd9Sstevel@tonic-gate { 37827c478bd9Sstevel@tonic-gate bundle_t *b; 37837c478bd9Sstevel@tonic-gate uu_list_walk_t *svcs, *insts; 37847c478bd9Sstevel@tonic-gate entity_t *svc, *inst; 37857c478bd9Sstevel@tonic-gate 37867c478bd9Sstevel@tonic-gate b = internal_bundle_new(); 37877c478bd9Sstevel@tonic-gate 37883eae19d9Swesolows if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) != 0) { 37897c478bd9Sstevel@tonic-gate internal_bundle_free(b); 37907c478bd9Sstevel@tonic-gate return (-1); 37917c478bd9Sstevel@tonic-gate } 37927c478bd9Sstevel@tonic-gate 37937c478bd9Sstevel@tonic-gate svcs = uu_list_walk_start(b->sc_bundle_services, 0); 37947c478bd9Sstevel@tonic-gate if (svcs == NULL) 37957c478bd9Sstevel@tonic-gate uu_die(gettext("Couldn't walk services")); 37967c478bd9Sstevel@tonic-gate 37977c478bd9Sstevel@tonic-gate while ((svc = uu_list_walk_next(svcs)) != NULL) { 37987c478bd9Sstevel@tonic-gate uu_list_t *inst_list; 37997c478bd9Sstevel@tonic-gate 38007c478bd9Sstevel@tonic-gate inst_list = svc->sc_u.sc_service.sc_service_instances; 38017c478bd9Sstevel@tonic-gate insts = uu_list_walk_start(inst_list, 0); 38027c478bd9Sstevel@tonic-gate if (insts == NULL) 38037c478bd9Sstevel@tonic-gate uu_die(gettext("Couldn't walk instances")); 38047c478bd9Sstevel@tonic-gate 38057c478bd9Sstevel@tonic-gate while ((inst = uu_list_walk_next(insts)) != NULL) 38067c478bd9Sstevel@tonic-gate (void) printf("svc:/%s:%s\n", svc->sc_name, 38077c478bd9Sstevel@tonic-gate inst->sc_name); 38087c478bd9Sstevel@tonic-gate 38097c478bd9Sstevel@tonic-gate uu_list_walk_end(insts); 38107c478bd9Sstevel@tonic-gate } 38117c478bd9Sstevel@tonic-gate 38127c478bd9Sstevel@tonic-gate uu_list_walk_end(svcs); 38137c478bd9Sstevel@tonic-gate 38147c478bd9Sstevel@tonic-gate svcs = uu_list_walk_start(b->sc_bundle_services, 0); 38157c478bd9Sstevel@tonic-gate while ((svc = uu_list_walk_next(svcs)) != NULL) { 38167c478bd9Sstevel@tonic-gate (void) fputs("svc:/", stdout); 38177c478bd9Sstevel@tonic-gate (void) puts(svc->sc_name); 38187c478bd9Sstevel@tonic-gate } 38197c478bd9Sstevel@tonic-gate uu_list_walk_end(svcs); 38207c478bd9Sstevel@tonic-gate 38217c478bd9Sstevel@tonic-gate internal_bundle_free(b); 38227c478bd9Sstevel@tonic-gate 38237c478bd9Sstevel@tonic-gate return (0); 38247c478bd9Sstevel@tonic-gate } 3825