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 \
rrd_last_r
rrd_lastupdate
rrd_lastupdate_r
+rrd_list
+rrd_list_r
rrd_lock
rrd_mkdir_p
rrd_new_context
rrd_info_t * data);
void rrd_info_free(
rrd_info_t *);
+ char *rrd_list(int, char **);
int rrd_update(
int,
char **);
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];
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];
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) /* {{{ */
{
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,
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,
#include <libgen.h>
#include <grp.h>
#include <pwd.h>
+#include <glob.h>
#ifdef HAVE_LIBWRAP
#include <tcpd.h>
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;
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) /* {{{ */
{
"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,
--- /dev/null
+
+#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;
+}
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 =
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");
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,
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"))
case C_INFO:
puts(_(help_info));
break;
+ case C_LIST:
+ puts(_(help_listrrds));
+ break;
case C_RESTORE:
puts(_(help_restore));
break;
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 ||
rrd_first_r
rrd_flush
rrd_flushcached
+rrd_flushall
rrd_free
rrd_free_context
rrd_freemem
rrd_info_print
rrd_info_push
rrd_info_r
+rrd_list
+rrd_list_r
rrd_init
rrd_last
rrd_last_r
rrdc_is_connected
rrdc_disconnect
rrdc_flush
+rrdc_flushall
rrdc_stats_free
rrdc_stats_get
rrdc_update