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