#include #include #include #include #include #include #include #include #include #include #include #include int main(int argc, char *argv[]) { (void)argc; const char *usage = "Usage: seatd-launch [options] [--] command\n" "\n" " -h Show this help message\n" " -s Where to create the seatd socket\n" " -v Show the version number\n" "\n"; int c; char *sockpath = NULL; while ((c = getopt(argc, argv, "vhs:")) != -1) { switch (c) { case 's': sockpath = optarg; break; case 'v': printf("seatd-launch version %s\n", SEATD_VERSION); return 0; case 'h': printf("%s", usage); return 0; case '?': fprintf(stderr, "Try '%s -h' for more information.\n", argv[0]); return 1; default: abort(); } } char sockbuf[256]; if (sockpath == NULL) { sprintf(sockbuf, "/tmp/seatd.%d.sock", getpid()); sockpath = sockbuf; } unlink(sockpath); 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()); if (!user) { perror("getpwuid failed"); _exit(1); } // TODO: Make seatd accept the numeric UID execlp("seatd", "seatd", "-n", pipebuf, "-u", user->pw_name, "-s", sockpath, NULL); perror("Could not start seatd"); _exit(1); } 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", sockpath, 1); execv(argv[1], &argv[1]); perror("Could not start target"); _exit(1); } int status = 0; while (true) { pid_t p = waitpid(child, &status, 0); if (p == child) { break; } else if (p == -1 && errno != EINTR) { perror("Could not wait for target process"); goto error_seatd; } } unlink(sockpath); kill(seatd_child, SIGTERM); if (WIFEXITED(status)) { return WEXITSTATUS(status); } else { return 1; } error_seatd: unlink(sockpath); kill(seatd_child, SIGTERM); error: return 1; }