rrdcached: Fix permissions of the default socket.
[rrdtool.git] / src / rrd_daemon.c
index bfcf6a3..1a20974 100644 (file)
@@ -71,7 +71,7 @@
 #endif
 #endif
 
-#include "rrd.h"
+#include "rrd_tool.h"
 #include "rrd_client.h"
 #include "unused.h"
 
 #include <libgen.h>
 #include <grp.h>
 
+#ifdef HAVE_LIBWRAP
+#include <tcpd.h>
+#endif /* HAVE_LIBWRAP */
+
 #include <glib-2.0/glib.h>
 /* }}} */
 
@@ -275,7 +279,7 @@ static uint64_t stats_journal_bytes = 0;
 static uint64_t stats_journal_rotate = 0;
 static pthread_mutex_t stats_lock = PTHREAD_MUTEX_INITIALIZER;
 
-static int opt_no_overwrite = 0;
+static int opt_no_overwrite = 0; /* default for the daemon */
 
 /* Journaled updates */
 #define JOURNAL_REPLAY(s) ((s) == NULL)
@@ -1701,7 +1705,7 @@ static int handle_request_info (HANDLER_PROTO) /* {{{ */
 {
   char *file, file_tmp[PATH_MAX];
   int status;
-  rrd_info_t *data;
+  rrd_info_t *info;
 
   /* obtain filename */
   status = buffer_get_field(&buffer, &buffer_size, &file);
@@ -1714,11 +1718,11 @@ static int handle_request_info (HANDLER_PROTO) /* {{{ */
   }
   /* get data */
   rrd_clear_error ();
-  data = rrd_info_r(file);
-  if(!data) {
+  info = rrd_info_r(file);
+  if(!info) {
     return send_response(sock, RESP_ERR, "RRD Error: %s\n", rrd_get_error());
   }
-  while (data) {
+  for (rrd_info_t *data = info; data != NULL; data = data->next) {
       switch (data->type) {
       case RD_I_VAL:
           if (isnan(data->value.u_val))
@@ -1739,8 +1743,10 @@ static int handle_request_info (HANDLER_PROTO) /* {{{ */
           add_response_info(sock,"%s %d %lu\n", data->key, data->type, data->value.u_blo.size);
           break;
       }
-      data = data->next;
   }
+
+  rrd_info_free(info);
+
   return send_response(sock, RESP_OK, "Info for %s follows\n",file);
 } /* }}} static int handle_request_info  */
 
@@ -1776,13 +1782,17 @@ static int handle_request_first (HANDLER_PROTO) /* {{{ */
     return send_response(sock, RESP_ERR, "RRD Error: %s\n", rrd_get_error());
   }
   return send_response(sock, RESP_OK, "%lu\n",(unsigned)t);
-} /* }}} static int handle_request_last  */
+} /* }}} static int handle_request_first  */
+
 
 static int handle_request_last (HANDLER_PROTO) /* {{{ */
 {
   char *file, file_tmp[PATH_MAX];
   int status;
-  time_t t;
+  time_t t, from_file, step;
+  rrd_file_t * rrd_file;
+  cache_item_t * ci;
+  rrd_t rrd; 
 
   /* obtain filename */
   status = buffer_get_field(&buffer, &buffer_size, &file);
@@ -1793,12 +1803,27 @@ static int handle_request_last (HANDLER_PROTO) /* {{{ */
   if (!check_file_access(file, sock)) {
     return send_response(sock, RESP_ERR, "Cannot read: %s\n", file);
   }
-  /* get data */
-  rrd_clear_error ();
-  t = rrd_last_r(file);
-  if(t<1) {
+  rrd_clear_error();
+  rrd_init(&rrd);
+  rrd_file = rrd_open(file,&rrd,RRD_READONLY);
+  if(!rrd_file) {
     return send_response(sock, RESP_ERR, "RRD Error: %s\n", rrd_get_error());
   }
+  from_file = rrd.live_head->last_up;
+  step = rrd.stat_head->pdp_step;
+  rrd_close(rrd_file);
+  pthread_mutex_lock(&cache_lock);
+  ci = g_tree_lookup(cache_tree, file);
+  if (ci)
+    t = ci->last_update_stamp;
+  else
+    t = from_file;
+  pthread_mutex_unlock(&cache_lock);
+  t -= t % step;
+  rrd_free(&rrd);
+  if(t<1) {
+    return send_response(sock, RESP_ERR, "Error: rrdcached: Invalid timestamp returned\n");
+  }
   return send_response(sock, RESP_OK, "%lu\n",(unsigned)t);
 } /* }}} static int handle_request_last  */
 
@@ -1809,10 +1834,8 @@ static int handle_request_create (HANDLER_PROTO) /* {{{ */
   int ac = 0;
   char *av[128];
   int status;
-  ulong step = 300;
+  unsigned long step = 300;
   time_t last_up = time(NULL)-10;
-  rrd_time_value_t last_up_tv;
-  char     *parsetime_error = NULL;
   int no_overwrite = opt_no_overwrite;
 
 
@@ -1827,19 +1850,11 @@ static int handle_request_create (HANDLER_PROTO) /* {{{ */
   }
   RRDD_LOG(LOG_INFO, "rrdcreate request for %s",file);
 
