* New FETCH command allowing rrd_fetch to operate through the daemon and
thus work remotely. By Florian Forster
+* New rrd_client commands INFO, FIRST, LAST, CREATE by Steve Shipway
API
---
[-g]
[B<-b>E<nbsp>I<base_dir>E<nbsp>[B<-B>]]
[B<-a>E<nbsp>I<alloc_size>]
+[-O]
=head1 DESCRIPTION
Do not set this more than the B<-w> value divided by your average RRD step
size.
+=item B<-O>
+
+Preven the CREATE command from overwriting existing files, even when it is
+instructed to do so. This is for added security.
+
=back
=head1 AFFECTED RRDTOOL COMMANDS
=item *
+first
+
+=item *
+
last
=item *
xport
+=item *
+
+create
+
=back
The B<update> command can send values to the daemon instead of writing them to
updates have already been applied. It is I<only> valid in the journal; it
is not accepted from the other command channels.
+=item B<FIRST> I<filename> [I<rranum>]
+
+Return the timestamp for the first CDP in the specified RRA. Default is to
+use RRA zero if none is specified.
+
+=item B<LAST> I<filename>
+
+Return the timestamp for the last update to the specified RRD. Note that the
+cache is I<not> flushed before checking, as the client is expected to request
+this separately if it is required.
+
+=item B<INFO> I<filename>
+
+Return the configuration information for the specified RRD. Note that the
+cache is I<not> flushed before checking, as the client is expected to request
+this separately if it is required.
+
+The information is returned, one item per line, with the format:
+
+ I<keyname> I<type> I<value>
+
+=item B<CREATE> I<filename> [-s I<stepsize>] [-b I<begintime>] [-O] I<DSdefinitions> ... I<RRAdefinitions> ...
+
+This will create the RRD file according to the supplied parameters, provided
+the parameters are valid, and (if the -O option is given or if the rrdcached
+was started with the -O flag) the specified I<filename> does not already
+exist.
+
=item B<BATCH>
This command initiates the bulk load of multiple commands. This is
=head1 CONTRIBUTORS
kevin brintnall E<lt>kbrint@rufus.netE<gt>
+Steve Shipway E<lt>steve@steveshipway.orgE<gt>
=cut
S<[B<--start>|B<-b> I<start time>]>
S<[B<--step>|B<-s> I<step>]>
S<[B<--no-overwrite>]>
+S<[B<--daemon> I<address>]>
S<[B<DS:>I<ds-name>B<:>I<DST>B<:>I<dst arguments>]>
S<[B<RRA:>I<CF>B<:>I<cf arguments>]>
Do not clobber an existing file of the same name.
+=item B<--daemon> I<address>
+
+Address of the L<rrdcached> daemon. For a list of accepted formats, see
+the B<-l> option in the L<rrdcached> manual.
+
+ rrdtool create --daemon unix:/var/run/rrdcached.sock /var/lib/rrd/foo.rrd I<other options>
+
=head2 B<DS:>I<ds-name>B<:>I<DST>B<:>I<dst arguments>
A single B<RRD> can accept input from several data sources (B<DS>),
=head1 SYNOPSIS
-B<rrdtool> B<first> I<filename> [I<--rraindex number>]
+B<rrdtool> B<first> I<filename> [I<--rraindex number>] [B<--daemon> I<address>]
=head1 DESCRIPTION
index defaults to zero. B<RRA> index numbers can be determined through
B<rrdtool info>.
+=item B<--daemon> I<address>
+
+Address of the L<rrdcached> daemon. For a list of accepted formats, see
+the B<-l> option in the L<rrdcached> manual.
+
+ rrdtool first --daemon unix:/var/run/rrdcached.sock /var/lib/rrd/foo.rrd
+
=back
=head1 AUTHOR
Burton Strauss <Burton@ntopSupport.com>
-
+Daemon support added by Steve Shipway <steve@steveshipway.org>
rrdtool info --daemon unix:/var/run/rrdcached.sock /var/lib/rrd/foo.rrd
+=item B<--noflush>
+
+Omit the C<flush> command usually sent to the daemon prior to retrieving the
+data. If all you are interested in the the RRD Structure, and not the last update
+time or current values, then this will improve efficiency.
+
=back
=head1 EXAMPLE
rrdtool last --daemon unix:/var/run/rrdcached.sock /var/lib/rrd/foo.rrd
+=item B<--noflush>
+
+If the L<rrdcached> daemon is being used, then omit the flush normally
+send before returning the last update. If you add this option, you get the
+last time the file on disk was updated; if you have relatively low cache times
+and are calling this frequently it will preserve the caching benefit
+
=back
=head1 ENVIRONMENT VARIABLES
=head1 AUTHOR
Russ Wright <rwwright@home.com>
-
+Daemon support added by Steve Shipway <steve@steveshipway.org>
rrd_close
rrd_create
rrd_create_r
+rrd_create_set_no_overwrite
rrd_dontneed
rrd_dump
rrd_dump_r
int rrd_create(
int,
char **);
+ void rrd_create_set_no_overwrite(
+ int);
rrd_info_t *rrd_info(
int,
char **);
return (buffer_add_string (temp, buffer_ret, buffer_size_ret));
} /* }}} int buffer_add_value */
+static int buffer_add_ulong (const unsigned long value, /* {{{ */
+ char **buffer_ret, size_t *buffer_size_ret)
+{
+ char temp[4096];
+
+ snprintf (temp, sizeof (temp), "%lu", value);
+ temp[sizeof (temp) - 1] = 0;
+ return (buffer_add_string (temp, buffer_ret, buffer_size_ret));
+} /* }}} int buffer_add_ulong */
+
/* Remove trailing newline (NL) and carriage return (CR) characters. Similar to
* the Perl function `chomp'. Returns the number of characters that have been
* removed. */
return (status);
} /* }}} int rrdc_flush */
+rrd_info_t * rrdc_info (const char *filename) /* {{{ */
+{
+ char buffer[4096];
+ char *buffer_ptr;
+ size_t buffer_free;
+ size_t buffer_size;
+ rrdc_response_t *res;
+ int status;
+ char file_path[PATH_MAX];
+ rrd_info_t *data = NULL, *cd;
+ rrd_infoval_t info;
+ unsigned int l;
+ rrd_info_type_t itype;
+ char *k, *s;
+
+ if (filename == NULL) {
+ rrd_set_error ("rrdc_info: no filename");
+ return (NULL);
+ }
+
+ memset (buffer, 0, sizeof (buffer));
+ buffer_ptr = &buffer[0];
+ buffer_free = sizeof (buffer);
+
+ status = buffer_add_string ("info", &buffer_ptr, &buffer_free);
+ if (status != 0) {
+ rrd_set_error ("rrdc_info: out of memory");
+ return (NULL);
+ }
+
+ pthread_mutex_lock (&lock);
+ filename = get_path (filename, file_path);
+ if (filename == NULL)
+ {
+ pthread_mutex_unlock (&lock);
+ return (NULL);
+ }
+
+ status = buffer_add_string (filename, &buffer_ptr, &buffer_free);
+ if (status != 0)
+ {
+ pthread_mutex_unlock (&lock);
+ rrd_set_error ("rrdc_info: 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;
+ status = request (buffer, buffer_size, &res);
+ pthread_mutex_unlock (&lock);
+
+ if (status != 0) {
+ rrd_set_error ("rrdcached: %s", res->message);
+ return (NULL);
+ }
+ data = cd = NULL;
+ for( l=0 ; l < res->lines_num ; l++ ) {
+ /* first extract the keyword */
+ for(k = s = res->lines[l];s && *s;s++) {
+ if(*s == ' ') { *s = 0; s++; break; }
+ }
+ if(!s || !*s) break;
+ itype = atoi(s); /* extract type code */
+ for(;*s;s++) { if(*s == ' ') { *s = 0; s++; break; } }
+ if(!*s) break;
+ /* finally, we're pointing to the value */
+ switch(itype) {
+ case RD_I_VAL:
+ if(*s == 'N') { info.u_val = DNAN; } else { info.u_val = atof(s); }
+ break;
+ case RD_I_CNT:
+ info.u_cnt = atol(s);
+ break;
+ case RD_I_INT:
+ info.u_int = atoi(s);
+ break;
+ case RD_I_STR:
+ chomp(s);
+ info.u_str = (char*)malloc(sizeof(char) * (strlen(s) + 1));
+ strcpy(info.u_str,s);
+ break;
+ case RD_I_BLO:
+ rrd_set_error ("rrdc_info: BLOB objects are not supported");
+ return (NULL);
+ default:
+ rrd_set_error ("rrdc_info: Unsupported info type %d",itype);
+ return (NULL);
+ }
+
+ cd = rrd_info_push(cd, sprintf_alloc("%s",k), itype, info);
+ if(!data) data = cd;
+ }
+ response_free (res);
+
+ return (data);
+} /* }}} int rrdc_info */
+
+time_t rrdc_last (const char *filename) /* {{{ */
+{
+ char buffer[4096];
+ char *buffer_ptr;
+ size_t buffer_free;
+ size_t buffer_size;
+ rrdc_response_t *res;
+ int status;
+ char file_path[PATH_MAX];
+ time_t lastup;
+
+ if (filename == NULL) {
+ rrd_set_error ("rrdc_last: no filename");
+ return (-1);
+ }
+
+ memset (buffer, 0, sizeof (buffer));
+ buffer_ptr = &buffer[0];
+ buffer_free = sizeof (buffer);
+
+ status = buffer_add_string ("last", &buffer_ptr, &buffer_free);
+ if (status != 0) {
+ rrd_set_error ("rrdc_last: out of memory");
+ return (-1);
+ }
+
+ pthread_mutex_lock (&lock);
+ filename = get_path (filename, file_path);
+ if (filename == NULL)
+ {
+ pthread_mutex_unlock (&lock);
+ return (-1);
+ }
+
+ status = buffer_add_string (filename, &buffer_ptr, &buffer_free);
+ if (status != 0)
+ {
+ pthread_mutex_unlock (&lock);
+ rrd_set_error ("rrdc_last: out of memory");
+ return (-1);
+ }
+
+ 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) {
+ rrd_set_error ("rrdcached: %s", res->message);
+ return (-1);
+ }
+ lastup = atol(res->message);
+ response_free (res);
+
+ return (lastup);
+} /* }}} int rrdc_last */
+
+time_t rrdc_first (const char *filename, int rraindex) /* {{{ */
+{
+ char buffer[4096];
+ char *buffer_ptr;
+ size_t buffer_free;
+ size_t buffer_size;
+ rrdc_response_t *res;
+ int status;
+ char file_path[PATH_MAX];
+ time_t firstup;
+
+ if (filename == NULL) {
+ rrd_set_error ("rrdc_first: no filename specified");
+ return (-1);
+ }
+
+ memset (buffer, 0, sizeof (buffer));
+ buffer_ptr = &buffer[0];
+ buffer_free = sizeof (buffer);
+
+ status = buffer_add_string ("first", &buffer_ptr, &buffer_free);
+ if (status != 0) {
+ rrd_set_error ("rrdc_first: out of memory");
+ return (-1);
+ }
+
+ pthread_mutex_lock (&lock);
+ filename = get_path (filename, file_path);
+ if (filename == NULL)
+ {
+ pthread_mutex_unlock (&lock);
+ return (-1);
+ }
+
+ status = buffer_add_string (filename, &buffer_ptr, &buffer_free);
+ if (status != 0)
+ {
+ pthread_mutex_unlock (&lock);
+ rrd_set_error ("rrdc_first: out of memory");
+ return (-1);
+ }
+ status = buffer_add_ulong (rraindex, &buffer_ptr, &buffer_free);
+ if (status != 0)
+ {
+ pthread_mutex_unlock (&lock);
+ rrd_set_error ("rrdc_first: out of memory");
+ return (-1);
+ }
+
+ 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) {
+ rrd_set_error ("rrdcached: %s", res->message);
+ return (-1);
+ }
+ firstup = atol(res->message);
+ response_free (res);
+
+ return (firstup);
+} /* }}} int rrdc_first */
+
+int rrdc_create (const char *filename, /* {{{ */
+ unsigned long pdp_step,
+ time_t last_up,
+ int no_overwrite,
+ int argc,
+ const char **argv)
+{
+ char buffer[4096];
+ char *buffer_ptr;
+ size_t buffer_free;
+ size_t buffer_size;
+ rrdc_response_t *res;
+ int status;
+ char file_path[PATH_MAX];
+ int i;
+
+ if (filename == NULL) {
+ rrd_set_error ("rrdc_create: no filename specified");
+ return (-1);
+ }
+
+ memset (buffer, 0, sizeof (buffer));
+ buffer_ptr = &buffer[0];
+ buffer_free = sizeof (buffer);
+
+ status = buffer_add_string ("create", &buffer_ptr, &buffer_free);
+ if (status != 0) {
+ rrd_set_error ("rrdc_create: out of memory");
+ return (-1);
+ }
+
+ pthread_mutex_lock (&lock);
+ filename = get_path (filename, file_path);
+ if (filename == NULL)
+ {
+ pthread_mutex_unlock (&lock);
+ return (-1);
+ }
+
+ status = buffer_add_string (filename, &buffer_ptr, &buffer_free);
+ status = buffer_add_string ("-b", &buffer_ptr, &buffer_free);
+ status = buffer_add_ulong (last_up, &buffer_ptr, &buffer_free);
+ status = buffer_add_string ("-s", &buffer_ptr, &buffer_free);
+ status = buffer_add_ulong (pdp_step, &buffer_ptr, &buffer_free);
+ if(no_overwrite) {
+ status = buffer_add_string ("-O", &buffer_ptr, &buffer_free);
+ }
+ if (status != 0)
+ {
+ pthread_mutex_unlock (&lock);
+ rrd_set_error ("rrdc_create: out of memory");
+ return (-1);
+ }
+
+ for( i=0; i<argc; i++ ) {
+ if( argv[i] ) {
+ status = buffer_add_string (argv[i], &buffer_ptr, &buffer_free);
+ if (status != 0)
+ {
+ pthread_mutex_unlock (&lock);
+ rrd_set_error ("rrdc_create: out of memory");
+ return (-1);
+ }
+ }
+ }
+
+ /* buffer ready to send? */
+ 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) {
+ rrd_set_error ("rrdcached: %s", res->message);
+ return (-1);
+ }
+ response_free (res);
+ return(0);
+} /* }}} int rrdc_create */
+
int rrdc_fetch (const char *filename, /* {{{ */
const char *cf,
time_t *ret_start, time_t *ret_end,
int rrdc_update (const char *filename, int values_num,
const char * const *values);
+rrd_info_t * rrdc_info (const char *filename);
+time_t rrdc_last (const char *filename);
+time_t rrdc_first (const char *filename, int rraindex);
+int rrdc_create (const char *filename,
+ unsigned long pdp_step,
+ time_t last_up,
+ int no_overwrite,
+ int argc,
+ const char **argv);
+
+
int rrdc_flush (const char *filename);
int rrdc_flush_if_daemon (const char *opt_daemon, const char *filename);
#include "rrd_tool.h"
#include "rrd_rpncalc.h"
#include "rrd_hw.h"
+#include "rrd_client.h"
#include "rrd_is_thread_safe.h"
static int opt_no_overwrite = 0;
static void rrd_free2(
rrd_t *rrd); /* our onwn copy, immmune to mmap */
+void rrd_create_set_no_overwrite(
+ int opt )
+{
+ opt_no_overwrite = (opt?1:0);
+}
+
int rrd_create(
int argc,
char **argv)
struct option long_options[] = {
{"start", required_argument, 0, 'b'},
{"step", required_argument, 0, 's'},
+ {"daemon", required_argument, 0, 'd'},
{"no-overwrite", no_argument, 0, 'O'},
{0, 0, 0, 0}
};
char *parsetime_error = NULL;
long long_tmp;
int rc;
+ char * opt_daemon = NULL;
optind = 0;
opterr = 0; /* initialize getopt */
while (1) {
- opt = getopt_long(argc, argv, "Ob:s:", long_options, &option_index);
+ opt = getopt_long(argc, argv, "Ob:s:d:", long_options, &option_index);
if (opt == EOF)
break;
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 (-1);
+ }
+ break;
+
case 'b':
if ((parsetime_error = rrd_parsetime(optarg, &last_up_tv))) {
rrd_set_error("start time: %s", parsetime_error);
rrd_set_error("need name of an rrd file to create");
return -1;
}
+
+ rrdc_connect (opt_daemon);
+ if (rrdc_is_connected (opt_daemon)) {
+ rc = rrdc_create (argv[optind],
+ pdp_step, last_up, opt_no_overwrite,
+ argc - optind - 1, (const char **) (argv + optind + 1));
+ } else {
rc = rrd_create_r(argv[optind],
pdp_step, last_up,
argc - optind - 1, (const char **) (argv + optind + 1));
+ }
return rc;
}
unsigned short token_idx, error_flag, period = 0;
unsigned long hashed_name;
+ /* clear any previous errors */
+ rrd_clear_error();
+
/* init rrd clean */
rrd_init(&rrd);
/* static header */
dummychar2, &offset)) {
case 0:
case 1:
- rrd_set_error("Invalid DS name");
+ rrd_set_error("Invalid DS name in [%s]",&argv[i][3]);
break;
case 2:
case 3:
- rrd_set_error("Invalid DS type");
+ rrd_set_error("Invalid DS type in [%s]",&argv[i][3]);
break;
case 4: /* (%n may or may not be counted) */
case 5: /* check for duplicate datasource names */
static uint64_t stats_journal_rotate = 0;
static pthread_mutex_t stats_lock = PTHREAD_MUTEX_INITIALIZER;
+static int opt_no_overwrite = 0;
+
/* Journaled updates */
#define JOURNAL_REPLAY(s) ((s) == NULL)
#define JOURNAL_BASE "rrd.journal"
return (0);
} /* }}} int handle_request_wrote */
+static int handle_request_info (HANDLER_PROTO) /* {{{ */
+{
+ char *file, file_tmp[PATH_MAX];
+ int status;
+ rrd_info_t *data;
+
+ /* obtain filename */
+ status = buffer_get_field(&buffer, &buffer_size, &file);
+ if (status != 0)
+ return syntax_error(sock,cmd);
+ /* get full pathname */
+ get_abs_path(&file, file_tmp);
+ if (!check_file_access(file, sock)) {
+ return send_response(sock, RESP_ERR, "Cannot read: %s\n", file);
+ }
+ /* get data */
+ rrd_clear_error ();
+ data = rrd_info_r(file);
+ if(!data) {
+ return send_response(sock, RESP_ERR, "RRD Error: %s\n", rrd_get_error());
+ }
+ while (data) {
+ switch (data->type) {
+ case RD_I_VAL:
+ if (isnan(data->value.u_val))
+ add_response_info(sock,"%s %d NaN\n",data->key, data->type);
+ else
+ add_response_info(sock,"%s %d %0.10e\n", data->key, data->type, data->value.u_val);
+ break;
+ case RD_I_CNT:
+ add_response_info(sock,"%s %d %lu\n", data->key, data->type, data->value.u_cnt);
+ break;
+ case RD_I_INT:
+ add_response_info(sock,"%s %d %d\n", data->key, data->type, data->value.u_int);
+ break;
+ case RD_I_STR:
+ add_response_info(sock,"%s %d %s\n", data->key, data->type, data->value.u_str);
+ break;
+ case RD_I_BLO:
+ add_response_info(sock,"%s %d %lu\n", data->key, data->type, data->value.u_blo.size);
+ break;
+ }
+ data = data->next;
+ }
+ return send_response(sock, RESP_OK, "Info for %s follows\n",file);
+} /* }}} static int handle_request_info */
+
+static int handle_request_first (HANDLER_PROTO) /* {{{ */
+{
+ char *i, *file, file_tmp[PATH_MAX];
+ int status;
+ int idx;
+ time_t t;
+
+ /* obtain filename */
+ status = buffer_get_field(&buffer, &buffer_size, &file);
+ if (status != 0)
+ return syntax_error(sock,cmd);
+ /* get full pathname */
+ get_abs_path(&file, file_tmp);
+ if (!check_file_access(file, sock)) {
+ return send_response(sock, RESP_ERR, "Cannot read: %s\n", file);
+ }
+
+ status = buffer_get_field(&buffer, &buffer_size, &i);
+ if (status != 0)
+ return syntax_error(sock,cmd);
+ idx = atoi(i);
+ if(idx<0) {
+ return send_response(sock, RESP_ERR, "Invalid index specified (%d)\n", idx);
+ }
+
+ /* get data */
+ rrd_clear_error ();
+ t = rrd_first_r(file,idx);
+ if(t<1) {
+ 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_last (HANDLER_PROTO) /* {{{ */
+{
+ char *file, file_tmp[PATH_MAX];
+ int status;
+ time_t t;
+
+ /* obtain filename */
+ status = buffer_get_field(&buffer, &buffer_size, &file);
+ if (status != 0)
+ return syntax_error(sock,cmd);
+ /* get full pathname */
+ get_abs_path(&file, file_tmp);
+ 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) {
+ 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_create (HANDLER_PROTO) /* {{{ */
+{
+ char *file, file_tmp[PATH_MAX];
+ char *tok;
+ int ac = 0;
+ char *av[128];
+ int status;
+ ulong 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;
+
+
+ /* obtain filename */
+ status = buffer_get_field(&buffer, &buffer_size, &file);
+ if (status != 0)
+ return syntax_error(sock,cmd);
+ /* get full pathname */
+ get_abs_path(&file, file_tmp);
+ if (!check_file_access(file, sock)) {
+ return send_response(sock, RESP_ERR, "Cannot read: %s\n", file);
+ }
+ 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 )) {
+ 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;
+
+ continue;
+ }
+ if( ! strncmp(tok,"-s",2) ) {
+ status = buffer_get_field(&buffer, &buffer_size, &tok );
+ if (status != 0) return syntax_error(sock,cmd);
+ step = atol(tok);
+ continue;
+ }
+ if( ! strncmp(tok,"-O",2) ) {
+ no_overwrite = 1;
+ continue;
+ }
+ if( ! strncmp(tok,"DS:",3) ) { av[ac++]=tok; continue; }
+ if( ! strncmp(tok,"RRA:",4) ) { av[ac++]=tok; continue; }
+ return syntax_error(sock,cmd);
+ }
+ if(step<1) {
+ return send_response(sock, RESP_ERR, "The step size cannot be less than 1 second.\n");
+ }
+ if (last_up < 3600 * 24 * 365 * 10) {
+ 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);
+
+ if(!status) {
+ return send_response(sock, RESP_OK, "RRD created OK\n");
+ }
+ return send_response(sock, RESP_ERR, "RRD Error: %s\n", rrd_get_error());
+} /* }}} static int handle_request_create */
+
/* start "BATCH" processing */
static int batch_start (HANDLER_PROTO) /* {{{ */
{
"The 'FETCH' can be used by the client to retrieve values from an RRD file.\n"
},
{
+ "INFO",
+ handle_request_info,
+ CMD_CONTEXT_CLIENT,
+ "INFO <filename>\n",
+ "The INFO command retrieves information about a specified RRD file.\n"
+ "This is returned in standard rrdinfo format, a sequence of lines\n"
+ "with the format <keyname> = <value>\n"
+ "Note that this is the data as of the last update of the RRD file itself,\n"
+ "not the last time data was received via rrdcached, so there may be pending\n"
+ "updates in the queue. If this bothers you, then first run a FLUSH.\n"
+ },
+ {
+ "FIRST",
+ handle_request_first,
+ CMD_CONTEXT_CLIENT,
+ "FIRST <filename> <rra index>\n",
+ "The FIRST command retrieves the first data time for a specified RRA in\n"
+ "an RRD file.\n"
+ },
+ {
+ "LAST",
+ handle_request_last,
+ CMD_CONTEXT_CLIENT,
+ "LAST <filename>\n",
+ "The LAST command retrieves the last update time for a specified RRD file.\n"
+ "Note that this is the time of the last update of the RRD file itself, not\n"
+ "the last time data was received via rrdcached, so there may be pending\n"
+ "updates in the queue. If this bothers you, then first run a FLUSH.\n"
+ },
+ {
+ "CREATE",
+ handle_request_create,
+ CMD_CONTEXT_CLIENT | CMD_CONTEXT_BATCH,
+ "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 DS and RRA definitions are as for the 'rrdtool create' command.\n"
+ },
+ {
"QUIT",
handle_request_quit,
CMD_CONTEXT_CLIENT | CMD_CONTEXT_BATCH,
default_socket.socket_group = (gid_t)-1;
default_socket.socket_permissions = (mode_t)-1;
- while ((option = getopt(argc, argv, "gl:s:m:P:f:w:z:t:Bb:p:Fj:a:h?")) != -1)
+ while ((option = getopt(argc, argv, "Ogl:s:m:P:f:w:z:t:Bb:p:Fj:a:h?")) != -1)
{
switch (option)
{
+ case 'O':
+ opt_no_overwrite = 1;
+ break;
+
case 'g':
stay_foreground=1;
break;
"for that group)\n"
" -m <mode> File permissions (octal) of all following UNIX "
"sockets\n"
- " -a <size> Memory allocation chunk size. Default is 1."
+ " -a <size> Memory allocation chunk size. Default is 1.\n"
+ " -O Do not allow CREATE commands to overwrite existing\n"
+ " files, even if asked to.\n"
"\n"
"For more information and a detailed description of all options "
"please refer\n"
#include <stdlib.h>
#include "rrd_tool.h"
+#include "rrd_client.h"
time_t rrd_first(
{
int target_rraindex = 0;
char *endptr;
+ char *opt_daemon = NULL;
struct option long_options[] = {
{"rraindex", required_argument, 0, 129},
+ {"daemon", required_argument, 0, 'd'},
{0, 0, 0, 0}
};
int option_index = 0;
int opt;
- opt = getopt_long(argc, argv, "", long_options, &option_index);
+ opt = getopt_long(argc, argv, "d:F", long_options, &option_index);
if (opt == EOF)
break;
return (-1);
}
break;
+ case 'd':
+ if (opt_daemon != NULL)
+ free (opt_daemon);
+ opt_daemon = strdup (optarg);
+ if (opt_daemon == NULL)
+ {
+ rrd_set_error ("strdup failed.");
+ return (-1);
+ }
+ break;
default:
- rrd_set_error("usage rrdtool %s [--rraindex number] file.rrd",
+ rrd_set_error("usage rrdtool %s [--rraindex number] [--daemon <addr>] file.rrd",
argv[0]);
return (-1);
}
}
if (optind >= argc) {
- rrd_set_error("not enough arguments");
+ rrd_set_error("usage rrdtool %s [--rraindex number] [--daemon <addr>] file.rrd",
+ argv[0]);
return -1;
}
+ rrdc_connect (opt_daemon);
+ if (rrdc_is_connected (opt_daemon)) {
+ return (rrdc_first (argv[optind], target_rraindex));
+ } else {
return (rrd_first_r(argv[optind], target_rraindex));
+ }
}
rrd_info_t *info;
char *opt_daemon = NULL;
int status;
+ int flushfirst = 1;
optind = 0;
opterr = 0; /* initialize getopt */
int option_index = 0;
static struct option long_options[] = {
{"daemon", required_argument, 0, 'd'},
+ {"noflush", no_argument, 0, 'F'},
{0, 0, 0, 0}
};
- opt = getopt_long(argc, argv, "d:", long_options, &option_index);
+ opt = getopt_long(argc, argv, "d:F", long_options, &option_index);
if (opt == EOF)
break;
}
break;
+ case 'F':
+ flushfirst = 0;
+ break;
+
default:
- rrd_set_error ("Usage: rrdtool %s [--daemon <addr>] <file>",
+ rrd_set_error ("Usage: rrdtool %s [--daemon <addr> [--noflush]] <file>",
argv[0]);
return (NULL);
break;
} /* while (42) */
if ((argc - optind) != 1) {
- rrd_set_error ("Usage: rrdtool %s [--daemon <addr>] <file>",
+ rrd_set_error ("Usage: rrdtool %s [--daemon <addr> [--noflush]] <file>",
argv[0]);
return (NULL);
}
+ if( flushfirst ) {
status = rrdc_flush_if_daemon(opt_daemon, argv[optind]);
- if (opt_daemon) free (opt_daemon);
if (status) return (NULL);
+ }
+ rrdc_connect (opt_daemon);
+ if (rrdc_is_connected (opt_daemon))
+ info = rrdc_info (argv[optind]);
+ else
info = rrd_info_r(argv[optind]);
return (info);
{
char *opt_daemon = NULL;
int status;
+ time_t lastupdate;
+ int flushfirst = 1;
optind = 0;
opterr = 0; /* initialize getopt */
int option_index = 0;
static struct option long_options[] = {
{"daemon", required_argument, 0, 'd'},
+ {"noflush", no_argument, 0, 'F'},
{0, 0, 0, 0}
};
- opt = getopt_long(argc, argv, "d:", long_options, &option_index);
+ opt = getopt_long(argc, argv, "d:F", long_options, &option_index);
if (opt == EOF)
break;
}
break;
+ case 'F':
+ flushfirst = 0;
+ break;
+
default:
- rrd_set_error ("Usage: rrdtool %s [--daemon <addr>] <file>",
+ rrd_set_error ("Usage: rrdtool %s [--daemon <addr> [--noflush]] <file>",
argv[0]);
return (-1);
break;
} /* while (42) */
if ((argc - optind) != 1) {
- rrd_set_error ("Usage: rrdtool %s [--daemon <addr>] <file>",
+ rrd_set_error ("Usage: rrdtool %s [--daemon <addr> [--noflush]] <file>",
argv[0]);
return (-1);
}
+ if(flushfirst) {
status = rrdc_flush_if_daemon(opt_daemon, argv[optind]);
- if (opt_daemon) free(opt_daemon);
if (status) return (-1);
+ }
+
+ rrdc_connect (opt_daemon);
+ if (rrdc_is_connected (opt_daemon))
+ lastupdate = rrdc_last (argv[optind]);
+
+ else
+ lastupdate = rrd_last_r(argv[optind]);
- return (rrd_last_r (argv[optind]));
+ return (lastupdate);
}
time_t rrd_last_r(