Print this page
335 service manifest does not support multiple manpage references for the same keyword


   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