コード例 #1
0
ファイル: main.c プロジェクト: Peoplecantfly/netdata
static void get_netdata_configured_variables() {
    backwards_compatible_config();

    // ------------------------------------------------------------------------
    // get the hostname

    char buf[HOSTNAME_MAX + 1];
    if(gethostname(buf, HOSTNAME_MAX) == -1)
        error("Cannot get machine hostname.");

    netdata_configured_hostname = config_get(CONFIG_SECTION_GLOBAL, "hostname", buf);
    debug(D_OPTIONS, "hostname set to '%s'", netdata_configured_hostname);

    // ------------------------------------------------------------------------
    // get default database size

    default_rrd_history_entries = (int) config_get_number(CONFIG_SECTION_GLOBAL, "history", align_entries_to_pagesize(default_rrd_memory_mode, RRD_DEFAULT_HISTORY_ENTRIES));

    long h = align_entries_to_pagesize(default_rrd_memory_mode, default_rrd_history_entries);
    if(h != default_rrd_history_entries) {
        config_set_number(CONFIG_SECTION_GLOBAL, "history", h);
        default_rrd_history_entries = (int)h;
    }

    if(default_rrd_history_entries < 5 || default_rrd_history_entries > RRD_HISTORY_ENTRIES_MAX) {
        error("Invalid history entries %d given. Defaulting to %d.", default_rrd_history_entries, RRD_DEFAULT_HISTORY_ENTRIES);
        default_rrd_history_entries = RRD_DEFAULT_HISTORY_ENTRIES;
    }

    // ------------------------------------------------------------------------
    // get default database update frequency

    default_rrd_update_every = (int) config_get_number(CONFIG_SECTION_GLOBAL, "update every", UPDATE_EVERY);
    if(default_rrd_update_every < 1 || default_rrd_update_every > 600) {
        error("Invalid data collection frequency (update every) %d given. Defaulting to %d.", default_rrd_update_every, UPDATE_EVERY_MAX);
        default_rrd_update_every = UPDATE_EVERY;
    }

    // ------------------------------------------------------------------------
    // get system paths

    netdata_configured_config_dir  = config_get(CONFIG_SECTION_GLOBAL, "config directory",    CONFIG_DIR);
    netdata_configured_log_dir     = config_get(CONFIG_SECTION_GLOBAL, "log directory",       LOG_DIR);
    netdata_configured_web_dir     = config_get(CONFIG_SECTION_GLOBAL, "web files directory", WEB_DIR);
    netdata_configured_cache_dir   = config_get(CONFIG_SECTION_GLOBAL, "cache directory",     CACHE_DIR);
    netdata_configured_varlib_dir  = config_get(CONFIG_SECTION_GLOBAL, "lib directory",       VARLIB_DIR);
    netdata_configured_home_dir    = config_get(CONFIG_SECTION_GLOBAL, "home directory",      CACHE_DIR);

    {
        char plugins_dirs[(FILENAME_MAX * 2) + 1];
        snprintfz(plugins_dirs, FILENAME_MAX * 2, "\"%s\" \"%s/custom-plugins.d\"", PLUGINS_DIR, CONFIG_DIR);
        netdata_configured_plugins_dir_base = strdupz(config_get(CONFIG_SECTION_GLOBAL, "plugins directory",  plugins_dirs));
        quoted_strings_splitter(netdata_configured_plugins_dir_base, plugin_directories, PLUGINSD_MAX_DIRECTORIES, config_isspace);
        netdata_configured_plugins_dir = plugin_directories[0];
    }

    // ------------------------------------------------------------------------
    // get default memory mode for the database

    default_rrd_memory_mode = rrd_memory_mode_id(config_get(CONFIG_SECTION_GLOBAL, "memory mode", rrd_memory_mode_name(default_rrd_memory_mode)));

    // ------------------------------------------------------------------------

    netdata_configured_host_prefix = config_get(CONFIG_SECTION_GLOBAL, "host access prefix", "");
    verify_netdata_host_prefix();

    // --------------------------------------------------------------------
    // get KSM settings

#ifdef MADV_MERGEABLE
    enable_ksm = config_get_boolean(CONFIG_SECTION_GLOBAL, "memory deduplication (ksm)", enable_ksm);
#endif

    // --------------------------------------------------------------------
    // get various system parameters

    get_system_HZ();
    get_system_cpus();
    get_system_pid_max();
}
コード例 #2
0
ファイル: main.c プロジェクト: bmaggard/netdata
int main(int argc, char **argv)
{
    char *hostname = "localhost";
    int i, check_config = 0;
    int config_loaded = 0;
    int dont_fork = 0;
    size_t wanted_stacksize = 0, stacksize = 0;
    pthread_attr_t attr;

    // set the name for logging
    program_name = "netdata";

    // parse depercated options
    // TODO: Remove this block with the next major release.
    {
        i = 1;
        while(i < argc) {
            if(strcmp(argv[i], "-pidfile") == 0 && (i+1) < argc) {
                strncpyz(pidfile, argv[i+1], FILENAME_MAX);
                fprintf(stderr, "%s: deprecated option -- %s -- please use -P instead.\n", argv[0], argv[i]);
                remove_option(i, &argc, argv);
            }
            else if(strcmp(argv[i], "-nodaemon") == 0 || strcmp(argv[i], "-nd") == 0) {
                dont_fork = 1;
                fprintf(stderr, "%s: deprecated option -- %s -- please use -D instead.\n ", argv[0], argv[i]);
                remove_option(i, &argc, argv);
            }
            else if(strcmp(argv[i], "-ch") == 0 && (i+1) < argc) {
                config_set("global", "host access prefix", argv[i+1]);
                fprintf(stderr, "%s: deprecated option -- %s -- please use -s instead.\n", argv[0], argv[i]);
                remove_option(i, &argc, argv);
            }
            else if(strcmp(argv[i], "-l") == 0 && (i+1) < argc) {
                config_set("global", "history", argv[i+1]);
                fprintf(stderr, "%s: deprecated option -- %s -- This option will be removed with V2.*.\n", argv[0], argv[i]);
                remove_option(i, &argc, argv);
            }
            else i++;
        }
    }

    // parse options
    {
        int num_opts = sizeof(options) / sizeof(struct option_def);
        char optstring[(num_opts * 2) + 1];

        int string_i = 0;
        for( i = 0; i < num_opts; i++ ) {
            optstring[string_i] = options[i].val;
            string_i++;
            if(options[i].arg_name) {
                optstring[string_i] = ':';
                string_i++;
            }
        }

        int opt;
        while( (opt = getopt(argc, argv, optstring)) != -1 ) {
            switch(opt) {
                case 'c':
                    if(load_config(optarg, 1) != 1) {
                        error("Cannot load configuration file %s.", optarg);
                        exit(1);
                    }
                    else {
                        debug(D_OPTIONS, "Configuration loaded from %s.", optarg);
                        config_loaded = 1;
                    }
                    break;
                case 'D':
                    dont_fork = 1;
                    break;
                case 'h':
                    help(0);
                    break;
                case 'i':
                    config_set("global", "bind to", optarg);
                    break;
                case 'k':
                    dont_fork = 1;
                    check_config = 1;
                    break;
                case 'P':
                    strncpy(pidfile, optarg, FILENAME_MAX);
                    pidfile[FILENAME_MAX] = '\0';
                    break;
                case 'p':
                    config_set("global", "default port", optarg);
                    break;
                case 's':
                    config_set("global", "host access prefix", optarg);
                    break;
                case 't':
                    config_set("global", "update every", optarg);
                    break;
                case 'u':
                    config_set("global", "run as user", optarg);
                    break;
                case 'v':
                    // TODO: Outsource version to makefile which can compute version from git.
                    printf("netdata %s\n", VERSION);
                    return 0;
                case 'W':
                    {
                        char* stacksize_string = "stacksize=";
                        char* debug_flags_string = "debug_flags=";
                        if(strcmp(optarg, "unittest") == 0) {
                            rrd_update_every = 1;
                            if(run_all_mockup_tests()) exit(1);
                            if(unit_test_storage()) exit(1);
                            fprintf(stderr, "\n\nALL TESTS PASSED\n\n");
                            exit(0);
                        } else if(strncmp(optarg, stacksize_string, strlen(stacksize_string)) == 0) {
                            optarg += strlen(stacksize_string);
                            config_set("global", "pthread stack size", optarg);
                        } else if(strncmp(optarg, debug_flags_string, strlen(debug_flags_string)) == 0) {
                            optarg += strlen(debug_flags_string);
                            config_set("global", "debug flags",  optarg);
                            debug_flags = strtoull(optarg, NULL, 0);
                        }
                    }
                    break;
                default: /* ? */
                    help(1);
                    break;
            }
        }
    }

    if(!config_loaded)
        load_config(NULL, 0);

    {
        char *pmax = config_get("global", "glibc malloc arena max for plugins", "1");
        if(pmax && *pmax)
            setenv("MALLOC_ARENA_MAX", pmax, 1);

#if defined(HAVE_C_MALLOPT)
        int i = config_get_number("global", "glibc malloc arena max for netdata", 1);
        if(i > 0)
            mallopt(M_ARENA_MAX, 1);
#endif

        char *config_dir = config_get("global", "config directory", CONFIG_DIR);

        // prepare configuration environment variables for the plugins
        setenv("NETDATA_CONFIG_DIR" , verify_required_directory(config_dir) , 1);
        setenv("NETDATA_PLUGINS_DIR", verify_required_directory(config_get("global", "plugins directory"  , PLUGINS_DIR)), 1);
        setenv("NETDATA_WEB_DIR"    , verify_required_directory(config_get("global", "web files directory", WEB_DIR))    , 1);
        setenv("NETDATA_CACHE_DIR"  , verify_required_directory(config_get("global", "cache directory"    , CACHE_DIR))  , 1);
        setenv("NETDATA_LIB_DIR"    , verify_required_directory(config_get("global", "lib directory"      , VARLIB_DIR)) , 1);
        setenv("NETDATA_LOG_DIR"    , verify_required_directory(config_get("global", "log directory"      , LOG_DIR))    , 1);

        setenv("NETDATA_HOST_PREFIX", config_get("global", "host access prefix" , "")         , 1);
        setenv("HOME"               , config_get("global", "home directory"     , CACHE_DIR)  , 1);

        // disable buffering for python plugins
        setenv("PYTHONUNBUFFERED", "1", 1);

        // avoid flood calls to stat(/etc/localtime)
        // http://stackoverflow.com/questions/4554271/how-to-avoid-excessive-stat-etc-localtime-calls-in-strftime-on-linux
        setenv("TZ", ":/etc/localtime", 0);

        // work while we are cd into config_dir
        // to allow the plugins refer to their config
        // files using relative filenames
        if(chdir(config_dir) == -1)
            fatal("Cannot cd to '%s'", config_dir);

        char path[1024 + 1], *p = getenv("PATH");
        if(!p) p = "/bin:/usr/bin";
        snprintfz(path, 1024, "%s:%s", p, "/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin");
        setenv("PATH", config_get("plugins", "PATH environment variable", path), 1);
    }

    char *user = NULL;
    {
        char *flags = config_get("global", "debug flags",  "0x00000000");
        setenv("NETDATA_DEBUG_FLAGS", flags, 1);

        debug_flags = strtoull(flags, NULL, 0);
        debug(D_OPTIONS, "Debug flags set to '0x%8llx'.", debug_flags);

        if(debug_flags != 0) {
            struct rlimit rl = { RLIM_INFINITY, RLIM_INFINITY };
            if(setrlimit(RLIMIT_CORE, &rl) != 0)
                error("Cannot request unlimited core dumps for debugging... Proceeding anyway...");

#ifndef __FreeBSD__
            prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
#endif /* __FreeBSD__ */
        }

        // --------------------------------------------------------------------

#ifdef MADV_MERGEABLE
        enable_ksm = config_get_boolean("global", "memory deduplication (ksm)", enable_ksm);
#else
#warning "Kernel memory deduplication (KSM) is not available"
#endif

        // --------------------------------------------------------------------

        global_host_prefix = config_get("global", "host access prefix", "");
        setenv("NETDATA_HOST_PREFIX", global_host_prefix, 1);

        get_system_HZ();
        get_system_cpus();
        get_system_pid_max();
        
        // --------------------------------------------------------------------

        stdout_filename    = config_get("global", "debug log",  LOG_DIR "/debug.log");
        stderr_filename    = config_get("global", "error log",  LOG_DIR "/error.log");
        stdaccess_filename = config_get("global", "access log", LOG_DIR "/access.log");

        error_log_throttle_period_backup =
            error_log_throttle_period = config_get_number("global", "errors flood protection period", error_log_throttle_period);
        setenv("NETDATA_ERRORS_THROTTLE_PERIOD", config_get("global", "errors flood protection period"    , ""), 1);

        error_log_errors_per_period = (unsigned long)config_get_number("global", "errors to trigger flood protection", error_log_errors_per_period);
        setenv("NETDATA_ERRORS_PER_PERIOD"     , config_get("global", "errors to trigger flood protection", ""), 1);

        if(check_config) {
            stdout_filename = stderr_filename = stdaccess_filename = "system";
            error_log_throttle_period = 0;
            error_log_errors_per_period = 0;
        }
        error_log_limit_unlimited();

        // --------------------------------------------------------------------

        rrd_memory_mode = rrd_memory_mode_id(config_get("global", "memory mode", rrd_memory_mode_name(rrd_memory_mode)));

        // --------------------------------------------------------------------

        {
            char hostnamebuf[HOSTNAME_MAX + 1];
            if(gethostname(hostnamebuf, HOSTNAME_MAX) == -1)
                error("WARNING: Cannot get machine hostname.");
            hostname = config_get("global", "hostname", hostnamebuf);
            debug(D_OPTIONS, "hostname set to '%s'", hostname);
            setenv("NETDATA_HOSTNAME", hostname, 1);
        }

        // --------------------------------------------------------------------

        rrd_default_history_entries = (int) config_get_number("global", "history", RRD_DEFAULT_HISTORY_ENTRIES);
        if(rrd_default_history_entries < 5 || rrd_default_history_entries > RRD_HISTORY_ENTRIES_MAX) {
            error("Invalid history entries %d given. Defaulting to %d.", rrd_default_history_entries, RRD_DEFAULT_HISTORY_ENTRIES);
            rrd_default_history_entries = RRD_DEFAULT_HISTORY_ENTRIES;
        }
        else {
            debug(D_OPTIONS, "save lines set to %d.", rrd_default_history_entries);
        }

        // --------------------------------------------------------------------

        rrd_update_every = (int) config_get_number("global", "update every", UPDATE_EVERY);
        if(rrd_update_every < 1 || rrd_update_every > 600) {
            error("Invalid data collection frequency (update every) %d given. Defaulting to %d.", rrd_update_every, UPDATE_EVERY_MAX);
            rrd_update_every = UPDATE_EVERY;
        }
        else debug(D_OPTIONS, "update timer set to %d.", rrd_update_every);

        // let the plugins know the min update_every
        {
            char buf[16];
            snprintfz(buf, 15, "%d", rrd_update_every);
            setenv("NETDATA_UPDATE_EVERY", buf, 1);
        }

        // --------------------------------------------------------------------

        // block signals while initializing threads.
        // this causes the threads to block signals.
        sigset_t sigset;
        sigfillset(&sigset);
        if(pthread_sigmask(SIG_BLOCK, &sigset, NULL) == -1)
            error("Could not block signals for threads");

        // Catch signals which we want to use
        struct sigaction sa;
        sa.sa_flags = 0;

        // ingore all signals while we run in a signal handler
        sigfillset(&sa.sa_mask);

        // INFO: If we add signals here we have to unblock them
        // at popen.c when running a external plugin.

        // Ignore SIGPIPE completely.
        sa.sa_handler = SIG_IGN;
        if(sigaction(SIGPIPE, &sa, NULL) == -1)
            error("Failed to change signal handler for SIGPIPE");

        sa.sa_handler = sig_handler_exit;
        if(sigaction(SIGINT, &sa, NULL) == -1)
            error("Failed to change signal handler for SIGINT");

        sa.sa_handler = sig_handler_exit;
        if(sigaction(SIGTERM, &sa, NULL) == -1)
            error("Failed to change signal handler for SIGTERM");

        sa.sa_handler = sig_handler_logrotate;
        if(sigaction(SIGHUP, &sa, NULL) == -1)
            error("Failed to change signal handler for SIGHUP");

        // save database on SIGUSR1
        sa.sa_handler = sig_handler_save;
        if(sigaction(SIGUSR1, &sa, NULL) == -1)
            error("Failed to change signal handler for SIGUSR1");

        // reload health configuration on SIGUSR2
        sa.sa_handler = sig_handler_reload_health;
        if(sigaction(SIGUSR2, &sa, NULL) == -1)
            error("Failed to change signal handler for SIGUSR2");

        // --------------------------------------------------------------------

        i = pthread_attr_init(&attr);
        if(i != 0)
            fatal("pthread_attr_init() failed with code %d.", i);

        i = pthread_attr_getstacksize(&attr, &stacksize);
        if(i != 0)
            fatal("pthread_attr_getstacksize() failed with code %d.", i);
        else
            debug(D_OPTIONS, "initial pthread stack size is %zu bytes", stacksize);

        wanted_stacksize = (size_t)config_get_number("global", "pthread stack size", (long)stacksize);

        // --------------------------------------------------------------------

        for (i = 0; static_threads[i].name != NULL ; i++) {
            struct netdata_static_thread *st = &static_threads[i];

            if(st->config_name) st->enabled = config_get_boolean(st->config_section, st->config_name, st->enabled);
            if(st->enabled && st->init_routine) st->init_routine();
        }

        // --------------------------------------------------------------------

        // get the user we should run
        // IMPORTANT: this is required before web_files_uid()
        user = config_get("global", "run as user"    , (getuid() == 0)?NETDATA_USER:"");

        // IMPORTANT: these have to run once, while single threaded
        web_files_uid(); // IMPORTANT: web_files_uid() before web_files_gid()
        web_files_gid();

        // --------------------------------------------------------------------

        if(!check_config)
            create_listen_sockets();
    }

    // initialize the log files
    open_all_log_files();

#ifdef NETDATA_INTERNAL_CHECKS
    if(debug_flags != 0) {
        struct rlimit rl = { RLIM_INFINITY, RLIM_INFINITY };
        if(setrlimit(RLIMIT_CORE, &rl) != 0)
            error("Cannot request unlimited core dumps for debugging... Proceeding anyway...");
#ifndef __FreeBSD__
        prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
#endif /* __FreeBSD__ */
    }
#endif /* NETDATA_INTERNAL_CHECKS */

    // fork, switch user, create pid file, set process priority
    if(become_daemon(dont_fork, user) == -1)
        fatal("Cannot daemonize myself.");

    info("NetData started on pid %d", getpid());


    // ------------------------------------------------------------------------
    // get default pthread stack size

    if(stacksize < wanted_stacksize) {
        i = pthread_attr_setstacksize(&attr, wanted_stacksize);
        if(i != 0)
            fatal("pthread_attr_setstacksize() to %zu bytes, failed with code %d.", wanted_stacksize, i);
        else
            debug(D_SYSTEM, "Successfully set pthread stacksize to %zu bytes", wanted_stacksize);
    }

    // ------------------------------------------------------------------------
    // initialize rrd host

    rrdhost_init(hostname);

    // ------------------------------------------------------------------------
    // initialize the registry

    registry_init();

    // ------------------------------------------------------------------------
    // initialize health monitoring

    health_init();

    if(check_config)
        exit(1);

    // ------------------------------------------------------------------------
    // enable log flood protection

    error_log_limit_reset();

    // ------------------------------------------------------------------------
    // spawn the threads

    web_server_threading_selection();

    for (i = 0; static_threads[i].name != NULL ; i++) {
        struct netdata_static_thread *st = &static_threads[i];

        if(st->enabled) {
            st->thread = mallocz(sizeof(pthread_t));

            debug(D_SYSTEM, "Starting thread %s.", st->name);

            if(pthread_create(st->thread, &attr, st->start_routine, NULL))
                error("failed to create new thread for %s.", st->name);

            else if(pthread_detach(*st->thread))
                error("Cannot request detach of newly created %s thread.", st->name);
        }
        else debug(D_SYSTEM, "Not starting thread %s.", st->name);
    }

    // ------------------------------------------------------------------------
    // block signals while initializing threads.
    sigset_t sigset;
    sigfillset(&sigset);

    if(pthread_sigmask(SIG_UNBLOCK, &sigset, NULL) == -1) {
        error("Could not unblock signals for threads");
    }

    // Handle flags set in the signal handler.
    while(1) {
        pause();
        if(netdata_exit) {
            debug(D_EXIT, "Exit main loop of netdata.");
            netdata_cleanup_and_exit(0);
            exit(0);
        }
    }
}