1 /*****************************************************************************
2 * RRDtool 1.3.0 Copyright by Tobi Oetiker, 1997-2008
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 *****************************************************************************
9 *************************************************************************** */
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)
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
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
27 * Florian octo Forster <octo at verplant.org>
36 #if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
41 #include <libxml/parser.h>
43 #include "rrd_rpncalc.h"
44 #define ARRAY_LENGTH(a) (sizeof (a) / sizeof ((a)[0]))
45 static int opt_range_check = 0;
46 static int opt_force_overwrite = 0;
51 static int get_string_from_node(
61 temp0 = xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
63 rrd_set_error("get_string_from_node: xmlNodeListGetString failed.");
67 begin_ptr = (char *) temp0;
68 while ((begin_ptr[0] != 0) && (isspace(begin_ptr[0])))
71 if (begin_ptr[0] == 0) {
78 while ((end_ptr[0] != 0) && (!isspace(end_ptr[0])))
82 strncpy(buffer, begin_ptr, buffer_size);
83 buffer[buffer_size - 1] = 0;
88 } /* int get_string_from_node */
90 static int get_int_from_node(
99 str_ptr = (char *) xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
100 if (str_ptr == NULL) {
101 rrd_set_error("get_int_from_node: xmlNodeListGetString failed.");
106 temp = strtol(str_ptr, &end_ptr, 0);
109 if (str_ptr == end_ptr) {
110 rrd_set_error("get_int_from_node: Cannot parse buffer as int: %s",
118 } /* int get_int_from_node */
120 static int get_double_from_node(
129 str_ptr = (char *) xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
130 if (str_ptr == NULL) {
131 rrd_set_error("get_double_from_node: xmlNodeListGetString failed.");
136 temp = strtod(str_ptr, &end_ptr);
139 if (str_ptr == end_ptr) {
141 ("get_double_from_node: Cannot parse buffer as double: %s",
149 } /* int get_double_from_node */
151 static int value_check_range(
152 rrd_value_t *rrd_value,
153 const ds_def_t *ds_def)
158 if (opt_range_check == 0)
161 min = ds_def->par[DS_min_val].u_val;
162 max = ds_def->par[DS_max_val].u_val;
164 if (((!isnan(min)) && (*rrd_value < min))
165 || ((!isnan(max)) && (*rrd_value > max)))
169 } /* int value_check_range */
172 * Parse the <database> block within an RRA definition
174 static int parse_tag_rra_database_row(
178 rrd_value_t *rrd_value)
180 unsigned int values_count = 0;
185 for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
186 if ((xmlStrcmp(child->name, (const xmlChar *) "comment") == 0)
187 || (xmlStrcmp(child->name, (const xmlChar *) "text") == 0))
189 else if (xmlStrcmp(child->name, (const xmlChar *) "v") == 0) {
190 if (values_count < rrd->stat_head->ds_cnt) {
192 get_double_from_node(doc, child,
193 rrd_value + values_count);
195 value_check_range(rrd_value + values_count,
196 rrd->ds_def + values_count);
201 rrd_set_error("parse_tag_rra_database_row: Unknown tag: %s",
208 } /* for (child = node->xmlChildrenNode) */
210 if (values_count != rrd->stat_head->ds_cnt) {
211 rrd_set_error("parse_tag_rra_database_row: Row has %u values "
212 "and RRD has %lu data sources.",
213 values_count, rrd->stat_head->ds_cnt);
218 } /* int parse_tag_rra_database_row */
220 static int parse_tag_rra_database(
225 rra_def_t *cur_rra_def;
226 unsigned int total_row_cnt;
232 for (i = 0; i < (((int) rrd->stat_head->rra_cnt) - 1); i++)
233 total_row_cnt += rrd->rra_def[i].row_cnt;
235 cur_rra_def = rrd->rra_def + i;
238 for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
239 if ((xmlStrcmp(child->name, (const xmlChar *) "comment") == 0)
240 || (xmlStrcmp(child->name, (const xmlChar *) "text") == 0))
242 else if (xmlStrcmp(child->name, (const xmlChar *) "row") == 0) {
244 rrd_value_t *cur_rrd_value;
245 unsigned int total_values_count = rrd->stat_head->ds_cnt
246 * (total_row_cnt + 1);
248 /* Allocate space for the new values.. */
249 temp = (rrd_value_t *) realloc(rrd->rrd_value,
250 sizeof(rrd_value_t) *
253 rrd_set_error("parse_tag_rra_database: realloc failed.");
257 rrd->rrd_value = temp;
258 cur_rrd_value = rrd->rrd_value
259 + (rrd->stat_head->ds_cnt * total_row_cnt);
260 memset(cur_rrd_value, '\0',
261 sizeof(rrd_value_t) * rrd->stat_head->ds_cnt);
263 cur_rra_def->row_cnt++;
266 parse_tag_rra_database_row(doc, child, rrd, cur_rrd_value);
267 } /* if (xmlStrcmp (child->name, (const xmlChar *) "row") == 0) */
269 rrd_set_error("parse_tag_rra_database: Unknown tag: %s",
276 } /* for (child = node->xmlChildrenNode) */
279 } /* int parse_tag_rra_database */
282 * Parse the <cdp_prep> block within an RRA definition
284 static int parse_tag_rra_cdp_prep_ds_history(
287 cdp_prep_t *cdp_prep)
289 /* Make `history_buffer' the same size as the scratch area, plus the
290 * terminating NULL byte. */
291 char history_buffer[sizeof(((cdp_prep_t *)0)->scratch) + 1];
296 status = get_string_from_node(doc, node,
297 history_buffer, sizeof(history_buffer));
301 history_ptr = (char *) (&cdp_prep->scratch[0]);
302 for (i = 0; history_buffer[i] != '\0'; i++)
303 history_ptr[i] = (history_buffer[i] == '1') ? 1 : 0;
306 } /* int parse_tag_rra_cdp_prep_ds_history */
308 static int parse_tag_rra_cdp_prep_ds(
312 cdp_prep_t *cdp_prep)
317 memset(cdp_prep, '\0', sizeof(cdp_prep_t));
320 for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
321 if (atoi(rrd->stat_head->version) == 1){
322 cdp_prep->scratch[CDP_primary_val].u_val = 0.0;
323 cdp_prep->scratch[CDP_secondary_val].u_val = 0.0;
325 if ((xmlStrcmp(child->name, (const xmlChar *) "comment") == 0)
326 || (xmlStrcmp(child->name, (const xmlChar *) "text") == 0))
328 else if (xmlStrcmp(child->name, (const xmlChar *) "primary_value") ==
331 get_double_from_node(doc, child,
332 &cdp_prep->scratch[CDP_primary_val].
334 else if (xmlStrcmp(child->name, (const xmlChar *) "secondary_value")
337 get_double_from_node(doc, child,
338 &cdp_prep->scratch[CDP_secondary_val].
340 else if (xmlStrcmp(child->name, (const xmlChar *) "intercept") == 0)
341 status = get_double_from_node(doc, child,
343 scratch[CDP_hw_intercept].u_val);
344 else if (xmlStrcmp(child->name, (const xmlChar *) "last_intercept") ==
347 get_double_from_node(doc, child,
349 scratch[CDP_hw_last_intercept].u_val);
350 else if (xmlStrcmp(child->name, (const xmlChar *) "slope") == 0)
351 status = get_double_from_node(doc, child,
352 &cdp_prep->scratch[CDP_hw_slope].
354 else if (xmlStrcmp(child->name, (const xmlChar *) "last_slope") == 0)
355 status = get_double_from_node(doc, child,
357 scratch[CDP_hw_last_slope].u_val);
358 else if (xmlStrcmp(child->name, (const xmlChar *) "nan_count") == 0)
359 status = get_int_from_node(doc, child,
361 scratch[CDP_null_count].u_cnt);
362 else if (xmlStrcmp(child->name, (const xmlChar *) "last_nan_count") ==
365 get_int_from_node(doc, child,
367 scratch[CDP_last_null_count].u_cnt);
368 else if (xmlStrcmp(child->name, (const xmlChar *) "seasonal") == 0)
369 status = get_double_from_node(doc, child,
370 &cdp_prep->scratch[CDP_hw_seasonal].
372 else if (xmlStrcmp(child->name, (const xmlChar *) "last_seasonal") ==
375 get_double_from_node(doc, child,
376 &cdp_prep->scratch[CDP_hw_last_seasonal].
378 else if (xmlStrcmp(child->name, (const xmlChar *) "init_flag") == 0)
379 status = get_int_from_node(doc, child,
381 scratch[CDP_init_seasonal].u_cnt);
382 else if (xmlStrcmp(child->name, (const xmlChar *) "history") == 0)
383 status = parse_tag_rra_cdp_prep_ds_history(doc, child, cdp_prep);
384 else if (xmlStrcmp(child->name, (const xmlChar *) "value") == 0)
385 status = get_double_from_node(doc, child,
386 &cdp_prep->scratch[CDP_val].u_val);
387 else if (xmlStrcmp(child->name,
388 (const xmlChar *) "unknown_datapoints") == 0)
389 status = get_int_from_node(doc, child,
391 scratch[CDP_unkn_pdp_cnt].u_cnt);
393 rrd_set_error("parse_tag_rra_cdp_prep: Unknown tag: %s",
403 } /* int parse_tag_rra_cdp_prep_ds */
405 static int parse_tag_rra_cdp_prep(
409 cdp_prep_t *cdp_prep)
414 unsigned int ds_count = 0;
417 for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
418 if ((xmlStrcmp(child->name, (const xmlChar *) "comment") == 0)
419 || (xmlStrcmp(child->name, (const xmlChar *) "text") == 0))
421 else if (xmlStrcmp(child->name, (const xmlChar *) "ds") == 0) {
422 if (ds_count >= rrd->stat_head->ds_cnt)
425 status = parse_tag_rra_cdp_prep_ds(doc, child, rrd,
426 cdp_prep + ds_count);
430 rrd_set_error("parse_tag_rra_cdp_prep: Unknown tag: %s",
439 if (ds_count != rrd->stat_head->ds_cnt) {
440 rrd_set_error("parse_tag_rra_cdp_prep: There are %i data sources in "
441 "the RRD file, but %i in this cdp_prep block!",
442 (int) rrd->stat_head->ds_cnt, ds_count);
447 } /* int parse_tag_rra_cdp_prep */
450 * Parse the <params> block within an RRA definition
452 static int parse_tag_rra_params(
461 for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
462 if ((xmlStrcmp(child->name, (const xmlChar *) "comment") == 0)
463 || (xmlStrcmp(child->name, (const xmlChar *) "text") == 0))
466 * Parameters for CF_HWPREDICT
468 else if (xmlStrcmp(child->name, (const xmlChar *) "hw_alpha") == 0)
469 status = get_double_from_node(doc, child,
470 &rra_def->par[RRA_hw_alpha].u_val);
471 else if (xmlStrcmp(child->name, (const xmlChar *) "hw_beta") == 0)
472 status = get_double_from_node(doc, child,
473 &rra_def->par[RRA_hw_beta].u_val);
474 else if (xmlStrcmp(child->name,
475 (const xmlChar *) "dependent_rra_idx") == 0)
476 status = get_int_from_node(doc, child,
478 par[RRA_dependent_rra_idx].u_cnt);
480 * Parameters for CF_SEASONAL and CF_DEVSEASONAL
482 else if (xmlStrcmp(child->name, (const xmlChar *) "seasonal_gamma") ==
485 get_double_from_node(doc, child,
486 &rra_def->par[RRA_seasonal_gamma].u_val);
488 (child->name, (const xmlChar *) "seasonal_smooth_idx") == 0)
490 get_int_from_node(doc, child,
492 par[RRA_seasonal_smooth_idx].u_cnt);
493 else if (xmlStrcmp(child->name, (const xmlChar *) "smoothing_window")
496 get_double_from_node(doc, child,
498 par[RRA_seasonal_smoothing_window].
500 /* else if (dependent_rra_idx) ...; */
502 * Parameters for CF_FAILURES
504 else if (xmlStrcmp(child->name, (const xmlChar *) "delta_pos") == 0)
505 status = get_double_from_node(doc, child,
506 &rra_def->par[RRA_delta_pos].u_val);
507 else if (xmlStrcmp(child->name, (const xmlChar *) "delta_neg") == 0)
508 status = get_double_from_node(doc, child,
509 &rra_def->par[RRA_delta_neg].u_val);
510 else if (xmlStrcmp(child->name, (const xmlChar *) "window_len") == 0)
511 status = get_int_from_node(doc, child,
512 (int *) &rra_def->par[RRA_window_len].
514 else if (xmlStrcmp(child->name, (const xmlChar *) "failure_threshold")
517 get_int_from_node(doc, child,
519 par[RRA_failure_threshold].u_cnt);
521 * Parameters for CF_AVERAGE, CF_MAXIMUM, CF_MINIMUM, and CF_LAST
523 else if (xmlStrcmp(child->name, (const xmlChar *) "xff") == 0)
524 status = get_double_from_node(doc, child,
525 &rra_def->par[RRA_cdp_xff_val].
528 * Compatibility code for 1.0.49
530 else if (xmlStrcmp(child->name, (const xmlChar *) "value") == 0) { /* {{{ */
534 if (i >= ARRAY_LENGTH(rra_def->par)) {
539 if ((i == RRA_dependent_rra_idx)
540 || (i == RRA_seasonal_smooth_idx)
541 || (i == RRA_failure_threshold))
542 status = get_int_from_node(doc, child,
543 (int *) &rra_def->par[i].
546 status = get_double_from_node(doc, child,
547 &rra_def->par[i].u_val);
552 /* When this loops exits (sucessfully) `child' points to the last
553 * `value' tag in the list. */
554 if ((child->next == NULL)
555 || (xmlStrcmp(child->name, (const xmlChar *) "value") !=
564 rrd_set_error("parse_tag_rra_params: Unknown tag: %s",
574 } /* int parse_tag_rra_params */
577 * Parse an RRA definition
579 static int parse_tag_rra_cf(
586 status = get_string_from_node(doc, node,
587 rra_def->cf_nam, sizeof(rra_def->cf_nam));
591 status = cf_conv(rra_def->cf_nam);
593 rrd_set_error("parse_tag_rra_cf: Unknown consolidation function: %s",
599 } /* int parse_tag_rra_cf */
601 static int parse_tag_rra(
609 rra_def_t *cur_rra_def;
610 cdp_prep_t *cur_cdp_prep;
611 rra_ptr_t *cur_rra_ptr;
613 /* Allocate more rra_def space for this RRA */
617 temp = (rra_def_t *) realloc(rrd->rra_def,
619 (rrd->stat_head->rra_cnt + 1));
621 rrd_set_error("parse_tag_rra: realloc failed.");
625 cur_rra_def = rrd->rra_def + rrd->stat_head->rra_cnt;
626 memset(cur_rra_def, '\0', sizeof(rra_def_t));
629 /* allocate cdp_prep_t */
633 temp = (cdp_prep_t *) realloc(rrd->cdp_prep, sizeof(cdp_prep_t)
634 * rrd->stat_head->ds_cnt
635 * (rrd->stat_head->rra_cnt + 1));
637 rrd_set_error("parse_tag_rra: realloc failed.");
640 rrd->cdp_prep = temp;
641 cur_cdp_prep = rrd->cdp_prep
642 + (rrd->stat_head->ds_cnt * rrd->stat_head->rra_cnt);
643 memset(cur_cdp_prep, '\0',
644 sizeof(cdp_prep_t) * rrd->stat_head->ds_cnt);
647 /* allocate rra_ptr_t */
651 temp = (rra_ptr_t *) realloc(rrd->rra_ptr,
653 (rrd->stat_head->rra_cnt + 1));
655 rrd_set_error("parse_tag_rra: realloc failed.");
659 cur_rra_ptr = rrd->rra_ptr + rrd->stat_head->rra_cnt;
660 memset(cur_rra_ptr, '\0', sizeof(rra_ptr_t));
663 /* All space successfully allocated, increment number of RRAs. */
664 rrd->stat_head->rra_cnt++;
667 for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
668 if ((xmlStrcmp(child->name, (const xmlChar *) "comment") == 0)
669 || (xmlStrcmp(child->name, (const xmlChar *) "text") == 0))
671 else if (xmlStrcmp(child->name, (const xmlChar *) "cf") == 0)
672 status = parse_tag_rra_cf(doc, child, cur_rra_def);
673 else if (xmlStrcmp(child->name, (const xmlChar *) "pdp_per_row") == 0)
674 status = get_int_from_node(doc, child,
675 (int *) &cur_rra_def->pdp_cnt);
676 else if (atoi(rrd->stat_head->version) == 1
677 && xmlStrcmp(child->name, (const xmlChar *) "xff") == 0)
678 status = get_double_from_node(doc, child,
679 (double *) &cur_rra_def->par[RRA_cdp_xff_val].u_val);
680 else if (atoi(rrd->stat_head->version) >= 2
681 && xmlStrcmp(child->name, (const xmlChar *) "params") == 0)
682 status = parse_tag_rra_params(doc, child, cur_rra_def);
683 else if (xmlStrcmp(child->name, (const xmlChar *) "cdp_prep") == 0)
684 status = parse_tag_rra_cdp_prep(doc, child, rrd, cur_cdp_prep);
685 else if (xmlStrcmp(child->name, (const xmlChar *) "database") == 0)
686 status = parse_tag_rra_database(doc, child, rrd);
688 rrd_set_error("parse_tag_rra: Unknown tag: %s", child->name);
696 /* Set the RRA pointer to the last value in the archive */
697 cur_rra_ptr->cur_row = cur_rra_def->row_cnt - 1;
700 } /* int parse_tag_rra */
703 * Parse a DS definition
705 static int parse_tag_ds_cdef(
713 status = get_string_from_node(doc, node, buffer, sizeof(buffer));
717 /* We're always working on the last DS that has been added to the structure
718 * when we get here */
719 parseCDEF_DS(buffer, rrd, rrd->stat_head->ds_cnt - 1);
722 } /* int parse_tag_ds_cdef */
724 static int parse_tag_ds_type(
731 status = get_string_from_node(doc, node,
732 ds_def->dst, sizeof(ds_def->dst));
736 status = dst_conv(ds_def->dst);
738 rrd_set_error("parse_tag_ds_type: Unknown data source type: %s",
744 } /* int parse_tag_ds_type */
746 static int parse_tag_ds(
754 ds_def_t *cur_ds_def;
755 pdp_prep_t *cur_pdp_prep;
758 * If there are DS definitions after RRA definitions the number of values,
759 * cdp_prep areas and so on will be calculated wrong. Thus, enforce a
760 * specific order in this case.
762 if (rrd->stat_head->rra_cnt > 0) {
763 rrd_set_error("parse_tag_ds: All data source definitions MUST "
764 "precede the RRA definitions!");
768 /* Allocate space for the new DS definition */
772 temp = (ds_def_t *) realloc(rrd->ds_def,
774 (rrd->stat_head->ds_cnt + 1));
776 rrd_set_error("parse_tag_ds: malloc failed.");
780 cur_ds_def = rrd->ds_def + rrd->stat_head->ds_cnt;
781 memset(cur_ds_def, '\0', sizeof(ds_def_t));
784 /* Allocate pdp_prep space for the new DS definition */
788 temp = (pdp_prep_t *) realloc(rrd->pdp_prep,
790 (rrd->stat_head->ds_cnt + 1));
792 rrd_set_error("parse_tag_ds: malloc failed.");
795 rrd->pdp_prep = temp;
796 cur_pdp_prep = rrd->pdp_prep + rrd->stat_head->ds_cnt;
797 memset(cur_pdp_prep, '\0', sizeof(pdp_prep_t));
800 /* All allocations successful, let's increment the number of DSes. */
801 rrd->stat_head->ds_cnt++;
804 for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
805 if ((xmlStrcmp(child->name, (const xmlChar *) "comment") == 0)
806 || (xmlStrcmp(child->name, (const xmlChar *) "text") == 0))
808 else if (xmlStrcmp(child->name, (const xmlChar *) "name") == 0)
809 status = get_string_from_node(doc, child,
811 sizeof(cur_ds_def->ds_nam));
812 else if (xmlStrcmp(child->name, (const xmlChar *) "type") == 0)
813 status = parse_tag_ds_type(doc, child, cur_ds_def);
814 else if (xmlStrcmp(child->name,
815 (const xmlChar *) "minimal_heartbeat") == 0)
816 status = get_int_from_node(doc, child,
817 (int *) &cur_ds_def->par[DS_mrhb_cnt].
819 else if (xmlStrcmp(child->name, (const xmlChar *) "min") == 0)
820 status = get_double_from_node(doc, child,
821 &cur_ds_def->par[DS_min_val].u_val);
822 else if (xmlStrcmp(child->name, (const xmlChar *) "max") == 0)
823 status = get_double_from_node(doc, child,
824 &cur_ds_def->par[DS_max_val].u_val);
825 else if (xmlStrcmp(child->name, (const xmlChar *) "cdef") == 0)
826 status = parse_tag_ds_cdef(doc, child, rrd);
827 else if (xmlStrcmp(child->name, (const xmlChar *) "last_ds") == 0)
828 status = get_string_from_node(doc, child,
829 cur_pdp_prep->last_ds,
830 sizeof(cur_pdp_prep->last_ds));
831 else if (xmlStrcmp(child->name, (const xmlChar *) "value") == 0)
832 status = get_double_from_node(doc, child,
833 &cur_pdp_prep->scratch[PDP_val].
835 else if (xmlStrcmp(child->name, (const xmlChar *) "unknown_sec") == 0)
836 status = get_int_from_node(doc, child,
837 (int *) &cur_pdp_prep->
838 scratch[PDP_unkn_sec_cnt].u_cnt);
840 rrd_set_error("parse_tag_ds: Unknown tag: %s", child->name);
849 } /* int parse_tag_ds */
854 static int parse_tag_rrd(
863 for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
864 if ((xmlStrcmp(child->name, (const xmlChar *) "comment") == 0)
865 || (xmlStrcmp(child->name, (const xmlChar *) "text") == 0))
867 else if (xmlStrcmp(child->name, (const xmlChar *) "version") == 0)
868 status = get_string_from_node(doc, child,
869 rrd->stat_head->version,
870 sizeof(rrd->stat_head->version));
871 else if (xmlStrcmp(child->name, (const xmlChar *) "step") == 0)
872 status = get_int_from_node(doc, child,
873 (int *) &rrd->stat_head->pdp_step);
874 else if (xmlStrcmp(child->name, (const xmlChar *) "lastupdate") == 0)
875 status = get_int_from_node(doc, child,
876 (int *) &rrd->live_head->last_up);
877 else if (xmlStrcmp(child->name, (const xmlChar *) "ds") == 0)
878 status = parse_tag_ds(doc, child, rrd);
879 else if (xmlStrcmp(child->name, (const xmlChar *) "rra") == 0)
880 status = parse_tag_rra(doc, child, rrd);
882 rrd_set_error("parse_tag_rrd: Unknown tag: %s", child->name);
891 } /* int parse_tag_rrd */
893 static rrd_t *parse_file(
894 const char *filename)
902 doc = xmlParseFile(filename);
904 rrd_set_error("Document not parsed successfully.");
908 cur = xmlDocGetRootElement(doc);
910 rrd_set_error("Document is empty.");
915 if (xmlStrcmp(cur->name, (const xmlChar *) "rrd") != 0) {
917 ("Document of the wrong type, root node is not \"rrd\".");
922 rrd = (rrd_t *) malloc(sizeof(rrd_t));
924 rrd_set_error("parse_file: malloc failed.");
928 memset(rrd, '\0', sizeof(rrd_t));
930 rrd->stat_head = (stat_head_t *) malloc(sizeof(stat_head_t));
931 if (rrd->stat_head == NULL) {
932 rrd_set_error("parse_tag_rrd: malloc failed.");
937 memset(rrd->stat_head, '\0', sizeof(stat_head_t));
939 strncpy(rrd->stat_head->cookie, "RRD", sizeof(rrd->stat_head->cookie));
940 rrd->stat_head->float_cookie = FLOAT_COOKIE;
942 rrd->live_head = (live_head_t *) malloc(sizeof(live_head_t));
943 if (rrd->live_head == NULL) {
944 rrd_set_error("parse_tag_rrd: malloc failed.");
946 free(rrd->stat_head);
950 memset(rrd->live_head, '\0', sizeof(live_head_t));
952 status = parse_tag_rrd(doc, cur, rrd);
961 } /* rrd_t *parse_file */
963 static int write_file(
964 const char *file_name,
969 unsigned int value_count;
971 if (strcmp("-", file_name) == 0)
974 int fd_flags = O_WRONLY | O_CREAT;
977 #if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
978 fd_flags |= O_BINARY;
981 if (opt_force_overwrite == 0)
984 fd = open(file_name, fd_flags, 0666);
986 rrd_set_error("creating '%s': %s", file_name,
987 rrd_strerror(errno));
991 fh = fdopen(fd, "wb");
993 rrd_set_error("fdopen failed: %s", rrd_strerror(errno));
998 if (atoi(rrd->stat_head->version) < 3){
999 /* we output 3 or higher */
1000 strcpy(rrd->stat_head->version,"0003");
1002 fwrite(rrd->stat_head, sizeof(stat_head_t), 1, fh);
1003 fwrite(rrd->ds_def, sizeof(ds_def_t), rrd->stat_head->ds_cnt, fh);
1004 fwrite(rrd->rra_def, sizeof(rra_def_t), rrd->stat_head->rra_cnt, fh);
1005 fwrite(rrd->live_head, sizeof(live_head_t), 1, fh);
1006 fwrite(rrd->pdp_prep, sizeof(pdp_prep_t), rrd->stat_head->ds_cnt, fh);
1007 fwrite(rrd->cdp_prep, sizeof(cdp_prep_t),
1008 rrd->stat_head->rra_cnt * rrd->stat_head->ds_cnt, fh);
1009 fwrite(rrd->rra_ptr, sizeof(rra_ptr_t), rrd->stat_head->rra_cnt, fh);
1011 /* calculate the number of rrd_values to dump */
1013 for (i = 0; i < rrd->stat_head->rra_cnt; i++)
1014 value_count += (rrd->rra_def[i].row_cnt * rrd->stat_head->ds_cnt);
1016 fwrite(rrd->rrd_value, sizeof(rrd_value_t), value_count, fh);
1018 /* lets see if we had an error */
1020 rrd_set_error("a file error occurred while creating '%s'", file_name);
1027 } /* int write_file */
1035 /* init rrd clean */
1037 opterr = 0; /* initialize getopt */
1040 int option_index = 0;
1041 static struct option long_options[] = {
1042 {"range-check", no_argument, 0, 'r'},
1043 {"force-overwrite", no_argument, 0, 'f'},
1047 opt = getopt_long(argc, argv, "rf", long_options, &option_index);
1054 opt_range_check = 1;
1058 opt_force_overwrite = 1;
1062 rrd_set_error("usage rrdtool %s [--range-check|-r] "
1063 "[--force-overwrite/-f] file.xml file.rrd",
1070 if ((argc - optind) != 2) {
1071 rrd_set_error("usage rrdtool %s [--range-check/-r] "
1072 "[--force-overwrite/-f] file.xml file.rrd", argv[0]);
1076 rrd = parse_file(argv[optind]);
1080 if (write_file(argv[optind + 1], rrd) != 0) {
1087 } /* int rrd_restore */
1089 /* vim: set sw=2 sts=2 ts=8 et fdm=marker : */