示例#1
0
int
netsnmp_parse_args(int argc,
                   char **argv,
                   netsnmp_session * session, const char *localOpts,
                   void (*proc) (int, char *const *, int),
                   int flags)
{
    static char	   *sensitive[4] = { NULL, NULL, NULL, NULL };
    int             arg, sp = 0, testcase = 0;
    char           *cp;
    char           *Apsz = NULL;
    char           *Xpsz = NULL;
    char           *Cpsz = NULL;
    char            Opts[BUF_SIZE];
    int             zero_sensitive = !( flags & NETSNMP_PARSE_ARGS_NOZERO );
    char           *backup_NETSNMP_DS_LIB_OUTPUT_PRECISION = NULL;

    /*
     * initialize session to default values 
     */
    snmp_sess_init(session);
    strcpy(Opts, "Y:VhHm:M:O:I:P:D:dv:r:t:c:Z:e:E:n:u:l:x:X:a:A:p:T:-:3:s:S:L:");
    if (localOpts) {
        if (strlen(localOpts) + strlen(Opts) >= sizeof(Opts)) {
            snmp_log(LOG_ERR, "Too many localOpts in snmp_parse_args()\n");
            return -1;
        }
        strcat(Opts, localOpts);
    }

    /*
     * get the options 
     */
    DEBUGMSGTL(("snmp_parse_args", "starting: %d/%d\n", optind, argc));
    for (arg = 0; arg < argc; arg++) {
        DEBUGMSGTL(("snmp_parse_args", " arg %d = %s\n", arg, argv[arg]));
    }

    optind = 1;
    while ((arg = getopt(argc, argv, Opts)) != EOF) {
        DEBUGMSGTL(("snmp_parse_args", "handling (#%d): %c\n", optind, arg));
        switch (arg) {
        case '-':
            if (strcasecmp(optarg, "help") == 0) {
                return (NETSNMP_PARSE_ARGS_ERROR_USAGE);
            }
            if (strcasecmp(optarg, "version") == 0) {
                fprintf(stderr,"NET-SNMP version: %s\n",netsnmp_get_version());
                return (NETSNMP_PARSE_ARGS_SUCCESS_EXIT);
            }

            handle_long_opt(optarg);
            break;

        case 'V':
            fprintf(stderr, "NET-SNMP version: %s\n", netsnmp_get_version());
            return (NETSNMP_PARSE_ARGS_SUCCESS_EXIT);

        case 'h':
            return (NETSNMP_PARSE_ARGS_ERROR_USAGE);
            break;

        case 'H':
            init_snmp("snmpapp");
            fprintf(stderr, "Configuration directives understood:\n");
            read_config_print_usage("  ");
            return (NETSNMP_PARSE_ARGS_SUCCESS_EXIT);

        case 'Y':
            netsnmp_config_remember(optarg);
            break;

#ifndef NETSNMP_DISABLE_MIB_LOADING
        case 'm':
            setenv("MIBS", optarg, 1);
            break;

        case 'M':
            netsnmp_get_mib_directory(); /* prepare the default directories */
            netsnmp_set_mib_directory(optarg);
            break;
#endif /* NETSNMP_DISABLE_MIB_LOADING */

        case 'O':
            cp = snmp_out_options(optarg, argc, argv);
            if (cp != NULL) {
                fprintf(stderr, "Unknown output option passed to -O: %c.\n", 
			*cp);
                return (NETSNMP_PARSE_ARGS_ERROR_USAGE);
            }
            break;

        case 'I':
            cp = snmp_in_options(optarg, argc, argv);
            if (cp != NULL) {
                fprintf(stderr, "Unknown input option passed to -I: %c.\n",
			*cp);
                return (NETSNMP_PARSE_ARGS_ERROR_USAGE);
            }
            break;

#ifndef NETSNMP_DISABLE_MIB_LOADING
        case 'P':
            cp = snmp_mib_toggle_options(optarg);
            if (cp != NULL) {
                fprintf(stderr,
                        "Unknown parsing option passed to -P: %c.\n", *cp);
                return (NETSNMP_PARSE_ARGS_ERROR_USAGE);
            }
            break;
#endif /* NETSNMP_DISABLE_MIB_LOADING */

        case 'D':
            debug_register_tokens(optarg);
            snmp_set_do_debugging(1);
            break;

        case 'd':
            netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, 
				   NETSNMP_DS_LIB_DUMP_PACKET, 1);
            break;

        case 'v':
            session->version = -1;
#ifndef NETSNMP_DISABLE_SNMPV1
            if (!strcmp(optarg, "1")) {
                session->version = SNMP_VERSION_1;
            }
#endif
#ifndef NETSNMP_DISABLE_SNMPV2C
            if (!strcasecmp(optarg, "2c")) {
                session->version = SNMP_VERSION_2c;
            }
#endif
            if (!strcasecmp(optarg, "3")) {
                session->version = SNMP_VERSION_3;
            }
            if (session->version == -1) {
                fprintf(stderr,
                        "Invalid version specified after -v flag: %s\n",
                        optarg);
                return (NETSNMP_PARSE_ARGS_ERROR_USAGE);
            }
            break;

        case 'p':
            fprintf(stderr, "Warning: -p option is no longer used - ");
            fprintf(stderr, "specify the remote host as HOST:PORT\n");
            return (NETSNMP_PARSE_ARGS_ERROR_USAGE);
            break;

        case 'T':
        {
            char leftside[SNMP_MAXBUF_MEDIUM], rightside[SNMP_MAXBUF_MEDIUM];
            char *tmpcp, *tmpopt;
            
            /* ensure we have a proper argument */
            tmpopt = strdup(optarg);
            tmpcp = strchr(tmpopt, '=');
            if (!tmpcp) {
                fprintf(stderr, "-T expects a NAME=VALUE pair.\n");
                return (NETSNMP_PARSE_ARGS_ERROR_USAGE);
            }
            *tmpcp++ = '\0';

            /* create the transport config container if this is the first */
            if (!session->transport_configuration) {
                netsnmp_container_init_list();
                session->transport_configuration =
                    netsnmp_container_find("transport_configuration:fifo");
                if (!session->transport_configuration) {
                    fprintf(stderr, "failed to initialize the transport configuration container\n");
                    free(tmpopt);
                    return (NETSNMP_PARSE_ARGS_ERROR);
                }

                session->transport_configuration->compare =
                    (netsnmp_container_compare*)
                    netsnmp_transport_config_compare;
            }

            /* set the config */
            strlcpy(leftside, tmpopt, sizeof(leftside));
            strlcpy(rightside, tmpcp, sizeof(rightside));

            CONTAINER_INSERT(session->transport_configuration,
                             netsnmp_transport_create_config(leftside,
                                                             rightside));
            free(tmpopt);
        }
        break;
            
        case 't':
            session->timeout = (long)(atof(optarg) * 1000000L);
            if (session->timeout <= 0) {
                fprintf(stderr, "Invalid timeout in seconds after -t flag.\n");
                return (NETSNMP_PARSE_ARGS_ERROR_USAGE);
            }
            break;

        case 'r':
            session->retries = atoi(optarg);
            if (session->retries < 0 || !isdigit((unsigned char)(optarg[0]))) {
                fprintf(stderr, "Invalid number of retries after -r flag.\n");
                return (NETSNMP_PARSE_ARGS_ERROR_USAGE);
            }
            break;

        case 'c':
	    if (zero_sensitive) {
		if ((sensitive[sp] = strdup(optarg)) != NULL) {
		    Cpsz = sensitive[sp];
		    memset(optarg, '\0', strlen(optarg));
		    sp++;
		} else {
		    fprintf(stderr, "malloc failure processing -c flag.\n");
		    return NETSNMP_PARSE_ARGS_ERROR;
		}
	    } else {
		Cpsz = optarg;
	    }
            break;

        case '3':
	    /*  TODO: This needs to zero things too.  */
            if (snmpv3_options(optarg, session, &Apsz, &Xpsz, argc, argv) < 0){
                return (NETSNMP_PARSE_ARGS_ERROR_USAGE);
            }
            break;

        case 'L':
            if (snmp_log_options(optarg, argc, argv) < 0) {
                return (NETSNMP_PARSE_ARGS_ERROR_USAGE);
            }
            break;

#define SNMPV3_CMD_OPTIONS
#ifdef  SNMPV3_CMD_OPTIONS
        case 'Z':
            errno = 0;
            session->engineBoots = strtoul(optarg, &cp, 10);
            if (errno || cp == optarg) {
                fprintf(stderr, "Need engine boots value after -Z flag.\n");
                return (NETSNMP_PARSE_ARGS_ERROR_USAGE);
            }
            if (*cp == ',') {
                char *endptr;
                cp++;
                session->engineTime = strtoul(cp, &endptr, 10);
                if (errno || cp == endptr) {
                    fprintf(stderr, "Need engine time after \"-Z engineBoot,\".\n");
                    return (NETSNMP_PARSE_ARGS_ERROR_USAGE);
                }
            }
            /*
             * Handle previous '-Z boot time' syntax 
             */
            else if (optind < argc) {
                session->engineTime = strtoul(argv[optind], &cp, 10);
                if (errno || cp == argv[optind]) {
                    fprintf(stderr, "Need engine time after \"-Z engineBoot\".\n");
                    return (NETSNMP_PARSE_ARGS_ERROR_USAGE);
                }
            } else {
                fprintf(stderr, "Need engine time after \"-Z engineBoot\".\n");
                return (NETSNMP_PARSE_ARGS_ERROR_USAGE);
            }
            break;

        case 'e':{
                size_t ebuf_len = 32, eout_len = 0;
                u_char *ebuf = (u_char *)malloc(ebuf_len);

                if (ebuf == NULL) {
                    fprintf(stderr, "malloc failure processing -e flag.\n");
                    return (NETSNMP_PARSE_ARGS_ERROR);
                }
                if (!snmp_hex_to_binary
                    (&ebuf, &ebuf_len, &eout_len, 1, optarg)) {
                    fprintf(stderr, "Bad engine ID value after -e flag.\n");
                    free(ebuf);
                    return (NETSNMP_PARSE_ARGS_ERROR_USAGE);
                }
                if ((eout_len < 5) || (eout_len > 32)) {
                    fprintf(stderr, "Invalid engine ID value after -e flag.\n");
                    free(ebuf);
                    return (NETSNMP_PARSE_ARGS_ERROR_USAGE);
                }
                session->securityEngineID = ebuf;
                session->securityEngineIDLen = eout_len;
                break;
            }

        case 'E':{
                size_t ebuf_len = 32, eout_len = 0;
                u_char *ebuf = (u_char *)malloc(ebuf_len);

                if (ebuf == NULL) {
                    fprintf(stderr, "malloc failure processing -E flag.\n");
                    return (NETSNMP_PARSE_ARGS_ERROR);
                }
                if (!snmp_hex_to_binary(&ebuf, &ebuf_len,
					&eout_len, 1, optarg)) {
                    fprintf(stderr, "Bad engine ID value after -E flag.\n");
                    free(ebuf);
                    return (NETSNMP_PARSE_ARGS_ERROR_USAGE);
                }
                if ((eout_len < 5) || (eout_len > 32)) {
                    fprintf(stderr, "Invalid engine ID value after -E flag.\n");
                    free(ebuf);
                    return (NETSNMP_PARSE_ARGS_ERROR_USAGE);
                }
                session->contextEngineID = ebuf;
                session->contextEngineIDLen = eout_len;
                break;
            }

        case 'n':
            session->contextName = optarg;
            session->contextNameLen = strlen(optarg);
            break;

        case 'u':
	    if (zero_sensitive) {
		if ((sensitive[sp] = strdup(optarg)) != NULL) {
		    session->securityName = sensitive[sp];
		    session->securityNameLen = strlen(sensitive[sp]);
		    memset(optarg, '\0', strlen(optarg));
		    sp++;
		} else {
		    fprintf(stderr, "malloc failure processing -u flag.\n");
		    return NETSNMP_PARSE_ARGS_ERROR;
		}
	    } else {
		session->securityName = optarg;
		session->securityNameLen = strlen(optarg);
	    }
            break;

        case 'l':
            if (!strcasecmp(optarg, "noAuthNoPriv") || !strcmp(optarg, "1")
                || !strcasecmp(optarg, "noauth")
                || !strcasecmp(optarg, "nanp")) {
                session->securityLevel = SNMP_SEC_LEVEL_NOAUTH;
            } else if (!strcasecmp(optarg, "authNoPriv")
                       || !strcmp(optarg, "2")
                       || !strcasecmp(optarg, "auth")
                       || !strcasecmp(optarg, "anp")) {
                session->securityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV;
            } else if (!strcasecmp(optarg, "authPriv")
                       || !strcmp(optarg, "3")
                       || !strcasecmp(optarg, "priv")
                       || !strcasecmp(optarg, "ap")) {
                session->securityLevel = SNMP_SEC_LEVEL_AUTHPRIV;
            } else {
                fprintf(stderr,
                        "Invalid security level specified after -l flag: %s\n",
                        optarg);
                return (NETSNMP_PARSE_ARGS_ERROR_USAGE);
            }

            break;

#ifdef NETSNMP_SECMOD_USM
        case 'a':
#ifndef NETSNMP_DISABLE_MD5
            if (!strcasecmp(optarg, "MD5")) {
                session->securityAuthProto = usmHMACMD5AuthProtocol;
                session->securityAuthProtoLen = USM_AUTH_PROTO_MD5_LEN;
            } else
#endif
                if (!strcasecmp(optarg, "SHA")) {
                session->securityAuthProto = usmHMACSHA1AuthProtocol;
                session->securityAuthProtoLen = USM_AUTH_PROTO_SHA_LEN;
            } else {
                fprintf(stderr,
                        "Invalid authentication protocol specified after -a flag: %s\n",
                        optarg);
                return (NETSNMP_PARSE_ARGS_ERROR_USAGE);
            }
            break;

        case 'x':
            testcase = 0;
#ifndef NETSNMP_DISABLE_DES
            if (!strcasecmp(optarg, "DES")) {
                testcase = 1;
                session->securityPrivProto = usmDESPrivProtocol;
                session->securityPrivProtoLen = USM_PRIV_PROTO_DES_LEN;
            }
#endif
#ifdef HAVE_AES
            if (!strcasecmp(optarg, "AES128") ||
                !strcasecmp(optarg, "AES")) {
                testcase = 1;
                session->securityPrivProto = usmAESPrivProtocol;
                session->securityPrivProtoLen = USM_PRIV_PROTO_AES_LEN;
            }
#endif
            if (testcase == 0) {
                fprintf(stderr,
                      "Invalid privacy protocol specified after -x flag: %s\n",
                        optarg);
                return (NETSNMP_PARSE_ARGS_ERROR_USAGE);
            }
            break;

        case 'A':
	    if (zero_sensitive) {
		if ((sensitive[sp] = strdup(optarg)) != NULL) {
		    Apsz = sensitive[sp];
		    memset(optarg, '\0', strlen(optarg));
		    sp++;
		} else {
		    fprintf(stderr, "malloc failure processing -A flag.\n");
		    return NETSNMP_PARSE_ARGS_ERROR;
		}
	    } else {
		Apsz = optarg;
	    }
            break;

        case 'X':
	    if (zero_sensitive) {
		if ((sensitive[sp] = strdup(optarg)) != NULL) {
		    Xpsz = sensitive[sp];
		    memset(optarg, '\0', strlen(optarg));
		    sp++;
		} else {
		    fprintf(stderr, "malloc failure processing -X flag.\n");
		    return NETSNMP_PARSE_ARGS_ERROR;
		}
	    } else {
		Xpsz = optarg;
	    }
            break;
#endif                          /* SNMPV3_CMD_OPTIONS */
#endif /* NETSNMP_SECMOD_USM */

        case '?':
            return (NETSNMP_PARSE_ARGS_ERROR_USAGE);
            break;

        default:
            proc(argc, argv, arg);
            break;
        }
    }
    DEBUGMSGTL(("snmp_parse_args", "finished: %d/%d\n", optind, argc));
    
    /*
     * save command line parameters which should have precedence above config file settings
     *    (There ought to be a more scalable approach than this....)
     */
    if (netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OUTPUT_PRECISION)) {
        backup_NETSNMP_DS_LIB_OUTPUT_PRECISION = 
            strdup(netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OUTPUT_PRECISION));
    }

    /*
     * read in MIB database and initialize the snmp library, read the config file
     */
    init_snmp("snmpapp");

    /*
     * restore command line parameters which should have precedence above config file settings
     */
    if(backup_NETSNMP_DS_LIB_OUTPUT_PRECISION) {
        netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OUTPUT_PRECISION, backup_NETSNMP_DS_LIB_OUTPUT_PRECISION);
        free(backup_NETSNMP_DS_LIB_OUTPUT_PRECISION);
    }

    /*
     * session default version 
     */
    if (session->version == SNMP_DEFAULT_VERSION) {
        /*
         * run time default version 
         */
        session->version = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 
					      NETSNMP_DS_LIB_SNMPVERSION);

        /*
         * compile time default version 
         */
        if (!session->version) {
            switch (NETSNMP_DEFAULT_SNMP_VERSION) {
#ifndef NETSNMP_DISABLE_SNMPV1
            case 1:
                session->version = SNMP_VERSION_1;
                break;
#endif

#ifndef NETSNMP_DISABLE_SNMPV2C
            case 2:
                session->version = SNMP_VERSION_2c;
                break;
#endif

            case 3:
                session->version = SNMP_VERSION_3;
                break;

            default:
                snmp_log(LOG_ERR, "Can't determine a valid SNMP version for the session\n");
                return(NETSNMP_PARSE_ARGS_ERROR);
            }
        } else {
#ifndef NETSNMP_DISABLE_SNMPV1
            if (session->version == NETSNMP_DS_SNMP_VERSION_1)  /* bogus value.  version 1 actually = 0 */
                session->version = SNMP_VERSION_1;
#endif
        }
    }

