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