Skip to content

Fix #219 #229

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jan 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions cbits/posix/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ struct std_handle {
int get_max_fd(void);

// defined in find_executable.c
#if !defined(HAVE_execvpe)
char *find_executable(char *filename);
#if !defined(HAVE_EXECVPE)
char *find_executable(char *workingDirectory, char *filename);
#endif

// defined in fork_exec.c
Expand All @@ -49,4 +49,4 @@ do_spawn_posix (char *const args[],
struct std_handle *stdErrHdl,
gid_t *childGroup, uid_t *childUser,
int flags,
char **failed_doing);
char **failed_doing);
89 changes: 74 additions & 15 deletions cbits/posix/find_executable.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,48 @@
#include "common.h"

// the below is only necessary when we need to emulate execvpe.
#if !defined(HAVE_execvpe)
#if !defined(HAVE_EXECVPE)

/* Return true if the given file exists and is an executable. */
static bool is_executable(const char *path) {
return access(path, X_OK) == 0;
/* A quick check for whether the given path is absolute. */
static bool is_absolute(const char *path) {
return path[0] == '/';
}

static char *concat_paths(const char *path1, const char *path2) {
if (is_absolute(path2)) {
return strdup(path2);
} else {
int len = strlen(path1) + 1 + strlen(path2) + 1;
char *tmp = malloc(len);
int ret = snprintf(tmp, len, "%s/%s", path1, path2);
if (ret < 0) {
free(tmp);
return NULL;
}
return tmp;
}
}

/* Return true if the given file exists and is an executable, optionally
* relative to the given working directory.
*/
static bool is_executable(char *working_dir, const char *path) {
if (working_dir && !is_absolute(path)) {
char *tmp = concat_paths(working_dir, path);
bool ret = access(tmp, X_OK) == 0;
free(tmp);
return ret;
} else {
return access(path, X_OK) == 0;
}
}

/* Find an executable with the given filename in the given search path. The
* result must be freed by the caller. Returns NULL if a matching file is not
* found.
*/
static char *find_in_search_path(char *search_path, const char *filename) {
static char *find_in_search_path(char *working_dir, char *search_path, const char *filename) {
int workdir_len = strlen(working_dir);
const int filename_len = strlen(filename);
char *tokbuf;
char *path = strtok_r(search_path, ":", &tokbuf);
Expand All @@ -34,13 +64,21 @@ static char *find_in_search_path(char *search_path, const char *filename) {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#endif
const int tmp_len = filename_len + 1 + strlen(path) + 1;
char *tmp;
if (is_absolute(path)) {
const int tmp_len = strlen(path) + 1 + filename_len + 1;
tmp = malloc(tmp_len);
snprintf(tmp, tmp_len, "%s/%s", path, filename);
} else {
const int tmp_len = workdir_len + 1 + strlen(path) + 1 + filename_len + 1;
tmp = malloc(tmp_len);
snprintf(tmp, tmp_len, "%s/%s/%s", working_dir, path, filename);
}
#if defined(__GNUC__) && __GNUC__ == 6 && __GNUC_MINOR__ == 3
#pragma GCC diagnostic pop
#endif
char *tmp = malloc(tmp_len);
snprintf(tmp, tmp_len, "%s/%s", path, filename);
if (is_executable(tmp)) {

if (is_executable(working_dir, tmp)) {
return tmp;
} else {
free(tmp);
Expand Down Expand Up @@ -74,15 +112,36 @@ static char *get_executable_search_path(void) {
return strdup(":");
}

/* Find the given executable in the executable search path. */
char *find_executable(char *filename) {
/* If it's an absolute or relative path name, it's easy. */
if (strchr(filename, '/') && is_executable(filename)) {
/* Find the given executable in the executable search path relative to
* workingDirectory (or the current directory, if NULL).
* N.B. the caller is responsible for free()ing the result.
*/
char *find_executable(char *working_dir, char *filename) {
/* Drop trailing slash from working directory if necessary */
if (working_dir) {
int workdir_len = strlen(working_dir);
if (working_dir[workdir_len-1] == '/') {
working_dir[workdir_len-1] = '\0';
}
}

if (is_absolute(filename)) {
/* If it's an absolute path name, it's easy. */
return filename;

} else if (strchr(filename, '/')) {
/* If it's a relative path name, we must look for executables relative
* to the working directory. */
if (is_executable(working_dir, filename)) {
return filename;
}
}

/* Otherwise look through the search path... */
char *search_path = get_executable_search_path();
return find_in_search_path(search_path, filename);
char *result = find_in_search_path(working_dir, search_path, filename);
free(search_path);
return result;
}

#endif
#endif
14 changes: 11 additions & 3 deletions cbits/posix/fork_exec.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
/* ensure that execvpe is provided if possible */
#define _GNU_SOURCE 1

#include "common.h"

#include <sys/types.h>
Expand Down Expand Up @@ -125,10 +128,15 @@ do_spawn_fork (char *const args[],
// we emulate this using fork and exec. However, to safely do so
// we need to perform all allocations *prior* to forking. Consequently, we
// need to find_executable before forking.
#if !defined(HAVE_execvpe)
#if !defined(HAVE_EXECVPE)
char *exec_path;
if (environment) {
exec_path = find_executable(args[0]);
exec_path = find_executable(workingDirectory, args[0]);
if (exec_path == NULL) {
errno = -ENOENT;
*failed_doing = "find_executable";
return -1;
}
}
#endif

Expand Down Expand Up @@ -234,7 +242,7 @@ do_spawn_fork (char *const args[],

/* the child */
if (environment) {
#if defined(HAVE_execvpe)
#if defined(HAVE_EXECVPE)
// XXX Check result
execvpe(args[0], args, environment);
#else
Expand Down
2 changes: 1 addition & 1 deletion cbits/posix/posix_spawn.c
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ do_spawn_posix (char *const args[],
#if defined(HAVE_POSIX_SPAWN_SETPGROUP)
spawn_flags |= POSIX_SPAWN_SETPGROUP;
#else
goto not_supported;
goto not_supported;
#endif
}

Expand Down