net-snmp 5.7
snmpd.c
00001 /*
00002  * snmpd.c
00003  */
00007 /* Portions of this file are subject to the following copyrights.  See
00008  * the Net-SNMP's COPYING file for more details and other copyrights
00009  * that may apply:
00010  */
00011 /*
00012  * Copyright 1988, 1989 by Carnegie Mellon University
00013  * 
00014  * All Rights Reserved
00015  * 
00016  * Permission to use, copy, modify, and distribute this software and its 
00017  * documentation for any purpose and without fee is hereby granted, 
00018  * provided that the above copyright notice appear in all copies and that
00019  * both that copyright notice and this permission notice appear in 
00020  * supporting documentation, and that the name of CMU not be
00021  * used in advertising or publicity pertaining to distribution of the
00022  * software without specific, written prior permission.  
00023  * 
00024  * CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
00025  * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
00026  * CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
00027  * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
00028  * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
00029  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
00030  * SOFTWARE.
00031  * *****************************************************************
00032  */
00033 /*
00034  * Copyright © 2003 Sun Microsystems, Inc. All rights reserved.
00035  * Use is subject to license terms specified in the COPYING file
00036  * distributed with the Net-SNMP package.
00037  */
00038 #include <net-snmp/net-snmp-config.h>
00039 #include <net-snmp/net-snmp-features.h>
00040 #include <net-snmp/types.h>
00041 
00042 #if HAVE_IO_H
00043 #include <io.h>
00044 #endif
00045 #include <stdio.h>
00046 #include <errno.h>
00047 #if HAVE_STRING_H
00048 #include <string.h>
00049 #else
00050 #include <strings.h>
00051 #endif
00052 #if HAVE_STDLIB_H
00053 #include <stdlib.h>
00054 #endif
00055 #if HAVE_UNISTD_H
00056 #include <unistd.h>
00057 #endif
00058 #include <sys/types.h>
00059 #if HAVE_NETINET_IN_H
00060 #include <netinet/in.h>
00061 #endif
00062 #if HAVE_ARPA_INET_H
00063 #include <arpa/inet.h>
00064 #endif
00065 #if TIME_WITH_SYS_TIME
00066 # include <sys/time.h>
00067 # include <time.h>
00068 #else
00069 # if HAVE_SYS_TIME_H
00070 #  include <sys/time.h>
00071 # else
00072 #  include <time.h>
00073 # endif
00074 #endif
00075 #if HAVE_SYS_SELECT_H
00076 #include <sys/select.h>
00077 #endif
00078 #if HAVE_SYS_SOCKET_H
00079 #include <sys/socket.h>
00080 #endif
00081 #if HAVE_NET_IF_H
00082 #include <net/if.h>
00083 #endif
00084 #if HAVE_INET_MIB2_H
00085 #include <inet/mib2.h>
00086 #endif
00087 #if HAVE_SYS_IOCTL_H
00088 #include <sys/ioctl.h>
00089 #endif
00090 #if HAVE_SYS_FILE_H
00091 #include <sys/file.h>
00092 #endif
00093 #ifdef HAVE_FCNTL_H
00094 #include <fcntl.h>
00095 #endif
00096 #if HAVE_SYS_WAIT_H
00097 #include <sys/wait.h>
00098 #endif
00099 #include <signal.h>
00100 #ifdef HAVE_SYS_PARAM_H
00101 #include <sys/param.h>
00102 #endif
00103 #if HAVE_PROCESS_H              /* Win32-getpid */
00104 #include <process.h>
00105 #endif
00106 #if HAVE_LIMITS_H
00107 #include <limits.h>
00108 #endif
00109 #if HAVE_PWD_H
00110 #include <pwd.h>
00111 #endif
00112 #if HAVE_GRP_H
00113 #include <grp.h>
00114 #endif
00115 #ifdef HAVE_CRTDBG_H
00116 #include <crtdbg.h>
00117 #endif
00118 
00119 #ifndef PATH_MAX
00120 # ifdef _POSIX_PATH_MAX
00121 #  define PATH_MAX _POSIX_PATH_MAX
00122 # else
00123 #  define PATH_MAX 255
00124 # endif
00125 #endif
00126 
00127 #ifndef FD_SET
00128 typedef long    fd_mask;
00129 #define NFDBITS (sizeof(fd_mask) * NBBY)        /* bits per mask */
00130 #define FD_SET(n, p)    ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
00131 #define FD_CLR(n, p)    ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
00132 #define FD_ISSET(n, p)  ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
00133 #define FD_ZERO(p)      memset((p), 0, sizeof(*(p)))
00134 #endif
00135 
00136 #include <net-snmp/net-snmp-includes.h>
00137 #include <net-snmp/agent/net-snmp-agent-includes.h>
00138 
00139 #include <net-snmp/library/fd_event_manager.h>
00140 #include <net-snmp/library/large_fd_set.h>
00141 
00142 #include "m2m.h"
00143 #include <net-snmp/agent/agent_module_config.h>
00144 #include <net-snmp/agent/mib_module_config.h>
00145 
00146 #include "snmpd.h"
00147 
00148 #include <net-snmp/agent/mib_modules.h>
00149 
00150 #include <net-snmp/agent/agent_trap.h>
00151 
00152 #include <net-snmp/agent/table.h>
00153 #include <net-snmp/agent/table_iterator.h>
00154 
00155 /*
00156  * Include winservice.h to support Windows Service
00157  */
00158 #ifdef WIN32
00159 #include <windows.h>
00160 #include <tchar.h>
00161 #include <net-snmp/library/winservice.h>
00162 
00163 #define WIN32SERVICE
00164 
00165 #endif
00166 
00167 netsnmp_feature_want(logging_file)
00168 netsnmp_feature_want(logging_stdio)
00169 netsnmp_feature_want(logging_syslog)
00170 
00171 /*
00172  * Globals.
00173  */
00174 #ifdef NETSNMP_USE_LIBWRAP
00175 #include <tcpd.h>
00176 #endif                          /* NETSNMP_USE_LIBWRAP */
00177 
00178 #define TIMETICK         500000L
00179 
00180 int             snmp_dump_packet;
00181 static int      reconfig = 0;
00182 int             Facility = LOG_DAEMON;
00183 
00184 #ifdef WIN32SERVICE
00185 /*
00186  * SNMP Agent Status 
00187  */
00188 #define AGENT_RUNNING 1
00189 #define AGENT_STOPPED 0
00190 int             agent_status = AGENT_STOPPED;
00191 /* app_name_long used for Event Log (syslog), SCM, registry etc */
00192 LPCTSTR         app_name_long = _T("Net-SNMP Agent");     /* Application Name */
00193 #endif
00194 
00195 const char     *app_name = "snmpd";
00196 
00197 extern int      netsnmp_running;
00198 #ifdef USING_UTIL_FUNCS_RESTART_MODULE
00199 extern char   **argvrestartp;
00200 extern char    *argvrestart;
00201 extern char    *argvrestartname;
00202 #endif /* USING_UTIL_FUNCS_RESTART_MODULE */
00203 
00204 #ifdef USING_SMUX_MODULE
00205 #include <mibgroup/smux/smux.h>
00206 #endif /* USING_SMUX_MODULE */
00207 
00208 /*
00209  * Prototypes.
00210  */
00211 int             snmp_read_packet(int);
00212 int             snmp_input(int, netsnmp_session *, int, netsnmp_pdu *,
00213                            void *);
00214 static void     usage(char *);
00215 static void     SnmpTrapNodeDown(void);
00216 static int      receive(void);
00217 #ifdef WIN32SERVICE
00218 void            StopSnmpAgent(void);
00219 int             SnmpDaemonMain(int argc, TCHAR * argv[]);
00220 int __cdecl     _tmain(int argc, TCHAR * argv[]);
00221 #else
00222 int             main(int, char **);
00223 #endif
00224 
00225 /*
00226  * These definitions handle 4.2 systems without additional syslog facilities.
00227  */
00228 #ifndef LOG_CONS
00229 #define LOG_CONS        0       /* Don't bother if not defined... */
00230 #endif
00231 #ifndef LOG_PID
00232 #define LOG_PID         0       /* Don't bother if not defined... */
00233 #endif
00234 #ifndef LOG_LOCAL0
00235 #define LOG_LOCAL0      0
00236 #endif
00237 #ifndef LOG_LOCAL1
00238 #define LOG_LOCAL1      0
00239 #endif
00240 #ifndef LOG_LOCAL2
00241 #define LOG_LOCAL2      0
00242 #endif
00243 #ifndef LOG_LOCAL3
00244 #define LOG_LOCAL3      0
00245 #endif
00246 #ifndef LOG_LOCAL4
00247 #define LOG_LOCAL4      0
00248 #endif
00249 #ifndef LOG_LOCAL5
00250 #define LOG_LOCAL5      0
00251 #endif
00252 #ifndef LOG_LOCAL6
00253 #define LOG_LOCAL6      0
00254 #endif
00255 #ifndef LOG_LOCAL7
00256 #define LOG_LOCAL7      0
00257 #endif
00258 #ifndef LOG_DAEMON
00259 #define LOG_DAEMON      0
00260 #endif
00261 
00262 
00263 static void
00264 usage(char *prog)
00265 {
00266 #ifdef WIN32SERVICE
00267     printf("\nUsage:  %s [-register] [-quiet] [OPTIONS] [LISTENING ADDRESSES]"
00268            "\n        %s [-unregister] [-quiet]", prog, prog);
00269 #else
00270     printf("\nUsage:  %s [OPTIONS] [LISTENING ADDRESSES]", prog);
00271 #endif
00272     printf("\n"
00273            "\n\tVersion:  %s\n%s"
00274            "\t\t\t  (config search path: %s)\n%s%s",
00275            netsnmp_get_version(),
00276            "\tWeb:      http://www.net-snmp.org/\n"
00277            "\tEmail:    net-snmp-coders@lists.sourceforge.net\n"
00278            "\n  -a\t\t\tlog addresses\n"
00279            "  -A\t\t\tappend to the logfile rather than truncating it\n"
00280            "  -c FILE[,...]\t\tread FILE(s) as configuration file(s)\n"
00281            "  -C\t\t\tdo not read the default configuration files\n",
00282            get_configuration_directory(),
00283            "  -d\t\t\tdump sent and received SNMP packets\n"
00284            "  -D[TOKEN[,...]]\tturn on debugging output for the given TOKEN(s)\n"
00285            "\t\t\t  (try ALL for extremely verbose output)\n"
00286            "\t\t\t  Don't put space(s) between -D and TOKEN(s).\n"
00287            "  -f\t\t\tdo not fork from the shell\n",
00288 #if HAVE_UNISTD_H
00289            "  -g GID\t\tchange to this numeric gid after opening\n"
00290            "\t\t\t  transport endpoints\n"
00291 #endif
00292            "  -h, --help\t\tdisplay this usage message\n"
00293            "  -H\t\t\tdisplay configuration file directives understood\n"
00294            "  -I [-]INITLIST\tlist of mib modules to initialize (or not)\n"
00295            "\t\t\t  (run snmpd with -Dmib_init for a list)\n"
00296            "  -L <LOGOPTS>\t\ttoggle options controlling where to log to\n");
00297     snmp_log_options_usage("\t", stdout);
00298     printf("  -m MIBLIST\t\tuse MIBLIST instead of the default MIB list\n"
00299            "  -M DIRLIST\t\tuse DIRLIST as the list of locations to look for MIBs\n"
00300            "\t\t\t  (default %s)\n%s%s",
00301 #ifndef NETSNMP_DISABLE_MIB_LOADING
00302            netsnmp_get_mib_directory(),
00303 #else
00304            "MIBs not loaded",
00305 #endif
00306            "  -p FILE\t\tstore process id in FILE\n"
00307            "  -q\t\t\tprint information in a more parsable format\n"
00308            "  -r\t\t\tdo not exit if files only accessible to root\n"
00309            "\t\t\t  cannot be opened\n"
00310 #ifdef WIN32SERVICE
00311            "  -register\t\tregister as a Windows service\n"
00312            "  \t\t\t  (followed by -quiet to prevent message popups)\n"
00313            "  \t\t\t  (followed by the startup parameter list)\n"
00314            "  \t\t\t  Note that some parameters are not relevant when running as a service\n"
00315 #endif
00316 #if HAVE_UNISTD_H
00317            "  -u UID\t\tchange to this uid (numeric or textual) after\n"
00318            "\t\t\t  opening transport endpoints\n"
00319 #endif
00320 #ifdef WIN32SERVICE
00321            "  -unregister\t\tunregister as a Windows service\n"
00322            "  \t\t\t  (followed -quiet to prevent message popups)\n"
00323 #endif
00324            "  -v, --version\t\tdisplay version information\n"
00325            "  -V\t\t\tverbose display\n"
00326 #if defined(USING_AGENTX_SUBAGENT_MODULE)|| defined(USING_AGENTX_MASTER_MODULE)
00327            "  -x ADDRESS\t\tuse ADDRESS as AgentX address\n"
00328 #endif
00329 #ifdef USING_AGENTX_SUBAGENT_MODULE
00330            "  -X\t\t\trun as an AgentX subagent rather than as an\n"
00331            "\t\t\t  SNMP master agent\n"
00332 #endif
00333            ,
00334            "\nDeprecated options:\n"
00335            "  -l FILE\t\tuse -Lf <FILE> instead\n"
00336            "  -P\t\t\tuse -p instead\n"
00337            "  -s\t\t\tuse -Lsd instead\n"
00338            "  -S d|i|0-7\t\tuse -Ls <facility> instead\n"
00339            "\n"
00340            );
00341     exit(1);
00342 }
00343 
00344 static void
00345 version(void)
00346 {
00347     printf("\nNET-SNMP version:  %s\n"
00348            "Web:               http://www.net-snmp.org/\n"
00349            "Email:             net-snmp-coders@lists.sourceforge.net\n\n",
00350            netsnmp_get_version());
00351     exit(0);
00352 }
00353 
00354 RETSIGTYPE
00355 SnmpdShutDown(int a)
00356 {
00357 #ifdef WIN32SERVICE
00358     extern netsnmp_session *main_session;
00359 #endif
00360     netsnmp_running = 0;
00361 #ifdef WIN32SERVICE
00362     /*
00363      * In case of windows, select() in receive() function will not return 
00364      * on signal. Thats why following function is called, which closes the 
00365      * socket descriptors and causes the select() to return
00366      */
00367     snmp_close(main_session);
00368 #endif
00369 }
00370 
00371 #ifdef SIGHUP
00372 RETSIGTYPE
00373 SnmpdReconfig(int a)
00374 {
00375     reconfig = 1;
00376     signal(SIGHUP, SnmpdReconfig);
00377 }
00378 #endif
00379 
00380 #ifdef SIGUSR1
00381 extern void     dump_registry(void);
00382 RETSIGTYPE
00383 SnmpdDump(int a)
00384 {
00385     dump_registry();
00386     signal(SIGUSR1, SnmpdDump);
00387 }
00388 #endif
00389 
00390 RETSIGTYPE
00391 SnmpdCatchRandomSignal(int a)
00392 {
00393     /* Disable all logs and log the error via syslog */
00394     snmp_disable_log();
00395 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
00396     snmp_enable_syslog();
00397 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
00398     snmp_log(LOG_ERR, "Exiting on signal %d\n", a);
00399 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
00400     snmp_disable_syslog();
00401 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
00402     exit(1);
00403 }
00404 
00405 static void
00406 SnmpTrapNodeDown(void)
00407 {
00408     send_easy_trap(SNMP_TRAP_ENTERPRISESPECIFIC, 2);
00409     /*
00410      * XXX  2 - Node Down #define it as NODE_DOWN_TRAP 
00411      */
00412 }
00413 
00414 /*******************************************************************-o-******
00415  * main - Non Windows
00416  * SnmpDaemonMain - Windows to support windows service
00417  *
00418  * Parameters:
00419  *       argc
00420  *      *argv[]
00421  *      
00422  * Returns:
00423  *      0       Always succeeds.  (?)
00424  *
00425  *
00426  * Setup and start the agent daemon.
00427  *
00428  * Also successfully EXITs with zero for some options.
00429  */
00430 int
00431 #ifdef WIN32SERVICE
00432 SnmpDaemonMain(int argc, TCHAR * argv[])
00433 #else
00434 main(int argc, char *argv[])
00435 #endif
00436 {
00437     char            options[128] = "aAc:CdD::fhHI:l:L:m:M:n:p:P:qrsS:UvV-:Y:";
00438     int             arg, i, ret;
00439     int             dont_fork = 0, do_help = 0;
00440     int             log_set = 0;
00441     int             uid = 0, gid = 0;
00442     int             agent_mode = -1;
00443     char           *pid_file = NULL;
00444     char            option_compatability[] = "-Le";
00445 #if HAVE_GETPID
00446     int fd;
00447     FILE           *PID;
00448 #endif
00449 #if HAVE_GETPWNAM && HAVE_PWD_H
00450     struct passwd  *info;
00451 #endif
00452 #if HAVE_UNISTD_H
00453     const char     *persistent_dir;
00454 #endif
00455 
00456 #ifndef WIN32
00457     /*
00458      * close all non-standard file descriptors we may have
00459      * inherited from the shell.
00460      */
00461     for (i = getdtablesize() - 1; i > 2; --i) {
00462         (void) close(i);
00463     }
00464 #endif /* #WIN32 */
00465     
00466     /*
00467      * register signals ASAP to prevent default action (usually core)
00468      * for signals during startup...
00469      */
00470 #ifdef SIGTERM
00471     DEBUGMSGTL(("signal", "registering SIGTERM signal handler\n"));
00472     signal(SIGTERM, SnmpdShutDown);
00473 #endif
00474 #ifdef SIGINT
00475     DEBUGMSGTL(("signal", "registering SIGINT signal handler\n"));
00476     signal(SIGINT, SnmpdShutDown);
00477 #endif
00478 #ifdef SIGHUP
00479     signal(SIGHUP, SIG_IGN);   /* do not terminate on early SIGHUP */
00480 #endif
00481 #ifdef SIGUSR1
00482     DEBUGMSGTL(("signal", "registering SIGUSR1 signal handler\n"));
00483     signal(SIGUSR1, SnmpdDump);
00484 #endif
00485 #ifdef SIGPIPE
00486     DEBUGMSGTL(("signal", "registering SIGPIPE signal handler\n"));
00487     signal(SIGPIPE, SIG_IGN);   /* 'Inline' failure of wayward readers */
00488 #endif
00489 #ifdef SIGXFSZ
00490     signal(SIGXFSZ, SnmpdCatchRandomSignal);
00491 #endif
00492 
00493 #ifdef NETSNMP_NO_ROOT_ACCESS
00494     /*
00495      * Default to no.  
00496      */
00497     netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, 
00498                            NETSNMP_DS_AGENT_NO_ROOT_ACCESS, 1);
00499 #endif
00500     /*
00501      * Default to NOT running an AgentX master.  
00502      */
00503     netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, 
00504                            NETSNMP_DS_AGENT_AGENTX_MASTER, 0);
00505     netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID,
00506                        NETSNMP_DS_AGENT_AGENTX_TIMEOUT, -1);
00507     netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID,
00508                        NETSNMP_DS_AGENT_AGENTX_RETRIES, -1);
00509 
00510     netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID,
00511                        NETSNMP_DS_AGENT_CACHE_TIMEOUT, 5);
00512     /*
00513      * Add some options if they are available.  
00514      */
00515 #if HAVE_UNISTD_H
00516     strcat(options, "g:u:");
00517 #endif
00518 #if defined(USING_AGENTX_SUBAGENT_MODULE)|| defined(USING_AGENTX_MASTER_MODULE)
00519     strcat(options, "x:");
00520 #endif
00521 #ifdef USING_AGENTX_SUBAGENT_MODULE
00522     strcat(options, "X");
00523 #endif
00524 
00525     /*
00526      * This is incredibly ugly, but it's probably the simplest way
00527      *  to handle the old '-L' option as well as the new '-Lx' style
00528      */
00529     for (i=0; i<argc; i++) {
00530         if (!strcmp(argv[i], "-L"))
00531             argv[i] = option_compatability;            
00532     }
00533 
00534 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
00535 #ifdef WIN32
00536     snmp_log_syslogname(app_name_long);
00537 #else
00538     snmp_log_syslogname(app_name);
00539 #endif
00540 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
00541     netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID,
00542                           NETSNMP_DS_LIB_APPTYPE, app_name);
00543 
00544     /*
00545      * Now process options normally.  
00546      */
00547     while ((arg = getopt(argc, argv, options)) != EOF) {
00548         switch (arg) {
00549         case '-':
00550             if (strcasecmp(optarg, "help") == 0) {
00551                 usage(argv[0]);
00552             }
00553             if (strcasecmp(optarg, "version") == 0) {
00554                 version();
00555             }
00556 
00557             handle_long_opt(optarg);
00558             break;
00559 
00560         case 'a':
00561             log_addresses++;
00562             break;
00563 
00564         case 'A':
00565             netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID,
00566                                    NETSNMP_DS_LIB_APPEND_LOGFILES, 1);
00567             break;
00568 
00569         case 'c':
00570             if (optarg != NULL) {
00571                 netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID, 
00572                                       NETSNMP_DS_LIB_OPTIONALCONFIG, optarg);
00573             } else {
00574                 usage(argv[0]);
00575             }
00576             break;
00577 
00578         case 'C':
00579             netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, 
00580                                    NETSNMP_DS_LIB_DONT_READ_CONFIGS, 1);
00581             break;
00582 
00583         case 'd':
00584             netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, 
00585                                    NETSNMP_DS_LIB_QUICK_PRINT,
00586                                    ++snmp_dump_packet);
00587             break;
00588 
00589         case 'D':
00590             debug_register_tokens(optarg);
00591             snmp_set_do_debugging(1);
00592             break;
00593 
00594         case 'f':
00595             dont_fork = 1;
00596             break;
00597 
00598 #if HAVE_UNISTD_H
00599         case 'g':
00600             if (optarg != NULL) {
00601                 char           *ecp;
00602                 int             gid;
00603 
00604                 gid = strtoul(optarg, &ecp, 10);
00605                 if (*ecp) {
00606 #if HAVE_GETPWNAM && HAVE_PWD_H
00607                     struct group  *info;
00608                     info = getgrnam(optarg);
00609                     if (info) {
00610                         gid = info->gr_gid;
00611                     } else {
00612 #endif
00613                         fprintf(stderr, "Bad group id: %s\n", optarg);
00614                         exit(1);
00615 #if HAVE_GETPWNAM && HAVE_PWD_H
00616                     }
00617 #endif
00618                 }
00619                 netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID, 
00620                                    NETSNMP_DS_AGENT_GROUPID, gid);
00621             } else {
00622                 usage(argv[0]);
00623             }
00624             break;
00625 #endif
00626 
00627         case 'h':
00628             usage(argv[0]);
00629             break;
00630 
00631         case 'H':
00632             do_help = 1;
00633             break;
00634 
00635         case 'I':
00636             if (optarg != NULL) {
00637                 add_to_init_list(optarg);
00638             } else {
00639                 usage(argv[0]);
00640             }
00641             break;
00642 
00643 #ifdef NETSNMP_FEATURE_HAS_LOGGING_FILE
00644         case 'l':
00645             printf("Warning: -l option is deprecated, use -Lf <file> instead\n");
00646             if (optarg != NULL) {
00647                 if (strlen(optarg) > PATH_MAX) {
00648                     fprintf(stderr,
00649                             "%s: logfile path too long (limit %d chars)\n",
00650                             argv[0], PATH_MAX);
00651                     exit(1);
00652                 }
00653                 snmp_enable_filelog(optarg,
00654                                     netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
00655                                                            NETSNMP_DS_LIB_APPEND_LOGFILES));
00656                 log_set = 1;
00657             } else {
00658                 usage(argv[0]);
00659             }
00660             break;
00661 #endif /* NETSNMP_FEATURE_HAS_LOGGING_FILE */
00662 
00663         case 'L':
00664             if  (snmp_log_options( optarg, argc, argv ) < 0 ) {
00665                 usage(argv[0]);
00666             }
00667             log_set = 1;
00668             break;
00669 
00670         case 'm':
00671             if (optarg != NULL) {
00672                 setenv("MIBS", optarg, 1);
00673             } else {
00674                 usage(argv[0]);
00675             }
00676             break;
00677 
00678         case 'M':
00679             if (optarg != NULL) {
00680                 setenv("MIBDIRS", optarg, 1);
00681             } else {
00682                 usage(argv[0]);
00683             }
00684             break;
00685 
00686         case 'n':
00687             if (optarg != NULL) {
00688                 app_name = optarg;
00689                 netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID,
00690                                       NETSNMP_DS_LIB_APPTYPE, app_name);
00691             } else {
00692                 usage(argv[0]);
00693             }
00694             break;
00695 
00696         case 'P':
00697             printf("Warning: -P option is deprecated, use -p instead\n");
00698         case 'p':
00699             if (optarg != NULL) {
00700                 pid_file = optarg;
00701             } else {
00702                 usage(argv[0]);
00703             }
00704             break;
00705 
00706         case 'q':
00707             netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, 
00708                                    NETSNMP_DS_LIB_QUICK_PRINT, 1);
00709             break;
00710 
00711         case 'r':
00712             netsnmp_ds_toggle_boolean(NETSNMP_DS_APPLICATION_ID, 
00713                                       NETSNMP_DS_AGENT_NO_ROOT_ACCESS);
00714             break;
00715 
00716 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
00717         case 's':
00718             printf("Warning: -s option is deprecated, use -Lsd instead\n");
00719             snmp_enable_syslog();
00720             log_set = 1;
00721             break;
00722 
00723         case 'S':
00724             printf("Warning: -S option is deprecated, use -Ls <facility> instead\n");
00725             if (optarg != NULL) {
00726                 switch (*optarg) {
00727                 case 'd':
00728                 case 'D':
00729                     Facility = LOG_DAEMON;
00730                     break;
00731                 case 'i':
00732                 case 'I':
00733                     Facility = LOG_INFO;
00734                     break;
00735                 case '0':
00736                     Facility = LOG_LOCAL0;
00737                     break;
00738                 case '1':
00739                     Facility = LOG_LOCAL1;
00740                     break;
00741                 case '2':
00742                     Facility = LOG_LOCAL2;
00743                     break;
00744                 case '3':
00745                     Facility = LOG_LOCAL3;
00746                     break;
00747                 case '4':
00748                     Facility = LOG_LOCAL4;
00749                     break;
00750                 case '5':
00751                     Facility = LOG_LOCAL5;
00752                     break;
00753                 case '6':
00754                     Facility = LOG_LOCAL6;
00755                     break;
00756                 case '7':
00757                     Facility = LOG_LOCAL7;
00758                     break;
00759                 default:
00760                     fprintf(stderr, "invalid syslog facility: -S%c\n",*optarg);
00761                     usage(argv[0]);
00762                 }
00763                 snmp_enable_syslog_ident(snmp_log_syslogname(NULL), Facility);
00764                 log_set = 1;
00765             } else {
00766                 fprintf(stderr, "no syslog facility specified\n");
00767                 usage(argv[0]);
00768             }
00769             break;
00770 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
00771 
00772         case 'U':
00773             netsnmp_ds_toggle_boolean(NETSNMP_DS_APPLICATION_ID, 
00774                                       NETSNMP_DS_AGENT_LEAVE_PIDFILE);
00775             break;
00776 
00777 #if HAVE_UNISTD_H
00778         case 'u':
00779             if (optarg != NULL) {
00780                 char           *ecp;
00781                 int             uid;
00782 
00783                 uid = strtoul(optarg, &ecp, 10);
00784                 if (*ecp) {
00785 #if HAVE_GETPWNAM && HAVE_PWD_H
00786                     info = getpwnam(optarg);
00787                     if (info) {
00788                         uid = info->pw_uid;
00789                     } else {
00790 #endif
00791                         fprintf(stderr, "Bad user id: %s\n", optarg);
00792                         exit(1);
00793 #if HAVE_GETPWNAM && HAVE_PWD_H
00794                     }
00795 #endif
00796                 }
00797                 netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID, 
00798                                    NETSNMP_DS_AGENT_USERID, uid);
00799             } else {
00800                 usage(argv[0]);
00801             }
00802             break;
00803 #endif
00804 
00805         case 'v':
00806             version();
00807 
00808         case 'V':
00809             netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, 
00810                                    NETSNMP_DS_AGENT_VERBOSE, 1);
00811             break;
00812 
00813 #if defined(USING_AGENTX_SUBAGENT_MODULE)|| defined(USING_AGENTX_MASTER_MODULE)
00814         case 'x':
00815             if (optarg != NULL) {
00816                 netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, 
00817                                       NETSNMP_DS_AGENT_X_SOCKET, optarg);
00818             } else {
00819                 usage(argv[0]);
00820             }
00821             netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, 
00822                                    NETSNMP_DS_AGENT_AGENTX_MASTER, 1);
00823             break;
00824 #endif
00825 
00826         case 'X':
00827 #if defined(USING_AGENTX_SUBAGENT_MODULE)
00828             agent_mode = SUB_AGENT;
00829 #else
00830             fprintf(stderr, "%s: Illegal argument -X:"
00831                             "AgentX support not compiled in.\n", argv[0]);
00832             usage(argv[0]);
00833             exit(1);
00834 #endif
00835             break;
00836 
00837         case 'Y':
00838             netsnmp_config_remember(optarg);
00839             break;
00840 
00841         default:
00842             usage(argv[0]);
00843             break;
00844         }
00845     }
00846 
00847     if (do_help) {
00848         netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, 
00849                                NETSNMP_DS_AGENT_NO_ROOT_ACCESS, 1);
00850         init_agent(app_name);        /* register our .conf handlers */
00851         init_mib_modules();
00852         init_snmp(app_name);
00853         fprintf(stderr, "Configuration directives understood:\n");
00854         read_config_print_usage("  ");
00855         exit(0);
00856     }
00857 
00858     if (optind < argc) {
00859 #ifndef NETSNMP_NO_LISTEN_SUPPORT
00860         /*
00861          * There are optional transport addresses on the command line.  
00862          */
00863         DEBUGMSGTL(("snmpd/main", "optind %d, argc %d\n", optind, argc));
00864         for (i = optind; i < argc; i++) {
00865             char *c, *astring;
00866             if ((c = netsnmp_ds_get_string(NETSNMP_DS_APPLICATION_ID, 
00867                                            NETSNMP_DS_AGENT_PORTS))) {
00868                 astring = (char*)malloc(strlen(c) + 2 + strlen(argv[i]));
00869                 if (astring == NULL) {
00870                     fprintf(stderr, "malloc failure processing argv[%d]\n", i);
00871                     exit(1);
00872                 }
00873                 sprintf(astring, "%s,%s", c, argv[i]);
00874                 netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, 
00875                                       NETSNMP_DS_AGENT_PORTS, astring);
00876                 SNMP_FREE(astring);
00877             } else {
00878                 netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, 
00879                                       NETSNMP_DS_AGENT_PORTS, argv[i]);
00880             }
00881         }
00882         DEBUGMSGTL(("snmpd/main", "port spec: %s\n",
00883                     netsnmp_ds_get_string(NETSNMP_DS_APPLICATION_ID, 
00884                                           NETSNMP_DS_AGENT_PORTS)));
00885 #else /* NETSNMP_NO_LISTEN_SUPPORT */
00886         fprintf(stderr, "You specified ports to open; this agent was built to only send notifications\n");
00887         exit(1);
00888 #endif /* NETSNMP_NO_LISTEN_SUPPORT */
00889     }
00890 
00891 #ifdef NETSNMP_LOGFILE
00892 #ifdef NETSNMP_FEATURE_HAS_LOGGING_FILE
00893     if (0 == log_set)
00894         snmp_enable_filelog(NETSNMP_LOGFILE,
00895                             netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
00896                                                    NETSNMP_DS_LIB_APPEND_LOGFILES));
00897 #endif /* NETSNMP_FEATURE_HAS_LOGGING_FILE */
00898 #endif
00899 
00900 #ifdef USING_UTIL_FUNCS_RESTART_MODULE
00901     {
00902         /*
00903          * Initialize a argv set to the current for restarting the agent.
00904          */
00905         char *cptr, **argvptr;
00906 
00907         argvrestartp = (char **)malloc((argc + 2) * sizeof(char *));
00908         argvptr = argvrestartp;
00909         for (i = 0, ret = 1; i < argc; i++) {
00910             ret += strlen(argv[i]) + 1;
00911         }
00912         argvrestart = (char *) malloc(ret);
00913         argvrestartname = (char *) malloc(strlen(argv[0]) + 1);
00914         if (!argvrestartp || !argvrestart || !argvrestartname) {
00915             fprintf(stderr, "malloc failure processing argvrestart\n");
00916             exit(1);
00917         }
00918         strcpy(argvrestartname, argv[0]);
00919 
00920         for (cptr = argvrestart, i = 0; i < argc; i++) {
00921             strcpy(cptr, argv[i]);
00922             *(argvptr++) = cptr;
00923             cptr += strlen(argv[i]) + 1;
00924         }
00925     }
00926 #endif /* USING_UTIL_FUNCS_RESTART_MODULE */
00927 
00928     if (agent_mode == -1) {
00929         if (strstr(argv[0], "agentxd") != NULL) {
00930             netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID,
00931                                    NETSNMP_DS_AGENT_ROLE, SUB_AGENT);
00932         } else {
00933             netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID,
00934                                    NETSNMP_DS_AGENT_ROLE, MASTER_AGENT);
00935         }
00936     } else {
00937         netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID,
00938                                NETSNMP_DS_AGENT_ROLE, agent_mode);
00939     }
00940 
00941     SOCK_STARTUP;
00942     init_agent(app_name);        /* do what we need to do first. */
00943     init_mib_modules();
00944 
00945     /*
00946      * start library 
00947      */
00948     init_snmp(app_name);
00949 
00950     if ((ret = init_master_agent()) != 0) {
00951         /*
00952          * Some error opening one of the specified agent transports.  
00953          */
00954         snmp_log(LOG_ERR, "Server Exiting with code 1\n");
00955         exit(1);
00956     }
00957 
00958     /*
00959      * Initialize the world.  Detach from the shell.  Create initial user.  
00960      */
00961     if(!dont_fork) {
00962         int quit = ! netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
00963                                             NETSNMP_DS_AGENT_QUIT_IMMEDIATELY);
00964         ret = netsnmp_daemonize(quit,
00965 #ifdef NETSNMP_FEATURE_HAS_LOGGING_STDIO
00966                                 snmp_stderrlog_status()
00967 #else /* NETSNMP_FEATURE_HAS_LOGGING_STDIO */
00968                                 0
00969 #endif /* NETSNMP_FEATURE_HAS_LOGGING_STDIO */
00970             );
00971         /*
00972          * xxx-rks: do we care if fork fails? I think we should...
00973          */
00974         if(ret != 0) {
00975             snmp_log(LOG_ERR, "Server Exiting with code 1\n");
00976             exit(1);
00977         }
00978     }
00979 
00980 #if HAVE_GETPID
00981     if (pid_file != NULL) {
00982         /*
00983          * unlink the pid_file, if it exists, prior to open.  Without
00984          * doing this the open will fail if the user specified pid_file
00985          * already exists.
00986          */
00987         unlink(pid_file);
00988         fd = open(pid_file, O_CREAT | O_EXCL | O_WRONLY, 0600);
00989         if (fd == -1) {
00990             snmp_log_perror(pid_file);
00991             if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
00992                                         NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) {
00993                 exit(1);
00994             }
00995         } else {
00996             if ((PID = fdopen(fd, "w")) == NULL) {
00997                 snmp_log_perror(pid_file);
00998                 exit(1);
00999             } else {
01000                 fprintf(PID, "%d\n", (int) getpid());
01001                 fclose(PID);
01002             }
01003             close(fd);
01004         }
01005     }
01006 #endif
01007 
01008 #if HAVE_UNISTD_H
01009     persistent_dir = get_persistent_directory();
01010     mkdirhier( persistent_dir, NETSNMP_AGENT_DIRECTORY_MODE, 0 );
01011    
01012     uid = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, 
01013                              NETSNMP_DS_AGENT_USERID);
01014     gid = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, 
01015                              NETSNMP_DS_AGENT_GROUPID);
01016     
01017 #ifdef HAVE_CHOWN
01018     if ( uid != 0 || gid != 0 )
01019         chown( persistent_dir, uid, gid );
01020 #endif
01021 
01022 #ifdef HAVE_SETGID
01023     if ((gid = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, 
01024                                   NETSNMP_DS_AGENT_GROUPID)) != 0) {
01025         DEBUGMSGTL(("snmpd/main", "Changing gid to %d.\n", gid));
01026         if (setgid(gid) == -1
01027 #ifdef HAVE_SETGROUPS
01028             || setgroups(1, (gid_t *)&gid) == -1
01029 #endif
01030             ) {
01031             snmp_log_perror("setgid failed");
01032             if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
01033                                         NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) {
01034                 exit(1);
01035             }
01036         }
01037     }
01038 #endif
01039 #ifdef HAVE_SETUID
01040     if ((uid = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, 
01041                                   NETSNMP_DS_AGENT_USERID)) != 0) {
01042 #if HAVE_GETPWNAM && HAVE_PWD_H && HAVE_INITGROUPS
01043         /*
01044          * Set supplementary groups before changing UID
01045          *   (which probably involves giving up privileges)
01046          */
01047         info = getpwuid(uid);
01048         if (info) {
01049             DEBUGMSGTL(("snmpd/main", "Supplementary groups for %s.\n", info->pw_name));
01050             if (initgroups(info->pw_name, (gid != 0 ? (gid_t)gid : info->pw_gid)) == -1) {
01051                 snmp_log_perror("initgroups failed");
01052                 if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
01053                                             NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) {
01054                     exit(1);
01055                 }
01056             }
01057         }
01058 #endif
01059         DEBUGMSGTL(("snmpd/main", "Changing uid to %d.\n", uid));
01060         if (setuid(uid) == -1) {
01061             snmp_log_perror("setuid failed");
01062             if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
01063                                         NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) {
01064                 exit(1);
01065             }
01066         }
01067     }
01068 #endif
01069 #endif
01070 
01071     /*
01072      * Store persistent data immediately in case we crash later.  
01073      */
01074     snmp_store(app_name);
01075 
01076 #ifdef SIGHUP
01077     DEBUGMSGTL(("signal", "registering SIGHUP signal handler\n"));
01078     signal(SIGHUP, SnmpdReconfig);
01079 #endif
01080 
01081     /*
01082      * Send coldstart trap if possible.  
01083      */
01084     send_easy_trap(0, 0);
01085 
01086     /*
01087      * We're up, log our version number.  
01088      */
01089     snmp_log(LOG_INFO, "NET-SNMP version %s\n", netsnmp_get_version());
01090 #ifdef WIN32SERVICE
01091     agent_status = AGENT_RUNNING;
01092 #endif
01093     netsnmp_addrcache_initialise();
01094 
01095     /*
01096      * Forever monitor the dest_port for incoming PDUs.  
01097      */
01098     DEBUGMSGTL(("snmpd/main", "We're up.  Starting to process data.\n"));
01099     if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
01100                                 NETSNMP_DS_AGENT_QUIT_IMMEDIATELY))
01101         receive();
01102     DEBUGMSGTL(("snmpd/main", "sending shutdown trap\n"));
01103     SnmpTrapNodeDown();
01104     DEBUGMSGTL(("snmpd/main", "Bye...\n"));
01105     snmp_shutdown(app_name);
01106     shutdown_master_agent();
01107     shutdown_agent();
01108 
01109     if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
01110                                 NETSNMP_DS_AGENT_LEAVE_PIDFILE) &&
01111         (pid_file != NULL)) {
01112         unlink(pid_file);
01113     }
01114 #ifdef WIN32SERVICE
01115     agent_status = AGENT_STOPPED;
01116 #endif
01117 
01118 #ifdef USING_UTIL_FUNCS_RESTART_MODULE
01119     SNMP_FREE(argvrestartname);
01120     SNMP_FREE(argvrestart);
01121     SNMP_FREE(argvrestartp);
01122 #endif /* USING_UTIL_FUNCS_RESTART_MODULE */
01123 
01124     SOCK_CLEANUP;
01125     return 0;
01126 }                               /* End main() -- snmpd */
01127 
01128 #if defined(WIN32)
01129 
01130 #include <process.h>
01131 #include <net-snmp/library/snmp_assert.h>
01132 
01133 static unsigned s_threadid;
01134 HANDLE s_thread_handle;
01135 
01136 static unsigned __stdcall wait_for_stdin(void* arg)
01137 {
01138     if (getc(stdin) != EOF)
01139         netsnmp_running = 0;
01140     return 0;
01141 }
01142 
01143 static void create_stdin_waiter_thread(void)
01144 {
01145     netsnmp_assert(s_thread_handle == 0);
01146     s_thread_handle = (HANDLE)_beginthreadex(0, 0, wait_for_stdin, 0, 0, &s_threadid);
01147     netsnmp_assert(s_thread_handle != 0);
01148 }
01149 
01150 static void join_stdin_waiter_thread(void)
01151 {
01152     int result;
01153 
01154     netsnmp_assert(s_thread_handle != 0);
01155     result = WaitForSingleObject(s_thread_handle, 1000);
01156     netsnmp_assert(result != WAIT_TIMEOUT);
01157     CloseHandle(s_thread_handle);
01158     s_thread_handle = 0;
01159 }
01160 #endif
01161 
01162 /*******************************************************************-o-******
01163  * receive
01164  *
01165  * Parameters:
01166  *      
01167  * Returns:
01168  *      0       On success.
01169  *      -1      System error.
01170  *
01171  * Infinite while-loop which monitors incoming messages for the agent.
01172  * Invoke the established message handlers for incoming messages on a per
01173  * port basis.  Handle timeouts.
01174  */
01175 static int
01176 receive(void)
01177 {
01178     int             numfds;
01179     netsnmp_large_fd_set readfds, writefds, exceptfds;
01180     struct timeval  timeout, *tvp = &timeout;
01181     int             count, block, i;
01182 #ifdef  USING_SMUX_MODULE
01183     int             sd;
01184 #endif                          /* USING_SMUX_MODULE */
01185 
01186     netsnmp_large_fd_set_init(&readfds, FD_SETSIZE);
01187     netsnmp_large_fd_set_init(&writefds, FD_SETSIZE);
01188     netsnmp_large_fd_set_init(&exceptfds, FD_SETSIZE);
01189 
01190     /*
01191      * ignore early sighup during startup
01192      */
01193     reconfig = 0;
01194 
01195 #if defined(WIN32)
01196     create_stdin_waiter_thread();
01197 #endif
01198 
01199     /*
01200      * Loop-forever: execute message handlers for sockets with data
01201      */
01202     while (netsnmp_running) {
01203         if (reconfig) {
01204 #if HAVE_SIGHOLD
01205             sighold(SIGHUP);
01206 #endif
01207             reconfig = 0;
01208             snmp_log(LOG_INFO, "Reconfiguring daemon\n");
01209             /*  Stop and restart logging.  This allows logfiles to be
01210                 rotated etc.  */
01211             netsnmp_logging_restart();
01212             snmp_log(LOG_INFO, "NET-SNMP version %s restarted\n",
01213                      netsnmp_get_version());
01214             update_config();
01215             send_easy_trap(SNMP_TRAP_ENTERPRISESPECIFIC, 3);
01216 #if HAVE_SIGHOLD
01217             sigrelse(SIGHUP);
01218 #endif
01219         }
01220 
01221         for (i = 0; i < NUM_EXTERNAL_SIGS; i++) {
01222             if (external_signal_scheduled[i]) {
01223                 external_signal_scheduled[i]--;
01224                 external_signal_handler[i](i);
01225             }
01226         }
01227 
01228         /*
01229          * default to sleeping for a really long time. INT_MAX
01230          * should be sufficient (eg we don't care if time_t is
01231          * a long that's bigger than an int).
01232          */
01233         tvp = &timeout;
01234         tvp->tv_sec = INT_MAX;
01235         tvp->tv_usec = 0;
01236 
01237         numfds = 0;
01238         NETSNMP_LARGE_FD_ZERO(&readfds);
01239         NETSNMP_LARGE_FD_ZERO(&writefds);
01240         NETSNMP_LARGE_FD_ZERO(&exceptfds);
01241         block = 0;
01242         snmp_select_info2(&numfds, &readfds, tvp, &block);
01243         if (block == 1) {
01244             tvp = NULL;         /* block without timeout */
01245         }
01246 
01247 #ifdef  USING_SMUX_MODULE
01248         if (smux_listen_sd >= 0) {
01249             NETSNMP_LARGE_FD_SET(smux_listen_sd, &readfds);
01250             numfds =
01251                 smux_listen_sd >= numfds ? smux_listen_sd + 1 : numfds;
01252 
01253             for (i = 0; i < smux_snmp_select_list_get_length(); i++) {
01254                 sd = smux_snmp_select_list_get_SD_from_List(i);
01255                 if (sd != 0)
01256                 {
01257                    NETSNMP_LARGE_FD_SET(sd, &readfds);
01258                    numfds = sd >= numfds ? sd + 1 : numfds;
01259                 }
01260             }
01261         }
01262 #endif                          /* USING_SMUX_MODULE */
01263 
01264 #ifndef NETSNMP_FEATURE_REMOVE_FD_EVENT_MANAGER
01265         netsnmp_external_event_info2(&numfds, &readfds, &writefds, &exceptfds);
01266 #endif /* NETSNMP_FEATURE_REMOVE_FD_EVENT_MANAGER */
01267 
01268     reselect:
01269         DEBUGMSGTL(("snmpd/select", "select( numfds=%d, ..., tvp=%p)\n",
01270                     numfds, tvp));
01271         if(tvp)
01272             DEBUGMSGTL(("timer", "tvp %ld.%ld\n", tvp->tv_sec, tvp->tv_usec));
01273         count = netsnmp_large_fd_set_select(numfds, &readfds, &writefds, &exceptfds,
01274                                      tvp);
01275         DEBUGMSGTL(("snmpd/select", "returned, count = %d\n", count));
01276 
01277         if (count > 0) {
01278 
01279 #ifdef USING_SMUX_MODULE
01280             /*
01281              * handle the SMUX sd's 
01282              */
01283             if (smux_listen_sd >= 0) {
01284                 for (i = 0; i < smux_snmp_select_list_get_length(); i++) {
01285                     sd = smux_snmp_select_list_get_SD_from_List(i);
01286                     if (NETSNMP_LARGE_FD_ISSET(sd, &readfds)) {
01287                         if (smux_process(sd) < 0) {
01288                             smux_snmp_select_list_del(sd);
01289                         }
01290                     }
01291                 }
01292                 /*
01293                  * new connection 
01294                  */
01295                 if (NETSNMP_LARGE_FD_ISSET(smux_listen_sd, &readfds)) {
01296                     if ((sd = smux_accept(smux_listen_sd)) >= 0) {
01297                         smux_snmp_select_list_add(sd);
01298                     }
01299                 }
01300             }
01301 
01302 #endif                          /* USING_SMUX_MODULE */
01303 
01304 #ifndef NETSNMP_FEATURE_REMOVE_FD_EVENT_MANAGER
01305             netsnmp_dispatch_external_events2(&count, &readfds,
01306                                               &writefds, &exceptfds);
01307 #endif /* NETSNMP_FEATURE_REMOVE_FD_EVENT_MANAGER */
01308 
01309             /* If there are still events leftover, process them */
01310             if (count > 0) {
01311               snmp_read2(&readfds);
01312             }
01313         } else
01314             switch (count) {
01315             case 0:
01316                 snmp_timeout();
01317                 break;
01318             case -1:
01319                 DEBUGMSGTL(("snmpd/select", "  errno = %d\n", errno));
01320                 if (errno == EINTR) {
01321                     /*
01322                      * likely that we got a signal. Check our special signal
01323                      * flags before retrying select.
01324                      */
01325                     if (netsnmp_running && !reconfig) {
01326                         goto reselect;
01327                     }
01328                     continue;
01329                 } else {
01330                     snmp_log_perror("select");
01331                 }
01332                 return -1;
01333             default:
01334                 snmp_log(LOG_ERR, "select returned %d\n", count);
01335                 return -1;
01336             }                   /* endif -- count>0 */
01337 
01338         /*
01339          * see if persistent store needs to be saved
01340          */
01341         snmp_store_if_needed();
01342 
01343         /*
01344          * run requested alarms 
01345          */
01346         run_alarms();
01347 
01348         netsnmp_check_outstanding_agent_requests();
01349 
01350     }                           /* endwhile */
01351 
01352     netsnmp_large_fd_set_cleanup(&readfds);
01353     netsnmp_large_fd_set_cleanup(&writefds);
01354     netsnmp_large_fd_set_cleanup(&exceptfds);
01355 
01356 #if defined(WIN32)
01357     join_stdin_waiter_thread();
01358 #endif
01359 
01360     snmp_log(LOG_INFO, "Received TERM or STOP signal...  shutting down...\n");
01361     return 0;
01362 
01363 }                               /* end receive() */
01364 
01365 
01366 
01367 /*******************************************************************-o-******
01368  * snmp_input
01369  *
01370  * Parameters:
01371  *       op
01372  *      *session
01373  *       requid
01374  *      *pdu
01375  *      *magic
01376  *      
01377  * Returns:
01378  *      1               On success      -OR-
01379  *      Passes through  Return from alarmGetResponse() when 
01380  *                        USING_V2PARTY_ALARM_MODULE is defined.
01381  *
01382  * Call-back function to manage responses to traps (informs) and alarms.
01383  * Not used by the agent to process other Response PDUs.
01384  */
01385 int
01386 snmp_input(int op,
01387            netsnmp_session * session,
01388            int reqid, netsnmp_pdu *pdu, void *magic)
01389 {
01390     struct get_req_state *state = (struct get_req_state *) magic;
01391 
01392     if (op == NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE) {
01393         if (pdu->command == SNMP_MSG_GET) {
01394             if (state->type == EVENT_GET_REQ) {
01395                 /*
01396                  * this is just the ack to our inform pdu 
01397                  */
01398                 return 1;
01399             }
01400         }
01401     } else if (op == NETSNMP_CALLBACK_OP_TIMED_OUT) {
01402         if (state->type == ALARM_GET_REQ) {
01403             /*
01404              * Need a mechanism to replace obsolete SNMPv2p alarm 
01405              */
01406         }
01407     }
01408     return 1;
01409 
01410 }                               /* end snmp_input() */
01411 
01412 
01413 
01414 /*
01415  * Windows Service Related functions 
01416  */
01417 #ifdef WIN32SERVICE
01418 /************************************************************
01419 * main function for Windows
01420 * Parse command line arguments for startup options,
01421 * to start as service or console mode application in windows.
01422 * Invokes appropriate startup functions depending on the 
01423 * parameters passed
01424 *************************************************************/
01425 int
01426     __cdecl
01427 _tmain(int argc, TCHAR * argv[])
01428 {
01429     /*
01430      * Define Service Name and Description, which appears in windows SCM 
01431      */
01432     LPCTSTR         lpszServiceName = app_name_long;      /* Service Registry Name */
01433     LPCTSTR         lpszServiceDisplayName = _T("Net-SNMP Agent");       /* Display Name */
01434     LPCTSTR         lpszServiceDescription =
01435 #ifdef IFDESCR
01436         _T("SNMPv2c / SNMPv3 command responder from Net-SNMP. Supports MIB objects for IP,ICMP,TCP,UDP, and network interface sub-layers.");
01437 #else
01438         _T("SNMPv2c / SNMPv3 command responder from Net-SNMP");
01439 #endif
01440     InputParams     InputOptions;
01441 
01442 
01443     int             nRunType = RUN_AS_CONSOLE;
01444     int             quiet = 0;
01445     
01446 #if 0
01447     _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF /*| _CRTDBG_CHECK_ALWAYS_DF*/);
01448 #endif
01449 
01450     nRunType = ParseCmdLineForServiceOption(argc, argv, &quiet);
01451 
01452     switch (nRunType) {
01453     case REGISTER_SERVICE:
01454         /*
01455          * Register As service 
01456          */
01457         InputOptions.Argc = argc;
01458         InputOptions.Argv = argv;
01459         exit (RegisterService(lpszServiceName,
01460                         lpszServiceDisplayName,
01461                         lpszServiceDescription, &InputOptions, quiet));
01462         break;
01463     case UN_REGISTER_SERVICE:
01464         /*
01465          * Unregister service 
01466          */
01467         exit (UnregisterService(lpszServiceName, quiet));
01468         break;
01469     case RUN_AS_SERVICE:
01470         /*
01471          * Run as service 
01472          */
01473         /*
01474          * Register Stop Function 
01475          */
01476         RegisterStopFunction(StopSnmpAgent);
01477         return RunAsService(SnmpDaemonMain);
01478         break;
01479     default:
01480         /*
01481          * Run in console mode 
01482          */
01483         return SnmpDaemonMain(argc, argv);
01484         break;
01485     }
01486 }
01487 
01488 /*
01489  * To stop Snmp Agent daemon
01490  * This portion is still not working
01491  */
01492 void
01493 StopSnmpAgent(void)
01494 {
01495     /*
01496      * Shut Down Agent 
01497      */
01498     SnmpdShutDown(1);
01499 
01500     /*
01501      * Wait till agent is completely stopped 
01502      */
01503 
01504     while (agent_status != AGENT_STOPPED) {
01505         Sleep(100);
01506     }
01507 }
01508 
01509 #endif /*WIN32SERVICE*/