xref: /titanic_50/usr/src/cmd/svc/svccfg/svccfg_tmpl.c (revision 870ad75a2b67a92c3449d93b4fef8a0baa982b4a)
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
composed_pg_compare(const void * left,const void * right,void * unused)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
composed_prop_compare(const void * left,const void * right,void * unused)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 *
composed_pg_create()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
composed_pg_destroy(composed_pg_t * cpg)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
grow_props_tree(pgroup_t * pg,uu_avl_t * tree)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
compose_props(composed_pg_t * cpg)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
build_composed_property_groups(entity_t * inst,uu_avl_t * tree)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
build_composed_instance(entity_t * inst)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
demolish_composed_instance(entity_t * inst)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
count_prop_values(property_t * prop)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
is_numeric_type(scf_type_t type)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
pgroup_type(pgroup_t * pg)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 *
property_find(pgroup_t * pg,const char * name)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
av_destroy(avalues_t * av)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 *
av_create(size_t count,scf_type_t type)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
av_get_integer(avalues_t * av,uint_t i)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 *
av_get_string(avalues_t * av,uint_t i)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
av_get_unsigned(avalues_t * av,uint_t i)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
av_set_value(avalues_t * av,uint_t i,const char * value)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
av_get_values(pgroup_t * pg,const char * prop_name,scf_type_t type,avalues_t ** values)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 *
find_astring_value_in_pg(pgroup_t * pg,const char * prop_name)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
find_count_value(property_t * prop,uint64_t * count)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 *
find_name_specification(pgroup_t * pattern)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 *
find_type_specification(pgroup_t * pattern)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 *
find_restarter(entity_t * e)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
get_cardinality(pgroup_t * prop_pattern,uint64_t * min,uint64_t * max)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
get_ranges(property_t * range_prop,scf_type_t type,range_t ** ranges,uint_t * count)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 *
tv_errors_create(const char * fmri)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
destroy_scf_errors(tv_errors_t * ste)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
gen_prop_pattern_pg_name(pgroup_t * pg_pattern,const char * prop_name,char ** prop_pattern_pg_name)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
im_perror_item(FILE * out,const char * desc,void * item,scf_type_t type,int * flags)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
im_perror_fmri(FILE * out,im_tmpl_error_t * i,int * flags)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
im_perror_pg_name(FILE * out,im_tmpl_error_t * i,int * flags)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
im_perror_pattern_info(FILE * out,pgroup_t * pattern,int * flags,int srcflag)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
im_perror_template_info(FILE * out,im_tmpl_error_t * i,int * flags)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
im_perror_bad_conversion(FILE * out,im_tmpl_error_t * i,const char * prefix)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
im_perror_bad_template(FILE * out,im_tmpl_error_t * i,const char * prefix)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
im_perror_invalid_type(FILE * out,im_tmpl_error_t * i,const char * prefix)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
im_perror_missing_pg_type(FILE * out,im_tmpl_error_t * i,const char * prefix)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
im_perror_missing_type(FILE * out,im_tmpl_error_t * i,const char * prefix)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
im_tmpl_error_print(FILE * out,im_tmpl_error_t * ite,const char * prefix)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 *
int64_to_str(int64_t i)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 *
uint64_to_str(uint64_t u)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 *
value_to_string(value_t * v)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
add_scf_error(tmpl_errors_t * errs,scf_tmpl_error_type_t ec,pgroup_t * pg_pattern,pgroup_t * pg,pgroup_t * prop_pattern,property_t * prop,value_t * val,error_info_t * einfo)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
tmpl_errors_add_im(tmpl_errors_t * errs,tmpl_validate_status_t ec,entity_t * e,pgroup_t * pg_pattern,pgroup_t * pg,pgroup_t * prop_pattern,property_t * prop,value_t * val,error_info_t * einfo)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
is_required(pgroup_t * pattern)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
load_general_templates(entity_t * svc)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
load_instance_restarter(entity_t * i)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 *
next_property(pgroup_t * pg,property_t * current)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 *
ptrn_info_create(pgroup_t * pat)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
ptrn_info_destroy(ptrn_info_t * info)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
gather_pattern(entity_t * e,ptrn_type_t type,uu_avl_t * tree,tmpl_errors_t * errs)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
pg_iter_destroy(pg_iter_t * i)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 *
pg_iter_create(entity_t * e,const char * restriction)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 *
next_pattern_pg(pg_iter_t * i)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
ptrn_info_compare(const void * left,const void * right,void * unused)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
target_check(const char * target,tmpl_level_t level)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
pg_target_check(pgroup_t * pg_pattern,tmpl_level_t level)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
prop_pattern_type(pgroup_t * pattern,scf_type_t * type)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
property_is_type(property_t * prop,scf_type_t type)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 *
gen_pg_pattern_pg_name(const char * name,const char * type)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
include_values_support(ptrn_info_t * pinfo,const char * type,tmpl_errors_t * errs)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
tmpl_include_values_check(uu_avl_t * tree,tmpl_errors_t * errs)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
tmpl_pattern_conflict(entity_t * inst,uu_avl_t * tree,ptrn_type_t type,tmpl_errors_t * errs)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
tmpl_required_attr_present(uu_avl_t * tree,tmpl_errors_t * errs)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
tmpl_scan_general(entity_t * general,uu_avl_t * tree,tmpl_level_t level,tmpl_errors_t * errs)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
tmpl_level_redefine(entity_t * inst,uu_avl_t * tree,tmpl_errors_t * errs)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
tmpl_consistency(entity_t * inst,tmpl_errors_t * errs)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
tmpl_errors_destroy(tmpl_errors_t * te)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 *
tmpl_errors_create()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
tmpl_errors_print(FILE * out,tmpl_errors_t * errs,const char * prefix)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
tmpl_find_prop_pattern(entity_t * inst,pgroup_t * pg_pattern,property_t * prop,pgroup_t ** prop_pattern)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
tmpl_find_pg_pattern(entity_t * e,pgroup_t * pg,pgroup_t ** pgp)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
tmpl_init(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
tmpl_property_fini(property_t * p)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
tmpl_property_init(property_t * p)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
tmpl_validate_cardinality(pgroup_t * prop_pattern,property_t * prop,pgroup_t * pg,pgroup_t * pg_pattern,tmpl_errors_t * errs)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
tmpl_required_pg_present(entity_t * e,tmpl_errors_t * errs)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
tmpl_required_props_present(entity_t * e,pgroup_t * pg,pgroup_t * pg_pattern,tmpl_errors_t * errs)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
value_in_range(value_t * v,scf_type_t type,range_t * r,size_t count)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
tmpl_validate_value_range(pgroup_t * pattern,property_t * prop,pgroup_t * pg,pgroup_t * pg_pattern,tmpl_errors_t * errs)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
tmpl_validate_values(pgroup_t * prop_pattern,property_t * prop,pgroup_t * pg,pgroup_t * pg_pattern,tmpl_errors_t * errs)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
tmpl_validate_value_constraints(pgroup_t * pattern,property_t * prop,pgroup_t * pg,pgroup_t * pg_pattern,tmpl_errors_t * errs)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
tmpl_validate_prop(property_t * prop,pgroup_t * tmpl,pgroup_t * pg,pgroup_t * pg_pattern,tmpl_errors_t * errs)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
tmpl_validate_pg(entity_t * e,pgroup_t * pg,tmpl_errors_t * errs)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
tmpl_validate_entity_pgs(entity_t * e,tmpl_errors_t * errs)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
tmpl_validate_instance(entity_t * e,tmpl_errors_t * errs)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
tmpl_validate_service(entity_t * svc,tmpl_errors_t * errs)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
tmpl_validate_bundle(bundle_t * bndl,tmpl_errors_t ** err_list)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