summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@tavianator.com>2017-07-20 23:33:43 -0400
committerTavian Barnes <tavianator@tavianator.com>2017-07-20 23:33:43 -0400
commit4242283189a94a79dda78540efe78b2666a944cc (patch)
tree831d2e27413db667239c8f60fad64d447026dd44
parent03adbcf0aa8914fd5556b7913901c98a6940fae4 (diff)
downloadbfs-4242283189a94a79dda78540efe78b2666a944cc.tar.xz
Implement -exit [STATUS]
From NetBSD again.
-rw-r--r--bfs.h1
-rw-r--r--eval.c28
-rw-r--r--main.c4
-rw-r--r--parse.c23
-rwxr-xr-xtests.sh15
-rw-r--r--tests/test_exit.out16
6 files changed, 75 insertions, 12 deletions
diff --git a/bfs.h b/bfs.h
index f63bda7..cc00f6b 100644
--- a/bfs.h
+++ b/bfs.h
@@ -320,6 +320,7 @@ bool eval_regex(const struct expr *expr, struct eval_state *state);
bool eval_delete(const struct expr *expr, struct eval_state *state);
bool eval_exec(const struct expr *expr, struct eval_state *state);
+bool eval_exit(const struct expr *expr, struct eval_state *state);
bool eval_nohidden(const struct expr *expr, struct eval_state *state);
bool eval_fls(const struct expr *expr, struct eval_state *state);
bool eval_fprint(const struct expr *expr, struct eval_state *state);
diff --git a/eval.c b/eval.c
index daee9d6..b095279 100644
--- a/eval.c
+++ b/eval.c
@@ -61,7 +61,7 @@ static bool eval_should_ignore(const struct eval_state *state, int error) {
static void eval_error(struct eval_state *state) {
if (!eval_should_ignore(state, errno)) {
cfprintf(state->cmdline->cerr, "%{er}'%s': %s%{rs}\n", state->ftwbuf->path, strerror(errno));
- *state->ret = -1;
+ *state->ret = EXIT_FAILURE;
}
}
@@ -305,6 +305,16 @@ bool eval_exec(const struct expr *expr, struct eval_state *state) {
}
/**
+ * -exit action.
+ */
+bool eval_exit(const struct expr *expr, struct eval_state *state) {
+ state->action = BFTW_STOP;
+ *state->ret = expr->idata;
+ *state->quit = true;
+ return true;
+}
+
+/**
* -depth N test.
*/
bool eval_depth(const struct expr *expr, struct eval_state *state) {
@@ -703,7 +713,7 @@ bool eval_regex(const struct expr *expr, struct eval_state *state) {
perror("xregerror()");
}
- *state->ret = -1;
+ *state->ret = EXIT_FAILURE;
}
return false;
@@ -971,7 +981,7 @@ static enum bftw_action cmdline_callback(struct BFTW *ftwbuf, void *ptr) {
if (ftwbuf->typeflag == BFTW_ERROR) {
if (!eval_should_ignore(&state, ftwbuf->error)) {
- args->ret = -1;
+ args->ret = EXIT_FAILURE;
cfprintf(cmdline->cerr, "%{er}'%s': %s%{rs}\n", ftwbuf->path, strerror(ftwbuf->error));
}
state.action = BFTW_SKIP_SUBTREE;
@@ -979,7 +989,7 @@ static enum bftw_action cmdline_callback(struct BFTW *ftwbuf, void *ptr) {
}
if (cmdline->xargs_safe && strpbrk(ftwbuf->path, " \t\n\'\"\\")) {
- args->ret = -1;
+ args->ret = EXIT_FAILURE;
cfprintf(cmdline->cerr, "%{er}'%s': Path is not safe for xargs.%{rs}\n", ftwbuf->path);
state.action = BFTW_SKIP_SUBTREE;
goto done;
@@ -1064,33 +1074,33 @@ static int infer_fdlimit(const struct cmdline *cmdline) {
*/
int eval_cmdline(const struct cmdline *cmdline) {
if (!cmdline->expr) {
- return 0;
+ return EXIT_SUCCESS;
}
if (cmdline->optlevel >= 4 && cmdline->expr->eval == eval_false) {
if (cmdline->debug & DEBUG_OPT) {
fputs("-O4: skipping evaluation of top-level -false\n", stderr);
}
- return 0;
+ return EXIT_SUCCESS;
}
int nopenfd = infer_fdlimit(cmdline);
struct callback_args args = {
.cmdline = cmdline,
- .ret = 0,
+ .ret = EXIT_SUCCESS,
.quit = false,
};
for (struct root *root = cmdline->roots; root && !args.quit; root = root->next) {
if (bftw(root->path, cmdline_callback, nopenfd, cmdline->flags, &args) != 0) {
- args.ret = -1;
+ args.ret = EXIT_FAILURE;
perror("bftw()");
}
}
if (eval_exec_finish(cmdline->expr) != 0) {
- args.ret = -1;
+ args.ret = EXIT_FAILURE;
}
if (cmdline->debug & DEBUG_RATES) {
diff --git a/main.c b/main.c
index 0b957d3..f925915 100644
--- a/main.c
+++ b/main.c
@@ -48,9 +48,7 @@ int main(int argc, char *argv[]) {
struct cmdline *cmdline = parse_cmdline(argc, argv);
if (cmdline) {
- if (eval_cmdline(cmdline) == 0) {
- ret = EXIT_SUCCESS;
- }
+ ret = eval_cmdline(cmdline);
}
free_cmdline(cmdline);
diff --git a/parse.c b/parse.c
index 98f603d..f5bb5e1 100644
--- a/parse.c
+++ b/parse.c
@@ -960,6 +960,26 @@ static struct expr *parse_exec(struct parser_state *state, int flags, int arg2)
}
/**
+ * Parse -exit [STATUS].
+ */
+static struct expr *parse_exit(struct parser_state *state, int arg1, int arg2) {
+ size_t argc = 1;
+ const char *value = state->argv[1];
+
+ int status = EXIT_SUCCESS;
+ if (value && parse_int(state, value, &status, IF_INT | IF_UNSIGNED | IF_QUIET)) {
+ argc = 2;
+ }
+
+ struct expr *expr = parse_action(state, eval_exit, argc);
+ if (expr) {
+ expr->never_returns = true;
+ expr->idata = status;
+ }
+ return expr;
+}
+
+/**
* Parse -f PATH.
*/
static struct expr *parse_f(struct parser_state *state, int arg1, int arg2) {
@@ -2156,6 +2176,8 @@ static struct expr *parse_help(struct parser_state *state, int arg1, int arg2) {
cfprintf(cout, " %{blu}-sparse%{rs}\n");
cfprintf(cout, " Find files that occupy fewer disk blocks than expected\n\n");
+ cfprintf(cout, " %{blu}-exit%{rs} %{bld}[STATUS]%{rs}\n");
+ cfprintf(cout, " Exit immediately with the given status (%d if unspecified)\n", EXIT_SUCCESS);
cfprintf(cout, " %{blu}-rm%{rs}\n");
cfprintf(cout, " Delete any found files (same as %{blu}-delete%{rs}; implies %{blu}-depth%{rs})\n\n");
@@ -2228,6 +2250,7 @@ static const struct table_entry parse_table[] = {
{"-exec", false, parse_exec, 0},
{"-execdir", false, parse_exec, BFS_EXEC_CHDIR},
{"-executable", false, parse_access, X_OK},
+ {"-exit", false, parse_exit},
{"-f", false, parse_f},
{"-false", false, parse_const, false},
{"-fls", false, parse_fls},
diff --git a/tests.sh b/tests.sh
index a701e3d..0e337bd 100755
--- a/tests.sh
+++ b/tests.sh
@@ -255,6 +255,7 @@ bsd_tests=(
test_inum
test_nogroup
test_nouser
+ test_exit
)
gnu_tests=(
@@ -1202,6 +1203,20 @@ function test_deep_strict() {
bfs_diff deep -mindepth 18
}
+function test_exit() {
+ $BFS basic -name foo -exit 42
+ if [ $? -ne 42 ]; then
+ return 1
+ fi
+
+ $BFS basic -name qux -exit 42
+ if [ $? -ne 0 ]; then
+ return 1
+ fi
+
+ bfs_diff basic -name bar -exit -o -print
+}
+
passed=0
failed=0
diff --git a/tests/test_exit.out b/tests/test_exit.out
new file mode 100644
index 0000000..b79fef1
--- /dev/null
+++ b/tests/test_exit.out
@@ -0,0 +1,16 @@
+basic
+basic/a
+basic/b
+basic/c
+basic/e
+basic/g
+basic/i
+basic/j
+basic/k
+basic/l
+basic/c/d
+basic/e/f
+basic/g/h
+basic/j/foo
+basic/k/foo
+basic/l/foo