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