1 /* Portions of this file are subject to the following copyright(s).  See
2  * the Net-SNMP's COPYING file for more details and other copyrights
3  * that may apply:
4  */
5 /*
6  * Portions of this file are copyrighted by:
7  * Copyright (C) 2007 Apple, Inc. All rights reserved.
8  * Use is subject to license terms specified in the COPYING file
9  * distributed with the Net-SNMP package.
10  *
11  * Portions of this file are copyrighted by:
12  * Copyright (c) 2016 VMware, Inc. All rights reserved.
13  * Use is subject to license terms specified in the COPYING file
14  * distributed with the Net-SNMP package.
15  */
16 #include <net-snmp/net-snmp-config.h>
17 #include <net-snmp/net-snmp-features.h>
18 #include <net-snmp/net-snmp-includes.h>
19 #include <net-snmp/library/container.h>
20 #include <net-snmp/library/container_binary_array.h>
21 #include <net-snmp/library/container_list_ssll.h>
22 #include <net-snmp/library/container_null.h>
23 
24 #include <stdint.h>
25 
26 netsnmp_feature_child_of(container_all, libnetsnmp);
27 
28 netsnmp_feature_child_of(container_factories, container_all);
29 netsnmp_feature_child_of(container_types, container_all);
30 netsnmp_feature_child_of(container_compare, container_all);
31 netsnmp_feature_child_of(container_dup, container_all);
32 netsnmp_feature_child_of(container_free_all, container_all);
33 netsnmp_feature_child_of(subcontainer_find, container_all);
34 
35 netsnmp_feature_child_of(container_ncompare_cstring, container_compare);
36 netsnmp_feature_child_of(container_compare_mem, container_compare);
37 netsnmp_feature_child_of(container_compare_long, container_compare);
38 netsnmp_feature_child_of(container_compare_ulong, container_compare);
39 netsnmp_feature_child_of(container_compare_int32, container_compare);
40 netsnmp_feature_child_of(container_compare_uint32, container_compare);
41 
42 netsnmp_feature_child_of(container_find_factory, container_factories);
43 
44 /** @defgroup container container
45  */
46 
47 /*------------------------------------------------------------------
48  */
49 static netsnmp_container *containers = NULL;
50 
51 typedef struct container_type_s {
52    const char                 *name;
53    netsnmp_factory            *factory;
54    netsnmp_container_compare  *compare;
55 } container_type;
56 
57 netsnmp_factory *
58 netsnmp_container_get_factory(const char *type);
59 
60 /*------------------------------------------------------------------
61  */
62 static void
_factory_free(void * dat,void * context)63 _factory_free(void *dat, void *context)
64 {
65     container_type *data = (container_type *)dat;
66     if (data == NULL)
67 	return;
68 
69     if (data->name != NULL) {
70         DEBUGMSGTL(("container", "  _factory_free_list() called for %s\n",
71                     data->name));
72 	free(NETSNMP_REMOVE_CONST(void *, data->name)); /* SNMP_FREE wasted on object about to be freed */
73     }
74     free(data); /* SNMP_FREE wasted on param */
75 }
76 
77 /*------------------------------------------------------------------
78  */
79 void
netsnmp_container_init_list(void)80 netsnmp_container_init_list(void)
81 {
82     if (NULL != containers)
83         return;
84 
85     /*
86      * create a binary arry container to hold container
87      * factories
88      */
89     containers = netsnmp_container_get_binary_array();
90     containers->compare = netsnmp_compare_cstring;
91     containers->container_name = strdup("container list");
92 
93     /*
94      * register containers
95      */
96     netsnmp_container_binary_array_init();
97 #ifndef NETSNMP_FEATURE_REMOVE_CONTAINER_LINKED_LIST
98     netsnmp_container_ssll_init();
99 #endif /* NETSNMP_FEATURE_REMOVE_CONTAINER_LINKED_LIST */
100 #ifndef NETSNMP_FEATURE_REMOVE_CONTAINER_NULL
101     netsnmp_container_null_init();
102 #endif /* NETSNMP_FEATURE_REMOVE_CONTAINER_NULL */
103 
104     /*
105      * default aliases for some containers
106      */
107     netsnmp_container_register("table_container",
108                                netsnmp_container_get_factory("binary_array"));
109 
110 #ifndef NETSNMP_FEATURE_REMOVE_CONTAINER_LINKED_LIST
111     netsnmp_container_register("linked_list",
112                                netsnmp_container_get_factory("sorted_singly_linked_list"));
113     netsnmp_container_register("ssll_container",
114                                netsnmp_container_get_factory("sorted_singly_linked_list"));
115 #endif /* NETSNMP_FEATURE_REMOVE_CONTAINER_LINKED_LIST */
116 
117     netsnmp_container_register_with_compare
118         ("cstring", netsnmp_container_get_factory("binary_array"),
119          netsnmp_compare_direct_cstring);
120 
121     netsnmp_container_register_with_compare
122         ("string", netsnmp_container_get_factory("binary_array"),
123          netsnmp_compare_cstring);
124     netsnmp_container_register_with_compare
125         ("string_binary_array", netsnmp_container_get_factory("binary_array"),
126          netsnmp_compare_cstring);
127 
128 }
129 
130 void
netsnmp_container_free_list(void)131 netsnmp_container_free_list(void)
132 {
133     DEBUGMSGTL(("container", "netsnmp_container_free_list() called\n"));
134     if (containers == NULL)
135 	return;
136 
137     /*
138      * free memory used by each factory entry
139      */
140     CONTAINER_FOR_EACH(containers, ((netsnmp_container_obj_func *)_factory_free), NULL);
141 
142     /*
143      * free factory container
144      */
145     CONTAINER_FREE(containers);
146     containers = NULL;
147 }
148 
149 int
netsnmp_container_register_with_compare(const char * name,netsnmp_factory * f,netsnmp_container_compare * c)150 netsnmp_container_register_with_compare(const char* name, netsnmp_factory *f,
151                                         netsnmp_container_compare  *c)
152 {
153     container_type *ct, tmp;
154 
155     if (NULL==containers)
156         return -1;
157 
158     tmp.name = NETSNMP_REMOVE_CONST(char *, name);
159     ct = (container_type *)CONTAINER_FIND(containers, &tmp);
160     if (NULL!=ct) {
161         DEBUGMSGT(("container_registry",
162                    "replacing previous container factory\n"));
163         ct->factory = f;
164     }
165     else {
166         ct = SNMP_MALLOC_TYPEDEF(container_type);
167         if (NULL == ct)
168             return -1;
169         ct->name = strdup(name);
170         ct->factory = f;
171         ct->compare = c;
172         CONTAINER_INSERT(containers, ct);
173     }
174     DEBUGMSGT(("container_registry", "registered container factory %s (%s)\n",
175                ct->name, f->product));
176 
177     return 0;
178 }
179 
180 int
netsnmp_container_register(const char * name,netsnmp_factory * f)181 netsnmp_container_register(const char* name, netsnmp_factory *f)
182 {
183     return netsnmp_container_register_with_compare(name, f, NULL);
184 }
185 
186 /*------------------------------------------------------------------
187  */
188 netsnmp_factory *
netsnmp_container_get_factory(const char * type)189 netsnmp_container_get_factory(const char *type)
190 {
191     container_type ct, *found;
192 
193     if (NULL==containers)
194         return NULL;
195 
196     ct.name = type;
197     found = (container_type *)CONTAINER_FIND(containers, &ct);
198 
199     return found ? found->factory : NULL;
200 }
201 
202 #ifndef NETSNMP_FEATURE_REMOVE_CONTAINER_FIND_FACTORY
203 netsnmp_factory *
netsnmp_container_find_factory(const char * type_list)204 netsnmp_container_find_factory(const char *type_list)
205 {
206     netsnmp_factory   *f = NULL;
207     char              *list, *entry;
208     char              *st = NULL;
209 
210     if (NULL==type_list)
211         return NULL;
212 
213     list = strdup(type_list);
214     if (!list)
215         return NULL;
216     entry = strtok_r(list, ":", &st);
217     while (entry) {
218         f = netsnmp_container_get_factory(entry);
219         if (NULL != f)
220             break;
221         entry = strtok_r(NULL, ":", &st);
222     }
223 
224     free(list);
225     return f;
226 }
227 #endif /* NETSNMP_FEATURE_REMOVE_CONTAINER_FIND_FACTORY */
228 
229 /*------------------------------------------------------------------
230  */
231 static container_type *
netsnmp_container_get_ct(const char * type)232 netsnmp_container_get_ct(const char *type)
233 {
234     container_type ct;
235 
236     if (NULL == containers)
237         return NULL;
238 
239     ct.name = type;
240     return (container_type *)CONTAINER_FIND(containers, &ct);
241 }
242 
243 static container_type *
netsnmp_container_find_ct(const char * type_list)244 netsnmp_container_find_ct(const char *type_list)
245 {
246     container_type    *ct = NULL;
247     char              *list, *entry;
248     char              *st = NULL;
249 
250     if (NULL==type_list)
251         return NULL;
252 
253     list = strdup(type_list);
254     if (!list)
255         return NULL;
256     entry = strtok_r(list, ":", &st);
257     while (entry) {
258         ct = netsnmp_container_get_ct(entry);
259         if (NULL != ct)
260             break;
261         entry = strtok_r(NULL, ":", &st);
262     }
263 
264     free(list);
265     return ct;
266 }
267 
268 
269 
270 /*------------------------------------------------------------------
271  */
272 netsnmp_container *
netsnmp_container_get(const char * type)273 netsnmp_container_get(const char *type)
274 {
275     netsnmp_container *c;
276     container_type *ct = netsnmp_container_get_ct(type);
277     if (ct) {
278         c = (netsnmp_container *)(ct->factory->produce());
279         if (c && ct->compare)
280             c->compare = ct->compare;
281         return c;
282     }
283 
284     return NULL;
285 }
286 
287 /*------------------------------------------------------------------
288  */
289 netsnmp_container *
netsnmp_container_find(const char * type)290 netsnmp_container_find(const char *type)
291 {
292     container_type *ct = netsnmp_container_find_ct(type);
293     netsnmp_container *c = ct ? (netsnmp_container *)(ct->factory->produce()) : NULL;
294 
295     /*
296      * provide default compare
297      */
298     if (c) {
299         if (ct->compare)
300             c->compare = ct->compare;
301         else if (NULL == c->compare)
302             c->compare = netsnmp_compare_netsnmp_index;
303     }
304 
305     return c;
306 }
307 
308 /*------------------------------------------------------------------
309  */
310 void
netsnmp_container_add_index(netsnmp_container * primary,netsnmp_container * new_index)311 netsnmp_container_add_index(netsnmp_container *primary,
312                             netsnmp_container *new_index)
313 {
314     netsnmp_container *curr = primary;
315 
316     if((NULL == new_index) || (NULL == primary)) {
317         snmp_log(LOG_ERR, "add index called with null pointer\n");
318         return;
319     }
320 
321     while(curr->next)
322         curr = curr->next;
323 
324     curr->next = new_index;
325     new_index->prev = curr;
326 }
327 
CONTAINER_INSERT_HELPER(netsnmp_container * x,const void * k)328 int CONTAINER_INSERT_HELPER(netsnmp_container* x, const void* k)
329 {
330     while(x && x->insert_filter && x->insert_filter(x,k) == 1)
331         x = x->next;
332     if(x) {
333         int rc = x->insert(x,k);
334         if(rc)
335             snmp_log(LOG_DEBUG,"error on subcontainer '%s' insert (%d)\n",
336                      x->container_name ? x->container_name : "", rc);
337         else {
338             rc = CONTAINER_INSERT_HELPER(x->next, k);
339             if(rc)
340                 x->remove(x,k);
341         }
342         return rc;
343     }
344     return 0;
345 }
346 
CONTAINER_INSERT(netsnmp_container * x,const void * k)347 int CONTAINER_INSERT(netsnmp_container* x, const void* k)
348 {
349     /** start at first container */
350     while(x->prev)
351         x = x->prev;
352     return CONTAINER_INSERT_HELPER(x, k);
353 }
354 
CONTAINER_INSERT_BEFORE(netsnmp_container * x,size_t pos,void * k)355 int CONTAINER_INSERT_BEFORE(netsnmp_container *x, size_t pos, void *k)
356 {
357     int rc = 0;
358 
359     if (NULL == x || NULL == x->insert_before) {
360         snmp_log(LOG_ERR, "container '%s' does not support insert_before\n",
361                  x && x->container_name ? x->container_name : "");
362         return -1;
363     }
364 
365     rc = x->insert_before(x, pos, k);
366     if (rc < 0)
367         snmp_log(LOG_ERR, "error on container '%s' insert_before %" NETSNMP_PRIz "d (%d)\n",
368                  x->container_name ? x->container_name : "", pos, rc);
369 
370     return rc;
371 }
372 
CONTAINER_REMOVE(netsnmp_container * x,const void * k)373 int CONTAINER_REMOVE(netsnmp_container *x, const void *k)
374 {
375     int rc2, rc = 0;
376 
377     /** start at last container */
378     while(x->next)
379         x = x->next;
380     while(x) {
381         rc2 = x->remove(x,k);
382         /** ignore remove errors if there is a filter in place */
383         if ((rc2) && (NULL == x->insert_filter)) {
384             snmp_log(LOG_ERR,"error on subcontainer '%s' remove (%d)\n",
385                      x->container_name ? x->container_name : "", rc2);
386             rc = rc2;
387         }
388         x = x->prev;
389 
390     }
391     return rc;
392 }
393 
CONTAINER_REMOVE_AT(netsnmp_container * x,size_t pos,void ** k)394 int CONTAINER_REMOVE_AT(netsnmp_container *x, size_t pos, void **k)
395 {
396     int rc = 0;
397     netsnmp_container *orig = x;
398 
399     if (NULL == x || NULL == x->remove_at) {
400         snmp_log(LOG_ERR, "container '%s' does not support REMOVE_AT\n",
401                  x && x->container_name ? x->container_name : "");
402         return -1;
403     }
404 
405     /** start at given container */
406     rc = x->remove_at(x, pos, k);
407     if (rc < 0) {
408         snmp_log(LOG_ERR, "error on container '%s' remove_at %" NETSNMP_PRIz "d (%d)\n",
409                  x->container_name ? x->container_name : "", pos, rc);
410         return rc;
411     } else if (NULL == k || NULL == *k)
412         return rc;
413 
414     /** remove k from any other containers */
415     while(x->prev)
416         x = x->prev;
417     for(; x; x = x->next) {
418         if (x == orig)
419             continue;
420         x->remove(x,*k); /** ignore remove errors in other containers */
421     }
422     return rc;
423 }
424 
CONTAINER_GET_AT(netsnmp_container * x,size_t pos,void ** k)425 int CONTAINER_GET_AT(netsnmp_container *x, size_t pos, void **k)
426 {
427     int rc = 0;
428 
429     if (NULL == x || NULL == x->get_at) {
430         snmp_log(LOG_ERR, "container '%s' does not support GET_AT\n",
431                  x && x->container_name ? x->container_name : "");
432         return -1;
433     }
434 
435     /** start at given container */
436     rc = x->get_at(x, pos, k);
437     if (rc < 0)
438         snmp_log(LOG_ERR, "error on container '%s' get_at %" NETSNMP_PRIz "d (%d)\n",
439                  x->container_name ? x->container_name : "", pos, rc);
440 
441     return rc;
442 }
443 
444 #ifndef NETSNMP_FEATURE_REMOVE_CONTAINER_DUP
CONTAINER_DUP(netsnmp_container * x,void * ctx,u_int flags)445 netsnmp_container *CONTAINER_DUP(netsnmp_container *x, void *ctx, u_int flags)
446 {
447     if (NULL == x->duplicate) {
448         snmp_log(LOG_ERR, "container '%s' does not support duplicate\n",
449                  x->container_name ? x->container_name : "");
450         return NULL;
451     }
452     return x->duplicate(x, ctx, flags);
453 }
454 #endif /* NETSNMP_FEATURE_REMOVE_CONTAINER_DUP */
455 
CONTAINER_FREE(netsnmp_container * x)456 int CONTAINER_FREE(netsnmp_container *x)
457 {
458     int  rc2, rc = 0;
459 
460     if (!x)
461         return rc;
462 
463     /** start at last container */
464     while(x->next)
465         x = x->next;
466     while(x) {
467         netsnmp_container *tmp;
468         char *name;
469         tmp = x->prev;
470         name = x->container_name;
471         x->container_name = NULL;
472         rc2 = x->cfree(x);
473         if (rc2) {
474             snmp_log(LOG_ERR,"error on subcontainer '%s' cfree (%d)\n",
475                      name ? name : "", rc2);
476             rc = rc2;
477         }
478         SNMP_FREE(name);
479         x = tmp;
480     }
481     return rc;
482 }
483 
484 /*
485  * clear all containers. When clearing the *first* container, and
486  * *only* the first container, call the function f for each item.
487  * After calling this function, all containers should be empty.
488  */
CONTAINER_CLEAR(netsnmp_container * x,netsnmp_container_obj_func * f,void * c)489 void CONTAINER_CLEAR(netsnmp_container *x, netsnmp_container_obj_func *f,
490                     void *c)
491 {
492     /** start at last container */
493     while(x->next)
494         x = x->next;
495     while(x->prev) {
496         x->clear(x, NULL, c);
497         x = x->prev;
498     }
499     x->clear(x, f, c);
500 }
501 
502 #ifndef NETSNMP_FEATURE_REMOVE_CONTAINER_FREE_ALL
503 /*
504  * clear all containers. When clearing the *first* container, and
505  * *only* the first container, call the free_item function for each item.
506  * After calling this function, all containers should be empty.
507  */
CONTAINER_FREE_ALL(netsnmp_container * x,void * c)508 void CONTAINER_FREE_ALL(netsnmp_container *x, void *c)
509 {
510     CONTAINER_CLEAR(x, x->free_item, c);
511 }
512 #endif /* NETSNMP_FEATURE_REMOVE_CONTAINER_FREE_ALL */
513 
514 #ifndef NETSNMP_FEATURE_REMOVE_SUBCONTAINER_FIND
515 /*
516  * Find a sub-container with the given name
517  */
SUBCONTAINER_FIND(netsnmp_container * x,const char * name)518 netsnmp_container *SUBCONTAINER_FIND(netsnmp_container *x,
519                                      const char* name)
520 {
521     if ((NULL == x) || (NULL == name))
522         return NULL;
523 
524     /** start at first container */
525     while(x->prev)
526         x = x->prev;
527     while(x) {
528         if ((NULL != x->container_name) && (0 == strcmp(name,x->container_name)))
529             break;
530         x = x->next;
531     }
532     return x;
533 }
534 #endif /* NETSNMP_FEATURE_REMOVE_SUBCONTAINER_FIND */
535 
536 
537 /*------------------------------------------------------------------
538  */
539 void
netsnmp_init_container(netsnmp_container * c,netsnmp_container_rc * init,netsnmp_container_rc * cfree,netsnmp_container_size * size,netsnmp_container_compare * cmp,netsnmp_container_op * ins,netsnmp_container_op * rem,netsnmp_container_rtn * fnd)540 netsnmp_init_container(netsnmp_container         *c,
541                        netsnmp_container_rc      *init,
542                        netsnmp_container_rc      *cfree,
543                        netsnmp_container_size    *size,
544                        netsnmp_container_compare *cmp,
545                        netsnmp_container_op      *ins,
546                        netsnmp_container_op      *rem,
547                        netsnmp_container_rtn     *fnd)
548 {
549     if (c == NULL)
550         return;
551 
552     c->init = init;
553     c->cfree = cfree;
554     c->get_size = size;
555     c->compare = cmp;
556     c->insert = ins;
557     c->remove = rem;
558     c->find = fnd;
559     c->free_item = netsnmp_container_simple_free;
560 }
561 
562 int
netsnmp_container_data_dup(netsnmp_container * dup,netsnmp_container * c)563 netsnmp_container_data_dup(netsnmp_container *dup, netsnmp_container *c)
564 {
565     if (!dup || !c)
566         return -1;
567 
568     if (c->container_name)
569         dup->container_name = strdup(c->container_name);
570     dup->compare = c->compare;
571     dup->ncompare = c->ncompare;
572     dup->release = c->release;
573     dup->insert_filter = c->insert_filter;
574     dup->free_item = c->free_item;
575     dup->sync = c->sync;
576     dup->flags = c->flags;
577 
578     return 0;
579 }
580 
581 /*------------------------------------------------------------------
582  *
583  * simple comparison routines
584  *
585  */
586 int
netsnmp_compare_netsnmp_index(const void * lhs,const void * rhs)587 netsnmp_compare_netsnmp_index(const void *lhs, const void *rhs)
588 {
589     int rc;
590     netsnmp_assert((NULL != lhs) && (NULL != rhs));
591     DEBUGIF("compare:index") {
592         DEBUGMSGT(("compare:index", "compare "));
593         DEBUGMSGSUBOID(("compare:index", ((const netsnmp_index *) lhs)->oids,
594                      ((const netsnmp_index *) lhs)->len));
595         DEBUGMSG(("compare:index", " to "));
596         DEBUGMSGSUBOID(("compare:index", ((const netsnmp_index *) rhs)->oids,
597                      ((const netsnmp_index *) rhs)->len));
598         DEBUGMSG(("compare:index", "\n"));
599     }
600     rc = snmp_oid_compare(((const netsnmp_index *) lhs)->oids,
601                           ((const netsnmp_index *) lhs)->len,
602                           ((const netsnmp_index *) rhs)->oids,
603                           ((const netsnmp_index *) rhs)->len);
604     DEBUGMSGT(("compare:index", "result was %d\n", rc));
605     return rc;
606 }
607 
608 int
netsnmp_ncompare_netsnmp_index(const void * lhs,const void * rhs)609 netsnmp_ncompare_netsnmp_index(const void *lhs, const void *rhs)
610 {
611     int rc;
612     netsnmp_assert((NULL != lhs) && (NULL != rhs));
613     DEBUGIF("compare:index") {
614         DEBUGMSGT(("compare:index", "compare "));
615         DEBUGMSGSUBOID(("compare:index", ((const netsnmp_index *) lhs)->oids,
616                      ((const netsnmp_index *) lhs)->len));
617         DEBUGMSG(("compare:index", " to "));
618         DEBUGMSGSUBOID(("compare:index", ((const netsnmp_index *) rhs)->oids,
619                      ((const netsnmp_index *) rhs)->len));
620         DEBUGMSG(("compare:index", "\n"));
621     }
622     rc = snmp_oid_ncompare(((const netsnmp_index *) lhs)->oids,
623                            ((const netsnmp_index *) lhs)->len,
624                            ((const netsnmp_index *) rhs)->oids,
625                            ((const netsnmp_index *) rhs)->len,
626                            ((const netsnmp_index *) rhs)->len);
627     DEBUGMSGT(("compare:index", "result was %d\n", rc));
628     return rc;
629 }
630 
631 int
netsnmp_compare_cstring(const void * lhs,const void * rhs)632 netsnmp_compare_cstring(const void * lhs, const void * rhs)
633 {
634     return strcmp(((const container_type*)lhs)->name,
635                   ((const container_type*)rhs)->name);
636 }
637 
638 #ifndef NETSNMP_FEATURE_REMOVE_CONTAINER_NCOMPARE_CSTRING
639 int
netsnmp_ncompare_cstring(const void * lhs,const void * rhs)640 netsnmp_ncompare_cstring(const void * lhs, const void * rhs)
641 {
642     return strncmp(((const container_type*)lhs)->name,
643                    ((const container_type*)rhs)->name,
644                    strlen(((const container_type*)rhs)->name));
645 }
646 #endif /* NETSNMP_FEATURE_REMOVE_CONTAINER_NCOMPARE_CSTRING */
647 
648 int
netsnmp_compare_direct_cstring(const void * lhs,const void * rhs)649 netsnmp_compare_direct_cstring(const void * lhs, const void * rhs)
650 {
651     return strcmp((const char*)lhs, (const char*)rhs);
652 }
653 
654 /*
655  * compare two memory buffers
656  *
657  * since snmp strings aren't NULL terminated, we can't use strcmp. So
658  * compare up to the length of the smaller, and then use length to
659  * break any ties.
660  */
661 #ifndef NETSNMP_FEATURE_REMOVE_CONTAINER_COMPARE_MEM
662 int
netsnmp_compare_mem(const char * lhs,size_t lhs_len,const char * rhs,size_t rhs_len)663 netsnmp_compare_mem(const char * lhs, size_t lhs_len,
664                     const char * rhs, size_t rhs_len)
665 {
666     int rc, min = SNMP_MIN(lhs_len, rhs_len);
667 
668     rc = memcmp(lhs, rhs, min);
669     if((rc==0) && (lhs_len != rhs_len)) {
670         if(lhs_len < rhs_len)
671             rc = -1;
672         else
673             rc = 1;
674     }
675 
676     return rc;
677 }
678 #endif /* NETSNMP_FEATURE_REMOVE_CONTAINER_COMPARE_MEM */
679 
680 #ifndef NETSNMP_FEATURE_REMOVE_CONTAINER_COMPARE_LONG
681 int
netsnmp_compare_long(const void * lhs,const void * rhs)682 netsnmp_compare_long(const void * lhs, const void * rhs)
683 {
684     typedef struct { long index; } dummy;
685 
686     const dummy *lhd = (const dummy*)lhs;
687     const dummy *rhd = (const dummy*)rhs;
688 
689     if (lhd->index < rhd->index)
690         return -1;
691     else if (lhd->index > rhd->index)
692         return 1;
693 
694     return 0;
695 }
696 #endif /* NETSNMP_FEATURE_REMOVE_CONTAINER_COMPARE_LONG */
697 
698 #ifndef NETSNMP_FEATURE_REMOVE_CONTAINER_COMPARE_ULONG
699 int
netsnmp_compare_ulong(const void * lhs,const void * rhs)700 netsnmp_compare_ulong(const void * lhs, const void * rhs)
701 {
702     typedef struct { u_long index; } dummy;
703 
704     const dummy *lhd = (const dummy*)lhs;
705     const dummy *rhd = (const dummy*)rhs;
706 
707     if (lhd->index < rhd->index)
708         return -1;
709     else if (lhd->index > rhd->index)
710         return 1;
711 
712     return 0;
713 }
714 #endif /* NETSNMP_FEATURE_REMOVE_CONTAINER_COMPARE_ULONG */
715 
716 #ifndef NETSNMP_FEATURE_REMOVE_CONTAINER_COMPARE_INT32
717 int
netsnmp_compare_int32(const void * lhs,const void * rhs)718 netsnmp_compare_int32(const void * lhs, const void * rhs)
719 {
720     typedef struct { int32_t index; } dummy;
721 
722     const dummy *lhd = (const dummy*)lhs;
723     const dummy *rhd = (const dummy*)rhs;
724 
725     if (lhd->index < rhd->index)
726         return -1;
727     else if (lhd->index > rhd->index)
728         return 1;
729 
730     return 0;
731 }
732 #endif /* NETSNMP_FEATURE_REMOVE_CONTAINER_COMPARE_INT32 */
733 
734 #ifndef NETSNMP_FEATURE_REMOVE_CONTAINER_COMPARE_UINT32
735 int
netsnmp_compare_uint32(const void * lhs,const void * rhs)736 netsnmp_compare_uint32(const void * lhs, const void * rhs)
737 {
738     typedef struct { uint32_t index; } dummy;
739 
740     const dummy *lhd = (const dummy*)lhs;
741     const dummy *rhd = (const dummy*)rhs;
742 
743     if (lhd->index < rhd->index)
744         return -1;
745     else if (lhd->index > rhd->index)
746         return 1;
747 
748     return 0;
749 }
750 #endif /* NETSNMP_FEATURE_REMOVE_CONTAINER_COMPARE_UINT32 */
751 
752 /*------------------------------------------------------------------
753  * netsnmp_container_simple_free
754  *
755  * useful function to pass to CONTAINER_FOR_EACH, when a simple
756  * free is needed for every item.
757  */
758 void
netsnmp_container_simple_free(void * data,void * context)759 netsnmp_container_simple_free(void *data, void *context)
760 {
761     if (data == NULL)
762 	return;
763 
764     DEBUGMSGTL(("verbose:container",
765                 "netsnmp_container_simple_free) called for %p/%p\n",
766                 data, context));
767     free((void*)data); /* SNMP_FREE wasted on param */
768 }
769