]> git.ipfire.org Git - thirdparty/rrdtool-1.x.git/commitdiff
rrd_daemon: Add LIST command to list the rrd databases
authorSebastien Dugue <sebastien.dugue@bull.net>
Tue, 28 Oct 2014 14:37:03 +0000 (15:37 +0100)
committerMarek Schimara <Marek.Schimara@bull.net>
Wed, 24 Aug 2016 11:51:26 +0000 (13:51 +0200)
src/Makefile.am
src/librrd.sym
src/rrd.h
src/rrd_client.c
src/rrd_client.h
src/rrd_daemon.c
src/rrd_list.c [new file with mode: 0644]
src/rrd_tool.c
win32/librrd-4.def

index 9c60f42f4c063273dd9421aa99139fb2c2936404..100eed737256b04d8ebeca4db984964603131f04 100644 (file)
@@ -51,7 +51,9 @@ RRD_C_FILES =         \
        rrd_fetch.c     \
        rrd_fetch_cb.c  \
        rrd_resize.c \
-       rrd_tune.c
+       rrd_tune.c      \
+       rrd_list.c
+
 
 if BUILD_RRDGRAPH
 RRD_C_FILES += rrd_graph.c     \
index 3f304b7c398fc7bf05b19248866e5106d99e0491..17bb693c1ea8f97fcadd16b665b1ace85684aedb 100644 (file)
@@ -36,6 +36,8 @@ rrd_last
 rrd_last_r
 rrd_lastupdate
 rrd_lastupdate_r
+rrd_list
+rrd_list_r
 rrd_lock
 rrd_mkdir_p
 rrd_new_context
index 6ea20099dce1a85be799d01b94f5cfdb4ad49640..1b54377006fced0ee78e03a1b973743182830ec7 100644 (file)
--- a/src/rrd.h
+++ b/src/rrd.h
@@ -165,6 +165,7 @@ struct rrd_t;
     rrd_info_t * data);
     void      rrd_info_free(
     rrd_info_t *);
+    char      *rrd_list(int, char **);
     int       rrd_update(
     int,
     char **);
index b6ee4b117c0302c5ed74d41dd5433ee286b3a7c2..9cf82d6510183615063545e730c85c30757669eb 100644 (file)
@@ -1015,6 +1015,44 @@ int rrdc_forget (const char *filename) {
   return rrdc_filebased_command("forget", filename);
 }
 
+int rrdc_flushall (void) /* {{{ */
+{
+  char buffer[RRD_CMD_MAX];
+  char *buffer_ptr;
+  size_t buffer_free;
+  size_t buffer_size;
+  rrdc_response_t *res;
+  int status;
+
+  memset (buffer, 0, sizeof (buffer));
+  buffer_ptr = &buffer[0];
+  buffer_free = sizeof (buffer);
+
+  status = buffer_add_string ("flushall", &buffer_ptr, &buffer_free);
+
+  if (status != 0)
+    return (ENOBUFS);
+
+  pthread_mutex_lock (&lock);
+
+  assert (buffer_free < sizeof (buffer));
+  buffer_size = sizeof (buffer) - buffer_free;
+  assert (buffer[buffer_size - 1] == ' ');
+  buffer[buffer_size - 1] = '\n';
+
+  res = NULL;
+  status = request (buffer, buffer_size, &res);
+  pthread_mutex_unlock (&lock);
+
+  if (status != 0)
+    return (status);
+
+  status = res->status;
+  response_free (res);
+
+  return (status);
+} /* }}} int rrdc_flushall */
+
 rrd_info_t * rrdc_info (const char *filename) /* {{{ */
 {
   char buffer[RRD_CMD_MAX];
@@ -1126,6 +1164,106 @@ rrd_info_t * rrdc_info (const char *filename) /* {{{ */
   return (data);
 } /* }}} int rrdc_info */
 
