From cef7779f31e915366b1507e0eafc6665b9161c5d Mon Sep 17 00:00:00 2001 From: Jonas 'Sortie' Termansen Date: Sat, 22 Jun 2024 09:47:04 +0000 Subject: [PATCH] Handle SIGTERM in display(1). Display a final frame with a message explaining what is happening that is displayed while the system powers off, reboots, halts, when the user logs out, or just exits the compositor. --- display/connection.c | 12 +++---- display/connection.h | 3 +- display/display-code.c | 78 ++++++++++++++++++++++++++++++++++++++++-- display/display.c | 4 +-- display/display.h | 7 +++- display/server.c | 41 ++++++++++++++++++++-- 6 files changed, 130 insertions(+), 15 deletions(-) diff --git a/display/connection.c b/display/connection.c index 57e2ccfb..eb9a9ffa 100644 --- a/display/connection.c +++ b/display/connection.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, 2016, 2023 Jonas 'Sortie' Termansen. + * Copyright (c) 2014, 2015, 2016, 2023, 2024 Jonas 'Sortie' Termansen. * Copyright (c) 2023 Juhani 'nortti' Krekelä. * * Permission to use, copy, modify, and distribute this software for any @@ -149,15 +149,15 @@ CONNECTION_MESSAGE_HANDLER_NO_AUX(shutdown) { (void) connection; if ( msg->code == 0 ) - exit(0); + display_exit(server->display, 0); else if ( msg->code == 1 ) - exit(1); + display_exit(server->display, 1); else if ( msg->code == 2 ) - exit(2); + display_exit(server->display, 2); else if ( msg->code == 3 ) - exit(3); + display_exit(server->display, 3); else - exit(0); + display_exit(server->display, 0); } CONNECTION_MESSAGE_HANDLER_NO_AUX(create_window) diff --git a/display/connection.h b/display/connection.h index 2fb1898c..2539fa10 100644 --- a/display/connection.h +++ b/display/connection.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, 2016 Jonas 'Sortie' Termansen. + * Copyright (c) 2014, 2015, 2016, 2024 Jonas 'Sortie' Termansen. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -25,6 +25,7 @@ #include +#include "display.h" #include "server.h" #include "window.h" diff --git a/display/display-code.c b/display/display-code.c index fbe3666f..69a02e2d 100644 --- a/display/display-code.c +++ b/display/display-code.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, 2016, 2018, 2022, 2023 Jonas 'Sortie' Termansen. + * Copyright (c) 2014-2016, 2018, 2022-2024 Jonas 'Sortie' Termansen. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -23,6 +23,8 @@ #include #include +#include +#include #include #include #include @@ -47,6 +49,43 @@ void display_initialize(struct display* display) { memset(display, 0, sizeof(*display)); display->redraw = true; + display->running = true; +} + +static int get_init_exit_plan(void) +{ + FILE* fp = popen("/sbin/service default exit-code", "r"); + if ( !fp ) + return -1; + int result = -1; + char buffer[sizeof(int) * 3]; + if ( fgets(buffer, sizeof(buffer), fp) && buffer[0] ) + result = atoi(buffer); + pclose(fp); + return result; +} + +void display_exit(struct display* display, int exit_code) +{ + display->running = false; + display->exit_code = exit_code; + int plan = exit_code == -1 ? get_init_exit_plan() : exit_code; + display->announcement = "Exiting..."; + if ( plan == 0 ) + display->announcement = "Powering off..."; + else if ( plan == 1 ) + display->announcement = "Rebooting..."; + else if ( plan == 2 ) + display->announcement = "Halting..."; + else if ( plan == 3 ) + display->announcement = "Reinitializing operating system..."; + else if ( getenv("LOGIN_PID") ) // TODO: display -l? + { + intmax_t login_pid = strtoimax(getenv("LOGIN_PID"), NULL, 10); + if ( login_pid == getppid() ) + display->announcement = "Logging out..."; + } + display->redraw = true; } void assert_is_well_formed_display_list(struct display* display) @@ -281,6 +320,31 @@ static void wallpaper(struct framebuffer fb) } } +static void display_render_exit(struct display* display, struct framebuffer fb) +{ + for ( int yoff = -1; yoff <= 1; yoff++ ) + { + for ( int xoff = -1; xoff <= 1; xoff++ ) + { + struct framebuffer msgfb = fb; + int y = (fb.yres - FONT_HEIGHT) / 2 + yoff; + msgfb = framebuffer_cut_top_y(msgfb, y); + int w = strlen(display->announcement) * (FONT_WIDTH+1); + int x = (fb.xres - w) / 2 + xoff; + msgfb = framebuffer_cut_left_x(msgfb, x); + render_text(msgfb, display->announcement, make_color_a(0, 0, 0, 64)); + } + } + + struct framebuffer msgfb = fb; + int y = (fb.yres - FONT_HEIGHT) / 2; + msgfb = framebuffer_cut_top_y(msgfb, y); + int w = strlen(display->announcement) * (FONT_WIDTH+1); + int x = (fb.xres - w) / 2; + msgfb = framebuffer_cut_left_x(msgfb, x); + render_text(msgfb, display->announcement, make_color(255, 255, 255)); +} + void display_composit(struct display* display, struct framebuffer fb) { struct damage_rect damage_rect = display->damage_rect; @@ -301,6 +365,12 @@ void display_composit(struct display* display, struct framebuffer fb) framebuffer_copy_to_framebuffer(fb, display->wallpaper); + if ( display->announcement ) + { + display_render_exit(display, fb); + return; + } + for ( struct window* window = display->bottom_window; window; window = window->above_window ) @@ -482,11 +552,15 @@ void display_keyboard_event(struct display* display, uint32_t codepoint) case KBKEY_RSUPER: display->key_rsuper = kbkey > 0; break; } if ( display->key_lctrl && display->key_lalt && kbkey == KBKEY_DELETE ) - exit(0); + display_exit(display, -1); if ( display->key_lctrl && display->key_lalt && kbkey == KBKEY_T ) { if ( !fork() ) { + sigset_t sigterm; + sigemptyset(&sigterm); + sigaddset(&sigterm, SIGTERM); + sigprocmask(SIG_UNBLOCK, &sigterm, NULL); execlp("terminal", "terminal", (char*) NULL); _exit(127); } diff --git a/display/display.c b/display/display.c index 2c01975c..153ee8ba 100644 --- a/display/display.c +++ b/display/display.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, 2016, 2017, 2022, 2023 Jonas 'Sortie' Termansen. + * Copyright (c) 2014-2017, 2022-2024 Jonas 'Sortie' Termansen. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -119,5 +119,5 @@ int main(int argc, char* argv[]) server_mainloop(&server); - return 0; + return display.exit_code; } diff --git a/display/display.h b/display/display.h index a8635344..9c6b87fd 100644 --- a/display/display.h +++ b/display/display.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, 2016, 2022, 2023 Jonas 'Sortie' Termansen. + * Copyright (c) 2014, 2015, 2016, 2022, 2023, 2024 Jonas 'Sortie' Termansen. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -68,14 +68,19 @@ struct display bool key_rsuper; bool codepoint_discard; bool redraw; + bool running; int pointer_x; int pointer_y; enum mouse_state mouse_state; size_t mouse_byte_count; uint8_t mouse_bytes[MOUSE_PACKET_SIZE]; + const char* announcement; + int exit_code; + }; void display_initialize(struct display* display); +void display_exit(struct display* display, int exit_code); void assert_is_well_formed_display_list(struct display* display); void assert_is_well_formed_display(struct display* display); void display_link_window_at_top(struct display* display, struct window* window); diff --git a/display/server.c b/display/server.c index 253ee595..afd1bc3d 100644 --- a/display/server.c +++ b/display/server.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, 2016, 2023 Jonas 'Sortie' Termansen. + * Copyright (c) 2014, 2015, 2016, 2023, 2024 Jonas 'Sortie' Termansen. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -40,6 +41,14 @@ #include "server.h" #include "vgafont.h" +static volatile sig_atomic_t got_sigterm; + +static void on_sigterm(int signum) +{ + (void) signum; + got_sigterm = 1; +} + static int open_local_server_socket(const char* path, int flags) { size_t path_length = strlen(path); @@ -196,9 +205,24 @@ void server_poll(struct server* server) } size_t pfds_used = cpfd_off + connections_polled; - int num_events = ppoll(pfds, pfds_used, NULL, NULL); + sigset_t mask; + sigprocmask(SIG_SETMASK, NULL, &mask); + sigdelset(&mask, SIGTERM); + + int num_events = ppoll(pfds, pfds_used, NULL, &mask); + + if ( got_sigterm ) + { + display_exit(server->display, -1); + got_sigterm = 0; + } + if ( num_events < 0 ) + { + if ( errno == EINTR ) + return; err(1, "poll"); + } if ( pfds[0].revents ) { @@ -273,9 +297,20 @@ void server_poll(struct server* server) void server_mainloop(struct server* server) { - while ( true ) + sigset_t sigterm, oldset; + sigemptyset(&sigterm); + sigaddset(&sigterm, SIGTERM); + sigprocmask(SIG_BLOCK, &sigterm, &oldset); + struct sigaction sa = { .sa_handler = on_sigterm }, old_sa; + sigaction(SIGTERM, &sa, &old_sa); + + while ( server->display->running ) { display_render(server->display); server_poll(server); } + display_render(server->display); + + sigaction(SIGTERM, &old_sa, NULL); + sigprocmask(SIG_SETMASK, &oldset, NULL); }