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