int rrd_xport( int argc, char **argv, int UNUSED(*xsize), time_t *start, time_t *end, /* which time frame do you want ? * will be changed to represent reality */ unsigned long *step, /* which stepsize do you want? * will be changed to represent reality */ unsigned long *col_cnt, /* number of data columns in the result */ char ***legend_v, /* legend entries */ rrd_value_t **data) { /* two dimensional array containing the data */ image_desc_t im; time_t start_tmp = 0, end_tmp = 0; rrd_time_value_t start_tv, end_tv; char *parsetime_error = NULL; struct optparse options; optparse_init(&options, argc, argv); struct optparse_long longopts[] = { {"start", 's', OPTPARSE_REQUIRED}, {"end", 'e', OPTPARSE_REQUIRED}, {"maxrows",'m', OPTPARSE_REQUIRED}, {"step", 261, OPTPARSE_REQUIRED}, {"enumds", 262, OPTPARSE_NONE}, {"json", 263, OPTPARSE_NONE}, {"showtime", 't', OPTPARSE_NONE}, {"daemon", 'd', OPTPARSE_REQUIRED}, {0} }; rrd_thread_init(); rrd_graph_init(&im, IMAGE_INIT_NO_CAIRO); rrd_parsetime("end-24h", &start_tv); rrd_parsetime("now", &end_tv); int enumds=0; int json=0; int showtime=0; int opt; while ((opt = optparse_long(&options,longopts,NULL)) != -1){ switch (opt) { case 261: im.step = atoi(options.optarg); break; case 262: enumds=1; break; case 263: json=1; break; case 't': showtime=1; break; case 's': if ((parsetime_error = rrd_parsetime(options.optarg, &start_tv))) { rrd_set_error("start time: %s", parsetime_error); return -1; } break; case 'e': if ((parsetime_error = rrd_parsetime(options.optarg, &end_tv))) { rrd_set_error("end time: %s", parsetime_error); return -1; } break; case 'm': im.xsize = atol(options.optarg); if (im.xsize < 10) { rrd_set_error("maxrows below 10 rows"); return -1; } break; case 'd': { if (im.daemon_addr != NULL) { rrd_set_error ("You cannot specify --daemon " "more than once."); return (-1); } im.daemon_addr = strdup(options.optarg); if (im.daemon_addr == NULL) { rrd_set_error("strdup error"); return -1; } break; } case '?': rrd_set_error("%s", options.errmsg); return -1; } } if (rrd_proc_start_end(&start_tv, &end_tv, &start_tmp, &end_tmp) == -1) { return -1; } if (start_tmp < 3600 * 24 * 365 * 10) { rrd_set_error("the first entry to fetch should be after 1980 (%ld)", start_tmp); return -1; } if (end_tmp < start_tmp) { rrd_set_error("start (%ld) should be less than end (%ld)", start_tmp, end_tmp); return -1; } im.start = start_tmp; im.end = end_tmp; im.step = max((long) im.step, (im.end - im.start) / im.xsize); rrd_graph_script(options.argc, options.argv, &im, options.optind); if (rrd_test_error()) { im_free(&im); return -1; } if (im.gdes_c == 0) { rrd_set_error("can't make an xport without contents"); im_free(&im); return (-1); } { /* try to connect to rrdcached */ int status = rrdc_connect(im.daemon_addr); if (status != 0) return status; } if (rrd_xport_fn(&im, start, end, step, col_cnt, legend_v, data,0) == -1) { im_free(&im); return -1; } /* and create the export */ if (!xsize) { int flags=0; if (json) { flags|=1; } if (showtime) { flags|=2; } if (enumds) { flags|=4; } stringbuffer_t buffer={0,0,NULL,stdout}; rrd_xport_format_xmljson(flags,&buffer,&im, *start, *end, *step, *col_cnt, *legend_v, *data); } im_free(&im); 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; }