From 8359a7bc484c110552b347f6277d1218198bbec6 Mon Sep 17 00:00:00 2001 From: "B. Watson" Date: Wed, 7 May 2025 01:56:01 -0400 Subject: exit cleanly on both SIGTERM and die(). --- TODO | 12 +++++++----- marsond.8 | 2 +- marsond.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- marsond.rst | 19 +++++++++++++++---- 4 files changed, 79 insertions(+), 12 deletions(-) diff --git a/TODO b/TODO index bb32e1d..22f46c4 100644 --- a/TODO +++ b/TODO @@ -1,9 +1,11 @@ -- actual realtime scheduling (maybe). sched(7). +Definitely: + +Maybe: + +- actual realtime scheduling (maybe). sched(7). not sure it's + needed (nice -20 seems OK even while compiling mame with -j5), and it + might interfere with stuff like JACK. - use a log file instead of stderr, so we can have error/warning messages after detaching from the tty. - print our /dev/input/event* node name, if possible. - options to set the virtual device name and vendor/product IDs. -- possibly use a UNIX socket. if we can connect to it on startup, - that means another instance is already running... so either exit - or pass a command to it (like "marsond -K" would kill an existing - instance). diff --git a/marsond.8 b/marsond.8 index 0bc4835..2a73f93 100644 --- a/marsond.8 +++ b/marsond.8 @@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "MARSOND" 8 "2025-05-06" "0.1.4" "SlackBuilds.org" +.TH "MARSOND" 8 "2025-05-07" "0.1.4" "SlackBuilds.org" .SH NAME marsond \- Fix Enter key timing on Marson/USBLink/MT606-1 PS/2-USB adaptors .SH SYNOPSIS diff --git a/marsond.c b/marsond.c index 9419105..4a3b06a 100644 --- a/marsond.c +++ b/marsond.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -35,6 +36,10 @@ int foreground = 0; /* -v */ const char *keyboard_dev = DEFAULT_KBD; /* -k */ int delay_ms = DEFAULT_DELAY_MS; /* -d */ +int infd = -1, outfd = -1; + +void cleanup(void); + /* variadic macros are apparently C99 and not just a GNU extension */ void logmsg(const char *prefix, const char *fmt, ...) { va_list ap; @@ -45,7 +50,7 @@ void logmsg(const char *prefix, const char *fmt, ...) { fputc('\n', stderr); } -#define die(fmt, ...) { logmsg("fatal", fmt, ##__VA_ARGS__); exit(1); }; +#define die(fmt, ...) { logmsg("fatal", fmt, ##__VA_ARGS__); cleanup(); exit(1); }; #define warn(fmt, ...) { logmsg("warning", fmt, ##__VA_ARGS__); }; #define info(fmt, ...) { logmsg("info", fmt, ##__VA_ARGS__); }; #define debug(fmt, ...) { if(debugging) logmsg("debug", fmt, ##__VA_ARGS__); }; @@ -106,6 +111,53 @@ void parse_args(int argc, char **argv) { if(delay_ms < 1) die("invalid -d argument"); } +/* cleanup() gets called by die() and sighandler() */ +void cleanup(void) { + if(outfd != -1) { + ioctl(outfd, UI_DEV_DESTROY); + close(outfd); + outfd = -1; + } + + if(infd != -1) { + ioctl(infd, EVIOCGRAB, 0); + close(infd); + infd = -1; + } +} + +/* (try to) exit cleanly if we get a SIGTERM. + I say "try" because ioctl() (used by cleanup()) is not listed as + async-signal-safe in signal-safety(7). However, it does seem to + work OK. + If we didn't catch SIGTERM, the result would be that the keyboard + stops working entirely if marsond was started from udev and + manually killed. Cleanly exiting allows the physical keyboard to + keep working (with the Enter key timing issue of course). + */ +void sighandler(int sig, siginfo_t *si, void *) { + if(sig != SIGTERM) { + /* this should never happen! */ + return; + } + + cleanup(); + + exit(0); +} + +void setup_sighandler(void) { + struct sigaction sa; + + sa.sa_flags = SA_SIGINFO; + sigemptyset(&sa.sa_mask); + sa.sa_sigaction = sighandler; + + if(sigaction(SIGTERM, &sa, NULL) < 0) { + warn("can't catch SIGTERM (WTF?)"); + } +} + /* since every keystroke passes through this daemon, we *don't* want it to be swapped out. it would suck if you couldn't type because you were compiling something huge... note that we have to @@ -215,7 +267,7 @@ void set_evbit(int outfd, int event) { } int main(int argc, char **argv) { - int infd, outfd, i; + int i; struct uinput_user_dev dev; struct input_event ev; @@ -280,6 +332,8 @@ int main(int argc, char **argv) { die("UI_DEV_CREATE failed: %s", strerror(errno)); } + setup_sighandler(); + /* this must be done while still running as root... */ if(foreground) { lock_memory(); diff --git a/marsond.rst b/marsond.rst index ee36b42..8f79bf3 100644 --- a/marsond.rst +++ b/marsond.rst @@ -57,10 +57,21 @@ does, with SDL 1 and 2 running under X (and SDL 1 on the console, too). I don't use Wayland, so I haven't tested it there. If you do, please contact me and let me know if it works for you. -**marsond** must be run as root. After grabbing the keyboard -and creating the virtual keyboard device, it will drop -privileges and run as the *nobody* user by default (but -see **ENVIRONMENT** if you need a different user). +**marsond** must be run as root. At startup, it does these +things as root: + +- Grab the physical keyboard. + +- Create the virtual keyboard device. + +- Lock its pages into physical memory, to avoid being swapped out. + +- Set its priority (nice value) to -20 (highest priority), to + avoid slow response on a loaded system. + +After doing the above, root access is no longer needed, so it will +drop privileges and run as the *nobody* user by default (but see +**ENVIRONMENT** if you need a different user). While **marsond** is running, "xinput --list" will show an input device called "marson virtual keyboard". -- cgit v1.2.3