Code

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