xref: /onnv-gate/usr/src/cmd/svc/svccfg/svccfg_tmpl.c (revision 9765:2522fef20c5f)
17887SLiane.Praza@Sun.COM /*
27887SLiane.Praza@Sun.COM  * CDDL HEADER START
37887SLiane.Praza@Sun.COM  *
47887SLiane.Praza@Sun.COM  * The contents of this file are subject to the terms of the
57887SLiane.Praza@Sun.COM  * Common Development and Distribution License (the "License").
67887SLiane.Praza@Sun.COM  * You may not use this file except in compliance with the License.
77887SLiane.Praza@Sun.COM  *
87887SLiane.Praza@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97887SLiane.Praza@Sun.COM  * or http://www.opensolaris.org/os/licensing.
107887SLiane.Praza@Sun.COM  * See the License for the specific language governing permissions
117887SLiane.Praza@Sun.COM  * and limitations under the License.
127887SLiane.Praza@Sun.COM  *
137887SLiane.Praza@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
147887SLiane.Praza@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157887SLiane.Praza@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
167887SLiane.Praza@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
177887SLiane.Praza@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
187887SLiane.Praza@Sun.COM  *
197887SLiane.Praza@Sun.COM  * CDDL HEADER END
207887SLiane.Praza@Sun.COM  */
217887SLiane.Praza@Sun.COM 
227887SLiane.Praza@Sun.COM /*
23*9765SSean.Wilcox@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
247887SLiane.Praza@Sun.COM  * Use is subject to license terms.
257887SLiane.Praza@Sun.COM  */
267887SLiane.Praza@Sun.COM 
277887SLiane.Praza@Sun.COM /*
287887SLiane.Praza@Sun.COM  * This file provides the code that allows svccfg(1M) to validate a
297887SLiane.Praza@Sun.COM  * manifest against the template specifications.  svccfg uses the
307887SLiane.Praza@Sun.COM  * validation facilities for the import and validate subcommands.
317887SLiane.Praza@Sun.COM  *
327887SLiane.Praza@Sun.COM  * There are three entry points -- tmpl_validate_bundle(),
337887SLiane.Praza@Sun.COM  * tmpl_errors_print() and tmpl_errors_destroy().  svccfg calls
347887SLiane.Praza@Sun.COM  * tmpl_validate_bundle() to validate a bundle.  tmpl_validate_bundle()
357887SLiane.Praza@Sun.COM  * returns a pointer to a tmpl_errors_t.  This is a pointer to information
367887SLiane.Praza@Sun.COM  * about any validation errors that were found.  If an error was detected,
377887SLiane.Praza@Sun.COM  * svccfg calls tmpl_errors_print() to print the error information.  Once
387887SLiane.Praza@Sun.COM  * the error information is printed, svccfg calls tmpl_errors_destroy() to
397887SLiane.Praza@Sun.COM  * free the memory associated with the tmpl_errors_t.
407887SLiane.Praza@Sun.COM  *
417887SLiane.Praza@Sun.COM  * libscf's scf_tmpl.c performs similar checks to the ones described in
427887SLiane.Praza@Sun.COM  * this paragraph.  Any changes to the algorithms in this file should also
437887SLiane.Praza@Sun.COM  * be infcorporated into scf_tmpl.c.  The reason that there are two bodies
447887SLiane.Praza@Sun.COM  * of code is that they work on different data structures.
457887SLiane.Praza@Sun.COM  * tmpl_validate_bundle() validates each instance of each service in the
467887SLiane.Praza@Sun.COM  * bundle.  The following checks are performed on each instance:
477887SLiane.Praza@Sun.COM  *
487887SLiane.Praza@Sun.COM  *	1.  Verify template consistency.
497887SLiane.Praza@Sun.COM  *	    A.  No conflicting definitions of "pg_pattern" are allowed
507887SLiane.Praza@Sun.COM  *		within a single instance.
517887SLiane.Praza@Sun.COM  *	    B.  Templates at a narrow target (e.g. instance) which define
527887SLiane.Praza@Sun.COM  *		property groups already templated at a broad target
537887SLiane.Praza@Sun.COM  *		(e.g. delegate or all) are strongly discouraged.
547887SLiane.Praza@Sun.COM  *	    C.  Developers may not define a template which specifies a
557887SLiane.Praza@Sun.COM  *		single prop_pattern name with differing types on the same
567887SLiane.Praza@Sun.COM  *		target entity.
577887SLiane.Praza@Sun.COM  *	    D.  If a pg_pattern has a required attribute with a value of
587887SLiane.Praza@Sun.COM  *		true, then its name and type attributes must be
597887SLiane.Praza@Sun.COM  *		specified.
607887SLiane.Praza@Sun.COM  *	    E.  If a prop_pattern has a required attribute with a value
617887SLiane.Praza@Sun.COM  *		of true, then its type attribute must be specified.
627887SLiane.Praza@Sun.COM  *	    F.  If a prop_pattern has an include_values element make sure
637887SLiane.Praza@Sun.COM  *		that the appropriate constraints or values element has
647887SLiane.Praza@Sun.COM  *		also been declared.
657887SLiane.Praza@Sun.COM  *	2.  Validate that each property group in the instance is in
667887SLiane.Praza@Sun.COM  *	    conformance with the template specifications.
677887SLiane.Praza@Sun.COM  *	    A.  Verify that the types of the PG and the pg_pattern are
687887SLiane.Praza@Sun.COM  *		compatible.
697887SLiane.Praza@Sun.COM  *	    B.  Verify properties of the PG against the prop_patterns in
707887SLiane.Praza@Sun.COM  *		the template.
717887SLiane.Praza@Sun.COM  *		o Verify property's type.
727887SLiane.Praza@Sun.COM  *		o Verify cardinality.
737887SLiane.Praza@Sun.COM  *		o Vefiy that property values satisfy the constraints
747887SLiane.Praza@Sun.COM  *		  imposed by the prop_pattern.
757887SLiane.Praza@Sun.COM  *	    C.  Verify that required properties are present.
767887SLiane.Praza@Sun.COM  *	3.  Verify that all required property groups are present in the
777887SLiane.Praza@Sun.COM  *	    insance.
787887SLiane.Praza@Sun.COM  *
797887SLiane.Praza@Sun.COM  * tmpl_validate_bundle() is called after svccfg has processed the manifest
807887SLiane.Praza@Sun.COM  * file.  The manifest is represented in memory by a set of entity_t,
817887SLiane.Praza@Sun.COM  * pgroup_t, property_t and value_t structures.  These structures are
827887SLiane.Praza@Sun.COM  * defined in svccfg.h.
837887SLiane.Praza@Sun.COM  *
847887SLiane.Praza@Sun.COM  * tmpl_validate_bundle() calls tmpl_validate_service() for each service in
857887SLiane.Praza@Sun.COM  * the bundle, and tmpl_validate_service() then calls
867887SLiane.Praza@Sun.COM  * tmpl_validate_instance() for each instance in the service.
877887SLiane.Praza@Sun.COM  * tmpl_validate_instance() is the function that does the real work of
887887SLiane.Praza@Sun.COM  * validation against the template specification.
897887SLiane.Praza@Sun.COM  *
907887SLiane.Praza@Sun.COM  * Subsystems:
917887SLiane.Praza@Sun.COM  * ==========
927887SLiane.Praza@Sun.COM  *
937887SLiane.Praza@Sun.COM  * General Templates:
947887SLiane.Praza@Sun.COM  * -----------------
957887SLiane.Praza@Sun.COM  * In order to perform the validation specified by 1.B above, we need to
967887SLiane.Praza@Sun.COM  * load the templates specifications for the global service and the
977887SLiane.Praza@Sun.COM  * instance's restarter.  This information is loaded from the repository
987887SLiane.Praza@Sun.COM  * and it is held in memory using the entity_t, pgroup_t, property_t and
997887SLiane.Praza@Sun.COM  * value_t hierarchy of structures.  When a service is processed,
1007887SLiane.Praza@Sun.COM  * load_general_templates() is called to load the information for the
1017887SLiane.Praza@Sun.COM  * global service and restarter that is declared at the service level.  The
1027887SLiane.Praza@Sun.COM  * sc_service.sc_global and sc_service.sc_restarter members of the
1037887SLiane.Praza@Sun.COM  * service's entity_t point to the information for the global and restarter
1047887SLiane.Praza@Sun.COM  * services.
1057887SLiane.Praza@Sun.COM  *
1067887SLiane.Praza@Sun.COM  * The instance portion of a manifest can declare an instance specific
1077887SLiane.Praza@Sun.COM  * restarter.  If this is the case, load_instance_restarter() will load the
1087887SLiane.Praza@Sun.COM  * information for that restarter, and it is saved in the
1097887SLiane.Praza@Sun.COM  * sc_instance.sc_instance_restarter member of the entity_t that represents
1107887SLiane.Praza@Sun.COM  * the instance.
1117887SLiane.Praza@Sun.COM  *
1127887SLiane.Praza@Sun.COM  * Composed Properties:
1137887SLiane.Praza@Sun.COM  * -------------------
1147887SLiane.Praza@Sun.COM  * We need the ability to process the composed properties of an instance.
1157887SLiane.Praza@Sun.COM  * That is to say if an instance defines a property, it overrides any
1167887SLiane.Praza@Sun.COM  * definition in the service.  Otherwise, the service's definition is
1177887SLiane.Praza@Sun.COM  * inherited in the instance.
1187887SLiane.Praza@Sun.COM  *
1197887SLiane.Praza@Sun.COM  * In an entity_t, the sc_instance.sc_composed member points to a
1207887SLiane.Praza@Sun.COM  * uu_avl tree of composed property groups (composed_pg_t) for the
1217887SLiane.Praza@Sun.COM  * instance.  The composed_pg_t has two members, cpg_instance_pg and
1227887SLiane.Praza@Sun.COM  * cpg_service_pg, that point to the instance and service property group
1237887SLiane.Praza@Sun.COM  * definitions respectively.  Either of these may be NULL indicating that
1247887SLiane.Praza@Sun.COM  * only an instance or service definition exists in the manifest.
1257887SLiane.Praza@Sun.COM  *
1267887SLiane.Praza@Sun.COM  * In the case where both the instance and the service define a property
1277887SLiane.Praza@Sun.COM  * group, the properties must be composed.  This is done by
1287887SLiane.Praza@Sun.COM  * compose_props().  The compose_pg_t holds the composed properties in a
1297887SLiane.Praza@Sun.COM  * uu_avl_tree at cpf_compose_props.  This is a tree of property_t
1307887SLiane.Praza@Sun.COM  * structures.  If a property is defined in both the instance and service
1317887SLiane.Praza@Sun.COM  * property group, the tree will hold the instance definition.  If the
1327887SLiane.Praza@Sun.COM  * property is defined at only one level, the tree will hold the property_t
1337887SLiane.Praza@Sun.COM  * for that level.  Thus, the tree is truly a set of composed properties of
1347887SLiane.Praza@Sun.COM  * the property group.
1357887SLiane.Praza@Sun.COM  *
1367887SLiane.Praza@Sun.COM  * Property Group Iteration:
1377887SLiane.Praza@Sun.COM  * ------------------------
1387887SLiane.Praza@Sun.COM  * A number of functions must iterate through an instance's property groups
1397887SLiane.Praza@Sun.COM  * looking for the ones that define a pg_pattern or a prop_pattern.  To be
1407887SLiane.Praza@Sun.COM  * specific, the iteration starts with the composed view of the instance.
1417887SLiane.Praza@Sun.COM  * It then proceeds through the restarter information and finally moves on
1427887SLiane.Praza@Sun.COM  * to the global service.  The pg_iter_t structure holds the information
1437887SLiane.Praza@Sun.COM  * that is needed to implement this type of iteration.  pg_iter_create()
1447887SLiane.Praza@Sun.COM  * creates one of these iterators, and pg_iter_destroy() frees the memory
1457887SLiane.Praza@Sun.COM  * associated with the pg_iter_t.  next_pattern_pg(), is used to step
1467887SLiane.Praza@Sun.COM  * through the iteration.
1477887SLiane.Praza@Sun.COM  *
1487887SLiane.Praza@Sun.COM  * Error Reporting:
1497887SLiane.Praza@Sun.COM  * ---------------
1507887SLiane.Praza@Sun.COM  * While performing the templates validation checks, svccfg collects
1517887SLiane.Praza@Sun.COM  * information for all the errors that it finds.  Because of this you will
1527887SLiane.Praza@Sun.COM  * see many places in the code where a loop is not exited when an error is
1537887SLiane.Praza@Sun.COM  * encountered.  We note that fact that an error has occurred, but continue
1547887SLiane.Praza@Sun.COM  * in the loop to see if there are more validation errors.  The error code
1557887SLiane.Praza@Sun.COM  * of the last error that is encountered is returned.  This works, because
1567887SLiane.Praza@Sun.COM  * the callers of tmpl_validate_bundle() only look to see whether or not
1577887SLiane.Praza@Sun.COM  * the return code is TVS_SUCCESS.
1587887SLiane.Praza@Sun.COM  *
1597887SLiane.Praza@Sun.COM  * The information for reporting the errors is collected in a tmpl_errors_t
1607887SLiane.Praza@Sun.COM  * structure, and tmpl_validate_bundle() returns the address of this
1617887SLiane.Praza@Sun.COM  * structure.  The caller of tmpl_validate_bundle() can then call
1627887SLiane.Praza@Sun.COM  * tmpl_errors_print() to display the error information to the user.
1637887SLiane.Praza@Sun.COM  *
1647887SLiane.Praza@Sun.COM  * There are two categories of errors.  Some errors are seen when
1657887SLiane.Praza@Sun.COM  * processing the information in the manifest.  This type of error is only
1667887SLiane.Praza@Sun.COM  * seen by svccfg when it is importing or validating a manifest.  The other
1677887SLiane.Praza@Sun.COM  * type of error consists of template validation errors.  These errors can
1687887SLiane.Praza@Sun.COM  * be seen when processing a manifest or when performing a templates
1697887SLiane.Praza@Sun.COM  * validation of the information associated with an FMRI in the the
1707887SLiane.Praza@Sun.COM  * repository.  tmpl_errors_add_im() is used to capture error information
1717887SLiane.Praza@Sun.COM  * about the first type of error, and add_scf_error() is used to capture
1727887SLiane.Praza@Sun.COM  * error information about the second type of error.
1737887SLiane.Praza@Sun.COM  *
1747887SLiane.Praza@Sun.COM  * The distinction is important when printing the error information.  The
1757887SLiane.Praza@Sun.COM  * fuctions for printing the first type of error reside in this file, since
1767887SLiane.Praza@Sun.COM  * these errors will only be seen by the functions in this file.  The
1777887SLiane.Praza@Sun.COM  * functions for printing the template validation errors reside in libscf,
1787887SLiane.Praza@Sun.COM  * because these errors are of a more general nature.
1797887SLiane.Praza@Sun.COM  *
1807887SLiane.Praza@Sun.COM  * Thus, tmpl_errors_t has two lists -- one for each type of error.
1817887SLiane.Praza@Sun.COM  * te_list is a list of im_tmpl_error_t structures that represent the first
1827887SLiane.Praza@Sun.COM  * type of error.  te_scf is a list of tv_errors_t structures that hold
1837887SLiane.Praza@Sun.COM  * information about general template validation errors.
1847887SLiane.Praza@Sun.COM  * tmpl_errors_print() processes both lists to print information about all
1857887SLiane.Praza@Sun.COM  * errors.  In tmpl_errors_print() im_tmpl_error_print() is used to print
1867887SLiane.Praza@Sun.COM  * the errors that are specific to this file.  scf_tmpl_strerror() provides
1877887SLiane.Praza@Sun.COM  * the errors messages for general templates errors.
1887887SLiane.Praza@Sun.COM  *
1897887SLiane.Praza@Sun.COM  * As was mentioned in the previous paragraph, im_tmpl_error_print() is
1907887SLiane.Praza@Sun.COM  * responsible for printing the errors that are specific to this file.
1917887SLiane.Praza@Sun.COM  * Based on the error code, it dispatches to one of
1927887SLiane.Praza@Sun.COM  * im_perror_bad_conversion(), im_perror_bad_template(),
1937887SLiane.Praza@Sun.COM  * im_perror_invalid_type(), im_perror_missing_pg_type() or
1947887SLiane.Praza@Sun.COM  * im_perror_missing_type().  The rest of the im_perror_* functions provide
1957887SLiane.Praza@Sun.COM  * services to these error specific functions by printing common
1967887SLiane.Praza@Sun.COM  * information.
1977887SLiane.Praza@Sun.COM  *
1987887SLiane.Praza@Sun.COM  * im_perror_item() is the heart of this message printing subsystem.  It is
1997887SLiane.Praza@Sun.COM  * called directly or indirectly by all of the other im_perror_* functions.
2007887SLiane.Praza@Sun.COM  * im_perror_item() prints a single item of error information.  If svccfg
2017887SLiane.Praza@Sun.COM  * is running in interactive mode, im_perror_item() prints each item on a
2027887SLiane.Praza@Sun.COM  * single line, so that they are readable by a human.  In non-interactive
2037887SLiane.Praza@Sun.COM  * mode, all items are printed on a single line separated by semi-colons.
2047887SLiane.Praza@Sun.COM  */
2057887SLiane.Praza@Sun.COM 
2067887SLiane.Praza@Sun.COM #include <assert.h>
2077887SLiane.Praza@Sun.COM #include <errno.h>
2087887SLiane.Praza@Sun.COM #include <inttypes.h>
2097887SLiane.Praza@Sun.COM #include <libintl.h>
2107887SLiane.Praza@Sun.COM #include <limits.h>
2117887SLiane.Praza@Sun.COM #include <libscf.h>
2127887SLiane.Praza@Sun.COM #include <libscf_priv.h>
2137887SLiane.Praza@Sun.COM #include <stdio.h>
2147887SLiane.Praza@Sun.COM #include <stdlib.h>
2157887SLiane.Praza@Sun.COM #include <strings.h>
2167887SLiane.Praza@Sun.COM #include "svccfg.h"
2177887SLiane.Praza@Sun.COM 
2187887SLiane.Praza@Sun.COM /*
2197887SLiane.Praza@Sun.COM  * Clear error_info_t structure.
2207887SLiane.Praza@Sun.COM  */
2217887SLiane.Praza@Sun.COM #define	CLEAR_ERROR_INFO(ei)	((void) memset((ei), 0, sizeof (error_info_t)))
2227887SLiane.Praza@Sun.COM 
2237887SLiane.Praza@Sun.COM /*
2247887SLiane.Praza@Sun.COM  * Retrieve the property group pointer from the composed_pg structure.
2257887SLiane.Praza@Sun.COM  */
2267887SLiane.Praza@Sun.COM #define	CPG2PG(cpg)	(cpg->cpg_instance_pg ? cpg->cpg_instance_pg : \
2277887SLiane.Praza@Sun.COM 			    cpg->cpg_service_pg)
2287887SLiane.Praza@Sun.COM 
2297887SLiane.Praza@Sun.COM /*
2307887SLiane.Praza@Sun.COM  * Convert a pointer to an empty string into a NULL pointer.
2317887SLiane.Praza@Sun.COM  */
2327887SLiane.Praza@Sun.COM #define	EMPTY_TO_NULL(p) (((p) && (*(p) == 0)) ? NULL : (p))
2337887SLiane.Praza@Sun.COM 
2347887SLiane.Praza@Sun.COM /* uu_avl and uu_list debugging bits. */
2357887SLiane.Praza@Sun.COM #ifdef	NDEBUG
2367887SLiane.Praza@Sun.COM #define	TMPL_DEBUG_AVL_POOL	UU_DEFAULT
2377887SLiane.Praza@Sun.COM #define	TMPL_DEBUG_LIST		UU_DEFAULT
2387887SLiane.Praza@Sun.COM #define	TMPL_DEBUG_LIST_POOL	UU_DEFAULT
2397887SLiane.Praza@Sun.COM #define	TMPL_DEBUG_TREE		UU_DEFAULT
2407887SLiane.Praza@Sun.COM #else
2417887SLiane.Praza@Sun.COM #define	TMPL_DEBUG_AVL_POOL	UU_AVL_POOL_DEBUG
2427887SLiane.Praza@Sun.COM #define	TMPL_DEBUG_LIST		UU_LIST_DEBUG
2437887SLiane.Praza@Sun.COM #define	TMPL_DEBUG_LIST_POOL	UU_LIST_POOL_DEBUG
2447887SLiane.Praza@Sun.COM #define	TMPL_DEBUG_TREE		UU_AVL_DEBUG
2457887SLiane.Praza@Sun.COM #endif	/* NDEBUG */
2467887SLiane.Praza@Sun.COM 
2477887SLiane.Praza@Sun.COM /*
2487887SLiane.Praza@Sun.COM  * Structures and enums that are used in producing error messages:
2497887SLiane.Praza@Sun.COM  *
2507887SLiane.Praza@Sun.COM  * error_info_t is used to pass information about an error to
2517887SLiane.Praza@Sun.COM  * tmpl_errors_add_im() and add_scf_error().  tmpl_errors_add_im() collects
2527887SLiane.Praza@Sun.COM  * the error information and stores it in an im_tmpl_error_t.  The
2537887SLiane.Praza@Sun.COM  * im_tmpl_error_t is linked into the tmpl_errors_t, so that the captured
2547887SLiane.Praza@Sun.COM  * information can be used later when error messages are printed.
2557887SLiane.Praza@Sun.COM  *
2567887SLiane.Praza@Sun.COM  * tv_errors_t is used to keep track of error information for general
2577887SLiane.Praza@Sun.COM  * template errors that are known by libscf.  add_scf_error() captures the
2587887SLiane.Praza@Sun.COM  * error information for use in this structure.
2597887SLiane.Praza@Sun.COM  */
2607887SLiane.Praza@Sun.COM /*
2617887SLiane.Praza@Sun.COM  * enum to designate the type of data that is held in a err_info structure.
2627887SLiane.Praza@Sun.COM  */
2637887SLiane.Praza@Sun.COM typedef enum err_info_type {
2647887SLiane.Praza@Sun.COM 	EIT_NONE,		/* No values in the structure */
2657887SLiane.Praza@Sun.COM 	EIT_BAD_TEMPLATE,	/* Reason that template is bad */
2667887SLiane.Praza@Sun.COM 	EIT_CARDINALITY,	/* Ranges for property cardinality */
2677887SLiane.Praza@Sun.COM 	EIT_INCLUDE_VALUES,	/* include_values type attribute */
2687887SLiane.Praza@Sun.COM 	EIT_MISSING_PG,		/* Name of missing pg */
2697887SLiane.Praza@Sun.COM 	EIT_MISSING_PROP,	/* Name of missing property */
2707887SLiane.Praza@Sun.COM 	EIT_PATTERN_CONFLICT, 	/* Conflicting pattern definition */
2717887SLiane.Praza@Sun.COM 	EIT_PROP_TYPE,		/* Value with invalid type */
2727887SLiane.Praza@Sun.COM 	EIT_RANGE		/* Value that is out of range */
2737887SLiane.Praza@Sun.COM } err_info_type_t;
2747887SLiane.Praza@Sun.COM 
2757887SLiane.Praza@Sun.COM /*
2767887SLiane.Praza@Sun.COM  * Structure to hold information that will be used in generating error
2777887SLiane.Praza@Sun.COM  * messages.
2787887SLiane.Praza@Sun.COM  */
2797887SLiane.Praza@Sun.COM typedef struct error_info {
2807887SLiane.Praza@Sun.COM 	err_info_type_t	ei_type;	/* Type of information stored here */
2817887SLiane.Praza@Sun.COM 	union {
2827887SLiane.Praza@Sun.COM 		/* EIT_BAD_TEMPLATE */
2837887SLiane.Praza@Sun.COM 		struct {
2847887SLiane.Praza@Sun.COM 			const char	*ei_reason;
2857887SLiane.Praza@Sun.COM 		} ei_bad_template;
2867887SLiane.Praza@Sun.COM 		/* EIT_CARDINALITY */
2877887SLiane.Praza@Sun.COM 		struct {
2887887SLiane.Praza@Sun.COM 			uint64_t	ei_min;
2897887SLiane.Praza@Sun.COM 			uint64_t	ei_max;
2907887SLiane.Praza@Sun.COM 			uint64_t	ei_count; /* Number of prop values */
2917887SLiane.Praza@Sun.COM 		} ei_cardinality;
2927887SLiane.Praza@Sun.COM 		/* EIT_INCLUDE_VALUES */
2937887SLiane.Praza@Sun.COM 		struct {
2947887SLiane.Praza@Sun.COM 			const char	*ei_type;
2957887SLiane.Praza@Sun.COM 		} ei_inc_values;
2967887SLiane.Praza@Sun.COM 		/* EIT_MISSING_PG */
2977887SLiane.Praza@Sun.COM 		struct {
2987887SLiane.Praza@Sun.COM 			const char	*ei_pg_name;	/* Name of missing pg */
2997887SLiane.Praza@Sun.COM 			const char	*ei_pg_type;	/* Type of missing pg */
3007887SLiane.Praza@Sun.COM 		} ei_missing_pg;
3017887SLiane.Praza@Sun.COM 		/* EIT_MISSING_PROP */
3027887SLiane.Praza@Sun.COM 		struct {
3037887SLiane.Praza@Sun.COM 			const char	*ei_prop_name; /* Name of prop */
3047887SLiane.Praza@Sun.COM 		} ei_missing_prop;
3057887SLiane.Praza@Sun.COM 		/* EIT_PATTERN_CONFLICT */
3067887SLiane.Praza@Sun.COM 		struct {
3077887SLiane.Praza@Sun.COM 			pgroup_t	*ei_pattern; /* Conficting pattern */
3087887SLiane.Praza@Sun.COM 		} ei_pattern_conflict;
3097887SLiane.Praza@Sun.COM 		/* EIT_PROP_TYPE */
3107887SLiane.Praza@Sun.COM 		struct {
3117887SLiane.Praza@Sun.COM 			scf_type_t	ei_actual;
3127887SLiane.Praza@Sun.COM 			scf_type_t	ei_specified;
3137887SLiane.Praza@Sun.COM 		} ei_prop_type;
3147887SLiane.Praza@Sun.COM 		/* EIT_RANGE */
3157887SLiane.Praza@Sun.COM 		struct {
3167887SLiane.Praza@Sun.COM 			scf_type_t	ei_rtype;
3177887SLiane.Praza@Sun.COM 			int64_t		ei_ivalue;
3187887SLiane.Praza@Sun.COM 			uint64_t	ei_uvalue;
3197887SLiane.Praza@Sun.COM 		} ei_range;
3207887SLiane.Praza@Sun.COM 	} ei_u;
3217887SLiane.Praza@Sun.COM } error_info_t;
3227887SLiane.Praza@Sun.COM 
3237887SLiane.Praza@Sun.COM /*
3247887SLiane.Praza@Sun.COM  * Structure with information about a template violation.  This structure
3257887SLiane.Praza@Sun.COM  * is for use with in memory representations of the manifest and template.
3267887SLiane.Praza@Sun.COM  * See scf_tmpl_error_t for use with repository representations.  Some of
3277887SLiane.Praza@Sun.COM  * the pointers may be NULL for some types of errors.
3287887SLiane.Praza@Sun.COM  */
3297887SLiane.Praza@Sun.COM typedef struct im_tmpl_error {
3307887SLiane.Praza@Sun.COM 	tmpl_validate_status_t ite_type; /* Type of error */
3317887SLiane.Praza@Sun.COM 	entity_t	*ite_entity;	/* Instance or service */
3327887SLiane.Praza@Sun.COM 	pgroup_t	*ite_pg;	/* Non-conforming prop. group */
3337887SLiane.Praza@Sun.COM 	pgroup_t	*ite_pg_pattern; /* Violated pg_pattern */
3347887SLiane.Praza@Sun.COM 	property_t	*ite_prop;	/* Non-conforming property */
3357887SLiane.Praza@Sun.COM 	pgroup_t	*ite_prop_pattern; /* Violated prop_pattern */
3367887SLiane.Praza@Sun.COM 	value_t		*ite_value;	/* Non-conforming value */
3377887SLiane.Praza@Sun.COM 	error_info_t	ite_einfo;	/* Extra error information */
3387887SLiane.Praza@Sun.COM 	uu_list_node_t	ite_node;	/* Node to link us in a list. */
3397887SLiane.Praza@Sun.COM } im_tmpl_error_t;
3407887SLiane.Praza@Sun.COM 
3417887SLiane.Praza@Sun.COM /*
3427887SLiane.Praza@Sun.COM  * This structure holds the data that will be used by scf_tmpl_strerror()
3437887SLiane.Praza@Sun.COM  * for printing template validation errors.
3447887SLiane.Praza@Sun.COM  */
3457887SLiane.Praza@Sun.COM typedef struct tv_errors {
3467887SLiane.Praza@Sun.COM 	scf_tmpl_errors_t *tve_errors;	/* Errors for scf_tmpl_strerror() */
3477887SLiane.Praza@Sun.COM 	uu_list_node_t	tve_node;	/* Linkage in a list. */
3487887SLiane.Praza@Sun.COM } tv_errors_t;
3497887SLiane.Praza@Sun.COM 
3507887SLiane.Praza@Sun.COM /*
3517887SLiane.Praza@Sun.COM  * Structure to collect template validation errors.
3527887SLiane.Praza@Sun.COM  */
3537887SLiane.Praza@Sun.COM struct tmpl_errors {
3547887SLiane.Praza@Sun.COM 	uu_list_t	*te_list;	/* List of im_tmpl_error_t */
3557887SLiane.Praza@Sun.COM 	im_tmpl_error_t *te_next;	/* Next error to present */
3567887SLiane.Praza@Sun.COM 	uu_list_t	*te_scf;	/* Errors for scf_tmpl_strerror() */
3577887SLiane.Praza@Sun.COM 	tv_errors_t	*te_cur_scf;	/* Current member of te_scf */
3587887SLiane.Praza@Sun.COM };
3597887SLiane.Praza@Sun.COM 
3607887SLiane.Praza@Sun.COM /* End of structures used in error processing. */
3617887SLiane.Praza@Sun.COM 
3627887SLiane.Praza@Sun.COM /*
3637887SLiane.Praza@Sun.COM  * Property group types that are of interest to us.  See pgroup_type().
3647887SLiane.Praza@Sun.COM  */
3657887SLiane.Praza@Sun.COM typedef enum pg_type {
3667887SLiane.Praza@Sun.COM 	NORMAL_PG,
3677887SLiane.Praza@Sun.COM 	PG_PATTERN_PG,
3687887SLiane.Praza@Sun.COM 	PROP_PATTERN_PG
3697887SLiane.Praza@Sun.COM } pg_type_t;
3707887SLiane.Praza@Sun.COM 
3717887SLiane.Praza@Sun.COM /*
3727887SLiane.Praza@Sun.COM  * Structure to keep track of a set of ASTRING property values for a
3737887SLiane.Praza@Sun.COM  * property.  The consumer may wish to have the ASTRING property values
3747887SLiane.Praza@Sun.COM  * converted to a numeric form which is the reason for the av_v union.
3757887SLiane.Praza@Sun.COM  * This structure is returned by av_get_values() and is accessed by
3767887SLiane.Praza@Sun.COM  * av_get_integer(), av_get_string() and av_get_unsigned().
3777887SLiane.Praza@Sun.COM  */
3787887SLiane.Praza@Sun.COM typedef struct avalues {
3797887SLiane.Praza@Sun.COM 	uint_t		av_count;	/* Number of values */
3807887SLiane.Praza@Sun.COM 	scf_type_t	av_type;	/* Type of value representation */
3817887SLiane.Praza@Sun.COM 	union {
3827887SLiane.Praza@Sun.COM 		uint64_t	*av_unsigned;	/* Count & boolean values */
3837887SLiane.Praza@Sun.COM 		int64_t		*av_integer;	/* Integer values */
3847887SLiane.Praza@Sun.COM 		const char 	**av_string;	/* String values */
3857887SLiane.Praza@Sun.COM 	} av_v;				/* Container for the values */
3867887SLiane.Praza@Sun.COM } avalues_t;
3877887SLiane.Praza@Sun.COM 
3887887SLiane.Praza@Sun.COM /*
3897887SLiane.Praza@Sun.COM  * composed_pg_t contains the information that is needed to compose a
3907887SLiane.Praza@Sun.COM  * property group.  See the section on Composed Properties in the block
3917887SLiane.Praza@Sun.COM  * comment at the beginning of this file.  The composed_pg structures are
3927887SLiane.Praza@Sun.COM  * linked into a uu_avl tree.  The tree is at sc_instance.sc_composed in
3937887SLiane.Praza@Sun.COM  * the entity_t.
3947887SLiane.Praza@Sun.COM  */
3957887SLiane.Praza@Sun.COM struct composed_pg {
3967887SLiane.Praza@Sun.COM 	/*
3977887SLiane.Praza@Sun.COM 	 * Property group is uniquely identified by its name and type.
3987887SLiane.Praza@Sun.COM 	 * These two elements point to the name and type in a pgroup_t
3997887SLiane.Praza@Sun.COM 	 * (either service or instance), so they do not need to be
4007887SLiane.Praza@Sun.COM 	 * allocated or freed.
4017887SLiane.Praza@Sun.COM 	 */
4027887SLiane.Praza@Sun.COM 	const char	*cpg_name;
4037887SLiane.Praza@Sun.COM 	const char	*cpg_type;
4047887SLiane.Praza@Sun.COM 
4057887SLiane.Praza@Sun.COM 	/* References to the actual property group definitions. */
4067887SLiane.Praza@Sun.COM 	pgroup_t	*cpg_instance_pg;
4077887SLiane.Praza@Sun.COM 	pgroup_t	*cpg_service_pg;
4087887SLiane.Praza@Sun.COM 
4097887SLiane.Praza@Sun.COM 	/* Composed properties of the property group. */
4107887SLiane.Praza@Sun.COM 	uu_avl_t	*cpg_composed_props;
4117887SLiane.Praza@Sun.COM 
4127887SLiane.Praza@Sun.COM 	uu_avl_node_t	cpg_node;	/* Linkage for AVL tree */
4137887SLiane.Praza@Sun.COM };
4147887SLiane.Praza@Sun.COM 
4157887SLiane.Praza@Sun.COM /*
4167887SLiane.Praza@Sun.COM  * Prefixes for standard property names.  Used in
4177887SLiane.Praza@Sun.COM  * include_values_support().
4187887SLiane.Praza@Sun.COM  */
4197887SLiane.Praza@Sun.COM typedef struct prop_prefix {
4207887SLiane.Praza@Sun.COM 	const char	*pp_prefix;
4217887SLiane.Praza@Sun.COM 	size_t		pp_size;
4227887SLiane.Praza@Sun.COM } prop_prefix_t;
4237887SLiane.Praza@Sun.COM 
4247887SLiane.Praza@Sun.COM /*
4257887SLiane.Praza@Sun.COM  * Store a legal range for a property allowing for either signed or
4267887SLiane.Praza@Sun.COM  * unsigned ranges.  It is used to store a range from a template
4277887SLiane.Praza@Sun.COM  * constraint element of a prop_pattern.  The structure is returned by
4287887SLiane.Praza@Sun.COM  * get_ranges() and is used by value_in_range() to validate the values of a
4297887SLiane.Praza@Sun.COM  * property.
4307887SLiane.Praza@Sun.COM  */
4317887SLiane.Praza@Sun.COM typedef struct range {
4327887SLiane.Praza@Sun.COM 	union {
4337887SLiane.Praza@Sun.COM 		struct {
4347887SLiane.Praza@Sun.COM 			uint64_t	rng_min;
4357887SLiane.Praza@Sun.COM 			uint64_t	rng_max;
4367887SLiane.Praza@Sun.COM 		} rng_unsigned;
4377887SLiane.Praza@Sun.COM 		struct {
4387887SLiane.Praza@Sun.COM 			int64_t		rng_min;
4397887SLiane.Praza@Sun.COM 			int64_t		rng_max;
4407887SLiane.Praza@Sun.COM 		} rng_signed;
4417887SLiane.Praza@Sun.COM 	} rng_u;
4427887SLiane.Praza@Sun.COM } range_t;
4437887SLiane.Praza@Sun.COM 
4447887SLiane.Praza@Sun.COM /*
4457887SLiane.Praza@Sun.COM  * This enum defines the levels where templates can be defined.  See the
4467887SLiane.Praza@Sun.COM  * pg_iter structure below.
4477887SLiane.Praza@Sun.COM  */
4487887SLiane.Praza@Sun.COM typedef enum tmpl_level {
4497887SLiane.Praza@Sun.COM 	TL_NOLEVEL = 0,		/* No level yet specified. */
4507887SLiane.Praza@Sun.COM 	TL_INSTANCE,		/* Instance templates. */
4517887SLiane.Praza@Sun.COM 	TL_COMPOSED,		/* Composed instance. */
4527887SLiane.Praza@Sun.COM 	TL_SERVICE,		/* Service wide templates. */
4537887SLiane.Praza@Sun.COM 	TL_RESTARTER,		/* Templates from restarter manifest. */
4547887SLiane.Praza@Sun.COM 	TL_GLOBAL		/* SMF wide templates. */
4557887SLiane.Praza@Sun.COM } tmpl_level_t;
4567887SLiane.Praza@Sun.COM 
4577887SLiane.Praza@Sun.COM /*
4587887SLiane.Praza@Sun.COM  * pg_iter is a structure that allows us to iterate through property groups
4597887SLiane.Praza@Sun.COM  * in an instance followed by the property groups of the instance's
4607887SLiane.Praza@Sun.COM  * service, the instance's restarter and finally the global service.  See
4617887SLiane.Praza@Sun.COM  * the Property Group Iteration section of the block comment at the
4627887SLiane.Praza@Sun.COM  * beginning of this file.
4637887SLiane.Praza@Sun.COM  */
4647887SLiane.Praza@Sun.COM typedef struct pg_iter {
4657887SLiane.Praza@Sun.COM 	entity_t	*pgi_entity;	/* Entity being searched */
4667887SLiane.Praza@Sun.COM 	const char	*pgi_restrict;	/* Only return PGs of this type */
4677887SLiane.Praza@Sun.COM 	tmpl_level_t	pgi_level;	/* Current level */
4687887SLiane.Praza@Sun.COM 	entity_t	*pgi_service;	/* Service being processed. */
4697887SLiane.Praza@Sun.COM 	union {
4707887SLiane.Praza@Sun.COM 		pgroup_t	*pgi_pg;
4717887SLiane.Praza@Sun.COM 		composed_pg_t	*pgi_cpg;
4727887SLiane.Praza@Sun.COM 	} pgi_current;			/* Current property group. */
4737887SLiane.Praza@Sun.COM } pg_iter_t;
4747887SLiane.Praza@Sun.COM 
4757887SLiane.Praza@Sun.COM /*
4767887SLiane.Praza@Sun.COM  * enum to distinguish between pg_patterns and prop_patterns.  It is used
4777887SLiane.Praza@Sun.COM  * in the ptrn_info_t structure.  See below.
4787887SLiane.Praza@Sun.COM  */
4797887SLiane.Praza@Sun.COM typedef enum ptrn_type {
4807887SLiane.Praza@Sun.COM 	PG_PATTERN,
4817887SLiane.Praza@Sun.COM 	PROP_PATTERN
4827887SLiane.Praza@Sun.COM } ptrn_type_t;
4837887SLiane.Praza@Sun.COM 
4847887SLiane.Praza@Sun.COM /*
4857887SLiane.Praza@Sun.COM  * Structure of information about a pg_pattern or a prop_pattern.  It is
4867887SLiane.Praza@Sun.COM  * used for template consistency checks.  gather_pattern() is used to
4877887SLiane.Praza@Sun.COM  * gather information for all the pg_patterns or prop_patterns in an
4887887SLiane.Praza@Sun.COM  * instance.  It allocates a ptrn_info_t for each of these and adds them to
4897887SLiane.Praza@Sun.COM  * an avl tree that is held by tmpl_consistency().
4907887SLiane.Praza@Sun.COM  */
4917887SLiane.Praza@Sun.COM typedef struct ptrn_info {
4927887SLiane.Praza@Sun.COM 	ptrn_type_t	pi_ptrn_type;
4937887SLiane.Praza@Sun.COM 	pgroup_t	*pi_ptrnpg;	/* pgroup_t defining the pattern. */
4947887SLiane.Praza@Sun.COM 	const char	*pi_name;	/* Name attribute. */
4957887SLiane.Praza@Sun.COM 	const char	*pi_type;	/* Type attribute. */
4967887SLiane.Praza@Sun.COM 	const char	*pi_target;	/* Target attribute - only PG_PATTERN */
4977887SLiane.Praza@Sun.COM 	const char	*pi_pgp_name;	/* Name of the pg pattern.  Only */
4987887SLiane.Praza@Sun.COM 					/* used for PROP_PATTERN. */
4997887SLiane.Praza@Sun.COM 	pgroup_t	*pi_enc_pgp;	/* PG of the pg_pattern that holds */
5007887SLiane.Praza@Sun.COM 					/* the prop_pattern defined by this */
5017887SLiane.Praza@Sun.COM 					/* structure.  Only used for */
5027887SLiane.Praza@Sun.COM 					/* PROP_PATTERN. */
5037887SLiane.Praza@Sun.COM 	uu_avl_node_t	pi_link;	/* Linkage into AVL tree */
5047887SLiane.Praza@Sun.COM } ptrn_info_t;
5057887SLiane.Praza@Sun.COM 
5067887SLiane.Praza@Sun.COM static const char *emesg_nomem;
5077887SLiane.Praza@Sun.COM 
5087887SLiane.Praza@Sun.COM /*
5097887SLiane.Praza@Sun.COM  * Pool for trees of composed property groups.
5107887SLiane.Praza@Sun.COM  */
5117887SLiane.Praza@Sun.COM static uu_avl_pool_t *composed_pg_pool;
5127887SLiane.Praza@Sun.COM 
5137887SLiane.Praza@Sun.COM /*
5147887SLiane.Praza@Sun.COM  * Pool for trees of composed properties.
5157887SLiane.Praza@Sun.COM  */
5167887SLiane.Praza@Sun.COM static uu_avl_pool_t *composed_prop_pool;
5177887SLiane.Praza@Sun.COM 
5187887SLiane.Praza@Sun.COM /*
5197887SLiane.Praza@Sun.COM  * Pool for lists of errors in the internal representation.
5207887SLiane.Praza@Sun.COM  */
5217887SLiane.Praza@Sun.COM static uu_list_pool_t *inmem_errors_pool;
5227887SLiane.Praza@Sun.COM 
5237887SLiane.Praza@Sun.COM /*
5247887SLiane.Praza@Sun.COM  * Pool for trees of pg_pattern info structures (ptrn_info_t).
5257887SLiane.Praza@Sun.COM  */
5267887SLiane.Praza@Sun.COM static uu_avl_pool_t *ptrn_info_pool;
5277887SLiane.Praza@Sun.COM 
5287887SLiane.Praza@Sun.COM /*
5297887SLiane.Praza@Sun.COM  * Pool for lists of template errors in the libscf representation.
5307887SLiane.Praza@Sun.COM  */
5317887SLiane.Praza@Sun.COM static uu_list_pool_t *tv_errors_pool;
5327887SLiane.Praza@Sun.COM 
5337887SLiane.Praza@Sun.COM /*
5347887SLiane.Praza@Sun.COM  * Property name prefixes for constraints and values.
5357887SLiane.Praza@Sun.COM  */
5367887SLiane.Praza@Sun.COM static const char *constraint_prefixes[] = {
5377887SLiane.Praza@Sun.COM 	SCF_PROPERTY_TM_CONSTRAINT_NAME,
5387887SLiane.Praza@Sun.COM 	SCF_PROPERTY_TM_CONSTRAINT_RANGE,
5397887SLiane.Praza@Sun.COM 	NULL
5407887SLiane.Praza@Sun.COM };
5417887SLiane.Praza@Sun.COM static const char *value_prefixes[] = {
5427887SLiane.Praza@Sun.COM 	SCF_PROPERTY_TM_VALUE_PREFIX,
5437887SLiane.Praza@Sun.COM 	NULL
5447887SLiane.Praza@Sun.COM };
5457887SLiane.Praza@Sun.COM 
5467887SLiane.Praza@Sun.COM /*
5477887SLiane.Praza@Sun.COM  * Function to compare two composed_pg structures.
5487887SLiane.Praza@Sun.COM  */
5497887SLiane.Praza@Sun.COM /* ARGSUSED2 */
5507887SLiane.Praza@Sun.COM static int
composed_pg_compare(const void * left,const void * right,void * unused)5517887SLiane.Praza@Sun.COM composed_pg_compare(const void *left, const void *right, void *unused)
5527887SLiane.Praza@Sun.COM {
5537887SLiane.Praza@Sun.COM 	composed_pg_t *l = (composed_pg_t *)left;
5547887SLiane.Praza@Sun.COM 	composed_pg_t *r = (composed_pg_t *)right;
5557887SLiane.Praza@Sun.COM 	int rc;
5567887SLiane.Praza@Sun.COM 
5577887SLiane.Praza@Sun.COM 	if ((rc = strcmp(l->cpg_name, r->cpg_name)) == 0) {
5587887SLiane.Praza@Sun.COM 		rc = strcmp(l->cpg_type, r->cpg_type);
5597887SLiane.Praza@Sun.COM 	}
5607887SLiane.Praza@Sun.COM 	return (rc);
5617887SLiane.Praza@Sun.COM }
5627887SLiane.Praza@Sun.COM 
5637887SLiane.Praza@Sun.COM /* ARGSUSED2 */
5647887SLiane.Praza@Sun.COM static int
composed_prop_compare(const void * left,const void * right,void * unused)5657887SLiane.Praza@Sun.COM composed_prop_compare(const void *left, const void *right, void *unused)
5667887SLiane.Praza@Sun.COM {
5677887SLiane.Praza@Sun.COM 	property_t *l = (property_t *)left;
5687887SLiane.Praza@Sun.COM 	property_t *r = (property_t *)right;
5697887SLiane.Praza@Sun.COM 
5707887SLiane.Praza@Sun.COM 	return (strcmp(l->sc_property_name, r->sc_property_name));
5717887SLiane.Praza@Sun.COM }
5727887SLiane.Praza@Sun.COM 
5737887SLiane.Praza@Sun.COM static composed_pg_t *
composed_pg_create()5747887SLiane.Praza@Sun.COM composed_pg_create()
5757887SLiane.Praza@Sun.COM {
5767887SLiane.Praza@Sun.COM 	composed_pg_t *cpg;
5777887SLiane.Praza@Sun.COM 
5787887SLiane.Praza@Sun.COM 	cpg = safe_malloc(sizeof (*cpg));
5797887SLiane.Praza@Sun.COM 	uu_avl_node_init(cpg, &cpg->cpg_node, composed_pg_pool);
5807887SLiane.Praza@Sun.COM 	return (cpg);
5817887SLiane.Praza@Sun.COM }
5827887SLiane.Praza@Sun.COM 
5837887SLiane.Praza@Sun.COM static void
composed_pg_destroy(composed_pg_t * cpg)5847887SLiane.Praza@Sun.COM composed_pg_destroy(composed_pg_t *cpg)
5857887SLiane.Praza@Sun.COM {
5867887SLiane.Praza@Sun.COM 	void *marker = NULL;
5877887SLiane.Praza@Sun.COM 	pgroup_t *pg;
5887887SLiane.Praza@Sun.COM 
5897887SLiane.Praza@Sun.COM 	if (cpg == NULL)
5907887SLiane.Praza@Sun.COM 		return;
5917887SLiane.Praza@Sun.COM 	/* Tear down composed property tree if we have one. */
5927887SLiane.Praza@Sun.COM 	if ((cpg->cpg_composed_props != NULL)) {
5937887SLiane.Praza@Sun.COM 		while (uu_avl_teardown(cpg->cpg_composed_props, &marker) !=
5947887SLiane.Praza@Sun.COM 		    NULL) {
5957887SLiane.Praza@Sun.COM 			/*
5967887SLiane.Praza@Sun.COM 			 * Nothing to do other than getting the property
5977887SLiane.Praza@Sun.COM 			 * out of the list.  This cleans up the property's
5987887SLiane.Praza@Sun.COM 			 * uu_avl_node.
5997887SLiane.Praza@Sun.COM 			 */
6007887SLiane.Praza@Sun.COM 		}
6017887SLiane.Praza@Sun.COM 		uu_avl_destroy(cpg->cpg_composed_props);
6027887SLiane.Praza@Sun.COM 	}
6037887SLiane.Praza@Sun.COM 
6047887SLiane.Praza@Sun.COM 	/* Clean up any pgroup_t references to us. */
6057887SLiane.Praza@Sun.COM 	if ((pg = cpg->cpg_instance_pg) != NULL) {
6067887SLiane.Praza@Sun.COM 		assert((pg->sc_pgroup_composed == NULL) ||
6077887SLiane.Praza@Sun.COM 		    (pg->sc_pgroup_composed == cpg));
6087887SLiane.Praza@Sun.COM 		pg->sc_pgroup_composed = NULL;
6097887SLiane.Praza@Sun.COM 	}
6107887SLiane.Praza@Sun.COM 
6117887SLiane.Praza@Sun.COM 	uu_avl_node_fini(cpg, &cpg->cpg_node, composed_pg_pool);
6127887SLiane.Praza@Sun.COM 	free(cpg);
6137887SLiane.Praza@Sun.COM }
6147887SLiane.Praza@Sun.COM 
6157887SLiane.Praza@Sun.COM /*
6167887SLiane.Praza@Sun.COM  * Walk the property group at pg, and add its properties to the AVL tree at
6177887SLiane.Praza@Sun.COM  * tree.
6187887SLiane.Praza@Sun.COM  */
6197887SLiane.Praza@Sun.COM static void
grow_props_tree(pgroup_t * pg,uu_avl_t * tree)6207887SLiane.Praza@Sun.COM grow_props_tree(pgroup_t *pg, uu_avl_t *tree)
6217887SLiane.Praza@Sun.COM {
6227887SLiane.Praza@Sun.COM 	uu_avl_index_t marker;
6237887SLiane.Praza@Sun.COM 	property_t *prop;
6247887SLiane.Praza@Sun.COM 
6257887SLiane.Praza@Sun.COM 	for (prop = uu_list_first(pg->sc_pgroup_props);
6267887SLiane.Praza@Sun.COM 	    prop != NULL;
6277887SLiane.Praza@Sun.COM 	    prop = uu_list_next(pg->sc_pgroup_props, prop)) {
6287887SLiane.Praza@Sun.COM 		if (uu_avl_find(tree, prop, NULL, &marker) == NULL) {
6297887SLiane.Praza@Sun.COM 			/*
6307887SLiane.Praza@Sun.COM 			 * If there was no match, insert the property into
6317887SLiane.Praza@Sun.COM 			 * the tree.  If we do get a match, there is
6327887SLiane.Praza@Sun.COM 			 * nothing to do.  That is because we rely on our
6337887SLiane.Praza@Sun.COM 			 * caller to process the instance properties first,
6347887SLiane.Praza@Sun.COM 			 * and the instance properties override the service
6357887SLiane.Praza@Sun.COM 			 * properties.
6367887SLiane.Praza@Sun.COM 			 */
6377887SLiane.Praza@Sun.COM 			uu_avl_insert(tree, prop, marker);
6387887SLiane.Praza@Sun.COM 		}
6397887SLiane.Praza@Sun.COM 	}
6407887SLiane.Praza@Sun.COM }
6417887SLiane.Praza@Sun.COM 
6427887SLiane.Praza@Sun.COM /*
6437887SLiane.Praza@Sun.COM  * The composed properties are stored in a uu_avl_tree.  First we populate
6447887SLiane.Praza@Sun.COM  * the tree with properties from the instance level property group.  Then,
6457887SLiane.Praza@Sun.COM  * we'll add the properties from the service level property group.
6467887SLiane.Praza@Sun.COM  */
6477887SLiane.Praza@Sun.COM static void
compose_props(composed_pg_t * cpg)6487887SLiane.Praza@Sun.COM compose_props(composed_pg_t *cpg)
6497887SLiane.Praza@Sun.COM {
6507887SLiane.Praza@Sun.COM 	uu_avl_t *tree;
6517887SLiane.Praza@Sun.COM 
6527887SLiane.Praza@Sun.COM 	tree = uu_avl_create(composed_prop_pool, cpg, TMPL_DEBUG_TREE);
6537887SLiane.Praza@Sun.COM 	if (tree == NULL) {
6547887SLiane.Praza@Sun.COM 		uu_die(gettext("composed_pool tree creation failed: %s\n"),
6557887SLiane.Praza@Sun.COM 		    uu_strerror(uu_error()));
6567887SLiane.Praza@Sun.COM 	}
6577887SLiane.Praza@Sun.COM 	cpg->cpg_composed_props = tree;
6587887SLiane.Praza@Sun.COM 
6597887SLiane.Praza@Sun.COM 	/*
6607887SLiane.Praza@Sun.COM 	 * compose_props() is only called when there is both an instance
6617887SLiane.Praza@Sun.COM 	 * and a service definition of the property group.  This implies
6627887SLiane.Praza@Sun.COM 	 * that neither cpg->cpg_instance_pg nor cpg->cpg_service_pg can be
6637887SLiane.Praza@Sun.COM 	 * NULL.
6647887SLiane.Praza@Sun.COM 	 */
6657887SLiane.Praza@Sun.COM 	/*
6667887SLiane.Praza@Sun.COM 	 * First add instance properties to the tree.
6677887SLiane.Praza@Sun.COM 	 */
6687887SLiane.Praza@Sun.COM 	assert(cpg->cpg_instance_pg != NULL);
6697887SLiane.Praza@Sun.COM 	grow_props_tree(cpg->cpg_instance_pg, tree);
6707887SLiane.Praza@Sun.COM 
6717887SLiane.Praza@Sun.COM 	/*
6727887SLiane.Praza@Sun.COM 	 * Add service properties to the tree.
6737887SLiane.Praza@Sun.COM 	 */
6747887SLiane.Praza@Sun.COM 	assert(cpg->cpg_service_pg != NULL);
6757887SLiane.Praza@Sun.COM 	grow_props_tree(cpg->cpg_service_pg, tree);
6767887SLiane.Praza@Sun.COM }
6777887SLiane.Praza@Sun.COM 
6787887SLiane.Praza@Sun.COM /*
6797887SLiane.Praza@Sun.COM  * This function is a utility for build_composed_instance().
6807887SLiane.Praza@Sun.COM  */
6817887SLiane.Praza@Sun.COM static void
build_composed_property_groups(entity_t * inst,uu_avl_t * tree)6827887SLiane.Praza@Sun.COM build_composed_property_groups(entity_t *inst, uu_avl_t *tree)
6837887SLiane.Praza@Sun.COM {
6847887SLiane.Praza@Sun.COM 	composed_pg_t *cpg;
6857887SLiane.Praza@Sun.COM 	uu_avl_index_t marker;
6867887SLiane.Praza@Sun.COM 	composed_pg_t *match;
6877887SLiane.Praza@Sun.COM 	pgroup_t *pg;
6887887SLiane.Praza@Sun.COM 	entity_t *svc;
6897887SLiane.Praza@Sun.COM 
6907887SLiane.Praza@Sun.COM 	/* First capture the instance property groups. */
6917887SLiane.Praza@Sun.COM 	for (pg = uu_list_first(inst->sc_pgroups);
6927887SLiane.Praza@Sun.COM 	    pg != NULL;
6937887SLiane.Praza@Sun.COM 	    pg = uu_list_next(inst->sc_pgroups, pg)) {
6947887SLiane.Praza@Sun.COM 		cpg = composed_pg_create();
6957887SLiane.Praza@Sun.COM 		cpg->cpg_name = pg->sc_pgroup_name;
6967887SLiane.Praza@Sun.COM 		cpg->cpg_type = pg->sc_pgroup_type;
6977887SLiane.Praza@Sun.COM 		cpg->cpg_instance_pg = pg;
6987887SLiane.Praza@Sun.COM 		match = uu_avl_find(tree, cpg, NULL, &marker);
6997887SLiane.Praza@Sun.COM 		/* Since we do the instance first, there should be no match. */
7007887SLiane.Praza@Sun.COM 		assert(match == NULL);
7017887SLiane.Praza@Sun.COM 		uu_avl_insert(tree, cpg, marker);
7027887SLiane.Praza@Sun.COM 		pg->sc_pgroup_composed = cpg;
7037887SLiane.Praza@Sun.COM 	}
7047887SLiane.Praza@Sun.COM 
7057887SLiane.Praza@Sun.COM 	/* Now capture the service property groups. */
7067887SLiane.Praza@Sun.COM 	svc = inst->sc_parent;
7077887SLiane.Praza@Sun.COM 	cpg = NULL;
7087887SLiane.Praza@Sun.COM 	for (pg = uu_list_first(svc->sc_pgroups);
7097887SLiane.Praza@Sun.COM 	    pg != NULL;
7107887SLiane.Praza@Sun.COM 	    pg = uu_list_next(svc->sc_pgroups, pg)) {
7117887SLiane.Praza@Sun.COM 		if (cpg == NULL)
7127887SLiane.Praza@Sun.COM 			cpg = composed_pg_create();
7137887SLiane.Praza@Sun.COM 		cpg->cpg_name = pg->sc_pgroup_name;
7147887SLiane.Praza@Sun.COM 		cpg->cpg_type = pg->sc_pgroup_type;
7157887SLiane.Praza@Sun.COM 		cpg->cpg_service_pg = pg;
7167887SLiane.Praza@Sun.COM 		match = uu_avl_find(tree, cpg, NULL, &marker);
7177887SLiane.Praza@Sun.COM 		if (match == NULL) {
7187887SLiane.Praza@Sun.COM 			uu_avl_insert(tree, cpg, marker);
7197887SLiane.Praza@Sun.COM 			/* Get new composed_pg_t next at top of loop. */
7207887SLiane.Praza@Sun.COM 			cpg = NULL;
7217887SLiane.Praza@Sun.COM 		} else {
7227887SLiane.Praza@Sun.COM 			/*
7237887SLiane.Praza@Sun.COM 			 * Already have a composed_pg from instance
7247887SLiane.Praza@Sun.COM 			 * processing.  Just add the pointer to the service
7257887SLiane.Praza@Sun.COM 			 * pg and compose the properties.
7267887SLiane.Praza@Sun.COM 			 */
7277887SLiane.Praza@Sun.COM 			match->cpg_service_pg = pg;
7287887SLiane.Praza@Sun.COM 			compose_props(match);
7297887SLiane.Praza@Sun.COM 		}
7307887SLiane.Praza@Sun.COM 	}
7317887SLiane.Praza@Sun.COM 	if (cpg != NULL)
7327887SLiane.Praza@Sun.COM 		composed_pg_destroy(cpg);
7337887SLiane.Praza@Sun.COM }
7347887SLiane.Praza@Sun.COM 
7357887SLiane.Praza@Sun.COM static void
build_composed_instance(entity_t * inst)7367887SLiane.Praza@Sun.COM build_composed_instance(entity_t *inst)
7377887SLiane.Praza@Sun.COM {
7387887SLiane.Praza@Sun.COM 	uu_avl_t *tree;
7397887SLiane.Praza@Sun.COM 
7407887SLiane.Praza@Sun.COM 	assert(inst->sc_etype == SVCCFG_INSTANCE_OBJECT);
7417887SLiane.Praza@Sun.COM 
7427887SLiane.Praza@Sun.COM 	if (inst->sc_u.sc_instance.sc_composed == NULL) {
7437887SLiane.Praza@Sun.COM 		tree = uu_avl_create(composed_pg_pool, inst, TMPL_DEBUG_TREE);
7447887SLiane.Praza@Sun.COM 		if (tree == NULL) {
7457887SLiane.Praza@Sun.COM 			uu_die(gettext("composed_instance tree creation "
7467887SLiane.Praza@Sun.COM 			    "failed: %s\n"), uu_strerror(uu_error()));
7477887SLiane.Praza@Sun.COM 		}
7487887SLiane.Praza@Sun.COM 		inst->sc_u.sc_instance.sc_composed = tree;
7497887SLiane.Praza@Sun.COM 	}
7507887SLiane.Praza@Sun.COM 	build_composed_property_groups(inst,
7517887SLiane.Praza@Sun.COM 	    inst->sc_u.sc_instance.sc_composed);
7527887SLiane.Praza@Sun.COM }
7537887SLiane.Praza@Sun.COM 
7547887SLiane.Praza@Sun.COM static void
demolish_composed_instance(entity_t * inst)7557887SLiane.Praza@Sun.COM demolish_composed_instance(entity_t *inst)
7567887SLiane.Praza@Sun.COM {
7577887SLiane.Praza@Sun.COM 	composed_pg_t *cpg;
7587887SLiane.Praza@Sun.COM 	void *marker = NULL;
7597887SLiane.Praza@Sun.COM 	uu_avl_t *tree;
7607887SLiane.Praza@Sun.COM 
7617887SLiane.Praza@Sun.COM 	tree = inst->sc_u.sc_instance.sc_composed;
7627887SLiane.Praza@Sun.COM 	if (tree == NULL)
7637887SLiane.Praza@Sun.COM 		return;
7647887SLiane.Praza@Sun.COM 
7657887SLiane.Praza@Sun.COM 	marker = NULL;
7667887SLiane.Praza@Sun.COM 	while ((cpg = uu_avl_teardown(tree, &marker)) != NULL) {
7677887SLiane.Praza@Sun.COM 		composed_pg_destroy(cpg);
7687887SLiane.Praza@Sun.COM 	}
7697887SLiane.Praza@Sun.COM 	uu_avl_destroy(tree);
7707887SLiane.Praza@Sun.COM 
7717887SLiane.Praza@Sun.COM 	inst->sc_u.sc_instance.sc_composed = NULL;
7727887SLiane.Praza@Sun.COM }
7737887SLiane.Praza@Sun.COM /*
7747887SLiane.Praza@Sun.COM  * Return the number of values in prop.
7757887SLiane.Praza@Sun.COM  */
7767887SLiane.Praza@Sun.COM static size_t
count_prop_values(property_t * prop)7777887SLiane.Praza@Sun.COM count_prop_values(property_t *prop)
7787887SLiane.Praza@Sun.COM {
7797887SLiane.Praza@Sun.COM 	return (uu_list_numnodes(prop->sc_property_values));
7807887SLiane.Praza@Sun.COM }
7817887SLiane.Praza@Sun.COM 
7827887SLiane.Praza@Sun.COM static int
is_numeric_type(scf_type_t type)7837887SLiane.Praza@Sun.COM is_numeric_type(scf_type_t type)
7847887SLiane.Praza@Sun.COM {
7857887SLiane.Praza@Sun.COM 	if (type == SCF_TYPE_BOOLEAN)
7867887SLiane.Praza@Sun.COM 		return (1);
7877887SLiane.Praza@Sun.COM 	if (type == SCF_TYPE_COUNT)
7887887SLiane.Praza@Sun.COM 		return (1);
7897887SLiane.Praza@Sun.COM 	if (type == SCF_TYPE_INTEGER)
7907887SLiane.Praza@Sun.COM 		return (1);
7917887SLiane.Praza@Sun.COM 	return (0);
7927887SLiane.Praza@Sun.COM }
7937887SLiane.Praza@Sun.COM 
7947887SLiane.Praza@Sun.COM static pg_type_t
pgroup_type(pgroup_t * pg)7957887SLiane.Praza@Sun.COM pgroup_type(pgroup_t *pg)
7967887SLiane.Praza@Sun.COM {
7977887SLiane.Praza@Sun.COM 	if (strcmp(pg->sc_pgroup_type, SCF_GROUP_TEMPLATE_PG_PATTERN) == 0)
7987887SLiane.Praza@Sun.COM 		return (PG_PATTERN_PG);
7997887SLiane.Praza@Sun.COM 	if (strcmp(pg->sc_pgroup_type, SCF_GROUP_TEMPLATE_PROP_PATTERN) == 0)
8007887SLiane.Praza@Sun.COM 		return (PROP_PATTERN_PG);
8017887SLiane.Praza@Sun.COM 	return (NORMAL_PG);
8027887SLiane.Praza@Sun.COM }
8037887SLiane.Praza@Sun.COM 
8047887SLiane.Praza@Sun.COM /*
8057887SLiane.Praza@Sun.COM  * Search the property group at pg for a property named name.  If the
8067887SLiane.Praza@Sun.COM  * property group has a tree of composed properties, the tree will be
8077887SLiane.Praza@Sun.COM  * searched for the property.  Otherwise, the property group's linked list
8087887SLiane.Praza@Sun.COM  * will be searched.
8097887SLiane.Praza@Sun.COM  */
8107887SLiane.Praza@Sun.COM static property_t *
property_find(pgroup_t * pg,const char * name)8117887SLiane.Praza@Sun.COM property_find(pgroup_t *pg, const char *name)
8127887SLiane.Praza@Sun.COM {
8137887SLiane.Praza@Sun.COM 	composed_pg_t *cpg;
8147887SLiane.Praza@Sun.COM 	property_t look;
8157887SLiane.Praza@Sun.COM 
8167887SLiane.Praza@Sun.COM 	cpg = pg->sc_pgroup_composed;
8177887SLiane.Praza@Sun.COM 
8187887SLiane.Praza@Sun.COM 	if ((cpg == NULL) || (cpg->cpg_composed_props == NULL)) {
8197887SLiane.Praza@Sun.COM 		/* This is not a composed property group. */
8207887SLiane.Praza@Sun.COM 		return (internal_property_find(pg, name));
8217887SLiane.Praza@Sun.COM 	}
8227887SLiane.Praza@Sun.COM 
8237887SLiane.Praza@Sun.COM 	/*
8247887SLiane.Praza@Sun.COM 	 * This is a composed property group, so look for the property in
8257887SLiane.Praza@Sun.COM 	 * the AVL tree.
8267887SLiane.Praza@Sun.COM 	 */
8277887SLiane.Praza@Sun.COM 	look.sc_property_name = (char *)name;
8287887SLiane.Praza@Sun.COM 	return (uu_avl_find(cpg->cpg_composed_props, &look, NULL, NULL));
8297887SLiane.Praza@Sun.COM }
8307887SLiane.Praza@Sun.COM 
8317887SLiane.Praza@Sun.COM /*
8327887SLiane.Praza@Sun.COM  * Functions for manipulating the avalues structure.
8337887SLiane.Praza@Sun.COM  */
8347887SLiane.Praza@Sun.COM 
8357887SLiane.Praza@Sun.COM /*
8367887SLiane.Praza@Sun.COM  * Free allocated memory referenced by the avalues structure.  Then, free
8377887SLiane.Praza@Sun.COM  * the structure itself.
8387887SLiane.Praza@Sun.COM  */
8397887SLiane.Praza@Sun.COM static void
av_destroy(avalues_t * av)8407887SLiane.Praza@Sun.COM av_destroy(avalues_t *av)
8417887SLiane.Praza@Sun.COM {
8427887SLiane.Praza@Sun.COM 	if (av == NULL)
8437887SLiane.Praza@Sun.COM 		return;
8447887SLiane.Praza@Sun.COM 	switch (av->av_type) {
8457887SLiane.Praza@Sun.COM 	case SCF_TYPE_BOOLEAN:
8467887SLiane.Praza@Sun.COM 	case SCF_TYPE_COUNT:
8477887SLiane.Praza@Sun.COM 		uu_free(av->av_v.av_unsigned);
8487887SLiane.Praza@Sun.COM 		break;
8497887SLiane.Praza@Sun.COM 	case SCF_TYPE_INTEGER:
8507887SLiane.Praza@Sun.COM 		uu_free(av->av_v.av_integer);
8517887SLiane.Praza@Sun.COM 		break;
8527887SLiane.Praza@Sun.COM 	default:
8537887SLiane.Praza@Sun.COM 		/*
8547887SLiane.Praza@Sun.COM 		 * We don't need to free the strings that are referenced by
8557887SLiane.Praza@Sun.COM 		 * av_string.  The strings are held in propery_t structures
8567887SLiane.Praza@Sun.COM 		 * that will be freed at a later time.
8577887SLiane.Praza@Sun.COM 		 */
8587887SLiane.Praza@Sun.COM 		uu_free(av->av_v.av_string);
8597887SLiane.Praza@Sun.COM 		break;
8607887SLiane.Praza@Sun.COM 	}
8617887SLiane.Praza@Sun.COM 	uu_free(av);
8627887SLiane.Praza@Sun.COM }
8637887SLiane.Praza@Sun.COM /*
8647887SLiane.Praza@Sun.COM  * Allocate and inialize an avalues structure.  count represents the
8657887SLiane.Praza@Sun.COM  * number of values the structure is expected to hold.  type specifies how
8667887SLiane.Praza@Sun.COM  * the consumer of the property values would like to see them represented.
8677887SLiane.Praza@Sun.COM  * See comments for the av_get_values() more details on how type is used.
8687887SLiane.Praza@Sun.COM  *
8697887SLiane.Praza@Sun.COM  * The returned structure must be freed by calling av_destroy().
8707887SLiane.Praza@Sun.COM  *
8717887SLiane.Praza@Sun.COM  * NULL is returned if memory allocation fails.
8727887SLiane.Praza@Sun.COM  */
8737887SLiane.Praza@Sun.COM static avalues_t *
av_create(size_t count,scf_type_t type)8747887SLiane.Praza@Sun.COM av_create(size_t count, scf_type_t type)
8757887SLiane.Praza@Sun.COM {
8767887SLiane.Praza@Sun.COM 	uint_t alloc_failed = 0;
8777887SLiane.Praza@Sun.COM 	avalues_t *av;
8787887SLiane.Praza@Sun.COM 
8797887SLiane.Praza@Sun.COM 	av = uu_zalloc(sizeof (*av));
8807887SLiane.Praza@Sun.COM 	if (av == NULL)
8817887SLiane.Praza@Sun.COM 		return (NULL);
8827887SLiane.Praza@Sun.COM 	av->av_count = count;
8837887SLiane.Praza@Sun.COM 	av->av_type = type;
8847887SLiane.Praza@Sun.COM 	switch (type) {
8857887SLiane.Praza@Sun.COM 	case SCF_TYPE_BOOLEAN:
8867887SLiane.Praza@Sun.COM 	case SCF_TYPE_COUNT:
8877887SLiane.Praza@Sun.COM 		av->av_v.av_unsigned = uu_zalloc(count * sizeof (uint64_t));
8887887SLiane.Praza@Sun.COM 		if (av->av_v.av_unsigned == NULL)
8897887SLiane.Praza@Sun.COM 			alloc_failed = 1;
8907887SLiane.Praza@Sun.COM 		break;
8917887SLiane.Praza@Sun.COM 	case SCF_TYPE_INTEGER:
8927887SLiane.Praza@Sun.COM 		av->av_v.av_integer = uu_zalloc(count * sizeof (int64_t));
8937887SLiane.Praza@Sun.COM 		if (av->av_v.av_integer == NULL)
8947887SLiane.Praza@Sun.COM 			alloc_failed = 1;
8957887SLiane.Praza@Sun.COM 		break;
8967887SLiane.Praza@Sun.COM 	default:
8977887SLiane.Praza@Sun.COM 		av->av_v.av_string = uu_zalloc(count * sizeof (char *));
8987887SLiane.Praza@Sun.COM 		if (av->av_v.av_string == NULL)
8997887SLiane.Praza@Sun.COM 			alloc_failed = 1;
9007887SLiane.Praza@Sun.COM 	}
9017887SLiane.Praza@Sun.COM 	if (alloc_failed) {
9027887SLiane.Praza@Sun.COM 		av_destroy(av);
9037887SLiane.Praza@Sun.COM 		return (NULL);
9047887SLiane.Praza@Sun.COM 	}
9057887SLiane.Praza@Sun.COM 	return (av);
9067887SLiane.Praza@Sun.COM }
9077887SLiane.Praza@Sun.COM 
9087887SLiane.Praza@Sun.COM /*
9097887SLiane.Praza@Sun.COM  * Return the ith integer value in av.
9107887SLiane.Praza@Sun.COM  */
9117887SLiane.Praza@Sun.COM static int64_t
av_get_integer(avalues_t * av,uint_t i)9127887SLiane.Praza@Sun.COM av_get_integer(avalues_t *av, uint_t i)
9137887SLiane.Praza@Sun.COM {
9147887SLiane.Praza@Sun.COM 	assert(av->av_type == SCF_TYPE_INTEGER);
9157887SLiane.Praza@Sun.COM 	assert(i < av->av_count);
9167887SLiane.Praza@Sun.COM 	return (*(av->av_v.av_integer + i));
9177887SLiane.Praza@Sun.COM }
9187887SLiane.Praza@Sun.COM 
9197887SLiane.Praza@Sun.COM /*
9207887SLiane.Praza@Sun.COM  * Return the ith string value in av.
9217887SLiane.Praza@Sun.COM  */
9227887SLiane.Praza@Sun.COM static const char *
av_get_string(avalues_t * av,uint_t i)9237887SLiane.Praza@Sun.COM av_get_string(avalues_t *av, uint_t i)
9247887SLiane.Praza@Sun.COM {
9257887SLiane.Praza@Sun.COM 	assert(is_numeric_type(av->av_type) == 0);
9267887SLiane.Praza@Sun.COM 	assert(i < av->av_count);
9277887SLiane.Praza@Sun.COM 	return (*(av->av_v.av_string + i));
9287887SLiane.Praza@Sun.COM }
9297887SLiane.Praza@Sun.COM 
9307887SLiane.Praza@Sun.COM /*
9317887SLiane.Praza@Sun.COM  * Return the ith unsigned value in av.
9327887SLiane.Praza@Sun.COM  */
9337887SLiane.Praza@Sun.COM static uint64_t
av_get_unsigned(avalues_t * av,uint_t i)9347887SLiane.Praza@Sun.COM av_get_unsigned(avalues_t *av, uint_t i)
9357887SLiane.Praza@Sun.COM {
9367887SLiane.Praza@Sun.COM 	assert((av->av_type == SCF_TYPE_BOOLEAN) ||
9377887SLiane.Praza@Sun.COM 	    (av->av_type == SCF_TYPE_COUNT));
9387887SLiane.Praza@Sun.COM 	assert(i < av->av_count);
9397887SLiane.Praza@Sun.COM 	return (*(av->av_v.av_unsigned + i));
9407887SLiane.Praza@Sun.COM }
9417887SLiane.Praza@Sun.COM 
9427887SLiane.Praza@Sun.COM /*
9437887SLiane.Praza@Sun.COM  * Store the value in the ith slot of the av structure.  If av is being
9447887SLiane.Praza@Sun.COM  * used to store numeric values, the string at value will be converted to
9457887SLiane.Praza@Sun.COM  * the appropriate numeric form.
9467887SLiane.Praza@Sun.COM  */
9477887SLiane.Praza@Sun.COM static tmpl_validate_status_t
av_set_value(avalues_t * av,uint_t i,const char * value)9487887SLiane.Praza@Sun.COM av_set_value(avalues_t *av, uint_t i, const char *value)
9497887SLiane.Praza@Sun.COM {
9507887SLiane.Praza@Sun.COM 	char *endptr;
9517887SLiane.Praza@Sun.COM 	int64_t n;
9527887SLiane.Praza@Sun.COM 	uint64_t un;
9537887SLiane.Praza@Sun.COM 
9547887SLiane.Praza@Sun.COM 	if (is_numeric_type(av->av_type)) {
9557887SLiane.Praza@Sun.COM 		switch (av->av_type) {
9567887SLiane.Praza@Sun.COM 		case SCF_TYPE_BOOLEAN:
9577887SLiane.Praza@Sun.COM 		case SCF_TYPE_COUNT:
9587887SLiane.Praza@Sun.COM 			un = strtoull(value, &endptr, 0);
9597887SLiane.Praza@Sun.COM 			if ((endptr == value) || (*endptr != 0)) {
9607887SLiane.Praza@Sun.COM 				return (TVS_BAD_CONVERSION);
9617887SLiane.Praza@Sun.COM 			}
9627887SLiane.Praza@Sun.COM 			*(av->av_v.av_unsigned + i) = un;
9637887SLiane.Praza@Sun.COM 			break;
9647887SLiane.Praza@Sun.COM 		case SCF_TYPE_INTEGER:
9657887SLiane.Praza@Sun.COM 			n = strtoll(value, &endptr, 0);
9667887SLiane.Praza@Sun.COM 			if ((endptr == value) || (*endptr != 0)) {
9677887SLiane.Praza@Sun.COM 				return (TVS_BAD_CONVERSION);
9687887SLiane.Praza@Sun.COM 			}
9697887SLiane.Praza@Sun.COM 			*(av->av_v.av_integer + i) = n;
9707887SLiane.Praza@Sun.COM 		}
9717887SLiane.Praza@Sun.COM 	} else {
9727887SLiane.Praza@Sun.COM 		*(av->av_v.av_string + i) = value;
9737887SLiane.Praza@Sun.COM 	}
9747887SLiane.Praza@Sun.COM 
9757887SLiane.Praza@Sun.COM 	return (TVS_SUCCESS);
9767887SLiane.Praza@Sun.COM }
9777887SLiane.Praza@Sun.COM 
9787887SLiane.Praza@Sun.COM /*
9797887SLiane.Praza@Sun.COM  * Find the property whose name is prop_name in the property group at pg.
9807887SLiane.Praza@Sun.COM  * Read all the values of this property and return them in an avalues
9817887SLiane.Praza@Sun.COM  * structure placing the address of the structure in *values.  The caller
9827887SLiane.Praza@Sun.COM  * must free the structure by calling av_destroy().
9837887SLiane.Praza@Sun.COM  *
9847887SLiane.Praza@Sun.COM  * The type parameter is used to indicate the type of information that the
9857887SLiane.Praza@Sun.COM  * caller would like to consume.  If it is one of the numeric types, the
9867887SLiane.Praza@Sun.COM  * property value will be converted to the appropriate numeric type before
9877887SLiane.Praza@Sun.COM  * placing it in the avalues struct.  Decoding will be done before the
9887887SLiane.Praza@Sun.COM  * conversion if necessary.
9897887SLiane.Praza@Sun.COM  */
9907887SLiane.Praza@Sun.COM static tmpl_validate_status_t
av_get_values(pgroup_t * pg,const char * prop_name,scf_type_t type,avalues_t ** values)9917887SLiane.Praza@Sun.COM av_get_values(pgroup_t *pg, const char *prop_name, scf_type_t type,
9927887SLiane.Praza@Sun.COM     avalues_t **values)
9937887SLiane.Praza@Sun.COM {
9947887SLiane.Praza@Sun.COM 	avalues_t *av;
9957887SLiane.Praza@Sun.COM 	uint_t i;
9967887SLiane.Praza@Sun.COM 	property_t *prop;
9977887SLiane.Praza@Sun.COM 	tmpl_validate_status_t rc;
9987887SLiane.Praza@Sun.COM 	value_t *v;
9997887SLiane.Praza@Sun.COM 
10007887SLiane.Praza@Sun.COM 	prop = property_find(pg, prop_name);
10017887SLiane.Praza@Sun.COM 	if (prop == NULL) {
10027887SLiane.Praza@Sun.COM 		return (TVS_NOMATCH);
10037887SLiane.Praza@Sun.COM 	}
10047887SLiane.Praza@Sun.COM 	assert(prop->sc_value_type == SCF_TYPE_ASTRING);
10057887SLiane.Praza@Sun.COM 	av = av_create(count_prop_values(prop), type);
10067887SLiane.Praza@Sun.COM 	if (av == NULL)
10077887SLiane.Praza@Sun.COM 		uu_die(emesg_nomem);
10087887SLiane.Praza@Sun.COM 
10097887SLiane.Praza@Sun.COM 	/* Collect the values. */
10107887SLiane.Praza@Sun.COM 	for ((v = uu_list_first(prop->sc_property_values)), i = 0;
10117887SLiane.Praza@Sun.COM 	    v != NULL;
10127887SLiane.Praza@Sun.COM 	    (v = uu_list_next(prop->sc_property_values, v)), i++) {
10137887SLiane.Praza@Sun.COM 		assert(i < av->av_count);
10147887SLiane.Praza@Sun.COM 		assert(v->sc_type == SCF_TYPE_ASTRING);
10157887SLiane.Praza@Sun.COM 		rc = av_set_value(av, i, v->sc_u.sc_string);
10167887SLiane.Praza@Sun.COM 		if (rc != TVS_SUCCESS) {
10177887SLiane.Praza@Sun.COM 			av_destroy(av);
10187887SLiane.Praza@Sun.COM 			return (rc);
10197887SLiane.Praza@Sun.COM 		}
10207887SLiane.Praza@Sun.COM 	}
10217887SLiane.Praza@Sun.COM 	*values = av;
10227887SLiane.Praza@Sun.COM 	return (TVS_SUCCESS);
10237887SLiane.Praza@Sun.COM }
10247887SLiane.Praza@Sun.COM 
10257887SLiane.Praza@Sun.COM /*
10267887SLiane.Praza@Sun.COM  * Find the property in pg whose name is prop_name.  Return a pointer to
10277887SLiane.Praza@Sun.COM  * the first astring value in that property.
10287887SLiane.Praza@Sun.COM  *
10297887SLiane.Praza@Sun.COM  * NULL is returned if there is no property named prop_name or if it does
10307887SLiane.Praza@Sun.COM  * not have an astring value.
10317887SLiane.Praza@Sun.COM  */
10327887SLiane.Praza@Sun.COM static const char *
find_astring_value_in_pg(pgroup_t * pg,const char * prop_name)10337887SLiane.Praza@Sun.COM find_astring_value_in_pg(pgroup_t *pg, const char *prop_name)
10347887SLiane.Praza@Sun.COM {
10357887SLiane.Praza@Sun.COM 	property_t *prop;
10367887SLiane.Praza@Sun.COM 	value_t *v;
10377887SLiane.Praza@Sun.COM 
10387887SLiane.Praza@Sun.COM 	prop = property_find(pg, prop_name);
10397887SLiane.Praza@Sun.COM 	if (prop == NULL)
10407887SLiane.Praza@Sun.COM 		return (NULL);
10417887SLiane.Praza@Sun.COM 	if (prop->sc_value_type != SCF_TYPE_ASTRING)
10427887SLiane.Praza@Sun.COM 		return (NULL);
10437887SLiane.Praza@Sun.COM 	v = uu_list_first(prop->sc_property_values);
10447887SLiane.Praza@Sun.COM 	if (v == NULL)
10457887SLiane.Praza@Sun.COM 		return (NULL);
10467887SLiane.Praza@Sun.COM 	assert(v->sc_type == SCF_TYPE_ASTRING);
10477887SLiane.Praza@Sun.COM 	return (v->sc_u.sc_string);
10487887SLiane.Praza@Sun.COM }
10497887SLiane.Praza@Sun.COM /*
10507887SLiane.Praza@Sun.COM  * Find the first property value of type SCF_TYPE_COUNT in the property at
10517887SLiane.Praza@Sun.COM  * prop.  Return the value to count.
10527887SLiane.Praza@Sun.COM  */
10537887SLiane.Praza@Sun.COM static tmpl_validate_status_t
find_count_value(property_t * prop,uint64_t * count)10547887SLiane.Praza@Sun.COM find_count_value(property_t *prop, uint64_t *count)
10557887SLiane.Praza@Sun.COM {
10567887SLiane.Praza@Sun.COM 	value_t *value;
10577887SLiane.Praza@Sun.COM 
10587887SLiane.Praza@Sun.COM 	assert(prop->sc_value_type == SCF_TYPE_COUNT);
10597887SLiane.Praza@Sun.COM 	value = uu_list_first(prop->sc_property_values);
10607887SLiane.Praza@Sun.COM 	if (value == NULL)
10617887SLiane.Praza@Sun.COM 		return (TVS_NOMATCH);
10627887SLiane.Praza@Sun.COM 	*count = value->sc_u.sc_count;
10637887SLiane.Praza@Sun.COM 	return (TVS_SUCCESS);
10647887SLiane.Praza@Sun.COM }
10657887SLiane.Praza@Sun.COM 
10667887SLiane.Praza@Sun.COM /*
10677887SLiane.Praza@Sun.COM  * pattern is a property group representing a pg_pattern or a
10687887SLiane.Praza@Sun.COM  * prop_pattern.  This function returns the name specification from the
10697887SLiane.Praza@Sun.COM  * pg_pattern or prop_pattern.
10707887SLiane.Praza@Sun.COM  */
10717887SLiane.Praza@Sun.COM static const char *
find_name_specification(pgroup_t * pattern)10727887SLiane.Praza@Sun.COM find_name_specification(pgroup_t *pattern)
10737887SLiane.Praza@Sun.COM {
10747887SLiane.Praza@Sun.COM 	return (find_astring_value_in_pg(pattern, SCF_PROPERTY_TM_NAME));
10757887SLiane.Praza@Sun.COM }
10767887SLiane.Praza@Sun.COM 
10777887SLiane.Praza@Sun.COM /*
10787887SLiane.Praza@Sun.COM  * pattern is a property group representing a pg_pattern or a prop_pattern.
10797887SLiane.Praza@Sun.COM  * This function returns the type specification from the pg_pattern or
10807887SLiane.Praza@Sun.COM  * prop_pattern.
10817887SLiane.Praza@Sun.COM  */
10827887SLiane.Praza@Sun.COM static const char *
find_type_specification(pgroup_t * pattern)10837887SLiane.Praza@Sun.COM find_type_specification(pgroup_t *pattern)
10847887SLiane.Praza@Sun.COM {
10857887SLiane.Praza@Sun.COM 	return (find_astring_value_in_pg(pattern, SCF_PROPERTY_TM_TYPE));
10867887SLiane.Praza@Sun.COM }
10877887SLiane.Praza@Sun.COM 
10887887SLiane.Praza@Sun.COM /*
10897887SLiane.Praza@Sun.COM  * Find the FMRI of the restarter for the entity, e.  The restarter is the
10907887SLiane.Praza@Sun.COM  * value of the "restarter" property in the "general" property group.
10917887SLiane.Praza@Sun.COM  */
10927887SLiane.Praza@Sun.COM static const char *
find_restarter(entity_t * e)10937887SLiane.Praza@Sun.COM find_restarter(entity_t *e)
10947887SLiane.Praza@Sun.COM {
10957887SLiane.Praza@Sun.COM 	pgroup_t *pg;
10967887SLiane.Praza@Sun.COM 	property_t *prop;
10977887SLiane.Praza@Sun.COM 	value_t *v;
10987887SLiane.Praza@Sun.COM 
10997887SLiane.Praza@Sun.COM 	pg = internal_pgroup_find(e, scf_pg_general, scf_group_framework);
11007887SLiane.Praza@Sun.COM 	if (pg != NULL) {
11017887SLiane.Praza@Sun.COM 		prop = property_find(pg, SCF_PROPERTY_RESTARTER);
11027887SLiane.Praza@Sun.COM 		if ((prop != NULL) && (prop->sc_value_type == SCF_TYPE_FMRI)) {
11037887SLiane.Praza@Sun.COM 			v = uu_list_first(prop->sc_property_values);
11047887SLiane.Praza@Sun.COM 			if (v != NULL)
11057887SLiane.Praza@Sun.COM 				return (v->sc_u.sc_string);
11067887SLiane.Praza@Sun.COM 		}
11077887SLiane.Praza@Sun.COM 	}
11087887SLiane.Praza@Sun.COM 
11097887SLiane.Praza@Sun.COM 	/*
11107887SLiane.Praza@Sun.COM 	 * Didn't find the restarter.
11117887SLiane.Praza@Sun.COM 	 */
11127887SLiane.Praza@Sun.COM 	return (NULL);
11137887SLiane.Praza@Sun.COM }
11147887SLiane.Praza@Sun.COM 
11157887SLiane.Praza@Sun.COM /*
11167887SLiane.Praza@Sun.COM  * prop_pattern points to a prop_pattern.  This function finds the
11177887SLiane.Praza@Sun.COM  * cardinality specification in the prop_pattern and returns the minimum
11187887SLiane.Praza@Sun.COM  * and maximum values of the cardinality.
11197887SLiane.Praza@Sun.COM  *
11207887SLiane.Praza@Sun.COM  * Returns TVS_NOMATCH if either the cardinality minimum or maximum are
11217887SLiane.Praza@Sun.COM  * missing.
11227887SLiane.Praza@Sun.COM  */
11237887SLiane.Praza@Sun.COM static tmpl_validate_status_t
get_cardinality(pgroup_t * prop_pattern,uint64_t * min,uint64_t * max)11247887SLiane.Praza@Sun.COM get_cardinality(pgroup_t *prop_pattern, uint64_t *min, uint64_t *max)
11257887SLiane.Praza@Sun.COM {
11267887SLiane.Praza@Sun.COM 	property_t *prop;
11277887SLiane.Praza@Sun.COM 	tmpl_validate_status_t rc;
11287887SLiane.Praza@Sun.COM 
11297887SLiane.Praza@Sun.COM 	assert(strcmp(prop_pattern->sc_pgroup_type,
11307887SLiane.Praza@Sun.COM 	    SCF_GROUP_TEMPLATE_PROP_PATTERN) == 0);
11317887SLiane.Praza@Sun.COM 
11327887SLiane.Praza@Sun.COM 	prop = property_find(prop_pattern,
11337887SLiane.Praza@Sun.COM 	    SCF_PROPERTY_TM_CARDINALITY_MIN);
11347887SLiane.Praza@Sun.COM 	if (prop == NULL)
11357887SLiane.Praza@Sun.COM 		return (TVS_NOMATCH);
11367887SLiane.Praza@Sun.COM 	rc = find_count_value(prop, min);
11377887SLiane.Praza@Sun.COM 	if (rc != TVS_SUCCESS)
11387887SLiane.Praza@Sun.COM 		return (rc);
11397887SLiane.Praza@Sun.COM 
11407887SLiane.Praza@Sun.COM 	prop = property_find(prop_pattern,
11417887SLiane.Praza@Sun.COM 	    SCF_PROPERTY_TM_CARDINALITY_MAX);
11427887SLiane.Praza@Sun.COM 	if (prop == NULL)
11437887SLiane.Praza@Sun.COM 		return (TVS_NOMATCH);
11447887SLiane.Praza@Sun.COM 	rc = find_count_value(prop, max);
11457887SLiane.Praza@Sun.COM 
11467887SLiane.Praza@Sun.COM 	return (rc);
11477887SLiane.Praza@Sun.COM }
11487887SLiane.Praza@Sun.COM 
11497887SLiane.Praza@Sun.COM /*
11507887SLiane.Praza@Sun.COM  * Ranges are represented as ASTRING values in the property at range_prop.
11517887SLiane.Praza@Sun.COM  * The minimum and maximum of the range are separated by a comma.
11527887SLiane.Praza@Sun.COM  *
11537887SLiane.Praza@Sun.COM  * range_prop can contain multiple range values, so we return a pointer to
11547887SLiane.Praza@Sun.COM  * an allocated array of range_t in ranges.  This array must be freed by
11557887SLiane.Praza@Sun.COM  * the caller using free().  count receives the number of range_t
11567887SLiane.Praza@Sun.COM  * structures that are allocated.
11577887SLiane.Praza@Sun.COM  *
11587887SLiane.Praza@Sun.COM  * type tells us whether the range values should be treated as signed or
11597887SLiane.Praza@Sun.COM  * unsigned.  It must be SCF_TYPE_COUNT or SCF_TYPE_INTEGER.
11607887SLiane.Praza@Sun.COM  */
11617887SLiane.Praza@Sun.COM static tmpl_validate_status_t
get_ranges(property_t * range_prop,scf_type_t type,range_t ** ranges,uint_t * count)11627887SLiane.Praza@Sun.COM get_ranges(property_t *range_prop, scf_type_t type, range_t **ranges,
11637887SLiane.Praza@Sun.COM     uint_t *count)
11647887SLiane.Praza@Sun.COM {
11657887SLiane.Praza@Sun.COM 	char *endptr;
11667887SLiane.Praza@Sun.COM 	char *endptr2;
11677887SLiane.Praza@Sun.COM 	range_t *r;
11687887SLiane.Praza@Sun.COM 	value_t *value;
11697887SLiane.Praza@Sun.COM 
11707887SLiane.Praza@Sun.COM 	*count = uu_list_numnodes(range_prop->sc_property_values);
11717887SLiane.Praza@Sun.COM 	assert(*count != 0);
11727887SLiane.Praza@Sun.COM 	r = safe_malloc(*count * sizeof (*r));
11737887SLiane.Praza@Sun.COM 	*ranges = r;
11747887SLiane.Praza@Sun.COM 	for (value = uu_list_first(range_prop->sc_property_values);
11757887SLiane.Praza@Sun.COM 	    value != NULL;
11767887SLiane.Praza@Sun.COM 	    value = uu_list_next(range_prop->sc_property_values, value)) {
11777887SLiane.Praza@Sun.COM 		assert(value->sc_type == SCF_TYPE_ASTRING);
11787887SLiane.Praza@Sun.COM 
11797887SLiane.Praza@Sun.COM 		/* First get the minimum */
11807887SLiane.Praza@Sun.COM 		errno = 0;
11817887SLiane.Praza@Sun.COM 		if (type == SCF_TYPE_INTEGER) {
11827887SLiane.Praza@Sun.COM 			r->rng_u.rng_signed.rng_min =
11837887SLiane.Praza@Sun.COM 			    strtoll(value->sc_u.sc_string, &endptr, 0);
11847887SLiane.Praza@Sun.COM 		} else {
11857887SLiane.Praza@Sun.COM 			r->rng_u.rng_unsigned.rng_min =
11867887SLiane.Praza@Sun.COM 			    strtoull(value->sc_u.sc_string, &endptr, 0);
11877887SLiane.Praza@Sun.COM 		}
11887887SLiane.Praza@Sun.COM 		if ((errno != 0) || (endptr == value->sc_u.sc_string))
11897887SLiane.Praza@Sun.COM 			goto badtemplate;
11907887SLiane.Praza@Sun.COM 		if (*endptr != ',')
11917887SLiane.Praza@Sun.COM 			goto badtemplate;
11927887SLiane.Praza@Sun.COM 
11937887SLiane.Praza@Sun.COM 		/* Now get the maximum */
11947887SLiane.Praza@Sun.COM 		endptr++;
11957887SLiane.Praza@Sun.COM 		if (type == SCF_TYPE_INTEGER) {
11967887SLiane.Praza@Sun.COM 			r->rng_u.rng_signed.rng_max =
11977887SLiane.Praza@Sun.COM 			    strtoll(endptr, &endptr2, 0);
11987887SLiane.Praza@Sun.COM 		} else {
11997887SLiane.Praza@Sun.COM 			r->rng_u.rng_unsigned.rng_max =
12007887SLiane.Praza@Sun.COM 			    strtoull(endptr, &endptr2, 0);
12017887SLiane.Praza@Sun.COM 		}
12027887SLiane.Praza@Sun.COM 		if ((errno != 0) || (endptr2 == endptr) ||
12037887SLiane.Praza@Sun.COM 		    (*endptr2 != 0))
12047887SLiane.Praza@Sun.COM 			goto badtemplate;
12057887SLiane.Praza@Sun.COM 		r++;
12067887SLiane.Praza@Sun.COM 	}
12077887SLiane.Praza@Sun.COM 
12087887SLiane.Praza@Sun.COM 	return (TVS_SUCCESS);
12097887SLiane.Praza@Sun.COM 
12107887SLiane.Praza@Sun.COM badtemplate:
12117887SLiane.Praza@Sun.COM 	free(*ranges);
12127887SLiane.Praza@Sun.COM 	*ranges = NULL;
12137887SLiane.Praza@Sun.COM 	return (TVS_BAD_TEMPLATE);
12147887SLiane.Praza@Sun.COM }
12157887SLiane.Praza@Sun.COM 
12167887SLiane.Praza@Sun.COM static tv_errors_t *
tv_errors_create(const char * fmri)12177887SLiane.Praza@Sun.COM tv_errors_create(const char *fmri)
12187887SLiane.Praza@Sun.COM {
12197887SLiane.Praza@Sun.COM 	tv_errors_t *ste;
12207887SLiane.Praza@Sun.COM 
12217887SLiane.Praza@Sun.COM 	ste = safe_malloc(sizeof (*ste));
12227887SLiane.Praza@Sun.COM 	uu_list_node_init(ste, &ste->tve_node, tv_errors_pool);
12237887SLiane.Praza@Sun.COM 	ste->tve_errors = _scf_create_errors(fmri, 1);
12247887SLiane.Praza@Sun.COM 	if (ste->tve_errors == NULL)
12257887SLiane.Praza@Sun.COM 		uu_die(emesg_nomem);
12267887SLiane.Praza@Sun.COM 
12277887SLiane.Praza@Sun.COM 	return (ste);
12287887SLiane.Praza@Sun.COM }
12297887SLiane.Praza@Sun.COM 
12307887SLiane.Praza@Sun.COM static void
destroy_scf_errors(tv_errors_t * ste)12317887SLiane.Praza@Sun.COM destroy_scf_errors(tv_errors_t *ste)
12327887SLiane.Praza@Sun.COM {
12337887SLiane.Praza@Sun.COM 	scf_tmpl_errors_destroy(ste->tve_errors);
12347887SLiane.Praza@Sun.COM 	uu_list_node_fini(ste, &ste->tve_node, tv_errors_pool);
12357887SLiane.Praza@Sun.COM 	free(ste);
12367887SLiane.Praza@Sun.COM }
12377887SLiane.Praza@Sun.COM 
12387887SLiane.Praza@Sun.COM /*
12397887SLiane.Praza@Sun.COM  * Given a property group and the name of a property within that property
12407887SLiane.Praza@Sun.COM  * group, generate the name of the property group that holds the
12417887SLiane.Praza@Sun.COM  * prop_pattern information for the property.  The address of the generated
12427887SLiane.Praza@Sun.COM  * name is returned to prop_pattern_pg_name.  The memory holding the
12437887SLiane.Praza@Sun.COM  * generated name must be freed using uu_free().
12447887SLiane.Praza@Sun.COM  */
12457887SLiane.Praza@Sun.COM static tmpl_validate_status_t
gen_prop_pattern_pg_name(pgroup_t * pg_pattern,const char * prop_name,char ** prop_pattern_pg_name)12467887SLiane.Praza@Sun.COM gen_prop_pattern_pg_name(pgroup_t *pg_pattern, const char *prop_name,
12477887SLiane.Praza@Sun.COM     char **prop_pattern_pg_name)
12487887SLiane.Praza@Sun.COM {
12497887SLiane.Praza@Sun.COM 	ssize_t limit;
12507887SLiane.Praza@Sun.COM 	char *name;
12517887SLiane.Praza@Sun.COM 	size_t prefix_size;
12527887SLiane.Praza@Sun.COM 	const char *unique;
12537887SLiane.Praza@Sun.COM 
12547887SLiane.Praza@Sun.COM 	limit = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
12557887SLiane.Praza@Sun.COM 	assert(limit > 0);
12567887SLiane.Praza@Sun.COM 
12577887SLiane.Praza@Sun.COM 	/* Get the unique part of the pg_pattern's property group name. */
12587887SLiane.Praza@Sun.COM 	prefix_size = strlen(SCF_PG_TM_PG_PAT_BASE);
12597887SLiane.Praza@Sun.COM 	assert(strncmp(pg_pattern->sc_pgroup_name, SCF_PG_TM_PG_PAT_BASE,
12607887SLiane.Praza@Sun.COM 	    prefix_size) == 0);
12617887SLiane.Praza@Sun.COM 	unique = pg_pattern->sc_pgroup_name + prefix_size;
12627887SLiane.Praza@Sun.COM 
12637887SLiane.Praza@Sun.COM 	/* Construct the prop pattern property group name. */
12647887SLiane.Praza@Sun.COM 	*prop_pattern_pg_name = NULL;
12657887SLiane.Praza@Sun.COM 	name = uu_zalloc(limit);
12667887SLiane.Praza@Sun.COM 	if (name == NULL)
12677887SLiane.Praza@Sun.COM 		uu_die(emesg_nomem);
12687887SLiane.Praza@Sun.COM 	if (snprintf(name, limit, "%s%s_%s", SCF_PG_TM_PROP_PATTERN_PREFIX,
12697887SLiane.Praza@Sun.COM 	    unique, prop_name) >= limit) {
12707887SLiane.Praza@Sun.COM 		uu_free(name);
12717887SLiane.Praza@Sun.COM 		return (TVS_BAD_TEMPLATE);
12727887SLiane.Praza@Sun.COM 	}
12737887SLiane.Praza@Sun.COM 	*prop_pattern_pg_name = name;
12747887SLiane.Praza@Sun.COM 	return (TVS_SUCCESS);
12757887SLiane.Praza@Sun.COM }
12767887SLiane.Praza@Sun.COM 
12777887SLiane.Praza@Sun.COM /*
12787887SLiane.Praza@Sun.COM  * Error message printing functions:
12797887SLiane.Praza@Sun.COM  */
12807887SLiane.Praza@Sun.COM 
12817887SLiane.Praza@Sun.COM /*
12827887SLiane.Praza@Sun.COM  * Flags for use by im_perror_item.
12837887SLiane.Praza@Sun.COM  */
12847887SLiane.Praza@Sun.COM #define	IPI_NOT_FIRST	0x1	/* Not first item to be displayed. */
12857887SLiane.Praza@Sun.COM 
12867887SLiane.Praza@Sun.COM /*
12877887SLiane.Praza@Sun.COM  * Print a single item of information about a validation failure.  This
12887887SLiane.Praza@Sun.COM  * function takes care of printing the appropriate decoration before the
12897887SLiane.Praza@Sun.COM  * first item and between subsequent items.
12907887SLiane.Praza@Sun.COM  *
12917887SLiane.Praza@Sun.COM  * Parameters:
12927887SLiane.Praza@Sun.COM  *	out		Stream to receive the output.
12937887SLiane.Praza@Sun.COM  *	desc		Text describing the items
12947887SLiane.Praza@Sun.COM  *	item		Address of the item to be displayed
12957887SLiane.Praza@Sun.COM  *	type		Type of the item
12967887SLiane.Praza@Sun.COM  *	flags		Used by im_perror_item to keep track of where it
12977887SLiane.Praza@Sun.COM  *			is.  Caller should set flags to 0 before calling
12987887SLiane.Praza@Sun.COM  *			this function with the first item.
12997887SLiane.Praza@Sun.COM  */
13007887SLiane.Praza@Sun.COM static void
im_perror_item(FILE * out,const char * desc,void * item,scf_type_t type,int * flags)13017887SLiane.Praza@Sun.COM im_perror_item(FILE *out, const char *desc, void *item, scf_type_t type,
13027887SLiane.Praza@Sun.COM     int *flags)
13037887SLiane.Praza@Sun.COM {
13047887SLiane.Praza@Sun.COM 	const char *cp;
13057887SLiane.Praza@Sun.COM 	const char *first_sep;
13067887SLiane.Praza@Sun.COM 	int64_t ival;
13077887SLiane.Praza@Sun.COM 	const char *subsequent_sep;
13087887SLiane.Praza@Sun.COM 	uint64_t uval;
13097887SLiane.Praza@Sun.COM 
13107887SLiane.Praza@Sun.COM 	/* Nothing to print if item is NULL. */
13117887SLiane.Praza@Sun.COM 	if (item == NULL)
13127887SLiane.Praza@Sun.COM 		return;
13137887SLiane.Praza@Sun.COM 
13147887SLiane.Praza@Sun.COM 	assert(type != SCF_TYPE_INVALID);
13157887SLiane.Praza@Sun.COM 
13167887SLiane.Praza@Sun.COM 	/* Establish separators for environment. */
13177887SLiane.Praza@Sun.COM 	if (est->sc_cmd_flags & SC_CMD_IACTIVE) {
13187887SLiane.Praza@Sun.COM 		/* Interactive mode - make messages readable */
13197887SLiane.Praza@Sun.COM 		first_sep = ":\n\t";
13207887SLiane.Praza@Sun.COM 		subsequent_sep = "\n\t";
13217887SLiane.Praza@Sun.COM 	} else {
13227887SLiane.Praza@Sun.COM 		/* Non-interactive - one line messages. */
13237887SLiane.Praza@Sun.COM 		first_sep = ": ";
13247887SLiane.Praza@Sun.COM 		subsequent_sep = "; ";
13257887SLiane.Praza@Sun.COM 	}
13267887SLiane.Praza@Sun.COM 
13277887SLiane.Praza@Sun.COM 	/* Print separator and description */
13287887SLiane.Praza@Sun.COM 	if (*flags & IPI_NOT_FIRST) {
13297887SLiane.Praza@Sun.COM 		(void) fprintf(out, subsequent_sep);
13307887SLiane.Praza@Sun.COM 	} else {
13317887SLiane.Praza@Sun.COM 		(void) fprintf(out, first_sep);
13327887SLiane.Praza@Sun.COM 		*flags |= IPI_NOT_FIRST;
13337887SLiane.Praza@Sun.COM 	}
13347887SLiane.Praza@Sun.COM 	(void) fprintf(out, "%s=", desc);
13357887SLiane.Praza@Sun.COM 
13367887SLiane.Praza@Sun.COM 	switch (type) {
13377887SLiane.Praza@Sun.COM 	case SCF_TYPE_BOOLEAN:
13387887SLiane.Praza@Sun.COM 		uval = *((uint64_t *)item);
13397887SLiane.Praza@Sun.COM 		if (uval) {
13407887SLiane.Praza@Sun.COM 			(void) fprintf(out, "\"%s\"", gettext("true"));
13417887SLiane.Praza@Sun.COM 		} else {
13427887SLiane.Praza@Sun.COM 			(void) fprintf(out, "\"%s\"", gettext("false"));
13437887SLiane.Praza@Sun.COM 		}
13447887SLiane.Praza@Sun.COM 		break;
13457887SLiane.Praza@Sun.COM 	case SCF_TYPE_COUNT:
13467887SLiane.Praza@Sun.COM 		uval = *((uint64_t *)item);
13477887SLiane.Praza@Sun.COM 		(void) fprintf(out, "%" PRIu64, uval);
13487887SLiane.Praza@Sun.COM 		break;
13497887SLiane.Praza@Sun.COM 	case SCF_TYPE_INTEGER:
13507887SLiane.Praza@Sun.COM 		ival = *((int64_t *)item);
13517887SLiane.Praza@Sun.COM 		(void) fprintf(out, "%" PRIi64, ival);
13527887SLiane.Praza@Sun.COM 		break;
13537887SLiane.Praza@Sun.COM 	default:
13547887SLiane.Praza@Sun.COM 		/*
13557887SLiane.Praza@Sun.COM 		 * Treat everything else as a string, but escape any
13567887SLiane.Praza@Sun.COM 		 * internal quotes.
13577887SLiane.Praza@Sun.COM 		 */
13587887SLiane.Praza@Sun.COM 		(void) fputc('\"', out);
13597887SLiane.Praza@Sun.COM 		cp = (const char *)item;
13607887SLiane.Praza@Sun.COM 		while (*cp != 0) {
13617887SLiane.Praza@Sun.COM 			if (*cp == '\"') {
13627887SLiane.Praza@Sun.COM 				(void) fprintf(out, "\\\"");
13637887SLiane.Praza@Sun.COM 			} else {
13647887SLiane.Praza@Sun.COM 				(void) fputc(*cp, out);
13657887SLiane.Praza@Sun.COM 			}
13667887SLiane.Praza@Sun.COM 			cp++;
13677887SLiane.Praza@Sun.COM 		}
13687887SLiane.Praza@Sun.COM 		(void) fputc('\"', out);
13697887SLiane.Praza@Sun.COM 		break;
13707887SLiane.Praza@Sun.COM 	}
13717887SLiane.Praza@Sun.COM }
13727887SLiane.Praza@Sun.COM 
13737887SLiane.Praza@Sun.COM /*
13747887SLiane.Praza@Sun.COM  * Print erroneous FMRI.
13757887SLiane.Praza@Sun.COM  */
13767887SLiane.Praza@Sun.COM static void
im_perror_fmri(FILE * out,im_tmpl_error_t * i,int * flags)13777887SLiane.Praza@Sun.COM im_perror_fmri(FILE *out, im_tmpl_error_t *i, int *flags)
13787887SLiane.Praza@Sun.COM {
13797887SLiane.Praza@Sun.COM 	if (i->ite_entity != NULL) {
13807887SLiane.Praza@Sun.COM 		im_perror_item(out, "FMRI", (void *)i->ite_entity->sc_fmri,
13817887SLiane.Praza@Sun.COM 		    SCF_TYPE_FMRI, flags);
13827887SLiane.Praza@Sun.COM 	}
13837887SLiane.Praza@Sun.COM }
13847887SLiane.Praza@Sun.COM 
13857887SLiane.Praza@Sun.COM /*
13867887SLiane.Praza@Sun.COM  * Print erroneous property group name.
13877887SLiane.Praza@Sun.COM  */
13887887SLiane.Praza@Sun.COM static void
im_perror_pg_name(FILE * out,im_tmpl_error_t * i,int * flags)13897887SLiane.Praza@Sun.COM im_perror_pg_name(FILE *out, im_tmpl_error_t *i, int *flags)
13907887SLiane.Praza@Sun.COM {
13917887SLiane.Praza@Sun.COM 	if (i->ite_pg != NULL) {
13927887SLiane.Praza@Sun.COM 		im_perror_item(out, gettext("Property group"),
13937887SLiane.Praza@Sun.COM 		    (void *)i->ite_pg->sc_pgroup_name, SCF_TYPE_ASTRING,
13947887SLiane.Praza@Sun.COM 		    flags);
13957887SLiane.Praza@Sun.COM 	}
13967887SLiane.Praza@Sun.COM }
13977887SLiane.Praza@Sun.COM 
13987887SLiane.Praza@Sun.COM /*
13997887SLiane.Praza@Sun.COM  * If srcflag is 1, print the template source of the pg_pattern or
14007887SLiane.Praza@Sun.COM  * prop_pattern at pattern.  Always print the name and type of the pattern.
14017887SLiane.Praza@Sun.COM  */
14027887SLiane.Praza@Sun.COM static void
im_perror_pattern_info(FILE * out,pgroup_t * pattern,int * flags,int srcflag)14037887SLiane.Praza@Sun.COM im_perror_pattern_info(FILE *out, pgroup_t *pattern, int *flags, int srcflag)
14047887SLiane.Praza@Sun.COM {
14057887SLiane.Praza@Sun.COM 	void *c;
14067887SLiane.Praza@Sun.COM 	const char *name_string;
14077887SLiane.Praza@Sun.COM 	const char *type_string;
14087887SLiane.Praza@Sun.COM 
14097887SLiane.Praza@Sun.COM 	if (pattern == NULL)
14107887SLiane.Praza@Sun.COM 		return;
14117887SLiane.Praza@Sun.COM 	switch (pgroup_type(pattern)) {
14127887SLiane.Praza@Sun.COM 	case PG_PATTERN_PG:
14137887SLiane.Praza@Sun.COM 		name_string = gettext("pg_pattern name");
14147887SLiane.Praza@Sun.COM 		type_string = gettext("pg_pattern type");
14157887SLiane.Praza@Sun.COM 		break;
14167887SLiane.Praza@Sun.COM 	case PROP_PATTERN_PG:
14177887SLiane.Praza@Sun.COM 		name_string = gettext("prop_pattern name");
14187887SLiane.Praza@Sun.COM 		type_string = gettext("prop_pattern type");
14197887SLiane.Praza@Sun.COM 		break;
14207887SLiane.Praza@Sun.COM 	default:
14217887SLiane.Praza@Sun.COM 		assert(0);
14227887SLiane.Praza@Sun.COM 		abort();
14237887SLiane.Praza@Sun.COM 	}
14247887SLiane.Praza@Sun.COM 	if (srcflag) {
14257887SLiane.Praza@Sun.COM 		im_perror_item(out, gettext("Template source"),
14267887SLiane.Praza@Sun.COM 		    (void *)pattern->sc_parent->sc_fmri, SCF_TYPE_FMRI, flags);
14277887SLiane.Praza@Sun.COM 	}
14287887SLiane.Praza@Sun.COM 	c = (void *)find_name_specification(pattern);
14297887SLiane.Praza@Sun.COM 	im_perror_item(out, name_string,
14307887SLiane.Praza@Sun.COM 	    (c == NULL) ? "" : c, SCF_TYPE_ASTRING, flags);
14317887SLiane.Praza@Sun.COM 	c = (void *)find_type_specification(pattern);
14327887SLiane.Praza@Sun.COM 	im_perror_item(out, type_string,
14337887SLiane.Praza@Sun.COM 	    (c == NULL) ? "" : c, SCF_TYPE_ASTRING, flags);
14347887SLiane.Praza@Sun.COM }
14357887SLiane.Praza@Sun.COM 
14367887SLiane.Praza@Sun.COM /*
14377887SLiane.Praza@Sun.COM  * Print information about the template specifications that were violated,
14387887SLiane.Praza@Sun.COM  * so that the user can find the specification.
14397887SLiane.Praza@Sun.COM  */
14407887SLiane.Praza@Sun.COM static void
im_perror_template_info(FILE * out,im_tmpl_error_t * i,int * flags)14417887SLiane.Praza@Sun.COM im_perror_template_info(FILE *out, im_tmpl_error_t *i, int *flags)
14427887SLiane.Praza@Sun.COM {
14437887SLiane.Praza@Sun.COM 	pgroup_t *pg_pattern = i->ite_pg_pattern;
14447887SLiane.Praza@Sun.COM 	pgroup_t *prop_pattern = i->ite_prop_pattern;
14457887SLiane.Praza@Sun.COM 	int srcflag = 1;
14467887SLiane.Praza@Sun.COM 
14477887SLiane.Praza@Sun.COM 	if (pg_pattern != NULL) {
14487887SLiane.Praza@Sun.COM 		im_perror_pattern_info(out, pg_pattern, flags, srcflag);
14497887SLiane.Praza@Sun.COM 		srcflag = 0;
14507887SLiane.Praza@Sun.COM 	}
14517887SLiane.Praza@Sun.COM 	if (prop_pattern != NULL) {
14527887SLiane.Praza@Sun.COM 		im_perror_pattern_info(out, prop_pattern, flags, srcflag);
14537887SLiane.Praza@Sun.COM 	}
14547887SLiane.Praza@Sun.COM }
14557887SLiane.Praza@Sun.COM 
14567887SLiane.Praza@Sun.COM /* Print error message for TVS_BAD_CONVERSION errors. */
14577887SLiane.Praza@Sun.COM static void
im_perror_bad_conversion(FILE * out,im_tmpl_error_t * i,const char * prefix)14587887SLiane.Praza@Sun.COM im_perror_bad_conversion(FILE *out, im_tmpl_error_t *i, const char *prefix)
14597887SLiane.Praza@Sun.COM {
14607887SLiane.Praza@Sun.COM 	int flags = 0;
14617887SLiane.Praza@Sun.COM 
14627887SLiane.Praza@Sun.COM 	(void) fprintf(out, gettext("%sUnable to convert property value"),
14637887SLiane.Praza@Sun.COM 	    prefix);
14647887SLiane.Praza@Sun.COM 	im_perror_fmri(out, i, &flags);
14657887SLiane.Praza@Sun.COM 	im_perror_pg_name(out, i, &flags);
14667887SLiane.Praza@Sun.COM 	im_perror_item(out, gettext("Property"),
14677887SLiane.Praza@Sun.COM 	    (void *)i->ite_prop->sc_property_name, SCF_TYPE_ASTRING, &flags);
14687887SLiane.Praza@Sun.COM 	im_perror_template_info(out, i, &flags);
14697887SLiane.Praza@Sun.COM 	(void) fputc('\n', out);
14707887SLiane.Praza@Sun.COM }
14717887SLiane.Praza@Sun.COM 
14727887SLiane.Praza@Sun.COM /* Print error message for TVS_BAD_TEMPLATE errors. */
14737887SLiane.Praza@Sun.COM static void
im_perror_bad_template(FILE * out,im_tmpl_error_t * i,const char * prefix)14747887SLiane.Praza@Sun.COM im_perror_bad_template(FILE *out, im_tmpl_error_t *i, const char *prefix)
14757887SLiane.Praza@Sun.COM {
14767887SLiane.Praza@Sun.COM 	int flags = 0;
14777887SLiane.Praza@Sun.COM 
14787887SLiane.Praza@Sun.COM 	assert(i->ite_einfo.ei_type == EIT_BAD_TEMPLATE);
14797887SLiane.Praza@Sun.COM 	(void) fprintf(out, gettext("%sInvalid template - %s"), prefix,
14807887SLiane.Praza@Sun.COM 	    i->ite_einfo.ei_u.ei_bad_template.ei_reason);
14817887SLiane.Praza@Sun.COM 	im_perror_fmri(out, i, &flags);
14827887SLiane.Praza@Sun.COM 	im_perror_template_info(out, i, &flags);
14837887SLiane.Praza@Sun.COM 	(void) fputc('\n', out);
14847887SLiane.Praza@Sun.COM }
14857887SLiane.Praza@Sun.COM 
14867887SLiane.Praza@Sun.COM /*
14877887SLiane.Praza@Sun.COM  * Print error message for TVS_INVALID_TYPE_SPECIFICATION errors.  This
14887887SLiane.Praza@Sun.COM  * error occurs if a prop_pattern has an invalid type specification.  Thus,
14897887SLiane.Praza@Sun.COM  * it is an indication of an invalid template rather than a violation of a
14907887SLiane.Praza@Sun.COM  * template.
14917887SLiane.Praza@Sun.COM  */
14927887SLiane.Praza@Sun.COM static void
im_perror_invalid_type(FILE * out,im_tmpl_error_t * i,const char * prefix)14937887SLiane.Praza@Sun.COM im_perror_invalid_type(FILE *out, im_tmpl_error_t *i, const char *prefix)
14947887SLiane.Praza@Sun.COM {
14957887SLiane.Praza@Sun.COM 	int flags = 0;
14967887SLiane.Praza@Sun.COM 	const char *prop_pattern_name;
14977887SLiane.Praza@Sun.COM 
14987887SLiane.Praza@Sun.COM 	(void) fprintf(out, gettext("%sInvalid type in prop_pattern"), prefix);
14997887SLiane.Praza@Sun.COM 	im_perror_pg_name(out, i, &flags);
15007887SLiane.Praza@Sun.COM 	if (i->ite_prop_pattern != NULL) {
15017887SLiane.Praza@Sun.COM 		prop_pattern_name =
15027887SLiane.Praza@Sun.COM 		    find_name_specification(i->ite_prop_pattern);
15037887SLiane.Praza@Sun.COM 		im_perror_item(out, gettext("prop_pattern name"),
15047887SLiane.Praza@Sun.COM 		    (void *)prop_pattern_name, SCF_TYPE_ASTRING, &flags);
15057887SLiane.Praza@Sun.COM 	}
15067887SLiane.Praza@Sun.COM 	im_perror_template_info(out, i, &flags);
15077887SLiane.Praza@Sun.COM 	(void) fputc('\n', out);
15087887SLiane.Praza@Sun.COM }
15097887SLiane.Praza@Sun.COM 
15107887SLiane.Praza@Sun.COM /*
15117887SLiane.Praza@Sun.COM  * Print error message for TVS_MISSING_PG_TYPE errors.  In this case the
15127887SLiane.Praza@Sun.COM  * template specifies a type, but the property group itself has no type.
15137887SLiane.Praza@Sun.COM  */
15147887SLiane.Praza@Sun.COM static void
im_perror_missing_pg_type(FILE * out,im_tmpl_error_t * i,const char * prefix)15157887SLiane.Praza@Sun.COM im_perror_missing_pg_type(FILE *out, im_tmpl_error_t *i, const char *prefix)
15167887SLiane.Praza@Sun.COM {
15177887SLiane.Praza@Sun.COM 	int flags = 0;
15187887SLiane.Praza@Sun.COM 	const char *type_spec;
15197887SLiane.Praza@Sun.COM 
15207887SLiane.Praza@Sun.COM 	(void) fprintf(out, gettext("%sProperty group has no type"), prefix);
15217887SLiane.Praza@Sun.COM 	im_perror_fmri(out, i, &flags);
15227887SLiane.Praza@Sun.COM 	im_perror_pg_name(out, i, &flags);
15237887SLiane.Praza@Sun.COM 	if (i->ite_pg_pattern != NULL) {
15247887SLiane.Praza@Sun.COM 		type_spec = find_type_specification(i->ite_pg_pattern);
15257887SLiane.Praza@Sun.COM 		im_perror_item(out, gettext("Type specified in pg_pattern"),
15267887SLiane.Praza@Sun.COM 		    (void *)type_spec, SCF_TYPE_ASTRING, &flags);
15277887SLiane.Praza@Sun.COM 	}
15287887SLiane.Praza@Sun.COM 	(void) fputc('\n', out);
15297887SLiane.Praza@Sun.COM }
15307887SLiane.Praza@Sun.COM 
15317887SLiane.Praza@Sun.COM /*
15327887SLiane.Praza@Sun.COM  * Print error message for TVS_MISSING_TYPE_SPECIFICATION errors.  A
15337887SLiane.Praza@Sun.COM  * property group has a "required" attribute of true, but it does not have
15347887SLiane.Praza@Sun.COM  * a type specification.
15357887SLiane.Praza@Sun.COM  */
15367887SLiane.Praza@Sun.COM static void
im_perror_missing_type(FILE * out,im_tmpl_error_t * i,const char * prefix)15377887SLiane.Praza@Sun.COM im_perror_missing_type(FILE *out, im_tmpl_error_t *i, const char *prefix)
15387887SLiane.Praza@Sun.COM {
15397887SLiane.Praza@Sun.COM 	int flags = 0;
15407887SLiane.Praza@Sun.COM 	const char *pg_pattern_name;
15417887SLiane.Praza@Sun.COM 
15427887SLiane.Praza@Sun.COM 	(void) fprintf(out, gettext("%sPg_pattern with true required attribute "
15437887SLiane.Praza@Sun.COM 	    "is missing the type attribute"), prefix);
15447887SLiane.Praza@Sun.COM 	im_perror_fmri(out, i, &flags);
15457887SLiane.Praza@Sun.COM 	if (i->ite_pg_pattern != NULL) {
15467887SLiane.Praza@Sun.COM 		pg_pattern_name = find_name_specification(i->ite_pg_pattern);
15477887SLiane.Praza@Sun.COM 		im_perror_item(out, gettext("Pg_pattern name"),
15487887SLiane.Praza@Sun.COM 		    (void *)pg_pattern_name, SCF_TYPE_ASTRING, &flags);
15497887SLiane.Praza@Sun.COM 	}
15507887SLiane.Praza@Sun.COM 	im_perror_template_info(out, i, &flags);
15517887SLiane.Praza@Sun.COM 	(void) fputc('\n', out);
15527887SLiane.Praza@Sun.COM }
15537887SLiane.Praza@Sun.COM 
15547887SLiane.Praza@Sun.COM static void
im_tmpl_error_print(FILE * out,im_tmpl_error_t * ite,const char * prefix)15557887SLiane.Praza@Sun.COM im_tmpl_error_print(FILE *out, im_tmpl_error_t *ite, const char *prefix)
15567887SLiane.Praza@Sun.COM {
15577887SLiane.Praza@Sun.COM 	switch (ite->ite_type) {
15587887SLiane.Praza@Sun.COM 	case TVS_BAD_CONVERSION:
15597887SLiane.Praza@Sun.COM 		im_perror_bad_conversion(out, ite, prefix);
15607887SLiane.Praza@Sun.COM 		break;
15617887SLiane.Praza@Sun.COM 	case TVS_BAD_TEMPLATE:
15627887SLiane.Praza@Sun.COM 		im_perror_bad_template(out, ite, prefix);
15637887SLiane.Praza@Sun.COM 		break;
15647887SLiane.Praza@Sun.COM 	case TVS_INVALID_TYPE_SPECIFICATION:
15657887SLiane.Praza@Sun.COM 		im_perror_invalid_type(out, ite, prefix);
15667887SLiane.Praza@Sun.COM 		break;
15677887SLiane.Praza@Sun.COM 	case TVS_MISSING_PG_TYPE:
15687887SLiane.Praza@Sun.COM 		im_perror_missing_pg_type(out, ite, prefix);
15697887SLiane.Praza@Sun.COM 		break;
15707887SLiane.Praza@Sun.COM 	case TVS_MISSING_TYPE_SPECIFICATION:
15717887SLiane.Praza@Sun.COM 		im_perror_missing_type(out, ite, prefix);
15727887SLiane.Praza@Sun.COM 		break;
15737887SLiane.Praza@Sun.COM 	case TVS_NOMATCH:
15747887SLiane.Praza@Sun.COM 		/*
15757887SLiane.Praza@Sun.COM 		 * TVS_NOMATCH should be handled where it occurs.  Thus,
15767887SLiane.Praza@Sun.COM 		 * there are no error messages associated with it.
15777887SLiane.Praza@Sun.COM 		 */
15787887SLiane.Praza@Sun.COM 		assert(0);
15797887SLiane.Praza@Sun.COM 		abort();
15807887SLiane.Praza@Sun.COM 		break;
15817887SLiane.Praza@Sun.COM 	case TVS_SUCCESS:
15827887SLiane.Praza@Sun.COM 		break;
15837887SLiane.Praza@Sun.COM 	default:
15847887SLiane.Praza@Sun.COM 		assert(0);
15857887SLiane.Praza@Sun.COM 		abort();
15867887SLiane.Praza@Sun.COM 	}
15877887SLiane.Praza@Sun.COM }
15887887SLiane.Praza@Sun.COM 
15897887SLiane.Praza@Sun.COM static char *
int64_to_str(int64_t i)15907887SLiane.Praza@Sun.COM int64_to_str(int64_t i)
15917887SLiane.Praza@Sun.COM {
15927887SLiane.Praza@Sun.COM 	char *c;
15937887SLiane.Praza@Sun.COM 	const char *fmt;
15947887SLiane.Praza@Sun.COM 	int size;
15957887SLiane.Praza@Sun.COM 
15967887SLiane.Praza@Sun.COM 	fmt = "%" PRIi64;
15977887SLiane.Praza@Sun.COM 	size = snprintf(NULL, 0, fmt, i) + 1;
15987887SLiane.Praza@Sun.COM 	c = safe_malloc(size);
15997887SLiane.Praza@Sun.COM 	(void) snprintf(c, size, fmt, i);
16007887SLiane.Praza@Sun.COM 	return (c);
16017887SLiane.Praza@Sun.COM }
16027887SLiane.Praza@Sun.COM 
16037887SLiane.Praza@Sun.COM static char *
uint64_to_str(uint64_t u)16047887SLiane.Praza@Sun.COM uint64_to_str(uint64_t u)
16057887SLiane.Praza@Sun.COM {
16067887SLiane.Praza@Sun.COM 	char *c;
16077887SLiane.Praza@Sun.COM 	const char *fmt;
16087887SLiane.Praza@Sun.COM 	int size;
16097887SLiane.Praza@Sun.COM 
16107887SLiane.Praza@Sun.COM 	fmt = "%" PRIu64;
16117887SLiane.Praza@Sun.COM 	size = snprintf(NULL, 0, fmt, u) + 1;
16127887SLiane.Praza@Sun.COM 	c = safe_malloc(size);
16137887SLiane.Praza@Sun.COM 	(void) snprintf(c, size, fmt, u);
16147887SLiane.Praza@Sun.COM 	return (c);
16157887SLiane.Praza@Sun.COM }
16167887SLiane.Praza@Sun.COM 
16177887SLiane.Praza@Sun.COM /*
16187887SLiane.Praza@Sun.COM  * Convert the value to a string.  The returned value must be freed using
16197887SLiane.Praza@Sun.COM  * free(3C).
16207887SLiane.Praza@Sun.COM  */
16217887SLiane.Praza@Sun.COM static const char *
value_to_string(value_t * v)16227887SLiane.Praza@Sun.COM value_to_string(value_t *v)
16237887SLiane.Praza@Sun.COM {
16247887SLiane.Praza@Sun.COM 	char *c;
16257887SLiane.Praza@Sun.COM 
16267887SLiane.Praza@Sun.COM 	if (is_numeric_type(v->sc_type)) {
16277887SLiane.Praza@Sun.COM 		switch (v->sc_type) {
16287887SLiane.Praza@Sun.COM 		case SCF_TYPE_BOOLEAN:
16297887SLiane.Praza@Sun.COM 			if (v->sc_u.sc_count == 0) {
16307887SLiane.Praza@Sun.COM 				c = gettext("false");
16317887SLiane.Praza@Sun.COM 			} else {
16327887SLiane.Praza@Sun.COM 				c = gettext("true");
16337887SLiane.Praza@Sun.COM 			}
16347887SLiane.Praza@Sun.COM 			break;
16357887SLiane.Praza@Sun.COM 		case SCF_TYPE_COUNT:
16367887SLiane.Praza@Sun.COM 			c = uint64_to_str(v->sc_u.sc_count);
16377887SLiane.Praza@Sun.COM 			return (c);
16387887SLiane.Praza@Sun.COM 		case SCF_TYPE_INTEGER:
16397887SLiane.Praza@Sun.COM 			c = int64_to_str(v->sc_u.sc_integer);
16407887SLiane.Praza@Sun.COM 			return (c);
16417887SLiane.Praza@Sun.COM 		}
16427887SLiane.Praza@Sun.COM 	} else {
16437887SLiane.Praza@Sun.COM 		c = v->sc_u.sc_string;
16447887SLiane.Praza@Sun.COM 	}
16457887SLiane.Praza@Sun.COM 
16467887SLiane.Praza@Sun.COM 	return (safe_strdup(c));
16477887SLiane.Praza@Sun.COM }
16487887SLiane.Praza@Sun.COM 
16497887SLiane.Praza@Sun.COM /*
16507887SLiane.Praza@Sun.COM  * Subscripts for common error data.
16517887SLiane.Praza@Sun.COM  */
16527887SLiane.Praza@Sun.COM #define	ED_PG_NAME	0
16537887SLiane.Praza@Sun.COM #define	ED_PROP_NAME	1
16547887SLiane.Praza@Sun.COM #define	ED_TMPL_FMRI	2
16557887SLiane.Praza@Sun.COM #define	ED_TMPL_PG_NAME	3
16567887SLiane.Praza@Sun.COM #define	ED_TMPL_PG_TYPE	4
16577887SLiane.Praza@Sun.COM #define	ED_TMPL_PROP_NAME	5
16587887SLiane.Praza@Sun.COM #define	ED_TMPL_PROP_TYPE	6
16597887SLiane.Praza@Sun.COM #define	ED_COUNT	7
16607887SLiane.Praza@Sun.COM 
16617887SLiane.Praza@Sun.COM /*
16627887SLiane.Praza@Sun.COM  * This function converts the error information specified by the function
16637887SLiane.Praza@Sun.COM  * parameters.  It converts it to form needed by _scf_tmpl_add_error().
16647887SLiane.Praza@Sun.COM  * _scf_tmpl_add_error() requires that the error information be in the form
16657887SLiane.Praza@Sun.COM  * of allocated strings that can be freed when it is done with them.  Thus,
16667887SLiane.Praza@Sun.COM  * the bulk of this function is devoted to producing those allocated
16677887SLiane.Praza@Sun.COM  * strings.
16687887SLiane.Praza@Sun.COM  *
16697887SLiane.Praza@Sun.COM  * Once the strings are ready, we call _scf_tmpl_add_error() to add an
16707887SLiane.Praza@Sun.COM  * new error structure to errs.
16717887SLiane.Praza@Sun.COM  */
16727887SLiane.Praza@Sun.COM 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)16737887SLiane.Praza@Sun.COM add_scf_error(tmpl_errors_t *errs, scf_tmpl_error_type_t ec,
16747887SLiane.Praza@Sun.COM     pgroup_t *pg_pattern, pgroup_t *pg, pgroup_t *prop_pattern,
16757887SLiane.Praza@Sun.COM     property_t *prop, value_t *val, error_info_t *einfo)
16767887SLiane.Praza@Sun.COM {
16777887SLiane.Praza@Sun.COM 	const char *actual = NULL;
16787887SLiane.Praza@Sun.COM 	char *c;
16797887SLiane.Praza@Sun.COM 	pgroup_t *conflict;
16807887SLiane.Praza@Sun.COM 	const char *ed[ED_COUNT];
16817887SLiane.Praza@Sun.COM 	const char *ev1 = NULL;
16827887SLiane.Praza@Sun.COM 	const char *ev2 = NULL;
16837887SLiane.Praza@Sun.COM 	int i;
16847887SLiane.Praza@Sun.COM 	scf_type_t prop_type;
16857887SLiane.Praza@Sun.COM 	int rc;
16867887SLiane.Praza@Sun.COM 
16877887SLiane.Praza@Sun.COM 	(void) memset(ed, 0, sizeof (ed));
16887887SLiane.Praza@Sun.COM 
16897887SLiane.Praza@Sun.COM 	/* Set values that are common to most error types. */
16907887SLiane.Praza@Sun.COM 	if (pg != NULL) {
16917887SLiane.Praza@Sun.COM 		ed[ED_PG_NAME] = pg->sc_pgroup_name;
16927887SLiane.Praza@Sun.COM 	}
16937887SLiane.Praza@Sun.COM 	if (prop != NULL) {
16947887SLiane.Praza@Sun.COM 		ed[ED_PROP_NAME] = prop->sc_property_name;
16957887SLiane.Praza@Sun.COM 	}
16967887SLiane.Praza@Sun.COM 	if (pg_pattern == NULL) {
16977887SLiane.Praza@Sun.COM 		if (prop_pattern != NULL) {
16987887SLiane.Praza@Sun.COM 			ed[ED_TMPL_FMRI] = prop_pattern->sc_parent->sc_fmri;
16997887SLiane.Praza@Sun.COM 		}
17007887SLiane.Praza@Sun.COM 	} else {
17017887SLiane.Praza@Sun.COM 		ed[ED_TMPL_FMRI] = pg_pattern->sc_parent->sc_fmri;
17027887SLiane.Praza@Sun.COM 		ed[ED_TMPL_PG_NAME] = find_name_specification(pg_pattern);
17037887SLiane.Praza@Sun.COM 		ed[ED_TMPL_PG_TYPE] = find_type_specification(pg_pattern);
17047887SLiane.Praza@Sun.COM 	}
17057887SLiane.Praza@Sun.COM 	if (prop_pattern != NULL) {
17067887SLiane.Praza@Sun.COM 		ed[ED_TMPL_PROP_NAME] = find_name_specification(prop_pattern);
17077887SLiane.Praza@Sun.COM 		ed[ED_TMPL_PROP_TYPE] = find_type_specification(prop_pattern);
17087887SLiane.Praza@Sun.COM 	}
17097887SLiane.Praza@Sun.COM 
17107887SLiane.Praza@Sun.COM 	/*
17117887SLiane.Praza@Sun.COM 	 * All of the strings that we've found must be strduped.  This is
17127887SLiane.Praza@Sun.COM 	 * so that scf_tmpl_errors_destroy() can free them.  We cannot use
17137887SLiane.Praza@Sun.COM 	 * the flag argument of _scf_create_errors() to indicate that the
17147887SLiane.Praza@Sun.COM 	 * strings should not be freed.  The flag argument is an all or
17157887SLiane.Praza@Sun.COM 	 * nothing thing.  In the code below we need to convert integers to
17167887SLiane.Praza@Sun.COM 	 * strings, and this requires memory allocation.  Since we have to
17177887SLiane.Praza@Sun.COM 	 * allocate memory for that data, we need to allocate it for every
17187887SLiane.Praza@Sun.COM 	 * thing.
17197887SLiane.Praza@Sun.COM 	 */
17207887SLiane.Praza@Sun.COM 	for (i = 0; i < ED_COUNT; i++) {
17217887SLiane.Praza@Sun.COM 		if (ed[i] == NULL)
17227887SLiane.Praza@Sun.COM 			continue;
17237887SLiane.Praza@Sun.COM 		ed[i] = safe_strdup(ed[i]);
17247887SLiane.Praza@Sun.COM 	}
17257887SLiane.Praza@Sun.COM 
17267887SLiane.Praza@Sun.COM 	/* actual, ev1 and ev2 are error code specific. */
17277887SLiane.Praza@Sun.COM 	switch (ec) {
17287887SLiane.Praza@Sun.COM 	case SCF_TERR_CARDINALITY_VIOLATION:
17297887SLiane.Praza@Sun.COM 		assert(einfo != NULL);
17307887SLiane.Praza@Sun.COM 		assert(einfo->ei_type == EIT_CARDINALITY);
17317887SLiane.Praza@Sun.COM 		ev1 = uint64_to_str(einfo->ei_u.ei_cardinality.ei_min);
17327887SLiane.Praza@Sun.COM 		ev2 = uint64_to_str(einfo->ei_u.ei_cardinality.ei_max);
17337887SLiane.Praza@Sun.COM 		actual = uint64_to_str(einfo->ei_u.ei_cardinality.ei_count);
17347887SLiane.Praza@Sun.COM 		break;
17357887SLiane.Praza@Sun.COM 	case SCF_TERR_WRONG_PG_TYPE:
17367887SLiane.Praza@Sun.COM 		/* Specified type. */
17377887SLiane.Praza@Sun.COM 		if (pg_pattern != NULL) {
17387887SLiane.Praza@Sun.COM 			ev1 = find_type_specification(pg_pattern);
17397887SLiane.Praza@Sun.COM 			if (ev1 != NULL) {
17407887SLiane.Praza@Sun.COM 				ev1 = safe_strdup(ev1);
17417887SLiane.Praza@Sun.COM 			}
17427887SLiane.Praza@Sun.COM 		}
17437887SLiane.Praza@Sun.COM 		/* Actual type. */
17447887SLiane.Praza@Sun.COM 		if (pg != NULL) {
17457887SLiane.Praza@Sun.COM 			actual = pg->sc_pgroup_type;
17467887SLiane.Praza@Sun.COM 			if (actual != NULL) {
17477887SLiane.Praza@Sun.COM 				actual = safe_strdup(actual);
17487887SLiane.Praza@Sun.COM 			}
17497887SLiane.Praza@Sun.COM 		}
17507887SLiane.Praza@Sun.COM 		break;
17517887SLiane.Praza@Sun.COM 	case SCF_TERR_WRONG_PROP_TYPE:
17527887SLiane.Praza@Sun.COM 		assert(einfo->ei_type == EIT_PROP_TYPE);
17537887SLiane.Praza@Sun.COM 		prop_type = einfo->ei_u.ei_prop_type.ei_specified;
17547887SLiane.Praza@Sun.COM 		ev1 = safe_strdup(scf_type_to_string(prop_type));
17557887SLiane.Praza@Sun.COM 		prop_type = einfo->ei_u.ei_prop_type.ei_actual;
17567887SLiane.Praza@Sun.COM 		actual = safe_strdup(scf_type_to_string(prop_type));
17577887SLiane.Praza@Sun.COM 		break;
17587887SLiane.Praza@Sun.COM 	case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
17597887SLiane.Praza@Sun.COM 		actual = value_to_string(val);
17607887SLiane.Praza@Sun.COM 		break;
17617887SLiane.Praza@Sun.COM 	case SCF_TERR_MISSING_PG:
17627887SLiane.Praza@Sun.COM 		assert(einfo->ei_type == EIT_MISSING_PG);
17637887SLiane.Praza@Sun.COM 		ev1 = safe_strdup(einfo->ei_u.ei_missing_pg.ei_pg_name);
17647887SLiane.Praza@Sun.COM 		ev2 = safe_strdup(einfo->ei_u.ei_missing_pg.ei_pg_type);
17657887SLiane.Praza@Sun.COM 		break;
17667887SLiane.Praza@Sun.COM 	case SCF_TERR_MISSING_PROP:
17677887SLiane.Praza@Sun.COM 		assert(einfo->ei_type == EIT_MISSING_PROP);
17687887SLiane.Praza@Sun.COM 		ev1 = safe_strdup(einfo->ei_u.ei_missing_prop.ei_prop_name);
17697887SLiane.Praza@Sun.COM 		break;
17707887SLiane.Praza@Sun.COM 	case SCF_TERR_RANGE_VIOLATION:
17717887SLiane.Praza@Sun.COM 		assert(einfo->ei_type == EIT_RANGE);
17727887SLiane.Praza@Sun.COM 		if (einfo->ei_u.ei_range.ei_rtype == SCF_TYPE_COUNT) {
17737887SLiane.Praza@Sun.COM 			c = uint64_to_str(einfo->ei_u.ei_range.ei_uvalue);
17747887SLiane.Praza@Sun.COM 		} else {
17757887SLiane.Praza@Sun.COM 			c = int64_to_str(einfo->ei_u.ei_range.ei_ivalue);
17767887SLiane.Praza@Sun.COM 		}
17777887SLiane.Praza@Sun.COM 		actual = c;
17787887SLiane.Praza@Sun.COM 		break;
17797887SLiane.Praza@Sun.COM 	case SCF_TERR_PG_PATTERN_CONFLICT:
17807887SLiane.Praza@Sun.COM 	case SCF_TERR_PROP_PATTERN_CONFLICT:
17817887SLiane.Praza@Sun.COM 	case SCF_TERR_GENERAL_REDEFINE:
17827887SLiane.Praza@Sun.COM 		assert(einfo->ei_type == EIT_PATTERN_CONFLICT);
17837887SLiane.Praza@Sun.COM 		conflict = einfo->ei_u.ei_pattern_conflict.ei_pattern;
17847887SLiane.Praza@Sun.COM 		ev1 = safe_strdup(conflict->sc_parent->sc_fmri);
17857887SLiane.Praza@Sun.COM 		ev2 = find_name_specification(conflict);
17867887SLiane.Praza@Sun.COM 		if (ev2 != NULL)
17877887SLiane.Praza@Sun.COM 			ev2 = safe_strdup(ev2);
17887887SLiane.Praza@Sun.COM 		actual = find_type_specification(conflict);
17897887SLiane.Praza@Sun.COM 		if (actual != NULL)
17907887SLiane.Praza@Sun.COM 			actual = safe_strdup(actual);
17917887SLiane.Praza@Sun.COM 		break;
17927887SLiane.Praza@Sun.COM 	case SCF_TERR_INCLUDE_VALUES:
17937887SLiane.Praza@Sun.COM 		assert(einfo->ei_type == EIT_INCLUDE_VALUES);
17947887SLiane.Praza@Sun.COM 		ev1 = safe_strdup(einfo->ei_u.ei_inc_values.ei_type);
17957887SLiane.Praza@Sun.COM 		break;
17967887SLiane.Praza@Sun.COM 	case SCF_TERR_PG_PATTERN_INCOMPLETE:
17977887SLiane.Praza@Sun.COM 	case SCF_TERR_PROP_PATTERN_INCOMPLETE:
17987887SLiane.Praza@Sun.COM 		break;
17997887SLiane.Praza@Sun.COM 	default:
18007887SLiane.Praza@Sun.COM 		assert(0);
18017887SLiane.Praza@Sun.COM 		abort();
18027887SLiane.Praza@Sun.COM 	};
18037887SLiane.Praza@Sun.COM 
18047887SLiane.Praza@Sun.COM 	rc = _scf_tmpl_add_error(errs->te_cur_scf->tve_errors, ec,
18057887SLiane.Praza@Sun.COM 	    ed[ED_PG_NAME], ed[ED_PROP_NAME], ev1, ev2, actual,
18067887SLiane.Praza@Sun.COM 	    ed[ED_TMPL_FMRI], ed[ED_TMPL_PG_NAME], ed[ED_TMPL_PG_TYPE],
18077887SLiane.Praza@Sun.COM 	    ed[ED_TMPL_PROP_NAME], ed[ED_TMPL_PROP_TYPE]);
18087887SLiane.Praza@Sun.COM 
18097887SLiane.Praza@Sun.COM 	return (rc);
18107887SLiane.Praza@Sun.COM }
18117887SLiane.Praza@Sun.COM 
18127887SLiane.Praza@Sun.COM /*
18137887SLiane.Praza@Sun.COM  * Create and initialize a new im_tmpl_error structure and add it to the
18147887SLiane.Praza@Sun.COM  * list of errors in errs.  The rest of the parameters are used to
18157887SLiane.Praza@Sun.COM  * initialize the im_tmpl_error structure.
18167887SLiane.Praza@Sun.COM  */
18177887SLiane.Praza@Sun.COM 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)18187887SLiane.Praza@Sun.COM tmpl_errors_add_im(tmpl_errors_t *errs, tmpl_validate_status_t ec, entity_t *e,
18197887SLiane.Praza@Sun.COM     pgroup_t *pg_pattern, pgroup_t *pg, pgroup_t *prop_pattern,
18207887SLiane.Praza@Sun.COM     property_t *prop, value_t *val, error_info_t *einfo)
18217887SLiane.Praza@Sun.COM {
18227887SLiane.Praza@Sun.COM 	im_tmpl_error_t *ite;
18237887SLiane.Praza@Sun.COM 	int result;
18247887SLiane.Praza@Sun.COM 
18257887SLiane.Praza@Sun.COM 	ite = uu_zalloc(sizeof (*ite));
18267887SLiane.Praza@Sun.COM 	if (ite == NULL)
18277887SLiane.Praza@Sun.COM 		uu_die(emesg_nomem);
18287887SLiane.Praza@Sun.COM 	uu_list_node_init(ite, &ite->ite_node, inmem_errors_pool);
18297887SLiane.Praza@Sun.COM 	ite->ite_type = ec;
18307887SLiane.Praza@Sun.COM 	ite->ite_entity = e;
18317887SLiane.Praza@Sun.COM 	ite->ite_pg = pg;
18327887SLiane.Praza@Sun.COM 	ite->ite_pg_pattern = pg_pattern;
18337887SLiane.Praza@Sun.COM 	ite->ite_prop = prop;
18347887SLiane.Praza@Sun.COM 	ite->ite_prop_pattern = prop_pattern;
18357887SLiane.Praza@Sun.COM 	ite->ite_value = val;
18367887SLiane.Praza@Sun.COM 	if (einfo != NULL)
18377887SLiane.Praza@Sun.COM 		ite->ite_einfo = *einfo;
18387887SLiane.Praza@Sun.COM 
18397887SLiane.Praza@Sun.COM 	result = uu_list_insert_after(errs->te_list, NULL, ite);
18407887SLiane.Praza@Sun.COM 	assert(result == 0);
18417887SLiane.Praza@Sun.COM 	return (TVS_SUCCESS);
18427887SLiane.Praza@Sun.COM }
18437887SLiane.Praza@Sun.COM 
18447887SLiane.Praza@Sun.COM /*
18457887SLiane.Praza@Sun.COM  * pattern must point to a pg_pattern or a prop_pattern.  This function
18467887SLiane.Praza@Sun.COM  * finds the property named required and returns the property's value.  If
18477887SLiane.Praza@Sun.COM  * the property does not exist, false is return since it is the default.
18487887SLiane.Praza@Sun.COM  */
18497887SLiane.Praza@Sun.COM static int
is_required(pgroup_t * pattern)18507887SLiane.Praza@Sun.COM is_required(pgroup_t *pattern)
18517887SLiane.Praza@Sun.COM {
18527887SLiane.Praza@Sun.COM 	property_t *required;
18537887SLiane.Praza@Sun.COM 	value_t *value;
18547887SLiane.Praza@Sun.COM 
18557887SLiane.Praza@Sun.COM 	assert((strcmp(pattern->sc_pgroup_type,
18567887SLiane.Praza@Sun.COM 	    SCF_GROUP_TEMPLATE_PG_PATTERN) == 0) ||
18577887SLiane.Praza@Sun.COM 	    (strcmp(pattern->sc_pgroup_type,
18587887SLiane.Praza@Sun.COM 	    SCF_GROUP_TEMPLATE_PROP_PATTERN) == 0));
18597887SLiane.Praza@Sun.COM 
18607887SLiane.Praza@Sun.COM 	required = property_find(pattern, SCF_PROPERTY_TM_REQUIRED);
18617887SLiane.Praza@Sun.COM 
18627887SLiane.Praza@Sun.COM 	/* Default if there is no required property is false. */
18637887SLiane.Praza@Sun.COM 	if (required == NULL)
18647887SLiane.Praza@Sun.COM 		return (0);
18657887SLiane.Praza@Sun.COM 
18667887SLiane.Praza@Sun.COM 	/* Retrieve the value of the required property. */
18677887SLiane.Praza@Sun.COM 	value = uu_list_first(required->sc_property_values);
18687887SLiane.Praza@Sun.COM 	if (value == NULL)
18697887SLiane.Praza@Sun.COM 		return (0);
18707887SLiane.Praza@Sun.COM 	if (value->sc_type == SCF_TYPE_BOOLEAN)
18717887SLiane.Praza@Sun.COM 		return (value->sc_u.sc_count == 0 ? 0 : 1);
18727887SLiane.Praza@Sun.COM 
18737887SLiane.Praza@Sun.COM 	/* No boolean property values, so return false. */
18747887SLiane.Praza@Sun.COM 	return (0);
18757887SLiane.Praza@Sun.COM }
18767887SLiane.Praza@Sun.COM 
18777887SLiane.Praza@Sun.COM /*
18787887SLiane.Praza@Sun.COM  * Load the service's restarter instance and the global instance from the
18797887SLiane.Praza@Sun.COM  * repository.  This will allow us to use their templates in validating the
18807887SLiane.Praza@Sun.COM  * service.
18817887SLiane.Praza@Sun.COM  *
18827887SLiane.Praza@Sun.COM  * There is no function to unload the general templates.  The memory that
18837887SLiane.Praza@Sun.COM  * is allocated by load_general_templates() will be freed automatically in
18847887SLiane.Praza@Sun.COM  * internal_service_free() which is called by internal_bundle_free().
18857887SLiane.Praza@Sun.COM  */
18867887SLiane.Praza@Sun.COM static void
load_general_templates(entity_t * svc)18877887SLiane.Praza@Sun.COM load_general_templates(entity_t *svc)
18887887SLiane.Praza@Sun.COM {
18897887SLiane.Praza@Sun.COM 	const char *restarter;
18907887SLiane.Praza@Sun.COM 	int is_global = 0;
18917887SLiane.Praza@Sun.COM 	int r;
18927887SLiane.Praza@Sun.COM 
18937887SLiane.Praza@Sun.COM 	assert(svc->sc_etype == SVCCFG_SERVICE_OBJECT);
18947887SLiane.Praza@Sun.COM 
18957887SLiane.Praza@Sun.COM 	/*
18967887SLiane.Praza@Sun.COM 	 * If e is the global service, we only need to load the restarter.
18977887SLiane.Praza@Sun.COM 	 */
18987887SLiane.Praza@Sun.COM 	if ((strcmp(svc->sc_fmri, SCF_INSTANCE_GLOBAL) == 0) ||
18997887SLiane.Praza@Sun.COM 	    (strcmp(svc->sc_fmri, SCF_SERVICE_GLOBAL) == 0)) {
19007887SLiane.Praza@Sun.COM 		is_global = 1;
19017887SLiane.Praza@Sun.COM 	}
19027887SLiane.Praza@Sun.COM 
19037887SLiane.Praza@Sun.COM 	/*
19047887SLiane.Praza@Sun.COM 	 * Load the templates for the service's restarter.
19057887SLiane.Praza@Sun.COM 	 */
19067887SLiane.Praza@Sun.COM 	restarter = find_restarter(svc);
19077887SLiane.Praza@Sun.COM 	if (restarter == NULL)
19087887SLiane.Praza@Sun.COM 		restarter = SCF_SERVICE_STARTD;
19097887SLiane.Praza@Sun.COM 	if ((r = load_instance(restarter, "restarter",
19107887SLiane.Praza@Sun.COM 	    &svc->sc_u.sc_service.sc_restarter)) != 0) {
19117887SLiane.Praza@Sun.COM 		/*
19127887SLiane.Praza@Sun.COM 		 * During initial manifest import, restarter may
19137887SLiane.Praza@Sun.COM 		 * not be in the repository yet.  In this case we
19147887SLiane.Praza@Sun.COM 		 * continue on without it.
19157887SLiane.Praza@Sun.COM 		 */
1916*9765SSean.Wilcox@Sun.COM 		if (r == EINVAL)
1917*9765SSean.Wilcox@Sun.COM 			warn(gettext("WARNING: restarter FMRI %s is invalid\n"),
1918*9765SSean.Wilcox@Sun.COM 			    restarter);
1919*9765SSean.Wilcox@Sun.COM 
1920*9765SSean.Wilcox@Sun.COM 		if (r == ENOTSUP)
1921*9765SSean.Wilcox@Sun.COM 			warn(gettext("WARNING: restarter FMRI %s is not valid; "
1922*9765SSean.Wilcox@Sun.COM 			    "instance fmri required.\n"), restarter);
1923*9765SSean.Wilcox@Sun.COM 
19247887SLiane.Praza@Sun.COM 		if (r == ENOMEM)
19257887SLiane.Praza@Sun.COM 			uu_die(emesg_nomem);
1926*9765SSean.Wilcox@Sun.COM 
1927*9765SSean.Wilcox@Sun.COM 		svc->sc_u.sc_service.sc_restarter = NULL;
19287887SLiane.Praza@Sun.COM 	}
19297887SLiane.Praza@Sun.COM 	if (is_global == 0) {
19307887SLiane.Praza@Sun.COM 		if ((r = load_instance(SCF_INSTANCE_GLOBAL, "global",
19317887SLiane.Praza@Sun.COM 		    &svc->sc_u.sc_service.sc_global)) != 0) {
19327887SLiane.Praza@Sun.COM 			/*
19337887SLiane.Praza@Sun.COM 			 * During initial manifest import, global may not be in
19347887SLiane.Praza@Sun.COM 			 * the repository yet.
19357887SLiane.Praza@Sun.COM 			 */
19367887SLiane.Praza@Sun.COM 			if (r == ENOMEM)
19377887SLiane.Praza@Sun.COM 				uu_die(emesg_nomem);
19387887SLiane.Praza@Sun.COM 			else
19397887SLiane.Praza@Sun.COM 				svc->sc_u.sc_service.sc_global = NULL;
19407887SLiane.Praza@Sun.COM 		}
19417887SLiane.Praza@Sun.COM 	}
19427887SLiane.Praza@Sun.COM }
19437887SLiane.Praza@Sun.COM 
19447887SLiane.Praza@Sun.COM /*
19457887SLiane.Praza@Sun.COM  * Load the instance specific restarter if one is declared.
19467887SLiane.Praza@Sun.COM  *
19477887SLiane.Praza@Sun.COM  * There is no corresponding unload_instance_restarter() function because
19487887SLiane.Praza@Sun.COM  * it is not needed.  The memory will be freed in internal_instance_free()
19497887SLiane.Praza@Sun.COM  * when internal_bundle_free() is called.
19507887SLiane.Praza@Sun.COM  */
19517887SLiane.Praza@Sun.COM static void
load_instance_restarter(entity_t * i)19527887SLiane.Praza@Sun.COM load_instance_restarter(entity_t *i)
19537887SLiane.Praza@Sun.COM {
19547887SLiane.Praza@Sun.COM 	const char *restarter;
19557887SLiane.Praza@Sun.COM 	int r;
19567887SLiane.Praza@Sun.COM 
19577887SLiane.Praza@Sun.COM 	assert(i->sc_etype == SVCCFG_INSTANCE_OBJECT);
19587887SLiane.Praza@Sun.COM 
19597887SLiane.Praza@Sun.COM 	restarter = find_restarter(i);
19607887SLiane.Praza@Sun.COM 	if (restarter == NULL) {
19617887SLiane.Praza@Sun.COM 		/* No instance specific restarter */
19627887SLiane.Praza@Sun.COM 		return;
19637887SLiane.Praza@Sun.COM 	}
19647887SLiane.Praza@Sun.COM 	r = load_instance(restarter, "instance_restarter",
19657887SLiane.Praza@Sun.COM 	    &i->sc_u.sc_instance.sc_instance_restarter);
19667887SLiane.Praza@Sun.COM 	if (r != 0) {
19677887SLiane.Praza@Sun.COM 		/*
19687887SLiane.Praza@Sun.COM 		 * During initial manifest import, the restarter may not be
19697887SLiane.Praza@Sun.COM 		 * in the repository yet.  In this case we continue on
19707887SLiane.Praza@Sun.COM 		 * without it.
19717887SLiane.Praza@Sun.COM 		 */
1972*9765SSean.Wilcox@Sun.COM 		if (r == EINVAL)
1973*9765SSean.Wilcox@Sun.COM 			warn(gettext("WARNING: restarter FMRI %s is invalid\n"),
1974*9765SSean.Wilcox@Sun.COM 			    restarter);
1975*9765SSean.Wilcox@Sun.COM 
1976*9765SSean.Wilcox@Sun.COM 		if (r == ENOTSUP)
1977*9765SSean.Wilcox@Sun.COM 			warn(gettext("WARNING: restarter FMRI %s is not valid; "
1978*9765SSean.Wilcox@Sun.COM 			    "instance fmri required.\n"), restarter);
1979*9765SSean.Wilcox@Sun.COM 
19807887SLiane.Praza@Sun.COM 		if (r == ENOMEM)
19817887SLiane.Praza@Sun.COM 			uu_die(emesg_nomem);
19827887SLiane.Praza@Sun.COM 	}
19837887SLiane.Praza@Sun.COM }
19847887SLiane.Praza@Sun.COM 
19857887SLiane.Praza@Sun.COM /*
19867887SLiane.Praza@Sun.COM  * Find the next property after current in the property group at pg.  If
19877887SLiane.Praza@Sun.COM  * the property group contains a tree of composed properties, that tree is
19887887SLiane.Praza@Sun.COM  * walked.  Otherwise, we walk through the uu_list at sc_pgroup_props.
19897887SLiane.Praza@Sun.COM  */
19907887SLiane.Praza@Sun.COM static property_t *
next_property(pgroup_t * pg,property_t * current)19917887SLiane.Praza@Sun.COM next_property(pgroup_t *pg, property_t *current)
19927887SLiane.Praza@Sun.COM {
19937887SLiane.Praza@Sun.COM 	composed_pg_t *cpg;
19947887SLiane.Praza@Sun.COM 	property_t *prop;
19957887SLiane.Praza@Sun.COM 
19967887SLiane.Praza@Sun.COM 	cpg = pg->sc_pgroup_composed;
19977887SLiane.Praza@Sun.COM 	if ((cpg != NULL) && (cpg->cpg_composed_props != NULL)) {
19987887SLiane.Praza@Sun.COM 		/* Walk through composed property list. */
19997887SLiane.Praza@Sun.COM 		if (current) {
20007887SLiane.Praza@Sun.COM 			prop = uu_avl_next(cpg->cpg_composed_props, current);
20017887SLiane.Praza@Sun.COM 		} else {
20027887SLiane.Praza@Sun.COM 			prop = uu_avl_first(cpg->cpg_composed_props);
20037887SLiane.Praza@Sun.COM 		}
20047887SLiane.Praza@Sun.COM 	} else {
20057887SLiane.Praza@Sun.COM 		/* No composition available, so walk the list of properties */
20067887SLiane.Praza@Sun.COM 		if (current) {
20077887SLiane.Praza@Sun.COM 			prop = uu_list_next(pg->sc_pgroup_props, current);
20087887SLiane.Praza@Sun.COM 		} else {
20097887SLiane.Praza@Sun.COM 			prop = uu_list_first(pg->sc_pgroup_props);
20107887SLiane.Praza@Sun.COM 		}
20117887SLiane.Praza@Sun.COM 	}
20127887SLiane.Praza@Sun.COM 
20137887SLiane.Praza@Sun.COM 	return (prop);
20147887SLiane.Praza@Sun.COM }
20157887SLiane.Praza@Sun.COM 
20167887SLiane.Praza@Sun.COM static ptrn_info_t *
ptrn_info_create(pgroup_t * pat)20177887SLiane.Praza@Sun.COM ptrn_info_create(pgroup_t *pat)
20187887SLiane.Praza@Sun.COM {
20197887SLiane.Praza@Sun.COM 	entity_t *e;
20207887SLiane.Praza@Sun.COM 	ptrn_info_t *info;
20217887SLiane.Praza@Sun.COM 	composed_pg_t *match;
20227887SLiane.Praza@Sun.COM 	composed_pg_t cpg;
20237887SLiane.Praza@Sun.COM 
20247887SLiane.Praza@Sun.COM 	info = safe_malloc(sizeof (*info));
20257887SLiane.Praza@Sun.COM 
20267887SLiane.Praza@Sun.COM 	switch (pgroup_type(pat)) {
20277887SLiane.Praza@Sun.COM 	case PG_PATTERN_PG:
20287887SLiane.Praza@Sun.COM 		info->pi_ptrn_type = PG_PATTERN;
20297887SLiane.Praza@Sun.COM 		break;
20307887SLiane.Praza@Sun.COM 	case PROP_PATTERN_PG:
20317887SLiane.Praza@Sun.COM 		info->pi_ptrn_type = PROP_PATTERN;
20327887SLiane.Praza@Sun.COM 		break;
20337887SLiane.Praza@Sun.COM 	default:
20347887SLiane.Praza@Sun.COM 		assert(0);
20357887SLiane.Praza@Sun.COM 		abort();
20367887SLiane.Praza@Sun.COM 	}
20377887SLiane.Praza@Sun.COM 	info->pi_ptrnpg = pat;
20387887SLiane.Praza@Sun.COM 	info->pi_name = find_name_specification(pat);
20397887SLiane.Praza@Sun.COM 	info->pi_name = EMPTY_TO_NULL(info->pi_name);
20407887SLiane.Praza@Sun.COM 	info->pi_type = find_type_specification(pat);
20417887SLiane.Praza@Sun.COM 	info->pi_type = EMPTY_TO_NULL(info->pi_type);
20427887SLiane.Praza@Sun.COM 	if (info->pi_ptrn_type == PG_PATTERN) {
20437887SLiane.Praza@Sun.COM 		info->pi_target = find_astring_value_in_pg(pat,
20447887SLiane.Praza@Sun.COM 		    SCF_PROPERTY_TM_TARGET);
20457887SLiane.Praza@Sun.COM 		if (info->pi_target == NULL)
20467887SLiane.Praza@Sun.COM 			info->pi_target = SCF_TM_TARGET_THIS;
20477887SLiane.Praza@Sun.COM 	}
20487887SLiane.Praza@Sun.COM 	if (info->pi_ptrn_type == PROP_PATTERN) {
20497887SLiane.Praza@Sun.COM 		info->pi_pgp_name = find_astring_value_in_pg(pat,
20507887SLiane.Praza@Sun.COM 		    SCF_PROPERTY_TM_PG_PATTERN);
20517887SLiane.Praza@Sun.COM 		assert((info->pi_pgp_name != NULL) &&
20527887SLiane.Praza@Sun.COM 		    (*(info->pi_pgp_name) != 0));
20537887SLiane.Praza@Sun.COM 
20547887SLiane.Praza@Sun.COM 		/*
20557887SLiane.Praza@Sun.COM 		 * Find the property group that defines the pg_pattern that
20567887SLiane.Praza@Sun.COM 		 * holds this prop_pattern.
20577887SLiane.Praza@Sun.COM 		 */
20587887SLiane.Praza@Sun.COM 		e = pat->sc_parent;
20597887SLiane.Praza@Sun.COM 		if (e->sc_etype == SVCCFG_INSTANCE_OBJECT) {
20607887SLiane.Praza@Sun.COM 			(void) memset(&cpg, 0, sizeof (cpg));
20617887SLiane.Praza@Sun.COM 			cpg.cpg_name = info->pi_pgp_name;
20627887SLiane.Praza@Sun.COM 			cpg.cpg_type = SCF_GROUP_TEMPLATE_PG_PATTERN;
20637887SLiane.Praza@Sun.COM 			match = uu_avl_find(e->sc_u.sc_instance.sc_composed,
20647887SLiane.Praza@Sun.COM 			    &cpg, NULL, NULL);
20657887SLiane.Praza@Sun.COM 			assert(match != NULL);
20667887SLiane.Praza@Sun.COM 			info->pi_enc_pgp = CPG2PG(match);
20677887SLiane.Praza@Sun.COM 		} else {
20687887SLiane.Praza@Sun.COM 			info->pi_enc_pgp = internal_pgroup_find(e,
20697887SLiane.Praza@Sun.COM 			    info->pi_pgp_name, SCF_GROUP_TEMPLATE_PG_PATTERN);
20707887SLiane.Praza@Sun.COM 		}
20717887SLiane.Praza@Sun.COM 		assert(info->pi_enc_pgp != NULL);
20727887SLiane.Praza@Sun.COM 	}
20737887SLiane.Praza@Sun.COM 	uu_avl_node_init(info, &info->pi_link, ptrn_info_pool);
20747887SLiane.Praza@Sun.COM 	return (info);
20757887SLiane.Praza@Sun.COM }
20767887SLiane.Praza@Sun.COM 
20777887SLiane.Praza@Sun.COM static void
ptrn_info_destroy(ptrn_info_t * info)20787887SLiane.Praza@Sun.COM ptrn_info_destroy(ptrn_info_t *info)
20797887SLiane.Praza@Sun.COM {
20807887SLiane.Praza@Sun.COM 	if (info == NULL)
20817887SLiane.Praza@Sun.COM 		return;
20827887SLiane.Praza@Sun.COM 	uu_avl_node_fini(info, &info->pi_link, ptrn_info_pool);
20837887SLiane.Praza@Sun.COM 	free(info);
20847887SLiane.Praza@Sun.COM }
20857887SLiane.Praza@Sun.COM 
20867887SLiane.Praza@Sun.COM /*
20877887SLiane.Praza@Sun.COM  * Walk through the property groups of the instance or service at e looking
20887887SLiane.Praza@Sun.COM  * for definitions of pg_patterns or prop_patterns as specified by type.
20897887SLiane.Praza@Sun.COM  * For each property group that matches type create a ptrn_info_t and add
20907887SLiane.Praza@Sun.COM  * it to the avl tree at tree.  If duplicates are found add an error entry
20917887SLiane.Praza@Sun.COM  * to errs.
20927887SLiane.Praza@Sun.COM  */
20937887SLiane.Praza@Sun.COM static tmpl_validate_status_t
gather_pattern(entity_t * e,ptrn_type_t type,uu_avl_t * tree,tmpl_errors_t * errs)20947887SLiane.Praza@Sun.COM gather_pattern(entity_t *e, ptrn_type_t type, uu_avl_t *tree,
20957887SLiane.Praza@Sun.COM     tmpl_errors_t *errs)
20967887SLiane.Praza@Sun.COM {
20977887SLiane.Praza@Sun.COM 	error_info_t einfo;
20987887SLiane.Praza@Sun.COM 	ptrn_info_t *info = NULL;
20997887SLiane.Praza@Sun.COM 	uu_avl_index_t marker;
21007887SLiane.Praza@Sun.COM 	ptrn_info_t *match;
21017887SLiane.Praza@Sun.COM 	pgroup_t *pg;
21027887SLiane.Praza@Sun.COM 	tmpl_validate_status_t rc = TVS_SUCCESS;
21037887SLiane.Praza@Sun.COM 	const char *selector;
21047887SLiane.Praza@Sun.COM 
21057887SLiane.Praza@Sun.COM 	switch (type) {
21067887SLiane.Praza@Sun.COM 	case PG_PATTERN:
21077887SLiane.Praza@Sun.COM 		selector = SCF_GROUP_TEMPLATE_PG_PATTERN;
21087887SLiane.Praza@Sun.COM 		break;
21097887SLiane.Praza@Sun.COM 	case PROP_PATTERN:
21107887SLiane.Praza@Sun.COM 		selector = SCF_GROUP_TEMPLATE_PROP_PATTERN;
21117887SLiane.Praza@Sun.COM 		break;
21127887SLiane.Praza@Sun.COM 	default:
21137887SLiane.Praza@Sun.COM 		assert(0);
21147887SLiane.Praza@Sun.COM 		abort();
21157887SLiane.Praza@Sun.COM 	}
21167887SLiane.Praza@Sun.COM 
21177887SLiane.Praza@Sun.COM 	for (pg = uu_list_first(e->sc_pgroups);
21187887SLiane.Praza@Sun.COM 	    pg != NULL;
21197887SLiane.Praza@Sun.COM 	    pg = uu_list_next(e->sc_pgroups, pg)) {
21207887SLiane.Praza@Sun.COM 		if (strcmp(pg->sc_pgroup_type, selector) != 0) {
21217887SLiane.Praza@Sun.COM 			continue;
21227887SLiane.Praza@Sun.COM 		}
21237887SLiane.Praza@Sun.COM 		if (info != NULL) {
21247887SLiane.Praza@Sun.COM 			/* Get rid of old structure. */
21257887SLiane.Praza@Sun.COM 			ptrn_info_destroy(info);
21267887SLiane.Praza@Sun.COM 		}
21277887SLiane.Praza@Sun.COM 		info = ptrn_info_create(pg);
21287887SLiane.Praza@Sun.COM 		match = uu_avl_find(tree, info, NULL, &marker);
21297887SLiane.Praza@Sun.COM 		if (match == NULL) {
21307887SLiane.Praza@Sun.COM 			/* No match.  Insert the info. */
21317887SLiane.Praza@Sun.COM 			uu_avl_insert(tree, info, marker);
21327887SLiane.Praza@Sun.COM 			info = NULL;
21337887SLiane.Praza@Sun.COM 			continue;
21347887SLiane.Praza@Sun.COM 		}
21357887SLiane.Praza@Sun.COM 
21367887SLiane.Praza@Sun.COM 		/* Got a match.  Determine if it is a conflict. */
21377887SLiane.Praza@Sun.COM 		if ((info->pi_name == NULL) ||
21387887SLiane.Praza@Sun.COM 		    (info->pi_type == NULL) ||
21397887SLiane.Praza@Sun.COM 		    (match->pi_name == NULL) ||
21407887SLiane.Praza@Sun.COM 		    (match->pi_type == NULL)) {
21417887SLiane.Praza@Sun.COM 			/* No conflicts if any wild cards. */
21427887SLiane.Praza@Sun.COM 			continue;
21437887SLiane.Praza@Sun.COM 		}
21447887SLiane.Praza@Sun.COM 
21457887SLiane.Praza@Sun.COM 		/*
21467887SLiane.Praza@Sun.COM 		 * Name already matches, or we wouldn't have gotten
21477887SLiane.Praza@Sun.COM 		 * here.  Make sure that the type also matches.
21487887SLiane.Praza@Sun.COM 		 */
21497887SLiane.Praza@Sun.COM 		if (strcmp(info->pi_type, match->pi_type) == 0) {
21507887SLiane.Praza@Sun.COM 			continue;
21517887SLiane.Praza@Sun.COM 		}
21527887SLiane.Praza@Sun.COM 
21537887SLiane.Praza@Sun.COM 		/*
21547887SLiane.Praza@Sun.COM 		 * If we get to this point we have a conflict, and
21557887SLiane.Praza@Sun.COM 		 * we need to generate the correct type of error.
21567887SLiane.Praza@Sun.COM 		 */
21577887SLiane.Praza@Sun.COM 		CLEAR_ERROR_INFO(&einfo);
21587887SLiane.Praza@Sun.COM 		einfo.ei_type = EIT_PATTERN_CONFLICT;
21597887SLiane.Praza@Sun.COM 		einfo.ei_u.ei_pattern_conflict.ei_pattern =
21607887SLiane.Praza@Sun.COM 		    match->pi_ptrnpg;
21617887SLiane.Praza@Sun.COM 		if (type == PG_PATTERN) {
21627887SLiane.Praza@Sun.COM 			rc = TVS_VALIDATION;
21637887SLiane.Praza@Sun.COM 			if (add_scf_error(errs, SCF_TERR_PG_PATTERN_CONFLICT,
21647887SLiane.Praza@Sun.COM 			    info->pi_ptrnpg, NULL, NULL, NULL, NULL,
21657887SLiane.Praza@Sun.COM 			    &einfo) != 0) {
21667887SLiane.Praza@Sun.COM 				/*
21677887SLiane.Praza@Sun.COM 				 * If we can no longer accumulate
21687887SLiane.Praza@Sun.COM 				 * errors, break out of the loop.
21697887SLiane.Praza@Sun.COM 				 */
21707887SLiane.Praza@Sun.COM 				break;
21717887SLiane.Praza@Sun.COM 			}
21727887SLiane.Praza@Sun.COM 		} else {
21737887SLiane.Praza@Sun.COM 			/*
21747887SLiane.Praza@Sun.COM 			 * Possible conflicting prop_pattern.  See if the
21757887SLiane.Praza@Sun.COM 			 * prop_patterns are declared in the same
21767887SLiane.Praza@Sun.COM 			 * pg_pattern.
21777887SLiane.Praza@Sun.COM 			 */
21787887SLiane.Praza@Sun.COM 			if ((info->pi_pgp_name == NULL) ||
21797887SLiane.Praza@Sun.COM 			    (match->pi_pgp_name == NULL)) {
21807887SLiane.Praza@Sun.COM 				continue;
21817887SLiane.Praza@Sun.COM 			}
21827887SLiane.Praza@Sun.COM 			if (strcmp(info->pi_pgp_name, match->pi_pgp_name) != 0)
21837887SLiane.Praza@Sun.COM 				continue;
21847887SLiane.Praza@Sun.COM 
21857887SLiane.Praza@Sun.COM 			/* It is a real conflict. */
21867887SLiane.Praza@Sun.COM 			rc = TVS_VALIDATION;
21877887SLiane.Praza@Sun.COM 			if (add_scf_error(errs, SCF_TERR_PROP_PATTERN_CONFLICT,
21887887SLiane.Praza@Sun.COM 			    info->pi_enc_pgp, NULL, info->pi_ptrnpg, NULL, NULL,
21897887SLiane.Praza@Sun.COM 			    &einfo) != 0) {
21907887SLiane.Praza@Sun.COM 				/*
21917887SLiane.Praza@Sun.COM 				 * If we can no longer accumulate
21927887SLiane.Praza@Sun.COM 				 * errors, break out of the loop.
21937887SLiane.Praza@Sun.COM 				 */
21947887SLiane.Praza@Sun.COM 				break;
21957887SLiane.Praza@Sun.COM 			}
21967887SLiane.Praza@Sun.COM 		}
21977887SLiane.Praza@Sun.COM 	}
21987887SLiane.Praza@Sun.COM 
21997887SLiane.Praza@Sun.COM 	ptrn_info_destroy(info);
22007887SLiane.Praza@Sun.COM 	return (rc);
22017887SLiane.Praza@Sun.COM }
22027887SLiane.Praza@Sun.COM 
22037887SLiane.Praza@Sun.COM /*
22047887SLiane.Praza@Sun.COM  * Free the pg_iter structure.
22057887SLiane.Praza@Sun.COM  */
22067887SLiane.Praza@Sun.COM static void
pg_iter_destroy(pg_iter_t * i)22077887SLiane.Praza@Sun.COM pg_iter_destroy(pg_iter_t *i)
22087887SLiane.Praza@Sun.COM {
22097887SLiane.Praza@Sun.COM 	if (i == NULL)
22107887SLiane.Praza@Sun.COM 		return;
22117887SLiane.Praza@Sun.COM 
22127887SLiane.Praza@Sun.COM 	uu_free(i);
22137887SLiane.Praza@Sun.COM }
22147887SLiane.Praza@Sun.COM 
22157887SLiane.Praza@Sun.COM /*
22167887SLiane.Praza@Sun.COM  * Create a property group iterator for the instance at e.  This iterator
22177887SLiane.Praza@Sun.COM  * will walk through the composed property groups of the instance.  It will
22187887SLiane.Praza@Sun.COM  * then step through the property groups of the instance's restarter and
22197887SLiane.Praza@Sun.COM  * finally the global service.  If you wish to iterate over a specific type
22207887SLiane.Praza@Sun.COM  * of property group, set restriction to point the the desired type.
22217887SLiane.Praza@Sun.COM  * Otherwise set restriction to NULL.
22227887SLiane.Praza@Sun.COM  *
22237887SLiane.Praza@Sun.COM  * The returned interator must be freed by calling pg_iter_destroy().  NULL
22247887SLiane.Praza@Sun.COM  * is returned if we are unable to allocate the necessary memory.
22257887SLiane.Praza@Sun.COM  */
22267887SLiane.Praza@Sun.COM static pg_iter_t *
pg_iter_create(entity_t * e,const char * restriction)22277887SLiane.Praza@Sun.COM pg_iter_create(entity_t *e, const char *restriction)
22287887SLiane.Praza@Sun.COM {
22297887SLiane.Praza@Sun.COM 	pg_iter_t *i;
22307887SLiane.Praza@Sun.COM 
22317887SLiane.Praza@Sun.COM 	assert(e->sc_etype == SVCCFG_INSTANCE_OBJECT);
22327887SLiane.Praza@Sun.COM 
22337887SLiane.Praza@Sun.COM 	i = uu_zalloc(sizeof (*i));
22347887SLiane.Praza@Sun.COM 	if (i == NULL)
22357887SLiane.Praza@Sun.COM 		return (NULL);
22367887SLiane.Praza@Sun.COM 
22377887SLiane.Praza@Sun.COM 	i->pgi_entity = e;
22387887SLiane.Praza@Sun.COM 	i->pgi_restrict = restriction;
22397887SLiane.Praza@Sun.COM 	i->pgi_level = TL_COMPOSED;
22407887SLiane.Praza@Sun.COM 	i->pgi_service = e->sc_parent;
22417887SLiane.Praza@Sun.COM 
22427887SLiane.Praza@Sun.COM 	return (i);
22437887SLiane.Praza@Sun.COM }
22447887SLiane.Praza@Sun.COM 
22457887SLiane.Praza@Sun.COM /*
22467887SLiane.Praza@Sun.COM  * Return the next property group in the iteration.  NULL is returned if we
22477887SLiane.Praza@Sun.COM  * reach the end of the list.  The iterator will automatically proceed from
22487887SLiane.Praza@Sun.COM  * most specific to most general levels.
22497887SLiane.Praza@Sun.COM  */
22507887SLiane.Praza@Sun.COM static pgroup_t *
next_pattern_pg(pg_iter_t * i)22517887SLiane.Praza@Sun.COM next_pattern_pg(pg_iter_t *i)
22527887SLiane.Praza@Sun.COM {
22537887SLiane.Praza@Sun.COM 	composed_pg_t *cpg;
22547887SLiane.Praza@Sun.COM 	entity_t *e;
22557887SLiane.Praza@Sun.COM 	pgroup_t *pg;
22567887SLiane.Praza@Sun.COM 	uu_avl_t *composed_tree;
22577887SLiane.Praza@Sun.COM 
22587887SLiane.Praza@Sun.COM 	assert(i->pgi_level != TL_NOLEVEL);
22597887SLiane.Praza@Sun.COM 
22607887SLiane.Praza@Sun.COM 	while (i->pgi_entity != NULL) {
22617887SLiane.Praza@Sun.COM 		if (i->pgi_level == TL_COMPOSED) {
22627887SLiane.Praza@Sun.COM 			composed_tree =
22637887SLiane.Praza@Sun.COM 			    i->pgi_entity->sc_u.sc_instance.sc_composed;
22647887SLiane.Praza@Sun.COM 			cpg = i->pgi_current.pgi_cpg;
22657887SLiane.Praza@Sun.COM 			if (cpg == NULL) {
22667887SLiane.Praza@Sun.COM 				cpg = uu_avl_first(composed_tree);
22677887SLiane.Praza@Sun.COM 			} else {
22687887SLiane.Praza@Sun.COM 				cpg = uu_avl_next(composed_tree, cpg);
22697887SLiane.Praza@Sun.COM 			}
22707887SLiane.Praza@Sun.COM 			if (cpg == NULL) {
22717887SLiane.Praza@Sun.COM 				pg = NULL;
22727887SLiane.Praza@Sun.COM 			} else {
22737887SLiane.Praza@Sun.COM 				pg = CPG2PG(cpg);
22747887SLiane.Praza@Sun.COM 				i->pgi_current.pgi_cpg = cpg;
22757887SLiane.Praza@Sun.COM 			}
22767887SLiane.Praza@Sun.COM 		} else {
22777887SLiane.Praza@Sun.COM 			pg = i->pgi_current.pgi_pg;
22787887SLiane.Praza@Sun.COM 			if (pg == NULL) {
22797887SLiane.Praza@Sun.COM 				pg = uu_list_first(i->pgi_entity->sc_pgroups);
22807887SLiane.Praza@Sun.COM 			} else {
22817887SLiane.Praza@Sun.COM 				pg = uu_list_next(i->pgi_entity->sc_pgroups,
22827887SLiane.Praza@Sun.COM 				    pg);
22837887SLiane.Praza@Sun.COM 			}
22847887SLiane.Praza@Sun.COM 			i->pgi_current.pgi_pg = pg;
22857887SLiane.Praza@Sun.COM 		}
22867887SLiane.Praza@Sun.COM 
22877887SLiane.Praza@Sun.COM 		if (pg == NULL) {
22887887SLiane.Praza@Sun.COM 			/*
22897887SLiane.Praza@Sun.COM 			 * End of the list.  Reset current and break out of
22907887SLiane.Praza@Sun.COM 			 * the loop.
22917887SLiane.Praza@Sun.COM 			 */
22927887SLiane.Praza@Sun.COM 			(void) memset(&i->pgi_current, 0,
22937887SLiane.Praza@Sun.COM 			    sizeof (i->pgi_current));
22947887SLiane.Praza@Sun.COM 			break;
22957887SLiane.Praza@Sun.COM 		}
22967887SLiane.Praza@Sun.COM 
22977887SLiane.Praza@Sun.COM 		/*
22987887SLiane.Praza@Sun.COM 		 * If this iteration is for a specific type, verify that
22997887SLiane.Praza@Sun.COM 		 * this pg is of that type.
23007887SLiane.Praza@Sun.COM 		 */
23017887SLiane.Praza@Sun.COM 		if (i->pgi_restrict) {
23027887SLiane.Praza@Sun.COM 			if (strcmp(pg->sc_pgroup_type, i->pgi_restrict) != 0) {
23037887SLiane.Praza@Sun.COM 				continue;
23047887SLiane.Praza@Sun.COM 			}
23057887SLiane.Praza@Sun.COM 		}
23067887SLiane.Praza@Sun.COM 
23077887SLiane.Praza@Sun.COM 		return (pg);
23087887SLiane.Praza@Sun.COM 	}
23097887SLiane.Praza@Sun.COM 
23107887SLiane.Praza@Sun.COM 	/*
23117887SLiane.Praza@Sun.COM 	 * End of the list in the current level.  Move up to the next
23127887SLiane.Praza@Sun.COM 	 * level.
23137887SLiane.Praza@Sun.COM 	 */
23147887SLiane.Praza@Sun.COM 	switch (i->pgi_level) {
23157887SLiane.Praza@Sun.COM 	case TL_COMPOSED:
23167887SLiane.Praza@Sun.COM 		/* Skip service if we've finished a composed instance. */
23177887SLiane.Praza@Sun.COM 		e = i->pgi_entity;
23187887SLiane.Praza@Sun.COM 		if (e->sc_u.sc_instance.sc_instance_restarter == NULL) {
23197887SLiane.Praza@Sun.COM 			/* Use service restarter */
23207887SLiane.Praza@Sun.COM 			i->pgi_entity =
23217887SLiane.Praza@Sun.COM 			    i->pgi_service->sc_u.sc_service.sc_restarter;
23227887SLiane.Praza@Sun.COM 		} else {
23237887SLiane.Praza@Sun.COM 			/* Use instance restarter */
23247887SLiane.Praza@Sun.COM 			i->pgi_entity =
23257887SLiane.Praza@Sun.COM 			    e->sc_u.sc_instance.sc_instance_restarter;
23267887SLiane.Praza@Sun.COM 		}
23277887SLiane.Praza@Sun.COM 		i->pgi_level = TL_RESTARTER;
23287887SLiane.Praza@Sun.COM 		break;
23297887SLiane.Praza@Sun.COM 	case TL_RESTARTER:
23307887SLiane.Praza@Sun.COM 		i->pgi_entity = i->pgi_service->sc_u.sc_service.sc_global;
23317887SLiane.Praza@Sun.COM 		i->pgi_level = TL_GLOBAL;
23327887SLiane.Praza@Sun.COM 		break;
23337887SLiane.Praza@Sun.COM 	case TL_GLOBAL:
23347887SLiane.Praza@Sun.COM 		i->pgi_level = TL_NOLEVEL;
23357887SLiane.Praza@Sun.COM 		return (NULL);
23367887SLiane.Praza@Sun.COM 	default:
23377887SLiane.Praza@Sun.COM 		assert(0);
23387887SLiane.Praza@Sun.COM 		abort();
23397887SLiane.Praza@Sun.COM 	}
23407887SLiane.Praza@Sun.COM 
23417887SLiane.Praza@Sun.COM 	/* Go process the next level. */
23427887SLiane.Praza@Sun.COM 	return (next_pattern_pg(i));
23437887SLiane.Praza@Sun.COM }
23447887SLiane.Praza@Sun.COM 
23457887SLiane.Praza@Sun.COM /*
23467887SLiane.Praza@Sun.COM  * Compare two pattern info structures (ptrn_info_t).  If both structures
23477887SLiane.Praza@Sun.COM  * have names, the comparison is based on the name.  If only one has a
23487887SLiane.Praza@Sun.COM  * name, the structure with no name will be first.  If neither structure
23497887SLiane.Praza@Sun.COM  * has a name, the comparison is based on their types using similar wild
23507887SLiane.Praza@Sun.COM  * card logic.
23517887SLiane.Praza@Sun.COM  */
23527887SLiane.Praza@Sun.COM /* ARGSUSED2 */
23537887SLiane.Praza@Sun.COM static int
ptrn_info_compare(const void * left,const void * right,void * unused)23547887SLiane.Praza@Sun.COM ptrn_info_compare(const  void *left, const void *right, void *unused)
23557887SLiane.Praza@Sun.COM {
23567887SLiane.Praza@Sun.COM 	ptrn_info_t *l = (ptrn_info_t *)left;
23577887SLiane.Praza@Sun.COM 	ptrn_info_t *r = (ptrn_info_t *)right;
23587887SLiane.Praza@Sun.COM 
23597887SLiane.Praza@Sun.COM 	if ((l->pi_name != NULL) && (r->pi_name != NULL))
23607887SLiane.Praza@Sun.COM 		return (strcmp(l->pi_name, r->pi_name));
23617887SLiane.Praza@Sun.COM 	if ((l->pi_name == NULL) && (r->pi_name == NULL)) {
23627887SLiane.Praza@Sun.COM 		/* No names, so we need to compare types. */
23637887SLiane.Praza@Sun.COM 		if ((l->pi_type != NULL) && (r->pi_type != NULL))
23647887SLiane.Praza@Sun.COM 			return (strcmp(l->pi_type, r->pi_type));
23657887SLiane.Praza@Sun.COM 		if ((l->pi_type == NULL) && (r->pi_type == NULL))
23667887SLiane.Praza@Sun.COM 			return (0);
23677887SLiane.Praza@Sun.COM 
23687887SLiane.Praza@Sun.COM 		/* If we get here, exactly one of the types is NULL */
23697887SLiane.Praza@Sun.COM 		if (l->pi_type == NULL)
23707887SLiane.Praza@Sun.COM 			return (-1);
23717887SLiane.Praza@Sun.COM 		return (1);
23727887SLiane.Praza@Sun.COM 	}
23737887SLiane.Praza@Sun.COM 
23747887SLiane.Praza@Sun.COM 	/* If we get here, exactly one of the names is NULL */
23757887SLiane.Praza@Sun.COM 	if (l->pi_name == NULL)
23767887SLiane.Praza@Sun.COM 		return (-1);
23777887SLiane.Praza@Sun.COM 	return (1);
23787887SLiane.Praza@Sun.COM }
23797887SLiane.Praza@Sun.COM 
23807887SLiane.Praza@Sun.COM /*
23817887SLiane.Praza@Sun.COM  * The target of a pg_pattern in combination with the level at which the
23827887SLiane.Praza@Sun.COM  * pg_pattern was defined determines whether or not it should be applied.
23837887SLiane.Praza@Sun.COM  * The following combinations should be ignored, and all others should be
23847887SLiane.Praza@Sun.COM  * applied.
23857887SLiane.Praza@Sun.COM  *
23867887SLiane.Praza@Sun.COM  *	Target		Level
23877887SLiane.Praza@Sun.COM  *	------		-----
23887887SLiane.Praza@Sun.COM  *	this		TL_RESTARTER, TL_GLOBAL
23897887SLiane.Praza@Sun.COM  *			"this" only applies if the pg_pattern was defined
23907887SLiane.Praza@Sun.COM  *			at the instance or service level
23917887SLiane.Praza@Sun.COM  *	delegate	TL_INSTANCE, TL_SERVICE
23927887SLiane.Praza@Sun.COM  *			Only restarters and the global service can
23937887SLiane.Praza@Sun.COM  *			delegate.
23947887SLiane.Praza@Sun.COM  *	instance	TL_INSTANCE, TL_RESTARTER, TL_GLOBAL
23957887SLiane.Praza@Sun.COM  *			Only the service level can specify the "instance"
23967887SLiane.Praza@Sun.COM  *			target.
23977887SLiane.Praza@Sun.COM  *	all		TL_INSTANCE, TL_SERVICE, TL_RESTARTER
23987887SLiane.Praza@Sun.COM  *			Only the global service can specify the "all"
23997887SLiane.Praza@Sun.COM  *			target.
24007887SLiane.Praza@Sun.COM  *
24017887SLiane.Praza@Sun.COM  * Return Values:
24027887SLiane.Praza@Sun.COM  *	1	apply the pg_pattern
24037887SLiane.Praza@Sun.COM  *	0	ignore the pg_pattern
24047887SLiane.Praza@Sun.COM  */
24057887SLiane.Praza@Sun.COM static int
target_check(const char * target,tmpl_level_t level)24067887SLiane.Praza@Sun.COM target_check(const char *target, tmpl_level_t level)
24077887SLiane.Praza@Sun.COM {
24087887SLiane.Praza@Sun.COM 	if ((target == NULL) || (*target == 0)) {
24097887SLiane.Praza@Sun.COM 		/* Default is this */
24107887SLiane.Praza@Sun.COM 		target = SCF_TM_TARGET_THIS;
24117887SLiane.Praza@Sun.COM 	}
24127887SLiane.Praza@Sun.COM 	if (strcmp(target, SCF_TM_TARGET_THIS) == 0) {
24137887SLiane.Praza@Sun.COM 		if ((level == TL_RESTARTER) ||
24147887SLiane.Praza@Sun.COM 		    (level == TL_GLOBAL)) {
24157887SLiane.Praza@Sun.COM 			return (0);
24167887SLiane.Praza@Sun.COM 		} else {
24177887SLiane.Praza@Sun.COM 			return (1);
24187887SLiane.Praza@Sun.COM 		}
24197887SLiane.Praza@Sun.COM 	}
24207887SLiane.Praza@Sun.COM 	if (strcmp(target, SCF_TM_TARGET_DELEGATE) == 0) {
24217887SLiane.Praza@Sun.COM 		if ((level == TL_INSTANCE) ||
24227887SLiane.Praza@Sun.COM 		    (level == TL_SERVICE)) {
24237887SLiane.Praza@Sun.COM 			return (0);
24247887SLiane.Praza@Sun.COM 		} else {
24257887SLiane.Praza@Sun.COM 			return (1);
24267887SLiane.Praza@Sun.COM 		}
24277887SLiane.Praza@Sun.COM 	}
24287887SLiane.Praza@Sun.COM 	if (strcmp(target, SCF_TM_TARGET_INSTANCE) == 0) {
24297887SLiane.Praza@Sun.COM 		/*
24307887SLiane.Praza@Sun.COM 		 * Note that the test is inverted from the other cases.
24317887SLiane.Praza@Sun.COM 		 * This is because there is only one instance where apply
24327887SLiane.Praza@Sun.COM 		 * is the correct thing to do.
24337887SLiane.Praza@Sun.COM 		 */
24347887SLiane.Praza@Sun.COM 		if (level == TL_SERVICE) {
24357887SLiane.Praza@Sun.COM 			return (1);
24367887SLiane.Praza@Sun.COM 		} else {
24377887SLiane.Praza@Sun.COM 			return (0);
24387887SLiane.Praza@Sun.COM 		}
24397887SLiane.Praza@Sun.COM 	}
24407887SLiane.Praza@Sun.COM 	if (strcmp(target, SCF_TM_TARGET_ALL) == 0) {
24417887SLiane.Praza@Sun.COM 		if ((level == TL_INSTANCE) ||
24427887SLiane.Praza@Sun.COM 		    (level == TL_SERVICE) ||
24437887SLiane.Praza@Sun.COM 		    (level == TL_RESTARTER)) {
24447887SLiane.Praza@Sun.COM 			return (0);
24457887SLiane.Praza@Sun.COM 		}
24467887SLiane.Praza@Sun.COM 	}
24477887SLiane.Praza@Sun.COM 	return (1);
24487887SLiane.Praza@Sun.COM }
24497887SLiane.Praza@Sun.COM 
24507887SLiane.Praza@Sun.COM static int
pg_target_check(pgroup_t * pg_pattern,tmpl_level_t level)24517887SLiane.Praza@Sun.COM pg_target_check(pgroup_t *pg_pattern, tmpl_level_t level)
24527887SLiane.Praza@Sun.COM {
24537887SLiane.Praza@Sun.COM 	const char *target;
24547887SLiane.Praza@Sun.COM 
24557887SLiane.Praza@Sun.COM 	target = find_astring_value_in_pg(pg_pattern, SCF_PROPERTY_TM_TARGET);
24567887SLiane.Praza@Sun.COM 	if (level == TL_COMPOSED) {
24577887SLiane.Praza@Sun.COM 		switch (pg_pattern->sc_parent->sc_etype) {
24587887SLiane.Praza@Sun.COM 		case SVCCFG_INSTANCE_OBJECT:
24597887SLiane.Praza@Sun.COM 			level = TL_INSTANCE;
24607887SLiane.Praza@Sun.COM 			break;
24617887SLiane.Praza@Sun.COM 		case SVCCFG_SERVICE_OBJECT:
24627887SLiane.Praza@Sun.COM 			level = TL_SERVICE;
24637887SLiane.Praza@Sun.COM 			break;
24647887SLiane.Praza@Sun.COM 		default:
24657887SLiane.Praza@Sun.COM 			assert(0);
24667887SLiane.Praza@Sun.COM 			abort();
24677887SLiane.Praza@Sun.COM 		}
24687887SLiane.Praza@Sun.COM 	}
24697887SLiane.Praza@Sun.COM 	return (target_check(target, level));
24707887SLiane.Praza@Sun.COM }
24717887SLiane.Praza@Sun.COM 
24727887SLiane.Praza@Sun.COM /*
24737887SLiane.Praza@Sun.COM  * Find the prop_pattern's type sepcification and convert it to the
24747887SLiane.Praza@Sun.COM  * appropriate scf_type.
24757887SLiane.Praza@Sun.COM  */
24767887SLiane.Praza@Sun.COM static tmpl_validate_status_t
prop_pattern_type(pgroup_t * pattern,scf_type_t * type)24777887SLiane.Praza@Sun.COM prop_pattern_type(pgroup_t *pattern, scf_type_t *type)
24787887SLiane.Praza@Sun.COM {
24797887SLiane.Praza@Sun.COM 	const char *type_spec;
24807887SLiane.Praza@Sun.COM 
24817887SLiane.Praza@Sun.COM 	assert(strcmp(pattern->sc_pgroup_type,
24827887SLiane.Praza@Sun.COM 	    SCF_GROUP_TEMPLATE_PROP_PATTERN) == 0);
24837887SLiane.Praza@Sun.COM 
24847887SLiane.Praza@Sun.COM 	type_spec = find_type_specification(pattern);
24857887SLiane.Praza@Sun.COM 	if ((type_spec == NULL) || (*type_spec == 0))
24867887SLiane.Praza@Sun.COM 		return (TVS_MISSING_TYPE_SPECIFICATION);
24877887SLiane.Praza@Sun.COM 	*type = scf_string_to_type(type_spec);
24887887SLiane.Praza@Sun.COM 	return (TVS_SUCCESS);
24897887SLiane.Praza@Sun.COM }
24907887SLiane.Praza@Sun.COM 
24917887SLiane.Praza@Sun.COM /*
24927887SLiane.Praza@Sun.COM  * This function is analagous to scf_property_is_type(3SCF), but it works
24937887SLiane.Praza@Sun.COM  * on the in memory representation of the property.
24947887SLiane.Praza@Sun.COM  *
24957887SLiane.Praza@Sun.COM  * RETURNS:
24967887SLiane.Praza@Sun.COM  *	0		The property at prop does not have the specified
24977887SLiane.Praza@Sun.COM  *			type.
24987887SLiane.Praza@Sun.COM  *	non-zero	The property at prop does have the specified type.
24997887SLiane.Praza@Sun.COM  */
25007887SLiane.Praza@Sun.COM static int
property_is_type(property_t * prop,scf_type_t type)25017887SLiane.Praza@Sun.COM property_is_type(property_t *prop, scf_type_t type)
25027887SLiane.Praza@Sun.COM {
2503*9765SSean.Wilcox@Sun.COM 	return (scf_is_compatible_type(type, prop->sc_value_type) ==
2504*9765SSean.Wilcox@Sun.COM 	    SCF_SUCCESS);
25057887SLiane.Praza@Sun.COM }
25067887SLiane.Praza@Sun.COM 
25077887SLiane.Praza@Sun.COM /*
25087887SLiane.Praza@Sun.COM  * This function generates a property group name for a template's
25097887SLiane.Praza@Sun.COM  * pg_pattern.  The name and type of the pg_pattern are used to construct
25107887SLiane.Praza@Sun.COM  * the name, but either or both may be null.  A pointer to the constructed
25117887SLiane.Praza@Sun.COM  * name is returned, and the referenced memory must be freed using
25127887SLiane.Praza@Sun.COM  * free(3c).  NULL is returned if we are unable to allocate enough memory.
25137887SLiane.Praza@Sun.COM  */
25147887SLiane.Praza@Sun.COM static char *
gen_pg_pattern_pg_name(const char * name,const char * type)25157887SLiane.Praza@Sun.COM gen_pg_pattern_pg_name(const char *name, const char *type)
25167887SLiane.Praza@Sun.COM {
25177887SLiane.Praza@Sun.COM 	char *pg_name;
25187887SLiane.Praza@Sun.COM 	char *rv = NULL;
25197887SLiane.Praza@Sun.COM 	ssize_t	name_size;
25207887SLiane.Praza@Sun.COM 
25217887SLiane.Praza@Sun.COM 	name_size = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH);
25227887SLiane.Praza@Sun.COM 	pg_name = safe_malloc(name_size);
25237887SLiane.Praza@Sun.COM 	rv = pg_name;
25247887SLiane.Praza@Sun.COM 
25257887SLiane.Praza@Sun.COM 	/*
25267887SLiane.Praza@Sun.COM 	 * There are four cases -- name and type are both null, name and
25277887SLiane.Praza@Sun.COM 	 * type are both non-null, only name is present or only type is
25287887SLiane.Praza@Sun.COM 	 * present.
25297887SLiane.Praza@Sun.COM 	 */
25307887SLiane.Praza@Sun.COM 	if ((name == NULL) || (*name == 0)) {
25317887SLiane.Praza@Sun.COM 		if ((type == NULL) || (*type == 0)) {
25327887SLiane.Praza@Sun.COM 			/*
25337887SLiane.Praza@Sun.COM 			 * Name and type are both null, so the PG name
25347887SLiane.Praza@Sun.COM 			 * contains only the prefix.
25357887SLiane.Praza@Sun.COM 			 */
25367887SLiane.Praza@Sun.COM 			if (strlcpy(pg_name, SCF_PG_TM_PG_PATTERN_PREFIX,
25377887SLiane.Praza@Sun.COM 			    name_size) >= name_size) {
25387887SLiane.Praza@Sun.COM 				rv = NULL;
25397887SLiane.Praza@Sun.COM 			}
25407887SLiane.Praza@Sun.COM 		} else {
25417887SLiane.Praza@Sun.COM 			/*
25427887SLiane.Praza@Sun.COM 			 * If we have a type and no name, the type becomes
25437887SLiane.Praza@Sun.COM 			 * part of the pg_pattern property group name.
25447887SLiane.Praza@Sun.COM 			 */
25457887SLiane.Praza@Sun.COM 			if (snprintf(pg_name, name_size, "%s%s",
25467887SLiane.Praza@Sun.COM 			    SCF_PG_TM_PG_PATTERN_T_PREFIX, type) >=
25477887SLiane.Praza@Sun.COM 			    name_size) {
25487887SLiane.Praza@Sun.COM 				rv = NULL;
25497887SLiane.Praza@Sun.COM 			}
25507887SLiane.Praza@Sun.COM 		}
25517887SLiane.Praza@Sun.COM 	} else {
25527887SLiane.Praza@Sun.COM 		/*
25537887SLiane.Praza@Sun.COM 		 * As long as the pg_pattern has a name, it becomes part of
25547887SLiane.Praza@Sun.COM 		 * the name of the pg_pattern property group name.  We
25557887SLiane.Praza@Sun.COM 		 * merely need to pick the appropriate prefix.
25567887SLiane.Praza@Sun.COM 		 */
25577887SLiane.Praza@Sun.COM 		const char *prefix;
25587887SLiane.Praza@Sun.COM 		if ((type == NULL) || (*type == 0)) {
25597887SLiane.Praza@Sun.COM 			prefix = SCF_PG_TM_PG_PATTERN_N_PREFIX;
25607887SLiane.Praza@Sun.COM 		} else {
25617887SLiane.Praza@Sun.COM 			prefix = SCF_PG_TM_PG_PATTERN_NT_PREFIX;
25627887SLiane.Praza@Sun.COM 		}
25637887SLiane.Praza@Sun.COM 		if (snprintf(pg_name, name_size, "%s%s", prefix, name) >=
25647887SLiane.Praza@Sun.COM 		    name_size) {
25657887SLiane.Praza@Sun.COM 			rv = NULL;
25667887SLiane.Praza@Sun.COM 		}
25677887SLiane.Praza@Sun.COM 	}
25687887SLiane.Praza@Sun.COM 
25697887SLiane.Praza@Sun.COM 	if (rv == NULL) {
25707887SLiane.Praza@Sun.COM 		/* Name was too big. */
25717887SLiane.Praza@Sun.COM 		free(pg_name);
25727887SLiane.Praza@Sun.COM 	}
25737887SLiane.Praza@Sun.COM 	return (rv);
25747887SLiane.Praza@Sun.COM }
25757887SLiane.Praza@Sun.COM 
25767887SLiane.Praza@Sun.COM /*
25777887SLiane.Praza@Sun.COM  * pinfo contains information about a prop_pattern.  An include_values
25787887SLiane.Praza@Sun.COM  * element with a type of type has been included in the prop_pattern
25797887SLiane.Praza@Sun.COM  * specification.  We need to determine if the prop_pattern also contains
25807887SLiane.Praza@Sun.COM  * constraints or values specifications as determined by type.  Thus, we
25817887SLiane.Praza@Sun.COM  * search the prop_pattern for properties whose names start with the
25827887SLiane.Praza@Sun.COM  * correct prefix.
25837887SLiane.Praza@Sun.COM  */
25847887SLiane.Praza@Sun.COM static tmpl_validate_status_t
include_values_support(ptrn_info_t * pinfo,const char * type,tmpl_errors_t * errs)25857887SLiane.Praza@Sun.COM include_values_support(ptrn_info_t *pinfo, const char *type,
25867887SLiane.Praza@Sun.COM     tmpl_errors_t *errs)
25877887SLiane.Praza@Sun.COM {
25887887SLiane.Praza@Sun.COM 	error_info_t einfo;
25897887SLiane.Praza@Sun.COM 	int i;
25907887SLiane.Praza@Sun.COM 	const char **prefixes;
25917887SLiane.Praza@Sun.COM 	const char *pfx;
25927887SLiane.Praza@Sun.COM 	property_t *prop;
25937887SLiane.Praza@Sun.COM 	pgroup_t *ptrn;
25947887SLiane.Praza@Sun.COM 
25957887SLiane.Praza@Sun.COM 	if (strcmp(type, "constraints") == 0) {
25967887SLiane.Praza@Sun.COM 		prefixes = constraint_prefixes;
25977887SLiane.Praza@Sun.COM 	} else if (strcmp(type, "values") == 0) {
25987887SLiane.Praza@Sun.COM 		prefixes = value_prefixes;
25997887SLiane.Praza@Sun.COM 	} else {
26007887SLiane.Praza@Sun.COM 		CLEAR_ERROR_INFO(&einfo);
26017887SLiane.Praza@Sun.COM 		einfo.ei_type = EIT_BAD_TEMPLATE;
26027887SLiane.Praza@Sun.COM 		einfo.ei_u.ei_bad_template.ei_reason = gettext("include_values "
26037887SLiane.Praza@Sun.COM 		    "type must be \"constraints\" or \"values\"");
26047887SLiane.Praza@Sun.COM 		(void) tmpl_errors_add_im(errs, TVS_BAD_TEMPLATE,
26057887SLiane.Praza@Sun.COM 		    pinfo->pi_ptrnpg->sc_parent, pinfo->pi_enc_pgp,
26067887SLiane.Praza@Sun.COM 		    NULL, pinfo->pi_ptrnpg, NULL, NULL, &einfo);
26077887SLiane.Praza@Sun.COM 		return (TVS_BAD_TEMPLATE);
26087887SLiane.Praza@Sun.COM 	}
26097887SLiane.Praza@Sun.COM 
26107887SLiane.Praza@Sun.COM 	/*
26117887SLiane.Praza@Sun.COM 	 * Now see if the prop_pattern has a property whose name starts
26127887SLiane.Praza@Sun.COM 	 * with one of these prefixes.
26137887SLiane.Praza@Sun.COM 	 */
26147887SLiane.Praza@Sun.COM 	ptrn = pinfo->pi_ptrnpg;
26157887SLiane.Praza@Sun.COM 	for (prop = uu_list_first(ptrn->sc_pgroup_props);
26167887SLiane.Praza@Sun.COM 	    prop != NULL;
26177887SLiane.Praza@Sun.COM 	    prop = uu_list_next(ptrn->sc_pgroup_props, prop)) {
26187887SLiane.Praza@Sun.COM 		for (pfx = prefixes[0], i = 0;
26197887SLiane.Praza@Sun.COM 		    pfx != NULL;
26207887SLiane.Praza@Sun.COM 		    ++i, pfx = prefixes[i]) {
26217887SLiane.Praza@Sun.COM 			if (strncmp(prop->sc_property_name, pfx,
26227887SLiane.Praza@Sun.COM 			    strlen(pfx)) == 0) {
26237887SLiane.Praza@Sun.COM 				return (TVS_SUCCESS);
26247887SLiane.Praza@Sun.COM 			}
26257887SLiane.Praza@Sun.COM 		}
26267887SLiane.Praza@Sun.COM 	}
26277887SLiane.Praza@Sun.COM 
26287887SLiane.Praza@Sun.COM 	/* No match found.  Generate error */
26297887SLiane.Praza@Sun.COM 	CLEAR_ERROR_INFO(&einfo);
26307887SLiane.Praza@Sun.COM 	einfo.ei_type = EIT_INCLUDE_VALUES;
26317887SLiane.Praza@Sun.COM 	einfo.ei_u.ei_inc_values.ei_type = type;
26327887SLiane.Praza@Sun.COM 	(void) add_scf_error(errs, SCF_TERR_INCLUDE_VALUES, pinfo->pi_enc_pgp,
26337887SLiane.Praza@Sun.COM 	    NULL, ptrn, NULL, NULL, &einfo);
26347887SLiane.Praza@Sun.COM 
26357887SLiane.Praza@Sun.COM 	return (TVS_VALIDATION);
26367887SLiane.Praza@Sun.COM }
26377887SLiane.Praza@Sun.COM 
26387887SLiane.Praza@Sun.COM /*
26397887SLiane.Praza@Sun.COM  * Walk through the prop_patterns in tree, looking for any that have an
26407887SLiane.Praza@Sun.COM  * include_values, SCF_PROPERTY_TM_CHOICES_INCLUDE_VALUES, property.  For
26417887SLiane.Praza@Sun.COM  * the prop_patterns with the include values property, verify that the
26427887SLiane.Praza@Sun.COM  * prop_pattern has constraint or values declarations as specified by the
26437887SLiane.Praza@Sun.COM  * include_values property.
26447887SLiane.Praza@Sun.COM  */
26457887SLiane.Praza@Sun.COM static tmpl_validate_status_t
tmpl_include_values_check(uu_avl_t * tree,tmpl_errors_t * errs)26467887SLiane.Praza@Sun.COM tmpl_include_values_check(uu_avl_t *tree, tmpl_errors_t *errs)
26477887SLiane.Praza@Sun.COM {
26487887SLiane.Praza@Sun.COM 	ptrn_info_t *info;
26497887SLiane.Praza@Sun.COM 	property_t *iv;
26507887SLiane.Praza@Sun.COM 	tmpl_validate_status_t r;
26517887SLiane.Praza@Sun.COM 	tmpl_validate_status_t rc = TVS_SUCCESS;
26527887SLiane.Praza@Sun.COM 	value_t *v;
26537887SLiane.Praza@Sun.COM 
26547887SLiane.Praza@Sun.COM 	for (info = uu_avl_first(tree);
26557887SLiane.Praza@Sun.COM 	    info != NULL;
26567887SLiane.Praza@Sun.COM 	    info = uu_avl_next(tree, info)) {
26577887SLiane.Praza@Sun.COM 		iv = internal_property_find(info->pi_ptrnpg,
26587887SLiane.Praza@Sun.COM 		    SCF_PROPERTY_TM_CHOICES_INCLUDE_VALUES);
26597887SLiane.Praza@Sun.COM 		if (iv == NULL)
26607887SLiane.Praza@Sun.COM 			continue;
26617887SLiane.Praza@Sun.COM 		for (v = uu_list_first(iv->sc_property_values);
26627887SLiane.Praza@Sun.COM 		    v != NULL;
26637887SLiane.Praza@Sun.COM 		    v = uu_list_next(iv->sc_property_values, v)) {
26647887SLiane.Praza@Sun.COM 			assert(is_numeric_type(v->sc_type) == 0);
26657887SLiane.Praza@Sun.COM 			r = include_values_support(info, v->sc_u.sc_string,
26667887SLiane.Praza@Sun.COM 			    errs);
26677887SLiane.Praza@Sun.COM 			if (r != TVS_SUCCESS)
26687887SLiane.Praza@Sun.COM 				rc = r;
26697887SLiane.Praza@Sun.COM 		}
26707887SLiane.Praza@Sun.COM 	}
26717887SLiane.Praza@Sun.COM 	return (rc);
26727887SLiane.Praza@Sun.COM }
26737887SLiane.Praza@Sun.COM 
26747887SLiane.Praza@Sun.COM /*
26757887SLiane.Praza@Sun.COM  * Verify that there are no conflicting definitions of pg_pattern or
26767887SLiane.Praza@Sun.COM  * prop_pattern.  Two patterns are said to be in conflict if they have the
26777887SLiane.Praza@Sun.COM  * same name and differing types.  There is a caveat, however.  Empty
26787887SLiane.Praza@Sun.COM  * pattern names or types are considered to be wild cards.  There is no
26797887SLiane.Praza@Sun.COM  * conflict if a pattern has a wild card.
26807887SLiane.Praza@Sun.COM  */
26817887SLiane.Praza@Sun.COM static tmpl_validate_status_t
tmpl_pattern_conflict(entity_t * inst,uu_avl_t * tree,ptrn_type_t type,tmpl_errors_t * errs)26827887SLiane.Praza@Sun.COM tmpl_pattern_conflict(entity_t *inst, uu_avl_t *tree, ptrn_type_t type,
26837887SLiane.Praza@Sun.COM     tmpl_errors_t *errs)
26847887SLiane.Praza@Sun.COM {
26857887SLiane.Praza@Sun.COM 	tmpl_validate_status_t r;
26867887SLiane.Praza@Sun.COM 	tmpl_validate_status_t rc;
26877887SLiane.Praza@Sun.COM 
26887887SLiane.Praza@Sun.COM 	/* First walk the instance. */
26897887SLiane.Praza@Sun.COM 	rc = gather_pattern(inst, type, tree, errs);
26907887SLiane.Praza@Sun.COM 
26917887SLiane.Praza@Sun.COM 	/* Now walk the service */
26927887SLiane.Praza@Sun.COM 	r = gather_pattern(inst->sc_parent, type, tree, errs);
26937887SLiane.Praza@Sun.COM 	if (r != TVS_SUCCESS)
26947887SLiane.Praza@Sun.COM 		rc = r;
26957887SLiane.Praza@Sun.COM 
26967887SLiane.Praza@Sun.COM 	return (rc);
26977887SLiane.Praza@Sun.COM }
26987887SLiane.Praza@Sun.COM 
26997887SLiane.Praza@Sun.COM static tmpl_validate_status_t
tmpl_required_attr_present(uu_avl_t * tree,tmpl_errors_t * errs)27007887SLiane.Praza@Sun.COM tmpl_required_attr_present(uu_avl_t *tree, tmpl_errors_t *errs)
27017887SLiane.Praza@Sun.COM {
27027887SLiane.Praza@Sun.COM 	ptrn_info_t *pinfo;
27037887SLiane.Praza@Sun.COM 	tmpl_validate_status_t rc = TVS_SUCCESS;
27047887SLiane.Praza@Sun.COM 	int reported_name;
27057887SLiane.Praza@Sun.COM 	int rv;
27067887SLiane.Praza@Sun.COM 
27077887SLiane.Praza@Sun.COM 	for (pinfo = uu_avl_first(tree);
27087887SLiane.Praza@Sun.COM 	    pinfo != NULL;
27097887SLiane.Praza@Sun.COM 	    pinfo = uu_avl_next(tree, pinfo)) {
27107887SLiane.Praza@Sun.COM 		if (is_required(pinfo->pi_ptrnpg) == 0) {
27117887SLiane.Praza@Sun.COM 			/* Nothing to check if pattern is not required. */
27127887SLiane.Praza@Sun.COM 			continue;
27137887SLiane.Praza@Sun.COM 		}
27147887SLiane.Praza@Sun.COM 
27157887SLiane.Praza@Sun.COM 		/*
27167887SLiane.Praza@Sun.COM 		 * For pg_pattern both name and type are optional unless
27177887SLiane.Praza@Sun.COM 		 * the required attribute has a value of true.  For
27187887SLiane.Praza@Sun.COM 		 * prop_patterns only the type is optional, but it must be
27197887SLiane.Praza@Sun.COM 		 * provided if the required attribute has a value of true.
27207887SLiane.Praza@Sun.COM 		 */
27217887SLiane.Praza@Sun.COM 		reported_name = 0;
27227887SLiane.Praza@Sun.COM 		if ((pinfo->pi_ptrn_type == PG_PATTERN) &&
27237887SLiane.Praza@Sun.COM 		    (pinfo->pi_name == NULL)) {
27247887SLiane.Praza@Sun.COM 			rc = TVS_VALIDATION;
27257887SLiane.Praza@Sun.COM 			if (add_scf_error(errs, SCF_TERR_PG_PATTERN_INCOMPLETE,
27267887SLiane.Praza@Sun.COM 			    pinfo->pi_ptrnpg,
27277887SLiane.Praza@Sun.COM 			    NULL, NULL, NULL, NULL, NULL) != 0) {
27287887SLiane.Praza@Sun.COM 				/*
27297887SLiane.Praza@Sun.COM 				 * If we're unable to report errors, break
27307887SLiane.Praza@Sun.COM 				 * out of the loop.
27317887SLiane.Praza@Sun.COM 				 */
27327887SLiane.Praza@Sun.COM 				break;
27337887SLiane.Praza@Sun.COM 			}
27347887SLiane.Praza@Sun.COM 			/*
27357887SLiane.Praza@Sun.COM 			 * Don't report the error twice if both name and
27367887SLiane.Praza@Sun.COM 			 * type are missing.  One error message is
27377887SLiane.Praza@Sun.COM 			 * adequate.
27387887SLiane.Praza@Sun.COM 			 */
27397887SLiane.Praza@Sun.COM 			reported_name = 1;
27407887SLiane.Praza@Sun.COM 		}
27417887SLiane.Praza@Sun.COM 		if ((pinfo->pi_type == NULL) && (reported_name == 0)) {
27427887SLiane.Praza@Sun.COM 			rc = TVS_VALIDATION;
27437887SLiane.Praza@Sun.COM 			if (pinfo->pi_ptrn_type == PG_PATTERN) {
27447887SLiane.Praza@Sun.COM 				rv = add_scf_error(errs,
27457887SLiane.Praza@Sun.COM 				    SCF_TERR_PG_PATTERN_INCOMPLETE,
27467887SLiane.Praza@Sun.COM 				    pinfo->pi_ptrnpg,
27477887SLiane.Praza@Sun.COM 				    NULL, NULL, NULL, NULL, NULL);
27487887SLiane.Praza@Sun.COM 			} else {
27497887SLiane.Praza@Sun.COM 				rv = add_scf_error(errs,
27507887SLiane.Praza@Sun.COM 				    SCF_TERR_PROP_PATTERN_INCOMPLETE,
27517887SLiane.Praza@Sun.COM 				    pinfo->pi_enc_pgp, NULL, pinfo->pi_ptrnpg,
27527887SLiane.Praza@Sun.COM 				    NULL, NULL, NULL);
27537887SLiane.Praza@Sun.COM 			}
27547887SLiane.Praza@Sun.COM 			/* If we're unable to log errors, break out of loop. */
27557887SLiane.Praza@Sun.COM 			if (rv != 0)
27567887SLiane.Praza@Sun.COM 				break;
27577887SLiane.Praza@Sun.COM 		}
27587887SLiane.Praza@Sun.COM 	}
27597887SLiane.Praza@Sun.COM 	return (rc);
27607887SLiane.Praza@Sun.COM }
27617887SLiane.Praza@Sun.COM 
27627887SLiane.Praza@Sun.COM /*
27637887SLiane.Praza@Sun.COM  * Look for pg_pattern definitions in general.  general is either the
27647887SLiane.Praza@Sun.COM  * restarter serivce for inst or it is the global service.  tree contains
27657887SLiane.Praza@Sun.COM  * the ptrn_info_t structures describing the pg_patterns for an instance.
27667887SLiane.Praza@Sun.COM  * For each general pg_pattern, see if the instance contains an overriding
27677887SLiane.Praza@Sun.COM  * definition in tree.  If it does generate an error entry.
27687887SLiane.Praza@Sun.COM  *
27697887SLiane.Praza@Sun.COM  * If a redefinition is found, TVS_WARN is returned.  This is because a
27707887SLiane.Praza@Sun.COM  * redefinition is not sufficient reason to inhibit the import operation.
27717887SLiane.Praza@Sun.COM  */
27727887SLiane.Praza@Sun.COM static tmpl_validate_status_t
tmpl_scan_general(entity_t * general,uu_avl_t * tree,tmpl_level_t level,tmpl_errors_t * errs)27737887SLiane.Praza@Sun.COM tmpl_scan_general(entity_t *general, uu_avl_t *tree,
27747887SLiane.Praza@Sun.COM     tmpl_level_t level, tmpl_errors_t *errs)
27757887SLiane.Praza@Sun.COM {
27767887SLiane.Praza@Sun.COM 	tmpl_level_t cur_level;
27777887SLiane.Praza@Sun.COM 	error_info_t einfo;
27787887SLiane.Praza@Sun.COM 	pgroup_t *pg;
27797887SLiane.Praza@Sun.COM 	ptrn_info_t *ginfo = NULL;
27807887SLiane.Praza@Sun.COM 	ptrn_info_t *match;
27817887SLiane.Praza@Sun.COM 	tmpl_validate_status_t rc = TVS_SUCCESS;
27827887SLiane.Praza@Sun.COM 
27837887SLiane.Praza@Sun.COM 	/*
27847887SLiane.Praza@Sun.COM 	 * General services may not be in repository yet.  It depends on
27857887SLiane.Praza@Sun.COM 	 * the order that manifests are imported.
27867887SLiane.Praza@Sun.COM 	 */
27877887SLiane.Praza@Sun.COM 	if (general == NULL)
27887887SLiane.Praza@Sun.COM 		return (TVS_SUCCESS);
27897887SLiane.Praza@Sun.COM 
27907887SLiane.Praza@Sun.COM 	for (pg = uu_list_first(general->sc_pgroups);
27917887SLiane.Praza@Sun.COM 	    pg != NULL;
27927887SLiane.Praza@Sun.COM 	    pg = uu_list_next(general->sc_pgroups, pg)) {
27937887SLiane.Praza@Sun.COM 		if (strcmp(pg->sc_pgroup_type,
27947887SLiane.Praza@Sun.COM 		    SCF_GROUP_TEMPLATE_PG_PATTERN) != 0) {
27957887SLiane.Praza@Sun.COM 			/* Not a pg_pattern */
27967887SLiane.Praza@Sun.COM 			continue;
27977887SLiane.Praza@Sun.COM 		}
27987887SLiane.Praza@Sun.COM 		if (ginfo != NULL)
27997887SLiane.Praza@Sun.COM 			ptrn_info_destroy(ginfo);
28007887SLiane.Praza@Sun.COM 		ginfo = ptrn_info_create(pg);
28017887SLiane.Praza@Sun.COM 		match = uu_avl_find(tree, ginfo, NULL, NULL);
28027887SLiane.Praza@Sun.COM 		if (match != NULL) {
28037887SLiane.Praza@Sun.COM 			/* See if global pg_pattern is targeted at us. */
28047887SLiane.Praza@Sun.COM 			if (target_check(ginfo->pi_target, level) == 0)
28057887SLiane.Praza@Sun.COM 				continue;
28067887SLiane.Praza@Sun.COM 
28077887SLiane.Praza@Sun.COM 			/*
28087887SLiane.Praza@Sun.COM 			 * See if the match applies to us.  If we happen to
28097887SLiane.Praza@Sun.COM 			 * be a restarter, the pg_pattern could have a
28107887SLiane.Praza@Sun.COM 			 * target of delegate.  That wouldn't apply to this
28117887SLiane.Praza@Sun.COM 			 * instance, it would only apply to our delegates.
28127887SLiane.Praza@Sun.COM 			 * Cases such as this are not a redefinition.
28137887SLiane.Praza@Sun.COM 			 */
28147887SLiane.Praza@Sun.COM 			if (match->pi_ptrnpg->sc_parent->sc_etype ==
28157887SLiane.Praza@Sun.COM 			    SVCCFG_INSTANCE_OBJECT) {
28167887SLiane.Praza@Sun.COM 				cur_level = TL_INSTANCE;
28177887SLiane.Praza@Sun.COM 			} else {
28187887SLiane.Praza@Sun.COM 				cur_level = TL_SERVICE;
28197887SLiane.Praza@Sun.COM 			}
28207887SLiane.Praza@Sun.COM 			if (target_check(match->pi_target, cur_level) == 0)
28217887SLiane.Praza@Sun.COM 				continue;
28227887SLiane.Praza@Sun.COM 
28237887SLiane.Praza@Sun.COM 			/*
28247887SLiane.Praza@Sun.COM 			 * Instance or service overrides a general
28257887SLiane.Praza@Sun.COM 			 * definition.  We need to issue a warning message.
28267887SLiane.Praza@Sun.COM 			 */
28277887SLiane.Praza@Sun.COM 			rc = TVS_WARN;
28287887SLiane.Praza@Sun.COM 			CLEAR_ERROR_INFO(&einfo);
28297887SLiane.Praza@Sun.COM 			einfo.ei_type = EIT_PATTERN_CONFLICT;
28307887SLiane.Praza@Sun.COM 			einfo.ei_u.ei_pattern_conflict.ei_pattern = pg;
28317887SLiane.Praza@Sun.COM 			if (add_scf_error(errs, SCF_TERR_GENERAL_REDEFINE,
28327887SLiane.Praza@Sun.COM 			    match->pi_ptrnpg, NULL, NULL, NULL, NULL,
28337887SLiane.Praza@Sun.COM 			    &einfo) != 0) {
28347887SLiane.Praza@Sun.COM 				/*
28357887SLiane.Praza@Sun.COM 				 * No need to continue the search if we
28367887SLiane.Praza@Sun.COM 				 * cannot record errors.
28377887SLiane.Praza@Sun.COM 				 */
28387887SLiane.Praza@Sun.COM 				break;
28397887SLiane.Praza@Sun.COM 			}
28407887SLiane.Praza@Sun.COM 		}
28417887SLiane.Praza@Sun.COM 	}
28427887SLiane.Praza@Sun.COM 
28437887SLiane.Praza@Sun.COM 	if (ginfo != NULL)
28447887SLiane.Praza@Sun.COM 		ptrn_info_destroy(ginfo);
28457887SLiane.Praza@Sun.COM 	return (rc);
28467887SLiane.Praza@Sun.COM }
28477887SLiane.Praza@Sun.COM 
28487887SLiane.Praza@Sun.COM /*
28497887SLiane.Praza@Sun.COM  * tree contains the pg_pattern definitions for the instance at inst.  See
28507887SLiane.Praza@Sun.COM  * if these pg_patterns redefine any pg_patterns in the instance's
28517887SLiane.Praza@Sun.COM  * restarter or in the global service.  TVS_WARN is returned if a
28527887SLiane.Praza@Sun.COM  * redefinition is encountered.
28537887SLiane.Praza@Sun.COM  */
28547887SLiane.Praza@Sun.COM static tmpl_validate_status_t
tmpl_level_redefine(entity_t * inst,uu_avl_t * tree,tmpl_errors_t * errs)28557887SLiane.Praza@Sun.COM tmpl_level_redefine(entity_t *inst, uu_avl_t *tree, tmpl_errors_t *errs)
28567887SLiane.Praza@Sun.COM {
28577887SLiane.Praza@Sun.COM 	entity_t *restarter;
28587887SLiane.Praza@Sun.COM 	entity_t *svc = inst->sc_parent;
28597887SLiane.Praza@Sun.COM 	tmpl_validate_status_t r;
28607887SLiane.Praza@Sun.COM 	tmpl_validate_status_t rc;
28617887SLiane.Praza@Sun.COM 
28627887SLiane.Praza@Sun.COM 	restarter = inst->sc_u.sc_instance.sc_instance_restarter;
28637887SLiane.Praza@Sun.COM 	if (restarter == NULL) {
28647887SLiane.Praza@Sun.COM 		/* No instance restarter.  Use the service restarter */
28657887SLiane.Praza@Sun.COM 		restarter = svc->sc_u.sc_service.sc_restarter;
28667887SLiane.Praza@Sun.COM 	}
28677887SLiane.Praza@Sun.COM 	rc = tmpl_scan_general(restarter, tree, TL_RESTARTER, errs);
28687887SLiane.Praza@Sun.COM 	r = tmpl_scan_general(svc->sc_u.sc_service.sc_global, tree,
28697887SLiane.Praza@Sun.COM 	    TL_GLOBAL, errs);
28707887SLiane.Praza@Sun.COM 	if (r != TVS_SUCCESS)
28717887SLiane.Praza@Sun.COM 		rc = r;
28727887SLiane.Praza@Sun.COM 	return (rc);
28737887SLiane.Praza@Sun.COM }
28747887SLiane.Praza@Sun.COM 
28757887SLiane.Praza@Sun.COM /*
28767887SLiane.Praza@Sun.COM  * Perform the following consistency checks on the template specifications
28777887SLiane.Praza@Sun.COM  * themselves:
28787887SLiane.Praza@Sun.COM  *
28797887SLiane.Praza@Sun.COM  *	- No conflicting definitions of `pg_pattern` are allowed within a
28807887SLiane.Praza@Sun.COM  *	  single instance.
28817887SLiane.Praza@Sun.COM  *
28827887SLiane.Praza@Sun.COM  *	- Templates at a narrow target (e.g. instance) which define
28837887SLiane.Praza@Sun.COM  *	  property groups already templated at a broad target
28847887SLiane.Praza@Sun.COM  *	  (e.g. restarter or all) are strongly discouraged.
28857887SLiane.Praza@Sun.COM  *
28867887SLiane.Praza@Sun.COM  *	- Developers may not define a template which specifies a single
28877887SLiane.Praza@Sun.COM  *	  prop_pattern name with differing types on the same target
28887887SLiane.Praza@Sun.COM  *	  entity.
28897887SLiane.Praza@Sun.COM  *
28907887SLiane.Praza@Sun.COM  *	- If a pg_pattern has a required attribute with a value of true,
28917887SLiane.Praza@Sun.COM  *	  then its name and type attributes must be specified.
28927887SLiane.Praza@Sun.COM  *
28937887SLiane.Praza@Sun.COM  *	- If a prop_pattern has a required attribute with a value of true,
28947887SLiane.Praza@Sun.COM  *	  then its type attribute must be specified.
28957887SLiane.Praza@Sun.COM  *
28967887SLiane.Praza@Sun.COM  *	- If a prop_pattern has an include values make sure that the
28977887SLiane.Praza@Sun.COM  *	  appropriate constraints or values element has also been
28987887SLiane.Praza@Sun.COM  *	  declared.
28997887SLiane.Praza@Sun.COM  */
29007887SLiane.Praza@Sun.COM static tmpl_validate_status_t
tmpl_consistency(entity_t * inst,tmpl_errors_t * errs)29017887SLiane.Praza@Sun.COM tmpl_consistency(entity_t *inst, tmpl_errors_t *errs)
29027887SLiane.Praza@Sun.COM {
29037887SLiane.Praza@Sun.COM 	void *marker = NULL;
29047887SLiane.Praza@Sun.COM 	ptrn_info_t *info;
29057887SLiane.Praza@Sun.COM 	uu_avl_t *tree;
29067887SLiane.Praza@Sun.COM 	tmpl_validate_status_t rc;
29077887SLiane.Praza@Sun.COM 	tmpl_validate_status_t r;
29087887SLiane.Praza@Sun.COM 
29097887SLiane.Praza@Sun.COM 	/* Allocate the tree. */
29107887SLiane.Praza@Sun.COM 	tree = uu_avl_create(ptrn_info_pool, NULL, TMPL_DEBUG_TREE);
29117887SLiane.Praza@Sun.COM 	if (tree == NULL) {
29127887SLiane.Praza@Sun.COM 		uu_die(gettext("pg_info tree creation failed: %s\n"),
29137887SLiane.Praza@Sun.COM 		    uu_strerror(uu_error()));
29147887SLiane.Praza@Sun.COM 	}
29157887SLiane.Praza@Sun.COM 
29167887SLiane.Praza@Sun.COM 	rc = tmpl_pattern_conflict(inst, tree, PG_PATTERN, errs);
29177887SLiane.Praza@Sun.COM 
29187887SLiane.Praza@Sun.COM 	/*
29197887SLiane.Praza@Sun.COM 	 * The tree now contains the instance and service pg_patterns.
29207887SLiane.Praza@Sun.COM 	 * Check to see if they override any pg_pattern definitions in the
29217887SLiane.Praza@Sun.COM 	 * restarter and global services.
29227887SLiane.Praza@Sun.COM 	 */
29237887SLiane.Praza@Sun.COM 	r = tmpl_level_redefine(inst, tree, errs);
29247887SLiane.Praza@Sun.COM 	if (r != TVS_SUCCESS) {
29257887SLiane.Praza@Sun.COM 		/*
29267887SLiane.Praza@Sun.COM 		 * tmpl_level_redefine() can return a warning.  Don't
29277887SLiane.Praza@Sun.COM 		 * override a serious error with a warning.
29287887SLiane.Praza@Sun.COM 		 */
29297887SLiane.Praza@Sun.COM 		if (r == TVS_WARN) {
29307887SLiane.Praza@Sun.COM 			if (rc == TVS_SUCCESS)
29317887SLiane.Praza@Sun.COM 				rc = r;
29327887SLiane.Praza@Sun.COM 		} else {
29337887SLiane.Praza@Sun.COM 			rc = r;
29347887SLiane.Praza@Sun.COM 		}
29357887SLiane.Praza@Sun.COM 	}
29367887SLiane.Praza@Sun.COM 
29377887SLiane.Praza@Sun.COM 	/*
29387887SLiane.Praza@Sun.COM 	 * If the pg_pattern has a required attribute with a value of true,
29397887SLiane.Praza@Sun.COM 	 * then it must also have name and type attributes.
29407887SLiane.Praza@Sun.COM 	 */
29417887SLiane.Praza@Sun.COM 	r = tmpl_required_attr_present(tree, errs);
29427887SLiane.Praza@Sun.COM 	if (r != TVS_SUCCESS)
29437887SLiane.Praza@Sun.COM 		rc = r;
29447887SLiane.Praza@Sun.COM 
29457887SLiane.Praza@Sun.COM 	/* Empty the tree, so that we can reuse it for prop_patterns. */
29467887SLiane.Praza@Sun.COM 	while ((info = uu_avl_teardown(tree, &marker)) != NULL) {
29477887SLiane.Praza@Sun.COM 		ptrn_info_destroy(info);
29487887SLiane.Praza@Sun.COM 	}
29497887SLiane.Praza@Sun.COM 
29507887SLiane.Praza@Sun.COM 	r = tmpl_pattern_conflict(inst, tree, PROP_PATTERN, errs);
29517887SLiane.Praza@Sun.COM 	if (r != TVS_SUCCESS)
29527887SLiane.Praza@Sun.COM 		rc = r;
29537887SLiane.Praza@Sun.COM 
29547887SLiane.Praza@Sun.COM 	/*
29557887SLiane.Praza@Sun.COM 	 * If a prop_pattern has required attribute with a value of true,
29567887SLiane.Praza@Sun.COM 	 * then it must also have a type attribute.
29577887SLiane.Praza@Sun.COM 	 */
29587887SLiane.Praza@Sun.COM 	r = tmpl_required_attr_present(tree, errs);
29597887SLiane.Praza@Sun.COM 	if (r != TVS_SUCCESS)
29607887SLiane.Praza@Sun.COM 		rc = r;
29617887SLiane.Praza@Sun.COM 
29627887SLiane.Praza@Sun.COM 	/*
29637887SLiane.Praza@Sun.COM 	 * Insure that include_values have the constraint for values
29647887SLiane.Praza@Sun.COM 	 * elements that are needed.
29657887SLiane.Praza@Sun.COM 	 */
29667887SLiane.Praza@Sun.COM 	r = tmpl_include_values_check(tree, errs);
29677887SLiane.Praza@Sun.COM 	if (r != TVS_SUCCESS)
29687887SLiane.Praza@Sun.COM 		rc = r;
29697887SLiane.Praza@Sun.COM 
29707887SLiane.Praza@Sun.COM 	/* Tear down the tree. */
29717887SLiane.Praza@Sun.COM 	marker = NULL;
29727887SLiane.Praza@Sun.COM 	while ((info = uu_avl_teardown(tree, &marker)) != NULL) {
29737887SLiane.Praza@Sun.COM 		ptrn_info_destroy(info);
29747887SLiane.Praza@Sun.COM 	}
29757887SLiane.Praza@Sun.COM 	uu_avl_destroy(tree);
29767887SLiane.Praza@Sun.COM 
29777887SLiane.Praza@Sun.COM 	return (rc);
29787887SLiane.Praza@Sun.COM }
29797887SLiane.Praza@Sun.COM 
29807887SLiane.Praza@Sun.COM /*
29817887SLiane.Praza@Sun.COM  * Release memory associated with the tmpl_errors structure and then free
29827887SLiane.Praza@Sun.COM  * the structure itself.
29837887SLiane.Praza@Sun.COM  */
29847887SLiane.Praza@Sun.COM void
tmpl_errors_destroy(tmpl_errors_t * te)29857887SLiane.Praza@Sun.COM tmpl_errors_destroy(tmpl_errors_t *te)
29867887SLiane.Praza@Sun.COM {
29877887SLiane.Praza@Sun.COM 	im_tmpl_error_t *ite;
29887887SLiane.Praza@Sun.COM 	tv_errors_t *ste;
29897887SLiane.Praza@Sun.COM 	void *marker = NULL;
29907887SLiane.Praza@Sun.COM 
29917887SLiane.Praza@Sun.COM 	if (te == NULL)
29927887SLiane.Praza@Sun.COM 		return;
29937887SLiane.Praza@Sun.COM 	if (te->te_list) {
29947887SLiane.Praza@Sun.COM 		while ((ite = uu_list_teardown(te->te_list, &marker)) != NULL) {
29957887SLiane.Praza@Sun.COM 			uu_list_node_fini(ite, &ite->ite_node,
29967887SLiane.Praza@Sun.COM 			    inmem_errors_pool);
29977887SLiane.Praza@Sun.COM 			uu_free(ite);
29987887SLiane.Praza@Sun.COM 		}
29997887SLiane.Praza@Sun.COM 		uu_list_destroy(te->te_list);
30007887SLiane.Praza@Sun.COM 	}
30017887SLiane.Praza@Sun.COM 	if (te->te_scf) {
30027887SLiane.Praza@Sun.COM 		marker = NULL;
30037887SLiane.Praza@Sun.COM 		while ((ste = uu_list_teardown(te->te_scf, &marker)) != NULL) {
30047887SLiane.Praza@Sun.COM 			destroy_scf_errors(ste);
30057887SLiane.Praza@Sun.COM 		}
30067887SLiane.Praza@Sun.COM 		uu_list_destroy(te->te_scf);
30077887SLiane.Praza@Sun.COM 	}
30087887SLiane.Praza@Sun.COM 	uu_free(te);
30097887SLiane.Praza@Sun.COM }
30107887SLiane.Praza@Sun.COM 
30117887SLiane.Praza@Sun.COM /*
30127887SLiane.Praza@Sun.COM  * Allocate and initialize a tmpl_errors structure.  The address of the
30137887SLiane.Praza@Sun.COM  * structure is returned, unless we are unable to allocate enough memory.
30147887SLiane.Praza@Sun.COM  * In the case of memory allocation failures, NULL is returned.
30157887SLiane.Praza@Sun.COM  *
30167887SLiane.Praza@Sun.COM  * The allocated structure should be freed by calling
30177887SLiane.Praza@Sun.COM  * tmpl_errors_destroy().
30187887SLiane.Praza@Sun.COM  */
30197887SLiane.Praza@Sun.COM static tmpl_errors_t *
tmpl_errors_create()30207887SLiane.Praza@Sun.COM tmpl_errors_create()
30217887SLiane.Praza@Sun.COM {
30227887SLiane.Praza@Sun.COM 	tmpl_errors_t *te;
30237887SLiane.Praza@Sun.COM 
30247887SLiane.Praza@Sun.COM 	te = uu_zalloc(sizeof (*te));
30257887SLiane.Praza@Sun.COM 	if (te == NULL)
30267887SLiane.Praza@Sun.COM 		return (NULL);
30277887SLiane.Praza@Sun.COM 	te->te_list = uu_list_create(inmem_errors_pool, NULL, TMPL_DEBUG_LIST);
30287887SLiane.Praza@Sun.COM 	if (te->te_list == NULL) {
30297887SLiane.Praza@Sun.COM 		uu_free(te);
30307887SLiane.Praza@Sun.COM 		return (NULL);
30317887SLiane.Praza@Sun.COM 	}
30327887SLiane.Praza@Sun.COM 	te->te_scf = uu_list_create(tv_errors_pool, NULL, TMPL_DEBUG_LIST);
30337887SLiane.Praza@Sun.COM 	if (te->te_scf == NULL) {
30347887SLiane.Praza@Sun.COM 		tmpl_errors_destroy(te);
30357887SLiane.Praza@Sun.COM 		return (NULL);
30367887SLiane.Praza@Sun.COM 	}
30377887SLiane.Praza@Sun.COM 
30387887SLiane.Praza@Sun.COM 	return (te);
30397887SLiane.Praza@Sun.COM }
30407887SLiane.Praza@Sun.COM 
30417887SLiane.Praza@Sun.COM void
tmpl_errors_print(FILE * out,tmpl_errors_t * errs,const char * prefix)30427887SLiane.Praza@Sun.COM tmpl_errors_print(FILE *out, tmpl_errors_t *errs, const char *prefix)
30437887SLiane.Praza@Sun.COM {
30447887SLiane.Praza@Sun.COM 	scf_tmpl_error_t *cur;
30457887SLiane.Praza@Sun.COM 	size_t buf_size = 4096;
30467887SLiane.Praza@Sun.COM 	im_tmpl_error_t *ite;
30477887SLiane.Praza@Sun.COM 	char *s = NULL;
30487887SLiane.Praza@Sun.COM 	scf_tmpl_errors_t *scferrs;
30497887SLiane.Praza@Sun.COM 	tv_errors_t *scft;
30507887SLiane.Praza@Sun.COM 	int interactive = (est->sc_cmd_flags & SC_CMD_IACTIVE) ?
30517887SLiane.Praza@Sun.COM 	    SCF_TMPL_STRERROR_HUMAN : 0;
30527887SLiane.Praza@Sun.COM 
30537887SLiane.Praza@Sun.COM 	for (ite = uu_list_first(errs->te_list);
30547887SLiane.Praza@Sun.COM 	    ite != NULL;
30557887SLiane.Praza@Sun.COM 	    ite = uu_list_next(errs->te_list, ite)) {
30567887SLiane.Praza@Sun.COM 		im_tmpl_error_print(out, ite, prefix);
30577887SLiane.Praza@Sun.COM 	}
30587887SLiane.Praza@Sun.COM 
30597887SLiane.Praza@Sun.COM 	/* Now handle the errors that can be printed via libscf. */
30607887SLiane.Praza@Sun.COM 	s = safe_malloc(buf_size);
30617887SLiane.Praza@Sun.COM 	for (scft = uu_list_first(errs->te_scf);
30627887SLiane.Praza@Sun.COM 	    scft != NULL;
30637887SLiane.Praza@Sun.COM 	    scft = uu_list_next(errs->te_scf, scft)) {
30647887SLiane.Praza@Sun.COM 		scferrs = scft->tve_errors;
30657887SLiane.Praza@Sun.COM 		if (_scf_tmpl_error_set_prefix(scferrs, prefix) != 0)
30667887SLiane.Praza@Sun.COM 			uu_die(emesg_nomem);
30677887SLiane.Praza@Sun.COM 		while ((cur = scf_tmpl_next_error(scferrs)) != NULL) {
30687887SLiane.Praza@Sun.COM 			(void) scf_tmpl_strerror(cur, s, buf_size, interactive);
30697887SLiane.Praza@Sun.COM 			(void) fputs(s, out);
30707887SLiane.Praza@Sun.COM 			(void) fputc('\n', out);
30717887SLiane.Praza@Sun.COM 		}
30727887SLiane.Praza@Sun.COM 	}
30737887SLiane.Praza@Sun.COM 
30747887SLiane.Praza@Sun.COM 	free(s);
30757887SLiane.Praza@Sun.COM }
30767887SLiane.Praza@Sun.COM 
30777887SLiane.Praza@Sun.COM /*
30787887SLiane.Praza@Sun.COM  * This function finds the prop_pattern for the property, prop.  e is the
30797887SLiane.Praza@Sun.COM  * instance where the search for the prop_pattern will start.  pg_pattern
30807887SLiane.Praza@Sun.COM  * is the address of the pg_pattern that holds the prop_pattern.
30817887SLiane.Praza@Sun.COM  */
30827887SLiane.Praza@Sun.COM static tmpl_validate_status_t
tmpl_find_prop_pattern(entity_t * inst,pgroup_t * pg_pattern,property_t * prop,pgroup_t ** prop_pattern)30837887SLiane.Praza@Sun.COM tmpl_find_prop_pattern(entity_t *inst, pgroup_t *pg_pattern,
30847887SLiane.Praza@Sun.COM     property_t *prop, pgroup_t **prop_pattern)
30857887SLiane.Praza@Sun.COM {
30867887SLiane.Praza@Sun.COM 	pgroup_t *candidate;
30877887SLiane.Praza@Sun.COM 	pg_iter_t *iter = NULL;
30887887SLiane.Praza@Sun.COM 	char *prop_pattern_name = NULL;
30897887SLiane.Praza@Sun.COM 	tmpl_validate_status_t rc;
30907887SLiane.Praza@Sun.COM 
30917887SLiane.Praza@Sun.COM 	/*
30927887SLiane.Praza@Sun.COM 	 * Get the name of the property group that holds the prop_pattern
30937887SLiane.Praza@Sun.COM 	 * definition.
30947887SLiane.Praza@Sun.COM 	 */
30957887SLiane.Praza@Sun.COM 	rc = gen_prop_pattern_pg_name(pg_pattern,
30967887SLiane.Praza@Sun.COM 	    prop->sc_property_name, &prop_pattern_name);
30977887SLiane.Praza@Sun.COM 	if (rc != TVS_SUCCESS)
30987887SLiane.Praza@Sun.COM 		goto out;
30997887SLiane.Praza@Sun.COM 
31007887SLiane.Praza@Sun.COM 	/* Find the property group. */
31017887SLiane.Praza@Sun.COM 	iter = pg_iter_create(inst, SCF_GROUP_TEMPLATE_PROP_PATTERN);
31027887SLiane.Praza@Sun.COM 	if (iter == NULL)
31037887SLiane.Praza@Sun.COM 		goto out;
31047887SLiane.Praza@Sun.COM 	while ((candidate = next_pattern_pg(iter)) != NULL) {
31057887SLiane.Praza@Sun.COM 		const char *c;
31067887SLiane.Praza@Sun.COM 
31077887SLiane.Praza@Sun.COM 		if (strcmp(prop_pattern_name, candidate->sc_pgroup_name) != 0)
31087887SLiane.Praza@Sun.COM 			continue;
31097887SLiane.Praza@Sun.COM 		c = find_astring_value_in_pg(candidate,
31107887SLiane.Praza@Sun.COM 		    SCF_PROPERTY_TM_PG_PATTERN);
31117887SLiane.Praza@Sun.COM 		if (c == NULL)
31127887SLiane.Praza@Sun.COM 			continue;
31137887SLiane.Praza@Sun.COM 		if (strcmp(pg_pattern->sc_pgroup_name, c) == 0)
31147887SLiane.Praza@Sun.COM 			break;
31157887SLiane.Praza@Sun.COM 	}
31167887SLiane.Praza@Sun.COM 	*prop_pattern = candidate;
31177887SLiane.Praza@Sun.COM 	if (candidate == NULL)
31187887SLiane.Praza@Sun.COM 		rc = TVS_NOMATCH;
31197887SLiane.Praza@Sun.COM 
31207887SLiane.Praza@Sun.COM out:
31217887SLiane.Praza@Sun.COM 	pg_iter_destroy(iter);
31227887SLiane.Praza@Sun.COM 	uu_free((void *)prop_pattern_name);
31237887SLiane.Praza@Sun.COM 	return (rc);
31247887SLiane.Praza@Sun.COM }
31257887SLiane.Praza@Sun.COM 
31267887SLiane.Praza@Sun.COM /*
31277887SLiane.Praza@Sun.COM  * Indexes for pg_pattern property group names.  Indexes are arranged
31287887SLiane.Praza@Sun.COM  * from most specific to least specific.
31297887SLiane.Praza@Sun.COM  */
31307887SLiane.Praza@Sun.COM #define	PGN_BOTH	0	/* both name and type */
31317887SLiane.Praza@Sun.COM #define	PGN_NAME	1	/* name only */
31327887SLiane.Praza@Sun.COM #define	PGN_TYPE	2	/* type only */
31337887SLiane.Praza@Sun.COM #define	PGN_NEITHER	3	/* neither name nor type */
31347887SLiane.Praza@Sun.COM #define	PGN_MAX		4	/* Size of array */
31357887SLiane.Praza@Sun.COM 
31367887SLiane.Praza@Sun.COM /*
31377887SLiane.Praza@Sun.COM  * Given an instance entity, e, and a propety group, pg, within the
31387887SLiane.Praza@Sun.COM  * instance; return the address of the pg_pattern for the property group.
31397887SLiane.Praza@Sun.COM  * The address of the pg_pattern is placed at pgp.  NULL indicates that no
31407887SLiane.Praza@Sun.COM  * pg_pattern was specified.
31417887SLiane.Praza@Sun.COM  */
31427887SLiane.Praza@Sun.COM static tmpl_validate_status_t
tmpl_find_pg_pattern(entity_t * e,pgroup_t * pg,pgroup_t ** pgp)31437887SLiane.Praza@Sun.COM tmpl_find_pg_pattern(entity_t *e, pgroup_t *pg, pgroup_t **pgp)
31447887SLiane.Praza@Sun.COM {
31457887SLiane.Praza@Sun.COM 	pgroup_t *cpg;		/* candidate property group */
31467887SLiane.Praza@Sun.COM 	int i;
31477887SLiane.Praza@Sun.COM 	pg_iter_t *iter = NULL;
31487887SLiane.Praza@Sun.COM 	char *pg_names[PGN_MAX];
31497887SLiane.Praza@Sun.COM 	pgroup_t *pg_patterns[PGN_MAX];
31507887SLiane.Praza@Sun.COM 	tmpl_validate_status_t rv = TVS_SUCCESS;
31517887SLiane.Praza@Sun.COM 
31527887SLiane.Praza@Sun.COM 	(void) memset(pg_patterns, 0, sizeof (pg_patterns));
31537887SLiane.Praza@Sun.COM 	*pgp = NULL;
31547887SLiane.Praza@Sun.COM 
31557887SLiane.Praza@Sun.COM 	/* Generate candidate names for pg_pattern property groups. */
31567887SLiane.Praza@Sun.COM 	pg_names[PGN_BOTH] = gen_pg_pattern_pg_name(pg->sc_pgroup_name,
31577887SLiane.Praza@Sun.COM 	    pg->sc_pgroup_type);
31587887SLiane.Praza@Sun.COM 	pg_names[PGN_NAME] = gen_pg_pattern_pg_name(pg->sc_pgroup_name,
31597887SLiane.Praza@Sun.COM 	    NULL);
31607887SLiane.Praza@Sun.COM 	pg_names[PGN_TYPE] = gen_pg_pattern_pg_name(NULL,
31617887SLiane.Praza@Sun.COM 	    pg->sc_pgroup_type);
31627887SLiane.Praza@Sun.COM 	pg_names[PGN_NEITHER] = gen_pg_pattern_pg_name(NULL, NULL);
31637887SLiane.Praza@Sun.COM 	for (i = 0; i < PGN_MAX; i++) {
31647887SLiane.Praza@Sun.COM 		if (pg_names[i] == NULL) {
31657887SLiane.Praza@Sun.COM 			rv = TVS_BAD_TEMPLATE;
31667887SLiane.Praza@Sun.COM 			goto errout;
31677887SLiane.Praza@Sun.COM 		}
31687887SLiane.Praza@Sun.COM 	}
31697887SLiane.Praza@Sun.COM 
31707887SLiane.Praza@Sun.COM 	/* Search for property groups that match these names */
31717887SLiane.Praza@Sun.COM 	iter = pg_iter_create(e, SCF_GROUP_TEMPLATE_PG_PATTERN);
31727887SLiane.Praza@Sun.COM 	if (iter == NULL) {
31737887SLiane.Praza@Sun.COM 		uu_die(emesg_nomem);
31747887SLiane.Praza@Sun.COM 	}
31757887SLiane.Praza@Sun.COM 	while ((cpg = next_pattern_pg(iter)) != NULL) {
31767887SLiane.Praza@Sun.COM 		if (pg_target_check(cpg, iter->pgi_level) == 0)
31777887SLiane.Praza@Sun.COM 			continue;
31787887SLiane.Praza@Sun.COM 
31797887SLiane.Praza@Sun.COM 		/* See if we have a name match. */
31807887SLiane.Praza@Sun.COM 		for (i = 0; i < PGN_MAX; i++) {
31817887SLiane.Praza@Sun.COM 			if (strcmp(cpg->sc_pgroup_name, pg_names[i]) == 0) {
31827887SLiane.Praza@Sun.COM 				/*
31837887SLiane.Praza@Sun.COM 				 * If we already have a lower level
31847887SLiane.Praza@Sun.COM 				 * pg_pattern, keep it.
31857887SLiane.Praza@Sun.COM 				 */
31867887SLiane.Praza@Sun.COM 				if (pg_patterns[i] == NULL)
31877887SLiane.Praza@Sun.COM 					pg_patterns[i] = cpg;
31887887SLiane.Praza@Sun.COM 				break;
31897887SLiane.Praza@Sun.COM 			}
31907887SLiane.Praza@Sun.COM 		}
31917887SLiane.Praza@Sun.COM 	}
31927887SLiane.Praza@Sun.COM 
31937887SLiane.Praza@Sun.COM 	/* Find the most specific pg_pattern. */
31947887SLiane.Praza@Sun.COM 	for (i = 0; i < PGN_MAX; i++) {
31957887SLiane.Praza@Sun.COM 		if (pg_patterns[i] != NULL) {
31967887SLiane.Praza@Sun.COM 			*pgp = pg_patterns[i];
31977887SLiane.Praza@Sun.COM 			break;
31987887SLiane.Praza@Sun.COM 		}
31997887SLiane.Praza@Sun.COM 	}
32007887SLiane.Praza@Sun.COM errout:
32017887SLiane.Praza@Sun.COM 	for (i = 0; i < PGN_MAX; i++) {
32027887SLiane.Praza@Sun.COM 		free(pg_names[i]);
32037887SLiane.Praza@Sun.COM 	}
32047887SLiane.Praza@Sun.COM 	pg_iter_destroy(iter);
32057887SLiane.Praza@Sun.COM 	return (rv);
32067887SLiane.Praza@Sun.COM }
32077887SLiane.Praza@Sun.COM 
32087887SLiane.Praza@Sun.COM /*
32097887SLiane.Praza@Sun.COM  * Initialize structures that are required for validation using
32107887SLiane.Praza@Sun.COM  * templates specifications.
32117887SLiane.Praza@Sun.COM  */
32127887SLiane.Praza@Sun.COM void
tmpl_init(void)32137887SLiane.Praza@Sun.COM tmpl_init(void)
32147887SLiane.Praza@Sun.COM {
32157887SLiane.Praza@Sun.COM 	emesg_nomem = gettext("Out of memory.\n");
32167887SLiane.Praza@Sun.COM 
32177887SLiane.Praza@Sun.COM 	composed_pg_pool = uu_avl_pool_create("composed_pg",
32187887SLiane.Praza@Sun.COM 	    sizeof (composed_pg_t), offsetof(composed_pg_t, cpg_node),
32197887SLiane.Praza@Sun.COM 	    composed_pg_compare, TMPL_DEBUG_AVL_POOL);
32207887SLiane.Praza@Sun.COM 	if (composed_pg_pool == NULL) {
32217887SLiane.Praza@Sun.COM 		uu_die(gettext("composed_pg pool creation failed: %s\n"),
32227887SLiane.Praza@Sun.COM 		    uu_strerror(uu_error()));
32237887SLiane.Praza@Sun.COM 	}
32247887SLiane.Praza@Sun.COM 	composed_prop_pool = uu_avl_pool_create("composed_prop",
32257887SLiane.Praza@Sun.COM 	    sizeof (property_t), offsetof(property_t, sc_composed_node),
32267887SLiane.Praza@Sun.COM 	    composed_prop_compare, TMPL_DEBUG_AVL_POOL);
32277887SLiane.Praza@Sun.COM 	if (composed_prop_pool == NULL) {
32287887SLiane.Praza@Sun.COM 		uu_die(gettext("composed_prop pool creation failed. %s\n"),
32297887SLiane.Praza@Sun.COM 		    uu_strerror(uu_error()));
32307887SLiane.Praza@Sun.COM 	}
32317887SLiane.Praza@Sun.COM 	ptrn_info_pool = uu_avl_pool_create("ptrn_info", sizeof (ptrn_info_t),
32327887SLiane.Praza@Sun.COM 	    offsetof(ptrn_info_t, pi_link), ptrn_info_compare,
32337887SLiane.Praza@Sun.COM 	    TMPL_DEBUG_AVL_POOL);
32347887SLiane.Praza@Sun.COM 	if (ptrn_info_pool == NULL) {
32357887SLiane.Praza@Sun.COM 		uu_die(gettext("pg_pattern info pool creation failed: %s\n"),
32367887SLiane.Praza@Sun.COM 		    uu_strerror(uu_error()));
32377887SLiane.Praza@Sun.COM 	}
32387887SLiane.Praza@Sun.COM 	inmem_errors_pool = uu_list_pool_create("errors-internal",
32397887SLiane.Praza@Sun.COM 	    sizeof (im_tmpl_error_t), offsetof(im_tmpl_error_t,
32407887SLiane.Praza@Sun.COM 	    ite_node), NULL, TMPL_DEBUG_LIST_POOL);
32417887SLiane.Praza@Sun.COM 	if (inmem_errors_pool == NULL) {
32427887SLiane.Praza@Sun.COM 		uu_die(gettext("inmem_errors_pool pool creation failed: "
32437887SLiane.Praza@Sun.COM 		    "%s\n"), uu_strerror(uu_error()));
32447887SLiane.Praza@Sun.COM 	}
32457887SLiane.Praza@Sun.COM 	tv_errors_pool = uu_list_pool_create("scf-terrors",
32467887SLiane.Praza@Sun.COM 	    sizeof (tv_errors_t), offsetof(tv_errors_t, tve_node),
32477887SLiane.Praza@Sun.COM 	    NULL,  TMPL_DEBUG_LIST_POOL);
32487887SLiane.Praza@Sun.COM 	if (tv_errors_pool == NULL) {
32497887SLiane.Praza@Sun.COM 		uu_die(gettext("tv_errors_pool pool creation failed: %s\n"),
32507887SLiane.Praza@Sun.COM 		    uu_strerror(uu_error()));
32517887SLiane.Praza@Sun.COM 	}
32527887SLiane.Praza@Sun.COM }
32537887SLiane.Praza@Sun.COM 
32547887SLiane.Praza@Sun.COM /*
32557887SLiane.Praza@Sun.COM  * Clean up the composed property node in the property.
32567887SLiane.Praza@Sun.COM  */
32577887SLiane.Praza@Sun.COM void
tmpl_property_fini(property_t * p)32587887SLiane.Praza@Sun.COM tmpl_property_fini(property_t *p)
32597887SLiane.Praza@Sun.COM {
32607887SLiane.Praza@Sun.COM 	uu_avl_node_fini(p, &p->sc_composed_node, composed_prop_pool);
32617887SLiane.Praza@Sun.COM }
32627887SLiane.Praza@Sun.COM 
32637887SLiane.Praza@Sun.COM /*
32647887SLiane.Praza@Sun.COM  * Initialize the composed property node in the property.
32657887SLiane.Praza@Sun.COM  */
32667887SLiane.Praza@Sun.COM void
tmpl_property_init(property_t * p)32677887SLiane.Praza@Sun.COM tmpl_property_init(property_t *p)
32687887SLiane.Praza@Sun.COM {
32697887SLiane.Praza@Sun.COM 	uu_avl_node_init(p, &p->sc_composed_node, composed_prop_pool);
32707887SLiane.Praza@Sun.COM }
32717887SLiane.Praza@Sun.COM 
32727887SLiane.Praza@Sun.COM /*
32737887SLiane.Praza@Sun.COM  * Use the cardinality specification in the prop_pattern to verify the
32747887SLiane.Praza@Sun.COM  * cardinality of the property at prop.  The cardinality of the property is
32757887SLiane.Praza@Sun.COM  * the number of values that it has.
32767887SLiane.Praza@Sun.COM  *
32777887SLiane.Praza@Sun.COM  * pg is the property group that holds prop, and pg_pattern is the
32787887SLiane.Praza@Sun.COM  * pg_pattern for the property group.  pg and pg_pattern are only used for
32797887SLiane.Praza@Sun.COM  * error reporting.
32807887SLiane.Praza@Sun.COM  */
32817887SLiane.Praza@Sun.COM 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)32827887SLiane.Praza@Sun.COM tmpl_validate_cardinality(pgroup_t *prop_pattern, property_t *prop,
32837887SLiane.Praza@Sun.COM     pgroup_t *pg, pgroup_t *pg_pattern, tmpl_errors_t *errs)
32847887SLiane.Praza@Sun.COM {
32857887SLiane.Praza@Sun.COM 	size_t count;
32867887SLiane.Praza@Sun.COM 	uint64_t max;
32877887SLiane.Praza@Sun.COM 	uint64_t min;
32887887SLiane.Praza@Sun.COM 	tmpl_validate_status_t rc;
32897887SLiane.Praza@Sun.COM 	error_info_t einfo;
32907887SLiane.Praza@Sun.COM 
32917887SLiane.Praza@Sun.COM 	assert(strcmp(prop_pattern->sc_pgroup_type,
32927887SLiane.Praza@Sun.COM 	    SCF_GROUP_TEMPLATE_PROP_PATTERN) == 0);
32937887SLiane.Praza@Sun.COM 
32947887SLiane.Praza@Sun.COM 	rc = get_cardinality(prop_pattern, &min, &max);
32957887SLiane.Praza@Sun.COM 	switch (rc) {
32967887SLiane.Praza@Sun.COM 	case TVS_NOMATCH:
32977887SLiane.Praza@Sun.COM 		/* Nothing to check. */
32987887SLiane.Praza@Sun.COM 		return (TVS_SUCCESS);
32997887SLiane.Praza@Sun.COM 	case TVS_SUCCESS:
33007887SLiane.Praza@Sun.COM 		/* Process the limits. */
33017887SLiane.Praza@Sun.COM 		break;
33027887SLiane.Praza@Sun.COM 	default:
33037887SLiane.Praza@Sun.COM 		return (rc);
33047887SLiane.Praza@Sun.COM 	}
33057887SLiane.Praza@Sun.COM 
33067887SLiane.Praza@Sun.COM 	if ((min == 0) && (max == ULLONG_MAX)) {
33077887SLiane.Praza@Sun.COM 		/* Any number of values is permitted.  No need to count. */
33087887SLiane.Praza@Sun.COM 		return (TVS_SUCCESS);
33097887SLiane.Praza@Sun.COM 	}
33107887SLiane.Praza@Sun.COM 
33117887SLiane.Praza@Sun.COM 	count = count_prop_values(prop);
33127887SLiane.Praza@Sun.COM 	if ((count < min) || (count > max)) {
33137887SLiane.Praza@Sun.COM 		CLEAR_ERROR_INFO(&einfo);
33147887SLiane.Praza@Sun.COM 		einfo.ei_type = EIT_CARDINALITY;
33157887SLiane.Praza@Sun.COM 		einfo.ei_u.ei_cardinality.ei_min = min;
33167887SLiane.Praza@Sun.COM 		einfo.ei_u.ei_cardinality.ei_max = max;
33177887SLiane.Praza@Sun.COM 		einfo.ei_u.ei_cardinality.ei_count = count;
33187887SLiane.Praza@Sun.COM 		(void) add_scf_error(errs, SCF_TERR_CARDINALITY_VIOLATION,
33197887SLiane.Praza@Sun.COM 		    pg_pattern, pg, prop_pattern, prop, NULL, &einfo);
33207887SLiane.Praza@Sun.COM 		return (TVS_VALIDATION);
33217887SLiane.Praza@Sun.COM 	}
33227887SLiane.Praza@Sun.COM 
33237887SLiane.Praza@Sun.COM 	return (TVS_SUCCESS);
33247887SLiane.Praza@Sun.COM }
33257887SLiane.Praza@Sun.COM 
33267887SLiane.Praza@Sun.COM /*
33277887SLiane.Praza@Sun.COM  * Iterate over pg_patterns in the entity, e.  If the pg_pattern's required
33287887SLiane.Praza@Sun.COM  * attribute is true, verify that the entity contains the corresponding
33297887SLiane.Praza@Sun.COM  * property group.
33307887SLiane.Praza@Sun.COM  */
33317887SLiane.Praza@Sun.COM static tmpl_validate_status_t
tmpl_required_pg_present(entity_t * e,tmpl_errors_t * errs)33327887SLiane.Praza@Sun.COM tmpl_required_pg_present(entity_t *e, tmpl_errors_t *errs)
33337887SLiane.Praza@Sun.COM {
33347887SLiane.Praza@Sun.COM 	composed_pg_t cpg;
33357887SLiane.Praza@Sun.COM 	composed_pg_t *match;
33367887SLiane.Praza@Sun.COM 	error_info_t einfo;
33377887SLiane.Praza@Sun.COM 	pg_iter_t *iter;
33387887SLiane.Praza@Sun.COM 	pgroup_t *pg;
33397887SLiane.Praza@Sun.COM 	const char *pg_name;
33407887SLiane.Praza@Sun.COM 	const char *pg_type;
33417887SLiane.Praza@Sun.COM 	tmpl_validate_status_t rc = TVS_SUCCESS;
33427887SLiane.Praza@Sun.COM 	uu_avl_t *tree;
33437887SLiane.Praza@Sun.COM 
33447887SLiane.Praza@Sun.COM 	assert(e->sc_etype == SVCCFG_INSTANCE_OBJECT);
33457887SLiane.Praza@Sun.COM 
33467887SLiane.Praza@Sun.COM 	iter = pg_iter_create(e, SCF_GROUP_TEMPLATE_PG_PATTERN);
33477887SLiane.Praza@Sun.COM 	if (iter == NULL)
33487887SLiane.Praza@Sun.COM 		uu_die(emesg_nomem);
33497887SLiane.Praza@Sun.COM 
33507887SLiane.Praza@Sun.COM 	CLEAR_ERROR_INFO(&einfo);
33517887SLiane.Praza@Sun.COM 	einfo.ei_type = EIT_MISSING_PG;
33527887SLiane.Praza@Sun.COM 
33537887SLiane.Praza@Sun.COM 	while ((pg = next_pattern_pg(iter)) != NULL) {
33547887SLiane.Praza@Sun.COM 		if (is_required(pg) == 0) {
33557887SLiane.Praza@Sun.COM 			/* If pg is not required, there is nothing to check. */
33567887SLiane.Praza@Sun.COM 			continue;
33577887SLiane.Praza@Sun.COM 		}
33587887SLiane.Praza@Sun.COM 		pg_name = find_astring_value_in_pg(pg, SCF_PROPERTY_TM_NAME);
33597887SLiane.Praza@Sun.COM 		pg_type = find_astring_value_in_pg(pg, SCF_PROPERTY_TM_TYPE);
33607887SLiane.Praza@Sun.COM 		if (pg_target_check(pg, iter->pgi_level) == 0)
33617887SLiane.Praza@Sun.COM 			continue;
33627887SLiane.Praza@Sun.COM 		einfo.ei_u.ei_missing_pg.ei_pg_name = pg_name;
33637887SLiane.Praza@Sun.COM 		einfo.ei_u.ei_missing_pg.ei_pg_type = pg_type;
33647887SLiane.Praza@Sun.COM 		tree = e->sc_u.sc_instance.sc_composed;
33657887SLiane.Praza@Sun.COM 		(void) memset(&cpg, 0, sizeof (cpg));
33667887SLiane.Praza@Sun.COM 		cpg.cpg_name = pg_name;
33677887SLiane.Praza@Sun.COM 		cpg.cpg_type = pg_type;
33687887SLiane.Praza@Sun.COM 		match = uu_avl_find(tree, &cpg, NULL, NULL);
33697887SLiane.Praza@Sun.COM 		if (match == NULL) {
33707887SLiane.Praza@Sun.COM 			rc = TVS_VALIDATION;
33717887SLiane.Praza@Sun.COM 			if (add_scf_error(errs, SCF_TERR_MISSING_PG, pg,
33727887SLiane.Praza@Sun.COM 			    NULL, NULL, NULL, NULL, &einfo) != 0) {
33737887SLiane.Praza@Sun.COM 				break;
33747887SLiane.Praza@Sun.COM 			}
33757887SLiane.Praza@Sun.COM 		}
33767887SLiane.Praza@Sun.COM 	}
33777887SLiane.Praza@Sun.COM 
33787887SLiane.Praza@Sun.COM 	pg_iter_destroy(iter);
33797887SLiane.Praza@Sun.COM 	return (rc);
33807887SLiane.Praza@Sun.COM }
33817887SLiane.Praza@Sun.COM 
33827887SLiane.Praza@Sun.COM /*
33837887SLiane.Praza@Sun.COM  * Verify that the property group, pg, contains property declarations for
33847887SLiane.Praza@Sun.COM  * all required properties.  Unfortunately, there is no direct way to find
33857887SLiane.Praza@Sun.COM  * the prop_patterns for a given property group.  Therefore, we need to
33867887SLiane.Praza@Sun.COM  * scan the entity at e looking for property groups with a type of
33877887SLiane.Praza@Sun.COM  * SCF_GROUP_TEMPLATE_PROP_PATTERN.  That is, we scan the entity looking
33887887SLiane.Praza@Sun.COM  * for all prop_patterns.  When we find a prop_pattern, we look at the
33897887SLiane.Praza@Sun.COM  * value of its pg_pattern property to see if it matches the name of the
33907887SLiane.Praza@Sun.COM  * pg_pattern.  If they match, this is a prop_pattern that is of interest
33917887SLiane.Praza@Sun.COM  * to us.
33927887SLiane.Praza@Sun.COM  *
33937887SLiane.Praza@Sun.COM  * When we find an interesting prop_pattern, we see if it's required
33947887SLiane.Praza@Sun.COM  * property is true.  If it is, we verify that the property group at pg
33957887SLiane.Praza@Sun.COM  * contains the specified property.
33967887SLiane.Praza@Sun.COM  */
33977887SLiane.Praza@Sun.COM static tmpl_validate_status_t
tmpl_required_props_present(entity_t * e,pgroup_t * pg,pgroup_t * pg_pattern,tmpl_errors_t * errs)33987887SLiane.Praza@Sun.COM tmpl_required_props_present(entity_t *e, pgroup_t *pg, pgroup_t *pg_pattern,
33997887SLiane.Praza@Sun.COM     tmpl_errors_t *errs)
34007887SLiane.Praza@Sun.COM {
34017887SLiane.Praza@Sun.COM 	error_info_t einfo;
34027887SLiane.Praza@Sun.COM 	pg_iter_t *iter;
34037887SLiane.Praza@Sun.COM 	const char *prop_name;
34047887SLiane.Praza@Sun.COM 	const char *prop_pg_pattern_name;
34057887SLiane.Praza@Sun.COM 	pgroup_t *prop_pattern;
34067887SLiane.Praza@Sun.COM 	scf_tmpl_error_type_t ec;
34077887SLiane.Praza@Sun.COM 	tmpl_validate_status_t rc = TVS_SUCCESS;
34087887SLiane.Praza@Sun.COM 
34097887SLiane.Praza@Sun.COM 	/*
34107887SLiane.Praza@Sun.COM 	 * Scan the entity's property groups looking for ones with a type
34117887SLiane.Praza@Sun.COM 	 * of SCF_GROUP_TEMPLATE_PROP_PATTERN.
34127887SLiane.Praza@Sun.COM 	 */
34137887SLiane.Praza@Sun.COM 	iter = pg_iter_create(e, SCF_GROUP_TEMPLATE_PROP_PATTERN);
34147887SLiane.Praza@Sun.COM 	if (iter == NULL)
34157887SLiane.Praza@Sun.COM 		uu_die(emesg_nomem);
34167887SLiane.Praza@Sun.COM 	CLEAR_ERROR_INFO(&einfo);
34177887SLiane.Praza@Sun.COM 	for (prop_pattern = next_pattern_pg(iter);
34187887SLiane.Praza@Sun.COM 	    prop_pattern != NULL;
34197887SLiane.Praza@Sun.COM 	    prop_pattern = next_pattern_pg(iter)) {
34207887SLiane.Praza@Sun.COM 		/*
34217887SLiane.Praza@Sun.COM 		 * Find the pg_pattern property in this prop_pattern.
34227887SLiane.Praza@Sun.COM 		 * Verify that its value matches the name of the
34237887SLiane.Praza@Sun.COM 		 * pg_pattern.
34247887SLiane.Praza@Sun.COM 		 */
34257887SLiane.Praza@Sun.COM 		prop_pg_pattern_name = find_astring_value_in_pg(prop_pattern,
34267887SLiane.Praza@Sun.COM 		    SCF_PROPERTY_TM_PG_PATTERN);
34277887SLiane.Praza@Sun.COM 		assert(prop_pg_pattern_name != NULL);
34287887SLiane.Praza@Sun.COM 		if (strcmp(pg_pattern->sc_pgroup_name,
34297887SLiane.Praza@Sun.COM 		    prop_pg_pattern_name) != 0) {
34307887SLiane.Praza@Sun.COM 			continue;
34317887SLiane.Praza@Sun.COM 		}
34327887SLiane.Praza@Sun.COM 
34337887SLiane.Praza@Sun.COM 		/* If the property is required, see if it is in the pg. */
34347887SLiane.Praza@Sun.COM 		if (is_required(prop_pattern) == 0)
34357887SLiane.Praza@Sun.COM 			continue;
34367887SLiane.Praza@Sun.COM 		prop_name = find_astring_value_in_pg(prop_pattern,
34377887SLiane.Praza@Sun.COM 		    SCF_PROPERTY_TM_NAME);
34387887SLiane.Praza@Sun.COM 		assert(prop_name != NULL);
34397887SLiane.Praza@Sun.COM 		if (property_find(pg, prop_name) == NULL) {
34407887SLiane.Praza@Sun.COM 			ec = SCF_TERR_MISSING_PROP;
34417887SLiane.Praza@Sun.COM 			rc = TVS_VALIDATION;
34427887SLiane.Praza@Sun.COM 			einfo.ei_type = EIT_MISSING_PROP;
34437887SLiane.Praza@Sun.COM 			einfo.ei_u.ei_missing_prop.ei_prop_name = prop_name;
34447887SLiane.Praza@Sun.COM 			if (add_scf_error(errs, ec, pg_pattern, pg,
34457887SLiane.Praza@Sun.COM 			    prop_pattern, NULL, NULL, &einfo) != 0) {
34467887SLiane.Praza@Sun.COM 				/*
34477887SLiane.Praza@Sun.COM 				 * If we can no longer accumulate errors,
34487887SLiane.Praza@Sun.COM 				 * break out of the loop.
34497887SLiane.Praza@Sun.COM 				 */
34507887SLiane.Praza@Sun.COM 				break;
34517887SLiane.Praza@Sun.COM 			}
34527887SLiane.Praza@Sun.COM 		}
34537887SLiane.Praza@Sun.COM 	}
34547887SLiane.Praza@Sun.COM 
34557887SLiane.Praza@Sun.COM 	pg_iter_destroy(iter);
34567887SLiane.Praza@Sun.COM 	return (rc);
34577887SLiane.Praza@Sun.COM }
34587887SLiane.Praza@Sun.COM 
34597887SLiane.Praza@Sun.COM /*
34607887SLiane.Praza@Sun.COM  * Check the value at v to see if it falls within any of the ranges at r.
34617887SLiane.Praza@Sun.COM  * count is the number of ranges at r, and type tells whether to treat the
34627887SLiane.Praza@Sun.COM  * value as signed or unsigned.
34637887SLiane.Praza@Sun.COM  *
34647887SLiane.Praza@Sun.COM  * Return 1 if the value falls within one of the ranges.  Otherwise return
34657887SLiane.Praza@Sun.COM  * 0.
34667887SLiane.Praza@Sun.COM  */
34677887SLiane.Praza@Sun.COM static int
value_in_range(value_t * v,scf_type_t type,range_t * r,size_t count)34687887SLiane.Praza@Sun.COM value_in_range(value_t *v, scf_type_t type, range_t *r, size_t count)
34697887SLiane.Praza@Sun.COM {
34707887SLiane.Praza@Sun.COM 	for (; count > 0; --count, r++) {
34717887SLiane.Praza@Sun.COM 		if (type == SCF_TYPE_COUNT) {
34727887SLiane.Praza@Sun.COM 			if ((v->sc_u.sc_count >=
34737887SLiane.Praza@Sun.COM 			    r->rng_u.rng_unsigned.rng_min) &&
34747887SLiane.Praza@Sun.COM 			    (v->sc_u.sc_count <=
34757887SLiane.Praza@Sun.COM 			    r->rng_u.rng_unsigned.rng_max))
34767887SLiane.Praza@Sun.COM 				return (1);
34777887SLiane.Praza@Sun.COM 		} else {
34787887SLiane.Praza@Sun.COM 			if ((v->sc_u.sc_integer >=
34797887SLiane.Praza@Sun.COM 			    r->rng_u.rng_signed.rng_min) &&
34807887SLiane.Praza@Sun.COM 			    (v->sc_u.sc_integer <=
34817887SLiane.Praza@Sun.COM 			    r->rng_u.rng_signed.rng_max))
34827887SLiane.Praza@Sun.COM 				return (1);
34837887SLiane.Praza@Sun.COM 		}
34847887SLiane.Praza@Sun.COM 	}
34857887SLiane.Praza@Sun.COM 	return (0);
34867887SLiane.Praza@Sun.COM }
34877887SLiane.Praza@Sun.COM 
34887887SLiane.Praza@Sun.COM /*
34897887SLiane.Praza@Sun.COM  * If the template prop_pattern at pattern contains a constraint_range
34907887SLiane.Praza@Sun.COM  * property, use the specified range to validate all the numeric property
34917887SLiane.Praza@Sun.COM  * values of the property at prop.
34927887SLiane.Praza@Sun.COM  *
34937887SLiane.Praza@Sun.COM  * pg is the property group that holds prop, and pg_pattern is the
34947887SLiane.Praza@Sun.COM  * pg_pattern for the property group.  pg and pg_pattern are only used for
34957887SLiane.Praza@Sun.COM  * error reporting.
34967887SLiane.Praza@Sun.COM  */
34977887SLiane.Praza@Sun.COM 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)34987887SLiane.Praza@Sun.COM tmpl_validate_value_range(pgroup_t *pattern, property_t *prop, pgroup_t *pg,
34997887SLiane.Praza@Sun.COM     pgroup_t *pg_pattern, tmpl_errors_t *errs)
35007887SLiane.Praza@Sun.COM {
35017887SLiane.Praza@Sun.COM 	uint_t count;
35027887SLiane.Praza@Sun.COM 	error_info_t einfo;
35037887SLiane.Praza@Sun.COM 	property_t *range_prop;
35047887SLiane.Praza@Sun.COM 	range_t *ranges;
35057887SLiane.Praza@Sun.COM 	tmpl_validate_status_t rc;
35067887SLiane.Praza@Sun.COM 	scf_type_t type;
35077887SLiane.Praza@Sun.COM 	value_t *v;
35087887SLiane.Praza@Sun.COM 
35097887SLiane.Praza@Sun.COM 	/* Get the range constraints if they exist. */
35107887SLiane.Praza@Sun.COM 	if ((range_prop = property_find(pattern,
35117887SLiane.Praza@Sun.COM 	    SCF_PROPERTY_TM_CONSTRAINT_RANGE)) == NULL) {
35127887SLiane.Praza@Sun.COM 		/* No range to check. */
35137887SLiane.Praza@Sun.COM 		return (TVS_SUCCESS);
35147887SLiane.Praza@Sun.COM 	}
35157887SLiane.Praza@Sun.COM 	type = prop->sc_value_type;
35167887SLiane.Praza@Sun.COM 	if ((type != SCF_TYPE_COUNT) && (type != SCF_TYPE_INTEGER)) {
35177887SLiane.Praza@Sun.COM 		rc = TVS_BAD_TEMPLATE;
35187887SLiane.Praza@Sun.COM 		CLEAR_ERROR_INFO(&einfo);
35197887SLiane.Praza@Sun.COM 		einfo.ei_type = EIT_BAD_TEMPLATE;
35207887SLiane.Praza@Sun.COM 		einfo.ei_u.ei_bad_template.ei_reason =
35217887SLiane.Praza@Sun.COM 		    gettext("Property does not have correct type for "
35227887SLiane.Praza@Sun.COM 		    "a range specification");
35237887SLiane.Praza@Sun.COM 		(void) tmpl_errors_add_im(errs, rc, pg_pattern->sc_parent,
35247887SLiane.Praza@Sun.COM 		    pg_pattern, pg, pattern, prop, NULL, &einfo);
35257887SLiane.Praza@Sun.COM 		return (rc);
35267887SLiane.Praza@Sun.COM 	}
35277887SLiane.Praza@Sun.COM 	if ((rc = get_ranges(range_prop, prop->sc_value_type, &ranges,
35287887SLiane.Praza@Sun.COM 	    &count)) != TVS_SUCCESS) {
35297887SLiane.Praza@Sun.COM 		rc = TVS_BAD_TEMPLATE;
35307887SLiane.Praza@Sun.COM 		CLEAR_ERROR_INFO(&einfo);
35317887SLiane.Praza@Sun.COM 		einfo.ei_type = EIT_BAD_TEMPLATE;
35327887SLiane.Praza@Sun.COM 		einfo.ei_u.ei_bad_template.ei_reason = gettext("Illegal range "
35337887SLiane.Praza@Sun.COM 		    "value");
35347887SLiane.Praza@Sun.COM 		(void) tmpl_errors_add_im(errs, rc, pg_pattern->sc_parent,
35357887SLiane.Praza@Sun.COM 		    pg_pattern, pg, pattern, prop, NULL, &einfo);
35367887SLiane.Praza@Sun.COM 		return (rc);
35377887SLiane.Praza@Sun.COM 	}
35387887SLiane.Praza@Sun.COM 
35397887SLiane.Praza@Sun.COM 	/* Set up error info before entering loop. */
35407887SLiane.Praza@Sun.COM 	CLEAR_ERROR_INFO(&einfo);
35417887SLiane.Praza@Sun.COM 	einfo.ei_type = EIT_RANGE;
35427887SLiane.Praza@Sun.COM 	einfo.ei_u.ei_range.ei_rtype = type;
35437887SLiane.Praza@Sun.COM 
35447887SLiane.Praza@Sun.COM 	/* Compare numeric values of the property to the range. */
35457887SLiane.Praza@Sun.COM 	for (v = uu_list_first(prop->sc_property_values);
35467887SLiane.Praza@Sun.COM 	    v != NULL;
35477887SLiane.Praza@Sun.COM 	    v = uu_list_next(prop->sc_property_values, v)) {
35487887SLiane.Praza@Sun.COM 		if (value_in_range(v, type, ranges, count) == 1)
35497887SLiane.Praza@Sun.COM 			continue;
35507887SLiane.Praza@Sun.COM 		if (type == SCF_TYPE_COUNT) {
35517887SLiane.Praza@Sun.COM 			einfo.ei_u.ei_range.ei_uvalue = v->sc_u.sc_count;
35527887SLiane.Praza@Sun.COM 		} else {
35537887SLiane.Praza@Sun.COM 			einfo.ei_u.ei_range.ei_ivalue = v->sc_u.sc_integer;
35547887SLiane.Praza@Sun.COM 		}
35557887SLiane.Praza@Sun.COM 		rc = TVS_VALIDATION;
35567887SLiane.Praza@Sun.COM 		if (add_scf_error(errs, SCF_TERR_RANGE_VIOLATION, pg_pattern,
35577887SLiane.Praza@Sun.COM 		    pg, pattern, prop, v, &einfo) != 0) {
35587887SLiane.Praza@Sun.COM 			return (rc);
35597887SLiane.Praza@Sun.COM 		}
35607887SLiane.Praza@Sun.COM 	}
35617887SLiane.Praza@Sun.COM 
35627887SLiane.Praza@Sun.COM 	return (rc);
35637887SLiane.Praza@Sun.COM }
35647887SLiane.Praza@Sun.COM 
35657887SLiane.Praza@Sun.COM /*
35667887SLiane.Praza@Sun.COM  * If the prop_pattern has value constraints, verify that all the values
35677887SLiane.Praza@Sun.COM  * for the property at prop are legal values.
35687887SLiane.Praza@Sun.COM  *
35697887SLiane.Praza@Sun.COM  * pg is the property group that holds prop, and pg_pattern is the
35707887SLiane.Praza@Sun.COM  * pg_pattern for the property group.  pg and pg_pattern are only used for
35717887SLiane.Praza@Sun.COM  * error reporting.
35727887SLiane.Praza@Sun.COM  */
35737887SLiane.Praza@Sun.COM 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)35747887SLiane.Praza@Sun.COM tmpl_validate_values(pgroup_t *prop_pattern, property_t *prop, pgroup_t *pg,
35757887SLiane.Praza@Sun.COM     pgroup_t *pg_pattern, tmpl_errors_t *errs)
35767887SLiane.Praza@Sun.COM {
35777887SLiane.Praza@Sun.COM 	int found;
35787887SLiane.Praza@Sun.COM 	uint_t i;
35797887SLiane.Praza@Sun.COM 	avalues_t *legal;
35807887SLiane.Praza@Sun.COM 	tmpl_validate_status_t r;
35817887SLiane.Praza@Sun.COM 	tmpl_validate_status_t rc = TVS_SUCCESS;
35827887SLiane.Praza@Sun.COM 	value_t *v;
35837887SLiane.Praza@Sun.COM 
35847887SLiane.Praza@Sun.COM 	/* Get list of legal values. */
35857887SLiane.Praza@Sun.COM 	r = av_get_values(prop_pattern, SCF_PROPERTY_TM_CONSTRAINT_NAME,
35867887SLiane.Praza@Sun.COM 	    prop->sc_value_type, &legal);
35877887SLiane.Praza@Sun.COM 	switch (r) {
35887887SLiane.Praza@Sun.COM 	case TVS_BAD_CONVERSION:
35897887SLiane.Praza@Sun.COM 		(void) tmpl_errors_add_im(errs, r, pg->sc_parent, pg_pattern,
35907887SLiane.Praza@Sun.COM 		    pg, prop_pattern, prop, NULL, NULL);
35917887SLiane.Praza@Sun.COM 		return (r);
35927887SLiane.Praza@Sun.COM 	case TVS_NOMATCH:
35937887SLiane.Praza@Sun.COM 		/* No constraints in template. */
35947887SLiane.Praza@Sun.COM 		return (TVS_SUCCESS);
35957887SLiane.Praza@Sun.COM 	case TVS_SUCCESS:
35967887SLiane.Praza@Sun.COM 		/* process the constraints. */
35977887SLiane.Praza@Sun.COM 		break;
35987887SLiane.Praza@Sun.COM 	default:
35997887SLiane.Praza@Sun.COM 		assert(0);
36007887SLiane.Praza@Sun.COM 		abort();
36017887SLiane.Praza@Sun.COM 	}
36027887SLiane.Praza@Sun.COM 
36037887SLiane.Praza@Sun.COM 	/* Check the property values against the legal values. */
36047887SLiane.Praza@Sun.COM 	for (v = uu_list_first(prop->sc_property_values);
36057887SLiane.Praza@Sun.COM 	    v != NULL;
36067887SLiane.Praza@Sun.COM 	    v = uu_list_next(prop->sc_property_values, v)) {
36077887SLiane.Praza@Sun.COM 		/* Check this property value against the legal values. */
36087887SLiane.Praza@Sun.COM 		found = 0;
36097887SLiane.Praza@Sun.COM 		for (i = 0; (i < legal->av_count) && (found == 0); i++) {
36107887SLiane.Praza@Sun.COM 			switch (v->sc_type) {
36117887SLiane.Praza@Sun.COM 			case SCF_TYPE_BOOLEAN:
36127887SLiane.Praza@Sun.COM 			case SCF_TYPE_COUNT:
36137887SLiane.Praza@Sun.COM 				if (av_get_unsigned(legal, i) ==
36147887SLiane.Praza@Sun.COM 				    v->sc_u.sc_count) {
36157887SLiane.Praza@Sun.COM 					found = 1;
36167887SLiane.Praza@Sun.COM 				}
36177887SLiane.Praza@Sun.COM 				break;
36187887SLiane.Praza@Sun.COM 			case SCF_TYPE_INTEGER:
36197887SLiane.Praza@Sun.COM 				if (av_get_integer(legal, i) ==
36207887SLiane.Praza@Sun.COM 				    v->sc_u.sc_integer) {
36217887SLiane.Praza@Sun.COM 					found = 1;
36227887SLiane.Praza@Sun.COM 				}
36237887SLiane.Praza@Sun.COM 				break;
36247887SLiane.Praza@Sun.COM 			default:
36257887SLiane.Praza@Sun.COM 				if (strcmp(av_get_string(legal, i),
36267887SLiane.Praza@Sun.COM 				    v->sc_u.sc_string) == 0) {
36277887SLiane.Praza@Sun.COM 					found = 1;
36287887SLiane.Praza@Sun.COM 				}
36297887SLiane.Praza@Sun.COM 				break;
36307887SLiane.Praza@Sun.COM 			}
36317887SLiane.Praza@Sun.COM 		}
36327887SLiane.Praza@Sun.COM 		if (found == 0) {
36337887SLiane.Praza@Sun.COM 			rc = TVS_VALIDATION;
36347887SLiane.Praza@Sun.COM 			if (add_scf_error(errs,
36357887SLiane.Praza@Sun.COM 			    SCF_TERR_VALUE_CONSTRAINT_VIOLATED, pg_pattern, pg,
36367887SLiane.Praza@Sun.COM 			    prop_pattern, prop, v, NULL) != 0) {
36377887SLiane.Praza@Sun.COM 				/*
36387887SLiane.Praza@Sun.COM 				 * Exit loop if no longer able to report
36397887SLiane.Praza@Sun.COM 				 * errors.
36407887SLiane.Praza@Sun.COM 				 */
36417887SLiane.Praza@Sun.COM 				break;
36427887SLiane.Praza@Sun.COM 			}
36437887SLiane.Praza@Sun.COM 		}
36447887SLiane.Praza@Sun.COM 	}
36457887SLiane.Praza@Sun.COM 
36467887SLiane.Praza@Sun.COM out:
36477887SLiane.Praza@Sun.COM 	av_destroy(legal);
36487887SLiane.Praza@Sun.COM 	return (rc);
36497887SLiane.Praza@Sun.COM }
36507887SLiane.Praza@Sun.COM 
36517887SLiane.Praza@Sun.COM /*
36527887SLiane.Praza@Sun.COM  * Verify the following items about the values of property, prop.
36537887SLiane.Praza@Sun.COM  *
36547887SLiane.Praza@Sun.COM  *	- The values all have the type specified by the prop_pattern at
36557887SLiane.Praza@Sun.COM  *	  pattern.
36567887SLiane.Praza@Sun.COM  *	- Check numeric values against range constraints.
36577887SLiane.Praza@Sun.COM  *	- If the prop_pattern has one or more value constraints, validate
36587887SLiane.Praza@Sun.COM  *	  the property's values against the constraints.
36597887SLiane.Praza@Sun.COM  *
36607887SLiane.Praza@Sun.COM  * pg is the property group that holds prop, and pg_pattern is the
36617887SLiane.Praza@Sun.COM  * pg_pattern for the property group.  pg and pg_pattern are only used for
36627887SLiane.Praza@Sun.COM  * error reporting.
36637887SLiane.Praza@Sun.COM  */
36647887SLiane.Praza@Sun.COM 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)36657887SLiane.Praza@Sun.COM tmpl_validate_value_constraints(pgroup_t *pattern, property_t *prop,
36667887SLiane.Praza@Sun.COM     pgroup_t *pg, pgroup_t *pg_pattern, tmpl_errors_t *errs)
36677887SLiane.Praza@Sun.COM {
36687887SLiane.Praza@Sun.COM 	tmpl_validate_status_t r;
36697887SLiane.Praza@Sun.COM 	tmpl_validate_status_t rc;
36707887SLiane.Praza@Sun.COM 
36717887SLiane.Praza@Sun.COM 	rc = tmpl_validate_value_range(pattern, prop, pg, pg_pattern, errs);
36727887SLiane.Praza@Sun.COM 	r = tmpl_validate_values(pattern, prop, pg, pg_pattern, errs);
36737887SLiane.Praza@Sun.COM 	if (r != TVS_SUCCESS)
36747887SLiane.Praza@Sun.COM 		rc = r;
36757887SLiane.Praza@Sun.COM 
36767887SLiane.Praza@Sun.COM 	return (rc);
36777887SLiane.Praza@Sun.COM }
36787887SLiane.Praza@Sun.COM 
36797887SLiane.Praza@Sun.COM /*
36807887SLiane.Praza@Sun.COM  * Perform the following validations on the property, prop.
36817887SLiane.Praza@Sun.COM  *
36827887SLiane.Praza@Sun.COM  *	- Verify that the property's type agrees with the type specified in
36837887SLiane.Praza@Sun.COM  *	  the prop_pattern template, tmpl.
36847887SLiane.Praza@Sun.COM  *	- Verify the cardinality.
36857887SLiane.Praza@Sun.COM  *	- Verify that the property values satisfy the constraints specified
36867887SLiane.Praza@Sun.COM  *	  by the template.
36877887SLiane.Praza@Sun.COM  *
36887887SLiane.Praza@Sun.COM  * pg is the property group that holds prop, and pg_pattern is the
36897887SLiane.Praza@Sun.COM  * pg_pattern for the property group.  pg and pg_pattern are only used for
36907887SLiane.Praza@Sun.COM  * error reporting.
36917887SLiane.Praza@Sun.COM  */
36927887SLiane.Praza@Sun.COM 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)36937887SLiane.Praza@Sun.COM tmpl_validate_prop(property_t *prop, pgroup_t *tmpl, pgroup_t *pg,
36947887SLiane.Praza@Sun.COM     pgroup_t *pg_pattern, tmpl_errors_t *errs)
36957887SLiane.Praza@Sun.COM {
36967887SLiane.Praza@Sun.COM 	scf_tmpl_error_type_t ec;
36977887SLiane.Praza@Sun.COM 	error_info_t einfo;
36987887SLiane.Praza@Sun.COM 	tmpl_validate_status_t r;
36997887SLiane.Praza@Sun.COM 	tmpl_validate_status_t rc = TVS_SUCCESS;
37007887SLiane.Praza@Sun.COM 	int status;
37017887SLiane.Praza@Sun.COM 	scf_type_t type;
37027887SLiane.Praza@Sun.COM 
37037887SLiane.Praza@Sun.COM 	r = prop_pattern_type(tmpl, &type);
37047887SLiane.Praza@Sun.COM 	switch (r) {
37057887SLiane.Praza@Sun.COM 	case TVS_SUCCESS:
37067887SLiane.Praza@Sun.COM 		if (type == SCF_TYPE_INVALID) {
37077887SLiane.Praza@Sun.COM 			rc = TVS_INVALID_TYPE_SPECIFICATION;
37087887SLiane.Praza@Sun.COM 			r = tmpl_errors_add_im(errs, rc, pg->sc_parent, NULL,
37097887SLiane.Praza@Sun.COM 			    pg, tmpl, NULL, NULL, NULL);
37107887SLiane.Praza@Sun.COM 			if (r != TVS_SUCCESS) {
37117887SLiane.Praza@Sun.COM 				/*
37127887SLiane.Praza@Sun.COM 				 * Give up if we can no longer accumulate
37137887SLiane.Praza@Sun.COM 				 * errors.
37147887SLiane.Praza@Sun.COM 				 */
37157887SLiane.Praza@Sun.COM 				return (rc);
37167887SLiane.Praza@Sun.COM 			}
37177887SLiane.Praza@Sun.COM 		} else {
37187887SLiane.Praza@Sun.COM 			if (property_is_type(prop, type) == 0) {
37197887SLiane.Praza@Sun.COM 				CLEAR_ERROR_INFO(&einfo);
37207887SLiane.Praza@Sun.COM 				rc = TVS_VALIDATION;
37217887SLiane.Praza@Sun.COM 				ec = SCF_TERR_WRONG_PROP_TYPE;
37227887SLiane.Praza@Sun.COM 				einfo.ei_type  = EIT_PROP_TYPE;
37237887SLiane.Praza@Sun.COM 				einfo.ei_u.ei_prop_type.ei_specified = type;
37247887SLiane.Praza@Sun.COM 				einfo.ei_u.ei_prop_type.ei_actual =
37257887SLiane.Praza@Sun.COM 				    prop->sc_value_type;
37267887SLiane.Praza@Sun.COM 				status = add_scf_error(errs, ec,
37277887SLiane.Praza@Sun.COM 				    pg_pattern, pg, tmpl, prop, NULL, &einfo);
37287887SLiane.Praza@Sun.COM 				if (status != 0) {
37297887SLiane.Praza@Sun.COM 					/*
37307887SLiane.Praza@Sun.COM 					 * Give up if we can no longer
37317887SLiane.Praza@Sun.COM 					 * accumulate errors.
37327887SLiane.Praza@Sun.COM 					 */
37337887SLiane.Praza@Sun.COM 					return (rc);
37347887SLiane.Praza@Sun.COM 				}
37357887SLiane.Praza@Sun.COM 			}
37367887SLiane.Praza@Sun.COM 		}
37377887SLiane.Praza@Sun.COM 		break;
37387887SLiane.Praza@Sun.COM 	case TVS_MISSING_TYPE_SPECIFICATION:
37397887SLiane.Praza@Sun.COM 		/*
37407887SLiane.Praza@Sun.COM 		 * A null type specification means that we do not need to
37417887SLiane.Praza@Sun.COM 		 * check the property's type.
37427887SLiane.Praza@Sun.COM 		 */
37437887SLiane.Praza@Sun.COM 		break;
37447887SLiane.Praza@Sun.COM 	default:
37457887SLiane.Praza@Sun.COM 		rc = r;
37467887SLiane.Praza@Sun.COM 	}
37477887SLiane.Praza@Sun.COM 
37487887SLiane.Praza@Sun.COM 	/* Validate the cardinality */
37497887SLiane.Praza@Sun.COM 	r = tmpl_validate_cardinality(tmpl, prop, pg, pg_pattern, errs);
37507887SLiane.Praza@Sun.COM 	if (r != TVS_SUCCESS)
37517887SLiane.Praza@Sun.COM 		rc = r;
37527887SLiane.Praza@Sun.COM 
37537887SLiane.Praza@Sun.COM 	/* Validate that property values satisfy constraints. */
37547887SLiane.Praza@Sun.COM 	r = tmpl_validate_value_constraints(tmpl, prop, pg, pg_pattern, errs);
37557887SLiane.Praza@Sun.COM 	if (r != TVS_SUCCESS)
37567887SLiane.Praza@Sun.COM 		rc = r;
37577887SLiane.Praza@Sun.COM 
37587887SLiane.Praza@Sun.COM 	return (rc);
37597887SLiane.Praza@Sun.COM }
37607887SLiane.Praza@Sun.COM 
37617887SLiane.Praza@Sun.COM /*
37627887SLiane.Praza@Sun.COM  * Validate the property group at pg by performing the following checks:
37637887SLiane.Praza@Sun.COM  *
37647887SLiane.Praza@Sun.COM  *	- Verify that the types of the pg and the pg_pattern are
37657887SLiane.Praza@Sun.COM  *	  compatible.
37667887SLiane.Praza@Sun.COM  *	- Verify the properties in the pg.
37677887SLiane.Praza@Sun.COM  *	- Verify that required properties are present.
37687887SLiane.Praza@Sun.COM  */
37697887SLiane.Praza@Sun.COM static tmpl_validate_status_t
tmpl_validate_pg(entity_t * e,pgroup_t * pg,tmpl_errors_t * errs)37707887SLiane.Praza@Sun.COM tmpl_validate_pg(entity_t *e, pgroup_t *pg, tmpl_errors_t *errs)
37717887SLiane.Praza@Sun.COM {
37727887SLiane.Praza@Sun.COM 	error_info_t einfo;
37737887SLiane.Praza@Sun.COM 	const char *pg_pattern_type;	/* Type declared by pg_pattern. */
37747887SLiane.Praza@Sun.COM 	pgroup_t *pg_pattern;	/* Prop. group for pg_pattern */
37757887SLiane.Praza@Sun.COM 	property_t *prop;
37767887SLiane.Praza@Sun.COM 	pgroup_t *prop_pattern;
37777887SLiane.Praza@Sun.COM 	tmpl_validate_status_t r;
37787887SLiane.Praza@Sun.COM 	tmpl_validate_status_t rc = TVS_SUCCESS;
37797887SLiane.Praza@Sun.COM 	int stat;
37807887SLiane.Praza@Sun.COM 
37817887SLiane.Praza@Sun.COM 	/*
37827887SLiane.Praza@Sun.COM 	 * See if there is a pg_pattern for this property group.  If it
37837887SLiane.Praza@Sun.COM 	 * exists, use it to validate the property group.  If there is no
37847887SLiane.Praza@Sun.COM 	 * pg_pattern, then there is no validation to do.
37857887SLiane.Praza@Sun.COM 	 */
37867887SLiane.Praza@Sun.COM 	rc = tmpl_find_pg_pattern(e, pg, &pg_pattern);
37877887SLiane.Praza@Sun.COM 	switch (rc) {
37887887SLiane.Praza@Sun.COM 	case TVS_SUCCESS:
37897887SLiane.Praza@Sun.COM 		break;
37907887SLiane.Praza@Sun.COM 	case TVS_BAD_TEMPLATE:
37917887SLiane.Praza@Sun.COM 		CLEAR_ERROR_INFO(&einfo);
37927887SLiane.Praza@Sun.COM 		einfo.ei_type = EIT_BAD_TEMPLATE;
37937887SLiane.Praza@Sun.COM 		einfo.ei_u.ei_bad_template.ei_reason = gettext("Property "
37947887SLiane.Praza@Sun.COM 		    "group name too long");
37957887SLiane.Praza@Sun.COM 		(void) tmpl_errors_add_im(errs, rc, e, NULL, pg, NULL, NULL,
37967887SLiane.Praza@Sun.COM 		    NULL, &einfo);
37977887SLiane.Praza@Sun.COM 		return (rc);
37987887SLiane.Praza@Sun.COM 	default:
37997887SLiane.Praza@Sun.COM 		assert(0);
38007887SLiane.Praza@Sun.COM 		abort();
38017887SLiane.Praza@Sun.COM 	}
38027887SLiane.Praza@Sun.COM 	if (pg_pattern == NULL)
38037887SLiane.Praza@Sun.COM 		return (TVS_SUCCESS);
38047887SLiane.Praza@Sun.COM 
38057887SLiane.Praza@Sun.COM 	/*
38067887SLiane.Praza@Sun.COM 	 * If the pg_pattern declares a type, verify that the PG has the
38077887SLiane.Praza@Sun.COM 	 * correct type.
38087887SLiane.Praza@Sun.COM 	 */
38097887SLiane.Praza@Sun.COM 	pg_pattern_type = find_type_specification(pg_pattern);
38107887SLiane.Praza@Sun.COM 	if ((pg_pattern_type != NULL) &&
38117887SLiane.Praza@Sun.COM 	    (*pg_pattern_type != 0)) {
38127887SLiane.Praza@Sun.COM 		if ((pg->sc_pgroup_type != NULL) &&
38137887SLiane.Praza@Sun.COM 		    (*(pg->sc_pgroup_type) != 0)) {
38147887SLiane.Praza@Sun.COM 			if (strcmp(pg_pattern_type,
38157887SLiane.Praza@Sun.COM 			    pg->sc_pgroup_type) != 0) {
38167887SLiane.Praza@Sun.COM 				rc = TVS_VALIDATION;
38177887SLiane.Praza@Sun.COM 				stat = add_scf_error(errs,
38187887SLiane.Praza@Sun.COM 				    SCF_TERR_WRONG_PG_TYPE, pg_pattern, pg,
38197887SLiane.Praza@Sun.COM 				    NULL, NULL, NULL, NULL);
38207887SLiane.Praza@Sun.COM 				if (stat != 0) {
38217887SLiane.Praza@Sun.COM 					/*
38227887SLiane.Praza@Sun.COM 					 * If we can no longer accumulate
38237887SLiane.Praza@Sun.COM 					 * errors, return without trying to
38247887SLiane.Praza@Sun.COM 					 * do further validation.
38257887SLiane.Praza@Sun.COM 					 */
38267887SLiane.Praza@Sun.COM 					return (rc);
38277887SLiane.Praza@Sun.COM 				}
38287887SLiane.Praza@Sun.COM 			}
38297887SLiane.Praza@Sun.COM 		} else {
38307887SLiane.Praza@Sun.COM 			rc = TVS_MISSING_PG_TYPE;
38317887SLiane.Praza@Sun.COM 			r = tmpl_errors_add_im(errs, rc, e, pg_pattern, pg,
38327887SLiane.Praza@Sun.COM 			    NULL, NULL, NULL, NULL);
38337887SLiane.Praza@Sun.COM 			if (r != TVS_SUCCESS) {
38347887SLiane.Praza@Sun.COM 				/*
38357887SLiane.Praza@Sun.COM 				 * If we can no longer accumulate errors,
38367887SLiane.Praza@Sun.COM 				 * return without trying to do further
38377887SLiane.Praza@Sun.COM 				 * validation.
38387887SLiane.Praza@Sun.COM 				 */
38397887SLiane.Praza@Sun.COM 				return (rc);
38407887SLiane.Praza@Sun.COM 			}
38417887SLiane.Praza@Sun.COM 		}
38427887SLiane.Praza@Sun.COM 	}
38437887SLiane.Praza@Sun.COM 
38447887SLiane.Praza@Sun.COM 	/* Verify the properties in the property group. */
38457887SLiane.Praza@Sun.COM 	prop = NULL;
38467887SLiane.Praza@Sun.COM 	while ((prop = next_property(pg, prop)) != NULL) {
38477887SLiane.Praza@Sun.COM 		r = tmpl_find_prop_pattern(e, pg_pattern, prop, &prop_pattern);
38487887SLiane.Praza@Sun.COM 		switch (r) {
38497887SLiane.Praza@Sun.COM 		case TVS_SUCCESS:
38507887SLiane.Praza@Sun.COM 			/* Found match.  Validate property. */
38517887SLiane.Praza@Sun.COM 			break;
38527887SLiane.Praza@Sun.COM 		case TVS_NOMATCH:
38537887SLiane.Praza@Sun.COM 			/* No prop_patern.  Go on to next property. */
38547887SLiane.Praza@Sun.COM 			continue;
38557887SLiane.Praza@Sun.COM 		case TVS_BAD_TEMPLATE:
38567887SLiane.Praza@Sun.COM 			CLEAR_ERROR_INFO(&einfo);
38577887SLiane.Praza@Sun.COM 			einfo.ei_type = EIT_BAD_TEMPLATE;
38587887SLiane.Praza@Sun.COM 			einfo.ei_u.ei_bad_template.ei_reason =
38597887SLiane.Praza@Sun.COM 			    gettext("prop_pattern name too long");
38607887SLiane.Praza@Sun.COM 			(void) tmpl_errors_add_im(errs, r, e, NULL, pg, NULL,
38617887SLiane.Praza@Sun.COM 			    NULL, NULL, &einfo);
38627887SLiane.Praza@Sun.COM 			continue;
38637887SLiane.Praza@Sun.COM 		default:
38647887SLiane.Praza@Sun.COM 			assert(0);
38657887SLiane.Praza@Sun.COM 			abort();
38667887SLiane.Praza@Sun.COM 		}
38677887SLiane.Praza@Sun.COM 		r = tmpl_validate_prop(prop, prop_pattern, pg, pg_pattern,
38687887SLiane.Praza@Sun.COM 		    errs);
38697887SLiane.Praza@Sun.COM 		if (r != TVS_SUCCESS)
38707887SLiane.Praza@Sun.COM 			rc = r;
38717887SLiane.Praza@Sun.COM 	}
38727887SLiane.Praza@Sun.COM 
38737887SLiane.Praza@Sun.COM 	/*
38747887SLiane.Praza@Sun.COM 	 * Confirm required properties are present.
38757887SLiane.Praza@Sun.COM 	 */
38767887SLiane.Praza@Sun.COM 	r = tmpl_required_props_present(e, pg, pg_pattern, errs);
38777887SLiane.Praza@Sun.COM 	if (r != TVS_SUCCESS)
38787887SLiane.Praza@Sun.COM 		rc = r;
38797887SLiane.Praza@Sun.COM 
38807887SLiane.Praza@Sun.COM 	return (rc);
38817887SLiane.Praza@Sun.COM }
38827887SLiane.Praza@Sun.COM 
38837887SLiane.Praza@Sun.COM /*
38847887SLiane.Praza@Sun.COM  * Validate that the property groups in the entity conform to the template
38857887SLiane.Praza@Sun.COM  * specifications.  Specifically, this means do the following:
38867887SLiane.Praza@Sun.COM  *
38877887SLiane.Praza@Sun.COM  *	- Loop through the property groups in the entity skipping the ones
38887887SLiane.Praza@Sun.COM  *	  that are of type "template".
38897887SLiane.Praza@Sun.COM  *
38907887SLiane.Praza@Sun.COM  *	- For the PG search for the corresponding template_pg_pattern
38917887SLiane.Praza@Sun.COM  *	  property group.  It is possible that one may not exist.
38927887SLiane.Praza@Sun.COM  *
38937887SLiane.Praza@Sun.COM  *	- Verify that the PG is in conformance with the pg_pattern
38947887SLiane.Praza@Sun.COM  *	  specification if it exists.
38957887SLiane.Praza@Sun.COM  */
38967887SLiane.Praza@Sun.COM static tmpl_validate_status_t
tmpl_validate_entity_pgs(entity_t * e,tmpl_errors_t * errs)38977887SLiane.Praza@Sun.COM tmpl_validate_entity_pgs(entity_t *e, tmpl_errors_t *errs)
38987887SLiane.Praza@Sun.COM {
38997887SLiane.Praza@Sun.COM 	composed_pg_t *cpg;
39007887SLiane.Praza@Sun.COM 	uu_avl_t *pgroups;
39017887SLiane.Praza@Sun.COM 	pgroup_t *pg;
39027887SLiane.Praza@Sun.COM 	tmpl_validate_status_t r;
39037887SLiane.Praza@Sun.COM 	tmpl_validate_status_t rc = TVS_SUCCESS;
39047887SLiane.Praza@Sun.COM 
39057887SLiane.Praza@Sun.COM 	assert(e->sc_etype == SVCCFG_INSTANCE_OBJECT);
39067887SLiane.Praza@Sun.COM 
39077887SLiane.Praza@Sun.COM 	pgroups = e->sc_u.sc_instance.sc_composed;
39087887SLiane.Praza@Sun.COM 	for (cpg = uu_avl_first(pgroups);
39097887SLiane.Praza@Sun.COM 	    cpg != NULL;
39107887SLiane.Praza@Sun.COM 	    cpg = uu_avl_next(pgroups, cpg)) {
39117887SLiane.Praza@Sun.COM 		if (strcmp(cpg->cpg_type, SCF_GROUP_TEMPLATE) == 0)
39127887SLiane.Praza@Sun.COM 			continue;
39137887SLiane.Praza@Sun.COM 		pg = CPG2PG(cpg);
39147887SLiane.Praza@Sun.COM 		if ((r = tmpl_validate_pg(e, pg, errs)) != TVS_SUCCESS)
39157887SLiane.Praza@Sun.COM 			rc = r;
39167887SLiane.Praza@Sun.COM 	}
39177887SLiane.Praza@Sun.COM 
39187887SLiane.Praza@Sun.COM 	return (rc);
39197887SLiane.Praza@Sun.COM }
39207887SLiane.Praza@Sun.COM 
39217887SLiane.Praza@Sun.COM /*
39227887SLiane.Praza@Sun.COM  * Validate the instance, e, by performing the following checks:
39237887SLiane.Praza@Sun.COM  *
39247887SLiane.Praza@Sun.COM  *	- Verify template consistency.
39257887SLiane.Praza@Sun.COM  *
39267887SLiane.Praza@Sun.COM  *	- Validate each property group in the entity is in conformance
39277887SLiane.Praza@Sun.COM  *	  with the template specifications.
39287887SLiane.Praza@Sun.COM  *
39297887SLiane.Praza@Sun.COM  *	- Verify that all required property groups are present in the
39307887SLiane.Praza@Sun.COM  *	  entity.
39317887SLiane.Praza@Sun.COM  */
39327887SLiane.Praza@Sun.COM static tmpl_validate_status_t
tmpl_validate_instance(entity_t * e,tmpl_errors_t * errs)39337887SLiane.Praza@Sun.COM tmpl_validate_instance(entity_t *e, tmpl_errors_t *errs)
39347887SLiane.Praza@Sun.COM {
39357887SLiane.Praza@Sun.COM 	tmpl_validate_status_t r;
39367887SLiane.Praza@Sun.COM 	tmpl_validate_status_t rc = TVS_SUCCESS;
39377887SLiane.Praza@Sun.COM 	int status;
39387887SLiane.Praza@Sun.COM 	tv_errors_t *ste;
39397887SLiane.Praza@Sun.COM 
39407887SLiane.Praza@Sun.COM 	/* Prepare to collect errors for this instance. */
39417887SLiane.Praza@Sun.COM 	ste = tv_errors_create(e->sc_fmri);
39427887SLiane.Praza@Sun.COM 	status = uu_list_insert_after(errs->te_scf, errs->te_cur_scf, ste);
39437887SLiane.Praza@Sun.COM 	assert(status == 0);
39447887SLiane.Praza@Sun.COM 	errs->te_cur_scf = ste;
39457887SLiane.Praza@Sun.COM 
39467887SLiane.Praza@Sun.COM 	/* Verify template consistency */
39477887SLiane.Praza@Sun.COM 	rc = tmpl_consistency(e, errs);
39487887SLiane.Praza@Sun.COM 
39497887SLiane.Praza@Sun.COM 	/* Validate the property groups in the entity. */
39507887SLiane.Praza@Sun.COM 	r = tmpl_validate_entity_pgs(e, errs);
39517887SLiane.Praza@Sun.COM 	if (r != TVS_SUCCESS)
39527887SLiane.Praza@Sun.COM 		rc = r;
39537887SLiane.Praza@Sun.COM 
39547887SLiane.Praza@Sun.COM 	/* Verify that all required property groups are present. */
39557887SLiane.Praza@Sun.COM 	r = tmpl_required_pg_present(e, errs);
39567887SLiane.Praza@Sun.COM 	if (r != TVS_SUCCESS)
39577887SLiane.Praza@Sun.COM 		rc = r;
39587887SLiane.Praza@Sun.COM 
39597887SLiane.Praza@Sun.COM 	return (rc);
39607887SLiane.Praza@Sun.COM }
39617887SLiane.Praza@Sun.COM 
39627887SLiane.Praza@Sun.COM /*
39637887SLiane.Praza@Sun.COM  * First validate the instances of the service.
39647887SLiane.Praza@Sun.COM  */
39657887SLiane.Praza@Sun.COM static tmpl_validate_status_t
tmpl_validate_service(entity_t * svc,tmpl_errors_t * errs)39667887SLiane.Praza@Sun.COM tmpl_validate_service(entity_t *svc, tmpl_errors_t *errs)
39677887SLiane.Praza@Sun.COM {
39687887SLiane.Praza@Sun.COM 	entity_t *inst;
39697887SLiane.Praza@Sun.COM 	tmpl_validate_status_t r;
39707887SLiane.Praza@Sun.COM 	tmpl_validate_status_t rc = TVS_SUCCESS;
39717887SLiane.Praza@Sun.COM 
39727887SLiane.Praza@Sun.COM 	assert(svc->sc_etype == SVCCFG_SERVICE_OBJECT);
39737887SLiane.Praza@Sun.COM 
39747887SLiane.Praza@Sun.COM 	load_general_templates(svc);
39757887SLiane.Praza@Sun.COM 
39767887SLiane.Praza@Sun.COM 	/* Validate the service's instances. */
39777887SLiane.Praza@Sun.COM 	for (inst = uu_list_first(svc->sc_u.sc_service.sc_service_instances);
39787887SLiane.Praza@Sun.COM 	    inst != NULL;
39797887SLiane.Praza@Sun.COM 	    inst = uu_list_next(svc->sc_u.sc_service.sc_service_instances,
39807887SLiane.Praza@Sun.COM 	    inst)) {
39817887SLiane.Praza@Sun.COM 		load_instance_restarter(inst);
39827887SLiane.Praza@Sun.COM 		build_composed_instance(inst);
39837887SLiane.Praza@Sun.COM 		r = tmpl_validate_instance(inst, errs);
39847887SLiane.Praza@Sun.COM 		if (r != TVS_SUCCESS)
39857887SLiane.Praza@Sun.COM 			rc = r;
39867887SLiane.Praza@Sun.COM 		demolish_composed_instance(inst);
39877887SLiane.Praza@Sun.COM 	}
39887887SLiane.Praza@Sun.COM 
39897887SLiane.Praza@Sun.COM 	return (rc);
39907887SLiane.Praza@Sun.COM }
39917887SLiane.Praza@Sun.COM 
39927887SLiane.Praza@Sun.COM /*
39937887SLiane.Praza@Sun.COM  * Validate all services and instances in the bundle against their
39947887SLiane.Praza@Sun.COM  * templates.  If err_list is not NULL, a tmpl_errors structure will be
39957887SLiane.Praza@Sun.COM  * allocated and its address will be returned to err_list.  This structure
39967887SLiane.Praza@Sun.COM  * can be used to generate error messages.
39977887SLiane.Praza@Sun.COM  */
39987887SLiane.Praza@Sun.COM tmpl_validate_status_t
tmpl_validate_bundle(bundle_t * bndl,tmpl_errors_t ** err_list)39997887SLiane.Praza@Sun.COM tmpl_validate_bundle(bundle_t *bndl, tmpl_errors_t **err_list)
40007887SLiane.Praza@Sun.COM {
40017887SLiane.Praza@Sun.COM 	tmpl_errors_t *errs = NULL;
40027887SLiane.Praza@Sun.COM 	entity_t *svc;
40037887SLiane.Praza@Sun.COM 	tmpl_validate_status_t r;
40047887SLiane.Praza@Sun.COM 	tmpl_validate_status_t rc = TVS_SUCCESS;
40057887SLiane.Praza@Sun.COM 
40067887SLiane.Praza@Sun.COM 	if (err_list != NULL)
40077887SLiane.Praza@Sun.COM 		*err_list = NULL;
40087887SLiane.Praza@Sun.COM 	if (bndl->sc_bundle_type != SVCCFG_MANIFEST) {
40097887SLiane.Praza@Sun.COM 		semerr(gettext("Bundle is not a manifest.  Unable to validate "
40107887SLiane.Praza@Sun.COM 		    "against templates.\n"));
40117887SLiane.Praza@Sun.COM 		return (TVS_FATAL);
40127887SLiane.Praza@Sun.COM 	}
40137887SLiane.Praza@Sun.COM 
40147887SLiane.Praza@Sun.COM 	errs = tmpl_errors_create();
40157887SLiane.Praza@Sun.COM 	if (errs == NULL)
40167887SLiane.Praza@Sun.COM 		uu_die(emesg_nomem);
40177887SLiane.Praza@Sun.COM 
40187887SLiane.Praza@Sun.COM 	lscf_prep_hndl();		/* Initialize g_hndl */
40197887SLiane.Praza@Sun.COM 	if (load_init() != 0)
40207887SLiane.Praza@Sun.COM 		uu_die(emesg_nomem);
40217887SLiane.Praza@Sun.COM 
40227887SLiane.Praza@Sun.COM 	/*
40237887SLiane.Praza@Sun.COM 	 * We will process all services in the bundle, unless we get a
40247887SLiane.Praza@Sun.COM 	 * fatal error.  That way we can report all errors on all services
40257887SLiane.Praza@Sun.COM 	 * on a single run of svccfg.
40267887SLiane.Praza@Sun.COM 	 */
40277887SLiane.Praza@Sun.COM 	for (svc = uu_list_first(bndl->sc_bundle_services);
40287887SLiane.Praza@Sun.COM 	    svc != NULL;
40297887SLiane.Praza@Sun.COM 	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
40307887SLiane.Praza@Sun.COM 		if (svc->sc_etype != SVCCFG_SERVICE_OBJECT) {
40317887SLiane.Praza@Sun.COM 			semerr(gettext("Manifest for %s contains an object "
40327887SLiane.Praza@Sun.COM 			    "named \"%s\" that is not a service.\n"),
40337887SLiane.Praza@Sun.COM 			    bndl->sc_bundle_name, svc->sc_name);
40347887SLiane.Praza@Sun.COM 			tmpl_errors_destroy(errs);
40357887SLiane.Praza@Sun.COM 			load_fini();
40367887SLiane.Praza@Sun.COM 			return (TVS_FATAL);
40377887SLiane.Praza@Sun.COM 		}
40387887SLiane.Praza@Sun.COM 		if ((r = tmpl_validate_service(svc, errs)) != TVS_SUCCESS)
40397887SLiane.Praza@Sun.COM 			rc = r;
40407887SLiane.Praza@Sun.COM 		if (r == TVS_FATAL)
40417887SLiane.Praza@Sun.COM 			break;
40427887SLiane.Praza@Sun.COM 	}
40437887SLiane.Praza@Sun.COM 
40447887SLiane.Praza@Sun.COM 	if (err_list == NULL) {
40457887SLiane.Praza@Sun.COM 		tmpl_errors_destroy(errs);
40467887SLiane.Praza@Sun.COM 	} else {
40477887SLiane.Praza@Sun.COM 		*err_list = errs;
40487887SLiane.Praza@Sun.COM 	}
40497887SLiane.Praza@Sun.COM 
40507887SLiane.Praza@Sun.COM 	load_fini();
40517887SLiane.Praza@Sun.COM 
40527887SLiane.Praza@Sun.COM 	return (rc);
40537887SLiane.Praza@Sun.COM }
4054