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