mirror of
https://github.com/Kicksecure/security-misc.git
synced 2025-11-26 11:46:25 -05:00
Add panic key handling to emergency shutdown utility
This commit is contained in:
parent
2a7071055f
commit
dfb6f143f0
1 changed files with 529 additions and 101 deletions
|
|
@ -74,6 +74,13 @@
|
|||
* (there are other similar posts as well).
|
||||
*/
|
||||
|
||||
/*
|
||||
* TODO: Consider handling signals more gracefully (perhaps use ppoll instead
|
||||
* of poll, handle things like EINTR, etc.). Right now the plan is to simply
|
||||
* terminate when a signal is received and let systemd restart the process,
|
||||
* but it might be better to just be signal-resilient.
|
||||
*/
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/reboot.h>
|
||||
#include <unistd.h>
|
||||
|
|
@ -83,11 +90,183 @@
|
|||
#include <stdbool.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <poll.h>
|
||||
#include <linux/input.h>
|
||||
|
||||
#define fd_stdin 0
|
||||
#define fd_stdout 1
|
||||
#define fd_stderr 2
|
||||
|
||||
#define max_inputs 255
|
||||
#define input_path_size 20
|
||||
#define key_flags_len 12
|
||||
|
||||
/* Adapted from kloak/src/keycodes.c */
|
||||
struct name_value {
|
||||
const char *name;
|
||||
const int value;
|
||||
};
|
||||
static struct name_value key_table[] = {
|
||||
{"KEY_ESC", KEY_ESC},
|
||||
{"KEY_1", KEY_1},
|
||||
{"KEY_2", KEY_2},
|
||||
{"KEY_3", KEY_3},
|
||||
{"KEY_4", KEY_4},
|
||||
{"KEY_5", KEY_5},
|
||||
{"KEY_6", KEY_6},
|
||||
{"KEY_7", KEY_7},
|
||||
{"KEY_8", KEY_8},
|
||||
{"KEY_9", KEY_9},
|
||||
{"KEY_0", KEY_0},
|
||||
{"KEY_MINUS", KEY_MINUS},
|
||||
{"KEY_EQUAL", KEY_EQUAL},
|
||||
{"KEY_BACKSPACE", KEY_BACKSPACE},
|
||||
{"KEY_TAB", KEY_TAB},
|
||||
{"KEY_Q", KEY_Q},
|
||||
{"KEY_W", KEY_W},
|
||||
{"KEY_E", KEY_E},
|
||||
{"KEY_R", KEY_R},
|
||||
{"KEY_T", KEY_T},
|
||||
{"KEY_Y", KEY_Y},
|
||||
{"KEY_U", KEY_U},
|
||||
{"KEY_I", KEY_I},
|
||||
{"KEY_O", KEY_O},
|
||||
{"KEY_P", KEY_P},
|
||||
{"KEY_LEFTBRACE", KEY_LEFTBRACE},
|
||||
{"KEY_RIGHTBRACE", KEY_RIGHTBRACE},
|
||||
{"KEY_ENTER", KEY_ENTER},
|
||||
{"KEY_LEFTCTRL", KEY_LEFTCTRL},
|
||||
{"KEY_A", KEY_A},
|
||||
{"KEY_S", KEY_S},
|
||||
{"KEY_D", KEY_D},
|
||||
{"KEY_F", KEY_F},
|
||||
{"KEY_G", KEY_G},
|
||||
{"KEY_H", KEY_H},
|
||||
{"KEY_J", KEY_J},
|
||||
{"KEY_K", KEY_K},
|
||||
{"KEY_L", KEY_L},
|
||||
{"KEY_SEMICOLON", KEY_SEMICOLON},
|
||||
{"KEY_APOSTROPHE", KEY_APOSTROPHE},
|
||||
{"KEY_GRAVE", KEY_GRAVE},
|
||||
{"KEY_LEFTSHIFT", KEY_LEFTSHIFT},
|
||||
{"KEY_BACKSLASH", KEY_BACKSLASH},
|
||||
{"KEY_Z", KEY_Z},
|
||||
{"KEY_X", KEY_X},
|
||||
{"KEY_C", KEY_C},
|
||||
{"KEY_V", KEY_V},
|
||||
{"KEY_B", KEY_B},
|
||||
{"KEY_N", KEY_N},
|
||||
{"KEY_M", KEY_M},
|
||||
{"KEY_COMMA", KEY_COMMA},
|
||||
{"KEY_DOT", KEY_DOT},
|
||||
{"KEY_SLASH", KEY_SLASH},
|
||||
{"KEY_RIGHTSHIFT", KEY_RIGHTSHIFT},
|
||||
{"KEY_KPASTERISK", KEY_KPASTERISK},
|
||||
{"KEY_LEFTALT", KEY_LEFTALT},
|
||||
{"KEY_SPACE", KEY_SPACE},
|
||||
{"KEY_CAPSLOCK", KEY_CAPSLOCK},
|
||||
{"KEY_F1", KEY_F1},
|
||||
{"KEY_F2", KEY_F2},
|
||||
{"KEY_F3", KEY_F3},
|
||||
{"KEY_F4", KEY_F4},
|
||||
{"KEY_F5", KEY_F5},
|
||||
{"KEY_F6", KEY_F6},
|
||||
{"KEY_F7", KEY_F7},
|
||||
{"KEY_F8", KEY_F8},
|
||||
{"KEY_F9", KEY_F9},
|
||||
{"KEY_F10", KEY_F10},
|
||||
{"KEY_NUMLOCK", KEY_NUMLOCK},
|
||||
{"KEY_SCROLLLOCK", KEY_SCROLLLOCK},
|
||||
{"KEY_KP7", KEY_KP7},
|
||||
{"KEY_KP8", KEY_KP8},
|
||||
{"KEY_KP9", KEY_KP9},
|
||||
{"KEY_KPMINUS", KEY_KPMINUS},
|
||||
{"KEY_KP4", KEY_KP4},
|
||||
{"KEY_KP5", KEY_KP5},
|
||||
{"KEY_KP6", KEY_KP6},
|
||||
{"KEY_KPPLUS", KEY_KPPLUS},
|
||||
{"KEY_KP1", KEY_KP1},
|
||||
{"KEY_KP2", KEY_KP2},
|
||||
{"KEY_KP3", KEY_KP3},
|
||||
{"KEY_KP0", KEY_KP0},
|
||||
{"KEY_KPDOT", KEY_KPDOT},
|
||||
{"KEY_ZENKAKUHANKAKU", KEY_ZENKAKUHANKAKU},
|
||||
{"KEY_102ND", KEY_102ND},
|
||||
{"KEY_F11", KEY_F11},
|
||||
{"KEY_F12", KEY_F12},
|
||||
{"KEY_RO", KEY_RO},
|
||||
{"KEY_KATAKANA", KEY_KATAKANA},
|
||||
{"KEY_HIRAGANA", KEY_HIRAGANA},
|
||||
{"KEY_HENKAN", KEY_HENKAN},
|
||||
{"KEY_KATAKANAHIRAGANA", KEY_KATAKANAHIRAGANA},
|
||||
{"KEY_MUHENKAN", KEY_MUHENKAN},
|
||||
{"KEY_KPJPCOMMA", KEY_KPJPCOMMA},
|
||||
{"KEY_KPENTER", KEY_KPENTER},
|
||||
{"KEY_RIGHTCTRL", KEY_RIGHTCTRL},
|
||||
{"KEY_KPSLASH", KEY_KPSLASH},
|
||||
{"KEY_SYSRQ", KEY_SYSRQ},
|
||||
{"KEY_RIGHTALT", KEY_RIGHTALT},
|
||||
{"KEY_LINEFEED", KEY_LINEFEED},
|
||||
{"KEY_HOME", KEY_HOME},
|
||||
{"KEY_UP", KEY_UP},
|
||||
{"KEY_PAGEUP", KEY_PAGEUP},
|
||||
{"KEY_LEFT", KEY_LEFT},
|
||||
{"KEY_RIGHT", KEY_RIGHT},
|
||||
{"KEY_END", KEY_END},
|
||||
{"KEY_DOWN", KEY_DOWN},
|
||||
{"KEY_PAGEDOWN", KEY_PAGEDOWN},
|
||||
{"KEY_INSERT", KEY_INSERT},
|
||||
{"KEY_DELETE", KEY_DELETE},
|
||||
{"KEY_MACRO", KEY_MACRO},
|
||||
{"KEY_MUTE", KEY_MUTE},
|
||||
{"KEY_VOLUMEDOWN", KEY_VOLUMEDOWN},
|
||||
{"KEY_VOLUMEUP", KEY_VOLUMEUP},
|
||||
{"KEY_POWER", KEY_POWER},
|
||||
{"KEY_POWER2", KEY_POWER2},
|
||||
{"KEY_KPEQUAL", KEY_KPEQUAL},
|
||||
{"KEY_KPPLUSMINUS", KEY_KPPLUSMINUS},
|
||||
{"KEY_PAUSE", KEY_PAUSE},
|
||||
{"KEY_SCALE", KEY_SCALE},
|
||||
{"KEY_KPCOMMA", KEY_KPCOMMA},
|
||||
{"KEY_HANGEUL", KEY_HANGEUL},
|
||||
{"KEY_HANGUEL", KEY_HANGUEL},
|
||||
{"KEY_HANJA", KEY_HANJA},
|
||||
{"KEY_YEN", KEY_YEN},
|
||||
{"KEY_LEFTMETA", KEY_LEFTMETA},
|
||||
{"KEY_RIGHTMETA", KEY_RIGHTMETA},
|
||||
{"KEY_COMPOSE", KEY_COMPOSE},
|
||||
{"KEY_F13", KEY_F13},
|
||||
{"KEY_F14", KEY_F14},
|
||||
{"KEY_F15", KEY_F15},
|
||||
{"KEY_F16", KEY_F16},
|
||||
{"KEY_F17", KEY_F17},
|
||||
{"KEY_F18", KEY_F18},
|
||||
{"KEY_F19", KEY_F19},
|
||||
{"KEY_F20", KEY_F20},
|
||||
{"KEY_F21", KEY_F21},
|
||||
{"KEY_F22", KEY_F22},
|
||||
{"KEY_F23", KEY_F23},
|
||||
{"KEY_F24", KEY_F24},
|
||||
{"KEY_UNKNOWN", KEY_UNKNOWN},
|
||||
{NULL, 0}
|
||||
};
|
||||
int lookup_keycode(const char *name) {
|
||||
struct name_value *p;
|
||||
for (p = key_table; p->name != NULL; ++p) {
|
||||
if (strcmp(p->name, name) == 0) {
|
||||
return p->value;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Adapted from systemd/src/login/logind-button.c */
|
||||
bool bitset_get(const uint64_t *bits, uint32_t i) {
|
||||
return (bits[i / 64] >> (i % 64)) & 1UL;
|
||||
}
|
||||
|
||||
void print(int fd, char *str) {
|
||||
size_t len = strlen(str) + 1;
|
||||
while (true) {
|
||||
|
|
@ -102,35 +281,151 @@ void print(int fd, char *str) {
|
|||
|
||||
void print_usage() {
|
||||
print(fd_stderr, "Usage:\n");
|
||||
print(fd_stderr, " force-shutdown-when-device-removed DEVICE1 [DEVICE2...]\n");
|
||||
print(fd_stderr, " emerg-shutdown --devices=DEVICE1[,DEVICE2...] --keys=KEY_1[,KEY_2...]\n");
|
||||
print(fd_stderr, "Example:\n");
|
||||
print(fd_stderr, " force-shutdown-when-device-removed /dev/sda3\n");
|
||||
print(fd_stderr, " emerg-shutdown --devices=/dev/sda3 --keys=KEY_POWER\n");
|
||||
}
|
||||
|
||||
void *safe_calloc(size_t nmemb, size_t size) {
|
||||
void *ret_buf = calloc(nmemb, size);
|
||||
if (ret_buf == NULL) {
|
||||
print(fd_stderr, "Out of memory!\n");
|
||||
exit(1);
|
||||
}
|
||||
return ret_buf;
|
||||
}
|
||||
|
||||
void *safe_reallocarray(void *ptr, size_t nmemb, size_t size) {
|
||||
void *ret_buf = reallocarray(ptr, nmemb, size);
|
||||
if (ret_buf == NULL) {
|
||||
print(fd_stderr, "Out of memory!\n");
|
||||
exit(1);
|
||||
}
|
||||
return ret_buf;
|
||||
}
|
||||
|
||||
/* Inspired by https://www.strudel.org.uk/itoa/ */
|
||||
char *int_to_str(uint32_t val) {
|
||||
static char buf[11];
|
||||
int8_t i;
|
||||
char *rslt = NULL;
|
||||
const char *digits = "0123456789";
|
||||
|
||||
buf[10] = '\0';
|
||||
|
||||
for (i = 9; i >= 0; i--) {
|
||||
buf[i] = digits[val % 10];
|
||||
val /= 10;
|
||||
if (val == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
rslt = safe_calloc(1, 11 - i);
|
||||
memcpy(rslt, buf + i, 11 - i);
|
||||
return rslt;
|
||||
}
|
||||
|
||||
void load_list(const char *arg, size_t *result_list_len_ref, char ***result_list_ref) {
|
||||
char **result_list = NULL;
|
||||
size_t result_list_len = 0;
|
||||
int arg_copy_len = strlen(arg) + 1;
|
||||
char *arg_copy = safe_calloc(1, arg_copy_len);
|
||||
char *arg_val;
|
||||
char *arg_part;
|
||||
|
||||
memcpy(arg_copy, arg, arg_copy_len);
|
||||
/* returns "--whatever" */
|
||||
arg_val = strtok(arg_copy, "=");
|
||||
/* returns everything after the = sign */
|
||||
arg_val = strtok(NULL, "");
|
||||
|
||||
arg_part = strtok(arg_val, ",");
|
||||
if (arg_part == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
result_list_len++;
|
||||
result_list = safe_reallocarray(result_list, result_list_len, sizeof(char *));
|
||||
result_list[result_list_len - 1] = safe_calloc(1, strlen(arg_part) + 1);
|
||||
strcpy(result_list[result_list_len - 1], arg_part);
|
||||
} while ((arg_part = strtok(NULL, ",")) != NULL);
|
||||
|
||||
*result_list_len_ref = result_list_len;
|
||||
*result_list_ref = result_list;
|
||||
free(arg_copy);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
/* Working variables */
|
||||
size_t target_dev_list_len = 0;
|
||||
char **target_dev_name_raw_list = NULL;
|
||||
size_t panic_key_list_len = 0;
|
||||
char **panic_key_str_list = NULL;
|
||||
char **target_dev_list = NULL;
|
||||
int *panic_key_list = NULL;
|
||||
bool *panic_key_active_list = NULL;
|
||||
size_t event_fd_list_len = 0;
|
||||
int *event_fd_list = NULL;
|
||||
char input_path_buf[input_path_size];
|
||||
struct pollfd *pollfd_list = NULL;
|
||||
struct input_event ie_buf[64];
|
||||
|
||||
/* Index variables */
|
||||
int arg_idx = 0;
|
||||
size_t tdl_idx = 0;
|
||||
size_t tdp_char_idx = 0;
|
||||
size_t pkl_idx = 0;
|
||||
int input_idx = 0;
|
||||
size_t efl_idx = 0;
|
||||
int ie_idx = 0;
|
||||
|
||||
/* Prerequisite check */
|
||||
if (getuid() != 0) {
|
||||
print(fd_stderr, "This program must be run as root!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Argument parsing */
|
||||
if (argc < 2) {
|
||||
print(fd_stderr, "Invalid number of arguments!\n");
|
||||
print_usage();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
size_t target_dev_name_list_len = argc - 1;
|
||||
char **target_dev_name_list = calloc(target_dev_name_list_len,
|
||||
sizeof(char *));
|
||||
if (target_dev_name_list == NULL) {
|
||||
print(fd_stderr, "Out of memory during early setup!\n");
|
||||
for (arg_idx = 1; arg_idx < argc; arg_idx++) {
|
||||
if (strncmp(argv[arg_idx], "--devices=", strlen("--devices=")) == 0) {
|
||||
if (target_dev_name_raw_list != NULL) {
|
||||
print(fd_stderr, "--devices cannot be passed more than once!\n");
|
||||
print_usage();
|
||||
exit(1);
|
||||
}
|
||||
load_list(argv[arg_idx], &target_dev_list_len, &target_dev_name_raw_list);
|
||||
} else if (strncmp(argv[arg_idx], "--keys=", strlen("--keys=")) == 0) {
|
||||
if (panic_key_str_list != NULL) {
|
||||
print(fd_stderr, "--keys cannot be passed more than once!\n");
|
||||
print_usage();
|
||||
exit(1);
|
||||
}
|
||||
load_list(argv[arg_idx], &panic_key_list_len, &panic_key_str_list);
|
||||
}
|
||||
}
|
||||
|
||||
target_dev_list = safe_calloc(target_dev_list_len, sizeof(char *));
|
||||
panic_key_list = safe_calloc(panic_key_list_len, sizeof(int));
|
||||
panic_key_active_list = safe_calloc(panic_key_list_len, sizeof(bool));
|
||||
|
||||
for (tdl_idx = 0; tdl_idx < target_dev_list_len; tdl_idx++) {
|
||||
char *target_dev_path = target_dev_name_raw_list[tdl_idx];
|
||||
size_t device_path_slash_count = 0;
|
||||
char *target_dev_parse = safe_calloc(1, strlen(target_dev_path) + 1);
|
||||
char *target_dev_name = NULL;
|
||||
|
||||
for (int i = 1; i < argc; i++) {
|
||||
char *target_dev_path = argv[i];
|
||||
if (access(target_dev_path, F_OK) != 0) {
|
||||
print(fd_stderr, "One of the specified devices does not exist!\n");
|
||||
print(fd_stderr, "The device '");
|
||||
print(fd_stderr, target_dev_path);
|
||||
print(fd_stderr, "' does not exist!\n");
|
||||
print_usage();
|
||||
exit(1);
|
||||
}
|
||||
|
|
@ -142,46 +437,58 @@ int main(int argc, char **argv) {
|
|||
&& strncmp(target_dev_path, "/dev/vd", strlen("/dev/vd")) != 0
|
||||
&& strncmp(target_dev_path, "/dev/xvd", strlen("/dev/xvd")) != 0
|
||||
&& strncmp(target_dev_path, "/dev/hd", strlen("/dev/hd")) != 0) {
|
||||
print(fd_stderr, "One of the specified devices is not supported!\n");
|
||||
print(fd_stderr, "The device '");
|
||||
print(fd_stderr, target_dev_path);
|
||||
print(fd_stderr, "' is not supported!\n");
|
||||
print_usage();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
size_t device_path_slash_count = 0;
|
||||
for (size_t j = 0; j < strlen(target_dev_path); j++) {
|
||||
if (target_dev_path[j] == '/') {
|
||||
for (tdp_char_idx = 0; tdp_char_idx < strlen(target_dev_path); tdp_char_idx++) {
|
||||
if (target_dev_path[tdp_char_idx] == '/') {
|
||||
device_path_slash_count++;
|
||||
}
|
||||
}
|
||||
if (device_path_slash_count != 2) {
|
||||
print(fd_stderr, "One of the specified devices is not supported!\n");
|
||||
print(fd_stderr, "The device '");
|
||||
print(fd_stderr, target_dev_path);
|
||||
print(fd_stderr, "' is not supported!\n");
|
||||
print_usage();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
char *target_dev_parse = calloc(1, strlen(target_dev_path) + 1);
|
||||
if (target_dev_parse == NULL) {
|
||||
print(fd_stderr, "Out of memory during early setup!\n");
|
||||
exit(1);
|
||||
}
|
||||
memcpy(target_dev_parse, target_dev_path, strlen(target_dev_path) + 1);
|
||||
|
||||
/* returns "dev" */
|
||||
char *target_dev_name = strtok(target_dev_parse, "/");
|
||||
target_dev_name = strtok(target_dev_parse, "/");
|
||||
/* returns the actual device name we want */
|
||||
target_dev_name = strtok(NULL, "/");
|
||||
if (target_dev_name == NULL) {
|
||||
print(fd_stderr, "One of the specified devices is not supported!\n");
|
||||
print(fd_stderr, "The device '");
|
||||
print(fd_stderr, target_dev_path);
|
||||
print(fd_stderr, "' is not supported!\n");
|
||||
print_usage();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
target_dev_name_list[i - 1] = calloc(1, strlen(target_dev_name) + 1);
|
||||
memcpy(target_dev_name_list[i - 1], target_dev_name,
|
||||
strlen(target_dev_name) + 1);
|
||||
target_dev_list[tdl_idx] = calloc(1, strlen(target_dev_name) + 1);
|
||||
memcpy(target_dev_list[tdl_idx], target_dev_name, strlen(target_dev_name) + 1);
|
||||
free(target_dev_parse);
|
||||
}
|
||||
|
||||
for (pkl_idx = 0; pkl_idx < panic_key_list_len; pkl_idx++) {
|
||||
int keycode = lookup_keycode(panic_key_str_list[pkl_idx]);
|
||||
if (keycode < 0) {
|
||||
print(fd_stderr, "Invalid key code '");
|
||||
print(fd_stderr, panic_key_str_list[pkl_idx]);
|
||||
print(fd_stderr, "'!\n");
|
||||
print_usage();
|
||||
exit(1);
|
||||
}
|
||||
panic_key_list[pkl_idx] = keycode;
|
||||
}
|
||||
|
||||
/* Device event listener setup */
|
||||
struct sockaddr_nl sa = {
|
||||
.nl_family = AF_NETLINK,
|
||||
.nl_pad = 0,
|
||||
|
|
@ -199,7 +506,122 @@ int main(int argc, char **argv) {
|
|||
exit(1);
|
||||
}
|
||||
|
||||
while (true) {
|
||||
/* Keyboard event listener setup
|
||||
* Heavily inspired by systemd/src/login/logind-button.c and
|
||||
* kloak/src/main.c */
|
||||
for (input_idx = 0; input_idx <= max_inputs; input_idx++) {
|
||||
int tmp_fd = 0;
|
||||
uint64_t key_flags[key_flags_len];
|
||||
bool supports_panic = true;
|
||||
char *loop_str = NULL;
|
||||
|
||||
strcpy(input_path_buf, "/dev/input/event");
|
||||
loop_str = int_to_str(input_idx);
|
||||
strcat(input_path_buf, loop_str);
|
||||
free(loop_str);
|
||||
|
||||
tmp_fd = open(input_path_buf, O_RDONLY | O_CLOEXEC | O_NOCTTY | O_NONBLOCK);
|
||||
if (tmp_fd < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ioctl(tmp_fd, EVIOCGBIT(EV_SYN, sizeof(key_flags)), key_flags) < 0) {
|
||||
print(fd_stderr, "Failed to query properties of input device '");
|
||||
print(fd_stderr, input_path_buf);
|
||||
print(fd_stderr, "'!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!bitset_get(key_flags, EV_KEY)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ioctl(tmp_fd, EVIOCGBIT(EV_KEY, sizeof(key_flags)), key_flags) < 0) {
|
||||
print(fd_stderr, "Failed to query keys available on input device '");
|
||||
print(fd_stderr, input_path_buf);
|
||||
print(fd_stderr, "'!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (pkl_idx = 0; pkl_idx < panic_key_list_len; pkl_idx++) {
|
||||
if (!bitset_get(key_flags, panic_key_list[pkl_idx])) {
|
||||
supports_panic = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!supports_panic) {
|
||||
continue;
|
||||
}
|
||||
|
||||
event_fd_list_len++;
|
||||
event_fd_list = safe_reallocarray(event_fd_list, event_fd_list_len, sizeof(int));
|
||||
event_fd_list[event_fd_list_len - 1] = tmp_fd;
|
||||
}
|
||||
|
||||
if (event_fd_list_len == 0) {
|
||||
print(fd_stderr, "Failed to find any input device supporting panic keys!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Poll setup */
|
||||
pollfd_list = safe_calloc(event_fd_list_len + 1, sizeof(struct pollfd));
|
||||
for (efl_idx = 0; efl_idx < event_fd_list_len; efl_idx++) {
|
||||
pollfd_list[efl_idx].fd = event_fd_list[efl_idx];
|
||||
pollfd_list[efl_idx].events = POLLIN;
|
||||
}
|
||||
pollfd_list[event_fd_list_len].fd = ns;
|
||||
pollfd_list[event_fd_list_len].events = POLLIN;
|
||||
|
||||
/* Event loop */
|
||||
while (poll(pollfd_list, event_fd_list_len + 1, -1) != -1) {
|
||||
/* Panic key handler */
|
||||
for (efl_idx = 0; efl_idx < event_fd_list_len; efl_idx++) {
|
||||
if (!(pollfd_list[efl_idx].revents & POLLIN)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
size_t ieread_bytes = read(event_fd_list[efl_idx], ie_buf, sizeof(struct input_event) * 64);
|
||||
|
||||
if (ieread_bytes == -1
|
||||
|| ieread_bytes == 0
|
||||
|| (ieread_bytes % sizeof(struct input_event)) != 0) {
|
||||
/* This will probably terminate the service if the user unplugs a
|
||||
* keyboard or similar, however systemd can start it again. The
|
||||
* alternative is to handle device hotplug, which sounds like a
|
||||
* recipe for bugs. */
|
||||
print(fd_stderr, "Error reading from input device!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (ie_idx = 0; ie_idx < ieread_bytes / sizeof(struct input_event); ie_idx++) {
|
||||
if (ie_buf[ie_idx].type != EV_KEY) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (pkl_idx = 0; pkl_idx < panic_key_list_len; pkl_idx++) {
|
||||
if (ie_buf[ie_idx].code == panic_key_list[pkl_idx]) {
|
||||
if (ie_buf[ie_idx].value == 0) {
|
||||
panic_key_active_list[pkl_idx] = false;
|
||||
} else {
|
||||
panic_key_active_list[pkl_idx] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (pkl_idx = 0; pkl_idx < panic_key_list_len; pkl_idx++) {
|
||||
if (!panic_key_active_list[pkl_idx]) {
|
||||
break;
|
||||
}
|
||||
if (pkl_idx == (panic_key_list_len - 1)) {
|
||||
print(fd_stderr, "SHUTDOWN!!!\n");
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Netlink socket handler */
|
||||
if (pollfd_list[event_fd_list_len].revents & POLLIN) {
|
||||
/*
|
||||
* So, you looked at `man 7 netlink`, then looked at this code, and can't
|
||||
* figure out how on earth any of this makes sense? Well guess what, turns
|
||||
|
|
@ -220,10 +642,13 @@ int main(int argc, char **argv) {
|
|||
struct iovec iov = { buf, sizeof(buf) };
|
||||
struct sockaddr_nl sa2;
|
||||
struct msghdr msg = { &sa2, sizeof(sa2), &iov, 1, NULL, 0, 0 };
|
||||
char *tmpbuf = NULL;
|
||||
bool device_removed = false;
|
||||
|
||||
len = recvmsg(ns, &msg, 0);
|
||||
if (len == -1) {
|
||||
reboot(RB_POWER_OFF);
|
||||
//print(fd_stderr, "SHUTDOWN!!!\n");
|
||||
//reboot(RB_POWER_OFF);
|
||||
print(fd_stderr, "SHUTDOWN!!!\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
|
@ -237,8 +662,7 @@ int main(int argc, char **argv) {
|
|||
continue;
|
||||
}
|
||||
|
||||
char *tmpbuf = buf;
|
||||
bool device_removed = false;
|
||||
tmpbuf = buf;
|
||||
while (len > 0) {
|
||||
if (strcmp(tmpbuf, "ACTION=remove") == 0) {
|
||||
device_removed = true;
|
||||
|
|
@ -247,7 +671,9 @@ int main(int argc, char **argv) {
|
|||
|
||||
if (strncmp(tmpbuf, "DEVNAME=", strlen("DEVNAME=")) == 0) {
|
||||
if (device_removed) {
|
||||
char *rem_devname_line;
|
||||
char *rem_devname_line = NULL;
|
||||
char *rem_dev_name = NULL;
|
||||
|
||||
/*
|
||||
* Try to allocate the memory needed to check DEVNAME in a loop. We
|
||||
* really do not want to simply abort here due to an out of memory
|
||||
|
|
@ -269,17 +695,18 @@ int main(int argc, char **argv) {
|
|||
|
||||
memcpy(rem_devname_line, tmpbuf, strlen(tmpbuf) + 1);
|
||||
/* returns DEVNAME */
|
||||
char *rem_dev_name = strtok(rem_devname_line, "=");
|
||||
rem_dev_name = strtok(rem_devname_line, "=");
|
||||
/* returns the actual device name */
|
||||
rem_dev_name = strtok(NULL, "=");
|
||||
if (rem_dev_name == NULL) {
|
||||
free(rem_devname_line);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int i = 0; i < target_dev_name_list_len; i++) {
|
||||
if (strcmp(rem_dev_name, target_dev_name_list[i]) == 0) {
|
||||
reboot(RB_POWER_OFF);
|
||||
//print(fd_stderr, "SHUTDOWN!!!\n");
|
||||
for (tdl_idx = 0; tdl_idx < target_dev_list_len; tdl_idx++) {
|
||||
if (strcmp(rem_dev_name, target_dev_list[tdl_idx]) == 0) {
|
||||
//reboot(RB_POWER_OFF);
|
||||
print(fd_stderr, "SHUTDOWN!!!\n");
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
|
@ -293,3 +720,4 @@ next_str:
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue