added --no-overwrite option to rrdtool create. It prevents rrdtool from clobbering...
[rrdtool.git] / src / rrd_create.c
index 43d608e..a1b4e5a 100644 (file)
@@ -1,14 +1,23 @@
 /*****************************************************************************
- * RRDtool 1.2.23  Copyright by Tobi Oetiker, 1997-2007
+ * RRDtool 1.4.2  Copyright by Tobi Oetiker, 1997-2009
  *****************************************************************************
  * rrd_create.c  creates new rrds
  *****************************************************************************/
 
+#include <stdlib.h>
+#include <time.h>
+#include <locale.h>
+
 #include "rrd_tool.h"
 #include "rrd_rpncalc.h"
 #include "rrd_hw.h"
 
 #include "rrd_is_thread_safe.h"
+static int opt_no_overwrite = 0;
+
+#ifdef WIN32
+# include <process.h>
+#endif
 
 unsigned long FnvHash(
     const char *str);
@@ -21,13 +30,24 @@ void      parseGENERIC_DS(
     rrd_t *rrd,
     int ds_idx);
 
+static void rrd_free2(
+    rrd_t *rrd);        /* our onwn copy, immmune to mmap */
+
 int rrd_create(
     int argc,
     char **argv)
 {
+    struct option long_options[] = {
+        {"start", required_argument, 0, 'b'},
+        {"step", required_argument, 0, 's'},
+        {"no-overwrite", no_argument, 0, 'O'},
+        {0, 0, 0, 0}
+    };
+    int       option_index = 0;
+    int       opt;
     time_t    last_up = time(NULL) - 10;
     unsigned long pdp_step = 300;
-    struct rrd_time_value last_up_tv;
+    rrd_time_value_t last_up_tv;
     char     *parsetime_error = NULL;
     long      long_tmp;
     int       rc;
@@ -36,22 +56,14 @@ int rrd_create(
     opterr = 0;         /* initialize getopt */
 
     while (1) {
-        static struct option long_options[] = {
-            {"start", required_argument, 0, 'b'},
-            {"step", required_argument, 0, 's'},
-            {0, 0, 0, 0}
-        };
-        int       option_index = 0;
-        int       opt;
-
-        opt = getopt_long(argc, argv, "b:s:", long_options, &option_index);
+        opt = getopt_long(argc, argv, "Ob:s:", long_options, &option_index);
 
         if (opt == EOF)
             break;
 
         switch (opt) {
         case 'b':
-            if ((parsetime_error = parsetime(optarg, &last_up_tv))) {
+            if ((parsetime_error = rrd_parsetime(optarg, &last_up_tv))) {
                 rrd_set_error("start time: %s", parsetime_error);
                 return (-1);
             }
@@ -62,7 +74,7 @@ int rrd_create(
                 return (-1);
             }
 
-            last_up = mktime(&last_up_tv.tm) + last_up_tv.offset;
+            last_up = mktime(&last_up_tv.tm) +last_up_tv.offset;
 
             if (last_up < 3600 * 24 * 365 * 10) {
                 rrd_set_error
@@ -80,6 +92,10 @@ int rrd_create(
             pdp_step = long_tmp;
             break;
 
+        case 'O':
+            opt_no_overwrite = 1;
+           break;
+
         case '?':
             if (optopt != 0)
                 rrd_set_error("unknown option '%c'", optopt);
@@ -89,7 +105,7 @@ int rrd_create(
         }
     }
     if (optind == argc) {
-        rrd_set_error("what is the name of the rrd file you want to create?");
+        rrd_set_error("need name of an rrd file to create");
         return -1;
     }
     rc = rrd_create_r(argv[optind],
@@ -118,22 +134,22 @@ int rrd_create_r(
     /* init rrd clean */
     rrd_init(&rrd);
     /* static header */
-    if ((rrd.stat_head = calloc(1, sizeof(stat_head_t))) == NULL) {
+    if ((rrd.stat_head = (stat_head_t*)calloc(1, sizeof(stat_head_t))) == NULL) {
         rrd_set_error("allocating rrd.stat_head");
-        rrd_free(&rrd);
+        rrd_free2(&rrd);
         return (-1);
     }
 
     /* live header */
-    if ((rrd.live_head = calloc(1, sizeof(live_head_t))) == NULL) {
+    if ((rrd.live_head = (live_head_t*)calloc(1, sizeof(live_head_t))) == NULL) {
         rrd_set_error("allocating rrd.live_head");
-        rrd_free(&rrd);
+        rrd_free2(&rrd);
         return (-1);
     }
 
     /* set some defaults */
     strcpy(rrd.stat_head->cookie, RRD_COOKIE);
-    strcpy(rrd.stat_head->version, RRD_VERSION);
+    strcpy(rrd.stat_head->version, RRD_VERSION3);   /* by default we are still version 3 */
     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 */
@@ -156,11 +172,11 @@ int rrd_create_r(
         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,
+            if ((rrd.ds_def = (ds_def_t*)rrd_realloc(rrd.ds_def,
                                           old_size + sizeof(ds_def_t))) ==
                 NULL) {
                 rrd_set_error("allocating rrd.ds_def");
-                rrd_free(&rrd);
+                rrd_free2(&rrd);
                 return (-1);
             }
             memset(&rrd.ds_def[rrd.stat_head->ds_cnt], 0, sizeof(ds_def_t));
@@ -192,7 +208,7 @@ int rrd_create_r(
                 rrd_set_error("invalid DS format");
             }
             if (rrd_test_error()) {
-                rrd_free(&rrd);
+                rrd_free2(&rrd);
                 return -1;
             }
 
@@ -215,20 +231,21 @@ int rrd_create_r(
             }
 
             if (rrd_test_error()) {
-                rrd_free(&rrd);
+                rrd_free2(&rrd);
                 return -1;
             }
             rrd.stat_head->ds_cnt++;
         } else if (strncmp(argv[i], "RRA:", 4) == 0) {
             char     *argvcopy;
-            char     *tokptr;
+            char     *tokptr = "";
             size_t    old_size = sizeof(rra_def_t) * (rrd.stat_head->rra_cnt);
+            int       row_cnt;
 
-            if ((rrd.rra_def = rrd_realloc(rrd.rra_def,
+            if ((rrd.rra_def = (rra_def_t*)rrd_realloc(rrd.rra_def,
                                            old_size + sizeof(rra_def_t))) ==
                 NULL) {
                 rrd_set_error("allocating rrd.rra_def");
-                rrd_free(&rrd);
+                rrd_free2(&rrd);
                 return (-1);
             }
             memset(&rrd.rra_def[rrd.stat_head->rra_cnt], 0,
@@ -246,6 +263,8 @@ int rrd_create_r(
                         rrd_set_error("Failed to parse CF name");
                     switch (cf_conv
                             (rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam)) {
+                    case CF_MHWPREDICT:
+                        strcpy(rrd.stat_head->version, RRD_VERSION);    /* MHWPREDICT causes Version 4 */
                     case CF_HWPREDICT:
                         /* initialize some parameters */
                         rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_hw_alpha].
@@ -261,6 +280,8 @@ int rrd_create_r(
                         /* initialize some parameters */
                         rrd.rra_def[rrd.stat_head->rra_cnt].
                             par[RRA_seasonal_gamma].u_val = 0.1;
+                        rrd.rra_def[rrd.stat_head->rra_cnt].
+                            par[RRA_seasonal_smoothing_window].u_val = 0.05;
                         /* fall through */
                     case CF_DEVPREDICT:
                         rrd.rra_def[rrd.stat_head->rra_cnt].
@@ -293,12 +314,15 @@ int rrd_create_r(
                     switch (cf_conv
                             (rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam)) {
                     case CF_HWPREDICT:
+                    case CF_MHWPREDICT:
                     case CF_DEVSEASONAL:
                     case CF_SEASONAL:
                     case CF_DEVPREDICT:
                     case CF_FAILURES:
-                        rrd.rra_def[rrd.stat_head->rra_cnt].row_cnt =
-                            atoi(token);
+                        row_cnt = atoi(token);
+                        if (row_cnt <= 0)
+                            rrd_set_error("Invalid row count: %i", row_cnt);
+                        rrd.rra_def[rrd.stat_head->rra_cnt].row_cnt = row_cnt;
                         break;
                     default:
                         rrd.rra_def[rrd.stat_head->rra_cnt].
@@ -316,6 +340,7 @@ int rrd_create_r(
                     switch (cf_conv
                             (rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam)) {
                     case CF_HWPREDICT:
+                    case CF_MHWPREDICT:
                         rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_hw_alpha].
                             u_val = atof(token);
                         if (atof(token) <= 0.0 || atof(token) >= 1.0)
@@ -354,6 +379,8 @@ int rrd_create_r(
                     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;
@@ -361,6 +388,7 @@ int rrd_create_r(
                     switch (cf_conv
                             (rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam)) {
                     case CF_HWPREDICT:
+                    case CF_MHWPREDICT:
                         rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_hw_beta].
                             u_val = atof(token);
                         if (atof(token) < 0.0 || atof(token) > 1.0)
@@ -399,8 +427,10 @@ int rrd_create_r(
                             ("Unexpected extra argument for consolidation function DEVPREDICT");
                         break;
                     default:
-                        rrd.rra_def[rrd.stat_head->rra_cnt].row_cnt =
-                            atoi(token);
+                        row_cnt = atoi(token);
+                        if (row_cnt <= 0)
+                            rrd_set_error("Invalid row count: %i", row_cnt);
+                        rrd.rra_def[rrd.stat_head->rra_cnt].row_cnt = row_cnt;
                         break;
                     }
                     break;
@@ -414,7 +444,31 @@ int rrd_create_r(
                             par[RRA_dependent_rra_idx].u_cnt =
                             atoi(token) - 1;
                         break;
+                    case CF_DEVSEASONAL:
+                    case CF_SEASONAL:
+                        /* optional smoothing window */
+                        if (sscanf(token, "smoothing-window=%lf",
+                                   &(rrd.rra_def[rrd.stat_head->rra_cnt].
+                                     par[RRA_seasonal_smoothing_window].
+                                     u_val))) {
+                            strcpy(rrd.stat_head->version, RRD_VERSION);    /* smoothing-window causes Version 4 */
+                            if (rrd.rra_def[rrd.stat_head->rra_cnt].
+                                par[RRA_seasonal_smoothing_window].u_val < 0.0
+                                || rrd.rra_def[rrd.stat_head->rra_cnt].
+                                par[RRA_seasonal_smoothing_window].u_val >
+                                1.0) {
+                                rrd_set_error
+                                    ("Invalid smoothing-window %f: must be between 0 and 1",
+                                     rrd.rra_def[rrd.stat_head->rra_cnt].
+                                     par[RRA_seasonal_smoothing_window].
+                                     u_val);
+                            }
+                        } else {
+                            rrd_set_error("Invalid option %s", token);
+                        }
+                        break;
                     case CF_HWPREDICT:
+                    case CF_MHWPREDICT:
                         /* length of the associated CF_SEASONAL and CF_DEVSEASONAL arrays. */
                         period = atoi(token);
                         if (period >
@@ -448,7 +502,7 @@ int rrd_create_r(
                 if (rrd_test_error()) {
                     /* all errors are unrecoverable */
                     free(argvcopy);
-                    rrd_free(&rrd);
+                    rrd_free2(&rrd);
                     return (-1);
                 }
                 token = strtok_r(NULL, ":", &tokptr);
@@ -463,8 +517,10 @@ int rrd_create_r(
                     par[RRA_dependent_rra_idx].u_cnt, rrd.stat_head->rra_cnt);
 #endif
             /* should we create CF_SEASONAL, CF_DEVSEASONAL, and CF_DEVPREDICT? */
-            if (cf_conv(rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam) ==
-                CF_HWPREDICT
+            if ((cf_conv(rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam) ==
+                 CF_HWPREDICT
+                 || cf_conv(rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam) ==
+                 CF_MHWPREDICT)
                 && rrd.rra_def[rrd.stat_head->rra_cnt].
                 par[RRA_dependent_rra_idx].u_cnt == rrd.stat_head->rra_cnt) {
 #ifdef DEBUG
@@ -473,14 +529,14 @@ int rrd_create_r(
                 if (create_hw_contingent_rras(&rrd, period, hashed_name) ==
                     -1) {
                     rrd_set_error("creating contingent RRA");
-                    rrd_free(&rrd);
+                    rrd_free2(&rrd);
                     return -1;
                 }
             }
             rrd.stat_head->rra_cnt++;
         } else {
             rrd_set_error("can't parse argument '%s'", argv[i]);
-            rrd_free(&rrd);
+            rrd_free2(&rrd);
             return -1;
         }
     }
@@ -488,13 +544,13 @@ int rrd_create_r(
 
     if (rrd.stat_head->rra_cnt < 1) {
         rrd_set_error("you must define at least one Round Robin Archive");
-        rrd_free(&rrd);
+        rrd_free2(&rrd);
         return (-1);
     }
 
     if (rrd.stat_head->ds_cnt < 1) {
         rrd_set_error("you must define at least one Data Source");
-        rrd_free(&rrd);
+        rrd_free2(&rrd);
         return (-1);
     }
     return rrd_create_fn(filename, &rrd);
@@ -506,6 +562,7 @@ void parseGENERIC_DS(
     int ds_idx)
 {
     char      minstr[DS_NAM_SIZE], maxstr[DS_NAM_SIZE];
+    char     *old_locale;
 
     /*
        int temp;
@@ -514,6 +571,7 @@ void parseGENERIC_DS(
        &(rrd -> ds_def[ds_idx].par[DS_mrhb_cnt].u_cnt),
        minstr,maxstr);
      */
+    old_locale = setlocale(LC_NUMERIC, "C");
     if (sscanf(def, "%lu:%18[^:]:%18[^:]",
                &(rrd->ds_def[ds_idx].par[DS_mrhb_cnt].u_cnt),
                minstr, maxstr) == 3) {
@@ -532,11 +590,13 @@ void parseGENERIC_DS(
             rrd->ds_def[ds_idx].par[DS_min_val].u_val
             >= rrd->ds_def[ds_idx].par[DS_max_val].u_val) {
             rrd_set_error("min must be less than max in DS definition");
+            setlocale(LC_NUMERIC, old_locale);
             return;
         }
     } else {
         rrd_set_error("failed to parse data source %s", def);
     }
+    setlocale(LC_NUMERIC, old_locale);
 }
 
 /* Create the CF_DEVPREDICT, CF_DEVSEASONAL, CF_SEASONAL, and CF_FAILURES RRAs
@@ -556,9 +616,10 @@ int create_hw_contingent_rras(
     (rrd->stat_head->rra_cnt)++;
     /* allocate the memory for the 4 contingent RRAs */
     old_size = sizeof(rra_def_t) * (rrd->stat_head->rra_cnt);
-    if ((rrd->rra_def = rrd_realloc(rrd->rra_def,
+    if ((rrd->rra_def = (rra_def_t*)rrd_realloc(rrd->rra_def,
                                     old_size + 4 * sizeof(rra_def_t))) ==
         NULL) {
+        rrd_free2(rrd);
         rrd_set_error("allocating rrd.rra_def");
         return (-1);
     }
@@ -618,52 +679,55 @@ int rrd_create_fn(
     rrd_t *rrd)
 {
     unsigned long i, ii;
-    FILE     *rrd_file;
     rrd_value_t *unknown;
     int       unkn_cnt;
+    rrd_file_t *rrd_file_dn;
+    rrd_t     rrd_dn;
+    unsigned  rrd_flags = RRD_READWRITE | RRD_CREAT;
 
-    long      rrd_head_size;
+    if (opt_no_overwrite) {
+      rrd_flags |= RRD_EXCL ;
+    }
 
-    if ((rrd_file = fopen(file_name, "wb")) == NULL) {
+    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;
+
+    if ((rrd_file_dn = rrd_open(file_name, rrd, rrd_flags)) == NULL) {
         rrd_set_error("creating '%s': %s", file_name, rrd_strerror(errno));
-        free(rrd->stat_head);
-        rrd->stat_head = NULL;
-        free(rrd->ds_def);
-        rrd->ds_def = NULL;
-        free(rrd->rra_def);
-        rrd->rra_def = NULL;
+        rrd_free2(rrd);
         return (-1);
     }
 
-    fwrite(rrd->stat_head, sizeof(stat_head_t), 1, rrd_file);
+    rrd_write(rrd_file_dn, rrd->stat_head, sizeof(stat_head_t));
 
-    fwrite(rrd->ds_def, sizeof(ds_def_t), rrd->stat_head->ds_cnt, rrd_file);
+    rrd_write(rrd_file_dn, rrd->ds_def, sizeof(ds_def_t) * rrd->stat_head->ds_cnt);
 
-    fwrite(rrd->rra_def,
-           sizeof(rra_def_t), rrd->stat_head->rra_cnt, rrd_file);
+    rrd_write(rrd_file_dn, rrd->rra_def,
+          sizeof(rra_def_t) * rrd->stat_head->rra_cnt);
 
-    fwrite(rrd->live_head, sizeof(live_head_t), 1, rrd_file);
+    rrd_write(rrd_file_dn, rrd->live_head, sizeof(live_head_t));
 
-    if ((rrd->pdp_prep = calloc(1, sizeof(pdp_prep_t))) == NULL) {
+    if ((rrd->pdp_prep = (pdp_prep_t*)calloc(1, sizeof(pdp_prep_t))) == NULL) {
         rrd_set_error("allocating pdp_prep");
-        rrd_free(rrd);
-        fclose(rrd_file);
+        rrd_free2(rrd);
+        rrd_close(rrd_file_dn);
         return (-1);
     }
 
-    strcpy(rrd->pdp_prep->last_ds, "UNKN");
+    strcpy(rrd->pdp_prep->last_ds, "U");
 
     rrd->pdp_prep->scratch[PDP_val].u_val = 0.0;
     rrd->pdp_prep->scratch[PDP_unkn_sec_cnt].u_cnt =
         rrd->live_head->last_up % rrd->stat_head->pdp_step;
 
     for (i = 0; i < rrd->stat_head->ds_cnt; i++)
-        fwrite(rrd->pdp_prep, sizeof(pdp_prep_t), 1, rrd_file);
+        rrd_write(rrd_file_dn, rrd->pdp_prep, sizeof(pdp_prep_t));
 
-    if ((rrd->cdp_prep = calloc(1, sizeof(cdp_prep_t))) == NULL) {
+    if ((rrd->cdp_prep = (cdp_prep_t*)calloc(1, sizeof(cdp_prep_t))) == NULL) {
         rrd_set_error("allocating cdp_prep");
-        rrd_free(rrd);
-        fclose(rrd_file);
+        rrd_free2(rrd);
+        rrd_close(rrd_file_dn);
         return (-1);
     }
 
@@ -671,6 +735,7 @@ int rrd_create_fn(
     for (i = 0; i < rrd->stat_head->rra_cnt; i++) {
         switch (cf_conv(rrd->rra_def[i].cf_nam)) {
         case CF_HWPREDICT:
+        case CF_MHWPREDICT:
             init_hwpredict_cdp(rrd->cdp_prep);
             break;
         case CF_SEASONAL:
@@ -699,17 +764,17 @@ int rrd_create_fn(
         }
 
         for (ii = 0; ii < rrd->stat_head->ds_cnt; ii++) {
-            fwrite(rrd->cdp_prep, sizeof(cdp_prep_t), 1, rrd_file);
+            rrd_write(rrd_file_dn, rrd->cdp_prep, sizeof(cdp_prep_t));
         }
     }
 
     /* now, we must make sure that the rest of the rrd
        struct is properly initialized */
 
-    if ((rrd->rra_ptr = calloc(1, sizeof(rra_ptr_t))) == NULL) {
+    if ((rrd->rra_ptr = (rra_ptr_t*)calloc(1, sizeof(rra_ptr_t))) == NULL) {
         rrd_set_error("allocating rra_ptr");
-        rrd_free(rrd);
-        fclose(rrd_file);
+        rrd_free2(rrd);
+        rrd_close(rrd_file_dn);
         return (-1);
     }
 
@@ -718,60 +783,57 @@ int rrd_create_fn(
      * would occur for cur_row = 1 because rrd_update increments
      * 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;
-        fwrite(rrd->rra_ptr, sizeof(rra_ptr_t), 1, rrd_file);
+        rrd->rra_ptr->cur_row = rrd_select_initial_row(rrd_file_dn, i, &rrd->rra_def[i]);
+        rrd_write(rrd_file_dn, rrd->rra_ptr, sizeof(rra_ptr_t));
     }
-    rrd_head_size = ftell(rrd_file);
 
     /* write the empty data area */
     if ((unknown = (rrd_value_t *) malloc(512 * sizeof(rrd_value_t))) == NULL) {
         rrd_set_error("allocating unknown");
-        rrd_free(rrd);
-        fclose(rrd_file);
+        rrd_free2(rrd);
+        rrd_close(rrd_file_dn);
         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);
+        if(rrd_write(rrd_file_dn, unknown, sizeof(rrd_value_t) * min(unkn_cnt, 512)) < 0)
+        {
+            rrd_set_error("creating rrd: %s", rrd_strerror(errno));
+            return -1;
+        }
+
         unkn_cnt -= 512;
     }
     free(unknown);
-
-    /* lets see if we had an error */
-    if (ferror(rrd_file)) {
-        rrd_set_error("a file error occurred while creating '%s'", file_name);
-        fclose(rrd_file);
-        rrd_free(rrd);
-        return (-1);
+    rrd_free2(rrd);
+    if (rrd_close(rrd_file_dn) == -1) {
+        rrd_set_error("creating rrd: %s", rrd_strerror(errno));
+        return -1;
     }
-#ifdef HAVE_POSIX_FADVISE
-    /* this file is not going to be read again any time
-       soon, so we drop everything except the header portion from
-       the buffer cache. for this to work, we have to fdsync the file
-       first though. This will not be all that fast, but 'good' data
-       like other rrdfiles headers will stay in cache. Now this only works if creating
-       a single rrd file is not too large, but I assume this should not be the case
-       in general. Otherwhise we would have to sync and release while writing all
-       the unknown data. */
-    fflush(rrd_file);
-    fdatasync(fileno(rrd_file));
-    if (0 !=
-        posix_fadvise(fileno(rrd_file), rrd_head_size, 0,
-                      POSIX_FADV_DONTNEED)) {
-        rrd_set_error("setting POSIX_FADV_DONTNEED on '%s': %s", file_name,
-                      rrd_strerror(errno));
-        fclose(rrd_file);
-        return (-1);
+    /* flush all we don't need out of the cache */
+    rrd_init(&rrd_dn);
+    if((rrd_file_dn = rrd_open(file_name, &rrd_dn, RRD_READONLY)) != NULL)
+    {
+        rrd_dontneed(rrd_file_dn, &rrd_dn);
+        /* rrd_free(&rrd_dn); */
+        rrd_close(rrd_file_dn);
     }
-#endif
-
-    fclose(rrd_file);
-    rrd_free(rrd);
     return (0);
 }
+
+
+static void rrd_free2(
+    rrd_t *rrd)
+{
+    free(rrd->live_head);
+    free(rrd->stat_head);
+    free(rrd->ds_def);
+    free(rrd->rra_def);
+    free(rrd->rra_ptr);
+    free(rrd->pdp_prep);
+    free(rrd->cdp_prep);
+    free(rrd->rrd_value);
+}
+