8b8046bd1ac123027fa2d3b0de71e816f4bce8ee
1 /*****************************************************************************
2 * RRDtool 1.4.0 Copyright by Tobi Oetiker, 1997-2009
3 *****************************************************************************
4 * rrd_restore.c Contains logic to parse XML input and create an RRD file
5 * This file:
6 * Copyright (C) 2008 Florian octo Forster (original libxml2 code)
7 * Copyright (C) 2008,2009 Tobias Oetiker
8 *****************************************************************************
9 * $Id$
10 *************************************************************************** */
12 #include "rrd_tool.h"
13 #include "rrd_rpncalc.h"
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <libxml/parser.h>
19 #include <libxml/xmlreader.h>
20 #include <locale.h>
22 #ifndef WIN32
23 # include <unistd.h> /* for off_t */
24 #else
25 typedef size_t ssize_t;
26 typedef long off_t;
27 #endif
29 #include <fcntl.h>
30 #if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
31 # include <io.h>
32 # define open _open
33 # define close _close
34 #endif
37 #define ARRAY_LENGTH(a) (sizeof (a) / sizeof ((a)[0]))
39 static int opt_range_check = 0;
40 static int opt_force_overwrite = 0;
42 /*
43 * Helpers
44 */
46 /* skip all but tags. complain if we do not get the right tag */
47 /* dept -1 causes depth to be ignored */
48 static xmlChar* get_xml_element (
49 xmlTextReaderPtr reader
50 )
51 {
52 while(xmlTextReaderRead(reader)){
53 int type;
54 xmlChar *name;
55 type = xmlTextReaderNodeType(reader);
56 if (type == XML_READER_TYPE_TEXT){
57 xmlChar *value;
58 value = xmlTextReaderValue(reader);
59 rrd_set_error("line %d: expected element but found text '%s'",
60 xmlTextReaderGetParserLineNumber(reader),value);
61 xmlFree(value);
62 return NULL;
63 }
64 /* skip all other non-elements */
65 if (type != XML_READER_TYPE_ELEMENT && type != XML_READER_TYPE_END_ELEMENT)
66 continue;
68 name = xmlTextReaderName(reader);
69 if (type == XML_READER_TYPE_END_ELEMENT){
70 xmlChar *temp;
71 xmlChar *temp2;
72 temp = (xmlChar*)sprintf_alloc("/%s",name);
73 temp2 = xmlStrdup(temp);
74 free(temp);
75 xmlFree(name);
76 return temp2;
77 }
78 /* all seems well, return the happy news */
79 return name;
80 }
81 rrd_set_error("the xml ended while we were looking for an element");
82 return NULL;
83 } /* get_xml_element */
85 static void local_rrd_free (rrd_t *rrd)
86 {
87 free(rrd->live_head);
88 free(rrd->stat_head);
89 free(rrd->ds_def);
90 free(rrd->rra_def);
91 free(rrd->rra_ptr);
92 free(rrd->pdp_prep);
93 free(rrd->cdp_prep);
94 free(rrd->rrd_value);
95 free(rrd);
96 }
99 static int expect_element (
100 xmlTextReaderPtr reader,
101 char *exp_name)
102 {
103 xmlChar *name;
104 name = get_xml_element(reader);
105 if (!name)
106 return -1;
107 if (xmlStrcasecmp(name,(xmlChar *)exp_name) != 0){
108 rrd_set_error("line %d: expected <%s> element but found <%s>",
109 xmlTextReaderGetParserLineNumber(reader),name,exp_name);
110 xmlFree(name);
111 return -1;
112 }
113 xmlFree(name);
114 return 0;
115 } /* expect_element */
117 static int expect_element_end (
118 xmlTextReaderPtr reader,
119 char *exp_name)
120 {
121 xmlChar *name;
122 name = get_xml_element(reader);
123 if (name == NULL)
124 return -1;
125 if (xmlStrcasecmp(name+1,(xmlChar *)exp_name) != 0 || name[0] != '/'){
126 rrd_set_error("line %d: expected </%s> end element but found <%s>",
127 xmlTextReaderGetParserLineNumber(reader),exp_name,name);
128 xmlFree(name);
129 return -1;
130 }
131 xmlFree(name);
132 return 0;
133 } /* expect_element_end */
136 static xmlChar* get_xml_text (
137 xmlTextReaderPtr reader
138 )
139 {
140 while(xmlTextReaderRead(reader)){
141 xmlChar *ret;
142 xmlChar *text;
143 xmlChar *begin_ptr;
144 xmlChar *end_ptr;
145 int type;
146 type = xmlTextReaderNodeType(reader);
147 if (type == XML_READER_TYPE_ELEMENT){
148 xmlChar *name;
149 name = xmlTextReaderName(reader);
150 rrd_set_error("line %d: expected a value but found an <%s> element",
151 xmlTextReaderGetParserLineNumber(reader),
152 name);
153 xmlFree(name);
154 return NULL;
155 }
156 /* skip all other non-text */
157 if (xmlTextReaderNodeType(reader) != XML_READER_TYPE_TEXT)
158 continue;
160 text = xmlTextReaderValue(reader);
162 begin_ptr = text;
163 while ((begin_ptr[0] != 0) && (isspace(begin_ptr[0])))
164 begin_ptr++;
165 if (begin_ptr[0] == 0) {
166 xmlFree(text);
167 return xmlStrdup(BAD_CAST "");
168 }
169 end_ptr = begin_ptr;
170 while ((end_ptr[0] != 0) && (!isspace(end_ptr[0])))
171 end_ptr++;
172 end_ptr[0] = 0;
174 ret = xmlStrdup(begin_ptr);
175 xmlFree(text);
176 return ret;
177 }
178 rrd_set_error("file ended while looking for text");
179 return NULL;
180 } /* get_xml_text */
183 static int get_xml_string(
184 xmlTextReaderPtr reader,
185 char *value,
186 int max_len)
187 {
188 xmlChar *str;
189 str = get_xml_text(reader);
190 if (str != NULL){
191 strncpy(value,(char *)str,max_len);
192 xmlFree(str);
193 return 0;
194 }
195 else
196 return -1;
197 }
200 static int get_xml_long(
201 xmlTextReaderPtr reader,
202 long *value)
203 {
204 xmlChar *text;
205 long temp;
206 if ((text = get_xml_text(reader)) != NULL){
207 errno = 0;
208 temp = strtol((char *)text,NULL, 0);
209 if (errno>0){
210 rrd_set_error("ling %d: get_xml_long from '%s' %s",
211 xmlTextReaderGetParserLineNumber(reader),
212 text,rrd_strerror(errno));
213 xmlFree(text);
214 return -1;
215 }
216 xmlFree(text);
217 *value = temp;
218 return 0;
219 }
220 return -1;
221 } /* get_xml_long */
223 static int get_xml_ulong(
224 xmlTextReaderPtr reader,
225 unsigned long *value)
226 {
228 xmlChar *text;
229 unsigned long temp;
230 if ((text = get_xml_text(reader)) != NULL){
231 errno = 0;
232 temp = strtoul((char *)text,NULL, 0);
233 if (errno>0){
234 rrd_set_error("ling %d: get_xml_ulong from '%s' %s",
235 xmlTextReaderGetParserLineNumber(reader),
236 text,rrd_strerror(errno));
237 xmlFree(text);
238 return -1;
239 }
240 xmlFree(text);
241 *value = temp;
242 return 0;
243 }
244 return -1;
245 } /* get_xml_ulong */
247 #ifndef TIME_T_IS_LONG
248 static int get_xml_llong(
249 xmlTextReaderPtr reader,
250 long long *value)
251 {
253 xmlChar *text;
254 long long temp;
255 if ((text = get_xml_text(reader)) != NULL){
256 errno = 0;
257 temp = strtoll((char *)text,NULL, 0);
258 if (errno>0){
259 rrd_set_error("ling %d: get_xml_llong from '%s' %s",
260 xmlTextReaderGetParserLineNumber(reader),
261 text,rrd_strerror(errno));
262 xmlFree(text);
263 return -1;
264 }
265 xmlFree(text);
266 *value = temp;
267 return 0;
268 }
269 return -1;
270 } /* get_xml_llong */
272 #endif
274 static int get_xml_double(
275 xmlTextReaderPtr reader,
276 double *value)
277 {
279 xmlChar *text;
280 double temp;
281 if ((text = get_xml_text(reader))!= NULL){
282 if (xmlStrcasestr(text,(xmlChar *)"nan")){
283 *value = DNAN;
284 xmlFree(text);
285 return 0;
286 }
287 else if (xmlStrcasestr(text,(xmlChar *)"-inf")){
288 *value = -DINF;
289 xmlFree(text);
290 return 0;
291 }
292 else if (xmlStrcasestr(text,(xmlChar *)"+inf")
293 || xmlStrcasestr(text,(xmlChar *)"inf")){
294 *value = DINF;
295 xmlFree(text);
296 return 0;
297 }
298 errno = 0;
299 temp = strtod((char *)text,NULL);
300 if (errno>0){
301 rrd_set_error("ling %d: get_xml_double from '%s' %s",
302 xmlTextReaderGetParserLineNumber(reader),
303 text,rrd_strerror(errno));
304 xmlFree(text);
305 return -1;
306 }
307 xmlFree(text);
308 *value = temp;
309 return 0;
310 }
311 return -1;
312 } /* get_xml_double */
315 static int value_check_range(
316 rrd_value_t *rrd_value,
317 const ds_def_t *ds_def)
318 {
319 double min;
320 double max;
322 if (opt_range_check == 0)
323 return (0);
325 min = ds_def->par[DS_min_val].u_val;
326 max = ds_def->par[DS_max_val].u_val;
328 if (((!isnan(min)) && (*rrd_value < min))
329 || ((!isnan(max)) && (*rrd_value > max)))
330 *rrd_value = DNAN;
332 return (0);
333 } /* int value_check_range */
335 /*
336 * Parse the <database> block within an RRA definition
337 */
339 static int parse_tag_rra_database_row(
340 xmlTextReaderPtr reader,
341 rrd_t *rrd,
342 rrd_value_t *rrd_value)
343 {
344 unsigned int values_count = 0;
345 int status;
347 status = 0;
348 for (values_count = 0;values_count < rrd->stat_head->ds_cnt;values_count++){
349 if (expect_element(reader,"v") == 0){
350 status = get_xml_double(reader,rrd_value + values_count);
351 if (status == 0)
352 value_check_range(rrd_value + values_count,
353 rrd->ds_def + values_count);
354 else
355 break;
356 } else
357 return -1;
358 if (expect_element(reader,"/v") == -1){
359 return -1;
360 }
361 }
362 return status;
363 } /* int parse_tag_rra_database_row */
365 static int parse_tag_rra_database(
366 xmlTextReaderPtr reader,
367 rrd_t *rrd )
368 {
369 rra_def_t *cur_rra_def;
370 unsigned int total_row_cnt;
371 int status;
372 int i;
373 xmlChar *element;
375 total_row_cnt = 0;
376 for (i = 0; i < (((int) rrd->stat_head->rra_cnt) - 1); i++)
377 total_row_cnt += rrd->rra_def[i].row_cnt;
379 cur_rra_def = rrd->rra_def + i;
381 status = 0;
382 while ((element = get_xml_element(reader)) != NULL){
383 if (xmlStrcasecmp(element,(const xmlChar *)"row") == 0){
384 rrd_value_t *temp;
385 rrd_value_t *cur_rrd_value;
386 unsigned int total_values_count = rrd->stat_head->ds_cnt
387 * (total_row_cnt + 1);
389 /* Allocate space for the new values.. */
390 temp = (rrd_value_t *) realloc(rrd->rrd_value,
391 sizeof(rrd_value_t) *
392 total_values_count);
393 if (temp == NULL) {
394 rrd_set_error("parse_tag_rra_database: realloc failed.");
395 status = -1;
396 break;
397 }
398 rrd->rrd_value = temp;
399 cur_rrd_value = rrd->rrd_value
400 + (rrd->stat_head->ds_cnt * total_row_cnt);
401 memset(cur_rrd_value, '\0',
402 sizeof(rrd_value_t) * rrd->stat_head->ds_cnt);
403 total_row_cnt++;
404 cur_rra_def->row_cnt++;
406 status =
407 parse_tag_rra_database_row(reader, rrd, cur_rrd_value);
408 if (status == 0)
409 status = expect_element(reader,"/row");
410 } /* if (xmlStrcasecmp(element,"row")) */
411 else {
412 if ( xmlStrcasecmp(element,(const xmlChar *)"/database") == 0){
413 xmlFree(element);
414 break;
415 }
416 else {
417 rrd_set_error("line %d: found unexpected tag: %s",
418 xmlTextReaderGetParserLineNumber(reader),element);
419 status = -1;
420 }
421 }
422 xmlFree(element);
423 if (status != 0)
424 break;
425 }
426 return (status);
427 } /* int parse_tag_rra_database */
429 /*
430 * Parse the <cdp_prep> block within an RRA definition
431 */
432 static int parse_tag_rra_cdp_prep_ds_history(
433 xmlTextReaderPtr reader,
434 cdp_prep_t *cdp_prep)
435 {
436 /* Make `history_buffer' the same size as the scratch area, plus the
437 * terminating NULL byte. */
438 xmlChar *history;
439 char *history_ptr;
440 int i;
441 if ((history = get_xml_text(reader)) != NULL){
442 history_ptr = (char *) (&cdp_prep->scratch[0]);
443 for (i = 0; history[i] != '\0'; i++)
444 history_ptr[i] = (history[i] == '1') ? 1 : 0;
445 xmlFree(history);
446 return 0;
447 }
448 return -1;
449 } /* int parse_tag_rra_cdp_prep_ds_history */
451 static int parse_tag_rra_cdp_prep_ds(
452 xmlTextReaderPtr reader,
453 rrd_t *rrd,
454 cdp_prep_t *cdp_prep)
455 {
456 int status;
457 xmlChar *element;
458 memset(cdp_prep, '\0', sizeof(cdp_prep_t));
460 status = -1;
462 if (atoi(rrd->stat_head->version) == 1) {
463 cdp_prep->scratch[CDP_primary_val].u_val = 0.0;
464 cdp_prep->scratch[CDP_secondary_val].u_val = 0.0;
465 }
467 while ((element = get_xml_element(reader)) != NULL){
468 if (xmlStrcasecmp(element, (const xmlChar *) "primary_value") == 0)
469 status =
470 get_xml_double(reader,&cdp_prep->scratch[CDP_primary_val].u_val);
471 else if (xmlStrcasecmp(element, (const xmlChar *) "secondary_value") == 0)
472 status =
473 get_xml_double(reader,&cdp_prep->scratch[CDP_secondary_val].u_val);
474 else if (xmlStrcasecmp(element, (const xmlChar *) "intercept") == 0)
475 status = get_xml_double(reader,
476 &cdp_prep->
477 scratch[CDP_hw_intercept].u_val);
478 else if (xmlStrcasecmp(element, (const xmlChar *) "last_intercept") ==
479 0)
480 status =
481 get_xml_double(reader,
482 &cdp_prep->
483 scratch[CDP_hw_last_intercept].u_val);
484 else if (xmlStrcasecmp(element, (const xmlChar *) "slope") == 0)
485 status = get_xml_double(reader,
486 &cdp_prep->scratch[CDP_hw_slope].
487 u_val);
488 else if (xmlStrcasecmp(element, (const xmlChar *) "last_slope") == 0)
489 status = get_xml_double(reader,
490 &cdp_prep->
491 scratch[CDP_hw_last_slope].u_val);
492 else if (xmlStrcasecmp(element, (const xmlChar *) "nan_count") == 0)
493 status = get_xml_ulong(reader,
494 &cdp_prep->
495 scratch[CDP_null_count].u_cnt);
496 else if (xmlStrcasecmp(element, (const xmlChar *) "last_nan_count") ==
497 0)
498 status =
499 get_xml_ulong(reader,
500 &cdp_prep->
501 scratch[CDP_last_null_count].u_cnt);
502 else if (xmlStrcasecmp(element, (const xmlChar *) "seasonal") == 0)
503 status = get_xml_double(reader,
504 &cdp_prep->scratch[CDP_hw_seasonal].
505 u_val);
506 else if (xmlStrcasecmp(element, (const xmlChar *) "last_seasonal") ==
507 0)
508 status =
509 get_xml_double(reader,
510 &cdp_prep->scratch[CDP_hw_last_seasonal].
511 u_val);
512 else if (xmlStrcasecmp(element, (const xmlChar *) "init_flag") == 0)
513 status = get_xml_ulong(reader,
514 &cdp_prep->
515 scratch[CDP_init_seasonal].u_cnt);
516 else if (xmlStrcasecmp(element, (const xmlChar *) "history") == 0)
517 status = parse_tag_rra_cdp_prep_ds_history(reader, cdp_prep);
518 else if (xmlStrcasecmp(element, (const xmlChar *) "value") == 0)
519 status = get_xml_double(reader,
520 &cdp_prep->scratch[CDP_val].u_val);
521 else if (xmlStrcasecmp(element,
522 (const xmlChar *) "unknown_datapoints") == 0)
523 status = get_xml_ulong(reader,
524 &cdp_prep->
525 scratch[CDP_unkn_pdp_cnt].u_cnt);
526 else if (xmlStrcasecmp(element,
527 (const xmlChar *) "/ds") == 0){
528 xmlFree(element);
529 break;
530 }
531 else {
532 rrd_set_error("parse_tag_rra_cdp_prep: Unknown tag: %s",
533 element);
534 status = -1;
535 xmlFree(element);
536 break;
537 }
538 if (status != 0){
539 xmlFree(element);
540 break;
541 }
542 status = expect_element_end(reader,(char *)element);
543 xmlFree(element);
544 if (status != 0)
545 break;
546 }
547 return (status);
548 } /* int parse_tag_rra_cdp_prep_ds */
550 static int parse_tag_rra_cdp_prep(
551 xmlTextReaderPtr reader,
552 rrd_t *rrd,
553 cdp_prep_t *cdp_prep)
554 {
555 int status;
557 unsigned int ds_count;
559 status = 0;
560 for ( ds_count = 0; ds_count < rrd->stat_head->ds_cnt;ds_count++){
561 if (expect_element(reader,"ds") == 0) {
562 status = parse_tag_rra_cdp_prep_ds(reader, rrd,
563 cdp_prep + ds_count);
564 if (status != 0)
565 break;
566 } else {
567 status = -1;
568 break;
569 }
570 }
571 if (status == 0)
572 status = expect_element(reader,"/cdp_prep");
573 return (status);
574 } /* int parse_tag_rra_cdp_prep */
576 /*
577 * Parse the <params> block within an RRA definition
578 */
579 static int parse_tag_rra_params(
580 xmlTextReaderPtr reader,
581 rra_def_t *rra_def)
582 {
583 xmlChar *element;
584 int status;
586 status = -1;
587 while ((element = get_xml_element(reader)) != NULL){
588 /*
589 * Parameters for CF_HWPREDICT
590 */
591 if (xmlStrcasecmp(element, (const xmlChar *) "hw_alpha") == 0)
592 status = get_xml_double(reader,
593 &rra_def->par[RRA_hw_alpha].u_val);
594 else if (xmlStrcasecmp(element, (const xmlChar *) "hw_beta") == 0)
595 status = get_xml_double(reader,
596 &rra_def->par[RRA_hw_beta].u_val);
597 else if (xmlStrcasecmp(element,
598 (const xmlChar *) "dependent_rra_idx") == 0)
599 status = get_xml_ulong(reader,
600 &rra_def->
601 par[RRA_dependent_rra_idx].u_cnt);
602 /*
603 * Parameters for CF_SEASONAL and CF_DEVSEASONAL
604 */
605 else if (xmlStrcasecmp(element, (const xmlChar *) "seasonal_gamma") ==
606 0)
607 status =
608 get_xml_double(reader,
609 &rra_def->par[RRA_seasonal_gamma].u_val);
610 else if (xmlStrcasecmp
611 (element, (const xmlChar *) "seasonal_smooth_idx") == 0)
612 status =
613 get_xml_ulong(reader,
614 &rra_def->
615 par[RRA_seasonal_smooth_idx].u_cnt);
616 else if (xmlStrcasecmp(element, (const xmlChar *) "smoothing_window")
617 == 0)
618 status =
619 get_xml_double(reader,
620 &rra_def->
621 par[RRA_seasonal_smoothing_window].
622 u_val);
623 /* else if (dependent_rra_idx) ...; */
624 /*
625 * Parameters for CF_FAILURES
626 */
627 else if (xmlStrcasecmp(element, (const xmlChar *) "delta_pos") == 0)
628 status = get_xml_double(reader,
629 &rra_def->par[RRA_delta_pos].u_val);
630 else if (xmlStrcasecmp(element, (const xmlChar *) "delta_neg") == 0)
631 status = get_xml_double(reader,
632 &rra_def->par[RRA_delta_neg].u_val);
633 else if (xmlStrcasecmp(element, (const xmlChar *) "window_len") == 0)
634 status = get_xml_ulong(reader,
635 &rra_def->par[RRA_window_len].
636 u_cnt);
637 else if (xmlStrcasecmp(element, (const xmlChar *) "failure_threshold")
638 == 0)
639 status =
640 get_xml_ulong(reader,
641 &rra_def->
642 par[RRA_failure_threshold].u_cnt);
643 /*
644 * Parameters for CF_AVERAGE, CF_MAXIMUM, CF_MINIMUM, and CF_LAST
645 */
646 else if (xmlStrcasecmp(element, (const xmlChar *) "xff") == 0)
647 status = get_xml_double(reader,
648 &rra_def->par[RRA_cdp_xff_val].
649 u_val);
650 /*
651 * Compatibility code for 1.0.49
652 */
653 else if (xmlStrcasecmp(element, (const xmlChar *) "value") == 0) { /* {{{ */
654 unsigned int i = 0;
656 for (i=0;i<ARRAY_LENGTH(rra_def->par);i++){
657 if ((i == RRA_dependent_rra_idx)
658 || (i == RRA_seasonal_smooth_idx)
659 || (i == RRA_failure_threshold))
660 status = get_xml_ulong(reader,
661 &rra_def->par[i].
662 u_cnt);
663 else
664 status = get_xml_double(reader,
665 &rra_def->par[i].u_val);
667 if (status != 0)
668 break;
669 if ( i-1 < ARRAY_LENGTH(rra_def->par)){
670 status = expect_element(reader,"/value");
671 if (status == 0){
672 status = expect_element(reader,"value");
673 }
674 }
675 if (status != 0){
676 break;
677 }
678 }
679 } /* }}} */
680 else if (xmlStrcasecmp(element,(const xmlChar *) "/params") == 0){
681 xmlFree(element);
682 return status;
683 } /* }}} */
684 else {
685 rrd_set_error("line %d: parse_tag_rra_params: Unknown tag: %s",
686 xmlTextReaderGetParserLineNumber(reader),element);
687 status = -1;
688 }
689 status = expect_element_end(reader,(char *)element);
690 xmlFree(element);
691 if (status != 0)
692 break;
693 }
694 return (status);
695 } /* int parse_tag_rra_params */
697 /*
698 * Parse an RRA definition
699 */
700 static int parse_tag_rra_cf(
701 xmlTextReaderPtr reader,
702 rra_def_t *rra_def)
703 {
704 int status;
706 status = get_xml_string(reader,
707 rra_def->cf_nam, sizeof(rra_def->cf_nam));
708 if (status != 0)
709 return status;
711 status = cf_conv(rra_def->cf_nam);
712 if (status == -1) {
713 rrd_set_error("parse_tag_rra_cf: Unknown consolidation function: %s",
714 rra_def->cf_nam);
715 return -1;
716 }
718 return 0;
719 } /* int parse_tag_rra_cf */
721 static int parse_tag_rra(
722 xmlTextReaderPtr reader,
723 rrd_t *rrd)
724 {
725 int status;
726 xmlChar *element;
728 rra_def_t *cur_rra_def;
729 cdp_prep_t *cur_cdp_prep;
730 rra_ptr_t *cur_rra_ptr;
732 /* Allocate more rra_def space for this RRA */
733 { /* {{{ */
734 rra_def_t *temp;
736 temp = (rra_def_t *) realloc(rrd->rra_def,
737 sizeof(rra_def_t) *
738 (rrd->stat_head->rra_cnt + 1));
739 if (temp == NULL) {
740 rrd_set_error("parse_tag_rra: realloc failed.");
741 return (-1);
742 }
743 rrd->rra_def = temp;
744 cur_rra_def = rrd->rra_def + rrd->stat_head->rra_cnt;
745 memset(cur_rra_def, '\0', sizeof(rra_def_t));
746 } /* }}} */
748 /* allocate cdp_prep_t */
749 { /* {{{ */
750 cdp_prep_t *temp;
752 temp = (cdp_prep_t *) realloc(rrd->cdp_prep, sizeof(cdp_prep_t)
753 * rrd->stat_head->ds_cnt
754 * (rrd->stat_head->rra_cnt + 1));
755 if (temp == NULL) {
756 rrd_set_error("parse_tag_rra: realloc failed.");
757 return (-1);
758 }
759 rrd->cdp_prep = temp;
760 cur_cdp_prep = rrd->cdp_prep
761 + (rrd->stat_head->ds_cnt * rrd->stat_head->rra_cnt);
762 memset(cur_cdp_prep, '\0',
763 sizeof(cdp_prep_t) * rrd->stat_head->ds_cnt);
764 } /* }}} */
766 /* allocate rra_ptr_t */
767 { /* {{{ */
768 rra_ptr_t *temp;
770 temp = (rra_ptr_t *) realloc(rrd->rra_ptr,
771 sizeof(rra_ptr_t) *
772 (rrd->stat_head->rra_cnt + 1));
773 if (temp == NULL) {
774 rrd_set_error("parse_tag_rra: realloc failed.");
775 return (-1);
776 }
777 rrd->rra_ptr = temp;
778 cur_rra_ptr = rrd->rra_ptr + rrd->stat_head->rra_cnt;
779 memset(cur_rra_ptr, '\0', sizeof(rra_ptr_t));
780 } /* }}} */
782 /* All space successfully allocated, increment number of RRAs. */
783 rrd->stat_head->rra_cnt++;
785 status = 0;
786 while ((element = get_xml_element(reader)) != NULL){
787 if (xmlStrcasecmp(element, (const xmlChar *) "cf") == 0)
788 status = parse_tag_rra_cf(reader, cur_rra_def);
789 else if (xmlStrcasecmp(element, (const xmlChar *) "pdp_per_row") == 0)
790 status = get_xml_ulong(reader,
791 &cur_rra_def->pdp_cnt);
792 else if (atoi(rrd->stat_head->version) == 1
793 && xmlStrcasecmp(element, (const xmlChar *) "xff") == 0)
794 status = get_xml_double(reader,
795 (double *) &cur_rra_def->
796 par[RRA_cdp_xff_val].u_val);
797 else if (atoi(rrd->stat_head->version) >= 2
798 && xmlStrcasecmp(element, (const xmlChar *) "params") == 0){
799 xmlFree(element);
800 status = parse_tag_rra_params(reader, cur_rra_def);
801 if (status == 0)
802 continue;
803 else
804 return status;
805 }
806 else if (xmlStrcasecmp(element, (const xmlChar *) "cdp_prep") == 0){
807 xmlFree(element);
808 status = parse_tag_rra_cdp_prep(reader, rrd, cur_cdp_prep);
809 if (status == 0)
810 continue;
811 else
812 return status;
813 }
814 else if (xmlStrcasecmp(element, (const xmlChar *) "database") == 0){
815 xmlFree(element);
816 status = parse_tag_rra_database(reader, rrd);
817 if (status == 0)
818 continue;
819 else
820 return status;
821 }
822 else if (xmlStrcasecmp(element,(const xmlChar *) "/rra") == 0){
823 xmlFree(element);
824 return status;
825 } /* }}} */
826 else {
827 rrd_set_error("line %d: parse_tag_rra: Unknown tag: %s",
828 xmlTextReaderGetParserLineNumber(reader), element);
829 status = -1;
830 }
831 if (status != 0) {
832 xmlFree(element);
833 return status;
834 }
835 status = expect_element_end(reader,(char *)element);
836 xmlFree(element);
837 if (status != 0) {
838 return status;
839 }
840 }
841 /* Set the RRA pointer to a random location */
842 cur_rra_ptr->cur_row = rrd_random() % cur_rra_def->row_cnt;
844 return (status);
845 } /* int parse_tag_rra */
847 /*
848 * Parse a DS definition
849 */
850 static int parse_tag_ds_cdef(
851 xmlTextReaderPtr reader,
852 rrd_t *rrd)
853 {
854 xmlChar *cdef;
856 cdef = get_xml_text(reader);
857 if (cdef != NULL){
858 /* We're always working on the last DS that has been added to the structure
859 * when we get here */
860 parseCDEF_DS((char *)cdef, rrd, rrd->stat_head->ds_cnt - 1);
861 xmlFree(cdef);
862 if (rrd_test_error())
863 return -1;
864 else
865 return 0;
866 }
867 return -1;
868 } /* int parse_tag_ds_cdef */
870 static int parse_tag_ds_type(
871 xmlTextReaderPtr reader,
872 ds_def_t *ds_def)
873 {
874 char *dst;
875 dst = (char *)get_xml_text(reader);
876 if (dst != NULL){
877 int status;
878 status = dst_conv(dst);
879 if (status == -1) {
880 rrd_set_error("parse_tag_ds_type: Unknown data source type: %s",
881 dst);
882 return -1;
883 }
884 strncpy(ds_def->dst,dst,sizeof(ds_def->dst)-1);
885 ds_def->dst[sizeof(ds_def->dst)-1] = '\0';
886 xmlFree(dst);
887 return 0;
888 }
889 return -1;
890 } /* int parse_tag_ds_type */
892 static int parse_tag_ds(
893 xmlTextReaderPtr reader,
894 rrd_t *rrd)
895 {
896 int status;
897 xmlChar *element;
899 ds_def_t *cur_ds_def;
900 pdp_prep_t *cur_pdp_prep;
902 /*
903 * If there are DS definitions after RRA definitions the number of values,
904 * cdp_prep areas and so on will be calculated wrong. Thus, enforce a
905 * specific order in this case.
906 */
907 if (rrd->stat_head->rra_cnt > 0) {
908 rrd_set_error("parse_tag_ds: All data source definitions MUST "
909 "precede the RRA definitions!");
910 return (-1);
911 }
913 /* Allocate space for the new DS definition */
914 { /* {{{ */
915 ds_def_t *temp;
917 temp = (ds_def_t *) realloc(rrd->ds_def,
918 sizeof(ds_def_t) *
919 (rrd->stat_head->ds_cnt + 1));
920 if (temp == NULL) {
921 rrd_set_error("parse_tag_ds: malloc failed.");
922 return (-1);
923 }
924 rrd->ds_def = temp;
925 cur_ds_def = rrd->ds_def + rrd->stat_head->ds_cnt;
926 memset(cur_ds_def, '\0', sizeof(ds_def_t));
927 } /* }}} */
929 /* Allocate pdp_prep space for the new DS definition */
930 { /* {{{ */
931 pdp_prep_t *temp;
933 temp = (pdp_prep_t *) realloc(rrd->pdp_prep,
934 sizeof(pdp_prep_t) *
935 (rrd->stat_head->ds_cnt + 1));
936 if (temp == NULL) {
937 rrd_set_error("parse_tag_ds: malloc failed.");
938 return (-1);
939 }
940 rrd->pdp_prep = temp;
941 cur_pdp_prep = rrd->pdp_prep + rrd->stat_head->ds_cnt;
942 memset(cur_pdp_prep, '\0', sizeof(pdp_prep_t));
943 } /* }}} */
945 /* All allocations successful, let's increment the number of DSes. */
946 rrd->stat_head->ds_cnt++;
948 status = 0;
949 while ((element = get_xml_element(reader)) != NULL){
950 if (xmlStrcasecmp(element, (const xmlChar *) "name") == 0){
951 status = get_xml_string(reader,cur_ds_def->ds_nam,sizeof(cur_ds_def->ds_nam));
952 }
953 else if (xmlStrcasecmp(element, (const xmlChar *) "type") == 0)
954 status = parse_tag_ds_type(reader, cur_ds_def);
955 else if (xmlStrcasecmp(element,
956 (const xmlChar *) "minimal_heartbeat") == 0)
957 status = get_xml_ulong(reader,
958 &cur_ds_def->par[DS_mrhb_cnt].
959 u_cnt);
960 else if (xmlStrcasecmp(element, (const xmlChar *) "min") == 0)
961 status = get_xml_double(reader,
962 &cur_ds_def->par[DS_min_val].u_val);
963 else if (xmlStrcasecmp(element, (const xmlChar *) "max") == 0)
964 status = get_xml_double(reader,
965 &cur_ds_def->par[DS_max_val].u_val);
966 else if (xmlStrcasecmp(element, (const xmlChar *) "cdef") == 0)
967 status = parse_tag_ds_cdef(reader, rrd);
968 else if (xmlStrcasecmp(element, (const xmlChar *) "last_ds") == 0)
969 status = get_xml_string(reader,
970 cur_pdp_prep->last_ds,
971 sizeof(cur_pdp_prep->last_ds));
972 else if (xmlStrcasecmp(element, (const xmlChar *) "value") == 0)
973 status = get_xml_double(reader,
974 &cur_pdp_prep->scratch[PDP_val].
975 u_val);
976 else if (xmlStrcasecmp(element, (const xmlChar *) "unknown_sec") == 0)
977 status = get_xml_ulong(reader,
978 &cur_pdp_prep->
979 scratch[PDP_unkn_sec_cnt].u_cnt);
980 else if (xmlStrcasecmp(element, (const xmlChar *) "/ds") == 0) {
981 xmlFree(element);
982 break;
983 }
984 else {
985 rrd_set_error("parse_tag_ds: Unknown tag: %s", element);
986 status = -1;
987 }
988 if (status != 0) {
989 xmlFree(element);
990 break;
991 }
992 status = expect_element_end(reader,(char *)element);
993 xmlFree(element);
994 if (status != 0)
995 break;
996 }
998 return (status);
999 } /* int parse_tag_ds */
1001 /*
1002 * Parse root nodes
1003 */
1004 static int parse_tag_rrd(
1005 xmlTextReaderPtr reader,
1006 rrd_t *rrd)
1007 {
1008 int status;
1009 xmlChar *element;
1011 status = 0;
1012 while ((element = get_xml_element(reader)) != NULL ){
1013 if (xmlStrcasecmp(element, (const xmlChar *) "version") == 0)
1014 status = get_xml_string(reader,
1015 rrd->stat_head->version,
1016 sizeof(rrd->stat_head->version));
1017 else if (xmlStrcasecmp(element, (const xmlChar *) "step") == 0)
1018 status = get_xml_ulong(reader,
1019 &rrd->stat_head->pdp_step);
1020 else if (xmlStrcasecmp(element, (const xmlChar *) "lastupdate") == 0) {
1021 #ifdef TIME_T_IS_LONG
1022 status = get_xml_long(reader, &rrd->live_head->last_up);
1023 #else
1024 #ifdef TIME_T_IS_LONG_LONG
1025 status = get_xml_llong(reader, &rrd->live_head->last_up);
1026 #else
1027 if (sizeof(time_t) == sizeof(long)) {
1028 status = get_xml_long(reader,
1029 (long *)&rrd->live_head->last_up);
1030 }
1031 else if (sizeof(time_t) == sizeof(long long)) {
1032 status = get_xml_llong(reader,
1033 (long long *)&rrd->live_head->last_up);
1034 }
1035 #endif
1036 #endif
1037 }
1038 else if (xmlStrcasecmp(element, (const xmlChar *) "ds") == 0){
1039 xmlFree(element);
1040 status = parse_tag_ds(reader, rrd);
1041 /* as we come back the </ds> tag is already gone */
1042 if (status == 0)
1043 continue;
1044 else
1045 return status;
1046 }
1047 else if (xmlStrcasecmp(element, (const xmlChar *) "rra") == 0){
1048 xmlFree(element);
1049 status = parse_tag_rra(reader, rrd);
1050 if (status == 0)
1051 continue;
1052 else
1053 return status;
1054 }
1055 else if (xmlStrcasecmp(element, (const xmlChar *) "/rrd") == 0) {
1056 xmlFree(element);
1057 return status;
1058 }
1059 else {
1060 rrd_set_error("parse_tag_rrd: Unknown tag: %s", element);
1061 status = -1;
1062 }
1064 if (status != 0){
1065 xmlFree(element);
1066 break;
1067 }
1068 status = expect_element_end(reader,(char *)element);
1069 xmlFree(element);
1070 if (status != 0)
1071 break;
1072 }
1073 return (status);
1074 } /* int parse_tag_rrd */
1076 static rrd_t *parse_file(
1077 const char *filename)
1078 {
1079 xmlTextReaderPtr reader;
1080 int status;
1082 rrd_t *rrd;
1084 reader = xmlNewTextReaderFilename(filename);
1085 if (reader == NULL) {
1086 rrd_set_error("Could not create xml reader for: %s",filename);
1087 return (NULL);
1088 }
1090 if (expect_element(reader,"rrd") != 0) {
1091 xmlFreeTextReader(reader);
1092 return (NULL);
1093 }
1095 rrd = (rrd_t *) malloc(sizeof(rrd_t));
1096 if (rrd == NULL) {
1097 rrd_set_error("parse_file: malloc failed.");
1098 xmlFreeTextReader(reader);
1099 return (NULL);
1100 }
1101 memset(rrd, '\0', sizeof(rrd_t));
1103 rrd->stat_head = (stat_head_t *) malloc(sizeof(stat_head_t));
1104 if (rrd->stat_head == NULL) {
1105 rrd_set_error("parse_tag_rrd: malloc failed.");
1106 xmlFreeTextReader(reader);
1107 free(rrd);
1108 return (NULL);
1109 }
1110 memset(rrd->stat_head, '\0', sizeof(stat_head_t));
1112 strncpy(rrd->stat_head->cookie, "RRD", sizeof(rrd->stat_head->cookie));
1113 rrd->stat_head->float_cookie = FLOAT_COOKIE;
1115 rrd->live_head = (live_head_t *) malloc(sizeof(live_head_t));
1116 if (rrd->live_head == NULL) {
1117 rrd_set_error("parse_tag_rrd: malloc failed.");
1118 xmlFreeTextReader(reader);
1119 free(rrd->stat_head);
1120 free(rrd);
1121 return (NULL);
1122 }
1123 memset(rrd->live_head, '\0', sizeof(live_head_t));
1125 status = parse_tag_rrd(reader, rrd);
1127 xmlFreeTextReader(reader);
1129 if (status != 0) {
1130 local_rrd_free(rrd);
1131 rrd = NULL;
1132 }
1134 return (rrd);
1135 } /* rrd_t *parse_file */
1137 static int write_file(
1138 const char *file_name,
1139 rrd_t *rrd)
1140 {
1141 FILE *fh;
1142 unsigned int i;
1143 unsigned int rra_offset;
1145 if (strcmp("-", file_name) == 0)
1146 fh = stdout;
1147 else {
1148 int fd_flags = O_WRONLY | O_CREAT;
1149 int fd;
1151 #if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
1152 fd_flags |= O_BINARY;
1153 #endif
1155 if (opt_force_overwrite == 0)
1156 fd_flags |= O_EXCL;
1158 fd = open(file_name, fd_flags, 0666);
1159 if (fd == -1) {
1160 rrd_set_error("creating '%s': %s", file_name,
1161 rrd_strerror(errno));
1162 return (-1);
1163 }
1165 fh = fdopen(fd, "wb");
1166 if (fh == NULL) {
1167 rrd_set_error("fdopen failed: %s", rrd_strerror(errno));
1168 close(fd);
1169 return (-1);
1170 }
1171 }
1172 if (atoi(rrd->stat_head->version) < 3) {
1173 /* we output 3 or higher */
1174 strcpy(rrd->stat_head->version, "0003");
1175 }
1176 fwrite(rrd->stat_head, sizeof(stat_head_t), 1, fh);
1177 fwrite(rrd->ds_def, sizeof(ds_def_t), rrd->stat_head->ds_cnt, fh);
1178 fwrite(rrd->rra_def, sizeof(rra_def_t), rrd->stat_head->rra_cnt, fh);
1179 fwrite(rrd->live_head, sizeof(live_head_t), 1, fh);
1180 fwrite(rrd->pdp_prep, sizeof(pdp_prep_t), rrd->stat_head->ds_cnt, fh);
1181 fwrite(rrd->cdp_prep, sizeof(cdp_prep_t),
1182 rrd->stat_head->rra_cnt * rrd->stat_head->ds_cnt, fh);
1183 fwrite(rrd->rra_ptr, sizeof(rra_ptr_t), rrd->stat_head->rra_cnt, fh);
1185 /* calculate the number of rrd_values to dump */
1186 rra_offset = 0;
1187 for (i = 0; i < rrd->stat_head->rra_cnt; i++) {
1188 unsigned long num_rows = rrd->rra_def[i].row_cnt;
1189 unsigned long cur_row = rrd->rra_ptr[i].cur_row;
1190 unsigned long ds_cnt = rrd->stat_head->ds_cnt;
1192 fwrite(rrd->rrd_value +
1193 (rra_offset + num_rows - 1 - cur_row) * ds_cnt,
1194 sizeof(rrd_value_t), (cur_row + 1) * ds_cnt, fh);
1196 fwrite(rrd->rrd_value + rra_offset * ds_cnt,
1197 sizeof(rrd_value_t), (num_rows - 1 - cur_row) * ds_cnt, fh);
1199 rra_offset += num_rows;
1200 }
1202 /* lets see if we had an error */
1203 if (ferror(fh)) {
1204 rrd_set_error("a file error occurred while creating '%s'", file_name);
1205 fclose(fh);
1206 return (-1);
1207 }
1209 fclose(fh);
1210 return (0);
1211 } /* int write_file */
1213 int rrd_restore(
1214 int argc,
1215 char **argv)
1216 {
1217 rrd_t *rrd;
1218 char *old_locale;
1219 /* init rrd clean */
1220 optind = 0;
1221 opterr = 0; /* initialize getopt */
1222 while (42) {
1223 int opt;
1224 int option_index = 0;
1225 static struct option long_options[] = {
1226 {"range-check", no_argument, 0, 'r'},
1227 {"force-overwrite", no_argument, 0, 'f'},
1228 {0, 0, 0, 0}
1229 };
1231 opt = getopt_long(argc, argv, "rf", long_options, &option_index);
1233 if (opt == EOF)
1234 break;
1236 switch (opt) {
1237 case 'r':
1238 opt_range_check = 1;
1239 break;
1241 case 'f':
1242 opt_force_overwrite = 1;
1243 break;
1245 default:
1246 rrd_set_error("usage rrdtool %s [--range-check|-r] "
1247 "[--force-overwrite/-f] file.xml file.rrd",
1248 argv[0]);
1249 return (-1);
1250 break;
1251 }
1252 } /* while (42) */
1254 if ((argc - optind) != 2) {
1255 rrd_set_error("usage rrdtool %s [--range-check/-r] "
1256 "[--force-overwrite/-f] file.xml file.rrd", argv[0]);
1257 return (-1);
1258 }
1260 old_locale = setlocale(LC_NUMERIC, "C");
1262 rrd = parse_file(argv[optind]);
1264 setlocale(LC_NUMERIC, old_locale);
1266 if (rrd == NULL)
1267 return (-1);
1269 if (write_file(argv[optind + 1], rrd) != 0) {
1270 local_rrd_free(rrd);
1271 return (-1);
1272 }
1273 local_rrd_free(rrd);
1276 return (0);
1277 } /* int rrd_restore */
1279 /* vim: set sw=2 sts=2 ts=8 et fdm=marker : */