1 /*****************************************************************************
2 * RRDtool 1.3.2 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>
37 # include <unistd.h> /* for off_t */
39 typedef size_t ssize_t;
44 #if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
49 #include <libxml/parser.h>
51 #include "rrd_rpncalc.h"
52 #define ARRAY_LENGTH(a) (sizeof (a) / sizeof ((a)[0]))
53 static int opt_range_check = 0;
54 static int opt_force_overwrite = 0;
59 static int get_string_from_node(
69 temp0 = xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
71 rrd_set_error("get_string_from_node: xmlNodeListGetString failed.");
75 begin_ptr = (char *) temp0;
76 while ((begin_ptr[0] != 0) && (isspace(begin_ptr[0])))
79 if (begin_ptr[0] == 0) {
86 while ((end_ptr[0] != 0) && (!isspace(end_ptr[0])))
90 strncpy(buffer, begin_ptr, buffer_size);
91 buffer[buffer_size - 1] = 0;
96 } /* int get_string_from_node */
98 static int get_long_from_node(
107 str_ptr = (char *) xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
108 if (str_ptr == NULL) {
109 rrd_set_error("get_long_from_node: xmlNodeListGetString failed.");
114 temp = strtol(str_ptr, &end_ptr, 0);
117 if (str_ptr == end_ptr) {
118 rrd_set_error("get_long_from_node: Cannot parse buffer as long: %s",
126 } /* int get_long_from_node */
128 static int get_ulong_from_node(
131 unsigned long *value)
137 str_ptr = (char *) xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
138 if (str_ptr == NULL) {
139 rrd_set_error("get_ulong_from_node: xmlNodeListGetString failed.");
144 temp = strtoul(str_ptr, &end_ptr, 0);
147 if (str_ptr == end_ptr) {
148 rrd_set_error("get_ulong_from_node: Cannot parse buffer as unsigned long: %s",
156 } /* int get_ulong_from_node */
158 static int get_double_from_node(
167 str_ptr = (char *) xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
168 if (str_ptr == NULL) {
169 rrd_set_error("get_double_from_node: xmlNodeListGetString failed.");
173 if (strstr(str_ptr, "NaN") != NULL)
181 temp = strtod(str_ptr, &end_ptr);
184 if (str_ptr == end_ptr) {
186 ("get_double_from_node: Cannot parse buffer as double: %s",
194 } /* int get_double_from_node */
196 static int value_check_range(
197 rrd_value_t *rrd_value,
198 const ds_def_t *ds_def)
203 if (opt_range_check == 0)
206 min = ds_def->par[DS_min_val].u_val;
207 max = ds_def->par[DS_max_val].u_val;
209 if (((!isnan(min)) && (*rrd_value < min))
210 || ((!isnan(max)) && (*rrd_value > max)))
214 } /* int value_check_range */
217 * Parse the <database> block within an RRA definition
219 static int parse_tag_rra_database_row(
223 rrd_value_t *rrd_value)
225 unsigned int values_count = 0;
230 for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
231 if ((xmlStrcmp(child->name, (const xmlChar *) "comment") == 0)
232 || (xmlStrcmp(child->name, (const xmlChar *) "text") == 0))
234 else if (xmlStrcmp(child->name, (const xmlChar *) "v") == 0) {
235 if (values_count < rrd->stat_head->ds_cnt) {
237 get_double_from_node(doc, child,
238 rrd_value + values_count);
240 value_check_range(rrd_value + values_count,
241 rrd->ds_def + values_count);
246 rrd_set_error("parse_tag_rra_database_row: Unknown tag: %s",
253 } /* for (child = node->xmlChildrenNode) */
255 if (values_count != rrd->stat_head->ds_cnt) {
256 rrd_set_error("parse_tag_rra_database_row: Row has %u values "
257 "and RRD has %lu data sources.",
258 values_count, rrd->stat_head->ds_cnt);
263 } /* int parse_tag_rra_database_row */
265 static int parse_tag_rra_database(
270 rra_def_t *cur_rra_def;
271 unsigned int total_row_cnt;
277 for (i = 0; i < (((int) rrd->stat_head->rra_cnt) - 1); i++)
278 total_row_cnt += rrd->rra_def[i].row_cnt;
280 cur_rra_def = rrd->rra_def + i;
283 for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
284 if ((xmlStrcmp(child->name, (const xmlChar *) "comment") == 0)
285 || (xmlStrcmp(child->name, (const xmlChar *) "text") == 0))
287 else if (xmlStrcmp(child->name, (const xmlChar *) "row") == 0) {
289 rrd_value_t *cur_rrd_value;
290 unsigned int total_values_count = rrd->stat_head->ds_cnt
291 * (total_row_cnt + 1);
293 /* Allocate space for the new values.. */
294 temp = (rrd_value_t *) realloc(rrd->rrd_value,
295 sizeof(rrd_value_t) *
298 rrd_set_error("parse_tag_rra_database: realloc failed.");
302 rrd->rrd_value = temp;
303 cur_rrd_value = rrd->rrd_value
304 + (rrd->stat_head->ds_cnt * total_row_cnt);
305 memset(cur_rrd_value, '\0',
306 sizeof(rrd_value_t) * rrd->stat_head->ds_cnt);
308 cur_rra_def->row_cnt++;
311 parse_tag_rra_database_row(doc, child, rrd, cur_rrd_value);
312 } /* if (xmlStrcmp (child->name, (const xmlChar *) "row") == 0) */
314 rrd_set_error("parse_tag_rra_database: Unknown tag: %s",
321 } /* for (child = node->xmlChildrenNode) */
324 } /* int parse_tag_rra_database */
327 * Parse the <cdp_prep> block within an RRA definition
329 static int parse_tag_rra_cdp_prep_ds_history(
332 cdp_prep_t *cdp_prep)
334 /* Make `history_buffer' the same size as the scratch area, plus the
335 * terminating NULL byte. */
336 char history_buffer[sizeof(((cdp_prep_t *)0)->scratch) + 1];
341 status = get_string_from_node(doc, node,
342 history_buffer, sizeof(history_buffer));
346 history_ptr = (char *) (&cdp_prep->scratch[0]);
347 for (i = 0; history_buffer[i] != '\0'; i++)
348 history_ptr[i] = (history_buffer[i] == '1') ? 1 : 0;
351 } /* int parse_tag_rra_cdp_prep_ds_history */
353 static int parse_tag_rra_cdp_prep_ds(
357 cdp_prep_t *cdp_prep)
362 memset(cdp_prep, '\0', sizeof(cdp_prep_t));
365 for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
366 if (atoi(rrd->stat_head->version) == 1) {
367 cdp_prep->scratch[CDP_primary_val].u_val = 0.0;
368 cdp_prep->scratch[CDP_secondary_val].u_val = 0.0;
370 if ((xmlStrcmp(child->name, (const xmlChar *) "comment") == 0)
371 || (xmlStrcmp(child->name, (const xmlChar *) "text") == 0))
373 else if (xmlStrcmp(child->name, (const xmlChar *) "primary_value") ==
376 get_double_from_node(doc, child,
377 &cdp_prep->scratch[CDP_primary_val].
379 else if (xmlStrcmp(child->name, (const xmlChar *) "secondary_value")
382 get_double_from_node(doc, child,
383 &cdp_prep->scratch[CDP_secondary_val].
385 else if (xmlStrcmp(child->name, (const xmlChar *) "intercept") == 0)
386 status = get_double_from_node(doc, child,
388 scratch[CDP_hw_intercept].u_val);
389 else if (xmlStrcmp(child->name, (const xmlChar *) "last_intercept") ==
392 get_double_from_node(doc, child,
394 scratch[CDP_hw_last_intercept].u_val);
395 else if (xmlStrcmp(child->name, (const xmlChar *) "slope") == 0)
396 status = get_double_from_node(doc, child,
397 &cdp_prep->scratch[CDP_hw_slope].
399 else if (xmlStrcmp(child->name, (const xmlChar *) "last_slope") == 0)
400 status = get_double_from_node(doc, child,
402 scratch[CDP_hw_last_slope].u_val);
403 else if (xmlStrcmp(child->name, (const xmlChar *) "nan_count") == 0)
404 status = get_ulong_from_node(doc, child,
406 scratch[CDP_null_count].u_cnt);
407 else if (xmlStrcmp(child->name, (const xmlChar *) "last_nan_count") ==
410 get_ulong_from_node(doc, child,
412 scratch[CDP_last_null_count].u_cnt);
413 else if (xmlStrcmp(child->name, (const xmlChar *) "seasonal") == 0)
414 status = get_double_from_node(doc, child,
415 &cdp_prep->scratch[CDP_hw_seasonal].
417 else if (xmlStrcmp(child->name, (const xmlChar *) "last_seasonal") ==
420 get_double_from_node(doc, child,
421 &cdp_prep->scratch[CDP_hw_last_seasonal].
423 else if (xmlStrcmp(child->name, (const xmlChar *) "init_flag") == 0)
424 status = get_ulong_from_node(doc, child,
426 scratch[CDP_init_seasonal].u_cnt);
427 else if (xmlStrcmp(child->name, (const xmlChar *) "history") == 0)
428 status = parse_tag_rra_cdp_prep_ds_history(doc, child, cdp_prep);
429 else if (xmlStrcmp(child->name, (const xmlChar *) "value") == 0)
430 status = get_double_from_node(doc, child,
431 &cdp_prep->scratch[CDP_val].u_val);
432 else if (xmlStrcmp(child->name,
433 (const xmlChar *) "unknown_datapoints") == 0)
434 status = get_ulong_from_node(doc, child,
436 scratch[CDP_unkn_pdp_cnt].u_cnt);
438 rrd_set_error("parse_tag_rra_cdp_prep: Unknown tag: %s",
448 } /* int parse_tag_rra_cdp_prep_ds */
450 static int parse_tag_rra_cdp_prep(
454 cdp_prep_t *cdp_prep)
459 unsigned int ds_count = 0;
462 for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
463 if ((xmlStrcmp(child->name, (const xmlChar *) "comment") == 0)
464 || (xmlStrcmp(child->name, (const xmlChar *) "text") == 0))
466 else if (xmlStrcmp(child->name, (const xmlChar *) "ds") == 0) {
467 if (ds_count >= rrd->stat_head->ds_cnt)
470 status = parse_tag_rra_cdp_prep_ds(doc, child, rrd,
471 cdp_prep + ds_count);
475 rrd_set_error("parse_tag_rra_cdp_prep: Unknown tag: %s",
484 if (ds_count != rrd->stat_head->ds_cnt) {
485 rrd_set_error("parse_tag_rra_cdp_prep: There are %i data sources in "
486 "the RRD file, but %i in this cdp_prep block!",
487 (int) rrd->stat_head->ds_cnt, ds_count);
492 } /* int parse_tag_rra_cdp_prep */
495 * Parse the <params> block within an RRA definition
497 static int parse_tag_rra_params(
506 for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
507 if ((xmlStrcmp(child->name, (const xmlChar *) "comment") == 0)
508 || (xmlStrcmp(child->name, (const xmlChar *) "text") == 0))
511 * Parameters for CF_HWPREDICT
513 else if (xmlStrcmp(child->name, (const xmlChar *) "hw_alpha") == 0)
514 status = get_double_from_node(doc, child,
515 &rra_def->par[RRA_hw_alpha].u_val);
516 else if (xmlStrcmp(child->name, (const xmlChar *) "hw_beta") == 0)
517 status = get_double_from_node(doc, child,
518 &rra_def->par[RRA_hw_beta].u_val);
519 else if (xmlStrcmp(child->name,
520 (const xmlChar *) "dependent_rra_idx") == 0)
521 status = get_ulong_from_node(doc, child,
523 par[RRA_dependent_rra_idx].u_cnt);
525 * Parameters for CF_SEASONAL and CF_DEVSEASONAL
527 else if (xmlStrcmp(child->name, (const xmlChar *) "seasonal_gamma") ==
530 get_double_from_node(doc, child,
531 &rra_def->par[RRA_seasonal_gamma].u_val);
533 (child->name, (const xmlChar *) "seasonal_smooth_idx") == 0)
535 get_ulong_from_node(doc, child,
537 par[RRA_seasonal_smooth_idx].u_cnt);
538 else if (xmlStrcmp(child->name, (const xmlChar *) "smoothing_window")
541 get_double_from_node(doc, child,
543 par[RRA_seasonal_smoothing_window].
545 /* else if (dependent_rra_idx) ...; */
547 * Parameters for CF_FAILURES
549 else if (xmlStrcmp(child->name, (const xmlChar *) "delta_pos") == 0)
550 status = get_double_from_node(doc, child,
551 &rra_def->par[RRA_delta_pos].u_val);
552 else if (xmlStrcmp(child->name, (const xmlChar *) "delta_neg") == 0)
553 status = get_double_from_node(doc, child,
554 &rra_def->par[RRA_delta_neg].u_val);
555 else if (xmlStrcmp(child->name, (const xmlChar *) "window_len") == 0)
556 status = get_ulong_from_node(doc, child,
557 &rra_def->par[RRA_window_len].
559 else if (xmlStrcmp(child->name, (const xmlChar *) "failure_threshold")
562 get_ulong_from_node(doc, child,
564 par[RRA_failure_threshold].u_cnt);
566 * Parameters for CF_AVERAGE, CF_MAXIMUM, CF_MINIMUM, and CF_LAST
568 else if (xmlStrcmp(child->name, (const xmlChar *) "xff") == 0)
569 status = get_double_from_node(doc, child,
570 &rra_def->par[RRA_cdp_xff_val].
573 * Compatibility code for 1.0.49
575 else if (xmlStrcmp(child->name, (const xmlChar *) "value") == 0) { /* {{{ */
579 if (i >= ARRAY_LENGTH(rra_def->par)) {
584 if ((i == RRA_dependent_rra_idx)
585 || (i == RRA_seasonal_smooth_idx)
586 || (i == RRA_failure_threshold))
587 status = get_ulong_from_node(doc, child,
591 status = get_double_from_node(doc, child,
592 &rra_def->par[i].u_val);
597 /* When this loops exits (sucessfully) `child' points to the last
598 * `value' tag in the list. */
599 if ((child->next == NULL)
600 || (xmlStrcmp(child->name, (const xmlChar *) "value") !=
609 rrd_set_error("parse_tag_rra_params: Unknown tag: %s",
619 } /* int parse_tag_rra_params */
622 * Parse an RRA definition
624 static int parse_tag_rra_cf(
631 status = get_string_from_node(doc, node,
632 rra_def->cf_nam, sizeof(rra_def->cf_nam));
636 status = cf_conv(rra_def->cf_nam);
638 rrd_set_error("parse_tag_rra_cf: Unknown consolidation function: %s",
644 } /* int parse_tag_rra_cf */
646 static int parse_tag_rra(
654 rra_def_t *cur_rra_def;
655 cdp_prep_t *cur_cdp_prep;
656 rra_ptr_t *cur_rra_ptr;
658 /* Allocate more rra_def space for this RRA */
662 temp = (rra_def_t *) realloc(rrd->rra_def,
664 (rrd->stat_head->rra_cnt + 1));
666 rrd_set_error("parse_tag_rra: realloc failed.");
670 cur_rra_def = rrd->rra_def + rrd->stat_head->rra_cnt;
671 memset(cur_rra_def, '\0', sizeof(rra_def_t));
674 /* allocate cdp_prep_t */
678 temp = (cdp_prep_t *) realloc(rrd->cdp_prep, sizeof(cdp_prep_t)
679 * rrd->stat_head->ds_cnt
680 * (rrd->stat_head->rra_cnt + 1));
682 rrd_set_error("parse_tag_rra: realloc failed.");
685 rrd->cdp_prep = temp;
686 cur_cdp_prep = rrd->cdp_prep
687 + (rrd->stat_head->ds_cnt * rrd->stat_head->rra_cnt);
688 memset(cur_cdp_prep, '\0',
689 sizeof(cdp_prep_t) * rrd->stat_head->ds_cnt);
692 /* allocate rra_ptr_t */
696 temp = (rra_ptr_t *) realloc(rrd->rra_ptr,
698 (rrd->stat_head->rra_cnt + 1));
700 rrd_set_error("parse_tag_rra: realloc failed.");
704 cur_rra_ptr = rrd->rra_ptr + rrd->stat_head->rra_cnt;
705 memset(cur_rra_ptr, '\0', sizeof(rra_ptr_t));
708 /* All space successfully allocated, increment number of RRAs. */
709 rrd->stat_head->rra_cnt++;
712 for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
713 if ((xmlStrcmp(child->name, (const xmlChar *) "comment") == 0)
714 || (xmlStrcmp(child->name, (const xmlChar *) "text") == 0))
716 else if (xmlStrcmp(child->name, (const xmlChar *) "cf") == 0)
717 status = parse_tag_rra_cf(doc, child, cur_rra_def);
718 else if (xmlStrcmp(child->name, (const xmlChar *) "pdp_per_row") == 0)
719 status = get_ulong_from_node(doc, child,
720 &cur_rra_def->pdp_cnt);
721 else if (atoi(rrd->stat_head->version) == 1
722 && xmlStrcmp(child->name, (const xmlChar *) "xff") == 0)
723 status = get_double_from_node(doc, child,
724 (double *) &cur_rra_def->
725 par[RRA_cdp_xff_val].u_val);
726 else if (atoi(rrd->stat_head->version) >= 2
727 && xmlStrcmp(child->name, (const xmlChar *) "params") == 0)
728 status = parse_tag_rra_params(doc, child, cur_rra_def);
729 else if (xmlStrcmp(child->name, (const xmlChar *) "cdp_prep") == 0)
730 status = parse_tag_rra_cdp_prep(doc, child, rrd, cur_cdp_prep);
731 else if (xmlStrcmp(child->name, (const xmlChar *) "database") == 0)
732 status = parse_tag_rra_database(doc, child, rrd);
734 rrd_set_error("parse_tag_rra: Unknown tag: %s", child->name);
742 /* Set the RRA pointer to a random location */
743 cur_rra_ptr->cur_row = rrd_random() % cur_rra_def->row_cnt;
746 } /* int parse_tag_rra */
749 * Parse a DS definition
751 static int parse_tag_ds_cdef(
759 status = get_string_from_node(doc, node, buffer, sizeof(buffer));
763 /* We're always working on the last DS that has been added to the structure
764 * when we get here */
765 parseCDEF_DS(buffer, rrd, rrd->stat_head->ds_cnt - 1);
768 } /* int parse_tag_ds_cdef */
770 static int parse_tag_ds_type(
777 status = get_string_from_node(doc, node,
778 ds_def->dst, sizeof(ds_def->dst));
782 status = dst_conv(ds_def->dst);
784 rrd_set_error("parse_tag_ds_type: Unknown data source type: %s",
790 } /* int parse_tag_ds_type */
792 static int parse_tag_ds(
800 ds_def_t *cur_ds_def;
801 pdp_prep_t *cur_pdp_prep;
804 * If there are DS definitions after RRA definitions the number of values,
805 * cdp_prep areas and so on will be calculated wrong. Thus, enforce a
806 * specific order in this case.
808 if (rrd->stat_head->rra_cnt > 0) {
809 rrd_set_error("parse_tag_ds: All data source definitions MUST "
810 "precede the RRA definitions!");
814 /* Allocate space for the new DS definition */
818 temp = (ds_def_t *) realloc(rrd->ds_def,
820 (rrd->stat_head->ds_cnt + 1));
822 rrd_set_error("parse_tag_ds: malloc failed.");
826 cur_ds_def = rrd->ds_def + rrd->stat_head->ds_cnt;
827 memset(cur_ds_def, '\0', sizeof(ds_def_t));
830 /* Allocate pdp_prep space for the new DS definition */
834 temp = (pdp_prep_t *) realloc(rrd->pdp_prep,
836 (rrd->stat_head->ds_cnt + 1));
838 rrd_set_error("parse_tag_ds: malloc failed.");
841 rrd->pdp_prep = temp;
842 cur_pdp_prep = rrd->pdp_prep + rrd->stat_head->ds_cnt;
843 memset(cur_pdp_prep, '\0', sizeof(pdp_prep_t));
846 /* All allocations successful, let's increment the number of DSes. */
847 rrd->stat_head->ds_cnt++;
850 for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
851 if ((xmlStrcmp(child->name, (const xmlChar *) "comment") == 0)
852 || (xmlStrcmp(child->name, (const xmlChar *) "text") == 0))
854 else if (xmlStrcmp(child->name, (const xmlChar *) "name") == 0)
855 status = get_string_from_node(doc, child,
857 sizeof(cur_ds_def->ds_nam));
858 else if (xmlStrcmp(child->name, (const xmlChar *) "type") == 0)
859 status = parse_tag_ds_type(doc, child, cur_ds_def);
860 else if (xmlStrcmp(child->name,
861 (const xmlChar *) "minimal_heartbeat") == 0)
862 status = get_ulong_from_node(doc, child,
863 &cur_ds_def->par[DS_mrhb_cnt].
865 else if (xmlStrcmp(child->name, (const xmlChar *) "min") == 0)
866 status = get_double_from_node(doc, child,
867 &cur_ds_def->par[DS_min_val].u_val);
868 else if (xmlStrcmp(child->name, (const xmlChar *) "max") == 0)
869 status = get_double_from_node(doc, child,
870 &cur_ds_def->par[DS_max_val].u_val);
871 else if (xmlStrcmp(child->name, (const xmlChar *) "cdef") == 0)
872 status = parse_tag_ds_cdef(doc, child, rrd);
873 else if (xmlStrcmp(child->name, (const xmlChar *) "last_ds") == 0)
874 status = get_string_from_node(doc, child,
875 cur_pdp_prep->last_ds,
876 sizeof(cur_pdp_prep->last_ds));
877 else if (xmlStrcmp(child->name, (const xmlChar *) "value") == 0)
878 status = get_double_from_node(doc, child,
879 &cur_pdp_prep->scratch[PDP_val].
881 else if (xmlStrcmp(child->name, (const xmlChar *) "unknown_sec") == 0)
882 status = get_ulong_from_node(doc, child,
884 scratch[PDP_unkn_sec_cnt].u_cnt);
886 rrd_set_error("parse_tag_ds: Unknown tag: %s", child->name);
895 } /* int parse_tag_ds */
900 static int parse_tag_rrd(
909 for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
910 if ((xmlStrcmp(child->name, (const xmlChar *) "comment") == 0)
911 || (xmlStrcmp(child->name, (const xmlChar *) "text") == 0))
913 else if (xmlStrcmp(child->name, (const xmlChar *) "version") == 0)
914 status = get_string_from_node(doc, child,
915 rrd->stat_head->version,
916 sizeof(rrd->stat_head->version));
917 else if (xmlStrcmp(child->name, (const xmlChar *) "step") == 0)
918 status = get_ulong_from_node(doc, child,
919 &rrd->stat_head->pdp_step);
920 else if (xmlStrcmp(child->name, (const xmlChar *) "lastupdate") == 0)
921 status = get_long_from_node(doc, child,
922 &rrd->live_head->last_up);
923 else if (xmlStrcmp(child->name, (const xmlChar *) "ds") == 0)
924 status = parse_tag_ds(doc, child, rrd);
925 else if (xmlStrcmp(child->name, (const xmlChar *) "rra") == 0)
926 status = parse_tag_rra(doc, child, rrd);
928 rrd_set_error("parse_tag_rrd: Unknown tag: %s", child->name);
937 } /* int parse_tag_rrd */
939 static rrd_t *parse_file(
940 const char *filename)
948 doc = xmlParseFile(filename);
950 rrd_set_error("Document not parsed successfully.");
954 cur = xmlDocGetRootElement(doc);
956 rrd_set_error("Document is empty.");
961 if (xmlStrcmp(cur->name, (const xmlChar *) "rrd") != 0) {
963 ("Document of the wrong type, root node is not \"rrd\".");
968 rrd = (rrd_t *) malloc(sizeof(rrd_t));
970 rrd_set_error("parse_file: malloc failed.");
974 memset(rrd, '\0', sizeof(rrd_t));
976 rrd->stat_head = (stat_head_t *) malloc(sizeof(stat_head_t));
977 if (rrd->stat_head == NULL) {
978 rrd_set_error("parse_tag_rrd: malloc failed.");
983 memset(rrd->stat_head, '\0', sizeof(stat_head_t));
985 strncpy(rrd->stat_head->cookie, "RRD", sizeof(rrd->stat_head->cookie));
986 rrd->stat_head->float_cookie = FLOAT_COOKIE;
988 rrd->live_head = (live_head_t *) malloc(sizeof(live_head_t));
989 if (rrd->live_head == NULL) {
990 rrd_set_error("parse_tag_rrd: malloc failed.");
992 free(rrd->stat_head);
996 memset(rrd->live_head, '\0', sizeof(live_head_t));
998 status = parse_tag_rrd(doc, cur, rrd);
1007 } /* rrd_t *parse_file */
1009 static int write_file(
1010 const char *file_name,
1015 unsigned int rra_offset;
1017 if (strcmp("-", file_name) == 0)
1020 int fd_flags = O_WRONLY | O_CREAT;
1023 #if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
1024 fd_flags |= O_BINARY;
1027 if (opt_force_overwrite == 0)
1030 fd = open(file_name, fd_flags, 0666);
1032 rrd_set_error("creating '%s': %s", file_name,
1033 rrd_strerror(errno));
1037 fh = fdopen(fd, "wb");
1039 rrd_set_error("fdopen failed: %s", rrd_strerror(errno));
1044 if (atoi(rrd->stat_head->version) < 3) {
1045 /* we output 3 or higher */
1046 strcpy(rrd->stat_head->version, "0003");
1048 fwrite(rrd->stat_head, sizeof(stat_head_t), 1, fh);
1049 fwrite(rrd->ds_def, sizeof(ds_def_t), rrd->stat_head->ds_cnt, fh);
1050 fwrite(rrd->rra_def, sizeof(rra_def_t), rrd->stat_head->rra_cnt, fh);
1051 fwrite(rrd->live_head, sizeof(live_head_t), 1, fh);
1052 fwrite(rrd->pdp_prep, sizeof(pdp_prep_t), rrd->stat_head->ds_cnt, fh);
1053 fwrite(rrd->cdp_prep, sizeof(cdp_prep_t),
1054 rrd->stat_head->rra_cnt * rrd->stat_head->ds_cnt, fh);
1055 fwrite(rrd->rra_ptr, sizeof(rra_ptr_t), rrd->stat_head->rra_cnt, fh);
1057 /* calculate the number of rrd_values to dump */
1059 for (i = 0; i < rrd->stat_head->rra_cnt; i++) {
1060 unsigned long num_rows = rrd->rra_def[i].row_cnt;
1061 unsigned long cur_row = rrd->rra_ptr[i].cur_row;
1062 unsigned long ds_cnt = rrd->stat_head->ds_cnt;
1064 fwrite(rrd->rrd_value +
1065 (rra_offset + num_rows - 1 - cur_row) * ds_cnt,
1066 sizeof(rrd_value_t), (cur_row + 1) * ds_cnt, fh);
1068 fwrite(rrd->rrd_value + rra_offset * ds_cnt,
1069 sizeof(rrd_value_t), (num_rows - 1 - cur_row) * ds_cnt, fh);
1071 rra_offset += num_rows;
1074 /* lets see if we had an error */
1076 rrd_set_error("a file error occurred while creating '%s'", file_name);
1083 } /* int write_file */
1091 /* init rrd clean */
1093 opterr = 0; /* initialize getopt */
1096 int option_index = 0;
1097 static struct option long_options[] = {
1098 {"range-check", no_argument, 0, 'r'},
1099 {"force-overwrite", no_argument, 0, 'f'},
1103 opt = getopt_long(argc, argv, "rf", long_options, &option_index);
1110 opt_range_check = 1;
1114 opt_force_overwrite = 1;
1118 rrd_set_error("usage rrdtool %s [--range-check|-r] "
1119 "[--force-overwrite/-f] file.xml file.rrd",
1126 if ((argc - optind) != 2) {
1127 rrd_set_error("usage rrdtool %s [--range-check/-r] "
1128 "[--force-overwrite/-f] file.xml file.rrd", argv[0]);
1132 rrd = parse_file(argv[optind]);
1136 if (write_file(argv[optind + 1], rrd) != 0) {
1143 } /* int rrd_restore */
1145 /* vim: set sw=2 sts=2 ts=8 et fdm=marker : */