src/rrd_daemon.c: Use static structs for the signal handler configuration.
[rrdtool.git] / src / rrd_daemon.c
index 9712fcd..87ac8e9 100644 (file)
@@ -148,6 +148,8 @@ static pthread_cond_t  flush_cond = PTHREAD_COND_INITIALIZER;
 
 static int config_write_interval = 300;
 static int config_flush_interval = 3600;
+static char *config_pid_file = NULL;
+static char *config_base_dir = NULL;
 
 static char **config_listen_address_list = NULL;
 static int config_listen_address_list_len = 0;
@@ -165,6 +167,46 @@ static void sig_term_handler (int s __attribute__((unused))) /* {{{ */
   do_shutdown++;
 } /* }}} void sig_term_handler */
 
+static int write_pidfile (void) /* {{{ */
+{
+  pid_t pid;
+  char *file;
+  FILE *fh;
+
+  pid = getpid ();
+  
+  file = (config_pid_file != NULL)
+    ? config_pid_file
+    : LOCALSTATEDIR "/run/rrdcached.pid";
+
+  fh = fopen (file, "w");
+  if (fh == NULL)
+  {
+    RRDD_LOG (LOG_ERR, "write_pidfile: Opening `%s' failed.", file);
+    return (-1);
+  }
+
+  fprintf (fh, "%i\n", (int) pid);
+  fclose (fh);
+
+  return (0);
+} /* }}} int write_pidfile */
+
+static int remove_pidfile (void) /* {{{ */
+{
+  char *file;
+  int status;
+
+  file = (config_pid_file != NULL)
+    ? config_pid_file
+    : LOCALSTATEDIR "/run/rrdcached.pid";
+
+  status = unlink (file);
+  if (status == 0)
+    return (0);
+  return (errno);
+} /* }}} int remove_pidfile */
+
 /*
  * enqueue_cache_item:
  * `cache_lock' must be acquired before calling this function!
@@ -1043,6 +1085,13 @@ static int daemonize (void) /* {{{ */
 {
   pid_t child;
   int status;
+  char *base_dir;
+
+  /* These structures are static, because `sigaction' behaves weird if the are
+   * overwritten.. */
+  static struct sigaction sa_int;
+  static struct sigaction sa_term;
+  static struct sigaction sa_pipe;
 
   child = fork ();
   if (child < 0)
@@ -1056,7 +1105,15 @@ static int daemonize (void) /* {{{ */
   }
 
   /* Change into the /tmp directory. */
-  chdir ("/tmp");
+  base_dir = (config_base_dir != NULL)
+    ? config_base_dir
+    : "/tmp";
+  status = chdir (base_dir);
+  if (status != 0)
+  {
+    fprintf (stderr, "daemonize: chdir (%s) failed.\n", base_dir);
+    return (-1);
+  }
 
   /* Become session leader */
   setsid ();
@@ -1070,21 +1127,18 @@ static int daemonize (void) /* {{{ */
   dup (0);
   dup (0);
 
-  {
-    struct sigaction sa;
+  /* Install signal handlers */
+  memset (&sa_int, 0, sizeof (sa_int));
+  sa_int.sa_handler = sig_int_handler;
+  sigaction (SIGINT, &sa_int, NULL);
 
-    memset (&sa, 0, sizeof (sa));
-    sa.sa_handler = sig_int_handler;
-    sigaction (SIGINT, &sa, NULL);
+  memset (&sa_term, 0, sizeof (sa_term));
+  sa_term.sa_handler = sig_term_handler;
+  sigaction (SIGINT, &sa_term, NULL);
 
-    memset (&sa, 0, sizeof (sa));
-    sa.sa_handler = sig_term_handler;
-    sigaction (SIGINT, &sa, NULL);
-
-    memset (&sa, 0, sizeof (sa));
-    sa.sa_handler = SIG_IGN;
-    sigaction (SIGPIPE, &sa, NULL);
-  }
+  memset (&sa_pipe, 0, sizeof (sa_pipe));
+  sa_pipe.sa_handler = SIG_IGN;
+  sigaction (SIGPIPE, &sa_pipe, NULL);
 
   openlog ("rrdcached", LOG_PID, LOG_DAEMON);
 
@@ -1104,6 +1158,8 @@ static int daemonize (void) /* {{{ */
     return (-1);
   }
 
+  write_pidfile ();
+
   return (0);
 } /* }}} int daemonize */
 
@@ -1118,6 +1174,8 @@ static int cleanup (void) /* {{{ */
   pthread_join (queue_thread, /* return = */ NULL);
   RRDD_LOG (LOG_DEBUG, "cleanup: done");
 
+  remove_pidfile ();
+
   closelog ();
 
   return (0);
@@ -1128,7 +1186,7 @@ static int read_options (int argc, char **argv) /* {{{ */
   int option;
   int status = 0;
 
-  while ((option = getopt(argc, argv, "l:f:w:h?")) != -1)
+  while ((option = getopt(argc, argv, "l:f:w:b:p:h?")) != -1)
   {
     switch (option)
     {
@@ -1185,6 +1243,47 @@ static int read_options (int argc, char **argv) /* {{{ */
       }
       break;
 
+      case 'b':
+      {
+        size_t len;
+
+        if (config_base_dir != NULL)
+          free (config_base_dir);
+        config_base_dir = strdup (optarg);
+        if (config_base_dir == NULL)
+        {
+          fprintf (stderr, "read_options: strdup failed.\n");
+          return (3);
+        }
+
+        len = strlen (config_base_dir);
+        while ((len > 0) && (config_base_dir[len - 1] == '/'))
+        {
+          config_base_dir[len - 1] = 0;
+          len--;
+        }
+
+        if (len < 1)
+        {
+          fprintf (stderr, "Invalid base directory: %s\n", optarg);
+          return (4);
+        }
+      }
+      break;
+
+      case 'p':
+      {
+        if (config_pid_file != NULL)
+          free (config_pid_file);
+        config_pid_file = strdup (optarg);
+        if (config_pid_file == NULL)
+        {
+          fprintf (stderr, "read_options: strdup failed.\n");
+          return (3);
+        }
+      }
+      break;
+
       case 'h':
       case '?':
         printf ("RRDd %s  Copyright (C) 2008 Florian octo Forster\n"
@@ -1195,6 +1294,8 @@ static int read_options (int argc, char **argv) /* {{{ */
             "  -l <address>  Socket address to listen to.\n"
             "  -w <seconds>  Interval in which to write data.\n"
             "  -f <seconds>  Interval in which to flush dead data.\n"
+            "  -p <file>     Location of the PID-file.\n"
+            "  -b <dir>      Base directory to change to.\n"
             "\n"
             "For more information and a detailed description of all options "
             "please refer\n"