xref: /freebsd/contrib/tcsh/tc.sig.c (revision 2b743a9e9ddc6736208dc8ca1ce06ce64ad20a19)
1 /* $Header: /src/pub/tcsh/tc.sig.c,v 3.29 2005/01/18 20:24:51 christos Exp $ */
2 /*
3  * tc.sig.c: Signal routine emulations
4  */
5 /*-
6  * Copyright (c) 1980, 1991 The Regents of the University of California.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 #include "sh.h"
34 
35 RCSID("$Id: tc.sig.c,v 3.29 2005/01/18 20:24:51 christos Exp $")
36 
37 #include "tc.wait.h"
38 
39 #ifndef BSDSIGS
40 
41 /* this stack is used to queue signals
42  * we can handle up to MAX_CHLD outstanding children now;
43  */
44 #define MAX_CHLD 50
45 
46 # ifdef UNRELSIGS
47 static struct mysigstack {
48     int     s_w;		/* wait report			 */
49     int     s_errno;		/* errno returned;		 */
50     pid_t   s_pid;		/* pid returned			 */
51 }       stk[MAX_CHLD];
52 static int stk_ptr = -1;
53 
54 
55 /* queue child signals
56  */
57 static RETSIGTYPE
58 sig_ch_queue()
59 {
60 #  ifdef JOBDEBUG
61     xprintf("queue SIGCHLD\n");
62     flush();
63 #  endif /* JOBDEBUG */
64     stk_ptr++;
65     stk[stk_ptr].s_pid = (pid_t) wait(&stk[stk_ptr].s_w);
66     stk[stk_ptr].s_errno = errno;
67     (void) signal(SIGCHLD, sig_ch_queue);
68 }
69 
70 /* process all awaiting child signals
71  */
72 static RETSIGTYPE
73 sig_ch_rel()
74 {
75     while (stk_ptr > -1)
76 	pchild(SIGCHLD);
77 #  ifdef JOBDEBUG
78     xprintf("signal(SIGCHLD, pchild);\n");
79 #  endif /* JOBDEBUG */
80     (void) signal(SIGCHLD, pchild);
81 }
82 
83 
84 /* libc.a contains these functions in SYSVREL >= 3. */
85 RETSIGTYPE
86 (*xsigset(a, b)) ()
87     int     a;
88     signalfun_t  b;
89 {
90     return (signal(a, b));
91 }
92 
93 /* release signal
94  *	release all queued signals and
95  *	set the default signal handler
96  */
97 void
98 sigrelse(what)
99     int     what;
100 {
101     if (what == SIGCHLD)
102 	sig_ch_rel();
103 
104 #  ifdef COHERENT
105     (void) signal(what, what == SIGINT ? pintr : SIG_DFL);
106 #  endif /* COHERENT */
107 }
108 
109 /* hold signal
110  * only works with child and interrupt
111  */
112 void
113 xsighold(what)
114     int     what;
115 {
116     if (what == SIGCHLD)
117 	(void) signal(SIGCHLD, sig_ch_queue);
118 
119 #  ifdef COHERENT
120     (void) signal(what, SIG_IGN);
121 #  endif /* COHERENT */
122 }
123 
124 /* ignore signal
125  */
126 void
127 xsigignore(a)
128     int     a;
129 {
130     (void) signal(a, SIG_IGN);
131 }
132 
133 /* atomically release one signal
134  */
135 void
136 xsigpause(what)
137     int     what;
138 {
139     /* From: Jim Mattson <mattson%cs@ucsd.edu> */
140     if (what == SIGCHLD)
141 	pchild(SIGCHLD);
142 }
143 
144 
145 /* return either awaiting processes or do a wait now
146  */
147 pid_t
148 ourwait(w)
149     int    *w;
150 {
151     pid_t pid;
152 
153 #  ifdef JOBDEBUG
154     xprintf(CGETS(25, 1, "our wait %d\n"), stk_ptr);
155     flush();
156 #  endif /* JOBDEBUG */
157 
158     if (stk_ptr == -1) {
159 	/* stack empty return signal from stack */
160 	pid = (pid_t) wait(w);
161 #  ifdef JOBDEBUG
162 	xprintf("signal(SIGCHLD, pchild);\n");
163 #  endif /* JOBDEBUG */
164 	(void) signal(SIGCHLD, pchild);
165 	return (pid);
166     }
167     else {
168 	/* return signal from stack */
169 	errno = stk[stk_ptr].s_errno;
170 	*w = stk[stk_ptr].s_w;
171 	stk_ptr--;
172 	return (stk[stk_ptr + 1].s_pid);
173     }
174 } /* end ourwait */
175 
176 #  ifdef COHERENT
177 #   undef signal
178 RETSIGTYPE
179 (*xsignal(a, b)) ()
180     int     a;
181     signalfun_t  b;
182 {
183     if (a == SIGCHLD)
184 	return SIG_DFL;
185     else
186 	return (signal(a, b));
187 }
188 #  endif /* COHERENT */
189 
190 # endif /* UNRELSIGS */
191 
192 # ifdef SXA
193 /*
194  * SX/A is SYSVREL3 but does not have sys5-sigpause().
195  * I've heard that sigpause() is not defined in SYSVREL3.
196  */
197 /* This is not need if you make tcsh by BSD option's cc. */
198 void
199 sigpause(what)
200 {
201     if (what == SIGCHLD) {
202 	(void) bsd_sigpause(bsd_sigblock((sigmask_t) 0) & ~sigmask(SIGBSDCHLD));
203     }
204     else if (what == 0) {
205 	pause();
206     }
207     else {
208 	xprintf("sigpause(%d)\n", what);
209 	pause();
210     }
211 }
212 # endif /* SXA */
213 
214 #endif /* !BSDSIGS */
215 
216 #ifdef NEEDsignal
217 /* turn into bsd signals */
218 RETSIGTYPE
219 (*xsignal(s, a)) ()
220     int     s;
221     signalfun_t a;
222 {
223     sigvec_t osv, sv;
224 
225     (void) mysigvec(s, NULL, &osv);
226     sv = osv;
227     sv.sv_handler = a;
228 #ifdef SIG_STK
229     sv.sv_onstack = SIG_STK;
230 #endif /* SIG_STK */
231 #ifdef SV_BSDSIG
232     sv.sv_flags = SV_BSDSIG;
233 #endif /* SV_BSDSIG */
234 
235     if (mysigvec(s, &sv, NULL) < 0)
236 	return (BADSIG);
237     return (osv.sv_handler);
238 }
239 
240 #endif /* NEEDsignal */
241 
242 #ifdef POSIXSIGS
243 /*
244  * Support for signals.
245  */
246 
247 extern int errno;
248 
249 /* Set and test a bit.  Bits numbered 1 to 32 */
250 
251 #define SETBIT(x, y)	x |= sigmask(y)
252 #define ISSET(x, y)	((x & sigmask(y)) != 0)
253 
254 #ifdef DEBUG
255 # define SHOW_SIGNALS	1	/* to assist in debugging signals */
256 #endif /* DEBUG */
257 
258 #ifdef SHOW_SIGNALS
259 char   *show_sig_mask();
260 #endif /* SHOW_SIGNALS */
261 
262 #ifndef __PARAGON__
263 /*
264  * sigsetmask(mask)
265  *
266  * Set a new signal mask.  Return old mask.
267  */
268 sigmask_t
269 sigsetmask(mask)
270     sigmask_t     mask;
271 {
272     sigset_t set, oset;
273     int     m;
274     int i;
275 
276     (void) sigemptyset(&set);
277     (void) sigemptyset(&oset);
278 
279     for (i = 1; i <= MAXSIG; i++)
280 	if (ISSET(mask, i))
281 	    (void) sigaddset(&set, i);
282 
283     if ((sigprocmask(SIG_SETMASK, &set, &oset)) == -1) {
284 	xprintf("sigsetmask(0x%x) - sigprocmask failed, errno %d",
285 		mask, errno);
286     }
287 
288     m = 0;
289     for (i = 1; i <= MAXSIG; i++)
290 	if (sigismember(&oset, i) == 1)
291 	    SETBIT(m, i);
292 
293     return (m);
294 }
295 #endif /* __PARAGON__ */
296 
297 #ifndef __DGUX__
298 /*
299  * sigblock(mask)
300  *
301  * Add "mask" set of signals to the present signal mask.
302  * Return old mask.
303  */
304 sigmask_t
305 sigblock(mask)
306     sigmask_t     mask;
307 {
308     sigset_t set, oset;
309     int     m;
310     int i;
311 
312     (void) sigemptyset(&set);
313     (void) sigemptyset(&oset);
314 
315     /* Get present set of signals. */
316     if ((sigprocmask(SIG_SETMASK, NULL, &set)) == -1)
317 	stderror(ERR_SYSTEM, "sigprocmask", strerror(errno));
318 
319     /* Add in signals from mask. */
320     for (i = 1; i <= MAXSIG; i++)
321 	if (ISSET(mask, i))
322 	    (void) sigaddset(&set, i);
323 
324     if ((sigprocmask(SIG_SETMASK, &set, &oset)) == -1)
325 	stderror(ERR_SYSTEM, "sigprocmask", strerror(errno));
326 
327     /* Return old mask to user. */
328     m = 0;
329     for (i = 1; i <= MAXSIG; i++)
330 	if (sigismember(&oset, i) == 1)
331 	    SETBIT(m, i);
332 
333     return (m);
334 }
335 #endif /* __DGUX__ */
336 
337 
338 /*
339  * bsd_sigpause(mask)
340  *
341  * Set new signal mask and wait for signal;
342  * Old mask is restored on signal.
343  */
344 void
345 bsd_sigpause(mask)
346     sigmask_t     mask;
347 {
348     sigset_t set;
349     int i;
350 
351     (void) sigemptyset(&set);
352 
353     for (i = 1; i <= MAXSIG; i++)
354 	if (ISSET(mask, i))
355 	    (void) sigaddset(&set, i);
356     (void) sigsuspend(&set);
357 }
358 
359 /*
360  * bsd_signal(sig, func)
361  *
362  * Emulate bsd style signal()
363  */
364 RETSIGTYPE (*bsd_signal(sig, func)) ()
365         int sig;
366         signalfun_t func;
367 {
368         struct sigaction act, oact;
369         sigset_t set;
370         signalfun_t r_func;
371 
372         if (sig < 0 || sig > MAXSIG) {
373                 xprintf(CGETS(25, 2,
374 			"error: bsd_signal(%d) signal out of range\n"), sig);
375                 return((signalfun_t) SIG_IGN);
376         }
377 
378         (void) sigemptyset(&set);
379 
380         act.sa_handler = (signalfun_t) func; /* user function */
381         act.sa_mask = set;                      /* signal mask */
382         act.sa_flags = 0;                       /* no special actions */
383 
384         if (sigaction(sig, &act, &oact)) {
385                 xprintf(CGETS(25, 3,
386 			"error: bsd_signal(%d) - sigaction failed, errno %d\n"),
387 			sig, errno);
388                 return((signalfun_t) SIG_IGN);
389         }
390 
391         r_func = (signalfun_t) oact.sa_handler;
392         return(r_func);
393 }
394 #endif /* POSIXSIG */
395 
396 
397 #ifdef SIGSYNCH
398 static long Synch_Cnt = 0;
399 
400 RETSIGTYPE
401 synch_handler(sno)
402 int sno;
403 {
404     if (sno != SIGSYNCH)
405 	abort();
406     Synch_Cnt++;
407 }
408 #endif /* SIGSYNCH */
409