No empty .Rs/.Re
[netbsd-mini2440.git] / usr.bin / mail / sig.c
blobb2bd31c68d9b5dd99bd48946ac6ad814ae13e667
1 /* $NetBSD: $ */
3 /*
4 * Copyright (c) 1980, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 #ifndef lint
34 __RCSID("$NetBSD: $");
35 #endif /* not lint */
37 #include <assert.h>
38 #include <util.h>
39 #include <sys/queue.h>
41 #include "rcv.h"
42 #include "extern.h"
43 #include "sig.h"
46 * Mail -- a mail program
48 * Signal routines.
51 static sig_t sigarray[NSIG];
53 typedef struct q_entry_s {
54 int qe_signo;
55 sig_t qe_handler;
56 struct q_entry_s *qe_next;
57 } q_entry_t;
59 static struct {
60 q_entry_t *qe_first;
61 q_entry_t **qe_last;
62 } sigqueue = { NULL, &sigqueue.qe_first };
63 #define SIGQUEUE_INIT(p) do {\
64 (p)->qe_first = NULL;\
65 (p)->qe_last = &((p)->qe_first);\
66 } while (/*CONSTCOND*/ 0)
69 * The routines alloc_entry() and free_entry() manage the queue
70 * elements.
72 * Currently, they just assign one element per signo from a fix array
73 * as we don't support POSIX signal queues. We leave them as this may
74 * change in the future and the modifications will be isolated.
76 static q_entry_t *
77 alloc_entry(int signo)
79 static q_entry_t entries[NSIG];
80 q_entry_t *e;
83 * We currently only post one signal per signal number, so
84 * there is no need to make this complicated.
86 e = &entries[signo];
87 if (e->qe_signo != 0)
88 return NULL;
90 e->qe_signo = signo;
91 e->qe_handler = sigarray[signo];
92 e->qe_next = NULL;
94 return e;
97 static void
98 free_entry(q_entry_t *e)
101 e->qe_signo = 0;
102 e->qe_handler = NULL;
103 e->qe_next = NULL;
107 * Attempt to post a signal to the sigqueue.
109 static void
110 sig_post(int signo)
112 q_entry_t *e;
114 if (sigarray[signo] == SIG_DFL || sigarray[signo] == SIG_IGN)
115 return;
117 e = alloc_entry(signo);
118 if (e != NULL) {
119 *sigqueue.qe_last = e;
120 sigqueue.qe_last = &e->qe_next;
125 * Check the sigqueue for any pending signals. If any are found,
126 * preform the required actions and remove them from the queue.
128 PUBLIC void
129 sig_check(void)
131 q_entry_t *e;
132 sigset_t nset;
133 sigset_t oset;
134 void (*handler)(int);
135 int signo;
137 (void)sigfillset(&nset);
138 (void)sigprocmask(SIG_SETMASK, &nset, &oset);
140 while ((e = sigqueue.qe_first) != NULL) {
141 signo = e->qe_signo;
142 handler = e->qe_handler;
145 * Remove the entry from the queue and free it.
147 sigqueue.qe_first = e->qe_next;
148 if (sigqueue.qe_first == NULL)
149 sigqueue.qe_last = &sigqueue.qe_first;
150 free_entry(e);
152 if (handler == SIG_DFL || handler == SIG_IGN) {
153 assert(/*CONSTCOND*/ 0); /* These should not get posted. */
155 else {
156 (void)sigprocmask(SIG_SETMASK, &oset, NULL);
157 handler(signo);
158 (void)sigprocmask(SIG_SETMASK, &nset, NULL);
161 (void)sigprocmask(SIG_SETMASK, &oset, NULL);
164 PUBLIC sig_t
165 sig_signal(int signo, sig_t handler)
167 sig_t old_handler;
168 sigset_t nset;
169 sigset_t oset;
171 assert(signo > 0 && signo < NSIG);
173 (void)sigemptyset(&nset);
174 (void)sigaddset(&nset, signo);
175 (void)sigprocmask(SIG_BLOCK, &nset, &oset);
177 old_handler = sigarray[signo];
178 sigarray[signo] = handler;
180 (void)sigprocmask(SIG_SETMASK, &oset, NULL);
182 return old_handler;
185 static void
186 do_default_handler(int signo, int flags)
188 struct sigaction nsa;
189 struct sigaction osa;
190 sigset_t nset;
191 sigset_t oset;
192 int save_errno;
194 save_errno = errno;
195 (void)sigemptyset(&nsa.sa_mask);
196 nsa.sa_flags = flags;
197 nsa.sa_handler = SIG_DFL;
198 (void)sigaction(signo, &nsa, &osa);
200 (void)sigemptyset(&nset);
201 (void)sigaddset(&nset, signo);
202 (void)sigprocmask(SIG_UNBLOCK, &nset, &oset);
204 (void)kill(0, signo);
206 (void)sigprocmask(SIG_SETMASK, &oset, NULL);
207 (void)sigaction(signo, &osa, NULL);
208 errno = save_errno;
212 * Our generic signal handler.
214 static void
215 sig_handler(int signo)
217 sigset_t nset;
218 sigset_t oset;
220 (void)sigfillset(&nset);
221 (void)sigprocmask(SIG_SETMASK, &nset, &oset);
223 assert (signo > 0 && signo < NSIG); /* Should be guaranteed. */
225 sig_post(signo);
227 switch (signo) {
228 case SIGCONT:
229 assert(/*CONSTCOND*/ 0); /* We should not be seeing these. */
230 do_default_handler(signo, 0);
231 break;
233 case SIGTSTP:
234 case SIGTTIN:
235 case SIGTTOU:
236 do_default_handler(signo, 0);
237 break;
239 case SIGINT:
240 case SIGHUP:
241 case SIGQUIT:
242 case SIGPIPE:
243 default:
244 if (sigarray[signo] == SIG_DFL)
245 do_default_handler(signo, SA_RESTART);
246 break;
248 (void)sigprocmask(SIG_SETMASK, &oset, NULL);
252 * Setup the signal handlers.
254 PUBLIC void
255 sig_setup(void)
257 sigset_t nset;
258 sigset_t oset;
259 struct sigaction sa;
260 struct sigaction osa;
262 /* Block all signals while setting things. */
263 (void)sigfillset(&nset);
264 (void)sigprocmask(SIG_BLOCK, &nset, &oset);
267 * Flow Control - SIGTSTP, SIGTTIN, SIGTTOU, SIGCONT:
269 * We grab SIGTSTP, SIGTTIN, and SIGTTOU so that we post the
270 * signals before suspending so that they are available when
271 * we resume. If we were to use SIGCONT instead, they will
272 * not get posted until SIGCONT is unblocked, even though the
273 * process has resumed.
275 * NOTE: We default these to SA_RESTART here, but we need to
276 * change this in certain cases, e.g., when reading from a
277 * tty.
279 (void)sigemptyset(&sa.sa_mask);
280 sa.sa_flags = SA_RESTART;
281 sa.sa_handler = sig_handler;
282 (void)sigaction(SIGTSTP, &sa, NULL);
283 (void)sigaction(SIGTTIN, &sa, NULL);
284 (void)sigaction(SIGTTOU, &sa, NULL);
287 * SIGHUP, SIGINT, and SIGQUIT:
289 * SIGHUP and SIGINT are trapped unless they are being
290 * ignored.
292 * Currently, we let the default handler deal with SIGQUIT.
294 (void)sigemptyset(&sa.sa_mask);
295 sa.sa_flags = 0;
296 sa.sa_handler = sig_handler;
298 if (sigaction(SIGHUP, &sa, &osa) != -1 && osa.sa_handler == SIG_IGN)
299 (void)signal(SIGHUP, SIG_IGN);
301 if (sigaction(SIGINT, &sa, &osa) != -1 && osa.sa_handler == SIG_IGN)
302 (void)signal(SIGINT, SIG_IGN);
303 #if 0
304 if (signal(SIGQUIT, SIG_DFL) == SIG_IGN)
305 (void)signal(SIGQUIT, SIG_IGN);
306 #endif
308 * SIGCHLD and SIGPIPE:
310 * SIGCHLD is setup early in main. The handler lives in
311 * popen.c as it uses internals of that module.
313 * SIGPIPE is grabbed here. It is only used in
314 * lex.c:setup_piping(), cmd1.c:type1(), and cmd1.c:pipecmd().
316 (void)sigemptyset(&sa.sa_mask);
317 sa.sa_flags = 0;
318 sa.sa_handler = sig_handler;
319 (void)sigaction(SIGPIPE, &sa, NULL);
322 * Make sure our structures are initialized.
323 * XXX: This should be unnecessary.
325 (void)memset(sigarray, 0, sizeof(sigarray));
326 SIGQUEUE_INIT(&sigqueue);
328 /* Restore the signal mask. */
329 (void)sigprocmask(SIG_SETMASK, &oset, NULL);
332 static struct { /* data shared by sig_hold() and sig_release() */
333 int depth; /* depth of sig_hold() */
334 sigset_t oset; /* old signal mask saved by sig_hold() */
335 } hold;
338 * Hold signals SIGHUP, SIGINT, and SIGQUIT.
340 PUBLIC void
341 sig_hold(void)
343 sigset_t nset;
345 if (hold.depth++ == 0) {
346 (void)sigemptyset(&nset);
347 (void)sigaddset(&nset, SIGHUP);
348 (void)sigaddset(&nset, SIGINT);
349 (void)sigaddset(&nset, SIGQUIT);
350 (void)sigprocmask(SIG_BLOCK, &nset, &hold.oset);
355 * Release signals SIGHUP, SIGINT, and SIGQUIT.
357 PUBLIC void
358 sig_release(void)
361 if (--hold.depth == 0)
362 (void)sigprocmask(SIG_SETMASK, &hold.oset, NULL);
366 * Unblock and ignore a signal.
368 PUBLIC int
369 sig_ignore(int sig, struct sigaction *osa, sigset_t *oset)
371 struct sigaction act;
372 sigset_t nset;
373 int error;
375 (void)sigemptyset(&act.sa_mask);
376 act.sa_flags = SA_RESTART;
377 act.sa_handler = SIG_IGN;
378 error = sigaction(sig, &act, osa);
380 if (error != -1) {
381 (void)sigemptyset(&nset);
382 (void)sigaddset(&nset, sig);
383 (void)sigprocmask(SIG_UNBLOCK, &nset, oset);
384 } else if (oset != NULL)
385 (void)sigprocmask(SIG_UNBLOCK, NULL, oset);
387 return error;
391 * Restore a signal and the current signal mask.
393 PUBLIC int
394 sig_restore(int sig, struct sigaction *osa, sigset_t *oset)
396 int error;
398 error = 0;
399 if (oset)
400 error = sigprocmask(SIG_SETMASK, oset, NULL);
401 if (osa)
402 error = sigaction(sig, osa, NULL);
404 return error;
408 * Change the current flags and (optionally) return the old sigaction
409 * structure so we can restore things later. This is used to turn
410 * SA_RESTART on or off.
412 PUBLIC int
413 sig_setflags(int signo, int flags, struct sigaction *osa)
415 struct sigaction sa;
417 if (sigaction(signo, NULL, &sa) == -1)
418 return -1;
419 if (osa)
420 *osa = sa;
421 sa.sa_flags = flags;
422 return sigaction(signo, &sa, NULL);