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