Code

Fix for #167 - rrdcreate is arguably missing a check for 'step>=1' for RRAs with...
[rrdtool-all.git] / program / src / rrd_create.c
index f8208b8146a9f60c0fa764f844bc39bb0ea4f0f8..186b3b40fa6e92818e759b0e63ecc998363327c6 100644 (file)
@@ -1,18 +1,22 @@
 /*****************************************************************************
- * RRDtool 1.2rc8  Copyright by Tobi Oetiker, 1997-2005
+ * RRDtool 1.2.27  Copyright by Tobi Oetiker, 1997-2008
  *****************************************************************************
  * rrd_create.c  creates new rrds
  *****************************************************************************/
 
+#include <stdlib.h>
+#include <time.h>
+
 #include "rrd_tool.h"
 #include "rrd_rpncalc.h"
 #include "rrd_hw.h"
 
 #include "rrd_is_thread_safe.h"
 
-unsigned long FnvHash(char *str);
+unsigned long FnvHash(const 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);
+void parseGENERIC_DS(const char *def,rrd_t *rrd, int ds_idx);
+long int rra_random_row(rra_def_t *);
 
 int
 rrd_create(int argc, char **argv) 
@@ -23,6 +27,7 @@ rrd_create(int argc, char **argv)
     char *parsetime_error = NULL;
     long              long_tmp;
     int               rc;
+    optind = 0; opterr = 0;  /* initialize getopt */
 
     while (1){
        static struct option long_options[] =
@@ -77,24 +82,28 @@ rrd_create(int argc, char **argv)
            return(-1);
        }
     }
-
+    if (optind == argc) {
+         rrd_set_error("what is the name of the rrd file you want to create?");
+         return -1;
+    }
     rc = rrd_create_r(argv[optind],
                      pdp_step, last_up,
-                     argc - optind - 1, argv + optind + 1);
+                     argc - optind - 1, (const char **)(argv + optind + 1));
     
     return rc;
 }
 
 /* #define DEBUG */
 int
-rrd_create_r(char *filename,
+rrd_create_r(const char *filename,
             unsigned long pdp_step, time_t last_up,
-            int argc, char **argv) 
+            int argc, const 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;
 
@@ -145,19 +154,31 @@ rrd_create_r(char *filename,
            }
            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 */
@@ -182,7 +203,8 @@ rrd_create_r(char *filename,
                 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,
@@ -193,8 +215,9 @@ rrd_create_r(char *filename,
                 return(-1);    
            }
            memset(&rrd.rra_def[rrd.stat_head->rra_cnt], 0, sizeof(rra_def_t));
-            
-           token = strtok_r(&argv[i][4],":", &tokptr);
+
+            argvcopy = strdup(argv[i]);
+           token = strtok_r(&argvcopy[4],":", &tokptr);
            token_idx = error_flag = 0;
            while (token != NULL)
            {
@@ -289,6 +312,8 @@ rrd_create_r(char *filename,
                         break;
                     default:
                         rrd.rra_def[rrd.stat_head->rra_cnt].pdp_cnt = atoi(token);
+                        if (atoi(token) < 1) 
+                            rrd_set_error("Invalid step: must be >= 1"); 
                         break;
                     }
                     break;
@@ -369,12 +394,14 @@ rrd_create_r(char *filename,
                 if (rrd_test_error())
                 {
                     /* all errors are unrecoverable */
+                    free(argvcopy);
                     rrd_free(&rrd);
                     return (-1);
                 }
                 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,
@@ -418,7 +445,7 @@ rrd_create_r(char *filename,
     return rrd_create_fn(filename, &rrd);
 }
 
-void parseGENERIC_DS(char *def,rrd_t *rrd, int ds_idx)
+void parseGENERIC_DS(const char *def,rrd_t *rrd, int ds_idx)
 {
     char minstr[DS_NAM_SIZE], maxstr[DS_NAM_SIZE];     
     /*
@@ -526,7 +553,7 @@ create_hw_contingent_rras(rrd_t *rrd, unsigned short period, unsigned long hashe
 /* create and empty rrd file according to the specs given */
 
 int
-rrd_create_fn(char *file_name, rrd_t *rrd)
+rrd_create_fn(const char *file_name, rrd_t *rrd)
 {
     unsigned long    i,ii;
     FILE             *rrd_file;
@@ -535,9 +562,7 @@ rrd_create_fn(char *file_name, rrd_t *rrd)
     
     if ((rrd_file = fopen(file_name,"wb")) == NULL ) {
        rrd_set_error("creating '%s': %s",file_name, rrd_strerror(errno));
-       free(rrd->stat_head);
-       free(rrd->ds_def);
-       free(rrd->rra_def);
+        rrd_free(rrd);
        return(-1);
     }
     
@@ -631,7 +656,7 @@ rrd_create_fn(char *file_name, rrd_t *rrd)
      * the pointer a priori. */
     for (i=0; i < rrd->stat_head->rra_cnt; i++)
     {
-        rrd->rra_ptr->cur_row = rrd->rra_def[i].row_cnt - 1;
+        rrd->rra_ptr->cur_row = rra_random_row(&rrd->rra_def[i]);
         fwrite( rrd->rra_ptr, sizeof(rra_ptr_t),1,rrd_file);
     }
     
@@ -667,3 +692,17 @@ rrd_create_fn(char *file_name, rrd_t *rrd)
     rrd_free(rrd);
     return (0);
 }
+
+static int rand_init = 0;
+
+long int
+rra_random_row(rra_def_t *rra)
+{
+    if (!rand_init)
+    {
+        srandom((unsigned int)time(NULL) + (unsigned int)getpid());
+        rand_init++;
+    }
+    
+    return random() % rra->row_cnt;
+}