1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
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.
31 *
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.
40 *
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:
47 *
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.
78 *
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.
83 *
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.
89 *
90 * Subsystems:
91 * ==========
92 *
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.
105 *
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.
111 *
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.
118 *
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.
125 *
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.
135 *
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.
147 *
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.
158 *
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.
163 *
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.
173 *
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.
179 *
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.
188 *
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.
197 *
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.
204 */
205
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"
217
218 /*
219 * Clear error_info_t structure.
220 */
221 #define CLEAR_ERROR_INFO(ei) ((void) memset((ei), 0, sizeof (error_info_t)))
222
223 /*
224 * Retrieve the property group pointer from the composed_pg structure.
225 */
226 #define CPG2PG(cpg) (cpg->cpg_instance_pg ? cpg->cpg_instance_pg : \
227 cpg->cpg_service_pg)
228
229 /*
230 * Convert a pointer to an empty string into a NULL pointer.
231 */
232 #define EMPTY_TO_NULL(p) (((p) && (*(p) == 0)) ? NULL : (p))
233
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 */
246
247 /*
248 * Structures and enums that are used in producing error messages:
249 *
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.
255 *
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.
259 */
260 /*
261 * enum to designate the type of data that is held in a err_info structure.
262 */
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;
274
275 /*
276 * Structure to hold information that will be used in generating error
277 * messages.
278 */
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;
322
323 /*
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.
328 */
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;
340
341 /*
342 * This structure holds the data that will be used by scf_tmpl_strerror()
343 * for printing template validation errors.
344 */
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;
349
350 /*
351 * Structure to collect template validation errors.
352 */
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 */
358 };
359
360 /* End of structures used in error processing. */
361
362 /*
363 * Property group types that are of interest to us. See pgroup_type().
364 */
365 typedef enum pg_type {
366 NORMAL_PG,
367 PG_PATTERN_PG,
368 PROP_PATTERN_PG
369 } pg_type_t;
370
371 /*
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().
377 */
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;
387
388 /*
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.
394 */
395 struct composed_pg {
396 /*
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.
401 */
402 const char *cpg_name;
403 const char *cpg_type;
404
405 /* References to the actual property group definitions. */
406 pgroup_t *cpg_instance_pg;
407 pgroup_t *cpg_service_pg;
408
409 /* Composed properties of the property group. */
410 uu_avl_t *cpg_composed_props;
411
412 uu_avl_node_t cpg_node; /* Linkage for AVL tree */
413 };
414
415 /*
416 * Prefixes for standard property names. Used in
417 * include_values_support().
418 */
419 typedef struct prop_prefix {
420 const char *pp_prefix;
421 size_t pp_size;
422 } prop_prefix_t;
423
424 /*
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.
430 */
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;
443
444 /*
445 * This enum defines the levels where templates can be defined. See the
446 * pg_iter structure below.
447 */
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;
456
457 /*
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.
463 */
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;
474
475 /*
476 * enum to distinguish between pg_patterns and prop_patterns. It is used
477 * in the ptrn_info_t structure. See below.
478 */
479 typedef enum ptrn_type {
480 PG_PATTERN,
481 PROP_PATTERN
482 } ptrn_type_t;
483
484 /*
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().
490 */
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;
505
506 static const char *emesg_nomem;
507
508 /*
509 * Pool for trees of composed property groups.
510 */
511 static uu_avl_pool_t *composed_pg_pool;
512
513 /*
514 * Pool for trees of composed properties.
515 */
516 static uu_avl_pool_t *composed_prop_pool;
517
518 /*
519 * Pool for lists of errors in the internal representation.
520 */
521 static uu_list_pool_t *inmem_errors_pool;
522
523 /*
524 * Pool for trees of pg_pattern info structures (ptrn_info_t).
525 */
526 static uu_avl_pool_t *ptrn_info_pool;
527
528 /*
529 * Pool for lists of template errors in the libscf representation.
530 */
531 static uu_list_pool_t *tv_errors_pool;
532
533 /*
534 * Property name prefixes for constraints and values.
535 */
536 static const char *constraint_prefixes[] = {
537 SCF_PROPERTY_TM_CONSTRAINT_NAME,
538 SCF_PROPERTY_TM_CONSTRAINT_RANGE,
539 NULL
540 };
541 static const char *value_prefixes[] = {
542 SCF_PROPERTY_TM_VALUE_PREFIX,
543 NULL
544 };
545
546 /*
547 * Function to compare two composed_pg structures.
548 */
549 /* ARGSUSED2 */
550 static int
composed_pg_compare(const void * left,const void * right,void * unused)551 composed_pg_compare(const void *left, const void *right, void *unused)
552 {
553 composed_pg_t *l = (composed_pg_t *)left;
554 composed_pg_t *r = (composed_pg_t *)right;
555 int rc;
556
557 if ((rc = strcmp(l->cpg_name, r->cpg_name)) == 0) {
558 rc = strcmp(l->cpg_type, r->cpg_type);
559 }
560 return (rc);
561 }
562
563 /* ARGSUSED2 */
564 static int
composed_prop_compare(const void * left,const void * right,void * unused)565 composed_prop_compare(const void *left, const void *right, void *unused)
566 {
567 property_t *l = (property_t *)left;
568 property_t *r = (property_t *)right;
569
570 return (strcmp(l->sc_property_name, r->sc_property_name));
571 }
572
573 static composed_pg_t *
composed_pg_create()574 composed_pg_create()
575 {
576 composed_pg_t *cpg;
577
578 cpg = safe_malloc(sizeof (*cpg));
579 uu_avl_node_init(cpg, &cpg->cpg_node, composed_pg_pool);
580 return (cpg);
581 }
582
583 static void
composed_pg_destroy(composed_pg_t * cpg)584 composed_pg_destroy(composed_pg_t *cpg)
585 {
586 void *marker = NULL;
587 pgroup_t *pg;
588
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) {
595 /*
596 * Nothing to do other than getting the property
597 * out of the list. This cleans up the property's
598 * uu_avl_node.
599 */
600 }
601 uu_avl_destroy(cpg->cpg_composed_props);
602 }
603
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;
609 }
610
611 uu_avl_node_fini(cpg, &cpg->cpg_node, composed_pg_pool);
612 free(cpg);
613 }
614
615 /*
616 * Walk the property group at pg, and add its properties to the AVL tree at
617 * tree.
618 */
619 static void
grow_props_tree(pgroup_t * pg,uu_avl_t * tree)620 grow_props_tree(pgroup_t *pg, uu_avl_t *tree)
621 {
622 uu_avl_index_t marker;
623 property_t *prop;
624
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) {
629 /*
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.
636 */
637 uu_avl_insert(tree, prop, marker);
638 }
639 }
640 }
641
642 /*
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.
646 */
647 static void
compose_props(composed_pg_t * cpg)648 compose_props(composed_pg_t *cpg)
649 {
650 uu_avl_t *tree;
651
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()));
656 }
657 cpg->cpg_composed_props = tree;
658
659 /*
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.
664 */
665 /*
666 * First add instance properties to the tree.
667 */
668 assert(cpg->cpg_instance_pg != NULL);
669 grow_props_tree(cpg->cpg_instance_pg, tree);
670
671 /*
672 * Add service properties to the tree.
673 */
674 assert(cpg->cpg_service_pg != NULL);
675 grow_props_tree(cpg->cpg_service_pg, tree);
676 }
677
678 /*
679 * This function is a utility for build_composed_instance().
680 */
681 static void
build_composed_property_groups(entity_t * inst,uu_avl_t * tree)682 build_composed_property_groups(entity_t *inst, uu_avl_t *tree)
683 {
684 composed_pg_t *cpg;
685 uu_avl_index_t marker;
686 composed_pg_t *match;
687 pgroup_t *pg;
688 entity_t *svc;
689
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;
703 }
704
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 {
722 /*
723 * Already have a composed_pg from instance
724 * processing. Just add the pointer to the service
725 * pg and compose the properties.
726 */
727 match->cpg_service_pg = pg;
728 compose_props(match);
729 }
730 }
731 if (cpg != NULL)
732 composed_pg_destroy(cpg);
733 }
734
735 static void
build_composed_instance(entity_t * inst)736 build_composed_instance(entity_t *inst)
737 {
738 uu_avl_t *tree;
739
740 assert(inst->sc_etype == SVCCFG_INSTANCE_OBJECT);
741
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()));
747 }
748 inst->sc_u.sc_instance.sc_composed = tree;
749 }
750 build_composed_property_groups(inst,
751 inst->sc_u.sc_instance.sc_composed);
752 }
753
754 static void
demolish_composed_instance(entity_t * inst)755 demolish_composed_instance(entity_t *inst)
756 {
757 composed_pg_t *cpg;
758 void *marker = NULL;
759 uu_avl_t *tree;
760
761 tree = inst->sc_u.sc_instance.sc_composed;
762 if (tree == NULL)
763 return;
764
765 marker = NULL;
766 while ((cpg = uu_avl_teardown(tree, &marker)) != NULL) {
767 composed_pg_destroy(cpg);
768 }
769 uu_avl_destroy(tree);
770
771 inst->sc_u.sc_instance.sc_composed = NULL;
772 }
773 /*
774 * Return the number of values in prop.
775 */
776 static size_t
count_prop_values(property_t * prop)777 count_prop_values(property_t *prop)
778 {
779 return (uu_list_numnodes(prop->sc_property_values));
780 }
781
782 static int
is_numeric_type(scf_type_t type)783 is_numeric_type(scf_type_t type)
784 {
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);
792 }
793
794 static pg_type_t
pgroup_type(pgroup_t * pg)795 pgroup_type(pgroup_t *pg)
796 {
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);
802 }
803
804 /*
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.
809 */
810 static property_t *
property_find(pgroup_t * pg,const char * name)811 property_find(pgroup_t *pg, const char *name)
812 {
813 composed_pg_t *cpg;
814 property_t look;
815
816 cpg = pg->sc_pgroup_composed;
817
818 if ((cpg == NULL) || (cpg->cpg_composed_props == NULL)) {
819 /* This is not a composed property group. */
820 return (internal_property_find(pg, name));
821 }
822
823 /*
824 * This is a composed property group, so look for the property in
825 * the AVL tree.
826 */
827 look.sc_property_name = (char *)name;
828 return (uu_avl_find(cpg->cpg_composed_props, &look, NULL, NULL));
829 }
830
831 /*
832 * Functions for manipulating the avalues structure.
833 */
834
835 /*
836 * Free allocated memory referenced by the avalues structure. Then, free
837 * the structure itself.
838 */
839 static void
av_destroy(avalues_t * av)840 av_destroy(avalues_t *av)
841 {
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:
853 /*
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.
857 */
858 uu_free(av->av_v.av_string);
859 break;
860 }
861 uu_free(av);
862 }
863 /*
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.
868 *
869 * The returned structure must be freed by calling av_destroy().
870 *
871 * NULL is returned if memory allocation fails.
872 */
873 static avalues_t *
av_create(size_t count,scf_type_t type)874 av_create(size_t count, scf_type_t type)
875 {
876 uint_t alloc_failed = 0;
877 avalues_t *av;
878
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;
900 }
901 if (alloc_failed) {
902 av_destroy(av);
903 return (NULL);
904 }
905 return (av);
906 }
907
908 /*
909 * Return the ith integer value in av.
910 */
911 static int64_t
av_get_integer(avalues_t * av,uint_t i)912 av_get_integer(avalues_t *av, uint_t i)
913 {
914 assert(av->av_type == SCF_TYPE_INTEGER);
915 assert(i < av->av_count);
916 return (*(av->av_v.av_integer + i));
917 }
918
919 /*
920 * Return the ith string value in av.
921 */
922 static const char *
av_get_string(avalues_t * av,uint_t i)923 av_get_string(avalues_t *av, uint_t i)
924 {
925 assert(is_numeric_type(av->av_type) == 0);
926 assert(i < av->av_count);
927 return (*(av->av_v.av_string + i));
928 }
929
930 /*
931 * Return the ith unsigned value in av.
932 */
933 static uint64_t
av_get_unsigned(avalues_t * av,uint_t i)934 av_get_unsigned(avalues_t *av, uint_t i)
935 {
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));
940 }
941
942 /*
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.
946 */
947 static tmpl_validate_status_t
av_set_value(avalues_t * av,uint_t i,const char * value)948 av_set_value(avalues_t *av, uint_t i, const char *value)
949 {
950 char *endptr;
951 int64_t n;
952 uint64_t un;
953
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);
961 }
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);
968 }
969 *(av->av_v.av_integer + i) = n;
970 }
971 } else {
972 *(av->av_v.av_string + i) = value;
973 }
974
975 return (TVS_SUCCESS);
976 }
977
978 /*
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().
983 *
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.
989 */
990 static tmpl_validate_status_t
av_get_values(pgroup_t * pg,const char * prop_name,scf_type_t type,avalues_t ** values)991 av_get_values(pgroup_t *pg, const char *prop_name, scf_type_t type,
992 avalues_t **values)
993 {
994 avalues_t *av;
995 uint_t i;
996 property_t *prop;
997 tmpl_validate_status_t rc;
998 value_t *v;
999
1000 prop = property_find(pg, prop_name);
1001 if (prop == NULL) {
1002 return (TVS_NOMATCH);
1003 }
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);
1008
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);
1019 }
1020 }
1021 *values = av;
1022 return (TVS_SUCCESS);
1023 }
1024
1025 /*
1026 * Find the property in pg whose name is prop_name. Return a pointer to
1027 * the first astring value in that property.
1028 *
1029 * NULL is returned if there is no property named prop_name or if it does
1030 * not have an astring value.
1031 */
1032 static const char *
find_astring_value_in_pg(pgroup_t * pg,const char * prop_name)1033 find_astring_value_in_pg(pgroup_t *pg, const char *prop_name)
1034 {
1035 property_t *prop;
1036 value_t *v;
1037
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);
1048 }
1049 /*
1050 * Find the first property value of type SCF_TYPE_COUNT in the property at
1051 * prop. Return the value to count.
1052 */
1053 static tmpl_validate_status_t
find_count_value(property_t * prop,uint64_t * count)1054 find_count_value(property_t *prop, uint64_t *count)
1055 {
1056 value_t *value;
1057
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);
1064 }
1065
1066 /*
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.
1070 */
1071 static const char *
find_name_specification(pgroup_t * pattern)1072 find_name_specification(pgroup_t *pattern)
1073 {
1074 return (find_astring_value_in_pg(pattern, SCF_PROPERTY_TM_NAME));
1075 }
1076
1077 /*
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.
1081 */
1082 static const char *
find_type_specification(pgroup_t * pattern)1083 find_type_specification(pgroup_t *pattern)
1084 {
1085 return (find_astring_value_in_pg(pattern, SCF_PROPERTY_TM_TYPE));
1086 }
1087
1088 /*
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.
1091 */
1092 static const char *
find_restarter(entity_t * e)1093 find_restarter(entity_t *e)
1094 {
1095 pgroup_t *pg;
1096 property_t *prop;
1097 value_t *v;
1098
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);
1106 }
1107 }
1108
1109 /*
1110 * Didn't find the restarter.
1111 */
1112 return (NULL);
1113 }
1114
1115 /*
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.
1119 *
1120 * Returns TVS_NOMATCH if either the cardinality minimum or maximum are
1121 * missing.
1122 */
1123 static tmpl_validate_status_t
get_cardinality(pgroup_t * prop_pattern,uint64_t * min,uint64_t * max)1124 get_cardinality(pgroup_t *prop_pattern, uint64_t *min, uint64_t *max)
1125 {
1126 property_t *prop;
1127 tmpl_validate_status_t rc;
1128
1129 assert(strcmp(prop_pattern->sc_pgroup_type,
1130 SCF_GROUP_TEMPLATE_PROP_PATTERN) == 0);
1131
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);
1139
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);
1145
1146 return (rc);
1147 }
1148
1149 /*
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.
1152 *
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.
1157 *
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.
1160 */
1161 static tmpl_validate_status_t
get_ranges(property_t * range_prop,scf_type_t type,range_t ** ranges,uint_t * count)1162 get_ranges(property_t *range_prop, scf_type_t type, range_t **ranges,
1163 uint_t *count)
1164 {
1165 char *endptr;
1166 char *endptr2;
1167 range_t *r;
1168 value_t *value;
1169
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);
1178
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);
1187 }
1188 if ((errno != 0) || (endptr == value->sc_u.sc_string))
1189 goto badtemplate;
1190 if (*endptr != ',')
1191 goto badtemplate;
1192
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);
1201 }
1202 if ((errno != 0) || (endptr2 == endptr) ||
1203 (*endptr2 != 0))
1204 goto badtemplate;
1205 r++;
1206 }
1207
1208 return (TVS_SUCCESS);
1209
1210 badtemplate:
1211 free(*ranges);
1212 *ranges = NULL;
1213 return (TVS_BAD_TEMPLATE);
1214 }
1215
1216 static tv_errors_t *
tv_errors_create(const char * fmri)1217 tv_errors_create(const char *fmri)
1218 {
1219 tv_errors_t *ste;
1220
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);
1226
1227 return (ste);
1228 }
1229
1230 static void
destroy_scf_errors(tv_errors_t * ste)1231 destroy_scf_errors(tv_errors_t *ste)
1232 {
1233 scf_tmpl_errors_destroy(ste->tve_errors);
1234 uu_list_node_fini(ste, &ste->tve_node, tv_errors_pool);
1235 free(ste);
1236 }
1237
1238 /*
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().
1244 */
1245 static tmpl_validate_status_t
gen_prop_pattern_pg_name(pgroup_t * pg_pattern,const char * prop_name,char ** prop_pattern_pg_name)1246 gen_prop_pattern_pg_name(pgroup_t *pg_pattern, const char *prop_name,
1247 char **prop_pattern_pg_name)
1248 {
1249 ssize_t limit;
1250 char *name;
1251 size_t prefix_size;
1252 const char *unique;
1253
1254 limit = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
1255 assert(limit > 0);
1256
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;
1262
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);
1272 }
1273 *prop_pattern_pg_name = name;
1274 return (TVS_SUCCESS);
1275 }
1276
1277 /*
1278 * Error message printing functions:
1279 */
1280
1281 /*
1282 * Flags for use by im_perror_item.
1283 */
1284 #define IPI_NOT_FIRST 0x1 /* Not first item to be displayed. */
1285
1286 /*
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.
1290 *
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.
1299 */
1300 static void
im_perror_item(FILE * out,const char * desc,void * item,scf_type_t type,int * flags)1301 im_perror_item(FILE *out, const char *desc, void *item, scf_type_t type,
1302 int *flags)
1303 {
1304 const char *cp;
1305 const char *first_sep;
1306 int64_t ival;
1307 const char *subsequent_sep;
1308 uint64_t uval;
1309
1310 /* Nothing to print if item is NULL. */
1311 if (item == NULL)
1312 return;
1313
1314 assert(type != SCF_TYPE_INVALID);
1315
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 = "; ";
1325 }
1326
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;
1333 }
1334 (void) fprintf(out, "%s=", desc);
1335
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"));
1343 }
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:
1354 /*
1355 * Treat everything else as a string, but escape any
1356 * internal quotes.
1357 */
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);
1365 }
1366 cp++;
1367 }
1368 (void) fputc('\"', out);
1369 break;
1370 }
1371 }
1372
1373 /*
1374 * Print erroneous FMRI.
1375 */
1376 static void
im_perror_fmri(FILE * out,im_tmpl_error_t * i,int * flags)1377 im_perror_fmri(FILE *out, im_tmpl_error_t *i, int *flags)
1378 {
1379 if (i->ite_entity != NULL) {
1380 im_perror_item(out, "FMRI", (void *)i->ite_entity->sc_fmri,
1381 SCF_TYPE_FMRI, flags);
1382 }
1383 }
1384
1385 /*
1386 * Print erroneous property group name.
1387 */
1388 static void
im_perror_pg_name(FILE * out,im_tmpl_error_t * i,int * flags)1389 im_perror_pg_name(FILE *out, im_tmpl_error_t *i, int *flags)
1390 {
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);
1395 }
1396 }
1397
1398 /*
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.
1401 */
1402 static void
im_perror_pattern_info(FILE * out,pgroup_t * pattern,int * flags,int srcflag)1403 im_perror_pattern_info(FILE *out, pgroup_t *pattern, int *flags, int srcflag)
1404 {
1405 void *c;
1406 const char *name_string;
1407 const char *type_string;
1408
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();
1423 }
1424 if (srcflag) {
1425 im_perror_item(out, gettext("Template source"),
1426 (void *)pattern->sc_parent->sc_fmri, SCF_TYPE_FMRI, flags);
1427 }
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);
1434 }
1435
1436 /*
1437 * Print information about the template specifications that were violated,
1438 * so that the user can find the specification.
1439 */
1440 static void
im_perror_template_info(FILE * out,im_tmpl_error_t * i,int * flags)1441 im_perror_template_info(FILE *out, im_tmpl_error_t *i, int *flags)
1442 {
1443 pgroup_t *pg_pattern = i->ite_pg_pattern;
1444 pgroup_t *prop_pattern = i->ite_prop_pattern;
1445 int srcflag = 1;
1446
1447 if (pg_pattern != NULL) {
1448 im_perror_pattern_info(out, pg_pattern, flags, srcflag);
1449 srcflag = 0;
1450 }
1451 if (prop_pattern != NULL) {
1452 im_perror_pattern_info(out, prop_pattern, flags, srcflag);
1453 }
1454 }
1455
1456 /* Print error message for TVS_BAD_CONVERSION errors. */
1457 static void
im_perror_bad_conversion(FILE * out,im_tmpl_error_t * i,const char * prefix)1458 im_perror_bad_conversion(FILE *out, im_tmpl_error_t *i, const char *prefix)
1459 {
1460 int flags = 0;
1461
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);
1470 }
1471
1472 /* Print error message for TVS_BAD_TEMPLATE errors. */
1473 static void
im_perror_bad_template(FILE * out,im_tmpl_error_t * i,const char * prefix)1474 im_perror_bad_template(FILE *out, im_tmpl_error_t *i, const char *prefix)
1475 {
1476 int flags = 0;
1477
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);
1484 }
1485
1486 /*
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.
1491 */
1492 static void
im_perror_invalid_type(FILE * out,im_tmpl_error_t * i,const char * prefix)1493 im_perror_invalid_type(FILE *out, im_tmpl_error_t *i, const char *prefix)
1494 {
1495 int flags = 0;
1496 const char *prop_pattern_name;
1497
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);
1505 }
1506 im_perror_template_info(out, i, &flags);
1507 (void) fputc('\n', out);
1508 }
1509
1510 /*
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.
1513 */
1514 static void
im_perror_missing_pg_type(FILE * out,im_tmpl_error_t * i,const char * prefix)1515 im_perror_missing_pg_type(FILE *out, im_tmpl_error_t *i, const char *prefix)
1516 {
1517 int flags = 0;
1518 const char *type_spec;
1519
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);
1527 }
1528 (void) fputc('\n', out);
1529 }
1530
1531 /*
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.
1535 */
1536 static void
im_perror_missing_type(FILE * out,im_tmpl_error_t * i,const char * prefix)1537 im_perror_missing_type(FILE *out, im_tmpl_error_t *i, const char *prefix)
1538 {
1539 int flags = 0;
1540 const char *pg_pattern_name;
1541
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);
1549 }
1550 im_perror_template_info(out, i, &flags);
1551 (void) fputc('\n', out);
1552 }
1553
1554 static void
im_tmpl_error_print(FILE * out,im_tmpl_error_t * ite,const char * prefix)1555 im_tmpl_error_print(FILE *out, im_tmpl_error_t *ite, const char *prefix)
1556 {
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:
1574 /*
1575 * TVS_NOMATCH should be handled where it occurs. Thus,
1576 * there are no error messages associated with it.
1577 */
1578 assert(0);
1579 abort();
1580 break;
1581 case TVS_SUCCESS:
1582 break;
1583 default:
1584 assert(0);
1585 abort();
1586 }
1587 }
1588
1589 static char *
int64_to_str(int64_t i)1590 int64_to_str(int64_t i)
1591 {
1592 char *c;
1593 const char *fmt;
1594 int size;
1595
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);
1601 }
1602
1603 static char *
uint64_to_str(uint64_t u)1604 uint64_to_str(uint64_t u)
1605 {
1606 char *c;
1607 const char *fmt;
1608 int size;
1609
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);
1615 }
1616
1617 /*
1618 * Convert the value to a string. The returned value must be freed using
1619 * free(3C).
1620 */
1621 static const char *
value_to_string(value_t * v)1622 value_to_string(value_t *v)
1623 {
1624 char *c;
1625
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");
1633 }
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 }
1642 } else {
1643 c = v->sc_u.sc_string;
1644 }
1645
1646 return (safe_strdup(c));
1647 }
1648
1649 /*
1650 * Subscripts for common error data.
1651 */
1652 #define ED_PG_NAME 0
1653 #define ED_PROP_NAME 1
1654 #define ED_TMPL_FMRI 2
1655 #define ED_TMPL_PG_NAME 3
1656 #define ED_TMPL_PG_TYPE 4
1657 #define ED_TMPL_PROP_NAME 5
1658 #define ED_TMPL_PROP_TYPE 6
1659 #define ED_COUNT 7
1660
1661 /*
1662 * This function converts the error information specified by the function
1663 * parameters. It converts it to form needed by _scf_tmpl_add_error().
1664 * _scf_tmpl_add_error() requires that the error information be in the form
1665 * of allocated strings that can be freed when it is done with them. Thus,
1666 * the bulk of this function is devoted to producing those allocated
1667 * strings.
1668 *
1669 * Once the strings are ready, we call _scf_tmpl_add_error() to add an
1670 * new error structure to errs.
1671 */
1672 static int
add_scf_error(tmpl_errors_t * errs,scf_tmpl_error_type_t ec,pgroup_t * pg_pattern,pgroup_t * pg,pgroup_t * prop_pattern,property_t * prop,value_t * val,error_info_t * einfo)1673 add_scf_error(tmpl_errors_t *errs, scf_tmpl_error_type_t ec,
1674 pgroup_t *pg_pattern, pgroup_t *pg, pgroup_t *prop_pattern,
1675 property_t *prop, value_t *val, error_info_t *einfo)
1676 {
1677 const char *actual = NULL;
1678 char *c;
1679 pgroup_t *conflict;
1680 const char *ed[ED_COUNT];
1681 const char *ev1 = NULL;
1682 const char *ev2 = NULL;
1683 int i;
1684 scf_type_t prop_type;
1685 int rc;
1686
1687 (void) memset(ed, 0, sizeof (ed));
1688
1689 /* Set values that are common to most error types. */
1690 if (pg != NULL) {
1691 ed[ED_PG_NAME] = pg->sc_pgroup_name;
1692 }
1693 if (prop != NULL) {
1694 ed[ED_PROP_NAME] = prop->sc_property_name;
1695 }
1696 if (pg_pattern == NULL) {
1697 if (prop_pattern != NULL) {
1698 ed[ED_TMPL_FMRI] = prop_pattern->sc_parent->sc_fmri;
1699 }
1700 } else {
1701 ed[ED_TMPL_FMRI] = pg_pattern->sc_parent->sc_fmri;
1702 ed[ED_TMPL_PG_NAME] = find_name_specification(pg_pattern);
1703 ed[ED_TMPL_PG_TYPE] = find_type_specification(pg_pattern);
1704 }
1705 if (prop_pattern != NULL) {
1706 ed[ED_TMPL_PROP_NAME] = find_name_specification(prop_pattern);
1707 ed[ED_TMPL_PROP_TYPE] = find_type_specification(prop_pattern);
1708 }
1709
1710 /*
1711 * All of the strings that we've found must be strduped. This is
1712 * so that scf_tmpl_errors_destroy() can free them. We cannot use
1713 * the flag argument of _scf_create_errors() to indicate that the
1714 * strings should not be freed. The flag argument is an all or
1715 * nothing thing. In the code below we need to convert integers to
1716 * strings, and this requires memory allocation. Since we have to
1717 * allocate memory for that data, we need to allocate it for every
1718 * thing.
1719 */
1720 for (i = 0; i < ED_COUNT; i++) {
1721 if (ed[i] == NULL)
1722 continue;
1723 ed[i] = safe_strdup(ed[i]);
1724 }
1725
1726 /* actual, ev1 and ev2 are error code specific. */
1727 switch (ec) {
1728 case SCF_TERR_CARDINALITY_VIOLATION:
1729 assert(einfo != NULL);
1730 assert(einfo->ei_type == EIT_CARDINALITY);
1731 ev1 = uint64_to_str(einfo->ei_u.ei_cardinality.ei_min);
1732 ev2 = uint64_to_str(einfo->ei_u.ei_cardinality.ei_max);
1733 actual = uint64_to_str(einfo->ei_u.ei_cardinality.ei_count);
1734 break;
1735 case SCF_TERR_WRONG_PG_TYPE:
1736 /* Specified type. */
1737 if (pg_pattern != NULL) {
1738 ev1 = find_type_specification(pg_pattern);
1739 if (ev1 != NULL) {
1740 ev1 = safe_strdup(ev1);
1741 }
1742 }
1743 /* Actual type. */
1744 if (pg != NULL) {
1745 actual = pg->sc_pgroup_type;
1746 if (actual != NULL) {
1747 actual = safe_strdup(actual);
1748 }
1749 }
1750 break;
1751 case SCF_TERR_WRONG_PROP_TYPE:
1752 assert(einfo->ei_type == EIT_PROP_TYPE);
1753 prop_type = einfo->ei_u.ei_prop_type.ei_specified;
1754 ev1 = safe_strdup(scf_type_to_string(prop_type));
1755 prop_type = einfo->ei_u.ei_prop_type.ei_actual;
1756 actual = safe_strdup(scf_type_to_string(prop_type));
1757 break;
1758 case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
1759 actual = value_to_string(val);
1760 break;
1761 case SCF_TERR_MISSING_PG:
1762 assert(einfo->ei_type == EIT_MISSING_PG);
1763 ev1 = safe_strdup(einfo->ei_u.ei_missing_pg.ei_pg_name);
1764 ev2 = safe_strdup(einfo->ei_u.ei_missing_pg.ei_pg_type);
1765 break;
1766 case SCF_TERR_MISSING_PROP:
1767 assert(einfo->ei_type == EIT_MISSING_PROP);
1768 ev1 = safe_strdup(einfo->ei_u.ei_missing_prop.ei_prop_name);
1769 break;
1770 case SCF_TERR_RANGE_VIOLATION:
1771 assert(einfo->ei_type == EIT_RANGE);
1772 if (einfo->ei_u.ei_range.ei_rtype == SCF_TYPE_COUNT) {
1773 c = uint64_to_str(einfo->ei_u.ei_range.ei_uvalue);
1774 } else {
1775 c = int64_to_str(einfo->ei_u.ei_range.ei_ivalue);
1776 }
1777 actual = c;
1778 break;
1779 case SCF_TERR_PG_PATTERN_CONFLICT:
1780 case SCF_TERR_PROP_PATTERN_CONFLICT:
1781 case SCF_TERR_GENERAL_REDEFINE:
1782 assert(einfo->ei_type == EIT_PATTERN_CONFLICT);
1783 conflict = einfo->ei_u.ei_pattern_conflict.ei_pattern;
1784 ev1 = safe_strdup(conflict->sc_parent->sc_fmri);
1785 ev2 = find_name_specification(conflict);
1786 if (ev2 != NULL)
1787 ev2 = safe_strdup(ev2);
1788 actual = find_type_specification(conflict);
1789 if (actual != NULL)
1790 actual = safe_strdup(actual);
1791 break;
1792 case SCF_TERR_INCLUDE_VALUES:
1793 assert(einfo->ei_type == EIT_INCLUDE_VALUES);
1794 ev1 = safe_strdup(einfo->ei_u.ei_inc_values.ei_type);
1795 break;
1796 case SCF_TERR_PG_PATTERN_INCOMPLETE:
1797 case SCF_TERR_PROP_PATTERN_INCOMPLETE:
1798 break;
1799 default:
1800 assert(0);
1801 abort();
1802 };
1803
1804 rc = _scf_tmpl_add_error(errs->te_cur_scf->tve_errors, ec,
1805 ed[ED_PG_NAME], ed[ED_PROP_NAME], ev1, ev2, actual,
1806 ed[ED_TMPL_FMRI], ed[ED_TMPL_PG_NAME], ed[ED_TMPL_PG_TYPE],
1807 ed[ED_TMPL_PROP_NAME], ed[ED_TMPL_PROP_TYPE]);
1808
1809 return (rc);
1810 }
1811
1812 /*
1813 * Create and initialize a new im_tmpl_error structure and add it to the
1814 * list of errors in errs. The rest of the parameters are used to
1815 * initialize the im_tmpl_error structure.
1816 */
1817 static tmpl_validate_status_t
tmpl_errors_add_im(tmpl_errors_t * errs,tmpl_validate_status_t ec,entity_t * e,pgroup_t * pg_pattern,pgroup_t * pg,pgroup_t * prop_pattern,property_t * prop,value_t * val,error_info_t * einfo)1818 tmpl_errors_add_im(tmpl_errors_t *errs, tmpl_validate_status_t ec, entity_t *e,
1819 pgroup_t *pg_pattern, pgroup_t *pg, pgroup_t *prop_pattern,
1820 property_t *prop, value_t *val, error_info_t *einfo)
1821 {
1822 im_tmpl_error_t *ite;
1823 int result;
1824
1825 ite = uu_zalloc(sizeof (*ite));
1826 if (ite == NULL)
1827 uu_die(emesg_nomem);
1828 uu_list_node_init(ite, &ite->ite_node, inmem_errors_pool);
1829 ite->ite_type = ec;
1830 ite->ite_entity = e;
1831 ite->ite_pg = pg;
1832 ite->ite_pg_pattern = pg_pattern;
1833 ite->ite_prop = prop;
1834 ite->ite_prop_pattern = prop_pattern;
1835 ite->ite_value = val;
1836 if (einfo != NULL)
1837 ite->ite_einfo = *einfo;
1838
1839 result = uu_list_insert_after(errs->te_list, NULL, ite);
1840 assert(result == 0);
1841 return (TVS_SUCCESS);
1842 }
1843
1844 /*
1845 * pattern must point to a pg_pattern or a prop_pattern. This function
1846 * finds the property named required and returns the property's value. If
1847 * the property does not exist, false is return since it is the default.
1848 */
1849 static int
is_required(pgroup_t * pattern)1850 is_required(pgroup_t *pattern)
1851 {
1852 property_t *required;
1853 value_t *value;
1854
1855 assert((strcmp(pattern->sc_pgroup_type,
1856 SCF_GROUP_TEMPLATE_PG_PATTERN) == 0) ||
1857 (strcmp(pattern->sc_pgroup_type,
1858 SCF_GROUP_TEMPLATE_PROP_PATTERN) == 0));
1859
1860 required = property_find(pattern, SCF_PROPERTY_TM_REQUIRED);
1861
1862 /* Default if there is no required property is false. */
1863 if (required == NULL)
1864 return (0);
1865
1866 /* Retrieve the value of the required property. */
1867 value = uu_list_first(required->sc_property_values);
1868 if (value == NULL)
1869 return (0);
1870 if (value->sc_type == SCF_TYPE_BOOLEAN)
1871 return (value->sc_u.sc_count == 0 ? 0 : 1);
1872
1873 /* No boolean property values, so return false. */
1874 return (0);
1875 }
1876
1877 /*
1878 * Load the service's restarter instance and the global instance from the
1879 * repository. This will allow us to use their templates in validating the
1880 * service.
1881 *
1882 * There is no function to unload the general templates. The memory that
1883 * is allocated by load_general_templates() will be freed automatically in
1884 * internal_service_free() which is called by internal_bundle_free().
1885 */
1886 static void
load_general_templates(entity_t * svc)1887 load_general_templates(entity_t *svc)
1888 {
1889 const char *restarter;
1890 int is_global = 0;
1891 int r;
1892
1893 assert(svc->sc_etype == SVCCFG_SERVICE_OBJECT);
1894
1895 /*
1896 * If e is the global service, we only need to load the restarter.
1897 */
1898 if ((strcmp(svc->sc_fmri, SCF_INSTANCE_GLOBAL) == 0) ||
1899 (strcmp(svc->sc_fmri, SCF_SERVICE_GLOBAL) == 0)) {
1900 is_global = 1;
1901 }
1902
1903 /*
1904 * Load the templates for the service's restarter.
1905 */
1906 restarter = find_restarter(svc);
1907 if (restarter == NULL)
1908 restarter = SCF_SERVICE_STARTD;
1909 if ((r = load_instance(restarter, "restarter",
1910 &svc->sc_u.sc_service.sc_restarter)) != 0) {
1911 /*
1912 * During initial manifest import, restarter may
1913 * not be in the repository yet. In this case we
1914 * continue on without it.
1915 */
1916 if (r == EINVAL)
1917 warn(gettext("WARNING: restarter FMRI %s is invalid\n"),
1918 restarter);
1919
1920 if (r == ENOTSUP)
1921 warn(gettext("WARNING: restarter FMRI %s is not valid; "
1922 "instance fmri required.\n"), restarter);
1923
1924 if (r == ENOMEM)
1925 uu_die(emesg_nomem);
1926
1927 svc->sc_u.sc_service.sc_restarter = NULL;
1928 }
1929 if (is_global == 0) {
1930 if ((r = load_instance(SCF_INSTANCE_GLOBAL, "global",
1931 &svc->sc_u.sc_service.sc_global)) != 0) {
1932 /*
1933 * During initial manifest import, global may not be in
1934 * the repository yet.
1935 */
1936 if (r == ENOMEM)
1937 uu_die(emesg_nomem);
1938 else
1939 svc->sc_u.sc_service.sc_global = NULL;
1940 }
1941 }
1942 }
1943
1944 /*
1945 * Load the instance specific restarter if one is declared.
1946 *
1947 * There is no corresponding unload_instance_restarter() function because
1948 * it is not needed. The memory will be freed in internal_instance_free()
1949 * when internal_bundle_free() is called.
1950 */
1951 static void
load_instance_restarter(entity_t * i)1952 load_instance_restarter(entity_t *i)
1953 {
1954 const char *restarter;
1955 int r;
1956
1957 assert(i->sc_etype == SVCCFG_INSTANCE_OBJECT);
1958
1959 restarter = find_restarter(i);
1960 if (restarter == NULL) {
1961 /* No instance specific restarter */
1962 return;
1963 }
1964 r = load_instance(restarter, "instance_restarter",
1965 &i->sc_u.sc_instance.sc_instance_restarter);
1966 if (r != 0) {
1967 /*
1968 * During initial manifest import, the restarter may not be
1969 * in the repository yet. In this case we continue on
1970 * without it.
1971 */
1972 if (r == EINVAL)
1973 warn(gettext("WARNING: restarter FMRI %s is invalid\n"),
1974 restarter);
1975
1976 if (r == ENOTSUP)
1977 warn(gettext("WARNING: restarter FMRI %s is not valid; "
1978 "instance fmri required.\n"), restarter);
1979
1980 if (r == ENOMEM)
1981 uu_die(emesg_nomem);
1982 }
1983 }
1984
1985 /*
1986 * Find the next property after current in the property group at pg. If
1987 * the property group contains a tree of composed properties, that tree is
1988 * walked. Otherwise, we walk through the uu_list at sc_pgroup_props.
1989 */
1990 static property_t *
next_property(pgroup_t * pg,property_t * current)1991 next_property(pgroup_t *pg, property_t *current)
1992 {
1993 composed_pg_t *cpg;
1994 property_t *prop;
1995
1996 cpg = pg->sc_pgroup_composed;
1997 if ((cpg != NULL) && (cpg->cpg_composed_props != NULL)) {
1998 /* Walk through composed property list. */
1999 if (current) {
2000 prop = uu_avl_next(cpg->cpg_composed_props, current);
2001 } else {
2002 prop = uu_avl_first(cpg->cpg_composed_props);
2003 }
2004 } else {
2005 /* No composition available, so walk the list of properties */
2006 if (current) {
2007 prop = uu_list_next(pg->sc_pgroup_props, current);
2008 } else {
2009 prop = uu_list_first(pg->sc_pgroup_props);
2010 }
2011 }
2012
2013 return (prop);
2014 }
2015
2016 static ptrn_info_t *
ptrn_info_create(pgroup_t * pat)2017 ptrn_info_create(pgroup_t *pat)
2018 {
2019 entity_t *e;
2020 ptrn_info_t *info;
2021 composed_pg_t *match;
2022 composed_pg_t cpg;
2023
2024 info = safe_malloc(sizeof (*info));
2025
2026 switch (pgroup_type(pat)) {
2027 case PG_PATTERN_PG:
2028 info->pi_ptrn_type = PG_PATTERN;
2029 break;
2030 case PROP_PATTERN_PG:
2031 info->pi_ptrn_type = PROP_PATTERN;
2032 break;
2033 default:
2034 assert(0);
2035 abort();
2036 }
2037 info->pi_ptrnpg = pat;
2038 info->pi_name = find_name_specification(pat);
2039 info->pi_name = EMPTY_TO_NULL(info->pi_name);
2040 info->pi_type = find_type_specification(pat);
2041 info->pi_type = EMPTY_TO_NULL(info->pi_type);
2042 if (info->pi_ptrn_type == PG_PATTERN) {
2043 info->pi_target = find_astring_value_in_pg(pat,
2044 SCF_PROPERTY_TM_TARGET);
2045 if (info->pi_target == NULL)
2046 info->pi_target = SCF_TM_TARGET_THIS;
2047 }
2048 if (info->pi_ptrn_type == PROP_PATTERN) {
2049 info->pi_pgp_name = find_astring_value_in_pg(pat,
2050 SCF_PROPERTY_TM_PG_PATTERN);
2051 assert((info->pi_pgp_name != NULL) &&
2052 (*(info->pi_pgp_name) != 0));
2053
2054 /*
2055 * Find the property group that defines the pg_pattern that
2056 * holds this prop_pattern.
2057 */
2058 e = pat->sc_parent;
2059 if (e->sc_etype == SVCCFG_INSTANCE_OBJECT) {
2060 (void) memset(&cpg, 0, sizeof (cpg));
2061 cpg.cpg_name = info->pi_pgp_name;
2062 cpg.cpg_type = SCF_GROUP_TEMPLATE_PG_PATTERN;
2063 match = uu_avl_find(e->sc_u.sc_instance.sc_composed,
2064 &cpg, NULL, NULL);
2065 assert(match != NULL);
2066 info->pi_enc_pgp = CPG2PG(match);
2067 } else {
2068 info->pi_enc_pgp = internal_pgroup_find(e,
2069 info->pi_pgp_name, SCF_GROUP_TEMPLATE_PG_PATTERN);
2070 }
2071 assert(info->pi_enc_pgp != NULL);
2072 }
2073 uu_avl_node_init(info, &info->pi_link, ptrn_info_pool);
2074 return (info);
2075 }
2076
2077 static void
ptrn_info_destroy(ptrn_info_t * info)2078 ptrn_info_destroy(ptrn_info_t *info)
2079 {
2080 if (info == NULL)
2081 return;
2082 uu_avl_node_fini(info, &info->pi_link, ptrn_info_pool);
2083 free(info);
2084 }
2085
2086 /*
2087 * Walk through the property groups of the instance or service at e looking
2088 * for definitions of pg_patterns or prop_patterns as specified by type.
2089 * For each property group that matches type create a ptrn_info_t and add
2090 * it to the avl tree at tree. If duplicates are found add an error entry
2091 * to errs.
2092 */
2093 static tmpl_validate_status_t
gather_pattern(entity_t * e,ptrn_type_t type,uu_avl_t * tree,tmpl_errors_t * errs)2094 gather_pattern(entity_t *e, ptrn_type_t type, uu_avl_t *tree,
2095 tmpl_errors_t *errs)
2096 {
2097 error_info_t einfo;
2098 ptrn_info_t *info = NULL;
2099 uu_avl_index_t marker;
2100 ptrn_info_t *match;
2101 pgroup_t *pg;
2102 tmpl_validate_status_t rc = TVS_SUCCESS;
2103 const char *selector;
2104
2105 switch (type) {
2106 case PG_PATTERN:
2107 selector = SCF_GROUP_TEMPLATE_PG_PATTERN;
2108 break;
2109 case PROP_PATTERN:
2110 selector = SCF_GROUP_TEMPLATE_PROP_PATTERN;
2111 break;
2112 default:
2113 assert(0);
2114 abort();
2115 }
2116
2117 for (pg = uu_list_first(e->sc_pgroups);
2118 pg != NULL;
2119 pg = uu_list_next(e->sc_pgroups, pg)) {
2120 if (strcmp(pg->sc_pgroup_type, selector) != 0) {
2121 continue;
2122 }
2123 if (info != NULL) {
2124 /* Get rid of old structure. */
2125 ptrn_info_destroy(info);
2126 }
2127 info = ptrn_info_create(pg);
2128 match = uu_avl_find(tree, info, NULL, &marker);
2129 if (match == NULL) {
2130 /* No match. Insert the info. */
2131 uu_avl_insert(tree, info, marker);
2132 info = NULL;
2133 continue;
2134 }
2135
2136 /* Got a match. Determine if it is a conflict. */
2137 if ((info->pi_name == NULL) ||
2138 (info->pi_type == NULL) ||
2139 (match->pi_name == NULL) ||
2140 (match->pi_type == NULL)) {
2141 /* No conflicts if any wild cards. */
2142 continue;
2143 }
2144
2145 /*
2146 * Name already matches, or we wouldn't have gotten
2147 * here. Make sure that the type also matches.
2148 */
2149 if (strcmp(info->pi_type, match->pi_type) == 0) {
2150 continue;
2151 }
2152
2153 /*
2154 * If we get to this point we have a conflict, and
2155 * we need to generate the correct type of error.
2156 */
2157 CLEAR_ERROR_INFO(&einfo);
2158 einfo.ei_type = EIT_PATTERN_CONFLICT;
2159 einfo.ei_u.ei_pattern_conflict.ei_pattern =
2160 match->pi_ptrnpg;
2161 if (type == PG_PATTERN) {
2162 rc = TVS_VALIDATION;
2163 if (add_scf_error(errs, SCF_TERR_PG_PATTERN_CONFLICT,
2164 info->pi_ptrnpg, NULL, NULL, NULL, NULL,
2165 &einfo) != 0) {
2166 /*
2167 * If we can no longer accumulate
2168 * errors, break out of the loop.
2169 */
2170 break;
2171 }
2172 } else {
2173 /*
2174 * Possible conflicting prop_pattern. See if the
2175 * prop_patterns are declared in the same
2176 * pg_pattern.
2177 */
2178 if ((info->pi_pgp_name == NULL) ||
2179 (match->pi_pgp_name == NULL)) {
2180 continue;
2181 }
2182 if (strcmp(info->pi_pgp_name, match->pi_pgp_name) != 0)
2183 continue;
2184
2185 /* It is a real conflict. */
2186 rc = TVS_VALIDATION;
2187 if (add_scf_error(errs, SCF_TERR_PROP_PATTERN_CONFLICT,
2188 info->pi_enc_pgp, NULL, info->pi_ptrnpg, NULL, NULL,
2189 &einfo) != 0) {
2190 /*
2191 * If we can no longer accumulate
2192 * errors, break out of the loop.
2193 */
2194 break;
2195 }
2196 }
2197 }
2198
2199 ptrn_info_destroy(info);
2200 return (rc);
2201 }
2202
2203 /*
2204 * Free the pg_iter structure.
2205 */
2206 static void
pg_iter_destroy(pg_iter_t * i)2207 pg_iter_destroy(pg_iter_t *i)
2208 {
2209 if (i == NULL)
2210 return;
2211
2212 uu_free(i);
2213 }
2214
2215 /*
2216 * Create a property group iterator for the instance at e. This iterator
2217 * will walk through the composed property groups of the instance. It will
2218 * then step through the property groups of the instance's restarter and
2219 * finally the global service. If you wish to iterate over a specific type
2220 * of property group, set restriction to point the the desired type.
2221 * Otherwise set restriction to NULL.
2222 *
2223 * The returned interator must be freed by calling pg_iter_destroy(). NULL
2224 * is returned if we are unable to allocate the necessary memory.
2225 */
2226 static pg_iter_t *
pg_iter_create(entity_t * e,const char * restriction)2227 pg_iter_create(entity_t *e, const char *restriction)
2228 {
2229 pg_iter_t *i;
2230
2231 assert(e->sc_etype == SVCCFG_INSTANCE_OBJECT);
2232
2233 i = uu_zalloc(sizeof (*i));
2234 if (i == NULL)
2235 return (NULL);
2236
2237 i->pgi_entity = e;
2238 i->pgi_restrict = restriction;
2239 i->pgi_level = TL_COMPOSED;
2240 i->pgi_service = e->sc_parent;
2241
2242 return (i);
2243 }
2244
2245 /*
2246 * Return the next property group in the iteration. NULL is returned if we
2247 * reach the end of the list. The iterator will automatically proceed from
2248 * most specific to most general levels.
2249 */
2250 static pgroup_t *
next_pattern_pg(pg_iter_t * i)2251 next_pattern_pg(pg_iter_t *i)
2252 {
2253 composed_pg_t *cpg;
2254 entity_t *e;
2255 pgroup_t *pg;
2256 uu_avl_t *composed_tree;
2257
2258 assert(i->pgi_level != TL_NOLEVEL);
2259
2260 while (i->pgi_entity != NULL) {
2261 if (i->pgi_level == TL_COMPOSED) {
2262 composed_tree =
2263 i->pgi_entity->sc_u.sc_instance.sc_composed;
2264 cpg = i->pgi_current.pgi_cpg;
2265 if (cpg == NULL) {
2266 cpg = uu_avl_first(composed_tree);
2267 } else {
2268 cpg = uu_avl_next(composed_tree, cpg);
2269 }
2270 if (cpg == NULL) {
2271 pg = NULL;
2272 } else {
2273 pg = CPG2PG(cpg);
2274 i->pgi_current.pgi_cpg = cpg;
2275 }
2276 } else {
2277 pg = i->pgi_current.pgi_pg;
2278 if (pg == NULL) {
2279 pg = uu_list_first(i->pgi_entity->sc_pgroups);
2280 } else {
2281 pg = uu_list_next(i->pgi_entity->sc_pgroups,
2282 pg);
2283 }
2284 i->pgi_current.pgi_pg = pg;
2285 }
2286
2287 if (pg == NULL) {
2288 /*
2289 * End of the list. Reset current and break out of
2290 * the loop.
2291 */
2292 (void) memset(&i->pgi_current, 0,
2293 sizeof (i->pgi_current));
2294 break;
2295 }
2296
2297 /*
2298 * If this iteration is for a specific type, verify that
2299 * this pg is of that type.
2300 */
2301 if (i->pgi_restrict) {
2302 if (strcmp(pg->sc_pgroup_type, i->pgi_restrict) != 0) {
2303 continue;
2304 }
2305 }
2306
2307 return (pg);
2308 }
2309
2310 /*
2311 * End of the list in the current level. Move up to the next
2312 * level.
2313 */
2314 switch (i->pgi_level) {
2315 case TL_COMPOSED:
2316 /* Skip service if we've finished a composed instance. */
2317 e = i->pgi_entity;
2318 if (e->sc_u.sc_instance.sc_instance_restarter == NULL) {
2319 /* Use service restarter */
2320 i->pgi_entity =
2321 i->pgi_service->sc_u.sc_service.sc_restarter;
2322 } else {
2323 /* Use instance restarter */
2324 i->pgi_entity =
2325 e->sc_u.sc_instance.sc_instance_restarter;
2326 }
2327 i->pgi_level = TL_RESTARTER;
2328 break;
2329 case TL_RESTARTER:
2330 i->pgi_entity = i->pgi_service->sc_u.sc_service.sc_global;
2331 i->pgi_level = TL_GLOBAL;
2332 break;
2333 case TL_GLOBAL:
2334 i->pgi_level = TL_NOLEVEL;
2335 return (NULL);
2336 default:
2337 assert(0);
2338 abort();
2339 }
2340
2341 /* Go process the next level. */
2342 return (next_pattern_pg(i));
2343 }
2344
2345 /*
2346 * Compare two pattern info structures (ptrn_info_t). If both structures
2347 * have names, the comparison is based on the name. If only one has a
2348 * name, the structure with no name will be first. If neither structure
2349 * has a name, the comparison is based on their types using similar wild
2350 * card logic.
2351 */
2352 /* ARGSUSED2 */
2353 static int
ptrn_info_compare(const void * left,const void * right,void * unused)2354 ptrn_info_compare(const void *left, const void *right, void *unused)
2355 {
2356 ptrn_info_t *l = (ptrn_info_t *)left;
2357 ptrn_info_t *r = (ptrn_info_t *)right;
2358
2359 if ((l->pi_name != NULL) && (r->pi_name != NULL))
2360 return (strcmp(l->pi_name, r->pi_name));
2361 if ((l->pi_name == NULL) && (r->pi_name == NULL)) {
2362 /* No names, so we need to compare types. */
2363 if ((l->pi_type != NULL) && (r->pi_type != NULL))
2364 return (strcmp(l->pi_type, r->pi_type));
2365 if ((l->pi_type == NULL) && (r->pi_type == NULL))
2366 return (0);
2367
2368 /* If we get here, exactly one of the types is NULL */
2369 if (l->pi_type == NULL)
2370 return (-1);
2371 return (1);
2372 }
2373
2374 /* If we get here, exactly one of the names is NULL */
2375 if (l->pi_name == NULL)
2376 return (-1);
2377 return (1);
2378 }
2379
2380 /*
2381 * The target of a pg_pattern in combination with the level at which the
2382 * pg_pattern was defined determines whether or not it should be applied.
2383 * The following combinations should be ignored, and all others should be
2384 * applied.
2385 *
2386 * Target Level
2387 * ------ -----
2388 * this TL_RESTARTER, TL_GLOBAL
2389 * "this" only applies if the pg_pattern was defined
2390 * at the instance or service level
2391 * delegate TL_INSTANCE, TL_SERVICE
2392 * Only restarters and the global service can
2393 * delegate.
2394 * instance TL_INSTANCE, TL_RESTARTER, TL_GLOBAL
2395 * Only the service level can specify the "instance"
2396 * target.
2397 * all TL_INSTANCE, TL_SERVICE, TL_RESTARTER
2398 * Only the global service can specify the "all"
2399 * target.
2400 *
2401 * Return Values:
2402 * 1 apply the pg_pattern
2403 * 0 ignore the pg_pattern
2404 */
2405 static int
target_check(const char * target,tmpl_level_t level)2406 target_check(const char *target, tmpl_level_t level)
2407 {
2408 if ((target == NULL) || (*target == 0)) {
2409 /* Default is this */
2410 target = SCF_TM_TARGET_THIS;
2411 }
2412 if (strcmp(target, SCF_TM_TARGET_THIS) == 0) {
2413 if ((level == TL_RESTARTER) ||
2414 (level == TL_GLOBAL)) {
2415 return (0);
2416 } else {
2417 return (1);
2418 }
2419 }
2420 if (strcmp(target, SCF_TM_TARGET_DELEGATE) == 0) {
2421 if ((level == TL_INSTANCE) ||
2422 (level == TL_SERVICE)) {
2423 return (0);
2424 } else {
2425 return (1);
2426 }
2427 }
2428 if (strcmp(target, SCF_TM_TARGET_INSTANCE) == 0) {
2429 /*
2430 * Note that the test is inverted from the other cases.
2431 * This is because there is only one instance where apply
2432 * is the correct thing to do.
2433 */
2434 if (level == TL_SERVICE) {
2435 return (1);
2436 } else {
2437 return (0);
2438 }
2439 }
2440 if (strcmp(target, SCF_TM_TARGET_ALL) == 0) {
2441 if ((level == TL_INSTANCE) ||
2442 (level == TL_SERVICE) ||
2443 (level == TL_RESTARTER)) {
2444 return (0);
2445 }
2446 }
2447 return (1);
2448 }
2449
2450 static int
pg_target_check(pgroup_t * pg_pattern,tmpl_level_t level)2451 pg_target_check(pgroup_t *pg_pattern, tmpl_level_t level)
2452 {
2453 const char *target;
2454
2455 target = find_astring_value_in_pg(pg_pattern, SCF_PROPERTY_TM_TARGET);
2456 if (level == TL_COMPOSED) {
2457 switch (pg_pattern->sc_parent->sc_etype) {
2458 case SVCCFG_INSTANCE_OBJECT:
2459 level = TL_INSTANCE;
2460 break;
2461 case SVCCFG_SERVICE_OBJECT:
2462 level = TL_SERVICE;
2463 break;
2464 default:
2465 assert(0);
2466 abort();
2467 }
2468 }
2469 return (target_check(target, level));
2470 }
2471
2472 /*
2473 * Find the prop_pattern's type sepcification and convert it to the
2474 * appropriate scf_type.
2475 */
2476 static tmpl_validate_status_t
prop_pattern_type(pgroup_t * pattern,scf_type_t * type)2477 prop_pattern_type(pgroup_t *pattern, scf_type_t *type)
2478 {
2479 const char *type_spec;
2480
2481 assert(strcmp(pattern->sc_pgroup_type,
2482 SCF_GROUP_TEMPLATE_PROP_PATTERN) == 0);
2483
2484 type_spec = find_type_specification(pattern);
2485 if ((type_spec == NULL) || (*type_spec == 0))
2486 return (TVS_MISSING_TYPE_SPECIFICATION);
2487 *type = scf_string_to_type(type_spec);
2488 return (TVS_SUCCESS);
2489 }
2490
2491 /*
2492 * This function is analagous to scf_property_is_type(3SCF), but it works
2493 * on the in memory representation of the property.
2494 *
2495 * RETURNS:
2496 * 0 The property at prop does not have the specified
2497 * type.
2498 * non-zero The property at prop does have the specified type.
2499 */
2500 static int
property_is_type(property_t * prop,scf_type_t type)2501 property_is_type(property_t *prop, scf_type_t type)
2502 {
2503 return (scf_is_compatible_type(type, prop->sc_value_type) ==
2504 SCF_SUCCESS);
2505 }
2506
2507 /*
2508 * This function generates a property group name for a template's
2509 * pg_pattern. The name and type of the pg_pattern are used to construct
2510 * the name, but either or both may be null. A pointer to the constructed
2511 * name is returned, and the referenced memory must be freed using
2512 * free(3c). NULL is returned if we are unable to allocate enough memory.
2513 */
2514 static char *
gen_pg_pattern_pg_name(const char * name,const char * type)2515 gen_pg_pattern_pg_name(const char *name, const char *type)
2516 {
2517 char *pg_name;
2518 char *rv = NULL;
2519 ssize_t name_size;
2520
2521 name_size = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH);
2522 pg_name = safe_malloc(name_size);
2523 rv = pg_name;
2524
2525 /*
2526 * There are four cases -- name and type are both null, name and
2527 * type are both non-null, only name is present or only type is
2528 * present.
2529 */
2530 if ((name == NULL) || (*name == 0)) {
2531 if ((type == NULL) || (*type == 0)) {
2532 /*
2533 * Name and type are both null, so the PG name
2534 * contains only the prefix.
2535 */
2536 if (strlcpy(pg_name, SCF_PG_TM_PG_PATTERN_PREFIX,
2537 name_size) >= name_size) {
2538 rv = NULL;
2539 }
2540 } else {
2541 /*
2542 * If we have a type and no name, the type becomes
2543 * part of the pg_pattern property group name.
2544 */
2545 if (snprintf(pg_name, name_size, "%s%s",
2546 SCF_PG_TM_PG_PATTERN_T_PREFIX, type) >=
2547 name_size) {
2548 rv = NULL;
2549 }
2550 }
2551 } else {
2552 /*
2553 * As long as the pg_pattern has a name, it becomes part of
2554 * the name of the pg_pattern property group name. We
2555 * merely need to pick the appropriate prefix.
2556 */
2557 const char *prefix;
2558 if ((type == NULL) || (*type == 0)) {
2559 prefix = SCF_PG_TM_PG_PATTERN_N_PREFIX;
2560 } else {
2561 prefix = SCF_PG_TM_PG_PATTERN_NT_PREFIX;
2562 }
2563 if (snprintf(pg_name, name_size, "%s%s", prefix, name) >=
2564 name_size) {
2565 rv = NULL;
2566 }
2567 }
2568
2569 if (rv == NULL) {
2570 /* Name was too big. */
2571 free(pg_name);
2572 }
2573 return (rv);
2574 }
2575
2576 /*
2577 * pinfo contains information about a prop_pattern. An include_values
2578 * element with a type of type has been included in the prop_pattern
2579 * specification. We need to determine if the prop_pattern also contains
2580 * constraints or values specifications as determined by type. Thus, we
2581 * search the prop_pattern for properties whose names start with the
2582 * correct prefix.
2583 */
2584 static tmpl_validate_status_t
include_values_support(ptrn_info_t * pinfo,const char * type,tmpl_errors_t * errs)2585 include_values_support(ptrn_info_t *pinfo, const char *type,
2586 tmpl_errors_t *errs)
2587 {
2588 error_info_t einfo;
2589 int i;
2590 const char **prefixes;
2591 const char *pfx;
2592 property_t *prop;
2593 pgroup_t *ptrn;
2594
2595 if (strcmp(type, "constraints") == 0) {
2596 prefixes = constraint_prefixes;
2597 } else if (strcmp(type, "values") == 0) {
2598 prefixes = value_prefixes;
2599 } else {
2600 CLEAR_ERROR_INFO(&einfo);
2601 einfo.ei_type = EIT_BAD_TEMPLATE;
2602 einfo.ei_u.ei_bad_template.ei_reason = gettext("include_values "
2603 "type must be \"constraints\" or \"values\"");
2604 (void) tmpl_errors_add_im(errs, TVS_BAD_TEMPLATE,
2605 pinfo->pi_ptrnpg->sc_parent, pinfo->pi_enc_pgp,
2606 NULL, pinfo->pi_ptrnpg, NULL, NULL, &einfo);
2607 return (TVS_BAD_TEMPLATE);
2608 }
2609
2610 /*
2611 * Now see if the prop_pattern has a property whose name starts
2612 * with one of these prefixes.
2613 */
2614 ptrn = pinfo->pi_ptrnpg;
2615 for (prop = uu_list_first(ptrn->sc_pgroup_props);
2616 prop != NULL;
2617 prop = uu_list_next(ptrn->sc_pgroup_props, prop)) {
2618 for (pfx = prefixes[0], i = 0;
2619 pfx != NULL;
2620 ++i, pfx = prefixes[i]) {
2621 if (strncmp(prop->sc_property_name, pfx,
2622 strlen(pfx)) == 0) {
2623 return (TVS_SUCCESS);
2624 }
2625 }
2626 }
2627
2628 /* No match found. Generate error */
2629 CLEAR_ERROR_INFO(&einfo);
2630 einfo.ei_type = EIT_INCLUDE_VALUES;
2631 einfo.ei_u.ei_inc_values.ei_type = type;
2632 (void) add_scf_error(errs, SCF_TERR_INCLUDE_VALUES, pinfo->pi_enc_pgp,
2633 NULL, ptrn, NULL, NULL, &einfo);
2634
2635 return (TVS_VALIDATION);
2636 }
2637
2638 /*
2639 * Walk through the prop_patterns in tree, looking for any that have an
2640 * include_values, SCF_PROPERTY_TM_CHOICES_INCLUDE_VALUES, property. For
2641 * the prop_patterns with the include values property, verify that the
2642 * prop_pattern has constraint or values declarations as specified by the
2643 * include_values property.
2644 */
2645 static tmpl_validate_status_t
tmpl_include_values_check(uu_avl_t * tree,tmpl_errors_t * errs)2646 tmpl_include_values_check(uu_avl_t *tree, tmpl_errors_t *errs)
2647 {
2648 ptrn_info_t *info;
2649 property_t *iv;
2650 tmpl_validate_status_t r;
2651 tmpl_validate_status_t rc = TVS_SUCCESS;
2652 value_t *v;
2653
2654 for (info = uu_avl_first(tree);
2655 info != NULL;
2656 info = uu_avl_next(tree, info)) {
2657 iv = internal_property_find(info->pi_ptrnpg,
2658 SCF_PROPERTY_TM_CHOICES_INCLUDE_VALUES);
2659 if (iv == NULL)
2660 continue;
2661 for (v = uu_list_first(iv->sc_property_values);
2662 v != NULL;
2663 v = uu_list_next(iv->sc_property_values, v)) {
2664 assert(is_numeric_type(v->sc_type) == 0);
2665 r = include_values_support(info, v->sc_u.sc_string,
2666 errs);
2667 if (r != TVS_SUCCESS)
2668 rc = r;
2669 }
2670 }
2671 return (rc);
2672 }
2673
2674 /*
2675 * Verify that there are no conflicting definitions of pg_pattern or
2676 * prop_pattern. Two patterns are said to be in conflict if they have the
2677 * same name and differing types. There is a caveat, however. Empty
2678 * pattern names or types are considered to be wild cards. There is no
2679 * conflict if a pattern has a wild card.
2680 */
2681 static tmpl_validate_status_t
tmpl_pattern_conflict(entity_t * inst,uu_avl_t * tree,ptrn_type_t type,tmpl_errors_t * errs)2682 tmpl_pattern_conflict(entity_t *inst, uu_avl_t *tree, ptrn_type_t type,
2683 tmpl_errors_t *errs)
2684 {
2685 tmpl_validate_status_t r;
2686 tmpl_validate_status_t rc;
2687
2688 /* First walk the instance. */
2689 rc = gather_pattern(inst, type, tree, errs);
2690
2691 /* Now walk the service */
2692 r = gather_pattern(inst->sc_parent, type, tree, errs);
2693 if (r != TVS_SUCCESS)
2694 rc = r;
2695
2696 return (rc);
2697 }
2698
2699 static tmpl_validate_status_t
tmpl_required_attr_present(uu_avl_t * tree,tmpl_errors_t * errs)2700 tmpl_required_attr_present(uu_avl_t *tree, tmpl_errors_t *errs)
2701 {
2702 ptrn_info_t *pinfo;
2703 tmpl_validate_status_t rc = TVS_SUCCESS;
2704 int reported_name;
2705 int rv;
2706
2707 for (pinfo = uu_avl_first(tree);
2708 pinfo != NULL;
2709 pinfo = uu_avl_next(tree, pinfo)) {
2710 if (is_required(pinfo->pi_ptrnpg) == 0) {
2711 /* Nothing to check if pattern is not required. */
2712 continue;
2713 }
2714
2715 /*
2716 * For pg_pattern both name and type are optional unless
2717 * the required attribute has a value of true. For
2718 * prop_patterns only the type is optional, but it must be
2719 * provided if the required attribute has a value of true.
2720 */
2721 reported_name = 0;
2722 if ((pinfo->pi_ptrn_type == PG_PATTERN) &&
2723 (pinfo->pi_name == NULL)) {
2724 rc = TVS_VALIDATION;
2725 if (add_scf_error(errs, SCF_TERR_PG_PATTERN_INCOMPLETE,
2726 pinfo->pi_ptrnpg,
2727 NULL, NULL, NULL, NULL, NULL) != 0) {
2728 /*
2729 * If we're unable to report errors, break
2730 * out of the loop.
2731 */
2732 break;
2733 }
2734 /*
2735 * Don't report the error twice if both name and
2736 * type are missing. One error message is
2737 * adequate.
2738 */
2739 reported_name = 1;
2740 }
2741 if ((pinfo->pi_type == NULL) && (reported_name == 0)) {
2742 rc = TVS_VALIDATION;
2743 if (pinfo->pi_ptrn_type == PG_PATTERN) {
2744 rv = add_scf_error(errs,
2745 SCF_TERR_PG_PATTERN_INCOMPLETE,
2746 pinfo->pi_ptrnpg,
2747 NULL, NULL, NULL, NULL, NULL);
2748 } else {
2749 rv = add_scf_error(errs,
2750 SCF_TERR_PROP_PATTERN_INCOMPLETE,
2751 pinfo->pi_enc_pgp, NULL, pinfo->pi_ptrnpg,
2752 NULL, NULL, NULL);
2753 }
2754 /* If we're unable to log errors, break out of loop. */
2755 if (rv != 0)
2756 break;
2757 }
2758 }
2759 return (rc);
2760 }
2761
2762 /*
2763 * Look for pg_pattern definitions in general. general is either the
2764 * restarter serivce for inst or it is the global service. tree contains
2765 * the ptrn_info_t structures describing the pg_patterns for an instance.
2766 * For each general pg_pattern, see if the instance contains an overriding
2767 * definition in tree. If it does generate an error entry.
2768 *
2769 * If a redefinition is found, TVS_WARN is returned. This is because a
2770 * redefinition is not sufficient reason to inhibit the import operation.
2771 */
2772 static tmpl_validate_status_t
tmpl_scan_general(entity_t * general,uu_avl_t * tree,tmpl_level_t level,tmpl_errors_t * errs)2773 tmpl_scan_general(entity_t *general, uu_avl_t *tree,
2774 tmpl_level_t level, tmpl_errors_t *errs)
2775 {
2776 tmpl_level_t cur_level;
2777 error_info_t einfo;
2778 pgroup_t *pg;
2779 ptrn_info_t *ginfo = NULL;
2780 ptrn_info_t *match;
2781 tmpl_validate_status_t rc = TVS_SUCCESS;
2782
2783 /*
2784 * General services may not be in repository yet. It depends on
2785 * the order that manifests are imported.
2786 */
2787 if (general == NULL)
2788 return (TVS_SUCCESS);
2789
2790 for (pg = uu_list_first(general->sc_pgroups);
2791 pg != NULL;
2792 pg = uu_list_next(general->sc_pgroups, pg)) {
2793 if (strcmp(pg->sc_pgroup_type,
2794 SCF_GROUP_TEMPLATE_PG_PATTERN) != 0) {
2795 /* Not a pg_pattern */
2796 continue;
2797 }
2798 if (ginfo != NULL)
2799 ptrn_info_destroy(ginfo);
2800 ginfo = ptrn_info_create(pg);
2801 match = uu_avl_find(tree, ginfo, NULL, NULL);
2802 if (match != NULL) {
2803 /* See if global pg_pattern is targeted at us. */
2804 if (target_check(ginfo->pi_target, level) == 0)
2805 continue;
2806
2807 /*
2808 * See if the match applies to us. If we happen to
2809 * be a restarter, the pg_pattern could have a
2810 * target of delegate. That wouldn't apply to this
2811 * instance, it would only apply to our delegates.
2812 * Cases such as this are not a redefinition.
2813 */
2814 if (match->pi_ptrnpg->sc_parent->sc_etype ==
2815 SVCCFG_INSTANCE_OBJECT) {
2816 cur_level = TL_INSTANCE;
2817 } else {
2818 cur_level = TL_SERVICE;
2819 }
2820 if (target_check(match->pi_target, cur_level) == 0)
2821 continue;
2822
2823 /*
2824 * Instance or service overrides a general
2825 * definition. We need to issue a warning message.
2826 */
2827 rc = TVS_WARN;
2828 CLEAR_ERROR_INFO(&einfo);
2829 einfo.ei_type = EIT_PATTERN_CONFLICT;
2830 einfo.ei_u.ei_pattern_conflict.ei_pattern = pg;
2831 if (add_scf_error(errs, SCF_TERR_GENERAL_REDEFINE,
2832 match->pi_ptrnpg, NULL, NULL, NULL, NULL,
2833 &einfo) != 0) {
2834 /*
2835 * No need to continue the search if we
2836 * cannot record errors.
2837 */
2838 break;
2839 }
2840 }
2841 }
2842
2843 if (ginfo != NULL)
2844 ptrn_info_destroy(ginfo);
2845 return (rc);
2846 }
2847
2848 /*
2849 * tree contains the pg_pattern definitions for the instance at inst. See
2850 * if these pg_patterns redefine any pg_patterns in the instance's
2851 * restarter or in the global service. TVS_WARN is returned if a
2852 * redefinition is encountered.
2853 */
2854 static tmpl_validate_status_t
tmpl_level_redefine(entity_t * inst,uu_avl_t * tree,tmpl_errors_t * errs)2855 tmpl_level_redefine(entity_t *inst, uu_avl_t *tree, tmpl_errors_t *errs)
2856 {
2857 entity_t *restarter;
2858 entity_t *svc = inst->sc_parent;
2859 tmpl_validate_status_t r;
2860 tmpl_validate_status_t rc;
2861
2862 restarter = inst->sc_u.sc_instance.sc_instance_restarter;
2863 if (restarter == NULL) {
2864 /* No instance restarter. Use the service restarter */
2865 restarter = svc->sc_u.sc_service.sc_restarter;
2866 }
2867 rc = tmpl_scan_general(restarter, tree, TL_RESTARTER, errs);
2868 r = tmpl_scan_general(svc->sc_u.sc_service.sc_global, tree,
2869 TL_GLOBAL, errs);
2870 if (r != TVS_SUCCESS)
2871 rc = r;
2872 return (rc);
2873 }
2874
2875 /*
2876 * Perform the following consistency checks on the template specifications
2877 * themselves:
2878 *
2879 * - No conflicting definitions of `pg_pattern` are allowed within a
2880 * single instance.
2881 *
2882 * - Templates at a narrow target (e.g. instance) which define
2883 * property groups already templated at a broad target
2884 * (e.g. restarter or all) are strongly discouraged.
2885 *
2886 * - Developers may not define a template which specifies a single
2887 * prop_pattern name with differing types on the same target
2888 * entity.
2889 *
2890 * - If a pg_pattern has a required attribute with a value of true,
2891 * then its name and type attributes must be specified.
2892 *
2893 * - If a prop_pattern has a required attribute with a value of true,
2894 * then its type attribute must be specified.
2895 *
2896 * - If a prop_pattern has an include values make sure that the
2897 * appropriate constraints or values element has also been
2898 * declared.
2899 */
2900 static tmpl_validate_status_t
tmpl_consistency(entity_t * inst,tmpl_errors_t * errs)2901 tmpl_consistency(entity_t *inst, tmpl_errors_t *errs)
2902 {
2903 void *marker = NULL;
2904 ptrn_info_t *info;
2905 uu_avl_t *tree;
2906 tmpl_validate_status_t rc;
2907 tmpl_validate_status_t r;
2908
2909 /* Allocate the tree. */
2910 tree = uu_avl_create(ptrn_info_pool, NULL, TMPL_DEBUG_TREE);
2911 if (tree == NULL) {
2912 uu_die(gettext("pg_info tree creation failed: %s\n"),
2913 uu_strerror(uu_error()));
2914 }
2915
2916 rc = tmpl_pattern_conflict(inst, tree, PG_PATTERN, errs);
2917
2918 /*
2919 * The tree now contains the instance and service pg_patterns.
2920 * Check to see if they override any pg_pattern definitions in the
2921 * restarter and global services.
2922 */
2923 r = tmpl_level_redefine(inst, tree, errs);
2924 if (r != TVS_SUCCESS) {
2925 /*
2926 * tmpl_level_redefine() can return a warning. Don't
2927 * override a serious error with a warning.
2928 */
2929 if (r == TVS_WARN) {
2930 if (rc == TVS_SUCCESS)
2931 rc = r;
2932 } else {
2933 rc = r;
2934 }
2935 }
2936
2937 /*
2938 * If the pg_pattern has a required attribute with a value of true,
2939 * then it must also have name and type attributes.
2940 */
2941 r = tmpl_required_attr_present(tree, errs);
2942 if (r != TVS_SUCCESS)
2943 rc = r;
2944
2945 /* Empty the tree, so that we can reuse it for prop_patterns. */
2946 while ((info = uu_avl_teardown(tree, &marker)) != NULL) {
2947 ptrn_info_destroy(info);
2948 }
2949
2950 r = tmpl_pattern_conflict(inst, tree, PROP_PATTERN, errs);
2951 if (r != TVS_SUCCESS)
2952 rc = r;
2953
2954 /*
2955 * If a prop_pattern has required attribute with a value of true,
2956 * then it must also have a type attribute.
2957 */
2958 r = tmpl_required_attr_present(tree, errs);
2959 if (r != TVS_SUCCESS)
2960 rc = r;
2961
2962 /*
2963 * Insure that include_values have the constraint for values
2964 * elements that are needed.
2965 */
2966 r = tmpl_include_values_check(tree, errs);
2967 if (r != TVS_SUCCESS)
2968 rc = r;
2969
2970 /* Tear down the tree. */
2971 marker = NULL;
2972 while ((info = uu_avl_teardown(tree, &marker)) != NULL) {
2973 ptrn_info_destroy(info);
2974 }
2975 uu_avl_destroy(tree);
2976
2977 return (rc);
2978 }
2979
2980 /*
2981 * Release memory associated with the tmpl_errors structure and then free
2982 * the structure itself.
2983 */
2984 void
tmpl_errors_destroy(tmpl_errors_t * te)2985 tmpl_errors_destroy(tmpl_errors_t *te)
2986 {
2987 im_tmpl_error_t *ite;
2988 tv_errors_t *ste;
2989 void *marker = NULL;
2990
2991 if (te == NULL)
2992 return;
2993 if (te->te_list) {
2994 while ((ite = uu_list_teardown(te->te_list, &marker)) != NULL) {
2995 uu_list_node_fini(ite, &ite->ite_node,
2996 inmem_errors_pool);
2997 uu_free(ite);
2998 }
2999 uu_list_destroy(te->te_list);
3000 }
3001 if (te->te_scf) {
3002 marker = NULL;
3003 while ((ste = uu_list_teardown(te->te_scf, &marker)) != NULL) {
3004 destroy_scf_errors(ste);
3005 }
3006 uu_list_destroy(te->te_scf);
3007 }
3008 uu_free(te);
3009 }
3010
3011 /*
3012 * Allocate and initialize a tmpl_errors structure. The address of the
3013 * structure is returned, unless we are unable to allocate enough memory.
3014 * In the case of memory allocation failures, NULL is returned.
3015 *
3016 * The allocated structure should be freed by calling
3017 * tmpl_errors_destroy().
3018 */
3019 static tmpl_errors_t *
tmpl_errors_create()3020 tmpl_errors_create()
3021 {
3022 tmpl_errors_t *te;
3023
3024 te = uu_zalloc(sizeof (*te));
3025 if (te == NULL)
3026 return (NULL);
3027 te->te_list = uu_list_create(inmem_errors_pool, NULL, TMPL_DEBUG_LIST);
3028 if (te->te_list == NULL) {
3029 uu_free(te);
3030 return (NULL);
3031 }
3032 te->te_scf = uu_list_create(tv_errors_pool, NULL, TMPL_DEBUG_LIST);
3033 if (te->te_scf == NULL) {
3034 tmpl_errors_destroy(te);
3035 return (NULL);
3036 }
3037
3038 return (te);
3039 }
3040
3041 void
tmpl_errors_print(FILE * out,tmpl_errors_t * errs,const char * prefix)3042 tmpl_errors_print(FILE *out, tmpl_errors_t *errs, const char *prefix)
3043 {
3044 scf_tmpl_error_t *cur;
3045 size_t buf_size = 4096;
3046 im_tmpl_error_t *ite;
3047 char *s = NULL;
3048 scf_tmpl_errors_t *scferrs;
3049 tv_errors_t *scft;
3050 int interactive = (est->sc_cmd_flags & SC_CMD_IACTIVE) ?
3051 SCF_TMPL_STRERROR_HUMAN : 0;
3052
3053 for (ite = uu_list_first(errs->te_list);
3054 ite != NULL;
3055 ite = uu_list_next(errs->te_list, ite)) {
3056 im_tmpl_error_print(out, ite, prefix);
3057 }
3058
3059 /* Now handle the errors that can be printed via libscf. */
3060 s = safe_malloc(buf_size);
3061 for (scft = uu_list_first(errs->te_scf);
3062 scft != NULL;
3063 scft = uu_list_next(errs->te_scf, scft)) {
3064 scferrs = scft->tve_errors;
3065 if (_scf_tmpl_error_set_prefix(scferrs, prefix) != 0)
3066 uu_die(emesg_nomem);
3067 while ((cur = scf_tmpl_next_error(scferrs)) != NULL) {
3068 (void) scf_tmpl_strerror(cur, s, buf_size, interactive);
3069 (void) fputs(s, out);
3070 (void) fputc('\n', out);
3071 }
3072 }
3073
3074 free(s);
3075 }
3076
3077 /*
3078 * This function finds the prop_pattern for the property, prop. e is the
3079 * instance where the search for the prop_pattern will start. pg_pattern
3080 * is the address of the pg_pattern that holds the prop_pattern.
3081 */
3082 static tmpl_validate_status_t
tmpl_find_prop_pattern(entity_t * inst,pgroup_t * pg_pattern,property_t * prop,pgroup_t ** prop_pattern)3083 tmpl_find_prop_pattern(entity_t *inst, pgroup_t *pg_pattern,
3084 property_t *prop, pgroup_t **prop_pattern)
3085 {
3086 pgroup_t *candidate;
3087 pg_iter_t *iter = NULL;
3088 char *prop_pattern_name = NULL;
3089 tmpl_validate_status_t rc;
3090
3091 /*
3092 * Get the name of the property group that holds the prop_pattern
3093 * definition.
3094 */
3095 rc = gen_prop_pattern_pg_name(pg_pattern,
3096 prop->sc_property_name, &prop_pattern_name);
3097 if (rc != TVS_SUCCESS)
3098 goto out;
3099
3100 /* Find the property group. */
3101 iter = pg_iter_create(inst, SCF_GROUP_TEMPLATE_PROP_PATTERN);
3102 if (iter == NULL)
3103 goto out;
3104 while ((candidate = next_pattern_pg(iter)) != NULL) {
3105 const char *c;
3106
3107 if (strcmp(prop_pattern_name, candidate->sc_pgroup_name) != 0)
3108 continue;
3109 c = find_astring_value_in_pg(candidate,
3110 SCF_PROPERTY_TM_PG_PATTERN);
3111 if (c == NULL)
3112 continue;
3113 if (strcmp(pg_pattern->sc_pgroup_name, c) == 0)
3114 break;
3115 }
3116 *prop_pattern = candidate;
3117 if (candidate == NULL)
3118 rc = TVS_NOMATCH;
3119
3120 out:
3121 pg_iter_destroy(iter);
3122 uu_free((void *)prop_pattern_name);
3123 return (rc);
3124 }
3125
3126 /*
3127 * Indexes for pg_pattern property group names. Indexes are arranged
3128 * from most specific to least specific.
3129 */
3130 #define PGN_BOTH 0 /* both name and type */
3131 #define PGN_NAME 1 /* name only */
3132 #define PGN_TYPE 2 /* type only */
3133 #define PGN_NEITHER 3 /* neither name nor type */
3134 #define PGN_MAX 4 /* Size of array */
3135
3136 /*
3137 * Given an instance entity, e, and a propety group, pg, within the
3138 * instance; return the address of the pg_pattern for the property group.
3139 * The address of the pg_pattern is placed at pgp. NULL indicates that no
3140 * pg_pattern was specified.
3141 */
3142 static tmpl_validate_status_t
tmpl_find_pg_pattern(entity_t * e,pgroup_t * pg,pgroup_t ** pgp)3143 tmpl_find_pg_pattern(entity_t *e, pgroup_t *pg, pgroup_t **pgp)
3144 {
3145 pgroup_t *cpg; /* candidate property group */
3146 int i;
3147 pg_iter_t *iter = NULL;
3148 char *pg_names[PGN_MAX];
3149 pgroup_t *pg_patterns[PGN_MAX];
3150 tmpl_validate_status_t rv = TVS_SUCCESS;
3151
3152 (void) memset(pg_patterns, 0, sizeof (pg_patterns));
3153 *pgp = NULL;
3154
3155 /* Generate candidate names for pg_pattern property groups. */
3156 pg_names[PGN_BOTH] = gen_pg_pattern_pg_name(pg->sc_pgroup_name,
3157 pg->sc_pgroup_type);
3158 pg_names[PGN_NAME] = gen_pg_pattern_pg_name(pg->sc_pgroup_name,
3159 NULL);
3160 pg_names[PGN_TYPE] = gen_pg_pattern_pg_name(NULL,
3161 pg->sc_pgroup_type);
3162 pg_names[PGN_NEITHER] = gen_pg_pattern_pg_name(NULL, NULL);
3163 for (i = 0; i < PGN_MAX; i++) {
3164 if (pg_names[i] == NULL) {
3165 rv = TVS_BAD_TEMPLATE;
3166 goto errout;
3167 }
3168 }
3169
3170 /* Search for property groups that match these names */
3171 iter = pg_iter_create(e, SCF_GROUP_TEMPLATE_PG_PATTERN);
3172 if (iter == NULL) {
3173 uu_die(emesg_nomem);
3174 }
3175 while ((cpg = next_pattern_pg(iter)) != NULL) {
3176 if (pg_target_check(cpg, iter->pgi_level) == 0)
3177 continue;
3178
3179 /* See if we have a name match. */
3180 for (i = 0; i < PGN_MAX; i++) {
3181 if (strcmp(cpg->sc_pgroup_name, pg_names[i]) == 0) {
3182 /*
3183 * If we already have a lower level
3184 * pg_pattern, keep it.
3185 */
3186 if (pg_patterns[i] == NULL)
3187 pg_patterns[i] = cpg;
3188 break;
3189 }
3190 }
3191 }
3192
3193 /* Find the most specific pg_pattern. */
3194 for (i = 0; i < PGN_MAX; i++) {
3195 if (pg_patterns[i] != NULL) {
3196 *pgp = pg_patterns[i];
3197 break;
3198 }
3199 }
3200 errout:
3201 for (i = 0; i < PGN_MAX; i++) {
3202 free(pg_names[i]);
3203 }
3204 pg_iter_destroy(iter);
3205 return (rv);
3206 }
3207
3208 /*
3209 * Initialize structures that are required for validation using
3210 * templates specifications.
3211 */
3212 void
tmpl_init(void)3213 tmpl_init(void)
3214 {
3215 emesg_nomem = gettext("Out of memory.\n");
3216
3217 composed_pg_pool = uu_avl_pool_create("composed_pg",
3218 sizeof (composed_pg_t), offsetof(composed_pg_t, cpg_node),
3219 composed_pg_compare, TMPL_DEBUG_AVL_POOL);
3220 if (composed_pg_pool == NULL) {
3221 uu_die(gettext("composed_pg pool creation failed: %s\n"),
3222 uu_strerror(uu_error()));
3223 }
3224 composed_prop_pool = uu_avl_pool_create("composed_prop",
3225 sizeof (property_t), offsetof(property_t, sc_composed_node),
3226 composed_prop_compare, TMPL_DEBUG_AVL_POOL);
3227 if (composed_prop_pool == NULL) {
3228 uu_die(gettext("composed_prop pool creation failed. %s\n"),
3229 uu_strerror(uu_error()));
3230 }
3231 ptrn_info_pool = uu_avl_pool_create("ptrn_info", sizeof (ptrn_info_t),
3232 offsetof(ptrn_info_t, pi_link), ptrn_info_compare,
3233 TMPL_DEBUG_AVL_POOL);
3234 if (ptrn_info_pool == NULL) {
3235 uu_die(gettext("pg_pattern info pool creation failed: %s\n"),
3236 uu_strerror(uu_error()));
3237 }
3238 inmem_errors_pool = uu_list_pool_create("errors-internal",
3239 sizeof (im_tmpl_error_t), offsetof(im_tmpl_error_t,
3240 ite_node), NULL, TMPL_DEBUG_LIST_POOL);
3241 if (inmem_errors_pool == NULL) {
3242 uu_die(gettext("inmem_errors_pool pool creation failed: "
3243 "%s\n"), uu_strerror(uu_error()));
3244 }
3245 tv_errors_pool = uu_list_pool_create("scf-terrors",
3246 sizeof (tv_errors_t), offsetof(tv_errors_t, tve_node),
3247 NULL, TMPL_DEBUG_LIST_POOL);
3248 if (tv_errors_pool == NULL) {
3249 uu_die(gettext("tv_errors_pool pool creation failed: %s\n"),
3250 uu_strerror(uu_error()));
3251 }
3252 }
3253
3254 /*
3255 * Clean up the composed property node in the property.
3256 */
3257 void
tmpl_property_fini(property_t * p)3258 tmpl_property_fini(property_t *p)
3259 {
3260 uu_avl_node_fini(p, &p->sc_composed_node, composed_prop_pool);
3261 }
3262
3263 /*
3264 * Initialize the composed property node in the property.
3265 */
3266 void
tmpl_property_init(property_t * p)3267 tmpl_property_init(property_t *p)
3268 {
3269 uu_avl_node_init(p, &p->sc_composed_node, composed_prop_pool);
3270 }
3271
3272 /*
3273 * Use the cardinality specification in the prop_pattern to verify the
3274 * cardinality of the property at prop. The cardinality of the property is
3275 * the number of values that it has.
3276 *
3277 * pg is the property group that holds prop, and pg_pattern is the
3278 * pg_pattern for the property group. pg and pg_pattern are only used for
3279 * error reporting.
3280 */
3281 static tmpl_validate_status_t
tmpl_validate_cardinality(pgroup_t * prop_pattern,property_t * prop,pgroup_t * pg,pgroup_t * pg_pattern,tmpl_errors_t * errs)3282 tmpl_validate_cardinality(pgroup_t *prop_pattern, property_t *prop,
3283 pgroup_t *pg, pgroup_t *pg_pattern, tmpl_errors_t *errs)
3284 {
3285 size_t count;
3286 uint64_t max;
3287 uint64_t min;
3288 tmpl_validate_status_t rc;
3289 error_info_t einfo;
3290
3291 assert(strcmp(prop_pattern->sc_pgroup_type,
3292 SCF_GROUP_TEMPLATE_PROP_PATTERN) == 0);
3293
3294 rc = get_cardinality(prop_pattern, &min, &max);
3295 switch (rc) {
3296 case TVS_NOMATCH:
3297 /* Nothing to check. */
3298 return (TVS_SUCCESS);
3299 case TVS_SUCCESS:
3300 /* Process the limits. */
3301 break;
3302 default:
3303 return (rc);
3304 }
3305
3306 if ((min == 0) && (max == ULLONG_MAX)) {
3307 /* Any number of values is permitted. No need to count. */
3308 return (TVS_SUCCESS);
3309 }
3310
3311 count = count_prop_values(prop);
3312 if ((count < min) || (count > max)) {
3313 CLEAR_ERROR_INFO(&einfo);
3314 einfo.ei_type = EIT_CARDINALITY;
3315 einfo.ei_u.ei_cardinality.ei_min = min;
3316 einfo.ei_u.ei_cardinality.ei_max = max;
3317 einfo.ei_u.ei_cardinality.ei_count = count;
3318 (void) add_scf_error(errs, SCF_TERR_CARDINALITY_VIOLATION,
3319 pg_pattern, pg, prop_pattern, prop, NULL, &einfo);
3320 return (TVS_VALIDATION);
3321 }
3322
3323 return (TVS_SUCCESS);
3324 }
3325
3326 /*
3327 * Iterate over pg_patterns in the entity, e. If the pg_pattern's required
3328 * attribute is true, verify that the entity contains the corresponding
3329 * property group.
3330 */
3331 static tmpl_validate_status_t
tmpl_required_pg_present(entity_t * e,tmpl_errors_t * errs)3332 tmpl_required_pg_present(entity_t *e, tmpl_errors_t *errs)
3333 {
3334 composed_pg_t cpg;
3335 composed_pg_t *match;
3336 error_info_t einfo;
3337 pg_iter_t *iter;
3338 pgroup_t *pg;
3339 const char *pg_name;
3340 const char *pg_type;
3341 tmpl_validate_status_t rc = TVS_SUCCESS;
3342 uu_avl_t *tree;
3343
3344 assert(e->sc_etype == SVCCFG_INSTANCE_OBJECT);
3345
3346 iter = pg_iter_create(e, SCF_GROUP_TEMPLATE_PG_PATTERN);
3347 if (iter == NULL)
3348 uu_die(emesg_nomem);
3349
3350 CLEAR_ERROR_INFO(&einfo);
3351 einfo.ei_type = EIT_MISSING_PG;
3352
3353 while ((pg = next_pattern_pg(iter)) != NULL) {
3354 if (is_required(pg) == 0) {
3355 /* If pg is not required, there is nothing to check. */
3356 continue;
3357 }
3358 pg_name = find_astring_value_in_pg(pg, SCF_PROPERTY_TM_NAME);
3359 pg_type = find_astring_value_in_pg(pg, SCF_PROPERTY_TM_TYPE);
3360 if (pg_target_check(pg, iter->pgi_level) == 0)
3361 continue;
3362 einfo.ei_u.ei_missing_pg.ei_pg_name = pg_name;
3363 einfo.ei_u.ei_missing_pg.ei_pg_type = pg_type;
3364 tree = e->sc_u.sc_instance.sc_composed;
3365 (void) memset(&cpg, 0, sizeof (cpg));
3366 cpg.cpg_name = pg_name;
3367 cpg.cpg_type = pg_type;
3368 match = uu_avl_find(tree, &cpg, NULL, NULL);
3369 if (match == NULL) {
3370 rc = TVS_VALIDATION;
3371 if (add_scf_error(errs, SCF_TERR_MISSING_PG, pg,
3372 NULL, NULL, NULL, NULL, &einfo) != 0) {
3373 break;
3374 }
3375 }
3376 }
3377
3378 pg_iter_destroy(iter);
3379 return (rc);
3380 }
3381
3382 /*
3383 * Verify that the property group, pg, contains property declarations for
3384 * all required properties. Unfortunately, there is no direct way to find
3385 * the prop_patterns for a given property group. Therefore, we need to
3386 * scan the entity at e looking for property groups with a type of
3387 * SCF_GROUP_TEMPLATE_PROP_PATTERN. That is, we scan the entity looking
3388 * for all prop_patterns. When we find a prop_pattern, we look at the
3389 * value of its pg_pattern property to see if it matches the name of the
3390 * pg_pattern. If they match, this is a prop_pattern that is of interest
3391 * to us.
3392 *
3393 * When we find an interesting prop_pattern, we see if it's required
3394 * property is true. If it is, we verify that the property group at pg
3395 * contains the specified property.
3396 */
3397 static tmpl_validate_status_t
tmpl_required_props_present(entity_t * e,pgroup_t * pg,pgroup_t * pg_pattern,tmpl_errors_t * errs)3398 tmpl_required_props_present(entity_t *e, pgroup_t *pg, pgroup_t *pg_pattern,
3399 tmpl_errors_t *errs)
3400 {
3401 error_info_t einfo;
3402 pg_iter_t *iter;
3403 const char *prop_name;
3404 const char *prop_pg_pattern_name;
3405 pgroup_t *prop_pattern;
3406 scf_tmpl_error_type_t ec;
3407 tmpl_validate_status_t rc = TVS_SUCCESS;
3408
3409 /*
3410 * Scan the entity's property groups looking for ones with a type
3411 * of SCF_GROUP_TEMPLATE_PROP_PATTERN.
3412 */
3413 iter = pg_iter_create(e, SCF_GROUP_TEMPLATE_PROP_PATTERN);
3414 if (iter == NULL)
3415 uu_die(emesg_nomem);
3416 CLEAR_ERROR_INFO(&einfo);
3417 for (prop_pattern = next_pattern_pg(iter);
3418 prop_pattern != NULL;
3419 prop_pattern = next_pattern_pg(iter)) {
3420 /*
3421 * Find the pg_pattern property in this prop_pattern.
3422 * Verify that its value matches the name of the
3423 * pg_pattern.
3424 */
3425 prop_pg_pattern_name = find_astring_value_in_pg(prop_pattern,
3426 SCF_PROPERTY_TM_PG_PATTERN);
3427 assert(prop_pg_pattern_name != NULL);
3428 if (strcmp(pg_pattern->sc_pgroup_name,
3429 prop_pg_pattern_name) != 0) {
3430 continue;
3431 }
3432
3433 /* If the property is required, see if it is in the pg. */
3434 if (is_required(prop_pattern) == 0)
3435 continue;
3436 prop_name = find_astring_value_in_pg(prop_pattern,
3437 SCF_PROPERTY_TM_NAME);
3438 assert(prop_name != NULL);
3439 if (property_find(pg, prop_name) == NULL) {
3440 ec = SCF_TERR_MISSING_PROP;
3441 rc = TVS_VALIDATION;
3442 einfo.ei_type = EIT_MISSING_PROP;
3443 einfo.ei_u.ei_missing_prop.ei_prop_name = prop_name;
3444 if (add_scf_error(errs, ec, pg_pattern, pg,
3445 prop_pattern, NULL, NULL, &einfo) != 0) {
3446 /*
3447 * If we can no longer accumulate errors,
3448 * break out of the loop.
3449 */
3450 break;
3451 }
3452 }
3453 }
3454
3455 pg_iter_destroy(iter);
3456 return (rc);
3457 }
3458
3459 /*
3460 * Check the value at v to see if it falls within any of the ranges at r.
3461 * count is the number of ranges at r, and type tells whether to treat the
3462 * value as signed or unsigned.
3463 *
3464 * Return 1 if the value falls within one of the ranges. Otherwise return
3465 * 0.
3466 */
3467 static int
value_in_range(value_t * v,scf_type_t type,range_t * r,size_t count)3468 value_in_range(value_t *v, scf_type_t type, range_t *r, size_t count)
3469 {
3470 for (; count > 0; --count, r++) {
3471 if (type == SCF_TYPE_COUNT) {
3472 if ((v->sc_u.sc_count >=
3473 r->rng_u.rng_unsigned.rng_min) &&
3474 (v->sc_u.sc_count <=
3475 r->rng_u.rng_unsigned.rng_max))
3476 return (1);
3477 } else {
3478 if ((v->sc_u.sc_integer >=
3479 r->rng_u.rng_signed.rng_min) &&
3480 (v->sc_u.sc_integer <=
3481 r->rng_u.rng_signed.rng_max))
3482 return (1);
3483 }
3484 }
3485 return (0);
3486 }
3487
3488 /*
3489 * If the template prop_pattern at pattern contains a constraint_range
3490 * property, use the specified range to validate all the numeric property
3491 * values of the property at prop.
3492 *
3493 * pg is the property group that holds prop, and pg_pattern is the
3494 * pg_pattern for the property group. pg and pg_pattern are only used for
3495 * error reporting.
3496 */
3497 static tmpl_validate_status_t
tmpl_validate_value_range(pgroup_t * pattern,property_t * prop,pgroup_t * pg,pgroup_t * pg_pattern,tmpl_errors_t * errs)3498 tmpl_validate_value_range(pgroup_t *pattern, property_t *prop, pgroup_t *pg,
3499 pgroup_t *pg_pattern, tmpl_errors_t *errs)
3500 {
3501 uint_t count;
3502 error_info_t einfo;
3503 property_t *range_prop;
3504 range_t *ranges;
3505 tmpl_validate_status_t rc;
3506 scf_type_t type;
3507 value_t *v;
3508
3509 /* Get the range constraints if they exist. */
3510 if ((range_prop = property_find(pattern,
3511 SCF_PROPERTY_TM_CONSTRAINT_RANGE)) == NULL) {
3512 /* No range to check. */
3513 return (TVS_SUCCESS);
3514 }
3515 type = prop->sc_value_type;
3516 if ((type != SCF_TYPE_COUNT) && (type != SCF_TYPE_INTEGER)) {
3517 rc = TVS_BAD_TEMPLATE;
3518 CLEAR_ERROR_INFO(&einfo);
3519 einfo.ei_type = EIT_BAD_TEMPLATE;
3520 einfo.ei_u.ei_bad_template.ei_reason =
3521 gettext("Property does not have correct type for "
3522 "a range specification");
3523 (void) tmpl_errors_add_im(errs, rc, pg_pattern->sc_parent,
3524 pg_pattern, pg, pattern, prop, NULL, &einfo);
3525 return (rc);
3526 }
3527 if ((rc = get_ranges(range_prop, prop->sc_value_type, &ranges,
3528 &count)) != TVS_SUCCESS) {
3529 rc = TVS_BAD_TEMPLATE;
3530 CLEAR_ERROR_INFO(&einfo);
3531 einfo.ei_type = EIT_BAD_TEMPLATE;
3532 einfo.ei_u.ei_bad_template.ei_reason = gettext("Illegal range "
3533 "value");
3534 (void) tmpl_errors_add_im(errs, rc, pg_pattern->sc_parent,
3535 pg_pattern, pg, pattern, prop, NULL, &einfo);
3536 return (rc);
3537 }
3538
3539 /* Set up error info before entering loop. */
3540 CLEAR_ERROR_INFO(&einfo);
3541 einfo.ei_type = EIT_RANGE;
3542 einfo.ei_u.ei_range.ei_rtype = type;
3543
3544 /* Compare numeric values of the property to the range. */
3545 for (v = uu_list_first(prop->sc_property_values);
3546 v != NULL;
3547 v = uu_list_next(prop->sc_property_values, v)) {
3548 if (value_in_range(v, type, ranges, count) == 1)
3549 continue;
3550 if (type == SCF_TYPE_COUNT) {
3551 einfo.ei_u.ei_range.ei_uvalue = v->sc_u.sc_count;
3552 } else {
3553 einfo.ei_u.ei_range.ei_ivalue = v->sc_u.sc_integer;
3554 }
3555 rc = TVS_VALIDATION;
3556 if (add_scf_error(errs, SCF_TERR_RANGE_VIOLATION, pg_pattern,
3557 pg, pattern, prop, v, &einfo) != 0) {
3558 return (rc);
3559 }
3560 }
3561
3562 return (rc);
3563 }
3564
3565 /*
3566 * If the prop_pattern has value constraints, verify that all the values
3567 * for the property at prop are legal values.
3568 *
3569 * pg is the property group that holds prop, and pg_pattern is the
3570 * pg_pattern for the property group. pg and pg_pattern are only used for
3571 * error reporting.
3572 */
3573 static tmpl_validate_status_t
tmpl_validate_values(pgroup_t * prop_pattern,property_t * prop,pgroup_t * pg,pgroup_t * pg_pattern,tmpl_errors_t * errs)3574 tmpl_validate_values(pgroup_t *prop_pattern, property_t *prop, pgroup_t *pg,
3575 pgroup_t *pg_pattern, tmpl_errors_t *errs)
3576 {
3577 int found;
3578 uint_t i;
3579 avalues_t *legal;
3580 tmpl_validate_status_t r;
3581 tmpl_validate_status_t rc = TVS_SUCCESS;
3582 value_t *v;
3583
3584 /* Get list of legal values. */
3585 r = av_get_values(prop_pattern, SCF_PROPERTY_TM_CONSTRAINT_NAME,
3586 prop->sc_value_type, &legal);
3587 switch (r) {
3588 case TVS_BAD_CONVERSION:
3589 (void) tmpl_errors_add_im(errs, r, pg->sc_parent, pg_pattern,
3590 pg, prop_pattern, prop, NULL, NULL);
3591 return (r);
3592 case TVS_NOMATCH:
3593 /* No constraints in template. */
3594 return (TVS_SUCCESS);
3595 case TVS_SUCCESS:
3596 /* process the constraints. */
3597 break;
3598 default:
3599 assert(0);
3600 abort();
3601 }
3602
3603 /* Check the property values against the legal values. */
3604 for (v = uu_list_first(prop->sc_property_values);
3605 v != NULL;
3606 v = uu_list_next(prop->sc_property_values, v)) {
3607 /* Check this property value against the legal values. */
3608 found = 0;
3609 for (i = 0; (i < legal->av_count) && (found == 0); i++) {
3610 switch (v->sc_type) {
3611 case SCF_TYPE_BOOLEAN:
3612 case SCF_TYPE_COUNT:
3613 if (av_get_unsigned(legal, i) ==
3614 v->sc_u.sc_count) {
3615 found = 1;
3616 }
3617 break;
3618 case SCF_TYPE_INTEGER:
3619 if (av_get_integer(legal, i) ==
3620 v->sc_u.sc_integer) {
3621 found = 1;
3622 }
3623 break;
3624 default:
3625 if (strcmp(av_get_string(legal, i),
3626 v->sc_u.sc_string) == 0) {
3627 found = 1;
3628 }
3629 break;
3630 }
3631 }
3632 if (found == 0) {
3633 rc = TVS_VALIDATION;
3634 if (add_scf_error(errs,
3635 SCF_TERR_VALUE_CONSTRAINT_VIOLATED, pg_pattern, pg,
3636 prop_pattern, prop, v, NULL) != 0) {
3637 /*
3638 * Exit loop if no longer able to report
3639 * errors.
3640 */
3641 break;
3642 }
3643 }
3644 }
3645
3646 out:
3647 av_destroy(legal);
3648 return (rc);
3649 }
3650
3651 /*
3652 * Verify the following items about the values of property, prop.
3653 *
3654 * - The values all have the type specified by the prop_pattern at
3655 * pattern.
3656 * - Check numeric values against range constraints.
3657 * - If the prop_pattern has one or more value constraints, validate
3658 * the property's values against the constraints.
3659 *
3660 * pg is the property group that holds prop, and pg_pattern is the
3661 * pg_pattern for the property group. pg and pg_pattern are only used for
3662 * error reporting.
3663 */
3664 static tmpl_validate_status_t
tmpl_validate_value_constraints(pgroup_t * pattern,property_t * prop,pgroup_t * pg,pgroup_t * pg_pattern,tmpl_errors_t * errs)3665 tmpl_validate_value_constraints(pgroup_t *pattern, property_t *prop,
3666 pgroup_t *pg, pgroup_t *pg_pattern, tmpl_errors_t *errs)
3667 {
3668 tmpl_validate_status_t r;
3669 tmpl_validate_status_t rc;
3670
3671 rc = tmpl_validate_value_range(pattern, prop, pg, pg_pattern, errs);
3672 r = tmpl_validate_values(pattern, prop, pg, pg_pattern, errs);
3673 if (r != TVS_SUCCESS)
3674 rc = r;
3675
3676 return (rc);
3677 }
3678
3679 /*
3680 * Perform the following validations on the property, prop.
3681 *
3682 * - Verify that the property's type agrees with the type specified in
3683 * the prop_pattern template, tmpl.
3684 * - Verify the cardinality.
3685 * - Verify that the property values satisfy the constraints specified
3686 * by the template.
3687 *
3688 * pg is the property group that holds prop, and pg_pattern is the
3689 * pg_pattern for the property group. pg and pg_pattern are only used for
3690 * error reporting.
3691 */
3692 static tmpl_validate_status_t
tmpl_validate_prop(property_t * prop,pgroup_t * tmpl,pgroup_t * pg,pgroup_t * pg_pattern,tmpl_errors_t * errs)3693 tmpl_validate_prop(property_t *prop, pgroup_t *tmpl, pgroup_t *pg,
3694 pgroup_t *pg_pattern, tmpl_errors_t *errs)
3695 {
3696 scf_tmpl_error_type_t ec;
3697 error_info_t einfo;
3698 tmpl_validate_status_t r;
3699 tmpl_validate_status_t rc = TVS_SUCCESS;
3700 int status;
3701 scf_type_t type;
3702
3703 r = prop_pattern_type(tmpl, &type);
3704 switch (r) {
3705 case TVS_SUCCESS:
3706 if (type == SCF_TYPE_INVALID) {
3707 rc = TVS_INVALID_TYPE_SPECIFICATION;
3708 r = tmpl_errors_add_im(errs, rc, pg->sc_parent, NULL,
3709 pg, tmpl, NULL, NULL, NULL);
3710 if (r != TVS_SUCCESS) {
3711 /*
3712 * Give up if we can no longer accumulate
3713 * errors.
3714 */
3715 return (rc);
3716 }
3717 } else {
3718 if (property_is_type(prop, type) == 0) {
3719 CLEAR_ERROR_INFO(&einfo);
3720 rc = TVS_VALIDATION;
3721 ec = SCF_TERR_WRONG_PROP_TYPE;
3722 einfo.ei_type = EIT_PROP_TYPE;
3723 einfo.ei_u.ei_prop_type.ei_specified = type;
3724 einfo.ei_u.ei_prop_type.ei_actual =
3725 prop->sc_value_type;
3726 status = add_scf_error(errs, ec,
3727 pg_pattern, pg, tmpl, prop, NULL, &einfo);
3728 if (status != 0) {
3729 /*
3730 * Give up if we can no longer
3731 * accumulate errors.
3732 */
3733 return (rc);
3734 }
3735 }
3736 }
3737 break;
3738 case TVS_MISSING_TYPE_SPECIFICATION:
3739 /*
3740 * A null type specification means that we do not need to
3741 * check the property's type.
3742 */
3743 break;
3744 default:
3745 rc = r;
3746 }
3747
3748 /* Validate the cardinality */
3749 r = tmpl_validate_cardinality(tmpl, prop, pg, pg_pattern, errs);
3750 if (r != TVS_SUCCESS)
3751 rc = r;
3752
3753 /* Validate that property values satisfy constraints. */
3754 r = tmpl_validate_value_constraints(tmpl, prop, pg, pg_pattern, errs);
3755 if (r != TVS_SUCCESS)
3756 rc = r;
3757
3758 return (rc);
3759 }
3760
3761 /*
3762 * Validate the property group at pg by performing the following checks:
3763 *
3764 * - Verify that the types of the pg and the pg_pattern are
3765 * compatible.
3766 * - Verify the properties in the pg.
3767 * - Verify that required properties are present.
3768 */
3769 static tmpl_validate_status_t
tmpl_validate_pg(entity_t * e,pgroup_t * pg,tmpl_errors_t * errs)3770 tmpl_validate_pg(entity_t *e, pgroup_t *pg, tmpl_errors_t *errs)
3771 {
3772 error_info_t einfo;
3773 const char *pg_pattern_type; /* Type declared by pg_pattern. */
3774 pgroup_t *pg_pattern; /* Prop. group for pg_pattern */
3775 property_t *prop;
3776 pgroup_t *prop_pattern;
3777 tmpl_validate_status_t r;
3778 tmpl_validate_status_t rc = TVS_SUCCESS;
3779 int stat;
3780
3781 /*
3782 * See if there is a pg_pattern for this property group. If it
3783 * exists, use it to validate the property group. If there is no
3784 * pg_pattern, then there is no validation to do.
3785 */
3786 rc = tmpl_find_pg_pattern(e, pg, &pg_pattern);
3787 switch (rc) {
3788 case TVS_SUCCESS:
3789 break;
3790 case TVS_BAD_TEMPLATE:
3791 CLEAR_ERROR_INFO(&einfo);
3792 einfo.ei_type = EIT_BAD_TEMPLATE;
3793 einfo.ei_u.ei_bad_template.ei_reason = gettext("Property "
3794 "group name too long");
3795 (void) tmpl_errors_add_im(errs, rc, e, NULL, pg, NULL, NULL,
3796 NULL, &einfo);
3797 return (rc);
3798 default:
3799 assert(0);
3800 abort();
3801 }
3802 if (pg_pattern == NULL)
3803 return (TVS_SUCCESS);
3804
3805 /*
3806 * If the pg_pattern declares a type, verify that the PG has the
3807 * correct type.
3808 */
3809 pg_pattern_type = find_type_specification(pg_pattern);
3810 if ((pg_pattern_type != NULL) &&
3811 (*pg_pattern_type != 0)) {
3812 if ((pg->sc_pgroup_type != NULL) &&
3813 (*(pg->sc_pgroup_type) != 0)) {
3814 if (strcmp(pg_pattern_type,
3815 pg->sc_pgroup_type) != 0) {
3816 rc = TVS_VALIDATION;
3817 stat = add_scf_error(errs,
3818 SCF_TERR_WRONG_PG_TYPE, pg_pattern, pg,
3819 NULL, NULL, NULL, NULL);
3820 if (stat != 0) {
3821 /*
3822 * If we can no longer accumulate
3823 * errors, return without trying to
3824 * do further validation.
3825 */
3826 return (rc);
3827 }
3828 }
3829 } else {
3830 rc = TVS_MISSING_PG_TYPE;
3831 r = tmpl_errors_add_im(errs, rc, e, pg_pattern, pg,
3832 NULL, NULL, NULL, NULL);
3833 if (r != TVS_SUCCESS) {
3834 /*
3835 * If we can no longer accumulate errors,
3836 * return without trying to do further
3837 * validation.
3838 */
3839 return (rc);
3840 }
3841 }
3842 }
3843
3844 /* Verify the properties in the property group. */
3845 prop = NULL;
3846 while ((prop = next_property(pg, prop)) != NULL) {
3847 r = tmpl_find_prop_pattern(e, pg_pattern, prop, &prop_pattern);
3848 switch (r) {
3849 case TVS_SUCCESS:
3850 /* Found match. Validate property. */
3851 break;
3852 case TVS_NOMATCH:
3853 /* No prop_patern. Go on to next property. */
3854 continue;
3855 case TVS_BAD_TEMPLATE:
3856 CLEAR_ERROR_INFO(&einfo);
3857 einfo.ei_type = EIT_BAD_TEMPLATE;
3858 einfo.ei_u.ei_bad_template.ei_reason =
3859 gettext("prop_pattern name too long");
3860 (void) tmpl_errors_add_im(errs, r, e, NULL, pg, NULL,
3861 NULL, NULL, &einfo);
3862 continue;
3863 default:
3864 assert(0);
3865 abort();
3866 }
3867 r = tmpl_validate_prop(prop, prop_pattern, pg, pg_pattern,
3868 errs);
3869 if (r != TVS_SUCCESS)
3870 rc = r;
3871 }
3872
3873 /*
3874 * Confirm required properties are present.
3875 */
3876 r = tmpl_required_props_present(e, pg, pg_pattern, errs);
3877 if (r != TVS_SUCCESS)
3878 rc = r;
3879
3880 return (rc);
3881 }
3882
3883 /*
3884 * Validate that the property groups in the entity conform to the template
3885 * specifications. Specifically, this means do the following:
3886 *
3887 * - Loop through the property groups in the entity skipping the ones
3888 * that are of type "template".
3889 *
3890 * - For the PG search for the corresponding template_pg_pattern
3891 * property group. It is possible that one may not exist.
3892 *
3893 * - Verify that the PG is in conformance with the pg_pattern
3894 * specification if it exists.
3895 */
3896 static tmpl_validate_status_t
tmpl_validate_entity_pgs(entity_t * e,tmpl_errors_t * errs)3897 tmpl_validate_entity_pgs(entity_t *e, tmpl_errors_t *errs)
3898 {
3899 composed_pg_t *cpg;
3900 uu_avl_t *pgroups;
3901 pgroup_t *pg;
3902 tmpl_validate_status_t r;
3903 tmpl_validate_status_t rc = TVS_SUCCESS;
3904
3905 assert(e->sc_etype == SVCCFG_INSTANCE_OBJECT);
3906
3907 pgroups = e->sc_u.sc_instance.sc_composed;
3908 for (cpg = uu_avl_first(pgroups);
3909 cpg != NULL;
3910 cpg = uu_avl_next(pgroups, cpg)) {
3911 if (strcmp(cpg->cpg_type, SCF_GROUP_TEMPLATE) == 0)
3912 continue;
3913 pg = CPG2PG(cpg);
3914 if ((r = tmpl_validate_pg(e, pg, errs)) != TVS_SUCCESS)
3915 rc = r;
3916 }
3917
3918 return (rc);
3919 }
3920
3921 /*
3922 * Validate the instance, e, by performing the following checks:
3923 *
3924 * - Verify template consistency.
3925 *
3926 * - Validate each property group in the entity is in conformance
3927 * with the template specifications.
3928 *
3929 * - Verify that all required property groups are present in the
3930 * entity.
3931 */
3932 static tmpl_validate_status_t
tmpl_validate_instance(entity_t * e,tmpl_errors_t * errs)3933 tmpl_validate_instance(entity_t *e, tmpl_errors_t *errs)
3934 {
3935 tmpl_validate_status_t r;
3936 tmpl_validate_status_t rc = TVS_SUCCESS;
3937 int status;
3938 tv_errors_t *ste;
3939
3940 /* Prepare to collect errors for this instance. */
3941 ste = tv_errors_create(e->sc_fmri);
3942 status = uu_list_insert_after(errs->te_scf, errs->te_cur_scf, ste);
3943 assert(status == 0);
3944 errs->te_cur_scf = ste;
3945
3946 /* Verify template consistency */
3947 rc = tmpl_consistency(e, errs);
3948
3949 /* Validate the property groups in the entity. */
3950 r = tmpl_validate_entity_pgs(e, errs);
3951 if (r != TVS_SUCCESS)
3952 rc = r;
3953
3954 /* Verify that all required property groups are present. */
3955 r = tmpl_required_pg_present(e, errs);
3956 if (r != TVS_SUCCESS)
3957 rc = r;
3958
3959 return (rc);
3960 }
3961
3962 /*
3963 * First validate the instances of the service.
3964 */
3965 static tmpl_validate_status_t
tmpl_validate_service(entity_t * svc,tmpl_errors_t * errs)3966 tmpl_validate_service(entity_t *svc, tmpl_errors_t *errs)
3967 {
3968 entity_t *inst;
3969 tmpl_validate_status_t r;
3970 tmpl_validate_status_t rc = TVS_SUCCESS;
3971
3972 assert(svc->sc_etype == SVCCFG_SERVICE_OBJECT);
3973
3974 load_general_templates(svc);
3975
3976 /* Validate the service's instances. */
3977 for (inst = uu_list_first(svc->sc_u.sc_service.sc_service_instances);
3978 inst != NULL;
3979 inst = uu_list_next(svc->sc_u.sc_service.sc_service_instances,
3980 inst)) {
3981 load_instance_restarter(inst);
3982 build_composed_instance(inst);
3983 r = tmpl_validate_instance(inst, errs);
3984 if (r != TVS_SUCCESS)
3985 rc = r;
3986 demolish_composed_instance(inst);
3987 }
3988
3989 return (rc);
3990 }
3991
3992 /*
3993 * Validate all services and instances in the bundle against their
3994 * templates. If err_list is not NULL, a tmpl_errors structure will be
3995 * allocated and its address will be returned to err_list. This structure
3996 * can be used to generate error messages.
3997 */
3998 tmpl_validate_status_t
tmpl_validate_bundle(bundle_t * bndl,tmpl_errors_t ** err_list)3999 tmpl_validate_bundle(bundle_t *bndl, tmpl_errors_t **err_list)
4000 {
4001 tmpl_errors_t *errs = NULL;
4002 entity_t *svc;
4003 tmpl_validate_status_t r;
4004 tmpl_validate_status_t rc = TVS_SUCCESS;
4005
4006 if (err_list != NULL)
4007 *err_list = NULL;
4008 if (bndl->sc_bundle_type != SVCCFG_MANIFEST) {
4009 semerr(gettext("Bundle is not a manifest. Unable to validate "
4010 "against templates.\n"));
4011 return (TVS_FATAL);
4012 }
4013
4014 errs = tmpl_errors_create();
4015 if (errs == NULL)
4016 uu_die(emesg_nomem);
4017
4018 lscf_prep_hndl(); /* Initialize g_hndl */
4019 if (load_init() != 0)
4020 uu_die(emesg_nomem);
4021
4022 /*
4023 * We will process all services in the bundle, unless we get a
4024 * fatal error. That way we can report all errors on all services
4025 * on a single run of svccfg.
4026 */
4027 for (svc = uu_list_first(bndl->sc_bundle_services);
4028 svc != NULL;
4029 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
4030 if (svc->sc_etype != SVCCFG_SERVICE_OBJECT) {
4031 semerr(gettext("Manifest for %s contains an object "
4032 "named \"%s\" that is not a service.\n"),
4033 bndl->sc_bundle_name, svc->sc_name);
4034 tmpl_errors_destroy(errs);
4035 load_fini();
4036 return (TVS_FATAL);
4037 }
4038 if ((r = tmpl_validate_service(svc, errs)) != TVS_SUCCESS)
4039 rc = r;
4040 if (r == TVS_FATAL)
4041 break;
4042 }
4043
4044 if (err_list == NULL) {
4045 tmpl_errors_destroy(errs);
4046 } else {
4047 *err_list = errs;
4048 }
4049
4050 load_fini();
4051
4052 return (rc);
4053 }
4054