Exemplo n.º 1
0
time_t rrd_last_r(
    const char *filename)
{
    time_t    lastup = -1;
    rrd_file_t *rrd_file;

    rrd_t     rrd;

    rrd_init(&rrd);
    rrd_file = rrd_open(filename, &rrd, RRD_READONLY);
    if (rrd_file != NULL) {
        lastup = rrd.live_head->last_up;
        rrd_close(rrd_file);
    }
    rrd_free(&rrd);
    return (lastup);
}
Exemplo n.º 2
0
time_t rrd_first_r(
    const char *filename,
    const int rraindex)
{
    off_t     rra_start, timer;
    time_t    then = -1;
    rrd_t     rrd;
    rrd_file_t *rrd_file;

    rrd_init(&rrd);
    rrd_file = rrd_open(filename, &rrd, RRD_READONLY);
    if (rrd_file == NULL) {
        goto err_free;
    }

    if ((rraindex < 0) || (rraindex >= (int) rrd.stat_head->rra_cnt)) {
        rrd_set_error("invalid rraindex number");
        goto err_close;
    }

    rra_start = rrd_file->header_len;
    rrd_seek(rrd_file,
             (rra_start +
              (rrd.rra_ptr[rraindex].cur_row + 1) *
              rrd.stat_head->ds_cnt * sizeof(rrd_value_t)), SEEK_SET);
    timer = -(long)(rrd.rra_def[rraindex].row_cnt - 1);
    if (rrd.rra_ptr[rraindex].cur_row + 1 > rrd.rra_def[rraindex].row_cnt) {
        rrd_seek(rrd_file, rra_start, SEEK_SET);
    }
    then = (rrd.live_head->last_up -
            rrd.live_head->last_up %
            (rrd.rra_def[rraindex].pdp_cnt * rrd.stat_head->pdp_step)) +
        (timer * rrd.rra_def[rraindex].pdp_cnt * rrd.stat_head->pdp_step);
  err_close:
    rrd_close(rrd_file);
  err_free:
    rrd_free(&rrd);
    return (then);
}
Exemplo n.º 3
0
/* #define DEBUG */
int rrd_create_r( const char *filename, unsigned long pdp_step,
		time_t last_up, int argc, const char **argv) {
	rrd_t     rrd;
	long      i;
	int       offset;
	char     *token;
	char      dummychar1[2], dummychar2[2];
	unsigned short token_idx, error_flag, period = 0;
	unsigned long hashed_name;
	int       ret = 0;

	/* init rrd clean */
	rrd_init(&rrd);
	/* static header */
	if ((rrd.stat_head = (stat_head_t*)calloc(1, sizeof(stat_head_t))) == NULL) {
		rrd_free2(&rrd);
		return -RRD_ERR_ALLOC;
	}

	/* live header */
	if ((rrd.live_head = (live_head_t*)calloc(1, sizeof(live_head_t))) == NULL) {
		rrd_free2(&rrd);
		return -RRD_ERR_ALLOC;
	}

	/* set some defaults */
	strcpy(rrd.stat_head->cookie, RRD_COOKIE);
	strcpy(rrd.stat_head->version, RRD_VERSION3);   /* by default we are still version 3 */
	rrd.stat_head->float_cookie = FLOAT_COOKIE;
	rrd.stat_head->ds_cnt = 0;  /* this will be adjusted later */
	rrd.stat_head->rra_cnt = 0; /* ditto */
	rrd.stat_head->pdp_step = pdp_step; /* 5 minute default */

	/* a default value */
	rrd.ds_def = NULL;
	rrd.rra_def = NULL;

	rrd.live_head->last_up = last_up;

	/* optind points to the first non-option command line arg,
	 * in this case, the file name. */
	/* Compute the FNV hash value (used by SEASONAL and DEVSEASONAL
	 * arrays. */
	hashed_name = FnvHash(filename);
	for (i = 0; i < argc; i++) {
		unsigned int ii;

		if (strncmp(argv[i], "DS:", 3) == 0) {
			size_t    old_size = sizeof(ds_def_t) * (rrd.stat_head->ds_cnt);

			if ((rrd.ds_def = (ds_def_t*)rrd_realloc(rrd.ds_def,
							old_size + sizeof(ds_def_t))) ==
					NULL) {
				rrd_free2(&rrd);
				return -RRD_ERR_ALLOC;
			}
			memset(&rrd.ds_def[rrd.stat_head->ds_cnt], 0, sizeof(ds_def_t));
			/* extract the name and type */
			switch (sscanf(&argv[i][3],
						DS_NAM_FMT "%1[:]" DST_FMT "%1[:]%n",
						rrd.ds_def[rrd.stat_head->ds_cnt].ds_nam,
						dummychar1,
						rrd.ds_def[rrd.stat_head->ds_cnt].dst,
						dummychar2, &offset)) {
				case 0:
				case 1:
					ret = -RRD_ERR_INVALID_DS_NAME;
					break;
				case 2:
				case 3:
					ret = -RRD_ERR_INVALID_DS_TYPE;
					break;
				case 4:    /* (%n may or may not be counted) */
				case 5:    /* check for duplicate datasource names */
					for (ii = 0; ii < rrd.stat_head->ds_cnt; ii++)
						if (strcmp(rrd.ds_def[rrd.stat_head->ds_cnt].ds_nam,
									rrd.ds_def[ii].ds_nam) == 0)
							ret = -RRD_ERR_DUPLICATE_DS_NAME;
					/* DS_type may be valid or not. Checked later */
					break;
				default:
					ret = -RRD_ERR_INVALID_DS_FORMAT;
			}
			if (ret) {
				rrd_free2(&rrd);
				return ret;
			}

			/* parse the remainder of the arguments */
			switch (dst_conv(rrd.ds_def[rrd.stat_head->ds_cnt].dst)) {
				case DST_COUNTER:
				case DST_ABSOLUTE:
				case DST_GAUGE:
				case DST_DERIVE:
					ret = parseGENERIC_DS(&argv[i][offset + 3], &rrd,
							rrd.stat_head->ds_cnt);
					break;
				case DST_CDEF:
					ret = parseCDEF_DS(&argv[i][offset + 3], &rrd,
							rrd.stat_head->ds_cnt);
					break;
				default:
					ret = -RRD_ERR_INVALID_DS_TYPE_SPEC;
					break;
			}

			if (ret) {
				rrd_free2(&rrd);
				return ret;
			}
			rrd.stat_head->ds_cnt++;
		} else if (strncmp(argv[i], "RRA:", 4) == 0) {
			char     *argvcopy;
			char     *tokptr = "";
			int       cf_id = -1;
			size_t    old_size = sizeof(rra_def_t) * (rrd.stat_head->rra_cnt);
			int       row_cnt;
			int       token_min = 4;
			if ((rrd.rra_def = (rra_def_t*)rrd_realloc(rrd.rra_def,
							old_size + sizeof(rra_def_t))) ==
					NULL) {
				rrd_free2(&rrd);
				return -RRD_ERR_ALLOC;
			}
			memset(&rrd.rra_def[rrd.stat_head->rra_cnt], 0,
					sizeof(rra_def_t));

			argvcopy = strdup(argv[i]);
			token = strtok_r(&argvcopy[4], ":", &tokptr);
			token_idx = error_flag = 0;

			while (token != NULL) {
				switch (token_idx) {
					case 0:
						if (sscanf(token, CF_NAM_FMT,
									rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam) !=
								1)
							ret = -RRD_ERR_FAILED_PARSE_CF_NAME;
						cf_id = cf_conv(rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam);
						switch (cf_id) {
							case CF_MHWPREDICT:
								strcpy(rrd.stat_head->version, RRD_VERSION);    /* MHWPREDICT causes Version 4 */
							case CF_HWPREDICT:
								token_min = 5;
								/* initialize some parameters */
								rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_hw_alpha].
									u_val = 0.1;
								rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_hw_beta].
									u_val = 1.0 / 288;
								rrd.rra_def[rrd.stat_head->rra_cnt].
									par[RRA_dependent_rra_idx].u_cnt =
									rrd.stat_head->rra_cnt;
								break;
							case CF_DEVSEASONAL:
								token_min = 3;
							case CF_SEASONAL:
								if (cf_id == CF_SEASONAL){
									token_min = 4;
								}
								/* initialize some parameters */
								rrd.rra_def[rrd.stat_head->rra_cnt].
									par[RRA_seasonal_gamma].u_val = 0.1;
								rrd.rra_def[rrd.stat_head->rra_cnt].
									par[RRA_seasonal_smoothing_window].u_val = 0.05;
								/* fall through */
							case CF_DEVPREDICT:
								if (cf_id == CF_DEVPREDICT){
									token_min = 3;
								}
								rrd.rra_def[rrd.stat_head->rra_cnt].
									par[RRA_dependent_rra_idx].u_cnt = -1;
								break;
							case CF_FAILURES:
								token_min = 5;
								rrd.rra_def[rrd.stat_head->rra_cnt].
									par[RRA_delta_pos].u_val = 2.0;
								rrd.rra_def[rrd.stat_head->rra_cnt].
									par[RRA_delta_neg].u_val = 2.0;
								rrd.rra_def[rrd.stat_head->rra_cnt].
									par[RRA_window_len].u_cnt = 3;
								rrd.rra_def[rrd.stat_head->rra_cnt].
									par[RRA_failure_threshold].u_cnt = 2;
								rrd.rra_def[rrd.stat_head->rra_cnt].
									par[RRA_dependent_rra_idx].u_cnt = -1;
								break;
								/* invalid consolidation function */
							case -1:
								ret = -RRD_ERR_UNREC_CONSOLIDATION_FUNC;
							default:
								break;
						}
						/* default: 1 pdp per cdp */
						rrd.rra_def[rrd.stat_head->rra_cnt].pdp_cnt = 1;
						break;
					case 1:
						switch (cf_conv(rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam)) {
							case CF_HWPREDICT:
							case CF_MHWPREDICT:
							case CF_DEVSEASONAL:
							case CF_SEASONAL:
							case CF_DEVPREDICT:
							case CF_FAILURES:
								row_cnt = atoi(token);
								if (row_cnt <= 0)
									ret = -RRD_ERR_INVALID_ROW_COUNT;
								rrd.rra_def[rrd.stat_head->rra_cnt].row_cnt = row_cnt;
								break;
							default:
								rrd.rra_def[rrd.stat_head->rra_cnt].
									par[RRA_cdp_xff_val].u_val = atof(token);
								if (rrd.rra_def[rrd.stat_head->rra_cnt].
										par[RRA_cdp_xff_val].u_val < 0.0
										|| rrd.rra_def[rrd.stat_head->rra_cnt].
										par[RRA_cdp_xff_val].u_val >= 1.0)
									ret = -RRD_ERR_INVALID_XFF;
								break;
						}
						break;
					case 2:
						switch (cf_conv
								(rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam)) {
							case CF_HWPREDICT:
							case CF_MHWPREDICT:
								rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_hw_alpha].
									u_val = atof(token);
								if (atof(token) <= 0.0 || atof(token) >= 1.0)
									ret = -RRD_ERR_INVALID_ALPHA;
								break;
							case CF_DEVSEASONAL:
							case CF_SEASONAL:
								rrd.rra_def[rrd.stat_head->rra_cnt].
									par[RRA_seasonal_gamma].u_val = atof(token);
								if (atof(token) <= 0.0 || atof(token) >= 1.0)
									ret = -RRD_ERR_INVALID_GAMMA;
								rrd.rra_def[rrd.stat_head->rra_cnt].
									par[RRA_seasonal_smooth_idx].u_cnt =
									hashed_name %
									rrd.rra_def[rrd.stat_head->rra_cnt].row_cnt;
								break;
							case CF_FAILURES:
								/* specifies the # of violations that constitutes the failure threshold */
								rrd.rra_def[rrd.stat_head->rra_cnt].
									par[RRA_failure_threshold].u_cnt = atoi(token);
								if (atoi(token) < 1
										|| atoi(token) > MAX_FAILURES_WINDOW_LEN)
									ret = -RRD_ERR_FAILURE_THRESHOLD_OUT_OF_RANGE;
								break;
							case CF_DEVPREDICT:
								/* specifies the index (1-based) of CF_DEVSEASONAL array
								 * associated with this CF_DEVPREDICT array. */
								rrd.rra_def[rrd.stat_head->rra_cnt].
									par[RRA_dependent_rra_idx].u_cnt =
									atoi(token) - 1;
								break;
							default:
								rrd.rra_def[rrd.stat_head->rra_cnt].pdp_cnt =
									atoi(token);
								if (atoi(token) < 1)
									ret = -RRD_ERR_INVALID_STEP;
								break;
						}
						break;
					case 3:
						switch (cf_conv(rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam)) {
							case CF_HWPREDICT:
							case CF_MHWPREDICT:
								rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_hw_beta].
									u_val = atof(token);
								if (atof(token) < 0.0 || atof(token) > 1.0)
									ret = -RRD_ERR_INVALID_BETA;
								break;
							case CF_DEVSEASONAL:
							case CF_SEASONAL:
								/* specifies the index (1-based) of CF_HWPREDICT array
								 * associated with this CF_DEVSEASONAL or CF_SEASONAL array. 
								 * */
								rrd.rra_def[rrd.stat_head->rra_cnt].
									par[RRA_dependent_rra_idx].u_cnt =
									atoi(token) - 1;
								break;
							case CF_FAILURES:
								/* specifies the window length */
								rrd.rra_def[rrd.stat_head->rra_cnt].
									par[RRA_window_len].u_cnt = atoi(token);
								if (atoi(token) < 1
										|| atoi(token) > MAX_FAILURES_WINDOW_LEN)
									ret = RRD_ERR_WIN_LEN_OUT_OF_RANGE;
								/* verify that window length exceeds the failure threshold */
								if (rrd.rra_def[rrd.stat_head->rra_cnt].
										par[RRA_window_len].u_cnt <
										rrd.rra_def[rrd.stat_head->rra_cnt].
										par[RRA_failure_threshold].u_cnt)
									ret = -RRD_ERR_WINLEN_SHORTER_FAILURE_THRESHOLD;
								break;
							case CF_DEVPREDICT:
								/* shouldn't be any more arguments */
								ret = -RRD_ERR_INVALID_ARG1;
								break;
							default:
								row_cnt = atoi(token);
								if (row_cnt <= 0)
									ret = -RRD_ERR_INVALID_ROW_COUNT;
#if SIZEOF_TIME_T == 4
								if ((long long) pdp_step * rrd.rra_def[rrd.stat_head->rra_cnt].pdp_cnt * row_cnt > 4294967296LL){
									/* database timespan > 2**32, would overflow time_t */
									ret = -RRD_ERR_TIME_TOO_LARGE;
								}
#endif
								rrd.rra_def[rrd.stat_head->rra_cnt].row_cnt = row_cnt;
								break;
						}
						break;
					case 4:
						switch (cf_conv(rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam)) {
							case CF_FAILURES:
								/* specifies the index (1-based) of CF_DEVSEASONAL array
								 * associated with this CF_DEVFAILURES array. */
								rrd.rra_def[rrd.stat_head->rra_cnt].
									par[RRA_dependent_rra_idx].u_cnt =
									atoi(token) - 1;
								break;
							case CF_DEVSEASONAL:
							case CF_SEASONAL:
								/* optional smoothing window */
								if (sscanf(token, "smoothing-window=%lf",
											&(rrd.rra_def[rrd.stat_head->rra_cnt].
												par[RRA_seasonal_smoothing_window].
												u_val))) {
									strcpy(rrd.stat_head->version, RRD_VERSION);    /* smoothing-window causes Version 4 */
									if (rrd.rra_def[rrd.stat_head->rra_cnt].
											par[RRA_seasonal_smoothing_window].u_val < 0.0
											|| rrd.rra_def[rrd.stat_head->rra_cnt].
											par[RRA_seasonal_smoothing_window].u_val >
											1.0) {
										ret = -RRD_ERR_INVALID_SMOOTHING_WINDOW;
									}
								} else {
									ret = -RRD_ERR_INVALID_OPT;
								}
								break;
							case CF_HWPREDICT:
							case CF_MHWPREDICT:
								/* length of the associated CF_SEASONAL and CF_DEVSEASONAL arrays. */
								period = atoi(token);
								if (period >
										rrd.rra_def[rrd.stat_head->rra_cnt].row_cnt)
									ret = -RRD_ERR_LEN_OF_SEASONAL_CYCLE;
								break;
							default:
								/* shouldn't be any more arguments */
								ret = -RRD_ERR_INVALID_ARG2;
								break;
						}
						break;
					case 5:
						/* If we are here, this must be a CF_HWPREDICT RRA.
						 * Specifies the index (1-based) of CF_SEASONAL array
						 * associated with this CF_HWPREDICT array. If this argument 
						 * is missing, then the CF_SEASONAL, CF_DEVSEASONAL, CF_DEVPREDICT,
						 * CF_FAILURES.
						 * arrays are created automatically. */
						rrd.rra_def[rrd.stat_head->rra_cnt].
							par[RRA_dependent_rra_idx].u_cnt = atoi(token) - 1;
						break;
					default:
						/* should never get here */
						ret = -RRD_ERR_UNKNOWN_ERROR;
						break;
				}       /* end switch */
				if (ret) {
					/* all errors are unrecoverable */
					free(argvcopy);
					rrd_free2(&rrd);
					return ret;
				}
				token = strtok_r(NULL, ":", &tokptr);
				token_idx++;
			}           /* end while */
			free(argvcopy);
			if (token_idx < token_min){
				rrd_free2(&rrd);
				return(-RRD_ERR_ARG3);
			}
