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 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 220Sstevel@tonic-gate /* 230Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate #include <libxml/parser.h> 300Sstevel@tonic-gate #include <libxml/xinclude.h> 310Sstevel@tonic-gate 320Sstevel@tonic-gate #include <assert.h> 330Sstevel@tonic-gate #include <ctype.h> 340Sstevel@tonic-gate #include <errno.h> 350Sstevel@tonic-gate #include <libintl.h> 360Sstevel@tonic-gate #include <libuutil.h> 370Sstevel@tonic-gate #include <stdlib.h> 380Sstevel@tonic-gate #include <string.h> 390Sstevel@tonic-gate 400Sstevel@tonic-gate #include "svccfg.h" 410Sstevel@tonic-gate 420Sstevel@tonic-gate /* 430Sstevel@tonic-gate * XML document manipulation routines 440Sstevel@tonic-gate * 450Sstevel@tonic-gate * These routines provide translation to and from the internal representation to 460Sstevel@tonic-gate * XML. Directionally-oriented verbs are with respect to the external source, 470Sstevel@tonic-gate * so lxml_get_service() fetches a service from the XML file into the 480Sstevel@tonic-gate * internal representation. 490Sstevel@tonic-gate */ 500Sstevel@tonic-gate 510Sstevel@tonic-gate const char * const delete_attr = "delete"; 520Sstevel@tonic-gate const char * const enabled_attr = "enabled"; 530Sstevel@tonic-gate const char * const name_attr = "name"; 540Sstevel@tonic-gate const char * const override_attr = "override"; 550Sstevel@tonic-gate const char * const type_attr = "type"; 560Sstevel@tonic-gate const char * const value_attr = "value"; 570Sstevel@tonic-gate const char * const true = "true"; 580Sstevel@tonic-gate const char * const false = "false"; 590Sstevel@tonic-gate 600Sstevel@tonic-gate /* 610Sstevel@tonic-gate * The following list must be kept in the same order as that of 620Sstevel@tonic-gate * element_t array 630Sstevel@tonic-gate */ 640Sstevel@tonic-gate static const char *lxml_elements[] = { 650Sstevel@tonic-gate "astring_list", /* SC_ASTRING */ 660Sstevel@tonic-gate "boolean_list", /* SC_BOOLEAN */ 670Sstevel@tonic-gate "common_name", /* SC_COMMON_NAME */ 680Sstevel@tonic-gate "count_list", /* SC_COUNT */ 690Sstevel@tonic-gate "create_default_instance", /* SC_INSTANCE_CREATE_DEFAULT */ 700Sstevel@tonic-gate "dependency", /* SC_DEPENDENCY */ 710Sstevel@tonic-gate "dependent", /* SC_DEPENDENT */ 720Sstevel@tonic-gate "description", /* SC_DESCRIPTION */ 730Sstevel@tonic-gate "doc_link", /* SC_DOC_LINK */ 740Sstevel@tonic-gate "documentation", /* SC_DOCUMENTATION */ 750Sstevel@tonic-gate "enabled", /* SC_ENABLED */ 760Sstevel@tonic-gate "exec_method", /* SC_EXEC_METHOD */ 770Sstevel@tonic-gate "fmri_list", /* SC_FMRI */ 780Sstevel@tonic-gate "host_list", /* SC_HOST */ 790Sstevel@tonic-gate "hostname_list", /* SC_HOSTNAME */ 800Sstevel@tonic-gate "instance", /* SC_INSTANCE */ 810Sstevel@tonic-gate "integer_list", /* SC_INTEGER */ 820Sstevel@tonic-gate "loctext", /* SC_LOCTEXT */ 830Sstevel@tonic-gate "manpage", /* SC_MANPAGE */ 840Sstevel@tonic-gate "method_context", /* SC_METHOD_CONTEXT */ 850Sstevel@tonic-gate "method_credential", /* SC_METHOD_CREDENTIAL */ 860Sstevel@tonic-gate "method_profile", /* SC_METHOD_PROFILE */ 870Sstevel@tonic-gate "method_environment", /* SC_METHOD_ENVIRONMENT */ 880Sstevel@tonic-gate "envvar", /* SC_METHOD_ENVVAR */ 890Sstevel@tonic-gate "net_address_v4_list", /* SC_NET_ADDR_V4 */ 900Sstevel@tonic-gate "net_address_v6_list", /* SC_NET_ADDR_V6 */ 910Sstevel@tonic-gate "opaque_list", /* SC_OPAQUE */ 920Sstevel@tonic-gate "property", /* SC_PROPERTY */ 930Sstevel@tonic-gate "property_group", /* SC_PROPERTY_GROUP */ 940Sstevel@tonic-gate "propval", /* SC_PROPVAL */ 950Sstevel@tonic-gate "restarter", /* SC_RESTARTER */ 960Sstevel@tonic-gate "service", /* SC_SERVICE */ 970Sstevel@tonic-gate "service_bundle", /* SC_SERVICE_BUNDLE */ 980Sstevel@tonic-gate "service_fmri", /* SC_SERVICE_FMRI */ 990Sstevel@tonic-gate "single_instance", /* SC_INSTANCE_SINGLE */ 1000Sstevel@tonic-gate "stability", /* SC_STABILITY */ 1010Sstevel@tonic-gate "template", /* SC_TEMPLATE */ 1020Sstevel@tonic-gate "time_list", /* SC_TIME */ 1030Sstevel@tonic-gate "uri_list", /* SC_URI */ 1040Sstevel@tonic-gate "ustring_list", /* SC_USTRING */ 1050Sstevel@tonic-gate "value_node", /* SC_VALUE_NODE */ 1060Sstevel@tonic-gate "xi:fallback", /* SC_XI_FALLBACK */ 1070Sstevel@tonic-gate "xi:include" /* SC_XI_INCLUDE */ 1080Sstevel@tonic-gate }; 1090Sstevel@tonic-gate 1100Sstevel@tonic-gate /* 1110Sstevel@tonic-gate * The following list must be kept in the same order as that of 1120Sstevel@tonic-gate * element_t array 1130Sstevel@tonic-gate */ 1140Sstevel@tonic-gate static const char *lxml_prop_types[] = { 1150Sstevel@tonic-gate "astring", /* SC_ASTRING */ 1160Sstevel@tonic-gate "boolean", /* SC_BOOLEAN */ 1170Sstevel@tonic-gate "", /* SC_COMMON_NAME */ 1180Sstevel@tonic-gate "count", /* SC_COUNT */ 1190Sstevel@tonic-gate "", /* SC_INSTANCE_CREATE_DEFAULT */ 1200Sstevel@tonic-gate "", /* SC_DEPENDENCY */ 1210Sstevel@tonic-gate "", /* SC_DEPENDENT */ 1220Sstevel@tonic-gate "", /* SC_DESCRIPTION */ 1230Sstevel@tonic-gate "", /* SC_DOC_LINK */ 1240Sstevel@tonic-gate "", /* SC_DOCUMENTATION */ 1250Sstevel@tonic-gate "", /* SC_ENABLED */ 1260Sstevel@tonic-gate "", /* SC_EXEC_METHOD */ 1270Sstevel@tonic-gate "fmri", /* SC_FMRI */ 1280Sstevel@tonic-gate "host", /* SC_HOST */ 1290Sstevel@tonic-gate "hostname", /* SC_HOSTNAME */ 1300Sstevel@tonic-gate "", /* SC_INSTANCE */ 1310Sstevel@tonic-gate "integer", /* SC_INTEGER */ 1320Sstevel@tonic-gate "", /* SC_LOCTEXT */ 1330Sstevel@tonic-gate "", /* SC_MANPAGE */ 1340Sstevel@tonic-gate "", /* SC_METHOD_CONTEXT */ 1350Sstevel@tonic-gate "", /* SC_METHOD_CREDENTIAL */ 1360Sstevel@tonic-gate "", /* SC_METHOD_PROFILE */ 1370Sstevel@tonic-gate "", /* SC_METHOD_ENVIRONMENT */ 1380Sstevel@tonic-gate "", /* SC_METHOD_ENVVAR */ 1390Sstevel@tonic-gate "net_address_v4", /* SC_NET_ADDR_V4 */ 1400Sstevel@tonic-gate "net_address_v6", /* SC_NET_ADDR_V6 */ 1410Sstevel@tonic-gate "opaque", /* SC_OPAQUE */ 1420Sstevel@tonic-gate "", /* SC_PROPERTY */ 1430Sstevel@tonic-gate "", /* SC_PROPERTY_GROUP */ 1440Sstevel@tonic-gate "", /* SC_PROPVAL */ 1450Sstevel@tonic-gate "", /* SC_RESTARTER */ 1460Sstevel@tonic-gate "", /* SC_SERVICE */ 1470Sstevel@tonic-gate "", /* SC_SERVICE_BUNDLE */ 1480Sstevel@tonic-gate "", /* SC_SERVICE_FMRI */ 1490Sstevel@tonic-gate "", /* SC_INSTANCE_SINGLE */ 1500Sstevel@tonic-gate "", /* SC_STABILITY */ 1510Sstevel@tonic-gate "", /* SC_TEMPLATE */ 1520Sstevel@tonic-gate "time", /* SC_TIME */ 1530Sstevel@tonic-gate "uri", /* SC_URI */ 1540Sstevel@tonic-gate "ustring", /* SC_USTRING */ 1550Sstevel@tonic-gate "" /* SC_VALUE_NODE */ 1560Sstevel@tonic-gate "" /* SC_XI_FALLBACK */ 1570Sstevel@tonic-gate "" /* SC_XI_INCLUDE */ 1580Sstevel@tonic-gate }; 1590Sstevel@tonic-gate 1600Sstevel@tonic-gate int 1610Sstevel@tonic-gate lxml_init() 1620Sstevel@tonic-gate { 1630Sstevel@tonic-gate if (getenv("SVCCFG_NOVALIDATE") == NULL) { 1640Sstevel@tonic-gate /* 1650Sstevel@tonic-gate * DTD validation, with line numbers. 1660Sstevel@tonic-gate */ 1670Sstevel@tonic-gate xmlLineNumbersDefault(1); 1680Sstevel@tonic-gate xmlLoadExtDtdDefaultValue |= XML_DETECT_IDS; 1690Sstevel@tonic-gate xmlLoadExtDtdDefaultValue |= XML_COMPLETE_ATTRS; 1700Sstevel@tonic-gate } 1710Sstevel@tonic-gate 1720Sstevel@tonic-gate return (0); 1730Sstevel@tonic-gate } 1740Sstevel@tonic-gate 1750Sstevel@tonic-gate static bundle_type_t 1760Sstevel@tonic-gate lxml_xlate_bundle_type(xmlChar *type) 1770Sstevel@tonic-gate { 1780Sstevel@tonic-gate if (xmlStrcmp(type, (const xmlChar *)"manifest") == 0) 1790Sstevel@tonic-gate return (SVCCFG_MANIFEST); 1800Sstevel@tonic-gate 1810Sstevel@tonic-gate if (xmlStrcmp(type, (const xmlChar *)"profile") == 0) 1820Sstevel@tonic-gate return (SVCCFG_PROFILE); 1830Sstevel@tonic-gate 1840Sstevel@tonic-gate if (xmlStrcmp(type, (const xmlChar *)"archive") == 0) 1850Sstevel@tonic-gate return (SVCCFG_ARCHIVE); 1860Sstevel@tonic-gate 1870Sstevel@tonic-gate return (SVCCFG_UNKNOWN_BUNDLE); 1880Sstevel@tonic-gate } 1890Sstevel@tonic-gate 1900Sstevel@tonic-gate static service_type_t 1910Sstevel@tonic-gate lxml_xlate_service_type(xmlChar *type) 1920Sstevel@tonic-gate { 1930Sstevel@tonic-gate if (xmlStrcmp(type, (const xmlChar *)"service") == 0) 1940Sstevel@tonic-gate return (SVCCFG_SERVICE); 1950Sstevel@tonic-gate 1960Sstevel@tonic-gate if (xmlStrcmp(type, (const xmlChar *)"restarter") == 0) 1970Sstevel@tonic-gate return (SVCCFG_RESTARTER); 1980Sstevel@tonic-gate 1990Sstevel@tonic-gate if (xmlStrcmp(type, (const xmlChar *)"milestone") == 0) 2000Sstevel@tonic-gate return (SVCCFG_MILESTONE); 2010Sstevel@tonic-gate 2020Sstevel@tonic-gate return (SVCCFG_UNKNOWN_SERVICE); 2030Sstevel@tonic-gate } 2040Sstevel@tonic-gate 2050Sstevel@tonic-gate static element_t 2060Sstevel@tonic-gate lxml_xlate_element(const xmlChar *tag) 2070Sstevel@tonic-gate { 2080Sstevel@tonic-gate int i; 2090Sstevel@tonic-gate 2100Sstevel@tonic-gate for (i = 0; i < sizeof (lxml_elements) / sizeof (char *); i++) 2110Sstevel@tonic-gate if (xmlStrcmp(tag, (const xmlChar *)lxml_elements[i]) == 0) 2120Sstevel@tonic-gate return ((element_t)i); 2130Sstevel@tonic-gate 2140Sstevel@tonic-gate return ((element_t)-1); 2150Sstevel@tonic-gate } 2160Sstevel@tonic-gate 2170Sstevel@tonic-gate static uint_t 2180Sstevel@tonic-gate lxml_xlate_boolean(const xmlChar *value) 2190Sstevel@tonic-gate { 2200Sstevel@tonic-gate if (xmlStrcmp(value, (const xmlChar *)true) == 0) 2210Sstevel@tonic-gate return (1); 2220Sstevel@tonic-gate 2230Sstevel@tonic-gate if (xmlStrcmp(value, (const xmlChar *)false) == 0) 2240Sstevel@tonic-gate return (0); 2250Sstevel@tonic-gate 2260Sstevel@tonic-gate uu_die(gettext("illegal boolean value \"%s\"\n"), value); 2270Sstevel@tonic-gate 2280Sstevel@tonic-gate /*NOTREACHED*/ 2290Sstevel@tonic-gate } 2300Sstevel@tonic-gate 2310Sstevel@tonic-gate static scf_type_t 2320Sstevel@tonic-gate lxml_element_to_type(element_t type) 2330Sstevel@tonic-gate { 2340Sstevel@tonic-gate switch (type) { 2350Sstevel@tonic-gate case SC_ASTRING: return (SCF_TYPE_ASTRING); 2360Sstevel@tonic-gate case SC_BOOLEAN: return (SCF_TYPE_BOOLEAN); 2370Sstevel@tonic-gate case SC_COUNT: return (SCF_TYPE_COUNT); 2380Sstevel@tonic-gate case SC_FMRI: return (SCF_TYPE_FMRI); 2390Sstevel@tonic-gate case SC_HOST: return (SCF_TYPE_HOST); 2400Sstevel@tonic-gate case SC_HOSTNAME: return (SCF_TYPE_HOSTNAME); 2410Sstevel@tonic-gate case SC_INTEGER: return (SCF_TYPE_INTEGER); 2420Sstevel@tonic-gate case SC_NET_ADDR_V4: return (SCF_TYPE_NET_ADDR_V4); 2430Sstevel@tonic-gate case SC_NET_ADDR_V6: return (SCF_TYPE_NET_ADDR_V6); 2440Sstevel@tonic-gate case SC_OPAQUE: return (SCF_TYPE_OPAQUE); 2450Sstevel@tonic-gate case SC_TIME: return (SCF_TYPE_TIME); 2460Sstevel@tonic-gate case SC_URI: return (SCF_TYPE_URI); 2470Sstevel@tonic-gate case SC_USTRING: return (SCF_TYPE_USTRING); 2480Sstevel@tonic-gate 2490Sstevel@tonic-gate default: 2500Sstevel@tonic-gate uu_die(gettext("unknown value type (%d)\n"), type); 2510Sstevel@tonic-gate } 2520Sstevel@tonic-gate 2530Sstevel@tonic-gate /* NOTREACHED */ 2540Sstevel@tonic-gate } 2550Sstevel@tonic-gate 2560Sstevel@tonic-gate static scf_type_t 2570Sstevel@tonic-gate lxml_element_to_scf_type(element_t type) 2580Sstevel@tonic-gate { 2590Sstevel@tonic-gate switch (type) { 2600Sstevel@tonic-gate case SC_ASTRING: return (SCF_TYPE_ASTRING); 2610Sstevel@tonic-gate case SC_BOOLEAN: return (SCF_TYPE_BOOLEAN); 2620Sstevel@tonic-gate case SC_COUNT: return (SCF_TYPE_COUNT); 2630Sstevel@tonic-gate case SC_FMRI: return (SCF_TYPE_FMRI); 2640Sstevel@tonic-gate case SC_HOST: return (SCF_TYPE_HOST); 2650Sstevel@tonic-gate case SC_HOSTNAME: return (SCF_TYPE_HOSTNAME); 2660Sstevel@tonic-gate case SC_INTEGER: return (SCF_TYPE_INTEGER); 2670Sstevel@tonic-gate case SC_NET_ADDR_V4: return (SCF_TYPE_NET_ADDR_V4); 2680Sstevel@tonic-gate case SC_NET_ADDR_V6: return (SCF_TYPE_NET_ADDR_V6); 2690Sstevel@tonic-gate case SC_OPAQUE: return (SCF_TYPE_OPAQUE); 2700Sstevel@tonic-gate case SC_TIME: return (SCF_TYPE_TIME); 2710Sstevel@tonic-gate case SC_URI: return (SCF_TYPE_URI); 2720Sstevel@tonic-gate case SC_USTRING: return (SCF_TYPE_USTRING); 2730Sstevel@tonic-gate default: 2740Sstevel@tonic-gate uu_die(gettext("unknown value type (%d)\n"), type); 2750Sstevel@tonic-gate } 2760Sstevel@tonic-gate 2770Sstevel@tonic-gate /* NOTREACHED */ 2780Sstevel@tonic-gate } 2790Sstevel@tonic-gate 2800Sstevel@tonic-gate static int 2810Sstevel@tonic-gate new_str_prop_from_attr(pgroup_t *pgrp, const char *pname, scf_type_t ty, 2820Sstevel@tonic-gate xmlNodePtr n, const char *attr) 2830Sstevel@tonic-gate { 2840Sstevel@tonic-gate xmlChar *val; 2850Sstevel@tonic-gate property_t *p; 2860Sstevel@tonic-gate int r; 2870Sstevel@tonic-gate 2880Sstevel@tonic-gate val = xmlGetProp(n, (xmlChar *)attr); 2890Sstevel@tonic-gate 2900Sstevel@tonic-gate p = internal_property_create(pname, ty, 1, val); 2910Sstevel@tonic-gate r = internal_attach_property(pgrp, p); 2920Sstevel@tonic-gate 2930Sstevel@tonic-gate if (r != 0) 2940Sstevel@tonic-gate internal_property_free(p); 2950Sstevel@tonic-gate 2960Sstevel@tonic-gate return (r); 2970Sstevel@tonic-gate } 2980Sstevel@tonic-gate 2990Sstevel@tonic-gate static int 3000Sstevel@tonic-gate lxml_ignorable_block(xmlNodePtr n) 3010Sstevel@tonic-gate { 3020Sstevel@tonic-gate return ((xmlStrcmp(n->name, (xmlChar *)"text") == 0 || 3030Sstevel@tonic-gate xmlStrcmp(n->name, (xmlChar *)"comment") == 0) ? 1 : 0); 3040Sstevel@tonic-gate } 3050Sstevel@tonic-gate 3060Sstevel@tonic-gate static int 3070Sstevel@tonic-gate lxml_validate_string_value(scf_type_t type, const char *v) 3080Sstevel@tonic-gate { 3090Sstevel@tonic-gate static scf_value_t *scf_value = NULL; 3100Sstevel@tonic-gate static scf_handle_t *scf_hndl = NULL; 3110Sstevel@tonic-gate 3120Sstevel@tonic-gate if (scf_hndl == NULL && (scf_hndl = scf_handle_create(SCF_VERSION)) == 3130Sstevel@tonic-gate NULL) 3140Sstevel@tonic-gate return (-1); 3150Sstevel@tonic-gate 3160Sstevel@tonic-gate if (scf_value == NULL && (scf_value = scf_value_create(scf_hndl)) == 3170Sstevel@tonic-gate NULL) 3180Sstevel@tonic-gate return (-1); 3190Sstevel@tonic-gate 3200Sstevel@tonic-gate return (scf_value_set_from_string(scf_value, type, v)); 3210Sstevel@tonic-gate } 3220Sstevel@tonic-gate 3230Sstevel@tonic-gate static void 3240Sstevel@tonic-gate lxml_free_str(value_t *val) 3250Sstevel@tonic-gate { 3260Sstevel@tonic-gate free(val->sc_u.sc_string); 3270Sstevel@tonic-gate } 3280Sstevel@tonic-gate 3290Sstevel@tonic-gate static value_t * 3300Sstevel@tonic-gate lxml_make_value(element_t type, const xmlChar *value) 3310Sstevel@tonic-gate { 3320Sstevel@tonic-gate value_t *v; 3330Sstevel@tonic-gate char *endptr; 3340Sstevel@tonic-gate scf_type_t scf_type = SCF_TYPE_INVALID; 3350Sstevel@tonic-gate 3360Sstevel@tonic-gate v = internal_value_new(); 3370Sstevel@tonic-gate 3380Sstevel@tonic-gate v->sc_type = lxml_element_to_type(type); 3390Sstevel@tonic-gate 3400Sstevel@tonic-gate switch (type) { 3410Sstevel@tonic-gate case SC_COUNT: 3420Sstevel@tonic-gate /* 3430Sstevel@tonic-gate * Although an SC_COUNT represents a uint64_t the use 3440Sstevel@tonic-gate * of a negative value is acceptable due to the usage 3450Sstevel@tonic-gate * established by inetd(1M). 3460Sstevel@tonic-gate */ 3470Sstevel@tonic-gate errno = 0; 3480Sstevel@tonic-gate v->sc_u.sc_count = strtoull((char *)value, &endptr, 10); 3490Sstevel@tonic-gate if (errno != 0 || endptr == (char *)value || *endptr) 3500Sstevel@tonic-gate uu_die(gettext("illegal value \"%s\" for " 3510Sstevel@tonic-gate "%s (%s)\n"), (char *)value, 3520Sstevel@tonic-gate lxml_prop_types[type], 3530Sstevel@tonic-gate (errno) ? strerror(errno) : 3540Sstevel@tonic-gate gettext("Illegal character")); 3550Sstevel@tonic-gate break; 3560Sstevel@tonic-gate case SC_INTEGER: 3570Sstevel@tonic-gate errno = 0; 3580Sstevel@tonic-gate v->sc_u.sc_integer = strtoll((char *)value, &endptr, 10); 3590Sstevel@tonic-gate if (errno != 0 || *endptr) 3600Sstevel@tonic-gate uu_die(gettext("illegal value \"%s\" for " 3610Sstevel@tonic-gate "%s (%s)\n"), (char *)value, 3620Sstevel@tonic-gate lxml_prop_types[type], 3630Sstevel@tonic-gate (errno) ? strerror(errno) : "Illegal character"); 3640Sstevel@tonic-gate break; 3650Sstevel@tonic-gate case SC_OPAQUE: 3660Sstevel@tonic-gate case SC_HOST: 3670Sstevel@tonic-gate case SC_HOSTNAME: 3680Sstevel@tonic-gate case SC_NET_ADDR_V4: 3690Sstevel@tonic-gate case SC_NET_ADDR_V6: 3700Sstevel@tonic-gate case SC_FMRI: 3710Sstevel@tonic-gate case SC_URI: 3720Sstevel@tonic-gate case SC_TIME: 3730Sstevel@tonic-gate case SC_ASTRING: 3740Sstevel@tonic-gate case SC_USTRING: 3750Sstevel@tonic-gate scf_type = lxml_element_to_scf_type(type); 3760Sstevel@tonic-gate 3770Sstevel@tonic-gate if ((v->sc_u.sc_string = strdup((char *)value)) == NULL) 3780Sstevel@tonic-gate uu_die(gettext("string duplication failed (%s)\n"), 3790Sstevel@tonic-gate strerror(errno)); 3800Sstevel@tonic-gate if (lxml_validate_string_value(scf_type, 3810Sstevel@tonic-gate v->sc_u.sc_string) != 0) 3820Sstevel@tonic-gate uu_die(gettext("illegal value \"%s\" for " 3830Sstevel@tonic-gate "%s (%s)\n"), (char *)value, 3840Sstevel@tonic-gate lxml_prop_types[type], 3850Sstevel@tonic-gate (scf_error()) ? scf_strerror(scf_error()) : 3860Sstevel@tonic-gate gettext("Illegal format")); 3870Sstevel@tonic-gate v->sc_free = lxml_free_str; 3880Sstevel@tonic-gate break; 3890Sstevel@tonic-gate case SC_BOOLEAN: 3900Sstevel@tonic-gate v->sc_u.sc_count = lxml_xlate_boolean(value); 3910Sstevel@tonic-gate break; 3920Sstevel@tonic-gate default: 3930Sstevel@tonic-gate uu_die(gettext("unknown value type (%d)\n"), type); 3940Sstevel@tonic-gate break; 3950Sstevel@tonic-gate } 3960Sstevel@tonic-gate 3970Sstevel@tonic-gate return (v); 3980Sstevel@tonic-gate } 3990Sstevel@tonic-gate 4000Sstevel@tonic-gate static int 4010Sstevel@tonic-gate lxml_get_value(property_t *prop, element_t vtype, xmlNodePtr value) 4020Sstevel@tonic-gate { 4030Sstevel@tonic-gate xmlNodePtr cursor; 4040Sstevel@tonic-gate 4050Sstevel@tonic-gate for (cursor = value->xmlChildrenNode; cursor != NULL; 4060Sstevel@tonic-gate cursor = cursor->next) { 4070Sstevel@tonic-gate xmlChar *assigned_value; 4080Sstevel@tonic-gate value_t *v; 4090Sstevel@tonic-gate 4100Sstevel@tonic-gate if (lxml_ignorable_block(cursor)) 4110Sstevel@tonic-gate continue; 4120Sstevel@tonic-gate 4130Sstevel@tonic-gate switch (lxml_xlate_element(cursor->name)) { 4140Sstevel@tonic-gate case SC_VALUE_NODE: 4150Sstevel@tonic-gate if ((assigned_value = xmlGetProp(cursor, 4160Sstevel@tonic-gate (xmlChar *)value_attr)) == NULL) 4170Sstevel@tonic-gate uu_die(gettext("no value on value node?\n")); 4180Sstevel@tonic-gate break; 4190Sstevel@tonic-gate default: 4200Sstevel@tonic-gate uu_die(gettext("value list contains illegal element " 4210Sstevel@tonic-gate "\'%s\'\n"), cursor->name); 4220Sstevel@tonic-gate break; 4230Sstevel@tonic-gate } 4240Sstevel@tonic-gate 4250Sstevel@tonic-gate v = lxml_make_value(vtype, assigned_value); 4260Sstevel@tonic-gate 4270Sstevel@tonic-gate xmlFree(assigned_value); 4280Sstevel@tonic-gate 4290Sstevel@tonic-gate internal_attach_value(prop, v); 4300Sstevel@tonic-gate } 4310Sstevel@tonic-gate 4320Sstevel@tonic-gate return (0); 4330Sstevel@tonic-gate } 4340Sstevel@tonic-gate 4350Sstevel@tonic-gate static int 4360Sstevel@tonic-gate lxml_get_propval(pgroup_t *pgrp, xmlNodePtr propval) 4370Sstevel@tonic-gate { 4380Sstevel@tonic-gate property_t *p; 4390Sstevel@tonic-gate element_t r; 4400Sstevel@tonic-gate value_t *v; 4410Sstevel@tonic-gate xmlChar *type, *val, *override; 4420Sstevel@tonic-gate 4430Sstevel@tonic-gate p = internal_property_new(); 4440Sstevel@tonic-gate 4450Sstevel@tonic-gate p->sc_property_name = (char *)xmlGetProp(propval, (xmlChar *)name_attr); 4460Sstevel@tonic-gate if (p->sc_property_name == NULL) 4470Sstevel@tonic-gate uu_die(gettext("property name missing in group '%s'\n"), 4480Sstevel@tonic-gate pgrp->sc_pgroup_name); 4490Sstevel@tonic-gate 4500Sstevel@tonic-gate type = xmlGetProp(propval, (xmlChar *)type_attr); 4510Sstevel@tonic-gate if (type == NULL) 4520Sstevel@tonic-gate uu_die(gettext("property type missing for property '%s/%s'\n"), 4530Sstevel@tonic-gate pgrp->sc_pgroup_name, p->sc_property_name); 4540Sstevel@tonic-gate 4550Sstevel@tonic-gate for (r = 0; r < sizeof (lxml_prop_types) / sizeof (char *); ++r) { 4560Sstevel@tonic-gate if (xmlStrcmp(type, (const xmlChar *)lxml_prop_types[r]) == 0) 4570Sstevel@tonic-gate break; 4580Sstevel@tonic-gate } 4590Sstevel@tonic-gate if (r >= sizeof (lxml_prop_types) / sizeof (char *)) 4600Sstevel@tonic-gate uu_die(gettext("property type invalid for property '%s/%s'\n"), 4610Sstevel@tonic-gate pgrp->sc_pgroup_name, p->sc_property_name); 4620Sstevel@tonic-gate 4630Sstevel@tonic-gate p->sc_value_type = lxml_element_to_type(r); 4640Sstevel@tonic-gate 4650Sstevel@tonic-gate val = xmlGetProp(propval, (xmlChar *)value_attr); 4660Sstevel@tonic-gate if (val == NULL) 4670Sstevel@tonic-gate uu_die(gettext("property value missing for property '%s/%s'\n"), 4680Sstevel@tonic-gate pgrp->sc_pgroup_name, p->sc_property_name); 4690Sstevel@tonic-gate 4700Sstevel@tonic-gate v = lxml_make_value(r, val); 4710Sstevel@tonic-gate internal_attach_value(p, v); 4720Sstevel@tonic-gate 4730Sstevel@tonic-gate override = xmlGetProp(propval, (xmlChar *)override_attr); 4740Sstevel@tonic-gate p->sc_property_override = (xmlStrcmp(override, (xmlChar *)true) == 0); 4750Sstevel@tonic-gate xmlFree(override); 4760Sstevel@tonic-gate 4770Sstevel@tonic-gate return (internal_attach_property(pgrp, p)); 4780Sstevel@tonic-gate } 4790Sstevel@tonic-gate 4800Sstevel@tonic-gate static int 4810Sstevel@tonic-gate lxml_get_property(pgroup_t *pgrp, xmlNodePtr property) 4820Sstevel@tonic-gate { 4830Sstevel@tonic-gate property_t *p; 4840Sstevel@tonic-gate xmlNodePtr cursor; 4850Sstevel@tonic-gate element_t r; 4860Sstevel@tonic-gate xmlChar *type, *override; 4870Sstevel@tonic-gate 4880Sstevel@tonic-gate p = internal_property_new(); 4890Sstevel@tonic-gate 4900Sstevel@tonic-gate if ((p->sc_property_name = (char *)xmlGetProp(property, 4910Sstevel@tonic-gate (xmlChar *)name_attr)) == NULL) 4920Sstevel@tonic-gate uu_die(gettext("property name missing in group \'%s\'\n"), 4930Sstevel@tonic-gate pgrp->sc_pgroup_name); 4940Sstevel@tonic-gate 4950Sstevel@tonic-gate if ((type = xmlGetProp(property, (xmlChar *)type_attr)) == NULL) 4960Sstevel@tonic-gate uu_die(gettext("property type missing for " 4970Sstevel@tonic-gate "property \'%s/%s\'\n"), pgrp->sc_pgroup_name, 4980Sstevel@tonic-gate p->sc_property_name); 4990Sstevel@tonic-gate 5000Sstevel@tonic-gate for (cursor = property->xmlChildrenNode; cursor != NULL; 5010Sstevel@tonic-gate cursor = cursor->next) { 5020Sstevel@tonic-gate if (lxml_ignorable_block(cursor)) 5030Sstevel@tonic-gate continue; 5040Sstevel@tonic-gate 5050Sstevel@tonic-gate switch (r = lxml_xlate_element(cursor->name)) { 5060Sstevel@tonic-gate case SC_ASTRING: 5070Sstevel@tonic-gate case SC_BOOLEAN: 5080Sstevel@tonic-gate case SC_COUNT: 5090Sstevel@tonic-gate case SC_FMRI: 5100Sstevel@tonic-gate case SC_HOST: 5110Sstevel@tonic-gate case SC_HOSTNAME: 5120Sstevel@tonic-gate case SC_INTEGER: 5130Sstevel@tonic-gate case SC_NET_ADDR_V4: 5140Sstevel@tonic-gate case SC_NET_ADDR_V6: 5150Sstevel@tonic-gate case SC_OPAQUE: 5160Sstevel@tonic-gate case SC_TIME: 5170Sstevel@tonic-gate case SC_URI: 5180Sstevel@tonic-gate case SC_USTRING: 5190Sstevel@tonic-gate if (strcmp(lxml_prop_types[r], (const char *)type) != 0) 5200Sstevel@tonic-gate uu_die(gettext("property \'%s\' " 5210Sstevel@tonic-gate "type-to-list mismatch\n"), 5220Sstevel@tonic-gate p->sc_property_name); 5230Sstevel@tonic-gate 5240Sstevel@tonic-gate p->sc_value_type = lxml_element_to_type(r); 5250Sstevel@tonic-gate (void) lxml_get_value(p, r, cursor); 5260Sstevel@tonic-gate break; 5270Sstevel@tonic-gate default: 5280Sstevel@tonic-gate uu_die(gettext("unknown value list type: %s\n"), 5290Sstevel@tonic-gate cursor->name); 5300Sstevel@tonic-gate break; 5310Sstevel@tonic-gate } 5320Sstevel@tonic-gate } 5330Sstevel@tonic-gate 5340Sstevel@tonic-gate xmlFree(type); 5350Sstevel@tonic-gate 5360Sstevel@tonic-gate override = xmlGetProp(property, (xmlChar *)override_attr); 5370Sstevel@tonic-gate p->sc_property_override = (xmlStrcmp(override, (xmlChar *)true) == 0); 5380Sstevel@tonic-gate xmlFree(override); 5390Sstevel@tonic-gate 5400Sstevel@tonic-gate return (internal_attach_property(pgrp, p)); 5410Sstevel@tonic-gate } 5420Sstevel@tonic-gate 5430Sstevel@tonic-gate static int 5440Sstevel@tonic-gate lxml_get_pgroup_stability(pgroup_t *pgrp, xmlNodePtr stab) 5450Sstevel@tonic-gate { 5460Sstevel@tonic-gate return (new_str_prop_from_attr(pgrp, SCF_PROPERTY_STABILITY, 5470Sstevel@tonic-gate SCF_TYPE_ASTRING, stab, value_attr)); 5480Sstevel@tonic-gate } 5490Sstevel@tonic-gate 5500Sstevel@tonic-gate /* 5510Sstevel@tonic-gate * Property groups can go on any of a service, an instance, or a template. 5520Sstevel@tonic-gate */ 5530Sstevel@tonic-gate static int 5540Sstevel@tonic-gate lxml_get_pgroup(entity_t *entity, xmlNodePtr pgroup) 5550Sstevel@tonic-gate { 5560Sstevel@tonic-gate pgroup_t *pg; 5570Sstevel@tonic-gate xmlNodePtr cursor; 5580Sstevel@tonic-gate xmlChar *name, *type, *delete; 5590Sstevel@tonic-gate 5600Sstevel@tonic-gate /* 5610Sstevel@tonic-gate * property group attributes: 5620Sstevel@tonic-gate * name: string 5630Sstevel@tonic-gate * type: string | framework | application 5640Sstevel@tonic-gate */ 5650Sstevel@tonic-gate name = xmlGetProp(pgroup, (xmlChar *)name_attr); 5660Sstevel@tonic-gate type = xmlGetProp(pgroup, (xmlChar *)type_attr); 5670Sstevel@tonic-gate pg = internal_pgroup_find_or_create(entity, (char *)name, (char *)type); 5680Sstevel@tonic-gate xmlFree(name); 5690Sstevel@tonic-gate xmlFree(type); 5700Sstevel@tonic-gate 5710Sstevel@tonic-gate /* 5720Sstevel@tonic-gate * Walk the children of this lxml_elements, which are a stability 5730Sstevel@tonic-gate * element, property elements, or propval elements. 5740Sstevel@tonic-gate */ 5750Sstevel@tonic-gate for (cursor = pgroup->xmlChildrenNode; cursor != NULL; 5760Sstevel@tonic-gate cursor = cursor->next) { 5770Sstevel@tonic-gate if (lxml_ignorable_block(cursor)) 5780Sstevel@tonic-gate continue; 5790Sstevel@tonic-gate 5800Sstevel@tonic-gate switch (lxml_xlate_element(cursor->name)) { 5810Sstevel@tonic-gate case SC_STABILITY: 5820Sstevel@tonic-gate (void) lxml_get_pgroup_stability(pg, cursor); 5830Sstevel@tonic-gate break; 5840Sstevel@tonic-gate case SC_PROPERTY: 5850Sstevel@tonic-gate (void) lxml_get_property(pg, cursor); 5860Sstevel@tonic-gate break; 5870Sstevel@tonic-gate case SC_PROPVAL: 5880Sstevel@tonic-gate (void) lxml_get_propval(pg, cursor); 5890Sstevel@tonic-gate break; 5900Sstevel@tonic-gate default: 5910Sstevel@tonic-gate abort(); 5920Sstevel@tonic-gate break; 5930Sstevel@tonic-gate } 5940Sstevel@tonic-gate } 5950Sstevel@tonic-gate 5960Sstevel@tonic-gate delete = xmlGetProp(pgroup, (xmlChar *)delete_attr); 5970Sstevel@tonic-gate pg->sc_pgroup_delete = (xmlStrcmp(delete, (xmlChar *)true) == 0); 5980Sstevel@tonic-gate xmlFree(delete); 5990Sstevel@tonic-gate 6000Sstevel@tonic-gate return (0); 6010Sstevel@tonic-gate } 6020Sstevel@tonic-gate 6030Sstevel@tonic-gate 6040Sstevel@tonic-gate /* 6050Sstevel@tonic-gate * Dependency groups, execution methods can go on either a service or an 6060Sstevel@tonic-gate * instance. 6070Sstevel@tonic-gate */ 6080Sstevel@tonic-gate 6090Sstevel@tonic-gate static int 6100Sstevel@tonic-gate lxml_get_method_profile(pgroup_t *pg, xmlNodePtr profile) 6110Sstevel@tonic-gate { 6120Sstevel@tonic-gate property_t *p; 6130Sstevel@tonic-gate 6140Sstevel@tonic-gate p = internal_property_create(SCF_PROPERTY_USE_PROFILE, SCF_TYPE_BOOLEAN, 6150Sstevel@tonic-gate 1, (uint64_t)1); 6160Sstevel@tonic-gate if (internal_attach_property(pg, p) != 0) 6170Sstevel@tonic-gate return (-1); 6180Sstevel@tonic-gate 6190Sstevel@tonic-gate return (new_str_prop_from_attr(pg, SCF_PROPERTY_PROFILE, 6200Sstevel@tonic-gate SCF_TYPE_ASTRING, profile, name_attr)); 6210Sstevel@tonic-gate } 6220Sstevel@tonic-gate 6230Sstevel@tonic-gate static int 6240Sstevel@tonic-gate lxml_get_method_credential(pgroup_t *pg, xmlNodePtr cred) 6250Sstevel@tonic-gate { 6260Sstevel@tonic-gate property_t *p; 6270Sstevel@tonic-gate 6280Sstevel@tonic-gate p = internal_property_create(SCF_PROPERTY_USE_PROFILE, SCF_TYPE_BOOLEAN, 6290Sstevel@tonic-gate 1, (uint64_t)0); 6300Sstevel@tonic-gate if (internal_attach_property(pg, p) != 0) 6310Sstevel@tonic-gate return (-1); 6320Sstevel@tonic-gate 6330Sstevel@tonic-gate if (new_str_prop_from_attr(pg, SCF_PROPERTY_USER, SCF_TYPE_ASTRING, 6340Sstevel@tonic-gate cred, "user") != 0) 6350Sstevel@tonic-gate return (-1); 6360Sstevel@tonic-gate 6370Sstevel@tonic-gate if (new_str_prop_from_attr(pg, SCF_PROPERTY_GROUP, SCF_TYPE_ASTRING, 6380Sstevel@tonic-gate cred, "group") != 0) 6390Sstevel@tonic-gate return (-1); 6400Sstevel@tonic-gate 6410Sstevel@tonic-gate if (new_str_prop_from_attr(pg, SCF_PROPERTY_SUPP_GROUPS, 6420Sstevel@tonic-gate SCF_TYPE_ASTRING, cred, "supp_groups") != 0) 6430Sstevel@tonic-gate return (-1); 6440Sstevel@tonic-gate 6450Sstevel@tonic-gate if (new_str_prop_from_attr(pg, SCF_PROPERTY_PRIVILEGES, 6460Sstevel@tonic-gate SCF_TYPE_ASTRING, cred, "privileges") != 0) 6470Sstevel@tonic-gate return (-1); 6480Sstevel@tonic-gate 6490Sstevel@tonic-gate if (new_str_prop_from_attr(pg, SCF_PROPERTY_LIMIT_PRIVILEGES, 6500Sstevel@tonic-gate SCF_TYPE_ASTRING, cred, "limit_privileges") != 0) 6510Sstevel@tonic-gate return (-1); 6520Sstevel@tonic-gate 6530Sstevel@tonic-gate return (0); 6540Sstevel@tonic-gate } 6550Sstevel@tonic-gate 6560Sstevel@tonic-gate static char * 6570Sstevel@tonic-gate lxml_get_envvar(xmlNodePtr envvar) 6580Sstevel@tonic-gate { 6590Sstevel@tonic-gate char *name; 6600Sstevel@tonic-gate char *value; 6610Sstevel@tonic-gate char *ret; 6620Sstevel@tonic-gate 6630Sstevel@tonic-gate name = (char *)xmlGetProp(envvar, (xmlChar *)"name"); 6640Sstevel@tonic-gate value = (char *)xmlGetProp(envvar, (xmlChar *)"value"); 6650Sstevel@tonic-gate 6660Sstevel@tonic-gate if (strlen(name) == 0 || strchr(name, '=') != NULL) 6670Sstevel@tonic-gate uu_die(gettext("Invalid environment variable " 6680Sstevel@tonic-gate "\"%s\".\n"), name); 6690Sstevel@tonic-gate if (strstr(name, "SMF_") == name) 6700Sstevel@tonic-gate uu_die(gettext("Invalid environment variable " 6710Sstevel@tonic-gate "\"%s\"; \"SMF_\" prefix is reserved.\n"), name); 6720Sstevel@tonic-gate 6730Sstevel@tonic-gate ret = uu_msprintf("%s=%s", name, value); 6740Sstevel@tonic-gate xmlFree(name); 6750Sstevel@tonic-gate xmlFree(value); 6760Sstevel@tonic-gate return (ret); 6770Sstevel@tonic-gate } 6780Sstevel@tonic-gate 6790Sstevel@tonic-gate static int 6800Sstevel@tonic-gate lxml_get_method_environment(pgroup_t *pg, xmlNodePtr environment) 6810Sstevel@tonic-gate { 6820Sstevel@tonic-gate property_t *p; 6830Sstevel@tonic-gate xmlNodePtr cursor; 6840Sstevel@tonic-gate value_t *val; 6850Sstevel@tonic-gate 6860Sstevel@tonic-gate p = internal_property_create(SCF_PROPERTY_ENVIRONMENT, 6870Sstevel@tonic-gate SCF_TYPE_ASTRING, 0); 6880Sstevel@tonic-gate 6890Sstevel@tonic-gate for (cursor = environment->xmlChildrenNode; cursor != NULL; 6900Sstevel@tonic-gate cursor = cursor->next) { 6910Sstevel@tonic-gate char *tmp; 6920Sstevel@tonic-gate 6930Sstevel@tonic-gate if (lxml_ignorable_block(cursor)) 6940Sstevel@tonic-gate continue; 6950Sstevel@tonic-gate 6960Sstevel@tonic-gate if (lxml_xlate_element(cursor->name) != SC_METHOD_ENVVAR) 6970Sstevel@tonic-gate uu_die(gettext("illegal element \"%s\" on " 6980Sstevel@tonic-gate "method environment for \"%s\"\n"), 6990Sstevel@tonic-gate cursor->name, pg->sc_pgroup_name); 7000Sstevel@tonic-gate 7010Sstevel@tonic-gate if ((tmp = lxml_get_envvar(cursor)) == NULL) 7020Sstevel@tonic-gate uu_die(gettext("Out of memory\n")); 7030Sstevel@tonic-gate 7040Sstevel@tonic-gate val = internal_value_new(); 7050Sstevel@tonic-gate val->sc_u.sc_string = tmp; 7060Sstevel@tonic-gate val->sc_type = SCF_TYPE_ASTRING; 7070Sstevel@tonic-gate val->sc_free = lxml_free_str; 7080Sstevel@tonic-gate internal_attach_value(p, val); 7090Sstevel@tonic-gate } 7100Sstevel@tonic-gate 7110Sstevel@tonic-gate if (internal_attach_property(pg, p) != 0) { 7120Sstevel@tonic-gate internal_property_free(p); 7130Sstevel@tonic-gate return (-1); 7140Sstevel@tonic-gate } 7150Sstevel@tonic-gate 7160Sstevel@tonic-gate return (0); 7170Sstevel@tonic-gate } 7180Sstevel@tonic-gate 7190Sstevel@tonic-gate static int 7200Sstevel@tonic-gate lxml_get_method_context(pgroup_t *pg, xmlNodePtr ctx) 7210Sstevel@tonic-gate { 7220Sstevel@tonic-gate xmlNodePtr cursor; 7230Sstevel@tonic-gate 7240Sstevel@tonic-gate if (new_str_prop_from_attr(pg, SCF_PROPERTY_WORKING_DIRECTORY, 7250Sstevel@tonic-gate SCF_TYPE_ASTRING, ctx, "working_directory") != 0) 7260Sstevel@tonic-gate return (-1); 7270Sstevel@tonic-gate 7280Sstevel@tonic-gate if (new_str_prop_from_attr(pg, SCF_PROPERTY_PROJECT, SCF_TYPE_ASTRING, 7290Sstevel@tonic-gate ctx, "project") != 0) 7300Sstevel@tonic-gate return (-1); 7310Sstevel@tonic-gate 7320Sstevel@tonic-gate if (new_str_prop_from_attr(pg, SCF_PROPERTY_RESOURCE_POOL, 7330Sstevel@tonic-gate SCF_TYPE_ASTRING, ctx, "resource_pool") != 0) 7340Sstevel@tonic-gate return (-1); 7350Sstevel@tonic-gate 7360Sstevel@tonic-gate for (cursor = ctx->xmlChildrenNode; cursor != NULL; 7370Sstevel@tonic-gate cursor = cursor->next) { 7380Sstevel@tonic-gate if (lxml_ignorable_block(cursor)) 7390Sstevel@tonic-gate continue; 7400Sstevel@tonic-gate 7410Sstevel@tonic-gate switch (lxml_xlate_element(cursor->name)) { 7420Sstevel@tonic-gate case SC_METHOD_CREDENTIAL: 7430Sstevel@tonic-gate (void) lxml_get_method_credential(pg, cursor); 7440Sstevel@tonic-gate break; 7450Sstevel@tonic-gate case SC_METHOD_PROFILE: 7460Sstevel@tonic-gate (void) lxml_get_method_profile(pg, cursor); 7470Sstevel@tonic-gate break; 7480Sstevel@tonic-gate case SC_METHOD_ENVIRONMENT: 7490Sstevel@tonic-gate (void) lxml_get_method_environment(pg, cursor); 7500Sstevel@tonic-gate break; 7510Sstevel@tonic-gate default: 7520Sstevel@tonic-gate semerr(gettext("illegal element \'%s\' in method " 7530Sstevel@tonic-gate "context\n"), (char *)cursor); 7540Sstevel@tonic-gate break; 7550Sstevel@tonic-gate } 7560Sstevel@tonic-gate } 7570Sstevel@tonic-gate 7580Sstevel@tonic-gate return (0); 7590Sstevel@tonic-gate } 7600Sstevel@tonic-gate 7610Sstevel@tonic-gate static int 7620Sstevel@tonic-gate lxml_get_entity_method_context(entity_t *entity, xmlNodePtr ctx) 7630Sstevel@tonic-gate { 7640Sstevel@tonic-gate pgroup_t *pg; 7650Sstevel@tonic-gate 7660Sstevel@tonic-gate pg = internal_pgroup_find_or_create(entity, SCF_PG_METHOD_CONTEXT, 7670Sstevel@tonic-gate (char *)scf_group_framework); 7680Sstevel@tonic-gate 7690Sstevel@tonic-gate return (lxml_get_method_context(pg, ctx)); 7700Sstevel@tonic-gate } 7710Sstevel@tonic-gate 7720Sstevel@tonic-gate static int 7730Sstevel@tonic-gate lxml_get_exec_method(entity_t *entity, xmlNodePtr emeth) 7740Sstevel@tonic-gate { 7750Sstevel@tonic-gate pgroup_t *pg; 7760Sstevel@tonic-gate property_t *p; 7770Sstevel@tonic-gate xmlChar *name, *timeout, *delete; 7780Sstevel@tonic-gate xmlNodePtr cursor; 7790Sstevel@tonic-gate int r = 0; 7800Sstevel@tonic-gate 7810Sstevel@tonic-gate name = xmlGetProp(emeth, (xmlChar *)name_attr); 7820Sstevel@tonic-gate pg = internal_pgroup_find_or_create(entity, (char *)name, 7830Sstevel@tonic-gate (char *)SCF_GROUP_METHOD); 7840Sstevel@tonic-gate xmlFree(name); 7850Sstevel@tonic-gate 7860Sstevel@tonic-gate if (new_str_prop_from_attr(pg, SCF_PROPERTY_TYPE, SCF_TYPE_ASTRING, 7870Sstevel@tonic-gate emeth, type_attr) != 0 || 7880Sstevel@tonic-gate new_str_prop_from_attr(pg, SCF_PROPERTY_EXEC, SCF_TYPE_ASTRING, 7890Sstevel@tonic-gate emeth, "exec") != 0) 7900Sstevel@tonic-gate return (-1); 7910Sstevel@tonic-gate 7920Sstevel@tonic-gate timeout = xmlGetProp(emeth, (xmlChar *)"timeout_seconds"); 7930Sstevel@tonic-gate if (timeout != NULL) { 7940Sstevel@tonic-gate uint64_t u_timeout; 7950Sstevel@tonic-gate char *endptr; 7960Sstevel@tonic-gate /* 7970Sstevel@tonic-gate * Although an SC_COUNT represents a uint64_t the use 7980Sstevel@tonic-gate * of a negative value is acceptable due to the usage 7990Sstevel@tonic-gate * established by inetd(1M). 8000Sstevel@tonic-gate */ 8010Sstevel@tonic-gate errno = 0; 8020Sstevel@tonic-gate u_timeout = strtoull((char *)timeout, &endptr, 10); 8030Sstevel@tonic-gate if (errno != 0 || endptr == (char *)timeout || *endptr) 8040Sstevel@tonic-gate uu_die(gettext("illegal value \"%s\" for " 8050Sstevel@tonic-gate "timeout_seconds (%s)\n"), 8060Sstevel@tonic-gate (char *)timeout, (errno) ? strerror(errno): 8070Sstevel@tonic-gate gettext("Illegal character")); 8080Sstevel@tonic-gate p = internal_property_create(SCF_PROPERTY_TIMEOUT, 8090Sstevel@tonic-gate SCF_TYPE_COUNT, 1, u_timeout); 8100Sstevel@tonic-gate r = internal_attach_property(pg, p); 8110Sstevel@tonic-gate xmlFree(timeout); 8120Sstevel@tonic-gate } 8130Sstevel@tonic-gate if (r != 0) 8140Sstevel@tonic-gate return (-1); 8150Sstevel@tonic-gate 8160Sstevel@tonic-gate /* 8170Sstevel@tonic-gate * There is a possibility that a method context also exists, in which 8180Sstevel@tonic-gate * case the following attributes are defined: project, resource_pool, 8190Sstevel@tonic-gate * working_directory, profile, user, group, privileges, limit_privileges 8200Sstevel@tonic-gate */ 8210Sstevel@tonic-gate for (cursor = emeth->xmlChildrenNode; cursor != NULL; 8220Sstevel@tonic-gate cursor = cursor->next) { 8230Sstevel@tonic-gate if (lxml_ignorable_block(cursor)) 8240Sstevel@tonic-gate continue; 8250Sstevel@tonic-gate 8260Sstevel@tonic-gate switch (lxml_xlate_element(cursor->name)) { 8270Sstevel@tonic-gate case SC_STABILITY: 8280Sstevel@tonic-gate if (lxml_get_pgroup_stability(pg, cursor) != 0) 8290Sstevel@tonic-gate return (-1); 8300Sstevel@tonic-gate break; 8310Sstevel@tonic-gate 8320Sstevel@tonic-gate case SC_METHOD_CONTEXT: 8330Sstevel@tonic-gate (void) lxml_get_method_context(pg, cursor); 8340Sstevel@tonic-gate break; 8350Sstevel@tonic-gate 8360Sstevel@tonic-gate case SC_PROPVAL: 8370Sstevel@tonic-gate (void) lxml_get_propval(pg, cursor); 8380Sstevel@tonic-gate break; 8390Sstevel@tonic-gate 8400Sstevel@tonic-gate case SC_PROPERTY: 8410Sstevel@tonic-gate (void) lxml_get_property(pg, cursor); 8420Sstevel@tonic-gate break; 8430Sstevel@tonic-gate 8440Sstevel@tonic-gate default: 8450Sstevel@tonic-gate uu_die(gettext("illegal element \"%s\" on " 8460Sstevel@tonic-gate "execution method \"%s\"\n"), cursor->name, 8470Sstevel@tonic-gate pg->sc_pgroup_name); 8480Sstevel@tonic-gate break; 8490Sstevel@tonic-gate } 8500Sstevel@tonic-gate } 8510Sstevel@tonic-gate 8520Sstevel@tonic-gate delete = xmlGetProp(emeth, (xmlChar *)delete_attr); 8530Sstevel@tonic-gate pg->sc_pgroup_delete = (xmlStrcmp(delete, (xmlChar *)true) == 0); 8540Sstevel@tonic-gate xmlFree(delete); 8550Sstevel@tonic-gate 8560Sstevel@tonic-gate return (0); 8570Sstevel@tonic-gate } 8580Sstevel@tonic-gate 8590Sstevel@tonic-gate static int 8600Sstevel@tonic-gate lxml_get_dependency(entity_t *entity, xmlNodePtr dependency) 8610Sstevel@tonic-gate { 8620Sstevel@tonic-gate pgroup_t *pg; 8630Sstevel@tonic-gate property_t *p; 8640Sstevel@tonic-gate xmlNodePtr cursor; 8650Sstevel@tonic-gate xmlChar *name; 8660Sstevel@tonic-gate xmlChar *delete; 8670Sstevel@tonic-gate 8680Sstevel@tonic-gate /* 8690Sstevel@tonic-gate * dependency attributes: 8700Sstevel@tonic-gate * name: string 8710Sstevel@tonic-gate * grouping: require_all | require_any | exclude_all | optional_all 8720Sstevel@tonic-gate * reset_on: string (error | restart | refresh | none) 8730Sstevel@tonic-gate * type: service / path /host 8740Sstevel@tonic-gate */ 8750Sstevel@tonic-gate 8760Sstevel@tonic-gate name = xmlGetProp(dependency, (xmlChar *)name_attr); 8770Sstevel@tonic-gate pg = internal_pgroup_find_or_create(entity, (char *)name, 8780Sstevel@tonic-gate (char *)SCF_GROUP_DEPENDENCY); 8790Sstevel@tonic-gate xmlFree(name); 8800Sstevel@tonic-gate 8810Sstevel@tonic-gate if (new_str_prop_from_attr(pg, SCF_PROPERTY_TYPE, SCF_TYPE_ASTRING, 8820Sstevel@tonic-gate dependency, type_attr) != 0) 8830Sstevel@tonic-gate return (-1); 8840Sstevel@tonic-gate 8850Sstevel@tonic-gate if (new_str_prop_from_attr(pg, SCF_PROPERTY_RESTART_ON, 8860Sstevel@tonic-gate SCF_TYPE_ASTRING, dependency, "restart_on") != 0) 8870Sstevel@tonic-gate return (-1); 8880Sstevel@tonic-gate 8890Sstevel@tonic-gate if (new_str_prop_from_attr(pg, SCF_PROPERTY_GROUPING, SCF_TYPE_ASTRING, 8900Sstevel@tonic-gate dependency, "grouping") != 0) 8910Sstevel@tonic-gate return (-1); 8920Sstevel@tonic-gate 8930Sstevel@tonic-gate p = internal_property_create(SCF_PROPERTY_ENTITIES, SCF_TYPE_FMRI, 0); 8940Sstevel@tonic-gate if (internal_attach_property(pg, p) != 0) 8950Sstevel@tonic-gate return (-1); 8960Sstevel@tonic-gate 8970Sstevel@tonic-gate for (cursor = dependency->xmlChildrenNode; cursor != NULL; 8980Sstevel@tonic-gate cursor = cursor->next) { 8990Sstevel@tonic-gate xmlChar *value; 9000Sstevel@tonic-gate value_t *v; 9010Sstevel@tonic-gate 9020Sstevel@tonic-gate if (lxml_ignorable_block(cursor)) 9030Sstevel@tonic-gate continue; 9040Sstevel@tonic-gate 9050Sstevel@tonic-gate switch (lxml_xlate_element(cursor->name)) { 9060Sstevel@tonic-gate case SC_STABILITY: 9070Sstevel@tonic-gate if (lxml_get_pgroup_stability(pg, cursor) != 0) 9080Sstevel@tonic-gate return (-1); 9090Sstevel@tonic-gate break; 9100Sstevel@tonic-gate 9110Sstevel@tonic-gate case SC_SERVICE_FMRI: 9120Sstevel@tonic-gate value = xmlGetProp(cursor, (xmlChar *)value_attr); 9130Sstevel@tonic-gate if (value != NULL) { 9140Sstevel@tonic-gate if (lxml_validate_string_value(SCF_TYPE_FMRI, 9150Sstevel@tonic-gate (char *)value) != 0) 9160Sstevel@tonic-gate uu_die(gettext("illegal value \"%s\" " 9170Sstevel@tonic-gate "for %s (%s)\n"), (char *)value, 9180Sstevel@tonic-gate lxml_prop_types[SC_FMRI], 9190Sstevel@tonic-gate (scf_error()) ? 9200Sstevel@tonic-gate scf_strerror(scf_error()) : 9210Sstevel@tonic-gate gettext("Illegal format")); 9220Sstevel@tonic-gate v = internal_value_new(); 9230Sstevel@tonic-gate v->sc_type = SCF_TYPE_FMRI; 9240Sstevel@tonic-gate v->sc_u.sc_string = (char *)value; 9250Sstevel@tonic-gate internal_attach_value(p, v); 9260Sstevel@tonic-gate } 9270Sstevel@tonic-gate 9280Sstevel@tonic-gate break; 9290Sstevel@tonic-gate 9300Sstevel@tonic-gate case SC_PROPVAL: 9310Sstevel@tonic-gate (void) lxml_get_propval(pg, cursor); 9320Sstevel@tonic-gate break; 9330Sstevel@tonic-gate 9340Sstevel@tonic-gate case SC_PROPERTY: 9350Sstevel@tonic-gate (void) lxml_get_property(pg, cursor); 9360Sstevel@tonic-gate break; 9370Sstevel@tonic-gate 9380Sstevel@tonic-gate default: 9390Sstevel@tonic-gate uu_die(gettext("illegal element \"%s\" on " 9400Sstevel@tonic-gate "dependency group \"%s\"\n"), cursor->name, name); 9410Sstevel@tonic-gate break; 9420Sstevel@tonic-gate } 9430Sstevel@tonic-gate } 9440Sstevel@tonic-gate 9450Sstevel@tonic-gate delete = xmlGetProp(dependency, (xmlChar *)delete_attr); 9460Sstevel@tonic-gate pg->sc_pgroup_delete = (xmlStrcmp(delete, (xmlChar *)true) == 0); 9470Sstevel@tonic-gate xmlFree(delete); 9480Sstevel@tonic-gate 9490Sstevel@tonic-gate return (0); 9500Sstevel@tonic-gate } 9510Sstevel@tonic-gate 9520Sstevel@tonic-gate /* 9530Sstevel@tonic-gate * Dependents are hairy. They should cause a dependency pg to be created in 9540Sstevel@tonic-gate * another service, but we can't do that here; we'll have to wait until the 9550Sstevel@tonic-gate * import routines. So for now we'll add the dependency group that should go 9560Sstevel@tonic-gate * in the other service to the entity's dependent list. 9570Sstevel@tonic-gate */ 9580Sstevel@tonic-gate static int 9590Sstevel@tonic-gate lxml_get_dependent(entity_t *entity, xmlNodePtr dependent) 9600Sstevel@tonic-gate { 9610Sstevel@tonic-gate xmlChar *name, *or; 9620Sstevel@tonic-gate xmlNodePtr sf; 9630Sstevel@tonic-gate xmlChar *fmri, *delete; 9640Sstevel@tonic-gate pgroup_t *pg; 9650Sstevel@tonic-gate property_t *p; 9660Sstevel@tonic-gate xmlNodePtr n; 9670Sstevel@tonic-gate char *myfmri; 9680Sstevel@tonic-gate 9690Sstevel@tonic-gate name = xmlGetProp(dependent, (xmlChar *)name_attr); 9700Sstevel@tonic-gate 9710Sstevel@tonic-gate if (internal_pgroup_find(entity, (char *)name, NULL) != NULL) { 9720Sstevel@tonic-gate semerr(gettext("Property group and dependent of entity %s " 9730Sstevel@tonic-gate "have same name \"%s\".\n"), entity->sc_name, name); 9740Sstevel@tonic-gate xmlFree(name); 9750Sstevel@tonic-gate return (-1); 9760Sstevel@tonic-gate } 9770Sstevel@tonic-gate 9780Sstevel@tonic-gate or = xmlGetProp(dependent, (xmlChar *)override_attr); 9790Sstevel@tonic-gate 9800Sstevel@tonic-gate pg = internal_pgroup_new(); 9810Sstevel@tonic-gate pg->sc_pgroup_name = (char *)name; 9820Sstevel@tonic-gate pg->sc_pgroup_type = (char *)SCF_GROUP_DEPENDENCY; 9830Sstevel@tonic-gate pg->sc_pgroup_override = (xmlStrcmp(or, (xmlChar *)true) == 0); 9840Sstevel@tonic-gate xmlFree(or); 9850Sstevel@tonic-gate if (internal_attach_dependent(entity, pg) != 0) { 9860Sstevel@tonic-gate xmlFree(name); 9870Sstevel@tonic-gate internal_pgroup_free(pg); 9880Sstevel@tonic-gate return (-1); 9890Sstevel@tonic-gate } 9900Sstevel@tonic-gate 9910Sstevel@tonic-gate for (sf = dependent->children; sf != NULL; sf = sf->next) 9920Sstevel@tonic-gate if (xmlStrcmp(sf->name, (xmlChar *)"service_fmri") == 0) 9930Sstevel@tonic-gate break; 9940Sstevel@tonic-gate assert(sf != NULL); 9950Sstevel@tonic-gate fmri = xmlGetProp(sf, (xmlChar *)value_attr); 9960Sstevel@tonic-gate pg->sc_pgroup_fmri = (char *)fmri; 9970Sstevel@tonic-gate 9980Sstevel@tonic-gate if (new_str_prop_from_attr(pg, SCF_PROPERTY_RESTART_ON, 9990Sstevel@tonic-gate SCF_TYPE_ASTRING, dependent, "restart_on") != 0) 10000Sstevel@tonic-gate return (-1); 10010Sstevel@tonic-gate 10020Sstevel@tonic-gate if (new_str_prop_from_attr(pg, SCF_PROPERTY_GROUPING, SCF_TYPE_ASTRING, 10030Sstevel@tonic-gate dependent, "grouping") != 0) 10040Sstevel@tonic-gate return (-1); 10050Sstevel@tonic-gate 10060Sstevel@tonic-gate myfmri = safe_malloc(max_scf_fmri_len + 1); 10070Sstevel@tonic-gate if (entity->sc_etype == SVCCFG_SERVICE_OBJECT) { 10080Sstevel@tonic-gate if (snprintf(myfmri, max_scf_fmri_len + 1, "svc:/%s", 10090Sstevel@tonic-gate entity->sc_name) < 0) 10100Sstevel@tonic-gate bad_error("snprintf", errno); 10110Sstevel@tonic-gate } else { 10120Sstevel@tonic-gate assert(entity->sc_etype == SVCCFG_INSTANCE_OBJECT); 10130Sstevel@tonic-gate if (snprintf(myfmri, max_scf_fmri_len + 1, "svc:/%s:%s", 10140Sstevel@tonic-gate entity->sc_parent->sc_name, entity->sc_name) < 0) 10150Sstevel@tonic-gate bad_error("snprintf", errno); 10160Sstevel@tonic-gate } 10170Sstevel@tonic-gate 10180Sstevel@tonic-gate p = internal_property_create(SCF_PROPERTY_ENTITIES, SCF_TYPE_FMRI, 1, 10190Sstevel@tonic-gate myfmri); 10200Sstevel@tonic-gate if (internal_attach_property(pg, p) != 0) 10210Sstevel@tonic-gate return (-1); 10220Sstevel@tonic-gate 10230Sstevel@tonic-gate /* Create a property to serve as a do-not-export flag. */ 10240Sstevel@tonic-gate p = internal_property_create("external", SCF_TYPE_BOOLEAN, 1, 10250Sstevel@tonic-gate (uint64_t)1); 10260Sstevel@tonic-gate if (internal_attach_property(pg, p) != 0) 10270Sstevel@tonic-gate return (-1); 10280Sstevel@tonic-gate 10290Sstevel@tonic-gate for (n = sf->next; n != NULL; n = n->next) { 10300Sstevel@tonic-gate if (lxml_ignorable_block(n)) 10310Sstevel@tonic-gate continue; 10320Sstevel@tonic-gate 10330Sstevel@tonic-gate switch (lxml_xlate_element(n->name)) { 10340Sstevel@tonic-gate case SC_STABILITY: 10350Sstevel@tonic-gate if (new_str_prop_from_attr(pg, 10360Sstevel@tonic-gate SCF_PROPERTY_ENTITY_STABILITY, SCF_TYPE_ASTRING, n, 10370Sstevel@tonic-gate value_attr) != 0) 10380Sstevel@tonic-gate return (-1); 10390Sstevel@tonic-gate break; 10400Sstevel@tonic-gate 10410Sstevel@tonic-gate case SC_PROPVAL: 10420Sstevel@tonic-gate (void) lxml_get_propval(pg, n); 10430Sstevel@tonic-gate break; 10440Sstevel@tonic-gate 10450Sstevel@tonic-gate case SC_PROPERTY: 10460Sstevel@tonic-gate (void) lxml_get_property(pg, n); 10470Sstevel@tonic-gate break; 10480Sstevel@tonic-gate 10490Sstevel@tonic-gate default: 10500Sstevel@tonic-gate uu_die(gettext("unexpected element %s.\n"), n->name); 10510Sstevel@tonic-gate } 10520Sstevel@tonic-gate } 10530Sstevel@tonic-gate 10540Sstevel@tonic-gate /* Go back and fill in defaults. */ 10550Sstevel@tonic-gate if (internal_property_find(pg, SCF_PROPERTY_TYPE) == NULL) { 10560Sstevel@tonic-gate p = internal_property_create(SCF_PROPERTY_TYPE, 10570Sstevel@tonic-gate SCF_TYPE_ASTRING, 1, "service"); 10580Sstevel@tonic-gate if (internal_attach_property(pg, p) != 0) 10590Sstevel@tonic-gate return (-1); 10600Sstevel@tonic-gate } 10610Sstevel@tonic-gate 10620Sstevel@tonic-gate delete = xmlGetProp(dependent, (xmlChar *)delete_attr); 10630Sstevel@tonic-gate pg->sc_pgroup_delete = (xmlStrcmp(delete, (xmlChar *)true) == 0); 10640Sstevel@tonic-gate xmlFree(delete); 10650Sstevel@tonic-gate 10660Sstevel@tonic-gate pg = internal_pgroup_find_or_create(entity, "dependents", 10670Sstevel@tonic-gate (char *)scf_group_framework); 1068*306Sbustos p = internal_property_create((char *)name, SCF_TYPE_FMRI, 1, fmri); 10690Sstevel@tonic-gate if (internal_attach_property(pg, p) != 0) 10700Sstevel@tonic-gate return (-1); 10710Sstevel@tonic-gate 10720Sstevel@tonic-gate return (0); 10730Sstevel@tonic-gate } 10740Sstevel@tonic-gate 10750Sstevel@tonic-gate static int 10760Sstevel@tonic-gate lxml_get_entity_stability(entity_t *entity, xmlNodePtr rstr) 10770Sstevel@tonic-gate { 10780Sstevel@tonic-gate pgroup_t *pg; 10790Sstevel@tonic-gate property_t *p; 10800Sstevel@tonic-gate xmlChar *stabval; 10810Sstevel@tonic-gate 10820Sstevel@tonic-gate if ((stabval = xmlGetProp(rstr, (xmlChar *)value_attr)) == NULL) { 10830Sstevel@tonic-gate uu_warn(gettext("no stability value found\n")); 10840Sstevel@tonic-gate stabval = (xmlChar *)strdup("External"); 10850Sstevel@tonic-gate } 10860Sstevel@tonic-gate 10870Sstevel@tonic-gate pg = internal_pgroup_find_or_create(entity, (char *)scf_pg_general, 10880Sstevel@tonic-gate (char *)scf_group_framework); 10890Sstevel@tonic-gate 10900Sstevel@tonic-gate p = internal_property_create(SCF_PROPERTY_ENTITY_STABILITY, 10910Sstevel@tonic-gate SCF_TYPE_ASTRING, 1, stabval); 10920Sstevel@tonic-gate 10930Sstevel@tonic-gate return (internal_attach_property(pg, p)); 10940Sstevel@tonic-gate } 10950Sstevel@tonic-gate 10960Sstevel@tonic-gate static int 10970Sstevel@tonic-gate lxml_get_restarter(entity_t *entity, xmlNodePtr rstr) 10980Sstevel@tonic-gate { 10990Sstevel@tonic-gate pgroup_t *pg; 11000Sstevel@tonic-gate property_t *p; 11010Sstevel@tonic-gate xmlChar *restarter; 11020Sstevel@tonic-gate xmlNode *cursor; 11030Sstevel@tonic-gate int r; 11040Sstevel@tonic-gate 11050Sstevel@tonic-gate /* 11060Sstevel@tonic-gate * Go find child. Child is a service_fmri element. value attribute 11070Sstevel@tonic-gate * contains restarter FMRI. 11080Sstevel@tonic-gate */ 11090Sstevel@tonic-gate 11100Sstevel@tonic-gate pg = internal_pgroup_find_or_create(entity, (char *)scf_pg_general, 11110Sstevel@tonic-gate (char *)scf_group_framework); 11120Sstevel@tonic-gate 11130Sstevel@tonic-gate /* 11140Sstevel@tonic-gate * Walk its child elements, as appropriate. 11150Sstevel@tonic-gate */ 11160Sstevel@tonic-gate for (cursor = rstr->xmlChildrenNode; cursor != NULL; 11170Sstevel@tonic-gate cursor = cursor->next) { 11180Sstevel@tonic-gate if (lxml_ignorable_block(cursor)) 11190Sstevel@tonic-gate continue; 11200Sstevel@tonic-gate 11210Sstevel@tonic-gate switch (lxml_xlate_element(cursor->name)) { 11220Sstevel@tonic-gate case SC_SERVICE_FMRI: 11230Sstevel@tonic-gate restarter = xmlGetProp(cursor, (xmlChar *)value_attr); 11240Sstevel@tonic-gate break; 11250Sstevel@tonic-gate default: 11260Sstevel@tonic-gate uu_die(gettext("illegal element \"%s\" on restarter " 11270Sstevel@tonic-gate "element for \"%s\"\n"), cursor->name, 11280Sstevel@tonic-gate entity->sc_name); 11290Sstevel@tonic-gate break; 11300Sstevel@tonic-gate } 11310Sstevel@tonic-gate } 11320Sstevel@tonic-gate 11330Sstevel@tonic-gate p = internal_property_create(SCF_PROPERTY_RESTARTER, SCF_TYPE_FMRI, 1, 11340Sstevel@tonic-gate restarter); 11350Sstevel@tonic-gate 11360Sstevel@tonic-gate r = internal_attach_property(pg, p); 11370Sstevel@tonic-gate if (r != 0) { 11380Sstevel@tonic-gate internal_property_free(p); 11390Sstevel@tonic-gate return (-1); 11400Sstevel@tonic-gate } 11410Sstevel@tonic-gate 11420Sstevel@tonic-gate return (0); 11430Sstevel@tonic-gate } 11440Sstevel@tonic-gate 11450Sstevel@tonic-gate static void 11460Sstevel@tonic-gate sanitize_locale(uchar_t *locale) 11470Sstevel@tonic-gate { 11480Sstevel@tonic-gate for (; *locale != '\0'; locale++) 11490Sstevel@tonic-gate if (!isalnum(*locale) && *locale != '_') 11500Sstevel@tonic-gate *locale = '_'; 11510Sstevel@tonic-gate } 11520Sstevel@tonic-gate 11530Sstevel@tonic-gate static int 11540Sstevel@tonic-gate lxml_get_loctext(entity_t *service, pgroup_t *pg, xmlNodePtr loctext) 11550Sstevel@tonic-gate { 11560Sstevel@tonic-gate xmlNodePtr cursor; 11570Sstevel@tonic-gate xmlChar *val; 11580Sstevel@tonic-gate char *stripped, *cp; 11590Sstevel@tonic-gate property_t *p; 11600Sstevel@tonic-gate int r; 11610Sstevel@tonic-gate 11620Sstevel@tonic-gate if ((val = xmlGetProp(loctext, (xmlChar *)"xml:lang")) == NULL) 11630Sstevel@tonic-gate if ((val = xmlGetProp(loctext, (xmlChar *)"lang")) == NULL) 11640Sstevel@tonic-gate val = (xmlChar *)"unknown"; 11650Sstevel@tonic-gate 11660Sstevel@tonic-gate sanitize_locale(val); 11670Sstevel@tonic-gate 11680Sstevel@tonic-gate for (cursor = loctext->xmlChildrenNode; cursor != NULL; 11690Sstevel@tonic-gate cursor = cursor->next) { 11700Sstevel@tonic-gate if (strcmp("text", (const char *)cursor->name) == 0) { 11710Sstevel@tonic-gate break; 11720Sstevel@tonic-gate } else if (strcmp("comment", (const char *)cursor->name) != 0) { 11730Sstevel@tonic-gate uu_die(gettext("illegal element \"%s\" on loctext " 11740Sstevel@tonic-gate "element for \"%s\"\n"), cursor->name, 11750Sstevel@tonic-gate service->sc_name); 11760Sstevel@tonic-gate } 11770Sstevel@tonic-gate } 11780Sstevel@tonic-gate 11790Sstevel@tonic-gate if (cursor == NULL) { 11800Sstevel@tonic-gate uu_die(gettext("loctext element has no content for \"%s\"\n"), 11810Sstevel@tonic-gate service->sc_name); 11820Sstevel@tonic-gate } 11830Sstevel@tonic-gate 11840Sstevel@tonic-gate /* 11850Sstevel@tonic-gate * Remove leading and trailing whitespace. 11860Sstevel@tonic-gate */ 11870Sstevel@tonic-gate if ((stripped = strdup((const char *)cursor->content)) == NULL) 11880Sstevel@tonic-gate uu_die(gettext("Out of memory\n")); 11890Sstevel@tonic-gate 11900Sstevel@tonic-gate for (; isspace(*stripped); stripped++); 11910Sstevel@tonic-gate for (cp = stripped + strlen(stripped) - 1; isspace(*cp); cp--); 11920Sstevel@tonic-gate *(cp + 1) = '\0'; 11930Sstevel@tonic-gate 11940Sstevel@tonic-gate p = internal_property_create((const char *)val, SCF_TYPE_USTRING, 1, 11950Sstevel@tonic-gate stripped); 11960Sstevel@tonic-gate 11970Sstevel@tonic-gate r = internal_attach_property(pg, p); 11980Sstevel@tonic-gate if (r != 0) 11990Sstevel@tonic-gate internal_property_free(p); 12000Sstevel@tonic-gate 12010Sstevel@tonic-gate return (r); 12020Sstevel@tonic-gate } 12030Sstevel@tonic-gate 12040Sstevel@tonic-gate static int 12050Sstevel@tonic-gate lxml_get_tm_common_name(entity_t *service, xmlNodePtr common_name) 12060Sstevel@tonic-gate { 12070Sstevel@tonic-gate xmlNodePtr cursor; 12080Sstevel@tonic-gate pgroup_t *pg; 12090Sstevel@tonic-gate 12100Sstevel@tonic-gate /* 12110Sstevel@tonic-gate * Create the property group, if absent. 12120Sstevel@tonic-gate */ 12130Sstevel@tonic-gate pg = internal_pgroup_find_or_create(service, 12140Sstevel@tonic-gate (char *)SCF_PG_TM_COMMON_NAME, (char *)SCF_GROUP_TEMPLATE); 12150Sstevel@tonic-gate 12160Sstevel@tonic-gate /* 12170Sstevel@tonic-gate * Iterate through one or more loctext elements. The locale is the 12180Sstevel@tonic-gate * property name; the contents are the ustring value for the property. 12190Sstevel@tonic-gate */ 12200Sstevel@tonic-gate for (cursor = common_name->xmlChildrenNode; cursor != NULL; 12210Sstevel@tonic-gate cursor = cursor->next) { 12220Sstevel@tonic-gate if (lxml_ignorable_block(cursor)) 12230Sstevel@tonic-gate continue; 12240Sstevel@tonic-gate 12250Sstevel@tonic-gate switch (lxml_xlate_element(cursor->name)) { 12260Sstevel@tonic-gate case SC_LOCTEXT: 12270Sstevel@tonic-gate if (lxml_get_loctext(service, pg, cursor)) 12280Sstevel@tonic-gate return (-1); 12290Sstevel@tonic-gate break; 12300Sstevel@tonic-gate default: 12310Sstevel@tonic-gate uu_die(gettext("illegal element \"%s\" on common_name " 12320Sstevel@tonic-gate "element for \"%s\"\n"), cursor->name, 12330Sstevel@tonic-gate service->sc_name); 12340Sstevel@tonic-gate break; 12350Sstevel@tonic-gate } 12360Sstevel@tonic-gate } 12370Sstevel@tonic-gate 12380Sstevel@tonic-gate return (0); 12390Sstevel@tonic-gate } 12400Sstevel@tonic-gate 12410Sstevel@tonic-gate static int 12420Sstevel@tonic-gate lxml_get_tm_description(entity_t *service, xmlNodePtr description) 12430Sstevel@tonic-gate { 12440Sstevel@tonic-gate xmlNodePtr cursor; 12450Sstevel@tonic-gate pgroup_t *pg; 12460Sstevel@tonic-gate 12470Sstevel@tonic-gate /* 12480Sstevel@tonic-gate * Create the property group, if absent. 12490Sstevel@tonic-gate */ 12500Sstevel@tonic-gate pg = internal_pgroup_find_or_create(service, 12510Sstevel@tonic-gate (char *)SCF_PG_TM_DESCRIPTION, (char *)SCF_GROUP_TEMPLATE); 12520Sstevel@tonic-gate 12530Sstevel@tonic-gate /* 12540Sstevel@tonic-gate * Iterate through one or more loctext elements. The locale is the 12550Sstevel@tonic-gate * property name; the contents are the ustring value for the property. 12560Sstevel@tonic-gate */ 12570Sstevel@tonic-gate for (cursor = description->xmlChildrenNode; cursor != NULL; 12580Sstevel@tonic-gate cursor = cursor->next) { 12590Sstevel@tonic-gate if (lxml_ignorable_block(cursor)) 12600Sstevel@tonic-gate continue; 12610Sstevel@tonic-gate 12620Sstevel@tonic-gate switch (lxml_xlate_element(cursor->name)) { 12630Sstevel@tonic-gate case SC_LOCTEXT: 12640Sstevel@tonic-gate if (lxml_get_loctext(service, pg, cursor)) 12650Sstevel@tonic-gate return (-1); 12660Sstevel@tonic-gate break; 12670Sstevel@tonic-gate default: 12680Sstevel@tonic-gate uu_die(gettext("illegal element \"%s\" on description " 12690Sstevel@tonic-gate "element for \"%s\"\n"), cursor->name, 12700Sstevel@tonic-gate service->sc_name); 12710Sstevel@tonic-gate break; 12720Sstevel@tonic-gate } 12730Sstevel@tonic-gate } 12740Sstevel@tonic-gate 12750Sstevel@tonic-gate return (0); 12760Sstevel@tonic-gate } 12770Sstevel@tonic-gate 12780Sstevel@tonic-gate static char * 12790Sstevel@tonic-gate lxml_label_to_groupname(const char *prefix, const char *in) 12800Sstevel@tonic-gate { 12810Sstevel@tonic-gate char *out, *cp; 12820Sstevel@tonic-gate size_t len, piece_len; 12830Sstevel@tonic-gate 12840Sstevel@tonic-gate out = uu_zalloc(2 * scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1); 12850Sstevel@tonic-gate if (out == NULL) 12860Sstevel@tonic-gate return (NULL); 12870Sstevel@tonic-gate 12880Sstevel@tonic-gate (void) strcpy(out, prefix); 12890Sstevel@tonic-gate (void) strcat(out, in); 12900Sstevel@tonic-gate 12910Sstevel@tonic-gate len = strlen(out); 12920Sstevel@tonic-gate if (len > max_scf_name_len) { 12930Sstevel@tonic-gate /* Use the first half and the second half. */ 12940Sstevel@tonic-gate piece_len = (max_scf_name_len - 2) / 2; 12950Sstevel@tonic-gate 12960Sstevel@tonic-gate (void) strncpy(out + piece_len, "..", 2); 12970Sstevel@tonic-gate 12980Sstevel@tonic-gate (void) strcpy(out + piece_len + 2, out + (len - piece_len)); 12990Sstevel@tonic-gate 13000Sstevel@tonic-gate len = strlen(out); 13010Sstevel@tonic-gate } 13020Sstevel@tonic-gate 13030Sstevel@tonic-gate /* 13040Sstevel@tonic-gate * Translate non-property characters to '_'. 13050Sstevel@tonic-gate */ 13060Sstevel@tonic-gate for (cp = out; *cp != '\0'; ++cp) { 13070Sstevel@tonic-gate if (!(isalnum(*cp) || *cp == '_' || *cp == '-')) 13080Sstevel@tonic-gate *cp = '_'; 13090Sstevel@tonic-gate } 13100Sstevel@tonic-gate 13110Sstevel@tonic-gate *cp = '\0'; 13120Sstevel@tonic-gate 13130Sstevel@tonic-gate return (out); 13140Sstevel@tonic-gate } 13150Sstevel@tonic-gate 13160Sstevel@tonic-gate static int 13170Sstevel@tonic-gate lxml_get_tm_manpage(entity_t *service, xmlNodePtr manpage) 13180Sstevel@tonic-gate { 13190Sstevel@tonic-gate pgroup_t *pg; 13200Sstevel@tonic-gate char *pgname; 13210Sstevel@tonic-gate xmlChar *title; 13220Sstevel@tonic-gate 13230Sstevel@tonic-gate /* 13240Sstevel@tonic-gate * Fetch title attribute, convert to something sanitized, and create 13250Sstevel@tonic-gate * property group. 13260Sstevel@tonic-gate */ 13270Sstevel@tonic-gate title = xmlGetProp(manpage, (xmlChar *)"title"); 13280Sstevel@tonic-gate pgname = (char *)lxml_label_to_groupname(SCF_PG_TM_MAN_PREFIX, 13290Sstevel@tonic-gate (const char *)title); 13300Sstevel@tonic-gate 13310Sstevel@tonic-gate pg = internal_pgroup_find_or_create(service, pgname, 13320Sstevel@tonic-gate (char *)SCF_GROUP_TEMPLATE); 13330Sstevel@tonic-gate 13340Sstevel@tonic-gate /* 13350Sstevel@tonic-gate * Each attribute is an astring property within the group. 13360Sstevel@tonic-gate */ 13370Sstevel@tonic-gate if (new_str_prop_from_attr(pg, "title", SCF_TYPE_ASTRING, manpage, 13380Sstevel@tonic-gate "title") != 0 || 13390Sstevel@tonic-gate new_str_prop_from_attr(pg, "section", SCF_TYPE_ASTRING, manpage, 13400Sstevel@tonic-gate "section") != 0 || 13410Sstevel@tonic-gate new_str_prop_from_attr(pg, "manpath", SCF_TYPE_ASTRING, manpage, 13420Sstevel@tonic-gate "manpath") != 0) 13430Sstevel@tonic-gate return (-1); 13440Sstevel@tonic-gate 13450Sstevel@tonic-gate return (0); 13460Sstevel@tonic-gate } 13470Sstevel@tonic-gate 13480Sstevel@tonic-gate static int 13490Sstevel@tonic-gate lxml_get_tm_doclink(entity_t *service, xmlNodePtr doc_link) 13500Sstevel@tonic-gate { 13510Sstevel@tonic-gate pgroup_t *pg; 13520Sstevel@tonic-gate char *pgname; 13530Sstevel@tonic-gate xmlChar *name; 13540Sstevel@tonic-gate 13550Sstevel@tonic-gate /* 13560Sstevel@tonic-gate * Fetch name attribute, convert name to something sanitized, and create 13570Sstevel@tonic-gate * property group. 13580Sstevel@tonic-gate */ 13590Sstevel@tonic-gate name = xmlGetProp(doc_link, (xmlChar *)"name"); 13600Sstevel@tonic-gate 13610Sstevel@tonic-gate pgname = (char *)lxml_label_to_groupname(SCF_PG_TM_DOC_PREFIX, 13620Sstevel@tonic-gate (const char *)name); 13630Sstevel@tonic-gate 13640Sstevel@tonic-gate pg = internal_pgroup_find_or_create(service, pgname, 13650Sstevel@tonic-gate (char *)SCF_GROUP_TEMPLATE); 13660Sstevel@tonic-gate 13670Sstevel@tonic-gate /* 13680Sstevel@tonic-gate * Each attribute is an astring property within the group. 13690Sstevel@tonic-gate */ 13700Sstevel@tonic-gate if (new_str_prop_from_attr(pg, "name", SCF_TYPE_ASTRING, doc_link, 13710Sstevel@tonic-gate "name") != 0 || 13720Sstevel@tonic-gate new_str_prop_from_attr(pg, "uri", SCF_TYPE_ASTRING, doc_link, 13730Sstevel@tonic-gate "uri") != 0) 13740Sstevel@tonic-gate return (-1); 13750Sstevel@tonic-gate 13760Sstevel@tonic-gate return (0); 13770Sstevel@tonic-gate } 13780Sstevel@tonic-gate 13790Sstevel@tonic-gate static int 13800Sstevel@tonic-gate lxml_get_tm_documentation(entity_t *service, xmlNodePtr documentation) 13810Sstevel@tonic-gate { 13820Sstevel@tonic-gate xmlNodePtr cursor; 13830Sstevel@tonic-gate 13840Sstevel@tonic-gate for (cursor = documentation->xmlChildrenNode; cursor != NULL; 13850Sstevel@tonic-gate cursor = cursor->next) { 13860Sstevel@tonic-gate if (lxml_ignorable_block(cursor)) 13870Sstevel@tonic-gate continue; 13880Sstevel@tonic-gate 13890Sstevel@tonic-gate switch (lxml_xlate_element(cursor->name)) { 13900Sstevel@tonic-gate case SC_MANPAGE: 13910Sstevel@tonic-gate (void) lxml_get_tm_manpage(service, cursor); 13920Sstevel@tonic-gate break; 13930Sstevel@tonic-gate case SC_DOC_LINK: 13940Sstevel@tonic-gate (void) lxml_get_tm_doclink(service, cursor); 13950Sstevel@tonic-gate break; 13960Sstevel@tonic-gate default: 13970Sstevel@tonic-gate uu_die(gettext("illegal element \"%s\" on template " 13980Sstevel@tonic-gate "for service \"%s\"\n"), 13990Sstevel@tonic-gate cursor->name, service->sc_name); 14000Sstevel@tonic-gate } 14010Sstevel@tonic-gate } 14020Sstevel@tonic-gate 14030Sstevel@tonic-gate return (0); 14040Sstevel@tonic-gate } 14050Sstevel@tonic-gate 14060Sstevel@tonic-gate static int 14070Sstevel@tonic-gate lxml_get_template(entity_t *service, xmlNodePtr templ) 14080Sstevel@tonic-gate { 14090Sstevel@tonic-gate xmlNodePtr cursor; 14100Sstevel@tonic-gate 14110Sstevel@tonic-gate for (cursor = templ->xmlChildrenNode; cursor != NULL; 14120Sstevel@tonic-gate cursor = cursor->next) { 14130Sstevel@tonic-gate if (lxml_ignorable_block(cursor)) 14140Sstevel@tonic-gate continue; 14150Sstevel@tonic-gate 14160Sstevel@tonic-gate switch (lxml_xlate_element(cursor->name)) { 14170Sstevel@tonic-gate case SC_COMMON_NAME: 14180Sstevel@tonic-gate (void) lxml_get_tm_common_name(service, cursor); 14190Sstevel@tonic-gate break; 14200Sstevel@tonic-gate case SC_DESCRIPTION: 14210Sstevel@tonic-gate (void) lxml_get_tm_description(service, cursor); 14220Sstevel@tonic-gate break; 14230Sstevel@tonic-gate case SC_DOCUMENTATION: 14240Sstevel@tonic-gate (void) lxml_get_tm_documentation(service, cursor); 14250Sstevel@tonic-gate break; 14260Sstevel@tonic-gate default: 14270Sstevel@tonic-gate uu_die(gettext("illegal element \"%s\" on template " 14280Sstevel@tonic-gate "for service \"%s\"\n"), 14290Sstevel@tonic-gate cursor->name, service->sc_name); 14300Sstevel@tonic-gate } 14310Sstevel@tonic-gate } 14320Sstevel@tonic-gate 14330Sstevel@tonic-gate return (0); 14340Sstevel@tonic-gate } 14350Sstevel@tonic-gate 14360Sstevel@tonic-gate static int 14370Sstevel@tonic-gate lxml_get_default_instance(entity_t *service, xmlNodePtr definst) 14380Sstevel@tonic-gate { 14390Sstevel@tonic-gate entity_t *i; 14400Sstevel@tonic-gate xmlChar *enabled; 14410Sstevel@tonic-gate pgroup_t *pg; 14420Sstevel@tonic-gate property_t *p; 14430Sstevel@tonic-gate char *package; 14440Sstevel@tonic-gate uint64_t enabled_val = 0; 14450Sstevel@tonic-gate 14460Sstevel@tonic-gate i = internal_instance_new("default"); 14470Sstevel@tonic-gate 14480Sstevel@tonic-gate if ((enabled = xmlGetProp(definst, (xmlChar *)enabled_attr)) != NULL) { 14490Sstevel@tonic-gate enabled_val = (strcmp(true, (const char *)enabled) == 0) ? 14500Sstevel@tonic-gate 1 : 0; 14510Sstevel@tonic-gate xmlFree(enabled); 14520Sstevel@tonic-gate } 14530Sstevel@tonic-gate 14540Sstevel@tonic-gate /* 14550Sstevel@tonic-gate * New general property group with enabled boolean property set. 14560Sstevel@tonic-gate */ 14570Sstevel@tonic-gate 14580Sstevel@tonic-gate pg = internal_pgroup_new(); 14590Sstevel@tonic-gate (void) internal_attach_pgroup(i, pg); 14600Sstevel@tonic-gate 14610Sstevel@tonic-gate pg->sc_pgroup_name = (char *)scf_pg_general; 14620Sstevel@tonic-gate pg->sc_pgroup_type = (char *)scf_group_framework; 14630Sstevel@tonic-gate pg->sc_pgroup_flags = 0; 14640Sstevel@tonic-gate 14650Sstevel@tonic-gate p = internal_property_create(SCF_PROPERTY_ENABLED, SCF_TYPE_BOOLEAN, 1, 14660Sstevel@tonic-gate enabled_val); 14670Sstevel@tonic-gate 14680Sstevel@tonic-gate (void) internal_attach_property(pg, p); 14690Sstevel@tonic-gate 14700Sstevel@tonic-gate /* 14710Sstevel@tonic-gate * Add general/package property if PKGINST is set. 14720Sstevel@tonic-gate */ 14730Sstevel@tonic-gate if ((package = getenv("PKGINST")) != NULL) { 14740Sstevel@tonic-gate p = internal_property_create(SCF_PROPERTY_PACKAGE, 14750Sstevel@tonic-gate SCF_TYPE_ASTRING, 1, package); 14760Sstevel@tonic-gate 14770Sstevel@tonic-gate (void) internal_attach_property(pg, p); 14780Sstevel@tonic-gate } 14790Sstevel@tonic-gate 14800Sstevel@tonic-gate return (internal_attach_entity(service, i)); 14810Sstevel@tonic-gate } 14820Sstevel@tonic-gate 14830Sstevel@tonic-gate /* 14840Sstevel@tonic-gate * Translate an instance element into an internal property tree, added to 14850Sstevel@tonic-gate * service. If apply is true, forbid subelements and set the enabled property 14860Sstevel@tonic-gate * to override. 14870Sstevel@tonic-gate */ 14880Sstevel@tonic-gate static int 14890Sstevel@tonic-gate lxml_get_instance(entity_t *service, xmlNodePtr inst, int apply) 14900Sstevel@tonic-gate { 14910Sstevel@tonic-gate entity_t *i; 14920Sstevel@tonic-gate pgroup_t *pg; 14930Sstevel@tonic-gate property_t *p; 14940Sstevel@tonic-gate xmlNodePtr cursor; 14950Sstevel@tonic-gate xmlChar *enabled; 14960Sstevel@tonic-gate int r; 14970Sstevel@tonic-gate 14980Sstevel@tonic-gate /* 14990Sstevel@tonic-gate * Fetch its attributes, as appropriate. 15000Sstevel@tonic-gate */ 15010Sstevel@tonic-gate i = internal_instance_new((char *)xmlGetProp(inst, 15020Sstevel@tonic-gate (xmlChar *)name_attr)); 15030Sstevel@tonic-gate 15040Sstevel@tonic-gate /* 15050Sstevel@tonic-gate * Note that this must be done before walking the children so that 15060Sstevel@tonic-gate * sc_fmri is set in case we enter lxml_get_dependent(). 15070Sstevel@tonic-gate */ 15080Sstevel@tonic-gate r = internal_attach_entity(service, i); 15090Sstevel@tonic-gate if (r != 0) 15100Sstevel@tonic-gate return (r); 15110Sstevel@tonic-gate 15120Sstevel@tonic-gate enabled = xmlGetProp(inst, (xmlChar *)enabled_attr); 15130Sstevel@tonic-gate 15140Sstevel@tonic-gate /* 15150Sstevel@tonic-gate * New general property group with enabled boolean property set. 15160Sstevel@tonic-gate */ 15170Sstevel@tonic-gate pg = internal_pgroup_new(); 15180Sstevel@tonic-gate (void) internal_attach_pgroup(i, pg); 15190Sstevel@tonic-gate 15200Sstevel@tonic-gate pg->sc_pgroup_name = (char *)scf_pg_general; 15210Sstevel@tonic-gate pg->sc_pgroup_type = (char *)scf_group_framework; 15220Sstevel@tonic-gate pg->sc_pgroup_flags = 0; 15230Sstevel@tonic-gate 15240Sstevel@tonic-gate p = internal_property_create(SCF_PROPERTY_ENABLED, SCF_TYPE_BOOLEAN, 1, 15250Sstevel@tonic-gate (uint64_t)(strcmp(true, (const char *)enabled) == 0 ? 1 : 0)); 15260Sstevel@tonic-gate 15270Sstevel@tonic-gate p->sc_property_override = apply; 15280Sstevel@tonic-gate 15290Sstevel@tonic-gate (void) internal_attach_property(pg, p); 15300Sstevel@tonic-gate 15310Sstevel@tonic-gate xmlFree(enabled); 15320Sstevel@tonic-gate 15330Sstevel@tonic-gate /* 15340Sstevel@tonic-gate * Walk its child elements, as appropriate. 15350Sstevel@tonic-gate */ 15360Sstevel@tonic-gate for (cursor = inst->xmlChildrenNode; cursor != NULL; 15370Sstevel@tonic-gate cursor = cursor->next) { 15380Sstevel@tonic-gate if (lxml_ignorable_block(cursor)) 15390Sstevel@tonic-gate continue; 15400Sstevel@tonic-gate 15410Sstevel@tonic-gate if (apply) { 15420Sstevel@tonic-gate semerr(gettext("Instance \"%s\" may not contain " 15430Sstevel@tonic-gate "elements in profiles.\n"), i->sc_name, 15440Sstevel@tonic-gate cursor->name); 15450Sstevel@tonic-gate return (-1); 15460Sstevel@tonic-gate } 15470Sstevel@tonic-gate 15480Sstevel@tonic-gate switch (lxml_xlate_element(cursor->name)) { 15490Sstevel@tonic-gate case SC_RESTARTER: 15500Sstevel@tonic-gate (void) lxml_get_restarter(i, cursor); 15510Sstevel@tonic-gate break; 15520Sstevel@tonic-gate case SC_DEPENDENCY: 15530Sstevel@tonic-gate (void) lxml_get_dependency(i, cursor); 15540Sstevel@tonic-gate break; 15550Sstevel@tonic-gate case SC_DEPENDENT: 15560Sstevel@tonic-gate (void) lxml_get_dependent(i, cursor); 15570Sstevel@tonic-gate break; 15580Sstevel@tonic-gate case SC_METHOD_CONTEXT: 15590Sstevel@tonic-gate (void) lxml_get_entity_method_context(i, cursor); 15600Sstevel@tonic-gate break; 15610Sstevel@tonic-gate case SC_EXEC_METHOD: 15620Sstevel@tonic-gate (void) lxml_get_exec_method(i, cursor); 15630Sstevel@tonic-gate break; 15640Sstevel@tonic-gate case SC_PROPERTY_GROUP: 15650Sstevel@tonic-gate (void) lxml_get_pgroup(i, cursor); 15660Sstevel@tonic-gate break; 15670Sstevel@tonic-gate case SC_TEMPLATE: 15680Sstevel@tonic-gate (void) lxml_get_template(i, cursor); 15690Sstevel@tonic-gate break; 15700Sstevel@tonic-gate default: 15710Sstevel@tonic-gate uu_die(gettext( 15720Sstevel@tonic-gate "illegal element \"%s\" on instance \"%s\"\n"), 15730Sstevel@tonic-gate cursor->name, i->sc_name); 15740Sstevel@tonic-gate break; 15750Sstevel@tonic-gate } 15760Sstevel@tonic-gate } 15770Sstevel@tonic-gate 15780Sstevel@tonic-gate return (0); 15790Sstevel@tonic-gate } 15800Sstevel@tonic-gate 15810Sstevel@tonic-gate /* ARGSUSED1 */ 15820Sstevel@tonic-gate static int 15830Sstevel@tonic-gate lxml_get_single_instance(entity_t *entity, xmlNodePtr si) 15840Sstevel@tonic-gate { 15850Sstevel@tonic-gate pgroup_t *pg; 15860Sstevel@tonic-gate property_t *p; 15870Sstevel@tonic-gate int r; 15880Sstevel@tonic-gate 15890Sstevel@tonic-gate pg = internal_pgroup_find_or_create(entity, (char *)scf_pg_general, 15900Sstevel@tonic-gate (char *)scf_group_framework); 15910Sstevel@tonic-gate 15920Sstevel@tonic-gate p = internal_property_create(SCF_PROPERTY_SINGLE_INSTANCE, 15930Sstevel@tonic-gate SCF_TYPE_BOOLEAN, 1, (uint64_t)1); 15940Sstevel@tonic-gate 15950Sstevel@tonic-gate r = internal_attach_property(pg, p); 15960Sstevel@tonic-gate if (r != 0) { 15970Sstevel@tonic-gate internal_property_free(p); 15980Sstevel@tonic-gate return (-1); 15990Sstevel@tonic-gate } 16000Sstevel@tonic-gate 16010Sstevel@tonic-gate return (0); 16020Sstevel@tonic-gate } 16030Sstevel@tonic-gate 16040Sstevel@tonic-gate /* 16050Sstevel@tonic-gate * Translate a service element into an internal instance/property tree, added 16060Sstevel@tonic-gate * to bundle. If apply is true, allow only instance subelements. 16070Sstevel@tonic-gate */ 16080Sstevel@tonic-gate static int 16090Sstevel@tonic-gate lxml_get_service(bundle_t *bundle, xmlNodePtr svc, int apply) 16100Sstevel@tonic-gate { 16110Sstevel@tonic-gate entity_t *s; 16120Sstevel@tonic-gate xmlNodePtr cursor; 16130Sstevel@tonic-gate xmlChar *type; 16140Sstevel@tonic-gate xmlChar *version; 16150Sstevel@tonic-gate int e; 16160Sstevel@tonic-gate 16170Sstevel@tonic-gate /* 16180Sstevel@tonic-gate * Fetch attributes, as appropriate. 16190Sstevel@tonic-gate */ 16200Sstevel@tonic-gate s = internal_service_new((char *)xmlGetProp(svc, 16210Sstevel@tonic-gate (xmlChar *)name_attr)); 16220Sstevel@tonic-gate 16230Sstevel@tonic-gate version = xmlGetProp(svc, (xmlChar *)"version"); 16240Sstevel@tonic-gate s->sc_u.sc_service.sc_service_version = atol((const char *)version); 16250Sstevel@tonic-gate xmlFree(version); 16260Sstevel@tonic-gate 16270Sstevel@tonic-gate type = xmlGetProp(svc, (xmlChar *)type_attr); 16280Sstevel@tonic-gate s->sc_u.sc_service.sc_service_type = lxml_xlate_service_type(type); 16290Sstevel@tonic-gate xmlFree(type); 16300Sstevel@tonic-gate 16310Sstevel@tonic-gate /* 16320Sstevel@tonic-gate * Walk its child elements, as appropriate. 16330Sstevel@tonic-gate */ 16340Sstevel@tonic-gate for (cursor = svc->xmlChildrenNode; cursor != NULL; 16350Sstevel@tonic-gate cursor = cursor->next) { 16360Sstevel@tonic-gate if (lxml_ignorable_block(cursor)) 16370Sstevel@tonic-gate continue; 16380Sstevel@tonic-gate 16390Sstevel@tonic-gate e = lxml_xlate_element(cursor->name); 16400Sstevel@tonic-gate 16410Sstevel@tonic-gate if (apply && e != SC_INSTANCE) { 16420Sstevel@tonic-gate semerr(gettext("Service \"%s\" may not contain the " 16430Sstevel@tonic-gate "non-instance element \"%s\" in a profile.\n"), 16440Sstevel@tonic-gate s->sc_name, cursor->name); 16450Sstevel@tonic-gate 16460Sstevel@tonic-gate return (-1); 16470Sstevel@tonic-gate } 16480Sstevel@tonic-gate 16490Sstevel@tonic-gate switch (e) { 16500Sstevel@tonic-gate case SC_INSTANCE: 16510Sstevel@tonic-gate (void) lxml_get_instance(s, cursor, apply); 16520Sstevel@tonic-gate break; 16530Sstevel@tonic-gate case SC_TEMPLATE: 16540Sstevel@tonic-gate (void) lxml_get_template(s, cursor); 16550Sstevel@tonic-gate break; 16560Sstevel@tonic-gate case SC_STABILITY: 16570Sstevel@tonic-gate (void) lxml_get_entity_stability(s, cursor); 16580Sstevel@tonic-gate break; 16590Sstevel@tonic-gate case SC_DEPENDENCY: 16600Sstevel@tonic-gate (void) lxml_get_dependency(s, cursor); 16610Sstevel@tonic-gate break; 16620Sstevel@tonic-gate case SC_DEPENDENT: 16630Sstevel@tonic-gate (void) lxml_get_dependent(s, cursor); 16640Sstevel@tonic-gate break; 16650Sstevel@tonic-gate case SC_RESTARTER: 16660Sstevel@tonic-gate (void) lxml_get_restarter(s, cursor); 16670Sstevel@tonic-gate break; 16680Sstevel@tonic-gate case SC_EXEC_METHOD: 16690Sstevel@tonic-gate (void) lxml_get_exec_method(s, cursor); 16700Sstevel@tonic-gate break; 16710Sstevel@tonic-gate case SC_METHOD_CONTEXT: 16720Sstevel@tonic-gate (void) lxml_get_entity_method_context(s, cursor); 16730Sstevel@tonic-gate break; 16740Sstevel@tonic-gate case SC_PROPERTY_GROUP: 16750Sstevel@tonic-gate (void) lxml_get_pgroup(s, cursor); 16760Sstevel@tonic-gate break; 16770Sstevel@tonic-gate case SC_INSTANCE_CREATE_DEFAULT: 16780Sstevel@tonic-gate (void) lxml_get_default_instance(s, cursor); 16790Sstevel@tonic-gate break; 16800Sstevel@tonic-gate case SC_INSTANCE_SINGLE: 16810Sstevel@tonic-gate (void) lxml_get_single_instance(s, cursor); 16820Sstevel@tonic-gate break; 16830Sstevel@tonic-gate default: 16840Sstevel@tonic-gate uu_die(gettext( 16850Sstevel@tonic-gate "illegal element \"%s\" on service \"%s\"\n"), 16860Sstevel@tonic-gate cursor->name, s->sc_name); 16870Sstevel@tonic-gate break; 16880Sstevel@tonic-gate } 16890Sstevel@tonic-gate } 16900Sstevel@tonic-gate 16910Sstevel@tonic-gate return (internal_attach_service(bundle, s)); 16920Sstevel@tonic-gate } 16930Sstevel@tonic-gate 16940Sstevel@tonic-gate #ifdef DEBUG 16950Sstevel@tonic-gate void 16960Sstevel@tonic-gate lxml_dump(int g, xmlNodePtr p) 16970Sstevel@tonic-gate { 16980Sstevel@tonic-gate if (p && p->name) { 16990Sstevel@tonic-gate printf("%d %s\n", g, p->name); 17000Sstevel@tonic-gate 17010Sstevel@tonic-gate for (p = p->xmlChildrenNode; p != NULL; p = p->next) 17020Sstevel@tonic-gate lxml_dump(g + 1, p); 17030Sstevel@tonic-gate } 17040Sstevel@tonic-gate } 17050Sstevel@tonic-gate #endif /* DEBUG */ 17060Sstevel@tonic-gate 17070Sstevel@tonic-gate static int 17080Sstevel@tonic-gate lxml_is_known_dtd(const xmlChar *dtdname) 17090Sstevel@tonic-gate { 17100Sstevel@tonic-gate if (dtdname == NULL || 17110Sstevel@tonic-gate strcmp(MANIFEST_DTD_PATH, (const char *)dtdname) != 0) 17120Sstevel@tonic-gate return (0); 17130Sstevel@tonic-gate 17140Sstevel@tonic-gate return (1); 17150Sstevel@tonic-gate } 17160Sstevel@tonic-gate 17170Sstevel@tonic-gate static int 17180Sstevel@tonic-gate lxml_get_bundle(bundle_t *bundle, bundle_type_t bundle_type, 17190Sstevel@tonic-gate xmlNodePtr subbundle, int apply) 17200Sstevel@tonic-gate { 17210Sstevel@tonic-gate xmlNodePtr cursor; 17220Sstevel@tonic-gate xmlChar *type; 17230Sstevel@tonic-gate int e; 17240Sstevel@tonic-gate 17250Sstevel@tonic-gate /* 17260Sstevel@tonic-gate * 1. Get bundle attributes. 17270Sstevel@tonic-gate */ 17280Sstevel@tonic-gate type = xmlGetProp(subbundle, (xmlChar *)"type"); 17290Sstevel@tonic-gate bundle->sc_bundle_type = lxml_xlate_bundle_type(type); 17300Sstevel@tonic-gate if (bundle->sc_bundle_type != bundle_type && 17310Sstevel@tonic-gate bundle_type != SVCCFG_UNKNOWN_BUNDLE) { 17320Sstevel@tonic-gate semerr(gettext("included bundle of different type.\n")); 17330Sstevel@tonic-gate return (-1); 17340Sstevel@tonic-gate } 17350Sstevel@tonic-gate 17360Sstevel@tonic-gate xmlFree(type); 17370Sstevel@tonic-gate 17380Sstevel@tonic-gate if (!apply) { 17390Sstevel@tonic-gate if (bundle->sc_bundle_type != SVCCFG_MANIFEST) { 17400Sstevel@tonic-gate semerr(gettext("document is not a manifest.\n")); 17410Sstevel@tonic-gate return (-1); 17420Sstevel@tonic-gate } 17430Sstevel@tonic-gate } else { 17440Sstevel@tonic-gate if (bundle->sc_bundle_type != SVCCFG_PROFILE) { 17450Sstevel@tonic-gate semerr(gettext("document is not a profile.\n")); 17460Sstevel@tonic-gate return (-1); 17470Sstevel@tonic-gate } 17480Sstevel@tonic-gate } 17490Sstevel@tonic-gate 17500Sstevel@tonic-gate if ((bundle->sc_bundle_name = xmlGetProp(subbundle, 17510Sstevel@tonic-gate (xmlChar *)"name")) == NULL) { 17520Sstevel@tonic-gate semerr(gettext("service bundle lacks name attribute\n")); 17530Sstevel@tonic-gate return (-1); 17540Sstevel@tonic-gate } 17550Sstevel@tonic-gate 17560Sstevel@tonic-gate /* 17570Sstevel@tonic-gate * 2. Get services, descend into each one and build state. 17580Sstevel@tonic-gate */ 17590Sstevel@tonic-gate for (cursor = subbundle->xmlChildrenNode; cursor != NULL; 17600Sstevel@tonic-gate cursor = cursor->next) { 17610Sstevel@tonic-gate if (lxml_ignorable_block(cursor)) 17620Sstevel@tonic-gate continue; 17630Sstevel@tonic-gate 17640Sstevel@tonic-gate e = lxml_xlate_element(cursor->name); 17650Sstevel@tonic-gate 17660Sstevel@tonic-gate switch (e) { 17670Sstevel@tonic-gate case SC_XI_INCLUDE: 17680Sstevel@tonic-gate continue; 17690Sstevel@tonic-gate 17700Sstevel@tonic-gate case SC_SERVICE_BUNDLE: 17710Sstevel@tonic-gate if (lxml_get_bundle(bundle, bundle_type, cursor, apply)) 17720Sstevel@tonic-gate return (-1); 17730Sstevel@tonic-gate break; 17740Sstevel@tonic-gate case SC_SERVICE: 17750Sstevel@tonic-gate (void) lxml_get_service(bundle, cursor, apply); 17760Sstevel@tonic-gate break; 17770Sstevel@tonic-gate } 17780Sstevel@tonic-gate } 17790Sstevel@tonic-gate 17800Sstevel@tonic-gate return (0); 17810Sstevel@tonic-gate } 17820Sstevel@tonic-gate 17830Sstevel@tonic-gate /* 17840Sstevel@tonic-gate * Load an XML tree from filename and translate it into an internal service 17850Sstevel@tonic-gate * tree bundle. If apply is false, require that the the bundle be of type 17860Sstevel@tonic-gate * manifest, or type profile otherwise. 17870Sstevel@tonic-gate */ 17880Sstevel@tonic-gate int 17890Sstevel@tonic-gate lxml_get_bundle_file(bundle_t *bundle, const char *filename, int apply) 17900Sstevel@tonic-gate { 17910Sstevel@tonic-gate xmlDocPtr document; 17920Sstevel@tonic-gate xmlNodePtr cursor; 17930Sstevel@tonic-gate xmlDtdPtr dtd = NULL; 17940Sstevel@tonic-gate xmlValidCtxtPtr vcp; 17950Sstevel@tonic-gate boolean_t do_validate; 17960Sstevel@tonic-gate char *dtdpath = NULL; 17970Sstevel@tonic-gate int r; 17980Sstevel@tonic-gate 17990Sstevel@tonic-gate /* 18000Sstevel@tonic-gate * Until libxml2 addresses DTD-based validation with XInclude, we don't 18010Sstevel@tonic-gate * validate service profiles (i.e. the apply path). 18020Sstevel@tonic-gate */ 18030Sstevel@tonic-gate do_validate = (apply == 0) && (getenv("SVCCFG_NOVALIDATE") == NULL); 18040Sstevel@tonic-gate if (do_validate) 18050Sstevel@tonic-gate dtdpath = getenv("SVCCFG_DTD"); 18060Sstevel@tonic-gate 18070Sstevel@tonic-gate if (dtdpath != NULL) 18080Sstevel@tonic-gate xmlLoadExtDtdDefaultValue = 0; 18090Sstevel@tonic-gate 18100Sstevel@tonic-gate if ((document = xmlReadFile(filename, NULL, 18110Sstevel@tonic-gate XML_PARSE_NOERROR | XML_PARSE_NOWARNING)) == NULL) { 18120Sstevel@tonic-gate semerr(gettext("couldn't parse document\n")); 18130Sstevel@tonic-gate return (-1); 18140Sstevel@tonic-gate } 18150Sstevel@tonic-gate 18160Sstevel@tonic-gate /* 18170Sstevel@tonic-gate * Verify that this is a document type we understand. 18180Sstevel@tonic-gate */ 18190Sstevel@tonic-gate if ((dtd = xmlGetIntSubset(document)) == NULL) { 18200Sstevel@tonic-gate semerr(gettext("document has no DTD\n")); 18210Sstevel@tonic-gate return (-1); 18220Sstevel@tonic-gate } 18230Sstevel@tonic-gate 18240Sstevel@tonic-gate if (!lxml_is_known_dtd(dtd->SystemID)) { 18250Sstevel@tonic-gate semerr(gettext("document DTD unknown; not service bundle?\n")); 18260Sstevel@tonic-gate return (-1); 18270Sstevel@tonic-gate } 18280Sstevel@tonic-gate 18290Sstevel@tonic-gate if ((cursor = xmlDocGetRootElement(document)) == NULL) { 18300Sstevel@tonic-gate semerr(gettext("document is empty\n")); 18310Sstevel@tonic-gate xmlFreeDoc(document); 18320Sstevel@tonic-gate return (-1); 18330Sstevel@tonic-gate } 18340Sstevel@tonic-gate 18350Sstevel@tonic-gate if (xmlStrcmp(cursor->name, (const xmlChar *)"service_bundle") != 0) { 18360Sstevel@tonic-gate semerr(gettext("document is not a service bundle\n")); 18370Sstevel@tonic-gate xmlFreeDoc(document); 18380Sstevel@tonic-gate return (-1); 18390Sstevel@tonic-gate } 18400Sstevel@tonic-gate 18410Sstevel@tonic-gate 18420Sstevel@tonic-gate if (dtdpath != NULL) { 18430Sstevel@tonic-gate dtd = xmlParseDTD(NULL, (xmlChar *)dtdpath); 18440Sstevel@tonic-gate if (dtd == NULL) { 18450Sstevel@tonic-gate semerr(gettext("Could not parse DTD \"%s\".\n"), 18460Sstevel@tonic-gate dtdpath); 18470Sstevel@tonic-gate return (-1); 18480Sstevel@tonic-gate } 18490Sstevel@tonic-gate 18500Sstevel@tonic-gate if (document->extSubset != NULL) 18510Sstevel@tonic-gate xmlFreeDtd(document->extSubset); 18520Sstevel@tonic-gate 18530Sstevel@tonic-gate document->extSubset = dtd; 18540Sstevel@tonic-gate } 18550Sstevel@tonic-gate 18560Sstevel@tonic-gate if (xmlXIncludeProcessFlags(document, XML_PARSE_XINCLUDE) == -1) {; 18570Sstevel@tonic-gate semerr(gettext("couldn't handle XInclude statements " 18580Sstevel@tonic-gate "in document\n")); 18590Sstevel@tonic-gate return (-1); 18600Sstevel@tonic-gate } 18610Sstevel@tonic-gate 18620Sstevel@tonic-gate if (do_validate) { 18630Sstevel@tonic-gate vcp = xmlNewValidCtxt(); 18640Sstevel@tonic-gate if (vcp == NULL) 18650Sstevel@tonic-gate uu_die(gettext("could not allocate memory")); 18660Sstevel@tonic-gate vcp->warning = xmlParserValidityWarning; 18670Sstevel@tonic-gate vcp->error = xmlParserValidityError; 18680Sstevel@tonic-gate 18690Sstevel@tonic-gate r = xmlValidateDocument(vcp, document); 18700Sstevel@tonic-gate 18710Sstevel@tonic-gate xmlFreeValidCtxt(vcp); 18720Sstevel@tonic-gate 18730Sstevel@tonic-gate if (r == 0) { 18740Sstevel@tonic-gate semerr(gettext("Document is not valid.\n")); 18750Sstevel@tonic-gate xmlFreeDoc(document); 18760Sstevel@tonic-gate return (-1); 18770Sstevel@tonic-gate } 18780Sstevel@tonic-gate } 18790Sstevel@tonic-gate 18800Sstevel@tonic-gate 18810Sstevel@tonic-gate #ifdef DEBUG 18820Sstevel@tonic-gate lxml_dump(0, cursor); 18830Sstevel@tonic-gate #endif /* DEBUG */ 18840Sstevel@tonic-gate 18850Sstevel@tonic-gate r = lxml_get_bundle(bundle, SVCCFG_UNKNOWN_BUNDLE, cursor, apply); 18860Sstevel@tonic-gate 18870Sstevel@tonic-gate xmlFreeDoc(document); 18880Sstevel@tonic-gate 18890Sstevel@tonic-gate return (r); 18900Sstevel@tonic-gate } 18910Sstevel@tonic-gate 18920Sstevel@tonic-gate int 18930Sstevel@tonic-gate lxml_inventory(const char *filename) 18940Sstevel@tonic-gate { 18950Sstevel@tonic-gate bundle_t *b; 18960Sstevel@tonic-gate uu_list_walk_t *svcs, *insts; 18970Sstevel@tonic-gate entity_t *svc, *inst; 18980Sstevel@tonic-gate 18990Sstevel@tonic-gate b = internal_bundle_new(); 19000Sstevel@tonic-gate 19010Sstevel@tonic-gate if (lxml_get_bundle_file(b, filename, 0) != 0) { 19020Sstevel@tonic-gate internal_bundle_free(b); 19030Sstevel@tonic-gate return (-1); 19040Sstevel@tonic-gate } 19050Sstevel@tonic-gate 19060Sstevel@tonic-gate svcs = uu_list_walk_start(b->sc_bundle_services, 0); 19070Sstevel@tonic-gate if (svcs == NULL) 19080Sstevel@tonic-gate uu_die(gettext("Couldn't walk services")); 19090Sstevel@tonic-gate 19100Sstevel@tonic-gate while ((svc = uu_list_walk_next(svcs)) != NULL) { 19110Sstevel@tonic-gate uu_list_t *inst_list; 19120Sstevel@tonic-gate 19130Sstevel@tonic-gate inst_list = svc->sc_u.sc_service.sc_service_instances; 19140Sstevel@tonic-gate insts = uu_list_walk_start(inst_list, 0); 19150Sstevel@tonic-gate if (insts == NULL) 19160Sstevel@tonic-gate uu_die(gettext("Couldn't walk instances")); 19170Sstevel@tonic-gate 19180Sstevel@tonic-gate while ((inst = uu_list_walk_next(insts)) != NULL) 19190Sstevel@tonic-gate (void) printf("svc:/%s:%s\n", svc->sc_name, 19200Sstevel@tonic-gate inst->sc_name); 19210Sstevel@tonic-gate 19220Sstevel@tonic-gate uu_list_walk_end(insts); 19230Sstevel@tonic-gate } 19240Sstevel@tonic-gate 19250Sstevel@tonic-gate uu_list_walk_end(svcs); 19260Sstevel@tonic-gate 19270Sstevel@tonic-gate svcs = uu_list_walk_start(b->sc_bundle_services, 0); 19280Sstevel@tonic-gate while ((svc = uu_list_walk_next(svcs)) != NULL) { 19290Sstevel@tonic-gate (void) fputs("svc:/", stdout); 19300Sstevel@tonic-gate (void) puts(svc->sc_name); 19310Sstevel@tonic-gate } 19320Sstevel@tonic-gate uu_list_walk_end(svcs); 19330Sstevel@tonic-gate 19340Sstevel@tonic-gate internal_bundle_free(b); 19350Sstevel@tonic-gate 19360Sstevel@tonic-gate return (0); 19370Sstevel@tonic-gate } 1938