1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * This file provides the code that allows svccfg(1M) to validate a 29 * manifest against the template specifications. svccfg uses the 30 * validation facilities for the import and validate subcommands. 31 * 32 * There are three entry points -- tmpl_validate_bundle(), 33 * tmpl_errors_print() and tmpl_errors_destroy(). svccfg calls 34 * tmpl_validate_bundle() to validate a bundle. tmpl_validate_bundle() 35 * returns a pointer to a tmpl_errors_t. This is a pointer to information 36 * about any validation errors that were found. If an error was detected, 37 * svccfg calls tmpl_errors_print() to print the error information. Once 38 * the error information is printed, svccfg calls tmpl_errors_destroy() to 39 * free the memory associated with the tmpl_errors_t. 40 * 41 * libscf's scf_tmpl.c performs similar checks to the ones described in 42 * this paragraph. Any changes to the algorithms in this file should also 43 * be infcorporated into scf_tmpl.c. The reason that there are two bodies 44 * of code is that they work on different data structures. 45 * tmpl_validate_bundle() validates each instance of each service in the 46 * bundle. The following checks are performed on each instance: 47 * 48 * 1. Verify template consistency. 49 * A. No conflicting definitions of "pg_pattern" are allowed 50 * within a single instance. 51 * B. Templates at a narrow target (e.g. instance) which define 52 * property groups already templated at a broad target 53 * (e.g. delegate or all) are strongly discouraged. 54 * C. Developers may not define a template which specifies a 55 * single prop_pattern name with differing types on the same 56 * target entity. 57 * D. If a pg_pattern has a required attribute with a value of 58 * true, then its name and type attributes must be 59 * specified. 60 * E. If a prop_pattern has a required attribute with a value 61 * of true, then its type attribute must be specified. 62 * F. If a prop_pattern has an include_values element make sure 63 * that the appropriate constraints or values element has 64 * also been declared. 65 * 2. Validate that each property group in the instance is in 66 * conformance with the template specifications. 67 * A. Verify that the types of the PG and the pg_pattern are 68 * compatible. 69 * B. Verify properties of the PG against the prop_patterns in 70 * the template. 71 * o Verify property's type. 72 * o Verify cardinality. 73 * o Vefiy that property values satisfy the constraints 74 * imposed by the prop_pattern. 75 * C. Verify that required properties are present. 76 * 3. Verify that all required property groups are present in the 77 * insance. 78 * 79 * tmpl_validate_bundle() is called after svccfg has processed the manifest 80 * file. The manifest is represented in memory by a set of entity_t, 81 * pgroup_t, property_t and value_t structures. These structures are 82 * defined in svccfg.h. 83 * 84 * tmpl_validate_bundle() calls tmpl_validate_service() for each service in 85 * the bundle, and tmpl_validate_service() then calls 86 * tmpl_validate_instance() for each instance in the service. 87 * tmpl_validate_instance() is the function that does the real work of 88 * validation against the template specification. 89 * 90 * Subsystems: 91 * ========== 92 * 93 * General Templates: 94 * ----------------- 95 * In order to perform the validation specified by 1.B above, we need to 96 * load the templates specifications for the global service and the 97 * instance's restarter. This information is loaded from the repository 98 * and it is held in memory using the entity_t, pgroup_t, property_t and 99 * value_t hierarchy of structures. When a service is processed, 100 * load_general_templates() is called to load the information for the 101 * global service and restarter that is declared at the service level. The 102 * sc_service.sc_global and sc_service.sc_restarter members of the 103 * service's entity_t point to the information for the global and restarter 104 * services. 105 * 106 * The instance portion of a manifest can declare an instance specific 107 * restarter. If this is the case, load_instance_restarter() will load the 108 * information for that restarter, and it is saved in the 109 * sc_instance.sc_instance_restarter member of the entity_t that represents 110 * the instance. 111 * 112 * Composed Properties: 113 * ------------------- 114 * We need the ability to process the composed properties of an instance. 115 * That is to say if an instance defines a property, it overrides any 116 * definition in the service. Otherwise, the service's definition is 117 * inherited in the instance. 118 * 119 * In an entity_t, the sc_instance.sc_composed member points to a 120 * uu_avl tree of composed property groups (composed_pg_t) for the 121 * instance. The composed_pg_t has two members, cpg_instance_pg and 122 * cpg_service_pg, that point to the instance and service property group 123 * definitions respectively. Either of these may be NULL indicating that 124 * only an instance or service definition exists in the manifest. 125 * 126 * In the case where both the instance and the service define a property 127 * group, the properties must be composed. This is done by 128 * compose_props(). The compose_pg_t holds the composed properties in a 129 * uu_avl_tree at cpf_compose_props. This is a tree of property_t 130 * structures. If a property is defined in both the instance and service 131 * property group, the tree will hold the instance definition. If the 132 * property is defined at only one level, the tree will hold the property_t 133 * for that level. Thus, the tree is truly a set of composed properties of 134 * the property group. 135 * 136 * Property Group Iteration: 137 * ------------------------ 138 * A number of functions must iterate through an instance's property groups 139 * looking for the ones that define a pg_pattern or a prop_pattern. To be 140 * specific, the iteration starts with the composed view of the instance. 141 * It then proceeds through the restarter information and finally moves on 142 * to the global service. The pg_iter_t structure holds the information 143 * that is needed to implement this type of iteration. pg_iter_create() 144 * creates one of these iterators, and pg_iter_destroy() frees the memory 145 * associated with the pg_iter_t. next_pattern_pg(), is used to step 146 * through the iteration. 147 * 148 * Error Reporting: 149 * --------------- 150 * While performing the templates validation checks, svccfg collects 151 * information for all the errors that it finds. Because of this you will 152 * see many places in the code where a loop is not exited when an error is 153 * encountered. We note that fact that an error has occurred, but continue 154 * in the loop to see if there are more validation errors. The error code 155 * of the last error that is encountered is returned. This works, because 156 * the callers of tmpl_validate_bundle() only look to see whether or not 157 * the return code is TVS_SUCCESS. 158 * 159 * The information for reporting the errors is collected in a tmpl_errors_t 160 * structure, and tmpl_validate_bundle() returns the address of this 161 * structure. The caller of tmpl_validate_bundle() can then call 162 * tmpl_errors_print() to display the error information to the user. 163 * 164 * There are two categories of errors. Some errors are seen when 165 * processing the information in the manifest. This type of error is only 166 * seen by svccfg when it is importing or validating a manifest. The other 167 * type of error consists of template validation errors. These errors can 168 * be seen when processing a manifest or when performing a templates 169 * validation of the information associated with an FMRI in the the 170 * repository. tmpl_errors_add_im() is used to capture error information 171 * about the first type of error, and add_scf_error() is used to capture 172 * error information about the second type of error. 173 * 174 * The distinction is important when printing the error information. The 175 * fuctions for printing the first type of error reside in this file, since 176 * these errors will only be seen by the functions in this file. The 177 * functions for printing the template validation errors reside in libscf, 178 * because these errors are of a more general nature. 179 * 180 * Thus, tmpl_errors_t has two lists -- one for each type of error. 181 * te_list is a list of im_tmpl_error_t structures that represent the first 182 * type of error. te_scf is a list of tv_errors_t structures that hold 183 * information about general template validation errors. 184 * tmpl_errors_print() processes both lists to print information about all 185 * errors. In tmpl_errors_print() im_tmpl_error_print() is used to print 186 * the errors that are specific to this file. scf_tmpl_strerror() provides 187 * the errors messages for general templates errors. 188 * 189 * As was mentioned in the previous paragraph, im_tmpl_error_print() is 190 * responsible for printing the errors that are specific to this file. 191 * Based on the error code, it dispatches to one of 192 * im_perror_bad_conversion(), im_perror_bad_template(), 193 * im_perror_invalid_type(), im_perror_missing_pg_type() or 194 * im_perror_missing_type(). The rest of the im_perror_* functions provide 195 * services to these error specific functions by printing common 196 * information. 197 * 198 * im_perror_item() is the heart of this message printing subsystem. It is 199 * called directly or indirectly by all of the other im_perror_* functions. 200 * im_perror_item() prints a single item of error information. If svccfg 201 * is running in interactive mode, im_perror_item() prints each item on a 202 * single line, so that they are readable by a human. In non-interactive 203 * mode, all items are printed on a single line separated by semi-colons. 204 */ 205 206 #include <assert.h> 207 #include <errno.h> 208 #include <inttypes.h> 209 #include <libintl.h> 210 #include <limits.h> 211 #include <libscf.h> 212 #include <libscf_priv.h> 213 #include <stdio.h> 214 #include <stdlib.h> 215 #include <strings.h> 216 #include "svccfg.h" 217 218 /* 219 * Clear error_info_t structure. 220 */ 221 #define CLEAR_ERROR_INFO(ei) ((void) memset((ei), 0, sizeof (error_info_t))) 222 223 /* 224 * Retrieve the property group pointer from the composed_pg structure. 225 */ 226 #define CPG2PG(cpg) (cpg->cpg_instance_pg ? cpg->cpg_instance_pg : \ 227 cpg->cpg_service_pg) 228 229 /* 230 * Convert a pointer to an empty string into a NULL pointer. 231 */ 232 #define EMPTY_TO_NULL(p) (((p) && (*(p) == 0)) ? NULL : (p)) 233 234 /* uu_avl and uu_list debugging bits. */ 235 #ifdef NDEBUG 236 #define TMPL_DEBUG_AVL_POOL UU_DEFAULT 237 #define TMPL_DEBUG_LIST UU_DEFAULT 238 #define TMPL_DEBUG_LIST_POOL UU_DEFAULT 239 #define TMPL_DEBUG_TREE UU_DEFAULT 240 #else 241 #define TMPL_DEBUG_AVL_POOL UU_AVL_POOL_DEBUG 242 #define TMPL_DEBUG_LIST UU_LIST_DEBUG 243 #define TMPL_DEBUG_LIST_POOL UU_LIST_POOL_DEBUG 244 #define TMPL_DEBUG_TREE UU_AVL_DEBUG 245 #endif /* NDEBUG */ 246 247 /* 248 * Structures and enums that are used in producing error messages: 249 * 250 * error_info_t is used to pass information about an error to 251 * tmpl_errors_add_im() and add_scf_error(). tmpl_errors_add_im() collects 252 * the error information and stores it in an im_tmpl_error_t. The 253 * im_tmpl_error_t is linked into the tmpl_errors_t, so that the captured 254 * information can be used later when error messages are printed. 255 * 256 * tv_errors_t is used to keep track of error information for general 257 * template errors that are known by libscf. add_scf_error() captures the 258 * error information for use in this structure. 259 */ 260 /* 261 * enum to designate the type of data that is held in a err_info structure. 262 */ 263 typedef enum err_info_type { 264 EIT_NONE, /* No values in the structure */ 265 EIT_BAD_TEMPLATE, /* Reason that template is bad */ 266 EIT_CARDINALITY, /* Ranges for property cardinality */ 267 EIT_INCLUDE_VALUES, /* include_values type attribute */ 268 EIT_MISSING_PG, /* Name of missing pg */ 269 EIT_MISSING_PROP, /* Name of missing property */ 270 EIT_PATTERN_CONFLICT, /* Conflicting pattern definition */ 271 EIT_PROP_TYPE, /* Value with invalid type */ 272 EIT_RANGE /* Value that is out of range */ 273 } err_info_type_t; 274 275 /* 276 * Structure to hold information that will be used in generating error 277 * messages. 278 */ 279 typedef struct error_info { 280 err_info_type_t ei_type; /* Type of information stored here */ 281 union { 282 /* EIT_BAD_TEMPLATE */ 283 struct { 284 const char *ei_reason; 285 } ei_bad_template; 286 /* EIT_CARDINALITY */ 287 struct { 288 uint64_t ei_min; 289 uint64_t ei_max; 290 uint64_t ei_count; /* Number of prop values */ 291 } ei_cardinality; 292 /* EIT_INCLUDE_VALUES */ 293 struct { 294 const char *ei_type; 295 } ei_inc_values; 296 /* EIT_MISSING_PG */ 297 struct { 298 const char *ei_pg_name; /* Name of missing pg */ 299 const char *ei_pg_type; /* Type of missing pg */ 300 } ei_missing_pg; 301 /* EIT_MISSING_PROP */ 302 struct { 303 const char *ei_prop_name; /* Name of prop */ 304 } ei_missing_prop; 305 /* EIT_PATTERN_CONFLICT */ 306 struct { 307 pgroup_t *ei_pattern; /* Conficting pattern */ 308 } ei_pattern_conflict; 309 /* EIT_PROP_TYPE */ 310 struct { 311 scf_type_t ei_actual; 312 scf_type_t ei_specified; 313 } ei_prop_type; 314 /* EIT_RANGE */ 315 struct { 316 scf_type_t ei_rtype; 317 int64_t ei_ivalue; 318 uint64_t ei_uvalue; 319 } ei_range; 320 } ei_u; 321 } error_info_t; 322 323 /* 324 * Structure with information about a template violation. This structure 325 * is for use with in memory representations of the manifest and template. 326 * See scf_tmpl_error_t for use with repository representations. Some of 327 * the pointers may be NULL for some types of errors. 328 */ 329 typedef struct im_tmpl_error { 330 tmpl_validate_status_t ite_type; /* Type of error */ 331 entity_t *ite_entity; /* Instance or service */ 332 pgroup_t *ite_pg; /* Non-conforming prop. group */ 333 pgroup_t *ite_pg_pattern; /* Violated pg_pattern */ 334 property_t *ite_prop; /* Non-conforming property */ 335 pgroup_t *ite_prop_pattern; /* Violated prop_pattern */ 336 value_t *ite_value; /* Non-conforming value */ 337 error_info_t ite_einfo; /* Extra error information */ 338 uu_list_node_t ite_node; /* Node to link us in a list. */ 339 } im_tmpl_error_t; 340 341 /* 342 * This structure holds the data that will be used by scf_tmpl_strerror() 343 * for printing template validation errors. 344 */ 345 typedef struct tv_errors { 346 scf_tmpl_errors_t *tve_errors; /* Errors for scf_tmpl_strerror() */ 347 uu_list_node_t tve_node; /* Linkage in a list. */ 348 } tv_errors_t; 349 350 /* 351 * Structure to collect template validation errors. 352 */ 353 struct tmpl_errors { 354 uu_list_t *te_list; /* List of im_tmpl_error_t */ 355 im_tmpl_error_t *te_next; /* Next error to present */ 356 uu_list_t *te_scf; /* Errors for scf_tmpl_strerror() */ 357 tv_errors_t *te_cur_scf; /* Current member of te_scf */ 358 }; 359 360 /* End of structures used in error processing. */ 361 362 /* 363 * Property group types that are of interest to us. See pgroup_type(). 364 */ 365 typedef enum pg_type { 366 NORMAL_PG, 367 PG_PATTERN_PG, 368 PROP_PATTERN_PG 369 } pg_type_t; 370 371 /* 372 * Structure to keep track of a set of ASTRING property values for a 373 * property. The consumer may wish to have the ASTRING property values 374 * converted to a numeric form which is the reason for the av_v union. 375 * This structure is returned by av_get_values() and is accessed by 376 * av_get_integer(), av_get_string() and av_get_unsigned(). 377 */ 378 typedef struct avalues { 379 uint_t av_count; /* Number of values */ 380 scf_type_t av_type; /* Type of value representation */ 381 union { 382 uint64_t *av_unsigned; /* Count & boolean values */ 383 int64_t *av_integer; /* Integer values */ 384 const char **av_string; /* String values */ 385 } av_v; /* Container for the values */ 386 } avalues_t; 387 388 /* 389 * composed_pg_t contains the information that is needed to compose a 390 * property group. See the section on Composed Properties in the block 391 * comment at the beginning of this file. The composed_pg structures are 392 * linked into a uu_avl tree. The tree is at sc_instance.sc_composed in 393 * the entity_t. 394 */ 395 struct composed_pg { 396 /* 397 * Property group is uniquely identified by its name and type. 398 * These two elements point to the name and type in a pgroup_t 399 * (either service or instance), so they do not need to be 400 * allocated or freed. 401 */ 402 const char *cpg_name; 403 const char *cpg_type; 404 405 /* References to the actual property group definitions. */ 406 pgroup_t *cpg_instance_pg; 407 pgroup_t *cpg_service_pg; 408 409 /* Composed properties of the property group. */ 410 uu_avl_t *cpg_composed_props; 411 412 uu_avl_node_t cpg_node; /* Linkage for AVL tree */ 413 }; 414 415 /* 416 * Prefixes for standard property names. Used in 417 * include_values_support(). 418 */ 419 typedef struct prop_prefix { 420 const char *pp_prefix; 421 size_t pp_size; 422 } prop_prefix_t; 423 424 /* 425 * Store a legal range for a property allowing for either signed or 426 * unsigned ranges. It is used to store a range from a template 427 * constraint element of a prop_pattern. The structure is returned by 428 * get_ranges() and is used by value_in_range() to validate the values of a 429 * property. 430 */ 431 typedef struct range { 432 union { 433 struct { 434 uint64_t rng_min; 435 uint64_t rng_max; 436 } rng_unsigned; 437 struct { 438 int64_t rng_min; 439 int64_t rng_max; 440 } rng_signed; 441 } rng_u; 442 } range_t; 443 444 /* 445 * This enum defines the levels where templates can be defined. See the 446 * pg_iter structure below. 447 */ 448 typedef enum tmpl_level { 449 TL_NOLEVEL = 0, /* No level yet specified. */ 450 TL_INSTANCE, /* Instance templates. */ 451 TL_COMPOSED, /* Composed instance. */ 452 TL_SERVICE, /* Service wide templates. */ 453 TL_RESTARTER, /* Templates from restarter manifest. */ 454 TL_GLOBAL /* SMF wide templates. */ 455 } tmpl_level_t; 456 457 /* 458 * pg_iter is a structure that allows us to iterate through property groups 459 * in an instance followed by the property groups of the instance's 460 * service, the instance's restarter and finally the global service. See 461 * the Property Group Iteration section of the block comment at the 462 * beginning of this file. 463 */ 464 typedef struct pg_iter { 465 entity_t *pgi_entity; /* Entity being searched */ 466 const char *pgi_restrict; /* Only return PGs of this type */ 467 tmpl_level_t pgi_level; /* Current level */ 468 entity_t *pgi_service; /* Service being processed. */ 469 union { 470 pgroup_t *pgi_pg; 471 composed_pg_t *pgi_cpg; 472 } pgi_current; /* Current property group. */ 473 } pg_iter_t; 474 475 /* 476 * enum to distinguish between pg_patterns and prop_patterns. It is used 477 * in the ptrn_info_t structure. See below. 478 */ 479 typedef enum ptrn_type { 480 PG_PATTERN, 481 PROP_PATTERN 482 } ptrn_type_t; 483 484 /* 485 * Structure of information about a pg_pattern or a prop_pattern. It is 486 * used for template consistency checks. gather_pattern() is used to 487 * gather information for all the pg_patterns or prop_patterns in an 488 * instance. It allocates a ptrn_info_t for each of these and adds them to 489 * an avl tree that is held by tmpl_consistency(). 490 */ 491 typedef struct ptrn_info { 492 ptrn_type_t pi_ptrn_type; 493 pgroup_t *pi_ptrnpg; /* pgroup_t defining the pattern. */ 494 const char *pi_name; /* Name attribute. */ 495 const char *pi_type; /* Type attribute. */ 496 const char *pi_target; /* Target attribute - only PG_PATTERN */ 497 const char *pi_pgp_name; /* Name of the pg pattern. Only */ 498 /* used for PROP_PATTERN. */ 499 pgroup_t *pi_enc_pgp; /* PG of the pg_pattern that holds */ 500 /* the prop_pattern defined by this */ 501 /* structure. Only used for */ 502 /* PROP_PATTERN. */ 503 uu_avl_node_t pi_link; /* Linkage into AVL tree */ 504 } ptrn_info_t; 505 506 static const char *emesg_nomem; 507 508 /* 509 * Pool for trees of composed property groups. 510 */ 511 static uu_avl_pool_t *composed_pg_pool; 512 513 /* 514 * Pool for trees of composed properties. 515 */ 516 static uu_avl_pool_t *composed_prop_pool; 517 518 /* 519 * Pool for lists of errors in the internal representation. 520 */ 521 static uu_list_pool_t *inmem_errors_pool; 522 523 /* 524 * Pool for trees of pg_pattern info structures (ptrn_info_t). 525 */ 526 static uu_avl_pool_t *ptrn_info_pool; 527 528 /* 529 * Pool for lists of template errors in the libscf representation. 530 */ 531 static uu_list_pool_t *tv_errors_pool; 532 533 /* 534 * Property name prefixes for constraints and values. 535 */ 536 static const char *constraint_prefixes[] = { 537 SCF_PROPERTY_TM_CONSTRAINT_NAME, 538 SCF_PROPERTY_TM_CONSTRAINT_RANGE, 539 NULL 540 }; 541 static const char *value_prefixes[] = { 542 SCF_PROPERTY_TM_VALUE_PREFIX, 543 NULL 544 }; 545 546 /* 547 * Function to compare two composed_pg structures. 548 */ 549 /* ARGSUSED2 */ 550 static int 551 composed_pg_compare(const void *left, const void *right, void *unused) 552 { 553 composed_pg_t *l = (composed_pg_t *)left; 554 composed_pg_t *r = (composed_pg_t *)right; 555 int rc; 556 557 if ((rc = strcmp(l->cpg_name, r->cpg_name)) == 0) { 558 rc = strcmp(l->cpg_type, r->cpg_type); 559 } 560 return (rc); 561 } 562 563 /* ARGSUSED2 */ 564 static int 565 composed_prop_compare(const void *left, const void *right, void *unused) 566 { 567 property_t *l = (property_t *)left; 568 property_t *r = (property_t *)right; 569 570 return (strcmp(l->sc_property_name, r->sc_property_name)); 571 } 572 573 static composed_pg_t * 574 composed_pg_create() 575 { 576 composed_pg_t *cpg; 577 578 cpg = safe_malloc(sizeof (*cpg)); 579 uu_avl_node_init(cpg, &cpg->cpg_node, composed_pg_pool); 580 return (cpg); 581 } 582 583 static void 584 composed_pg_destroy(composed_pg_t *cpg) 585 { 586 void *marker = NULL; 587 pgroup_t *pg; 588 589 if (cpg == NULL) 590 return; 591 /* Tear down composed property tree if we have one. */ 592 if ((cpg->cpg_composed_props != NULL)) { 593 while (uu_avl_teardown(cpg->cpg_composed_props, &marker) != 594 NULL) { 595 /* 596 * Nothing to do other than getting the property 597 * out of the list. This cleans up the property's 598 * uu_avl_node. 599 */ 600 } 601 uu_avl_destroy(cpg->cpg_composed_props); 602 } 603 604 /* Clean up any pgroup_t references to us. */ 605 if ((pg = cpg->cpg_instance_pg) != NULL) { 606 assert((pg->sc_pgroup_composed == NULL) || 607 (pg->sc_pgroup_composed == cpg)); 608 pg->sc_pgroup_composed = NULL; 609 } 610 611 uu_avl_node_fini(cpg, &cpg->cpg_node, composed_pg_pool); 612 free(cpg); 613 } 614 615 /* 616 * Walk the property group at pg, and add its properties to the AVL tree at 617 * tree. 618 */ 619 static void 620 grow_props_tree(pgroup_t *pg, uu_avl_t *tree) 621 { 622 uu_avl_index_t marker; 623 property_t *prop; 624 625 for (prop = uu_list_first(pg->sc_pgroup_props); 626 prop != NULL; 627 prop = uu_list_next(pg->sc_pgroup_props, prop)) { 628 if (uu_avl_find(tree, prop, NULL, &marker) == NULL) { 629 /* 630 * If there was no match, insert the property into 631 * the tree. If we do get a match, there is 632 * nothing to do. That is because we rely on our 633 * caller to process the instance properties first, 634 * and the instance properties override the service 635 * properties. 636 */ 637 uu_avl_insert(tree, prop, marker); 638 } 639 } 640 } 641 642 /* 643 * The composed properties are stored in a uu_avl_tree. First we populate 644 * the tree with properties from the instance level property group. Then, 645 * we'll add the properties from the service level property group. 646 */ 647 static void 648 compose_props(composed_pg_t *cpg) 649 { 650 uu_avl_t *tree; 651 652 tree = uu_avl_create(composed_prop_pool, cpg, TMPL_DEBUG_TREE); 653 if (tree == NULL) { 654 uu_die(gettext("composed_pool tree creation failed: %s\n"), 655 uu_strerror(uu_error())); 656 } 657 cpg->cpg_composed_props = tree; 658 659 /* 660 * compose_props() is only called when there is both an instance 661 * and a service definition of the property group. This implies 662 * that neither cpg->cpg_instance_pg nor cpg->cpg_service_pg can be 663 * NULL. 664 */ 665 /* 666 * First add instance properties to the tree. 667 */ 668 assert(cpg->cpg_instance_pg != NULL); 669 grow_props_tree(cpg->cpg_instance_pg, tree); 670 671 /* 672 * Add service properties to the tree. 673 */ 674 assert(cpg->cpg_service_pg != NULL); 675 grow_props_tree(cpg->cpg_service_pg, tree); 676 } 677 678 /* 679 * This function is a utility for build_composed_instance(). 680 */ 681 static void 682 build_composed_property_groups(entity_t *inst, uu_avl_t *tree) 683 { 684 composed_pg_t *cpg; 685 uu_avl_index_t marker; 686 composed_pg_t *match; 687 pgroup_t *pg; 688 entity_t *svc; 689 690 /* First capture the instance property groups. */ 691 for (pg = uu_list_first(inst->sc_pgroups); 692 pg != NULL; 693 pg = uu_list_next(inst->sc_pgroups, pg)) { 694 cpg = composed_pg_create(); 695 cpg->cpg_name = pg->sc_pgroup_name; 696 cpg->cpg_type = pg->sc_pgroup_type; 697 cpg->cpg_instance_pg = pg; 698 match = uu_avl_find(tree, cpg, NULL, &marker); 699 /* Since we do the instance first, there should be no match. */ 700 assert(match == NULL); 701 uu_avl_insert(tree, cpg, marker); 702 pg->sc_pgroup_composed = cpg; 703 } 704 705 /* Now capture the service property groups. */ 706 svc = inst->sc_parent; 707 cpg = NULL; 708 for (pg = uu_list_first(svc->sc_pgroups); 709 pg != NULL; 710 pg = uu_list_next(svc->sc_pgroups, pg)) { 711 if (cpg == NULL) 712 cpg = composed_pg_create(); 713 cpg->cpg_name = pg->sc_pgroup_name; 714 cpg->cpg_type = pg->sc_pgroup_type; 715 cpg->cpg_service_pg = pg; 716 match = uu_avl_find(tree, cpg, NULL, &marker); 717 if (match == NULL) { 718 uu_avl_insert(tree, cpg, marker); 719 /* Get new composed_pg_t next at top of loop. */ 720 cpg = NULL; 721 } else { 722 /* 723 * Already have a composed_pg from instance 724 * processing. Just add the pointer to the service 725 * pg and compose the properties. 726 */ 727 match->cpg_service_pg = pg; 728 compose_props(match); 729 } 730 } 731 if (cpg != NULL) 732 composed_pg_destroy(cpg); 733 } 734 735 static void 736 build_composed_instance(entity_t *inst) 737 { 738 uu_avl_t *tree; 739 740 assert(inst->sc_etype == SVCCFG_INSTANCE_OBJECT); 741 742 if (inst->sc_u.sc_instance.sc_composed == NULL) { 743 tree = uu_avl_create(composed_pg_pool, inst, TMPL_DEBUG_TREE); 744 if (tree == NULL) { 745 uu_die(gettext("composed_instance tree creation " 746 "failed: %s\n"), uu_strerror(uu_error())); 747 } 748 inst->sc_u.sc_instance.sc_composed = tree; 749 } 750 build_composed_property_groups(inst, 751 inst->sc_u.sc_instance.sc_composed); 752 } 753 754 static void 755 demolish_composed_instance(entity_t *inst) 756 { 757 composed_pg_t *cpg; 758 void *marker = NULL; 759 uu_avl_t *tree; 760 761 tree = inst->sc_u.sc_instance.sc_composed; 762 if (tree == NULL) 763 return; 764 765 marker = NULL; 766 while ((cpg = uu_avl_teardown(tree, &marker)) != NULL) { 767 composed_pg_destroy(cpg); 768 } 769 uu_avl_destroy(tree); 770 771 inst->sc_u.sc_instance.sc_composed = NULL; 772 } 773 /* 774 * Return the number of values in prop. 775 */ 776 static size_t 777 count_prop_values(property_t *prop) 778 { 779 return (uu_list_numnodes(prop->sc_property_values)); 780 } 781 782 static int 783 is_numeric_type(scf_type_t type) 784 { 785 if (type == SCF_TYPE_BOOLEAN) 786 return (1); 787 if (type == SCF_TYPE_COUNT) 788 return (1); 789 if (type == SCF_TYPE_INTEGER) 790 return (1); 791 return (0); 792 } 793 794 static pg_type_t 795 pgroup_type(pgroup_t *pg) 796 { 797 if (strcmp(pg->sc_pgroup_type, SCF_GROUP_TEMPLATE_PG_PATTERN) == 0) 798 return (PG_PATTERN_PG); 799 if (strcmp(pg->sc_pgroup_type, SCF_GROUP_TEMPLATE_PROP_PATTERN) == 0) 800 return (PROP_PATTERN_PG); 801 return (NORMAL_PG); 802 } 803 804 /* 805 * Search the property group at pg for a property named name. If the 806 * property group has a tree of composed properties, the tree will be 807 * searched for the property. Otherwise, the property group's linked list 808 * will be searched. 809 */ 810 static property_t * 811 property_find(pgroup_t *pg, const char *name) 812 { 813 composed_pg_t *cpg; 814 property_t look; 815 816 cpg = pg->sc_pgroup_composed; 817 818 if ((cpg == NULL) || (cpg->cpg_composed_props == NULL)) { 819 /* This is not a composed property group. */ 820 return (internal_property_find(pg, name)); 821 } 822 823 /* 824 * This is a composed property group, so look for the property in 825 * the AVL tree. 826 */ 827 look.sc_property_name = (char *)name; 828 return (uu_avl_find(cpg->cpg_composed_props, &look, NULL, NULL)); 829 } 830 831 /* 832 * Functions for manipulating the avalues structure. 833 */ 834 835 /* 836 * Free allocated memory referenced by the avalues structure. Then, free 837 * the structure itself. 838 */ 839 static void 840 av_destroy(avalues_t *av) 841 { 842 if (av == NULL) 843 return; 844 switch (av->av_type) { 845 case SCF_TYPE_BOOLEAN: 846 case SCF_TYPE_COUNT: 847 uu_free(av->av_v.av_unsigned); 848 break; 849 case SCF_TYPE_INTEGER: 850 uu_free(av->av_v.av_integer); 851 break; 852 default: 853 /* 854 * We don't need to free the strings that are referenced by 855 * av_string. The strings are held in propery_t structures 856 * that will be freed at a later time. 857 */ 858 uu_free(av->av_v.av_string); 859 break; 860 } 861 uu_free(av); 862 } 863 /* 864 * Allocate and inialize an avalues structure. count represents the 865 * number of values the structure is expected to hold. type specifies how 866 * the consumer of the property values would like to see them represented. 867 * See comments for the av_get_values() more details on how type is used. 868 * 869 * The returned structure must be freed by calling av_destroy(). 870 * 871 * NULL is returned if memory allocation fails. 872 */ 873 static avalues_t * 874 av_create(size_t count, scf_type_t type) 875 { 876 uint_t alloc_failed = 0; 877 avalues_t *av; 878 879 av = uu_zalloc(sizeof (*av)); 880 if (av == NULL) 881 return (NULL); 882 av->av_count = count; 883 av->av_type = type; 884 switch (type) { 885 case SCF_TYPE_BOOLEAN: 886 case SCF_TYPE_COUNT: 887 av->av_v.av_unsigned = uu_zalloc(count * sizeof (uint64_t)); 888 if (av->av_v.av_unsigned == NULL) 889 alloc_failed = 1; 890 break; 891 case SCF_TYPE_INTEGER: 892 av->av_v.av_integer = uu_zalloc(count * sizeof (int64_t)); 893 if (av->av_v.av_integer == NULL) 894 alloc_failed = 1; 895 break; 896 default: 897 av->av_v.av_string = uu_zalloc(count * sizeof (char *)); 898 if (av->av_v.av_string == NULL) 899 alloc_failed = 1; 900 } 901 if (alloc_failed) { 902 av_destroy(av); 903 return (NULL); 904 } 905 return (av); 906 } 907 908 /* 909 * Return the ith integer value in av. 910 */ 911 static int64_t 912 av_get_integer(avalues_t *av, uint_t i) 913 { 914 assert(av->av_type == SCF_TYPE_INTEGER); 915 assert(i < av->av_count); 916 return (*(av->av_v.av_integer + i)); 917 } 918 919 /* 920 * Return the ith string value in av. 921 */ 922 static const char * 923 av_get_string(avalues_t *av, uint_t i) 924 { 925 assert(is_numeric_type(av->av_type) == 0); 926 assert(i < av->av_count); 927 return (*(av->av_v.av_string + i)); 928 } 929 930 /* 931 * Return the ith unsigned value in av. 932 */ 933 static uint64_t 934 av_get_unsigned(avalues_t *av, uint_t i) 935 { 936 assert((av->av_type == SCF_TYPE_BOOLEAN) || 937 (av->av_type == SCF_TYPE_COUNT)); 938 assert(i < av->av_count); 939 return (*(av->av_v.av_unsigned + i)); 940 } 941 942 /* 943 * Store the value in the ith slot of the av structure. If av is being 944 * used to store numeric values, the string at value will be converted to 945 * the appropriate numeric form. 946 */ 947 static tmpl_validate_status_t 948 av_set_value(avalues_t *av, uint_t i, const char *value) 949 { 950 char *endptr; 951 int64_t n; 952 uint64_t un; 953 954 if (is_numeric_type(av->av_type)) { 955 switch (av->av_type) { 956 case SCF_TYPE_BOOLEAN: 957 case SCF_TYPE_COUNT: 958 un = strtoull(value, &endptr, 0); 959 if ((endptr == value) || (*endptr != 0)) { 960 return (TVS_BAD_CONVERSION); 961 } 962 *(av->av_v.av_unsigned + i) = un; 963 break; 964 case SCF_TYPE_INTEGER: 965 n = strtoll(value, &endptr, 0); 966 if ((endptr == value) || (*endptr != 0)) { 967 return (TVS_BAD_CONVERSION); 968 } 969 *(av->av_v.av_integer + i) = n; 970 } 971 } else { 972 *(av->av_v.av_string + i) = value; 973 } 974 975 return (TVS_SUCCESS); 976 } 977 978 /* 979 * Find the property whose name is prop_name in the property group at pg. 980 * Read all the values of this property and return them in an avalues 981 * structure placing the address of the structure in *values. The caller 982 * must free the structure by calling av_destroy(). 983 * 984 * The type parameter is used to indicate the type of information that the 985 * caller would like to consume. If it is one of the numeric types, the 986 * property value will be converted to the appropriate numeric type before 987 * placing it in the avalues struct. Decoding will be done before the 988 * conversion if necessary. 989 */ 990 static tmpl_validate_status_t 991 av_get_values(pgroup_t *pg, const char *prop_name, scf_type_t type, 992 avalues_t **values) 993 { 994 avalues_t *av; 995 uint_t i; 996 property_t *prop; 997 tmpl_validate_status_t rc; 998 value_t *v; 999 1000 prop = property_find(pg, prop_name); 1001 if (prop == NULL) { 1002 return (TVS_NOMATCH); 1003 } 1004 assert(prop->sc_value_type == SCF_TYPE_ASTRING); 1005 av = av_create(count_prop_values(prop), type); 1006 if (av == NULL) 1007 uu_die(emesg_nomem); 1008 1009 /* Collect the values. */ 1010 for ((v = uu_list_first(prop->sc_property_values)), i = 0; 1011 v != NULL; 1012 (v = uu_list_next(prop->sc_property_values, v)), i++) { 1013 assert(i < av->av_count); 1014 assert(v->sc_type == SCF_TYPE_ASTRING); 1015 rc = av_set_value(av, i, v->sc_u.sc_string); 1016 if (rc != TVS_SUCCESS) { 1017 av_destroy(av); 1018 return (rc); 1019 } 1020 } 1021 *values = av; 1022 return (TVS_SUCCESS); 1023 } 1024 1025 /* 1026 * Find the property in pg whose name is prop_name. Return a pointer to 1027 * the first astring value in that property. 1028 * 1029 * NULL is returned if there is no property named prop_name or if it does 1030 * not have an astring value. 1031 */ 1032 static const char * 1033 find_astring_value_in_pg(pgroup_t *pg, const char *prop_name) 1034 { 1035 property_t *prop; 1036 value_t *v; 1037 1038 prop = property_find(pg, prop_name); 1039 if (prop == NULL) 1040 return (NULL); 1041 if (prop->sc_value_type != SCF_TYPE_ASTRING) 1042 return (NULL); 1043 v = uu_list_first(prop->sc_property_values); 1044 if (v == NULL) 1045 return (NULL); 1046 assert(v->sc_type == SCF_TYPE_ASTRING); 1047 return (v->sc_u.sc_string); 1048 } 1049 /* 1050 * Find the first property value of type SCF_TYPE_COUNT in the property at 1051 * prop. Return the value to count. 1052 */ 1053 static tmpl_validate_status_t 1054 find_count_value(property_t *prop, uint64_t *count) 1055 { 1056 value_t *value; 1057 1058 assert(prop->sc_value_type == SCF_TYPE_COUNT); 1059 value = uu_list_first(prop->sc_property_values); 1060 if (value == NULL) 1061 return (TVS_NOMATCH); 1062 *count = value->sc_u.sc_count; 1063 return (TVS_SUCCESS); 1064 } 1065 1066 /* 1067 * pattern is a property group representing a pg_pattern or a 1068 * prop_pattern. This function returns the name specification from the 1069 * pg_pattern or prop_pattern. 1070 */ 1071 static const char * 1072 find_name_specification(pgroup_t *pattern) 1073 { 1074 return (find_astring_value_in_pg(pattern, SCF_PROPERTY_TM_NAME)); 1075 } 1076 1077 /* 1078 * pattern is a property group representing a pg_pattern or a prop_pattern. 1079 * This function returns the type specification from the pg_pattern or 1080 * prop_pattern. 1081 */ 1082 static const char * 1083 find_type_specification(pgroup_t *pattern) 1084 { 1085 return (find_astring_value_in_pg(pattern, SCF_PROPERTY_TM_TYPE)); 1086 } 1087 1088 /* 1089 * Find the FMRI of the restarter for the entity, e. The restarter is the 1090 * value of the "restarter" property in the "general" property group. 1091 */ 1092 static const char * 1093 find_restarter(entity_t *e) 1094 { 1095 pgroup_t *pg; 1096 property_t *prop; 1097 value_t *v; 1098 1099 pg = internal_pgroup_find(e, scf_pg_general, scf_group_framework); 1100 if (pg != NULL) { 1101 prop = property_find(pg, SCF_PROPERTY_RESTARTER); 1102 if ((prop != NULL) && (prop->sc_value_type == SCF_TYPE_FMRI)) { 1103 v = uu_list_first(prop->sc_property_values); 1104 if (v != NULL) 1105 return (v->sc_u.sc_string); 1106 } 1107 } 1108 1109 /* 1110 * Didn't find the restarter. 1111 */ 1112 return (NULL); 1113 } 1114 1115 /* 1116 * prop_pattern points to a prop_pattern. This function finds the 1117 * cardinality specification in the prop_pattern and returns the minimum 1118 * and maximum values of the cardinality. 1119 * 1120 * Returns TVS_NOMATCH if either the cardinality minimum or maximum are 1121 * missing. 1122 */ 1123 static tmpl_validate_status_t 1124 get_cardinality(pgroup_t *prop_pattern, uint64_t *min, uint64_t *max) 1125 { 1126 property_t *prop; 1127 tmpl_validate_status_t rc; 1128 1129 assert(strcmp(prop_pattern->sc_pgroup_type, 1130 SCF_GROUP_TEMPLATE_PROP_PATTERN) == 0); 1131 1132 prop = property_find(prop_pattern, 1133 SCF_PROPERTY_TM_CARDINALITY_MIN); 1134 if (prop == NULL) 1135 return (TVS_NOMATCH); 1136 rc = find_count_value(prop, min); 1137 if (rc != TVS_SUCCESS) 1138 return (rc); 1139 1140 prop = property_find(prop_pattern, 1141 SCF_PROPERTY_TM_CARDINALITY_MAX); 1142 if (prop == NULL) 1143 return (TVS_NOMATCH); 1144 rc = find_count_value(prop, max); 1145 1146 return (rc); 1147 } 1148 1149 /* 1150 * Ranges are represented as ASTRING values in the property at range_prop. 1151 * The minimum and maximum of the range are separated by a comma. 1152 * 1153 * range_prop can contain multiple range values, so we return a pointer to 1154 * an allocated array of range_t in ranges. This array must be freed by 1155 * the caller using free(). count receives the number of range_t 1156 * structures that are allocated. 1157 * 1158 * type tells us whether the range values should be treated as signed or 1159 * unsigned. It must be SCF_TYPE_COUNT or SCF_TYPE_INTEGER. 1160 */ 1161 static tmpl_validate_status_t 1162 get_ranges(property_t *range_prop, scf_type_t type, range_t **ranges, 1163 uint_t *count) 1164 { 1165 char *endptr; 1166 char *endptr2; 1167 range_t *r; 1168 value_t *value; 1169 1170 *count = uu_list_numnodes(range_prop->sc_property_values); 1171 assert(*count != 0); 1172 r = safe_malloc(*count * sizeof (*r)); 1173 *ranges = r; 1174 for (value = uu_list_first(range_prop->sc_property_values); 1175 value != NULL; 1176 value = uu_list_next(range_prop->sc_property_values, value)) { 1177 assert(value->sc_type == SCF_TYPE_ASTRING); 1178 1179 /* First get the minimum */ 1180 errno = 0; 1181 if (type == SCF_TYPE_INTEGER) { 1182 r->rng_u.rng_signed.rng_min = 1183 strtoll(value->sc_u.sc_string, &endptr, 0); 1184 } else { 1185 r->rng_u.rng_unsigned.rng_min = 1186 strtoull(value->sc_u.sc_string, &endptr, 0); 1187 } 1188 if ((errno != 0) || (endptr == value->sc_u.sc_string)) 1189 goto badtemplate; 1190 if (*endptr != ',') 1191 goto badtemplate; 1192 1193 /* Now get the maximum */ 1194 endptr++; 1195 if (type == SCF_TYPE_INTEGER) { 1196 r->rng_u.rng_signed.rng_max = 1197 strtoll(endptr, &endptr2, 0); 1198 } else { 1199 r->rng_u.rng_unsigned.rng_max = 1200 strtoull(endptr, &endptr2, 0); 1201 } 1202 if ((errno != 0) || (endptr2 == endptr) || 1203 (*endptr2 != 0)) 1204 goto badtemplate; 1205 r++; 1206 } 1207 1208 return (TVS_SUCCESS); 1209 1210 badtemplate: 1211 free(*ranges); 1212 *ranges = NULL; 1213 return (TVS_BAD_TEMPLATE); 1214 } 1215 1216 static tv_errors_t * 1217 tv_errors_create(const char *fmri) 1218 { 1219 tv_errors_t *ste; 1220 1221 ste = safe_malloc(sizeof (*ste)); 1222 uu_list_node_init(ste, &ste->tve_node, tv_errors_pool); 1223 ste->tve_errors = _scf_create_errors(fmri, 1); 1224 if (ste->tve_errors == NULL) 1225 uu_die(emesg_nomem); 1226 1227 return (ste); 1228 } 1229 1230 static void 1231 destroy_scf_errors(tv_errors_t *ste) 1232 { 1233 scf_tmpl_errors_destroy(ste->tve_errors); 1234 uu_list_node_fini(ste, &ste->tve_node, tv_errors_pool); 1235 free(ste); 1236 } 1237 1238 /* 1239 * Given a property group and the name of a property within that property 1240 * group, generate the name of the property group that holds the 1241 * prop_pattern information for the property. The address of the generated 1242 * name is returned to prop_pattern_pg_name. The memory holding the 1243 * generated name must be freed using uu_free(). 1244 */ 1245 static tmpl_validate_status_t 1246 gen_prop_pattern_pg_name(pgroup_t *pg_pattern, const char *prop_name, 1247 char **prop_pattern_pg_name) 1248 { 1249 ssize_t limit; 1250 char *name; 1251 size_t prefix_size; 1252 const char *unique; 1253 1254 limit = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1; 1255 assert(limit > 0); 1256 1257 /* Get the unique part of the pg_pattern's property group name. */ 1258 prefix_size = strlen(SCF_PG_TM_PG_PAT_BASE); 1259 assert(strncmp(pg_pattern->sc_pgroup_name, SCF_PG_TM_PG_PAT_BASE, 1260 prefix_size) == 0); 1261 unique = pg_pattern->sc_pgroup_name + prefix_size; 1262 1263 /* Construct the prop pattern property group name. */ 1264 *prop_pattern_pg_name = NULL; 1265 name = uu_zalloc(limit); 1266 if (name == NULL) 1267 uu_die(emesg_nomem); 1268 if (snprintf(name, limit, "%s%s_%s", SCF_PG_TM_PROP_PATTERN_PREFIX, 1269 unique, prop_name) >= limit) { 1270 uu_free(name); 1271 return (TVS_BAD_TEMPLATE); 1272 } 1273 *prop_pattern_pg_name = name; 1274 return (TVS_SUCCESS); 1275 } 1276 1277 /* 1278 * Error message printing functions: 1279 */ 1280 1281 /* 1282 * Flags for use by im_perror_item. 1283 */ 1284 #define IPI_NOT_FIRST 0x1 /* Not first item to be displayed. */ 1285 1286 /* 1287 * Print a single item of information about a validation failure. This 1288 * function takes care of printing the appropriate decoration before the 1289 * first item and between subsequent items. 1290 * 1291 * Parameters: 1292 * out Stream to receive the output. 1293 * desc Text describing the items 1294 * item Address of the item to be displayed 1295 * type Type of the item 1296 * flags Used by im_perror_item to keep track of where it 1297 * is. Caller should set flags to 0 before calling 1298 * this function with the first item. 1299 */ 1300 static void 1301 im_perror_item(FILE *out, const char *desc, void *item, scf_type_t type, 1302 int *flags) 1303 { 1304 const char *cp; 1305 const char *first_sep; 1306 int64_t ival; 1307 const char *subsequent_sep; 1308 uint64_t uval; 1309 1310 /* Nothing to print if item is NULL. */ 1311 if (item == NULL) 1312 return; 1313 1314 assert(type != SCF_TYPE_INVALID); 1315 1316 /* Establish separators for environment. */ 1317 if (est->sc_cmd_flags & SC_CMD_IACTIVE) { 1318 /* Interactive mode - make messages readable */ 1319 first_sep = ":\n\t"; 1320 subsequent_sep = "\n\t"; 1321 } else { 1322 /* Non-interactive - one line messages. */ 1323 first_sep = ": "; 1324 subsequent_sep = "; "; 1325 } 1326 1327 /* Print separator and description */ 1328 if (*flags & IPI_NOT_FIRST) { 1329 (void) fprintf(out, subsequent_sep); 1330 } else { 1331 (void) fprintf(out, first_sep); 1332 *flags |= IPI_NOT_FIRST; 1333 } 1334 (void) fprintf(out, "%s=", desc); 1335 1336 switch (type) { 1337 case SCF_TYPE_BOOLEAN: 1338 uval = *((uint64_t *)item); 1339 if (uval) { 1340 (void) fprintf(out, "\"%s\"", gettext("true")); 1341 } else { 1342 (void) fprintf(out, "\"%s\"", gettext("false")); 1343 } 1344 break; 1345 case SCF_TYPE_COUNT: 1346 uval = *((uint64_t *)item); 1347 (void) fprintf(out, "%" PRIu64, uval); 1348 break; 1349 case SCF_TYPE_INTEGER: 1350 ival = *((int64_t *)item); 1351 (void) fprintf(out, "%" PRIi64, ival); 1352 break; 1353 default: 1354 /* 1355 * Treat everything else as a string, but escape any 1356 * internal quotes. 1357 */ 1358 (void) fputc('\"', out); 1359 cp = (const char *)item; 1360 while (*cp != 0) { 1361 if (*cp == '\"') { 1362 (void) fprintf(out, "\\\""); 1363 } else { 1364 (void) fputc(*cp, out); 1365 } 1366 cp++; 1367 } 1368 (void) fputc('\"', out); 1369 break; 1370 } 1371 } 1372 1373 /* 1374 * Print erroneous FMRI. 1375 */ 1376 static void 1377 im_perror_fmri(FILE *out, im_tmpl_error_t *i, int *flags) 1378 { 1379 if (i->ite_entity != NULL) { 1380 im_perror_item(out, "FMRI", (void *)i->ite_entity->sc_fmri, 1381 SCF_TYPE_FMRI, flags); 1382 } 1383 } 1384 1385 /* 1386 * Print erroneous property group name. 1387 */ 1388 static void 1389 im_perror_pg_name(FILE *out, im_tmpl_error_t *i, int *flags) 1390 { 1391 if (i->ite_pg != NULL) { 1392 im_perror_item(out, gettext("Property group"), 1393 (void *)i->ite_pg->sc_pgroup_name, SCF_TYPE_ASTRING, 1394 flags); 1395 } 1396 } 1397 1398 /* 1399 * If srcflag is 1, print the template source of the pg_pattern or 1400 * prop_pattern at pattern. Always print the name and type of the pattern. 1401 */ 1402 static void 1403 im_perror_pattern_info(FILE *out, pgroup_t *pattern, int *flags, int srcflag) 1404 { 1405 void *c; 1406 const char *name_string; 1407 const char *type_string; 1408 1409 if (pattern == NULL) 1410 return; 1411 switch (pgroup_type(pattern)) { 1412 case PG_PATTERN_PG: 1413 name_string = gettext("pg_pattern name"); 1414 type_string = gettext("pg_pattern type"); 1415 break; 1416 case PROP_PATTERN_PG: 1417 name_string = gettext("prop_pattern name"); 1418 type_string = gettext("prop_pattern type"); 1419 break; 1420 default: 1421 assert(0); 1422 abort(); 1423 } 1424 if (srcflag) { 1425 im_perror_item(out, gettext("Template source"), 1426 (void *)pattern->sc_parent->sc_fmri, SCF_TYPE_FMRI, flags); 1427 } 1428 c = (void *)find_name_specification(pattern); 1429 im_perror_item(out, name_string, 1430 (c == NULL) ? "" : c, SCF_TYPE_ASTRING, flags); 1431 c = (void *)find_type_specification(pattern); 1432 im_perror_item(out, type_string, 1433 (c == NULL) ? "" : c, SCF_TYPE_ASTRING, flags); 1434 } 1435 1436 /* 1437 * Print information about the template specifications that were violated, 1438 * so that the user can find the specification. 1439 */ 1440 static void 1441 im_perror_template_info(FILE *out, im_tmpl_error_t *i, int *flags) 1442 { 1443 pgroup_t *pg_pattern = i->ite_pg_pattern; 1444 pgroup_t *prop_pattern = i->ite_prop_pattern; 1445 int srcflag = 1; 1446 1447 if (pg_pattern != NULL) { 1448 im_perror_pattern_info(out, pg_pattern, flags, srcflag); 1449 srcflag = 0; 1450 } 1451 if (prop_pattern != NULL) { 1452 im_perror_pattern_info(out, prop_pattern, flags, srcflag); 1453 } 1454 } 1455 1456 /* Print error message for TVS_BAD_CONVERSION errors. */ 1457 static void 1458 im_perror_bad_conversion(FILE *out, im_tmpl_error_t *i, const char *prefix) 1459 { 1460 int flags = 0; 1461 1462 (void) fprintf(out, gettext("%sUnable to convert property value"), 1463 prefix); 1464 im_perror_fmri(out, i, &flags); 1465 im_perror_pg_name(out, i, &flags); 1466 im_perror_item(out, gettext("Property"), 1467 (void *)i->ite_prop->sc_property_name, SCF_TYPE_ASTRING, &flags); 1468 im_perror_template_info(out, i, &flags); 1469 (void) fputc('\n', out); 1470 } 1471 1472 /* Print error message for TVS_BAD_TEMPLATE errors. */ 1473 static void 1474 im_perror_bad_template(FILE *out, im_tmpl_error_t *i, const char *prefix) 1475 { 1476 int flags = 0; 1477 1478 assert(i->ite_einfo.ei_type == EIT_BAD_TEMPLATE); 1479 (void) fprintf(out, gettext("%sInvalid template - %s"), prefix, 1480 i->ite_einfo.ei_u.ei_bad_template.ei_reason); 1481 im_perror_fmri(out, i, &flags); 1482 im_perror_template_info(out, i, &flags); 1483 (void) fputc('\n', out); 1484 } 1485 1486 /* 1487 * Print error message for TVS_INVALID_TYPE_SPECIFICATION errors. This 1488 * error occurs if a prop_pattern has an invalid type specification. Thus, 1489 * it is an indication of an invalid template rather than a violation of a 1490 * template. 1491 */ 1492 static void 1493 im_perror_invalid_type(FILE *out, im_tmpl_error_t *i, const char *prefix) 1494 { 1495 int flags = 0; 1496 const char *prop_pattern_name; 1497 1498 (void) fprintf(out, gettext("%sInvalid type in prop_pattern"), prefix); 1499 im_perror_pg_name(out, i, &flags); 1500 if (i->ite_prop_pattern != NULL) { 1501 prop_pattern_name = 1502 find_name_specification(i->ite_prop_pattern); 1503 im_perror_item(out, gettext("prop_pattern name"), 1504 (void *)prop_pattern_name, SCF_TYPE_ASTRING, &flags); 1505 } 1506 im_perror_template_info(out, i, &flags); 1507 (void) fputc('\n', out); 1508 } 1509 1510 /* 1511 * Print error message for TVS_MISSING_PG_TYPE errors. In this case the 1512 * template specifies a type, but the property group itself has no type. 1513 */ 1514 static void 1515 im_perror_missing_pg_type(FILE *out, im_tmpl_error_t *i, const char *prefix) 1516 { 1517 int flags = 0; 1518 const char *type_spec; 1519 1520 (void) fprintf(out, gettext("%sProperty group has no type"), prefix); 1521 im_perror_fmri(out, i, &flags); 1522 im_perror_pg_name(out, i, &flags); 1523 if (i->ite_pg_pattern != NULL) { 1524 type_spec = find_type_specification(i->ite_pg_pattern); 1525 im_perror_item(out, gettext("Type specified in pg_pattern"), 1526 (void *)type_spec, SCF_TYPE_ASTRING, &flags); 1527 } 1528 (void) fputc('\n', out); 1529 } 1530 1531 /* 1532 * Print error message for TVS_MISSING_TYPE_SPECIFICATION errors. A 1533 * property group has a "required" attribute of true, but it does not have 1534 * a type specification. 1535 */ 1536 static void 1537 im_perror_missing_type(FILE *out, im_tmpl_error_t *i, const char *prefix) 1538 { 1539 int flags = 0; 1540 const char *pg_pattern_name; 1541 1542 (void) fprintf(out, gettext("%sPg_pattern with true required attribute " 1543 "is missing the type attribute"), prefix); 1544 im_perror_fmri(out, i, &flags); 1545 if (i->ite_pg_pattern != NULL) { 1546 pg_pattern_name = find_name_specification(i->ite_pg_pattern); 1547 im_perror_item(out, gettext("Pg_pattern name"), 1548 (void *)pg_pattern_name, SCF_TYPE_ASTRING, &flags); 1549 } 1550 im_perror_template_info(out, i, &flags); 1551 (void) fputc('\n', out); 1552 } 1553 1554 static void 1555 im_tmpl_error_print(FILE *out, im_tmpl_error_t *ite, const char *prefix) 1556 { 1557 switch (ite->ite_type) { 1558 case TVS_BAD_CONVERSION: 1559 im_perror_bad_conversion(out, ite, prefix); 1560 break; 1561 case TVS_BAD_TEMPLATE: 1562 im_perror_bad_template(out, ite, prefix); 1563 break; 1564 case TVS_INVALID_TYPE_SPECIFICATION: 1565 im_perror_invalid_type(out, ite, prefix); 1566 break; 1567 case TVS_MISSING_PG_TYPE: 1568 im_perror_missing_pg_type(out, ite, prefix); 1569 break; 1570 case TVS_MISSING_TYPE_SPECIFICATION: 1571 im_perror_missing_type(out, ite, prefix); 1572 break; 1573 case TVS_NOMATCH: 1574 /* 1575 * TVS_NOMATCH should be handled where it occurs. Thus, 1576 * there are no error messages associated with it. 1577 */ 1578 assert(0); 1579 abort(); 1580 break; 1581 case TVS_SUCCESS: 1582 break; 1583 default: 1584 assert(0); 1585 abort(); 1586 } 1587 } 1588 1589 static char * 1590 int64_to_str(int64_t i) 1591 { 1592 char *c; 1593 const char *fmt; 1594 int size; 1595 1596 fmt = "%" PRIi64; 1597 size = snprintf(NULL, 0, fmt, i) + 1; 1598 c = safe_malloc(size); 1599 (void) snprintf(c, size, fmt, i); 1600 return (c); 1601 } 1602 1603 static char * 1604 uint64_to_str(uint64_t u) 1605 { 1606 char *c; 1607 const char *fmt; 1608 int size; 1609 1610 fmt = "%" PRIu64; 1611 size = snprintf(NULL, 0, fmt, u) + 1; 1612 c = safe_malloc(size); 1613 (void) snprintf(c, size, fmt, u); 1614 return (c); 1615 } 1616 1617 /* 1618 * Convert the value to a string. The returned value must be freed using 1619 * free(3C). 1620 */ 1621 static const char * 1622 value_to_string(value_t *v) 1623 { 1624 char *c; 1625 1626 if (is_numeric_type(v->sc_type)) { 1627 switch (v->sc_type) { 1628 case SCF_TYPE_BOOLEAN: 1629 if (v->sc_u.sc_count == 0) { 1630 c = gettext("false"); 1631 } else { 1632 c = gettext("true"); 1633 } 1634 break; 1635 case SCF_TYPE_COUNT: 1636 c = uint64_to_str(v->sc_u.sc_count); 1637 return (c); 1638 case SCF_TYPE_INTEGER: 1639 c = int64_to_str(v->sc_u.sc_integer); 1640 return (c); 1641 } 1642 } else { 1643 c = v->sc_u.sc_string; 1644 } 1645 1646 return (safe_strdup(c)); 1647 } 1648 1649 /* 1650 * Subscripts for common error data. 1651 */ 1652 #define ED_PG_NAME 0 1653 #define ED_PROP_NAME 1 1654 #define ED_TMPL_FMRI 2 1655 #define ED_TMPL_PG_NAME 3 1656 #define ED_TMPL_PG_TYPE 4 1657 #define ED_TMPL_PROP_NAME 5 1658 #define ED_TMPL_PROP_TYPE 6 1659 #define ED_COUNT 7 1660 1661 /* 1662 * This function converts the error information specified by the function 1663 * parameters. It converts it to form needed by _scf_tmpl_add_error(). 1664 * _scf_tmpl_add_error() requires that the error information be in the form 1665 * of allocated strings that can be freed when it is done with them. Thus, 1666 * the bulk of this function is devoted to producing those allocated 1667 * strings. 1668 * 1669 * Once the strings are ready, we call _scf_tmpl_add_error() to add an 1670 * new error structure to errs. 1671 */ 1672 static int 1673 add_scf_error(tmpl_errors_t *errs, scf_tmpl_error_type_t ec, 1674 pgroup_t *pg_pattern, pgroup_t *pg, pgroup_t *prop_pattern, 1675 property_t *prop, value_t *val, error_info_t *einfo) 1676 { 1677 const char *actual = NULL; 1678 char *c; 1679 pgroup_t *conflict; 1680 const char *ed[ED_COUNT]; 1681 const char *ev1 = NULL; 1682 const char *ev2 = NULL; 1683 int i; 1684 scf_type_t prop_type; 1685 int rc; 1686 1687 (void) memset(ed, 0, sizeof (ed)); 1688 1689 /* Set values that are common to most error types. */ 1690 if (pg != NULL) { 1691 ed[ED_PG_NAME] = pg->sc_pgroup_name; 1692 } 1693 if (prop != NULL) { 1694 ed[ED_PROP_NAME] = prop->sc_property_name; 1695 } 1696 if (pg_pattern == NULL) { 1697 if (prop_pattern != NULL) { 1698 ed[ED_TMPL_FMRI] = prop_pattern->sc_parent->sc_fmri; 1699 } 1700 } else { 1701 ed[ED_TMPL_FMRI] = pg_pattern->sc_parent->sc_fmri; 1702 ed[ED_TMPL_PG_NAME] = find_name_specification(pg_pattern); 1703 ed[ED_TMPL_PG_TYPE] = find_type_specification(pg_pattern); 1704 } 1705 if (prop_pattern != NULL) { 1706 ed[ED_TMPL_PROP_NAME] = find_name_specification(prop_pattern); 1707 ed[ED_TMPL_PROP_TYPE] = find_type_specification(prop_pattern); 1708 } 1709 1710 /* 1711 * All of the strings that we've found must be strduped. This is 1712 * so that scf_tmpl_errors_destroy() can free them. We cannot use 1713 * the flag argument of _scf_create_errors() to indicate that the 1714 * strings should not be freed. The flag argument is an all or 1715 * nothing thing. In the code below we need to convert integers to 1716 * strings, and this requires memory allocation. Since we have to 1717 * allocate memory for that data, we need to allocate it for every 1718 * thing. 1719 */ 1720 for (i = 0; i < ED_COUNT; i++) { 1721 if (ed[i] == NULL) 1722 continue; 1723 ed[i] = safe_strdup(ed[i]); 1724 } 1725 1726 /* actual, ev1 and ev2 are error code specific. */ 1727 switch (ec) { 1728 case SCF_TERR_CARDINALITY_VIOLATION: 1729 assert(einfo != NULL); 1730 assert(einfo->ei_type == EIT_CARDINALITY); 1731 ev1 = uint64_to_str(einfo->ei_u.ei_cardinality.ei_min); 1732 ev2 = uint64_to_str(einfo->ei_u.ei_cardinality.ei_max); 1733 actual = uint64_to_str(einfo->ei_u.ei_cardinality.ei_count); 1734 break; 1735 case SCF_TERR_WRONG_PG_TYPE: 1736 /* Specified type. */ 1737 if (pg_pattern != NULL) { 1738 ev1 = find_type_specification(pg_pattern); 1739 if (ev1 != NULL) { 1740 ev1 = safe_strdup(ev1); 1741 } 1742 } 1743 /* Actual type. */ 1744 if (pg != NULL) { 1745 actual = pg->sc_pgroup_type; 1746 if (actual != NULL) { 1747 actual = safe_strdup(actual); 1748 } 1749 } 1750 break; 1751 case SCF_TERR_WRONG_PROP_TYPE: 1752 assert(einfo->ei_type == EIT_PROP_TYPE); 1753 prop_type = einfo->ei_u.ei_prop_type.ei_specified; 1754 ev1 = safe_strdup(scf_type_to_string(prop_type)); 1755 prop_type = einfo->ei_u.ei_prop_type.ei_actual; 1756 actual = safe_strdup(scf_type_to_string(prop_type)); 1757 break; 1758 case SCF_TERR_VALUE_CONSTRAINT_VIOLATED: 1759 actual = value_to_string(val); 1760 break; 1761 case SCF_TERR_MISSING_PG: 1762 assert(einfo->ei_type == EIT_MISSING_PG); 1763 ev1 = safe_strdup(einfo->ei_u.ei_missing_pg.ei_pg_name); 1764 ev2 = safe_strdup(einfo->ei_u.ei_missing_pg.ei_pg_type); 1765 break; 1766 case SCF_TERR_MISSING_PROP: 1767 assert(einfo->ei_type == EIT_MISSING_PROP); 1768 ev1 = safe_strdup(einfo->ei_u.ei_missing_prop.ei_prop_name); 1769 break; 1770 case SCF_TERR_RANGE_VIOLATION: 1771 assert(einfo->ei_type == EIT_RANGE); 1772 if (einfo->ei_u.ei_range.ei_rtype == SCF_TYPE_COUNT) { 1773 c = uint64_to_str(einfo->ei_u.ei_range.ei_uvalue); 1774 } else { 1775 c = int64_to_str(einfo->ei_u.ei_range.ei_ivalue); 1776 } 1777 actual = c; 1778 break; 1779 case SCF_TERR_PG_PATTERN_CONFLICT: 1780 case SCF_TERR_PROP_PATTERN_CONFLICT: 1781 case SCF_TERR_GENERAL_REDEFINE: 1782 assert(einfo->ei_type == EIT_PATTERN_CONFLICT); 1783 conflict = einfo->ei_u.ei_pattern_conflict.ei_pattern; 1784 ev1 = safe_strdup(conflict->sc_parent->sc_fmri); 1785 ev2 = find_name_specification(conflict); 1786 if (ev2 != NULL) 1787 ev2 = safe_strdup(ev2); 1788 actual = find_type_specification(conflict); 1789 if (actual != NULL) 1790 actual = safe_strdup(actual); 1791 break; 1792 case SCF_TERR_INCLUDE_VALUES: 1793 assert(einfo->ei_type == EIT_INCLUDE_VALUES); 1794 ev1 = safe_strdup(einfo->ei_u.ei_inc_values.ei_type); 1795 break; 1796 case SCF_TERR_PG_PATTERN_INCOMPLETE: 1797 case SCF_TERR_PROP_PATTERN_INCOMPLETE: 1798 break; 1799 default: 1800 assert(0); 1801 abort(); 1802 }; 1803 1804 rc = _scf_tmpl_add_error(errs->te_cur_scf->tve_errors, ec, 1805 ed[ED_PG_NAME], ed[ED_PROP_NAME], ev1, ev2, actual, 1806 ed[ED_TMPL_FMRI], ed[ED_TMPL_PG_NAME], ed[ED_TMPL_PG_TYPE], 1807 ed[ED_TMPL_PROP_NAME], ed[ED_TMPL_PROP_TYPE]); 1808 1809 return (rc); 1810 } 1811 1812 /* 1813 * Create and initialize a new im_tmpl_error structure and add it to the 1814 * list of errors in errs. The rest of the parameters are used to 1815 * initialize the im_tmpl_error structure. 1816 */ 1817 static tmpl_validate_status_t 1818 tmpl_errors_add_im(tmpl_errors_t *errs, tmpl_validate_status_t ec, entity_t *e, 1819 pgroup_t *pg_pattern, pgroup_t *pg, pgroup_t *prop_pattern, 1820 property_t *prop, value_t *val, error_info_t *einfo) 1821 { 1822 im_tmpl_error_t *ite; 1823 int result; 1824 1825 ite = uu_zalloc(sizeof (*ite)); 1826 if (ite == NULL) 1827 uu_die(emesg_nomem); 1828 uu_list_node_init(ite, &ite->ite_node, inmem_errors_pool); 1829 ite->ite_type = ec; 1830 ite->ite_entity = e; 1831 ite->ite_pg = pg; 1832 ite->ite_pg_pattern = pg_pattern; 1833 ite->ite_prop = prop; 1834 ite->ite_prop_pattern = prop_pattern; 1835 ite->ite_value = val; 1836 if (einfo != NULL) 1837 ite->ite_einfo = *einfo; 1838 1839 result = uu_list_insert_after(errs->te_list, NULL, ite); 1840 assert(result == 0); 1841 return (TVS_SUCCESS); 1842 } 1843 1844 /* 1845 * pattern must point to a pg_pattern or a prop_pattern. This function 1846 * finds the property named required and returns the property's value. If 1847 * the property does not exist, false is return since it is the default. 1848 */ 1849 static int 1850 is_required(pgroup_t *pattern) 1851 { 1852 property_t *required; 1853 value_t *value; 1854 1855 assert((strcmp(pattern->sc_pgroup_type, 1856 SCF_GROUP_TEMPLATE_PG_PATTERN) == 0) || 1857 (strcmp(pattern->sc_pgroup_type, 1858 SCF_GROUP_TEMPLATE_PROP_PATTERN) == 0)); 1859 1860 required = property_find(pattern, SCF_PROPERTY_TM_REQUIRED); 1861 1862 /* Default if there is no required property is false. */ 1863 if (required == NULL) 1864 return (0); 1865 1866 /* Retrieve the value of the required property. */ 1867 value = uu_list_first(required->sc_property_values); 1868 if (value == NULL) 1869 return (0); 1870 if (value->sc_type == SCF_TYPE_BOOLEAN) 1871 return (value->sc_u.sc_count == 0 ? 0 : 1); 1872 1873 /* No boolean property values, so return false. */ 1874 return (0); 1875 } 1876 1877 /* 1878 * Load the service's restarter instance and the global instance from the 1879 * repository. This will allow us to use their templates in validating the 1880 * service. 1881 * 1882 * There is no function to unload the general templates. The memory that 1883 * is allocated by load_general_templates() will be freed automatically in 1884 * internal_service_free() which is called by internal_bundle_free(). 1885 */ 1886 static void 1887 load_general_templates(entity_t *svc) 1888 { 1889 const char *restarter; 1890 int is_global = 0; 1891 int r; 1892 1893 assert(svc->sc_etype == SVCCFG_SERVICE_OBJECT); 1894 1895 /* 1896 * If e is the global service, we only need to load the restarter. 1897 */ 1898 if ((strcmp(svc->sc_fmri, SCF_INSTANCE_GLOBAL) == 0) || 1899 (strcmp(svc->sc_fmri, SCF_SERVICE_GLOBAL) == 0)) { 1900 is_global = 1; 1901 } 1902 1903 /* 1904 * Load the templates for the service's restarter. 1905 */ 1906 restarter = find_restarter(svc); 1907 if (restarter == NULL) 1908 restarter = SCF_SERVICE_STARTD; 1909 if ((r = load_instance(restarter, "restarter", 1910 &svc->sc_u.sc_service.sc_restarter)) != 0) { 1911 /* 1912 * During initial manifest import, restarter may 1913 * not be in the repository yet. In this case we 1914 * continue on without it. 1915 */ 1916 if (r == ENOMEM) 1917 uu_die(emesg_nomem); 1918 else 1919 svc->sc_u.sc_service.sc_restarter = NULL; 1920 } 1921 if (is_global == 0) { 1922 if ((r = load_instance(SCF_INSTANCE_GLOBAL, "global", 1923 &svc->sc_u.sc_service.sc_global)) != 0) { 1924 /* 1925 * During initial manifest import, global may not be in 1926 * the repository yet. 1927 */ 1928 if (r == ENOMEM) 1929 uu_die(emesg_nomem); 1930 else 1931 svc->sc_u.sc_service.sc_global = NULL; 1932 } 1933 } 1934 } 1935 1936 /* 1937 * Load the instance specific restarter if one is declared. 1938 * 1939 * There is no corresponding unload_instance_restarter() function because 1940 * it is not needed. The memory will be freed in internal_instance_free() 1941 * when internal_bundle_free() is called. 1942 */ 1943 static void 1944 load_instance_restarter(entity_t *i) 1945 { 1946 const char *restarter; 1947 int r; 1948 1949 assert(i->sc_etype == SVCCFG_INSTANCE_OBJECT); 1950 1951 restarter = find_restarter(i); 1952 if (restarter == NULL) { 1953 /* No instance specific restarter */ 1954 return; 1955 } 1956 r = load_instance(restarter, "instance_restarter", 1957 &i->sc_u.sc_instance.sc_instance_restarter); 1958 if (r != 0) { 1959 /* 1960 * During initial manifest import, the restarter may not be 1961 * in the repository yet. In this case we continue on 1962 * without it. 1963 */ 1964 if (r == ENOMEM) 1965 uu_die(emesg_nomem); 1966 } 1967 } 1968 1969 /* 1970 * Find the next property after current in the property group at pg. If 1971 * the property group contains a tree of composed properties, that tree is 1972 * walked. Otherwise, we walk through the uu_list at sc_pgroup_props. 1973 */ 1974 static property_t * 1975 next_property(pgroup_t *pg, property_t *current) 1976 { 1977 composed_pg_t *cpg; 1978 property_t *prop; 1979 1980 cpg = pg->sc_pgroup_composed; 1981 if ((cpg != NULL) && (cpg->cpg_composed_props != NULL)) { 1982 /* Walk through composed property list. */ 1983 if (current) { 1984 prop = uu_avl_next(cpg->cpg_composed_props, current); 1985 } else { 1986 prop = uu_avl_first(cpg->cpg_composed_props); 1987 } 1988 } else { 1989 /* No composition available, so walk the list of properties */ 1990 if (current) { 1991 prop = uu_list_next(pg->sc_pgroup_props, current); 1992 } else { 1993 prop = uu_list_first(pg->sc_pgroup_props); 1994 } 1995 } 1996 1997 return (prop); 1998 } 1999 2000 static ptrn_info_t * 2001 ptrn_info_create(pgroup_t *pat) 2002 { 2003 entity_t *e; 2004 ptrn_info_t *info; 2005 composed_pg_t *match; 2006 composed_pg_t cpg; 2007 2008 info = safe_malloc(sizeof (*info)); 2009 2010 switch (pgroup_type(pat)) { 2011 case PG_PATTERN_PG: 2012 info->pi_ptrn_type = PG_PATTERN; 2013 break; 2014 case PROP_PATTERN_PG: 2015 info->pi_ptrn_type = PROP_PATTERN; 2016 break; 2017 default: 2018 assert(0); 2019 abort(); 2020 } 2021 info->pi_ptrnpg = pat; 2022 info->pi_name = find_name_specification(pat); 2023 info->pi_name = EMPTY_TO_NULL(info->pi_name); 2024 info->pi_type = find_type_specification(pat); 2025 info->pi_type = EMPTY_TO_NULL(info->pi_type); 2026 if (info->pi_ptrn_type == PG_PATTERN) { 2027 info->pi_target = find_astring_value_in_pg(pat, 2028 SCF_PROPERTY_TM_TARGET); 2029 if (info->pi_target == NULL) 2030 info->pi_target = SCF_TM_TARGET_THIS; 2031 } 2032 if (info->pi_ptrn_type == PROP_PATTERN) { 2033 info->pi_pgp_name = find_astring_value_in_pg(pat, 2034 SCF_PROPERTY_TM_PG_PATTERN); 2035 assert((info->pi_pgp_name != NULL) && 2036 (*(info->pi_pgp_name) != 0)); 2037 2038 /* 2039 * Find the property group that defines the pg_pattern that 2040 * holds this prop_pattern. 2041 */ 2042 e = pat->sc_parent; 2043 if (e->sc_etype == SVCCFG_INSTANCE_OBJECT) { 2044 (void) memset(&cpg, 0, sizeof (cpg)); 2045 cpg.cpg_name = info->pi_pgp_name; 2046 cpg.cpg_type = SCF_GROUP_TEMPLATE_PG_PATTERN; 2047 match = uu_avl_find(e->sc_u.sc_instance.sc_composed, 2048 &cpg, NULL, NULL); 2049 assert(match != NULL); 2050 info->pi_enc_pgp = CPG2PG(match); 2051 } else { 2052 info->pi_enc_pgp = internal_pgroup_find(e, 2053 info->pi_pgp_name, SCF_GROUP_TEMPLATE_PG_PATTERN); 2054 } 2055 assert(info->pi_enc_pgp != NULL); 2056 } 2057 uu_avl_node_init(info, &info->pi_link, ptrn_info_pool); 2058 return (info); 2059 } 2060 2061 static void 2062 ptrn_info_destroy(ptrn_info_t *info) 2063 { 2064 if (info == NULL) 2065 return; 2066 uu_avl_node_fini(info, &info->pi_link, ptrn_info_pool); 2067 free(info); 2068 } 2069 2070 /* 2071 * Walk through the property groups of the instance or service at e looking 2072 * for definitions of pg_patterns or prop_patterns as specified by type. 2073 * For each property group that matches type create a ptrn_info_t and add 2074 * it to the avl tree at tree. If duplicates are found add an error entry 2075 * to errs. 2076 */ 2077 static tmpl_validate_status_t 2078 gather_pattern(entity_t *e, ptrn_type_t type, uu_avl_t *tree, 2079 tmpl_errors_t *errs) 2080 { 2081 error_info_t einfo; 2082 ptrn_info_t *info = NULL; 2083 uu_avl_index_t marker; 2084 ptrn_info_t *match; 2085 pgroup_t *pg; 2086 tmpl_validate_status_t rc = TVS_SUCCESS; 2087 const char *selector; 2088 2089 switch (type) { 2090 case PG_PATTERN: 2091 selector = SCF_GROUP_TEMPLATE_PG_PATTERN; 2092 break; 2093 case PROP_PATTERN: 2094 selector = SCF_GROUP_TEMPLATE_PROP_PATTERN; 2095 break; 2096 default: 2097 assert(0); 2098 abort(); 2099 } 2100 2101 for (pg = uu_list_first(e->sc_pgroups); 2102 pg != NULL; 2103 pg = uu_list_next(e->sc_pgroups, pg)) { 2104 if (strcmp(pg->sc_pgroup_type, selector) != 0) { 2105 continue; 2106 } 2107 if (info != NULL) { 2108 /* Get rid of old structure. */ 2109 ptrn_info_destroy(info); 2110 } 2111 info = ptrn_info_create(pg); 2112 match = uu_avl_find(tree, info, NULL, &marker); 2113 if (match == NULL) { 2114 /* No match. Insert the info. */ 2115 uu_avl_insert(tree, info, marker); 2116 info = NULL; 2117 continue; 2118 } 2119 2120 /* Got a match. Determine if it is a conflict. */ 2121 if ((info->pi_name == NULL) || 2122 (info->pi_type == NULL) || 2123 (match->pi_name == NULL) || 2124 (match->pi_type == NULL)) { 2125 /* No conflicts if any wild cards. */ 2126 continue; 2127 } 2128 2129 /* 2130 * Name already matches, or we wouldn't have gotten 2131 * here. Make sure that the type also matches. 2132 */ 2133 if (strcmp(info->pi_type, match->pi_type) == 0) { 2134 continue; 2135 } 2136 2137 /* 2138 * If we get to this point we have a conflict, and 2139 * we need to generate the correct type of error. 2140 */ 2141 CLEAR_ERROR_INFO(&einfo); 2142 einfo.ei_type = EIT_PATTERN_CONFLICT; 2143 einfo.ei_u.ei_pattern_conflict.ei_pattern = 2144 match->pi_ptrnpg; 2145 if (type == PG_PATTERN) { 2146 rc = TVS_VALIDATION; 2147 if (add_scf_error(errs, SCF_TERR_PG_PATTERN_CONFLICT, 2148 info->pi_ptrnpg, NULL, NULL, NULL, NULL, 2149 &einfo) != 0) { 2150 /* 2151 * If we can no longer accumulate 2152 * errors, break out of the loop. 2153 */ 2154 break; 2155 } 2156 } else { 2157 /* 2158 * Possible conflicting prop_pattern. See if the 2159 * prop_patterns are declared in the same 2160 * pg_pattern. 2161 */ 2162 if ((info->pi_pgp_name == NULL) || 2163 (match->pi_pgp_name == NULL)) { 2164 continue; 2165 } 2166 if (strcmp(info->pi_pgp_name, match->pi_pgp_name) != 0) 2167 continue; 2168 2169 /* It is a real conflict. */ 2170 rc = TVS_VALIDATION; 2171 if (add_scf_error(errs, SCF_TERR_PROP_PATTERN_CONFLICT, 2172 info->pi_enc_pgp, NULL, info->pi_ptrnpg, NULL, NULL, 2173 &einfo) != 0) { 2174 /* 2175 * If we can no longer accumulate 2176 * errors, break out of the loop. 2177 */ 2178 break; 2179 } 2180 } 2181 } 2182 2183 ptrn_info_destroy(info); 2184 return (rc); 2185 } 2186 2187 /* 2188 * Free the pg_iter structure. 2189 */ 2190 static void 2191 pg_iter_destroy(pg_iter_t *i) 2192 { 2193 if (i == NULL) 2194 return; 2195 2196 uu_free(i); 2197 } 2198 2199 /* 2200 * Create a property group iterator for the instance at e. This iterator 2201 * will walk through the composed property groups of the instance. It will 2202 * then step through the property groups of the instance's restarter and 2203 * finally the global service. If you wish to iterate over a specific type 2204 * of property group, set restriction to point the the desired type. 2205 * Otherwise set restriction to NULL. 2206 * 2207 * The returned interator must be freed by calling pg_iter_destroy(). NULL 2208 * is returned if we are unable to allocate the necessary memory. 2209 */ 2210 static pg_iter_t * 2211 pg_iter_create(entity_t *e, const char *restriction) 2212 { 2213 pg_iter_t *i; 2214 2215 assert(e->sc_etype == SVCCFG_INSTANCE_OBJECT); 2216 2217 i = uu_zalloc(sizeof (*i)); 2218 if (i == NULL) 2219 return (NULL); 2220 2221 i->pgi_entity = e; 2222 i->pgi_restrict = restriction; 2223 i->pgi_level = TL_COMPOSED; 2224 i->pgi_service = e->sc_parent; 2225 2226 return (i); 2227 } 2228 2229 /* 2230 * Return the next property group in the iteration. NULL is returned if we 2231 * reach the end of the list. The iterator will automatically proceed from 2232 * most specific to most general levels. 2233 */ 2234 static pgroup_t * 2235 next_pattern_pg(pg_iter_t *i) 2236 { 2237 composed_pg_t *cpg; 2238 entity_t *e; 2239 pgroup_t *pg; 2240 uu_avl_t *composed_tree; 2241 2242 assert(i->pgi_level != TL_NOLEVEL); 2243 2244 while (i->pgi_entity != NULL) { 2245 if (i->pgi_level == TL_COMPOSED) { 2246 composed_tree = 2247 i->pgi_entity->sc_u.sc_instance.sc_composed; 2248 cpg = i->pgi_current.pgi_cpg; 2249 if (cpg == NULL) { 2250 cpg = uu_avl_first(composed_tree); 2251 } else { 2252 cpg = uu_avl_next(composed_tree, cpg); 2253 } 2254 if (cpg == NULL) { 2255 pg = NULL; 2256 } else { 2257 pg = CPG2PG(cpg); 2258 i->pgi_current.pgi_cpg = cpg; 2259 } 2260 } else { 2261 pg = i->pgi_current.pgi_pg; 2262 if (pg == NULL) { 2263 pg = uu_list_first(i->pgi_entity->sc_pgroups); 2264 } else { 2265 pg = uu_list_next(i->pgi_entity->sc_pgroups, 2266 pg); 2267 } 2268 i->pgi_current.pgi_pg = pg; 2269 } 2270 2271 if (pg == NULL) { 2272 /* 2273 * End of the list. Reset current and break out of 2274 * the loop. 2275 */ 2276 (void) memset(&i->pgi_current, 0, 2277 sizeof (i->pgi_current)); 2278 break; 2279 } 2280 2281 /* 2282 * If this iteration is for a specific type, verify that 2283 * this pg is of that type. 2284 */ 2285 if (i->pgi_restrict) { 2286 if (strcmp(pg->sc_pgroup_type, i->pgi_restrict) != 0) { 2287 continue; 2288 } 2289 } 2290 2291 return (pg); 2292 } 2293 2294 /* 2295 * End of the list in the current level. Move up to the next 2296 * level. 2297 */ 2298 switch (i->pgi_level) { 2299 case TL_COMPOSED: 2300 /* Skip service if we've finished a composed instance. */ 2301 e = i->pgi_entity; 2302 if (e->sc_u.sc_instance.sc_instance_restarter == NULL) { 2303 /* Use service restarter */ 2304 i->pgi_entity = 2305 i->pgi_service->sc_u.sc_service.sc_restarter; 2306 } else { 2307 /* Use instance restarter */ 2308 i->pgi_entity = 2309 e->sc_u.sc_instance.sc_instance_restarter; 2310 } 2311 i->pgi_level = TL_RESTARTER; 2312 break; 2313 case TL_RESTARTER: 2314 i->pgi_entity = i->pgi_service->sc_u.sc_service.sc_global; 2315 i->pgi_level = TL_GLOBAL; 2316 break; 2317 case TL_GLOBAL: 2318 i->pgi_level = TL_NOLEVEL; 2319 return (NULL); 2320 default: 2321 assert(0); 2322 abort(); 2323 } 2324 2325 /* Go process the next level. */ 2326 return (next_pattern_pg(i)); 2327 } 2328 2329 /* 2330 * Compare two pattern info structures (ptrn_info_t). If both structures 2331 * have names, the comparison is based on the name. If only one has a 2332 * name, the structure with no name will be first. If neither structure 2333 * has a name, the comparison is based on their types using similar wild 2334 * card logic. 2335 */ 2336 /* ARGSUSED2 */ 2337 static int 2338 ptrn_info_compare(const void *left, const void *right, void *unused) 2339 { 2340 ptrn_info_t *l = (ptrn_info_t *)left; 2341 ptrn_info_t *r = (ptrn_info_t *)right; 2342 2343 if ((l->pi_name != NULL) && (r->pi_name != NULL)) 2344 return (strcmp(l->pi_name, r->pi_name)); 2345 if ((l->pi_name == NULL) && (r->pi_name == NULL)) { 2346 /* No names, so we need to compare types. */ 2347 if ((l->pi_type != NULL) && (r->pi_type != NULL)) 2348 return (strcmp(l->pi_type, r->pi_type)); 2349 if ((l->pi_type == NULL) && (r->pi_type == NULL)) 2350 return (0); 2351 2352 /* If we get here, exactly one of the types is NULL */ 2353 if (l->pi_type == NULL) 2354 return (-1); 2355 return (1); 2356 } 2357 2358 /* If we get here, exactly one of the names is NULL */ 2359 if (l->pi_name == NULL) 2360 return (-1); 2361 return (1); 2362 } 2363 2364 /* 2365 * The target of a pg_pattern in combination with the level at which the 2366 * pg_pattern was defined determines whether or not it should be applied. 2367 * The following combinations should be ignored, and all others should be 2368 * applied. 2369 * 2370 * Target Level 2371 * ------ ----- 2372 * this TL_RESTARTER, TL_GLOBAL 2373 * "this" only applies if the pg_pattern was defined 2374 * at the instance or service level 2375 * delegate TL_INSTANCE, TL_SERVICE 2376 * Only restarters and the global service can 2377 * delegate. 2378 * instance TL_INSTANCE, TL_RESTARTER, TL_GLOBAL 2379 * Only the service level can specify the "instance" 2380 * target. 2381 * all TL_INSTANCE, TL_SERVICE, TL_RESTARTER 2382 * Only the global service can specify the "all" 2383 * target. 2384 * 2385 * Return Values: 2386 * 1 apply the pg_pattern 2387 * 0 ignore the pg_pattern 2388 */ 2389 static int 2390 target_check(const char *target, tmpl_level_t level) 2391 { 2392 if ((target == NULL) || (*target == 0)) { 2393 /* Default is this */ 2394 target = SCF_TM_TARGET_THIS; 2395 } 2396 if (strcmp(target, SCF_TM_TARGET_THIS) == 0) { 2397 if ((level == TL_RESTARTER) || 2398 (level == TL_GLOBAL)) { 2399 return (0); 2400 } else { 2401 return (1); 2402 } 2403 } 2404 if (strcmp(target, SCF_TM_TARGET_DELEGATE) == 0) { 2405 if ((level == TL_INSTANCE) || 2406 (level == TL_SERVICE)) { 2407 return (0); 2408 } else { 2409 return (1); 2410 } 2411 } 2412 if (strcmp(target, SCF_TM_TARGET_INSTANCE) == 0) { 2413 /* 2414 * Note that the test is inverted from the other cases. 2415 * This is because there is only one instance where apply 2416 * is the correct thing to do. 2417 */ 2418 if (level == TL_SERVICE) { 2419 return (1); 2420 } else { 2421 return (0); 2422 } 2423 } 2424 if (strcmp(target, SCF_TM_TARGET_ALL) == 0) { 2425 if ((level == TL_INSTANCE) || 2426 (level == TL_SERVICE) || 2427 (level == TL_RESTARTER)) { 2428 return (0); 2429 } 2430 } 2431 return (1); 2432 } 2433 2434 static int 2435 pg_target_check(pgroup_t *pg_pattern, tmpl_level_t level) 2436 { 2437 const char *target; 2438 2439 target = find_astring_value_in_pg(pg_pattern, SCF_PROPERTY_TM_TARGET); 2440 if (level == TL_COMPOSED) { 2441 switch (pg_pattern->sc_parent->sc_etype) { 2442 case SVCCFG_INSTANCE_OBJECT: 2443 level = TL_INSTANCE; 2444 break; 2445 case SVCCFG_SERVICE_OBJECT: 2446 level = TL_SERVICE; 2447 break; 2448 default: 2449 assert(0); 2450 abort(); 2451 } 2452 } 2453 return (target_check(target, level)); 2454 } 2455 2456 /* 2457 * Find the prop_pattern's type sepcification and convert it to the 2458 * appropriate scf_type. 2459 */ 2460 static tmpl_validate_status_t 2461 prop_pattern_type(pgroup_t *pattern, scf_type_t *type) 2462 { 2463 const char *type_spec; 2464 2465 assert(strcmp(pattern->sc_pgroup_type, 2466 SCF_GROUP_TEMPLATE_PROP_PATTERN) == 0); 2467 2468 type_spec = find_type_specification(pattern); 2469 if ((type_spec == NULL) || (*type_spec == 0)) 2470 return (TVS_MISSING_TYPE_SPECIFICATION); 2471 *type = scf_string_to_type(type_spec); 2472 return (TVS_SUCCESS); 2473 } 2474 2475 /* 2476 * This function is analagous to scf_property_is_type(3SCF), but it works 2477 * on the in memory representation of the property. 2478 * 2479 * RETURNS: 2480 * 0 The property at prop does not have the specified 2481 * type. 2482 * non-zero The property at prop does have the specified type. 2483 */ 2484 static int 2485 property_is_type(property_t *prop, scf_type_t type) 2486 { 2487 return (prop->sc_value_type == type); 2488 } 2489 2490 /* 2491 * This function generates a property group name for a template's 2492 * pg_pattern. The name and type of the pg_pattern are used to construct 2493 * the name, but either or both may be null. A pointer to the constructed 2494 * name is returned, and the referenced memory must be freed using 2495 * free(3c). NULL is returned if we are unable to allocate enough memory. 2496 */ 2497 static char * 2498 gen_pg_pattern_pg_name(const char *name, const char *type) 2499 { 2500 char *pg_name; 2501 char *rv = NULL; 2502 ssize_t name_size; 2503 2504 name_size = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH); 2505 pg_name = safe_malloc(name_size); 2506 rv = pg_name; 2507 2508 /* 2509 * There are four cases -- name and type are both null, name and 2510 * type are both non-null, only name is present or only type is 2511 * present. 2512 */ 2513 if ((name == NULL) || (*name == 0)) { 2514 if ((type == NULL) || (*type == 0)) { 2515 /* 2516 * Name and type are both null, so the PG name 2517 * contains only the prefix. 2518 */ 2519 if (strlcpy(pg_name, SCF_PG_TM_PG_PATTERN_PREFIX, 2520 name_size) >= name_size) { 2521 rv = NULL; 2522 } 2523 } else { 2524 /* 2525 * If we have a type and no name, the type becomes 2526 * part of the pg_pattern property group name. 2527 */ 2528 if (snprintf(pg_name, name_size, "%s%s", 2529 SCF_PG_TM_PG_PATTERN_T_PREFIX, type) >= 2530 name_size) { 2531 rv = NULL; 2532 } 2533 } 2534 } else { 2535 /* 2536 * As long as the pg_pattern has a name, it becomes part of 2537 * the name of the pg_pattern property group name. We 2538 * merely need to pick the appropriate prefix. 2539 */ 2540 const char *prefix; 2541 if ((type == NULL) || (*type == 0)) { 2542 prefix = SCF_PG_TM_PG_PATTERN_N_PREFIX; 2543 } else { 2544 prefix = SCF_PG_TM_PG_PATTERN_NT_PREFIX; 2545 } 2546 if (snprintf(pg_name, name_size, "%s%s", prefix, name) >= 2547 name_size) { 2548 rv = NULL; 2549 } 2550 } 2551 2552 if (rv == NULL) { 2553 /* Name was too big. */ 2554 free(pg_name); 2555 } 2556 return (rv); 2557 } 2558 2559 /* 2560 * pinfo contains information about a prop_pattern. An include_values 2561 * element with a type of type has been included in the prop_pattern 2562 * specification. We need to determine if the prop_pattern also contains 2563 * constraints or values specifications as determined by type. Thus, we 2564 * search the prop_pattern for properties whose names start with the 2565 * correct prefix. 2566 */ 2567 static tmpl_validate_status_t 2568 include_values_support(ptrn_info_t *pinfo, const char *type, 2569 tmpl_errors_t *errs) 2570 { 2571 error_info_t einfo; 2572 int i; 2573 const char **prefixes; 2574 const char *pfx; 2575 property_t *prop; 2576 pgroup_t *ptrn; 2577 2578 if (strcmp(type, "constraints") == 0) { 2579 prefixes = constraint_prefixes; 2580 } else if (strcmp(type, "values") == 0) { 2581 prefixes = value_prefixes; 2582 } else { 2583 CLEAR_ERROR_INFO(&einfo); 2584 einfo.ei_type = EIT_BAD_TEMPLATE; 2585 einfo.ei_u.ei_bad_template.ei_reason = gettext("include_values " 2586 "type must be \"constraints\" or \"values\""); 2587 (void) tmpl_errors_add_im(errs, TVS_BAD_TEMPLATE, 2588 pinfo->pi_ptrnpg->sc_parent, pinfo->pi_enc_pgp, 2589 NULL, pinfo->pi_ptrnpg, NULL, NULL, &einfo); 2590 return (TVS_BAD_TEMPLATE); 2591 } 2592 2593 /* 2594 * Now see if the prop_pattern has a property whose name starts 2595 * with one of these prefixes. 2596 */ 2597 ptrn = pinfo->pi_ptrnpg; 2598 for (prop = uu_list_first(ptrn->sc_pgroup_props); 2599 prop != NULL; 2600 prop = uu_list_next(ptrn->sc_pgroup_props, prop)) { 2601 for (pfx = prefixes[0], i = 0; 2602 pfx != NULL; 2603 ++i, pfx = prefixes[i]) { 2604 if (strncmp(prop->sc_property_name, pfx, 2605 strlen(pfx)) == 0) { 2606 return (TVS_SUCCESS); 2607 } 2608 } 2609 } 2610 2611 /* No match found. Generate error */ 2612 CLEAR_ERROR_INFO(&einfo); 2613 einfo.ei_type = EIT_INCLUDE_VALUES; 2614 einfo.ei_u.ei_inc_values.ei_type = type; 2615 (void) add_scf_error(errs, SCF_TERR_INCLUDE_VALUES, pinfo->pi_enc_pgp, 2616 NULL, ptrn, NULL, NULL, &einfo); 2617 2618 return (TVS_VALIDATION); 2619 } 2620 2621 /* 2622 * Walk through the prop_patterns in tree, looking for any that have an 2623 * include_values, SCF_PROPERTY_TM_CHOICES_INCLUDE_VALUES, property. For 2624 * the prop_patterns with the include values property, verify that the 2625 * prop_pattern has constraint or values declarations as specified by the 2626 * include_values property. 2627 */ 2628 static tmpl_validate_status_t 2629 tmpl_include_values_check(uu_avl_t *tree, tmpl_errors_t *errs) 2630 { 2631 ptrn_info_t *info; 2632 property_t *iv; 2633 tmpl_validate_status_t r; 2634 tmpl_validate_status_t rc = TVS_SUCCESS; 2635 value_t *v; 2636 2637 for (info = uu_avl_first(tree); 2638 info != NULL; 2639 info = uu_avl_next(tree, info)) { 2640 iv = internal_property_find(info->pi_ptrnpg, 2641 SCF_PROPERTY_TM_CHOICES_INCLUDE_VALUES); 2642 if (iv == NULL) 2643 continue; 2644 for (v = uu_list_first(iv->sc_property_values); 2645 v != NULL; 2646 v = uu_list_next(iv->sc_property_values, v)) { 2647 assert(is_numeric_type(v->sc_type) == 0); 2648 r = include_values_support(info, v->sc_u.sc_string, 2649 errs); 2650 if (r != TVS_SUCCESS) 2651 rc = r; 2652 } 2653 } 2654 return (rc); 2655 } 2656 2657 /* 2658 * Verify that there are no conflicting definitions of pg_pattern or 2659 * prop_pattern. Two patterns are said to be in conflict if they have the 2660 * same name and differing types. There is a caveat, however. Empty 2661 * pattern names or types are considered to be wild cards. There is no 2662 * conflict if a pattern has a wild card. 2663 */ 2664 static tmpl_validate_status_t 2665 tmpl_pattern_conflict(entity_t *inst, uu_avl_t *tree, ptrn_type_t type, 2666 tmpl_errors_t *errs) 2667 { 2668 tmpl_validate_status_t r; 2669 tmpl_validate_status_t rc; 2670 2671 /* First walk the instance. */ 2672 rc = gather_pattern(inst, type, tree, errs); 2673 2674 /* Now walk the service */ 2675 r = gather_pattern(inst->sc_parent, type, tree, errs); 2676 if (r != TVS_SUCCESS) 2677 rc = r; 2678 2679 return (rc); 2680 } 2681 2682 static tmpl_validate_status_t 2683 tmpl_required_attr_present(uu_avl_t *tree, tmpl_errors_t *errs) 2684 { 2685 ptrn_info_t *pinfo; 2686 tmpl_validate_status_t rc = TVS_SUCCESS; 2687 int reported_name; 2688 int rv; 2689 2690 for (pinfo = uu_avl_first(tree); 2691 pinfo != NULL; 2692 pinfo = uu_avl_next(tree, pinfo)) { 2693 if (is_required(pinfo->pi_ptrnpg) == 0) { 2694 /* Nothing to check if pattern is not required. */ 2695 continue; 2696 } 2697 2698 /* 2699 * For pg_pattern both name and type are optional unless 2700 * the required attribute has a value of true. For 2701 * prop_patterns only the type is optional, but it must be 2702 * provided if the required attribute has a value of true. 2703 */ 2704 reported_name = 0; 2705 if ((pinfo->pi_ptrn_type == PG_PATTERN) && 2706 (pinfo->pi_name == NULL)) { 2707 rc = TVS_VALIDATION; 2708 if (add_scf_error(errs, SCF_TERR_PG_PATTERN_INCOMPLETE, 2709 pinfo->pi_ptrnpg, 2710 NULL, NULL, NULL, NULL, NULL) != 0) { 2711 /* 2712 * If we're unable to report errors, break 2713 * out of the loop. 2714 */ 2715 break; 2716 } 2717 /* 2718 * Don't report the error twice if both name and 2719 * type are missing. One error message is 2720 * adequate. 2721 */ 2722 reported_name = 1; 2723 } 2724 if ((pinfo->pi_type == NULL) && (reported_name == 0)) { 2725 rc = TVS_VALIDATION; 2726 if (pinfo->pi_ptrn_type == PG_PATTERN) { 2727 rv = add_scf_error(errs, 2728 SCF_TERR_PG_PATTERN_INCOMPLETE, 2729 pinfo->pi_ptrnpg, 2730 NULL, NULL, NULL, NULL, NULL); 2731 } else { 2732 rv = add_scf_error(errs, 2733 SCF_TERR_PROP_PATTERN_INCOMPLETE, 2734 pinfo->pi_enc_pgp, NULL, pinfo->pi_ptrnpg, 2735 NULL, NULL, NULL); 2736 } 2737 /* If we're unable to log errors, break out of loop. */ 2738 if (rv != 0) 2739 break; 2740 } 2741 } 2742 return (rc); 2743 } 2744 2745 /* 2746 * Look for pg_pattern definitions in general. general is either the 2747 * restarter serivce for inst or it is the global service. tree contains 2748 * the ptrn_info_t structures describing the pg_patterns for an instance. 2749 * For each general pg_pattern, see if the instance contains an overriding 2750 * definition in tree. If it does generate an error entry. 2751 * 2752 * If a redefinition is found, TVS_WARN is returned. This is because a 2753 * redefinition is not sufficient reason to inhibit the import operation. 2754 */ 2755 static tmpl_validate_status_t 2756 tmpl_scan_general(entity_t *general, uu_avl_t *tree, 2757 tmpl_level_t level, tmpl_errors_t *errs) 2758 { 2759 tmpl_level_t cur_level; 2760 error_info_t einfo; 2761 pgroup_t *pg; 2762 ptrn_info_t *ginfo = NULL; 2763 ptrn_info_t *match; 2764 tmpl_validate_status_t rc = TVS_SUCCESS; 2765 2766 /* 2767 * General services may not be in repository yet. It depends on 2768 * the order that manifests are imported. 2769 */ 2770 if (general == NULL) 2771 return (TVS_SUCCESS); 2772 2773 for (pg = uu_list_first(general->sc_pgroups); 2774 pg != NULL; 2775 pg = uu_list_next(general->sc_pgroups, pg)) { 2776 if (strcmp(pg->sc_pgroup_type, 2777 SCF_GROUP_TEMPLATE_PG_PATTERN) != 0) { 2778 /* Not a pg_pattern */ 2779 continue; 2780 } 2781 if (ginfo != NULL) 2782 ptrn_info_destroy(ginfo); 2783 ginfo = ptrn_info_create(pg); 2784 match = uu_avl_find(tree, ginfo, NULL, NULL); 2785 if (match != NULL) { 2786 /* See if global pg_pattern is targeted at us. */ 2787 if (target_check(ginfo->pi_target, level) == 0) 2788 continue; 2789 2790 /* 2791 * See if the match applies to us. If we happen to 2792 * be a restarter, the pg_pattern could have a 2793 * target of delegate. That wouldn't apply to this 2794 * instance, it would only apply to our delegates. 2795 * Cases such as this are not a redefinition. 2796 */ 2797 if (match->pi_ptrnpg->sc_parent->sc_etype == 2798 SVCCFG_INSTANCE_OBJECT) { 2799 cur_level = TL_INSTANCE; 2800 } else { 2801 cur_level = TL_SERVICE; 2802 } 2803 if (target_check(match->pi_target, cur_level) == 0) 2804 continue; 2805 2806 /* 2807 * Instance or service overrides a general 2808 * definition. We need to issue a warning message. 2809 */ 2810 rc = TVS_WARN; 2811 CLEAR_ERROR_INFO(&einfo); 2812 einfo.ei_type = EIT_PATTERN_CONFLICT; 2813 einfo.ei_u.ei_pattern_conflict.ei_pattern = pg; 2814 if (add_scf_error(errs, SCF_TERR_GENERAL_REDEFINE, 2815 match->pi_ptrnpg, NULL, NULL, NULL, NULL, 2816 &einfo) != 0) { 2817 /* 2818 * No need to continue the search if we 2819 * cannot record errors. 2820 */ 2821 break; 2822 } 2823 } 2824 } 2825 2826 if (ginfo != NULL) 2827 ptrn_info_destroy(ginfo); 2828 return (rc); 2829 } 2830 2831 /* 2832 * tree contains the pg_pattern definitions for the instance at inst. See 2833 * if these pg_patterns redefine any pg_patterns in the instance's 2834 * restarter or in the global service. TVS_WARN is returned if a 2835 * redefinition is encountered. 2836 */ 2837 static tmpl_validate_status_t 2838 tmpl_level_redefine(entity_t *inst, uu_avl_t *tree, tmpl_errors_t *errs) 2839 { 2840 entity_t *restarter; 2841 entity_t *svc = inst->sc_parent; 2842 tmpl_validate_status_t r; 2843 tmpl_validate_status_t rc; 2844 2845 restarter = inst->sc_u.sc_instance.sc_instance_restarter; 2846 if (restarter == NULL) { 2847 /* No instance restarter. Use the service restarter */ 2848 restarter = svc->sc_u.sc_service.sc_restarter; 2849 } 2850 rc = tmpl_scan_general(restarter, tree, TL_RESTARTER, errs); 2851 r = tmpl_scan_general(svc->sc_u.sc_service.sc_global, tree, 2852 TL_GLOBAL, errs); 2853 if (r != TVS_SUCCESS) 2854 rc = r; 2855 return (rc); 2856 } 2857 2858 /* 2859 * Perform the following consistency checks on the template specifications 2860 * themselves: 2861 * 2862 * - No conflicting definitions of `pg_pattern` are allowed within a 2863 * single instance. 2864 * 2865 * - Templates at a narrow target (e.g. instance) which define 2866 * property groups already templated at a broad target 2867 * (e.g. restarter or all) are strongly discouraged. 2868 * 2869 * - Developers may not define a template which specifies a single 2870 * prop_pattern name with differing types on the same target 2871 * entity. 2872 * 2873 * - If a pg_pattern has a required attribute with a value of true, 2874 * then its name and type attributes must be specified. 2875 * 2876 * - If a prop_pattern has a required attribute with a value of true, 2877 * then its type attribute must be specified. 2878 * 2879 * - If a prop_pattern has an include values make sure that the 2880 * appropriate constraints or values element has also been 2881 * declared. 2882 */ 2883 static tmpl_validate_status_t 2884 tmpl_consistency(entity_t *inst, tmpl_errors_t *errs) 2885 { 2886 void *marker = NULL; 2887 ptrn_info_t *info; 2888 uu_avl_t *tree; 2889 tmpl_validate_status_t rc; 2890 tmpl_validate_status_t r; 2891 2892 /* Allocate the tree. */ 2893 tree = uu_avl_create(ptrn_info_pool, NULL, TMPL_DEBUG_TREE); 2894 if (tree == NULL) { 2895 uu_die(gettext("pg_info tree creation failed: %s\n"), 2896 uu_strerror(uu_error())); 2897 } 2898 2899 rc = tmpl_pattern_conflict(inst, tree, PG_PATTERN, errs); 2900 2901 /* 2902 * The tree now contains the instance and service pg_patterns. 2903 * Check to see if they override any pg_pattern definitions in the 2904 * restarter and global services. 2905 */ 2906 r = tmpl_level_redefine(inst, tree, errs); 2907 if (r != TVS_SUCCESS) { 2908 /* 2909 * tmpl_level_redefine() can return a warning. Don't 2910 * override a serious error with a warning. 2911 */ 2912 if (r == TVS_WARN) { 2913 if (rc == TVS_SUCCESS) 2914 rc = r; 2915 } else { 2916 rc = r; 2917 } 2918 } 2919 2920 /* 2921 * If the pg_pattern has a required attribute with a value of true, 2922 * then it must also have name and type attributes. 2923 */ 2924 r = tmpl_required_attr_present(tree, errs); 2925 if (r != TVS_SUCCESS) 2926 rc = r; 2927 2928 /* Empty the tree, so that we can reuse it for prop_patterns. */ 2929 while ((info = uu_avl_teardown(tree, &marker)) != NULL) { 2930 ptrn_info_destroy(info); 2931 } 2932 2933 r = tmpl_pattern_conflict(inst, tree, PROP_PATTERN, errs); 2934 if (r != TVS_SUCCESS) 2935 rc = r; 2936 2937 /* 2938 * If a prop_pattern has required attribute with a value of true, 2939 * then it must also have a type attribute. 2940 */ 2941 r = tmpl_required_attr_present(tree, errs); 2942 if (r != TVS_SUCCESS) 2943 rc = r; 2944 2945 /* 2946 * Insure that include_values have the constraint for values 2947 * elements that are needed. 2948 */ 2949 r = tmpl_include_values_check(tree, errs); 2950 if (r != TVS_SUCCESS) 2951 rc = r; 2952 2953 /* Tear down the tree. */ 2954 marker = NULL; 2955 while ((info = uu_avl_teardown(tree, &marker)) != NULL) { 2956 ptrn_info_destroy(info); 2957 } 2958 uu_avl_destroy(tree); 2959 2960 return (rc); 2961 } 2962 2963 /* 2964 * Release memory associated with the tmpl_errors structure and then free 2965 * the structure itself. 2966 */ 2967 void 2968 tmpl_errors_destroy(tmpl_errors_t *te) 2969 { 2970 im_tmpl_error_t *ite; 2971 tv_errors_t *ste; 2972 void *marker = NULL; 2973 2974 if (te == NULL) 2975 return; 2976 if (te->te_list) { 2977 while ((ite = uu_list_teardown(te->te_list, &marker)) != NULL) { 2978 uu_list_node_fini(ite, &ite->ite_node, 2979 inmem_errors_pool); 2980 uu_free(ite); 2981 } 2982 uu_list_destroy(te->te_list); 2983 } 2984 if (te->te_scf) { 2985 marker = NULL; 2986 while ((ste = uu_list_teardown(te->te_scf, &marker)) != NULL) { 2987 destroy_scf_errors(ste); 2988 } 2989 uu_list_destroy(te->te_scf); 2990 } 2991 uu_free(te); 2992 } 2993 2994 /* 2995 * Allocate and initialize a tmpl_errors structure. The address of the 2996 * structure is returned, unless we are unable to allocate enough memory. 2997 * In the case of memory allocation failures, NULL is returned. 2998 * 2999 * The allocated structure should be freed by calling 3000 * tmpl_errors_destroy(). 3001 */ 3002 static tmpl_errors_t * 3003 tmpl_errors_create() 3004 { 3005 tmpl_errors_t *te; 3006 3007 te = uu_zalloc(sizeof (*te)); 3008 if (te == NULL) 3009 return (NULL); 3010 te->te_list = uu_list_create(inmem_errors_pool, NULL, TMPL_DEBUG_LIST); 3011 if (te->te_list == NULL) { 3012 uu_free(te); 3013 return (NULL); 3014 } 3015 te->te_scf = uu_list_create(tv_errors_pool, NULL, TMPL_DEBUG_LIST); 3016 if (te->te_scf == NULL) { 3017 tmpl_errors_destroy(te); 3018 return (NULL); 3019 } 3020 3021 return (te); 3022 } 3023 3024 void 3025 tmpl_errors_print(FILE *out, tmpl_errors_t *errs, const char *prefix) 3026 { 3027 scf_tmpl_error_t *cur; 3028 size_t buf_size = 4096; 3029 im_tmpl_error_t *ite; 3030 char *s = NULL; 3031 scf_tmpl_errors_t *scferrs; 3032 tv_errors_t *scft; 3033 int interactive = (est->sc_cmd_flags & SC_CMD_IACTIVE) ? 3034 SCF_TMPL_STRERROR_HUMAN : 0; 3035 3036 for (ite = uu_list_first(errs->te_list); 3037 ite != NULL; 3038 ite = uu_list_next(errs->te_list, ite)) { 3039 im_tmpl_error_print(out, ite, prefix); 3040 } 3041 3042 /* Now handle the errors that can be printed via libscf. */ 3043 s = safe_malloc(buf_size); 3044 for (scft = uu_list_first(errs->te_scf); 3045 scft != NULL; 3046 scft = uu_list_next(errs->te_scf, scft)) { 3047 scferrs = scft->tve_errors; 3048 if (_scf_tmpl_error_set_prefix(scferrs, prefix) != 0) 3049 uu_die(emesg_nomem); 3050 while ((cur = scf_tmpl_next_error(scferrs)) != NULL) { 3051 (void) scf_tmpl_strerror(cur, s, buf_size, interactive); 3052 (void) fputs(s, out); 3053 (void) fputc('\n', out); 3054 } 3055 } 3056 3057 free(s); 3058 } 3059 3060 /* 3061 * This function finds the prop_pattern for the property, prop. e is the 3062 * instance where the search for the prop_pattern will start. pg_pattern 3063 * is the address of the pg_pattern that holds the prop_pattern. 3064 */ 3065 static tmpl_validate_status_t 3066 tmpl_find_prop_pattern(entity_t *inst, pgroup_t *pg_pattern, 3067 property_t *prop, pgroup_t **prop_pattern) 3068 { 3069 pgroup_t *candidate; 3070 pg_iter_t *iter = NULL; 3071 char *prop_pattern_name = NULL; 3072 tmpl_validate_status_t rc; 3073 3074 /* 3075 * Get the name of the property group that holds the prop_pattern 3076 * definition. 3077 */ 3078 rc = gen_prop_pattern_pg_name(pg_pattern, 3079 prop->sc_property_name, &prop_pattern_name); 3080 if (rc != TVS_SUCCESS) 3081 goto out; 3082 3083 /* Find the property group. */ 3084 iter = pg_iter_create(inst, SCF_GROUP_TEMPLATE_PROP_PATTERN); 3085 if (iter == NULL) 3086 goto out; 3087 while ((candidate = next_pattern_pg(iter)) != NULL) { 3088 const char *c; 3089 3090 if (strcmp(prop_pattern_name, candidate->sc_pgroup_name) != 0) 3091 continue; 3092 c = find_astring_value_in_pg(candidate, 3093 SCF_PROPERTY_TM_PG_PATTERN); 3094 if (c == NULL) 3095 continue; 3096 if (strcmp(pg_pattern->sc_pgroup_name, c) == 0) 3097 break; 3098 } 3099 *prop_pattern = candidate; 3100 if (candidate == NULL) 3101 rc = TVS_NOMATCH; 3102 3103 out: 3104 pg_iter_destroy(iter); 3105 uu_free((void *)prop_pattern_name); 3106 return (rc); 3107 } 3108 3109 /* 3110 * Indexes for pg_pattern property group names. Indexes are arranged 3111 * from most specific to least specific. 3112 */ 3113 #define PGN_BOTH 0 /* both name and type */ 3114 #define PGN_NAME 1 /* name only */ 3115 #define PGN_TYPE 2 /* type only */ 3116 #define PGN_NEITHER 3 /* neither name nor type */ 3117 #define PGN_MAX 4 /* Size of array */ 3118 3119 /* 3120 * Given an instance entity, e, and a propety group, pg, within the 3121 * instance; return the address of the pg_pattern for the property group. 3122 * The address of the pg_pattern is placed at pgp. NULL indicates that no 3123 * pg_pattern was specified. 3124 */ 3125 static tmpl_validate_status_t 3126 tmpl_find_pg_pattern(entity_t *e, pgroup_t *pg, pgroup_t **pgp) 3127 { 3128 pgroup_t *cpg; /* candidate property group */ 3129 int i; 3130 pg_iter_t *iter = NULL; 3131 char *pg_names[PGN_MAX]; 3132 pgroup_t *pg_patterns[PGN_MAX]; 3133 tmpl_validate_status_t rv = TVS_SUCCESS; 3134 3135 (void) memset(pg_patterns, 0, sizeof (pg_patterns)); 3136 *pgp = NULL; 3137 3138 /* Generate candidate names for pg_pattern property groups. */ 3139 pg_names[PGN_BOTH] = gen_pg_pattern_pg_name(pg->sc_pgroup_name, 3140 pg->sc_pgroup_type); 3141 pg_names[PGN_NAME] = gen_pg_pattern_pg_name(pg->sc_pgroup_name, 3142 NULL); 3143 pg_names[PGN_TYPE] = gen_pg_pattern_pg_name(NULL, 3144 pg->sc_pgroup_type); 3145 pg_names[PGN_NEITHER] = gen_pg_pattern_pg_name(NULL, NULL); 3146 for (i = 0; i < PGN_MAX; i++) { 3147 if (pg_names[i] == NULL) { 3148 rv = TVS_BAD_TEMPLATE; 3149 goto errout; 3150 } 3151 } 3152 3153 /* Search for property groups that match these names */ 3154 iter = pg_iter_create(e, SCF_GROUP_TEMPLATE_PG_PATTERN); 3155 if (iter == NULL) { 3156 uu_die(emesg_nomem); 3157 } 3158 while ((cpg = next_pattern_pg(iter)) != NULL) { 3159 if (pg_target_check(cpg, iter->pgi_level) == 0) 3160 continue; 3161 3162 /* See if we have a name match. */ 3163 for (i = 0; i < PGN_MAX; i++) { 3164 if (strcmp(cpg->sc_pgroup_name, pg_names[i]) == 0) { 3165 /* 3166 * If we already have a lower level 3167 * pg_pattern, keep it. 3168 */ 3169 if (pg_patterns[i] == NULL) 3170 pg_patterns[i] = cpg; 3171 break; 3172 } 3173 } 3174 } 3175 3176 /* Find the most specific pg_pattern. */ 3177 for (i = 0; i < PGN_MAX; i++) { 3178 if (pg_patterns[i] != NULL) { 3179 *pgp = pg_patterns[i]; 3180 break; 3181 } 3182 } 3183 errout: 3184 for (i = 0; i < PGN_MAX; i++) { 3185 free(pg_names[i]); 3186 } 3187 pg_iter_destroy(iter); 3188 return (rv); 3189 } 3190 3191 /* 3192 * Initialize structures that are required for validation using 3193 * templates specifications. 3194 */ 3195 void 3196 tmpl_init(void) 3197 { 3198 emesg_nomem = gettext("Out of memory.\n"); 3199 3200 composed_pg_pool = uu_avl_pool_create("composed_pg", 3201 sizeof (composed_pg_t), offsetof(composed_pg_t, cpg_node), 3202 composed_pg_compare, TMPL_DEBUG_AVL_POOL); 3203 if (composed_pg_pool == NULL) { 3204 uu_die(gettext("composed_pg pool creation failed: %s\n"), 3205 uu_strerror(uu_error())); 3206 } 3207 composed_prop_pool = uu_avl_pool_create("composed_prop", 3208 sizeof (property_t), offsetof(property_t, sc_composed_node), 3209 composed_prop_compare, TMPL_DEBUG_AVL_POOL); 3210 if (composed_prop_pool == NULL) { 3211 uu_die(gettext("composed_prop pool creation failed. %s\n"), 3212 uu_strerror(uu_error())); 3213 } 3214 ptrn_info_pool = uu_avl_pool_create("ptrn_info", sizeof (ptrn_info_t), 3215 offsetof(ptrn_info_t, pi_link), ptrn_info_compare, 3216 TMPL_DEBUG_AVL_POOL); 3217 if (ptrn_info_pool == NULL) { 3218 uu_die(gettext("pg_pattern info pool creation failed: %s\n"), 3219 uu_strerror(uu_error())); 3220 } 3221 inmem_errors_pool = uu_list_pool_create("errors-internal", 3222 sizeof (im_tmpl_error_t), offsetof(im_tmpl_error_t, 3223 ite_node), NULL, TMPL_DEBUG_LIST_POOL); 3224 if (inmem_errors_pool == NULL) { 3225 uu_die(gettext("inmem_errors_pool pool creation failed: " 3226 "%s\n"), uu_strerror(uu_error())); 3227 } 3228 tv_errors_pool = uu_list_pool_create("scf-terrors", 3229 sizeof (tv_errors_t), offsetof(tv_errors_t, tve_node), 3230 NULL, TMPL_DEBUG_LIST_POOL); 3231 if (tv_errors_pool == NULL) { 3232 uu_die(gettext("tv_errors_pool pool creation failed: %s\n"), 3233 uu_strerror(uu_error())); 3234 } 3235 } 3236 3237 /* 3238 * Clean up the composed property node in the property. 3239 */ 3240 void 3241 tmpl_property_fini(property_t *p) 3242 { 3243 uu_avl_node_fini(p, &p->sc_composed_node, composed_prop_pool); 3244 } 3245 3246 /* 3247 * Initialize the composed property node in the property. 3248 */ 3249 void 3250 tmpl_property_init(property_t *p) 3251 { 3252 uu_avl_node_init(p, &p->sc_composed_node, composed_prop_pool); 3253 } 3254 3255 /* 3256 * Use the cardinality specification in the prop_pattern to verify the 3257 * cardinality of the property at prop. The cardinality of the property is 3258 * the number of values that it has. 3259 * 3260 * pg is the property group that holds prop, and pg_pattern is the 3261 * pg_pattern for the property group. pg and pg_pattern are only used for 3262 * error reporting. 3263 */ 3264 static tmpl_validate_status_t 3265 tmpl_validate_cardinality(pgroup_t *prop_pattern, property_t *prop, 3266 pgroup_t *pg, pgroup_t *pg_pattern, tmpl_errors_t *errs) 3267 { 3268 size_t count; 3269 uint64_t max; 3270 uint64_t min; 3271 tmpl_validate_status_t rc; 3272 error_info_t einfo; 3273 3274 assert(strcmp(prop_pattern->sc_pgroup_type, 3275 SCF_GROUP_TEMPLATE_PROP_PATTERN) == 0); 3276 3277 rc = get_cardinality(prop_pattern, &min, &max); 3278 switch (rc) { 3279 case TVS_NOMATCH: 3280 /* Nothing to check. */ 3281 return (TVS_SUCCESS); 3282 case TVS_SUCCESS: 3283 /* Process the limits. */ 3284 break; 3285 default: 3286 return (rc); 3287 } 3288 3289 if ((min == 0) && (max == ULLONG_MAX)) { 3290 /* Any number of values is permitted. No need to count. */ 3291 return (TVS_SUCCESS); 3292 } 3293 3294 count = count_prop_values(prop); 3295 if ((count < min) || (count > max)) { 3296 CLEAR_ERROR_INFO(&einfo); 3297 einfo.ei_type = EIT_CARDINALITY; 3298 einfo.ei_u.ei_cardinality.ei_min = min; 3299 einfo.ei_u.ei_cardinality.ei_max = max; 3300 einfo.ei_u.ei_cardinality.ei_count = count; 3301 (void) add_scf_error(errs, SCF_TERR_CARDINALITY_VIOLATION, 3302 pg_pattern, pg, prop_pattern, prop, NULL, &einfo); 3303 return (TVS_VALIDATION); 3304 } 3305 3306 return (TVS_SUCCESS); 3307 } 3308 3309 /* 3310 * Iterate over pg_patterns in the entity, e. If the pg_pattern's required 3311 * attribute is true, verify that the entity contains the corresponding 3312 * property group. 3313 */ 3314 static tmpl_validate_status_t 3315 tmpl_required_pg_present(entity_t *e, tmpl_errors_t *errs) 3316 { 3317 composed_pg_t cpg; 3318 composed_pg_t *match; 3319 error_info_t einfo; 3320 pg_iter_t *iter; 3321 pgroup_t *pg; 3322 const char *pg_name; 3323 const char *pg_type; 3324 tmpl_validate_status_t rc = TVS_SUCCESS; 3325 uu_avl_t *tree; 3326 3327 assert(e->sc_etype == SVCCFG_INSTANCE_OBJECT); 3328 3329 iter = pg_iter_create(e, SCF_GROUP_TEMPLATE_PG_PATTERN); 3330 if (iter == NULL) 3331 uu_die(emesg_nomem); 3332 3333 CLEAR_ERROR_INFO(&einfo); 3334 einfo.ei_type = EIT_MISSING_PG; 3335 3336 while ((pg = next_pattern_pg(iter)) != NULL) { 3337 if (is_required(pg) == 0) { 3338 /* If pg is not required, there is nothing to check. */ 3339 continue; 3340 } 3341 pg_name = find_astring_value_in_pg(pg, SCF_PROPERTY_TM_NAME); 3342 pg_type = find_astring_value_in_pg(pg, SCF_PROPERTY_TM_TYPE); 3343 if (pg_target_check(pg, iter->pgi_level) == 0) 3344 continue; 3345 einfo.ei_u.ei_missing_pg.ei_pg_name = pg_name; 3346 einfo.ei_u.ei_missing_pg.ei_pg_type = pg_type; 3347 tree = e->sc_u.sc_instance.sc_composed; 3348 (void) memset(&cpg, 0, sizeof (cpg)); 3349 cpg.cpg_name = pg_name; 3350 cpg.cpg_type = pg_type; 3351 match = uu_avl_find(tree, &cpg, NULL, NULL); 3352 if (match == NULL) { 3353 rc = TVS_VALIDATION; 3354 if (add_scf_error(errs, SCF_TERR_MISSING_PG, pg, 3355 NULL, NULL, NULL, NULL, &einfo) != 0) { 3356 break; 3357 } 3358 } 3359 } 3360 3361 pg_iter_destroy(iter); 3362 return (rc); 3363 } 3364 3365 /* 3366 * Verify that the property group, pg, contains property declarations for 3367 * all required properties. Unfortunately, there is no direct way to find 3368 * the prop_patterns for a given property group. Therefore, we need to 3369 * scan the entity at e looking for property groups with a type of 3370 * SCF_GROUP_TEMPLATE_PROP_PATTERN. That is, we scan the entity looking 3371 * for all prop_patterns. When we find a prop_pattern, we look at the 3372 * value of its pg_pattern property to see if it matches the name of the 3373 * pg_pattern. If they match, this is a prop_pattern that is of interest 3374 * to us. 3375 * 3376 * When we find an interesting prop_pattern, we see if it's required 3377 * property is true. If it is, we verify that the property group at pg 3378 * contains the specified property. 3379 */ 3380 static tmpl_validate_status_t 3381 tmpl_required_props_present(entity_t *e, pgroup_t *pg, pgroup_t *pg_pattern, 3382 tmpl_errors_t *errs) 3383 { 3384 error_info_t einfo; 3385 pg_iter_t *iter; 3386 const char *prop_name; 3387 const char *prop_pg_pattern_name; 3388 pgroup_t *prop_pattern; 3389 scf_tmpl_error_type_t ec; 3390 tmpl_validate_status_t rc = TVS_SUCCESS; 3391 3392 /* 3393 * Scan the entity's property groups looking for ones with a type 3394 * of SCF_GROUP_TEMPLATE_PROP_PATTERN. 3395 */ 3396 iter = pg_iter_create(e, SCF_GROUP_TEMPLATE_PROP_PATTERN); 3397 if (iter == NULL) 3398 uu_die(emesg_nomem); 3399 CLEAR_ERROR_INFO(&einfo); 3400 for (prop_pattern = next_pattern_pg(iter); 3401 prop_pattern != NULL; 3402 prop_pattern = next_pattern_pg(iter)) { 3403 /* 3404 * Find the pg_pattern property in this prop_pattern. 3405 * Verify that its value matches the name of the 3406 * pg_pattern. 3407 */ 3408 prop_pg_pattern_name = find_astring_value_in_pg(prop_pattern, 3409 SCF_PROPERTY_TM_PG_PATTERN); 3410 assert(prop_pg_pattern_name != NULL); 3411 if (strcmp(pg_pattern->sc_pgroup_name, 3412 prop_pg_pattern_name) != 0) { 3413 continue; 3414 } 3415 3416 /* If the property is required, see if it is in the pg. */ 3417 if (is_required(prop_pattern) == 0) 3418 continue; 3419 prop_name = find_astring_value_in_pg(prop_pattern, 3420 SCF_PROPERTY_TM_NAME); 3421 assert(prop_name != NULL); 3422 if (property_find(pg, prop_name) == NULL) { 3423 ec = SCF_TERR_MISSING_PROP; 3424 rc = TVS_VALIDATION; 3425 einfo.ei_type = EIT_MISSING_PROP; 3426 einfo.ei_u.ei_missing_prop.ei_prop_name = prop_name; 3427 if (add_scf_error(errs, ec, pg_pattern, pg, 3428 prop_pattern, NULL, NULL, &einfo) != 0) { 3429 /* 3430 * If we can no longer accumulate errors, 3431 * break out of the loop. 3432 */ 3433 break; 3434 } 3435 } 3436 } 3437 3438 pg_iter_destroy(iter); 3439 return (rc); 3440 } 3441 3442 /* 3443 * Check the value at v to see if it falls within any of the ranges at r. 3444 * count is the number of ranges at r, and type tells whether to treat the 3445 * value as signed or unsigned. 3446 * 3447 * Return 1 if the value falls within one of the ranges. Otherwise return 3448 * 0. 3449 */ 3450 static int 3451 value_in_range(value_t *v, scf_type_t type, range_t *r, size_t count) 3452 { 3453 for (; count > 0; --count, r++) { 3454 if (type == SCF_TYPE_COUNT) { 3455 if ((v->sc_u.sc_count >= 3456 r->rng_u.rng_unsigned.rng_min) && 3457 (v->sc_u.sc_count <= 3458 r->rng_u.rng_unsigned.rng_max)) 3459 return (1); 3460 } else { 3461 if ((v->sc_u.sc_integer >= 3462 r->rng_u.rng_signed.rng_min) && 3463 (v->sc_u.sc_integer <= 3464 r->rng_u.rng_signed.rng_max)) 3465 return (1); 3466 } 3467 } 3468 return (0); 3469 } 3470 3471 /* 3472 * If the template prop_pattern at pattern contains a constraint_range 3473 * property, use the specified range to validate all the numeric property 3474 * values of the property at prop. 3475 * 3476 * pg is the property group that holds prop, and pg_pattern is the 3477 * pg_pattern for the property group. pg and pg_pattern are only used for 3478 * error reporting. 3479 */ 3480 static tmpl_validate_status_t 3481 tmpl_validate_value_range(pgroup_t *pattern, property_t *prop, pgroup_t *pg, 3482 pgroup_t *pg_pattern, tmpl_errors_t *errs) 3483 { 3484 uint_t count; 3485 error_info_t einfo; 3486 property_t *range_prop; 3487 range_t *ranges; 3488 tmpl_validate_status_t rc; 3489 scf_type_t type; 3490 value_t *v; 3491 3492 /* Get the range constraints if they exist. */ 3493 if ((range_prop = property_find(pattern, 3494 SCF_PROPERTY_TM_CONSTRAINT_RANGE)) == NULL) { 3495 /* No range to check. */ 3496 return (TVS_SUCCESS); 3497 } 3498 type = prop->sc_value_type; 3499 if ((type != SCF_TYPE_COUNT) && (type != SCF_TYPE_INTEGER)) { 3500 rc = TVS_BAD_TEMPLATE; 3501 CLEAR_ERROR_INFO(&einfo); 3502 einfo.ei_type = EIT_BAD_TEMPLATE; 3503 einfo.ei_u.ei_bad_template.ei_reason = 3504 gettext("Property does not have correct type for " 3505 "a range specification"); 3506 (void) tmpl_errors_add_im(errs, rc, pg_pattern->sc_parent, 3507 pg_pattern, pg, pattern, prop, NULL, &einfo); 3508 return (rc); 3509 } 3510 if ((rc = get_ranges(range_prop, prop->sc_value_type, &ranges, 3511 &count)) != TVS_SUCCESS) { 3512 rc = TVS_BAD_TEMPLATE; 3513 CLEAR_ERROR_INFO(&einfo); 3514 einfo.ei_type = EIT_BAD_TEMPLATE; 3515 einfo.ei_u.ei_bad_template.ei_reason = gettext("Illegal range " 3516 "value"); 3517 (void) tmpl_errors_add_im(errs, rc, pg_pattern->sc_parent, 3518 pg_pattern, pg, pattern, prop, NULL, &einfo); 3519 return (rc); 3520 } 3521 3522 /* Set up error info before entering loop. */ 3523 CLEAR_ERROR_INFO(&einfo); 3524 einfo.ei_type = EIT_RANGE; 3525 einfo.ei_u.ei_range.ei_rtype = type; 3526 3527 /* Compare numeric values of the property to the range. */ 3528 for (v = uu_list_first(prop->sc_property_values); 3529 v != NULL; 3530 v = uu_list_next(prop->sc_property_values, v)) { 3531 if (value_in_range(v, type, ranges, count) == 1) 3532 continue; 3533 if (type == SCF_TYPE_COUNT) { 3534 einfo.ei_u.ei_range.ei_uvalue = v->sc_u.sc_count; 3535 } else { 3536 einfo.ei_u.ei_range.ei_ivalue = v->sc_u.sc_integer; 3537 } 3538 rc = TVS_VALIDATION; 3539 if (add_scf_error(errs, SCF_TERR_RANGE_VIOLATION, pg_pattern, 3540 pg, pattern, prop, v, &einfo) != 0) { 3541 return (rc); 3542 } 3543 } 3544 3545 return (rc); 3546 } 3547 3548 /* 3549 * If the prop_pattern has value constraints, verify that all the values 3550 * for the property at prop are legal values. 3551 * 3552 * pg is the property group that holds prop, and pg_pattern is the 3553 * pg_pattern for the property group. pg and pg_pattern are only used for 3554 * error reporting. 3555 */ 3556 static tmpl_validate_status_t 3557 tmpl_validate_values(pgroup_t *prop_pattern, property_t *prop, pgroup_t *pg, 3558 pgroup_t *pg_pattern, tmpl_errors_t *errs) 3559 { 3560 int found; 3561 uint_t i; 3562 avalues_t *legal; 3563 tmpl_validate_status_t r; 3564 tmpl_validate_status_t rc = TVS_SUCCESS; 3565 value_t *v; 3566 3567 /* Get list of legal values. */ 3568 r = av_get_values(prop_pattern, SCF_PROPERTY_TM_CONSTRAINT_NAME, 3569 prop->sc_value_type, &legal); 3570 switch (r) { 3571 case TVS_BAD_CONVERSION: 3572 (void) tmpl_errors_add_im(errs, r, pg->sc_parent, pg_pattern, 3573 pg, prop_pattern, prop, NULL, NULL); 3574 return (r); 3575 case TVS_NOMATCH: 3576 /* No constraints in template. */ 3577 return (TVS_SUCCESS); 3578 case TVS_SUCCESS: 3579 /* process the constraints. */ 3580 break; 3581 default: 3582 assert(0); 3583 abort(); 3584 } 3585 3586 /* Check the property values against the legal values. */ 3587 for (v = uu_list_first(prop->sc_property_values); 3588 v != NULL; 3589 v = uu_list_next(prop->sc_property_values, v)) { 3590 /* Check this property value against the legal values. */ 3591 found = 0; 3592 for (i = 0; (i < legal->av_count) && (found == 0); i++) { 3593 switch (v->sc_type) { 3594 case SCF_TYPE_BOOLEAN: 3595 case SCF_TYPE_COUNT: 3596 if (av_get_unsigned(legal, i) == 3597 v->sc_u.sc_count) { 3598 found = 1; 3599 } 3600 break; 3601 case SCF_TYPE_INTEGER: 3602 if (av_get_integer(legal, i) == 3603 v->sc_u.sc_integer) { 3604 found = 1; 3605 } 3606 break; 3607 default: 3608 if (strcmp(av_get_string(legal, i), 3609 v->sc_u.sc_string) == 0) { 3610 found = 1; 3611 } 3612 break; 3613 } 3614 } 3615 if (found == 0) { 3616 rc = TVS_VALIDATION; 3617 if (add_scf_error(errs, 3618 SCF_TERR_VALUE_CONSTRAINT_VIOLATED, pg_pattern, pg, 3619 prop_pattern, prop, v, NULL) != 0) { 3620 /* 3621 * Exit loop if no longer able to report 3622 * errors. 3623 */ 3624 break; 3625 } 3626 } 3627 } 3628 3629 out: 3630 av_destroy(legal); 3631 return (rc); 3632 } 3633 3634 /* 3635 * Verify the following items about the values of property, prop. 3636 * 3637 * - The values all have the type specified by the prop_pattern at 3638 * pattern. 3639 * - Check numeric values against range constraints. 3640 * - If the prop_pattern has one or more value constraints, validate 3641 * the property's values against the constraints. 3642 * 3643 * pg is the property group that holds prop, and pg_pattern is the 3644 * pg_pattern for the property group. pg and pg_pattern are only used for 3645 * error reporting. 3646 */ 3647 static tmpl_validate_status_t 3648 tmpl_validate_value_constraints(pgroup_t *pattern, property_t *prop, 3649 pgroup_t *pg, pgroup_t *pg_pattern, tmpl_errors_t *errs) 3650 { 3651 tmpl_validate_status_t r; 3652 tmpl_validate_status_t rc; 3653 3654 rc = tmpl_validate_value_range(pattern, prop, pg, pg_pattern, errs); 3655 r = tmpl_validate_values(pattern, prop, pg, pg_pattern, errs); 3656 if (r != TVS_SUCCESS) 3657 rc = r; 3658 3659 return (rc); 3660 } 3661 3662 /* 3663 * Perform the following validations on the property, prop. 3664 * 3665 * - Verify that the property's type agrees with the type specified in 3666 * the prop_pattern template, tmpl. 3667 * - Verify the cardinality. 3668 * - Verify that the property values satisfy the constraints specified 3669 * by the template. 3670 * 3671 * pg is the property group that holds prop, and pg_pattern is the 3672 * pg_pattern for the property group. pg and pg_pattern are only used for 3673 * error reporting. 3674 */ 3675 static tmpl_validate_status_t 3676 tmpl_validate_prop(property_t *prop, pgroup_t *tmpl, pgroup_t *pg, 3677 pgroup_t *pg_pattern, tmpl_errors_t *errs) 3678 { 3679 scf_tmpl_error_type_t ec; 3680 error_info_t einfo; 3681 tmpl_validate_status_t r; 3682 tmpl_validate_status_t rc = TVS_SUCCESS; 3683 int status; 3684 scf_type_t type; 3685 3686 r = prop_pattern_type(tmpl, &type); 3687 switch (r) { 3688 case TVS_SUCCESS: 3689 if (type == SCF_TYPE_INVALID) { 3690 rc = TVS_INVALID_TYPE_SPECIFICATION; 3691 r = tmpl_errors_add_im(errs, rc, pg->sc_parent, NULL, 3692 pg, tmpl, NULL, NULL, NULL); 3693 if (r != TVS_SUCCESS) { 3694 /* 3695 * Give up if we can no longer accumulate 3696 * errors. 3697 */ 3698 return (rc); 3699 } 3700 } else { 3701 if (property_is_type(prop, type) == 0) { 3702 CLEAR_ERROR_INFO(&einfo); 3703 rc = TVS_VALIDATION; 3704 ec = SCF_TERR_WRONG_PROP_TYPE; 3705 einfo.ei_type = EIT_PROP_TYPE; 3706 einfo.ei_u.ei_prop_type.ei_specified = type; 3707 einfo.ei_u.ei_prop_type.ei_actual = 3708 prop->sc_value_type; 3709 status = add_scf_error(errs, ec, 3710 pg_pattern, pg, tmpl, prop, NULL, &einfo); 3711 if (status != 0) { 3712 /* 3713 * Give up if we can no longer 3714 * accumulate errors. 3715 */ 3716 return (rc); 3717 } 3718 } 3719 } 3720 break; 3721 case TVS_MISSING_TYPE_SPECIFICATION: 3722 /* 3723 * A null type specification means that we do not need to 3724 * check the property's type. 3725 */ 3726 break; 3727 default: 3728 rc = r; 3729 } 3730 3731 /* Validate the cardinality */ 3732 r = tmpl_validate_cardinality(tmpl, prop, pg, pg_pattern, errs); 3733 if (r != TVS_SUCCESS) 3734 rc = r; 3735 3736 /* Validate that property values satisfy constraints. */ 3737 r = tmpl_validate_value_constraints(tmpl, prop, pg, pg_pattern, errs); 3738 if (r != TVS_SUCCESS) 3739 rc = r; 3740 3741 return (rc); 3742 } 3743 3744 /* 3745 * Validate the property group at pg by performing the following checks: 3746 * 3747 * - Verify that the types of the pg and the pg_pattern are 3748 * compatible. 3749 * - Verify the properties in the pg. 3750 * - Verify that required properties are present. 3751 */ 3752 static tmpl_validate_status_t 3753 tmpl_validate_pg(entity_t *e, pgroup_t *pg, tmpl_errors_t *errs) 3754 { 3755 error_info_t einfo; 3756 const char *pg_pattern_type; /* Type declared by pg_pattern. */ 3757 pgroup_t *pg_pattern; /* Prop. group for pg_pattern */ 3758 property_t *prop; 3759 pgroup_t *prop_pattern; 3760 tmpl_validate_status_t r; 3761 tmpl_validate_status_t rc = TVS_SUCCESS; 3762 int stat; 3763 3764 /* 3765 * See if there is a pg_pattern for this property group. If it 3766 * exists, use it to validate the property group. If there is no 3767 * pg_pattern, then there is no validation to do. 3768 */ 3769 rc = tmpl_find_pg_pattern(e, pg, &pg_pattern); 3770 switch (rc) { 3771 case TVS_SUCCESS: 3772 break; 3773 case TVS_BAD_TEMPLATE: 3774 CLEAR_ERROR_INFO(&einfo); 3775 einfo.ei_type = EIT_BAD_TEMPLATE; 3776 einfo.ei_u.ei_bad_template.ei_reason = gettext("Property " 3777 "group name too long"); 3778 (void) tmpl_errors_add_im(errs, rc, e, NULL, pg, NULL, NULL, 3779 NULL, &einfo); 3780 return (rc); 3781 default: 3782 assert(0); 3783 abort(); 3784 } 3785 if (pg_pattern == NULL) 3786 return (TVS_SUCCESS); 3787 3788 /* 3789 * If the pg_pattern declares a type, verify that the PG has the 3790 * correct type. 3791 */ 3792 pg_pattern_type = find_type_specification(pg_pattern); 3793 if ((pg_pattern_type != NULL) && 3794 (*pg_pattern_type != 0)) { 3795 if ((pg->sc_pgroup_type != NULL) && 3796 (*(pg->sc_pgroup_type) != 0)) { 3797 if (strcmp(pg_pattern_type, 3798 pg->sc_pgroup_type) != 0) { 3799 rc = TVS_VALIDATION; 3800 stat = add_scf_error(errs, 3801 SCF_TERR_WRONG_PG_TYPE, pg_pattern, pg, 3802 NULL, NULL, NULL, NULL); 3803 if (stat != 0) { 3804 /* 3805 * If we can no longer accumulate 3806 * errors, return without trying to 3807 * do further validation. 3808 */ 3809 return (rc); 3810 } 3811 } 3812 } else { 3813 rc = TVS_MISSING_PG_TYPE; 3814 r = tmpl_errors_add_im(errs, rc, e, pg_pattern, pg, 3815 NULL, NULL, NULL, NULL); 3816 if (r != TVS_SUCCESS) { 3817 /* 3818 * If we can no longer accumulate errors, 3819 * return without trying to do further 3820 * validation. 3821 */ 3822 return (rc); 3823 } 3824 } 3825 } 3826 3827 /* Verify the properties in the property group. */ 3828 prop = NULL; 3829 while ((prop = next_property(pg, prop)) != NULL) { 3830 r = tmpl_find_prop_pattern(e, pg_pattern, prop, &prop_pattern); 3831 switch (r) { 3832 case TVS_SUCCESS: 3833 /* Found match. Validate property. */ 3834 break; 3835 case TVS_NOMATCH: 3836 /* No prop_patern. Go on to next property. */ 3837 continue; 3838 case TVS_BAD_TEMPLATE: 3839 CLEAR_ERROR_INFO(&einfo); 3840 einfo.ei_type = EIT_BAD_TEMPLATE; 3841 einfo.ei_u.ei_bad_template.ei_reason = 3842 gettext("prop_pattern name too long"); 3843 (void) tmpl_errors_add_im(errs, r, e, NULL, pg, NULL, 3844 NULL, NULL, &einfo); 3845 continue; 3846 default: 3847 assert(0); 3848 abort(); 3849 } 3850 r = tmpl_validate_prop(prop, prop_pattern, pg, pg_pattern, 3851 errs); 3852 if (r != TVS_SUCCESS) 3853 rc = r; 3854 } 3855 3856 /* 3857 * Confirm required properties are present. 3858 */ 3859 r = tmpl_required_props_present(e, pg, pg_pattern, errs); 3860 if (r != TVS_SUCCESS) 3861 rc = r; 3862 3863 return (rc); 3864 } 3865 3866 /* 3867 * Validate that the property groups in the entity conform to the template 3868 * specifications. Specifically, this means do the following: 3869 * 3870 * - Loop through the property groups in the entity skipping the ones 3871 * that are of type "template". 3872 * 3873 * - For the PG search for the corresponding template_pg_pattern 3874 * property group. It is possible that one may not exist. 3875 * 3876 * - Verify that the PG is in conformance with the pg_pattern 3877 * specification if it exists. 3878 */ 3879 static tmpl_validate_status_t 3880 tmpl_validate_entity_pgs(entity_t *e, tmpl_errors_t *errs) 3881 { 3882 composed_pg_t *cpg; 3883 uu_avl_t *pgroups; 3884 pgroup_t *pg; 3885 tmpl_validate_status_t r; 3886 tmpl_validate_status_t rc = TVS_SUCCESS; 3887 3888 assert(e->sc_etype == SVCCFG_INSTANCE_OBJECT); 3889 3890 pgroups = e->sc_u.sc_instance.sc_composed; 3891 for (cpg = uu_avl_first(pgroups); 3892 cpg != NULL; 3893 cpg = uu_avl_next(pgroups, cpg)) { 3894 if (strcmp(cpg->cpg_type, SCF_GROUP_TEMPLATE) == 0) 3895 continue; 3896 pg = CPG2PG(cpg); 3897 if ((r = tmpl_validate_pg(e, pg, errs)) != TVS_SUCCESS) 3898 rc = r; 3899 } 3900 3901 return (rc); 3902 } 3903 3904 /* 3905 * Validate the instance, e, by performing the following checks: 3906 * 3907 * - Verify template consistency. 3908 * 3909 * - Validate each property group in the entity is in conformance 3910 * with the template specifications. 3911 * 3912 * - Verify that all required property groups are present in the 3913 * entity. 3914 */ 3915 static tmpl_validate_status_t 3916 tmpl_validate_instance(entity_t *e, tmpl_errors_t *errs) 3917 { 3918 tmpl_validate_status_t r; 3919 tmpl_validate_status_t rc = TVS_SUCCESS; 3920 int status; 3921 tv_errors_t *ste; 3922 3923 /* Prepare to collect errors for this instance. */ 3924 ste = tv_errors_create(e->sc_fmri); 3925 status = uu_list_insert_after(errs->te_scf, errs->te_cur_scf, ste); 3926 assert(status == 0); 3927 errs->te_cur_scf = ste; 3928 3929 /* Verify template consistency */ 3930 rc = tmpl_consistency(e, errs); 3931 3932 /* Validate the property groups in the entity. */ 3933 r = tmpl_validate_entity_pgs(e, errs); 3934 if (r != TVS_SUCCESS) 3935 rc = r; 3936 3937 /* Verify that all required property groups are present. */ 3938 r = tmpl_required_pg_present(e, errs); 3939 if (r != TVS_SUCCESS) 3940 rc = r; 3941 3942 return (rc); 3943 } 3944 3945 /* 3946 * First validate the instances of the service. 3947 */ 3948 static tmpl_validate_status_t 3949 tmpl_validate_service(entity_t *svc, tmpl_errors_t *errs) 3950 { 3951 entity_t *inst; 3952 tmpl_validate_status_t r; 3953 tmpl_validate_status_t rc = TVS_SUCCESS; 3954 3955 assert(svc->sc_etype == SVCCFG_SERVICE_OBJECT); 3956 3957 load_general_templates(svc); 3958 3959 /* Validate the service's instances. */ 3960 for (inst = uu_list_first(svc->sc_u.sc_service.sc_service_instances); 3961 inst != NULL; 3962 inst = uu_list_next(svc->sc_u.sc_service.sc_service_instances, 3963 inst)) { 3964 load_instance_restarter(inst); 3965 build_composed_instance(inst); 3966 r = tmpl_validate_instance(inst, errs); 3967 if (r != TVS_SUCCESS) 3968 rc = r; 3969 demolish_composed_instance(inst); 3970 } 3971 3972 return (rc); 3973 } 3974 3975 /* 3976 * Validate all services and instances in the bundle against their 3977 * templates. If err_list is not NULL, a tmpl_errors structure will be 3978 * allocated and its address will be returned to err_list. This structure 3979 * can be used to generate error messages. 3980 */ 3981 tmpl_validate_status_t 3982 tmpl_validate_bundle(bundle_t *bndl, tmpl_errors_t **err_list) 3983 { 3984 tmpl_errors_t *errs = NULL; 3985 entity_t *svc; 3986 tmpl_validate_status_t r; 3987 tmpl_validate_status_t rc = TVS_SUCCESS; 3988 3989 if (err_list != NULL) 3990 *err_list = NULL; 3991 if (bndl->sc_bundle_type != SVCCFG_MANIFEST) { 3992 semerr(gettext("Bundle is not a manifest. Unable to validate " 3993 "against templates.\n")); 3994 return (TVS_FATAL); 3995 } 3996 3997 errs = tmpl_errors_create(); 3998 if (errs == NULL) 3999 uu_die(emesg_nomem); 4000 4001 lscf_prep_hndl(); /* Initialize g_hndl */ 4002 if (load_init() != 0) 4003 uu_die(emesg_nomem); 4004 4005 /* 4006 * We will process all services in the bundle, unless we get a 4007 * fatal error. That way we can report all errors on all services 4008 * on a single run of svccfg. 4009 */ 4010 for (svc = uu_list_first(bndl->sc_bundle_services); 4011 svc != NULL; 4012 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 4013 if (svc->sc_etype != SVCCFG_SERVICE_OBJECT) { 4014 semerr(gettext("Manifest for %s contains an object " 4015 "named \"%s\" that is not a service.\n"), 4016 bndl->sc_bundle_name, svc->sc_name); 4017 tmpl_errors_destroy(errs); 4018 load_fini(); 4019 return (TVS_FATAL); 4020 } 4021 if ((r = tmpl_validate_service(svc, errs)) != TVS_SUCCESS) 4022 rc = r; 4023 if (r == TVS_FATAL) 4024 break; 4025 } 4026 4027 if (err_list == NULL) { 4028 tmpl_errors_destroy(errs); 4029 } else { 4030 *err_list = errs; 4031 } 4032 4033 load_fini(); 4034 4035 return (rc); 4036 } 4037