diff options
| -rw-r--r-- | daemon/snmp-help.c | 168 | ||||
| -rw-r--r-- | mib/parse-compat.inc.c | 241 | ||||
| -rw-r--r-- | tools/Makefile.am | 13 | ||||
| -rw-r--r-- | tools/rrdbot-get.c | 393 | 
4 files changed, 405 insertions, 410 deletions
| diff --git a/daemon/snmp-help.c b/daemon/snmp-help.c deleted file mode 100644 index 31f8dc6..0000000 --- a/daemon/snmp-help.c +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright (c) 2005, Nate Nielsen - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - *     * Redistributions of source code must retain the above - *       copyright notice, this list of conditions and the - *       following disclaimer. - *     * Redistributions in binary form must reproduce the - *       above copyright notice, this list of conditions and - *       the following disclaimer in the documentation and/or - *       other materials provided with the distribution. - *     * The names of contributors to this software may not be - *       used to endorse or promote products derived from this - *       software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * - * CONTRIBUTORS - *  Nate Nielsen <nielsen@memberwebs.com> - * - */ - -#include "usuals.h" -#include <errno.h> -#include <syslog.h> - -#include <bsnmp/asn1.h> -#include <bsnmp/snmp.h> - -#include "rrdbotd.h" - -/* Whether we print warnings when loading MIBs or not */ -extern int g_mib_warnings; -extern const char* g_mib_directory; - -static int -parse_mixed_mib(const char* mib, struct asn_oid* oid) -{ -    mib_node n; -    int ret = 0; -    unsigned int sub; -    char* next; -    char* t; -    char* copy; -    char* src; - -    memset(oid, 0, sizeof(*oid)); - -    copy = strdup(mib); -    if(!copy) -    { -        errno = ENOMEM; -        return -1; -    } - -    for(src = copy; src && *src; src = next) -    { -        next = strchr(src, '.'); -        if(next) -        { -            *next = 0; -            next++; -        } - -        sub = strtoul(src, &t, 10); - -        /* An invalid number, try getting a named MIB */ -        if(*t || sub < 0) -        { -            /* Only initializes first time around */ -            rb_mib_init(g_mib_directory, g_mib_warnings); - -            /* -             * If we haven't parsed anything yet, try a symbolic -             * search for root -             */ - -            if(oid->len == 0) -            { -                n = rb_mib_lookup(src); -                if(n) -                { -                    /* That took care of it */ -                    rb_mib_oid(n, oid); -                    continue; -                } -            } - -            /* Try a by name search for sub item */ -            n = rb_mib_node(oid); -            if(n == NULL) -                sub = -1; -            else -                sub = rb_mib_subid(n, src); -        } - -        /* Make sure this is a valid part */ -        if(sub < 0 || (oid->len == 0 && sub < 1) || sub >= ASN_MAXID) -            ret = -1; - -        /* Too many parts */ -        if(oid->len > ASN_MAXOIDLEN) -            ret = -1; - -        if(ret < 0) -            break; - -        oid->subs[oid->len] = sub; -        oid->len++; -    } - -    free(copy); -    return ret; -} - -int -rb_snmp_parse_mib(const char* mib, struct snmp_value* value) -{ -    int ret; -    mib_node n; - -    value->syntax = SNMP_SYNTAX_NULL; -    memset(&(value->v), 0, sizeof(value->v)); - -    /* An initial dot */ -    if(*mib == '.') -        mib++; - -    /* -     * First try parsing a numeric OID. This will fall -     * back to mixed mode MIB's if necassary. Allows us -     * to avoid loading all the MIB files when not -     * necessary -     */ - -    ret = parse_mixed_mib(mib, &(value->var)); - -    /* Next try a symolic search */ -    if(ret == -1) -    { -        rb_mib_init(g_mib_directory, g_mib_warnings); - -        n = rb_mib_lookup(mib); -        if(n == NULL) -            return -1; - -        rb_mib_oid(n, &(value->var)); -        return 0; -    } - -    return ret; -} diff --git a/mib/parse-compat.inc.c b/mib/parse-compat.inc.c deleted file mode 100644 index 8f8fc0d..0000000 --- a/mib/parse-compat.inc.c +++ /dev/null @@ -1,241 +0,0 @@ -/* - * Copyright (c) 2005, Nate Nielsen - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - *     * Redistributions of source code must retain the above - *       copyright notice, this list of conditions and the - *       following disclaimer. - *     * Redistributions in binary form must reproduce the - *       above copyright notice, this list of conditions and - *       the following disclaimer in the documentation and/or - *       other materials provided with the distribution. - *     * The names of contributors to this software may not be - *       used to endorse or promote products derived from this - *       software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * - * CONTRIBUTORS - *  Nate Nielsen <nielsen@memberwebs.com> - * - */ - -/* - * This file is not compiled on it's own. It's included into parse.c - * and provides compatibility definitions for making it work without - * the rest of net-snmp - */ - -#include "usuals.h" -#include "rrdbotd.h" - -static int with_warnings = 0; -static int initialized = 0; - -/* ----------------------------------------------------------------------------- - * DEFINITIONS - */ - -#define FALSE 0 -#define TRUE 1 - -/* No need to implement these */ -#define DEBUGMSGTL(x) -#define set_function(tp) - -/* Just return the tree head */ -#define get_tree_head()     \ -    (tree_head) - -#define snmp_get_do_debugging()     (0) - -typedef u_long oid; - -#define NETSNMP_DS_LIBRARY_ID           0 -#define NETSNMP_DS_LIB_MIB_WARNINGS     1 -#define NETSNMP_DS_LIB_MIB_REPLACE      2 -#define NETSNMP_DS_LIB_SAVE_MIB_DESCRS  3 -#define NETSNMP_DS_LIB_MIB_ERRORS       4 -#define NETSNMP_DS_LIB_MIB_PARSE_LABEL  5 -#define NETSNMP_DS_LIB_MIB_COMMENT_TERM 6 - -#define netsnmp_ds_get_boolean(d, v) \ -    netsnmp_ds_get_int(d, v) - -static int -netsnmp_ds_get_int(int dummy, int var) -{ -    switch(var) -    { -    case NETSNMP_DS_LIB_MIB_WARNINGS: -        return with_warnings; -    case NETSNMP_DS_LIB_MIB_REPLACE: -        return 0; -    case NETSNMP_DS_LIB_SAVE_MIB_DESCRS: -        return 0; -    case NETSNMP_DS_LIB_MIB_PARSE_LABEL: -        return 1; -    case NETSNMP_DS_LIB_MIB_COMMENT_TERM: -        return 0; -    default: -        return 0; -    } -} - -#define netsnmp_ds_set_int(a, b, c) -#define netsnmp_ds_set_boolean(a, b, c) -#define netsnmp_ds_toggle_boolean(a, b) - -static void -snmp_log(int level, const char* msg, ...) -{ -    va_list ap; - -    if(level >= LOG_WARNING && !with_warnings) -        return; - -    va_start(ap, msg); -    rb_vmessage(level, 0, msg, ap); -    va_end(ap); -} - -/* Only used to open files */ -static void -snmp_log_perror(const char* file) -{ -    rb_message(LOG_ERR, "couldn't open file: %s", file); -} - -#define SNMP_FREE(s)           do { if (s) { free((void *)s); s=NULL; } } while(0) - -/* ----------------------------------------------------------------------------- - * RRDBOT GLUE CODE - */ - -static void -clear_tree_flags(struct tree *tp) -{ -    for( ; tp; tp = tp->next_peer) -    { -        tp->reported = 0; -        if(tp->child_list) -            clear_tree_flags(tp->child_list); -    } -} - -void -rb_mib_init(const char* dir, int warnings) -{ -    if(initialized) -        return; - -    with_warnings = warnings; - -    init_mib_internals(); -    add_mibdir(dir); -    read_all_mibs(); - -    rb_messagex(LOG_DEBUG, "loaded all MIB files"); -    initialized = 1; -} - -mib_node -rb_mib_lookup(const char* match) -{ -    extern struct tree *tree_head; -    struct tree* mib; - -    ASSERT(initialized); - -    clear_tree_flags(tree_head); -    mib = find_best_tree_node(match, NULL, NULL); -    return (mib_node)mib; -} - -int -rb_mib_subid(mib_node n, const char* name) -{ -    struct tree *parent = (struct tree*)n; -    struct tree *tp = NULL; - -    ASSERT(initialized); - -    for(tp = parent->child_list; tp; tp = tp->next_peer) -    { -        if(strcasecmp(name, tp->label) == 0) -            return tp->subid; -    } - -    return -1; -} - -void -rb_mib_oid(mib_node n, struct asn_oid* oid) -{ -    struct tree* mib = (struct tree*)n; -    struct tree *tp = NULL; -    int len; - -    ASSERT(mib); - -    /* Figure out where to start */ -    len = 0; -    for(tp = mib; tp; tp = tp->parent) -        len++; - -    oid->len = len; -    for(tp = mib; tp; tp = tp->parent) -        oid->subs[--len] = tp->subid; -} - -mib_node -rb_mib_node(struct asn_oid* oid) -{ -    extern struct tree *tree_head; -    struct tree *tp = NULL; -    asn_subid_t subid; -    int i; - -    ASSERT(initialized); - -    for(i = 0, tp = tree_head; tp && i < oid->len; -        i++, tp = tp ? tp->child_list : NULL) -    { -        subid = oid->subs[i]; - -        while(tp && tp->subid != subid) -            tp = tp->next_peer; - -        /* Did we find a match? */ -        if(tp && i == oid->len - 1) -            break; -    } - -    return tp; -} - -void -rb_mib_uninit() -{ -    if(initialized) { -        unload_all_mibs(); -        rb_messagex(LOG_DEBUG, "unloaded all MIB files"); -    } -    initialized = 0; -} diff --git a/tools/Makefile.am b/tools/Makefile.am index 94dfa06..a2185ab 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -1,8 +1,19 @@ -sbin_PROGRAMS = rrdbot-create +sbin_PROGRAMS = rrdbot-create rrdbot-get  rrdbot_create_SOURCES = rrdbot-create.c ../common/usuals.h \                  ../common/config-parser.h ../common/config-parser.c \                  ../common/compat.h ../common/compat.c  rrdbot_create_CFLAGS = -I${top_srcdir}/common/ -I${top_srcdir} \                  -DCONF_PREFIX=\"$(sysconfdir)\" -DDATA_PREFIX=\"$(datadir)\" + +rrdbot_get_SOURCES = rrdbot-get.c ../common/usuals.h \ +                ../common/compat.h ../common/compat.c \ +                ../common/config-parser.h ../common/config-parser.c \ +                ../common/server-mainloop.h ../common/server-mainloop.c \ +                ../common/sock-any.h ../common/sock-any.c \ +                ../mib/mib-parser.c ../mib/mib-parser.h \ +                ../bsnmp/asn1.h ../bsnmp/asn1.c \ +                ../bsnmp/snmp.h ../bsnmp/snmp.c +rrdbot_get_CFLAGS = -I${top_srcdir}/common/ -I${top_srcdir} \ +                -DCONF_PREFIX=\"$(sysconfdir)\" -DDATA_PREFIX=\"$(datadir)\" diff --git a/tools/rrdbot-get.c b/tools/rrdbot-get.c new file mode 100644 index 0000000..3abdc77 --- /dev/null +++ b/tools/rrdbot-get.c @@ -0,0 +1,393 @@ +/* + * Copyright (c) 2005, Nate Nielsen + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + *     * Redistributions of source code must retain the above + *       copyright notice, this list of conditions and the + *       following disclaimer. + *     * Redistributions in binary form must reproduce the + *       above copyright notice, this list of conditions and + *       the following disclaimer in the documentation and/or + *       other materials provided with the distribution. + *     * The names of contributors to this software may not be + *       used to endorse or promote products derived from this + *       software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * + * CONTRIBUTORS + *  Nate Nielsen <nielsen@memberwebs.com> + * + */ + +#include "usuals.h" +#include <errno.h> +#include <unistd.h> +#include <syslog.h> +#include <err.h> + +#include <bsnmp/asn1.h> +#include <bsnmp/snmp.h> +#include <mib/mib-parser.h> + +#include "sock-any.h" +#include "server-mainloop.h" +#include "config-parser.h" + +/* The socket to use */ +static int snmp_socket = -1; + +/* Since we only deal with one packet at a time, global buffer */ +static unsigned char snmp_buffer[0x1000]; + +/* The actual request data */ +static struct snmp_pdu snmp_data; + +/* The first OID we've done */ +static struct asn_oid oid_first; + +/* The remote host */ +static struct sockaddr_any snmp_hostaddr; +static char* snmp_hostname = NULL; + +static int retries = 0; + +/* Whether we're going recursive or not */ +static int recursive = 0; + +/* ----------------------------------------------------------------------------- + * DUMMY CONFIG FUNCTIONS + */ + +int +cfg_value(const char* filename, const char* header, const char* name, +          char* value, void* data) +{ +    return 0; +} + +int +cfg_error(const char* filename, const char* errmsg, void* data) +{ +    return 0; +} + +/* ----------------------------------------------------------------------------- + * SNMP ENGINE + */ + +static void +send_req() +{ +    struct asn_buf b; +    ssize_t ret; + +    b.asn_ptr = snmp_buffer; +    b.asn_len = sizeof(snmp_buffer); + +    if(snmp_pdu_encode(&snmp_data, &b)) +        errx(1, "couldn't encode snmp buffer"); + +    ret = sendto(snmp_socket, snmp_buffer, b.asn_ptr - snmp_buffer, 0, +                 &SANY_ADDR(snmp_hostaddr), SANY_LEN(snmp_hostaddr)); +    if(ret == -1) +        err(1, "couldn't send snmp packet to: %s", snmp_hostname); + +} + +static void +setup_req(char* uri) +{ +    const char* msg; +    char* scheme; +    char* copy; +    char* user; +    char* path; + +    /* Parse the SNMP URI */ +    copy = strdup(uri); +    msg = cfg_parse_uri(uri, &scheme, &snmp_hostname, &user, &path); +    if(msg) +        errx(2, "%s: %s", msg, copy); +    free(copy); + +    ASSERT(host && path); + +    /* Currently we only support SNMP pollers */ +    if(strcmp(scheme, "snmp") != 0) +        errx(2, "invalid scheme: %s", scheme); + +    if(sock_any_pton(snmp_hostname, &snmp_hostaddr, +                     SANY_OPT_DEFPORT(161) | SANY_OPT_DEFLOCAL) == -1) +        err(1, "couldn't resolve host address (ignoring): %s", snmp_hostname); + +    memset(&snmp_data, 0, sizeof(snmp_data)); +    snmp_data.version = 1; +    snmp_data.request_id = 0; +    snmp_data.type = recursive ? SNMP_PDU_GETNEXT : SNMP_PDU_GET; +    snmp_data.error_status = 0; +    snmp_data.error_index = 0; +    strlcpy(snmp_data.community, user ? user : "public", +            sizeof(snmp_data.community)); + + +    /* And parse the OID */ +    snmp_data.bindings[0].syntax = 0; +    if(mib_parse(path, &(snmp_data.bindings[0])) == -1) +        errx(2, "invalid MIB: %s", path); + +    /* Add an item to this request */ +    snmp_data.nbindings = 1; + +    /* Keep track of top for recursiveness */ +    memcpy(&oid_first, &(snmp_data.bindings[0].var), sizeof(oid_first)); + +} + +static void +setup_next(struct snmp_value* value) +{ +    snmp_data.request_id++; +    snmp_data.type = SNMP_PDU_GETNEXT; + +    /* And parse the OID */ +    memcpy(&(snmp_data.bindings[0]), value, sizeof(struct snmp_value)); +    snmp_data.bindings[0].syntax = 0; +    snmp_data.nbindings = 1; +} + + +static int +print_resp(struct snmp_pdu* pdu, uint64_t when) +{ +    struct snmp_value* value; +    char *t; +    int i; + +    ASSERT(req->id == pdu->request_id); + +    for(i = 0; i < pdu->nbindings; i++) +    { +        value = &(pdu->bindings[i]); + +        printf("%s: ", asn_oid2str(&(value->var))); + +        switch(value->syntax) +        { +        case SNMP_SYNTAX_NULL: +            printf("[null]\n"); +            break; +        case SNMP_SYNTAX_INTEGER: +            printf("%d\n", value->v.integer); +            break; +        case SNMP_SYNTAX_COUNTER: +        case SNMP_SYNTAX_GAUGE: +        case SNMP_SYNTAX_TIMETICKS: +            printf("%d\n", value->v.uint32); +            break; +        case SNMP_SYNTAX_COUNTER64: +            printf("%lld\n", value->v.counter64); +            break; +        case SNMP_SYNTAX_OCTETSTRING: +            t = xcalloc(value->v.octetstring.len + 1); +            memcpy(t, value->v.octetstring.octets, value->v.octetstring.len); +            printf("%s\n", t); +            free(t); +            break; +        case SNMP_SYNTAX_OID: +            printf("%s\n", asn_oid2str(&(value->v.oid))); +            break; +        case SNMP_SYNTAX_IPADDRESS: +            printf("%c.%c.%c.%c\n", value->v.ipaddress[0], value->v.ipaddress[1], +                   value->v.ipaddress[2], value->v.ipaddress[3]); +            break; +        case SNMP_SYNTAX_NOSUCHOBJECT: +            printf("[field not available on snmp server]\n"); +            break; +        case SNMP_SYNTAX_NOSUCHINSTANCE: +            printf("[no such instance on snmp server]\n"); +            break; +        case SNMP_SYNTAX_ENDOFMIBVIEW: +            return 0; +        default: +            printf("[unknown]\n"); +            break; +        } +    } + +    return 1; +} + +static void +receive_resp(int fd, int type, void* arg) +{ +    char hostname[MAXPATHLEN]; +    struct sockaddr_any from; +    struct snmp_pdu pdu; +    struct snmp_value *val; +    struct asn_buf b; +    const char* msg; +    int len, ret, subid; +    int32_t ip; + +    ASSERT(snmp_socket == fd); + +    /* Read in the packet */ + +    SANY_LEN(from) = sizeof(from); +    len = recvfrom(snmp_socket, snmp_buffer, sizeof(snmp_buffer), 0, +                   &SANY_ADDR(from), &SANY_LEN(from)); +    if(len < 0) +    { +        if(errno != EAGAIN && errno != EWOULDBLOCK) +            err(1, "error receiving snmp packet from network"); +    } + +    if(sock_any_ntop(&from, hostname, MAXPATHLEN, 0) == -1) +        strcpy(hostname, "[UNKNOWN]"); + +    /* Now parse the packet */ + +    b.asn_ptr = snmp_buffer; +    b.asn_len = len; + +    ret = snmp_pdu_decode(&b, &pdu, &ip); +    if(ret != SNMP_CODE_OK) +        errx(1, "invalid snmp packet received from: %s", hostname); + +    /* It needs to match something we're waiting for */ +    if(pdu.request_id != snmp_data.request_id) +        return; + +    /* Check for errors */ +    if(pdu.error_status != SNMP_ERR_NOERROR) +    { +        snmp_pdu_dump (&pdu); +        msg = snmp_get_errmsg (pdu.error_status); +        if(msg) +            errx(1, "snmp error from host '%s': %s", hostname, msg); +        else +            errx(1, "unknown snmp error from host '%s': %d", hostname, pdu.error_status); +        return; +    } + +    subid = ret = 1; + +    if(pdu.nbindings > 0) +    { +        val = &(pdu.bindings[pdu.nbindings - 1]); +        subid = asn_compare_oid(&oid_first, &(val->var)) == 0 || +                asn_is_suboid(&oid_first, &(val->var)); +    } + +    /* Print the packet values */ +    if(!recursive || subid) +        ret = print_resp(&pdu, server_get_time()); + +    if(ret && recursive && subid) +    { +        /* If recursive, move onto next one */ +        setup_next(&(pdu.bindings[pdu.nbindings - 1])); +        send_req(); +        return; +    } + +    server_stop (); +} + +/* ----------------------------------------------------------------------------- + * STARTUP + */ + +static void +usage() +{ +    fprintf(stderr, "usage: rrdbot-get [-nr] snmp://community@host/oid\n"); +    fprintf(stderr, "       rrdbot-get -V\n"); +    exit(2); +} + +static void +version() +{ +    printf("rrdbot-get (version %s)\n", VERSION); +    exit(0); +} + +int +main(int argc, char* argv[]) +{ +    struct sockaddr_in addr; +    int numeric = 0; +    char ch; + +    /* Parse the arguments nicely */ +    while((ch = getopt(argc, argv, "nrV")) != -1) +    { +        switch(ch) +        { + +        /* Numeric output */ +        case 'n': +            numeric = 1; +            break; + +        /* SNMP walk (recursive)*/ +        case 'r': +            recursive = 1; +            break; + +        /* Print version number */ +        case 'V': +            version(); +            break; + +        /* Usage information */ +        case '?': +        default: +            usage(); +            break; +        } +    } + +    argc -= optind; +    argv += optind; + +    if(argc != 1) +        usage(); + +    setup_req (argv[0]); + +    /* Setup the SNMP socket */ +    snmp_socket = socket(PF_INET, SOCK_DGRAM, 0); +    if(snmp_socket < 0) +        err(1, "couldn't open snmp socket"); +    memset(&addr, 0, sizeof(addr)); +    addr.sin_family = AF_INET; +    if(bind(snmp_socket, (struct sockaddr*)&addr, sizeof(addr)) < 0) +        err(1, "couldn't listen on port"); +    if(server_watch(snmp_socket, SERVER_READ, receive_resp, NULL) == -1) +        err(1, "couldn't listen on socket"); + +    send_req(); + +    server_run(); + +    return 0; +} | 