#ifdef DEBUG
			fprintf(stderr,
					"Creating RRA CF: %s, dep idx %lu, current idx %lu\n",
					rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam,
					rrd.rra_def[rrd.stat_head->rra_cnt].
					par[RRA_dependent_rra_idx].u_cnt, rrd.stat_head->rra_cnt);
#endif
			/* should we create CF_SEASONAL, CF_DEVSEASONAL, and CF_DEVPREDICT? */
			if ((cf_conv(rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam) ==
						CF_HWPREDICT
						|| cf_conv(rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam) ==
						CF_MHWPREDICT)
					&& rrd.rra_def[rrd.stat_head->rra_cnt].
					par[RRA_dependent_rra_idx].u_cnt == rrd.stat_head->rra_cnt) {
#ifdef DEBUG
				fprintf(stderr, "Creating HW contingent RRAs\n");
#endif
				if (create_hw_contingent_rras(&rrd, period, hashed_name) ==
						-1) {
					rrd_free2(&rrd);
					return (-RRD_ERR_CREATING_RRA);
				}
			}
			rrd.stat_head->rra_cnt++;
		} else {
			rrd_free2(&rrd);
			return (-RRD_ERR_ARG4);
		}
	}


	if (rrd.stat_head->rra_cnt < 1) {
		rrd_free2(&rrd);
		return (-RRD_ERR_ARG5);
	}

	if (rrd.stat_head->ds_cnt < 1) {
		rrd_free2(&rrd);
		return (-RRD_ERR_ARG6);
	}
	return rrd_create_fn(filename, &rrd);
}
Exemplo n.º 4
0
int rrd_dump_cb_r(
    const char *filename,
    int opt_header,
    rrd_output_callback_t cb,
    void *user)
{
    unsigned int i, ii, ix, iii = 0;
    time_t    now;
    char      somestring[255];
    rrd_value_t my_cdp;
    off_t     rra_base, rra_start, rra_next;
    rrd_file_t *rrd_file;
    rrd_t     rrd;
    rrd_value_t value;
    struct tm tm;

//These two macros are local defines to clean up visible code from its redndancy
//and make it easier to read.
#define CB_PUTS(str)                                            \
    do {							\
        size_t len = strlen(str);				\
								\
        if (cb((str), len, user) != len)                        \
            goto err_out;                                       \
    } while (0);
#define CB_FMTS(...) do {                                       \
    char buffer[256];                                           \
    rrd_snprintf (buffer, sizeof(buffer), __VA_ARGS__);         \
    CB_PUTS (buffer);                                           \
    } while (0)
