diff options
Diffstat (limited to 'marsond.c')
-rw-r--r-- | marsond.c | 58 |
1 files changed, 56 insertions, 2 deletions
@@ -10,6 +10,7 @@ #include <sys/types.h> #include <pwd.h> #include <grp.h> +#include <signal.h> #include <sys/resource.h> #include <sys/mman.h> @@ -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(); |