reset errno right befor the call I want to test
[rrdtool.git] / src / rrd_restore.c
index fa8493a..369f7bd 100644 (file)
@@ -1,35 +1,45 @@
 /*****************************************************************************
- * RRDtool 1.2.99907080300  Copyright by Tobi Oetiker, 1997-2007
+ * RRDtool 1.3.2  Copyright by Tobi Oetiker, 1997-2008
  * This file:     Copyright 2008 Florian octo Forster
  * Distributed under the GPL
  *****************************************************************************
- * rrd_thread_safe.c   Contains routines used when thread safety is required
+ * rrd_restore.c   Contains logic to parse XML input and create an RRD file
  *****************************************************************************
  * $Id$
  *************************************************************************** */
-* *This program is free software;
-you can redistribute it and / or modify it
-    *
-    under the terms of the GNU General Public License as published by the Free
-    * Software Foundation;
-either    version 2 of the License, or(
-    at your option)
-* any later version.
-    * *This program is distributed in the hope that it will be useful,
-but WITHOUT * ANY WARRANTY;
-    without even the implied warranty of MERCHANTABILITY or
-        *
-        FITNESS FOR A PARTICULAR PURPOSE.
-        See the GNU General Public License for *more details. *
-        *You should have received a copy of the GNU General Public License
-        along * with this program; if not
-      , write to the Free Software Foundation, Inc., *51 Franklin St, Fifth Floor, Boston, MA 02110 - 1301 USA * *Authors:
-        *Florian octo Forster < octo at verplant.org > **/
+
+/*
+ * This program is free software; you can redistribute it and / or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (t your option)
+ * any later version.
+ * 
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110 - 1301 USA
+ *
+ * Authors:
+ *   Florian octo Forster <octo at verplant.org>
+ **/
+
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 #include <ctype.h>
-#include <unistd.h>
+
+
+#ifndef WIN32
+#      include <unistd.h>     /* for off_t */
+#else
+       typedef size_t ssize_t;
+       typedef long off_t;
+#endif 
+
 #include <fcntl.h>
 #if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
 # include <io.h>
@@ -40,13 +50,13 @@ but WITHOUT * ANY WARRANTY;
 #include "rrd_tool.h"
 #include "rrd_rpncalc.h"
 #define ARRAY_LENGTH(a) (sizeof (a) / sizeof ((a)[0]))
-    static int opt_range_check = 0;
-    static int opt_force_overwrite = 0;
+static int opt_range_check = 0;
+static int opt_force_overwrite = 0;
 
 /*
  * Auxiliary functions
  */
