kludge to make undeleting an undeleted message work
[unix-history] / usr / src / usr.bin / mail / sigretro.c
CommitLineData
761330fe
DF
1/*
2 * Copyright (c) 1980 Regents of the University of California.
0c5f72fb
KB
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
6 * provided that this notice is preserved and that due credit is given
7 * to the University of California at Berkeley. The name of the University
8 * may not be used to endorse or promote products derived from this
9 * software without specific prior written permission. This software
10 * is provided ``as is'' without express or implied warranty.
761330fe
DF
11 */
12
0c5f72fb
KB
13#ifdef notdef
14static char sccsid[] = "@(#)sigretro.c 5.3 (Berkeley) %G%";
15#endif /* notdef */
ac348c3c
SL
16
17#include <signal.h>
18#include <errno.h>
19#include <setjmp.h>
20#include "sigretro.h"
21
22/*
23 * Retrofit new signal interface to old signal primitives.
24 * Supported routines:
25 * sigsys(sig, func)
26 * sigset(sig, func)
27 * sighold(sig)
28 * sigrelse(sig)
29 * sigignore(sig)
30 * sigpause(sig)
31 * Also,
32 * sigchild()
33 * to set all held signals to ignored signals in the
34 * child process after fork(2)
35 */
36
37typedef int (*sigtype)();
38
39sigtype sigdisp(), sighold(), sigignore();
40
41/*
42 * The following helps us keep the extended signal semantics together.
43 * We remember for each signal the address of the function we're
44 * supposed to call. s_func is SIG_DFL / SIG_IGN if appropriate.
45 */
46struct sigtable {
47 sigtype s_func; /* What to call */
48 int s_flag; /* Signal flags; see below */
49} sigtable[NSIG + 1];
50
51/*
52 * Signal flag values.
53 */
54#define SHELD 1 /* Signal is being held */
55#define SDEFER 2 /* Signal occured while held */
56#define SSET 4 /* s_func is believable */
57#define SPAUSE 8 /* are pausing, waiting for sig */
58
59jmp_buf _pause; /* For doing sigpause() */
60
61/*
62 * Approximate sigsys() system call
63 * This is almost useless since one only calls sigsys()
64 * in the child of a vfork(). If you have vfork(), you have new signals
65 * anyway. The real sigsys() does all the stuff needed to support
66 * the real sigset() library. We don't bother here, assuming that
67 * you are either ignoring or defaulting a signal in the child.
68 */
69sigtype
70sigsys(sig, func)
71 sigtype func;
72{
73 sigtype old;
74
75 old = sigdisp(sig);
76 signal(sig, func);
77 return(old);
78}
79
80/*
81 * Set the (permanent) disposition of a signal.
82 * If the signal is subsequently (or even now) held,
83 * the action you set here can be enabled using sigrelse().
84 */
85sigtype
86sigset(sig, func)
87 sigtype func;
88{
89 sigtype old;
90 int _sigtramp();
91 extern int errno;
92
93 if (sig < 1 || sig > NSIG) {
94 errno = EINVAL;
95 return(BADSIG);
96 }
97 old = sigdisp(sig);
98 /*
99 * Does anyone actually call sigset with SIG_HOLD!?
100 */
101 if (func == SIG_HOLD) {
102 sighold(sig);
103 return(old);
104 }
105 sigtable[sig].s_flag |= SSET;
106 sigtable[sig].s_func = func;
107 if (func == SIG_DFL) {
108 /*
109 * If signal has been held, must retain
110 * the catch so that we can note occurrance
111 * of signal.
112 */
113 if ((sigtable[sig].s_flag & SHELD) == 0)
114 signal(sig, SIG_DFL);
115 else
116 signal(sig, _sigtramp);
117 return(old);
118 }
119 if (func == SIG_IGN) {
120 /*
121 * Clear pending signal
122 */
123 signal(sig, SIG_IGN);
124 sigtable[sig].s_flag &= ~SDEFER;
125 return(old);
126 }
127 signal(sig, _sigtramp);
128 return(old);
129}
130
131/*
132 * Hold a signal.
133 * This CAN be tricky if the signal's disposition is SIG_DFL.
134 * In that case, we still catch the signal so we can note it
135 * happened and do something crazy later.
136 */
137sigtype
138sighold(sig)
139{
140 sigtype old;
141 extern int errno;
142
143 if (sig < 1 || sig > NSIG) {
144 errno = EINVAL;
145 return(BADSIG);
146 }
147 old = sigdisp(sig);
148 if (sigtable[sig].s_flag & SHELD)
149 return(old);
150 /*
151 * When the default action is required, we have to
152 * set up to catch the signal to note signal's occurrance.
153 */
154 if (old == SIG_DFL) {
155 sigtable[sig].s_flag |= SSET;
156 signal(sig, _sigtramp);
157 }
158 sigtable[sig].s_flag |= SHELD;
159 return(old);
160}
161
162/*
163 * Release a signal
164 * If the signal occurred while we had it held, cause the signal.
165 */
166sigtype
167sigrelse(sig)
168{
169 sigtype old;
170 extern int errno;
171 int _sigtramp();
172
173 if (sig < 1 || sig > NSIG) {
174 errno = EINVAL;
175 return(BADSIG);
176 }
177 old = sigdisp(sig);
178 if ((sigtable[sig].s_flag & SHELD) == 0)
179 return(old);
180 sigtable[sig].s_flag &= ~SHELD;
181 if (sigtable[sig].s_flag & SDEFER)
182 _sigtramp(sig);
183 /*
184 * If disposition was the default, then we can unset the
185 * catch to _sigtramp() and let the system do the work.
186 */
187 if (sigtable[sig].s_func == SIG_DFL)
188 signal(sig, SIG_DFL);
189 return(old);
190}
191
192/*
193 * Ignore a signal.
194 */
195sigtype
196sigignore(sig)
197{
198
199 return(sigset(sig, SIG_IGN));
200}
201
202/*
203 * Pause, waiting for sig to occur.
204 * We assume LUSER called us with the signal held.
205 * When we got the signal, mark the signal as having
206 * occurred. It will actually cause something when
207 * the signal is released.
208 *
209 * This is probably useless without job control anyway.
210 */
211sigpause(sig)
212{
213 extern int errno;
214
215 if (sig < 1 || sig > NSIG) {
216 errno = EINVAL;
217 return;
218 }
219 sigtable[sig].s_flag |= SHELD|SPAUSE;
220 if (setjmp(_pause) == 0)
221 pause();
222 sigtable[sig].s_flag &= ~SPAUSE;
223 sigtable[sig].s_flag |= SDEFER;
224}
225
226/*
227 * In the child process after fork(2), set the disposition of all held
228 * signals to SIG_IGN. This is a new procedure not in the real sigset()
229 * package, provided for retrofitting purposes.
230 */
231sigchild()
232{
233 register int i;
234
235 for (i = 1; i <= NSIG; i++)
236 if (sigtable[i].s_flag & SHELD)
237 signal(i, SIG_IGN);
238}
239
240/*
241 * Return the current disposition of a signal
242 * If we have not set this signal before, we have to
243 * ask the system
244 */
245sigtype
246sigdisp(sig)
247{
248 extern int errno;
249 sigtype old;
250
251 if (sig < 1 || sig > NSIG) {
252 errno = EINVAL;
253 return(BADSIG);
254 }
255 /*
256 * If we have no knowledge of this signal,
257 * ask the system, then save the result for later.
258 */
259 if ((sigtable[sig].s_flag & SSET) == 0) {
260 old = signal(sig, SIG_IGN);
261 sigtable[sig].s_func = old;
262 sigtable[sig].s_flag |= SSET;
263 signal(sig, old);
264 return(old);
265 }
266 /*
267 * If we have set this signal before, then sigset()
268 * will have been careful to leave something meaningful
269 * in s_func.
270 */
271 return(sigtable[sig].s_func);
272}
273
274/*
275 * The following routine gets called for any signal
276 * that is to be trapped to a user function.
277 */
278_sigtramp(sig)
279{
280 extern int errno;
281 sigtype old;
282
283 if (sig < 1 || sig > NSIG) {
284 errno = EINVAL;
285 return;
286 }
287
288top:
289 old = signal(sig, SIG_IGN);
290 /*
291 * If signal being paused on, wakeup sigpause()
292 */
293 if (sigtable[sig].s_flag & SPAUSE)
294 longjmp(_pause, 1);
295 /*
296 * If signal being held, mark its table entry
297 * so we can trigger it when signal released.
298 * Then just return.
299 */
300 if (sigtable[sig].s_flag & SHELD) {
301 sigtable[sig].s_flag |= SDEFER;
302 signal(sig, _sigtramp);
303 return;
304 }
305 /*
306 * If the signal is being ignored, just return.
307 * This would make SIGCONT more normal, but of course
308 * any system with SIGCONT also has the new signal pkg, so...
309 */
310 if (sigtable[sig].s_func == SIG_IGN)
311 return;
312 /*
313 * If the signal is SIG_DFL, then we probably got here
314 * by holding the signal, having it happen, then releasing
315 * the signal. I wonder if a process is allowed to send
316 * a signal to itself?
317 */
318 if (sigtable[sig].s_func == SIG_DFL) {
319 signal(sig, SIG_DFL);
320 kill(getpid(), sig);
321 /* Will we get back here? */
322 return;
323 }
324 /*
325 * Looks like we should just cause the signal...
326 * We hold the signal for the duration of the user's
327 * code with the signal re-enabled. If the signal
328 * happens again while in user code, we will recursively
329 * trap here and mark that we had another occurance
330 * and return to the user's trap code. When we return
331 * from there, we can cause the signal again.
332 */
333 sigtable[sig].s_flag &= ~SDEFER;
334 sigtable[sig].s_flag |= SHELD;
335 signal(sig, _sigtramp);
336 (*sigtable[sig].s_func)(sig);
337 /*
338 * If the signal re-occurred while in the user's routine,
339 * just go try it again...
340 */
341 sigtable[sig].s_flag &= ~SHELD;
342 if (sigtable[sig].s_flag & SDEFER)
343 goto top;
344}