From 9bd4f25b6b0ea8103324b685fcc21525a29849a8 Mon Sep 17 00:00:00 2001 From: Gaurav Date: Wed, 23 Mar 2011 00:50:17 +0000 Subject: CLI : Validate options farmework. Signed-off-by: Gaurav Signed-off-by: Vijay Bellur BUG: 2064 (NFS options are removed upon glusterd restart) URL: http://bugs.gluster.com/cgi-bin/bugzilla3/show_bug.cgi?id=2064 --- libglusterfs/src/xlator.c | 612 +++++++++++++++++++++++++++++++++++++++++++++- libglusterfs/src/xlator.h | 20 +- 2 files changed, 623 insertions(+), 9 deletions(-) (limited to 'libglusterfs') diff --git a/libglusterfs/src/xlator.c b/libglusterfs/src/xlator.c index fd10eb0975e..b9952120ddb 100644 --- a/libglusterfs/src/xlator.c +++ b/libglusterfs/src/xlator.c @@ -105,6 +105,548 @@ fill_defaults (xlator_t *xl) return; } +int +_volume_option_value_validate_attacherr (xlator_t *xl, + data_pair_t *pair, + volume_option_t *opt, + char **op_errstr) +{ + int i = 0; + int ret = -1; + uint64_t input_size = 0; + long long inputll = 0; + char errstr[256] = {0, }; + + /* Key is valid, validate the option */ + switch (opt->type) { + case GF_OPTION_TYPE_PATH: + { + if (strstr (pair->value->data, "../")) { + gf_log (xl->name, GF_LOG_ERROR, + "invalid path given '%s'", + pair->value->data); + snprintf (errstr, 256, + "invalid path given '%s'", + pair->value->data); + + *op_errstr = gf_strdup (errstr); + ret = -1; + goto out; + } + + /* Make sure the given path is valid */ + if (pair->value->data[0] != '/') { + gf_log (xl->name, GF_LOG_WARNING, + "option %s %s: '%s' is not an " + "absolute path name", + pair->key, pair->value->data, + pair->value->data); + snprintf (errstr, 256, + "option %s %s: '%s' is not an " + "absolute path name", + pair->key, pair->value->data, + pair->value->data); + + *op_errstr = gf_strdup (errstr); + goto out; + } + ret = 0; + } + break; + case GF_OPTION_TYPE_INT: + { + /* Check the range */ + if (gf_string2longlong (pair->value->data, + &inputll) != 0) { + gf_log (xl->name, GF_LOG_ERROR, + "invalid number format \"%s\" in " + "\"option %s\"", + pair->value->data, pair->key); + snprintf (errstr, 256, + "invalid number format \"%s\" in " + "\"option %s\"", + pair->value->data, pair->key); + + *op_errstr = gf_strdup (errstr); + goto out; + } + + if ((opt->min == 0) && (opt->max == 0)) { + gf_log (xl->name, GF_LOG_DEBUG, + "no range check required for " + "'option %s %s'", + pair->key, pair->value->data); + ret = 0; + break; + } + if ((inputll < opt->min) || + (inputll > opt->max)) { + gf_log (xl->name, GF_LOG_WARNING, + "'%lld' in 'option %s %s' is out of " + "range [%"PRId64" - %"PRId64"]", + inputll, pair->key, + pair->value->data, + opt->min, opt->max); + snprintf (errstr, 256, + "'%lld' in 'option %s %s' is out of " + "range [%"PRId64" - %"PRId64"]", + inputll, pair->key, + pair->value->data, + opt->min, opt->max); + + *op_errstr = gf_strdup (errstr); + goto out; + } + ret = 0; + } + break; + case GF_OPTION_TYPE_SIZET: + { + /* Check the range */ + if (gf_string2bytesize (pair->value->data, + &input_size) != 0) { + gf_log (xl->name, GF_LOG_ERROR, + "invalid size format \"%s\" in " + "\"option %s\"", + pair->value->data, pair->key); + snprintf (errstr, 256, + "invalid size format \"%s\" in " + "\"option %s\"", + pair->value->data, pair->key); + + *op_errstr = gf_strdup (errstr); + goto out; + } + + if ((opt->min == 0) && (opt->max == 0)) { + gf_log (xl->name, GF_LOG_DEBUG, + "no range check required for " + "'option %s %s'", + pair->key, pair->value->data); + ret = 0; + break; + } + if ((input_size < opt->min) || + (input_size > opt->max)) { + gf_log (xl->name, GF_LOG_ERROR, + "'%"PRId64"' in 'option %s %s' is " + "out of range [%"PRId64" - %"PRId64"]", + input_size, pair->key, + pair->value->data, + opt->min, opt->max); + snprintf (errstr, 256, + "'%"PRId64"' in 'option %s %s' is " + "out of range [%"PRId64" - %"PRId64"]", + input_size, pair->key, + pair->value->data, + opt->min, opt->max); + + *op_errstr = gf_strdup (errstr); + goto out; + } + ret = 0; + } + break; + case GF_OPTION_TYPE_BOOL: + { + /* Check if the value is one of + '0|1|on|off|no|yes|true|false|enable|disable' */ + gf_boolean_t bool_value; + if (gf_string2boolean (pair->value->data, + &bool_value) != 0) { + gf_log (xl->name, GF_LOG_ERROR, + "option %s %s: '%s' is not a valid " + "boolean value", + pair->key, pair->value->data, + pair->value->data); + snprintf (errstr, 256, + "option %s %s: '%s' is not a valid " + "boolean value", + pair->key, pair->value->data, + pair->value->data); + + *op_errstr = gf_strdup (errstr); + goto out; + } + ret = 0; + } + break; + case GF_OPTION_TYPE_XLATOR: + { + /* Check if the value is one of the xlators */ + xlator_t *xlopt = xl; + while (xlopt->prev) + xlopt = xlopt->prev; + + while (xlopt) { + if (strcmp (pair->value->data, + xlopt->name) == 0) { + ret = 0; + break; + } + xlopt = xlopt->next; + } + if (!xlopt) { + gf_log (xl->name, GF_LOG_ERROR, + "option %s %s: '%s' is not a " + "valid volume name", + pair->key, pair->value->data, + pair->value->data); + snprintf (errstr, 256, + "option %s %s: '%s' is not a " + "valid volume name", + pair->key, pair->value->data, + pair->value->data); + + *op_errstr = gf_strdup (errstr); + goto out; + } + ret = 0; + } + break; + case GF_OPTION_TYPE_STR: + { + /* Check if the '*str' is valid */ + if (GF_OPTION_LIST_EMPTY(opt)) { + ret = 0; + goto out; + } + + for (i = 0; (i < ZR_OPTION_MAX_ARRAY_SIZE) && + opt->value[i]; i++) { + if (fnmatch (opt->value[i], pair->value->data, + FNM_EXTMATCH) == 0) { + ret = 0; + break; + } + } + + if ((i == ZR_OPTION_MAX_ARRAY_SIZE) + || ((i < ZR_OPTION_MAX_ARRAY_SIZE) + && (!opt->value[i]))) { + /* enter here only if + * 1. reached end of opt->value array and haven't + * validated input + * OR + * 2. valid input list is less than + * ZR_OPTION_MAX_ARRAY_SIZE and input has not + * matched all possible input values. + */ + char given_array[4096] = {0,}; + for (i = 0; (i < ZR_OPTION_MAX_ARRAY_SIZE) && + opt->value[i]; i++) { + strcat (given_array, opt->value[i]); + strcat (given_array, ", "); + } + + gf_log (xl->name, GF_LOG_ERROR, + "option %s %s: '%s' is not valid " + "(possible options are %s)", + pair->key, pair->value->data, + pair->value->data, given_array); + snprintf (errstr, 256, + "option %s %s: '%s' is not valid " + "(possible options are %s)", + pair->key, pair->value->data, + pair->value->data, given_array); + + *op_errstr = gf_strdup (errstr); + goto out; + } + } + break; + case GF_OPTION_TYPE_PERCENT: + { + uint32_t percent = 0; + + + /* Check if the value is valid percentage */ + if (gf_string2percent (pair->value->data, + &percent) != 0) { + gf_log (xl->name, GF_LOG_ERROR, + "invalid percent format \"%s\" " + "in \"option %s\"", + pair->value->data, pair->key); + snprintf (errstr, 256, + "invalid percent format \"%s\" " + "in \"option %s\"", + pair->value->data, pair->key); + + *op_errstr = gf_strdup (errstr); + goto out; + } + + if ((percent < 0) || (percent > 100)) { + gf_log (xl->name, GF_LOG_ERROR, + "'%d' in 'option %s %s' is out of " + "range [0 - 100]", + percent, pair->key, + pair->value->data); + snprintf (errstr, 256, + "'%d' in 'option %s %s' is out of " + "range [0 - 100]", + percent, pair->key, + pair->value->data); + + *op_errstr = gf_strdup (errstr); + goto out; + } + ret = 0; + } + break; + case GF_OPTION_TYPE_PERCENT_OR_SIZET: + { + uint32_t percent = 0; + uint64_t input_size = 0; + + /* Check if the value is valid percentage */ + if (gf_string2percent (pair->value->data, + &percent) == 0) { + if (percent > 100) { + gf_log (xl->name, GF_LOG_DEBUG, + "value given was greater than 100, " + "assuming this is actually a size"); + if (gf_string2bytesize (pair->value->data, + &input_size) == 0) { + /* Check the range */ + if ((opt->min == 0) && + (opt->max == 0)) { + gf_log (xl->name, GF_LOG_DEBUG, + "no range check " + "required for " + "'option %s %s'", + pair->key, + pair->value->data); + // It is a size + ret = 0; + goto out; + } + if ((input_size < opt->min) || + (input_size > opt->max)) { + gf_log (xl->name, GF_LOG_ERROR, + "'%"PRId64"' in " + "'option %s %s' is out" + " of range [%"PRId64"" + "- %"PRId64"]", + input_size, pair->key, + pair->value->data, + opt->min, opt->max); + snprintf (errstr, 256, + "'%"PRId64"' in " + "'option %s %s' is " + " out of range [" + "%"PRId64"- %"PRId64"]", + input_size, pair->key, + pair->value->data, + opt->min, opt->max); + + *op_errstr = gf_strdup (errstr); + goto out; + } + // It is a size + ret = 0; + goto out; + } else { + // It's not a percent or size + gf_log (xl->name, GF_LOG_ERROR, + "invalid number format \"%s\" " + "in \"option %s\"", + pair->value->data, pair->key); + + snprintf (errstr, 256, + "invalid number format \"%s\" " + "in \"option %s\"", + pair->value->data, pair->key); + + + *op_errstr = gf_strdup (errstr); + goto out; + } + + } + // It is a percent + ret = 0; + goto out; + } else { + if (gf_string2bytesize (pair->value->data, + &input_size) == 0) { + /* Check the range */ + if ((opt->min == 0) && (opt->max == 0)) { + gf_log (xl->name, GF_LOG_DEBUG, + "no range check required for " + "'option %s %s'", + pair->key, pair->value->data); + // It is a size + ret = 0; + goto out; + } + if ((input_size < opt->min) || + (input_size > opt->max)) { + gf_log (xl->name, GF_LOG_ERROR, + "'%"PRId64"' in 'option %s %s'" + " is out of range [%"PRId64" -" + " %"PRId64"]", + input_size, pair->key, + pair->value->data, + opt->min, opt->max); + snprintf (errstr, 256, + "'%"PRId64"' in 'option %s %s'" + " is out of range [%"PRId64" -" + " %"PRId64"]", + input_size, pair->key, + pair->value->data, + opt->min, opt->max); + + *op_errstr = gf_strdup (errstr); + goto out; + } + } else { + // It's not a percent or size + gf_log (xl->name, GF_LOG_ERROR, + "invalid number format \"%s\" " + "in \"option %s\"", + pair->value->data, pair->key); + snprintf (errstr, 256, + "invalid number format \"%s\" " + "in \"option %s\"", + pair->value->data, pair->key); + + *op_errstr = gf_strdup (errstr); + goto out; + } + //It is a size + ret = 0; + goto out; + } + + } + break; + case GF_OPTION_TYPE_TIME: + { + uint32_t input_time = 0; + + /* Check if the value is valid percentage */ + if (gf_string2time (pair->value->data, + &input_time) != 0) { + gf_log (xl->name, + GF_LOG_ERROR, + "invalid time format \"%s\" in " + "\"option %s\"", + pair->value->data, pair->key); + + snprintf (errstr, 256, + "invalid time format \"%s\" in " + "\"option %s\"", + pair->value->data, pair->key); + + *op_errstr = gf_strdup (errstr); + goto out; + } + + if ((opt->min == 0) && (opt->max == 0)) { + gf_log (xl->name, GF_LOG_DEBUG, + "no range check required for " + "'option %s %s'", + pair->key, pair->value->data); + ret = 0; + goto out; + } + if ((input_time < opt->min) || + (input_time > opt->max)) { + gf_log (xl->name, GF_LOG_ERROR, + "'%"PRIu32"' in 'option %s %s' is " + "out of range [%"PRId64" - %"PRId64"]", + input_time, pair->key, + pair->value->data, + opt->min, opt->max); + + snprintf (errstr, 256, + "'%"PRIu32"' in 'option %s %s' is " + "out of range [%"PRId64" - %"PRId64"]", + input_time, pair->key, + pair->value->data, + opt->min, opt->max); + + *op_errstr = gf_strdup (errstr); + goto out; + } + ret = 0; + } + break; + case GF_OPTION_TYPE_DOUBLE: + { + double input_time = 0.0; + + /* Check if the value is valid double */ + if (gf_string2double (pair->value->data, + &input_time) != 0) { + gf_log (xl->name, + GF_LOG_ERROR, + "invalid double \"%s\" in \"option %s\"", + pair->value->data, pair->key); + + snprintf (errstr, 256, + "invalid double \"%s\" in \"option %s\"", + pair->value->data, pair->key); + + *op_errstr = gf_strdup (errstr); + goto out; + } + + if (input_time < 0.0) { + gf_log (xl->name, + GF_LOG_ERROR, + "invalid time format \"%s\" in \"option %s\"", + pair->value->data, pair->key); + + snprintf (errstr, 256, + "invalid double \"%s\" in \"option %s\"", + pair->value->data, pair->key); + + *op_errstr = gf_strdup (errstr); + goto out; + } + + if ((opt->min == 0) && (opt->max == 0)) { + gf_log (xl->name, GF_LOG_DEBUG, + "no range check required for 'option %s %s'", + pair->key, pair->value->data); + ret = 0; + goto out; + } + ret = 0; + } + break; + case GF_OPTION_TYPE_INTERNET_ADDRESS: + { + if (valid_internet_address (pair->value->data)) { + ret = 0; + } else { + gf_log (xl->name, GF_LOG_ERROR, "internet address '%s'" + " does not conform to standards.", + pair->value->data); + + snprintf (errstr, 256, + "internet address '%s'" + " does not conform to standards.", + pair->value->data); + + *op_errstr = gf_strdup (errstr); + goto out; + } + } + break; + case GF_OPTION_TYPE_ANY: + /* NO CHECK */ + ret = 0; + break; + } + +out: + return ret; +} + + int _volume_option_value_validate (xlator_t *xl, data_pair_t *pair, @@ -497,6 +1039,71 @@ out: return ret; } +int +validate_xlator_volume_options_attacherr (xlator_t *xl, + volume_option_t *opt, + char **op_errstr) +{ + int i = 0; + int ret = -1; + int index = 0; + volume_option_t *trav = NULL; + data_pair_t *pairs = NULL; + + if (!opt) { + ret = 0; + goto out; + } + + /* First search for not supported options, if any report error */ + pairs = xl->options->members_list; + while (pairs) { + ret = -1; + for (index = 0; + opt[index].key && opt[index].key[0] ; index++) { + trav = &(opt[index]); + for (i = 0 ; + (i < ZR_VOLUME_MAX_NUM_KEY) && + trav->key[i]; i++) { + /* Check if the key is valid */ + if (fnmatch (trav->key[i], + pairs->key, FNM_NOESCAPE) == 0) { + ret = 0; + break; + } + } + if (!ret) { + if (i) { + gf_log (xl->name, GF_LOG_WARNING, + "option '%s' is deprecated, " + "preferred is '%s', continuing" + " with correction", + trav->key[i], trav->key[0]); + /* TODO: some bytes lost */ + pairs->key = gf_strdup (trav->key[0]); + } + break; + } + } + if (!ret) { + ret = _volume_option_value_validate_attacherr (xl, + pairs, + trav, + op_errstr); + if (-1 == ret) { + goto out; + } + } + + pairs = pairs->next; + } + + ret = 0; + out: + return ret; +} + + int validate_xlator_volume_options (xlator_t *xl, volume_option_t *opt) { @@ -888,9 +1495,8 @@ xlator_validate_rec (xlator_t *xlator, char **op_errstr) gf_log ("", GF_LOG_DEBUG, "Did not load the symbols"); if (xlator->validate_options) { - if (xlator->validate_options (xlator, xlator->options, - op_errstr)) { - gf_log ("", GF_LOG_INFO, "%s", *op_errstr); + if (xlator->validate_options (xlator, op_errstr)) { + gf_log ("", GF_LOG_DEBUG, "%s", *op_errstr); return -1; } gf_log (xlator->name, GF_LOG_DEBUG, "Validated option"); diff --git a/libglusterfs/src/xlator.h b/libglusterfs/src/xlator.h index 604c8c08f32..e587ae5784d 100644 --- a/libglusterfs/src/xlator.h +++ b/libglusterfs/src/xlator.h @@ -771,8 +771,8 @@ typedef struct volume_options { char *key[ZR_VOLUME_MAX_NUM_KEY]; /* different key, same meaning */ volume_option_type_t type; - int64_t min; /* -1 means no range */ - int64_t max; /* -1 means no range */ + int64_t min; /* 0 means no range */ + int64_t max; /* 0 means no range */ char *value[ZR_OPTION_MAX_ARRAY_SIZE]; /* If specified, will check for one of the value from this array */ @@ -806,10 +806,9 @@ struct _xlator { void (*fini) (xlator_t *this); int32_t (*init) (xlator_t *this); int32_t (*reconfigure) (xlator_t *this, dict_t *options); - int32_t (*mem_acct_init) (xlator_t *this); - int32_t (*validate_options) (xlator_t *this, dict_t *options, - char **op_errstr); - event_notify_fn_t notify; + int32_t (*mem_acct_init) (xlator_t *this); + int32_t (*validate_options) (xlator_t *this, char **op_errstr); + event_notify_fn_t notify; gf_loglevel_t loglevel; /* Log level for translator */ @@ -865,5 +864,14 @@ int is_gf_log_command (xlator_t *trans, const char *name, char *value); int xlator_validate_rec (xlator_t *xlator, char **op_errstr); int graph_reconf_validateopt (glusterfs_graph_t *graph, char **op_errstr); int glusterd_check_log_level (const char *value); +int validate_xlator_volume_options_attacherr (xlator_t *xl, + volume_option_t *opt, + char **op_errstr); +int _volume_option_value_validate_attacherr (xlator_t *xl, + data_pair_t *pair, + volume_option_t *opt, + char **op_errstr); + + #endif /* _XLATOR_H */ -- cgit