summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/xspawn.c56
-rw-r--r--tests/gnu/execdir_self.out1
-rw-r--r--tests/gnu/execdir_self.sh9
3 files changed, 50 insertions, 16 deletions
diff --git a/src/xspawn.c b/src/xspawn.c
index 3fa4e60..7fa16b7 100644
--- a/src/xspawn.c
+++ b/src/xspawn.c
@@ -401,18 +401,40 @@ static bool bfs_resolve_relative(const struct bfs_resolver *res) {
return false;
}
+/** Check if the actions include fchdir(). */
+static bool bfs_spawn_will_chdir(const struct bfs_spawn *ctx) {
+ if (ctx) {
+ for_slist (const struct bfs_spawn_action, action, ctx) {
+ if (action->op == BFS_SPAWN_FCHDIR) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+/** Check if we can call xfaccessat() before file actions. */
+static bool bfs_can_access_early(const struct bfs_resolver *res, const struct bfs_spawn *ctx) {
+ if (res->exe[0] == '/') {
+ return true;
+ }
+
+ if (bfs_spawn_will_chdir(ctx)) {
+ return false;
+ }
+
+ return true;
+}
+
/** Check if we can resolve the executable before file actions. */
static bool bfs_can_resolve_early(const struct bfs_resolver *res, const struct bfs_spawn *ctx) {
if (!bfs_resolve_relative(res)) {
return true;
}
- if (ctx) {
- for_slist (const struct bfs_spawn_action, action, ctx) {
- if (action->op == BFS_SPAWN_FCHDIR) {
- return false;
- }
- }
+ if (bfs_spawn_will_chdir(ctx)) {
+ return false;
}
return true;
@@ -442,17 +464,19 @@ static int bfs_resolve_early(struct bfs_resolver *res, const char *exe, const st
};
if (bfs_can_skip_resolve(res, ctx)) {
- // Do this check eagerly, even though posix_spawn()/execv() also
- // would, because:
- //
- // - faccessat() is faster than fork()/clone() + execv()
- // - posix_spawn() is not guaranteed to report ENOENT
- if (xfaccessat(AT_FDCWD, exe, X_OK) == 0) {
- res->done = true;
- return 0;
- } else {
- return -1;
+ if (bfs_can_access_early(res, ctx)) {
+ // Do this check eagerly, even though posix_spawn()/execv() also
+ // would, because:
+ //
+ // - faccessat() is faster than fork()/clone() + execv()
+ // - posix_spawn() is not guaranteed to report ENOENT
+ if (xfaccessat(AT_FDCWD, exe, X_OK) != 0) {
+ return -1;
+ }
}
+
+ res->done = true;
+ return 0;
}
res->path = getenv("PATH");
diff --git a/tests/gnu/execdir_self.out b/tests/gnu/execdir_self.out
new file mode 100644
index 0000000..3ad0640
--- /dev/null
+++ b/tests/gnu/execdir_self.out
@@ -0,0 +1 @@
+./bar.sh
diff --git a/tests/gnu/execdir_self.sh b/tests/gnu/execdir_self.sh
new file mode 100644
index 0000000..1fc5d04
--- /dev/null
+++ b/tests/gnu/execdir_self.sh
@@ -0,0 +1,9 @@
+cd "$TEST"
+mkdir foo
+cat >foo/bar.sh <<EOF
+#!/bin/sh
+printf '%s\n' "\$@"
+EOF
+chmod +x foo/bar.sh
+
+bfs_diff . -name bar.sh -execdir {} {} \;