Fix compile time issues
[collectd.git] / src / daemon / collectd.c
index 7e85975..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>
 #define COLLECTD_LOCALE "C"
 #endif
 
-static int loop;
-
-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");
@@ -86,10 +68,14 @@ static int init_hostname(void) {
     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) {
@@ -318,128 +304,15 @@ 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) {
-    ERROR("fopen (%s): %s", file, STRERRNO);
-    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 readiness.");
-  raise(SIGSTOP);
-  unsetenv("UPSTART_JOB");
-
-  return 1;
-}
-
-static int notify_systemd(void) {
-  size_t su_size;
-  const char *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 readiness.");
-
-  unsetenv("NOTIFY_SOCKET");
-
-  int fd;
-#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) {
-    ERROR("creating UNIX socket failed: %s", STRERRNO);
-    return 0;
-  }
-
-  struct sockaddr_un su = {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);
-  }
-
-  const char buffer[] = "READY=1\n";
-  if (sendto(fd, buffer, strlen(buffer), MSG_NOSIGNAL, (void *)&su,
-             (socklen_t)su_size) < 0) {
-    ERROR("sendto(\"%s\") failed: %s", notifysocket, STRERRNO);
-    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;
-};
-
 static void read_cmdline(int argc, char **argv, struct cmdline_config *config) {
   /* read options */
   while (1) {
-    int c = getopt(argc, argv, "htTC:"
+    int c = getopt(argc, argv,
+                   "BhtTC:"
 #if COLLECT_DAEMON
-                               "fP:"
+                   "fP:"
 #endif
-                   );
+    );
 
     if (c == -1)
       break;
@@ -485,8 +358,7 @@ static 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;
   }
 
@@ -516,17 +388,19 @@ static int configure_collectd(struct cmdline_config *config) {
   return 0;
 }
 
-int main(int argc, char **argv) {
-  int exit_status = 0;
+void stop_collectd(void) { loop++; }
 
+struct cmdline_config init_config(int argc, char **argv) {
   struct cmdline_config config = {
-      .daemonize = true, .create_basedir = true, .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);
@@ -536,109 +410,18 @@ int main(int argc, char **argv) {
   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
-      ) {
-    pid_t pid;
-    if ((pid = fork()) == -1) {
-      /* error */
-      fprintf(stderr, "fork: %s", STRERRNO);
-      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);
-
-    int 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 (sigaction(SIGINT, &sig_int_action, NULL) != 0) {
-    ERROR("Error: Failed to install a signal handler for signal INT: %s",
-          STRERRNO);
-    return 1;
-  }
-
-  struct sigaction sig_term_action = {.sa_handler = sig_term_handler};
-
-  if (sigaction(SIGTERM, &sig_term_action, NULL) != 0) {
-    ERROR("Error: Failed to install a signal handler for signal TERM: %s",
-          STRERRNO);
-    return 1;
-  }
-
-  struct sigaction sig_usr1_action = {.sa_handler = sig_usr1_handler};
+  return config;
+}
 
-  if (sigaction(SIGUSR1, &sig_usr1_action, NULL) != 0) {
-    ERROR("Error: Failed to install a signal handler for signal USR1: %s",
-          STRERRNO);
-    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;
@@ -656,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 */