prep for 1.2rc4 release
[rrdtool.git] / src / rrd_create.c
index 57ac76b..d571ea7 100644 (file)
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * RRDtool 1.1.x  Copyright Tobias Oetiker, 1997 - 2002
+ * RRDtool 1.2rc4  Copyright by Tobi Oetiker, 1997-2005
  *****************************************************************************
  * rrd_create.c  creates new rrds
  *****************************************************************************/
@@ -8,52 +8,22 @@
 #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);
-    }
-
-    /* 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 */
+    long              long_tmp;
+    int               rc;
 
-    /* a default value */
-    rrd.ds_def = NULL;
-    rrd.rra_def = NULL;
-    
     while (1){
        static struct option long_options[] =
        {
@@ -67,20 +37,18 @@ rrd_create(int argc, char **argv)
                          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);
            }
 
@@ -88,7 +56,6 @@ rrd_create(int argc, char **argv)
            
            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;
@@ -97,10 +64,9 @@ rrd_create(int argc, char **argv)
            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 '?':
@@ -108,19 +74,67 @@ rrd_create(int argc, char **argv)
                 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;
+    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,
@@ -169,6 +183,7 @@ rrd_create(int argc, char **argv)
             }
             rrd.stat_head -> ds_cnt++;
        } else if (strncmp(argv[i],"RRA:",3)==0){
+           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)
@@ -179,7 +194,7 @@ rrd_create(int argc, char **argv)
            }
            memset(&rrd.rra_def[rrd.stat_head->rra_cnt], 0, sizeof(rra_def_t));
             
-           token = strtok(&argv[i][4],":");
+           token = strtok_r(&argv[i][4],":", &tokptr);
            token_idx = error_flag = 0;
            while (token != NULL)
            {
@@ -197,8 +212,6 @@ rrd_create(int argc, char **argv)
                         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:
@@ -359,7 +372,7 @@ rrd_create(int argc, char **argv)
                     rrd_free(&rrd);
                     return (-1);
                 }
-                token = strtok(NULL,":");
+                token = strtok_r(NULL,":", &tokptr);
                 token_idx++;
            } /* end while */
 #ifdef DEBUG
@@ -377,6 +390,7 @@ rrd_create(int argc, char **argv)
                 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;
                 }
@@ -401,7 +415,7 @@ rrd_create(int argc, char **argv)
        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)
@@ -516,10 +530,11 @@ rrd_create_fn(char *file_name, rrd_t *rrd)
 {
     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);
@@ -621,17 +636,24 @@ rrd_create_fn(char *file_name, rrd_t *rrd)
     }
     
     /* 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)){