diff options
author | Kenny Levinsen <kl@kl.wtf> | 2021-08-06 00:06:44 +0200 |
---|---|---|
committer | Kenny Levinsen <kl@kl.wtf> | 2021-08-06 01:29:52 +0200 |
commit | 1e98727ae9dfdb23316249a4f32b3169d956e417 (patch) | |
tree | 9d886b4708cf7d9bfac266fc7a494c0f5b4cd347 /seatd-launch/seatd-launch.c | |
parent | c8b3a22d4ef0f69c3d22f0ec1170b89c93ef1dc3 (diff) |
seatd-launch: Add seatd launch wrapper
This launch wrapper is used to conveniently start a new seatd instance,
wait for it to be ready, and launch a target application.
Diffstat (limited to 'seatd-launch/seatd-launch.c')
-rw-r--r-- | seatd-launch/seatd-launch.c | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/seatd-launch/seatd-launch.c b/seatd-launch/seatd-launch.c new file mode 100644 index 0000000..ffa6cc6 --- /dev/null +++ b/seatd-launch/seatd-launch.c @@ -0,0 +1,123 @@ +#include <errno.h> +#include <poll.h> +#include <pwd.h> +#include <signal.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> + +int main(int argc, char *argv[]) { + (void)argc; + char sockbuf[256]; + + sprintf(sockbuf, "/tmp/seatd.%d.sock", getpid()); + unlink(sockbuf); + + int fds[2]; + if (pipe(fds) == -1) { + perror("Could not create pipe"); + goto error; + } + + pid_t seatd_child = fork(); + if (seatd_child == -1) { + perror("Could not fork seatd process"); + goto error; + } else if (seatd_child == 0) { + close(fds[0]); + + char pipebuf[8]; + sprintf(pipebuf, "%d", fds[1]); + struct passwd *user = getpwuid(getuid()); + + // TODO: Make seatd accept the numeric UID + execlp("seatd", "seatd", "-n", pipebuf, "-u", user->pw_name, "-s", sockbuf, NULL); + perror("Could not start seatd"); + goto error; + } + close(fds[1]); + + // Drop privileges + if (setgid(getgid()) == -1) { + perror("Could not set gid to drop privileges"); + goto error_seatd; + } + if (setuid(getuid()) == -1) { + perror("Could not set uid to drop privileges"); + goto error_seatd; + } + + char buf[1] = {0}; + while (true) { + pid_t p = waitpid(seatd_child, NULL, WNOHANG); + if (p == seatd_child) { + fprintf(stderr, "seatd exited prematurely\n"); + goto error_seatd; + } else if (p == -1 && (errno != EINTR && errno != ECHILD)) { + perror("Could not wait for seatd process"); + goto error_seatd; + } + + struct pollfd fd = { + .fd = fds[0], + .events = POLLIN, + }; + + // We poll with timeout to avoid a racing on a blocking read + if (poll(&fd, 1, 1000) == -1) { + if (errno == EAGAIN || errno == EINTR) { + continue; + } else { + perror("Could not poll notification fd"); + goto error_seatd; + } + } + + if (fd.revents & POLLIN) { + ssize_t n = read(fds[0], buf, 1); + if (n == -1 && errno != EINTR) { + perror("Could not read from pipe"); + goto error_seatd; + } else if (n > 0) { + break; + } + } + } + close(fds[0]); + + pid_t child = fork(); + if (child == -1) { + perror("Could not fork target process"); + goto error_seatd; + } else if (child == 0) { + setenv("SEATD_SOCK", sockbuf, 1); + execv(argv[1], &argv[1]); + perror("Could not start target"); + goto error_seatd; + } + + while (true) { + pid_t p = waitpid(child, NULL, 0); + if (p == child) { + break; + } else if (p == -1 && errno != EINTR) { + perror("Could not wait for target process"); + goto error_seatd; + } + } + + unlink(sockbuf); + kill(seatd_child, SIGTERM); + return 0; + +error_seatd: + unlink(sockbuf); + kill(seatd_child, SIGTERM); +error: + return 1; +} |