int main(void) { int e, i; pid_t p, child; #ifdef ARC4_PREINIT (void) arc4random(); #endif fork_data = (arc4_fork_t *)mmap(NULL, sizeof (arc4_fork_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0); assert(fork_data != MAP_FAILED); p = forkall(); assert(p != -1); if (p == 0) { fork_data->af_child = arc4random(); arc4random_buf(fork_data->af_cbuf, sizeof (fork_data->af_cbuf)); exit(0); } fork_data->af_parent = arc4random(); arc4random_buf(fork_data->af_pbuf, sizeof (fork_data->af_pbuf)); do { child = wait(&e); } while (child == -1 && errno == EINTR); assert(child == p); /* Now verify our data doesn't match */ assert(fork_data->af_parent != fork_data->af_child); /* * For the buffer here, we're mostly concerned that they aren't somehow * getting the same stream. */ for (i = 0; i < sizeof (fork_data->af_pbuf); i++) { if (fork_data->af_pbuf[i] != fork_data->af_cbuf[i]) break; } assert(i != sizeof (fork_data->af_pbuf)); return (0); }
main(int argc, char *argv[]) #endif { char options[128] = "aAc:CdD::efF:g:hHI:L:m:M:no:O:Ptu:vx:X-:"; netsnmp_session *sess_list = NULL, *ss = NULL; netsnmp_transport *transport = NULL; int arg, i = 0; int uid = 0, gid = 0; int exit_code = 1; char *cp, *listen_ports = NULL; #if defined(USING_AGENTX_SUBAGENT_MODULE) && !defined(NETSNMP_SNMPTRAPD_DISABLE_AGENTX) int agentx_subagent = 1; #endif netsnmp_trapd_handler *traph; #ifndef WIN32 int prepared_sockets = 0; #endif #ifndef NETSNMP_NO_SYSTEMD /* check if systemd has sockets for us and don't close them */ prepared_sockets = netsnmp_sd_listen_fds(0); #endif #ifndef WIN32 /* * close all non-standard file descriptors we may have * inherited from the shell. */ if (!prepared_sockets) netsnmp_close_fds(2); #endif #ifdef SIGTERM signal(SIGTERM, term_handler); #endif #ifdef SIGHUP signal(SIGHUP, SIG_IGN); /* do not terminate on early SIGHUP */ #endif #ifdef SIGINT signal(SIGINT, term_handler); #endif #ifdef SIGPIPE signal(SIGPIPE, SIG_IGN); /* 'Inline' failure of wayward readers */ #endif /* * register our configuration handlers now so -H properly displays them */ snmptrapd_register_configs( ); #ifdef NETSNMP_USE_MYSQL snmptrapd_register_sql_configs( ); #endif #ifdef NETSNMP_SECMOD_USM init_usm_conf( "snmptrapd" ); #endif /* NETSNMP_SECMOD_USM */ register_config_handler("snmptrapd", "snmpTrapdAddr", parse_trapd_address, free_trapd_address, "string"); register_config_handler("snmptrapd", "doNotLogTraps", parse_config_doNotLogTraps, NULL, "(1|yes|true|0|no|false)"); #if HAVE_GETPID register_config_handler("snmptrapd", "pidFile", parse_config_pidFile, NULL, "string"); #endif #ifdef HAVE_UNISTD_H register_config_handler("snmptrapd", "agentuser", parse_config_agentuser, NULL, "userid"); register_config_handler("snmptrapd", "agentgroup", parse_config_agentgroup, NULL, "groupid"); #endif register_config_handler("snmptrapd", "doNotFork", parse_config_doNotFork, NULL, "(1|yes|true|0|no|false)"); register_config_handler("snmptrapd", "ignoreAuthFailure", parse_config_ignoreAuthFailure, NULL, "(1|yes|true|0|no|false)"); register_config_handler("snmptrapd", "outputOption", parse_config_outputOption, NULL, "string"); /* * Add some options if they are available. */ #if HAVE_GETPID strcat(options, "p:"); #endif #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG #ifdef WIN32 snmp_log_syslogname(app_name_long); #else snmp_log_syslogname(app_name); #endif #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */ /* * Now process options normally. */ while ((arg = getopt(argc, argv, options)) != EOF) { switch (arg) { case '-': if (strcasecmp(optarg, "help") == 0 || strcasecmp(optarg, "version") == 0) { version(); exit_code = 0; goto out; } handle_long_opt(optarg); break; case 'a': dropauth = 1; break; case 'A': netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_APPEND_LOGFILES, 1); break; case 'c': if (optarg != NULL) { netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OPTIONALCONFIG, optarg); } else { usage(); goto out; } break; case 'C': netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DONT_READ_CONFIGS, 1); break; case 'd': netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DUMP_PACKET, 1); break; case 'D': debug_register_tokens(optarg); snmp_set_do_debugging(1); break; case 'f': dofork = 0; break; case 'F': if (optarg != NULL) { if (( strncmp( optarg, "print", 5 ) == 0 ) || ( strncmp( optarg, "syslog", 6 ) == 0 ) || ( strncmp( optarg, "execute", 7 ) == 0 )) { /* New style: "type=format" */ trap1_fmt_str_remember = strdup(optarg); cp = strchr( trap1_fmt_str_remember, '=' ); if (cp) *cp = ' '; } else { /* Old style: implicitly "print=format" */ trap1_fmt_str_remember = malloc(strlen(optarg) + 7); sprintf( trap1_fmt_str_remember, "print %s", optarg ); } } else { usage(); goto out; } break; #if HAVE_UNISTD_H case 'g': if (optarg != NULL) { netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_GROUPID, gid = atoi(optarg)); } else { usage(); goto out; } break; #endif case 'h': usage(); exit_code = 0; goto out; case 'H': init_agent("snmptrapd"); #ifdef USING_NOTIFICATION_LOG_MIB_NOTIFICATION_LOG_MODULE init_notification_log(); #endif #ifdef NETSNMP_EMBEDDED_PERL init_perl(); #endif init_snmp("snmptrapd"); fprintf(stderr, "Configuration directives understood:\n"); read_config_print_usage(" "); exit_code = 0; goto out; case 'I': if (optarg != NULL) { add_to_init_list(optarg); } else { usage(); } break; case 'S': fprintf(stderr, "Warning: -S option has been withdrawn; use -Ls <facility> instead\n"); goto out; case 'm': if (optarg != NULL) { setenv("MIBS", optarg, 1); } else { usage(); goto out; } break; case 'M': if (optarg != NULL) { setenv("MIBDIRS", optarg, 1); } else { usage(); goto out; } break; case 'n': netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_APP_NUMERIC_IP, 1); break; case 'o': fprintf(stderr, "Warning: -o option has been withdrawn; use -Lf <file> instead\n"); goto out; case 'O': cp = snmp_out_toggle_options(optarg); if (cp != NULL) { fprintf(stderr, "Unknown output option passed to -O: %c\n", *cp); usage(); goto out; } break; case 'L': if (snmp_log_options( optarg, argc, argv ) < 0 ) { usage(); goto out; } break; #if HAVE_GETPID case 'p': if (optarg != NULL) { parse_config_pidFile(NULL, optarg); } else { usage(); goto out; } break; #endif case 'P': fprintf(stderr, "Warning: -P option has been withdrawn; use -f -Le instead\n"); goto out; case 's': fprintf(stderr, "Warning: -s option has been withdrawn; use -Lsd instead\n"); goto out; case 't': SyslogTrap++; break; #if HAVE_UNISTD_H case 'u': if (optarg != NULL) { char *ecp; uid = strtoul(optarg, &ecp, 10); #if HAVE_GETPWNAM && HAVE_PWD_H if (*ecp) { struct passwd *info; info = getpwnam(optarg); uid = info ? info->pw_uid : -1; endpwent(); } #endif if (uid < 0) { fprintf(stderr, "Bad user id: %s\n", optarg); goto out; } netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_USERID, uid); } else { usage(); goto out; } break; #endif case 'v': version(); exit(0); break; #if defined(USING_AGENTX_SUBAGENT_MODULE) && !defined(NETSNMP_SNMPTRAPD_DISABLE_AGENTX) case 'x': if (optarg != NULL) { netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_X_SOCKET, optarg); } else { usage(); goto out; } break; case 'X': agentx_subagent = 0; break; #endif default: fprintf(stderr, "invalid option: -%c\n", arg); usage(); goto out; break; } } if (optind < argc) { /* * There are optional transport addresses on the command line. */ for (i = optind; i < argc; i++) { char *astring; if (listen_ports != NULL) { astring = malloc(strlen(listen_ports) + 2 + strlen(argv[i])); if (astring == NULL) { fprintf(stderr, "malloc failure processing argv[%d]\n", i); goto out; } sprintf(astring, "%s,%s", listen_ports, argv[i]); free(listen_ports); listen_ports = astring; } else { listen_ports = strdup(argv[i]); if (listen_ports == NULL) { fprintf(stderr, "malloc failure processing argv[%d]\n", i); goto out; } } } } SOCK_STARTUP; /* * I'm being lazy here, and not checking the * return value from these registration calls. * Don't try this at home, children! */ if (0 == snmp_get_do_logging()) { #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG traph = netsnmp_add_global_traphandler(NETSNMPTRAPD_PRE_HANDLER, syslog_handler); traph->authtypes = TRAP_AUTH_LOG; snmp_enable_syslog(); #else /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */ #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_STDIO traph = netsnmp_add_global_traphandler(NETSNMPTRAPD_PRE_HANDLER, print_handler); traph->authtypes = TRAP_AUTH_LOG; snmp_enable_stderr(); #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_STDIO */ #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */ } else { traph = netsnmp_add_global_traphandler(NETSNMPTRAPD_PRE_HANDLER, print_handler); traph->authtypes = TRAP_AUTH_LOG; } #if defined(USING_AGENTX_SUBAGENT_MODULE) && !defined(NETSNMP_SNMPTRAPD_DISABLE_AGENTX) /* * we're an agentx subagent? */ if (agentx_subagent) { /* * make us a agentx client. */ netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, 1); } #endif /* * don't fail if we can't do agentx (ie, socket not there, or not root) */ netsnmp_ds_toggle_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_ROOT_ACCESS); /* * ignore any warning messages. */ netsnmp_ds_toggle_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_CONNECTION_WARNINGS); /* * initialize the agent library */ init_agent("snmptrapd"); #if defined(USING_AGENTX_SUBAGENT_MODULE) && !defined(NETSNMP_SNMPTRAPD_DISABLE_AGENTX) #ifdef NETSNMP_FEATURE_CHECKING netsnmp_feature_require(register_snmpEngine_scalars_context) #endif /* NETSNMP_FEATURE_CHECKING */ /* * initialize local modules */ if (agentx_subagent) { #ifdef USING_SNMPV3_SNMPENGINE_MODULE extern void register_snmpEngine_scalars_context(const char *); #endif subagent_init(); #ifdef USING_NOTIFICATION_LOG_MIB_NOTIFICATION_LOG_MODULE /* register the notification log table */ if (should_init("notificationLogMib")) { netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_NOTIF_LOG_CTX, "snmptrapd"); traph = netsnmp_add_global_traphandler(NETSNMPTRAPD_POST_HANDLER, notification_handler); traph->authtypes = TRAP_AUTH_LOG; init_notification_log(); } #endif #ifdef USING_SNMPV3_SNMPENGINE_MODULE /* * register scalars from SNMP-FRAMEWORK-MIB::snmpEngineID group; * allows engineID probes via the master agent under the * snmptrapd context */ register_snmpEngine_scalars_context("snmptrapd"); #endif } #endif /* USING_AGENTX_SUBAGENT_MODULE && !NETSNMP_SNMPTRAPD_DISABLE_AGENTX */ /* register our authorization handler */ init_netsnmp_trapd_auth(); #if defined(USING_AGENTX_SUBAGENT_MODULE) && !defined(NETSNMP_SNMPTRAPD_DISABLE_AGENTX) if (agentx_subagent) { #ifdef USING_AGENT_NSVACMACCESSTABLE_MODULE extern void init_register_nsVacm_context(const char *); #endif #ifdef USING_SNMPV3_USMUSER_MODULE #ifdef NETSNMP_FEATURE_CHECKING netsnmp_feature_require(init_register_usmUser_context) #endif /* NETSNMP_FEATURE_CHECKING */ extern void init_register_usmUser_context(const char *); /* register ourselves as having a USM user database */ init_register_usmUser_context("snmptrapd"); #endif #ifdef USING_AGENT_NSVACMACCESSTABLE_MODULE /* register net-snmp vacm extensions */ init_register_nsVacm_context("snmptrapd"); #endif #ifdef USING_TLSTM_MIB_SNMPTLSTMCERTTOTSNTABLE_MODULE init_snmpTlstmCertToTSNTable_context("snmptrapd"); #endif } #endif #ifdef NETSNMP_EMBEDDED_PERL init_perl(); { /* set the default path to load */ char init_file[SNMP_MAXBUF]; snprintf(init_file, sizeof(init_file) - 1, "%s/%s", SNMPSHAREPATH, "snmp_perl_trapd.pl"); netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_PERL_INIT_FILE, init_file); } #endif /* * Initialize the world. */ init_snmp("snmptrapd"); #ifdef SIGHUP signal(SIGHUP, hup_handler); #endif if (trap1_fmt_str_remember) { parse_format( NULL, trap1_fmt_str_remember ); } if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_QUIT_IMMEDIATELY)) { /* * just starting up to process specific configuration and then * shutting down immediately. */ netsnmp_running = 0; } /* * if no logging options on command line or in conf files, use syslog */ if (0 == snmp_get_do_logging()) { #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG #ifdef WIN32 snmp_enable_syslog_ident(app_name_long, Facility); #else snmp_enable_syslog_ident(app_name, Facility); #endif #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */ } if (listen_ports) cp = listen_ports; else cp = default_port; while (cp != NULL) { char *sep = strchr(cp, ','); if (sep != NULL) { *sep = 0; } transport = netsnmp_transport_open_server("snmptrap", cp); if (transport == NULL) { snmp_log(LOG_ERR, "couldn't open %s -- errno %d (\"%s\")\n", cp, errno, strerror(errno)); snmptrapd_close_sessions(sess_list); goto sock_cleanup; } else { ss = snmptrapd_add_session(transport); if (ss == NULL) { /* * Shouldn't happen? We have already opened the transport * successfully so what could have gone wrong? */ snmptrapd_close_sessions(sess_list); snmp_log(LOG_ERR, "couldn't open snmp - %s", strerror(errno)); goto sock_cleanup; } else { ss->next = sess_list; sess_list = ss; } } /* * Process next listen address, if there is one. */ if (sep != NULL) { *sep = ','; cp = sep + 1; } else { cp = NULL; } } SNMP_FREE(listen_ports); /* done with them */ #ifdef NETSNMP_USE_MYSQL if( netsnmp_mysql_init() ) { fprintf(stderr, "MySQL initialization failed\n"); goto sock_cleanup; } #endif #ifndef WIN32 /* * fork the process to the background if we are not printing to stderr */ if (dofork && netsnmp_running) { int fd; #if HAVE_FORKALL switch (forkall()) { #else switch (fork()) { #endif case -1: fprintf(stderr, "bad fork - %s\n", strerror(errno)); goto sock_cleanup; case 0: /* * become process group leader */ if (setsid() == -1) { fprintf(stderr, "bad setsid - %s\n", strerror(errno)); goto sock_cleanup; } /* * if we are forked, we don't want to print out to stdout or stderr */ fd = open("/dev/null", O_RDWR); if (fd >= 0) { dup2(fd, STDIN_FILENO); dup2(fd, STDOUT_FILENO); dup2(fd, STDERR_FILENO); close(fd); } break; default: _exit(0); } } #endif /* WIN32 */ #if HAVE_GETPID if (pid_file != NULL) { if ((PID = fopen(pid_file, "w")) == NULL) { snmp_log_perror("fopen"); goto sock_cleanup; } fprintf(PID, "%d\n", (int) getpid()); fclose(PID); free_config_pidFile(); } #endif snmp_log(LOG_INFO, "NET-SNMP version %s\n", netsnmp_get_version()); /* * ignore early sighup during startup */ reconfig = 0; #if HAVE_UNISTD_H #ifdef HAVE_SETGID if ((gid = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_GROUPID)) > 0) { DEBUGMSGTL(("snmptrapd/main", "Changing gid to %d.\n", gid)); if (setgid(gid) == -1 #ifdef HAVE_SETGROUPS || setgroups(1, (gid_t *)&gid) == -1 #endif ) { snmp_log_perror("setgid failed"); if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) { goto sock_cleanup; } } } #endif #ifdef HAVE_SETUID if ((uid = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_USERID)) != 0) { DEBUGMSGTL(("snmptrapd/main", "Changing uid to %d.\n", uid)); if (setuid(uid) == -1) { snmp_log_perror("setuid failed"); if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) { goto sock_cleanup; } } } #endif #endif /* * Let systemd know we're up. */ #ifndef NETSNMP_NO_SYSTEMD netsnmp_sd_notify(1, "READY=1\n"); if (prepared_sockets) /* * Clear the environment variable, we already processed all the sockets * by now. */ netsnmp_sd_listen_fds(1); #endif #ifdef WIN32SERVICE trapd_status = SNMPTRAPD_RUNNING; #endif snmptrapd_main_loop(); if (snmp_get_do_logging()) { struct tm *tm; time_t timer; time(&timer); tm = localtime(&timer); snmp_log(LOG_INFO, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d NET-SNMP version %s Stopped.\n", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, netsnmp_get_version()); } snmp_log(LOG_INFO, "Stopping snmptrapd\n"); #ifdef NETSNMP_EMBEDDED_PERL shutdown_perl(); #endif snmptrapd_close_sessions(sess_list); snmp_shutdown("snmptrapd"); #ifdef WIN32SERVICE trapd_status = SNMPTRAPD_STOPPED; #endif snmp_disable_log(); exit_code = 0; sock_cleanup: SOCK_CLEANUP; out: return exit_code; } /* * Read the configuration files. Implemented as a signal handler so that * receipt of SIGHUP will cause configuration to be re-read when the * trap daemon is running detatched from the console. * */ void trapd_update_config(void) { free_config(); #ifdef USING_MIBII_VACM_CONF_MODULE vacm_standard_views(0,0,NULL,NULL); #endif read_configs(); }
int main(int argc, char *argv[]) { char c; char log_severity[16] = ""; JavaVMInitArgs vm_args; JavaVMOption vm_opts[5]; int nopts = 0; const char *classpath; const char *libpath; size_t len; const char *err_desc; JNIEnv *env; jmethodID poold_getinstancewcl_mid; jmethodID poold_run_mid; jobject log_severity_string = NULL; jobject log_severity_obj = NULL; jclass severity_class; jmethodID severity_cons_mid; jfieldID base_log_fid; pthread_t hdl_thread; FILE *p; (void) pthread_mutex_lock(&jvm_lock); pname = pu_getpname(argv[0]); openlog(pname, 0, LOG_DAEMON); (void) chdir("/"); (void) setlocale(LC_ALL, ""); #if !defined(TEXT_DOMAIN) /* Should be defined with cc -D. */ #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it wasn't. */ #endif (void) textdomain(TEXT_DOMAIN); opterr = 0; while ((c = getopt(argc, argv, "l:P")) != EOF) { switch (c) { case 'l': /* -l option */ lflag++; (void) strlcpy(log_severity, optarg, sizeof (log_severity)); log_dest = LD_TERMINAL; break; default: usage(); /*NOTREACHED*/ } } /* * Check permission */ if (!priv_ineffect(PRIV_SYS_RES_CONFIG)) pu_die(gettext(ERR_PRIVILEGE), PRIV_SYS_RES_CONFIG); /* * In order to avoid problems with arbitrary thread selection * when handling asynchronous signals, dedicate a thread to * look after these signals. */ if (sigemptyset(&hdl_set) < 0 || sigaddset(&hdl_set, SIGHUP) < 0 || sigaddset(&hdl_set, SIGTERM) < 0 || sigaddset(&hdl_set, SIGINT) < 0 || pthread_sigmask(SIG_BLOCK, &hdl_set, NULL) || pthread_create(&hdl_thread, NULL, handle_sig, NULL)) pu_die(gettext("can't install signal handler")); /* * If the -l flag is supplied, terminate the SMF service and * run interactively from the command line. */ if (lflag) { char *cmd = "/usr/sbin/svcadm disable -st " SMF_SVC_INSTANCE; if (getenv("SMF_FMRI") != NULL) pu_die("-l option illegal: %s\n", SMF_SVC_INSTANCE); /* * Since disabling a service isn't synchronous, use the * synchronous option from svcadm to achieve synchronous * behaviour. * This is not very satisfactory, but since this is only * for use in debugging scenarios, it will do until there * is a C API to synchronously shutdown a service in SMF. */ if ((p = popen(cmd, "w")) == NULL || pclose(p) != 0) pu_die("could not temporarily disable service: %s\n", SMF_SVC_INSTANCE); } else { /* * Check if we are running as a SMF service. If we * aren't, terminate this process after enabling the * service. */ if (getenv("SMF_FMRI") == NULL) { char *cmd = "/usr/sbin/svcadm enable -s " \ SMF_SVC_INSTANCE; if ((p = popen(cmd, "w")) == NULL || pclose(p) != 0) pu_die("could not enable " "service: %s\n", SMF_SVC_INSTANCE); return (E_PO_SUCCESS); } } /* * Establish the classpath and LD_LIBRARY_PATH for native * methods, and get the interpreter going. */ if ((classpath = getenv("POOLD_CLASSPATH")) == NULL) { classpath = POOLD_DEF_CLASSPATH; } else { const char *cur = classpath; /* * Check the components to make sure they're absolute * paths. */ while (cur != NULL && *cur) { if (*cur != '/') pu_die(gettext( "POOLD_CLASSPATH must contain absolute " "components\n")); cur = strchr(cur + 1, ':'); } } vm_opts[nopts].optionString = malloc(len = strlen(classpath) + strlen("-Djava.class.path=") + 1); (void) strlcpy(vm_opts[nopts].optionString, "-Djava.class.path=", len); (void) strlcat(vm_opts[nopts++].optionString, classpath, len); if ((libpath = getenv("POOLD_LD_LIBRARY_PATH")) == NULL) libpath = POOLD_DEF_LIBPATH; vm_opts[nopts].optionString = malloc(len = strlen(libpath) + strlen("-Djava.library.path=") + 1); (void) strlcpy(vm_opts[nopts].optionString, "-Djava.library.path=", len); (void) strlcat(vm_opts[nopts++].optionString, libpath, len); vm_opts[nopts++].optionString = "-Xrs"; vm_opts[nopts++].optionString = "-enableassertions"; vm_args.options = vm_opts; vm_args.nOptions = nopts; vm_args.ignoreUnrecognized = JNI_FALSE; vm_args.version = 0x00010002; if (JNI_CreateJavaVM(&jvm, (void **)&env, &vm_args) < 0) pu_die(gettext("can't create Java VM")); /* * Locate the Poold class and construct an instance. A side * effect of this is that the poold instance's logHelper will be * initialized, establishing loggers for logging errors from * this point on. (Note, in the event of an unanticipated * exception, poold will invoke die() itself.) */ err_desc = gettext("JVM-related error initializing poold\n"); if ((poold_class = (*env)->FindClass(env, POOLD_CLASS_DESC)) == NULL) goto destroy; if ((poold_getinstancewcl_mid = (*env)->GetStaticMethodID(env, poold_class, "getInstanceWithConsoleLogging", "(" CLASS_FIELD_DESC(SEVERITY_CLASS_DESC) ")" CLASS_FIELD_DESC(POOLD_CLASS_DESC))) == NULL) goto destroy; if ((poold_run_mid = (*env)->GetMethodID(env, poold_class, "run", "()V")) == NULL) goto destroy; if ((severity_class = (*env)->FindClass(env, SEVERITY_CLASS_DESC)) == NULL) goto destroy; if ((severity_cons_mid = (*env)->GetStaticMethodID(env, severity_class, "getSeverityWithName", "(" CLASS_FIELD_DESC(STRING_CLASS_DESC) ")" CLASS_FIELD_DESC(SEVERITY_CLASS_DESC))) == NULL) goto destroy; /* * -l <level> was specified, indicating that messages are to be * logged to the console only. */ if (strlen(log_severity) > 0) { if ((log_severity_string = (*env)->NewStringUTF(env, log_severity)) == NULL) goto destroy; if ((log_severity_obj = (*env)->CallStaticObjectMethod(env, severity_class, severity_cons_mid, log_severity_string)) == NULL) { err_desc = gettext("invalid level specified\n"); goto destroy; } } else log_severity_obj = NULL; if ((poold_instance = (*env)->CallStaticObjectMethod(env, poold_class, poold_getinstancewcl_mid, log_severity_obj)) == NULL) goto destroy; /* * Grab a global reference to poold for use in our signal * handlers. */ poold_instance = (*env)->NewGlobalRef(env, poold_instance); /* * Ready LD_JAVA logging. */ err_desc = gettext("cannot initialize logging\n"); if ((log_severity_string = (*env)->NewStringUTF(env, "err")) == NULL) goto destroy; if (!(severity_err = (*env)->CallStaticObjectMethod(env, severity_class, severity_cons_mid, log_severity_string))) goto destroy; if (!(severity_err = (*env)->NewGlobalRef(env, severity_err))) goto destroy; if ((log_severity_string = (*env)->NewStringUTF(env, "notice")) == NULL) goto destroy; if (!(severity_notice = (*env)->CallStaticObjectMethod(env, severity_class, severity_cons_mid, log_severity_string))) goto destroy; if (!(severity_notice = (*env)->NewGlobalRef(env, severity_notice))) goto destroy; if (!(base_log_fid = (*env)->GetStaticFieldID(env, poold_class, "BASE_LOG", CLASS_FIELD_DESC(LOGGER_CLASS_DESC)))) goto destroy; if (!(base_log = (*env)->GetStaticObjectField(env, poold_class, base_log_fid))) goto destroy; if (!(base_log = (*env)->NewGlobalRef(env, base_log))) goto destroy; if (!(log_mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, base_log), "log", "(" CLASS_FIELD_DESC(LEVEL_CLASS_DESC) CLASS_FIELD_DESC(STRING_CLASS_DESC) ")V"))) goto destroy; log_dest = LD_JAVA; /* * If invoked directly and -l is specified, forking is not * desired. */ if (!lflag) switch (forkall()) { case 0: (void) setsid(); (void) fclose(stdin); (void) fclose(stdout); (void) fclose(stderr); break; case -1: pu_die(gettext("cannot fork")); /*NOTREACHED*/ default: return (E_PO_SUCCESS); } instance_running = 1; (void) pthread_mutex_unlock(&jvm_lock); (*env)->CallVoidMethod(env, poold_instance, poold_run_mid); (void) pthread_mutex_lock(&jvm_lock); if ((*env)->ExceptionOccurred(env)) { goto destroy; } if (jvm) { (*jvm)->DestroyJavaVM(jvm); jvm = NULL; } (void) pthread_mutex_unlock(&jvm_lock); return (E_PO_SUCCESS); destroy: if (lflag && (*env)->ExceptionOccurred(env)) (*env)->ExceptionDescribe(env); pu_die(err_desc); }
/** * fork current process into the background. * * This function forks a process into the background, in order to * become a daemon process. It does a few things along the way: * * - becoming a process/session group leader, and forking a second time so * that process/session group leader can exit. * * - changing the working directory to / * * - closing stdin, stdout and stderr (unless stderr_log is set) and * redirecting them to /dev/null * * @param quit_immediately : indicates if the parent process should * exit after a successful fork. * @param stderr_log : indicates if stderr is being used for * logging and shouldn't be closed * @returns -1 : fork error * 0 : child process returning * >0 : parent process returning. returned value is the child PID. */ int netsnmp_daemonize(int quit_immediately, int stderr_log) { int i = 0; DEBUGMSGT(("daemonize","deamonizing...\n")); #if HAVE_FORK #if defined(darwin9) char path [PATH_MAX] = ""; uint32_t size = sizeof (path); /* * if we are already launched in a "daemonized state", just * close & redirect the file descriptors */ if(getppid() <= 2) { _daemon_prep(stderr_log); return 0; } if (_NSGetExecutablePath (path, &size)) return -1; #endif /* * Fork to return control to the invoking process and to * guarantee that we aren't a process group leader. */ #if HAVE_FORKALL i = forkall(); #else i = fork(); #endif if (i != 0) { /* Parent. */ DEBUGMSGT(("daemonize","first fork returned %d.\n", i)); if(i == -1) { snmp_log(LOG_ERR,"first fork failed (errno %d) in " "netsnmp_daemonize()\n", errno); return -1; } if (quit_immediately) { DEBUGMSGT(("daemonize","parent exiting\n")); exit(0); } } else { /* Child. */ #ifdef HAVE_SETSID /* Become a process/session group leader. */ setsid(); #endif /* * Fork to let the process/session group leader exit. */ #if HAVE_FORKALL i = forkall(); #else i = fork(); #endif if (i != 0) { DEBUGMSGT(("daemonize","second fork returned %d.\n", i)); if(i == -1) { snmp_log(LOG_ERR,"second fork failed (errno %d) in " "netsnmp_daemonize()\n", errno); } /* Parent. */ exit(0); } #ifndef WIN32 else { /* Child. */ DEBUGMSGT(("daemonize","child continuing\n")); #if ! defined(darwin9) _daemon_prep(stderr_log); #else /* * Some darwin calls (using mach ports) don't work after * a fork. So, now that we've forked, we re-exec ourself * to ensure that the child's mach ports are all set up correctly, * the getppid call above will prevent the exec child from * forking... */ char * const *argv = *_NSGetArgv (); DEBUGMSGT(("daemonize","re-execing forked child\n")); execv (path, argv); snmp_log(LOG_ERR,"Forked child unable to re-exec - %s.\n", strerror (errno)); exit (0); #endif } #endif /* !WIN32 */ } #endif /* HAVE_FORK */ return i; }