//These macros are to be undefined at the end of this function

    //Check if we got a (valid) callback method
    if (!cb) {
        return (-1);
    }

    rrd_init(&rrd);

    rrd_file = rrd_open(filename, &rrd, RRD_READONLY | RRD_READAHEAD);
    if (rrd_file == NULL) {
        rrd_free(&rrd);
        return (-1);
    }

    if (opt_header == 1) {
        CB_PUTS("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
        CB_PUTS("<!DOCTYPE rrd SYSTEM \"http://oss.oetiker.ch/rrdtool/rrdtool.dtd\">\n");
        CB_PUTS("<!-- Round Robin Database Dump -->\n");
        CB_PUTS("<rrd>\n");
    } else if (opt_header == 2) {
        CB_PUTS("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
        CB_PUTS("<!-- Round Robin Database Dump -->\n");
        CB_PUTS("<rrd xmlns=\"http://oss.oetiker.ch/rrdtool/rrdtool-dump.xml\" "
                "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n");
        CB_PUTS("\txsi:schemaLocation=\"http://oss.oetiker.ch/rrdtool/rrdtool-dump.xml "
                "http://oss.oetiker.ch/rrdtool/rrdtool-dump.xsd\">\n");
    } else {
        CB_PUTS("<!-- Round Robin Database Dump -->\n");
        CB_PUTS("<rrd>\n");
    }

    if (atoi(rrd.stat_head->version) <= 3) {
        CB_FMTS("\t<version>%s</version>\n", RRD_VERSION3);
    } else {
        CB_FMTS("\t<version>%s</version>\n", rrd.stat_head->version);
    }
    
    CB_FMTS("\t<step>%lu</step> <!-- Seconds -->\n",
        rrd.stat_head->pdp_step);

#ifdef HAVE_STRFTIME
    localtime_r(&rrd.live_head->last_up, &tm);
    strftime(somestring, 255, "%Y-%m-%d %H:%M:%S %Z", &tm);
#else
# error "Need strftime"
#endif
    CB_FMTS("\t<lastupdate>%lld</lastupdate> <!-- %s -->\n\n",
        (long long int) rrd.live_head->last_up, somestring);
    for (i = 0; i < rrd.stat_head->ds_cnt; i++) {
        CB_PUTS("\t<ds>\n");

        CB_FMTS("\t\t<name> %s </name>\n", rrd.ds_def[i].ds_nam);

        CB_FMTS("\t\t<type> %s </type>\n", rrd.ds_def[i].dst);

        if (dst_conv(rrd.ds_def[i].dst) != DST_CDEF) {
            CB_FMTS("\t\t<minimal_heartbeat>%lu</minimal_heartbeat>\n",
                    rrd.ds_def[i].par[DS_mrhb_cnt].u_cnt);

            if (isnan(rrd.ds_def[i].par[DS_min_val].u_val)) {
                CB_PUTS("\t\t<min>NaN</min>\n");
            } else {
                CB_FMTS("\t\t<min>%0.10e</min>\n",
                    rrd.ds_def[i].par[DS_min_val].u_val);
            }
            
            if (isnan(rrd.ds_def[i].par[DS_max_val].u_val)) {
                CB_PUTS("\t\t<max>NaN</max>\n");
            } else {
                CB_FMTS("\t\t<max>%0.10e</max>\n",
                    rrd.ds_def[i].par[DS_max_val].u_val);
            }
        } else {        /* DST_CDEF */
            char     *str = NULL;

            rpn_compact2str((rpn_cdefds_t *) &(rrd.ds_def[i].par[DS_cdef]),
                rrd.ds_def, &str);

            //Splitting into 3 writes to avoid allocating memory
            //This is better compared to snprintf as str may be of arbitrary size
            CB_PUTS("\t\t<cdef> ");
            CB_PUTS(str);
            CB_PUTS(" </cdef>\n");

            free(str);
        }

        CB_PUTS("\n\t\t<!-- PDP Status -->\n");
        CB_FMTS("\t\t<last_ds>%s</last_ds>\n",
            rrd.pdp_prep[i].last_ds);

        if (isnan(rrd.pdp_prep[i].scratch[PDP_val].u_val)) {
            CB_PUTS("\t\t<value>NaN</value>\n");
        } else {
            CB_FMTS("\t\t<value>%0.10e</value>\n",
                rrd.pdp_prep[i].scratch[PDP_val].u_val);
        }

        CB_FMTS("\t\t<unknown_sec> %lu </unknown_sec>\n",
            rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt);

        CB_PUTS("\t</ds>\n\n");
    }

    CB_PUTS("\t<!-- Round Robin Archives -->\n");

    rra_base = rrd_file->header_len;
    rra_next = rra_base;

    for (i = 0; i < rrd.stat_head->rra_cnt; i++) {

        long      timer = 0;

        rra_start = rra_next;
        rra_next += (rrd.stat_head->ds_cnt
                     * rrd.rra_def[i].row_cnt * sizeof(rrd_value_t));

        CB_PUTS("\t<rra>\n");

        CB_FMTS("\t\t<cf>%s</cf>\n", rrd.rra_def[i].cf_nam);

        CB_FMTS("\t\t<pdp_per_row>%lu</pdp_per_row> <!-- %lu seconds -->\n\n",
            rrd.rra_def[i].pdp_cnt, 
            rrd.rra_def[i].pdp_cnt * rrd.stat_head->pdp_step);

        /* support for RRA parameters */
        CB_PUTS("\t\t<params>\n");

        switch (cf_conv(rrd.rra_def[i].cf_nam)) {
        case CF_HWPREDICT:
        case CF_MHWPREDICT:
            CB_FMTS("\t\t<hw_alpha>%0.10e</hw_alpha>\n",
                rrd.rra_def[i].par[RRA_hw_alpha].u_val);

            CB_FMTS("\t\t<hw_beta>%0.10e</hw_beta>\n",
                rrd.rra_def[i].par[RRA_hw_beta].u_val);

            CB_FMTS("\t\t<dependent_rra_idx>%lu</dependent_rra_idx>\n",
                rrd.rra_def[i].par[RRA_dependent_rra_idx].u_cnt);
            break;
        case CF_SEASONAL:
        case CF_DEVSEASONAL:
            CB_FMTS("\t\t<seasonal_gamma>%0.10e</seasonal_gamma>\n",
                rrd.rra_def[i].par[RRA_seasonal_gamma].u_val);

            CB_FMTS("\t\t<seasonal_smooth_idx>%lu</seasonal_smooth_idx>\n",
                rrd.rra_def[i].par[RRA_seasonal_smooth_idx].u_cnt);

            if (atoi(rrd.stat_head->version) >= 4) {
                CB_FMTS("\t\t<smoothing_window>%0.10e</smoothing_window>\n",
                    rrd.rra_def[i].par[RRA_seasonal_smoothing_window].u_val);
            }

            CB_FMTS("\t\t<dependent_rra_idx>%lu</dependent_rra_idx>\n",
                rrd.rra_def[i].par[RRA_dependent_rra_idx].u_cnt);
            break;
        case CF_FAILURES:
            CB_FMTS("\t\t<delta_pos>%0.10e</delta_pos>\n",
                rrd.rra_def[i].par[RRA_delta_pos].u_val);

            CB_FMTS("\t\t<delta_neg>%0.10e</delta_neg>\n",
                rrd.rra_def[i].par[RRA_delta_neg].u_val);

            CB_FMTS("\t\t<window_len>%lu</window_len>\n",
                rrd.rra_def[i].par[RRA_window_len].u_cnt);

            CB_FMTS("\t\t<failure_threshold>%lu</failure_threshold>\n",
                rrd.rra_def[i].par[RRA_failure_threshold].u_cnt);

            /* fall thru */
        case CF_DEVPREDICT:
            CB_FMTS("\t\t<dependent_rra_idx>%lu</dependent_rra_idx>\n",
                rrd.rra_def[i].par[RRA_dependent_rra_idx].u_cnt);
            break;
        case CF_AVERAGE:
        case CF_MAXIMUM:
        case CF_MINIMUM:
        case CF_LAST:
        default:
            CB_FMTS("\t\t<xff>%0.10e</xff>\n",
                rrd.rra_def[i].par[RRA_cdp_xff_val].u_val);
            break;
        }

        CB_PUTS("\t\t</params>\n");
        CB_PUTS("\t\t<cdp_prep>\n");

        for (ii = 0; ii < rrd.stat_head->ds_cnt; ii++) {
            unsigned long ivalue;

            CB_PUTS("\t\t\t<ds>\n");
            /* support for exporting all CDP parameters */
            /* parameters common to all CFs */
            /* primary_val and secondary_val do not need to be saved between updates
             * so strictly speaking they could be omitted.
             * However, they can be useful for diagnostic purposes, so are included here. */
            value = rrd.cdp_prep[i * rrd.stat_head->ds_cnt + ii].
                scratch[CDP_primary_val].u_val;
            if (isnan(value)) {
                CB_PUTS("\t\t\t<primary_value>NaN</primary_value>\n");
            } else {
                CB_FMTS("\t\t\t<primary_value>%0.10e</primary_value>\n", value);
            }

            value = rrd.cdp_prep[i * rrd.stat_head->ds_cnt + ii].
                scratch[CDP_secondary_val].u_val;
            if (isnan(value)) {
                CB_PUTS("\t\t\t<secondary_value>NaN</secondary_value>\n");
            } else {
                CB_FMTS("\t\t\t<secondary_value>%0.10e</secondary_value>\n", value);
            }

            switch (cf_conv(rrd.rra_def[i].cf_nam)) {
            case CF_HWPREDICT:
            case CF_MHWPREDICT:
                value = rrd.cdp_prep[i * rrd.stat_head->ds_cnt + ii].
                    scratch[CDP_hw_intercept].u_val;
                if (isnan(value)) {
                    CB_PUTS("\t\t\t<intercept>NaN</intercept>\n");
                } else {
                    CB_FMTS("\t\t\t<intercept>%0.10e</intercept>\n", value);
                }

                value = rrd.cdp_prep[i * rrd.stat_head->ds_cnt + ii].
                    scratch[CDP_hw_last_intercept].u_val;
                if (isnan(value)) {
                    CB_PUTS("\t\t\t<last_intercept>NaN</last_intercept>\n");
                } else {
                    CB_FMTS("\t\t\t<last_intercept>%0.10e</last_intercept>\n", value);
                }

                value = rrd.cdp_prep[i * rrd.stat_head->ds_cnt + ii].
                    scratch[CDP_hw_slope].u_val;
                if (isnan(value)) {
                    CB_PUTS("\t\t\t<slope>NaN</slope>\n");
                } else {
                    CB_FMTS("\t\t\t<slope>%0.10e</slope>\n", value);
                }

                value = rrd.cdp_prep[i * rrd.stat_head->ds_cnt + ii].
                    scratch[CDP_hw_last_slope].u_val;
                if (isnan(value)) {
                    CB_PUTS("\t\t\t<last_slope>NaN</last_slope>\n");
                } else {
                    CB_FMTS("\t\t\t<last_slope>%0.10e</last_slope>\n", value);
                }

                ivalue = rrd.cdp_prep[i * rrd.stat_head->ds_cnt + ii].
                    scratch[CDP_null_count].u_cnt;
                CB_FMTS("\t\t\t<nan_count>%lu</nan_count>\n", ivalue);

                ivalue = rrd.cdp_prep[i * rrd.stat_head->ds_cnt + ii].
                    scratch[CDP_last_null_count].u_cnt;
                CB_FMTS("\t\t\t<last_nan_count>%lu</last_nan_count>\n", ivalue);
                break;
            case CF_SEASONAL:
            case CF_DEVSEASONAL:
                value = rrd.cdp_prep[i * rrd.stat_head->ds_cnt + ii].
                    scratch[CDP_hw_seasonal].u_val;
                if (isnan(value)) {
                    CB_PUTS("\t\t\t<seasonal>NaN</seasonal>\n");
                } else {
                    CB_FMTS("\t\t\t<seasonal>%0.10e</seasonal>\n", value);
                }

                value = rrd.cdp_prep[i * rrd.stat_head->ds_cnt + ii].
                    scratch[CDP_hw_last_seasonal].u_val;
                if (isnan(value)) {
                    CB_PUTS("\t\t\t<last_seasonal>NaN</last_seasonal>\n");
                } else {
                    CB_FMTS("\t\t\t<last_seasonal>%0.10e</last_seasonal>\n", value);
                }

                ivalue = rrd.cdp_prep[i * rrd.stat_head->ds_cnt + ii].
                    scratch[CDP_init_seasonal].u_cnt;
                CB_FMTS("\t\t\t<init_flag>%lu</init_flag>\n", ivalue);
                break;
            case CF_DEVPREDICT:
                break;
            case CF_FAILURES:
            {
                unsigned short vidx;
                char *violations_array = (char *) ((void *)
                    rrd.cdp_prep[i * rrd.stat_head->ds_cnt + ii].scratch);
                CB_PUTS("\t\t\t<history>");
                for (vidx = 0;
                    vidx < rrd.rra_def[i].par[RRA_window_len].u_cnt;
                    ++vidx) {
                    CB_FMTS("%d", violations_array[vidx]);
                }
                CB_PUTS("</history>\n");
            }
                break;
            case CF_AVERAGE:
            case CF_MAXIMUM:
            case CF_MINIMUM:
            case CF_LAST:
            default:
                value = rrd.cdp_prep[i * rrd.stat_head->ds_cnt + ii].scratch[CDP_val].u_val;
                if (isnan(value)) {
                    CB_PUTS("\t\t\t<value>NaN</value>\n");
                } else {
                    CB_FMTS("\t\t\t<value>%0.10e</value>\n", value);
                }

                CB_FMTS("\t\t\t<unknown_datapoints>%lu</unknown_datapoints>\n",
                    rrd.cdp_prep[i * rrd.stat_head->ds_cnt + ii].
                        scratch[CDP_unkn_pdp_cnt].u_cnt);
                break;
            }
            CB_PUTS("\t\t\t</ds>\n");
        }
        CB_PUTS("\t\t</cdp_prep>\n");

        CB_PUTS("\t\t<database>\n");
        rrd_seek(rrd_file, (rra_start + (rrd.rra_ptr[i].cur_row + 1)
                            * rrd.stat_head->ds_cnt
                            * sizeof(rrd_value_t)), SEEK_SET);
        timer = -(long)(rrd.rra_def[i].row_cnt - 1);
        ii = rrd.rra_ptr[i].cur_row;
        for (ix = 0; ix < rrd.rra_def[i].row_cnt; ix++) {
            ii++;
            if (ii >= rrd.rra_def[i].row_cnt) {
                rrd_seek(rrd_file, rra_start, SEEK_SET);
                ii = 0; /* wrap if max row cnt is reached */
            }
            now = (rrd.live_head->last_up
                   - rrd.live_head->last_up
                   % (rrd.rra_def[i].pdp_cnt * rrd.stat_head->pdp_step))
                + (timer * rrd.rra_def[i].pdp_cnt * rrd.stat_head->pdp_step);

            timer++;
#if HAVE_STRFTIME
            localtime_r(&now, &tm);
            strftime(somestring, 255, "%Y-%m-%d %H:%M:%S %Z", &tm);
#else
# error "Need strftime"
#endif
            CB_FMTS("\t\t\t<!-- %s / %lld --> <row>",  somestring, (long long int) now);
            for (iii = 0; iii < rrd.stat_head->ds_cnt; iii++) {
                rrd_read(rrd_file, &my_cdp, sizeof(rrd_value_t) * 1);
                if (isnan(my_cdp)) {
                    CB_PUTS("<v>NaN</v>");
                } else {
                    CB_FMTS("<v>%0.10e</v>", my_cdp);
                }
            }
            CB_PUTS("</row>\n");
        }
        CB_PUTS("\t\t</database>\n\t</rra>\n");
    }

    CB_PUTS("</rrd>\n");

    rrd_free(&rrd);

    return rrd_close(rrd_file);

err_out:
    rrd_set_error("error writing output file: %s", rrd_strerror(errno));
    rrd_free(&rrd);
    rrd_close(rrd_file);
    return (-1);

//Undefining the previously defined shortcuts
//See start of this function
#undef CB_PUTS
#undef CB_FMTS
//End of macro undefining

}
Exemplo n.º 5
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;
}
Exemplo n.º 6
0
int main(int argc, char **argv) {
    int i;
    int config_loaded = 0;
    int dont_fork = 0;
    size_t default_stacksize;

    // set the name for logging
    program_name = "netdata";

    // parse depercated options
    // TODO: Remove this block with the next major release.
    {
        i = 1;
        while(i < argc) {
            if(strcmp(argv[i], "-pidfile") == 0 && (i+1) < argc) {
                strncpyz(pidfile, argv[i+1], FILENAME_MAX);
                fprintf(stderr, "%s: deprecated option -- %s -- please use -P instead.\n", argv[0], argv[i]);
                remove_option(i, &argc, argv);
            }
            else if(strcmp(argv[i], "-nodaemon") == 0 || strcmp(argv[i], "-nd") == 0) {
                dont_fork = 1;
                fprintf(stderr, "%s: deprecated option -- %s -- please use -D instead.\n ", argv[0], argv[i]);
                remove_option(i, &argc, argv);
            }
            else if(strcmp(argv[i], "-ch") == 0 && (i+1) < argc) {
                config_set(CONFIG_SECTION_GLOBAL, "host access prefix", argv[i+1]);
                fprintf(stderr, "%s: deprecated option -- %s -- please use -s instead.\n", argv[0], argv[i]);
                remove_option(i, &argc, argv);
            }
            else if(strcmp(argv[i], "-l") == 0 && (i+1) < argc) {
                config_set(CONFIG_SECTION_GLOBAL, "history", argv[i+1]);
                fprintf(stderr, "%s: deprecated option -- %s -- This option will be removed with V2.*.\n", argv[0], argv[i]);
                remove_option(i, &argc, argv);
            }
            else i++;
        }
    }

    // parse options
    {
        int num_opts = sizeof(option_definitions) / sizeof(struct option_def);
        char optstring[(num_opts * 2) + 1];

        int string_i = 0;
        for( i = 0; i < num_opts; i++ ) {
            optstring[string_i] = option_definitions[i].val;
            string_i++;
            if(option_definitions[i].arg_name) {
                optstring[string_i] = ':';
                string_i++;
            }
        }
        // terminate optstring
        optstring[string_i] ='\0';
        optstring[(num_opts *2)] ='\0';

        int opt;
        while( (opt = getopt(argc, argv, optstring)) != -1 ) {
            switch(opt) {
                case 'c':
                    if(config_load(optarg, 1) != 1) {
                        error("Cannot load configuration file %s.", optarg);
                        return 1;
                    }
                    else {
                        debug(D_OPTIONS, "Configuration loaded from %s.", optarg);
                        config_loaded = 1;
                    }
                    break;
                case 'D':
                    dont_fork = 1;
                    break;
                case 'h':
                    return help(0);
                case 'i':
                    config_set(CONFIG_SECTION_WEB, "bind to", optarg);
                    break;
                case 'P':
                    strncpy(pidfile, optarg, FILENAME_MAX);
                    pidfile[FILENAME_MAX] = '\0';
                    break;
                case 'p':
                    config_set(CONFIG_SECTION_GLOBAL, "default port", optarg);
                    break;
                case 's':
                    config_set(CONFIG_SECTION_GLOBAL, "host access prefix", optarg);
                    break;
                case 't':
                    config_set(CONFIG_SECTION_GLOBAL, "update every", optarg);
                    break;
                case 'u':
                    config_set(CONFIG_SECTION_GLOBAL, "run as user", optarg);
                    break;
                case 'v':
                case 'V':
                    printf("%s %s\n", program_name, program_version);
                    return 0;
                case 'W':
                    {
                        char* stacksize_string = "stacksize=";
                        char* debug_flags_string = "debug_flags=";

                        if(strcmp(optarg, "unittest") == 0) {
                            if(unit_test_buffer()) return 1;
                            if(unit_test_str2ld()) return 1;
                            //default_rrd_update_every = 1;
                            //default_rrd_memory_mode = RRD_MEMORY_MODE_RAM;
                            //if(!config_loaded) config_load(NULL, 0);
                            get_netdata_configured_variables();
                            default_rrd_update_every = 1;
                            default_rrd_memory_mode = RRD_MEMORY_MODE_RAM;
                            default_health_enabled = 0;
                            rrd_init("unittest");
                            default_rrdpush_enabled = 0;
                            if(run_all_mockup_tests()) return 1;
                            if(unit_test_storage()) return 1;
                            fprintf(stderr, "\n\nALL TESTS PASSED\n\n");
                            return 0;
                        }
                        else if(strcmp(optarg, "simple-pattern") == 0) {
                            if(optind + 2 > argc) {
                                fprintf(stderr, "%s", "\nUSAGE: -W simple-pattern 'pattern' 'string'\n\n"
                                        " Checks if 'pattern' matches the given 'string'.\n"
                                        " - 'pattern' can be one or more space separated words.\n"
                                        " - each 'word' can contain one or more asterisks.\n"
                                        " - words starting with '!' give negative matches.\n"
                                        " - words are processed left to right\n"
                                        "\n"
                                        "Examples:\n"
                                        "\n"
                                        " > match all veth interfaces, except veth0:\n"
                                        "\n"
                                        "   -W simple-pattern '!veth0 veth*' 'veth12'\n"
                                        "\n"
                                        "\n"
                                        " > match all *.ext files directly in /path/:\n"
                                        "   (this will not match *.ext files in a subdir of /path/)\n"
                                        "\n"
                                        "   -W simple-pattern '!/path/*/*.ext /path/*.ext' '/path/test.ext'\n"
                                        "\n"
                                );
                                return 1;
                            }

                            const char *heystack = argv[optind];
                            const char *needle = argv[optind + 1];
                            size_t len = strlen(needle) + 1;
                            char wildcarded[len];

                            SIMPLE_PATTERN *p = simple_pattern_create(heystack, NULL, SIMPLE_PATTERN_EXACT);
                            int ret = simple_pattern_matches_extract(p, needle, wildcarded, len);
                            simple_pattern_free(p);

                            if(ret) {
                                fprintf(stdout, "RESULT: MATCHED - pattern '%s' matches '%s', wildcarded '%s'\n", heystack, needle, wildcarded);
                                return 0;
                            }
                            else {
                                fprintf(stdout, "RESULT: NOT MATCHED - pattern '%s' does not match '%s', wildcarded '%s'\n", heystack, needle, wildcarded);
                                return 1;
                            }
                        }
                        else if(strncmp(optarg, stacksize_string, strlen(stacksize_string)) == 0) {
                            optarg += strlen(stacksize_string);
                            config_set(CONFIG_SECTION_GLOBAL, "pthread stack size", optarg);
                        }
                        else if(strncmp(optarg, debug_flags_string, strlen(debug_flags_string)) == 0) {
                            optarg += strlen(debug_flags_string);
                            config_set(CONFIG_SECTION_GLOBAL, "debug flags",  optarg);
                            debug_flags = strtoull(optarg, NULL, 0);
                        }
                        else if(strcmp(optarg, "set") == 0) {
                            if(optind + 3 > argc) {
                                fprintf(stderr, "%s", "\nUSAGE: -W set 'section' 'key' 'value'\n\n"
                                        " Overwrites settings of netdata.conf.\n"
                                        "\n"
                                        " These options interact with: -c netdata.conf\n"
                                        " If -c netdata.conf is given on the command line,\n"
                                        " before -W set... the user may overwrite command\n"
                                        " line parameters at netdata.conf\n"
                                        " If -c netdata.conf is given after (or missing)\n"
                                        " -W set... the user cannot overwrite the command line\n"
                                        " parameters."
                                        "\n"
                                );
                                return 1;
                            }
                            const char *section = argv[optind];
                            const char *key = argv[optind + 1];
                            const char *value = argv[optind + 2];
                            optind += 3;

                            // set this one as the default
                            // only if it is not already set in the config file
                            // so the caller can use -c netdata.conf before or
                            // after this parameter to prevent or allow overwriting
                            // variables at netdata.conf
                            config_set_default(section, key,  value);

                            // fprintf(stderr, "SET section '%s', key '%s', value '%s'\n", section, key, value);
                        }
                        else if(strcmp(optarg, "get") == 0) {
                            if(optind + 3 > argc) {
                                fprintf(stderr, "%s", "\nUSAGE: -W get 'section' 'key' 'value'\n\n"
                                        " Prints settings of netdata.conf.\n"
                                        "\n"
                                        " These options interact with: -c netdata.conf\n"
                                        " -c netdata.conf has to be given before -W get.\n"
                                        "\n"
                                );
                                return 1;
                            }

                            if(!config_loaded) {
                                fprintf(stderr, "warning: no configuration file has been loaded. Use -c CONFIG_FILE, before -W get. Using default config.\n");
                                config_load(NULL, 0);
                            }

                            backwards_compatible_config();
                            get_netdata_configured_variables();

                            const char *section = argv[optind];
                            const char *key = argv[optind + 1];
                            const char *def = argv[optind + 2];
                            const char *value = config_get(section, key, def);
                            printf("%s\n", value);
                            return 0;
                        }
                        else {
                            fprintf(stderr, "Unknown -W parameter '%s'\n", optarg);
                            return help(1);
                        }
                    }
                    break;

                default: /* ? */
                    fprintf(stderr, "Unknown parameter '%c'\n", opt);
                    return help(1);
            }
        }
    }

#ifdef _SC_OPEN_MAX
    // close all open file descriptors, except the standard ones
    // the caller may have left open files (lxc-attach has this issue)
    {
        int fd;
        for(fd = (int) (sysconf(_SC_OPEN_MAX) - 1); fd > 2; fd--)
            if(fd_is_valid(fd)) close(fd);
    }
#endif

    if(!config_loaded)
        config_load(NULL, 0);

    // ------------------------------------------------------------------------
    // initialize netdata
    {
        char *pmax = config_get(CONFIG_SECTION_GLOBAL, "glibc malloc arena max for plugins", "1");
        if(pmax && *pmax)
            setenv("MALLOC_ARENA_MAX", pmax, 1);

#if defined(HAVE_C_MALLOPT)
        i = (int)config_get_number(CONFIG_SECTION_GLOBAL, "glibc malloc arena max for netdata", 1);
        if(i > 0)
            mallopt(M_ARENA_MAX, 1);
#endif

        // prepare configuration environment variables for the plugins

        get_netdata_configured_variables();
        set_global_environment();

        // work while we are cd into config_dir
        // to allow the plugins refer to their config
        // files using relative filenames
        if(chdir(netdata_configured_config_dir) == -1)
            fatal("Cannot cd to '%s'", netdata_configured_config_dir);
    }

    char *user = NULL;

    {
        // --------------------------------------------------------------------
        // get the debugging flags from the configuration file

        char *flags = config_get(CONFIG_SECTION_GLOBAL, "debug flags",  "0x0000000000000000");
        setenv("NETDATA_DEBUG_FLAGS", flags, 1);

        debug_flags = strtoull(flags, NULL, 0);
        debug(D_OPTIONS, "Debug flags set to '0x%" PRIX64 "'.", debug_flags);

        if(debug_flags != 0) {
            struct rlimit rl = { RLIM_INFINITY, RLIM_INFINITY };
            if(setrlimit(RLIMIT_CORE, &rl) != 0)
                error("Cannot request unlimited core dumps for debugging... Proceeding anyway...");

#ifdef HAVE_SYS_PRCTL_H
            prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
#endif
        }


        // --------------------------------------------------------------------
        // get log filenames and settings

        log_init();
        error_log_limit_unlimited();


        // --------------------------------------------------------------------
        // load stream.conf
        {
            char filename[FILENAME_MAX + 1];
            snprintfz(filename, FILENAME_MAX, "%s/stream.conf", netdata_configured_config_dir);
            appconfig_load(&stream_config, filename, 0);
        }


        // --------------------------------------------------------------------
        // setup process signals

        // block signals while initializing threads.
        // this causes the threads to block signals.
        signals_block();

        // setup the signals we want to use
        signals_init();

        // setup threads configs
        default_stacksize = netdata_threads_init();


        // --------------------------------------------------------------------
        // check which threads are enabled and initialize them

        for (i = 0; static_threads[i].name != NULL ; i++) {
            struct netdata_static_thread *st = &static_threads[i];

            if(st->config_name)
                st->enabled = config_get_boolean(st->config_section, st->config_name, st->enabled);

            if(st->enabled && st->init_routine)
                st->init_routine();
        }


        // --------------------------------------------------------------------
        // get the user we should run

        // IMPORTANT: this is required before web_files_uid()
        if(getuid() == 0) {
            user = config_get(CONFIG_SECTION_GLOBAL, "run as user", NETDATA_USER);
        }
        else {
            struct passwd *passwd = getpwuid(getuid());
            user = config_get(CONFIG_SECTION_GLOBAL, "run as user", (passwd && passwd->pw_name)?passwd->pw_name:"");
        }

        // --------------------------------------------------------------------
        // create the listening sockets

        web_client_api_v1_init();
        web_server_threading_selection();

        if(web_server_mode != WEB_SERVER_MODE_NONE)
            api_listen_sockets_setup();
    }

    // initialize the log files
    open_all_log_files();

#ifdef NETDATA_INTERNAL_CHECKS
    if(debug_flags != 0) {
        struct rlimit rl = { RLIM_INFINITY, RLIM_INFINITY };
        if(setrlimit(RLIMIT_CORE, &rl) != 0)
            error("Cannot request unlimited core dumps for debugging... Proceeding anyway...");
#ifdef HAVE_SYS_PRCTL_H
        prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
#endif
    }
#endif /* NETDATA_INTERNAL_CHECKS */

    // get the max file limit
    if(getrlimit(RLIMIT_NOFILE, &rlimit_nofile) != 0)
        error("getrlimit(RLIMIT_NOFILE) failed");
    else
        info("resources control: allowed file descriptors: soft = %zu, max = %zu", rlimit_nofile.rlim_cur, rlimit_nofile.rlim_max);

    // fork, switch user, create pid file, set process priority
    if(become_daemon(dont_fork, user) == -1)
        fatal("Cannot daemonize myself.");

    info("netdata started on pid %d.", getpid());

    // IMPORTANT: these have to run once, while single threaded
    // but after we have switched user
    web_files_uid();
    web_files_gid();

    netdata_threads_init_after_fork((size_t)config_get_number(CONFIG_SECTION_GLOBAL, "pthread stack size", (long)default_stacksize));

    // ------------------------------------------------------------------------
    // initialize rrd, registry, health, rrdpush, etc.

    rrd_init(netdata_configured_hostname);


    // ------------------------------------------------------------------------
    // enable log flood protection

    error_log_limit_reset();


    // ------------------------------------------------------------------------
    // spawn the threads

    web_server_config_options();

    for (i = 0; static_threads[i].name != NULL ; i++) {
        struct netdata_static_thread *st = &static_threads[i];

        if(st->enabled) {
            st->thread = mallocz(sizeof(netdata_thread_t));
            debug(D_SYSTEM, "Starting thread %s.", st->name);
            netdata_thread_create(st->thread, st->name, NETDATA_THREAD_OPTION_DEFAULT, st->start_routine, st);
        }
        else debug(D_SYSTEM, "Not starting thread %s.", st->name);
    }

    info("netdata initialization completed. Enjoy real-time performance monitoring!");


    // ------------------------------------------------------------------------
    // unblock signals

    signals_unblock();

    // ------------------------------------------------------------------------
    // Handle signals

    signals_handle();

    // should never reach this point
    // but we need it for rpmlint #2752
    return 1;
}
Exemplo n.º 7
0
rrd_info_t *rrd_info_r(
    const char *filename)
{
    unsigned int i, ii = 0;
    rrd_t     rrd;
    rrd_info_t *data = NULL, *cd;
    rrd_infoval_t info;
    rrd_file_t *rrd_file;
    enum cf_en current_cf;
    enum dst_en current_ds;

    rrd_init(&rrd);
    rrd_file = rrd_open(filename, &rrd, RRD_READONLY);
    if (rrd_file == NULL)
        goto err_free;

    info.u_str = filename;
    cd = rrd_info_push(NULL, sprintf_alloc("filename"), RD_I_STR, info);
    data = cd;

    info.u_str = rrd.stat_head->version;
    cd = rrd_info_push(cd, sprintf_alloc("rrd_version"), RD_I_STR, info);

    info.u_cnt = rrd.stat_head->pdp_step;
    cd = rrd_info_push(cd, sprintf_alloc("step"), RD_I_CNT, info);

    info.u_cnt = rrd.live_head->last_up;
    cd = rrd_info_push(cd, sprintf_alloc("last_update"), RD_I_CNT, info);

    info.u_cnt = rrd_get_header_size(&rrd);
    cd = rrd_info_push(cd, sprintf_alloc("header_size"), RD_I_CNT, info);

    for (i = 0; i < rrd.stat_head->ds_cnt; i++) {

        info.u_cnt=i;
        cd= rrd_info_push(cd,sprintf_alloc("ds[%s].index",
                                     rrd.ds_def[i].ds_nam),
                     RD_I_CNT, info);
    
        info.u_str = rrd.ds_def[i].dst;
        cd = rrd_info_push(cd, sprintf_alloc("ds[%s].type",
                                             rrd.ds_def[i].ds_nam),
                           RD_I_STR, info);

        current_ds = dst_conv(rrd.ds_def[i].dst);
        switch (current_ds) {
        case DST_CDEF:
        {
            char     *buffer = NULL;

            rpn_compact2str((rpn_cdefds_t *) &(rrd.ds_def[i].par[DS_cdef]),
                            rrd.ds_def, &buffer);
            info.u_str = buffer;
            cd = rrd_info_push(cd,
                               sprintf_alloc("ds[%s].cdef",
                                             rrd.ds_def[i].ds_nam), RD_I_STR,
                               info);
            free(buffer);
        }
            break;
        default:
            info.u_cnt = rrd.ds_def[i].par[DS_mrhb_cnt].u_cnt;
            cd = rrd_info_push(cd,
                               sprintf_alloc("ds[%s].minimal_heartbeat",
                                             rrd.ds_def[i].ds_nam), RD_I_CNT,
                               info);

            info.u_val = rrd.ds_def[i].par[DS_min_val].u_val;
            cd = rrd_info_push(cd,
                               sprintf_alloc("ds[%s].min",
                                             rrd.ds_def[i].ds_nam), RD_I_VAL,
                               info);

            info.u_val = rrd.ds_def[i].par[DS_max_val].u_val;
            cd = rrd_info_push(cd,
                               sprintf_alloc("ds[%s].max",
                                             rrd.ds_def[i].ds_nam), RD_I_VAL,
                               info);
            break;
        }

        info.u_str = rrd.pdp_prep[i].last_ds;
        cd = rrd_info_push(cd,
                           sprintf_alloc("ds[%s].last_ds",
                                         rrd.ds_def[i].ds_nam), RD_I_STR,
                           info);

        info.u_val = rrd.pdp_prep[i].scratch[PDP_val].u_val;
        cd = rrd_info_push(cd,
                           sprintf_alloc("ds[%s].value",
                                         rrd.ds_def[i].ds_nam), RD_I_VAL,
                           info);

        info.u_cnt = rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt;
        cd = rrd_info_push(cd,
                           sprintf_alloc("ds[%s].unknown_sec",
                                         rrd.ds_def[i].ds_nam), RD_I_CNT,
                           info);
    }

    for (i = 0; i < rrd.stat_head->rra_cnt; i++) {
        info.u_str = rrd.rra_def[i].cf_nam;
        cd = rrd_info_push(cd, sprintf_alloc("rra[%d].cf", i), RD_I_STR,
                           info);
        current_cf = cf_conv(rrd.rra_def[i].cf_nam);

        info.u_cnt = rrd.rra_def[i].row_cnt;
        cd = rrd_info_push(cd, sprintf_alloc("rra[%d].rows", i), RD_I_CNT,
                           info);

        info.u_cnt = rrd.rra_ptr[i].cur_row;
        cd = rrd_info_push(cd, sprintf_alloc("rra[%d].cur_row", i), RD_I_CNT,
                           info);

        info.u_cnt = rrd.rra_def[i].pdp_cnt;
        cd = rrd_info_push(cd, sprintf_alloc("rra[%d].pdp_per_row", i),
                           RD_I_CNT, info);

        switch (current_cf) {
        case CF_HWPREDICT:
        case CF_MHWPREDICT:
            info.u_val = rrd.rra_def[i].par[RRA_hw_alpha].u_val;
            cd = rrd_info_push(cd, sprintf_alloc("rra[%d].alpha", i),
                               RD_I_VAL, info);
            info.u_val = rrd.rra_def[i].par[RRA_hw_beta].u_val;
            cd = rrd_info_push(cd, sprintf_alloc("rra[%d].beta", i), RD_I_VAL,
                               info);
            break;
        case CF_SEASONAL:
        case CF_DEVSEASONAL:
            info.u_val = rrd.rra_def[i].par[RRA_seasonal_gamma].u_val;
            cd = rrd_info_push(cd, sprintf_alloc("rra[%d].gamma", i),
                               RD_I_VAL, info);
            if (atoi(rrd.stat_head->version) >= 4) {
                info.u_val =
                    rrd.rra_def[i].par[RRA_seasonal_smoothing_window].u_val;
                cd = rrd_info_push(cd,
                                   sprintf_alloc("rra[%d].smoothing_window",
                                                 i), RD_I_VAL, info);
            }
            break;
        case CF_FAILURES:
            info.u_val = rrd.rra_def[i].par[RRA_delta_pos].u_val;
            cd = rrd_info_push(cd, sprintf_alloc("rra[%d].delta_pos", i),
                               RD_I_VAL, info);
            info.u_val = rrd.rra_def[i].par[RRA_delta_neg].u_val;
            cd = rrd_info_push(cd, sprintf_alloc("rra[%d].delta_neg", i),
                               RD_I_VAL, info);
            info.u_cnt = rrd.rra_def[i].par[RRA_failure_threshold].u_cnt;
            cd = rrd_info_push(cd,
                               sprintf_alloc("rra[%d].failure_threshold", i),
                               RD_I_CNT, info);
            info.u_cnt = rrd.rra_def[i].par[RRA_window_len].u_cnt;
            cd = rrd_info_push(cd, sprintf_alloc("rra[%d].window_length", i),
                               RD_I_CNT, info);
            break;
        case CF_DEVPREDICT:
            break;
        default:
            info.u_val = rrd.rra_def[i].par[RRA_cdp_xff_val].u_val;
            cd = rrd_info_push(cd, sprintf_alloc("rra[%d].xff", i), RD_I_VAL,
                               info);
            break;
        }

        for (ii = 0; ii < rrd.stat_head->ds_cnt; ii++) {
            switch (current_cf) {
            case CF_HWPREDICT:
            case CF_MHWPREDICT:
                info.u_val =
                    rrd.cdp_prep[i * rrd.stat_head->ds_cnt +
                                 ii].scratch[CDP_hw_intercept].u_val;
                cd = rrd_info_push(cd,
                                   sprintf_alloc
                                   ("rra[%d].cdp_prep[%d].intercept", i, ii),
                                   RD_I_VAL, info);
                info.u_val =
                    rrd.cdp_prep[i * rrd.stat_head->ds_cnt +
                                 ii].scratch[CDP_hw_slope].u_val;
                cd = rrd_info_push(cd,
                                   sprintf_alloc("rra[%d].cdp_prep[%d].slope",
                                                 i, ii), RD_I_VAL, info);
                info.u_cnt =
                    rrd.cdp_prep[i * rrd.stat_head->ds_cnt +
                                 ii].scratch[CDP_null_count].u_cnt;
                cd = rrd_info_push(cd,
                                   sprintf_alloc
                                   ("rra[%d].cdp_prep[%d].NaN_count", i, ii),
                                   RD_I_CNT, info);
                break;
            case CF_SEASONAL:
                info.u_val =
                    rrd.cdp_prep[i * rrd.stat_head->ds_cnt +
                                 ii].scratch[CDP_hw_seasonal].u_val;
                cd = rrd_info_push(cd,
                                   sprintf_alloc
                                   ("rra[%d].cdp_prep[%d].seasonal", i, ii),
                                   RD_I_VAL, info);
                break;
            case CF_DEVSEASONAL:
                info.u_val =
                    rrd.cdp_prep[i * rrd.stat_head->ds_cnt +
                                 ii].scratch[CDP_seasonal_deviation].u_val;
                cd = rrd_info_push(cd,
                                   sprintf_alloc
                                   ("rra[%d].cdp_prep[%d].deviation", i, ii),
                                   RD_I_VAL, info);
                break;
            case CF_DEVPREDICT:
                break;
            case CF_FAILURES:
            {
                unsigned short j;
                char     *violations_array;
                char      history[MAX_FAILURES_WINDOW_LEN + 1];

                violations_array =
                    (char *) rrd.cdp_prep[i * rrd.stat_head->ds_cnt +
                                          ii].scratch;
                for (j = 0; j < rrd.rra_def[i].par[RRA_window_len].u_cnt; ++j)
                    history[j] = (violations_array[j] == 1) ? '1' : '0';
                history[j] = '\0';
                info.u_str = history;
                cd = rrd_info_push(cd,
                                   sprintf_alloc
                                   ("rra[%d].cdp_prep[%d].history", i, ii),
                                   RD_I_STR, info);
            }
                break;
            default:
                info.u_val =
                    rrd.cdp_prep[i * rrd.stat_head->ds_cnt +
                                 ii].scratch[CDP_val].u_val;
                cd = rrd_info_push(cd,
                                   sprintf_alloc("rra[%d].cdp_prep[%d].value",
                                                 i, ii), RD_I_VAL, info);
                info.u_cnt =
                    rrd.cdp_prep[i * rrd.stat_head->ds_cnt +
                                 ii].scratch[CDP_unkn_pdp_cnt].u_cnt;
                cd = rrd_info_push(cd,
                                   sprintf_alloc
                                   ("rra[%d].cdp_prep[%d].unknown_datapoints",
                                    i, ii), RD_I_CNT, info);
                break;
            }
        }
    }

    rrd_close(rrd_file);
  err_free:
    rrd_free(&rrd);
    return (data);
}
Exemplo n.º 8
0
int
rrd_open(const char *file_name, FILE **in_file, rrd_t *rrd, int rdwr)    
{

    
    char *mode = NULL;
    int version;
    
    rrd_init(rrd);
    if (rdwr == RRD_READONLY) {
        mode = "rb";
    } else {
        mode = "rb+";
    }
    
    if (((*in_file) = fopen(file_name,mode)) == NULL ){
        rrd_set_error("opening '%s': %s",file_name, rrd_strerror(errno));
        return (-1);
    }

#ifdef HAVE_POSIX_FADVISE
    /* In general we need no read-ahead when dealing with rrd_files.
       When we stop reading, it is highly unlikely that we start up again.
       In this manner we actually save time and diskaccess (and buffer cache).
       Thanks to Dave Plonka for the Idea of using POSIX_FADV_RANDOM here. */       
    /* if (0 != posix_fadvise(fileno(*in_file), 0, 0, POSIX_FADV_RANDOM)) {
        rrd_set_error("setting POSIX_FADV_RANDOM on '%s': %s",file_name, rrd_strerror(errno));
        fclose(*in_file);
        return(-1); */

        /* if it does not work, then this is sad, but we should not quit */
     posix_fadvise(fileno(*in_file), 0, 0, POSIX_FADV_RANDOM);
        
     /*     }     */
#endif

/*
        if (rdwr == RRD_READWRITE)
        {
           if (setvbuf((*in_file),NULL,_IONBF,2)) {
                  rrd_set_error("failed to disable the stream buffer\n");
                  return (-1);
           }
        }
*/
    
#define MYFREAD(MYVAR,MYVART,MYCNT) \
    if ((MYVAR = malloc(sizeof(MYVART) * MYCNT)) == NULL) {\
        rrd_set_error("" #MYVAR " malloc"); \
        fclose(*in_file); \
        return (-1); } \
    fread(MYVAR,sizeof(MYVART),MYCNT, *in_file); 


    MYFREAD(rrd->stat_head, stat_head_t,  1)
    /* lets see if the first read worked */
    if (ferror( *in_file ) || feof(*in_file)) {
        rrd_set_error("reading the cookie off %s faild",file_name);
        fclose(*in_file);
        return(-1);
    }        

        /* lets do some test if we are on track ... */
        if (strncmp(rrd->stat_head->cookie,RRD_COOKIE,4) != 0){
            rrd_set_error("'%s' is not an RRD file",file_name);
            free(rrd->stat_head);
            rrd->stat_head = NULL; 
            fclose(*in_file);
            return(-1);}

        if (rrd->stat_head->float_cookie != FLOAT_COOKIE){
            rrd_set_error("This RRD was created on other architecture");
            free(rrd->stat_head);
            rrd->stat_head = NULL; 
            fclose(*in_file);
            return(-1);}

    version = atoi(rrd->stat_head->version);

        if (version > atoi(RRD_VERSION)){
            rrd_set_error("can't handle RRD file version %s",
                        rrd->stat_head->version);
            free(rrd->stat_head);
            rrd->stat_head = NULL; 
            fclose(*in_file);
            return(-1);}


    MYFREAD(rrd->ds_def,    ds_def_t,     rrd->stat_head->ds_cnt)
    MYFREAD(rrd->rra_def,   rra_def_t,    rrd->stat_head->rra_cnt)
    /* handle different format for the live_head */
    if(version < 3) {
            rrd->live_head = (live_head_t *)malloc(sizeof(live_head_t));
            if(rrd->live_head == NULL) {
                rrd_set_error("live_head_t malloc");
                fclose(*in_file); 
                return (-1);
            }
                fread(&rrd->live_head->last_up, sizeof(long), 1, *in_file); 
                rrd->live_head->last_up_usec = 0;
    }
    else {
            MYFREAD(rrd->live_head, live_head_t, 1)
    }
    MYFREAD(rrd->pdp_prep,  pdp_prep_t,   rrd->stat_head->ds_cnt)
    MYFREAD(rrd->cdp_prep,  cdp_prep_t,   (rrd->stat_head->rra_cnt
                                             * rrd->stat_head->ds_cnt))
    MYFREAD(rrd->rra_ptr,   rra_ptr_t,    rrd->stat_head->rra_cnt)
#undef MYFREAD

    return(0);
}
Exemplo n.º 9
0
int rrd_fetch_fn(
    const char *filename,   /* name of the rrd */
    enum cf_en cf_idx,  /* which consolidation function ? */
    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 *ds_cnt,  /* number of data sources in file */
    char ***ds_namv,    /* names of data_sources */
    rrd_value_t **data)
{                       /* two dimensional array containing the data */
    long      i, ii;
    time_t    cal_start, cal_end, rra_start_time, rra_end_time;
    long      best_full_rra = 0, best_part_rra = 0, chosen_rra =
        0, rra_pointer = 0;
    long      best_full_step_diff = 0, best_part_step_diff =
        0, tmp_step_diff = 0, tmp_match = 0, best_match = 0;
    long      full_match, rra_base;
    off_t     start_offset, end_offset;
    int       first_full = 1;
    int       first_part = 1;
    rrd_t     rrd;
    rrd_file_t *rrd_file;
    rrd_value_t *data_ptr;
    unsigned long rows;

#ifdef DEBUG
    fprintf(stderr, "Entered rrd_fetch_fn() searching for the best match\n");
    fprintf(stderr, "Looking for: start %10lu end %10lu step %5lu\n",
            *start, *end, *step);
#endif

#ifdef HAVE_LIBDBI
    /* handle libdbi datasources */
    if (strncmp("sql//",filename,5)==0 || strncmp("sql||",filename,5)==0) {
	return rrd_fetch_fn_libdbi(filename,cf_idx,start,end,step,ds_cnt,ds_namv,data);
    }
#endif

    rrd_init(&rrd);
    rrd_file = rrd_open(filename, &rrd, RRD_READONLY);
    if (rrd_file == NULL)
        goto err_free;

    /* when was the really last update of this file ? */

    if (((*ds_namv) =
         (char **) malloc(rrd.stat_head->ds_cnt * sizeof(char *))) == NULL) {
        rrd_set_error("malloc fetch ds_namv array");
        goto err_close;
    }

    for (i = 0; (unsigned long) i < rrd.stat_head->ds_cnt; i++) {
        if ((((*ds_namv)[i]) = (char*)malloc(sizeof(char) * DS_NAM_SIZE)) == NULL) {
            rrd_set_error("malloc fetch ds_namv entry");
            goto err_free_ds_namv;
        }
        strncpy((*ds_namv)[i], rrd.ds_def[i].ds_nam, DS_NAM_SIZE - 1);
        (*ds_namv)[i][DS_NAM_SIZE - 1] = '\0';

    }

    /* find the rra which best matches the requirements */
    for (i = 0; (unsigned) i < rrd.stat_head->rra_cnt; i++) {
      enum cf_en rratype=cf_conv(rrd.rra_def[i].cf_nam);
      /* handle this RRA */
      if (
	  /* if we found a direct match */
	  (rratype == cf_idx)
	  || 
	  /*if we found a DS with interval 1 
	    and CF (requested,available) are MIN,MAX,AVERAGE,LAST
	  */
	  ( 
	      /* only if we are on interval 1 */
	      (rrd.rra_def[i].pdp_cnt==1) 
	      && ( 
		  /* and requested CF is MIN,MAX,AVERAGE,LAST */
		  (cf_idx == CF_MINIMUM)
		  ||(cf_idx == CF_MAXIMUM)
		  ||(cf_idx == CF_AVERAGE)
		  ||(cf_idx == CF_LAST)
		  )
	      && (
		  /* and found CF is MIN,MAX,AVERAGE,LAST */
		  (rratype == CF_MINIMUM)
		  ||(rratype == CF_MAXIMUM)
		  ||(rratype == CF_AVERAGE)
		  ||(rratype == CF_LAST)
		  )
	      )
	  ){

            cal_end = (rrd.live_head->last_up - (rrd.live_head->last_up
                                                 % (rrd.rra_def[i].pdp_cnt
                                                    *
                                                    rrd.stat_head->
                                                    pdp_step)));
            cal_start =
                (cal_end -
                 (rrd.rra_def[i].pdp_cnt * rrd.rra_def[i].row_cnt *
                  rrd.stat_head->pdp_step));

            full_match = *end - *start;
#ifdef DEBUG
            fprintf(stderr, "Considering: start %10lu end %10lu step %5lu ",
                    cal_start, cal_end,
                    rrd.stat_head->pdp_step * rrd.rra_def[i].pdp_cnt);
#endif
            /* we need step difference in either full or partial case */
            tmp_step_diff = labs(*step - (rrd.stat_head->pdp_step
                                          * rrd.rra_def[i].pdp_cnt));
            /* best full match */
            if (cal_start <= *start) {
                if (first_full || (tmp_step_diff < best_full_step_diff)) {
                    first_full = 0;
                    best_full_step_diff = tmp_step_diff;
                    best_full_rra = i;
#ifdef DEBUG
                    fprintf(stderr, "best full match so far\n");
                } else {
                    fprintf(stderr, "full match, not best\n");
#endif
                }

            } else {
                /* best partial match */
                tmp_match = full_match;
                if (cal_start > *start)
                    tmp_match -= (cal_start - *start);
                if (first_part ||
                    (best_match < tmp_match) ||
                    (best_match == tmp_match &&
                     tmp_step_diff < best_part_step_diff)) {
#ifdef DEBUG
                    fprintf(stderr, "best partial so far\n");
#endif
                    first_part = 0;
                    best_match = tmp_match;
                    best_part_step_diff = tmp_step_diff;
                    best_part_rra = i;
                } else {
#ifdef DEBUG
                    fprintf(stderr, "partial match, not best\n");
#endif
                }
            }
        }
    }

    /* lets see how the matching went. */
    if (first_full == 0)
        chosen_rra = best_full_rra;
    else if (first_part == 0)
        chosen_rra = best_part_rra;
    else {
        rrd_set_error
            ("the RRD does not contain an RRA matching the chosen CF");
        goto err_free_all_ds_namv;
    }

    /* set the wish parameters to their real values */
    *step = rrd.stat_head->pdp_step * rrd.rra_def[chosen_rra].pdp_cnt;
    *start -= (*start % *step);
    *end += (*step - *end % *step);
    rows = (*end - *start) / *step + 1;

#ifdef DEBUG
    fprintf(stderr,
            "We found:    start %10lu end %10lu step %5lu rows  %lu\n",
            *start, *end, *step, rows);
#endif

/* Start and end are now multiples of the step size.  The amount of
** steps we want is (end-start)/step and *not* an extra one.
** Reasoning:  if step is s and we want to graph from t to t+s,
** we need exactly ((t+s)-t)/s rows.  The row to collect from the
** database is the one with time stamp (t+s) which means t to t+s.
*/
    *ds_cnt = rrd.stat_head->ds_cnt;
    if (((*data) = (rrd_value_t*)malloc(*ds_cnt * rows * sizeof(rrd_value_t))) == NULL) {
        rrd_set_error("malloc fetch data area");
        goto err_free_all_ds_namv;
    }

    data_ptr = (*data);

    /* find base address of rra */
    rra_base = rrd_file->header_len;
    for (i = 0; i < chosen_rra; i++)
        rra_base += (*ds_cnt * rrd.rra_def[i].row_cnt * sizeof(rrd_value_t));

    /* find start and end offset */
    rra_end_time = (rrd.live_head->last_up
                    - (rrd.live_head->last_up % *step));
    rra_start_time = (rra_end_time
                      - (*step * (rrd.rra_def[chosen_rra].row_cnt - 1)));
    /* here's an error by one if we don't be careful */
    start_offset = ((long long)*start + (long long)*step - (long long)rra_start_time) / (long long) *step;
    end_offset = ((long long)rra_end_time - (long long)*end) / (long long) *step;
#ifdef DEBUG
    fprintf(stderr,
            "start %10lu step %10lu rra_start %lld, rra_end %lld, start_off %lld, end_off %lld\n",
            *start, *step,(long long)rra_start_time, (long long)rra_end_time, (long long)start_offset, (long long)end_offset);
#endif
    /* only seek if the start time is before the end time */
    if (*start <= rra_end_time && *end >= rra_start_time - (off_t)*step ){
        if (start_offset <= 0)
            rra_pointer = rrd.rra_ptr[chosen_rra].cur_row + 1;
        else
            rra_pointer = rrd.rra_ptr[chosen_rra].cur_row + 1 + start_offset;

        rra_pointer = rra_pointer % (signed) rrd.rra_def[chosen_rra].row_cnt;
         
        if (rrd_seek(rrd_file, (rra_base + (rra_pointer * (*ds_cnt)
                                        * sizeof(rrd_value_t))),
                 SEEK_SET) != 0) {
            rrd_set_error("seek error in RRA");
            goto err_free_data;
        }
#ifdef DEBUG
        fprintf(stderr, "First Seek: rra_base %lu rra_pointer %lu\n",
                rra_base, rra_pointer);
#endif
    }
    
    /* step trough the array */

    for (i = start_offset;
         i < (signed) rrd.rra_def[chosen_rra].row_cnt - end_offset; i++) {
        /* no valid data yet */
        if (i < 0) {
#ifdef DEBUG
            fprintf(stderr, "pre fetch %li -- ", i);
#endif
            for (ii = 0; (unsigned) ii < *ds_cnt; ii++) {
                *(data_ptr++) = DNAN;
#ifdef DEBUG
                fprintf(stderr, "%10.2f ", *(data_ptr - 1));
#endif
            }
        }
        /* past the valid data area */
        else if (i >= (signed) rrd.rra_def[chosen_rra].row_cnt) {
#ifdef DEBUG
            fprintf(stderr, "past fetch %li -- ", i);
#endif
            for (ii = 0; (unsigned) ii < *ds_cnt; ii++) {
                *(data_ptr++) = DNAN;
#ifdef DEBUG
                fprintf(stderr, "%10.2f ", *(data_ptr - 1));
#endif
            }
        } else {
            /* OK we are inside the valid area but the pointer has to 
             * be wrapped*/
            if (rra_pointer >= (signed) rrd.rra_def[chosen_rra].row_cnt) {
                rra_pointer -= rrd.rra_def[chosen_rra].row_cnt;
                if (rrd_seek(rrd_file, (rra_base + rra_pointer * (*ds_cnt)
                                        * sizeof(rrd_value_t)),
                             SEEK_SET) != 0) {
                    rrd_set_error("wrap seek in RRA did fail");
                    goto err_free_data;
                }
#ifdef DEBUG
                fprintf(stderr, "wrap seek ...\n");
#endif
            }

            if (rrd_read(rrd_file, data_ptr, sizeof(rrd_value_t) * (*ds_cnt))
                != (ssize_t) (sizeof(rrd_value_t) * (*ds_cnt))) {
                rrd_set_error("fetching cdp from rra");
                goto err_free_data;
            }
#ifdef DEBUG
            fprintf(stderr, "post fetch %li -- ", i);
            for (ii = 0; ii < *ds_cnt; ii++)
                fprintf(stderr, "%10.2f ", *(data_ptr + ii));
#endif
            data_ptr += *ds_cnt;
            rra_pointer++;
        }
#ifdef DEBUG
        fprintf(stderr, "\n");
#endif

    }

    rrd_close(rrd_file);
    rrd_free(&rrd);
    return (0);
  err_free_data:
    free(*data);
    *data = NULL;
  err_free_all_ds_namv:
    for (i = 0; (unsigned long) i < rrd.stat_head->ds_cnt; ++i)
        free((*ds_namv)[i]);
  err_free_ds_namv:
    free(*ds_namv);
  err_close:
    rrd_close(rrd_file);
  err_free:
    rrd_free(&rrd);
    return (-1);
}
Exemplo n.º 10
0
static rrd_t *rrd_modify_structure(const rrd_t *in,
				   const char **removeDS,
				   const char **addDS,
				   rra_mod_op_t *rra_mod_ops, int rra_mod_ops_cnt,
				   unsigned long hash)
{
    rrd_t *out;
    int rc = -1;
    unsigned int i, j;
    char       *ds_ops = NULL;
    unsigned int ds_ops_cnt = 0;
    int *ds_map = NULL;
    
	out = (rrd_t *) malloc(sizeof(rrd_t));
    if (out == NULL) {
	rrd_set_error("Out of memory");
	goto done;
    }
    rrd_init(out);
    
    /* currently we only allow to modify version 3 RRDs. If other
       files should be modified, a dump/restore cycle should be
       done.... */
    
    if (atoi(in->stat_head->version) < atoi(RRD_VERSION3) || atoi(in->stat_head->version) > atoi(RRD_VERSION5)) {
	rrd_set_error("direct modification is only supported for version 3, 4 or 5 of RRD files. Consider to dump/restore before retrying a modification");
	goto done;
    }
    
    
    /* copy over structure to out RRD */
    
    out->stat_head = (stat_head_t *) malloc(sizeof(stat_head_t));
    if (out->stat_head == NULL) {
	rrd_set_error("rrd_modify_r: malloc failed.");
	goto done;
    }
    
    memset(out->stat_head, 0, (sizeof(stat_head_t)));
    
    strncpy(out->stat_head->cookie, "RRD", sizeof(out->stat_head->cookie));
    strcpy(out->stat_head->version, in->stat_head->version);
    out->stat_head->float_cookie = FLOAT_COOKIE;
    out->stat_head->pdp_step = in->stat_head->pdp_step;
    
    out->stat_head->ds_cnt = 0;
    out->stat_head->rra_cnt = 0;
    
	out->live_head = (live_head_t *) copy_over_realloc(out->live_head, 0, in->live_head, 0,
				       sizeof(live_head_t));
    
    if (out->live_head == NULL) goto done;
    
    /* use the ops array as a scratchpad to remember what we are about
    to do to each DS. There is one entry for every DS in the
    original RRD and one additional entry for every added DS. 

    Entries marked as 
    - 'c' will be copied to the out RRD, 
    - 'd' will not be copied (= will effectively be deleted)
    - 'a' will be added.
    */
    ds_ops_cnt = in->stat_head->ds_cnt;
    ds_ops = (char *) malloc(ds_ops_cnt);
    
    if (ds_ops == NULL) {
	rrd_set_error("parse_tag_rrd: malloc failed.");
	goto done;
    } 
    
    memset(ds_ops, 'c', in->stat_head->ds_cnt);
    
    // record DSs to be deleted in ds_ops
    if (removeDS != NULL) {
	for (unsigned int in_ds = 0 ; in_ds < in->stat_head->ds_cnt ; in_ds++) {
	    const char *c;
	    for (j = 0, c = removeDS[j] ; c ; j++, c = removeDS[j]) {
		if (strcmp(in->ds_def[in_ds].ds_nam, c) == 0) {
		    ds_ops[in_ds] = 'd';
		    break;
		}
	    }
	}
    }
    
    if (copy_or_delete_DSs(in, out, ds_ops) != 0) {
	// error
	goto done;
    }
    
    /* now add any DS definitions to be added */
    int added_cnt = add_dss(in, out, addDS);
    if (added_cnt < 0) {
	// error
	goto done;
    }
    if (added_cnt > 0) {
	// and extend the ds_ops array as well
		ds_ops = (char *) realloc(ds_ops, ds_ops_cnt + added_cnt);
	for(; added_cnt > 0 ; added_cnt--) {
	    ds_ops[ds_ops_cnt++] = 'a';
	}
    }
    
    /* prepare explicit data source index to map from output index to
       input index */
    
    ds_map = (int *) malloc(sizeof(int) * out->stat_head->ds_cnt);
    
    j = 0;
    for (i = 0 ; i < ds_ops_cnt ; i++) {
	switch (ds_ops[i]) {
	case 'c': 
	    ds_map[j++] = i;
	    break;
	case 'd': 
	    break;
	case 'a':
	    ds_map[j++] = -1;
	    break;
	}
    }
    
    /* now take care to copy all RRAs, removing and adding columns for
       every row as needed for the requested DS changes */
    
    /* we also reorder all rows, adding/removing rows as needed */
    
    /* later on, we'll need to know the total number of rows for both RRDs in
       order to allocate memory. Luckily, handle_rra_defs will give that to us. */
    int total_out_rra_rows = 0, total_in_rra_rows = 0;
    
    rc = handle_rra_defs(in, out, rra_mod_ops, rra_mod_ops_cnt, ds_ops, ds_ops_cnt, &total_in_rra_rows, &total_out_rra_rows);
    if (rc != 0) goto done;
    
    /* read and process all data ... */
    
    /* there seem to be two function in the current rrdtool codebase dealing
       with writing a new rrd file to disk: write_file and rrd_create_fn. The
       latter has the major problem, that it tries to free data passed to it
       (WTF?), but write_file assumes chronologically ordered data in RRAs (that
       is, in the data space starting at rrd.rrd_value....

       This is the reason why: 
        - we use write_file and 
        - why we reset cur_row in RRAs and reorder data to be cronological
    */
    
    /* prepare space for output data */
	out->rrd_value = (rrd_value_t *) realloc(out->rrd_value,
			     total_out_rra_rows * out->stat_head->ds_cnt
			     * sizeof(rrd_value_t));
    
    if (out->rrd_value == NULL) {
	rrd_set_error("out of memory");
	goto done;
    }
    
    rc = mod_rras(in, out, ds_map, rra_mod_ops, rra_mod_ops_cnt, ds_ops, ds_ops_cnt);
    if (rc != 0) goto done;
    
    rc = add_rras(in, out, ds_map, rra_mod_ops, rra_mod_ops_cnt, hash);
    if (rc != 0) goto done;
    

done:
    if (ds_ops != NULL) free(ds_ops);
    if (ds_map != NULL) free(ds_map);

    if (rc != 0 && out != NULL) {
	rrd_memory_free(out);
	free(out);
	out = NULL;
    }
    return out;
}
Exemplo n.º 11
0
int
rrd_create(int argc, char **argv) 
{
    rrd_t          rrd;
    long                i,long_tmp;
    time_t             last_up;
    struct rrd_time_value last_up_tv;
    char *parsetime_error = NULL;

    /* init last_up */
    last_up = time(NULL)-10;
    /* init rrd clean */
    rrd_init(&rrd);
    /* static header */
    if((rrd.stat_head = calloc(1,sizeof(stat_head_t)))==NULL){
	rrd_set_error("allocating rrd.stat_head");
	return(-1);
    }

    /* live header */
    if((rrd.live_head = calloc(1,sizeof(live_head_t)))==NULL){
	rrd_set_error("allocating rrd.live_head");
	return(-1);
    }

    /* set some defaults */
    strcpy(rrd.stat_head->cookie,RRD_COOKIE);
    strcpy(rrd.stat_head->version,RRD_VERSION);
    rrd.stat_head->float_cookie = FLOAT_COOKIE;
    rrd.stat_head->ds_cnt = 0; /* this will be adjusted later */
    rrd.stat_head->rra_cnt = 0; /* ditto */
    rrd.stat_head->pdp_step = 300; /* 5 minute default */

    /* a default value */
    rrd.ds_def = NULL;
    rrd.rra_def = NULL;
    
    while (1){
	static struct option long_options[] =
	{
	    {"start",      required_argument, 0, 'b'},
	    {"step",        required_argument,0,'s'},
	    {0,0,0,0}
	};
	int option_index = 0;
	int opt;
	opt = getopt_long(argc, argv, "b:s:", 
			  long_options, &option_index);
	
	if (opt == EOF)
	  break;
	
	switch(opt) {
	case 'b':
            if ((parsetime_error = parsetime(optarg, &last_up_tv))) {
                rrd_set_error("start time: %s", parsetime_error );
		rrd_free(&rrd);
                return(-1);
	    }
	    if (last_up_tv.type == RELATIVE_TO_END_TIME ||
		last_up_tv.type == RELATIVE_TO_START_TIME) {
		rrd_set_error("specifying time relative to the 'start' "
                              "or 'end' makes no sense here");
		rrd_free(&rrd);
		return(-1);
	    }

	    last_up = mktime(&last_up_tv.tm) + last_up_tv.offset;
	    
	    if (last_up < 3600*24*365*10){
		rrd_set_error("the first entry to the RRD should be after 1980");
		rrd_free(&rrd);
		return(-1);
	    }	
	    break;

	case 's':
	    long_tmp = atol(optarg);
	    if (long_tmp < 1){
		rrd_set_error("step size should be no less than one second");
		rrd_free(&rrd);
		return(-1);
	    }
	    rrd.stat_head->pdp_step = long_tmp;
	    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);
	    return(-1);
	}
    }
    rrd.live_head->last_up = last_up;

    for(i=optind+1;i<argc;i++){
	char minstr[DS_NAM_SIZE], maxstr[DS_NAM_SIZE];	
	int ii;
	if (strncmp(argv[i],"DS:",3)==0){
	    size_t old_size = sizeof(ds_def_t)*(rrd.stat_head->ds_cnt);
	    if((rrd.ds_def = rrd_realloc(rrd.ds_def,
				     old_size+sizeof(ds_def_t)))==NULL){
		rrd_set_error("allocating rrd.ds_def");
		rrd_free(&rrd);
		return(-1);	
	    }
	    memset(&rrd.ds_def[rrd.stat_head->ds_cnt], 0, sizeof(ds_def_t));
	    if (sscanf(&argv[i][3],
		       DS_NAM_FMT ":" DST_FMT ":%lu:%18[^:]:%18[^:]",
		       rrd.ds_def[rrd.stat_head->ds_cnt].ds_nam,
		       rrd.ds_def[rrd.stat_head->ds_cnt].dst,
		       &rrd.ds_def[rrd.stat_head->ds_cnt].par[DS_mrhb_cnt].u_cnt,
		       minstr,maxstr) == 5){
		/* check for duplicate datasource names */
		for(ii=0;ii<rrd.stat_head->ds_cnt;ii++){
			if(strcmp(rrd.ds_def[rrd.stat_head->ds_cnt].ds_nam,
			  	  rrd.ds_def[ii].ds_nam) == 0){
				rrd_set_error("Duplicate DS name: %s",rrd.ds_def[ii].ds_nam);
		                rrd_free(&rrd);
                                return(-1);
			}				                                
		}
		if(dst_conv(rrd.ds_def[rrd.stat_head->ds_cnt].dst) == -1){
		    rrd_free(&rrd);
		    return (-1);
		}
		if (minstr[0] == 'U' && minstr[1] == 0)
		    rrd.ds_def[rrd.stat_head->ds_cnt].par[DS_min_val].u_val = DNAN;
		else
		    rrd.ds_def[rrd.stat_head->ds_cnt].par[DS_min_val].u_val = atof(minstr);
		
		if (maxstr[0] == 'U' && maxstr[1] == 0)
		    rrd.ds_def[rrd.stat_head->ds_cnt].par[DS_max_val].u_val = DNAN;
		else
		    rrd.ds_def[rrd.stat_head->ds_cnt].par[DS_max_val].u_val  = atof(maxstr);
		
		if (! isnan(rrd.ds_def[rrd.stat_head->ds_cnt].par[DS_min_val].u_val) &&
		    ! isnan(rrd.ds_def[rrd.stat_head->ds_cnt].par[DS_max_val].u_val) &&
		    rrd.ds_def[rrd.stat_head->ds_cnt].par[DS_min_val].u_val
		    >= rrd.ds_def[rrd.stat_head->ds_cnt].par[DS_max_val].u_val ) {
		    rrd_set_error("min must be less than max in DS definition");
		    rrd_free(&rrd);
		    return (-1);		
		}
		rrd.stat_head->ds_cnt++;	    
	    } else {
		rrd_set_error("can't parse argument '%s'",argv[i]);
		rrd_free(&rrd);
		return (-1);		
	    }
	} else if (strncmp(argv[i],"RRA:",3)==0){
	    size_t old_size = sizeof(rra_def_t)*(rrd.stat_head->rra_cnt);
	    if((rrd.rra_def = rrd_realloc(rrd.rra_def,
				      old_size+sizeof(rra_def_t)))==NULL){
		rrd_set_error("allocating rrd.rra_def");
		rrd_free(&rrd);
		return(-1);	
	    }
	    memset(&rrd.rra_def[rrd.stat_head->rra_cnt], 0, sizeof(rra_def_t));
	    if (sscanf(&argv[i][4],
		       CF_NAM_FMT ":%lf:%lu:%lu",
		       rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam,
		       &rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_cdp_xff_val].u_val,
		       &rrd.rra_def[rrd.stat_head->rra_cnt].pdp_cnt,
		       &rrd.rra_def[rrd.stat_head->rra_cnt].row_cnt) == 4){
		if(cf_conv(rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam) == -1){
		    rrd_free(&rrd);
		    return (-1);
		}
	        if (rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_cdp_xff_val].u_val<0.0 ||
		    rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_cdp_xff_val].u_val>=1.0) {
		    rrd_set_error("the xff must always be >= 0 and < 1");
		    rrd_free(&rrd);
		    return (-1);
		}
		rrd.stat_head->rra_cnt++;	    		
	    }
	    else {  
		rrd_set_error("can't parse argument '%s'",argv[i]);
		rrd_free(&rrd);
		return (-1);		
	    }

	} else {
	    rrd_set_error("can't parse argument '%s'",argv[i]);
	    rrd_free(&rrd);
            return -1;
	}
    }


    if (rrd.stat_head->rra_cnt < 1){
	rrd_set_error("you must define at least one Round Robin Archive");
	rrd_free(&rrd);
	return(-1);
    }

    if (rrd.stat_head->ds_cnt < 1){
	rrd_set_error("you must define at least one Data Source");
	rrd_free(&rrd);
	return(-1);
    }
    return rrd_create_fn(argv[optind],&rrd);
}
Exemplo n.º 12
0
int
rrd_restore(int argc, char **argv) 
{
    rrd_t          rrd;
    char          *buf;
	char			rc = 0;
	char			force_overwrite = 0;	

    /* init rrd clean */
    optind = 0; opterr = 0;  /* initialize getopt */
    rrd_init(&rrd);
    if (argc<3) {
		rrd_set_error("usage rrdtool %s [--range-check/-r] [--force-overwrite/-f] file.xml file.rrd",argv[0]);
		return -1;
    }
	
	while (1) {
		static struct option long_options[] =
		{
			{"range-check",      required_argument, 0,  'r'},
			{"force-overwrite",	required_argument, 0,	'f'},
			{0,0,0,0}
		};
		int option_index = 0;
		int opt;
		
		
		opt = getopt_long(argc, argv, "r:f", long_options, &option_index);
		
		if (opt == EOF)
			break;
		
		switch(opt) {
		case 'r':
			rc=1;
			break;
		case 'f':
			force_overwrite=1;
			break;
		default:
			rrd_set_error("usage rrdtool %s [--range-check|-r] [--force-overwrite/-f]  file.xml file.rrd",argv[0]);
                	return -1;
			break;
		}
    }
	
    if (readfile(argv[optind],&buf,0)==-1){
      return -1;
    }
    if (xml2rrd(buf,&rrd,rc)==-1) {
	rrd_free(&rrd);
	free(buf);
	return -1;
    }
    free(buf);
    if(rrd_write(argv[optind+1],&rrd,force_overwrite)==-1){
	rrd_free(&rrd);	
	return -1;	
    };
    rrd_free(&rrd);    
    return 0;
}
int rrd_lastupdate_r(const char *filename,
        time_t *ret_last_update,
        unsigned long *ret_ds_count,
        char ***ret_ds_names,
        char ***ret_last_ds)
{
    unsigned long i = 0;
    rrd_t     rrd;
    rrd_file_t *rrd_file;

    rrd_init(&rrd);
    rrd_file = rrd_open(filename, &rrd, RRD_READONLY);
    if (rrd_file == NULL) {
        rrd_free(&rrd);
        return (-1);
    }

    *ret_last_update = rrd.live_head->last_up;
    *ret_ds_count = rrd.stat_head->ds_cnt;
    *ret_ds_names = (char **) malloc (rrd.stat_head->ds_cnt * sizeof(char *));
    if (*ret_ds_names == NULL) {
        rrd_set_error ("malloc fetch ret_ds_names array");
        rrd_close (rrd_file);
        rrd_free (&rrd);
        return (-1);
    }
    memset (*ret_ds_names, 0, rrd.stat_head->ds_cnt * sizeof(char *));

    *ret_last_ds = (char **) malloc (rrd.stat_head->ds_cnt * sizeof(char *));
    if (*ret_last_ds == NULL) {
        rrd_set_error ("malloc fetch ret_last_ds array");
        free (*ret_ds_names);
        *ret_ds_names = NULL;
        rrd_close (rrd_file);
        rrd_free (&rrd);
        return (-1);
    }
    memset (*ret_last_ds, 0, rrd.stat_head->ds_cnt * sizeof(char *));

    for (i = 0; i < rrd.stat_head->ds_cnt; i++) {
        (*ret_ds_names)[i] = sprintf_alloc("%s", rrd.ds_def[i].ds_nam);
        (*ret_last_ds)[i] = sprintf_alloc("%s", rrd.pdp_prep[i].last_ds);

        if (((*ret_ds_names)[i] == NULL) || ((*ret_last_ds)[i] == NULL))
            break;
    }

    /* Check if all names and values could be copied and free everything if
     * not. */
    if (i < rrd.stat_head->ds_cnt) {
        rrd_set_error ("sprintf_alloc failed");
        for (i = 0; i < rrd.stat_head->ds_cnt; i++) {
            if ((*ret_ds_names)[i] != NULL)
            {
                free ((*ret_ds_names)[i]);
                (*ret_ds_names)[i] = NULL;
            }
            if ((*ret_last_ds)[i] != NULL)
            {
                free ((*ret_last_ds)[i]);
                (*ret_last_ds)[i] = NULL;
            }
        }
        free (*ret_ds_names);
        *ret_ds_names = NULL;
        free (*ret_last_ds);
        *ret_last_ds = NULL;
        rrd_close (rrd_file);
        rrd_free (&rrd);
        return (-1);
    }

    rrd_free(&rrd);
    rrd_close(rrd_file);
    return (0);
} /* int rrd_lastupdate_r */
Exemplo n.º 14
0
int rrd_resize(
    int argc,
    char **argv)
{
    char     *infilename, outfilename[11] = "resize.rrd";
    rrd_t     rrdold, rrdnew;
    rrd_value_t buffer;
    int       version;
    unsigned long l, rra;
    long      modify;
    unsigned long target_rra;
    int       grow = 0, shrink = 0;
    char     *endptr;
    rrd_file_t *rrd_file, *rrd_out_file;

    infilename = argv[1];
    if (!strcmp(infilename, "resize.rrd")) {
        rrd_set_error("resize.rrd is a reserved name");
        return (-1);
    }
    if (argc != 5) {
        rrd_set_error("wrong number of parameters");
        return (-1);
    }

    target_rra = strtol(argv[2], &endptr, 0);

    if (!strcmp(argv[3], "GROW"))
        grow = 1;
    else if (!strcmp(argv[3], "SHRINK"))
        shrink = 1;
    else {
        rrd_set_error("I can only GROW or SHRINK");
        return (-1);
    }

    modify = strtol(argv[4], &endptr, 0);

    if ((modify < 1)) {
        rrd_set_error("Please grow or shrink with at least 1 row");
        return (-1);
    }

    if (shrink)
        modify = -modify;


    rrd_init(&rrdold);
    rrd_file = rrd_open(infilename, &rrdold, RRD_READWRITE | RRD_COPY);
    if (rrd_file == NULL) {
        rrd_free(&rrdold);
        return (-1);
    }

    if (rrd_lock(rrd_file) != 0) {
        rrd_set_error("could not lock original RRD");
        rrd_free(&rrdold);
        rrd_close(rrd_file);
        return (-1);
    }


    if (target_rra >= rrdold.stat_head->rra_cnt) {
        rrd_set_error("no such RRA in this RRD");
        rrd_free(&rrdold);
        rrd_close(rrd_file);
        return (-1);
    }

    if (modify < 0)
        if ((long) rrdold.rra_def[target_rra].row_cnt <= -modify) {
            rrd_set_error("This RRA is not that big");
            rrd_free(&rrdold);
            rrd_close(rrd_file);
            return (-1);
        }

    rrd_init(&rrdnew);
    /* These need to be initialised before calling rrd_open() with 
       the RRD_CREATE flag */

    if ((rrdnew.stat_head = (stat_head_t*)calloc(1, sizeof(stat_head_t))) == NULL) {
        rrd_set_error("allocating stat_head for new RRD");
        rrd_free(&rrdold);
        rrd_close(rrd_file);
        return (-1);
    }
    memcpy(rrdnew.stat_head,rrdold.stat_head,sizeof(stat_head_t));

    if ((rrdnew.rra_def = (rra_def_t *)malloc(sizeof(rra_def_t) * rrdold.stat_head->rra_cnt)) == NULL) {
        rrd_set_error("allocating rra_def for new RRD");
        rrd_free(&rrdnew);
        rrd_free(&rrdold);
        rrd_close(rrd_file);
        return (-1);
    }
    memcpy(rrdnew.rra_def,rrdold.rra_def,sizeof(rra_def_t) * rrdold.stat_head->rra_cnt);

    /* Set this so that the file will be created with the correct size */
    rrdnew.rra_def[target_rra].row_cnt += modify;

    rrd_out_file = rrd_open(outfilename, &rrdnew, RRD_READWRITE | RRD_CREAT);
    if (rrd_out_file == NULL) {
        rrd_set_error("Can't create '%s': %s", outfilename,
                      rrd_strerror(errno));
        rrd_free(&rrdnew);
        rrd_free(&rrdold);
        rrd_close(rrd_file);
        return (-1);
    }
    if (rrd_lock(rrd_out_file) != 0) {
        rrd_set_error("could not lock new RRD");
        rrd_free(&rrdnew);
        rrd_free(&rrdold);
        rrd_close(rrd_file);
        rrd_close(rrd_out_file);
        return (-1);
    }
/*XXX: do one write for those parts of header that are unchanged */
    if ((rrdnew.rra_ptr = (rra_ptr_t *)malloc(sizeof(rra_ptr_t) * rrdold.stat_head->rra_cnt)) == NULL) {
        rrd_set_error("allocating rra_ptr for new RRD");
        rrd_free(&rrdnew);
        rrd_free(&rrdold);
        rrd_close(rrd_file);
        rrd_close(rrd_out_file);
        return (-1);
    }

    /* Put this back the way it was so that the rest of the algorithm
       below remains unchanged, it will be corrected later */
    rrdnew.rra_def[target_rra].row_cnt -= modify;

    rrdnew.ds_def = rrdold.ds_def;
    rrdnew.live_head = rrdold.live_head;
    rrdnew.pdp_prep = rrdold.pdp_prep;
    rrdnew.cdp_prep = rrdold.cdp_prep;
    memcpy(rrdnew.rra_ptr,rrdold.rra_ptr,sizeof(rra_ptr_t) * rrdold.stat_head->rra_cnt);


    version = atoi(rrdold.stat_head->version);
    switch (version) {
    case 4:
        break;        
    case 3:
        break;
    case 1:
        rrdnew.stat_head->version[3] = '3';
        break;
    default:
        rrd_set_error("Do not know how to handle RRD version %s",
                      rrdold.stat_head->version);

        rrdnew.ds_def = NULL;
        rrdnew.live_head = NULL;
        rrdnew.pdp_prep = NULL;
        rrdnew.cdp_prep = NULL;

        rrd_free(&rrdnew);
        rrd_free(&rrdold);
        rrd_close(rrd_file);
        rrd_close(rrd_out_file);
        return (-1);
        break;
    }

/* XXX: Error checking? */
    rrd_write(rrd_out_file, rrdnew.stat_head, sizeof(stat_head_t) * 1);
    rrd_write(rrd_out_file, rrdnew.ds_def,
              sizeof(ds_def_t) * rrdnew.stat_head->ds_cnt);
    rrd_write(rrd_out_file, rrdnew.rra_def,
              sizeof(rra_def_t) * rrdnew.stat_head->rra_cnt);
    rrd_write(rrd_out_file, rrdnew.live_head, sizeof(live_head_t) * 1);
    rrd_write(rrd_out_file, rrdnew.pdp_prep,
              sizeof(pdp_prep_t) * rrdnew.stat_head->ds_cnt);
    rrd_write(rrd_out_file, rrdnew.cdp_prep,
              sizeof(cdp_prep_t) * rrdnew.stat_head->ds_cnt *
              rrdnew.stat_head->rra_cnt);
    rrd_write(rrd_out_file, rrdnew.rra_ptr,
              sizeof(rra_ptr_t) * rrdnew.stat_head->rra_cnt);

    /* Move the CDPs from the old to the new database.
     ** This can be made (much) faster but isn't worth the effort. Clarity
     ** is much more important.
     */

    /* Move data in unmodified RRAs
     */
    l = 0;
    for (rra = 0; rra < target_rra; rra++) {
        l += rrdnew.stat_head->ds_cnt * rrdnew.rra_def[rra].row_cnt;
    }
    while (l > 0) {
        rrd_read(rrd_file, &buffer, sizeof(rrd_value_t) * 1);
        rrd_write(rrd_out_file, &buffer, sizeof(rrd_value_t) * 1);
        l--;
    }
    /* Move data in this RRA, either removing or adding some rows
     */
    if (modify > 0) {
        /* Adding extra rows; insert unknown values just after the
         ** current row number.
         */
        l = rrdnew.stat_head->ds_cnt *
            (rrdnew.rra_ptr[target_rra].cur_row + 1);
        while (l > 0) {
            rrd_read(rrd_file, &buffer, sizeof(rrd_value_t) * 1);
            rrd_write(rrd_out_file, &buffer, sizeof(rrd_value_t) * 1);
            l--;
        }
        buffer = DNAN;
        l = rrdnew.stat_head->ds_cnt * modify;
        while (l > 0) {
            rrd_write(rrd_out_file, &buffer, sizeof(rrd_value_t) * 1);
            l--;
        }
    } else {
        /* Removing rows. Normally this would be just after the cursor
         ** however this may also mean that we wrap to the beginning of
         ** the array.
         */
        signed long int remove_end = 0;

        remove_end =
            (rrdnew.rra_ptr[target_rra].cur_row -
             modify) % rrdnew.rra_def[target_rra].row_cnt;
        if (remove_end <=
            (signed long int) rrdnew.rra_ptr[target_rra].cur_row) {
            while (remove_end >= 0) {
                rrd_seek(rrd_file,
                         sizeof(rrd_value_t) * rrdnew.stat_head->ds_cnt,
                         SEEK_CUR);
                rrdnew.rra_ptr[target_rra].cur_row--;
                rrdnew.rra_def[target_rra].row_cnt--;
                remove_end--;
                modify++;
            }
            remove_end = rrdnew.rra_def[target_rra].row_cnt - 1;
        }
        for (l = 0; l <= rrdnew.rra_ptr[target_rra].cur_row; l++) {
            unsigned int tmp;

            for (tmp = 0; tmp < rrdnew.stat_head->ds_cnt; tmp++) {
                rrd_read(rrd_file, &buffer, sizeof(rrd_value_t) * 1);
                rrd_write(rrd_out_file, &buffer, sizeof(rrd_value_t) * 1);
            }
        }
        while (modify < 0) {
            rrd_seek(rrd_file,
                     sizeof(rrd_value_t) * rrdnew.stat_head->ds_cnt,
                     SEEK_CUR);
            rrdnew.rra_def[target_rra].row_cnt--;
            modify++;
        }
    }
    /* Move the rest of the CDPs
     */
    while (1) {
        ssize_t b_read;
        if ((b_read=rrd_read(rrd_file, &buffer, sizeof(rrd_value_t) * 1)) <= 0)
            break;
        if(rrd_out_file->pos+b_read > rrd_out_file->file_len) {
            fprintf(stderr,"WARNING: ignoring last %zu bytes\nWARNING: if you see this message multiple times for a single file you're in trouble\n", b_read);
            continue;
        }
        rrd_write(rrd_out_file, &buffer, b_read);
    }
    rrdnew.rra_def[target_rra].row_cnt += modify;
    rrd_seek(rrd_out_file,
             sizeof(stat_head_t) +
             sizeof(ds_def_t) * rrdnew.stat_head->ds_cnt, SEEK_SET);
    rrd_write(rrd_out_file, rrdnew.rra_def,
              sizeof(rra_def_t) * rrdnew.stat_head->rra_cnt);
    rrd_seek(rrd_out_file, sizeof(live_head_t), SEEK_CUR);
    rrd_seek(rrd_out_file, sizeof(pdp_prep_t) * rrdnew.stat_head->ds_cnt,
             SEEK_CUR);
    rrd_seek(rrd_out_file,
             sizeof(cdp_prep_t) * rrdnew.stat_head->ds_cnt *
             rrdnew.stat_head->rra_cnt, SEEK_CUR);
    rrd_write(rrd_out_file, rrdnew.rra_ptr,
              sizeof(rra_ptr_t) * rrdnew.stat_head->rra_cnt);
    rrd_close(rrd_file);    
    rrd_close(rrd_out_file);    
    rrd_free(&rrdold);

    rrdnew.ds_def = NULL;
    rrdnew.live_head = NULL;
    rrdnew.pdp_prep = NULL;
    rrdnew.cdp_prep = NULL;

    rrd_free(&rrdnew);
    return (0);
}
Exemplo n.º 15
0
int rrd_create_fn(const char *file_name, rrd_t *rrd)
{
	unsigned long i, ii;
	rrd_value_t *unknown;
	int       unkn_cnt;
	rrd_file_t *rrd_file_dn;
	rrd_t     rrd_dn;
	unsigned  rrd_flags = RRD_READWRITE | RRD_CREAT;
	int ret = 0;

	if (opt_no_overwrite) {
		rrd_flags |= RRD_EXCL ;
	}

	unkn_cnt = 0;
	for (i = 0; i < rrd->stat_head->rra_cnt; i++)
		unkn_cnt += rrd->stat_head->ds_cnt * rrd->rra_def[i].row_cnt;

	if ((rrd_file_dn = rrd_open(file_name, rrd, rrd_flags, &ret)) == NULL) {
		rrd_free2(rrd);
		return ret;
	}

	if (rrd_write(rrd_file_dn, rrd->stat_head, sizeof(stat_head_t)) < 0){
		rrd_free2(rrd);
		rrd_close(rrd_file_dn);
		return (-RRD_ERR_WRITE5);
	}

	rrd_write(rrd_file_dn, rrd->ds_def, sizeof(ds_def_t) * rrd->stat_head->ds_cnt);

	rrd_write(rrd_file_dn, rrd->rra_def,
			sizeof(rra_def_t) * rrd->stat_head->rra_cnt);

	rrd_write(rrd_file_dn, rrd->live_head, sizeof(live_head_t));

	if ((rrd->pdp_prep = (pdp_prep_t*)calloc(1, sizeof(pdp_prep_t))) == NULL) {
		rrd_free2(rrd);
		rrd_close(rrd_file_dn);
		return (-RRD_ERR_ALLOC);
	}

	strcpy(rrd->pdp_prep->last_ds, "U");

	rrd->pdp_prep->scratch[PDP_val].u_val = 0.0;
	rrd->pdp_prep->scratch[PDP_unkn_sec_cnt].u_cnt =
		rrd->live_head->last_up % rrd->stat_head->pdp_step;

	for (i = 0; i < rrd->stat_head->ds_cnt; i++)
		rrd_write(rrd_file_dn, rrd->pdp_prep, sizeof(pdp_prep_t));

	if ((rrd->cdp_prep = (cdp_prep_t*)calloc(1, sizeof(cdp_prep_t))) == NULL) {
		rrd_free2(rrd);
		rrd_close(rrd_file_dn);
		return (-RRD_ERR_ALLOC);
	}


	for (i = 0; i < rrd->stat_head->rra_cnt; i++) {
		switch (cf_conv(rrd->rra_def[i].cf_nam)) {
			case CF_HWPREDICT:
			case CF_MHWPREDICT:
				init_hwpredict_cdp(rrd->cdp_prep);
				break;
			case CF_SEASONAL:
			case CF_DEVSEASONAL:
				init_seasonal_cdp(rrd->cdp_prep);
				break;
			case CF_FAILURES:
				/* initialize violation history to 0 */
				for (ii = 0; ii < MAX_CDP_PAR_EN; ii++) {
					/* We can zero everything out, by setting u_val to the
					 * NULL address. Each array entry in scratch is 8 bytes
					 * (a double), but u_cnt only accessed 4 bytes (long) */
					rrd->cdp_prep->scratch[ii].u_val = 0.0;
				}
				break;
			default:
				/* can not be zero because we don't know anything ... */
				rrd->cdp_prep->scratch[CDP_val].u_val = DNAN;
				/* startup missing pdp count */
				rrd->cdp_prep->scratch[CDP_unkn_pdp_cnt].u_cnt =
					((rrd->live_head->last_up -
					  rrd->pdp_prep->scratch[PDP_unkn_sec_cnt].u_cnt)
					 % (rrd->stat_head->pdp_step
						 * rrd->rra_def[i].pdp_cnt)) / rrd->stat_head->pdp_step;
				break;
		}

		for (ii = 0; ii < rrd->stat_head->ds_cnt; ii++) {
			rrd_write(rrd_file_dn, rrd->cdp_prep, sizeof(cdp_prep_t));
		}
	}

	/* now, we must make sure that the rest of the rrd
	   struct is properly initialized */

	if ((rrd->rra_ptr = (rra_ptr_t*)calloc(1, sizeof(rra_ptr_t))) == NULL) {
		rrd_free2(rrd);
		rrd_close(rrd_file_dn);
		return -RRD_ERR_ALLOC;
	}

	/* changed this initialization to be consistent with
	 * rrd_restore. With the old value (0), the first update
	 * would occur for cur_row = 1 because rrd_update increments
	 * the pointer a priori. */
	for (i = 0; i < rrd->stat_head->rra_cnt; i++) {
		rrd->rra_ptr->cur_row = rrd_select_initial_row(rrd_file_dn, i, &rrd->rra_def[i]);
		rrd_write(rrd_file_dn, rrd->rra_ptr, sizeof(rra_ptr_t));
	}

	/* write the empty data area */
	if ((unknown = (rrd_value_t *) malloc(512 * sizeof(rrd_value_t))) == NULL) {
		rrd_free2(rrd);
		rrd_close(rrd_file_dn);
		return -RRD_ERR_ALLOC;
	}
	for (i = 0; i < 512; ++i)
		unknown[i] = DNAN;

	while (unkn_cnt > 0) {
		if(rrd_write(rrd_file_dn, unknown, sizeof(rrd_value_t) * min(unkn_cnt, 512)) < 0)
		{
			return -RRD_ERR_CREATE_WRITE;
		}

		unkn_cnt -= 512;
	}
	free(unknown);
	rrd_free2(rrd);
	if (rrd_close(rrd_file_dn) == -1) {
		return -RRD_ERR_CREATE_WRITE;
	}
	/* flush all we don't need out of the cache */
	rrd_init(&rrd_dn);
	if((rrd_file_dn = rrd_open(file_name, &rrd_dn, RRD_READONLY, &ret)) != NULL)
	{
		rrd_dontneed(rrd_file_dn, &rrd_dn);
		/* rrd_free(&rrd_dn); */
		rrd_close(rrd_file_dn);
	}
	return ret;
}
Exemplo n.º 16
0
/* #define DEBUG */
int rrd_create_r(
    const char *filename,
    unsigned long pdp_step,
    time_t last_up,
    int argc,
    const char **argv)
{
    rrd_t     rrd;
    long      i;
    int       offset;
    char     *token;
    char      dummychar1[2], dummychar2[2];
    unsigned short token_idx, error_flag, period = 0;
    unsigned long hashed_name;

    /* init rrd clean */
    rrd_init(&rrd);
    /* static header */
    if ((rrd.stat_head = (stat_head_t*)calloc(1, sizeof(stat_head_t))) == NULL) {
        rrd_set_error("allocating rrd.stat_head");
        rrd_free2(&rrd);
        return (-1);
    }

    /* live header */
    if ((rrd.live_head = (live_head_t*)calloc(1, sizeof(live_head_t))) == NULL) {
        rrd_set_error("allocating rrd.live_head");
        rrd_free2(&rrd);
        return (-1);
    }

    /* set some defaults */
    strcpy(rrd.stat_head->cookie, RRD_COOKIE);
    strcpy(rrd.stat_head->version, RRD_VERSION3);   /* by default we are still version 3 */
    rrd.stat_head->float_cookie = FLOAT_COOKIE;
    rrd.stat_head->ds_cnt = 0;  /* this will be adjusted later */
    rrd.stat_head->rra_cnt = 0; /* ditto */
    rrd.stat_head->pdp_step = pdp_step; /* 5 minute default */

    /* a default value */
    rrd.ds_def = NULL;
    rrd.rra_def = NULL;

    rrd.live_head->last_up = last_up;

    /* optind points to the first non-option command line arg,
     * in this case, the file name. */
    /* Compute the FNV hash value (used by SEASONAL and DEVSEASONAL
     * arrays. */
    hashed_name = FnvHash(filename);
    for (i = 0; i < argc; i++) {
        unsigned int ii;

        if (strncmp(argv[i], "DS:", 3) == 0) {
            size_t    old_size = sizeof(ds_def_t) * (rrd.stat_head->ds_cnt);

            if ((rrd.ds_def = (ds_def_t*)rrd_realloc(rrd.ds_def,
                                          old_size + sizeof(ds_def_t))) ==
                NULL) {
                rrd_set_error("allocating rrd.ds_def");
                rrd_free2(&rrd);
                return (-1);
            }
            memset(&rrd.ds_def[rrd.stat_head->ds_cnt], 0, sizeof(ds_def_t));
            /* extract the name and type */
            switch (sscanf(&argv[i][3],
                           DS_NAM_FMT "%1[:]" DST_FMT "%1[:]%n",
                           rrd.ds_def[rrd.stat_head->ds_cnt].ds_nam,
                           dummychar1,
                           rrd.ds_def[rrd.stat_head->ds_cnt].dst,
                           dummychar2, &offset)) {
            case 0:
            case 1:
                rrd_set_error("Invalid DS name");
                break;
            case 2:
            case 3:
                rrd_set_error("Invalid DS type");
                break;
            case 4:    /* (%n may or may not be counted) */
            case 5:    /* check for duplicate datasource names */
                for (ii = 0; ii < rrd.stat_head->ds_cnt; ii++)
                    if (strcmp(rrd.ds_def[rrd.stat_head->ds_cnt].ds_nam,
                               rrd.ds_def[ii].ds_nam) == 0)
                        rrd_set_error("Duplicate DS name: %s",
                                      rrd.ds_def[ii].ds_nam);
                /* DS_type may be valid or not. Checked later */
                break;
            default:
                rrd_set_error("invalid DS format");
            }
            if (rrd_test_error()) {
                rrd_free2(&rrd);
                return -1;
            }

            /* parse the remainder of the arguments */
            switch (dst_conv(rrd.ds_def[rrd.stat_head->ds_cnt].dst)) {
            case DST_COUNTER:
            case DST_ABSOLUTE:
            case DST_GAUGE:
            case DST_DERIVE:
                parseGENERIC_DS(&argv[i][offset + 3], &rrd,
                                rrd.stat_head->ds_cnt);
                break;
            case DST_CDEF:
                parseCDEF_DS(&argv[i][offset + 3], &rrd,
                             rrd.stat_head->ds_cnt);
                break;
            default:
                rrd_set_error("invalid DS type specified");
                break;
            }

            if (rrd_test_error()) {
                rrd_free2(&rrd);
                return -1;
            }
            rrd.stat_head->ds_cnt++;
        } else if (strncmp(argv[i], "RRA:", 4) == 0) {
            char     *argvcopy;
            char     *tokptr = "";
            size_t    old_size = sizeof(rra_def_t) * (rrd.stat_head->rra_cnt);
            int       row_cnt;

            if ((rrd.rra_def = (rra_def_t*)rrd_realloc(rrd.rra_def,
                                           old_size + sizeof(rra_def_t))) ==
                NULL) {
                rrd_set_error("allocating rrd.rra_def");
                rrd_free2(&rrd);
                return (-1);
            }
            memset(&rrd.rra_def[rrd.stat_head->rra_cnt], 0,
                   sizeof(rra_def_t));

            argvcopy = strdup(argv[i]);
            token = strtok_r(&argvcopy[4], ":", &tokptr);
            token_idx = error_flag = 0;
            while (token != NULL) {
                switch (token_idx) {
                case 0:
                    if (sscanf(token, CF_NAM_FMT,
                               rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam) !=
                        1)
                        rrd_set_error("Failed to parse CF name");
                    switch (cf_conv
                            (rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam)) {
                    case CF_MHWPREDICT:
                        strcpy(rrd.stat_head->version, RRD_VERSION);    /* MHWPREDICT causes Version 4 */
                    case CF_HWPREDICT:
                        /* initialize some parameters */
                        rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_hw_alpha].
                            u_val = 0.1;
                        rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_hw_beta].
                            u_val = 1.0 / 288;
                        rrd.rra_def[rrd.stat_head->rra_cnt].
                            par[RRA_dependent_rra_idx].u_cnt =
                            rrd.stat_head->rra_cnt;
                        break;
                    case CF_DEVSEASONAL:
                    case CF_SEASONAL:
                        /* initialize some parameters */
                        rrd.rra_def[rrd.stat_head->rra_cnt].
                            par[RRA_seasonal_gamma].u_val = 0.1;
                        rrd.rra_def[rrd.stat_head->rra_cnt].
                            par[RRA_seasonal_smoothing_window].u_val = 0.05;
                        /* fall through */
                    case CF_DEVPREDICT:
                        rrd.rra_def[rrd.stat_head->rra_cnt].
                            par[RRA_dependent_rra_idx].u_cnt = -1;
                        break;
                    case CF_FAILURES:
                        rrd.rra_def[rrd.stat_head->rra_cnt].
                            par[RRA_delta_pos].u_val = 2.0;
                        rrd.rra_def[rrd.stat_head->rra_cnt].
                            par[RRA_delta_neg].u_val = 2.0;
                        rrd.rra_def[rrd.stat_head->rra_cnt].
                            par[RRA_window_len].u_cnt = 3;
                        rrd.rra_def[rrd.stat_head->rra_cnt].
                            par[RRA_failure_threshold].u_cnt = 2;
                        rrd.rra_def[rrd.stat_head->rra_cnt].
                            par[RRA_dependent_rra_idx].u_cnt = -1;
                        break;
                        /* invalid consolidation function */
                    case -1:
                        rrd_set_error
                            ("Unrecognized consolidation function %s",
                             rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam);
                    default:
                        break;
                    }
                    /* default: 1 pdp per cdp */
                    rrd.rra_def[rrd.stat_head->rra_cnt].pdp_cnt = 1;
                    break;
                case 1:
                    switch (cf_conv
                            (rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam)) {
                    case CF_HWPREDICT:
                    case CF_MHWPREDICT:
                    case CF_DEVSEASONAL:
                    case CF_SEASONAL:
                    case CF_DEVPREDICT:
                    case CF_FAILURES:
                        row_cnt = atoi(token);
                        if (row_cnt <= 0)
                            rrd_set_error("Invalid row count: %i", row_cnt);
                        rrd.rra_def[rrd.stat_head->rra_cnt].row_cnt = row_cnt;
                        break;
                    default:
                        rrd.rra_def[rrd.stat_head->rra_cnt].
                            par[RRA_cdp_xff_val].u_val = atof(token);
                        if (rrd.rra_def[rrd.stat_head->rra_cnt].
                            par[RRA_cdp_xff_val].u_val < 0.0
                            || rrd.rra_def[rrd.stat_head->rra_cnt].
                            par[RRA_cdp_xff_val].u_val >= 1.0)
                            rrd_set_error
                                ("Invalid xff: must be between 0 and 1");
                        break;
                    }
                    break;
                case 2:
                    switch (cf_conv
                            (rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam)) {
                    case CF_HWPREDICT:
                    case CF_MHWPREDICT:
                        rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_hw_alpha].
                            u_val = atof(token);
                        if (atof(token) <= 0.0 || atof(token) >= 1.0)
                            rrd_set_error
                                ("Invalid alpha: must be between 0 and 1");
                        break;
                    case CF_DEVSEASONAL:
                    case CF_SEASONAL:
                        rrd.rra_def[rrd.stat_head->rra_cnt].
                            par[RRA_seasonal_gamma].u_val = atof(token);
                        if (atof(token) <= 0.0 || atof(token) >= 1.0)
                            rrd_set_error
                                ("Invalid gamma: must be between 0 and 1");
                        rrd.rra_def[rrd.stat_head->rra_cnt].
                            par[RRA_seasonal_smooth_idx].u_cnt =
                            hashed_name %
                            rrd.rra_def[rrd.stat_head->rra_cnt].row_cnt;
                        break;
                    case CF_FAILURES:
                        /* specifies the # of violations that constitutes the failure threshold */
                        rrd.rra_def[rrd.stat_head->rra_cnt].
                            par[RRA_failure_threshold].u_cnt = atoi(token);
                        if (atoi(token) < 1
                            || atoi(token) > MAX_FAILURES_WINDOW_LEN)
                            rrd_set_error
                                ("Failure threshold is out of range %d, %d",
                                 1, MAX_FAILURES_WINDOW_LEN);
                        break;
                    case CF_DEVPREDICT:
                        /* specifies the index (1-based) of CF_DEVSEASONAL array
                         * associated with this CF_DEVPREDICT array. */
                        rrd.rra_def[rrd.stat_head->rra_cnt].
                            par[RRA_dependent_rra_idx].u_cnt =
                            atoi(token) - 1;
                        break;
                    default:
                        rrd.rra_def[rrd.stat_head->rra_cnt].pdp_cnt =
                            atoi(token);
                        if (atoi(token) < 1)
                            rrd_set_error("Invalid step: must be >= 1");
                        break;
                    }
                    break;
                case 3:
                    switch (cf_conv
                            (rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam)) {
                    case CF_HWPREDICT:
                    case CF_MHWPREDICT:
                        rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_hw_beta].
                            u_val = atof(token);
                        if (atof(token) < 0.0 || atof(token) > 1.0)
                            rrd_set_error
                                ("Invalid beta: must be between 0 and 1");
                        break;
                    case CF_DEVSEASONAL:
                    case CF_SEASONAL:
                        /* specifies the index (1-based) of CF_HWPREDICT array
                         * associated with this CF_DEVSEASONAL or CF_SEASONAL array. 
                         * */
                        rrd.rra_def[rrd.stat_head->rra_cnt].
                            par[RRA_dependent_rra_idx].u_cnt =
                            atoi(token) - 1;
                        break;
                    case CF_FAILURES:
                        /* specifies the window length */
                        rrd.rra_def[rrd.stat_head->rra_cnt].
                            par[RRA_window_len].u_cnt = atoi(token);
                        if (atoi(token) < 1
                            || atoi(token) > MAX_FAILURES_WINDOW_LEN)
                            rrd_set_error
                                ("Window length is out of range %d, %d", 1,
                                 MAX_FAILURES_WINDOW_LEN);
                        /* verify that window length exceeds the failure threshold */
                        if (rrd.rra_def[rrd.stat_head->rra_cnt].
                            par[RRA_window_len].u_cnt <
                            rrd.rra_def[rrd.stat_head->rra_cnt].
                            par[RRA_failure_threshold].u_cnt)
                            rrd_set_error
                                ("Window length is shorter than the failure threshold");
                        break;
                    case CF_DEVPREDICT:
                        /* shouldn't be any more arguments */
                        rrd_set_error
                            ("Unexpected extra argument for consolidation function DEVPREDICT");
                        break;
                    default:
                        row_cnt = atoi(token);
                        if (row_cnt <= 0)
                            rrd_set_error("Invalid row count: %i", row_cnt);
                        rrd.rra_def[rrd.stat_head->rra_cnt].row_cnt = row_cnt;
                        break;
                    }
                    break;
                case 4:
                    switch (cf_conv
                            (rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam)) {
                    case CF_FAILURES:
                        /* specifies the index (1-based) of CF_DEVSEASONAL array
                         * associated with this CF_DEVFAILURES array. */
                        rrd.rra_def[rrd.stat_head->rra_cnt].
                            par[RRA_dependent_rra_idx].u_cnt =
                            atoi(token) - 1;
                        break;
                    case CF_DEVSEASONAL:
                    case CF_SEASONAL:
                        /* optional smoothing window */
                        if (sscanf(token, "smoothing-window=%lf",
                                   &(rrd.rra_def[rrd.stat_head->rra_cnt].
                                     par[RRA_seasonal_smoothing_window].
                                     u_val))) {
                            strcpy(rrd.stat_head->version, RRD_VERSION);    /* smoothing-window causes Version 4 */
                            if (rrd.rra_def[rrd.stat_head->rra_cnt].
                                par[RRA_seasonal_smoothing_window].u_val < 0.0
                                || rrd.rra_def[rrd.stat_head->rra_cnt].
                                par[RRA_seasonal_smoothing_window].u_val >
                                1.0) {
                                rrd_set_error
                                    ("Invalid smoothing-window %f: must be between 0 and 1",
                                     rrd.rra_def[rrd.stat_head->rra_cnt].
                                     par[RRA_seasonal_smoothing_window].
                                     u_val);
                            }
                        } else {
                            rrd_set_error("Invalid option %s", token);
                        }
                        break;
                    case CF_HWPREDICT:
                    case CF_MHWPREDICT:
                        /* length of the associated CF_SEASONAL and CF_DEVSEASONAL arrays. */
                        period = atoi(token);
                        if (period >
                            rrd.rra_def[rrd.stat_head->rra_cnt].row_cnt)
                            rrd_set_error
                                ("Length of seasonal cycle exceeds length of HW prediction array");
                        break;
                    default:
                        /* shouldn't be any more arguments */
                        rrd_set_error
                            ("Unexpected extra argument for consolidation function %s",
                             rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam);
                        break;
                    }
                    break;
                case 5:
                    /* If we are here, this must be a CF_HWPREDICT RRA.
                     * Specifies the index (1-based) of CF_SEASONAL array
                     * associated with this CF_HWPREDICT array. If this argument 
                     * is missing, then the CF_SEASONAL, CF_DEVSEASONAL, CF_DEVPREDICT,
                     * CF_FAILURES.
                     * arrays are created automatically. */
                    rrd.rra_def[rrd.stat_head->rra_cnt].
                        par[RRA_dependent_rra_idx].u_cnt = atoi(token) - 1;
                    break;
                default:
                    /* should never get here */
                    rrd_set_error("Unknown error");
                    break;
                }       /* end switch */
                if (rrd_test_error()) {
                    /* all errors are unrecoverable */
                    free(argvcopy);
                    rrd_free2(&rrd);
                    return (-1);
                }
                token = strtok_r(NULL, ":", &tokptr);
                token_idx++;
            }           /* end while */
            free(argvcopy);
