# nft list chain x y Error: No such file or directory; did you mean chain ‘y’ in family ‘inet’? list chain x y ^ Signed-off-by: Pablo Neira Ayuso <pablo@xxxxxxxxxxxxx> --- include/rule.h | 3 +++ src/evaluate.c | 31 ++++++++++++++++++++++--------- src/rule.c | 18 ++++++++++++++++++ 3 files changed, 43 insertions(+), 9 deletions(-) diff --git a/include/rule.h b/include/rule.h index a3e0bf117d68..66786bdb2140 100644 --- a/include/rule.h +++ b/include/rule.h @@ -221,6 +221,9 @@ extern void chain_free(struct chain *chain); extern void chain_add_hash(struct chain *chain, struct table *table); extern struct chain *chain_lookup(const struct table *table, const struct handle *h); +extern struct chain *chain_lookup_fuzzy(const struct handle *h, + const struct nft_cache *cache, + const struct table **table); extern const char *family2str(unsigned int family); extern const char *hooknum2str(unsigned int family, unsigned int hooknum); diff --git a/src/evaluate.c b/src/evaluate.c index 12b6a4cac727..f6c090be57ac 100644 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -181,6 +181,23 @@ static int table_not_found(struct eval_ctx *ctx) table->handle.table.name); } +static int chain_not_found(struct eval_ctx *ctx) +{ + const struct table *table; + struct chain *chain; + + chain = chain_lookup_fuzzy(&ctx->cmd->handle, &ctx->nft->cache, &table); + if (chain == NULL) + return cmd_error(ctx, &ctx->cmd->handle.chain.location, + "%s", strerror(ENOENT)); + + return cmd_error(ctx, &ctx->cmd->handle.chain.location, + "%s; did you mean chain ‘%s’ in table %s ‘%s’?", + strerror(ENOENT), chain->handle.chain.name, + family2str(chain->handle.family), + table->handle.table.name); +} + /* * Symbol expression: parse symbol and evaluate resulting expression. */ @@ -3109,9 +3126,7 @@ static int rule_translate_index(struct eval_ctx *ctx, struct rule *rule) chain = chain_lookup(table, &rule->handle); if (!chain) - return cmd_error(ctx, &rule->handle.chain.location, - "Could not process rule: %s", - strerror(ENOENT)); + return chain_not_found(ctx); list_for_each_entry(r, &chain->rules, list) { if (++index < rule->handle.index.id) @@ -3499,9 +3514,8 @@ static int cmd_evaluate_list(struct eval_ctx *ctx, struct cmd *cmd) return table_not_found(ctx); if (chain_lookup(table, &cmd->handle) == NULL) - return cmd_error(ctx, &cmd->handle.chain.location, - "Could not process rule: %s", - strerror(ENOENT)); + return chain_not_found(ctx); + return 0; case CMD_OBJ_QUOTA: return cmd_evaluate_list_obj(ctx, cmd, NFT_OBJECT_QUOTA); @@ -3646,9 +3660,8 @@ static int cmd_evaluate_rename(struct eval_ctx *ctx, struct cmd *cmd) return table_not_found(ctx); if (chain_lookup(table, &ctx->cmd->handle) == NULL) - return cmd_error(ctx, &ctx->cmd->handle.chain.location, - "Could not process rule: %s", - strerror(ENOENT)); + return chain_not_found(ctx); + break; default: BUG("invalid command object type %u\n", cmd->obj); diff --git a/src/rule.c b/src/rule.c index 3553b43def06..39f717cabeac 100644 --- a/src/rule.c +++ b/src/rule.c @@ -762,6 +762,24 @@ struct chain *chain_lookup(const struct table *table, const struct handle *h) return NULL; } +struct chain *chain_lookup_fuzzy(const struct handle *h, + const struct nft_cache *cache, + const struct table **t) +{ + struct table *table; + struct chain *chain; + + list_for_each_entry(table, &cache->list, list) { + list_for_each_entry(chain, &table->chains, list) { + if (!strcmp(chain->handle.chain.name, h->chain.name)) { + *t = table; + return chain; + } + } + } + return NULL; +} + const char *family2str(unsigned int family) { switch (family) { -- 2.11.0