From 056ec64bcb63235c307d11d4b532ba1d15351a14 Mon Sep 17 00:00:00 2001 From: javalsai Date: Wed, 27 Aug 2025 20:29:16 +0200 Subject: [PATCH] feat: better spawn error handling --- src/auth.c | 77 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 53 insertions(+), 24 deletions(-) diff --git a/src/auth.c b/src/auth.c index c076eb4..68dded0 100644 --- a/src/auth.c +++ b/src/auth.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -81,6 +82,12 @@ void source_paths(struct Vector* NNULLABLE vec_envlist, /*setenv("XDG_SESSION_DESKTOP", , true);*/ /*setenv("XDG_SEAT", "seat0", true);*/ +struct child_msg { + char* msg; + int _errno; + bool err; +}; + // NOLINTBEGIN(readability-function-cognitive-complexity) bool launch(char* user, char* passwd, struct session session, void (*cb)(void), struct config* config) { @@ -134,45 +141,67 @@ bool launch(char* user, char* passwd, struct session session, void (*cb)(void), return false; } + int pipefd[2]; + pipe(pipefd); + uint pid = fork(); if (pid == 0) { // child - if (chdir(pw->pw_dir) == -1) print_errno("can't chdir to user home"); - // TODO: chown stdin to user - // does it inherit stdin from parent and - // does parent need to reclaim it after - // this dies? +#define SEND_MSG(MSG) \ + { \ + write(pipefd[1], &(MSG), sizeof(struct child_msg)); \ + close(pipefd[1]); \ + } +#define SEND_ERR(MSG) \ + { \ + write(pipefd[1], \ + &(struct child_msg){.msg = (MSG), ._errno = errno, .err = true}, \ + sizeof(struct child_msg)); \ + close(pipefd[1]); \ + _exit(EXIT_FAILURE); \ + } - if (setgid(pw->pw_gid) == -1) { - print_errno("setgid"); - _exit(EXIT_FAILURE); - } - if (initgroups(user, pw->pw_gid) == -1) { - print_errno("initgroups"); - _exit(EXIT_FAILURE); - } + if (chdir(pw->pw_dir) == -1) SEND_ERR("chdir"); + if (setgid(pw->pw_gid) == -1) SEND_ERR("setgid"); + if (initgroups(user, pw->pw_gid) == -1) SEND_ERR("initgroups"); + if (setuid(pw->pw_uid) == -1) SEND_ERR("setuid"); - if (setuid(pw->pw_uid) == -1) { - perror("setuid"); - _exit(EXIT_FAILURE); - } + SEND_MSG((struct child_msg){.err = false}); +#undef SEND_MSG +#undef SEND_ERR + char _; + read(pipefd[0], &_, sizeof(_)); + close(pipefd[0]); - if (cb) cb(); - - printf("\x1b[0m\x1b[H\x1b[J"); - (void)fflush(stdout); + int exit; if (session.type == SHELL) { - execle(session.exec, session.exec, NULL, envlist); + exit = execle(session.exec, session.exec, NULL, envlist); } else if (session.type == XORG || session.type == WAYLAND) { // TODO: test existence of executable with TryExec // NOLINTNEXTLINE - execve(desktop_exec[0], desktop_exec, envlist); + exit = execve(desktop_exec[0], desktop_exec, envlist); // NOLINTNEXTLINE free_parsed_args(desktop_count, desktop_exec); - } + } else + exit = -1; perror("exec error"); (void)fputs("failure calling session\n", stderr); + _exit(exit); } else { + struct child_msg msg; + read(pipefd[0], &msg, sizeof(struct child_msg)); + close(pipefd[0]); + if (msg.err) { + errno = msg._errno; + print_errno(msg.msg); + return false; + } + + if (cb) cb(); + printf("\x1b[0m\x1b[H\x1b[J"); + (void)fflush(stdout); + close(pipefd[1]); + int exit_code; waitpid((pid_t)pid, &exit_code, 0);