svccfg_tmpl.c revision 1f6eb0216cb17ca5fdff9563329f1dda47c8b801
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* This file provides the code that allows svccfg(1M) to validate a
* manifest against the template specifications. svccfg uses the
* validation facilities for the import and validate subcommands.
*
* There are three entry points -- tmpl_validate_bundle(),
* tmpl_errors_print() and tmpl_errors_destroy(). svccfg calls
* tmpl_validate_bundle() to validate a bundle. tmpl_validate_bundle()
* returns a pointer to a tmpl_errors_t. This is a pointer to information
* about any validation errors that were found. If an error was detected,
* svccfg calls tmpl_errors_print() to print the error information. Once
* the error information is printed, svccfg calls tmpl_errors_destroy() to
* free the memory associated with the tmpl_errors_t.
*
* libscf's scf_tmpl.c performs similar checks to the ones described in
* this paragraph. Any changes to the algorithms in this file should also
* be infcorporated into scf_tmpl.c. The reason that there are two bodies
* of code is that they work on different data structures.
* tmpl_validate_bundle() validates each instance of each service in the
* bundle. The following checks are performed on each instance:
*
* 1. Verify template consistency.
* A. No conflicting definitions of "pg_pattern" are allowed
* within a single instance.
* B. Templates at a narrow target (e.g. instance) which define
* property groups already templated at a broad target
* (e.g. delegate or all) are strongly discouraged.
* C. Developers may not define a template which specifies a
* single prop_pattern name with differing types on the same
* target entity.
* D. If a pg_pattern has a required attribute with a value of
* true, then its name and type attributes must be
* specified.
* E. If a prop_pattern has a required attribute with a value
* of true, then its type attribute must be specified.
* F. If a prop_pattern has an include_values element make sure
* that the appropriate constraints or values element has
* also been declared.
* 2. Validate that each property group in the instance is in
* conformance with the template specifications.
* A. Verify that the types of the PG and the pg_pattern are
* compatible.
* B. Verify properties of the PG against the prop_patterns in
* the template.
* o Verify property's type.
* o Verify cardinality.
* o Vefiy that property values satisfy the constraints
* imposed by the prop_pattern.
* C. Verify that required properties are present.
* 3. Verify that all required property groups are present in the
* insance.
*
* tmpl_validate_bundle() is called after svccfg has processed the manifest
* file. The manifest is represented in memory by a set of entity_t,
* pgroup_t, property_t and value_t structures. These structures are
* defined in svccfg.h.
*
* tmpl_validate_bundle() calls tmpl_validate_service() for each service in
* the bundle, and tmpl_validate_service() then calls
* tmpl_validate_instance() for each instance in the service.
* tmpl_validate_instance() is the function that does the real work of
* validation against the template specification.
*
* Subsystems:
* ==========
*
* General Templates:
* -----------------
* In order to perform the validation specified by 1.B above, we need to
* load the templates specifications for the global service and the
* instance's restarter. This information is loaded from the repository
* and it is held in memory using the entity_t, pgroup_t, property_t and
* value_t hierarchy of structures. When a service is processed,
* load_general_templates() is called to load the information for the
* global service and restarter that is declared at the service level. The
* sc_service.sc_global and sc_service.sc_restarter members of the
* service's entity_t point to the information for the global and restarter
* services.
*
* The instance portion of a manifest can declare an instance specific
* restarter. If this is the case, load_instance_restarter() will load the
* information for that restarter, and it is saved in the
* sc_instance.sc_instance_restarter member of the entity_t that represents
* the instance.
*
* Composed Properties:
* -------------------
* We need the ability to process the composed properties of an instance.
* That is to say if an instance defines a property, it overrides any
* definition in the service. Otherwise, the service's definition is
* inherited in the instance.
*
* In an entity_t, the sc_instance.sc_composed member points to a
* uu_avl tree of composed property groups (composed_pg_t) for the
* instance. The composed_pg_t has two members, cpg_instance_pg and
* cpg_service_pg, that point to the instance and service property group
* definitions respectively. Either of these may be NULL indicating that
* only an instance or service definition exists in the manifest.
*
* In the case where both the instance and the service define a property
* group, the properties must be composed. This is done by
* compose_props(). The compose_pg_t holds the composed properties in a
* uu_avl_tree at cpf_compose_props. This is a tree of property_t
* structures. If a property is defined in both the instance and service
* property group, the tree will hold the instance definition. If the
* property is defined at only one level, the tree will hold the property_t
* for that level. Thus, the tree is truly a set of composed properties of
* the property group.
*
* Property Group Iteration:
* ------------------------
* A number of functions must iterate through an instance's property groups
* looking for the ones that define a pg_pattern or a prop_pattern. To be
* specific, the iteration starts with the composed view of the instance.
* It then proceeds through the restarter information and finally moves on
* to the global service. The pg_iter_t structure holds the information
* that is needed to implement this type of iteration. pg_iter_create()
* creates one of these iterators, and pg_iter_destroy() frees the memory
* associated with the pg_iter_t. next_pattern_pg(), is used to step
* through the iteration.
*
* Error Reporting:
* ---------------
* While performing the templates validation checks, svccfg collects
* information for all the errors that it finds. Because of this you will
* see many places in the code where a loop is not exited when an error is
* encountered. We note that fact that an error has occurred, but continue
* in the loop to see if there are more validation errors. The error code
* of the last error that is encountered is returned. This works, because
* the callers of tmpl_validate_bundle() only look to see whether or not
* the return code is TVS_SUCCESS.
*
* The information for reporting the errors is collected in a tmpl_errors_t
* structure, and tmpl_validate_bundle() returns the address of this
* structure. The caller of tmpl_validate_bundle() can then call
* tmpl_errors_print() to display the error information to the user.
*
* There are two categories of errors. Some errors are seen when
* processing the information in the manifest. This type of error is only
* seen by svccfg when it is importing or validating a manifest. The other
* type of error consists of template validation errors. These errors can
* be seen when processing a manifest or when performing a templates
* validation of the information associated with an FMRI in the the
* repository. tmpl_errors_add_im() is used to capture error information
* about the first type of error, and add_scf_error() is used to capture
* error information about the second type of error.
*
* The distinction is important when printing the error information. The
* fuctions for printing the first type of error reside in this file, since
* these errors will only be seen by the functions in this file. The
* functions for printing the template validation errors reside in libscf,
* because these errors are of a more general nature.
*
* Thus, tmpl_errors_t has two lists -- one for each type of error.
* te_list is a list of im_tmpl_error_t structures that represent the first
* type of error. te_scf is a list of tv_errors_t structures that hold
* information about general template validation errors.
* tmpl_errors_print() processes both lists to print information about all
* errors. In tmpl_errors_print() im_tmpl_error_print() is used to print
* the errors that are specific to this file. scf_tmpl_strerror() provides
* the errors messages for general templates errors.
*
* As was mentioned in the previous paragraph, im_tmpl_error_print() is
* responsible for printing the errors that are specific to this file.
* Based on the error code, it dispatches to one of
* im_perror_bad_conversion(), im_perror_bad_template(),
* im_perror_invalid_type(), im_perror_missing_pg_type() or
* im_perror_missing_type(). The rest of the im_perror_* functions provide
* services to these error specific functions by printing common
* information.
*
* im_perror_item() is the heart of this message printing subsystem. It is
* called directly or indirectly by all of the other im_perror_* functions.
* im_perror_item() prints a single item of error information. If svccfg
* is running in interactive mode, im_perror_item() prints each item on a
* single line, so that they are readable by a human. In non-interactive
* mode, all items are printed on a single line separated by semi-colons.
*/
#include <assert.h>
#include <errno.h>
#include <inttypes.h>
#include <libintl.h>
#include <limits.h>
#include <libscf.h>
#include <libscf_priv.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include "svccfg.h"
/*
* Clear error_info_t structure.
*/
/*
* Retrieve the property group pointer from the composed_pg structure.
*/
/*
* Convert a pointer to an empty string into a NULL pointer.
*/
#define EMPTY_TO_NULL(p) (((p) && (*(p) == 0)) ? NULL : (p))
/* uu_avl and uu_list debugging bits. */
#ifdef NDEBUG
#define TMPL_DEBUG_AVL_POOL UU_DEFAULT
#define TMPL_DEBUG_LIST UU_DEFAULT
#define TMPL_DEBUG_LIST_POOL UU_DEFAULT
#define TMPL_DEBUG_TREE UU_DEFAULT
#else
#define TMPL_DEBUG_AVL_POOL UU_AVL_POOL_DEBUG
#define TMPL_DEBUG_LIST UU_LIST_DEBUG
#define TMPL_DEBUG_TREE UU_AVL_DEBUG
#endif /* NDEBUG */
/*
* Structures and enums that are used in producing error messages:
*
* error_info_t is used to pass information about an error to
* tmpl_errors_add_im() and add_scf_error(). tmpl_errors_add_im() collects
* the error information and stores it in an im_tmpl_error_t. The
* im_tmpl_error_t is linked into the tmpl_errors_t, so that the captured
* information can be used later when error messages are printed.
*
* tv_errors_t is used to keep track of error information for general
* template errors that are known by libscf. add_scf_error() captures the
* error information for use in this structure.
*/
/*
* enum to designate the type of data that is held in a err_info structure.
*/
typedef enum err_info_type {
EIT_NONE, /* No values in the structure */
EIT_BAD_TEMPLATE, /* Reason that template is bad */
EIT_CARDINALITY, /* Ranges for property cardinality */
EIT_INCLUDE_VALUES, /* include_values type attribute */
EIT_MISSING_PG, /* Name of missing pg */
EIT_MISSING_PROP, /* Name of missing property */
EIT_PATTERN_CONFLICT, /* Conflicting pattern definition */
EIT_PROP_TYPE, /* Value with invalid type */
EIT_RANGE /* Value that is out of range */
/*
* Structure to hold information that will be used in generating error
* messages.
*/
typedef struct error_info {
union {
/* EIT_BAD_TEMPLATE */
struct {
const char *ei_reason;
/* EIT_CARDINALITY */
struct {
/* EIT_INCLUDE_VALUES */
struct {
const char *ei_type;
/* EIT_MISSING_PG */
struct {
const char *ei_pg_name; /* Name of missing pg */
const char *ei_pg_type; /* Type of missing pg */
/* EIT_MISSING_PROP */
struct {
const char *ei_prop_name; /* Name of prop */
/* EIT_PATTERN_CONFLICT */
struct {
/* EIT_PROP_TYPE */
struct {
} ei_prop_type;
/* EIT_RANGE */
struct {
} ei_range;
} ei_u;
} error_info_t;
/*
* Structure with information about a template violation. This structure
* is for use with in memory representations of the manifest and template.
* See scf_tmpl_error_t for use with repository representations. Some of
* the pointers may be NULL for some types of errors.
*/
typedef struct im_tmpl_error {
/*
* This structure holds the data that will be used by scf_tmpl_strerror()
* for printing template validation errors.
*/
typedef struct tv_errors {
} tv_errors_t;
/*
* Structure to collect template validation errors.
*/
struct tmpl_errors {
};
/* End of structures used in error processing. */
/*
* Property group types that are of interest to us. See pgroup_type().
*/
typedef enum pg_type {
} pg_type_t;
/*
* Structure to keep track of a set of ASTRING property values for a
* property. The consumer may wish to have the ASTRING property values
* converted to a numeric form which is the reason for the av_v union.
* This structure is returned by av_get_values() and is accessed by
* av_get_integer(), av_get_string() and av_get_unsigned().
*/
typedef struct avalues {
union {
const char **av_string; /* String values */
} av_v; /* Container for the values */
} avalues_t;
/*
* composed_pg_t contains the information that is needed to compose a
* property group. See the section on Composed Properties in the block
* comment at the beginning of this file. The composed_pg structures are
* linked into a uu_avl tree. The tree is at sc_instance.sc_composed in
* the entity_t.
*/
struct composed_pg {
/*
* Property group is uniquely identified by its name and type.
* These two elements point to the name and type in a pgroup_t
* (either service or instance), so they do not need to be
* allocated or freed.
*/
const char *cpg_name;
const char *cpg_type;
/* References to the actual property group definitions. */
/* Composed properties of the property group. */
};
/*
* Prefixes for standard property names. Used in
* include_values_support().
*/
typedef struct prop_prefix {
const char *pp_prefix;
/*
* Store a legal range for a property allowing for either signed or
* unsigned ranges. It is used to store a range from a template
* constraint element of a prop_pattern. The structure is returned by
* get_ranges() and is used by value_in_range() to validate the values of a
* property.
*/
typedef struct range {
union {
struct {
} rng_unsigned;
struct {
} rng_signed;
} rng_u;
} range_t;
/*
* This enum defines the levels where templates can be defined. See the
* pg_iter structure below.
*/
typedef enum tmpl_level {
TL_NOLEVEL = 0, /* No level yet specified. */
TL_INSTANCE, /* Instance templates. */
TL_COMPOSED, /* Composed instance. */
TL_SERVICE, /* Service wide templates. */
TL_RESTARTER, /* Templates from restarter manifest. */
TL_GLOBAL /* SMF wide templates. */
} tmpl_level_t;
/*
* pg_iter is a structure that allows us to iterate through property groups
* in an instance followed by the property groups of the instance's
* service, the instance's restarter and finally the global service. See
* the Property Group Iteration section of the block comment at the
* beginning of this file.
*/
typedef struct pg_iter {
const char *pgi_restrict; /* Only return PGs of this type */
union {
} pgi_current; /* Current property group. */
} pg_iter_t;
/*
* enum to distinguish between pg_patterns and prop_patterns. It is used
* in the ptrn_info_t structure. See below.
*/
typedef enum ptrn_type {
} ptrn_type_t;
/*
* Structure of information about a pg_pattern or a prop_pattern. It is
* used for template consistency checks. gather_pattern() is used to
* gather information for all the pg_patterns or prop_patterns in an
* instance. It allocates a ptrn_info_t for each of these and adds them to
* an avl tree that is held by tmpl_consistency().
*/
typedef struct ptrn_info {
const char *pi_name; /* Name attribute. */
const char *pi_type; /* Type attribute. */
const char *pi_target; /* Target attribute - only PG_PATTERN */
const char *pi_pgp_name; /* Name of the pg pattern. Only */
/* used for PROP_PATTERN. */
/* the prop_pattern defined by this */
/* structure. Only used for */
/* PROP_PATTERN. */
} ptrn_info_t;
static const char *emesg_nomem;
/*
* Pool for trees of composed property groups.
*/
static uu_avl_pool_t *composed_pg_pool;
/*
* Pool for trees of composed properties.
*/
static uu_avl_pool_t *composed_prop_pool;
/*
* Pool for lists of errors in the internal representation.
*/
static uu_list_pool_t *inmem_errors_pool;
/*
* Pool for trees of pg_pattern info structures (ptrn_info_t).
*/
static uu_avl_pool_t *ptrn_info_pool;
/*
* Pool for lists of template errors in the libscf representation.
*/
static uu_list_pool_t *tv_errors_pool;
/*
* Property name prefixes for constraints and values.
*/
static const char *constraint_prefixes[] = {
};
static const char *value_prefixes[] = {
};
/*
* Function to compare two composed_pg structures.
*/
/* ARGSUSED2 */
static int
{
int rc;
}
return (rc);
}
/* ARGSUSED2 */
static int
{
}
static composed_pg_t *
{
return (cpg);
}
static void
{
return;
/* Tear down composed property tree if we have one. */
NULL) {
/*
* Nothing to do other than getting the property
* out of the list. This cleans up the property's
* uu_avl_node.
*/
}
}
/* Clean up any pgroup_t references to us. */
}
}
/*
* Walk the property group at pg, and add its properties to the AVL tree at
* tree.
*/
static void
{
/*
* If there was no match, insert the property into
* the tree. If we do get a match, there is
* nothing to do. That is because we rely on our
* caller to process the instance properties first,
* and the instance properties override the service
* properties.
*/
}
}
}
/*
* The composed properties are stored in a uu_avl_tree. First we populate
* the tree with properties from the instance level property group. Then,
* we'll add the properties from the service level property group.
*/
static void
{
uu_strerror(uu_error()));
}
/*
* compose_props() is only called when there is both an instance
* and a service definition of the property group. This implies
* that neither cpg->cpg_instance_pg nor cpg->cpg_service_pg can be
* NULL.
*/
/*
* First add instance properties to the tree.
*/
/*
* Add service properties to the tree.
*/
}
/*
* This function is a utility for build_composed_instance().
*/
static void
{
/* First capture the instance property groups. */
cpg = composed_pg_create();
/* Since we do the instance first, there should be no match. */
}
/* Now capture the service property groups. */
cpg = composed_pg_create();
/* Get new composed_pg_t next at top of loop. */
} else {
/*
* Already have a composed_pg from instance
* processing. Just add the pointer to the service
* pg and compose the properties.
*/
}
}
}
static void
{
}
}
}
static void
{
return;
}
}
/*
* Return the number of values in prop.
*/
static size_t
{
}
static int
{
if (type == SCF_TYPE_BOOLEAN)
return (1);
if (type == SCF_TYPE_COUNT)
return (1);
if (type == SCF_TYPE_INTEGER)
return (1);
return (0);
}
static pg_type_t
{
return (PG_PATTERN_PG);
return (PROP_PATTERN_PG);
return (NORMAL_PG);
}
/*
* Search the property group at pg for a property named name. If the
* property group has a tree of composed properties, the tree will be
* searched for the property. Otherwise, the property group's linked list
* will be searched.
*/
static property_t *
{
/* This is not a composed property group. */
}
/*
* This is a composed property group, so look for the property in
* the AVL tree.
*/
}
/*
* Functions for manipulating the avalues structure.
*/
/*
* Free allocated memory referenced by the avalues structure. Then, free
* the structure itself.
*/
static void
{
return;
case SCF_TYPE_BOOLEAN:
case SCF_TYPE_COUNT:
break;
case SCF_TYPE_INTEGER:
break;
default:
/*
* We don't need to free the strings that are referenced by
* av_string. The strings are held in propery_t structures
* that will be freed at a later time.
*/
break;
}
}
/*
* Allocate and inialize an avalues structure. count represents the
* number of values the structure is expected to hold. type specifies how
* the consumer of the property values would like to see them represented.
* See comments for the av_get_values() more details on how type is used.
*
* The returned structure must be freed by calling av_destroy().
*
* NULL is returned if memory allocation fails.
*/
static avalues_t *
{
uint_t alloc_failed = 0;
return (NULL);
switch (type) {
case SCF_TYPE_BOOLEAN:
case SCF_TYPE_COUNT:
alloc_failed = 1;
break;
case SCF_TYPE_INTEGER:
alloc_failed = 1;
break;
default:
alloc_failed = 1;
}
if (alloc_failed) {
av_destroy(av);
return (NULL);
}
return (av);
}
/*
* Return the ith integer value in av.
*/
static int64_t
{
}
/*
* Return the ith string value in av.
*/
static const char *
{
}
/*
* Return the ith unsigned value in av.
*/
static uint64_t
{
}
/*
* Store the value in the ith slot of the av structure. If av is being
* used to store numeric values, the string at value will be converted to
* the appropriate numeric form.
*/
static tmpl_validate_status_t
{
char *endptr;
int64_t n;
case SCF_TYPE_BOOLEAN:
case SCF_TYPE_COUNT:
return (TVS_BAD_CONVERSION);
}
break;
case SCF_TYPE_INTEGER:
return (TVS_BAD_CONVERSION);
}
}
} else {
}
return (TVS_SUCCESS);
}
/*
* Find the property whose name is prop_name in the property group at pg.
* Read all the values of this property and return them in an avalues
* structure placing the address of the structure in *values. The caller
* must free the structure by calling av_destroy().
*
* The type parameter is used to indicate the type of information that the
* caller would like to consume. If it is one of the numeric types, the
* property value will be converted to the appropriate numeric type before
* placing it in the avalues struct. Decoding will be done before the
* conversion if necessary.
*/
static tmpl_validate_status_t
{
uint_t i;
value_t *v;
return (TVS_NOMATCH);
}
/* Collect the values. */
v != NULL;
if (rc != TVS_SUCCESS) {
av_destroy(av);
return (rc);
}
}
return (TVS_SUCCESS);
}
/*
* Find the property in pg whose name is prop_name. Return a pointer to
* the first astring value in that property.
*
* NULL is returned if there is no property named prop_name or if it does
* not have an astring value.
*/
static const char *
{
value_t *v;
return (NULL);
return (NULL);
if (v == NULL)
return (NULL);
}
/*
* Find the first property value of type SCF_TYPE_COUNT in the property at
* prop. Return the value to count.
*/
static tmpl_validate_status_t
{
return (TVS_NOMATCH);
return (TVS_SUCCESS);
}
/*
* pattern is a property group representing a pg_pattern or a
* prop_pattern. This function returns the name specification from the
* pg_pattern or prop_pattern.
*/
static const char *
{
}
/*
* pattern is a property group representing a pg_pattern or a prop_pattern.
* This function returns the type specification from the pg_pattern or
* prop_pattern.
*/
static const char *
{
}
/*
* Find the FMRI of the restarter for the entity, e. The restarter is the
* value of the "restarter" property in the "general" property group.
*/
static const char *
{
value_t *v;
if (v != NULL)
}
}
/*
* Didn't find the restarter.
*/
return (NULL);
}
/*
* prop_pattern points to a prop_pattern. This function finds the
* cardinality specification in the prop_pattern and returns the minimum
* and maximum values of the cardinality.
*
* Returns TVS_NOMATCH if either the cardinality minimum or maximum are
* missing.
*/
static tmpl_validate_status_t
{
SCF_GROUP_TEMPLATE_PROP_PATTERN) == 0);
return (TVS_NOMATCH);
if (rc != TVS_SUCCESS)
return (rc);
return (TVS_NOMATCH);
return (rc);
}
/*
* Ranges are represented as ASTRING values in the property at range_prop.
* The minimum and maximum of the range are separated by a comma.
*
* range_prop can contain multiple range values, so we return a pointer to
* an allocated array of range_t in ranges. This array must be freed by
* the caller using free(). count receives the number of range_t
* structures that are allocated.
*
* type tells us whether the range values should be treated as signed or
* unsigned. It must be SCF_TYPE_COUNT or SCF_TYPE_INTEGER.
*/
static tmpl_validate_status_t
{
char *endptr;
char *endptr2;
range_t *r;
r = safe_malloc(*count * sizeof (*r));
*ranges = r;
/* First get the minimum */
errno = 0;
if (type == SCF_TYPE_INTEGER) {
} else {
}
goto badtemplate;
if (*endptr != ',')
goto badtemplate;
/* Now get the maximum */
endptr++;
if (type == SCF_TYPE_INTEGER) {
} else {
}
(*endptr2 != 0))
goto badtemplate;
r++;
}
return (TVS_SUCCESS);
return (TVS_BAD_TEMPLATE);
}
static tv_errors_t *
tv_errors_create(const char *fmri)
{
return (ste);
}
static void
{
}
/*
* Given a property group and the name of a property within that property
* group, generate the name of the property group that holds the
* prop_pattern information for the property. The address of the generated
* name is returned to prop_pattern_pg_name. The memory holding the
* generated name must be freed using uu_free().
*/
static tmpl_validate_status_t
char **prop_pattern_pg_name)
{
char *name;
const char *unique;
/* Get the unique part of the pg_pattern's property group name. */
prefix_size) == 0);
/* Construct the prop pattern property group name. */
return (TVS_BAD_TEMPLATE);
}
return (TVS_SUCCESS);
}
/*
* Error message printing functions:
*/
/*
* Flags for use by im_perror_item.
*/
/*
* Print a single item of information about a validation failure. This
* function takes care of printing the appropriate decoration before the
* first item and between subsequent items.
*
* Parameters:
* out Stream to receive the output.
* desc Text describing the items
* item Address of the item to be displayed
* type Type of the item
* flags Used by im_perror_item to keep track of where it
* is. Caller should set flags to 0 before calling
* this function with the first item.
*/
static void
int *flags)
{
const char *cp;
const char *first_sep;
const char *subsequent_sep;
/* Nothing to print if item is NULL. */
return;
/* Establish separators for environment. */
/* Interactive mode - make messages readable */
first_sep = ":\n\t";
subsequent_sep = "\n\t";
} else {
/* Non-interactive - one line messages. */
first_sep = ": ";
subsequent_sep = "; ";
}
/* Print separator and description */
if (*flags & IPI_NOT_FIRST) {
} else {
*flags |= IPI_NOT_FIRST;
}
switch (type) {
case SCF_TYPE_BOOLEAN:
if (uval) {
} else {
}
break;
case SCF_TYPE_COUNT:
break;
case SCF_TYPE_INTEGER:
break;
default:
/*
* Treat everything else as a string, but escape any
* internal quotes.
*/
while (*cp != 0) {
if (*cp == '\"') {
} else {
}
cp++;
}
break;
}
}
/*
* Print erroneous FMRI.
*/
static void
{
if (i->ite_entity != NULL) {
}
}
/*
* Print erroneous property group name.
*/
static void
{
flags);
}
}
/*
* If srcflag is 1, print the template source of the pg_pattern or
* prop_pattern at pattern. Always print the name and type of the pattern.
*/
static void
{
void *c;
const char *name_string;
const char *type_string;
return;
switch (pgroup_type(pattern)) {
case PG_PATTERN_PG:
break;
case PROP_PATTERN_PG:
break;
default:
assert(0);
abort();
}
if (srcflag) {
}
c = (void *)find_name_specification(pattern);
c = (void *)find_type_specification(pattern);
}
/*
* Print information about the template specifications that were violated,
* so that the user can find the specification.
*/
static void
{
int srcflag = 1;
if (pg_pattern != NULL) {
srcflag = 0;
}
if (prop_pattern != NULL) {
}
}
/* Print error message for TVS_BAD_CONVERSION errors. */
static void
{
int flags = 0;
prefix);
}
/* Print error message for TVS_BAD_TEMPLATE errors. */
static void
{
int flags = 0;
}
/*
* Print error message for TVS_INVALID_TYPE_SPECIFICATION errors. This
* error occurs if a prop_pattern has an invalid type specification. Thus,
* it is an indication of an invalid template rather than a violation of a
* template.
*/
static void
{
int flags = 0;
const char *prop_pattern_name;
if (i->ite_prop_pattern != NULL) {
}
}
/*
* Print error message for TVS_MISSING_PG_TYPE errors. In this case the
* template specifies a type, but the property group itself has no type.
*/
static void
{
int flags = 0;
const char *type_spec;
if (i->ite_pg_pattern != NULL) {
}
}
/*
* Print error message for TVS_MISSING_TYPE_SPECIFICATION errors. A
* property group has a "required" attribute of true, but it does not have
* a type specification.
*/
static void
{
int flags = 0;
const char *pg_pattern_name;
"is missing the type attribute"), prefix);
if (i->ite_pg_pattern != NULL) {
}
}
static void
{
case TVS_BAD_CONVERSION:
break;
case TVS_BAD_TEMPLATE:
break;
break;
case TVS_MISSING_PG_TYPE:
break;
break;
case TVS_NOMATCH:
/*
* TVS_NOMATCH should be handled where it occurs. Thus,
* there are no error messages associated with it.
*/
assert(0);
abort();
break;
case TVS_SUCCESS:
break;
default:
assert(0);
abort();
}
}
static char *
{
char *c;
const char *fmt;
int size;
c = safe_malloc(size);
return (c);
}
static char *
{
char *c;
const char *fmt;
int size;
c = safe_malloc(size);
return (c);
}
/*
* Convert the value to a string. The returned value must be freed using
* free(3C).
*/
static const char *
{
char *c;
if (is_numeric_type(v->sc_type)) {
switch (v->sc_type) {
case SCF_TYPE_BOOLEAN:
c = gettext("false");
} else {
c = gettext("true");
}
break;
case SCF_TYPE_COUNT:
return (c);
case SCF_TYPE_INTEGER:
return (c);
}
} else {
}
return (safe_strdup(c));
}
/*
* Subscripts for common error data.
*/
#define ED_PG_NAME 0
#define ED_PROP_NAME 1
#define ED_TMPL_FMRI 2
#define ED_TMPL_PG_NAME 3
#define ED_TMPL_PG_TYPE 4
#define ED_TMPL_PROP_NAME 5
#define ED_TMPL_PROP_TYPE 6
#define ED_COUNT 7
/*
* This function converts the error information specified by the function
* parameters. It converts it to form needed by _scf_tmpl_add_error().
* _scf_tmpl_add_error() requires that the error information be in the form
* of allocated strings that can be freed when it is done with them. Thus,
* the bulk of this function is devoted to producing those allocated
* strings.
*
* Once the strings are ready, we call _scf_tmpl_add_error() to add an
* new error structure to errs.
*/
static int
{
char *c;
int i;
int rc;
/* Set values that are common to most error types. */
}
}
if (pg_pattern == NULL) {
if (prop_pattern != NULL) {
}
} else {
}
if (prop_pattern != NULL) {
}
/*
* All of the strings that we've found must be strduped. This is
* so that scf_tmpl_errors_destroy() can free them. We cannot use
* the flag argument of _scf_create_errors() to indicate that the
* strings should not be freed. The flag argument is an all or
* nothing thing. In the code below we need to convert integers to
* strings, and this requires memory allocation. Since we have to
* allocate memory for that data, we need to allocate it for every
* thing.
*/
for (i = 0; i < ED_COUNT; i++) {
continue;
}
/* actual, ev1 and ev2 are error code specific. */
switch (ec) {
break;
case SCF_TERR_WRONG_PG_TYPE:
/* Specified type. */
if (pg_pattern != NULL) {
}
}
/* Actual type. */
}
}
break;
case SCF_TERR_WRONG_PROP_TYPE:
break;
break;
case SCF_TERR_MISSING_PG:
break;
case SCF_TERR_MISSING_PROP:
break;
case SCF_TERR_RANGE_VIOLATION:
} else {
}
actual = c;
break;
break;
case SCF_TERR_INCLUDE_VALUES:
break;
break;
default:
assert(0);
abort();
};
return (rc);
}
/*
* Create and initialize a new im_tmpl_error structure and add it to the
* list of errors in errs. The rest of the parameters are used to
* initialize the im_tmpl_error structure.
*/
static tmpl_validate_status_t
{
int result;
ite->ite_entity = e;
return (TVS_SUCCESS);
}
/*
* pattern must point to a pg_pattern or a prop_pattern. This function
* finds the property named required and returns the property's value. If
* the property does not exist, false is return since it is the default.
*/
static int
{
SCF_GROUP_TEMPLATE_PG_PATTERN) == 0) ||
SCF_GROUP_TEMPLATE_PROP_PATTERN) == 0));
/* Default if there is no required property is false. */
return (0);
/* Retrieve the value of the required property. */
return (0);
/* No boolean property values, so return false. */
return (0);
}
/*
* Load the service's restarter instance and the global instance from the
* repository. This will allow us to use their templates in validating the
* service.
*
* There is no function to unload the general templates. The memory that
* is allocated by load_general_templates() will be freed automatically in
* internal_service_free() which is called by internal_bundle_free().
*/
static void
{
const char *restarter;
int is_global = 0;
int r;
/*
* If e is the global service, we only need to load the restarter.
*/
is_global = 1;
}
/*
* Load the templates for the service's restarter.
*/
/*
* During initial manifest import, restarter may
* not be in the repository yet. In this case we
* continue on without it.
*/
if (r == ENOMEM)
else
}
if (is_global == 0) {
/*
* During initial manifest import, global may not be in
* the repository yet.
*/
if (r == ENOMEM)
else
}
}
}
/*
* Load the instance specific restarter if one is declared.
*
* There is no corresponding unload_instance_restarter() function because
* it is not needed. The memory will be freed in internal_instance_free()
* when internal_bundle_free() is called.
*/
static void
{
const char *restarter;
int r;
restarter = find_restarter(i);
/* No instance specific restarter */
return;
}
if (r != 0) {
/*
* During initial manifest import, the restarter may not be
* in the repository yet. In this case we continue on
* without it.
*/
if (r == ENOMEM)
}
}
/*
* Find the next property after current in the property group at pg. If
* the property group contains a tree of composed properties, that tree is
* walked. Otherwise, we walk through the uu_list at sc_pgroup_props.
*/
static property_t *
{
/* Walk through composed property list. */
if (current) {
} else {
}
} else {
/* No composition available, so walk the list of properties */
if (current) {
} else {
}
}
return (prop);
}
static ptrn_info_t *
{
entity_t *e;
switch (pgroup_type(pat)) {
case PG_PATTERN_PG:
break;
case PROP_PATTERN_PG:
break;
default:
assert(0);
abort();
}
}
(*(info->pi_pgp_name) != 0));
/*
* Find the property group that defines the pg_pattern that
* holds this prop_pattern.
*/
if (e->sc_etype == SVCCFG_INSTANCE_OBJECT) {
} else {
}
}
return (info);
}
static void
{
return;
}
/*
* Walk through the property groups of the instance or service at e looking
* for definitions of pg_patterns or prop_patterns as specified by type.
* For each property group that matches type create a ptrn_info_t and add
* it to the avl tree at tree. If duplicates are found add an error entry
* to errs.
*/
static tmpl_validate_status_t
{
const char *selector;
switch (type) {
case PG_PATTERN:
break;
case PROP_PATTERN:
break;
default:
assert(0);
abort();
}
continue;
}
/* Get rid of old structure. */
}
/* No match. Insert the info. */
continue;
}
/* Got a match. Determine if it is a conflict. */
/* No conflicts if any wild cards. */
continue;
}
/*
* Name already matches, or we wouldn't have gotten
* here. Make sure that the type also matches.
*/
continue;
}
/*
* If we get to this point we have a conflict, and
* we need to generate the correct type of error.
*/
if (type == PG_PATTERN) {
rc = TVS_VALIDATION;
&einfo) != 0) {
/*
* If we can no longer accumulate
* errors, break out of the loop.
*/
break;
}
} else {
/*
* Possible conflicting prop_pattern. See if the
* prop_patterns are declared in the same
* pg_pattern.
*/
continue;
}
continue;
/* It is a real conflict. */
rc = TVS_VALIDATION;
&einfo) != 0) {
/*
* If we can no longer accumulate
* errors, break out of the loop.
*/
break;
}
}
}
return (rc);
}
/*
* Free the pg_iter structure.
*/
static void
{
if (i == NULL)
return;
uu_free(i);
}
/*
* Create a property group iterator for the instance at e. This iterator
* will walk through the composed property groups of the instance. It will
* then step through the property groups of the instance's restarter and
* finally the global service. If you wish to iterate over a specific type
* of property group, set restriction to point the the desired type.
* Otherwise set restriction to NULL.
*
* The returned interator must be freed by calling pg_iter_destroy(). NULL
* is returned if we are unable to allocate the necessary memory.
*/
static pg_iter_t *
{
pg_iter_t *i;
i = uu_zalloc(sizeof (*i));
if (i == NULL)
return (NULL);
i->pgi_entity = e;
i->pgi_restrict = restriction;
i->pgi_level = TL_COMPOSED;
i->pgi_service = e->sc_parent;
return (i);
}
/*
* Return the next property group in the iteration. NULL is returned if we
* reach the end of the list. The iterator will automatically proceed from
* most specific to most general levels.
*/
static pgroup_t *
{
entity_t *e;
while (i->pgi_entity != NULL) {
if (i->pgi_level == TL_COMPOSED) {
} else {
}
} else {
}
} else {
} else {
pg);
}
}
/*
* End of the list. Reset current and break out of
* the loop.
*/
(void) memset(&i->pgi_current, 0,
sizeof (i->pgi_current));
break;
}
/*
* If this iteration is for a specific type, verify that
* this pg is of that type.
*/
if (i->pgi_restrict) {
continue;
}
}
return (pg);
}
/*
* End of the list in the current level. Move up to the next
* level.
*/
switch (i->pgi_level) {
case TL_COMPOSED:
/* Skip service if we've finished a composed instance. */
e = i->pgi_entity;
/* Use service restarter */
i->pgi_entity =
} else {
/* Use instance restarter */
i->pgi_entity =
}
i->pgi_level = TL_RESTARTER;
break;
case TL_RESTARTER:
break;
case TL_GLOBAL:
i->pgi_level = TL_NOLEVEL;
return (NULL);
default:
assert(0);
abort();
}
/* Go process the next level. */
return (next_pattern_pg(i));
}
/*
* Compare two pattern info structures (ptrn_info_t). If both structures
* have names, the comparison is based on the name. If only one has a
* name, the structure with no name will be first. If neither structure
* has a name, the comparison is based on their types using similar wild
* card logic.
*/
/* ARGSUSED2 */
static int
{
/* No names, so we need to compare types. */
return (0);
/* If we get here, exactly one of the types is NULL */
return (-1);
return (1);
}
/* If we get here, exactly one of the names is NULL */
return (-1);
return (1);
}
/*
* The target of a pg_pattern in combination with the level at which the
* pg_pattern was defined determines whether or not it should be applied.
* The following combinations should be ignored, and all others should be
* applied.
*
* Target Level
* ------ -----
* this TL_RESTARTER, TL_GLOBAL
* "this" only applies if the pg_pattern was defined
* at the instance or service level
* delegate TL_INSTANCE, TL_SERVICE
* Only restarters and the global service can
* delegate.
* instance TL_INSTANCE, TL_RESTARTER, TL_GLOBAL
* Only the service level can specify the "instance"
* target.
* all TL_INSTANCE, TL_SERVICE, TL_RESTARTER
* Only the global service can specify the "all"
* target.
*
* Return Values:
* 1 apply the pg_pattern
* 0 ignore the pg_pattern
*/
static int
{
/* Default is this */
}
if ((level == TL_RESTARTER) ||
return (0);
} else {
return (1);
}
}
if ((level == TL_INSTANCE) ||
(level == TL_SERVICE)) {
return (0);
} else {
return (1);
}
}
/*
* Note that the test is inverted from the other cases.
* This is because there is only one instance where apply
* is the correct thing to do.
*/
if (level == TL_SERVICE) {
return (1);
} else {
return (0);
}
}
if ((level == TL_INSTANCE) ||
(level == TL_SERVICE) ||
(level == TL_RESTARTER)) {
return (0);
}
}
return (1);
}
static int
{
const char *target;
if (level == TL_COMPOSED) {
case SVCCFG_INSTANCE_OBJECT:
level = TL_INSTANCE;
break;
case SVCCFG_SERVICE_OBJECT:
level = TL_SERVICE;
break;
default:
assert(0);
abort();
}
}
}
/*
* Find the prop_pattern's type sepcification and convert it to the
* appropriate scf_type.
*/
static tmpl_validate_status_t
{
const char *type_spec;
SCF_GROUP_TEMPLATE_PROP_PATTERN) == 0);
return (TVS_MISSING_TYPE_SPECIFICATION);
return (TVS_SUCCESS);
}
/*
* This function is analagous to scf_property_is_type(3SCF), but it works
* on the in memory representation of the property.
*
* RETURNS:
* 0 The property at prop does not have the specified
* type.
* non-zero The property at prop does have the specified type.
*/
static int
{
}
/*
* This function generates a property group name for a template's
* pg_pattern. The name and type of the pg_pattern are used to construct
* the name, but either or both may be null. A pointer to the constructed
* name is returned, and the referenced memory must be freed using
* free(3c). NULL is returned if we are unable to allocate enough memory.
*/
static char *
{
char *pg_name;
/*
* There are four cases -- name and type are both null, name and
* type are both non-null, only name is present or only type is
* present.
*/
/*
* Name and type are both null, so the PG name
* contains only the prefix.
*/
}
} else {
/*
* If we have a type and no name, the type becomes
* part of the pg_pattern property group name.
*/
name_size) {
}
}
} else {
/*
* As long as the pg_pattern has a name, it becomes part of
* the name of the pg_pattern property group name. We
* merely need to pick the appropriate prefix.
*/
const char *prefix;
} else {
}
name_size) {
}
}
/* Name was too big. */
}
return (rv);
}
/*
* pinfo contains information about a prop_pattern. An include_values
* element with a type of type has been included in the prop_pattern
* specification. We need to determine if the prop_pattern also contains
* constraints or values specifications as determined by type. Thus, we
* search the prop_pattern for properties whose names start with the
* correct prefix.
*/
static tmpl_validate_status_t
{
int i;
const char **prefixes;
const char *pfx;
} else {
"type must be \"constraints\" or \"values\"");
return (TVS_BAD_TEMPLATE);
}
/*
* Now see if the prop_pattern has a property whose name starts
* with one of these prefixes.
*/
return (TVS_SUCCESS);
}
}
}
/* No match found. Generate error */
return (TVS_VALIDATION);
}
/*
* Walk through the prop_patterns in tree, looking for any that have an
* include_values, SCF_PROPERTY_TM_CHOICES_INCLUDE_VALUES, property. For
* the prop_patterns with the include values property, verify that the
* prop_pattern has constraint or values declarations as specified by the
* include_values property.
*/
static tmpl_validate_status_t
{
property_t *iv;
value_t *v;
continue;
v != NULL;
errs);
if (r != TVS_SUCCESS)
rc = r;
}
}
return (rc);
}
/*
* Verify that there are no conflicting definitions of pg_pattern or
* prop_pattern. Two patterns are said to be in conflict if they have the
* same name and differing types. There is a caveat, however. Empty
* pattern names or types are considered to be wild cards. There is no
* conflict if a pattern has a wild card.
*/
static tmpl_validate_status_t
{
/* First walk the instance. */
/* Now walk the service */
if (r != TVS_SUCCESS)
rc = r;
return (rc);
}
static tmpl_validate_status_t
{
int reported_name;
int rv;
/* Nothing to check if pattern is not required. */
continue;
}
/*
* For pg_pattern both name and type are optional unless
* the required attribute has a value of true. For
* prop_patterns only the type is optional, but it must be
* provided if the required attribute has a value of true.
*/
reported_name = 0;
rc = TVS_VALIDATION;
/*
* If we're unable to report errors, break
* out of the loop.
*/
break;
}
/*
* Don't report the error twice if both name and
* type are missing. One error message is
* adequate.
*/
reported_name = 1;
}
rc = TVS_VALIDATION;
} else {
}
/* If we're unable to log errors, break out of loop. */
if (rv != 0)
break;
}
}
return (rc);
}
/*
* Look for pg_pattern definitions in general. general is either the
* restarter serivce for inst or it is the global service. tree contains
* the ptrn_info_t structures describing the pg_patterns for an instance.
* For each general pg_pattern, see if the instance contains an overriding
* definition in tree. If it does generate an error entry.
*
* If a redefinition is found, TVS_WARN is returned. This is because a
* redefinition is not sufficient reason to inhibit the import operation.
*/
static tmpl_validate_status_t
{
/*
* General services may not be in repository yet. It depends on
* the order that manifests are imported.
*/
return (TVS_SUCCESS);
SCF_GROUP_TEMPLATE_PG_PATTERN) != 0) {
/* Not a pg_pattern */
continue;
}
/* See if global pg_pattern is targeted at us. */
continue;
/*
* See if the match applies to us. If we happen to
* be a restarter, the pg_pattern could have a
* target of delegate. That wouldn't apply to this
* instance, it would only apply to our delegates.
* Cases such as this are not a redefinition.
*/
} else {
}
continue;
/*
* Instance or service overrides a general
* definition. We need to issue a warning message.
*/
&einfo) != 0) {
/*
* No need to continue the search if we
* cannot record errors.
*/
break;
}
}
}
return (rc);
}
/*
* tree contains the pg_pattern definitions for the instance at inst. See
* if these pg_patterns redefine any pg_patterns in the instance's
* restarter or in the global service. TVS_WARN is returned if a
* redefinition is encountered.
*/
static tmpl_validate_status_t
{
/* No instance restarter. Use the service restarter */
}
if (r != TVS_SUCCESS)
rc = r;
return (rc);
}
/*
* Perform the following consistency checks on the template specifications
* themselves:
*
* - No conflicting definitions of `pg_pattern` are allowed within a
* single instance.
*
* - Templates at a narrow target (e.g. instance) which define
* property groups already templated at a broad target
* (e.g. restarter or all) are strongly discouraged.
*
* - Developers may not define a template which specifies a single
* prop_pattern name with differing types on the same target
* entity.
*
* - If a pg_pattern has a required attribute with a value of true,
* then its name and type attributes must be specified.
*
* - If a prop_pattern has a required attribute with a value of true,
* then its type attribute must be specified.
*
* - If a prop_pattern has an include values make sure that the
* appropriate constraints or values element has also been
* declared.
*/
static tmpl_validate_status_t
{
/* Allocate the tree. */
uu_strerror(uu_error()));
}
/*
* The tree now contains the instance and service pg_patterns.
* Check to see if they override any pg_pattern definitions in the
* restarter and global services.
*/
if (r != TVS_SUCCESS) {
/*
* tmpl_level_redefine() can return a warning. Don't
* override a serious error with a warning.
*/
if (r == TVS_WARN) {
if (rc == TVS_SUCCESS)
rc = r;
} else {
rc = r;
}
}
/*
* If the pg_pattern has a required attribute with a value of true,
* then it must also have name and type attributes.
*/
if (r != TVS_SUCCESS)
rc = r;
/* Empty the tree, so that we can reuse it for prop_patterns. */
}
if (r != TVS_SUCCESS)
rc = r;
/*
* If a prop_pattern has required attribute with a value of true,
* then it must also have a type attribute.
*/
if (r != TVS_SUCCESS)
rc = r;
/*
* Insure that include_values have the constraint for values
* elements that are needed.
*/
if (r != TVS_SUCCESS)
rc = r;
/* Tear down the tree. */
}
return (rc);
}
/*
* Release memory associated with the tmpl_errors structure and then free
* the structure itself.
*/
void
{
return;
}
}
}
}
}
/*
* Allocate and initialize a tmpl_errors structure. The address of the
* structure is returned, unless we are unable to allocate enough memory.
* In the case of memory allocation failures, NULL is returned.
*
* The allocated structure should be freed by calling
* tmpl_errors_destroy().
*/
static tmpl_errors_t *
{
return (NULL);
return (NULL);
}
return (NULL);
}
return (te);
}
void
{
char *s = NULL;
}
/* Now handle the errors that can be printed via libscf. */
s = safe_malloc(buf_size);
}
}
free(s);
}
/*
* This function finds the prop_pattern for the property, prop. e is the
* instance where the search for the prop_pattern will start. pg_pattern
* is the address of the pg_pattern that holds the prop_pattern.
*/
static tmpl_validate_status_t
{
char *prop_pattern_name = NULL;
/*
* Get the name of the property group that holds the prop_pattern
* definition.
*/
if (rc != TVS_SUCCESS)
goto out;
/* Find the property group. */
goto out;
const char *c;
continue;
if (c == NULL)
continue;
break;
}
rc = TVS_NOMATCH;
out:
uu_free((void *)prop_pattern_name);
return (rc);
}
/*
* Indexes for pg_pattern property group names. Indexes are arranged
* from most specific to least specific.
*/
#define PGN_BOTH 0 /* both name and type */
/*
* Given an instance entity, e, and a propety group, pg, within the
* instance; return the address of the pg_pattern for the property group.
* The address of the pg_pattern is placed at pgp. NULL indicates that no
* pg_pattern was specified.
*/
static tmpl_validate_status_t
{
int i;
/* Generate candidate names for pg_pattern property groups. */
pg->sc_pgroup_type);
NULL);
pg->sc_pgroup_type);
for (i = 0; i < PGN_MAX; i++) {
goto errout;
}
}
/* Search for property groups that match these names */
}
continue;
/* See if we have a name match. */
for (i = 0; i < PGN_MAX; i++) {
/*
* If we already have a lower level
* pg_pattern, keep it.
*/
if (pg_patterns[i] == NULL)
pg_patterns[i] = cpg;
break;
}
}
}
/* Find the most specific pg_pattern. */
for (i = 0; i < PGN_MAX; i++) {
if (pg_patterns[i] != NULL) {
*pgp = pg_patterns[i];
break;
}
}
for (i = 0; i < PGN_MAX; i++) {
}
return (rv);
}
/*
* Initialize structures that are required for validation using
* templates specifications.
*/
void
tmpl_init(void)
{
if (composed_pg_pool == NULL) {
uu_strerror(uu_error()));
}
if (composed_prop_pool == NULL) {
uu_strerror(uu_error()));
}
if (ptrn_info_pool == NULL) {
uu_strerror(uu_error()));
}
if (inmem_errors_pool == NULL) {
}
if (tv_errors_pool == NULL) {
uu_strerror(uu_error()));
}
}
/*
* Clean up the composed property node in the property.
*/
void
{
}
/*
* Initialize the composed property node in the property.
*/
void
{
}
/*
* Use the cardinality specification in the prop_pattern to verify the
* cardinality of the property at prop. The cardinality of the property is
* the number of values that it has.
*
* pg is the property group that holds prop, and pg_pattern is the
* pg_pattern for the property group. pg and pg_pattern are only used for
* error reporting.
*/
static tmpl_validate_status_t
{
SCF_GROUP_TEMPLATE_PROP_PATTERN) == 0);
switch (rc) {
case TVS_NOMATCH:
/* Nothing to check. */
return (TVS_SUCCESS);
case TVS_SUCCESS:
/* Process the limits. */
break;
default:
return (rc);
}
/* Any number of values is permitted. No need to count. */
return (TVS_SUCCESS);
}
return (TVS_VALIDATION);
}
return (TVS_SUCCESS);
}
/*
* Iterate over pg_patterns in the entity, e. If the pg_pattern's required
* attribute is true, verify that the entity contains the corresponding
* property group.
*/
static tmpl_validate_status_t
{
const char *pg_name;
const char *pg_type;
if (is_required(pg) == 0) {
/* If pg is not required, there is nothing to check. */
continue;
}
continue;
rc = TVS_VALIDATION;
break;
}
}
}
return (rc);
}
/*
* Verify that the property group, pg, contains property declarations for
* all required properties. Unfortunately, there is no direct way to find
* the prop_patterns for a given property group. Therefore, we need to
* scan the entity at e looking for property groups with a type of
* SCF_GROUP_TEMPLATE_PROP_PATTERN. That is, we scan the entity looking
* for all prop_patterns. When we find a prop_pattern, we look at the
* value of its pg_pattern property to see if it matches the name of the
* pg_pattern. If they match, this is a prop_pattern that is of interest
* to us.
*
* When we find an interesting prop_pattern, we see if it's required
* property is true. If it is, we verify that the property group at pg
* contains the specified property.
*/
static tmpl_validate_status_t
{
const char *prop_name;
const char *prop_pg_pattern_name;
/*
* Scan the entity's property groups looking for ones with a type
* of SCF_GROUP_TEMPLATE_PROP_PATTERN.
*/
prop_pattern != NULL;
/*
* Find the pg_pattern property in this prop_pattern.
* Verify that its value matches the name of the
* pg_pattern.
*/
prop_pg_pattern_name) != 0) {
continue;
}
/* If the property is required, see if it is in the pg. */
if (is_required(prop_pattern) == 0)
continue;
rc = TVS_VALIDATION;
/*
* If we can no longer accumulate errors,
* break out of the loop.
*/
break;
}
}
}
return (rc);
}
/*
* Check the value at v to see if it falls within any of the ranges at r.
* count is the number of ranges at r, and type tells whether to treat the
* value as signed or unsigned.
*
* Return 1 if the value falls within one of the ranges. Otherwise return
* 0.
*/
static int
{
if (type == SCF_TYPE_COUNT) {
return (1);
} else {
if ((v->sc_u.sc_integer >=
(v->sc_u.sc_integer <=
return (1);
}
}
return (0);
}
/*
* If the template prop_pattern at pattern contains a constraint_range
* property, use the specified range to validate all the numeric property
* values of the property at prop.
*
* pg is the property group that holds prop, and pg_pattern is the
* pg_pattern for the property group. pg and pg_pattern are only used for
* error reporting.
*/
static tmpl_validate_status_t
{
value_t *v;
/* Get the range constraints if they exist. */
SCF_PROPERTY_TM_CONSTRAINT_RANGE)) == NULL) {
/* No range to check. */
return (TVS_SUCCESS);
}
gettext("Property does not have correct type for "
"a range specification");
return (rc);
}
&count)) != TVS_SUCCESS) {
"value");
return (rc);
}
/* Set up error info before entering loop. */
/* Compare numeric values of the property to the range. */
v != NULL;
continue;
if (type == SCF_TYPE_COUNT) {
} else {
}
rc = TVS_VALIDATION;
return (rc);
}
}
return (rc);
}
/*
* If the prop_pattern has value constraints, verify that all the values
* for the property at prop are legal values.
*
* pg is the property group that holds prop, and pg_pattern is the
* pg_pattern for the property group. pg and pg_pattern are only used for
* error reporting.
*/
static tmpl_validate_status_t
{
int found;
uint_t i;
value_t *v;
/* Get list of legal values. */
switch (r) {
case TVS_BAD_CONVERSION:
return (r);
case TVS_NOMATCH:
/* No constraints in template. */
return (TVS_SUCCESS);
case TVS_SUCCESS:
/* process the constraints. */
break;
default:
assert(0);
abort();
}
/* Check the property values against the legal values. */
v != NULL;
/* Check this property value against the legal values. */
found = 0;
switch (v->sc_type) {
case SCF_TYPE_BOOLEAN:
case SCF_TYPE_COUNT:
if (av_get_unsigned(legal, i) ==
found = 1;
}
break;
case SCF_TYPE_INTEGER:
if (av_get_integer(legal, i) ==
v->sc_u.sc_integer) {
found = 1;
}
break;
default:
found = 1;
}
break;
}
}
if (found == 0) {
rc = TVS_VALIDATION;
if (add_scf_error(errs,
/*
* Exit loop if no longer able to report
* errors.
*/
break;
}
}
}
out:
return (rc);
}
/*
* Verify the following items about the values of property, prop.
*
* - The values all have the type specified by the prop_pattern at
* pattern.
* - Check numeric values against range constraints.
* - If the prop_pattern has one or more value constraints, validate
* the property's values against the constraints.
*
* pg is the property group that holds prop, and pg_pattern is the
* pg_pattern for the property group. pg and pg_pattern are only used for
* error reporting.
*/
static tmpl_validate_status_t
{
if (r != TVS_SUCCESS)
rc = r;
return (rc);
}
/*
* Perform the following validations on the property, prop.
*
* - Verify that the property's type agrees with the type specified in
* the prop_pattern template, tmpl.
* - Verify the cardinality.
* - Verify that the property values satisfy the constraints specified
* by the template.
*
* pg is the property group that holds prop, and pg_pattern is the
* pg_pattern for the property group. pg and pg_pattern are only used for
* error reporting.
*/
static tmpl_validate_status_t
{
int status;
switch (r) {
case TVS_SUCCESS:
if (type == SCF_TYPE_INVALID) {
if (r != TVS_SUCCESS) {
/*
* Give up if we can no longer accumulate
* errors.
*/
return (rc);
}
} else {
rc = TVS_VALIDATION;
if (status != 0) {
/*
* Give up if we can no longer
* accumulate errors.
*/
return (rc);
}
}
}
break;
/*
* A null type specification means that we do not need to
* check the property's type.
*/
break;
default:
rc = r;
}
/* Validate the cardinality */
if (r != TVS_SUCCESS)
rc = r;
/* Validate that property values satisfy constraints. */
if (r != TVS_SUCCESS)
rc = r;
return (rc);
}
/*
* Validate the property group at pg by performing the following checks:
*
* - Verify that the types of the pg and the pg_pattern are
* compatible.
* - Verify the properties in the pg.
* - Verify that required properties are present.
*/
static tmpl_validate_status_t
{
const char *pg_pattern_type; /* Type declared by pg_pattern. */
int stat;
/*
* See if there is a pg_pattern for this property group. If it
* exists, use it to validate the property group. If there is no
* pg_pattern, then there is no validation to do.
*/
switch (rc) {
case TVS_SUCCESS:
break;
case TVS_BAD_TEMPLATE:
"group name too long");
return (rc);
default:
assert(0);
abort();
}
if (pg_pattern == NULL)
return (TVS_SUCCESS);
/*
* If the pg_pattern declares a type, verify that the PG has the
* correct type.
*/
if ((pg_pattern_type != NULL) &&
(*pg_pattern_type != 0)) {
(*(pg->sc_pgroup_type) != 0)) {
if (strcmp(pg_pattern_type,
pg->sc_pgroup_type) != 0) {
rc = TVS_VALIDATION;
if (stat != 0) {
/*
* If we can no longer accumulate
* errors, return without trying to
* do further validation.
*/
return (rc);
}
}
} else {
if (r != TVS_SUCCESS) {
/*
* If we can no longer accumulate errors,
* return without trying to do further
* validation.
*/
return (rc);
}
}
}
/* Verify the properties in the property group. */
switch (r) {
case TVS_SUCCESS:
/* Found match. Validate property. */
break;
case TVS_NOMATCH:
/* No prop_patern. Go on to next property. */
continue;
case TVS_BAD_TEMPLATE:
gettext("prop_pattern name too long");
continue;
default:
assert(0);
abort();
}
errs);
if (r != TVS_SUCCESS)
rc = r;
}
/*
* Confirm required properties are present.
*/
if (r != TVS_SUCCESS)
rc = r;
return (rc);
}
/*
* Validate that the property groups in the entity conform to the template
* specifications. Specifically, this means do the following:
*
* - Loop through the property groups in the entity skipping the ones
* that are of type "template".
*
* - For the PG search for the corresponding template_pg_pattern
* property group. It is possible that one may not exist.
*
* - Verify that the PG is in conformance with the pg_pattern
* specification if it exists.
*/
static tmpl_validate_status_t
{
continue;
rc = r;
}
return (rc);
}
/*
* Validate the instance, e, by performing the following checks:
*
* - Verify template consistency.
*
* - Validate each property group in the entity is in conformance
* with the template specifications.
*
* - Verify that all required property groups are present in the
* entity.
*/
static tmpl_validate_status_t
{
int status;
/* Prepare to collect errors for this instance. */
/* Verify template consistency */
/* Validate the property groups in the entity. */
r = tmpl_validate_entity_pgs(e, errs);
if (r != TVS_SUCCESS)
rc = r;
/* Verify that all required property groups are present. */
r = tmpl_required_pg_present(e, errs);
if (r != TVS_SUCCESS)
rc = r;
return (rc);
}
/*
* First validate the instances of the service.
*/
static tmpl_validate_status_t
{
/* Validate the service's instances. */
inst)) {
if (r != TVS_SUCCESS)
rc = r;
}
return (rc);
}
/*
* Validate all services and instances in the bundle against their
* templates. If err_list is not NULL, a tmpl_errors structure will be
* allocated and its address will be returned to err_list. This structure
* can be used to generate error messages.
*/
{
"against templates.\n"));
return (TVS_FATAL);
}
errs = tmpl_errors_create();
lscf_prep_hndl(); /* Initialize g_hndl */
if (load_init() != 0)
/*
* We will process all services in the bundle, unless we get a
* fatal error. That way we can report all errors on all services
* on a single run of svccfg.
*/
"named \"%s\" that is not a service.\n"),
load_fini();
return (TVS_FATAL);
}
rc = r;
if (r == TVS_FATAL)
break;
}
} else {
}
load_fini();
return (rc);
}