-    static int get_string_from_node(
+static int get_string_from_node(
     xmlDoc * doc,
     xmlNode * node,
     char *buffer,
@@ -85,18 +95,18 @@ but WITHOUT * ANY WARRANTY;
     return (0);
 }                       /* int get_string_from_node */
 
-static int get_int_from_node(
+static int get_long_from_node(
     xmlDoc * doc,
     xmlNode * node,
-    int *value)
+    long *value)
 {
-    int       temp;
+    long       temp;
     char     *str_ptr;
     char     *end_ptr;
 
     str_ptr = (char *) xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
     if (str_ptr == NULL) {
-        rrd_set_error("get_int_from_node: xmlNodeListGetString failed.");
+        rrd_set_error("get_long_from_node: xmlNodeListGetString failed.");
         return (-1);
     }
 
@@ -105,7 +115,37 @@ static int get_int_from_node(
     xmlFree(str_ptr);
 
     if (str_ptr == end_ptr) {
-        rrd_set_error("get_int_from_node: Cannot parse buffer as int: %s",
+        rrd_set_error("get_long_from_node: Cannot parse buffer as long: %s",
+                      str_ptr);
+        return (-1);
+    }
+
+    *value = temp;
+
+    return (0);
+}                       /* int get_long_from_node */
+
+static int get_ulong_from_node(
+    xmlDoc * doc,
+    xmlNode * node,
+    unsigned long *value)
+{
+    unsigned long       temp;
+    char     *str_ptr;
+    char     *end_ptr;
+
+    str_ptr = (char *) xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
+    if (str_ptr == NULL) {
+        rrd_set_error("get_ulong_from_node: xmlNodeListGetString failed.");
+        return (-1);
+    }
+
+    end_ptr = NULL;
+    temp = strtoul(str_ptr, &end_ptr, 0);
+    xmlFree(str_ptr);
+
+    if (str_ptr == end_ptr) {
+        rrd_set_error("get_ulong_from_node: Cannot parse buffer as unsigned long: %s",
                       str_ptr);
         return (-1);
     }
@@ -113,7 +153,7 @@ static int get_int_from_node(
     *value = temp;
 
     return (0);
-}                       /* int get_int_from_node */
+}                       /* int get_ulong_from_node */
 
 static int get_double_from_node(
     xmlDoc * doc,
@@ -130,6 +170,13 @@ static int get_double_from_node(
         return (-1);
     }
 
+    if (strstr(str_ptr, "NaN") != NULL)
+    {
+        *value = DNAN;   
+        xmlFree(str_ptr);
+        return 0;
+    }
+
     end_ptr = NULL;
     temp = strtod(str_ptr, &end_ptr);
     xmlFree(str_ptr);
@@ -161,7 +208,7 @@ static int value_check_range(
 
     if (((!isnan(min)) && (*rrd_value < min))
         || ((!isnan(max)) && (*rrd_value > max)))
-        *rrd_value = NAN;
+        *rrd_value = DNAN;
 
     return (0);
 }                       /* int value_check_range */
@@ -316,6 +363,10 @@ static int parse_tag_rra_cdp_prep_ds(
 
     status = 0;
     for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
+        if (atoi(rrd->stat_head->version) == 1) {
+            cdp_prep->scratch[CDP_primary_val].u_val = 0.0;
+            cdp_prep->scratch[CDP_secondary_val].u_val = 0.0;
+        }
         if ((xmlStrcmp(child->name, (const xmlChar *) "comment") == 0)
             || (xmlStrcmp(child->name, (const xmlChar *) "text") == 0))
             /* ignore */ ;
@@ -350,14 +401,14 @@ static int parse_tag_rra_cdp_prep_ds(
                                           &cdp_prep->
                                           scratch[CDP_hw_last_slope].u_val);
         else if (xmlStrcmp(child->name, (const xmlChar *) "nan_count") == 0)
-            status = get_int_from_node(doc, child,
-                                       (int *) &cdp_prep->
+            status = get_ulong_from_node(doc, child,
+                                        &cdp_prep->
                                        scratch[CDP_null_count].u_cnt);
         else if (xmlStrcmp(child->name, (const xmlChar *) "last_nan_count") ==
                  0)
             status =
-                get_int_from_node(doc, child,
-                                  (int *) &cdp_prep->
+                get_ulong_from_node(doc, child,
+                                   &cdp_prep->
                                   scratch[CDP_last_null_count].u_cnt);
         else if (xmlStrcmp(child->name, (const xmlChar *) "seasonal") == 0)
             status = get_double_from_node(doc, child,
@@ -370,8 +421,8 @@ static int parse_tag_rra_cdp_prep_ds(
                                      &cdp_prep->scratch[CDP_hw_last_seasonal].
                                      u_val);
         else if (xmlStrcmp(child->name, (const xmlChar *) "init_flag") == 0)
-            status = get_int_from_node(doc, child,
-                                       (int *) &cdp_prep->
+            status = get_ulong_from_node(doc, child,
+                                        &cdp_prep->
                                        scratch[CDP_init_seasonal].u_cnt);
         else if (xmlStrcmp(child->name, (const xmlChar *) "history") == 0)
             status = parse_tag_rra_cdp_prep_ds_history(doc, child, cdp_prep);
@@ -380,48 +431,9 @@ static int parse_tag_rra_cdp_prep_ds(
                                           &cdp_prep->scratch[CDP_val].u_val);
         else if (xmlStrcmp(child->name,
                            (const xmlChar *) "unknown_datapoints") == 0)
-            status = get_int_from_node(doc, child,
-                                       (int *) &cdp_prep->
+            status = get_ulong_from_node(doc, child,
+                                        &cdp_prep->
                                        scratch[CDP_unkn_pdp_cnt].u_cnt);
-        /*
-         * Compatibility code for 1.0.49
-         */
-        else if (xmlStrcmp(child->name, (const xmlChar *) "value") == 0) {  /* {{{ */
-            unsigned int i = 0;
-            rra_def_t *rra_def = rrd->rra_def + (rrd->stat_head->rra_cnt - 1);
-
-            while (42) {
-                if (i >= ARRAY_LENGTH(cdp_prep->scratch)) {
-                    status = -1;
-                    break;
-                }
-
-                if ((cf_conv(rra_def->cf_nam) == CF_FAILURES)
-                    || (i == CDP_unkn_pdp_cnt)
-                    || (i == CDP_null_count)
-                    || (i == CDP_last_null_count))
-                    status = get_int_from_node(doc, child,
-                                               (int *) &cdp_prep->scratch[i].
-                                               u_cnt);
-                else
-                    status = get_double_from_node(doc, child,
-                                                  &cdp_prep->scratch[i].
-                                                  u_val);
-
-                if (status != 0)
-                    break;
-
-                /* When this loops exits (sucessfully) `child' points to the last
-                 * `value' tag in the list. */
-                if ((child->next == NULL)
-                    || (xmlStrcmp(child->name, (const xmlChar *) "value") !=
-                        0))
-                    break;
-
-                child = child->next;
-                i++;
-            }
-        } /* }}} */
         else {
             rrd_set_error("parse_tag_rra_cdp_prep: Unknown tag: %s",
                           child->name);
@@ -506,8 +518,8 @@ static int parse_tag_rra_params(
                                           &rra_def->par[RRA_hw_beta].u_val);
         else if (xmlStrcmp(child->name,
                            (const xmlChar *) "dependent_rra_idx") == 0)
-            status = get_int_from_node(doc, child,
-                                       (int *) &rra_def->
+            status = get_ulong_from_node(doc, child,
+                                        &rra_def->
                                        par[RRA_dependent_rra_idx].u_cnt);
         /*
          * Parameters for CF_SEASONAL and CF_DEVSEASONAL
@@ -520,8 +532,8 @@ static int parse_tag_rra_params(
         else if (xmlStrcmp
                  (child->name, (const xmlChar *) "seasonal_smooth_idx") == 0)
             status =
-                get_int_from_node(doc, child,
-                                  (int *) &rra_def->
+                get_ulong_from_node(doc, child,
+                                   &rra_def->
                                   par[RRA_seasonal_smooth_idx].u_cnt);
         else if (xmlStrcmp(child->name, (const xmlChar *) "smoothing_window")
                  == 0)
@@ -541,14 +553,14 @@ static int parse_tag_rra_params(
             status = get_double_from_node(doc, child,
                                           &rra_def->par[RRA_delta_neg].u_val);
         else if (xmlStrcmp(child->name, (const xmlChar *) "window_len") == 0)
-            status = get_int_from_node(doc, child,
-                                       (int *) &rra_def->par[RRA_window_len].
+            status = get_ulong_from_node(doc, child,
+                                        &rra_def->par[RRA_window_len].
                                        u_cnt);
         else if (xmlStrcmp(child->name, (const xmlChar *) "failure_threshold")
                  == 0)
             status =
-                get_int_from_node(doc, child,
-                                  (int *) &rra_def->
+                get_ulong_from_node(doc, child,
+                                   &rra_def->
                                   par[RRA_failure_threshold].u_cnt);
         /*
          * Parameters for CF_AVERAGE, CF_MAXIMUM, CF_MINIMUM, and CF_LAST
@@ -572,8 +584,8 @@ static int parse_tag_rra_params(
                 if ((i == RRA_dependent_rra_idx)
                     || (i == RRA_seasonal_smooth_idx)
                     || (i == RRA_failure_threshold))
-                    status = get_int_from_node(doc, child,
-                                               (int *) &rra_def->par[i].
+                    status = get_ulong_from_node(doc, child,
+                                                &rra_def->par[i].
                                                u_cnt);
                 else
                     status = get_double_from_node(doc, child,
@@ -704,9 +716,15 @@ static int parse_tag_rra(
         else if (xmlStrcmp(child->name, (const xmlChar *) "cf") == 0)
             status = parse_tag_rra_cf(doc, child, cur_rra_def);
         else if (xmlStrcmp(child->name, (const xmlChar *) "pdp_per_row") == 0)
-            status = get_int_from_node(doc, child,
-                                       (int *) &cur_rra_def->pdp_cnt);
-        else if (xmlStrcmp(child->name, (const xmlChar *) "params") == 0)
+            status = get_ulong_from_node(doc, child,
+                                        &cur_rra_def->pdp_cnt);
+        else if (atoi(rrd->stat_head->version) == 1
+                 && xmlStrcmp(child->name, (const xmlChar *) "xff") == 0)
+            status = get_double_from_node(doc, child,
+                                          (double *) &cur_rra_def->
+                                          par[RRA_cdp_xff_val].u_val);
+        else if (atoi(rrd->stat_head->version) >= 2
+                 && xmlStrcmp(child->name, (const xmlChar *) "params") == 0)
             status = parse_tag_rra_params(doc, child, cur_rra_def);
         else if (xmlStrcmp(child->name, (const xmlChar *) "cdp_prep") == 0)
             status = parse_tag_rra_cdp_prep(doc, child, rrd, cur_cdp_prep);
@@ -721,8 +739,8 @@ static int parse_tag_rra(
             break;
     }
 
-    /* Set the RRA pointer to the last value in the archive */
-    cur_rra_ptr->cur_row = cur_rra_def->row_cnt - 1;
+    /* Set the RRA pointer to a random location */
+    cur_rra_ptr->cur_row = rrd_random() % cur_rra_def->row_cnt;
 
     return (status);
 }                       /* int parse_tag_rra */
@@ -841,8 +859,8 @@ static int parse_tag_ds(
             status = parse_tag_ds_type(doc, child, cur_ds_def);
         else if (xmlStrcmp(child->name,
                            (const xmlChar *) "minimal_heartbeat") == 0)
-            status = get_int_from_node(doc, child,
-                                       (int *) &cur_ds_def->par[DS_mrhb_cnt].
+            status = get_ulong_from_node(doc, child,
+                                        &cur_ds_def->par[DS_mrhb_cnt].
                                        u_cnt);
         else if (xmlStrcmp(child->name, (const xmlChar *) "min") == 0)
             status = get_double_from_node(doc, child,
@@ -861,8 +879,8 @@ static int parse_tag_ds(
                                           &cur_pdp_prep->scratch[PDP_val].
                                           u_val);
         else if (xmlStrcmp(child->name, (const xmlChar *) "unknown_sec") == 0)
-            status = get_int_from_node(doc, child,
-                                       (int *) &cur_pdp_prep->
+            status = get_ulong_from_node(doc, child,
+                                        &cur_pdp_prep->
                                        scratch[PDP_unkn_sec_cnt].u_cnt);
         else {
             rrd_set_error("parse_tag_ds: Unknown tag: %s", child->name);
@@ -897,11 +915,11 @@ static int parse_tag_rrd(
                                           rrd->stat_head->version,
                                           sizeof(rrd->stat_head->version));
         else if (xmlStrcmp(child->name, (const xmlChar *) "step") == 0)
-            status = get_int_from_node(doc, child,
-                                       (int *) &rrd->stat_head->pdp_step);
+            status = get_ulong_from_node(doc, child,
+                                        &rrd->stat_head->pdp_step);
         else if (xmlStrcmp(child->name, (const xmlChar *) "lastupdate") == 0)
-            status = get_int_from_node(doc, child,
-                                       (int *) &rrd->live_head->last_up);
+            status = get_long_from_node(doc, child,
+                                        &rrd->live_head->last_up);
         else if (xmlStrcmp(child->name, (const xmlChar *) "ds") == 0)
             status = parse_tag_ds(doc, child, rrd);
         else if (xmlStrcmp(child->name, (const xmlChar *) "rra") == 0)
@@ -994,7 +1012,7 @@ static int write_file(
 {
     FILE     *fh;
     unsigned int i;
-    unsigned int value_count;
+    unsigned int rra_offset;
 
     if (strcmp("-", file_name) == 0)
         fh = stdout;
@@ -1023,7 +1041,10 @@ static int write_file(
             return (-1);
         }
     }
-
+    if (atoi(rrd->stat_head->version) < 3) {
+        /* we output 3 or higher */
+        strcpy(rrd->stat_head->version, "0003");
+    }
     fwrite(rrd->stat_head, sizeof(stat_head_t), 1, fh);
     fwrite(rrd->ds_def, sizeof(ds_def_t), rrd->stat_head->ds_cnt, fh);
     fwrite(rrd->rra_def, sizeof(rra_def_t), rrd->stat_head->rra_cnt, fh);
@@ -1034,11 +1055,21 @@ static int write_file(
     fwrite(rrd->rra_ptr, sizeof(rra_ptr_t), rrd->stat_head->rra_cnt, fh);
 
     /* calculate the number of rrd_values to dump */
-    value_count = 0;
-    for (i = 0; i < rrd->stat_head->rra_cnt; i++)
-        value_count += (rrd->rra_def[i].row_cnt * rrd->stat_head->ds_cnt);
+    rra_offset = 0;
+    for (i = 0; i < rrd->stat_head->rra_cnt; i++) {
+        unsigned long num_rows = rrd->rra_def[i].row_cnt;
+        unsigned long cur_row = rrd->rra_ptr[i].cur_row;
+        unsigned long ds_cnt = rrd->stat_head->ds_cnt;
+
+        fwrite(rrd->rrd_value +
+               (rra_offset + num_rows - 1 - cur_row) * ds_cnt,
+               sizeof(rrd_value_t), (cur_row + 1) * ds_cnt, fh);
 
-    fwrite(rrd->rrd_value, sizeof(rrd_value_t), value_count, fh);
+        fwrite(rrd->rrd_value + rra_offset * ds_cnt,
+               sizeof(rrd_value_t), (num_rows - 1 - cur_row) * ds_cnt, fh);
+
+        rra_offset += num_rows;
+    }
 
     /* lets see if we had an error */
     if (ferror(fh)) {