Code

must use int for a proper for to the freebsd 32 time_t issue
[rrdtool-all.git] / program / src / rrd_restore.c
1 /*****************************************************************************
2  * RRDtool 1.3.9  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>
35 #include <locale.h>
37 #if defined(WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
38 #include <math.h>
39 # include <io.h>
40 # define open _open
41 # define close _close
42 #else
43 # include <unistd.h>
44 #endif
46 #include <libxml/parser.h>
47 #include "rrd_tool.h"
48 #include "rrd_rpncalc.h"
49 #define ARRAY_LENGTH(a) (sizeof (a) / sizeof ((a)[0]))
50 static int opt_range_check = 0;
51 static int opt_force_overwrite = 0;
53 /*
54  * Auxiliary functions
55  */
56 static int get_string_from_node(
57     xmlDoc * doc,
58     xmlNode * node,
59     char *buffer,
60     size_t buffer_size)
61 {
62     xmlChar  *temp0;
63     char     *begin_ptr;
64     char     *end_ptr;
66     temp0 = xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
67     if (temp0 == NULL) {
68         rrd_set_error("get_string_from_node: xmlNodeListGetString failed.");
69         return (-1);
70     }
72     begin_ptr = (char *) temp0;
73     while ((begin_ptr[0] != 0) && (isspace(begin_ptr[0])))
74         begin_ptr++;
76     if (begin_ptr[0] == 0) {
77         xmlFree(temp0);
78         buffer[0] = 0;
79         return (0);
80     }
82     end_ptr = begin_ptr;
83     while ((end_ptr[0] != 0) && (!isspace(end_ptr[0])))
84         end_ptr++;
85     end_ptr[0] = 0;
87     strncpy(buffer, begin_ptr, buffer_size);
88     buffer[buffer_size - 1] = 0;
90     xmlFree(temp0);
92     return (0);
93 }                       /* int get_string_from_node */
95 static int get_int_from_node(
96     xmlDoc * doc,
97     xmlNode * node,
98     int *value)
99 {
100     int      temp;
101     char     *str_ptr;
102     char     *end_ptr;
104     str_ptr = (char *) xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
105     if (str_ptr == NULL) {
106         rrd_set_error("get_int_from_node: xmlNodeListGetString failed.");
107         return (-1);
108     }
110     end_ptr = NULL;
111     temp = strtol(str_ptr, &end_ptr, 0);
113     if (str_ptr == end_ptr) {
114         rrd_set_error("get_int_from_node: Cannot parse buffer as long: %s",
115                       str_ptr);
116         xmlFree(str_ptr);
117         return (-1);
118     }
119     xmlFree(str_ptr);
120     *value = temp;
122     return (0);
123 }                       /* int get_int_from_node */
125 static int get_ulong_from_node(
126     xmlDoc * doc,
127     xmlNode * node,
128     unsigned long *value)
130     unsigned long       temp;
131     char     *str_ptr;
132     char     *end_ptr;
134     str_ptr = (char *) xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
135     if (str_ptr == NULL) {
136         rrd_set_error("get_ulong_from_node: xmlNodeListGetString failed.");
137         return (-1);
138     }
140     end_ptr = NULL;
141     temp = strtoul(str_ptr, &end_ptr, 0);
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         xmlFree(str_ptr);
147         return (-1);
148     }
149  
150     xmlFree(str_ptr);
151     *value = temp;
153     return (0);
154 }                       /* int get_ulong_from_node */
157 #ifdef WIN32
158 /* Gross Hack Alert */
159 #if _MSC_VER < 1300
160 #define strtoll(p, e, b) ((*(e) = (char*)(p) + (((b) == 10) ? strspn((p), "0123456789") : 0)), _atoi64(p))
161 #else
162 #define strtoll(p, e, b) _strtoi64(p, e, b)
163 #endif
164 #endif
166 static int get_llong_from_node(
167     xmlDoc * doc,
168     xmlNode * node,
169     long long *value)
171     long long       temp;
172     char     *str_ptr;
173     char     *end_ptr;
175     str_ptr = (char *) xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
176     if (str_ptr == NULL) {
177         rrd_set_error("get_llong_from_node: xmlNodeListGetString failed.");
178         return (-1);
179     }
181     end_ptr = NULL;
182     temp = strtoll(str_ptr, &end_ptr, 10);
184     if (str_ptr == end_ptr) {
185         rrd_set_error("get_llong_from_node: Cannot parse buffer as unsigned long long: %s",
186                       str_ptr);
187         xmlFree(str_ptr);
188         return (-1);
189     }
190     xmlFree(str_ptr);
191     *value = temp;
193     return (0);
194 }                       /* int get_llong_from_node */
196 static int get_double_from_node(
197     xmlDoc * doc,
198     xmlNode * node,
199     double *value)
201     double    temp;
202     char     *str_ptr;
203     char     *end_ptr;
205     str_ptr = (char *) xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
206     if (str_ptr == NULL) {
207         rrd_set_error("get_double_from_node: xmlNodeListGetString failed.");
208         return (-1);
209     }
211     if (strstr(str_ptr, "NaN") != NULL)
212     {
213         *value = DNAN;
214         xmlFree(str_ptr);
215         return 0;
216     }
218     end_ptr = NULL;
219     temp = strtod(str_ptr, &end_ptr);
221     if (str_ptr == end_ptr) {
222         rrd_set_error
223             ("get_double_from_node: Cannot parse buffer as double: %s",
224              str_ptr);
225         xmlFree(str_ptr);
226         return (-1);
227     }
228     xmlFree(str_ptr);           
229     *value = temp;
231     return (0);
232 }                       /* int get_double_from_node */
234 static int value_check_range(
235     rrd_value_t *rrd_value,
236     const ds_def_t *ds_def)
238     double    min;
239     double    max;
241     if (opt_range_check == 0)
242         return (0);
244     min = ds_def->par[DS_min_val].u_val;
245     max = ds_def->par[DS_max_val].u_val;
247     if (((!isnan(min)) && (*rrd_value < min))
248         || ((!isnan(max)) && (*rrd_value > max)))
249         *rrd_value = DNAN;
251     return (0);
252 }                       /* int value_check_range */
254 /*
255  * Parse the <database> block within an RRA definition
256  */
257 static int parse_tag_rra_database_row(
258     xmlDoc * doc,
259     xmlNode * node,
260     rrd_t *rrd,
261     rrd_value_t *rrd_value)
263     unsigned int values_count = 0;
264     xmlNode  *child;
265     int       status;
267     status = 0;
268     for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
269         if ((xmlStrcmp(child->name, (const xmlChar *) "comment") == 0)
270             || (xmlStrcmp(child->name, (const xmlChar *) "text") == 0))
271             /* ignore */ ;
272         else if (xmlStrcmp(child->name, (const xmlChar *) "v") == 0) {
273             if (values_count < rrd->stat_head->ds_cnt) {
274                 status =
275                     get_double_from_node(doc, child,
276                                          rrd_value + values_count);
277                 if (status == 0)
278                     value_check_range(rrd_value + values_count,
279                                       rrd->ds_def + values_count);
280             }
282             values_count++;
283         } else {
284             rrd_set_error("parse_tag_rra_database_row: Unknown tag: %s",
285                           child->name);
286             status = -1;
287         }
289         if (status != 0)
290             break;
291     }                   /* for (child = node->xmlChildrenNode) */
293     if (values_count != rrd->stat_head->ds_cnt) {
294         rrd_set_error("parse_tag_rra_database_row: Row has %u values "
295                       "and RRD has %lu data sources.",
296                       values_count, rrd->stat_head->ds_cnt);
297         status = -1;
298     }
300     return (status);
301 }                       /* int parse_tag_rra_database_row */
303 static int parse_tag_rra_database(
304     xmlDoc * doc,
305     xmlNode * node,
306     rrd_t *rrd)
308     rra_def_t *cur_rra_def;
309     unsigned int total_row_cnt;
310     xmlNode  *child;
311     int       status;
312     int       i;
314     total_row_cnt = 0;
315     for (i = 0; i < (((int) rrd->stat_head->rra_cnt) - 1); i++)
316         total_row_cnt += rrd->rra_def[i].row_cnt;
318     cur_rra_def = rrd->rra_def + i;
320     status = 0;
321     for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
322         if ((xmlStrcmp(child->name, (const xmlChar *) "comment") == 0)
323             || (xmlStrcmp(child->name, (const xmlChar *) "text") == 0))
324             /* ignore */ ;
325         else if (xmlStrcmp(child->name, (const xmlChar *) "row") == 0) {
326             rrd_value_t *temp;
327             rrd_value_t *cur_rrd_value;
328             unsigned int total_values_count = rrd->stat_head->ds_cnt
329                 * (total_row_cnt + 1);
331             /* Allocate space for the new values.. */
332             temp = (rrd_value_t *) realloc(rrd->rrd_value,
333                                            sizeof(rrd_value_t) *
334                                            total_values_count);
335             if (temp == NULL) {
336                 rrd_set_error("parse_tag_rra_database: realloc failed.");
337                 status = -1;
338                 break;
339             }
340             rrd->rrd_value = temp;
341             cur_rrd_value = rrd->rrd_value
342                 + (rrd->stat_head->ds_cnt * total_row_cnt);
343             memset(cur_rrd_value, '\0',
344                    sizeof(rrd_value_t) * rrd->stat_head->ds_cnt);
345             total_row_cnt++;
346             cur_rra_def->row_cnt++;
348             status =
349                 parse_tag_rra_database_row(doc, child, rrd, cur_rrd_value);
350         } /* if (xmlStrcmp (child->name, (const xmlChar *) "row") == 0) */
351         else {
352             rrd_set_error("parse_tag_rra_database: Unknown tag: %s",
353                           child->name);
354             status = -1;
355         }
357         if (status != 0)
358             break;
359     }                   /* for (child = node->xmlChildrenNode) */
361     return (status);
362 }                       /* int parse_tag_rra_database */
364 /*
365  * Parse the <cdp_prep> block within an RRA definition
366  */
367 static int parse_tag_rra_cdp_prep_ds_history(
368     xmlDoc * doc,
369     xmlNode * node,
370     cdp_prep_t *cdp_prep)
372     /* Make `history_buffer' the same size as the scratch area, plus the
373      * terminating NULL byte. */
374     char      history_buffer[sizeof(((cdp_prep_t *)0)->scratch) + 1];
375     char     *history_ptr;
376     int       status;
377     int       i;
379     status = get_string_from_node(doc, node,
380                                   history_buffer, sizeof(history_buffer));
381     if (status != 0)
382         return (-1);
384     history_ptr = (char *) (&cdp_prep->scratch[0]);
385     for (i = 0; history_buffer[i] != '\0'; i++)
386         history_ptr[i] = (history_buffer[i] == '1') ? 1 : 0;
388     return (0);
389 }                       /* int parse_tag_rra_cdp_prep_ds_history */
391 static int parse_tag_rra_cdp_prep_ds(
392     xmlDoc * doc,
393     xmlNode * node,
394     rrd_t *rrd,
395     cdp_prep_t *cdp_prep)
397     xmlNode  *child;
398     int       status;
400     memset(cdp_prep, '\0', sizeof(cdp_prep_t));
402     status = 0;
403     for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
404         if (atoi(rrd->stat_head->version) == 1) {
405             cdp_prep->scratch[CDP_primary_val].u_val = 0.0;
406             cdp_prep->scratch[CDP_secondary_val].u_val = 0.0;
407         }
408         if ((xmlStrcmp(child->name, (const xmlChar *) "comment") == 0)
409             || (xmlStrcmp(child->name, (const xmlChar *) "text") == 0))
410             /* ignore */ ;
411         else if (xmlStrcmp(child->name, (const xmlChar *) "primary_value") ==
412                  0)
413             status =
414                 get_double_from_node(doc, child,
415                                      &cdp_prep->scratch[CDP_primary_val].
416                                      u_val);
417         else if (xmlStrcmp(child->name, (const xmlChar *) "secondary_value")
418                  == 0)
419             status =
420                 get_double_from_node(doc, child,
421                                      &cdp_prep->scratch[CDP_secondary_val].
422                                      u_val);
423         else if (xmlStrcmp(child->name, (const xmlChar *) "intercept") == 0)
424             status = get_double_from_node(doc, child,
425                                           &cdp_prep->
426                                           scratch[CDP_hw_intercept].u_val);
427         else if (xmlStrcmp(child->name, (const xmlChar *) "last_intercept") ==
428                  0)
429             status =
430                 get_double_from_node(doc, child,
431                                      &cdp_prep->
432                                      scratch[CDP_hw_last_intercept].u_val);
433         else if (xmlStrcmp(child->name, (const xmlChar *) "slope") == 0)
434             status = get_double_from_node(doc, child,
435                                           &cdp_prep->scratch[CDP_hw_slope].
436                                           u_val);
437         else if (xmlStrcmp(child->name, (const xmlChar *) "last_slope") == 0)
438             status = get_double_from_node(doc, child,
439                                           &cdp_prep->
440                                           scratch[CDP_hw_last_slope].u_val);
441         else if (xmlStrcmp(child->name, (const xmlChar *) "nan_count") == 0)
442             status = get_ulong_from_node(doc, child,
443                                         &cdp_prep->
444                                        scratch[CDP_null_count].u_cnt);
445         else if (xmlStrcmp(child->name, (const xmlChar *) "last_nan_count") ==
446                  0)
447             status =
448                 get_ulong_from_node(doc, child,
449                                    &cdp_prep->
450                                   scratch[CDP_last_null_count].u_cnt);
451         else if (xmlStrcmp(child->name, (const xmlChar *) "seasonal") == 0)
452             status = get_double_from_node(doc, child,
453                                           &cdp_prep->scratch[CDP_hw_seasonal].
454                                           u_val);
455         else if (xmlStrcmp(child->name, (const xmlChar *) "last_seasonal") ==
456                  0)
457             status =
458                 get_double_from_node(doc, child,
459                                      &cdp_prep->scratch[CDP_hw_last_seasonal].
460                                      u_val);
461         else if (xmlStrcmp(child->name, (const xmlChar *) "init_flag") == 0)
462             status = get_ulong_from_node(doc, child,
463                                         &cdp_prep->
464                                        scratch[CDP_init_seasonal].u_cnt);
465         else if (xmlStrcmp(child->name, (const xmlChar *) "history") == 0)
466             status = parse_tag_rra_cdp_prep_ds_history(doc, child, cdp_prep);
467         else if (xmlStrcmp(child->name, (const xmlChar *) "value") == 0)
468             status = get_double_from_node(doc, child,
469                                           &cdp_prep->scratch[CDP_val].u_val);
470         else if (xmlStrcmp(child->name,
471                            (const xmlChar *) "unknown_datapoints") == 0)
472             status = get_ulong_from_node(doc, child,
473                                         &cdp_prep->
474                                        scratch[CDP_unkn_pdp_cnt].u_cnt);
475         else {
476             rrd_set_error("parse_tag_rra_cdp_prep: Unknown tag: %s",
477                           child->name);
478             status = -1;
479         }
481         if (status != 0)
482             break;
483     }
485     return (status);
486 }                       /* int parse_tag_rra_cdp_prep_ds */
488 static int parse_tag_rra_cdp_prep(
489     xmlDoc * doc,
490     xmlNode * node,
491     rrd_t *rrd,
492     cdp_prep_t *cdp_prep)
494     xmlNode  *child;
495     int       status;
497     unsigned int ds_count = 0;
499     status = 0;
500     for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
501         if ((xmlStrcmp(child->name, (const xmlChar *) "comment") == 0)
502             || (xmlStrcmp(child->name, (const xmlChar *) "text") == 0))
503             /* ignore */ ;
504         else if (xmlStrcmp(child->name, (const xmlChar *) "ds") == 0) {
505             if (ds_count >= rrd->stat_head->ds_cnt)
506                 status = -1;
507             else {
508                 status = parse_tag_rra_cdp_prep_ds(doc, child, rrd,
509                                                    cdp_prep + ds_count);
510                 ds_count++;
511             }
512         } else {
513             rrd_set_error("parse_tag_rra_cdp_prep: Unknown tag: %s",
514                           child->name);
515             status = -1;
516         }
518         if (status != 0)
519             break;
520     }
522     if (ds_count != rrd->stat_head->ds_cnt) {
523         rrd_set_error("parse_tag_rra_cdp_prep: There are %i data sources in "
524                       "the RRD file, but %i in this cdp_prep block!",
525                       (int) rrd->stat_head->ds_cnt, ds_count);
526         status = -1;
527     }
529     return (status);
530 }                       /* int parse_tag_rra_cdp_prep */
532 /*
533  * Parse the <params> block within an RRA definition
534  */
535 static int parse_tag_rra_params(
536     xmlDoc * doc,
537     xmlNode * node,
538     rra_def_t *rra_def)
540     xmlNode  *child;
541     int       status;
543     status = 0;
544     for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
545         if ((xmlStrcmp(child->name, (const xmlChar *) "comment") == 0)
546             || (xmlStrcmp(child->name, (const xmlChar *) "text") == 0))
547             /* ignore */ ;
548         /*
549          * Parameters for CF_HWPREDICT
550          */
551         else if (xmlStrcmp(child->name, (const xmlChar *) "hw_alpha") == 0)
552             status = get_double_from_node(doc, child,
553                                           &rra_def->par[RRA_hw_alpha].u_val);
554         else if (xmlStrcmp(child->name, (const xmlChar *) "hw_beta") == 0)
555             status = get_double_from_node(doc, child,
556                                           &rra_def->par[RRA_hw_beta].u_val);
557         else if (xmlStrcmp(child->name,
558                            (const xmlChar *) "dependent_rra_idx") == 0)
559             status = get_ulong_from_node(doc, child,
560                                         &rra_def->
561                                        par[RRA_dependent_rra_idx].u_cnt);
562         /*
563          * Parameters for CF_SEASONAL and CF_DEVSEASONAL
564          */
565         else if (xmlStrcmp(child->name, (const xmlChar *) "seasonal_gamma") ==
566                  0)
567             status =
568                 get_double_from_node(doc, child,
569                                      &rra_def->par[RRA_seasonal_gamma].u_val);
570         else if (xmlStrcmp
571                  (child->name, (const xmlChar *) "seasonal_smooth_idx") == 0)
572             status =
573                 get_ulong_from_node(doc, child,
574                                    &rra_def->
575                                   par[RRA_seasonal_smooth_idx].u_cnt);
576         else if (xmlStrcmp(child->name, (const xmlChar *) "smoothing_window")
577                  == 0)
578             status =
579                 get_double_from_node(doc, child,
580                                      &rra_def->
581                                      par[RRA_seasonal_smoothing_window].
582                                      u_val);
583         /* else if (dependent_rra_idx) ...; */
584         /*
585          * Parameters for CF_FAILURES
586          */
587         else if (xmlStrcmp(child->name, (const xmlChar *) "delta_pos") == 0)
588             status = get_double_from_node(doc, child,
589                                           &rra_def->par[RRA_delta_pos].u_val);
590         else if (xmlStrcmp(child->name, (const xmlChar *) "delta_neg") == 0)
591             status = get_double_from_node(doc, child,
592                                           &rra_def->par[RRA_delta_neg].u_val);
593         else if (xmlStrcmp(child->name, (const xmlChar *) "window_len") == 0)
594             status = get_ulong_from_node(doc, child,
595                                         &rra_def->par[RRA_window_len].
596                                        u_cnt);
597         else if (xmlStrcmp(child->name, (const xmlChar *) "failure_threshold")
598                  == 0)
599             status =
600                 get_ulong_from_node(doc, child,
601                                    &rra_def->
602                                   par[RRA_failure_threshold].u_cnt);
603         /*
604          * Parameters for CF_AVERAGE, CF_MAXIMUM, CF_MINIMUM, and CF_LAST
605          */
606         else if (xmlStrcmp(child->name, (const xmlChar *) "xff") == 0)
607             status = get_double_from_node(doc, child,
608                                           &rra_def->par[RRA_cdp_xff_val].
609                                           u_val);
610         /*
611          * Compatibility code for 1.0.49
612          */
613         else if (xmlStrcmp(child->name, (const xmlChar *) "value") == 0) {  /* {{{ */
614             unsigned int i = 0;
616             while (42) {
617                 if (i >= ARRAY_LENGTH(rra_def->par)) {
618                     status = -1;
619                     break;
620                 }
622                 if ((i == RRA_dependent_rra_idx)
623                     || (i == RRA_seasonal_smooth_idx)
624                     || (i == RRA_failure_threshold))
625                     status = get_ulong_from_node(doc, child,
626                                                 &rra_def->par[i].
627                                                u_cnt);
628                 else
629                     status = get_double_from_node(doc, child,
630                                                   &rra_def->par[i].u_val);
632                 if (status != 0)
633                     break;
635                 /* When this loops exits (sucessfully) `child' points to the last
636                  * `value' tag in the list. */
637                 if ((child->next == NULL)
638                     || (xmlStrcmp(child->name, (const xmlChar *) "value") !=
639                         0))
640                     break;
642                 child = child->next;
643                 i++;
644             }
645         } /* }}} */
646         else {
647             rrd_set_error("parse_tag_rra_params: Unknown tag: %s",
648                           child->name);
649             status = -1;
650         }
652         if (status != 0)
653             break;
654     }
656     return (status);
657 }                       /* int parse_tag_rra_params */
659 /*
660  * Parse an RRA definition
661  */
662 static int parse_tag_rra_cf(
663     xmlDoc * doc,
664     xmlNode * node,
665     rra_def_t *rra_def)
667     int       status;
669     status = get_string_from_node(doc, node,
670                                   rra_def->cf_nam, sizeof(rra_def->cf_nam));
671     if (status != 0)
672         return (-1);
674     status = cf_conv(rra_def->cf_nam);
675     if (status == -1) {
676         rrd_set_error("parse_tag_rra_cf: Unknown consolidation function: %s",
677                       rra_def->cf_nam);
678         return (-1);
679     }
681     return (0);
682 }                       /* int parse_tag_rra_cf */
684 static int parse_tag_rra(
685     xmlDoc * doc,
686     xmlNode * node,
687     rrd_t *rrd)
689     xmlNode  *child;
690     int       status;
692     rra_def_t *cur_rra_def;
693     cdp_prep_t *cur_cdp_prep;
694     rra_ptr_t *cur_rra_ptr;
696     /* Allocate more rra_def space for this RRA */
697     {                   /* {{{ */
698         rra_def_t *temp;
700         temp = (rra_def_t *) realloc(rrd->rra_def,
701                                      sizeof(rra_def_t) *
702                                      (rrd->stat_head->rra_cnt + 1));
703         if (temp == NULL) {
704             rrd_set_error("parse_tag_rra: realloc failed.");
705             return (-1);
706         }
707         rrd->rra_def = temp;
708         cur_rra_def = rrd->rra_def + rrd->stat_head->rra_cnt;
709         memset(cur_rra_def, '\0', sizeof(rra_def_t));
710     }                   /* }}} */
712     /* allocate cdp_prep_t */
713     {                   /* {{{ */
714         cdp_prep_t *temp;
716         temp = (cdp_prep_t *) realloc(rrd->cdp_prep, sizeof(cdp_prep_t)
717                                       * rrd->stat_head->ds_cnt
718                                       * (rrd->stat_head->rra_cnt + 1));
719         if (temp == NULL) {
720             rrd_set_error("parse_tag_rra: realloc failed.");
721             return (-1);
722         }
723         rrd->cdp_prep = temp;
724         cur_cdp_prep = rrd->cdp_prep
725             + (rrd->stat_head->ds_cnt * rrd->stat_head->rra_cnt);
726         memset(cur_cdp_prep, '\0',
727                sizeof(cdp_prep_t) * rrd->stat_head->ds_cnt);
728     }                   /* }}} */
730     /* allocate rra_ptr_t */
731     {                   /* {{{ */
732         rra_ptr_t *temp;
734         temp = (rra_ptr_t *) realloc(rrd->rra_ptr,
735                                      sizeof(rra_ptr_t) *
736                                      (rrd->stat_head->rra_cnt + 1));
737         if (temp == NULL) {
738             rrd_set_error("parse_tag_rra: realloc failed.");
739             return (-1);
740         }
741         rrd->rra_ptr = temp;
742         cur_rra_ptr = rrd->rra_ptr + rrd->stat_head->rra_cnt;
743         memset(cur_rra_ptr, '\0', sizeof(rra_ptr_t));
744     }                   /* }}} */
746     /* All space successfully allocated, increment number of RRAs. */
747     rrd->stat_head->rra_cnt++;
749     status = 0;
750     for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
751         if ((xmlStrcmp(child->name, (const xmlChar *) "comment") == 0)
752             || (xmlStrcmp(child->name, (const xmlChar *) "text") == 0))
753             /* ignore */ ;
754         else if (xmlStrcmp(child->name, (const xmlChar *) "cf") == 0)
755             status = parse_tag_rra_cf(doc, child, cur_rra_def);
756         else if (xmlStrcmp(child->name, (const xmlChar *) "pdp_per_row") == 0)
757             status = get_ulong_from_node(doc, child,
758                                         &cur_rra_def->pdp_cnt);
759         else if (atoi(rrd->stat_head->version) == 1
760                  && xmlStrcmp(child->name, (const xmlChar *) "xff") == 0)
761             status = get_double_from_node(doc, child,
762                                           (double *) &cur_rra_def->
763                                           par[RRA_cdp_xff_val].u_val);
764         else if (atoi(rrd->stat_head->version) >= 2
765                  && xmlStrcmp(child->name, (const xmlChar *) "params") == 0)
766             status = parse_tag_rra_params(doc, child, cur_rra_def);
767         else if (xmlStrcmp(child->name, (const xmlChar *) "cdp_prep") == 0)
768             status = parse_tag_rra_cdp_prep(doc, child, rrd, cur_cdp_prep);
769         else if (xmlStrcmp(child->name, (const xmlChar *) "database") == 0)
770             status = parse_tag_rra_database(doc, child, rrd);
771         else {
772             rrd_set_error("parse_tag_rra: Unknown tag: %s", child->name);
773             status = -1;
774         }
776         if (status != 0)
777             break;
778     }
780     /* Set the RRA pointer to a random location */
781 #ifdef WIN32
782     cur_rra_ptr->cur_row = rand() % cur_rra_def->row_cnt;
783 #else
784     cur_rra_ptr->cur_row = random() % cur_rra_def->row_cnt;
785 #endif
787     return (status);
788 }                       /* int parse_tag_rra */
790 /*
791  * Parse a DS definition
792  */
793 static int parse_tag_ds_cdef(
794     xmlDoc * doc,
795     xmlNode * node,
796     rrd_t *rrd)
798     char      buffer[1024];
799     int       status;
801     status = get_string_from_node(doc, node, buffer, sizeof(buffer));
802     if (status != 0)
803         return (-1);
805     /* We're always working on the last DS that has been added to the structure
806      * when we get here */
807     parseCDEF_DS(buffer, rrd, rrd->stat_head->ds_cnt - 1);
809     return (0);
810 }                       /* int parse_tag_ds_cdef */
812 static int parse_tag_ds_type(
813     xmlDoc * doc,
814     xmlNode * node,
815     ds_def_t *ds_def)
817     int       status;
819     status = get_string_from_node(doc, node,
820                                   ds_def->dst, sizeof(ds_def->dst));
821     if (status != 0)
822         return (-1);
824     status = dst_conv(ds_def->dst);
825     if (status == -1) {
826         rrd_set_error("parse_tag_ds_type: Unknown data source type: %s",
827                       ds_def->dst);
828         return (-1);
829     }
831     return (0);
832 }                       /* int parse_tag_ds_type */
834 static int parse_tag_ds(
835     xmlDoc * doc,
836     xmlNode * node,
837     rrd_t *rrd)
839     xmlNode  *child;
840     int       status;
842     ds_def_t *cur_ds_def;
843     pdp_prep_t *cur_pdp_prep;
845     /*
846      * If there are DS definitions after RRA definitions the number of values,
847      * cdp_prep areas and so on will be calculated wrong. Thus, enforce a
848      * specific order in this case.
849      */
850     if (rrd->stat_head->rra_cnt > 0) {
851         rrd_set_error("parse_tag_ds: All data source definitions MUST "
852                       "precede the RRA definitions!");
853         return (-1);
854     }
856     /* Allocate space for the new DS definition */
857     {                   /* {{{ */
858         ds_def_t *temp;
860         temp = (ds_def_t *) realloc(rrd->ds_def,
861                                     sizeof(ds_def_t) *
862                                     (rrd->stat_head->ds_cnt + 1));
863         if (temp == NULL) {
864             rrd_set_error("parse_tag_ds: malloc failed.");
865             return (-1);
866         }
867         rrd->ds_def = temp;
868         cur_ds_def = rrd->ds_def + rrd->stat_head->ds_cnt;
869         memset(cur_ds_def, '\0', sizeof(ds_def_t));
870     }                   /* }}} */
872     /* Allocate pdp_prep space for the new DS definition */
873     {                   /* {{{ */
874         pdp_prep_t *temp;
876         temp = (pdp_prep_t *) realloc(rrd->pdp_prep,
877                                       sizeof(pdp_prep_t) *
878                                       (rrd->stat_head->ds_cnt + 1));
879         if (temp == NULL) {
880             rrd_set_error("parse_tag_ds: malloc failed.");
881             return (-1);
882         }
883         rrd->pdp_prep = temp;
884         cur_pdp_prep = rrd->pdp_prep + rrd->stat_head->ds_cnt;
885         memset(cur_pdp_prep, '\0', sizeof(pdp_prep_t));
886     }                   /* }}} */
888     /* All allocations successful, let's increment the number of DSes. */
889     rrd->stat_head->ds_cnt++;
891     status = 0;
892     for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
893         if ((xmlStrcmp(child->name, (const xmlChar *) "comment") == 0)
894             || (xmlStrcmp(child->name, (const xmlChar *) "text") == 0))
895             /* ignore */ ;
896         else if (xmlStrcmp(child->name, (const xmlChar *) "name") == 0)
897             status = get_string_from_node(doc, child,
898                                           cur_ds_def->ds_nam,
899                                           sizeof(cur_ds_def->ds_nam));
900         else if (xmlStrcmp(child->name, (const xmlChar *) "type") == 0)
901             status = parse_tag_ds_type(doc, child, cur_ds_def);
902         else if (xmlStrcmp(child->name,
903                            (const xmlChar *) "minimal_heartbeat") == 0)
904             status = get_ulong_from_node(doc, child,
905                                         &cur_ds_def->par[DS_mrhb_cnt].
906                                        u_cnt);
907         else if (xmlStrcmp(child->name, (const xmlChar *) "min") == 0)
908             status = get_double_from_node(doc, child,
909                                           &cur_ds_def->par[DS_min_val].u_val);
910         else if (xmlStrcmp(child->name, (const xmlChar *) "max") == 0)
911             status = get_double_from_node(doc, child,
912                                           &cur_ds_def->par[DS_max_val].u_val);
913         else if (xmlStrcmp(child->name, (const xmlChar *) "cdef") == 0)
914             status = parse_tag_ds_cdef(doc, child, rrd);
915         else if (xmlStrcmp(child->name, (const xmlChar *) "last_ds") == 0)
916             status = get_string_from_node(doc, child,
917                                           cur_pdp_prep->last_ds,
918                                           sizeof(cur_pdp_prep->last_ds));
919         else if (xmlStrcmp(child->name, (const xmlChar *) "value") == 0)
920             status = get_double_from_node(doc, child,
921                                           &cur_pdp_prep->scratch[PDP_val].
922                                           u_val);
923         else if (xmlStrcmp(child->name, (const xmlChar *) "unknown_sec") == 0)
924             status = get_ulong_from_node(doc, child,
925                                         &cur_pdp_prep->
926                                        scratch[PDP_unkn_sec_cnt].u_cnt);
927         else {
928             rrd_set_error("parse_tag_ds: Unknown tag: %s", child->name);
929             status = -1;
930         }
932         if (status != 0)
933             break;
934     }
936     return (status);
937 }                       /* int parse_tag_ds */
939 /*
940  * Parse root nodes
941  */
942 static int parse_tag_rrd(
943     xmlDoc * doc,
944     xmlNode * node,
945     rrd_t *rrd)
947     xmlNode  *child;
948     int       status;
950     status = 0;
951     for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
952         if ((xmlStrcmp(child->name, (const xmlChar *) "comment") == 0)
953             || (xmlStrcmp(child->name, (const xmlChar *) "text") == 0))
954             /* ignore */ ;
955         else if (xmlStrcmp(child->name, (const xmlChar *) "version") == 0)
956             status = get_string_from_node(doc, child,
957                                           rrd->stat_head->version,
958                                           sizeof(rrd->stat_head->version));
959         else if (xmlStrcmp(child->name, (const xmlChar *) "step") == 0)
960             status = get_ulong_from_node(doc, child,
961                                         &rrd->stat_head->pdp_step);
962         else if (xmlStrcmp(child->name, (const xmlChar *) "lastupdate") == 0) {
963             if (sizeof(time_t) == sizeof(int)) {
964                status = get_int_from_node(doc, child, (int *)&rrd->live_head->last_up);
965             }
966             else { if (sizeof(time_t) == sizeof(long long)) {
967                        status = get_llong_from_node(doc, child, (long long *)&rrd->live_head->last_up);
968                     }
969                     else {
970                        rrd_set_error("can't convert to time_t ...", child->name);
971                        status = -1;    
972                     }
973             }
974         }
975         else if (xmlStrcmp(child->name, (const xmlChar *) "ds") == 0)
976             status = parse_tag_ds(doc, child, rrd);
977         else if (xmlStrcmp(child->name, (const xmlChar *) "rra") == 0)
978             status = parse_tag_rra(doc, child, rrd);
979         else {
980             rrd_set_error("parse_tag_rrd: Unknown tag: %s", child->name);
981             status = -1;
982         }
984         if (status != 0)
985             break;
986     }
988     return (status);
989 }                       /* int parse_tag_rrd */
991 static rrd_t *parse_file(
992     const char *filename)
994     xmlDoc   *doc;
995     xmlNode  *cur;
996     int       status;
998     rrd_t    *rrd;
1000     doc = xmlParseFile(filename);
1001     if (doc == NULL) {
1002         rrd_set_error("Document not parsed successfully.");
1003         return (NULL);
1004     }
1006     cur = xmlDocGetRootElement(doc);
1007     if (cur == NULL) {
1008         rrd_set_error("Document is empty.");
1009         xmlFreeDoc(doc);
1010         return (NULL);
1011     }
1013     if (xmlStrcmp(cur->name, (const xmlChar *) "rrd") != 0) {
1014         rrd_set_error
1015             ("Document of the wrong type, root node is not \"rrd\".");
1016         xmlFreeDoc(doc);
1017         return (NULL);
1018     }
1020     rrd = (rrd_t *) malloc(sizeof(rrd_t));
1021     if (rrd == NULL) {
1022         rrd_set_error("parse_file: malloc failed.");
1023         xmlFreeDoc(doc);
1024         return (NULL);
1025     }
1026     memset(rrd, '\0', sizeof(rrd_t));
1028     rrd->stat_head = (stat_head_t *) malloc(sizeof(stat_head_t));
1029     if (rrd->stat_head == NULL) {
1030         rrd_set_error("parse_tag_rrd: malloc failed.");
1031         xmlFreeDoc(doc);
1032         free(rrd);
1033         return (NULL);
1034     }
1035     memset(rrd->stat_head, '\0', sizeof(stat_head_t));
1037     strncpy(rrd->stat_head->cookie, "RRD", sizeof(rrd->stat_head->cookie));
1038     rrd->stat_head->float_cookie = FLOAT_COOKIE;
1040     rrd->live_head = (live_head_t *) malloc(sizeof(live_head_t));
1041     if (rrd->live_head == NULL) {
1042         rrd_set_error("parse_tag_rrd: malloc failed.");
1043         xmlFreeDoc(doc);
1044         free(rrd->stat_head);
1045         free(rrd);
1046         return (NULL);
1047     }
1048     memset(rrd->live_head, '\0', sizeof(live_head_t));
1050     status = parse_tag_rrd(doc, cur, rrd);
1052     xmlFreeDoc(doc);
1053     if (status != 0) {
1054         rrd_free(rrd);
1055         rrd = NULL;
1056     }
1058     return (rrd);
1059 }                       /* rrd_t *parse_file */
1061 static int write_file(
1062     const char *file_name,
1063     rrd_t *rrd)
1065     FILE     *fh;
1066     unsigned int i;
1067     unsigned int rra_offset;
1069     if (strcmp("-", file_name) == 0)
1070         fh = stdout;
1071     else {
1072         int       fd_flags = O_WRONLY | O_CREAT;
1073         int       fd;
1075 #if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
1076         fd_flags |= O_BINARY;
1077 #endif
1079         if (opt_force_overwrite == 0)
1080             fd_flags |= O_EXCL;
1082         fd = open(file_name, fd_flags, 0666);
1083         if (fd == -1) {
1084             rrd_set_error("creating '%s': %s", file_name,
1085                           rrd_strerror(errno));
1086             return (-1);
1087         }
1089         fh = fdopen(fd, "wb");
1090         if (fh == NULL) {
1091             rrd_set_error("fdopen failed: %s", rrd_strerror(errno));
1092             close(fd);
1093             return (-1);
1094         }
1095     }
1096     if (atoi(rrd->stat_head->version) < 3) {
1097         /* we output 3 or higher */
1098         strcpy(rrd->stat_head->version, "0003");
1099     }
1100     fwrite(rrd->stat_head, sizeof(stat_head_t), 1, fh);
1101     fwrite(rrd->ds_def, sizeof(ds_def_t), rrd->stat_head->ds_cnt, fh);
1102     fwrite(rrd->rra_def, sizeof(rra_def_t), rrd->stat_head->rra_cnt, fh);
1103     fwrite(rrd->live_head, sizeof(live_head_t), 1, fh);
1104     fwrite(rrd->pdp_prep, sizeof(pdp_prep_t), rrd->stat_head->ds_cnt, fh);
1105     fwrite(rrd->cdp_prep, sizeof(cdp_prep_t),
1106            rrd->stat_head->rra_cnt * rrd->stat_head->ds_cnt, fh);
1107     fwrite(rrd->rra_ptr, sizeof(rra_ptr_t), rrd->stat_head->rra_cnt, fh);
1109     /* calculate the number of rrd_values to dump */
1110     rra_offset = 0;
1111     for (i = 0; i < rrd->stat_head->rra_cnt; i++) {
1112         unsigned long num_rows = rrd->rra_def[i].row_cnt;
1113         unsigned long cur_row = rrd->rra_ptr[i].cur_row;
1114         unsigned long ds_cnt = rrd->stat_head->ds_cnt;
1116         fwrite(rrd->rrd_value +
1117                (rra_offset + num_rows - 1 - cur_row) * ds_cnt,
1118                sizeof(rrd_value_t), (cur_row + 1) * ds_cnt, fh);
1120         fwrite(rrd->rrd_value + rra_offset * ds_cnt,
1121                sizeof(rrd_value_t), (num_rows - 1 - cur_row) * ds_cnt, fh);
1123         rra_offset += num_rows;
1124     }
1126     /* lets see if we had an error */
1127     if (ferror(fh)) {
1128         rrd_set_error("a file error occurred while creating '%s'", file_name);
1129         fclose(fh);
1130         return (-1);
1131     }
1133     fclose(fh);
1134     return (0);
1135 }                       /* int write_file */
1137 int rrd_restore(
1138     int argc,
1139     char **argv)
1141     rrd_t    *rrd;
1142     char*    old_locale;
1144 #ifdef WIN32
1145     srand((unsigned int) time(NULL));
1146 #else
1147     srandom((unsigned int) time(NULL) + (unsigned int) getpid());
1148 #endif
1149     /* init rrd clean */
1150     optind = 0;
1151     opterr = 0;         /* initialize getopt */
1152     while (42) {
1153         int       opt;
1154         int       option_index = 0;
1155         static struct option long_options[] = {
1156             {"range-check", no_argument, 0, 'r'},
1157             {"force-overwrite", no_argument, 0, 'f'},
1158             {0, 0, 0, 0}
1159         };
1161         opt = getopt_long(argc, argv, "rf", long_options, &option_index);
1163         if (opt == EOF)
1164             break;
1166         switch (opt) {
1167         case 'r':
1168             opt_range_check = 1;
1169             break;
1171         case 'f':
1172             opt_force_overwrite = 1;
1173             break;
1175         default:
1176             rrd_set_error("usage rrdtool %s [--range-check|-r] "
1177                           "[--force-overwrite/-f]  file.xml file.rrd",
1178                           argv[0]);
1179             return (-1);
1180             break;
1181         }
1182     }                   /* while (42) */
1184     if ((argc - optind) != 2) {
1185         rrd_set_error("usage rrdtool %s [--range-check/-r] "
1186                       "[--force-overwrite/-f] file.xml file.rrd", argv[0]);
1187         return (-1);
1188     }
1190 #ifdef HAVE_SETLOCALE
1191     old_locale = setlocale(LC_NUMERIC, "C");
1192 #endif
1194     rrd = parse_file(argv[optind]);
1196 #ifdef HAVE_SETLOCALE
1197     setlocale(LC_NUMERIC, old_locale);
1198 #endif
1200     if (rrd == NULL)
1201         return (-1);
1203     if (write_file(argv[optind + 1], rrd) != 0) {
1204         rrd_free(rrd);
1205         return (-1);
1206     }
1208     rrd_free(rrd);
1209     return (0);
1210 }                       /* int rrd_restore */
1212 /* vim: set sw=2 sts=2 ts=8 et fdm=marker : */