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