svccfg: remove -Wno-unitialized
[unleashed/lotheac.git] / usr / src / cmd / svc / svccfg / svccfg_tmpl.c
blob13a0aa06c284a397b42774ee70c2dd84fe9a22ec
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
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
56 * target entity.
57 * D. If a pg_pattern has a required attribute with a value of
58 * true, then its name and type attributes must be
59 * specified.
60 * E. If a prop_pattern has a required attribute with a value
61 * of true, then its type attribute must be specified.
62 * F. If a prop_pattern has an include_values element make sure
63 * that the appropriate constraints or values element has
64 * also been declared.
65 * 2. Validate that each property group in the instance is in
66 * conformance with the template specifications.
67 * A. Verify that the types of the PG and the pg_pattern are
68 * compatible.
69 * B. Verify properties of the PG against the prop_patterns in
70 * the template.
71 * o Verify property's type.
72 * o Verify cardinality.
73 * o Vefiy that property values satisfy the constraints
74 * imposed by the prop_pattern.
75 * C. Verify that required properties are present.
76 * 3. Verify that all required property groups are present in the
77 * insance.
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.
90 * Subsystems:
91 * ==========
93 * General Templates:
94 * -----------------
95 * In order to perform the validation specified by 1.B above, we need to
96 * load the templates specifications for the global service and the
97 * instance's restarter. This information is loaded from the repository
98 * and it is held in memory using the entity_t, pgroup_t, property_t and
99 * value_t hierarchy of structures. When a service is processed,
100 * load_general_templates() is called to load the information for the
101 * global service and restarter that is declared at the service level. The
102 * sc_service.sc_global and sc_service.sc_restarter members of the
103 * service's entity_t point to the information for the global and restarter
104 * services.
106 * The instance portion of a manifest can declare an instance specific
107 * restarter. If this is the case, load_instance_restarter() will load the
108 * information for that restarter, and it is saved in the
109 * sc_instance.sc_instance_restarter member of the entity_t that represents
110 * the instance.
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.
148 * Error Reporting:
149 * ---------------
150 * While performing the templates validation checks, svccfg collects
151 * information for all the errors that it finds. Because of this you will
152 * see many places in the code where a loop is not exited when an error is
153 * encountered. We note that fact that an error has occurred, but continue
154 * in the loop to see if there are more validation errors. The error code
155 * of the last error that is encountered is returned. This works, because
156 * the callers of tmpl_validate_bundle() only look to see whether or not
157 * the return code is TVS_SUCCESS.
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
196 * information.
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.
206 #include <assert.h>
207 #include <errno.h>
208 #include <inttypes.h>
209 #include <libintl.h>
210 #include <limits.h>
211 #include <libscf.h>
212 #include <libscf_priv.h>
213 #include <stdio.h>
214 #include <stdlib.h>
215 #include <strings.h>
216 #include "svccfg.h"
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 : \
227 cpg->cpg_service_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. */
235 #ifdef NDEBUG
236 #define TMPL_DEBUG_AVL_POOL UU_DEFAULT
237 #define TMPL_DEBUG_LIST UU_DEFAULT
238 #define TMPL_DEBUG_LIST_POOL UU_DEFAULT
239 #define TMPL_DEBUG_TREE UU_DEFAULT
240 #else
241 #define TMPL_DEBUG_AVL_POOL UU_AVL_POOL_DEBUG
242 #define TMPL_DEBUG_LIST UU_LIST_DEBUG
243 #define TMPL_DEBUG_LIST_POOL UU_LIST_POOL_DEBUG
244 #define TMPL_DEBUG_TREE UU_AVL_DEBUG
245 #endif /* NDEBUG */
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 */
273 } err_info_type_t;
276 * Structure to hold information that will be used in generating error
277 * messages.
279 typedef struct error_info {
280 err_info_type_t ei_type; /* Type of information stored here */
281 union {
282 /* EIT_BAD_TEMPLATE */
283 struct {
284 const char *ei_reason;
285 } ei_bad_template;
286 /* EIT_CARDINALITY */
287 struct {
288 uint64_t ei_min;
289 uint64_t ei_max;
290 uint64_t ei_count; /* Number of prop values */
291 } ei_cardinality;
292 /* EIT_INCLUDE_VALUES */
293 struct {
294 const char *ei_type;
295 } ei_inc_values;
296 /* EIT_MISSING_PG */
297 struct {
298 const char *ei_pg_name; /* Name of missing pg */
299 const char *ei_pg_type; /* Type of missing pg */
300 } ei_missing_pg;
301 /* EIT_MISSING_PROP */
302 struct {
303 const char *ei_prop_name; /* Name of prop */
304 } ei_missing_prop;
305 /* EIT_PATTERN_CONFLICT */
306 struct {
307 pgroup_t *ei_pattern; /* Conficting pattern */
308 } ei_pattern_conflict;
309 /* EIT_PROP_TYPE */
310 struct {
311 scf_type_t ei_actual;
312 scf_type_t ei_specified;
313 } ei_prop_type;
314 /* EIT_RANGE */
315 struct {
316 scf_type_t ei_rtype;
317 int64_t ei_ivalue;
318 uint64_t ei_uvalue;
319 } ei_range;
320 } ei_u;
321 } error_info_t;
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. */
339 } im_tmpl_error_t;
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. */
348 } tv_errors_t;
351 * Structure to collect template validation errors.
353 struct tmpl_errors {
354 uu_list_t *te_list; /* List of im_tmpl_error_t */
355 im_tmpl_error_t *te_next; /* Next error to present */
356 uu_list_t *te_scf; /* Errors for scf_tmpl_strerror() */
357 tv_errors_t *te_cur_scf; /* Current member of te_scf */
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 {
366 NORMAL_PG,
367 PG_PATTERN_PG,
368 PROP_PATTERN_PG
369 } pg_type_t;
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 */
381 union {
382 uint64_t *av_unsigned; /* Count & boolean values */
383 int64_t *av_integer; /* Integer values */
384 const char **av_string; /* String values */
385 } av_v; /* Container for the values */
386 } avalues_t;
389 * composed_pg_t contains the information that is needed to compose a
390 * property group. See the section on Composed Properties in the block
391 * comment at the beginning of this file. The composed_pg structures are
392 * linked into a uu_avl tree. The tree is at sc_instance.sc_composed in
393 * the entity_t.
395 struct composed_pg {
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;
421 size_t pp_size;
422 } prop_prefix_t;
425 * Store a legal range for a property allowing for either signed or
426 * unsigned ranges. It is used to store a range from a template
427 * constraint element of a prop_pattern. The structure is returned by
428 * get_ranges() and is used by value_in_range() to validate the values of a
429 * property.
431 typedef struct range {
432 union {
433 struct {
434 uint64_t rng_min;
435 uint64_t rng_max;
436 } rng_unsigned;
437 struct {
438 int64_t rng_min;
439 int64_t rng_max;
440 } rng_signed;
441 } rng_u;
442 } range_t;
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. */
455 } tmpl_level_t;
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. */
469 union {
470 pgroup_t *pgi_pg;
471 composed_pg_t *pgi_cpg;
472 } pgi_current; /* Current property group. */
473 } pg_iter_t;
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 {
480 PG_PATTERN,
481 PROP_PATTERN
482 } ptrn_type_t;
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 */
502 /* PROP_PATTERN. */
503 uu_avl_node_t pi_link; /* Linkage into AVL tree */
504 } ptrn_info_t;
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,
539 NULL
541 static const char *value_prefixes[] = {
542 SCF_PROPERTY_TM_VALUE_PREFIX,
543 NULL
547 * Function to compare two composed_pg structures.
549 /* ARGSUSED2 */
550 static int
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;
555 int rc;
557 if ((rc = strcmp(l->cpg_name, r->cpg_name)) == 0) {
558 rc = strcmp(l->cpg_type, r->cpg_type);
560 return (rc);
563 /* ARGSUSED2 */
564 static int
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 *
574 composed_pg_create()
576 composed_pg_t *cpg;
578 cpg = safe_malloc(sizeof (*cpg));
579 uu_avl_node_init(cpg, &cpg->cpg_node, composed_pg_pool);
580 return (cpg);
583 static void
584 composed_pg_destroy(composed_pg_t *cpg)
586 void *marker = NULL;
587 pgroup_t *pg;
589 if (cpg == NULL)
590 return;
591 /* Tear down composed property tree if we have one. */
592 if ((cpg->cpg_composed_props != NULL)) {
593 while (uu_avl_teardown(cpg->cpg_composed_props, &marker) !=
594 NULL) {
596 * Nothing to do other than getting the property
597 * out of the list. This cleans up the property's
598 * uu_avl_node.
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);
612 free(cpg);
616 * Walk the property group at pg, and add its properties to the AVL tree at
617 * tree.
619 static void
620 grow_props_tree(pgroup_t *pg, uu_avl_t *tree)
622 uu_avl_index_t marker;
623 property_t *prop;
625 for (prop = uu_list_first(pg->sc_pgroup_props);
626 prop != NULL;
627 prop = uu_list_next(pg->sc_pgroup_props, prop)) {
628 if (uu_avl_find(tree, prop, NULL, &marker) == NULL) {
630 * If there was no match, insert the property into
631 * the tree. If we do get a match, there is
632 * nothing to do. That is because we rely on our
633 * caller to process the instance properties first,
634 * and the instance properties override the service
635 * properties.
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.
647 static void
648 compose_props(composed_pg_t *cpg)
650 uu_avl_t *tree;
652 tree = uu_avl_create(composed_prop_pool, cpg, TMPL_DEBUG_TREE);
653 if (tree == NULL) {
654 uu_die(gettext("composed_pool tree creation failed: %s\n"),
655 uu_strerror(uu_error()));
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
663 * NULL.
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().
681 static void
682 build_composed_property_groups(entity_t *inst, uu_avl_t *tree)
684 composed_pg_t *cpg;
685 uu_avl_index_t marker;
686 composed_pg_t *match;
687 pgroup_t *pg;
688 entity_t *svc;
690 /* First capture the instance property groups. */
691 for (pg = uu_list_first(inst->sc_pgroups);
692 pg != NULL;
693 pg = uu_list_next(inst->sc_pgroups, pg)) {
694 cpg = composed_pg_create();
695 cpg->cpg_name = pg->sc_pgroup_name;
696 cpg->cpg_type = pg->sc_pgroup_type;
697 cpg->cpg_instance_pg = pg;
698 match = uu_avl_find(tree, cpg, NULL, &marker);
699 /* Since we do the instance first, there should be no match. */
700 assert(match == NULL);
701 uu_avl_insert(tree, cpg, marker);
702 pg->sc_pgroup_composed = cpg;
705 /* Now capture the service property groups. */
706 svc = inst->sc_parent;
707 cpg = NULL;
708 for (pg = uu_list_first(svc->sc_pgroups);
709 pg != NULL;
710 pg = uu_list_next(svc->sc_pgroups, pg)) {
711 if (cpg == NULL)
712 cpg = composed_pg_create();
713 cpg->cpg_name = pg->sc_pgroup_name;
714 cpg->cpg_type = pg->sc_pgroup_type;
715 cpg->cpg_service_pg = pg;
716 match = uu_avl_find(tree, cpg, NULL, &marker);
717 if (match == NULL) {
718 uu_avl_insert(tree, cpg, marker);
719 /* Get new composed_pg_t next at top of loop. */
720 cpg = NULL;
721 } else {
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);
731 if (cpg != NULL)
732 composed_pg_destroy(cpg);
735 static void
736 build_composed_instance(entity_t *inst)
738 uu_avl_t *tree;
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);
744 if (tree == NULL) {
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);
754 static void
755 demolish_composed_instance(entity_t *inst)
757 composed_pg_t *cpg;
758 void *marker = NULL;
759 uu_avl_t *tree;
761 tree = inst->sc_u.sc_instance.sc_composed;
762 if (tree == NULL)
763 return;
765 marker = NULL;
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.
776 static size_t
777 count_prop_values(property_t *prop)
779 return (uu_list_numnodes(prop->sc_property_values));
782 static int
783 is_numeric_type(scf_type_t type)
785 if (type == SCF_TYPE_BOOLEAN)
786 return (1);
787 if (type == SCF_TYPE_COUNT)
788 return (1);
789 if (type == SCF_TYPE_INTEGER)
790 return (1);
791 return (0);
794 static pg_type_t
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);
801 return (NORMAL_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
808 * will be searched.
810 static property_t *
811 property_find(pgroup_t *pg, const char *name)
813 composed_pg_t *cpg;
814 property_t look;
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
825 * the AVL tree.
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.
839 static void
840 av_destroy(avalues_t *av)
842 if (av == NULL)
843 return;
844 switch (av->av_type) {
845 case SCF_TYPE_BOOLEAN:
846 case SCF_TYPE_COUNT:
847 uu_free(av->av_v.av_unsigned);
848 break;
849 case SCF_TYPE_INTEGER:
850 uu_free(av->av_v.av_integer);
851 break;
852 default:
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);
859 break;
861 uu_free(av);
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.
873 static avalues_t *
874 av_create(size_t count, scf_type_t type)
876 uint_t alloc_failed = 0;
877 avalues_t *av;
879 av = uu_zalloc(sizeof (*av));
880 if (av == NULL)
881 return (NULL);
882 av->av_count = count;
883 av->av_type = type;
884 switch (type) {
885 case SCF_TYPE_BOOLEAN:
886 case SCF_TYPE_COUNT:
887 av->av_v.av_unsigned = uu_zalloc(count * sizeof (uint64_t));
888 if (av->av_v.av_unsigned == NULL)
889 alloc_failed = 1;
890 break;
891 case SCF_TYPE_INTEGER:
892 av->av_v.av_integer = uu_zalloc(count * sizeof (int64_t));
893 if (av->av_v.av_integer == NULL)
894 alloc_failed = 1;
895 break;
896 default:
897 av->av_v.av_string = uu_zalloc(count * sizeof (char *));
898 if (av->av_v.av_string == NULL)
899 alloc_failed = 1;
901 if (alloc_failed) {
902 av_destroy(av);
903 return (NULL);
905 return (av);
909 * Return the ith integer value in av.
911 static int64_t
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.
922 static const char *
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.
933 static uint64_t
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)
950 char *endptr;
951 int64_t n;
952 uint64_t un;
954 if (is_numeric_type(av->av_type)) {
955 switch (av->av_type) {
956 case SCF_TYPE_BOOLEAN:
957 case SCF_TYPE_COUNT:
958 un = strtoull(value, &endptr, 0);
959 if ((endptr == value) || (*endptr != 0)) {
960 return (TVS_BAD_CONVERSION);
962 *(av->av_v.av_unsigned + i) = un;
963 break;
964 case SCF_TYPE_INTEGER:
965 n = strtoll(value, &endptr, 0);
966 if ((endptr == value) || (*endptr != 0)) {
967 return (TVS_BAD_CONVERSION);
969 *(av->av_v.av_integer + i) = n;
971 } else {
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,
992 avalues_t **values)
994 avalues_t *av;
995 uint_t i;
996 property_t *prop;
997 tmpl_validate_status_t rc;
998 value_t *v;
1000 prop = property_find(pg, prop_name);
1001 if (prop == NULL) {
1002 return (TVS_NOMATCH);
1004 assert(prop->sc_value_type == SCF_TYPE_ASTRING);
1005 av = av_create(count_prop_values(prop), type);
1006 if (av == NULL)
1007 uu_die(emesg_nomem);
1009 /* Collect the values. */
1010 for ((v = uu_list_first(prop->sc_property_values)), i = 0;
1011 v != NULL;
1012 (v = uu_list_next(prop->sc_property_values, v)), i++) {
1013 assert(i < av->av_count);
1014 assert(v->sc_type == SCF_TYPE_ASTRING);
1015 rc = av_set_value(av, i, v->sc_u.sc_string);
1016 if (rc != TVS_SUCCESS) {
1017 av_destroy(av);
1018 return (rc);
1021 *values = av;
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.
1032 static const char *
1033 find_astring_value_in_pg(pgroup_t *pg, const char *prop_name)
1035 property_t *prop;
1036 value_t *v;
1038 prop = property_find(pg, prop_name);
1039 if (prop == NULL)
1040 return (NULL);
1041 if (prop->sc_value_type != SCF_TYPE_ASTRING)
1042 return (NULL);
1043 v = uu_list_first(prop->sc_property_values);
1044 if (v == NULL)
1045 return (NULL);
1046 assert(v->sc_type == SCF_TYPE_ASTRING);
1047 return (v->sc_u.sc_string);
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)
1056 value_t *value;
1058 assert(prop->sc_value_type == SCF_TYPE_COUNT);
1059 value = uu_list_first(prop->sc_property_values);
1060 if (value == NULL)
1061 return (TVS_NOMATCH);
1062 *count = value->sc_u.sc_count;
1063 return (TVS_SUCCESS);
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.
1071 static const char *
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
1080 * prop_pattern.
1082 static const char *
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.
1092 static const char *
1093 find_restarter(entity_t *e)
1095 pgroup_t *pg;
1096 property_t *prop;
1097 value_t *v;
1099 pg = internal_pgroup_find(e, scf_pg_general, scf_group_framework);
1100 if (pg != NULL) {
1101 prop = property_find(pg, SCF_PROPERTY_RESTARTER);
1102 if ((prop != NULL) && (prop->sc_value_type == SCF_TYPE_FMRI)) {
1103 v = uu_list_first(prop->sc_property_values);
1104 if (v != NULL)
1105 return (v->sc_u.sc_string);
1110 * Didn't find the restarter.
1112 return (NULL);
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
1121 * missing.
1123 static tmpl_validate_status_t
1124 get_cardinality(pgroup_t *prop_pattern, uint64_t *min, uint64_t *max)
1126 property_t *prop;
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);
1134 if (prop == NULL)
1135 return (TVS_NOMATCH);
1136 rc = find_count_value(prop, min);
1137 if (rc != TVS_SUCCESS)
1138 return (rc);
1140 prop = property_find(prop_pattern,
1141 SCF_PROPERTY_TM_CARDINALITY_MAX);
1142 if (prop == NULL)
1143 return (TVS_NOMATCH);
1144 rc = find_count_value(prop, max);
1146 return (rc);
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,
1163 uint_t *count)
1165 char *endptr;
1166 char *endptr2;
1167 range_t *r;
1168 value_t *value;
1170 *count = uu_list_numnodes(range_prop->sc_property_values);
1171 assert(*count != 0);
1172 r = safe_malloc(*count * sizeof (*r));
1173 *ranges = r;
1174 for (value = uu_list_first(range_prop->sc_property_values);
1175 value != NULL;
1176 value = uu_list_next(range_prop->sc_property_values, value)) {
1177 assert(value->sc_type == SCF_TYPE_ASTRING);
1179 /* First get the minimum */
1180 errno = 0;
1181 if (type == SCF_TYPE_INTEGER) {
1182 r->rng_u.rng_signed.rng_min =
1183 strtoll(value->sc_u.sc_string, &endptr, 0);
1184 } else {
1185 r->rng_u.rng_unsigned.rng_min =
1186 strtoull(value->sc_u.sc_string, &endptr, 0);
1188 if ((errno != 0) || (endptr == value->sc_u.sc_string))
1189 goto badtemplate;
1190 if (*endptr != ',')
1191 goto badtemplate;
1193 /* Now get the maximum */
1194 endptr++;
1195 if (type == SCF_TYPE_INTEGER) {
1196 r->rng_u.rng_signed.rng_max =
1197 strtoll(endptr, &endptr2, 0);
1198 } else {
1199 r->rng_u.rng_unsigned.rng_max =
1200 strtoull(endptr, &endptr2, 0);
1202 if ((errno != 0) || (endptr2 == endptr) ||
1203 (*endptr2 != 0))
1204 goto badtemplate;
1205 r++;
1208 return (TVS_SUCCESS);
1210 badtemplate:
1211 free(*ranges);
1212 *ranges = NULL;
1213 return (TVS_BAD_TEMPLATE);
1216 static tv_errors_t *
1217 tv_errors_create(const char *fmri)
1219 tv_errors_t *ste;
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);
1227 return (ste);
1230 static void
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);
1235 free(ste);
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)
1249 ssize_t limit;
1250 char *name;
1251 size_t prefix_size;
1252 const char *unique;
1254 limit = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
1255 assert(limit > 0);
1257 /* Get the unique part of the pg_pattern's property group name. */
1258 prefix_size = strlen(SCF_PG_TM_PG_PAT_BASE);
1259 assert(strncmp(pg_pattern->sc_pgroup_name, SCF_PG_TM_PG_PAT_BASE,
1260 prefix_size) == 0);
1261 unique = pg_pattern->sc_pgroup_name + prefix_size;
1263 /* Construct the prop pattern property group name. */
1264 *prop_pattern_pg_name = NULL;
1265 name = uu_zalloc(limit);
1266 if (name == NULL)
1267 uu_die(emesg_nomem);
1268 if (snprintf(name, limit, "%s%s_%s", SCF_PG_TM_PROP_PATTERN_PREFIX,
1269 unique, prop_name) >= limit) {
1270 uu_free(name);
1271 return (TVS_BAD_TEMPLATE);
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.
1291 * Parameters:
1292 * out Stream to receive the output.
1293 * desc Text describing the items
1294 * item Address of the item to be displayed
1295 * type Type of the item
1296 * flags Used by im_perror_item to keep track of where it
1297 * is. Caller should set flags to 0 before calling
1298 * this function with the first item.
1300 static void
1301 im_perror_item(FILE *out, const char *desc, void *item, scf_type_t type,
1302 int *flags)
1304 const char *cp;
1305 const char *first_sep;
1306 int64_t ival;
1307 const char *subsequent_sep;
1308 uint64_t uval;
1310 /* Nothing to print if item is NULL. */
1311 if (item == NULL)
1312 return;
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";
1321 } else {
1322 /* Non-interactive - one line messages. */
1323 first_sep = ": ";
1324 subsequent_sep = "; ";
1327 /* Print separator and description */
1328 if (*flags & IPI_NOT_FIRST) {
1329 (void) fprintf(out, subsequent_sep);
1330 } else {
1331 (void) fprintf(out, first_sep);
1332 *flags |= IPI_NOT_FIRST;
1334 (void) fprintf(out, "%s=", desc);
1336 switch (type) {
1337 case SCF_TYPE_BOOLEAN:
1338 uval = *((uint64_t *)item);
1339 if (uval) {
1340 (void) fprintf(out, "\"%s\"", gettext("true"));
1341 } else {
1342 (void) fprintf(out, "\"%s\"", gettext("false"));
1344 break;
1345 case SCF_TYPE_COUNT:
1346 uval = *((uint64_t *)item);
1347 (void) fprintf(out, "%" PRIu64, uval);
1348 break;
1349 case SCF_TYPE_INTEGER:
1350 ival = *((int64_t *)item);
1351 (void) fprintf(out, "%" PRIi64, ival);
1352 break;
1353 default:
1355 * Treat everything else as a string, but escape any
1356 * internal quotes.
1358 (void) fputc('\"', out);
1359 cp = (const char *)item;
1360 while (*cp != 0) {
1361 if (*cp == '\"') {
1362 (void) fprintf(out, "\\\"");
1363 } else {
1364 (void) fputc(*cp, out);
1366 cp++;
1368 (void) fputc('\"', out);
1369 break;
1374 * Print erroneous FMRI.
1376 static void
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.
1388 static void
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,
1394 flags);
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.
1402 static void
1403 im_perror_pattern_info(FILE *out, pgroup_t *pattern, int *flags, int srcflag)
1405 void *c;
1406 const char *name_string;
1407 const char *type_string;
1409 if (pattern == NULL)
1410 return;
1411 switch (pgroup_type(pattern)) {
1412 case PG_PATTERN_PG:
1413 name_string = gettext("pg_pattern name");
1414 type_string = gettext("pg_pattern type");
1415 break;
1416 case PROP_PATTERN_PG:
1417 name_string = gettext("prop_pattern name");
1418 type_string = gettext("prop_pattern type");
1419 break;
1420 default:
1421 assert(0);
1422 abort();
1424 if (srcflag) {
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.
1440 static void
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;
1445 int srcflag = 1;
1447 if (pg_pattern != NULL) {
1448 im_perror_pattern_info(out, pg_pattern, flags, srcflag);
1449 srcflag = 0;
1451 if (prop_pattern != NULL) {
1452 im_perror_pattern_info(out, prop_pattern, flags, srcflag);
1456 /* Print error message for TVS_BAD_CONVERSION errors. */
1457 static void
1458 im_perror_bad_conversion(FILE *out, im_tmpl_error_t *i, const char *prefix)
1460 int flags = 0;
1462 (void) fprintf(out, gettext("%sUnable to convert property value"),
1463 prefix);
1464 im_perror_fmri(out, i, &flags);
1465 im_perror_pg_name(out, i, &flags);
1466 im_perror_item(out, gettext("Property"),
1467 (void *)i->ite_prop->sc_property_name, SCF_TYPE_ASTRING, &flags);
1468 im_perror_template_info(out, i, &flags);
1469 (void) fputc('\n', out);
1472 /* Print error message for TVS_BAD_TEMPLATE errors. */
1473 static void
1474 im_perror_bad_template(FILE *out, im_tmpl_error_t *i, const char *prefix)
1476 int flags = 0;
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
1490 * template.
1492 static void
1493 im_perror_invalid_type(FILE *out, im_tmpl_error_t *i, const char *prefix)
1495 int flags = 0;
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) {
1501 prop_pattern_name =
1502 find_name_specification(i->ite_prop_pattern);
1503 im_perror_item(out, gettext("prop_pattern name"),
1504 (void *)prop_pattern_name, SCF_TYPE_ASTRING, &flags);
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.
1514 static void
1515 im_perror_missing_pg_type(FILE *out, im_tmpl_error_t *i, const char *prefix)
1517 int flags = 0;
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.
1536 static void
1537 im_perror_missing_type(FILE *out, im_tmpl_error_t *i, const char *prefix)
1539 int flags = 0;
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);
1554 static void
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);
1560 break;
1561 case TVS_BAD_TEMPLATE:
1562 im_perror_bad_template(out, ite, prefix);
1563 break;
1564 case TVS_INVALID_TYPE_SPECIFICATION:
1565 im_perror_invalid_type(out, ite, prefix);
1566 break;
1567 case TVS_MISSING_PG_TYPE:
1568 im_perror_missing_pg_type(out, ite, prefix);
1569 break;
1570 case TVS_MISSING_TYPE_SPECIFICATION:
1571 im_perror_missing_type(out, ite, prefix);
1572 break;
1573 case TVS_NOMATCH:
1575 * TVS_NOMATCH should be handled where it occurs. Thus,
1576 * there are no error messages associated with it.
1578 assert(0);
1579 abort();
1580 break;
1581 case TVS_SUCCESS:
1582 break;
1583 default:
1584 assert(0);
1585 abort();
1589 static char *
1590 int64_to_str(int64_t i)
1592 char *c;
1593 const char *fmt;
1594 int size;
1596 fmt = "%" PRIi64;
1597 size = snprintf(NULL, 0, fmt, i) + 1;
1598 c = safe_malloc(size);
1599 (void) snprintf(c, size, fmt, i);
1600 return (c);
1603 static char *
1604 uint64_to_str(uint64_t u)
1606 char *c;
1607 const char *fmt;
1608 int size;
1610 fmt = "%" PRIu64;
1611 size = snprintf(NULL, 0, fmt, u) + 1;
1612 c = safe_malloc(size);
1613 (void) snprintf(c, size, fmt, u);
1614 return (c);
1618 * Convert the value to a string. The returned value must be freed using
1619 * free(3C).
1621 static const char *
1622 value_to_string(value_t *v)
1624 char *c;
1626 if (is_numeric_type(v->sc_type)) {
1627 switch (v->sc_type) {
1628 case SCF_TYPE_BOOLEAN:
1629 if (v->sc_u.sc_count == 0) {
1630 c = gettext("false");
1631 } else {
1632 c = gettext("true");
1634 break;
1635 case SCF_TYPE_COUNT:
1636 c = uint64_to_str(v->sc_u.sc_count);
1637 return (c);
1638 case SCF_TYPE_INTEGER:
1639 c = int64_to_str(v->sc_u.sc_integer);
1640 return (c);
1641 default:
1642 /* unhandled numeric type */
1643 abort();
1645 } else {
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
1662 #define ED_COUNT 7
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
1670 * strings.
1672 * Once the strings are ready, we call _scf_tmpl_add_error() to add an
1673 * new error structure to errs.
1675 static int
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;
1681 char *c;
1682 pgroup_t *conflict;
1683 const char *ed[ED_COUNT];
1684 const char *ev1 = NULL;
1685 const char *ev2 = NULL;
1686 int i;
1687 scf_type_t prop_type;
1688 int rc;
1690 (void) memset(ed, 0, sizeof (ed));
1692 /* Set values that are common to most error types. */
1693 if (pg != NULL) {
1694 ed[ED_PG_NAME] = pg->sc_pgroup_name;
1696 if (prop != NULL) {
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;
1703 } else {
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
1721 * thing.
1723 for (i = 0; i < ED_COUNT; i++) {
1724 if (ed[i] == NULL)
1725 continue;
1726 ed[i] = safe_strdup(ed[i]);
1729 /* actual, ev1 and ev2 are error code specific. */
1730 switch (ec) {
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);
1737 break;
1738 case SCF_TERR_WRONG_PG_TYPE:
1739 /* Specified type. */
1740 if (pg_pattern != NULL) {
1741 ev1 = find_type_specification(pg_pattern);
1742 if (ev1 != NULL) {
1743 ev1 = safe_strdup(ev1);
1746 /* Actual type. */
1747 if (pg != NULL) {
1748 actual = pg->sc_pgroup_type;
1749 if (actual != NULL) {
1750 actual = safe_strdup(actual);
1753 break;
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));
1760 break;
1761 case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
1762 actual = value_to_string(val);
1763 break;
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);
1768 break;
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);
1772 break;
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);
1777 } else {
1778 c = int64_to_str(einfo->ei_u.ei_range.ei_ivalue);
1780 actual = c;
1781 break;
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);
1789 if (ev2 != NULL)
1790 ev2 = safe_strdup(ev2);
1791 actual = find_type_specification(conflict);
1792 if (actual != NULL)
1793 actual = safe_strdup(actual);
1794 break;
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);
1798 break;
1799 case SCF_TERR_PG_PATTERN_INCOMPLETE:
1800 case SCF_TERR_PROP_PATTERN_INCOMPLETE:
1801 break;
1802 default:
1803 assert(0);
1804 abort();
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]);
1812 return (rc);
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;
1826 int result;
1828 ite = uu_zalloc(sizeof (*ite));
1829 if (ite == NULL)
1830 uu_die(emesg_nomem);
1831 uu_list_node_init(ite, &ite->ite_node, inmem_errors_pool);
1832 ite->ite_type = ec;
1833 ite->ite_entity = e;
1834 ite->ite_pg = pg;
1835 ite->ite_pg_pattern = pg_pattern;
1836 ite->ite_prop = prop;
1837 ite->ite_prop_pattern = prop_pattern;
1838 ite->ite_value = val;
1839 if (einfo != NULL)
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.
1852 static int
1853 is_required(pgroup_t *pattern)
1855 property_t *required;
1856 value_t *value;
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)
1867 return (0);
1869 /* Retrieve the value of the required property. */
1870 value = uu_list_first(required->sc_property_values);
1871 if (value == NULL)
1872 return (0);
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. */
1877 return (0);
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
1883 * service.
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().
1889 static void
1890 load_general_templates(entity_t *svc)
1892 const char *restarter;
1893 int is_global = 0;
1894 int r;
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)) {
1903 is_global = 1;
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.
1919 if (r == EINVAL)
1920 warn(gettext("WARNING: restarter FMRI %s is invalid\n"),
1921 restarter);
1923 if (r == ENOTSUP)
1924 warn(gettext("WARNING: restarter FMRI %s is not valid; "
1925 "instance fmri required.\n"), restarter);
1927 if (r == ENOMEM)
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.
1939 if (r == ENOMEM)
1940 uu_die(emesg_nomem);
1941 else
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.
1954 static void
1955 load_instance_restarter(entity_t *i)
1957 const char *restarter;
1958 int r;
1960 assert(i->sc_etype == SVCCFG_INSTANCE_OBJECT);
1962 restarter = find_restarter(i);
1963 if (restarter == NULL) {
1964 /* No instance specific restarter */
1965 return;
1967 r = load_instance(restarter, "instance_restarter",
1968 &i->sc_u.sc_instance.sc_instance_restarter);
1969 if (r != 0) {
1971 * During initial manifest import, the restarter may not be
1972 * in the repository yet. In this case we continue on
1973 * without it.
1975 if (r == EINVAL)
1976 warn(gettext("WARNING: restarter FMRI %s is invalid\n"),
1977 restarter);
1979 if (r == ENOTSUP)
1980 warn(gettext("WARNING: restarter FMRI %s is not valid; "
1981 "instance fmri required.\n"), restarter);
1983 if (r == ENOMEM)
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.
1993 static property_t *
1994 next_property(pgroup_t *pg, property_t *current)
1996 composed_pg_t *cpg;
1997 property_t *prop;
1999 cpg = pg->sc_pgroup_composed;
2000 if ((cpg != NULL) && (cpg->cpg_composed_props != NULL)) {
2001 /* Walk through composed property list. */
2002 if (current) {
2003 prop = uu_avl_next(cpg->cpg_composed_props, current);
2004 } else {
2005 prop = uu_avl_first(cpg->cpg_composed_props);
2007 } else {
2008 /* No composition available, so walk the list of properties */
2009 if (current) {
2010 prop = uu_list_next(pg->sc_pgroup_props, current);
2011 } else {
2012 prop = uu_list_first(pg->sc_pgroup_props);
2016 return (prop);
2019 static ptrn_info_t *
2020 ptrn_info_create(pgroup_t *pat)
2022 entity_t *e;
2023 ptrn_info_t *info;
2024 composed_pg_t *match;
2025 composed_pg_t cpg;
2027 info = safe_malloc(sizeof (*info));
2029 switch (pgroup_type(pat)) {
2030 case PG_PATTERN_PG:
2031 info->pi_ptrn_type = PG_PATTERN;
2032 break;
2033 case PROP_PATTERN_PG:
2034 info->pi_ptrn_type = PROP_PATTERN;
2035 break;
2036 default:
2037 assert(0);
2038 abort();
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.
2061 e = pat->sc_parent;
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,
2067 &cpg, NULL, NULL);
2068 assert(match != NULL);
2069 info->pi_enc_pgp = CPG2PG(match);
2070 } else {
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);
2077 return (info);
2080 static void
2081 ptrn_info_destroy(ptrn_info_t *info)
2083 if (info == NULL)
2084 return;
2085 uu_avl_node_fini(info, &info->pi_link, ptrn_info_pool);
2086 free(info);
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
2094 * to errs.
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)
2100 error_info_t einfo;
2101 ptrn_info_t *info = NULL;
2102 uu_avl_index_t marker;
2103 ptrn_info_t *match;
2104 pgroup_t *pg;
2105 tmpl_validate_status_t rc = TVS_SUCCESS;
2106 const char *selector;
2108 switch (type) {
2109 case PG_PATTERN:
2110 selector = SCF_GROUP_TEMPLATE_PG_PATTERN;
2111 break;
2112 case PROP_PATTERN:
2113 selector = SCF_GROUP_TEMPLATE_PROP_PATTERN;
2114 break;
2115 default:
2116 assert(0);
2117 abort();
2120 for (pg = uu_list_first(e->sc_pgroups);
2121 pg != NULL;
2122 pg = uu_list_next(e->sc_pgroups, pg)) {
2123 if (strcmp(pg->sc_pgroup_type, selector) != 0) {
2124 continue;
2126 if (info != NULL) {
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);
2135 info = NULL;
2136 continue;
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. */
2145 continue;
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) {
2153 continue;
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 =
2163 match->pi_ptrnpg;
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,
2168 &einfo) != 0) {
2170 * If we can no longer accumulate
2171 * errors, break out of the loop.
2173 break;
2175 } else {
2177 * Possible conflicting prop_pattern. See if the
2178 * prop_patterns are declared in the same
2179 * pg_pattern.
2181 if ((info->pi_pgp_name == NULL) ||
2182 (match->pi_pgp_name == NULL)) {
2183 continue;
2185 if (strcmp(info->pi_pgp_name, match->pi_pgp_name) != 0)
2186 continue;
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,
2192 &einfo) != 0) {
2194 * If we can no longer accumulate
2195 * errors, break out of the loop.
2197 break;
2202 ptrn_info_destroy(info);
2203 return (rc);
2207 * Free the pg_iter structure.
2209 static void
2210 pg_iter_destroy(pg_iter_t *i)
2212 if (i == NULL)
2213 return;
2215 uu_free(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.
2229 static pg_iter_t *
2230 pg_iter_create(entity_t *e, const char *restriction)
2232 pg_iter_t *i;
2234 assert(e->sc_etype == SVCCFG_INSTANCE_OBJECT);
2236 i = uu_zalloc(sizeof (*i));
2237 if (i == NULL)
2238 return (NULL);
2240 i->pgi_entity = e;
2241 i->pgi_restrict = restriction;
2242 i->pgi_level = TL_COMPOSED;
2243 i->pgi_service = e->sc_parent;
2245 return (i);
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.
2253 static pgroup_t *
2254 next_pattern_pg(pg_iter_t *i)
2256 composed_pg_t *cpg;
2257 entity_t *e;
2258 pgroup_t *pg;
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) {
2265 composed_tree =
2266 i->pgi_entity->sc_u.sc_instance.sc_composed;
2267 cpg = i->pgi_current.pgi_cpg;
2268 if (cpg == NULL) {
2269 cpg = uu_avl_first(composed_tree);
2270 } else {
2271 cpg = uu_avl_next(composed_tree, cpg);
2273 if (cpg == NULL) {
2274 pg = NULL;
2275 } else {
2276 pg = CPG2PG(cpg);
2277 i->pgi_current.pgi_cpg = cpg;
2279 } else {
2280 pg = i->pgi_current.pgi_pg;
2281 if (pg == NULL) {
2282 pg = uu_list_first(i->pgi_entity->sc_pgroups);
2283 } else {
2284 pg = uu_list_next(i->pgi_entity->sc_pgroups,
2285 pg);
2287 i->pgi_current.pgi_pg = pg;
2290 if (pg == NULL) {
2292 * End of the list. Reset current and break out of
2293 * the loop.
2295 (void) memset(&i->pgi_current, 0,
2296 sizeof (i->pgi_current));
2297 break;
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) {
2306 continue;
2310 return (pg);
2314 * End of the list in the current level. Move up to the next
2315 * level.
2317 switch (i->pgi_level) {
2318 case TL_COMPOSED:
2319 /* Skip service if we've finished a composed instance. */
2320 e = i->pgi_entity;
2321 if (e->sc_u.sc_instance.sc_instance_restarter == NULL) {
2322 /* Use service restarter */
2323 i->pgi_entity =
2324 i->pgi_service->sc_u.sc_service.sc_restarter;
2325 } else {
2326 /* Use instance restarter */
2327 i->pgi_entity =
2328 e->sc_u.sc_instance.sc_instance_restarter;
2330 i->pgi_level = TL_RESTARTER;
2331 break;
2332 case TL_RESTARTER:
2333 i->pgi_entity = i->pgi_service->sc_u.sc_service.sc_global;
2334 i->pgi_level = TL_GLOBAL;
2335 break;
2336 case TL_GLOBAL:
2337 i->pgi_level = TL_NOLEVEL;
2338 return (NULL);
2339 default:
2340 assert(0);
2341 abort();
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
2353 * card logic.
2355 /* ARGSUSED2 */
2356 static int
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))
2369 return (0);
2371 /* If we get here, exactly one of the types is NULL */
2372 if (l->pi_type == NULL)
2373 return (-1);
2374 return (1);
2377 /* If we get here, exactly one of the names is NULL */
2378 if (l->pi_name == NULL)
2379 return (-1);
2380 return (1);
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
2387 * applied.
2389 * Target Level
2390 * ------ -----
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
2396 * delegate.
2397 * instance TL_INSTANCE, TL_RESTARTER, TL_GLOBAL
2398 * Only the service level can specify the "instance"
2399 * target.
2400 * all TL_INSTANCE, TL_SERVICE, TL_RESTARTER
2401 * Only the global service can specify the "all"
2402 * target.
2404 * Return Values:
2405 * 1 apply the pg_pattern
2406 * 0 ignore the pg_pattern
2408 static int
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)) {
2418 return (0);
2419 } else {
2420 return (1);
2423 if (strcmp(target, SCF_TM_TARGET_DELEGATE) == 0) {
2424 if ((level == TL_INSTANCE) ||
2425 (level == TL_SERVICE)) {
2426 return (0);
2427 } else {
2428 return (1);
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) {
2438 return (1);
2439 } else {
2440 return (0);
2443 if (strcmp(target, SCF_TM_TARGET_ALL) == 0) {
2444 if ((level == TL_INSTANCE) ||
2445 (level == TL_SERVICE) ||
2446 (level == TL_RESTARTER)) {
2447 return (0);
2450 return (1);
2453 static int
2454 pg_target_check(pgroup_t *pg_pattern, tmpl_level_t level)
2456 const char *target;
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;
2463 break;
2464 case SVCCFG_SERVICE_OBJECT:
2465 level = TL_SERVICE;
2466 break;
2467 default:
2468 assert(0);
2469 abort();
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.
2498 * RETURNS:
2499 * 0 The property at prop does not have the specified
2500 * type.
2501 * non-zero The property at prop does have the specified type.
2503 static int
2504 property_is_type(property_t *prop, scf_type_t type)
2506 return (scf_is_compatible_type(type, prop->sc_value_type) ==
2507 SCF_SUCCESS);
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.
2517 static char *
2518 gen_pg_pattern_pg_name(const char *name, const char *type)
2520 char *pg_name;
2521 char *rv = NULL;
2522 ssize_t name_size;
2524 name_size = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH);
2525 pg_name = safe_malloc(name_size);
2526 rv = pg_name;
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
2531 * present.
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) {
2541 rv = NULL;
2543 } else {
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) >=
2550 name_size) {
2551 rv = NULL;
2554 } else {
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.
2560 const char *prefix;
2561 if ((type == NULL) || (*type == 0)) {
2562 prefix = SCF_PG_TM_PG_PATTERN_N_PREFIX;
2563 } else {
2564 prefix = SCF_PG_TM_PG_PATTERN_NT_PREFIX;
2566 if (snprintf(pg_name, name_size, "%s%s", prefix, name) >=
2567 name_size) {
2568 rv = NULL;
2572 if (rv == NULL) {
2573 /* Name was too big. */
2574 free(pg_name);
2576 return (rv);
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
2585 * correct prefix.
2587 static tmpl_validate_status_t
2588 include_values_support(ptrn_info_t *pinfo, const char *type,
2589 tmpl_errors_t *errs)
2591 error_info_t einfo;
2592 int i;
2593 const char **prefixes;
2594 const char *pfx;
2595 property_t *prop;
2596 pgroup_t *ptrn;
2598 if (strcmp(type, "constraints") == 0) {
2599 prefixes = constraint_prefixes;
2600 } else if (strcmp(type, "values") == 0) {
2601 prefixes = value_prefixes;
2602 } else {
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);
2619 prop != NULL;
2620 prop = uu_list_next(ptrn->sc_pgroup_props, prop)) {
2621 for (pfx = prefixes[0], i = 0;
2622 pfx != NULL;
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)
2651 ptrn_info_t *info;
2652 property_t *iv;
2653 tmpl_validate_status_t r;
2654 tmpl_validate_status_t rc = TVS_SUCCESS;
2655 value_t *v;
2657 for (info = uu_avl_first(tree);
2658 info != NULL;
2659 info = uu_avl_next(tree, info)) {
2660 iv = internal_property_find(info->pi_ptrnpg,
2661 SCF_PROPERTY_TM_CHOICES_INCLUDE_VALUES);
2662 if (iv == NULL)
2663 continue;
2664 for (v = uu_list_first(iv->sc_property_values);
2665 v != NULL;
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,
2669 errs);
2670 if (r != TVS_SUCCESS)
2671 rc = r;
2674 return (rc);
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)
2697 rc = r;
2699 return (rc);
2702 static tmpl_validate_status_t
2703 tmpl_required_attr_present(uu_avl_t *tree, tmpl_errors_t *errs)
2705 ptrn_info_t *pinfo;
2706 tmpl_validate_status_t rc = TVS_SUCCESS;
2707 int reported_name;
2708 int rv;
2710 for (pinfo = uu_avl_first(tree);
2711 pinfo != NULL;
2712 pinfo = uu_avl_next(tree, pinfo)) {
2713 if (is_required(pinfo->pi_ptrnpg) == 0) {
2714 /* Nothing to check if pattern is not required. */
2715 continue;
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.
2724 reported_name = 0;
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,
2729 pinfo->pi_ptrnpg,
2730 NULL, NULL, NULL, NULL, NULL) != 0) {
2732 * If we're unable to report errors, break
2733 * out of the loop.
2735 break;
2738 * Don't report the error twice if both name and
2739 * type are missing. One error message is
2740 * adequate.
2742 reported_name = 1;
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,
2749 pinfo->pi_ptrnpg,
2750 NULL, NULL, NULL, NULL, NULL);
2751 } else {
2752 rv = add_scf_error(errs,
2753 SCF_TERR_PROP_PATTERN_INCOMPLETE,
2754 pinfo->pi_enc_pgp, NULL, pinfo->pi_ptrnpg,
2755 NULL, NULL, NULL);
2757 /* If we're unable to log errors, break out of loop. */
2758 if (rv != 0)
2759 break;
2762 return (rc);
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;
2780 error_info_t einfo;
2781 pgroup_t *pg;
2782 ptrn_info_t *ginfo = NULL;
2783 ptrn_info_t *match;
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);
2794 pg != NULL;
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 */
2799 continue;
2801 if (ginfo != NULL)
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)
2808 continue;
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;
2820 } else {
2821 cur_level = TL_SERVICE;
2823 if (target_check(match->pi_target, cur_level) == 0)
2824 continue;
2827 * Instance or service overrides a general
2828 * definition. We need to issue a warning message.
2830 rc = TVS_WARN;
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,
2836 &einfo) != 0) {
2838 * No need to continue the search if we
2839 * cannot record errors.
2841 break;
2846 if (ginfo != NULL)
2847 ptrn_info_destroy(ginfo);
2848 return (rc);
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,
2872 TL_GLOBAL, errs);
2873 if (r != TVS_SUCCESS)
2874 rc = r;
2875 return (rc);
2879 * Perform the following consistency checks on the template specifications
2880 * themselves:
2882 * - No conflicting definitions of `pg_pattern` are allowed within a
2883 * single instance.
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
2891 * entity.
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
2901 * declared.
2903 static tmpl_validate_status_t
2904 tmpl_consistency(entity_t *inst, tmpl_errors_t *errs)
2906 void *marker = NULL;
2907 ptrn_info_t *info;
2908 uu_avl_t *tree;
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);
2914 if (tree == NULL) {
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)
2934 rc = r;
2935 } else {
2936 rc = r;
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)
2946 rc = r;
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)
2955 rc = r;
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)
2963 rc = r;
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)
2971 rc = r;
2973 /* Tear down the tree. */
2974 marker = NULL;
2975 while ((info = uu_avl_teardown(tree, &marker)) != NULL) {
2976 ptrn_info_destroy(info);
2978 uu_avl_destroy(tree);
2980 return (rc);
2984 * Release memory associated with the tmpl_errors structure and then free
2985 * the structure itself.
2987 void
2988 tmpl_errors_destroy(tmpl_errors_t *te)
2990 im_tmpl_error_t *ite;
2991 tv_errors_t *ste;
2992 void *marker = NULL;
2994 if (te == NULL)
2995 return;
2996 if (te->te_list) {
2997 while ((ite = uu_list_teardown(te->te_list, &marker)) != NULL) {
2998 uu_list_node_fini(ite, &ite->ite_node,
2999 inmem_errors_pool);
3000 uu_free(ite);
3002 uu_list_destroy(te->te_list);
3004 if (te->te_scf) {
3005 marker = NULL;
3006 while ((ste = uu_list_teardown(te->te_scf, &marker)) != NULL) {
3007 destroy_scf_errors(ste);
3009 uu_list_destroy(te->te_scf);
3011 uu_free(te);
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()
3025 tmpl_errors_t *te;
3027 te = uu_zalloc(sizeof (*te));
3028 if (te == NULL)
3029 return (NULL);
3030 te->te_list = uu_list_create(inmem_errors_pool, NULL, TMPL_DEBUG_LIST);
3031 if (te->te_list == NULL) {
3032 uu_free(te);
3033 return (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);
3038 return (NULL);
3041 return (te);
3044 void
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;
3050 char *s = NULL;
3051 scf_tmpl_errors_t *scferrs;
3052 tv_errors_t *scft;
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);
3057 ite != NULL;
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);
3065 scft != NULL;
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);
3077 free(s);
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
3096 * definition.
3098 rc = gen_prop_pattern_pg_name(pg_pattern,
3099 prop->sc_property_name, &prop_pattern_name);
3100 if (rc != TVS_SUCCESS)
3101 goto out;
3103 /* Find the property group. */
3104 iter = pg_iter_create(inst, SCF_GROUP_TEMPLATE_PROP_PATTERN);
3105 if (iter == NULL)
3106 goto out;
3107 while ((candidate = next_pattern_pg(iter)) != NULL) {
3108 const char *c;
3110 if (strcmp(prop_pattern_name, candidate->sc_pgroup_name) != 0)
3111 continue;
3112 c = find_astring_value_in_pg(candidate,
3113 SCF_PROPERTY_TM_PG_PATTERN);
3114 if (c == NULL)
3115 continue;
3116 if (strcmp(pg_pattern->sc_pgroup_name, c) == 0)
3117 break;
3119 *prop_pattern = candidate;
3120 if (candidate == NULL)
3121 rc = TVS_NOMATCH;
3123 out:
3124 pg_iter_destroy(iter);
3125 uu_free((void *)prop_pattern_name);
3126 return (rc);
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 */
3149 int i;
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));
3156 *pgp = NULL;
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,
3162 NULL);
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;
3169 goto errout;
3173 /* Search for property groups that match these names */
3174 iter = pg_iter_create(e, SCF_GROUP_TEMPLATE_PG_PATTERN);
3175 if (iter == NULL) {
3176 uu_die(emesg_nomem);
3178 while ((cpg = next_pattern_pg(iter)) != NULL) {
3179 if (pg_target_check(cpg, iter->pgi_level) == 0)
3180 continue;
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;
3191 break;
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];
3200 break;
3203 errout:
3204 for (i = 0; i < PGN_MAX; i++) {
3205 free(pg_names[i]);
3207 pg_iter_destroy(iter);
3208 return (rv);
3212 * Initialize structures that are required for validation using
3213 * templates specifications.
3215 void
3216 tmpl_init(void)
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.
3260 void
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.
3269 void
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
3282 * error reporting.
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)
3288 size_t count;
3289 uint64_t max;
3290 uint64_t min;
3291 tmpl_validate_status_t rc;
3292 error_info_t einfo;
3294 assert(strcmp(prop_pattern->sc_pgroup_type,
3295 SCF_GROUP_TEMPLATE_PROP_PATTERN) == 0);
3297 rc = get_cardinality(prop_pattern, &min, &max);
3298 switch (rc) {
3299 case TVS_NOMATCH:
3300 /* Nothing to check. */
3301 return (TVS_SUCCESS);
3302 case TVS_SUCCESS:
3303 /* Process the limits. */
3304 break;
3305 default:
3306 return (rc);
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
3332 * property group.
3334 static tmpl_validate_status_t
3335 tmpl_required_pg_present(entity_t *e, tmpl_errors_t *errs)
3337 composed_pg_t cpg;
3338 composed_pg_t *match;
3339 error_info_t einfo;
3340 pg_iter_t *iter;
3341 pgroup_t *pg;
3342 const char *pg_name;
3343 const char *pg_type;
3344 tmpl_validate_status_t rc = TVS_SUCCESS;
3345 uu_avl_t *tree;
3347 assert(e->sc_etype == SVCCFG_INSTANCE_OBJECT);
3349 iter = pg_iter_create(e, SCF_GROUP_TEMPLATE_PG_PATTERN);
3350 if (iter == NULL)
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. */
3359 continue;
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)
3364 continue;
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) {
3376 break;
3381 pg_iter_destroy(iter);
3382 return (rc);
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
3394 * to us.
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)
3404 error_info_t einfo;
3405 pg_iter_t *iter;
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);
3417 if (iter == NULL)
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
3426 * pg_pattern.
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) {
3433 continue;
3436 /* If the property is required, see if it is in the pg. */
3437 if (is_required(prop_pattern) == 0)
3438 continue;
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.
3453 break;
3458 pg_iter_destroy(iter);
3459 return (rc);
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
3468 * 0.
3470 static int
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))
3479 return (1);
3480 } else {
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))
3485 return (1);
3488 return (0);
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
3498 * error reporting.
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)
3504 uint_t count;
3505 error_info_t einfo;
3506 property_t *range_prop;
3507 range_t *ranges;
3508 tmpl_validate_status_t rc;
3509 scf_type_t type;
3510 value_t *v;
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);
3528 return (rc);
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 "
3536 "value");
3537 (void) tmpl_errors_add_im(errs, rc, pg_pattern->sc_parent,
3538 pg_pattern, pg, pattern, prop, NULL, &einfo);
3539 return (rc);
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);
3549 v != NULL;
3550 v = uu_list_next(prop->sc_property_values, v)) {
3551 if (value_in_range(v, type, ranges, count) == 1)
3552 continue;
3553 if (type == SCF_TYPE_COUNT) {
3554 einfo.ei_u.ei_range.ei_uvalue = v->sc_u.sc_count;
3555 } else {
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) {
3561 return (rc);
3565 return (rc);
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
3574 * error reporting.
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)
3580 int found;
3581 uint_t i;
3582 avalues_t *legal;
3583 tmpl_validate_status_t r;
3584 tmpl_validate_status_t rc = TVS_SUCCESS;
3585 value_t *v;
3587 /* Get list of legal values. */
3588 r = av_get_values(prop_pattern, SCF_PROPERTY_TM_CONSTRAINT_NAME,
3589 prop->sc_value_type, &legal);
3590 switch (r) {
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);
3594 return (r);
3595 case TVS_NOMATCH:
3596 /* No constraints in template. */
3597 return (TVS_SUCCESS);
3598 case TVS_SUCCESS:
3599 /* process the constraints. */
3600 break;
3601 default:
3602 assert(0);
3603 abort();
3606 /* Check the property values against the legal values. */
3607 for (v = uu_list_first(prop->sc_property_values);
3608 v != NULL;
3609 v = uu_list_next(prop->sc_property_values, v)) {
3610 /* Check this property value against the legal values. */
3611 found = 0;
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) ==
3617 v->sc_u.sc_count) {
3618 found = 1;
3620 break;
3621 case SCF_TYPE_INTEGER:
3622 if (av_get_integer(legal, i) ==
3623 v->sc_u.sc_integer) {
3624 found = 1;
3626 break;
3627 default:
3628 if (strcmp(av_get_string(legal, i),
3629 v->sc_u.sc_string) == 0) {
3630 found = 1;
3632 break;
3635 if (found == 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
3642 * errors.
3644 break;
3649 out:
3650 av_destroy(legal);
3651 return (rc);
3655 * Verify the following items about the values of property, prop.
3657 * - The values all have the type specified by the prop_pattern at
3658 * pattern.
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
3665 * error reporting.
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)
3677 rc = r;
3679 return (rc);
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
3689 * by the template.
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
3693 * error reporting.
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;
3700 error_info_t einfo;
3701 tmpl_validate_status_t r;
3702 tmpl_validate_status_t rc = TVS_SUCCESS;
3703 int status;
3704 scf_type_t type;
3706 r = prop_pattern_type(tmpl, &type);
3707 switch (r) {
3708 case TVS_SUCCESS:
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
3716 * errors.
3718 return (rc);
3720 } else {
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);
3731 if (status != 0) {
3733 * Give up if we can no longer
3734 * accumulate errors.
3736 return (rc);
3740 break;
3741 case TVS_MISSING_TYPE_SPECIFICATION:
3743 * A null type specification means that we do not need to
3744 * check the property's type.
3746 break;
3747 default:
3748 rc = r;
3751 /* Validate the cardinality */
3752 r = tmpl_validate_cardinality(tmpl, prop, pg, pg_pattern, errs);
3753 if (r != TVS_SUCCESS)
3754 rc = r;
3756 /* Validate that property values satisfy constraints. */
3757 r = tmpl_validate_value_constraints(tmpl, prop, pg, pg_pattern, errs);
3758 if (r != TVS_SUCCESS)
3759 rc = r;
3761 return (rc);
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
3768 * compatible.
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)
3775 error_info_t einfo;
3776 const char *pg_pattern_type; /* Type declared by pg_pattern. */
3777 pgroup_t *pg_pattern; /* Prop. group for pg_pattern */
3778 property_t *prop;
3779 pgroup_t *prop_pattern;
3780 tmpl_validate_status_t r;
3781 tmpl_validate_status_t rc = TVS_SUCCESS;
3782 int stat;
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);
3790 switch (rc) {
3791 case TVS_SUCCESS:
3792 break;
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,
3799 NULL, &einfo);
3800 return (rc);
3801 default:
3802 assert(0);
3803 abort();
3805 if (pg_pattern == NULL)
3806 return (TVS_SUCCESS);
3809 * If the pg_pattern declares a type, verify that the PG has the
3810 * correct type.
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);
3823 if (stat != 0) {
3825 * If we can no longer accumulate
3826 * errors, return without trying to
3827 * do further validation.
3829 return (rc);
3832 } else {
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
3840 * validation.
3842 return (rc);
3847 /* Verify the properties in the property group. */
3848 prop = NULL;
3849 while ((prop = next_property(pg, prop)) != NULL) {
3850 r = tmpl_find_prop_pattern(e, pg_pattern, prop, &prop_pattern);
3851 switch (r) {
3852 case TVS_SUCCESS:
3853 /* Found match. Validate property. */
3854 break;
3855 case TVS_NOMATCH:
3856 /* No prop_patern. Go on to next property. */
3857 continue;
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);
3865 continue;
3866 default:
3867 assert(0);
3868 abort();
3870 r = tmpl_validate_prop(prop, prop_pattern, pg, pg_pattern,
3871 errs);
3872 if (r != TVS_SUCCESS)
3873 rc = r;
3877 * Confirm required properties are present.
3879 r = tmpl_required_props_present(e, pg, pg_pattern, errs);
3880 if (r != TVS_SUCCESS)
3881 rc = r;
3883 return (rc);
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)
3902 composed_pg_t *cpg;
3903 uu_avl_t *pgroups;
3904 pgroup_t *pg;
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);
3912 cpg != NULL;
3913 cpg = uu_avl_next(pgroups, cpg)) {
3914 if (strcmp(cpg->cpg_type, SCF_GROUP_TEMPLATE) == 0)
3915 continue;
3916 pg = CPG2PG(cpg);
3917 if ((r = tmpl_validate_pg(e, pg, errs)) != TVS_SUCCESS)
3918 rc = r;
3921 return (rc);
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
3933 * entity.
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;
3940 int status;
3941 tv_errors_t *ste;
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)
3955 rc = r;
3957 /* Verify that all required property groups are present. */
3958 r = tmpl_required_pg_present(e, errs);
3959 if (r != TVS_SUCCESS)
3960 rc = r;
3962 return (rc);
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)
3971 entity_t *inst;
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);
3981 inst != NULL;
3982 inst = uu_list_next(svc->sc_u.sc_service.sc_service_instances,
3983 inst)) {
3984 load_instance_restarter(inst);
3985 build_composed_instance(inst);
3986 r = tmpl_validate_instance(inst, errs);
3987 if (r != TVS_SUCCESS)
3988 rc = r;
3989 demolish_composed_instance(inst);
3992 return (rc);
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;
4005 entity_t *svc;
4006 tmpl_validate_status_t r;
4007 tmpl_validate_status_t rc = TVS_SUCCESS;
4009 if (err_list != NULL)
4010 *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"));
4014 return (TVS_FATAL);
4017 errs = tmpl_errors_create();
4018 if (errs == NULL)
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);
4031 svc != NULL;
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);
4038 load_fini();
4039 return (TVS_FATAL);
4041 if ((r = tmpl_validate_service(svc, errs)) != TVS_SUCCESS)
4042 rc = r;
4043 if (r == TVS_FATAL)
4044 break;
4047 if (err_list == NULL) {
4048 tmpl_errors_destroy(errs);
4049 } else {
4050 *err_list = errs;
4053 load_fini();
4055 return (rc);