#ifdef NETSNMP_SECMOD_USM
    /* XXX: this should ideally be moved to snmpusm.c somehow */

    /*
     * make master key from pass phrases 
     */
    if (Apsz) {
        session->securityAuthKeyLen = USM_AUTH_KU_LEN;
        if (session->securityAuthProto == NULL) {
            /*
             * get .conf set default 
             */
            const oid      *def =
                get_default_authtype(&session->securityAuthProtoLen);
            session->securityAuthProto =
                snmp_duplicate_objid(def, session->securityAuthProtoLen);
        }
        if (session->securityAuthProto == NULL) {
#ifndef NETSNMP_DISABLE_MD5
            /*
             * assume MD5
             */
            session->securityAuthProto =
                snmp_duplicate_objid(usmHMACMD5AuthProtocol,
                                     USM_AUTH_PROTO_MD5_LEN);
            session->securityAuthProtoLen = USM_AUTH_PROTO_MD5_LEN;
#else
            session->securityAuthProto =
                snmp_duplicate_objid(usmHMACSHA1AuthProtocol,
                                     USM_AUTH_PROTO_SHA_LEN);
            session->securityAuthProtoLen = USM_AUTH_PROTO_SHA_LEN;
#endif
        }
        if (generate_Ku(session->securityAuthProto,
                        session->securityAuthProtoLen,
                        (u_char *) Apsz, strlen(Apsz),
                        session->securityAuthKey,
                        &session->securityAuthKeyLen) != SNMPERR_SUCCESS) {
            snmp_perror(argv[0]);
            fprintf(stderr,
                    "Error generating a key (Ku) from the supplied authentication pass phrase. \n");
            return (NETSNMP_PARSE_ARGS_ERROR);
        }
    }
    if (Xpsz) {
        session->securityPrivKeyLen = USM_PRIV_KU_LEN;
        if (session->securityPrivProto == NULL) {
            /*
             * get .conf set default 
             */
            const oid      *def =
                get_default_privtype(&session->securityPrivProtoLen);
            session->securityPrivProto =
                snmp_duplicate_objid(def, session->securityPrivProtoLen);
        }
        if (session->securityPrivProto == NULL) {
            /*
             * assume DES 
             */
#ifndef NETSNMP_DISABLE_DES
            session->securityPrivProto =
                snmp_duplicate_objid(usmDESPrivProtocol,
                                     USM_PRIV_PROTO_DES_LEN);
            session->securityPrivProtoLen = USM_PRIV_PROTO_DES_LEN;
#else
            session->securityPrivProto =
                snmp_duplicate_objid(usmAESPrivProtocol,
                                     USM_PRIV_PROTO_AES_LEN);
            session->securityPrivProtoLen = USM_PRIV_PROTO_AES_LEN;
#endif

        }
        if (generate_Ku(session->securityAuthProto,
                        session->securityAuthProtoLen,
                        (u_char *) Xpsz, strlen(Xpsz),
                        session->securityPrivKey,
                        &session->securityPrivKeyLen) != SNMPERR_SUCCESS) {
            snmp_perror(argv[0]);
            fprintf(stderr,
                    "Error generating a key (Ku) from the supplied privacy pass phrase. \n");
            return (NETSNMP_PARSE_ARGS_ERROR);
        }
    }
