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 2009 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(8) 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 == EINVAL) 1917 warn(gettext("WARNING: restarter FMRI %s is invalid\n"), 1918 restarter); 1919 1920 if (r == ENOTSUP) 1921 warn(gettext("WARNING: restarter FMRI %s is not valid; " 1922 "instance fmri required.\n"), restarter); 1923 1924 if (r == ENOMEM) 1925 uu_die(emesg_nomem); 1926 1927 svc->sc_u.sc_service.sc_restarter = NULL; 1928 } 1929 if (is_global == 0) { 1930 if ((r = load_instance(SCF_INSTANCE_GLOBAL, "global", 1931 &svc->sc_u.sc_service.sc_global)) != 0) { 1932 /* 1933 * During initial manifest import, global may not be in 1934 * the repository yet. 1935 */ 1936 if (r == ENOMEM) 1937 uu_die(emesg_nomem); 1938 else 1939 svc->sc_u.sc_service.sc_global = NULL; 1940 } 1941 } 1942 } 1943 1944 /* 1945 * Load the instance specific restarter if one is declared. 1946 * 1947 * There is no corresponding unload_instance_restarter() function because 1948 * it is not needed. The memory will be freed in internal_instance_free() 1949 * when internal_bundle_free() is called. 1950 */ 1951 static void 1952 load_instance_restarter(entity_t *i) 1953 { 1954 const char *restarter; 1955 int r; 1956 1957 assert(i->sc_etype == SVCCFG_INSTANCE_OBJECT); 1958 1959 restarter = find_restarter(i); 1960 if (restarter == NULL) { 1961 /* No instance specific restarter */ 1962 return; 1963 } 1964 r = load_instance(restarter, "instance_restarter", 1965 &i->sc_u.sc_instance.sc_instance_restarter); 1966 if (r != 0) { 1967 /* 1968 * During initial manifest import, the restarter may not be 1969 * in the repository yet. In this case we continue on 1970 * without it. 1971 */ 1972 if (r == EINVAL) 1973 warn(gettext("WARNING: restarter FMRI %s is invalid\n"), 1974 restarter); 1975 1976 if (r == ENOTSUP) 1977 warn(gettext("WARNING: restarter FMRI %s is not valid; " 1978 "instance fmri required.\n"), restarter); 1979 1980 if (r == ENOMEM) 1981 uu_die(emesg_nomem); 1982 } 1983 } 1984 1985 /* 1986 * Find the next property after current in the property group at pg. If 1987 * the property group contains a tree of composed properties, that tree is 1988 * walked. Otherwise, we walk through the uu_list at sc_pgroup_props. 1989 */ 1990 static property_t * 1991 next_property(pgroup_t *pg, property_t *current) 1992 { 1993 composed_pg_t *cpg; 1994 property_t *prop; 1995 1996 cpg = pg->sc_pgroup_composed; 1997 if ((cpg != NULL) && (cpg->cpg_composed_props != NULL)) { 1998 /* Walk through composed property list. */ 1999 if (current) { 2000 prop = uu_avl_next(cpg->cpg_composed_props, current); 2001 } else { 2002 prop = uu_avl_first(cpg->cpg_composed_props); 2003 } 2004 } else { 2005 /* No composition available, so walk the list of properties */ 2006 if (current) { 2007 prop = uu_list_next(pg->sc_pgroup_props, current); 2008 } else { 2009 prop = uu_list_first(pg->sc_pgroup_props); 2010 } 2011 } 2012 2013 return (prop); 2014 } 2015 2016 static ptrn_info_t * 2017 ptrn_info_create(pgroup_t *pat) 2018 { 2019 entity_t *e; 2020 ptrn_info_t *info; 2021 composed_pg_t *match; 2022 composed_pg_t cpg; 2023 2024 info = safe_malloc(sizeof (*info)); 2025 2026 switch (pgroup_type(pat)) { 2027 case PG_PATTERN_PG: 2028 info->pi_ptrn_type = PG_PATTERN; 2029 break; 2030 case PROP_PATTERN_PG: 2031 info->pi_ptrn_type = PROP_PATTERN; 2032 break; 2033 default: 2034 assert(0); 2035 abort(); 2036 } 2037 info->pi_ptrnpg = pat; 2038 info->pi_name = find_name_specification(pat); 2039 info->pi_name = EMPTY_TO_NULL(info->pi_name); 2040 info->pi_type = find_type_specification(pat); 2041 info->pi_type = EMPTY_TO_NULL(info->pi_type); 2042 if (info->pi_ptrn_type == PG_PATTERN) { 2043 info->pi_target = find_astring_value_in_pg(pat, 2044 SCF_PROPERTY_TM_TARGET); 2045 if (info->pi_target == NULL) 2046 info->pi_target = SCF_TM_TARGET_THIS; 2047 } 2048 if (info->pi_ptrn_type == PROP_PATTERN) { 2049 info->pi_pgp_name = find_astring_value_in_pg(pat, 2050 SCF_PROPERTY_TM_PG_PATTERN); 2051 assert((info->pi_pgp_name != NULL) && 2052 (*(info->pi_pgp_name) != 0)); 2053 2054 /* 2055 * Find the property group that defines the pg_pattern that 2056 * holds this prop_pattern. 2057 */ 2058 e = pat->sc_parent; 2059 if (e->sc_etype == SVCCFG_INSTANCE_OBJECT) { 2060 (void) memset(&cpg, 0, sizeof (cpg)); 2061 cpg.cpg_name = info->pi_pgp_name; 2062 cpg.cpg_type = SCF_GROUP_TEMPLATE_PG_PATTERN; 2063 match = uu_avl_find(e->sc_u.sc_instance.sc_composed, 2064 &cpg, NULL, NULL); 2065 assert(match != NULL); 2066 info->pi_enc_pgp = CPG2PG(match); 2067 } else { 2068 info->pi_enc_pgp = internal_pgroup_find(e, 2069 info->pi_pgp_name, SCF_GROUP_TEMPLATE_PG_PATTERN); 2070 } 2071 assert(info->pi_enc_pgp != NULL); 2072 } 2073 uu_avl_node_init(info, &info->pi_link, ptrn_info_pool); 2074 return (info); 2075 } 2076 2077 static void 2078 ptrn_info_destroy(ptrn_info_t *info) 2079 { 2080 if (info == NULL) 2081 return; 2082 uu_avl_node_fini(info, &info->pi_link, ptrn_info_pool); 2083 free(info); 2084 } 2085 2086 /* 2087 * Walk through the property groups of the instance or service at e looking 2088 * for definitions of pg_patterns or prop_patterns as specified by type. 2089 * For each property group that matches type create a ptrn_info_t and add 2090 * it to the avl tree at tree. If duplicates are found add an error entry 2091 * to errs. 2092 */ 2093 static tmpl_validate_status_t 2094 gather_pattern(entity_t *e, ptrn_type_t type, uu_avl_t *tree, 2095 tmpl_errors_t *errs) 2096 { 2097 error_info_t einfo; 2098 ptrn_info_t *info = NULL; 2099 uu_avl_index_t marker; 2100 ptrn_info_t *match; 2101 pgroup_t *pg; 2102 tmpl_validate_status_t rc = TVS_SUCCESS; 2103 const char *selector; 2104 2105 switch (type) { 2106 case PG_PATTERN: 2107 selector = SCF_GROUP_TEMPLATE_PG_PATTERN; 2108 break; 2109 case PROP_PATTERN: 2110 selector = SCF_GROUP_TEMPLATE_PROP_PATTERN; 2111 break; 2112 default: 2113 assert(0); 2114 abort(); 2115 } 2116 2117 for (pg = uu_list_first(e->sc_pgroups); 2118 pg != NULL; 2119 pg = uu_list_next(e->sc_pgroups, pg)) { 2120 if (strcmp(pg->sc_pgroup_type, selector) != 0) { 2121 continue; 2122 } 2123 if (info != NULL) { 2124 /* Get rid of old structure. */ 2125 ptrn_info_destroy(info); 2126 } 2127 info = ptrn_info_create(pg); 2128 match = uu_avl_find(tree, info, NULL, &marker); 2129 if (match == NULL) { 2130 /* No match. Insert the info. */ 2131 uu_avl_insert(tree, info, marker); 2132 info = NULL; 2133 continue; 2134 } 2135 2136 /* Got a match. Determine if it is a conflict. */ 2137 if ((info->pi_name == NULL) || 2138 (info->pi_type == NULL) || 2139 (match->pi_name == NULL) || 2140 (match->pi_type == NULL)) { 2141 /* No conflicts if any wild cards. */ 2142 continue; 2143 } 2144 2145 /* 2146 * Name already matches, or we wouldn't have gotten 2147 * here. Make sure that the type also matches. 2148 */ 2149 if (strcmp(info->pi_type, match->pi_type) == 0) { 2150 continue; 2151 } 2152 2153 /* 2154 * If we get to this point we have a conflict, and 2155 * we need to generate the correct type of error. 2156 */ 2157 CLEAR_ERROR_INFO(&einfo); 2158 einfo.ei_type = EIT_PATTERN_CONFLICT; 2159 einfo.ei_u.ei_pattern_conflict.ei_pattern = 2160 match->pi_ptrnpg; 2161 if (type == PG_PATTERN) { 2162 rc = TVS_VALIDATION; 2163 if (add_scf_error(errs, SCF_TERR_PG_PATTERN_CONFLICT, 2164 info->pi_ptrnpg, NULL, NULL, NULL, NULL, 2165 &einfo) != 0) { 2166 /* 2167 * If we can no longer accumulate 2168 * errors, break out of the loop. 2169 */ 2170 break; 2171 } 2172 } else { 2173 /* 2174 * Possible conflicting prop_pattern. See if the 2175 * prop_patterns are declared in the same 2176 * pg_pattern. 2177 */ 2178 if ((info->pi_pgp_name == NULL) || 2179 (match->pi_pgp_name == NULL)) { 2180 continue; 2181 } 2182 if (strcmp(info->pi_pgp_name, match->pi_pgp_name) != 0) 2183 continue; 2184 2185 /* It is a real conflict. */ 2186 rc = TVS_VALIDATION; 2187 if (add_scf_error(errs, SCF_TERR_PROP_PATTERN_CONFLICT, 2188 info->pi_enc_pgp, NULL, info->pi_ptrnpg, NULL, NULL, 2189 &einfo) != 0) { 2190 /* 2191 * If we can no longer accumulate 2192 * errors, break out of the loop. 2193 */ 2194 break; 2195 } 2196 } 2197 } 2198 2199 ptrn_info_destroy(info); 2200 return (rc); 2201 } 2202 2203 /* 2204 * Free the pg_iter structure. 2205 */ 2206 static void 2207 pg_iter_destroy(pg_iter_t *i) 2208 { 2209 if (i == NULL) 2210 return; 2211 2212 uu_free(i); 2213 } 2214 2215 /* 2216 * Create a property group iterator for the instance at e. This iterator 2217 * will walk through the composed property groups of the instance. It will 2218 * then step through the property groups of the instance's restarter and 2219 * finally the global service. If you wish to iterate over a specific type 2220 * of property group, set restriction to point the the desired type. 2221 * Otherwise set restriction to NULL. 2222 * 2223 * The returned interator must be freed by calling pg_iter_destroy(). NULL 2224 * is returned if we are unable to allocate the necessary memory. 2225 */ 2226 static pg_iter_t * 2227 pg_iter_create(entity_t *e, const char *restriction) 2228 { 2229 pg_iter_t *i; 2230 2231 assert(e->sc_etype == SVCCFG_INSTANCE_OBJECT); 2232 2233 i = uu_zalloc(sizeof (*i)); 2234 if (i == NULL) 2235 return (NULL); 2236 2237 i->pgi_entity = e; 2238 i->pgi_restrict = restriction; 2239 i->pgi_level = TL_COMPOSED; 2240 i->pgi_service = e->sc_parent; 2241 2242 return (i); 2243 } 2244 2245 /* 2246 * Return the next property group in the iteration. NULL is returned if we 2247 * reach the end of the list. The iterator will automatically proceed from 2248 * most specific to most general levels. 2249 */ 2250 static pgroup_t * 2251 next_pattern_pg(pg_iter_t *i) 2252 { 2253 composed_pg_t *cpg; 2254 entity_t *e; 2255 pgroup_t *pg; 2256 uu_avl_t *composed_tree; 2257 2258 assert(i->pgi_level != TL_NOLEVEL); 2259 2260 while (i->pgi_entity != NULL) { 2261 if (i->pgi_level == TL_COMPOSED) { 2262 composed_tree = 2263 i->pgi_entity->sc_u.sc_instance.sc_composed; 2264 cpg = i->pgi_current.pgi_cpg; 2265 if (cpg == NULL) { 2266 cpg = uu_avl_first(composed_tree); 2267 } else { 2268 cpg = uu_avl_next(composed_tree, cpg); 2269 } 2270 if (cpg == NULL) { 2271 pg = NULL; 2272 } else { 2273 pg = CPG2PG(cpg); 2274 i->pgi_current.pgi_cpg = cpg; 2275 } 2276 } else { 2277 pg = i->pgi_current.pgi_pg; 2278 if (pg == NULL) { 2279 pg = uu_list_first(i->pgi_entity->sc_pgroups); 2280 } else { 2281 pg = uu_list_next(i->pgi_entity->sc_pgroups, 2282 pg); 2283 } 2284 i->pgi_current.pgi_pg = pg; 2285 } 2286 2287 if (pg == NULL) { 2288 /* 2289 * End of the list. Reset current and break out of 2290 * the loop. 2291 */ 2292 (void) memset(&i->pgi_current, 0, 2293 sizeof (i->pgi_current)); 2294 break; 2295 } 2296 2297 /* 2298 * If this iteration is for a specific type, verify that 2299 * this pg is of that type. 2300 */ 2301 if (i->pgi_restrict) { 2302 if (strcmp(pg->sc_pgroup_type, i->pgi_restrict) != 0) { 2303 continue; 2304 } 2305 } 2306 2307 return (pg); 2308 } 2309 2310 /* 2311 * End of the list in the current level. Move up to the next 2312 * level. 2313 */ 2314 switch (i->pgi_level) { 2315 case TL_COMPOSED: 2316 /* Skip service if we've finished a composed instance. */ 2317 e = i->pgi_entity; 2318 if (e->sc_u.sc_instance.sc_instance_restarter == NULL) { 2319 /* Use service restarter */ 2320 i->pgi_entity = 2321 i->pgi_service->sc_u.sc_service.sc_restarter; 2322 } else { 2323 /* Use instance restarter */ 2324 i->pgi_entity = 2325 e->sc_u.sc_instance.sc_instance_restarter; 2326 } 2327 i->pgi_level = TL_RESTARTER; 2328 break; 2329 case TL_RESTARTER: 2330 i->pgi_entity = i->pgi_service->sc_u.sc_service.sc_global; 2331 i->pgi_level = TL_GLOBAL; 2332 break; 2333 case TL_GLOBAL: 2334 i->pgi_level = TL_NOLEVEL; 2335 return (NULL); 2336 default: 2337 assert(0); 2338 abort(); 2339 } 2340 2341 /* Go process the next level. */ 2342 return (next_pattern_pg(i)); 2343 } 2344 2345 /* 2346 * Compare two pattern info structures (ptrn_info_t). If both structures 2347 * have names, the comparison is based on the name. If only one has a 2348 * name, the structure with no name will be first. If neither structure 2349 * has a name, the comparison is based on their types using similar wild 2350 * card logic. 2351 */ 2352 /* ARGSUSED2 */ 2353 static int 2354 ptrn_info_compare(const void *left, const void *right, void *unused) 2355 { 2356 ptrn_info_t *l = (ptrn_info_t *)left; 2357 ptrn_info_t *r = (ptrn_info_t *)right; 2358 2359 if ((l->pi_name != NULL) && (r->pi_name != NULL)) 2360 return (strcmp(l->pi_name, r->pi_name)); 2361 if ((l->pi_name == NULL) && (r->pi_name == NULL)) { 2362 /* No names, so we need to compare types. */ 2363 if ((l->pi_type != NULL) && (r->pi_type != NULL)) 2364 return (strcmp(l->pi_type, r->pi_type)); 2365 if ((l->pi_type == NULL) && (r->pi_type == NULL)) 2366 return (0); 2367 2368 /* If we get here, exactly one of the types is NULL */ 2369 if (l->pi_type == NULL) 2370 return (-1); 2371 return (1); 2372 } 2373 2374 /* If we get here, exactly one of the names is NULL */ 2375 if (l->pi_name == NULL) 2376 return (-1); 2377 return (1); 2378 } 2379 2380 /* 2381 * The target of a pg_pattern in combination with the level at which the 2382 * pg_pattern was defined determines whether or not it should be applied. 2383 * The following combinations should be ignored, and all others should be 2384 * applied. 2385 * 2386 * Target Level 2387 * ------ ----- 2388 * this TL_RESTARTER, TL_GLOBAL 2389 * "this" only applies if the pg_pattern was defined 2390 * at the instance or service level 2391 * delegate TL_INSTANCE, TL_SERVICE 2392 * Only restarters and the global service can 2393 * delegate. 2394 * instance TL_INSTANCE, TL_RESTARTER, TL_GLOBAL 2395 * Only the service level can specify the "instance" 2396 * target. 2397 * all TL_INSTANCE, TL_SERVICE, TL_RESTARTER 2398 * Only the global service can specify the "all" 2399 * target. 2400 * 2401 * Return Values: 2402 * 1 apply the pg_pattern 2403 * 0 ignore the pg_pattern 2404 */ 2405 static int 2406 target_check(const char *target, tmpl_level_t level) 2407 { 2408 if ((target == NULL) || (*target == 0)) { 2409 /* Default is this */ 2410 target = SCF_TM_TARGET_THIS; 2411 } 2412 if (strcmp(target, SCF_TM_TARGET_THIS) == 0) { 2413 if ((level == TL_RESTARTER) || 2414 (level == TL_GLOBAL)) { 2415 return (0); 2416 } else { 2417 return (1); 2418 } 2419 } 2420 if (strcmp(target, SCF_TM_TARGET_DELEGATE) == 0) { 2421 if ((level == TL_INSTANCE) || 2422 (level == TL_SERVICE)) { 2423 return (0); 2424 } else { 2425 return (1); 2426 } 2427 } 2428 if (strcmp(target, SCF_TM_TARGET_INSTANCE) == 0) { 2429 /* 2430 * Note that the test is inverted from the other cases. 2431 * This is because there is only one instance where apply 2432 * is the correct thing to do. 2433 */ 2434 if (level == TL_SERVICE) { 2435 return (1); 2436 } else { 2437 return (0); 2438 } 2439 } 2440 if (strcmp(target, SCF_TM_TARGET_ALL) == 0) { 2441 if ((level == TL_INSTANCE) || 2442 (level == TL_SERVICE) || 2443 (level == TL_RESTARTER)) { 2444 return (0); 2445 } 2446 } 2447 return (1); 2448 } 2449 2450 static int 2451 pg_target_check(pgroup_t *pg_pattern, tmpl_level_t level) 2452 { 2453 const char *target; 2454 2455 target = find_astring_value_in_pg(pg_pattern, SCF_PROPERTY_TM_TARGET); 2456 if (level == TL_COMPOSED) { 2457 switch (pg_pattern->sc_parent->sc_etype) { 2458 case SVCCFG_INSTANCE_OBJECT: 2459 level = TL_INSTANCE; 2460 break; 2461 case SVCCFG_SERVICE_OBJECT: 2462 level = TL_SERVICE; 2463 break; 2464 default: 2465 assert(0); 2466 abort(); 2467 } 2468 } 2469 return (target_check(target, level)); 2470 } 2471 2472 /* 2473 * Find the prop_pattern's type sepcification and convert it to the 2474 * appropriate scf_type. 2475 */ 2476 static tmpl_validate_status_t 2477 prop_pattern_type(pgroup_t *pattern, scf_type_t *type) 2478 { 2479 const char *type_spec; 2480 2481 assert(strcmp(pattern->sc_pgroup_type, 2482 SCF_GROUP_TEMPLATE_PROP_PATTERN) == 0); 2483 2484 type_spec = find_type_specification(pattern); 2485 if ((type_spec == NULL) || (*type_spec == 0)) 2486 return (TVS_MISSING_TYPE_SPECIFICATION); 2487 *type = scf_string_to_type(type_spec); 2488 return (TVS_SUCCESS); 2489 } 2490 2491 /* 2492 * This function is analagous to scf_property_is_type(3SCF), but it works 2493 * on the in memory representation of the property. 2494 * 2495 * RETURNS: 2496 * 0 The property at prop does not have the specified 2497 * type. 2498 * non-zero The property at prop does have the specified type. 2499 */ 2500 static int 2501 property_is_type(property_t *prop, scf_type_t type) 2502 { 2503 return (scf_is_compatible_type(type, prop->sc_value_type) == 2504 SCF_SUCCESS); 2505 } 2506 2507 /* 2508 * This function generates a property group name for a template's 2509 * pg_pattern. The name and type of the pg_pattern are used to construct 2510 * the name, but either or both may be null. A pointer to the constructed 2511 * name is returned, and the referenced memory must be freed using 2512 * free(3c). NULL is returned if we are unable to allocate enough memory. 2513 */ 2514 static char * 2515 gen_pg_pattern_pg_name(const char *name, const char *type) 2516 { 2517 char *pg_name; 2518 char *rv = NULL; 2519 ssize_t name_size; 2520 2521 name_size = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH); 2522 pg_name = safe_malloc(name_size); 2523 rv = pg_name; 2524 2525 /* 2526 * There are four cases -- name and type are both null, name and 2527 * type are both non-null, only name is present or only type is 2528 * present. 2529 */ 2530 if ((name == NULL) || (*name == 0)) { 2531 if ((type == NULL) || (*type == 0)) { 2532 /* 2533 * Name and type are both null, so the PG name 2534 * contains only the prefix. 2535 */ 2536 if (strlcpy(pg_name, SCF_PG_TM_PG_PATTERN_PREFIX, 2537 name_size) >= name_size) { 2538 rv = NULL; 2539 } 2540 } else { 2541 /* 2542 * If we have a type and no name, the type becomes 2543 * part of the pg_pattern property group name. 2544 */ 2545 if (snprintf(pg_name, name_size, "%s%s", 2546 SCF_PG_TM_PG_PATTERN_T_PREFIX, type) >= 2547 name_size) { 2548 rv = NULL; 2549 } 2550 } 2551 } else { 2552 /* 2553 * As long as the pg_pattern has a name, it becomes part of 2554 * the name of the pg_pattern property group name. We 2555 * merely need to pick the appropriate prefix. 2556 */ 2557 const char *prefix; 2558 if ((type == NULL) || (*type == 0)) { 2559 prefix = SCF_PG_TM_PG_PATTERN_N_PREFIX; 2560 } else { 2561 prefix = SCF_PG_TM_PG_PATTERN_NT_PREFIX; 2562 } 2563 if (snprintf(pg_name, name_size, "%s%s", prefix, name) >= 2564 name_size) { 2565 rv = NULL; 2566 } 2567 } 2568 2569 if (rv == NULL) { 2570 /* Name was too big. */ 2571 free(pg_name); 2572 } 2573 return (rv); 2574 } 2575 2576 /* 2577 * pinfo contains information about a prop_pattern. An include_values 2578 * element with a type of type has been included in the prop_pattern 2579 * specification. We need to determine if the prop_pattern also contains 2580 * constraints or values specifications as determined by type. Thus, we 2581 * search the prop_pattern for properties whose names start with the 2582 * correct prefix. 2583 */ 2584 static tmpl_validate_status_t 2585 include_values_support(ptrn_info_t *pinfo, const char *type, 2586 tmpl_errors_t *errs) 2587 { 2588 error_info_t einfo; 2589 int i; 2590 const char **prefixes; 2591 const char *pfx; 2592 property_t *prop; 2593 pgroup_t *ptrn; 2594 2595 if (strcmp(type, "constraints") == 0) { 2596 prefixes = constraint_prefixes; 2597 } else if (strcmp(type, "values") == 0) { 2598 prefixes = value_prefixes; 2599 } else { 2600 CLEAR_ERROR_INFO(&einfo); 2601 einfo.ei_type = EIT_BAD_TEMPLATE; 2602 einfo.ei_u.ei_bad_template.ei_reason = gettext("include_values " 2603 "type must be \"constraints\" or \"values\""); 2604 (void) tmpl_errors_add_im(errs, TVS_BAD_TEMPLATE, 2605 pinfo->pi_ptrnpg->sc_parent, pinfo->pi_enc_pgp, 2606 NULL, pinfo->pi_ptrnpg, NULL, NULL, &einfo); 2607 return (TVS_BAD_TEMPLATE); 2608 } 2609 2610 /* 2611 * Now see if the prop_pattern has a property whose name starts 2612 * with one of these prefixes. 2613 */ 2614 ptrn = pinfo->pi_ptrnpg; 2615 for (prop = uu_list_first(ptrn->sc_pgroup_props); 2616 prop != NULL; 2617 prop = uu_list_next(ptrn->sc_pgroup_props, prop)) { 2618 for (pfx = prefixes[0], i = 0; 2619 pfx != NULL; 2620 ++i, pfx = prefixes[i]) { 2621 if (strncmp(prop->sc_property_name, pfx, 2622 strlen(pfx)) == 0) { 2623 return (TVS_SUCCESS); 2624 } 2625 } 2626 } 2627 2628 /* No match found. Generate error */ 2629 CLEAR_ERROR_INFO(&einfo); 2630 einfo.ei_type = EIT_INCLUDE_VALUES; 2631 einfo.ei_u.ei_inc_values.ei_type = type; 2632 (void) add_scf_error(errs, SCF_TERR_INCLUDE_VALUES, pinfo->pi_enc_pgp, 2633 NULL, ptrn, NULL, NULL, &einfo); 2634 2635 return (TVS_VALIDATION); 2636 } 2637 2638 /* 2639 * Walk through the prop_patterns in tree, looking for any that have an 2640 * include_values, SCF_PROPERTY_TM_CHOICES_INCLUDE_VALUES, property. For 2641 * the prop_patterns with the include values property, verify that the 2642 * prop_pattern has constraint or values declarations as specified by the 2643 * include_values property. 2644 */ 2645 static tmpl_validate_status_t 2646 tmpl_include_values_check(uu_avl_t *tree, tmpl_errors_t *errs) 2647 { 2648 ptrn_info_t *info; 2649 property_t *iv; 2650 tmpl_validate_status_t r; 2651 tmpl_validate_status_t rc = TVS_SUCCESS; 2652 value_t *v; 2653 2654 for (info = uu_avl_first(tree); 2655 info != NULL; 2656 info = uu_avl_next(tree, info)) { 2657 iv = internal_property_find(info->pi_ptrnpg, 2658 SCF_PROPERTY_TM_CHOICES_INCLUDE_VALUES); 2659 if (iv == NULL) 2660 continue; 2661 for (v = uu_list_first(iv->sc_property_values); 2662 v != NULL; 2663 v = uu_list_next(iv->sc_property_values, v)) { 2664 assert(is_numeric_type(v->sc_type) == 0); 2665 r = include_values_support(info, v->sc_u.sc_string, 2666 errs); 2667 if (r != TVS_SUCCESS) 2668 rc = r; 2669 } 2670 } 2671 return (rc); 2672 } 2673 2674 /* 2675 * Verify that there are no conflicting definitions of pg_pattern or 2676 * prop_pattern. Two patterns are said to be in conflict if they have the 2677 * same name and differing types. There is a caveat, however. Empty 2678 * pattern names or types are considered to be wild cards. There is no 2679 * conflict if a pattern has a wild card. 2680 */ 2681 static tmpl_validate_status_t 2682 tmpl_pattern_conflict(entity_t *inst, uu_avl_t *tree, ptrn_type_t type, 2683 tmpl_errors_t *errs) 2684 { 2685 tmpl_validate_status_t r; 2686 tmpl_validate_status_t rc; 2687 2688 /* First walk the instance. */ 2689 rc = gather_pattern(inst, type, tree, errs); 2690 2691 /* Now walk the service */ 2692 r = gather_pattern(inst->sc_parent, type, tree, errs); 2693 if (r != TVS_SUCCESS) 2694 rc = r; 2695 2696 return (rc); 2697 } 2698 2699 static tmpl_validate_status_t 2700 tmpl_required_attr_present(uu_avl_t *tree, tmpl_errors_t *errs) 2701 { 2702 ptrn_info_t *pinfo; 2703 tmpl_validate_status_t rc = TVS_SUCCESS; 2704 int reported_name; 2705 int rv; 2706 2707 for (pinfo = uu_avl_first(tree); 2708 pinfo != NULL; 2709 pinfo = uu_avl_next(tree, pinfo)) { 2710 if (is_required(pinfo->pi_ptrnpg) == 0) { 2711 /* Nothing to check if pattern is not required. */ 2712 continue; 2713 } 2714 2715 /* 2716 * For pg_pattern both name and type are optional unless 2717 * the required attribute has a value of true. For 2718 * prop_patterns only the type is optional, but it must be 2719 * provided if the required attribute has a value of true. 2720 */ 2721 reported_name = 0; 2722 if ((pinfo->pi_ptrn_type == PG_PATTERN) && 2723 (pinfo->pi_name == NULL)) { 2724 rc = TVS_VALIDATION; 2725 if (add_scf_error(errs, SCF_TERR_PG_PATTERN_INCOMPLETE, 2726 pinfo->pi_ptrnpg, 2727 NULL, NULL, NULL, NULL, NULL) != 0) { 2728 /* 2729 * If we're unable to report errors, break 2730 * out of the loop. 2731 */ 2732 break; 2733 } 2734 /* 2735 * Don't report the error twice if both name and 2736 * type are missing. One error message is 2737 * adequate. 2738 */ 2739 reported_name = 1; 2740 } 2741 if ((pinfo->pi_type == NULL) && (reported_name == 0)) { 2742 rc = TVS_VALIDATION; 2743 if (pinfo->pi_ptrn_type == PG_PATTERN) { 2744 rv = add_scf_error(errs, 2745 SCF_TERR_PG_PATTERN_INCOMPLETE, 2746 pinfo->pi_ptrnpg, 2747 NULL, NULL, NULL, NULL, NULL); 2748 } else { 2749 rv = add_scf_error(errs, 2750 SCF_TERR_PROP_PATTERN_INCOMPLETE, 2751 pinfo->pi_enc_pgp, NULL, pinfo->pi_ptrnpg, 2752 NULL, NULL, NULL); 2753 } 2754 /* If we're unable to log errors, break out of loop. */ 2755 if (rv != 0) 2756 break; 2757 } 2758 } 2759 return (rc); 2760 } 2761 2762 /* 2763 * Look for pg_pattern definitions in general. general is either the 2764 * restarter serivce for inst or it is the global service. tree contains 2765 * the ptrn_info_t structures describing the pg_patterns for an instance. 2766 * For each general pg_pattern, see if the instance contains an overriding 2767 * definition in tree. If it does generate an error entry. 2768 * 2769 * If a redefinition is found, TVS_WARN is returned. This is because a 2770 * redefinition is not sufficient reason to inhibit the import operation. 2771 */ 2772 static tmpl_validate_status_t 2773 tmpl_scan_general(entity_t *general, uu_avl_t *tree, 2774 tmpl_level_t level, tmpl_errors_t *errs) 2775 { 2776 tmpl_level_t cur_level; 2777 error_info_t einfo; 2778 pgroup_t *pg; 2779 ptrn_info_t *ginfo = NULL; 2780 ptrn_info_t *match; 2781 tmpl_validate_status_t rc = TVS_SUCCESS; 2782 2783 /* 2784 * General services may not be in repository yet. It depends on 2785 * the order that manifests are imported. 2786 */ 2787 if (general == NULL) 2788 return (TVS_SUCCESS); 2789 2790 for (pg = uu_list_first(general->sc_pgroups); 2791 pg != NULL; 2792 pg = uu_list_next(general->sc_pgroups, pg)) { 2793 if (strcmp(pg->sc_pgroup_type, 2794 SCF_GROUP_TEMPLATE_PG_PATTERN) != 0) { 2795 /* Not a pg_pattern */ 2796 continue; 2797 } 2798 if (ginfo != NULL) 2799 ptrn_info_destroy(ginfo); 2800 ginfo = ptrn_info_create(pg); 2801 match = uu_avl_find(tree, ginfo, NULL, NULL); 2802 if (match != NULL) { 2803 /* See if global pg_pattern is targeted at us. */ 2804 if (target_check(ginfo->pi_target, level) == 0) 2805 continue; 2806 2807 /* 2808 * See if the match applies to us. If we happen to 2809 * be a restarter, the pg_pattern could have a 2810 * target of delegate. That wouldn't apply to this 2811 * instance, it would only apply to our delegates. 2812 * Cases such as this are not a redefinition. 2813 */ 2814 if (match->pi_ptrnpg->sc_parent->sc_etype == 2815 SVCCFG_INSTANCE_OBJECT) { 2816 cur_level = TL_INSTANCE; 2817 } else { 2818 cur_level = TL_SERVICE; 2819 } 2820 if (target_check(match->pi_target, cur_level) == 0) 2821 continue; 2822 2823 /* 2824 * Instance or service overrides a general 2825 * definition. We need to issue a warning message. 2826 */ 2827 rc = TVS_WARN; 2828 CLEAR_ERROR_INFO(&einfo); 2829 einfo.ei_type = EIT_PATTERN_CONFLICT; 2830 einfo.ei_u.ei_pattern_conflict.ei_pattern = pg; 2831 if (add_scf_error(errs, SCF_TERR_GENERAL_REDEFINE, 2832 match->pi_ptrnpg, NULL, NULL, NULL, NULL, 2833 &einfo) != 0) { 2834 /* 2835 * No need to continue the search if we 2836 * cannot record errors. 2837 */ 2838 break; 2839 } 2840 } 2841 } 2842 2843 if (ginfo != NULL) 2844 ptrn_info_destroy(ginfo); 2845 return (rc); 2846 } 2847 2848 /* 2849 * tree contains the pg_pattern definitions for the instance at inst. See 2850 * if these pg_patterns redefine any pg_patterns in the instance's 2851 * restarter or in the global service. TVS_WARN is returned if a 2852 * redefinition is encountered. 2853 */ 2854 static tmpl_validate_status_t 2855 tmpl_level_redefine(entity_t *inst, uu_avl_t *tree, tmpl_errors_t *errs) 2856 { 2857 entity_t *restarter; 2858 entity_t *svc = inst->sc_parent; 2859 tmpl_validate_status_t r; 2860 tmpl_validate_status_t rc; 2861 2862 restarter = inst->sc_u.sc_instance.sc_instance_restarter; 2863 if (restarter == NULL) { 2864 /* No instance restarter. Use the service restarter */ 2865 restarter = svc->sc_u.sc_service.sc_restarter; 2866 } 2867 rc = tmpl_scan_general(restarter, tree, TL_RESTARTER, errs); 2868 r = tmpl_scan_general(svc->sc_u.sc_service.sc_global, tree, 2869 TL_GLOBAL, errs); 2870 if (r != TVS_SUCCESS) 2871 rc = r; 2872 return (rc); 2873 } 2874 2875 /* 2876 * Perform the following consistency checks on the template specifications 2877 * themselves: 2878 * 2879 * - No conflicting definitions of `pg_pattern` are allowed within a 2880 * single instance. 2881 * 2882 * - Templates at a narrow target (e.g. instance) which define 2883 * property groups already templated at a broad target 2884 * (e.g. restarter or all) are strongly discouraged. 2885 * 2886 * - Developers may not define a template which specifies a single 2887 * prop_pattern name with differing types on the same target 2888 * entity. 2889 * 2890 * - If a pg_pattern has a required attribute with a value of true, 2891 * then its name and type attributes must be specified. 2892 * 2893 * - If a prop_pattern has a required attribute with a value of true, 2894 * then its type attribute must be specified. 2895 * 2896 * - If a prop_pattern has an include values make sure that the 2897 * appropriate constraints or values element has also been 2898 * declared. 2899 */ 2900 static tmpl_validate_status_t 2901 tmpl_consistency(entity_t *inst, tmpl_errors_t *errs) 2902 { 2903 void *marker = NULL; 2904 ptrn_info_t *info; 2905 uu_avl_t *tree; 2906 tmpl_validate_status_t rc; 2907 tmpl_validate_status_t r; 2908 2909 /* Allocate the tree. */ 2910 tree = uu_avl_create(ptrn_info_pool, NULL, TMPL_DEBUG_TREE); 2911 if (tree == NULL) { 2912 uu_die(gettext("pg_info tree creation failed: %s\n"), 2913 uu_strerror(uu_error())); 2914 } 2915 2916 rc = tmpl_pattern_conflict(inst, tree, PG_PATTERN, errs); 2917 2918 /* 2919 * The tree now contains the instance and service pg_patterns. 2920 * Check to see if they override any pg_pattern definitions in the 2921 * restarter and global services. 2922 */ 2923 r = tmpl_level_redefine(inst, tree, errs); 2924 if (r != TVS_SUCCESS) { 2925 /* 2926 * tmpl_level_redefine() can return a warning. Don't 2927 * override a serious error with a warning. 2928 */ 2929 if (r == TVS_WARN) { 2930 if (rc == TVS_SUCCESS) 2931 rc = r; 2932 } else { 2933 rc = r; 2934 } 2935 } 2936 2937 /* 2938 * If the pg_pattern has a required attribute with a value of true, 2939 * then it must also have name and type attributes. 2940 */ 2941 r = tmpl_required_attr_present(tree, errs); 2942 if (r != TVS_SUCCESS) 2943 rc = r; 2944 2945 /* Empty the tree, so that we can reuse it for prop_patterns. */ 2946 while ((info = uu_avl_teardown(tree, &marker)) != NULL) { 2947 ptrn_info_destroy(info); 2948 } 2949 2950 r = tmpl_pattern_conflict(inst, tree, PROP_PATTERN, errs); 2951 if (r != TVS_SUCCESS) 2952 rc = r; 2953 2954 /* 2955 * If a prop_pattern has required attribute with a value of true, 2956 * then it must also have a type attribute. 2957 */ 2958 r = tmpl_required_attr_present(tree, errs); 2959 if (r != TVS_SUCCESS) 2960 rc = r; 2961 2962 /* 2963 * Insure that include_values have the constraint for values 2964 * elements that are needed. 2965 */ 2966 r = tmpl_include_values_check(tree, errs); 2967 if (r != TVS_SUCCESS) 2968 rc = r; 2969 2970 /* Tear down the tree. */ 2971 marker = NULL; 2972 while ((info = uu_avl_teardown(tree, &marker)) != NULL) { 2973 ptrn_info_destroy(info); 2974 } 2975 uu_avl_destroy(tree); 2976 2977 return (rc); 2978 } 2979 2980 /* 2981 * Release memory associated with the tmpl_errors structure and then free 2982 * the structure itself. 2983 */ 2984 void 2985 tmpl_errors_destroy(tmpl_errors_t *te) 2986 { 2987 im_tmpl_error_t *ite; 2988 tv_errors_t *ste; 2989 void *marker = NULL; 2990 2991 if (te == NULL) 2992 return; 2993 if (te->te_list) { 2994 while ((ite = uu_list_teardown(te->te_list, &marker)) != NULL) { 2995 uu_list_node_fini(ite, &ite->ite_node, 2996 inmem_errors_pool); 2997 uu_free(ite); 2998 } 2999 uu_list_destroy(te->te_list); 3000 } 3001 if (te->te_scf) { 3002 marker = NULL; 3003 while ((ste = uu_list_teardown(te->te_scf, &marker)) != NULL) { 3004 destroy_scf_errors(ste); 3005 } 3006 uu_list_destroy(te->te_scf); 3007 } 3008 uu_free(te); 3009 } 3010 3011 /* 3012 * Allocate and initialize a tmpl_errors structure. The address of the 3013 * structure is returned, unless we are unable to allocate enough memory. 3014 * In the case of memory allocation failures, NULL is returned. 3015 * 3016 * The allocated structure should be freed by calling 3017 * tmpl_errors_destroy(). 3018 */ 3019 static tmpl_errors_t * 3020 tmpl_errors_create() 3021 { 3022 tmpl_errors_t *te; 3023 3024 te = uu_zalloc(sizeof (*te)); 3025 if (te == NULL) 3026 return (NULL); 3027 te->te_list = uu_list_create(inmem_errors_pool, NULL, TMPL_DEBUG_LIST); 3028 if (te->te_list == NULL) { 3029 uu_free(te); 3030 return (NULL); 3031 } 3032 te->te_scf = uu_list_create(tv_errors_pool, NULL, TMPL_DEBUG_LIST); 3033 if (te->te_scf == NULL) { 3034 tmpl_errors_destroy(te); 3035 return (NULL); 3036 } 3037 3038 return (te); 3039 } 3040 3041 void 3042 tmpl_errors_print(FILE *out, tmpl_errors_t *errs, const char *prefix) 3043 { 3044 scf_tmpl_error_t *cur; 3045 size_t buf_size = 4096; 3046 im_tmpl_error_t *ite; 3047 char *s = NULL; 3048 scf_tmpl_errors_t *scferrs; 3049 tv_errors_t *scft; 3050 int interactive = (est->sc_cmd_flags & SC_CMD_IACTIVE) ? 3051 SCF_TMPL_STRERROR_HUMAN : 0; 3052 3053 for (ite = uu_list_first(errs->te_list); 3054 ite != NULL; 3055 ite = uu_list_next(errs->te_list, ite)) { 3056 im_tmpl_error_print(out, ite, prefix); 3057 } 3058 3059 /* Now handle the errors that can be printed via libscf. */ 3060 s = safe_malloc(buf_size); 3061 for (scft = uu_list_first(errs->te_scf); 3062 scft != NULL; 3063 scft = uu_list_next(errs->te_scf, scft)) { 3064 scferrs = scft->tve_errors; 3065 if (_scf_tmpl_error_set_prefix(scferrs, prefix) != 0) 3066 uu_die(emesg_nomem); 3067 while ((cur = scf_tmpl_next_error(scferrs)) != NULL) { 3068 (void) scf_tmpl_strerror(cur, s, buf_size, interactive); 3069 (void) fputs(s, out); 3070 (void) fputc('\n', out); 3071 } 3072 } 3073 3074 free(s); 3075 } 3076 3077 /* 3078 * This function finds the prop_pattern for the property, prop. e is the 3079 * instance where the search for the prop_pattern will start. pg_pattern 3080 * is the address of the pg_pattern that holds the prop_pattern. 3081 */ 3082 static tmpl_validate_status_t 3083 tmpl_find_prop_pattern(entity_t *inst, pgroup_t *pg_pattern, 3084 property_t *prop, pgroup_t **prop_pattern) 3085 { 3086 pgroup_t *candidate; 3087 pg_iter_t *iter = NULL; 3088 char *prop_pattern_name = NULL; 3089 tmpl_validate_status_t rc; 3090 3091 /* 3092 * Get the name of the property group that holds the prop_pattern 3093 * definition. 3094 */ 3095 rc = gen_prop_pattern_pg_name(pg_pattern, 3096 prop->sc_property_name, &prop_pattern_name); 3097 if (rc != TVS_SUCCESS) 3098 goto out; 3099 3100 /* Find the property group. */ 3101 iter = pg_iter_create(inst, SCF_GROUP_TEMPLATE_PROP_PATTERN); 3102 if (iter == NULL) 3103 goto out; 3104 while ((candidate = next_pattern_pg(iter)) != NULL) { 3105 const char *c; 3106 3107 if (strcmp(prop_pattern_name, candidate->sc_pgroup_name) != 0) 3108 continue; 3109 c = find_astring_value_in_pg(candidate, 3110 SCF_PROPERTY_TM_PG_PATTERN); 3111 if (c == NULL) 3112 continue; 3113 if (strcmp(pg_pattern->sc_pgroup_name, c) == 0) 3114 break; 3115 } 3116 *prop_pattern = candidate; 3117 if (candidate == NULL) 3118 rc = TVS_NOMATCH; 3119 3120 out: 3121 pg_iter_destroy(iter); 3122 uu_free((void *)prop_pattern_name); 3123 return (rc); 3124 } 3125 3126 /* 3127 * Indexes for pg_pattern property group names. Indexes are arranged 3128 * from most specific to least specific. 3129 */ 3130 #define PGN_BOTH 0 /* both name and type */ 3131 #define PGN_NAME 1 /* name only */ 3132 #define PGN_TYPE 2 /* type only */ 3133 #define PGN_NEITHER 3 /* neither name nor type */ 3134 #define PGN_MAX 4 /* Size of array */ 3135 3136 /* 3137 * Given an instance entity, e, and a propety group, pg, within the 3138 * instance; return the address of the pg_pattern for the property group. 3139 * The address of the pg_pattern is placed at pgp. NULL indicates that no 3140 * pg_pattern was specified. 3141 */ 3142 static tmpl_validate_status_t 3143 tmpl_find_pg_pattern(entity_t *e, pgroup_t *pg, pgroup_t **pgp) 3144 { 3145 pgroup_t *cpg; /* candidate property group */ 3146 int i; 3147 pg_iter_t *iter = NULL; 3148 char *pg_names[PGN_MAX]; 3149 pgroup_t *pg_patterns[PGN_MAX]; 3150 tmpl_validate_status_t rv = TVS_SUCCESS; 3151 3152 (void) memset(pg_patterns, 0, sizeof (pg_patterns)); 3153 *pgp = NULL; 3154 3155 /* Generate candidate names for pg_pattern property groups. */ 3156 pg_names[PGN_BOTH] = gen_pg_pattern_pg_name(pg->sc_pgroup_name, 3157 pg->sc_pgroup_type); 3158 pg_names[PGN_NAME] = gen_pg_pattern_pg_name(pg->sc_pgroup_name, 3159 NULL); 3160 pg_names[PGN_TYPE] = gen_pg_pattern_pg_name(NULL, 3161 pg->sc_pgroup_type); 3162 pg_names[PGN_NEITHER] = gen_pg_pattern_pg_name(NULL, NULL); 3163 for (i = 0; i < PGN_MAX; i++) { 3164 if (pg_names[i] == NULL) { 3165 rv = TVS_BAD_TEMPLATE; 3166 goto errout; 3167 } 3168 } 3169 3170 /* Search for property groups that match these names */ 3171 iter = pg_iter_create(e, SCF_GROUP_TEMPLATE_PG_PATTERN); 3172 if (iter == NULL) { 3173 uu_die(emesg_nomem); 3174 } 3175 while ((cpg = next_pattern_pg(iter)) != NULL) { 3176 if (pg_target_check(cpg, iter->pgi_level) == 0) 3177 continue; 3178 3179 /* See if we have a name match. */ 3180 for (i = 0; i < PGN_MAX; i++) { 3181 if (strcmp(cpg->sc_pgroup_name, pg_names[i]) == 0) { 3182 /* 3183 * If we already have a lower level 3184 * pg_pattern, keep it. 3185 */ 3186 if (pg_patterns[i] == NULL) 3187 pg_patterns[i] = cpg; 3188 break; 3189 } 3190 } 3191 } 3192 3193 /* Find the most specific pg_pattern. */ 3194 for (i = 0; i < PGN_MAX; i++) { 3195 if (pg_patterns[i] != NULL) { 3196 *pgp = pg_patterns[i]; 3197 break; 3198 } 3199 } 3200 errout: 3201 for (i = 0; i < PGN_MAX; i++) { 3202 free(pg_names[i]); 3203 } 3204 pg_iter_destroy(iter); 3205 return (rv); 3206 } 3207 3208 /* 3209 * Initialize structures that are required for validation using 3210 * templates specifications. 3211 */ 3212 void 3213 tmpl_init(void) 3214 { 3215 emesg_nomem = gettext("Out of memory.\n"); 3216 3217 composed_pg_pool = uu_avl_pool_create("composed_pg", 3218 sizeof (composed_pg_t), offsetof(composed_pg_t, cpg_node), 3219 composed_pg_compare, TMPL_DEBUG_AVL_POOL); 3220 if (composed_pg_pool == NULL) { 3221 uu_die(gettext("composed_pg pool creation failed: %s\n"), 3222 uu_strerror(uu_error())); 3223 } 3224 composed_prop_pool = uu_avl_pool_create("composed_prop", 3225 sizeof (property_t), offsetof(property_t, sc_composed_node), 3226 composed_prop_compare, TMPL_DEBUG_AVL_POOL); 3227 if (composed_prop_pool == NULL) { 3228 uu_die(gettext("composed_prop pool creation failed. %s\n"), 3229 uu_strerror(uu_error())); 3230 } 3231 ptrn_info_pool = uu_avl_pool_create("ptrn_info", sizeof (ptrn_info_t), 3232 offsetof(ptrn_info_t, pi_link), ptrn_info_compare, 3233 TMPL_DEBUG_AVL_POOL); 3234 if (ptrn_info_pool == NULL) { 3235 uu_die(gettext("pg_pattern info pool creation failed: %s\n"), 3236 uu_strerror(uu_error())); 3237 } 3238 inmem_errors_pool = uu_list_pool_create("errors-internal", 3239 sizeof (im_tmpl_error_t), offsetof(im_tmpl_error_t, 3240 ite_node), NULL, TMPL_DEBUG_LIST_POOL); 3241 if (inmem_errors_pool == NULL) { 3242 uu_die(gettext("inmem_errors_pool pool creation failed: " 3243 "%s\n"), uu_strerror(uu_error())); 3244 } 3245 tv_errors_pool = uu_list_pool_create("scf-terrors", 3246 sizeof (tv_errors_t), offsetof(tv_errors_t, tve_node), 3247 NULL, TMPL_DEBUG_LIST_POOL); 3248 if (tv_errors_pool == NULL) { 3249 uu_die(gettext("tv_errors_pool pool creation failed: %s\n"), 3250 uu_strerror(uu_error())); 3251 } 3252 } 3253 3254 /* 3255 * Clean up the composed property node in the property. 3256 */ 3257 void 3258 tmpl_property_fini(property_t *p) 3259 { 3260 uu_avl_node_fini(p, &p->sc_composed_node, composed_prop_pool); 3261 } 3262 3263 /* 3264 * Initialize the composed property node in the property. 3265 */ 3266 void 3267 tmpl_property_init(property_t *p) 3268 { 3269 uu_avl_node_init(p, &p->sc_composed_node, composed_prop_pool); 3270 } 3271 3272 /* 3273 * Use the cardinality specification in the prop_pattern to verify the 3274 * cardinality of the property at prop. The cardinality of the property is 3275 * the number of values that it has. 3276 * 3277 * pg is the property group that holds prop, and pg_pattern is the 3278 * pg_pattern for the property group. pg and pg_pattern are only used for 3279 * error reporting. 3280 */ 3281 static tmpl_validate_status_t 3282 tmpl_validate_cardinality(pgroup_t *prop_pattern, property_t *prop, 3283 pgroup_t *pg, pgroup_t *pg_pattern, tmpl_errors_t *errs) 3284 { 3285 size_t count; 3286 uint64_t max; 3287 uint64_t min; 3288 tmpl_validate_status_t rc; 3289 error_info_t einfo; 3290 3291 assert(strcmp(prop_pattern->sc_pgroup_type, 3292 SCF_GROUP_TEMPLATE_PROP_PATTERN) == 0); 3293 3294 rc = get_cardinality(prop_pattern, &min, &max); 3295 switch (rc) { 3296 case TVS_NOMATCH: 3297 /* Nothing to check. */ 3298 return (TVS_SUCCESS); 3299 case TVS_SUCCESS: 3300 /* Process the limits. */ 3301 break; 3302 default: 3303 return (rc); 3304 } 3305 3306 if ((min == 0) && (max == ULLONG_MAX)) { 3307 /* Any number of values is permitted. No need to count. */ 3308 return (TVS_SUCCESS); 3309 } 3310 3311 count = count_prop_values(prop); 3312 if ((count < min) || (count > max)) { 3313 CLEAR_ERROR_INFO(&einfo); 3314 einfo.ei_type = EIT_CARDINALITY; 3315 einfo.ei_u.ei_cardinality.ei_min = min; 3316 einfo.ei_u.ei_cardinality.ei_max = max; 3317 einfo.ei_u.ei_cardinality.ei_count = count; 3318 (void) add_scf_error(errs, SCF_TERR_CARDINALITY_VIOLATION, 3319 pg_pattern, pg, prop_pattern, prop, NULL, &einfo); 3320 return (TVS_VALIDATION); 3321 } 3322 3323 return (TVS_SUCCESS); 3324 } 3325 3326 /* 3327 * Iterate over pg_patterns in the entity, e. If the pg_pattern's required 3328 * attribute is true, verify that the entity contains the corresponding 3329 * property group. 3330 */ 3331 static tmpl_validate_status_t 3332 tmpl_required_pg_present(entity_t *e, tmpl_errors_t *errs) 3333 { 3334 composed_pg_t cpg; 3335 composed_pg_t *match; 3336 error_info_t einfo; 3337 pg_iter_t *iter; 3338 pgroup_t *pg; 3339 const char *pg_name; 3340 const char *pg_type; 3341 tmpl_validate_status_t rc = TVS_SUCCESS; 3342 uu_avl_t *tree; 3343 3344 assert(e->sc_etype == SVCCFG_INSTANCE_OBJECT); 3345 3346 iter = pg_iter_create(e, SCF_GROUP_TEMPLATE_PG_PATTERN); 3347 if (iter == NULL) 3348 uu_die(emesg_nomem); 3349 3350 CLEAR_ERROR_INFO(&einfo); 3351 einfo.ei_type = EIT_MISSING_PG; 3352 3353 while ((pg = next_pattern_pg(iter)) != NULL) { 3354 if (is_required(pg) == 0) { 3355 /* If pg is not required, there is nothing to check. */ 3356 continue; 3357 } 3358 pg_name = find_astring_value_in_pg(pg, SCF_PROPERTY_TM_NAME); 3359 pg_type = find_astring_value_in_pg(pg, SCF_PROPERTY_TM_TYPE); 3360 if (pg_target_check(pg, iter->pgi_level) == 0) 3361 continue; 3362 einfo.ei_u.ei_missing_pg.ei_pg_name = pg_name; 3363 einfo.ei_u.ei_missing_pg.ei_pg_type = pg_type; 3364 tree = e->sc_u.sc_instance.sc_composed; 3365 (void) memset(&cpg, 0, sizeof (cpg)); 3366 cpg.cpg_name = pg_name; 3367 cpg.cpg_type = pg_type; 3368 match = uu_avl_find(tree, &cpg, NULL, NULL); 3369 if (match == NULL) { 3370 rc = TVS_VALIDATION; 3371 if (add_scf_error(errs, SCF_TERR_MISSING_PG, pg, 3372 NULL, NULL, NULL, NULL, &einfo) != 0) { 3373 break; 3374 } 3375 } 3376 } 3377 3378 pg_iter_destroy(iter); 3379 return (rc); 3380 } 3381 3382 /* 3383 * Verify that the property group, pg, contains property declarations for 3384 * all required properties. Unfortunately, there is no direct way to find 3385 * the prop_patterns for a given property group. Therefore, we need to 3386 * scan the entity at e looking for property groups with a type of 3387 * SCF_GROUP_TEMPLATE_PROP_PATTERN. That is, we scan the entity looking 3388 * for all prop_patterns. When we find a prop_pattern, we look at the 3389 * value of its pg_pattern property to see if it matches the name of the 3390 * pg_pattern. If they match, this is a prop_pattern that is of interest 3391 * to us. 3392 * 3393 * When we find an interesting prop_pattern, we see if it's required 3394 * property is true. If it is, we verify that the property group at pg 3395 * contains the specified property. 3396 */ 3397 static tmpl_validate_status_t 3398 tmpl_required_props_present(entity_t *e, pgroup_t *pg, pgroup_t *pg_pattern, 3399 tmpl_errors_t *errs) 3400 { 3401 error_info_t einfo; 3402 pg_iter_t *iter; 3403 const char *prop_name; 3404 const char *prop_pg_pattern_name; 3405 pgroup_t *prop_pattern; 3406 scf_tmpl_error_type_t ec; 3407 tmpl_validate_status_t rc = TVS_SUCCESS; 3408 3409 /* 3410 * Scan the entity's property groups looking for ones with a type 3411 * of SCF_GROUP_TEMPLATE_PROP_PATTERN. 3412 */ 3413 iter = pg_iter_create(e, SCF_GROUP_TEMPLATE_PROP_PATTERN); 3414 if (iter == NULL) 3415 uu_die(emesg_nomem); 3416 CLEAR_ERROR_INFO(&einfo); 3417 for (prop_pattern = next_pattern_pg(iter); 3418 prop_pattern != NULL; 3419 prop_pattern = next_pattern_pg(iter)) { 3420 /* 3421 * Find the pg_pattern property in this prop_pattern. 3422 * Verify that its value matches the name of the 3423 * pg_pattern. 3424 */ 3425 prop_pg_pattern_name = find_astring_value_in_pg(prop_pattern, 3426 SCF_PROPERTY_TM_PG_PATTERN); 3427 assert(prop_pg_pattern_name != NULL); 3428 if (strcmp(pg_pattern->sc_pgroup_name, 3429 prop_pg_pattern_name) != 0) { 3430 continue; 3431 } 3432 3433 /* If the property is required, see if it is in the pg. */ 3434 if (is_required(prop_pattern) == 0) 3435 continue; 3436 prop_name = find_astring_value_in_pg(prop_pattern, 3437 SCF_PROPERTY_TM_NAME); 3438 assert(prop_name != NULL); 3439 if (property_find(pg, prop_name) == NULL) { 3440 ec = SCF_TERR_MISSING_PROP; 3441 rc = TVS_VALIDATION; 3442 einfo.ei_type = EIT_MISSING_PROP; 3443 einfo.ei_u.ei_missing_prop.ei_prop_name = prop_name; 3444 if (add_scf_error(errs, ec, pg_pattern, pg, 3445 prop_pattern, NULL, NULL, &einfo) != 0) { 3446 /* 3447 * If we can no longer accumulate errors, 3448 * break out of the loop. 3449 */ 3450 break; 3451 } 3452 } 3453 } 3454 3455 pg_iter_destroy(iter); 3456 return (rc); 3457 } 3458 3459 /* 3460 * Check the value at v to see if it falls within any of the ranges at r. 3461 * count is the number of ranges at r, and type tells whether to treat the 3462 * value as signed or unsigned. 3463 * 3464 * Return 1 if the value falls within one of the ranges. Otherwise return 3465 * 0. 3466 */ 3467 static int 3468 value_in_range(value_t *v, scf_type_t type, range_t *r, size_t count) 3469 { 3470 for (; count > 0; --count, r++) { 3471 if (type == SCF_TYPE_COUNT) { 3472 if ((v->sc_u.sc_count >= 3473 r->rng_u.rng_unsigned.rng_min) && 3474 (v->sc_u.sc_count <= 3475 r->rng_u.rng_unsigned.rng_max)) 3476 return (1); 3477 } else { 3478 if ((v->sc_u.sc_integer >= 3479 r->rng_u.rng_signed.rng_min) && 3480 (v->sc_u.sc_integer <= 3481 r->rng_u.rng_signed.rng_max)) 3482 return (1); 3483 } 3484 } 3485 return (0); 3486 } 3487 3488 /* 3489 * If the template prop_pattern at pattern contains a constraint_range 3490 * property, use the specified range to validate all the numeric property 3491 * values of the property at prop. 3492 * 3493 * pg is the property group that holds prop, and pg_pattern is the 3494 * pg_pattern for the property group. pg and pg_pattern are only used for 3495 * error reporting. 3496 */ 3497 static tmpl_validate_status_t 3498 tmpl_validate_value_range(pgroup_t *pattern, property_t *prop, pgroup_t *pg, 3499 pgroup_t *pg_pattern, tmpl_errors_t *errs) 3500 { 3501 uint_t count; 3502 error_info_t einfo; 3503 property_t *range_prop; 3504 range_t *ranges; 3505 tmpl_validate_status_t rc; 3506 scf_type_t type; 3507 value_t *v; 3508 3509 /* Get the range constraints if they exist. */ 3510 if ((range_prop = property_find(pattern, 3511 SCF_PROPERTY_TM_CONSTRAINT_RANGE)) == NULL) { 3512 /* No range to check. */ 3513 return (TVS_SUCCESS); 3514 } 3515 type = prop->sc_value_type; 3516 if ((type != SCF_TYPE_COUNT) && (type != SCF_TYPE_INTEGER)) { 3517 rc = TVS_BAD_TEMPLATE; 3518 CLEAR_ERROR_INFO(&einfo); 3519 einfo.ei_type = EIT_BAD_TEMPLATE; 3520 einfo.ei_u.ei_bad_template.ei_reason = 3521 gettext("Property does not have correct type for " 3522 "a range specification"); 3523 (void) tmpl_errors_add_im(errs, rc, pg_pattern->sc_parent, 3524 pg_pattern, pg, pattern, prop, NULL, &einfo); 3525 return (rc); 3526 } 3527 if ((rc = get_ranges(range_prop, prop->sc_value_type, &ranges, 3528 &count)) != TVS_SUCCESS) { 3529 rc = TVS_BAD_TEMPLATE; 3530 CLEAR_ERROR_INFO(&einfo); 3531 einfo.ei_type = EIT_BAD_TEMPLATE; 3532 einfo.ei_u.ei_bad_template.ei_reason = gettext("Illegal range " 3533 "value"); 3534 (void) tmpl_errors_add_im(errs, rc, pg_pattern->sc_parent, 3535 pg_pattern, pg, pattern, prop, NULL, &einfo); 3536 return (rc); 3537 } 3538 3539 /* Set up error info before entering loop. */ 3540 CLEAR_ERROR_INFO(&einfo); 3541 einfo.ei_type = EIT_RANGE; 3542 einfo.ei_u.ei_range.ei_rtype = type; 3543 3544 /* Compare numeric values of the property to the range. */ 3545 for (v = uu_list_first(prop->sc_property_values); 3546 v != NULL; 3547 v = uu_list_next(prop->sc_property_values, v)) { 3548 if (value_in_range(v, type, ranges, count) == 1) 3549 continue; 3550 if (type == SCF_TYPE_COUNT) { 3551 einfo.ei_u.ei_range.ei_uvalue = v->sc_u.sc_count; 3552 } else { 3553 einfo.ei_u.ei_range.ei_ivalue = v->sc_u.sc_integer; 3554 } 3555 rc = TVS_VALIDATION; 3556 if (add_scf_error(errs, SCF_TERR_RANGE_VIOLATION, pg_pattern, 3557 pg, pattern, prop, v, &einfo) != 0) { 3558 return (rc); 3559 } 3560 } 3561 3562 return (rc); 3563 } 3564 3565 /* 3566 * If the prop_pattern has value constraints, verify that all the values 3567 * for the property at prop are legal values. 3568 * 3569 * pg is the property group that holds prop, and pg_pattern is the 3570 * pg_pattern for the property group. pg and pg_pattern are only used for 3571 * error reporting. 3572 */ 3573 static tmpl_validate_status_t 3574 tmpl_validate_values(pgroup_t *prop_pattern, property_t *prop, pgroup_t *pg, 3575 pgroup_t *pg_pattern, tmpl_errors_t *errs) 3576 { 3577 int found; 3578 uint_t i; 3579 avalues_t *legal; 3580 tmpl_validate_status_t r; 3581 tmpl_validate_status_t rc = TVS_SUCCESS; 3582 value_t *v; 3583 3584 /* Get list of legal values. */ 3585 r = av_get_values(prop_pattern, SCF_PROPERTY_TM_CONSTRAINT_NAME, 3586 prop->sc_value_type, &legal); 3587 switch (r) { 3588 case TVS_BAD_CONVERSION: 3589 (void) tmpl_errors_add_im(errs, r, pg->sc_parent, pg_pattern, 3590 pg, prop_pattern, prop, NULL, NULL); 3591 return (r); 3592 case TVS_NOMATCH: 3593 /* No constraints in template. */ 3594 return (TVS_SUCCESS); 3595 case TVS_SUCCESS: 3596 /* process the constraints. */ 3597 break; 3598 default: 3599 assert(0); 3600 abort(); 3601 } 3602 3603 /* Check the property values against the legal values. */ 3604 for (v = uu_list_first(prop->sc_property_values); 3605 v != NULL; 3606 v = uu_list_next(prop->sc_property_values, v)) { 3607 /* Check this property value against the legal values. */ 3608 found = 0; 3609 for (i = 0; (i < legal->av_count) && (found == 0); i++) { 3610 switch (v->sc_type) { 3611 case SCF_TYPE_BOOLEAN: 3612 case SCF_TYPE_COUNT: 3613 if (av_get_unsigned(legal, i) == 3614 v->sc_u.sc_count) { 3615 found = 1; 3616 } 3617 break; 3618 case SCF_TYPE_INTEGER: 3619 if (av_get_integer(legal, i) == 3620 v->sc_u.sc_integer) { 3621 found = 1; 3622 } 3623 break; 3624 default: 3625 if (strcmp(av_get_string(legal, i), 3626 v->sc_u.sc_string) == 0) { 3627 found = 1; 3628 } 3629 break; 3630 } 3631 } 3632 if (found == 0) { 3633 rc = TVS_VALIDATION; 3634 if (add_scf_error(errs, 3635 SCF_TERR_VALUE_CONSTRAINT_VIOLATED, pg_pattern, pg, 3636 prop_pattern, prop, v, NULL) != 0) { 3637 /* 3638 * Exit loop if no longer able to report 3639 * errors. 3640 */ 3641 break; 3642 } 3643 } 3644 } 3645 3646 out: 3647 av_destroy(legal); 3648 return (rc); 3649 } 3650 3651 /* 3652 * Verify the following items about the values of property, prop. 3653 * 3654 * - The values all have the type specified by the prop_pattern at 3655 * pattern. 3656 * - Check numeric values against range constraints. 3657 * - If the prop_pattern has one or more value constraints, validate 3658 * the property's values against the constraints. 3659 * 3660 * pg is the property group that holds prop, and pg_pattern is the 3661 * pg_pattern for the property group. pg and pg_pattern are only used for 3662 * error reporting. 3663 */ 3664 static tmpl_validate_status_t 3665 tmpl_validate_value_constraints(pgroup_t *pattern, property_t *prop, 3666 pgroup_t *pg, pgroup_t *pg_pattern, tmpl_errors_t *errs) 3667 { 3668 tmpl_validate_status_t r; 3669 tmpl_validate_status_t rc; 3670 3671 rc = tmpl_validate_value_range(pattern, prop, pg, pg_pattern, errs); 3672 r = tmpl_validate_values(pattern, prop, pg, pg_pattern, errs); 3673 if (r != TVS_SUCCESS) 3674 rc = r; 3675 3676 return (rc); 3677 } 3678 3679 /* 3680 * Perform the following validations on the property, prop. 3681 * 3682 * - Verify that the property's type agrees with the type specified in 3683 * the prop_pattern template, tmpl. 3684 * - Verify the cardinality. 3685 * - Verify that the property values satisfy the constraints specified 3686 * by the template. 3687 * 3688 * pg is the property group that holds prop, and pg_pattern is the 3689 * pg_pattern for the property group. pg and pg_pattern are only used for 3690 * error reporting. 3691 */ 3692 static tmpl_validate_status_t 3693 tmpl_validate_prop(property_t *prop, pgroup_t *tmpl, pgroup_t *pg, 3694 pgroup_t *pg_pattern, tmpl_errors_t *errs) 3695 { 3696 scf_tmpl_error_type_t ec; 3697 error_info_t einfo; 3698 tmpl_validate_status_t r; 3699 tmpl_validate_status_t rc = TVS_SUCCESS; 3700 int status; 3701 scf_type_t type; 3702 3703 r = prop_pattern_type(tmpl, &type); 3704 switch (r) { 3705 case TVS_SUCCESS: 3706 if (type == SCF_TYPE_INVALID) { 3707 rc = TVS_INVALID_TYPE_SPECIFICATION; 3708 r = tmpl_errors_add_im(errs, rc, pg->sc_parent, NULL, 3709 pg, tmpl, NULL, NULL, NULL); 3710 if (r != TVS_SUCCESS) { 3711 /* 3712 * Give up if we can no longer accumulate 3713 * errors. 3714 */ 3715 return (rc); 3716 } 3717 } else { 3718 if (property_is_type(prop, type) == 0) { 3719 CLEAR_ERROR_INFO(&einfo); 3720 rc = TVS_VALIDATION; 3721 ec = SCF_TERR_WRONG_PROP_TYPE; 3722 einfo.ei_type = EIT_PROP_TYPE; 3723 einfo.ei_u.ei_prop_type.ei_specified = type; 3724 einfo.ei_u.ei_prop_type.ei_actual = 3725 prop->sc_value_type; 3726 status = add_scf_error(errs, ec, 3727 pg_pattern, pg, tmpl, prop, NULL, &einfo); 3728 if (status != 0) { 3729 /* 3730 * Give up if we can no longer 3731 * accumulate errors. 3732 */ 3733 return (rc); 3734 } 3735 } 3736 } 3737 break; 3738 case TVS_MISSING_TYPE_SPECIFICATION: 3739 /* 3740 * A null type specification means that we do not need to 3741 * check the property's type. 3742 */ 3743 break; 3744 default: 3745 rc = r; 3746 } 3747 3748 /* Validate the cardinality */ 3749 r = tmpl_validate_cardinality(tmpl, prop, pg, pg_pattern, errs); 3750 if (r != TVS_SUCCESS) 3751 rc = r; 3752 3753 /* Validate that property values satisfy constraints. */ 3754 r = tmpl_validate_value_constraints(tmpl, prop, pg, pg_pattern, errs); 3755 if (r != TVS_SUCCESS) 3756 rc = r; 3757 3758 return (rc); 3759 } 3760 3761 /* 3762 * Validate the property group at pg by performing the following checks: 3763 * 3764 * - Verify that the types of the pg and the pg_pattern are 3765 * compatible. 3766 * - Verify the properties in the pg. 3767 * - Verify that required properties are present. 3768 */ 3769 static tmpl_validate_status_t 3770 tmpl_validate_pg(entity_t *e, pgroup_t *pg, tmpl_errors_t *errs) 3771 { 3772 error_info_t einfo; 3773 const char *pg_pattern_type; /* Type declared by pg_pattern. */ 3774 pgroup_t *pg_pattern; /* Prop. group for pg_pattern */ 3775 property_t *prop; 3776 pgroup_t *prop_pattern; 3777 tmpl_validate_status_t r; 3778 tmpl_validate_status_t rc = TVS_SUCCESS; 3779 int stat; 3780 3781 /* 3782 * See if there is a pg_pattern for this property group. If it 3783 * exists, use it to validate the property group. If there is no 3784 * pg_pattern, then there is no validation to do. 3785 */ 3786 rc = tmpl_find_pg_pattern(e, pg, &pg_pattern); 3787 switch (rc) { 3788 case TVS_SUCCESS: 3789 break; 3790 case TVS_BAD_TEMPLATE: 3791 CLEAR_ERROR_INFO(&einfo); 3792 einfo.ei_type = EIT_BAD_TEMPLATE; 3793 einfo.ei_u.ei_bad_template.ei_reason = gettext("Property " 3794 "group name too long"); 3795 (void) tmpl_errors_add_im(errs, rc, e, NULL, pg, NULL, NULL, 3796 NULL, &einfo); 3797 return (rc); 3798 default: 3799 assert(0); 3800 abort(); 3801 } 3802 if (pg_pattern == NULL) 3803 return (TVS_SUCCESS); 3804 3805 /* 3806 * If the pg_pattern declares a type, verify that the PG has the 3807 * correct type. 3808 */ 3809 pg_pattern_type = find_type_specification(pg_pattern); 3810 if ((pg_pattern_type != NULL) && 3811 (*pg_pattern_type != 0)) { 3812 if ((pg->sc_pgroup_type != NULL) && 3813 (*(pg->sc_pgroup_type) != 0)) { 3814 if (strcmp(pg_pattern_type, 3815 pg->sc_pgroup_type) != 0) { 3816 rc = TVS_VALIDATION; 3817 stat = add_scf_error(errs, 3818 SCF_TERR_WRONG_PG_TYPE, pg_pattern, pg, 3819 NULL, NULL, NULL, NULL); 3820 if (stat != 0) { 3821 /* 3822 * If we can no longer accumulate 3823 * errors, return without trying to 3824 * do further validation. 3825 */ 3826 return (rc); 3827 } 3828 } 3829 } else { 3830 rc = TVS_MISSING_PG_TYPE; 3831 r = tmpl_errors_add_im(errs, rc, e, pg_pattern, pg, 3832 NULL, NULL, NULL, NULL); 3833 if (r != TVS_SUCCESS) { 3834 /* 3835 * If we can no longer accumulate errors, 3836 * return without trying to do further 3837 * validation. 3838 */ 3839 return (rc); 3840 } 3841 } 3842 } 3843 3844 /* Verify the properties in the property group. */ 3845 prop = NULL; 3846 while ((prop = next_property(pg, prop)) != NULL) { 3847 r = tmpl_find_prop_pattern(e, pg_pattern, prop, &prop_pattern); 3848 switch (r) { 3849 case TVS_SUCCESS: 3850 /* Found match. Validate property. */ 3851 break; 3852 case TVS_NOMATCH: 3853 /* No prop_patern. Go on to next property. */ 3854 continue; 3855 case TVS_BAD_TEMPLATE: 3856 CLEAR_ERROR_INFO(&einfo); 3857 einfo.ei_type = EIT_BAD_TEMPLATE; 3858 einfo.ei_u.ei_bad_template.ei_reason = 3859 gettext("prop_pattern name too long"); 3860 (void) tmpl_errors_add_im(errs, r, e, NULL, pg, NULL, 3861 NULL, NULL, &einfo); 3862 continue; 3863 default: 3864 assert(0); 3865 abort(); 3866 } 3867 r = tmpl_validate_prop(prop, prop_pattern, pg, pg_pattern, 3868 errs); 3869 if (r != TVS_SUCCESS) 3870 rc = r; 3871 } 3872 3873 /* 3874 * Confirm required properties are present. 3875 */ 3876 r = tmpl_required_props_present(e, pg, pg_pattern, errs); 3877 if (r != TVS_SUCCESS) 3878 rc = r; 3879 3880 return (rc); 3881 } 3882 3883 /* 3884 * Validate that the property groups in the entity conform to the template 3885 * specifications. Specifically, this means do the following: 3886 * 3887 * - Loop through the property groups in the entity skipping the ones 3888 * that are of type "template". 3889 * 3890 * - For the PG search for the corresponding template_pg_pattern 3891 * property group. It is possible that one may not exist. 3892 * 3893 * - Verify that the PG is in conformance with the pg_pattern 3894 * specification if it exists. 3895 */ 3896 static tmpl_validate_status_t 3897 tmpl_validate_entity_pgs(entity_t *e, tmpl_errors_t *errs) 3898 { 3899 composed_pg_t *cpg; 3900 uu_avl_t *pgroups; 3901 pgroup_t *pg; 3902 tmpl_validate_status_t r; 3903 tmpl_validate_status_t rc = TVS_SUCCESS; 3904 3905 assert(e->sc_etype == SVCCFG_INSTANCE_OBJECT); 3906 3907 pgroups = e->sc_u.sc_instance.sc_composed; 3908 for (cpg = uu_avl_first(pgroups); 3909 cpg != NULL; 3910 cpg = uu_avl_next(pgroups, cpg)) { 3911 if (strcmp(cpg->cpg_type, SCF_GROUP_TEMPLATE) == 0) 3912 continue; 3913 pg = CPG2PG(cpg); 3914 if ((r = tmpl_validate_pg(e, pg, errs)) != TVS_SUCCESS) 3915 rc = r; 3916 } 3917 3918 return (rc); 3919 } 3920 3921 /* 3922 * Validate the instance, e, by performing the following checks: 3923 * 3924 * - Verify template consistency. 3925 * 3926 * - Validate each property group in the entity is in conformance 3927 * with the template specifications. 3928 * 3929 * - Verify that all required property groups are present in the 3930 * entity. 3931 */ 3932 static tmpl_validate_status_t 3933 tmpl_validate_instance(entity_t *e, tmpl_errors_t *errs) 3934 { 3935 tmpl_validate_status_t r; 3936 tmpl_validate_status_t rc = TVS_SUCCESS; 3937 int status; 3938 tv_errors_t *ste; 3939 3940 /* Prepare to collect errors for this instance. */ 3941 ste = tv_errors_create(e->sc_fmri); 3942 status = uu_list_insert_after(errs->te_scf, errs->te_cur_scf, ste); 3943 assert(status == 0); 3944 errs->te_cur_scf = ste; 3945 3946 /* Verify template consistency */ 3947 rc = tmpl_consistency(e, errs); 3948 3949 /* Validate the property groups in the entity. */ 3950 r = tmpl_validate_entity_pgs(e, errs); 3951 if (r != TVS_SUCCESS) 3952 rc = r; 3953 3954 /* Verify that all required property groups are present. */ 3955 r = tmpl_required_pg_present(e, errs); 3956 if (r != TVS_SUCCESS) 3957 rc = r; 3958 3959 return (rc); 3960 } 3961 3962 /* 3963 * First validate the instances of the service. 3964 */ 3965 static tmpl_validate_status_t 3966 tmpl_validate_service(entity_t *svc, tmpl_errors_t *errs) 3967 { 3968 entity_t *inst; 3969 tmpl_validate_status_t r; 3970 tmpl_validate_status_t rc = TVS_SUCCESS; 3971 3972 assert(svc->sc_etype == SVCCFG_SERVICE_OBJECT); 3973 3974 load_general_templates(svc); 3975 3976 /* Validate the service's instances. */ 3977 for (inst = uu_list_first(svc->sc_u.sc_service.sc_service_instances); 3978 inst != NULL; 3979 inst = uu_list_next(svc->sc_u.sc_service.sc_service_instances, 3980 inst)) { 3981 load_instance_restarter(inst); 3982 build_composed_instance(inst); 3983 r = tmpl_validate_instance(inst, errs); 3984 if (r != TVS_SUCCESS) 3985 rc = r; 3986 demolish_composed_instance(inst); 3987 } 3988 3989 return (rc); 3990 } 3991 3992 /* 3993 * Validate all services and instances in the bundle against their 3994 * templates. If err_list is not NULL, a tmpl_errors structure will be 3995 * allocated and its address will be returned to err_list. This structure 3996 * can be used to generate error messages. 3997 */ 3998 tmpl_validate_status_t 3999 tmpl_validate_bundle(bundle_t *bndl, tmpl_errors_t **err_list) 4000 { 4001 tmpl_errors_t *errs = NULL; 4002 entity_t *svc; 4003 tmpl_validate_status_t r; 4004 tmpl_validate_status_t rc = TVS_SUCCESS; 4005 4006 if (err_list != NULL) 4007 *err_list = NULL; 4008 if (bndl->sc_bundle_type != SVCCFG_MANIFEST) { 4009 semerr(gettext("Bundle is not a manifest. Unable to validate " 4010 "against templates.\n")); 4011 return (TVS_FATAL); 4012 } 4013 4014 errs = tmpl_errors_create(); 4015 if (errs == NULL) 4016 uu_die(emesg_nomem); 4017 4018 lscf_prep_hndl(); /* Initialize g_hndl */ 4019 if (load_init() != 0) 4020 uu_die(emesg_nomem); 4021 4022 /* 4023 * We will process all services in the bundle, unless we get a 4024 * fatal error. That way we can report all errors on all services 4025 * on a single run of svccfg. 4026 */ 4027 for (svc = uu_list_first(bndl->sc_bundle_services); 4028 svc != NULL; 4029 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 4030 if (svc->sc_etype != SVCCFG_SERVICE_OBJECT) { 4031 semerr(gettext("Manifest for %s contains an object " 4032 "named \"%s\" that is not a service.\n"), 4033 bndl->sc_bundle_name, svc->sc_name); 4034 tmpl_errors_destroy(errs); 4035 load_fini(); 4036 return (TVS_FATAL); 4037 } 4038 if ((r = tmpl_validate_service(svc, errs)) != TVS_SUCCESS) 4039 rc = r; 4040 if (r == TVS_FATAL) 4041 break; 4042 } 4043 4044 if (err_list == NULL) { 4045 tmpl_errors_destroy(errs); 4046 } else { 4047 *err_list = errs; 4048 } 4049 4050 load_fini(); 4051 4052 return (rc); 4053 } 4054