Source code

Revision control

Copy as Markdown

Other Tools

/*
*
* registry.c
*
* $Source: /Users/ekr/tmp/nrappkit-dump/nrappkit/src/registry/registry_local.c,v $
* $Revision: 1.4 $
* $Date: 2007/11/21 00:09:13 $
*
* Datastore for tracking configuration and related info.
*
*
* Copyright (C) 2005, Network Resonance, Inc.
* Copyright (C) 2006, Network Resonance, Inc.
* All Rights Reserved
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Network Resonance, Inc. nor the name of any
* contributors to this software may be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*
*/
#include <assert.h>
#include <string.h>
#ifndef WIN32
#include <strings.h>
#include <sys/param.h>
#include <netinet/in.h>
#endif
#ifdef OPENSSL
#include <openssl/ssl.h>
#endif
#include <ctype.h>
#include <stdlib.h>
#include "registry.h"
#include "registry_int.h"
#include "registry_vtbl.h"
#include "r_assoc.h"
#include "nr_common.h"
#include "r_log.h"
#include "r_errors.h"
#include "r_macros.h"
static int nr_reg_local_compare_string(const void *arg1, const void *arg2) {
return strcasecmp(*(const char **)arg1, *(const char **)arg2);
}
/* if C were an object-oriented language, nr_scalar_registry_node and
* nr_array_registry_node would subclass nr_registry_node, but it isn't
* object-oriented language, so this is used in cases where the pointer
* could be of either type */
typedef struct nr_registry_node_ {
unsigned char type;
} nr_registry_node;
typedef struct nr_scalar_registry_node_ {
unsigned char type;
union {
char _char;
UCHAR _uchar;
INT2 _nr_int2;
UINT2 _nr_uint2;
INT4 _nr_int4;
UINT4 _nr_uint4;
INT8 _nr_int8;
UINT8 _nr_uint8;
double _double;
} scalar;
} nr_scalar_registry_node;
/* string, bytes */
typedef struct nr_array_registry_node_ {
unsigned char type;
struct {
unsigned int length;
unsigned char data[1];
} array;
} nr_array_registry_node;
static int nr_reg_local_init(nr_registry_module *me);
static int nr_reg_local_get_char(NR_registry name, char *data);
static int nr_reg_local_get_uchar(NR_registry name, UCHAR *data);
static int nr_reg_local_get_int2(NR_registry name, INT2 *data);
static int nr_reg_local_get_uint2(NR_registry name, UINT2 *data);
static int nr_reg_local_get_int4(NR_registry name, INT4 *data);
static int nr_reg_local_get_uint4(NR_registry name, UINT4 *data);
static int nr_reg_local_get_int8(NR_registry name, INT8 *data);
static int nr_reg_local_get_uint8(NR_registry name, UINT8 *data);
static int nr_reg_local_get_double(NR_registry name, double *data);
static int nr_reg_local_get_registry(NR_registry name, NR_registry data);
static int nr_reg_local_get_bytes(NR_registry name, UCHAR *data, size_t size, size_t *length);
static int nr_reg_local_get_string(NR_registry name, char *data, size_t size);
static int nr_reg_local_get_length(NR_registry name, size_t *len);
static int nr_reg_local_get_type(NR_registry name, NR_registry_type type);
static int nr_reg_local_set_char(NR_registry name, char data);
static int nr_reg_local_set_uchar(NR_registry name, UCHAR data);
static int nr_reg_local_set_int2(NR_registry name, INT2 data);
static int nr_reg_local_set_uint2(NR_registry name, UINT2 data);
static int nr_reg_local_set_int4(NR_registry name, INT4 data);
static int nr_reg_local_set_uint4(NR_registry name, UINT4 data);
static int nr_reg_local_set_int8(NR_registry name, INT8 data);
static int nr_reg_local_set_uint8(NR_registry name, UINT8 data);
static int nr_reg_local_set_double(NR_registry name, double data);
static int nr_reg_local_set_registry(NR_registry name);
static int nr_reg_local_set_bytes(NR_registry name, UCHAR *data, size_t length);
static int nr_reg_local_set_string(NR_registry name, char *data);
static int nr_reg_local_del(NR_registry name);
static int nr_reg_local_get_child_count(NR_registry parent, size_t *count);
static int nr_reg_local_get_children(NR_registry parent, NR_registry *data, size_t size, size_t *length);
static int nr_reg_local_fin(NR_registry name);
static int nr_reg_local_dump(int sorted);
static int nr_reg_insert_node(char *name, void *node);
static int nr_reg_change_node(char *name, void *node, void *old);
static int nr_reg_get(char *name, int type, void *out);
static int nr_reg_get_data(NR_registry name, nr_scalar_registry_node *node, void *out);
static int nr_reg_get_array(char *name, unsigned char type, UCHAR *out, size_t size, size_t *length);
static int nr_reg_set(char *name, int type, void *data);
static int nr_reg_set_array(char *name, unsigned char type, UCHAR *data, size_t length);
static int nr_reg_set_parent_registries(char *name);
int nr_reg_fetch_node(char *name, unsigned char type, nr_registry_node **node, int *free_node);
char *nr_reg_alloc_node_data(char *name, nr_registry_node *node, int *freeit);
static int nr_reg_rfree(void *ptr);
static int nr_reg_compute_length(char *name, nr_registry_node *node, size_t *length);
char *nr_reg_action_name(int action);
/* the registry, containing mappings like "foo.bar.baz" to registry
* nodes, which are either of type nr_scalar_registry_node or
* nr_array_registry_node */
static r_assoc *nr_registry = 0;
typedef struct nr_reg_find_children_arg_ {
size_t size;
NR_registry *children;
size_t length;
} nr_reg_find_children_arg;
static int nr_reg_local_iter(NR_registry prefix, int (*action)(void *ptr, r_assoc_iterator *iter, char *prefix, char *name, nr_registry_node *node), void *ptr);
static int nr_reg_local_iter_delete(void *ptr, r_assoc_iterator *iter, char *prefix, char *name, nr_registry_node *node);
static int nr_reg_local_find_children(void *ptr, r_assoc_iterator *iter, char *prefix, char *name, nr_registry_node *node);
static int nr_reg_local_count_children(void *ptr, r_assoc_iterator *iter, char *prefix, char *name, nr_registry_node *node);
static int nr_reg_local_dump_print(void *ptr, r_assoc_iterator *iter, char *prefix, char *name, nr_registry_node *node);
int
nr_reg_local_iter(NR_registry prefix, int (*action)(void *ptr, r_assoc_iterator *iter, char *prefix, char *name, nr_registry_node *node), void *ptr)
{
int r, _status;
r_assoc_iterator iter;
char *name = 0;
int namel;
nr_registry_node *node;
int prefixl;
if (prefix == 0)
ABORT(R_INTERNAL);
if ((r=r_assoc_init_iter(nr_registry, &iter)))
ABORT(r);
prefixl = strlen(prefix);
for (;;) {
if ((r=r_assoc_iter(&iter, (void*)&name, &namel, (void*)&node))) {
if (r == R_EOD)
break;
else
ABORT(r);
}
/* subtract to remove the '\0' character from the string length */
--namel;
/* sanity check that the name is null-terminated */
assert(namel >= 0);
assert(name[namel] == '\0');
if (namel < 0 || name[namel] != '\0' || node == 0)
break;
/* 3 cases where action will be called:
* 1) prefix == ""
* 2) prefix == name
* 3) name == prefix + '.'
*/
if (prefixl == 0
|| ((namel == prefixl || (namel > prefixl && name[prefixl] == '.'))
&& !strncmp(prefix, name, prefixl))) {
if ((r=action(ptr, &iter, prefix, name, node)))
ABORT(r);
}
}
_status=0;
abort:
return(_status);
}
int
nr_reg_local_iter_delete(void *ptr, r_assoc_iterator *iter, char *prefix, char *name, nr_registry_node *node)
{
int r, _status;
if ((r=r_assoc_iter_delete(iter)))
ABORT(r);
_status=0;
abort:
return(_status);
}
int
nr_reg_local_find_children(void *ptr, r_assoc_iterator *iter, char *prefix, char *name, nr_registry_node *node)
{
int _status;
int prefixl = strlen(prefix);
char *dot = 0;
nr_reg_find_children_arg *arg = (void*)ptr;
assert(sizeof(*(arg->children)) == sizeof(NR_registry));
/* only grovel through immediate children */
if (prefixl == 0 || name[prefixl] == '.') {
if (name[prefixl] != '\0') {
dot = strchr(&name[prefixl+1], '.');
if (dot == 0) {
strncpy(arg->children[arg->length], name, sizeof(NR_registry)-1);
++arg->length;
/* only grab as many as there are room for */
if (arg->length >= arg->size)
ABORT(R_INTERRUPTED);
}
}
}
_status = 0;
abort:
return _status;
}
int
nr_reg_local_count_children(void *ptr, r_assoc_iterator *iter, char *prefix, char *name, nr_registry_node *node)
{
int prefixl = strlen(prefix);
char *dot = 0;
/* only count children */
if (name[prefixl] == '.') {
dot = strchr(&name[prefixl+1], '.');
if (dot == 0)
++(*(unsigned int *)ptr);
}
else if (name[0] != '\0') {
if (prefixl == 0)
++(*(unsigned int *)ptr);
}
return 0;
}
int
nr_reg_local_dump_print(void *ptr, r_assoc_iterator *iter, char *prefix, char *name, nr_registry_node *node)
{
int _status;
int freeit = 0;
char *data = 0;
/* only print leaf nodes */
if (node->type != NR_REG_TYPE_REGISTRY) {
data = nr_reg_alloc_node_data(name, node, &freeit);
if (ptr)
fprintf((FILE*)ptr, "%s: %s\n", name, data);
else
r_log(NR_LOG_REGISTRY, LOG_INFO, "%s: %s", name, data);
if (freeit)
RFREE(data);
}
_status=0;
//abort:
return(_status);
}
int
nr_reg_rfree(void *ptr)
{
RFREE(ptr);
return 0;
}
int
nr_reg_fetch_node(char *name, unsigned char type, nr_registry_node **node, int *free_node)
{
int r, _status;
*node = 0;
*free_node = 0;
if ((r=nr_reg_is_valid(name)))
ABORT(r);
if ((r=r_assoc_fetch(nr_registry, name, strlen(name)+1, (void*)node)))
ABORT(r);
if ((*node)->type != type)
ABORT(R_FAILED);
_status=0;
abort:
if (_status) {
if (*node)
r_log(NR_LOG_REGISTRY, LOG_DEBUG, "Couldn't fetch node '%s' ('%s'), found '%s' instead",
name, nr_reg_type_name(type), nr_reg_type_name((*node)->type));
else
r_log(NR_LOG_REGISTRY, LOG_DEBUG, "Couldn't fetch node '%s' ('%s')",
name, nr_reg_type_name(type));
}
else {
r_log(NR_LOG_REGISTRY, LOG_DEBUG, "Fetched node '%s' ('%s')",
name, nr_reg_type_name(type));
}
return(_status);
}
int
nr_reg_insert_node(char *name, void *node)
{
int r, _status;
if ((r=nr_reg_is_valid(name)))
ABORT(r);
/* since the registry application is not multi-threaded, a node being
* inserted should always be a new node because the registry app must
* have looked for a node with this key but not found it, so it is
* being created/inserted now using R_ASSOC_NEW */
if ((r=r_assoc_insert(nr_registry, name, strlen(name)+1, node, 0, nr_reg_rfree, R_ASSOC_NEW)))
ABORT(r);
if ((r=nr_reg_set_parent_registries(name)))
ABORT(r);
if ((r=nr_reg_raise_event(name, NR_REG_CB_ACTION_ADD)))
ABORT(r);
_status=0;
abort:
if (r_logging(NR_LOG_REGISTRY, LOG_INFO)) {
int freeit;
char *data = nr_reg_alloc_node_data(name, (void*)node, &freeit);
r_log(NR_LOG_REGISTRY, LOG_INFO,
"insert '%s' (%s) %s: %s", name,
nr_reg_type_name(((nr_registry_node*)node)->type),
(_status ? "FAILED" : "succeeded"), data);
if (freeit)
RFREE(data);
}
return(_status);
}
int
nr_reg_change_node(char *name, void *node, void *old)
{
int r, _status;
if ((r=nr_reg_is_valid(name)))
ABORT(r);
if (old != node) {
if ((r=r_assoc_insert(nr_registry, name, strlen(name)+1, node, 0, nr_reg_rfree, R_ASSOC_REPLACE)))
ABORT(r);
}
if ((r=nr_reg_raise_event(name, NR_REG_CB_ACTION_CHANGE)))
ABORT(r);
_status=0;
abort:
if (r_logging(NR_LOG_REGISTRY, LOG_INFO)) {
int freeit;
char *data = nr_reg_alloc_node_data(name, (void*)node, &freeit);
r_log(NR_LOG_REGISTRY, LOG_INFO,
"change '%s' (%s) %s: %s", name,
nr_reg_type_name(((nr_registry_node*)node)->type),
(_status ? "FAILED" : "succeeded"), data);
if (freeit)
RFREE(data);
}
return(_status);
}
char *
nr_reg_alloc_node_data(char *name, nr_registry_node *node, int *freeit)
{
char *s = 0;
int len;
int alloc = 0;
unsigned int i;
*freeit = 0;
switch (node->type) {
default:
alloc = 100; /* plenty of room for any of the scalar types */
break;
case NR_REG_TYPE_REGISTRY:
alloc = strlen(name) + 1;
break;
case NR_REG_TYPE_BYTES:
alloc = (2 * ((nr_array_registry_node*)node)->array.length) + 1;
break;
case NR_REG_TYPE_STRING:
alloc = 0;
break;
}
if (alloc > 0) {
s = (void*)RMALLOC(alloc);
if (!s)
return "";
*freeit = 1;
}
len = alloc;
switch (node->type) {
case NR_REG_TYPE_CHAR:
i = ((nr_scalar_registry_node*)node)->scalar._char;
if (isprint(i) && ! isspace(i))
snprintf(s, len, "%c", (char)i);
else
snprintf(s, len, "\\%03o", (char)i);
break;
case NR_REG_TYPE_UCHAR:
snprintf(s, len, "0x%02x", ((nr_scalar_registry_node*)node)->scalar._uchar);
break;
case NR_REG_TYPE_INT2:
snprintf(s, len, "%d", ((nr_scalar_registry_node*)node)->scalar._nr_int2);
break;
case NR_REG_TYPE_UINT2:
snprintf(s, len, "%u", ((nr_scalar_registry_node*)node)->scalar._nr_uint2);
break;
case NR_REG_TYPE_INT4:
snprintf(s, len, "%d", ((nr_scalar_registry_node*)node)->scalar._nr_int4);
break;
case NR_REG_TYPE_UINT4:
snprintf(s, len, "%u", ((nr_scalar_registry_node*)node)->scalar._nr_uint4);
break;
case NR_REG_TYPE_INT8:
snprintf(s, len, "%lld", ((nr_scalar_registry_node*)node)->scalar._nr_int8);
break;
case NR_REG_TYPE_UINT8:
snprintf(s, len, "%llu", ((nr_scalar_registry_node*)node)->scalar._nr_uint8);
break;
case NR_REG_TYPE_DOUBLE:
snprintf(s, len, "%#f", ((nr_scalar_registry_node*)node)->scalar._double);
break;
case NR_REG_TYPE_REGISTRY:
snprintf(s, len, "%s", name);
break;
case NR_REG_TYPE_BYTES:
for (i = 0; i < ((nr_array_registry_node*)node)->array.length; ++i) {
sprintf(&s[2*i], "%02x", ((nr_array_registry_node*)node)->array.data[i]);
}
break;
case NR_REG_TYPE_STRING:
s = (char*)((nr_array_registry_node*)node)->array.data;
break;
default:
assert(0); /* bad value */
*freeit = 0;
s = "";
break;
}
return s;
}
int
nr_reg_get(char *name, int type, void *out)
{
int r, _status;
nr_scalar_registry_node *node = 0;
int free_node = 0;
if ((r=nr_reg_fetch_node(name, type, (void*)&node, &free_node)))
ABORT(r);
if ((r=nr_reg_get_data(name, node, out)))
ABORT(r);
_status=0;
abort:
if (free_node) RFREE(node);
return(_status);
}
int
nr_reg_get_data(NR_registry name, nr_scalar_registry_node *node, void *out)
{
int _status;
switch (node->type) {
case NR_REG_TYPE_CHAR:
*(char*)out = node->scalar._char;
break;
case NR_REG_TYPE_UCHAR:
*(UCHAR*)out = node->scalar._uchar;
break;
case NR_REG_TYPE_INT2:
*(INT2*)out = node->scalar._nr_int2;
break;
case NR_REG_TYPE_UINT2:
*(UINT2*)out = node->scalar._nr_uint2;
break;
case NR_REG_TYPE_INT4:
*(INT4*)out = node->scalar._nr_int4;
break;
case NR_REG_TYPE_UINT4:
*(UINT4*)out = node->scalar._nr_uint4;
break;
case NR_REG_TYPE_INT8:
*(INT8*)out = node->scalar._nr_int8;
break;
case NR_REG_TYPE_UINT8:
*(UINT8*)out = node->scalar._nr_uint8;
break;
case NR_REG_TYPE_DOUBLE:
*(double*)out = node->scalar._double;
break;
default:
ABORT(R_INTERNAL);
break;
}
_status=0;
abort:
return(_status);
}
int
nr_reg_get_array(char *name, unsigned char type, unsigned char *out, size_t size, size_t *length)
{
int r, _status;
nr_array_registry_node *node = 0;
int free_node = 0;
if ((r=nr_reg_fetch_node(name, type, (void*)&node, &free_node)))
ABORT(r);
if (size < node->array.length)
ABORT(R_BAD_ARGS);
if (out != 0)
memcpy(out, node->array.data, node->array.length);
if (length != 0)
*length = node->array.length;
_status=0;
abort:
if (node && free_node) RFREE(node);
return(_status);
}
int
nr_reg_set(char *name, int type, void *data)
{
int r, _status;
nr_scalar_registry_node *node = 0;
int create_node = 0;
int changed = 0;
int free_node = 0;
if ((r=nr_reg_fetch_node(name, type, (void*)&node, &free_node)))
if (r == R_NOT_FOUND) {
create_node = 1;
free_node = 1;
}
else
ABORT(r);
if (create_node) {
if (!(node=(void*)RCALLOC(sizeof(nr_scalar_registry_node))))
ABORT(R_NO_MEMORY);
node->type = type;
}
else {
if (node->type != type)
ABORT(R_BAD_ARGS);
}
switch (type) {
#define CASE(TYPE, _name, type) \
case TYPE: \
if (node->scalar._name != *(type*)data) { \
node->scalar._name = *(type*)data; \
if (! create_node) \
changed = 1; \
} \
break;
CASE(NR_REG_TYPE_CHAR, _char, char)
CASE(NR_REG_TYPE_UCHAR, _uchar, UCHAR)
CASE(NR_REG_TYPE_INT2, _nr_int2, INT2)
CASE(NR_REG_TYPE_UINT2, _nr_uint2, UINT2)
CASE(NR_REG_TYPE_INT4, _nr_int4, INT4)
CASE(NR_REG_TYPE_UINT4, _nr_uint4, UINT4)
CASE(NR_REG_TYPE_INT8, _nr_int8, INT8)
CASE(NR_REG_TYPE_UINT8, _nr_uint8, UINT8)
CASE(NR_REG_TYPE_DOUBLE, _double, double)
#undef CASE
case NR_REG_TYPE_REGISTRY:
/* do nothing */
break;
default:
ABORT(R_INTERNAL);
break;
}
if (create_node) {
if ((r=nr_reg_insert_node(name, node)))
ABORT(r);
free_node = 0;
}
else {
if (changed) {
if ((r=nr_reg_change_node(name, node, node)))
ABORT(r);
free_node = 0;
}
}
_status=0;
abort:
if (_status) {
if (node && free_node) RFREE(node);
}
return(_status);
}
int
nr_reg_set_array(char *name, unsigned char type, UCHAR *data, size_t length)
{
int r, _status;
nr_array_registry_node *old = 0;
nr_array_registry_node *node = 0;
int free_node = 0;
int added = 0;
int changed = 0;
if ((r=nr_reg_fetch_node(name, type, (void*)&old, &free_node))) {
if (r != R_NOT_FOUND)
ABORT(r);
}
else {
assert(free_node == 0);
}
if (old) {
if (old->type != type)
ABORT(R_BAD_ARGS);
if (old->array.length != length
|| memcmp(old->array.data, data, length)) {
changed = 1;
if (old->array.length < length) {
if (!(node=(void*)RCALLOC(sizeof(nr_array_registry_node)+length)))
ABORT(R_NO_MEMORY);
}
else {
node = old;
}
}
}
else {
if (!(node=(void*)RCALLOC(sizeof(nr_array_registry_node)+length)))
ABORT(R_NO_MEMORY);
added = 1;
}
if (added || changed) {
node->type = type;
node->array.length = length;
memcpy(node->array.data, data, length);
}
if (added) {
if ((r=nr_reg_insert_node(name, node)))
ABORT(r);
}
else if (changed) {
if ((r=nr_reg_change_node(name, node, old)))
ABORT(r);
}
_status=0;
abort:
return(_status);
}
int
nr_reg_set_parent_registries(char *name)
{
int r, _status;
char *parent = 0;
char *dot = 0;
if ((parent = r_strdup(name)) == 0)
ABORT(R_NO_MEMORY);
if ((dot = strrchr(parent, '.')) != 0) {
*dot = '\0';
if ((r=NR_reg_set_registry(parent)))
ABORT(r);
}
_status=0;
abort:
if (parent) RFREE(parent);
return(_status);
}
/* NON-STATIC METHODS */
int
nr_reg_is_valid(NR_registry name)
{
int _status;
unsigned int length;
unsigned int i;
if (name == 0)
ABORT(R_BAD_ARGS);
/* make sure the key is null-terminated */
if (memchr(name, '\0', sizeof(NR_registry)) == 0)
ABORT(R_BAD_ARGS);
length = strlen(name);
/* cannot begin or end with a period */
if (name[0] == '.')
ABORT(R_BAD_ARGS);
if (strlen(name) > 0 && name[length-1] == '.')
ABORT(R_BAD_ARGS);
/* all characters cannot be space, and must be printable and not / */
for (i = 0; i < length; ++i) {
if (isspace(name[i]) || !isprint(name[i]) || name[i] == '/')
ABORT(R_BAD_ARGS);
}
_status=0;
abort:
if (_status) {
r_log(NR_LOG_REGISTRY, LOG_DEBUG, "invalid name '%s'", name);
}
return(_status);
}
int
nr_reg_compute_length(char *name, nr_registry_node *in, size_t *length)
{
int _status;
nr_array_registry_node *node = (nr_array_registry_node*)in;
switch (node->type) {
case NR_REG_TYPE_STRING:
*length = node->array.length - 1;
break;
case NR_REG_TYPE_BYTES:
*length = node->array.length;
break;
case NR_REG_TYPE_CHAR:
*length = sizeof(char);
break;
case NR_REG_TYPE_UCHAR:
*length = sizeof(UCHAR);
break;
case NR_REG_TYPE_INT2:
case NR_REG_TYPE_UINT2:
*length = 2;
break;
case NR_REG_TYPE_INT4:
case NR_REG_TYPE_UINT4:
*length = 4;
break;
case NR_REG_TYPE_INT8:
case NR_REG_TYPE_UINT8:
*length = 8;
break;
case NR_REG_TYPE_DOUBLE:
*length = sizeof(double);
break;
case NR_REG_TYPE_REGISTRY:
*length = strlen(name);
break;
default:
ABORT(R_INTERNAL);
break;
}
_status=0;
abort:
return(_status);
}
/* VTBL METHODS */
int
nr_reg_local_init(nr_registry_module *me)
{
int r, _status;
if (nr_registry == 0) {
if ((r=r_assoc_create(&nr_registry, r_assoc_crc32_hash_compute, 12)))
ABORT(r);
if ((r=nr_reg_cb_init()))
ABORT(r);
/* make sure NR_TOP_LEVEL_REGISTRY always exists */
if ((r=nr_reg_local_set_registry(NR_TOP_LEVEL_REGISTRY)))
ABORT(r);
}
_status=0;
abort:
return(_status);
}
#define NRREGLOCALGET(func, TYPE, type) \
int \
func(NR_registry name, type *out) \
{ \
return nr_reg_get(name, TYPE, out); \
}
NRREGLOCALGET(nr_reg_local_get_char, NR_REG_TYPE_CHAR, char)
NRREGLOCALGET(nr_reg_local_get_uchar, NR_REG_TYPE_UCHAR, UCHAR)
NRREGLOCALGET(nr_reg_local_get_int2, NR_REG_TYPE_INT2, INT2)
NRREGLOCALGET(nr_reg_local_get_uint2, NR_REG_TYPE_UINT2, UINT2)
NRREGLOCALGET(nr_reg_local_get_int4, NR_REG_TYPE_INT4, INT4)
NRREGLOCALGET(nr_reg_local_get_uint4, NR_REG_TYPE_UINT4, UINT4)
NRREGLOCALGET(nr_reg_local_get_int8, NR_REG_TYPE_INT8, INT8)
NRREGLOCALGET(nr_reg_local_get_uint8, NR_REG_TYPE_UINT8, UINT8)
NRREGLOCALGET(nr_reg_local_get_double, NR_REG_TYPE_DOUBLE, double)
int
nr_reg_local_get_registry(NR_registry name, NR_registry out)
{
int r, _status;
nr_scalar_registry_node *node = 0;
int free_node = 0;
if ((r=nr_reg_fetch_node(name, NR_REG_TYPE_REGISTRY, (void*)&node, &free_node)))
ABORT(r);
strncpy(out, name, sizeof(NR_registry));
_status=0;
abort:
if (free_node) RFREE(node);
return(_status);
}
int
nr_reg_local_get_bytes(NR_registry name, UCHAR *out, size_t size, size_t *length)
{
return nr_reg_get_array(name, NR_REG_TYPE_BYTES, out, size, length);
}
int
nr_reg_local_get_string(NR_registry name, char *out, size_t size)
{
return nr_reg_get_array(name, NR_REG_TYPE_STRING, (UCHAR*)out, size, 0);
}
int
nr_reg_local_get_length(NR_registry name, size_t *length)
{
int r, _status;
nr_registry_node *node = 0;
if ((r=nr_reg_is_valid(name)))
ABORT(r);
if ((r=r_assoc_fetch(nr_registry, name, strlen(name)+1, (void*)&node)))
ABORT(r);
if ((r=nr_reg_compute_length(name, node, length)))
ABORT(r);
_status=0;
abort:
return(_status);
}
int
nr_reg_local_get_type(NR_registry name, NR_registry_type type)
{
int r, _status;
nr_registry_node *node = 0;
char *str = 0;
if ((r=nr_reg_is_valid(name)))
ABORT(r);
if ((r=r_assoc_fetch(nr_registry, name, strlen(name)+1, (void*)&node)))
ABORT(r);
str = nr_reg_type_name(node->type);
if (! str)
ABORT(R_BAD_ARGS);
strncpy(type, str, sizeof(NR_registry_type));
_status=0;
abort:
return(_status);
}
#define NRREGLOCALSET(func, TYPE, type) \
int \
func(NR_registry name, type data) \
{ \
return nr_reg_set(name, TYPE, &data); \
}
NRREGLOCALSET(nr_reg_local_set_char, NR_REG_TYPE_CHAR, char)
NRREGLOCALSET(nr_reg_local_set_uchar, NR_REG_TYPE_UCHAR, UCHAR)
NRREGLOCALSET(nr_reg_local_set_int2, NR_REG_TYPE_INT2, INT2)
NRREGLOCALSET(nr_reg_local_set_uint2, NR_REG_TYPE_UINT2, UINT2)
NRREGLOCALSET(nr_reg_local_set_int4, NR_REG_TYPE_INT4, INT4)
NRREGLOCALSET(nr_reg_local_set_uint4, NR_REG_TYPE_UINT4, UINT4)
NRREGLOCALSET(nr_reg_local_set_int8, NR_REG_TYPE_INT8, INT8)
NRREGLOCALSET(nr_reg_local_set_uint8, NR_REG_TYPE_UINT8, UINT8)
NRREGLOCALSET(nr_reg_local_set_double, NR_REG_TYPE_DOUBLE, double)
int
nr_reg_local_set_registry(NR_registry name)
{
return nr_reg_set(name, NR_REG_TYPE_REGISTRY, 0);
}
int
nr_reg_local_set_bytes(NR_registry name, unsigned char *data, size_t length)
{
return nr_reg_set_array(name, NR_REG_TYPE_BYTES, data, length);
}
int
nr_reg_local_set_string(NR_registry name, char *data)
{
return nr_reg_set_array(name, NR_REG_TYPE_STRING, (UCHAR*)data, strlen(data)+1);
}
int
nr_reg_local_del(NR_registry name)
{
int r, _status;
if ((r=nr_reg_is_valid(name)))
ABORT(r);
/* delete from NR_registry */
if ((r=nr_reg_local_iter(name, nr_reg_local_iter_delete, 0)))
ABORT(r);
if ((r=nr_reg_raise_event(name, NR_REG_CB_ACTION_DELETE)))
ABORT(r);
/* if deleting from the root, re-insert the root */
if (! strcasecmp(name, NR_TOP_LEVEL_REGISTRY)) {
if ((r=nr_reg_local_set_registry(NR_TOP_LEVEL_REGISTRY)))
ABORT(r);
}
_status=0;
abort:
r_log(NR_LOG_REGISTRY,
(_status ? LOG_INFO : LOG_INFO),
"delete of '%s' %s", name,
(_status ? "FAILED" : "succeeded"));
return(_status);
}
int
nr_reg_local_get_child_count(NR_registry parent, size_t *count)
{
int r, _status;
nr_registry_node *ignore1 = 0;
int ignore2;
if ((r=nr_reg_is_valid(parent)))
ABORT(r);
/* test to see whether it is present */
if ((r=nr_reg_fetch_node(parent, NR_REG_TYPE_REGISTRY, &ignore1, &ignore2)))
ABORT(r);
/* sanity check that there isn't any memory to free */
assert(ignore2 == 0);
*count = 0;
if ((r=nr_reg_local_iter(parent, nr_reg_local_count_children, count)))
ABORT(r);
_status=0;
abort:
return(_status);
}
int
nr_reg_local_get_children(NR_registry parent, NR_registry *data, size_t size, size_t *length)
{
int r, _status;
nr_reg_find_children_arg arg;
if ((r=nr_reg_is_valid(parent)))
ABORT(r);
arg.children = data;
arg.size = size;
arg.length = 0;
if ((r=nr_reg_local_iter(parent, nr_reg_local_find_children, (void*)&arg))) {
if (r == R_INTERRUPTED)
ABORT(R_BAD_ARGS);
else
ABORT(r);
}
assert(sizeof(*arg.children) == sizeof(NR_registry));
qsort(arg.children, arg.length, sizeof(*arg.children), nr_reg_local_compare_string);
*length = arg.length;
_status = 0;
abort:
return(_status);
}
int
nr_reg_local_fin(NR_registry name)
{
int r, _status;
if ((r=nr_reg_raise_event(name, NR_REG_CB_ACTION_FINAL)))
ABORT(r);
_status=0;
abort:
return(_status);
}
int
nr_reg_local_dump(int sorted)
{
int r, _status;
if ((r=nr_reg_local_iter(NR_TOP_LEVEL_REGISTRY, nr_reg_local_dump_print, 0)))
ABORT(r);
_status=0;
abort:
return(_status);
}
static nr_registry_module_vtbl nr_reg_local_vtbl = {
nr_reg_local_init,
nr_reg_local_get_char,
nr_reg_local_get_uchar,
nr_reg_local_get_int2,
nr_reg_local_get_uint2,
nr_reg_local_get_int4,
nr_reg_local_get_uint4,
nr_reg_local_get_int8,
nr_reg_local_get_uint8,
nr_reg_local_get_double,
nr_reg_local_get_registry,
nr_reg_local_get_bytes,
nr_reg_local_get_string,
nr_reg_local_get_length,
nr_reg_local_get_type,
nr_reg_local_set_char,
nr_reg_local_set_uchar,
nr_reg_local_set_int2,
nr_reg_local_set_uint2,
nr_reg_local_set_int4,
nr_reg_local_set_uint4,
nr_reg_local_set_int8,
nr_reg_local_set_uint8,
nr_reg_local_set_double,
nr_reg_local_set_registry,
nr_reg_local_set_bytes,
nr_reg_local_set_string,
nr_reg_local_del,
nr_reg_local_get_child_count,
nr_reg_local_get_children,
nr_reg_local_fin,
nr_reg_local_dump
};
static nr_registry_module nr_reg_local_module = { 0, &nr_reg_local_vtbl };
void *NR_REG_MODE_LOCAL = &nr_reg_local_module;