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 # define random() rand()
40 # define srandom(x) srand(x)
42 typedef size_t ssize_t;
47 #if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
52 #include <libxml/parser.h>
54 #include "rrd_rpncalc.h"
55 #define ARRAY_LENGTH(a) (sizeof (a) / sizeof ((a)[0]))
56 static int opt_range_check = 0;
57 static int opt_force_overwrite = 0;
62 static int get_string_from_node(
72 temp0 = xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
74 rrd_set_error("get_string_from_node: xmlNodeListGetString failed.");
78 begin_ptr = (char *) temp0;
79 while ((begin_ptr[0] != 0) && (isspace(begin_ptr[0])))
82 if (begin_ptr[0] == 0) {
89 while ((end_ptr[0] != 0) && (!isspace(end_ptr[0])))
93 strncpy(buffer, begin_ptr, buffer_size);
94 buffer[buffer_size - 1] = 0;
99 } /* int get_string_from_node */
101 static int get_int_from_node(
110 str_ptr = (char *) xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
111 if (str_ptr == NULL) {
112 rrd_set_error("get_int_from_node: xmlNodeListGetString failed.");
117 temp = strtol(str_ptr, &end_ptr, 0);
120 if (str_ptr == end_ptr) {
121 rrd_set_error("get_int_from_node: Cannot parse buffer as int: %s",
129 } /* int get_int_from_node */
131 static int get_double_from_node(
140 str_ptr = (char *) xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
141 if (str_ptr == NULL) {
142 rrd_set_error("get_double_from_node: xmlNodeListGetString failed.");
146 if (strstr(str_ptr, "NaN") != NULL)
154 temp = strtod(str_ptr, &end_ptr);
157 if (str_ptr == end_ptr) {
159 ("get_double_from_node: Cannot parse buffer as double: %s",
167 } /* int get_double_from_node */
169 static int value_check_range(
170 rrd_value_t *rrd_value,
171 const ds_def_t *ds_def)
176 if (opt_range_check == 0)
179 min = ds_def->par[DS_min_val].u_val;
180 max = ds_def->par[DS_max_val].u_val;
182 if (((!isnan(min)) && (*rrd_value < min))
183 || ((!isnan(max)) && (*rrd_value > max)))
187 } /* int value_check_range */
190 * Parse the <database> block within an RRA definition
192 static int parse_tag_rra_database_row(
196 rrd_value_t *rrd_value)
198 unsigned int values_count = 0;
203 for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
204 if ((xmlStrcmp(child->name, (const xmlChar *) "comment") == 0)
205 || (xmlStrcmp(child->name, (const xmlChar *) "text") == 0))
207 else if (xmlStrcmp(child->name, (const xmlChar *) "v") == 0) {
208 if (values_count < rrd->stat_head->ds_cnt) {
210 get_double_from_node(doc, child,
211 rrd_value + values_count);
213 value_check_range(rrd_value + values_count,
214 rrd->ds_def + values_count);
219 rrd_set_error("parse_tag_rra_database_row: Unknown tag: %s",
226 } /* for (child = node->xmlChildrenNode) */
228 if (values_count != rrd->stat_head->ds_cnt) {
229 rrd_set_error("parse_tag_rra_database_row: Row has %u values "
230 "and RRD has %lu data sources.",
231 values_count, rrd->stat_head->ds_cnt);
236 } /* int parse_tag_rra_database_row */
238 static int parse_tag_rra_database(
243 rra_def_t *cur_rra_def;
244 unsigned int total_row_cnt;
250 for (i = 0; i < (((int) rrd->stat_head->rra_cnt) - 1); i++)
251 total_row_cnt += rrd->rra_def[i].row_cnt;
253 cur_rra_def = rrd->rra_def + i;
256 for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
257 if ((xmlStrcmp(child->name, (const xmlChar *) "comment") == 0)
258 || (xmlStrcmp(child->name, (const xmlChar *) "text") == 0))
260 else if (xmlStrcmp(child->name, (const xmlChar *) "row") == 0) {
262 rrd_value_t *cur_rrd_value;
263 unsigned int total_values_count = rrd->stat_head->ds_cnt
264 * (total_row_cnt + 1);
266 /* Allocate space for the new values.. */
267 temp = (rrd_value_t *) realloc(rrd->rrd_value,
268 sizeof(rrd_value_t) *
271 rrd_set_error("parse_tag_rra_database: realloc failed.");
275 rrd->rrd_value = temp;
276 cur_rrd_value = rrd->rrd_value
277 + (rrd->stat_head->ds_cnt * total_row_cnt);
278 memset(cur_rrd_value, '\0',
279 sizeof(rrd_value_t) * rrd->stat_head->ds_cnt);
281 cur_rra_def->row_cnt++;
284 parse_tag_rra_database_row(doc, child, rrd, cur_rrd_value);
285 } /* if (xmlStrcmp (child->name, (const xmlChar *) "row") == 0) */
287 rrd_set_error("parse_tag_rra_database: Unknown tag: %s",
294 } /* for (child = node->xmlChildrenNode) */
297 } /* int parse_tag_rra_database */
300 * Parse the <cdp_prep> block within an RRA definition
302 static int parse_tag_rra_cdp_prep_ds_history(
305 cdp_prep_t *cdp_prep)
307 /* Make `history_buffer' the same size as the scratch area, plus the
308 * terminating NULL byte. */
309 char history_buffer[sizeof(((cdp_prep_t *)0)->scratch) + 1];
314 status = get_string_from_node(doc, node,
315 history_buffer, sizeof(history_buffer));
319 history_ptr = (char *) (&cdp_prep->scratch[0]);
320 for (i = 0; history_buffer[i] != '\0'; i++)
321 history_ptr[i] = (history_buffer[i] == '1') ? 1 : 0;
324 } /* int parse_tag_rra_cdp_prep_ds_history */
326 static int parse_tag_rra_cdp_prep_ds(
330 cdp_prep_t *cdp_prep)
335 memset(cdp_prep, '\0', sizeof(cdp_prep_t));
338 for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
339 if (atoi(rrd->stat_head->version) == 1) {
340 cdp_prep->scratch[CDP_primary_val].u_val = 0.0;
341 cdp_prep->scratch[CDP_secondary_val].u_val = 0.0;
343 if ((xmlStrcmp(child->name, (const xmlChar *) "comment") == 0)
344 || (xmlStrcmp(child->name, (const xmlChar *) "text") == 0))
346 else if (xmlStrcmp(child->name, (const xmlChar *) "primary_value") ==
349 get_double_from_node(doc, child,
350 &cdp_prep->scratch[CDP_primary_val].
352 else if (xmlStrcmp(child->name, (const xmlChar *) "secondary_value")
355 get_double_from_node(doc, child,
356 &cdp_prep->scratch[CDP_secondary_val].
358 else if (xmlStrcmp(child->name, (const xmlChar *) "intercept") == 0)
359 status = get_double_from_node(doc, child,
361 scratch[CDP_hw_intercept].u_val);
362 else if (xmlStrcmp(child->name, (const xmlChar *) "last_intercept") ==
365 get_double_from_node(doc, child,
367 scratch[CDP_hw_last_intercept].u_val);
368 else if (xmlStrcmp(child->name, (const xmlChar *) "slope") == 0)
369 status = get_double_from_node(doc, child,
370 &cdp_prep->scratch[CDP_hw_slope].
372 else if (xmlStrcmp(child->name, (const xmlChar *) "last_slope") == 0)
373 status = get_double_from_node(doc, child,
375 scratch[CDP_hw_last_slope].u_val);
376 else if (xmlStrcmp(child->name, (const xmlChar *) "nan_count") == 0)
377 status = get_int_from_node(doc, child,
379 scratch[CDP_null_count].u_cnt);
380 else if (xmlStrcmp(child->name, (const xmlChar *) "last_nan_count") ==
383 get_int_from_node(doc, child,
385 scratch[CDP_last_null_count].u_cnt);
386 else if (xmlStrcmp(child->name, (const xmlChar *) "seasonal") == 0)
387 status = get_double_from_node(doc, child,
388 &cdp_prep->scratch[CDP_hw_seasonal].
390 else if (xmlStrcmp(child->name, (const xmlChar *) "last_seasonal") ==
393 get_double_from_node(doc, child,
394 &cdp_prep->scratch[CDP_hw_last_seasonal].
396 else if (xmlStrcmp(child->name, (const xmlChar *) "init_flag") == 0)
397 status = get_int_from_node(doc, child,
399 scratch[CDP_init_seasonal].u_cnt);
400 else if (xmlStrcmp(child->name, (const xmlChar *) "history") == 0)
401 status = parse_tag_rra_cdp_prep_ds_history(doc, child, cdp_prep);
402 else if (xmlStrcmp(child->name, (const xmlChar *) "value") == 0)
403 status = get_double_from_node(doc, child,
404 &cdp_prep->scratch[CDP_val].u_val);
405 else if (xmlStrcmp(child->name,
406 (const xmlChar *) "unknown_datapoints") == 0)
407 status = get_int_from_node(doc, child,
409 scratch[CDP_unkn_pdp_cnt].u_cnt);
411 rrd_set_error("parse_tag_rra_cdp_prep: Unknown tag: %s",
421 } /* int parse_tag_rra_cdp_prep_ds */
423 static int parse_tag_rra_cdp_prep(
427 cdp_prep_t *cdp_prep)
432 unsigned int ds_count = 0;
435 for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
436 if ((xmlStrcmp(child->name, (const xmlChar *) "comment") == 0)
437 || (xmlStrcmp(child->name, (const xmlChar *) "text") == 0))
439 else if (xmlStrcmp(child->name, (const xmlChar *) "ds") == 0) {
440 if (ds_count >= rrd->stat_head->ds_cnt)
443 status = parse_tag_rra_cdp_prep_ds(doc, child, rrd,
444 cdp_prep + ds_count);
448 rrd_set_error("parse_tag_rra_cdp_prep: Unknown tag: %s",
457 if (ds_count != rrd->stat_head->ds_cnt) {
458 rrd_set_error("parse_tag_rra_cdp_prep: There are %i data sources in "
459 "the RRD file, but %i in this cdp_prep block!",
460 (int) rrd->stat_head->ds_cnt, ds_count);
465 } /* int parse_tag_rra_cdp_prep */
468 * Parse the <params> block within an RRA definition
470 static int parse_tag_rra_params(
479 for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
480 if ((xmlStrcmp(child->name, (const xmlChar *) "comment") == 0)
481 || (xmlStrcmp(child->name, (const xmlChar *) "text") == 0))
484 * Parameters for CF_HWPREDICT
486 else if (xmlStrcmp(child->name, (const xmlChar *) "hw_alpha") == 0)
487 status = get_double_from_node(doc, child,
488 &rra_def->par[RRA_hw_alpha].u_val);
489 else if (xmlStrcmp(child->name, (const xmlChar *) "hw_beta") == 0)
490 status = get_double_from_node(doc, child,
491 &rra_def->par[RRA_hw_beta].u_val);
492 else if (xmlStrcmp(child->name,
493 (const xmlChar *) "dependent_rra_idx") == 0)
494 status = get_int_from_node(doc, child,
496 par[RRA_dependent_rra_idx].u_cnt);
498 * Parameters for CF_SEASONAL and CF_DEVSEASONAL
500 else if (xmlStrcmp(child->name, (const xmlChar *) "seasonal_gamma") ==
503 get_double_from_node(doc, child,
504 &rra_def->par[RRA_seasonal_gamma].u_val);
506 (child->name, (const xmlChar *) "seasonal_smooth_idx") == 0)
508 get_int_from_node(doc, child,
510 par[RRA_seasonal_smooth_idx].u_cnt);
511 else if (xmlStrcmp(child->name, (const xmlChar *) "smoothing_window")
514 get_double_from_node(doc, child,
516 par[RRA_seasonal_smoothing_window].
518 /* else if (dependent_rra_idx) ...; */
520 * Parameters for CF_FAILURES
522 else if (xmlStrcmp(child->name, (const xmlChar *) "delta_pos") == 0)
523 status = get_double_from_node(doc, child,
524 &rra_def->par[RRA_delta_pos].u_val);
525 else if (xmlStrcmp(child->name, (const xmlChar *) "delta_neg") == 0)
526 status = get_double_from_node(doc, child,
527 &rra_def->par[RRA_delta_neg].u_val);
528 else if (xmlStrcmp(child->name, (const xmlChar *) "window_len") == 0)
529 status = get_int_from_node(doc, child,
530 (int *) &rra_def->par[RRA_window_len].
532 else if (xmlStrcmp(child->name, (const xmlChar *) "failure_threshold")
535 get_int_from_node(doc, child,
537 par[RRA_failure_threshold].u_cnt);
539 * Parameters for CF_AVERAGE, CF_MAXIMUM, CF_MINIMUM, and CF_LAST
541 else if (xmlStrcmp(child->name, (const xmlChar *) "xff") == 0)
542 status = get_double_from_node(doc, child,
543 &rra_def->par[RRA_cdp_xff_val].
546 * Compatibility code for 1.0.49
548 else if (xmlStrcmp(child->name, (const xmlChar *) "value") == 0) { /* {{{ */
552 if (i >= ARRAY_LENGTH(rra_def->par)) {
557 if ((i == RRA_dependent_rra_idx)
558 || (i == RRA_seasonal_smooth_idx)
559 || (i == RRA_failure_threshold))
560 status = get_int_from_node(doc, child,
561 (int *) &rra_def->par[i].
564 status = get_double_from_node(doc, child,
565 &rra_def->par[i].u_val);
570 /* When this loops exits (sucessfully) `child' points to the last
571 * `value' tag in the list. */
572 if ((child->next == NULL)
573 || (xmlStrcmp(child->name, (const xmlChar *) "value") !=
582 rrd_set_error("parse_tag_rra_params: Unknown tag: %s",
592 } /* int parse_tag_rra_params */
595 * Parse an RRA definition
597 static int parse_tag_rra_cf(
604 status = get_string_from_node(doc, node,
605 rra_def->cf_nam, sizeof(rra_def->cf_nam));
609 status = cf_conv(rra_def->cf_nam);
611 rrd_set_error("parse_tag_rra_cf: Unknown consolidation function: %s",
617 } /* int parse_tag_rra_cf */
619 static int parse_tag_rra(
627 rra_def_t *cur_rra_def;
628 cdp_prep_t *cur_cdp_prep;
629 rra_ptr_t *cur_rra_ptr;
631 /* Allocate more rra_def space for this RRA */
635 temp = (rra_def_t *) realloc(rrd->rra_def,
637 (rrd->stat_head->rra_cnt + 1));
639 rrd_set_error("parse_tag_rra: realloc failed.");
643 cur_rra_def = rrd->rra_def + rrd->stat_head->rra_cnt;
644 memset(cur_rra_def, '\0', sizeof(rra_def_t));
647 /* allocate cdp_prep_t */
651 temp = (cdp_prep_t *) realloc(rrd->cdp_prep, sizeof(cdp_prep_t)
652 * rrd->stat_head->ds_cnt
653 * (rrd->stat_head->rra_cnt + 1));
655 rrd_set_error("parse_tag_rra: realloc failed.");
658 rrd->cdp_prep = temp;
659 cur_cdp_prep = rrd->cdp_prep
660 + (rrd->stat_head->ds_cnt * rrd->stat_head->rra_cnt);
661 memset(cur_cdp_prep, '\0',
662 sizeof(cdp_prep_t) * rrd->stat_head->ds_cnt);
665 /* allocate rra_ptr_t */
669 temp = (rra_ptr_t *) realloc(rrd->rra_ptr,
671 (rrd->stat_head->rra_cnt + 1));
673 rrd_set_error("parse_tag_rra: realloc failed.");
677 cur_rra_ptr = rrd->rra_ptr + rrd->stat_head->rra_cnt;
678 memset(cur_rra_ptr, '\0', sizeof(rra_ptr_t));
681 /* All space successfully allocated, increment number of RRAs. */
682 rrd->stat_head->rra_cnt++;
685 for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
686 if ((xmlStrcmp(child->name, (const xmlChar *) "comment") == 0)
687 || (xmlStrcmp(child->name, (const xmlChar *) "text") == 0))
689 else if (xmlStrcmp(child->name, (const xmlChar *) "cf") == 0)
690 status = parse_tag_rra_cf(doc, child, cur_rra_def);
691 else if (xmlStrcmp(child->name, (const xmlChar *) "pdp_per_row") == 0)
692 status = get_int_from_node(doc, child,
693 (int *) &cur_rra_def->pdp_cnt);
694 else if (atoi(rrd->stat_head->version) == 1
695 && xmlStrcmp(child->name, (const xmlChar *) "xff") == 0)
696 status = get_double_from_node(doc, child,
697 (double *) &cur_rra_def->
698 par[RRA_cdp_xff_val].u_val);
699 else if (atoi(rrd->stat_head->version) >= 2
700 && xmlStrcmp(child->name, (const xmlChar *) "params") == 0)
701 status = parse_tag_rra_params(doc, child, cur_rra_def);
702 else if (xmlStrcmp(child->name, (const xmlChar *) "cdp_prep") == 0)
703 status = parse_tag_rra_cdp_prep(doc, child, rrd, cur_cdp_prep);
704 else if (xmlStrcmp(child->name, (const xmlChar *) "database") == 0)
705 status = parse_tag_rra_database(doc, child, rrd);
707 rrd_set_error("parse_tag_rra: Unknown tag: %s", child->name);
715 /* Set the RRA pointer to a random location */
716 cur_rra_ptr->cur_row = random() % cur_rra_def->row_cnt;
719 } /* int parse_tag_rra */
722 * Parse a DS definition
724 static int parse_tag_ds_cdef(
732 status = get_string_from_node(doc, node, buffer, sizeof(buffer));
736 /* We're always working on the last DS that has been added to the structure
737 * when we get here */
738 parseCDEF_DS(buffer, rrd, rrd->stat_head->ds_cnt - 1);
741 } /* int parse_tag_ds_cdef */
743 static int parse_tag_ds_type(
750 status = get_string_from_node(doc, node,
751 ds_def->dst, sizeof(ds_def->dst));
755 status = dst_conv(ds_def->dst);
757 rrd_set_error("parse_tag_ds_type: Unknown data source type: %s",
763 } /* int parse_tag_ds_type */
765 static int parse_tag_ds(
773 ds_def_t *cur_ds_def;
774 pdp_prep_t *cur_pdp_prep;
777 * If there are DS definitions after RRA definitions the number of values,
778 * cdp_prep areas and so on will be calculated wrong. Thus, enforce a
779 * specific order in this case.
781 if (rrd->stat_head->rra_cnt > 0) {
782 rrd_set_error("parse_tag_ds: All data source definitions MUST "
783 "precede the RRA definitions!");
787 /* Allocate space for the new DS definition */
791 temp = (ds_def_t *) realloc(rrd->ds_def,
793 (rrd->stat_head->ds_cnt + 1));
795 rrd_set_error("parse_tag_ds: malloc failed.");
799 cur_ds_def = rrd->ds_def + rrd->stat_head->ds_cnt;
800 memset(cur_ds_def, '\0', sizeof(ds_def_t));
803 /* Allocate pdp_prep space for the new DS definition */
807 temp = (pdp_prep_t *) realloc(rrd->pdp_prep,
809 (rrd->stat_head->ds_cnt + 1));
811 rrd_set_error("parse_tag_ds: malloc failed.");
814 rrd->pdp_prep = temp;
815 cur_pdp_prep = rrd->pdp_prep + rrd->stat_head->ds_cnt;
816 memset(cur_pdp_prep, '\0', sizeof(pdp_prep_t));
819 /* All allocations successful, let's increment the number of DSes. */
820 rrd->stat_head->ds_cnt++;
823 for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
824 if ((xmlStrcmp(child->name, (const xmlChar *) "comment") == 0)
825 || (xmlStrcmp(child->name, (const xmlChar *) "text") == 0))
827 else if (xmlStrcmp(child->name, (const xmlChar *) "name") == 0)
828 status = get_string_from_node(doc, child,
830 sizeof(cur_ds_def->ds_nam));
831 else if (xmlStrcmp(child->name, (const xmlChar *) "type") == 0)
832 status = parse_tag_ds_type(doc, child, cur_ds_def);
833 else if (xmlStrcmp(child->name,
834 (const xmlChar *) "minimal_heartbeat") == 0)
835 status = get_int_from_node(doc, child,
836 (int *) &cur_ds_def->par[DS_mrhb_cnt].
838 else if (xmlStrcmp(child->name, (const xmlChar *) "min") == 0)
839 status = get_double_from_node(doc, child,
840 &cur_ds_def->par[DS_min_val].u_val);
841 else if (xmlStrcmp(child->name, (const xmlChar *) "max") == 0)
842 status = get_double_from_node(doc, child,
843 &cur_ds_def->par[DS_max_val].u_val);
844 else if (xmlStrcmp(child->name, (const xmlChar *) "cdef") == 0)
845 status = parse_tag_ds_cdef(doc, child, rrd);
846 else if (xmlStrcmp(child->name, (const xmlChar *) "last_ds") == 0)
847 status = get_string_from_node(doc, child,
848 cur_pdp_prep->last_ds,
849 sizeof(cur_pdp_prep->last_ds));
850 else if (xmlStrcmp(child->name, (const xmlChar *) "value") == 0)
851 status = get_double_from_node(doc, child,
852 &cur_pdp_prep->scratch[PDP_val].
854 else if (xmlStrcmp(child->name, (const xmlChar *) "unknown_sec") == 0)
855 status = get_int_from_node(doc, child,
856 (int *) &cur_pdp_prep->
857 scratch[PDP_unkn_sec_cnt].u_cnt);
859 rrd_set_error("parse_tag_ds: Unknown tag: %s", child->name);
868 } /* int parse_tag_ds */
873 static int parse_tag_rrd(
882 for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
883 if ((xmlStrcmp(child->name, (const xmlChar *) "comment") == 0)
884 || (xmlStrcmp(child->name, (const xmlChar *) "text") == 0))
886 else if (xmlStrcmp(child->name, (const xmlChar *) "version") == 0)
887 status = get_string_from_node(doc, child,
888 rrd->stat_head->version,
889 sizeof(rrd->stat_head->version));
890 else if (xmlStrcmp(child->name, (const xmlChar *) "step") == 0)
891 status = get_int_from_node(doc, child,
892 (int *) &rrd->stat_head->pdp_step);
893 else if (xmlStrcmp(child->name, (const xmlChar *) "lastupdate") == 0)
894 status = get_int_from_node(doc, child,
895 (int *) &rrd->live_head->last_up);
896 else if (xmlStrcmp(child->name, (const xmlChar *) "ds") == 0)
897 status = parse_tag_ds(doc, child, rrd);
898 else if (xmlStrcmp(child->name, (const xmlChar *) "rra") == 0)
899 status = parse_tag_rra(doc, child, rrd);
901 rrd_set_error("parse_tag_rrd: Unknown tag: %s", child->name);
910 } /* int parse_tag_rrd */
912 static rrd_t *parse_file(
913 const char *filename)
921 doc = xmlParseFile(filename);
923 rrd_set_error("Document not parsed successfully.");
927 cur = xmlDocGetRootElement(doc);
929 rrd_set_error("Document is empty.");
934 if (xmlStrcmp(cur->name, (const xmlChar *) "rrd") != 0) {
936 ("Document of the wrong type, root node is not \"rrd\".");
941 rrd = (rrd_t *) malloc(sizeof(rrd_t));
943 rrd_set_error("parse_file: malloc failed.");
947 memset(rrd, '\0', sizeof(rrd_t));
949 rrd->stat_head = (stat_head_t *) malloc(sizeof(stat_head_t));
950 if (rrd->stat_head == NULL) {
951 rrd_set_error("parse_tag_rrd: malloc failed.");
956 memset(rrd->stat_head, '\0', sizeof(stat_head_t));
958 strncpy(rrd->stat_head->cookie, "RRD", sizeof(rrd->stat_head->cookie));
959 rrd->stat_head->float_cookie = FLOAT_COOKIE;
961 rrd->live_head = (live_head_t *) malloc(sizeof(live_head_t));
962 if (rrd->live_head == NULL) {
963 rrd_set_error("parse_tag_rrd: malloc failed.");
965 free(rrd->stat_head);
969 memset(rrd->live_head, '\0', sizeof(live_head_t));
971 status = parse_tag_rrd(doc, cur, rrd);
980 } /* rrd_t *parse_file */
982 static int write_file(
983 const char *file_name,
988 unsigned int rra_offset;
990 if (strcmp("-", file_name) == 0)
993 int fd_flags = O_WRONLY | O_CREAT;
996 #if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
997 fd_flags |= O_BINARY;
1000 if (opt_force_overwrite == 0)
1003 fd = open(file_name, fd_flags, 0666);
1005 rrd_set_error("creating '%s': %s", file_name,
1006 rrd_strerror(errno));
1010 fh = fdopen(fd, "wb");
1012 rrd_set_error("fdopen failed: %s", rrd_strerror(errno));
1017 if (atoi(rrd->stat_head->version) < 3) {
1018 /* we output 3 or higher */
1019 strcpy(rrd->stat_head->version, "0003");
1021 fwrite(rrd->stat_head, sizeof(stat_head_t), 1, fh);
1022 fwrite(rrd->ds_def, sizeof(ds_def_t), rrd->stat_head->ds_cnt, fh);
1023 fwrite(rrd->rra_def, sizeof(rra_def_t), rrd->stat_head->rra_cnt, fh);
1024 fwrite(rrd->live_head, sizeof(live_head_t), 1, fh);
1025 fwrite(rrd->pdp_prep, sizeof(pdp_prep_t), rrd->stat_head->ds_cnt, fh);
1026 fwrite(rrd->cdp_prep, sizeof(cdp_prep_t),
1027 rrd->stat_head->rra_cnt * rrd->stat_head->ds_cnt, fh);
1028 fwrite(rrd->rra_ptr, sizeof(rra_ptr_t), rrd->stat_head->rra_cnt, fh);
1030 /* calculate the number of rrd_values to dump */
1032 for (i = 0; i < rrd->stat_head->rra_cnt; i++) {
1033 unsigned long num_rows = rrd->rra_def[i].row_cnt;
1034 unsigned long cur_row = rrd->rra_ptr[i].cur_row;
1035 unsigned long ds_cnt = rrd->stat_head->ds_cnt;
1037 fwrite(rrd->rrd_value +
1038 (rra_offset + num_rows - 1 - cur_row) * ds_cnt,
1039 sizeof(rrd_value_t), (cur_row + 1) * ds_cnt, fh);
1041 fwrite(rrd->rrd_value + rra_offset * ds_cnt,
1042 sizeof(rrd_value_t), (num_rows - 1 - cur_row) * ds_cnt, fh);
1044 rra_offset += num_rows;
1047 /* lets see if we had an error */
1049 rrd_set_error("a file error occurred while creating '%s'", file_name);
1056 } /* int write_file */
1064 srandom((unsigned int) time(NULL) + (unsigned int) getpid());
1065 /* init rrd clean */
1067 opterr = 0; /* initialize getopt */
1070 int option_index = 0;
1071 static struct option long_options[] = {
1072 {"range-check", no_argument, 0, 'r'},
1073 {"force-overwrite", no_argument, 0, 'f'},
1077 opt = getopt_long(argc, argv, "rf", long_options, &option_index);
1084 opt_range_check = 1;
1088 opt_force_overwrite = 1;
1092 rrd_set_error("usage rrdtool %s [--range-check|-r] "
1093 "[--force-overwrite/-f] file.xml file.rrd",
1100 if ((argc - optind) != 2) {
1101 rrd_set_error("usage rrdtool %s [--range-check/-r] "
1102 "[--force-overwrite/-f] file.xml file.rrd", argv[0]);
1106 rrd = parse_file(argv[optind]);
1110 if (write_file(argv[optind + 1], rrd) != 0) {
1117 } /* int rrd_restore */
1119 /* vim: set sw=2 sts=2 ts=8 et fdm=marker : */