diff options
author | Tavian Barnes <tavianator@tavianator.com> | 2024-05-07 15:42:46 -0400 |
---|---|---|
committer | Tavian Barnes <tavianator@tavianator.com> | 2024-05-07 15:42:46 -0400 |
commit | 452d6697e0f92326ab139eed4eadd9c2fd8b55ca (patch) | |
tree | 0feeb3722dcf6debb6c33c5175342bf1d70a1dba /tests/xspawn.c | |
parent | a4299f9bc1d3e60a7e628561e8d650c2a241e1c2 (diff) | |
parent | c5cf2cf90834f2f56b2940d2a499a1a614ebfd21 (diff) | |
download | bfs-452d6697e0f92326ab139eed4eadd9c2fd8b55ca.tar.xz |
Merge branch 'main' into find2fdfind2fd
Diffstat (limited to 'tests/xspawn.c')
-rw-r--r-- | tests/xspawn.c | 197 |
1 files changed, 197 insertions, 0 deletions
diff --git a/tests/xspawn.c b/tests/xspawn.c new file mode 100644 index 0000000..785ea48 --- /dev/null +++ b/tests/xspawn.c @@ -0,0 +1,197 @@ +// Copyright © Tavian Barnes <tavianator@tavianator.com> +// SPDX-License-Identifier: 0BSD + +#include "prelude.h" +#include "tests.h" +#include "alloc.h" +#include "bfstd.h" +#include "dstring.h" +#include "xspawn.h" +#include <stdlib.h> +#include <string.h> +#include <sys/wait.h> + +/** Duplicate the current environment. */ +static char **envdup(void) { + extern char **environ; + + char **envp = NULL; + size_t envc = 0; + + for (char **var = environ; ; ++var) { + char *copy = NULL; + if (*var) { + copy = strdup(*var); + if (!copy) { + goto fail; + } + } + + char **dest = RESERVE(char *, &envp, &envc); + if (!dest) { + free(copy); + goto fail; + } + *dest = copy; + + if (!*var) { + break; + } + } + + return envp; + +fail: + for (size_t i = 0; i < envc; ++i) { + free(envp[i]); + } + free(envp); + return NULL; +} + +/** Check that we resolve executables in $PATH correctly. */ +static bool check_use_path(bool use_posix) { + bool ret = true; + + struct bfs_spawn spawn; + ret &= bfs_pcheck(bfs_spawn_init(&spawn) == 0); + if (!ret) { + goto out; + } + + spawn.flags |= BFS_SPAWN_USE_PATH; + if (!use_posix) { + spawn.flags &= ~BFS_SPAWN_USE_POSIX; + } + + ret &= bfs_pcheck(bfs_spawn_addopen(&spawn, 10, "bin", O_RDONLY | O_DIRECTORY, 0) == 0); + ret &= bfs_pcheck(bfs_spawn_adddup2(&spawn, 10, 11) == 0); + ret &= bfs_pcheck(bfs_spawn_addclose(&spawn, 10) == 0); + ret &= bfs_pcheck(bfs_spawn_addfchdir(&spawn, 11) == 0); + ret &= bfs_pcheck(bfs_spawn_addclose(&spawn, 11) == 0); + if (!ret) { + goto destroy; + } + + // Check that $PATH is resolved in the parent's environment + char **envp; + ret &= bfs_pcheck(envp = envdup()); + if (!ret) { + goto destroy; + } + + // Check that $PATH is resolved after the file actions + char *old_path = getenv("PATH"); + dchar *new_path = NULL; + if (old_path) { + ret &= bfs_pcheck(old_path = strdup(old_path)); + if (!ret) { + goto env; + } + new_path = dstrprintf("tests:%s", old_path); + } else { + new_path = dstrdup("tests"); + } + ret &= bfs_check(new_path); + if (!ret) { + goto path; + } + + ret &= bfs_pcheck(setenv("PATH", new_path, true) == 0); + if (!ret) { + goto path; + } + + char *argv[] = {"xspawnee", old_path, NULL}; + pid_t pid = bfs_spawn("xspawnee", &spawn, argv, envp); + ret &= bfs_pcheck(pid >= 0, "bfs_spawn()"); + if (!ret) { + goto unset; + } + + int wstatus; + ret &= bfs_pcheck(xwaitpid(pid, &wstatus, 0) == pid) + && bfs_check(WIFEXITED(wstatus)); + if (ret) { + int wexit = WEXITSTATUS(wstatus); + ret &= bfs_check(wexit == EXIT_SUCCESS, "xspawnee: exit(%d)", wexit); + } + +unset: + if (old_path) { + ret &= bfs_pcheck(setenv("PATH", old_path, true) == 0); + } else { + ret &= bfs_pcheck(unsetenv("PATH") == 0); + } +path: + dstrfree(new_path); + free(old_path); +env: + for (char **var = envp; *var; ++var) { + free(*var); + } + free(envp); +destroy: + ret &= bfs_pcheck(bfs_spawn_destroy(&spawn) == 0); +out: + return ret; +} + +/** Check path resolution of non-existent executables. */ +static bool check_enoent(bool use_posix) { + bool ret = true; + + struct bfs_spawn spawn; + ret &= bfs_pcheck(bfs_spawn_init(&spawn) == 0); + if (!ret) { + goto out; + } + + spawn.flags |= BFS_SPAWN_USE_PATH; + if (!use_posix) { + spawn.flags &= ~BFS_SPAWN_USE_POSIX; + } + + char *argv[] = {"eW6f5RM9Qi", NULL}; + pid_t pid = bfs_spawn("eW6f5RM9Qi", &spawn, argv, NULL); + ret &= bfs_pcheck(pid < 0 && errno == ENOENT, "bfs_spawn()"); + + ret &= bfs_pcheck(bfs_spawn_destroy(&spawn) == 0); +out: + return ret; +} + +static bool check_resolve(void) { + bool ret = true; + char *exe; + + exe = bfs_spawn_resolve("sh"); + ret &= bfs_pcheck(exe, "bfs_spawn_resolve('sh')"); + free(exe); + + exe = bfs_spawn_resolve("/bin/sh"); + ret &= bfs_pcheck(exe && strcmp(exe, "/bin/sh") == 0); + free(exe); + + exe = bfs_spawn_resolve("bin/tests/xspawnee"); + ret &= bfs_pcheck(exe && strcmp(exe, "bin/tests/xspawnee") == 0); + free(exe); + + ret &= bfs_pcheck(!bfs_spawn_resolve("eW6f5RM9Qi") && errno == ENOENT); + + return ret; +} + +bool check_xspawn(void) { + bool ret = true; + + ret &= check_use_path(true); + ret &= check_use_path(false); + + ret &= check_enoent(true); + ret &= check_enoent(false); + + ret &= check_resolve(); + + return ret; +} |