1*b4d0d230SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 231d921c7SDavid Howells /* Filesystem parameter parser. 331d921c7SDavid Howells * 431d921c7SDavid Howells * Copyright (C) 2018 Red Hat, Inc. All Rights Reserved. 531d921c7SDavid Howells * Written by David Howells ([email protected]) 631d921c7SDavid Howells */ 731d921c7SDavid Howells 831d921c7SDavid Howells #include <linux/export.h> 931d921c7SDavid Howells #include <linux/fs_context.h> 1031d921c7SDavid Howells #include <linux/fs_parser.h> 1131d921c7SDavid Howells #include <linux/slab.h> 1231d921c7SDavid Howells #include <linux/security.h> 1331d921c7SDavid Howells #include <linux/namei.h> 1431d921c7SDavid Howells #include "internal.h" 1531d921c7SDavid Howells 1631d921c7SDavid Howells static const struct constant_table bool_names[] = { 1731d921c7SDavid Howells { "0", false }, 1831d921c7SDavid Howells { "1", true }, 1931d921c7SDavid Howells { "false", false }, 2031d921c7SDavid Howells { "no", false }, 2131d921c7SDavid Howells { "true", true }, 2231d921c7SDavid Howells { "yes", true }, 2331d921c7SDavid Howells }; 2431d921c7SDavid Howells 2531d921c7SDavid Howells /** 2631d921c7SDavid Howells * lookup_constant - Look up a constant by name in an ordered table 2731d921c7SDavid Howells * @tbl: The table of constants to search. 2831d921c7SDavid Howells * @tbl_size: The size of the table. 2931d921c7SDavid Howells * @name: The name to look up. 3031d921c7SDavid Howells * @not_found: The value to return if the name is not found. 3131d921c7SDavid Howells */ 3231d921c7SDavid Howells int __lookup_constant(const struct constant_table *tbl, size_t tbl_size, 3331d921c7SDavid Howells const char *name, int not_found) 3431d921c7SDavid Howells { 3531d921c7SDavid Howells unsigned int i; 3631d921c7SDavid Howells 3731d921c7SDavid Howells for (i = 0; i < tbl_size; i++) 3831d921c7SDavid Howells if (strcmp(name, tbl[i].name) == 0) 3931d921c7SDavid Howells return tbl[i].value; 4031d921c7SDavid Howells 4131d921c7SDavid Howells return not_found; 4231d921c7SDavid Howells } 4331d921c7SDavid Howells EXPORT_SYMBOL(__lookup_constant); 4431d921c7SDavid Howells 4531d921c7SDavid Howells static const struct fs_parameter_spec *fs_lookup_key( 4631d921c7SDavid Howells const struct fs_parameter_description *desc, 4731d921c7SDavid Howells const char *name) 4831d921c7SDavid Howells { 4931d921c7SDavid Howells const struct fs_parameter_spec *p; 5031d921c7SDavid Howells 5131d921c7SDavid Howells if (!desc->specs) 5231d921c7SDavid Howells return NULL; 5331d921c7SDavid Howells 5431d921c7SDavid Howells for (p = desc->specs; p->name; p++) 5531d921c7SDavid Howells if (strcmp(p->name, name) == 0) 5631d921c7SDavid Howells return p; 5731d921c7SDavid Howells 5831d921c7SDavid Howells return NULL; 5931d921c7SDavid Howells } 6031d921c7SDavid Howells 6131d921c7SDavid Howells /* 6231d921c7SDavid Howells * fs_parse - Parse a filesystem configuration parameter 6331d921c7SDavid Howells * @fc: The filesystem context to log errors through. 6431d921c7SDavid Howells * @desc: The parameter description to use. 6531d921c7SDavid Howells * @param: The parameter. 6631d921c7SDavid Howells * @result: Where to place the result of the parse 6731d921c7SDavid Howells * 6831d921c7SDavid Howells * Parse a filesystem configuration parameter and attempt a conversion for a 6931d921c7SDavid Howells * simple parameter for which this is requested. If successful, the determined 7031d921c7SDavid Howells * parameter ID is placed into @result->key, the desired type is indicated in 7131d921c7SDavid Howells * @result->t and any converted value is placed into an appropriate member of 7231d921c7SDavid Howells * the union in @result. 7331d921c7SDavid Howells * 7431d921c7SDavid Howells * The function returns the parameter number if the parameter was matched, 7531d921c7SDavid Howells * -ENOPARAM if it wasn't matched and @desc->ignore_unknown indicated that 7631d921c7SDavid Howells * unknown parameters are okay and -EINVAL if there was a conversion issue or 7731d921c7SDavid Howells * the parameter wasn't recognised and unknowns aren't okay. 7831d921c7SDavid Howells */ 7931d921c7SDavid Howells int fs_parse(struct fs_context *fc, 8031d921c7SDavid Howells const struct fs_parameter_description *desc, 8131d921c7SDavid Howells struct fs_parameter *param, 8231d921c7SDavid Howells struct fs_parse_result *result) 8331d921c7SDavid Howells { 8431d921c7SDavid Howells const struct fs_parameter_spec *p; 8531d921c7SDavid Howells const struct fs_parameter_enum *e; 8631d921c7SDavid Howells int ret = -ENOPARAM, b; 8731d921c7SDavid Howells 8831d921c7SDavid Howells result->has_value = !!param->string; 8931d921c7SDavid Howells result->negated = false; 9031d921c7SDavid Howells result->uint_64 = 0; 9131d921c7SDavid Howells 9231d921c7SDavid Howells p = fs_lookup_key(desc, param->key); 9331d921c7SDavid Howells if (!p) { 9431d921c7SDavid Howells /* If we didn't find something that looks like "noxxx", see if 9531d921c7SDavid Howells * "xxx" takes the "no"-form negative - but only if there 9631d921c7SDavid Howells * wasn't an value. 9731d921c7SDavid Howells */ 9831d921c7SDavid Howells if (result->has_value) 9931d921c7SDavid Howells goto unknown_parameter; 10031d921c7SDavid Howells if (param->key[0] != 'n' || param->key[1] != 'o' || !param->key[2]) 10131d921c7SDavid Howells goto unknown_parameter; 10231d921c7SDavid Howells 10331d921c7SDavid Howells p = fs_lookup_key(desc, param->key + 2); 10431d921c7SDavid Howells if (!p) 10531d921c7SDavid Howells goto unknown_parameter; 10631d921c7SDavid Howells if (!(p->flags & fs_param_neg_with_no)) 10731d921c7SDavid Howells goto unknown_parameter; 10831d921c7SDavid Howells result->boolean = false; 10931d921c7SDavid Howells result->negated = true; 11031d921c7SDavid Howells } 11131d921c7SDavid Howells 11231d921c7SDavid Howells if (p->flags & fs_param_deprecated) 11331d921c7SDavid Howells warnf(fc, "%s: Deprecated parameter '%s'", 11431d921c7SDavid Howells desc->name, param->key); 11531d921c7SDavid Howells 11631d921c7SDavid Howells if (result->negated) 11731d921c7SDavid Howells goto okay; 11831d921c7SDavid Howells 11931d921c7SDavid Howells /* Certain parameter types only take a string and convert it. */ 12031d921c7SDavid Howells switch (p->type) { 12131d921c7SDavid Howells case __fs_param_wasnt_defined: 12231d921c7SDavid Howells return -EINVAL; 12331d921c7SDavid Howells case fs_param_is_u32: 12431d921c7SDavid Howells case fs_param_is_u32_octal: 12531d921c7SDavid Howells case fs_param_is_u32_hex: 12631d921c7SDavid Howells case fs_param_is_s32: 12731d921c7SDavid Howells case fs_param_is_u64: 12831d921c7SDavid Howells case fs_param_is_enum: 12931d921c7SDavid Howells case fs_param_is_string: 13031d921c7SDavid Howells if (param->type != fs_value_is_string) 13131d921c7SDavid Howells goto bad_value; 13231d921c7SDavid Howells if (!result->has_value) { 13331d921c7SDavid Howells if (p->flags & fs_param_v_optional) 13431d921c7SDavid Howells goto okay; 13531d921c7SDavid Howells goto bad_value; 13631d921c7SDavid Howells } 13731d921c7SDavid Howells /* Fall through */ 13831d921c7SDavid Howells default: 13931d921c7SDavid Howells break; 14031d921c7SDavid Howells } 14131d921c7SDavid Howells 14231d921c7SDavid Howells /* Try to turn the type we were given into the type desired by the 14331d921c7SDavid Howells * parameter and give an error if we can't. 14431d921c7SDavid Howells */ 14531d921c7SDavid Howells switch (p->type) { 14631d921c7SDavid Howells case fs_param_is_flag: 14731d921c7SDavid Howells if (param->type != fs_value_is_flag && 14831d921c7SDavid Howells (param->type != fs_value_is_string || result->has_value)) 14931d921c7SDavid Howells return invalf(fc, "%s: Unexpected value for '%s'", 15031d921c7SDavid Howells desc->name, param->key); 15131d921c7SDavid Howells result->boolean = true; 15231d921c7SDavid Howells goto okay; 15331d921c7SDavid Howells 15431d921c7SDavid Howells case fs_param_is_bool: 15531d921c7SDavid Howells switch (param->type) { 15631d921c7SDavid Howells case fs_value_is_flag: 15731d921c7SDavid Howells result->boolean = true; 15831d921c7SDavid Howells goto okay; 15931d921c7SDavid Howells case fs_value_is_string: 16031d921c7SDavid Howells if (param->size == 0) { 16131d921c7SDavid Howells result->boolean = true; 16231d921c7SDavid Howells goto okay; 16331d921c7SDavid Howells } 16431d921c7SDavid Howells b = lookup_constant(bool_names, param->string, -1); 16531d921c7SDavid Howells if (b == -1) 16631d921c7SDavid Howells goto bad_value; 16731d921c7SDavid Howells result->boolean = b; 16831d921c7SDavid Howells goto okay; 16931d921c7SDavid Howells default: 17031d921c7SDavid Howells goto bad_value; 17131d921c7SDavid Howells } 17231d921c7SDavid Howells 17331d921c7SDavid Howells case fs_param_is_u32: 17431d921c7SDavid Howells ret = kstrtouint(param->string, 0, &result->uint_32); 17531d921c7SDavid Howells goto maybe_okay; 17631d921c7SDavid Howells case fs_param_is_u32_octal: 17731d921c7SDavid Howells ret = kstrtouint(param->string, 8, &result->uint_32); 17831d921c7SDavid Howells goto maybe_okay; 17931d921c7SDavid Howells case fs_param_is_u32_hex: 18031d921c7SDavid Howells ret = kstrtouint(param->string, 16, &result->uint_32); 18131d921c7SDavid Howells goto maybe_okay; 18231d921c7SDavid Howells case fs_param_is_s32: 18331d921c7SDavid Howells ret = kstrtoint(param->string, 0, &result->int_32); 18431d921c7SDavid Howells goto maybe_okay; 18531d921c7SDavid Howells case fs_param_is_u64: 18631d921c7SDavid Howells ret = kstrtoull(param->string, 0, &result->uint_64); 18731d921c7SDavid Howells goto maybe_okay; 18831d921c7SDavid Howells 18931d921c7SDavid Howells case fs_param_is_enum: 19031d921c7SDavid Howells for (e = desc->enums; e->name[0]; e++) { 19131d921c7SDavid Howells if (e->opt == p->opt && 19231d921c7SDavid Howells strcmp(e->name, param->string) == 0) { 19331d921c7SDavid Howells result->uint_32 = e->value; 19431d921c7SDavid Howells goto okay; 19531d921c7SDavid Howells } 19631d921c7SDavid Howells } 19731d921c7SDavid Howells goto bad_value; 19831d921c7SDavid Howells 19931d921c7SDavid Howells case fs_param_is_string: 20031d921c7SDavid Howells goto okay; 20131d921c7SDavid Howells case fs_param_is_blob: 20231d921c7SDavid Howells if (param->type != fs_value_is_blob) 20331d921c7SDavid Howells goto bad_value; 20431d921c7SDavid Howells goto okay; 20531d921c7SDavid Howells 20631d921c7SDavid Howells case fs_param_is_fd: { 20731d921c7SDavid Howells if (param->type != fs_value_is_file) 20831d921c7SDavid Howells goto bad_value; 20931d921c7SDavid Howells goto okay; 21031d921c7SDavid Howells } 21131d921c7SDavid Howells 21231d921c7SDavid Howells case fs_param_is_blockdev: 21331d921c7SDavid Howells case fs_param_is_path: 21431d921c7SDavid Howells goto okay; 21531d921c7SDavid Howells default: 21631d921c7SDavid Howells BUG(); 21731d921c7SDavid Howells } 21831d921c7SDavid Howells 21931d921c7SDavid Howells maybe_okay: 22031d921c7SDavid Howells if (ret < 0) 22131d921c7SDavid Howells goto bad_value; 22231d921c7SDavid Howells okay: 22331d921c7SDavid Howells return p->opt; 22431d921c7SDavid Howells 22531d921c7SDavid Howells bad_value: 22631d921c7SDavid Howells return invalf(fc, "%s: Bad value for '%s'", desc->name, param->key); 22731d921c7SDavid Howells unknown_parameter: 22831d921c7SDavid Howells return -ENOPARAM; 22931d921c7SDavid Howells } 23031d921c7SDavid Howells EXPORT_SYMBOL(fs_parse); 23131d921c7SDavid Howells 23231d921c7SDavid Howells /** 23331d921c7SDavid Howells * fs_lookup_param - Look up a path referred to by a parameter 23431d921c7SDavid Howells * @fc: The filesystem context to log errors through. 23531d921c7SDavid Howells * @param: The parameter. 23631d921c7SDavid Howells * @want_bdev: T if want a blockdev 23731d921c7SDavid Howells * @_path: The result of the lookup 23831d921c7SDavid Howells */ 23931d921c7SDavid Howells int fs_lookup_param(struct fs_context *fc, 24031d921c7SDavid Howells struct fs_parameter *param, 24131d921c7SDavid Howells bool want_bdev, 24231d921c7SDavid Howells struct path *_path) 24331d921c7SDavid Howells { 24431d921c7SDavid Howells struct filename *f; 24531d921c7SDavid Howells unsigned int flags = 0; 24631d921c7SDavid Howells bool put_f; 24731d921c7SDavid Howells int ret; 24831d921c7SDavid Howells 24931d921c7SDavid Howells switch (param->type) { 25031d921c7SDavid Howells case fs_value_is_string: 25131d921c7SDavid Howells f = getname_kernel(param->string); 25231d921c7SDavid Howells if (IS_ERR(f)) 25331d921c7SDavid Howells return PTR_ERR(f); 25431d921c7SDavid Howells put_f = true; 25531d921c7SDavid Howells break; 25631d921c7SDavid Howells case fs_value_is_filename_empty: 25731d921c7SDavid Howells flags = LOOKUP_EMPTY; 25831d921c7SDavid Howells /* Fall through */ 25931d921c7SDavid Howells case fs_value_is_filename: 26031d921c7SDavid Howells f = param->name; 26131d921c7SDavid Howells put_f = false; 26231d921c7SDavid Howells break; 26331d921c7SDavid Howells default: 26431d921c7SDavid Howells return invalf(fc, "%s: not usable as path", param->key); 26531d921c7SDavid Howells } 26631d921c7SDavid Howells 26731d921c7SDavid Howells ret = filename_lookup(param->dirfd, f, flags, _path, NULL); 26831d921c7SDavid Howells if (ret < 0) { 26931d921c7SDavid Howells errorf(fc, "%s: Lookup failure for '%s'", param->key, f->name); 27031d921c7SDavid Howells goto out; 27131d921c7SDavid Howells } 27231d921c7SDavid Howells 27331d921c7SDavid Howells if (want_bdev && 27431d921c7SDavid Howells !S_ISBLK(d_backing_inode(_path->dentry)->i_mode)) { 27531d921c7SDavid Howells path_put(_path); 27631d921c7SDavid Howells _path->dentry = NULL; 27731d921c7SDavid Howells _path->mnt = NULL; 27831d921c7SDavid Howells errorf(fc, "%s: Non-blockdev passed as '%s'", 27931d921c7SDavid Howells param->key, f->name); 28031d921c7SDavid Howells ret = -ENOTBLK; 28131d921c7SDavid Howells } 28231d921c7SDavid Howells 28331d921c7SDavid Howells out: 28431d921c7SDavid Howells if (put_f) 28531d921c7SDavid Howells putname(f); 28631d921c7SDavid Howells return ret; 28731d921c7SDavid Howells } 28831d921c7SDavid Howells EXPORT_SYMBOL(fs_lookup_param); 28931d921c7SDavid Howells 29031d921c7SDavid Howells #ifdef CONFIG_VALIDATE_FS_PARSER 29131d921c7SDavid Howells /** 29231d921c7SDavid Howells * validate_constant_table - Validate a constant table 29331d921c7SDavid Howells * @name: Name to use in reporting 29431d921c7SDavid Howells * @tbl: The constant table to validate. 29531d921c7SDavid Howells * @tbl_size: The size of the table. 29631d921c7SDavid Howells * @low: The lowest permissible value. 29731d921c7SDavid Howells * @high: The highest permissible value. 29831d921c7SDavid Howells * @special: One special permissible value outside of the range. 29931d921c7SDavid Howells */ 30031d921c7SDavid Howells bool validate_constant_table(const struct constant_table *tbl, size_t tbl_size, 30131d921c7SDavid Howells int low, int high, int special) 30231d921c7SDavid Howells { 30331d921c7SDavid Howells size_t i; 30431d921c7SDavid Howells bool good = true; 30531d921c7SDavid Howells 30631d921c7SDavid Howells if (tbl_size == 0) { 30731d921c7SDavid Howells pr_warn("VALIDATE C-TBL: Empty\n"); 30831d921c7SDavid Howells return true; 30931d921c7SDavid Howells } 31031d921c7SDavid Howells 31131d921c7SDavid Howells for (i = 0; i < tbl_size; i++) { 31231d921c7SDavid Howells if (!tbl[i].name) { 31331d921c7SDavid Howells pr_err("VALIDATE C-TBL[%zu]: Null\n", i); 31431d921c7SDavid Howells good = false; 31531d921c7SDavid Howells } else if (i > 0 && tbl[i - 1].name) { 31631d921c7SDavid Howells int c = strcmp(tbl[i-1].name, tbl[i].name); 31731d921c7SDavid Howells 31831d921c7SDavid Howells if (c == 0) { 31931d921c7SDavid Howells pr_err("VALIDATE C-TBL[%zu]: Duplicate %s\n", 32031d921c7SDavid Howells i, tbl[i].name); 32131d921c7SDavid Howells good = false; 32231d921c7SDavid Howells } 32331d921c7SDavid Howells if (c > 0) { 32431d921c7SDavid Howells pr_err("VALIDATE C-TBL[%zu]: Missorted %s>=%s\n", 32531d921c7SDavid Howells i, tbl[i-1].name, tbl[i].name); 32631d921c7SDavid Howells good = false; 32731d921c7SDavid Howells } 32831d921c7SDavid Howells } 32931d921c7SDavid Howells 33031d921c7SDavid Howells if (tbl[i].value != special && 33131d921c7SDavid Howells (tbl[i].value < low || tbl[i].value > high)) { 33231d921c7SDavid Howells pr_err("VALIDATE C-TBL[%zu]: %s->%d const out of range (%d-%d)\n", 33331d921c7SDavid Howells i, tbl[i].name, tbl[i].value, low, high); 33431d921c7SDavid Howells good = false; 33531d921c7SDavid Howells } 33631d921c7SDavid Howells } 33731d921c7SDavid Howells 33831d921c7SDavid Howells return good; 33931d921c7SDavid Howells } 34031d921c7SDavid Howells 34131d921c7SDavid Howells /** 34231d921c7SDavid Howells * fs_validate_description - Validate a parameter description 34331d921c7SDavid Howells * @desc: The parameter description to validate. 34431d921c7SDavid Howells */ 34531d921c7SDavid Howells bool fs_validate_description(const struct fs_parameter_description *desc) 34631d921c7SDavid Howells { 34731d921c7SDavid Howells const struct fs_parameter_spec *param, *p2; 34831d921c7SDavid Howells const struct fs_parameter_enum *e; 34931d921c7SDavid Howells const char *name = desc->name; 35031d921c7SDavid Howells unsigned int nr_params = 0; 35131d921c7SDavid Howells bool good = true, enums = false; 35231d921c7SDavid Howells 35331d921c7SDavid Howells pr_notice("*** VALIDATE %s ***\n", name); 35431d921c7SDavid Howells 35531d921c7SDavid Howells if (!name[0]) { 35631d921c7SDavid Howells pr_err("VALIDATE Parser: No name\n"); 35731d921c7SDavid Howells name = "Unknown"; 35831d921c7SDavid Howells good = false; 35931d921c7SDavid Howells } 36031d921c7SDavid Howells 36131d921c7SDavid Howells if (desc->specs) { 36231d921c7SDavid Howells for (param = desc->specs; param->name; param++) { 36331d921c7SDavid Howells enum fs_parameter_type t = param->type; 36431d921c7SDavid Howells 36531d921c7SDavid Howells /* Check that the type is in range */ 36631d921c7SDavid Howells if (t == __fs_param_wasnt_defined || 36731d921c7SDavid Howells t >= nr__fs_parameter_type) { 36831d921c7SDavid Howells pr_err("VALIDATE %s: PARAM[%s] Bad type %u\n", 36931d921c7SDavid Howells name, param->name, t); 37031d921c7SDavid Howells good = false; 37131d921c7SDavid Howells } else if (t == fs_param_is_enum) { 37231d921c7SDavid Howells enums = true; 37331d921c7SDavid Howells } 37431d921c7SDavid Howells 37531d921c7SDavid Howells /* Check for duplicate parameter names */ 37631d921c7SDavid Howells for (p2 = desc->specs; p2 < param; p2++) { 37731d921c7SDavid Howells if (strcmp(param->name, p2->name) == 0) { 37831d921c7SDavid Howells pr_err("VALIDATE %s: PARAM[%s]: Duplicate\n", 37931d921c7SDavid Howells name, param->name); 38031d921c7SDavid Howells good = false; 38131d921c7SDavid Howells } 38231d921c7SDavid Howells } 38331d921c7SDavid Howells } 38431d921c7SDavid Howells 38531d921c7SDavid Howells nr_params = param - desc->specs; 38631d921c7SDavid Howells } 38731d921c7SDavid Howells 38831d921c7SDavid Howells if (desc->enums) { 38931d921c7SDavid Howells if (!nr_params) { 39031d921c7SDavid Howells pr_err("VALIDATE %s: Enum table but no parameters\n", 39131d921c7SDavid Howells name); 39231d921c7SDavid Howells good = false; 39331d921c7SDavid Howells goto no_enums; 39431d921c7SDavid Howells } 39531d921c7SDavid Howells if (!enums) { 39631d921c7SDavid Howells pr_err("VALIDATE %s: Enum table but no enum-type values\n", 39731d921c7SDavid Howells name); 39831d921c7SDavid Howells good = false; 39931d921c7SDavid Howells goto no_enums; 40031d921c7SDavid Howells } 40131d921c7SDavid Howells 40231d921c7SDavid Howells for (e = desc->enums; e->name[0]; e++) { 40331d921c7SDavid Howells /* Check that all entries in the enum table have at 40431d921c7SDavid Howells * least one parameter that uses them. 40531d921c7SDavid Howells */ 40631d921c7SDavid Howells for (param = desc->specs; param->name; param++) { 40731d921c7SDavid Howells if (param->opt == e->opt && 40831d921c7SDavid Howells param->type != fs_param_is_enum) { 40926203278SRandy Dunlap pr_err("VALIDATE %s: e[%tu] enum val for %s\n", 41031d921c7SDavid Howells name, e - desc->enums, param->name); 41131d921c7SDavid Howells good = false; 41231d921c7SDavid Howells } 41331d921c7SDavid Howells } 41431d921c7SDavid Howells } 41531d921c7SDavid Howells 41631d921c7SDavid Howells /* Check that all enum-type parameters have at least one enum 41731d921c7SDavid Howells * value in the enum table. 41831d921c7SDavid Howells */ 41931d921c7SDavid Howells for (param = desc->specs; param->name; param++) { 42031d921c7SDavid Howells if (param->type != fs_param_is_enum) 42131d921c7SDavid Howells continue; 42231d921c7SDavid Howells for (e = desc->enums; e->name[0]; e++) 42331d921c7SDavid Howells if (e->opt == param->opt) 42431d921c7SDavid Howells break; 42531d921c7SDavid Howells if (!e->name[0]) { 42631d921c7SDavid Howells pr_err("VALIDATE %s: PARAM[%s] enum with no values\n", 42731d921c7SDavid Howells name, param->name); 42831d921c7SDavid Howells good = false; 42931d921c7SDavid Howells } 43031d921c7SDavid Howells } 43131d921c7SDavid Howells } else { 43231d921c7SDavid Howells if (enums) { 43331d921c7SDavid Howells pr_err("VALIDATE %s: enum-type values, but no enum table\n", 43431d921c7SDavid Howells name); 43531d921c7SDavid Howells good = false; 43631d921c7SDavid Howells goto no_enums; 43731d921c7SDavid Howells } 43831d921c7SDavid Howells } 43931d921c7SDavid Howells 44031d921c7SDavid Howells no_enums: 44131d921c7SDavid Howells return good; 44231d921c7SDavid Howells } 44331d921c7SDavid Howells #endif /* CONFIG_VALIDATE_FS_PARSER */ 444