← Back to davo.co
aboutsummaryrefslogtreecommitdiffstats
path: root/sighandler.c
blob: bb8fd11ed5ce3b7795d879d67913dd27699c61c1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
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;
}