/*****************************************************************************
- * RRDtool 1.1.x Copyright Tobias Oetiker, 1997 - 2002
+ * RRDtool 1.2.11 Copyright by Tobi Oetiker, 1997-2005
*****************************************************************************
* rrd_create.c creates new rrds
*****************************************************************************/
#include "rrd_rpncalc.h"
#include "rrd_hw.h"
+#include "rrd_is_thread_safe.h"
+
unsigned long FnvHash(char *str);
int create_hw_contingent_rras(rrd_t *rrd, unsigned short period, unsigned long hashed_name);
void parseGENERIC_DS(char *def,rrd_t *rrd, int ds_idx);
-/* #define DEBUG */
int
rrd_create(int argc, char **argv)
{
- rrd_t rrd;
- long i,long_tmp;
- int offset;
- time_t last_up;
- struct time_value last_up_tv;
+ time_t last_up = time(NULL)-10;
+ unsigned long pdp_step = 300;
+ struct rrd_time_value last_up_tv;
char *parsetime_error = NULL;
- char *token;
- unsigned short token_idx, error_flag, period=0;
- unsigned long hashed_name;
- /* init last_up */
- last_up = time(NULL)-10;
- /* init rrd clean */
- rrd_init(&rrd);
- /* static header */
- if((rrd.stat_head = calloc(1,sizeof(stat_head_t)))==NULL){
- rrd_set_error("allocating rrd.stat_head");
- return(-1);
- }
-
- /* live header */
- if((rrd.live_head = calloc(1,sizeof(live_head_t)))==NULL){
- rrd_set_error("allocating rrd.live_head");
- return(-1);
- }
+ long long_tmp;
+ int rc;
+ optind = 0; opterr = 0; /* initialize getopt */
- /* set some defaults */
- strcpy(rrd.stat_head->cookie,RRD_COOKIE);
- /* assume the will be version 1 compatible */
- strcpy(rrd.stat_head->version,"0001");
- rrd.stat_head->float_cookie = FLOAT_COOKIE;
- rrd.stat_head->ds_cnt = 0; /* this will be adjusted later */
- rrd.stat_head->rra_cnt = 0; /* ditto */
- rrd.stat_head->pdp_step = 300; /* 5 minute default */
-
- /* a default value */
- rrd.ds_def = NULL;
- rrd.rra_def = NULL;
-
while (1){
static struct option long_options[] =
{
long_options, &option_index);
if (opt == EOF)
- break;
+ break;
switch(opt) {
case 'b':
if ((parsetime_error = parsetime(optarg, &last_up_tv))) {
rrd_set_error("start time: %s", parsetime_error );
- rrd_free(&rrd);
return(-1);
}
if (last_up_tv.type == RELATIVE_TO_END_TIME ||
last_up_tv.type == RELATIVE_TO_START_TIME) {
rrd_set_error("specifying time relative to the 'start' "
"or 'end' makes no sense here");
- rrd_free(&rrd);
return(-1);
}
if (last_up < 3600*24*365*10){
rrd_set_error("the first entry to the RRD should be after 1980");
- rrd_free(&rrd);
return(-1);
}
break;
long_tmp = atol(optarg);
if (long_tmp < 1){
rrd_set_error("step size should be no less than one second");
- rrd_free(&rrd);
return(-1);
}
- rrd.stat_head->pdp_step = long_tmp;
+ pdp_step = long_tmp;
break;
case '?':
rrd_set_error("unknown option '%c'", optopt);
else
rrd_set_error("unknown option '%s'",argv[optind-1]);
- rrd_free(&rrd);
return(-1);
}
}
+
+ rc = rrd_create_r(argv[optind],
+ pdp_step, last_up,
+ argc - optind - 1, argv + optind + 1);
+
+ return rc;
+}
+
+/* #define DEBUG */
+int
+rrd_create_r(char *filename,
+ unsigned long pdp_step, time_t last_up,
+ int argc, char **argv)
+{
+ rrd_t rrd;
+ long i;
+ int offset;
+ char *token;
+ char dummychar1[2], dummychar2[2];
+ unsigned short token_idx, error_flag, period=0;
+ unsigned long hashed_name;
+
+ /* init rrd clean */
+ rrd_init(&rrd);
+ /* static header */
+ if((rrd.stat_head = calloc(1,sizeof(stat_head_t)))==NULL){
+ rrd_set_error("allocating rrd.stat_head");
+ rrd_free(&rrd);
+ return(-1);
+ }
+
+ /* live header */
+ if((rrd.live_head = calloc(1,sizeof(live_head_t)))==NULL){
+ rrd_set_error("allocating rrd.live_head");
+ rrd_free(&rrd);
+ return(-1);
+ }
+
+ /* set some defaults */
+ strcpy(rrd.stat_head->cookie,RRD_COOKIE);
+ strcpy(rrd.stat_head->version,RRD_VERSION);
+ rrd.stat_head->float_cookie = FLOAT_COOKIE;
+ rrd.stat_head->ds_cnt = 0; /* this will be adjusted later */
+ rrd.stat_head->rra_cnt = 0; /* ditto */
+ rrd.stat_head->pdp_step = pdp_step; /* 5 minute default */
+
+ /* a default value */
+ rrd.ds_def = NULL;
+ rrd.rra_def = NULL;
+
rrd.live_head->last_up = last_up;
/* optind points to the first non-option command line arg,
* in this case, the file name. */
/* Compute the FNV hash value (used by SEASONAL and DEVSEASONAL
* arrays. */
- hashed_name = FnvHash(argv[optind]);
- for(i=optind+1;i<argc;i++){
- int ii;
+ hashed_name = FnvHash(filename);
+ for(i=0;i<argc;i++){
+ unsigned int ii;
if (strncmp(argv[i],"DS:",3)==0){
size_t old_size = sizeof(ds_def_t)*(rrd.stat_head->ds_cnt);
if((rrd.ds_def = rrd_realloc(rrd.ds_def,
}
memset(&rrd.ds_def[rrd.stat_head->ds_cnt], 0, sizeof(ds_def_t));
/* extract the name and type */
- if (sscanf(&argv[i][3],
- DS_NAM_FMT ":" DST_FMT ":%n",
- rrd.ds_def[rrd.stat_head->ds_cnt].ds_nam,
- rrd.ds_def[rrd.stat_head->ds_cnt].dst,&offset) == 2)
- {
- /* check for duplicate datasource names */
- for(ii=0;ii<rrd.stat_head->ds_cnt;ii++)
- if(strcmp(rrd.ds_def[rrd.stat_head->ds_cnt].ds_nam,
- rrd.ds_def[ii].ds_nam) == 0){
- rrd_set_error("Duplicate DS name: %s",rrd.ds_def[ii].ds_nam);
- }
- } else {
- rrd_set_error("invalid DS format");
+ switch (sscanf(&argv[i][3],
+ DS_NAM_FMT "%1[:]" DST_FMT "%1[:]%n",
+ rrd.ds_def[rrd.stat_head->ds_cnt].ds_nam,
+ dummychar1,
+ rrd.ds_def[rrd.stat_head->ds_cnt].dst,
+ dummychar2,
+ &offset)) {
+ case 0:
+ case 1: rrd_set_error("Invalid DS name"); break;
+ case 2:
+ case 3: rrd_set_error("Invalid DS type"); break;
+ case 4: /* (%n may or may not be counted) */
+ case 5: /* check for duplicate datasource names */
+ for (ii=0;ii<rrd.stat_head->ds_cnt;ii++)
+ if(strcmp(rrd.ds_def[rrd.stat_head->ds_cnt].ds_nam,
+ rrd.ds_def[ii].ds_nam) == 0)
+ rrd_set_error("Duplicate DS name: %s",
+ rrd.ds_def[ii].ds_nam);
+ /* DS_type may be valid or not. Checked later */
+ break;
+ default: rrd_set_error("invalid DS format");
+ }
+ if (rrd_test_error()) {
+ rrd_free(&rrd);
+ return -1;
}
/* parse the remainder of the arguments */
return -1;
}
rrd.stat_head -> ds_cnt++;
- } else if (strncmp(argv[i],"RRA:",3)==0){
+ } else if (strncmp(argv[i],"RRA:",4)==0){
+ char *argvcopy;
+ char *tokptr;
size_t old_size = sizeof(rra_def_t)*(rrd.stat_head->rra_cnt);
if((rrd.rra_def = rrd_realloc(rrd.rra_def,
old_size+sizeof(rra_def_t)))==NULL)
return(-1);
}
memset(&rrd.rra_def[rrd.stat_head->rra_cnt], 0, sizeof(rra_def_t));
-
- token = strtok(&argv[i][4],":");
+
+ argvcopy = strdup(argv[i]);
+ token = strtok_r(&argvcopy[4],":", &tokptr);
token_idx = error_flag = 0;
while (token != NULL)
{
rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_hw_beta].u_val = 1.0/288;
rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_dependent_rra_idx].u_cnt =
rrd.stat_head -> rra_cnt;
- /* need to mark the file version */
- strcpy(rrd.stat_head->version,RRD_VERSION);
break;
case CF_DEVSEASONAL:
case CF_SEASONAL:
if (rrd_test_error())
{
/* all errors are unrecoverable */
+ free(argvcopy);
rrd_free(&rrd);
return (-1);
}
- token = strtok(NULL,":");
+ token = strtok_r(NULL,":", &tokptr);
token_idx++;
} /* end while */
+ free(argvcopy);
#ifdef DEBUG
fprintf(stderr,"Creating RRA CF: %s, dep idx %lu, current idx %lu\n",
rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam,
fprintf(stderr,"Creating HW contingent RRAs\n");
#endif
if (create_hw_contingent_rras(&rrd,period,hashed_name) == -1) {
+ rrd_set_error("creating contingent RRA");
rrd_free(&rrd);
return -1;
}
rrd_free(&rrd);
return(-1);
}
- return rrd_create_fn(argv[optind],&rrd);
+ return rrd_create_fn(filename, &rrd);
}
void parseGENERIC_DS(char *def,rrd_t *rrd, int ds_idx)
{
unsigned long i,ii;
FILE *rrd_file;
- rrd_value_t unknown = DNAN ;
+ rrd_value_t *unknown;
+ int unkn_cnt;
if ((rrd_file = fopen(file_name,"wb")) == NULL ) {
- rrd_set_error("creating '%s': %s",file_name,strerror(errno));
+ rrd_set_error("creating '%s': %s",file_name, rrd_strerror(errno));
free(rrd->stat_head);
free(rrd->ds_def);
free(rrd->rra_def);
}
/* write the empty data area */
- for(i=0;
- i < rrd->stat_head->rra_cnt;
- i++)
- {
- for(ii=0;
- ii < rrd->rra_def[i].row_cnt
- * rrd->stat_head->ds_cnt;
- ii++){
- fwrite(&unknown,sizeof(rrd_value_t),1,rrd_file);
- }
+ if ((unknown = (rrd_value_t *)malloc(512 * sizeof(rrd_value_t))) == NULL) {
+ rrd_set_error("allocating unknown");
+ rrd_free(rrd);
+ fclose(rrd_file);
+ return(-1);
}
+ for (i = 0; i < 512; ++i)
+ unknown[i] = DNAN;
+
+ unkn_cnt = 0;
+ for (i = 0; i < rrd->stat_head->rra_cnt; i++)
+ unkn_cnt += rrd->stat_head->ds_cnt * rrd->rra_def[i].row_cnt;
+
+ while (unkn_cnt > 0) {
+ fwrite(unknown, sizeof(rrd_value_t), min(unkn_cnt, 512), rrd_file);
+ unkn_cnt -= 512;
+ }
+ free(unknown);
/* lets see if we had an error */
if(ferror(rrd_file)){