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$
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 #ifndef TIME_T_IS_LONG
245 static int get_xml_llong(
246 xmlTextReaderPtr reader,
247 long long *value)
248 {
250 xmlChar *text;
251 long long temp;
252 if ((text = get_xml_text(reader)) != NULL){
253 errno = 0;
254 temp = strtoll((char *)text,NULL, 0);
255 if (errno>0){
256 rrd_set_error("ling %d: get_xml_llong from '%s' %s",
257 xmlTextReaderGetParserLineNumber(reader),
258 text,rrd_strerror(errno));
259 xmlFree(text);
260 return -1;
261 }
262 xmlFree(text);
263 *value = temp;
264 return 0;
265 }
266 return -1;
267 } /* get_xml_llong */
269 #endif
271 static int get_xml_double(
272 xmlTextReaderPtr reader,
273 double *value)
274 {
276 char *text;
277 double temp;
278 if ((text = (char *)get_xml_text(reader))!= NULL){
279 if (strcasestr(text,"nan")){
280 *value = DNAN;
281 xmlFree(text);
282 return 0;
283 }
284 else if (strcasestr(text,"-inf")){
285 *value = -DINF;
286 xmlFree(text);
287 return 0;
288 }
289 else if (strcasestr(text,"+inf")
290 || strcasestr(text,"inf")){
291 *value = DINF;
292 xmlFree(text);
293 return 0;
294 }
295 errno = 0;
296 temp = strtod((char *)text,NULL);
297 if (errno>0){
298 rrd_set_error("ling %d: get_xml_double from '%s' %s",
299 xmlTextReaderGetParserLineNumber(reader),
300 text,rrd_strerror(errno));
301 xmlFree(text);
302 return -1;
303 }
304 xmlFree(text);
305 *value = temp;
306 return 0;
307 }
308 return -1;
309 } /* get_xml_double */
312 static int value_check_range(
313 rrd_value_t *rrd_value,
314 const ds_def_t *ds_def)
315 {
316 double min;
317 double max;
319 if (opt_range_check == 0)
320 return (0);
322 min = ds_def->par[DS_min_val].u_val;
323 max = ds_def->par[DS_max_val].u_val;
325 if (((!isnan(min)) && (*rrd_value < min))
326 || ((!isnan(max)) && (*rrd_value > max)))
327 *rrd_value = DNAN;
329 return (0);
330 } /* int value_check_range */
332 /*
333 * Parse the <database> block within an RRA definition
334 */
336 static int parse_tag_rra_database_row(
337 xmlTextReaderPtr reader,
338 rrd_t *rrd,
339 rrd_value_t *rrd_value)
340 {
341 unsigned int values_count = 0;
342 int status;
344 status = 0;
345 for (values_count = 0;values_count < rrd->stat_head->ds_cnt;values_count++){
346 if (expect_element(reader,"v") == 0){
347 status = get_xml_double(reader,rrd_value + values_count);
348 if (status == 0)
349 value_check_range(rrd_value + values_count,
350 rrd->ds_def + values_count);
351 else
352 break;
353 } else
354 return -1;
355 if (expect_element(reader,"/v") == -1){
356 return -1;
357 }
358 }
359 return status;
360 } /* int parse_tag_rra_database_row */
362 static int parse_tag_rra_database(
363 xmlTextReaderPtr reader,
364 rrd_t *rrd )
365 {
366 rra_def_t *cur_rra_def;
367 unsigned int total_row_cnt;
368 int status;
369 int i;
370 xmlChar *element;
372 total_row_cnt = 0;
373 for (i = 0; i < (((int) rrd->stat_head->rra_cnt) - 1); i++)
374 total_row_cnt += rrd->rra_def[i].row_cnt;
376 cur_rra_def = rrd->rra_def + i;
378 status = 0;
379 while ((element = get_xml_element(reader)) != NULL){
380 if (xmlStrcasecmp(element,(const xmlChar *)"row") == 0){
381 rrd_value_t *temp;
382 rrd_value_t *cur_rrd_value;
383 unsigned int total_values_count = rrd->stat_head->ds_cnt
384 * (total_row_cnt + 1);
386 /* Allocate space for the new values.. */
387 temp = (rrd_value_t *) realloc(rrd->rrd_value,
388 sizeof(rrd_value_t) *
389 total_values_count);
390 if (temp == NULL) {
391 rrd_set_error("parse_tag_rra_database: realloc failed.");
392 status = -1;
393 break;
394 }
395 rrd->rrd_value = temp;
396 cur_rrd_value = rrd->rrd_value
397 + (rrd->stat_head->ds_cnt * total_row_cnt);
398 memset(cur_rrd_value, '\0',
399 sizeof(rrd_value_t) * rrd->stat_head->ds_cnt);
400 total_row_cnt++;
401 cur_rra_def->row_cnt++;
403 status =
404 parse_tag_rra_database_row(reader, rrd, cur_rrd_value);
405 if (status == 0)
406 status = expect_element(reader,"/row");
407 } /* if (xmlStrcasecmp(element,"row")) */
408 else {
409 if ( xmlStrcasecmp(element,(const xmlChar *)"/database") == 0){
410 xmlFree(element);
411 break;
412 }
413 else {
414 rrd_set_error("line %d: found unexpected tag: %s",
415 xmlTextReaderGetParserLineNumber(reader),element);
416 status = -1;
417 }
418 }
419 xmlFree(element);
420 if (status != 0)
421 break;
422 }
423 return (status);
424 } /* int parse_tag_rra_database */
426 /*
427 * Parse the <cdp_prep> block within an RRA definition
428 */
429 static int parse_tag_rra_cdp_prep_ds_history(
430 xmlTextReaderPtr reader,
431 cdp_prep_t *cdp_prep)
432 {
433 /* Make `history_buffer' the same size as the scratch area, plus the
434 * terminating NULL byte. */
435 xmlChar *history;
436 char *history_ptr;
437 int i;
438 if ((history = get_xml_text(reader)) != NULL){
439 history_ptr = (char *) (&cdp_prep->scratch[0]);
440 for (i = 0; history[i] != '\0'; i++)
441 history_ptr[i] = (history[i] == '1') ? 1 : 0;
442 xmlFree(history);
443 return 0;
444 }
445 return -1;
446 } /* int parse_tag_rra_cdp_prep_ds_history */
448 static int parse_tag_rra_cdp_prep_ds(
449 xmlTextReaderPtr reader,
450 rrd_t *rrd,
451 cdp_prep_t *cdp_prep)
452 {
453 int status;
454 xmlChar *element;
455 memset(cdp_prep, '\0', sizeof(cdp_prep_t));
457 status = -1;
459 if (atoi(rrd->stat_head->version) == 1) {
460 cdp_prep->scratch[CDP_primary_val].u_val = 0.0;
461 cdp_prep->scratch[CDP_secondary_val].u_val = 0.0;
462 }
464 while ((element = get_xml_element(reader)) != NULL){
465 if (xmlStrcasecmp(element, (const xmlChar *) "primary_value") == 0)
466 status =
467 get_xml_double(reader,&cdp_prep->scratch[CDP_primary_val].u_val);
468 else if (xmlStrcasecmp(element, (const xmlChar *) "secondary_value") == 0)
469 status =
470 get_xml_double(reader,&cdp_prep->scratch[CDP_secondary_val].u_val);
471 else if (xmlStrcasecmp(element, (const xmlChar *) "intercept") == 0)
472 status = get_xml_double(reader,
473 &cdp_prep->
474 scratch[CDP_hw_intercept].u_val);
475 else if (xmlStrcasecmp(element, (const xmlChar *) "last_intercept") ==
476 0)
477 status =
478 get_xml_double(reader,
479 &cdp_prep->
480 scratch[CDP_hw_last_intercept].u_val);
481 else if (xmlStrcasecmp(element, (const xmlChar *) "slope") == 0)
482 status = get_xml_double(reader,
483 &cdp_prep->scratch[CDP_hw_slope].
484 u_val);
485 else if (xmlStrcasecmp(element, (const xmlChar *) "last_slope") == 0)
486 status = get_xml_double(reader,
487 &cdp_prep->
488 scratch[CDP_hw_last_slope].u_val);
489 else if (xmlStrcasecmp(element, (const xmlChar *) "nan_count") == 0)
490 status = get_xml_ulong(reader,
491 &cdp_prep->
492 scratch[CDP_null_count].u_cnt);
493 else if (xmlStrcasecmp(element, (const xmlChar *) "last_nan_count") ==
494 0)
495 status =
496 get_xml_ulong(reader,
497 &cdp_prep->
498 scratch[CDP_last_null_count].u_cnt);
499 else if (xmlStrcasecmp(element, (const xmlChar *) "seasonal") == 0)
500 status = get_xml_double(reader,
501 &cdp_prep->scratch[CDP_hw_seasonal].
502 u_val);
503 else if (xmlStrcasecmp(element, (const xmlChar *) "last_seasonal") ==
504 0)
505 status =
506 get_xml_double(reader,
507 &cdp_prep->scratch[CDP_hw_last_seasonal].
508 u_val);
509 else if (xmlStrcasecmp(element, (const xmlChar *) "init_flag") == 0)
510 status = get_xml_ulong(reader,
511 &cdp_prep->
512 scratch[CDP_init_seasonal].u_cnt);
513 else if (xmlStrcasecmp(element, (const xmlChar *) "history") == 0)
514 status = parse_tag_rra_cdp_prep_ds_history(reader, cdp_prep);
515 else if (xmlStrcasecmp(element, (const xmlChar *) "value") == 0)
516 status = get_xml_double(reader,
517 &cdp_prep->scratch[CDP_val].u_val);
518 else if (xmlStrcasecmp(element,
519 (const xmlChar *) "unknown_datapoints") == 0)
520 status = get_xml_ulong(reader,
521 &cdp_prep->
522 scratch[CDP_unkn_pdp_cnt].u_cnt);
523 else if (xmlStrcasecmp(element,
524 (const xmlChar *) "/ds") == 0){
525 xmlFree(element);
526 break;
527 }
528 else {
529 rrd_set_error("parse_tag_rra_cdp_prep: Unknown tag: %s",
530 element);
531 status = -1;
532 xmlFree(element);
533 break;
534 }
535 if (status != 0){
536 xmlFree(element);
537 break;
538 }
539 status = expect_element_end(reader,(char *)element);
540 xmlFree(element);
541 if (status != 0)
542 break;
543 }
544 return (status);
545 } /* int parse_tag_rra_cdp_prep_ds */
547 static int parse_tag_rra_cdp_prep(
548 xmlTextReaderPtr reader,
549 rrd_t *rrd,
550 cdp_prep_t *cdp_prep)
551 {
552 int status;
554 unsigned int ds_count;
556 status = 0;
557 for ( ds_count = 0; ds_count < rrd->stat_head->ds_cnt;ds_count++){
558 if (expect_element(reader,"ds") == 0) {
559 status = parse_tag_rra_cdp_prep_ds(reader, rrd,
560 cdp_prep + ds_count);
561 if (status != 0)
562 break;
563 } else {
564 status = -1;
565 break;
566 }
567 }
568 if (status == 0)
569 status = expect_element(reader,"/cdp_prep");
570 return (status);
571 } /* int parse_tag_rra_cdp_prep */
573 /*
574 * Parse the <params> block within an RRA definition
575 */
576 static int parse_tag_rra_params(
577 xmlTextReaderPtr reader,
578 rra_def_t *rra_def)
579 {
580 xmlChar *element;
581 int status;
583 status = -1;
584 while ((element = get_xml_element(reader)) != NULL){
585 /*
586 * Parameters for CF_HWPREDICT
587 */
588 if (xmlStrcasecmp(element, (const xmlChar *) "hw_alpha") == 0)
589 status = get_xml_double(reader,
590 &rra_def->par[RRA_hw_alpha].u_val);
591 else if (xmlStrcasecmp(element, (const xmlChar *) "hw_beta") == 0)
592 status = get_xml_double(reader,
593 &rra_def->par[RRA_hw_beta].u_val);
594 else if (xmlStrcasecmp(element,
595 (const xmlChar *) "dependent_rra_idx") == 0)
596 status = get_xml_ulong(reader,
597 &rra_def->
598 par[RRA_dependent_rra_idx].u_cnt);
599 /*
600 * Parameters for CF_SEASONAL and CF_DEVSEASONAL
601 */
602 else if (xmlStrcasecmp(element, (const xmlChar *) "seasonal_gamma") ==
603 0)
604 status =
605 get_xml_double(reader,
606 &rra_def->par[RRA_seasonal_gamma].u_val);
607 else if (xmlStrcasecmp
608 (element, (const xmlChar *) "seasonal_smooth_idx") == 0)
609 status =
610 get_xml_ulong(reader,
611 &rra_def->
612 par[RRA_seasonal_smooth_idx].u_cnt);
613 else if (xmlStrcasecmp(element, (const xmlChar *) "smoothing_window")
614 == 0)
615 status =
616 get_xml_double(reader,
617 &rra_def->
618 par[RRA_seasonal_smoothing_window].
619 u_val);
620 /* else if (dependent_rra_idx) ...; */
621 /*
622 * Parameters for CF_FAILURES
623 */
624 else if (xmlStrcasecmp(element, (const xmlChar *) "delta_pos") == 0)
625 status = get_xml_double(reader,
626 &rra_def->par[RRA_delta_pos].u_val);
627 else if (xmlStrcasecmp(element, (const xmlChar *) "delta_neg") == 0)
628 status = get_xml_double(reader,
629 &rra_def->par[RRA_delta_neg].u_val);
630 else if (xmlStrcasecmp(element, (const xmlChar *) "window_len") == 0)
631 status = get_xml_ulong(reader,
632 &rra_def->par[RRA_window_len].
633 u_cnt);
634 else if (xmlStrcasecmp(element, (const xmlChar *) "failure_threshold")
635 == 0)
636 status =
637 get_xml_ulong(reader,
638 &rra_def->
639 par[RRA_failure_threshold].u_cnt);
640 /*
641 * Parameters for CF_AVERAGE, CF_MAXIMUM, CF_MINIMUM, and CF_LAST
642 */
643 else if (xmlStrcasecmp(element, (const xmlChar *) "xff") == 0)
644 status = get_xml_double(reader,
645 &rra_def->par[RRA_cdp_xff_val].
646 u_val);
647 /*
648 * Compatibility code for 1.0.49
649 */
650 else if (xmlStrcasecmp(element, (const xmlChar *) "value") == 0) { /* {{{ */
651 unsigned int i = 0;
653 for (i=0;i<ARRAY_LENGTH(rra_def->par);i++){
654 if ((i == RRA_dependent_rra_idx)
655 || (i == RRA_seasonal_smooth_idx)
656 || (i == RRA_failure_threshold))
657 status = get_xml_ulong(reader,
658 &rra_def->par[i].
659 u_cnt);
660 else
661 status = get_xml_double(reader,
662 &rra_def->par[i].u_val);
664 if (status != 0)
665 break;
666 if ( i-1 < ARRAY_LENGTH(rra_def->par)){
667 status = expect_element(reader,"/value");
668 if (status == 0){
669 status = expect_element(reader,"value");
670 }
671 }
672 if (status != 0){
673 break;
674 }
675 }
676 } /* }}} */
677 else if (xmlStrcasecmp(element,(const xmlChar *) "/params") == 0){
678 xmlFree(element);
679 return status;
680 } /* }}} */
681 else {
682 rrd_set_error("line %d: parse_tag_rra_params: Unknown tag: %s",
683 xmlTextReaderGetParserLineNumber(reader),element);
684 status = -1;
685 }
686 status = expect_element_end(reader,(char *)element);
687 xmlFree(element);
688 if (status != 0)
689 break;
690 }
691 return (status);
692 } /* int parse_tag_rra_params */
694 /*
695 * Parse an RRA definition
696 */
697 static int parse_tag_rra_cf(
698 xmlTextReaderPtr reader,
699 rra_def_t *rra_def)
700 {
701 int status;
703 status = get_xml_string(reader,
704 rra_def->cf_nam, sizeof(rra_def->cf_nam));
705 if (status != 0)
706 return status;
708 status = cf_conv(rra_def->cf_nam);
709 if (status == -1) {
710 rrd_set_error("parse_tag_rra_cf: Unknown consolidation function: %s",
711 rra_def->cf_nam);
712 return -1;
713 }
715 return 0;
716 } /* int parse_tag_rra_cf */
718 static int parse_tag_rra(
719 xmlTextReaderPtr reader,
720 rrd_t *rrd)
721 {
722 int status;
723 xmlChar *element;
725 rra_def_t *cur_rra_def;
726 cdp_prep_t *cur_cdp_prep;
727 rra_ptr_t *cur_rra_ptr;
729 /* Allocate more rra_def space for this RRA */
730 { /* {{{ */
731 rra_def_t *temp;
733 temp = (rra_def_t *) realloc(rrd->rra_def,
734 sizeof(rra_def_t) *
735 (rrd->stat_head->rra_cnt + 1));
736 if (temp == NULL) {
737 rrd_set_error("parse_tag_rra: realloc failed.");
738 return (-1);
739 }
740 rrd->rra_def = temp;
741 cur_rra_def = rrd->rra_def + rrd->stat_head->rra_cnt;
742 memset(cur_rra_def, '\0', sizeof(rra_def_t));
743 } /* }}} */
745 /* allocate cdp_prep_t */
746 { /* {{{ */
747 cdp_prep_t *temp;
749 temp = (cdp_prep_t *) realloc(rrd->cdp_prep, sizeof(cdp_prep_t)
750 * rrd->stat_head->ds_cnt
751 * (rrd->stat_head->rra_cnt + 1));
752 if (temp == NULL) {
753 rrd_set_error("parse_tag_rra: realloc failed.");
754 return (-1);
755 }
756 rrd->cdp_prep = temp;
757 cur_cdp_prep = rrd->cdp_prep
758 + (rrd->stat_head->ds_cnt * rrd->stat_head->rra_cnt);
759 memset(cur_cdp_prep, '\0',
760 sizeof(cdp_prep_t) * rrd->stat_head->ds_cnt);
761 } /* }}} */
763 /* allocate rra_ptr_t */
764 { /* {{{ */
765 rra_ptr_t *temp;
767 temp = (rra_ptr_t *) realloc(rrd->rra_ptr,
768 sizeof(rra_ptr_t) *
769 (rrd->stat_head->rra_cnt + 1));
770 if (temp == NULL) {
771 rrd_set_error("parse_tag_rra: realloc failed.");
772 return (-1);
773 }
774 rrd->rra_ptr = temp;
775 cur_rra_ptr = rrd->rra_ptr + rrd->stat_head->rra_cnt;
776 memset(cur_rra_ptr, '\0', sizeof(rra_ptr_t));
777 } /* }}} */
779 /* All space successfully allocated, increment number of RRAs. */
780 rrd->stat_head->rra_cnt++;
782 status = 0;
783 while ((element = get_xml_element(reader)) != NULL){
784 if (xmlStrcasecmp(element, (const xmlChar *) "cf") == 0)
785 status = parse_tag_rra_cf(reader, cur_rra_def);
786 else if (xmlStrcasecmp(element, (const xmlChar *) "pdp_per_row") == 0)
787 status = get_xml_ulong(reader,
788 &cur_rra_def->pdp_cnt);
789 else if (atoi(rrd->stat_head->version) == 1
790 && xmlStrcasecmp(element, (const xmlChar *) "xff") == 0)
791 status = get_xml_double(reader,
792 (double *) &cur_rra_def->
793 par[RRA_cdp_xff_val].u_val);
794 else if (atoi(rrd->stat_head->version) >= 2
795 && xmlStrcasecmp(element, (const xmlChar *) "params") == 0){
796 xmlFree(element);
797 status = parse_tag_rra_params(reader, cur_rra_def);
798 if (status == 0)
799 continue;
800 else
801 return status;
802 }
803 else if (xmlStrcasecmp(element, (const xmlChar *) "cdp_prep") == 0){
804 xmlFree(element);
805 status = parse_tag_rra_cdp_prep(reader, rrd, cur_cdp_prep);
806 if (status == 0)
807 continue;
808 else
809 return status;
810 }
811 else if (xmlStrcasecmp(element, (const xmlChar *) "database") == 0){
812 xmlFree(element);
813 status = parse_tag_rra_database(reader, rrd);
814 if (status == 0)
815 continue;
816 else
817 return status;
818 }
819 else if (xmlStrcasecmp(element,(const xmlChar *) "/rra") == 0){
820 xmlFree(element);
821 return status;
822 } /* }}} */
823 else {
824 rrd_set_error("line %d: parse_tag_rra: Unknown tag: %s",
825 xmlTextReaderGetParserLineNumber(reader), element);
826 status = -1;
827 }
828 if (status != 0) {
829 xmlFree(element);
830 return status;
831 }
832 status = expect_element_end(reader,(char *)element);
833 xmlFree(element);
834 if (status != 0) {
835 return status;
836 }
837 }
838 /* Set the RRA pointer to a random location */
839 cur_rra_ptr->cur_row = rrd_random() % cur_rra_def->row_cnt;
841 return (status);
842 } /* int parse_tag_rra */
844 /*
845 * Parse a DS definition
846 */
847 static int parse_tag_ds_cdef(
848 xmlTextReaderPtr reader,
849 rrd_t *rrd)
850 {
851 xmlChar *cdef;
853 cdef = get_xml_text(reader);
854 if (cdef != NULL){
855 /* We're always working on the last DS that has been added to the structure
856 * when we get here */
857 parseCDEF_DS((char *)cdef, rrd, rrd->stat_head->ds_cnt - 1);
858 xmlFree(cdef);
859 if (rrd_test_error())
860 return -1;
861 else
862 return 0;
863 }
864 return -1;
865 } /* int parse_tag_ds_cdef */
867 static int parse_tag_ds_type(
868 xmlTextReaderPtr reader,
869 ds_def_t *ds_def)
870 {
871 char *dst;
872 dst = (char *)get_xml_text(reader);
873 if (dst != NULL){
874 int status;
875 status = dst_conv(dst);
876 if (status == -1) {
877 rrd_set_error("parse_tag_ds_type: Unknown data source type: %s",
878 dst);
879 return -1;
880 }
881 strncpy(ds_def->dst,dst,sizeof(ds_def->dst)-1);
882 ds_def->dst[sizeof(ds_def->dst)-1] = '\0';
883 xmlFree(dst);
884 return 0;
885 }
886 return -1;
887 } /* int parse_tag_ds_type */
889 static int parse_tag_ds(
890 xmlTextReaderPtr reader,
891 rrd_t *rrd)
892 {
893 int status;
894 xmlChar *element;
896 ds_def_t *cur_ds_def;
897 pdp_prep_t *cur_pdp_prep;
899 /*
900 * If there are DS definitions after RRA definitions the number of values,
901 * cdp_prep areas and so on will be calculated wrong. Thus, enforce a
902 * specific order in this case.
903 */
904 if (rrd->stat_head->rra_cnt > 0) {
905 rrd_set_error("parse_tag_ds: All data source definitions MUST "
906 "precede the RRA definitions!");
907 return (-1);
908 }
910 /* Allocate space for the new DS definition */
911 { /* {{{ */
912 ds_def_t *temp;
914 temp = (ds_def_t *) realloc(rrd->ds_def,
915 sizeof(ds_def_t) *
916 (rrd->stat_head->ds_cnt + 1));
917 if (temp == NULL) {
918 rrd_set_error("parse_tag_ds: malloc failed.");
919 return (-1);
920 }
921 rrd->ds_def = temp;
922 cur_ds_def = rrd->ds_def + rrd->stat_head->ds_cnt;
923 memset(cur_ds_def, '\0', sizeof(ds_def_t));
924 } /* }}} */
926 /* Allocate pdp_prep space for the new DS definition */
927 { /* {{{ */
928 pdp_prep_t *temp;
930 temp = (pdp_prep_t *) realloc(rrd->pdp_prep,
931 sizeof(pdp_prep_t) *
932 (rrd->stat_head->ds_cnt + 1));
933 if (temp == NULL) {
934 rrd_set_error("parse_tag_ds: malloc failed.");
935 return (-1);
936 }
937 rrd->pdp_prep = temp;
938 cur_pdp_prep = rrd->pdp_prep + rrd->stat_head->ds_cnt;
939 memset(cur_pdp_prep, '\0', sizeof(pdp_prep_t));
940 } /* }}} */
942 /* All allocations successful, let's increment the number of DSes. */
943 rrd->stat_head->ds_cnt++;
945 status = 0;
946 while ((element = get_xml_element(reader)) != NULL){
947 if (xmlStrcasecmp(element, (const xmlChar *) "name") == 0){
948 status = get_xml_string(reader,cur_ds_def->ds_nam,sizeof(cur_ds_def->ds_nam));
949 }
950 else if (xmlStrcasecmp(element, (const xmlChar *) "type") == 0)
951 status = parse_tag_ds_type(reader, cur_ds_def);
952 else if (xmlStrcasecmp(element,
953 (const xmlChar *) "minimal_heartbeat") == 0)
954 status = get_xml_ulong(reader,
955 &cur_ds_def->par[DS_mrhb_cnt].
956 u_cnt);
957 else if (xmlStrcasecmp(element, (const xmlChar *) "min") == 0)
958 status = get_xml_double(reader,
959 &cur_ds_def->par[DS_min_val].u_val);
960 else if (xmlStrcasecmp(element, (const xmlChar *) "max") == 0)
961 status = get_xml_double(reader,
962 &cur_ds_def->par[DS_max_val].u_val);
963 else if (xmlStrcasecmp(element, (const xmlChar *) "cdef") == 0)
964 status = parse_tag_ds_cdef(reader, rrd);
965 else if (xmlStrcasecmp(element, (const xmlChar *) "last_ds") == 0)
966 status = get_xml_string(reader,
967 cur_pdp_prep->last_ds,
968 sizeof(cur_pdp_prep->last_ds));
969 else if (xmlStrcasecmp(element, (const xmlChar *) "value") == 0)
970 status = get_xml_double(reader,
971 &cur_pdp_prep->scratch[PDP_val].
972 u_val);
973 else if (xmlStrcasecmp(element, (const xmlChar *) "unknown_sec") == 0)
974 status = get_xml_ulong(reader,
975 &cur_pdp_prep->
976 scratch[PDP_unkn_sec_cnt].u_cnt);
977 else if (xmlStrcasecmp(element, (const xmlChar *) "/ds") == 0) {
978 xmlFree(element);
979 break;
980 }
981 else {
982 rrd_set_error("parse_tag_ds: Unknown tag: %s", element);
983 status = -1;
984 }
985 if (status != 0) {
986 xmlFree(element);
987 break;
988 }
989 status = expect_element_end(reader,(char *)element);
990 xmlFree(element);
991 if (status != 0)
992 break;
993 }
995 return (status);
996 } /* int parse_tag_ds */
998 /*
999 * Parse root nodes
1000 */
1001 static int parse_tag_rrd(
1002 xmlTextReaderPtr reader,
1003 rrd_t *rrd)
1004 {
1005 int status;
1006 xmlChar *element;
1008 status = 0;
1009 while ((element = get_xml_element(reader)) != NULL ){
1010 if (xmlStrcasecmp(element, (const xmlChar *) "version") == 0)
1011 status = get_xml_string(reader,
1012 rrd->stat_head->version,
1013 sizeof(rrd->stat_head->version));
1014 else if (xmlStrcasecmp(element, (const xmlChar *) "step") == 0)
1015 status = get_xml_ulong(reader,
1016 &rrd->stat_head->pdp_step);
1017 else if (xmlStrcasecmp(element, (const xmlChar *) "lastupdate") == 0) {
1018 #ifdef TIME_T_IS_LONG
1019 status = get_xml_long(reader, &rrd->live_head->last_up);
1020 #else
1021 #ifdef TIME_T_IS_LONG_LONG
1022 status = get_xml_llong(reader, &rrd->live_head->last_up);
1023 #else
1024 if (sizeof(time_t) == sizeof(long)) {
1025 status = get_xml_long(reader,
1026 (long *)&rrd->live_head->last_up);
1027 }
1028 else if (sizeof(time_t) == sizeof(long long)) {
1029 status = get_xml_llong(reader,
1030 (long long *)&rrd->live_head->last_up);
1031 }
1032 #endif
1033 #endif
1034 }
1035 else if (xmlStrcasecmp(element, (const xmlChar *) "ds") == 0){
1036 xmlFree(element);
1037 status = parse_tag_ds(reader, rrd);
1038 /* as we come back the </ds> tag is already gone */
1039 if (status == 0)
1040 continue;
1041 else
1042 return status;
1043 }
1044 else if (xmlStrcasecmp(element, (const xmlChar *) "rra") == 0){
1045 xmlFree(element);
1046 status = parse_tag_rra(reader, rrd);
1047 if (status == 0)
1048 continue;
1049 else
1050 return status;
1051 }
1052 else if (xmlStrcasecmp(element, (const xmlChar *) "/rrd") == 0) {
1053 xmlFree(element);
1054 return status;
1055 }
1056 else {
1057 rrd_set_error("parse_tag_rrd: Unknown tag: %s", element);
1058 status = -1;
1059 }
1061 if (status != 0){
1062 xmlFree(element);
1063 break;
1064 }
1065 status = expect_element_end(reader,(char *)element);
1066 xmlFree(element);
1067 if (status != 0)
1068 break;
1069 }
1070 return (status);
1071 } /* int parse_tag_rrd */
1073 static rrd_t *parse_file(
1074 const char *filename)
1075 {
1076 xmlTextReaderPtr reader;
1077 int status;
1079 rrd_t *rrd;
1081 reader = xmlNewTextReaderFilename(filename);
1082 if (reader == NULL) {
1083 rrd_set_error("Could not create xml reader for: %s",filename);
1084 return (NULL);
1085 }
1087 if (expect_element(reader,"rrd") != 0) {
1088 xmlFreeTextReader(reader);
1089 return (NULL);
1090 }
1092 rrd = (rrd_t *) malloc(sizeof(rrd_t));
1093 if (rrd == NULL) {
1094 rrd_set_error("parse_file: malloc failed.");
1095 xmlFreeTextReader(reader);
1096 return (NULL);
1097 }
1098 memset(rrd, '\0', sizeof(rrd_t));
1100 rrd->stat_head = (stat_head_t *) malloc(sizeof(stat_head_t));
1101 if (rrd->stat_head == NULL) {
1102 rrd_set_error("parse_tag_rrd: malloc failed.");
1103 xmlFreeTextReader(reader);
1104 free(rrd);
1105 return (NULL);
1106 }
1107 memset(rrd->stat_head, '\0', sizeof(stat_head_t));
1109 strncpy(rrd->stat_head->cookie, "RRD", sizeof(rrd->stat_head->cookie));
1110 rrd->stat_head->float_cookie = FLOAT_COOKIE;
1112 rrd->live_head = (live_head_t *) malloc(sizeof(live_head_t));
1113 if (rrd->live_head == NULL) {
1114 rrd_set_error("parse_tag_rrd: malloc failed.");
1115 xmlFreeTextReader(reader);
1116 free(rrd->stat_head);
1117 free(rrd);
1118 return (NULL);
1119 }
1120 memset(rrd->live_head, '\0', sizeof(live_head_t));
1122 status = parse_tag_rrd(reader, rrd);
1124 xmlFreeTextReader(reader);
1126 if (status != 0) {
1127 local_rrd_free(rrd);
1128 rrd = NULL;
1129 }
1131 return (rrd);
1132 } /* rrd_t *parse_file */
1134 static int write_file(
1135 const char *file_name,
1136 rrd_t *rrd)
1137 {
1138 FILE *fh;
1139 unsigned int i;
1140 unsigned int rra_offset;
1142 if (strcmp("-", file_name) == 0)
1143 fh = stdout;
1144 else {
1145 int fd_flags = O_WRONLY | O_CREAT;
1146 int fd;
1148 #if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
1149 fd_flags |= O_BINARY;
1150 #endif
1152 if (opt_force_overwrite == 0)
1153 fd_flags |= O_EXCL;
1155 fd = open(file_name, fd_flags, 0666);
1156 if (fd == -1) {
1157 rrd_set_error("creating '%s': %s", file_name,
1158 rrd_strerror(errno));
1159 return (-1);
1160 }
1162 fh = fdopen(fd, "wb");
1163 if (fh == NULL) {
1164 rrd_set_error("fdopen failed: %s", rrd_strerror(errno));
1165 close(fd);
1166 return (-1);
1167 }
1168 }
1169 if (atoi(rrd->stat_head->version) < 3) {
1170 /* we output 3 or higher */
1171 strcpy(rrd->stat_head->version, "0003");
1172 }
1173 fwrite(rrd->stat_head, sizeof(stat_head_t), 1, fh);
1174 fwrite(rrd->ds_def, sizeof(ds_def_t), rrd->stat_head->ds_cnt, fh);
1175 fwrite(rrd->rra_def, sizeof(rra_def_t), rrd->stat_head->rra_cnt, fh);
1176 fwrite(rrd->live_head, sizeof(live_head_t), 1, fh);
1177 fwrite(rrd->pdp_prep, sizeof(pdp_prep_t), rrd->stat_head->ds_cnt, fh);
1178 fwrite(rrd->cdp_prep, sizeof(cdp_prep_t),
1179 rrd->stat_head->rra_cnt * rrd->stat_head->ds_cnt, fh);
1180 fwrite(rrd->rra_ptr, sizeof(rra_ptr_t), rrd->stat_head->rra_cnt, fh);
1182 /* calculate the number of rrd_values to dump */
1183 rra_offset = 0;
1184 for (i = 0; i < rrd->stat_head->rra_cnt; i++) {
1185 unsigned long num_rows = rrd->rra_def[i].row_cnt;
1186 unsigned long cur_row = rrd->rra_ptr[i].cur_row;
1187 unsigned long ds_cnt = rrd->stat_head->ds_cnt;
1189 fwrite(rrd->rrd_value +
1190 (rra_offset + num_rows - 1 - cur_row) * ds_cnt,
1191 sizeof(rrd_value_t), (cur_row + 1) * ds_cnt, fh);
1193 fwrite(rrd->rrd_value + rra_offset * ds_cnt,
1194 sizeof(rrd_value_t), (num_rows - 1 - cur_row) * ds_cnt, fh);
1196 rra_offset += num_rows;
1197 }
1199 /* lets see if we had an error */
1200 if (ferror(fh)) {
1201 rrd_set_error("a file error occurred while creating '%s'", file_name);
1202 fclose(fh);
1203 return (-1);
1204 }
1206 fclose(fh);
1207 return (0);
1208 } /* int write_file */
1210 int rrd_restore(
1211 int argc,
1212 char **argv)
1213 {
1214 rrd_t *rrd;
1216 /* init rrd clean */
1217 optind = 0;
1218 opterr = 0; /* initialize getopt */
1219 while (42) {
1220 int opt;
1221 int option_index = 0;
1222 static struct option long_options[] = {
1223 {"range-check", no_argument, 0, 'r'},
1224 {"force-overwrite", no_argument, 0, 'f'},
1225 {0, 0, 0, 0}
1226 };
1228 opt = getopt_long(argc, argv, "rf", long_options, &option_index);
1230 if (opt == EOF)
1231 break;
1233 switch (opt) {
1234 case 'r':
1235 opt_range_check = 1;
1236 break;
1238 case 'f':
1239 opt_force_overwrite = 1;
1240 break;
1242 default:
1243 rrd_set_error("usage rrdtool %s [--range-check|-r] "
1244 "[--force-overwrite/-f] file.xml file.rrd",
1245 argv[0]);
1246 return (-1);
1247 break;
1248 }
1249 } /* while (42) */
1251 if ((argc - optind) != 2) {
1252 rrd_set_error("usage rrdtool %s [--range-check/-r] "
1253 "[--force-overwrite/-f] file.xml file.rrd", argv[0]);
1254 return (-1);
1255 }
1257 rrd = parse_file(argv[optind]);
1258 if (rrd == NULL)
1259 return (-1);
1261 if (write_file(argv[optind + 1], rrd) != 0) {
1262 local_rrd_free(rrd);
1263 return (-1);
1264 }
1265 local_rrd_free(rrd);
1268 return (0);
1269 } /* int rrd_restore */
1271 /* vim: set sw=2 sts=2 ts=8 et fdm=marker : */