From dcd7970fbc899ef32986c9dbc6ebf4fb23f9a611 Mon Sep 17 00:00:00 2001 From: Jonathan GUILLOT Date: Fri, 18 Aug 2023 15:25:21 +0200 Subject: [PATCH] cage: return exit code of primary client Some applications indicate different shutdown conditions by returning specific exit codes. One of these is e.g. Kodi, which returns 64 in case the user chose "Power off" and 66 in case the user chose "Reboot". In order to act on these exit codes, it thus makes sense in some situations to pass them on from the primary client to the caller of Cage. This exit code is only returned if the primary client is the cause of Cage terminating. Co-authored-by: Patrick Steinhardt --- cage.c | 26 +++++++++++++++++--------- server.h | 1 + 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/cage.c b/cage.c index 75f0696..7a4bd9f 100644 --- a/cage.c +++ b/cage.c @@ -62,7 +62,7 @@ static int sigchld_handler(int fd, uint32_t mask, void *data) { - struct wl_display *display = data; + struct cg_server *server = data; /* Close Cage's read pipe. */ close(fd); @@ -73,7 +73,8 @@ sigchld_handler(int fd, uint32_t mask, void *data) wlr_log(WLR_DEBUG, "Connection closed by server"); } - wl_display_terminate(display); + server->return_app_code = true; + wl_display_terminate(server->wl_display); return 0; } @@ -97,7 +98,7 @@ set_cloexec(int fd) } static bool -spawn_primary_client(struct wl_display *display, char *argv[], pid_t *pid_out, struct wl_event_source **sigchld_source) +spawn_primary_client(struct cg_server *server, char *argv[], pid_t *pid_out, struct wl_event_source **sigchld_source) { int fd[2]; if (pipe(fd) != 0) { @@ -131,15 +132,15 @@ spawn_primary_client(struct wl_display *display, char *argv[], pid_t *pid_out, s /* Close write, we only need read in Cage. */ close(fd[1]); - struct wl_event_loop *event_loop = wl_display_get_event_loop(display); + struct wl_event_loop *event_loop = wl_display_get_event_loop(server->wl_display); uint32_t mask = WL_EVENT_HANGUP | WL_EVENT_ERROR; - *sigchld_source = wl_event_loop_add_fd(event_loop, fd[0], mask, sigchld_handler, display); + *sigchld_source = wl_event_loop_add_fd(event_loop, fd[0], mask, sigchld_handler, server); wlr_log(WLR_DEBUG, "Child process created with pid %d", pid); return true; } -static void +static int cleanup_primary_client(pid_t pid) { int status; @@ -148,9 +149,14 @@ cleanup_primary_client(pid_t pid) if (WIFEXITED(status)) { wlr_log(WLR_DEBUG, "Child exited normally with exit status %d", WEXITSTATUS(status)); + return WEXITSTATUS(status); } else if (WIFSIGNALED(status)) { + /* Mimic Bash and other shells for the exit status */ wlr_log(WLR_DEBUG, "Child was terminated by a signal (%d)", WTERMSIG(status)); + return 128 + WTERMSIG(status); } + + return 0; } static bool @@ -278,7 +284,7 @@ main(int argc, char *argv[]) struct wlr_xcursor_manager *xcursor_manager = NULL; #endif pid_t pid = 0; - int ret = 0; + int ret = 0, app_ret = 0; if (!parse_args(&server, argc, argv)) { return 1; @@ -568,7 +574,7 @@ main(int argc, char *argv[]) wlr_xwayland_set_seat(xwayland, server.seat->seat); #endif - if (!spawn_primary_client(server.wl_display, argv + optind, &pid, &sigchld_source)) { + if (!spawn_primary_client(&server, argv + optind, &pid, &sigchld_source)) { ret = 1; goto end; } @@ -587,7 +593,9 @@ main(int argc, char *argv[]) wl_display_destroy_clients(server.wl_display); end: - cleanup_primary_client(pid); + app_ret = cleanup_primary_client(pid); + if (!ret && server.return_app_code) + ret = app_ret; wl_event_source_remove(sigint_source); wl_event_source_remove(sigterm_source); diff --git a/server.h b/server.h index 6e2fddf..643ac0d 100644 --- a/server.h +++ b/server.h @@ -53,6 +53,7 @@ struct cg_server { bool xdg_decoration; bool allow_vt_switch; + bool return_app_code; }; #endif