979926ff85ae55a7635ac7b95d03af17f6b2fdc1
[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 }