Hostinfo day 2: Implement the daemon.
[virt-hostinfo.git] / hostinfod / main.c
index ad5b326..e272210 100644 (file)
 #include <apr_general.h>
 #include <apr_network_io.h>
 #include <apr_getopt.h>
+#include <apr_strings.h>
+#include <apr_thread_proc.h>
+#include <apr_poll.h>
+#include <apr_portable.h>
 
 #include "hostinfod.h"
 
+static void main_loop (void);
+static void set_reread_socket_dir (const apr_pollfd_t *);
+static void do_reread_socket_dir (void);
+
+typedef void (*poll_callback) (const apr_pollfd_t *);
+
 const char *conf_file = DEFAULT_CONF_FILE;
-const char *socket_dir = DEFAULT_SOCKET_DIR;
+char *socket_dir = NULL;
 char *guests_file = NULL;
-int socket_dir_set_on_cmdline = 0;
-int debug = 0;
-int debug_set_on_cmdline = 0;
+
 int verbose = 0;
 int verbose_set_on_cmdline = 0;
 int foreground = 0;
 int foreground_set_on_cmdline = 0;
+
+int messages_to_stderr = 1;
+
+static int reread_socket_dir = 1;
+static int quit = 0;
+
 apr_pool_t *pool = NULL;
+static apr_pollset_t *set;
 
 static void
 usage (void)
@@ -55,14 +70,11 @@ usage (void)
          "  --help           Display full usage\n"
          "  -c file | --config file\n"
          "                   Configuration file (default: %s)\n"
-         "  -d | --debug     Enable debug messages to stderr (implies -v)\n"
          "  -f | --foreground\n"
          "                   Run in the foreground (don't fork)\n"
-         "  -s dir | --socketdir dir\n"
-         "                   Socket directory (default: %s)\n"
          "  -v               Enable verbose messages (sent to syslog, and to\n"
          "                     stderr if -d option is given)\n",
-         DEFAULT_CONF_FILE, DEFAULT_SOCKET_DIR);
+         DEFAULT_CONF_FILE);
 }
 
 int
@@ -70,9 +82,7 @@ main (int argc, char *argv[])
 {
   static const apr_getopt_option_t options[] = {
     { "config", 'c', TRUE, "configuration file" },
-    { "debug", 'd', FALSE, "enable debug messages to stderr" },
     { "foreground", 'f', FALSE, "run in foreground (don't fork)" },
-    { "socketdir", 's', TRUE, "socket directory" },
     { "verbose", 'v', FALSE, "enable verbose messages" },
     { "help", '?', FALSE, "display help" },
     { NULL, 0, 0, NULL },
@@ -87,6 +97,12 @@ main (int argc, char *argv[])
 
   apr_getopt_init (&opt, pool, argc, argv);
 
+  init_syslog ();
+
+  socket_dir = apr_pstrdup (pool, DEFAULT_SOCKET_DIR);
+  guests_file = apr_pstrdup (pool, DEFAULT_GUESTS_FILE);
+
+  /* Command line. */
   while ((r = apr_getopt_long (opt, options, &c, &optarg)) == APR_SUCCESS) {
     switch (c) {
     case 'c':
@@ -95,22 +111,14 @@ main (int argc, char *argv[])
        * it should exist.  They may have typo'd the name.
        */
       if (access (conf_file, R_OK) == -1) {
-       perror (conf_file);
+       perrorf ("%s", conf_file);
        exit (1);
       }
       break;
-    case 'd':
-      debug = verbose = 1;
-      debug_set_on_cmdline = verbose_set_on_cmdline = 1;
-      break;
     case 'f':
       foreground = 1;
       foreground_set_on_cmdline = 1;
       break;
-    case 's':
-      socket_dir = optarg;
-      socket_dir_set_on_cmdline = 1;
-      break;
     case 'v':
       verbose = 1;
       verbose_set_on_cmdline = 1;
@@ -127,22 +135,114 @@ main (int argc, char *argv[])
     exit (1);
   }
 
+  /* Read the config file. */
   read_main_conf_file ();
 
+  /* Monitor the socket directory. */
+  monitor_socket_dir ();
 
-
-
-
-
-
+  /* Create the initial pollset, just containing inotify socket. */
+  r = apr_pollset_create (&set, 1024 /* ? */, pool, 0);
+  if (r != APR_SUCCESS) {
+    paprerror (r, "apr_pollset_create");
+    exit (1);
+  }
+  apr_socket_t *tsock;
+  r = apr_os_sock_put (&tsock, &sockets_inotify_fd, pool);
+  if (r != APR_SUCCESS) {
+    paprerror (r, "apr_os_sock_put");
+    exit (1);
+  }
+  apr_pollfd_t *tpollfd = apr_palloc (pool, sizeof *tpollfd);
+  tpollfd->p = pool;
+  tpollfd->desc_type = APR_POLL_SOCKET;
+  tpollfd->reqevents = APR_POLLIN;
+  tpollfd->rtnevents = 0;
+  tpollfd->desc.s = tsock;
+  tpollfd->client_data = set_reread_socket_dir;
+  r = apr_pollset_add (set, tpollfd);
+  if (r != APR_SUCCESS) {
+    paprerror (r, "apr_pollset_add");
+    exit (1);
+  }
 
   /* Daemonize. */
   chdir ("/");
-  if (!foreground)
+  if (!foreground) {
     apr_proc_detach (1);
 
+    /* After we detach from the terminal, all further messages
+     * should just go to syslog.
+     */
+    messages_to_stderr = 0;
+  }
 
+  message (PACKAGE_STRING);
+  main_loop ();
 
   apr_terminate ();
   return 0;
 }
+
+static void
+main_loop (void)
+{
+  apr_status_t r;
+  apr_int32_t numdescs;
+  const apr_pollfd_t *descs;
+  int i;
+
+  while (!quit) {
+    /* A socket has appeared or disappeared from the socket directory. */
+    if (reread_socket_dir) {
+      do_reread_socket_dir ();
+      reread_socket_dir = 0;
+    }
+
+    /* Poll. */
+    r = apr_pollset_poll (set, 0, &numdescs, &descs);
+    if (r != APR_SUCCESS) {
+      paprerror (r, "apr_pollset_poll");
+      exit (1);
+    }
+
+    /* Perform the callbacks. */
+    for (i = 0; i < numdescs; ++i) {
+      poll_callback callback;
+
+      callback = descs[i].client_data;
+      callback (&descs[i]);
+    }
+  }
+}
+
+static void
+set_reread_socket_dir (const apr_pollfd_t *_)
+{
+  reread_socket_dir = 1;
+}
+
+static void
+do_reread_socket_dir (void)
+{
+  char buf[256];
+
+  debug ("reading socket directory");
+
+  /* Discard anything which appears on the inotify socket.  We will
+   * reread the whole directory each time.
+   */
+  while (read (sockets_inotify_fd, buf, sizeof buf) > 0)
+    ;
+
+
+
+
+
+
+
+
+
+
+
+}