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