4
/* Portions of this file are subject to the following copyright(s). See
5
* the Net-SNMP's COPYING file for more details and other copyrights
9
* Portions of this file are copyrighted by:
10
* Copyright ļæ½ 2003 Sun Microsystems, Inc. All rights reserved.
11
* Use is subject to license terms specified in the COPYING file
12
* distributed with the Net-SNMP package.
14
/** @defgroup agent_registry Maintain a registry of MIB subtrees, together with related information regarding mibmodule, sessions, etc
20
#define IN_SNMP_VARS_C
22
#include <net-snmp/net-snmp-config.h>
30
#include <sys/types.h>
36
#if TIME_WITH_SYS_TIME
38
# include <sys/timeb.h>
40
# include <sys/time.h>
45
# include <sys/time.h>
51
#include <netinet/in.h>
58
#include <net-snmp/net-snmp-includes.h>
59
#include <net-snmp/agent/net-snmp-agent-includes.h>
60
#include <net-snmp/agent/agent_callbacks.h>
63
#include "mibgroup/struct.h"
64
#include <net-snmp/agent/old_api.h>
65
#include <net-snmp/agent/null.h>
66
#include <net-snmp/agent/table.h>
67
#include <net-snmp/agent/table_iterator.h>
68
#include <net-snmp/agent/agent_registry.h>
69
#include "mib_module_includes.h"
71
#ifdef USING_AGENTX_SUBAGENT_MODULE
72
#include "agentx/subagent.h"
73
#include "agentx/client.h"
76
static void register_mib_detach_node(netsnmp_subtree *s);
77
NETSNMP_STATIC_INLINE void invalidate_lookup_cache(const char *context);
78
void netsnmp_set_lookup_cache_size(int newsize);
79
int netsnmp_get_lookup_cache_size(void);
81
subtree_context_cache *context_subtrees = NULL;
84
netsnmp_subtree_free(netsnmp_subtree *a)
87
if (a->variables != NULL && netsnmp_oid_equals(a->name_a, a->namelen,
88
a->start_a, a->start_len) == 0) {
89
SNMP_FREE(a->variables);
92
SNMP_FREE(a->start_a);
94
SNMP_FREE(a->label_a);
95
netsnmp_handler_registration_free(a->reginfo);
101
netsnmp_subtree_deepcopy(netsnmp_subtree *a)
103
netsnmp_subtree *b = (netsnmp_subtree *)calloc(1, sizeof(netsnmp_subtree));
106
memcpy(b, a, sizeof(netsnmp_subtree));
107
b->name_a = snmp_duplicate_objid(a->name_a, a->namelen);
108
b->start_a = snmp_duplicate_objid(a->start_a, a->start_len);
109
b->end_a = snmp_duplicate_objid(a->end_a, a->end_len);
110
b->label_a = strdup(a->label_a);
112
if (b->name_a == NULL || b->start_a == NULL ||
113
b->end_a == NULL || b->label_a == NULL) {
114
netsnmp_subtree_free(b);
118
if (a->variables != NULL) {
119
b->variables = (struct variable *)malloc(a->variables_len *
121
if (b->variables != NULL) {
122
memcpy(b->variables, a->variables,a->variables_len*a->variables_width);
124
netsnmp_subtree_free(b);
129
if (a->reginfo != NULL) {
130
b->reginfo = netsnmp_handler_registration_dup(a->reginfo);
131
if (b->reginfo == NULL) {
132
netsnmp_subtree_free(b);
140
subtree_context_cache *
141
get_top_context_cache(void)
143
return context_subtrees;
147
netsnmp_subtree_find_first(const char *context_name)
149
subtree_context_cache *ptr;
155
DEBUGMSGTL(("subtree", "looking for subtree for context: \"%s\"\n",
157
for (ptr = context_subtrees; ptr != NULL; ptr = ptr->next) {
158
if (ptr->context_name != NULL &&
159
strcmp(ptr->context_name, context_name) == 0) {
160
DEBUGMSGTL(("subtree", "found one for: \"%s\"\n", context_name));
161
return ptr->first_subtree;
164
DEBUGMSGTL(("subtree", "didn't find a subtree for context: \"%s\"\n",
170
add_subtree(netsnmp_subtree *new_tree, const char *context_name)
172
subtree_context_cache *ptr = SNMP_MALLOC_TYPEDEF(subtree_context_cache);
181
DEBUGMSGTL(("subtree", "adding subtree for context: \"%s\"\n",
183
ptr->next = context_subtrees;
184
ptr->first_subtree = new_tree;
185
ptr->context_name = strdup(context_name);
186
context_subtrees = ptr;
187
return ptr->first_subtree;
191
netsnmp_subtree_replace_first(netsnmp_subtree *new_tree,
192
const char *context_name)
194
subtree_context_cache *ptr;
198
for (ptr = context_subtrees; ptr != NULL; ptr = ptr->next) {
199
if (ptr->context_name != NULL &&
200
strcmp(ptr->context_name, context_name) == 0) {
201
ptr->first_subtree = new_tree;
202
return ptr->first_subtree;
205
return add_subtree(new_tree, context_name);
211
netsnmp_subtree_compare(const netsnmp_subtree *ap, const netsnmp_subtree *bp)
213
return snmp_oid_compare(ap->name_a, ap->namelen, bp->name_a, bp->namelen);
217
netsnmp_subtree_join(netsnmp_subtree *root)
219
netsnmp_subtree *s, *tmp, *c, *d;
221
while (root != NULL) {
223
while (s != NULL && root->reginfo == s->reginfo) {
225
DEBUGMSGTL(("subtree", "root start "));
226
DEBUGMSGOID(("subtree", root->start_a, root->start_len));
227
DEBUGMSG(("subtree", " (original end "));
228
DEBUGMSGOID(("subtree", root->end_a, root->end_len));
229
DEBUGMSG(("subtree", ")\n"));
230
DEBUGMSGTL(("subtree", " JOINING to "));
231
DEBUGMSGOID(("subtree", s->start_a, s->start_len));
233
SNMP_FREE(root->end_a);
234
root->end_a = s->end_a;
235
root->end_len = s->end_len;
238
for (c = root; c != NULL; c = c->children) {
241
for (c = s; c != NULL; c = c->children) {
244
DEBUGMSG(("subtree", " so new end "));
245
DEBUGMSGOID(("subtree", root->end_a, root->end_len));
246
DEBUGMSG(("subtree", "\n"));
248
* Probably need to free children too?
250
for (c = s->children; c != NULL; c = d) {
252
netsnmp_subtree_free(c);
254
netsnmp_subtree_free(s);
263
* Split the subtree into two at the specified point,
264
* returning the new (second) subtree
267
netsnmp_subtree_split(netsnmp_subtree *current, oid name[], int name_len)
269
struct variable *vp = NULL;
270
netsnmp_subtree *new_sub, *ptr;
271
int i = 0, rc = 0, rc2 = 0;
272
size_t common_len = 0;
276
if (snmp_oid_compare(name, name_len, current->end_a, current->end_len)>0) {
277
/* Split comes after the end of this subtree */
281
new_sub = netsnmp_subtree_deepcopy(current);
282
if (new_sub == NULL) {
286
/* Set up the point of division. */
287
tmp_a = snmp_duplicate_objid(name, name_len);
289
netsnmp_subtree_free(new_sub);
292
tmp_b = snmp_duplicate_objid(name, name_len);
294
netsnmp_subtree_free(new_sub);
299
if (current->end_a != NULL) {
300
SNMP_FREE(current->end_a);
302
current->end_a = tmp_a;
303
current->end_len = name_len;
304
if (new_sub->start_a != NULL) {
305
SNMP_FREE(new_sub->start_a);
307
new_sub->start_a = tmp_b;
308
new_sub->start_len = name_len;
310
/* Split the variables between the two new subtrees. */
311
i = current->variables_len;
312
current->variables_len = 0;
314
for (vp = current->variables; i > 0; i--) {
315
/* Note that the variable "name" field omits the prefix common to the
316
whole registration, hence the strange comparison here. */
318
rc = snmp_oid_compare(vp->name, vp->namelen,
319
name + current->namelen,
320
name_len - current->namelen);
322
if (name_len - current->namelen > vp->namelen) {
323
common_len = vp->namelen;
325
common_len = name_len - current->namelen;
328
rc2 = snmp_oid_compare(vp->name, common_len,
329
name + current->namelen, common_len);
332
break; /* All following variables belong to the second subtree */
335
current->variables_len++;
337
new_sub->variables_len--;
338
cp = (char *) new_sub->variables;
339
new_sub->variables = (struct variable *)(cp +
340
new_sub->variables_width);
342
vp = (struct variable *) ((char *) vp + current->variables_width);
345
/* Delegated trees should retain their variables regardless */
346
if (current->variables_len > 0 &&
347
IS_DELEGATED((u_char) current->variables[0].type)) {
348
new_sub->variables_len = 1;
349
new_sub->variables = current->variables;
352
/* Propogate this split down through any children */
353
if (current->children) {
354
new_sub->children = netsnmp_subtree_split(current->children,
358
/* Retain the correct linking of the list */
359
for (ptr = current; ptr != NULL; ptr = ptr->children) {
362
for (ptr = new_sub; ptr != NULL; ptr = ptr->children) {
365
for (ptr = new_sub->next; ptr != NULL; ptr=ptr->children) {
373
netsnmp_subtree_load(netsnmp_subtree *new_sub, const char *context_name)
375
netsnmp_subtree *tree1, *tree2, *new2;
376
netsnmp_subtree *prev, *next;
379
if (new_sub == NULL) {
380
return MIB_REGISTERED_OK; /* Degenerate case */
383
/* Find the subtree that contains the start of the new subtree (if
386
tree1 = netsnmp_subtree_find(new_sub->start_a, new_sub->start_len,
389
/* ... and the subtree that follows the new one (NULL implies this is the
390
final region covered). */
393
tree2 = netsnmp_subtree_find_next(new_sub->start_a, new_sub->start_len,
399
/* Handle new subtrees that start in virgin territory. */
403
/* Is there any overlap with later subtrees? */
404
if (tree2 && snmp_oid_compare(new_sub->end_a, new_sub->end_len,
405
tree2->start_a, tree2->start_len) > 0) {
406
new2 = netsnmp_subtree_split(new_sub,
407
tree2->start_a, tree2->start_len);
410
/* Link the new subtree (less any overlapping region) with the list of
411
existing registrations. */
414
new_sub->prev = tree2->prev;
415
tree2->prev = new_sub;
417
new_sub->prev = netsnmp_subtree_find_prev(new_sub->start_a,
418
new_sub->start_len, NULL, context_name);
421
new_sub->prev->next = new_sub;
423
netsnmp_subtree_replace_first(new_sub, context_name);
426
new_sub->next = tree2;
428
/* If there was any overlap, recurse to merge in the overlapping
429
region (including anything that may follow the overlap). */
431
return netsnmp_subtree_load(new2, context_name);
435
/* If the new subtree starts *within* an existing registration
436
(rather than at the same point as it), then split the existing
437
subtree at this point. */
439
if (netsnmp_oid_equals(new_sub->start_a, new_sub->start_len,
440
tree1->start_a, tree1->start_len) != 0) {
441
tree1 = netsnmp_subtree_split(tree1, new_sub->start_a,
446
return MIB_REGISTRATION_FAILED;
449
/* Now consider the end of this existing subtree:
451
If it matches the new subtree precisely,
452
simply merge the new one into the list of children
454
If it includes the whole of the new subtree,
455
split it at the appropriate point, and merge again
457
If the new subtree extends beyond this existing region,
458
split it, and recurse to merge the two parts. */
460
rc = snmp_oid_compare(new_sub->end_a, new_sub->end_len,
461
tree1->end_a, tree1->end_len);
466
/* Existing subtree contains new one. */
467
netsnmp_subtree_split(tree1, new_sub->end_a, new_sub->end_len);
471
/* The two trees match precisely. */
473
/* Note: This is the only point where the original registration
474
OID ("name") is used. */
479
while (next && next->namelen > new_sub->namelen) {
481
next = next->children;
484
while (next && next->namelen == new_sub->namelen &&
485
next->priority < new_sub->priority ) {
487
next = next->children;
490
if (next && (next->namelen == new_sub->namelen) &&
491
(next->priority == new_sub->priority)) {
492
return MIB_DUPLICATE_REGISTRATION;
496
prev->children = new_sub;
497
new_sub->children = next;
498
new_sub->prev = prev->prev;
499
new_sub->next = prev->next;
501
new_sub->children = next;
502
new_sub->prev = next->prev;
503
new_sub->next = next->next;
505
for (next = new_sub->next; next != NULL;next = next->children){
506
next->prev = new_sub;
509
for (prev = new_sub->prev; prev != NULL;prev = prev->children){
510
prev->next = new_sub;
516
/* New subtree contains the existing one. */
517
new2 = netsnmp_subtree_split(new_sub, tree1->end_a,tree1->end_len);
518
res = netsnmp_subtree_load(new_sub, context_name);
519
if (res != MIB_REGISTERED_OK) {
520
netsnmp_subtree_free(new2);
523
return netsnmp_subtree_load(new2, context_name);
530
netsnmp_register_mib(const char *moduleName,
531
struct variable *var,
539
netsnmp_session * ss,
543
netsnmp_handler_registration *reginfo,
544
int perform_callback)
546
netsnmp_subtree *subtree, *sub2;
548
struct register_parameters reg_parms;
549
int old_lookup_cache_val = netsnmp_get_lookup_cache_size();
551
subtree = (netsnmp_subtree *)calloc(1, sizeof(netsnmp_subtree));
552
if (subtree == NULL) {
553
return MIB_REGISTRATION_FAILED;
556
DEBUGMSGTL(("register_mib", "registering \"%s\" at ", moduleName));
557
DEBUGMSGOIDRANGE(("register_mib", mibloc, mibloclen, range_subid,
559
DEBUGMSG(("register_mib", "\n"));
561
/* Create the new subtree node being registered. */
563
subtree->name_a = snmp_duplicate_objid(mibloc, mibloclen);
564
subtree->start_a = snmp_duplicate_objid(mibloc, mibloclen);
565
subtree->end_a = snmp_duplicate_objid(mibloc, mibloclen);
566
subtree->label_a = strdup(moduleName);
567
if (subtree->name_a == NULL || subtree->start_a == NULL ||
568
subtree->end_a == NULL || subtree->label_a == NULL) {
569
netsnmp_subtree_free(subtree);
570
return MIB_REGISTRATION_FAILED;
572
subtree->namelen = (u_char)mibloclen;
573
subtree->start_len = (u_char)mibloclen;
574
subtree->end_len = (u_char)mibloclen;
575
subtree->end_a[mibloclen - 1]++;
578
subtree->variables = (struct variable *)malloc(varsize*numvars);
579
if (subtree->variables == NULL) {
580
netsnmp_subtree_free(subtree);
581
return MIB_REGISTRATION_FAILED;
583
memcpy(subtree->variables, var, numvars*varsize);
584
subtree->variables_len = numvars;
585
subtree->variables_width = varsize;
587
subtree->priority = priority;
588
subtree->timeout = timeout;
589
subtree->range_subid = range_subid;
590
subtree->range_ubound = range_ubound;
591
subtree->session = ss;
592
subtree->reginfo = reginfo;
593
subtree->flags = (u_char)flags; /* used to identify instance oids */
594
subtree->flags |= SUBTREE_ATTACHED;
595
subtree->global_cacheid = reginfo->global_cacheid;
597
netsnmp_set_lookup_cache_size(0);
598
res = netsnmp_subtree_load(subtree, context);
600
/* If registering a range, use the first subtree as a template for the
601
rest of the range. */
603
if (res == MIB_REGISTERED_OK && range_subid != 0) {
604
for (i = mibloc[range_subid - 1] + 1; i <= (int)range_ubound; i++) {
605
sub2 = netsnmp_subtree_deepcopy(subtree);
608
unregister_mib_context(mibloc, mibloclen, priority,
609
range_subid, range_ubound, context);
610
netsnmp_set_lookup_cache_size(old_lookup_cache_val);
611
invalidate_lookup_cache(context);
612
return MIB_REGISTRATION_FAILED;
615
sub2->name_a[range_subid - 1] = i;
616
sub2->start_a[range_subid - 1] = i;
617
sub2->end_a[range_subid - 1] = i; /* XXX - ???? */
618
res = netsnmp_subtree_load(sub2, context);
619
sub2->flags |= SUBTREE_ATTACHED;
620
if (res != MIB_REGISTERED_OK) {
621
unregister_mib_context(mibloc, mibloclen, priority,
622
range_subid, range_ubound, context);
623
netsnmp_subtree_free(sub2);
624
netsnmp_set_lookup_cache_size(old_lookup_cache_val);
625
invalidate_lookup_cache(context);
629
} else if (res == MIB_DUPLICATE_REGISTRATION ||
630
res == MIB_REGISTRATION_FAILED) {
631
netsnmp_subtree_free(subtree);
635
* mark the MIB as detached, if there's no master agent present as of now
637
if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
638
NETSNMP_DS_AGENT_ROLE) != MASTER_AGENT) {
639
extern struct snmp_session *main_session;
640
if (main_session == NULL) {
641
register_mib_detach_node(subtree);
645
if (perform_callback) {
646
reg_parms.name = mibloc;
647
reg_parms.namelen = mibloclen;
648
reg_parms.priority = priority;
649
reg_parms.range_subid = range_subid;
650
reg_parms.range_ubound = range_ubound;
651
reg_parms.timeout = timeout;
652
reg_parms.flags = (u_char) flags;
655
* Should this really be called if the registration hasn't actually
659
snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
660
SNMPD_CALLBACK_REGISTER_OID, ®_parms);
663
netsnmp_set_lookup_cache_size(old_lookup_cache_val);
664
invalidate_lookup_cache(context);
669
* Reattach a particular node.
673
register_mib_reattach_node(netsnmp_subtree *s)
675
if ((s != NULL) && (s->namelen > 1) && !(s->flags & SUBTREE_ATTACHED)) {
676
struct register_parameters reg_parms;
678
* only do registrations that are not the top level nodes
681
* XXX: do this better
683
reg_parms.name = s->name_a;
684
reg_parms.namelen = s->namelen;
685
reg_parms.priority = s->priority;
686
reg_parms.range_subid = s->range_subid;
687
reg_parms.range_ubound = s->range_ubound;
688
reg_parms.timeout = s->timeout;
689
reg_parms.flags = s->flags;
690
snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
691
SNMPD_CALLBACK_REGISTER_OID, ®_parms);
692
s->flags |= SUBTREE_ATTACHED;
697
* Call callbacks to reattach all our nodes.
701
register_mib_reattach(void)
703
netsnmp_subtree *s, *t;
704
subtree_context_cache *ptr;
706
for (ptr = context_subtrees; ptr; ptr = ptr->next) {
707
for (s = ptr->first_subtree; s != NULL; s = s->next) {
708
register_mib_reattach_node(s);
709
for (t = s->children; t != NULL; t = t->children) {
710
register_mib_reattach_node(t);
717
* Mark a node as detached.
721
register_mib_detach_node(netsnmp_subtree *s)
724
s->flags = s->flags & ~SUBTREE_ATTACHED;
729
* Mark all our registered OIDs as detached. This is only really
730
* useful for subagent protocols, when a connection is lost or
735
register_mib_detach(void)
737
netsnmp_subtree *s, *t;
738
subtree_context_cache *ptr;
739
for (ptr = context_subtrees; ptr; ptr = ptr->next) {
740
for (s = ptr->first_subtree; s != NULL; s = s->next) {
741
register_mib_detach_node(s);
742
for (t = s->children; t != NULL; t = t->children) {
743
register_mib_detach_node(t);
750
register_mib_context(const char *moduleName,
751
struct variable *var,
759
netsnmp_session * ss,
760
const char *context, int timeout, int flags)
762
return netsnmp_register_old_api(moduleName, var, varsize, numvars,
763
mibloc, mibloclen, priority,
764
range_subid, range_ubound, ss, context,
769
register_mib_range(const char *moduleName,
770
struct variable *var,
776
int range_subid, oid range_ubound, netsnmp_session * ss)
778
return register_mib_context(moduleName, var, varsize, numvars,
779
mibloc, mibloclen, priority,
780
range_subid, range_ubound, ss, "", -1, 0);
784
register_mib_priority(const char *moduleName,
785
struct variable *var,
788
oid * mibloc, size_t mibloclen, int priority)
790
return register_mib_range(moduleName, var, varsize, numvars,
791
mibloc, mibloclen, priority, 0, 0, NULL);
795
register_mib(const char *moduleName,
796
struct variable *var,
798
size_t numvars, oid * mibloc, size_t mibloclen)
800
return register_mib_priority(moduleName, var, varsize, numvars,
801
mibloc, mibloclen, DEFAULT_MIB_PRIORITY);
805
netsnmp_subtree_unload(netsnmp_subtree *sub, netsnmp_subtree *prev, const char *context)
807
netsnmp_subtree *ptr;
809
DEBUGMSGTL(("register_mib", "unload("));
811
DEBUGMSGOID(("register_mib", sub->start_a, sub->start_len));
813
DEBUGMSG(("register_mib", "[NIL]"));
815
DEBUGMSG(("register_mib", ", "));
817
DEBUGMSGOID(("register_mib", prev->start_a, prev->start_len));
819
DEBUGMSG(("register_mib", "[NIL]"));
821
DEBUGMSG(("register_mib", ")\n"));
823
if (prev != NULL) { /* non-leading entries are easy */
824
prev->children = sub->children;
825
invalidate_lookup_cache(context);
829
* otherwise, we need to amend our neighbours as well
832
if (sub->children == NULL) { /* just remove this node completely */
833
for (ptr = sub->prev; ptr; ptr = ptr->children)
834
ptr->next = sub->next;
835
for (ptr = sub->next; ptr; ptr = ptr->children)
836
ptr->prev = sub->prev;
838
if (sub->prev == NULL) {
839
netsnmp_subtree_replace_first(sub->next, context);
843
for (ptr = sub->prev; ptr; ptr = ptr->children)
844
ptr->next = sub->children;
845
for (ptr = sub->next; ptr; ptr = ptr->children)
846
ptr->prev = sub->children;
848
if (sub->prev == NULL) {
849
netsnmp_subtree_replace_first(sub->children, context);
852
invalidate_lookup_cache(context);
856
* Unregisters an OID that has an associated context name value.
857
* Typically used when a module has multiple contexts defined. The parameters
858
* priority, range_subid, and range_ubound should be used in conjunction with
859
* agentx, see RFC 2741, otherwise these values should always be 0.
861
* @param name the specific OID to unregister if it conatins the associated
864
* @param len the length of the OID, use OID_LENGTH macro.
866
* @param priority a value between 1 and 255, used to achieve a desired
867
* configuration when different sessions register identical or
868
* overlapping regions. Subagents with no particular
869
* knowledge of priority should register with the default
872
* @param range_subid permits specifying a range in place of one of a subtree
873
* sub-identifiers. When this value is zero, no range is
876
* @param range_ubound the upper bound of a sub-identifier's range.
877
* This field is present only if range_subid is not 0.
879
* @param context a context name that has been created
885
unregister_mib_context(oid * name, size_t len, int priority,
886
int range_subid, oid range_ubound,
889
netsnmp_subtree *list, *myptr;
890
netsnmp_subtree *prev, *child; /* loop through children */
891
struct register_parameters reg_parms;
892
int old_lookup_cache_val = netsnmp_get_lookup_cache_size();
893
netsnmp_set_lookup_cache_size(0);
895
DEBUGMSGTL(("register_mib", "unregistering "));
896
DEBUGMSGOIDRANGE(("register_mib", name, len, range_subid, range_ubound));
897
DEBUGMSG(("register_mib", "\n"));
899
list = netsnmp_subtree_find(name, len, netsnmp_subtree_find_first(context),
902
return MIB_NO_SUCH_REGISTRATION;
905
for (child = list, prev = NULL; child != NULL;
906
prev = child, child = child->children) {
907
if (netsnmp_oid_equals(child->name_a, child->namelen, name, len) == 0 &&
908
child->priority == priority) {
909
break; /* found it */
914
return MIB_NO_SUCH_REGISTRATION;
917
netsnmp_subtree_unload(child, prev, context);
918
myptr = child; /* remember this for later */
921
* Now handle any occurances in the following subtrees,
922
* as a result of splitting this range. Due to the
923
* nature of the way such splits work, the first
924
* subtree 'slice' that doesn't refer to the given
925
* name marks the end of the original region.
927
* This should also serve to register ranges.
930
for (list = myptr->next; list != NULL; list = list->next) {
931
for (child = list, prev = NULL; child != NULL;
932
prev = child, child = child->children) {
933
if ((netsnmp_oid_equals(child->name_a, child->namelen,
935
(child->priority == priority)) {
936
netsnmp_subtree_unload(child, prev, context);
937
netsnmp_subtree_free(child);
941
if (child == NULL) /* Didn't find the given name */
944
netsnmp_subtree_free(myptr);
946
reg_parms.name = name;
947
reg_parms.namelen = len;
948
reg_parms.priority = priority;
949
reg_parms.range_subid = range_subid;
950
reg_parms.range_ubound = range_ubound;
951
reg_parms.flags = 0x00; /* this is okay I think */
952
snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
953
SNMPD_CALLBACK_UNREGISTER_OID, ®_parms);
955
netsnmp_set_lookup_cache_size(old_lookup_cache_val);
956
invalidate_lookup_cache(context);
957
return MIB_UNREGISTERED_OK;
961
netsnmp_unregister_mib_table_row(oid * name, size_t len, int priority,
962
int var_subid, oid range_ubound,
965
netsnmp_subtree *list, *myptr;
966
netsnmp_subtree *prev, *child; /* loop through children */
967
struct register_parameters reg_parms;
968
oid range_lbound = name[var_subid - 1];
970
DEBUGMSGTL(("register_mib", "unregistering "));
971
DEBUGMSGOIDRANGE(("register_mib", name, len, var_subid, range_ubound));
972
DEBUGMSG(("register_mib", "\n"));
974
for (; name[var_subid - 1] <= range_ubound; name[var_subid - 1]++) {
975
list = netsnmp_subtree_find(name, len,
976
netsnmp_subtree_find_first(context), context);
982
for (child = list, prev = NULL; child != NULL;
983
prev = child, child = child->children) {
985
if (netsnmp_oid_equals(child->name_a, child->namelen,
987
(child->priority == priority)) {
988
break; /* found it */
996
netsnmp_subtree_unload(child, prev, context);
997
myptr = child; /* remember this for later */
999
for (list = myptr->next; list != NULL; list = list->next) {
1000
for (child = list, prev = NULL; child != NULL;
1001
prev = child, child = child->children) {
1003
if (netsnmp_oid_equals(child->name_a, child->namelen,
1005
(child->priority == priority)) {
1006
netsnmp_subtree_unload(child, prev, context);
1007
netsnmp_subtree_free(child);
1011
if (child == NULL) { /* Didn't find the given name */
1015
netsnmp_subtree_free(myptr);
1018
name[var_subid - 1] = range_lbound;
1019
reg_parms.name = name;
1020
reg_parms.namelen = len;
1021
reg_parms.priority = priority;
1022
reg_parms.range_subid = var_subid;
1023
reg_parms.range_ubound = range_ubound;
1024
reg_parms.flags = 0x00; /* this is okay I think */
1025
snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
1026
SNMPD_CALLBACK_UNREGISTER_OID, ®_parms);
1032
unregister_mib_range(oid * name, size_t len, int priority,
1033
int range_subid, oid range_ubound)
1035
return unregister_mib_context(name, len, priority, range_subid,
1040
unregister_mib_priority(oid * name, size_t len, int priority)
1042
return unregister_mib_range(name, len, priority, 0, 0);
1046
unregister_mib(oid * name, size_t len)
1048
return unregister_mib_priority(name, len, DEFAULT_MIB_PRIORITY);
1052
unregister_mibs_by_session(netsnmp_session * ss)
1054
netsnmp_subtree *list, *list2;
1055
netsnmp_subtree *child, *prev, *next_child;
1056
struct register_parameters rp;
1057
subtree_context_cache *contextptr;
1059
DEBUGMSGTL(("register_mib", "unregister_mibs_by_session(%p) ctxt \"%s\"\n",
1060
ss, (ss && ss->contextName) ? ss->contextName : "[NIL]"));
1062
for (contextptr = get_top_context_cache(); contextptr != NULL;
1063
contextptr = contextptr->next) {
1064
for (list = contextptr->first_subtree; list != NULL; list = list2) {
1067
for (child = list, prev = NULL; child != NULL; child = next_child){
1068
next_child = child->children;
1070
if (((!ss || ss->flags & SNMP_FLAGS_SUBSESSION) &&
1071
child->session == ss) ||
1072
(!(!ss || ss->flags & SNMP_FLAGS_SUBSESSION) && child->session &&
1073
child->session->subsession == ss)) {
1075
rp.name = child->name_a;
1076
child->name_a = NULL;
1077
rp.namelen = child->namelen;
1078
rp.priority = child->priority;
1079
rp.range_subid = child->range_subid;
1080
rp.range_ubound = child->range_ubound;
1081
rp.timeout = child->timeout;
1082
rp.flags = child->flags;
1084
if (child->reginfo != NULL) {
1086
* Don't let's free the session pointer just yet!
1088
child->reginfo->handler->myvoid = NULL;
1089
netsnmp_handler_registration_free(child->reginfo);
1090
child->reginfo = NULL;
1093
netsnmp_subtree_unload(child, prev, contextptr->context_name);
1094
netsnmp_subtree_free(child);
1096
snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
1097
SNMPD_CALLBACK_UNREGISTER_OID, &rp);
1104
netsnmp_subtree_join(contextptr->first_subtree);
1109
* in_a_view: determines if a given snmp_pdu is allowed to see a
1110
* given name/namelen OID pointer
1111
* name IN - name of var, OUT - name matched
1112
* nameLen IN -number of sub-ids in name, OUT - subid-is in matched name
1113
* pi IN - relevant auth info re PDU
1114
* cvp IN - relevant auth info re mib module
1118
in_a_view(oid *name, size_t *namelen, netsnmp_pdu *pdu, int type)
1120
struct view_parameters view_parms;
1122
if (pdu->flags & UCD_MSG_FLAG_ALWAYS_IN_VIEW) {
1123
/* Enable bypassing of view-based access control */
1124
return VACM_SUCCESS;
1128
* check for v1 and counter64s, since snmpv1 doesn't support it
1130
if (pdu->version == SNMP_VERSION_1 && type == ASN_COUNTER64) {
1131
return VACM_NOTINVIEW;
1134
view_parms.pdu = pdu;
1135
view_parms.name = name;
1136
if (namelen != NULL) {
1137
view_parms.namelen = *namelen;
1139
view_parms.namelen = 0;
1141
view_parms.errorcode = 0;
1142
view_parms.check_subtree = 0;
1144
switch (pdu->version) {
1145
case SNMP_VERSION_1:
1146
case SNMP_VERSION_2c:
1147
case SNMP_VERSION_3:
1148
snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
1149
SNMPD_CALLBACK_ACM_CHECK, &view_parms);
1150
return view_parms.errorcode;
1152
return VACM_NOSECNAME;
1156
* check_acces: determines if a given snmp_pdu is ever going to be
1157
* allowed to do anynthing or if it's not going to ever be
1161
check_access(netsnmp_pdu *pdu)
1162
{ /* IN - pdu being checked */
1163
struct view_parameters view_parms;
1164
view_parms.pdu = pdu;
1165
view_parms.name = 0;
1166
view_parms.namelen = 0;
1167
view_parms.errorcode = 0;
1168
view_parms.check_subtree = 0;
1170
if (pdu->flags & UCD_MSG_FLAG_ALWAYS_IN_VIEW) {
1171
/* Enable bypassing of view-based access control */
1175
switch (pdu->version) {
1176
case SNMP_VERSION_1:
1177
case SNMP_VERSION_2c:
1178
case SNMP_VERSION_3:
1179
snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
1180
SNMPD_CALLBACK_ACM_CHECK_INITIAL, &view_parms);
1181
return view_parms.errorcode;
1186
/** checks to see if everything within a
1187
* given subtree is either: in view, not in view, or possibly both.
1188
* If the entire subtree is not-in-view we can use this information to
1189
* skip calling the sub-handlers entirely.
1190
* @returns 0 if entire subtree is accessible, 5 if not and 7 if
1191
* portions are both. 1 on error (illegal pdu version).
1194
netsnmp_acm_check_subtree(netsnmp_pdu *pdu, oid *name, size_t namelen)
1195
{ /* IN - pdu being checked */
1196
struct view_parameters view_parms;
1197
view_parms.pdu = pdu;
1198
view_parms.name = name;
1199
view_parms.namelen = namelen;
1200
view_parms.errorcode = 0;
1201
view_parms.check_subtree = 1;
1203
if (pdu->flags & UCD_MSG_FLAG_ALWAYS_IN_VIEW) {
1204
/* Enable bypassing of view-based access control */
1208
switch (pdu->version) {
1209
case SNMP_VERSION_1:
1210
case SNMP_VERSION_2c:
1211
case SNMP_VERSION_3:
1212
snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
1213
SNMPD_CALLBACK_ACM_CHECK_SUBTREE, &view_parms);
1214
return view_parms.errorcode;
1219
#define SUBTREE_DEFAULT_CACHE_SIZE 8
1220
#define SUBTREE_MAX_CACHE_SIZE 32
1221
int lookup_cache_size = 0; /*enabled later after registrations are loaded */
1223
typedef struct lookup_cache_s {
1224
netsnmp_subtree *next;
1225
netsnmp_subtree *previous;
1228
typedef struct lookup_cache_context_s {
1230
struct lookup_cache_context_s *next;
1233
lookup_cache cache[SUBTREE_MAX_CACHE_SIZE];
1234
} lookup_cache_context;
1236
static lookup_cache_context *thecontextcache = NULL;
1238
/** set the lookup cache size for optimized agent registration performance.
1239
* @param newsize set to the maximum size of a cache for a given
1240
* context. Set to 0 to completely disable caching, or to -1 to set
1241
* to the default cache size (8), or to a number of your chosing. The
1242
* rough guide is that it should be equal to the maximum number of
1243
* simultanious managers you expect to talk to the agent (M) times 80%
1244
* (or so, he says randomly) the average number (N) of varbinds you
1245
* expect to receive in a given request for a manager. ie, M times N.
1246
* Bigger does NOT necessarily mean better. Certainly 16 should be an
1247
* upper limit. 32 is the hard coded limit.
1250
netsnmp_set_lookup_cache_size(int newsize) {
1252
lookup_cache_size = SUBTREE_DEFAULT_CACHE_SIZE;
1253
else if (newsize < SUBTREE_MAX_CACHE_SIZE)
1254
lookup_cache_size = newsize;
1256
lookup_cache_size = SUBTREE_MAX_CACHE_SIZE;
1259
/** retrieves the current value of the lookup cache size
1260
* @return the current lookup cache size
1263
netsnmp_get_lookup_cache_size(void) {
1264
return lookup_cache_size;
1267
NETSNMP_STATIC_INLINE lookup_cache_context *
1268
get_context_lookup_cache(const char *context) {
1269
lookup_cache_context *ptr;
1273
for(ptr = thecontextcache; ptr; ptr = ptr->next) {
1274
if (strcmp(ptr->context, context) == 0)
1278
if (netsnmp_subtree_find_first(context)) {
1279
ptr = SNMP_MALLOC_TYPEDEF(lookup_cache_context);
1280
ptr->next = thecontextcache;
1281
ptr->context = strdup(context);
1282
thecontextcache = ptr;
1290
NETSNMP_STATIC_INLINE void
1291
lookup_cache_add(const char *context,
1292
netsnmp_subtree *next, netsnmp_subtree *previous) {
1293
lookup_cache_context *cptr;
1295
if ((cptr = get_context_lookup_cache(context)) == NULL)
1298
if (cptr->thecachecount < lookup_cache_size)
1299
cptr->thecachecount++;
1301
cptr->cache[cptr->currentpos].next = next;
1302
cptr->cache[cptr->currentpos].previous = previous;
1304
if (++cptr->currentpos >= lookup_cache_size)
1305
cptr->currentpos = 0;
1308
NETSNMP_STATIC_INLINE void
1309
lookup_cache_replace(lookup_cache *ptr,
1310
netsnmp_subtree *next, netsnmp_subtree *previous) {
1313
ptr->previous = previous;
1316
NETSNMP_STATIC_INLINE lookup_cache *
1317
lookup_cache_find(const char *context, oid *name, size_t name_len,
1319
lookup_cache_context *cptr;
1320
lookup_cache *ret = NULL;
1324
if ((cptr = get_context_lookup_cache(context)) == NULL)
1327
for(i = 0; i < cptr->thecachecount && i < lookup_cache_size; i++) {
1328
if (cptr->cache[i].previous->start_a)
1329
cmp = snmp_oid_compare(name, name_len,
1330
cptr->cache[i].previous->start_a,
1331
cptr->cache[i].previous->start_len);
1336
ret = &(cptr->cache[i]);
1342
NETSNMP_STATIC_INLINE void
1343
invalidate_lookup_cache(const char *context) {
1344
lookup_cache_context *cptr;
1345
if ((cptr = get_context_lookup_cache(context)) != NULL) {
1346
cptr->thecachecount = 0;
1347
cptr->currentpos = 0;
1352
netsnmp_subtree_find_prev(oid *name, size_t len, netsnmp_subtree *subtree,
1353
const char *context_name)
1355
lookup_cache *lookup_cache = NULL;
1356
netsnmp_subtree *myptr = NULL, *previous = NULL;
1362
/* look through everything */
1363
if (lookup_cache_size) {
1364
lookup_cache = lookup_cache_find(context_name, name, len, &cmp);
1366
myptr = lookup_cache->next;
1367
previous = lookup_cache->previous;
1370
myptr = netsnmp_subtree_find_first(context_name);
1372
myptr = netsnmp_subtree_find_first(context_name);
1376
for (; myptr != NULL; previous = myptr, myptr = myptr->next) {
1377
if (snmp_oid_compare(name, len, myptr->start_a, myptr->start_len) < 0) {
1378
if (lookup_cache_size && previous && cmp) {
1380
lookup_cache_replace(lookup_cache, myptr, previous);
1382
lookup_cache_add(context_name, myptr, previous);
1392
netsnmp_subtree_find_next(oid *name, size_t len,
1393
netsnmp_subtree *subtree, const char *context_name)
1395
netsnmp_subtree *myptr = NULL;
1397
myptr = netsnmp_subtree_find_prev(name, len, subtree, context_name);
1399
if (myptr != NULL) {
1400
myptr = myptr->next;
1401
while (myptr != NULL && (myptr->variables == NULL ||
1402
myptr->variables_len == 0)) {
1403
myptr = myptr->next;
1406
} else if (subtree != NULL && snmp_oid_compare(name, len,
1407
subtree->start_a, subtree->start_len) < 0) {
1415
netsnmp_subtree_find(oid *name, size_t len, netsnmp_subtree *subtree,
1416
const char *context_name)
1418
netsnmp_subtree *myptr;
1420
myptr = netsnmp_subtree_find_prev(name, len, subtree, context_name);
1421
if (myptr && myptr->end_a &&
1422
snmp_oid_compare(name, len, myptr->end_a, myptr->end_len)<0) {
1430
get_session_for_oid(oid *name, size_t len, const char *context_name)
1432
netsnmp_subtree *myptr;
1434
myptr = netsnmp_subtree_find_prev(name, len,
1435
netsnmp_subtree_find_first(context_name),
1438
while (myptr && myptr->variables == NULL) {
1439
myptr = myptr->next;
1442
if (myptr == NULL) {
1445
return myptr->session;
1452
oid ccitt[1] = { 0 };
1454
oid joint_ccitt_iso[1] = { 2 };
1456
#ifdef USING_AGENTX_SUBAGENT_MODULE
1457
int role = netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
1458
NETSNMP_DS_AGENT_ROLE);
1460
netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE,
1465
* we need to have the oid's in the heap, that we can *free* it for every case,
1466
* thats the purpose of the duplicate_objid's
1468
netsnmp_register_null(snmp_duplicate_objid(ccitt, 1), 1);
1469
netsnmp_register_null(snmp_duplicate_objid(iso, 1), 1);
1470
netsnmp_register_null(snmp_duplicate_objid(joint_ccitt_iso, 1), 1);
1472
#ifdef USING_AGENTX_SUBAGENT_MODULE
1473
netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE,
1479
remove_tree_entry (oid *name, size_t len) {
1481
netsnmp_subtree *sub = NULL;
1483
if ((sub = netsnmp_subtree_find(name, len, NULL, "")) == NULL) {
1484
return MIB_NO_SUCH_REGISTRATION;
1487
return unregister_mib_context(name, len, sub->priority,
1488
sub->range_subid, sub->range_ubound, "");
1494
shutdown_tree(void) {
1495
oid ccitt[1] = { 0 };
1497
oid joint_ccitt_iso[1] = { 2 };
1499
DEBUGMSGTL(("agent_registry", "shut down tree\n"));
1501
remove_tree_entry(joint_ccitt_iso, 1);
1502
remove_tree_entry(iso, 1);
1503
remove_tree_entry(ccitt, 1);
1508
clear_subtree (netsnmp_subtree *sub) {
1510
netsnmp_subtree *nxt;
1515
for(nxt = sub; nxt;) {
1516
if (nxt->children != NULL) {
1517
clear_subtree(nxt->children);
1521
netsnmp_subtree_free(sub);
1527
clear_lookup_cache(void) {
1529
lookup_cache_context *ptr = NULL, *next = NULL;
1531
ptr = thecontextcache;
1534
SNMP_FREE(ptr->context);
1538
thecontextcache = NULL; /* !!! */
1542
clear_context(void) {
1544
subtree_context_cache *ptr = NULL, *next = NULL;
1546
DEBUGMSGTL(("agent_registry", "clear context\n"));
1548
ptr = get_top_context_cache();
1552
if (ptr->first_subtree) {
1553
clear_subtree(ptr->first_subtree);
1556
SNMP_FREE(ptr->context_name);
1561
context_subtrees = NULL; /* !!! */
1562
clear_lookup_cache();
1565
extern void dump_idx_registry(void);
1569
struct variable *vp = NULL;
1570
netsnmp_subtree *myptr, *myptr2;
1571
u_char *s = NULL, *e = NULL, *v = NULL;
1572
size_t sl = 256, el = 256, vl = 256, sl_o = 0, el_o = 0, vl_o = 0;
1575
if ((s = (u_char *) calloc(sl, 1)) != NULL &&
1576
(e = (u_char *) calloc(sl, 1)) != NULL &&
1577
(v = (u_char *) calloc(sl, 1)) != NULL) {
1579
subtree_context_cache *ptr;
1580
for (ptr = context_subtrees; ptr; ptr = ptr->next) {
1581
printf("Subtrees for Context: %s\n", ptr->context_name);
1582
for (myptr = ptr->first_subtree; myptr != NULL;
1583
myptr = myptr->next) {
1584
sl_o = el_o = vl_o = 0;
1586
if (!sprint_realloc_objid(&s, &sl, &sl_o, 1,
1588
myptr->start_len)) {
1591
if (!sprint_realloc_objid(&e, &el, &el_o, 1,
1597
if (myptr->variables) {
1598
printf("%02x ( %s - %s ) [", myptr->flags, s, e);
1599
for (i = 0, vp = myptr->variables;
1600
i < myptr->variables_len; i++) {
1602
if (!sprint_realloc_objid
1603
(&v, &vl, &vl_o, 1, vp->name, vp->namelen)) {
1607
vp = (struct variable *) ((char *) vp +
1608
myptr->variables_width);
1612
printf("%02x %s - %s \n", myptr->flags, s, e);
1614
for (myptr2 = myptr; myptr2 != NULL;
1615
myptr2 = myptr2->children) {
1616
if (myptr2->label_a && myptr2->label_a[0]) {
1617
if (strcmp(myptr2->label_a, "old_api") == 0) {
1618
struct variable *vp =
1619
myptr2->reginfo->handler->myvoid;
1621
sprint_realloc_objid(&s, &sl, &sl_o, 1,
1622
vp->name, vp->namelen);
1623
printf("\t%s[%s] %p var %s\n", myptr2->label_a,
1624
myptr2->reginfo->handlerName ? myptr2->
1625
reginfo->handlerName : "no-name",
1626
myptr2->reginfo, s);
1628
printf("\t%s %s %p\n", myptr2->label_a,
1629
myptr2->reginfo->handlerName ? myptr2->
1631
handlerName : "no-handler-name",
1650
dump_idx_registry();
1654
int external_readfd[NUM_EXTERNAL_FDS], external_readfdlen = 0;
1655
int external_writefd[NUM_EXTERNAL_FDS], external_writefdlen = 0;
1656
int external_exceptfd[NUM_EXTERNAL_FDS], external_exceptfdlen = 0;
1657
void (*external_readfdfunc[NUM_EXTERNAL_FDS]) (int, void *);
1658
void (*external_writefdfunc[NUM_EXTERNAL_FDS]) (int, void *);
1659
void (*external_exceptfdfunc[NUM_EXTERNAL_FDS]) (int, void *);
1660
void *external_readfd_data[NUM_EXTERNAL_FDS];
1661
void *external_writefd_data[NUM_EXTERNAL_FDS];
1662
void *external_exceptfd_data[NUM_EXTERNAL_FDS];
1665
register_readfd(int fd, void (*func) (int, void *), void *data)
1667
if (external_readfdlen < NUM_EXTERNAL_FDS) {
1668
external_readfd[external_readfdlen] = fd;
1669
external_readfdfunc[external_readfdlen] = func;
1670
external_readfd_data[external_readfdlen] = data;
1671
external_readfdlen++;
1672
DEBUGMSGTL(("register_readfd", "registered fd %d\n", fd));
1673
return FD_REGISTERED_OK;
1675
snmp_log(LOG_CRIT, "register_readfd: too many file descriptors\n");
1676
return FD_REGISTRATION_FAILED;
1681
register_writefd(int fd, void (*func) (int, void *), void *data)
1683
if (external_writefdlen < NUM_EXTERNAL_FDS) {
1684
external_writefd[external_writefdlen] = fd;
1685
external_writefdfunc[external_writefdlen] = func;
1686
external_writefd_data[external_writefdlen] = data;
1687
external_writefdlen++;
1688
DEBUGMSGTL(("register_writefd", "registered fd %d\n", fd));
1689
return FD_REGISTERED_OK;
1692
"register_writefd: too many file descriptors\n");
1693
return FD_REGISTRATION_FAILED;
1698
register_exceptfd(int fd, void (*func) (int, void *), void *data)
1700
if (external_exceptfdlen < NUM_EXTERNAL_FDS) {
1701
external_exceptfd[external_exceptfdlen] = fd;
1702
external_exceptfdfunc[external_exceptfdlen] = func;
1703
external_exceptfd_data[external_exceptfdlen] = data;
1704
external_exceptfdlen++;
1705
DEBUGMSGTL(("register_exceptfd", "registered fd %d\n", fd));
1706
return FD_REGISTERED_OK;
1709
"register_exceptfd: too many file descriptors\n");
1710
return FD_REGISTRATION_FAILED;
1715
unregister_readfd(int fd)
1719
for (i = 0; i < external_readfdlen; i++) {
1720
if (external_readfd[i] == fd) {
1721
external_readfdlen--;
1722
for (j = i; j < external_readfdlen; j++) {
1723
external_readfd[j] = external_readfd[j + 1];
1724
external_readfdfunc[j] = external_readfdfunc[j + 1];
1725
external_readfd_data[j] = external_readfd_data[j + 1];
1727
DEBUGMSGTL(("unregister_readfd", "unregistered fd %d\n", fd));
1728
return FD_UNREGISTERED_OK;
1731
return FD_NO_SUCH_REGISTRATION;
1735
unregister_writefd(int fd)
1739
for (i = 0; i < external_writefdlen; i++) {
1740
if (external_writefd[i] == fd) {
1741
external_writefdlen--;
1742
for (j = i; j < external_writefdlen; j++) {
1743
external_writefd[j] = external_writefd[j + 1];
1744
external_writefdfunc[j] = external_writefdfunc[j + 1];
1745
external_writefd_data[j] = external_writefd_data[j + 1];
1747
DEBUGMSGTL(("unregister_writefd", "unregistered fd %d\n", fd));
1748
return FD_UNREGISTERED_OK;
1751
return FD_NO_SUCH_REGISTRATION;
1755
unregister_exceptfd(int fd)
1759
for (i = 0; i < external_exceptfdlen; i++) {
1760
if (external_exceptfd[i] == fd) {
1761
external_exceptfdlen--;
1762
for (j = i; j < external_exceptfdlen; j++) {
1763
external_exceptfd[j] = external_exceptfd[j + 1];
1764
external_exceptfdfunc[j] = external_exceptfdfunc[j + 1];
1765
external_exceptfd_data[j] = external_exceptfd_data[j + 1];
1767
DEBUGMSGTL(("unregister_exceptfd", "unregistered fd %d\n",
1769
return FD_UNREGISTERED_OK;
1772
return FD_NO_SUCH_REGISTRATION;
1775
int external_signal_scheduled[NUM_EXTERNAL_SIGS];
1776
void (*external_signal_handler[NUM_EXTERNAL_SIGS]) (int);
1781
* TODO: add agent_SIGXXX_handler functions and `case SIGXXX: ...' lines
1782
* below for every single that might be handled by register_signal().
1786
agent_SIGCHLD_handler(int sig)
1788
external_signal_scheduled[SIGCHLD]++;
1789
#ifndef HAVE_SIGACTION
1791
* signal() sucks. It *might* have SysV semantics, which means that
1792
* * a signal handler is reset once it gets called. Ensure that it
1795
signal(SIGCHLD, agent_SIGCHLD_handler);
1800
register_signal(int sig, void (*func) (int))
1804
#if defined(SIGCHLD)
1806
#ifdef HAVE_SIGACTION
1808
static struct sigaction act;
1809
act.sa_handler = agent_SIGCHLD_handler;
1810
sigemptyset(&act.sa_mask);
1812
sigaction(SIGCHLD, &act, NULL);
1815
signal(SIGCHLD, agent_SIGCHLD_handler);
1821
"register_signal: signal %d cannot be handled\n", sig);
1822
return SIG_REGISTRATION_FAILED;
1825
external_signal_handler[sig] = func;
1826
external_signal_scheduled[sig] = 0;
1828
DEBUGMSGTL(("register_signal", "registered signal %d\n", sig));
1829
return SIG_REGISTERED_OK;
1833
unregister_signal(int sig)
1835
signal(sig, SIG_DFL);
1836
DEBUGMSGTL(("unregister_signal", "unregistered signal %d\n", sig));
1837
return SIG_UNREGISTERED_OK;