fix indents gone out of kileter by patching ...
[rrdtool.git] / src / rrd_restore.c
1 /*****************************************************************************
2  * RRDtool 1.2.99907080300  Copyright by Tobi Oetiker, 1997-2007
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(
20     char *);
21 int       skip(
22     char **);
23 int       skipxml(
24     char **);
25 int       eat_tag(
26     char **,
27     char *);
28 int       read_tag(
29     char **,
30     char *,
31     char *,
32     void *);
33 int       xml2rrd(
34     char *,
35     rrd_t *,
36     char);
37 int       rrd_creat(
38     char *,
39     rrd_t *,
40     char);
41 void      parse_patch1028_RRA_params(
42     char **buf,
43     rrd_t *rrd,
44     int rra_index);
45 void      parse_patch1028_CDP_params(
46     char **buf,
47     rrd_t *rrd,
48     int rra_index,
49     int ds_index);
50 void      parse_FAILURES_history(
51     char **buf,
52     rrd_t *rrd,
53     int rra_index,
54     int ds_index);
55 long int  rra_random_row(
56     rra_def_t *);
57
58 /* convert all occurrences of <BlaBlaBla> to <blablabla> */
59
60 void xml_lc(
61     char *buf)
62 {
63     int       intag = 0;
64
65     while ((*buf)) {
66         if (intag == 0 && (*buf) == '<') {
67             intag = 1;
68         } else if (intag == 1 && (*buf) == '>') {
69             intag = 0;
70             continue;
71         } else if (intag == 1) {
72             *buf = tolower(*buf);
73         }
74         buf++;
75     }
76 }
77
78 int skipxml(
79     char **buf)
80 {
81     char     *ptr;
82
83     ptr = (*buf);
84     do {
85         (*buf) = ptr;
86         while ((*(ptr + 1))
87                && ((*ptr) == ' ' || (*ptr) == '\r' || (*ptr) == '\n'
88                    || (*ptr) == '\t'))
89             ptr++;
90         if (strncmp(ptr, "<?xml", 4) == 0) {
91             ptr = strstr(ptr, "?>");
92             if (ptr)
93                 ptr += 2;
94             else {
95                 rrd_set_error("Dangling XML header");
96                 (*buf) = NULL;
97                 return -1;
98             }
99         }
100     } while ((*buf) != ptr);
101     return 1;
102 }
103
104 int skip(
105     char **buf)
106 {
107     char     *ptr;
108
109     if ((buf == NULL) || (*buf == NULL))
110         return -1;
111     ptr = (*buf);
112     do {
113         (*buf) = ptr;
114         while ((*(ptr + 1))
115                && ((*ptr) == ' ' || (*ptr) == '\r' || (*ptr) == '\n'
116                    || (*ptr) == '\t'))
117             ptr++;
118         if (strncmp(ptr, "<!--", 4) == 0) {
119             ptr = strstr(ptr, "-->");
120             if (ptr)
121                 ptr += 3;
122             else {
123                 rrd_set_error("Dangling Comment");
124                 (*buf) = NULL;
125                 return -1;
126             }
127         }
128     } while ((*buf) != ptr);
129     return 1;
130 }
131
132 int eat_tag(
133     char **buf,
134     char *tag)
135 {
136     if ((*buf) == NULL)
137         return -1;      /* fall though clause */
138
139     rrd_clear_error();
140     skip(buf);
141     if ((**buf) == '<'
142         && strncmp((*buf) + 1, tag, strlen(tag)) == 0
143         && *((*buf) + strlen(tag) + 1) == '>') {
144         (*buf) += strlen(tag) + 2;
145     } else {
146         rrd_set_error("No <%s> tag found", tag);
147         (*buf) = NULL;
148         return -1;
149     }
150     skip(buf);
151     return 1;
152 }
153
154 int read_tag(
155     char **buf,
156     char *tag,
157     char *format,
158     void *value)
159 {
160     char     *end_tag;
161     int       matches;
162
163     if ((*buf) == NULL)
164         return -1;      /* fall though clause */
165     rrd_clear_error();
166     if (eat_tag(buf, tag) == 1) {
167         char     *temp;
168
169         temp = (*buf);
170         while (*((*buf) + 1) && (*(*buf) != '<'))
171             (*buf)++;   /*find start of endtag */
172         *(*buf) = '\0';
173         matches = sscanf(temp, format, value);
174         *(*buf) = '<';
175         end_tag = malloc((strlen(tag) + 2) * sizeof(char));
176         sprintf(end_tag, "/%s", tag);
177         eat_tag(buf, end_tag);
178         free(end_tag);
179         if (matches == 0 && strcmp(format, "%lf") == 0)
180             (*((double *) (value))) = DNAN;
181         if (matches != 1)
182             return 0;
183         return 1;
184     }
185     return -1;
186 }
187
188
189 /* parse the data stored in buf and return a filled rrd structure */
190 int xml2rrd(
191     char *buf,
192     rrd_t *rrd,
193     char rc)
194 {
195     /* pass 1 identify number of RRAs  */
196     char     *ptr, *ptr2, *ptr3;    /* walks thought the buffer */
197     long      rows = 0, mempool = 0, i = 0;
198     int       rra_index;
199     int       input_version;
200
201     xml_lc(buf);        /* lets lowercase all active parts of the xml */
202     ptr = buf;
203     ptr2 = buf;
204     ptr3 = buf;
205     /* start with an RRD tag */
206
207     skipxml(&ptr);
208
209     eat_tag(&ptr, "rrd");
210     /* allocate static header */
211     if ((rrd->stat_head = calloc(1, sizeof(stat_head_t))) == NULL) {
212         rrd_set_error("allocating rrd.stat_head");
213         return -1;
214     };
215
216     strcpy(rrd->stat_head->cookie, RRD_COOKIE);
217     read_tag(&ptr, "version", "%4[0-9]", rrd->stat_head->version);
218     input_version = atoi(rrd->stat_head->version);
219     /* added primitive version checking */
220     if (input_version > atoi(RRD_VERSION) || input_version < 1) {
221         rrd_set_error
222             ("Incompatible file version, detected version %s. This is not supported by the version %s restore tool.\n",
223              rrd->stat_head->version, RRD_VERSION);
224         free(rrd->stat_head);
225         rrd->stat_head = NULL;
226         return -1;
227     }
228     /* make sure we output the right version only go over 3 if input is over 3 too */
229     if (input_version > 3) {
230         strcpy(rrd->stat_head->version, RRD_VERSION);
231     } else {
232         strcpy(rrd->stat_head->version, RRD_VERSION3);
233     }
234
235     rrd->stat_head->float_cookie = FLOAT_COOKIE;
236     rrd->stat_head->ds_cnt = 0;
237     rrd->stat_head->rra_cnt = 0;
238     read_tag(&ptr, "step", "%lu", &(rrd->stat_head->pdp_step));
239
240     /* allocate live head */
241     if ((rrd->live_head = calloc(1, sizeof(live_head_t))) == NULL) {
242         rrd_set_error("allocating rrd.live_head");
243         return -1;
244     }
245     read_tag(&ptr, "lastupdate", "%lu", &(rrd->live_head->last_up));
246
247     /* Data Source Definition Part */
248     ptr2 = ptr;
249     while (eat_tag(&ptr2, "ds") == 1) {
250         rrd->stat_head->ds_cnt++;
251         if ((rrd->ds_def =
252              rrd_realloc(rrd->ds_def,
253                          rrd->stat_head->ds_cnt * sizeof(ds_def_t))) ==
254             NULL) {
255             rrd_set_error("allocating rrd.ds_def");
256             return -1;
257         };
258         /* clean out memory to make sure no data gets stored from previous tasks */
259         memset(&(rrd->ds_def[rrd->stat_head->ds_cnt - 1]), 0,
260                sizeof(ds_def_t));
261         if ((rrd->pdp_prep =
262              rrd_realloc(rrd->pdp_prep,
263                          rrd->stat_head->ds_cnt * sizeof(pdp_prep_t))) ==
264             NULL) {
265             rrd_set_error("allocating pdp_prep");
266             return (-1);
267         }
268         /* clean out memory to make sure no data gets stored from previous tasks */
269         memset(&(rrd->pdp_prep[rrd->stat_head->ds_cnt - 1]), 0,
270                sizeof(pdp_prep_t));
271
272         read_tag(&ptr2, "name", DS_NAM_FMT,
273                  rrd->ds_def[rrd->stat_head->ds_cnt - 1].ds_nam);
274
275         read_tag(&ptr2, "type", DST_FMT,
276                  rrd->ds_def[rrd->stat_head->ds_cnt - 1].dst);
277         /* test for valid type */
278         if ((int) dst_conv(rrd->ds_def[rrd->stat_head->ds_cnt - 1].dst) == -1)
279             return -1;
280
281         if (dst_conv(rrd->ds_def[rrd->stat_head->ds_cnt - 1].dst) != DST_CDEF) {
282             read_tag(&ptr2, "minimal_heartbeat", "%lu",
283                      &(rrd->ds_def[rrd->stat_head->ds_cnt - 1].
284                        par[DS_mrhb_cnt].u_cnt));
285             read_tag(&ptr2, "min", "%lf",
286                      &(rrd->ds_def[rrd->stat_head->ds_cnt - 1].
287                        par[DS_min_val].u_val));
288             read_tag(&ptr2, "max", "%lf",
289                      &(rrd->ds_def[rrd->stat_head->ds_cnt - 1].
290                        par[DS_max_val].u_val));
291         } else {        /* DST_CDEF */
292             char      buffer[1024];
293
294             read_tag(&ptr2, "cdef", "%1000s", buffer);
295             parseCDEF_DS(buffer, rrd, rrd->stat_head->ds_cnt - 1);
296             if (rrd_test_error())
297                 return -1;
298         }
299
300         read_tag(&ptr2, "last_ds", "%30s",
301                  rrd->pdp_prep[rrd->stat_head->ds_cnt - 1].last_ds);
302         read_tag(&ptr2, "value", "%lf",
303                  &(rrd->pdp_prep[rrd->stat_head->ds_cnt - 1].scratch[PDP_val].
304                    u_val));
305         read_tag(&ptr2, "unknown_sec", "%lu",
306                  &(rrd->pdp_prep[rrd->stat_head->ds_cnt - 1].
307                    scratch[PDP_unkn_sec_cnt].u_cnt));
308         eat_tag(&ptr2, "/ds");
309         ptr = ptr2;
310     }
311
312     ptr2 = ptr;
313     while (eat_tag(&ptr2, "rra") == 1) {
314         rrd->stat_head->rra_cnt++;
315
316         /* allocate and reset rra definition areas */
317         if ((rrd->rra_def =
318              rrd_realloc(rrd->rra_def,
319                          rrd->stat_head->rra_cnt * sizeof(rra_def_t))) ==
320             NULL) {
321             rrd_set_error("allocating rra_def");
322             return -1;
323         }
324         memset(&(rrd->rra_def[rrd->stat_head->rra_cnt - 1]), 0,
325                sizeof(rra_def_t));
326
327         /* allocate and reset consolidation point areas */
328         if ((rrd->cdp_prep = rrd_realloc(rrd->cdp_prep,
329                                          rrd->stat_head->rra_cnt
330                                          * rrd->stat_head->ds_cnt *
331                                          sizeof(cdp_prep_t))) == NULL) {
332             rrd_set_error("allocating cdp_prep");
333             return -1;
334         }
335
336         memset(&
337                (rrd->
338                 cdp_prep[rrd->stat_head->ds_cnt *
339                          (rrd->stat_head->rra_cnt - 1)]), 0,
340                rrd->stat_head->ds_cnt * sizeof(cdp_prep_t));
341
342
343         read_tag(&ptr2, "cf", CF_NAM_FMT,
344                  rrd->rra_def[rrd->stat_head->rra_cnt - 1].cf_nam);
345         /* test for valid type */
346         if ((int) cf_conv(rrd->rra_def[rrd->stat_head->rra_cnt - 1].cf_nam) ==
347             -1)
348             return -1;
349
350         read_tag(&ptr2, "pdp_per_row", "%lu",
351                  &(rrd->rra_def[rrd->stat_head->rra_cnt - 1].pdp_cnt));
352         /* support to read RRA parameters */
353         rra_index = rrd->stat_head->rra_cnt - 1;
354         if (input_version < 2) {
355             read_tag(&ptr2, "xff", "%lf",
356                      &(rrd->rra_def[rra_index].par[RRA_cdp_xff_val].u_val));
357         } else {
358             if (eat_tag(&ptr2, "params") != 1) {
359                 rrd_set_error("could not find params tag to eat and skip");
360                 return -1;
361             }
362             skip(&ptr2);
363             /* backwards compatibility w/ old patch */
364             if (strncmp(ptr2, "<value>", 7) == 0) {
365                 parse_patch1028_RRA_params(&ptr2, rrd, rra_index);
366             } else {
367                 switch (cf_conv(rrd->rra_def[rra_index].cf_nam)) {
368                 case CF_HWPREDICT:
369                 case CF_MHWPREDICT:
370                     read_tag(&ptr2, "hw_alpha", "%lf",
371                              &(rrd->rra_def[rra_index].par[RRA_hw_alpha].
372                                u_val));
373                     read_tag(&ptr2, "hw_beta", "%lf",
374                              &(rrd->rra_def[rra_index].par[RRA_hw_beta].
375                                u_val));
376                     read_tag(&ptr2, "dependent_rra_idx", "%lu",
377                              &(rrd->rra_def[rra_index].
378                                par[RRA_dependent_rra_idx].u_cnt));
379                     break;
380                 case CF_SEASONAL:
381                 case CF_DEVSEASONAL:
382                     read_tag(&ptr2, "seasonal_gamma", "%lf",
383                              &(rrd->rra_def[rra_index].
384                                par[RRA_seasonal_gamma].u_val));
385                     read_tag(&ptr2, "seasonal_smooth_idx", "%lu",
386                              &(rrd->rra_def[rra_index].
387                                par[RRA_seasonal_smooth_idx].u_cnt));
388                     if (atoi(rrd->stat_head->version) >= 4) {
389                         read_tag(&ptr2, "smoothing_window", "%lf",
390                                  &(rrd->rra_def[rra_index].
391                                    par[RRA_seasonal_smoothing_window].u_val));
392                     }
393                     read_tag(&ptr2, "dependent_rra_idx", "%lu",
394                              &(rrd->rra_def[rra_index].
395                                par[RRA_dependent_rra_idx].u_cnt));
396                     break;
397                 case CF_FAILURES:
398                     read_tag(&ptr2, "delta_pos", "%lf",
399                              &(rrd->rra_def[rra_index].par[RRA_delta_pos].
400                                u_val));
401                     read_tag(&ptr2, "delta_neg", "%lf",
402                              &(rrd->rra_def[rra_index].par[RRA_delta_neg].
403                                u_val));
404                     read_tag(&ptr2, "window_len", "%lu",
405                              &(rrd->rra_def[rra_index].par[RRA_window_len].
406                                u_cnt));
407                     read_tag(&ptr2, "failure_threshold", "%lu",
408                              &(rrd->rra_def[rra_index].
409                                par[RRA_failure_threshold].u_cnt));
410                     /* fall thru */
411                 case CF_DEVPREDICT:
412                     read_tag(&ptr2, "dependent_rra_idx", "%lu",
413                              &(rrd->rra_def[rra_index].
414                                par[RRA_dependent_rra_idx].u_cnt));
415                     break;
416                 case CF_AVERAGE:
417                 case CF_MAXIMUM:
418                 case CF_MINIMUM:
419                 case CF_LAST:
420                 default:
421                     read_tag(&ptr2, "xff", "%lf",
422                              &(rrd->rra_def[rra_index].par[RRA_cdp_xff_val].
423                                u_val));
424                 }
425             }
426             eat_tag(&ptr2, "/params");
427         }
428
429
430         eat_tag(&ptr2, "cdp_prep");
431         for (i = 0; i < (int) rrd->stat_head->ds_cnt; i++) {
432             if (eat_tag(&ptr2, "ds") != 1) {
433                 rrd_set_error
434                     ("expected to find %lu <ds> entries in <cdp_prep>",
435                      rrd->stat_head->ds_cnt);
436                 return -1;
437             }
438             /* support to read CDP parameters */
439             rra_index = rrd->stat_head->rra_cnt - 1;
440             skip(&ptr2);
441             if (input_version < 2) {
442                 rrd->cdp_prep[rrd->stat_head->ds_cnt * (rra_index) +
443                               i].scratch[CDP_primary_val].u_val = 0.0;
444                 rrd->cdp_prep[rrd->stat_head->ds_cnt * (rra_index) +
445                               i].scratch[CDP_secondary_val].u_val = 0.0;
446                 read_tag(&ptr2, "value", "%lf",
447                          &(rrd->
448                            cdp_prep[rrd->stat_head->ds_cnt * (rra_index) +
449                                     i].scratch[CDP_val].u_val));
450                 read_tag(&ptr2, "unknown_datapoints", "%lu",
451                          &(rrd->
452                            cdp_prep[rrd->stat_head->ds_cnt * (rra_index) +
453                                     i].scratch[CDP_unkn_pdp_cnt].u_cnt));
454             } else {
455
456                 if (strncmp(ptr2, "<value>", 7) == 0) {
457                     parse_patch1028_CDP_params(&ptr2, rrd, rra_index, i);
458                 } else {
459                     read_tag(&ptr2, "primary_value", "%lf",
460                              &(rrd->
461                                cdp_prep[rrd->stat_head->ds_cnt * (rra_index)
462                                         + i].scratch[CDP_primary_val].u_val));
463                     read_tag(&ptr2, "secondary_value", "%lf",
464                              &(rrd->
465                                cdp_prep[rrd->stat_head->ds_cnt * (rra_index)
466                                         +
467                                         i].scratch[CDP_secondary_val].u_val));
468                     switch (cf_conv(rrd->rra_def[rra_index].cf_nam)) {
469                     case CF_HWPREDICT:
470                     case CF_MHWPREDICT:
471                         read_tag(&ptr2, "intercept", "%lf",
472                                  &(rrd->
473                                    cdp_prep[rrd->stat_head->ds_cnt *
474                                             (rra_index)
475                                             +
476                                             i].scratch[CDP_hw_intercept].
477                                    u_val));
478                         read_tag(&ptr2, "last_intercept", "%lf",
479                                  &(rrd->
480                                    cdp_prep[rrd->stat_head->ds_cnt *
481                                             (rra_index)
482                                             +
483                                             i].scratch[CDP_hw_last_intercept].
484                                    u_val));
485                         read_tag(&ptr2, "slope", "%lf",
486                                  &(rrd->
487                                    cdp_prep[rrd->stat_head->ds_cnt *
488                                             (rra_index)
489                                             +
490                                             i].scratch[CDP_hw_slope].u_val));
491                         read_tag(&ptr2, "last_slope", "%lf",
492                                  &(rrd->
493                                    cdp_prep[rrd->stat_head->ds_cnt *
494                                             (rra_index)
495                                             +
496                                             i].scratch[CDP_hw_last_slope].
497                                    u_val));
498                         read_tag(&ptr2, "nan_count", "%lu",
499                                  &(rrd->
500                                    cdp_prep[rrd->stat_head->ds_cnt *
501                                             (rra_index)
502                                             +
503                                             i].scratch[CDP_null_count].
504                                    u_cnt));
505                         read_tag(&ptr2, "last_nan_count", "%lu",
506                                  &(rrd->
507                                    cdp_prep[rrd->stat_head->ds_cnt *
508                                             (rra_index)
509                                             +
510                                             i].scratch[CDP_last_null_count].
511                                    u_cnt));
512                         break;
513                     case CF_SEASONAL:
514                     case CF_DEVSEASONAL:
515                         read_tag(&ptr2, "seasonal", "%lf",
516                                  &(rrd->
517                                    cdp_prep[rrd->stat_head->ds_cnt *
518                                             (rra_index)
519                                             +
520                                             i].scratch[CDP_hw_seasonal].
521                                    u_val));
522                         read_tag(&ptr2, "last_seasonal", "%lf",
523                                  &(rrd->
524                                    cdp_prep[rrd->stat_head->ds_cnt *
525                                             (rra_index)
526                                             +
527                                             i].scratch[CDP_hw_last_seasonal].
528                                    u_val));
529                         read_tag(&ptr2, "init_flag", "%lu",
530                                  &(rrd->
531                                    cdp_prep[rrd->stat_head->ds_cnt *
532                                             (rra_index)
533                                             +
534                                             i].scratch[CDP_init_seasonal].
535                                    u_cnt));
536                         break;
537                     case CF_DEVPREDICT:
538                         break;
539                     case CF_FAILURES:
540                         parse_FAILURES_history(&ptr2, rrd, rra_index, i);
541                         break;
542                     case CF_AVERAGE:
543                     case CF_MAXIMUM:
544                     case CF_MINIMUM:
545                     case CF_LAST:
546                     default:
547                         read_tag(&ptr2, "value", "%lf",
548                                  &(rrd->
549                                    cdp_prep[rrd->stat_head->ds_cnt *
550                                             (rra_index) +
551                                             i].scratch[CDP_val].u_val));
552                         read_tag(&ptr2, "unknown_datapoints", "%lu",
553                                  &(rrd->
554                                    cdp_prep[rrd->stat_head->ds_cnt *
555                                             (rra_index) +
556                                             i].scratch[CDP_unkn_pdp_cnt].
557                                    u_cnt));
558                         break;
559                     }
560                 }
561             }
562             eat_tag(&ptr2, "/ds");
563         }
564         eat_tag(&ptr2, "/cdp_prep");
565         rrd->rra_def[rrd->stat_head->rra_cnt - 1].row_cnt = 0;
566         eat_tag(&ptr2, "database");
567         ptr3 = ptr2;
568         while (eat_tag(&ptr3, "row") == 1) {
569
570             if (mempool == 0) {
571                 mempool = 1000;
572                 if ((rrd->rrd_value = rrd_realloc(rrd->rrd_value,
573                                                   (rows +
574                                                    mempool) *
575                                                   (rrd->stat_head->ds_cnt)
576                                                   * sizeof(rrd_value_t))) ==
577                     NULL) {
578                     rrd_set_error("allocating rrd_values");
579                     return -1;
580                 }
581             }
582             rows++;
583             mempool--;
584             rrd->rra_def[rrd->stat_head->rra_cnt - 1].row_cnt++;
585             for (i = 0; i < (int) rrd->stat_head->ds_cnt; i++) {
586
587                 rrd_value_t *value =
588                     &(rrd->
589                       rrd_value[(rows - 1) * rrd->stat_head->ds_cnt + i]);
590
591                 read_tag(&ptr3, "v", "%lf", value);
592
593                 if ((rc == 1)   /* do we have to check for the ranges */
594                     &&(!isnan(*value))  /* not a NAN value */
595                     &&(dst_conv(rrd->ds_def[i].dst) != DST_CDEF)
596                     && (    /* min defined and in the range ? */
597                            (!isnan(rrd->ds_def[i].par[DS_min_val].u_val)
598                             && (*value <
599                                 rrd->ds_def[i].par[DS_min_val].u_val))
600                            ||   /* max defined and in the range ? */
601                            (!isnan(rrd->ds_def[i].par[DS_max_val].u_val)
602                             && (*value >
603                                 rrd->ds_def[i].par[DS_max_val].u_val))
604                     )
605                     ) {
606                     fprintf(stderr,
607                             "out of range found [ds: %lu], [value : %0.10e]\n",
608                             i, *value);
609                     *value = DNAN;
610                 }
611             }
612             eat_tag(&ptr3, "/row");
613             ptr2 = ptr3;
614         }
615         eat_tag(&ptr2, "/database");
616         eat_tag(&ptr2, "/rra");
617         ptr = ptr2;
618     }
619     eat_tag(&ptr, "/rrd");
620
621     if ((rrd->rra_ptr =
622          calloc(1, sizeof(rra_ptr_t) * rrd->stat_head->rra_cnt)) == NULL) {
623         rrd_set_error("allocating rra_ptr");
624         return (-1);
625     }
626
627     if (ptr == NULL)
628         return -1;
629     return 1;
630 }
631
632
633
634
635
636 /* create and empty rrd file according to the specs given */
637
638 int rrd_creat(
639     char *file_name,
640     rrd_t *rrd,
641     char force_overwrite)
642 {
643     unsigned long i, ii, rra_offset;
644     FILE     *rrd_file = NULL;
645     int       fdflags;
646     int       fd;
647
648     if (strcmp("-", file_name) == 0) {
649         rrd_file = stdout;
650     } else {
651 #if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
652         fdflags = O_RDWR | O_BINARY | O_CREAT;
653 #else
654         fdflags = O_WRONLY | O_CREAT;
655 #endif
656         if (force_overwrite == 0) {
657             fdflags |= O_EXCL;
658         }
659         fd = open(file_name, fdflags, 0666);
660         if (fd == -1 || (rrd_file = fdopen(fd, "wb")) == NULL) {
661             rrd_set_error("creating '%s': %s", file_name,
662                           rrd_strerror(errno));
663             if (fd != -1)
664                 close(fd);
665             return (-1);
666         }
667     }
668     fwrite(rrd->stat_head, sizeof(stat_head_t), 1, rrd_file);
669
670     fwrite(rrd->ds_def, sizeof(ds_def_t), rrd->stat_head->ds_cnt, rrd_file);
671
672     fwrite(rrd->rra_def,
673            sizeof(rra_def_t), rrd->stat_head->rra_cnt, rrd_file);
674
675     fwrite(rrd->live_head, sizeof(live_head_t), 1, rrd_file);
676
677     fwrite(rrd->pdp_prep, sizeof(pdp_prep_t), rrd->stat_head->ds_cnt,
678            rrd_file);
679
680     fwrite(rrd->cdp_prep, sizeof(cdp_prep_t), rrd->stat_head->rra_cnt *
681            rrd->stat_head->ds_cnt, rrd_file);
682
683     for (i = 0; i < rrd->stat_head->rra_cnt; i++)
684         rrd->rra_ptr[i].cur_row = rra_random_row(&rrd->rra_def[i]);
685
686     fwrite(rrd->rra_ptr, sizeof(rra_ptr_t), rrd->stat_head->rra_cnt,
687            rrd_file);
688
689
690     /* Dump RRD values */
691     rra_offset = 0;
692     for (i = 0; i < rrd->stat_head->rra_cnt; i++) {
693         unsigned long num_rows = rrd->rra_def[i].row_cnt;
694         unsigned long cur_row = rrd->rra_ptr[i].cur_row;
695         unsigned long ds_cnt = rrd->stat_head->ds_cnt;
696
697         fwrite(rrd->rrd_value +
698                (rra_offset + num_rows - 1 - cur_row) * ds_cnt,
699                sizeof(rrd_value_t), (cur_row + 1) * ds_cnt, rrd_file);
700
701         fwrite(rrd->rrd_value + rra_offset * ds_cnt,
702                sizeof(rrd_value_t), (num_rows - 1 - cur_row) * ds_cnt,
703                rrd_file);
704
705         rra_offset += num_rows;
706     }
707
708     /* lets see if we had an error */
709     if (ferror(rrd_file)) {
710         rrd_set_error("a file error occurred while creating '%s'", file_name);
711         fclose(rrd_file);
712         return (-1);
713     }
714
715     fclose(rrd_file);
716     return 0;
717 }
718
719
720 int rrd_restore(
721     int argc,
722     char **argv)
723 {
724     rrd_t     rrd;
725     char     *buf;
726     char      rc = 0;
727     char      force_overwrite = 0;
728     struct option long_options[] = {
729         {"range-check", no_argument, 0, 'r'},
730         {"force-overwrite", no_argument, 0, 'f'},
731         {0, 0, 0, 0}
732     };
733
734     /* init rrd clean */
735     optind = 0;
736     opterr = 0;         /* initialize getopt */
737     while (1) {
738         int       option_index = 0;
739         int       opt;
740
741         opt = getopt_long(argc, argv, "rf", long_options, &option_index);
742
743         if (opt == EOF)
744             break;
745
746         switch (opt) {
747         case 'r':
748             rc = 1;
749             break;
750         case 'f':
751             force_overwrite = 1;
752             break;
753         default:
754             rrd_set_error
755                 ("usage rrdtool %s [--range-check|-r] [--force-overwrite/-f]  file.xml file.rrd",
756                  argv[0]);
757             return -1;
758             break;
759         }
760     }
761
762     if (argc - optind != 2) {
763         rrd_set_error
764             ("usage rrdtool %s [--range-check/-r] [--force-overwrite/-f] file.xml file.rrd",
765              argv[0]);
766         return -1;
767     }
768
769     if (readfile(argv[optind], &buf, 0) == -1) {
770         return -1;
771     }
772
773     rrd_init(&rrd);
774
775     if (xml2rrd(buf, &rrd, rc) == -1) {
776         rrd_free(&rrd);
777         free(buf);
778         return -1;
779     }
780
781     free(buf);
782
783     if (rrd_creat(argv[optind + 1], &rrd, force_overwrite) == -1) {
784         rrd_free(&rrd);
785         return -1;
786     };
787     rrd_free(&rrd);
788     return 0;
789 }
790
791 /* a backwards compatibility routine that will parse the RRA params section
792  * generated by the aberrant patch to 1.0.28. */
793
794 void parse_patch1028_RRA_params(
795     char **buf,
796     rrd_t *rrd,
797     int rra_index)
798 {
799     int       i;
800
801     for (i = 0; i < MAX_RRA_PAR_EN; i++) {
802         if (i == RRA_dependent_rra_idx ||
803             i == RRA_seasonal_smooth_idx || i == RRA_failure_threshold)
804             read_tag(buf, "value", "%lu",
805                      &(rrd->rra_def[rra_index].par[i].u_cnt));
806         else
807             read_tag(buf, "value", "%lf",
808                      &(rrd->rra_def[rra_index].par[i].u_val));
809     }
810 }
811
812 /* a backwards compatibility routine that will parse the CDP params section
813  * generated by the aberrant patch to 1.0.28. */
814 void parse_patch1028_CDP_params(
815     char **buf,
816     rrd_t *rrd,
817     int rra_index,
818     int ds_index)
819 {
820     int       ii;
821
822     for (ii = 0; ii < MAX_CDP_PAR_EN; ii++) {
823         if (cf_conv(rrd->rra_def[rra_index].cf_nam) == CF_FAILURES ||
824             ii == CDP_unkn_pdp_cnt ||
825             ii == CDP_null_count || ii == CDP_last_null_count) {
826             read_tag(buf, "value", "%lu",
827                      &(rrd->
828                        cdp_prep[rrd->stat_head->ds_cnt * (rra_index) +
829                                 ds_index].scratch[ii].u_cnt));
830         } else {
831             read_tag(buf, "value", "%lf",
832                      &(rrd->
833                        cdp_prep[rrd->stat_head->ds_cnt * (rra_index) +
834                                 ds_index].scratch[ii].u_val));
835         }
836     }
837 }
838
839 void parse_FAILURES_history(
840     char **buf,
841     rrd_t *rrd,
842     int rra_index,
843     int ds_index)
844 {
845     char      history[MAX_FAILURES_WINDOW_LEN + 1];
846     char     *violations_array;
847     unsigned short i;
848
849     /* 28 = MAX_FAILURES_WINDOW_LEN */
850     read_tag(buf, "history", "%28[0-1]", history);
851     violations_array =
852         (char *) rrd->cdp_prep[rrd->stat_head->ds_cnt * (rra_index)
853                                + ds_index].scratch;
854
855     for (i = 0; i < rrd->rra_def[rra_index].par[RRA_window_len].u_cnt; ++i)
856         violations_array[i] = (history[i] == '1') ? 1 : 0;
857
858 }