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