summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@tavianator.com>2020-09-27 12:55:55 -0400
committerTavian Barnes <tavianator@tavianator.com>2020-09-27 13:23:49 -0400
commit62bbbe1a4165f63b31c68b1595ecb0e67d7af3dc (patch)
treec770ff13f37023cae132108b29077a904e6d4dfb
parent3c83bf4e1920be909f65945e56dc8b779c472a59 (diff)
Rename struct cmdline to bfs_ctx
The API remains similar, with some added accessor functions for lazy initialization of the pwcache and mtab.
-rw-r--r--Makefile1
-rw-r--r--ctx.c217
-rw-r--r--ctx.h (renamed from cmdline.h)135
-rw-r--r--diag.c48
-rw-r--r--diag.h20
-rw-r--r--eval.c146
-rw-r--r--eval.h12
-rw-r--r--exec.c24
-rw-r--r--exec.h17
-rw-r--r--main.c24
-rw-r--r--mtab.c8
-rw-r--r--mtab.h6
-rw-r--r--opt.c77
-rw-r--r--opt.h37
-rw-r--r--parse.c482
-rw-r--r--parse.h38
-rw-r--r--printf.c40
-rw-r--r--printf.h16
18 files changed, 786 insertions, 562 deletions
diff --git a/Makefile b/Makefile
index 72abf89..ec5e6d0 100644
--- a/Makefile
+++ b/Makefile
@@ -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 \
diff --git a/ctx.c b/ctx.c
new file mode 100644
index 0000000..95e668c
--- /dev/null
+++ b/ctx.c
@@ -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;
+}
diff --git a/cmdline.h b/ctx.h
index 309dfa3..b638e74 100644
--- a/cmdline.h
+++ b/ctx.h
@@ -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
diff --git a/diag.c b/diag.c
index fb1a295..7ed132e 100644
--- a/diag.c
+++ b/diag.c
@@ -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;
}
diff --git a/diag.h b/diag.h
index 2e5513e..8faef07 100644
--- a/diag.h
+++ b/diag.h
@@ -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
diff --git a/eval.c b/eval.c
index 1498282..ca8c78f 100644
--- a/eval.c
+++ b/eval.c
@@ -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);
}
diff --git a/eval.h b/eval.h
index a95c3ac..9a1885b 100644
--- a/eval.h
+++ b/eval.h
@@ -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.
+ */