4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25 /*
26 * XML document manipulation routines
27 *
28 * These routines provide translation to and from the internal representation to
29 * XML. Directionally-oriented verbs are with respect to the external source,
30 * so lxml_get_service() fetches a service from the XML file into the
31 * internal representation.
32 */
33
34 #include <libxml/parser.h>
35 #include <libxml/xinclude.h>
36
37 #include <assert.h>
38 #include <ctype.h>
39 #include <errno.h>
40 #include <libintl.h>
41 #include <libscf.h>
42 #include <libscf_priv.h>
43 #include <libuutil.h>
563 v->sc_u.sc_integer = strtoll((char *)value, &endptr, 10);
564 if (errno != 0 || *endptr)
565 uu_die(gettext("illegal value \"%s\" for "
566 "%s (%s)\n"), (char *)value,
567 lxml_prop_types[type],
568 (errno) ? strerror(errno) : "Illegal character");
569 break;
570 case SC_OPAQUE:
571 case SC_HOST:
572 case SC_HOSTNAME:
573 case SC_NET_ADDR:
574 case SC_NET_ADDR_V4:
575 case SC_NET_ADDR_V6:
576 case SC_FMRI:
577 case SC_URI:
578 case SC_TIME:
579 case SC_ASTRING:
580 case SC_USTRING:
581 scf_type = lxml_element_to_type(type);
582
583 if ((v->sc_u.sc_string = strdup((char *)value)) == NULL)
584 uu_die(gettext("string duplication failed (%s)\n"),
585 strerror(errno));
586 if (lxml_validate_string_value(scf_type,
587 v->sc_u.sc_string) != 0)
588 uu_die(gettext("illegal value \"%s\" for "
589 "%s (%s)\n"), (char *)value,
590 lxml_prop_types[type],
591 (scf_error()) ? scf_strerror(scf_error()) :
592 gettext("Illegal format"));
593 v->sc_free = lxml_free_str;
594 break;
595 case SC_BOOLEAN:
596 v->sc_u.sc_count = lxml_xlate_boolean(value);
597 break;
598 default:
599 uu_die(gettext("unknown value type (%d)\n"), type);
600 break;
601 }
602
603 /* Free the old value */
604 if (fov && v->sc_free != NULL)
605 free((char *)value);
1353
1354 pg = internal_pgroup_find_or_create(entity, "dependents",
1355 (char *)scf_group_framework);
1356 p = internal_property_create((char *)name, SCF_TYPE_FMRI, 1, fmri);
1357 if (internal_attach_property(pg, p) != 0)
1358 return (-1);
1359
1360 return (0);
1361 }
1362
1363 static int
1364 lxml_get_entity_stability(entity_t *entity, xmlNodePtr rstr)
1365 {
1366 pgroup_t *pg;
1367 property_t *p;
1368 xmlChar *stabval;
1369
1370 if (((stabval = xmlGetProp(rstr, (xmlChar *)value_attr)) == NULL) ||
1371 (*stabval == 0)) {
1372 uu_warn(gettext("no stability value found\n"));
1373 stabval = (xmlChar *)strdup("External");
1374 }
1375
1376 pg = internal_pgroup_find_or_create(entity, (char *)scf_pg_general,
1377 (char *)scf_group_framework);
1378
1379 p = internal_property_create(SCF_PROPERTY_ENTITY_STABILITY,
1380 SCF_TYPE_ASTRING, 1, stabval);
1381
1382 return (internal_attach_property(pg, p));
1383 }
1384
1385 static int
1386 lxml_get_restarter(entity_t *entity, xmlNodePtr rstr)
1387 {
1388 pgroup_t *pg;
1389 property_t *p;
1390 xmlChar *restarter;
1391 xmlNode *cursor;
1392 int r;
1393
1421
1422 p = internal_property_create(SCF_PROPERTY_RESTARTER, SCF_TYPE_FMRI, 1,
1423 restarter);
1424
1425 r = internal_attach_property(pg, p);
1426 if (r != 0) {
1427 internal_property_free(p);
1428 return (-1);
1429 }
1430
1431 return (0);
1432 }
1433
1434 static void
1435 lxml_get_paramval(pgroup_t *pgrp, const char *propname, xmlNodePtr pval)
1436 {
1437 property_t *p;
1438 char *value;
1439 char *prop;
1440
1441 if ((prop = strdup(propname)) == NULL)
1442 uu_die(gettext("Out of memory.\n"));
1443
1444 value = (char *)xmlGetProp(pval, (xmlChar *)value_attr);
1445 if (value == NULL || *value == '\0')
1446 uu_die(gettext("property value missing for property '%s/%s'\n"),
1447 pgrp->sc_pgroup_name, propname);
1448 p = internal_property_create(prop, SCF_TYPE_ASTRING, 1, value);
1449
1450 (void) internal_attach_property(pgrp, p);
1451 }
1452
1453 static void
1454 lxml_get_parameter(pgroup_t *pgrp, const char *propname, xmlNodePtr param)
1455 {
1456 property_t *p = internal_property_new();
1457
1458 if ((p->sc_property_name = strdup(propname)) == NULL)
1459 uu_die(gettext("Out of memory.\n"));
1460 p->sc_value_type = SCF_TYPE_ASTRING;
1461
1462 (void) lxml_get_value(p, SC_ASTRING, param);
1463
1464 (void) internal_attach_property(pgrp, p);
1465 }
1466
1467 static void
1468 lxml_get_type(pgroup_t *pgrp, xmlNodePtr type)
1469 {
1470 property_t *p;
1471 xmlChar *name;
1472 xmlChar *active;
1473 xmlNodePtr cursor;
1474 uint64_t active_val;
1475 size_t sz = max_scf_name_len + 1;
1476 char *propname = safe_malloc(sz);
1477
1478 if (pgrp->sc_parent->sc_op == SVCCFG_OP_APPLY)
1479 lxml_validate_element(type);
1690
1691 for (cursor = loctext->xmlChildrenNode; cursor != NULL;
1692 cursor = cursor->next) {
1693 if (strcmp("text", (const char *)cursor->name) == 0) {
1694 break;
1695 } else if (strcmp("comment", (const char *)cursor->name) != 0) {
1696 uu_die(gettext("illegal element \"%s\" on loctext "
1697 "element for \"%s\"\n"), cursor->name,
1698 service->sc_name);
1699 }
1700 }
1701
1702 if (cursor == NULL) {
1703 uu_die(gettext("loctext element has no content for \"%s\"\n"),
1704 service->sc_name);
1705 }
1706
1707 /*
1708 * Remove leading and trailing whitespace.
1709 */
1710 if ((stripped = strdup((const char *)cursor->content)) == NULL)
1711 uu_die(gettext("Out of memory\n"));
1712
1713 for (; isspace(*stripped); stripped++)
1714 ;
1715 for (cp = stripped + strlen(stripped) - 1; isspace(*cp); cp--)
1716 ;
1717 *(cp + 1) = '\0';
1718
1719 p = internal_property_create(prop_name, SCF_TYPE_USTRING, 1,
1720 stripped);
1721
1722 r = internal_attach_property(pg, p);
1723 if (r != 0) {
1724 internal_property_free(p);
1725 free(prop_name);
1726 }
1727
1728 return (r);
1729 }
1730
1731 /*
1927 lxml_get_tm_description(entity_t *service, xmlNodePtr description)
1928 {
1929 pgroup_t *pg;
1930
1931 /*
1932 * Create the property group, if absent.
1933 */
1934 pg = internal_pgroup_find_or_create(service, SCF_PG_TM_DESCRIPTION,
1935 SCF_GROUP_TEMPLATE);
1936
1937 return (lxml_get_all_loctext(service, pg, description,
1938 LOCALE_ONLY_FMT, "description"));
1939 }
1940
1941 static char *
1942 lxml_label_to_groupname(const char *prefix, const char *in)
1943 {
1944 char *out, *cp;
1945 size_t len, piece_len;
1946
1947 out = uu_zalloc(2 * scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1);
1948 if (out == NULL)
1949 return (NULL);
1950
1951 (void) strcpy(out, prefix);
1952 (void) strcat(out, in);
1953
1954 len = strlen(out);
1955 if (len > max_scf_name_len) {
1956 /* Use the first half and the second half. */
1957 piece_len = (max_scf_name_len - 2) / 2;
1958
1959 (void) strncpy(out + piece_len, "..", 2);
1960
1961 (void) strcpy(out + piece_len + 2, out + (len - piece_len));
1962
1963 len = strlen(out);
1964 }
1965
1966 /*
1967 * Translate non-property characters to '_'.
1968 */
1969 for (cp = out; *cp != '\0'; ++cp) {
1970 if (!(isalnum(*cp) || *cp == '_' || *cp == '-'))
1971 *cp = '_';
1972 }
1973
1974 *cp = '\0';
1975
1976 return (out);
1977 }
1978
1979 /*
1980 * If *p is NULL, astring_prop_value() first creates a property with the
1981 * name specified in prop_name. The address of the newly created property
1982 * is placed in *p.
1983 *
1984 * In either case, newly created property or existing property, a new
1985 * SCF_TYPE_ASTRING value will created and attached to the property at *p.
1986 * The value of the newly created property is prop_value.
1987 *
1988 * free_flag is used to indicate whether or not the memory at prop_value
1989 * should be freed when the property is freed by a call to
1990 * internal_property_free().
1991 */
1992 static void
1993 astring_prop_value(property_t **p, const char *prop_name, char *prop_value,
1994 boolean_t free_flag)
1995 {
2019 static void
2020 seps_to_prop_values(property_t **p, xmlChar *seps)
2021 {
2022 value_t *v;
2023 char val_str[2];
2024
2025 if (*p == NULL) {
2026 *p = internal_property_new();
2027 (*p)->sc_property_name =
2028 (char *)SCF_PROPERTY_INTERNAL_SEPARATORS;
2029 (*p)->sc_value_type = SCF_TYPE_ASTRING;
2030 }
2031
2032 /* Add the values to the property's list. */
2033 val_str[1] = 0; /* Terminate the string. */
2034 for (; *seps != 0; seps++) {
2035 v = internal_value_new();
2036 v->sc_type = (*p)->sc_value_type;
2037 v->sc_free = lxml_free_str;
2038 val_str[0] = *seps;
2039 v->sc_u.sc_string = strdup(val_str);
2040 if (v->sc_u.sc_string == NULL)
2041 uu_die(gettext("Out of memory\n"));
2042 internal_attach_value(*p, v);
2043 }
2044 }
2045
2046 /*
2047 * Create an internal_separators property and attach it to the property
2048 * group at pg. The separator characters are provided in the text nodes
2049 * that are the children of seps. Each separator character is stored as a
2050 * property value in the internal_separators property.
2051 */
2052 static int
2053 lxml_get_tm_internal_seps(entity_t *service, pgroup_t *pg, xmlNodePtr seps)
2054 {
2055 xmlNodePtr cursor;
2056 property_t *prop = NULL;
2057 int r;
2058
2059 for (cursor = seps->xmlChildrenNode; cursor != NULL;
2060 cursor = cursor->next) {
2061 if (strcmp("text", (const char *)cursor->name) == 0) {
2066 service->sc_name);
2067 }
2068 }
2069 if (prop == NULL) {
2070 semerr(gettext("The %s element in %s had an empty list of "
2071 "separators.\n"), (const char *)seps->name,
2072 service->sc_name);
2073 return (-1);
2074 }
2075 r = internal_attach_property(pg, prop);
2076 if (r != 0)
2077 internal_property_free(prop);
2078 return (r);
2079 }
2080
2081 static int
2082 lxml_get_tm_manpage(entity_t *service, xmlNodePtr manpage)
2083 {
2084 pgroup_t *pg;
2085 char *pgname;
2086 xmlChar *title;
2087
2088 /*
2089 * Fetch title attribute, convert to something sanitized, and create
2090 * property group.
2091 */
2092 title = xmlGetProp(manpage, (xmlChar *)title_attr);
2093 pgname = (char *)lxml_label_to_groupname(SCF_PG_TM_MAN_PREFIX,
2094 (const char *)title);
2095 xmlFree(title);
2096
2097 pg = internal_pgroup_find_or_create(service, pgname,
2098 (char *)SCF_GROUP_TEMPLATE);
2099
2100 /*
2101 * Each attribute is an astring property within the group.
2102 */
2103 if (new_str_prop_from_attr(pg, SCF_PROPERTY_TM_TITLE,
2104 SCF_TYPE_ASTRING, manpage, title_attr) != 0 ||
2105 new_str_prop_from_attr(pg, SCF_PROPERTY_TM_SECTION,
2106 SCF_TYPE_ASTRING, manpage, section_attr) != 0 ||
2107 new_str_prop_from_attr(pg, SCF_PROPERTY_TM_MANPATH,
2108 SCF_TYPE_ASTRING, manpage, manpath_attr) != 0)
2109 return (-1);
2110
2111 return (0);
2112 }
2113
2114 static int
2115 lxml_get_tm_doclink(entity_t *service, xmlNodePtr doc_link)
2116 {
2117 pgroup_t *pg;
2118 char *pgname;
2119 xmlChar *name;
2120
2121 /*
2122 * Fetch name attribute, convert name to something sanitized, and create
2123 * property group.
2124 */
2125 name = xmlGetProp(doc_link, (xmlChar *)name_attr);
2126
2127 pgname = (char *)lxml_label_to_groupname(SCF_PG_TM_DOC_PREFIX,
2128 (const char *)name);
2129
2130 pg = internal_pgroup_find_or_create(service, pgname,
2131 (char *)SCF_GROUP_TEMPLATE);
2132 xmlFree(name);
2133
2134 /*
2135 * Each attribute is an astring property within the group.
2136 */
2137 if (new_str_prop_from_attr(pg, SCF_PROPERTY_TM_NAME, SCF_TYPE_ASTRING,
2138 doc_link, name_attr) != 0 ||
2139 new_str_prop_from_attr(pg, SCF_PROPERTY_TM_URI, SCF_TYPE_ASTRING,
2140 doc_link, uri_attr) != 0)
2141 return (-1);
2142
2143 return (0);
2144 }
2145
2146 static int
2147 lxml_get_tm_documentation(entity_t *service, xmlNodePtr documentation)
2148 {
2149 xmlNodePtr cursor;
2150
2151 for (cursor = documentation->xmlChildrenNode; cursor != NULL;
3651 return (-1);
3652 }
3653
3654 /*
3655 * Until libxml2 addresses DTD-based validation with XInclude, we don't
3656 * validate service profiles (i.e. the apply path).
3657 */
3658 do_validate = (op != SVCCFG_OP_APPLY) &&
3659 (getenv("SVCCFG_NOVALIDATE") == NULL);
3660 if (do_validate)
3661 dtdpath = getenv("SVCCFG_DTD");
3662
3663 if (dtdpath != NULL)
3664 xmlLoadExtDtdDefaultValue = 0;
3665
3666 if ((document = xmlReadFile(filename, NULL, 0)) == NULL) {
3667 semerr(gettext("couldn't parse document\n"));
3668 return (-1);
3669 }
3670
3671 document->name = strdup(filename);
3672
3673 /*
3674 * Verify that this is a document type we understand.
3675 */
3676 if ((dtd = xmlGetIntSubset(document)) == NULL) {
3677 semerr(gettext("document has no DTD\n"));
3678 return (-1);
3679 } else if (dtdpath == NULL && !do_validate) {
3680 /*
3681 * If apply then setup so that some validation
3682 * for specific elements can be done.
3683 */
3684 dtdpath = (char *)document->intSubset->SystemID;
3685 }
3686
3687 if (!lxml_is_known_dtd(dtd->SystemID)) {
3688 semerr(gettext("document DTD unknown; not service bundle?\n"));
3689 return (-1);
3690 }
3691
|
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24 /*
25 * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
26 */
27
28
29 /*
30 * XML document manipulation routines
31 *
32 * These routines provide translation to and from the internal representation to
33 * XML. Directionally-oriented verbs are with respect to the external source,
34 * so lxml_get_service() fetches a service from the XML file into the
35 * internal representation.
36 */
37
38 #include <libxml/parser.h>
39 #include <libxml/xinclude.h>
40
41 #include <assert.h>
42 #include <ctype.h>
43 #include <errno.h>
44 #include <libintl.h>
45 #include <libscf.h>
46 #include <libscf_priv.h>
47 #include <libuutil.h>
567 v->sc_u.sc_integer = strtoll((char *)value, &endptr, 10);
568 if (errno != 0 || *endptr)
569 uu_die(gettext("illegal value \"%s\" for "
570 "%s (%s)\n"), (char *)value,
571 lxml_prop_types[type],
572 (errno) ? strerror(errno) : "Illegal character");
573 break;
574 case SC_OPAQUE:
575 case SC_HOST:
576 case SC_HOSTNAME:
577 case SC_NET_ADDR:
578 case SC_NET_ADDR_V4:
579 case SC_NET_ADDR_V6:
580 case SC_FMRI:
581 case SC_URI:
582 case SC_TIME:
583 case SC_ASTRING:
584 case SC_USTRING:
585 scf_type = lxml_element_to_type(type);
586
587 v->sc_u.sc_string = safe_strdup((const char *)value);
588 if (lxml_validate_string_value(scf_type,
589 v->sc_u.sc_string) != 0)
590 uu_die(gettext("illegal value \"%s\" for "
591 "%s (%s)\n"), (char *)value,
592 lxml_prop_types[type],
593 (scf_error()) ? scf_strerror(scf_error()) :
594 gettext("Illegal format"));
595 v->sc_free = lxml_free_str;
596 break;
597 case SC_BOOLEAN:
598 v->sc_u.sc_count = lxml_xlate_boolean(value);
599 break;
600 default:
601 uu_die(gettext("unknown value type (%d)\n"), type);
602 break;
603 }
604
605 /* Free the old value */
606 if (fov && v->sc_free != NULL)
607 free((char *)value);
1355
1356 pg = internal_pgroup_find_or_create(entity, "dependents",
1357 (char *)scf_group_framework);
1358 p = internal_property_create((char *)name, SCF_TYPE_FMRI, 1, fmri);
1359 if (internal_attach_property(pg, p) != 0)
1360 return (-1);
1361
1362 return (0);
1363 }
1364
1365 static int
1366 lxml_get_entity_stability(entity_t *entity, xmlNodePtr rstr)
1367 {
1368 pgroup_t *pg;
1369 property_t *p;
1370 xmlChar *stabval;
1371
1372 if (((stabval = xmlGetProp(rstr, (xmlChar *)value_attr)) == NULL) ||
1373 (*stabval == 0)) {
1374 uu_warn(gettext("no stability value found\n"));
1375 stabval = (xmlChar *)safe_strdup("External");
1376 }
1377
1378 pg = internal_pgroup_find_or_create(entity, (char *)scf_pg_general,
1379 (char *)scf_group_framework);
1380
1381 p = internal_property_create(SCF_PROPERTY_ENTITY_STABILITY,
1382 SCF_TYPE_ASTRING, 1, stabval);
1383
1384 return (internal_attach_property(pg, p));
1385 }
1386
1387 static int
1388 lxml_get_restarter(entity_t *entity, xmlNodePtr rstr)
1389 {
1390 pgroup_t *pg;
1391 property_t *p;
1392 xmlChar *restarter;
1393 xmlNode *cursor;
1394 int r;
1395
1423
1424 p = internal_property_create(SCF_PROPERTY_RESTARTER, SCF_TYPE_FMRI, 1,
1425 restarter);
1426
1427 r = internal_attach_property(pg, p);
1428 if (r != 0) {
1429 internal_property_free(p);
1430 return (-1);
1431 }
1432
1433 return (0);
1434 }
1435
1436 static void
1437 lxml_get_paramval(pgroup_t *pgrp, const char *propname, xmlNodePtr pval)
1438 {
1439 property_t *p;
1440 char *value;
1441 char *prop;
1442
1443 prop = safe_strdup(propname);
1444
1445 value = (char *)xmlGetProp(pval, (xmlChar *)value_attr);
1446 if (value == NULL || *value == '\0')
1447 uu_die(gettext("property value missing for property '%s/%s'\n"),
1448 pgrp->sc_pgroup_name, propname);
1449 p = internal_property_create(prop, SCF_TYPE_ASTRING, 1, value);
1450
1451 (void) internal_attach_property(pgrp, p);
1452 }
1453
1454 static void
1455 lxml_get_parameter(pgroup_t *pgrp, const char *propname, xmlNodePtr param)
1456 {
1457 property_t *p = internal_property_new();
1458
1459 p->sc_property_name = safe_strdup(propname);
1460 p->sc_value_type = SCF_TYPE_ASTRING;
1461
1462 (void) lxml_get_value(p, SC_ASTRING, param);
1463
1464 (void) internal_attach_property(pgrp, p);
1465 }
1466
1467 static void
1468 lxml_get_type(pgroup_t *pgrp, xmlNodePtr type)
1469 {
1470 property_t *p;
1471 xmlChar *name;
1472 xmlChar *active;
1473 xmlNodePtr cursor;
1474 uint64_t active_val;
1475 size_t sz = max_scf_name_len + 1;
1476 char *propname = safe_malloc(sz);
1477
1478 if (pgrp->sc_parent->sc_op == SVCCFG_OP_APPLY)
1479 lxml_validate_element(type);
1690
1691 for (cursor = loctext->xmlChildrenNode; cursor != NULL;
1692 cursor = cursor->next) {
1693 if (strcmp("text", (const char *)cursor->name) == 0) {
1694 break;
1695 } else if (strcmp("comment", (const char *)cursor->name) != 0) {
1696 uu_die(gettext("illegal element \"%s\" on loctext "
1697 "element for \"%s\"\n"), cursor->name,
1698 service->sc_name);
1699 }
1700 }
1701
1702 if (cursor == NULL) {
1703 uu_die(gettext("loctext element has no content for \"%s\"\n"),
1704 service->sc_name);
1705 }
1706
1707 /*
1708 * Remove leading and trailing whitespace.
1709 */
1710 stripped = safe_strdup((const char *)cursor->content);
1711
1712 for (; isspace(*stripped); stripped++)
1713 ;
1714 for (cp = stripped + strlen(stripped) - 1; isspace(*cp); cp--)
1715 ;
1716 *(cp + 1) = '\0';
1717
1718 p = internal_property_create(prop_name, SCF_TYPE_USTRING, 1,
1719 stripped);
1720
1721 r = internal_attach_property(pg, p);
1722 if (r != 0) {
1723 internal_property_free(p);
1724 free(prop_name);
1725 }
1726
1727 return (r);
1728 }
1729
1730 /*
1926 lxml_get_tm_description(entity_t *service, xmlNodePtr description)
1927 {
1928 pgroup_t *pg;
1929
1930 /*
1931 * Create the property group, if absent.
1932 */
1933 pg = internal_pgroup_find_or_create(service, SCF_PG_TM_DESCRIPTION,
1934 SCF_GROUP_TEMPLATE);
1935
1936 return (lxml_get_all_loctext(service, pg, description,
1937 LOCALE_ONLY_FMT, "description"));
1938 }
1939
1940 static char *
1941 lxml_label_to_groupname(const char *prefix, const char *in)
1942 {
1943 char *out, *cp;
1944 size_t len, piece_len;
1945
1946 out = uu_zalloc(2 * max_scf_name_len + 1);
1947 if (out == NULL)
1948 return (NULL);
1949
1950 (void) strlcpy(out, prefix, 2 * max_scf_name_len + 1);
1951
1952 len = strlcat(out, in, 2 * max_scf_name_len + 1);
1953 if (len > max_scf_name_len) {
1954 /* Use the first half and the second half. */
1955 piece_len = (max_scf_name_len - 2) / 2;
1956
1957 (void) strncpy(out + piece_len, "..", 2);
1958
1959 (void) strcpy(out + piece_len + 2, out + (len - piece_len));
1960 }
1961
1962 /*
1963 * Translate non-property characters to '_'.
1964 */
1965 for (cp = out; *cp != '\0'; ++cp) {
1966 if (!(isalnum(*cp) || *cp == '_' || *cp == '-'))
1967 *cp = '_';
1968 }
1969
1970 return (out);
1971 }
1972
1973 /*
1974 * If *p is NULL, astring_prop_value() first creates a property with the
1975 * name specified in prop_name. The address of the newly created property
1976 * is placed in *p.
1977 *
1978 * In either case, newly created property or existing property, a new
1979 * SCF_TYPE_ASTRING value will created and attached to the property at *p.
1980 * The value of the newly created property is prop_value.
1981 *
1982 * free_flag is used to indicate whether or not the memory at prop_value
1983 * should be freed when the property is freed by a call to
1984 * internal_property_free().
1985 */
1986 static void
1987 astring_prop_value(property_t **p, const char *prop_name, char *prop_value,
1988 boolean_t free_flag)
1989 {
2013 static void
2014 seps_to_prop_values(property_t **p, xmlChar *seps)
2015 {
2016 value_t *v;
2017 char val_str[2];
2018
2019 if (*p == NULL) {
2020 *p = internal_property_new();
2021 (*p)->sc_property_name =
2022 (char *)SCF_PROPERTY_INTERNAL_SEPARATORS;
2023 (*p)->sc_value_type = SCF_TYPE_ASTRING;
2024 }
2025
2026 /* Add the values to the property's list. */
2027 val_str[1] = 0; /* Terminate the string. */
2028 for (; *seps != 0; seps++) {
2029 v = internal_value_new();
2030 v->sc_type = (*p)->sc_value_type;
2031 v->sc_free = lxml_free_str;
2032 val_str[0] = *seps;
2033 v->sc_u.sc_string = safe_strdup(val_str);
2034 internal_attach_value(*p, v);
2035 }
2036 }
2037
2038 /*
2039 * Create an internal_separators property and attach it to the property
2040 * group at pg. The separator characters are provided in the text nodes
2041 * that are the children of seps. Each separator character is stored as a
2042 * property value in the internal_separators property.
2043 */
2044 static int
2045 lxml_get_tm_internal_seps(entity_t *service, pgroup_t *pg, xmlNodePtr seps)
2046 {
2047 xmlNodePtr cursor;
2048 property_t *prop = NULL;
2049 int r;
2050
2051 for (cursor = seps->xmlChildrenNode; cursor != NULL;
2052 cursor = cursor->next) {
2053 if (strcmp("text", (const char *)cursor->name) == 0) {
2058 service->sc_name);
2059 }
2060 }
2061 if (prop == NULL) {
2062 semerr(gettext("The %s element in %s had an empty list of "
2063 "separators.\n"), (const char *)seps->name,
2064 service->sc_name);
2065 return (-1);
2066 }
2067 r = internal_attach_property(pg, prop);
2068 if (r != 0)
2069 internal_property_free(prop);
2070 return (r);
2071 }
2072
2073 static int
2074 lxml_get_tm_manpage(entity_t *service, xmlNodePtr manpage)
2075 {
2076 pgroup_t *pg;
2077 char *pgname;
2078 char *name;
2079 xmlChar *title;
2080 xmlChar *section;
2081
2082 /*
2083 * Fetch title and section attributes, convert to something sanitized,
2084 * and create property group.
2085 */
2086 title = xmlGetProp(manpage, (xmlChar *)title_attr);
2087 if (title == NULL)
2088 return (-1);
2089 section = xmlGetProp(manpage, (xmlChar *)section_attr);
2090 if (section == NULL) {
2091 xmlFree(title);
2092 return (-1);
2093 }
2094
2095 name = safe_malloc(max_scf_name_len + 1);
2096
2097 /* Find existing property group with underscore separators */
2098 (void) snprintf(name, max_scf_name_len + 1, "%s_%s", title, section);
2099 pgname = lxml_label_to_groupname(SCF_PG_TM_MAN_PREFIX, name);
2100 pg = internal_pgroup_find(service, pgname, SCF_GROUP_TEMPLATE);
2101
2102 uu_free(pgname);
2103 (void) snprintf(name, max_scf_name_len + 1, "%s%s", title, section);
2104 pgname = lxml_label_to_groupname(SCF_PG_TM_MAN_PREFIX, name);
2105
2106 if (pg == NULL) {
2107 pg = internal_pgroup_find_or_create(service, pgname,
2108 SCF_GROUP_TEMPLATE);
2109 } else {
2110 /* Rename property group */
2111 free((char *)pg->sc_pgroup_name);
2112 pg->sc_pgroup_name = safe_strdup(pgname);
2113 }
2114
2115 uu_free(pgname);
2116 free(name);
2117 xmlFree(section);
2118 xmlFree(title);
2119
2120
2121 /*
2122 * Each attribute is an astring property within the group.
2123 */
2124 if (new_str_prop_from_attr(pg, SCF_PROPERTY_TM_TITLE,
2125 SCF_TYPE_ASTRING, manpage, title_attr) != 0 ||
2126 new_str_prop_from_attr(pg, SCF_PROPERTY_TM_SECTION,
2127 SCF_TYPE_ASTRING, manpage, section_attr) != 0 ||
2128 new_str_prop_from_attr(pg, SCF_PROPERTY_TM_MANPATH,
2129 SCF_TYPE_ASTRING, manpage, manpath_attr) != 0)
2130 return (-1);
2131
2132 return (0);
2133 }
2134
2135 static int
2136 lxml_get_tm_doclink(entity_t *service, xmlNodePtr doc_link)
2137 {
2138 pgroup_t *pg;
2139 char *pgname;
2140 xmlChar *name;
2141
2142 /*
2143 * Fetch name attribute, convert name to something sanitized, and create
2144 * property group.
2145 */
2146 name = xmlGetProp(doc_link, (xmlChar *)name_attr);
2147 if (name == NULL)
2148 return (-1);
2149
2150 pgname = (char *)lxml_label_to_groupname(SCF_PG_TM_DOC_PREFIX,
2151 (const char *)name);
2152
2153 pg = internal_pgroup_find_or_create(service, pgname,
2154 (char *)SCF_GROUP_TEMPLATE);
2155
2156 uu_free(pgname);
2157 xmlFree(name);
2158
2159 /*
2160 * Each attribute is an astring property within the group.
2161 */
2162 if (new_str_prop_from_attr(pg, SCF_PROPERTY_TM_NAME, SCF_TYPE_ASTRING,
2163 doc_link, name_attr) != 0 ||
2164 new_str_prop_from_attr(pg, SCF_PROPERTY_TM_URI, SCF_TYPE_ASTRING,
2165 doc_link, uri_attr) != 0)
2166 return (-1);
2167
2168 return (0);
2169 }
2170
2171 static int
2172 lxml_get_tm_documentation(entity_t *service, xmlNodePtr documentation)
2173 {
2174 xmlNodePtr cursor;
2175
2176 for (cursor = documentation->xmlChildrenNode; cursor != NULL;
3676 return (-1);
3677 }
3678
3679 /*
3680 * Until libxml2 addresses DTD-based validation with XInclude, we don't
3681 * validate service profiles (i.e. the apply path).
3682 */
3683 do_validate = (op != SVCCFG_OP_APPLY) &&
3684 (getenv("SVCCFG_NOVALIDATE") == NULL);
3685 if (do_validate)
3686 dtdpath = getenv("SVCCFG_DTD");
3687
3688 if (dtdpath != NULL)
3689 xmlLoadExtDtdDefaultValue = 0;
3690
3691 if ((document = xmlReadFile(filename, NULL, 0)) == NULL) {
3692 semerr(gettext("couldn't parse document\n"));
3693 return (-1);
3694 }
3695
3696 document->name = safe_strdup(filename);
3697
3698 /*
3699 * Verify that this is a document type we understand.
3700 */
3701 if ((dtd = xmlGetIntSubset(document)) == NULL) {
3702 semerr(gettext("document has no DTD\n"));
3703 return (-1);
3704 } else if (dtdpath == NULL && !do_validate) {
3705 /*
3706 * If apply then setup so that some validation
3707 * for specific elements can be done.
3708 */
3709 dtdpath = (char *)document->intSubset->SystemID;
3710 }
3711
3712 if (!lxml_is_known_dtd(dtd->SystemID)) {
3713 semerr(gettext("document DTD unknown; not service bundle?\n"));
3714 return (-1);
3715 }
3716
|