4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * This file provides the code that allows svccfg(8) to validate a
29 * manifest against the template specifications. svccfg uses the
30 * validation facilities for the import and validate subcommands.
32 * There are three entry points -- tmpl_validate_bundle(),
33 * tmpl_errors_print() and tmpl_errors_destroy(). svccfg calls
34 * tmpl_validate_bundle() to validate a bundle. tmpl_validate_bundle()
35 * returns a pointer to a tmpl_errors_t. This is a pointer to information
36 * about any validation errors that were found. If an error was detected,
37 * svccfg calls tmpl_errors_print() to print the error information. Once
38 * the error information is printed, svccfg calls tmpl_errors_destroy() to
39 * free the memory associated with the tmpl_errors_t.
41 * libscf's scf_tmpl.c performs similar checks to the ones described in
42 * this paragraph. Any changes to the algorithms in this file should also
43 * be infcorporated into scf_tmpl.c. The reason that there are two bodies
44 * of code is that they work on different data structures.
45 * tmpl_validate_bundle() validates each instance of each service in the
46 * bundle. The following checks are performed on each instance:
48 * 1. Verify template consistency.
49 * A. No conflicting definitions of "pg_pattern" are allowed
50 * within a single instance.
51 * B. Templates at a narrow target (e.g. instance) which define
52 * property groups already templated at a broad target
53 * (e.g. delegate or all) are strongly discouraged.
54 * C. Developers may not define a template which specifies a
55 * single prop_pattern name with differing types on the same
57 * D. If a pg_pattern has a required attribute with a value of
58 * true, then its name and type attributes must be
60 * E. If a prop_pattern has a required attribute with a value
61 * of true, then its type attribute must be specified.
62 * F. If a prop_pattern has an include_values element make sure
63 * that the appropriate constraints or values element has
65 * 2. Validate that each property group in the instance is in
66 * conformance with the template specifications.
67 * A. Verify that the types of the PG and the pg_pattern are
69 * B. Verify properties of the PG against the prop_patterns in
71 * o Verify property's type.
72 * o Verify cardinality.
73 * o Vefiy that property values satisfy the constraints
74 * imposed by the prop_pattern.
75 * C. Verify that required properties are present.
76 * 3. Verify that all required property groups are present in the
79 * tmpl_validate_bundle() is called after svccfg has processed the manifest
80 * file. The manifest is represented in memory by a set of entity_t,
81 * pgroup_t, property_t and value_t structures. These structures are
82 * defined in svccfg.h.
84 * tmpl_validate_bundle() calls tmpl_validate_service() for each service in
85 * the bundle, and tmpl_validate_service() then calls
86 * tmpl_validate_instance() for each instance in the service.
87 * tmpl_validate_instance() is the function that does the real work of
88 * validation against the template specification.
95 * In order to perform the validation specified by 1.B above, we need to
96 * load the templates specifications for the global service and the
97 * instance's restarter. This information is loaded from the repository
98 * and it is held in memory using the entity_t, pgroup_t, property_t and
99 * value_t hierarchy of structures. When a service is processed,
100 * load_general_templates() is called to load the information for the
101 * global service and restarter that is declared at the service level. The
102 * sc_service.sc_global and sc_service.sc_restarter members of the
103 * service's entity_t point to the information for the global and restarter
106 * The instance portion of a manifest can declare an instance specific
107 * restarter. If this is the case, load_instance_restarter() will load the
108 * information for that restarter, and it is saved in the
109 * sc_instance.sc_instance_restarter member of the entity_t that represents
112 * Composed Properties:
113 * -------------------
114 * We need the ability to process the composed properties of an instance.
115 * That is to say if an instance defines a property, it overrides any
116 * definition in the service. Otherwise, the service's definition is
117 * inherited in the instance.
119 * In an entity_t, the sc_instance.sc_composed member points to a
120 * uu_avl tree of composed property groups (composed_pg_t) for the
121 * instance. The composed_pg_t has two members, cpg_instance_pg and
122 * cpg_service_pg, that point to the instance and service property group
123 * definitions respectively. Either of these may be NULL indicating that
124 * only an instance or service definition exists in the manifest.
126 * In the case where both the instance and the service define a property
127 * group, the properties must be composed. This is done by
128 * compose_props(). The compose_pg_t holds the composed properties in a
129 * uu_avl_tree at cpf_compose_props. This is a tree of property_t
130 * structures. If a property is defined in both the instance and service
131 * property group, the tree will hold the instance definition. If the
132 * property is defined at only one level, the tree will hold the property_t
133 * for that level. Thus, the tree is truly a set of composed properties of
134 * the property group.
136 * Property Group Iteration:
137 * ------------------------
138 * A number of functions must iterate through an instance's property groups
139 * looking for the ones that define a pg_pattern or a prop_pattern. To be
140 * specific, the iteration starts with the composed view of the instance.
141 * It then proceeds through the restarter information and finally moves on
142 * to the global service. The pg_iter_t structure holds the information
143 * that is needed to implement this type of iteration. pg_iter_create()
144 * creates one of these iterators, and pg_iter_destroy() frees the memory
145 * associated with the pg_iter_t. next_pattern_pg(), is used to step
146 * through the iteration.
150 * While performing the templates validation checks, svccfg collects
151 * information for all the errors that it finds. Because of this you will
152 * see many places in the code where a loop is not exited when an error is
153 * encountered. We note that fact that an error has occurred, but continue
154 * in the loop to see if there are more validation errors. The error code
155 * of the last error that is encountered is returned. This works, because
156 * the callers of tmpl_validate_bundle() only look to see whether or not
157 * the return code is TVS_SUCCESS.
159 * The information for reporting the errors is collected in a tmpl_errors_t
160 * structure, and tmpl_validate_bundle() returns the address of this
161 * structure. The caller of tmpl_validate_bundle() can then call
162 * tmpl_errors_print() to display the error information to the user.
164 * There are two categories of errors. Some errors are seen when
165 * processing the information in the manifest. This type of error is only
166 * seen by svccfg when it is importing or validating a manifest. The other
167 * type of error consists of template validation errors. These errors can
168 * be seen when processing a manifest or when performing a templates
169 * validation of the information associated with an FMRI in the the
170 * repository. tmpl_errors_add_im() is used to capture error information
171 * about the first type of error, and add_scf_error() is used to capture
172 * error information about the second type of error.
174 * The distinction is important when printing the error information. The
175 * fuctions for printing the first type of error reside in this file, since
176 * these errors will only be seen by the functions in this file. The
177 * functions for printing the template validation errors reside in libscf,
178 * because these errors are of a more general nature.
180 * Thus, tmpl_errors_t has two lists -- one for each type of error.
181 * te_list is a list of im_tmpl_error_t structures that represent the first
182 * type of error. te_scf is a list of tv_errors_t structures that hold
183 * information about general template validation errors.
184 * tmpl_errors_print() processes both lists to print information about all
185 * errors. In tmpl_errors_print() im_tmpl_error_print() is used to print
186 * the errors that are specific to this file. scf_tmpl_strerror() provides
187 * the errors messages for general templates errors.
189 * As was mentioned in the previous paragraph, im_tmpl_error_print() is
190 * responsible for printing the errors that are specific to this file.
191 * Based on the error code, it dispatches to one of
192 * im_perror_bad_conversion(), im_perror_bad_template(),
193 * im_perror_invalid_type(), im_perror_missing_pg_type() or
194 * im_perror_missing_type(). The rest of the im_perror_* functions provide
195 * services to these error specific functions by printing common
198 * im_perror_item() is the heart of this message printing subsystem. It is
199 * called directly or indirectly by all of the other im_perror_* functions.
200 * im_perror_item() prints a single item of error information. If svccfg
201 * is running in interactive mode, im_perror_item() prints each item on a
202 * single line, so that they are readable by a human. In non-interactive
203 * mode, all items are printed on a single line separated by semi-colons.
208 #include <inttypes.h>
212 #include <libscf_priv.h>
219 * Clear error_info_t structure.
221 #define CLEAR_ERROR_INFO(ei) ((void) memset((ei), 0, sizeof (error_info_t)))
224 * Retrieve the property group pointer from the composed_pg structure.
226 #define CPG2PG(cpg) (cpg->cpg_instance_pg ? cpg->cpg_instance_pg : \
230 * Convert a pointer to an empty string into a NULL pointer.
232 #define EMPTY_TO_NULL(p) (((p) && (*(p) == 0)) ? NULL : (p))
234 /* uu_avl and uu_list debugging bits. */
236 #define TMPL_DEBUG_AVL_POOL UU_DEFAULT
237 #define TMPL_DEBUG_LIST UU_DEFAULT
238 #define TMPL_DEBUG_LIST_POOL UU_DEFAULT
239 #define TMPL_DEBUG_TREE UU_DEFAULT
241 #define TMPL_DEBUG_AVL_POOL UU_AVL_POOL_DEBUG
242 #define TMPL_DEBUG_LIST UU_LIST_DEBUG
243 #define TMPL_DEBUG_LIST_POOL UU_LIST_POOL_DEBUG
244 #define TMPL_DEBUG_TREE UU_AVL_DEBUG
248 * Structures and enums that are used in producing error messages:
250 * error_info_t is used to pass information about an error to
251 * tmpl_errors_add_im() and add_scf_error(). tmpl_errors_add_im() collects
252 * the error information and stores it in an im_tmpl_error_t. The
253 * im_tmpl_error_t is linked into the tmpl_errors_t, so that the captured
254 * information can be used later when error messages are printed.
256 * tv_errors_t is used to keep track of error information for general
257 * template errors that are known by libscf. add_scf_error() captures the
258 * error information for use in this structure.
261 * enum to designate the type of data that is held in a err_info structure.
263 typedef enum err_info_type
{
264 EIT_NONE
, /* No values in the structure */
265 EIT_BAD_TEMPLATE
, /* Reason that template is bad */
266 EIT_CARDINALITY
, /* Ranges for property cardinality */
267 EIT_INCLUDE_VALUES
, /* include_values type attribute */
268 EIT_MISSING_PG
, /* Name of missing pg */
269 EIT_MISSING_PROP
, /* Name of missing property */
270 EIT_PATTERN_CONFLICT
, /* Conflicting pattern definition */
271 EIT_PROP_TYPE
, /* Value with invalid type */
272 EIT_RANGE
/* Value that is out of range */
276 * Structure to hold information that will be used in generating error
279 typedef struct error_info
{
280 err_info_type_t ei_type
; /* Type of information stored here */
282 /* EIT_BAD_TEMPLATE */
284 const char *ei_reason
;
286 /* EIT_CARDINALITY */
290 uint64_t ei_count
; /* Number of prop values */
292 /* EIT_INCLUDE_VALUES */
298 const char *ei_pg_name
; /* Name of missing pg */
299 const char *ei_pg_type
; /* Type of missing pg */
301 /* EIT_MISSING_PROP */
303 const char *ei_prop_name
; /* Name of prop */
305 /* EIT_PATTERN_CONFLICT */
307 pgroup_t
*ei_pattern
; /* Conficting pattern */
308 } ei_pattern_conflict
;
311 scf_type_t ei_actual
;
312 scf_type_t ei_specified
;
324 * Structure with information about a template violation. This structure
325 * is for use with in memory representations of the manifest and template.
326 * See scf_tmpl_error_t for use with repository representations. Some of
327 * the pointers may be NULL for some types of errors.
329 typedef struct im_tmpl_error
{
330 tmpl_validate_status_t ite_type
; /* Type of error */
331 entity_t
*ite_entity
; /* Instance or service */
332 pgroup_t
*ite_pg
; /* Non-conforming prop. group */
333 pgroup_t
*ite_pg_pattern
; /* Violated pg_pattern */
334 property_t
*ite_prop
; /* Non-conforming property */
335 pgroup_t
*ite_prop_pattern
; /* Violated prop_pattern */
336 value_t
*ite_value
; /* Non-conforming value */
337 error_info_t ite_einfo
; /* Extra error information */
338 uu_list_node_t ite_node
; /* Node to link us in a list. */
342 * This structure holds the data that will be used by scf_tmpl_strerror()
343 * for printing template validation errors.
345 typedef struct tv_errors
{
346 scf_tmpl_errors_t
*tve_errors
; /* Errors for scf_tmpl_strerror() */
347 uu_list_node_t tve_node
; /* Linkage in a list. */
351 * Structure to collect template validation errors.
354 uu_list_t
*te_list
; /* List of im_tmpl_error_t */
355 im_tmpl_error_t
*te_next
; /* Next error to present */
356 uu_list_t
*te_scf
; /* Errors for scf_tmpl_strerror() */
357 tv_errors_t
*te_cur_scf
; /* Current member of te_scf */
360 /* End of structures used in error processing. */
363 * Property group types that are of interest to us. See pgroup_type().
365 typedef enum pg_type
{
372 * Structure to keep track of a set of ASTRING property values for a
373 * property. The consumer may wish to have the ASTRING property values
374 * converted to a numeric form which is the reason for the av_v union.
375 * This structure is returned by av_get_values() and is accessed by
376 * av_get_integer(), av_get_string() and av_get_unsigned().
378 typedef struct avalues
{
379 uint_t av_count
; /* Number of values */
380 scf_type_t av_type
; /* Type of value representation */
382 uint64_t *av_unsigned
; /* Count & boolean values */
383 int64_t *av_integer
; /* Integer values */
384 const char **av_string
; /* String values */
385 } av_v
; /* Container for the values */
389 * composed_pg_t contains the information that is needed to compose a
390 * property group. See the section on Composed Properties in the block
391 * comment at the beginning of this file. The composed_pg structures are
392 * linked into a uu_avl tree. The tree is at sc_instance.sc_composed in
397 * Property group is uniquely identified by its name and type.
398 * These two elements point to the name and type in a pgroup_t
399 * (either service or instance), so they do not need to be
400 * allocated or freed.
402 const char *cpg_name
;
403 const char *cpg_type
;
405 /* References to the actual property group definitions. */
406 pgroup_t
*cpg_instance_pg
;
407 pgroup_t
*cpg_service_pg
;
409 /* Composed properties of the property group. */
410 uu_avl_t
*cpg_composed_props
;
412 uu_avl_node_t cpg_node
; /* Linkage for AVL tree */
416 * Prefixes for standard property names. Used in
417 * include_values_support().
419 typedef struct prop_prefix
{
420 const char *pp_prefix
;
425 * Store a legal range for a property allowing for either signed or
426 * unsigned ranges. It is used to store a range from a template
427 * constraint element of a prop_pattern. The structure is returned by
428 * get_ranges() and is used by value_in_range() to validate the values of a
431 typedef struct range
{
445 * This enum defines the levels where templates can be defined. See the
446 * pg_iter structure below.
448 typedef enum tmpl_level
{
449 TL_NOLEVEL
= 0, /* No level yet specified. */
450 TL_INSTANCE
, /* Instance templates. */
451 TL_COMPOSED
, /* Composed instance. */
452 TL_SERVICE
, /* Service wide templates. */
453 TL_RESTARTER
, /* Templates from restarter manifest. */
454 TL_GLOBAL
/* SMF wide templates. */
458 * pg_iter is a structure that allows us to iterate through property groups
459 * in an instance followed by the property groups of the instance's
460 * service, the instance's restarter and finally the global service. See
461 * the Property Group Iteration section of the block comment at the
462 * beginning of this file.
464 typedef struct pg_iter
{
465 entity_t
*pgi_entity
; /* Entity being searched */
466 const char *pgi_restrict
; /* Only return PGs of this type */
467 tmpl_level_t pgi_level
; /* Current level */
468 entity_t
*pgi_service
; /* Service being processed. */
471 composed_pg_t
*pgi_cpg
;
472 } pgi_current
; /* Current property group. */
476 * enum to distinguish between pg_patterns and prop_patterns. It is used
477 * in the ptrn_info_t structure. See below.
479 typedef enum ptrn_type
{
485 * Structure of information about a pg_pattern or a prop_pattern. It is
486 * used for template consistency checks. gather_pattern() is used to
487 * gather information for all the pg_patterns or prop_patterns in an
488 * instance. It allocates a ptrn_info_t for each of these and adds them to
489 * an avl tree that is held by tmpl_consistency().
491 typedef struct ptrn_info
{
492 ptrn_type_t pi_ptrn_type
;
493 pgroup_t
*pi_ptrnpg
; /* pgroup_t defining the pattern. */
494 const char *pi_name
; /* Name attribute. */
495 const char *pi_type
; /* Type attribute. */
496 const char *pi_target
; /* Target attribute - only PG_PATTERN */
497 const char *pi_pgp_name
; /* Name of the pg pattern. Only */
498 /* used for PROP_PATTERN. */
499 pgroup_t
*pi_enc_pgp
; /* PG of the pg_pattern that holds */
500 /* the prop_pattern defined by this */
501 /* structure. Only used for */
503 uu_avl_node_t pi_link
; /* Linkage into AVL tree */
506 static const char *emesg_nomem
;
509 * Pool for trees of composed property groups.
511 static uu_avl_pool_t
*composed_pg_pool
;
514 * Pool for trees of composed properties.
516 static uu_avl_pool_t
*composed_prop_pool
;
519 * Pool for lists of errors in the internal representation.
521 static uu_list_pool_t
*inmem_errors_pool
;
524 * Pool for trees of pg_pattern info structures (ptrn_info_t).
526 static uu_avl_pool_t
*ptrn_info_pool
;
529 * Pool for lists of template errors in the libscf representation.
531 static uu_list_pool_t
*tv_errors_pool
;
534 * Property name prefixes for constraints and values.
536 static const char *constraint_prefixes
[] = {
537 SCF_PROPERTY_TM_CONSTRAINT_NAME
,
538 SCF_PROPERTY_TM_CONSTRAINT_RANGE
,
541 static const char *value_prefixes
[] = {
542 SCF_PROPERTY_TM_VALUE_PREFIX
,
547 * Function to compare two composed_pg structures.
551 composed_pg_compare(const void *left
, const void *right
, void *unused
)
553 composed_pg_t
*l
= (composed_pg_t
*)left
;
554 composed_pg_t
*r
= (composed_pg_t
*)right
;
557 if ((rc
= strcmp(l
->cpg_name
, r
->cpg_name
)) == 0) {
558 rc
= strcmp(l
->cpg_type
, r
->cpg_type
);
565 composed_prop_compare(const void *left
, const void *right
, void *unused
)
567 property_t
*l
= (property_t
*)left
;
568 property_t
*r
= (property_t
*)right
;
570 return (strcmp(l
->sc_property_name
, r
->sc_property_name
));
573 static composed_pg_t
*
578 cpg
= safe_malloc(sizeof (*cpg
));
579 uu_avl_node_init(cpg
, &cpg
->cpg_node
, composed_pg_pool
);
584 composed_pg_destroy(composed_pg_t
*cpg
)
591 /* Tear down composed property tree if we have one. */
592 if ((cpg
->cpg_composed_props
!= NULL
)) {
593 while (uu_avl_teardown(cpg
->cpg_composed_props
, &marker
) !=
596 * Nothing to do other than getting the property
597 * out of the list. This cleans up the property's
601 uu_avl_destroy(cpg
->cpg_composed_props
);
604 /* Clean up any pgroup_t references to us. */
605 if ((pg
= cpg
->cpg_instance_pg
) != NULL
) {
606 assert((pg
->sc_pgroup_composed
== NULL
) ||
607 (pg
->sc_pgroup_composed
== cpg
));
608 pg
->sc_pgroup_composed
= NULL
;
611 uu_avl_node_fini(cpg
, &cpg
->cpg_node
, composed_pg_pool
);
616 * Walk the property group at pg, and add its properties to the AVL tree at
620 grow_props_tree(pgroup_t
*pg
, uu_avl_t
*tree
)
622 uu_avl_index_t marker
;
625 for (prop
= uu_list_first(pg
->sc_pgroup_props
);
627 prop
= uu_list_next(pg
->sc_pgroup_props
, prop
)) {
628 if (uu_avl_find(tree
, prop
, NULL
, &marker
) == NULL
) {
630 * If there was no match, insert the property into
631 * the tree. If we do get a match, there is
632 * nothing to do. That is because we rely on our
633 * caller to process the instance properties first,
634 * and the instance properties override the service
637 uu_avl_insert(tree
, prop
, marker
);
643 * The composed properties are stored in a uu_avl_tree. First we populate
644 * the tree with properties from the instance level property group. Then,
645 * we'll add the properties from the service level property group.
648 compose_props(composed_pg_t
*cpg
)
652 tree
= uu_avl_create(composed_prop_pool
, cpg
, TMPL_DEBUG_TREE
);
654 uu_die(gettext("composed_pool tree creation failed: %s\n"),
655 uu_strerror(uu_error()));
657 cpg
->cpg_composed_props
= tree
;
660 * compose_props() is only called when there is both an instance
661 * and a service definition of the property group. This implies
662 * that neither cpg->cpg_instance_pg nor cpg->cpg_service_pg can be
666 * First add instance properties to the tree.
668 assert(cpg
->cpg_instance_pg
!= NULL
);
669 grow_props_tree(cpg
->cpg_instance_pg
, tree
);
672 * Add service properties to the tree.
674 assert(cpg
->cpg_service_pg
!= NULL
);
675 grow_props_tree(cpg
->cpg_service_pg
, tree
);
679 * This function is a utility for build_composed_instance().
682 build_composed_property_groups(entity_t
*inst
, uu_avl_t
*tree
)
685 uu_avl_index_t marker
;
686 composed_pg_t
*match
;
690 /* First capture the instance property groups. */
691 for (pg
= uu_list_first(inst
->sc_pgroups
);
693 pg
= uu_list_next(inst
->sc_pgroups
, pg
)) {
694 cpg
= composed_pg_create();
695 cpg
->cpg_name
= pg
->sc_pgroup_name
;
696 cpg
->cpg_type
= pg
->sc_pgroup_type
;
697 cpg
->cpg_instance_pg
= pg
;
698 match
= uu_avl_find(tree
, cpg
, NULL
, &marker
);
699 /* Since we do the instance first, there should be no match. */
700 assert(match
== NULL
);
701 uu_avl_insert(tree
, cpg
, marker
);
702 pg
->sc_pgroup_composed
= cpg
;
705 /* Now capture the service property groups. */
706 svc
= inst
->sc_parent
;
708 for (pg
= uu_list_first(svc
->sc_pgroups
);
710 pg
= uu_list_next(svc
->sc_pgroups
, pg
)) {
712 cpg
= composed_pg_create();
713 cpg
->cpg_name
= pg
->sc_pgroup_name
;
714 cpg
->cpg_type
= pg
->sc_pgroup_type
;
715 cpg
->cpg_service_pg
= pg
;
716 match
= uu_avl_find(tree
, cpg
, NULL
, &marker
);
718 uu_avl_insert(tree
, cpg
, marker
);
719 /* Get new composed_pg_t next at top of loop. */
723 * Already have a composed_pg from instance
724 * processing. Just add the pointer to the service
725 * pg and compose the properties.
727 match
->cpg_service_pg
= pg
;
728 compose_props(match
);
732 composed_pg_destroy(cpg
);
736 build_composed_instance(entity_t
*inst
)
740 assert(inst
->sc_etype
== SVCCFG_INSTANCE_OBJECT
);
742 if (inst
->sc_u
.sc_instance
.sc_composed
== NULL
) {
743 tree
= uu_avl_create(composed_pg_pool
, inst
, TMPL_DEBUG_TREE
);
745 uu_die(gettext("composed_instance tree creation "
746 "failed: %s\n"), uu_strerror(uu_error()));
748 inst
->sc_u
.sc_instance
.sc_composed
= tree
;
750 build_composed_property_groups(inst
,
751 inst
->sc_u
.sc_instance
.sc_composed
);
755 demolish_composed_instance(entity_t
*inst
)
761 tree
= inst
->sc_u
.sc_instance
.sc_composed
;
766 while ((cpg
= uu_avl_teardown(tree
, &marker
)) != NULL
) {
767 composed_pg_destroy(cpg
);
769 uu_avl_destroy(tree
);
771 inst
->sc_u
.sc_instance
.sc_composed
= NULL
;
774 * Return the number of values in prop.
777 count_prop_values(property_t
*prop
)
779 return (uu_list_numnodes(prop
->sc_property_values
));
783 is_numeric_type(scf_type_t type
)
785 if (type
== SCF_TYPE_BOOLEAN
)
787 if (type
== SCF_TYPE_COUNT
)
789 if (type
== SCF_TYPE_INTEGER
)
795 pgroup_type(pgroup_t
*pg
)
797 if (strcmp(pg
->sc_pgroup_type
, SCF_GROUP_TEMPLATE_PG_PATTERN
) == 0)
798 return (PG_PATTERN_PG
);
799 if (strcmp(pg
->sc_pgroup_type
, SCF_GROUP_TEMPLATE_PROP_PATTERN
) == 0)
800 return (PROP_PATTERN_PG
);
805 * Search the property group at pg for a property named name. If the
806 * property group has a tree of composed properties, the tree will be
807 * searched for the property. Otherwise, the property group's linked list
811 property_find(pgroup_t
*pg
, const char *name
)
816 cpg
= pg
->sc_pgroup_composed
;
818 if ((cpg
== NULL
) || (cpg
->cpg_composed_props
== NULL
)) {
819 /* This is not a composed property group. */
820 return (internal_property_find(pg
, name
));
824 * This is a composed property group, so look for the property in
827 look
.sc_property_name
= (char *)name
;
828 return (uu_avl_find(cpg
->cpg_composed_props
, &look
, NULL
, NULL
));
832 * Functions for manipulating the avalues structure.
836 * Free allocated memory referenced by the avalues structure. Then, free
837 * the structure itself.
840 av_destroy(avalues_t
*av
)
844 switch (av
->av_type
) {
845 case SCF_TYPE_BOOLEAN
:
847 uu_free(av
->av_v
.av_unsigned
);
849 case SCF_TYPE_INTEGER
:
850 uu_free(av
->av_v
.av_integer
);
854 * We don't need to free the strings that are referenced by
855 * av_string. The strings are held in propery_t structures
856 * that will be freed at a later time.
858 uu_free(av
->av_v
.av_string
);
864 * Allocate and inialize an avalues structure. count represents the
865 * number of values the structure is expected to hold. type specifies how
866 * the consumer of the property values would like to see them represented.
867 * See comments for the av_get_values() more details on how type is used.
869 * The returned structure must be freed by calling av_destroy().
871 * NULL is returned if memory allocation fails.
874 av_create(size_t count
, scf_type_t type
)
876 uint_t alloc_failed
= 0;
879 av
= uu_zalloc(sizeof (*av
));
882 av
->av_count
= count
;
885 case SCF_TYPE_BOOLEAN
:
887 av
->av_v
.av_unsigned
= uu_zalloc(count
* sizeof (uint64_t));
888 if (av
->av_v
.av_unsigned
== NULL
)
891 case SCF_TYPE_INTEGER
:
892 av
->av_v
.av_integer
= uu_zalloc(count
* sizeof (int64_t));
893 if (av
->av_v
.av_integer
== NULL
)
897 av
->av_v
.av_string
= uu_zalloc(count
* sizeof (char *));
898 if (av
->av_v
.av_string
== NULL
)
909 * Return the ith integer value in av.
912 av_get_integer(avalues_t
*av
, uint_t i
)
914 assert(av
->av_type
== SCF_TYPE_INTEGER
);
915 assert(i
< av
->av_count
);
916 return (*(av
->av_v
.av_integer
+ i
));
920 * Return the ith string value in av.
923 av_get_string(avalues_t
*av
, uint_t i
)
925 assert(is_numeric_type(av
->av_type
) == 0);
926 assert(i
< av
->av_count
);
927 return (*(av
->av_v
.av_string
+ i
));
931 * Return the ith unsigned value in av.
934 av_get_unsigned(avalues_t
*av
, uint_t i
)
936 assert((av
->av_type
== SCF_TYPE_BOOLEAN
) ||
937 (av
->av_type
== SCF_TYPE_COUNT
));
938 assert(i
< av
->av_count
);
939 return (*(av
->av_v
.av_unsigned
+ i
));
943 * Store the value in the ith slot of the av structure. If av is being
944 * used to store numeric values, the string at value will be converted to
945 * the appropriate numeric form.
947 static tmpl_validate_status_t
948 av_set_value(avalues_t
*av
, uint_t i
, const char *value
)
954 if (is_numeric_type(av
->av_type
)) {
955 switch (av
->av_type
) {
956 case SCF_TYPE_BOOLEAN
:
958 un
= strtoull(value
, &endptr
, 0);
959 if ((endptr
== value
) || (*endptr
!= 0)) {
960 return (TVS_BAD_CONVERSION
);
962 *(av
->av_v
.av_unsigned
+ i
) = un
;
964 case SCF_TYPE_INTEGER
:
965 n
= strtoll(value
, &endptr
, 0);
966 if ((endptr
== value
) || (*endptr
!= 0)) {
967 return (TVS_BAD_CONVERSION
);
969 *(av
->av_v
.av_integer
+ i
) = n
;
972 *(av
->av_v
.av_string
+ i
) = value
;
975 return (TVS_SUCCESS
);
979 * Find the property whose name is prop_name in the property group at pg.
980 * Read all the values of this property and return them in an avalues
981 * structure placing the address of the structure in *values. The caller
982 * must free the structure by calling av_destroy().
984 * The type parameter is used to indicate the type of information that the
985 * caller would like to consume. If it is one of the numeric types, the
986 * property value will be converted to the appropriate numeric type before
987 * placing it in the avalues struct. Decoding will be done before the
988 * conversion if necessary.
990 static tmpl_validate_status_t
991 av_get_values(pgroup_t
*pg
, const char *prop_name
, scf_type_t type
,
997 tmpl_validate_status_t rc
;
1000 prop
= property_find(pg
, prop_name
);
1002 return (TVS_NOMATCH
);
1004 assert(prop
->sc_value_type
== SCF_TYPE_ASTRING
);
1005 av
= av_create(count_prop_values(prop
), type
);
1007 uu_die(emesg_nomem
);
1009 /* Collect the values. */
1010 for ((v
= uu_list_first(prop
->sc_property_values
)), i
= 0;
1012 (v
= uu_list_next(prop
->sc_property_values
, v
)), i
++) {
1013 assert(i
< av
->av_count
);
1014 assert(v
->sc_type
== SCF_TYPE_ASTRING
);
1015 rc
= av_set_value(av
, i
, v
->sc_u
.sc_string
);
1016 if (rc
!= TVS_SUCCESS
) {
1022 return (TVS_SUCCESS
);
1026 * Find the property in pg whose name is prop_name. Return a pointer to
1027 * the first astring value in that property.
1029 * NULL is returned if there is no property named prop_name or if it does
1030 * not have an astring value.
1033 find_astring_value_in_pg(pgroup_t
*pg
, const char *prop_name
)
1038 prop
= property_find(pg
, prop_name
);
1041 if (prop
->sc_value_type
!= SCF_TYPE_ASTRING
)
1043 v
= uu_list_first(prop
->sc_property_values
);
1046 assert(v
->sc_type
== SCF_TYPE_ASTRING
);
1047 return (v
->sc_u
.sc_string
);
1050 * Find the first property value of type SCF_TYPE_COUNT in the property at
1051 * prop. Return the value to count.
1053 static tmpl_validate_status_t
1054 find_count_value(property_t
*prop
, uint64_t *count
)
1058 assert(prop
->sc_value_type
== SCF_TYPE_COUNT
);
1059 value
= uu_list_first(prop
->sc_property_values
);
1061 return (TVS_NOMATCH
);
1062 *count
= value
->sc_u
.sc_count
;
1063 return (TVS_SUCCESS
);
1067 * pattern is a property group representing a pg_pattern or a
1068 * prop_pattern. This function returns the name specification from the
1069 * pg_pattern or prop_pattern.
1072 find_name_specification(pgroup_t
*pattern
)
1074 return (find_astring_value_in_pg(pattern
, SCF_PROPERTY_TM_NAME
));
1078 * pattern is a property group representing a pg_pattern or a prop_pattern.
1079 * This function returns the type specification from the pg_pattern or
1083 find_type_specification(pgroup_t
*pattern
)
1085 return (find_astring_value_in_pg(pattern
, SCF_PROPERTY_TM_TYPE
));
1089 * Find the FMRI of the restarter for the entity, e. The restarter is the
1090 * value of the "restarter" property in the "general" property group.
1093 find_restarter(entity_t
*e
)
1099 pg
= internal_pgroup_find(e
, scf_pg_general
, scf_group_framework
);
1101 prop
= property_find(pg
, SCF_PROPERTY_RESTARTER
);
1102 if ((prop
!= NULL
) && (prop
->sc_value_type
== SCF_TYPE_FMRI
)) {
1103 v
= uu_list_first(prop
->sc_property_values
);
1105 return (v
->sc_u
.sc_string
);
1110 * Didn't find the restarter.
1116 * prop_pattern points to a prop_pattern. This function finds the
1117 * cardinality specification in the prop_pattern and returns the minimum
1118 * and maximum values of the cardinality.
1120 * Returns TVS_NOMATCH if either the cardinality minimum or maximum are
1123 static tmpl_validate_status_t
1124 get_cardinality(pgroup_t
*prop_pattern
, uint64_t *min
, uint64_t *max
)
1127 tmpl_validate_status_t rc
;
1129 assert(strcmp(prop_pattern
->sc_pgroup_type
,
1130 SCF_GROUP_TEMPLATE_PROP_PATTERN
) == 0);
1132 prop
= property_find(prop_pattern
,
1133 SCF_PROPERTY_TM_CARDINALITY_MIN
);
1135 return (TVS_NOMATCH
);
1136 rc
= find_count_value(prop
, min
);
1137 if (rc
!= TVS_SUCCESS
)
1140 prop
= property_find(prop_pattern
,
1141 SCF_PROPERTY_TM_CARDINALITY_MAX
);
1143 return (TVS_NOMATCH
);
1144 rc
= find_count_value(prop
, max
);
1150 * Ranges are represented as ASTRING values in the property at range_prop.
1151 * The minimum and maximum of the range are separated by a comma.
1153 * range_prop can contain multiple range values, so we return a pointer to
1154 * an allocated array of range_t in ranges. This array must be freed by
1155 * the caller using free(). count receives the number of range_t
1156 * structures that are allocated.
1158 * type tells us whether the range values should be treated as signed or
1159 * unsigned. It must be SCF_TYPE_COUNT or SCF_TYPE_INTEGER.
1161 static tmpl_validate_status_t
1162 get_ranges(property_t
*range_prop
, scf_type_t type
, range_t
**ranges
,
1170 *count
= uu_list_numnodes(range_prop
->sc_property_values
);
1171 assert(*count
!= 0);
1172 r
= safe_malloc(*count
* sizeof (*r
));
1174 for (value
= uu_list_first(range_prop
->sc_property_values
);
1176 value
= uu_list_next(range_prop
->sc_property_values
, value
)) {
1177 assert(value
->sc_type
== SCF_TYPE_ASTRING
);
1179 /* First get the minimum */
1181 if (type
== SCF_TYPE_INTEGER
) {
1182 r
->rng_u
.rng_signed
.rng_min
=
1183 strtoll(value
->sc_u
.sc_string
, &endptr
, 0);
1185 r
->rng_u
.rng_unsigned
.rng_min
=
1186 strtoull(value
->sc_u
.sc_string
, &endptr
, 0);
1188 if ((errno
!= 0) || (endptr
== value
->sc_u
.sc_string
))
1193 /* Now get the maximum */
1195 if (type
== SCF_TYPE_INTEGER
) {
1196 r
->rng_u
.rng_signed
.rng_max
=
1197 strtoll(endptr
, &endptr2
, 0);
1199 r
->rng_u
.rng_unsigned
.rng_max
=
1200 strtoull(endptr
, &endptr2
, 0);
1202 if ((errno
!= 0) || (endptr2
== endptr
) ||
1208 return (TVS_SUCCESS
);
1213 return (TVS_BAD_TEMPLATE
);
1216 static tv_errors_t
*
1217 tv_errors_create(const char *fmri
)
1221 ste
= safe_malloc(sizeof (*ste
));
1222 uu_list_node_init(ste
, &ste
->tve_node
, tv_errors_pool
);
1223 ste
->tve_errors
= _scf_create_errors(fmri
, 1);
1224 if (ste
->tve_errors
== NULL
)
1225 uu_die(emesg_nomem
);
1231 destroy_scf_errors(tv_errors_t
*ste
)
1233 scf_tmpl_errors_destroy(ste
->tve_errors
);
1234 uu_list_node_fini(ste
, &ste
->tve_node
, tv_errors_pool
);
1239 * Given a property group and the name of a property within that property
1240 * group, generate the name of the property group that holds the
1241 * prop_pattern information for the property. The address of the generated
1242 * name is returned to prop_pattern_pg_name. The memory holding the
1243 * generated name must be freed using uu_free().
1245 static tmpl_validate_status_t
1246 gen_prop_pattern_pg_name(pgroup_t
*pg_pattern
, const char *prop_name
,
1247 char **prop_pattern_pg_name
)
1254 limit
= scf_limit(SCF_LIMIT_MAX_NAME_LENGTH
) + 1;
1257 /* Get the unique part of the pg_pattern's property group name. */
1258 prefix_size
= strlen(SCF_PG_TM_PG_PAT_BASE
);
1259 assert(strncmp(pg_pattern
->sc_pgroup_name
, SCF_PG_TM_PG_PAT_BASE
,
1261 unique
= pg_pattern
->sc_pgroup_name
+ prefix_size
;
1263 /* Construct the prop pattern property group name. */
1264 *prop_pattern_pg_name
= NULL
;
1265 name
= uu_zalloc(limit
);
1267 uu_die(emesg_nomem
);
1268 if (snprintf(name
, limit
, "%s%s_%s", SCF_PG_TM_PROP_PATTERN_PREFIX
,
1269 unique
, prop_name
) >= limit
) {
1271 return (TVS_BAD_TEMPLATE
);
1273 *prop_pattern_pg_name
= name
;
1274 return (TVS_SUCCESS
);
1278 * Error message printing functions:
1282 * Flags for use by im_perror_item.
1284 #define IPI_NOT_FIRST 0x1 /* Not first item to be displayed. */
1287 * Print a single item of information about a validation failure. This
1288 * function takes care of printing the appropriate decoration before the
1289 * first item and between subsequent items.
1292 * out Stream to receive the output.
1293 * desc Text describing the items
1294 * item Address of the item to be displayed
1295 * type Type of the item
1296 * flags Used by im_perror_item to keep track of where it
1297 * is. Caller should set flags to 0 before calling
1298 * this function with the first item.
1301 im_perror_item(FILE *out
, const char *desc
, void *item
, scf_type_t type
,
1305 const char *first_sep
;
1307 const char *subsequent_sep
;
1310 /* Nothing to print if item is NULL. */
1314 assert(type
!= SCF_TYPE_INVALID
);
1316 /* Establish separators for environment. */
1317 if (est
->sc_cmd_flags
& SC_CMD_IACTIVE
) {
1318 /* Interactive mode - make messages readable */
1319 first_sep
= ":\n\t";
1320 subsequent_sep
= "\n\t";
1322 /* Non-interactive - one line messages. */
1324 subsequent_sep
= "; ";
1327 /* Print separator and description */
1328 if (*flags
& IPI_NOT_FIRST
) {
1329 (void) fprintf(out
, subsequent_sep
);
1331 (void) fprintf(out
, first_sep
);
1332 *flags
|= IPI_NOT_FIRST
;
1334 (void) fprintf(out
, "%s=", desc
);
1337 case SCF_TYPE_BOOLEAN
:
1338 uval
= *((uint64_t *)item
);
1340 (void) fprintf(out
, "\"%s\"", gettext("true"));
1342 (void) fprintf(out
, "\"%s\"", gettext("false"));
1345 case SCF_TYPE_COUNT
:
1346 uval
= *((uint64_t *)item
);
1347 (void) fprintf(out
, "%" PRIu64
, uval
);
1349 case SCF_TYPE_INTEGER
:
1350 ival
= *((int64_t *)item
);
1351 (void) fprintf(out
, "%" PRIi64
, ival
);
1355 * Treat everything else as a string, but escape any
1358 (void) fputc('\"', out
);
1359 cp
= (const char *)item
;
1362 (void) fprintf(out
, "\\\"");
1364 (void) fputc(*cp
, out
);
1368 (void) fputc('\"', out
);
1374 * Print erroneous FMRI.
1377 im_perror_fmri(FILE *out
, im_tmpl_error_t
*i
, int *flags
)
1379 if (i
->ite_entity
!= NULL
) {
1380 im_perror_item(out
, "FMRI", (void *)i
->ite_entity
->sc_fmri
,
1381 SCF_TYPE_FMRI
, flags
);
1386 * Print erroneous property group name.
1389 im_perror_pg_name(FILE *out
, im_tmpl_error_t
*i
, int *flags
)
1391 if (i
->ite_pg
!= NULL
) {
1392 im_perror_item(out
, gettext("Property group"),
1393 (void *)i
->ite_pg
->sc_pgroup_name
, SCF_TYPE_ASTRING
,
1399 * If srcflag is 1, print the template source of the pg_pattern or
1400 * prop_pattern at pattern. Always print the name and type of the pattern.
1403 im_perror_pattern_info(FILE *out
, pgroup_t
*pattern
, int *flags
, int srcflag
)
1406 const char *name_string
;
1407 const char *type_string
;
1409 if (pattern
== NULL
)
1411 switch (pgroup_type(pattern
)) {
1413 name_string
= gettext("pg_pattern name");
1414 type_string
= gettext("pg_pattern type");
1416 case PROP_PATTERN_PG
:
1417 name_string
= gettext("prop_pattern name");
1418 type_string
= gettext("prop_pattern type");
1425 im_perror_item(out
, gettext("Template source"),
1426 (void *)pattern
->sc_parent
->sc_fmri
, SCF_TYPE_FMRI
, flags
);
1428 c
= (void *)find_name_specification(pattern
);
1429 im_perror_item(out
, name_string
,
1430 (c
== NULL
) ? "" : c
, SCF_TYPE_ASTRING
, flags
);
1431 c
= (void *)find_type_specification(pattern
);
1432 im_perror_item(out
, type_string
,
1433 (c
== NULL
) ? "" : c
, SCF_TYPE_ASTRING
, flags
);
1437 * Print information about the template specifications that were violated,
1438 * so that the user can find the specification.
1441 im_perror_template_info(FILE *out
, im_tmpl_error_t
*i
, int *flags
)
1443 pgroup_t
*pg_pattern
= i
->ite_pg_pattern
;
1444 pgroup_t
*prop_pattern
= i
->ite_prop_pattern
;
1447 if (pg_pattern
!= NULL
) {
1448 im_perror_pattern_info(out
, pg_pattern
, flags
, srcflag
);
1451 if (prop_pattern
!= NULL
) {
1452 im_perror_pattern_info(out
, prop_pattern
, flags
, srcflag
);
1456 /* Print error message for TVS_BAD_CONVERSION errors. */
1458 im_perror_bad_conversion(FILE *out
, im_tmpl_error_t
*i
, const char *prefix
)
1462 (void) fprintf(out
, gettext("%sUnable to convert property value"),
1464 im_perror_fmri(out
, i
, &flags
);
1465 im_perror_pg_name(out
, i
, &flags
);
1466 im_perror_item(out
, gettext("Property"),
1467 (void *)i
->ite_prop
->sc_property_name
, SCF_TYPE_ASTRING
, &flags
);
1468 im_perror_template_info(out
, i
, &flags
);
1469 (void) fputc('\n', out
);
1472 /* Print error message for TVS_BAD_TEMPLATE errors. */
1474 im_perror_bad_template(FILE *out
, im_tmpl_error_t
*i
, const char *prefix
)
1478 assert(i
->ite_einfo
.ei_type
== EIT_BAD_TEMPLATE
);
1479 (void) fprintf(out
, gettext("%sInvalid template - %s"), prefix
,
1480 i
->ite_einfo
.ei_u
.ei_bad_template
.ei_reason
);
1481 im_perror_fmri(out
, i
, &flags
);
1482 im_perror_template_info(out
, i
, &flags
);
1483 (void) fputc('\n', out
);
1487 * Print error message for TVS_INVALID_TYPE_SPECIFICATION errors. This
1488 * error occurs if a prop_pattern has an invalid type specification. Thus,
1489 * it is an indication of an invalid template rather than a violation of a
1493 im_perror_invalid_type(FILE *out
, im_tmpl_error_t
*i
, const char *prefix
)
1496 const char *prop_pattern_name
;
1498 (void) fprintf(out
, gettext("%sInvalid type in prop_pattern"), prefix
);
1499 im_perror_pg_name(out
, i
, &flags
);
1500 if (i
->ite_prop_pattern
!= NULL
) {
1502 find_name_specification(i
->ite_prop_pattern
);
1503 im_perror_item(out
, gettext("prop_pattern name"),
1504 (void *)prop_pattern_name
, SCF_TYPE_ASTRING
, &flags
);
1506 im_perror_template_info(out
, i
, &flags
);
1507 (void) fputc('\n', out
);
1511 * Print error message for TVS_MISSING_PG_TYPE errors. In this case the
1512 * template specifies a type, but the property group itself has no type.
1515 im_perror_missing_pg_type(FILE *out
, im_tmpl_error_t
*i
, const char *prefix
)
1518 const char *type_spec
;
1520 (void) fprintf(out
, gettext("%sProperty group has no type"), prefix
);
1521 im_perror_fmri(out
, i
, &flags
);
1522 im_perror_pg_name(out
, i
, &flags
);
1523 if (i
->ite_pg_pattern
!= NULL
) {
1524 type_spec
= find_type_specification(i
->ite_pg_pattern
);
1525 im_perror_item(out
, gettext("Type specified in pg_pattern"),
1526 (void *)type_spec
, SCF_TYPE_ASTRING
, &flags
);
1528 (void) fputc('\n', out
);
1532 * Print error message for TVS_MISSING_TYPE_SPECIFICATION errors. A
1533 * property group has a "required" attribute of true, but it does not have
1534 * a type specification.
1537 im_perror_missing_type(FILE *out
, im_tmpl_error_t
*i
, const char *prefix
)
1540 const char *pg_pattern_name
;
1542 (void) fprintf(out
, gettext("%sPg_pattern with true required attribute "
1543 "is missing the type attribute"), prefix
);
1544 im_perror_fmri(out
, i
, &flags
);
1545 if (i
->ite_pg_pattern
!= NULL
) {
1546 pg_pattern_name
= find_name_specification(i
->ite_pg_pattern
);
1547 im_perror_item(out
, gettext("Pg_pattern name"),
1548 (void *)pg_pattern_name
, SCF_TYPE_ASTRING
, &flags
);
1550 im_perror_template_info(out
, i
, &flags
);
1551 (void) fputc('\n', out
);
1555 im_tmpl_error_print(FILE *out
, im_tmpl_error_t
*ite
, const char *prefix
)
1557 switch (ite
->ite_type
) {
1558 case TVS_BAD_CONVERSION
:
1559 im_perror_bad_conversion(out
, ite
, prefix
);
1561 case TVS_BAD_TEMPLATE
:
1562 im_perror_bad_template(out
, ite
, prefix
);
1564 case TVS_INVALID_TYPE_SPECIFICATION
:
1565 im_perror_invalid_type(out
, ite
, prefix
);
1567 case TVS_MISSING_PG_TYPE
:
1568 im_perror_missing_pg_type(out
, ite
, prefix
);
1570 case TVS_MISSING_TYPE_SPECIFICATION
:
1571 im_perror_missing_type(out
, ite
, prefix
);
1575 * TVS_NOMATCH should be handled where it occurs. Thus,
1576 * there are no error messages associated with it.
1590 int64_to_str(int64_t i
)
1597 size
= snprintf(NULL
, 0, fmt
, i
) + 1;
1598 c
= safe_malloc(size
);
1599 (void) snprintf(c
, size
, fmt
, i
);
1604 uint64_to_str(uint64_t u
)
1611 size
= snprintf(NULL
, 0, fmt
, u
) + 1;
1612 c
= safe_malloc(size
);
1613 (void) snprintf(c
, size
, fmt
, u
);
1618 * Convert the value to a string. The returned value must be freed using
1622 value_to_string(value_t
*v
)
1626 if (is_numeric_type(v
->sc_type
)) {
1627 switch (v
->sc_type
) {
1628 case SCF_TYPE_BOOLEAN
:
1629 if (v
->sc_u
.sc_count
== 0) {
1630 c
= gettext("false");
1632 c
= gettext("true");
1635 case SCF_TYPE_COUNT
:
1636 c
= uint64_to_str(v
->sc_u
.sc_count
);
1638 case SCF_TYPE_INTEGER
:
1639 c
= int64_to_str(v
->sc_u
.sc_integer
);
1642 /* unhandled numeric type */
1646 c
= v
->sc_u
.sc_string
;
1649 return (safe_strdup(c
));
1653 * Subscripts for common error data.
1655 #define ED_PG_NAME 0
1656 #define ED_PROP_NAME 1
1657 #define ED_TMPL_FMRI 2
1658 #define ED_TMPL_PG_NAME 3
1659 #define ED_TMPL_PG_TYPE 4
1660 #define ED_TMPL_PROP_NAME 5
1661 #define ED_TMPL_PROP_TYPE 6
1665 * This function converts the error information specified by the function
1666 * parameters. It converts it to form needed by _scf_tmpl_add_error().
1667 * _scf_tmpl_add_error() requires that the error information be in the form
1668 * of allocated strings that can be freed when it is done with them. Thus,
1669 * the bulk of this function is devoted to producing those allocated
1672 * Once the strings are ready, we call _scf_tmpl_add_error() to add an
1673 * new error structure to errs.
1676 add_scf_error(tmpl_errors_t
*errs
, scf_tmpl_error_type_t ec
,
1677 pgroup_t
*pg_pattern
, pgroup_t
*pg
, pgroup_t
*prop_pattern
,
1678 property_t
*prop
, value_t
*val
, error_info_t
*einfo
)
1680 const char *actual
= NULL
;
1683 const char *ed
[ED_COUNT
];
1684 const char *ev1
= NULL
;
1685 const char *ev2
= NULL
;
1687 scf_type_t prop_type
;
1690 (void) memset(ed
, 0, sizeof (ed
));
1692 /* Set values that are common to most error types. */
1694 ed
[ED_PG_NAME
] = pg
->sc_pgroup_name
;
1697 ed
[ED_PROP_NAME
] = prop
->sc_property_name
;
1699 if (pg_pattern
== NULL
) {
1700 if (prop_pattern
!= NULL
) {
1701 ed
[ED_TMPL_FMRI
] = prop_pattern
->sc_parent
->sc_fmri
;
1704 ed
[ED_TMPL_FMRI
] = pg_pattern
->sc_parent
->sc_fmri
;
1705 ed
[ED_TMPL_PG_NAME
] = find_name_specification(pg_pattern
);
1706 ed
[ED_TMPL_PG_TYPE
] = find_type_specification(pg_pattern
);
1708 if (prop_pattern
!= NULL
) {
1709 ed
[ED_TMPL_PROP_NAME
] = find_name_specification(prop_pattern
);
1710 ed
[ED_TMPL_PROP_TYPE
] = find_type_specification(prop_pattern
);
1714 * All of the strings that we've found must be strduped. This is
1715 * so that scf_tmpl_errors_destroy() can free them. We cannot use
1716 * the flag argument of _scf_create_errors() to indicate that the
1717 * strings should not be freed. The flag argument is an all or
1718 * nothing thing. In the code below we need to convert integers to
1719 * strings, and this requires memory allocation. Since we have to
1720 * allocate memory for that data, we need to allocate it for every
1723 for (i
= 0; i
< ED_COUNT
; i
++) {
1726 ed
[i
] = safe_strdup(ed
[i
]);
1729 /* actual, ev1 and ev2 are error code specific. */
1731 case SCF_TERR_CARDINALITY_VIOLATION
:
1732 assert(einfo
!= NULL
);
1733 assert(einfo
->ei_type
== EIT_CARDINALITY
);
1734 ev1
= uint64_to_str(einfo
->ei_u
.ei_cardinality
.ei_min
);
1735 ev2
= uint64_to_str(einfo
->ei_u
.ei_cardinality
.ei_max
);
1736 actual
= uint64_to_str(einfo
->ei_u
.ei_cardinality
.ei_count
);
1738 case SCF_TERR_WRONG_PG_TYPE
:
1739 /* Specified type. */
1740 if (pg_pattern
!= NULL
) {
1741 ev1
= find_type_specification(pg_pattern
);
1743 ev1
= safe_strdup(ev1
);
1748 actual
= pg
->sc_pgroup_type
;
1749 if (actual
!= NULL
) {
1750 actual
= safe_strdup(actual
);
1754 case SCF_TERR_WRONG_PROP_TYPE
:
1755 assert(einfo
->ei_type
== EIT_PROP_TYPE
);
1756 prop_type
= einfo
->ei_u
.ei_prop_type
.ei_specified
;
1757 ev1
= safe_strdup(scf_type_to_string(prop_type
));
1758 prop_type
= einfo
->ei_u
.ei_prop_type
.ei_actual
;
1759 actual
= safe_strdup(scf_type_to_string(prop_type
));
1761 case SCF_TERR_VALUE_CONSTRAINT_VIOLATED
:
1762 actual
= value_to_string(val
);
1764 case SCF_TERR_MISSING_PG
:
1765 assert(einfo
->ei_type
== EIT_MISSING_PG
);
1766 ev1
= safe_strdup(einfo
->ei_u
.ei_missing_pg
.ei_pg_name
);
1767 ev2
= safe_strdup(einfo
->ei_u
.ei_missing_pg
.ei_pg_type
);
1769 case SCF_TERR_MISSING_PROP
:
1770 assert(einfo
->ei_type
== EIT_MISSING_PROP
);
1771 ev1
= safe_strdup(einfo
->ei_u
.ei_missing_prop
.ei_prop_name
);
1773 case SCF_TERR_RANGE_VIOLATION
:
1774 assert(einfo
->ei_type
== EIT_RANGE
);
1775 if (einfo
->ei_u
.ei_range
.ei_rtype
== SCF_TYPE_COUNT
) {
1776 c
= uint64_to_str(einfo
->ei_u
.ei_range
.ei_uvalue
);
1778 c
= int64_to_str(einfo
->ei_u
.ei_range
.ei_ivalue
);
1782 case SCF_TERR_PG_PATTERN_CONFLICT
:
1783 case SCF_TERR_PROP_PATTERN_CONFLICT
:
1784 case SCF_TERR_GENERAL_REDEFINE
:
1785 assert(einfo
->ei_type
== EIT_PATTERN_CONFLICT
);
1786 conflict
= einfo
->ei_u
.ei_pattern_conflict
.ei_pattern
;
1787 ev1
= safe_strdup(conflict
->sc_parent
->sc_fmri
);
1788 ev2
= find_name_specification(conflict
);
1790 ev2
= safe_strdup(ev2
);
1791 actual
= find_type_specification(conflict
);
1793 actual
= safe_strdup(actual
);
1795 case SCF_TERR_INCLUDE_VALUES
:
1796 assert(einfo
->ei_type
== EIT_INCLUDE_VALUES
);
1797 ev1
= safe_strdup(einfo
->ei_u
.ei_inc_values
.ei_type
);
1799 case SCF_TERR_PG_PATTERN_INCOMPLETE
:
1800 case SCF_TERR_PROP_PATTERN_INCOMPLETE
:
1807 rc
= _scf_tmpl_add_error(errs
->te_cur_scf
->tve_errors
, ec
,
1808 ed
[ED_PG_NAME
], ed
[ED_PROP_NAME
], ev1
, ev2
, actual
,
1809 ed
[ED_TMPL_FMRI
], ed
[ED_TMPL_PG_NAME
], ed
[ED_TMPL_PG_TYPE
],
1810 ed
[ED_TMPL_PROP_NAME
], ed
[ED_TMPL_PROP_TYPE
]);
1816 * Create and initialize a new im_tmpl_error structure and add it to the
1817 * list of errors in errs. The rest of the parameters are used to
1818 * initialize the im_tmpl_error structure.
1820 static tmpl_validate_status_t
1821 tmpl_errors_add_im(tmpl_errors_t
*errs
, tmpl_validate_status_t ec
, entity_t
*e
,
1822 pgroup_t
*pg_pattern
, pgroup_t
*pg
, pgroup_t
*prop_pattern
,
1823 property_t
*prop
, value_t
*val
, error_info_t
*einfo
)
1825 im_tmpl_error_t
*ite
;
1828 ite
= uu_zalloc(sizeof (*ite
));
1830 uu_die(emesg_nomem
);
1831 uu_list_node_init(ite
, &ite
->ite_node
, inmem_errors_pool
);
1833 ite
->ite_entity
= e
;
1835 ite
->ite_pg_pattern
= pg_pattern
;
1836 ite
->ite_prop
= prop
;
1837 ite
->ite_prop_pattern
= prop_pattern
;
1838 ite
->ite_value
= val
;
1840 ite
->ite_einfo
= *einfo
;
1842 result
= uu_list_insert_after(errs
->te_list
, NULL
, ite
);
1843 assert(result
== 0);
1844 return (TVS_SUCCESS
);
1848 * pattern must point to a pg_pattern or a prop_pattern. This function
1849 * finds the property named required and returns the property's value. If
1850 * the property does not exist, false is return since it is the default.
1853 is_required(pgroup_t
*pattern
)
1855 property_t
*required
;
1858 assert((strcmp(pattern
->sc_pgroup_type
,
1859 SCF_GROUP_TEMPLATE_PG_PATTERN
) == 0) ||
1860 (strcmp(pattern
->sc_pgroup_type
,
1861 SCF_GROUP_TEMPLATE_PROP_PATTERN
) == 0));
1863 required
= property_find(pattern
, SCF_PROPERTY_TM_REQUIRED
);
1865 /* Default if there is no required property is false. */
1866 if (required
== NULL
)
1869 /* Retrieve the value of the required property. */
1870 value
= uu_list_first(required
->sc_property_values
);
1873 if (value
->sc_type
== SCF_TYPE_BOOLEAN
)
1874 return (value
->sc_u
.sc_count
== 0 ? 0 : 1);
1876 /* No boolean property values, so return false. */
1881 * Load the service's restarter instance and the global instance from the
1882 * repository. This will allow us to use their templates in validating the
1885 * There is no function to unload the general templates. The memory that
1886 * is allocated by load_general_templates() will be freed automatically in
1887 * internal_service_free() which is called by internal_bundle_free().
1890 load_general_templates(entity_t
*svc
)
1892 const char *restarter
;
1896 assert(svc
->sc_etype
== SVCCFG_SERVICE_OBJECT
);
1899 * If e is the global service, we only need to load the restarter.
1901 if ((strcmp(svc
->sc_fmri
, SCF_INSTANCE_GLOBAL
) == 0) ||
1902 (strcmp(svc
->sc_fmri
, SCF_SERVICE_GLOBAL
) == 0)) {
1907 * Load the templates for the service's restarter.
1909 restarter
= find_restarter(svc
);
1910 if (restarter
== NULL
)
1911 restarter
= SCF_SERVICE_STARTD
;
1912 if ((r
= load_instance(restarter
, "restarter",
1913 &svc
->sc_u
.sc_service
.sc_restarter
)) != 0) {
1915 * During initial manifest import, restarter may
1916 * not be in the repository yet. In this case we
1917 * continue on without it.
1920 warn(gettext("WARNING: restarter FMRI %s is invalid\n"),
1924 warn(gettext("WARNING: restarter FMRI %s is not valid; "
1925 "instance fmri required.\n"), restarter
);
1928 uu_die(emesg_nomem
);
1930 svc
->sc_u
.sc_service
.sc_restarter
= NULL
;
1932 if (is_global
== 0) {
1933 if ((r
= load_instance(SCF_INSTANCE_GLOBAL
, "global",
1934 &svc
->sc_u
.sc_service
.sc_global
)) != 0) {
1936 * During initial manifest import, global may not be in
1937 * the repository yet.
1940 uu_die(emesg_nomem
);
1942 svc
->sc_u
.sc_service
.sc_global
= NULL
;
1948 * Load the instance specific restarter if one is declared.
1950 * There is no corresponding unload_instance_restarter() function because
1951 * it is not needed. The memory will be freed in internal_instance_free()
1952 * when internal_bundle_free() is called.
1955 load_instance_restarter(entity_t
*i
)
1957 const char *restarter
;
1960 assert(i
->sc_etype
== SVCCFG_INSTANCE_OBJECT
);
1962 restarter
= find_restarter(i
);
1963 if (restarter
== NULL
) {
1964 /* No instance specific restarter */
1967 r
= load_instance(restarter
, "instance_restarter",
1968 &i
->sc_u
.sc_instance
.sc_instance_restarter
);
1971 * During initial manifest import, the restarter may not be
1972 * in the repository yet. In this case we continue on
1976 warn(gettext("WARNING: restarter FMRI %s is invalid\n"),
1980 warn(gettext("WARNING: restarter FMRI %s is not valid; "
1981 "instance fmri required.\n"), restarter
);
1984 uu_die(emesg_nomem
);
1989 * Find the next property after current in the property group at pg. If
1990 * the property group contains a tree of composed properties, that tree is
1991 * walked. Otherwise, we walk through the uu_list at sc_pgroup_props.
1994 next_property(pgroup_t
*pg
, property_t
*current
)
1999 cpg
= pg
->sc_pgroup_composed
;
2000 if ((cpg
!= NULL
) && (cpg
->cpg_composed_props
!= NULL
)) {
2001 /* Walk through composed property list. */
2003 prop
= uu_avl_next(cpg
->cpg_composed_props
, current
);
2005 prop
= uu_avl_first(cpg
->cpg_composed_props
);
2008 /* No composition available, so walk the list of properties */
2010 prop
= uu_list_next(pg
->sc_pgroup_props
, current
);
2012 prop
= uu_list_first(pg
->sc_pgroup_props
);
2019 static ptrn_info_t
*
2020 ptrn_info_create(pgroup_t
*pat
)
2024 composed_pg_t
*match
;
2027 info
= safe_malloc(sizeof (*info
));
2029 switch (pgroup_type(pat
)) {
2031 info
->pi_ptrn_type
= PG_PATTERN
;
2033 case PROP_PATTERN_PG
:
2034 info
->pi_ptrn_type
= PROP_PATTERN
;
2040 info
->pi_ptrnpg
= pat
;
2041 info
->pi_name
= find_name_specification(pat
);
2042 info
->pi_name
= EMPTY_TO_NULL(info
->pi_name
);
2043 info
->pi_type
= find_type_specification(pat
);
2044 info
->pi_type
= EMPTY_TO_NULL(info
->pi_type
);
2045 if (info
->pi_ptrn_type
== PG_PATTERN
) {
2046 info
->pi_target
= find_astring_value_in_pg(pat
,
2047 SCF_PROPERTY_TM_TARGET
);
2048 if (info
->pi_target
== NULL
)
2049 info
->pi_target
= SCF_TM_TARGET_THIS
;
2051 if (info
->pi_ptrn_type
== PROP_PATTERN
) {
2052 info
->pi_pgp_name
= find_astring_value_in_pg(pat
,
2053 SCF_PROPERTY_TM_PG_PATTERN
);
2054 assert((info
->pi_pgp_name
!= NULL
) &&
2055 (*(info
->pi_pgp_name
) != 0));
2058 * Find the property group that defines the pg_pattern that
2059 * holds this prop_pattern.
2062 if (e
->sc_etype
== SVCCFG_INSTANCE_OBJECT
) {
2063 (void) memset(&cpg
, 0, sizeof (cpg
));
2064 cpg
.cpg_name
= info
->pi_pgp_name
;
2065 cpg
.cpg_type
= SCF_GROUP_TEMPLATE_PG_PATTERN
;
2066 match
= uu_avl_find(e
->sc_u
.sc_instance
.sc_composed
,
2068 assert(match
!= NULL
);
2069 info
->pi_enc_pgp
= CPG2PG(match
);
2071 info
->pi_enc_pgp
= internal_pgroup_find(e
,
2072 info
->pi_pgp_name
, SCF_GROUP_TEMPLATE_PG_PATTERN
);
2074 assert(info
->pi_enc_pgp
!= NULL
);
2076 uu_avl_node_init(info
, &info
->pi_link
, ptrn_info_pool
);
2081 ptrn_info_destroy(ptrn_info_t
*info
)
2085 uu_avl_node_fini(info
, &info
->pi_link
, ptrn_info_pool
);
2090 * Walk through the property groups of the instance or service at e looking
2091 * for definitions of pg_patterns or prop_patterns as specified by type.
2092 * For each property group that matches type create a ptrn_info_t and add
2093 * it to the avl tree at tree. If duplicates are found add an error entry
2096 static tmpl_validate_status_t
2097 gather_pattern(entity_t
*e
, ptrn_type_t type
, uu_avl_t
*tree
,
2098 tmpl_errors_t
*errs
)
2101 ptrn_info_t
*info
= NULL
;
2102 uu_avl_index_t marker
;
2105 tmpl_validate_status_t rc
= TVS_SUCCESS
;
2106 const char *selector
;
2110 selector
= SCF_GROUP_TEMPLATE_PG_PATTERN
;
2113 selector
= SCF_GROUP_TEMPLATE_PROP_PATTERN
;
2120 for (pg
= uu_list_first(e
->sc_pgroups
);
2122 pg
= uu_list_next(e
->sc_pgroups
, pg
)) {
2123 if (strcmp(pg
->sc_pgroup_type
, selector
) != 0) {
2127 /* Get rid of old structure. */
2128 ptrn_info_destroy(info
);
2130 info
= ptrn_info_create(pg
);
2131 match
= uu_avl_find(tree
, info
, NULL
, &marker
);
2132 if (match
== NULL
) {
2133 /* No match. Insert the info. */
2134 uu_avl_insert(tree
, info
, marker
);
2139 /* Got a match. Determine if it is a conflict. */
2140 if ((info
->pi_name
== NULL
) ||
2141 (info
->pi_type
== NULL
) ||
2142 (match
->pi_name
== NULL
) ||
2143 (match
->pi_type
== NULL
)) {
2144 /* No conflicts if any wild cards. */
2149 * Name already matches, or we wouldn't have gotten
2150 * here. Make sure that the type also matches.
2152 if (strcmp(info
->pi_type
, match
->pi_type
) == 0) {
2157 * If we get to this point we have a conflict, and
2158 * we need to generate the correct type of error.
2160 CLEAR_ERROR_INFO(&einfo
);
2161 einfo
.ei_type
= EIT_PATTERN_CONFLICT
;
2162 einfo
.ei_u
.ei_pattern_conflict
.ei_pattern
=
2164 if (type
== PG_PATTERN
) {
2165 rc
= TVS_VALIDATION
;
2166 if (add_scf_error(errs
, SCF_TERR_PG_PATTERN_CONFLICT
,
2167 info
->pi_ptrnpg
, NULL
, NULL
, NULL
, NULL
,
2170 * If we can no longer accumulate
2171 * errors, break out of the loop.
2177 * Possible conflicting prop_pattern. See if the
2178 * prop_patterns are declared in the same
2181 if ((info
->pi_pgp_name
== NULL
) ||
2182 (match
->pi_pgp_name
== NULL
)) {
2185 if (strcmp(info
->pi_pgp_name
, match
->pi_pgp_name
) != 0)
2188 /* It is a real conflict. */
2189 rc
= TVS_VALIDATION
;
2190 if (add_scf_error(errs
, SCF_TERR_PROP_PATTERN_CONFLICT
,
2191 info
->pi_enc_pgp
, NULL
, info
->pi_ptrnpg
, NULL
, NULL
,
2194 * If we can no longer accumulate
2195 * errors, break out of the loop.
2202 ptrn_info_destroy(info
);
2207 * Free the pg_iter structure.
2210 pg_iter_destroy(pg_iter_t
*i
)
2219 * Create a property group iterator for the instance at e. This iterator
2220 * will walk through the composed property groups of the instance. It will
2221 * then step through the property groups of the instance's restarter and
2222 * finally the global service. If you wish to iterate over a specific type
2223 * of property group, set restriction to point the the desired type.
2224 * Otherwise set restriction to NULL.
2226 * The returned interator must be freed by calling pg_iter_destroy(). NULL
2227 * is returned if we are unable to allocate the necessary memory.
2230 pg_iter_create(entity_t
*e
, const char *restriction
)
2234 assert(e
->sc_etype
== SVCCFG_INSTANCE_OBJECT
);
2236 i
= uu_zalloc(sizeof (*i
));
2241 i
->pgi_restrict
= restriction
;
2242 i
->pgi_level
= TL_COMPOSED
;
2243 i
->pgi_service
= e
->sc_parent
;
2249 * Return the next property group in the iteration. NULL is returned if we
2250 * reach the end of the list. The iterator will automatically proceed from
2251 * most specific to most general levels.
2254 next_pattern_pg(pg_iter_t
*i
)
2259 uu_avl_t
*composed_tree
;
2261 assert(i
->pgi_level
!= TL_NOLEVEL
);
2263 while (i
->pgi_entity
!= NULL
) {
2264 if (i
->pgi_level
== TL_COMPOSED
) {
2266 i
->pgi_entity
->sc_u
.sc_instance
.sc_composed
;
2267 cpg
= i
->pgi_current
.pgi_cpg
;
2269 cpg
= uu_avl_first(composed_tree
);
2271 cpg
= uu_avl_next(composed_tree
, cpg
);
2277 i
->pgi_current
.pgi_cpg
= cpg
;
2280 pg
= i
->pgi_current
.pgi_pg
;
2282 pg
= uu_list_first(i
->pgi_entity
->sc_pgroups
);
2284 pg
= uu_list_next(i
->pgi_entity
->sc_pgroups
,
2287 i
->pgi_current
.pgi_pg
= pg
;
2292 * End of the list. Reset current and break out of
2295 (void) memset(&i
->pgi_current
, 0,
2296 sizeof (i
->pgi_current
));
2301 * If this iteration is for a specific type, verify that
2302 * this pg is of that type.
2304 if (i
->pgi_restrict
) {
2305 if (strcmp(pg
->sc_pgroup_type
, i
->pgi_restrict
) != 0) {
2314 * End of the list in the current level. Move up to the next
2317 switch (i
->pgi_level
) {
2319 /* Skip service if we've finished a composed instance. */
2321 if (e
->sc_u
.sc_instance
.sc_instance_restarter
== NULL
) {
2322 /* Use service restarter */
2324 i
->pgi_service
->sc_u
.sc_service
.sc_restarter
;
2326 /* Use instance restarter */
2328 e
->sc_u
.sc_instance
.sc_instance_restarter
;
2330 i
->pgi_level
= TL_RESTARTER
;
2333 i
->pgi_entity
= i
->pgi_service
->sc_u
.sc_service
.sc_global
;
2334 i
->pgi_level
= TL_GLOBAL
;
2337 i
->pgi_level
= TL_NOLEVEL
;
2344 /* Go process the next level. */
2345 return (next_pattern_pg(i
));
2349 * Compare two pattern info structures (ptrn_info_t). If both structures
2350 * have names, the comparison is based on the name. If only one has a
2351 * name, the structure with no name will be first. If neither structure
2352 * has a name, the comparison is based on their types using similar wild
2357 ptrn_info_compare(const void *left
, const void *right
, void *unused
)
2359 ptrn_info_t
*l
= (ptrn_info_t
*)left
;
2360 ptrn_info_t
*r
= (ptrn_info_t
*)right
;
2362 if ((l
->pi_name
!= NULL
) && (r
->pi_name
!= NULL
))
2363 return (strcmp(l
->pi_name
, r
->pi_name
));
2364 if ((l
->pi_name
== NULL
) && (r
->pi_name
== NULL
)) {
2365 /* No names, so we need to compare types. */
2366 if ((l
->pi_type
!= NULL
) && (r
->pi_type
!= NULL
))
2367 return (strcmp(l
->pi_type
, r
->pi_type
));
2368 if ((l
->pi_type
== NULL
) && (r
->pi_type
== NULL
))
2371 /* If we get here, exactly one of the types is NULL */
2372 if (l
->pi_type
== NULL
)
2377 /* If we get here, exactly one of the names is NULL */
2378 if (l
->pi_name
== NULL
)
2384 * The target of a pg_pattern in combination with the level at which the
2385 * pg_pattern was defined determines whether or not it should be applied.
2386 * The following combinations should be ignored, and all others should be
2391 * this TL_RESTARTER, TL_GLOBAL
2392 * "this" only applies if the pg_pattern was defined
2393 * at the instance or service level
2394 * delegate TL_INSTANCE, TL_SERVICE
2395 * Only restarters and the global service can
2397 * instance TL_INSTANCE, TL_RESTARTER, TL_GLOBAL
2398 * Only the service level can specify the "instance"
2400 * all TL_INSTANCE, TL_SERVICE, TL_RESTARTER
2401 * Only the global service can specify the "all"
2405 * 1 apply the pg_pattern
2406 * 0 ignore the pg_pattern
2409 target_check(const char *target
, tmpl_level_t level
)
2411 if ((target
== NULL
) || (*target
== 0)) {
2412 /* Default is this */
2413 target
= SCF_TM_TARGET_THIS
;
2415 if (strcmp(target
, SCF_TM_TARGET_THIS
) == 0) {
2416 if ((level
== TL_RESTARTER
) ||
2417 (level
== TL_GLOBAL
)) {
2423 if (strcmp(target
, SCF_TM_TARGET_DELEGATE
) == 0) {
2424 if ((level
== TL_INSTANCE
) ||
2425 (level
== TL_SERVICE
)) {
2431 if (strcmp(target
, SCF_TM_TARGET_INSTANCE
) == 0) {
2433 * Note that the test is inverted from the other cases.
2434 * This is because there is only one instance where apply
2435 * is the correct thing to do.
2437 if (level
== TL_SERVICE
) {
2443 if (strcmp(target
, SCF_TM_TARGET_ALL
) == 0) {
2444 if ((level
== TL_INSTANCE
) ||
2445 (level
== TL_SERVICE
) ||
2446 (level
== TL_RESTARTER
)) {
2454 pg_target_check(pgroup_t
*pg_pattern
, tmpl_level_t level
)
2458 target
= find_astring_value_in_pg(pg_pattern
, SCF_PROPERTY_TM_TARGET
);
2459 if (level
== TL_COMPOSED
) {
2460 switch (pg_pattern
->sc_parent
->sc_etype
) {
2461 case SVCCFG_INSTANCE_OBJECT
:
2462 level
= TL_INSTANCE
;
2464 case SVCCFG_SERVICE_OBJECT
:
2472 return (target_check(target
, level
));
2476 * Find the prop_pattern's type sepcification and convert it to the
2477 * appropriate scf_type.
2479 static tmpl_validate_status_t
2480 prop_pattern_type(pgroup_t
*pattern
, scf_type_t
*type
)
2482 const char *type_spec
;
2484 assert(strcmp(pattern
->sc_pgroup_type
,
2485 SCF_GROUP_TEMPLATE_PROP_PATTERN
) == 0);
2487 type_spec
= find_type_specification(pattern
);
2488 if ((type_spec
== NULL
) || (*type_spec
== 0))
2489 return (TVS_MISSING_TYPE_SPECIFICATION
);
2490 *type
= scf_string_to_type(type_spec
);
2491 return (TVS_SUCCESS
);
2495 * This function is analagous to scf_property_is_type(3SCF), but it works
2496 * on the in memory representation of the property.
2499 * 0 The property at prop does not have the specified
2501 * non-zero The property at prop does have the specified type.
2504 property_is_type(property_t
*prop
, scf_type_t type
)
2506 return (scf_is_compatible_type(type
, prop
->sc_value_type
) ==
2511 * This function generates a property group name for a template's
2512 * pg_pattern. The name and type of the pg_pattern are used to construct
2513 * the name, but either or both may be null. A pointer to the constructed
2514 * name is returned, and the referenced memory must be freed using
2515 * free(3c). NULL is returned if we are unable to allocate enough memory.
2518 gen_pg_pattern_pg_name(const char *name
, const char *type
)
2524 name_size
= scf_limit(SCF_LIMIT_MAX_NAME_LENGTH
);
2525 pg_name
= safe_malloc(name_size
);
2529 * There are four cases -- name and type are both null, name and
2530 * type are both non-null, only name is present or only type is
2533 if ((name
== NULL
) || (*name
== 0)) {
2534 if ((type
== NULL
) || (*type
== 0)) {
2536 * Name and type are both null, so the PG name
2537 * contains only the prefix.
2539 if (strlcpy(pg_name
, SCF_PG_TM_PG_PATTERN_PREFIX
,
2540 name_size
) >= name_size
) {
2545 * If we have a type and no name, the type becomes
2546 * part of the pg_pattern property group name.
2548 if (snprintf(pg_name
, name_size
, "%s%s",
2549 SCF_PG_TM_PG_PATTERN_T_PREFIX
, type
) >=
2556 * As long as the pg_pattern has a name, it becomes part of
2557 * the name of the pg_pattern property group name. We
2558 * merely need to pick the appropriate prefix.
2561 if ((type
== NULL
) || (*type
== 0)) {
2562 prefix
= SCF_PG_TM_PG_PATTERN_N_PREFIX
;
2564 prefix
= SCF_PG_TM_PG_PATTERN_NT_PREFIX
;
2566 if (snprintf(pg_name
, name_size
, "%s%s", prefix
, name
) >=
2573 /* Name was too big. */
2580 * pinfo contains information about a prop_pattern. An include_values
2581 * element with a type of type has been included in the prop_pattern
2582 * specification. We need to determine if the prop_pattern also contains
2583 * constraints or values specifications as determined by type. Thus, we
2584 * search the prop_pattern for properties whose names start with the
2587 static tmpl_validate_status_t
2588 include_values_support(ptrn_info_t
*pinfo
, const char *type
,
2589 tmpl_errors_t
*errs
)
2593 const char **prefixes
;
2598 if (strcmp(type
, "constraints") == 0) {
2599 prefixes
= constraint_prefixes
;
2600 } else if (strcmp(type
, "values") == 0) {
2601 prefixes
= value_prefixes
;
2603 CLEAR_ERROR_INFO(&einfo
);
2604 einfo
.ei_type
= EIT_BAD_TEMPLATE
;
2605 einfo
.ei_u
.ei_bad_template
.ei_reason
= gettext("include_values "
2606 "type must be \"constraints\" or \"values\"");
2607 (void) tmpl_errors_add_im(errs
, TVS_BAD_TEMPLATE
,
2608 pinfo
->pi_ptrnpg
->sc_parent
, pinfo
->pi_enc_pgp
,
2609 NULL
, pinfo
->pi_ptrnpg
, NULL
, NULL
, &einfo
);
2610 return (TVS_BAD_TEMPLATE
);
2614 * Now see if the prop_pattern has a property whose name starts
2615 * with one of these prefixes.
2617 ptrn
= pinfo
->pi_ptrnpg
;
2618 for (prop
= uu_list_first(ptrn
->sc_pgroup_props
);
2620 prop
= uu_list_next(ptrn
->sc_pgroup_props
, prop
)) {
2621 for (pfx
= prefixes
[0], i
= 0;
2623 ++i
, pfx
= prefixes
[i
]) {
2624 if (strncmp(prop
->sc_property_name
, pfx
,
2625 strlen(pfx
)) == 0) {
2626 return (TVS_SUCCESS
);
2631 /* No match found. Generate error */
2632 CLEAR_ERROR_INFO(&einfo
);
2633 einfo
.ei_type
= EIT_INCLUDE_VALUES
;
2634 einfo
.ei_u
.ei_inc_values
.ei_type
= type
;
2635 (void) add_scf_error(errs
, SCF_TERR_INCLUDE_VALUES
, pinfo
->pi_enc_pgp
,
2636 NULL
, ptrn
, NULL
, NULL
, &einfo
);
2638 return (TVS_VALIDATION
);
2642 * Walk through the prop_patterns in tree, looking for any that have an
2643 * include_values, SCF_PROPERTY_TM_CHOICES_INCLUDE_VALUES, property. For
2644 * the prop_patterns with the include values property, verify that the
2645 * prop_pattern has constraint or values declarations as specified by the
2646 * include_values property.
2648 static tmpl_validate_status_t
2649 tmpl_include_values_check(uu_avl_t
*tree
, tmpl_errors_t
*errs
)
2653 tmpl_validate_status_t r
;
2654 tmpl_validate_status_t rc
= TVS_SUCCESS
;
2657 for (info
= uu_avl_first(tree
);
2659 info
= uu_avl_next(tree
, info
)) {
2660 iv
= internal_property_find(info
->pi_ptrnpg
,
2661 SCF_PROPERTY_TM_CHOICES_INCLUDE_VALUES
);
2664 for (v
= uu_list_first(iv
->sc_property_values
);
2666 v
= uu_list_next(iv
->sc_property_values
, v
)) {
2667 assert(is_numeric_type(v
->sc_type
) == 0);
2668 r
= include_values_support(info
, v
->sc_u
.sc_string
,
2670 if (r
!= TVS_SUCCESS
)
2678 * Verify that there are no conflicting definitions of pg_pattern or
2679 * prop_pattern. Two patterns are said to be in conflict if they have the
2680 * same name and differing types. There is a caveat, however. Empty
2681 * pattern names or types are considered to be wild cards. There is no
2682 * conflict if a pattern has a wild card.
2684 static tmpl_validate_status_t
2685 tmpl_pattern_conflict(entity_t
*inst
, uu_avl_t
*tree
, ptrn_type_t type
,
2686 tmpl_errors_t
*errs
)
2688 tmpl_validate_status_t r
;
2689 tmpl_validate_status_t rc
;
2691 /* First walk the instance. */
2692 rc
= gather_pattern(inst
, type
, tree
, errs
);
2694 /* Now walk the service */
2695 r
= gather_pattern(inst
->sc_parent
, type
, tree
, errs
);
2696 if (r
!= TVS_SUCCESS
)
2702 static tmpl_validate_status_t
2703 tmpl_required_attr_present(uu_avl_t
*tree
, tmpl_errors_t
*errs
)
2706 tmpl_validate_status_t rc
= TVS_SUCCESS
;
2710 for (pinfo
= uu_avl_first(tree
);
2712 pinfo
= uu_avl_next(tree
, pinfo
)) {
2713 if (is_required(pinfo
->pi_ptrnpg
) == 0) {
2714 /* Nothing to check if pattern is not required. */
2719 * For pg_pattern both name and type are optional unless
2720 * the required attribute has a value of true. For
2721 * prop_patterns only the type is optional, but it must be
2722 * provided if the required attribute has a value of true.
2725 if ((pinfo
->pi_ptrn_type
== PG_PATTERN
) &&
2726 (pinfo
->pi_name
== NULL
)) {
2727 rc
= TVS_VALIDATION
;
2728 if (add_scf_error(errs
, SCF_TERR_PG_PATTERN_INCOMPLETE
,
2730 NULL
, NULL
, NULL
, NULL
, NULL
) != 0) {
2732 * If we're unable to report errors, break
2738 * Don't report the error twice if both name and
2739 * type are missing. One error message is
2744 if ((pinfo
->pi_type
== NULL
) && (reported_name
== 0)) {
2745 rc
= TVS_VALIDATION
;
2746 if (pinfo
->pi_ptrn_type
== PG_PATTERN
) {
2747 rv
= add_scf_error(errs
,
2748 SCF_TERR_PG_PATTERN_INCOMPLETE
,
2750 NULL
, NULL
, NULL
, NULL
, NULL
);
2752 rv
= add_scf_error(errs
,
2753 SCF_TERR_PROP_PATTERN_INCOMPLETE
,
2754 pinfo
->pi_enc_pgp
, NULL
, pinfo
->pi_ptrnpg
,
2757 /* If we're unable to log errors, break out of loop. */
2766 * Look for pg_pattern definitions in general. general is either the
2767 * restarter serivce for inst or it is the global service. tree contains
2768 * the ptrn_info_t structures describing the pg_patterns for an instance.
2769 * For each general pg_pattern, see if the instance contains an overriding
2770 * definition in tree. If it does generate an error entry.
2772 * If a redefinition is found, TVS_WARN is returned. This is because a
2773 * redefinition is not sufficient reason to inhibit the import operation.
2775 static tmpl_validate_status_t
2776 tmpl_scan_general(entity_t
*general
, uu_avl_t
*tree
,
2777 tmpl_level_t level
, tmpl_errors_t
*errs
)
2779 tmpl_level_t cur_level
;
2782 ptrn_info_t
*ginfo
= NULL
;
2784 tmpl_validate_status_t rc
= TVS_SUCCESS
;
2787 * General services may not be in repository yet. It depends on
2788 * the order that manifests are imported.
2790 if (general
== NULL
)
2791 return (TVS_SUCCESS
);
2793 for (pg
= uu_list_first(general
->sc_pgroups
);
2795 pg
= uu_list_next(general
->sc_pgroups
, pg
)) {
2796 if (strcmp(pg
->sc_pgroup_type
,
2797 SCF_GROUP_TEMPLATE_PG_PATTERN
) != 0) {
2798 /* Not a pg_pattern */
2802 ptrn_info_destroy(ginfo
);
2803 ginfo
= ptrn_info_create(pg
);
2804 match
= uu_avl_find(tree
, ginfo
, NULL
, NULL
);
2805 if (match
!= NULL
) {
2806 /* See if global pg_pattern is targeted at us. */
2807 if (target_check(ginfo
->pi_target
, level
) == 0)
2811 * See if the match applies to us. If we happen to
2812 * be a restarter, the pg_pattern could have a
2813 * target of delegate. That wouldn't apply to this
2814 * instance, it would only apply to our delegates.
2815 * Cases such as this are not a redefinition.
2817 if (match
->pi_ptrnpg
->sc_parent
->sc_etype
==
2818 SVCCFG_INSTANCE_OBJECT
) {
2819 cur_level
= TL_INSTANCE
;
2821 cur_level
= TL_SERVICE
;
2823 if (target_check(match
->pi_target
, cur_level
) == 0)
2827 * Instance or service overrides a general
2828 * definition. We need to issue a warning message.
2831 CLEAR_ERROR_INFO(&einfo
);
2832 einfo
.ei_type
= EIT_PATTERN_CONFLICT
;
2833 einfo
.ei_u
.ei_pattern_conflict
.ei_pattern
= pg
;
2834 if (add_scf_error(errs
, SCF_TERR_GENERAL_REDEFINE
,
2835 match
->pi_ptrnpg
, NULL
, NULL
, NULL
, NULL
,
2838 * No need to continue the search if we
2839 * cannot record errors.
2847 ptrn_info_destroy(ginfo
);
2852 * tree contains the pg_pattern definitions for the instance at inst. See
2853 * if these pg_patterns redefine any pg_patterns in the instance's
2854 * restarter or in the global service. TVS_WARN is returned if a
2855 * redefinition is encountered.
2857 static tmpl_validate_status_t
2858 tmpl_level_redefine(entity_t
*inst
, uu_avl_t
*tree
, tmpl_errors_t
*errs
)
2860 entity_t
*restarter
;
2861 entity_t
*svc
= inst
->sc_parent
;
2862 tmpl_validate_status_t r
;
2863 tmpl_validate_status_t rc
;
2865 restarter
= inst
->sc_u
.sc_instance
.sc_instance_restarter
;
2866 if (restarter
== NULL
) {
2867 /* No instance restarter. Use the service restarter */
2868 restarter
= svc
->sc_u
.sc_service
.sc_restarter
;
2870 rc
= tmpl_scan_general(restarter
, tree
, TL_RESTARTER
, errs
);
2871 r
= tmpl_scan_general(svc
->sc_u
.sc_service
.sc_global
, tree
,
2873 if (r
!= TVS_SUCCESS
)
2879 * Perform the following consistency checks on the template specifications
2882 * - No conflicting definitions of `pg_pattern` are allowed within a
2885 * - Templates at a narrow target (e.g. instance) which define
2886 * property groups already templated at a broad target
2887 * (e.g. restarter or all) are strongly discouraged.
2889 * - Developers may not define a template which specifies a single
2890 * prop_pattern name with differing types on the same target
2893 * - If a pg_pattern has a required attribute with a value of true,
2894 * then its name and type attributes must be specified.
2896 * - If a prop_pattern has a required attribute with a value of true,
2897 * then its type attribute must be specified.
2899 * - If a prop_pattern has an include values make sure that the
2900 * appropriate constraints or values element has also been
2903 static tmpl_validate_status_t
2904 tmpl_consistency(entity_t
*inst
, tmpl_errors_t
*errs
)
2906 void *marker
= NULL
;
2909 tmpl_validate_status_t rc
;
2910 tmpl_validate_status_t r
;
2912 /* Allocate the tree. */
2913 tree
= uu_avl_create(ptrn_info_pool
, NULL
, TMPL_DEBUG_TREE
);
2915 uu_die(gettext("pg_info tree creation failed: %s\n"),
2916 uu_strerror(uu_error()));
2919 rc
= tmpl_pattern_conflict(inst
, tree
, PG_PATTERN
, errs
);
2922 * The tree now contains the instance and service pg_patterns.
2923 * Check to see if they override any pg_pattern definitions in the
2924 * restarter and global services.
2926 r
= tmpl_level_redefine(inst
, tree
, errs
);
2927 if (r
!= TVS_SUCCESS
) {
2929 * tmpl_level_redefine() can return a warning. Don't
2930 * override a serious error with a warning.
2932 if (r
== TVS_WARN
) {
2933 if (rc
== TVS_SUCCESS
)
2941 * If the pg_pattern has a required attribute with a value of true,
2942 * then it must also have name and type attributes.
2944 r
= tmpl_required_attr_present(tree
, errs
);
2945 if (r
!= TVS_SUCCESS
)
2948 /* Empty the tree, so that we can reuse it for prop_patterns. */
2949 while ((info
= uu_avl_teardown(tree
, &marker
)) != NULL
) {
2950 ptrn_info_destroy(info
);
2953 r
= tmpl_pattern_conflict(inst
, tree
, PROP_PATTERN
, errs
);
2954 if (r
!= TVS_SUCCESS
)
2958 * If a prop_pattern has required attribute with a value of true,
2959 * then it must also have a type attribute.
2961 r
= tmpl_required_attr_present(tree
, errs
);
2962 if (r
!= TVS_SUCCESS
)
2966 * Insure that include_values have the constraint for values
2967 * elements that are needed.
2969 r
= tmpl_include_values_check(tree
, errs
);
2970 if (r
!= TVS_SUCCESS
)
2973 /* Tear down the tree. */
2975 while ((info
= uu_avl_teardown(tree
, &marker
)) != NULL
) {
2976 ptrn_info_destroy(info
);
2978 uu_avl_destroy(tree
);
2984 * Release memory associated with the tmpl_errors structure and then free
2985 * the structure itself.
2988 tmpl_errors_destroy(tmpl_errors_t
*te
)
2990 im_tmpl_error_t
*ite
;
2992 void *marker
= NULL
;
2997 while ((ite
= uu_list_teardown(te
->te_list
, &marker
)) != NULL
) {
2998 uu_list_node_fini(ite
, &ite
->ite_node
,
3002 uu_list_destroy(te
->te_list
);
3006 while ((ste
= uu_list_teardown(te
->te_scf
, &marker
)) != NULL
) {
3007 destroy_scf_errors(ste
);
3009 uu_list_destroy(te
->te_scf
);
3015 * Allocate and initialize a tmpl_errors structure. The address of the
3016 * structure is returned, unless we are unable to allocate enough memory.
3017 * In the case of memory allocation failures, NULL is returned.
3019 * The allocated structure should be freed by calling
3020 * tmpl_errors_destroy().
3022 static tmpl_errors_t
*
3023 tmpl_errors_create()
3027 te
= uu_zalloc(sizeof (*te
));
3030 te
->te_list
= uu_list_create(inmem_errors_pool
, NULL
, TMPL_DEBUG_LIST
);
3031 if (te
->te_list
== NULL
) {
3035 te
->te_scf
= uu_list_create(tv_errors_pool
, NULL
, TMPL_DEBUG_LIST
);
3036 if (te
->te_scf
== NULL
) {
3037 tmpl_errors_destroy(te
);
3045 tmpl_errors_print(FILE *out
, tmpl_errors_t
*errs
, const char *prefix
)
3047 scf_tmpl_error_t
*cur
;
3048 size_t buf_size
= 4096;
3049 im_tmpl_error_t
*ite
;
3051 scf_tmpl_errors_t
*scferrs
;
3053 int interactive
= (est
->sc_cmd_flags
& SC_CMD_IACTIVE
) ?
3054 SCF_TMPL_STRERROR_HUMAN
: 0;
3056 for (ite
= uu_list_first(errs
->te_list
);
3058 ite
= uu_list_next(errs
->te_list
, ite
)) {
3059 im_tmpl_error_print(out
, ite
, prefix
);
3062 /* Now handle the errors that can be printed via libscf. */
3063 s
= safe_malloc(buf_size
);
3064 for (scft
= uu_list_first(errs
->te_scf
);
3066 scft
= uu_list_next(errs
->te_scf
, scft
)) {
3067 scferrs
= scft
->tve_errors
;
3068 if (_scf_tmpl_error_set_prefix(scferrs
, prefix
) != 0)
3069 uu_die(emesg_nomem
);
3070 while ((cur
= scf_tmpl_next_error(scferrs
)) != NULL
) {
3071 (void) scf_tmpl_strerror(cur
, s
, buf_size
, interactive
);
3072 (void) fputs(s
, out
);
3073 (void) fputc('\n', out
);
3081 * This function finds the prop_pattern for the property, prop. e is the
3082 * instance where the search for the prop_pattern will start. pg_pattern
3083 * is the address of the pg_pattern that holds the prop_pattern.
3085 static tmpl_validate_status_t
3086 tmpl_find_prop_pattern(entity_t
*inst
, pgroup_t
*pg_pattern
,
3087 property_t
*prop
, pgroup_t
**prop_pattern
)
3089 pgroup_t
*candidate
;
3090 pg_iter_t
*iter
= NULL
;
3091 char *prop_pattern_name
= NULL
;
3092 tmpl_validate_status_t rc
;
3095 * Get the name of the property group that holds the prop_pattern
3098 rc
= gen_prop_pattern_pg_name(pg_pattern
,
3099 prop
->sc_property_name
, &prop_pattern_name
);
3100 if (rc
!= TVS_SUCCESS
)
3103 /* Find the property group. */
3104 iter
= pg_iter_create(inst
, SCF_GROUP_TEMPLATE_PROP_PATTERN
);
3107 while ((candidate
= next_pattern_pg(iter
)) != NULL
) {
3110 if (strcmp(prop_pattern_name
, candidate
->sc_pgroup_name
) != 0)
3112 c
= find_astring_value_in_pg(candidate
,
3113 SCF_PROPERTY_TM_PG_PATTERN
);
3116 if (strcmp(pg_pattern
->sc_pgroup_name
, c
) == 0)
3119 *prop_pattern
= candidate
;
3120 if (candidate
== NULL
)
3124 pg_iter_destroy(iter
);
3125 uu_free((void *)prop_pattern_name
);
3130 * Indexes for pg_pattern property group names. Indexes are arranged
3131 * from most specific to least specific.
3133 #define PGN_BOTH 0 /* both name and type */
3134 #define PGN_NAME 1 /* name only */
3135 #define PGN_TYPE 2 /* type only */
3136 #define PGN_NEITHER 3 /* neither name nor type */
3137 #define PGN_MAX 4 /* Size of array */
3140 * Given an instance entity, e, and a propety group, pg, within the
3141 * instance; return the address of the pg_pattern for the property group.
3142 * The address of the pg_pattern is placed at pgp. NULL indicates that no
3143 * pg_pattern was specified.
3145 static tmpl_validate_status_t
3146 tmpl_find_pg_pattern(entity_t
*e
, pgroup_t
*pg
, pgroup_t
**pgp
)
3148 pgroup_t
*cpg
; /* candidate property group */
3150 pg_iter_t
*iter
= NULL
;
3151 char *pg_names
[PGN_MAX
];
3152 pgroup_t
*pg_patterns
[PGN_MAX
];
3153 tmpl_validate_status_t rv
= TVS_SUCCESS
;
3155 (void) memset(pg_patterns
, 0, sizeof (pg_patterns
));
3158 /* Generate candidate names for pg_pattern property groups. */
3159 pg_names
[PGN_BOTH
] = gen_pg_pattern_pg_name(pg
->sc_pgroup_name
,
3160 pg
->sc_pgroup_type
);
3161 pg_names
[PGN_NAME
] = gen_pg_pattern_pg_name(pg
->sc_pgroup_name
,
3163 pg_names
[PGN_TYPE
] = gen_pg_pattern_pg_name(NULL
,
3164 pg
->sc_pgroup_type
);
3165 pg_names
[PGN_NEITHER
] = gen_pg_pattern_pg_name(NULL
, NULL
);
3166 for (i
= 0; i
< PGN_MAX
; i
++) {
3167 if (pg_names
[i
] == NULL
) {
3168 rv
= TVS_BAD_TEMPLATE
;
3173 /* Search for property groups that match these names */
3174 iter
= pg_iter_create(e
, SCF_GROUP_TEMPLATE_PG_PATTERN
);
3176 uu_die(emesg_nomem
);
3178 while ((cpg
= next_pattern_pg(iter
)) != NULL
) {
3179 if (pg_target_check(cpg
, iter
->pgi_level
) == 0)
3182 /* See if we have a name match. */
3183 for (i
= 0; i
< PGN_MAX
; i
++) {
3184 if (strcmp(cpg
->sc_pgroup_name
, pg_names
[i
]) == 0) {
3186 * If we already have a lower level
3187 * pg_pattern, keep it.
3189 if (pg_patterns
[i
] == NULL
)
3190 pg_patterns
[i
] = cpg
;
3196 /* Find the most specific pg_pattern. */
3197 for (i
= 0; i
< PGN_MAX
; i
++) {
3198 if (pg_patterns
[i
] != NULL
) {
3199 *pgp
= pg_patterns
[i
];
3204 for (i
= 0; i
< PGN_MAX
; i
++) {
3207 pg_iter_destroy(iter
);
3212 * Initialize structures that are required for validation using
3213 * templates specifications.
3218 emesg_nomem
= gettext("Out of memory.\n");
3220 composed_pg_pool
= uu_avl_pool_create("composed_pg",
3221 sizeof (composed_pg_t
), offsetof(composed_pg_t
, cpg_node
),
3222 composed_pg_compare
, TMPL_DEBUG_AVL_POOL
);
3223 if (composed_pg_pool
== NULL
) {
3224 uu_die(gettext("composed_pg pool creation failed: %s\n"),
3225 uu_strerror(uu_error()));
3227 composed_prop_pool
= uu_avl_pool_create("composed_prop",
3228 sizeof (property_t
), offsetof(property_t
, sc_composed_node
),
3229 composed_prop_compare
, TMPL_DEBUG_AVL_POOL
);
3230 if (composed_prop_pool
== NULL
) {
3231 uu_die(gettext("composed_prop pool creation failed. %s\n"),
3232 uu_strerror(uu_error()));
3234 ptrn_info_pool
= uu_avl_pool_create("ptrn_info", sizeof (ptrn_info_t
),
3235 offsetof(ptrn_info_t
, pi_link
), ptrn_info_compare
,
3236 TMPL_DEBUG_AVL_POOL
);
3237 if (ptrn_info_pool
== NULL
) {
3238 uu_die(gettext("pg_pattern info pool creation failed: %s\n"),
3239 uu_strerror(uu_error()));
3241 inmem_errors_pool
= uu_list_pool_create("errors-internal",
3242 sizeof (im_tmpl_error_t
), offsetof(im_tmpl_error_t
,
3243 ite_node
), NULL
, TMPL_DEBUG_LIST_POOL
);
3244 if (inmem_errors_pool
== NULL
) {
3245 uu_die(gettext("inmem_errors_pool pool creation failed: "
3246 "%s\n"), uu_strerror(uu_error()));
3248 tv_errors_pool
= uu_list_pool_create("scf-terrors",
3249 sizeof (tv_errors_t
), offsetof(tv_errors_t
, tve_node
),
3250 NULL
, TMPL_DEBUG_LIST_POOL
);
3251 if (tv_errors_pool
== NULL
) {
3252 uu_die(gettext("tv_errors_pool pool creation failed: %s\n"),
3253 uu_strerror(uu_error()));
3258 * Clean up the composed property node in the property.
3261 tmpl_property_fini(property_t
*p
)
3263 uu_avl_node_fini(p
, &p
->sc_composed_node
, composed_prop_pool
);
3267 * Initialize the composed property node in the property.
3270 tmpl_property_init(property_t
*p
)
3272 uu_avl_node_init(p
, &p
->sc_composed_node
, composed_prop_pool
);
3276 * Use the cardinality specification in the prop_pattern to verify the
3277 * cardinality of the property at prop. The cardinality of the property is
3278 * the number of values that it has.
3280 * pg is the property group that holds prop, and pg_pattern is the
3281 * pg_pattern for the property group. pg and pg_pattern are only used for
3284 static tmpl_validate_status_t
3285 tmpl_validate_cardinality(pgroup_t
*prop_pattern
, property_t
*prop
,
3286 pgroup_t
*pg
, pgroup_t
*pg_pattern
, tmpl_errors_t
*errs
)
3291 tmpl_validate_status_t rc
;
3294 assert(strcmp(prop_pattern
->sc_pgroup_type
,
3295 SCF_GROUP_TEMPLATE_PROP_PATTERN
) == 0);
3297 rc
= get_cardinality(prop_pattern
, &min
, &max
);
3300 /* Nothing to check. */
3301 return (TVS_SUCCESS
);
3303 /* Process the limits. */
3309 if ((min
== 0) && (max
== ULLONG_MAX
)) {
3310 /* Any number of values is permitted. No need to count. */
3311 return (TVS_SUCCESS
);
3314 count
= count_prop_values(prop
);
3315 if ((count
< min
) || (count
> max
)) {
3316 CLEAR_ERROR_INFO(&einfo
);
3317 einfo
.ei_type
= EIT_CARDINALITY
;
3318 einfo
.ei_u
.ei_cardinality
.ei_min
= min
;
3319 einfo
.ei_u
.ei_cardinality
.ei_max
= max
;
3320 einfo
.ei_u
.ei_cardinality
.ei_count
= count
;
3321 (void) add_scf_error(errs
, SCF_TERR_CARDINALITY_VIOLATION
,
3322 pg_pattern
, pg
, prop_pattern
, prop
, NULL
, &einfo
);
3323 return (TVS_VALIDATION
);
3326 return (TVS_SUCCESS
);
3330 * Iterate over pg_patterns in the entity, e. If the pg_pattern's required
3331 * attribute is true, verify that the entity contains the corresponding
3334 static tmpl_validate_status_t
3335 tmpl_required_pg_present(entity_t
*e
, tmpl_errors_t
*errs
)
3338 composed_pg_t
*match
;
3342 const char *pg_name
;
3343 const char *pg_type
;
3344 tmpl_validate_status_t rc
= TVS_SUCCESS
;
3347 assert(e
->sc_etype
== SVCCFG_INSTANCE_OBJECT
);
3349 iter
= pg_iter_create(e
, SCF_GROUP_TEMPLATE_PG_PATTERN
);
3351 uu_die(emesg_nomem
);
3353 CLEAR_ERROR_INFO(&einfo
);
3354 einfo
.ei_type
= EIT_MISSING_PG
;
3356 while ((pg
= next_pattern_pg(iter
)) != NULL
) {
3357 if (is_required(pg
) == 0) {
3358 /* If pg is not required, there is nothing to check. */
3361 pg_name
= find_astring_value_in_pg(pg
, SCF_PROPERTY_TM_NAME
);
3362 pg_type
= find_astring_value_in_pg(pg
, SCF_PROPERTY_TM_TYPE
);
3363 if (pg_target_check(pg
, iter
->pgi_level
) == 0)
3365 einfo
.ei_u
.ei_missing_pg
.ei_pg_name
= pg_name
;
3366 einfo
.ei_u
.ei_missing_pg
.ei_pg_type
= pg_type
;
3367 tree
= e
->sc_u
.sc_instance
.sc_composed
;
3368 (void) memset(&cpg
, 0, sizeof (cpg
));
3369 cpg
.cpg_name
= pg_name
;
3370 cpg
.cpg_type
= pg_type
;
3371 match
= uu_avl_find(tree
, &cpg
, NULL
, NULL
);
3372 if (match
== NULL
) {
3373 rc
= TVS_VALIDATION
;
3374 if (add_scf_error(errs
, SCF_TERR_MISSING_PG
, pg
,
3375 NULL
, NULL
, NULL
, NULL
, &einfo
) != 0) {
3381 pg_iter_destroy(iter
);
3386 * Verify that the property group, pg, contains property declarations for
3387 * all required properties. Unfortunately, there is no direct way to find
3388 * the prop_patterns for a given property group. Therefore, we need to
3389 * scan the entity at e looking for property groups with a type of
3390 * SCF_GROUP_TEMPLATE_PROP_PATTERN. That is, we scan the entity looking
3391 * for all prop_patterns. When we find a prop_pattern, we look at the
3392 * value of its pg_pattern property to see if it matches the name of the
3393 * pg_pattern. If they match, this is a prop_pattern that is of interest
3396 * When we find an interesting prop_pattern, we see if it's required
3397 * property is true. If it is, we verify that the property group at pg
3398 * contains the specified property.
3400 static tmpl_validate_status_t
3401 tmpl_required_props_present(entity_t
*e
, pgroup_t
*pg
, pgroup_t
*pg_pattern
,
3402 tmpl_errors_t
*errs
)
3406 const char *prop_name
;
3407 const char *prop_pg_pattern_name
;
3408 pgroup_t
*prop_pattern
;
3409 scf_tmpl_error_type_t ec
;
3410 tmpl_validate_status_t rc
= TVS_SUCCESS
;
3413 * Scan the entity's property groups looking for ones with a type
3414 * of SCF_GROUP_TEMPLATE_PROP_PATTERN.
3416 iter
= pg_iter_create(e
, SCF_GROUP_TEMPLATE_PROP_PATTERN
);
3418 uu_die(emesg_nomem
);
3419 CLEAR_ERROR_INFO(&einfo
);
3420 for (prop_pattern
= next_pattern_pg(iter
);
3421 prop_pattern
!= NULL
;
3422 prop_pattern
= next_pattern_pg(iter
)) {
3424 * Find the pg_pattern property in this prop_pattern.
3425 * Verify that its value matches the name of the
3428 prop_pg_pattern_name
= find_astring_value_in_pg(prop_pattern
,
3429 SCF_PROPERTY_TM_PG_PATTERN
);
3430 assert(prop_pg_pattern_name
!= NULL
);
3431 if (strcmp(pg_pattern
->sc_pgroup_name
,
3432 prop_pg_pattern_name
) != 0) {
3436 /* If the property is required, see if it is in the pg. */
3437 if (is_required(prop_pattern
) == 0)
3439 prop_name
= find_astring_value_in_pg(prop_pattern
,
3440 SCF_PROPERTY_TM_NAME
);
3441 assert(prop_name
!= NULL
);
3442 if (property_find(pg
, prop_name
) == NULL
) {
3443 ec
= SCF_TERR_MISSING_PROP
;
3444 rc
= TVS_VALIDATION
;
3445 einfo
.ei_type
= EIT_MISSING_PROP
;
3446 einfo
.ei_u
.ei_missing_prop
.ei_prop_name
= prop_name
;
3447 if (add_scf_error(errs
, ec
, pg_pattern
, pg
,
3448 prop_pattern
, NULL
, NULL
, &einfo
) != 0) {
3450 * If we can no longer accumulate errors,
3451 * break out of the loop.
3458 pg_iter_destroy(iter
);
3463 * Check the value at v to see if it falls within any of the ranges at r.
3464 * count is the number of ranges at r, and type tells whether to treat the
3465 * value as signed or unsigned.
3467 * Return 1 if the value falls within one of the ranges. Otherwise return
3471 value_in_range(value_t
*v
, scf_type_t type
, range_t
*r
, size_t count
)
3473 for (; count
> 0; --count
, r
++) {
3474 if (type
== SCF_TYPE_COUNT
) {
3475 if ((v
->sc_u
.sc_count
>=
3476 r
->rng_u
.rng_unsigned
.rng_min
) &&
3477 (v
->sc_u
.sc_count
<=
3478 r
->rng_u
.rng_unsigned
.rng_max
))
3481 if ((v
->sc_u
.sc_integer
>=
3482 r
->rng_u
.rng_signed
.rng_min
) &&
3483 (v
->sc_u
.sc_integer
<=
3484 r
->rng_u
.rng_signed
.rng_max
))
3492 * If the template prop_pattern at pattern contains a constraint_range
3493 * property, use the specified range to validate all the numeric property
3494 * values of the property at prop.
3496 * pg is the property group that holds prop, and pg_pattern is the
3497 * pg_pattern for the property group. pg and pg_pattern are only used for
3500 static tmpl_validate_status_t
3501 tmpl_validate_value_range(pgroup_t
*pattern
, property_t
*prop
, pgroup_t
*pg
,
3502 pgroup_t
*pg_pattern
, tmpl_errors_t
*errs
)
3506 property_t
*range_prop
;
3508 tmpl_validate_status_t rc
;
3512 /* Get the range constraints if they exist. */
3513 if ((range_prop
= property_find(pattern
,
3514 SCF_PROPERTY_TM_CONSTRAINT_RANGE
)) == NULL
) {
3515 /* No range to check. */
3516 return (TVS_SUCCESS
);
3518 type
= prop
->sc_value_type
;
3519 if ((type
!= SCF_TYPE_COUNT
) && (type
!= SCF_TYPE_INTEGER
)) {
3520 rc
= TVS_BAD_TEMPLATE
;
3521 CLEAR_ERROR_INFO(&einfo
);
3522 einfo
.ei_type
= EIT_BAD_TEMPLATE
;
3523 einfo
.ei_u
.ei_bad_template
.ei_reason
=
3524 gettext("Property does not have correct type for "
3525 "a range specification");
3526 (void) tmpl_errors_add_im(errs
, rc
, pg_pattern
->sc_parent
,
3527 pg_pattern
, pg
, pattern
, prop
, NULL
, &einfo
);
3530 if ((rc
= get_ranges(range_prop
, prop
->sc_value_type
, &ranges
,
3531 &count
)) != TVS_SUCCESS
) {
3532 rc
= TVS_BAD_TEMPLATE
;
3533 CLEAR_ERROR_INFO(&einfo
);
3534 einfo
.ei_type
= EIT_BAD_TEMPLATE
;
3535 einfo
.ei_u
.ei_bad_template
.ei_reason
= gettext("Illegal range "
3537 (void) tmpl_errors_add_im(errs
, rc
, pg_pattern
->sc_parent
,
3538 pg_pattern
, pg
, pattern
, prop
, NULL
, &einfo
);
3542 /* Set up error info before entering loop. */
3543 CLEAR_ERROR_INFO(&einfo
);
3544 einfo
.ei_type
= EIT_RANGE
;
3545 einfo
.ei_u
.ei_range
.ei_rtype
= type
;
3547 /* Compare numeric values of the property to the range. */
3548 for (v
= uu_list_first(prop
->sc_property_values
);
3550 v
= uu_list_next(prop
->sc_property_values
, v
)) {
3551 if (value_in_range(v
, type
, ranges
, count
) == 1)
3553 if (type
== SCF_TYPE_COUNT
) {
3554 einfo
.ei_u
.ei_range
.ei_uvalue
= v
->sc_u
.sc_count
;
3556 einfo
.ei_u
.ei_range
.ei_ivalue
= v
->sc_u
.sc_integer
;
3558 rc
= TVS_VALIDATION
;
3559 if (add_scf_error(errs
, SCF_TERR_RANGE_VIOLATION
, pg_pattern
,
3560 pg
, pattern
, prop
, v
, &einfo
) != 0) {
3569 * If the prop_pattern has value constraints, verify that all the values
3570 * for the property at prop are legal values.
3572 * pg is the property group that holds prop, and pg_pattern is the
3573 * pg_pattern for the property group. pg and pg_pattern are only used for
3576 static tmpl_validate_status_t
3577 tmpl_validate_values(pgroup_t
*prop_pattern
, property_t
*prop
, pgroup_t
*pg
,
3578 pgroup_t
*pg_pattern
, tmpl_errors_t
*errs
)
3583 tmpl_validate_status_t r
;
3584 tmpl_validate_status_t rc
= TVS_SUCCESS
;
3587 /* Get list of legal values. */
3588 r
= av_get_values(prop_pattern
, SCF_PROPERTY_TM_CONSTRAINT_NAME
,
3589 prop
->sc_value_type
, &legal
);
3591 case TVS_BAD_CONVERSION
:
3592 (void) tmpl_errors_add_im(errs
, r
, pg
->sc_parent
, pg_pattern
,
3593 pg
, prop_pattern
, prop
, NULL
, NULL
);
3596 /* No constraints in template. */
3597 return (TVS_SUCCESS
);
3599 /* process the constraints. */
3606 /* Check the property values against the legal values. */
3607 for (v
= uu_list_first(prop
->sc_property_values
);
3609 v
= uu_list_next(prop
->sc_property_values
, v
)) {
3610 /* Check this property value against the legal values. */
3612 for (i
= 0; (i
< legal
->av_count
) && (found
== 0); i
++) {
3613 switch (v
->sc_type
) {
3614 case SCF_TYPE_BOOLEAN
:
3615 case SCF_TYPE_COUNT
:
3616 if (av_get_unsigned(legal
, i
) ==
3621 case SCF_TYPE_INTEGER
:
3622 if (av_get_integer(legal
, i
) ==
3623 v
->sc_u
.sc_integer
) {
3628 if (strcmp(av_get_string(legal
, i
),
3629 v
->sc_u
.sc_string
) == 0) {
3636 rc
= TVS_VALIDATION
;
3637 if (add_scf_error(errs
,
3638 SCF_TERR_VALUE_CONSTRAINT_VIOLATED
, pg_pattern
, pg
,
3639 prop_pattern
, prop
, v
, NULL
) != 0) {
3641 * Exit loop if no longer able to report
3655 * Verify the following items about the values of property, prop.
3657 * - The values all have the type specified by the prop_pattern at
3659 * - Check numeric values against range constraints.
3660 * - If the prop_pattern has one or more value constraints, validate
3661 * the property's values against the constraints.
3663 * pg is the property group that holds prop, and pg_pattern is the
3664 * pg_pattern for the property group. pg and pg_pattern are only used for
3667 static tmpl_validate_status_t
3668 tmpl_validate_value_constraints(pgroup_t
*pattern
, property_t
*prop
,
3669 pgroup_t
*pg
, pgroup_t
*pg_pattern
, tmpl_errors_t
*errs
)
3671 tmpl_validate_status_t r
;
3672 tmpl_validate_status_t rc
;
3674 rc
= tmpl_validate_value_range(pattern
, prop
, pg
, pg_pattern
, errs
);
3675 r
= tmpl_validate_values(pattern
, prop
, pg
, pg_pattern
, errs
);
3676 if (r
!= TVS_SUCCESS
)
3683 * Perform the following validations on the property, prop.
3685 * - Verify that the property's type agrees with the type specified in
3686 * the prop_pattern template, tmpl.
3687 * - Verify the cardinality.
3688 * - Verify that the property values satisfy the constraints specified
3691 * pg is the property group that holds prop, and pg_pattern is the
3692 * pg_pattern for the property group. pg and pg_pattern are only used for
3695 static tmpl_validate_status_t
3696 tmpl_validate_prop(property_t
*prop
, pgroup_t
*tmpl
, pgroup_t
*pg
,
3697 pgroup_t
*pg_pattern
, tmpl_errors_t
*errs
)
3699 scf_tmpl_error_type_t ec
;
3701 tmpl_validate_status_t r
;
3702 tmpl_validate_status_t rc
= TVS_SUCCESS
;
3706 r
= prop_pattern_type(tmpl
, &type
);
3709 if (type
== SCF_TYPE_INVALID
) {
3710 rc
= TVS_INVALID_TYPE_SPECIFICATION
;
3711 r
= tmpl_errors_add_im(errs
, rc
, pg
->sc_parent
, NULL
,
3712 pg
, tmpl
, NULL
, NULL
, NULL
);
3713 if (r
!= TVS_SUCCESS
) {
3715 * Give up if we can no longer accumulate
3721 if (property_is_type(prop
, type
) == 0) {
3722 CLEAR_ERROR_INFO(&einfo
);
3723 rc
= TVS_VALIDATION
;
3724 ec
= SCF_TERR_WRONG_PROP_TYPE
;
3725 einfo
.ei_type
= EIT_PROP_TYPE
;
3726 einfo
.ei_u
.ei_prop_type
.ei_specified
= type
;
3727 einfo
.ei_u
.ei_prop_type
.ei_actual
=
3728 prop
->sc_value_type
;
3729 status
= add_scf_error(errs
, ec
,
3730 pg_pattern
, pg
, tmpl
, prop
, NULL
, &einfo
);
3733 * Give up if we can no longer
3734 * accumulate errors.
3741 case TVS_MISSING_TYPE_SPECIFICATION
:
3743 * A null type specification means that we do not need to
3744 * check the property's type.
3751 /* Validate the cardinality */
3752 r
= tmpl_validate_cardinality(tmpl
, prop
, pg
, pg_pattern
, errs
);
3753 if (r
!= TVS_SUCCESS
)
3756 /* Validate that property values satisfy constraints. */
3757 r
= tmpl_validate_value_constraints(tmpl
, prop
, pg
, pg_pattern
, errs
);
3758 if (r
!= TVS_SUCCESS
)
3765 * Validate the property group at pg by performing the following checks:
3767 * - Verify that the types of the pg and the pg_pattern are
3769 * - Verify the properties in the pg.
3770 * - Verify that required properties are present.
3772 static tmpl_validate_status_t
3773 tmpl_validate_pg(entity_t
*e
, pgroup_t
*pg
, tmpl_errors_t
*errs
)
3776 const char *pg_pattern_type
; /* Type declared by pg_pattern. */
3777 pgroup_t
*pg_pattern
; /* Prop. group for pg_pattern */
3779 pgroup_t
*prop_pattern
;
3780 tmpl_validate_status_t r
;
3781 tmpl_validate_status_t rc
= TVS_SUCCESS
;
3785 * See if there is a pg_pattern for this property group. If it
3786 * exists, use it to validate the property group. If there is no
3787 * pg_pattern, then there is no validation to do.
3789 rc
= tmpl_find_pg_pattern(e
, pg
, &pg_pattern
);
3793 case TVS_BAD_TEMPLATE
:
3794 CLEAR_ERROR_INFO(&einfo
);
3795 einfo
.ei_type
= EIT_BAD_TEMPLATE
;
3796 einfo
.ei_u
.ei_bad_template
.ei_reason
= gettext("Property "
3797 "group name too long");
3798 (void) tmpl_errors_add_im(errs
, rc
, e
, NULL
, pg
, NULL
, NULL
,
3805 if (pg_pattern
== NULL
)
3806 return (TVS_SUCCESS
);
3809 * If the pg_pattern declares a type, verify that the PG has the
3812 pg_pattern_type
= find_type_specification(pg_pattern
);
3813 if ((pg_pattern_type
!= NULL
) &&
3814 (*pg_pattern_type
!= 0)) {
3815 if ((pg
->sc_pgroup_type
!= NULL
) &&
3816 (*(pg
->sc_pgroup_type
) != 0)) {
3817 if (strcmp(pg_pattern_type
,
3818 pg
->sc_pgroup_type
) != 0) {
3819 rc
= TVS_VALIDATION
;
3820 stat
= add_scf_error(errs
,
3821 SCF_TERR_WRONG_PG_TYPE
, pg_pattern
, pg
,
3822 NULL
, NULL
, NULL
, NULL
);
3825 * If we can no longer accumulate
3826 * errors, return without trying to
3827 * do further validation.
3833 rc
= TVS_MISSING_PG_TYPE
;
3834 r
= tmpl_errors_add_im(errs
, rc
, e
, pg_pattern
, pg
,
3835 NULL
, NULL
, NULL
, NULL
);
3836 if (r
!= TVS_SUCCESS
) {
3838 * If we can no longer accumulate errors,
3839 * return without trying to do further
3847 /* Verify the properties in the property group. */
3849 while ((prop
= next_property(pg
, prop
)) != NULL
) {
3850 r
= tmpl_find_prop_pattern(e
, pg_pattern
, prop
, &prop_pattern
);
3853 /* Found match. Validate property. */
3856 /* No prop_patern. Go on to next property. */
3858 case TVS_BAD_TEMPLATE
:
3859 CLEAR_ERROR_INFO(&einfo
);
3860 einfo
.ei_type
= EIT_BAD_TEMPLATE
;
3861 einfo
.ei_u
.ei_bad_template
.ei_reason
=
3862 gettext("prop_pattern name too long");
3863 (void) tmpl_errors_add_im(errs
, r
, e
, NULL
, pg
, NULL
,
3864 NULL
, NULL
, &einfo
);
3870 r
= tmpl_validate_prop(prop
, prop_pattern
, pg
, pg_pattern
,
3872 if (r
!= TVS_SUCCESS
)
3877 * Confirm required properties are present.
3879 r
= tmpl_required_props_present(e
, pg
, pg_pattern
, errs
);
3880 if (r
!= TVS_SUCCESS
)
3887 * Validate that the property groups in the entity conform to the template
3888 * specifications. Specifically, this means do the following:
3890 * - Loop through the property groups in the entity skipping the ones
3891 * that are of type "template".
3893 * - For the PG search for the corresponding template_pg_pattern
3894 * property group. It is possible that one may not exist.
3896 * - Verify that the PG is in conformance with the pg_pattern
3897 * specification if it exists.
3899 static tmpl_validate_status_t
3900 tmpl_validate_entity_pgs(entity_t
*e
, tmpl_errors_t
*errs
)
3905 tmpl_validate_status_t r
;
3906 tmpl_validate_status_t rc
= TVS_SUCCESS
;
3908 assert(e
->sc_etype
== SVCCFG_INSTANCE_OBJECT
);
3910 pgroups
= e
->sc_u
.sc_instance
.sc_composed
;
3911 for (cpg
= uu_avl_first(pgroups
);
3913 cpg
= uu_avl_next(pgroups
, cpg
)) {
3914 if (strcmp(cpg
->cpg_type
, SCF_GROUP_TEMPLATE
) == 0)
3917 if ((r
= tmpl_validate_pg(e
, pg
, errs
)) != TVS_SUCCESS
)
3925 * Validate the instance, e, by performing the following checks:
3927 * - Verify template consistency.
3929 * - Validate each property group in the entity is in conformance
3930 * with the template specifications.
3932 * - Verify that all required property groups are present in the
3935 static tmpl_validate_status_t
3936 tmpl_validate_instance(entity_t
*e
, tmpl_errors_t
*errs
)
3938 tmpl_validate_status_t r
;
3939 tmpl_validate_status_t rc
= TVS_SUCCESS
;
3943 /* Prepare to collect errors for this instance. */
3944 ste
= tv_errors_create(e
->sc_fmri
);
3945 status
= uu_list_insert_after(errs
->te_scf
, errs
->te_cur_scf
, ste
);
3946 assert(status
== 0);
3947 errs
->te_cur_scf
= ste
;
3949 /* Verify template consistency */
3950 rc
= tmpl_consistency(e
, errs
);
3952 /* Validate the property groups in the entity. */
3953 r
= tmpl_validate_entity_pgs(e
, errs
);
3954 if (r
!= TVS_SUCCESS
)
3957 /* Verify that all required property groups are present. */
3958 r
= tmpl_required_pg_present(e
, errs
);
3959 if (r
!= TVS_SUCCESS
)
3966 * First validate the instances of the service.
3968 static tmpl_validate_status_t
3969 tmpl_validate_service(entity_t
*svc
, tmpl_errors_t
*errs
)
3972 tmpl_validate_status_t r
;
3973 tmpl_validate_status_t rc
= TVS_SUCCESS
;
3975 assert(svc
->sc_etype
== SVCCFG_SERVICE_OBJECT
);
3977 load_general_templates(svc
);
3979 /* Validate the service's instances. */
3980 for (inst
= uu_list_first(svc
->sc_u
.sc_service
.sc_service_instances
);
3982 inst
= uu_list_next(svc
->sc_u
.sc_service
.sc_service_instances
,
3984 load_instance_restarter(inst
);
3985 build_composed_instance(inst
);
3986 r
= tmpl_validate_instance(inst
, errs
);
3987 if (r
!= TVS_SUCCESS
)
3989 demolish_composed_instance(inst
);
3996 * Validate all services and instances in the bundle against their
3997 * templates. If err_list is not NULL, a tmpl_errors structure will be
3998 * allocated and its address will be returned to err_list. This structure
3999 * can be used to generate error messages.
4001 tmpl_validate_status_t
4002 tmpl_validate_bundle(bundle_t
*bndl
, tmpl_errors_t
**err_list
)
4004 tmpl_errors_t
*errs
= NULL
;
4006 tmpl_validate_status_t r
;
4007 tmpl_validate_status_t rc
= TVS_SUCCESS
;
4009 if (err_list
!= NULL
)
4011 if (bndl
->sc_bundle_type
!= SVCCFG_MANIFEST
) {
4012 semerr(gettext("Bundle is not a manifest. Unable to validate "
4013 "against templates.\n"));
4017 errs
= tmpl_errors_create();
4019 uu_die(emesg_nomem
);
4021 lscf_prep_hndl(); /* Initialize g_hndl */
4022 if (load_init() != 0)
4023 uu_die(emesg_nomem
);
4026 * We will process all services in the bundle, unless we get a
4027 * fatal error. That way we can report all errors on all services
4028 * on a single run of svccfg.
4030 for (svc
= uu_list_first(bndl
->sc_bundle_services
);
4032 svc
= uu_list_next(bndl
->sc_bundle_services
, svc
)) {
4033 if (svc
->sc_etype
!= SVCCFG_SERVICE_OBJECT
) {
4034 semerr(gettext("Manifest for %s contains an object "
4035 "named \"%s\" that is not a service.\n"),
4036 bndl
->sc_bundle_name
, svc
->sc_name
);
4037 tmpl_errors_destroy(errs
);
4041 if ((r
= tmpl_validate_service(svc
, errs
)) != TVS_SUCCESS
)
4047 if (err_list
== NULL
) {
4048 tmpl_errors_destroy(errs
);