+char *rrdc_list(const char *dirname)
+{
+  char buffer[RRD_CMD_MAX];
+  char *buffer_ptr;
+  size_t buffer_free;
+  size_t buffer_size;
+  rrdc_response_t *res;
+  int status;
+  unsigned int i;
+  char *list = NULL;
+  int list_len = 0;
+
+  if (dirname == NULL) {
+    rrd_set_error ("rrdc_info: no directory name");
+    return (NULL);
+  }
+
+  memset (buffer, 0, sizeof (buffer));
+  buffer_ptr = &buffer[0];
+  buffer_free = sizeof (buffer);
+
+  status = buffer_add_string ("list", &buffer_ptr, &buffer_free);
+
+  if (status != 0) {
+    rrd_set_error ("rrdc_list: out of memory");
+    return NULL;
+  }
+
+  status = buffer_add_string (dirname, &buffer_ptr, &buffer_free);
+  if (status != 0)
+  {
+    rrd_set_error ("rrdc_list: out of memory");
+    return (NULL);
+  }
+
+
+  assert (buffer_free < sizeof (buffer));
+  buffer_size = sizeof (buffer) - buffer_free;
+  assert (buffer[buffer_size - 1] == ' ');
+  buffer[buffer_size - 1] = '\n';
+
+  res = NULL;
+
+  pthread_mutex_lock (&lock);
+  status = request (buffer, buffer_size, &res);
+  pthread_mutex_unlock (&lock);
+
+  if (status != 0) {
+    rrd_set_error ("rrdcached: %s", res->message);
+    goto out_free_res;
+  }
+
+  /* Handle the case where the list is empty, allocate
+   * a single byte zeroed string.
+   */
+  if (res->lines_num == 0) {
+    list = calloc(1, 1);
+
+    if (!list) {
+      rrd_set_error ("rrdc_list: out of memory");
+      goto out_free_res;
+    }
+
+    goto out_free_res;
+  }
+
+  for (i = 0; i < res->lines_num ; i++ ) {
+    int len;
+    char *buf;
+
+    len = strlen(res->lines[i]);
+    buf = realloc(list, list_len + len + 2);
+
+    if (!buf) {
+      rrd_set_error ("rrdc_list: out of memory");
+
+      if (list) {
+       free(list);
+       list = NULL;
+      }
+
+      goto out_free_res;
+    }
+
+    if (!list)
+      buf[0] = '\0';
+
+    strcat(buf, res->lines[i]);
+    strcat(buf, "\n");
+
+    list = buf;
+    list_len += (len + 1);
+  }
+
+out_free_res:
+  response_free (res);
+
+  return list;
+}
+
 time_t rrdc_last (const char *filename) /* {{{ */
 {
   char buffer[RRD_CMD_MAX];
@@ -1633,6 +1771,36 @@ int rrdc_flush_if_daemon (const char *opt_daemon, const char *filename) /* {{{ *
   return status;
 } /* }}} int rrdc_flush_if_daemon */
 
+/* convenience function; if there is a daemon specified, or if we can
+ * detect one from the environment, then flush the file.  Otherwise, no-op
+ */
+int rrdc_flushall_if_daemon (const char *opt_daemon) /* {{{ */
+{
+  int status = 0;
+
+  rrdc_connect(opt_daemon);
+
+  if (rrdc_is_connected(opt_daemon))
+  {
+    rrd_clear_error();
+    status = rrdc_flushall ();
+
+    if (status != 0 && !rrd_test_error())
+    {
+      if (status > 0)
+      {
+        rrd_set_error("rrdc_flushall failed: %s", rrd_strerror(status));
+      }
+      else if (status < 0)
+      {
+        rrd_set_error("rrdc_flushall failed with status %i.", status);
+      }
+    }
+  } /* if (rrdc_is_connected(..)) */
+
+  return status;
+} /* }}} int rrdc_flush_if_daemon */
+
 
 int rrdc_stats_get (rrdc_stats_t **ret_stats) /* {{{ */
 {
index 28ab584174a49ecbfdff3edb71ac4a88fab87f04..470a7e79bdfce2d93d5a13602c397d759749454f 100644 (file)
@@ -51,6 +51,7 @@ int rrdc_update (const char *filename, int values_num,
     const char * const *values);
 
 rrd_info_t * rrdc_info (const char *filename);
+char *rrdc_list(const char *dirname);
 time_t rrdc_last (const char *filename);
 time_t rrdc_first (const char *filename, int rraindex);
 int rrdc_create (const char *filename,
@@ -72,6 +73,8 @@ int rrdc_create_r2 (const char *filename,
 int rrdc_flush (const char *filename);
 int rrdc_forget (const char *filename);
 int rrdc_flush_if_daemon (const char *opt_daemon, const char *filename);
+int rrdc_flushall (void);
+int rrdc_flushall_if_daemon (const char *opt_daemon);
 
 int rrdc_fetch (const char *filename,
     const char *cf,
index 4ceddfcc6107cbfd723701212c5c0bd71a1bc3c1..3bae3fba3c2a1e888a6a211cf63911a067a60048 100644 (file)
 #include <libgen.h>
 #include <grp.h>
 #include <pwd.h>
+#include <glob.h>
 
 #ifdef HAVE_LIBWRAP
 #include <tcpd.h>
@@ -1229,7 +1230,7 @@ static int check_file_access (const char *file, listen_socket_t *sock) /* {{{ */
   if (*file != '/') return 1;
 
   /* file must be of the format base + "/" + <1+ char filename> */
-  if (strlen(file) < _config_base_dir_len + 2) return 0;
+  if (strlen(file) < _config_base_dir_len + 1) return 0;
   if (strncmp(file, config_base_dir, _config_base_dir_len) != 0) return 0;
   if (*(file + _config_base_dir_len) != '/') return 0;
 
@@ -2385,6 +2386,103 @@ done:
   return rc;
 } /* }}} static int handle_request_create  */
 
+static int handle_request_list (HANDLER_PROTO) /* {{{ */
+{
+  char *filename;
+  char fullpath[PATH_MAX];
+  int status;
+  DIR *dir;
+  struct dirent *entry;
+
+  if (config_base_dir == NULL) {
+    return send_response(sock, RESP_ERR, "No base directory defined\n");
+  }
+
+  /* Get pathname */
+  status = buffer_get_field(&buffer, &buffer_size, &filename);
+
+  if (status != 0)
+    return syntax_error(sock,cmd);
+
+  /* get full pathname */
+  snprintf(fullpath, PATH_MAX, "%s%s%s",
+          config_base_dir, (filename[0] == '/') ? "" : "/", filename);
+
+  /* Prevent moving up the directory tree */
+  if (strstr(fullpath, ".."))
+      send_response(sock, RESP_ERR, "%s\n", rrd_strerror(EACCES));
+
+  /* if filename contains wildcards, then use glob() */
+  if (strchr(fullpath, '*') || strchr(fullpath, '?')) {
+    glob_t buf;
+    unsigned int i;
+
+    if (glob(fullpath, 0, NULL, &buf)) {
+      globfree(&buf);
+      goto out_send_response;
+    }
+
+    for (i = 0; i < buf.gl_pathc; i++) {
+      char *ptr;
+
+      if (!check_file_access(buf.gl_pathv[i], sock))
+       return send_response(sock, RESP_ERR,
+                            "Cannot read: %s\n", buf.gl_pathv[i]);
+
+      ptr = strrchr(buf.gl_pathv[i], '/');
+
+      if (ptr != NULL)
+       add_response_info(sock, "%s\n", ptr + 1);
+    }
+
+    globfree(&buf);
+    goto out_send_response;
+  }
+
+  if (!check_file_access(fullpath, sock))
+    return send_response(sock, RESP_ERR, "Cannot read: %s\n", fullpath);
+
+  /* If filename matches an RRD file, then return it */
+  if (strstr(fullpath, ".rrd")) {
+         struct stat st;
+         char *ptr;
+
+         if (!stat(fullpath, &st) && S_ISREG(st.st_mode)) {
+                 ptr = strrchr(fullpath, '/');
+
+                 if (ptr)
+                         add_response_info(sock, "%s\n", ptr + 1);
+         }
+
+         goto out_send_response;
+  }
+
+  dir = opendir(fullpath);
+
+  if (dir == NULL) {
+    return send_response(sock, RESP_ERR,
+                        "Failed to open directory %s : %s\n",
+                        fullpath, strerror(errno));
+  }
+
+  while ((entry = readdir(dir)) != NULL) {
+
+    if ((strcmp(entry->d_name, ".") == 0) ||
+       (strcmp(entry->d_name, "..") == 0)) {
+      continue;
+    }
+
+    add_response_info(sock, "%s\n", entry->d_name);
+  }
+  closedir(dir);
+
+out_send_response:
+  send_response(sock, RESP_OK, "RRDs\n");
+
+  return (0);
+} /* }}} int handle_request_list */
+
+
 /* start "BATCH" processing */
 static int batch_start (HANDLER_PROTO) /* {{{ */
 {
@@ -2594,6 +2692,16 @@ static command_t list_of_commands[] = { /* {{{ */
     "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"
   },
+  {
+    "LIST",
+    handle_request_list,
+    CMD_CONTEXT_CLIENT,
+    "LIST\n",
+    "This command lists the RRD files in the storage base directory.\n"
+    "Note that this is the list of RRD files on storage as of the last update.\n"
+    "There may be pending updates in the queue, so a FLUSH may have to be run\n"
+    "beforehand.\n"
+  },
   {
     "QUIT",
     handle_request_quit,
diff --git a/src/rrd_list.c b/src/rrd_list.c
new file mode 100644 (file)
index 0000000..bb58365
--- /dev/null
@@ -0,0 +1,120 @@
+
+#include <stdio.h>
+
+#include "rrd_tool.h"
+#include "rrd_client.h"
+
+char *rrd_list_r(char *dirname);
+char *rrd_list(int argc, char **argv);
+
+char *rrd_list_r(char *dirname)
+{
+       printf("rrd_list_r not implemented yet\n");
+       return NULL;
+}
+
+char *rrd_list(int argc, char **argv)
+{
+       char *opt_daemon = NULL;
+       int status;
+       int flushfirst = 1;
+       char *list;
+
+       static struct optparse_long long_options[] = {
+               {"daemon", 'd', OPTPARSE_REQUIRED},
+               {"noflush", 'F', OPTPARSE_NONE},
+               {0},
+       };
+       struct optparse options;
+       int    opt;
+       char    *err = NULL;
+
+        optparse_init(&options, argc, argv);
+
+        while ((opt = optparse_long(&options, long_options, NULL)) != -1) {
+
+               switch (opt) {
+               case 'd':
+                       if (opt_daemon != NULL) {
+                               free (opt_daemon);
+                       }
+                       opt_daemon = strdup (optarg);
+                       if (opt_daemon == NULL)
+                       {
+                               rrd_set_error ("strdup failed.");
+                               return NULL;
+                       }
+                       break;
+
+               case 'F':
+                       flushfirst = 0;
+                       break;
+
+
+                case '?':
+                        if (opt_daemon)
+                               free(opt_daemon);
+                        rrd_set_error("%s", options.errmsg);
+                        return NULL;
+                        break;
+
+               default:
+                       rrd_set_error ("Usage: rrdtool %s [--daemon <addr> [--noflush]] <file>",
+                                      argv[0]);
+                       if (opt_daemon != NULL) {
+                               free (opt_daemon);
+                       }
+
+                       return NULL;
+                       break;
+               }
+
+       }
+
+       if ((argc - optind) != 1) {
+               rrd_set_error ("Usage: rrdtool %s [--daemon <addr> [--noflush]] <directory>",
+                argv[0]);
+
+               if (opt_daemon != NULL) {
+                       free (opt_daemon);
+               }
+
+               return NULL;
+       }
+
+       if( flushfirst ) {
+               status = rrdc_flushall_if_daemon(opt_daemon);
+
+               if (status) {
+                       if (opt_daemon != NULL) {
+                               free (opt_daemon);
+                       }
+
+                       return NULL;
+               }
+       }
+
+       rrdc_connect (opt_daemon);
+
+       if (rrdc_is_connected (opt_daemon)) {
+               list = rrdc_list(argv[optind]);
+               rrdc_disconnect();
+
+       } else {
+               if (opt_daemon) {
+                       fprintf(stderr, "Error connecting to rrdcached");
+                       err = rrd_get_error();
+
+                       if (err)
+                               fprintf(stderr, ": %s", err);
+                       fprintf(stderr, "\n");
+               }
+               list = rrd_list_r(argv[optind]);
+       }
+
+       if (opt_daemon != NULL) {
+               free(opt_daemon);
+       }
+
+       return list;
+}
index 432db7b4d995200a2cc126b20f6140e013123e45..63855a10997124981be27cd9327379e1db3c793d 100644 (file)
@@ -53,7 +53,7 @@ void PrintUsage(
     const char *help_list =
         N_
         ("Valid commands: create, update, updatev, graph, graphv,  dump, restore,\n"
-         "\t\tlast, lastupdate, first, info, fetch, tune\n"
+         "\t\tlast, lastupdate, first, info, list, fetch, tune,\n"
          "\t\tresize, xport, flushcached\n");
 
     const char *help_listremote =
@@ -82,6 +82,10 @@ void PrintUsage(
         N_("* info - returns the configuration and status of the RRD\n\n"
            "\trrdtool info [--daemon|-d <addr> [--noflush|-F]] filename.rrd\n");
 
+    const char *help_listrrds =
+        N_("* list - returns the list of RRDs\n\n"
+           "\trrdtool list [--daemon <address>] [--noflush] <dirname>\n");
+
     const char *help_restore =
         N_("* restore - restore an RRD file from its XML form\n\n"
            "\trrdtool restore [--range-check|-r] [--force-overwrite|-f] filename.xml filename.rrd\n");
@@ -252,7 +256,7 @@ void PrintUsage(
         N_("RRDtool is distributed under the Terms of the GNU General\n"
            "Public License Version 2. (www.gnu.org/copyleft/gpl.html)\n\n"
            "For more information read the RRD manpages\n");
-    enum { C_NONE, C_CREATE, C_DUMP, C_INFO, C_RESTORE, C_LAST,
+    enum { C_NONE, C_CREATE, C_DUMP, C_INFO, C_LIST, C_RESTORE, C_LAST,
         C_LASTUPDATE, C_FIRST, C_UPDATE, C_FETCH, C_GRAPH, C_GRAPHV,
         C_TUNE,
         C_RESIZE, C_XPORT, C_QUIT, C_LS, C_CD, C_MKDIR, C_PWD,
@@ -267,6 +271,8 @@ void PrintUsage(
             help_cmd = C_DUMP;
         else if (!strcmp(cmd, "info"))
             help_cmd = C_INFO;
+        else if (!strcmp(cmd, "list"))
+            help_cmd = C_LIST;
         else if (!strcmp(cmd, "restore"))
             help_cmd = C_RESTORE;
         else if (!strcmp(cmd, "last"))
@@ -322,6 +328,9 @@ void PrintUsage(
     case C_INFO:
         puts(_(help_info));
         break;
+    case C_LIST:
+        puts(_(help_listrrds));
+        break;
     case C_RESTORE:
         puts(_(help_restore));
         break;
@@ -682,7 +691,15 @@ int HandleInputLine(
         rrd_info_print(data);
         rrd_info_free(data);
     }
-
+    else if (strcmp("list", argv[1]) == 0) {
+        char *list;
+        list = rrd_list(argc - 1, &argv[1]);
+
+       if (list) {
+         printf("%s", list);
+         free(list);
+       }
+    }
     else if (strcmp("--version", argv[1]) == 0 ||
              strcmp("version", argv[1]) == 0 ||
              strcmp("v", argv[1]) == 0 ||
index 94392e6d95a026b6bc65d99c7c0d726e4529036a..5856f2a1d1ffd68f45c9b5ad37b55eeca6d0e23b 100644 (file)
@@ -16,6 +16,7 @@ rrd_first
 rrd_first_r
 rrd_flush
 rrd_flushcached
+rrd_flushall
 rrd_free
 rrd_free_context
 rrd_freemem
@@ -29,6 +30,8 @@ rrd_info_free
 rrd_info_print
 rrd_info_push
 rrd_info_r
+rrd_list
+rrd_list_r
 rrd_init
 rrd_last
 rrd_last_r
@@ -63,6 +66,7 @@ rrdc_connect
 rrdc_is_connected
 rrdc_disconnect
 rrdc_flush
+rrdc_flushall
 rrdc_stats_free
 rrdc_stats_get
 rrdc_update