diff options
author | Mattias Andrée <maandree@kth.se> | 2024-05-05 10:24:40 +0200 |
---|---|---|
committer | Mattias Andrée <maandree@kth.se> | 2024-05-05 10:24:40 +0200 |
commit | 3dfd6c11ed5599ab8baf4a6114f4ccb34150de6e (patch) | |
tree | b7717583b99f29028c85c3423cf43b104dfa8943 /libexec_exec.c | |
download | libexec-3dfd6c11ed5599ab8baf4a6114f4ccb34150de6e.tar.gz libexec-3dfd6c11ed5599ab8baf4a6114f4ccb34150de6e.tar.bz2 libexec-3dfd6c11ed5599ab8baf4a6114f4ccb34150de6e.tar.xz |
First commit
Signed-off-by: Mattias Andrée <maandree@kth.se>
Diffstat (limited to '')
-rw-r--r-- | libexec_exec.c | 200 |
1 files changed, 200 insertions, 0 deletions
diff --git a/libexec_exec.c b/libexec_exec.c new file mode 100644 index 0000000..3f306d0 --- /dev/null +++ b/libexec_exec.c @@ -0,0 +1,200 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + + +static char * +which(const char *name, char *path, char **end_colon_out) +{ + size_t namelen_nul, dirlen, maxlen; + char *p, *q, *buf; + int eacces_encountered = 0; + + if (!path || !*path) + goto enoent; + + maxlen = 0; + for (p = path; p; p = q) { + q = strchr(p, ':'); + if (q) + dirlen = (size_t)(q++ - p); + else + dirlen = strlen(p); + if (dirlen > maxlen) + dirlen = maxlen; + } + + namelen_nul = strlen(name) + 1; + + buf = NULL; + if (maxlen) { + buf = malloc(maxlen + 1 + namelen_nul); + if (!buf) + return NULL; + } + + for (; path; path = q) { + q = strchr(p, ':'); + if (q) + dirlen = (size_t)(q++ - path); + else + dirlen = strlen(path); + p = buf; + if (dirlen) { + memcpy(p, path, dirlen); + p = &p[dirlen]; + *p++ = '/'; + } + memcpy(p, name, namelen_nul); + if (!faccessat(AT_FDCWD, buf, X_OK, AT_EACCESS)) { + *end_colon_out = q; + return buf; + } + if (errno == EACCES) + eacces_encountered = 1; + } + + free(buf); + + if (eacces_encountered) { + errno = EACCES; + return NULL; + } + +enoent: + errno = ENOENT; + return NULL; +} + + +static void +exec_path(struct libexec_command *cmd) +{ + const char *file = cmd->executable ? cmd->executable : cmd->arguments[0]; + execve(file, cmd->arguments, cmd->environ ? cmd->environ : environ); +} + + +static void +exec_name(struct libexec_command *cmd) +{ + /* execvpe is non-standard */ + const char *file = cmd->executable ? cmd->executable : cmd->arguments[0]; + char *end_colon = NULL, *file_free = NULL; + if (!strchr(file, '/')) { + file = file_free = which(file, getenv("PATH"), &end_colon); + if (!file) + return; + } + execve(file, cmd->arguments, cmd->environ ? cmd->environ : environ); + free(file_free); + if (end_colon) + *end_colon = ':'; +} + + +static void +exec_fd(struct libexec_command *cmd) +{ + fexecve(cmd->exec_fd, cmd->arguments, cmd->environ ? cmd->environ : environ); +} + + +static void +exec_at(struct libexec_command *cmd) +{ + const char *file = cmd->executable ? cmd->executable : cmd->arguments[0]; + execveat(cmd->exec_fd, file, cmd->arguments, cmd->environ ? cmd->environ : environ, 0); +} + + +int +libexec_exec(struct libexec_command *cmd) +{ + void (*exec_function)(struct libexec_command *cmd); + size_t i; + int fd; + + if (!cmd) + goto einval; + + if (cmd->library_version > LIBEXEC_VERSION) + abort(); + + if (!cmd->narguments) + goto einval; + + if (cmd->exec_how == LIBEXEC_REQUIRE_PATH) + exec_function = &exec_path; + else if (cmd->exec_how == LIBEXEC_ALLOW_NAME) + exec_function = &exec_name; + else if (cmd->exec_how == LIBEXEC_EXEC_FD) + exec_function = &exec_fd; + else if (cmd->exec_how == LIBEXEC_EXEC_AT) + exec_function = &exec_at; + else + goto einval; + + for (i = 0; i < cmd->nplumings; i++) { + switch (cmd->plumings[i].type) { + case LIBEXEC_PLUMING_CLOSE: + if (cmd->plumings[i].fd >= 0) { + close(cmd->plumings[i].fd); + cmd->plumings[i].fd = -1; + } + break; + +#if defined(__linux__) + case LIBEXEC_PLUMING_OPENAT2: + fd = (int)syscall(SYS_openat2, + cmd->plumings[i].target.dirfd, cmd->plumings[i].target.file, + cmd->plumings[i].target.how, cmd->plumings[i].target.how_size); + if (fd < 0) + return -1; + free(cmd->plumings[i].target.file); + free(cmd->plumings[i].target.how); + goto openned_fd; +#endif + + case LIBEXEC_PLUMING_OPENAT: + fd = openat(cmd->plumings[i].target.dirfd, cmd->plumings[i].target.file, + cmd->plumings[i].target.flags, cmd->plumings[i].target.mode); + if (fd < 0) + return -1; + free(cmd->plumings[i].target.file); +#if defined(__linux__) + openned_fd: +#endif + cmd->plumings[i].type = LIBEXEC_PLUMING_PIPE; + cmd->plumings[i].target.fd = fd; + /* fall through */ + + case LIBEXEC_PLUMING_DUP2: + case LIBEXEC_PLUMING_PIPE: + if (cmd->plumings[i].fd == cmd->plumings[i].target.fd) + break; + if (dup2(cmd->plumings[i].target.fd, cmd->plumings[i].fd) == -1) + return -1; + if (cmd->plumings[i].type == LIBEXEC_PLUMING_PIPE) + close(cmd->plumings[i].target.fd); + cmd->plumings[i].target.fd = cmd->plumings[i].fd; + break; + + default: + case LIBEXEC_PLUMING_DOCUMENT: + goto einval; + } + } + + (*exec_function)(cmd); + return -1; + +einval: + errno = EINVAL; + return -1; +} + + +#else +LIBEXEC_CONST__ int main(void) {return 0;} /* TODO test */ +#endif |