示例#1
0
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);
}
示例#2
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();
}
示例#3
0
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);
}
示例#4
0
/**
 * 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;
}