diff options
Diffstat (limited to 'src/eval.c')
-rw-r--r-- | src/eval.c | 62 |
1 files changed, 58 insertions, 4 deletions
@@ -7,6 +7,7 @@ #include "prelude.h" #include "eval.h" +#include "atomic.h" #include "bar.h" #include "bfstd.h" #include "bftw.h" @@ -22,6 +23,7 @@ #include "printf.h" #include "pwcache.h" #include "sanity.h" +#include "sighook.h" #include "stat.h" #include "trie.h" #include "xregex.h" @@ -997,6 +999,13 @@ bool eval_xtype(const struct bfs_expr *expr, struct bfs_eval *state) { const struct BFTW *ftwbuf = state->ftwbuf; enum bfs_stat_flags flags = ftwbuf->stat_flags ^ (BFS_STAT_NOFOLLOW | BFS_STAT_TRYFOLLOW); enum bfs_type type = bftw_type(ftwbuf, flags); + + // GNU find treats ELOOP as a broken symbolic link for -xtype l + // (but not -L -type l) + if ((flags & BFS_STAT_TRYFOLLOW) && type == BFS_ERROR && errno == ELOOP) { + type = BFS_LNK; + } + if (type == BFS_ERROR) { eval_report_error(state); return false; @@ -1284,7 +1293,7 @@ static void debug_stat(const struct bfs_ctx *ctx, const struct BFTW *ftwbuf, enu DEBUG_FLAG(flags, BFS_STAT_TRYFOLLOW); DEBUG_FLAG(flags, BFS_STAT_NOSYNC); - fprintf(stderr, ") == %d", err ? 0 : -1); + fprintf(stderr, ") == %d", err == 0 ? 0 : -1); if (err) { fprintf(stderr, " [%d]", err); @@ -1373,6 +1382,11 @@ struct callback_args { struct bfs_bar *bar; /** The time of the last status update. */ struct timespec last_status; + /** SIGINFO hook. */ + struct sighook *info_hook; + /** Flag set by SIGINFO hook. */ + atomic bool info_flag; + /** The number of files visited so far. */ size_t count; @@ -1399,15 +1413,38 @@ static enum bftw_action eval_callback(const struct BFTW *ftwbuf, void *ptr) { state.ret = &args->ret; state.quit = false; + // Check whether SIGINFO was delivered and show/hide the bar + if (exchange(&args->info_flag, false, relaxed)) { + if (args->bar) { + bfs_bar_hide(args->bar); + args->bar = NULL; + } else { + args->bar = bfs_bar_show(); + if (!args->bar) { + bfs_warning(ctx, "Couldn't show status bar: %s.\n", errstr()); + } + } + } + if (args->bar) { eval_status(&state, args->bar, &args->last_status, args->count); } if (ftwbuf->type == BFS_ERROR) { - if (!eval_should_ignore(&state, ftwbuf->error)) { - eval_error(&state, "%s.\n", xstrerror(ftwbuf->error)); - } state.action = BFTW_PRUNE; + + if (ftwbuf->error == ELOOP && ftwbuf->loopoff > 0) { + char *loop = strndup(ftwbuf->path, ftwbuf->loopoff); + if (loop) { + eval_error(&state, "Filesystem loop back to ${di}%pq${rs}\n", loop); + free(loop); + goto done; + } + } else if (eval_should_ignore(&state, ftwbuf->error)) { + goto done; + } + + eval_error(&state, "%s.\n", xstrerror(ftwbuf->error)); goto done; } @@ -1462,10 +1499,19 @@ done: return state.action; } +/** Show/hide the bar in response to SIGINFO. */ +static void eval_siginfo(int sig, siginfo_t *info, void *ptr) { + struct callback_args *args = ptr; + store(&args->info_flag, true, relaxed); +} + /** Raise RLIMIT_NOFILE if possible, and return the new limit. */ static int raise_fdlimit(struct bfs_ctx *ctx) { rlim_t cur = ctx->orig_nofile.rlim_cur; rlim_t max = ctx->orig_nofile.rlim_max; + if (!ctx->raise_nofile) { + max = cur; + } rlim_t target = 64 << 10; if (rlim_cmp(target, max) > 0) { @@ -1621,6 +1667,13 @@ int bfs_eval(struct bfs_ctx *ctx) { } } +#ifdef SIGINFO + int siginfo = SIGINFO; +#else + int siginfo = SIGUSR1; +#endif + args.info_hook = sighook(siginfo, eval_siginfo, &args, SH_CONTINUE); + struct trie seen; if (ctx->unique) { trie_init(&seen); @@ -1688,6 +1741,7 @@ int bfs_eval(struct bfs_ctx *ctx) { trie_destroy(&seen); } + sigunhook(args.info_hook); bfs_bar_hide(args.bar); return args.ret; |