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