xref: /illumos-gate/usr/src/cmd/sh/fault.c (revision 7c478bd9)
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  * Copyright (c) 1996, by Sun Microsystems, Inc.
28  * All rights reserved.
29  */
30 
31 #ident	"%Z%%M%	%I%	%E% SMI"	/* SVr4.0 1.13.17.1	*/
32 /*
33  * UNIX shell
34  */
35 
36 #include	"defs.h"
37 #include	<sys/procset.h>
38 #include	<siginfo.h>
39 #include	<ucontext.h>
40 #include	<errno.h>
41 #include	<string.h>
42 
43 static	void (*psig0_func)() = SIG_ERR;	/* previous signal handler for signal 0 */
44 static	char sigsegv_stack[SIGSTKSZ];
45 
46 static void sigsegv(int sig, siginfo_t *sip, ucontext_t *uap);
47 static void fault();
48 static BOOL sleeping = 0;
49 static unsigned char *trapcom[MAXTRAP]; /* array of actions, one per signal */
50 static BOOL trapflg[MAXTRAP] =
51 {
52 	0,
53 	0,	/* hangup */
54 	0,	/* interrupt */
55 	0,	/* quit */
56 	0,	/* illegal instr */
57 	0,	/* trace trap */
58 	0,	/* IOT */
59 	0,	/* EMT */
60 	0,	/* float pt. exp */
61 	0,	/* kill */
62 	0, 	/* bus error */
63 	0,	/* memory faults */
64 	0,	/* bad sys call */
65 	0,	/* bad pipe call */
66 	0,	/* alarm */
67 	0, 	/* software termination */
68 	0,	/* unassigned */
69 	0,	/* unassigned */
70 	0,	/* death of child */
71 	0,	/* power fail */
72 	0,	/* window size change */
73 	0,	/* urgent IO condition */
74 	0,	/* pollable event occured */
75 	0,	/* stopped by signal */
76 	0,	/* stopped by user */
77 	0,	/* continued */
78 	0,	/* stopped by tty input */
79 	0,	/* stopped by tty output */
80 	0,	/* virtual timer expired */
81 	0,	/* profiling timer expired */
82 	0,	/* exceeded cpu limit */
83 	0,	/* exceeded file size limit */
84 	0, 	/* process's lwps are blocked */
85 	0,	/* special signal used by thread library */
86 	0, 	/* check point freeze */
87 	0,	/* check point thaw */
88 };
89 
90 static void (*(
91 sigval[MAXTRAP]))() =
92 {
93 	0,
94 	done, 	/* hangup */
95 	fault,	/* interrupt */
96 	fault,	/* quit */
97 	done,	/* illegal instr */
98 	done,	/* trace trap */
99 	done,	/* IOT */
100 	done,	/* EMT */
101 	done,	/* floating pt. exp */
102 	0,	/* kill */
103 	done, 	/* bus error */
104 	sigsegv,	/* memory faults */
105 	done, 	/* bad sys call */
106 	done,	/* bad pipe call */
107 	done,	/* alarm */
108 	fault,	/* software termination */
109 	done,	/* unassigned */
110 	done,	/* unassigned */
111 	0,	/* death of child */
112 	done,	/* power fail */
113 	0,	/* window size change */
114 	done,	/* urgent IO condition */
115 	done,	/* pollable event occured */
116 	0,	/* uncatchable stop */
117 	0,	/* foreground stop */
118 	0,	/* stopped process continued */
119 	0,	/* background tty read */
120 	0,	/* background tty write */
121 	done,	/* virtual timer expired */
122 	done,	/* profiling timer expired */
123 	done,	/* exceeded cpu limit */
124 	done,	/* exceeded file size limit */
125 	0, 	/* process's lwps are blocked */
126 	0,	/* special signal used by thread library */
127 	0, 	/* check point freeze */
128 	0,	/* check point thaw */
129 };
130 
131 static int
132 ignoring(i)
133 register int i;
134 {
135 	struct sigaction act;
136 	if (trapflg[i] & SIGIGN)
137 		return (1);
138 	sigaction(i, 0, &act);
139 	if (act.sa_handler == SIG_IGN) {
140 		trapflg[i] |= SIGIGN;
141 		return (1);
142 	}
143 	return (0);
144 }
145 
146 static void
147 clrsig(i)
148 int	i;
149 {
150 	if (trapcom[i] != 0) {
151 		free(trapcom[i]);
152 		trapcom[i] = 0;
153 	}
154 
155 
156 	if (trapflg[i] & SIGMOD) {
157 		/*
158 		 * If the signal has been set to SIGIGN and we are now
159 		 * clearing the disposition of the signal (restoring it
160 		 * back to its default value) then we need to clear this
161 		 * bit as well
162 		 *
163 		 */
164 		if (trapflg[i] & SIGIGN)
165 			trapflg[i] &= ~SIGIGN;
166 
167 		trapflg[i] &= ~SIGMOD;
168 		handle(i, sigval[i]);
169 	}
170 }
171 
172 void
173 done(sig)
174 {
175 	register unsigned char	*t;
176 	int	savxit;
177 
178 	if (t = trapcom[0])
179 	{
180 		trapcom[0] = 0;
181 		/* Save exit value so trap handler will not change its val */
182 		savxit = exitval;
183 		execexp(t, 0);
184 		exitval = savxit;		/* Restore exit value */
185 		free(t);
186 	}
187 	else
188 		chktrap();
189 
190 	rmtemp(0);
191 	rmfunctmp();
192 
193 #ifdef ACCT
194 	doacct();
195 #endif
196 	if (flags & subsh) {
197 		/* in a subshell, need to wait on foreground job */
198 		collect_fg_job();
199 	}
200 
201 	(void) endjobs(0);
202 	if (sig) {
203 		sigset_t set;
204 		sigemptyset(&set);
205 		sigaddset(&set, sig);
206 		sigprocmask(SIG_UNBLOCK, &set, 0);
207 		handle(sig, SIG_DFL);
208 		kill(mypid, sig);
209 	}
210 	exit(exitval);
211 }
212 
213 static void
214 fault(sig)
215 register int	sig;
216 {
217 	register int flag;
218 
219 	switch (sig) {
220 		case SIGALRM:
221 			if (sleeping)
222 				return;
223 			break;
224 	}
225 
226 	if (trapcom[sig])
227 		flag = TRAPSET;
228 	else if (flags & subsh)
229 		done(sig);
230 	else
231 		flag = SIGSET;
232 
233 	trapnote |= flag;
234 	trapflg[sig] |= flag;
235 }
236 
237 int
238 handle(sig, func)
239 	int sig;
240 	void (*func)();
241 {
242 	int	ret;
243 	struct sigaction act, oact;
244 
245 	if (func == SIG_IGN && (trapflg[sig] & SIGIGN))
246 		return (0);
247 
248 	/*
249 	 * Ensure that sigaction is only called with valid signal numbers,
250 	 * we can get random values back for oact.sa_handler if the signal
251 	 * number is invalid
252 	 *
253 	 */
254 	if (sig > MINTRAP && sig < MAXTRAP) {
255 		sigemptyset(&act.sa_mask);
256 		act.sa_flags = (sig == SIGSEGV) ? (SA_ONSTACK | SA_SIGINFO) : 0;
257 		act.sa_handler = func;
258 		sigaction(sig, &act, &oact);
259 	}
260 
261 	if (func == SIG_IGN)
262 		trapflg[sig] |= SIGIGN;
263 
264 	/*
265 	 * Special case for signal zero, we can not obtain the previos
266 	 * action by calling sigaction, instead we save it in the variable
267 	 * psig0_func, so we can test it next time through this code
268 	 *
269 	 */
270 	if (sig == 0) {
271 		ret = (psig0_func != func);
272 		psig0_func = func;
273 	} else {
274 		ret = (func != oact.sa_handler);
275 	}
276 
277 	return (ret);
278 }
279 
280 void
281 stdsigs()
282 {
283 	register int	i;
284 	stack_t	ss;
285 	int	err = 0;
286 	int rtmin = (int)SIGRTMIN;
287 	int rtmax = (int)SIGRTMAX;
288 
289 	ss.ss_size = SIGSTKSZ;
290 	ss.ss_sp = sigsegv_stack;
291 	ss.ss_flags = 0;
292 	errno = 0;
293 	if (sigaltstack(&ss, (stack_t *)NULL) == -1) {
294 		err = errno;
295 		failure("sigaltstack(2) failed with", strerror(err));
296 	}
297 
298 	for (i = 1; i < MAXTRAP; i++) {
299 		if (i == rtmin) {
300 			i = rtmax;
301 			continue;
302 		}
303 		if (sigval[i] == 0)
304 			continue;
305 		if (i != SIGSEGV && ignoring(i))
306 			continue;
307 		handle(i, sigval[i]);
308 	}
309 
310 	/*
311 	 * handle all the realtime signals
312 	 *
313 	 */
314 	for (i = rtmin; i <= rtmax; i++) {
315 		handle(i, done);
316 	}
317 }
318 
319 void
320 oldsigs()
321 {
322 	register int	i;
323 	register unsigned char	*t;
324 
325 	i = MAXTRAP;
326 	while (i--)
327 	{
328 		t = trapcom[i];
329 		if (t == 0 || *t)
330 			clrsig(i);
331 		trapflg[i] = 0;
332 	}
333 	trapnote = 0;
334 }
335 
336 /*
337  * check for traps
338  */
339 
340 void
341 chktrap()
342 {
343 	register int	i = MAXTRAP;
344 	register unsigned char	*t;
345 
346 	trapnote &= ~TRAPSET;
347 	while (--i)
348 	{
349 		if (trapflg[i] & TRAPSET)
350 		{
351 			trapflg[i] &= ~TRAPSET;
352 			if (t = trapcom[i])
353 			{
354 				int	savxit = exitval;
355 				execexp(t, 0);
356 				exitval = savxit;
357 				exitset();
358 			}
359 		}
360 	}
361 }
362 
363 systrap(argc, argv)
364 int argc;
365 char **argv;
366 {
367 	int sig;
368 
369 	if (argc == 1) {
370 		/*
371 		 * print out the current action associated with each signal
372 		 * handled by the shell
373 		 *
374 		 */
375 		for (sig = 0; sig < MAXTRAP; sig++) {
376 			if (trapcom[sig]) {
377 				prn_buff(sig);
378 				prs_buff(colon);
379 				prs_buff(trapcom[sig]);
380 				prc_buff(NL);
381 			}
382 		}
383 	} else {
384 		/*
385 		 * set the action for the list of signals
386 		 *
387 		 */
388 		char *cmd = *argv, *a1 = *(argv+1);
389 		BOOL noa1;
390 		noa1 = (str2sig(a1, &sig) == 0);
391 		if (noa1 == 0)
392 			++argv;
393 		while (*++argv) {
394 			if (str2sig(*argv, &sig) < 0 ||
395 			    sig >= MAXTRAP || sig < MINTRAP ||
396 			    sig == SIGSEGV) {
397 				failure(cmd, badtrap);
398 			} else if (noa1) {
399 				/*
400 				 * no action specifed so reset the siganl
401 				 * to its default disposition
402 				 *
403 				 */
404 				clrsig(sig);
405 			} else if (*a1) {
406 				/*
407 				 * set the action associated with the signal
408 				 * to a1
409 				 *
410 				 */
411 				if (trapflg[sig] & SIGMOD || sig == 0 ||
412 				    !ignoring(sig)) {
413 					handle(sig, fault);
414 					trapflg[sig] |= SIGMOD;
415 					replace(&trapcom[sig], a1);
416 				}
417 			} else if (handle(sig, SIG_IGN)) {
418 				/*
419 				 * set the action associated with the signal
420 				 * to SIG_IGN
421 				 *
422 				 */
423 				trapflg[sig] |= SIGMOD;
424 				replace(&trapcom[sig], a1);
425 			}
426 		}
427 	}
428 }
429 
430 unsigned int
431 sleep(ticks)
432 unsigned int ticks;
433 {
434 	sigset_t set, oset;
435 	struct sigaction act, oact;
436 
437 
438 	/*
439 	 * add SIGALRM to mask
440 	 */
441 
442 	sigemptyset(&set);
443 	sigaddset(&set, SIGALRM);
444 	sigprocmask(SIG_BLOCK, &set, &oset);
445 
446 	/*
447 	 * catch SIGALRM
448 	 */
449 
450 	sigemptyset(&act.sa_mask);
451 	act.sa_flags = 0;
452 	act.sa_handler = fault;
453 	sigaction(SIGALRM, &act, &oact);
454 
455 	/*
456 	 * start alarm and wait for signal
457 	 */
458 
459 	alarm(ticks);
460 	sleeping = 1;
461 	sigsuspend(&oset);
462 	sleeping = 0;
463 
464 	/*
465 	 * reset alarm, catcher and mask
466 	 */
467 
468 	alarm(0);
469 	sigaction(SIGALRM, &oact, NULL);
470 	sigprocmask(SIG_SETMASK, &oset, 0);
471 
472 }
473 
474 void
475 sigsegv(int sig, siginfo_t *sip, ucontext_t *uap)
476 {
477 	if (sip == (siginfo_t *)NULL) {
478 		/*
479 		 * This should never happen, but if it does this is all we
480 		 * can do. It can only happen if sigaction(2) for SIGSEGV
481 		 * has been called without SA_SIGINFO being set.
482 		 *
483 		 */
484 
485 		exit(ERROR);
486 	} else {
487 		if (sip->si_code <= 0) {
488 			/*
489 			 * If we are here then SIGSEGV must have been sent to
490 			 * us from a user process NOT as a result of an
491 			 * internal error within the shell eg
492 			 * kill -SEGV $$
493 			 * will bring us here. So do the normal thing.
494 			 *
495 			 */
496 			fault(sig);
497 		} else {
498 			/*
499 			 * If we are here then there must have been an internal
500 			 * error within the shell to generate SIGSEGV eg
501 			 * the stack is full and we cannot call any more
502 			 * functions (Remeber this signal handler is running
503 			 * on an alternate stack). So we just exit cleanly
504 			 * with an error status (no core file).
505 			 */
506 			exit(ERROR);
507 		}
508 	}
509 }
510