162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* Filesystem parameter parser. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 2018 Red Hat, Inc. All Rights Reserved. 562306a36Sopenharmony_ci * Written by David Howells (dhowells@redhat.com) 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/export.h> 962306a36Sopenharmony_ci#include <linux/fs_context.h> 1062306a36Sopenharmony_ci#include <linux/fs_parser.h> 1162306a36Sopenharmony_ci#include <linux/slab.h> 1262306a36Sopenharmony_ci#include <linux/security.h> 1362306a36Sopenharmony_ci#include <linux/namei.h> 1462306a36Sopenharmony_ci#include "internal.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_cistatic const struct constant_table bool_names[] = { 1762306a36Sopenharmony_ci { "0", false }, 1862306a36Sopenharmony_ci { "1", true }, 1962306a36Sopenharmony_ci { "false", false }, 2062306a36Sopenharmony_ci { "no", false }, 2162306a36Sopenharmony_ci { "true", true }, 2262306a36Sopenharmony_ci { "yes", true }, 2362306a36Sopenharmony_ci { }, 2462306a36Sopenharmony_ci}; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistatic const struct constant_table * 2762306a36Sopenharmony_ci__lookup_constant(const struct constant_table *tbl, const char *name) 2862306a36Sopenharmony_ci{ 2962306a36Sopenharmony_ci for ( ; tbl->name; tbl++) 3062306a36Sopenharmony_ci if (strcmp(name, tbl->name) == 0) 3162306a36Sopenharmony_ci return tbl; 3262306a36Sopenharmony_ci return NULL; 3362306a36Sopenharmony_ci} 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci/** 3662306a36Sopenharmony_ci * lookup_constant - Look up a constant by name in an ordered table 3762306a36Sopenharmony_ci * @tbl: The table of constants to search. 3862306a36Sopenharmony_ci * @name: The name to look up. 3962306a36Sopenharmony_ci * @not_found: The value to return if the name is not found. 4062306a36Sopenharmony_ci */ 4162306a36Sopenharmony_ciint lookup_constant(const struct constant_table *tbl, const char *name, int not_found) 4262306a36Sopenharmony_ci{ 4362306a36Sopenharmony_ci const struct constant_table *p = __lookup_constant(tbl, name); 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci return p ? p->value : not_found; 4662306a36Sopenharmony_ci} 4762306a36Sopenharmony_ciEXPORT_SYMBOL(lookup_constant); 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistatic inline bool is_flag(const struct fs_parameter_spec *p) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci return p->type == NULL; 5262306a36Sopenharmony_ci} 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistatic const struct fs_parameter_spec *fs_lookup_key( 5562306a36Sopenharmony_ci const struct fs_parameter_spec *desc, 5662306a36Sopenharmony_ci struct fs_parameter *param, bool *negated) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci const struct fs_parameter_spec *p, *other = NULL; 5962306a36Sopenharmony_ci const char *name = param->key; 6062306a36Sopenharmony_ci bool want_flag = param->type == fs_value_is_flag; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci *negated = false; 6362306a36Sopenharmony_ci for (p = desc; p->name; p++) { 6462306a36Sopenharmony_ci if (strcmp(p->name, name) != 0) 6562306a36Sopenharmony_ci continue; 6662306a36Sopenharmony_ci if (likely(is_flag(p) == want_flag)) 6762306a36Sopenharmony_ci return p; 6862306a36Sopenharmony_ci other = p; 6962306a36Sopenharmony_ci } 7062306a36Sopenharmony_ci if (want_flag) { 7162306a36Sopenharmony_ci if (name[0] == 'n' && name[1] == 'o' && name[2]) { 7262306a36Sopenharmony_ci for (p = desc; p->name; p++) { 7362306a36Sopenharmony_ci if (strcmp(p->name, name + 2) != 0) 7462306a36Sopenharmony_ci continue; 7562306a36Sopenharmony_ci if (!(p->flags & fs_param_neg_with_no)) 7662306a36Sopenharmony_ci continue; 7762306a36Sopenharmony_ci *negated = true; 7862306a36Sopenharmony_ci return p; 7962306a36Sopenharmony_ci } 8062306a36Sopenharmony_ci } 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci return other; 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci/* 8662306a36Sopenharmony_ci * fs_parse - Parse a filesystem configuration parameter 8762306a36Sopenharmony_ci * @fc: The filesystem context to log errors through. 8862306a36Sopenharmony_ci * @desc: The parameter description to use. 8962306a36Sopenharmony_ci * @param: The parameter. 9062306a36Sopenharmony_ci * @result: Where to place the result of the parse 9162306a36Sopenharmony_ci * 9262306a36Sopenharmony_ci * Parse a filesystem configuration parameter and attempt a conversion for a 9362306a36Sopenharmony_ci * simple parameter for which this is requested. If successful, the determined 9462306a36Sopenharmony_ci * parameter ID is placed into @result->key, the desired type is indicated in 9562306a36Sopenharmony_ci * @result->t and any converted value is placed into an appropriate member of 9662306a36Sopenharmony_ci * the union in @result. 9762306a36Sopenharmony_ci * 9862306a36Sopenharmony_ci * The function returns the parameter number if the parameter was matched, 9962306a36Sopenharmony_ci * -ENOPARAM if it wasn't matched and @desc->ignore_unknown indicated that 10062306a36Sopenharmony_ci * unknown parameters are okay and -EINVAL if there was a conversion issue or 10162306a36Sopenharmony_ci * the parameter wasn't recognised and unknowns aren't okay. 10262306a36Sopenharmony_ci */ 10362306a36Sopenharmony_ciint __fs_parse(struct p_log *log, 10462306a36Sopenharmony_ci const struct fs_parameter_spec *desc, 10562306a36Sopenharmony_ci struct fs_parameter *param, 10662306a36Sopenharmony_ci struct fs_parse_result *result) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci const struct fs_parameter_spec *p; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci result->uint_64 = 0; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci p = fs_lookup_key(desc, param, &result->negated); 11362306a36Sopenharmony_ci if (!p) 11462306a36Sopenharmony_ci return -ENOPARAM; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci if (p->flags & fs_param_deprecated) 11762306a36Sopenharmony_ci warn_plog(log, "Deprecated parameter '%s'", param->key); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci /* Try to turn the type we were given into the type desired by the 12062306a36Sopenharmony_ci * parameter and give an error if we can't. 12162306a36Sopenharmony_ci */ 12262306a36Sopenharmony_ci if (is_flag(p)) { 12362306a36Sopenharmony_ci if (param->type != fs_value_is_flag) 12462306a36Sopenharmony_ci return inval_plog(log, "Unexpected value for '%s'", 12562306a36Sopenharmony_ci param->key); 12662306a36Sopenharmony_ci result->boolean = !result->negated; 12762306a36Sopenharmony_ci } else { 12862306a36Sopenharmony_ci int ret = p->type(log, p, param, result); 12962306a36Sopenharmony_ci if (ret) 13062306a36Sopenharmony_ci return ret; 13162306a36Sopenharmony_ci } 13262306a36Sopenharmony_ci return p->opt; 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ciEXPORT_SYMBOL(__fs_parse); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci/** 13762306a36Sopenharmony_ci * fs_lookup_param - Look up a path referred to by a parameter 13862306a36Sopenharmony_ci * @fc: The filesystem context to log errors through. 13962306a36Sopenharmony_ci * @param: The parameter. 14062306a36Sopenharmony_ci * @want_bdev: T if want a blockdev 14162306a36Sopenharmony_ci * @flags: Pathwalk flags passed to filename_lookup() 14262306a36Sopenharmony_ci * @_path: The result of the lookup 14362306a36Sopenharmony_ci */ 14462306a36Sopenharmony_ciint fs_lookup_param(struct fs_context *fc, 14562306a36Sopenharmony_ci struct fs_parameter *param, 14662306a36Sopenharmony_ci bool want_bdev, 14762306a36Sopenharmony_ci unsigned int flags, 14862306a36Sopenharmony_ci struct path *_path) 14962306a36Sopenharmony_ci{ 15062306a36Sopenharmony_ci struct filename *f; 15162306a36Sopenharmony_ci bool put_f; 15262306a36Sopenharmony_ci int ret; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci switch (param->type) { 15562306a36Sopenharmony_ci case fs_value_is_string: 15662306a36Sopenharmony_ci f = getname_kernel(param->string); 15762306a36Sopenharmony_ci if (IS_ERR(f)) 15862306a36Sopenharmony_ci return PTR_ERR(f); 15962306a36Sopenharmony_ci put_f = true; 16062306a36Sopenharmony_ci break; 16162306a36Sopenharmony_ci case fs_value_is_filename: 16262306a36Sopenharmony_ci f = param->name; 16362306a36Sopenharmony_ci put_f = false; 16462306a36Sopenharmony_ci break; 16562306a36Sopenharmony_ci default: 16662306a36Sopenharmony_ci return invalf(fc, "%s: not usable as path", param->key); 16762306a36Sopenharmony_ci } 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci ret = filename_lookup(param->dirfd, f, flags, _path, NULL); 17062306a36Sopenharmony_ci if (ret < 0) { 17162306a36Sopenharmony_ci errorf(fc, "%s: Lookup failure for '%s'", param->key, f->name); 17262306a36Sopenharmony_ci goto out; 17362306a36Sopenharmony_ci } 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci if (want_bdev && 17662306a36Sopenharmony_ci !S_ISBLK(d_backing_inode(_path->dentry)->i_mode)) { 17762306a36Sopenharmony_ci path_put(_path); 17862306a36Sopenharmony_ci _path->dentry = NULL; 17962306a36Sopenharmony_ci _path->mnt = NULL; 18062306a36Sopenharmony_ci errorf(fc, "%s: Non-blockdev passed as '%s'", 18162306a36Sopenharmony_ci param->key, f->name); 18262306a36Sopenharmony_ci ret = -ENOTBLK; 18362306a36Sopenharmony_ci } 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ciout: 18662306a36Sopenharmony_ci if (put_f) 18762306a36Sopenharmony_ci putname(f); 18862306a36Sopenharmony_ci return ret; 18962306a36Sopenharmony_ci} 19062306a36Sopenharmony_ciEXPORT_SYMBOL(fs_lookup_param); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_cistatic int fs_param_bad_value(struct p_log *log, struct fs_parameter *param) 19362306a36Sopenharmony_ci{ 19462306a36Sopenharmony_ci return inval_plog(log, "Bad value for '%s'", param->key); 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ciint fs_param_is_bool(struct p_log *log, const struct fs_parameter_spec *p, 19862306a36Sopenharmony_ci struct fs_parameter *param, struct fs_parse_result *result) 19962306a36Sopenharmony_ci{ 20062306a36Sopenharmony_ci int b; 20162306a36Sopenharmony_ci if (param->type != fs_value_is_string) 20262306a36Sopenharmony_ci return fs_param_bad_value(log, param); 20362306a36Sopenharmony_ci if (!*param->string && (p->flags & fs_param_can_be_empty)) 20462306a36Sopenharmony_ci return 0; 20562306a36Sopenharmony_ci b = lookup_constant(bool_names, param->string, -1); 20662306a36Sopenharmony_ci if (b == -1) 20762306a36Sopenharmony_ci return fs_param_bad_value(log, param); 20862306a36Sopenharmony_ci result->boolean = b; 20962306a36Sopenharmony_ci return 0; 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ciEXPORT_SYMBOL(fs_param_is_bool); 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ciint fs_param_is_u32(struct p_log *log, const struct fs_parameter_spec *p, 21462306a36Sopenharmony_ci struct fs_parameter *param, struct fs_parse_result *result) 21562306a36Sopenharmony_ci{ 21662306a36Sopenharmony_ci int base = (unsigned long)p->data; 21762306a36Sopenharmony_ci if (param->type != fs_value_is_string) 21862306a36Sopenharmony_ci return fs_param_bad_value(log, param); 21962306a36Sopenharmony_ci if (!*param->string && (p->flags & fs_param_can_be_empty)) 22062306a36Sopenharmony_ci return 0; 22162306a36Sopenharmony_ci if (kstrtouint(param->string, base, &result->uint_32) < 0) 22262306a36Sopenharmony_ci return fs_param_bad_value(log, param); 22362306a36Sopenharmony_ci return 0; 22462306a36Sopenharmony_ci} 22562306a36Sopenharmony_ciEXPORT_SYMBOL(fs_param_is_u32); 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ciint fs_param_is_s32(struct p_log *log, const struct fs_parameter_spec *p, 22862306a36Sopenharmony_ci struct fs_parameter *param, struct fs_parse_result *result) 22962306a36Sopenharmony_ci{ 23062306a36Sopenharmony_ci if (param->type != fs_value_is_string) 23162306a36Sopenharmony_ci return fs_param_bad_value(log, param); 23262306a36Sopenharmony_ci if (!*param->string && (p->flags & fs_param_can_be_empty)) 23362306a36Sopenharmony_ci return 0; 23462306a36Sopenharmony_ci if (kstrtoint(param->string, 0, &result->int_32) < 0) 23562306a36Sopenharmony_ci return fs_param_bad_value(log, param); 23662306a36Sopenharmony_ci return 0; 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ciEXPORT_SYMBOL(fs_param_is_s32); 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ciint fs_param_is_u64(struct p_log *log, const struct fs_parameter_spec *p, 24162306a36Sopenharmony_ci struct fs_parameter *param, struct fs_parse_result *result) 24262306a36Sopenharmony_ci{ 24362306a36Sopenharmony_ci if (param->type != fs_value_is_string) 24462306a36Sopenharmony_ci return fs_param_bad_value(log, param); 24562306a36Sopenharmony_ci if (!*param->string && (p->flags & fs_param_can_be_empty)) 24662306a36Sopenharmony_ci return 0; 24762306a36Sopenharmony_ci if (kstrtoull(param->string, 0, &result->uint_64) < 0) 24862306a36Sopenharmony_ci return fs_param_bad_value(log, param); 24962306a36Sopenharmony_ci return 0; 25062306a36Sopenharmony_ci} 25162306a36Sopenharmony_ciEXPORT_SYMBOL(fs_param_is_u64); 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ciint fs_param_is_enum(struct p_log *log, const struct fs_parameter_spec *p, 25462306a36Sopenharmony_ci struct fs_parameter *param, struct fs_parse_result *result) 25562306a36Sopenharmony_ci{ 25662306a36Sopenharmony_ci const struct constant_table *c; 25762306a36Sopenharmony_ci if (param->type != fs_value_is_string) 25862306a36Sopenharmony_ci return fs_param_bad_value(log, param); 25962306a36Sopenharmony_ci if (!*param->string && (p->flags & fs_param_can_be_empty)) 26062306a36Sopenharmony_ci return 0; 26162306a36Sopenharmony_ci c = __lookup_constant(p->data, param->string); 26262306a36Sopenharmony_ci if (!c) 26362306a36Sopenharmony_ci return fs_param_bad_value(log, param); 26462306a36Sopenharmony_ci result->uint_32 = c->value; 26562306a36Sopenharmony_ci return 0; 26662306a36Sopenharmony_ci} 26762306a36Sopenharmony_ciEXPORT_SYMBOL(fs_param_is_enum); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ciint fs_param_is_string(struct p_log *log, const struct fs_parameter_spec *p, 27062306a36Sopenharmony_ci struct fs_parameter *param, struct fs_parse_result *result) 27162306a36Sopenharmony_ci{ 27262306a36Sopenharmony_ci if (param->type != fs_value_is_string || 27362306a36Sopenharmony_ci (!*param->string && !(p->flags & fs_param_can_be_empty))) 27462306a36Sopenharmony_ci return fs_param_bad_value(log, param); 27562306a36Sopenharmony_ci return 0; 27662306a36Sopenharmony_ci} 27762306a36Sopenharmony_ciEXPORT_SYMBOL(fs_param_is_string); 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ciint fs_param_is_blob(struct p_log *log, const struct fs_parameter_spec *p, 28062306a36Sopenharmony_ci struct fs_parameter *param, struct fs_parse_result *result) 28162306a36Sopenharmony_ci{ 28262306a36Sopenharmony_ci if (param->type != fs_value_is_blob) 28362306a36Sopenharmony_ci return fs_param_bad_value(log, param); 28462306a36Sopenharmony_ci return 0; 28562306a36Sopenharmony_ci} 28662306a36Sopenharmony_ciEXPORT_SYMBOL(fs_param_is_blob); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ciint fs_param_is_fd(struct p_log *log, const struct fs_parameter_spec *p, 28962306a36Sopenharmony_ci struct fs_parameter *param, struct fs_parse_result *result) 29062306a36Sopenharmony_ci{ 29162306a36Sopenharmony_ci switch (param->type) { 29262306a36Sopenharmony_ci case fs_value_is_string: 29362306a36Sopenharmony_ci if ((!*param->string && !(p->flags & fs_param_can_be_empty)) || 29462306a36Sopenharmony_ci kstrtouint(param->string, 0, &result->uint_32) < 0) 29562306a36Sopenharmony_ci break; 29662306a36Sopenharmony_ci if (result->uint_32 <= INT_MAX) 29762306a36Sopenharmony_ci return 0; 29862306a36Sopenharmony_ci break; 29962306a36Sopenharmony_ci case fs_value_is_file: 30062306a36Sopenharmony_ci result->uint_32 = param->dirfd; 30162306a36Sopenharmony_ci if (result->uint_32 <= INT_MAX) 30262306a36Sopenharmony_ci return 0; 30362306a36Sopenharmony_ci break; 30462306a36Sopenharmony_ci default: 30562306a36Sopenharmony_ci break; 30662306a36Sopenharmony_ci } 30762306a36Sopenharmony_ci return fs_param_bad_value(log, param); 30862306a36Sopenharmony_ci} 30962306a36Sopenharmony_ciEXPORT_SYMBOL(fs_param_is_fd); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ciint fs_param_is_blockdev(struct p_log *log, const struct fs_parameter_spec *p, 31262306a36Sopenharmony_ci struct fs_parameter *param, struct fs_parse_result *result) 31362306a36Sopenharmony_ci{ 31462306a36Sopenharmony_ci return 0; 31562306a36Sopenharmony_ci} 31662306a36Sopenharmony_ciEXPORT_SYMBOL(fs_param_is_blockdev); 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ciint fs_param_is_path(struct p_log *log, const struct fs_parameter_spec *p, 31962306a36Sopenharmony_ci struct fs_parameter *param, struct fs_parse_result *result) 32062306a36Sopenharmony_ci{ 32162306a36Sopenharmony_ci return 0; 32262306a36Sopenharmony_ci} 32362306a36Sopenharmony_ciEXPORT_SYMBOL(fs_param_is_path); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci#ifdef CONFIG_VALIDATE_FS_PARSER 32662306a36Sopenharmony_ci/** 32762306a36Sopenharmony_ci * validate_constant_table - Validate a constant table 32862306a36Sopenharmony_ci * @tbl: The constant table to validate. 32962306a36Sopenharmony_ci * @tbl_size: The size of the table. 33062306a36Sopenharmony_ci * @low: The lowest permissible value. 33162306a36Sopenharmony_ci * @high: The highest permissible value. 33262306a36Sopenharmony_ci * @special: One special permissible value outside of the range. 33362306a36Sopenharmony_ci */ 33462306a36Sopenharmony_cibool validate_constant_table(const struct constant_table *tbl, size_t tbl_size, 33562306a36Sopenharmony_ci int low, int high, int special) 33662306a36Sopenharmony_ci{ 33762306a36Sopenharmony_ci size_t i; 33862306a36Sopenharmony_ci bool good = true; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci if (tbl_size == 0) { 34162306a36Sopenharmony_ci pr_warn("VALIDATE C-TBL: Empty\n"); 34262306a36Sopenharmony_ci return true; 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci for (i = 0; i < tbl_size; i++) { 34662306a36Sopenharmony_ci if (!tbl[i].name) { 34762306a36Sopenharmony_ci pr_err("VALIDATE C-TBL[%zu]: Null\n", i); 34862306a36Sopenharmony_ci good = false; 34962306a36Sopenharmony_ci } else if (i > 0 && tbl[i - 1].name) { 35062306a36Sopenharmony_ci int c = strcmp(tbl[i-1].name, tbl[i].name); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci if (c == 0) { 35362306a36Sopenharmony_ci pr_err("VALIDATE C-TBL[%zu]: Duplicate %s\n", 35462306a36Sopenharmony_ci i, tbl[i].name); 35562306a36Sopenharmony_ci good = false; 35662306a36Sopenharmony_ci } 35762306a36Sopenharmony_ci if (c > 0) { 35862306a36Sopenharmony_ci pr_err("VALIDATE C-TBL[%zu]: Missorted %s>=%s\n", 35962306a36Sopenharmony_ci i, tbl[i-1].name, tbl[i].name); 36062306a36Sopenharmony_ci good = false; 36162306a36Sopenharmony_ci } 36262306a36Sopenharmony_ci } 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci if (tbl[i].value != special && 36562306a36Sopenharmony_ci (tbl[i].value < low || tbl[i].value > high)) { 36662306a36Sopenharmony_ci pr_err("VALIDATE C-TBL[%zu]: %s->%d const out of range (%d-%d)\n", 36762306a36Sopenharmony_ci i, tbl[i].name, tbl[i].value, low, high); 36862306a36Sopenharmony_ci good = false; 36962306a36Sopenharmony_ci } 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci return good; 37362306a36Sopenharmony_ci} 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci/** 37662306a36Sopenharmony_ci * fs_validate_description - Validate a parameter description 37762306a36Sopenharmony_ci * @name: The parameter name to search for. 37862306a36Sopenharmony_ci * @desc: The parameter description to validate. 37962306a36Sopenharmony_ci */ 38062306a36Sopenharmony_cibool fs_validate_description(const char *name, 38162306a36Sopenharmony_ci const struct fs_parameter_spec *desc) 38262306a36Sopenharmony_ci{ 38362306a36Sopenharmony_ci const struct fs_parameter_spec *param, *p2; 38462306a36Sopenharmony_ci bool good = true; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci for (param = desc; param->name; param++) { 38762306a36Sopenharmony_ci /* Check for duplicate parameter names */ 38862306a36Sopenharmony_ci for (p2 = desc; p2 < param; p2++) { 38962306a36Sopenharmony_ci if (strcmp(param->name, p2->name) == 0) { 39062306a36Sopenharmony_ci if (is_flag(param) != is_flag(p2)) 39162306a36Sopenharmony_ci continue; 39262306a36Sopenharmony_ci pr_err("VALIDATE %s: PARAM[%s]: Duplicate\n", 39362306a36Sopenharmony_ci name, param->name); 39462306a36Sopenharmony_ci good = false; 39562306a36Sopenharmony_ci } 39662306a36Sopenharmony_ci } 39762306a36Sopenharmony_ci } 39862306a36Sopenharmony_ci return good; 39962306a36Sopenharmony_ci} 40062306a36Sopenharmony_ci#endif /* CONFIG_VALIDATE_FS_PARSER */ 401