* Now for some includes..
*/
/* {{{ */
-#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__) && !defined(HAVE_CONFIG_H)
-#include "../win32/config.h"
-#else
-#ifdef HAVE_CONFIG_H
-#include "../rrd_config.h"
-#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>
/* }}} */
size_t values_num; /* number of valid pointers */
size_t values_alloc; /* number of allocated pointers */
time_t last_flush_time;
- time_t last_update_stamp;
+ double last_update_stamp;
#define CI_FLAGS_IN_TREE (1<<0)
#define CI_FLAGS_IN_QUEUE (1<<1)
int flags;
size_t files_num;
} journal_set;
-/* max length of socket command or response */
-#define CMD_MAX 4096
-#define RBUF_SIZE (CMD_MAX*2)
+#define RBUF_SIZE (RRD_CMD_MAX*2)
/*
* Variables
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)
static int add_response_info(listen_socket_t *sock, char *fmt, ...) /* {{{ */
{
va_list argp;
- char buffer[CMD_MAX];
+ char buffer[RRD_CMD_MAX];
int len;
if (JOURNAL_REPLAY(sock)) return 0;
char *fmt, ...) /* {{{ */
{
va_list argp;
- char buffer[CMD_MAX];
+ char buffer[RRD_CMD_MAX];
int lines;
ssize_t wrote;
int rclen, len;
char *file, file_tmp[PATH_MAX];
int values_num = 0;
int status;
- char orig_buf[CMD_MAX];
+ char orig_buf[RRD_CMD_MAX];
cache_item_t *ci;
/* save it for the journal later */
if (!JOURNAL_REPLAY(sock))
- strncpy(orig_buf, buffer, buffer_size);
+ strncpy(orig_buf, buffer, min(RRD_CMD_MAX,buffer_size));
status = buffer_get_field (&buffer, &buffer_size, &file);
if (status != 0)
while (buffer_size > 0)
{
char *value;
- time_t stamp;
+ double stamp;
char *eostamp;
status = buffer_get_field (&buffer, &buffer_size, &value);
break;
}
- /* make sure update time is always moving forward */
- stamp = strtol(value, &eostamp, 10);
+ /* make sure update time is always moving forward. We use double here since
+ update does support subsecond precision for timestamps ... */
+ stamp = strtod(value, &eostamp);
if (eostamp == value || eostamp == NULL || *eostamp != ':')
{
pthread_mutex_unlock(&cache_lock);
{
pthread_mutex_unlock(&cache_lock);
return send_response(sock, RESP_ERR,
- "illegal attempt to update using time %ld when last"
- " update time is %ld (minimum one second step)\n",
+ "illegal attempt to update using time %lf when last"
+ " update time is %lf (minimum one second step)\n",
stamp, ci->last_update_stamp);
}
else
{
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);
}
/* 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))
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 */
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);
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 */
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;
}
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) ) {
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");
"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"
},
{
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)
{
if (help && (help->syntax || help->help))
{
- char tmp[CMD_MAX];
+ char tmp[RRD_CMD_MAX];
snprintf(tmp, sizeof(tmp)-1, "Help for %s\n", help->cmd);
resp_txt = tmp;
int entry_cnt = 0;
int fail_cnt = 0;
uint64_t line = 0;
- char entry[CMD_MAX];
+ char entry[RRD_CMD_MAX];
time_t now;
if (file == NULL) return 0;
}
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, "rrdcached\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);
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);
}
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. */
case 'j':
{
char journal_dir_actual[PATH_MAX];
- const char *dir;
- dir = journal_dir = strdup(realpath((const char *)optarg, journal_dir_actual));
-
- status = rrd_mkdir_p(dir, 0777);
- if (status != 0)
- {
- fprintf(stderr, "Failed to create journal directory '%s': %s\n",
- dir, rrd_strerror(errno));
- return 6;
- }
-
- if (access(dir, R_OK|W_OK|X_OK) != 0)
- {
- fprintf(stderr, "Must specify a writable directory with -j! (%s)\n",
- errno ? rrd_strerror(errno) : "");
- return 6;
- }
+ journal_dir = realpath((const char *)optarg, journal_dir_actual);
+ if (journal_dir)
+ {
+ // if we were able to properly resolve the path, lets have a copy
+ // for use outside this block.
+ journal_dir = strdup(journal_dir);
+ status = rrd_mkdir_p(journal_dir, 0777);
+ if (status != 0)
+ {
+ fprintf(stderr, "Failed to create journal directory '%s': %s\n",
+ journal_dir, rrd_strerror(errno));
+ return 6;
+ }
+ if (access(journal_dir, R_OK|W_OK|X_OK) != 0)
+ {
+ fprintf(stderr, "Must specify a writable directory with -j! (%s)\n",
+ errno ? rrd_strerror(errno) : "");
+ return 6;
+ }
+ } else {
+ fprintf(stderr, "Unable to resolve journal path (%s,%s)\n", optarg,
+ errno ? rrd_strerror(errno) : "");
+ return 6;
+ }
}
break;
"\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"