xref: /illumos-gate/usr/src/cmd/sh/fault.c (revision 79033acb)
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 (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 
31 #pragma ident	"%Z%%M%	%I%	%E% SMI"
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(int i)
133 {
134 	struct sigaction act;
135 	if (trapflg[i] & SIGIGN)
136 		return (1);
137 	sigaction(i, 0, &act);
138 	if (act.sa_handler == SIG_IGN) {
139 		trapflg[i] |= SIGIGN;
140 		return (1);
141 	}
142 	return (0);
143 }
144 
145 static void
146 clrsig(i)
147 int	i;
148 {
149 	if (trapcom[i] != 0) {
150 		free(trapcom[i]);
151 		trapcom[i] = 0;
152 	}
153 
154 
155 	if (trapflg[i] & SIGMOD) {
156 		/*
157 		 * If the signal has been set to SIGIGN and we are now
158 		 * clearing the disposition of the signal (restoring it
159 		 * back to its default value) then we need to clear this
160 		 * bit as well
161 		 *
162 		 */
163 		if (trapflg[i] & SIGIGN)
164 			trapflg[i] &= ~SIGIGN;
165 
166 		trapflg[i] &= ~SIGMOD;
167 		handle(i, sigval[i]);
168 	}
169 }
170 
171 void
172 done(sig)
173 {
174 	unsigned char	*t;
175 	int	savxit;
176 
177 	if (t = trapcom[0])
178 	{
179 		trapcom[0] = 0;
180 		/* Save exit value so trap handler will not change its val */
181 		savxit = exitval;
182 		execexp(t, 0);
183 		exitval = savxit;		/* Restore exit value */
184 		free(t);
185 	}
186 	else
187 		chktrap();
188 
189 	rmtemp(0);
190 	rmfunctmp();
191 
192 #ifdef ACCT
193 	doacct();
194 #endif
195 	if (flags & subsh) {
196 		/* in a subshell, need to wait on foreground job */
197 		collect_fg_job();
198 	}
199 
200 	(void) endjobs(0);
201 	if (sig) {
202 		sigset_t set;
203 		sigemptyset(&set);
204 		sigaddset(&set, sig);
205 		sigprocmask(SIG_UNBLOCK, &set, 0);
206 		handle(sig, SIG_DFL);
207 		kill(mypid, sig);
208 	}
209 	exit(exitval);
210 }
211 
212 static void
213 fault(int sig)
214 {
215 	int flag;
216 
217 	switch (sig) {
218 		case SIGALRM:
219 			if (sleeping)
220 				return;
221 			break;
222 	}
223 
224 	if (trapcom[sig])
225 		flag = TRAPSET;
226 	else if (flags & subsh)
227 		done(sig);
228 	else
229 		flag = SIGSET;
230 
231 	trapnote |= flag;
232 	trapflg[sig] |= flag;
233 }
234 
235 int
236 handle(sig, func)
237 	int sig;
238 	void (*func)();
239 {
240 	int	ret;
241 	struct sigaction act, oact;
242 
243 	if (func == SIG_IGN && (trapflg[sig] & SIGIGN))
244 		return (0);
245 
246 	/*
247 	 * Ensure that sigaction is only called with valid signal numbers,
248 	 * we can get random values back for oact.sa_handler if the signal
249 	 * number is invalid
250 	 *
251 	 */
252 	if (sig > MINTRAP && sig < MAXTRAP) {
253 		sigemptyset(&act.sa_mask);
254 		act.sa_flags = (sig == SIGSEGV) ? (SA_ONSTACK | SA_SIGINFO) : 0;
255 		act.sa_handler = func;
256 		sigaction(sig, &act, &oact);
257 	}
258 
259 	if (func == SIG_IGN)
260 		trapflg[sig] |= SIGIGN;
261 
262 	/*
263 	 * Special case for signal zero, we can not obtain the previos
264 	 * action by calling sigaction, instead we save it in the variable
265 	 * psig0_func, so we can test it next time through this code
266 	 *
267 	 */
268 	if (sig == 0) {
269 		ret = (psig0_func != func);
270 		psig0_func = func;
271 	} else {
272 		ret = (func != oact.sa_handler);
273 	}
274 
275 	return (ret);
276 }
277 
278 void
279 stdsigs()
280 {
281 	int	i;
282 	stack_t	ss;
283 	int rtmin = (int)SIGRTMIN;
284 	int rtmax = (int)SIGRTMAX;
285 
286 	ss.ss_size = SIGSTKSZ;
287 	ss.ss_sp = sigsegv_stack;
288 	ss.ss_flags = 0;
289 	if (sigaltstack(&ss, NULL) == -1) {
290 		error("sigaltstack(2) failed");
291 	}
292 
293 	for (i = 1; i < MAXTRAP; i++) {
294 		if (i == rtmin) {
295 			i = rtmax;
296 			continue;
297 		}
298 		if (sigval[i] == 0)
299 			continue;
300 		if (i != SIGSEGV && ignoring(i))
301 			continue;
302 		handle(i, sigval[i]);
303 	}
304 
305 	/*
306 	 * handle all the realtime signals
307 	 *
308 	 */
309 	for (i = rtmin; i <= rtmax; i++) {
310 		handle(i, done);
311 	}
312 }
313 
314 void
315 oldsigs()
316 {
317 	int	i;
318 	unsigned char	*t;
319 
320 	i = MAXTRAP;
321 	while (i--)
322 	{
323 		t = trapcom[i];
324 		if (t == 0 || *t)
325 			clrsig(i);
326 		trapflg[i] = 0;
327 	}
328 	trapnote = 0;
329 }
330 
331 /*
332  * check for traps
333  */
334 
335 void
336 chktrap()
337 {
338 	int	i = MAXTRAP;
339 	unsigned char	*t;
340 
341 	trapnote &= ~TRAPSET;
342 	while (--i)
343 	{
344 		if (trapflg[i] & TRAPSET)
345 		{
346 			trapflg[i] &= ~TRAPSET;
347 			if (t = trapcom[i])
348 			{
349 				int	savxit = exitval;
350 				execexp(t, 0);
351 				exitval = savxit;
352 				exitset();
353 			}
354 		}
355 	}
356 }
357 
358 void
359 systrap(int argc, char **argv)
360 {
361 	int sig;
362 
363 	if (argc == 1) {
364 		/*
365 		 * print out the current action associated with each signal
366 		 * handled by the shell
367 		 *
368 		 */
369 		for (sig = 0; sig < MAXTRAP; sig++) {
370 			if (trapcom[sig]) {
371 				prn_buff(sig);
372 				prs_buff(colon);
373 				prs_buff(trapcom[sig]);
374 				prc_buff(NL);
375 			}
376 		}
377 	} else {
378 		/*
379 		 * set the action for the list of signals
380 		 *
381 		 */
382 		char *cmd = *argv, *a1 = *(argv+1);
383 		BOOL noa1;
384 		noa1 = (str2sig(a1, &sig) == 0);
385 		if (noa1 == 0)
386 			++argv;
387 		while (*++argv) {
388 			if (str2sig(*argv, &sig) < 0 ||
389 			    sig >= MAXTRAP || sig < MINTRAP ||
390 			    sig == SIGSEGV) {
391 				failure(cmd, badtrap);
392 			} else if (noa1) {
393 				/*
394 				 * no action specifed so reset the siganl
395 				 * to its default disposition
396 				 *
397 				 */
398 				clrsig(sig);
399 			} else if (*a1) {
400 				/*
401 				 * set the action associated with the signal
402 				 * to a1
403 				 *
404 				 */
405 				if (trapflg[sig] & SIGMOD || sig == 0 ||
406 				    !ignoring(sig)) {
407 					handle(sig, fault);
408 					trapflg[sig] |= SIGMOD;
409 					replace(&trapcom[sig], a1);
410 				}
411 			} else if (handle(sig, SIG_IGN)) {
412 				/*
413 				 * set the action associated with the signal
414 				 * to SIG_IGN
415 				 *
416 				 */
417 				trapflg[sig] |= SIGMOD;
418 				replace(&trapcom[sig], a1);
419 			}
420 		}
421 	}
422 }
423 
424 void
425 sh_sleep(unsigned int ticks)
426 {
427 	sigset_t set, oset;
428 	struct sigaction act, oact;
429 
430 
431 	/*
432 	 * add SIGALRM to mask
433 	 */
434 
435 	sigemptyset(&set);
436 	sigaddset(&set, SIGALRM);
437 	sigprocmask(SIG_BLOCK, &set, &oset);
438 
439 	/*
440 	 * catch SIGALRM
441 	 */
442 
443 	sigemptyset(&act.sa_mask);
444 	act.sa_flags = 0;
445 	act.sa_handler = fault;
446 	sigaction(SIGALRM, &act, &oact);
447 
448 	/*
449 	 * start alarm and wait for signal
450 	 */
451 
452 	alarm(ticks);
453 	sleeping = 1;
454 	sigsuspend(&oset);
455 	sleeping = 0;
456 
457 	/*
458 	 * reset alarm, catcher and mask
459 	 */
460 
461 	alarm(0);
462 	sigaction(SIGALRM, &oact, NULL);
463 	sigprocmask(SIG_SETMASK, &oset, 0);
464 
465 }
466 
467 void
468 sigsegv(int sig, siginfo_t *sip, ucontext_t *uap)
469 {
470 	if (sip == (siginfo_t *)NULL) {
471 		/*
472 		 * This should never happen, but if it does this is all we
473 		 * can do. It can only happen if sigaction(2) for SIGSEGV
474 		 * has been called without SA_SIGINFO being set.
475 		 *
476 		 */
477 
478 		exit(ERROR);
479 	} else {
480 		if (sip->si_code <= 0) {
481 			/*
482 			 * If we are here then SIGSEGV must have been sent to
483 			 * us from a user process NOT as a result of an
484 			 * internal error within the shell eg
485 			 * kill -SEGV $$
486 			 * will bring us here. So do the normal thing.
487 			 *
488 			 */
489 			fault(sig);
490 		} else {
491 			/*
492 			 * If we are here then there must have been an internal
493 			 * error within the shell to generate SIGSEGV eg
494 			 * the stack is full and we cannot call any more
495 			 * functions (Remeber this signal handler is running
496 			 * on an alternate stack). So we just exit cleanly
497 			 * with an error status (no core file).
498 			 */
499 			exit(ERROR);
500 		}
501 	}
502 }
503