lowlevel.c revision 3eae19d9cf3390cf5b75e10c9c1945fd36ad856a
/*
* 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 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* This is the main implementation file for the low-level repository
* interface.
*/
#include "lowlevel_impl.h"
#include "repcache_protocol.h"
#include "scf_type.h"
#include <assert.h>
#include <alloca.h>
#include <door.h>
#include <errno.h>
#include <fcntl.h>
#include <fnmatch.h>
#include <libuutil.h>
#include <poll.h>
#include <pthread.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/sysmacros.h>
#include <unistd.h>
#define ENV_SCF_DEBUG "LIBSCF_DEBUG"
#define ENV_SCF_DOORPATH "LIBSCF_DOORPATH"
static uint32_t default_debug = 0;
static const char *default_door_path = REPOSITORY_DOOR_NAME;
#define CALL_FAILED -1
#define RESULT_TOO_BIG -2
#define NOT_BOUND -3
static pthread_mutex_t lowlevel_init_lock;
static int32_t lowlevel_inited;
static uu_list_pool_t *tran_entry_pool;
static uu_list_pool_t *datael_pool;
static uu_list_pool_t *iter_pool;
/*
* We want MUTEX_HELD, but we also want pthreads.
*/
struct _lwp_mutex;
extern int _mutex_held(struct _lwp_mutex *);
/*
* no cancellation, please
*/
struct _lwp_cond;
#ifdef lint
#define assert_nolint(x) (void)0
#else
#define assert_nolint(x) assert(x)
#endif
#define TYPE_VALUE (-100)
/*
* Hold and release subhandles. We only allow one thread access to the
* subhandles at a time, and he can use any subset, grabbing and releasing
* them in any order. The only restrictions are that you cannot hold an
* already-held subhandle, and all subhandles must be released before
* returning to the original caller.
*/
static void
{
(void) pthread_mutex_lock(&h->rh_lock);
if (h->rh_hold_flags == 0)
h->rh_holder = pthread_self();
h->rh_hold_flags |= mask;
(void) pthread_mutex_unlock(&h->rh_lock);
}
static void
{
(void) pthread_mutex_lock(&h->rh_lock);
h->rh_hold_flags &= ~mask;
if (h->rh_hold_flags == 0)
(void) pthread_cond_signal(&h->rh_cv);
(void) pthread_mutex_unlock(&h->rh_lock);
}
#define RELE_HANDLE(h, flag) \
(handle_rele_subhandles((h), (flag)))
/*
* convenience macros, for functions that only need a one or two handles at
* any given time
*/
/*ARGSUSED*/
static int
{
const char *l_prop =
const char *r_prop =
int ret;
if (ret > 0)
return (1);
if (ret < 0)
return (-1);
return (0);
}
static int
{
return (1);
return (-1);
return (0);
}
static int
{
return (1);
return (-1);
return (0);
}
static int
lowlevel_init(void)
{
const char *debug;
const char *door_path;
(void) pthread_mutex_lock(&lowlevel_init_lock);
if (lowlevel_inited == 0) {
if (!issetugid() &&
0, 0, 0) == -1) {
uu_strerror(uu_error()));
}
if (!issetugid() &&
door_path[0] != 0) {
if (default_door_path == NULL)
}
entry_property) == 0);
"SUNW,libscf_transaction_entity",
sizeof (scf_transaction_entry_t),
tran_entry_pool == NULL) {
lowlevel_inited = -1;
goto end;
}
if (!scf_setup_error()) {
lowlevel_inited = -1;
goto end;
}
lowlevel_inited = 1;
}
end:
(void) pthread_mutex_unlock(&lowlevel_init_lock);
if (lowlevel_inited > 0)
return (1);
return (0);
}
static const struct {
const char *ti_name;
} scf_type_info[] = {
"net_address_v4"},
"net_address_v6"}
};
static rep_protocol_value_type_t
{
int i;
for (i = 0; i < SCF_TYPE_INFO_COUNT; i++)
if (scf_type_info[i].ti_type == t)
return (scf_type_info[i].ti_proto_type);
return (REP_PROTOCOL_TYPE_INVALID);
}
static scf_type_t
{
int i;
for (i = 0; i < SCF_TYPE_INFO_COUNT; i++)
if (scf_type_info[i].ti_proto_type == t)
return (scf_type_info[i].ti_type);
return (SCF_TYPE_INVALID);
}
const char *
{
int i;
for (i = 0; i < SCF_TYPE_INFO_COUNT; i++)
return (scf_type_info[i].ti_name);
return ("unknown");
}
scf_string_to_type(const char *name)
{
int i;
for (i = 0; i < sizeof (scf_type_info) / sizeof (*scf_type_info); i++)
return (scf_type_info[i].ti_type);
return (SCF_TYPE_INVALID);
}
int
{
if (t == REP_PROTOCOL_TYPE_INVALID)
return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
return (SCF_SUCCESS);
}
/*
* Convert a protocol error code into an SCF_ERROR_* code.
*/
static scf_error_t
{
switch (e) {
return (SCF_ERROR_INTERNAL);
case REP_PROTOCOL_FAIL_BAD_TX:
return (SCF_ERROR_INVALID_ARGUMENT);
return (SCF_ERROR_INVALID_ARGUMENT);
return (SCF_ERROR_NO_RESOURCES);
return (SCF_ERROR_NOT_FOUND);
return (SCF_ERROR_DELETED);
return (SCF_ERROR_NOT_SET);
case REP_PROTOCOL_FAIL_EXISTS:
return (SCF_ERROR_EXISTS);
return (SCF_ERROR_EXISTS);
return (SCF_ERROR_PERMISSION_DENIED);
return (SCF_ERROR_BACKEND_ACCESS);
return (SCF_ERROR_BACKEND_READONLY);
case REP_PROTOCOL_SUCCESS:
case REP_PROTOCOL_DONE:
case REP_PROTOCOL_FAIL_NOT_LATEST: /* TX code should handle this */
default:
#ifndef NDEBUG
uu_warn("%s:%d: Bad error code %d passed to proto_error().\n",
#endif
abort();
/*NOTREACHED*/
}
}
{
switch (limit) {
return (REP_PROTOCOL_NAME_LEN - 1);
return (REP_PROTOCOL_VALUE_LEN - 1);
return (SCF_FMRI_PREFIX_MAX_LEN +
sizeof (SCF_FMRI_SCOPE_PREFIX) - 1 +
sizeof (SCF_FMRI_SCOPE_SUFFIX) - 1 +
sizeof (SCF_FMRI_SERVICE_PREFIX) - 1 +
sizeof (SCF_FMRI_INSTANCE_PREFIX) - 1 +
sizeof (SCF_FMRI_PROPERTYGRP_PREFIX) - 1 +
sizeof (SCF_FMRI_PROPERTY_PREFIX) - 1 +
default:
return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
}
}
static size_t
{
char a, b;
in += 2;
if (a >= '0' && a <= '9')
a -= '0';
else if (a >= 'a' && a <= 'f')
a = a - 'a' + 10;
else if (a >= 'A' && a <= 'F')
a = a - 'A' + 10;
else
break;
if (b >= '0' && b <= '9')
b -= '0';
else if (b >= 'a' && b <= 'f')
b = b - 'a' + 10;
else if (b >= 'A' && b <= 'F')
b = b - 'A' + 10;
else
break;
*out++ = (a << 4) | b;
max_out--;
}
}
static size_t
{
return (2 * in_sz);
uint8_t b = (c & 0x0f);
if (a <= 9)
*out++ = a + '0';
else
if (b <= 9)
*out++ = b + '0';
else
}
*out = 0;
}
static void
{
/*
* if there are any active FD users, we just move the FD over
* to rh_doorfd_old -- they'll close it when they finish.
*/
if (h->rh_fd_users > 0) {
h->rh_doorfd_old = h->rh_doorfd;
h->rh_doorfd = -1;
} else {
h->rh_doorfd = -1;
}
}
/*
* Check if a handle is currently bound. fork()ing implicitly unbinds
* the handle in the child.
*/
static int
{
if (h->rh_doorfd == -1)
return (0);
if (getpid() == h->rh_doorpid)
return (1);
/* forked since our last bind -- initiate handle close */
handle_do_close(h);
return (0);
}
static int
{
door_info_t i;
i.di_target != -1);
}
static int
{
int ret;
(void) pthread_mutex_lock(&h->rh_lock);
ret = handle_has_server_locked(h);
(void) pthread_mutex_unlock(&h->rh_lock);
return (ret);
}
/*
* This makes a door request on the client door associated with handle h.
* It will automatically retry calls which fail on EINTR. If h is not bound,
* returns NOT_BOUND. If the door call fails or the server response is too
* small, returns CALL_FAILED. If the server response is too big, truncates the
* response and returns RESULT_TOO_BIG. Otherwise, the size of the result is
* returned.
*/
static ssize_t
{
int r;
if (!handle_is_bound(h)) {
return (NOT_BOUND);
}
break;
}
if (r < 0) {
return (CALL_FAILED);
}
}
}
}
return (RESULT_TOO_BIG);
return (CALL_FAILED);
}
/*
* Should only be used when r < 0.
*/
#define DOOR_ERRORS_BLOCK(r) { \
switch (r) { \
case NOT_BOUND: \
return (scf_set_error(SCF_ERROR_NOT_BOUND)); \
\
case CALL_FAILED: \
return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN)); \
\
case RESULT_TOO_BIG: \
return (scf_set_error(SCF_ERROR_INTERNAL)); \
\
default: \
r == RESULT_TOO_BIG); \
abort(); \
} \
}
/*
* Like make_door_call(), but takes an fd instead of a handle, and expects
* a single file descriptor, returned via res_fd.
*
* If no file descriptor is returned, *res_fd == -1.
*/
static int
{
int r;
char rbuf[256];
*res_fd = -1;
if (fd == -1)
return (NOT_BOUND);
break;
}
if (r < 0)
return (CALL_FAILED);
int cfd =
}
}
}
return (RESULT_TOO_BIG);
return (CALL_FAILED);
}
/*
* Fails with
* _VERSION_MISMATCH
* _NO_MEMORY
*/
{
int failed;
/*
* This will need to be revisited when we bump SCF_VERSION
*/
if (v != SCF_VERSION) {
(void) scf_set_error(SCF_ERROR_VERSION_MISMATCH);
return (NULL);
}
if (!lowlevel_init()) {
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
return (NULL);
}
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
return (NULL);
}
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
return (NULL);
}
/*
* these subhandles count as internal references, not external ones.
*/
ret->rh_extrefs = 0;
if (failed) {
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
return (NULL);
}
return (ret);
}
int
{
return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
if (handle_is_bound(handle)) {
return (scf_set_error(SCF_ERROR_IN_USE));
}
if (v == SCF_DECORATE_CLEAR) {
} else {
if (scf_value_get_count(v, &val) < 0)
return (-1); /* error already set */
}
return (0);
}
if (v == SCF_DECORATE_CLEAR) {
handle->rh_doorpath[0] = 0;
} else {
sizeof (name))) < 0) {
return (-1); /* error already set */
}
return (scf_set_error(
}
sizeof (handle->rh_doorpath));
}
return (0);
}
return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
}
/*
* fails with INVALID_ARGUMENT and HANDLE_MISMATCH.
*/
int
scf_value_t *v, void *data)
{
return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
if (v->value_handle != handle)
return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
i.sdi_name = (const char *)"debug";
i.sdi_type = SCF_TYPE_COUNT;
if (debug != 0) {
scf_value_set_count(v, debug);
i.sdi_value = v;
} else {
}
if ((*f)(&i, data) == 0)
return (0);
i.sdi_name = (const char *)"door_path";
i.sdi_type = SCF_TYPE_ASTRING;
if (name[0] != 0) {
(void) scf_value_set_astring(v, name);
i.sdi_value = v;
} else {
}
if ((*f)(&i, data) == 0)
return (0);
return (1);
}
/*
* Fails if handle is not bound.
*/
static int
{
if (!handle_is_bound(handle))
return (-1);
return (SCF_SUCCESS);
}
/*
* Fails with
* _HANDLE_DESTROYED - dp's handle has been destroyed
* _INTERNAL - server response too big
* entity already set up with different type
* _NO_RESOURCES - server out of memory
*/
static int
{
struct rep_protocol_entity_setup request;
ssize_t r;
if (h->rh_flags & HANDLE_DEAD)
return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED));
if (!handle_is_bound(h))
return (SCF_SUCCESS); /* nothing to do */
if (r == NOT_BOUND || r == CALL_FAILED)
return (SCF_SUCCESS);
if (r == RESULT_TOO_BIG)
return (scf_set_error(SCF_ERROR_INTERNAL));
return (SCF_SUCCESS);
}
/*
* Fails with
* _HANDLE_DESTROYED - iter's handle has been destroyed
* _INTERNAL - server response too big
* iter already existed
* _NO_RESOURCES
*/
static int
{
struct rep_protocol_iter_request request;
struct rep_protocol_response response;
int r;
if (h->rh_flags & HANDLE_DEAD)
return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED));
if (!handle_is_bound(h))
return (SCF_SUCCESS); /* nothing to do */
if (r == NOT_BOUND || r == CALL_FAILED)
return (SCF_SUCCESS);
if (r == RESULT_TOO_BIG)
return (scf_set_error(SCF_ERROR_INTERNAL));
return (SCF_SUCCESS);
}
/*
* Fails with
* _IN_USE - handle already bound
* _NO_SERVER - server door could not be open()ed
* door call failed
* door_info() failed
* _VERSION_MISMATCH - server returned bad file descriptor
* server claimed bad request
* server reported version mismatch
* server refused with unknown reason
* _INVALID_ARGUMENT
* _NO_RESOURCES - server is out of memory
* _PERMISSION_DENIED
* _INTERNAL - could not set up entities or iters
* server response too big
*
* perhaps this should try multiple times.
*/
int
{
int fd;
int res;
const char *door_name = default_door_path;
if (handle_is_bound(handle)) {
return (scf_set_error(SCF_ERROR_IN_USE));
}
/* wait until any active fd users have cleared out */
while (handle->rh_fd_users > 0)
/* check again, since we had to drop the lock */
if (handle_is_bound(handle)) {
return (scf_set_error(SCF_ERROR_IN_USE));
}
if (handle->rh_doorpath[0] != 0)
if (fd == -1) {
return (scf_set_error(SCF_ERROR_NO_SERVER));
}
if (res < 0) {
if (res == CALL_FAILED)
return (scf_set_error(SCF_ERROR_NO_SERVER));
return (scf_set_error(SCF_ERROR_INTERNAL));
}
switch (response.rdr_status) {
case REPOSITORY_DOOR_SUCCESS:
return (scf_set_error(SCF_ERROR_VERSION_MISMATCH));
return (scf_set_error(SCF_ERROR_VERSION_MISMATCH));
return (scf_set_error(SCF_ERROR_VERSION_MISMATCH));
return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
return (scf_set_error(SCF_ERROR_NO_RESOURCES));
return (scf_set_error(SCF_ERROR_PERMISSION_DENIED));
default:
return (scf_set_error(SCF_ERROR_VERSION_MISMATCH));
}
}
return (scf_set_error(SCF_ERROR_NO_SERVER));
}
/*
* Now, re-attach everything
*/
(void) handle_unbind_unlocked(handle);
return (-1);
}
}
(void) handle_unbind_unlocked(handle);
return (-1);
}
}
return (SCF_SUCCESS);
}
int
{
int ret;
}
static scf_handle_t *
{
(void) pthread_mutex_lock(&h->rh_lock);
if (h->rh_flags & HANDLE_DEAD) {
(void) pthread_mutex_unlock(&h->rh_lock);
(void) scf_set_error(SCF_ERROR_HANDLE_DESTROYED);
return (NULL);
}
(void) pthread_mutex_unlock(&h->rh_lock);
return (h);
}
/*
* Called when an object is removed from the handle. On the last remove,
* cleans up and frees the handle.
*/
static void
{
scf_value_t *v;
/*
* Don't do anything if the handle has not yet been destroyed, there
* are still external references, or we're already doing unrefed
* handling.
*/
handle->rh_extrefs > 0 ||
handle->rh_fd_users > 0 ||
return;
}
/*
* Now that we know that there are no external references, and the
* HANDLE_DEAD flag keeps new ones from appearing, we can clean up
* our subhandles and destroy the handle completely.
*/
handle->rh_intrefs = 0;
if (v != NULL)
/* there should be no outstanding children at this point */
}
void
{
return;
/*
* This is an error (you are not allowed to reference the
* handle after it is destroyed), but we can't report it.
*/
return;
}
(void) handle_unbind_unlocked(handle);
}
{
char *cp;
if (!handle_has_server(h))
return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN));
return (scf_set_error(SCF_ERROR_NOT_SET));
}
static uint32_t
{
return (0); /* no ids available */
/*
* The following loop assumes that there are not a huge number of
* outstanding entities when we've wrapped. If that ends up not
* being the case, the O(N^2) nature of this search will hurt a lot,
* and the data structure should be switched to an AVL tree.
*/
for (;;) {
if (nextid == 0) {
nextid++;
h->rh_flags |= HANDLE_WRAPPED_ENTITY;
}
if (!(h->rh_flags & HANDLE_WRAPPED_ENTITY))
break;
break; /* not in use */
if (nextid == h->rh_nextentity)
return (0); /* wrapped around; no ids available */
nextid++;
}
h->rh_nextentity = nextid;
return (nextid);
}
static uint32_t
{
return (0); /* no ids available */
/* see the comment in handle_alloc_entityid */
for (;;) {
if (nextid == 0) {
nextid++;
h->rh_flags |= HANDLE_WRAPPED_ITER;
}
if (!(h->rh_flags & HANDLE_WRAPPED_ITER))
break; /* not yet wrapped */
break; /* not in use */
if (nextid == h->rh_nextiter)
return (0); /* wrapped around; no ids available */
nextid++;
}
h->rh_nextiter = nextid;
return (nextid);
}
static uint32_t
{
if (nextid == 0)
return (nextid);
}
/*
* Fails with
* _INVALID_ARGUMENT - h is NULL
* _HANDLE_DESTROYED
* _INTERNAL - server response too big
* entity already set up with different type
* _NO_RESOURCES
*/
static int
{
int ret;
if (h == NULL)
return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
(void) pthread_mutex_lock(&h->rh_lock);
if (h->rh_flags & HANDLE_DEAD) {
/*
* we're in undefined territory (the user cannot use a handle
* directly after it has been destroyed), but we don't want
* to allow any new references to happen, so we fail here.
*/
(void) pthread_mutex_unlock(&h->rh_lock);
return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED));
}
(void) pthread_mutex_unlock(&h->rh_lock);
return (scf_set_error(SCF_ERROR_NO_MEMORY));
}
if (ret == 0) {
h->rh_extrefs++;
} else {
}
(void) pthread_mutex_unlock(&h->rh_lock);
return (ret);
}
static void
{
struct rep_protocol_entity_teardown request;
(void) pthread_mutex_lock(&h->rh_lock);
--h->rh_extrefs;
if (handle_is_bound(h)) {
}
handle_unrefed(h); /* drops h->rh_lock */
}
static scf_handle_t *
{
}
/*
* We delay ENTITY_RESETs until right before the entity is used. By doing
* them lazily, we remove quite a few unnecessary calls.
*/
static void
{
struct rep_protocol_entity_reset request;
}
static void
{
}
static void
{
(void) pthread_mutex_lock(&h->rh_lock);
(void) pthread_mutex_unlock(&h->rh_lock);
}
static void
{
}
/*
* Fails with _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response too
* big, bad entity id, request not applicable to entity, name too long for
* buffer), _NOT_SET, _DELETED, or _CONSTRAINT_VIOLATED (snaplevel is not of an
* instance).
*/
static ssize_t
{
struct rep_protocol_entity_name request;
struct rep_protocol_name_response response;
ssize_t r;
(void) pthread_mutex_lock(&h->rh_lock);
(void) pthread_mutex_unlock(&h->rh_lock);
if (r < 0)
return (scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED));
}
}
/*
* Fails with _HANDLE_MISMATCH, _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL
* (server response too big, bad element id), _EXISTS (elements have same id),
* _NOT_SET, _DELETED, _CONSTRAINT_VIOLATED, _NOT_FOUND (scope has no parent),
* or _SUCCESS.
*/
static int
{
struct rep_protocol_entity_parent request;
struct rep_protocol_response response;
ssize_t r;
return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
(void) pthread_mutex_lock(&h->rh_lock);
(void) pthread_mutex_unlock(&h->rh_lock);
if (r < 0)
return (scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED));
}
return (SCF_SUCCESS);
}
/*
* Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT (out does not have type type,
* name is invalid), _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response
* too big, bad id, iter already exists, element cannot have children of type,
* type is invalid, iter was reset, sequence was bad, iter walks values, iter
* does not walk type entities), _NOT_SET, _DELETED, _NO_RESOURCES,
* _BACKEND_ACCESS, _NOT_FOUND.
*/
static int
{
struct rep_protocol_iter_start request;
struct rep_protocol_iter_read read_request;
struct rep_protocol_response response;
ssize_t r;
return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
}
/*
* We hold the handle lock across both door calls, so that they
* appear atomic.
*/
if (r < 0)
iter->iter_sequence++;
if (r < 0)
return (scf_set_error(SCF_ERROR_NOT_FOUND));
}
return (scf_set_error(SCF_ERROR_INTERNAL));
}
return (0);
}
/*
* Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT (out does not have type type,
* name is invalid), _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response
* too big, bad id, element cannot have children of type, type is invalid),
* _NOT_SET, _DELETED, _NO_RESOURCES, _BACKEND_ACCESS.
*/
static int
{
struct rep_protocol_entity_get_child request;
struct rep_protocol_response response;
ssize_t r;
return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
}
if (r < 0)
return (0);
}
/*
* Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT (out does not have type type,
* name is invalid), _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response
* too big, bad id, iter already exists, element cannot have children of type,
* type is invalid, iter was reset, sequence was bad, iter walks values, iter
* does not walk type entities), _NOT_SET, _DELETED, _NO_RESOURCES,
* _BACKEND_ACCESS, _NOT_FOUND.
*/
static int
{
int ret;
if (composed)
iter = HANDLE_HOLD_ITER(h);
switch (type) {
break;
break;
break;
break;
held = RH_HOLD_PG;
break;
break;
default:
assert(0);
abort();
}
}
(void) pthread_mutex_lock(&h->rh_lock);
if (composed)
iter);
else
(void) pthread_mutex_unlock(&h->rh_lock);
if (composed)
HANDLE_RELE_ITER(h);
if (held)
return (ret);
}
/*
* Fails with
* _HANDLE_MISMATCH
* _INVALID_ARGUMENT - name is too long
* invalid changeid
* name is invalid
* cannot create children for dp's type of node
* _NOT_BOUND - handle is not bound
* _CONNECTION_BROKEN - server is not reachable
* _INTERNAL - server response too big
* dp or cp has unknown id
* type is _PROPERTYGRP
* type is invalid
* dp cannot have children of type type
* database is corrupt
* _EXISTS - dp & cp have the same id
* _EXISTS - child already exists
* _DELETED - dp has been deleted
* _NOT_SET - dp is reset
* _NO_RESOURCES
* _PERMISSION_DENIED
* _BACKEND_ACCESS
* _BACKEND_READONLY
*/
static int
{
struct rep_protocol_response response;
ssize_t r;
switch (type) {
break;
break;
break;
default:
assert(0);
abort();
}
return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
}
goto err;
}
(void) pthread_mutex_lock(&h->rh_lock);
(void) pthread_mutex_unlock(&h->rh_lock);
if (held)
if (r < 0)
return (SCF_SUCCESS);
err:
if (held)
return (r);
}
static int
{
struct rep_protocol_entity_create_pg request;
struct rep_protocol_response response;
ssize_t r;
int holding_els = 0;
holding_els = 1;
return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
}
goto err;
}
goto err;
}
(void) pthread_mutex_lock(&h->rh_lock);
(void) pthread_mutex_unlock(&h->rh_lock);
if (holding_els)
HANDLE_RELE_PG(h);
if (r < 0)
return (SCF_SUCCESS);
err:
if (holding_els)
HANDLE_RELE_PG(h);
return (r);
}
static int
{
struct rep_protocol_entity_delete request;
struct rep_protocol_response response;
ssize_t r;
(void) pthread_mutex_lock(&h->rh_lock);
(void) pthread_mutex_unlock(&h->rh_lock);
if (r < 0)
return (SCF_SUCCESS);
}
/*
* Fails with
* _INVALID_ARGUMENT - h is NULL
* _NO_MEMORY
* _HANDLE_DESTROYED - h has been destroyed
* _INTERNAL - server response too big
* iter already exists
* _NO_RESOURCES
*/
{
if (h == NULL) {
(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
return (NULL);
}
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
return (NULL);
}
iter->iter_handle = h;
(void) pthread_mutex_lock(&h->rh_lock);
(void) pthread_mutex_unlock(&h->rh_lock);
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
return (NULL);
}
(void) pthread_mutex_unlock(&h->rh_lock);
return (NULL);
}
h->rh_extrefs++;
(void) pthread_mutex_unlock(&h->rh_lock);
return (iter);
}
{
}
static void
{
struct rep_protocol_iter_request request;
struct rep_protocol_response response;
}
void
{
}
void
{
struct rep_protocol_iter_request request;
struct rep_protocol_response response;
return;
--handle->rh_extrefs;
}
static int
{
struct rep_protocol_entity_get request;
struct rep_protocol_name_response response;
ssize_t r;
return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
if (r < 0)
return (SCF_SUCCESS);
}
int
{
if (h != handle)
return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
(void) pthread_mutex_lock(&h->rh_lock);
if (!handle_is_bound(h)) {
(void) pthread_mutex_unlock(&h->rh_lock);
return (scf_set_error(SCF_ERROR_NOT_BOUND));
}
if (!handle_has_server_locked(h)) {
(void) pthread_mutex_unlock(&h->rh_lock);
return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN));
}
(void) pthread_mutex_unlock(&h->rh_lock);
return (0);
}
int
{
int ret;
return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
(void) pthread_mutex_lock(&h->rh_lock);
(void) pthread_mutex_unlock(&h->rh_lock);
return (scf_set_error(SCF_ERROR_NOT_SET));
}
(void) pthread_mutex_unlock(&h->rh_lock);
return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
}
SCF_SUCCESS) {
iter->iter_sequence++;
ret = 1;
}
} else {
ret = 0;
}
(void) pthread_mutex_unlock(&h->rh_lock);
return (ret);
}
int
{
int ret;
return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
(void) pthread_mutex_lock(&h->rh_lock);
} else {
else
}
(void) pthread_mutex_unlock(&h->rh_lock);
return (ret);
}
static int
{
struct rep_protocol_iter_start request;
struct rep_protocol_response response;
ssize_t r;
if (h != iter->iter_handle)
return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
(void) pthread_mutex_lock(&h->rh_lock);
(composed ? RP_ITER_START_COMPOSED : 0);
request.rpr_pattern[0] = 0;
if (r < 0) {
(void) pthread_mutex_unlock(&h->rh_lock);
}
(void) pthread_mutex_unlock(&h->rh_lock);
}
iter->iter_sequence++;
(void) pthread_mutex_unlock(&h->rh_lock);
return (SCF_SUCCESS);
}
static int
{
struct rep_protocol_iter_start request;
struct rep_protocol_response response;
ssize_t r;
if (h != iter->iter_handle)
return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
}
(void) pthread_mutex_lock(&h->rh_lock);
(composed ? RP_ITER_START_COMPOSED : 0);
if (r < 0) {
(void) pthread_mutex_unlock(&h->rh_lock);
}
(void) pthread_mutex_unlock(&h->rh_lock);
}
iter->iter_sequence++;
(void) pthread_mutex_unlock(&h->rh_lock);
return (SCF_SUCCESS);
}
static int
{
struct rep_protocol_iter_read request;
struct rep_protocol_response response;
ssize_t r;
return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
(void) pthread_mutex_lock(&h->rh_lock);
(void) pthread_mutex_unlock(&h->rh_lock);
return (scf_set_error(SCF_ERROR_NOT_SET));
}
(void) pthread_mutex_unlock(&h->rh_lock);
return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
}
if (r < 0) {
(void) pthread_mutex_unlock(&h->rh_lock);
}
(void) pthread_mutex_unlock(&h->rh_lock);
return (0);
}
(void) pthread_mutex_unlock(&h->rh_lock);
}
iter->iter_sequence++;
(void) pthread_mutex_unlock(&h->rh_lock);
return (1);
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
const char *type)
{
}
int
{
}
int
{
}
int
{
}
int
const char *type)
{
}
int
const scf_snapshot_t *snap)
{
return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
}
int
{
return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
return (datael_setup_iter_pgtyped(iter,
}
int
{
}
int
const char *type)
{
}
int
{
}
int
{
}
int
{
}
/*
* Fails with
* _INVALID_ARGUMENT - handle is NULL
* _INTERNAL - server response too big
* entity already set up with different type
* _NO_RESOURCES
* _NO_MEMORY
*/
{
REP_PROTOCOL_ENTITY_SCOPE) == -1) {
return (NULL);
}
} else {
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
}
return (ret);
}
{
}
void
{
return;
}
{
}
/*ARGSUSED*/
int
{
char name[1];
/* fake up the side-effects */
return (-1);
return (scf_set_error(SCF_ERROR_NOT_FOUND));
}
/*
* Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
* (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
*/
{
REP_PROTOCOL_ENTITY_SERVICE) == -1) {
return (NULL);
}
} else {
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
}
return (ret);
}
/*
* Fails with
* _HANDLE_MISMATCH
* _INVALID_ARGUMENT
* _NOT_BOUND
* _CONNECTION_BROKEN
* _INTERNAL
* _EXISTS
* _DELETED
* _NOT_SET
* _NO_RESOURCES
* _PERMISSION_DENIED
* _BACKEND_ACCESS
* _BACKEND_READONLY
*/
int
{
}
/*
* Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
* _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
* _BACKEND_ACCESS, _NOT_FOUND.
*/
int
{
}
{
}
int
{
}
int
{
}
int
{
}
int
{
}
/*
* Fails with
* _HANDLE_MISMATCH
* _INVALID_ARGUMENT
* _NOT_BOUND
* _CONNECTION_BROKEN
* _INTERNAL
* _EXISTS
* _DELETED
* _NOT_SET
* _NO_RESOURCES
* _PERMISSION_DENIED
* _BACKEND_ACCESS
* _BACKEND_READONLY
*/
int
{
}
/*
* Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
* _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
* _BACKEND_ACCESS, _NOT_FOUND.
*/
int
{
}
int
{
}
/*
* Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
* _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
* _BACKEND_ACCESS, _NOT_FOUND.
*/
int
{
}
int
{
}
/*
* Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
* _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
* _BACKEND_ACCESS, _NOT_FOUND.
*/
int
{
}
/*
* Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
* _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
* _BACKEND_ACCESS, _NOT_FOUND.
*/
int
{
}
/*
* Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
* _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
* _BACKEND_ACCESS, _NOT_FOUND.
*/
int
{
return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
}
/*
* Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
* _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
* _BACKEND_ACCESS, _NOT_FOUND.
*/
int
{
}
void
{
return;
}
{
}
/*
* Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
* (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
*/
{
REP_PROTOCOL_ENTITY_INSTANCE) == -1) {
return (NULL);
}
} else {
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
}
return (ret);
}
{
}
void
{
return;
}
{
}
/*
* Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
* (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
*/
{
REP_PROTOCOL_ENTITY_SNAPSHOT) == -1) {
return (NULL);
}
} else {
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
}
return (ret);
}
{
}
void
{
return;
}
{
}
/*
* Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
* (bad server response or id in use), _NO_RESOURCES, _NO_MEMORY.
*/
{
REP_PROTOCOL_ENTITY_SNAPLEVEL) == -1) {
return (NULL);
}
} else {
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
}
return (ret);
}
{
}
void
{
return;
}
{
}
{
}
{
}
/*
* Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
* _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
* _BACKEND_ACCESS, _NOT_FOUND.
*/
int
{
}
static int
{
struct rep_protocol_entity_pair request;
struct rep_protocol_response response;
int r;
int dups = 0;
return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
dups = 1;
dst = HANDLE_HOLD_SNAPLVL(h);
}
(void) pthread_mutex_lock(&h->rh_lock);
/*
* if we succeeded, we need to swap dst and dst_arg's identity. We
* take advantage of the fact that the only in-library knowledge is
* their entity ids.
*/
if (dups && r >= 0 &&
}
(void) pthread_mutex_unlock(&h->rh_lock);
if (dups)
if (r < 0)
}
}
{
}
{
}
/*
* Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
* (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
*/
{
REP_PROTOCOL_ENTITY_PROPERTYGRP) == -1) {
return (NULL);
}
} else {
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
}
return (ret);
}
{
}
void
{
return;
}
{
}
{
}
int
{
char buf[REP_PROTOCOL_NAME_LEN];
if (res == -1)
return (-1);
return (scf_set_error(SCF_ERROR_INTERNAL));
return (0);
}
static int
{
struct rep_protocol_entity_update request;
struct rep_protocol_response response;
int r;
(void) pthread_mutex_lock(&h->rh_lock);
(void) pthread_mutex_unlock(&h->rh_lock);
if (r < 0)
/*
* This should never happen but if it does something has
* gone terribly wrong and we should abort.
*/
abort();
}
}
int
{
}
int
{
}
int
{
struct rep_protocol_response response;
int r;
(void) pthread_mutex_lock(&h->rh_lock);
if (!handle_is_bound(h)) {
(void) pthread_mutex_unlock(&h->rh_lock);
return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN));
}
(void) pthread_mutex_unlock(&h->rh_lock);
if (r < 0)
return (SCF_SUCCESS);
}
static int
{
struct rep_protocol_notify_request request;
struct rep_protocol_response response;
int r;
(void) pthread_mutex_lock(&h->rh_lock);
(void) pthread_mutex_unlock(&h->rh_lock);
if (r < 0)
return (SCF_SUCCESS);
}
int
{
}
int
{
}
int
{
struct rep_protocol_wait_request request;
struct rep_protocol_fmri_response response;
int dummy;
int fd;
int r;
(void) pthread_mutex_lock(&h->rh_lock);
if (!handle_is_bound(h)) {
(void) pthread_mutex_unlock(&h->rh_lock);
return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN));
}
++h->rh_fd_users;
assert(h->rh_fd_users > 0);
(void) pthread_mutex_unlock(&h->rh_lock);
(void) pthread_mutex_lock(&h->rh_lock);
assert(h->rh_fd_users > 0);
if (--h->rh_fd_users == 0) {
(void) pthread_cond_broadcast(&h->rh_cv);
/*
* check for a delayed close, now that there are no other
* users.
*/
if (h->rh_doorfd_old != -1) {
(void) close(h->rh_doorfd_old);
h->rh_doorfd_old = -1;
}
}
handle_unrefed(h); /* drops h->rh_lock */
if (r < 0)
return (scf_set_error(SCF_ERROR_NOT_SET));
/* the following will be non-zero for delete notifications */
}
static int
{
struct rep_protocol_snapshot_take request;
struct rep_protocol_response response;
int r;
return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
(void) pthread_mutex_lock(&h->rh_lock);
(void) pthread_mutex_unlock(&h->rh_lock);
if (r < 0)
return (SCF_SUCCESS);
}
int
{
struct rep_protocol_response response;
int r;
return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
(void) pthread_mutex_lock(&h->rh_lock);
(void) pthread_mutex_unlock(&h->rh_lock);
if (r < 0)
}
return (SCF_SUCCESS);
}
int
{
}
int
{
}
int
{
struct rep_protocol_snapshot_attach request;
struct rep_protocol_response response;
int r;
return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
(void) pthread_mutex_lock(&h->rh_lock);
(void) pthread_mutex_unlock(&h->rh_lock);
if (r < 0)
return (SCF_SUCCESS);
}
/*
* Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
* (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
*/
{
REP_PROTOCOL_ENTITY_PROPERTY) == -1) {
return (NULL);
}
} else {
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
}
return (ret);
}
{
}
void
{
return;
}
static int
{
struct rep_protocol_property_request request;
int r;
if (r < 0)
r < sizeof (response)) {
}
return (SCF_SUCCESS);
}
int
{
int ret;
(void) pthread_mutex_lock(&h->rh_lock);
(void) pthread_mutex_unlock(&h->rh_lock);
if (ret == SCF_SUCCESS)
return (ret);
}
int
{
int ret;
if (base == REP_PROTOCOL_TYPE_INVALID)
return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
(void) pthread_mutex_lock(&h->rh_lock);
(void) pthread_mutex_unlock(&h->rh_lock);
if (ret == SCF_SUCCESS) {
return (scf_set_error(SCF_ERROR_TYPE_MISMATCH));
}
return (ret);
}
{
}
/*
* transaction functions
*/
/*
* Fails with _NO_MEMORY, _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED,
* _INTERNAL (bad server response or id in use), or _NO_RESOURCES.
*/
{
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
return (NULL);
}
REP_PROTOCOL_ENTITY_PROPERTYGRP) == -1) {
return (NULL); /* error already set */
}
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
return (NULL);
}
return (ret);
}
{
}
int
{
struct rep_protocol_response response;
int r;
return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
(void) pthread_mutex_lock(&h->rh_lock);
(void) pthread_mutex_unlock(&h->rh_lock);
return (scf_set_error(SCF_ERROR_IN_USE));
}
if (r < 0) {
(void) pthread_mutex_unlock(&h->rh_lock);
}
/* r < sizeof (response) cannot happen because sizeof (response) == 4 */
r < sizeof (response)) {
(void) pthread_mutex_unlock(&h->rh_lock);
}
tran->tran_invalid = 0;
(void) pthread_mutex_unlock(&h->rh_lock);
return (SCF_SUCCESS);
}
static void
int and_reset_value)
{
scf_value_t *v, *next;
}
next = v->value_next;
v->value_next = NULL;
if (and_destroy || and_reset_value)
}
}
static void
{
entry_invalidate(entry, 0, 0);
assert(h->rh_entries > 0);
--h->rh_entries;
--h->rh_extrefs;
}
/*
* Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
* _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
* _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
*/
static int
{
int ret;
if (h != entry->entry_handle)
return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
if (action == REP_PROTOCOL_TX_ENTRY_DELETE)
else if (type == REP_PROTOCOL_TYPE_INVALID)
return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
prop_p = HANDLE_HOLD_PROPERTY(h);
(void) pthread_mutex_lock(&h->rh_lock);
goto error;
}
if (tran->tran_invalid) {
goto error;
}
entry_invalidate(entry, 0, 0);
goto error;
}
goto error;
}
switch (action) {
if (ret == -1) {
goto error;
}
break;
if (ret != -1) {
goto error;
}
break;
if (ret == -1) {
goto error;
}
if (action == REP_PROTOCOL_TX_ENTRY_CLEAR) {
goto error;
}
goto error;
}
}
break;
default:
assert(0);
abort();
}
sizeof (entry->entry_namebuf));
(void) pthread_mutex_unlock(&h->rh_lock);
return (SCF_SUCCESS);
(void) pthread_mutex_unlock(&h->rh_lock);
return (scf_set_error(error));
}
/*
* Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
* _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
* _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
*/
int
{
}
/*
* Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
* _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
* _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
*/
int
{
}
/*
* Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
* _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
* _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
*/
int
{
}
/*
* Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
* _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
* _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
*/
int
{
}
#define BAD_SIZE (-1UL)
static size_t
{
if (t == REP_PROTOCOL_TYPE_OPAQUE) {
val->value_size);
} else {
else
if (len >= REP_PROTOCOL_VALUE_LEN)
return (BAD_SIZE);
}
}
static size_t
struct rep_protocol_transaction_cmd *out)
{
} else {
}
if (len >= REP_PROTOCOL_NAME_LEN)
return (BAD_SIZE);
cur->entry_type);
/* LINTED alignment */
} else
return (BAD_SIZE);
}
return (REP_PROTOCOL_TRANSACTION_CMD_SIZE(sz));
}
int
{
struct rep_protocol_transaction_commit *request;
struct rep_protocol_response response;
int r;
(void) pthread_mutex_lock(&h->rh_lock);
tran->tran_invalid) {
(void) pthread_mutex_unlock(&h->rh_lock);
return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
}
total = 0;
(void) pthread_mutex_unlock(&h->rh_lock);
return (scf_set_error(SCF_ERROR_INTERNAL));
}
}
new_total = 0;
(void) pthread_mutex_unlock(&h->rh_lock);
return (scf_set_error(SCF_ERROR_INTERNAL));
}
}
if (r < 0) {
(void) pthread_mutex_unlock(&h->rh_lock);
}
(void) pthread_mutex_unlock(&h->rh_lock);
}
(void) pthread_mutex_unlock(&h->rh_lock);
}
static void
{
}
static void
int and_reset_value)
{
void *cookie;
if (and_destroy)
}
}
void
{
scf_transaction_reset_impl(tran, 0, 0);
}
void
{
}
void
{
return;
}
void
{
}
{
if (h == NULL) {
(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
return (NULL);
}
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
return (NULL);
}
ret->entry_handle = h;
(void) pthread_mutex_lock(&h->rh_lock);
if (h->rh_flags & HANDLE_DEAD) {
(void) pthread_mutex_unlock(&h->rh_lock);
(void) scf_set_error(SCF_ERROR_HANDLE_DESTROYED);
return (NULL);
}
h->rh_entries++;
h->rh_extrefs++;
(void) pthread_mutex_unlock(&h->rh_lock);
return (ret);
}
{
}
void
{
(void) pthread_mutex_lock(&h->rh_lock);
entry_invalidate(entry, 0, 0);
(void) pthread_mutex_unlock(&h->rh_lock);
}
void
{
(void) pthread_mutex_lock(&h->rh_lock);
handle_unrefed(h); /* drops h->rh_lock */
}
void
{
scf_handle_t *h;
return;
h = entry->entry_handle;
(void) pthread_mutex_lock(&h->rh_lock);
handle_unrefed(h); /* drops h->rh_lock */
}
/*
* Fails with
* _HANDLE_MISMATCH
* _NOT_SET - has not been added to a transaction
* _INTERNAL - entry is corrupt
* _INVALID_ARGUMENT - entry's transaction is not started or corrupt
* entry is set to delete a property
* v is reset or corrupt
* _TYPE_MISMATCH - entry & v's types aren't compatible
* _IN_USE - v has been added to another entry
*/
int
{
if (h != v->value_handle)
return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
(void) pthread_mutex_lock(&h->rh_lock);
(void) pthread_mutex_unlock(&h->rh_lock);
return (scf_set_error(SCF_ERROR_NOT_SET));
}
(void) pthread_mutex_unlock(&h->rh_lock);
return (scf_set_error(SCF_ERROR_INTERNAL));
}
(void) pthread_mutex_unlock(&h->rh_lock);
return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
}
(void) pthread_mutex_unlock(&h->rh_lock);
return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
}
if (v->value_type == REP_PROTOCOL_TYPE_INVALID) {
(void) pthread_mutex_unlock(&h->rh_lock);
return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
}
(void) pthread_mutex_unlock(&h->rh_lock);
return (scf_set_error(SCF_ERROR_TYPE_MISMATCH));
}
(void) pthread_mutex_unlock(&h->rh_lock);
return (scf_set_error(SCF_ERROR_IN_USE));
}
entry->entry_head = v;
(void) pthread_mutex_unlock(&h->rh_lock);
return (SCF_SUCCESS);
}
/*
* value functions
*/
{
if (h == NULL) {
(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
return (NULL);
}
ret->value_handle = h;
(void) pthread_mutex_lock(&h->rh_lock);
if (h->rh_flags & HANDLE_DEAD) {
(void) pthread_mutex_unlock(&h->rh_lock);
(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
return (NULL);
}
h->rh_values++;
h->rh_extrefs++;
(void) pthread_mutex_unlock(&h->rh_lock);
} else {
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
}
return (ret);
}
static void
{
scf_value_t **curp;
break;
}
}
}
if (and_destroy) {
--h->rh_values;
--h->rh_extrefs;
}
}
void
{
(void) pthread_mutex_lock(&h->rh_lock);
(void) pthread_mutex_unlock(&h->rh_lock);
}
{
}
void
{
scf_handle_t *h;
return;
h = val->value_handle;
(void) pthread_mutex_lock(&h->rh_lock);
handle_unrefed(h); /* drops h->rh_lock */
}
{
(void) pthread_mutex_lock(&h->rh_lock);
t = val->value_type;
(void) pthread_mutex_unlock(&h->rh_lock);
for (;;) {
cur = scf_proto_underlying_type(t);
if (cur == t)
break;
t = cur;
}
return (scf_protocol_type_to_type(t));
}
{
(void) pthread_mutex_lock(&h->rh_lock);
t = val->value_type;
(void) pthread_mutex_unlock(&h->rh_lock);
return (scf_protocol_type_to_type(t));
}
int
{
(void) pthread_mutex_lock(&h->rh_lock);
t = val->value_type;
(void) pthread_mutex_unlock(&h->rh_lock);
if (t == REP_PROTOCOL_TYPE_INVALID)
return (scf_set_error(SCF_ERROR_NOT_SET));
if (base == REP_PROTOCOL_TYPE_INVALID)
return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
if (!scf_is_compatible_type(base, t))
return (scf_set_error(SCF_ERROR_TYPE_MISMATCH));
return (SCF_SUCCESS);
}
/*
* Fails with
* _NOT_SET - val is reset
* _TYPE_MISMATCH - val's type is not compatible with t
*/
static int
{
(void) scf_set_error(SCF_ERROR_NOT_SET);
return (0);
}
(void) scf_set_error(SCF_ERROR_TYPE_MISMATCH);
return (0);
}
return (1);
}
/*
* Fails with
* _NOT_SET - val is reset
* _TYPE_MISMATCH - val is not _TYPE_BOOLEAN
*/
int
{
char c;
uint8_t o;
(void) pthread_mutex_lock(&h->rh_lock);
(void) pthread_mutex_unlock(&h->rh_lock);
return (-1);
}
c = val->value_value[0];
o = (c != '0');
(void) pthread_mutex_unlock(&h->rh_lock);
*out = o;
return (SCF_SUCCESS);
}
int
{
uint64_t o;
(void) pthread_mutex_lock(&h->rh_lock);
(void) pthread_mutex_unlock(&h->rh_lock);
return (-1);
}
(void) pthread_mutex_unlock(&h->rh_lock);
*out = o;
return (SCF_SUCCESS);
}
int
{
int64_t o;
(void) pthread_mutex_lock(&h->rh_lock);
(void) pthread_mutex_unlock(&h->rh_lock);
return (-1);
}
(void) pthread_mutex_unlock(&h->rh_lock);
*out = o;
return (SCF_SUCCESS);
}
int
{
char *p;
(void) pthread_mutex_lock(&h->rh_lock);
(void) pthread_mutex_unlock(&h->rh_lock);
return (-1);
}
if (*p == '.')
else
ons = 0;
(void) pthread_mutex_unlock(&h->rh_lock);
return (SCF_SUCCESS);
}
/*
* Fails with
* _NOT_SET - val is reset
* _TYPE_MISMATCH - val's type is not compatible with _TYPE_STRING.
*/
{
(void) pthread_mutex_lock(&h->rh_lock);
(void) pthread_mutex_unlock(&h->rh_lock);
return ((ssize_t)-1);
}
(void) pthread_mutex_unlock(&h->rh_lock);
return (ret);
}
{
(void) pthread_mutex_lock(&h->rh_lock);
(void) pthread_mutex_unlock(&h->rh_lock);
return ((ssize_t)-1);
}
(void) pthread_mutex_unlock(&h->rh_lock);
return (ret);
}
{
scf_handle_t *h = v->value_handle;
(void) pthread_mutex_lock(&h->rh_lock);
if (!scf_value_check_type(v, REP_PROTOCOL_TYPE_OPAQUE)) {
(void) pthread_mutex_unlock(&h->rh_lock);
return ((ssize_t)-1);
}
if (len > v->value_size)
len = v->value_size;
(void) pthread_mutex_unlock(&h->rh_lock);
return (ret);
}
void
{
scf_handle_t *h = v->value_handle;
(void) pthread_mutex_lock(&h->rh_lock);
scf_value_reset_locked(v, 0);
(void) pthread_mutex_unlock(&h->rh_lock);
}
void
{
scf_handle_t *h = v->value_handle;
(void) pthread_mutex_lock(&h->rh_lock);
scf_value_reset_locked(v, 0);
(void) pthread_mutex_unlock(&h->rh_lock);
}
void
{
scf_handle_t *h = v->value_handle;
(void) pthread_mutex_lock(&h->rh_lock);
scf_value_reset_locked(v, 0);
(void) pthread_mutex_unlock(&h->rh_lock);
}
int
{
scf_handle_t *h = v->value_handle;
(void) pthread_mutex_lock(&h->rh_lock);
scf_value_reset_locked(v, 0);
(void) pthread_mutex_unlock(&h->rh_lock);
return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
}
if (new_nsec == 0)
else
(unsigned)new_nsec);
(void) pthread_mutex_unlock(&h->rh_lock);
return (0);
}
int
{
scf_handle_t *h = v->value_handle;
(void) pthread_mutex_lock(&h->rh_lock);
scf_value_reset_locked(v, 0);
(void) pthread_mutex_unlock(&h->rh_lock);
return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
}
sizeof (v->value_value)) {
(void) pthread_mutex_unlock(&h->rh_lock);
return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
}
(void) pthread_mutex_unlock(&h->rh_lock);
return (0);
}
int
{
scf_handle_t *h = v->value_handle;
(void) pthread_mutex_lock(&h->rh_lock);
scf_value_reset_locked(v, 0);
(void) pthread_mutex_unlock(&h->rh_lock);
return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
}
sizeof (v->value_value)) {
(void) pthread_mutex_unlock(&h->rh_lock);
return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
}
(void) pthread_mutex_unlock(&h->rh_lock);
return (0);
}
int
{
scf_handle_t *h = v->value_handle;
(void) pthread_mutex_lock(&h->rh_lock);
scf_value_reset_locked(v, 0);
if (len > sizeof (v->value_value)) {
(void) pthread_mutex_unlock(&h->rh_lock);
return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
}
v->value_size = len;
(void) pthread_mutex_unlock(&h->rh_lock);
return (0);
}
/*
* Fails with
* _NOT_SET - v_arg is reset
* _INTERNAL - v_arg is corrupt
*
* If t is not _TYPE_INVALID, fails with
* _TYPE_MISMATCH - v_arg's type is not compatible with t
*/
static ssize_t
{
scf_value_t *v = &v_s;
ssize_t r;
uint8_t b;
(void) pthread_mutex_lock(&h->rh_lock);
(void) pthread_mutex_unlock(&h->rh_lock);
return (-1);
}
h->rh_values++; /* keep the handle from going away */
h->rh_extrefs++;
(void) pthread_mutex_unlock(&h->rh_lock);
switch (REP_PROTOCOL_BASE_TYPE(v->value_type)) {
r = scf_value_get_boolean(v, &b);
assert(r == SCF_SUCCESS);
break;
case REP_PROTOCOL_TYPE_COUNT:
case REP_PROTOCOL_TYPE_TIME:
case REP_PROTOCOL_TYPE_STRING:
break;
case REP_PROTOCOL_TYPE_OPAQUE:
/*
* Note that we only write out full hex bytes -- if they're
* short, and bufsz is even, we'll only fill (bufsz - 2) bytes
* with data.
*/
if (bufsz > 0)
r = (v->value_size * 2);
break;
break;
default:
r = (scf_set_error(SCF_ERROR_INTERNAL));
break;
}
(void) pthread_mutex_lock(&h->rh_lock);
h->rh_values--;
h->rh_extrefs--;
handle_unrefed(h);
return (r);
}
{
}
{
if (ty == REP_PROTOCOL_TYPE_INVALID)
return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
}
int
{
scf_handle_t *h = v->value_handle;
switch (type) {
case SCF_TYPE_BOOLEAN: {
uint8_t b;
b = 1;
b = 0;
else {
goto bad;
}
scf_value_set_boolean(v, b);
return (0);
}
case SCF_TYPE_COUNT: {
uint64_t c;
char *endp;
errno = 0;
goto bad;
scf_value_set_count(v, c);
return (0);
}
case SCF_TYPE_INTEGER: {
int64_t i;
char *endp;
errno = 0;
goto bad;
scf_value_set_integer(v, i);
return (0);
}
case SCF_TYPE_TIME: {
int64_t s;
errno = 0;
goto bad;
if (*endp == '.') {
goto bad;
goto bad;
while (len++ < 9)
ns *= 10;
}
return (scf_value_set_time(v, s, ns));
}
case SCF_TYPE_ASTRING:
case SCF_TYPE_USTRING:
case SCF_TYPE_OPAQUE:
case SCF_TYPE_URI:
case SCF_TYPE_FMRI:
case SCF_TYPE_HOST:
case SCF_TYPE_HOSTNAME:
case SCF_TYPE_NET_ADDR_V4:
case SCF_TYPE_NET_ADDR_V6:
(void) pthread_mutex_lock(&h->rh_lock);
scf_value_reset_locked(v, 0);
if (type == SCF_TYPE_OPAQUE) {
str, sizeof (v->value_value));
(void) pthread_mutex_lock(&h->rh_lock);
goto bad;
}
} else {
sizeof (v->value_value));
(void) pthread_mutex_lock(&h->rh_lock);
goto bad;
}
}
v->value_type = ty;
(void) pthread_mutex_unlock(&h->rh_lock);
return (SCF_SUCCESS);
default:
scf_value_reset(v);
return (scf_set_error(SCF_ERROR_TYPE_MISMATCH));
}
bad:
scf_value_reset(v);
return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
}
int
{
}
int
{
struct rep_protocol_iter_read_value request;
struct rep_protocol_value_response response;
int r;
if (h != v->value_handle)
return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
(void) pthread_mutex_lock(&h->rh_lock);
scf_value_reset_locked(v, 0);
(void) pthread_mutex_unlock(&h->rh_lock);
return (scf_set_error(SCF_ERROR_NOT_SET));
}
(void) pthread_mutex_unlock(&h->rh_lock);
return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
}
if (r < 0) {
(void) pthread_mutex_unlock(&h->rh_lock);
}
(void) pthread_mutex_unlock(&h->rh_lock);
return (0);
}
(void) pthread_mutex_unlock(&h->rh_lock);
}
iter->iter_sequence++;
if (v->value_type != REP_PROTOCOL_TYPE_OPAQUE) {
sizeof (v->value_value));
} else {
}
(void) pthread_mutex_unlock(&h->rh_lock);
return (1);
}
int
{
struct rep_protocol_property_request request;
struct rep_protocol_value_response response;
int r;
if (h != v->value_handle)
return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
(void) pthread_mutex_lock(&h->rh_lock);
scf_value_reset_locked(v, 0);
if (r < 0) {
(void) pthread_mutex_unlock(&h->rh_lock);
}
(void) pthread_mutex_unlock(&h->rh_lock);
}
if (v->value_type != REP_PROTOCOL_TYPE_OPAQUE) {
sizeof (v->value_value));
} else {
}
(void) pthread_mutex_unlock(&h->rh_lock);
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
/*
* FMRI functions
*
* Note: In the scf_parse_svc_fmri(), scf_parse_file_fmri() and
* scf_parse_fmri(), fmri isn't const because that would require
* allocating memory. Also, note that scope, at least, is not necessarily
* in the passed in fmri.
*/
int
{
if (propertygroup != NULL)
*propertygroup = NULL;
s = fmri;
e = strchr(s, '\0');
if (strncmp(s, SCF_FMRI_SVC_PREFIX,
sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0)
s += sizeof (SCF_FMRI_SVC_PREFIX) - 1;
if (strncmp(s, SCF_FMRI_SCOPE_PREFIX,
sizeof (SCF_FMRI_SCOPE_PREFIX) - 1) == 0) {
char *my_scope;
s += sizeof (SCF_FMRI_SCOPE_PREFIX) - 1;
te = e;
*te = 0;
my_scope = s;
s = te;
if (s < e)
s += sizeof (SCF_FMRI_SERVICE_PREFIX) - 1;
/* If the scope ends with the suffix, remove it. */
*te = 0;
/* Validate the scope. */
if (my_scope[0] == '\0')
return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
}
} else {
}
if (s[0] != 0) {
if (strncmp(s, SCF_FMRI_SERVICE_PREFIX,
sizeof (SCF_FMRI_SERVICE_PREFIX) - 1) == 0)
s += sizeof (SCF_FMRI_SERVICE_PREFIX) - 1;
/*
* Can't validate service here because it might not be null
* terminated.
*/
my_s = s;
}
*te = 0;
/* Can't validate instance here either. */
} else {
}
*te = 0;
*te = 0;
s = te;
}
}
return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
}
return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
}
return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
if (propertygroup != NULL)
*propertygroup = my_pg;
}
return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
}
return (0);
}
int
{
char *s, *e, *te;
s = fmri;
e = strchr(s, '\0');
if (strncmp(s, SCF_FMRI_FILE_PREFIX,
sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0)
s += sizeof (SCF_FMRI_FILE_PREFIX) - 1;
if (strncmp(s, SCF_FMRI_SCOPE_PREFIX,
sizeof (SCF_FMRI_SCOPE_PREFIX) - 1) == 0) {
char *my_scope;
s += sizeof (SCF_FMRI_SCOPE_PREFIX) - 1;
te = e;
*te = 0;
my_scope = s;
s = te;
/* Validate the scope. */
if (my_scope[0] != '\0' &&
return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
}
} else {
/*
* FMRI paths must be absolute
*/
if (s[0] != '/')
return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
}
s += sizeof (SCF_FMRI_SERVICE_PREFIX) - 1;
if (s >= e)
return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
/*
* If the user requests it, return the full path of the file.
*/
s[-1] = '/';
*path = s - 1;
}
return (0);
}
int
{
sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) {
if (type)
sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) {
if (type)
} else {
/*
* Parse as a svc if the fmri type is not explicitly
* specified.
*/
if (type)
}
}
/*
* Fails with _INVALID_ARGUMENT. fmri and buf may be equal.
*/
{
int r;
/* Should this be CONSTRAINT_VIOLATED? */
(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
return (-1);
}
&property);
if (r != 0)
return (-1);
}
if (service)
if (instance) {
}
if (pg) {
}
if (property) {
}
return (len);
}
/*
* Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _CONSTRAINT_VIOLATED,
* _NOT_FOUND, _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED,
* _NO_RESOURCES, _BACKEND_ACCESS.
*/
int
{
int last;
int ret;
/*
* verify that all handles match
*/
return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
goto reset_args;
}
/*
* We can simply return from an error in parsing, because
* scf_parse_fmri sets the error code correctly.
*/
ret = -1;
goto reset_args;
}
/*
* the FMRI looks valid at this point -- do constraint checks.
*/
goto reset_args;
}
goto reset_args;
}
else
if (flags & SCF_DECODE_FMRI_EXACT) {
int last_fmri;
else if (propertygroup != NULL)
else
goto reset_args;
}
}
if ((flags & SCF_DECODE_FMRI_TRUNCATE) &&
last == REP_PROTOCOL_ENTITY_NONE) {
ret = 0; /* nothing to do */
goto reset_args;
}
if (!(flags & SCF_DECODE_FMRI_TRUNCATE))
/*
* passed the constraint checks -- try to grab the thing itself.
*/
else
svc = h->rh_service;
else
inst = h->rh_instance;
else
else
prop = h->rh_property;
else
/*
* We only support local scopes, but we check *after* getting
* the local scope, so that any repository-related errors take
* precedence.
*/
ret = -1;
goto reset_args;
}
goto reset_args;
}
return (0);
}
ret = -1;
if (scf_error() == SCF_ERROR_DELETED)
(void) scf_set_error(SCF_ERROR_NOT_FOUND);
goto reset_args;
}
if (last == REP_PROTOCOL_ENTITY_SERVICE) {
return (0);
}
if (propertygroup == NULL ||
return (0);
}
ret = -1;
if (scf_error() == SCF_ERROR_DELETED)
(void) scf_set_error(SCF_ERROR_NOT_FOUND);
goto reset_args;
}
} else {
ret = -1;
if (scf_error() == SCF_ERROR_DELETED)
(void) scf_set_error(SCF_ERROR_NOT_FOUND);
goto reset_args;
}
if (propertygroup == NULL ||
return (0);
}
ret = -1;
if (scf_error() == SCF_ERROR_DELETED)
(void) scf_set_error(SCF_ERROR_NOT_FOUND);
goto reset_args;
}
}
return (0);
}
ret = -1;
if (scf_error() == SCF_ERROR_DELETED)
(void) scf_set_error(SCF_ERROR_NOT_FOUND);
goto reset_args;
}
return (0);
return (ret);
}
/*
* Fails with _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response too
* big, bad entity id, request not applicable to entity, name too long for
* buffer), _NOT_SET, or _DELETED.
*/
{
char tmp[REP_PROTOCOL_NAME_LEN];
if (r <= 0)
return (r);
}
return (len);
}
/*
* Fails with _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response too
* big, bad element id, bad ids, bad types, scope has no parent, request not
* applicable to entity, name too long), _NOT_SET, _DELETED,
*/
{
char tmp[REP_PROTOCOL_NAME_LEN];
if (r != SCF_SUCCESS) {
return (-1);
}
else
if (len < 0)
return (-1);
else
if (r < 0)
return (r);
len += r;
else
return (len);
}
{
char tmp[REP_PROTOCOL_NAME_LEN];
if (r != SCF_SUCCESS) {
return (-1);
}
if (len < 0)
return (len);
else
if (r < 0)
return (r);
len += r;
else
return (len);
}
{
char tmp[REP_PROTOCOL_NAME_LEN];
(void) pthread_mutex_lock(&h->rh_lock);
(void) pthread_mutex_unlock(&h->rh_lock);
if (r < 0)
r < sizeof (response)) {
}
case REP_PROTOCOL_ENTITY_SERVICE: {
svc = HANDLE_HOLD_SERVICE(h);
if (r == SCF_SUCCESS)
break;
}
case REP_PROTOCOL_ENTITY_INSTANCE: {
inst = HANDLE_HOLD_INSTANCE(h);
if (r == SCF_SUCCESS)
break;
}
case REP_PROTOCOL_ENTITY_SNAPLEVEL: {
if (r == SCF_SUCCESS)
if (r == SCF_SUCCESS)
if (r == SCF_SUCCESS)
break;
}
default:
return (scf_set_error(SCF_ERROR_INTERNAL));
}
if (r != SCF_SUCCESS)
return (r);
else
if (r < 0)
return (r);
len += r;
else
return (len);
}
{
char tmp[REP_PROTOCOL_NAME_LEN];
int r;
if (r != SCF_SUCCESS) {
HANDLE_RELE_PG(h);
return (-1);
}
HANDLE_RELE_PG(h);
else
if (r < 0)
return (r);
len += r;
else
return (len);
}
/*
* Fails with _HANDLE_MISMATCH, _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL
* (server response too big, bad entity id, request not applicable to entity,
* name too long for buffer, bad element id, iter already exists, element
* cannot have children of type, type is invalid, iter was reset, sequence
* was bad, iter walks values, iter does not walk type entities),
* _NOT_SET, _DELETED, or _CONSTRAINT_VIOLATED,
* _NOT_FOUND (scope has no parent), _INVALID_ARGUMENT, _NO_RESOURCES,
* _BACKEND_ACCESS.
*/
int
{
char me[REP_PROTOCOL_NAME_LEN];
int r;
return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
if (r < 0)
return (r);
svc = HANDLE_HOLD_SERVICE(h);
inst = HANDLE_HOLD_INSTANCE(h);
if (r == SCF_SUCCESS) {
if (r != SCF_SUCCESS) {
goto out;
}
} else {
}
out:
return (r);
}
#define LEGACY_SCHEME "lrc:"
#define LEGACY_UNKNOWN "unknown"
/*
* Implementation of scf_walk_fmri()
*
* This is a little tricky due to the many-to-many relationship between patterns
* and matches. We need to be able to satisfy the following requirements:
*
* 1) Detect patterns which match more than one FMRI, and be able to
* report which FMRIs have been matched.
* 2) Detect patterns which have not matched any FMRIs
* 3) Visit each matching FMRI exactly once across all patterns
* 4) Ignore FMRIs which have only been matched due to multiply-matching
* patterns.
*
* We maintain an array of scf_pattern_t structures, one for each argument, and
* maintain a linked list of scf_match_t structures for each one. We first
* qualify each pattern's type:
*
* PATTERN_INVALID The argument is invalid (too long).
*
* PATTERN_EXACT The pattern is a complete FMRI. The list of
* matches contains only a single entry.
*
* PATTERN_GLOB The pattern will be matched against all
* FMRIs via fnmatch() in the second phase.
* Matches will be added to the pattern's list
* as they are found.
*
* PATTERN_PARTIAL Everything else. We will assume that this is
* an abbreviated FMRI, and match according to
* our abbreviated FMRI rules. Matches will be
* added to the pattern's list as they are found.
*
* The first pass searches for arguments that are complete FMRIs. These are
* classified as EXACT patterns and do not necessitate searching the entire
* tree.
*
* Once this is done, if we have any GLOB or PARTIAL patterns (or if no
* arguments were given), we iterate over all services and instances in the
* repository, looking for matches.
*
* When a match is found, we add the match to the pattern's list. We also enter
* the match into a hash table, resulting in something like this:
*
* scf_pattern_t scf_match_t
* +---------------+ +-------+ +-------+
* | pattern 'foo' |----->| match |---->| match |
* +---------------+ +-------+ +-------+
* | |
* scf_match_key_t | |
* +--------------+ | |
* +--------------+ |
* +--------------+
*
* Once we have all of this set up, we do one pass to report patterns matching
* multiple FMRIs (if SCF_WALK_MULTIPLE is not set) and patterns for which no
* match was found.
*
* Finally, we walk through all valid patterns, and for each match, if we
* haven't already seen the match (as recorded in the hash table), then we
* execute the callback.
*/
struct scf_matchkey;
struct scf_match;
/*
* scf_matchkey_t
*/
typedef struct scf_matchkey {
char *sk_fmri; /* Matching FMRI */
char *sk_legacy; /* Legacy name */
int sk_seen; /* If we've been seen */
/*
* scf_match_t
*/
typedef struct scf_match {
} scf_match_t;
#define WALK_HTABLE_SIZE 123
/*
* scf_get_key()
*
* Given an FMRI and a hash table, returns the scf_matchkey_t corresponding to
* this FMRI. If the FMRI does not exist, it is added to the hash table. If a
* new entry cannot be allocated due to lack of memory, NULL is returned.
*/
static scf_matchkey_t *
{
uint_t h = 0, g;
const char *p, *k;
k += 2;
/*
*/
for (p = k; *p != '\0'; ++p) {
h = (h << 4) + *p;
if ((g = (h & 0xf0000000)) != 0) {
h ^= (g >> 24);
h ^= g;
}
}
h %= WALK_HTABLE_SIZE;
/*
* Search for an existing key
*/
return (key);
}
return (NULL);
/*
* Add new key to hash table.
*/
return (NULL);
}
return (NULL);
}
return (key);
}
/*
* Given an FMRI, insert it into the pattern's list appropriately.
* svc_explicit indicates whether matching services should take
* precedence over matching instances.
*/
static scf_error_t
{
/*
* If svc_explicit is set, enforce the constaint that matching
* instances take precedence over matching services. Otherwise,
* matching services take precedence over matching instances.
*/
if (svc_explicit) {
/*
* If we match an instance, check to see if we must remove
* any matching services (for SCF_WALK_EXPLICIT).
*/
else
pattern->sp_matchcount--;
} else
}
} else {
/*
* If we've matched a service don't add any instances (for
* SCF_WALK_SERVICE).
*/
return (0);
}
}
return (SCF_ERROR_NO_MEMORY);
return (SCF_ERROR_NO_MEMORY);
}
pattern->sp_matchcount++;
return (0);
}
/*
* Returns 1 if the fmri matches the given pattern, 0 otherwise.
*/
int
{
char *tmp;
return (1);
/*
* We only allow partial matches anchored on the end of
* a service or instance, and beginning on an element
* boundary.
*/
tmp[0] != ':')
return (0);
return (0);
/*
* If the user has supplied a short pattern that matches
* 'svc:/' or 'lrc:/', ignore it.
*/
return (0);
return (1);
}
return (0);
}
/*
* Attempts to match the given FMRI against a set of patterns, keeping track of
* the results.
*/
static scf_error_t
{
int i;
int ret = 0;
for (i = 0; i < npattern; i++) {
return (ret);
}
return (0);
}
/*
* Fails with _INVALID_ARGUMENT, _HANDLE_DESTROYED, _INTERNAL (bad server
* response or id in use), _NO_MEMORY, _HANDLE_MISMATCH, _CONSTRAINT_VIOLATED,
* _NOT_FOUND, _NOT_BOUND, _CONNECTION_BROKEN, _NOT_SET, _DELETED,
* _NO_RESOURCES, _BACKEND_ACCESS, _TYPE_MISMATCH.
*/
void (*errfunc)(const char *, ...))
{
int i;
int ret = 0;
int pattern_search = 0;
#ifndef NDEBUG
if (flags & SCF_WALK_EXPLICIT)
if (flags & SCF_WALK_NOINSTANCE)
if (flags & SCF_WALK_PROPERTY)
#endif
/*
* Setup initial variables
*/
return (SCF_ERROR_INTERNAL);
goto error;
}
if (argc == 0) {
== NULL) {
goto error;
}
goto error;
}
goto error;
}
/*
* For each fmri given, we first check to see if it's a full service,
* instance, property group, or property FMRI. This avoids having to do
* the (rather expensive) walk of all instances. Any element which does
* not match a full fmri is identified as a globbed pattern or a partial
* fmri and stored in a private array when walking instances.
*/
for (i = 0; i < argc; i++) {
const char *prop_name;
*err = UU_EXIT_FATAL;
continue;
}
goto badfmri;
/*
* If the user has specified SCF_WALK_PROPERTY, allow property
* groups and properties.
*/
if (!(flags & SCF_WALK_PROPERTY))
goto badfmri;
goto badfmri;
goto badfmri;
<= 0) {
/*
* scf_parse_fmri() should have caught this.
*/
abort();
}
goto error;
goto error;
}
}
/*
* We need at least a service name
*/
goto badfmri;
/*
* If we have a fully qualified instance, add it to our list of
* fmris to watch.
*/
if (flags & SCF_WALK_NOINSTANCE)
goto badfmri;
goto badfmri;
<= 0)
goto badfmri;
goto error;
goto error;
}
continue;
}
goto badfmri;
/*
* If the user allows for bare services, then simply
* pass this service on.
*/
if (flags & SCF_WALK_SERVICE) {
max_fmri_length + 1) <= 0) {
goto error;
}
goto error;
== NULL) {
goto error;
}
continue;
}
if (flags & SCF_WALK_NOINSTANCE)
goto badfmri;
/*
* Otherwise, iterate over all instances in the service.
*/
SCF_SUCCESS) {
goto error;
}
for (;;) {
if (ret == 0)
break;
if (ret != 1) {
goto error;
}
goto badfmri;
goto error;
}
goto error;
}
continue;
/*
* If we got here because of a fatal error, bail out
* immediately.
*/
if (scf_error() == SCF_ERROR_CONNECTION_BROKEN) {
goto error;
}
/*
* At this point we failed to interpret the argument as a
* complete fmri, so mark it as a partial or globbed FMRI for
* later processing.
*/
/*
* Prepend svc:/ to patterns which don't begin with * or
* svc: or lrc:.
*/
if (argv[i][0] == '*' ||
else {
argv[i]);
}
} else {
}
pattern_search = 1;
goto error;
}
}
if (pattern_search || argc == 0) {
/*
* We have a set of patterns to search for. Iterate over all
* instances and legacy services searching for matches.
*/
if (scf_handle_get_local_scope(h, scope) != 0) {
goto error;
}
goto error;
}
for (;;) {
if (ret == 0)
break;
if (ret != 1) {
goto error;
}
if (flags & SCF_WALK_SERVICE) {
/*
* If the user is requesting bare services, try
* to match the service first.
*/
max_fmri_length + 1) < 0) {
goto error;
}
if (argc == 0) {
goto error;
continue;
flags & SCF_WALK_EXPLICIT)) != 0) {
goto error;
}
}
if (flags & SCF_WALK_NOINSTANCE)
continue;
/*
* Iterate over all instances in the service.
*/
if (scf_error() != SCF_ERROR_DELETED) {
goto error;
}
continue;
}
for (;;) {
if (ret == 0)
break;
if (ret != 1) {
if (scf_error() != SCF_ERROR_DELETED) {
goto error;
}
break;
}
max_fmri_length + 1) < 0) {
goto error;
}
/*
* Without arguments, execute the callback
* immediately.
*/
if (argc == 0) {
goto error;
flags & SCF_WALK_EXPLICIT)) != 0) {
goto error;
}
}
}
/*
* Search legacy services
*/
if ((flags & SCF_WALK_LEGACY)) {
svc) != 0) {
if (scf_error() != SCF_ERROR_NOT_FOUND) {
goto error;
}
goto nolegacy;
}
SCF_GROUP_FRAMEWORK) != SCF_SUCCESS) {
goto error;
}
for (;;) {
if (ret == -1) {
goto error;
}
if (ret == 0)
break;
if (scf_pg_get_property(pg,
if (ret == SCF_ERROR_DELETED ||
ret == SCF_ERROR_NOT_FOUND) {
ret = 0;
continue;
}
goto error;
}
!= SCF_SUCCESS) {
if (scf_error() == SCF_ERROR_DELETED)
continue;
goto error;
}
continue;
max_fmri_length + 2 -
sizeof (LEGACY_SCHEME)) <= 0)
continue;
max_name_length + 1) <= 0) {
if (scf_error() == SCF_ERROR_DELETED)
continue;
goto error;
}
if (argc == 0) {
goto error;
flags & SCF_WALK_EXPLICIT)) != 0)
goto error;
}
}
}
ret = 0;
if (argc == 0)
goto error;
/*
* Check all patterns, and see if we have that any that didn't match
* or any that matched multiple instances. For svcprop, add up the
* total number of matching keys.
*/
for (i = 0; i < argc; i++) {
continue;
if (pattern[i].sp_matchcount == 0) {
/*
* Provide a useful error message based on the argument
* and the type of entity requested.
*/
if (!(flags & SCF_WALK_LEGACY) &&
else if (flags & SCF_WALK_PROPERTY)
else if (flags & SCF_WALK_NOINSTANCE)
else if (flags & SCF_WALK_SERVICE)
else
if (err)
*err = UU_EXIT_FATAL;
} else if (!(flags & SCF_WALK_MULTIPLE) &&
char *msg;
/*
* Construct a message with all possible FMRIs before
* passing off to error handling function.
*
* Note that strlen(scf_get_msg(...)) includes the
* length of '%s', which accounts for the terminating
* null byte.
*/
}
goto error;
}
/* LINTED - format argument */
}
*err = UU_EXIT_FATAL;
} else {
}
}
}
/*
* Clear 'sk_seen' for all keys.
*/
for (i = 0; i < WALK_HTABLE_SIZE; i++) {
}
/*
* Iterate over all the FMRIs in our hash table and execute the
* callback.
*/
for (i = 0; i < argc; i++) {
/*
* Ignore patterns which didn't match anything or matched too
* many FMRIs.
*/
if (pattern[i].sp_matchcount == 0 ||
(!(flags & SCF_WALK_MULTIPLE) &&
continue;
continue;
"smf/legacy_run", svc) != 0) {
goto error;
}
pg) != 0)
continue;
goto error;
} else {
continue;
if (scf_error() ==
goto error;
}
} else {
}
if (scf_error() ==
goto error;
}
} else {
}
if (scf_error() ==
goto error;
}
} else {
}
goto error;
}
}
}
if (htable) {
for (i = 0; i < WALK_HTABLE_SIZE; i++) {
}
}
}
for (i = 0; i < argc; i++) {
}
}
}
return (ret);
}
/*
* _scf_request_backup: a simple wrapper routine
*/
int
{
struct rep_protocol_backup_request request;
struct rep_protocol_response response;
int r;
return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
(void) pthread_mutex_lock(&h->rh_lock);
(void) pthread_mutex_unlock(&h->rh_lock);
if (r < 0) {
}
return (SCF_SUCCESS);
}
int
{
char buf[REP_PROTOCOL_NAME_LEN];
if (res == -1)
return (-1);
return (scf_set_error(SCF_ERROR_INTERNAL));
return (SCF_SUCCESS);
}