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