aboutsummaryrefslogtreecommitdiffstats
path: root/libexec_exec.c
diff options
context:
space:
mode:
authorMattias Andrée <maandree@kth.se>2024-05-05 10:24:40 +0200
committerMattias Andrée <maandree@kth.se>2024-05-05 10:24:40 +0200
commit3dfd6c11ed5599ab8baf4a6114f4ccb34150de6e (patch)
treeb7717583b99f29028c85c3423cf43b104dfa8943 /libexec_exec.c
downloadlibexec-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.c200
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