use _NL_TIME_WEEK_1STDAY to determin the first day of the week.
[rrdtool.git] / src / rrd_daemon.c
index 710fa01..4c84f19 100644 (file)
 #include <assert.h>
 #include <sys/time.h>
 #include <time.h>
+#include <libgen.h>
 
 #include <glib-2.0/glib.h>
 /* }}} */
@@ -264,6 +265,7 @@ static uint64_t stats_journal_rotate = 0;
 static pthread_mutex_t stats_lock = PTHREAD_MUTEX_INITIALIZER;
 
 /* Journaled updates */
+#define JOURNAL_REPLAY(s) ((s) == NULL)
 #define JOURNAL_BASE "rrd.journal"
 static journal_set *journal_cur = NULL;
 static journal_set *journal_old = NULL;
@@ -348,12 +350,32 @@ static void install_signal_handlers(void) /* {{{ */
 static int open_pidfile(char *action, int oflag) /* {{{ */
 {
   int fd;
-  char *file;
+  const char *file;
+  char *file_copy, *dir;
 
   file = (config_pid_file != NULL)
     ? config_pid_file
     : LOCALSTATEDIR "/run/rrdcached.pid";
 
+  /* dirname may modify its argument */
+  file_copy = strdup(file);
+  if (file_copy == NULL)
+  {
+    fprintf(stderr, "rrdcached: strdup(): %s\n",
+        rrd_strerror(errno));
+    return -1;
+  }
+
+  dir = dirname(file_copy);
+  if (rrd_mkdir_p(dir, 0777) != 0)
+  {
+    fprintf(stderr, "Failed to create pidfile directory '%s': %s\n",
+        dir, rrd_strerror(errno));
+    return -1;
+  }
+
+  free(file_copy);
+
   fd = open(file, oflag, S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH);
   if (fd < 0)
     fprintf(stderr, "rrdcached: can't %s pid file '%s' (%s)\n",
@@ -507,7 +529,7 @@ static int add_response_info(listen_socket_t *sock, char *fmt, ...) /* {{{ */
   char buffer[CMD_MAX];
   int len;
 
-  if (sock == NULL) return 0; /* journal replay mode */
+  if (JOURNAL_REPLAY(sock)) return 0;
   if (sock->batch_start) return 0; /* no extra info returned when in BATCH */
 
   va_start(argp, fmt);
@@ -554,7 +576,7 @@ static int send_response (listen_socket_t *sock, response_code rc,
   ssize_t wrote;
   int rclen, len;
 
-  if (sock == NULL) return rc;  /* journal replay mode */
+  if (JOURNAL_REPLAY(sock)) return rc;
 
   if (sock->batch_start)
   {
@@ -1022,7 +1044,7 @@ static int check_file_access (const char *file, listen_socket_t *sock) /* {{{ */
   assert(file != NULL);
 
   if (!config_write_base_only
-      || sock == NULL /* journal replay */
+      || JOURNAL_REPLAY(sock)
       || config_base_dir == NULL)
     return 1;
 
@@ -1251,7 +1273,7 @@ static int handle_request_forget(HANDLER_PROTO) /* {{{ */
 
   if (found == TRUE)
   {
-    if (sock != NULL)
+    if (!JOURNAL_REPLAY(sock))
       journal_write("forget", file);
 
     return send_response(sock, RESP_OK, "Gone!\n");
@@ -1291,7 +1313,8 @@ static int handle_request_update (HANDLER_PROTO) /* {{{ */
   cache_item_t *ci;
 
   /* save it for the journal later */
-  strncpy(orig_buf, buffer, sizeof(orig_buf)-1);
+  if (!JOURNAL_REPLAY(sock))
+    strncpy(orig_buf, buffer, buffer_size);
 
   status = buffer_get_field (&buffer, &buffer_size, &file);
   if (status != 0)
@@ -1376,7 +1399,7 @@ static int handle_request_update (HANDLER_PROTO) /* {{{ */
   assert (ci != NULL);
 
   /* don't re-write updates in replay mode */
-  if (sock != NULL)
+  if (!JOURNAL_REPLAY(sock))
     journal_write("update", orig_buf);
 
   while (buffer_size > 0)
@@ -1652,6 +1675,9 @@ static int socket_permission_check (listen_socket_t *sock, /* {{{ */
 {
   ssize_t i;
 
+  if (JOURNAL_REPLAY(sock))
+    return (1);
+
   if (cmd == NULL)
     return (-1);
 
@@ -1688,7 +1714,7 @@ static int socket_permission_add (listen_socket_t *sock, /* {{{ */
 /* check whether commands are received in the expected context */
 static int command_check_context(listen_socket_t *sock, command_t *cmd)
 {
-  if (sock == NULL)
+  if (JOURNAL_REPLAY(sock))
     return (cmd->context & CMD_CONTEXT_JOURNAL);
   else if (sock->batch_start)
     return (cmd->context & CMD_CONTEXT_BATCH);
@@ -1740,7 +1766,6 @@ static int handle_request_help (HANDLER_PROTO) /* {{{ */
   return send_response(sock, RESP_OK, resp_txt);
 } /* }}} int handle_request_help */
 
-/* if sock==NULL, we are in journal replay mode */
 static int handle_request (DISPATCH_PROTO) /* {{{ */
 {
   char *buffer_ptr = buffer;
@@ -2239,11 +2264,31 @@ static int open_listen_socket_unix (const listen_socket_t *sock) /* {{{ */
   listen_socket_t *temp;
   int status;
   const char *path;
+  char *path_copy, *dir;
 
   path = sock->addr;
   if (strncmp(path, "unix:", strlen("unix:")) == 0)
     path += strlen("unix:");
 
+  /* dirname may modify its argument */
+  path_copy = strdup(path);
+  if (path_copy == NULL)
+  {
+    fprintf(stderr, "rrdcached: strdup(): %s\n",
+        rrd_strerror(errno));
+    return (-1);
+  }
+
+  dir = dirname(path_copy);
+  if (rrd_mkdir_p(dir, 0777) != 0)
+  {
+    fprintf(stderr, "Failed to create socket directory '%s': %s\n",
+        dir, rrd_strerror(errno));
+    return (-1);
+  }
+
+  free(path_copy);
+
   temp = (listen_socket_t *) rrd_realloc (listen_fds,
       sizeof (listen_fds[0]) * (listen_fds_num + 1));
   if (temp == NULL)
@@ -2346,8 +2391,8 @@ static int open_listen_socket_network(const listen_socket_t *sock) /* {{{ */
       fprintf (stderr, "rrdcached: Garbage after address: %s\n", port);
       return (-1);
     }
-  } /* if (*addr = ']') */
-  else if (strchr (addr, '.') != NULL) /* Hostname or IPv4 */
+  } /* if (*addr == '[') */
+  else
   {
     port = rindex(addr, ':');
     if (port != NULL)
@@ -2866,6 +2911,13 @@ static int read_options (int argc, char **argv) /* {{{ */
           return (3);
         }
 
+        if (rrd_mkdir_p (config_base_dir, 0777) != 0)
+        {
+          fprintf (stderr, "Failed to create base directory '%s': %s\n",
+              config_base_dir, rrd_strerror (errno));
+          return (3);
+        }
+
         /* make sure that the base directory is not resolved via
          * symbolic links.  this makes some performance-enhancing
          * assumptions possible (we don't have to resolve paths
@@ -2873,17 +2925,8 @@ static int read_options (int argc, char **argv) /* {{{ */
          */
         if (realpath(config_base_dir, base_realpath) == NULL)
         {
-          fprintf (stderr, "Invalid base directory '%s'.\n", config_base_dir);
-          return 5;
-        }
-        else if (strncmp(config_base_dir,
-                         base_realpath, sizeof(base_realpath)) != 0)
-        {
-          fprintf(stderr,
-                  "Base directory (-b) resolved via file system links!\n"
-                  "Please consult rrdcached '-b' documentation!\n"
-                  "Consider specifying the real directory (%s)\n",
-                  base_realpath);
+          fprintf (stderr, "Failed to canonicalize the base directory '%s': "
+              "%s\n", config_base_dir, rrd_strerror(errno));
           return 5;
         }
 
@@ -2901,6 +2944,24 @@ static int read_options (int argc, char **argv) /* {{{ */
         }
 
         _config_base_dir_len = len;
+
+        len = strlen (base_realpath);
+        while ((len > 0) && (base_realpath[len - 1] == '/'))
+        {
+          base_realpath[len - 1] = '\0';
+          len--;
+        }
+
+        if (strncmp(config_base_dir,
+                         base_realpath, sizeof(base_realpath)) != 0)
+        {
+          fprintf(stderr,
+                  "Base directory (-b) resolved via file system links!\n"
+                  "Please consult rrdcached '-b' documentation!\n"
+                  "Consider specifying the real directory (%s)\n",
+                  base_realpath);
+          return 5;
+        }
       }
       break;