#endif /* NETSNMP_SECMOD_USM */

    /*
     * get the hostname 
     */
    if (optind == argc) {
        fprintf(stderr, "No hostname specified.\n");
        return (NETSNMP_PARSE_ARGS_ERROR_USAGE);
    }
    session->peername = argv[optind++]; /* hostname */

#if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
    /*
     * If v1 or v2c, check community has been set, either by a -c option above,
     * or via a default token somewhere.  
     * If neither, it will be taken from the incoming request PDU.
     */

#if defined(NETSNMP_DISABLE_SNMPV1)
    if (session->version == SNMP_VERSION_2c)
#else 
#if defined(NETSNMP_DISABLE_SNMPV2C)
    if (session->version == SNMP_VERSION_1)
#else
    if (session->version == SNMP_VERSION_1 ||
	session->version == SNMP_VERSION_2c)
#endif
#endif
    {
        if (Cpsz == NULL) {
            Cpsz = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
					 NETSNMP_DS_LIB_COMMUNITY);
	    if (Cpsz == NULL) {
                if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
                                           NETSNMP_DS_LIB_IGNORE_NO_COMMUNITY)){
                    DEBUGMSGTL(("snmp_parse_args",
                                "ignoring that the community string is not present\n"));
                    session->community = NULL;
                    session->community_len = 0;
                } else {
                    fprintf(stderr, "No community name specified.\n");
                    return (NETSNMP_PARSE_ARGS_ERROR_USAGE);
                }
	    }
	} else {
            session->community = (unsigned char *)Cpsz;
            session->community_len = strlen(Cpsz);
        }
    }
