diff options
-rw-r--r-- | Makefile | 1 | ||||
-rw-r--r-- | ctx.c | 217 | ||||
-rw-r--r-- | ctx.h (renamed from cmdline.h) | 135 | ||||
-rw-r--r-- | diag.c | 48 | ||||
-rw-r--r-- | diag.h | 20 | ||||
-rw-r--r-- | eval.c | 146 | ||||
-rw-r--r-- | eval.h | 12 | ||||
-rw-r--r-- | exec.c | 24 | ||||
-rw-r--r-- | exec.h | 17 | ||||
-rw-r--r-- | main.c | 24 | ||||
-rw-r--r-- | mtab.c | 8 | ||||
-rw-r--r-- | mtab.h | 6 | ||||
-rw-r--r-- | opt.c | 77 | ||||
-rw-r--r-- | opt.h | 37 | ||||
-rw-r--r-- | parse.c | 482 | ||||
-rw-r--r-- | parse.h | 38 | ||||
-rw-r--r-- | printf.c | 40 | ||||
-rw-r--r-- | printf.h | 16 |
18 files changed, 786 insertions, 562 deletions
@@ -94,6 +94,7 @@ all: bfs tests/mksock tests/trie tests/xtimegm bfs: \ bftw.o \ color.o \ + ctx.o \ darray.o \ diag.o \ dstring.o \ @@ -0,0 +1,217 @@ +/**************************************************************************** + * bfs * + * Copyright (C) 2015-2020 Tavian Barnes <tavianator@tavianator.com> * + * * + * Permission to use, copy, modify, and/or distribute this software for any * + * purpose with or without fee is hereby granted. * + * * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * + ****************************************************************************/ + +#include "ctx.h" +#include "darray.h" +#include "diag.h" +#include "expr.h" +#include "mtab.h" +#include "pwcache.h" +#include "trie.h" +#include <assert.h> +#include <errno.h> +#include <stdlib.h> + +struct bfs_ctx *bfs_ctx_new(void) { + struct bfs_ctx *ctx = malloc(sizeof(*ctx)); + if (!ctx) { + return NULL; + } + + ctx->argv = NULL; + ctx->paths = NULL; + ctx->expr = NULL; + ctx->exclude = NULL; + + ctx->mindepth = 0; + ctx->maxdepth = INT_MAX; + ctx->flags = BFTW_RECOVER; + ctx->strategy = BFTW_BFS; + ctx->optlevel = 3; + ctx->debug = 0; + ctx->ignore_races = false; + ctx->unique = false; + ctx->warn = false; + ctx->xargs_safe = false; + + ctx->colors = NULL; + ctx->cout = NULL; + ctx->cerr = NULL; + + ctx->users = NULL; + ctx->users_error = 0; + ctx->groups = NULL; + ctx->groups_error = 0; + + ctx->mtab = NULL; + ctx->mtab_error = 0; + + trie_init(&ctx->files); + ctx->nfiles = 0; + + return ctx; +} + +const struct bfs_users *bfs_ctx_users(const struct bfs_ctx *ctx) { + struct bfs_ctx *mut = (struct bfs_ctx *)ctx; + + if (mut->users_error) { + errno = mut->users_error; + } else if (!mut->users) { + mut->users = bfs_parse_users(); + if (!mut->users) { + mut->users_error = errno; + } + } + + return mut->users; +} + +const struct bfs_groups *bfs_ctx_groups(const struct bfs_ctx *ctx) { + struct bfs_ctx *mut = (struct bfs_ctx *)ctx; + + if (mut->groups_error) { + errno = mut->groups_error; + } else if (!mut->groups) { + mut->groups = bfs_parse_groups(); + if (!mut->groups) { + mut->groups_error = errno; + } + } + + return mut->groups; +} + +const struct bfs_mtab *bfs_ctx_mtab(const struct bfs_ctx *ctx) { + struct bfs_ctx *mut = (struct bfs_ctx *)ctx; + + if (mut->mtab_error) { + errno = mut->mtab_error; + } else if (!mut->mtab) { + mut->mtab = bfs_parse_mtab(); + if (!mut->mtab) { + mut->mtab_error = errno; + } + } + + return mut->mtab; +} + +/** + * An open file tracked by the bfs context. + */ +struct bfs_ctx_file { + /** The file itself. */ + CFILE *cfile; + /** The path to the file (for diagnostics). */ + const char *path; +}; + +CFILE *bfs_ctx_open(struct bfs_ctx *ctx, const char *path, bool use_color) { + CFILE *cfile = cfopen(path, use_color ? ctx->colors : NULL); + if (!cfile) { + goto out; + } + + struct bfs_stat sb; + if (bfs_stat(fileno(cfile->file), NULL, 0, &sb) != 0) { + goto out_close; + } + + bfs_file_id id; + bfs_stat_id(&sb, &id); + + struct trie_leaf *leaf = trie_insert_mem(&ctx->files, id, sizeof(id)); + if (!leaf) { + goto out_close; + } + + if (leaf->value) { + struct bfs_ctx_file *ctx_file = leaf->value; + cfclose(cfile); + cfile = ctx_file->cfile; + goto out; + } + + struct bfs_ctx_file *ctx_file = malloc(sizeof(*ctx_file)); + if (!ctx_file) { + trie_remove(&ctx->files, leaf); + goto out_close; + } + + ctx_file->cfile = cfile; + ctx_file->path = path; + leaf->value = ctx_file; + ++ctx->nfiles; + + goto out; + +out_close: + cfclose(cfile); + cfile = NULL; +out: + return cfile; +} + +int bfs_ctx_free(struct bfs_ctx *ctx) { + int ret = 0; + + if (ctx) { + CFILE *cout = ctx->cout; + CFILE *cerr = ctx->cerr; + + free_expr(ctx->expr); + free_expr(ctx->exclude); + + bfs_free_mtab(ctx->mtab); + + bfs_free_groups(ctx->groups); + bfs_free_users(ctx->users); + + struct trie_leaf *leaf; + while ((leaf = trie_first_leaf(&ctx->files))) { + struct bfs_ctx_file *ctx_file = leaf->value; + + if (cfclose(ctx_file->cfile) != 0) { + if (cerr) { + bfs_error(ctx, "'%s': %m.\n", ctx_file->path); + } + ret = -1; + } + + free(ctx_file); + trie_remove(&ctx->files, leaf); + } + trie_destroy(&ctx->files); + + if (cout && fflush(cout->file) != 0) { + if (cerr) { + bfs_error(ctx, "standard output: %m.\n"); + } + ret = -1; + } + + cfclose(cout); + cfclose(cerr); + + free_colors(ctx->colors); + darray_free(ctx->paths); + free(ctx->argv); + free(ctx); + } + + return ret; +} @@ -15,14 +15,14 @@ ****************************************************************************/ /** - * Representation of the parsed command line. + * bfs execution context. */ -#ifndef BFS_CMDLINE_H -#define BFS_CMDLINE_H +#ifndef BFS_CTX_H +#define BFS_CTX_H -#include "color.h" #include "trie.h" +#include "color.h" /** * Various debugging flags. @@ -47,35 +47,17 @@ enum debug_flags { }; /** - * The parsed command line. + * The execution context for bfs. */ -struct cmdline { +struct bfs_ctx { /** The unparsed command line arguments. */ char **argv; - /** The root paths. */ const char **paths; - - /** Color data. */ - struct colors *colors; - /** Colored stdout. */ - CFILE *cout; - /** Colored stderr. */ - CFILE *cerr; - - /** User table. */ - struct bfs_users *users; - /** The error that occurred parsing the user table, if any. */ - int users_error; - /** Group table. */ - struct bfs_groups *groups; - /** The error that occurred parsing the group table, if any. */ - int groups_error; - - /** Table of mounted file systems. */ - struct bfs_mtab *mtab; - /** The error that occurred parsing the mount table, if any. */ - int mtab_error; + /** The main command line expression. */ + struct expr *expr; + /** An expression for files to filter out. */ + struct expr *exclude; /** -mindepth option. */ int mindepth; @@ -100,44 +82,99 @@ struct cmdline { /** Whether to only handle paths with xargs-safe characters (-X). */ bool xargs_safe; - /** An expression for files to filter out. */ - struct expr *exclude; - /** The main command line expression. */ - struct expr *expr; + /** Color data. */ + struct colors *colors; + /** Colored stdout. */ + CFILE *cout; + /** Colored stderr. */ + CFILE *cerr; + + /** User table. */ + struct bfs_users *users; + /** The error that occurred parsing the user table, if any. */ + int users_error; + /** Group table. */ + struct bfs_groups *groups; + /** The error that occurred parsing the group table, if any. */ + int groups_error; + + /** Table of mounted file systems. */ + struct bfs_mtab *mtab; + /** The error that occurred parsing the mount table, if any. */ + int mtab_error; - /** All the open files owned by the command line. */ - struct trie open_files; - /** The number of open files owned by the command line. */ - int nopen_files; + /** All the files owned by the context. */ + struct trie files; + /** The number of files owned by the context. */ + int nfiles; }; /** - * Parse the command line. + * @return + * A new bfs context, or NULL on failure. */ -struct cmdline *parse_cmdline(int argc, char *argv[]); +struct bfs_ctx *bfs_ctx_new(void); /** - * Dump the parsed command line. + * Get the users table. + * + * @param ctx + * The bfs context. + * @return + * The cached users table, or NULL on failure. + */ +const struct bfs_users *bfs_ctx_users(const struct bfs_ctx *ctx); + +/** + * Get the groups table. + * + * @param ctx + * The bfs context. + * @return + * The cached groups table, or NULL on failure. + */ +const struct bfs_groups *bfs_ctx_groups(const struct bfs_ctx *ctx); + +/** + * Get the mount table. + * + * @param ctx + * The bfs context. + * @return + * The cached mount table, or NULL on failure. */ -void dump_cmdline(const struct cmdline *cmdline, enum debug_flags flag); +const struct bfs_mtab *bfs_ctx_mtab(const struct bfs_ctx *ctx); /** - * Optimize the parsed command line. + * Open a file for the bfs context. * - * @return 0 if successful, -1 on error. + * @param ctx + * The bfs context. + * @param use_color + * Whether to use colors if the file is a TTY. + * @return + * The opened file, or NULL on failure. */ -int optimize_cmdline(struct cmdline *cmdline); +CFILE *bfs_ctx_open(struct bfs_ctx *ctx, const char *path, bool use_color); /** - * Evaluate the command line. + * Dump the parsed command line. + * + * @param ctx + * The bfs context. + * @param flag + * The -D flag that triggered the dump. */ -int eval_cmdline(const struct cmdline *cmdline); +void bfs_ctx_dump(const struct bfs_ctx *ctx, enum debug_flags flag); /** - * Free the parsed command line. + * Free a bfs context. * - * @return 0 if successful, -1 on error. + * @param ctx + * The context to free. + * @return + * 0 on success, -1 if any errors occurred. */ -int free_cmdline(struct cmdline *cmdline); +int bfs_ctx_free(struct bfs_ctx *ctx); -#endif // BFS_CMDLINE_H +#endif // BFS_CTX_H @@ -15,7 +15,7 @@ ****************************************************************************/ #include "diag.h" -#include "cmdline.h" +#include "ctx.h" #include "color.h" #include "util.h" #include <assert.h> @@ -24,77 +24,77 @@ #include <stdlib.h> #include <string.h> -void bfs_error(const struct cmdline *cmdline, const char *format, ...) { +void bfs_error(const struct bfs_ctx *ctx, const char *format, ...) { va_list args; va_start(args, format); - bfs_verror(cmdline, format, args); + bfs_verror(ctx, format, args); va_end(args); } -bool bfs_warning(const struct cmdline *cmdline, const char *format, ...) { +bool bfs_warning(const struct bfs_ctx *ctx, const char *format, ...) { va_list args; va_start(args, format); - bool ret = bfs_vwarning(cmdline, format, args); + bool ret = bfs_vwarning(ctx, format, args); va_end(args); return ret; } -bool bfs_debug(const struct cmdline *cmdline, enum debug_flags flag, const char *format, ...) { +bool bfs_debug(const struct bfs_ctx *ctx, enum debug_flags flag, const char *format, ...) { va_list args; va_start(args, format); - bool ret = bfs_vdebug(cmdline, flag, format, args); + bool ret = bfs_vdebug(ctx, flag, format, args); va_end(args); return ret; } -void bfs_verror(const struct cmdline *cmdline, const char *format, va_list args) { +void bfs_verror(const struct bfs_ctx *ctx, const char *format, va_list args) { int error = errno; - bfs_error_prefix(cmdline); + bfs_error_prefix(ctx); errno = error; - cvfprintf(cmdline->cerr, format, args); + cvfprintf(ctx->cerr, format, args); } -bool bfs_vwarning(const struct cmdline *cmdline, const char *format, va_list args) { +bool bfs_vwarning(const struct bfs_ctx *ctx, const char *format, va_list args) { int error = errno; - if (bfs_warning_prefix(cmdline)) { + if (bfs_warning_prefix(ctx)) { errno = error; - cvfprintf(cmdline->cerr, format, args); + cvfprintf(ctx->cerr, format, args); return true; } else { return false; } } -bool bfs_vdebug(const struct cmdline *cmdline, enum debug_flags flag, const char *format, va_list args) { +bool bfs_vdebug(const struct bfs_ctx *ctx, enum debug_flags flag, const char *format, va_list args) { int error = errno; - if (bfs_debug_prefix(cmdline, flag)) { + if (bfs_debug_prefix(ctx, flag)) { errno = error; - cvfprintf(cmdline->cerr, format, args); + cvfprintf(ctx->cerr, format, args); return true; } else { return false; } } -void bfs_error_prefix(const struct cmdline *cmdline) { - cfprintf(cmdline->cerr, "${bld}%s:${rs} ${er}error:${rs} ", xbasename(cmdline->argv[0])); +void bfs_error_prefix(const struct bfs_ctx *ctx) { + cfprintf(ctx->cerr, "${bld}%s:${rs} ${er}error:${rs} ", xbasename(ctx->argv[0])); } -bool bfs_warning_prefix(const struct cmdline *cmdline) { - if (cmdline->warn) { - cfprintf(cmdline->cerr, "${bld}%s:${rs} ${wr}warning:${rs} ", xbasename(cmdline->argv[0])); +bool bfs_warning_prefix(const struct bfs_ctx *ctx) { + if (ctx->warn) { + cfprintf(ctx->cerr, "${bld}%s:${rs} ${wr}warning:${rs} ", xbasename(ctx->argv[0])); return true; } else { return false; } } -bool bfs_debug_prefix(const struct cmdline *cmdline, enum debug_flags flag) { - if (!(cmdline->debug & flag)) { +bool bfs_debug_prefix(const struct bfs_ctx *ctx, enum debug_flags flag) { + if (!(ctx->debug & flag)) { return false; } @@ -128,6 +128,6 @@ bool bfs_debug_prefix(const struct cmdline *cmdline, enum debug_flags flag) { break; } - cfprintf(cmdline->cerr, "${bld}%s:${rs} ${cyn}-D %s${rs}: ", xbasename(cmdline->argv[0]), str); + cfprintf(ctx->cerr, "${bld}%s:${rs} ${cyn}-D %s${rs}: ", xbasename(ctx->argv[0]), str); return true; } @@ -21,7 +21,7 @@ #ifndef BFS_DIAG_H #define BFS_DIAG_H -#include "cmdline.h" +#include "ctx.h" #include "util.h" #include <stdarg.h> #include <stdbool.h> @@ -30,7 +30,7 @@ * Shorthand for printing error messages. */ BFS_FORMATTER(2, 3) -void bfs_error(const struct cmdline *cmdline, const char *format, ...); +void bfs_error(const struct bfs_ctx *ctx, const char *format, ...); /** * Shorthand for printing warning messages. @@ -38,7 +38,7 @@ void bfs_error(const struct cmdline *cmdline, const char *format, ...); * @return Whether a warning was printed. */ BFS_FORMATTER(2, 3) -bool bfs_warning(const struct cmdline *cmdline, const char *format, ...); +bool bfs_warning(const struct bfs_ctx *ctx, const char *format, ...); /** * Shorthand for printing debug messages. @@ -46,36 +46,36 @@ bool bfs_warning(const struct cmdline *cmdline, const char *format, ...); * @return Whether a debug message was printed. */ BFS_FORMATTER(3, 4) -bool bfs_debug(const struct cmdline *cmdline, enum debug_flags flag, const char *format, ...); +bool bfs_debug(const struct bfs_ctx *ctx, enum debug_flags flag, const char *format, ...); /** * bfs_error() variant that takes a va_list. */ -void bfs_verror(const struct cmdline *cmdline, const char *format, va_list args); +void bfs_verror(const struct bfs_ctx *ctx, const char *format, va_list args); /** * bfs_warning() variant that takes a va_list. */ -bool bfs_vwarning(const struct cmdline *cmdline, const char *format, va_list args); +bool bfs_vwarning(const struct bfs_ctx *ctx, const char *format, va_list args); /** * bfs_debug() variant that takes a va_list. */ -bool bfs_vdebug(const struct cmdline *cmdline, enum debug_flags flag, const char *format, va_list args); +bool bfs_vdebug(const struct bfs_ctx *ctx, enum debug_flags flag, const char *format, va_list args); /** * Print the error message prefix. */ -void bfs_error_prefix(const struct cmdline *cmdline); +void bfs_error_prefix(const struct bfs_ctx *ctx); /** * Print the warning message prefix. */ -bool bfs_warning_prefix(const struct cmdline *cmdline); +bool bfs_warning_prefix(const struct bfs_ctx *ctx); /** * Print the debug message prefix. */ -bool bfs_debug_prefix(const struct cmdline *cmdline, enum debug_flags flag); +bool bfs_debug_prefix(const struct bfs_ctx *ctx, enum debug_flags flag); #endif // BFS_DIAG_H @@ -20,7 +20,6 @@ #include "eval.h" #include "bftw.h" -#include "cmdline.h" #include "color.h" #include "darray.h" #include "diag.h" @@ -54,11 +53,11 @@ struct eval_state { /** Data about the current file. */ const struct BFTW *ftwbuf; - /** The parsed command line. */ - const struct cmdline *cmdline; + /** The bfs context. */ + const struct bfs_ctx *ctx; /** The bftw() callback return value. */ enum bftw_action action; - /** The eval_cmdline() return value. */ + /** The bfs_eval() return value. */ int *ret; /** Whether to quit immediately. */ bool quit; @@ -70,10 +69,10 @@ struct eval_state { BFS_FORMATTER(2, 3) static void eval_error(struct eval_state *state, const char *format, ...) { int error = errno; - const struct cmdline *cmdline = state->cmdline; - CFILE *cerr = cmdline->cerr; + const struct bfs_ctx *ctx = state->ctx; + CFILE *cerr = ctx->cerr; - bfs_error(cmdline, "%pP: ", state->ftwbuf); + bfs_error(ctx, "%pP: ", state->ftwbuf); va_list args; va_start(args, format); @@ -86,7 +85,7 @@ static void eval_error(struct eval_state *state, const char *format, ...) { * Check if an error should be ignored. */ static bool eval_should_ignore(const struct eval_state *state, int error) { - return state->cmdline->ignore_races + return state->ctx->ignore_races && is_nonexistence_error(error) && state->ftwbuf->depth > 0; } @@ -295,7 +294,13 @@ bool eval_nogroup(const struct expr *expr, struct eval_state *state) { return false; } - return bfs_getgrgid(state->cmdline->groups, statbuf->gid) == NULL; + const struct bfs_groups *groups = bfs_ctx_groups(state->ctx); + if (!groups) { + eval_report_error(state); + return false; + } + + return bfs_getgrgid(groups, statbuf->gid) == NULL; } /** @@ -307,7 +312,13 @@ bool eval_nouser(const struct expr *expr, struct eval_state *state) { return false; } - return bfs_getpwuid(state->cmdline->users, statbuf->uid) == NULL; + const struct bfs_users *users = bfs_ctx_users(state->ctx); + if (!users) { + eval_report_error(state); + return false; + } + + return bfs_getpwuid(users, statbuf->uid) == NULL; } /** @@ -341,18 +352,18 @@ bool eval_delete(const struct expr *expr, struct eval_state *state) { } /** Finish any pending -exec ... + operations. */ -static int eval_exec_finish(const struct expr *expr, const struct cmdline *cmdline) { +static int eval_exec_finish(const struct expr *expr, const struct bfs_ctx *ctx) { int ret = 0; if (expr->execbuf && bfs_exec_finish(expr->execbuf) != 0) { if (errno != 0) { - bfs_error(cmdline, "%s %s: %m.\n", expr->argv[0], expr->argv[1]); + bfs_error(ctx, "%s %s: %m.\n", expr->argv[0], expr->argv[1]); } ret = -1; } - if (expr->lhs && eval_exec_finish(expr->lhs, cmdline) != 0) { + if (expr->lhs && eval_exec_finish(expr->lhs, ctx) != 0) { ret = -1; } - if (expr->rhs && eval_exec_finish(expr->rhs, cmdline) != 0) { + if (expr->rhs && eval_exec_finish(expr->rhs, ctx) != 0) { ret = -1; } return ret; @@ -436,7 +447,13 @@ bool eval_fstype(const struct expr *expr, struct eval_state *state) { return false; } - const char *type = bfs_fstype(state->cmdline->mtab, statbuf); + const struct bfs_mtab *mtab = bfs_ctx_mtab(state->ctx); + if (!mtab) { + eval_report_error(state); + return false; + } + + const char *type = bfs_fstype(mtab, statbuf); return strcmp(type, expr->sdata) == 0; } @@ -572,8 +589,8 @@ bool eval_perm(const struct expr *expr, struct eval_state *state) { bool eval_fls(const struct expr *expr, struct eval_state *state) { CFILE *cfile = expr->cfile; FILE *file = cfile->file; - const struct bfs_users *users = state->cmdline->users; - const struct bfs_groups *groups = state->cmdline->groups; + const struct bfs_users *users = bfs_ctx_users(state->ctx); + const struct bfs_groups *groups = bfs_ctx_groups(state->ctx); const struct BFTW *ftwbuf = state->ftwbuf; const struct bfs_stat *statbuf = eval_stat(state); if (!statbuf) { @@ -930,7 +947,7 @@ static void add_elapsed(struct expr *expr, const struct timespec *start, const s */ static bool eval_expr(struct expr *expr, struct eval_state *state) { struct timespec start, end; - bool time = state->cmdline->debug & DEBUG_RATES; + bool time = state->ctx->debug & DEBUG_RATES; if (time) { if (eval_gettime(&start) != 0) { time = false; @@ -1051,8 +1068,8 @@ static bool eval_file_unique(struct eval_state *state, struct trie *seen) { /** * Log a stat() call. */ -static void debug_stat(const struct cmdline *cmdline, const struct BFTW *ftwbuf, const struct bftw_stat *cache, enum bfs_stat_flags flags) { - bfs_debug_prefix(cmdline, DEBUG_STAT); +static void debug_stat(const struct bfs_ctx *ctx, const struct BFTW *ftwbuf, const struct bftw_stat *cache, enum bfs_stat_flags flags) { + bfs_debug_prefix(ctx, DEBUG_STAT); fprintf(stderr, "bfs_stat("); if (ftwbuf->at_fd == AT_FDCWD) { @@ -1082,19 +1099,19 @@ static void debug_stat(const struct cmdline *cmdline, const struct BFTW *ftwbuf, /** * Log any stat() calls that happened. */ -static void debug_stats(const struct cmdline *cmdline, const struct BFTW *ftwbuf) { - if (!(cmdline->debug & DEBUG_STAT)) { +static void debug_stats(const struct bfs_ctx *ctx, const struct BFTW *ftwbuf) { + if (!(ctx->debug & DEBUG_STAT)) { return; } const struct bfs_stat *statbuf = ftwbuf->stat_cache.buf; if (statbuf || ftwbuf->stat_cache.error) { - debug_stat(cmdline, ftwbuf, &ftwbuf->stat_cache, BFS_STAT_FOLLOW); + debug_stat(ctx, ftwbuf, &ftwbuf->stat_cache, BFS_STAT_FOLLOW); } const struct bfs_stat *lstatbuf = ftwbuf->lstat_cache.buf; if ((lstatbuf && lstatbuf != statbuf) || ftwbuf->lstat_cache.error) { - debug_stat(cmdline, ftwbuf, &ftwbuf->lstat_cache, BFS_STAT_NOFOLLOW); + debug_stat(ctx, ftwbuf, &ftwbuf->lstat_cache, BFS_STAT_NOFOLLOW); } } @@ -1152,25 +1169,25 @@ static const char *dump_bftw_action(enum bftw_action action) { * Type passed as the argument to the bftw() callback. */ struct callback_args { - /** The parsed command line. */ - const struct cmdline *cmdline; + /** The bfs context. */ + const struct bfs_ctx *ctx; /** The set of seen files. */ struct trie *seen; - /** Eventual return value from eval_cmdline(). */ + /** Eventual return value from bfs_eval(). */ int ret; }; /** * bftw() callback. */ -static enum bftw_action cmdline_callback(const struct BFTW *ftwbuf, void *ptr) { +static enum bftw_action eval_callback(const struct BFTW *ftwbuf, void *ptr) { struct callback_args *args = ptr; - const struct cmdline *cmdline = args->cmdline; + const struct bfs_ctx *ctx = args->ctx; struct eval_state state; state.ftwbuf = ftwbuf; - state.cmdline = cmdline; + state.ctx = ctx; state.action = BFTW_CONTINUE; state.ret = &args->ret; state.quit = false; @@ -1184,46 +1201,46 @@ static enum bftw_action cmdline_callback(const struct BFTW *ftwbuf, void *ptr) { goto done; } - if (cmdline->unique && ftwbuf->visit == BFTW_PRE) { + if (ctx->unique && ftwbuf->visit == BFTW_PRE) { if (!eval_file_unique(&state, args->seen)) { goto done; } } - if (eval_expr(cmdline->exclude, &state)) { + if (eval_expr(ctx->exclude, &state)) { state.action = BFTW_PRUNE; goto done; } - if (cmdline->xargs_safe && strpbrk(ftwbuf->path, " \t\n\'\"\\")) { + if (ctx->xargs_safe && strpbrk(ftwbuf->path, " \t\n\'\"\\")) { args->ret = EXIT_FAILURE; eval_error(&state, "Path is not safe for xargs.\n"); state.action = BFTW_PRUNE; goto done; } - if (cmdline->maxdepth < 0 || ftwbuf->depth >= cmdline->maxdepth) { + if (ctx->maxdepth < 0 || ftwbuf->depth >= ctx->maxdepth) { state.action = BFTW_PRUNE; } // In -depth mode, only handle directories on the BFTW_POST visit enum bftw_visit expected_visit = BFTW_PRE; - if ((cmdline->flags & BFTW_POST_ORDER) - && (cmdline->strategy == BFTW_IDS || ftwbuf->type == BFTW_DIR) - && ftwbuf->depth < cmdline->maxdepth) { + if ((ctx->flags & BFTW_POST_ORDER) + && (ctx->strategy == BFTW_IDS || ftwbuf->type == BFTW_DIR) + && ftwbuf->depth < ctx->maxdepth) { expected_visit = BFTW_POST; } if (ftwbuf->visit == expected_visit - && ftwbuf->depth >= cmdline->mindepth - && ftwbuf->depth <= cmdline->maxdepth) { - eval_expr(cmdline->expr, &state); + && ftwbuf->depth >= ctx->mindepth + && ftwbuf->depth <= ctx->maxdepth) { + eval_expr(ctx->expr, &state); } done: - debug_stats(cmdline, ftwbuf); + debug_stats(ctx, ftwbuf); - if (bfs_debug(cmdline, DEBUG_SEARCH, "cmdline_callback({\n")) { + if (bfs_debug(ctx, DEBUG_SEARCH, "eval_callback({\n")) { fprintf(stderr, "\t.path = \"%s\",\n", ftwbuf->path); fprintf(stderr, "\t.root = \"%s\",\n", ftwbuf->root); fprintf(stderr, "\t.depth = %zu,\n", ftwbuf->depth); @@ -1239,7 +1256,7 @@ done: /** * Infer the number of open file descriptors we're allowed to have. */ -static int infer_fdlimit(const struct cmdline *cmdline) { +static int infer_fdlimit(const struct bfs_ctx *ctx) { int ret = 4096; struct rlimit rl; @@ -1250,7 +1267,7 @@ static int infer_fdlimit(const struct cmdline *cmdline) { } // 3 for std{in,out,err} - int nopen = 3 + cmdline->nopen_files; + int nopen = 3 + ctx->nfiles; // Check /proc/self/fd for the current number of open fds, if possible // (we may have inherited more than just the standard ones) @@ -1271,8 +1288,8 @@ static int infer_fdlimit(const struct cmdline *cmdline) { } ret -= nopen; - ret -= cmdline->expr->persistent_fds; - ret -= cmdline->expr->ephemeral_fds; + ret -= ctx->expr->persistent_fds; + ret -= ctx->expr->ephemeral_fds; // bftw() needs at least 2 available fds if (ret < 2) { @@ -1313,44 +1330,41 @@ static const char *dump_bftw_strategy(enum bftw_strategy strategy) { return strategies[strategy]; } -/** - * Evaluate the command line. - */ -int eval_cmdline(const struct cmdline *cmdline) { - if (!cmdline->expr) { +int bfs_eval(const struct bfs_ctx *ctx) { + if (!ctx->expr) { return EXIT_SUCCESS; } struct callback_args args = { - .cmdline = cmdline, + .ctx = ctx, .ret = EXIT_SUCCESS, }; struct trie seen; - if (cmdline->unique) { + if (ctx->unique) { trie_init(&seen); args.seen = &seen; } struct bftw_args bftw_args = { - .paths = cmdline->paths, - .npaths = darray_length(cmdline->paths), - .callback = cmdline_callback, + .paths = ctx->paths, + .npaths = darray_length(ctx->paths), + .callback = eval_callback, .ptr = &args, - .nopenfd = infer_fdlimit(cmdline), - .flags = cmdline->flags, - .strategy = cmdline->strategy, - .mtab = cmdline->mtab, + .nopenfd = infer_fdlimit(ctx), + .flags = ctx->flags, + .strategy = ctx->strategy, + .mtab = bfs_ctx_mtab(ctx), }; - if (bfs_debug(cmdline, DEBUG_SEARCH, "bftw({\n")) { + if (bfs_debug(ctx, DEBUG_SEARCH, "bftw({\n")) { fprintf(stderr, "\t.paths = {\n"); for (size_t i = 0; i < bftw_args.npaths; ++i) { fprintf(stderr, "\t\t\"%s\",\n", bftw_args.paths[i]); } fprintf(stderr, "\t},\n"); fprintf(stderr, "\t.npaths = %zu,\n", bftw_args.npaths); - fprintf(stderr, "\t.callback = cmdline_callback,\n"); + fprintf(stderr, "\t.callback = eval_callback,\n"); fprintf(stderr, "\t.ptr = &args,\n"); fprintf(stderr, "\t.nopenfd = %d,\n", bftw_args.nopenfd); fprintf(stderr, "\t.flags = "); @@ -1358,7 +1372,7 @@ int eval_cmdline(const struct cmdline *cmdline) { fprintf(stderr, ",\n\t.strategy = %s,\n", dump_bftw_strategy(bftw_args.strategy)); fprintf(stderr, "\t.mtab = "); if (bftw_args.mtab) { - fprintf(stderr, "cmdline->mtab"); + fprintf(stderr, "ctx->mtab"); } else { fprintf(stderr, "NULL"); } @@ -1370,13 +1384,13 @@ int eval_cmdline(const struct cmdline *cmdline) { perror("bftw()"); } - if (eval_exec_finish(cmdline->expr, cmdline) != 0) { + if (eval_exec_finish(ctx->expr, ctx) != 0) { args.ret = EXIT_FAILURE; } - dump_cmdline(cmdline, DEBUG_RATES); + bfs_ctx_dump(ctx, DEBUG_RATES); - if (cmdline->unique) { + if (ctx->unique) { trie_destroy(&seen); } @@ -22,9 +22,21 @@ #ifndef BFS_EVAL_H #define BFS_EVAL_H +#include "ctx.h" #include "expr.h" +/** + * Evaluate the command line. + * + * @param ctx + * The bfs context to evaluate. + * @return + * EXIT_SUCCESS on success, otherwise on failure. + */ +int bfs_eval(const struct bfs_ctx *ctx); + // Predicate evaluation functions + bool eval_true(const struct expr *expr, struct eval_state *state); bool eval_false(const struct expr *expr, struct eval_state *state); @@ -16,7 +16,7 @@ #include "exec.h" #include "bftw.h" -#include "cmdline.h" +#include "ctx.h" #include "color.h" #include "diag.h" #include "dstring.h" @ |