#define COLLECTD_LOCALE "C"
#endif
-/*
- * Global variables
- */
-char hostname_g[DATA_MAX_NAME_LEN];
-cdtime_t interval_g;
-int timeout_g;
-#if HAVE_LIBKSTAT
-kstat_ctl_t *kc;
-#endif /* HAVE_LIBKSTAT */
-
static int loop = 0;
static void *do_flush(void __attribute__((unused)) * arg) {
}
static int init_hostname(void) {
- const char *str;
-
- struct addrinfo *ai_list;
- int status;
-
- str = global_option_get("Hostname");
+ const char *str = global_option_get("Hostname");
if ((str != NULL) && (str[0] != 0)) {
- sstrncpy(hostname_g, str, sizeof(hostname_g));
- return (0);
+ hostname_set(str);
+ return 0;
+ }
+
+ long hostname_len = sysconf(_SC_HOST_NAME_MAX);
+ if (hostname_len == -1) {
+ hostname_len = NI_MAXHOST;
}
+ char hostname[hostname_len];
- if (gethostname(hostname_g, sizeof(hostname_g)) != 0) {
+ if (gethostname(hostname, hostname_len) != 0) {
fprintf(stderr, "`gethostname' failed and no "
"hostname was configured.\n");
- return (-1);
+ return -1;
}
+ hostname_set(hostname);
+
str = global_option_get("FQDNLookup");
if (IS_FALSE(str))
- return (0);
+ return 0;
+ struct addrinfo *ai_list;
struct addrinfo ai_hints = {.ai_flags = AI_CANONNAME};
- status = getaddrinfo(hostname_g, NULL, &ai_hints, &ai_list);
+ int status = getaddrinfo(hostname, NULL, &ai_hints, &ai_list);
if (status != 0) {
ERROR("Looking up \"%s\" failed. You have set the "
"\"FQDNLookup\" option, but I cannot resolve "
"my hostname to a fully qualified domain "
"name. Please fix the network "
"configuration.",
- hostname_g);
- return (-1);
+ hostname);
+ return -1;
}
for (struct addrinfo *ai_ptr = ai_list; ai_ptr != NULL;
if (ai_ptr->ai_canonname == NULL)
continue;
- sstrncpy(hostname_g, ai_ptr->ai_canonname, sizeof(hostname_g));
+ hostname_set(ai_ptr->ai_canonname);
break;
}
freeaddrinfo(ai_list);
- return (0);
+ return 0;
} /* int init_hostname */
static int init_global_variables(void) {
if (timeout_g <= 1) {
fprintf(stderr, "Cannot set the timeout to a correct value.\n"
"Please check your settings.\n");
- return (-1);
+ return -1;
}
DEBUG("timeout_g = %i;", timeout_g);
if (init_hostname() != 0)
- return (-1);
+ return -1;
DEBUG("hostname_g = %s;", hostname_g);
- return (0);
+ return 0;
} /* int init_global_variables */
-static int change_basedir(const char *orig_dir) {
+static int change_basedir(const char *orig_dir, _Bool create) {
char *dir;
size_t dirlen;
int status;
if (dir == NULL) {
char errbuf[1024];
ERROR("strdup failed: %s", sstrerror(errno, errbuf, sizeof(errbuf)));
- return (-1);
+ return -1;
}
dirlen = strlen(dir);
if (dirlen == 0) {
free(dir);
- return (-1);
+ return -1;
}
status = chdir(dir);
if (status == 0) {
free(dir);
- return (0);
- } else if (errno != ENOENT) {
+ return 0;
+ } else if (!create || (errno != ENOENT)) {
char errbuf[1024];
ERROR("change_basedir: chdir (%s): %s", dir,
sstrerror(errno, errbuf, sizeof(errbuf)));
free(dir);
- return (-1);
+ return -1;
}
status = mkdir(dir, S_IRWXU | S_IRWXG | S_IRWXO);
ERROR("change_basedir: mkdir (%s): %s", dir,
sstrerror(errno, errbuf, sizeof(errbuf)));
free(dir);
- return (-1);
+ return -1;
}
status = chdir(dir);
ERROR("change_basedir: chdir (%s): %s", dir,
sstrerror(errno, errbuf, sizeof(errbuf)));
free(dir);
- return (-1);
+ return -1;
}
free(dir);
- return (0);
+ return 0;
} /* static int change_basedir (char *dir) */
#if HAVE_LIBKSTAT
#if COLLECT_DAEMON
" -f Don't fork to the background.\n"
#endif
+ " -B Don't create the BaseDir\n"
" -h Display help (this message)\n"
"\nBuiltin defaults:\n"
" Config file " CONFIGFILE "\n"
#endif
)) {
ERROR("sg_init: %s", sg_str_error(sg_get_error()));
- return (-1);
+ return -1;
}
if (sg_drop_privileges()) {
ERROR("sg_drop_privileges: %s", sg_str_error(sg_get_error()));
- return (-1);
+ return -1;
}
#endif
if (errno != EINTR) {
char errbuf[1024];
ERROR("nanosleep failed: %s", sstrerror(errno, errbuf, sizeof(errbuf)));
- return (-1);
+ return -1;
}
}
} /* while (loop == 0) */
- return (0);
+ return 0;
} /* int do_loop */
static int do_shutdown(void) {
if ((fh = fopen(file, "w")) == NULL) {
char errbuf[1024];
ERROR("fopen (%s): %s", file, sstrerror(errno, errbuf, sizeof(errbuf)));
- return (1);
+ return 1;
}
fprintf(fh, "%i\n", (int)getpid());
fclose(fh);
- return (0);
+ return 0;
} /* static int pidfile_create (const char *file) */
static int pidfile_remove(void) {
if (file == NULL)
return 0;
- return (unlink(file));
+ return unlink(file);
} /* static int pidfile_remove (const char *file) */
#endif /* COLLECT_DAEMON */
}
#endif /* KERNEL_LINUX */
-int main(int argc, char **argv) {
- const char *configfile = CONFIGFILE;
- int test_config = 0;
- int test_readall = 0;
- const char *basedir;
-#if COLLECT_DAEMON
- pid_t pid;
- int daemonize = 1;
-#endif
- int exit_status = 0;
+struct cmdline_config {
+ _Bool test_config;
+ _Bool test_readall;
+ _Bool create_basedir;
+ const char *configfile;
+ _Bool daemonize;
+};
+void read_cmdline(int argc, char **argv, struct cmdline_config *config) {
/* read options */
while (1) {
int c;
-
c = getopt(argc, argv, "htTC:"
#if COLLECT_DAEMON
"fP:"
break;
switch (c) {
+ case 'B':
+ config->create_basedir = 0;
+ break;
case 'C':
- configfile = optarg;
+ config->configfile = optarg;
break;
case 't':
- test_config = 1;
+ config->test_config = 1;
break;
case 'T':
- test_readall = 1;
+ config->test_readall = 1;
global_option_set("ReadThreads", "-1", 1);
#if COLLECT_DAEMON
- daemonize = 0;
+ config->daemonize = 0;
#endif /* COLLECT_DAEMON */
break;
#if COLLECT_DAEMON
global_option_set("PIDFile", optarg, 1);
break;
case 'f':
- daemonize = 0;
+ config->daemonize = 0;
break;
#endif /* COLLECT_DAEMON */
case 'h':
exit_usage(1);
} /* switch (c) */
} /* while (1) */
+}
- if (optind < argc)
- exit_usage(1);
-
- plugin_init_ctx();
-
+int configure_collectd(struct cmdline_config *config) {
+ const char *basedir;
/*
* Read options from the config file, the environment and the command
* line (in that order, with later options overwriting previous ones in
* general).
* Also, this will automatically load modules.
*/
- if (cf_read(configfile)) {
+ if (cf_read(config->configfile)) {
fprintf(stderr, "Error: Reading the config file failed!\n"
"Read the logs for details.\n");
- return (1);
+ return 1;
}
/*
if ((basedir = global_option_get("BaseDir")) == NULL) {
fprintf(stderr,
"Don't have a basedir to use. This should not happen. Ever.");
- return (1);
- } else if (change_basedir(basedir)) {
+ return 1;
+ } else if (change_basedir(basedir, config->create_basedir)) {
fprintf(stderr, "Error: Unable to change to directory `%s'.\n", basedir);
- return (1);
+ return 1;
}
/*
- * Set global variables or, if that failes, exit. We cannot run with
+ * Set global variables or, if that fails, exit. We cannot run with
* them being uninitialized. If nothing is configured, then defaults
* are being used. So this means that the user has actually done
* something wrong.
*/
if (init_global_variables() != 0)
- exit(EXIT_FAILURE);
+ return 1;
- if (test_config)
- return (0);
+ return 0;
+}
+
+int main(int argc, char **argv) {
+#if COLLECT_DAEMON
+ pid_t pid;
+#endif
+ int exit_status = 0;
+
+ struct cmdline_config config = {
+ .daemonize = 1, .create_basedir = 1, .configfile = CONFIGFILE,
+ };
+
+ read_cmdline(argc, argv, &config);
+
+ if (config.test_config)
+ return 0;
+
+ if (optind < argc)
+ exit_usage(1);
+
+ plugin_init_ctx();
+
+ int status;
+ if ((status = configure_collectd(&config)) != 0)
+ exit(EXIT_FAILURE);
#if COLLECT_DAEMON
/*
* Only daemonize if we're not being supervised
* by upstart or systemd (when using Linux).
*/
- if (daemonize
+ if (config.daemonize
#ifdef KERNEL_LINUX
&& notify_upstart() == 0 && notify_systemd() == 0
#endif
/* error */
char errbuf[1024];
fprintf(stderr, "fork: %s", sstrerror(errno, errbuf, sizeof(errbuf)));
- return (1);
+ return 1;
} else if (pid != 0) {
/* parent */
/* printf ("Running (PID %i)\n", pid); */
- return (0);
+ return 0;
}
/* Detach from session */
if (status != 0) {
ERROR("Error: Could not connect `STDIN' to `/dev/null' (status %d)",
status);
- return (1);
+ return 1;
}
status = dup(0);
if (status != 1) {
ERROR("Error: Could not connect `STDOUT' to `/dev/null' (status %d)",
status);
- return (1);
+ return 1;
}
status = dup(0);
if (status != 2) {
ERROR("Error: Could not connect `STDERR' to `/dev/null', (status %d)",
status);
- return (1);
+ return 1;
}
- } /* if (daemonize) */
+ } /* if (config.daemonize) */
#endif /* COLLECT_DAEMON */
struct sigaction sig_pipe_action = {.sa_handler = SIG_IGN};
char errbuf[1024];
ERROR("Error: Failed to install a signal handler for signal INT: %s",
sstrerror(errno, errbuf, sizeof(errbuf)));
- return (1);
+ return 1;
}
struct sigaction sig_term_action = {.sa_handler = sig_term_handler};
char errbuf[1024];
ERROR("Error: Failed to install a signal handler for signal TERM: %s",
sstrerror(errno, errbuf, sizeof(errbuf)));
- return (1);
+ return 1;
}
struct sigaction sig_usr1_action = {.sa_handler = sig_usr1_handler};
char errbuf[1024];
ERROR("Error: Failed to install a signal handler for signal USR1: %s",
sstrerror(errno, errbuf, sizeof(errbuf)));
- return (1);
+ return 1;
}
/*
exit_status = 1;
}
- if (test_readall) {
+ if (config.test_readall) {
if (plugin_read_all_once() != 0) {
ERROR("Error: one or more plugin read callbacks failed.");
exit_status = 1;
}
#if COLLECT_DAEMON
- if (daemonize)
+ if (config.daemonize)
pidfile_remove();
#endif /* COLLECT_DAEMON */
- return (exit_status);
+ return exit_status;
} /* int main */