Line data Source code
1 : /*
2 : *
3 : * registry.c
4 : *
5 : * $Source: /Users/ekr/tmp/nrappkit-dump/nrappkit/src/registry/registry_local.c,v $
6 : * $Revision: 1.4 $
7 : * $Date: 2007/11/21 00:09:13 $
8 : *
9 : * Datastore for tracking configuration and related info.
10 : *
11 : *
12 : * Copyright (C) 2005, Network Resonance, Inc.
13 : * Copyright (C) 2006, Network Resonance, Inc.
14 : * All Rights Reserved
15 : *
16 : * Redistribution and use in source and binary forms, with or without
17 : * modification, are permitted provided that the following conditions
18 : * are met:
19 : *
20 : * 1. Redistributions of source code must retain the above copyright
21 : * notice, this list of conditions and the following disclaimer.
22 : * 2. Redistributions in binary form must reproduce the above copyright
23 : * notice, this list of conditions and the following disclaimer in the
24 : * documentation and/or other materials provided with the distribution.
25 : * 3. Neither the name of Network Resonance, Inc. nor the name of any
26 : * contributors to this software may be used to endorse or promote
27 : * products derived from this software without specific prior written
28 : * permission.
29 : *
30 : * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
31 : * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33 : * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
34 : * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
35 : * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
36 : * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
37 : * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
38 : * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
39 : * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
40 : * POSSIBILITY OF SUCH DAMAGE.
41 : *
42 : *
43 : */
44 :
45 : #include <assert.h>
46 : #include <string.h>
47 : #ifndef WIN32
48 : #include <strings.h>
49 : #include <sys/param.h>
50 : #include <netinet/in.h>
51 : #endif
52 : #ifdef OPENSSL
53 : #include <openssl/ssl.h>
54 : #endif
55 : #include <ctype.h>
56 : #include "registry.h"
57 : #include "registry_int.h"
58 : #include "registry_vtbl.h"
59 : #include "r_assoc.h"
60 : #include "nr_common.h"
61 : #include "r_log.h"
62 : #include "r_errors.h"
63 : #include "r_macros.h"
64 :
65 : /* if C were an object-oriented language, nr_scalar_registry_node and
66 : * nr_array_registry_node would subclass nr_registry_node, but it isn't
67 : * object-oriented language, so this is used in cases where the pointer
68 : * could be of either type */
69 : typedef struct nr_registry_node_ {
70 : unsigned char type;
71 : } nr_registry_node;
72 :
73 : typedef struct nr_scalar_registry_node_ {
74 : unsigned char type;
75 : union {
76 : char _char;
77 : UCHAR _uchar;
78 : INT2 _nr_int2;
79 : UINT2 _nr_uint2;
80 : INT4 _nr_int4;
81 : UINT4 _nr_uint4;
82 : INT8 _nr_int8;
83 : UINT8 _nr_uint8;
84 : double _double;
85 : } scalar;
86 : } nr_scalar_registry_node;
87 :
88 : /* string, bytes */
89 : typedef struct nr_array_registry_node_ {
90 : unsigned char type;
91 : struct {
92 : unsigned int length;
93 : unsigned char data[1];
94 : } array;
95 : } nr_array_registry_node;
96 :
97 : static int nr_reg_local_init(nr_registry_module *me);
98 : static int nr_reg_local_get_char(NR_registry name, char *data);
99 : static int nr_reg_local_get_uchar(NR_registry name, UCHAR *data);
100 : static int nr_reg_local_get_int2(NR_registry name, INT2 *data);
101 : static int nr_reg_local_get_uint2(NR_registry name, UINT2 *data);
102 : static int nr_reg_local_get_int4(NR_registry name, INT4 *data);
103 : static int nr_reg_local_get_uint4(NR_registry name, UINT4 *data);
104 : static int nr_reg_local_get_int8(NR_registry name, INT8 *data);
105 : static int nr_reg_local_get_uint8(NR_registry name, UINT8 *data);
106 : static int nr_reg_local_get_double(NR_registry name, double *data);
107 : static int nr_reg_local_get_registry(NR_registry name, NR_registry data);
108 : static int nr_reg_local_get_bytes(NR_registry name, UCHAR *data, size_t size, size_t *length);
109 : static int nr_reg_local_get_string(NR_registry name, char *data, size_t size);
110 : static int nr_reg_local_get_length(NR_registry name, size_t *len);
111 : static int nr_reg_local_get_type(NR_registry name, NR_registry_type type);
112 : static int nr_reg_local_set_char(NR_registry name, char data);
113 : static int nr_reg_local_set_uchar(NR_registry name, UCHAR data);
114 : static int nr_reg_local_set_int2(NR_registry name, INT2 data);
115 : static int nr_reg_local_set_uint2(NR_registry name, UINT2 data);
116 : static int nr_reg_local_set_int4(NR_registry name, INT4 data);
117 : static int nr_reg_local_set_uint4(NR_registry name, UINT4 data);
118 : static int nr_reg_local_set_int8(NR_registry name, INT8 data);
119 : static int nr_reg_local_set_uint8(NR_registry name, UINT8 data);
120 : static int nr_reg_local_set_double(NR_registry name, double data);
121 : static int nr_reg_local_set_registry(NR_registry name);
122 : static int nr_reg_local_set_bytes(NR_registry name, UCHAR *data, size_t length);
123 : static int nr_reg_local_set_string(NR_registry name, char *data);
124 : static int nr_reg_local_del(NR_registry name);
125 : static int nr_reg_local_get_child_count(NR_registry parent, size_t *count);
126 : static int nr_reg_local_get_children(NR_registry parent, NR_registry *data, size_t size, size_t *length);
127 : static int nr_reg_local_fin(NR_registry name);
128 : static int nr_reg_local_dump(int sorted);
129 : static int nr_reg_insert_node(char *name, void *node);
130 : static int nr_reg_change_node(char *name, void *node, void *old);
131 : static int nr_reg_get(char *name, int type, void *out);
132 : static int nr_reg_get_data(NR_registry name, nr_scalar_registry_node *node, void *out);
133 : static int nr_reg_get_array(char *name, unsigned char type, UCHAR *out, size_t size, size_t *length);
134 : static int nr_reg_set(char *name, int type, void *data);
135 : static int nr_reg_set_array(char *name, unsigned char type, UCHAR *data, size_t length);
136 : static int nr_reg_set_parent_registries(char *name);
137 :
138 : /* make these static OLD_REGISTRY */
139 : #if 0
140 : static int nr_reg_fetch_node(char *name, unsigned char type, nr_registry_node **node, int *free_node);
141 : static char *nr_reg_alloc_node_data(char *name, nr_registry_node *node, int *freeit);
142 : #else
143 : int nr_reg_fetch_node(char *name, unsigned char type, nr_registry_node **node, int *free_node);
144 : char *nr_reg_alloc_node_data(char *name, nr_registry_node *node, int *freeit);
145 : #endif
146 : static int nr_reg_rfree(void *ptr);
147 : #if 0 /* Unused currently */
148 : static int nr_reg_noop(void *ptr);
149 : #endif
150 : static int nr_reg_compute_length(char *name, nr_registry_node *node, size_t *length);
151 : char *nr_reg_action_name(int action);
152 :
153 : /* the registry, containing mappings like "foo.bar.baz" to registry
154 : * nodes, which are either of type nr_scalar_registry_node or
155 : * nr_array_registry_node */
156 : static r_assoc *nr_registry = 0;
157 :
158 : #if 0 /* Unused currently */
159 : static nr_array_registry_node nr_top_level_node;
160 : #endif
161 :
162 : typedef struct nr_reg_find_children_arg_ {
163 : size_t size;
164 : NR_registry *children;
165 : size_t length;
166 : } nr_reg_find_children_arg;
167 :
168 : static int nr_reg_local_iter(char *prefix, int (*action)(void *ptr, r_assoc_iterator *iter, char *prefix, char *name, nr_registry_node *node), void *ptr);
169 : static int nr_reg_local_iter_delete(void *ptr, r_assoc_iterator *iter, char *prefix, char *name, nr_registry_node *node);
170 : static int nr_reg_local_find_children(void *ptr, r_assoc_iterator *iter, char *prefix, char *name, nr_registry_node *node);
171 : static int nr_reg_local_count_children(void *ptr, r_assoc_iterator *iter, char *prefix, char *name, nr_registry_node *node);
172 : static int nr_reg_local_dump_print(void *ptr, r_assoc_iterator *iter, char *prefix, char *name, nr_registry_node *node);
173 :
174 :
175 :
176 : int
177 0 : 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)
178 : {
179 : int r, _status;
180 : r_assoc_iterator iter;
181 : char *name;
182 : int namel;
183 : nr_registry_node *node;
184 : int prefixl;
185 :
186 0 : if (prefix == 0)
187 0 : ABORT(R_INTERNAL);
188 :
189 0 : if ((r=r_assoc_init_iter(nr_registry, &iter)))
190 0 : ABORT(r);
191 :
192 0 : prefixl = strlen(prefix);
193 :
194 : for (;;) {
195 0 : if ((r=r_assoc_iter(&iter, (void*)&name, &namel, (void*)&node))) {
196 0 : if (r == R_EOD)
197 0 : break;
198 : else
199 0 : ABORT(r);
200 : }
201 :
202 : /* subtract to remove the '\0' character from the string length */
203 0 : --namel;
204 :
205 : /* sanity check that the name is null-terminated */
206 0 : assert(namel >= 0);
207 0 : assert(name[namel] == '\0');
208 :
209 0 : if (namel < 0 || name[namel] != '\0' || node == 0)
210 : break;
211 :
212 : /* 3 cases where action will be called:
213 : * 1) prefix == ""
214 : * 2) prefix == name
215 : * 3) name == prefix + '.'
216 : */
217 0 : if (prefixl == 0
218 0 : || ((namel == prefixl || (namel > prefixl && name[prefixl] == '.'))
219 0 : && !strncmp(prefix, name, prefixl))) {
220 0 : if ((r=action(ptr, &iter, prefix, name, node)))
221 0 : ABORT(r);
222 : }
223 : }
224 :
225 0 : _status=0;
226 : abort:
227 :
228 0 : return(_status);
229 : }
230 :
231 : int
232 0 : nr_reg_local_iter_delete(void *ptr, r_assoc_iterator *iter, char *prefix, char *name, nr_registry_node *node)
233 : {
234 : int r, _status;
235 :
236 0 : if ((r=r_assoc_iter_delete(iter)))
237 0 : ABORT(r);
238 :
239 0 : _status=0;
240 : abort:
241 0 : return(_status);
242 : }
243 :
244 : int
245 0 : nr_reg_local_find_children(void *ptr, r_assoc_iterator *iter, char *prefix, char *name, nr_registry_node *node)
246 : {
247 : int _status;
248 0 : int prefixl = strlen(prefix);
249 : char *dot;
250 0 : nr_reg_find_children_arg *arg = (void*)ptr;
251 :
252 : assert(sizeof(*(arg->children)) == sizeof(NR_registry));
253 :
254 : /* only grovel through immediate children */
255 0 : if (prefixl == 0 || name[prefixl] == '.') {
256 0 : if (name[prefixl] != '\0') {
257 0 : dot = strchr(&name[prefixl+1], '.');
258 0 : if (dot == 0) {
259 0 : strncpy(arg->children[arg->length], name, sizeof(NR_registry)-1);
260 0 : ++arg->length;
261 :
262 : /* only grab as many as there are room for */
263 0 : if (arg->length >= arg->size)
264 0 : ABORT(R_INTERRUPTED);
265 : }
266 : }
267 : }
268 :
269 0 : _status = 0;
270 : abort:
271 0 : return _status;
272 : }
273 :
274 : int
275 0 : nr_reg_local_count_children(void *ptr, r_assoc_iterator *iter, char *prefix, char *name, nr_registry_node *node)
276 : {
277 0 : int prefixl = strlen(prefix);
278 : char *dot;
279 :
280 : /* only count children */
281 0 : if (name[prefixl] == '.') {
282 0 : dot = strchr(&name[prefixl+1], '.');
283 0 : if (dot == 0)
284 0 : ++(*(unsigned int *)ptr);
285 : }
286 0 : else if (name[0] != '\0') {
287 0 : if (prefixl == 0)
288 0 : ++(*(unsigned int *)ptr);
289 : }
290 :
291 0 : return 0;
292 : }
293 :
294 : int
295 0 : nr_reg_local_dump_print(void *ptr, r_assoc_iterator *iter, char *prefix, char *name, nr_registry_node *node)
296 : {
297 : int _status;
298 0 : int freeit = 0;
299 : char *data;
300 :
301 : /* only print leaf nodes */
302 0 : if (node->type != NR_REG_TYPE_REGISTRY) {
303 0 : data = nr_reg_alloc_node_data(name, node, &freeit);
304 0 : if (ptr)
305 0 : fprintf((FILE*)ptr, "%s: %s\n", name, data);
306 : else
307 0 : r_log(NR_LOG_REGISTRY, LOG_INFO, "%s: %s", name, data);
308 0 : if (freeit)
309 0 : RFREE(data);
310 : }
311 :
312 0 : _status=0;
313 : //abort:
314 0 : return(_status);
315 : }
316 :
317 :
318 : #if 0 /* Unused currently */
319 : int
320 : nr_reg_noop(void *ptr)
321 : {
322 : return 0;
323 : }
324 : #endif
325 :
326 : int
327 0 : nr_reg_rfree(void *ptr)
328 : {
329 0 : RFREE(ptr);
330 0 : return 0;
331 : }
332 :
333 : int
334 0 : nr_reg_fetch_node(char *name, unsigned char type, nr_registry_node **node, int *free_node)
335 : {
336 : int r, _status;
337 :
338 0 : *node = 0;
339 0 : *free_node = 0;
340 :
341 0 : if ((r=nr_reg_is_valid(name)))
342 0 : ABORT(r);
343 :
344 0 : if ((r=r_assoc_fetch(nr_registry, name, strlen(name)+1, (void*)node)))
345 0 : ABORT(r);
346 :
347 0 : if ((*node)->type != type)
348 0 : ABORT(R_FAILED);
349 :
350 0 : _status=0;
351 : abort:
352 0 : if (_status) {
353 0 : if (*node)
354 0 : r_log(NR_LOG_REGISTRY, LOG_DEBUG, "Couldn't fetch node '%s' ('%s'), found '%s' instead",
355 0 : name, nr_reg_type_name(type), nr_reg_type_name((*node)->type));
356 : else
357 0 : r_log(NR_LOG_REGISTRY, LOG_DEBUG, "Couldn't fetch node '%s' ('%s')",
358 : name, nr_reg_type_name(type));
359 : }
360 : else {
361 0 : r_log(NR_LOG_REGISTRY, LOG_DEBUG, "Fetched node '%s' ('%s')",
362 : name, nr_reg_type_name(type));
363 : }
364 0 : return(_status);
365 : }
366 :
367 : int
368 0 : nr_reg_insert_node(char *name, void *node)
369 : {
370 : int r, _status;
371 :
372 0 : if ((r=nr_reg_is_valid(name)))
373 0 : ABORT(r);
374 :
375 : /* since the registry application is not multi-threaded, a node being
376 : * inserted should always be a new node because the registry app must
377 : * have looked for a node with this key but not found it, so it is
378 : * being created/inserted now using R_ASSOC_NEW */
379 0 : if ((r=r_assoc_insert(nr_registry, name, strlen(name)+1, node, 0, nr_reg_rfree, R_ASSOC_NEW)))
380 0 : ABORT(r);
381 :
382 0 : if ((r=nr_reg_set_parent_registries(name)))
383 0 : ABORT(r);
384 :
385 0 : if ((r=nr_reg_raise_event(name, NR_REG_CB_ACTION_ADD)))
386 0 : ABORT(r);
387 :
388 0 : _status=0;
389 : abort:
390 0 : if (r_logging(NR_LOG_REGISTRY, LOG_INFO)) {
391 : int freeit;
392 0 : char *data = nr_reg_alloc_node_data(name, (void*)node, &freeit);
393 0 : r_log(NR_LOG_REGISTRY, LOG_INFO,
394 : "insert '%s' (%s) %s: %s", name,
395 0 : nr_reg_type_name(((nr_registry_node*)node)->type),
396 : (_status ? "FAILED" : "succeeded"), data);
397 0 : if (freeit)
398 0 : RFREE(data);
399 : }
400 0 : return(_status);
401 : }
402 :
403 : int
404 0 : nr_reg_change_node(char *name, void *node, void *old)
405 : {
406 : int r, _status;
407 :
408 0 : if ((r=nr_reg_is_valid(name)))
409 0 : ABORT(r);
410 :
411 0 : if (old != node) {
412 0 : if ((r=r_assoc_insert(nr_registry, name, strlen(name)+1, node, 0, nr_reg_rfree, R_ASSOC_REPLACE)))
413 0 : ABORT(r);
414 : }
415 :
416 0 : if ((r=nr_reg_raise_event(name, NR_REG_CB_ACTION_CHANGE)))
417 0 : ABORT(r);
418 :
419 0 : _status=0;
420 : abort:
421 0 : if (r_logging(NR_LOG_REGISTRY, LOG_INFO)) {
422 : int freeit;
423 0 : char *data = nr_reg_alloc_node_data(name, (void*)node, &freeit);
424 0 : r_log(NR_LOG_REGISTRY, LOG_INFO,
425 : "change '%s' (%s) %s: %s", name,
426 0 : nr_reg_type_name(((nr_registry_node*)node)->type),
427 : (_status ? "FAILED" : "succeeded"), data);
428 0 : if (freeit)
429 0 : RFREE(data);
430 : }
431 0 : return(_status);
432 : }
433 :
434 : char *
435 0 : nr_reg_alloc_node_data(char *name, nr_registry_node *node, int *freeit)
436 : {
437 0 : char *s = 0;
438 : int len;
439 0 : int alloc = 0;
440 : unsigned int i;
441 :
442 0 : *freeit = 0;
443 :
444 0 : switch (node->type) {
445 : default:
446 0 : alloc = 100; /* plenty of room for any of the scalar types */
447 0 : break;
448 : case NR_REG_TYPE_REGISTRY:
449 0 : alloc = strlen(name) + 1;
450 0 : break;
451 : case NR_REG_TYPE_BYTES:
452 0 : alloc = (2 * ((nr_array_registry_node*)node)->array.length) + 1;
453 0 : break;
454 : case NR_REG_TYPE_STRING:
455 0 : alloc = 0;
456 0 : break;
457 : }
458 :
459 0 : if (alloc > 0) {
460 0 : s = (void*)RMALLOC(alloc);
461 0 : if (!s)
462 0 : return "";
463 :
464 0 : *freeit = 1;
465 : }
466 :
467 0 : len = alloc;
468 :
469 0 : switch (node->type) {
470 : case NR_REG_TYPE_CHAR:
471 0 : i = ((nr_scalar_registry_node*)node)->scalar._char;
472 0 : if (isprint(i) && ! isspace(i))
473 0 : snprintf(s, len, "%c", (char)i);
474 : else
475 0 : snprintf(s, len, "\\%03o", (char)i);
476 0 : break;
477 : case NR_REG_TYPE_UCHAR:
478 0 : snprintf(s, len, "0x%02x", ((nr_scalar_registry_node*)node)->scalar._uchar);
479 0 : break;
480 : case NR_REG_TYPE_INT2:
481 0 : snprintf(s, len, "%d", ((nr_scalar_registry_node*)node)->scalar._nr_int2);
482 0 : break;
483 : case NR_REG_TYPE_UINT2:
484 0 : snprintf(s, len, "%u", ((nr_scalar_registry_node*)node)->scalar._nr_uint2);
485 0 : break;
486 : case NR_REG_TYPE_INT4:
487 0 : snprintf(s, len, "%d", ((nr_scalar_registry_node*)node)->scalar._nr_int4);
488 0 : break;
489 : case NR_REG_TYPE_UINT4:
490 0 : snprintf(s, len, "%u", ((nr_scalar_registry_node*)node)->scalar._nr_uint4);
491 0 : break;
492 : case NR_REG_TYPE_INT8:
493 0 : snprintf(s, len, "%lld", ((nr_scalar_registry_node*)node)->scalar._nr_int8);
494 0 : break;
495 : case NR_REG_TYPE_UINT8:
496 0 : snprintf(s, len, "%llu", ((nr_scalar_registry_node*)node)->scalar._nr_uint8);
497 0 : break;
498 : case NR_REG_TYPE_DOUBLE:
499 0 : snprintf(s, len, "%#f", ((nr_scalar_registry_node*)node)->scalar._double);
500 0 : break;
501 : case NR_REG_TYPE_REGISTRY:
502 0 : snprintf(s, len, "%s", name);
503 0 : break;
504 : case NR_REG_TYPE_BYTES:
505 0 : for (i = 0; i < ((nr_array_registry_node*)node)->array.length; ++i) {
506 0 : sprintf(&s[2*i], "%02x", ((nr_array_registry_node*)node)->array.data[i]);
507 : }
508 0 : break;
509 : case NR_REG_TYPE_STRING:
510 0 : s = (char*)((nr_array_registry_node*)node)->array.data;
511 0 : break;
512 : default:
513 0 : assert(0); /* bad value */
514 : *freeit = 0;
515 : s = "";
516 : break;
517 : }
518 :
519 0 : return s;
520 : }
521 :
522 : int
523 0 : nr_reg_get(char *name, int type, void *out)
524 : {
525 : int r, _status;
526 0 : nr_scalar_registry_node *node = 0;
527 0 : int free_node = 0;
528 :
529 0 : if ((r=nr_reg_fetch_node(name, type, (void*)&node, &free_node)))
530 0 : ABORT(r);
531 :
532 0 : if ((r=nr_reg_get_data(name, node, out)))
533 0 : ABORT(r);
534 :
535 0 : _status=0;
536 : abort:
537 0 : if (free_node) RFREE(node);
538 0 : return(_status);
539 : }
540 :
541 : int
542 0 : nr_reg_get_data(NR_registry name, nr_scalar_registry_node *node, void *out)
543 : {
544 : int _status;
545 :
546 0 : switch (node->type) {
547 : case NR_REG_TYPE_CHAR:
548 0 : *(char*)out = node->scalar._char;
549 0 : break;
550 : case NR_REG_TYPE_UCHAR:
551 0 : *(UCHAR*)out = node->scalar._uchar;
552 0 : break;
553 : case NR_REG_TYPE_INT2:
554 0 : *(INT2*)out = node->scalar._nr_int2;
555 0 : break;
556 : case NR_REG_TYPE_UINT2:
557 0 : *(UINT2*)out = node->scalar._nr_uint2;
558 0 : break;
559 : case NR_REG_TYPE_INT4:
560 0 : *(INT4*)out = node->scalar._nr_int4;
561 0 : break;
562 : case NR_REG_TYPE_UINT4:
563 0 : *(UINT4*)out = node->scalar._nr_uint4;
564 0 : break;
565 : case NR_REG_TYPE_INT8:
566 0 : *(INT8*)out = node->scalar._nr_int8;
567 0 : break;
568 : case NR_REG_TYPE_UINT8:
569 0 : *(UINT8*)out = node->scalar._nr_uint8;
570 0 : break;
571 : case NR_REG_TYPE_DOUBLE:
572 0 : *(double*)out = node->scalar._double;
573 0 : break;
574 : default:
575 0 : ABORT(R_INTERNAL);
576 : break;
577 : }
578 :
579 0 : _status=0;
580 : abort:
581 0 : return(_status);
582 : }
583 :
584 : int
585 0 : nr_reg_get_array(char *name, unsigned char type, unsigned char *out, size_t size, size_t *length)
586 : {
587 : int r, _status;
588 0 : nr_array_registry_node *node = 0;
589 0 : int free_node = 0;
590 :
591 0 : if ((r=nr_reg_fetch_node(name, type, (void*)&node, &free_node)))
592 0 : ABORT(r);
593 :
594 0 : if (size < node->array.length)
595 0 : ABORT(R_BAD_ARGS);
596 :
597 0 : if (out != 0)
598 0 : memcpy(out, node->array.data, node->array.length);
599 0 : if (length != 0)
600 0 : *length = node->array.length;
601 :
602 0 : _status=0;
603 : abort:
604 0 : if (node && free_node) RFREE(node);
605 0 : return(_status);
606 : }
607 :
608 : int
609 0 : nr_reg_set(char *name, int type, void *data)
610 : {
611 : int r, _status;
612 0 : nr_scalar_registry_node *node = 0;
613 0 : int create_node = 0;
614 0 : int changed = 0;
615 0 : int free_node = 0;
616 :
617 0 : if ((r=nr_reg_fetch_node(name, type, (void*)&node, &free_node)))
618 0 : if (r == R_NOT_FOUND) {
619 0 : create_node = 1;
620 0 : free_node = 1;
621 : }
622 : else
623 0 : ABORT(r);
624 :
625 0 : if (create_node) {
626 0 : if (!(node=(void*)RCALLOC(sizeof(nr_scalar_registry_node))))
627 0 : ABORT(R_NO_MEMORY);
628 :
629 0 : node->type = type;
630 : }
631 : else {
632 0 : if (node->type != type)
633 0 : ABORT(R_BAD_ARGS);
634 : }
635 :
636 0 : switch (type) {
637 : #define CASE(TYPE, _name, type) \
638 : case TYPE: \
639 : if (node->scalar._name != *(type*)data) { \
640 : node->scalar._name = *(type*)data; \
641 : if (! create_node) \
642 : changed = 1; \
643 : } \
644 : break;
645 0 : CASE(NR_REG_TYPE_CHAR, _char, char)
646 0 : CASE(NR_REG_TYPE_UCHAR, _uchar, UCHAR)
647 0 : CASE(NR_REG_TYPE_INT2, _nr_int2, INT2)
648 0 : CASE(NR_REG_TYPE_UINT2, _nr_uint2, UINT2)
649 0 : CASE(NR_REG_TYPE_INT4, _nr_int4, INT4)
650 0 : CASE(NR_REG_TYPE_UINT4, _nr_uint4, UINT4)
651 0 : CASE(NR_REG_TYPE_INT8, _nr_int8, INT8)
652 0 : CASE(NR_REG_TYPE_UINT8, _nr_uint8, UINT8)
653 0 : CASE(NR_REG_TYPE_DOUBLE, _double, double)
654 : #undef CASE
655 :
656 : case NR_REG_TYPE_REGISTRY:
657 : /* do nothing */
658 0 : break;
659 :
660 : default:
661 0 : ABORT(R_INTERNAL);
662 : break;
663 : }
664 :
665 0 : if (create_node) {
666 0 : if ((r=nr_reg_insert_node(name, node)))
667 0 : ABORT(r);
668 0 : free_node = 0;
669 : }
670 : else {
671 0 : if (changed) {
672 0 : if ((r=nr_reg_change_node(name, node, node)))
673 0 : ABORT(r);
674 0 : free_node = 0;
675 : }
676 : }
677 :
678 0 : _status=0;
679 : abort:
680 0 : if (_status) {
681 0 : if (node && free_node) RFREE(node);
682 : }
683 0 : return(_status);
684 : }
685 :
686 : int
687 0 : nr_reg_set_array(char *name, unsigned char type, UCHAR *data, size_t length)
688 : {
689 : int r, _status;
690 0 : nr_array_registry_node *old = 0;
691 0 : nr_array_registry_node *node = 0;
692 0 : int free_node = 0;
693 0 : int added = 0;
694 0 : int changed = 0;
695 :
696 0 : if ((r=nr_reg_fetch_node(name, type, (void*)&old, &free_node))) {
697 0 : if (r != R_NOT_FOUND)
698 0 : ABORT(r);
699 : }
700 : else {
701 0 : assert(free_node == 0);
702 : }
703 :
704 0 : if (old) {
705 0 : if (old->type != type)
706 0 : ABORT(R_BAD_ARGS);
707 :
708 0 : if (old->array.length != length
709 0 : || memcmp(old->array.data, data, length)) {
710 0 : changed = 1;
711 :
712 0 : if (old->array.length < length) {
713 0 : if (!(node=(void*)RCALLOC(sizeof(nr_array_registry_node)+length)))
714 0 : ABORT(R_NO_MEMORY);
715 : }
716 : else {
717 0 : node = old;
718 : }
719 : }
720 : }
721 : else {
722 0 : if (!(node=(void*)RCALLOC(sizeof(nr_array_registry_node)+length)))
723 0 : ABORT(R_NO_MEMORY);
724 :
725 0 : added = 1;
726 : }
727 :
728 0 : if (added || changed) {
729 0 : node->type = type;
730 0 : node->array.length = length;
731 0 : memcpy(node->array.data, data, length);
732 : }
733 :
734 0 : if (added) {
735 0 : if ((r=nr_reg_insert_node(name, node)))
736 0 : ABORT(r);
737 : }
738 0 : else if (changed) {
739 0 : if ((r=nr_reg_change_node(name, node, old)))
740 0 : ABORT(r);
741 : }
742 :
743 0 : _status=0;
744 : abort:
745 0 : return(_status);
746 : }
747 :
748 : int
749 0 : nr_reg_set_parent_registries(char *name)
750 : {
751 : int r, _status;
752 0 : char *parent = 0;
753 : char *dot;
754 :
755 0 : if ((parent = r_strdup(name)) == 0)
756 0 : ABORT(R_NO_MEMORY);
757 :
758 0 : if ((dot = strrchr(parent, '.')) != 0) {
759 0 : *dot = '\0';
760 0 : if ((r=NR_reg_set_registry(parent)))
761 0 : ABORT(r);
762 : }
763 :
764 0 : _status=0;
765 : abort:
766 0 : if (parent) RFREE(parent);
767 0 : return(_status);
768 : }
769 :
770 :
771 :
772 :
773 :
774 : /* NON-STATIC METHODS */
775 :
776 : int
777 0 : nr_reg_is_valid(NR_registry name)
778 : {
779 : int _status;
780 : unsigned int length;
781 : unsigned int i;
782 :
783 0 : if (name == 0)
784 0 : ABORT(R_BAD_ARGS);
785 :
786 : /* make sure the key is null-terminated */
787 0 : if (memchr(name, '\0', sizeof(NR_registry)) == 0)
788 0 : ABORT(R_BAD_ARGS);
789 :
790 0 : length = strlen(name);
791 :
792 : /* cannot begin or end with a period */
793 0 : if (name[0] == '.')
794 0 : ABORT(R_BAD_ARGS);
795 0 : if (strlen(name) > 0 && name[length-1] == '.')
796 0 : ABORT(R_BAD_ARGS);
797 :
798 : /* all characters cannot be space, and must be printable and not / */
799 0 : for (i = 0; i < length; ++i) {
800 0 : if (isspace(name[i]) || ! (isprint(name[i]) || name[i] == '/'))
801 0 : ABORT(R_BAD_ARGS);
802 : }
803 :
804 0 : _status=0;
805 : abort:
806 0 : if (_status) {
807 0 : r_log(NR_LOG_REGISTRY, LOG_DEBUG, "invalid name '%s'", name);
808 : }
809 0 : return(_status);
810 : }
811 :
812 :
813 : int
814 0 : nr_reg_compute_length(char *name, nr_registry_node *in, size_t *length)
815 : {
816 : int _status;
817 0 : nr_array_registry_node *node = (nr_array_registry_node*)in;
818 :
819 0 : switch (node->type) {
820 : case NR_REG_TYPE_STRING:
821 0 : *length = node->array.length - 1;
822 0 : break;
823 : case NR_REG_TYPE_BYTES:
824 0 : *length = node->array.length;
825 0 : break;
826 : case NR_REG_TYPE_CHAR:
827 0 : *length = sizeof(char);
828 0 : break;
829 : case NR_REG_TYPE_UCHAR:
830 0 : *length = sizeof(UCHAR);
831 0 : break;
832 : case NR_REG_TYPE_INT2:
833 : case NR_REG_TYPE_UINT2:
834 0 : *length = 2;
835 0 : break;
836 : case NR_REG_TYPE_INT4:
837 : case NR_REG_TYPE_UINT4:
838 0 : *length = 4;
839 0 : break;
840 : case NR_REG_TYPE_INT8:
841 : case NR_REG_TYPE_UINT8:
842 0 : *length = 8;
843 0 : break;
844 : case NR_REG_TYPE_DOUBLE:
845 0 : *length = sizeof(double);
846 0 : break;
847 : case NR_REG_TYPE_REGISTRY:
848 0 : *length = strlen(name);
849 0 : break;
850 : default:
851 0 : ABORT(R_INTERNAL);
852 : break;
853 : }
854 :
855 0 : _status=0;
856 : abort:
857 0 : return(_status);
858 : }
859 :
860 :
861 : /* VTBL METHODS */
862 :
863 : int
864 0 : nr_reg_local_init(nr_registry_module *me)
865 : {
866 : int r, _status;
867 :
868 0 : if (nr_registry == 0) {
869 0 : if ((r=r_assoc_create(&nr_registry, r_assoc_crc32_hash_compute, 12)))
870 0 : ABORT(r);
871 :
872 0 : if ((r=nr_reg_cb_init()))
873 0 : ABORT(r);
874 :
875 : /* make sure NR_TOP_LEVEL_REGISTRY always exists */
876 0 : if ((r=nr_reg_local_set_registry(NR_TOP_LEVEL_REGISTRY)))
877 0 : ABORT(r);
878 : }
879 :
880 0 : _status=0;
881 : abort:
882 0 : return(_status);
883 : }
884 :
885 : #define NRREGGET(func, TYPE, type) \
886 : int \
887 : func(NR_registry name, type *out) \
888 : { \
889 : return nr_reg_get(name, TYPE, out); \
890 : }
891 :
892 0 : NRREGGET(nr_reg_local_get_char, NR_REG_TYPE_CHAR, char)
893 0 : NRREGGET(nr_reg_local_get_uchar, NR_REG_TYPE_UCHAR, UCHAR)
894 0 : NRREGGET(nr_reg_local_get_int2, NR_REG_TYPE_INT2, INT2)
895 0 : NRREGGET(nr_reg_local_get_uint2, NR_REG_TYPE_UINT2, UINT2)
896 0 : NRREGGET(nr_reg_local_get_int4, NR_REG_TYPE_INT4, INT4)
897 0 : NRREGGET(nr_reg_local_get_uint4, NR_REG_TYPE_UINT4, UINT4)
898 0 : NRREGGET(nr_reg_local_get_int8, NR_REG_TYPE_INT8, INT8)
899 0 : NRREGGET(nr_reg_local_get_uint8, NR_REG_TYPE_UINT8, UINT8)
900 0 : NRREGGET(nr_reg_local_get_double, NR_REG_TYPE_DOUBLE, double)
901 :
902 : int
903 0 : nr_reg_local_get_registry(NR_registry name, NR_registry out)
904 : {
905 : int r, _status;
906 0 : nr_scalar_registry_node *node = 0;
907 0 : int free_node = 0;
908 :
909 0 : if ((r=nr_reg_fetch_node(name, NR_REG_TYPE_REGISTRY, (void*)&node, &free_node)))
910 0 : ABORT(r);
911 :
912 0 : strncpy(out, name, sizeof(NR_registry));
913 :
914 0 : _status=0;
915 : abort:
916 0 : if (free_node) RFREE(node);
917 0 : return(_status);
918 :
919 : }
920 :
921 : int
922 0 : nr_reg_local_get_bytes(NR_registry name, UCHAR *out, size_t size, size_t *length)
923 : {
924 0 : return nr_reg_get_array(name, NR_REG_TYPE_BYTES, out, size, length);
925 : }
926 :
927 : int
928 0 : nr_reg_local_get_string(NR_registry name, char *out, size_t size)
929 : {
930 0 : return nr_reg_get_array(name, NR_REG_TYPE_STRING, (UCHAR*)out, size, 0);
931 : }
932 :
933 : int
934 0 : nr_reg_local_get_length(NR_registry name, size_t *length)
935 : {
936 : int r, _status;
937 0 : nr_registry_node *node = 0;
938 :
939 0 : if ((r=nr_reg_is_valid(name)))
940 0 : ABORT(r);
941 :
942 0 : if ((r=r_assoc_fetch(nr_registry, name, strlen(name)+1, (void*)&node)))
943 0 : ABORT(r);
944 :
945 0 : if ((r=nr_reg_compute_length(name, node, length)))
946 0 : ABORT(r);
947 :
948 0 : _status=0;
949 : abort:
950 0 : return(_status);
951 : }
952 :
953 : int
954 0 : nr_reg_local_get_type(NR_registry name, NR_registry_type type)
955 : {
956 : int r, _status;
957 0 : nr_registry_node *node = 0;
958 : char *str;
959 :
960 0 : if ((r=nr_reg_is_valid(name)))
961 0 : ABORT(r);
962 :
963 0 : if ((r=r_assoc_fetch(nr_registry, name, strlen(name)+1, (void*)&node)))
964 0 : ABORT(r);
965 :
966 0 : str = nr_reg_type_name(node->type);
967 0 : if (! str)
968 0 : ABORT(R_BAD_ARGS);
969 :
970 0 : strncpy(type, str, sizeof(NR_registry_type));
971 :
972 0 : _status=0;
973 : abort:
974 0 : return(_status);
975 : }
976 :
977 :
978 : #define NRREGSET(func, TYPE, type) \
979 : int \
980 : func(NR_registry name, type data) \
981 : { \
982 : return nr_reg_set(name, TYPE, &data); \
983 : }
984 :
985 0 : NRREGSET(nr_reg_local_set_char, NR_REG_TYPE_CHAR, char)
986 0 : NRREGSET(nr_reg_local_set_uchar, NR_REG_TYPE_UCHAR, UCHAR)
987 0 : NRREGSET(nr_reg_local_set_int2, NR_REG_TYPE_INT2, INT2)
988 0 : NRREGSET(nr_reg_local_set_uint2, NR_REG_TYPE_UINT2, UINT2)
989 0 : NRREGSET(nr_reg_local_set_int4, NR_REG_TYPE_INT4, INT4)
990 0 : NRREGSET(nr_reg_local_set_uint4, NR_REG_TYPE_UINT4, UINT4)
991 0 : NRREGSET(nr_reg_local_set_int8, NR_REG_TYPE_INT8, INT8)
992 0 : NRREGSET(nr_reg_local_set_uint8, NR_REG_TYPE_UINT8, UINT8)
993 0 : NRREGSET(nr_reg_local_set_double, NR_REG_TYPE_DOUBLE, double)
994 :
995 : int
996 0 : nr_reg_local_set_registry(NR_registry name)
997 : {
998 0 : return nr_reg_set(name, NR_REG_TYPE_REGISTRY, 0);
999 : }
1000 :
1001 : int
1002 0 : nr_reg_local_set_bytes(NR_registry name, unsigned char *data, size_t length)
1003 : {
1004 0 : return nr_reg_set_array(name, NR_REG_TYPE_BYTES, data, length);
1005 : }
1006 :
1007 : int
1008 0 : nr_reg_local_set_string(NR_registry name, char *data)
1009 : {
1010 0 : return nr_reg_set_array(name, NR_REG_TYPE_STRING, (UCHAR*)data, strlen(data)+1);
1011 : }
1012 :
1013 : int
1014 0 : nr_reg_local_del(NR_registry name)
1015 : {
1016 : int r, _status;
1017 :
1018 0 : if ((r=nr_reg_is_valid(name)))
1019 0 : ABORT(r);
1020 :
1021 : /* delete from NR_registry */
1022 0 : if ((r=nr_reg_local_iter(name, nr_reg_local_iter_delete, 0)))
1023 0 : ABORT(r);
1024 :
1025 0 : if ((r=nr_reg_raise_event(name, NR_REG_CB_ACTION_DELETE)))
1026 0 : ABORT(r);
1027 :
1028 : /* if deleting from the root, re-insert the root */
1029 0 : if (! strcasecmp(name, NR_TOP_LEVEL_REGISTRY)) {
1030 0 : if ((r=nr_reg_local_set_registry(NR_TOP_LEVEL_REGISTRY)))
1031 0 : ABORT(r);
1032 : }
1033 :
1034 0 : _status=0;
1035 : abort:
1036 0 : r_log(NR_LOG_REGISTRY,
1037 : (_status ? LOG_INFO : LOG_INFO),
1038 : "delete of '%s' %s", name,
1039 : (_status ? "FAILED" : "succeeded"));
1040 0 : return(_status);
1041 : }
1042 :
1043 : int
1044 0 : nr_reg_local_get_child_count(char *parent, size_t *count)
1045 : {
1046 : int r, _status;
1047 : nr_registry_node *ignore1;
1048 : int ignore2;
1049 :
1050 :
1051 0 : if ((r=nr_reg_is_valid(parent)))
1052 0 : ABORT(r);
1053 :
1054 : /* test to see whether it is present */
1055 0 : if ((r=nr_reg_fetch_node(parent, NR_REG_TYPE_REGISTRY, &ignore1, &ignore2)))
1056 0 : ABORT(r);
1057 :
1058 : /* sanity check that there isn't any memory to free */
1059 0 : assert(ignore2 == 0);
1060 :
1061 0 : *count = 0;
1062 :
1063 0 : if ((r=nr_reg_local_iter(parent, nr_reg_local_count_children, count)))
1064 0 : ABORT(r);
1065 :
1066 0 : _status=0;
1067 : abort:
1068 0 : return(_status);
1069 : }
1070 :
1071 : int
1072 0 : nr_reg_local_get_children(NR_registry parent, NR_registry *data, size_t size, size_t *length)
1073 : {
1074 : int r, _status;
1075 : nr_reg_find_children_arg arg;
1076 :
1077 0 : if ((r=nr_reg_is_valid(parent)))
1078 0 : ABORT(r);
1079 :
1080 0 : arg.children = data;
1081 0 : arg.size = size;
1082 0 : arg.length = 0;
1083 :
1084 0 : if ((r=nr_reg_local_iter(parent, nr_reg_local_find_children, (void*)&arg))) {
1085 0 : if (r == R_INTERRUPTED)
1086 0 : ABORT(R_BAD_ARGS);
1087 : else
1088 0 : ABORT(r);
1089 : }
1090 :
1091 : assert(sizeof(*arg.children) == sizeof(NR_registry));
1092 0 : qsort(arg.children, arg.length, sizeof(*arg.children), (void*)strcasecmp);
1093 :
1094 0 : *length = arg.length;
1095 :
1096 0 : _status = 0;
1097 : abort:
1098 0 : return(_status);
1099 : }
1100 :
1101 : int
1102 0 : nr_reg_local_fin(NR_registry name)
1103 : {
1104 : int r, _status;
1105 :
1106 0 : if ((r=nr_reg_raise_event(name, NR_REG_CB_ACTION_FINAL)))
1107 0 : ABORT(r);
1108 :
1109 0 : _status=0;
1110 : abort:
1111 0 : return(_status);
1112 : }
1113 :
1114 : int
1115 0 : nr_reg_local_dump(int sorted)
1116 : {
1117 : int r, _status;
1118 :
1119 0 : if ((r=nr_reg_local_iter(NR_TOP_LEVEL_REGISTRY, nr_reg_local_dump_print, 0)))
1120 0 : ABORT(r);
1121 :
1122 0 : _status=0;
1123 : abort:
1124 0 : return(_status);
1125 : }
1126 :
1127 :
1128 :
1129 : static nr_registry_module_vtbl nr_reg_local_vtbl = {
1130 : nr_reg_local_init,
1131 : nr_reg_local_get_char,
1132 : nr_reg_local_get_uchar,
1133 : nr_reg_local_get_int2,
1134 : nr_reg_local_get_uint2,
1135 : nr_reg_local_get_int4,
1136 : nr_reg_local_get_uint4,
1137 : nr_reg_local_get_int8,
1138 : nr_reg_local_get_uint8,
1139 : nr_reg_local_get_double,
1140 : nr_reg_local_get_registry,
1141 : nr_reg_local_get_bytes,
1142 : nr_reg_local_get_string,
1143 : nr_reg_local_get_length,
1144 : nr_reg_local_get_type,
1145 : nr_reg_local_set_char,
1146 : nr_reg_local_set_uchar,
1147 : nr_reg_local_set_int2,
1148 : nr_reg_local_set_uint2,
1149 : nr_reg_local_set_int4,
1150 : nr_reg_local_set_uint4,
1151 : nr_reg_local_set_int8,
1152 : nr_reg_local_set_uint8,
1153 : nr_reg_local_set_double,
1154 : nr_reg_local_set_registry,
1155 : nr_reg_local_set_bytes,
1156 : nr_reg_local_set_string,
1157 : nr_reg_local_del,
1158 : nr_reg_local_get_child_count,
1159 : nr_reg_local_get_children,
1160 : nr_reg_local_fin,
1161 : nr_reg_local_dump
1162 : };
1163 :
1164 : static nr_registry_module nr_reg_local_module = { 0, &nr_reg_local_vtbl };
1165 :
1166 : void *NR_REG_MODE_LOCAL = &nr_reg_local_module;
1167 :
1168 :
|