summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@tavianator.com>2019-07-04 17:07:50 -0400
committerTavian Barnes <tavianator@tavianator.com>2019-07-04 17:07:50 -0400
commitd3e64d6e1f905cd67264845c38b38fc6d1bdb088 (patch)
tree52a303272ec29b520b7d9d1f0237290b1e38ab3d
parent43039c98eb6bc2514434fe3b33faa3eb32e75ba3 (diff)
downloadbfs-d3e64d6e1f905cd67264845c38b38fc6d1bdb088.tar.xz
Make -mount and -xdev do different things
POSIX now says -mount should skip the whole mount point, while -xdev should only skip its descendents. C.f. http://austingroupbugs.net/view.php?id=1133 C.f. https://savannah.gnu.org/bugs/?42318 C.f. https://savannah.gnu.org/bugs/?54745
-rw-r--r--bfs.17
-rw-r--r--bftw.c39
-rw-r--r--bftw.h6
-rw-r--r--eval.c1
-rw-r--r--parse.c51
-rw-r--r--tests/test_mount.out1
6 files changed, 71 insertions, 34 deletions
diff --git a/bfs.1 b/bfs.1
index 3f6ad50..277aeb7 100644
--- a/bfs.1
+++ b/bfs.1
@@ -244,13 +244,12 @@ detects that the file tree is modified during the search (default:
Ignore files deeper/shallower than
.IR N .
.RE
-.PP
+.TP
.B \-mount
-.br
+Skip mount points entirely.
+.TP
.B \-xdev
-.RS
Don't descend into other mount points.
-.RE
.TP
.B \-noleaf
Ignored; for compatibility with GNU find.
diff --git a/bftw.c b/bftw.c
index 444310c..370ab12 100644
--- a/bftw.c
+++ b/bftw.c
@@ -901,7 +901,7 @@ static bool bftw_need_stat(const struct bftw_state *state) {
}
if (ftwbuf->typeflag == BFTW_DIR) {
- if (state->flags & (BFTW_DETECT_CYCLES | BFTW_XDEV)) {
+ if (state->flags & (BFTW_DETECT_CYCLES | BFTW_MOUNT | BFTW_XDEV)) {
return true;
}
#if __linux__
@@ -1041,6 +1041,23 @@ static void bftw_init_ftwbuf(struct bftw_state *state, enum bftw_visit visit) {
}
}
+/** Check if the current file is a mount point. */
+static bool bftw_is_mount(struct bftw_state *state, const char *name) {
+ const struct bftw_file *file = state->file;
+ if (!file) {
+ return false;
+ }
+
+ const struct bftw_file *parent = name ? file : file->parent;
+ if (!parent) {
+ return false;
+ }
+
+ const struct BFTW *ftwbuf = &state->ftwbuf;
+ const struct bfs_stat *statbuf = bftw_stat(ftwbuf, ftwbuf->stat_flags);
+ return statbuf && statbuf->dev != parent->dev;
+}
+
/** Fill file identity information from an ftwbuf. */
static void bftw_fill_id(struct bftw_file *file, const struct BFTW *ftwbuf) {
const struct bfs_stat *statbuf = ftwbuf->stat_cache.buf;
@@ -1071,6 +1088,10 @@ static enum bftw_action bftw_visit(struct bftw_state *state, const char *name, e
return BFTW_STOP;
}
+ if ((state->flags & BFTW_MOUNT) && bftw_is_mount(state, name)) {
+ return BFTW_PRUNE;
+ }
+
enum bftw_action ret = state->callback(ftwbuf, state->ptr);
switch (ret) {
case BFTW_CONTINUE:
@@ -1088,19 +1109,9 @@ static enum bftw_action bftw_visit(struct bftw_state *state, const char *name, e
goto done;
}
- if (state->flags & BFTW_XDEV) {
- const struct bftw_file *parent = state->file;
- if (parent && !name) {
- parent = parent->parent;
- }
-
- if (parent) {
- const struct bfs_stat *statbuf = bftw_stat(ftwbuf, ftwbuf->stat_flags);
- if (statbuf && statbuf->dev != parent->dev) {
- ret = BFTW_PRUNE;
- goto done;
- }
- }
+ if ((state->flags & BFTW_XDEV) && bftw_is_mount(state, name)) {
+ ret = BFTW_PRUNE;
+ goto done;
}
done:
diff --git a/bftw.h b/bftw.h
index 573c5a9..06fdedb 100644
--- a/bftw.h
+++ b/bftw.h
@@ -184,8 +184,10 @@ enum bftw_flags {
BFTW_LOGICAL = 1 << 4,
/** Detect directory cycles. */
BFTW_DETECT_CYCLES = 1 << 5,
- /** Stay on the same filesystem. */
- BFTW_XDEV = 1 << 6,
+ /** Skip mount points and their descendents. */
+ BFTW_MOUNT = 1 << 6,
+ /** Skip the descendents of mount points. */
+ BFTW_XDEV = 1 << 7,
};
/**
diff --git a/eval.c b/eval.c
index d89e62a..e2690c0 100644
--- a/eval.c
+++ b/eval.c
@@ -1300,6 +1300,7 @@ static void dump_bftw_flags(enum bftw_flags flags) {
DEBUG_FLAG(flags, BFTW_COMFOLLOW);
DEBUG_FLAG(flags, BFTW_LOGICAL);
DEBUG_FLAG(flags, BFTW_DETECT_CYCLES);
+ DEBUG_FLAG(flags, BFTW_MOUNT);
DEBUG_FLAG(flags, BFTW_XDEV);
assert(!flags);
diff --git a/parse.c b/parse.c
index fbc987c..70cf13d 100644
--- a/parse.c
+++ b/parse.c
@@ -346,6 +346,10 @@ struct parser_state {
const char *depth_arg;
/** A "-prune"-type argument if any. */
const char *prune_arg;
+ /** A "-mount"-type argument if any. */
+ const char *mount_arg;
+ /** An "-xdev"-type argument if any. */
+ const char *xdev_arg;
/** The current time. */
struct timespec now;
@@ -1546,10 +1550,11 @@ static struct expr *parse_ls(struct parser_state *state, int arg1, int arg2) {
}
/**
- * Parse -mount, -xdev.
+ * Parse -mount.
*/
static struct expr *parse_mount(struct parser_state *state, int arg1, int arg2) {
- state->cmdline->flags |= BFTW_XDEV;
+ state->cmdline->flags |= BFTW_MOUNT;
+ state->mount_arg = state->argv[0];
return parse_nullary_option(state);
}
@@ -2409,6 +2414,15 @@ static struct expr *parse_xattr(struct parser_state *state, int arg1, int arg2)
}
/**
+ * Parse -xdev.
+ */
+static struct expr *parse_xdev(struct parser_state *state, int arg1, int arg2) {
+ state->cmdline->flags |= BFTW_XDEV;
+ state->xdev_arg = state->argv[0];
+ return parse_nullary_option(state);
+}
+
+/**
* Launch a pager for the help output.
*/
static CFILE *launch_pager(pid_t *pid, CFILE *cout) {
@@ -2594,6 +2608,7 @@ static struct expr *parse_help(struct parser_state *state, int arg1, int arg2) {
cfprintf(cout, " ${blu}-mindepth${rs} ${bld}N${rs}\n");
cfprintf(cout, " Ignore files deeper/shallower than ${bld}N${rs}\n");
cfprintf(cout, " ${blu}-mount${rs}\n");
+ cfprintf(cout, " Skip mount points entirely\n");
cfprintf(cout, " ${blu}-xdev${rs}\n");
cfprintf(cout, " Don't descend into other mount points\n");
cfprintf(cout, " ${blu}-noleaf${rs}\n");
@@ -2888,9 +2903,9 @@ static const struct table_entry parse_table[] = {
{"-warn", parse_warn, true},
{"-wholename", parse_path, false},
{"-writable", parse_access, W_OK},
- {"-x", parse_mount},
+ {"-x", parse_xdev},
{"-xattr", parse_xattr},
- {"-xdev", parse_mount},
+ {"-xdev", parse_xdev},
{"-xtype", parse_type, true},
{0},
};
@@ -3183,17 +3198,23 @@ static struct expr *parse_whole_expr(struct parser_state *state) {
}
}
- if (state->warn && state->depth_arg && state->prune_arg) {
- parse_warning(state, "%s does not work in the presence of %s.\n", state->prune_arg, state->depth_arg);
+ if (state->warn) {
+ if (state->mount_arg && state->xdev_arg) {
+ parse_warning(state, "%s is redundant in the presence of %s.\n\n", state->xdev_arg, state->mount_arg);
+ }
+
+ if (state->depth_arg && state->prune_arg) {
+ parse_warning(state, "%s does not work in the presence of %s.\n", state->prune_arg, state->depth_arg);
- if (state->interactive) {
- fprintf(stderr, "Do you want to continue? ");
- if (ynprompt() == 0) {
- goto fail;
+ if (state->interactive) {
+ fprintf(stderr, "Do you want to continue? ");
+ if (ynprompt() == 0) {
+ goto fail;
+ }
}
- }
- fprintf(stderr, "\n");
+ fprintf(stderr, "\n");
+ }
}
return expr;
@@ -3275,8 +3296,10 @@ void dump_cmdline(const struct cmdline *cmdline, bool verbose) {
if (cmdline->ignore_races) {
cfprintf(cerr, "${blu}-ignore_readdir_race${rs} ");
}
- if (cmdline->flags & BFTW_XDEV) {
+ if (cmdline->flags & BFTW_MOUNT) {
cfprintf(cerr, "${blu}-mount${rs} ");
+ } else if (cmdline->flags & BFTW_XDEV) {
+ cfprintf(cerr, "${blu}-xdev{rs} ");
}
if (cmdline->mindepth != 0) {
cfprintf(cerr, "${blu}-mindepth${rs} ${bld}%d${rs} ", cmdline->mindepth);
@@ -3411,6 +3434,8 @@ struct cmdline *parse_cmdline(int argc, char *argv[]) {
.last_arg = NULL,
.depth_arg = NULL,
.prune_arg = NULL,
+ .mount_arg = NULL,
+ .xdev_arg = NULL,
};
if (strcmp(xbasename(state.command), "find") == 0) {
diff --git a/tests/test_mount.out b/tests/test_mount.out
index 005bdcf..2425675 100644
--- a/tests/test_mount.out
+++ b/tests/test_mount.out
@@ -1,4 +1,3 @@
scratch
scratch/foo
-scratch/mnt
scratch/foo/bar