#endif /* support for community based SNMP */

    return optind;
}
示例#2
0
main(int argc, char *argv[])
#endif
{
    char            options[128] = "aAc:CdD::fhHI:l:L:m:M:n:p:P:qrsS:UvV-:Y:";
    int             arg, i, ret;
    int             dont_fork = 0, do_help = 0;
    int             log_set = 0;
    int             agent_mode = -1;
    char           *pid_file = NULL;
    char            option_compatability[] = "-Le";
#ifndef WIN32
    int             prepared_sockets = 0;
#endif
#if HAVE_GETPID
    int fd;
    FILE           *PID;
#endif

#ifndef WIN32
#ifndef NETSNMP_NO_SYSTEMD
    /* check if systemd has sockets for us and don't close them */
    prepared_sockets = netsnmp_sd_listen_fds(0);
#endif /* NETSNMP_NO_SYSTEMD */

    /*
     * close all non-standard file descriptors we may have
     * inherited from the shell.
     */
    if (!prepared_sockets) {
        for (i = getdtablesize() - 1; i > 2; --i) {
            (void) close(i);
        }
    }
#endif /* #WIN32 */
    
    /*
     * register signals ASAP to prevent default action (usually core)
     * for signals during startup...
     */
#ifdef SIGTERM
    DEBUGMSGTL(("signal", "registering SIGTERM signal handler\n"));
    signal(SIGTERM, SnmpdShutDown);
#endif
#ifdef SIGINT
    DEBUGMSGTL(("signal", "registering SIGINT signal handler\n"));
    signal(SIGINT, SnmpdShutDown);
#endif
#ifdef SIGHUP
    signal(SIGHUP, SIG_IGN);   /* do not terminate on early SIGHUP */
#endif
#ifdef SIGUSR1
    DEBUGMSGTL(("signal", "registering SIGUSR1 signal handler\n"));
    signal(SIGUSR1, SnmpdDump);
#endif
#ifdef SIGPIPE
    DEBUGMSGTL(("signal", "registering SIGPIPE signal handler\n"));
    signal(SIGPIPE, SIG_IGN);   /* 'Inline' failure of wayward readers */
#endif
#ifdef SIGXFSZ
    signal(SIGXFSZ, SnmpdCatchRandomSignal);
#endif

#ifdef NETSNMP_NO_ROOT_ACCESS
    /*
     * Default to no.  
     */
    netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, 
			   NETSNMP_DS_AGENT_NO_ROOT_ACCESS, 1);
#endif
    /*
     * Default to NOT running an AgentX master.  
     */
    netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, 
			   NETSNMP_DS_AGENT_AGENTX_MASTER, 0);
    netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID,
                       NETSNMP_DS_AGENT_AGENTX_TIMEOUT, -1);
    netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID,
                       NETSNMP_DS_AGENT_AGENTX_RETRIES, -1);

    netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID,
                       NETSNMP_DS_AGENT_CACHE_TIMEOUT, 5);
    /*
     * Add some options if they are available.  
     */
#if HAVE_UNISTD_H
    strcat(options, "g:u:");
#endif
#if defined(USING_AGENTX_SUBAGENT_MODULE)|| defined(USING_AGENTX_MASTER_MODULE)
    strcat(options, "x:");
#endif
#ifdef USING_AGENTX_SUBAGENT_MODULE
    strcat(options, "X");
#endif

    /*
     * This is incredibly ugly, but it's probably the simplest way
     *  to handle the old '-L' option as well as the new '-Lx' style
     */
    for (i=0; i<argc; i++) {
        if (!strcmp(argv[i], "-L"))
            argv[i] = option_compatability;            
    }

#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
#ifdef WIN32
    snmp_log_syslogname(app_name_long);
#else
    snmp_log_syslogname(app_name);
#endif
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
    netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID,
                          NETSNMP_DS_LIB_APPTYPE, app_name);

    /*
     * Now process options normally.  
     */
    while ((arg = getopt(argc, argv, options)) != EOF) {
        switch (arg) {
        case '-':
            if (strcasecmp(optarg, "help") == 0) {
                usage(argv[0]);
            }
            if (strcasecmp(optarg, "version") == 0) {
                version();
            }

            handle_long_opt(optarg);
            break;

        case 'a':
            log_addresses++;
            break;

        case 'A':
            netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID,
                                   NETSNMP_DS_LIB_APPEND_LOGFILES, 1);
            break;

        case 'c':
            if (optarg != NULL) {
                netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID, 
				      NETSNMP_DS_LIB_OPTIONALCONFIG, optarg);
            } else {
                usage(argv[0]);
            }
            break;

        case 'C':
            netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, 
				   NETSNMP_DS_LIB_DONT_READ_CONFIGS, 1);
            break;

        case 'd':
            netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID,
                                   NETSNMP_DS_LIB_DUMP_PACKET,
                                   ++snmp_dump_packet);
            break;

        case 'D':
            debug_register_tokens(optarg);
            snmp_set_do_debugging(1);
            break;

        case 'f':
            dont_fork = 1;
            break;

#if HAVE_UNISTD_H
        case 'g':
            if (optarg != NULL) {
                char           *ecp;
                int             gid;

                gid = strtoul(optarg, &ecp, 10);
#if HAVE_GETGRNAM && HAVE_PWD_H
                if (*ecp) {
                    struct group  *info;

                    info = getgrnam(optarg);
                    gid = info ? info->gr_gid : -1;
                    endgrent();
                }
#endif
                if (gid < 0) {
                    fprintf(stderr, "Bad group id: %s\n", optarg);
                    exit(1);
                }
                netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID, 
				   NETSNMP_DS_AGENT_GROUPID, gid);
            } else {
                usage(argv[0]);
            }
            break;
