diff options
Diffstat (limited to 'daemon/main.c')
-rw-r--r-- | daemon/main.c | 326 |
1 files changed, 276 insertions, 50 deletions
diff --git a/daemon/main.c b/daemon/main.c index de7a4370..7c002ac4 100644 --- a/daemon/main.c +++ b/daemon/main.c @@ -1,12 +1,14 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "common.h" +#include "buildinfo.h" int netdata_zero_metrics_enabled; int netdata_anonymous_statistics_enabled; struct config netdata_config = { - .sections = NULL, + .first_section = NULL, + .last_section = NULL, .mutex = NETDATA_MUTEX_INITIALIZER, .index = { .avl_tree = { @@ -35,12 +37,18 @@ void netdata_cleanup_and_exit(int ret) { // exit cleanly // stop everything - info("EXIT: stopping master threads..."); + info("EXIT: stopping static threads..."); cancel_main_threads(); // free the database info("EXIT: freeing database memory..."); +#ifdef ENABLE_DBENGINE + rrdeng_prepare_exit(&multidb_ctx); +#endif rrdhost_free_all(); +#ifdef ENABLE_DBENGINE + rrdeng_exit(&multidb_ctx); +#endif } // unlink the pid @@ -53,7 +61,6 @@ void netdata_cleanup_and_exit(int ret) { #ifdef ENABLE_HTTPS security_clean_openssl(); #endif - info("EXIT: all done - netdata is now exiting - bye bye..."); exit(ret); } @@ -73,8 +80,13 @@ struct netdata_static_thread static_threads[] = { NETDATA_PLUGIN_HOOK_IDLEJITTER NETDATA_PLUGIN_HOOK_STATSD +#ifdef ENABLE_ACLK + NETDATA_ACLK_HOOK +#endif + // common plugins for all systems {"BACKENDS", NULL, NULL, 1, NULL, NULL, backends_main}, + {"EXPORTING", NULL, NULL, 1, NULL, NULL, exporting_main}, {"WEB_SERVER[static1]", NULL, NULL, 0, NULL, NULL, socket_listen_main_static_threaded}, {"STREAM", NULL, NULL, 0, NULL, NULL, rrdpush_sender_thread}, @@ -106,6 +118,7 @@ int make_dns_decision(const char *section_name, const char *config_name, const c if(strcmp("heuristic",value)) error("Invalid configuration option '%s' for '%s'/'%s'. Valid options are 'yes', 'no' and 'heuristic'. Proceeding with 'heuristic'", value, section_name, config_name); + return simple_pattern_is_potential_name(p); } @@ -151,9 +164,9 @@ void web_server_config_options(void) "localhost fd* 10.* 192.168.* 172.16.* 172.17.* 172.18.*" " 172.19.* 172.20.* 172.21.* 172.22.* 172.23.* 172.24.*" " 172.25.* 172.26.* 172.27.* 172.28.* 172.29.* 172.30.*" - " 172.31.*"), NULL, SIMPLE_PATTERN_EXACT); + " 172.31.* UNKNOWN"), NULL, SIMPLE_PATTERN_EXACT); web_allow_netdataconf_dns = - make_dns_decision(CONFIG_SECTION_WEB, "allow netdata.conf by dns", "no", web_allow_mgmt_from); + make_dns_decision(CONFIG_SECTION_WEB, "allow netdata.conf by dns", "no", web_allow_netdataconf_from); web_allow_mgmt_from = simple_pattern_create(config_get(CONFIG_SECTION_WEB, "allow management from", "localhost"), NULL, SIMPLE_PATTERN_EXACT); @@ -226,7 +239,7 @@ void cancel_main_threads() { usec_t max = 5 * USEC_PER_SEC, step = 100000; for (i = 0; static_threads[i].name != NULL ; i++) { if(static_threads[i].enabled == NETDATA_MAIN_THREAD_RUNNING) { - info("EXIT: Stopping master thread: %s", static_threads[i].name); + info("EXIT: Stopping main thread: %s", static_threads[i].name); netdata_thread_cancel(*static_threads[i].thread); found++; } @@ -248,7 +261,7 @@ void cancel_main_threads() { if(found) { for (i = 0; static_threads[i].name != NULL ; i++) { if (static_threads[i].enabled != NETDATA_MAIN_THREAD_EXITED) - error("Master thread %s takes too long to exit. Giving up...", static_threads[i].name); + error("Main thread %s takes too long to exit. Giving up...", static_threads[i].name); } } else @@ -300,13 +313,13 @@ int help(int exitcode) { " | '-' '-' '-' '-' real-time performance monitoring, done right! \n" " +----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+--->\n" "\n" - " Copyright (C) 2016-2017, Costa Tsaousis <costa@tsaousis.gr>\n" + " Copyright (C) 2016-2020, Netdata, Inc. <info@netdata.cloud>\n" " Released under GNU General Public License v3 or later.\n" " All rights reserved.\n" "\n" - " Home Page : https://my-netdata.io\n" + " Home Page : https://netdata.cloud\n" " Source Code: https://github.com/netdata/netdata\n" - " Wiki / Docs: https://github.com/netdata/netdata/wiki\n" + " Docs : https://learn.netdata.cloud\n" " Support : https://github.com/netdata/netdata/issues\n" " License : https://github.com/netdata/netdata/blob/master/LICENSE.md\n" "\n" @@ -337,15 +350,19 @@ int help(int exitcode) { " -W unittest Run internal unittests and exit.\n\n" #ifdef ENABLE_DBENGINE " -W createdataset=N Create a DB engine dataset of N seconds and exit.\n\n" - " -W stresstest=A,B,C,D,E Run a DB engine stress test for A seconds,\n" + " -W stresstest=A,B,C,D,E,F\n" + " Run a DB engine stress test for A seconds,\n" " with B writers and C readers, with a ramp up\n" " time of D seconds for writers, a page cache\n" - " size of E MiB, and exit.\n\n" + " size of E MiB, an optional disk space limit" + " of F MiB and exit.\n\n" #endif " -W set section option value\n" " set netdata.conf option from the command line.\n\n" " -W simple-pattern pattern string\n" " Check if string matches pattern and exit.\n\n" + " -W \"claim -token=TOKEN -rooms=ROOM1,ROOM2\"\n" + " Claim the agent to the workspace rooms pointed to by TOKEN and ROOM*.\n\n" ); fprintf(stream, "\n Signals netdata handles:\n\n" @@ -394,6 +411,9 @@ static void security_init(){ snprintfz(filename, FILENAME_MAX, "%s/ssl/cert.pem",netdata_configured_user_config_dir); security_cert = config_get(CONFIG_SECTION_WEB, "ssl certificate", filename); + tls_version = config_get(CONFIG_SECTION_WEB, "tls version", "1.3"); + tls_ciphers = config_get(CONFIG_SECTION_WEB, "tls ciphers", "none"); + security_openssl_library(); } #endif @@ -421,6 +441,14 @@ static void log_init(void) { setenv("NETDATA_ERRORS_PER_PERIOD", config_get(CONFIG_SECTION_GLOBAL, "errors to trigger flood protection", ""), 1); } +char *initialize_lock_directory_path(char *prefix) +{ + char filename[FILENAME_MAX + 1]; + snprintfz(filename, FILENAME_MAX, "%s/lock", prefix); + + return config_get(CONFIG_SECTION_GLOBAL, "lock directory", filename); +} + static void backwards_compatible_config() { // move [global] options to the [web] section config_move(CONFIG_SECTION_GLOBAL, "http port listen backlog", @@ -514,7 +542,10 @@ static void get_netdata_configured_variables() { netdata_configured_web_dir = config_get(CONFIG_SECTION_GLOBAL, "web files directory", netdata_configured_web_dir); netdata_configured_cache_dir = config_get(CONFIG_SECTION_GLOBAL, "cache directory", netdata_configured_cache_dir); netdata_configured_varlib_dir = config_get(CONFIG_SECTION_GLOBAL, "lib directory", netdata_configured_varlib_dir); - netdata_configured_home_dir = config_get(CONFIG_SECTION_GLOBAL, "home directory", netdata_configured_home_dir); + char *env_home=getenv("HOME"); + netdata_configured_home_dir = config_get(CONFIG_SECTION_GLOBAL, "home directory", env_home?env_home:netdata_configured_home_dir); + + netdata_configured_lock_dir = initialize_lock_directory_path(netdata_configured_varlib_dir); { pluginsd_initialize_plugin_directories(); @@ -544,6 +575,13 @@ static void get_netdata_configured_variables() { error("Invalid dbengine disk space %d given. Defaulting to %d.", default_rrdeng_disk_quota_mb, RRDENG_MIN_DISK_SPACE_MB); default_rrdeng_disk_quota_mb = RRDENG_MIN_DISK_SPACE_MB; } + + default_multidb_disk_quota_mb = (int) config_get_number(CONFIG_SECTION_GLOBAL, "dbengine multihost disk space", compute_multidb_diskspace()); + if(default_multidb_disk_quota_mb < RRDENG_MIN_DISK_SPACE_MB) { + error("Invalid multidb disk space %d given. Defaulting to %d.", default_multidb_disk_quota_mb, default_rrdeng_disk_quota_mb); + default_multidb_disk_quota_mb = default_rrdeng_disk_quota_mb; + } + #endif // ------------------------------------------------------------------------ @@ -563,6 +601,8 @@ static void get_netdata_configured_variables() { get_system_HZ(); get_system_cpus(); get_system_pid_max(); + + } static void get_system_timezone(void) { @@ -670,10 +710,22 @@ void set_global_environment() { setenv("NETDATA_WEB_DIR" , verify_required_directory(netdata_configured_web_dir), 1); setenv("NETDATA_CACHE_DIR" , verify_required_directory(netdata_configured_cache_dir), 1); setenv("NETDATA_LIB_DIR" , verify_required_directory(netdata_configured_varlib_dir), 1); + setenv("NETDATA_LOCK_DIR" , netdata_configured_lock_dir, 1); setenv("NETDATA_LOG_DIR" , verify_required_directory(netdata_configured_log_dir), 1); setenv("HOME" , verify_required_directory(netdata_configured_home_dir), 1); setenv("NETDATA_HOST_PREFIX" , netdata_configured_host_prefix, 1); + char *default_port = appconfig_get(&netdata_config, CONFIG_SECTION_WEB, "default port", NULL); + int clean = 0; + if (!default_port) { + default_port = strdupz("19999"); + clean = 1; + } + + setenv("NETDATA_LISTEN_PORT" , default_port, 1); + if(clean) + freez(default_port); + get_system_timezone(); // set the path we need @@ -700,20 +752,20 @@ static int load_netdata_conf(char *filename, char overwrite_used) { int ret = 0; if(filename && *filename) { - ret = config_load(filename, overwrite_used); + ret = config_load(filename, overwrite_used, NULL); if(!ret) error("CONFIG: cannot load config file '%s'.", filename); } else { filename = strdupz_path_subpath(netdata_configured_user_config_dir, "netdata.conf"); - ret = config_load(filename, overwrite_used); + ret = config_load(filename, overwrite_used, NULL); if(!ret) { info("CONFIG: cannot load user config '%s'. Will try the stock version.", filename); freez(filename); filename = strdupz_path_subpath(netdata_configured_stock_config_dir, "netdata.conf"); - ret = config_load(filename, overwrite_used); + ret = config_load(filename, overwrite_used, NULL); if(!ret) info("CONFIG: cannot load stock config '%s'. Running with internal defaults.", filename); } @@ -724,6 +776,12 @@ static int load_netdata_conf(char *filename, char overwrite_used) { return ret; } +// coverity[ +tainted_string_sanitize_content : arg-0 ] +static inline void coverity_remove_taint(char *s) +{ + (void)s; +} + int get_system_info(struct rrdhost_system_info *system_info) { char *script; script = mallocz(sizeof(char) * (strlen(netdata_configured_primary_plugins_dir) + strlen("system-info.sh") + 2)); @@ -740,27 +798,27 @@ int get_system_info(struct rrdhost_system_info *system_info) { FILE *fp = mypopen(script, &command_pid); if(fp) { - char buffer[200 + 1]; - while (fgets(buffer, 200, fp) != NULL) { - char *name=buffer; - char *value=buffer; + char line[200 + 1]; + // Removed the double strlens, if the Coverity tainted string warning reappears I'll revert. + // One time init code, but I'm curious about the warning... + while (fgets(line, 200, fp) != NULL) { + char *value=line; while (*value && *value != '=') value++; if (*value=='=') { *value='\0'; value++; - if (strlen(value)>1) { - char *newline = value + strlen(value) - 1; - (*newline) = '\0'; - } - char n[51], v[101]; - snprintfz(n, 50,"%s",name); - snprintfz(v, 100,"%s",value); - if(unlikely(rrdhost_set_system_info_variable(system_info, n, v))) { - info("Unexpected environment variable %s=%s", n, v); + char *end = value; + while (*end && *end != '\n') end++; + *end = '\0'; // Overwrite newline if present + coverity_remove_taint(line); // I/O is controlled result of system_info.sh - not tainted + coverity_remove_taint(value); + + if(unlikely(rrdhost_set_system_info_variable(system_info, line, value))) { + info("Unexpected environment variable %s=%s", line, value); } else { - info("%s=%s", n, v); - setenv(n, v, 1); + info("%s=%s", line, value); + setenv(line, value, 1); } } } @@ -772,6 +830,7 @@ int get_system_info(struct rrdhost_system_info *system_info) { void send_statistics( const char *action, const char *action_result, const char *action_data) { static char *as_script; + if (netdata_anonymous_statistics_enabled == -1) { char *optout_file = mallocz(sizeof(char) * (strlen(netdata_configured_user_config_dir) +strlen(".opt-out-from-anonymous-statistics") + 2)); sprintf(optout_file, "%s/%s", netdata_configured_user_config_dir, ".opt-out-from-anonymous-statistics"); @@ -816,11 +875,41 @@ void set_silencers_filename() { silencers_filename = config_get(CONFIG_SECTION_HEALTH, "silencers file", filename); } +/* Any config setting that can be accessed without a default value i.e. configget(...,...,NULL) *MUST* + be set in this procedure to be called in all the relevant code paths. +*/ +void post_conf_load(char **user) +{ + // -------------------------------------------------------------------- + // get the user we should run + + // IMPORTANT: this is required before web_files_uid() + if(getuid() == 0) { + *user = config_get(CONFIG_SECTION_GLOBAL, "run as user", NETDATA_USER); + } + else { + struct passwd *passwd = getpwuid(getuid()); + *user = config_get(CONFIG_SECTION_GLOBAL, "run as user", (passwd && passwd->pw_name)?passwd->pw_name:""); + } + + // -------------------------------------------------------------------- + // Check if the cloud is enabled +#if defined( DISABLE_CLOUD ) || !defined( ENABLE_ACLK ) + netdata_cloud_setting = 0; +#else + netdata_cloud_setting = appconfig_get_boolean(&cloud_config, CONFIG_SECTION_GLOBAL, "enabled", 1); +#endif + // This must be set before any point in the code that accesses it. Do not move it from this function. + appconfig_get(&cloud_config, CONFIG_SECTION_GLOBAL, "cloud base url", DEFAULT_CLOUD_BASE_URL); +} + int main(int argc, char **argv) { int i; int config_loaded = 0; int dont_fork = 0; size_t default_stacksize; + char *user = NULL; + netdata_ready=0; // set the name for logging @@ -854,6 +943,11 @@ int main(int argc, char **argv) { else i++; } } + if (argc > 1 && strcmp(argv[1], SPAWN_SERVER_COMMAND_LINE_ARGUMENT) == 0) { + // don't run netdata, this is the spawn server + spawn_server(); + exit(0); + } // parse options { @@ -883,6 +977,8 @@ int main(int argc, char **argv) { } else { debug(D_OPTIONS, "Configuration loaded from %s.", optarg); + post_conf_load(&user); + load_cloud_conf(1); config_loaded = 1; } break; @@ -921,6 +1017,7 @@ int main(int argc, char **argv) { { char* stacksize_string = "stacksize="; char* debug_flags_string = "debug_flags="; + char* claim_string = "claim"; #ifdef ENABLE_DBENGINE char* createdataset_string = "createdataset="; char* stresstest_string = "stresstest="; @@ -929,11 +1026,17 @@ int main(int argc, char **argv) { if(strcmp(optarg, "unittest") == 0) { if(unit_test_buffer()) return 1; if(unit_test_str2ld()) return 1; + // No call to load the config file on this code-path + post_conf_load(&user); get_netdata_configured_variables(); default_rrd_update_every = 1; default_rrd_memory_mode = RRD_MEMORY_MODE_RAM; default_health_enabled = 0; - rrd_init("unittest", NULL); + registry_init(); + if(rrd_init("unittest", NULL)) { + fprintf(stderr, "rrd_init failed for unittest\n"); + return 1; + } default_rrdpush_enabled = 0; if(run_all_mockup_tests()) return 1; if(unit_test_storage()) return 1; @@ -953,7 +1056,7 @@ int main(int argc, char **argv) { else if(strncmp(optarg, stresstest_string, strlen(stresstest_string)) == 0) { char *endptr; unsigned test_duration_sec = 0, dset_charts = 0, query_threads = 0, ramp_up_seconds = 0, - page_cache_mb = 0; + page_cache_mb = 0, disk_space_mb = 0; optarg += strlen(stresstest_string); test_duration_sec = (unsigned)strtoul(optarg, &endptr, 0); @@ -965,8 +1068,11 @@ int main(int argc, char **argv) { ramp_up_seconds = (unsigned)strtoul(endptr + 1, &endptr, 0); if (',' == *endptr) page_cache_mb = (unsigned)strtoul(endptr + 1, &endptr, 0); + if (',' == *endptr) + disk_space_mb = (unsigned)strtoul(endptr + 1, &endptr, 0); + dbengine_stress_test(test_duration_sec, dset_charts, query_threads, ramp_up_seconds, - page_cache_mb); + page_cache_mb, disk_space_mb); return 0; } #endif @@ -1052,6 +1158,39 @@ int main(int argc, char **argv) { // fprintf(stderr, "SET section '%s', key '%s', value '%s'\n", section, key, value); } + else if(strcmp(optarg, "set2") == 0) { + if(optind + 4 > argc) { + fprintf(stderr, "%s", "\nUSAGE: -W set 'conf_file' 'section' 'key' 'value'\n\n" + " Overwrites settings of netdata.conf or cloud.conf\n" + "\n" + " These options interact with: -c netdata.conf\n" + " If -c netdata.conf is given on the command line,\n" + " before -W set... the user may overwrite command\n" + " line parameters at netdata.conf\n" + " If -c netdata.conf is given after (or missing)\n" + " -W set... the user cannot overwrite the command line\n" + " parameters." + " conf_file can be \"cloud\" or \"netdata\".\n" + "\n" + ); + return 1; + } + const char *conf_file = argv[optind]; /* "cloud" is cloud.conf, otherwise netdata.conf */ + struct config *tmp_config = strcmp(conf_file, "cloud") ? &netdata_config : &cloud_config; + const char *section = argv[optind + 1]; + const char *key = argv[optind + 2]; + const char *value = argv[optind + 3]; + optind += 4; + + // set this one as the default + // only if it is not already set in the config file + // so the caller can use -c netdata.conf before or + // after this parameter to prevent or allow overwriting + // variables at netdata.conf + appconfig_set_default(tmp_config, section, key, value); + + // fprintf(stderr, "SET section '%s', key '%s', value '%s'\n", section, key, value); + } else if(strcmp(optarg, "get") == 0) { if(optind + 3 > argc) { fprintf(stderr, "%s", "\nUSAGE: -W get 'section' 'key' 'value'\n\n" @@ -1067,6 +1206,7 @@ int main(int argc, char **argv) { if(!config_loaded) { fprintf(stderr, "warning: no configuration file has been loaded. Use -c CONFIG_FILE, before -W get. Using default config.\n"); load_netdata_conf(NULL, 0); + post_conf_load(&user); } get_netdata_configured_variables(); @@ -1078,6 +1218,46 @@ int main(int argc, char **argv) { printf("%s\n", value); return 0; } + else if(strcmp(optarg, "get2") == 0) { + if(optind + 4 > argc) { + fprintf(stderr, "%s", "\nUSAGE: -W get2 'conf_file' 'section' 'key' 'value'\n\n" + " Prints settings of netdata.conf or cloud.conf\n" + "\n" + " These options interact with: -c netdata.conf\n" + " -c netdata.conf has to be given before -W get2.\n" + " conf_file can be \"cloud\" or \"netdata\".\n" + "\n" + ); + return 1; + } + + if(!config_loaded) { + fprintf(stderr, "warning: no configuration file has been loaded. Use -c CONFIG_FILE, before -W get. Using default config.\n"); + load_netdata_conf(NULL, 0); + post_conf_load(&user); + load_cloud_conf(1); + } + + get_netdata_configured_variables(); + + const char *conf_file = argv[optind]; /* "cloud" is cloud.conf, otherwise netdata.conf */ + struct config *tmp_config = strcmp(conf_file, "cloud") ? &netdata_config : &cloud_config; + const char *section = argv[optind + 1]; + const char *key = argv[optind + 2]; + const char *def = argv[optind + 3]; + const char *value = appconfig_get(tmp_config, section, key, def); + printf("%s\n", value); + return 0; + } + else if(strncmp(optarg, claim_string, strlen(claim_string)) == 0) { + /* will trigger a claiming attempt when the agent is initialized */ + claiming_pending_arguments = optarg + strlen(claim_string); + } + else if(strcmp(optarg, "buildinfo") == 0) { + printf("Version: %s %s\n", program_name, program_version); + print_build_info(); + return 0; + } else { fprintf(stderr, "Unknown -W parameter '%s'\n", optarg); return help(1); @@ -1103,7 +1283,12 @@ int main(int argc, char **argv) { #endif if(!config_loaded) + { load_netdata_conf(NULL, 0); + post_conf_load(&user); + load_cloud_conf(0); + } + // ------------------------------------------------------------------------ // initialize netdata @@ -1118,6 +1303,7 @@ int main(int argc, char **argv) { mallopt(M_ARENA_MAX, 1); #endif test_clock_boottime(); + test_clock_monotonic_coarse(); // prepare configuration environment variables for the plugins @@ -1129,9 +1315,10 @@ int main(int argc, char **argv) { // files using relative filenames if(chdir(netdata_configured_user_config_dir) == -1) fatal("Cannot cd to '%s'", netdata_configured_user_config_dir); - } - char *user = NULL; + // Get execution path before switching user to avoid permission issues + get_netdata_execution_path(); + } { // -------------------------------------------------------------------- @@ -1199,19 +1386,6 @@ int main(int argc, char **argv) { // -------------------------------------------------------------------- - // get the user we should run - - // IMPORTANT: this is required before web_files_uid() - if(getuid() == 0) { - user = config_get(CONFIG_SECTION_GLOBAL, "run as user", NETDATA_USER); - } - else { - struct passwd *passwd = getpwuid(getuid()); - user = config_get(CONFIG_SECTION_GLOBAL, "run as user", (passwd && passwd->pw_name)?passwd->pw_name:""); - } - - - // -------------------------------------------------------------------- // create the listening sockets web_client_api_v1_init(); @@ -1254,6 +1428,19 @@ int main(int argc, char **argv) { netdata_threads_init_after_fork((size_t)config_get_number(CONFIG_SECTION_GLOBAL, "pthread stack size", (long)default_stacksize)); + // initialyze internal registry + registry_init(); + // fork the spawn server + spawn_init(); + /* + * Libuv uv_spawn() uses SIGCHLD internally: + * https://github.com/libuv/libuv/blob/cc51217a317e96510fbb284721d5e6bc2af31e33/src/unix/process.c#L485 + * and inadvertently replaces the netdata signal handler which was setup during initialization. + * Thusly, we must explicitly restore the signal handler for SIGCHLD. + * Warning: extreme care is needed when mixing and matching POSIX and libuv. + */ + signals_restore_SIGCHLD(); + // ------------------------------------------------------------------------ // initialize rrd, registry, health, rrdpush, etc. @@ -1261,12 +1448,24 @@ int main(int argc, char **argv) { struct rrdhost_system_info *system_info = calloc(1, sizeof(struct rrdhost_system_info)); get_system_info(system_info); - rrd_init(netdata_configured_hostname, system_info); + if(rrd_init(netdata_configured_hostname, system_info)) + fatal("Cannot initialize localhost instance with name '%s'.", netdata_configured_hostname); + + // ------------------------------------------------------------------------ + // Claim netdata agent to a cloud endpoint + + if (claiming_pending_arguments) + claim_agent(claiming_pending_arguments); + load_claiming_state(); + // ------------------------------------------------------------------------ // enable log flood protection error_log_limit_reset(); + // Load host labels + reload_host_labels(); + // ------------------------------------------------------------------------ // spawn the threads @@ -1285,12 +1484,39 @@ int main(int argc, char **argv) { else debug(D_SYSTEM, "Not starting thread %s.", st->name); } + // ------------------------------------------------------------------------ + // Initialize netdata agent command serving from cli and signals + + commands_init(); + info("netdata initialization completed. Enjoy real-time performance monitoring!"); netdata_ready = 1; send_statistics("START", "-", "-"); // ------------------------------------------------------------------------ + // Report ACLK build failure +#ifndef ENABLE_ACLK + error("This agent doesn't have ACLK."); + char filename[FILENAME_MAX + 1]; + snprintfz(filename, FILENAME_MAX, "%s/.aclk_report_sent", netdata_configured_varlib_dir); + if (netdata_anonymous_statistics_enabled > 0 && access(filename, F_OK)) { // -1 -> not initialized + send_statistics("ACLK_DISABLED", "-", "-"); +#ifdef ACLK_NO_LWS + send_statistics("BUILD_FAIL_LWS", "-", "-"); +#endif +#ifdef ACLK_NO_LIBMOSQ + send_statistics("BUILD_FAIL_MOSQ", "-", "-"); +#endif + int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 444); + if (fd == -1) + error("Cannot create file '%s'. Please fix this.", filename); + else + close(fd); + } +#endif + + // ------------------------------------------------------------------------ // unblock signals signals_unblock(); |