← Back to davo.co
aboutsummaryrefslogtreecommitdiffstats
path: root/sighandler.c
diff options
context:
space:
mode:
Diffstat (limited to 'sighandler.c')
-rw-r--r--sighandler.c99
1 files changed, 99 insertions, 0 deletions
diff --git a/sighandler.c b/sighandler.c
new file mode 100644
index 0000000..bb8fd11
--- /dev/null
+++ b/sighandler.c
@@ -0,0 +1,99 @@
+#include <signal.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include "sighandler.h"
+
+#define SH_PAIR(X, D) [X] = { .name = #X, .desc = "" D "", }
+
+sh_pair const sh_pairs[] = {
+ /* Execution errors */
+ SH_PAIR(SIGFPE, "erroneous arithmetic operation"),
+ SH_PAIR(SIGILL, "invalid instruction"),
+ SH_PAIR(SIGSEGV, "invalid access to storage"),
+#ifdef SIGBUS
+ SH_PAIR(SIGBUS, "bad address"),
+#endif
+ /* Job control */
+ SH_PAIR(SIGABRT, "abnormal termination"),
+ SH_PAIR(SIGINT, "interactive attention signal"),
+ SH_PAIR(SIGTERM, "termination request"),
+#ifdef SIGKILL
+ SH_PAIR(SIGKILL, "kill signal"),
+#endif
+#ifdef SIGQUIT
+ SH_PAIR(SIGQUIT, "keyboard quit"),
+#endif
+#ifdef SIGSTOP
+ SH_PAIR(SIGSTOP, "stop process"),
+#endif
+#ifdef SIGCONT
+ SH_PAIR(SIGCONT, "continue if stopped"),
+#endif
+#ifdef SIGINFO
+ SH_PAIR(SIGINFO, "status information request"),
+#endif
+};
+
+size_t const sh_known = (sizeof sh_pairs/sizeof sh_pairs[0]);
+
+#if ATOMIC_LONG_LOCK_FREE > 1
+_Atomic(unsigned long) sh_counts[sizeof sh_pairs/sizeof sh_pairs[0]];
+# define SH_COU " (%lu times),"
+#else
+# define SH_COU "%0.0lu,"
+#endif
+
+void sh_count(int);
+unsigned long sh_counted(int);
+
+#define SH_HEAD "\r%s:%zu: "
+#define SH_DOC "\t%s,\t%s"
+
+
+void sh_print(FILE* io, int sig,
+ char const* filename, size_t line,
+ char const* string) {
+ char const* doc =
+ (sig < sh_known && sh_pairs[sig].name)
+ ? sh_pairs[sig].desc
+ : "unknown signal number";
+ if (errno) {
+ char const* err = strerror(errno);
+ errno = 0;
+ if (!sig)
+ fprintf(io, SH_HEAD "\t%s:\t%s\n", filename, line,
+ string, err);
+ else if (sig < sh_known && sh_pairs[sig].name)
+ fprintf(io, SH_HEAD "%s" SH_COU SH_DOC ":\t%s\n", filename, line,
+ sh_pairs[sig].name, sh_counted(sig), doc, string, err);
+ else
+ fprintf(io, SH_HEAD "#%d" SH_COU SH_DOC ":\t%s\n", filename, line,
+ sig, sh_counted(sig), doc, string, err);
+ } else {
+ if (!sig)
+ fprintf(io, SH_HEAD "\t%s\n", filename, line,
+ string);
+ else if (sig < sh_known && sh_pairs[sig].name)
+ fprintf(io, SH_HEAD "%s" SH_COU SH_DOC "\n", filename, line,
+ sh_pairs[sig].name, sh_counted(sig), doc, string);
+ else
+ fprintf(io, SH_HEAD "#%d" SH_COU SH_DOC "\n", filename, line,
+ sig, sh_counted(sig), doc, string);
+ }
+}
+
+sh_handler* sh_enable(int sig, sh_handler* hnd) {
+ sh_handler* ret = signal(sig, hnd);
+ if (ret == SIG_ERR) {
+ SH_PRINT(stderr, sig, "failed");
+ errno = 0;
+ } else if (ret == SIG_IGN) {
+ SH_PRINT(stderr, sig, "previously ignored");
+ } else if (ret && ret != SIG_DFL) {
+ SH_PRINT(stderr, sig, "previously set otherwise");
+ } else {
+ SH_PRINT(stderr, sig, "ok");
+ }
+ return ret;
+}