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