#ifdef DEBUG
            fprintf(stderr,
                    "Creating RRA CF: %s, dep idx %lu, current idx %lu\n",
                    rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam,
                    rrd.rra_def[rrd.stat_head->rra_cnt].
                    par[RRA_dependent_rra_idx].u_cnt, rrd.stat_head->rra_cnt);
#endif
            /* should we create CF_SEASONAL, CF_DEVSEASONAL, and CF_DEVPREDICT? */
            if ((cf_conv(rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam) ==
                 CF_HWPREDICT
                 || cf_conv(rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam) ==
                 CF_MHWPREDICT)
                && rrd.rra_def[rrd.stat_head->rra_cnt].
                par[RRA_dependent_rra_idx].u_cnt == rrd.stat_head->rra_cnt) {
#ifdef DEBUG
                fprintf(stderr, "Creating HW contingent RRAs\n");
#endif
                if (create_hw_contingent_rras(&rrd, period, hashed_name) ==
                    -1) {
                    rrd_set_error("creating contingent RRA");
                    rrd_free2(&rrd);
                    return -1;
                }
            }
            rrd.stat_head->rra_cnt++;
        } else {
            rrd_set_error("can't parse argument '%s'", argv[i]);
            rrd_free2(&rrd);
            return -1;
        }
    }


    if (rrd.stat_head->rra_cnt < 1) {
        rrd_set_error("you must define at least one Round Robin Archive");
        rrd_free2(&rrd);
        return (-1);
    }

    if (rrd.stat_head->ds_cnt < 1) {
        rrd_set_error("you must define at least one Data Source");
        rrd_free2(&rrd);
        return (-1);
    }
    return rrd_create_fn(filename, &rrd);
}
Exemplo n.º 17
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;
    double    max;
    char      dst[DST_SIZE];
    rrd_file_t *rrd_file;
    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'},
        {0, 0, 0, 0}
    };

    optind = 0;
    opterr = 0;         /* initialize getopt */


    rrd_init(&rrd);
    rrd_file = rrd_open(argv[1], &rrd, RRD_READWRITE);
    if (rrd_file == NULL) {
        rrd_free(&rrd);
        return -1;
    }

    while (1) {
        int       option_index = 0;
        int       opt;
        char     *old_locale = "";

        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':
            old_locale = setlocale(LC_NUMERIC, NULL);
            setlocale(LC_NUMERIC, "C");
            if ((matches =
                 sscanf(optarg, DS_NAM_FMT ":%ld", ds_nam,
                        &heartbeat)) != 2) {
                rrd_set_error("invalid arguments for heartbeat");
                rrd_free(&rrd);
                rrd_close(rrd_file);
                setlocale(LC_NUMERIC, old_locale);
                return -1;
            }
            setlocale(LC_NUMERIC, old_locale);
            if ((ds = ds_match(&rrd, ds_nam)) == -1) {
                rrd_free(&rrd);
                rrd_close(rrd_file);
                return -1;
            }
            rrd.ds_def[ds].par[DS_mrhb_cnt].u_cnt = heartbeat;
            break;

        case 'i':
            old_locale = setlocale(LC_NUMERIC, NULL);
            setlocale(LC_NUMERIC, "C");
            if ((matches =
                 sscanf(optarg, DS_NAM_FMT ":%lf", ds_nam, &min)) < 1) {
                rrd_set_error("invalid arguments for minimum ds value");
                rrd_free(&rrd);
                rrd_close(rrd_file);
                setlocale(LC_NUMERIC, old_locale);
                return -1;
            }
            setlocale(LC_NUMERIC, old_locale);
            if ((ds = ds_match(&rrd, ds_nam)) == -1) {
                rrd_free(&rrd);
                rrd_close(rrd_file);
                return -1;
            }

            if (matches == 1)
                min = DNAN;
            rrd.ds_def[ds].par[DS_min_val].u_val = min;
            break;

        case 'a':
            old_locale = setlocale(LC_NUMERIC, NULL);
            setlocale(LC_NUMERIC, "C");
            if ((matches =
                 sscanf(optarg, DS_NAM_FMT ":%lf", ds_nam, &max)) < 1) {
                rrd_set_error("invalid arguments for maximum ds value");
                rrd_free(&rrd);
                rrd_close(rrd_file);
                setlocale(LC_NUMERIC, old_locale);
                return -1;
            }
            setlocale(LC_NUMERIC, old_locale);
            if ((ds = ds_match(&rrd, ds_nam)) == -1) {
                rrd_free(&rrd);
                rrd_close(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);
                rrd_close(rrd_file);
                return -1;
            }
            if ((ds = ds_match(&rrd, ds_nam)) == -1) {
                rrd_free(&rrd);
                rrd_close(rrd_file);
                return -1;
            }
            if ((int) dst_conv(dst) == -1) {
                rrd_free(&rrd);
                rrd_close(rrd_file);
                return -1;
            }
            /* 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");
                rrd_free(&rrd);
                rrd_close(rrd_file);
                return -1;
            }
            if ((ds = ds_match(&rrd, ds_nam)) == -1) {
                rrd_free(&rrd);
                rrd_close(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)) {
                if (set_hwarg(&rrd, CF_MHWPREDICT, RRA_hw_alpha, optarg)) {
                    rrd_free(&rrd);
                    return -1;
                }
                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)) {
                    rrd_free(&rrd);
                    return -1;
                }
                rrd_clear_error();
            }
            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);
                rrd_close(rrd_file);
                return -1;
            }
            if ((ds = ds_match(&rrd, ds_nam)) == -1) {
                /* ds_match handles it own errors */
                rrd_free(&rrd);
                rrd_close(rrd_file);
                return -1;
            }
            reset_aberrant_coefficients(&rrd, rrd_file, (unsigned long) ds);
            if (rrd_test_error()) {
                rrd_free(&rrd);
                rrd_close(rrd_file);
                return -1;
            }
            break;
        case 's':
            strcpy(rrd.stat_head->version, RRD_VERSION);    /* smoothing_window causes Version 4 */
            if (set_hwsmootharg
                (&rrd, CF_SEASONAL, RRA_seasonal_smoothing_window, optarg)) {
                rrd_free(&rrd);
                return -1;
            }
            break;
        case 'S':
            strcpy(rrd.stat_head->version, RRD_VERSION);    /* smoothing_window causes Version 4 */
            if (set_hwsmootharg
                (&rrd, CF_DEVSEASONAL, RRA_seasonal_smoothing_window,
                 optarg)) {
                rrd_free(&rrd);
                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);
            rrd_close(rrd_file);
            return -1;
        }
    }
    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);
    } 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);
            }
    }
    rrd_close(rrd_file);
    rrd_free(&rrd);
    return 0;
}