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