Handle SIGTERM in login(8).
Display a final frame with a message explaining what is happening that is displayed while the system powers off, reboots, or halts.
This commit is contained in:
parent
2bc6e40f1d
commit
65bc117891
3 changed files with 178 additions and 8 deletions
|
@ -63,6 +63,7 @@ enum stage
|
||||||
STAGE_USERNAME,
|
STAGE_USERNAME,
|
||||||
STAGE_PASSWORD,
|
STAGE_PASSWORD,
|
||||||
STAGE_CHECKING,
|
STAGE_CHECKING,
|
||||||
|
STAGE_EXITING,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct textbox
|
struct textbox
|
||||||
|
@ -111,6 +112,7 @@ struct glogin
|
||||||
enum stage stage;
|
enum stage stage;
|
||||||
bool animating;
|
bool animating;
|
||||||
const char* warning;
|
const char* warning;
|
||||||
|
const char* announcement;
|
||||||
bool pointer_working;
|
bool pointer_working;
|
||||||
struct termios old_tio;
|
struct termios old_tio;
|
||||||
bool has_old_tio;
|
bool has_old_tio;
|
||||||
|
@ -499,6 +501,33 @@ static void render_progress(struct framebuffer fb)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void render_exit(struct framebuffer fb)
|
||||||
|
{
|
||||||
|
assert(state.announcement);
|
||||||
|
|
||||||
|
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(state.announcement) * (FONT_WIDTH+1);
|
||||||
|
int x = (fb.xres - w) / 2 + xoff;
|
||||||
|
msgfb = framebuffer_cut_left_x(msgfb, x);
|
||||||
|
render_text(msgfb, state.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(state.announcement) * (FONT_WIDTH+1);
|
||||||
|
int x = (fb.xres - w) / 2;
|
||||||
|
msgfb = framebuffer_cut_left_x(msgfb, x);
|
||||||
|
render_text(msgfb, state.announcement, make_color(255, 255, 255));
|
||||||
|
}
|
||||||
|
|
||||||
static void render_login(struct framebuffer fb)
|
static void render_login(struct framebuffer fb)
|
||||||
{
|
{
|
||||||
render_background(fb);
|
render_background(fb);
|
||||||
|
@ -509,6 +538,7 @@ static void render_login(struct framebuffer fb)
|
||||||
case STAGE_USERNAME: render_form(fb); break;
|
case STAGE_USERNAME: render_form(fb); break;
|
||||||
case STAGE_PASSWORD: render_form(fb); break;
|
case STAGE_PASSWORD: render_form(fb); break;
|
||||||
case STAGE_CHECKING: render_progress(fb); break;
|
case STAGE_CHECKING: render_progress(fb); break;
|
||||||
|
case STAGE_EXITING: render_exit(fb); break;
|
||||||
}
|
}
|
||||||
if ( state.pointer_working )
|
if ( state.pointer_working )
|
||||||
render_pointer(fb);
|
render_pointer(fb);
|
||||||
|
@ -669,6 +699,52 @@ static bool render(struct glogin* state)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void handle_special_graphical(struct glogin* state,
|
||||||
|
enum special_action special_action)
|
||||||
|
{
|
||||||
|
switch ( special_action )
|
||||||
|
{
|
||||||
|
case SPECIAL_ACTION_NONE:
|
||||||
|
state->announcement = NULL;
|
||||||
|
break;
|
||||||
|
case SPECIAL_ACTION_EXIT:
|
||||||
|
state->announcement = "Exiting...";
|
||||||
|
break;
|
||||||
|
case SPECIAL_ACTION_POWEROFF:
|
||||||
|
state->announcement = "Powering off...";
|
||||||
|
break;
|
||||||
|
case SPECIAL_ACTION_REBOOT:
|
||||||
|
state->announcement = "Rebooting...";
|
||||||
|
break;
|
||||||
|
case SPECIAL_ACTION_HALT:
|
||||||
|
state->announcement = "Halting...";
|
||||||
|
break;
|
||||||
|
case SPECIAL_ACTION_REINIT:
|
||||||
|
state->announcement = "Reinitializing operating system...";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ( state->announcement )
|
||||||
|
{
|
||||||
|
state->stage = STAGE_EXITING;
|
||||||
|
state->fading_from = false;
|
||||||
|
render(state);
|
||||||
|
}
|
||||||
|
handle_special(special_action);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
static void think(struct glogin* state)
|
static void think(struct glogin* state)
|
||||||
{
|
{
|
||||||
if ( state->stage == STAGE_CHECKING )
|
if ( state->stage == STAGE_CHECKING )
|
||||||
|
@ -679,6 +755,7 @@ static void think(struct glogin* state)
|
||||||
sched_yield();
|
sched_yield();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
forward_sigterm_to = 0;
|
||||||
if ( result )
|
if ( result )
|
||||||
{
|
{
|
||||||
if ( !login(username, session) )
|
if ( !login(username, session) )
|
||||||
|
@ -696,6 +773,21 @@ static void think(struct glogin* state)
|
||||||
state->warning = strerror(errno);
|
state->warning = strerror(errno);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( got_sigterm )
|
||||||
|
{
|
||||||
|
int exit_code = get_init_exit_plan();
|
||||||
|
enum special_action action = SPECIAL_ACTION_EXIT;
|
||||||
|
if ( exit_code == 0 )
|
||||||
|
action = SPECIAL_ACTION_POWEROFF;
|
||||||
|
else if ( exit_code == 1 )
|
||||||
|
action = SPECIAL_ACTION_REBOOT;
|
||||||
|
else if ( exit_code == 2 )
|
||||||
|
action = SPECIAL_ACTION_HALT;
|
||||||
|
else if ( exit_code == 3 )
|
||||||
|
action = SPECIAL_ACTION_REINIT;
|
||||||
|
handle_special_graphical(state, action);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void keyboard_event(struct glogin* state, uint32_t codepoint)
|
static void keyboard_event(struct glogin* state, uint32_t codepoint)
|
||||||
|
@ -717,7 +809,7 @@ static void keyboard_event(struct glogin* state, uint32_t codepoint)
|
||||||
state->warning = "Invalid username";
|
state->warning = "Invalid username";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
handle_special(action);
|
handle_special_graphical(state, action);
|
||||||
state->stage = STAGE_PASSWORD;
|
state->stage = STAGE_PASSWORD;
|
||||||
textbox_reset(&textbox_password);
|
textbox_reset(&textbox_password);
|
||||||
break;
|
break;
|
||||||
|
@ -729,8 +821,10 @@ static void keyboard_event(struct glogin* state, uint32_t codepoint)
|
||||||
state->stage = STAGE_USERNAME;
|
state->stage = STAGE_USERNAME;
|
||||||
state->warning = strerror(errno);
|
state->warning = strerror(errno);
|
||||||
}
|
}
|
||||||
|
forward_sigterm_to = state->chk.pid;
|
||||||
break;
|
break;
|
||||||
case STAGE_CHECKING:
|
case STAGE_CHECKING:
|
||||||
|
case STAGE_EXITING:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -741,6 +835,7 @@ static void keyboard_event(struct glogin* state, uint32_t codepoint)
|
||||||
case STAGE_USERNAME: textbox = &textbox_username; break;
|
case STAGE_USERNAME: textbox = &textbox_username; break;
|
||||||
case STAGE_PASSWORD: textbox = &textbox_password; break;
|
case STAGE_PASSWORD: textbox = &textbox_password; break;
|
||||||
case STAGE_CHECKING: break;
|
case STAGE_CHECKING: break;
|
||||||
|
case STAGE_EXITING: break;
|
||||||
}
|
}
|
||||||
if ( textbox && codepoint < 128 )
|
if ( textbox && codepoint < 128 )
|
||||||
{
|
{
|
||||||
|
@ -871,6 +966,12 @@ bool glogin_init(struct glogin* state)
|
||||||
struct timespec duration = timespec_make(0, 150*1000*1000);
|
struct timespec duration = timespec_make(0, 150*1000*1000);
|
||||||
state->fade_from_end = timespec_add(state->fade_from_begin, duration);
|
state->fade_from_end = timespec_add(state->fade_from_begin, duration);
|
||||||
}
|
}
|
||||||
|
sigset_t sigterm;
|
||||||
|
sigemptyset(&sigterm);
|
||||||
|
sigaddset(&sigterm, SIGTERM);
|
||||||
|
sigprocmask(SIG_BLOCK, &sigterm, NULL);
|
||||||
|
struct sigaction sa = { .sa_handler = on_interrupt_signal };
|
||||||
|
sigaction(SIGTERM, &sa, NULL);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -900,9 +1001,14 @@ int glogin_main(struct glogin* state)
|
||||||
nfds_t nfds = 2;
|
nfds_t nfds = 2;
|
||||||
struct timespec wake_now_ts = timespec_make(0, 0);
|
struct timespec wake_now_ts = timespec_make(0, 0);
|
||||||
struct timespec* wake = state->animating ? &wake_now_ts : NULL;
|
struct timespec* wake = state->animating ? &wake_now_ts : NULL;
|
||||||
int num_events = ppoll(pfds, nfds, wake, NULL);
|
sigset_t pollmask;
|
||||||
|
sigprocmask(SIG_SETMASK, NULL, &pollmask);
|
||||||
|
sigdelset(&pollmask, SIGTERM);
|
||||||
|
int num_events = ppoll(pfds, nfds, wake, &pollmask);
|
||||||
if ( num_events < 0 )
|
if ( num_events < 0 )
|
||||||
{
|
{
|
||||||
|
if ( errno == EINTR )
|
||||||
|
continue;
|
||||||
warn("poll");
|
warn("poll");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2014, 2015, 2018, 2022, 2023 Jonas 'Sortie' Termansen.
|
* Copyright (c) 2014, 2015, 2018, 2022, 2023, 2024 Jonas 'Sortie' Termansen.
|
||||||
* Copyright (c) 2023 dzwdz.
|
* Copyright (c) 2023 dzwdz.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
@ -46,12 +46,21 @@
|
||||||
|
|
||||||
#include "login.h"
|
#include "login.h"
|
||||||
|
|
||||||
static void on_interrupt_signal(int signum)
|
pid_t forward_sigterm_to = 0;
|
||||||
|
volatile sig_atomic_t got_sigterm = 0;
|
||||||
|
|
||||||
|
void on_interrupt_signal(int signum)
|
||||||
{
|
{
|
||||||
if ( signum == SIGINT )
|
if ( signum == SIGINT )
|
||||||
dprintf(1, "^C");
|
dprintf(1, "^C");
|
||||||
if ( signum == SIGQUIT )
|
if ( signum == SIGQUIT )
|
||||||
dprintf(1, "^\\");
|
dprintf(1, "^\\");
|
||||||
|
if ( signum == SIGTERM )
|
||||||
|
{
|
||||||
|
got_sigterm = 1;
|
||||||
|
if ( forward_sigterm_to )
|
||||||
|
kill(forward_sigterm_to, SIGTERM);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool check_real(const char* username, const char* password)
|
bool check_real(const char* username, const char* password)
|
||||||
|
@ -112,8 +121,10 @@ bool check_begin(struct check* chk,
|
||||||
{
|
{
|
||||||
sigdelset(&chk->oldset, SIGINT);
|
sigdelset(&chk->oldset, SIGINT);
|
||||||
sigdelset(&chk->oldset, SIGQUIT);
|
sigdelset(&chk->oldset, SIGQUIT);
|
||||||
|
sigdelset(&chk->oldset, SIGTERM);
|
||||||
signal(SIGINT, SIG_DFL);
|
signal(SIGINT, SIG_DFL);
|
||||||
signal(SIGQUIT, SIG_DFL);
|
signal(SIGQUIT, SIG_DFL);
|
||||||
|
signal(SIGTERM, SIG_DFL);
|
||||||
unsigned int termmode = TERMMODE_UNICODE | TERMMODE_SIGNAL |
|
unsigned int termmode = TERMMODE_UNICODE | TERMMODE_SIGNAL |
|
||||||
TERMMODE_UTF8 | TERMMODE_LINEBUFFER |
|
TERMMODE_UTF8 | TERMMODE_LINEBUFFER |
|
||||||
TERMMODE_ECHO;
|
TERMMODE_ECHO;
|
||||||
|
@ -144,6 +155,17 @@ bool check_end(struct check* chk, bool* result, bool try)
|
||||||
fcntl(chk->pipe, F_SETFL, fcntl(chk->pipe, F_GETFL) | O_NONBLOCK);
|
fcntl(chk->pipe, F_SETFL, fcntl(chk->pipe, F_GETFL) | O_NONBLOCK);
|
||||||
chk->pipe_nonblock = true;
|
chk->pipe_nonblock = true;
|
||||||
}
|
}
|
||||||
|
sigset_t sigterm, oldset;
|
||||||
|
sigemptyset(&sigterm);
|
||||||
|
sigaddset(&sigterm, SIGTERM);
|
||||||
|
struct sigaction sa = { .sa_handler = on_interrupt_signal }, old_sa;
|
||||||
|
if ( !try )
|
||||||
|
{
|
||||||
|
sigprocmask(SIG_BLOCK, &sigterm, &oldset);
|
||||||
|
forward_sigterm_to = chk->pid;
|
||||||
|
sigaction(SIGTERM, &sa, &old_sa);
|
||||||
|
sigprocmask(SIG_UNBLOCK, &sigterm, NULL);
|
||||||
|
}
|
||||||
while ( chk->errnum_done < sizeof(chk->errnum_bytes) )
|
while ( chk->errnum_done < sizeof(chk->errnum_bytes) )
|
||||||
{
|
{
|
||||||
ssize_t amount = read(chk->pipe, chk->errnum_bytes + chk->errnum_done,
|
ssize_t amount = read(chk->pipe, chk->errnum_bytes + chk->errnum_done,
|
||||||
|
@ -156,6 +178,13 @@ bool check_end(struct check* chk, bool* result, bool try)
|
||||||
}
|
}
|
||||||
chk->errnum_done += amount;
|
chk->errnum_done += amount;
|
||||||
}
|
}
|
||||||
|
if ( !try )
|
||||||
|
{
|
||||||
|
sigprocmask(SIG_BLOCK, &sigterm, NULL);
|
||||||
|
forward_sigterm_to = 0;
|
||||||
|
sigaction(SIGTERM, &old_sa, NULL);
|
||||||
|
sigprocmask(SIG_SETMASK, &oldset, NULL);
|
||||||
|
}
|
||||||
int code;
|
int code;
|
||||||
pid_t wait_ret = waitpid(chk->pid, &code, try ? WNOHANG : 0);
|
pid_t wait_ret = waitpid(chk->pid, &code, try ? WNOHANG : 0);
|
||||||
if ( try && wait_ret == 0 )
|
if ( try && wait_ret == 0 )
|
||||||
|
@ -230,11 +259,17 @@ bool login(const char* username, const char* session)
|
||||||
return free(login_shell), close(pipe_fds[0]), close(pipe_fds[1]), false;
|
return free(login_shell), close(pipe_fds[0]), close(pipe_fds[1]), false;
|
||||||
if ( child_pid == 0 )
|
if ( child_pid == 0 )
|
||||||
{
|
{
|
||||||
|
sigset_t sigterm;
|
||||||
|
sigemptyset(&sigterm);
|
||||||
|
sigaddset(&sigterm, SIGTERM);
|
||||||
|
sigprocmask(SIG_UNBLOCK, &sigterm, NULL);
|
||||||
sigdelset(&oldset, SIGINT);
|
sigdelset(&oldset, SIGINT);
|
||||||
sigdelset(&oldset, SIGQUIT);
|
sigdelset(&oldset, SIGQUIT);
|
||||||
|
sigdelset(&oldset, SIGTERM);
|
||||||
sigdelset(&oldset, SIGTSTP);
|
sigdelset(&oldset, SIGTSTP);
|
||||||
signal(SIGINT, SIG_DFL);
|
signal(SIGINT, SIG_DFL);
|
||||||
signal(SIGQUIT, SIG_DFL);
|
signal(SIGQUIT, SIG_DFL);
|
||||||
|
signal(SIGTERM, SIG_DFL);
|
||||||
(void) (
|
(void) (
|
||||||
setpgid(0, 0) < 0 ||
|
setpgid(0, 0) < 0 ||
|
||||||
close(pipe_fds[0]) < 0 ||
|
close(pipe_fds[0]) < 0 ||
|
||||||
|
@ -269,13 +304,33 @@ bool login(const char* username, const char* session)
|
||||||
}
|
}
|
||||||
free(login_shell);
|
free(login_shell);
|
||||||
close(pipe_fds[1]);
|
close(pipe_fds[1]);
|
||||||
|
|
||||||
|
sigset_t sigterm;
|
||||||
|
sigemptyset(&sigterm);
|
||||||
|
sigaddset(&sigterm, SIGTERM);
|
||||||
|
sigprocmask(SIG_BLOCK, &sigterm, NULL);
|
||||||
|
struct sigaction sa = { .sa_handler = on_interrupt_signal }, old_sa;
|
||||||
|
forward_sigterm_to = child_pid;
|
||||||
|
sigaction(SIGTERM, &sa, &old_sa);
|
||||||
|
sigprocmask(SIG_UNBLOCK, &sigterm, NULL);
|
||||||
|
|
||||||
int errnum;
|
int errnum;
|
||||||
if ( readall(pipe_fds[0], &errnum, sizeof(errnum)) < (ssize_t) sizeof(errnum) )
|
if ( readall(pipe_fds[0], &errnum, sizeof(errnum)) < (ssize_t) sizeof(errnum) )
|
||||||
errnum = 0;
|
errnum = 0;
|
||||||
close(pipe_fds[0]);
|
close(pipe_fds[0]);
|
||||||
int child_status;
|
int child_status;
|
||||||
if ( waitpid(child_pid, &child_status, 0) < 0 )
|
while ( waitpid(child_pid, &child_status, 0) < 0 )
|
||||||
|
{
|
||||||
|
if ( errno == EINTR )
|
||||||
|
continue;
|
||||||
errnum = errno;
|
errnum = errno;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
sigprocmask(SIG_BLOCK, &sigterm, NULL);
|
||||||
|
forward_sigterm_to = 0;
|
||||||
|
sigaction(SIGTERM, &old_sa, NULL);
|
||||||
|
|
||||||
tcsetattr(0, TCSAFLUSH, &tio);
|
tcsetattr(0, TCSAFLUSH, &tio);
|
||||||
tcsetpgrp(0, getpgid(0));
|
tcsetpgrp(0, getpgid(0));
|
||||||
sigprocmask(SIG_SETMASK, &oldset, NULL);
|
sigprocmask(SIG_SETMASK, &oldset, NULL);
|
||||||
|
@ -334,7 +389,7 @@ bool parse_username(const char* input,
|
||||||
*session = NULL;
|
*session = NULL;
|
||||||
*action = SPECIAL_ACTION_NONE;
|
*action = SPECIAL_ACTION_NONE;
|
||||||
if ( !strcmp(input, "exit") )
|
if ( !strcmp(input, "exit") )
|
||||||
return *action = SPECIAL_ACTION_POWEROFF, true;
|
return *action = SPECIAL_ACTION_EXIT, true;
|
||||||
else if ( !strcmp(input, "poweroff") )
|
else if ( !strcmp(input, "poweroff") )
|
||||||
return *action = SPECIAL_ACTION_POWEROFF, true;
|
return *action = SPECIAL_ACTION_POWEROFF, true;
|
||||||
else if ( !strcmp(input, "reboot") )
|
else if ( !strcmp(input, "reboot") )
|
||||||
|
@ -376,6 +431,7 @@ void handle_special(enum special_action action)
|
||||||
switch ( action )
|
switch ( action )
|
||||||
{
|
{
|
||||||
case SPECIAL_ACTION_NONE: return;
|
case SPECIAL_ACTION_NONE: return;
|
||||||
|
case SPECIAL_ACTION_EXIT: exit(0);
|
||||||
case SPECIAL_ACTION_POWEROFF: exit(0);
|
case SPECIAL_ACTION_POWEROFF: exit(0);
|
||||||
case SPECIAL_ACTION_REBOOT: exit(1);
|
case SPECIAL_ACTION_REBOOT: exit(1);
|
||||||
case SPECIAL_ACTION_HALT: exit(2);
|
case SPECIAL_ACTION_HALT: exit(2);
|
||||||
|
@ -394,7 +450,7 @@ int textual(void)
|
||||||
char* username = NULL;
|
char* username = NULL;
|
||||||
char* session = NULL;
|
char* session = NULL;
|
||||||
|
|
||||||
while ( true )
|
while ( !got_sigterm )
|
||||||
{
|
{
|
||||||
char hostname[HOST_NAME_MAX + 1];
|
char hostname[HOST_NAME_MAX + 1];
|
||||||
hostname[0] = '\0';
|
hostname[0] = '\0';
|
||||||
|
@ -460,6 +516,9 @@ int textual(void)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( got_sigterm )
|
||||||
|
break;
|
||||||
|
|
||||||
if ( !login(username, session) )
|
if ( !login(username, session) )
|
||||||
{
|
{
|
||||||
warn("logging in as %s", username);
|
warn("logging in as %s", username);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2014, 2015, 2023 Jonas 'Sortie' Termansen.
|
* Copyright (c) 2014, 2015, 2023, 2024 Jonas 'Sortie' Termansen.
|
||||||
* Copyright (c) 2023 dzwdz.
|
* Copyright (c) 2023 dzwdz.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
@ -39,12 +39,14 @@ struct check
|
||||||
enum special_action
|
enum special_action
|
||||||
{
|
{
|
||||||
SPECIAL_ACTION_NONE,
|
SPECIAL_ACTION_NONE,
|
||||||
|
SPECIAL_ACTION_EXIT,
|
||||||
SPECIAL_ACTION_POWEROFF,
|
SPECIAL_ACTION_POWEROFF,
|
||||||
SPECIAL_ACTION_REBOOT,
|
SPECIAL_ACTION_REBOOT,
|
||||||
SPECIAL_ACTION_HALT,
|
SPECIAL_ACTION_HALT,
|
||||||
SPECIAL_ACTION_REINIT,
|
SPECIAL_ACTION_REINIT,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void on_interrupt_signal(int signum);
|
||||||
bool login(const char* username, const char* session);
|
bool login(const char* username, const char* session);
|
||||||
bool check_real(const char* username, const char* password);
|
bool check_real(const char* username, const char* password);
|
||||||
bool check_begin(struct check* chk,
|
bool check_begin(struct check* chk,
|
||||||
|
@ -62,4 +64,7 @@ bool parse_username(const char* input,
|
||||||
enum special_action* action);
|
enum special_action* action);
|
||||||
void handle_special(enum special_action action);
|
void handle_special(enum special_action action);
|
||||||
|
|
||||||
|
extern pid_t forward_sigterm_to;
|
||||||
|
extern volatile sig_atomic_t got_sigterm;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue