int rrd_tune(int argc, char **argv) { rrd_t rrd; FILE *rrd_file; int matches; int optcnt = 0; long ds; char ds_nam[DS_NAM_SIZE]; char ds_new[DS_NAM_SIZE]; long heartbeat; double min; double max; char dst[DST_SIZE]; optind = 0; opterr = 0; /* initialize getopt */ if(rrd_open(argv[1],&rrd_file,&rrd, RRD_READWRITE)==-1){ return -1; } while (1){ static struct option long_options[] = { {"heartbeat", required_argument, 0, 'h'}, {"minimum", required_argument, 0, 'i'}, {"maximum", required_argument, 0, 'a'}, {"data-source-type", required_argument, 0, 'd'}, {"data-source-rename", required_argument, 0, 'r'}, /* added parameter tuning options for aberrant behavior detection */ {"deltapos",required_argument,0,'p'}, {"deltaneg",required_argument,0,'n'}, {"window-length",required_argument,0,'w'}, {"failure-threshold",required_argument,0,'f'}, {"alpha",required_argument,0,'x'}, {"beta",required_argument,0,'y'}, {"gamma",required_argument,0,'z'}, {"gamma-deviation",required_argument,0,'v'}, {"aberrant-reset",required_argument,0,'b'}, {0,0,0,0} }; int option_index = 0; int opt; opt = getopt_long(argc, argv, "h:i:a:d:r:p:n:w:f:x:y:z:v:b:", long_options, &option_index); if (opt == EOF) break; optcnt++; switch(opt) { case 'h': if ((matches = sscanf(optarg, DS_NAM_FMT ":%ld",ds_nam,&heartbeat)) != 2){ rrd_set_error("invalid arguments for heartbeat"); rrd_free(&rrd); fclose(rrd_file); return -1; } if ((ds=ds_match(&rrd,ds_nam))==-1){ rrd_free(&rrd); fclose(rrd_file); return -1; } rrd.ds_def[ds].par[DS_mrhb_cnt].u_cnt = heartbeat; break; case 'i': if ((matches = sscanf(optarg,DS_NAM_FMT ":%lf",ds_nam,&min)) <1){ rrd_set_error("invalid arguments for minimum ds value"); rrd_free(&rrd); fclose(rrd_file); return -1; } if ((ds=ds_match(&rrd,ds_nam))==-1){ rrd_free(&rrd); fclose(rrd_file); return -1; } if(matches == 1) min= DNAN; rrd.ds_def[ds].par[DS_min_val].u_val = min; break; case 'a': if ((matches = sscanf(optarg, DS_NAM_FMT ":%lf",ds_nam,&max)) <1){ rrd_set_error("invalid arguments for maximum ds value"); rrd_free(&rrd); fclose(rrd_file); return -1; } if ((ds=ds_match(&rrd,ds_nam))==-1){ rrd_free(&rrd); fclose(rrd_file); return -1; } if(matches == 1) max= DNAN; rrd.ds_def[ds].par[DS_max_val].u_val = max; break; case 'd': if ((matches = sscanf(optarg, DS_NAM_FMT ":" DST_FMT ,ds_nam,dst)) != 2){ rrd_set_error("invalid arguments for data source type"); rrd_free(&rrd); fclose(rrd_file); return -1; } if ((ds=ds_match(&rrd,ds_nam))==-1){ rrd_free(&rrd); fclose(rrd_file); return -1; } if ((int)dst_conv(dst) == -1){ rrd_free(&rrd); fclose(rrd_file); return -1; } strncpy(rrd.ds_def[ds].dst,dst,DST_SIZE-1); rrd.ds_def[ds].dst[DST_SIZE-1]='\0'; rrd.pdp_prep[ds].last_ds[0] = 'U'; rrd.pdp_prep[ds].last_ds[1] = 'N'; rrd.pdp_prep[ds].last_ds[2] = 'K'; rrd.pdp_prep[ds].last_ds[3] = 'N'; rrd.pdp_prep[ds].last_ds[4] = '\0'; break; case 'r': if ((matches = sscanf(optarg,DS_NAM_FMT ":" DS_NAM_FMT , ds_nam,ds_new)) != 2){ rrd_set_error("invalid arguments for data source type"); rrd_free(&rrd); fclose(rrd_file); return -1; } if ((ds=ds_match(&rrd,ds_nam))==-1){ rrd_free(&rrd); fclose(rrd_file); return -1; } strncpy(rrd.ds_def[ds].ds_nam,ds_new,DS_NAM_SIZE-1); rrd.ds_def[ds].ds_nam[DS_NAM_SIZE-1]='\0'; break; case 'p': if (set_deltaarg(&rrd,RRA_delta_pos,optarg)) { rrd_free(&rrd); return -1; } break; case 'n': if (set_deltaarg(&rrd,RRA_delta_neg,optarg)) { rrd_free(&rrd); return -1; } break; case 'f': if (set_windowarg(&rrd,RRA_failure_threshold,optarg)) { rrd_free(&rrd); return -1; } break; case 'w': if (set_windowarg(&rrd,RRA_window_len,optarg)) { rrd_free(&rrd); return -1; } break; case 'x': if (set_hwarg(&rrd,CF_HWPREDICT,RRA_hw_alpha,optarg)) { rrd_free(&rrd); return -1; } break; case 'y': if (set_hwarg(&rrd,CF_HWPREDICT,RRA_hw_beta,optarg)) { rrd_free(&rrd); return -1; } break; case 'z': if (set_hwarg(&rrd,CF_SEASONAL,RRA_seasonal_gamma,optarg)) { rrd_free(&rrd); return -1; } break; case 'v': if (set_hwarg(&rrd,CF_DEVSEASONAL,RRA_seasonal_gamma,optarg)) { rrd_free(&rrd); return -1; } break; case 'b': if (sscanf(optarg,DS_NAM_FMT,ds_nam) != 1){ rrd_set_error("invalid argument for aberrant-reset"); rrd_free(&rrd); fclose(rrd_file); return -1; } if ((ds=ds_match(&rrd,ds_nam))==-1){ /* ds_match handles it own errors */ rrd_free(&rrd); fclose(rrd_file); return -1; } reset_aberrant_coefficients(&rrd,rrd_file,(unsigned long) ds); if (rrd_test_error()) { rrd_free(&rrd); fclose(rrd_file); return -1; } break; case '?': if (optopt != 0) rrd_set_error("unknown option '%c'", optopt); else rrd_set_error("unknown option '%s'",argv[optind-1]); rrd_free(&rrd); fclose(rrd_file); return -1; } } if(optcnt>0){ fseek(rrd_file,0,SEEK_SET); fwrite(rrd.stat_head, sizeof(stat_head_t),1, rrd_file); fwrite(rrd.ds_def, sizeof(ds_def_t), rrd.stat_head->ds_cnt, rrd_file); /* need to write rra_defs for RRA parameter changes */ fwrite(rrd.rra_def, sizeof(rra_def_t), rrd.stat_head->rra_cnt, rrd_file); } else { int i; for(i=0;i< (int)rrd.stat_head->ds_cnt;i++) if (dst_conv(rrd.ds_def[i].dst) != DST_CDEF) { printf("DS[%s] typ: %s\thbt: %ld\tmin: %1.4f\tmax: %1.4f\n", rrd.ds_def[i].ds_nam, rrd.ds_def[i].dst, rrd.ds_def[i].par[DS_mrhb_cnt].u_cnt, rrd.ds_def[i].par[DS_min_val].u_val, rrd.ds_def[i].par[DS_max_val].u_val); } else { char *buffer = NULL; rpn_compact2str((rpn_cdefds_t *) &(rrd.ds_def[i].par[DS_cdef]),rrd.ds_def,&buffer); printf("DS[%s] typ: %s\tcdef: %s\n", rrd.ds_def[i].ds_nam,rrd.ds_def[i].dst,buffer); free(buffer); } } fclose(rrd_file); rrd_free(&rrd); return 0; }
int rrd_tune( int argc, char **argv) { rrd_t rrd; int matches; int optcnt = 0; long ds; char ds_nam[DS_NAM_SIZE]; char ds_new[DS_NAM_SIZE]; long heartbeat; double min = 0; double max = 0; char dst[DST_SIZE]; int rc = -1; int opt_newstep = -1; rrd_file_t *rrd_file = NULL; char *opt_daemon = NULL; char double_str[ 41 ] = {0}; const char *in_filename = NULL; struct optparse_long longopts[] = { {"heartbeat", 'h', OPTPARSE_REQUIRED}, {"minimum", 'i', OPTPARSE_REQUIRED}, {"maximum", 'a', OPTPARSE_REQUIRED}, {"data-source-type", 'd', OPTPARSE_REQUIRED}, {"data-source-rename", 'r', OPTPARSE_REQUIRED}, /* added parameter tuning options for aberrant behavior detection */ {"deltapos", 'p', OPTPARSE_REQUIRED}, {"deltaneg", 'n', OPTPARSE_REQUIRED}, {"window-length", 'w', OPTPARSE_REQUIRED}, {"failure-threshold", 'f', OPTPARSE_REQUIRED}, {"alpha", 'x', OPTPARSE_REQUIRED}, {"beta", 'y', OPTPARSE_REQUIRED}, {"gamma", 'z', OPTPARSE_REQUIRED}, {"gamma-deviation", 'v', OPTPARSE_REQUIRED}, {"smoothing-window", 's', OPTPARSE_REQUIRED}, {"smoothing-window-deviation", 'S', OPTPARSE_REQUIRED}, {"aberrant-reset", 'b', OPTPARSE_REQUIRED}, // integration of rrd_modify functionality. {"step", 't', OPTPARSE_REQUIRED}, /* unfortunately, '-d' is already taken */ {"daemon", 'D', OPTPARSE_REQUIRED}, {0} }; struct optparse options; int opt; rrd_thread_init(); /* Fix CWE-457 */ memset(&rrd, 0, sizeof(rrd_t)); /* before we open the input RRD, we should flush it from any caching daemon, because we might totally rewrite it later on */ /* for this, we FIRST have to find the daemon, this means we must parse options twice... */ optparse_init(&options, argc, argv); while ((opt = optparse_long(&options, longopts, NULL)) != -1) { switch (opt) { case 'D': if (opt_daemon != NULL) free (opt_daemon); opt_daemon = strdup (options.optarg); if (opt_daemon == NULL) { rrd_set_error ("strdup failed."); return (-1); } break; default: break; } } // connect to daemon (will take care of environment variable automatically) if (rrdc_connect(opt_daemon) != 0) { rrd_set_error("Cannot connect to daemon"); free(opt_daemon); return 1; } if (opt_daemon) { free(opt_daemon); opt_daemon = NULL; } if (!options.optind || options.optind >= options.argc) { // missing file name... rrd_set_error("missing file name"); goto done; } /* NOTE: optparse_long reorders argv and places all NON option arguments to the back, starting with optind. This means the file name has travelled to options.argv[options.optind] */ in_filename = options.argv[options.optind]; if (rrdc_is_any_connected()) { // is it a good idea to just ignore the error ???? rrdc_flush(in_filename); rrd_clear_error(); } rrd_init(&rrd); rrd_file = rrd_open(in_filename, &rrd, RRD_READWRITE | RRD_READAHEAD | RRD_READVALUES); if (rrd_file == NULL) { goto done; } optparse_init(&options, argc, argv); /* re-initialize optparse */ while ((opt = optparse_long(&options, longopts, NULL)) != -1) { unsigned int strtod_ret_val; optcnt++; switch (opt) { case 'h': if ((matches = sscanf(options.optarg, DS_NAM_FMT ":%ld", ds_nam, &heartbeat)) != 2) { rrd_set_error("invalid arguments for heartbeat"); goto done; } if ((ds = ds_match(&rrd, ds_nam)) == -1) { goto done; } rrd.ds_def[ds].par[DS_mrhb_cnt].u_cnt = heartbeat; break; case 'i': matches = sscanf(options.optarg, DS_NAM_FMT ":%40[U0-9.e+-]", ds_nam, double_str); if ( matches == 2 ) { if (strcmp(double_str,"U") == 0){ min = DNAN; } else { strtod_ret_val = rrd_strtodbl( double_str, NULL, &min, NULL ); if ((strtod_ret_val != 2)) { rrd_set_error("invalid arguments for minimum ds value"); goto done; } } } else { rrd_set_error("invalid arguments for minimum ds value"); goto done; } if ((ds = ds_match(&rrd, ds_nam)) == -1) { goto done; } rrd.ds_def[ds].par[DS_min_val].u_val = min; break; case 'a': matches = sscanf(options.optarg, DS_NAM_FMT ":%40[U0-9.e+-]", ds_nam, double_str); if ( matches == 2 ) { if (strcmp(double_str,"U") == 0){ max = DNAN; } else { strtod_ret_val = rrd_strtodbl( double_str, NULL, &max, NULL ); if ((strtod_ret_val != 2)) { rrd_set_error("invalid arguments for maximum ds value"); goto done; } } } else { rrd_set_error("invalid arguments for maximum ds value"); goto done; } if ((ds = ds_match(&rrd, ds_nam)) == -1) { goto done; } rrd.ds_def[ds].par[DS_max_val].u_val = max; break; case 'd': if ((matches = sscanf(options.optarg, DS_NAM_FMT ":" DST_FMT, ds_nam, dst)) != 2) { rrd_set_error("invalid arguments for data source type"); goto done; } if ((ds = ds_match(&rrd, ds_nam)) == -1) { goto done; } if ((int) dst_conv(dst) == -1) { goto done; } /* only reset when something is changed */ if (strncmp(rrd.ds_def[ds].dst, dst, DST_SIZE - 1) != 0) { strncpy(rrd.ds_def[ds].dst, dst, DST_SIZE - 1); rrd.ds_def[ds].dst[DST_SIZE - 1] = '\0'; rrd.pdp_prep[ds].last_ds[0] = 'U'; rrd.pdp_prep[ds].last_ds[1] = 'N'; rrd.pdp_prep[ds].last_ds[2] = 'K'; rrd.pdp_prep[ds].last_ds[3] = 'N'; rrd.pdp_prep[ds].last_ds[4] = '\0'; } break; case 'r': if ((matches = sscanf(options.optarg, DS_NAM_FMT ":" DS_NAM_FMT, ds_nam, ds_new)) != 2) { rrd_set_error("invalid arguments for data source type"); goto done; } if ((ds = ds_match(&rrd, ds_nam)) == -1) { goto done; } strncpy(rrd.ds_def[ds].ds_nam, ds_new, DS_NAM_SIZE - 1); rrd.ds_def[ds].ds_nam[DS_NAM_SIZE - 1] = '\0'; break; case 'p': if (set_deltaarg(&rrd, RRA_delta_pos, options.optarg)) { goto done; } break; case 'n': if (set_deltaarg(&rrd, RRA_delta_neg, options.optarg)) { goto done; } break; case 'f': if (set_windowarg(&rrd, RRA_failure_threshold, options.optarg)) { goto done; } break; case 'w': if (set_windowarg(&rrd, RRA_window_len, options.optarg)) { goto done; } break; case 'x': if (set_hwarg(&rrd, CF_HWPREDICT, RRA_hw_alpha, options.optarg)) { if (set_hwarg(&rrd, CF_MHWPREDICT, RRA_hw_alpha, options.optarg)) { goto done; } rrd_clear_error(); } break; case 'y': if (set_hwarg(&rrd, CF_HWPREDICT, RRA_hw_beta, options.optarg)) { if (set_hwarg(&rrd, CF_MHWPREDICT, RRA_hw_beta, options.optarg)) { goto done; } rrd_clear_error(); } break; case 'z': if (set_hwarg(&rrd, CF_SEASONAL, RRA_seasonal_gamma, options.optarg)) { goto done; } break; case 'v': if (set_hwarg(&rrd, CF_DEVSEASONAL, RRA_seasonal_gamma, options.optarg)) { goto done; } break; case 'b': if (sscanf(options.optarg, DS_NAM_FMT, ds_nam) != 1) { rrd_set_error("invalid argument for aberrant-reset"); goto done; } if ((ds = ds_match(&rrd, ds_nam)) == -1) { /* ds_match handles it own errors */ goto done; } reset_aberrant_coefficients(&rrd, rrd_file, (unsigned long) ds); if (rrd_test_error()) { goto done; } break; case 's': if (atoi(rrd.stat_head->version) < atoi(RRD_VERSION4)) { strcpy(rrd.stat_head->version, RRD_VERSION4); /* smoothing_window causes Version 4 */ } if (set_hwsmootharg (&rrd, CF_SEASONAL, RRA_seasonal_smoothing_window, options.optarg)) { goto done; } break; case 'S': if (atoi(rrd.stat_head->version) < atoi(RRD_VERSION4)) { strcpy(rrd.stat_head->version, RRD_VERSION4); /* smoothing_window causes Version 4 */ } if (set_hwsmootharg (&rrd, CF_DEVSEASONAL, RRA_seasonal_smoothing_window, options.optarg)) { goto done; } break; case 't': opt_newstep = atoi(options.optarg); break; case 'D': // ignore, handled in previous argv parsing round break; case '?': rrd_set_error("%s", options.errmsg); goto done; } } if (optcnt > 0) { rrd_seek(rrd_file, 0, SEEK_SET); rrd_write(rrd_file, rrd.stat_head, sizeof(stat_head_t) * 1); rrd_write(rrd_file, rrd.ds_def, sizeof(ds_def_t) * rrd.stat_head->ds_cnt); /* need to write rra_defs for RRA parameter changes */ rrd_write(rrd_file, rrd.rra_def, sizeof(rra_def_t) * rrd.stat_head->rra_cnt); } if (options.optind >= options.argc) { int i; for (i = 0; i < (int) rrd.stat_head->ds_cnt; i++) if (dst_conv(rrd.ds_def[i].dst) != DST_CDEF) { printf("DS[%s] typ: %s\thbt: %ld\tmin: %1.4f\tmax: %1.4f\n", rrd.ds_def[i].ds_nam, rrd.ds_def[i].dst, rrd.ds_def[i].par[DS_mrhb_cnt].u_cnt, rrd.ds_def[i].par[DS_min_val].u_val, rrd.ds_def[i].par[DS_max_val].u_val); } else { char *buffer = NULL; rpn_compact2str((rpn_cdefds_t *) & (rrd.ds_def[i].par[DS_cdef]), rrd.ds_def, &buffer); printf("DS[%s] typ: %s\tcdef: %s\n", rrd.ds_def[i].ds_nam, rrd.ds_def[i].dst, buffer); if (buffer) free(buffer); } } optind = handle_modify(&rrd, in_filename, options.argc, options.argv, options.optind + 1, opt_newstep); rc = 0; done: if (in_filename && rrdc_is_any_connected()) { // save any errors.... char *e = strdup(rrd_get_error()); // is it a good idea to just ignore the error ???? rrdc_forget(in_filename); rrd_clear_error(); if (e && *e) { rrd_set_error(e); } if (e) free(e); } if (rrd_file) { rrd_close(rrd_file); } rrd_free(&rrd); return rc; }