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