int getDouble(const char* v, double *val,char**extra) { /* try to execute the parser */ /* NOTE that this may be a bit different from the original parser */ *extra=NULL; /* see rrd_strtodbl's return values for more information */ switch (rrd_strtodbl( v, extra, val, NULL)){ case 0: return -1; break; case 1: return 1; break; case 2: return 0; break; default: return -2; break; } }
int set_hwsmootharg( rrd_t *rrd, enum cf_en cf, enum rra_par_en rra_par, char *arg) { double param; unsigned long i; signed short rra_idx = -1; unsigned int strtod_ret_val; /* read the value */ strtod_ret_val = rrd_strtodbl(arg, NULL, ¶m, NULL); /* in order to avoid smoothing of SEASONAL or DEVSEASONAL, we need to * the 0.0 value*/ if ( (strtod_ret_val == 1 || strtod_ret_val == 2 ) && (param < 0.0 || param > 1.0) ) { rrd_set_error("Holt-Winters parameter must be between 0 and 1"); return -1; } else if( strtod_ret_val == 0 || strtod_ret_val > 2 ) { rrd_set_error("Unable to parse Holt-Winters parameter"); return -1; } /* does the appropriate RRA exist? */ for (i = 0; i < rrd->stat_head->rra_cnt; ++i) { if (cf_conv(rrd->rra_def[i].cf_nam) == cf) { rra_idx = i; break; } } if (rra_idx == -1) { rrd_set_error("Holt-Winters RRA does not exist in this RRD"); return -1; } /* set the value */ rrd->rra_def[rra_idx].par[rra_par].u_val = param; return 0; }
static int get_xml_double( xmlTextReaderPtr reader, double *value) { xmlChar *text; double temp; if ((text = get_xml_text(reader))!= NULL){ if (xmlStrcasestr(text,(xmlChar *)"nan")){ *value = DNAN; xmlFree(text); return 0; } else if (xmlStrcasestr(text,(xmlChar *)"-inf")){ *value = -DINF; xmlFree(text); return 0; } else if (xmlStrcasestr(text,(xmlChar *)"+inf") || xmlStrcasestr(text,(xmlChar *)"inf")){ *value = DINF; xmlFree(text); return 0; } if ( rrd_strtodbl((char *)text,NULL, &temp, NULL) != 2 ){ rrd_set_error("ling %d: get_xml_double from '%s' %s", xmlTextReaderGetParserLineNumber(reader), text,rrd_strerror(errno)); xmlFree(text); return -1; } xmlFree(text); *value = temp; return 0; } return -1; } /* get_xml_double */
int set_deltaarg( rrd_t *rrd, enum rra_par_en rra_par, char *arg) { rrd_value_t param; unsigned long i; signed short rra_idx = -1; unsigned int strtod_ret_val; strtod_ret_val = rrd_strtodbl(arg, NULL, ¶m, NULL); if ((strtod_ret_val == 1 || strtod_ret_val == 2) && param < 0.1) { rrd_set_error("Parameter specified is too small"); return -1; } else if( strtod_ret_val == 1 || strtod_ret_val > 2 ) { rrd_set_error("Unable to parse parameter in set_deltaarg"); return -1; } /* does the appropriate RRA exist? */ for (i = 0; i < rrd->stat_head->rra_cnt; ++i) { if (cf_conv(rrd->rra_def[i].cf_nam) == CF_FAILURES) { rra_idx = i; break; } } if (rra_idx == -1) { rrd_set_error("Failures RRA does not exist in this RRD"); return -1; } /* set the value */ rrd->rra_def[rra_idx].par[rra_par].u_val = param; 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[ 12 ]; const char *in_filename = NULL; 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'}, {"smoothing-window", required_argument, 0, 's'}, {"smoothing-window-deviation", required_argument, 0, 'S'}, {"aberrant-reset", required_argument, 0, 'b'}, // integration of rrd_modify functionality. {"step", required_argument, 0, 't'}, /* unfortunately, '-d' is already taken */ {"daemon", required_argument, 0, 'D'}, {0, 0, 0, 0} }; optind = 0; opterr = 0; /* initialize getopt */ /* 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... */ while (1) { int option_index = 0; int 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; switch (opt) { case 'D': if (opt_daemon != NULL) free (opt_daemon); opt_daemon = strdup (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"); return 1; } if (opt_daemon) { free(opt_daemon); opt_daemon = NULL; } if (optind < 0 || optind >= argc) { // missing file name... rrd_set_error("missing file name"); goto done; } /* NOTE: getopt_long reorders argv and places all NON option arguments to the back, starting with optind. This means the file name has travelled to argv[optind] */ in_filename = argv[optind]; if (rrdc_is_any_connected()) { // is it a good idea to just ignore the error ???? rrdc_flush(in_filename); rrd_clear_error(); } optind = 0; opterr = 0; /* re-initialize getopt */ rrd_init(&rrd); rrd_file = rrd_open(in_filename, &rrd, RRD_READWRITE | RRD_READAHEAD | RRD_READVALUES); if (rrd_file == NULL) { goto done; } while (1) { int option_index = 0; int opt; unsigned int strtod_ret_val; 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"); 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(optarg, DS_NAM_FMT ":%[0-9.e+-]", ds_nam, double_str); if( matches >= 1 ) { strtod_ret_val = rrd_strtodbl( double_str, NULL, &min, NULL ); } if ((matches < 1) || (strtod_ret_val != 2)) { rrd_set_error("invalid arguments for minimum ds value"); goto done; } if ((ds = ds_match(&rrd, ds_nam)) == -1) { goto done; } if (matches == 1) min = DNAN; rrd.ds_def[ds].par[DS_min_val].u_val = min; break; case 'a': matches = sscanf(optarg, DS_NAM_FMT ":%[0-9.e+-]", ds_nam, double_str); if( matches >= 1 ) { strtod_ret_val = rrd_strtodbl( double_str, NULL, &max, NULL ); } if ((matches < 1 ) || (strtod_ret_val != 2)) { rrd_set_error("invalid arguments for maximum ds value"); goto done; } if ((ds = ds_match(&rrd, ds_nam)) == -1) { goto done; } 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"); 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(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, optarg)) { goto done; } break; case 'n': if (set_deltaarg(&rrd, RRA_delta_neg, optarg)) { goto done; } break; case 'f': if (set_windowarg(&rrd, RRA_failure_threshold, optarg)) { goto done; } break; case 'w': if (set_windowarg(&rrd, RRA_window_len, optarg)) { goto done; } break; case 'x': if (set_hwarg(&rrd, CF_HWPREDICT, RRA_hw_alpha, optarg)) { if (set_hwarg(&rrd, CF_MHWPREDICT, RRA_hw_alpha, optarg)) { goto done; } rrd_clear_error(); } break; case 'y': if (set_hwarg(&rrd, CF_HWPREDICT, RRA_hw_beta, optarg)) { if (set_hwarg(&rrd, CF_MHWPREDICT, RRA_hw_beta, optarg)) { goto done; } rrd_clear_error(); } break; case 'z': if (set_hwarg(&rrd, CF_SEASONAL, RRA_seasonal_gamma, optarg)) { goto done; } break; case 'v': if (set_hwarg(&rrd, CF_DEVSEASONAL, RRA_seasonal_gamma, optarg)) { goto done; } break; case 'b': if (sscanf(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, 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, optarg)) { goto done; } break; case 't': opt_newstep = atoi(optarg); break; case 'D': // ignore, handled in previous argv parsing round break; case '?': if (optopt != 0) rrd_set_error("unknown option '%c'", optopt); else rrd_set_error("unknown option '%s'", argv[optind - 1]); 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 (optind >= 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, argc, argv, optind + 1, opt_newstep); if (optind < 0) { goto done; } 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; }
double rrd_diff( char *a, char *b) { char res[LAST_DS_LEN + 1], *a1, *b1, *r1, *fix; int c, x, m; char a_neg = 0, b_neg = 0; double result; while (!(isdigit((int) *a) || *a == 0)) { if (*a == '-') a_neg = 1; a++; } fix = a; while (isdigit((int) *fix)) fix++; *fix = 0; /* maybe there is some non digit data in the string */ while (!(isdigit((int) *b) || *b == 0)) { if (*b == '-') b_neg = 1; b++; } fix = b; while (isdigit((int) *fix)) fix++; *fix = 0; /* maybe there is some non digit data in the string */ if (!isdigit((int) *a) || !isdigit((int) *b)) return DNAN; if (a_neg + b_neg == 1) /* can not handle numbers with different signs yet */ return DNAN; a1 = &a[strlen(a) - 1]; m = max(strlen(a), strlen(b)); if (m > LAST_DS_LEN) return DNAN; /* result string too short */ r1 = &res[m + 1]; for (b1 = res; b1 <= r1; b1++) *b1 = ' '; b1 = &b[strlen(b) - 1]; r1[1] = 0; /* Null terminate result */ c = 0; for (x = 0; x < m; x++) { if (a1 >= a && b1 >= b) { *r1 = ((*a1 - c) - *b1) + '0'; } else if (a1 >= a) { *r1 = (*a1 - c); } else { *r1 = ('0' - *b1 - c) + '0'; } if (*r1 < '0') { *r1 += 10; c = 1; } else if (*r1 > '9') { /* 0 - 10 */ *r1 -= 10; c = 1; } else { c = 0; } a1--; b1--; r1--; } if (c) { r1 = &res[m + 1]; for (x = 0; isdigit((int) *r1) && x < m; x++, r1--) { *r1 = ('9' - *r1 + c) + '0'; if (*r1 > '9') { *r1 -= 10; c = 1; } else { c = 0; } } if (rrd_strtodbl(res, NULL, &result, "expected a number") != 2){ result = DNAN; } else { result = -result; } } else { if (rrd_strtodbl(res, NULL, &result, "expected a number") != 2){ result = DNAN; } } if (a_neg + b_neg == 2) /* both are negatives, reverse sign */ result = -result; return result; }
static double rrd_fetch_dbi_double(dbi_result *result,int idx) { char *ptmp=""; double value=DNAN; /* get the attributes for this filed */ unsigned int attr=dbi_result_get_field_attribs_idx(result,idx); unsigned int type=dbi_result_get_field_type_idx(result,idx); unsigned int strtod_ret_val; /* return NAN if NULL */ if(dbi_result_field_is_null_idx(result,idx)) { return DNAN; } /* do some conversions */ switch (type) { case DBI_TYPE_STRING: ptmp=(char*)dbi_result_get_string_idx(result,idx); strtod_ret_val = rrd_strtodbl(ptmp,NULL, &value, "rrd_fetch_dbi_double, DBI_TYPE_STRING"); if( strtod_ret_val == 1 || strtod_ret_val == 2 ) { break; } else { value = DNAN; break; } case DBI_TYPE_INTEGER: if (attr & DBI_INTEGER_SIZE1) { value=dbi_result_get_char_idx(result,idx); } else if (attr & DBI_INTEGER_SIZE2) { value=dbi_result_get_short_idx(result,idx); } else if (attr & DBI_INTEGER_SIZE3) { value=dbi_result_get_int_idx(result,idx); } else if (attr & DBI_INTEGER_SIZE4) { value=dbi_result_get_int_idx(result,idx); } else if (attr & DBI_INTEGER_SIZE8) { value=dbi_result_get_longlong_idx(result,idx); } else { value=DNAN; if (getenv("RRDDEBUGSQL")) { fprintf(stderr,"RRDDEBUGSQL: %li: column %i unsupported attribute flags %i for type INTEGER\n",time(NULL),idx,attr ); } } break; case DBI_TYPE_DECIMAL: if (attr & DBI_DECIMAL_SIZE4) { value=dbi_result_get_float_idx(result,idx); } else if (attr & DBI_DECIMAL_SIZE8) { value=dbi_result_get_double_idx(result,idx); } else { value=DNAN; if (getenv("RRDDEBUGSQL")) { fprintf(stderr,"RRDDEBUGSQL: %li: column %i unsupported attribute flags %i for type DECIMAL\n",time(NULL),idx,attr ); } } break; case DBI_TYPE_BINARY: attr=dbi_result_get_field_length_idx(result,idx); ptmp=(char*)dbi_result_get_binary_copy_idx(result,idx); ptmp[attr-1]=0; /* check for "known" libdbi error */ if (strncmp("ERROR",ptmp,5)==0) { if (!getenv("RRD_NO_LIBDBI_BUG_WARNING")) { fprintf(stderr,"rrdtool_fetch_libDBI: you have possibly triggered a bug in libDBI by using a (TINY,MEDIUM,LONG) TEXT field with mysql\n this may trigger a core dump in at least one version of libdbi\n if you are not touched by this bug and you find this message annoying\n please set the environment-variable RRD_NO_LIBDBI_BUG_WARNING to ignore this message\n"); } } /* convert to number */ strtod_ret_val = rrd_strtodbl(ptmp,NULL, &value, "rrd_fetch_dbi_double, DBI_TYPE_BINARY"); /* free pointer */ free(ptmp); break; case DBI_TYPE_DATETIME: value=dbi_result_get_datetime_idx(result,idx); break; default: if (getenv("RRDDEBUGSQL")) { fprintf(stderr,"RRDDEBUGSQL: %li: column %i unsupported type: %i with attribute %i\n",time(NULL),idx,type,attr ); } value=DNAN; break; } return value; }