Code

make this code windows save ???
[rrdtool-all.git] / program / src / rrd_restore.c
1 /*****************************************************************************
2  * RRDtool 1.3.8  Copyright by Tobi Oetiker, 1997-2009
3  * This file:     Copyright 2008 Florian octo Forster
4  * Distributed under the GPL
5  *****************************************************************************
6  * rrd_restore.c   Contains logic to parse XML input and create an RRD file
7  *****************************************************************************
8  * $Id$
9  *************************************************************************** */
11 /*
12  * This program is free software; you can redistribute it and / or modify it
13  * under the terms of the GNU General Public License as published by the Free
14  * Software Foundation; either version 2 of the License, or (t your option)
15  * any later version.
16  * 
17  * This program is distributed in the hope that it will be useful, but WITHOUT
18  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
20  * more details.
21  *
22  * You should have received a copy of the GNU General Public License along
23  * with this program; if not, write to the Free Software Foundation, Inc.,
24  * 51 Franklin St, Fifth Floor, Boston, MA 02110 - 1301 USA
25  *
26  * Authors:
27  *   Florian octo Forster <octo at verplant.org>
28  **/
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <ctype.h>
34 #include <fcntl.h>
36 #if defined(WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
37 #include <math.h>
38 # include <io.h>
39 # define open _open
40 # define close _close
41 #else
42 # include <unistd.h>
43 #endif
45 #include <libxml/parser.h>
46 #include "rrd_tool.h"
47 #include "rrd_rpncalc.h"
48 #define ARRAY_LENGTH(a) (sizeof (a) / sizeof ((a)[0]))
49 static int opt_range_check = 0;
50 static int opt_force_overwrite = 0;
52 /*
53  * Auxiliary functions
54  */
55 static int get_string_from_node(
56     xmlDoc * doc,
57     xmlNode * node,
58     char *buffer,
59     size_t buffer_size)
60 {
61     xmlChar  *temp0;
62     char     *begin_ptr;
63     char     *end_ptr;
65     temp0 = xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
66     if (temp0 == NULL) {
67         rrd_set_error("get_string_from_node: xmlNodeListGetString failed.");
68         return (-1);
69     }
71     begin_ptr = (char *) temp0;
72     while ((begin_ptr[0] != 0) && (isspace(begin_ptr[0])))
73         begin_ptr++;
75     if (begin_ptr[0] == 0) {
76         xmlFree(temp0);
77         buffer[0] = 0;
78         return (0);
79     }
81     end_ptr = begin_ptr;
82     while ((end_ptr[0] != 0) && (!isspace(end_ptr[0])))
83         end_ptr++;
84     end_ptr[0] = 0;
86     strncpy(buffer, begin_ptr, buffer_size);
87     buffer[buffer_size - 1] = 0;
89     xmlFree(temp0);
91     return (0);
92 }                       /* int get_string_from_node */
94 static int get_long_from_node(
95     xmlDoc * doc,
96     xmlNode * node,
97     long *value)
98 {
99     long       temp;
100     char     *str_ptr;
101     char     *end_ptr;
103     str_ptr = (char *) xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
104     if (str_ptr == NULL) {
105         rrd_set_error("get_long_from_node: xmlNodeListGetString failed.");
106         return (-1);
107     }
109     end_ptr = NULL;
110     temp = strtol(str_ptr, &end_ptr, 0);
111     xmlFree(str_ptr);
113     if (str_ptr == end_ptr) {
114         rrd_set_error("get_long_from_node: Cannot parse buffer as long: %s",
115                       str_ptr);
116         return (-1);
117     }
119     *value = temp;
121     return (0);
122 }                       /* int get_long_from_node */
124 static int get_ulong_from_node(
125     xmlDoc * doc,
126     xmlNode * node,
127     unsigned long *value)
129     unsigned long       temp;
130     char     *str_ptr;
131     char     *end_ptr;
133     str_ptr = (char *) xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
134     if (str_ptr == NULL) {
135         rrd_set_error("get_ulong_from_node: xmlNodeListGetString failed.");
136         return (-1);
137     }
139     end_ptr = NULL;
140     temp = strtoul(str_ptr, &end_ptr, 0);
141     xmlFree(str_ptr);
143     if (str_ptr == end_ptr) {
144         rrd_set_error("get_ulong_from_node: Cannot parse buffer as unsigned long: %s",
145                       str_ptr);
146         return (-1);
147     }
149     *value = temp;
151     return (0);
152 }                       /* int get_ulong_from_node */
155 #ifdef WIN32
156 /* Gross Hack Alert */
157 #if _MSC_VER < 1300
158 #define strtoll(p, e, b) ((*(e) = (char*)(p) + (((b) == 10) ? strspn((p), "0123456789") : 0)), _atoi64(p))
159 #else
160 #define strtoll(p, e, b) _strtoi64(p, e, b)
161 #endif
162 #endif
164 static int get_llong_from_node(
165     xmlDoc * doc,
166     xmlNode * node,
167     long long *value)
169     long long       temp;
170     char     *str_ptr;
171     char     *end_ptr;
173     str_ptr = (char *) xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
174     if (str_ptr == NULL) {
175         rrd_set_error("get_llong_from_node: xmlNodeListGetString failed.");
176         return (-1);
177     }
179     end_ptr = NULL;
180     temp = strtoll(str_ptr, &end_ptr, 10);
181     xmlFree(str_ptr);
183     if (str_ptr == end_ptr) {
184         rrd_set_error("get_llong_from_node: Cannot parse buffer as unsigned long long: %s",
185                       str_ptr);
186         return (-1);
187     }
189     *value = temp;
191     return (0);
192 }                       /* int get_llong_from_node */
194 static int get_double_from_node(
195     xmlDoc * doc,
196     xmlNode * node,
197     double *value)
199     double    temp;
200     char     *str_ptr;
201     char     *end_ptr;
203     str_ptr = (char *) xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
204     if (str_ptr == NULL) {
205         rrd_set_error("get_double_from_node: xmlNodeListGetString failed.");
206         return (-1);
207     }
209     if (strstr(str_ptr, "NaN") != NULL)
210     {
211         *value = DNAN;
212         xmlFree(str_ptr);
213         return 0;
214     }
216     end_ptr = NULL;
217     temp = strtod(str_ptr, &end_ptr);
218     xmlFree(str_ptr);
220     if (str_ptr == end_ptr) {
221         rrd_set_error
222             ("get_double_from_node: Cannot parse buffer as double: %s",
223              str_ptr);
224         return (-1);
225     }
227     *value = temp;
229     return (0);
230 }                       /* int get_double_from_node */
232 static int value_check_range(
233     rrd_value_t *rrd_value,
234     const ds_def_t *ds_def)
236     double    min;
237     double    max;
239     if (opt_range_check == 0)
240         return (0);
242     min = ds_def->par[DS_min_val].u_val;
243     max = ds_def->par[DS_max_val].u_val;
245     if (((!isnan(min)) && (*rrd_value < min))
246         || ((!isnan(max)) && (*rrd_value > max)))
247         *rrd_value = DNAN;
249     return (0);
250 }                       /* int value_check_range */
252 /*
253  * Parse the <database> block within an RRA definition
254  */
255 static int parse_tag_rra_database_row(
256     xmlDoc * doc,
257     xmlNode * node,
258     rrd_t *rrd,
259     rrd_value_t *rrd_value)
261     unsigned int values_count = 0;
262     xmlNode  *child;
263     int       status;
265     status = 0;
266     for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
267         if ((xmlStrcmp(child->name, (const xmlChar *) "comment") == 0)
268             || (xmlStrcmp(child->name, (const xmlChar *) "text") == 0))
269             /* ignore */ ;
270         else if (xmlStrcmp(child->name, (const xmlChar *) "v") == 0) {
271             if (values_count < rrd->stat_head->ds_cnt) {
272                 status =
273                     get_double_from_node(doc, child,
274                                          rrd_value + values_count);
275                 if (status == 0)
276                     value_check_range(rrd_value + values_count,
277                                       rrd->ds_def + values_count);
278             }
280             values_count++;
281         } else {
282             rrd_set_error("parse_tag_rra_database_row: Unknown tag: %s",
283                           child->name);
284             status = -1;
285         }
287         if (status != 0)
288             break;
289     }                   /* for (child = node->xmlChildrenNode) */
291     if (values_count != rrd->stat_head->ds_cnt) {
292         rrd_set_error("parse_tag_rra_database_row: Row has %u values "
293                       "and RRD has %lu data sources.",
294                       values_count, rrd->stat_head->ds_cnt);
295         status = -1;
296     }
298     return (status);
299 }                       /* int parse_tag_rra_database_row */
301 static int parse_tag_rra_database(
302     xmlDoc * doc,
303     xmlNode * node,
304     rrd_t *rrd)
306     rra_def_t *cur_rra_def;
307     unsigned int total_row_cnt;
308     xmlNode  *child;
309     int       status;
310     int       i;
312     total_row_cnt = 0;
313     for (i = 0; i < (((int) rrd->stat_head->rra_cnt) - 1); i++)
314         total_row_cnt += rrd->rra_def[i].row_cnt;
316     cur_rra_def = rrd->rra_def + i;
318     status = 0;
319     for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
320         if ((xmlStrcmp(child->name, (const xmlChar *) "comment") == 0)
321             || (xmlStrcmp(child->name, (const xmlChar *) "text") == 0))
322             /* ignore */ ;
323         else if (xmlStrcmp(child->name, (const xmlChar *) "row") == 0) {
324             rrd_value_t *temp;
325             rrd_value_t *cur_rrd_value;
326             unsigned int total_values_count = rrd->stat_head->ds_cnt
327                 * (total_row_cnt + 1);
329             /* Allocate space for the new values.. */
330             temp = (rrd_value_t *) realloc(rrd->rrd_value,
331                                            sizeof(rrd_value_t) *
332                                            total_values_count);
333             if (temp == NULL) {
334                 rrd_set_error("parse_tag_rra_database: realloc failed.");
335                 status = -1;
336                 break;
337             }
338             rrd->rrd_value = temp;
339             cur_rrd_value = rrd->rrd_value
340                 + (rrd->stat_head->ds_cnt * total_row_cnt);
341             memset(cur_rrd_value, '\0',
342                    sizeof(rrd_value_t) * rrd->stat_head->ds_cnt);
343             total_row_cnt++;
344             cur_rra_def->row_cnt++;
346             status =
347                 parse_tag_rra_database_row(doc, child, rrd, cur_rrd_value);
348         } /* if (xmlStrcmp (child->name, (const xmlChar *) "row") == 0) */
349         else {
350             rrd_set_error("parse_tag_rra_database: Unknown tag: %s",
351                           child->name);
352             status = -1;
353         }
355         if (status != 0)
356             break;
357     }                   /* for (child = node->xmlChildrenNode) */
359     return (status);
360 }                       /* int parse_tag_rra_database */
362 /*
363  * Parse the <cdp_prep> block within an RRA definition
364  */
365 static int parse_tag_rra_cdp_prep_ds_history(
366     xmlDoc * doc,
367     xmlNode * node,
368     cdp_prep_t *cdp_prep)
370     /* Make `history_buffer' the same size as the scratch area, plus the
371      * terminating NULL byte. */
372     char      history_buffer[sizeof(((cdp_prep_t *)0)->scratch) + 1];
373     char     *history_ptr;
374     int       status;
375     int       i;
377     status = get_string_from_node(doc, node,
378                                   history_buffer, sizeof(history_buffer));
379     if (status != 0)
380         return (-1);
382     history_ptr = (char *) (&cdp_prep->scratch[0]);
383     for (i = 0; history_buffer[i] != '\0'; i++)
384         history_ptr[i] = (history_buffer[i] == '1') ? 1 : 0;
386     return (0);
387 }                       /* int parse_tag_rra_cdp_prep_ds_history */
389 static int parse_tag_rra_cdp_prep_ds(
390     xmlDoc * doc,
391     xmlNode * node,
392     rrd_t *rrd,
393     cdp_prep_t *cdp_prep)
395     xmlNode  *child;
396     int       status;
398     memset(cdp_prep, '\0', sizeof(cdp_prep_t));
400     status = 0;
401     for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
402         if (atoi(rrd->stat_head->version) == 1) {
403             cdp_prep->scratch[CDP_primary_val].u_val = 0.0;
404             cdp_prep->scratch[CDP_secondary_val].u_val = 0.0;
405         }
406         if ((xmlStrcmp(child->name, (const xmlChar *) "comment") == 0)
407             || (xmlStrcmp(child->name, (const xmlChar *) "text") == 0))
408             /* ignore */ ;
409         else if (xmlStrcmp(child->name, (const xmlChar *) "primary_value") ==
410                  0)
411             status =
412                 get_double_from_node(doc, child,
413                                      &cdp_prep->scratch[CDP_primary_val].
414                                      u_val);
415         else if (xmlStrcmp(child->name, (const xmlChar *) "secondary_value")
416                  == 0)
417             status =
418                 get_double_from_node(doc, child,
419                                      &cdp_prep->scratch[CDP_secondary_val].
420                                      u_val);
421         else if (xmlStrcmp(child->name, (const xmlChar *) "intercept") == 0)
422             status = get_double_from_node(doc, child,
423                                           &cdp_prep->
424                                           scratch[CDP_hw_intercept].u_val);
425         else if (xmlStrcmp(child->name, (const xmlChar *) "last_intercept") ==
426                  0)
427             status =
428                 get_double_from_node(doc, child,
429                                      &cdp_prep->
430                                      scratch[CDP_hw_last_intercept].u_val);
431         else if (xmlStrcmp(child->name, (const xmlChar *) "slope") == 0)
432             status = get_double_from_node(doc, child,
433                                           &cdp_prep->scratch[CDP_hw_slope].
434                                           u_val);
435         else if (xmlStrcmp(child->name, (const xmlChar *) "last_slope") == 0)
436             status = get_double_from_node(doc, child,
437                                           &cdp_prep->
438                                           scratch[CDP_hw_last_slope].u_val);
439         else if (xmlStrcmp(child->name, (const xmlChar *) "nan_count") == 0)
440             status = get_ulong_from_node(doc, child,
441                                         &cdp_prep->
442                                        scratch[CDP_null_count].u_cnt);
443         else if (xmlStrcmp(child->name, (const xmlChar *) "last_nan_count") ==
444                  0)
445             status =
446                 get_ulong_from_node(doc, child,
447                                    &cdp_prep->
448                                   scratch[CDP_last_null_count].u_cnt);
449         else if (xmlStrcmp(child->name, (const xmlChar *) "seasonal") == 0)
450             status = get_double_from_node(doc, child,
451                                           &cdp_prep->scratch[CDP_hw_seasonal].
452                                           u_val);
453         else if (xmlStrcmp(child->name, (const xmlChar *) "last_seasonal") ==
454                  0)
455             status =
456                 get_double_from_node(doc, child,
457                                      &cdp_prep->scratch[CDP_hw_last_seasonal].
458                                      u_val);
459         else if (xmlStrcmp(child->name, (const xmlChar *) "init_flag") == 0)
460             status = get_ulong_from_node(doc, child,
461                                         &cdp_prep->
462                                        scratch[CDP_init_seasonal].u_cnt);
463         else if (xmlStrcmp(child->name, (const xmlChar *) "history") == 0)
464             status = parse_tag_rra_cdp_prep_ds_history(doc, child, cdp_prep);
465         else if (xmlStrcmp(child->name, (const xmlChar *) "value") == 0)
466             status = get_double_from_node(doc, child,
467                                           &cdp_prep->scratch[CDP_val].u_val);
468         else if (xmlStrcmp(child->name,
469                            (const xmlChar *) "unknown_datapoints") == 0)
470             status = get_ulong_from_node(doc, child,
471                                         &cdp_prep->
472                                        scratch[CDP_unkn_pdp_cnt].u_cnt);
473         else {
474             rrd_set_error("parse_tag_rra_cdp_prep: Unknown tag: %s",
475                           child->name);
476             status = -1;
477         }
479         if (status != 0)
480             break;
481     }
483     return (status);
484 }                       /* int parse_tag_rra_cdp_prep_ds */
486 static int parse_tag_rra_cdp_prep(
487     xmlDoc * doc,
488     xmlNode * node,
489     rrd_t *rrd,
490     cdp_prep_t *cdp_prep)
492     xmlNode  *child;
493     int       status;
495     unsigned int ds_count = 0;
497     status = 0;
498     for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
499         if ((xmlStrcmp(child->name, (const xmlChar *) "comment") == 0)
500             || (xmlStrcmp(child->name, (const xmlChar *) "text") == 0))
501             /* ignore */ ;
502         else if (xmlStrcmp(child->name, (const xmlChar *) "ds") == 0) {
503             if (ds_count >= rrd->stat_head->ds_cnt)
504                 status = -1;
505             else {
506                 status = parse_tag_rra_cdp_prep_ds(doc, child, rrd,
507                                                    cdp_prep + ds_count);
508                 ds_count++;
509             }
510         } else {
511             rrd_set_error("parse_tag_rra_cdp_prep: Unknown tag: %s",
512                           child->name);
513             status = -1;
514         }
516         if (status != 0)
517             break;
518     }
520     if (ds_count != rrd->stat_head->ds_cnt) {
521         rrd_set_error("parse_tag_rra_cdp_prep: There are %i data sources in "
522                       "the RRD file, but %i in this cdp_prep block!",
523                       (int) rrd->stat_head->ds_cnt, ds_count);
524         status = -1;
525     }
527     return (status);
528 }                       /* int parse_tag_rra_cdp_prep */
530 /*
531  * Parse the <params> block within an RRA definition
532  */
533 static int parse_tag_rra_params(
534     xmlDoc * doc,
535     xmlNode * node,
536     rra_def_t *rra_def)
538     xmlNode  *child;
539     int       status;
541     status = 0;
542     for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
543         if ((xmlStrcmp(child->name, (const xmlChar *) "comment") == 0)
544             || (xmlStrcmp(child->name, (const xmlChar *) "text") == 0))
545             /* ignore */ ;
546         /*
547          * Parameters for CF_HWPREDICT
548          */
549         else if (xmlStrcmp(child->name, (const xmlChar *) "hw_alpha") == 0)
550             status = get_double_from_node(doc, child,
551                                           &rra_def->par[RRA_hw_alpha].u_val);
552         else if (xmlStrcmp(child->name, (const xmlChar *) "hw_beta") == 0)
553             status = get_double_from_node(doc, child,
554                                           &rra_def->par[RRA_hw_beta].u_val);
555         else if (xmlStrcmp(child->name,
556                            (const xmlChar *) "dependent_rra_idx") == 0)
557             status = get_ulong_from_node(doc, child,
558                                         &rra_def->
559                                        par[RRA_dependent_rra_idx].u_cnt);
560         /*
561          * Parameters for CF_SEASONAL and CF_DEVSEASONAL
562          */
563         else if (xmlStrcmp(child->name, (const xmlChar *) "seasonal_gamma") ==
564                  0)
565             status =
566                 get_double_from_node(doc, child,
567                                      &rra_def->par[RRA_seasonal_gamma].u_val);
568         else if (xmlStrcmp
569                  (child->name, (const xmlChar *) "seasonal_smooth_idx") == 0)
570             status =
571                 get_ulong_from_node(doc, child,
572                                    &rra_def->
573                                   par[RRA_seasonal_smooth_idx].u_cnt);
574         else if (xmlStrcmp(child->name, (const xmlChar *) "smoothing_window")
575                  == 0)
576             status =
577                 get_double_from_node(doc, child,
578                                      &rra_def->
579                                      par[RRA_seasonal_smoothing_window].
580                                      u_val);
581         /* else if (dependent_rra_idx) ...; */
582         /*
583          * Parameters for CF_FAILURES
584          */
585         else if (xmlStrcmp(child->name, (const xmlChar *) "delta_pos") == 0)
586             status = get_double_from_node(doc, child,
587                                           &rra_def->par[RRA_delta_pos].u_val);
588         else if (xmlStrcmp(child->name, (const xmlChar *) "delta_neg") == 0)
589             status = get_double_from_node(doc, child,
590                                           &rra_def->par[RRA_delta_neg].u_val);
591         else if (xmlStrcmp(child->name, (const xmlChar *) "window_len") == 0)
592             status = get_ulong_from_node(doc, child,
593                                         &rra_def->par[RRA_window_len].
594                                        u_cnt);
595         else if (xmlStrcmp(child->name, (const xmlChar *) "failure_threshold")
596                  == 0)
597             status =
598                 get_ulong_from_node(doc, child,
599                                    &rra_def->
600                                   par[RRA_failure_threshold].u_cnt);
601         /*
602          * Parameters for CF_AVERAGE, CF_MAXIMUM, CF_MINIMUM, and CF_LAST
603          */
604         else if (xmlStrcmp(child->name, (const xmlChar *) "xff") == 0)
605             status = get_double_from_node(doc, child,
606                                           &rra_def->par[RRA_cdp_xff_val].
607                                           u_val);
608         /*
609          * Compatibility code for 1.0.49
610          */
611         else if (xmlStrcmp(child->name, (const xmlChar *) "value") == 0) {  /* {{{ */
612             unsigned int i = 0;
614             while (42) {
615                 if (i >= ARRAY_LENGTH(rra_def->par)) {
616                     status = -1;
617                     break;
618                 }
620                 if ((i == RRA_dependent_rra_idx)
621                     || (i == RRA_seasonal_smooth_idx)
622                     || (i == RRA_failure_threshold))
623                     status = get_ulong_from_node(doc, child,
624                                                 &rra_def->par[i].
625                                                u_cnt);
626                 else
627                     status = get_double_from_node(doc, child,
628                                                   &rra_def->par[i].u_val);
630                 if (status != 0)
631                     break;
633                 /* When this loops exits (sucessfully) `child' points to the last
634                  * `value' tag in the list. */
635                 if ((child->next == NULL)
636                     || (xmlStrcmp(child->name, (const xmlChar *) "value") !=
637                         0))
638                     break;
640                 child = child->next;
641                 i++;
642             }
643         } /* }}} */
644         else {
645             rrd_set_error("parse_tag_rra_params: Unknown tag: %s",
646                           child->name);
647             status = -1;
648         }
650         if (status != 0)
651             break;
652     }
654     return (status);
655 }                       /* int parse_tag_rra_params */
657 /*
658  * Parse an RRA definition
659  */
660 static int parse_tag_rra_cf(
661     xmlDoc * doc,
662     xmlNode * node,
663     rra_def_t *rra_def)
665     int       status;
667     status = get_string_from_node(doc, node,
668                                   rra_def->cf_nam, sizeof(rra_def->cf_nam));
669     if (status != 0)
670         return (-1);
672     status = cf_conv(rra_def->cf_nam);
673     if (status == -1) {
674         rrd_set_error("parse_tag_rra_cf: Unknown consolidation function: %s",
675                       rra_def->cf_nam);
676         return (-1);
677     }
679     return (0);
680 }                       /* int parse_tag_rra_cf */
682 static int parse_tag_rra(
683     xmlDoc * doc,
684     xmlNode * node,
685     rrd_t *rrd)
687     xmlNode  *child;
688     int       status;
690     rra_def_t *cur_rra_def;
691     cdp_prep_t *cur_cdp_prep;
692     rra_ptr_t *cur_rra_ptr;
694     /* Allocate more rra_def space for this RRA */
695     {                   /* {{{ */
696         rra_def_t *temp;
698         temp = (rra_def_t *) realloc(rrd->rra_def,
699                                      sizeof(rra_def_t) *
700                                      (rrd->stat_head->rra_cnt + 1));
701         if (temp == NULL) {
702             rrd_set_error("parse_tag_rra: realloc failed.");
703             return (-1);
704         }
705         rrd->rra_def = temp;
706         cur_rra_def = rrd->rra_def + rrd->stat_head->rra_cnt;
707         memset(cur_rra_def, '\0', sizeof(rra_def_t));
708     }                   /* }}} */
710     /* allocate cdp_prep_t */
711     {                   /* {{{ */
712         cdp_prep_t *temp;
714         temp = (cdp_prep_t *) realloc(rrd->cdp_prep, sizeof(cdp_prep_t)
715                                       * rrd->stat_head->ds_cnt
716                                       * (rrd->stat_head->rra_cnt + 1));
717         if (temp == NULL) {
718             rrd_set_error("parse_tag_rra: realloc failed.");
719             return (-1);
720         }
721         rrd->cdp_prep = temp;
722         cur_cdp_prep = rrd->cdp_prep
723             + (rrd->stat_head->ds_cnt * rrd->stat_head->rra_cnt);
724         memset(cur_cdp_prep, '\0',
725                sizeof(cdp_prep_t) * rrd->stat_head->ds_cnt);
726     }                   /* }}} */
728     /* allocate rra_ptr_t */
729     {                   /* {{{ */
730         rra_ptr_t *temp;
732         temp = (rra_ptr_t *) realloc(rrd->rra_ptr,
733                                      sizeof(rra_ptr_t) *
734                                      (rrd->stat_head->rra_cnt + 1));
735         if (temp == NULL) {
736             rrd_set_error("parse_tag_rra: realloc failed.");
737             return (-1);
738         }
739         rrd->rra_ptr = temp;
740         cur_rra_ptr = rrd->rra_ptr + rrd->stat_head->rra_cnt;
741         memset(cur_rra_ptr, '\0', sizeof(rra_ptr_t));
742     }                   /* }}} */
744     /* All space successfully allocated, increment number of RRAs. */
745     rrd->stat_head->rra_cnt++;
747     status = 0;
748     for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
749         if ((xmlStrcmp(child->name, (const xmlChar *) "comment") == 0)
750             || (xmlStrcmp(child->name, (const xmlChar *) "text") == 0))
751             /* ignore */ ;
752         else if (xmlStrcmp(child->name, (const xmlChar *) "cf") == 0)
753             status = parse_tag_rra_cf(doc, child, cur_rra_def);
754         else if (xmlStrcmp(child->name, (const xmlChar *) "pdp_per_row") == 0)
755             status = get_ulong_from_node(doc, child,
756                                         &cur_rra_def->pdp_cnt);
757         else if (atoi(rrd->stat_head->version) == 1
758                  && xmlStrcmp(child->name, (const xmlChar *) "xff") == 0)
759             status = get_double_from_node(doc, child,
760                                           (double *) &cur_rra_def->
761                                           par[RRA_cdp_xff_val].u_val);
762         else if (atoi(rrd->stat_head->version) >= 2
763                  && xmlStrcmp(child->name, (const xmlChar *) "params") == 0)
764             status = parse_tag_rra_params(doc, child, cur_rra_def);
765         else if (xmlStrcmp(child->name, (const xmlChar *) "cdp_prep") == 0)
766             status = parse_tag_rra_cdp_prep(doc, child, rrd, cur_cdp_prep);
767         else if (xmlStrcmp(child->name, (const xmlChar *) "database") == 0)
768             status = parse_tag_rra_database(doc, child, rrd);
769         else {
770             rrd_set_error("parse_tag_rra: Unknown tag: %s", child->name);
771             status = -1;
772         }
774         if (status != 0)
775             break;
776     }
778     /* Set the RRA pointer to a random location */
779 #ifdef WIN32
780     cur_rra_ptr->cur_row = rand() % cur_rra_def->row_cnt;
781 #else
782     cur_rra_ptr->cur_row = random() % cur_rra_def->row_cnt;
783 #endif
785     return (status);
786 }                       /* int parse_tag_rra */
788 /*
789  * Parse a DS definition
790  */
791 static int parse_tag_ds_cdef(
792     xmlDoc * doc,
793     xmlNode * node,
794     rrd_t *rrd)
796     char      buffer[1024];
797     int       status;
799     status = get_string_from_node(doc, node, buffer, sizeof(buffer));
800     if (status != 0)
801         return (-1);
803     /* We're always working on the last DS that has been added to the structure
804      * when we get here */
805     parseCDEF_DS(buffer, rrd, rrd->stat_head->ds_cnt - 1);
807     return (0);
808 }                       /* int parse_tag_ds_cdef */
810 static int parse_tag_ds_type(
811     xmlDoc * doc,
812     xmlNode * node,
813     ds_def_t *ds_def)
815     int       status;
817     status = get_string_from_node(doc, node,
818                                   ds_def->dst, sizeof(ds_def->dst));
819     if (status != 0)
820         return (-1);
822     status = dst_conv(ds_def->dst);
823     if (status == -1) {
824         rrd_set_error("parse_tag_ds_type: Unknown data source type: %s",
825                       ds_def->dst);
826         return (-1);
827     }
829     return (0);
830 }                       /* int parse_tag_ds_type */
832 static int parse_tag_ds(
833     xmlDoc * doc,
834     xmlNode * node,
835     rrd_t *rrd)
837     xmlNode  *child;
838     int       status;
840     ds_def_t *cur_ds_def;
841     pdp_prep_t *cur_pdp_prep;
843     /*
844      * If there are DS definitions after RRA definitions the number of values,
845      * cdp_prep areas and so on will be calculated wrong. Thus, enforce a
846      * specific order in this case.
847      */
848     if (rrd->stat_head->rra_cnt > 0) {
849         rrd_set_error("parse_tag_ds: All data source definitions MUST "
850                       "precede the RRA definitions!");
851         return (-1);
852     }
854     /* Allocate space for the new DS definition */
855     {                   /* {{{ */
856         ds_def_t *temp;
858         temp = (ds_def_t *) realloc(rrd->ds_def,
859                                     sizeof(ds_def_t) *
860                                     (rrd->stat_head->ds_cnt + 1));
861         if (temp == NULL) {
862             rrd_set_error("parse_tag_ds: malloc failed.");
863             return (-1);
864         }
865         rrd->ds_def = temp;
866         cur_ds_def = rrd->ds_def + rrd->stat_head->ds_cnt;
867         memset(cur_ds_def, '\0', sizeof(ds_def_t));
868     }                   /* }}} */
870     /* Allocate pdp_prep space for the new DS definition */
871     {                   /* {{{ */
872         pdp_prep_t *temp;
874         temp = (pdp_prep_t *) realloc(rrd->pdp_prep,
875                                       sizeof(pdp_prep_t) *
876                                       (rrd->stat_head->ds_cnt + 1));
877         if (temp == NULL) {
878             rrd_set_error("parse_tag_ds: malloc failed.");
879             return (-1);
880         }
881         rrd->pdp_prep = temp;
882         cur_pdp_prep = rrd->pdp_prep + rrd->stat_head->ds_cnt;
883         memset(cur_pdp_prep, '\0', sizeof(pdp_prep_t));
884     }                   /* }}} */
886     /* All allocations successful, let's increment the number of DSes. */
887     rrd->stat_head->ds_cnt++;
889     status = 0;
890     for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
891         if ((xmlStrcmp(child->name, (const xmlChar *) "comment") == 0)
892             || (xmlStrcmp(child->name, (const xmlChar *) "text") == 0))
893             /* ignore */ ;
894         else if (xmlStrcmp(child->name, (const xmlChar *) "name") == 0)
895             status = get_string_from_node(doc, child,
896                                           cur_ds_def->ds_nam,
897                                           sizeof(cur_ds_def->ds_nam));
898         else if (xmlStrcmp(child->name, (const xmlChar *) "type") == 0)
899             status = parse_tag_ds_type(doc, child, cur_ds_def);
900         else if (xmlStrcmp(child->name,
901                            (const xmlChar *) "minimal_heartbeat") == 0)
902             status = get_ulong_from_node(doc, child,
903                                         &cur_ds_def->par[DS_mrhb_cnt].
904                                        u_cnt);
905         else if (xmlStrcmp(child->name, (const xmlChar *) "min") == 0)
906             status = get_double_from_node(doc, child,
907                                           &cur_ds_def->par[DS_min_val].u_val);
908         else if (xmlStrcmp(child->name, (const xmlChar *) "max") == 0)
909             status = get_double_from_node(doc, child,
910                                           &cur_ds_def->par[DS_max_val].u_val);
911         else if (xmlStrcmp(child->name, (const xmlChar *) "cdef") == 0)
912             status = parse_tag_ds_cdef(doc, child, rrd);
913         else if (xmlStrcmp(child->name, (const xmlChar *) "last_ds") == 0)
914             status = get_string_from_node(doc, child,
915                                           cur_pdp_prep->last_ds,
916                                           sizeof(cur_pdp_prep->last_ds));
917         else if (xmlStrcmp(child->name, (const xmlChar *) "value") == 0)
918             status = get_double_from_node(doc, child,
919                                           &cur_pdp_prep->scratch[PDP_val].
920                                           u_val);
921         else if (xmlStrcmp(child->name, (const xmlChar *) "unknown_sec") == 0)
922             status = get_ulong_from_node(doc, child,
923                                         &cur_pdp_prep->
924                                        scratch[PDP_unkn_sec_cnt].u_cnt);
925         else {
926             rrd_set_error("parse_tag_ds: Unknown tag: %s", child->name);
927             status = -1;
928         }
930         if (status != 0)
931             break;
932     }
934     return (status);
935 }                       /* int parse_tag_ds */
937 /*
938  * Parse root nodes
939  */
940 static int parse_tag_rrd(
941     xmlDoc * doc,
942     xmlNode * node,
943     rrd_t *rrd)
945     xmlNode  *child;
946     int       status;
948     status = 0;
949     for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
950         if ((xmlStrcmp(child->name, (const xmlChar *) "comment") == 0)
951             || (xmlStrcmp(child->name, (const xmlChar *) "text") == 0))
952             /* ignore */ ;
953         else if (xmlStrcmp(child->name, (const xmlChar *) "version") == 0)
954             status = get_string_from_node(doc, child,
955                                           rrd->stat_head->version,
956                                           sizeof(rrd->stat_head->version));
957         else if (xmlStrcmp(child->name, (const xmlChar *) "step") == 0)
958             status = get_ulong_from_node(doc, child,
959                                         &rrd->stat_head->pdp_step);
960         else if (xmlStrcmp(child->name, (const xmlChar *) "lastupdate") == 0)
961             if (sizeof(time_t) == sizeof(long)) {
962                status = get_long_from_node(doc, child, (long *)&rrd->live_head->last_up);
963             }
964             else if (sizeof(time_t) == sizeof(long long)) {
965                status = get_llong_from_node(doc, child, (long long *)&rrd->live_head->last_up);
966             }
967             else {
968                rrd_set_error("can't convert to time_t ...", child->name);
969                status = -1;    
970             }
971         else if (xmlStrcmp(child->name, (const xmlChar *) "ds") == 0)
972             status = parse_tag_ds(doc, child, rrd);
973         else if (xmlStrcmp(child->name, (const xmlChar *) "rra") == 0)
974             status = parse_tag_rra(doc, child, rrd);
975         else {
976             rrd_set_error("parse_tag_rrd: Unknown tag: %s", child->name);
977             status = -1;
978         }
980         if (status != 0)
981             break;
982     }
984     return (status);
985 }                       /* int parse_tag_rrd */
987 static rrd_t *parse_file(
988     const char *filename)
990     xmlDoc   *doc;
991     xmlNode  *cur;
992     int       status;
994     rrd_t    *rrd;
996     doc = xmlParseFile(filename);
997     if (doc == NULL) {
998         rrd_set_error("Document not parsed successfully.");
999         return (NULL);
1000     }
1002     cur = xmlDocGetRootElement(doc);
1003     if (cur == NULL) {
1004         rrd_set_error("Document is empty.");
1005         xmlFreeDoc(doc);
1006         return (NULL);
1007     }
1009     if (xmlStrcmp(cur->name, (const xmlChar *) "rrd") != 0) {
1010         rrd_set_error
1011             ("Document of the wrong type, root node is not \"rrd\".");
1012         xmlFreeDoc(doc);
1013         return (NULL);
1014     }
1016     rrd = (rrd_t *) malloc(sizeof(rrd_t));
1017     if (rrd == NULL) {
1018         rrd_set_error("parse_file: malloc failed.");
1019         xmlFreeDoc(doc);
1020         return (NULL);
1021     }
1022     memset(rrd, '\0', sizeof(rrd_t));
1024     rrd->stat_head = (stat_head_t *) malloc(sizeof(stat_head_t));
1025     if (rrd->stat_head == NULL) {
1026         rrd_set_error("parse_tag_rrd: malloc failed.");
1027         xmlFreeDoc(doc);
1028         free(rrd);
1029         return (NULL);
1030     }
1031     memset(rrd->stat_head, '\0', sizeof(stat_head_t));
1033     strncpy(rrd->stat_head->cookie, "RRD", sizeof(rrd->stat_head->cookie));
1034     rrd->stat_head->float_cookie = FLOAT_COOKIE;
1036     rrd->live_head = (live_head_t *) malloc(sizeof(live_head_t));
1037     if (rrd->live_head == NULL) {
1038         rrd_set_error("parse_tag_rrd: malloc failed.");
1039         xmlFreeDoc(doc);
1040         free(rrd->stat_head);
1041         free(rrd);
1042         return (NULL);
1043     }
1044     memset(rrd->live_head, '\0', sizeof(live_head_t));
1046     status = parse_tag_rrd(doc, cur, rrd);
1048     xmlFreeDoc(doc);
1049     if (status != 0) {
1050         rrd_free(rrd);
1051         rrd = NULL;
1052     }
1054     return (rrd);
1055 }                       /* rrd_t *parse_file */
1057 static int write_file(
1058     const char *file_name,
1059     rrd_t *rrd)
1061     FILE     *fh;
1062     unsigned int i;
1063     unsigned int rra_offset;
1065     if (strcmp("-", file_name) == 0)
1066         fh = stdout;
1067     else {
1068         int       fd_flags = O_WRONLY | O_CREAT;
1069         int       fd;
1071 #if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
1072         fd_flags |= O_BINARY;
1073 #endif
1075         if (opt_force_overwrite == 0)
1076             fd_flags |= O_EXCL;
1078         fd = open(file_name, fd_flags, 0666);
1079         if (fd == -1) {
1080             rrd_set_error("creating '%s': %s", file_name,
1081                           rrd_strerror(errno));
1082             return (-1);
1083         }
1085         fh = fdopen(fd, "wb");
1086         if (fh == NULL) {
1087             rrd_set_error("fdopen failed: %s", rrd_strerror(errno));
1088             close(fd);
1089             return (-1);
1090         }
1091     }
1092     if (atoi(rrd->stat_head->version) < 3) {
1093         /* we output 3 or higher */
1094         strcpy(rrd->stat_head->version, "0003");
1095     }
1096     fwrite(rrd->stat_head, sizeof(stat_head_t), 1, fh);
1097     fwrite(rrd->ds_def, sizeof(ds_def_t), rrd->stat_head->ds_cnt, fh);
1098     fwrite(rrd->rra_def, sizeof(rra_def_t), rrd->stat_head->rra_cnt, fh);
1099     fwrite(rrd->live_head, sizeof(live_head_t), 1, fh);
1100     fwrite(rrd->pdp_prep, sizeof(pdp_prep_t), rrd->stat_head->ds_cnt, fh);
1101     fwrite(rrd->cdp_prep, sizeof(cdp_prep_t),
1102            rrd->stat_head->rra_cnt * rrd->stat_head->ds_cnt, fh);
1103     fwrite(rrd->rra_ptr, sizeof(rra_ptr_t), rrd->stat_head->rra_cnt, fh);
1105     /* calculate the number of rrd_values to dump */
1106     rra_offset = 0;
1107     for (i = 0; i < rrd->stat_head->rra_cnt; i++) {
1108         unsigned long num_rows = rrd->rra_def[i].row_cnt;
1109         unsigned long cur_row = rrd->rra_ptr[i].cur_row;
1110         unsigned long ds_cnt = rrd->stat_head->ds_cnt;
1112         fwrite(rrd->rrd_value +
1113                (rra_offset + num_rows - 1 - cur_row) * ds_cnt,
1114                sizeof(rrd_value_t), (cur_row + 1) * ds_cnt, fh);
1116         fwrite(rrd->rrd_value + rra_offset * ds_cnt,
1117                sizeof(rrd_value_t), (num_rows - 1 - cur_row) * ds_cnt, fh);
1119         rra_offset += num_rows;
1120     }
1122     /* lets see if we had an error */
1123     if (ferror(fh)) {
1124         rrd_set_error("a file error occurred while creating '%s'", file_name);
1125         fclose(fh);
1126         return (-1);
1127     }
1129     fclose(fh);
1130     return (0);
1131 }                       /* int write_file */
1133 int rrd_restore(
1134     int argc,
1135     char **argv)
1137     rrd_t    *rrd;
1139 #ifdef WIN32
1140     srand((unsigned int) time(NULL));
1141 #else
1142     srandom((unsigned int) time(NULL) + (unsigned int) getpid());
1143 #endif
1144     /* init rrd clean */
1145     optind = 0;
1146     opterr = 0;         /* initialize getopt */
1147     while (42) {
1148         int       opt;
1149         int       option_index = 0;
1150         static struct option long_options[] = {
1151             {"range-check", no_argument, 0, 'r'},
1152             {"force-overwrite", no_argument, 0, 'f'},
1153             {0, 0, 0, 0}
1154         };
1156         opt = getopt_long(argc, argv, "rf", long_options, &option_index);
1158         if (opt == EOF)
1159             break;
1161         switch (opt) {
1162         case 'r':
1163             opt_range_check = 1;
1164             break;
1166         case 'f':
1167             opt_force_overwrite = 1;
1168             break;
1170         default:
1171             rrd_set_error("usage rrdtool %s [--range-check|-r] "
1172                           "[--force-overwrite/-f]  file.xml file.rrd",
1173                           argv[0]);
1174             return (-1);
1175             break;
1176         }
1177     }                   /* while (42) */
1179     if ((argc - optind) != 2) {
1180         rrd_set_error("usage rrdtool %s [--range-check/-r] "
1181                       "[--force-overwrite/-f] file.xml file.rrd", argv[0]);
1182         return (-1);
1183     }
1185     rrd = parse_file(argv[optind]);
1186     if (rrd == NULL)
1187         return (-1);
1189     if (write_file(argv[optind + 1], rrd) != 0) {
1190         rrd_free(rrd);
1191         return (-1);
1192     }
1194     rrd_free(rrd);
1195     return (0);
1196 }                       /* int rrd_restore */
1198 /* vim: set sw=2 sts=2 ts=8 et fdm=marker : */