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