Support for COMPUTE data sources (CDEF data sources). Removes the RPN
[rrdtool.git] / src / rrd_create.c
1 /*****************************************************************************
2  * RRDtool 1.0.33  Copyright Tobias Oetiker, 1997 - 2000
3  *****************************************************************************
4  * rrd_create.c  creates new rrds
5  *****************************************************************************/
6
7 #include "rrd_tool.h"
8 #include "rrd_rpncalc.h"
9
10 unsigned long FnvHash(char *str);
11 int create_hw_contingent_rras(rrd_t *rrd, unsigned short period, unsigned long hashed_name);
12 void parseGENERIC_DS(char *def,rrd_t *rrd, int ds_idx);
13
14 /* #define DEBUG */
15 int
16 rrd_create(int argc, char **argv) 
17 {
18     rrd_t             rrd;
19     long              i,long_tmp;
20         int               offset;
21     time_t            last_up;
22     struct time_value last_up_tv;
23     char *parsetime_error = NULL;
24     char *token;
25     unsigned short token_idx, error_flag, period=0;
26         unsigned long hashed_name;
27     /* init last_up */
28     last_up = time(NULL)-10;
29     /* init rrd clean */
30     rrd_init(&rrd);
31     /* static header */
32     if((rrd.stat_head = calloc(1,sizeof(stat_head_t)))==NULL){
33         rrd_set_error("allocating rrd.stat_head");
34         return(-1);
35     }
36
37     /* live header */
38     if((rrd.live_head = calloc(1,sizeof(live_head_t)))==NULL){
39         rrd_set_error("allocating rrd.live_head");
40         return(-1);
41     }
42
43     /* set some defaults */
44     strcpy(rrd.stat_head->cookie,RRD_COOKIE);
45         /* assume the will be version 1 compatible */
46     strcpy(rrd.stat_head->version,"0001");
47     rrd.stat_head->float_cookie = FLOAT_COOKIE;
48     rrd.stat_head->ds_cnt = 0; /* this will be adjusted later */
49     rrd.stat_head->rra_cnt = 0; /* ditto */
50     rrd.stat_head->pdp_step = 300; /* 5 minute default */
51
52     /* a default value */
53     rrd.ds_def = NULL;
54     rrd.rra_def = NULL;
55     
56     while (1){
57         static struct option long_options[] =
58         {
59             {"start",      required_argument, 0, 'b'},
60             {"step",        required_argument,0,'s'},
61             {0,0,0,0}
62         };
63         int option_index = 0;
64         int opt;
65         opt = getopt_long(argc, argv, "b:s:", 
66                           long_options, &option_index);
67         
68         if (opt == EOF)
69           break;
70         
71         switch(opt) {
72         case 'b':
73             if ((parsetime_error = parsetime(optarg, &last_up_tv))) {
74                 rrd_set_error("start time: %s", parsetime_error );
75                 rrd_free(&rrd);
76                 return(-1);
77             }
78             if (last_up_tv.type == RELATIVE_TO_END_TIME ||
79                 last_up_tv.type == RELATIVE_TO_START_TIME) {
80                 rrd_set_error("specifying time relative to the 'start' "
81                               "or 'end' makes no sense here");
82                 rrd_free(&rrd);
83                 return(-1);
84             }
85
86             last_up = mktime(&last_up_tv.tm) + last_up_tv.offset;
87             
88             if (last_up < 3600*24*365*10){
89                 rrd_set_error("the first entry to the RRD should be after 1980");
90                 rrd_free(&rrd);
91                 return(-1);
92             }   
93             break;
94
95         case 's':
96             long_tmp = atol(optarg);
97             if (long_tmp < 1){
98                 rrd_set_error("step size should be no less than one second");
99                 rrd_free(&rrd);
100                 return(-1);
101             }
102             rrd.stat_head->pdp_step = long_tmp;
103             break;
104
105         case '?':
106             if (optopt != 0)
107                 rrd_set_error("unknown option '%c'", optopt);
108             else
109                 rrd_set_error("unknown option '%s'",argv[optind-1]);
110             rrd_free(&rrd);
111             return(-1);
112         }
113     }
114     rrd.live_head->last_up = last_up;
115         
116         /* optind points to the first non-option command line arg,
117          * in this case, the file name. */
118         /* Compute the FNV hash value (used by SEASONAL and DEVSEASONAL
119          * arrays. */
120         hashed_name = FnvHash(argv[optind]);
121     for(i=optind+1;i<argc;i++){
122         int ii;
123         if (strncmp(argv[i],"DS:",3)==0){
124             size_t old_size = sizeof(ds_def_t)*(rrd.stat_head->ds_cnt);
125             if((rrd.ds_def = rrd_realloc(rrd.ds_def,
126                                      old_size+sizeof(ds_def_t)))==NULL){
127                 rrd_set_error("allocating rrd.ds_def");
128                 rrd_free(&rrd);
129                 return(-1);     
130             }
131             memset(&rrd.ds_def[rrd.stat_head->ds_cnt], 0, sizeof(ds_def_t));
132                 /* extract the name and type */
133             if (sscanf(&argv[i][3],
134                        DS_NAM_FMT ":" DST_FMT ":%n",
135                        rrd.ds_def[rrd.stat_head->ds_cnt].ds_nam,
136                        rrd.ds_def[rrd.stat_head->ds_cnt].dst,&offset) == 2)
137                 {
138                    /* check for duplicate datasource names */
139                    for(ii=0;ii<rrd.stat_head->ds_cnt;ii++)
140                         if(strcmp(rrd.ds_def[rrd.stat_head->ds_cnt].ds_nam,
141                                   rrd.ds_def[ii].ds_nam) == 0){
142                                 rrd_set_error("Duplicate DS name: %s",rrd.ds_def[ii].ds_nam);
143                         }                                                               
144                 } else {
145                    rrd_set_error("invalid DS format");
146                 }
147
148                 /* parse the remainder of the arguments */
149                 switch(dst_conv(rrd.ds_def[rrd.stat_head->ds_cnt].dst))
150             {
151                    case DST_COUNTER:
152                    case DST_ABSOLUTE:
153                    case DST_GAUGE:
154                    case DST_DERIVE:
155                           parseGENERIC_DS(&argv[i][offset+3],&rrd, rrd.stat_head->ds_cnt);
156                           break;
157                case DST_CDEF:
158                           parseCDEF_DS(&argv[i][offset+3],&rrd, rrd.stat_head->ds_cnt);
159                           break;
160            default:
161                           rrd_set_error("invalid DS type specified");
162                           break;
163                 }
164
165                 if (rrd_test_error()) {
166                    rrd_free(&rrd);
167                    return -1;
168         }
169                 rrd.stat_head -> ds_cnt++;
170         } else if (strncmp(argv[i],"RRA:",3)==0){
171             size_t old_size = sizeof(rra_def_t)*(rrd.stat_head->rra_cnt);
172             if((rrd.rra_def = rrd_realloc(rrd.rra_def,
173                                       old_size+sizeof(rra_def_t)))==NULL)
174             {
175                    rrd_set_error("allocating rrd.rra_def");
176                    rrd_free(&rrd);
177                    return(-1);  
178             }
179             memset(&rrd.rra_def[rrd.stat_head->rra_cnt], 0, sizeof(rra_def_t));
180
181             token = strtok(&argv[i][4],":");
182             token_idx = error_flag = 0;
183             while (token != NULL)
184             {
185               switch(token_idx)
186               {
187               case 0:
188                 if (sscanf(token,CF_NAM_FMT,
189                            rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam) != 1)
190                   rrd_set_error("Failed to parse CF name");
191                 switch(cf_conv(rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam))
192                 {
193                 case CF_HWPREDICT:
194                   /* initialize some parameters */
195                   rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_hw_alpha].u_val = 0.1;
196                   rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_hw_beta].u_val = 1.0/288;
197                   rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_dependent_rra_idx].u_cnt = 
198                     rrd.stat_head -> rra_cnt;
199                   /* need to mark the file version */
200           strcpy(rrd.stat_head->version,RRD_VERSION);
201                   break;
202                 case CF_DEVSEASONAL:
203                 case CF_SEASONAL:
204                   /* initialize some parameters */
205                   rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_seasonal_gamma].u_val = 0.1;
206                   /* fall through */
207                 case CF_DEVPREDICT:
208                   rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_dependent_rra_idx].u_cnt = -1;
209                   break;
210                 case CF_FAILURES:
211                   rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_delta_pos].u_val = 2.0;
212                   rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_delta_neg].u_val = 2.0;
213                   rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_window_len].u_cnt = 3;
214                   rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_failure_threshold].u_cnt = 2;
215                   rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_dependent_rra_idx].u_cnt = -1;
216                   break;
217                 /* invalid consolidation function */
218                 case -1:
219                   rrd_set_error("Unrecognized consolidation function %s",
220                          rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam);
221                 default:
222                   break;
223                 }
224                 /* default: 1 pdp per cdp */ 
225                 rrd.rra_def[rrd.stat_head->rra_cnt].pdp_cnt = 1;
226                 break;
227               case 1:
228                 switch(cf_conv(rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam))
229                 {
230                 case CF_HWPREDICT:
231                 case CF_DEVSEASONAL:
232                 case CF_SEASONAL:
233                 case CF_DEVPREDICT:
234                 case CF_FAILURES:
235                   rrd.rra_def[rrd.stat_head->rra_cnt].row_cnt = atoi(token);
236                   break;
237                 default:
238                   rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_cdp_xff_val].u_val = atof(token);
239                   if (rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_cdp_xff_val].u_val<0.0 ||
240                       rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_cdp_xff_val].u_val>=1.0)
241                     rrd_set_error("Invalid xff: must be between 0 and 1");
242                   break;
243                 }
244                 break;
245               case 2:
246                 switch(cf_conv(rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam))
247                 {
248                 case CF_HWPREDICT:
249                   rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_hw_alpha].u_val = atof(token);
250                   if (atof(token) <= 0.0 || atof(token) >= 1.0)
251                     rrd_set_error("Invalid alpha: must be between 0 and 1");
252                   break;
253                 case CF_DEVSEASONAL:
254                 case CF_SEASONAL:
255                   rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_seasonal_gamma].u_val = 
256                         atof(token);
257                   if (atof(token) <= 0.0 || atof(token) >= 1.0)
258                     rrd_set_error("Invalid gamma: must be between 0 and 1");
259                   rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_seasonal_smooth_idx].u_cnt
260                         = hashed_name % rrd.rra_def[rrd.stat_head->rra_cnt].row_cnt; 
261                   break;
262             case CF_FAILURES:
263                   /* specifies the # of violations that constitutes the failure threshold */
264                   rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_failure_threshold].u_cnt =
265                         atoi(token);
266                   if (atoi(token) < 1 || atoi(token) > MAX_FAILURES_WINDOW_LEN)
267                         rrd_set_error("Failure threshold is out of range %d, %d",1,
268                           MAX_FAILURES_WINDOW_LEN);
269                   break;
270                 case CF_DEVPREDICT:
271                   /* specifies the index (1-based) of CF_DEVSEASONAL array
272                    * associated with this CF_DEVPREDICT array. */
273                   rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_dependent_rra_idx].u_cnt =
274                     atoi(token) - 1;
275                   break;
276                 default:
277                   rrd.rra_def[rrd.stat_head->rra_cnt].pdp_cnt = atoi(token);
278                   break;
279                 }
280                 break;
281               case 3:
282                 switch(cf_conv(rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam))
283                 {
284                 case CF_HWPREDICT:
285                   rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_hw_beta].u_val = atof(token);
286                   if (atof(token) < 0.0 || atof(token) > 1.0)
287                     rrd_set_error("Invalid beta: must be between 0 and 1");
288                   break;
289                 case CF_DEVSEASONAL:
290                 case CF_SEASONAL:
291                   /* specifies the index (1-based) of CF_HWPREDICT array
292                    * associated with this CF_DEVSEASONAL or CF_SEASONAL array. 
293                    * */
294                   rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_dependent_rra_idx].u_cnt =
295                     atoi(token) - 1;
296                   break;
297                 case CF_FAILURES:
298                   /* specifies the window length */
299                   rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_window_len].u_cnt =
300                         atoi(token);
301                   if (atoi(token) < 1 || atoi(token) > MAX_FAILURES_WINDOW_LEN)
302                         rrd_set_error("Window length is out of range %d, %d",1,
303                            MAX_FAILURES_WINDOW_LEN);
304                   /* verify that window length exceeds the failure threshold */
305                   if (rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_window_len].u_cnt <
306                           rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_failure_threshold].u_cnt)
307                     rrd_set_error("Window length is shorter than the failure threshold");
308                   break;
309                 case CF_DEVPREDICT:
310                   /* shouldn't be any more arguments */
311                   rrd_set_error("Unexpected extra argument for consolidation function DEVPREDICT");
312                   break;
313                 default:
314                   rrd.rra_def[rrd.stat_head->rra_cnt].row_cnt = atoi(token);
315                   break;
316                 }
317                 break;
318               case 4:
319                 switch(cf_conv(rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam))
320                 {
321                 case CF_FAILURES:
322                   /* specifies the index (1-based) of CF_DEVSEASONAL array
323                    * associated with this CF_DEVFAILURES array. */
324                   rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_dependent_rra_idx].u_cnt =
325                     atoi(token) - 1;
326                   break;
327                 case CF_HWPREDICT:
328                   /* length of the associated CF_SEASONAL and CF_DEVSEASONAL arrays. */
329                   period = atoi(token);
330           if (period > rrd.rra_def[rrd.stat_head->rra_cnt].row_cnt)
331                     rrd_set_error("Length of seasonal cycle exceeds length of HW prediction array");
332                   break;
333                 default:
334                   /* shouldn't be any more arguments */
335                   rrd_set_error("Unexpected extra argument for consolidation function %s",
336                                 rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam);
337                   break;
338                 }
339                 break;
340               case 5:
341                 /* If we are here, this must be a CF_HWPREDICT RRA.
342                  * Specifies the index (1-based) of CF_SEASONAL array
343                  * associated with this CF_HWPREDICT array. If this argument 
344                  * is missing, then the CF_SEASONAL, CF_DEVSEASONAL, CF_DEVPREDICT,
345                  * CF_FAILURES.
346                  * arrays are created automatically. */
347                 rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_dependent_rra_idx].u_cnt =
348                   atoi(token) - 1;
349                 break;
350               default:
351                 /* should never get here */
352                 rrd_set_error("Unknown error");
353                 break;
354               } /* end switch */
355               if (rrd_test_error())
356               {
357                 /* all errors are unrecoverable */
358                 rrd_free(&rrd);
359                 return (-1);
360               }
361               token = strtok(NULL,":");
362               token_idx++;
363             } /* end while */
364 #ifdef DEBUG
365             fprintf(stderr,"Creating RRA CF: %s, dep idx %lu, current idx %lu\n",
366                     rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam,
367                     rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_dependent_rra_idx].u_cnt, 
368                     rrd.stat_head -> rra_cnt);
369 #endif
370             /* should we create CF_SEASONAL, CF_DEVSEASONAL, and CF_DEVPREDICT? */
371             if (cf_conv(rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam) == CF_HWPREDICT
372                 && rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_dependent_rra_idx].u_cnt 
373                 == rrd.stat_head -> rra_cnt)
374             {
375 #ifdef DEBUG
376               fprintf(stderr,"Creating HW contingent RRAs\n");
377 #endif
378               if (create_hw_contingent_rras(&rrd,period,hashed_name) == -1) {
379                 rrd_free(&rrd);
380                 return -1;
381               }
382             }
383             rrd.stat_head->rra_cnt++;                   
384         } else {
385             rrd_set_error("can't parse argument '%s'",argv[i]);
386             rrd_free(&rrd);
387             return -1;
388         }
389     }
390
391
392     if (rrd.stat_head->rra_cnt < 1){
393         rrd_set_error("you must define at least one Round Robin Archive");
394         rrd_free(&rrd);
395         return(-1);
396     }
397
398     if (rrd.stat_head->ds_cnt < 1){
399         rrd_set_error("you must define at least one Data Source");
400         rrd_free(&rrd);
401         return(-1);
402     }
403     return rrd_create_fn(argv[optind],&rrd);
404 }
405
406 void parseGENERIC_DS(char *def,rrd_t *rrd, int ds_idx)
407 {
408    char minstr[DS_NAM_SIZE], maxstr[DS_NAM_SIZE];       
409    /*
410    int temp;
411
412    temp = sscanf(def,"%lu:%18[^:]:%18[^:]",     
413        &(rrd -> ds_def[ds_idx].par[DS_mrhb_cnt].u_cnt),
414        minstr,maxstr);
415    */
416    if (sscanf(def,"%lu:%18[^:]:%18[^:]",        
417        &(rrd -> ds_def[ds_idx].par[DS_mrhb_cnt].u_cnt),
418        minstr,maxstr) == 3)
419    {
420                 if (minstr[0] == 'U' && minstr[1] == 0)
421                     rrd -> ds_def[ds_idx].par[DS_min_val].u_val = DNAN;
422                 else
423                     rrd -> ds_def[ds_idx].par[DS_min_val].u_val = atof(minstr);
424                 
425                 if (maxstr[0] == 'U' && maxstr[1] == 0)
426                     rrd -> ds_def[ds_idx].par[DS_max_val].u_val = DNAN;
427                 else
428                     rrd -> ds_def[ds_idx].par[DS_max_val].u_val  = atof(maxstr);
429                 
430                 if (! isnan(rrd -> ds_def[ds_idx].par[DS_min_val].u_val) &&
431                     ! isnan(rrd -> ds_def[ds_idx].par[DS_max_val].u_val) &&
432                     rrd -> ds_def[ds_idx].par[DS_min_val].u_val
433                     >= rrd -> ds_def[ds_idx].par[DS_max_val].u_val ) {
434                     rrd_set_error("min must be less than max in DS definition");
435                     return;             
436                 }
437    } else {
438           rrd_set_error("failed to parse data source %s", def);
439    }
440 }
441
442 /* Create the CF_DEVPREDICT, CF_DEVSEASONAL, CF_SEASONAL, and CF_FAILURES RRAs
443  * associated with a CF_HWPREDICT RRA. */
444 int
445 create_hw_contingent_rras(rrd_t *rrd, unsigned short period, unsigned long hashed_name)
446 {
447    size_t old_size;
448    rra_def_t* current_rra;
449    
450    /* save index to CF_HWPREDICT */
451    unsigned long hw_index = rrd -> stat_head -> rra_cnt;
452    /* advance the pointer */
453    (rrd -> stat_head -> rra_cnt)++;                     
454    /* allocate the memory for the 4 contingent RRAs */
455    old_size = sizeof(rra_def_t)*(rrd -> stat_head->rra_cnt);
456    if ((rrd -> rra_def = rrd_realloc(rrd -> rra_def,
457        old_size+4*sizeof(rra_def_t)))==NULL)
458    {
459      rrd_set_error("allocating rrd.rra_def");
460      return(-1);        
461    }
462    /* clear memory */
463    memset(&(rrd -> rra_def[rrd -> stat_head->rra_cnt]), 0, 4*sizeof(rra_def_t));
464
465    /* create the CF_SEASONAL RRA */
466    current_rra = &(rrd -> rra_def[rrd -> stat_head -> rra_cnt]);
467    strcpy(current_rra -> cf_nam,"SEASONAL");
468    current_rra -> row_cnt = period;
469    current_rra -> par[RRA_seasonal_smooth_idx].u_cnt = hashed_name % period;
470    current_rra -> pdp_cnt = 1;
471    current_rra -> par[RRA_seasonal_gamma].u_val = 
472      rrd -> rra_def[hw_index].par[RRA_hw_alpha].u_val;
473    current_rra -> par[RRA_dependent_rra_idx].u_cnt = hw_index; 
474    rrd -> rra_def[hw_index].par[RRA_dependent_rra_idx].u_cnt = rrd -> stat_head -> rra_cnt;
475
476    /* create the CF_DEVSEASONAL RRA */
477    (rrd -> stat_head -> rra_cnt)++; 
478    current_rra = &(rrd -> rra_def[rrd -> stat_head -> rra_cnt]);
479    strcpy(current_rra -> cf_nam,"DEVSEASONAL");
480    current_rra -> row_cnt = period;
481    current_rra -> par[RRA_seasonal_smooth_idx].u_cnt = hashed_name % period;
482    current_rra -> pdp_cnt = 1;
483    current_rra -> par[RRA_seasonal_gamma].u_val = 
484      rrd -> rra_def[hw_index].par[RRA_hw_alpha].u_val;
485    current_rra -> par[RRA_dependent_rra_idx].u_cnt = hw_index; 
486    
487    /* create the CF_DEVPREDICT RRA */
488    (rrd -> stat_head -> rra_cnt)++; 
489    current_rra = &(rrd -> rra_def[rrd -> stat_head -> rra_cnt]);
490    strcpy(current_rra -> cf_nam,"DEVPREDICT");
491    current_rra -> row_cnt = (rrd -> rra_def[hw_index]).row_cnt;
492    current_rra -> pdp_cnt = 1;
493    current_rra -> par[RRA_dependent_rra_idx].u_cnt 
494      = hw_index + 2; /* DEVSEASONAL */
495
496    /* create the CF_FAILURES RRA */
497    (rrd -> stat_head -> rra_cnt)++; 
498    current_rra = &(rrd -> rra_def[rrd -> stat_head -> rra_cnt]);
499    strcpy(current_rra -> cf_nam,"FAILURES");
500    current_rra -> row_cnt = period; 
501    current_rra -> pdp_cnt = 1;
502    current_rra -> par[RRA_delta_pos].u_val = 2.0;
503    current_rra -> par[RRA_delta_neg].u_val = 2.0;
504    current_rra -> par[RRA_failure_threshold].u_cnt = 7;
505    current_rra -> par[RRA_window_len].u_cnt = 9;
506    current_rra -> par[RRA_dependent_rra_idx].u_cnt = 
507          hw_index + 2; /* DEVSEASONAL */
508    return 0;
509 }
510
511 /* create and empty rrd file according to the specs given */
512
513 int
514 rrd_create_fn(char *file_name, rrd_t *rrd)
515 {
516     unsigned long    i,ii;
517     FILE             *rrd_file;
518     rrd_value_t       unknown = DNAN ;
519
520     if ((rrd_file = fopen(file_name,"wb")) == NULL ) {
521         rrd_set_error("creating '%s': %s",file_name,strerror(errno));
522         free(rrd->stat_head);
523         free(rrd->ds_def);
524         free(rrd->rra_def);
525         return(-1);
526     }
527     
528     fwrite(rrd->stat_head,
529            sizeof(stat_head_t), 1, rrd_file);
530
531     fwrite(rrd->ds_def,
532            sizeof(ds_def_t), rrd->stat_head->ds_cnt, rrd_file);
533
534     fwrite(rrd->rra_def,
535            sizeof(rra_def_t), rrd->stat_head->rra_cnt, rrd_file);
536     
537     fwrite(rrd->live_head,
538            sizeof(live_head_t),1, rrd_file);
539
540     if((rrd->pdp_prep = calloc(1,sizeof(pdp_prep_t))) == NULL){
541         rrd_set_error("allocating pdp_prep");
542         rrd_free(rrd);
543         fclose(rrd_file);
544         return(-1);
545     }
546
547     strcpy(rrd->pdp_prep->last_ds,"UNKN");
548
549     rrd->pdp_prep->scratch[PDP_val].u_val = 0.0;
550     rrd->pdp_prep->scratch[PDP_unkn_sec_cnt].u_cnt = 
551         rrd->live_head->last_up % rrd->stat_head->pdp_step;
552
553     for(i=0; i < rrd->stat_head->ds_cnt; i++)
554         fwrite( rrd->pdp_prep,sizeof(pdp_prep_t),1,rrd_file);
555     
556     if((rrd->cdp_prep = calloc(1,sizeof(cdp_prep_t))) == NULL){
557         rrd_set_error("allocating cdp_prep");
558         rrd_free(rrd);
559         fclose(rrd_file);
560         return(-1);
561     }
562
563
564     for(i=0; i < rrd->stat_head->rra_cnt; i++) {
565        switch (cf_conv(rrd->rra_def[i].cf_nam))
566            {
567                   case CF_HWPREDICT:
568              rrd->cdp_prep->scratch[CDP_hw_intercept].u_val = DNAN;
569              rrd->cdp_prep->scratch[CDP_hw_last_intercept].u_val = DNAN;
570              rrd->cdp_prep->scratch[CDP_hw_slope].u_val = DNAN;
571              rrd->cdp_prep->scratch[CDP_hw_last_slope].u_val = DNAN;
572              rrd->cdp_prep->scratch[CDP_null_count].u_cnt = 1; 
573              rrd->cdp_prep->scratch[CDP_last_null_count].u_cnt = 1;
574                          break;
575                   case CF_SEASONAL:
576                   case CF_DEVSEASONAL:
577              rrd->cdp_prep->scratch[CDP_hw_seasonal].u_val = DNAN;
578              rrd->cdp_prep->scratch[CDP_hw_last_seasonal].u_val = DNAN;
579              rrd->cdp_prep->scratch[CDP_init_seasonal].u_cnt = 1; 
580                          break;
581                   case CF_FAILURES:
582              /* initialize violation history to 0 */
583                          for (ii = 0; ii < MAX_CDP_PAR_EN; ii++)
584                          {
585                                 /* We can zero everything out, by setting u_val to the
586                                  * NULL address. Each array entry in scratch is 8 bytes
587                                  * (a double), but u_cnt only accessed 4 bytes (long) */
588                                 rrd->cdp_prep->scratch[ii].u_val = 0.0;
589                          }
590                          break;
591                   default:
592              /* can not be zero because we don't know anything ... */
593              rrd->cdp_prep->scratch[CDP_val].u_val = DNAN;
594                  /* startup missing pdp count */
595                  rrd->cdp_prep->scratch[CDP_unkn_pdp_cnt].u_cnt = 
596                  ((rrd->live_head->last_up -
597                  rrd->pdp_prep->scratch[PDP_unkn_sec_cnt].u_cnt)
598                  % (rrd->stat_head->pdp_step 
599                  * rrd->rra_def[i].pdp_cnt)) / rrd->stat_head->pdp_step;        
600                      break;
601            }
602
603            for(ii=0; ii < rrd->stat_head->ds_cnt; ii++) 
604            {
605               fwrite( rrd->cdp_prep,sizeof(cdp_prep_t),1,rrd_file);
606            }
607     }
608
609     /* now, we must make sure that the rest of the rrd
610        struct is properly initialized */
611
612     if((rrd->rra_ptr = calloc(1,sizeof(rra_ptr_t))) == NULL) {
613         rrd_set_error("allocating rra_ptr");
614         rrd_free(rrd);
615         fclose(rrd_file);
616         return(-1);
617     }
618  
619         /* changed this initialization to be consistent with
620          * rrd_restore. With the old value (0), the first update
621          * would occur for cur_row = 1 because rrd_update increments
622          * the pointer a priori. */
623     for (i=0; i < rrd->stat_head->rra_cnt; i++)
624         {
625            rrd->rra_ptr->cur_row = rrd->rra_def[i].row_cnt - 1;
626            fwrite( rrd->rra_ptr, sizeof(rra_ptr_t),1,rrd_file);
627         }
628
629     /* write the empty data area */
630     for(i=0; 
631         i <  rrd->stat_head->rra_cnt;
632         i++)
633         {
634             for(ii=0; 
635                 ii <  rrd->rra_def[i].row_cnt 
636                     * rrd->stat_head->ds_cnt;
637                 ii++){
638                 fwrite(&unknown,sizeof(rrd_value_t),1,rrd_file);
639             }
640         }
641
642     /* lets see if we had an error */
643     if(ferror(rrd_file)){
644         rrd_set_error("a file error occurred while creating '%s'",file_name);
645         fclose(rrd_file);       
646         rrd_free(rrd);
647         return(-1);
648     }
649
650     fclose(rrd_file);    
651     rrd_free(rrd);
652     return (0);
653 }