Blob


1 /*
2 * Signal handling for Plan 9 programs.
3 * We stubbornly use the strings from Plan 9 instead
4 * of the enumerated Unix constants.
5 * There are some weird translations. In particular,
6 * a "kill" note is the same as SIGTERM in Unix.
7 * There is no equivalent note to Unix's SIGKILL, since
8 * it's not a deliverable signal anyway.
9 *
10 * We do not handle SIGABRT or SIGSEGV, mainly because
11 * the thread library queues its notes for later, and we want
12 * to dump core with the state at time of delivery.
13 *
14 * We have to add some extra entry points to provide the
15 * ability to tweak which signals are deliverable and which
16 * are acted upon. Notifydisable and notifyenable play with
17 * the process signal mask. Notifyignore enables the signal
18 * but will not call notifyf when it comes in. This is occasionally
19 * useful.
20 */
22 #include <u.h>
23 #include <signal.h>
24 #define NOPLAN9DEFINES
25 #include <libc.h>
27 extern char *_p9sigstr(int, char*);
28 extern int _p9strsig(char*);
30 typedef struct Sig Sig;
31 struct Sig
32 {
33 int sig; /* signal number */
34 int restart; /* do we restart the system call after this signal is handled? */
35 int enabled; /* is this signal enabled (not masked)? */
36 int notified; /* do we call the notify function for this signal? */
37 };
39 /*
40 * Bug. It is profoundly anti-social to play with the masks like this.
41 * For example, even though we don't want to see SIGTSTP, others do.
42 * Running bash inside a 9term that has disabled SIGTSTP makes ^Z not work.
43 * Instead we need to leave the signals enabled but notifyoff them.
44 */
46 /* initial settings; for current status, ask the kernel */
47 static Sig sigs[] = {
48 SIGHUP, 0, 1, 1,
49 SIGINT, 0, 1, 1,
50 SIGQUIT, 0, 1, 1,
51 SIGILL, 0, 1, 1,
52 SIGTRAP, 0, 1, 1,
53 /* SIGABRT, 0, 1, 1, */
54 #ifdef SIGEMT
55 SIGEMT, 0, 1, 1,
56 #endif
57 SIGFPE, 0, 1, 1,
58 SIGBUS, 0, 1, 1,
59 /* SIGSEGV, 0, 1, 1, */
60 SIGCHLD, 1, 0, 1,
61 SIGSYS, 0, 1, 1,
62 SIGPIPE, 0, 0, 1,
63 SIGALRM, 0, 1, 1,
64 SIGTERM, 0, 1, 1,
65 SIGTSTP, 1, 0, 1,
66 SIGTTIN, 1, 0, 1,
67 SIGTTOU, 1, 0, 1,
68 SIGXCPU, 0, 1, 1,
69 SIGXFSZ, 0, 1, 1,
70 SIGVTALRM, 0, 1, 1,
71 SIGUSR1, 0, 1, 1,
72 SIGUSR2, 0, 1, 1,
73 SIGWINCH, 1, 0, 1,
74 #ifdef SIGINFO
75 SIGINFO, 1, 1, 1,
76 #endif
77 };
79 static Sig*
80 findsig(int s)
81 {
82 int i;
84 for(i=0; i<nelem(sigs); i++)
85 if(sigs[i].sig == s)
86 return &sigs[i];
87 return nil;
88 }
90 /*
91 * The thread library initializes _notejmpbuf to its own
92 * routine which provides a per-pthread jump buffer.
93 * If we're not using the thread library, we assume we are
94 * single-threaded.
95 */
96 typedef struct Jmp Jmp;
97 struct Jmp
98 {
99 p9jmp_buf b;
100 };
102 static Jmp onejmp;
104 static Jmp*
105 getonejmp(void)
107 return &onejmp;
110 Jmp *(*_notejmpbuf)(void) = getonejmp;
111 static void noteinit(void);
113 /*
114 * Actual signal handler.
115 */
117 static void (*notifyf)(void*, char*); /* Plan 9 handler */
119 static void
120 signotify(int sig)
122 char tmp[64];
123 Jmp *j;
125 j = (*_notejmpbuf)();
126 switch(p9setjmp(j->b)){
127 case 0:
128 if(notifyf)
129 (*notifyf)(nil, _p9sigstr(sig, tmp));
130 /* fall through */
131 case 1: /* noted(NDFLT) */
132 if(0)print("DEFAULT %d\n", sig);
133 signal(sig, SIG_DFL);
134 raise(sig);
135 _exit(1);
136 case 2: /* noted(NCONT) */
137 if(0)print("HANDLED %d\n", sig);
138 return;
142 static void
143 signonotify(int sig)
145 USED(sig);
148 int
149 noted(int v)
151 p9longjmp((*_notejmpbuf)()->b, v==NCONT ? 2 : 1);
152 abort();
153 return 0;
156 int
157 notify(void (*f)(void*, char*))
159 static int init;
161 notifyf = f;
162 if(!init){
163 init = 1;
164 noteinit();
166 return 0;
169 /*
170 * Nonsense about enabling and disabling signals.
171 */
172 typedef void Sighandler(int);
173 static Sighandler*
174 handler(int s)
176 struct sigaction sa;
178 sigaction(s, nil, &sa);
179 return sa.sa_handler;
182 static int
183 notesetenable(int sig, int enabled)
185 sigset_t mask, omask;
187 if(sig == 0)
188 return -1;
190 sigemptyset(&mask);
191 sigaddset(&mask, sig);
192 sigprocmask(enabled ? SIG_UNBLOCK : SIG_BLOCK, &mask, &omask);
193 return !sigismember(&omask, sig);
196 int
197 noteenable(char *msg)
199 return notesetenable(_p9strsig(msg), 1);
202 int
203 notedisable(char *msg)
205 return notesetenable(_p9strsig(msg), 0);
208 static int
209 notifyseton(int s, int on)
211 Sig *sig;
212 struct sigaction sa, osa;
214 sig = findsig(s);
215 if(sig == nil)
216 return -1;
217 memset(&sa, 0, sizeof sa);
218 sa.sa_handler = on ? signotify : signonotify;
219 if(sig->restart)
220 sa.sa_flags |= SA_RESTART;
222 /*
223 * We can't allow signals within signals because there's
224 * only one jump buffer.
225 */
226 sigfillset(&sa.sa_mask);
228 /*
229 * Install handler.
230 */
231 sigaction(sig->sig, &sa, &osa);
232 return osa.sa_handler == signotify;
235 int
236 notifyon(char *msg)
238 return notifyseton(_p9strsig(msg), 1);
241 int
242 notifyoff(char *msg)
244 return notifyseton(_p9strsig(msg), 0);
247 /*
248 * Initialization follows sigs table.
249 */
250 static void
251 noteinit(void)
253 int i;
254 Sig *sig;
256 for(i=0; i<nelem(sigs); i++){
257 sig = &sigs[i];
258 /*
259 * If someone has already installed a handler,
260 * It's probably some ld preload nonsense,
261 * like pct (a SIGVTALRM-based profiler).
262 * Or maybe someone has already called notifyon/notifyoff.
263 * Leave it alone.
264 */
265 if(handler(sig->sig) != SIG_DFL)
266 continue;
267 /*
268 * Should we only disable and not enable signals?
269 * (I.e. if parent has disabled for us, should we still enable?)
270 * Right now we always initialize to the state we want.
271 */
272 notesetenable(sig->sig, sig->enabled);
273 notifyseton(sig->sig, sig->notified);