-  status = buffer_get_field(&buffer, &buffer_size, &tok );
-  for(;(tok && !status);status = buffer_get_field(&buffer, &buffer_size, &tok )) {
+  while ((status = buffer_get_field(&buffer, &buffer_size, &tok)) == 0 && tok) {
     if( ! strncmp(tok,"-b",2) ) {
       status = buffer_get_field(&buffer, &buffer_size, &tok );
       if (status != 0) return syntax_error(sock,cmd);
-      if ((parsetime_error = rrd_parsetime(tok, &last_up_tv))) 
-        return send_response(sock, RESP_ERR, "start time: %s\n", parsetime_error);
-      if (last_up_tv.type == RELATIVE_TO_END_TIME ||
-        last_up_tv.type == RELATIVE_TO_START_TIME) {
-        return send_response(sock, RESP_ERR, "Cannot specify time relative to start or end here.\n");
-      }
-      last_up = mktime(&last_up_tv.tm) +last_up_tv.offset;
-
+      last_up = (time_t) atol(tok);
       continue;
     }
     if( ! strncmp(tok,"-s",2) ) {
@@ -1863,9 +1878,8 @@ static int handle_request_create (HANDLER_PROTO) /* {{{ */
     return send_response(sock, RESP_ERR, "The first entry must be after 1980.\n");
   }
 
-  rrd_create_set_no_overwrite(no_overwrite);
   rrd_clear_error ();
-  status = rrd_create_r(file,step,last_up,ac,(const char **)av);
+  status = rrd_create_r2(file,step,last_up,no_overwrite,ac,(const char **)av);
 
   if(!status) {
     return send_response(sock, RESP_OK, "RRD created OK\n");
@@ -2062,6 +2076,8 @@ static command_t list_of_commands[] = { /* {{{ */
     "CREATE <filename> [-b start] [-s step] [-O] <DS definitions> <RRA definitions>\n",
     "The CREATE command will create an RRD file, overwriting any existing file\n"
     "unless the -O option is given or rrdcached was started with the -O option.\n"
+    "The start parameter needs to be in seconds since 1/1/70 (AT-style syntax is\n"
+    "not acceptable) and the step is in seconds (default is 300).\n"
     "The DS and RRA definitions are as for the 'rrdtool create' command.\n"
   },
   {
@@ -2152,6 +2168,15 @@ static void socket_permission_copy (listen_socket_t *dest, /* {{{ */
   dest->permissions = src->permissions;
 } /* }}} socket_permission_copy */
 
+static void socket_permission_set_all (listen_socket_t *sock) /* {{{ */
+{
+  size_t i;
+
+  sock->permissions = 0;
+  for (i = 0; i < list_of_commands_len; i++)
+    sock->permissions |= (1 << i);
+} /* }}} void socket_permission_set_all */
+
 /* check whether commands are received in the expected context */
 static int command_check_context(listen_socket_t *sock, command_t *cmd)
 {
@@ -2624,6 +2649,21 @@ static void *connection_thread_main (void *args) /* {{{ */
   }
 
   pthread_mutex_lock (&connection_threads_lock);
+#ifdef HAVE_LIBWRAP
+  /* LIBWRAP does not support multiple threads! By putting this code
+     inside pthread_mutex_lock we do not have to worry about request_info
+     getting overwritten by another thread.
+  */
+  struct request_info req;
+  request_init(&req, RQ_DAEMON, "rrdcache\0", RQ_FILE, fd, NULL );
+  fromhost(&req);
+  if(!hosts_access(&req)) {
+    RRDD_LOG(LOG_INFO, "refused connection from %s", eval_client(&req));
+    pthread_mutex_unlock (&connection_threads_lock);
+    close_connection(sock);
+    return NULL;
+  }
+#endif /* HAVE_LIBWRAP */
   connection_threads_num++;
   pthread_mutex_unlock (&connection_threads_lock);
 
@@ -3100,6 +3140,10 @@ static int daemonize (void) /* {{{ */
     strncpy(default_socket.addr, RRDCACHED_DEFAULT_ADDRESS,
         sizeof(default_socket.addr) - 1);
     default_socket.addr[sizeof(default_socket.addr) - 1] = '\0';
+
+    if (default_socket.permissions == 0)
+      socket_permission_set_all (&default_socket);
+
     open_listen_socket (&default_socket);
   }
 
@@ -3244,18 +3288,7 @@ static int read_options (int argc, char **argv) /* {{{ */
         else /* if (default_socket.permissions == 0) */
         {
           /* Add permission for ALL commands to the socket. */
-          size_t i;
-          for (i = 0; i < list_of_commands_len; i++)
-          {
-            status = socket_permission_add (new, list_of_commands[i].cmd);
-            if (status != 0)
-            {
-              fprintf (stderr, "read_options: Adding permission \"%s\" to "
-                  "socket failed. This should never happen, ever! Sorry.\n",
-                  list_of_commands[i].cmd);
-              status = 4;
-            }
-          }
+          socket_permission_set_all (new);
         }
         /* }}} Done adding permissions. */
 
@@ -3542,6 +3575,7 @@ static int read_options (int argc, char **argv) /* {{{ */
             "\n"
             "Valid options are:\n"
             "  -l <address>  Socket address to listen to.\n"
+            "                Default: "RRDCACHED_DEFAULT_ADDRESS"\n"
             "  -P <perms>    Sets the permissions to assign to all following "
                             "sockets\n"
             "  -w <seconds>  Interval in which to write data.\n"