Fix compile time issues
[collectd.git] / src / daemon / collectd.c
index 9ec0934..78d410c 100644 (file)
  *   Alvaro Barcellos <alvaro.barcellos at gmail.com>
  **/
 
+#include "cmd.h"
 #include "collectd.h"
 
-#include "common.h"
 #include "configfile.h"
 #include "plugin.h"
+#include "utils/common/common.h"
 
 #include <netdb.h>
 #include <sys/types.h>
-#include <sys/un.h>
 
 #if HAVE_LOCALE_H
 #include <locale.h>
 #include <statgrab.h>
 #endif
 
+#if HAVE_KSTAT_H
+#include <kstat.h>
+#endif
+
 #ifndef COLLECTD_LOCALE
 #define COLLECTD_LOCALE "C"
 #endif
 
-static int loop = 0;
-
-static void *do_flush(void __attribute__((unused)) * arg) {
-  INFO("Flushing all data.");
-  plugin_flush(/* plugin = */ NULL,
-               /* timeout = */ 0,
-               /* ident = */ NULL);
-  INFO("Finished flushing all data.");
-  pthread_exit(NULL);
-  return NULL;
-}
-
-static void sig_int_handler(int __attribute__((unused)) signal) { loop++; }
-
-static void sig_term_handler(int __attribute__((unused)) signal) { loop++; }
-
-static void sig_usr1_handler(int __attribute__((unused)) signal) {
-  pthread_t thread;
-  pthread_attr_t attr;
+#ifdef WIN32
+#undef COLLECT_DAEMON
+#include <unistd.h>
+#undef gethostname
+#include <locale.h>
+#include <winsock2.h>
+#endif
 
-  /* flushing the data might take a while,
-   * so it should be done asynchronously */
-  pthread_attr_init(&attr);
-  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-  pthread_create(&thread, &attr, do_flush, NULL);
-  pthread_attr_destroy(&attr);
-}
+static int loop;
 
 static int init_hostname(void) {
   const char *str = global_option_get("Hostname");
-  if ((str != NULL) && (str[0] != 0)) {
+  if (str && str[0] != '\0') {
     hostname_set(str);
     return 0;
   }
 
+#ifdef WIN32
+  long hostname_len = NI_MAXHOST;
+#else
   long hostname_len = sysconf(_SC_HOST_NAME_MAX);
   if (hostname_len == -1) {
     hostname_len = NI_MAXHOST;
   }
+#endif /* WIN32 */
   char hostname[hostname_len];
 
   if (gethostname(hostname, hostname_len) != 0) {
@@ -114,8 +104,7 @@ static int init_hostname(void) {
     return -1;
   }
 
-  for (struct addrinfo *ai_ptr = ai_list; ai_ptr != NULL;
-       ai_ptr = ai_ptr->ai_next) {
+  for (struct addrinfo *ai_ptr = ai_list; ai_ptr; ai_ptr = ai_ptr->ai_next) {
     if (ai_ptr->ai_canonname == NULL)
       continue;
 
@@ -128,13 +117,11 @@ static int init_hostname(void) {
 } /* int init_hostname */
 
 static int init_global_variables(void) {
-  char const *str;
-
   interval_g = cf_get_default_interval();
   assert(interval_g > 0);
   DEBUG("interval_g = %.3f;", CDTIME_T_TO_DOUBLE(interval_g));
 
-  str = global_option_get("Timeout");
+  const char *str = global_option_get("Timeout");
   if (str == NULL)
     str = "2";
   timeout_g = atoi(str);
@@ -152,19 +139,14 @@ static int init_global_variables(void) {
   return 0;
 } /* int init_global_variables */
 
-static int change_basedir(const char *orig_dir, _Bool create) {
-  char *dir;
-  size_t dirlen;
-  int status;
-
-  dir = strdup(orig_dir);
+static int change_basedir(const char *orig_dir, bool create) {
+  char *dir = strdup(orig_dir);
   if (dir == NULL) {
-    char errbuf[1024];
-    ERROR("strdup failed: %s", sstrerror(errno, errbuf, sizeof(errbuf)));
+    ERROR("strdup failed: %s", STRERRNO);
     return -1;
   }
 
-  dirlen = strlen(dir);
+  size_t dirlen = strlen(dir);
   while ((dirlen > 0) && (dir[dirlen - 1] == '/'))
     dir[--dirlen] = '\0';
 
@@ -173,32 +155,26 @@ static int change_basedir(const char *orig_dir, _Bool create) {
     return -1;
   }
 
-  status = chdir(dir);
+  int status = chdir(dir);
   if (status == 0) {
     free(dir);
     return 0;
   } else if (!create || (errno != ENOENT)) {
-    char errbuf[1024];
-    ERROR("change_basedir: chdir (%s): %s", dir,
-          sstrerror(errno, errbuf, sizeof(errbuf)));
+    ERROR("change_basedir: chdir (%s): %s", dir, STRERRNO);
     free(dir);
     return -1;
   }
 
   status = mkdir(dir, S_IRWXU | S_IRWXG | S_IRWXO);
   if (status != 0) {
-    char errbuf[1024];
-    ERROR("change_basedir: mkdir (%s): %s", dir,
-          sstrerror(errno, errbuf, sizeof(errbuf)));
+    ERROR("change_basedir: mkdir (%s): %s", dir, STRERRNO);
     free(dir);
     return -1;
   }
 
   status = chdir(dir);
   if (status != 0) {
-    char errbuf[1024];
-    ERROR("change_basedir: chdir (%s): %s", dir,
-          sstrerror(errno, errbuf, sizeof(errbuf)));
+    ERROR("change_basedir: chdir (%s): %s", dir, STRERRNO);
     free(dir);
     return -1;
   }
@@ -208,13 +184,13 @@ static int change_basedir(const char *orig_dir, _Bool create) {
 } /* static int change_basedir (char *dir) */
 
 #if HAVE_LIBKSTAT
+extern kstat_ctl_t *kc;
 static void update_kstat(void) {
   if (kc == NULL) {
     if ((kc = kstat_open()) == NULL)
       ERROR("Unable to open kstat control structure");
   } else {
-    kid_t kid;
-    kid = kstat_chain_update(kc);
+    kid_t kid = kstat_chain_update(kc);
     if (kid > 0) {
       INFO("kstat chain has been updated");
       plugin_init_all();
@@ -227,9 +203,6 @@ static void update_kstat(void) {
 } /* static void update_kstat (void) */
 #endif /* HAVE_LIBKSTAT */
 
-/* TODO
- * Remove all settings but `-f' and `-C'
- */
 __attribute__((noreturn)) static void exit_usage(int status) {
   printf("Usage: " PACKAGE_NAME " [OPTIONS]\n\n"
 
@@ -294,13 +267,9 @@ static int do_init(void) {
 
 static int do_loop(void) {
   cdtime_t interval = cf_get_default_interval();
-  cdtime_t wait_until;
-
-  wait_until = cdtime() + interval;
+  cdtime_t wait_until = cdtime() + interval;
 
   while (loop == 0) {
-    cdtime_t now;
-
 #if HAVE_LIBKSTAT
     update_kstat();
 #endif
@@ -308,7 +277,7 @@ static int do_loop(void) {
     /* Issue all plugins */
     plugin_read_all();
 
-    now = cdtime();
+    cdtime_t now = cdtime();
     if (now >= wait_until) {
       WARNING("Not sleeping because the next interval is "
               "%.3f seconds in the past!",
@@ -322,8 +291,7 @@ static int do_loop(void) {
 
     while ((loop == 0) && (nanosleep(&ts_wait, &ts_wait) != 0)) {
       if (errno != EINTR) {
-        char errbuf[1024];
-        ERROR("nanosleep failed: %s", sstrerror(errno, errbuf, sizeof(errbuf)));
+        ERROR("nanosleep failed: %s", STRERRNO);
         return -1;
       }
     }
@@ -336,155 +304,34 @@ static int do_shutdown(void) {
   return plugin_shutdown_all();
 } /* int do_shutdown */
 
-#if COLLECT_DAEMON
-static int pidfile_create(void) {
-  FILE *fh;
-  const char *file = global_option_get("PIDFile");
-
-  if ((fh = fopen(file, "w")) == NULL) {
-    char errbuf[1024];
-    ERROR("fopen (%s): %s", file, sstrerror(errno, errbuf, sizeof(errbuf)));
-    return 1;
-  }
-
-  fprintf(fh, "%i\n", (int)getpid());
-  fclose(fh);
-
-  return 0;
-} /* static int pidfile_create (const char *file) */
-
-static int pidfile_remove(void) {
-  const char *file = global_option_get("PIDFile");
-  if (file == NULL)
-    return 0;
-
-  return unlink(file);
-} /* static int pidfile_remove (const char *file) */
-#endif /* COLLECT_DAEMON */
-
-#ifdef KERNEL_LINUX
-static int notify_upstart(void) {
-  char const *upstart_job = getenv("UPSTART_JOB");
-
-  if (upstart_job == NULL)
-    return 0;
-
-  if (strcmp(upstart_job, "collectd") != 0) {
-    WARNING("Environment specifies unexpected UPSTART_JOB=\"%s\", expected "
-            "\"collectd\". Ignoring the variable.",
-            upstart_job);
-    return 0;
-  }
-
-  NOTICE("Upstart detected, stopping now to signal readyness.");
-  raise(SIGSTOP);
-  unsetenv("UPSTART_JOB");
-
-  return 1;
-}
-
-static int notify_systemd(void) {
-  int fd;
-  const char *notifysocket;
-  struct sockaddr_un su = {0};
-  size_t su_size;
-  char buffer[] = "READY=1\n";
-
-  notifysocket = getenv("NOTIFY_SOCKET");
-  if (notifysocket == NULL)
-    return 0;
-
-  if ((strlen(notifysocket) < 2) ||
-      ((notifysocket[0] != '@') && (notifysocket[0] != '/'))) {
-    ERROR("invalid notification socket NOTIFY_SOCKET=\"%s\": path must be "
-          "absolute",
-          notifysocket);
-    return 0;
-  }
-  NOTICE("Systemd detected, trying to signal readyness.");
-
-  unsetenv("NOTIFY_SOCKET");
-
-#if defined(SOCK_CLOEXEC)
-  fd = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, /* protocol = */ 0);
-#else
-  fd = socket(AF_UNIX, SOCK_DGRAM, /* protocol = */ 0);
-#endif
-  if (fd < 0) {
-    char errbuf[1024];
-    ERROR("creating UNIX socket failed: %s",
-          sstrerror(errno, errbuf, sizeof(errbuf)));
-    return 0;
-  }
-
-  su.sun_family = AF_UNIX;
-  if (notifysocket[0] != '@') {
-    /* regular UNIX socket */
-    sstrncpy(su.sun_path, notifysocket, sizeof(su.sun_path));
-    su_size = sizeof(su);
-  } else {
-    /* Linux abstract namespace socket: specify address as "\0foo", i.e.
-     * start with a null byte. Since null bytes have no special meaning in
-     * that case, we have to set su_size correctly to cover only the bytes
-     * that are part of the address. */
-    sstrncpy(su.sun_path, notifysocket, sizeof(su.sun_path));
-    su.sun_path[0] = 0;
-    su_size = sizeof(sa_family_t) + strlen(notifysocket);
-    if (su_size > sizeof(su))
-      su_size = sizeof(su);
-  }
-
-  if (sendto(fd, buffer, strlen(buffer), MSG_NOSIGNAL, (void *)&su,
-             (socklen_t)su_size) < 0) {
-    char errbuf[1024];
-    ERROR("sendto(\"%s\") failed: %s", notifysocket,
-          sstrerror(errno, errbuf, sizeof(errbuf)));
-    close(fd);
-    return 0;
-  }
-
-  unsetenv("NOTIFY_SOCKET");
-  close(fd);
-  return 1;
-}
-#endif /* KERNEL_LINUX */
-
-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) {
+static void read_cmdline(int argc, char **argv, struct cmdline_config *config) {
   /* read options */
   while (1) {
-    int c;
-    c = getopt(argc, argv, "htTC:"
+    int c = getopt(argc, argv,
+                   "BhtTC:"
 #if COLLECT_DAEMON
-                           "fP:"
+                   "fP:"
 #endif
-               );
+    );
 
     if (c == -1)
       break;
 
     switch (c) {
     case 'B':
-      config->create_basedir = 0;
+      config->create_basedir = false;
       break;
     case 'C':
       config->configfile = optarg;
       break;
     case 't':
-      config->test_config = 1;
+      config->test_config = true;
       break;
     case 'T':
-      config->test_readall = 1;
+      config->test_readall = true;
       global_option_set("ReadThreads", "-1", 1);
 #if COLLECT_DAEMON
-      config->daemonize = 0;
+      config->daemonize = false;
 #endif /* COLLECT_DAEMON */
       break;
 #if COLLECT_DAEMON
@@ -492,20 +339,18 @@ void read_cmdline(int argc, char **argv, struct cmdline_config *config) {
       global_option_set("PIDFile", optarg, 1);
       break;
     case 'f':
-      config->daemonize = 0;
+      config->daemonize = false;
       break;
 #endif /* COLLECT_DAEMON */
     case 'h':
       exit_usage(0);
-      break;
     default:
       exit_usage(1);
     } /* switch (c) */
   }   /* while (1) */
 }
 
-int configure_collectd(struct cmdline_config *config) {
-  const char *basedir;
+static int configure_collectd(struct cmdline_config *config) {
   /*
    * Read options from the config file, the environment and the command
    * line (in that order, with later options overwriting previous ones in
@@ -513,8 +358,7 @@ int configure_collectd(struct cmdline_config *config) {
    * Also, this will automatically load modules.
    */
   if (cf_read(config->configfile)) {
-    fprintf(stderr, "Error: Reading the config file failed!\n"
-                    "Read the logs for details.\n");
+    fprintf(stderr, "Error: Parsing the config file failed!\n");
     return 1;
   }
 
@@ -522,6 +366,7 @@ int configure_collectd(struct cmdline_config *config) {
    * Change directory. We do this _after_ reading the config and loading
    * modules to relative paths work as expected.
    */
+  const char *basedir;
   if ((basedir = global_option_get("BaseDir")) == NULL) {
     fprintf(stderr,
             "Don't have a basedir to use. This should not happen. Ever.");
@@ -543,138 +388,40 @@ int configure_collectd(struct cmdline_config *config) {
   return 0;
 }
 
-int main(int argc, char **argv) {
-#if COLLECT_DAEMON
-  pid_t pid;
-#endif
-  int exit_status = 0;
+void stop_collectd(void) { loop++; }
 
+struct cmdline_config init_config(int argc, char **argv) {
   struct cmdline_config config = {
-      .daemonize = 1, .create_basedir = 1, .configfile = CONFIGFILE,
+      .daemonize = true,
+      .create_basedir = true,
+      .configfile = CONFIGFILE,
   };
 
   read_cmdline(argc, argv, &config);
 
   if (config.test_config)
-    return 0;
+    exit(EXIT_SUCCESS);
 
   if (optind < argc)
     exit_usage(1);
 
   plugin_init_ctx();
 
-  int status;
-  if ((status = configure_collectd(&config)) != 0)
+  if (configure_collectd(&config) != 0)
     exit(EXIT_FAILURE);
 
-#if COLLECT_DAEMON
-  /*
-   * fork off child
-   */
-  struct sigaction sig_chld_action = {.sa_handler = SIG_IGN};
-
-  sigaction(SIGCHLD, &sig_chld_action, NULL);
-
-  /*
-   * Only daemonize if we're not being supervised
-   * by upstart or systemd (when using Linux).
-   */
-  if (config.daemonize
-#ifdef KERNEL_LINUX
-      && notify_upstart() == 0 && notify_systemd() == 0
-#endif
-      ) {
-    int status;
-
-    if ((pid = fork()) == -1) {
-      /* error */
-      char errbuf[1024];
-      fprintf(stderr, "fork: %s", sstrerror(errno, errbuf, sizeof(errbuf)));
-      return 1;
-    } else if (pid != 0) {
-      /* parent */
-      /* printf ("Running (PID %i)\n", pid); */
-      return 0;
-    }
-
-    /* Detach from session */
-    setsid();
-
-    /* Write pidfile */
-    if (pidfile_create())
-      exit(2);
-
-    /* close standard descriptors */
-    close(2);
-    close(1);
-    close(0);
-
-    status = open("/dev/null", O_RDWR);
-    if (status != 0) {
-      ERROR("Error: Could not connect `STDIN' to `/dev/null' (status %d)",
-            status);
-      return 1;
-    }
-
-    status = dup(0);
-    if (status != 1) {
-      ERROR("Error: Could not connect `STDOUT' to `/dev/null' (status %d)",
-            status);
-      return 1;
-    }
-
-    status = dup(0);
-    if (status != 2) {
-      ERROR("Error: Could not connect `STDERR' to `/dev/null', (status %d)",
-            status);
-      return 1;
-    }
-  }    /* if (config.daemonize) */
-#endif /* COLLECT_DAEMON */
-
-  struct sigaction sig_pipe_action = {.sa_handler = SIG_IGN};
-
-  sigaction(SIGPIPE, &sig_pipe_action, NULL);
-
-  /*
-   * install signal handlers
-   */
-  struct sigaction sig_int_action = {.sa_handler = sig_int_handler};
-
-  if (0 != sigaction(SIGINT, &sig_int_action, NULL)) {
-    char errbuf[1024];
-    ERROR("Error: Failed to install a signal handler for signal INT: %s",
-          sstrerror(errno, errbuf, sizeof(errbuf)));
-    return 1;
-  }
-
-  struct sigaction sig_term_action = {.sa_handler = sig_term_handler};
-
-  if (0 != sigaction(SIGTERM, &sig_term_action, NULL)) {
-    char errbuf[1024];
-    ERROR("Error: Failed to install a signal handler for signal TERM: %s",
-          sstrerror(errno, errbuf, sizeof(errbuf)));
-    return 1;
-  }
-
-  struct sigaction sig_usr1_action = {.sa_handler = sig_usr1_handler};
+  return config;
+}
 
-  if (0 != sigaction(SIGUSR1, &sig_usr1_action, NULL)) {
-    char errbuf[1024];
-    ERROR("Error: Failed to install a signal handler for signal USR1: %s",
-          sstrerror(errno, errbuf, sizeof(errbuf)));
-    return 1;
-  }
+int run_loop(bool test_readall) {
+  int exit_status = 0;
 
-  /*
-   * run the actual loops
-   */
   if (do_init() != 0) {
     ERROR("Error: one or more plugin init callbacks failed.");
     exit_status = 1;
   }
 
-  if (config.test_readall) {
+  if (test_readall) {
     if (plugin_read_all_once() != 0) {
       ERROR("Error: one or more plugin read callbacks failed.");
       exit_status = 1;
@@ -692,10 +439,5 @@ int main(int argc, char **argv) {
     exit_status = 1;
   }
 
-#if COLLECT_DAEMON
-  if (config.daemonize)
-    pidfile_remove();
-#endif /* COLLECT_DAEMON */
-
   return exit_status;
-} /* int main */
+} /* int run_loop */