#endif

        case 'h':
            usage(argv[0]);
            break;

        case 'H':
            do_help = 1;
            break;

        case 'I':
            if (optarg != NULL) {
                add_to_init_list(optarg);
            } else {
                usage(argv[0]);
            }
            break;

#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_FILE
        case 'l':
            printf("Warning: -l option is deprecated, use -Lf <file> instead\n");
            if (optarg != NULL) {
                if (strlen(optarg) > PATH_MAX) {
                    fprintf(stderr,
                            "%s: logfile path too long (limit %d chars)\n",
                            argv[0], PATH_MAX);
                    exit(1);
                }
                snmp_enable_filelog(optarg,
                                    netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
                                                           NETSNMP_DS_LIB_APPEND_LOGFILES));
                log_set = 1;
            } else {
                usage(argv[0]);
            }
            break;
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_FILE */

        case 'L':
	    if  (snmp_log_options( optarg, argc, argv ) < 0 ) {
                usage(argv[0]);
            }
            log_set = 1;
            break;

        case 'm':
            if (optarg != NULL) {
                setenv("MIBS", optarg, 1);
            } else {
                usage(argv[0]);
            }
            break;

        case 'M':
            if (optarg != NULL) {
                setenv("MIBDIRS", optarg, 1);
            } else {
                usage(argv[0]);
            }
            break;

        case 'n':
            if (optarg != NULL) {
                app_name = optarg;
                netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID,
                                      NETSNMP_DS_LIB_APPTYPE, app_name);
            } else {
                usage(argv[0]);
            }
            break;

        case 'P':
            printf("Warning: -P option is deprecated, use -p instead\n");
        case 'p':
            if (optarg != NULL) {
                pid_file = optarg;
            } else {
                usage(argv[0]);
            }
            break;

        case 'q':
            netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, 
                                   NETSNMP_DS_LIB_QUICK_PRINT, 1);
            break;

        case 'r':
            netsnmp_ds_toggle_boolean(NETSNMP_DS_APPLICATION_ID, 
				      NETSNMP_DS_AGENT_NO_ROOT_ACCESS);
            break;

#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
        case 's':
            printf("Warning: -s option is deprecated, use -Lsd instead\n");
            snmp_enable_syslog();
            log_set = 1;
            break;

        case 'S':
            printf("Warning: -S option is deprecated, use -Ls <facility> instead\n");
            if (optarg != NULL) {
                switch (*optarg) {
                case 'd':
                case 'D':
                    Facility = LOG_DAEMON;
                    break;
                case 'i':
                case 'I':
                    Facility = LOG_INFO;
                    break;
                case '0':
                    Facility = LOG_LOCAL0;
                    break;
                case '1':
                    Facility = LOG_LOCAL1;
                    break;
                case '2':
                    Facility = LOG_LOCAL2;
                    break;
                case '3':
                    Facility = LOG_LOCAL3;
                    break;
                case '4':
                    Facility = LOG_LOCAL4;
                    break;
                case '5':
                    Facility = LOG_LOCAL5;
                    break;
                case '6':
                    Facility = LOG_LOCAL6;
                    break;
                case '7':
                    Facility = LOG_LOCAL7;
                    break;
                default:
                    fprintf(stderr, "invalid syslog facility: -S%c\n",*optarg);
                    usage(argv[0]);
                }
                snmp_enable_syslog_ident(snmp_log_syslogname(NULL), Facility);
                log_set = 1;
            } else {
                fprintf(stderr, "no syslog facility specified\n");
                usage(argv[0]);
            }
            break;
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */

        case 'U':
            netsnmp_ds_toggle_boolean(NETSNMP_DS_APPLICATION_ID, 
				      NETSNMP_DS_AGENT_LEAVE_PIDFILE);
            break;

#if HAVE_UNISTD_H
        case 'u':
            if (optarg != NULL) {
                char           *ecp;
                int             uid;

                uid = strtoul(optarg, &ecp, 10);
#if HAVE_GETPWNAM && HAVE_PWD_H
                if (*ecp) {
                    struct passwd  *info;

                    info = getpwnam(optarg);
                    uid = info ? info->pw_uid : -1;
                    endpwent();
                }
#endif
                if (uid < 0) {
                    fprintf(stderr, "Bad user id: %s\n", optarg);
                    exit(1);
                }
                netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID, 
				   NETSNMP_DS_AGENT_USERID, uid);
            } else {
                usage(argv[0]);
            }
            break;
#endif

        case 'v':
            version();

        case 'V':
            netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, 
				   NETSNMP_DS_AGENT_VERBOSE, 1);
            break;

#if defined(USING_AGENTX_SUBAGENT_MODULE)|| defined(USING_AGENTX_MASTER_MODULE)
        case 'x':
            if (optarg != NULL) {
                netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, 
				      NETSNMP_DS_AGENT_X_SOCKET, optarg);
            } else {
                usage(argv[0]);
            }
            netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, 
				   NETSNMP_DS_AGENT_AGENTX_MASTER, 1);
            break;
#endif

        case 'X':
#if defined(USING_AGENTX_SUBAGENT_MODULE)
            agent_mode = SUB_AGENT;
#else
            fprintf(stderr, "%s: Illegal argument -X:"
		            "AgentX support not compiled in.\n", argv[0]);
            usage(argv[0]);
            exit(1);
#endif
            break;

        case 'Y':
            netsnmp_config_remember(optarg);
            break;

        default:
            usage(argv[0]);
            break;
        }
    }

    if (do_help) {
        netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, 
                               NETSNMP_DS_AGENT_NO_ROOT_ACCESS, 1);
        init_agent(app_name);        /* register our .conf handlers */
        init_mib_modules();
        init_snmp(app_name);
        fprintf(stderr, "Configuration directives understood:\n");
        read_config_print_usage("  ");
        exit(0);
    }

    if (optind < argc) {
#ifndef NETSNMP_NO_LISTEN_SUPPORT
        /*
         * There are optional transport addresses on the command line.  
         */
        DEBUGMSGTL(("snmpd/main", "optind %d, argc %d\n", optind, argc));
        for (i = optind; i < argc; i++) {
            char *c, *astring;
            if ((c = netsnmp_ds_get_string(NETSNMP_DS_APPLICATION_ID, 
					   NETSNMP_DS_AGENT_PORTS))) {
                astring = (char*)malloc(strlen(c) + 2 + strlen(argv[i]));
                if (astring == NULL) {
                    fprintf(stderr, "malloc failure processing argv[%d]\n", i);
                    exit(1);
                }
                sprintf(astring, "%s,%s", c, argv[i]);
                netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, 
				      NETSNMP_DS_AGENT_PORTS, astring);
                SNMP_FREE(astring);
            } else {
                netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, 
				      NETSNMP_DS_AGENT_PORTS, argv[i]);
            }
        }
        DEBUGMSGTL(("snmpd/main", "port spec: %s\n",
                    netsnmp_ds_get_string(NETSNMP_DS_APPLICATION_ID, 
					  NETSNMP_DS_AGENT_PORTS)));
#else /* NETSNMP_NO_LISTEN_SUPPORT */
        fprintf(stderr, "You specified ports to open; this agent was built to only send notifications\n");
        exit(1);
