1 /*
   2  * CDDL HEADER START
   3  *
   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  * Copyright 2017 RackTop Systems.
  27  */
  28 
  29 
  30 /*
  31  * XML document manipulation routines
  32  *
  33  * These routines provide translation to and from the internal representation to
  34  * XML.  Directionally-oriented verbs are with respect to the external source,
  35  * so lxml_get_service() fetches a service from the XML file into the
  36  * internal representation.
  37  */
  38 
  39 #include <libxml/parser.h>
  40 #include <libxml/xinclude.h>
  41 
  42 #include <assert.h>
  43 #include <ctype.h>
  44 #include <errno.h>
  45 #include <libintl.h>
  46 #include <libscf.h>
  47 #include <libscf_priv.h>
  48 #include <libuutil.h>
  49 #include <sasl/saslutil.h>
  50 #include <stdlib.h>
  51 #include <string.h>
  52 #include <limits.h>
  53 
  54 #include <sys/types.h>
  55 #include <sys/stat.h>
  56 #include <unistd.h>
  57 
  58 #include <sys/param.h>
  59 #include "manifest_hash.h"
  60 
  61 #include "svccfg.h"
  62 #include "notify_params.h"
  63 
  64 /*
  65  * snprintf(3C) format strings for constructing property names that include
  66  * the locale designation.  Use %s to indicate where the locale should go.
  67  *
  68  * The VALUE_* symbols are an exception.  The firs %s will be replaced with
  69  * "value_".  The second %s will be replaced by the name of the value and
  70  * %%s will be replaced by the locale designation.  These formats are
  71  * processed twice by snprintf(3C).  The first time captures the value name
  72  * and the second time captures the locale.
  73  */
  74 #define LOCALE_ONLY_FMT         ("%s")
  75 #define COMMON_NAME_FMT         ("common_name_%s")
  76 #define DESCRIPTION_FMT         ("description_%s")
  77 #define UNITS_FMT               ("units_%s")
  78 #define VALUE_COMMON_NAME_FMT   ("%s%s_common_name_%%s")
  79 #define VALUE_DESCRIPTION_FMT   ("%s%s_description_%%s")
  80 
  81 /* Attribute names */
  82 const char * const delete_attr = "delete";
  83 const char * const enabled_attr = "enabled";
  84 const char * const lang_attr = "lang";
  85 const char * const manpath_attr = "manpath";
  86 const char * const max_attr = "max";
  87 const char * const min_attr = "min";
  88 const char * const name_attr = "name";
  89 const char * const override_attr = "override";
  90 const char * const required_attr = "required";
  91 const char * const section_attr = "section";
  92 const char * const set_attr = "set";
  93 const char * const target_attr = "target";
  94 const char * const timeout_seconds_attr = "timeout_seconds";
  95 const char * const title_attr = "title";
  96 const char * const type_attr = "type";
  97 const char * const uri_attr = "uri";
  98 const char * const value_attr = "value";
  99 const char * const version_attr = "version";
 100 const char * const xml_lang_attr = "xml:lang";
 101 const char * const active_attr = "active";
 102 
 103 /* Attribute values */
 104 const char * const all_value = "all";
 105 
 106 const char * const true = "true";
 107 const char * const false = "false";
 108 
 109 /*
 110  * The following list must be kept in the same order as that of
 111  * element_t array
 112  */
 113 static const char *lxml_elements[] = {
 114         "astring_list",                 /* SC_ASTRING */
 115         "boolean_list",                 /* SC_BOOLEAN */
 116         "cardinality",                  /* SC_CARDINALITY */
 117         "choices",                      /* SC_CHOICES */
 118         "common_name",                  /* SC_COMMON_NAME */
 119         "constraints",                  /* SC_CONSTRAINTS */
 120         "count_list",                   /* SC_COUNT */
 121         "create_default_instance",      /* SC_INSTANCE_CREATE_DEFAULT */
 122         "dependency",                   /* SC_DEPENDENCY */
 123         "dependent",                    /* SC_DEPENDENT */
 124         "description",                  /* SC_DESCRIPTION */
 125         "doc_link",                     /* SC_DOC_LINK */
 126         "documentation",                /* SC_DOCUMENTATION */
 127         "enabled",                      /* SC_ENABLED */
 128         "event",                        /* SC_EVENT */
 129         "exec_method",                  /* SC_EXEC_METHOD */
 130         "fmri_list",                    /* SC_FMRI */
 131         "host_list",                    /* SC_HOST */
 132         "hostname_list",                /* SC_HOSTNAME */
 133         "include_values",               /* SC_INCLUDE_VALUES */
 134         "instance",                     /* SC_INSTANCE */
 135         "integer_list",                 /* SC_INTEGER */
 136         "internal_separators",          /* SC_INTERNAL_SEPARATORS */
 137         "loctext",                      /* SC_LOCTEXT */
 138         "manpage",                      /* SC_MANPAGE */
 139         "method_context",               /* SC_METHOD_CONTEXT */
 140         "method_credential",            /* SC_METHOD_CREDENTIAL */
 141         "method_profile",               /* SC_METHOD_PROFILE */
 142         "method_environment",           /* SC_METHOD_ENVIRONMENT */
 143         "envvar",                       /* SC_METHOD_ENVVAR */
 144         "net_address_list",             /* SC_NET_ADDR */
 145         "net_address_v4_list",          /* SC_NET_ADDR_V4 */
 146         "net_address_v6_list",          /* SC_NET_ADDR_V6 */
 147         "notification_parameters",      /* SC_NOTIFICATION_PARAMETERS */
 148         "opaque_list",                  /* SC_OPAQUE */
 149         "parameter",                    /* SC_PARAMETER */
 150         "paramval",                     /* SC_PARAMVAL */
 151         "pg_pattern",                   /* SC_PG_PATTERN */
 152         "prop_pattern",                 /* SC_PROP_PATTERN */
 153         "property",                     /* SC_PROPERTY */
 154         "property_group",               /* SC_PROPERTY_GROUP */
 155         "propval",                      /* SC_PROPVAL */
 156         "range",                        /* SC_RANGE */
 157         "restarter",                    /* SC_RESTARTER */
 158         "service",                      /* SC_SERVICE */
 159         "service_bundle",               /* SC_SERVICE_BUNDLE */
 160         "service_fmri",                 /* SC_SERVICE_FMRI */
 161         "single_instance",              /* SC_INSTANCE_SINGLE */
 162         "stability",                    /* SC_STABILITY */
 163         "template",                     /* SC_TEMPLATE */
 164         "time_list",                    /* SC_TIME */
 165         "type",                         /* SC_TYPE */
 166         "units",                        /* SC_UNITS */
 167         "uri_list",                     /* SC_URI */
 168         "ustring_list",                 /* SC_USTRING */
 169         "value",                        /* SC_VALUE */
 170         "value_node",                   /* SC_VALUE_NODE */
 171         "values",                       /* SC_VALUES */
 172         "visibility",                   /* SC_VISIBILITY */
 173         "xi:fallback",                  /* SC_XI_FALLBACK */
 174         "xi:include"                    /* SC_XI_INCLUDE */
 175 };
 176 
 177 /*
 178  * The following list must be kept in the same order as that of
 179  * element_t array
 180  */
 181 static const char *lxml_prop_types[] = {
 182         "astring",                      /* SC_ASTRING */
 183         "boolean",                      /* SC_BOOLEAN */
 184         "",                             /* SC_CARDINALITY */
 185         "",                             /* SC_CHOICES */
 186         "",                             /* SC_COMMON_NAME */
 187         "",                             /* SC_CONSTRAINTS */
 188         "count",                        /* SC_COUNT */
 189         "",                             /* SC_INSTANCE_CREATE_DEFAULT */
 190         "",                             /* SC_DEPENDENCY */
 191         "",                             /* SC_DEPENDENT */
 192         "",                             /* SC_DESCRIPTION */
 193         "",                             /* SC_DOC_LINK */
 194         "",                             /* SC_DOCUMENTATION */
 195         "",                             /* SC_ENABLED */
 196         "",                             /* SC_EVENT */
 197         "",                             /* SC_EXEC_METHOD */
 198         "fmri",                         /* SC_FMRI */
 199         "host",                         /* SC_HOST */
 200         "hostname",                     /* SC_HOSTNAME */
 201         "",                             /* SC_INCLUDE_VALUES */
 202         "",                             /* SC_INSTANCE */
 203         "integer",                      /* SC_INTEGER */
 204         "",                             /* SC_INTERNAL_SEPARATORS */
 205         "",                             /* SC_LOCTEXT */
 206         "",                             /* SC_MANPAGE */
 207         "",                             /* SC_METHOD_CONTEXT */
 208         "",                             /* SC_METHOD_CREDENTIAL */
 209         "",                             /* SC_METHOD_PROFILE */
 210         "",                             /* SC_METHOD_ENVIRONMENT */
 211         "",                             /* SC_METHOD_ENVVAR */
 212         "net_address",                  /* SC_NET_ADDR */
 213         "net_address_v4",               /* SC_NET_ADDR_V4 */
 214         "net_address_v6",               /* SC_NET_ADDR_V6 */
 215         "",                             /* SC_NOTIFICATION_PARAMETERS */
 216         "opaque",                       /* SC_OPAQUE */
 217         "",                             /* SC_PARAMETER */
 218         "",                             /* SC_PARAMVAL */
 219         "",                             /* SC_PG_PATTERN */
 220         "",                             /* SC_PROP_PATTERN */
 221         "",                             /* SC_PROPERTY */
 222         "",                             /* SC_PROPERTY_GROUP */
 223         "",                             /* SC_PROPVAL */
 224         "",                             /* SC_RANGE */
 225         "",                             /* SC_RESTARTER */
 226         "",                             /* SC_SERVICE */
 227         "",                             /* SC_SERVICE_BUNDLE */
 228         "",                             /* SC_SERVICE_FMRI */
 229         "",                             /* SC_INSTANCE_SINGLE */
 230         "",                             /* SC_STABILITY */
 231         "",                             /* SC_TEMPLATE */
 232         "time",                         /* SC_TIME */
 233         "",                             /* SC_TYPE */
 234         "",                             /* SC_UNITS */
 235         "uri",                          /* SC_URI */
 236         "ustring",                      /* SC_USTRING */
 237         "",                             /* SC_VALUE */
 238         "",                             /* SC_VALUE_NODE */
 239         "",                             /* SC_VALUES */
 240         "",                             /* SC_VISIBILITY */
 241         "",                             /* SC_XI_FALLBACK */
 242         ""                              /* SC_XI_INCLUDE */
 243 };
 244 
 245 int
 246 lxml_init()
 247 {
 248         if (getenv("SVCCFG_NOVALIDATE") == NULL) {
 249                 /*
 250                  * DTD validation, with line numbers.
 251                  */
 252                 (void) xmlLineNumbersDefault(1);
 253                 xmlLoadExtDtdDefaultValue |= XML_DETECT_IDS;
 254                 xmlLoadExtDtdDefaultValue |= XML_COMPLETE_ATTRS;
 255         }
 256 
 257         return (0);
 258 }
 259 
 260 static bundle_type_t
 261 lxml_xlate_bundle_type(xmlChar *type)
 262 {
 263         if (xmlStrcmp(type, (const xmlChar *)"manifest") == 0)
 264                 return (SVCCFG_MANIFEST);
 265 
 266         if (xmlStrcmp(type, (const xmlChar *)"profile") == 0)
 267                 return (SVCCFG_PROFILE);
 268 
 269         if (xmlStrcmp(type, (const xmlChar *)"archive") == 0)
 270                 return (SVCCFG_ARCHIVE);
 271 
 272         return (SVCCFG_UNKNOWN_BUNDLE);
 273 }
 274 
 275 static service_type_t
 276 lxml_xlate_service_type(xmlChar *type)
 277 {
 278         if (xmlStrcmp(type, (const xmlChar *)"service") == 0)
 279                 return (SVCCFG_SERVICE);
 280 
 281         if (xmlStrcmp(type, (const xmlChar *)"restarter") == 0)
 282                 return (SVCCFG_RESTARTER);
 283 
 284         if (xmlStrcmp(type, (const xmlChar *)"milestone") == 0)
 285                 return (SVCCFG_MILESTONE);
 286 
 287         return (SVCCFG_UNKNOWN_SERVICE);
 288 }
 289 
 290 static element_t
 291 lxml_xlate_element(const xmlChar *tag)
 292 {
 293         int i;
 294 
 295         for (i = 0; i < sizeof (lxml_elements) / sizeof (char *); i++)
 296                 if (xmlStrcmp(tag, (const xmlChar *)lxml_elements[i]) == 0)
 297                         return ((element_t)i);
 298 
 299         return ((element_t)-1);
 300 }
 301 
 302 static uint_t
 303 lxml_xlate_boolean(const xmlChar *value)
 304 {
 305         if (xmlStrcmp(value, (const xmlChar *)true) == 0)
 306                 return (1);
 307 
 308         if (xmlStrcmp(value, (const xmlChar *)false) == 0)
 309                 return (0);
 310 
 311         uu_die(gettext("illegal boolean value \"%s\"\n"), value);
 312 
 313         /*NOTREACHED*/
 314 }
 315 
 316 static scf_type_t
 317 lxml_element_to_type(element_t type)
 318 {
 319         switch (type) {
 320         case SC_ASTRING:        return (SCF_TYPE_ASTRING);
 321         case SC_BOOLEAN:        return (SCF_TYPE_BOOLEAN);
 322         case SC_COUNT:          return (SCF_TYPE_COUNT);
 323         case SC_FMRI:           return (SCF_TYPE_FMRI);
 324         case SC_HOST:           return (SCF_TYPE_HOST);
 325         case SC_HOSTNAME:       return (SCF_TYPE_HOSTNAME);
 326         case SC_INTEGER:        return (SCF_TYPE_INTEGER);
 327         case SC_NET_ADDR:       return (SCF_TYPE_NET_ADDR);
 328         case SC_NET_ADDR_V4:    return (SCF_TYPE_NET_ADDR_V4);
 329         case SC_NET_ADDR_V6:    return (SCF_TYPE_NET_ADDR_V6);
 330         case SC_OPAQUE:         return (SCF_TYPE_OPAQUE);
 331         case SC_TIME:           return (SCF_TYPE_TIME);
 332         case SC_URI:            return (SCF_TYPE_URI);
 333         case SC_USTRING:        return (SCF_TYPE_USTRING);
 334 
 335         default:
 336                 uu_die(gettext("unknown value type (%d)\n"), type);
 337         }
 338 
 339         /* NOTREACHED */
 340 }
 341 
 342 static element_t
 343 lxml_type_to_element(scf_type_t type)
 344 {
 345         switch (type) {
 346         case SCF_TYPE_ASTRING:          return (SC_ASTRING);
 347         case SCF_TYPE_BOOLEAN:          return (SC_BOOLEAN);
 348         case SCF_TYPE_COUNT:            return (SC_COUNT);
 349         case SCF_TYPE_FMRI:             return (SC_FMRI);
 350         case SCF_TYPE_HOST:             return (SC_HOST);
 351         case SCF_TYPE_HOSTNAME:         return (SC_HOSTNAME);
 352         case SCF_TYPE_INTEGER:          return (SC_INTEGER);
 353         case SCF_TYPE_NET_ADDR:         return (SC_NET_ADDR);
 354         case SCF_TYPE_NET_ADDR_V4:      return (SC_NET_ADDR_V4);
 355         case SCF_TYPE_NET_ADDR_V6:      return (SC_NET_ADDR_V6);
 356         case SCF_TYPE_OPAQUE:           return (SC_OPAQUE);
 357         case SCF_TYPE_TIME:             return (SC_TIME);
 358         case SCF_TYPE_URI:              return (SC_URI);
 359         case SCF_TYPE_USTRING:          return (SC_USTRING);
 360 
 361         default:
 362                 uu_die(gettext("unknown value type (%d)\n"), type);
 363         }
 364 
 365         /* NOTREACHED */
 366 }
 367 
 368 /*
 369  * Create a SCF_TYPE_BOOLEAN property name pname and attach it to the
 370  * property group at pgrp.  The value of the property will be set from the
 371  * attribute named attr.  attr must have a value of 0, 1, true or false.
 372  *
 373  * Zero is returned on success.  An error is indicated by -1.  It indicates
 374  * that either the attribute had an invalid value or that we could not
 375  * attach the property to pgrp.  The attribute should not have an invalid
 376  * value if the DTD is correctly written.
 377  */
 378 static int
 379 new_bool_prop_from_attr(pgroup_t *pgrp, const char *pname, xmlNodePtr n,
 380     const char *attr)
 381 {
 382         uint64_t bool;
 383         xmlChar *val;
 384         property_t *p;
 385         int r;
 386 
 387         val = xmlGetProp(n, (xmlChar *)attr);
 388         if (val == NULL)
 389                 return (0);
 390 
 391         if ((xmlStrcmp(val, (xmlChar *)"0") == 0) ||
 392             (xmlStrcmp(val, (xmlChar *)"false") == 0)) {
 393                 bool = 0;
 394         } else if ((xmlStrcmp(val, (xmlChar *)"1") == 0) ||
 395             (xmlStrcmp(val, (xmlChar *)"true") == 0)) {
 396                 bool = 1;
 397         } else {
 398                 xmlFree(val);
 399                 return (-1);
 400         }
 401         xmlFree(val);
 402         p = internal_property_create(pname, SCF_TYPE_BOOLEAN, 1, bool);
 403         r = internal_attach_property(pgrp, p);
 404 
 405         if (r != 0)
 406                 internal_property_free(p);
 407 
 408         return (r);
 409 }
 410 
 411 static int
 412 new_str_prop_from_attr(pgroup_t *pgrp, const char *pname, scf_type_t ty,
 413     xmlNodePtr n, const char *attr)
 414 {
 415         xmlChar *val;
 416         property_t *p;
 417         int r;
 418 
 419         val = xmlGetProp(n, (xmlChar *)attr);
 420 
 421         /* Some properties may have multiple values. */
 422         p = internal_property_find(pgrp, pname);
 423         if (p != NULL) {
 424                 value_t *v = internal_value_new();
 425                 v->sc_u.sc_string = (char *)val;
 426                 v->sc_type = ty;
 427                 internal_attach_value(p, v);
 428                 return (0);
 429         }
 430 
 431         p = internal_property_create(pname, ty, 1, val);
 432         r = internal_attach_property(pgrp, p);
 433 
 434         if (r != 0)
 435                 internal_property_free(p);
 436 
 437         return (r);
 438 }
 439 
 440 static int
 441 new_opt_str_prop_from_attr(pgroup_t *pgrp, const char *pname, scf_type_t ty,
 442     xmlNodePtr n, const char *attr, const char *dflt)
 443 {
 444         xmlChar *val;
 445         property_t *p;
 446         int r;
 447 
 448         val = xmlGetProp(n, (xmlChar *)attr);
 449         if (val == NULL) {
 450                 if (dflt == NULL) {
 451                         /*
 452                          * A missing attribute is considered to be a
 453                          * success in this function, because many of the
 454                          * attributes are optional.  Missing non-optional
 455                          * attributes will be detected later when template
 456                          * validation is done.
 457                          */
 458                         return (0);
 459                 } else {
 460                         val = (xmlChar *)dflt;
 461                 }
 462         }
 463 
 464         p = internal_property_create(pname, ty, 1, val);
 465         r = internal_attach_property(pgrp, p);
 466 
 467         if (r != 0)
 468                 internal_property_free(p);
 469 
 470         return (r);
 471 }
 472 
 473 static int
 474 lxml_ignorable_block(xmlNodePtr n)
 475 {
 476         return ((xmlStrcmp(n->name, (xmlChar *)"text") == 0 ||
 477             xmlStrcmp(n->name, (xmlChar *)"comment") == 0) ? 1 : 0);
 478 }
 479 
 480 static void
 481 lxml_validate_element(xmlNodePtr n)
 482 {
 483         xmlValidCtxtPtr vcp;
 484 
 485         if (n->doc == NULL)
 486                 uu_die(gettext("Could not validate element\n"));
 487 
 488         if (n->doc->extSubset == NULL) {
 489                 xmlDtdPtr dtd;
 490                 dtd = xmlParseDTD(NULL, n->doc->intSubset->SystemID);
 491 
 492                 if (dtd == NULL) {
 493                         uu_die(gettext("Could not parse DTD \"%s\".\n"),
 494                             n->doc->intSubset->SystemID);
 495                 }
 496 
 497                 n->doc->extSubset = dtd;
 498         }
 499 
 500         vcp = xmlNewValidCtxt();
 501         if (vcp == NULL)
 502                 uu_die(gettext("could not allocate memory"));
 503 
 504         vcp->warning = xmlParserValidityWarning;
 505         vcp->error = xmlParserValidityError;
 506 
 507         if (xmlValidateElement(vcp, n->doc, n) == 0)
 508                 uu_die(gettext("Document is not valid.\n"));
 509 
 510         xmlFreeValidCtxt(vcp);
 511 }
 512 
 513 static int
 514 lxml_validate_string_value(scf_type_t type, const char *v)
 515 {
 516         static scf_value_t *scf_value = NULL;
 517         static scf_handle_t *scf_hndl = NULL;
 518 
 519         if (scf_hndl == NULL && (scf_hndl = scf_handle_create(SCF_VERSION)) ==
 520             NULL)
 521                 return (-1);
 522 
 523         if (scf_value == NULL && (scf_value = scf_value_create(scf_hndl)) ==
 524             NULL)
 525                 return (-1);
 526 
 527         return (scf_value_set_from_string(scf_value, type, v));
 528 }
 529 
 530 static void
 531 lxml_free_str(value_t *val)
 532 {
 533         free(val->sc_u.sc_string);
 534 }
 535 
 536 /*
 537  * Take a value_t structure and a type and value.  Based on the type
 538  * ensure that the value is of that type.  If so store the value in
 539  * the correct location of the value_t structure.
 540  *
 541  * If the value is NULL, the value_t structure will have been created
 542  * and the value would have ultimately been stored as a string value
 543  * but at the time the type was unknown.  Now the type should be known
 544  * so take the type and value from value_t and validate and store
 545  * the value correctly if the value is of the stated type.
 546  */
 547 void
 548 lxml_store_value(value_t *v, element_t type, const xmlChar *value)
 549 {
 550         char *endptr;
 551         int fov = 0;
 552         scf_type_t scf_type = SCF_TYPE_INVALID;
 553 
 554         if (value == NULL) {
 555                 type = lxml_type_to_element(v->sc_type);
 556                 value = (const xmlChar *)v->sc_u.sc_string;
 557                 fov = 1;
 558         }
 559 
 560         switch (type) {
 561         case SC_COUNT:
 562                 /*
 563                  * Although an SC_COUNT represents a uint64_t the use
 564                  * of a negative value is acceptable due to the usage
 565                  * established by inetd(1M).
 566                  */
 567                 errno = 0;
 568                 v->sc_u.sc_count = strtoull((char *)value, &endptr, 10);
 569                 if (errno != 0 || endptr == (char *)value || *endptr)
 570                         uu_die(gettext("illegal value \"%s\" for "
 571                             "%s (%s)\n"), (char *)value,
 572                             lxml_prop_types[type],
 573                             (errno) ? strerror(errno) :
 574                             gettext("Illegal character"));
 575                 break;
 576         case SC_INTEGER:
 577                 errno = 0;
 578                 v->sc_u.sc_integer = strtoll((char *)value, &endptr, 10);
 579                 if (errno != 0 || *endptr)
 580                         uu_die(gettext("illegal value \"%s\" for "
 581                             "%s (%s)\n"), (char *)value,
 582                             lxml_prop_types[type],
 583                             (errno) ? strerror(errno) : "Illegal character");
 584                 break;
 585         case SC_OPAQUE:
 586         case SC_HOST:
 587         case SC_HOSTNAME:
 588         case SC_NET_ADDR:
 589         case SC_NET_ADDR_V4:
 590         case SC_NET_ADDR_V6:
 591         case SC_FMRI:
 592         case SC_URI:
 593         case SC_TIME:
 594         case SC_ASTRING:
 595         case SC_USTRING:
 596                 scf_type = lxml_element_to_type(type);
 597 
 598                 v->sc_u.sc_string = safe_strdup((const char *)value);
 599                 if (lxml_validate_string_value(scf_type,
 600                     v->sc_u.sc_string) != 0)
 601                         uu_die(gettext("illegal value \"%s\" for "
 602                             "%s (%s)\n"), (char *)value,
 603                             lxml_prop_types[type],
 604                             (scf_error()) ? scf_strerror(scf_error()) :
 605                             gettext("Illegal format"));
 606                 v->sc_free = lxml_free_str;
 607                 break;
 608         case SC_BOOLEAN:
 609                 v->sc_u.sc_count = lxml_xlate_boolean(value);
 610                 break;
 611         default:
 612                 uu_die(gettext("unknown value type (%d)\n"), type);
 613                 break;
 614         }
 615 
 616         /* Free the old value */
 617         if (fov && v->sc_free != NULL)
 618                 free((char *)value);
 619 }
 620 
 621 static value_t *
 622 lxml_make_value(element_t type, const xmlChar *value)
 623 {
 624         value_t *v;
 625 
 626         v = internal_value_new();
 627 
 628         v->sc_type = lxml_element_to_type(type);
 629 
 630         lxml_store_value(v, type, value);
 631 
 632         return (v);
 633 }
 634 
 635 static int
 636 lxml_get_value(property_t *prop, element_t vtype, xmlNodePtr value)
 637 {
 638         xmlNodePtr cursor;
 639 
 640         for (cursor = value->xmlChildrenNode; cursor != NULL;
 641             cursor = cursor->next) {
 642                 xmlChar *assigned_value;
 643                 value_t *v;
 644 
 645                 if (lxml_ignorable_block(cursor))
 646                         continue;
 647 
 648                 switch (lxml_xlate_element(cursor->name)) {
 649                 case SC_VALUE_NODE:
 650                         if ((assigned_value = xmlGetProp(cursor,
 651                             (xmlChar *)value_attr)) == NULL)
 652                                 uu_die(gettext("no value on value node?\n"));
 653                         break;
 654                 default:
 655                         uu_die(gettext("value list contains illegal element "
 656                             "\'%s\'\n"), cursor->name);
 657                         break;
 658                 }
 659 
 660                 v = lxml_make_value(vtype, assigned_value);
 661 
 662                 xmlFree(assigned_value);
 663 
 664                 internal_attach_value(prop, v);
 665         }
 666 
 667         return (0);
 668 }
 669 
 670 static int
 671 lxml_get_propval(pgroup_t *pgrp, xmlNodePtr propval)
 672 {
 673         property_t *p;
 674         element_t r;
 675         value_t *v;
 676         xmlChar *type, *val, *override;
 677         int op = pgrp->sc_parent->sc_op;
 678 
 679         p = internal_property_new();
 680 
 681         p->sc_property_name = (char *)xmlGetProp(propval, (xmlChar *)name_attr);
 682         if ((p->sc_property_name == NULL) || (*p->sc_property_name == 0))
 683                 uu_die(gettext("property name missing in group '%s'\n"),
 684                     pgrp->sc_pgroup_name);
 685 
 686         type = xmlGetProp(propval, (xmlChar *)type_attr);
 687         if ((type != NULL) && (*type != 0)) {
 688                 for (r = 0;
 689                     r < sizeof (lxml_prop_types) / sizeof (char *); ++r) {
 690                         if (xmlStrcmp(type,
 691                             (const xmlChar *)lxml_prop_types[r]) == 0)
 692                                 break;
 693                 }
 694 
 695                 if (r >= sizeof (lxml_prop_types) / sizeof (char *))
 696                         uu_die(gettext("property type invalid for "
 697                             "property '%s/%s'\n"), pgrp->sc_pgroup_name,
 698                             p->sc_property_name);
 699 
 700                 p->sc_value_type = lxml_element_to_type(r);
 701         } else if (op == SVCCFG_OP_APPLY) {
 702                 /*
 703                  * Store the property type as invalid, and the value
 704                  * as an ASTRING and let the bundle apply code validate
 705                  * the type/value once the type is found.
 706                  */
 707                 est->sc_miss_type = B_TRUE;
 708                 p->sc_value_type = SCF_TYPE_INVALID;
 709                 r = SC_ASTRING;
 710         } else {
 711                 uu_die(gettext("property type missing for property '%s/%s'\n"),
 712                     pgrp->sc_pgroup_name, p->sc_property_name);
 713         }
 714 
 715         val = xmlGetProp(propval, (xmlChar *)value_attr);
 716         if (val == NULL)
 717                 uu_die(gettext("property value missing for property '%s/%s'\n"),
 718                     pgrp->sc_pgroup_name, p->sc_property_name);
 719 
 720         v = lxml_make_value(r, val);
 721         xmlFree(val);
 722         internal_attach_value(p, v);
 723 
 724         xmlFree(type);
 725 
 726         override = xmlGetProp(propval, (xmlChar *)override_attr);
 727         p->sc_property_override = (xmlStrcmp(override, (xmlChar *)true) == 0);
 728         xmlFree(override);
 729 
 730         return (internal_attach_property(pgrp, p));
 731 }
 732 
 733 static int
 734 lxml_get_property(pgroup_t *pgrp, xmlNodePtr property)
 735 {
 736         property_t *p;
 737         xmlNodePtr cursor;
 738         element_t r;
 739         xmlChar *type, *override;
 740         int op = pgrp->sc_parent->sc_op;
 741 
 742         p = internal_property_new();
 743 
 744         if (((p->sc_property_name = (char *)xmlGetProp(property,
 745             (xmlChar *)name_attr)) == NULL) || (*p->sc_property_name == 0))
 746                 uu_die(gettext("property name missing in group \'%s\'\n"),
 747                     pgrp->sc_pgroup_name);
 748 
 749         type = xmlGetProp(property, (xmlChar *)type_attr);
 750         if ((type != NULL) && (*type != 0)) {
 751                 for (r = 0;
 752                     r < sizeof (lxml_prop_types) / sizeof (char *); r++) {
 753                         if (xmlStrcmp(type,
 754                             (const xmlChar *)lxml_prop_types[r]) == 0)
 755                                 break;
 756                 }
 757 
 758                 if (r >= sizeof (lxml_prop_types) / sizeof (char *))
 759                         uu_die(gettext("property type invalid for "
 760                             "property '%s/%s'\n"), pgrp->sc_pgroup_name,
 761                             p->sc_property_name);
 762 
 763                 p->sc_value_type = lxml_element_to_type(r);
 764         } else if (op == SVCCFG_OP_APPLY) {
 765                 /*
 766                  * Store the property type as invalid, and let the bundle apply
 767                  * code validate the type/value once the type is found.
 768                  */
 769                 p->sc_value_type = SCF_TYPE_INVALID;
 770                 est->sc_miss_type = B_TRUE;
 771         } else {
 772                 uu_die(gettext("property type missing for "
 773                     "property \'%s/%s\'\n"), pgrp->sc_pgroup_name,
 774                     p->sc_property_name);
 775         }
 776 
 777         for (cursor = property->xmlChildrenNode; cursor != NULL;
 778             cursor = cursor->next) {
 779                 if (lxml_ignorable_block(cursor))
 780                         continue;
 781 
 782                 switch (r = lxml_xlate_element(cursor->name)) {
 783                 case SC_ASTRING:
 784                 case SC_BOOLEAN:
 785                 case SC_COUNT:
 786                 case SC_FMRI:
 787                 case SC_HOST:
 788                 case SC_HOSTNAME:
 789                 case SC_INTEGER:
 790                 case SC_NET_ADDR:
 791                 case SC_NET_ADDR_V4:
 792                 case SC_NET_ADDR_V6:
 793                 case SC_OPAQUE:
 794                 case SC_TIME:
 795                 case SC_URI:
 796                 case SC_USTRING:
 797                         /*
 798                          * If the type is invalid then this is an apply
 799                          * operation and the type can be taken from the
 800                          * value list.
 801                          */
 802                         if (p->sc_value_type == SCF_TYPE_INVALID) {
 803                                 p->sc_value_type = lxml_element_to_type(r);
 804                                 type = xmlStrdup((const
 805                                     xmlChar *)lxml_prop_types[r]);
 806 
 807                         } else if (strcmp(lxml_prop_types[r],
 808                             (const char *)type) != 0) {
 809                                 uu_die(gettext("property \'%s\' "
 810                                     "type-to-list mismatch\n"),
 811                                     p->sc_property_name);
 812                         }
 813 
 814                         (void) lxml_get_value(p, r, cursor);
 815                         break;
 816                 default:
 817                         uu_die(gettext("unknown value list type: %s\n"),
 818                             cursor->name);
 819                         break;
 820                 }
 821         }
 822 
 823         xmlFree(type);
 824 
 825         override = xmlGetProp(property, (xmlChar *)override_attr);
 826         p->sc_property_override = (xmlStrcmp(override, (xmlChar *)true) == 0);
 827         xmlFree(override);
 828 
 829         return (internal_attach_property(pgrp, p));
 830 }
 831 
 832 static int
 833 lxml_get_pgroup_stability(pgroup_t *pgrp, xmlNodePtr stab)
 834 {
 835         if (pgrp->sc_parent->sc_op == SVCCFG_OP_APPLY)
 836                 lxml_validate_element(stab);
 837 
 838         return (new_str_prop_from_attr(pgrp, SCF_PROPERTY_STABILITY,
 839             SCF_TYPE_ASTRING, stab, value_attr));
 840 }
 841 
 842 /*
 843  * Property groups can go on any of a service, an instance, or a template.
 844  */
 845 static int
 846 lxml_get_pgroup(entity_t *entity, xmlNodePtr pgroup)
 847 {
 848         pgroup_t *pg;
 849         xmlNodePtr cursor;
 850         xmlChar *name, *type, *delete;
 851 
 852         /*
 853          * property group attributes:
 854          * name: string
 855          * type: string | framework | application
 856          */
 857         name = xmlGetProp(pgroup, (xmlChar *)name_attr);
 858         type = xmlGetProp(pgroup, (xmlChar *)type_attr);
 859         pg = internal_pgroup_find_or_create(entity, (char *)name, (char *)type);
 860         xmlFree(name);
 861         xmlFree(type);
 862 
 863         /*
 864          * Walk the children of this lxml_elements, which are a stability
 865          * element, property elements, or propval elements.
 866          */
 867         for (cursor = pgroup->xmlChildrenNode; cursor != NULL;
 868             cursor = cursor->next) {
 869                 if (lxml_ignorable_block(cursor))
 870                         continue;
 871 
 872                 switch (lxml_xlate_element(cursor->name)) {
 873                 case SC_STABILITY:
 874                         (void) lxml_get_pgroup_stability(pg, cursor);
 875                         break;
 876                 case SC_PROPERTY:
 877                         (void) lxml_get_property(pg, cursor);
 878                         break;
 879                 case SC_PROPVAL:
 880                         (void) lxml_get_propval(pg, cursor);
 881                         break;
 882                 default:
 883                         abort();
 884                         break;
 885                 }
 886         }
 887 
 888         delete = xmlGetProp(pgroup, (xmlChar *)delete_attr);
 889         pg->sc_pgroup_delete = (xmlStrcmp(delete, (xmlChar *)true) == 0);
 890         xmlFree(delete);
 891 
 892         return (0);
 893 }
 894 
 895 
 896 /*
 897  * Dependency groups, execution methods can go on either a service or an
 898  * instance.
 899  */
 900 
 901 static int
 902 lxml_get_method_profile(pgroup_t *pg, xmlNodePtr profile)
 903 {
 904         property_t *p;
 905 
 906         p = internal_property_create(SCF_PROPERTY_USE_PROFILE, SCF_TYPE_BOOLEAN,
 907             1, (uint64_t)1);
 908         if (internal_attach_property(pg, p) != 0)
 909                 return (-1);
 910 
 911         return (new_str_prop_from_attr(pg, SCF_PROPERTY_PROFILE,
 912             SCF_TYPE_ASTRING, profile, name_attr));
 913 }
 914 
 915 static int
 916 lxml_get_method_credential(pgroup_t *pg, xmlNodePtr cred)
 917 {
 918         property_t *p;
 919 
 920         p = internal_property_create(SCF_PROPERTY_USE_PROFILE, SCF_TYPE_BOOLEAN,
 921             1, (uint64_t)0);
 922         if (internal_attach_property(pg, p) != 0)
 923                 return (-1);
 924 
 925         if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_USER, SCF_TYPE_ASTRING,
 926             cred, "user", NULL) != 0)
 927                 return (-1);
 928 
 929         if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_GROUP, SCF_TYPE_ASTRING,
 930             cred, "group", NULL) != 0)
 931                 return (-1);
 932 
 933         if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_SUPP_GROUPS,
 934             SCF_TYPE_ASTRING, cred, "supp_groups", NULL) != 0)
 935                 return (-1);
 936 
 937         if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_PRIVILEGES,
 938             SCF_TYPE_ASTRING, cred, "privileges", NULL) != 0)
 939                 return (-1);
 940 
 941         if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_LIMIT_PRIVILEGES,
 942             SCF_TYPE_ASTRING, cred, "limit_privileges", NULL) != 0)
 943                 return (-1);
 944 
 945         return (0);
 946 }
 947 
 948 static char *
 949 lxml_get_envvar(xmlNodePtr envvar)
 950 {
 951         char *name;
 952         char *value;
 953         char *ret;
 954 
 955         name = (char *)xmlGetProp(envvar, (xmlChar *)name_attr);
 956         value = (char *)xmlGetProp(envvar, (xmlChar *)value_attr);
 957 
 958         if (strlen(name) == 0 || strchr(name, '=') != NULL)
 959                 uu_die(gettext("Invalid environment variable "
 960                     "\"%s\".\n"), name);
 961         if (strstr(name, "SMF_") == name)
 962                 uu_die(gettext("Invalid environment variable "
 963                     "\"%s\"; \"SMF_\" prefix is reserved.\n"), name);
 964 
 965         ret = uu_msprintf("%s=%s", name, value);
 966         xmlFree(name);
 967         xmlFree(value);
 968         return (ret);
 969 }
 970 
 971 static int
 972 lxml_get_method_environment(pgroup_t *pg, xmlNodePtr environment)
 973 {
 974         property_t *p;
 975         xmlNodePtr cursor;
 976         value_t *val;
 977 
 978         p = internal_property_create(SCF_PROPERTY_ENVIRONMENT,
 979             SCF_TYPE_ASTRING, 0);
 980 
 981         for (cursor = environment->xmlChildrenNode; cursor != NULL;
 982             cursor = cursor->next) {
 983                 char *tmp;
 984 
 985                 if (lxml_ignorable_block(cursor))
 986                         continue;
 987 
 988                 if (lxml_xlate_element(cursor->name) != SC_METHOD_ENVVAR)
 989                         uu_die(gettext("illegal element \"%s\" on "
 990                             "method environment for \"%s\"\n"),
 991                             cursor->name, pg->sc_pgroup_name);
 992 
 993                 if ((tmp = lxml_get_envvar(cursor)) == NULL)
 994                         uu_die(gettext("Out of memory\n"));
 995 
 996                 val = internal_value_new();
 997                 val->sc_u.sc_string = tmp;
 998                 val->sc_type = SCF_TYPE_ASTRING;
 999                 val->sc_free = lxml_free_str;
1000                 internal_attach_value(p, val);
1001         }
1002 
1003         if (internal_attach_property(pg, p) != 0) {
1004                 internal_property_free(p);
1005                 return (-1);
1006         }
1007 
1008         return (0);
1009 }
1010 
1011 static int
1012 lxml_get_method_context(pgroup_t *pg, xmlNodePtr ctx)
1013 {
1014         xmlNodePtr cursor;
1015 
1016         if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_WORKING_DIRECTORY,
1017             SCF_TYPE_ASTRING, ctx, "working_directory", NULL) != 0)
1018                 return (-1);
1019 
1020         if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_PROJECT,
1021             SCF_TYPE_ASTRING, ctx, "project", NULL) != 0)
1022                 return (-1);
1023 
1024         if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_RESOURCE_POOL,
1025             SCF_TYPE_ASTRING, ctx, "resource_pool", NULL) != 0)
1026                 return (-1);
1027 
1028         if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_SECFLAGS,
1029             SCF_TYPE_ASTRING, ctx, "security_flags", NULL) != 0)
1030                 return (-1);
1031 
1032         for (cursor = ctx->xmlChildrenNode; cursor != NULL;
1033             cursor = cursor->next) {
1034                 if (lxml_ignorable_block(cursor))
1035                         continue;
1036 
1037                 switch (lxml_xlate_element(cursor->name)) {
1038                 case SC_METHOD_CREDENTIAL:
1039                         (void) lxml_get_method_credential(pg, cursor);
1040                         break;
1041                 case SC_METHOD_PROFILE:
1042                         (void) lxml_get_method_profile(pg, cursor);
1043                         break;
1044                 case SC_METHOD_ENVIRONMENT:
1045                         (void) lxml_get_method_environment(pg, cursor);
1046                         break;
1047                 default:
1048                         semerr(gettext("illegal element \'%s\' in method "
1049                             "context\n"), (char *)cursor);
1050                         break;
1051                 }
1052         }
1053 
1054         return (0);
1055 }
1056 
1057 static int
1058 lxml_get_entity_method_context(entity_t *entity, xmlNodePtr ctx)
1059 {
1060         pgroup_t *pg;
1061 
1062         pg = internal_pgroup_find_or_create(entity, SCF_PG_METHOD_CONTEXT,
1063             (char *)scf_group_framework);
1064 
1065         return (lxml_get_method_context(pg, ctx));
1066 }
1067 
1068 static int
1069 lxml_get_exec_method(entity_t *entity, xmlNodePtr emeth)
1070 {
1071         pgroup_t *pg;
1072         property_t *p;
1073         xmlChar *name, *timeout, *delete;
1074         xmlNodePtr cursor;
1075         int r = 0;
1076 
1077         if (entity->sc_op == SVCCFG_OP_APPLY)
1078                 lxml_validate_element(emeth);
1079 
1080         name = xmlGetProp(emeth, (xmlChar *)name_attr);
1081         pg = internal_pgroup_find_or_create(entity, (char *)name,
1082             (char *)SCF_GROUP_METHOD);
1083         xmlFree(name);
1084 
1085         if (new_str_prop_from_attr(pg, SCF_PROPERTY_TYPE, SCF_TYPE_ASTRING,
1086             emeth, type_attr) != 0 ||
1087             new_str_prop_from_attr(pg, SCF_PROPERTY_EXEC, SCF_TYPE_ASTRING,
1088             emeth, "exec") != 0)
1089                 return (-1);
1090 
1091         timeout = xmlGetProp(emeth, (xmlChar *)timeout_seconds_attr);
1092         if (timeout != NULL) {
1093                 uint64_t u_timeout;
1094                 char *endptr;
1095                 /*
1096                  * Although an SC_COUNT represents a uint64_t the use
1097                  * of a negative value is acceptable due to the usage
1098                  * established by inetd(1M).
1099                  */
1100                 errno = 0;
1101                 u_timeout = strtoull((char *)timeout, &endptr, 10);
1102                 if (errno != 0 || endptr == (char *)timeout || *endptr)
1103                         uu_die(gettext("illegal value \"%s\" for "
1104                             "timeout_seconds (%s)\n"),
1105                             (char *)timeout, (errno) ? strerror(errno):
1106                             gettext("Illegal character"));
1107                 p = internal_property_create(SCF_PROPERTY_TIMEOUT,
1108                     SCF_TYPE_COUNT, 1, u_timeout);
1109                 r = internal_attach_property(pg, p);
1110                 xmlFree(timeout);
1111         }
1112         if (r != 0)
1113                 return (-1);
1114 
1115         /*
1116          * There is a possibility that a method context also exists, in which
1117          * case the following attributes are defined: project, resource_pool,
1118          * working_directory, profile, user, group, privileges,
1119          * limit_privileges, security_flags
1120          */
1121         for (cursor = emeth->xmlChildrenNode; cursor != NULL;
1122             cursor = cursor->next) {
1123                 if (lxml_ignorable_block(cursor))
1124                         continue;
1125 
1126                 switch (lxml_xlate_element(cursor->name)) {
1127                 case SC_STABILITY:
1128                         if (lxml_get_pgroup_stability(pg, cursor) != 0)
1129                                 return (-1);
1130                         break;
1131 
1132                 case SC_METHOD_CONTEXT:
1133                         (void) lxml_get_method_context(pg, cursor);
1134                         break;
1135 
1136                 case SC_PROPVAL:
1137                         (void) lxml_get_propval(pg, cursor);
1138                         break;
1139 
1140                 case SC_PROPERTY:
1141                         (void) lxml_get_property(pg, cursor);
1142                         break;
1143 
1144                 default:
1145                         uu_die(gettext("illegal element \"%s\" on "
1146                             "execution method \"%s\"\n"), cursor->name,
1147                             pg->sc_pgroup_name);
1148                         break;
1149                 }
1150         }
1151 
1152         delete = xmlGetProp(emeth, (xmlChar *)delete_attr);
1153         pg->sc_pgroup_delete = (xmlStrcmp(delete, (xmlChar *)true) == 0);
1154         xmlFree(delete);
1155 
1156         return (0);
1157 }
1158 
1159 static int
1160 lxml_get_dependency(entity_t *entity, xmlNodePtr dependency)
1161 {
1162         pgroup_t *pg;
1163         property_t *p;
1164         xmlNodePtr cursor;
1165         xmlChar *name;
1166         xmlChar *delete;
1167 
1168         /*
1169          * dependency attributes:
1170          * name: string
1171          * grouping: require_all | require_any | exclude_all | optional_all
1172          * reset_on: string (error | restart | refresh | none)
1173          * type:  service / path /host
1174          */
1175 
1176         if (entity->sc_op == SVCCFG_OP_APPLY)
1177                 lxml_validate_element(dependency);
1178 
1179         name = xmlGetProp(dependency, (xmlChar *)name_attr);
1180         pg = internal_pgroup_find_or_create(entity, (char *)name,
1181             (char *)SCF_GROUP_DEPENDENCY);
1182         xmlFree(name);
1183 
1184         if (new_str_prop_from_attr(pg, SCF_PROPERTY_TYPE, SCF_TYPE_ASTRING,
1185             dependency, type_attr) != 0)
1186                 return (-1);
1187 
1188         if (new_str_prop_from_attr(pg, SCF_PROPERTY_RESTART_ON,
1189             SCF_TYPE_ASTRING, dependency, "restart_on") != 0)
1190                 return (-1);
1191 
1192         if (new_str_prop_from_attr(pg, SCF_PROPERTY_GROUPING, SCF_TYPE_ASTRING,
1193             dependency, "grouping") != 0)
1194                 return (-1);
1195 
1196         p = internal_property_create(SCF_PROPERTY_ENTITIES, SCF_TYPE_FMRI, 0);
1197         if (internal_attach_property(pg, p) != 0)
1198                 return (-1);
1199 
1200         for (cursor = dependency->xmlChildrenNode; cursor != NULL;
1201             cursor = cursor->next) {
1202                 xmlChar *value;
1203                 value_t *v;
1204 
1205                 if (lxml_ignorable_block(cursor))
1206                         continue;
1207 
1208                 switch (lxml_xlate_element(cursor->name)) {
1209                 case SC_STABILITY:
1210                         if (lxml_get_pgroup_stability(pg, cursor) != 0)
1211                                 return (-1);
1212                         break;
1213 
1214                 case SC_SERVICE_FMRI:
1215                         value = xmlGetProp(cursor, (xmlChar *)value_attr);
1216                         if (value != NULL) {
1217                                 if (lxml_validate_string_value(SCF_TYPE_FMRI,
1218                                     (char *)value) != 0)
1219                                         uu_die(gettext("illegal value \"%s\" "
1220                                             "for %s (%s)\n"), (char *)value,
1221                                             lxml_prop_types[SC_FMRI],
1222                                             (scf_error()) ?
1223                                             scf_strerror(scf_error()) :
1224                                             gettext("Illegal format"));
1225                                 v = internal_value_new();
1226                                 v->sc_type = SCF_TYPE_FMRI;
1227                                 v->sc_u.sc_string = (char *)value;
1228                                 internal_attach_value(p, v);
1229                         }
1230 
1231                         break;
1232 
1233                 case SC_PROPVAL:
1234                         (void) lxml_get_propval(pg, cursor);
1235                         break;
1236 
1237                 case SC_PROPERTY:
1238                         (void) lxml_get_property(pg, cursor);
1239                         break;
1240 
1241                 default:
1242                         uu_die(gettext("illegal element \"%s\" on "
1243                             "dependency group \"%s\"\n"), cursor->name, name);
1244                         break;
1245                 }
1246         }
1247 
1248         delete = xmlGetProp(dependency, (xmlChar *)delete_attr);
1249         pg->sc_pgroup_delete = (xmlStrcmp(delete, (xmlChar *)true) == 0);
1250         xmlFree(delete);
1251 
1252         return (0);
1253 }
1254 
1255 /*
1256  * Dependents are hairy.  They should cause a dependency pg to be created in
1257  * another service, but we can't do that here; we'll have to wait until the
1258  * import routines.  So for now we'll add the dependency group that should go
1259  * in the other service to the entity's dependent list.
1260  */
1261 static int
1262 lxml_get_dependent(entity_t *entity, xmlNodePtr dependent)
1263 {
1264         xmlChar *name, *or;
1265         xmlNodePtr sf;
1266         xmlChar *fmri, *delete;
1267         pgroup_t *pg;
1268         property_t *p;
1269         xmlNodePtr n;
1270         char *myfmri;
1271 
1272         if (entity->sc_op == SVCCFG_OP_APPLY)
1273                 lxml_validate_element(dependent);
1274 
1275         name = xmlGetProp(dependent, (xmlChar *)name_attr);
1276 
1277         if (internal_pgroup_find(entity, (char *)name, NULL) != NULL) {
1278                 semerr(gettext("Property group and dependent of entity %s "
1279                     "have same name \"%s\".\n"), entity->sc_name, name);
1280                 xmlFree(name);
1281                 return (-1);
1282         }
1283 
1284         or = xmlGetProp(dependent, (xmlChar *)override_attr);
1285 
1286         pg = internal_pgroup_new();
1287         pg->sc_pgroup_name = (char *)name;
1288         pg->sc_pgroup_type = (char *)SCF_GROUP_DEPENDENCY;
1289         pg->sc_pgroup_override = (xmlStrcmp(or, (xmlChar *)true) == 0);
1290         xmlFree(or);
1291         if (internal_attach_dependent(entity, pg) != 0) {
1292                 xmlFree(name);
1293                 internal_pgroup_free(pg);
1294                 return (-1);
1295         }
1296 
1297         for (sf = dependent->children; sf != NULL; sf = sf->next)
1298                 if (xmlStrcmp(sf->name, (xmlChar *)"service_fmri") == 0)
1299                         break;
1300         assert(sf != NULL);
1301         fmri = xmlGetProp(sf, (xmlChar *)value_attr);
1302         pg->sc_pgroup_fmri = (char *)fmri;
1303 
1304         if (new_str_prop_from_attr(pg, SCF_PROPERTY_RESTART_ON,
1305             SCF_TYPE_ASTRING, dependent, "restart_on") != 0)
1306                 return (-1);
1307 
1308         if (new_str_prop_from_attr(pg, SCF_PROPERTY_GROUPING, SCF_TYPE_ASTRING,
1309             dependent, "grouping") != 0)
1310                 return (-1);
1311 
1312         myfmri = safe_malloc(max_scf_fmri_len + 1);
1313         if (entity->sc_etype == SVCCFG_SERVICE_OBJECT) {
1314                 if (snprintf(myfmri, max_scf_fmri_len + 1, "svc:/%s",
1315                     entity->sc_name) < 0)
1316                         bad_error("snprintf", errno);
1317         } else {
1318                 assert(entity->sc_etype == SVCCFG_INSTANCE_OBJECT);
1319                 if (snprintf(myfmri, max_scf_fmri_len + 1, "svc:/%s:%s",
1320                     entity->sc_parent->sc_name, entity->sc_name) < 0)
1321                         bad_error("snprintf", errno);
1322         }
1323 
1324         p = internal_property_create(SCF_PROPERTY_ENTITIES, SCF_TYPE_FMRI, 1,
1325             myfmri);
1326         if (internal_attach_property(pg, p) != 0)
1327                 return (-1);
1328 
1329         /* Create a property to serve as a do-not-export flag. */
1330         p = internal_property_create("external", SCF_TYPE_BOOLEAN, 1,
1331             (uint64_t)1);
1332         if (internal_attach_property(pg, p) != 0)
1333                 return (-1);
1334 
1335         for (n = sf->next; n != NULL; n = n->next) {
1336                 if (lxml_ignorable_block(n))
1337                         continue;
1338 
1339                 switch (lxml_xlate_element(n->name)) {
1340                 case SC_STABILITY:
1341                         if (new_str_prop_from_attr(pg,
1342                             SCF_PROPERTY_ENTITY_STABILITY, SCF_TYPE_ASTRING, n,
1343                             value_attr) != 0)
1344                                 return (-1);
1345                         break;
1346 
1347                 case SC_PROPVAL:
1348                         (void) lxml_get_propval(pg, n);
1349                         break;
1350 
1351                 case SC_PROPERTY:
1352                         (void) lxml_get_property(pg, n);
1353                         break;
1354 
1355                 default:
1356                         uu_die(gettext("unexpected element %s.\n"), n->name);
1357                 }
1358         }
1359 
1360         /* Go back and fill in defaults. */
1361         if (internal_property_find(pg, SCF_PROPERTY_TYPE) == NULL) {
1362                 p = internal_property_create(SCF_PROPERTY_TYPE,
1363                     SCF_TYPE_ASTRING, 1, "service");
1364                 if (internal_attach_property(pg, p) != 0)
1365                         return (-1);
1366         }
1367 
1368         delete = xmlGetProp(dependent, (xmlChar *)delete_attr);
1369         pg->sc_pgroup_delete = (xmlStrcmp(delete, (xmlChar *)true) == 0);
1370         xmlFree(delete);
1371 
1372         pg = internal_pgroup_find_or_create(entity, "dependents",
1373             (char *)scf_group_framework);
1374         p = internal_property_create((char *)name, SCF_TYPE_FMRI, 1, fmri);
1375         if (internal_attach_property(pg, p) != 0)
1376                 return (-1);
1377 
1378         return (0);
1379 }
1380 
1381 static int
1382 lxml_get_entity_stability(entity_t *entity, xmlNodePtr rstr)
1383 {
1384         pgroup_t *pg;
1385         property_t *p;
1386         xmlChar *stabval;
1387 
1388         if (((stabval = xmlGetProp(rstr, (xmlChar *)value_attr)) == NULL) ||
1389             (*stabval == 0)) {
1390                 uu_warn(gettext("no stability value found\n"));
1391                 stabval = (xmlChar *)safe_strdup("External");
1392         }
1393 
1394         pg = internal_pgroup_find_or_create(entity, (char *)scf_pg_general,
1395             (char *)scf_group_framework);
1396 
1397         p = internal_property_create(SCF_PROPERTY_ENTITY_STABILITY,
1398             SCF_TYPE_ASTRING, 1, stabval);
1399 
1400         return (internal_attach_property(pg, p));
1401 }
1402 
1403 static int
1404 lxml_get_restarter(entity_t *entity, xmlNodePtr rstr)
1405 {
1406         pgroup_t *pg;
1407         property_t *p;
1408         xmlChar *restarter;
1409         xmlNode *cursor;
1410         int r;
1411 
1412         /*
1413          * Go find child.  Child is a service_fmri element.  value attribute
1414          * contains restarter FMRI.
1415          */
1416 
1417         pg = internal_pgroup_find_or_create(entity, (char *)scf_pg_general,
1418             (char *)scf_group_framework);
1419 
1420         /*
1421          * Walk its child elements, as appropriate.
1422          */
1423         for (cursor = rstr->xmlChildrenNode; cursor != NULL;
1424             cursor = cursor->next) {
1425                 if (lxml_ignorable_block(cursor))
1426                         continue;
1427 
1428                 switch (lxml_xlate_element(cursor->name)) {
1429                 case SC_SERVICE_FMRI:
1430                         restarter = xmlGetProp(cursor, (xmlChar *)value_attr);
1431                         break;
1432                 default:
1433                         uu_die(gettext("illegal element \"%s\" on restarter "
1434                             "element for \"%s\"\n"), cursor->name,
1435                             entity->sc_name);
1436                         break;
1437                 }
1438         }
1439 
1440         p = internal_property_create(SCF_PROPERTY_RESTARTER, SCF_TYPE_FMRI, 1,
1441             restarter);
1442 
1443         r = internal_attach_property(pg, p);
1444         if (r != 0) {
1445                 internal_property_free(p);
1446                 return (-1);
1447         }
1448 
1449         return (0);
1450 }
1451 
1452 static void
1453 lxml_get_paramval(pgroup_t *pgrp, const char *propname, xmlNodePtr pval)
1454 {
1455         property_t *p;
1456         char *value;
1457         char *prop;
1458 
1459         prop = safe_strdup(propname);
1460 
1461         value = (char *)xmlGetProp(pval, (xmlChar *)value_attr);
1462         if (value == NULL || *value == '\0')
1463                 uu_die(gettext("property value missing for property '%s/%s'\n"),
1464                     pgrp->sc_pgroup_name, propname);
1465         p = internal_property_create(prop, SCF_TYPE_ASTRING, 1, value);
1466 
1467         (void) internal_attach_property(pgrp, p);
1468 }
1469 
1470 static void
1471 lxml_get_parameter(pgroup_t *pgrp, const char *propname, xmlNodePtr param)
1472 {
1473         property_t *p = internal_property_new();
1474 
1475         p->sc_property_name = safe_strdup(propname);
1476         p->sc_value_type = SCF_TYPE_ASTRING;
1477 
1478         (void) lxml_get_value(p, SC_ASTRING, param);
1479 
1480         (void) internal_attach_property(pgrp, p);
1481 }
1482 
1483 static void
1484 lxml_get_type(pgroup_t *pgrp, xmlNodePtr type)
1485 {
1486         property_t *p;
1487         xmlChar *name;
1488         xmlChar *active;
1489         xmlNodePtr cursor;
1490         uint64_t active_val;
1491         size_t sz = max_scf_name_len + 1;
1492         char *propname = safe_malloc(sz);
1493 
1494         if (pgrp->sc_parent->sc_op == SVCCFG_OP_APPLY)
1495                 lxml_validate_element(type);
1496 
1497         name = xmlGetProp(type, (xmlChar *)name_attr);
1498         if (name == NULL || *name == '\0')
1499                 uu_die(gettext("attribute name missing in element 'type'\n"));
1500 
1501         for (cursor = type->xmlChildrenNode; cursor != NULL;
1502             cursor = cursor->next) {
1503                 xmlChar *pname;
1504 
1505                 if (lxml_ignorable_block(cursor))
1506                         continue;
1507 
1508                 pname = xmlGetProp(cursor, (xmlChar *)name_attr);
1509                 if (pname == NULL || *pname == '\0')
1510                         uu_die(gettext(
1511                             "attribute name missing in sub-element of type\n"));
1512 
1513                 if (snprintf(propname, sz, "%s,%s", (char *)name,
1514                     (char *)pname) >= sz)
1515                         uu_die(gettext("name '%s,%s' is too long\n"),
1516                             (char *)name, (char *)pname);
1517                 xmlFree(pname);
1518 
1519                 switch (lxml_xlate_element(cursor->name)) {
1520                 case SC_PARAMETER:
1521                         lxml_get_parameter(pgrp, propname, cursor);
1522                         break;
1523 
1524                 case SC_PARAMVAL:
1525                         lxml_get_paramval(pgrp, propname, cursor);
1526                         break;
1527 
1528                 default:
1529                         uu_die(gettext("unknown element %s\n"), cursor->name);
1530                 }
1531         }
1532 
1533         active = xmlGetProp(type, (xmlChar *)active_attr);
1534         if (active == NULL || strcmp(true, (const char *)active) == 0)
1535                 active_val = 1;
1536         else
1537                 active_val = 0;
1538         xmlFree(active);
1539 
1540         if (snprintf(propname, sz, "%s,%s", (char *)name,
1541             SCF_PROPERTY_ACTIVE_POSTFIX) >= sz)
1542                 uu_die(gettext("name '%s,%s' is too long\n"),
1543                     (char *)name, SCF_PROPERTY_ACTIVE_POSTFIX);
1544 
1545         p = internal_property_create(propname, SCF_TYPE_BOOLEAN, 1, active_val);
1546 
1547         (void) internal_attach_property(pgrp, p);
1548 
1549         xmlFree(name);
1550 }
1551 
1552 static void
1553 lxml_get_event(entity_t *entity, const char *pgname, xmlNodePtr np)
1554 {
1555         xmlNodePtr cursor;
1556         pgroup_t *pgrp;
1557 
1558         pgrp = internal_pgroup_find_or_create(entity, pgname,
1559             SCF_NOTIFY_PARAMS_PG_TYPE);
1560         for (cursor = np->xmlChildrenNode; cursor != NULL;
1561             cursor = cursor->next) {
1562                 if (lxml_ignorable_block(cursor))
1563                         continue;
1564 
1565                 switch (lxml_xlate_element(cursor->name)) {
1566                 case SC_EVENT:
1567                         continue;
1568 
1569                 case SC_TYPE:
1570                         lxml_get_type(pgrp, cursor);
1571                         break;
1572 
1573                 default:
1574                         uu_warn(gettext("illegal element '%s' on "
1575                             "notification parameters\n"), cursor->name);
1576                 }
1577         }
1578 }
1579 
1580 static int
1581 lxml_get_notification_parameters(entity_t *entity, xmlNodePtr np)
1582 {
1583         char *event = NULL;
1584         char **pgs = NULL;
1585         char **p;
1586         char *pgname = NULL;
1587         xmlNodePtr cursor;
1588         int32_t tset, t;
1589         size_t sz = max_scf_name_len + 1;
1590         int count;
1591         int r = -1;
1592 
1593         for (count = 0, cursor = np->xmlChildrenNode; cursor != NULL;
1594             cursor = cursor->next) {
1595                 if (lxml_ignorable_block(cursor))
1596                         continue;
1597 
1598                 if (lxml_xlate_element(cursor->name) == SC_EVENT) {
1599                         xmlChar *s;
1600 
1601                         count++;
1602                         if (count > 1)
1603                                 uu_die(gettext("Can't have more than 1 element "
1604                                     "event in a notification parameter\n"));
1605                         s = xmlGetProp(cursor, (xmlChar *)value_attr);
1606                         if (s == NULL || (event = strdup((char *)s)) == NULL)
1607                                 uu_die(gettext("couldn't allocate memory"));
1608                         xmlFree(s);
1609                 }
1610         }
1611 
1612         pgs = tokenize(event, ",");
1613 
1614         switch (tset = check_tokens(pgs)) {
1615         case INVALID_TOKENS:
1616                 uu_die(gettext("Invalid input.\n"));
1617                 /*NOTREACHED*/
1618         case MIXED_TOKENS:
1619                 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
1620                 goto out;
1621         case FMA_TOKENS:
1622                 /* make sure this is SCF_NOTIFY_PARAMS_INST */
1623                 if (entity->sc_etype != SVCCFG_INSTANCE_OBJECT ||
1624                     strcmp(entity->sc_fmri, SCF_NOTIFY_PARAMS_INST) != 0) {
1625                         semerr(gettext(
1626                             "Non-SMF transition evenst must go to %s\n"),
1627                             SCF_NOTIFY_PARAMS_INST);
1628                         goto out;
1629                 }
1630                 pgname = safe_malloc(sz);
1631                 for (p = pgs; *p; ++p) {
1632                         if (snprintf(pgname, sz, "%s,%s", de_tag(*p),
1633                             SCF_NOTIFY_PG_POSTFIX) >= sz)
1634                                 uu_die(gettext("event name too long: %s\n"),
1635                                     *p);
1636 
1637                         lxml_get_event(entity, pgname, np);
1638                 }
1639 
1640         default:        /* smf state transition tokens */
1641                 if (entity->sc_etype == SVCCFG_SERVICE_OBJECT &&
1642                     strcmp(entity->sc_fmri, SCF_SERVICE_GLOBAL) == 0) {
1643                         semerr(gettext(
1644                             "Can't set events for global service\n"));
1645                         goto out;
1646                 }
1647                 for (t = 0x1; t < SCF_STATE_ALL; t <<= 1) {
1648                         if (t & tset) {
1649                                 lxml_get_event(entity, tset_to_string(t), np);
1650                         }
1651                         if ((t << 16) & tset) {
1652                                 lxml_get_event(entity, tset_to_string(t << 16),
1653                                     np);
1654                         }
1655                 }
1656         }
1657 
1658         r = 0;
1659 out:
1660         free(pgname);
1661         free(pgs);
1662         free(event);
1663 
1664         return (r);
1665 }
1666 
1667 /*
1668  * Add a property containing the localized text from the manifest.  The
1669  * property is added to the property group at pg.  The name of the created
1670  * property is based on the format at pn_format.  This is an snprintf(3C)
1671  * format containing a single %s conversion specification.  At conversion
1672  * time, the %s is replaced by the locale designation.
1673  *
1674  * source is the source element and it is only used for error messages.
1675  */
1676 static int
1677 lxml_get_loctext(entity_t *service, pgroup_t *pg, xmlNodePtr loctext,
1678     const char *pn_format, const char *source)
1679 {
1680         int extra;
1681         xmlNodePtr cursor;
1682         xmlChar *val;
1683         char *stripped, *cp;
1684         property_t *p;
1685         char *prop_name;
1686         int r;
1687 
1688         if (((val = xmlGetProp(loctext, (xmlChar *)xml_lang_attr)) == NULL) ||
1689             (*val == 0)) {
1690                 if (((val = xmlGetProp(loctext,
1691                     (xmlChar *)lang_attr)) == NULL) || (*val == 0)) {
1692                         val = (xmlChar *)"unknown";
1693                 }
1694         }
1695 
1696         _scf_sanitize_locale((char *)val);
1697         prop_name = safe_malloc(max_scf_name_len + 1);
1698         if ((extra = snprintf(prop_name, max_scf_name_len + 1, pn_format,
1699             val)) >= max_scf_name_len + 1) {
1700                 extra -= max_scf_name_len;
1701                 uu_die(gettext("%s attribute is %d characters too long for "
1702                     "%s in %s\n"),
1703                     xml_lang_attr, extra, source, service->sc_name);
1704         }
1705         xmlFree(val);
1706 
1707         for (cursor = loctext->xmlChildrenNode; cursor != NULL;
1708             cursor = cursor->next) {
1709                 if (strcmp("text", (const char *)cursor->name) == 0) {
1710                         break;
1711                 } else if (strcmp("comment", (const char *)cursor->name) != 0) {
1712                         uu_die(gettext("illegal element \"%s\" on loctext "
1713                             "element for \"%s\"\n"), cursor->name,
1714                             service->sc_name);
1715                 }
1716         }
1717 
1718         if (cursor == NULL) {
1719                 uu_die(gettext("loctext element has no content for \"%s\"\n"),
1720                     service->sc_name);
1721         }
1722 
1723         /*
1724          * Remove leading and trailing whitespace.
1725          */
1726         stripped = safe_strdup((const char *)cursor->content);
1727 
1728         for (; isspace(*stripped); stripped++)
1729                 ;
1730         for (cp = stripped + strlen(stripped) - 1; isspace(*cp); cp--)
1731                 ;
1732         *(cp + 1) = '\0';
1733 
1734         p = internal_property_create(prop_name, SCF_TYPE_USTRING, 1,
1735             stripped);
1736 
1737         r = internal_attach_property(pg, p);
1738         if (r != 0) {
1739                 internal_property_free(p);
1740                 free(prop_name);
1741         }
1742 
1743         return (r);
1744 }
1745 
1746 /*
1747  * This function processes all loctext elements in the current XML element
1748  * designated by container.  A property is created for each loctext element
1749  * and added to the property group at pg.  The name of the property is
1750  * derived from the loctext language designation using the format at
1751  * pn_format.  pn_format should be an snprintf format string containing one
1752  * %s which is replaced by the language designation.
1753  *
1754  * The function returns 0 on success and -1 if it is unable to attach the
1755  * newly created property to pg.
1756  */
1757 static int
1758 lxml_get_all_loctext(entity_t *service, pgroup_t *pg, xmlNodePtr container,
1759     const char *pn_format, const char *source)
1760 {
1761         xmlNodePtr cursor;
1762 
1763         /*
1764          * Iterate through one or more loctext elements.  The locale is
1765          * used to generate the property name; the contents are the ustring
1766          * value for the property.
1767          */
1768         for (cursor = container->xmlChildrenNode; cursor != NULL;
1769             cursor = cursor->next) {
1770                 if (lxml_ignorable_block(cursor))
1771                         continue;
1772 
1773                 switch (lxml_xlate_element(cursor->name)) {
1774                 case SC_LOCTEXT:
1775                         if (lxml_get_loctext(service, pg, cursor, pn_format,
1776                             source))
1777                                 return (-1);
1778                         break;
1779                 default:
1780                         uu_die(gettext("illegal element \"%s\" on %s element "
1781                             "for \"%s\"\n"), cursor->name, container->name,
1782                             service->sc_name);
1783                         break;
1784                 }
1785         }
1786 
1787         return (0);
1788 }
1789 
1790 /*
1791  * Obtain the specified cardinality attribute and place it in a property
1792  * named prop_name.  The converted attribute is placed at *value, and the
1793  * newly created property is returned to propp.  NULL is returned to propp
1794  * if the attribute is not provided in the manifest.
1795  *
1796  * 0 is returned upon success, and -1 indicates that the manifest contained
1797  * an invalid cardinality value.
1798  */
1799 static int
1800 lxml_get_cardinality_attribute(entity_t *service, xmlNodePtr cursor,
1801     const char *attr_name, const char *prop_name, uint64_t *value,
1802     property_t **propp)
1803 {
1804         char *c;
1805         property_t *p;
1806         xmlChar *val;
1807         uint64_t count;
1808         char *endptr;
1809 
1810         *propp = NULL;
1811         val = xmlGetProp(cursor, (xmlChar *)attr_name);
1812         if (val == NULL)
1813                 return (0);
1814         if (*val == 0) {
1815                 xmlFree(val);
1816                 return (0);
1817         }
1818 
1819         /*
1820          * Make sure that the string at val doesn't have a leading minus
1821          * sign.  The strtoull() call below does not catch this problem.
1822          */
1823         for (c = (char *)val; *c != 0; c++) {
1824                 if (isspace(*c))
1825                         continue;
1826                 if (isdigit(*c))
1827                         break;
1828                 semerr(gettext("\"%c\" is not a legal character in the %s "
1829                     "attribute of the %s element in %s.\n"), *c,
1830                     attr_name, prop_name, service->sc_name);
1831                 xmlFree(val);
1832                 return (-1);
1833         }
1834         errno = 0;
1835         count = strtoull((char *)val, &endptr, 10);
1836         if (errno != 0 || endptr == (char *)val || *endptr) {
1837                 semerr(gettext("\"%s\" is not a legal number for the %s "
1838                     "attribute of the %s element in %s.\n"), (char *)val,
1839                     attr_name, prop_name, service->sc_name);
1840                 xmlFree(val);
1841                 return (-1);
1842         }
1843 
1844         xmlFree(val);
1845 
1846         /* Value is valid.  Create the property. */
1847         p = internal_property_create(prop_name, SCF_TYPE_COUNT, 1, count);
1848         *value = count;
1849         *propp = p;
1850         return (0);
1851 }
1852 
1853 /*
1854  * The cardinality is specified by two attributes max and min at cursor.
1855  * Both are optional, but if present they must be unsigned integers.
1856  */
1857 static int
1858 lxml_get_tm_cardinality(entity_t *service, pgroup_t *pg, xmlNodePtr cursor)
1859 {
1860         int min_attached = 0;
1861         int compare = 1;
1862         property_t *min_prop;
1863         property_t *max_prop;
1864         uint64_t max;
1865         uint64_t min;
1866         int r;
1867 
1868         r = lxml_get_cardinality_attribute(service, cursor, min_attr,
1869             SCF_PROPERTY_TM_CARDINALITY_MIN, &min, &min_prop);
1870         if (r != 0)
1871                 return (r);
1872         if (min_prop == NULL)
1873                 compare = 0;
1874         r = lxml_get_cardinality_attribute(service, cursor, max_attr,
1875             SCF_PROPERTY_TM_CARDINALITY_MAX, &max, &max_prop);
1876         if (r != 0)
1877                 goto errout;
1878         if ((max_prop != NULL) && (compare == 1)) {
1879                 if (max < min) {
1880                         semerr(gettext("Cardinality max is less than min for "
1881                             "the %s element in %s.\n"), pg->sc_pgroup_name,
1882                             service->sc_fmri);
1883                         goto errout;
1884                 }
1885         }
1886 
1887         /* Attach the properties to the property group. */
1888         if (min_prop) {
1889                 if (internal_attach_property(pg, min_prop) == 0) {
1890                         min_attached = 1;
1891                 } else {
1892                         goto errout;
1893                 }
1894         }
1895         if (max_prop) {
1896                 if (internal_attach_property(pg, max_prop) != 0) {
1897                         if (min_attached)
1898                                 internal_detach_property(pg, min_prop);
1899                         goto errout;
1900                 }
1901         }
1902         return (0);
1903 
1904 errout:
1905         if (min_prop)
1906                 internal_property_free(min_prop);
1907         if (max_prop)
1908                 internal_property_free(max_prop);
1909         return (-1);
1910 }
1911 
1912 /*
1913  * Get the common_name which is present as localized text at common_name in
1914  * the manifest.  The common_name is stored as the value of a property in
1915  * the property group whose name is SCF_PG_TM_COMMON_NAME and type is
1916  * SCF_GROUP_TEMPLATE.  This property group will be created in service if
1917  * it is not already there.
1918  */
1919 static int
1920 lxml_get_tm_common_name(entity_t *service, xmlNodePtr common_name)
1921 {
1922         pgroup_t *pg;
1923 
1924         /*
1925          * Create the property group, if absent.
1926          */
1927         pg = internal_pgroup_find_or_create(service, SCF_PG_TM_COMMON_NAME,
1928             SCF_GROUP_TEMPLATE);
1929 
1930         return (lxml_get_all_loctext(service, pg, common_name, LOCALE_ONLY_FMT,
1931             "common_name"));
1932 }
1933 
1934 /*
1935  * Get the description which is present as localized text at description in
1936  * the manifest.  The description is stored as the value of a property in
1937  * the property group whose name is SCF_PG_TM_DESCRIPTION and type is
1938  * SCF_GROUP_TEMPLATE.  This property group will be created in service if
1939  * it is not already there.
1940  */
1941 static int
1942 lxml_get_tm_description(entity_t *service, xmlNodePtr description)
1943 {
1944         pgroup_t *pg;
1945 
1946         /*
1947          * Create the property group, if absent.
1948          */
1949         pg = internal_pgroup_find_or_create(service, SCF_PG_TM_DESCRIPTION,
1950             SCF_GROUP_TEMPLATE);
1951 
1952         return (lxml_get_all_loctext(service, pg, description,
1953             LOCALE_ONLY_FMT, "description"));
1954 }
1955 
1956 static char *
1957 lxml_label_to_groupname(const char *prefix, const char *in)
1958 {
1959         char *out, *cp;
1960         size_t len, piece_len;
1961 
1962         out = uu_zalloc(2 * max_scf_name_len + 1);
1963         if (out == NULL)
1964                 return (NULL);
1965 
1966         (void) strlcpy(out, prefix, 2 * max_scf_name_len + 1);
1967 
1968         len = strlcat(out, in, 2 * max_scf_name_len + 1);
1969         if (len > max_scf_name_len) {
1970                 /* Use the first half and the second half. */
1971                 piece_len = (max_scf_name_len - 2) / 2;
1972 
1973                 (void) strncpy(out + piece_len, "..", 2);
1974 
1975                 (void) strcpy(out + piece_len + 2, out + (len - piece_len));
1976         }
1977 
1978         /*
1979          * Translate non-property characters to '_'.
1980          */
1981         for (cp = out; *cp != '\0'; ++cp) {
1982                 if (!(isalnum(*cp) || *cp == '_' || *cp == '-'))
1983                         *cp = '_';
1984         }
1985 
1986         return (out);
1987 }
1988 
1989 /*
1990  * If *p is NULL, astring_prop_value() first creates a property with the
1991  * name specified in prop_name.  The address of the newly created property
1992  * is placed in *p.
1993  *
1994  * In either case, newly created property or existing property, a new
1995  * SCF_TYPE_ASTRING value will created and attached to the property at *p.
1996  * The value of the newly created property is prop_value.
1997  *
1998  * free_flag is used to indicate whether or not the memory at prop_value
1999  * should be freed when the property is freed by a call to
2000  * internal_property_free().
2001  */
2002 static void
2003 astring_prop_value(property_t **p, const char *prop_name, char *prop_value,
2004     boolean_t free_flag)
2005 {
2006         value_t *v;
2007 
2008         if (*p == NULL) {
2009                 /* Create the property */
2010                 *p = internal_property_new();
2011                 (*p)->sc_property_name = (char *)prop_name;
2012                 (*p)->sc_value_type = SCF_TYPE_ASTRING;
2013         }
2014 
2015         /* Add the property value to the property's list of values. */
2016         v = internal_value_new();
2017         v->sc_type = SCF_TYPE_ASTRING;
2018         if (free_flag == B_TRUE)
2019                 v->sc_free = lxml_free_str;
2020         v->sc_u.sc_string = prop_value;
2021         internal_attach_value(*p, v);
2022 }
2023 
2024 /*
2025  * If p points to a null pointer, create an internal_separators property
2026  * saving the address at p.  For each character at seps create a property
2027  * value and attach it to the property at p.
2028  */
2029 static void
2030 seps_to_prop_values(property_t **p, xmlChar *seps)
2031 {
2032         value_t *v;
2033         char val_str[2];
2034 
2035         if (*p == NULL) {
2036                 *p = internal_property_new();
2037                 (*p)->sc_property_name =
2038                     (char *)SCF_PROPERTY_INTERNAL_SEPARATORS;
2039                 (*p)->sc_value_type = SCF_TYPE_ASTRING;
2040         }
2041 
2042         /* Add the values to the property's list. */
2043         val_str[1] = 0;         /* Terminate the string. */
2044         for (; *seps != 0; seps++) {
2045                 v = internal_value_new();
2046                 v->sc_type = (*p)->sc_value_type;
2047                 v->sc_free = lxml_free_str;
2048                 val_str[0] = *seps;
2049                 v->sc_u.sc_string = safe_strdup(val_str);
2050                 internal_attach_value(*p, v);
2051         }
2052 }
2053 
2054 /*
2055  * Create an internal_separators property and attach it to the property
2056  * group at pg.  The separator characters are provided in the text nodes
2057  * that are the children of seps.  Each separator character is stored as a
2058  * property value in the internal_separators property.
2059  */
2060 static int
2061 lxml_get_tm_internal_seps(entity_t *service, pgroup_t *pg, xmlNodePtr seps)
2062 {
2063         xmlNodePtr cursor;
2064         property_t *prop = NULL;
2065         int r;
2066 
2067         for (cursor = seps->xmlChildrenNode; cursor != NULL;
2068             cursor = cursor->next) {
2069                 if (strcmp("text", (const char *)cursor->name) == 0) {
2070                         seps_to_prop_values(&prop, cursor->content);
2071                 } else if (strcmp("comment", (const char *)cursor->name) != 0) {
2072                         uu_die(gettext("illegal element \"%s\" on %s element "
2073                             "for \"%s\"\n"), cursor->name, seps->name,
2074                             service->sc_name);
2075                 }
2076         }
2077         if (prop == NULL) {
2078                 semerr(gettext("The %s element in %s had an empty list of "
2079                     "separators.\n"), (const char *)seps->name,
2080                     service->sc_name);
2081                 return (-1);
2082         }
2083         r = internal_attach_property(pg, prop);
2084         if (r != 0)
2085                 internal_property_free(prop);
2086         return (r);
2087 }
2088 
2089 static int
2090 lxml_get_tm_manpage(entity_t *service, xmlNodePtr manpage)
2091 {
2092         pgroup_t *pg;
2093         char *pgname;
2094         char *name;
2095         xmlChar *title;
2096         xmlChar *section;
2097 
2098         /*
2099          * Fetch title and section attributes, convert to something sanitized,
2100          * and create property group.
2101          */
2102         title = xmlGetProp(manpage, (xmlChar *)title_attr);
2103         if (title == NULL)
2104                 return (-1);
2105         section = xmlGetProp(manpage, (xmlChar *)section_attr);
2106         if (section == NULL) {
2107                 xmlFree(title);
2108                 return (-1);
2109         }
2110 
2111         name = safe_malloc(max_scf_name_len + 1);
2112 
2113         /* Find existing property group with underscore separators */
2114         (void) snprintf(name, max_scf_name_len + 1, "%s_%s", title, section);
2115         pgname = lxml_label_to_groupname(SCF_PG_TM_MAN_PREFIX, name);
2116         pg = internal_pgroup_find(service, pgname, SCF_GROUP_TEMPLATE);
2117 
2118         uu_free(pgname);
2119         (void) snprintf(name, max_scf_name_len + 1, "%s%s", title, section);
2120         pgname = lxml_label_to_groupname(SCF_PG_TM_MAN_PREFIX, name);
2121 
2122         if (pg == NULL) {
2123                 pg = internal_pgroup_find_or_create(service, pgname,
2124                     SCF_GROUP_TEMPLATE);
2125         } else {
2126                 /* Rename property group */
2127                 free((char *)pg->sc_pgroup_name);
2128                 pg->sc_pgroup_name = safe_strdup(pgname);
2129         }
2130 
2131         uu_free(pgname);
2132         free(name);
2133         xmlFree(section);
2134         xmlFree(title);
2135 
2136 
2137         /*
2138          * Each attribute is an astring property within the group.
2139          */
2140         if (new_str_prop_from_attr(pg, SCF_PROPERTY_TM_TITLE,
2141             SCF_TYPE_ASTRING, manpage, title_attr) != 0 ||
2142             new_str_prop_from_attr(pg, SCF_PROPERTY_TM_SECTION,
2143             SCF_TYPE_ASTRING, manpage, section_attr) != 0 ||
2144             new_str_prop_from_attr(pg, SCF_PROPERTY_TM_MANPATH,
2145             SCF_TYPE_ASTRING, manpage, manpath_attr) != 0)
2146                 return (-1);
2147 
2148         return (0);
2149 }
2150 
2151 static int
2152 lxml_get_tm_doclink(entity_t *service, xmlNodePtr doc_link)
2153 {
2154         pgroup_t *pg;
2155         char *pgname;
2156         xmlChar *name;
2157 
2158         /*
2159          * Fetch name attribute, convert name to something sanitized, and create
2160          * property group.
2161          */
2162         name = xmlGetProp(doc_link, (xmlChar *)name_attr);
2163         if (name == NULL)
2164                 return (-1);
2165 
2166         pgname = (char *)lxml_label_to_groupname(SCF_PG_TM_DOC_PREFIX,
2167             (const char *)name);
2168 
2169         pg = internal_pgroup_find_or_create(service, pgname,
2170             (char *)SCF_GROUP_TEMPLATE);
2171 
2172         uu_free(pgname);
2173         xmlFree(name);
2174 
2175         /*
2176          * Each attribute is an astring property within the group.
2177          */
2178         if (new_str_prop_from_attr(pg, SCF_PROPERTY_TM_NAME, SCF_TYPE_ASTRING,
2179             doc_link, name_attr) != 0 ||
2180             new_str_prop_from_attr(pg, SCF_PROPERTY_TM_URI, SCF_TYPE_ASTRING,
2181             doc_link, uri_attr) != 0)
2182                 return (-1);
2183 
2184         return (0);
2185 }
2186 
2187 static int
2188 lxml_get_tm_documentation(entity_t *service, xmlNodePtr documentation)
2189 {
2190         xmlNodePtr cursor;
2191 
2192         for (cursor = documentation->xmlChildrenNode; cursor != NULL;
2193             cursor = cursor->next) {
2194                 if (lxml_ignorable_block(cursor))
2195                         continue;
2196 
2197                 switch (lxml_xlate_element(cursor->name)) {
2198                 case SC_MANPAGE:
2199                         (void) lxml_get_tm_manpage(service, cursor);
2200                         break;
2201                 case SC_DOC_LINK:
2202                         (void) lxml_get_tm_doclink(service, cursor);
2203                         break;
2204                 default:
2205                         uu_die(gettext("illegal element \"%s\" on template "
2206                             "for service \"%s\"\n"),
2207                             cursor->name, service->sc_name);
2208                 }
2209         }
2210 
2211         return (0);
2212 }
2213 
2214 static int
2215 lxml_get_prop_pattern_attributes(pgroup_t *pg, xmlNodePtr cursor)
2216 {
2217         if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_TM_NAME,
2218             SCF_TYPE_ASTRING, cursor, name_attr, NULL) != 0) {
2219                 return (-1);
2220         }
2221         if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_TM_TYPE,
2222             SCF_TYPE_ASTRING, cursor, type_attr, "") != 0) {
2223                 return (-1);
2224         }
2225         if (new_bool_prop_from_attr(pg, SCF_PROPERTY_TM_REQUIRED, cursor,
2226             required_attr) != 0)
2227                 return (-1);
2228         return (0);
2229 }
2230 
2231 static int
2232 lxml_get_tm_include_values(entity_t *service, pgroup_t *pg,
2233     xmlNodePtr include_values, const char *prop_name)
2234 {
2235         boolean_t attach_to_pg = B_FALSE;
2236         property_t *p;
2237         int r = 0;
2238         char *type;
2239 
2240         /* Get the type attribute of the include_values element. */
2241         type = (char *)xmlGetProp(include_values, (const xmlChar *)type_attr);
2242         if ((type == NULL) || (*type == 0)) {
2243                 uu_die(gettext("%s element requires a %s attribute in the %s "
2244                     "service.\n"), include_values->name, type_attr,
2245                     service->sc_name);
2246         }
2247 
2248         /* Add the type to the values of the prop_name property. */
2249         p = internal_property_find(pg, prop_name);
2250         if (p == NULL)
2251                 attach_to_pg = B_TRUE;
2252         astring_prop_value(&p, prop_name, type, B_FALSE);
2253         if (attach_to_pg == B_TRUE) {
2254                 r = internal_attach_property(pg, p);
2255                 if (r != 0)
2256                         internal_property_free(p);
2257         }
2258         return (r);
2259 }
2260 
2261 #define RC_MIN          0
2262 #define RC_MAX          1
2263 #define RC_COUNT        2
2264 
2265 /*
2266  * Verify that the strings at min and max are valid numeric strings.  Also
2267  * verify that max is numerically >= min.
2268  *
2269  * 0 is returned if the range is valid, and -1 is returned if it is not.
2270  */
2271 static int
2272 verify_range(entity_t *service, xmlNodePtr range, char *min, char *max)
2273 {
2274         char *c;
2275         int i;
2276         int is_signed = 0;
2277         int inverted = 0;
2278         const char *limit[RC_COUNT];
2279         char *strings[RC_COUNT];
2280         uint64_t urange[RC_COUNT];      /* unsigned range. */
2281         int64_t srange[RC_COUNT];       /* signed range. */
2282 
2283         strings[RC_MIN] = min;
2284         strings[RC_MAX] = max;
2285         limit[RC_MIN] = min_attr;
2286         limit[RC_MAX] = max_attr;
2287 
2288         /* See if the range is signed. */
2289         for (i = 0; (i < RC_COUNT) && (is_signed == 0); i++) {
2290                 c = strings[i];
2291                 while (isspace(*c)) {
2292                         c++;
2293                 }
2294                 if (*c == '-')
2295                         is_signed = 1;
2296         }
2297 
2298         /* Attempt to convert the strings. */
2299         for (i = 0; i < RC_COUNT; i++) {
2300                 errno = 0;
2301                 if (is_signed) {
2302                         srange[i] = strtoll(strings[i], &c, 0);
2303                 } else {
2304                         urange[i] = strtoull(strings[i], &c, 0);
2305                 }
2306                 if ((errno != 0) || (c == strings[i]) || (*c != 0)) {
2307                         /* Conversion failed. */
2308                         uu_die(gettext("Unable to convert %s for the %s "
2309                             "element in service %s.\n"), limit[i],
2310                             (char *)range->name, service->sc_name);
2311                 }
2312         }
2313 
2314         /* Make sure that min is <= max */
2315         if (is_signed) {
2316                 if (srange[RC_MAX] < srange[RC_MIN])
2317                         inverted = 1;
2318         } else {
2319                 if (urange[RC_MAX] < urange[RC_MIN])
2320                         inverted = 1;
2321         }
2322         if (inverted != 0) {
2323                 semerr(gettext("Maximum less than minimum for the %s element "
2324                     "in service %s.\n"), (char *)range->name,
2325                     service->sc_name);
2326                 return (-1);
2327         }
2328 
2329         return (0);
2330 }
2331 
2332 /*
2333  * This, function creates a property named prop_name.  The range element
2334  * should have two attributes -- min and max.  The property value then
2335  * becomes the concatenation of their value separated by a comma.  The
2336  * property is then attached to the property group at pg.
2337  *
2338  * If pg already contains a property with a name of prop_name, it is only
2339  * necessary to create a new value and attach it to the existing property.
2340  */
2341 static int
2342 lxml_get_tm_range(entity_t *service, pgroup_t *pg, xmlNodePtr range,
2343     const char *prop_name)
2344 {
2345         boolean_t attach_to_pg = B_FALSE;
2346         char *max;
2347         char *min;
2348         property_t *p;
2349         char *prop_value;
2350         int r = 0;
2351 
2352         /* Get max and min from the XML description. */
2353         max = (char *)xmlGetProp(range, (xmlChar *)max_attr);
2354         if ((max == NULL) || (*max == 0)) {
2355                 uu_die(gettext("%s element is missing the %s attribute in "
2356                     "service %s.\n"), (char *)range->name, max_attr,
2357                     service->sc_name);
2358         }
2359         min = (char *)xmlGetProp(range, (xmlChar *)min_attr);
2360         if ((min == NULL) || (*min == 0)) {
2361                 uu_die(gettext("%s element is missing the %s attribute in "
2362                     "service %s.\n"), (char *)range->name, min_attr,
2363                     service->sc_name);
2364         }
2365         if (verify_range(service, range, min, max) != 0) {
2366                 xmlFree(min);
2367                 xmlFree(max);
2368                 return (-1);
2369         }
2370 
2371         /* Property value is concatenation of min and max. */
2372         prop_value = safe_malloc(max_scf_value_len + 1);
2373         if (snprintf(prop_value, max_scf_value_len + 1, "%s,%s", min, max) >=
2374             max_scf_value_len + 1) {
2375                 uu_die(gettext("min and max are too long for the %s element "
2376                     "of %s.\n"), (char *)range->name, service->sc_name);
2377         }
2378         xmlFree(min);
2379         xmlFree(max);
2380 
2381         /*
2382          * If necessary create the property and attach it to the property
2383          * group.
2384          */
2385         p = internal_property_find(pg, prop_name);
2386         if (p == NULL)
2387                 attach_to_pg = B_TRUE;
2388         astring_prop_value(&p, prop_name, prop_value, B_TRUE);
2389         if (attach_to_pg == B_TRUE) {
2390                 r = internal_attach_property(pg, p);
2391                 if (r != 0) {
2392                         internal_property_free(p);
2393                 }
2394         }
2395         return (r);
2396 }
2397 
2398 /*
2399  * Determine how many plain characters are represented by count Base32
2400  * encoded characters.  5 plain text characters are converted to 8 Base32
2401  * characters.
2402  */
2403 static size_t
2404 encoded_count_to_plain(size_t count)
2405 {
2406         return (5 * ((count + 7) / 8));
2407 }
2408 
2409 /*
2410  * The value element contains 0 or 1 common_name element followed by 0 or 1
2411  * description element.  It also has a required attribute called "name".
2412  * The common_name and description are stored as property values in pg.
2413  * The property names are:
2414  *      value_<name>_common_name_<lang>
2415  *      value_<name>_description_<lang>
2416  *
2417  * The <name> portion of the preceeding proper names requires more
2418  * explanation.  Ideally it would just the name attribute of this value
2419  * element.  Unfortunately, the name attribute can contain characters that
2420  * are not legal in a property name.  Thus, we base 32 encode the name
2421  * attribute and use that for <name>.
2422  *
2423  * There are cases where the caller needs to know the name, so it is
2424  * returned through the name_value pointer if it is not NULL.
2425  *
2426  * Parameters:
2427  *      service -       Information about the service that is being
2428  *                      processed.  This function only uses this parameter
2429  *                      for producing error messages.
2430  *
2431  *      pg -            The property group to receive the newly created
2432  *                      properties.
2433  *
2434  *      value -         Pointer to the value element in the XML tree.
2435  *
2436  *      name_value -    Address to receive the value of the name attribute.
2437  *                      The caller must free the memory.
2438  */
2439 static int
2440 lxml_get_tm_value_element(entity_t *service, pgroup_t *pg, xmlNodePtr value,
2441     char **name_value)
2442 {
2443         char *common_name_fmt;
2444         xmlNodePtr cursor;
2445         char *description_fmt;
2446         char *encoded_value = NULL;
2447         size_t extra;
2448         char *value_name;
2449         int r = 0;
2450 
2451         common_name_fmt = safe_malloc(max_scf_name_len + 1);
2452         description_fmt = safe_malloc(max_scf_name_len + 1);
2453 
2454         /*
2455          * Get the value of our name attribute, so that we can use it to
2456          * construct property names.
2457          */
2458         value_name = (char *)xmlGetProp(value, (xmlChar *)name_attr);
2459         /* The value name must be present, but it can be empty. */
2460         if (value_name == NULL) {
2461                 uu_die(gettext("%s element requires a %s attribute in the %s "
2462                     "service.\n"), (char *)value->name, name_attr,
2463                     service->sc_name);
2464         }
2465 
2466         /*
2467          * The value_name may contain characters that are not valid in in a
2468          * property name.  So we will encode value_name and then use the
2469          * encoded value in the property name.
2470          */
2471         encoded_value = safe_malloc(max_scf_name_len + 1);
2472         if (scf_encode32(value_name, strlen(value_name), encoded_value,
2473             max_scf_name_len + 1, &extra, SCF_ENCODE32_PAD) != 0) {
2474                 extra = encoded_count_to_plain(extra - max_scf_name_len);
2475                 uu_die(gettext("Constructed property name is %u characters "
2476                     "too long for value \"%s\" in the %s service.\n"),
2477                     extra, value_name, service->sc_name);
2478         }
2479         if ((extra = snprintf(common_name_fmt, max_scf_name_len + 1,
2480             VALUE_COMMON_NAME_FMT, SCF_PROPERTY_TM_VALUE_PREFIX,
2481             encoded_value)) >= max_scf_name_len + 1) {
2482                 extra = encoded_count_to_plain(extra - max_scf_name_len);
2483                 uu_die(gettext("Name attribute is "
2484                     "%u characters too long for %s in service %s\n"),
2485                     extra, (char *)value->name, service->sc_name);
2486         }
2487         if ((extra = snprintf(description_fmt, max_scf_name_len + 1,
2488             VALUE_DESCRIPTION_FMT, SCF_PROPERTY_TM_VALUE_PREFIX,
2489             encoded_value)) >= max_scf_name_len + 1) {
2490                 extra = encoded_count_to_plain(extra - max_scf_name_len);
2491                 uu_die(gettext("Name attribute is "
2492                     "%u characters too long for %s in service %s\n"),
2493                     extra, (char *)value->name, service->sc_name);
2494         }
2495 
2496         for (cursor = value->xmlChildrenNode;
2497             cursor != NULL;
2498             cursor = cursor->next) {
2499                 if (lxml_ignorable_block(cursor))
2500                         continue;
2501                 switch (lxml_xlate_element(cursor->name)) {
2502                 case SC_COMMON_NAME:
2503                         r = lxml_get_all_loctext(service, pg, cursor,
2504                             common_name_fmt, (const char *)cursor->name);
2505                         break;
2506                 case SC_DESCRIPTION:
2507                         r = lxml_get_all_loctext(service, pg, cursor,
2508                             description_fmt, (const char *)cursor->name);
2509                         break;
2510                 default:
2511                         uu_die(gettext("\"%s\" is an illegal element in %s "
2512                             "of service %s\n"), (char *)cursor->name,
2513                             (char *)value->name, service->sc_name);
2514                 }
2515                 if (r != 0)
2516                         break;
2517         }
2518 
2519         free(description_fmt);
2520         free(common_name_fmt);
2521         if (r == 0) {
2522                 *name_value = safe_strdup(value_name);
2523         }
2524         xmlFree(value_name);
2525         free(encoded_value);
2526         return (r);
2527 }
2528 
2529 static int
2530 lxml_get_tm_choices(entity_t *service, pgroup_t *pg, xmlNodePtr choices)
2531 {
2532         xmlNodePtr cursor;
2533         char *name_value;
2534         property_t *name_prop = NULL;
2535         int r = 0;
2536 
2537         for (cursor = choices->xmlChildrenNode;
2538             (cursor != NULL) && (r == 0);
2539             cursor = cursor->next) {
2540                 if (lxml_ignorable_block(cursor))
2541                         continue;
2542                 switch (lxml_xlate_element(cursor->name)) {
2543                 case SC_INCLUDE_VALUES:
2544                         (void) lxml_get_tm_include_values(service, pg, cursor,
2545                             SCF_PROPERTY_TM_CHOICES_INCLUDE_VALUES);
2546                         break;
2547                 case SC_RANGE:
2548                         r = lxml_get_tm_range(service, pg, cursor,
2549                             SCF_PROPERTY_TM_CHOICES_RANGE);
2550                         if (r != 0)
2551                                 goto out;
2552                         break;
2553                 case SC_VALUE:
2554                         r = lxml_get_tm_value_element(service, pg, cursor,
2555                             &name_value);
2556                         if (r == 0) {
2557                                 /*
2558                                  * There is no need to free the memory
2559                                  * associated with name_value, because the
2560                                  * property value will end up pointing to
2561                                  * the memory.
2562                                  */
2563                                 astring_prop_value(&name_prop,
2564                                     SCF_PROPERTY_TM_CHOICES_NAME, name_value,
2565                                     B_TRUE);
2566                         } else {
2567                                 goto out;
2568                         }
2569                         break;
2570                 default:
2571                         uu_die(gettext("%s is an invalid element of "
2572                             "choices for service %s.\n"),  cursor->name,
2573                             service->sc_name);
2574                 }
2575         }
2576 
2577 out:
2578         /* Attach the name property if we created one. */
2579         if ((r == 0) && (name_prop != NULL)) {
2580                 r = internal_attach_property(pg, name_prop);
2581         }
2582         if ((r != 0) && (name_prop != NULL)) {
2583                 internal_property_free(name_prop);
2584         }
2585 
2586         return (r);
2587 }
2588 
2589 static int
2590 lxml_get_tm_constraints(entity_t *service, pgroup_t *pg, xmlNodePtr constraints)
2591 {
2592         xmlNodePtr cursor;
2593         char *name_value;
2594         property_t *name_prop = NULL;
2595         int r = 0;
2596 
2597         for (cursor = constraints->xmlChildrenNode;
2598             (cursor != NULL) && (r == 0);
2599             cursor = cursor->next) {
2600                 if (lxml_ignorable_block(cursor))
2601                         continue;
2602                 switch (lxml_xlate_element(cursor->name)) {
2603                 case SC_RANGE:
2604                         r = lxml_get_tm_range(service, pg, cursor,
2605                             SCF_PROPERTY_TM_CONSTRAINT_RANGE);
2606                         if (r != 0)
2607                                 goto out;
2608                         break;
2609                 case SC_VALUE:
2610                         r = lxml_get_tm_value_element(service, pg, cursor,
2611                             &name_value);
2612                         if (r == 0) {
2613                                 /*
2614                                  * There is no need to free the memory
2615                                  * associated with name_value, because the
2616                                  * property value will end up pointing to
2617                                  * the memory.
2618                                  */
2619                                 astring_prop_value(&name_prop,
2620                                     SCF_PROPERTY_TM_CONSTRAINT_NAME, name_value,
2621                                     B_TRUE);
2622                         } else {
2623                                 goto out;
2624                         }
2625                         break;
2626                 default:
2627                         uu_die(gettext("%s is an invalid element of "
2628                             "constraints for service %s.\n"),  cursor->name,
2629                             service->sc_name);
2630                 }
2631         }
2632 
2633 out:
2634         /* Attach the name property if we created one. */
2635         if ((r == 0) && (name_prop != NULL)) {
2636                 r = internal_attach_property(pg, name_prop);
2637         }
2638         if ((r != 0) && (name_prop != NULL)) {
2639                 internal_property_free(name_prop);
2640         }
2641 
2642         return (r);
2643 }
2644 
2645 /*
2646  * The values element contains one or more value elements.
2647  */
2648 static int
2649 lxml_get_tm_values(entity_t *service, pgroup_t *pg, xmlNodePtr values)
2650 {
2651         xmlNodePtr cursor;
2652         char *name_value;
2653         property_t *name_prop = NULL;
2654         int r = 0;
2655 
2656         for (cursor = values->xmlChildrenNode;
2657             (cursor != NULL) && (r == 0);
2658             cursor = cursor->next) {
2659                 if (lxml_ignorable_block(cursor))
2660                         continue;
2661                 if (lxml_xlate_element(cursor->name) != SC_VALUE) {
2662                         uu_die(gettext("\"%s\" is an illegal element in the "
2663                             "%s element of %s\n"), (char *)cursor->name,
2664                             (char *)values->name, service->sc_name);
2665                 }
2666                 r = lxml_get_tm_value_element(service, pg, cursor, &name_value);
2667                 if (r == 0) {
2668                         /*
2669                          * There is no need to free the memory
2670                          * associated with name_value, because the
2671                          * property value will end up pointing to
2672                          * the memory.
2673                          */
2674                         astring_prop_value(&name_prop,
2675                             SCF_PROPERTY_TM_VALUES_NAME, name_value,
2676                             B_TRUE);
2677                 }
2678         }
2679 
2680         /* Attach the name property if we created one. */
2681         if ((r == 0) && (name_prop != NULL)) {
2682                 r = internal_attach_property(pg, name_prop);
2683         }
2684         if ((r != 0) && (name_prop != NULL)) {
2685                 internal_property_free(name_prop);
2686         }
2687 
2688         return (r);
2689 }
2690 
2691 /*
2692  * This function processes a prop_pattern element within a pg_pattern XML
2693  * element.  First it creates a property group to hold the prop_pattern
2694  * information.  The name of this property group is the concatenation of:
2695  *      - SCF_PG_TM_PROP_PATTERN_PREFIX
2696  *      - The unique part of the property group name of the enclosing
2697  *        pg_pattern.  The property group name of the enclosing pg_pattern
2698  *        is passed to us in pgpat_name.  The unique part, is the part
2699  *        following SCF_PG_TM_PG_PATTERN_PREFIX.
2700  *      - The name of this prop_pattern element.
2701  *
2702  * After creating the property group, the prop_pattern attributes are saved
2703  * as properties in the PG.  Finally, the prop_pattern elements are
2704  * processed and added to the PG.
2705  */
2706 static int
2707 lxml_get_tm_prop_pattern(entity_t *service, xmlNodePtr prop_pattern,
2708     const char *pgpat_name)
2709 {
2710         xmlNodePtr cursor;
2711         int extra;
2712         pgroup_t *pg;
2713         property_t *p;
2714         char *pg_name;
2715         size_t prefix_len;
2716         xmlChar *prop_pattern_name;
2717         int r;
2718         const char *unique;
2719         value_t *v;
2720 
2721         /* Find the unique part of the pg_pattern property group name. */
2722         prefix_len = strlen(SCF_PG_TM_PG_PAT_BASE);
2723         assert(strncmp(pgpat_name, SCF_PG_TM_PG_PAT_BASE, prefix_len) == 0);
2724         unique = pgpat_name + prefix_len;
2725 
2726         /*
2727          * We need to get the value of the name attribute first.  The
2728          * prop_pattern name as well as the name of the enclosing
2729          * pg_pattern both constitute part of the name of the property
2730          * group that we will create.
2731          */
2732         prop_pattern_name = xmlGetProp(prop_pattern, (xmlChar *)name_attr);
2733         if ((prop_pattern_name == NULL) || (*prop_pattern_name == 0)) {
2734                 semerr(gettext("prop_pattern name is missing for %s\n"),
2735                     service->sc_name);
2736                 return (-1);
2737         }
2738         if (uu_check_name((const char *)prop_pattern_name,
2739             UU_NAME_DOMAIN) != 0) {
2740                 semerr(gettext("prop_pattern name, \"%s\", for %s is not "
2741                     "valid.\n"), prop_pattern_name, service->sc_name);
2742                 xmlFree(prop_pattern_name);
2743                 return (-1);
2744         }
2745         pg_name = safe_malloc(max_scf_name_len + 1);
2746         if ((extra = snprintf(pg_name, max_scf_name_len + 1, "%s%s_%s",
2747             SCF_PG_TM_PROP_PATTERN_PREFIX, unique,
2748             (char *)prop_pattern_name)) >= max_scf_name_len + 1) {
2749                 uu_die(gettext("prop_pattern name, \"%s\", for %s is %d "
2750                     "characters too long\n"), (char *)prop_pattern_name,
2751                     service->sc_name, extra - max_scf_name_len);
2752         }
2753 
2754         /*
2755          * Create the property group, the property referencing the pg_pattern
2756          * name, and add the prop_pattern attributes to the property group.
2757          */
2758         pg = internal_pgroup_create_strict(service, pg_name,
2759             SCF_GROUP_TEMPLATE_PROP_PATTERN);
2760         if (pg == NULL) {
2761                 uu_die(gettext("Property group for prop_pattern, \"%s\", "
2762                     "already exists in %s\n"), prop_pattern_name,
2763                     service->sc_name);
2764         }
2765 
2766         p = internal_property_create(SCF_PROPERTY_TM_PG_PATTERN,
2767             SCF_TYPE_ASTRING, 1, safe_strdup(pgpat_name));
2768         /*
2769          * Unfortunately, internal_property_create() does not set the free
2770          * function for the value, so we'll set it now.
2771          */
2772         v = uu_list_first(p->sc_property_values);
2773         v->sc_free = lxml_free_str;
2774         if (internal_attach_property(pg, p) != 0)
2775                 internal_property_free(p);
2776 
2777 
2778         r = lxml_get_prop_pattern_attributes(pg, prop_pattern);
2779         if (r != 0)
2780                 goto out;
2781 
2782         /*
2783          * Now process the elements of prop_pattern
2784          */
2785         for (cursor = prop_pattern->xmlChildrenNode;
2786             cursor != NULL;
2787             cursor = cursor->next) {
2788                 if (lxml_ignorable_block(cursor))
2789                         continue;
2790 
2791                 switch (lxml_xlate_element(cursor->name)) {
2792                 case SC_CARDINALITY:
2793                         r = lxml_get_tm_cardinality(service, pg, cursor);
2794                         if (r != 0)
2795                                 goto out;
2796                         break;
2797                 case SC_CHOICES:
2798                         r = lxml_get_tm_choices(service, pg, cursor);
2799                         if (r != 0)
2800                                 goto out;
2801                         break;
2802                 case SC_COMMON_NAME:
2803                         (void) lxml_get_all_loctext(service, pg, cursor,
2804                             COMMON_NAME_FMT, (const char *)cursor->name);
2805                         break;
2806                 case SC_CONSTRAINTS:
2807                         r = lxml_get_tm_constraints(service, pg, cursor);
2808                         if (r != 0)
2809                                 goto out;
2810                         break;
2811                 case SC_DESCRIPTION:
2812                         (void) lxml_get_all_loctext(service, pg, cursor,
2813                             DESCRIPTION_FMT, (const char *)cursor->name);
2814                         break;
2815                 case SC_INTERNAL_SEPARATORS:
2816                         r = lxml_get_tm_internal_seps(service, pg, cursor);
2817                         if (r != 0)
2818                                 goto out;
2819                         break;
2820                 case SC_UNITS:
2821                         (void) lxml_get_all_loctext(service, pg, cursor,
2822                             UNITS_FMT, "units");
2823                         break;
2824                 case SC_VALUES:
2825                         (void) lxml_get_tm_values(service, pg, cursor);
2826                         break;
2827                 case SC_VISIBILITY:
2828                         /*
2829                          * The visibility element is empty, so we only need
2830                          * to proccess the value attribute.
2831                          */
2832                         (void) new_str_prop_from_attr(pg,
2833                             SCF_PROPERTY_TM_VISIBILITY, SCF_TYPE_ASTRING,
2834                             cursor, value_attr);
2835                         break;
2836                 default:
2837                         uu_die(gettext("illegal element \"%s\" in prop_pattern "
2838                             "for service \"%s\"\n"), cursor->name,
2839                             service->sc_name);
2840                 }
2841         }
2842 
2843 out:
2844         xmlFree(prop_pattern_name);
2845         free(pg_name);
2846         return (r);
2847 }
2848 
2849 /*
2850  * Get the pg_pattern attributes and save them as properties in the
2851  * property group at pg.  The pg_pattern element accepts four attributes --
2852  * name, type, required and target.
2853  */
2854 static int
2855 lxml_get_pg_pattern_attributes(pgroup_t *pg, xmlNodePtr cursor)
2856 {
2857         if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_TM_NAME,
2858             SCF_TYPE_ASTRING, cursor, name_attr, NULL) != 0) {
2859                 return (-1);
2860         }
2861         if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_TM_TYPE,
2862             SCF_TYPE_ASTRING, cursor, type_attr, NULL) != 0) {
2863                 return (-1);
2864         }
2865         if (new_opt_str_prop_from_attr(pg, SCF_PROPERTY_TM_TARGET,
2866             SCF_TYPE_ASTRING, cursor, target_attr, NULL) != 0) {
2867                 return (-1);
2868         }
2869         if (new_bool_prop_from_attr(pg, SCF_PROPERTY_TM_REQUIRED, cursor,
2870             required_attr) != 0)
2871                 return (-1);
2872         return (0);
2873 }
2874 
2875 /*
2876  * There are several restrictions on the pg_pattern attributes that cannot
2877  * be specifed in the service bundle DTD.  This function verifies that
2878  * those restrictions have been satisfied.  The restrictions are:
2879  *
2880  *      - The target attribute may have a value of "instance" only when the
2881  *        template block is in a service declaration.
2882  *
2883  *      - The target attribute may have a value of "delegate" only when the
2884  *        template block applies to a restarter.
2885  *
2886  *      - The target attribute may have a value of "all" only when the
2887  *        template block applies to the master restarter.
2888  *
2889  * The function returns 0 on success and -1 on failure.
2890  */
2891 static int
2892 verify_pg_pattern_attributes(entity_t *s, pgroup_t *pg)
2893 {
2894         int is_restarter;
2895         property_t *target;
2896         value_t *v;
2897 
2898         /* Find the value of the target property. */
2899         target = internal_property_find(pg, SCF_PROPERTY_TM_TARGET);
2900         if (target == NULL) {
2901                 uu_die(gettext("pg_pattern is missing the %s attribute "
2902                     "in %s\n"), target_attr, s->sc_name);
2903                 return (-1);
2904         }
2905         v = uu_list_first(target->sc_property_values);
2906         assert(v != NULL);
2907         assert(v->sc_type == SCF_TYPE_ASTRING);
2908 
2909         /*
2910          * If target has a value of instance, the template must be in a
2911          * service object.
2912          */
2913         if (strcmp(v->sc_u.sc_string, "instance") == 0) {
2914                 if (s->sc_etype != SVCCFG_SERVICE_OBJECT) {
2915                         uu_warn(gettext("pg_pattern %s attribute may only "
2916                             "have a value of \"instance\" when it is in a "
2917                             "service declaration.\n"), target_attr);
2918                         return (-1);
2919                 }
2920         }
2921 
2922         /*
2923          * If target has a value of "delegate", the template must be in a
2924          * restarter.
2925          */
2926         if (strcmp(v->sc_u.sc_string, "delegate") == 0) {
2927                 is_restarter = 0;
2928                 if ((s->sc_etype == SVCCFG_SERVICE_OBJECT) &&
2929                     (s->sc_u.sc_service.sc_service_type == SVCCFG_RESTARTER)) {
2930                         is_restarter = 1;
2931                 }
2932                 if ((s->sc_etype == SVCCFG_INSTANCE_OBJECT) &&
2933                     (s->sc_parent->sc_u.sc_service.sc_service_type ==
2934                     SVCCFG_RESTARTER)) {
2935                         is_restarter = 1;
2936                 }
2937                 if (is_restarter == 0) {
2938                         uu_warn(gettext("pg_pattern %s attribute has a "
2939                             "value of \"delegate\" but is not in a "
2940                             "restarter service\n"), target_attr);
2941                         return (-1);
2942                 }
2943         }
2944 
2945         /*
2946          * If target has a value of "all", the template must be in the
2947          * global (SCF_SERVICE_GLOBAL) service.
2948          */
2949         if (strcmp(v->sc_u.sc_string, all_value) == 0) {
2950                 if (s->sc_etype != SVCCFG_SERVICE_OBJECT) {
2951                         uu_warn(gettext("pg_pattern %s attribute has a "
2952                             "value of \"%s\" but is not in a "
2953                             "service entity.\n"), target_attr, all_value);
2954                         return (-1);
2955                 }
2956                 if (strcmp(s->sc_fmri, SCF_SERVICE_GLOBAL) != 0) {
2957                         uu_warn(gettext("pg_pattern %s attribute has a "
2958                             "value of \"%s\" but is in the \"%s\" service.  "
2959                             "pg_patterns with target \"%s\" are only allowed "
2960                             "in the global service.\n"),
2961                             target_attr, all_value, s->sc_fmri, all_value);
2962                         return (-1);
2963                 }
2964         }
2965 
2966         return (0);
2967 }
2968 
2969 static int
2970 lxml_get_tm_pg_pattern(entity_t *service, xmlNodePtr pg_pattern)
2971 {
2972         xmlNodePtr cursor;
2973         int out_len;
2974         xmlChar *name;
2975         pgroup_t *pg = NULL;
2976         char *pg_name;
2977         int r = -1;
2978         xmlChar *type;
2979 
2980         pg_name = safe_malloc(max_scf_name_len + 1);
2981 
2982         /*
2983          * Get the name and type attributes.  Their presence or absence
2984          * determines whcih prefix we will use for the property group name.
2985          * There are four cases -- neither attribute is present, both are
2986          * present, only name is present or only type is present.
2987          */
2988         name = xmlGetProp(pg_pattern, (xmlChar *)name_attr);
2989         type = xmlGetProp(pg_pattern, (xmlChar *)type_attr);
2990         if ((name == NULL) || (*name == 0)) {
2991                 if ((type == NULL) || (*type == 0)) {
2992                         /* PG name contains only the prefix in this case */
2993                         if (strlcpy(pg_name, SCF_PG_TM_PG_PATTERN_PREFIX,
2994                             max_scf_name_len + 1) >= max_scf_name_len + 1) {
2995                                 uu_die(gettext("Unable to create pg_pattern "
2996                                     "property for %s\n"), service->sc_name);
2997                         }
2998                 } else {
2999                         /*
3000                          * If we have a type and no name, the type becomes
3001                          * part of the pg_pattern property group name.
3002                          */
3003                         if ((out_len = snprintf(pg_name, max_scf_name_len + 1,
3004                             "%s%s", SCF_PG_TM_PG_PATTERN_T_PREFIX, type)) >=
3005                             max_scf_name_len + 1) {
3006                                 uu_die(gettext("pg_pattern type is for %s is "
3007                                     "%d bytes too long\n"), service->sc_name,
3008                                     out_len - max_scf_name_len);
3009                         }
3010                 }
3011         } else {
3012                 const char *prefix;
3013 
3014                 /* Make sure that the name is valid. */
3015                 if (uu_check_name((const char *)name, UU_NAME_DOMAIN) != 0) {
3016                         semerr(gettext("pg_pattern name attribute, \"%s\", "
3017                             "for %s is invalid\n"), name, service->sc_name);
3018                         goto out;
3019                 }
3020 
3021                 /*
3022                  * As long as the pg_pattern has a name, it becomes part of
3023                  * the name of the pg_pattern property group name.  We
3024                  * merely need to pick the appropriate prefix.
3025                  */
3026                 if ((type == NULL) || (*type == 0)) {
3027                         prefix = SCF_PG_TM_PG_PATTERN_N_PREFIX;
3028                 } else {
3029                         prefix = SCF_PG_TM_PG_PATTERN_NT_PREFIX;
3030                 }
3031                 if ((out_len = snprintf(pg_name, max_scf_name_len + 1, "%s%s",
3032                     prefix, name)) >= max_scf_name_len + 1) {
3033                         uu_die(gettext("pg_pattern property group name "
3034                             "for %s is %d bytes too long\n"), service->sc_name,
3035                             out_len - max_scf_name_len);
3036                 }
3037         }
3038 
3039         /*
3040          * Create the property group for holding this pg_pattern
3041          * information, and capture the pg_pattern attributes.
3042          */
3043         pg = internal_pgroup_create_strict(service, pg_name,
3044             SCF_GROUP_TEMPLATE_PG_PATTERN);
3045         if (pg == NULL) {
3046                 if ((name == NULL) || (*name == 0)) {
3047                         if ((type == NULL) ||(*type == 0)) {
3048                                 semerr(gettext("pg_pattern with empty name and "
3049                                     "type is not unique in %s\n"),
3050                                     service->sc_name);
3051                         } else {
3052                                 semerr(gettext("pg_pattern with empty name and "
3053                                     "type \"%s\" is not unique in %s\n"),
3054                                     type, service->sc_name);
3055                         }
3056                 } else {
3057                         if ((type == NULL) || (*type == 0)) {
3058                                 semerr(gettext("pg_pattern with name \"%s\" "
3059                                     "and empty type is not unique in %s\n"),
3060                                     name, service->sc_name);
3061                         } else {
3062                                 semerr(gettext("pg_pattern with name \"%s\" "
3063                                     "and type \"%s\" is not unique in %s\n"),
3064                                     name, type, service->sc_name);
3065                         }
3066                 }
3067                 goto out;
3068         }
3069 
3070         /*
3071          * Get the pg_pattern attributes from the manifest and verify
3072          * that they satisfy our restrictions.
3073          */
3074         r = lxml_get_pg_pattern_attributes(pg, pg_pattern);
3075         if (r != 0)
3076                 goto out;
3077         if (verify_pg_pattern_attributes(service, pg) != 0) {
3078                 semerr(gettext("Invalid pg_pattern attributes in %s\n"),
3079                     service->sc_name);
3080                 r = -1;
3081                 goto out;
3082         }
3083 
3084         /*
3085          * Now process all of the elements of pg_pattern.
3086          */
3087         for (cursor = pg_pattern->xmlChildrenNode;
3088             cursor != NULL;
3089             cursor = cursor->next) {
3090                 if (lxml_ignorable_block(cursor))
3091                         continue;
3092 
3093                 switch (lxml_xlate_element(cursor->name)) {
3094                 case SC_COMMON_NAME:
3095                         (void) lxml_get_all_loctext(service, pg, cursor,
3096                             COMMON_NAME_FMT, (const char *)cursor->name);
3097                         break;
3098                 case SC_DESCRIPTION:
3099                         (void) lxml_get_all_loctext(service, pg, cursor,
3100                             DESCRIPTION_FMT, (const char *)cursor->name);
3101                         break;
3102                 case SC_PROP_PATTERN:
3103                         r = lxml_get_tm_prop_pattern(service, cursor,
3104                             pg_name);
3105                         if (r != 0)
3106                                 goto out;
3107                         break;
3108                 default:
3109                         uu_die(gettext("illegal element \"%s\" in pg_pattern "
3110                             "for service \"%s\"\n"), cursor->name,
3111                             service->sc_name);
3112                 }
3113         }
3114 
3115 out:
3116         if ((r != 0) && (pg != NULL)) {
3117                 internal_detach_pgroup(service, pg);
3118                 internal_pgroup_free(pg);
3119         }
3120         free(pg_name);
3121         xmlFree(name);
3122         xmlFree(type);
3123 
3124         return (r);
3125 }
3126 
3127 static int
3128 lxml_get_template(entity_t *service, xmlNodePtr templ)
3129 {
3130         xmlNodePtr cursor;
3131 
3132         for (cursor = templ->xmlChildrenNode; cursor != NULL;
3133             cursor = cursor->next) {
3134                 if (lxml_ignorable_block(cursor))
3135                         continue;
3136 
3137                 switch (lxml_xlate_element(cursor->name)) {
3138                 case SC_COMMON_NAME:
3139                         (void) lxml_get_tm_common_name(service, cursor);
3140                         break;
3141                 case SC_DESCRIPTION:
3142                         (void) lxml_get_tm_description(service, cursor);
3143                         break;
3144                 case SC_DOCUMENTATION:
3145                         (void) lxml_get_tm_documentation(service, cursor);
3146                         break;
3147                 case SC_PG_PATTERN:
3148                         if (lxml_get_tm_pg_pattern(service, cursor) != 0)
3149                                 return (-1);
3150                         break;
3151                 default:
3152                         uu_die(gettext("illegal element \"%s\" on template "
3153                             "for service \"%s\"\n"),
3154                             cursor->name, service->sc_name);
3155                 }
3156         }
3157 
3158         return (0);
3159 }
3160 
3161 static int
3162 lxml_get_default_instance(entity_t *service, xmlNodePtr definst)
3163 {
3164         entity_t *i;
3165         xmlChar *enabled;
3166         pgroup_t *pg;
3167         property_t *p;
3168         char *package;
3169         uint64_t enabled_val = 0;
3170 
3171         i = internal_instance_new("default");
3172 
3173         if ((enabled = xmlGetProp(definst, (xmlChar *)enabled_attr)) != NULL) {
3174                 enabled_val = (strcmp(true, (const char *)enabled) == 0) ?
3175                     1 : 0;
3176                 xmlFree(enabled);
3177         }
3178 
3179         /*
3180          * New general property group with enabled boolean property set.
3181          */
3182 
3183         i->sc_op = service->sc_op;
3184         pg = internal_pgroup_new();
3185         (void) internal_attach_pgroup(i, pg);
3186 
3187         pg->sc_pgroup_name = (char *)scf_pg_general;
3188         pg->sc_pgroup_type = (char *)scf_group_framework;
3189         pg->sc_pgroup_flags = 0;
3190 
3191         p = internal_property_create(SCF_PROPERTY_ENABLED, SCF_TYPE_BOOLEAN, 1,
3192             enabled_val);
3193 
3194         (void) internal_attach_property(pg, p);
3195 
3196         /*
3197          * Add general/package property if PKGINST is set.
3198          */
3199         if ((package = getenv("PKGINST")) != NULL) {
3200                 p = internal_property_create(SCF_PROPERTY_PACKAGE,
3201                     SCF_TYPE_ASTRING, 1, package);
3202 
3203                 (void) internal_attach_property(pg, p);
3204         }
3205 
3206         return (internal_attach_entity(service, i));
3207 }
3208 
3209 /*
3210  * Translate an instance element into an internal property tree, added to
3211  * service.  If op is SVCCFG_OP_APPLY (i.e., apply a profile), set the
3212  * enabled property to override.
3213  *
3214  * If op is SVCCFG_OP_APPLY (i.e., apply a profile), do not allow for
3215  * modification of template data.
3216  */
3217 static int
3218 lxml_get_instance(entity_t *service, xmlNodePtr inst, bundle_type_t bt,
3219     svccfg_op_t op)
3220 {
3221         entity_t *i;
3222         pgroup_t *pg;
3223         property_t *p;
3224         xmlNodePtr cursor;
3225         xmlChar *enabled;
3226         int r, e_val;
3227 
3228         /*
3229          * Fetch its attributes, as appropriate.
3230          */
3231         i = internal_instance_new((char *)xmlGetProp(inst,
3232             (xmlChar *)name_attr));
3233 
3234         /*
3235          * Note that this must be done before walking the children so that
3236          * sc_fmri is set in case we enter lxml_get_dependent().
3237          */
3238         r = internal_attach_entity(service, i);
3239         if (r != 0)
3240                 return (r);
3241 
3242         i->sc_op = op;
3243         enabled = xmlGetProp(inst, (xmlChar *)enabled_attr);
3244 
3245         if (enabled == NULL) {
3246                 if (bt == SVCCFG_MANIFEST) {
3247                         semerr(gettext("Instance \"%s\" missing attribute "
3248                             "\"%s\".\n"), i->sc_name, enabled_attr);
3249                         return (-1);
3250                 }
3251         } else {        /* enabled != NULL */
3252                 if (strcmp(true, (const char *)enabled) != 0 &&
3253                     strcmp(false, (const char *)enabled) != 0) {
3254                         xmlFree(enabled);
3255                         semerr(gettext("Invalid enabled value\n"));
3256                         return (-1);
3257                 }
3258                 pg = internal_pgroup_new();
3259                 (void) internal_attach_pgroup(i, pg);
3260 
3261                 pg->sc_pgroup_name = (char *)scf_pg_general;
3262                 pg->sc_pgroup_type = (char *)scf_group_framework;
3263                 pg->sc_pgroup_flags = 0;
3264 
3265                 e_val = (strcmp(true, (const char *)enabled) == 0);
3266                 p = internal_property_create(SCF_PROPERTY_ENABLED,
3267                     SCF_TYPE_BOOLEAN, 1, (uint64_t)e_val);
3268 
3269                 p->sc_property_override = (op == SVCCFG_OP_APPLY);
3270 
3271                 (void) internal_attach_property(pg, p);
3272 
3273                 xmlFree(enabled);
3274         }
3275 
3276         /*
3277          * Walk its child elements, as appropriate.
3278          */
3279         for (cursor = inst->xmlChildrenNode; cursor != NULL;
3280             cursor = cursor->next) {
3281                 if (lxml_ignorable_block(cursor))
3282                         continue;
3283 
3284                 switch (lxml_xlate_element(cursor->name)) {
3285                 case SC_RESTARTER:
3286                         (void) lxml_get_restarter(i, cursor);
3287                         break;
3288                 case SC_DEPENDENCY:
3289                         (void) lxml_get_dependency(i, cursor);
3290                         break;
3291                 case SC_DEPENDENT:
3292                         (void) lxml_get_dependent(i, cursor);
3293                         break;
3294                 case SC_METHOD_CONTEXT:
3295                         (void) lxml_get_entity_method_context(i, cursor);
3296                         break;
3297                 case SC_EXEC_METHOD:
3298                         (void) lxml_get_exec_method(i, cursor);
3299                         break;
3300                 case SC_PROPERTY_GROUP:
3301                         (void) lxml_get_pgroup(i, cursor);
3302                         break;
3303                 case SC_TEMPLATE:
3304                         if (op == SVCCFG_OP_APPLY) {
3305                                 semerr(gettext("Template data for \"%s\" may "
3306                                     "not be modified in a profile.\n"),
3307                                     i->sc_name);
3308 
3309                                 return (-1);
3310                         }
3311 
3312                         if (lxml_get_template(i, cursor) != 0)
3313                                 return (-1);
3314                         break;
3315                 case SC_NOTIFICATION_PARAMETERS:
3316                         if (lxml_get_notification_parameters(i, cursor) != 0)
3317                                 return (-1);
3318                         break;
3319                 default:
3320                         uu_die(gettext(
3321                             "illegal element \"%s\" on instance \"%s\"\n"),
3322                             cursor->name, i->sc_name);
3323                         break;
3324                 }
3325         }
3326 
3327         return (0);
3328 }
3329 
3330 /* ARGSUSED1 */
3331 static int
3332 lxml_get_single_instance(entity_t *entity, xmlNodePtr si)
3333 {
3334         pgroup_t *pg;
3335         property_t *p;
3336         int r;
3337 
3338         pg = internal_pgroup_find_or_create(entity, (char *)scf_pg_general,
3339             (char *)scf_group_framework);
3340 
3341         p = internal_property_create(SCF_PROPERTY_SINGLE_INSTANCE,
3342             SCF_TYPE_BOOLEAN, 1, (uint64_t)1);
3343 
3344         r = internal_attach_property(pg, p);
3345         if (r != 0) {
3346                 internal_property_free(p);
3347                 return (-1);
3348         }
3349 
3350         return (0);
3351 }
3352 
3353 /*
3354  * Check to see if the service should allow the upgrade
3355  * process to handle adding of the manifestfiles linkage.
3356  *
3357  * If the service exists and does not have a manifestfiles
3358  * property group then the upgrade process should handle
3359  * the service.
3360  *
3361  * If the service doesn't exist or the service exists
3362  * and has a manifestfiles property group then the import
3363  * process can handle the manifestfiles property group
3364  * work.
3365  *
3366  * This prevents potential cleanup of unaccounted for instances
3367  * in early manifest import due to upgrade process needing
3368  * information that has not yet been supplied by manifests
3369  * that are still located in the /var/svc manifests directory.
3370  */
3371 static int
3372 lxml_check_upgrade(const char *service)
3373 {
3374         scf_handle_t    *h = NULL;
3375         scf_scope_t     *sc = NULL;
3376         scf_service_t   *svc = NULL;
3377         scf_propertygroup_t     *pg = NULL;
3378         int rc = SCF_FAILED;
3379 
3380         if ((h = scf_handle_create(SCF_VERSION)) == NULL ||
3381             (sc = scf_scope_create(h)) == NULL ||
3382             (svc = scf_service_create(h)) == NULL ||
3383             (pg = scf_pg_create(h)) == NULL)
3384                 goto out;
3385 
3386         if (scf_handle_bind(h) != 0)
3387                 goto out;
3388 
3389         if (scf_handle_get_scope(h, SCF_FMRI_LOCAL_SCOPE, sc) == -1)
3390                 goto out;
3391 
3392         if (scf_scope_get_service(sc, service, svc) != SCF_SUCCESS) {
3393                 if (scf_error() == SCF_ERROR_NOT_FOUND)
3394                         rc = SCF_SUCCESS;
3395 
3396                 goto out;
3397         }
3398 
3399         if (scf_service_get_pg(svc, SCF_PG_MANIFESTFILES, pg) != SCF_SUCCESS)
3400                 goto out;
3401 
3402         rc = SCF_SUCCESS;
3403 out:
3404         scf_pg_destroy(pg);
3405         scf_service_destroy(svc);
3406         scf_scope_destroy(sc);
3407         scf_handle_destroy(h);
3408 
3409         return (rc);
3410 }
3411 
3412 /*
3413  * Translate a service element into an internal instance/property tree, added
3414  * to bundle.
3415  *
3416  * If op is SVCCFG_OP_APPLY (i.e., apply a profile), do not allow for
3417  * modification of template data.
3418  */
3419 static int
3420 lxml_get_service(bundle_t *bundle, xmlNodePtr svc, svccfg_op_t op)
3421 {
3422         pgroup_t *pg;
3423         property_t *p;
3424         entity_t *s;
3425         xmlNodePtr cursor;
3426         xmlChar *type;
3427         xmlChar *version;
3428         int e;
3429 
3430         /*
3431          * Fetch attributes, as appropriate.
3432          */
3433         s = internal_service_new((char *)xmlGetProp(svc,
3434             (xmlChar *)name_attr));
3435 
3436         version = xmlGetProp(svc, (xmlChar *)version_attr);
3437         s->sc_u.sc_service.sc_service_version = atol((const char *)version);
3438         xmlFree(version);
3439 
3440         type = xmlGetProp(svc, (xmlChar *)type_attr);
3441         s->sc_u.sc_service.sc_service_type = lxml_xlate_service_type(type);
3442         xmlFree(type);
3443 
3444         /*
3445          * Set the global missing type to false before processing the service
3446          */
3447         est->sc_miss_type = B_FALSE;
3448         s->sc_op = op;
3449 
3450         /*
3451          * Now that the service is created create the manifest
3452          * property group and add the property value of the service.
3453          */
3454         if (lxml_check_upgrade(s->sc_name) == SCF_SUCCESS &&
3455             svc->doc->name != NULL &&
3456             bundle->sc_bundle_type == SVCCFG_MANIFEST) {
3457                 char *buf, *base, *fname, *bname;
3458                 size_t  base_sz = 0;
3459 
3460                 /*
3461                  * Must remove the PKG_INSTALL_ROOT, point to the correct
3462                  * directory after install
3463                  */
3464                 bname = uu_zalloc(PATH_MAX + 1);
3465                 if (realpath(svc->doc->name, bname) == NULL) {
3466                         uu_die(gettext("Unable to create the real path of the "
3467                             "manifest file \"%s\" : %d\n"), svc->doc->name,
3468                             errno);
3469                 }
3470 
3471                 base = getenv("PKG_INSTALL_ROOT");
3472                 if (base != NULL && strncmp(bname, base, strlen(base)) == 0) {
3473                         base_sz = strlen(base);
3474                 }
3475                 fname = safe_strdup(bname + base_sz);
3476 
3477                 uu_free(bname);
3478                 buf = mhash_filename_to_propname(svc->doc->name, B_FALSE);
3479 
3480                 pg = internal_pgroup_create_strict(s, SCF_PG_MANIFESTFILES,
3481                     SCF_GROUP_FRAMEWORK);
3482 
3483                 if (pg == NULL) {
3484                         uu_die(gettext("Property group for prop_pattern, "
3485                             "\"%s\", already exists in %s\n"),
3486                             SCF_PG_MANIFESTFILES, s->sc_name);
3487                 }
3488 
3489                 p = internal_property_create(buf, SCF_TYPE_ASTRING, 1, fname);
3490 
3491                 (void) internal_attach_property(pg, p);
3492         }
3493 
3494         /*
3495          * Walk its child elements, as appropriate.
3496          */
3497         for (cursor = svc->xmlChildrenNode; cursor != NULL;
3498             cursor = cursor->next) {
3499                 if (lxml_ignorable_block(cursor))
3500                         continue;
3501 
3502                 e = lxml_xlate_element(cursor->name);
3503 
3504                 switch (e) {
3505                 case SC_INSTANCE:
3506                         if (lxml_get_instance(s, cursor,
3507                             bundle->sc_bundle_type, op) != 0)
3508                                 return (-1);
3509                         break;
3510                 case SC_TEMPLATE:
3511                         if (op == SVCCFG_OP_APPLY) {
3512                                 semerr(gettext("Template data for \"%s\" may "
3513                                     "not be modified in a profile.\n"),
3514                                     s->sc_name);
3515 
3516                                 return (-1);
3517                         }
3518 
3519                         if (lxml_get_template(s, cursor) != 0)
3520                                 return (-1);
3521                         break;
3522                 case SC_NOTIFICATION_PARAMETERS:
3523                         if (lxml_get_notification_parameters(s, cursor) != 0)
3524                                 return (-1);
3525                         break;
3526                 case SC_STABILITY:
3527                         (void) lxml_get_entity_stability(s, cursor);
3528                         break;
3529                 case SC_DEPENDENCY:
3530                         (void) lxml_get_dependency(s, cursor);
3531                         break;
3532                 case SC_DEPENDENT:
3533                         (void) lxml_get_dependent(s, cursor);
3534                         break;
3535                 case SC_RESTARTER:
3536                         (void) lxml_get_restarter(s, cursor);
3537                         break;
3538                 case SC_EXEC_METHOD:
3539                         (void) lxml_get_exec_method(s, cursor);
3540                         break;
3541                 case SC_METHOD_CONTEXT:
3542                         (void) lxml_get_entity_method_context(s, cursor);
3543                         break;
3544                 case SC_PROPERTY_GROUP:
3545                         (void) lxml_get_pgroup(s, cursor);
3546                         break;
3547                 case SC_INSTANCE_CREATE_DEFAULT:
3548                         (void) lxml_get_default_instance(s, cursor);
3549                         break;
3550                 case SC_INSTANCE_SINGLE:
3551                         (void) lxml_get_single_instance(s, cursor);
3552                         break;
3553                 default:
3554                         uu_die(gettext(
3555                             "illegal element \"%s\" on service \"%s\"\n"),
3556                             cursor->name, s->sc_name);
3557                         break;
3558                 }
3559         }
3560 
3561         /*
3562          * Now that the service has been processed set the missing type
3563          * for the service.  So that only the services with missing
3564          * types are processed.
3565          */
3566         s->sc_miss_type = est->sc_miss_type;
3567         if (est->sc_miss_type)
3568                 est->sc_miss_type = B_FALSE;
3569 
3570         return (internal_attach_service(bundle, s));
3571 }
3572 
3573 #ifdef DEBUG
3574 void
3575 lxml_dump(int g, xmlNodePtr p)
3576 {
3577         if (p && p->name) {
3578                 (void) printf("%d %s\n", g, p->name);
3579 
3580                 for (p = p->xmlChildrenNode; p != NULL; p = p->next)
3581                         lxml_dump(g + 1, p);
3582         }
3583 }
3584 #endif /* DEBUG */
3585 
3586 static int
3587 lxml_is_known_dtd(const xmlChar *dtdname)
3588 {
3589         if (dtdname == NULL ||
3590             strcmp(MANIFEST_DTD_PATH, (const char *)dtdname) != 0)
3591                 return (0);
3592 
3593         return (1);
3594 }
3595 
3596 static int
3597 lxml_get_bundle(bundle_t *bundle, bundle_type_t bundle_type,
3598     xmlNodePtr subbundle, svccfg_op_t op)
3599 {
3600         xmlNodePtr cursor;
3601         xmlChar *type;
3602         int e;
3603 
3604         /*
3605          * 1.  Get bundle attributes.
3606          */
3607         type = xmlGetProp(subbundle, (xmlChar *)type_attr);
3608         bundle->sc_bundle_type = lxml_xlate_bundle_type(type);
3609         if (bundle->sc_bundle_type != bundle_type &&
3610             bundle_type != SVCCFG_UNKNOWN_BUNDLE) {
3611                 semerr(gettext("included bundle of different type.\n"));
3612                 return (-1);
3613         }
3614 
3615         xmlFree(type);
3616 
3617         switch (op) {
3618         case SVCCFG_OP_IMPORT:
3619                 if (bundle->sc_bundle_type != SVCCFG_MANIFEST) {
3620                         semerr(gettext("document is not a manifest.\n"));
3621                         return (-1);
3622                 }
3623                 break;
3624         case SVCCFG_OP_APPLY:
3625                 if (bundle->sc_bundle_type != SVCCFG_PROFILE) {
3626                         semerr(gettext("document is not a profile.\n"));
3627                         return (-1);
3628                 }
3629                 break;
3630         case SVCCFG_OP_RESTORE:
3631                 if (bundle->sc_bundle_type != SVCCFG_ARCHIVE) {
3632                         semerr(gettext("document is not an archive.\n"));
3633                         return (-1);
3634                 }
3635                 break;
3636         }
3637 
3638         if (((bundle->sc_bundle_name = xmlGetProp(subbundle,
3639             (xmlChar *)name_attr)) == NULL) || (*bundle->sc_bundle_name == 0)) {
3640                 semerr(gettext("service bundle lacks name attribute\n"));
3641                 return (-1);
3642         }
3643 
3644         /*
3645          * 2.  Get services, descend into each one and build state.
3646          */
3647         for (cursor = subbundle->xmlChildrenNode; cursor != NULL;
3648             cursor = cursor->next) {
3649                 if (lxml_ignorable_block(cursor))
3650                         continue;
3651 
3652                 e = lxml_xlate_element(cursor->name);
3653 
3654                 switch (e) {
3655                 case SC_XI_INCLUDE:
3656                         continue;
3657 
3658                 case SC_SERVICE_BUNDLE:
3659                         if (lxml_get_bundle(bundle, bundle_type, cursor, op))
3660                                 return (-1);
3661                         break;
3662                 case SC_SERVICE:
3663                         if (lxml_get_service(bundle, cursor, op) != 0)
3664                                 return (-1);
3665                         break;
3666                 }
3667         }
3668 
3669         return (0);
3670 }
3671 
3672 /*
3673  * Load an XML tree from filename and translate it into an internal service
3674  * tree bundle.  Require that the bundle be of appropriate type for the
3675  * operation: archive for RESTORE, manifest for IMPORT, profile for APPLY.
3676  */
3677 int
3678 lxml_get_bundle_file(bundle_t *bundle, const char *filename, svccfg_op_t op)
3679 {
3680         xmlDocPtr document;
3681         xmlNodePtr cursor;
3682         xmlDtdPtr dtd = NULL;
3683         xmlValidCtxtPtr vcp;
3684         boolean_t do_validate;
3685         char *dtdpath = NULL;
3686         int r;
3687 
3688         /*
3689          * Verify we can read the file before we try to parse it.
3690          */
3691         if (access(filename, R_OK | F_OK) == -1) {
3692                 semerr(gettext("unable to open file: %s\n"), strerror(errno));
3693                 return (-1);
3694         }
3695 
3696         /*
3697          * Until libxml2 addresses DTD-based validation with XInclude, we don't
3698          * validate service profiles (i.e. the apply path).
3699          */
3700         do_validate = (op != SVCCFG_OP_APPLY) &&
3701             (getenv("SVCCFG_NOVALIDATE") == NULL);
3702         if (do_validate)
3703                 dtdpath = getenv("SVCCFG_DTD");
3704 
3705         if (dtdpath != NULL)
3706                 xmlLoadExtDtdDefaultValue = 0;
3707 
3708         if ((document = xmlReadFile(filename, NULL, 0)) == NULL) {
3709                 semerr(gettext("couldn't parse document\n"));
3710                 return (-1);
3711         }
3712 
3713         document->name = safe_strdup(filename);
3714 
3715         /*
3716          * Verify that this is a document type we understand.
3717          */
3718         if ((dtd = xmlGetIntSubset(document)) == NULL) {
3719                 semerr(gettext("document has no DTD\n"));
3720                 return (-1);
3721         } else if (dtdpath == NULL && !do_validate) {
3722                 /*
3723                  * If apply then setup so that some validation
3724                  * for specific elements can be done.
3725                  */
3726                 dtdpath = (char *)document->intSubset->SystemID;
3727         }
3728 
3729         if (!lxml_is_known_dtd(dtd->SystemID)) {
3730                 semerr(gettext("document DTD unknown; not service bundle?\n"));
3731                 return (-1);
3732         }
3733 
3734         if ((cursor = xmlDocGetRootElement(document)) == NULL) {
3735                 semerr(gettext("document is empty\n"));
3736                 xmlFreeDoc(document);
3737                 return (-1);
3738         }
3739 
3740         if (xmlStrcmp(cursor->name, (const xmlChar *)"service_bundle") != 0) {
3741                 semerr(gettext("document is not a service bundle\n"));
3742                 xmlFreeDoc(document);
3743                 return (-1);
3744         }
3745 
3746 
3747         if (dtdpath != NULL) {
3748                 dtd = xmlParseDTD(NULL, (xmlChar *)dtdpath);
3749                 if (dtd == NULL) {
3750                         semerr(gettext("Could not parse DTD \"%s\".\n"),
3751                             dtdpath);
3752                         return (-1);
3753                 }
3754 
3755                 if (document->extSubset != NULL)
3756                         xmlFreeDtd(document->extSubset);
3757 
3758                 document->extSubset = dtd;
3759         }
3760 
3761         if (xmlXIncludeProcessFlags(document, XML_PARSE_XINCLUDE) == -1) {
3762                 semerr(gettext("couldn't handle XInclude statements "
3763                     "in document\n"));
3764                 return (-1);
3765         }
3766 
3767         if (do_validate) {
3768                 vcp = xmlNewValidCtxt();
3769                 if (vcp == NULL)
3770                         uu_die(gettext("could not allocate memory"));
3771                 vcp->warning = xmlParserValidityWarning;
3772                 vcp->error = xmlParserValidityError;
3773 
3774                 r = xmlValidateDocument(vcp, document);
3775 
3776                 xmlFreeValidCtxt(vcp);
3777 
3778                 if (r == 0) {
3779                         semerr(gettext("Document is not valid.\n"));
3780                         xmlFreeDoc(document);
3781                         return (-1);
3782                 }
3783         }
3784 
3785 #ifdef DEBUG
3786         lxml_dump(0, cursor);
3787 #endif /* DEBUG */
3788 
3789         r = lxml_get_bundle(bundle, SVCCFG_UNKNOWN_BUNDLE, cursor, op);
3790 
3791         xmlFreeDoc(document);
3792 
3793         return (r);
3794 }
3795 
3796 int
3797 lxml_inventory(const char *filename)
3798 {
3799         bundle_t *b;
3800         uu_list_walk_t *svcs, *insts;
3801         entity_t *svc, *inst;
3802 
3803         b = internal_bundle_new();
3804 
3805         if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) != 0) {
3806                 internal_bundle_free(b);
3807                 return (-1);
3808         }
3809 
3810         svcs = uu_list_walk_start(b->sc_bundle_services, 0);
3811         if (svcs == NULL)
3812                 uu_die(gettext("Couldn't walk services"));
3813 
3814         while ((svc = uu_list_walk_next(svcs)) != NULL) {
3815                 uu_list_t *inst_list;
3816 
3817                 inst_list = svc->sc_u.sc_service.sc_service_instances;
3818                 insts = uu_list_walk_start(inst_list, 0);
3819                 if (insts == NULL)
3820                         uu_die(gettext("Couldn't walk instances"));
3821 
3822                 while ((inst = uu_list_walk_next(insts)) != NULL)
3823                         (void) printf("svc:/%s:%s\n", svc->sc_name,
3824                             inst->sc_name);
3825 
3826                 uu_list_walk_end(insts);
3827         }
3828 
3829         uu_list_walk_end(svcs);
3830 
3831         svcs = uu_list_walk_start(b->sc_bundle_services, 0);
3832         while ((svc = uu_list_walk_next(svcs)) != NULL) {
3833                 (void) fputs("svc:/", stdout);
3834                 (void) puts(svc->sc_name);
3835         }
3836         uu_list_walk_end(svcs);
3837 
3838         internal_bundle_free(b);
3839 
3840         return (0);
3841 }