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