Code

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