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