/*
* 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
*/
/*
*/
/*
*
* This file implements the bulk of the libscf templates interfaces.
* Templates describe metadata about a service or instance in general,
* and individual configuration properties on those services and instances.
* Human-consumable descriptions can be provided, along with definitions
* of valid configuration. See service_bundle.dtd.1 for XML definitions
* of templates, and the svccfg code for information on how those definitions
* are translated into the repository.
*
* The main data structures are scf_pg_tmpl and scf_prop_tmpl. These
* are allocated by the callers through scf_tmpl_[pg|prop]_create(), and
* destroyed with scf_tmpl_[pg|prop]_destroy(). They are populated by
* scf_tmpl_get_by_pg_name(), scf_tmpl_get_by_pg(), and
* scf_tmpl_get_by_prop(). They also store the iterator state for
* scf_tmpl_iter_pgs() and scf_tmpl_iter_props().
*
* These data structures are then consumed by other functions to
* gather information about the template (e.g. name, description,
* choices, constraints, etc.).
*
* scf_tmpl_validate_fmri() does instance validation against template
* data, and populates a set of template errors which can be explored using
* the scf_tmpl_next_error() and the scf_tmpl_error*() suite of functions.
*
* The main data structures for template errors are scf_tmpl_errors,
* defined in this file, and scf_tmpl_error, defined in libscf_priv.h.
* scf_tmpl_error is shared with svccfg to offer common printing
* of error messages between libscf and svccfg.
*
* General convenience functions are towards the top of this file,
* followed by pg and prop template discovery functions, followed
* by functions which gather information about the discovered
* template. Validation and error functions are at the end of this file.
*/
#include "lowlevel_impl.h"
#include "libscf_impl.h"
#include <assert.h>
#include <errno.h>
#include <libintl.h>
#include <stdlib.h>
#include <stdio.h>
#include <strings.h>
#include <locale.h>
#include <ctype.h>
#include <inttypes.h>
#define SCF__TMPL_ITER_NONE 0
#define SCF_TMPL_PG_NT 0
struct scf_pg_tmpl {
int pt_populated;
int pt_is_iter;
int pt_iter_last;
};
#define SCF_WALK_NEXT 0
struct pg_tmpl_walk {
const char *pw_snapname;
const char *pw_pgname;
const char *pw_pgtype;
const char *pw_target;
char *pw_tmpl_pgname;
};
struct scf_prop_tmpl {
int prt_populated;
char *prt_pg_name;
};
/*
* Common server errors are usually passed back to the caller. This
* array defines them centrally so that they don't need to be enumerated
* in every libscf call.
*/
0
};
/*
* int ismember()
*
* Returns 1 if the supplied error is a member of the error array, 0
* if it is not.
*/
int
{
int i;
for (i = 0; error_array[i] != 0; ++i) {
if (error == error_array[i])
return (1);
}
return (0);
}
/*
* char *_scf_tmpl_get_fmri()
*
* Given a pg_tmpl, returns the FMRI of the service or instance that
* template describes. The allocated string must be freed with free().
*
* On failure, returns NULL and sets scf_error() to _CONNECTION_BROKEN,
* _DELETED, or _NO_MEMORY.
*/
static char *
{
int r;
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
return (buf);
}
else
if (r == -1) {
} else {
assert(0);
abort();
}
}
return (buf);
}
/*
* char *_scf_get_pg_type()
*
* Given a propertygroup, returns an allocated string containing the
* type. The string must be freed with free().
*
* On failure, returns NULL and sets scf_error() to: _CONNECTION_BROKEN,
* _DELETED, or _NO_MEMORY.
*/
static char *
{
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
} else {
assert(0);
abort();
}
}
return (buf);
}
/*
* char *_scf_get_prop_name()
*
* Given a property, returns the name in an allocated string. The string must
* be freed with free().
*
* On error, returns NULL and sets scf_error() to _CONNECTION_BROKEN,
* _DELETED, or _NO_MEMORY.
*/
static char *
{
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
} else {
assert(0);
abort();
}
}
return (buf);
}
/*
* char *_scf_get_prop_type()
*
* Given a property, returns the type in an allocated string. The string must
* be freed with free().
*
* On error, returns NULL and sets scf_error() to _CONNECTION_BROKEN,
* _DELETED, or _NO_MEMORY.
*/
static char *
{
char *ret;
return (NULL);
} else {
assert(0);
abort();
}
}
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
return (ret);
}
/*
* int _read_single_value_from_pg()
*
* Reads a single value from the pg and property name specified. On success,
* returns an allocated value that must be freed.
*
* Returns -1 on failure, sets scf_error() to:
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_CONSTRAINT_VIOLATED
* Property has more than one value associated with it.
* SCF_ERROR_DELETED
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_INVALID_ARGUMENT
* prop_name not a valid property name.
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_NOT_FOUND
* Property doesn't exist or exists and has no value.
* SCF_ERROR_NOT_SET
* Property group specified by pg is not set.
* SCF_ERROR_PERMISSION_DENIED
*/
static int
scf_value_t **val)
{
scf_handle_t *h;
int ret = 0;
return (-1);
}
prop = scf_property_create(h);
*val = scf_value_create(h);
}
}
}
ret = -1;
return (ret);
}
/*
* char *_scf_read_single_astring_from_pg()
*
* Reads an astring from the pg and property name specified. On success,
* returns an allocated string. The string must be freed with free().
*
* Returns NULL on failure, sets scf_error() to:
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_CONSTRAINT_VIOLATED
* Property has more than one value associated with it.
* SCF_ERROR_DELETED
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_INVALID_ARGUMENT
* prop_name not a valid property name.
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_NOT_FOUND
* Property doesn't exist or exists and has no value.
* SCF_ERROR_NOT_SET
* The property group specified by pg is not set.
* SCF_ERROR_PERMISSION_DENIED
* SCF_ERROR_TYPE_MISMATCH
*/
char *
{
return (NULL);
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
goto cleanup;
}
}
return (ret);
}
/*
* char *_scf_read_tmpl_prop_type_as_string()
*
* Reads the property type and returns it as an allocated string. The string
* must be freed with free().
*
* Returns NULL on failure, sets scf_error() to _BACKEND_ACCESS,
* _CONNECTION_BROKEN, _DELETED, _HANDLE_DESTROYED, _INTERNAL, _NO_MEMORY,
* _NO_RESOURCES, _NOT_BOUND, _PERMISSION_DENIED, or _TEMPLATE_INVALID.
*/
char *
{
char *type;
return (NULL);
} else switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
case SCF_ERROR_TYPE_MISMATCH:
(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
return (NULL);
case SCF_ERROR_NOT_SET:
default:
assert(0);
abort();
}
}
return (type);
}
/*
* int _read_single_boolean_from_pg()
*
* Reads a boolean from the pg and property name specified.
*
* Returns -1 on failure, sets scf_error() to:
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_CONSTRAINT_VIOLATED
* Property has more than one value associated with it.
* SCF_ERROR_DELETED
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_INVALID_ARGUMENT
* prop_name is not a valid property name.
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_NOT_FOUND
* Property doesn't exist or exists and has no value.
* SCF_ERROR_NOT_SET
* The property group specified by pg is not set.
* SCF_ERROR_PERMISSION_DENIED
* SCF_ERROR_TYPE_MISMATCH
*/
static int
uint8_t *bool)
{
int ret = 0;
return (-1);
if (scf_value_get_boolean(val, bool) < 0) {
ret = -1;
}
return (ret);
}
/*
* static char ** _append_astrings_values()
*
* This function reads the values from the property prop_name in pg and
* appends to an existing scf_values_t *vals. vals may be empty, but
* must exist. The function skips over zero-length and duplicate values.
*
* Returns NULL on failure, sets scf_error() to:
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_DELETED
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_INVALID_ARGUMENT
* prop_name is not a valid property name.
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_NOT_FOUND
* SCF_ERROR_NOT_SET
* SCF_ERROR_PERMISSION_DENIED
* SCF_ERROR_TYPE_MISMATCH
*/
static char **
{
scf_handle_t *h;
if (count == 0) {
cursz = 8;
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
return (NULL);
}
} else {
/*
* The array may be bigger, but it is irrelevant since
* we will always re-allocate a new one.
*/
}
return (NULL);
}
prop = scf_property_create(h);
val = scf_value_create(h);
iter = scf_iter_create(h);
}
}
}
int flag;
int r;
void *aux;
cursz *= 2;
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
}
count * sizeof (char *));
}
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
}
if ((r = scf_value_get_astring(val,
/* discard zero length strings */
if (r == 0) {
continue;
}
}
/* find and discard duplicates */
flag = 1;
break;
}
}
if (flag == 1)
continue;
count++;
}
if (err != 0) {
} else {
}
for (i = 0; i <= count; ++i) {
}
vals->value_count = 0;
}
/*
* Returns NULL on failure, sets scf_error() to:
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_DELETED
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_INVALID_ARGUMENT
* prop_name is not a valid property name.
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_NOT_FOUND
* SCF_ERROR_NOT_SET
* SCF_ERROR_PERMISSION_DENIED
* SCF_ERROR_TYPE_MISMATCH
*/
static char **
{
vals->value_count = 0;
}
void
{
*locale = '_';
}
/*
* The returned string needs to be freed by the caller
* Returns NULL on failure. Sets scf_error() to:
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_INVALID_ARGUMENT
* Name isn't short enough to add the locale to.
*/
static char *
{
char *loc;
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
return (NULL);
} else {
}
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
goto cleanup;
}
(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
}
return (lname);
}
/*
* char *_tmpl_pg_name(pg, type, use_type)
*
* pg and type can both be NULL. Returns the name of the most specific
* template property group name based on the inputs.
* If use_type is set and pg is not NULL, a property group name for a
* property group template that has type defined is returned, even if no
* type is provided.
*
* Returns NULL on failure and sets scf_error() to:
* SCF_ERROR_INVALID_ARGUMENT
* can't combine the arguments and get a reasonable length name
* SCF_ERROR_NO_MEMORY
*
*/
static char *
{
char *name;
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
return (NULL);
}
limit) {
assert(0);
abort();
}
return (name);
} else {
assert(0);
abort();
}
(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
return (NULL);
} else {
return (name);
}
}
/*
* _scf_get_pg_name()
* Gets the name of the supplied property group. On success, returns an
* allocated string. The string must be freed by free().
*
* Returns NULL on failure and sets scf_error() to _CONNECTION_BROKEN,
* _DELETED, or _NO_MEMORY.
*/
static char *
{
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
} else {
assert(0);
abort();
}
}
return (buf);
}
/*
* char *_tmpl_prop_name()
*
* Returns the name of the property template prop (which is the name of
* the property template property group) in the property group
* template t. Returns NULL on failure and sets scf_error() to:
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_DELETED
* SCF_ERROR_INVALID_ARGUMENT
* can't combine the arguments and get a reasonable length name
* SCF_ERROR_NO_MEMORY
*/
static char *
{
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
return (NULL);
}
return (NULL);
}
(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
return (NULL);
}
(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
return (NULL);
} else {
return (name);
}
}
/*
* int _get_snapshot()
*
* Gets the specified snapshot. If "snapshot" isn't defined, use the
* running snapshot. If the snapshot isn't found, that may or may
* not be an error depending on the caller. Return 0 in that case,
* but leave scf_error() set to SCF_ERROR_NOT_FOUND. On all other
* errors, set scf_error() to:
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_DELETED
* SCF_ERR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_INVALID_ARGUMENT
* The handle argument is NULL, or snaphot is not a valid snapshot name
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_NOT_FOUND
*/
static int
{
int err;
scf_handle_t *h;
h = scf_instance_handle(inst);
if (h == NULL)
return (-1);
return (-1);
}
/* Use running snapshot by default. */
else
if (err != 0) {
return (-1);
} else switch (scf_error()) {
return (-1);
case SCF_ERROR_NOT_FOUND:
return (0);
case SCF_ERROR_NOT_SET:
default:
assert(0);
abort();
}
}
/*
* Explicitly set SCF_ERROR_NONE so that the SCF_ERROR_NOT_FOUND
* return above is explicitly guaranteed to be from
* scf_instance_get_snapshot().
*/
(void) scf_set_error(SCF_ERROR_NONE);
return (0);
}
/*
* Returns NULL on error, sets scf_error() to:
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_CONSTRAINT_VIOLATED
* The restarter's FMRI does not match an existing instance.
* SCF_ERROR_DELETED
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_INVALID_ARGUMENT
* The restarter's FMRI is not a valid FMRI.
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_NOT_FOUND
* Property doesn't exist or exists and has no value.
* SCF_ERROR_TEMPLATE_INVALID
* restarter property is not SCF_TYPE_ASTRING or has more than one value
*/
static scf_instance_t *
{
int ret = 0;
goto _get_restarter_inst_fail;
}
pg);
else
if (ret != 0) {
goto _get_restarter_inst_fail;
} else switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
/* Assume default restarter. */
break;
case SCF_ERROR_NOT_SET:
/*
* If the arguments to the above functions
* aren't derived from the same handle, there's
* something wrong with the internal implementation,
* not the public caller further up the chain.
*/
default:
assert(0);
abort();
}
} else {
/* zero length string is NOT a valid restarter */
goto _get_restarter_inst_fail;
} else switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
break;
case SCF_ERROR_TYPE_MISMATCH:
(void) scf_set_error(
goto _get_restarter_inst_fail;
case SCF_ERROR_NOT_SET:
default:
assert(0);
abort();
}
}
}
/* Use default restarter */
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
goto _get_restarter_inst_fail;
}
}
goto _get_restarter_inst_fail;
} else switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
goto _get_restarter_inst_fail;
case SCF_ERROR_NOT_SET:
default:
assert(0);
abort();
}
}
return (ri);
return (NULL);
}
/*
* Returns NULL on error, sets scf_error() to:
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_CONSTRAINT_VIOLATED
* Restarter property has more than one value associated with it,
* or FMRI does not meet restrictions in scf_handle_decode_fmri() flags.
* SCF_ERROR_DELETED
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_INVALID_ARGUMENT
* The fmri argument in scf_handle_decode_fmri() is not a valid FMRI.
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_NOT_FOUND
* Property doesn't exist or exists and has no value.
*/
static scf_instance_t *
{
(void) scf_set_error(SCF_ERROR_NO_RESOURCES);
return (NULL);
}
return (NULL);
} else switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
return (NULL);
case SCF_ERROR_NOT_SET:
default:
assert(0);
abort();
}
}
return (ri);
}
/*
* Call the supplied function for each of the service or instance, the
* service's restarter, and the globally defined template instance.
* If the function returns SCF_WALK_ERROR, the walk is ended. If
* the function returns SCF_WALK_NEXT, the next entity is tried.
*
* The function is only expected to return SCF_WALK_DONE if it has
* found a property group match in the current entity, and has
* populated p->pw_pg with the matching property group.
*
* The caller of _walk_template_instances() MUST check if the passed parameters
* inst and svc match the fields pw_inst and pw_svc in the resulting
* pg_tmpl_walk_t and call the destructor for the unmatching objects. The walker
* may silently drop them if the template definition is in the restarter or in
* the global instance.
*/
static void
pg_tmpl_walk_t *p, int flag)
{
scf_handle_t *h;
int ret;
h = scf_instance_handle(inst);
else
h = scf_service_handle(svc);
if (h == NULL)
goto done;
/* First, use supplied service or instance */
p->pw_target = SCF_TM_TARGET_THIS;
switch (ret) {
case SCF_WALK_NEXT:
break;
case SCF_WALK_DONE:
/*
* Check that the template scoping matches and if not,
* continue.
*/
(flag & SCF_PG_TMPL_FLAG_EXACT) !=
scf_pg_destroy(p->pw_pg);
break;
}
}
/*FALLTHROUGH*/
case SCF_WALK_ERROR:
goto done;
/*NOTREACHED*/
default:
assert(0);
abort();
}
/* Next the restarter. */
switch (ret) {
case SCF_WALK_NEXT:
break;
case SCF_WALK_DONE:
/*
* Check that the template scoping matches and if not,
* continue.
*/
scf_pg_destroy(p->pw_pg);
break;
}
}
/*FALLTHROUGH*/
case SCF_WALK_ERROR:
goto done;
/*NOTREACHED*/
default:
assert(0);
abort();
}
}
p->pw_target = SCF_TM_TARGET_ALL;
tmpl_inst = _get_global_inst(h);
switch (ret) {
case SCF_WALK_NEXT:
break;
case SCF_WALK_DONE:
/*
* Check that the template scoping matches and if not,
* continue.
*/
scf_pg_destroy(p->pw_pg);
break;
}
}
/*FALLTHROUGH*/
case SCF_WALK_ERROR:
goto done;
/*NOTREACHED*/
default:
assert(0);
abort();
}
}
done:
if (ret != SCF_WALK_DONE)
}
/*
* _get_pg() returns 0 on success and -1 on failure. Sets scf_error()
* on failure.
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_DELETED
* SCF_ERROR_HANDLE_MISMATCH
* SCF_ERROR_INTERNAL
* SCF_ERROR_INVALID_ARGUMENT
* name is not a valid property group.
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_NOT_FOUND
* SCF_ERROR_NOT_SET
*/
static int
{
int ret;
else
return (ret);
}
/*
* Returns SCF_WALK_NEXT for not found, SCF_WALK_ERROR for error,
* and SCF_WALK_DONE for found.
* On error, destroy pg and set it to NULL.
*
* Sets scf_error() if SCF_WALK_ERROR is returned to _BACKEND_ACCESS,
* _CONNECTION_BROKEN, _INTERNAL, _INVALID_ARGUMENT (name is not a
* valid property group), _NO_RESOURCES, or _NOT_BOUND.
*/
static int
{
int ret;
if (ret == 0) {
return (SCF_WALK_DONE);
} else {
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
case SCF_ERROR_DELETED:
return (SCF_WALK_NEXT);
case SCF_ERROR_BACKEND_ACCESS:
case SCF_ERROR_INTERNAL:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NO_RESOURCES:
return (SCF_WALK_ERROR);
case SCF_ERROR_NOT_SET:
default:
assert(0);
abort();
}
}
/*NOTREACHED*/
}
/*
* If match, return 0. If no match, return 1. If error, return -1.
* On error set scf_error() to _BACKEND_ACCESS, _CONNECTION_BROKEN,
* _HANDLE_DESTROYED, _INTERNAL, _NO_MEMORY, _NO_RESOURCES, _NOT_BOUND,
* _NOT_SET (property group specified by pg is not set), _PERMISSION_DENIED,
* or _TEMPLATE_INVALID (target property is not SCF_TYPE_ASTRING or has
* more than one value).
*/
static int
{
char *pg_target;
int ret = 0;
switch (scf_error()) {
case SCF_ERROR_DELETED:
case SCF_ERROR_NOT_FOUND:
return (1);
case SCF_ERROR_TYPE_MISMATCH:
(void) scf_set_error(
/*FALLTHROUGH*/
case SCF_ERROR_BACKEND_ACCESS:
case SCF_ERROR_INTERNAL:
case SCF_ERROR_NO_RESOURCES:
case SCF_ERROR_NOT_BOUND:
return (-1);
case SCF_ERROR_NOT_SET:
default:
assert(0);
abort();
}
/*NOTREACHED*/
}
/* For a desired target of 'this', check for 'this' and 'instance'. */
goto cleanup;
}
goto cleanup;
}
goto cleanup;
}
ret = 1;
return (ret);
}
/*
* Check if a matching template property group exists for each of:
* name and type, name only, type only, and completely wildcarded
* template.
*
* Both pg_name and pg_type are optional.
*
* Returns NULL on failure, sets scf_error():
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_DELETED
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_INVALID_ARGUMENT
* can't combine the _tmpl_pg_name arguments and get a reasonable
* length name, or pg_name is not a valid property group.
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_NOT_FOUND
* Property doesn't exist or exists and has no value.
* SCF_ERROR_PERMISSION_DENIED
* SCF_ERROR_TEMPLATE_INVALID
* target property is not SCF_TYPE_ASTRING or has more than one value.
*/
static scf_propertygroup_t *
const char *target, char **tmpl_pg_name)
{
int ret, r;
scf_handle_t *h;
h = scf_instance_handle(inst);
else
h = scf_service_handle(svc);
if (h == NULL) {
return (NULL);
}
return (NULL);
}
/*
* We're going to walk through the possible pg templates that
* could match the supplied name and type. We do this
* by explicit name lookups when possible to avoid having to
* keep track of a most-explicit-match during iteration.
*/
/* First look for a template with name and type set and matching. */
if (*tmpl_pg_name == NULL)
goto fail;
if (ret != SCF_WALK_NEXT) {
goto done;
else if (r == -1)
goto fail;
} else {
goto done;
}
}
free(*tmpl_pg_name);
/*
* Need to search on a name-only match before searching on
* type matches.
*/
if (*tmpl_pg_name == NULL)
goto fail;
if (ret != SCF_WALK_NEXT) {
goto done;
else if (r == -1)
goto fail;
} else {
goto done;
}
}
free(*tmpl_pg_name);
/* Next, see if there's an "nt" template where the type matches. */
else
if (ret != 0) {
goto fail;
} else {
assert(0);
abort();
}
}
/* Make sure this is a name and type specified pg. */
continue;
continue;
}
*tmpl_pg_name = name;
goto done;
}
}
if (ret == -1) {
goto fail;
} else {
assert(0);
abort();
}
}
}
if (*tmpl_pg_name == NULL)
goto fail;
if (ret != SCF_WALK_NEXT) {
goto done;
else if (r == -1)
goto fail;
} else {
goto done;
}
}
free(*tmpl_pg_name);
if (*tmpl_pg_name == NULL)
goto fail;
if (ret != SCF_WALK_NEXT) {
goto done;
else if (r == -1)
goto fail;
} else {
goto done;
}
}
(void) scf_set_error(SCF_ERROR_NOT_FOUND);
fail:
if (*tmpl_pg_name != NULL)
free(*tmpl_pg_name);
*tmpl_pg_name = NULL;
done:
if (ret == SCF_WALK_ERROR)
free(*tmpl_pg_name);
return (pg);
}
/*
* Finds the pg match in either the supplied service or instance.
* Returns SCF_WALK_ERROR, SCF_WALK_NEXT, or SCF_WALK_DONE.
* If returning SCF_WALK_ERROR, sets scf_error():
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_DELETED
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_INVALID_ARGUMENT
* The snaphot is not a valid snapshot name,
* or can't create a reasonable property group template name.
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_NOT_FOUND
* Property doesn't exist or exists and has no value.
* SCF_ERROR_PERMISSION_DENIED
* SCF_ERROR_TEMPLATE_INVALID
* target property is not SCF_TYPE_ASTRING or has more than one value.
*/
static int
{
scf_handle_t *h;
char *tmpl_pg_name;
h = scf_instance_handle(inst);
else
h = scf_service_handle(svc);
if (h == NULL)
return (SCF_WALK_ERROR);
if (p->pw_snapname != NULL) {
return (SCF_WALK_ERROR);
}
p->pw_tmpl_pgname = tmpl_pg_name;
return (SCF_WALK_DONE);
}
return (SCF_WALK_NEXT);
}
/*
* return 0 on success and -1 on failure.
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_DELETED
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_HANDLE_MISMATCH
* SCF_ERROR_INTERNAL
* SCF_ERROR_INVALID_ARGUMENT
* FMRI argument, snapshot name, pg_name, or pg is invalid.
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_NOT_FOUND
* SCF_ERROR_NOT_SET
*/
int
{
int ret;
scf_handle_t *h;
pg_tmpl_walk_t *p = NULL;
return (-1);
goto fail;
}
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
goto fail;
}
goto fail;
}
goto fail;
}
if (ret == -1) {
switch (scf_error()) {
/* Parent type doesn't match. Keep looking. */
break;
case SCF_ERROR_DELETED:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
/* Pass these back to the caller. */
goto fail;
default:
assert(0);
abort();
}
/*
* No snapshot. We'll use 'editing' by default since
* snap and snapbuf are NULL.
*/
p->pw_snapname = NULL;
} else {
goto fail;
}
if (ret == -1) {
goto fail;
} else {
assert(0);
abort();
}
}
/* Grab snapshot name while we're here. */
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
goto fail;
}
goto fail;
} else {
assert(0);
abort();
}
}
p->pw_snapname = snapbuf;
if (ret == -1) {
goto fail;
} else {
assert(0);
abort();
}
}
}
/* No snapshot parent. Go looking for instance parent. */
/* First look for instance parent. */
if (ret == 0) {
p, flags);
/* OK, check for service parent */
} else if (ret == -1 &&
if (ret == 0) {
p, flags);
} else {
switch (scf_error()) {
(void) scf_set_error(
/*FALLTHROUGH*/
case SCF_ERROR_DELETED:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
goto fail;
default:
assert(0);
abort();
}
}
} else {
goto fail;
}
}
/* we may get a different instance back */
/* we may get a different service back */
free(p->pw_tmpl_pgname);
ret = 0;
goto done;
}
(void) scf_set_error(SCF_ERROR_NOT_FOUND);
fail:
ret = -1;
done:
free(p);
return (ret);
}
/*
* int scf_tmpl_get_by_pg_name()
*
* Get a template by a combination of the name and type. Either name
* or type can be null, which indicates a wildcard. flags may be
* SCF_PG_TMPL_FLAG_CURRENT (use current properties rather than
* the defined or running snapshot), and SCF_PG_TMPL_FLAG_EXACT (match
* only templates defined by the FMRI in question, not by its restarter
* or globally). Returns 0 on success and -1 on error, and sets
* scf_error() to:
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* The connection to the repository was lost.
* SCF_ERROR_DELETED
* The instance has been deleted.
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_INVALID_ARGUMENT
* FMRI isn't valid, pg_name is too long to look for a template, or
* snapshot specified isn't a valid name
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* The server does not have adequate resources to complete the request.
* SCF_ERROR_NOT_BOUND
* The handle is not currently bound.
* SCF_ERROR_NOT_FOUND
* Object matching FMRI doesn't exist in the repository, or snapshot
* doesn't exist.
*/
int
{
pg_tmpl_walk_t *p = NULL;
scf_handle_t *h;
int ret;
goto fail;
}
if (p == NULL) {
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
goto fail;
}
if (ret == 0) {
} else if (ret != 0 &&
if (ret == 0) {
}
}
if (ret != 0) {
goto fail;
} else switch (scf_error()) {
(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
goto fail;
case SCF_ERROR_NOT_FOUND:
goto fail;
case SCF_ERROR_NOT_SET:
default:
assert(0);
abort();
}
}
/* If we have a service fmri, snapshot is ignored. */
(flags & SCF_PG_TMPL_FLAG_CURRENT) ==
goto fail;
} else {
goto fail;
} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
goto fail;
}
}
}
p->pw_snapname = snapshot;
/*
* For each of instance, restarter, global
* - check for a tm_pg_pattern_nt_<name> matching type
* - check for a tm_pg_pattern_t_<type> matching type
* - check for any tm_pg_pattern_
* Currently plan to return the most specific match only.
*/
/* we may get a different instance back */
/* we may get a different service back */
free(p->pw_tmpl_pgname);
free(p);
return (0);
}
(void) scf_set_error(SCF_ERROR_NOT_FOUND);
fail:
free(p);
return (-1);
}
/*
* Returns NULL on failure, sets scf_error() to _CONNECTION_BROKEN,
* _DELETED, _NO_RESOURCES, or _NOT_BOUND.
*/
static scf_iter_t *
{
int ret;
return (NULL);
}
/* Iterate on property groups of type template_pg_pattern */
if (ret != 0) {
return (NULL);
} else {
assert(0);
abort();
}
}
return (iter);
}
/*
* Returns NULL on failure, sets scf_error() to:
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_DELETED
* SCF_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_INVALID_ARGUMENT
* Handle argument is NULL, or snaphot is not a valid snapshot name.
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_NOT_FOUND
*/
static scf_iter_t *
int exact)
{
/*
* Check what level we last iterated on: none, service,
* restarter, or global. Make sure that if one in the middle
* doesn't exist, we move on to the next entity.
*
* Before we drop any references to pt_inst or pt_svc we must
* destroy them so we don't leak them.
*/
do {
switch (t->pt_iter_last) {
case SCF__TMPL_ITER_NONE:
if (t->pt_inst != t->pt_orig_inst)
t->pt_inst = t->pt_orig_inst;
if (t->pt_svc != t->pt_orig_svc)
t->pt_svc = t->pt_orig_svc;
break;
case SCF__TMPL_ITER_INST:
/*
* Don't go any further than the specified instance
* if exact was set.
*/
if (exact == 1) {
(void) scf_set_error(SCF_ERROR_NOT_FOUND);
goto fail;
}
if (t->pt_inst != t->pt_orig_inst)
t->pt_orig_inst, t->pt_snap);
if (t->pt_svc != t->pt_orig_svc)
break;
case SCF__TMPL_ITER_RESTARTER:
if (t->pt_inst != t->pt_orig_inst)
t->pt_inst = _get_global_inst(h);
if (t->pt_svc != t->pt_orig_svc)
break;
case SCF__TMPL_ITER_GLOBAL:
(void) scf_set_error(SCF_ERROR_NOT_FOUND);
return (NULL);
default:
assert(0);
abort();
}
/* Set pt_snap to the snapshot for this instance */
&t->pt_snap) == -1)
goto fail;
}
iter = _get_svc_or_inst_iter(h, t);
fail:
return (iter);
}
/*
* scf_pg_tmpl_t *scf_tmpl_pg_create(scf_handle_t *)
*
* Returns NULL on failure, sets scf_error() to _INVALID_ARGUMENT
* or _NO_MEMORY.
*/
{
(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
return (NULL);
}
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
else
return (pg_tmpl);
}
/*
* Retrieves name or type of a template pg.
* Returns -1 on failure. Sets scf_error():
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_DELETED
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_PERMISSION_DENIED
* SCF_ERROR_TEMPLATE_INVALID
* pname property is not SCF_TYPE_ASTRING or has more than one value.
*/
static ssize_t
{
(void) scf_set_error(SCF_ERROR_NONE);
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
}
return (-1);
} else switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
case SCF_ERROR_TYPE_MISMATCH:
(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
return (-1);
case SCF_ERROR_NOT_SET:
default:
assert(0);
abort();
}
}
}
/*
* int scf_tmpl_iter_pgs()
*
* Iterates through the property group templates for the fmri given.
* When t is uninitialized or reset, sets t to the first property group
* template in fmri. On subsequent calls, sets t to the next property group
* template in frmi.
* Returns 1 on success, 0 when no property group templates are left to
* iterate, -1 on error.
* The flags argument may include SCF_PG_TMPL_FLAG_REQUIRED,
*
* Returns -1 on error and sets scf_error() to:
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_DELETED
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_INVALID_ARGUMENT
* The handle argument is NULL, fmri is invalid, or snapshot is invalid.
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_NOT_FOUND
* SCF_ERROR_PERMISSION_DENIED
*/
int
{
scf_handle_t *h;
int err;
int found = 0;
char *tmpl_type;
int ret;
if (t == NULL) {
(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
return (-1);
}
h = t->pt_h;
if (t->pt_populated == 0) {
goto fail_non_populated;
}
if (ret == 0) {
} else if (ret != 0 &&
if (ret == 0) {
}
}
if (ret != 0) {
goto fail_non_populated;
} else switch (scf_error()) {
(void) scf_set_error(
goto fail_non_populated;
case SCF_ERROR_NOT_FOUND:
goto fail_non_populated;
case SCF_ERROR_NOT_SET:
default:
assert(0);
abort();
}
}
(flags & SCF_PG_TMPL_FLAG_CURRENT) ==
goto fail_non_populated;
} else {
(void) scf_set_error(SCF_ERROR_NONE);
&snap) == -1) {
goto fail_non_populated;
} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
goto fail_non_populated;
}
}
} else {
}
pg_tmpl = t;
} else {
if (t->pt_is_iter != 1) {
(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
return (-1);
}
pg_tmpl = t;
}
if (scf_error() == SCF_ERROR_NOT_FOUND)
return (0);
else
return (-1);
}
}
while (found == 0) {
if (err == -1) {
return (-1);
} else switch (scf_error()) {
return (-1);
case SCF_ERROR_NOT_SET:
default:
assert(0);
abort();
}
} else if (err == 0) {
/* This iteration is done. Get the next one */
if (scf_error() == SCF_ERROR_NOT_FOUND)
return (0);
else
return (-1);
}
continue;
} else {
assert(0);
abort();
}
}
/*
* Discard pgs which don't exist at the right scoping. This
* check also makes sure that if we're looking at, for
* don't hand back the same property groups twice.
*/
switch (t->pt_iter_last) {
case SCF__TMPL_ITER_INST:
break;
case SCF__TMPL_ITER_RESTARTER:
break;
case SCF__TMPL_ITER_GLOBAL:
break;
case SCF__TMPL_ITER_NONE:
default:
assert(0);
abort();
}
if (ret != 0)
continue;
/*
* If walking only required property groups, check if
* the retrieved group is required.
*/
if (flags & SCF_PG_TMPL_FLAG_REQUIRED) {
if (required == 0)
continue;
} else {
return (-1);
}
}
/*
* If type != NULL, check if type property matches. If no
* type property exists, consider it a match.
*/
break;
}
} else if (scf_error() == SCF_ERROR_NOT_FOUND ||
scf_error() == SCF_ERROR_TYPE_MISMATCH) {
break;
} else {
return (-1);
}
} else {
break;
}
}
return (1);
return (-1);
}
void
{
if (t == NULL)
return;
scf_pg_destroy(t->pt_pg);
if (t->pt_inst != t->pt_orig_inst)
if (t->pt_svc != t->pt_orig_svc)
scf_iter_destroy(t->pt_iter);
free(t);
}
void
{
scf_pg_destroy(t->pt_pg);
if (t->pt_inst != t->pt_orig_inst)
t->pt_orig_inst = NULL;
if (t->pt_svc != t->pt_orig_svc)
t->pt_orig_svc = NULL;
scf_iter_destroy(t->pt_iter);
t->pt_populated = 0;
t->pt_is_iter = 0;
t->pt_iter_last = 0;
/* Do not reset t->pt_h. */
}
/*
* int scf_tmpl_get_by_prop()
*
* Get the property template given a property group template and property
* name. No flags are currently defined for this function.
*
* Returns NULL on failure, and sets scf_error():
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_DELETED
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_INVALID_ARGUMENT
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_NOT_FOUND
* Template object matching property doesn't exist in the repository.
* SCF_ERROR_TYPE_MISMATCH
* Matching template object is the wrong type in the repository.
*/
int
{
char *tmpl_prop_name;
char *pg_type;
int found = 0;
if (flags != 0) {
(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
return (-1);
}
return (-1);
if (tmpl_prop_name == NULL) {
return (-1);
}
tmpl_prop_name, pg) != 0) {
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
break;
case SCF_ERROR_NOT_SET:
default:
assert(0);
abort();
}
}
} else {
/*
* We've only found a template property group if the type
* is correct.
*/
found++;
else
(void) scf_set_error(SCF_ERROR_TYPE_MISMATCH);
}
if (found == 0) {
return (-1);
}
return (0);
}
/*
* scf_prop_tmpl_t *scf_tmpl_prop_create(scf_handle_t *);
*
* Returns NULL on failure, sets scf_error() to _INVALID_ARGUMENT, or
* _NO_MEMORY.
*/
{
(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
return (NULL);
}
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
else
return (pt);
}
/*
* int scf_tmpl_iter_props()
*
* Iterates over all property templates defined in the specified property
* group template. The iterator state is stored on the property template
* data structure, and the data structure should be allocated with
* scf_tmpl_prop_create(). To continue the iteration, the previously
* returned structure should be passed in as an argument to this function.
* flags can include SCF_PROP_TMPL_FLAG_REQUIRED. The function returns
* 1 when a result was found, and 0 when the iteration is complete.
*
* Returns -1 on failure, and sets scf_error():
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_DELETED
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_INVALID_ARGUMENT
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_PERMISSION_DENIED
* SCF_ERROR_TEMPLATE_INVALID
* Template data is invalid. One of the property templates in this
* pg_tmpl is malformed.
*/
int
{
char *pg_pat;
int err;
int ret;
scf_handle_t *h;
(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
return (-1);
}
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
return (-1);
}
if (pt->prt_populated == 0) {
goto fail_non_populated;
goto fail_non_populated;
if (err != 0) {
goto fail_non_populated;
} else switch (scf_error()) {
goto fail_non_populated;
case SCF_ERROR_NOT_SET:
default:
assert(0);
abort();
}
}
} else {
}
/*
* Check if the name matches the appropriate property
* group template name.
*/
return (-1);
} else switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
continue;
case SCF_ERROR_TYPE_MISMATCH:
(void) scf_set_error(
return (-1);
case SCF_ERROR_NOT_SET:
default:
assert(0);
abort();
}
}
if (ret == 0)
continue;
return (-1);
} else {
assert(0);
abort();
}
}
continue;
}
/*
* If walking only required properties, check if
* the retrieved property is required.
*/
if (flags & SCF_PROP_TMPL_FLAG_REQUIRED) {
if (required == 0)
continue;
} else {
return (-1);
}
}
return (0);
}
if (err == -1) {
return (-1);
} else {
assert(0);
abort();
}
} else if (err == 0) {
prop_tmpl->prt_populated = 0;
}
return (1);
return (-1);
}
void
{
if (t == NULL)
return;
scf_pg_destroy(t->prt_pg);
scf_iter_destroy(t->prt_iter);
free(t->prt_pg_name);
free(t);
}
void
{
scf_pg_destroy(t->prt_pg);
free(t->prt_pg_name);
t->prt_pg_name = NULL;
scf_iter_destroy(t->prt_iter);
t->prt_populated = 0;
}
/*
* Returns -1 on failure. Sets scf_error():
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_DELETED
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_PERMISSION_DENIED
* SCF_ERROR_TEMPLATE_INVALID
* The name of the template property group (the pname property) has
* an improper repository format and is not type astring or has
* more than one value.
*/
{
}
/*
* returns an allocated string that must be freed
*
* Returns NULL on failure, sets scf_error() to:
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_DELETED
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_INVALID_ARGUMENT
* name not a valid property name
* name and locale are too long to make a property name
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_NOT_FOUND
* Property doesn't exist or exists and has no value.
* SCF_ERROR_PERMISSION_DENIED
* SCF_ERROR_TEMPLATE_INVALID
*/
static char *
{
/*
* Valid locales are always in the for of xx_YY.CODESET@ATTRIBUTE
* Only xx, the language part is required. The country code, YY as well
* as the CODESET and ATTRIBUTE are all optional but they MUST appear
* that order.
*
* If we use the locale from setlocale, we'll look first for it as
* provided by the setlocale(3C). If the the lookup fails, we'll trim
* from right to left in this order: '@', '.' and '_'. We'll pick the
* first match. If all of them fail, we'll try the "C" locale.
*
* For locales provided by the caller, we'll not do the trimming
* described above, but will fall back to "C" locale.
*/
char const *t;
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
return (NULL);
}
for (t = "@._"; *t != '\0'; t++) {
if (lname_prop != NULL)
break;
if (scf_error() != SCF_ERROR_NOT_FOUND &&
scf_error() != SCF_ERROR_DELETED)
goto out; /* lname_prop == NULL */
}
while (*t != '\0') {
char *p;
*p = '\0';
/*
* try new locale.
*/
break;
}
/*
* The trimming char is not on the locale,
* let's try the one next without a trip to the
* repository.
*/
t++;
}
/*
* if the inner while loop reached the end of t, bail.
*/
if (*t == '\0')
break;
}
}
if (lname_prop == NULL) {
if (scf_error() != SCF_ERROR_NOT_FOUND &&
scf_error() != SCF_ERROR_DELETED)
goto out; /* lname_prop == NULL */
goto out; /* lname_prop == NULL */
*elocale = "C";
}
if (lname_prop == NULL) {
if (scf_error() == SCF_ERROR_TYPE_MISMATCH ||
(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
}
out:
return (lname_prop);
}
{
return (-1);
}
/*
* returns an allocated string that must be freed
*
* Returns -1 on failure, sets scf_error() to:
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_DELETED
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_INVALID_ARGUMENT
* locale is too long to make a valid property name
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_NOT_FOUND
* Property doesn't exist or exists and has no value.
* SCF_ERROR_PERMISSION_DENIED
* SCF_ERROR_TEMPLATE_INVALID
*/
{
}
{
return (-1);
}
/*
* returns an allocated string that must be freed
*
* Returns -1 on failure, sets scf_error() to:
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_DELETED
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_INVALID_ARGUMENT
* locale is too long to make a valid property name
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_NOT_FOUND
* Property doesn't exist or exists and has no value.
* SCF_ERROR_PERMISSION_DENIED
* SCF_ERROR_TEMPLATE_INVALID
*/
{
}
/*
* Returns -1 on failure. Sets scf_error():
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_DELETED
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_NOT_FOUND
* 'type' property doesn't exist or exists and has no value.
* SCF_ERROR_PERMISSION_DENIED
* SCF_ERROR_TEMPLATE_INVALID
* 'type' property is not SCF_TYPE_ASTRING or has more than one value.
*/
{
}
/*
* Returns -1 on failure, sets scf_error() to:
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_DELETED
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_PERMISSION_DENIED
* SCF_ERROR_TEMPLATE_INVALID
* required property is not SCF_TYPE_BOOLEAN or has more than one value.
*/
int
{
out) == -1) {
return (-1);
} else switch (scf_error()) {
case SCF_ERROR_TYPE_MISMATCH:
(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
return (-1);
case SCF_ERROR_NOT_FOUND:
*out = 0;
return (0);
default:
assert(0);
abort();
}
}
return (0);
}
/*
* Returns -1 on failure. Sets scf_error():
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_DELETED
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_PERMISSION_DENIED
* SCF_ERROR_TEMPLATE_INVALID
* target property is not SCF_TYPE_ASTRING or has more than one value.
*/
{
return (-1);
} else switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
case SCF_ERROR_TYPE_MISMATCH:
(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
return (-1);
case SCF_ERROR_NOT_SET:
default:
assert(0);
abort();
}
}
}
/*
* Returns -1 on failure. Sets scf_error():
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_DELETED
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_PERMISSION_DENIED
* SCF_ERROR_TEMPLATE_INVALID
*/
{
(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
}
return (-1);
} else switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
case SCF_ERROR_TYPE_MISMATCH:
(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
return (-1);
case SCF_ERROR_NOT_SET:
default:
assert(0);
abort();
}
}
}
/*
* Returns -1 on failure. Sets scf_error():
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_DELETED
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_NOT_FOUND
* 'type' property doesn't exist or exists and has no value.
* SCF_ERROR_PERMISSION_DENIED
* SCF_ERROR_TEMPLATE_INVALID
* 'type' property is not SCF_TYPE_ASTRING, has more than one value,
* is SCF_TYPE_INVALID, or is the empty string.
*/
int
{
char *type;
(void) scf_set_error(SCF_ERROR_NOT_FOUND);
return (-1);
}
return (-1);
} else switch (scf_error()) {
case SCF_ERROR_TYPE_MISMATCH:
(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
/*FALLTHROUGH*/
case SCF_ERROR_NOT_FOUND:
return (-1);
case SCF_ERROR_NOT_SET:
default:
assert(0);
abort();
}
}
if (*out == SCF_TYPE_INVALID) {
(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
return (-1);
}
return (0);
}
/*
* Returns -1 on failure, sets scf_error() to:
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_DELETED
* Property group which represents t was deleted.
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_PERMISSION_DENIED
* SCF_ERROR_TEMPLATE_INVALID
* required property is not SCF_TYPE_ASTRING has more than one value.
*/
int
{
out) == -1) {
return (-1);
} else switch (scf_error()) {
case SCF_ERROR_TYPE_MISMATCH:
(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
return (-1);
case SCF_ERROR_NOT_FOUND:
*out = 0;
return (0);
case SCF_ERROR_NOT_SET:
default:
assert(0);
abort();
}
}
return (0);
}
{
return (-1);
}
/*
* Returns -1 on failure. Sets scf_error():
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_DELETED
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_NOT_FOUND
* Property doesn't exist or exists and has no value.
* SCF_ERROR_INVALID_ARGUMENT
* locale is too long to make a property name
* SCF_ERROR_PERMISSION_DENIED
* SCF_ERROR_TEMPLATE_INVALID
* common_name property is not SCF_TYPE_ASTRING has more than one value.
*/
char **out)
{
}
{
return (-1);
}
/*
* Returns -1 on failure. Sets scf_error():
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_DELETED
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_NOT_FOUND
* Property doesn't exist or exists and has no value.
* SCF_ERROR_INVALID_ARGUMENT
* locale is too long to make a property name
* SCF_ERROR_PERMISSION_DENIED
* SCF_ERROR_TEMPLATE_INVALID
* description property is not SCF_TYPE_ASTRING has more than one value.
*/
char **out)
{
}
{
return (-1);
}
/*
* Returns -1 on failure. Sets scf_error():
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_DELETED
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_NOT_FOUND
* Property doesn't exist or exists and has no value.
* SCF_ERROR_INVALID_ARGUMENT
* locale is too long to make a property name
* SCF_ERROR_PERMISSION_DENIED
* SCF_ERROR_TEMPLATE_INVALID
* units property is not SCF_TYPE_ASTRING has more than one value.
*/
{
}
/*
* Returns -1 on failure. Sets scf_error():
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_DELETED
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_PERMISSION_DENIED
* SCF_ERROR_TEMPLATE_INVALID
* visibility property is not SCF_TYPE_ASTRING has more than one value.
*/
int
{
char *visibility;
if (visibility == NULL) {
return (-1);
} else switch (scf_error()) {
/* prop doesn't exist we take the default value */
case SCF_ERROR_NOT_FOUND:
return (0);
case SCF_ERROR_TYPE_MISMATCH:
(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
return (-1);
case SCF_ERROR_NOT_SET:
default:
assert(0);
abort();
}
} else {
(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
return (-1);
}
return (0);
}
/*
* Return an allocated string containing the value that must be freed
* with free().
*
* On error set scf_error() _NO_MEMORY, or _NOT_SET (val has not been set
* to a value).
*/
static char *
{
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
}
return (buf);
}
/*
* Returns -1 on failure, sets scf_error() to:
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_DELETED
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_NOT_FOUND
* SCF_ERROR_PERMISSION_DENIED
* SCF_ERROR_TEMPLATE_INVALID
*/
int
{
int ret = 0;
if (_read_single_value_from_pg(t->prt_pg,
SCF_PROPERTY_TM_CARDINALITY_MIN, &val_min) == 0) {
goto error;
} else {
if (scf_error() == SCF_ERROR_NOT_FOUND)
*min = 0;
else
goto error;
}
if (_read_single_value_from_pg(t->prt_pg,
SCF_PROPERTY_TM_CARDINALITY_MAX, &val_max) == 0) {
goto error;
} else {
if (scf_error() == SCF_ERROR_NOT_FOUND)
*max = UINT64_MAX;
else
goto error;
}
goto cleanup;
ret = -1;
} else switch (scf_error()) {
case SCF_ERROR_TYPE_MISMATCH:
(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
/*FALLTHROUGH*/
case SCF_ERROR_NOT_FOUND:
ret = -1;
break;
case SCF_ERROR_NOT_SET:
default:
assert(0);
abort();
}
return (ret);
}
/*
* Returns -1 on failure. Sets scf_error():
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_DELETED
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_NOT_FOUND
* Property doesn't exist or exists and has no value.
* SCF_ERROR_PERMISSION_DENIED
* SCF_ERROR_TEMPLATE_INVALID
*/
int
{
if (_read_astrings_values(t->prt_pg,
return (-1);
} else switch (scf_error()) {
case SCF_ERROR_TYPE_MISMATCH:
(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
/*FALLTHROUGH*/
case SCF_ERROR_NOT_FOUND:
return (-1);
case SCF_ERROR_NOT_SET:
default:
assert(0);
abort();
}
} else if (vals->value_count == 0) {
/* property has no value */
(void) scf_set_error(SCF_ERROR_NOT_FOUND);
return (-1);
}
return (0);
}
/*
* Returns -1 on failure. Sets scf_error():
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_DELETED
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_NOT_FOUND
* Property doesn't exist or exists and has no value.
* SCF_ERROR_PERMISSION_DENIED
* SCF_ERROR_TEMPLATE_INVALID
*/
int
{
char **ret;
return (-1);
} else switch (scf_error()) {
case SCF_ERROR_TYPE_MISMATCH:
(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
/*FALLTHROUGH*/
case SCF_ERROR_NOT_FOUND:
return (-1);
case SCF_ERROR_NOT_SET:
default:
assert(0);
abort();
}
} else if (vals->value_count == 0) {
/* property has no value */
(void) scf_set_error(SCF_ERROR_NOT_FOUND);
return (-1);
}
return (0);
}
/*
* Returns NULL on failure. Sets scf_error():
* Caller is responsible for freeing returned pointer after use.
* SCF_ERROR_CONSTRAINT_VIOLATED
* More tokens than the array size supplied.
* SCF_ERROR_NO_MEMORY
*/
static void *
{
char *lasts;
int n = 0;
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
return (NULL);
}
assert(0);
abort();
}
n++;
if (n >= size) {
goto error;
}
n++;
}
if (n < size) {
goto error;
}
return (str);
return (NULL);
}
/*
* check if name is among values of CHOICES_INCLUDE_VALUES
* return 0 if name is present, 1 name is not present, -1 on failure
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_DELETED
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_PERMISSION_DENIED
* SCF_ERROR_TEMPLATE_INVALID
*/
static int
{
int n = 0, r = 1;
char **ret;
return (-1);
} else switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
return (1);
case SCF_ERROR_TYPE_MISMATCH:
(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
return (-1);
case SCF_ERROR_NOT_SET:
default:
assert(0);
abort();
}
}
for (n = 0; n < vals.value_count; ++n) {
r = 0;
break;
}
}
return (r);
}
void
{
return;
ranges->scr_num_ranges = 0;
}
void
{
return;
ranges->sir_num_ranges = 0;
}
/*
* Returns -1 on failure. Sets scf_error():
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_CONSTRAINT_VIOLATED
* SCF_ERROR_DELETED
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_NOT_FOUND
* Property doesn't exist or exists and has no value.
* SCF_ERROR_PERMISSION_DENIED
* SCF_ERROR_TEMPLATE_INVALID
*/
static int
{
int i = 0;
char **ret;
char *endptr;
goto error;
if (vals.value_count == 0) {
/* range values are empty */
(void) scf_set_error(SCF_ERROR_NOT_FOUND);
goto cleanup;
}
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
goto cleanup;
}
for (i = 0; i < vals.value_count; ++i) {
/* min and max should be separated by a "," */
2)) == NULL)
goto cleanup;
errno = 0;
goto cleanup;
}
errno = 0;
goto cleanup;
}
goto cleanup;
}
}
return (0);
return (-1);
} else switch (scf_error()) {
case SCF_ERROR_TYPE_MISMATCH:
(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
/*FALLTHROUGH*/
case SCF_ERROR_NOT_FOUND:
return (-1);
case SCF_ERROR_NOT_SET:
default:
assert(0);
abort();
}
/*NOTREACHED*/
}
/*
* Returns -1 on failure. Sets scf_error():
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_CONSTRAINT_VIOLATED
* SCF_ERROR_DELETED
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_NOT_FOUND
* Property doesn't exist or exists and has no value.
* SCF_ERROR_PERMISSION_DENIED
* SCF_ERROR_TEMPLATE_INVALID
*/
static int
{
int n = 0;
char **ret;
char *endptr;
goto error;
if (vals.value_count == 0) {
/* range values are empty */
(void) scf_set_error(SCF_ERROR_NOT_FOUND);
goto cleanup;
}
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
goto cleanup;
}
while (n < vals.value_count) {
/* min and max should be separated by a "," */
== NULL)
goto cleanup;
errno = 0;
goto cleanup;
}
errno = 0;
goto cleanup;
}
(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
goto cleanup;
}
++n;
}
return (0);
return (-1);
} else switch (scf_error()) {
case SCF_ERROR_TYPE_MISMATCH:
(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
/*FALLTHROUGH*/
case SCF_ERROR_NOT_FOUND:
return (-1);
case SCF_ERROR_NOT_SET:
default:
assert(0);
abort();
}
/*NOTREACHED*/
}
/*
* Returns -1 on failure. Sets scf_error():
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_CONSTRAINT_VIOLATED
* SCF_ERROR_DELETED
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_NOT_FOUND
* Property doesn't exist or exists and has no value.
* SCF_ERROR_PERMISSION_DENIED
* SCF_ERROR_TEMPLATE_INVALID
*/
int
{
ranges));
}
int
{
ranges));
}
int
{
ranges));
}
int
{
ranges));
}
/*
* Returns -1 on failure. Sets scf_error():
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_DELETED
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_NOT_FOUND
* Property doesn't exist or exists and has no value.
* SCF_ERROR_PERMISSION_DENIED
* SCF_ERROR_TEMPLATE_INVALID
*/
int
{
int r;
char **ret;
/* First, look for explicitly declared choices. */
c_flag = 1;
} else if (scf_error() != SCF_ERROR_NOT_FOUND) {
goto error;
}
/* Next, check for choices included by 'values'. */
/* read values_name */
if (c_flag == 1)
/* append values */
else
/* read values */
c_flag = 1;
} else if (scf_error() != SCF_ERROR_NOT_FOUND) {
goto error;
}
} else if (r == -1) {
goto error;
}
/* Finally check for choices included by 'constraints'. */
0) {
/* read constraint_name */
if (c_flag == 1)
/* append values */
else
/* read values */
c_flag = 1;
} else if (scf_error() != SCF_ERROR_NOT_FOUND) {
goto error;
}
} else if (r == -1) {
goto error;
}
(void) scf_set_error(SCF_ERROR_NOT_FOUND);
return (-1);
}
return (0);
return (-1);
} else switch (scf_error()) {
case SCF_ERROR_TYPE_MISMATCH:
(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
return (-1);
case SCF_ERROR_NOT_SET:
default:
assert(0);
abort();
}
/*NOTREACHED*/
}
void
{
int i;
return;
/* free values */
switch (vals->value_type) {
case SCF_TYPE_BOOLEAN:
break;
case SCF_TYPE_COUNT:
break;
case SCF_TYPE_INTEGER:
break;
case SCF_TYPE_ASTRING:
break;
case SCF_TYPE_USTRING:
break;
case SCF_TYPE_OPAQUE:
break;
case SCF_TYPE_TIME:
break;
default:
assert(0);
abort();
}
for (i = 0; i < vals->value_count; ++i) {
}
vals->value_count = 0;
}
/*
* char *_make_value_name()
*
* Construct the prefix for a value common name or value description property.
* It takes the form:
* value_<BASE32 name>_<common_name|description>_
* This is then combined with a localized suffix by the caller to look
* up the property in the repository:
* value_<BASE32 name>_<common_name|description>_<lang>
*
* Returns NULL on failure. Sets scf_error():
* SCF_ERROR_INVALID_ARGUMENT
* Name isn't short enough make a value name with.
* SCF_ERROR_NO_MEMORY
*/
static char *
{
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
return (NULL);
}
SCF_ENCODE32_PAD) != 0) {
/* Shouldn't happen. */
assert(0);
}
(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
return (NULL);
}
(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
return (NULL);
}
(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
return (NULL);
}
(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
return (NULL);
}
return (name);
}
{
if (value_name == NULL)
return (-1);
elocale);
return (-1);
}
/*
* ssize_t scf_tmpl_value_common_name()
*
* Populates "out" with an allocated string containing the value's
* common name. Returns the size of the string on successful return.
* out must be freed with free() on successful return.
*
* Returns -1 on failure, sets scf_error() to:
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_DELETED
* Property group was deleted.
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_INVALID_ARGUMENT
* name not a valid property name
* name and locale are too long to make a property name
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_NOT_FOUND
* Property doesn't exist or exists and has no value.
* SCF_ERROR_PERMISSION_DENIED
* SCF_ERROR_TEMPLATE_INVALID
* property is not SCF_TYPE_ASTRING has more than one value.
*/
{
}
{
if (value_name == NULL)
return (-1);
elocale);
return (-1);
}
/*
* ssize_t scf_tmpl_value_description()
*
* Populates "out" with an allocated string containing the value's
* description. Returns the size of the string on successful return.
* out must be freed with free() on successful return.
*
* Returns -1 on failure, sets scf_error() to:
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_DELETED
* Property group was deleted.
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_INVALID_ARGUMENT
* name not a valid property name
* name and locale are too long to make a property name
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_NOT_FOUND
* Property doesn't exist or exists and has no value.
* SCF_ERROR_PERMISSION_DENIED
* SCF_ERROR_TEMPLATE_INVALID
* property is not SCF_TYPE_ASTRING has more than one value.
*/
{
}
/*
* Templates error messages format, in human readable form.
* Each line is one error item:
*
* prefix error message
* FMRI="err->te_errs->tes_fmri"
* Property group="err->te_pg_name"
* Property name="err->te_prop_name"
* expected value 1="err->te_ev1"
* expected value 2="err->te_ev2"
* actual value="err->te_actual"
* Tempalte source="err->te_tmpl_fmri"
* pg_pattern name="err->tmpl_pg_name"
* pg_pattern type="err->tmpl_pg_type"
* prop_pattern name="err->tmpl_prop_name"
* prop_pattern type="err->tmpl_prop_type"
*
* To add a new error type, include scf_tmpl_error_type_t in libscf.h
* add one entry in em_desc[], and update the functions pointed by the
* _tmpl_error_access array with the new error code. Also, update the
* scf_tmpl_error_* functions to provide access to desired
* scf_tmpl_error_t fields.
*
* To add a new error item, add a new field to scf_tmpl_error_t, a new field
* in _scf_tmpl_error_desc or a new non-error-dependent string, add a new entry
* in _tmpl_error_access array and create the appropriate get_val, get_desc
* functions.
*
* Changes to both the validation logic and the error types and items must
* be coordinated with the code in svccfg to ensure both libscf and svccfg's
* manifest validation validate the same things.
*/
/*
* Container for all template errors on a validated object.
*/
struct scf_tmpl_errors {
int tes_index;
int tes_num_errs;
int tes_errs_size;
const char *tes_fmri;
const char *tes_prefix;
/* will free strings in tes_errs */
};
/*
* Templates error-dependent labels
*/
struct _scf_tmpl_error_desc {
const char *em_msg;
const char *em_ev1;
const char *em_ev2;
const char *em_actual;
};
/*
* This array MUST be kept in synch with the template error definition of
* scf_tmpl_error_type_t in libscf.h
*/
/* SCF_TERR_MISSING_PG */
{ "Required property group missing", "Name of missing property group",
"Type of missing property group", NULL },
/* SCF_TERR_WRONG_PG_TYPE */
"Actual type" },
/* SCF_TERR_MISSING_PROP */
/* SCF_TERR_WRONG_PROP_TYPE */
"Actual property type" },
/* SCF_TERR_CARDINALITY_VIOLATION */
{ "Number of property values violates cardinality restriction",
"Cardinality minimum", "Cardinality maximum",
"Actual number of values" },
/* SCF_TERR_VALUE_CONSTRAINT_VIOLATED */
/* SCF_TERR_RANGE_VIOLATION */
/* SCF_TERR_PG_REDEFINE */
{ "Instance redefines pg_pattern", "Instance pg_pattern name",
"Instance pg_pattern type", NULL },
/* SCF_TERR_PROP_TYPE_MISMATCH */
/* SCF_TERR_VALUE_OUT_OF_RANGE */
/* SCF_TERR_INVALID_VALUE */
/* SCF_TERR_PG_PATTERN_CONFLICT */
{ "Conflicting pg_pattern specifications", "Template source",
"pg_pattern name", "pg_pattern type" },
/* SCF_TERR_PROP_PATTERN_CONFLICT */
{ "Conflicting prop_pattern specifications", "Template source",
"prop_pattern name", "prop_pattern type" },
/* SCF_TERR_GENERAL_REDEFINE */
{ "Service or instance pg_pattern redefines a global or restarter "
"pg_pattern", "Template source", "pg_pattern name",
"pg_pattern type" },
/* SCF_TERR_INCLUDE_VALUES */
{ "Missing constraints or values for include_values element",
/* SCF_TERR_PG_PATTERN_INCOMPLETE */
{ "Required pg_pattern is missing a name or type attribute",
/* SCF_TERR_PROP_PATTERN_INCOMPLETE */
{ "Required prop_pattern is missing a type attribute",
};
/*
* Templates non error-dependent labels
*/
static const char *
{
case SCF_TERR_MISSING_PG:
case SCF_TERR_WRONG_PG_TYPE:
case SCF_TERR_MISSING_PROP:
case SCF_TERR_WRONG_PROP_TYPE:
case SCF_TERR_RANGE_VIOLATION:
case SCF_TERR_PG_REDEFINE:
case SCF_TERR_INCLUDE_VALUES:
case SCF_TERR_INVALID_VALUE:
default:
return (NULL);
}
}
static const char *
{
case SCF_TERR_WRONG_PG_TYPE:
case SCF_TERR_MISSING_PROP:
case SCF_TERR_WRONG_PROP_TYPE:
case SCF_TERR_RANGE_VIOLATION:
case SCF_TERR_MISSING_PG:
case SCF_TERR_PG_REDEFINE:
case SCF_TERR_INVALID_VALUE:
case SCF_TERR_INCLUDE_VALUES:
default:
return (NULL);
}
}
static const char *
{
case SCF_TERR_WRONG_PROP_TYPE:
case SCF_TERR_RANGE_VIOLATION:
case SCF_TERR_MISSING_PG:
case SCF_TERR_WRONG_PG_TYPE:
case SCF_TERR_MISSING_PROP:
case SCF_TERR_PG_REDEFINE:
case SCF_TERR_INVALID_VALUE:
case SCF_TERR_INCLUDE_VALUES:
default:
return (NULL);
}
}
static const char *
{
case SCF_TERR_MISSING_PG:
case SCF_TERR_WRONG_PG_TYPE:
case SCF_TERR_MISSING_PROP:
case SCF_TERR_WRONG_PROP_TYPE:
case SCF_TERR_RANGE_VIOLATION:
case SCF_TERR_PG_REDEFINE:
case SCF_TERR_INCLUDE_VALUES:
case SCF_TERR_INVALID_VALUE:
default:
return (NULL);
}
}
static const char *
{
case SCF_TERR_MISSING_PG:
case SCF_TERR_RANGE_VIOLATION:
case SCF_TERR_PG_REDEFINE:
case SCF_TERR_WRONG_PG_TYPE:
case SCF_TERR_MISSING_PROP:
case SCF_TERR_WRONG_PROP_TYPE:
case SCF_TERR_INVALID_VALUE:
case SCF_TERR_INCLUDE_VALUES:
default:
return (NULL);
}
}
static const char *
{
case SCF_TERR_MISSING_PG:
case SCF_TERR_WRONG_PG_TYPE:
case SCF_TERR_WRONG_PROP_TYPE:
case SCF_TERR_RANGE_VIOLATION:
case SCF_TERR_INVALID_VALUE:
case SCF_TERR_INCLUDE_VALUES:
return (dgettext(TEXT_DOMAIN,
case SCF_TERR_MISSING_PROP:
case SCF_TERR_PG_REDEFINE:
default:
return (NULL);
}
}
static const char *
{
case SCF_TERR_MISSING_PG:
case SCF_TERR_WRONG_PG_TYPE:
case SCF_TERR_MISSING_PROP:
case SCF_TERR_WRONG_PROP_TYPE:
case SCF_TERR_RANGE_VIOLATION:
case SCF_TERR_PG_REDEFINE:
case SCF_TERR_INVALID_VALUE:
case SCF_TERR_INCLUDE_VALUES:
default:
return (NULL);
}
}
static const char *
{
case SCF_TERR_MISSING_PG:
case SCF_TERR_WRONG_PG_TYPE:
case SCF_TERR_MISSING_PROP:
case SCF_TERR_WRONG_PROP_TYPE:
case SCF_TERR_RANGE_VIOLATION:
case SCF_TERR_PG_REDEFINE:
case SCF_TERR_INVALID_VALUE:
case SCF_TERR_INCLUDE_VALUES:
default:
return (NULL);
}
}
static const char *
{
case SCF_TERR_MISSING_PG:
case SCF_TERR_WRONG_PG_TYPE:
case SCF_TERR_MISSING_PROP:
case SCF_TERR_WRONG_PROP_TYPE:
case SCF_TERR_RANGE_VIOLATION:
case SCF_TERR_PG_REDEFINE:
case SCF_TERR_INVALID_VALUE:
case SCF_TERR_INCLUDE_VALUES:
default:
return (NULL);
}
}
static const char *
{
case SCF_TERR_MISSING_PROP:
case SCF_TERR_WRONG_PROP_TYPE:
case SCF_TERR_RANGE_VIOLATION:
case SCF_TERR_INVALID_VALUE:
case SCF_TERR_INCLUDE_VALUES:
case SCF_TERR_MISSING_PG:
case SCF_TERR_WRONG_PG_TYPE:
case SCF_TERR_PG_REDEFINE:
default:
return (NULL);
}
}
static const char *
{
case SCF_TERR_MISSING_PROP:
case SCF_TERR_WRONG_PROP_TYPE:
case SCF_TERR_RANGE_VIOLATION:
case SCF_TERR_INVALID_VALUE:
case SCF_TERR_INCLUDE_VALUES:
case SCF_TERR_MISSING_PG:
case SCF_TERR_WRONG_PG_TYPE:
case SCF_TERR_PG_REDEFINE:
default:
return (NULL);
}
}
static const char *
{
}
static const char *
{
return (err->te_pg_name);
}
static const char *
{
return (err->te_prop_name);
}
static const char *
{
}
static const char *
{
}
static const char *
{
}
static const char *
{
return (err->te_tmpl_fmri);
}
static const char *
{
return (err->te_tmpl_pg_name);
}
static const char *
{
return (err->te_tmpl_pg_type);
}
static const char *
{
return (err->te_tmpl_prop_name);
}
static const char *
{
return (err->te_tmpl_prop_type);
}
/*
* Templates error item retrival functions
*/
/*
* if new items (lines) are added to the templates error messages,
* new entries in this array (and new fuctions) will be required.
*/
static struct _tmpl_error_access {
} _tmpl_error_items[] = {
{ NULL }
};
/*
* Allocate a new scf_tmpl_error_t and add it to the errs list provided.
* Returns NULL on failure. Sets scf_error():
* SCF_ERROR_NO_MEMORY
*/
static scf_tmpl_error_t *
{
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
return (NULL);
}
/* Time to grow the pointer array. */
sizeof (scf_tmpl_error_t *));
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
return (NULL);
}
sizeof (scf_tmpl_error_t *));
}
errs->tes_num_errs++;
return (ret);
}
/*
*
* If destroy_strings is set, scf_tmpl_errors_destroy will free the
* strings in scf_tmpl_error_t entries.
*
* Returns NULL on failure. Sets scf_error():
* SCF_ERROR_NO_MEMORY
*/
{
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
return (NULL);
}
ret->tes_num_errs = 0;
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
return (NULL);
}
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
return (NULL);
}
/* Make space for a few errors. */
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
return (NULL);
}
return (ret);
}
/*
* return 0 on success, if fails set scf_error() to:
*
* SCF_ERROR_NO_MEMORY
*/
int
{
else
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
return (-1);
}
return (0);
}
/*
*
* Returns -1 on failure. Sets scf_error():
* SCF_ERROR_NO_MEMORY
*/
int
const char *tmpl_prop_name, const char *tmpl_prop_type)
{
return (-1);
return (0);
}
/*
* returns an allocated string that must be freed with free()
* string contains converted 64-bit integer value
* flag set for signed values
* if fails return NULL and set scf_error() to:
* SCF_ERROR_NO_MEMORY
*/
static char *
{
char *buf;
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
return (NULL);
}
if (flag == 0)
else
return (buf);
}
/*
* return 0 on success, -1 on failure.
* set scf_error() to:
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_DELETED
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_PERMISSION_DENIED
* SCF_ERROR_TEMPLATE_INVALID
*/
static int
{
return (-1);
goto cleanup;
}
goto cleanup;
}
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
goto cleanup;
}
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
goto cleanup;
}
return (-1);
}
/*
* return 0 on success, -1 on failure.
* set scf_error() to:
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_DELETED
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_PERMISSION_DENIED
* SCF_ERROR_TEMPLATE_INVALID
*/
static int
{
return (-1);
goto cleanup;
goto cleanup;
goto cleanup;
}
goto cleanup;
}
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
goto cleanup;
}
return (-1);
}
/*
* return 0 on success, -1 on failure.
* set scf_error() to:
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_DELETED
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_PERMISSION_DENIED
* SCF_ERROR_TEMPLATE_INVALID
*/
static int
{
return (-1);
goto cleanup;
goto cleanup;
}
goto cleanup;
}
goto cleanup;
}
t_prop_type = NULL;
} else if (t_prop_type == NULL) {
goto cleanup;
}
if (t_prop_type == NULL)
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
goto cleanup;
}
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
goto cleanup;
}
t_prop_type));
return (-1);
}
/*
* return 0 on success, -1 on failure.
* set scf_error() to:
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_DELETED
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_PERMISSION_DENIED
* SCF_ERROR_TEMPLATE_INVALID
*/
static int
{
return (-1);
goto cleanup;
goto cleanup;
goto cleanup;
goto cleanup;
}
goto cleanup;
}
goto cleanup;
}
t_prop_type = NULL;
} else if (t_prop_type == NULL) {
goto cleanup;
}
if (t_prop_type == NULL)
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
goto cleanup;
}
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
goto cleanup;
}
return (-1);
}
/*
* return 0 on success, -1 on failure.
* set scf_error() to:
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_DELETED
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_PERMISSION_DENIED
* SCF_ERROR_TEMPLATE_INVALID
*/
static int
{
return (-1);
switch (type) {
case SCF_TERR_RANGE_VIOLATION:
goto cleanup;
goto cleanup;
break;
/* keep pg_name = NULL and prop_name = NULL */
break;
}
goto cleanup;
}
goto cleanup;
}
goto cleanup;
}
t_prop_type = NULL;
} else if (t_prop_type == NULL) {
goto cleanup;
}
if (t_prop_type == NULL)
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
goto cleanup;
}
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
goto cleanup;
}
} else {
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
goto cleanup;
}
}
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
goto cleanup;
}
} else {
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
goto cleanup;
}
}
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
goto cleanup;
}
t_prop_type));
return (-1);
}
/*
* return 0 on success, -1 on failure.
* set scf_error() to:
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_DELETED
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_PERMISSION_DENIED
* SCF_ERROR_TEMPLATE_INVALID
*/
static int
{
return (-1);
switch (type) {
goto cleanup;
goto cleanup;
/*FALLTHROUGH*/
case SCF_TERR_INVALID_VALUE:
/* keep pg_name = NULL and prop_name = NULL */
goto cleanup;
break;
/* keep pg_name = NULL and prop_name = NULL */
/* use value for value type */
NULL) {
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
goto cleanup;
}
break;
}
goto cleanup;
}
goto cleanup;
}
goto cleanup;
}
t_prop_type = NULL;
} else if (t_prop_type == NULL) {
goto cleanup;
}
if (t_prop_type == NULL)
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
goto cleanup;
}
return (-1);
}
/*
* return 0 on success, -1 on failure.
* set scf_error() to:
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_DELETED
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_PERMISSION_DENIED
* SCF_ERROR_TEMPLATE_INVALID
*/
static int
{
return (-1);
switch (type) {
case SCF_TERR_RANGE_VIOLATION:
goto cleanup;
goto cleanup;
break;
/* keep pg_name = NULL and prop_name = NULL */
break;
}
goto cleanup;
}
goto cleanup;
}
goto cleanup;
}
t_prop_type = NULL;
} else if (t_prop_type == NULL) {
goto cleanup;
}
if (t_prop_type == NULL)
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
goto cleanup;
}
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
goto cleanup;
}
} else {
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
goto cleanup;
}
}
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
goto cleanup;
}
} else {
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
goto cleanup;
}
}
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
goto cleanup;
}
t_prop_type));
return (-1);
}
/*
* return 0 on success, -1 on failure.
* set scf_error() to:
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_DELETED
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_PERMISSION_DENIED
* SCF_ERROR_TEMPLATE_INVALID
*/
static int
scf_pg_tmpl_t *r)
{
return (-1);
goto cleanup;
}
goto cleanup;
}
goto cleanup;
}
goto cleanup;
}
return (-1);
}
/*
* return 0 if value is within count ranges constraint.
* return -1 otherwise
*/
static int
{
int i;
for (i = 0; i < cr->scr_num_ranges; ++i) {
/* value is within ranges constraint */
return (0);
}
}
return (-1);
}
/*
* return 0 if value is within count ranges constraint.
* return -1 otherwise
*/
static int
{
int i;
for (i = 0; i < ir->sir_num_ranges; ++i) {
/* value is within integer ranges constraint */
return (0);
}
}
return (-1);
}
/*
* int _value_in_constraint()
*
* Checks whether the supplied value violates any of the constraints
* specified in the supplied property template. If it does, an appropriate
* error is appended to "errs". pg and prop, if supplied, are used to
* augment the information in the error. Returns 0 on success.
*
* Returns -1 on failure. Sets scf_error():
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_DELETED
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_INVALID_ARGUMENT
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_PERMISSION_DENIED
* SCF_ERROR_TEMPLATE_INVALID
*/
static int
{
char *vstr;
char **constraints;
int n = 0;
int r;
int err_flag = 0;
if (type == SCF_TYPE_INVALID) {
(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
return (-1);
}
/* Check if template type matches value type. */
if (scf_error() != SCF_ERROR_NOT_FOUND)
/* type is not wildcarded */
return (-1);
return (-1);
}
}
return (1);
}
/* Numeric values should be checked against any range constraints. */
switch (type) {
case SCF_TYPE_COUNT:
assert(r == 0);
if (scf_error() == SCF_ERROR_NOT_FOUND)
break;
if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED)
(void) scf_set_error(
return (-1);
} else {
/* value is within ranges constraint */
return (0);
}
}
/*
* If we get here, we have a possible constraint
* violation.
*/
break;
case SCF_TYPE_INTEGER:
assert(0);
if (scf_error() == SCF_ERROR_NOT_FOUND)
break;
if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED)
(void) scf_set_error(
return (-1);
} else {
/* value is within ranges constraint */
return (0);
}
}
/*
* If we get here, we have a possible constraint
* violation.
*/
break;
default:
break;
}
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
return (-1);
}
/*
* If a set of names is provided, confirm value has one of
* those names.
*/
if (scf_error() != SCF_ERROR_NOT_FOUND) {
return (-1);
}
} else {
/*
* All errors (INVALID_ARGUMENT, NOT_SET, TYPE_MISMATCH)
* should be impossible or already caught above.
*/
assert(r > 0);
for (n = 0; constraints[n] != NULL; ++n) {
/* value is within constraint */
return (0);
}
}
/* if we get here, we have a constraint violation */
}
if (err_flag != 0)
ret = 1;
/* register the errors found */
/*
* Help make the error more human-friendly. If
* pg and prop are provided, we know we're
* validating repository data. If they're not,
* we're validating a potentially hypothetical
* value.
*/
else
ret = -1;
}
else
v_int, 0, 0) == -1)
ret = -1;
}
else
ret = -1;
}
}
return (ret);
}
/*
* Returns -1 on failure. Sets scf_error():
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_DELETED
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_INVALID_ARGUMENT
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_PERMISSION_DENIED
* SCF_ERROR_TEMPLATE_INVALID
*/
int
{
scf_tmpl_errors_t *e = NULL;
char *fmri;
return (-1);
return (-1);
e = *errs;
}
}
{
} else {
return (NULL);
}
}
void
{
}
int
{
const char *str;
int i;
const char *val;
/* prefix */
}
/* error message */
/* no item to print */
continue;
}
return (nsz);
}
/*
* return 0 on success, -1 on failure.
* set scf_error() to:
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_DELETED
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_PERMISSION_DENIED
* SCF_ERROR_TEMPLATE_INVALID
*/
static int
{
scf_handle_t *h;
int count = 0;
int r;
if (scf_error() == SCF_ERROR_NOT_FOUND)
return (0);
else
return (-1);
}
/* Any number of values permitted. Just return success. */
return (0);
}
h = scf_property_handle(prop);
if (h == NULL) {
goto cleanup;
}
iter = scf_iter_create(h);
val = scf_value_create(h);
goto cleanup;
} else {
assert(0);
abort();
}
}
goto cleanup;
} else {
assert(0);
abort();
}
}
count++;
if (r < 0) {
goto cleanup;
} else {
assert(0);
abort();
}
}
goto cleanup;
ret = 0;
return (ret);
}
/*
* Returns -1 on error. Sets scf_error():
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_DELETED
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_PERMISSION_DENIED
* SCF_ERROR_TEMPLATE_INVALID
*/
static int
{
scf_handle_t *h;
int r;
h = scf_pg_handle(pg);
if (h == NULL) {
return (-1);
}
iter = scf_iter_create(h);
val = scf_value_create(h);
return (-1);
} else {
assert(0);
abort();
}
}
goto cleanup;
/* Check type */
if (scf_error() != SCF_ERROR_NOT_FOUND) {
goto cleanup;
} else if (required) {
/* If required, type must be specified. */
(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
goto cleanup;
}
goto cleanup;
} else switch (scf_error()) {
case SCF_ERROR_TYPE_MISMATCH:
prop) == -1)
goto cleanup;
break;
/*
* tmpl_prop_type shouldn't have handed back
* an invalid property type.
*/
case SCF_ERROR_NOT_SET:
default:
assert(0);
abort();
}
}
/* Cardinality */
goto cleanup;
/* Value constraints */
/*
* Iterate through each value, and confirm it is defined as
* constrained.
*/
goto cleanup;
}
goto cleanup;
} else switch (scf_error()) {
goto cleanup;
default:
assert(0);
abort();
}
}
}
if (r < 0) {
goto cleanup;
} else {
assert(0);
abort();
}
}
ret = 0;
return (ret);
}
/*
* Returns -1 on failure, sets scf_error() to:
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_DELETED
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_PERMISSION_DENIED
* SCF_ERROR_TEMPLATE_INVALID
*/
static int
{
scf_handle_t *h;
int r;
return (-1);
}
return (-1);
}
goto cleanup;
}
goto cleanup;
}
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
goto cleanup;
}
if (scf_tmpl_pg_required(t, &pg_required) != 0)
goto cleanup;
goto cleanup;
} else if (pg_required != 0 &&
/* Type must be specified for required pgs. */
(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
goto cleanup;
}
goto cleanup;
}
}
/* Iterate through properties in the repository and check them. */
goto cleanup;
} else {
assert(0);
abort();
}
}
goto cleanup;
}
goto cleanup;
} else switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
/* No template. Continue. */
continue;
default:
assert(0);
abort();
}
}
goto cleanup;
}
if (r < 0) {
goto cleanup;
} else {
assert(0);
abort();
}
}
/*
* Confirm required properties are present.
*/
while ((r = scf_tmpl_iter_props(t, pt,
SCF_PROP_TMPL_FLAG_REQUIRED)) == 0) {
goto cleanup;
/* required properties cannot have type wildcarded */
if (scf_error() == SCF_ERROR_NOT_FOUND)
(void) scf_set_error(
goto cleanup;
}
goto cleanup;
} else switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
pt) == -1)
goto cleanup;
break;
(void) scf_set_error(
goto cleanup;
case SCF_ERROR_NOT_SET:
default:
assert(0);
abort();
}
}
}
if (r < 0) {
goto cleanup;
} else switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
break;
goto cleanup;
default:
assert(0);
abort();
}
}
ret = 0;
return (ret);
}
/*
* Checks if instance fmri redefines any pgs defined in restarter or global
* Return -1 on failure, sets scf_error() to:
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_DELETED
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_INVALID_ARGUMENT
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_NOT_FOUND
* SCF_ERROR_PERMISSION_DENIED
* SCF_ERROR_TEMPLATE_INVALID
*/
static int
{
scf_pg_tmpl_t *t = NULL;
scf_pg_tmpl_t *r = NULL;
int ret;
t = scf_tmpl_pg_create(h);
r = scf_tmpl_pg_create(h);
goto cleanup;
SCF_PG_TMPL_FLAG_EXACT)) == 1) {
goto cleanup;
}
goto cleanup;
}
0)) == 1) {
goto cleanup;
/* not a match */
continue;
}
goto cleanup;
/* not a match */
continue;
}
goto cleanup;
}
/* found a pg_pattern redefinition */
if (_add_tmpl_pg_redefine_error(errs, t,
r) == -1)
goto cleanup;
break;
}
}
if (ret == -1)
goto cleanup;
}
if (ret == -1)
goto cleanup;
ret_val = 0;
if (ret_val == -1) {
switch (scf_error()) {
case SCF_ERROR_TYPE_MISMATCH:
(void) scf_set_error(
/*FALLTHROUGH*/
case SCF_ERROR_NOT_FOUND:
break;
case SCF_ERROR_NOT_SET:
default:
assert(0);
abort();
}
}
}
return (ret_val);
}
/*
* Returns -1 on failure, sets scf_error() to:
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_DELETED
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_INVALID_ARGUMENT
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_NOT_FOUND
* SCF_ERROR_PERMISSION_DENIED
* SCF_ERROR_TEMPLATE_INVALID
*/
int
{
scf_pg_tmpl_t *t = NULL;
int r;
return (-1);
(t = scf_tmpl_pg_create(h)) == NULL) {
/*
* Sets SCF_ERROR_INVALID_ARGUMENT, SCF_ERROR_NO_MEMORY,
* SCF_ERROR_NO_RESOURCES, SCF_ERROR_INTERNAL or
* SCF_ERROR_HANDLE_DESTROYED.
*/
goto cleanup;
}
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
goto cleanup;
}
goto cleanup;
} else switch (scf_error()) {
(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
/*FALLTHROUGH*/
case SCF_ERROR_NOT_FOUND:
goto cleanup;
case SCF_ERROR_NOT_SET:
default:
assert(0);
abort();
}
}
if (flags & SCF_TMPL_VALIDATE_FLAG_CURRENT) {
} else {
(void) scf_set_error(SCF_ERROR_NONE);
goto cleanup;
} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
goto cleanup;
}
}
goto cleanup;
}
/*
* Check that property groups on this instance conform to the template.
*/
goto cleanup;
} else {
assert(0);
abort();
}
}
goto cleanup;
} else {
assert(0);
abort();
}
}
goto cleanup;
} else {
assert(0);
abort();
}
}
0) != 0) {
goto cleanup;
} else switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
continue;
goto cleanup;
default:
assert(0);
abort();
}
}
goto cleanup;
}
if (r < 0) {
goto cleanup;
} else {
assert(0);
abort();
}
}
/*
* Confirm required property groups are present.
*/
SCF_PG_TMPL_FLAG_REQUIRED)) == 1) {
goto cleanup;
goto cleanup;
/*
* required property group templates should not have
* wildcarded name or type
*/
(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
goto cleanup;
}
goto cleanup;
} else switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
goto cleanup;
continue;
case SCF_ERROR_NOT_SET:
default:
assert(0);
abort();
}
}
}
if (r < 0) {
goto cleanup;
} else switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
break;
goto cleanup;
default:
assert(0);
abort();
}
}
ret = 0;
if ((*errs)->tes_num_errs > 0)
ret = 1;
if (ret != 1) {
/* there are no errors to report */
}
return (ret);
}
void
{
int i;
scf_tmpl_error_t *e;
return;
for (i = 0; i < errs->tes_num_errs; ++i) {
free((char *)e->te_pg_name);
free((char *)e->te_prop_name);
free((char *)e->te_tmpl_fmri);
free((char *)e->te_tmpl_pg_name);
free((char *)e->te_tmpl_pg_type);
free((char *)e->te_tmpl_prop_name);
free((char *)e->te_tmpl_prop_type);
}
free(e);
}
}
int
{
case SCF_TERR_MISSING_PG:
case SCF_TERR_WRONG_PG_TYPE:
case SCF_TERR_MISSING_PROP:
case SCF_TERR_WRONG_PROP_TYPE:
case SCF_TERR_RANGE_VIOLATION:
case SCF_TERR_INVALID_VALUE:
case SCF_TERR_PG_REDEFINE:
return (0);
/*NOTREACHED*/
default:
(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
}
return (-1);
}
int
{
case SCF_TERR_MISSING_PG:
case SCF_TERR_WRONG_PG_TYPE:
case SCF_TERR_MISSING_PROP:
case SCF_TERR_WRONG_PROP_TYPE:
case SCF_TERR_RANGE_VIOLATION:
case SCF_TERR_INVALID_VALUE:
case SCF_TERR_PG_REDEFINE:
return (0);
/*NOTREACHED*/
default:
(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
}
return (-1);
}
int
{
case SCF_TERR_MISSING_PG:
case SCF_TERR_WRONG_PG_TYPE:
case SCF_TERR_MISSING_PROP:
case SCF_TERR_WRONG_PROP_TYPE:
case SCF_TERR_RANGE_VIOLATION:
case SCF_TERR_INVALID_VALUE:
case SCF_TERR_PG_REDEFINE:
return (0);
}
(void) scf_set_error(SCF_ERROR_NOT_FOUND);
break;
default:
(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
}
return (-1);
}
int
{
case SCF_TERR_WRONG_PG_TYPE:
return (0);
}
(void) scf_set_error(SCF_ERROR_NOT_FOUND);
break;
case SCF_TERR_WRONG_PROP_TYPE:
case SCF_TERR_RANGE_VIOLATION:
return (0);
}
/*FALLTHROUGH*/
case SCF_TERR_MISSING_PROP:
case SCF_TERR_MISSING_PG:
case SCF_TERR_INVALID_VALUE:
(void) scf_set_error(SCF_ERROR_NOT_FOUND);
break;
case SCF_TERR_PG_REDEFINE:
return (0);
}
(void) scf_set_error(SCF_ERROR_NOT_FOUND);
break;
default:
(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
}
return (-1);
}
int
{
case SCF_TERR_MISSING_PROP:
case SCF_TERR_WRONG_PROP_TYPE:
case SCF_TERR_RANGE_VIOLATION:
case SCF_TERR_INVALID_VALUE:
return (0);
}
/*FALLTHROUGH*/
case SCF_TERR_MISSING_PG:
case SCF_TERR_WRONG_PG_TYPE:
case SCF_TERR_PG_REDEFINE:
(void) scf_set_error(SCF_ERROR_NOT_FOUND);
break;
default:
(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
}
return (-1);
}
int
{
case SCF_TERR_WRONG_PROP_TYPE:
case SCF_TERR_RANGE_VIOLATION:
return (0);
}
/*FALLTHROUGH*/
case SCF_TERR_MISSING_PG:
case SCF_TERR_WRONG_PG_TYPE:
case SCF_TERR_MISSING_PROP:
case SCF_TERR_INVALID_VALUE:
case SCF_TERR_PG_REDEFINE:
(void) scf_set_error(SCF_ERROR_NOT_FOUND);
break;
default:
(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
}
return (-1);
}
int
{
case SCF_TERR_RANGE_VIOLATION:
case SCF_TERR_INVALID_VALUE:
return (0);
}
/*FALLTHROUGH*/
case SCF_TERR_MISSING_PG:
case SCF_TERR_WRONG_PG_TYPE:
case SCF_TERR_MISSING_PROP:
case SCF_TERR_WRONG_PROP_TYPE:
case SCF_TERR_PG_REDEFINE:
(void) scf_set_error(SCF_ERROR_NOT_FOUND);
break;
default:
(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
}
return (-1);
}
const char *
{
if (vis == SCF_TMPL_VISIBILITY_READONLY)
return (SCF_TM_VISIBILITY_READONLY);
else if (vis == SCF_TMPL_VISIBILITY_HIDDEN)
return (SCF_TM_VISIBILITY_HIDDEN);
else if (vis == SCF_TMPL_VISIBILITY_READWRITE)
return (SCF_TM_VISIBILITY_READWRITE);
else
return ("unknown");
}
/*
* The conflict printing code is located here so we can keep the
* number files which require processing for the message build to
* a minimum.
*/
/*
* Message format:
*
* Can set error to:
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_DELETED
* SCF_ERROR_INTERNAL
* SCF_ERROR_INVALID_ARGUMENT
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
*/
int
{
int namelen;
iter = scf_iter_create(h);
dec_iter = scf_iter_create(h);
prop = scf_property_create(h);
dec = scf_decoration_create(h);
goto pg_conflicts_cleanup;
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
goto pg_conflicts_cleanup;
}
goto pg_conflicts_cleanup;
}
if (scf_pg_in_conflict(pg)) {
(void) printf("%s: FMRI=\"%s\";",
"Name of conflicting property group"), pg_name);
SCF_ITER_CONFLICTS_ONLY) < 0) {
(void) printf("\n");
goto pg_conflicts_cleanup;
}
MAXPATHLEN) < 0) {
(void) printf("\n");
goto pg_conflicts_cleanup;
}
(void) printf(" %s=\"%s\";",
}
(void) printf("\n");
}
goto pg_conflicts_cleanup;
}
if (!scf_property_in_conflict(prop))
continue;
goto pg_conflicts_cleanup;
}
(void) printf("%s: FMRI=\"%s\";",
(void) printf(" %s=\"%s/%s\";",
SCF_ITER_CONFLICTS_ONLY) < 0) {
(void) printf("\n");
goto pg_conflicts_cleanup;
}
MAXPATHLEN) < 0) {
(void) printf("\n");
goto pg_conflicts_cleanup;
}
(void) printf(" %s=\"%s\";",
}
(void) printf("\n");
}
ret = 0;
return (ret);
}
/*
* Prints all service and instance conflicts for an instance.
* Can set error to:
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_DELETED
* SCF_ERROR_INTERNAL
* SCF_ERROR_INVALID_ARGUMENT
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NOT_BOUND
*/
int
{
svc = scf_service_create(h);
iter = scf_iter_create(h);
pg = scf_pg_create(h);
goto inst_conflicts_cleanup;
/* First look at instance's parent for conflicts. */
goto inst_conflicts_cleanup;
}
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
goto inst_conflicts_cleanup;
}
goto inst_conflicts_cleanup;
}
goto inst_conflicts_cleanup;
}
goto inst_conflicts_cleanup;
}
/* Reset the iterator, and then look at the instance. */
goto inst_conflicts_cleanup;
}
goto inst_conflicts_cleanup;
}
goto inst_conflicts_cleanup;
}
ret = 0;
return (ret);
}