#endif /* NETSNMP_NO_LISTEN_SUPPORT */
    }

#ifdef NETSNMP_LOGFILE
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_FILE
    if (0 == log_set)
        snmp_enable_filelog(NETSNMP_LOGFILE,
                            netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
                                                   NETSNMP_DS_LIB_APPEND_LOGFILES));
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_FILE */
#endif

#ifdef USING_UTIL_FUNCS_RESTART_MODULE
    {
        /*
         * Initialize a argv set to the current for restarting the agent.
         */
        char *cptr, **argvptr;

        argvrestartp = (char **)malloc((argc + 2) * sizeof(char *));
        argvptr = argvrestartp;
        for (i = 0, ret = 1; i < argc; i++) {
            ret += strlen(argv[i]) + 1;
        }
        argvrestart = (char *) malloc(ret);
        argvrestartname = (char *) malloc(strlen(argv[0]) + 1);
        if (!argvrestartp || !argvrestart || !argvrestartname) {
            fprintf(stderr, "malloc failure processing argvrestart\n");
            exit(1);
        }
        strcpy(argvrestartname, argv[0]);

        for (cptr = argvrestart, i = 0; i < argc; i++) {
            strcpy(cptr, argv[i]);
            *(argvptr++) = cptr;
            cptr += strlen(argv[i]) + 1;
        }
    }
#endif /* USING_UTIL_FUNCS_RESTART_MODULE */

    if (agent_mode == -1) {
        if (strstr(argv[0], "agentxd") != NULL) {
            netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID,
				   NETSNMP_DS_AGENT_ROLE, SUB_AGENT);
        } else {
            netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID,
				   NETSNMP_DS_AGENT_ROLE, MASTER_AGENT);
        }
    } else {
        netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID,
			       NETSNMP_DS_AGENT_ROLE, agent_mode);
    }

    SOCK_STARTUP;
    if (init_agent(app_name) != 0) {
        snmp_log(LOG_ERR, "Agent initialization failed\n");
        exit(1);
    }
    init_mib_modules();

    /*
     * start library 
     */
    init_snmp(app_name);

    if ((ret = init_master_agent()) != 0) {
        /*
         * Some error opening one of the specified agent transports.  
         */
        snmp_log(LOG_ERR, "Server Exiting with code 1\n");
        exit(1);
    }

    /*
     * Initialize the world.  Detach from the shell.  Create initial user.  
     */
    if(!dont_fork) {
        int quit = ! netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
                                            NETSNMP_DS_AGENT_QUIT_IMMEDIATELY);
        ret = netsnmp_daemonize(quit,
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_STDIO
                                snmp_stderrlog_status()
#else /* NETSNMP_FEATURE_REMOVE_LOGGING_STDIO */
                                0
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_STDIO */
            );
        /*
         * xxx-rks: do we care if fork fails? I think we should...
         */
        if(ret != 0) {
            snmp_log(LOG_ERR, "Server Exiting with code 1\n");
            exit(1);
        }
    }

#if HAVE_GETPID
    if (pid_file != NULL) {
        /*
         * unlink the pid_file, if it exists, prior to open.  Without
         * doing this the open will fail if the user specified pid_file
         * already exists.
         */
        unlink(pid_file);
        fd = open(pid_file, O_CREAT | O_EXCL | O_WRONLY, 0600);
        if (fd == -1) {
            snmp_log_perror(pid_file);
            if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
                                        NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) {
                exit(1);
            }
        } else {
            if ((PID = fdopen(fd, "w")) == NULL) {
                snmp_log_perror(pid_file);
                exit(1);
            } else {
                fprintf(PID, "%d\n", (int) getpid());
                fclose(PID);
            }
#ifndef _MSC_VER
            /* The sequence open()/fdopen()/fclose()/close() makes MSVC crash,
               hence skip the close() call when using the MSVC runtime. */
            close(fd);
#endif
        }
    }
#endif

#if defined(HAVE_UNISTD_H) && (defined(HAVE_CHOWN) || defined(HAVE_SETGID) || defined(HAVE_SETUID))
    {
    const char     *persistent_dir;
    int             uid, gid;

    persistent_dir = get_persistent_directory();
    mkdirhier( persistent_dir, NETSNMP_AGENT_DIRECTORY_MODE, 0 );
   
    uid = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, 
			     NETSNMP_DS_AGENT_USERID);
    gid = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, 
			     NETSNMP_DS_AGENT_GROUPID);
    
#ifdef HAVE_CHOWN
    if ( uid != 0 || gid != 0 )
        chown( persistent_dir, uid, gid );
#endif

#ifdef HAVE_SETGID
    if ((gid = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, 
				  NETSNMP_DS_AGENT_GROUPID)) > 0) {
        DEBUGMSGTL(("snmpd/main", "Changing gid to %d.\n", gid));
        if (setgid(gid) == -1
#ifdef HAVE_SETGROUPS
            || setgroups(1, (gid_t *)&gid) == -1
#endif
            ) {
            snmp_log_perror("setgid failed");
            if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
					NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) {
                exit(1);
            }
        }
    }
#endif
#ifdef HAVE_SETUID
    if ((uid = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, 
				  NETSNMP_DS_AGENT_USERID)) > 0) {
#if HAVE_GETPWNAM && HAVE_PWD_H && HAVE_INITGROUPS
        struct passwd *info;

        /*
         * Set supplementary groups before changing UID
         *   (which probably involves giving up privileges)
         */
        info = getpwuid(uid);
        if (info) {
            DEBUGMSGTL(("snmpd/main", "Supplementary groups for %s.\n", info->pw_name));
            if (initgroups(info->pw_name, (gid != 0 ? (gid_t)gid : info->pw_gid)) == -1) {
                snmp_log_perror("initgroups failed");
                if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
                                            NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) {
                    exit(1);
                }
            }
        }
        endpwent();
#endif
        DEBUGMSGTL(("snmpd/main", "Changing uid to %d.\n", uid));
        if (setuid(uid) == -1) {
            snmp_log_perror("setuid failed");
            if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
					NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) {
                exit(1);
            }
        }
    }
#endif
    }
#endif

    /*
     * Store persistent data immediately in case we crash later.  
     */
    snmp_store(app_name);

#ifdef SIGHUP
    DEBUGMSGTL(("signal", "registering SIGHUP signal handler\n"));
    signal(SIGHUP, SnmpdReconfig);
#endif

    /*
     * Send coldstart trap if possible.  
     */
    send_easy_trap(0, 0);

    /*
     * We're up, log our version number.  
     */
    snmp_log(LOG_INFO, "NET-SNMP version %s\n", netsnmp_get_version());
#ifdef WIN32SERVICE
    agent_status = AGENT_RUNNING;
#endif
    netsnmp_addrcache_initialise();

    /*
     * Let systemd know we're up.
     */
#ifndef NETSNMP_NO_SYSTEMD
    netsnmp_sd_notify(1, "READY=1\n");
    if (prepared_sockets)
        /*
         * Clear the environment variable, we already processed all the sockets
         * by now.
         */
        netsnmp_sd_listen_fds(1);
