11f6eb021SLiane Praza /* 21f6eb021SLiane Praza * CDDL HEADER START 31f6eb021SLiane Praza * 41f6eb021SLiane Praza * The contents of this file are subject to the terms of the 51f6eb021SLiane Praza * Common Development and Distribution License (the "License"). 61f6eb021SLiane Praza * You may not use this file except in compliance with the License. 71f6eb021SLiane Praza * 81f6eb021SLiane Praza * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 91f6eb021SLiane Praza * or http://www.opensolaris.org/os/licensing. 101f6eb021SLiane Praza * See the License for the specific language governing permissions 111f6eb021SLiane Praza * and limitations under the License. 121f6eb021SLiane Praza * 131f6eb021SLiane Praza * When distributing Covered Code, include this CDDL HEADER in each 141f6eb021SLiane Praza * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 151f6eb021SLiane Praza * If applicable, add the following below this CDDL HEADER, with the 161f6eb021SLiane Praza * fields enclosed by brackets "[]" replaced with your own identifying 171f6eb021SLiane Praza * information: Portions Copyright [yyyy] [name of copyright owner] 181f6eb021SLiane Praza * 191f6eb021SLiane Praza * CDDL HEADER END 201f6eb021SLiane Praza */ 211f6eb021SLiane Praza 221f6eb021SLiane Praza /* 23*870ad75aSSean Wilcox * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 241f6eb021SLiane Praza * Use is subject to license terms. 251f6eb021SLiane Praza */ 261f6eb021SLiane Praza 271f6eb021SLiane Praza /* 281f6eb021SLiane Praza * This file provides the code that allows svccfg(1M) to validate a 291f6eb021SLiane Praza * manifest against the template specifications. svccfg uses the 301f6eb021SLiane Praza * validation facilities for the import and validate subcommands. 311f6eb021SLiane Praza * 321f6eb021SLiane Praza * There are three entry points -- tmpl_validate_bundle(), 331f6eb021SLiane Praza * tmpl_errors_print() and tmpl_errors_destroy(). svccfg calls 341f6eb021SLiane Praza * tmpl_validate_bundle() to validate a bundle. tmpl_validate_bundle() 351f6eb021SLiane Praza * returns a pointer to a tmpl_errors_t. This is a pointer to information 361f6eb021SLiane Praza * about any validation errors that were found. If an error was detected, 371f6eb021SLiane Praza * svccfg calls tmpl_errors_print() to print the error information. Once 381f6eb021SLiane Praza * the error information is printed, svccfg calls tmpl_errors_destroy() to 391f6eb021SLiane Praza * free the memory associated with the tmpl_errors_t. 401f6eb021SLiane Praza * 411f6eb021SLiane Praza * libscf's scf_tmpl.c performs similar checks to the ones described in 421f6eb021SLiane Praza * this paragraph. Any changes to the algorithms in this file should also 431f6eb021SLiane Praza * be infcorporated into scf_tmpl.c. The reason that there are two bodies 441f6eb021SLiane Praza * of code is that they work on different data structures. 451f6eb021SLiane Praza * tmpl_validate_bundle() validates each instance of each service in the 461f6eb021SLiane Praza * bundle. The following checks are performed on each instance: 471f6eb021SLiane Praza * 481f6eb021SLiane Praza * 1. Verify template consistency. 491f6eb021SLiane Praza * A. No conflicting definitions of "pg_pattern" are allowed 501f6eb021SLiane Praza * within a single instance. 511f6eb021SLiane Praza * B. Templates at a narrow target (e.g. instance) which define 521f6eb021SLiane Praza * property groups already templated at a broad target 531f6eb021SLiane Praza * (e.g. delegate or all) are strongly discouraged. 541f6eb021SLiane Praza * C. Developers may not define a template which specifies a 551f6eb021SLiane Praza * single prop_pattern name with differing types on the same 561f6eb021SLiane Praza * target entity. 571f6eb021SLiane Praza * D. If a pg_pattern has a required attribute with a value of 581f6eb021SLiane Praza * true, then its name and type attributes must be 591f6eb021SLiane Praza * specified. 601f6eb021SLiane Praza * E. If a prop_pattern has a required attribute with a value 611f6eb021SLiane Praza * of true, then its type attribute must be specified. 621f6eb021SLiane Praza * F. If a prop_pattern has an include_values element make sure 631f6eb021SLiane Praza * that the appropriate constraints or values element has 641f6eb021SLiane Praza * also been declared. 651f6eb021SLiane Praza * 2. Validate that each property group in the instance is in 661f6eb021SLiane Praza * conformance with the template specifications. 671f6eb021SLiane Praza * A. Verify that the types of the PG and the pg_pattern are 681f6eb021SLiane Praza * compatible. 691f6eb021SLiane Praza * B. Verify properties of the PG against the prop_patterns in 701f6eb021SLiane Praza * the template. 711f6eb021SLiane Praza * o Verify property's type. 721f6eb021SLiane Praza * o Verify cardinality. 731f6eb021SLiane Praza * o Vefiy that property values satisfy the constraints 741f6eb021SLiane Praza * imposed by the prop_pattern. 751f6eb021SLiane Praza * C. Verify that required properties are present. 761f6eb021SLiane Praza * 3. Verify that all required property groups are present in the 771f6eb021SLiane Praza * insance. 781f6eb021SLiane Praza * 791f6eb021SLiane Praza * tmpl_validate_bundle() is called after svccfg has processed the manifest 801f6eb021SLiane Praza * file. The manifest is represented in memory by a set of entity_t, 811f6eb021SLiane Praza * pgroup_t, property_t and value_t structures. These structures are 821f6eb021SLiane Praza * defined in svccfg.h. 831f6eb021SLiane Praza * 841f6eb021SLiane Praza * tmpl_validate_bundle() calls tmpl_validate_service() for each service in 851f6eb021SLiane Praza * the bundle, and tmpl_validate_service() then calls 861f6eb021SLiane Praza * tmpl_validate_instance() for each instance in the service. 871f6eb021SLiane Praza * tmpl_validate_instance() is the function that does the real work of 881f6eb021SLiane Praza * validation against the template specification. 891f6eb021SLiane Praza * 901f6eb021SLiane Praza * Subsystems: 911f6eb021SLiane Praza * ========== 921f6eb021SLiane Praza * 931f6eb021SLiane Praza * General Templates: 941f6eb021SLiane Praza * ----------------- 951f6eb021SLiane Praza * In order to perform the validation specified by 1.B above, we need to 961f6eb021SLiane Praza * load the templates specifications for the global service and the 971f6eb021SLiane Praza * instance's restarter. This information is loaded from the repository 981f6eb021SLiane Praza * and it is held in memory using the entity_t, pgroup_t, property_t and 991f6eb021SLiane Praza * value_t hierarchy of structures. When a service is processed, 1001f6eb021SLiane Praza * load_general_templates() is called to load the information for the 1011f6eb021SLiane Praza * global service and restarter that is declared at the service level. The 1021f6eb021SLiane Praza * sc_service.sc_global and sc_service.sc_restarter members of the 1031f6eb021SLiane Praza * service's entity_t point to the information for the global and restarter 1041f6eb021SLiane Praza * services. 1051f6eb021SLiane Praza * 1061f6eb021SLiane Praza * The instance portion of a manifest can declare an instance specific 1071f6eb021SLiane Praza * restarter. If this is the case, load_instance_restarter() will load the 1081f6eb021SLiane Praza * information for that restarter, and it is saved in the 1091f6eb021SLiane Praza * sc_instance.sc_instance_restarter member of the entity_t that represents 1101f6eb021SLiane Praza * the instance. 1111f6eb021SLiane Praza * 1121f6eb021SLiane Praza * Composed Properties: 1131f6eb021SLiane Praza * ------------------- 1141f6eb021SLiane Praza * We need the ability to process the composed properties of an instance. 1151f6eb021SLiane Praza * That is to say if an instance defines a property, it overrides any 1161f6eb021SLiane Praza * definition in the service. Otherwise, the service's definition is 1171f6eb021SLiane Praza * inherited in the instance. 1181f6eb021SLiane Praza * 1191f6eb021SLiane Praza * In an entity_t, the sc_instance.sc_composed member points to a 1201f6eb021SLiane Praza * uu_avl tree of composed property groups (composed_pg_t) for the 1211f6eb021SLiane Praza * instance. The composed_pg_t has two members, cpg_instance_pg and 1221f6eb021SLiane Praza * cpg_service_pg, that point to the instance and service property group 1231f6eb021SLiane Praza * definitions respectively. Either of these may be NULL indicating that 1241f6eb021SLiane Praza * only an instance or service definition exists in the manifest. 1251f6eb021SLiane Praza * 1261f6eb021SLiane Praza * In the case where both the instance and the service define a property 1271f6eb021SLiane Praza * group, the properties must be composed. This is done by 1281f6eb021SLiane Praza * compose_props(). The compose_pg_t holds the composed properties in a 1291f6eb021SLiane Praza * uu_avl_tree at cpf_compose_props. This is a tree of property_t 1301f6eb021SLiane Praza * structures. If a property is defined in both the instance and service 1311f6eb021SLiane Praza * property group, the tree will hold the instance definition. If the 1321f6eb021SLiane Praza * property is defined at only one level, the tree will hold the property_t 1331f6eb021SLiane Praza * for that level. Thus, the tree is truly a set of composed properties of 1341f6eb021SLiane Praza * the property group. 1351f6eb021SLiane Praza * 1361f6eb021SLiane Praza * Property Group Iteration: 1371f6eb021SLiane Praza * ------------------------ 1381f6eb021SLiane Praza * A number of functions must iterate through an instance's property groups 1391f6eb021SLiane Praza * looking for the ones that define a pg_pattern or a prop_pattern. To be 1401f6eb021SLiane Praza * specific, the iteration starts with the composed view of the instance. 1411f6eb021SLiane Praza * It then proceeds through the restarter information and finally moves on 1421f6eb021SLiane Praza * to the global service. The pg_iter_t structure holds the information 1431f6eb021SLiane Praza * that is needed to implement this type of iteration. pg_iter_create() 1441f6eb021SLiane Praza * creates one of these iterators, and pg_iter_destroy() frees the memory 1451f6eb021SLiane Praza * associated with the pg_iter_t. next_pattern_pg(), is used to step 1461f6eb021SLiane Praza * through the iteration. 1471f6eb021SLiane Praza * 1481f6eb021SLiane Praza * Error Reporting: 1491f6eb021SLiane Praza * --------------- 1501f6eb021SLiane Praza * While performing the templates validation checks, svccfg collects 1511f6eb021SLiane Praza * information for all the errors that it finds. Because of this you will 1521f6eb021SLiane Praza * see many places in the code where a loop is not exited when an error is 1531f6eb021SLiane Praza * encountered. We note that fact that an error has occurred, but continue 1541f6eb021SLiane Praza * in the loop to see if there are more validation errors. The error code 1551f6eb021SLiane Praza * of the last error that is encountered is returned. This works, because 1561f6eb021SLiane Praza * the callers of tmpl_validate_bundle() only look to see whether or not 1571f6eb021SLiane Praza * the return code is TVS_SUCCESS. 1581f6eb021SLiane Praza * 1591f6eb021SLiane Praza * The information for reporting the errors is collected in a tmpl_errors_t 1601f6eb021SLiane Praza * structure, and tmpl_validate_bundle() returns the address of this 1611f6eb021SLiane Praza * structure. The caller of tmpl_validate_bundle() can then call 1621f6eb021SLiane Praza * tmpl_errors_print() to display the error information to the user. 1631f6eb021SLiane Praza * 1641f6eb021SLiane Praza * There are two categories of errors. Some errors are seen when 1651f6eb021SLiane Praza * processing the information in the manifest. This type of error is only 1661f6eb021SLiane Praza * seen by svccfg when it is importing or validating a manifest. The other 1671f6eb021SLiane Praza * type of error consists of template validation errors. These errors can 1681f6eb021SLiane Praza * be seen when processing a manifest or when performing a templates 1691f6eb021SLiane Praza * validation of the information associated with an FMRI in the the 1701f6eb021SLiane Praza * repository. tmpl_errors_add_im() is used to capture error information 1711f6eb021SLiane Praza * about the first type of error, and add_scf_error() is used to capture 1721f6eb021SLiane Praza * error information about the second type of error. 1731f6eb021SLiane Praza * 1741f6eb021SLiane Praza * The distinction is important when printing the error information. The 1751f6eb021SLiane Praza * fuctions for printing the first type of error reside in this file, since 1761f6eb021SLiane Praza * these errors will only be seen by the functions in this file. The 1771f6eb021SLiane Praza * functions for printing the template validation errors reside in libscf, 1781f6eb021SLiane Praza * because these errors are of a more general nature. 1791f6eb021SLiane Praza * 1801f6eb021SLiane Praza * Thus, tmpl_errors_t has two lists -- one for each type of error. 1811f6eb021SLiane Praza * te_list is a list of im_tmpl_error_t structures that represent the first 1821f6eb021SLiane Praza * type of error. te_scf is a list of tv_errors_t structures that hold 1831f6eb021SLiane Praza * information about general template validation errors. 1841f6eb021SLiane Praza * tmpl_errors_print() processes both lists to print information about all 1851f6eb021SLiane Praza * errors. In tmpl_errors_print() im_tmpl_error_print() is used to print 1861f6eb021SLiane Praza * the errors that are specific to this file. scf_tmpl_strerror() provides 1871f6eb021SLiane Praza * the errors messages for general templates errors. 1881f6eb021SLiane Praza * 1891f6eb021SLiane Praza * As was mentioned in the previous paragraph, im_tmpl_error_print() is 1901f6eb021SLiane Praza * responsible for printing the errors that are specific to this file. 1911f6eb021SLiane Praza * Based on the error code, it dispatches to one of 1921f6eb021SLiane Praza * im_perror_bad_conversion(), im_perror_bad_template(), 1931f6eb021SLiane Praza * im_perror_invalid_type(), im_perror_missing_pg_type() or 1941f6eb021SLiane Praza * im_perror_missing_type(). The rest of the im_perror_* functions provide 1951f6eb021SLiane Praza * services to these error specific functions by printing common 1961f6eb021SLiane Praza * information. 1971f6eb021SLiane Praza * 1981f6eb021SLiane Praza * im_perror_item() is the heart of this message printing subsystem. It is 1991f6eb021SLiane Praza * called directly or indirectly by all of the other im_perror_* functions. 2001f6eb021SLiane Praza * im_perror_item() prints a single item of error information. If svccfg 2011f6eb021SLiane Praza * is running in interactive mode, im_perror_item() prints each item on a 2021f6eb021SLiane Praza * single line, so that they are readable by a human. In non-interactive 2031f6eb021SLiane Praza * mode, all items are printed on a single line separated by semi-colons. 2041f6eb021SLiane Praza */ 2051f6eb021SLiane Praza 2061f6eb021SLiane Praza #include <assert.h> 2071f6eb021SLiane Praza #include <errno.h> 2081f6eb021SLiane Praza #include <inttypes.h> 2091f6eb021SLiane Praza #include <libintl.h> 2101f6eb021SLiane Praza #include <limits.h> 2111f6eb021SLiane Praza #include <libscf.h> 2121f6eb021SLiane Praza #include <libscf_priv.h> 2131f6eb021SLiane Praza #include <stdio.h> 2141f6eb021SLiane Praza #include <stdlib.h> 2151f6eb021SLiane Praza #include <strings.h> 2161f6eb021SLiane Praza #include "svccfg.h" 2171f6eb021SLiane Praza 2181f6eb021SLiane Praza /* 2191f6eb021SLiane Praza * Clear error_info_t structure. 2201f6eb021SLiane Praza */ 2211f6eb021SLiane Praza #define CLEAR_ERROR_INFO(ei) ((void) memset((ei), 0, sizeof (error_info_t))) 2221f6eb021SLiane Praza 2231f6eb021SLiane Praza /* 2241f6eb021SLiane Praza * Retrieve the property group pointer from the composed_pg structure. 2251f6eb021SLiane Praza */ 2261f6eb021SLiane Praza #define CPG2PG(cpg) (cpg->cpg_instance_pg ? cpg->cpg_instance_pg : \ 2271f6eb021SLiane Praza cpg->cpg_service_pg) 2281f6eb021SLiane Praza 2291f6eb021SLiane Praza /* 2301f6eb021SLiane Praza * Convert a pointer to an empty string into a NULL pointer. 2311f6eb021SLiane Praza */ 2321f6eb021SLiane Praza #define EMPTY_TO_NULL(p) (((p) && (*(p) == 0)) ? NULL : (p)) 2331f6eb021SLiane Praza 2341f6eb021SLiane Praza /* uu_avl and uu_list debugging bits. */ 2351f6eb021SLiane Praza #ifdef NDEBUG 2361f6eb021SLiane Praza #define TMPL_DEBUG_AVL_POOL UU_DEFAULT 2371f6eb021SLiane Praza #define TMPL_DEBUG_LIST UU_DEFAULT 2381f6eb021SLiane Praza #define TMPL_DEBUG_LIST_POOL UU_DEFAULT 2391f6eb021SLiane Praza #define TMPL_DEBUG_TREE UU_DEFAULT 2401f6eb021SLiane Praza #else 2411f6eb021SLiane Praza #define TMPL_DEBUG_AVL_POOL UU_AVL_POOL_DEBUG 2421f6eb021SLiane Praza #define TMPL_DEBUG_LIST UU_LIST_DEBUG 2431f6eb021SLiane Praza #define TMPL_DEBUG_LIST_POOL UU_LIST_POOL_DEBUG 2441f6eb021SLiane Praza #define TMPL_DEBUG_TREE UU_AVL_DEBUG 2451f6eb021SLiane Praza #endif /* NDEBUG */ 2461f6eb021SLiane Praza 2471f6eb021SLiane Praza /* 2481f6eb021SLiane Praza * Structures and enums that are used in producing error messages: 2491f6eb021SLiane Praza * 2501f6eb021SLiane Praza * error_info_t is used to pass information about an error to 2511f6eb021SLiane Praza * tmpl_errors_add_im() and add_scf_error(). tmpl_errors_add_im() collects 2521f6eb021SLiane Praza * the error information and stores it in an im_tmpl_error_t. The 2531f6eb021SLiane Praza * im_tmpl_error_t is linked into the tmpl_errors_t, so that the captured 2541f6eb021SLiane Praza * information can be used later when error messages are printed. 2551f6eb021SLiane Praza * 2561f6eb021SLiane Praza * tv_errors_t is used to keep track of error information for general 2571f6eb021SLiane Praza * template errors that are known by libscf. add_scf_error() captures the 2581f6eb021SLiane Praza * error information for use in this structure. 2591f6eb021SLiane Praza */ 2601f6eb021SLiane Praza /* 2611f6eb021SLiane Praza * enum to designate the type of data that is held in a err_info structure. 2621f6eb021SLiane Praza */ 2631f6eb021SLiane Praza typedef enum err_info_type { 2641f6eb021SLiane Praza EIT_NONE, /* No values in the structure */ 2651f6eb021SLiane Praza EIT_BAD_TEMPLATE, /* Reason that template is bad */ 2661f6eb021SLiane Praza EIT_CARDINALITY, /* Ranges for property cardinality */ 2671f6eb021SLiane Praza EIT_INCLUDE_VALUES, /* include_values type attribute */ 2681f6eb021SLiane Praza EIT_MISSING_PG, /* Name of missing pg */ 2691f6eb021SLiane Praza EIT_MISSING_PROP, /* Name of missing property */ 2701f6eb021SLiane Praza EIT_PATTERN_CONFLICT, /* Conflicting pattern definition */ 2711f6eb021SLiane Praza EIT_PROP_TYPE, /* Value with invalid type */ 2721f6eb021SLiane Praza EIT_RANGE /* Value that is out of range */ 2731f6eb021SLiane Praza } err_info_type_t; 2741f6eb021SLiane Praza 2751f6eb021SLiane Praza /* 2761f6eb021SLiane Praza * Structure to hold information that will be used in generating error 2771f6eb021SLiane Praza * messages. 2781f6eb021SLiane Praza */ 2791f6eb021SLiane Praza typedef struct error_info { 2801f6eb021SLiane Praza err_info_type_t ei_type; /* Type of information stored here */ 2811f6eb021SLiane Praza union { 2821f6eb021SLiane Praza /* EIT_BAD_TEMPLATE */ 2831f6eb021SLiane Praza struct { 2841f6eb021SLiane Praza const char *ei_reason; 2851f6eb021SLiane Praza } ei_bad_template; 2861f6eb021SLiane Praza /* EIT_CARDINALITY */ 2871f6eb021SLiane Praza struct { 2881f6eb021SLiane Praza uint64_t ei_min; 2891f6eb021SLiane Praza uint64_t ei_max; 2901f6eb021SLiane Praza uint64_t ei_count; /* Number of prop values */ 2911f6eb021SLiane Praza } ei_cardinality; 2921f6eb021SLiane Praza /* EIT_INCLUDE_VALUES */ 2931f6eb021SLiane Praza struct { 2941f6eb021SLiane Praza const char *ei_type; 2951f6eb021SLiane Praza } ei_inc_values; 2961f6eb021SLiane Praza /* EIT_MISSING_PG */ 2971f6eb021SLiane Praza struct { 2981f6eb021SLiane Praza const char *ei_pg_name; /* Name of missing pg */ 2991f6eb021SLiane Praza const char *ei_pg_type; /* Type of missing pg */ 3001f6eb021SLiane Praza } ei_missing_pg; 3011f6eb021SLiane Praza /* EIT_MISSING_PROP */ 3021f6eb021SLiane Praza struct { 3031f6eb021SLiane Praza const char *ei_prop_name; /* Name of prop */ 3041f6eb021SLiane Praza } ei_missing_prop; 3051f6eb021SLiane Praza /* EIT_PATTERN_CONFLICT */ 3061f6eb021SLiane Praza struct { 3071f6eb021SLiane Praza pgroup_t *ei_pattern; /* Conficting pattern */ 3081f6eb021SLiane Praza } ei_pattern_conflict; 3091f6eb021SLiane Praza /* EIT_PROP_TYPE */ 3101f6eb021SLiane Praza struct { 3111f6eb021SLiane Praza scf_type_t ei_actual; 3121f6eb021SLiane Praza scf_type_t ei_specified; 3131f6eb021SLiane Praza } ei_prop_type; 3141f6eb021SLiane Praza /* EIT_RANGE */ 3151f6eb021SLiane Praza struct { 3161f6eb021SLiane Praza scf_type_t ei_rtype; 3171f6eb021SLiane Praza int64_t ei_ivalue; 3181f6eb021SLiane Praza uint64_t ei_uvalue; 3191f6eb021SLiane Praza } ei_range; 3201f6eb021SLiane Praza } ei_u; 3211f6eb021SLiane Praza } error_info_t; 3221f6eb021SLiane Praza 3231f6eb021SLiane Praza /* 3241f6eb021SLiane Praza * Structure with information about a template violation. This structure 3251f6eb021SLiane Praza * is for use with in memory representations of the manifest and template. 3261f6eb021SLiane Praza * See scf_tmpl_error_t for use with repository representations. Some of 3271f6eb021SLiane Praza * the pointers may be NULL for some types of errors. 3281f6eb021SLiane Praza */ 3291f6eb021SLiane Praza typedef struct im_tmpl_error { 3301f6eb021SLiane Praza tmpl_validate_status_t ite_type; /* Type of error */ 3311f6eb021SLiane Praza entity_t *ite_entity; /* Instance or service */ 3321f6eb021SLiane Praza pgroup_t *ite_pg; /* Non-conforming prop. group */ 3331f6eb021SLiane Praza pgroup_t *ite_pg_pattern; /* Violated pg_pattern */ 3341f6eb021SLiane Praza property_t *ite_prop; /* Non-conforming property */ 3351f6eb021SLiane Praza pgroup_t *ite_prop_pattern; /* Violated prop_pattern */ 3361f6eb021SLiane Praza value_t *ite_value; /* Non-conforming value */ 3371f6eb021SLiane Praza error_info_t ite_einfo; /* Extra error information */ 3381f6eb021SLiane Praza uu_list_node_t ite_node; /* Node to link us in a list. */ 3391f6eb021SLiane Praza } im_tmpl_error_t; 3401f6eb021SLiane Praza 3411f6eb021SLiane Praza /* 3421f6eb021SLiane Praza * This structure holds the data that will be used by scf_tmpl_strerror() 3431f6eb021SLiane Praza * for printing template validation errors. 3441f6eb021SLiane Praza */ 3451f6eb021SLiane Praza typedef struct tv_errors { 3461f6eb021SLiane Praza scf_tmpl_errors_t *tve_errors; /* Errors for scf_tmpl_strerror() */ 3471f6eb021SLiane Praza uu_list_node_t tve_node; /* Linkage in a list. */ 3481f6eb021SLiane Praza } tv_errors_t; 3491f6eb021SLiane Praza 3501f6eb021SLiane Praza /* 3511f6eb021SLiane Praza * Structure to collect template validation errors. 3521f6eb021SLiane Praza */ 3531f6eb021SLiane Praza struct tmpl_errors { 3541f6eb021SLiane Praza uu_list_t *te_list; /* List of im_tmpl_error_t */ 3551f6eb021SLiane Praza im_tmpl_error_t *te_next; /* Next error to present */ 3561f6eb021SLiane Praza uu_list_t *te_scf; /* Errors for scf_tmpl_strerror() */ 3571f6eb021SLiane Praza tv_errors_t *te_cur_scf; /* Current member of te_scf */ 3581f6eb021SLiane Praza }; 3591f6eb021SLiane Praza 3601f6eb021SLiane Praza /* End of structures used in error processing. */ 3611f6eb021SLiane Praza 3621f6eb021SLiane Praza /* 3631f6eb021SLiane Praza * Property group types that are of interest to us. See pgroup_type(). 3641f6eb021SLiane Praza */ 3651f6eb021SLiane Praza typedef enum pg_type { 3661f6eb021SLiane Praza NORMAL_PG, 3671f6eb021SLiane Praza PG_PATTERN_PG, 3681f6eb021SLiane Praza PROP_PATTERN_PG 3691f6eb021SLiane Praza } pg_type_t; 3701f6eb021SLiane Praza 3711f6eb021SLiane Praza /* 3721f6eb021SLiane Praza * Structure to keep track of a set of ASTRING property values for a 3731f6eb021SLiane Praza * property. The consumer may wish to have the ASTRING property values 3741f6eb021SLiane Praza * converted to a numeric form which is the reason for the av_v union. 3751f6eb021SLiane Praza * This structure is returned by av_get_values() and is accessed by 3761f6eb021SLiane Praza * av_get_integer(), av_get_string() and av_get_unsigned(). 3771f6eb021SLiane Praza */ 3781f6eb021SLiane Praza typedef struct avalues { 3791f6eb021SLiane Praza uint_t av_count; /* Number of values */ 3801f6eb021SLiane Praza scf_type_t av_type; /* Type of value representation */ 3811f6eb021SLiane Praza union { 3821f6eb021SLiane Praza uint64_t *av_unsigned; /* Count & boolean values */ 3831f6eb021SLiane Praza int64_t *av_integer; /* Integer values */ 3841f6eb021SLiane Praza const char **av_string; /* String values */ 3851f6eb021SLiane Praza } av_v; /* Container for the values */ 3861f6eb021SLiane Praza } avalues_t; 3871f6eb021SLiane Praza 3881f6eb021SLiane Praza /* 3891f6eb021SLiane Praza * composed_pg_t contains the information that is needed to compose a 3901f6eb021SLiane Praza * property group. See the section on Composed Properties in the block 3911f6eb021SLiane Praza * comment at the beginning of this file. The composed_pg structures are 3921f6eb021SLiane Praza * linked into a uu_avl tree. The tree is at sc_instance.sc_composed in 3931f6eb021SLiane Praza * the entity_t. 3941f6eb021SLiane Praza */ 3951f6eb021SLiane Praza struct composed_pg { 3961f6eb021SLiane Praza /* 3971f6eb021SLiane Praza * Property group is uniquely identified by its name and type. 3981f6eb021SLiane Praza * These two elements point to the name and type in a pgroup_t 3991f6eb021SLiane Praza * (either service or instance), so they do not need to be 4001f6eb021SLiane Praza * allocated or freed. 4011f6eb021SLiane Praza */ 4021f6eb021SLiane Praza const char *cpg_name; 4031f6eb021SLiane Praza const char *cpg_type; 4041f6eb021SLiane Praza 4051f6eb021SLiane Praza /* References to the actual property group definitions. */ 4061f6eb021SLiane Praza pgroup_t *cpg_instance_pg; 4071f6eb021SLiane Praza pgroup_t *cpg_service_pg; 4081f6eb021SLiane Praza 4091f6eb021SLiane Praza /* Composed properties of the property group. */ 4101f6eb021SLiane Praza uu_avl_t *cpg_composed_props; 4111f6eb021SLiane Praza 4121f6eb021SLiane Praza uu_avl_node_t cpg_node; /* Linkage for AVL tree */ 4131f6eb021SLiane Praza }; 4141f6eb021SLiane Praza 4151f6eb021SLiane Praza /* 4161f6eb021SLiane Praza * Prefixes for standard property names. Used in 4171f6eb021SLiane Praza * include_values_support(). 4181f6eb021SLiane Praza */ 4191f6eb021SLiane Praza typedef struct prop_prefix { 4201f6eb021SLiane Praza const char *pp_prefix; 4211f6eb021SLiane Praza size_t pp_size; 4221f6eb021SLiane Praza } prop_prefix_t; 4231f6eb021SLiane Praza 4241f6eb021SLiane Praza /* 4251f6eb021SLiane Praza * Store a legal range for a property allowing for either signed or 4261f6eb021SLiane Praza * unsigned ranges. It is used to store a range from a template 4271f6eb021SLiane Praza * constraint element of a prop_pattern. The structure is returned by 4281f6eb021SLiane Praza * get_ranges() and is used by value_in_range() to validate the values of a 4291f6eb021SLiane Praza * property. 4301f6eb021SLiane Praza */ 4311f6eb021SLiane Praza typedef struct range { 4321f6eb021SLiane Praza union { 4331f6eb021SLiane Praza struct { 4341f6eb021SLiane Praza uint64_t rng_min; 4351f6eb021SLiane Praza uint64_t rng_max; 4361f6eb021SLiane Praza } rng_unsigned; 4371f6eb021SLiane Praza struct { 4381f6eb021SLiane Praza int64_t rng_min; 4391f6eb021SLiane Praza int64_t rng_max; 4401f6eb021SLiane Praza } rng_signed; 4411f6eb021SLiane Praza } rng_u; 4421f6eb021SLiane Praza } range_t; 4431f6eb021SLiane Praza 4441f6eb021SLiane Praza /* 4451f6eb021SLiane Praza * This enum defines the levels where templates can be defined. See the 4461f6eb021SLiane Praza * pg_iter structure below. 4471f6eb021SLiane Praza */ 4481f6eb021SLiane Praza typedef enum tmpl_level { 4491f6eb021SLiane Praza TL_NOLEVEL = 0, /* No level yet specified. */ 4501f6eb021SLiane Praza TL_INSTANCE, /* Instance templates. */ 4511f6eb021SLiane Praza TL_COMPOSED, /* Composed instance. */ 4521f6eb021SLiane Praza TL_SERVICE, /* Service wide templates. */ 4531f6eb021SLiane Praza TL_RESTARTER, /* Templates from restarter manifest. */ 4541f6eb021SLiane Praza TL_GLOBAL /* SMF wide templates. */ 4551f6eb021SLiane Praza } tmpl_level_t; 4561f6eb021SLiane Praza 4571f6eb021SLiane Praza /* 4581f6eb021SLiane Praza * pg_iter is a structure that allows us to iterate through property groups 4591f6eb021SLiane Praza * in an instance followed by the property groups of the instance's 4601f6eb021SLiane Praza * service, the instance's restarter and finally the global service. See 4611f6eb021SLiane Praza * the Property Group Iteration section of the block comment at the 4621f6eb021SLiane Praza * beginning of this file. 4631f6eb021SLiane Praza */ 4641f6eb021SLiane Praza typedef struct pg_iter { 4651f6eb021SLiane Praza entity_t *pgi_entity; /* Entity being searched */ 4661f6eb021SLiane Praza const char *pgi_restrict; /* Only return PGs of this type */ 4671f6eb021SLiane Praza tmpl_level_t pgi_level; /* Current level */ 4681f6eb021SLiane Praza entity_t *pgi_service; /* Service being processed. */ 4691f6eb021SLiane Praza union { 4701f6eb021SLiane Praza pgroup_t *pgi_pg; 4711f6eb021SLiane Praza composed_pg_t *pgi_cpg; 4721f6eb021SLiane Praza } pgi_current; /* Current property group. */ 4731f6eb021SLiane Praza } pg_iter_t; 4741f6eb021SLiane Praza 4751f6eb021SLiane Praza /* 4761f6eb021SLiane Praza * enum to distinguish between pg_patterns and prop_patterns. It is used 4771f6eb021SLiane Praza * in the ptrn_info_t structure. See below. 4781f6eb021SLiane Praza */ 4791f6eb021SLiane Praza typedef enum ptrn_type { 4801f6eb021SLiane Praza PG_PATTERN, 4811f6eb021SLiane Praza PROP_PATTERN 4821f6eb021SLiane Praza } ptrn_type_t; 4831f6eb021SLiane Praza 4841f6eb021SLiane Praza /* 4851f6eb021SLiane Praza * Structure of information about a pg_pattern or a prop_pattern. It is 4861f6eb021SLiane Praza * used for template consistency checks. gather_pattern() is used to 4871f6eb021SLiane Praza * gather information for all the pg_patterns or prop_patterns in an 4881f6eb021SLiane Praza * instance. It allocates a ptrn_info_t for each of these and adds them to 4891f6eb021SLiane Praza * an avl tree that is held by tmpl_consistency(). 4901f6eb021SLiane Praza */ 4911f6eb021SLiane Praza typedef struct ptrn_info { 4921f6eb021SLiane Praza ptrn_type_t pi_ptrn_type; 4931f6eb021SLiane Praza pgroup_t *pi_ptrnpg; /* pgroup_t defining the pattern. */ 4941f6eb021SLiane Praza const char *pi_name; /* Name attribute. */ 4951f6eb021SLiane Praza const char *pi_type; /* Type attribute. */ 4961f6eb021SLiane Praza const char *pi_target; /* Target attribute - only PG_PATTERN */ 4971f6eb021SLiane Praza const char *pi_pgp_name; /* Name of the pg pattern. Only */ 4981f6eb021SLiane Praza /* used for PROP_PATTERN. */ 4991f6eb021SLiane Praza pgroup_t *pi_enc_pgp; /* PG of the pg_pattern that holds */ 5001f6eb021SLiane Praza /* the prop_pattern defined by this */ 5011f6eb021SLiane Praza /* structure. Only used for */ 5021f6eb021SLiane Praza /* PROP_PATTERN. */ 5031f6eb021SLiane Praza uu_avl_node_t pi_link; /* Linkage into AVL tree */ 5041f6eb021SLiane Praza } ptrn_info_t; 5051f6eb021SLiane Praza 5061f6eb021SLiane Praza static const char *emesg_nomem; 5071f6eb021SLiane Praza 5081f6eb021SLiane Praza /* 5091f6eb021SLiane Praza * Pool for trees of composed property groups. 5101f6eb021SLiane Praza */ 5111f6eb021SLiane Praza static uu_avl_pool_t *composed_pg_pool; 5121f6eb021SLiane Praza 5131f6eb021SLiane Praza /* 5141f6eb021SLiane Praza * Pool for trees of composed properties. 5151f6eb021SLiane Praza */ 5161f6eb021SLiane Praza static uu_avl_pool_t *composed_prop_pool; 5171f6eb021SLiane Praza 5181f6eb021SLiane Praza /* 5191f6eb021SLiane Praza * Pool for lists of errors in the internal representation. 5201f6eb021SLiane Praza */ 5211f6eb021SLiane Praza static uu_list_pool_t *inmem_errors_pool; 5221f6eb021SLiane Praza 5231f6eb021SLiane Praza /* 5241f6eb021SLiane Praza * Pool for trees of pg_pattern info structures (ptrn_info_t). 5251f6eb021SLiane Praza */ 5261f6eb021SLiane Praza static uu_avl_pool_t *ptrn_info_pool; 5271f6eb021SLiane Praza 5281f6eb021SLiane Praza /* 5291f6eb021SLiane Praza * Pool for lists of template errors in the libscf representation. 5301f6eb021SLiane Praza */ 5311f6eb021SLiane Praza static uu_list_pool_t *tv_errors_pool; 5321f6eb021SLiane Praza 5331f6eb021SLiane Praza /* 5341f6eb021SLiane Praza * Property name prefixes for constraints and values. 5351f6eb021SLiane Praza */ 5361f6eb021SLiane Praza static const char *constraint_prefixes[] = { 5371f6eb021SLiane Praza SCF_PROPERTY_TM_CONSTRAINT_NAME, 5381f6eb021SLiane Praza SCF_PROPERTY_TM_CONSTRAINT_RANGE, 5391f6eb021SLiane Praza NULL 5401f6eb021SLiane Praza }; 5411f6eb021SLiane Praza static const char *value_prefixes[] = { 5421f6eb021SLiane Praza SCF_PROPERTY_TM_VALUE_PREFIX, 5431f6eb021SLiane Praza NULL 5441f6eb021SLiane Praza }; 5451f6eb021SLiane Praza 5461f6eb021SLiane Praza /* 5471f6eb021SLiane Praza * Function to compare two composed_pg structures. 5481f6eb021SLiane Praza */ 5491f6eb021SLiane Praza /* ARGSUSED2 */ 5501f6eb021SLiane Praza static int 5511f6eb021SLiane Praza composed_pg_compare(const void *left, const void *right, void *unused) 5521f6eb021SLiane Praza { 5531f6eb021SLiane Praza composed_pg_t *l = (composed_pg_t *)left; 5541f6eb021SLiane Praza composed_pg_t *r = (composed_pg_t *)right; 5551f6eb021SLiane Praza int rc; 5561f6eb021SLiane Praza 5571f6eb021SLiane Praza if ((rc = strcmp(l->cpg_name, r->cpg_name)) == 0) { 5581f6eb021SLiane Praza rc = strcmp(l->cpg_type, r->cpg_type); 5591f6eb021SLiane Praza } 5601f6eb021SLiane Praza return (rc); 5611f6eb021SLiane Praza } 5621f6eb021SLiane Praza 5631f6eb021SLiane Praza /* ARGSUSED2 */ 5641f6eb021SLiane Praza static int 5651f6eb021SLiane Praza composed_prop_compare(const void *left, const void *right, void *unused) 5661f6eb021SLiane Praza { 5671f6eb021SLiane Praza property_t *l = (property_t *)left; 5681f6eb021SLiane Praza property_t *r = (property_t *)right; 5691f6eb021SLiane Praza 5701f6eb021SLiane Praza return (strcmp(l->sc_property_name, r->sc_property_name)); 5711f6eb021SLiane Praza } 5721f6eb021SLiane Praza 5731f6eb021SLiane Praza static composed_pg_t * 5741f6eb021SLiane Praza composed_pg_create() 5751f6eb021SLiane Praza { 5761f6eb021SLiane Praza composed_pg_t *cpg; 5771f6eb021SLiane Praza 5781f6eb021SLiane Praza cpg = safe_malloc(sizeof (*cpg)); 5791f6eb021SLiane Praza uu_avl_node_init(cpg, &cpg->cpg_node, composed_pg_pool); 5801f6eb021SLiane Praza return (cpg); 5811f6eb021SLiane Praza } 5821f6eb021SLiane Praza 5831f6eb021SLiane Praza static void 5841f6eb021SLiane Praza composed_pg_destroy(composed_pg_t *cpg) 5851f6eb021SLiane Praza { 5861f6eb021SLiane Praza void *marker = NULL; 5871f6eb021SLiane Praza pgroup_t *pg; 5881f6eb021SLiane Praza 5891f6eb021SLiane Praza if (cpg == NULL) 5901f6eb021SLiane Praza return; 5911f6eb021SLiane Praza /* Tear down composed property tree if we have one. */ 5921f6eb021SLiane Praza if ((cpg->cpg_composed_props != NULL)) { 5931f6eb021SLiane Praza while (uu_avl_teardown(cpg->cpg_composed_props, &marker) != 5941f6eb021SLiane Praza NULL) { 5951f6eb021SLiane Praza /* 5961f6eb021SLiane Praza * Nothing to do other than getting the property 5971f6eb021SLiane Praza * out of the list. This cleans up the property's 5981f6eb021SLiane Praza * uu_avl_node. 5991f6eb021SLiane Praza */ 6001f6eb021SLiane Praza } 6011f6eb021SLiane Praza uu_avl_destroy(cpg->cpg_composed_props); 6021f6eb021SLiane Praza } 6031f6eb021SLiane Praza 6041f6eb021SLiane Praza /* Clean up any pgroup_t references to us. */ 6051f6eb021SLiane Praza if ((pg = cpg->cpg_instance_pg) != NULL) { 6061f6eb021SLiane Praza assert((pg->sc_pgroup_composed == NULL) || 6071f6eb021SLiane Praza (pg->sc_pgroup_composed == cpg)); 6081f6eb021SLiane Praza pg->sc_pgroup_composed = NULL; 6091f6eb021SLiane Praza } 6101f6eb021SLiane Praza 6111f6eb021SLiane Praza uu_avl_node_fini(cpg, &cpg->cpg_node, composed_pg_pool); 6121f6eb021SLiane Praza free(cpg); 6131f6eb021SLiane Praza } 6141f6eb021SLiane Praza 6151f6eb021SLiane Praza /* 6161f6eb021SLiane Praza * Walk the property group at pg, and add its properties to the AVL tree at 6171f6eb021SLiane Praza * tree. 6181f6eb021SLiane Praza */ 6191f6eb021SLiane Praza static void 6201f6eb021SLiane Praza grow_props_tree(pgroup_t *pg, uu_avl_t *tree) 6211f6eb021SLiane Praza { 6221f6eb021SLiane Praza uu_avl_index_t marker; 6231f6eb021SLiane Praza property_t *prop; 6241f6eb021SLiane Praza 6251f6eb021SLiane Praza for (prop = uu_list_first(pg->sc_pgroup_props); 6261f6eb021SLiane Praza prop != NULL; 6271f6eb021SLiane Praza prop = uu_list_next(pg->sc_pgroup_props, prop)) { 6281f6eb021SLiane Praza if (uu_avl_find(tree, prop, NULL, &marker) == NULL) { 6291f6eb021SLiane Praza /* 6301f6eb021SLiane Praza * If there was no match, insert the property into 6311f6eb021SLiane Praza * the tree. If we do get a match, there is 6321f6eb021SLiane Praza * nothing to do. That is because we rely on our 6331f6eb021SLiane Praza * caller to process the instance properties first, 6341f6eb021SLiane Praza * and the instance properties override the service 6351f6eb021SLiane Praza * properties. 6361f6eb021SLiane Praza */ 6371f6eb021SLiane Praza uu_avl_insert(tree, prop, marker); 6381f6eb021SLiane Praza } 6391f6eb021SLiane Praza } 6401f6eb021SLiane Praza } 6411f6eb021SLiane Praza 6421f6eb021SLiane Praza /* 6431f6eb021SLiane Praza * The composed properties are stored in a uu_avl_tree. First we populate 6441f6eb021SLiane Praza * the tree with properties from the instance level property group. Then, 6451f6eb021SLiane Praza * we'll add the properties from the service level property group. 6461f6eb021SLiane Praza */ 6471f6eb021SLiane Praza static void 6481f6eb021SLiane Praza compose_props(composed_pg_t *cpg) 6491f6eb021SLiane Praza { 6501f6eb021SLiane Praza uu_avl_t *tree; 6511f6eb021SLiane Praza 6521f6eb021SLiane Praza tree = uu_avl_create(composed_prop_pool, cpg, TMPL_DEBUG_TREE); 6531f6eb021SLiane Praza if (tree == NULL) { 6541f6eb021SLiane Praza uu_die(gettext("composed_pool tree creation failed: %s\n"), 6551f6eb021SLiane Praza uu_strerror(uu_error())); 6561f6eb021SLiane Praza } 6571f6eb021SLiane Praza cpg->cpg_composed_props = tree; 6581f6eb021SLiane Praza 6591f6eb021SLiane Praza /* 6601f6eb021SLiane Praza * compose_props() is only called when there is both an instance 6611f6eb021SLiane Praza * and a service definition of the property group. This implies 6621f6eb021SLiane Praza * that neither cpg->cpg_instance_pg nor cpg->cpg_service_pg can be 6631f6eb021SLiane Praza * NULL. 6641f6eb021SLiane Praza */ 6651f6eb021SLiane Praza /* 6661f6eb021SLiane Praza * First add instance properties to the tree. 6671f6eb021SLiane Praza */ 6681f6eb021SLiane Praza assert(cpg->cpg_instance_pg != NULL); 6691f6eb021SLiane Praza grow_props_tree(cpg->cpg_instance_pg, tree); 6701f6eb021SLiane Praza 6711f6eb021SLiane Praza /* 6721f6eb021SLiane Praza * Add service properties to the tree. 6731f6eb021SLiane Praza */ 6741f6eb021SLiane Praza assert(cpg->cpg_service_pg != NULL); 6751f6eb021SLiane Praza grow_props_tree(cpg->cpg_service_pg, tree); 6761f6eb021SLiane Praza } 6771f6eb021SLiane Praza 6781f6eb021SLiane Praza /* 6791f6eb021SLiane Praza * This function is a utility for build_composed_instance(). 6801f6eb021SLiane Praza */ 6811f6eb021SLiane Praza static void 6821f6eb021SLiane Praza build_composed_property_groups(entity_t *inst, uu_avl_t *tree) 6831f6eb021SLiane Praza { 6841f6eb021SLiane Praza composed_pg_t *cpg; 6851f6eb021SLiane Praza uu_avl_index_t marker; 6861f6eb021SLiane Praza composed_pg_t *match; 6871f6eb021SLiane Praza pgroup_t *pg; 6881f6eb021SLiane Praza entity_t *svc; 6891f6eb021SLiane Praza 6901f6eb021SLiane Praza /* First capture the instance property groups. */ 6911f6eb021SLiane Praza for (pg = uu_list_first(inst->sc_pgroups); 6921f6eb021SLiane Praza pg != NULL; 6931f6eb021SLiane Praza pg = uu_list_next(inst->sc_pgroups, pg)) { 6941f6eb021SLiane Praza cpg = composed_pg_create(); 6951f6eb021SLiane Praza cpg->cpg_name = pg->sc_pgroup_name; 6961f6eb021SLiane Praza cpg->cpg_type = pg->sc_pgroup_type; 6971f6eb021SLiane Praza cpg->cpg_instance_pg = pg; 6981f6eb021SLiane Praza match = uu_avl_find(tree, cpg, NULL, &marker); 6991f6eb021SLiane Praza /* Since we do the instance first, there should be no match. */ 7001f6eb021SLiane Praza assert(match == NULL); 7011f6eb021SLiane Praza uu_avl_insert(tree, cpg, marker); 7021f6eb021SLiane Praza pg->sc_pgroup_composed = cpg; 7031f6eb021SLiane Praza } 7041f6eb021SLiane Praza 7051f6eb021SLiane Praza /* Now capture the service property groups. */ 7061f6eb021SLiane Praza svc = inst->sc_parent; 7071f6eb021SLiane Praza cpg = NULL; 7081f6eb021SLiane Praza for (pg = uu_list_first(svc->sc_pgroups); 7091f6eb021SLiane Praza pg != NULL; 7101f6eb021SLiane Praza pg = uu_list_next(svc->sc_pgroups, pg)) { 7111f6eb021SLiane Praza if (cpg == NULL) 7121f6eb021SLiane Praza cpg = composed_pg_create(); 7131f6eb021SLiane Praza cpg->cpg_name = pg->sc_pgroup_name; 7141f6eb021SLiane Praza cpg->cpg_type = pg->sc_pgroup_type; 7151f6eb021SLiane Praza cpg->cpg_service_pg = pg; 7161f6eb021SLiane Praza match = uu_avl_find(tree, cpg, NULL, &marker); 7171f6eb021SLiane Praza if (match == NULL) { 7181f6eb021SLiane Praza uu_avl_insert(tree, cpg, marker); 7191f6eb021SLiane Praza /* Get new composed_pg_t next at top of loop. */ 7201f6eb021SLiane Praza cpg = NULL; 7211f6eb021SLiane Praza } else { 7221f6eb021SLiane Praza /* 7231f6eb021SLiane Praza * Already have a composed_pg from instance 7241f6eb021SLiane Praza * processing. Just add the pointer to the service 7251f6eb021SLiane Praza * pg and compose the properties. 7261f6eb021SLiane Praza */ 7271f6eb021SLiane Praza match->cpg_service_pg = pg; 7281f6eb021SLiane Praza compose_props(match); 7291f6eb021SLiane Praza } 7301f6eb021SLiane Praza } 7311f6eb021SLiane Praza if (cpg != NULL) 7321f6eb021SLiane Praza composed_pg_destroy(cpg); 7331f6eb021SLiane Praza } 7341f6eb021SLiane Praza 7351f6eb021SLiane Praza static void 7361f6eb021SLiane Praza build_composed_instance(entity_t *inst) 7371f6eb021SLiane Praza { 7381f6eb021SLiane Praza uu_avl_t *tree; 7391f6eb021SLiane Praza 7401f6eb021SLiane Praza assert(inst->sc_etype == SVCCFG_INSTANCE_OBJECT); 7411f6eb021SLiane Praza 7421f6eb021SLiane Praza if (inst->sc_u.sc_instance.sc_composed == NULL) { 7431f6eb021SLiane Praza tree = uu_avl_create(composed_pg_pool, inst, TMPL_DEBUG_TREE); 7441f6eb021SLiane Praza if (tree == NULL) { 7451f6eb021SLiane Praza uu_die(gettext("composed_instance tree creation " 7461f6eb021SLiane Praza "failed: %s\n"), uu_strerror(uu_error())); 7471f6eb021SLiane Praza } 7481f6eb021SLiane Praza inst->sc_u.sc_instance.sc_composed = tree; 7491f6eb021SLiane Praza } 7501f6eb021SLiane Praza build_composed_property_groups(inst, 7511f6eb021SLiane Praza inst->sc_u.sc_instance.sc_composed); 7521f6eb021SLiane Praza } 7531f6eb021SLiane Praza 7541f6eb021SLiane Praza static void 7551f6eb021SLiane Praza demolish_composed_instance(entity_t *inst) 7561f6eb021SLiane Praza { 7571f6eb021SLiane Praza composed_pg_t *cpg; 7581f6eb021SLiane Praza void *marker = NULL; 7591f6eb021SLiane Praza uu_avl_t *tree; 7601f6eb021SLiane Praza 7611f6eb021SLiane Praza tree = inst->sc_u.sc_instance.sc_composed; 7621f6eb021SLiane Praza if (tree == NULL) 7631f6eb021SLiane Praza return; 7641f6eb021SLiane Praza 7651f6eb021SLiane Praza marker = NULL; 7661f6eb021SLiane Praza while ((cpg = uu_avl_teardown(tree, &marker)) != NULL) { 7671f6eb021SLiane Praza composed_pg_destroy(cpg); 7681f6eb021SLiane Praza } 7691f6eb021SLiane Praza uu_avl_destroy(tree); 7701f6eb021SLiane Praza 7711f6eb021SLiane Praza inst->sc_u.sc_instance.sc_composed = NULL; 7721f6eb021SLiane Praza } 7731f6eb021SLiane Praza /* 7741f6eb021SLiane Praza * Return the number of values in prop. 7751f6eb021SLiane Praza */ 7761f6eb021SLiane Praza static size_t 7771f6eb021SLiane Praza count_prop_values(property_t *prop) 7781f6eb021SLiane Praza { 7791f6eb021SLiane Praza return (uu_list_numnodes(prop->sc_property_values)); 7801f6eb021SLiane Praza } 7811f6eb021SLiane Praza 7821f6eb021SLiane Praza static int 7831f6eb021SLiane Praza is_numeric_type(scf_type_t type) 7841f6eb021SLiane Praza { 7851f6eb021SLiane Praza if (type == SCF_TYPE_BOOLEAN) 7861f6eb021SLiane Praza return (1); 7871f6eb021SLiane Praza if (type == SCF_TYPE_COUNT) 7881f6eb021SLiane Praza return (1); 7891f6eb021SLiane Praza if (type == SCF_TYPE_INTEGER) 7901f6eb021SLiane Praza return (1); 7911f6eb021SLiane Praza return (0); 7921f6eb021SLiane Praza } 7931f6eb021SLiane Praza 7941f6eb021SLiane Praza static pg_type_t 7951f6eb021SLiane Praza pgroup_type(pgroup_t *pg) 7961f6eb021SLiane Praza { 7971f6eb021SLiane Praza if (strcmp(pg->sc_pgroup_type, SCF_GROUP_TEMPLATE_PG_PATTERN) == 0) 7981f6eb021SLiane Praza return (PG_PATTERN_PG); 7991f6eb021SLiane Praza if (strcmp(pg->sc_pgroup_type, SCF_GROUP_TEMPLATE_PROP_PATTERN) == 0) 8001f6eb021SLiane Praza return (PROP_PATTERN_PG); 8011f6eb021SLiane Praza return (NORMAL_PG); 8021f6eb021SLiane Praza } 8031f6eb021SLiane Praza 8041f6eb021SLiane Praza /* 8051f6eb021SLiane Praza * Search the property group at pg for a property named name. If the 8061f6eb021SLiane Praza * property group has a tree of composed properties, the tree will be 8071f6eb021SLiane Praza * searched for the property. Otherwise, the property group's linked list 8081f6eb021SLiane Praza * will be searched. 8091f6eb021SLiane Praza */ 8101f6eb021SLiane Praza static property_t * 8111f6eb021SLiane Praza property_find(pgroup_t *pg, const char *name) 8121f6eb021SLiane Praza { 8131f6eb021SLiane Praza composed_pg_t *cpg; 8141f6eb021SLiane Praza property_t look; 8151f6eb021SLiane Praza 8161f6eb021SLiane Praza cpg = pg->sc_pgroup_composed; 8171f6eb021SLiane Praza 8181f6eb021SLiane Praza if ((cpg == NULL) || (cpg->cpg_composed_props == NULL)) { 8191f6eb021SLiane Praza /* This is not a composed property group. */ 8201f6eb021SLiane Praza return (internal_property_find(pg, name)); 8211f6eb021SLiane Praza } 8221f6eb021SLiane Praza 8231f6eb021SLiane Praza /* 8241f6eb021SLiane Praza * This is a composed property group, so look for the property in 8251f6eb021SLiane Praza * the AVL tree. 8261f6eb021SLiane Praza */ 8271f6eb021SLiane Praza look.sc_property_name = (char *)name; 8281f6eb021SLiane Praza return (uu_avl_find(cpg->cpg_composed_props, &look, NULL, NULL)); 8291f6eb021SLiane Praza } 8301f6eb021SLiane Praza 8311f6eb021SLiane Praza /* 8321f6eb021SLiane Praza * Functions for manipulating the avalues structure. 8331f6eb021SLiane Praza */ 8341f6eb021SLiane Praza 8351f6eb021SLiane Praza /* 8361f6eb021SLiane Praza * Free allocated memory referenced by the avalues structure. Then, free 8371f6eb021SLiane Praza * the structure itself. 8381f6eb021SLiane Praza */ 8391f6eb021SLiane Praza static void 8401f6eb021SLiane Praza av_destroy(avalues_t *av) 8411f6eb021SLiane Praza { 8421f6eb021SLiane Praza if (av == NULL) 8431f6eb021SLiane Praza return; 8441f6eb021SLiane Praza switch (av->av_type) { 8451f6eb021SLiane Praza case SCF_TYPE_BOOLEAN: 8461f6eb021SLiane Praza case SCF_TYPE_COUNT: 8471f6eb021SLiane Praza uu_free(av->av_v.av_unsigned); 8481f6eb021SLiane Praza break; 8491f6eb021SLiane Praza case SCF_TYPE_INTEGER: 8501f6eb021SLiane Praza uu_free(av->av_v.av_integer); 8511f6eb021SLiane Praza break; 8521f6eb021SLiane Praza default: 8531f6eb021SLiane Praza /* 8541f6eb021SLiane Praza * We don't need to free the strings that are referenced by 8551f6eb021SLiane Praza * av_string. The strings are held in propery_t structures 8561f6eb021SLiane Praza * that will be freed at a later time. 8571f6eb021SLiane Praza */ 8581f6eb021SLiane Praza uu_free(av->av_v.av_string); 8591f6eb021SLiane Praza break; 8601f6eb021SLiane Praza } 8611f6eb021SLiane Praza uu_free(av); 8621f6eb021SLiane Praza } 8631f6eb021SLiane Praza /* 8641f6eb021SLiane Praza * Allocate and inialize an avalues structure. count represents the 8651f6eb021SLiane Praza * number of values the structure is expected to hold. type specifies how 8661f6eb021SLiane Praza * the consumer of the property values would like to see them represented. 8671f6eb021SLiane Praza * See comments for the av_get_values() more details on how type is used. 8681f6eb021SLiane Praza * 8691f6eb021SLiane Praza * The returned structure must be freed by calling av_destroy(). 8701f6eb021SLiane Praza * 8711f6eb021SLiane Praza * NULL is returned if memory allocation fails. 8721f6eb021SLiane Praza */ 8731f6eb021SLiane Praza static avalues_t * 8741f6eb021SLiane Praza av_create(size_t count, scf_type_t type) 8751f6eb021SLiane Praza { 8761f6eb021SLiane Praza uint_t alloc_failed = 0; 8771f6eb021SLiane Praza avalues_t *av; 8781f6eb021SLiane Praza 8791f6eb021SLiane Praza av = uu_zalloc(sizeof (*av)); 8801f6eb021SLiane Praza if (av == NULL) 8811f6eb021SLiane Praza return (NULL); 8821f6eb021SLiane Praza av->av_count = count; 8831f6eb021SLiane Praza av->av_type = type; 8841f6eb021SLiane Praza switch (type) { 8851f6eb021SLiane Praza case SCF_TYPE_BOOLEAN: 8861f6eb021SLiane Praza case SCF_TYPE_COUNT: 8871f6eb021SLiane Praza av->av_v.av_unsigned = uu_zalloc(count * sizeof (uint64_t)); 8881f6eb021SLiane Praza if (av->av_v.av_unsigned == NULL) 8891f6eb021SLiane Praza alloc_failed = 1; 8901f6eb021SLiane Praza break; 8911f6eb021SLiane Praza case SCF_TYPE_INTEGER: 8921f6eb021SLiane Praza av->av_v.av_integer = uu_zalloc(count * sizeof (int64_t)); 8931f6eb021SLiane Praza if (av->av_v.av_integer == NULL) 8941f6eb021SLiane Praza alloc_failed = 1; 8951f6eb021SLiane Praza break; 8961f6eb021SLiane Praza default: 8971f6eb021SLiane Praza av->av_v.av_string = uu_zalloc(count * sizeof (char *)); 8981f6eb021SLiane Praza if (av->av_v.av_string == NULL) 8991f6eb021SLiane Praza alloc_failed = 1; 9001f6eb021SLiane Praza } 9011f6eb021SLiane Praza if (alloc_failed) { 9021f6eb021SLiane Praza av_destroy(av); 9031f6eb021SLiane Praza return (NULL); 9041f6eb021SLiane Praza } 9051f6eb021SLiane Praza return (av); 9061f6eb021SLiane Praza } 9071f6eb021SLiane Praza 9081f6eb021SLiane Praza /* 9091f6eb021SLiane Praza * Return the ith integer value in av. 9101f6eb021SLiane Praza */ 9111f6eb021SLiane Praza static int64_t 9121f6eb021SLiane Praza av_get_integer(avalues_t *av, uint_t i) 9131f6eb021SLiane Praza { 9141f6eb021SLiane Praza assert(av->av_type == SCF_TYPE_INTEGER); 9151f6eb021SLiane Praza assert(i < av->av_count); 9161f6eb021SLiane Praza return (*(av->av_v.av_integer + i)); 9171f6eb021SLiane Praza } 9181f6eb021SLiane Praza 9191f6eb021SLiane Praza /* 9201f6eb021SLiane Praza * Return the ith string value in av. 9211f6eb021SLiane Praza */ 9221f6eb021SLiane Praza static const char * 9231f6eb021SLiane Praza av_get_string(avalues_t *av, uint_t i) 9241f6eb021SLiane Praza { 9251f6eb021SLiane Praza assert(is_numeric_type(av->av_type) == 0); 9261f6eb021SLiane Praza assert(i < av->av_count); 9271f6eb021SLiane Praza return (*(av->av_v.av_string + i)); 9281f6eb021SLiane Praza } 9291f6eb021SLiane Praza 9301f6eb021SLiane Praza /* 9311f6eb021SLiane Praza * Return the ith unsigned value in av. 9321f6eb021SLiane Praza */ 9331f6eb021SLiane Praza static uint64_t 9341f6eb021SLiane Praza av_get_unsigned(avalues_t *av, uint_t i) 9351f6eb021SLiane Praza { 9361f6eb021SLiane Praza assert((av->av_type == SCF_TYPE_BOOLEAN) || 9371f6eb021SLiane Praza (av->av_type == SCF_TYPE_COUNT)); 9381f6eb021SLiane Praza assert(i < av->av_count); 9391f6eb021SLiane Praza return (*(av->av_v.av_unsigned + i)); 9401f6eb021SLiane Praza } 9411f6eb021SLiane Praza 9421f6eb021SLiane Praza /* 9431f6eb021SLiane Praza * Store the value in the ith slot of the av structure. If av is being 9441f6eb021SLiane Praza * used to store numeric values, the string at value will be converted to 9451f6eb021SLiane Praza * the appropriate numeric form. 9461f6eb021SLiane Praza */ 9471f6eb021SLiane Praza static tmpl_validate_status_t 9481f6eb021SLiane Praza av_set_value(avalues_t *av, uint_t i, const char *value) 9491f6eb021SLiane Praza { 9501f6eb021SLiane Praza char *endptr; 9511f6eb021SLiane Praza int64_t n; 9521f6eb021SLiane Praza uint64_t un; 9531f6eb021SLiane Praza 9541f6eb021SLiane Praza if (is_numeric_type(av->av_type)) { 9551f6eb021SLiane Praza switch (av->av_type) { 9561f6eb021SLiane Praza case SCF_TYPE_BOOLEAN: 9571f6eb021SLiane Praza case SCF_TYPE_COUNT: 9581f6eb021SLiane Praza un = strtoull(value, &endptr, 0); 9591f6eb021SLiane Praza if ((endptr == value) || (*endptr != 0)) { 9601f6eb021SLiane Praza return (TVS_BAD_CONVERSION); 9611f6eb021SLiane Praza } 9621f6eb021SLiane Praza *(av->av_v.av_unsigned + i) = un; 9631f6eb021SLiane Praza break; 9641f6eb021SLiane Praza case SCF_TYPE_INTEGER: 9651f6eb021SLiane Praza n = strtoll(value, &endptr, 0); 9661f6eb021SLiane Praza if ((endptr == value) || (*endptr != 0)) { 9671f6eb021SLiane Praza return (TVS_BAD_CONVERSION); 9681f6eb021SLiane Praza } 9691f6eb021SLiane Praza *(av->av_v.av_integer + i) = n; 9701f6eb021SLiane Praza } 9711f6eb021SLiane Praza } else { 9721f6eb021SLiane Praza *(av->av_v.av_string + i) = value; 9731f6eb021SLiane Praza } 9741f6eb021SLiane Praza 9751f6eb021SLiane Praza return (TVS_SUCCESS); 9761f6eb021SLiane Praza } 9771f6eb021SLiane Praza 9781f6eb021SLiane Praza /* 9791f6eb021SLiane Praza * Find the property whose name is prop_name in the property group at pg. 9801f6eb021SLiane Praza * Read all the values of this property and return them in an avalues 9811f6eb021SLiane Praza * structure placing the address of the structure in *values. The caller 9821f6eb021SLiane Praza * must free the structure by calling av_destroy(). 9831f6eb021SLiane Praza * 9841f6eb021SLiane Praza * The type parameter is used to indicate the type of information that the 9851f6eb021SLiane Praza * caller would like to consume. If it is one of the numeric types, the 9861f6eb021SLiane Praza * property value will be converted to the appropriate numeric type before 9871f6eb021SLiane Praza * placing it in the avalues struct. Decoding will be done before the 9881f6eb021SLiane Praza * conversion if necessary. 9891f6eb021SLiane Praza */ 9901f6eb021SLiane Praza static tmpl_validate_status_t 9911f6eb021SLiane Praza av_get_values(pgroup_t *pg, const char *prop_name, scf_type_t type, 9921f6eb021SLiane Praza avalues_t **values) 9931f6eb021SLiane Praza { 9941f6eb021SLiane Praza avalues_t *av; 9951f6eb021SLiane Praza uint_t i; 9961f6eb021SLiane Praza property_t *prop; 9971f6eb021SLiane Praza tmpl_validate_status_t rc; 9981f6eb021SLiane Praza value_t *v; 9991f6eb021SLiane Praza 10001f6eb021SLiane Praza prop = property_find(pg, prop_name); 10011f6eb021SLiane Praza if (prop == NULL) { 10021f6eb021SLiane Praza return (TVS_NOMATCH); 10031f6eb021SLiane Praza } 10041f6eb021SLiane Praza assert(prop->sc_value_type == SCF_TYPE_ASTRING); 10051f6eb021SLiane Praza av = av_create(count_prop_values(prop), type); 10061f6eb021SLiane Praza if (av == NULL) 10071f6eb021SLiane Praza uu_die(emesg_nomem); 10081f6eb021SLiane Praza 10091f6eb021SLiane Praza /* Collect the values. */ 10101f6eb021SLiane Praza for ((v = uu_list_first(prop->sc_property_values)), i = 0; 10111f6eb021SLiane Praza v != NULL; 10121f6eb021SLiane Praza (v = uu_list_next(prop->sc_property_values, v)), i++) { 10131f6eb021SLiane Praza assert(i < av->av_count); 10141f6eb021SLiane Praza assert(v->sc_type == SCF_TYPE_ASTRING); 10151f6eb021SLiane Praza rc = av_set_value(av, i, v->sc_u.sc_string); 10161f6eb021SLiane Praza if (rc != TVS_SUCCESS) { 10171f6eb021SLiane Praza av_destroy(av); 10181f6eb021SLiane Praza return (rc); 10191f6eb021SLiane Praza } 10201f6eb021SLiane Praza } 10211f6eb021SLiane Praza *values = av; 10221f6eb021SLiane Praza return (TVS_SUCCESS); 10231f6eb021SLiane Praza } 10241f6eb021SLiane Praza 10251f6eb021SLiane Praza /* 10261f6eb021SLiane Praza * Find the property in pg whose name is prop_name. Return a pointer to 10271f6eb021SLiane Praza * the first astring value in that property. 10281f6eb021SLiane Praza * 10291f6eb021SLiane Praza * NULL is returned if there is no property named prop_name or if it does 10301f6eb021SLiane Praza * not have an astring value. 10311f6eb021SLiane Praza */ 10321f6eb021SLiane Praza static const char * 10331f6eb021SLiane Praza find_astring_value_in_pg(pgroup_t *pg, const char *prop_name) 10341f6eb021SLiane Praza { 10351f6eb021SLiane Praza property_t *prop; 10361f6eb021SLiane Praza value_t *v; 10371f6eb021SLiane Praza 10381f6eb021SLiane Praza prop = property_find(pg, prop_name); 10391f6eb021SLiane Praza if (prop == NULL) 10401f6eb021SLiane Praza return (NULL); 10411f6eb021SLiane Praza if (prop->sc_value_type != SCF_TYPE_ASTRING) 10421f6eb021SLiane Praza return (NULL); 10431f6eb021SLiane Praza v = uu_list_first(prop->sc_property_values); 10441f6eb021SLiane Praza if (v == NULL) 10451f6eb021SLiane Praza return (NULL); 10461f6eb021SLiane Praza assert(v->sc_type == SCF_TYPE_ASTRING); 10471f6eb021SLiane Praza return (v->sc_u.sc_string); 10481f6eb021SLiane Praza } 10491f6eb021SLiane Praza /* 10501f6eb021SLiane Praza * Find the first property value of type SCF_TYPE_COUNT in the property at 10511f6eb021SLiane Praza * prop. Return the value to count. 10521f6eb021SLiane Praza */ 10531f6eb021SLiane Praza static tmpl_validate_status_t 10541f6eb021SLiane Praza find_count_value(property_t *prop, uint64_t *count) 10551f6eb021SLiane Praza { 10561f6eb021SLiane Praza value_t *value; 10571f6eb021SLiane Praza 10581f6eb021SLiane Praza assert(prop->sc_value_type == SCF_TYPE_COUNT); 10591f6eb021SLiane Praza value = uu_list_first(prop->sc_property_values); 10601f6eb021SLiane Praza if (value == NULL) 10611f6eb021SLiane Praza return (TVS_NOMATCH); 10621f6eb021SLiane Praza *count = value->sc_u.sc_count; 10631f6eb021SLiane Praza return (TVS_SUCCESS); 10641f6eb021SLiane Praza } 10651f6eb021SLiane Praza 10661f6eb021SLiane Praza /* 10671f6eb021SLiane Praza * pattern is a property group representing a pg_pattern or a 10681f6eb021SLiane Praza * prop_pattern. This function returns the name specification from the 10691f6eb021SLiane Praza * pg_pattern or prop_pattern. 10701f6eb021SLiane Praza */ 10711f6eb021SLiane Praza static const char * 10721f6eb021SLiane Praza find_name_specification(pgroup_t *pattern) 10731f6eb021SLiane Praza { 10741f6eb021SLiane Praza return (find_astring_value_in_pg(pattern, SCF_PROPERTY_TM_NAME)); 10751f6eb021SLiane Praza } 10761f6eb021SLiane Praza 10771f6eb021SLiane Praza /* 10781f6eb021SLiane Praza * pattern is a property group representing a pg_pattern or a prop_pattern. 10791f6eb021SLiane Praza * This function returns the type specification from the pg_pattern or 10801f6eb021SLiane Praza * prop_pattern. 10811f6eb021SLiane Praza */ 10821f6eb021SLiane Praza static const char * 10831f6eb021SLiane Praza find_type_specification(pgroup_t *pattern) 10841f6eb021SLiane Praza { 10851f6eb021SLiane Praza return (find_astring_value_in_pg(pattern, SCF_PROPERTY_TM_TYPE)); 10861f6eb021SLiane Praza } 10871f6eb021SLiane Praza 10881f6eb021SLiane Praza /* 10891f6eb021SLiane Praza * Find the FMRI of the restarter for the entity, e. The restarter is the 10901f6eb021SLiane Praza * value of the "restarter" property in the "general" property group. 10911f6eb021SLiane Praza */ 10921f6eb021SLiane Praza static const char * 10931f6eb021SLiane Praza find_restarter(entity_t *e) 10941f6eb021SLiane Praza { 10951f6eb021SLiane Praza pgroup_t *pg; 10961f6eb021SLiane Praza property_t *prop; 10971f6eb021SLiane Praza value_t *v; 10981f6eb021SLiane Praza 10991f6eb021SLiane Praza pg = internal_pgroup_find(e, scf_pg_general, scf_group_framework); 11001f6eb021SLiane Praza if (pg != NULL) { 11011f6eb021SLiane Praza prop = property_find(pg, SCF_PROPERTY_RESTARTER); 11021f6eb021SLiane Praza if ((prop != NULL) && (prop->sc_value_type == SCF_TYPE_FMRI)) { 11031f6eb021SLiane Praza v = uu_list_first(prop->sc_property_values); 11041f6eb021SLiane Praza if (v != NULL) 11051f6eb021SLiane Praza return (v->sc_u.sc_string); 11061f6eb021SLiane Praza } 11071f6eb021SLiane Praza } 11081f6eb021SLiane Praza 11091f6eb021SLiane Praza /* 11101f6eb021SLiane Praza * Didn't find the restarter. 11111f6eb021SLiane Praza */ 11121f6eb021SLiane Praza return (NULL); 11131f6eb021SLiane Praza } 11141f6eb021SLiane Praza 11151f6eb021SLiane Praza /* 11161f6eb021SLiane Praza * prop_pattern points to a prop_pattern. This function finds the 11171f6eb021SLiane Praza * cardinality specification in the prop_pattern and returns the minimum 11181f6eb021SLiane Praza * and maximum values of the cardinality. 11191f6eb021SLiane Praza * 11201f6eb021SLiane Praza * Returns TVS_NOMATCH if either the cardinality minimum or maximum are 11211f6eb021SLiane Praza * missing. 11221f6eb021SLiane Praza */ 11231f6eb021SLiane Praza static tmpl_validate_status_t 11241f6eb021SLiane Praza get_cardinality(pgroup_t *prop_pattern, uint64_t *min, uint64_t *max) 11251f6eb021SLiane Praza { 11261f6eb021SLiane Praza property_t *prop; 11271f6eb021SLiane Praza tmpl_validate_status_t rc; 11281f6eb021SLiane Praza 11291f6eb021SLiane Praza assert(strcmp(prop_pattern->sc_pgroup_type, 11301f6eb021SLiane Praza SCF_GROUP_TEMPLATE_PROP_PATTERN) == 0); 11311f6eb021SLiane Praza 11321f6eb021SLiane Praza prop = property_find(prop_pattern, 11331f6eb021SLiane Praza SCF_PROPERTY_TM_CARDINALITY_MIN); 11341f6eb021SLiane Praza if (prop == NULL) 11351f6eb021SLiane Praza return (TVS_NOMATCH); 11361f6eb021SLiane Praza rc = find_count_value(prop, min); 11371f6eb021SLiane Praza if (rc != TVS_SUCCESS) 11381f6eb021SLiane Praza return (rc); 11391f6eb021SLiane Praza 11401f6eb021SLiane Praza prop = property_find(prop_pattern, 11411f6eb021SLiane Praza SCF_PROPERTY_TM_CARDINALITY_MAX); 11421f6eb021SLiane Praza if (prop == NULL) 11431f6eb021SLiane Praza return (TVS_NOMATCH); 11441f6eb021SLiane Praza rc = find_count_value(prop, max); 11451f6eb021SLiane Praza 11461f6eb021SLiane Praza return (rc); 11471f6eb021SLiane Praza } 11481f6eb021SLiane Praza 11491f6eb021SLiane Praza /* 11501f6eb021SLiane Praza * Ranges are represented as ASTRING values in the property at range_prop. 11511f6eb021SLiane Praza * The minimum and maximum of the range are separated by a comma. 11521f6eb021SLiane Praza * 11531f6eb021SLiane Praza * range_prop can contain multiple range values, so we return a pointer to 11541f6eb021SLiane Praza * an allocated array of range_t in ranges. This array must be freed by 11551f6eb021SLiane Praza * the caller using free(). count receives the number of range_t 11561f6eb021SLiane Praza * structures that are allocated. 11571f6eb021SLiane Praza * 11581f6eb021SLiane Praza * type tells us whether the range values should be treated as signed or 11591f6eb021SLiane Praza * unsigned. It must be SCF_TYPE_COUNT or SCF_TYPE_INTEGER. 11601f6eb021SLiane Praza */ 11611f6eb021SLiane Praza static tmpl_validate_status_t 11621f6eb021SLiane Praza get_ranges(property_t *range_prop, scf_type_t type, range_t **ranges, 11631f6eb021SLiane Praza uint_t *count) 11641f6eb021SLiane Praza { 11651f6eb021SLiane Praza char *endptr; 11661f6eb021SLiane Praza char *endptr2; 11671f6eb021SLiane Praza range_t *r; 11681f6eb021SLiane Praza value_t *value; 11691f6eb021SLiane Praza 11701f6eb021SLiane Praza *count = uu_list_numnodes(range_prop->sc_property_values); 11711f6eb021SLiane Praza assert(*count != 0); 11721f6eb021SLiane Praza r = safe_malloc(*count * sizeof (*r)); 11731f6eb021SLiane Praza *ranges = r; 11741f6eb021SLiane Praza for (value = uu_list_first(range_prop->sc_property_values); 11751f6eb021SLiane Praza value != NULL; 11761f6eb021SLiane Praza value = uu_list_next(range_prop->sc_property_values, value)) { 11771f6eb021SLiane Praza assert(value->sc_type == SCF_TYPE_ASTRING); 11781f6eb021SLiane Praza 11791f6eb021SLiane Praza /* First get the minimum */ 11801f6eb021SLiane Praza errno = 0; 11811f6eb021SLiane Praza if (type == SCF_TYPE_INTEGER) { 11821f6eb021SLiane Praza r->rng_u.rng_signed.rng_min = 11831f6eb021SLiane Praza strtoll(value->sc_u.sc_string, &endptr, 0); 11841f6eb021SLiane Praza } else { 11851f6eb021SLiane Praza r->rng_u.rng_unsigned.rng_min = 11861f6eb021SLiane Praza strtoull(value->sc_u.sc_string, &endptr, 0); 11871f6eb021SLiane Praza } 11881f6eb021SLiane Praza if ((errno != 0) || (endptr == value->sc_u.sc_string)) 11891f6eb021SLiane Praza goto badtemplate; 11901f6eb021SLiane Praza if (*endptr != ',') 11911f6eb021SLiane Praza goto badtemplate; 11921f6eb021SLiane Praza 11931f6eb021SLiane Praza /* Now get the maximum */ 11941f6eb021SLiane Praza endptr++; 11951f6eb021SLiane Praza if (type == SCF_TYPE_INTEGER) { 11961f6eb021SLiane Praza r->rng_u.rng_signed.rng_max = 11971f6eb021SLiane Praza strtoll(endptr, &endptr2, 0); 11981f6eb021SLiane Praza } else { 11991f6eb021SLiane Praza r->rng_u.rng_unsigned.rng_max = 12001f6eb021SLiane Praza strtoull(endptr, &endptr2, 0); 12011f6eb021SLiane Praza } 12021f6eb021SLiane Praza if ((errno != 0) || (endptr2 == endptr) || 12031f6eb021SLiane Praza (*endptr2 != 0)) 12041f6eb021SLiane Praza goto badtemplate; 12051f6eb021SLiane Praza r++; 12061f6eb021SLiane Praza } 12071f6eb021SLiane Praza 12081f6eb021SLiane Praza return (TVS_SUCCESS); 12091f6eb021SLiane Praza 12101f6eb021SLiane Praza badtemplate: 12111f6eb021SLiane Praza free(*ranges); 12121f6eb021SLiane Praza *ranges = NULL; 12131f6eb021SLiane Praza return (TVS_BAD_TEMPLATE); 12141f6eb021SLiane Praza } 12151f6eb021SLiane Praza 12161f6eb021SLiane Praza static tv_errors_t * 12171f6eb021SLiane Praza tv_errors_create(const char *fmri) 12181f6eb021SLiane Praza { 12191f6eb021SLiane Praza tv_errors_t *ste; 12201f6eb021SLiane Praza 12211f6eb021SLiane Praza ste = safe_malloc(sizeof (*ste)); 12221f6eb021SLiane Praza uu_list_node_init(ste, &ste->tve_node, tv_errors_pool); 12231f6eb021SLiane Praza ste->tve_errors = _scf_create_errors(fmri, 1); 12241f6eb021SLiane Praza if (ste->tve_errors == NULL) 12251f6eb021SLiane Praza uu_die(emesg_nomem); 12261f6eb021SLiane Praza 12271f6eb021SLiane Praza return (ste); 12281f6eb021SLiane Praza } 12291f6eb021SLiane Praza 12301f6eb021SLiane Praza static void 12311f6eb021SLiane Praza destroy_scf_errors(tv_errors_t *ste) 12321f6eb021SLiane Praza { 12331f6eb021SLiane Praza scf_tmpl_errors_destroy(ste->tve_errors); 12341f6eb021SLiane Praza uu_list_node_fini(ste, &ste->tve_node, tv_errors_pool); 12351f6eb021SLiane Praza free(ste); 12361f6eb021SLiane Praza } 12371f6eb021SLiane Praza 12381f6eb021SLiane Praza /* 12391f6eb021SLiane Praza * Given a property group and the name of a property within that property 12401f6eb021SLiane Praza * group, generate the name of the property group that holds the 12411f6eb021SLiane Praza * prop_pattern information for the property. The address of the generated 12421f6eb021SLiane Praza * name is returned to prop_pattern_pg_name. The memory holding the 12431f6eb021SLiane Praza * generated name must be freed using uu_free(). 12441f6eb021SLiane Praza */ 12451f6eb021SLiane Praza static tmpl_validate_status_t 12461f6eb021SLiane Praza gen_prop_pattern_pg_name(pgroup_t *pg_pattern, const char *prop_name, 12471f6eb021SLiane Praza char **prop_pattern_pg_name) 12481f6eb021SLiane Praza { 12491f6eb021SLiane Praza ssize_t limit; 12501f6eb021SLiane Praza char *name; 12511f6eb021SLiane Praza size_t prefix_size; 12521f6eb021SLiane Praza const char *unique; 12531f6eb021SLiane Praza 12541f6eb021SLiane Praza limit = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1; 12551f6eb021SLiane Praza assert(limit > 0); 12561f6eb021SLiane Praza 12571f6eb021SLiane Praza /* Get the unique part of the pg_pattern's property group name. */ 12581f6eb021SLiane Praza prefix_size = strlen(SCF_PG_TM_PG_PAT_BASE); 12591f6eb021SLiane Praza assert(strncmp(pg_pattern->sc_pgroup_name, SCF_PG_TM_PG_PAT_BASE, 12601f6eb021SLiane Praza prefix_size) == 0); 12611f6eb021SLiane Praza unique = pg_pattern->sc_pgroup_name + prefix_size; 12621f6eb021SLiane Praza 12631f6eb021SLiane Praza /* Construct the prop pattern property group name. */ 12641f6eb021SLiane Praza *prop_pattern_pg_name = NULL; 12651f6eb021SLiane Praza name = uu_zalloc(limit); 12661f6eb021SLiane Praza if (name == NULL) 12671f6eb021SLiane Praza uu_die(emesg_nomem); 12681f6eb021SLiane Praza if (snprintf(name, limit, "%s%s_%s", SCF_PG_TM_PROP_PATTERN_PREFIX, 12691f6eb021SLiane Praza unique, prop_name) >= limit) { 12701f6eb021SLiane Praza uu_free(name); 12711f6eb021SLiane Praza return (TVS_BAD_TEMPLATE); 12721f6eb021SLiane Praza } 12731f6eb021SLiane Praza *prop_pattern_pg_name = name; 12741f6eb021SLiane Praza return (TVS_SUCCESS); 12751f6eb021SLiane Praza } 12761f6eb021SLiane Praza 12771f6eb021SLiane Praza /* 12781f6eb021SLiane Praza * Error message printing functions: 12791f6eb021SLiane Praza */ 12801f6eb021SLiane Praza 12811f6eb021SLiane Praza /* 12821f6eb021SLiane Praza * Flags for use by im_perror_item. 12831f6eb021SLiane Praza */ 12841f6eb021SLiane Praza #define IPI_NOT_FIRST 0x1 /* Not first item to be displayed. */ 12851f6eb021SLiane Praza 12861f6eb021SLiane Praza /* 12871f6eb021SLiane Praza * Print a single item of information about a validation failure. This 12881f6eb021SLiane Praza * function takes care of printing the appropriate decoration before the 12891f6eb021SLiane Praza * first item and between subsequent items. 12901f6eb021SLiane Praza * 12911f6eb021SLiane Praza * Parameters: 12921f6eb021SLiane Praza * out Stream to receive the output. 12931f6eb021SLiane Praza * desc Text describing the items 12941f6eb021SLiane Praza * item Address of the item to be displayed 12951f6eb021SLiane Praza * type Type of the item 12961f6eb021SLiane Praza * flags Used by im_perror_item to keep track of where it 12971f6eb021SLiane Praza * is. Caller should set flags to 0 before calling 12981f6eb021SLiane Praza * this function with the first item. 12991f6eb021SLiane Praza */ 13001f6eb021SLiane Praza static void 13011f6eb021SLiane Praza im_perror_item(FILE *out, const char *desc, void *item, scf_type_t type, 13021f6eb021SLiane Praza int *flags) 13031f6eb021SLiane Praza { 13041f6eb021SLiane Praza const char *cp; 13051f6eb021SLiane Praza const char *first_sep; 13061f6eb021SLiane Praza int64_t ival; 13071f6eb021SLiane Praza const char *subsequent_sep; 13081f6eb021SLiane Praza uint64_t uval; 13091f6eb021SLiane Praza 13101f6eb021SLiane Praza /* Nothing to print if item is NULL. */ 13111f6eb021SLiane Praza if (item == NULL) 13121f6eb021SLiane Praza return; 13131f6eb021SLiane Praza 13141f6eb021SLiane Praza assert(type != SCF_TYPE_INVALID); 13151f6eb021SLiane Praza 13161f6eb021SLiane Praza /* Establish separators for environment. */ 13171f6eb021SLiane Praza if (est->sc_cmd_flags & SC_CMD_IACTIVE) { 13181f6eb021SLiane Praza /* Interactive mode - make messages readable */ 13191f6eb021SLiane Praza first_sep = ":\n\t"; 13201f6eb021SLiane Praza subsequent_sep = "\n\t"; 13211f6eb021SLiane Praza } else { 13221f6eb021SLiane Praza /* Non-interactive - one line messages. */ 13231f6eb021SLiane Praza first_sep = ": "; 13241f6eb021SLiane Praza subsequent_sep = "; "; 13251f6eb021SLiane Praza } 13261f6eb021SLiane Praza 13271f6eb021SLiane Praza /* Print separator and description */ 13281f6eb021SLiane Praza if (*flags & IPI_NOT_FIRST) { 13291f6eb021SLiane Praza (void) fprintf(out, subsequent_sep); 13301f6eb021SLiane Praza } else { 13311f6eb021SLiane Praza (void) fprintf(out, first_sep); 13321f6eb021SLiane Praza *flags |= IPI_NOT_FIRST; 13331f6eb021SLiane Praza } 13341f6eb021SLiane Praza (void) fprintf(out, "%s=", desc); 13351f6eb021SLiane Praza 13361f6eb021SLiane Praza switch (type) { 13371f6eb021SLiane Praza case SCF_TYPE_BOOLEAN: 13381f6eb021SLiane Praza uval = *((uint64_t *)item); 13391f6eb021SLiane Praza if (uval) { 13401f6eb021SLiane Praza (void) fprintf(out, "\"%s\"", gettext("true")); 13411f6eb021SLiane Praza } else { 13421f6eb021SLiane Praza (void) fprintf(out, "\"%s\"", gettext("false")); 13431f6eb021SLiane Praza } 13441f6eb021SLiane Praza break; 13451f6eb021SLiane Praza case SCF_TYPE_COUNT: 13461f6eb021SLiane Praza uval = *((uint64_t *)item); 13471f6eb021SLiane Praza (void) fprintf(out, "%" PRIu64, uval); 13481f6eb021SLiane Praza break; 13491f6eb021SLiane Praza case SCF_TYPE_INTEGER: 13501f6eb021SLiane Praza ival = *((int64_t *)item); 13511f6eb021SLiane Praza (void) fprintf(out, "%" PRIi64, ival); 13521f6eb021SLiane Praza break; 13531f6eb021SLiane Praza default: 13541f6eb021SLiane Praza /* 13551f6eb021SLiane Praza * Treat everything else as a string, but escape any 13561f6eb021SLiane Praza * internal quotes. 13571f6eb021SLiane Praza */ 13581f6eb021SLiane Praza (void) fputc('\"', out); 13591f6eb021SLiane Praza cp = (const char *)item; 13601f6eb021SLiane Praza while (*cp != 0) { 13611f6eb021SLiane Praza if (*cp == '\"') { 13621f6eb021SLiane Praza (void) fprintf(out, "\\\""); 13631f6eb021SLiane Praza } else { 13641f6eb021SLiane Praza (void) fputc(*cp, out); 13651f6eb021SLiane Praza } 13661f6eb021SLiane Praza cp++; 13671f6eb021SLiane Praza } 13681f6eb021SLiane Praza (void) fputc('\"', out); 13691f6eb021SLiane Praza break; 13701f6eb021SLiane Praza } 13711f6eb021SLiane Praza } 13721f6eb021SLiane Praza 13731f6eb021SLiane Praza /* 13741f6eb021SLiane Praza * Print erroneous FMRI. 13751f6eb021SLiane Praza */ 13761f6eb021SLiane Praza static void 13771f6eb021SLiane Praza im_perror_fmri(FILE *out, im_tmpl_error_t *i, int *flags) 13781f6eb021SLiane Praza { 13791f6eb021SLiane Praza if (i->ite_entity != NULL) { 13801f6eb021SLiane Praza im_perror_item(out, "FMRI", (void *)i->ite_entity->sc_fmri, 13811f6eb021SLiane Praza SCF_TYPE_FMRI, flags); 13821f6eb021SLiane Praza } 13831f6eb021SLiane Praza } 13841f6eb021SLiane Praza 13851f6eb021SLiane Praza /* 13861f6eb021SLiane Praza * Print erroneous property group name. 13871f6eb021SLiane Praza */ 13881f6eb021SLiane Praza static void 13891f6eb021SLiane Praza im_perror_pg_name(FILE *out, im_tmpl_error_t *i, int *flags) 13901f6eb021SLiane Praza { 13911f6eb021SLiane Praza if (i->ite_pg != NULL) { 13921f6eb021SLiane Praza im_perror_item(out, gettext("Property group"), 13931f6eb021SLiane Praza (void *)i->ite_pg->sc_pgroup_name, SCF_TYPE_ASTRING, 13941f6eb021SLiane Praza flags); 13951f6eb021SLiane Praza } 13961f6eb021SLiane Praza } 13971f6eb021SLiane Praza 13981f6eb021SLiane Praza /* 13991f6eb021SLiane Praza * If srcflag is 1, print the template source of the pg_pattern or 14001f6eb021SLiane Praza * prop_pattern at pattern. Always print the name and type of the pattern. 14011f6eb021SLiane Praza */ 14021f6eb021SLiane Praza static void 14031f6eb021SLiane Praza im_perror_pattern_info(FILE *out, pgroup_t *pattern, int *flags, int srcflag) 14041f6eb021SLiane Praza { 14051f6eb021SLiane Praza void *c; 14061f6eb021SLiane Praza const char *name_string; 14071f6eb021SLiane Praza const char *type_string; 14081f6eb021SLiane Praza 14091f6eb021SLiane Praza if (pattern == NULL) 14101f6eb021SLiane Praza return; 14111f6eb021SLiane Praza switch (pgroup_type(pattern)) { 14121f6eb021SLiane Praza case PG_PATTERN_PG: 14131f6eb021SLiane Praza name_string = gettext("pg_pattern name"); 14141f6eb021SLiane Praza type_string = gettext("pg_pattern type"); 14151f6eb021SLiane Praza break; 14161f6eb021SLiane Praza case PROP_PATTERN_PG: 14171f6eb021SLiane Praza name_string = gettext("prop_pattern name"); 14181f6eb021SLiane Praza type_string = gettext("prop_pattern type"); 14191f6eb021SLiane Praza break; 14201f6eb021SLiane Praza default: 14211f6eb021SLiane Praza assert(0); 14221f6eb021SLiane Praza abort(); 14231f6eb021SLiane Praza } 14241f6eb021SLiane Praza if (srcflag) { 14251f6eb021SLiane Praza im_perror_item(out, gettext("Template source"), 14261f6eb021SLiane Praza (void *)pattern->sc_parent->sc_fmri, SCF_TYPE_FMRI, flags); 14271f6eb021SLiane Praza } 14281f6eb021SLiane Praza c = (void *)find_name_specification(pattern); 14291f6eb021SLiane Praza im_perror_item(out, name_string, 14301f6eb021SLiane Praza (c == NULL) ? "" : c, SCF_TYPE_ASTRING, flags); 14311f6eb021SLiane Praza c = (void *)find_type_specification(pattern); 14321f6eb021SLiane Praza im_perror_item(out, type_string, 14331f6eb021SLiane Praza (c == NULL) ? "" : c, SCF_TYPE_ASTRING, flags); 14341f6eb021SLiane Praza } 14351f6eb021SLiane Praza 14361f6eb021SLiane Praza /* 14371f6eb021SLiane Praza * Print information about the template specifications that were violated, 14381f6eb021SLiane Praza * so that the user can find the specification. 14391f6eb021SLiane Praza */ 14401f6eb021SLiane Praza static void 14411f6eb021SLiane Praza im_perror_template_info(FILE *out, im_tmpl_error_t *i, int *flags) 14421f6eb021SLiane Praza { 14431f6eb021SLiane Praza pgroup_t *pg_pattern = i->ite_pg_pattern; 14441f6eb021SLiane Praza pgroup_t *prop_pattern = i->ite_prop_pattern; 14451f6eb021SLiane Praza int srcflag = 1; 14461f6eb021SLiane Praza 14471f6eb021SLiane Praza if (pg_pattern != NULL) { 14481f6eb021SLiane Praza im_perror_pattern_info(out, pg_pattern, flags, srcflag); 14491f6eb021SLiane Praza srcflag = 0; 14501f6eb021SLiane Praza } 14511f6eb021SLiane Praza if (prop_pattern != NULL) { 14521f6eb021SLiane Praza im_perror_pattern_info(out, prop_pattern, flags, srcflag); 14531f6eb021SLiane Praza } 14541f6eb021SLiane Praza } 14551f6eb021SLiane Praza 14561f6eb021SLiane Praza /* Print error message for TVS_BAD_CONVERSION errors. */ 14571f6eb021SLiane Praza static void 14581f6eb021SLiane Praza im_perror_bad_conversion(FILE *out, im_tmpl_error_t *i, const char *prefix) 14591f6eb021SLiane Praza { 14601f6eb021SLiane Praza int flags = 0; 14611f6eb021SLiane Praza 14621f6eb021SLiane Praza (void) fprintf(out, gettext("%sUnable to convert property value"), 14631f6eb021SLiane Praza prefix); 14641f6eb021SLiane Praza im_perror_fmri(out, i, &flags); 14651f6eb021SLiane Praza im_perror_pg_name(out, i, &flags); 14661f6eb021SLiane Praza im_perror_item(out, gettext("Property"), 14671f6eb021SLiane Praza (void *)i->ite_prop->sc_property_name, SCF_TYPE_ASTRING, &flags); 14681f6eb021SLiane Praza im_perror_template_info(out, i, &flags); 14691f6eb021SLiane Praza (void) fputc('\n', out); 14701f6eb021SLiane Praza } 14711f6eb021SLiane Praza 14721f6eb021SLiane Praza /* Print error message for TVS_BAD_TEMPLATE errors. */ 14731f6eb021SLiane Praza static void 14741f6eb021SLiane Praza im_perror_bad_template(FILE *out, im_tmpl_error_t *i, const char *prefix) 14751f6eb021SLiane Praza { 14761f6eb021SLiane Praza int flags = 0; 14771f6eb021SLiane Praza 14781f6eb021SLiane Praza assert(i->ite_einfo.ei_type == EIT_BAD_TEMPLATE); 14791f6eb021SLiane Praza (void) fprintf(out, gettext("%sInvalid template - %s"), prefix, 14801f6eb021SLiane Praza i->ite_einfo.ei_u.ei_bad_template.ei_reason); 14811f6eb021SLiane Praza im_perror_fmri(out, i, &flags); 14821f6eb021SLiane Praza im_perror_template_info(out, i, &flags); 14831f6eb021SLiane Praza (void) fputc('\n', out); 14841f6eb021SLiane Praza } 14851f6eb021SLiane Praza 14861f6eb021SLiane Praza /* 14871f6eb021SLiane Praza * Print error message for TVS_INVALID_TYPE_SPECIFICATION errors. This 14881f6eb021SLiane Praza * error occurs if a prop_pattern has an invalid type specification. Thus, 14891f6eb021SLiane Praza * it is an indication of an invalid template rather than a violation of a 14901f6eb021SLiane Praza * template. 14911f6eb021SLiane Praza */ 14921f6eb021SLiane Praza static void 14931f6eb021SLiane Praza im_perror_invalid_type(FILE *out, im_tmpl_error_t *i, const char *prefix) 14941f6eb021SLiane Praza { 14951f6eb021SLiane Praza int flags = 0; 14961f6eb021SLiane Praza const char *prop_pattern_name; 14971f6eb021SLiane Praza 14981f6eb021SLiane Praza (void) fprintf(out, gettext("%sInvalid type in prop_pattern"), prefix); 14991f6eb021SLiane Praza im_perror_pg_name(out, i, &flags); 15001f6eb021SLiane Praza if (i->ite_prop_pattern != NULL) { 15011f6eb021SLiane Praza prop_pattern_name = 15021f6eb021SLiane Praza find_name_specification(i->ite_prop_pattern); 15031f6eb021SLiane Praza im_perror_item(out, gettext("prop_pattern name"), 15041f6eb021SLiane Praza (void *)prop_pattern_name, SCF_TYPE_ASTRING, &flags); 15051f6eb021SLiane Praza } 15061f6eb021SLiane Praza im_perror_template_info(out, i, &flags); 15071f6eb021SLiane Praza (void) fputc('\n', out); 15081f6eb021SLiane Praza } 15091f6eb021SLiane Praza 15101f6eb021SLiane Praza /* 15111f6eb021SLiane Praza * Print error message for TVS_MISSING_PG_TYPE errors. In this case the 15121f6eb021SLiane Praza * template specifies a type, but the property group itself has no type. 15131f6eb021SLiane Praza */ 15141f6eb021SLiane Praza static void 15151f6eb021SLiane Praza im_perror_missing_pg_type(FILE *out, im_tmpl_error_t *i, const char *prefix) 15161f6eb021SLiane Praza { 15171f6eb021SLiane Praza int flags = 0; 15181f6eb021SLiane Praza const char *type_spec; 15191f6eb021SLiane Praza 15201f6eb021SLiane Praza (void) fprintf(out, gettext("%sProperty group has no type"), prefix); 15211f6eb021SLiane Praza im_perror_fmri(out, i, &flags); 15221f6eb021SLiane Praza im_perror_pg_name(out, i, &flags); 15231f6eb021SLiane Praza if (i->ite_pg_pattern != NULL) { 15241f6eb021SLiane Praza type_spec = find_type_specification(i->ite_pg_pattern); 15251f6eb021SLiane Praza im_perror_item(out, gettext("Type specified in pg_pattern"), 15261f6eb021SLiane Praza (void *)type_spec, SCF_TYPE_ASTRING, &flags); 15271f6eb021SLiane Praza } 15281f6eb021SLiane Praza (void) fputc('\n', out); 15291f6eb021SLiane Praza } 15301f6eb021SLiane Praza 15311f6eb021SLiane Praza /* 15321f6eb021SLiane Praza * Print error message for TVS_MISSING_TYPE_SPECIFICATION errors. A 15331f6eb021SLiane Praza * property group has a "required" attribute of true, but it does not have 15341f6eb021SLiane Praza * a type specification. 15351f6eb021SLiane Praza */ 15361f6eb021SLiane Praza static void 15371f6eb021SLiane Praza im_perror_missing_type(FILE *out, im_tmpl_error_t *i, const char *prefix) 15381f6eb021SLiane Praza { 15391f6eb021SLiane Praza int flags = 0; 15401f6eb021SLiane Praza const char *pg_pattern_name; 15411f6eb021SLiane Praza 15421f6eb021SLiane Praza (void) fprintf(out, gettext("%sPg_pattern with true required attribute " 15431f6eb021SLiane Praza "is missing the type attribute"), prefix); 15441f6eb021SLiane Praza im_perror_fmri(out, i, &flags); 15451f6eb021SLiane Praza if (i->ite_pg_pattern != NULL) { 15461f6eb021SLiane Praza pg_pattern_name = find_name_specification(i->ite_pg_pattern); 15471f6eb021SLiane Praza im_perror_item(out, gettext("Pg_pattern name"), 15481f6eb021SLiane Praza (void *)pg_pattern_name, SCF_TYPE_ASTRING, &flags); 15491f6eb021SLiane Praza } 15501f6eb021SLiane Praza im_perror_template_info(out, i, &flags); 15511f6eb021SLiane Praza (void) fputc('\n', out); 15521f6eb021SLiane Praza } 15531f6eb021SLiane Praza 15541f6eb021SLiane Praza static void 15551f6eb021SLiane Praza im_tmpl_error_print(FILE *out, im_tmpl_error_t *ite, const char *prefix) 15561f6eb021SLiane Praza { 15571f6eb021SLiane Praza switch (ite->ite_type) { 15581f6eb021SLiane Praza case TVS_BAD_CONVERSION: 15591f6eb021SLiane Praza im_perror_bad_conversion(out, ite, prefix); 15601f6eb021SLiane Praza break; 15611f6eb021SLiane Praza case TVS_BAD_TEMPLATE: 15621f6eb021SLiane Praza im_perror_bad_template(out, ite, prefix); 15631f6eb021SLiane Praza break; 15641f6eb021SLiane Praza case TVS_INVALID_TYPE_SPECIFICATION: 15651f6eb021SLiane Praza im_perror_invalid_type(out, ite, prefix); 15661f6eb021SLiane Praza break; 15671f6eb021SLiane Praza case TVS_MISSING_PG_TYPE: 15681f6eb021SLiane Praza im_perror_missing_pg_type(out, ite, prefix); 15691f6eb021SLiane Praza break; 15701f6eb021SLiane Praza case TVS_MISSING_TYPE_SPECIFICATION: 15711f6eb021SLiane Praza im_perror_missing_type(out, ite, prefix); 15721f6eb021SLiane Praza break; 15731f6eb021SLiane Praza case TVS_NOMATCH: 15741f6eb021SLiane Praza /* 15751f6eb021SLiane Praza * TVS_NOMATCH should be handled where it occurs. Thus, 15761f6eb021SLiane Praza * there are no error messages associated with it. 15771f6eb021SLiane Praza */ 15781f6eb021SLiane Praza assert(0); 15791f6eb021SLiane Praza abort(); 15801f6eb021SLiane Praza break; 15811f6eb021SLiane Praza case TVS_SUCCESS: 15821f6eb021SLiane Praza break; 15831f6eb021SLiane Praza default: 15841f6eb021SLiane Praza assert(0); 15851f6eb021SLiane Praza abort(); 15861f6eb021SLiane Praza } 15871f6eb021SLiane Praza } 15881f6eb021SLiane Praza 15891f6eb021SLiane Praza static char * 15901f6eb021SLiane Praza int64_to_str(int64_t i) 15911f6eb021SLiane Praza { 15921f6eb021SLiane Praza char *c; 15931f6eb021SLiane Praza const char *fmt; 15941f6eb021SLiane Praza int size; 15951f6eb021SLiane Praza 15961f6eb021SLiane Praza fmt = "%" PRIi64; 15971f6eb021SLiane Praza size = snprintf(NULL, 0, fmt, i) + 1; 15981f6eb021SLiane Praza c = safe_malloc(size); 15991f6eb021SLiane Praza (void) snprintf(c, size, fmt, i); 16001f6eb021SLiane Praza return (c); 16011f6eb021SLiane Praza } 16021f6eb021SLiane Praza 16031f6eb021SLiane Praza static char * 16041f6eb021SLiane Praza uint64_to_str(uint64_t u) 16051f6eb021SLiane Praza { 16061f6eb021SLiane Praza char *c; 16071f6eb021SLiane Praza const char *fmt; 16081f6eb021SLiane Praza int size; 16091f6eb021SLiane Praza 16101f6eb021SLiane Praza fmt = "%" PRIu64; 16111f6eb021SLiane Praza size = snprintf(NULL, 0, fmt, u) + 1; 16121f6eb021SLiane Praza c = safe_malloc(size); 16131f6eb021SLiane Praza (void) snprintf(c, size, fmt, u); 16141f6eb021SLiane Praza return (c); 16151f6eb021SLiane Praza } 16161f6eb021SLiane Praza 16171f6eb021SLiane Praza /* 16181f6eb021SLiane Praza * Convert the value to a string. The returned value must be freed using 16191f6eb021SLiane Praza * free(3C). 16201f6eb021SLiane Praza */ 16211f6eb021SLiane Praza static const char * 16221f6eb021SLiane Praza value_to_string(value_t *v) 16231f6eb021SLiane Praza { 16241f6eb021SLiane Praza char *c; 16251f6eb021SLiane Praza 16261f6eb021SLiane Praza if (is_numeric_type(v->sc_type)) { 16271f6eb021SLiane Praza switch (v->sc_type) { 16281f6eb021SLiane Praza case SCF_TYPE_BOOLEAN: 16291f6eb021SLiane Praza if (v->sc_u.sc_count == 0) { 16301f6eb021SLiane Praza c = gettext("false"); 16311f6eb021SLiane Praza } else { 16321f6eb021SLiane Praza c = gettext("true"); 16331f6eb021SLiane Praza } 16341f6eb021SLiane Praza break; 16351f6eb021SLiane Praza case SCF_TYPE_COUNT: 16361f6eb021SLiane Praza c = uint64_to_str(v->sc_u.sc_count); 16371f6eb021SLiane Praza return (c); 16381f6eb021SLiane Praza case SCF_TYPE_INTEGER: 16391f6eb021SLiane Praza c = int64_to_str(v->sc_u.sc_integer); 16401f6eb021SLiane Praza return (c); 16411f6eb021SLiane Praza } 16421f6eb021SLiane Praza } else { 16431f6eb021SLiane Praza c = v->sc_u.sc_string; 16441f6eb021SLiane Praza } 16451f6eb021SLiane Praza 16461f6eb021SLiane Praza return (safe_strdup(c)); 16471f6eb021SLiane Praza } 16481f6eb021SLiane Praza 16491f6eb021SLiane Praza /* 16501f6eb021SLiane Praza * Subscripts for common error data. 16511f6eb021SLiane Praza */ 16521f6eb021SLiane Praza #define ED_PG_NAME 0 16531f6eb021SLiane Praza #define ED_PROP_NAME 1 16541f6eb021SLiane Praza #define ED_TMPL_FMRI 2 16551f6eb021SLiane Praza #define ED_TMPL_PG_NAME 3 16561f6eb021SLiane Praza #define ED_TMPL_PG_TYPE 4 16571f6eb021SLiane Praza #define ED_TMPL_PROP_NAME 5 16581f6eb021SLiane Praza #define ED_TMPL_PROP_TYPE 6 16591f6eb021SLiane Praza #define ED_COUNT 7 16601f6eb021SLiane Praza 16611f6eb021SLiane Praza /* 16621f6eb021SLiane Praza * This function converts the error information specified by the function 16631f6eb021SLiane Praza * parameters. It converts it to form needed by _scf_tmpl_add_error(). 16641f6eb021SLiane Praza * _scf_tmpl_add_error() requires that the error information be in the form 16651f6eb021SLiane Praza * of allocated strings that can be freed when it is done with them. Thus, 16661f6eb021SLiane Praza * the bulk of this function is devoted to producing those allocated 16671f6eb021SLiane Praza * strings. 16681f6eb021SLiane Praza * 16691f6eb021SLiane Praza * Once the strings are ready, we call _scf_tmpl_add_error() to add an 16701f6eb021SLiane Praza * new error structure to errs. 16711f6eb021SLiane Praza */ 16721f6eb021SLiane Praza static int 16731f6eb021SLiane Praza add_scf_error(tmpl_errors_t *errs, scf_tmpl_error_type_t ec, 16741f6eb021SLiane Praza pgroup_t *pg_pattern, pgroup_t *pg, pgroup_t *prop_pattern, 16751f6eb021SLiane Praza property_t *prop, value_t *val, error_info_t *einfo) 16761f6eb021SLiane Praza { 16771f6eb021SLiane Praza const char *actual = NULL; 16781f6eb021SLiane Praza char *c; 16791f6eb021SLiane Praza pgroup_t *conflict; 16801f6eb021SLiane Praza const char *ed[ED_COUNT]; 16811f6eb021SLiane Praza const char *ev1 = NULL; 16821f6eb021SLiane Praza const char *ev2 = NULL; 16831f6eb021SLiane Praza int i; 16841f6eb021SLiane Praza scf_type_t prop_type; 16851f6eb021SLiane Praza int rc; 16861f6eb021SLiane Praza 16871f6eb021SLiane Praza (void) memset(ed, 0, sizeof (ed)); 16881f6eb021SLiane Praza 16891f6eb021SLiane Praza /* Set values that are common to most error types. */ 16901f6eb021SLiane Praza if (pg != NULL) { 16911f6eb021SLiane Praza ed[ED_PG_NAME] = pg->sc_pgroup_name; 16921f6eb021SLiane Praza } 16931f6eb021SLiane Praza if (prop != NULL) { 16941f6eb021SLiane Praza ed[ED_PROP_NAME] = prop->sc_property_name; 16951f6eb021SLiane Praza } 16961f6eb021SLiane Praza if (pg_pattern == NULL) { 16971f6eb021SLiane Praza if (prop_pattern != NULL) { 16981f6eb021SLiane Praza ed[ED_TMPL_FMRI] = prop_pattern->sc_parent->sc_fmri; 16991f6eb021SLiane Praza } 17001f6eb021SLiane Praza } else { 17011f6eb021SLiane Praza ed[ED_TMPL_FMRI] = pg_pattern->sc_parent->sc_fmri; 17021f6eb021SLiane Praza ed[ED_TMPL_PG_NAME] = find_name_specification(pg_pattern); 17031f6eb021SLiane Praza ed[ED_TMPL_PG_TYPE] = find_type_specification(pg_pattern); 17041f6eb021SLiane Praza } 17051f6eb021SLiane Praza if (prop_pattern != NULL) { 17061f6eb021SLiane Praza ed[ED_TMPL_PROP_NAME] = find_name_specification(prop_pattern); 17071f6eb021SLiane Praza ed[ED_TMPL_PROP_TYPE] = find_type_specification(prop_pattern); 17081f6eb021SLiane Praza } 17091f6eb021SLiane Praza 17101f6eb021SLiane Praza /* 17111f6eb021SLiane Praza * All of the strings that we've found must be strduped. This is 17121f6eb021SLiane Praza * so that scf_tmpl_errors_destroy() can free them. We cannot use 17131f6eb021SLiane Praza * the flag argument of _scf_create_errors() to indicate that the 17141f6eb021SLiane Praza * strings should not be freed. The flag argument is an all or 17151f6eb021SLiane Praza * nothing thing. In the code below we need to convert integers to 17161f6eb021SLiane Praza * strings, and this requires memory allocation. Since we have to 17171f6eb021SLiane Praza * allocate memory for that data, we need to allocate it for every 17181f6eb021SLiane Praza * thing. 17191f6eb021SLiane Praza */ 17201f6eb021SLiane Praza for (i = 0; i < ED_COUNT; i++) { 17211f6eb021SLiane Praza if (ed[i] == NULL) 17221f6eb021SLiane Praza continue; 17231f6eb021SLiane Praza ed[i] = safe_strdup(ed[i]); 17241f6eb021SLiane Praza } 17251f6eb021SLiane Praza 17261f6eb021SLiane Praza /* actual, ev1 and ev2 are error code specific. */ 17271f6eb021SLiane Praza switch (ec) { 17281f6eb021SLiane Praza case SCF_TERR_CARDINALITY_VIOLATION: 17291f6eb021SLiane Praza assert(einfo != NULL); 17301f6eb021SLiane Praza assert(einfo->ei_type == EIT_CARDINALITY); 17311f6eb021SLiane Praza ev1 = uint64_to_str(einfo->ei_u.ei_cardinality.ei_min); 17321f6eb021SLiane Praza ev2 = uint64_to_str(einfo->ei_u.ei_cardinality.ei_max); 17331f6eb021SLiane Praza actual = uint64_to_str(einfo->ei_u.ei_cardinality.ei_count); 17341f6eb021SLiane Praza break; 17351f6eb021SLiane Praza case SCF_TERR_WRONG_PG_TYPE: 17361f6eb021SLiane Praza /* Specified type. */ 17371f6eb021SLiane Praza if (pg_pattern != NULL) { 17381f6eb021SLiane Praza ev1 = find_type_specification(pg_pattern); 17391f6eb021SLiane Praza if (ev1 != NULL) { 17401f6eb021SLiane Praza ev1 = safe_strdup(ev1); 17411f6eb021SLiane Praza } 17421f6eb021SLiane Praza } 17431f6eb021SLiane Praza /* Actual type. */ 17441f6eb021SLiane Praza if (pg != NULL) { 17451f6eb021SLiane Praza actual = pg->sc_pgroup_type; 17461f6eb021SLiane Praza if (actual != NULL) { 17471f6eb021SLiane Praza actual = safe_strdup(actual); 17481f6eb021SLiane Praza } 17491f6eb021SLiane Praza } 17501f6eb021SLiane Praza break; 17511f6eb021SLiane Praza case SCF_TERR_WRONG_PROP_TYPE: 17521f6eb021SLiane Praza assert(einfo->ei_type == EIT_PROP_TYPE); 17531f6eb021SLiane Praza prop_type = einfo->ei_u.ei_prop_type.ei_specified; 17541f6eb021SLiane Praza ev1 = safe_strdup(scf_type_to_string(prop_type)); 17551f6eb021SLiane Praza prop_type = einfo->ei_u.ei_prop_type.ei_actual; 17561f6eb021SLiane Praza actual = safe_strdup(scf_type_to_string(prop_type)); 17571f6eb021SLiane Praza break; 17581f6eb021SLiane Praza case SCF_TERR_VALUE_CONSTRAINT_VIOLATED: 17591f6eb021SLiane Praza actual = value_to_string(val); 17601f6eb021SLiane Praza break; 17611f6eb021SLiane Praza case SCF_TERR_MISSING_PG: 17621f6eb021SLiane Praza assert(einfo->ei_type == EIT_MISSING_PG); 17631f6eb021SLiane Praza ev1 = safe_strdup(einfo->ei_u.ei_missing_pg.ei_pg_name); 17641f6eb021SLiane Praza ev2 = safe_strdup(einfo->ei_u.ei_missing_pg.ei_pg_type); 17651f6eb021SLiane Praza break; 17661f6eb021SLiane Praza case SCF_TERR_MISSING_PROP: 17671f6eb021SLiane Praza assert(einfo->ei_type == EIT_MISSING_PROP); 17681f6eb021SLiane Praza ev1 = safe_strdup(einfo->ei_u.ei_missing_prop.ei_prop_name); 17691f6eb021SLiane Praza break; 17701f6eb021SLiane Praza case SCF_TERR_RANGE_VIOLATION: 17711f6eb021SLiane Praza assert(einfo->ei_type == EIT_RANGE); 17721f6eb021SLiane Praza if (einfo->ei_u.ei_range.ei_rtype == SCF_TYPE_COUNT) { 17731f6eb021SLiane Praza c = uint64_to_str(einfo->ei_u.ei_range.ei_uvalue); 17741f6eb021SLiane Praza } else { 17751f6eb021SLiane Praza c = int64_to_str(einfo->ei_u.ei_range.ei_ivalue); 17761f6eb021SLiane Praza } 17771f6eb021SLiane Praza actual = c; 17781f6eb021SLiane Praza break; 17791f6eb021SLiane Praza case SCF_TERR_PG_PATTERN_CONFLICT: 17801f6eb021SLiane Praza case SCF_TERR_PROP_PATTERN_CONFLICT: 17811f6eb021SLiane Praza case SCF_TERR_GENERAL_REDEFINE: 17821f6eb021SLiane Praza assert(einfo->ei_type == EIT_PATTERN_CONFLICT); 17831f6eb021SLiane Praza conflict = einfo->ei_u.ei_pattern_conflict.ei_pattern; 17841f6eb021SLiane Praza ev1 = safe_strdup(conflict->sc_parent->sc_fmri); 17851f6eb021SLiane Praza ev2 = find_name_specification(conflict); 17861f6eb021SLiane Praza if (ev2 != NULL) 17871f6eb021SLiane Praza ev2 = safe_strdup(ev2); 17881f6eb021SLiane Praza actual = find_type_specification(conflict); 17891f6eb021SLiane Praza if (actual != NULL) 17901f6eb021SLiane Praza actual = safe_strdup(actual); 17911f6eb021SLiane Praza break; 17921f6eb021SLiane Praza case SCF_TERR_INCLUDE_VALUES: 17931f6eb021SLiane Praza assert(einfo->ei_type == EIT_INCLUDE_VALUES); 17941f6eb021SLiane Praza ev1 = safe_strdup(einfo->ei_u.ei_inc_values.ei_type); 17951f6eb021SLiane Praza break; 17961f6eb021SLiane Praza case SCF_TERR_PG_PATTERN_INCOMPLETE: 17971f6eb021SLiane Praza case SCF_TERR_PROP_PATTERN_INCOMPLETE: 17981f6eb021SLiane Praza break; 17991f6eb021SLiane Praza default: 18001f6eb021SLiane Praza assert(0); 18011f6eb021SLiane Praza abort(); 18021f6eb021SLiane Praza }; 18031f6eb021SLiane Praza 18041f6eb021SLiane Praza rc = _scf_tmpl_add_error(errs->te_cur_scf->tve_errors, ec, 18051f6eb021SLiane Praza ed[ED_PG_NAME], ed[ED_PROP_NAME], ev1, ev2, actual, 18061f6eb021SLiane Praza ed[ED_TMPL_FMRI], ed[ED_TMPL_PG_NAME], ed[ED_TMPL_PG_TYPE], 18071f6eb021SLiane Praza ed[ED_TMPL_PROP_NAME], ed[ED_TMPL_PROP_TYPE]); 18081f6eb021SLiane Praza 18091f6eb021SLiane Praza return (rc); 18101f6eb021SLiane Praza } 18111f6eb021SLiane Praza 18121f6eb021SLiane Praza /* 18131f6eb021SLiane Praza * Create and initialize a new im_tmpl_error structure and add it to the 18141f6eb021SLiane Praza * list of errors in errs. The rest of the parameters are used to 18151f6eb021SLiane Praza * initialize the im_tmpl_error structure. 18161f6eb021SLiane Praza */ 18171f6eb021SLiane Praza static tmpl_validate_status_t 18181f6eb021SLiane Praza tmpl_errors_add_im(tmpl_errors_t *errs, tmpl_validate_status_t ec, entity_t *e, 18191f6eb021SLiane Praza pgroup_t *pg_pattern, pgroup_t *pg, pgroup_t *prop_pattern, 18201f6eb021SLiane Praza property_t *prop, value_t *val, error_info_t *einfo) 18211f6eb021SLiane Praza { 18221f6eb021SLiane Praza im_tmpl_error_t *ite; 18231f6eb021SLiane Praza int result; 18241f6eb021SLiane Praza 18251f6eb021SLiane Praza ite = uu_zalloc(sizeof (*ite)); 18261f6eb021SLiane Praza if (ite == NULL) 18271f6eb021SLiane Praza uu_die(emesg_nomem); 18281f6eb021SLiane Praza uu_list_node_init(ite, &ite->ite_node, inmem_errors_pool); 18291f6eb021SLiane Praza ite->ite_type = ec; 18301f6eb021SLiane Praza ite->ite_entity = e; 18311f6eb021SLiane Praza ite->ite_pg = pg; 18321f6eb021SLiane Praza ite->ite_pg_pattern = pg_pattern; 18331f6eb021SLiane Praza ite->ite_prop = prop; 18341f6eb021SLiane Praza ite->ite_prop_pattern = prop_pattern; 18351f6eb021SLiane Praza ite->ite_value = val; 18361f6eb021SLiane Praza if (einfo != NULL) 18371f6eb021SLiane Praza ite->ite_einfo = *einfo; 18381f6eb021SLiane Praza 18391f6eb021SLiane Praza result = uu_list_insert_after(errs->te_list, NULL, ite); 18401f6eb021SLiane Praza assert(result == 0); 18411f6eb021SLiane Praza return (TVS_SUCCESS); 18421f6eb021SLiane Praza } 18431f6eb021SLiane Praza 18441f6eb021SLiane Praza /* 18451f6eb021SLiane Praza * pattern must point to a pg_pattern or a prop_pattern. This function 18461f6eb021SLiane Praza * finds the property named required and returns the property's value. If 18471f6eb021SLiane Praza * the property does not exist, false is return since it is the default. 18481f6eb021SLiane Praza */ 18491f6eb021SLiane Praza static int 18501f6eb021SLiane Praza is_required(pgroup_t *pattern) 18511f6eb021SLiane Praza { 18521f6eb021SLiane Praza property_t *required; 18531f6eb021SLiane Praza value_t *value; 18541f6eb021SLiane Praza 18551f6eb021SLiane Praza assert((strcmp(pattern->sc_pgroup_type, 18561f6eb021SLiane Praza SCF_GROUP_TEMPLATE_PG_PATTERN) == 0) || 18571f6eb021SLiane Praza (strcmp(pattern->sc_pgroup_type, 18581f6eb021SLiane Praza SCF_GROUP_TEMPLATE_PROP_PATTERN) == 0)); 18591f6eb021SLiane Praza 18601f6eb021SLiane Praza required = property_find(pattern, SCF_PROPERTY_TM_REQUIRED); 18611f6eb021SLiane Praza 18621f6eb021SLiane Praza /* Default if there is no required property is false. */ 18631f6eb021SLiane Praza if (required == NULL) 18641f6eb021SLiane Praza return (0); 18651f6eb021SLiane Praza 18661f6eb021SLiane Praza /* Retrieve the value of the required property. */ 18671f6eb021SLiane Praza value = uu_list_first(required->sc_property_values); 18681f6eb021SLiane Praza if (value == NULL) 18691f6eb021SLiane Praza return (0); 18701f6eb021SLiane Praza if (value->sc_type == SCF_TYPE_BOOLEAN) 18711f6eb021SLiane Praza return (value->sc_u.sc_count == 0 ? 0 : 1); 18721f6eb021SLiane Praza 18731f6eb021SLiane Praza /* No boolean property values, so return false. */ 18741f6eb021SLiane Praza return (0); 18751f6eb021SLiane Praza } 18761f6eb021SLiane Praza 18771f6eb021SLiane Praza /* 18781f6eb021SLiane Praza * Load the service's restarter instance and the global instance from the 18791f6eb021SLiane Praza * repository. This will allow us to use their templates in validating the 18801f6eb021SLiane Praza * service. 18811f6eb021SLiane Praza * 18821f6eb021SLiane Praza * There is no function to unload the general templates. The memory that 18831f6eb021SLiane Praza * is allocated by load_general_templates() will be freed automatically in 18841f6eb021SLiane Praza * internal_service_free() which is called by internal_bundle_free(). 18851f6eb021SLiane Praza */ 18861f6eb021SLiane Praza static void 18871f6eb021SLiane Praza load_general_templates(entity_t *svc) 18881f6eb021SLiane Praza { 18891f6eb021SLiane Praza const char *restarter; 18901f6eb021SLiane Praza int is_global = 0; 18911f6eb021SLiane Praza int r; 18921f6eb021SLiane Praza 18931f6eb021SLiane Praza assert(svc->sc_etype == SVCCFG_SERVICE_OBJECT); 18941f6eb021SLiane Praza 18951f6eb021SLiane Praza /* 18961f6eb021SLiane Praza * If e is the global service, we only need to load the restarter. 18971f6eb021SLiane Praza */ 18981f6eb021SLiane Praza if ((strcmp(svc->sc_fmri, SCF_INSTANCE_GLOBAL) == 0) || 18991f6eb021SLiane Praza (strcmp(svc->sc_fmri, SCF_SERVICE_GLOBAL) == 0)) { 19001f6eb021SLiane Praza is_global = 1; 19011f6eb021SLiane Praza } 19021f6eb021SLiane Praza 19031f6eb021SLiane Praza /* 19041f6eb021SLiane Praza * Load the templates for the service's restarter. 19051f6eb021SLiane Praza */ 19061f6eb021SLiane Praza restarter = find_restarter(svc); 19071f6eb021SLiane Praza if (restarter == NULL) 19081f6eb021SLiane Praza restarter = SCF_SERVICE_STARTD; 19091f6eb021SLiane Praza if ((r = load_instance(restarter, "restarter", 19101f6eb021SLiane Praza &svc->sc_u.sc_service.sc_restarter)) != 0) { 19111f6eb021SLiane Praza /* 19121f6eb021SLiane Praza * During initial manifest import, restarter may 19131f6eb021SLiane Praza * not be in the repository yet. In this case we 19141f6eb021SLiane Praza * continue on without it. 19151f6eb021SLiane Praza */ 1916*870ad75aSSean Wilcox if (r == EINVAL) 1917*870ad75aSSean Wilcox warn(gettext("WARNING: restarter FMRI %s is invalid\n"), 1918*870ad75aSSean Wilcox restarter); 1919*870ad75aSSean Wilcox 1920*870ad75aSSean Wilcox if (r == ENOTSUP) 1921*870ad75aSSean Wilcox warn(gettext("WARNING: restarter FMRI %s is not valid; " 1922*870ad75aSSean Wilcox "instance fmri required.\n"), restarter); 1923*870ad75aSSean Wilcox 19241f6eb021SLiane Praza if (r == ENOMEM) 19251f6eb021SLiane Praza uu_die(emesg_nomem); 1926*870ad75aSSean Wilcox 19271f6eb021SLiane Praza svc->sc_u.sc_service.sc_restarter = NULL; 19281f6eb021SLiane Praza } 19291f6eb021SLiane Praza if (is_global == 0) { 19301f6eb021SLiane Praza if ((r = load_instance(SCF_INSTANCE_GLOBAL, "global", 19311f6eb021SLiane Praza &svc->sc_u.sc_service.sc_global)) != 0) { 19321f6eb021SLiane Praza /* 19331f6eb021SLiane Praza * During initial manifest import, global may not be in 19341f6eb021SLiane Praza * the repository yet. 19351f6eb021SLiane Praza */ 19361f6eb021SLiane Praza if (r == ENOMEM) 19371f6eb021SLiane Praza uu_die(emesg_nomem); 19381f6eb021SLiane Praza else 19391f6eb021SLiane Praza svc->sc_u.sc_service.sc_global = NULL; 19401f6eb021SLiane Praza } 19411f6eb021SLiane Praza } 19421f6eb021SLiane Praza } 19431f6eb021SLiane Praza 19441f6eb021SLiane Praza /* 19451f6eb021SLiane Praza * Load the instance specific restarter if one is declared. 19461f6eb021SLiane Praza * 19471f6eb021SLiane Praza * There is no corresponding unload_instance_restarter() function because 19481f6eb021SLiane Praza * it is not needed. The memory will be freed in internal_instance_free() 19491f6eb021SLiane Praza * when internal_bundle_free() is called. 19501f6eb021SLiane Praza */ 19511f6eb021SLiane Praza static void 19521f6eb021SLiane Praza load_instance_restarter(entity_t *i) 19531f6eb021SLiane Praza { 19541f6eb021SLiane Praza const char *restarter; 19551f6eb021SLiane Praza int r; 19561f6eb021SLiane Praza 19571f6eb021SLiane Praza assert(i->sc_etype == SVCCFG_INSTANCE_OBJECT); 19581f6eb021SLiane Praza 19591f6eb021SLiane Praza restarter = find_restarter(i); 19601f6eb021SLiane Praza if (restarter == NULL) { 19611f6eb021SLiane Praza /* No instance specific restarter */ 19621f6eb021SLiane Praza return; 19631f6eb021SLiane Praza } 19641f6eb021SLiane Praza r = load_instance(restarter, "instance_restarter", 19651f6eb021SLiane Praza &i->sc_u.sc_instance.sc_instance_restarter); 19661f6eb021SLiane Praza if (r != 0) { 19671f6eb021SLiane Praza /* 19681f6eb021SLiane Praza * During initial manifest import, the restarter may not be 19691f6eb021SLiane Praza * in the repository yet. In this case we continue on 19701f6eb021SLiane Praza * without it. 19711f6eb021SLiane Praza */ 1972*870ad75aSSean Wilcox if (r == EINVAL) 1973*870ad75aSSean Wilcox warn(gettext("WARNING: restarter FMRI %s is invalid\n"), 1974*870ad75aSSean Wilcox restarter); 1975*870ad75aSSean Wilcox 1976*870ad75aSSean Wilcox if (r == ENOTSUP) 1977*870ad75aSSean Wilcox warn(gettext("WARNING: restarter FMRI %s is not valid; " 1978*870ad75aSSean Wilcox "instance fmri required.\n"), restarter); 1979*870ad75aSSean Wilcox 19801f6eb021SLiane Praza if (r == ENOMEM) 19811f6eb021SLiane Praza uu_die(emesg_nomem); 19821f6eb021SLiane Praza } 19831f6eb021SLiane Praza } 19841f6eb021SLiane Praza 19851f6eb021SLiane Praza /* 19861f6eb021SLiane Praza * Find the next property after current in the property group at pg. If 19871f6eb021SLiane Praza * the property group contains a tree of composed properties, that tree is 19881f6eb021SLiane Praza * walked. Otherwise, we walk through the uu_list at sc_pgroup_props. 19891f6eb021SLiane Praza */ 19901f6eb021SLiane Praza static property_t * 19911f6eb021SLiane Praza next_property(pgroup_t *pg, property_t *current) 19921f6eb021SLiane Praza { 19931f6eb021SLiane Praza composed_pg_t *cpg; 19941f6eb021SLiane Praza property_t *prop; 19951f6eb021SLiane Praza 19961f6eb021SLiane Praza cpg = pg->sc_pgroup_composed; 19971f6eb021SLiane Praza if ((cpg != NULL) && (cpg->cpg_composed_props != NULL)) { 19981f6eb021SLiane Praza /* Walk through composed property list. */ 19991f6eb021SLiane Praza if (current) { 20001f6eb021SLiane Praza prop = uu_avl_next(cpg->cpg_composed_props, current); 20011f6eb021SLiane Praza } else { 20021f6eb021SLiane Praza prop = uu_avl_first(cpg->cpg_composed_props); 20031f6eb021SLiane Praza } 20041f6eb021SLiane Praza } else { 20051f6eb021SLiane Praza /* No composition available, so walk the list of properties */ 20061f6eb021SLiane Praza if (current) { 20071f6eb021SLiane Praza prop = uu_list_next(pg->sc_pgroup_props, current); 20081f6eb021SLiane Praza } else { 20091f6eb021SLiane Praza prop = uu_list_first(pg->sc_pgroup_props); 20101f6eb021SLiane Praza } 20111f6eb021SLiane Praza } 20121f6eb021SLiane Praza 20131f6eb021SLiane Praza return (prop); 20141f6eb021SLiane Praza } 20151f6eb021SLiane Praza 20161f6eb021SLiane Praza static ptrn_info_t * 20171f6eb021SLiane Praza ptrn_info_create(pgroup_t *pat) 20181f6eb021SLiane Praza { 20191f6eb021SLiane Praza entity_t *e; 20201f6eb021SLiane Praza ptrn_info_t *info; 20211f6eb021SLiane Praza composed_pg_t *match; 20221f6eb021SLiane Praza composed_pg_t cpg; 20231f6eb021SLiane Praza 20241f6eb021SLiane Praza info = safe_malloc(sizeof (*info)); 20251f6eb021SLiane Praza 20261f6eb021SLiane Praza switch (pgroup_type(pat)) { 20271f6eb021SLiane Praza case PG_PATTERN_PG: 20281f6eb021SLiane Praza info->pi_ptrn_type = PG_PATTERN; 20291f6eb021SLiane Praza break; 20301f6eb021SLiane Praza case PROP_PATTERN_PG: 20311f6eb021SLiane Praza info->pi_ptrn_type = PROP_PATTERN; 20321f6eb021SLiane Praza break; 20331f6eb021SLiane Praza default: 20341f6eb021SLiane Praza assert(0); 20351f6eb021SLiane Praza abort(); 20361f6eb021SLiane Praza } 20371f6eb021SLiane Praza info->pi_ptrnpg = pat; 20381f6eb021SLiane Praza info->pi_name = find_name_specification(pat); 20391f6eb021SLiane Praza info->pi_name = EMPTY_TO_NULL(info->pi_name); 20401f6eb021SLiane Praza info->pi_type = find_type_specification(pat); 20411f6eb021SLiane Praza info->pi_type = EMPTY_TO_NULL(info->pi_type); 20421f6eb021SLiane Praza if (info->pi_ptrn_type == PG_PATTERN) { 20431f6eb021SLiane Praza info->pi_target = find_astring_value_in_pg(pat, 20441f6eb021SLiane Praza SCF_PROPERTY_TM_TARGET); 20451f6eb021SLiane Praza if (info->pi_target == NULL) 20461f6eb021SLiane Praza info->pi_target = SCF_TM_TARGET_THIS; 20471f6eb021SLiane Praza } 20481f6eb021SLiane Praza if (info->pi_ptrn_type == PROP_PATTERN) { 20491f6eb021SLiane Praza info->pi_pgp_name = find_astring_value_in_pg(pat, 20501f6eb021SLiane Praza SCF_PROPERTY_TM_PG_PATTERN); 20511f6eb021SLiane Praza assert((info->pi_pgp_name != NULL) && 20521f6eb021SLiane Praza (*(info->pi_pgp_name) != 0)); 20531f6eb021SLiane Praza 20541f6eb021SLiane Praza /* 20551f6eb021SLiane Praza * Find the property group that defines the pg_pattern that 20561f6eb021SLiane Praza * holds this prop_pattern. 20571f6eb021SLiane Praza */ 20581f6eb021SLiane Praza e = pat->sc_parent; 20591f6eb021SLiane Praza if (e->sc_etype == SVCCFG_INSTANCE_OBJECT) { 20601f6eb021SLiane Praza (void) memset(&cpg, 0, sizeof (cpg)); 20611f6eb021SLiane Praza cpg.cpg_name = info->pi_pgp_name; 20621f6eb021SLiane Praza cpg.cpg_type = SCF_GROUP_TEMPLATE_PG_PATTERN; 20631f6eb021SLiane Praza match = uu_avl_find(e->sc_u.sc_instance.sc_composed, 20641f6eb021SLiane Praza &cpg, NULL, NULL); 20651f6eb021SLiane Praza assert(match != NULL); 20661f6eb021SLiane Praza info->pi_enc_pgp = CPG2PG(match); 20671f6eb021SLiane Praza } else { 20681f6eb021SLiane Praza info->pi_enc_pgp = internal_pgroup_find(e, 20691f6eb021SLiane Praza info->pi_pgp_name, SCF_GROUP_TEMPLATE_PG_PATTERN); 20701f6eb021SLiane Praza } 20711f6eb021SLiane Praza assert(info->pi_enc_pgp != NULL); 20721f6eb021SLiane Praza } 20731f6eb021SLiane Praza uu_avl_node_init(info, &info->pi_link, ptrn_info_pool); 20741f6eb021SLiane Praza return (info); 20751f6eb021SLiane Praza } 20761f6eb021SLiane Praza 20771f6eb021SLiane Praza static void 20781f6eb021SLiane Praza ptrn_info_destroy(ptrn_info_t *info) 20791f6eb021SLiane Praza { 20801f6eb021SLiane Praza if (info == NULL) 20811f6eb021SLiane Praza return; 20821f6eb021SLiane Praza uu_avl_node_fini(info, &info->pi_link, ptrn_info_pool); 20831f6eb021SLiane Praza free(info); 20841f6eb021SLiane Praza } 20851f6eb021SLiane Praza 20861f6eb021SLiane Praza /* 20871f6eb021SLiane Praza * Walk through the property groups of the instance or service at e looking 20881f6eb021SLiane Praza * for definitions of pg_patterns or prop_patterns as specified by type. 20891f6eb021SLiane Praza * For each property group that matches type create a ptrn_info_t and add 20901f6eb021SLiane Praza * it to the avl tree at tree. If duplicates are found add an error entry 20911f6eb021SLiane Praza * to errs. 20921f6eb021SLiane Praza */ 20931f6eb021SLiane Praza static tmpl_validate_status_t 20941f6eb021SLiane Praza gather_pattern(entity_t *e, ptrn_type_t type, uu_avl_t *tree, 20951f6eb021SLiane Praza tmpl_errors_t *errs) 20961f6eb021SLiane Praza { 20971f6eb021SLiane Praza error_info_t einfo; 20981f6eb021SLiane Praza ptrn_info_t *info = NULL; 20991f6eb021SLiane Praza uu_avl_index_t marker; 21001f6eb021SLiane Praza ptrn_info_t *match; 21011f6eb021SLiane Praza pgroup_t *pg; 21021f6eb021SLiane Praza tmpl_validate_status_t rc = TVS_SUCCESS; 21031f6eb021SLiane Praza const char *selector; 21041f6eb021SLiane Praza 21051f6eb021SLiane Praza switch (type) { 21061f6eb021SLiane Praza case PG_PATTERN: 21071f6eb021SLiane Praza selector = SCF_GROUP_TEMPLATE_PG_PATTERN; 21081f6eb021SLiane Praza break; 21091f6eb021SLiane Praza case PROP_PATTERN: 21101f6eb021SLiane Praza selector = SCF_GROUP_TEMPLATE_PROP_PATTERN; 21111f6eb021SLiane Praza break; 21121f6eb021SLiane Praza default: 21131f6eb021SLiane Praza assert(0); 21141f6eb021SLiane Praza abort(); 21151f6eb021SLiane Praza } 21161f6eb021SLiane Praza 21171f6eb021SLiane Praza for (pg = uu_list_first(e->sc_pgroups); 21181f6eb021SLiane Praza pg != NULL; 21191f6eb021SLiane Praza pg = uu_list_next(e->sc_pgroups, pg)) { 21201f6eb021SLiane Praza if (strcmp(pg->sc_pgroup_type, selector) != 0) { 21211f6eb021SLiane Praza continue; 21221f6eb021SLiane Praza } 21231f6eb021SLiane Praza if (info != NULL) { 21241f6eb021SLiane Praza /* Get rid of old structure. */ 21251f6eb021SLiane Praza ptrn_info_destroy(info); 21261f6eb021SLiane Praza } 21271f6eb021SLiane Praza info = ptrn_info_create(pg); 21281f6eb021SLiane Praza match = uu_avl_find(tree, info, NULL, &marker); 21291f6eb021SLiane Praza if (match == NULL) { 21301f6eb021SLiane Praza /* No match. Insert the info. */ 21311f6eb021SLiane Praza uu_avl_insert(tree, info, marker); 21321f6eb021SLiane Praza info = NULL; 21331f6eb021SLiane Praza continue; 21341f6eb021SLiane Praza } 21351f6eb021SLiane Praza 21361f6eb021SLiane Praza /* Got a match. Determine if it is a conflict. */ 21371f6eb021SLiane Praza if ((info->pi_name == NULL) || 21381f6eb021SLiane Praza (info->pi_type == NULL) || 21391f6eb021SLiane Praza (match->pi_name == NULL) || 21401f6eb021SLiane Praza (match->pi_type == NULL)) { 21411f6eb021SLiane Praza /* No conflicts if any wild cards. */ 21421f6eb021SLiane Praza continue; 21431f6eb021SLiane Praza } 21441f6eb021SLiane Praza 21451f6eb021SLiane Praza /* 21461f6eb021SLiane Praza * Name already matches, or we wouldn't have gotten 21471f6eb021SLiane Praza * here. Make sure that the type also matches. 21481f6eb021SLiane Praza */ 21491f6eb021SLiane Praza if (strcmp(info->pi_type, match->pi_type) == 0) { 21501f6eb021SLiane Praza continue; 21511f6eb021SLiane Praza } 21521f6eb021SLiane Praza 21531f6eb021SLiane Praza /* 21541f6eb021SLiane Praza * If we get to this point we have a conflict, and 21551f6eb021SLiane Praza * we need to generate the correct type of error. 21561f6eb021SLiane Praza */ 21571f6eb021SLiane Praza CLEAR_ERROR_INFO(&einfo); 21581f6eb021SLiane Praza einfo.ei_type = EIT_PATTERN_CONFLICT; 21591f6eb021SLiane Praza einfo.ei_u.ei_pattern_conflict.ei_pattern = 21601f6eb021SLiane Praza match->pi_ptrnpg; 21611f6eb021SLiane Praza if (type == PG_PATTERN) { 21621f6eb021SLiane Praza rc = TVS_VALIDATION; 21631f6eb021SLiane Praza if (add_scf_error(errs, SCF_TERR_PG_PATTERN_CONFLICT, 21641f6eb021SLiane Praza info->pi_ptrnpg, NULL, NULL, NULL, NULL, 21651f6eb021SLiane Praza &einfo) != 0) { 21661f6eb021SLiane Praza /* 21671f6eb021SLiane Praza * If we can no longer accumulate 21681f6eb021SLiane Praza * errors, break out of the loop. 21691f6eb021SLiane Praza */ 21701f6eb021SLiane Praza break; 21711f6eb021SLiane Praza } 21721f6eb021SLiane Praza } else { 21731f6eb021SLiane Praza /* 21741f6eb021SLiane Praza * Possible conflicting prop_pattern. See if the 21751f6eb021SLiane Praza * prop_patterns are declared in the same 21761f6eb021SLiane Praza * pg_pattern. 21771f6eb021SLiane Praza */ 21781f6eb021SLiane Praza if ((info->pi_pgp_name == NULL) || 21791f6eb021SLiane Praza (match->pi_pgp_name == NULL)) { 21801f6eb021SLiane Praza continue; 21811f6eb021SLiane Praza } 21821f6eb021SLiane Praza if (strcmp(info->pi_pgp_name, match->pi_pgp_name) != 0) 21831f6eb021SLiane Praza continue; 21841f6eb021SLiane Praza 21851f6eb021SLiane Praza /* It is a real conflict. */ 21861f6eb021SLiane Praza rc = TVS_VALIDATION; 21871f6eb021SLiane Praza if (add_scf_error(errs, SCF_TERR_PROP_PATTERN_CONFLICT, 21881f6eb021SLiane Praza info->pi_enc_pgp, NULL, info->pi_ptrnpg, NULL, NULL, 21891f6eb021SLiane Praza &einfo) != 0) { 21901f6eb021SLiane Praza /* 21911f6eb021SLiane Praza * If we can no longer accumulate 21921f6eb021SLiane Praza * errors, break out of the loop. 21931f6eb021SLiane Praza */ 21941f6eb021SLiane Praza break; 21951f6eb021SLiane Praza } 21961f6eb021SLiane Praza } 21971f6eb021SLiane Praza } 21981f6eb021SLiane Praza 21991f6eb021SLiane Praza ptrn_info_destroy(info); 22001f6eb021SLiane Praza return (rc); 22011f6eb021SLiane Praza } 22021f6eb021SLiane Praza 22031f6eb021SLiane Praza /* 22041f6eb021SLiane Praza * Free the pg_iter structure. 22051f6eb021SLiane Praza */ 22061f6eb021SLiane Praza static void 22071f6eb021SLiane Praza pg_iter_destroy(pg_iter_t *i) 22081f6eb021SLiane Praza { 22091f6eb021SLiane Praza if (i == NULL) 22101f6eb021SLiane Praza return; 22111f6eb021SLiane Praza 22121f6eb021SLiane Praza uu_free(i); 22131f6eb021SLiane Praza } 22141f6eb021SLiane Praza 22151f6eb021SLiane Praza /* 22161f6eb021SLiane Praza * Create a property group iterator for the instance at e. This iterator 22171f6eb021SLiane Praza * will walk through the composed property groups of the instance. It will 22181f6eb021SLiane Praza * then step through the property groups of the instance's restarter and 22191f6eb021SLiane Praza * finally the global service. If you wish to iterate over a specific type 22201f6eb021SLiane Praza * of property group, set restriction to point the the desired type. 22211f6eb021SLiane Praza * Otherwise set restriction to NULL. 22221f6eb021SLiane Praza * 22231f6eb021SLiane Praza * The returned interator must be freed by calling pg_iter_destroy(). NULL 22241f6eb021SLiane Praza * is returned if we are unable to allocate the necessary memory. 22251f6eb021SLiane Praza */ 22261f6eb021SLiane Praza static pg_iter_t * 22271f6eb021SLiane Praza pg_iter_create(entity_t *e, const char *restriction) 22281f6eb021SLiane Praza { 22291f6eb021SLiane Praza pg_iter_t *i; 22301f6eb021SLiane Praza 22311f6eb021SLiane Praza assert(e->sc_etype == SVCCFG_INSTANCE_OBJECT); 22321f6eb021SLiane Praza 22331f6eb021SLiane Praza i = uu_zalloc(sizeof (*i)); 22341f6eb021SLiane Praza if (i == NULL) 22351f6eb021SLiane Praza return (NULL); 22361f6eb021SLiane Praza 22371f6eb021SLiane Praza i->pgi_entity = e; 22381f6eb021SLiane Praza i->pgi_restrict = restriction; 22391f6eb021SLiane Praza i->pgi_level = TL_COMPOSED; 22401f6eb021SLiane Praza i->pgi_service = e->sc_parent; 22411f6eb021SLiane Praza 22421f6eb021SLiane Praza return (i); 22431f6eb021SLiane Praza } 22441f6eb021SLiane Praza 22451f6eb021SLiane Praza /* 22461f6eb021SLiane Praza * Return the next property group in the iteration. NULL is returned if we 22471f6eb021SLiane Praza * reach the end of the list. The iterator will automatically proceed from 22481f6eb021SLiane Praza * most specific to most general levels. 22491f6eb021SLiane Praza */ 22501f6eb021SLiane Praza static pgroup_t * 22511f6eb021SLiane Praza next_pattern_pg(pg_iter_t *i) 22521f6eb021SLiane Praza { 22531f6eb021SLiane Praza composed_pg_t *cpg; 22541f6eb021SLiane Praza entity_t *e; 22551f6eb021SLiane Praza pgroup_t *pg; 22561f6eb021SLiane Praza uu_avl_t *composed_tree; 22571f6eb021SLiane Praza 22581f6eb021SLiane Praza assert(i->pgi_level != TL_NOLEVEL); 22591f6eb021SLiane Praza 22601f6eb021SLiane Praza while (i->pgi_entity != NULL) { 22611f6eb021SLiane Praza if (i->pgi_level == TL_COMPOSED) { 22621f6eb021SLiane Praza composed_tree = 22631f6eb021SLiane Praza i->pgi_entity->sc_u.sc_instance.sc_composed; 22641f6eb021SLiane Praza cpg = i->pgi_current.pgi_cpg; 22651f6eb021SLiane Praza if (cpg == NULL) { 22661f6eb021SLiane Praza cpg = uu_avl_first(composed_tree); 22671f6eb021SLiane Praza } else { 22681f6eb021SLiane Praza cpg = uu_avl_next(composed_tree, cpg); 22691f6eb021SLiane Praza } 22701f6eb021SLiane Praza if (cpg == NULL) { 22711f6eb021SLiane Praza pg = NULL; 22721f6eb021SLiane Praza } else { 22731f6eb021SLiane Praza pg = CPG2PG(cpg); 22741f6eb021SLiane Praza i->pgi_current.pgi_cpg = cpg; 22751f6eb021SLiane Praza } 22761f6eb021SLiane Praza } else { 22771f6eb021SLiane Praza pg = i->pgi_current.pgi_pg; 22781f6eb021SLiane Praza if (pg == NULL) { 22791f6eb021SLiane Praza pg = uu_list_first(i->pgi_entity->sc_pgroups); 22801f6eb021SLiane Praza } else { 22811f6eb021SLiane Praza pg = uu_list_next(i->pgi_entity->sc_pgroups, 22821f6eb021SLiane Praza pg); 22831f6eb021SLiane Praza } 22841f6eb021SLiane Praza i->pgi_current.pgi_pg = pg; 22851f6eb021SLiane Praza } 22861f6eb021SLiane Praza 22871f6eb021SLiane Praza if (pg == NULL) { 22881f6eb021SLiane Praza /* 22891f6eb021SLiane Praza * End of the list. Reset current and break out of 22901f6eb021SLiane Praza * the loop. 22911f6eb021SLiane Praza */ 22921f6eb021SLiane Praza (void) memset(&i->pgi_current, 0, 22931f6eb021SLiane Praza sizeof (i->pgi_current)); 22941f6eb021SLiane Praza break; 22951f6eb021SLiane Praza } 22961f6eb021SLiane Praza 22971f6eb021SLiane Praza /* 22981f6eb021SLiane Praza * If this iteration is for a specific type, verify that 22991f6eb021SLiane Praza * this pg is of that type. 23001f6eb021SLiane Praza */ 23011f6eb021SLiane Praza if (i->pgi_restrict) { 23021f6eb021SLiane Praza if (strcmp(pg->sc_pgroup_type, i->pgi_restrict) != 0) { 23031f6eb021SLiane Praza continue; 23041f6eb021SLiane Praza } 23051f6eb021SLiane Praza } 23061f6eb021SLiane Praza 23071f6eb021SLiane Praza return (pg); 23081f6eb021SLiane Praza } 23091f6eb021SLiane Praza 23101f6eb021SLiane Praza /* 23111f6eb021SLiane Praza * End of the list in the current level. Move up to the next 23121f6eb021SLiane Praza * level. 23131f6eb021SLiane Praza */ 23141f6eb021SLiane Praza switch (i->pgi_level) { 23151f6eb021SLiane Praza case TL_COMPOSED: 23161f6eb021SLiane Praza /* Skip service if we've finished a composed instance. */ 23171f6eb021SLiane Praza e = i->pgi_entity; 23181f6eb021SLiane Praza if (e->sc_u.sc_instance.sc_instance_restarter == NULL) { 23191f6eb021SLiane Praza /* Use service restarter */ 23201f6eb021SLiane Praza i->pgi_entity = 23211f6eb021SLiane Praza i->pgi_service->sc_u.sc_service.sc_restarter; 23221f6eb021SLiane Praza } else { 23231f6eb021SLiane Praza /* Use instance restarter */ 23241f6eb021SLiane Praza i->pgi_entity = 23251f6eb021SLiane Praza e->sc_u.sc_instance.sc_instance_restarter; 23261f6eb021SLiane Praza } 23271f6eb021SLiane Praza i->pgi_level = TL_RESTARTER; 23281f6eb021SLiane Praza break; 23291f6eb021SLiane Praza case TL_RESTARTER: 23301f6eb021SLiane Praza i->pgi_entity = i->pgi_service->sc_u.sc_service.sc_global; 23311f6eb021SLiane Praza i->pgi_level = TL_GLOBAL; 23321f6eb021SLiane Praza break; 23331f6eb021SLiane Praza case TL_GLOBAL: 23341f6eb021SLiane Praza i->pgi_level = TL_NOLEVEL; 23351f6eb021SLiane Praza return (NULL); 23361f6eb021SLiane Praza default: 23371f6eb021SLiane Praza assert(0); 23381f6eb021SLiane Praza abort(); 23391f6eb021SLiane Praza } 23401f6eb021SLiane Praza 23411f6eb021SLiane Praza /* Go process the next level. */ 23421f6eb021SLiane Praza return (next_pattern_pg(i)); 23431f6eb021SLiane Praza } 23441f6eb021SLiane Praza 23451f6eb021SLiane Praza /* 23461f6eb021SLiane Praza * Compare two pattern info structures (ptrn_info_t). If both structures 23471f6eb021SLiane Praza * have names, the comparison is based on the name. If only one has a 23481f6eb021SLiane Praza * name, the structure with no name will be first. If neither structure 23491f6eb021SLiane Praza * has a name, the comparison is based on their types using similar wild 23501f6eb021SLiane Praza * card logic. 23511f6eb021SLiane Praza */ 23521f6eb021SLiane Praza /* ARGSUSED2 */ 23531f6eb021SLiane Praza static int 23541f6eb021SLiane Praza ptrn_info_compare(const void *left, const void *right, void *unused) 23551f6eb021SLiane Praza { 23561f6eb021SLiane Praza ptrn_info_t *l = (ptrn_info_t *)left; 23571f6eb021SLiane Praza ptrn_info_t *r = (ptrn_info_t *)right; 23581f6eb021SLiane Praza 23591f6eb021SLiane Praza if ((l->pi_name != NULL) && (r->pi_name != NULL)) 23601f6eb021SLiane Praza return (strcmp(l->pi_name, r->pi_name)); 23611f6eb021SLiane Praza if ((l->pi_name == NULL) && (r->pi_name == NULL)) { 23621f6eb021SLiane Praza /* No names, so we need to compare types. */ 23631f6eb021SLiane Praza if ((l->pi_type != NULL) && (r->pi_type != NULL)) 23641f6eb021SLiane Praza return (strcmp(l->pi_type, r->pi_type)); 23651f6eb021SLiane Praza if ((l->pi_type == NULL) && (r->pi_type == NULL)) 23661f6eb021SLiane Praza return (0); 23671f6eb021SLiane Praza 23681f6eb021SLiane Praza /* If we get here, exactly one of the types is NULL */ 23691f6eb021SLiane Praza if (l->pi_type == NULL) 23701f6eb021SLiane Praza return (-1); 23711f6eb021SLiane Praza return (1); 23721f6eb021SLiane Praza } 23731f6eb021SLiane Praza 23741f6eb021SLiane Praza /* If we get here, exactly one of the names is NULL */ 23751f6eb021SLiane Praza if (l->pi_name == NULL) 23761f6eb021SLiane Praza return (-1); 23771f6eb021SLiane Praza return (1); 23781f6eb021SLiane Praza } 23791f6eb021SLiane Praza 23801f6eb021SLiane Praza /* 23811f6eb021SLiane Praza * The target of a pg_pattern in combination with the level at which the 23821f6eb021SLiane Praza * pg_pattern was defined determines whether or not it should be applied. 23831f6eb021SLiane Praza * The following combinations should be ignored, and all others should be 23841f6eb021SLiane Praza * applied. 23851f6eb021SLiane Praza * 23861f6eb021SLiane Praza * Target Level 23871f6eb021SLiane Praza * ------ ----- 23881f6eb021SLiane Praza * this TL_RESTARTER, TL_GLOBAL 23891f6eb021SLiane Praza * "this" only applies if the pg_pattern was defined 23901f6eb021SLiane Praza * at the instance or service level 23911f6eb021SLiane Praza * delegate TL_INSTANCE, TL_SERVICE 23921f6eb021SLiane Praza * Only restarters and the global service can 23931f6eb021SLiane Praza * delegate. 23941f6eb021SLiane Praza * instance TL_INSTANCE, TL_RESTARTER, TL_GLOBAL 23951f6eb021SLiane Praza * Only the service level can specify the "instance" 23961f6eb021SLiane Praza * target. 23971f6eb021SLiane Praza * all TL_INSTANCE, TL_SERVICE, TL_RESTARTER 23981f6eb021SLiane Praza * Only the global service can specify the "all" 23991f6eb021SLiane Praza * target. 24001f6eb021SLiane Praza * 24011f6eb021SLiane Praza * Return Values: 24021f6eb021SLiane Praza * 1 apply the pg_pattern 24031f6eb021SLiane Praza * 0 ignore the pg_pattern 24041f6eb021SLiane Praza */ 24051f6eb021SLiane Praza static int 24061f6eb021SLiane Praza target_check(const char *target, tmpl_level_t level) 24071f6eb021SLiane Praza { 24081f6eb021SLiane Praza if ((target == NULL) || (*target == 0)) { 24091f6eb021SLiane Praza /* Default is this */ 24101f6eb021SLiane Praza target = SCF_TM_TARGET_THIS; 24111f6eb021SLiane Praza } 24121f6eb021SLiane Praza if (strcmp(target, SCF_TM_TARGET_THIS) == 0) { 24131f6eb021SLiane Praza if ((level == TL_RESTARTER) || 24141f6eb021SLiane Praza (level == TL_GLOBAL)) { 24151f6eb021SLiane Praza return (0); 24161f6eb021SLiane Praza } else { 24171f6eb021SLiane Praza return (1); 24181f6eb021SLiane Praza } 24191f6eb021SLiane Praza } 24201f6eb021SLiane Praza if (strcmp(target, SCF_TM_TARGET_DELEGATE) == 0) { 24211f6eb021SLiane Praza if ((level == TL_INSTANCE) || 24221f6eb021SLiane Praza (level == TL_SERVICE)) { 24231f6eb021SLiane Praza return (0); 24241f6eb021SLiane Praza } else { 24251f6eb021SLiane Praza return (1); 24261f6eb021SLiane Praza } 24271f6eb021SLiane Praza } 24281f6eb021SLiane Praza if (strcmp(target, SCF_TM_TARGET_INSTANCE) == 0) { 24291f6eb021SLiane Praza /* 24301f6eb021SLiane Praza * Note that the test is inverted from the other cases. 24311f6eb021SLiane Praza * This is because there is only one instance where apply 24321f6eb021SLiane Praza * is the correct thing to do. 24331f6eb021SLiane Praza */ 24341f6eb021SLiane Praza if (level == TL_SERVICE) { 24351f6eb021SLiane Praza return (1); 24361f6eb021SLiane Praza } else { 24371f6eb021SLiane Praza return (0); 24381f6eb021SLiane Praza } 24391f6eb021SLiane Praza } 24401f6eb021SLiane Praza if (strcmp(target, SCF_TM_TARGET_ALL) == 0) { 24411f6eb021SLiane Praza if ((level == TL_INSTANCE) || 24421f6eb021SLiane Praza (level == TL_SERVICE) || 24431f6eb021SLiane Praza (level == TL_RESTARTER)) { 24441f6eb021SLiane Praza return (0); 24451f6eb021SLiane Praza } 24461f6eb021SLiane Praza } 24471f6eb021SLiane Praza return (1); 24481f6eb021SLiane Praza } 24491f6eb021SLiane Praza 24501f6eb021SLiane Praza static int 24511f6eb021SLiane Praza pg_target_check(pgroup_t *pg_pattern, tmpl_level_t level) 24521f6eb021SLiane Praza { 24531f6eb021SLiane Praza const char *target; 24541f6eb021SLiane Praza 24551f6eb021SLiane Praza target = find_astring_value_in_pg(pg_pattern, SCF_PROPERTY_TM_TARGET); 24561f6eb021SLiane Praza if (level == TL_COMPOSED) { 24571f6eb021SLiane Praza switch (pg_pattern->sc_parent->sc_etype) { 24581f6eb021SLiane Praza case SVCCFG_INSTANCE_OBJECT: 24591f6eb021SLiane Praza level = TL_INSTANCE; 24601f6eb021SLiane Praza break; 24611f6eb021SLiane Praza case SVCCFG_SERVICE_OBJECT: 24621f6eb021SLiane Praza level = TL_SERVICE; 24631f6eb021SLiane Praza break; 24641f6eb021SLiane Praza default: 24651f6eb021SLiane Praza assert(0); 24661f6eb021SLiane Praza abort(); 24671f6eb021SLiane Praza } 24681f6eb021SLiane Praza } 24691f6eb021SLiane Praza return (target_check(target, level)); 24701f6eb021SLiane Praza } 24711f6eb021SLiane Praza 24721f6eb021SLiane Praza /* 24731f6eb021SLiane Praza * Find the prop_pattern's type sepcification and convert it to the 24741f6eb021SLiane Praza * appropriate scf_type. 24751f6eb021SLiane Praza */ 24761f6eb021SLiane Praza static tmpl_validate_status_t 24771f6eb021SLiane Praza prop_pattern_type(pgroup_t *pattern, scf_type_t *type) 24781f6eb021SLiane Praza { 24791f6eb021SLiane Praza const char *type_spec; 24801f6eb021SLiane Praza 24811f6eb021SLiane Praza assert(strcmp(pattern->sc_pgroup_type, 24821f6eb021SLiane Praza SCF_GROUP_TEMPLATE_PROP_PATTERN) == 0); 24831f6eb021SLiane Praza 24841f6eb021SLiane Praza type_spec = find_type_specification(pattern); 24851f6eb021SLiane Praza if ((type_spec == NULL) || (*type_spec == 0)) 24861f6eb021SLiane Praza return (TVS_MISSING_TYPE_SPECIFICATION); 24871f6eb021SLiane Praza *type = scf_string_to_type(type_spec); 24881f6eb021SLiane Praza return (TVS_SUCCESS); 24891f6eb021SLiane Praza } 24901f6eb021SLiane Praza 24911f6eb021SLiane Praza /* 24921f6eb021SLiane Praza * This function is analagous to scf_property_is_type(3SCF), but it works 24931f6eb021SLiane Praza * on the in memory representation of the property. 24941f6eb021SLiane Praza * 24951f6eb021SLiane Praza * RETURNS: 24961f6eb021SLiane Praza * 0 The property at prop does not have the specified 24971f6eb021SLiane Praza * type. 24981f6eb021SLiane Praza * non-zero The property at prop does have the specified type. 24991f6eb021SLiane Praza */ 25001f6eb021SLiane Praza static int 25011f6eb021SLiane Praza property_is_type(property_t *prop, scf_type_t type) 25021f6eb021SLiane Praza { 2503*870ad75aSSean Wilcox return (scf_is_compatible_type(type, prop->sc_value_type) == 2504*870ad75aSSean Wilcox SCF_SUCCESS); 25051f6eb021SLiane Praza } 25061f6eb021SLiane Praza 25071f6eb021SLiane Praza /* 25081f6eb021SLiane Praza * This function generates a property group name for a template's 25091f6eb021SLiane Praza * pg_pattern. The name and type of the pg_pattern are used to construct 25101f6eb021SLiane Praza * the name, but either or both may be null. A pointer to the constructed 25111f6eb021SLiane Praza * name is returned, and the referenced memory must be freed using 25121f6eb021SLiane Praza * free(3c). NULL is returned if we are unable to allocate enough memory. 25131f6eb021SLiane Praza */ 25141f6eb021SLiane Praza static char * 25151f6eb021SLiane Praza gen_pg_pattern_pg_name(const char *name, const char *type) 25161f6eb021SLiane Praza { 25171f6eb021SLiane Praza char *pg_name; 25181f6eb021SLiane Praza char *rv = NULL; 25191f6eb021SLiane Praza ssize_t name_size; 25201f6eb021SLiane Praza 25211f6eb021SLiane Praza name_size = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH); 25221f6eb021SLiane Praza pg_name = safe_malloc(name_size); 25231f6eb021SLiane Praza rv = pg_name; 25241f6eb021SLiane Praza 25251f6eb021SLiane Praza /* 25261f6eb021SLiane Praza * There are four cases -- name and type are both null, name and 25271f6eb021SLiane Praza * type are both non-null, only name is present or only type is 25281f6eb021SLiane Praza * present. 25291f6eb021SLiane Praza */ 25301f6eb021SLiane Praza if ((name == NULL) || (*name == 0)) { 25311f6eb021SLiane Praza if ((type == NULL) || (*type == 0)) { 25321f6eb021SLiane Praza /* 25331f6eb021SLiane Praza * Name and type are both null, so the PG name 25341f6eb021SLiane Praza * contains only the prefix. 25351f6eb021SLiane Praza */ 25361f6eb021SLiane Praza if (strlcpy(pg_name, SCF_PG_TM_PG_PATTERN_PREFIX, 25371f6eb021SLiane Praza name_size) >= name_size) { 25381f6eb021SLiane Praza rv = NULL; 25391f6eb021SLiane Praza } 25401f6eb021SLiane Praza } else { 25411f6eb021SLiane Praza /* 25421f6eb021SLiane Praza * If we have a type and no name, the type becomes 25431f6eb021SLiane Praza * part of the pg_pattern property group name. 25441f6eb021SLiane Praza */ 25451f6eb021SLiane Praza if (snprintf(pg_name, name_size, "%s%s", 25461f6eb021SLiane Praza SCF_PG_TM_PG_PATTERN_T_PREFIX, type) >= 25471f6eb021SLiane Praza name_size) { 25481f6eb021SLiane Praza rv = NULL; 25491f6eb021SLiane Praza } 25501f6eb021SLiane Praza } 25511f6eb021SLiane Praza } else { 25521f6eb021SLiane Praza /* 25531f6eb021SLiane Praza * As long as the pg_pattern has a name, it becomes part of 25541f6eb021SLiane Praza * the name of the pg_pattern property group name. We 25551f6eb021SLiane Praza * merely need to pick the appropriate prefix. 25561f6eb021SLiane Praza */ 25571f6eb021SLiane Praza const char *prefix; 25581f6eb021SLiane Praza if ((type == NULL) || (*type == 0)) { 25591f6eb021SLiane Praza prefix = SCF_PG_TM_PG_PATTERN_N_PREFIX; 25601f6eb021SLiane Praza } else { 25611f6eb021SLiane Praza prefix = SCF_PG_TM_PG_PATTERN_NT_PREFIX; 25621f6eb021SLiane Praza } 25631f6eb021SLiane Praza if (snprintf(pg_name, name_size, "%s%s", prefix, name) >= 25641f6eb021SLiane Praza name_size) { 25651f6eb021SLiane Praza rv = NULL; 25661f6eb021SLiane Praza } 25671f6eb021SLiane Praza } 25681f6eb021SLiane Praza 25691f6eb021SLiane Praza if (rv == NULL) { 25701f6eb021SLiane Praza /* Name was too big. */ 25711f6eb021SLiane Praza free(pg_name); 25721f6eb021SLiane Praza } 25731f6eb021SLiane Praza return (rv); 25741f6eb021SLiane Praza } 25751f6eb021SLiane Praza 25761f6eb021SLiane Praza /* 25771f6eb021SLiane Praza * pinfo contains information about a prop_pattern. An include_values 25781f6eb021SLiane Praza * element with a type of type has been included in the prop_pattern 25791f6eb021SLiane Praza * specification. We need to determine if the prop_pattern also contains 25801f6eb021SLiane Praza * constraints or values specifications as determined by type. Thus, we 25811f6eb021SLiane Praza * search the prop_pattern for properties whose names start with the 25821f6eb021SLiane Praza * correct prefix. 25831f6eb021SLiane Praza */ 25841f6eb021SLiane Praza static tmpl_validate_status_t 25851f6eb021SLiane Praza include_values_support(ptrn_info_t *pinfo, const char *type, 25861f6eb021SLiane Praza tmpl_errors_t *errs) 25871f6eb021SLiane Praza { 25881f6eb021SLiane Praza error_info_t einfo; 25891f6eb021SLiane Praza int i; 25901f6eb021SLiane Praza const char **prefixes; 25911f6eb021SLiane Praza const char *pfx; 25921f6eb021SLiane Praza property_t *prop; 25931f6eb021SLiane Praza pgroup_t *ptrn; 25941f6eb021SLiane Praza 25951f6eb021SLiane Praza if (strcmp(type, "constraints") == 0) { 25961f6eb021SLiane Praza prefixes = constraint_prefixes; 25971f6eb021SLiane Praza } else if (strcmp(type, "values") == 0) { 25981f6eb021SLiane Praza prefixes = value_prefixes; 25991f6eb021SLiane Praza } else { 26001f6eb021SLiane Praza CLEAR_ERROR_INFO(&einfo); 26011f6eb021SLiane Praza einfo.ei_type = EIT_BAD_TEMPLATE; 26021f6eb021SLiane Praza einfo.ei_u.ei_bad_template.ei_reason = gettext("include_values " 26031f6eb021SLiane Praza "type must be \"constraints\" or \"values\""); 26041f6eb021SLiane Praza (void) tmpl_errors_add_im(errs, TVS_BAD_TEMPLATE, 26051f6eb021SLiane Praza pinfo->pi_ptrnpg->sc_parent, pinfo->pi_enc_pgp, 26061f6eb021SLiane Praza NULL, pinfo->pi_ptrnpg, NULL, NULL, &einfo); 26071f6eb021SLiane Praza return (TVS_BAD_TEMPLATE); 26081f6eb021SLiane Praza } 26091f6eb021SLiane Praza 26101f6eb021SLiane Praza /* 26111f6eb021SLiane Praza * Now see if the prop_pattern has a property whose name starts 26121f6eb021SLiane Praza * with one of these prefixes. 26131f6eb021SLiane Praza */ 26141f6eb021SLiane Praza ptrn = pinfo->pi_ptrnpg; 26151f6eb021SLiane Praza for (prop = uu_list_first(ptrn->sc_pgroup_props); 26161f6eb021SLiane Praza prop != NULL; 26171f6eb021SLiane Praza prop = uu_list_next(ptrn->sc_pgroup_props, prop)) { 26181f6eb021SLiane Praza for (pfx = prefixes[0], i = 0; 26191f6eb021SLiane Praza pfx != NULL; 26201f6eb021SLiane Praza ++i, pfx = prefixes[i]) { 26211f6eb021SLiane Praza if (strncmp(prop->sc_property_name, pfx, 26221f6eb021SLiane Praza strlen(pfx)) == 0) { 26231f6eb021SLiane Praza return (TVS_SUCCESS); 26241f6eb021SLiane Praza } 26251f6eb021SLiane Praza } 26261f6eb021SLiane Praza } 26271f6eb021SLiane Praza 26281f6eb021SLiane Praza /* No match found. Generate error */ 26291f6eb021SLiane Praza CLEAR_ERROR_INFO(&einfo); 26301f6eb021SLiane Praza einfo.ei_type = EIT_INCLUDE_VALUES; 26311f6eb021SLiane Praza einfo.ei_u.ei_inc_values.ei_type = type; 26321f6eb021SLiane Praza (void) add_scf_error(errs, SCF_TERR_INCLUDE_VALUES, pinfo->pi_enc_pgp, 26331f6eb021SLiane Praza NULL, ptrn, NULL, NULL, &einfo); 26341f6eb021SLiane Praza 26351f6eb021SLiane Praza return (TVS_VALIDATION); 26361f6eb021SLiane Praza } 26371f6eb021SLiane Praza 26381f6eb021SLiane Praza /* 26391f6eb021SLiane Praza * Walk through the prop_patterns in tree, looking for any that have an 26401f6eb021SLiane Praza * include_values, SCF_PROPERTY_TM_CHOICES_INCLUDE_VALUES, property. For 26411f6eb021SLiane Praza * the prop_patterns with the include values property, verify that the 26421f6eb021SLiane Praza * prop_pattern has constraint or values declarations as specified by the 26431f6eb021SLiane Praza * include_values property. 26441f6eb021SLiane Praza */ 26451f6eb021SLiane Praza static tmpl_validate_status_t 26461f6eb021SLiane Praza tmpl_include_values_check(uu_avl_t *tree, tmpl_errors_t *errs) 26471f6eb021SLiane Praza { 26481f6eb021SLiane Praza ptrn_info_t *info; 26491f6eb021SLiane Praza property_t *iv; 26501f6eb021SLiane Praza tmpl_validate_status_t r; 26511f6eb021SLiane Praza tmpl_validate_status_t rc = TVS_SUCCESS; 26521f6eb021SLiane Praza value_t *v; 26531f6eb021SLiane Praza 26541f6eb021SLiane Praza for (info = uu_avl_first(tree); 26551f6eb021SLiane Praza info != NULL; 26561f6eb021SLiane Praza info = uu_avl_next(tree, info)) { 26571f6eb021SLiane Praza iv = internal_property_find(info->pi_ptrnpg, 26581f6eb021SLiane Praza SCF_PROPERTY_TM_CHOICES_INCLUDE_VALUES); 26591f6eb021SLiane Praza if (iv == NULL) 26601f6eb021SLiane Praza continue; 26611f6eb021SLiane Praza for (v = uu_list_first(iv->sc_property_values); 26621f6eb021SLiane Praza v != NULL; 26631f6eb021SLiane Praza v = uu_list_next(iv->sc_property_values, v)) { 26641f6eb021SLiane Praza assert(is_numeric_type(v->sc_type) == 0); 26651f6eb021SLiane Praza r = include_values_support(info, v->sc_u.sc_string, 26661f6eb021SLiane Praza errs); 26671f6eb021SLiane Praza if (r != TVS_SUCCESS) 26681f6eb021SLiane Praza rc = r; 26691f6eb021SLiane Praza } 26701f6eb021SLiane Praza } 26711f6eb021SLiane Praza return (rc); 26721f6eb021SLiane Praza } 26731f6eb021SLiane Praza 26741f6eb021SLiane Praza /* 26751f6eb021SLiane Praza * Verify that there are no conflicting definitions of pg_pattern or 26761f6eb021SLiane Praza * prop_pattern. Two patterns are said to be in conflict if they have the 26771f6eb021SLiane Praza * same name and differing types. There is a caveat, however. Empty 26781f6eb021SLiane Praza * pattern names or types are considered to be wild cards. There is no 26791f6eb021SLiane Praza * conflict if a pattern has a wild card. 26801f6eb021SLiane Praza */ 26811f6eb021SLiane Praza static tmpl_validate_status_t 26821f6eb021SLiane Praza tmpl_pattern_conflict(entity_t *inst, uu_avl_t *tree, ptrn_type_t type, 26831f6eb021SLiane Praza tmpl_errors_t *errs) 26841f6eb021SLiane Praza { 26851f6eb021SLiane Praza tmpl_validate_status_t r; 26861f6eb021SLiane Praza tmpl_validate_status_t rc; 26871f6eb021SLiane Praza 26881f6eb021SLiane Praza /* First walk the instance. */ 26891f6eb021SLiane Praza rc = gather_pattern(inst, type, tree, errs); 26901f6eb021SLiane Praza 26911f6eb021SLiane Praza /* Now walk the service */ 26921f6eb021SLiane Praza r = gather_pattern(inst->sc_parent, type, tree, errs); 26931f6eb021SLiane Praza if (r != TVS_SUCCESS) 26941f6eb021SLiane Praza rc = r; 26951f6eb021SLiane Praza 26961f6eb021SLiane Praza return (rc); 26971f6eb021SLiane Praza } 26981f6eb021SLiane Praza 26991f6eb021SLiane Praza static tmpl_validate_status_t 27001f6eb021SLiane Praza tmpl_required_attr_present(uu_avl_t *tree, tmpl_errors_t *errs) 27011f6eb021SLiane Praza { 27021f6eb021SLiane Praza ptrn_info_t *pinfo; 27031f6eb021SLiane Praza tmpl_validate_status_t rc = TVS_SUCCESS; 27041f6eb021SLiane Praza int reported_name; 27051f6eb021SLiane Praza int rv; 27061f6eb021SLiane Praza 27071f6eb021SLiane Praza for (pinfo = uu_avl_first(tree); 27081f6eb021SLiane Praza pinfo != NULL; 27091f6eb021SLiane Praza pinfo = uu_avl_next(tree, pinfo)) { 27101f6eb021SLiane Praza if (is_required(pinfo->pi_ptrnpg) == 0) { 27111f6eb021SLiane Praza /* Nothing to check if pattern is not required. */ 27121f6eb021SLiane Praza continue; 27131f6eb021SLiane Praza } 27141f6eb021SLiane Praza 27151f6eb021SLiane Praza /* 27161f6eb021SLiane Praza * For pg_pattern both name and type are optional unless 27171f6eb021SLiane Praza * the required attribute has a value of true. For 27181f6eb021SLiane Praza * prop_patterns only the type is optional, but it must be 27191f6eb021SLiane Praza * provided if the required attribute has a value of true. 27201f6eb021SLiane Praza */ 27211f6eb021SLiane Praza reported_name = 0; 27221f6eb021SLiane Praza if ((pinfo->pi_ptrn_type == PG_PATTERN) && 27231f6eb021SLiane Praza (pinfo->pi_name == NULL)) { 27241f6eb021SLiane Praza rc = TVS_VALIDATION; 27251f6eb021SLiane Praza if (add_scf_error(errs, SCF_TERR_PG_PATTERN_INCOMPLETE, 27261f6eb021SLiane Praza pinfo->pi_ptrnpg, 27271f6eb021SLiane Praza NULL, NULL, NULL, NULL, NULL) != 0) { 27281f6eb021SLiane Praza /* 27291f6eb021SLiane Praza * If we're unable to report errors, break 27301f6eb021SLiane Praza * out of the loop. 27311f6eb021SLiane Praza */ 27321f6eb021SLiane Praza break; 27331f6eb021SLiane Praza } 27341f6eb021SLiane Praza /* 27351f6eb021SLiane Praza * Don't report the error twice if both name and 27361f6eb021SLiane Praza * type are missing. One error message is 27371f6eb021SLiane Praza * adequate. 27381f6eb021SLiane Praza */ 27391f6eb021SLiane Praza reported_name = 1; 27401f6eb021SLiane Praza } 27411f6eb021SLiane Praza if ((pinfo->pi_type == NULL) && (reported_name == 0)) { 27421f6eb021SLiane Praza rc = TVS_VALIDATION; 27431f6eb021SLiane Praza if (pinfo->pi_ptrn_type == PG_PATTERN) { 27441f6eb021SLiane Praza rv = add_scf_error(errs, 27451f6eb021SLiane Praza SCF_TERR_PG_PATTERN_INCOMPLETE, 27461f6eb021SLiane Praza pinfo->pi_ptrnpg, 27471f6eb021SLiane Praza NULL, NULL, NULL, NULL, NULL); 27481f6eb021SLiane Praza } else { 27491f6eb021SLiane Praza rv = add_scf_error(errs, 27501f6eb021SLiane Praza SCF_TERR_PROP_PATTERN_INCOMPLETE, 27511f6eb021SLiane Praza pinfo->pi_enc_pgp, NULL, pinfo->pi_ptrnpg, 27521f6eb021SLiane Praza NULL, NULL, NULL); 27531f6eb021SLiane Praza } 27541f6eb021SLiane Praza /* If we're unable to log errors, break out of loop. */ 27551f6eb021SLiane Praza if (rv != 0) 27561f6eb021SLiane Praza break; 27571f6eb021SLiane Praza } 27581f6eb021SLiane Praza } 27591f6eb021SLiane Praza return (rc); 27601f6eb021SLiane Praza } 27611f6eb021SLiane Praza 27621f6eb021SLiane Praza /* 27631f6eb021SLiane Praza * Look for pg_pattern definitions in general. general is either the 27641f6eb021SLiane Praza * restarter serivce for inst or it is the global service. tree contains 27651f6eb021SLiane Praza * the ptrn_info_t structures describing the pg_patterns for an instance. 27661f6eb021SLiane Praza * For each general pg_pattern, see if the instance contains an overriding 27671f6eb021SLiane Praza * definition in tree. If it does generate an error entry. 27681f6eb021SLiane Praza * 27691f6eb021SLiane Praza * If a redefinition is found, TVS_WARN is returned. This is because a 27701f6eb021SLiane Praza * redefinition is not sufficient reason to inhibit the import operation. 27711f6eb021SLiane Praza */ 27721f6eb021SLiane Praza static tmpl_validate_status_t 27731f6eb021SLiane Praza tmpl_scan_general(entity_t *general, uu_avl_t *tree, 27741f6eb021SLiane Praza tmpl_level_t level, tmpl_errors_t *errs) 27751f6eb021SLiane Praza { 27761f6eb021SLiane Praza tmpl_level_t cur_level; 27771f6eb021SLiane Praza error_info_t einfo; 27781f6eb021SLiane Praza pgroup_t *pg; 27791f6eb021SLiane Praza ptrn_info_t *ginfo = NULL; 27801f6eb021SLiane Praza ptrn_info_t *match; 27811f6eb021SLiane Praza tmpl_validate_status_t rc = TVS_SUCCESS; 27821f6eb021SLiane Praza 27831f6eb021SLiane Praza /* 27841f6eb021SLiane Praza * General services may not be in repository yet. It depends on 27851f6eb021SLiane Praza * the order that manifests are imported. 27861f6eb021SLiane Praza */ 27871f6eb021SLiane Praza if (general == NULL) 27881f6eb021SLiane Praza return (TVS_SUCCESS); 27891f6eb021SLiane Praza 27901f6eb021SLiane Praza for (pg = uu_list_first(general->sc_pgroups); 27911f6eb021SLiane Praza pg != NULL; 27921f6eb021SLiane Praza pg = uu_list_next(general->sc_pgroups, pg)) { 27931f6eb021SLiane Praza if (strcmp(pg->sc_pgroup_type, 27941f6eb021SLiane Praza SCF_GROUP_TEMPLATE_PG_PATTERN) != 0) { 27951f6eb021SLiane Praza /* Not a pg_pattern */ 27961f6eb021SLiane Praza continue; 27971f6eb021SLiane Praza } 27981f6eb021SLiane Praza if (ginfo != NULL) 27991f6eb021SLiane Praza ptrn_info_destroy(ginfo); 28001f6eb021SLiane Praza ginfo = ptrn_info_create(pg); 28011f6eb021SLiane Praza match = uu_avl_find(tree, ginfo, NULL, NULL); 28021f6eb021SLiane Praza if (match != NULL) { 28031f6eb021SLiane Praza /* See if global pg_pattern is targeted at us. */ 28041f6eb021SLiane Praza if (target_check(ginfo->pi_target, level) == 0) 28051f6eb021SLiane Praza continue; 28061f6eb021SLiane Praza 28071f6eb021SLiane Praza /* 28081f6eb021SLiane Praza * See if the match applies to us. If we happen to 28091f6eb021SLiane Praza * be a restarter, the pg_pattern could have a 28101f6eb021SLiane Praza * target of delegate. That wouldn't apply to this 28111f6eb021SLiane Praza * instance, it would only apply to our delegates. 28121f6eb021SLiane Praza * Cases such as this are not a redefinition. 28131f6eb021SLiane Praza */ 28141f6eb021SLiane Praza if (match->pi_ptrnpg->sc_parent->sc_etype == 28151f6eb021SLiane Praza SVCCFG_INSTANCE_OBJECT) { 28161f6eb021SLiane Praza cur_level = TL_INSTANCE; 28171f6eb021SLiane Praza } else { 28181f6eb021SLiane Praza cur_level = TL_SERVICE; 28191f6eb021SLiane Praza } 28201f6eb021SLiane Praza if (target_check(match->pi_target, cur_level) == 0) 28211f6eb021SLiane Praza continue; 28221f6eb021SLiane Praza 28231f6eb021SLiane Praza /* 28241f6eb021SLiane Praza * Instance or service overrides a general 28251f6eb021SLiane Praza * definition. We need to issue a warning message. 28261f6eb021SLiane Praza */ 28271f6eb021SLiane Praza rc = TVS_WARN; 28281f6eb021SLiane Praza CLEAR_ERROR_INFO(&einfo); 28291f6eb021SLiane Praza einfo.ei_type = EIT_PATTERN_CONFLICT; 28301f6eb021SLiane Praza einfo.ei_u.ei_pattern_conflict.ei_pattern = pg; 28311f6eb021SLiane Praza if (add_scf_error(errs, SCF_TERR_GENERAL_REDEFINE, 28321f6eb021SLiane Praza match->pi_ptrnpg, NULL, NULL, NULL, NULL, 28331f6eb021SLiane Praza &einfo) != 0) { 28341f6eb021SLiane Praza /* 28351f6eb021SLiane Praza * No need to continue the search if we 28361f6eb021SLiane Praza * cannot record errors. 28371f6eb021SLiane Praza */ 28381f6eb021SLiane Praza break; 28391f6eb021SLiane Praza } 28401f6eb021SLiane Praza } 28411f6eb021SLiane Praza } 28421f6eb021SLiane Praza 28431f6eb021SLiane Praza if (ginfo != NULL) 28441f6eb021SLiane Praza ptrn_info_destroy(ginfo); 28451f6eb021SLiane Praza return (rc); 28461f6eb021SLiane Praza } 28471f6eb021SLiane Praza 28481f6eb021SLiane Praza /* 28491f6eb021SLiane Praza * tree contains the pg_pattern definitions for the instance at inst. See 28501f6eb021SLiane Praza * if these pg_patterns redefine any pg_patterns in the instance's 28511f6eb021SLiane Praza * restarter or in the global service. TVS_WARN is returned if a 28521f6eb021SLiane Praza * redefinition is encountered. 28531f6eb021SLiane Praza */ 28541f6eb021SLiane Praza static tmpl_validate_status_t 28551f6eb021SLiane Praza tmpl_level_redefine(entity_t *inst, uu_avl_t *tree, tmpl_errors_t *errs) 28561f6eb021SLiane Praza { 28571f6eb021SLiane Praza entity_t *restarter; 28581f6eb021SLiane Praza entity_t *svc = inst->sc_parent; 28591f6eb021SLiane Praza tmpl_validate_status_t r; 28601f6eb021SLiane Praza tmpl_validate_status_t rc; 28611f6eb021SLiane Praza 28621f6eb021SLiane Praza restarter = inst->sc_u.sc_instance.sc_instance_restarter; 28631f6eb021SLiane Praza if (restarter == NULL) { 28641f6eb021SLiane Praza /* No instance restarter. Use the service restarter */ 28651f6eb021SLiane Praza restarter = svc->sc_u.sc_service.sc_restarter; 28661f6eb021SLiane Praza } 28671f6eb021SLiane Praza rc = tmpl_scan_general(restarter, tree, TL_RESTARTER, errs); 28681f6eb021SLiane Praza r = tmpl_scan_general(svc->sc_u.sc_service.sc_global, tree, 28691f6eb021SLiane Praza TL_GLOBAL, errs); 28701f6eb021SLiane Praza if (r != TVS_SUCCESS) 28711f6eb021SLiane Praza rc = r; 28721f6eb021SLiane Praza return (rc); 28731f6eb021SLiane Praza } 28741f6eb021SLiane Praza 28751f6eb021SLiane Praza /* 28761f6eb021SLiane Praza * Perform the following consistency checks on the template specifications 28771f6eb021SLiane Praza * themselves: 28781f6eb021SLiane Praza * 28791f6eb021SLiane Praza * - No conflicting definitions of `pg_pattern` are allowed within a 28801f6eb021SLiane Praza * single instance. 28811f6eb021SLiane Praza * 28821f6eb021SLiane Praza * - Templates at a narrow target (e.g. instance) which define 28831f6eb021SLiane Praza * property groups already templated at a broad target 28841f6eb021SLiane Praza * (e.g. restarter or all) are strongly discouraged. 28851f6eb021SLiane Praza * 28861f6eb021SLiane Praza * - Developers may not define a template which specifies a single 28871f6eb021SLiane Praza * prop_pattern name with differing types on the same target 28881f6eb021SLiane Praza * entity. 28891f6eb021SLiane Praza * 28901f6eb021SLiane Praza * - If a pg_pattern has a required attribute with a value of true, 28911f6eb021SLiane Praza * then its name and type attributes must be specified. 28921f6eb021SLiane Praza * 28931f6eb021SLiane Praza * - If a prop_pattern has a required attribute with a value of true, 28941f6eb021SLiane Praza * then its type attribute must be specified. 28951f6eb021SLiane Praza * 28961f6eb021SLiane Praza * - If a prop_pattern has an include values make sure that the 28971f6eb021SLiane Praza * appropriate constraints or values element has also been 28981f6eb021SLiane Praza * declared. 28991f6eb021SLiane Praza */ 29001f6eb021SLiane Praza static tmpl_validate_status_t 29011f6eb021SLiane Praza tmpl_consistency(entity_t *inst, tmpl_errors_t *errs) 29021f6eb021SLiane Praza { 29031f6eb021SLiane Praza void *marker = NULL; 29041f6eb021SLiane Praza ptrn_info_t *info; 29051f6eb021SLiane Praza uu_avl_t *tree; 29061f6eb021SLiane Praza tmpl_validate_status_t rc; 29071f6eb021SLiane Praza tmpl_validate_status_t r; 29081f6eb021SLiane Praza 29091f6eb021SLiane Praza /* Allocate the tree. */ 29101f6eb021SLiane Praza tree = uu_avl_create(ptrn_info_pool, NULL, TMPL_DEBUG_TREE); 29111f6eb021SLiane Praza if (tree == NULL) { 29121f6eb021SLiane Praza uu_die(gettext("pg_info tree creation failed: %s\n"), 29131f6eb021SLiane Praza uu_strerror(uu_error())); 29141f6eb021SLiane Praza } 29151f6eb021SLiane Praza 29161f6eb021SLiane Praza rc = tmpl_pattern_conflict(inst, tree, PG_PATTERN, errs); 29171f6eb021SLiane Praza 29181f6eb021SLiane Praza /* 29191f6eb021SLiane Praza * The tree now contains the instance and service pg_patterns. 29201f6eb021SLiane Praza * Check to see if they override any pg_pattern definitions in the 29211f6eb021SLiane Praza * restarter and global services. 29221f6eb021SLiane Praza */ 29231f6eb021SLiane Praza r = tmpl_level_redefine(inst, tree, errs); 29241f6eb021SLiane Praza if (r != TVS_SUCCESS) { 29251f6eb021SLiane Praza /* 29261f6eb021SLiane Praza * tmpl_level_redefine() can return a warning. Don't 29271f6eb021SLiane Praza * override a serious error with a warning. 29281f6eb021SLiane Praza */ 29291f6eb021SLiane Praza if (r == TVS_WARN) { 29301f6eb021SLiane Praza if (rc == TVS_SUCCESS) 29311f6eb021SLiane Praza rc = r; 29321f6eb021SLiane Praza } else { 29331f6eb021SLiane Praza rc = r; 29341f6eb021SLiane Praza } 29351f6eb021SLiane Praza } 29361f6eb021SLiane Praza 29371f6eb021SLiane Praza /* 29381f6eb021SLiane Praza * If the pg_pattern has a required attribute with a value of true, 29391f6eb021SLiane Praza * then it must also have name and type attributes. 29401f6eb021SLiane Praza */ 29411f6eb021SLiane Praza r = tmpl_required_attr_present(tree, errs); 29421f6eb021SLiane Praza if (r != TVS_SUCCESS) 29431f6eb021SLiane Praza rc = r; 29441f6eb021SLiane Praza 29451f6eb021SLiane Praza /* Empty the tree, so that we can reuse it for prop_patterns. */ 29461f6eb021SLiane Praza while ((info = uu_avl_teardown(tree, &marker)) != NULL) { 29471f6eb021SLiane Praza ptrn_info_destroy(info); 29481f6eb021SLiane Praza } 29491f6eb021SLiane Praza 29501f6eb021SLiane Praza r = tmpl_pattern_conflict(inst, tree, PROP_PATTERN, errs); 29511f6eb021SLiane Praza if (r != TVS_SUCCESS) 29521f6eb021SLiane Praza rc = r; 29531f6eb021SLiane Praza 29541f6eb021SLiane Praza /* 29551f6eb021SLiane Praza * If a prop_pattern has required attribute with a value of true, 29561f6eb021SLiane Praza * then it must also have a type attribute. 29571f6eb021SLiane Praza */ 29581f6eb021SLiane Praza r = tmpl_required_attr_present(tree, errs); 29591f6eb021SLiane Praza if (r != TVS_SUCCESS) 29601f6eb021SLiane Praza rc = r; 29611f6eb021SLiane Praza 29621f6eb021SLiane Praza /* 29631f6eb021SLiane Praza * Insure that include_values have the constraint for values 29641f6eb021SLiane Praza * elements that are needed. 29651f6eb021SLiane Praza */ 29661f6eb021SLiane Praza r = tmpl_include_values_check(tree, errs); 29671f6eb021SLiane Praza if (r != TVS_SUCCESS) 29681f6eb021SLiane Praza rc = r; 29691f6eb021SLiane Praza 29701f6eb021SLiane Praza /* Tear down the tree. */ 29711f6eb021SLiane Praza marker = NULL; 29721f6eb021SLiane Praza while ((info = uu_avl_teardown(tree, &marker)) != NULL) { 29731f6eb021SLiane Praza ptrn_info_destroy(info); 29741f6eb021SLiane Praza } 29751f6eb021SLiane Praza uu_avl_destroy(tree); 29761f6eb021SLiane Praza 29771f6eb021SLiane Praza return (rc); 29781f6eb021SLiane Praza } 29791f6eb021SLiane Praza 29801f6eb021SLiane Praza /* 29811f6eb021SLiane Praza * Release memory associated with the tmpl_errors structure and then free 29821f6eb021SLiane Praza * the structure itself. 29831f6eb021SLiane Praza */ 29841f6eb021SLiane Praza void 29851f6eb021SLiane Praza tmpl_errors_destroy(tmpl_errors_t *te) 29861f6eb021SLiane Praza { 29871f6eb021SLiane Praza im_tmpl_error_t *ite; 29881f6eb021SLiane Praza tv_errors_t *ste; 29891f6eb021SLiane Praza void *marker = NULL; 29901f6eb021SLiane Praza 29911f6eb021SLiane Praza if (te == NULL) 29921f6eb021SLiane Praza return; 29931f6eb021SLiane Praza if (te->te_list) { 29941f6eb021SLiane Praza while ((ite = uu_list_teardown(te->te_list, &marker)) != NULL) { 29951f6eb021SLiane Praza uu_list_node_fini(ite, &ite->ite_node, 29961f6eb021SLiane Praza inmem_errors_pool); 29971f6eb021SLiane Praza uu_free(ite); 29981f6eb021SLiane Praza } 29991f6eb021SLiane Praza uu_list_destroy(te->te_list); 30001f6eb021SLiane Praza } 30011f6eb021SLiane Praza if (te->te_scf) { 30021f6eb021SLiane Praza marker = NULL; 30031f6eb021SLiane Praza while ((ste = uu_list_teardown(te->te_scf, &marker)) != NULL) { 30041f6eb021SLiane Praza destroy_scf_errors(ste); 30051f6eb021SLiane Praza } 30061f6eb021SLiane Praza uu_list_destroy(te->te_scf); 30071f6eb021SLiane Praza } 30081f6eb021SLiane Praza uu_free(te); 30091f6eb021SLiane Praza } 30101f6eb021SLiane Praza 30111f6eb021SLiane Praza /* 30121f6eb021SLiane Praza * Allocate and initialize a tmpl_errors structure. The address of the 30131f6eb021SLiane Praza * structure is returned, unless we are unable to allocate enough memory. 30141f6eb021SLiane Praza * In the case of memory allocation failures, NULL is returned. 30151f6eb021SLiane Praza * 30161f6eb021SLiane Praza * The allocated structure should be freed by calling 30171f6eb021SLiane Praza * tmpl_errors_destroy(). 30181f6eb021SLiane Praza */ 30191f6eb021SLiane Praza static tmpl_errors_t * 30201f6eb021SLiane Praza tmpl_errors_create() 30211f6eb021SLiane Praza { 30221f6eb021SLiane Praza tmpl_errors_t *te; 30231f6eb021SLiane Praza 30241f6eb021SLiane Praza te = uu_zalloc(sizeof (*te)); 30251f6eb021SLiane Praza if (te == NULL) 30261f6eb021SLiane Praza return (NULL); 30271f6eb021SLiane Praza te->te_list = uu_list_create(inmem_errors_pool, NULL, TMPL_DEBUG_LIST); 30281f6eb021SLiane Praza if (te->te_list == NULL) { 30291f6eb021SLiane Praza uu_free(te); 30301f6eb021SLiane Praza return (NULL); 30311f6eb021SLiane Praza } 30321f6eb021SLiane Praza te->te_scf = uu_list_create(tv_errors_pool, NULL, TMPL_DEBUG_LIST); 30331f6eb021SLiane Praza if (te->te_scf == NULL) { 30341f6eb021SLiane Praza tmpl_errors_destroy(te); 30351f6eb021SLiane Praza return (NULL); 30361f6eb021SLiane Praza } 30371f6eb021SLiane Praza 30381f6eb021SLiane Praza return (te); 30391f6eb021SLiane Praza } 30401f6eb021SLiane Praza 30411f6eb021SLiane Praza void 30421f6eb021SLiane Praza tmpl_errors_print(FILE *out, tmpl_errors_t *errs, const char *prefix) 30431f6eb021SLiane Praza { 30441f6eb021SLiane Praza scf_tmpl_error_t *cur; 30451f6eb021SLiane Praza size_t buf_size = 4096; 30461f6eb021SLiane Praza im_tmpl_error_t *ite; 30471f6eb021SLiane Praza char *s = NULL; 30481f6eb021SLiane Praza scf_tmpl_errors_t *scferrs; 30491f6eb021SLiane Praza tv_errors_t *scft; 30501f6eb021SLiane Praza int interactive = (est->sc_cmd_flags & SC_CMD_IACTIVE) ? 30511f6eb021SLiane Praza SCF_TMPL_STRERROR_HUMAN : 0; 30521f6eb021SLiane Praza 30531f6eb021SLiane Praza for (ite = uu_list_first(errs->te_list); 30541f6eb021SLiane Praza ite != NULL; 30551f6eb021SLiane Praza ite = uu_list_next(errs->te_list, ite)) { 30561f6eb021SLiane Praza im_tmpl_error_print(out, ite, prefix); 30571f6eb021SLiane Praza } 30581f6eb021SLiane Praza 30591f6eb021SLiane Praza /* Now handle the errors that can be printed via libscf. */ 30601f6eb021SLiane Praza s = safe_malloc(buf_size); 30611f6eb021SLiane Praza for (scft = uu_list_first(errs->te_scf); 30621f6eb021SLiane Praza scft != NULL; 30631f6eb021SLiane Praza scft = uu_list_next(errs->te_scf, scft)) { 30641f6eb021SLiane Praza scferrs = scft->tve_errors; 30651f6eb021SLiane Praza if (_scf_tmpl_error_set_prefix(scferrs, prefix) != 0) 30661f6eb021SLiane Praza uu_die(emesg_nomem); 30671f6eb021SLiane Praza while ((cur = scf_tmpl_next_error(scferrs)) != NULL) { 30681f6eb021SLiane Praza (void) scf_tmpl_strerror(cur, s, buf_size, interactive); 30691f6eb021SLiane Praza (void) fputs(s, out); 30701f6eb021SLiane Praza (void) fputc('\n', out); 30711f6eb021SLiane Praza } 30721f6eb021SLiane Praza } 30731f6eb021SLiane Praza 30741f6eb021SLiane Praza free(s); 30751f6eb021SLiane Praza } 30761f6eb021SLiane Praza 30771f6eb021SLiane Praza /* 30781f6eb021SLiane Praza * This function finds the prop_pattern for the property, prop. e is the 30791f6eb021SLiane Praza * instance where the search for the prop_pattern will start. pg_pattern 30801f6eb021SLiane Praza * is the address of the pg_pattern that holds the prop_pattern. 30811f6eb021SLiane Praza */ 30821f6eb021SLiane Praza static tmpl_validate_status_t 30831f6eb021SLiane Praza tmpl_find_prop_pattern(entity_t *inst, pgroup_t *pg_pattern, 30841f6eb021SLiane Praza property_t *prop, pgroup_t **prop_pattern) 30851f6eb021SLiane Praza { 30861f6eb021SLiane Praza pgroup_t *candidate; 30871f6eb021SLiane Praza pg_iter_t *iter = NULL; 30881f6eb021SLiane Praza char *prop_pattern_name = NULL; 30891f6eb021SLiane Praza tmpl_validate_status_t rc; 30901f6eb021SLiane Praza 30911f6eb021SLiane Praza /* 30921f6eb021SLiane Praza * Get the name of the property group that holds the prop_pattern 30931f6eb021SLiane Praza * definition. 30941f6eb021SLiane Praza */ 30951f6eb021SLiane Praza rc = gen_prop_pattern_pg_name(pg_pattern, 30961f6eb021SLiane Praza prop->sc_property_name, &prop_pattern_name); 30971f6eb021SLiane Praza if (rc != TVS_SUCCESS) 30981f6eb021SLiane Praza goto out; 30991f6eb021SLiane Praza 31001f6eb021SLiane Praza /* Find the property group. */ 31011f6eb021SLiane Praza iter = pg_iter_create(inst, SCF_GROUP_TEMPLATE_PROP_PATTERN); 31021f6eb021SLiane Praza if (iter == NULL) 31031f6eb021SLiane Praza goto out; 31041f6eb021SLiane Praza while ((candidate = next_pattern_pg(iter)) != NULL) { 31051f6eb021SLiane Praza const char *c; 31061f6eb021SLiane Praza 31071f6eb021SLiane Praza if (strcmp(prop_pattern_name, candidate->sc_pgroup_name) != 0) 31081f6eb021SLiane Praza continue; 31091f6eb021SLiane Praza c = find_astring_value_in_pg(candidate, 31101f6eb021SLiane Praza SCF_PROPERTY_TM_PG_PATTERN); 31111f6eb021SLiane Praza if (c == NULL) 31121f6eb021SLiane Praza continue; 31131f6eb021SLiane Praza if (strcmp(pg_pattern->sc_pgroup_name, c) == 0) 31141f6eb021SLiane Praza break; 31151f6eb021SLiane Praza } 31161f6eb021SLiane Praza *prop_pattern = candidate; 31171f6eb021SLiane Praza if (candidate == NULL) 31181f6eb021SLiane Praza rc = TVS_NOMATCH; 31191f6eb021SLiane Praza 31201f6eb021SLiane Praza out: 31211f6eb021SLiane Praza pg_iter_destroy(iter); 31221f6eb021SLiane Praza uu_free((void *)prop_pattern_name); 31231f6eb021SLiane Praza return (rc); 31241f6eb021SLiane Praza } 31251f6eb021SLiane Praza 31261f6eb021SLiane Praza /* 31271f6eb021SLiane Praza * Indexes for pg_pattern property group names. Indexes are arranged 31281f6eb021SLiane Praza * from most specific to least specific. 31291f6eb021SLiane Praza */ 31301f6eb021SLiane Praza #define PGN_BOTH 0 /* both name and type */ 31311f6eb021SLiane Praza #define PGN_NAME 1 /* name only */ 31321f6eb021SLiane Praza #define PGN_TYPE 2 /* type only */ 31331f6eb021SLiane Praza #define PGN_NEITHER 3 /* neither name nor type */ 31341f6eb021SLiane Praza #define PGN_MAX 4 /* Size of array */ 31351f6eb021SLiane Praza 31361f6eb021SLiane Praza /* 31371f6eb021SLiane Praza * Given an instance entity, e, and a propety group, pg, within the 31381f6eb021SLiane Praza * instance; return the address of the pg_pattern for the property group. 31391f6eb021SLiane Praza * The address of the pg_pattern is placed at pgp. NULL indicates that no 31401f6eb021SLiane Praza * pg_pattern was specified. 31411f6eb021SLiane Praza */ 31421f6eb021SLiane Praza static tmpl_validate_status_t 31431f6eb021SLiane Praza tmpl_find_pg_pattern(entity_t *e, pgroup_t *pg, pgroup_t **pgp) 31441f6eb021SLiane Praza { 31451f6eb021SLiane Praza pgroup_t *cpg; /* candidate property group */ 31461f6eb021SLiane Praza int i; 31471f6eb021SLiane Praza pg_iter_t *iter = NULL; 31481f6eb021SLiane Praza char *pg_names[PGN_MAX]; 31491f6eb021SLiane Praza pgroup_t *pg_patterns[PGN_MAX]; 31501f6eb021SLiane Praza tmpl_validate_status_t rv = TVS_SUCCESS; 31511f6eb021SLiane Praza 31521f6eb021SLiane Praza (void) memset(pg_patterns, 0, sizeof (pg_patterns)); 31531f6eb021SLiane Praza *pgp = NULL; 31541f6eb021SLiane Praza 31551f6eb021SLiane Praza /* Generate candidate names for pg_pattern property groups. */ 31561f6eb021SLiane Praza pg_names[PGN_BOTH] = gen_pg_pattern_pg_name(pg->sc_pgroup_name, 31571f6eb021SLiane Praza pg->sc_pgroup_type); 31581f6eb021SLiane Praza pg_names[PGN_NAME] = gen_pg_pattern_pg_name(pg->sc_pgroup_name, 31591f6eb021SLiane Praza NULL); 31601f6eb021SLiane Praza pg_names[PGN_TYPE] = gen_pg_pattern_pg_name(NULL, 31611f6eb021SLiane Praza pg->sc_pgroup_type); 31621f6eb021SLiane Praza pg_names[PGN_NEITHER] = gen_pg_pattern_pg_name(NULL, NULL); 31631f6eb021SLiane Praza for (i = 0; i < PGN_MAX; i++) { 31641f6eb021SLiane Praza if (pg_names[i] == NULL) { 31651f6eb021SLiane Praza rv = TVS_BAD_TEMPLATE; 31661f6eb021SLiane Praza goto errout; 31671f6eb021SLiane Praza } 31681f6eb021SLiane Praza } 31691f6eb021SLiane Praza 31701f6eb021SLiane Praza /* Search for property groups that match these names */ 31711f6eb021SLiane Praza iter = pg_iter_create(e, SCF_GROUP_TEMPLATE_PG_PATTERN); 31721f6eb021SLiane Praza if (iter == NULL) { 31731f6eb021SLiane Praza uu_die(emesg_nomem); 31741f6eb021SLiane Praza } 31751f6eb021SLiane Praza while ((cpg = next_pattern_pg(iter)) != NULL) { 31761f6eb021SLiane Praza if (pg_target_check(cpg, iter->pgi_level) == 0) 31771f6eb021SLiane Praza continue; 31781f6eb021SLiane Praza 31791f6eb021SLiane Praza /* See if we have a name match. */ 31801f6eb021SLiane Praza for (i = 0; i < PGN_MAX; i++) { 31811f6eb021SLiane Praza if (strcmp(cpg->sc_pgroup_name, pg_names[i]) == 0) { 31821f6eb021SLiane Praza /* 31831f6eb021SLiane Praza * If we already have a lower level 31841f6eb021SLiane Praza * pg_pattern, keep it. 31851f6eb021SLiane Praza */ 31861f6eb021SLiane Praza if (pg_patterns[i] == NULL) 31871f6eb021SLiane Praza pg_patterns[i] = cpg; 31881f6eb021SLiane Praza break; 31891f6eb021SLiane Praza } 31901f6eb021SLiane Praza } 31911f6eb021SLiane Praza } 31921f6eb021SLiane Praza 31931f6eb021SLiane Praza /* Find the most specific pg_pattern. */ 31941f6eb021SLiane Praza for (i = 0; i < PGN_MAX; i++) { 31951f6eb021SLiane Praza if (pg_patterns[i] != NULL) { 31961f6eb021SLiane Praza *pgp = pg_patterns[i]; 31971f6eb021SLiane Praza break; 31981f6eb021SLiane Praza } 31991f6eb021SLiane Praza } 32001f6eb021SLiane Praza errout: 32011f6eb021SLiane Praza for (i = 0; i < PGN_MAX; i++) { 32021f6eb021SLiane Praza free(pg_names[i]); 32031f6eb021SLiane Praza } 32041f6eb021SLiane Praza pg_iter_destroy(iter); 32051f6eb021SLiane Praza return (rv); 32061f6eb021SLiane Praza } 32071f6eb021SLiane Praza 32081f6eb021SLiane Praza /* 32091f6eb021SLiane Praza * Initialize structures that are required for validation using 32101f6eb021SLiane Praza * templates specifications. 32111f6eb021SLiane Praza */ 32121f6eb021SLiane Praza void 32131f6eb021SLiane Praza tmpl_init(void) 32141f6eb021SLiane Praza { 32151f6eb021SLiane Praza emesg_nomem = gettext("Out of memory.\n"); 32161f6eb021SLiane Praza 32171f6eb021SLiane Praza composed_pg_pool = uu_avl_pool_create("composed_pg", 32181f6eb021SLiane Praza sizeof (composed_pg_t), offsetof(composed_pg_t, cpg_node), 32191f6eb021SLiane Praza composed_pg_compare, TMPL_DEBUG_AVL_POOL); 32201f6eb021SLiane Praza if (composed_pg_pool == NULL) { 32211f6eb021SLiane Praza uu_die(gettext("composed_pg pool creation failed: %s\n"), 32221f6eb021SLiane Praza uu_strerror(uu_error())); 32231f6eb021SLiane Praza } 32241f6eb021SLiane Praza composed_prop_pool = uu_avl_pool_create("composed_prop", 32251f6eb021SLiane Praza sizeof (property_t), offsetof(property_t, sc_composed_node), 32261f6eb021SLiane Praza composed_prop_compare, TMPL_DEBUG_AVL_POOL); 32271f6eb021SLiane Praza if (composed_prop_pool == NULL) { 32281f6eb021SLiane Praza uu_die(gettext("composed_prop pool creation failed. %s\n"), 32291f6eb021SLiane Praza uu_strerror(uu_error())); 32301f6eb021SLiane Praza } 32311f6eb021SLiane Praza ptrn_info_pool = uu_avl_pool_create("ptrn_info", sizeof (ptrn_info_t), 32321f6eb021SLiane Praza offsetof(ptrn_info_t, pi_link), ptrn_info_compare, 32331f6eb021SLiane Praza TMPL_DEBUG_AVL_POOL); 32341f6eb021SLiane Praza if (ptrn_info_pool == NULL) { 32351f6eb021SLiane Praza uu_die(gettext("pg_pattern info pool creation failed: %s\n"), 32361f6eb021SLiane Praza uu_strerror(uu_error())); 32371f6eb021SLiane Praza } 32381f6eb021SLiane Praza inmem_errors_pool = uu_list_pool_create("errors-internal", 32391f6eb021SLiane Praza sizeof (im_tmpl_error_t), offsetof(im_tmpl_error_t, 32401f6eb021SLiane Praza ite_node), NULL, TMPL_DEBUG_LIST_POOL); 32411f6eb021SLiane Praza if (inmem_errors_pool == NULL) { 32421f6eb021SLiane Praza uu_die(gettext("inmem_errors_pool pool creation failed: " 32431f6eb021SLiane Praza "%s\n"), uu_strerror(uu_error())); 32441f6eb021SLiane Praza } 32451f6eb021SLiane Praza tv_errors_pool = uu_list_pool_create("scf-terrors", 32461f6eb021SLiane Praza sizeof (tv_errors_t), offsetof(tv_errors_t, tve_node), 32471f6eb021SLiane Praza NULL, TMPL_DEBUG_LIST_POOL); 32481f6eb021SLiane Praza if (tv_errors_pool == NULL) { 32491f6eb021SLiane Praza uu_die(gettext("tv_errors_pool pool creation failed: %s\n"), 32501f6eb021SLiane Praza uu_strerror(uu_error())); 32511f6eb021SLiane Praza } 32521f6eb021SLiane Praza } 32531f6eb021SLiane Praza 32541f6eb021SLiane Praza /* 32551f6eb021SLiane Praza * Clean up the composed property node in the property. 32561f6eb021SLiane Praza */ 32571f6eb021SLiane Praza void 32581f6eb021SLiane Praza tmpl_property_fini(property_t *p) 32591f6eb021SLiane Praza { 32601f6eb021SLiane Praza uu_avl_node_fini(p, &p->sc_composed_node, composed_prop_pool); 32611f6eb021SLiane Praza } 32621f6eb021SLiane Praza 32631f6eb021SLiane Praza /* 32641f6eb021SLiane Praza * Initialize the composed property node in the property. 32651f6eb021SLiane Praza */ 32661f6eb021SLiane Praza void 32671f6eb021SLiane Praza tmpl_property_init(property_t *p) 32681f6eb021SLiane Praza { 32691f6eb021SLiane Praza uu_avl_node_init(p, &p->sc_composed_node, composed_prop_pool); 32701f6eb021SLiane Praza } 32711f6eb021SLiane Praza 32721f6eb021SLiane Praza /* 32731f6eb021SLiane Praza * Use the cardinality specification in the prop_pattern to verify the 32741f6eb021SLiane Praza * cardinality of the property at prop. The cardinality of the property is 32751f6eb021SLiane Praza * the number of values that it has. 32761f6eb021SLiane Praza * 32771f6eb021SLiane Praza * pg is the property group that holds prop, and pg_pattern is the 32781f6eb021SLiane Praza * pg_pattern for the property group. pg and pg_pattern are only used for 32791f6eb021SLiane Praza * error reporting. 32801f6eb021SLiane Praza */ 32811f6eb021SLiane Praza static tmpl_validate_status_t 32821f6eb021SLiane Praza tmpl_validate_cardinality(pgroup_t *prop_pattern, property_t *prop, 32831f6eb021SLiane Praza pgroup_t *pg, pgroup_t *pg_pattern, tmpl_errors_t *errs) 32841f6eb021SLiane Praza { 32851f6eb021SLiane Praza size_t count; 32861f6eb021SLiane Praza uint64_t max; 32871f6eb021SLiane Praza uint64_t min; 32881f6eb021SLiane Praza tmpl_validate_status_t rc; 32891f6eb021SLiane Praza error_info_t einfo; 32901f6eb021SLiane Praza 32911f6eb021SLiane Praza assert(strcmp(prop_pattern->sc_pgroup_type, 32921f6eb021SLiane Praza SCF_GROUP_TEMPLATE_PROP_PATTERN) == 0); 32931f6eb021SLiane Praza 32941f6eb021SLiane Praza rc = get_cardinality(prop_pattern, &min, &max); 32951f6eb021SLiane Praza switch (rc) { 32961f6eb021SLiane Praza case TVS_NOMATCH: 32971f6eb021SLiane Praza /* Nothing to check. */ 32981f6eb021SLiane Praza return (TVS_SUCCESS); 32991f6eb021SLiane Praza case TVS_SUCCESS: 33001f6eb021SLiane Praza /* Process the limits. */ 33011f6eb021SLiane Praza break; 33021f6eb021SLiane Praza default: 33031f6eb021SLiane Praza return (rc); 33041f6eb021SLiane Praza } 33051f6eb021SLiane Praza 33061f6eb021SLiane Praza if ((min == 0) && (max == ULLONG_MAX)) { 33071f6eb021SLiane Praza /* Any number of values is permitted. No need to count. */ 33081f6eb021SLiane Praza return (TVS_SUCCESS); 33091f6eb021SLiane Praza } 33101f6eb021SLiane Praza 33111f6eb021SLiane Praza count = count_prop_values(prop); 33121f6eb021SLiane Praza if ((count < min) || (count > max)) { 33131f6eb021SLiane Praza CLEAR_ERROR_INFO(&einfo); 33141f6eb021SLiane Praza einfo.ei_type = EIT_CARDINALITY; 33151f6eb021SLiane Praza einfo.ei_u.ei_cardinality.ei_min = min; 33161f6eb021SLiane Praza einfo.ei_u.ei_cardinality.ei_max = max; 33171f6eb021SLiane Praza einfo.ei_u.ei_cardinality.ei_count = count; 33181f6eb021SLiane Praza (void) add_scf_error(errs, SCF_TERR_CARDINALITY_VIOLATION, 33191f6eb021SLiane Praza pg_pattern, pg, prop_pattern, prop, NULL, &einfo); 33201f6eb021SLiane Praza return (TVS_VALIDATION); 33211f6eb021SLiane Praza } 33221f6eb021SLiane Praza 33231f6eb021SLiane Praza return (TVS_SUCCESS); 33241f6eb021SLiane Praza } 33251f6eb021SLiane Praza 33261f6eb021SLiane Praza /* 33271f6eb021SLiane Praza * Iterate over pg_patterns in the entity, e. If the pg_pattern's required 33281f6eb021SLiane Praza * attribute is true, verify that the entity contains the corresponding 33291f6eb021SLiane Praza * property group. 33301f6eb021SLiane Praza */ 33311f6eb021SLiane Praza static tmpl_validate_status_t 33321f6eb021SLiane Praza tmpl_required_pg_present(entity_t *e, tmpl_errors_t *errs) 33331f6eb021SLiane Praza { 33341f6eb021SLiane Praza composed_pg_t cpg; 33351f6eb021SLiane Praza composed_pg_t *match; 33361f6eb021SLiane Praza error_info_t einfo; 33371f6eb021SLiane Praza pg_iter_t *iter; 33381f6eb021SLiane Praza pgroup_t *pg; 33391f6eb021SLiane Praza const char *pg_name; 33401f6eb021SLiane Praza const char *pg_type; 33411f6eb021SLiane Praza tmpl_validate_status_t rc = TVS_SUCCESS; 33421f6eb021SLiane Praza uu_avl_t *tree; 33431f6eb021SLiane Praza 33441f6eb021SLiane Praza assert(e->sc_etype == SVCCFG_INSTANCE_OBJECT); 33451f6eb021SLiane Praza 33461f6eb021SLiane Praza iter = pg_iter_create(e, SCF_GROUP_TEMPLATE_PG_PATTERN); 33471f6eb021SLiane Praza if (iter == NULL) 33481f6eb021SLiane Praza uu_die(emesg_nomem); 33491f6eb021SLiane Praza 33501f6eb021SLiane Praza CLEAR_ERROR_INFO(&einfo); 33511f6eb021SLiane Praza einfo.ei_type = EIT_MISSING_PG; 33521f6eb021SLiane Praza 33531f6eb021SLiane Praza while ((pg = next_pattern_pg(iter)) != NULL) { 33541f6eb021SLiane Praza if (is_required(pg) == 0) { 33551f6eb021SLiane Praza /* If pg is not required, there is nothing to check. */ 33561f6eb021SLiane Praza continue; 33571f6eb021SLiane Praza } 33581f6eb021SLiane Praza pg_name = find_astring_value_in_pg(pg, SCF_PROPERTY_TM_NAME); 33591f6eb021SLiane Praza pg_type = find_astring_value_in_pg(pg, SCF_PROPERTY_TM_TYPE); 33601f6eb021SLiane Praza if (pg_target_check(pg, iter->pgi_level) == 0) 33611f6eb021SLiane Praza continue; 33621f6eb021SLiane Praza einfo.ei_u.ei_missing_pg.ei_pg_name = pg_name; 33631f6eb021SLiane Praza einfo.ei_u.ei_missing_pg.ei_pg_type = pg_type; 33641f6eb021SLiane Praza tree = e->sc_u.sc_instance.sc_composed; 33651f6eb021SLiane Praza (void) memset(&cpg, 0, sizeof (cpg)); 33661f6eb021SLiane Praza cpg.cpg_name = pg_name; 33671f6eb021SLiane Praza cpg.cpg_type = pg_type; 33681f6eb021SLiane Praza match = uu_avl_find(tree, &cpg, NULL, NULL); 33691f6eb021SLiane Praza if (match == NULL) { 33701f6eb021SLiane Praza rc = TVS_VALIDATION; 33711f6eb021SLiane Praza if (add_scf_error(errs, SCF_TERR_MISSING_PG, pg, 33721f6eb021SLiane Praza NULL, NULL, NULL, NULL, &einfo) != 0) { 33731f6eb021SLiane Praza break; 33741f6eb021SLiane Praza } 33751f6eb021SLiane Praza } 33761f6eb021SLiane Praza } 33771f6eb021SLiane Praza 33781f6eb021SLiane Praza pg_iter_destroy(iter); 33791f6eb021SLiane Praza return (rc); 33801f6eb021SLiane Praza } 33811f6eb021SLiane Praza 33821f6eb021SLiane Praza /* 33831f6eb021SLiane Praza * Verify that the property group, pg, contains property declarations for 33841f6eb021SLiane Praza * all required properties. Unfortunately, there is no direct way to find 33851f6eb021SLiane Praza * the prop_patterns for a given property group. Therefore, we need to 33861f6eb021SLiane Praza * scan the entity at e looking for property groups with a type of 33871f6eb021SLiane Praza * SCF_GROUP_TEMPLATE_PROP_PATTERN. That is, we scan the entity looking 33881f6eb021SLiane Praza * for all prop_patterns. When we find a prop_pattern, we look at the 33891f6eb021SLiane Praza * value of its pg_pattern property to see if it matches the name of the 33901f6eb021SLiane Praza * pg_pattern. If they match, this is a prop_pattern that is of interest 33911f6eb021SLiane Praza * to us. 33921f6eb021SLiane Praza * 33931f6eb021SLiane Praza * When we find an interesting prop_pattern, we see if it's required 33941f6eb021SLiane Praza * property is true. If it is, we verify that the property group at pg 33951f6eb021SLiane Praza * contains the specified property. 33961f6eb021SLiane Praza */ 33971f6eb021SLiane Praza static tmpl_validate_status_t 33981f6eb021SLiane Praza tmpl_required_props_present(entity_t *e, pgroup_t *pg, pgroup_t *pg_pattern, 33991f6eb021SLiane Praza tmpl_errors_t *errs) 34001f6eb021SLiane Praza { 34011f6eb021SLiane Praza error_info_t einfo; 34021f6eb021SLiane Praza pg_iter_t *iter; 34031f6eb021SLiane Praza const char *prop_name; 34041f6eb021SLiane Praza const char *prop_pg_pattern_name; 34051f6eb021SLiane Praza pgroup_t *prop_pattern; 34061f6eb021SLiane Praza scf_tmpl_error_type_t ec; 34071f6eb021SLiane Praza tmpl_validate_status_t rc = TVS_SUCCESS; 34081f6eb021SLiane Praza 34091f6eb021SLiane Praza /* 34101f6eb021SLiane Praza * Scan the entity's property groups looking for ones with a type 34111f6eb021SLiane Praza * of SCF_GROUP_TEMPLATE_PROP_PATTERN. 34121f6eb021SLiane Praza */ 34131f6eb021SLiane Praza iter = pg_iter_create(e, SCF_GROUP_TEMPLATE_PROP_PATTERN); 34141f6eb021SLiane Praza if (iter == NULL) 34151f6eb021SLiane Praza uu_die(emesg_nomem); 34161f6eb021SLiane Praza CLEAR_ERROR_INFO(&einfo); 34171f6eb021SLiane Praza for (prop_pattern = next_pattern_pg(iter); 34181f6eb021SLiane Praza prop_pattern != NULL; 34191f6eb021SLiane Praza prop_pattern = next_pattern_pg(iter)) { 34201f6eb021SLiane Praza /* 34211f6eb021SLiane Praza * Find the pg_pattern property in this prop_pattern. 34221f6eb021SLiane Praza * Verify that its value matches the name of the 34231f6eb021SLiane Praza * pg_pattern. 34241f6eb021SLiane Praza */ 34251f6eb021SLiane Praza prop_pg_pattern_name = find_astring_value_in_pg(prop_pattern, 34261f6eb021SLiane Praza SCF_PROPERTY_TM_PG_PATTERN); 34271f6eb021SLiane Praza assert(prop_pg_pattern_name != NULL); 34281f6eb021SLiane Praza if (strcmp(pg_pattern->sc_pgroup_name, 34291f6eb021SLiane Praza prop_pg_pattern_name) != 0) { 34301f6eb021SLiane Praza continue; 34311f6eb021SLiane Praza } 34321f6eb021SLiane Praza 34331f6eb021SLiane Praza /* If the property is required, see if it is in the pg. */ 34341f6eb021SLiane Praza if (is_required(prop_pattern) == 0) 34351f6eb021SLiane Praza continue; 34361f6eb021SLiane Praza prop_name = find_astring_value_in_pg(prop_pattern, 34371f6eb021SLiane Praza SCF_PROPERTY_TM_NAME); 34381f6eb021SLiane Praza assert(prop_name != NULL); 34391f6eb021SLiane Praza if (property_find(pg, prop_name) == NULL) { 34401f6eb021SLiane Praza ec = SCF_TERR_MISSING_PROP; 34411f6eb021SLiane Praza rc = TVS_VALIDATION; 34421f6eb021SLiane Praza einfo.ei_type = EIT_MISSING_PROP; 34431f6eb021SLiane Praza einfo.ei_u.ei_missing_prop.ei_prop_name = prop_name; 34441f6eb021SLiane Praza if (add_scf_error(errs, ec, pg_pattern, pg, 34451f6eb021SLiane Praza prop_pattern, NULL, NULL, &einfo) != 0) { 34461f6eb021SLiane Praza /* 34471f6eb021SLiane Praza * If we can no longer accumulate errors, 34481f6eb021SLiane Praza * break out of the loop. 34491f6eb021SLiane Praza */ 34501f6eb021SLiane Praza break; 34511f6eb021SLiane Praza } 34521f6eb021SLiane Praza } 34531f6eb021SLiane Praza } 34541f6eb021SLiane Praza 34551f6eb021SLiane Praza pg_iter_destroy(iter); 34561f6eb021SLiane Praza return (rc); 34571f6eb021SLiane Praza } 34581f6eb021SLiane Praza 34591f6eb021SLiane Praza /* 34601f6eb021SLiane Praza * Check the value at v to see if it falls within any of the ranges at r. 34611f6eb021SLiane Praza * count is the number of ranges at r, and type tells whether to treat the 34621f6eb021SLiane Praza * value as signed or unsigned. 34631f6eb021SLiane Praza * 34641f6eb021SLiane Praza * Return 1 if the value falls within one of the ranges. Otherwise return 34651f6eb021SLiane Praza * 0. 34661f6eb021SLiane Praza */ 34671f6eb021SLiane Praza static int 34681f6eb021SLiane Praza value_in_range(value_t *v, scf_type_t type, range_t *r, size_t count) 34691f6eb021SLiane Praza { 34701f6eb021SLiane Praza for (; count > 0; --count, r++) { 34711f6eb021SLiane Praza if (type == SCF_TYPE_COUNT) { 34721f6eb021SLiane Praza if ((v->sc_u.sc_count >= 34731f6eb021SLiane Praza r->rng_u.rng_unsigned.rng_min) && 34741f6eb021SLiane Praza (v->sc_u.sc_count <= 34751f6eb021SLiane Praza r->rng_u.rng_unsigned.rng_max)) 34761f6eb021SLiane Praza return (1); 34771f6eb021SLiane Praza } else { 34781f6eb021SLiane Praza if ((v->sc_u.sc_integer >= 34791f6eb021SLiane Praza r->rng_u.rng_signed.rng_min) && 34801f6eb021SLiane Praza (v->sc_u.sc_integer <= 34811f6eb021SLiane Praza r->rng_u.rng_signed.rng_max)) 34821f6eb021SLiane Praza return (1); 34831f6eb021SLiane Praza } 34841f6eb021SLiane Praza } 34851f6eb021SLiane Praza return (0); 34861f6eb021SLiane Praza } 34871f6eb021SLiane Praza 34881f6eb021SLiane Praza /* 34891f6eb021SLiane Praza * If the template prop_pattern at pattern contains a constraint_range 34901f6eb021SLiane Praza * property, use the specified range to validate all the numeric property 34911f6eb021SLiane Praza * values of the property at prop. 34921f6eb021SLiane Praza * 34931f6eb021SLiane Praza * pg is the property group that holds prop, and pg_pattern is the 34941f6eb021SLiane Praza * pg_pattern for the property group. pg and pg_pattern are only used for 34951f6eb021SLiane Praza * error reporting. 34961f6eb021SLiane Praza */ 34971f6eb021SLiane Praza static tmpl_validate_status_t 34981f6eb021SLiane Praza tmpl_validate_value_range(pgroup_t *pattern, property_t *prop, pgroup_t *pg, 34991f6eb021SLiane Praza pgroup_t *pg_pattern, tmpl_errors_t *errs) 35001f6eb021SLiane Praza { 35011f6eb021SLiane Praza uint_t count; 35021f6eb021SLiane Praza error_info_t einfo; 35031f6eb021SLiane Praza property_t *range_prop; 35041f6eb021SLiane Praza range_t *ranges; 35051f6eb021SLiane Praza tmpl_validate_status_t rc; 35061f6eb021SLiane Praza scf_type_t type; 35071f6eb021SLiane Praza value_t *v; 35081f6eb021SLiane Praza 35091f6eb021SLiane Praza /* Get the range constraints if they exist. */ 35101f6eb021SLiane Praza if ((range_prop = property_find(pattern, 35111f6eb021SLiane Praza SCF_PROPERTY_TM_CONSTRAINT_RANGE)) == NULL) { 35121f6eb021SLiane Praza /* No range to check. */ 35131f6eb021SLiane Praza return (TVS_SUCCESS); 35141f6eb021SLiane Praza } 35151f6eb021SLiane Praza type = prop->sc_value_type; 35161f6eb021SLiane Praza if ((type != SCF_TYPE_COUNT) && (type != SCF_TYPE_INTEGER)) { 35171f6eb021SLiane Praza rc = TVS_BAD_TEMPLATE; 35181f6eb021SLiane Praza CLEAR_ERROR_INFO(&einfo); 35191f6eb021SLiane Praza einfo.ei_type = EIT_BAD_TEMPLATE; 35201f6eb021SLiane Praza einfo.ei_u.ei_bad_template.ei_reason = 35211f6eb021SLiane Praza gettext("Property does not have correct type for " 35221f6eb021SLiane Praza "a range specification"); 35231f6eb021SLiane Praza (void) tmpl_errors_add_im(errs, rc, pg_pattern->sc_parent, 35241f6eb021SLiane Praza pg_pattern, pg, pattern, prop, NULL, &einfo); 35251f6eb021SLiane Praza return (rc); 35261f6eb021SLiane Praza } 35271f6eb021SLiane Praza if ((rc = get_ranges(range_prop, prop->sc_value_type, &ranges, 35281f6eb021SLiane Praza &count)) != TVS_SUCCESS) { 35291f6eb021SLiane Praza rc = TVS_BAD_TEMPLATE; 35301f6eb021SLiane Praza CLEAR_ERROR_INFO(&einfo); 35311f6eb021SLiane Praza einfo.ei_type = EIT_BAD_TEMPLATE; 35321f6eb021SLiane Praza einfo.ei_u.ei_bad_template.ei_reason = gettext("Illegal range " 35331f6eb021SLiane Praza "value"); 35341f6eb021SLiane Praza (void) tmpl_errors_add_im(errs, rc, pg_pattern->sc_parent, 35351f6eb021SLiane Praza pg_pattern, pg, pattern, prop, NULL, &einfo); 35361f6eb021SLiane Praza return (rc); 35371f6eb021SLiane Praza } 35381f6eb021SLiane Praza 35391f6eb021SLiane Praza /* Set up error info before entering loop. */ 35401f6eb021SLiane Praza CLEAR_ERROR_INFO(&einfo); 35411f6eb021SLiane Praza einfo.ei_type = EIT_RANGE; 35421f6eb021SLiane Praza einfo.ei_u.ei_range.ei_rtype = type; 35431f6eb021SLiane Praza 35441f6eb021SLiane Praza /* Compare numeric values of the property to the range. */ 35451f6eb021SLiane Praza for (v = uu_list_first(prop->sc_property_values); 35461f6eb021SLiane Praza v != NULL; 35471f6eb021SLiane Praza v = uu_list_next(prop->sc_property_values, v)) { 35481f6eb021SLiane Praza if (value_in_range(v, type, ranges, count) == 1) 35491f6eb021SLiane Praza continue; 35501f6eb021SLiane Praza if (type == SCF_TYPE_COUNT) { 35511f6eb021SLiane Praza einfo.ei_u.ei_range.ei_uvalue = v->sc_u.sc_count; 35521f6eb021SLiane Praza } else { 35531f6eb021SLiane Praza einfo.ei_u.ei_range.ei_ivalue = v->sc_u.sc_integer; 35541f6eb021SLiane Praza } 35551f6eb021SLiane Praza rc = TVS_VALIDATION; 35561f6eb021SLiane Praza if (add_scf_error(errs, SCF_TERR_RANGE_VIOLATION, pg_pattern, 35571f6eb021SLiane Praza pg, pattern, prop, v, &einfo) != 0) { 35581f6eb021SLiane Praza return (rc); 35591f6eb021SLiane Praza } 35601f6eb021SLiane Praza } 35611f6eb021SLiane Praza 35621f6eb021SLiane Praza return (rc); 35631f6eb021SLiane Praza } 35641f6eb021SLiane Praza 35651f6eb021SLiane Praza /* 35661f6eb021SLiane Praza * If the prop_pattern has value constraints, verify that all the values 35671f6eb021SLiane Praza * for the property at prop are legal values. 35681f6eb021SLiane Praza * 35691f6eb021SLiane Praza * pg is the property group that holds prop, and pg_pattern is the 35701f6eb021SLiane Praza * pg_pattern for the property group. pg and pg_pattern are only used for 35711f6eb021SLiane Praza * error reporting. 35721f6eb021SLiane Praza */ 35731f6eb021SLiane Praza static tmpl_validate_status_t 35741f6eb021SLiane Praza tmpl_validate_values(pgroup_t *prop_pattern, property_t *prop, pgroup_t *pg, 35751f6eb021SLiane Praza pgroup_t *pg_pattern, tmpl_errors_t *errs) 35761f6eb021SLiane Praza { 35771f6eb021SLiane Praza int found; 35781f6eb021SLiane Praza uint_t i; 35791f6eb021SLiane Praza avalues_t *legal; 35801f6eb021SLiane Praza tmpl_validate_status_t r; 35811f6eb021SLiane Praza tmpl_validate_status_t rc = TVS_SUCCESS; 35821f6eb021SLiane Praza value_t *v; 35831f6eb021SLiane Praza 35841f6eb021SLiane Praza /* Get list of legal values. */ 35851f6eb021SLiane Praza r = av_get_values(prop_pattern, SCF_PROPERTY_TM_CONSTRAINT_NAME, 35861f6eb021SLiane Praza prop->sc_value_type, &legal); 35871f6eb021SLiane Praza switch (r) { 35881f6eb021SLiane Praza case TVS_BAD_CONVERSION: 35891f6eb021SLiane Praza (void) tmpl_errors_add_im(errs, r, pg->sc_parent, pg_pattern, 35901f6eb021SLiane Praza pg, prop_pattern, prop, NULL, NULL); 35911f6eb021SLiane Praza return (r); 35921f6eb021SLiane Praza case TVS_NOMATCH: 35931f6eb021SLiane Praza /* No constraints in template. */ 35941f6eb021SLiane Praza return (TVS_SUCCESS); 35951f6eb021SLiane Praza case TVS_SUCCESS: 35961f6eb021SLiane Praza /* process the constraints. */ 35971f6eb021SLiane Praza break; 35981f6eb021SLiane Praza default: 35991f6eb021SLiane Praza assert(0); 36001f6eb021SLiane Praza abort(); 36011f6eb021SLiane Praza } 36021f6eb021SLiane Praza 36031f6eb021SLiane Praza /* Check the property values against the legal values. */ 36041f6eb021SLiane Praza for (v = uu_list_first(prop->sc_property_values); 36051f6eb021SLiane Praza v != NULL; 36061f6eb021SLiane Praza v = uu_list_next(prop->sc_property_values, v)) { 36071f6eb021SLiane Praza /* Check this property value against the legal values. */ 36081f6eb021SLiane Praza found = 0; 36091f6eb021SLiane Praza for (i = 0; (i < legal->av_count) && (found == 0); i++) { 36101f6eb021SLiane Praza switch (v->sc_type) { 36111f6eb021SLiane Praza case SCF_TYPE_BOOLEAN: 36121f6eb021SLiane Praza case SCF_TYPE_COUNT: 36131f6eb021SLiane Praza if (av_get_unsigned(legal, i) == 36141f6eb021SLiane Praza v->sc_u.sc_count) { 36151f6eb021SLiane Praza found = 1; 36161f6eb021SLiane Praza } 36171f6eb021SLiane Praza break; 36181f6eb021SLiane Praza case SCF_TYPE_INTEGER: 36191f6eb021SLiane Praza if (av_get_integer(legal, i) == 36201f6eb021SLiane Praza v->sc_u.sc_integer) { 36211f6eb021SLiane Praza found = 1; 36221f6eb021SLiane Praza } 36231f6eb021SLiane Praza break; 36241f6eb021SLiane Praza default: 36251f6eb021SLiane Praza if (strcmp(av_get_string(legal, i), 36261f6eb021SLiane Praza v->sc_u.sc_string) == 0) { 36271f6eb021SLiane Praza found = 1; 36281f6eb021SLiane Praza } 36291f6eb021SLiane Praza break; 36301f6eb021SLiane Praza } 36311f6eb021SLiane Praza } 36321f6eb021SLiane Praza if (found == 0) { 36331f6eb021SLiane Praza rc = TVS_VALIDATION; 36341f6eb021SLiane Praza if (add_scf_error(errs, 36351f6eb021SLiane Praza SCF_TERR_VALUE_CONSTRAINT_VIOLATED, pg_pattern, pg, 36361f6eb021SLiane Praza prop_pattern, prop, v, NULL) != 0) { 36371f6eb021SLiane Praza /* 36381f6eb021SLiane Praza * Exit loop if no longer able to report 36391f6eb021SLiane Praza * errors. 36401f6eb021SLiane Praza */ 36411f6eb021SLiane Praza break; 36421f6eb021SLiane Praza } 36431f6eb021SLiane Praza } 36441f6eb021SLiane Praza } 36451f6eb021SLiane Praza 36461f6eb021SLiane Praza out: 36471f6eb021SLiane Praza av_destroy(legal); 36481f6eb021SLiane Praza return (rc); 36491f6eb021SLiane Praza } 36501f6eb021SLiane Praza 36511f6eb021SLiane Praza /* 36521f6eb021SLiane Praza * Verify the following items about the values of property, prop. 36531f6eb021SLiane Praza * 36541f6eb021SLiane Praza * - The values all have the type specified by the prop_pattern at 36551f6eb021SLiane Praza * pattern. 36561f6eb021SLiane Praza * - Check numeric values against range constraints. 36571f6eb021SLiane Praza * - If the prop_pattern has one or more value constraints, validate 36581f6eb021SLiane Praza * the property's values against the constraints. 36591f6eb021SLiane Praza * 36601f6eb021SLiane Praza * pg is the property group that holds prop, and pg_pattern is the 36611f6eb021SLiane Praza * pg_pattern for the property group. pg and pg_pattern are only used for 36621f6eb021SLiane Praza * error reporting. 36631f6eb021SLiane Praza */ 36641f6eb021SLiane Praza static tmpl_validate_status_t 36651f6eb021SLiane Praza tmpl_validate_value_constraints(pgroup_t *pattern, property_t *prop, 36661f6eb021SLiane Praza pgroup_t *pg, pgroup_t *pg_pattern, tmpl_errors_t *errs) 36671f6eb021SLiane Praza { 36681f6eb021SLiane Praza tmpl_validate_status_t r; 36691f6eb021SLiane Praza tmpl_validate_status_t rc; 36701f6eb021SLiane Praza 36711f6eb021SLiane Praza rc = tmpl_validate_value_range(pattern, prop, pg, pg_pattern, errs); 36721f6eb021SLiane Praza r = tmpl_validate_values(pattern, prop, pg, pg_pattern, errs); 36731f6eb021SLiane Praza if (r != TVS_SUCCESS) 36741f6eb021SLiane Praza rc = r; 36751f6eb021SLiane Praza 36761f6eb021SLiane Praza return (rc); 36771f6eb021SLiane Praza } 36781f6eb021SLiane Praza 36791f6eb021SLiane Praza /* 36801f6eb021SLiane Praza * Perform the following validations on the property, prop. 36811f6eb021SLiane Praza * 36821f6eb021SLiane Praza * - Verify that the property's type agrees with the type specified in 36831f6eb021SLiane Praza * the prop_pattern template, tmpl. 36841f6eb021SLiane Praza * - Verify the cardinality. 36851f6eb021SLiane Praza * - Verify that the property values satisfy the constraints specified 36861f6eb021SLiane Praza * by the template. 36871f6eb021SLiane Praza * 36881f6eb021SLiane Praza * pg is the property group that holds prop, and pg_pattern is the 36891f6eb021SLiane Praza * pg_pattern for the property group. pg and pg_pattern are only used for 36901f6eb021SLiane Praza * error reporting. 36911f6eb021SLiane Praza */ 36921f6eb021SLiane Praza static tmpl_validate_status_t 36931f6eb021SLiane Praza tmpl_validate_prop(property_t *prop, pgroup_t *tmpl, pgroup_t *pg, 36941f6eb021SLiane Praza pgroup_t *pg_pattern, tmpl_errors_t *errs) 36951f6eb021SLiane Praza { 36961f6eb021SLiane Praza scf_tmpl_error_type_t ec; 36971f6eb021SLiane Praza error_info_t einfo; 36981f6eb021SLiane Praza tmpl_validate_status_t r; 36991f6eb021SLiane Praza tmpl_validate_status_t rc = TVS_SUCCESS; 37001f6eb021SLiane Praza int status; 37011f6eb021SLiane Praza scf_type_t type; 37021f6eb021SLiane Praza 37031f6eb021SLiane Praza r = prop_pattern_type(tmpl, &type); 37041f6eb021SLiane Praza switch (r) { 37051f6eb021SLiane Praza case TVS_SUCCESS: 37061f6eb021SLiane Praza if (type == SCF_TYPE_INVALID) { 37071f6eb021SLiane Praza rc = TVS_INVALID_TYPE_SPECIFICATION; 37081f6eb021SLiane Praza r = tmpl_errors_add_im(errs, rc, pg->sc_parent, NULL, 37091f6eb021SLiane Praza pg, tmpl, NULL, NULL, NULL); 37101f6eb021SLiane Praza if (r != TVS_SUCCESS) { 37111f6eb021SLiane Praza /* 37121f6eb021SLiane Praza * Give up if we can no longer accumulate 37131f6eb021SLiane Praza * errors. 37141f6eb021SLiane Praza */ 37151f6eb021SLiane Praza return (rc); 37161f6eb021SLiane Praza } 37171f6eb021SLiane Praza } else { 37181f6eb021SLiane Praza if (property_is_type(prop, type) == 0) { 37191f6eb021SLiane Praza CLEAR_ERROR_INFO(&einfo); 37201f6eb021SLiane Praza rc = TVS_VALIDATION; 37211f6eb021SLiane Praza ec = SCF_TERR_WRONG_PROP_TYPE; 37221f6eb021SLiane Praza einfo.ei_type = EIT_PROP_TYPE; 37231f6eb021SLiane Praza einfo.ei_u.ei_prop_type.ei_specified = type; 37241f6eb021SLiane Praza einfo.ei_u.ei_prop_type.ei_actual = 37251f6eb021SLiane Praza prop->sc_value_type; 37261f6eb021SLiane Praza status = add_scf_error(errs, ec, 37271f6eb021SLiane Praza pg_pattern, pg, tmpl, prop, NULL, &einfo); 37281f6eb021SLiane Praza if (status != 0) { 37291f6eb021SLiane Praza /* 37301f6eb021SLiane Praza * Give up if we can no longer 37311f6eb021SLiane Praza * accumulate errors. 37321f6eb021SLiane Praza */ 37331f6eb021SLiane Praza return (rc); 37341f6eb021SLiane Praza } 37351f6eb021SLiane Praza } 37361f6eb021SLiane Praza } 37371f6eb021SLiane Praza break; 37381f6eb021SLiane Praza case TVS_MISSING_TYPE_SPECIFICATION: 37391f6eb021SLiane Praza /* 37401f6eb021SLiane Praza * A null type specification means that we do not need to 37411f6eb021SLiane Praza * check the property's type. 37421f6eb021SLiane Praza */ 37431f6eb021SLiane Praza break; 37441f6eb021SLiane Praza default: 37451f6eb021SLiane Praza rc = r; 37461f6eb021SLiane Praza } 37471f6eb021SLiane Praza 37481f6eb021SLiane Praza /* Validate the cardinality */ 37491f6eb021SLiane Praza r = tmpl_validate_cardinality(tmpl, prop, pg, pg_pattern, errs); 37501f6eb021SLiane Praza if (r != TVS_SUCCESS) 37511f6eb021SLiane Praza rc = r; 37521f6eb021SLiane Praza 37531f6eb021SLiane Praza /* Validate that property values satisfy constraints. */ 37541f6eb021SLiane Praza r = tmpl_validate_value_constraints(tmpl, prop, pg, pg_pattern, errs); 37551f6eb021SLiane Praza if (r != TVS_SUCCESS) 37561f6eb021SLiane Praza rc = r; 37571f6eb021SLiane Praza 37581f6eb021SLiane Praza return (rc); 37591f6eb021SLiane Praza } 37601f6eb021SLiane Praza 37611f6eb021SLiane Praza /* 37621f6eb021SLiane Praza * Validate the property group at pg by performing the following checks: 37631f6eb021SLiane Praza * 37641f6eb021SLiane Praza * - Verify that the types of the pg and the pg_pattern are 37651f6eb021SLiane Praza * compatible. 37661f6eb021SLiane Praza * - Verify the properties in the pg. 37671f6eb021SLiane Praza * - Verify that required properties are present. 37681f6eb021SLiane Praza */ 37691f6eb021SLiane Praza static tmpl_validate_status_t 37701f6eb021SLiane Praza tmpl_validate_pg(entity_t *e, pgroup_t *pg, tmpl_errors_t *errs) 37711f6eb021SLiane Praza { 37721f6eb021SLiane Praza error_info_t einfo; 37731f6eb021SLiane Praza const char *pg_pattern_type; /* Type declared by pg_pattern. */ 37741f6eb021SLiane Praza pgroup_t *pg_pattern; /* Prop. group for pg_pattern */ 37751f6eb021SLiane Praza property_t *prop; 37761f6eb021SLiane Praza pgroup_t *prop_pattern; 37771f6eb021SLiane Praza tmpl_validate_status_t r; 37781f6eb021SLiane Praza tmpl_validate_status_t rc = TVS_SUCCESS; 37791f6eb021SLiane Praza int stat; 37801f6eb021SLiane Praza 37811f6eb021SLiane Praza /* 37821f6eb021SLiane Praza * See if there is a pg_pattern for this property group. If it 37831f6eb021SLiane Praza * exists, use it to validate the property group. If there is no 37841f6eb021SLiane Praza * pg_pattern, then there is no validation to do. 37851f6eb021SLiane Praza */ 37861f6eb021SLiane Praza rc = tmpl_find_pg_pattern(e, pg, &pg_pattern); 37871f6eb021SLiane Praza switch (rc) { 37881f6eb021SLiane Praza case TVS_SUCCESS: 37891f6eb021SLiane Praza break; 37901f6eb021SLiane Praza case TVS_BAD_TEMPLATE: 37911f6eb021SLiane Praza CLEAR_ERROR_INFO(&einfo); 37921f6eb021SLiane Praza einfo.ei_type = EIT_BAD_TEMPLATE; 37931f6eb021SLiane Praza einfo.ei_u.ei_bad_template.ei_reason = gettext("Property " 37941f6eb021SLiane Praza "group name too long"); 37951f6eb021SLiane Praza (void) tmpl_errors_add_im(errs, rc, e, NULL, pg, NULL, NULL, 37961f6eb021SLiane Praza NULL, &einfo); 37971f6eb021SLiane Praza return (rc); 37981f6eb021SLiane Praza default: 37991f6eb021SLiane Praza assert(0); 38001f6eb021SLiane Praza abort(); 38011f6eb021SLiane Praza } 38021f6eb021SLiane Praza if (pg_pattern == NULL) 38031f6eb021SLiane Praza return (TVS_SUCCESS); 38041f6eb021SLiane Praza 38051f6eb021SLiane Praza /* 38061f6eb021SLiane Praza * If the pg_pattern declares a type, verify that the PG has the 38071f6eb021SLiane Praza * correct type. 38081f6eb021SLiane Praza */ 38091f6eb021SLiane Praza pg_pattern_type = find_type_specification(pg_pattern); 38101f6eb021SLiane Praza if ((pg_pattern_type != NULL) && 38111f6eb021SLiane Praza (*pg_pattern_type != 0)) { 38121f6eb021SLiane Praza if ((pg->sc_pgroup_type != NULL) && 38131f6eb021SLiane Praza (*(pg->sc_pgroup_type) != 0)) { 38141f6eb021SLiane Praza if (strcmp(pg_pattern_type, 38151f6eb021SLiane Praza pg->sc_pgroup_type) != 0) { 38161f6eb021SLiane Praza rc = TVS_VALIDATION; 38171f6eb021SLiane Praza stat = add_scf_error(errs, 38181f6eb021SLiane Praza SCF_TERR_WRONG_PG_TYPE, pg_pattern, pg, 38191f6eb021SLiane Praza NULL, NULL, NULL, NULL); 38201f6eb021SLiane Praza if (stat != 0) { 38211f6eb021SLiane Praza /* 38221f6eb021SLiane Praza * If we can no longer accumulate 38231f6eb021SLiane Praza * errors, return without trying to 38241f6eb021SLiane Praza * do further validation. 38251f6eb021SLiane Praza */ 38261f6eb021SLiane Praza return (rc); 38271f6eb021SLiane Praza } 38281f6eb021SLiane Praza } 38291f6eb021SLiane Praza } else { 38301f6eb021SLiane Praza rc = TVS_MISSING_PG_TYPE; 38311f6eb021SLiane Praza r = tmpl_errors_add_im(errs, rc, e, pg_pattern, pg, 38321f6eb021SLiane Praza NULL, NULL, NULL, NULL); 38331f6eb021SLiane Praza if (r != TVS_SUCCESS) { 38341f6eb021SLiane Praza /* 38351f6eb021SLiane Praza * If we can no longer accumulate errors, 38361f6eb021SLiane Praza * return without trying to do further 38371f6eb021SLiane Praza * validation. 38381f6eb021SLiane Praza */ 38391f6eb021SLiane Praza return (rc); 38401f6eb021SLiane Praza } 38411f6eb021SLiane Praza } 38421f6eb021SLiane Praza } 38431f6eb021SLiane Praza 38441f6eb021SLiane Praza /* Verify the properties in the property group. */ 38451f6eb021SLiane Praza prop = NULL; 38461f6eb021SLiane Praza while ((prop = next_property(pg, prop)) != NULL) { 38471f6eb021SLiane Praza r = tmpl_find_prop_pattern(e, pg_pattern, prop, &prop_pattern); 38481f6eb021SLiane Praza switch (r) { 38491f6eb021SLiane Praza case TVS_SUCCESS: 38501f6eb021SLiane Praza /* Found match. Validate property. */ 38511f6eb021SLiane Praza break; 38521f6eb021SLiane Praza case TVS_NOMATCH: 38531f6eb021SLiane Praza /* No prop_patern. Go on to next property. */ 38541f6eb021SLiane Praza continue; 38551f6eb021SLiane Praza case TVS_BAD_TEMPLATE: 38561f6eb021SLiane Praza CLEAR_ERROR_INFO(&einfo); 38571f6eb021SLiane Praza einfo.ei_type = EIT_BAD_TEMPLATE; 38581f6eb021SLiane Praza einfo.ei_u.ei_bad_template.ei_reason = 38591f6eb021SLiane Praza gettext("prop_pattern name too long"); 38601f6eb021SLiane Praza (void) tmpl_errors_add_im(errs, r, e, NULL, pg, NULL, 38611f6eb021SLiane Praza NULL, NULL, &einfo); 38621f6eb021SLiane Praza continue; 38631f6eb021SLiane Praza default: 38641f6eb021SLiane Praza assert(0); 38651f6eb021SLiane Praza abort(); 38661f6eb021SLiane Praza } 38671f6eb021SLiane Praza r = tmpl_validate_prop(prop, prop_pattern, pg, pg_pattern, 38681f6eb021SLiane Praza errs); 38691f6eb021SLiane Praza if (r != TVS_SUCCESS) 38701f6eb021SLiane Praza rc = r; 38711f6eb021SLiane Praza } 38721f6eb021SLiane Praza 38731f6eb021SLiane Praza /* 38741f6eb021SLiane Praza * Confirm required properties are present. 38751f6eb021SLiane Praza */ 38761f6eb021SLiane Praza r = tmpl_required_props_present(e, pg, pg_pattern, errs); 38771f6eb021SLiane Praza if (r != TVS_SUCCESS) 38781f6eb021SLiane Praza rc = r; 38791f6eb021SLiane Praza 38801f6eb021SLiane Praza return (rc); 38811f6eb021SLiane Praza } 38821f6eb021SLiane Praza 38831f6eb021SLiane Praza /* 38841f6eb021SLiane Praza * Validate that the property groups in the entity conform to the template 38851f6eb021SLiane Praza * specifications. Specifically, this means do the following: 38861f6eb021SLiane Praza * 38871f6eb021SLiane Praza * - Loop through the property groups in the entity skipping the ones 38881f6eb021SLiane Praza * that are of type "template". 38891f6eb021SLiane Praza * 38901f6eb021SLiane Praza * - For the PG search for the corresponding template_pg_pattern 38911f6eb021SLiane Praza * property group. It is possible that one may not exist. 38921f6eb021SLiane Praza * 38931f6eb021SLiane Praza * - Verify that the PG is in conformance with the pg_pattern 38941f6eb021SLiane Praza * specification if it exists. 38951f6eb021SLiane Praza */ 38961f6eb021SLiane Praza static tmpl_validate_status_t 38971f6eb021SLiane Praza tmpl_validate_entity_pgs(entity_t *e, tmpl_errors_t *errs) 38981f6eb021SLiane Praza { 38991f6eb021SLiane Praza composed_pg_t *cpg; 39001f6eb021SLiane Praza uu_avl_t *pgroups; 39011f6eb021SLiane Praza pgroup_t *pg; 39021f6eb021SLiane Praza tmpl_validate_status_t r; 39031f6eb021SLiane Praza tmpl_validate_status_t rc = TVS_SUCCESS; 39041f6eb021SLiane Praza 39051f6eb021SLiane Praza assert(e->sc_etype == SVCCFG_INSTANCE_OBJECT); 39061f6eb021SLiane Praza 39071f6eb021SLiane Praza pgroups = e->sc_u.sc_instance.sc_composed; 39081f6eb021SLiane Praza for (cpg = uu_avl_first(pgroups); 39091f6eb021SLiane Praza cpg != NULL; 39101f6eb021SLiane Praza cpg = uu_avl_next(pgroups, cpg)) { 39111f6eb021SLiane Praza if (strcmp(cpg->cpg_type, SCF_GROUP_TEMPLATE) == 0) 39121f6eb021SLiane Praza continue; 39131f6eb021SLiane Praza pg = CPG2PG(cpg); 39141f6eb021SLiane Praza if ((r = tmpl_validate_pg(e, pg, errs)) != TVS_SUCCESS) 39151f6eb021SLiane Praza rc = r; 39161f6eb021SLiane Praza } 39171f6eb021SLiane Praza 39181f6eb021SLiane Praza return (rc); 39191f6eb021SLiane Praza } 39201f6eb021SLiane Praza 39211f6eb021SLiane Praza /* 39221f6eb021SLiane Praza * Validate the instance, e, by performing the following checks: 39231f6eb021SLiane Praza * 39241f6eb021SLiane Praza * - Verify template consistency. 39251f6eb021SLiane Praza * 39261f6eb021SLiane Praza * - Validate each property group in the entity is in conformance 39271f6eb021SLiane Praza * with the template specifications. 39281f6eb021SLiane Praza * 39291f6eb021SLiane Praza * - Verify that all required property groups are present in the 39301f6eb021SLiane Praza * entity. 39311f6eb021SLiane Praza */ 39321f6eb021SLiane Praza static tmpl_validate_status_t 39331f6eb021SLiane Praza tmpl_validate_instance(entity_t *e, tmpl_errors_t *errs) 39341f6eb021SLiane Praza { 39351f6eb021SLiane Praza tmpl_validate_status_t r; 39361f6eb021SLiane Praza tmpl_validate_status_t rc = TVS_SUCCESS; 39371f6eb021SLiane Praza int status; 39381f6eb021SLiane Praza tv_errors_t *ste; 39391f6eb021SLiane Praza 39401f6eb021SLiane Praza /* Prepare to collect errors for this instance. */ 39411f6eb021SLiane Praza ste = tv_errors_create(e->sc_fmri); 39421f6eb021SLiane Praza status = uu_list_insert_after(errs->te_scf, errs->te_cur_scf, ste); 39431f6eb021SLiane Praza assert(status == 0); 39441f6eb021SLiane Praza errs->te_cur_scf = ste; 39451f6eb021SLiane Praza 39461f6eb021SLiane Praza /* Verify template consistency */ 39471f6eb021SLiane Praza rc = tmpl_consistency(e, errs); 39481f6eb021SLiane Praza 39491f6eb021SLiane Praza /* Validate the property groups in the entity. */ 39501f6eb021SLiane Praza r = tmpl_validate_entity_pgs(e, errs); 39511f6eb021SLiane Praza if (r != TVS_SUCCESS) 39521f6eb021SLiane Praza rc = r; 39531f6eb021SLiane Praza 39541f6eb021SLiane Praza /* Verify that all required property groups are present. */ 39551f6eb021SLiane Praza r = tmpl_required_pg_present(e, errs); 39561f6eb021SLiane Praza if (r != TVS_SUCCESS) 39571f6eb021SLiane Praza rc = r; 39581f6eb021SLiane Praza 39591f6eb021SLiane Praza return (rc); 39601f6eb021SLiane Praza } 39611f6eb021SLiane Praza 39621f6eb021SLiane Praza /* 39631f6eb021SLiane Praza * First validate the instances of the service. 39641f6eb021SLiane Praza */ 39651f6eb021SLiane Praza static tmpl_validate_status_t 39661f6eb021SLiane Praza tmpl_validate_service(entity_t *svc, tmpl_errors_t *errs) 39671f6eb021SLiane Praza { 39681f6eb021SLiane Praza entity_t *inst; 39691f6eb021SLiane Praza tmpl_validate_status_t r; 39701f6eb021SLiane Praza tmpl_validate_status_t rc = TVS_SUCCESS; 39711f6eb021SLiane Praza 39721f6eb021SLiane Praza assert(svc->sc_etype == SVCCFG_SERVICE_OBJECT); 39731f6eb021SLiane Praza 39741f6eb021SLiane Praza load_general_templates(svc); 39751f6eb021SLiane Praza 39761f6eb021SLiane Praza /* Validate the service's instances. */ 39771f6eb021SLiane Praza for (inst = uu_list_first(svc->sc_u.sc_service.sc_service_instances); 39781f6eb021SLiane Praza inst != NULL; 39791f6eb021SLiane Praza inst = uu_list_next(svc->sc_u.sc_service.sc_service_instances, 39801f6eb021SLiane Praza inst)) { 39811f6eb021SLiane Praza load_instance_restarter(inst); 39821f6eb021SLiane Praza build_composed_instance(inst); 39831f6eb021SLiane Praza r = tmpl_validate_instance(inst, errs); 39841f6eb021SLiane Praza if (r != TVS_SUCCESS) 39851f6eb021SLiane Praza rc = r; 39861f6eb021SLiane Praza demolish_composed_instance(inst); 39871f6eb021SLiane Praza } 39881f6eb021SLiane Praza 39891f6eb021SLiane Praza return (rc); 39901f6eb021SLiane Praza } 39911f6eb021SLiane Praza 39921f6eb021SLiane Praza /* 39931f6eb021SLiane Praza * Validate all services and instances in the bundle against their 39941f6eb021SLiane Praza * templates. If err_list is not NULL, a tmpl_errors structure will be 39951f6eb021SLiane Praza * allocated and its address will be returned to err_list. This structure 39961f6eb021SLiane Praza * can be used to generate error messages. 39971f6eb021SLiane Praza */ 39981f6eb021SLiane Praza tmpl_validate_status_t 39991f6eb021SLiane Praza tmpl_validate_bundle(bundle_t *bndl, tmpl_errors_t **err_list) 40001f6eb021SLiane Praza { 40011f6eb021SLiane Praza tmpl_errors_t *errs = NULL; 40021f6eb021SLiane Praza entity_t *svc; 40031f6eb021SLiane Praza tmpl_validate_status_t r; 40041f6eb021SLiane Praza tmpl_validate_status_t rc = TVS_SUCCESS; 40051f6eb021SLiane Praza 40061f6eb021SLiane Praza if (err_list != NULL) 40071f6eb021SLiane Praza *err_list = NULL; 40081f6eb021SLiane Praza if (bndl->sc_bundle_type != SVCCFG_MANIFEST) { 40091f6eb021SLiane Praza semerr(gettext("Bundle is not a manifest. Unable to validate " 40101f6eb021SLiane Praza "against templates.\n")); 40111f6eb021SLiane Praza return (TVS_FATAL); 40121f6eb021SLiane Praza } 40131f6eb021SLiane Praza 40141f6eb021SLiane Praza errs = tmpl_errors_create(); 40151f6eb021SLiane Praza if (errs == NULL) 40161f6eb021SLiane Praza uu_die(emesg_nomem); 40171f6eb021SLiane Praza 40181f6eb021SLiane Praza lscf_prep_hndl(); /* Initialize g_hndl */ 40191f6eb021SLiane Praza if (load_init() != 0) 40201f6eb021SLiane Praza uu_die(emesg_nomem); 40211f6eb021SLiane Praza 40221f6eb021SLiane Praza /* 40231f6eb021SLiane Praza * We will process all services in the bundle, unless we get a 40241f6eb021SLiane Praza * fatal error. That way we can report all errors on all services 40251f6eb021SLiane Praza * on a single run of svccfg. 40261f6eb021SLiane Praza */ 40271f6eb021SLiane Praza for (svc = uu_list_first(bndl->sc_bundle_services); 40281f6eb021SLiane Praza svc != NULL; 40291f6eb021SLiane Praza svc = uu_list_next(bndl->sc_bundle_services, svc)) { 40301f6eb021SLiane Praza if (svc->sc_etype != SVCCFG_SERVICE_OBJECT) { 40311f6eb021SLiane Praza semerr(gettext("Manifest for %s contains an object " 40321f6eb021SLiane Praza "named \"%s\" that is not a service.\n"), 40331f6eb021SLiane Praza bndl->sc_bundle_name, svc->sc_name); 40341f6eb021SLiane Praza tmpl_errors_destroy(errs); 40351f6eb021SLiane Praza load_fini(); 40361f6eb021SLiane Praza return (TVS_FATAL); 40371f6eb021SLiane Praza } 40381f6eb021SLiane Praza if ((r = tmpl_validate_service(svc, errs)) != TVS_SUCCESS) 40391f6eb021SLiane Praza rc = r; 40401f6eb021SLiane Praza if (r == TVS_FATAL) 40411f6eb021SLiane Praza break; 40421f6eb021SLiane Praza } 40431f6eb021SLiane Praza 40441f6eb021SLiane Praza if (err_list == NULL) { 40451f6eb021SLiane Praza tmpl_errors_destroy(errs); 40461f6eb021SLiane Praza } else { 40471f6eb021SLiane Praza *err_list = errs; 40481f6eb021SLiane Praza } 40491f6eb021SLiane Praza 40501f6eb021SLiane Praza load_fini(); 40511f6eb021SLiane Praza 40521f6eb021SLiane Praza return (rc); 40531f6eb021SLiane Praza } 4054