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