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