prepare for the release of rrdtool-1.2.15
[rrdtool.git] / src / rrd_restore.c
1 /*****************************************************************************
2  * RRDtool 1.2.15  Copyright by Tobi Oetiker, 1997-2006
3  *****************************************************************************
4  * rrd_restore.c  creates new rrd from data dumped by rrd_dump.c
5  *****************************************************************************/
6
7 #include "rrd_tool.h"
8 #include "rrd_rpncalc.h"
9 #include <fcntl.h>
10
11 #if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
12 #include <io.h>
13 #define open _open
14 #define close _close
15 #endif
16
17 /* Prototypes */
18
19 void xml_lc(char*);
20 int skip(char **);
21 int skipxml(char **);
22 int eat_tag(char **, char *);
23 int read_tag(char **, char *, char *, void *);
24 int xml2rrd(char*, rrd_t*, char);
25 int rrd_write(char *, rrd_t *, char);
26 void parse_patch1028_RRA_params(char **buf, rrd_t *rrd, int rra_index);
27 void parse_patch1028_CDP_params(char **buf, rrd_t *rrd, int rra_index, int ds_index);
28 void parse_FAILURES_history(char **buf, rrd_t *rrd, int rra_index, int ds_index);
29
30 /* convert all occurrences of <BlaBlaBla> to <blablabla> */
31
32 void xml_lc(char* buf){
33   int intag=0;
34   while((*buf)){
35     if (intag ==0 && (*buf) == '<') {
36       intag = 1;
37     }
38     else if (intag ==1 && (*buf) == '>') {
39       intag = 0;
40       continue;
41     } else  if (intag ==1) {
42       *buf = tolower(*buf);
43     }
44     buf++;    
45   }
46 }
47
48 int skipxml(char **buf){
49   char *ptr;  
50   ptr=(*buf);
51   do {
52     (*buf)=ptr;
53     while((*(ptr+1)) && ((*ptr)==' ' ||  (*ptr)=='\r' || (*ptr)=='\n' || (*ptr)=='\t')) ptr++;
54     if (strncmp(ptr,"<?xml",4) == 0) {
55       ptr= strstr(ptr,"?>");
56       if (ptr) ptr+=2; else {
57         rrd_set_error("Dangling XML header");
58         (*buf) = NULL;
59         return -1;
60       }
61     }
62   } while ((*buf)!=ptr);  
63   return 1;
64 }
65
66 int skip(char **buf){
67   char *ptr;  
68   ptr=(*buf);
69   do {
70     (*buf)=ptr;
71     while((*(ptr+1)) && ((*ptr)==' ' ||  (*ptr)=='\r' || (*ptr)=='\n' || (*ptr)=='\t')) ptr++;
72     if (strncmp(ptr,"<!--",4) == 0) {
73       ptr= strstr(ptr,"-->");
74       if (ptr) ptr+=3; else {
75         rrd_set_error("Dangling Comment");
76         (*buf) = NULL;
77         return -1;
78       }
79     }
80   } while ((*buf)!=ptr);  
81   return 1;
82 }
83
84 int eat_tag(char **buf, char *tag){ 
85   if ((*buf)==NULL) return -1;   /* fall though clause */
86
87   rrd_clear_error();
88   skip(buf);
89   if ((**buf)=='<' 
90       && strncmp((*buf)+1,tag,strlen(tag)) == 0 
91       && *((*buf)+strlen(tag)+1)=='>') {
92     (*buf) += strlen(tag)+2;
93   }
94   else {
95     rrd_set_error("No <%s> tag found",tag);
96     (*buf) = NULL;
97     return -1;
98   }
99   skip(buf);
100   return 1;
101 }
102
103 int read_tag(char **buf, char *tag, char *format, void *value){
104     char *end_tag;
105     int matches;
106     if ((*buf)==NULL) return -1;   /* fall though clause */
107     rrd_clear_error();
108     if (eat_tag(buf,tag)==1){
109         char *temp;
110         temp = (*buf);
111         while(*((*buf)+1) && (*(*buf) != '<')) (*buf)++; /*find start of endtag*/
112         *(*buf) = '\0';
113         matches =sscanf(temp,format,value);
114         *(*buf) = '<';
115         end_tag = malloc((strlen(tag)+2)*sizeof(char));
116         sprintf(end_tag,"/%s",tag);
117         eat_tag(buf,end_tag);
118         free(end_tag);
119         if (matches == 0 && strcmp(format,"%lf") == 0)
120             (*((double* )(value))) = DNAN;
121         if (matches != 1)       return 0;       
122         return 1;
123     }
124     return -1;
125 }
126
127
128 /* parse the data stored in buf and return a filled rrd structure */
129 int xml2rrd(char* buf, rrd_t* rrd, char rc){
130   /* pass 1 identify number of RRAs  */
131   char *ptr,*ptr2,*ptr3; /* walks thought the buffer */
132   long rows=0,mempool=0,i=0;
133   int rra_index;
134   int input_version;
135   xml_lc(buf); /* lets lowercase all active parts of the xml */
136   ptr=buf;
137   ptr2=buf;
138   ptr3=buf;
139   /* start with an RRD tag */
140   
141   skipxml(&ptr);
142
143   eat_tag(&ptr,"rrd");
144   /* allocate static header */
145   if((rrd->stat_head = calloc(1,sizeof(stat_head_t)))==NULL){
146     rrd_set_error("allocating rrd.stat_head");
147     return -1;    
148   };
149
150   strcpy(rrd->stat_head->cookie,RRD_COOKIE);
151   read_tag(&ptr,"version","%4[0-9]",rrd->stat_head->version);
152   input_version = atoi(rrd->stat_head->version);
153   /* added primitive version checking */
154   if (input_version > atoi(RRD_VERSION) || input_version < 1)
155   {
156     rrd_set_error("Incompatible file version, detected version %s. This is not supported by the version %s restore tool.\n",
157                   rrd -> stat_head -> version, RRD_VERSION );
158     free(rrd -> stat_head); 
159     rrd->stat_head = NULL; 
160     return -1;
161   }
162   /* make sure we output the right version */
163   strcpy(rrd->stat_head->version,RRD_VERSION);
164
165   /*  if (atoi(rrd -> stat_head -> version) < 2) 
166   {
167     rrd_set_error("Can only restore version >= 2 (Not %s). Dump your old rrd using a current rrdtool dump.",  rrd -> stat_head -> version );
168     return -1;
169   } */
170
171   rrd->stat_head->float_cookie = FLOAT_COOKIE;
172   rrd->stat_head->ds_cnt = 0;
173   rrd->stat_head->rra_cnt = 0;
174   read_tag(&ptr,"step","%lu",&(rrd->stat_head->pdp_step));
175
176   /* allocate live head */
177   if((rrd->live_head = calloc(1,sizeof(live_head_t)))==NULL){
178     rrd_set_error("allocating rrd.live_head");
179     return -1;    
180   }
181   read_tag(&ptr,"lastupdate","%lu",&(rrd->live_head->last_up));
182
183   /* Data Source Definition Part */
184   ptr2 = ptr;
185   while (eat_tag(&ptr2,"ds") == 1){
186       rrd->stat_head->ds_cnt++;
187       if((rrd->ds_def = rrd_realloc(rrd->ds_def,rrd->stat_head->ds_cnt*sizeof(ds_def_t)))==NULL){
188           rrd_set_error("allocating rrd.ds_def");
189           return -1;
190       };
191       /* clean out memory to make sure no data gets stored from previous tasks */
192       memset(&(rrd->ds_def[rrd->stat_head->ds_cnt-1]), 0, sizeof(ds_def_t));
193       if((rrd->pdp_prep = rrd_realloc(rrd->pdp_prep,rrd->stat_head->ds_cnt
194                                   *sizeof(pdp_prep_t)))==NULL){
195         rrd_set_error("allocating pdp_prep");
196         return(-1);
197       }
198       /* clean out memory to make sure no data gets stored from previous tasks */
199       memset(&(rrd->pdp_prep[rrd->stat_head->ds_cnt-1]), 0, sizeof(pdp_prep_t));
200
201       read_tag(&ptr2,"name",DS_NAM_FMT,rrd->ds_def[rrd->stat_head->ds_cnt-1].ds_nam);
202
203       read_tag(&ptr2,"type",DST_FMT,rrd->ds_def[rrd->stat_head->ds_cnt-1].dst);
204       /* test for valid type */
205       if( (int)dst_conv(rrd->ds_def[rrd->stat_head->ds_cnt-1].dst) == -1) return -1;      
206
207           if (dst_conv(rrd->ds_def[rrd->stat_head->ds_cnt-1].dst) != DST_CDEF)
208           {
209       read_tag(&ptr2,"minimal_heartbeat","%lu",
210                &(rrd->ds_def[rrd->stat_head->ds_cnt-1].par[DS_mrhb_cnt].u_cnt));
211       read_tag(&ptr2,"min","%lf",&(rrd->ds_def[rrd->stat_head->ds_cnt-1].par[DS_min_val].u_val));
212       read_tag(&ptr2,"max","%lf",&(rrd->ds_def[rrd->stat_head->ds_cnt-1].par[DS_max_val].u_val));
213           } else { /* DST_CDEF */
214                  char buffer[1024];
215                  read_tag(&ptr2,"cdef","%1000s",buffer);
216                  parseCDEF_DS(buffer,rrd,rrd -> stat_head -> ds_cnt - 1);
217                  if (rrd_test_error()) return -1;
218           }
219
220       read_tag(&ptr2,"last_ds","%30s",rrd->pdp_prep[rrd->stat_head->ds_cnt-1].last_ds);
221       read_tag(&ptr2,"value","%lf",&(rrd->pdp_prep[rrd->stat_head->ds_cnt-1].scratch[PDP_val].u_val));
222       read_tag(&ptr2,"unknown_sec","%lu",&(rrd->pdp_prep[rrd->stat_head->ds_cnt-1].scratch[PDP_unkn_sec_cnt].u_cnt));      
223       eat_tag(&ptr2,"/ds");
224       ptr=ptr2;
225   }
226   
227   ptr2 = ptr;
228   while (eat_tag(&ptr2,"rra") == 1){
229       rrd->stat_head->rra_cnt++;
230
231       /* allocate and reset rra definition areas */
232       if((rrd->rra_def = rrd_realloc(rrd->rra_def,rrd->stat_head->rra_cnt*sizeof(rra_def_t)))==NULL){
233           rrd_set_error("allocating rra_def"); return -1; }      
234       memset(&(rrd->rra_def[rrd->stat_head->rra_cnt-1]), 0, sizeof(rra_def_t));
235
236       /* allocate and reset consolidation point areas */
237       if((rrd->cdp_prep = rrd_realloc(rrd->cdp_prep,
238                                   rrd->stat_head->rra_cnt
239                                   *rrd->stat_head->ds_cnt*sizeof(cdp_prep_t)))==NULL){
240           rrd_set_error("allocating cdp_prep"); return -1; }
241
242       memset(&(rrd->cdp_prep[rrd->stat_head->ds_cnt*(rrd->stat_head->rra_cnt-1)]), 
243              0, rrd->stat_head->ds_cnt*sizeof(cdp_prep_t));
244
245       
246       read_tag(&ptr2,"cf",CF_NAM_FMT,rrd->rra_def[rrd->stat_head->rra_cnt-1].cf_nam);
247       /* test for valid type */
248       if( (int)cf_conv(rrd->rra_def[rrd->stat_head->rra_cnt-1].cf_nam) == -1) return -1;
249
250       read_tag(&ptr2,"pdp_per_row","%lu",&(rrd->rra_def[rrd->stat_head->rra_cnt-1].pdp_cnt));
251       /* support to read RRA parameters */
252       rra_index = rrd->stat_head->rra_cnt - 1;
253       if ( input_version < 2 ){
254          read_tag(&ptr2, "xff","%lf",
255             &(rrd->rra_def[rra_index].par[RRA_cdp_xff_val].u_val));
256       } else {
257         eat_tag(&ptr2, "params");
258         skip(&ptr2);
259         /* backwards compatibility w/ old patch */
260       if (strncmp(ptr2, "<value>",7) == 0) {
261           parse_patch1028_RRA_params(&ptr2,rrd,rra_index); 
262       } else {
263       switch(cf_conv(rrd -> rra_def[rra_index].cf_nam)) {
264       case CF_HWPREDICT:
265          read_tag(&ptr2, "hw_alpha", "%lf", 
266             &(rrd->rra_def[rra_index].par[RRA_hw_alpha].u_val));
267          read_tag(&ptr2, "hw_beta", "%lf", 
268             &(rrd->rra_def[rra_index].par[RRA_hw_beta].u_val));
269          read_tag(&ptr2, "dependent_rra_idx", "%lu", 
270             &(rrd->rra_def[rra_index].par[RRA_dependent_rra_idx].u_cnt));
271          break;
272       case CF_SEASONAL:
273       case CF_DEVSEASONAL:
274          read_tag(&ptr2, "seasonal_gamma", "%lf", 
275             &(rrd->rra_def[rra_index].par[RRA_seasonal_gamma].u_val));
276          read_tag(&ptr2, "seasonal_smooth_idx", "%lu", 
277             &(rrd->rra_def[rra_index].par[RRA_seasonal_smooth_idx].u_cnt));
278          read_tag(&ptr2, "dependent_rra_idx", "%lu", 
279             &(rrd->rra_def[rra_index].par[RRA_dependent_rra_idx].u_cnt));
280          break;
281       case CF_FAILURES:
282          read_tag(&ptr2, "delta_pos", "%lf", 
283             &(rrd->rra_def[rra_index].par[RRA_delta_pos].u_val));
284          read_tag(&ptr2, "delta_neg", "%lf", 
285             &(rrd->rra_def[rra_index].par[RRA_delta_neg].u_val));
286          read_tag(&ptr2, "window_len", "%lu", 
287             &(rrd->rra_def[rra_index].par[RRA_window_len].u_cnt));
288          read_tag(&ptr2, "failure_threshold", "%lu", 
289             &(rrd->rra_def[rra_index].par[RRA_failure_threshold].u_cnt));
290          /* fall thru */
291       case CF_DEVPREDICT:
292          read_tag(&ptr2, "dependent_rra_idx", "%lu", 
293             &(rrd->rra_def[rra_index].par[RRA_dependent_rra_idx].u_cnt));
294          break;
295       case CF_AVERAGE:
296       case CF_MAXIMUM:
297       case CF_MINIMUM:
298       case CF_LAST:
299       default:
300          read_tag(&ptr2, "xff","%lf",
301             &(rrd->rra_def[rra_index].par[RRA_cdp_xff_val].u_val));
302       }
303       }
304       eat_tag(&ptr2, "/params");
305    }
306
307
308       eat_tag(&ptr2,"cdp_prep");
309       for(i=0;i< (int)rrd->stat_head->ds_cnt;i++)
310       {
311       eat_tag(&ptr2,"ds");
312       /* support to read CDP parameters */
313       rra_index = rrd->stat_head->rra_cnt-1; 
314       skip(&ptr2);
315       if ( input_version < 2 ){
316           rrd->cdp_prep[rrd->stat_head->ds_cnt*(rra_index)+i].scratch[CDP_primary_val].u_val = 0.0;
317           rrd->cdp_prep[rrd->stat_head->ds_cnt*(rra_index)+i].scratch[CDP_secondary_val].u_val = 0.0;
318           read_tag(&ptr2,"value","%lf",&(rrd->cdp_prep[rrd->stat_head->ds_cnt
319                *(rra_index) +i].scratch[CDP_val].u_val));
320           read_tag(&ptr2,"unknown_datapoints","%lu",&(rrd->cdp_prep[rrd->stat_head->ds_cnt
321               *(rra_index) +i].scratch[CDP_unkn_pdp_cnt].u_cnt));
322       } else {
323
324       if (strncmp(ptr2, "<value>",7) == 0) {
325          parse_patch1028_CDP_params(&ptr2,rrd,rra_index,i);
326       } else {
327          read_tag(&ptr2, "primary_value","%lf",
328                &(rrd->cdp_prep[rrd->stat_head->ds_cnt*(rra_index)
329                +i].scratch[CDP_primary_val].u_val));
330          read_tag(&ptr2, "secondary_value","%lf",
331                &(rrd->cdp_prep[rrd->stat_head->ds_cnt*(rra_index)
332                +i].scratch[CDP_secondary_val].u_val));
333          switch(cf_conv(rrd->rra_def[rra_index].cf_nam)) {
334          case CF_HWPREDICT:
335             read_tag(&ptr2,"intercept","%lf", 
336                &(rrd->cdp_prep[rrd->stat_head->ds_cnt*(rra_index)
337                +i].scratch[CDP_hw_intercept].u_val));
338             read_tag(&ptr2,"last_intercept","%lf", 
339                &(rrd->cdp_prep[rrd->stat_head->ds_cnt*(rra_index)
340                +i].scratch[CDP_hw_last_intercept].u_val));
341             read_tag(&ptr2,"slope","%lf", 
342                &(rrd->cdp_prep[rrd->stat_head->ds_cnt*(rra_index)
343                +i].scratch[CDP_hw_slope].u_val));
344             read_tag(&ptr2,"last_slope","%lf", 
345                &(rrd->cdp_prep[rrd->stat_head->ds_cnt*(rra_index)
346                +i].scratch[CDP_hw_last_slope].u_val));
347             read_tag(&ptr2,"nan_count","%lu", 
348                &(rrd->cdp_prep[rrd->stat_head->ds_cnt*(rra_index)
349                +i].scratch[CDP_null_count].u_cnt));
350             read_tag(&ptr2,"last_nan_count","%lu", 
351                &(rrd->cdp_prep[rrd->stat_head->ds_cnt*(rra_index)
352                +i].scratch[CDP_last_null_count].u_cnt));
353             break;
354          case CF_SEASONAL:
355          case CF_DEVSEASONAL:
356             read_tag(&ptr2,"seasonal","%lf", 
357                &(rrd->cdp_prep[rrd->stat_head->ds_cnt*(rra_index)
358                +i].scratch[CDP_hw_seasonal].u_val));
359             read_tag(&ptr2,"last_seasonal","%lf", 
360                &(rrd->cdp_prep[rrd->stat_head->ds_cnt*(rra_index)
361                +i].scratch[CDP_hw_last_seasonal].u_val));
362             read_tag(&ptr2,"init_flag","%lu", 
363                &(rrd->cdp_prep[rrd->stat_head->ds_cnt*(rra_index)
364                +i].scratch[CDP_init_seasonal].u_cnt));
365             break;
366          case CF_DEVPREDICT:
367             break;
368          case CF_FAILURES:
369             parse_FAILURES_history(&ptr2,rrd,rra_index,i); 
370             break;
371          case CF_AVERAGE:
372          case CF_MAXIMUM:
373          case CF_MINIMUM:
374          case CF_LAST:
375          default:
376             read_tag(&ptr2,"value","%lf",&(rrd->cdp_prep[rrd->stat_head->ds_cnt
377                *(rra_index) +i].scratch[CDP_val].u_val));
378             read_tag(&ptr2,"unknown_datapoints","%lu",&(rrd->cdp_prep[rrd->stat_head->ds_cnt
379                *(rra_index) +i].scratch[CDP_unkn_pdp_cnt].u_cnt));
380             break;
381          }
382       }
383       }
384       eat_tag(&ptr2,"/ds");
385       }
386       eat_tag(&ptr2,"/cdp_prep");
387       rrd->rra_def[rrd->stat_head->rra_cnt-1].row_cnt=0;
388       eat_tag(&ptr2,"database");
389       ptr3 = ptr2;      
390       while (eat_tag(&ptr3,"row") == 1){
391         
392           if(mempool==0){
393             mempool = 1000;
394             if((rrd->rrd_value = rrd_realloc(rrd->rrd_value,
395                                          (rows+mempool)*(rrd->stat_head->ds_cnt)
396                                          *sizeof(rrd_value_t)))==NULL) {
397               rrd_set_error("allocating rrd_values"); return -1; }
398           }
399           rows++;
400           mempool--;
401           rrd->rra_def[rrd->stat_head->rra_cnt-1].row_cnt++;
402           for(i=0;i< (int)rrd->stat_head->ds_cnt;i++){
403
404                   rrd_value_t  * value = &(rrd->rrd_value[(rows-1)*rrd->stat_head->ds_cnt+i]);
405
406                   read_tag(&ptr3,"v","%lf", value);
407                   
408                   if (
409                           (rc == 1)                     /* do we have to check for the ranges */
410                           &&
411                       (!isnan(*value))  /* not a NAN value */
412                       &&
413                           (dst_conv(rrd->ds_def[i].dst) != DST_CDEF)
414                           &&
415                       (                                 /* min defined and in the range ? */
416                           (!isnan(rrd->ds_def[i].par[DS_min_val].u_val) 
417                                 && (*value < rrd->ds_def[i].par[DS_min_val].u_val)) 
418                           ||                            /* max defined and in the range ? */
419                           (!isnan(rrd->ds_def[i].par[DS_max_val].u_val) 
420                                 && (*value > rrd->ds_def[i].par[DS_max_val].u_val))
421                       )
422                   ) {
423                       fprintf (stderr, "out of range found [ds: %lu], [value : %0.10e]\n", i, *value);
424                       *value = DNAN;
425                   }
426           }
427           eat_tag(&ptr3,"/row");                  
428           ptr2=ptr3;
429       }
430       eat_tag(&ptr2,"/database");
431       eat_tag(&ptr2,"/rra");                  
432       ptr=ptr2;
433   }  
434   eat_tag(&ptr,"/rrd");
435
436   if((rrd->rra_ptr = calloc(1,sizeof(rra_ptr_t)*rrd->stat_head->rra_cnt)) == NULL) {
437       rrd_set_error("allocating rra_ptr");
438       return(-1);
439   }
440
441   for(i=0; i < (int)rrd->stat_head->rra_cnt; i++) {
442           /* last row in the xml file is the most recent; as
443            * rrd_update increments the current row pointer, set cur_row
444            * here to the last row. */
445       rrd->rra_ptr[i].cur_row = rrd->rra_def[i].row_cnt-1;
446   }
447   if (ptr==NULL)
448       return -1;
449   return 1;
450 }
451   
452     
453
454
455
456 /* create and empty rrd file according to the specs given */
457
458 int
459 rrd_write(char *file_name, rrd_t *rrd, char force_overwrite)
460 {
461     unsigned long    i,ii,val_cnt;
462     FILE             *rrd_file=NULL;
463     int                 fdflags;
464     int                 fd;
465
466     if (strcmp("-",file_name)==0){
467       rrd_file= stdout;
468     } else {
469 #if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
470       fdflags = O_RDWR|O_BINARY|O_CREAT;
471 #else
472       fdflags = O_WRONLY|O_CREAT;
473 #endif            
474       if (force_overwrite == 0) {
475         fdflags |= O_EXCL;
476       }
477       fd = open(file_name,fdflags,0666);
478       if (fd == -1 || (rrd_file = fdopen(fd,"wb")) == NULL) {
479         rrd_set_error("creating '%s': %s",file_name,rrd_strerror(errno));
480         if (fd != -1)
481           close(fd);
482         return(-1);
483       }
484     }
485     fwrite(rrd->stat_head,
486            sizeof(stat_head_t), 1, rrd_file);
487
488     fwrite(rrd->ds_def,
489            sizeof(ds_def_t), rrd->stat_head->ds_cnt, rrd_file);
490
491     fwrite(rrd->rra_def,
492            sizeof(rra_def_t), rrd->stat_head->rra_cnt, rrd_file);
493
494     fwrite(rrd->live_head, sizeof(live_head_t),1, rrd_file);
495
496     fwrite( rrd->pdp_prep, sizeof(pdp_prep_t),rrd->stat_head->ds_cnt,rrd_file);
497     
498     fwrite( rrd->cdp_prep, sizeof(cdp_prep_t),rrd->stat_head->rra_cnt*
499             rrd->stat_head->ds_cnt,rrd_file);
500     fwrite( rrd->rra_ptr, sizeof(rra_ptr_t), rrd->stat_head->rra_cnt,rrd_file);
501
502
503
504     /* calculate the number of rrd_values to dump */
505     val_cnt=0;
506     for(i=0; i <  rrd->stat_head->rra_cnt; i++)
507         for(ii=0; ii <  rrd->rra_def[i].row_cnt * rrd->stat_head->ds_cnt;ii++)
508             val_cnt++;
509     fwrite( rrd->rrd_value, sizeof(rrd_value_t),val_cnt,rrd_file);
510
511     /* lets see if we had an error */
512     if(ferror(rrd_file)){
513         rrd_set_error("a file error occurred while creating '%s'",file_name);
514         fclose(rrd_file);       
515         return(-1);
516     }
517     
518     fclose(rrd_file);    
519     return 0;
520 }
521
522
523 int
524 rrd_restore(int argc, char **argv) 
525 {
526     rrd_t          rrd;
527     char          *buf;
528         char                    rc = 0;
529         char                    force_overwrite = 0;    
530
531     /* init rrd clean */
532     optind = 0; opterr = 0;  /* initialize getopt */
533         while (1) {
534                 static struct option long_options[] =
535                 {
536                         {"range-check",      no_argument, 0,  'r'},
537                         {"force-overwrite",  no_argument, 0,  'f'},
538                         {0,0,0,0}
539                 };
540                 int option_index = 0;
541                 int opt;
542                 
543                 
544                 opt = getopt_long(argc, argv, "rf", long_options, &option_index);
545                 
546                 if (opt == EOF)
547                         break;
548                 
549                 switch(opt) {
550                 case 'r':
551                         rc=1;
552                         break;
553                 case 'f':
554                         force_overwrite=1;
555                         break;
556                 default:
557                         rrd_set_error("usage rrdtool %s [--range-check|-r] [--force-overwrite/-f]  file.xml file.rrd",argv[0]);
558                         return -1;
559                         break;
560                 }
561     }
562
563     if (argc-optind != 2) {
564                 rrd_set_error("usage rrdtool %s [--range-check/-r] [--force-overwrite/-f] file.xml file.rrd",argv[0]);
565                 return -1;
566     }
567         
568     if (readfile(argv[optind],&buf,0)==-1){
569       return -1;
570     }
571
572     rrd_init(&rrd);
573
574     if (xml2rrd(buf,&rrd,rc)==-1) {
575         rrd_free(&rrd);
576         free(buf);
577         return -1;
578     }
579
580     free(buf);
581
582     if(rrd_write(argv[optind+1],&rrd,force_overwrite)==-1){
583         rrd_free(&rrd); 
584         return -1;      
585     };
586     rrd_free(&rrd);    
587     return 0;
588 }
589
590 /* a backwards compatibility routine that will parse the RRA params section
591  * generated by the aberrant patch to 1.0.28. */
592
593 void
594 parse_patch1028_RRA_params(char **buf, rrd_t *rrd, int rra_index)
595 {
596    int i;
597    for (i = 0; i < MAX_RRA_PAR_EN; i++)
598    {
599    if (i == RRA_dependent_rra_idx ||
600        i == RRA_seasonal_smooth_idx ||
601        i == RRA_failure_threshold)
602       read_tag(buf, "value","%lu",
603          &(rrd->rra_def[rra_index].par[i].u_cnt));
604    else
605       read_tag(buf, "value","%lf",
606          &(rrd->rra_def[rra_index].par[i].u_val));
607    }
608 }
609
610 /* a backwards compatibility routine that will parse the CDP params section
611  * generated by the aberrant patch to 1.0.28. */
612 void
613 parse_patch1028_CDP_params(char **buf, rrd_t *rrd, int rra_index, int ds_index)
614 {
615    int ii;
616    for (ii = 0; ii < MAX_CDP_PAR_EN; ii++)
617    {
618    if (cf_conv(rrd->rra_def[rra_index].cf_nam) == CF_FAILURES ||
619        ii == CDP_unkn_pdp_cnt ||
620        ii == CDP_null_count ||
621        ii == CDP_last_null_count)
622    {
623       read_tag(buf,"value","%lu",
624        &(rrd->cdp_prep[rrd->stat_head->ds_cnt*(rra_index) + ds_index].scratch[ii].u_cnt));
625    } else {
626       read_tag(buf,"value","%lf",&(rrd->cdp_prep[rrd->stat_head->ds_cnt*
627        (rra_index) + ds_index].scratch[ii].u_val));
628    }
629    }
630 }
631
632 void
633 parse_FAILURES_history(char **buf, rrd_t *rrd, int rra_index, int ds_index)
634 {
635    char history[MAX_FAILURES_WINDOW_LEN + 1];
636    char *violations_array;
637    unsigned short i;
638
639    /* 28 = MAX_FAILURES_WINDOW_LEN */ 
640    read_tag(buf, "history", "%28[0-1]", history);
641    violations_array = (char*) rrd -> cdp_prep[rrd->stat_head->ds_cnt*(rra_index)
642       + ds_index].scratch;
643    
644    for (i = 0; i < rrd -> rra_def[rra_index].par[RRA_window_len].u_cnt; ++i)
645       violations_array[i] = (history[i] == '1') ? 1 : 0;
646
647 }