#endif

    /*
     * Forever monitor the dest_port for incoming PDUs.  
     */
    DEBUGMSGTL(("snmpd/main", "We're up.  Starting to process data.\n"));
    if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
				NETSNMP_DS_AGENT_QUIT_IMMEDIATELY))
        receive();
    DEBUGMSGTL(("snmpd/main", "sending shutdown trap\n"));
    SnmpTrapNodeDown();
    DEBUGMSGTL(("snmpd/main", "Bye...\n"));
    snmp_shutdown(app_name);
    shutdown_master_agent();
    shutdown_agent();

    if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
				NETSNMP_DS_AGENT_LEAVE_PIDFILE) &&
	(pid_file != NULL)) {
        unlink(pid_file);
    }
#ifdef WIN32SERVICE
    agent_status = AGENT_STOPPED;
#endif

#ifdef USING_UTIL_FUNCS_RESTART_MODULE
    SNMP_FREE(argvrestartname);
    SNMP_FREE(argvrestart);
    SNMP_FREE(argvrestartp);
#endif /* USING_UTIL_FUNCS_RESTART_MODULE */

    SOCK_CLEANUP;
    return 0;
}                               /* End main() -- snmpd */
int
snmp_parse_args(int argc,
                char *const *argv,
                netsnmp_session * session, const char *localOpts,
                void (*proc) (int, char *const *, int))
{
    int             arg;
    char           *cp;
    char           *Apsz = NULL;
    char           *Xpsz = NULL;
    char           *Cpsz = NULL;
    char            Opts[BUF_SIZE];

    /*
     * initialize session to default values 
     */
    snmp_sess_init(session);
    strcpy(Opts, "Y:VhHm:M:O:I:P:D:dv:r:t:c:Z:e:E:n:u:l:x:X:a:A:p:T:-:3:");
    if (localOpts)
        strcat(Opts, localOpts);

    /*
     * get the options 
     */
    DEBUGMSGTL(("snmp_parse_args", "starting: %d/%d\n", optind, argc));
    for (arg = 0; arg < argc; arg++) {
        DEBUGMSGTL(("snmp_parse_args", " arg %d = %s\n", arg, argv[arg]));
    }

    optind = 1;
    while ((arg = getopt(argc, argv, Opts)) != EOF) {
        DEBUGMSGTL(("snmp_parse_args", "handling (#%d): %c\n", optind,
                    arg));
        switch (arg) {
        case '-':
            if (strcasecmp(optarg, "help") == 0) {
                return (-1);
            }
            if (strcasecmp(optarg, "version") == 0) {
                fprintf(stderr, "NET-SNMP version: %s\n",
                        netsnmp_get_version());
                return (-2);
            }

            handle_long_opt(optarg);
            break;

        case 'V':
            fprintf(stderr, "NET-SNMP version: %s\n",
                    netsnmp_get_version());
            return (-2);

        case 'h':
            return (-1);
            break;

        case 'H':
            init_snmp("snmpapp");
            fprintf(stderr, "Configuration directives understood:\n");
            read_config_print_usage("  ");
            return (-2);

        case 'Y':
            netsnmp_config_remember(optarg);
            break;

        case 'm':
            setenv("MIBS", optarg, 1);
            break;

        case 'M':
            setenv("MIBDIRS", optarg, 1);
            break;

        case 'O':
            cp = snmp_out_toggle_options(optarg);
            if (cp != NULL) {
                fprintf(stderr,
                        "Unknown output option passed to -O: %c.\n", *cp);
                return (-1);
            }
            break;

        case 'I':
            cp = snmp_in_toggle_options(optarg);
            if (cp != NULL) {
                fprintf(stderr, "Unknown input option passed to -I: %c.\n",
                        *cp);
                return (-1);
            }
            break;

        case 'P':
            cp = snmp_mib_toggle_options(optarg);
            if (cp != NULL) {
                fprintf(stderr,
                        "Unknown parsing option passed to -P: %c.\n", *cp);
                return (-1);
            }
            break;

        case 'D':
            debug_register_tokens(optarg);
            snmp_set_do_debugging(1);
            break;

        case 'd':
            ds_set_boolean(DS_LIBRARY_ID, DS_LIB_DUMP_PACKET, 1);
            break;

        case 'v':
            if (!strcmp(optarg, "1")) {
                session->version = SNMP_VERSION_1;
            } else if (!strcasecmp(optarg, "2c")) {
                session->version = SNMP_VERSION_2c;
            } else if (!strcasecmp(optarg, "3")) {
                session->version = SNMP_VERSION_3;
            } else {
                fprintf(stderr,
                        "Invalid version specified after -v flag: %s\n",
                        optarg);
                return (-1);
            }
            break;

        case 'p':
            fprintf(stderr, "Warning: -p option is no longer used - ");
            fprintf(stderr, "specify the remote host as HOST:PORT\n");
            return (-1);
            break;

        case 'T':
            fprintf(stderr, "Warning: -T option is no longer used - ");
            fprintf(stderr, "specify the remote host as TRANSPORT:HOST\n");
            return (-1);
            break;

        case 't':
            session->timeout = atoi(optarg) * 1000000L;
            if (session->timeout < 0 || !isdigit(optarg[0])) {
                fprintf(stderr,
                        "Invalid timeout in seconds after -t flag.\n");
                return (-1);
            }
            break;

        case 'r':
            session->retries = atoi(optarg);
            if (session->retries < 0 || !isdigit(optarg[0])) {
                fprintf(stderr,
                        "Invalid number of retries after -r flag.\n");
                return (-1);
            }
            break;

        case 'c':
            Cpsz = optarg;
            break;

        case '3':
            if (snmpv3_options(optarg, session, &Apsz, &Xpsz, argc, argv) <
                0) {
                return (-1);
            }
            break;

#define SNMPV3_CMD_OPTIONS
#ifdef  SNMPV3_CMD_OPTIONS
        case 'Z':
            session->engineBoots = strtoul(optarg, NULL, 10);
            if (session->engineBoots == 0 || !isdigit(optarg[0])) {
                fprintf(stderr,
                        "Need engine boots value after -Z flag.\n");
                return (-1);
            }
            cp = strchr(optarg, ',');
            if (cp && *(++cp) && isdigit(*cp))
                session->engineTime = strtoul(cp, NULL, 10);
            /*
             * Handle previous '-Z boot time' syntax 
             */
            else if ((optind < argc) && isdigit(argv[optind][0]))
                session->engineTime = strtoul(argv[optind], NULL, 10);
            else {
                fprintf(stderr, "Need engine time value after -Z flag.\n");
                return (-1);
            }
            break;

        case 'e':{
                size_t          ebuf_len = 32, eout_len = 0;
                u_char         *ebuf = (u_char *) malloc(ebuf_len);

                if (ebuf == NULL) {
                    fprintf(stderr,
                            "malloc failure processing -e flag.\n");
                    return (-1);
                }
                if (!snmp_hex_to_binary
                    (&ebuf, &ebuf_len, &eout_len, 1, optarg)) {
                    fprintf(stderr,
                            "Bad engine ID value after -e flag.\n");
                    free(ebuf);
                    return (-1);
                }
                session->securityEngineID = ebuf;
                session->securityEngineIDLen = eout_len;
                break;
            }

        case 'E':{
                size_t          ebuf_len = 32, eout_len = 0;
                u_char         *ebuf = (u_char *) malloc(ebuf_len);

                if (ebuf == NULL) {
                    fprintf(stderr,
                            "malloc failure processing -E flag.\n");
                    return (-1);
                }
                if (!snmp_hex_to_binary
                    (&ebuf, &ebuf_len, &eout_len, 1, optarg)) {
                    fprintf(stderr,
                            "Bad engine ID value after -E flag.\n");
                    free(ebuf);
                    return (-1);
                }
                session->contextEngineID = ebuf;
                session->contextEngineIDLen = eout_len;
                break;
            }

        case 'n':
            session->contextName = optarg;
            session->contextNameLen = strlen(optarg);
            break;

        case 'u':
            session->securityName = optarg;
            session->securityNameLen = strlen(optarg);
            break;

        case 'l':
            if (!strcasecmp(optarg, "noAuthNoPriv") || !strcmp(optarg, "1")
                || !strcasecmp(optarg, "nanp")) {
                session->securityLevel = SNMP_SEC_LEVEL_NOAUTH;
            } else if (!strcasecmp(optarg, "authNoPriv")
                       || !strcmp(optarg, "2")
                       || !strcasecmp(optarg, "anp")) {
                session->securityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV;
            } else if (!strcasecmp(optarg, "authPriv")
                       || !strcmp(optarg, "3")
                       || !strcasecmp(optarg, "ap")) {
                session->securityLevel = SNMP_SEC_LEVEL_AUTHPRIV;
            } else {
                fprintf(stderr,
                        "Invalid security level specified after -l flag: %s\n",
                        optarg);
                return (-1);
            }

            break;

        case 'a':
            if (!strcasecmp(optarg, "MD5")) {
                session->securityAuthProto = usmHMACMD5AuthProtocol;
                session->securityAuthProtoLen = USM_AUTH_PROTO_MD5_LEN;
            } else if (!strcasecmp(optarg, "SHA")) {
                session->securityAuthProto = usmHMACSHA1AuthProtocol;
                session->securityAuthProtoLen = USM_AUTH_PROTO_SHA_LEN;
            } else {
                fprintf(stderr,
                        "Invalid authentication protocol specified after -a flag: %s\n",
                        optarg);
                return (-1);
            }
            break;

        case 'x':
            if (!strcasecmp(optarg, "DES")) {
                session->securityPrivProto = usmDESPrivProtocol;
                session->securityPrivProtoLen = USM_PRIV_PROTO_DES_LEN;
            } else {
                fprintf(stderr,
                        "Invalid privacy protocol specified after -x flag: %s\n",
                        optarg);
                return (-1);
            }
            break;

        case 'A':
            Apsz = optarg;
            break;

        case 'X':
            Xpsz = optarg;
            break;
#endif                          /* SNMPV3_CMD_OPTIONS */

        case '?':
            return (-1);
            break;

        default:
            proc(argc, argv, arg);
            break;
        }
    }
    DEBUGMSGTL(("snmp_parse_args", "finished: %d/%d\n", optind, argc));

    /*
     * read in MIB database and initialize the snmp library
     */
    init_snmp("snmpapp");

    /*
     * session default version 
     */
    if (session->version == SNMP_DEFAULT_VERSION) {
        /*
         * run time default version 
         */
        session->version = ds_get_int(DS_LIBRARY_ID, DS_LIB_SNMPVERSION);

        /*
         * compile time default version 
         */
        if (!session->version) {
            switch (SNMP_DEFAULT_VERSION) {
            case 1:
                session->version = SNMP_VERSION_1;
                break;

            case 2:
                session->version = SNMP_VERSION_2c;
                break;

            case 3:
                session->version = SNMP_VERSION_3;
                break;
            }
        } else {
            if (session->version == DS_SNMP_VERSION_1)  /* bogus value.  version 1 actually = 0 */
                session->version = SNMP_VERSION_1;
        }
    }

    /*
     * make master key from pass phrases 
     */
    if (Apsz) {
        session->securityAuthKeyLen = USM_AUTH_KU_LEN;
        if (session->securityAuthProto == NULL) {
            /*
             * get .conf set default 
             */
            const oid      *def =
                get_default_authtype(&session->securityAuthProtoLen);
            session->securityAuthProto =
                snmp_duplicate_objid(def, session->securityAuthProtoLen);
        }
        if (session->securityAuthProto == NULL) {
            /*
             * assume MD5 
             */
            session->securityAuthProto =
                snmp_duplicate_objid(usmHMACMD5AuthProtocol,
                                     USM_AUTH_PROTO_MD5_LEN);
            session->securityAuthProtoLen = USM_AUTH_PROTO_MD5_LEN;
        }
        if (generate_Ku(session->securityAuthProto,
                        session->securityAuthProtoLen,
                        (u_char *) Apsz, strlen(Apsz),
                        session->securityAuthKey,
                        &session->securityAuthKeyLen) != SNMPERR_SUCCESS) {
            snmp_perror(argv[0]);
            fprintf(stderr,
                    "Error generating a key (Ku) from the supplied authentication pass phrase. \n");
            return (-2);
        }
    }
    if (Xpsz) {
        session->securityPrivKeyLen = USM_PRIV_KU_LEN;
        if (session->securityPrivProto == NULL) {
            /*
             * get .conf set default 
             */
            const oid      *def =
                get_default_privtype(&session->securityPrivProtoLen);
            session->securityPrivProto =
                snmp_duplicate_objid(def, session->securityPrivProtoLen);
        }
        if (session->securityPrivProto == NULL) {
            /*
             * assume DES 
             */
            session->securityPrivProto =
                snmp_duplicate_objid(usmDESPrivProtocol,
                                     USM_PRIV_PROTO_DES_LEN);
            session->securityPrivProtoLen = USM_PRIV_PROTO_DES_LEN;
        }
        if (generate_Ku(session->securityAuthProto,
                        session->securityAuthProtoLen,
                        (u_char *) Xpsz, strlen(Xpsz),
                        session->securityPrivKey,
                        &session->securityPrivKeyLen) != SNMPERR_SUCCESS) {
            snmp_perror(argv[0]);
            fprintf(stderr,
                    "Error generating a key (Ku) from the supplied privacy pass phrase. \n");
            return (-2);
        }
    }
    /*
     * get the hostname 
     */
    if (optind == argc) {
        fprintf(stderr, "No hostname specified.\n");
        return (-1);
    }
    session->peername = argv[optind++]; /* hostname */

    /*
     * If v1 or v2c, check community has been set, either by a -c option above,
     * or via a default token somewhere.  
     */

    if (session->version == SNMP_VERSION_1 ||
        session->version == SNMP_VERSION_2c) {
        if (Cpsz == NULL) {
            Cpsz = ds_get_string(DS_LIBRARY_ID, DS_LIB_COMMUNITY);
        }
        if (Cpsz == NULL) {
            fprintf(stderr, "No community name specified.\n");
            return (-1);
        }
        session->community = (unsigned char *) Cpsz;
        session->community_len = strlen(Cpsz);
    }
    return optind;
}