1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1982-2012 AT&T Intellectual Property          *
5 *                      and is licensed under the                       *
6 *                 Eclipse Public License, Version 1.0                  *
7 *                    by AT&T Intellectual Property                     *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *          http://www.eclipse.org/org/documents/epl-v10.html           *
11 *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12 *                                                                      *
13 *              Information and Software Systems Research               *
14 *                            AT&T Research                             *
15 *                           Florham Park NJ                            *
16 *                                                                      *
17 *                  David Korn <dgk@research.att.com>                   *
18 *                                                                      *
19 ***********************************************************************/
20 #pragma prototyped
21 /*
22  * Fault handling routines
23  *
24  *   David Korn
25  *   AT&T Labs
26  *
27  */
28 
29 #include	"defs.h"
30 #include	<fcin.h>
31 #include	"io.h"
32 #include	"history.h"
33 #include	"shlex.h"
34 #include	"variables.h"
35 #include	"jobs.h"
36 #include	"path.h"
37 #include	"builtins.h"
38 #include	"ulimit.h"
39 
40 #define abortsig(sig)	(sig==SIGABRT || sig==SIGBUS || sig==SIGILL || sig==SIGSEGV)
41 
42 static char	indone;
43 static int	cursig = -1;
44 
45 #if !_std_malloc
46 #   include	<vmalloc.h>
47 #endif
48 #if  defined(VMFL) && (VMALLOC_VERSION>=20031205L)
49     /*
50      * This exception handler is called after vmalloc() unlocks the region
51      */
52     static int malloc_done(Vmalloc_t* vm, int type, Void_t* val, Vmdisc_t* dp)
53     {
54 	dp->exceptf = 0;
55 	sh_exit(SH_EXITSIG);
56 	return(0);
57     }
58 #endif
59 
60 /*
61  * Most signals caught or ignored by the shell come here
62 */
63 void	sh_fault(register int sig)
64 {
65 	register Shell_t	*shp = sh_getinterp();
66 	register int 		flag=0;
67 	register char		*trap;
68 	register struct checkpt	*pp = (struct checkpt*)shp->jmplist;
69 	int	action=0;
70 	/* reset handler */
71 	if(!(sig&SH_TRAP))
72 		signal(sig, sh_fault);
73 	sig &= ~SH_TRAP;
74 #ifdef SIGWINCH
75 	if(sig==SIGWINCH)
76 	{
77 		int rows=0, cols=0;
78 		int32_t v;
79 		astwinsize(2,&rows,&cols);
80 		if(v = cols)
81 			nv_putval(COLUMNS, (char*)&v, NV_INT32|NV_RDONLY);
82 		if(v = rows)
83 			nv_putval(LINES, (char*)&v, NV_INT32|NV_RDONLY);
84 		shp->winch++;
85 	}
86 #endif  /* SIGWINCH */
87 	trap = shp->st.trapcom[sig];
88 	if(shp->savesig)
89 	{
90 		/* critical region, save and process later */
91 		if(!(shp->sigflag[sig]&SH_SIGIGNORE))
92 			shp->savesig = sig;
93 		return;
94 	}
95 	if(sig==SIGALRM && shp->bltinfun==b_sleep)
96 	{
97 		if(trap && *trap)
98 		{
99 			shp->trapnote |= SH_SIGTRAP;
100 			shp->sigflag[sig] |= SH_SIGTRAP;
101 		}
102 		return;
103 	}
104 	if(shp->subshell && trap && sig!=SIGINT && sig!=SIGQUIT && sig!=SIGWINCH && sig!=SIGCONT)
105 	{
106 		shp->exitval = SH_EXITSIG|sig;
107 		sh_subfork();
108 		shp->exitval = 0;
109 		return;
110 	}
111 	/* handle ignored signals */
112 	if(trap && *trap==0)
113 		return;
114 	flag = shp->sigflag[sig]&~SH_SIGOFF;
115 	if(!trap)
116 	{
117 		if(sig==SIGINT && (shp->trapnote&SH_SIGIGNORE))
118 			return;
119 		if(flag&SH_SIGIGNORE)
120 		{
121 			if(shp->subshell)
122 				shp->ignsig = sig;
123 			sigrelease(sig);
124 			return;
125 		}
126 		if(flag&SH_SIGDONE)
127 		{
128 			void *ptr=0;
129 			if((flag&SH_SIGINTERACTIVE) && sh_isstate(SH_INTERACTIVE) && !sh_isstate(SH_FORKED) && ! shp->subshell)
130 			{
131 				/* check for TERM signal between fork/exec */
132 				if(sig==SIGTERM && job.in_critical)
133 					shp->trapnote |= SH_SIGTERM;
134 				return;
135 			}
136 			shp->lastsig = sig;
137 			sigrelease(sig);
138 			if(pp->mode != SH_JMPSUB)
139 			{
140 				if(pp->mode < SH_JMPSUB)
141 					pp->mode = shp->subshell?SH_JMPSUB:SH_JMPFUN;
142 				else
143 					pp->mode = SH_JMPEXIT;
144 			}
145 			if(shp->subshell)
146 				sh_exit(SH_EXITSIG);
147 			if(sig==SIGABRT || (abortsig(sig) && (ptr = malloc(1))))
148 			{
149 				if(ptr)
150 					free(ptr);
151 				sh_done(shp,sig);
152 			}
153 			/* mark signal and continue */
154 			shp->trapnote |= SH_SIGSET;
155 			if(sig <= shp->gd->sigmax)
156 				shp->sigflag[sig] |= SH_SIGSET;
157 #if  defined(VMFL) && (VMALLOC_VERSION>=20031205L)
158 			if(abortsig(sig))
159 			{
160 				/* abort inside malloc, process when malloc returns */
161 				/* VMFL defined when using vmalloc() */
162 				Vmdisc_t* dp = vmdisc(Vmregion,0);
163 				if(dp)
164 					dp->exceptf = malloc_done;
165 			}
166 #endif
167 			return;
168 		}
169 	}
170 	errno = 0;
171 	if(pp->mode==SH_JMPCMD || (pp->mode==1 && shp->bltinfun) && !(flag&SH_SIGIGNORE))
172 		shp->lastsig = sig;
173 	if(trap)
174 	{
175 		/*
176 		 * propogate signal to foreground group
177 		 */
178 		if(sig==SIGHUP && job.curpgid)
179 			killpg(job.curpgid,SIGHUP);
180 		flag = SH_SIGTRAP;
181 	}
182 	else
183 	{
184 		shp->lastsig = sig;
185 		flag = SH_SIGSET;
186 #ifdef SIGTSTP
187 		if(sig==SIGTSTP)
188 		{
189 			shp->trapnote |= SH_SIGTSTP;
190 			if(pp->mode==SH_JMPCMD && sh_isstate(SH_STOPOK))
191 			{
192 				sigrelease(sig);
193 				sh_exit(SH_EXITSIG);
194 				return;
195 			}
196 		}
197 #endif /* SIGTSTP */
198 	}
199 #ifdef ERROR_NOTIFY
200 	if((error_info.flags&ERROR_NOTIFY) && shp->bltinfun)
201 		action = (*shp->bltinfun)(-sig,(char**)0,(void*)0);
202 	if(action>0)
203 		return;
204 #endif
205 	if(shp->bltinfun && shp->bltindata.notify)
206 	{
207 		shp->bltindata.sigset = 1;
208 		return;
209 	}
210 	shp->trapnote |= flag;
211 	if(sig <= shp->gd->sigmax)
212 		shp->sigflag[sig] |= flag;
213 	if(pp->mode==SH_JMPCMD && sh_isstate(SH_STOPOK))
214 	{
215 		if(action<0)
216 			return;
217 		sigrelease(sig);
218 		sh_exit(SH_EXITSIG);
219 	}
220 }
221 
222 /*
223  * initialize signal handling
224  */
225 void sh_siginit(void *ptr)
226 {
227 	Shell_t	*shp = (Shell_t*)ptr;
228 	register int sig, n;
229 	register const struct shtable2	*tp = shtab_signals;
230 	sig_begin();
231 	/* find the largest signal number in the table */
232 #if defined(SIGRTMIN) && defined(SIGRTMAX)
233 	if ((n = SIGRTMIN) > 0 && (sig = SIGRTMAX) > n && sig < SH_TRAP)
234 	{
235 		shp->gd->sigruntime[SH_SIGRTMIN] = n;
236 		shp->gd->sigruntime[SH_SIGRTMAX] = sig;
237 	}
238 #endif /* SIGRTMIN && SIGRTMAX */
239 	n = SIGTERM;
240 	while(*tp->sh_name)
241 	{
242 		sig = (tp->sh_number&((1<<SH_SIGBITS)-1));
243 		if (!(sig-- & SH_TRAP))
244 		{
245 			if ((tp->sh_number>>SH_SIGBITS) & SH_SIGRUNTIME)
246 				sig = shp->gd->sigruntime[sig];
247 			if(sig>n && sig<SH_TRAP)
248 				n = sig;
249 		}
250 		tp++;
251 	}
252 	shp->gd->sigmax = n++;
253 	shp->st.trapcom = (char**)calloc(n,sizeof(char*));
254 	shp->sigflag = (unsigned char*)calloc(n,1);
255 	shp->gd->sigmsg = (char**)calloc(n,sizeof(char*));
256 	for(tp=shtab_signals; sig=tp->sh_number; tp++)
257 	{
258 		n = (sig>>SH_SIGBITS);
259 		if((sig &= ((1<<SH_SIGBITS)-1)) > (shp->gd->sigmax+1))
260 			continue;
261 		sig--;
262 		if(n&SH_SIGRUNTIME)
263 			sig = shp->gd->sigruntime[sig];
264 		if(sig>=0)
265 		{
266 			shp->sigflag[sig] = n;
267 			if(*tp->sh_name)
268 				shp->gd->sigmsg[sig] = (char*)tp->sh_value;
269 		}
270 	}
271 }
272 
273 /*
274  * Turn on trap handler for signal <sig>
275  */
276 void	sh_sigtrap(register int sig)
277 {
278 	register int flag;
279 	void (*fun)(int);
280 	sh.st.otrapcom = 0;
281 	if(sig==0)
282 		sh_sigdone();
283 	else if(!((flag=sh.sigflag[sig])&(SH_SIGFAULT|SH_SIGOFF)))
284 	{
285 		/* don't set signal if already set or off by parent */
286 		if((fun=signal(sig,sh_fault))==SIG_IGN)
287 		{
288 			signal(sig,SIG_IGN);
289 			flag |= SH_SIGOFF;
290 		}
291 		else
292 		{
293 			flag |= SH_SIGFAULT;
294 			if(sig==SIGALRM && fun!=SIG_DFL && fun!=sh_fault)
295 				signal(sig,fun);
296 		}
297 		flag &= ~(SH_SIGSET|SH_SIGTRAP);
298 		sh.sigflag[sig] = flag;
299 	}
300 }
301 
302 /*
303  * set signal handler so sh_done is called for all caught signals
304  */
305 void	sh_sigdone(void)
306 {
307 	register int 	flag, sig = shgd->sigmax;
308 	sh.sigflag[0] |= SH_SIGFAULT;
309 	for(sig=shgd->sigmax; sig>0; sig--)
310 	{
311 		flag = sh.sigflag[sig];
312 		if((flag&(SH_SIGDONE|SH_SIGIGNORE|SH_SIGINTERACTIVE)) && !(flag&(SH_SIGFAULT|SH_SIGOFF)))
313 			sh_sigtrap(sig);
314 	}
315 }
316 
317 /*
318  * Restore to default signals
319  * Free the trap strings if mode is non-zero
320  * If mode>1 then ignored traps cause signal to be ignored
321  */
322 void	sh_sigreset(register int mode)
323 {
324 	register char	*trap;
325 	register int 	flag, sig=sh.st.trapmax;
326 	while(sig-- > 0)
327 	{
328 		if(trap=sh.st.trapcom[sig])
329 		{
330 			flag  = sh.sigflag[sig]&~(SH_SIGTRAP|SH_SIGSET);
331 			if(*trap)
332 			{
333 				if(mode)
334 					free(trap);
335 				sh.st.trapcom[sig] = 0;
336 			}
337 			else if(sig && mode>1)
338 			{
339 				if(sig!=SIGCHLD)
340 					signal(sig,SIG_IGN);
341 				flag &= ~SH_SIGFAULT;
342 				flag |= SH_SIGOFF;
343 			}
344 			sh.sigflag[sig] = flag;
345 		}
346 	}
347 	for(sig=SH_DEBUGTRAP-1;sig>=0;sig--)
348 	{
349 		if(trap=sh.st.trap[sig])
350 		{
351 			if(mode)
352 				free(trap);
353 			sh.st.trap[sig] = 0;
354 		}
355 
356 	}
357 	sh.st.trapcom[0] = 0;
358 	if(mode)
359 		sh.st.trapmax = 0;
360 	sh.trapnote=0;
361 }
362 
363 /*
364  * free up trap if set and restore signal handler if modified
365  */
366 void	sh_sigclear(register int sig)
367 {
368 	register int flag = sh.sigflag[sig];
369 	register char *trap;
370 	sh.st.otrapcom=0;
371 	if(!(flag&SH_SIGFAULT))
372 		return;
373 	flag &= ~(SH_SIGTRAP|SH_SIGSET);
374 	if(trap=sh.st.trapcom[sig])
375 	{
376 		if(!sh.subshell)
377 			free(trap);
378 		sh.st.trapcom[sig]=0;
379 	}
380 	sh.sigflag[sig] = flag;
381 }
382 
383 /*
384  * check for traps
385  */
386 
387 void	sh_chktrap(Shell_t* shp)
388 {
389 	register int 	sig=shp->st.trapmax;
390 	register char *trap;
391 	if(!(shp->trapnote&~SH_SIGIGNORE))
392 		sig=0;
393 	shp->trapnote &= ~SH_SIGTRAP;
394 	/* execute errexit trap first */
395 	if(sh_isstate(SH_ERREXIT) && shp->exitval)
396 	{
397 		int	sav_trapnote = shp->trapnote;
398 		shp->trapnote &= ~SH_SIGSET;
399 		if(shp->st.trap[SH_ERRTRAP])
400 		{
401 			trap = shp->st.trap[SH_ERRTRAP];
402 			shp->st.trap[SH_ERRTRAP] = 0;
403 			sh_trap(trap,0);
404 			shp->st.trap[SH_ERRTRAP] = trap;
405 		}
406 		shp->trapnote = sav_trapnote;
407 		if(sh_isoption(SH_ERREXIT))
408 		{
409 			struct checkpt	*pp = (struct checkpt*)shp->jmplist;
410 			pp->mode = SH_JMPEXIT;
411 			sh_exit(shp->exitval);
412 		}
413 	}
414 	if(shp->sigflag[SIGALRM]&SH_SIGALRM)
415 		sh_timetraps(shp);
416 #ifdef SHOPT_BGX
417 	if((shp->sigflag[SIGCHLD]&SH_SIGTRAP) && shp->st.trapcom[SIGCHLD])
418 		job_chldtrap(shp,shp->st.trapcom[SIGCHLD],1);
419 #endif /* SHOPT_BGX */
420 	while(--sig>=0)
421 	{
422 		if(sig==cursig)
423 			continue;
424 #ifdef SHOPT_BGX
425 		if(sig==SIGCHLD)
426 			continue;
427 #endif /* SHOPT_BGX */
428 		if(shp->sigflag[sig]&SH_SIGTRAP)
429 		{
430 			shp->sigflag[sig] &= ~SH_SIGTRAP;
431 			if(trap=shp->st.trapcom[sig])
432 			{
433 				cursig = sig;
434  				sh_trap(trap,0);
435 				cursig = -1;
436  			}
437 		}
438 	}
439 }
440 
441 
442 /*
443  * parse and execute the given trap string, stream or tree depending on mode
444  * mode==0 for string, mode==1 for stream, mode==2 for parse tree
445  */
446 int sh_trap(const char *trap, int mode)
447 {
448 	Shell_t	*shp = sh_getinterp();
449 	int	jmpval, savxit = shp->exitval;
450 	int	was_history = sh_isstate(SH_HISTORY);
451 	int	was_verbose = sh_isstate(SH_VERBOSE);
452 	int	staktop = staktell();
453 	char	*savptr = stakfreeze(0);
454 	char	ifstable[256];
455 	struct	checkpt buff;
456 	Fcin_t	savefc;
457 	fcsave(&savefc);
458 	memcpy(ifstable,shp->ifstable,sizeof(ifstable));
459 	sh_offstate(SH_HISTORY);
460 	sh_offstate(SH_VERBOSE);
461 	shp->intrap++;
462 	sh_pushcontext(shp,&buff,SH_JMPTRAP);
463 	jmpval = sigsetjmp(buff.buff,0);
464 	if(jmpval == 0)
465 	{
466 		if(mode==2)
467 			sh_exec((Shnode_t*)trap,sh_isstate(SH_ERREXIT));
468 		else
469 		{
470 			Sfio_t *sp;
471 			if(mode)
472 				sp = (Sfio_t*)trap;
473 			else
474 				sp = sfopen(NIL(Sfio_t*),trap,"s");
475 			sh_eval(sp,0);
476 		}
477 	}
478 	else if(indone)
479 	{
480 		if(jmpval==SH_JMPSCRIPT)
481 			indone=0;
482 		else
483 		{
484 			if(jmpval==SH_JMPEXIT)
485 				savxit = shp->exitval;
486 			jmpval=SH_JMPTRAP;
487 		}
488 	}
489 	sh_popcontext(shp,&buff);
490 	shp->intrap--;
491 	sfsync(shp->outpool);
492 	if(!shp->indebug && jmpval!=SH_JMPEXIT && jmpval!=SH_JMPFUN)
493 		shp->exitval=savxit;
494 	stakset(savptr,staktop);
495 	fcrestore(&savefc);
496 	memcpy(shp->ifstable,ifstable,sizeof(ifstable));
497 	if(was_history)
498 		sh_onstate(SH_HISTORY);
499 	if(was_verbose)
500 		sh_onstate(SH_VERBOSE);
501 	exitset();
502 	if(jmpval>SH_JMPTRAP && (((struct checkpt*)shp->jmpbuffer)->prev || ((struct checkpt*)shp->jmpbuffer)->mode==SH_JMPSCRIPT))
503 		siglongjmp(*shp->jmplist,jmpval);
504 	return(shp->exitval);
505 }
506 
507 /*
508  * exit the current scope and jump to an earlier one based on pp->mode
509  */
510 void sh_exit(register int xno)
511 {
512 	Shell_t *shp = sh_getinterp();
513 	register struct checkpt	*pp = (struct checkpt*)shp->jmplist;
514 	register int		sig=0;
515 	register Sfio_t*	pool;
516 	shp->exitval=xno;
517 	if(xno==SH_EXITSIG)
518 		shp->exitval |= (sig=shp->lastsig);
519 	if(pp && pp->mode>1)
520 		cursig = -1;
521 #ifdef SIGTSTP
522 	if(shp->trapnote&SH_SIGTSTP && job.jobcontrol)
523 	{
524 		/* ^Z detected by the shell */
525 		shp->trapnote = 0;
526 		shp->sigflag[SIGTSTP] = 0;
527 		if(!shp->subshell && sh_isstate(SH_MONITOR) && !sh_isstate(SH_STOPOK))
528 			return;
529 		if(sh_isstate(SH_TIMING))
530 			return;
531 		/* Handles ^Z for shell builtins, subshells, and functs */
532 		shp->lastsig = 0;
533 		sh_onstate(SH_MONITOR);
534 		sh_offstate(SH_STOPOK);
535 		shp->trapnote = 0;
536 		shp->forked = 1;
537 		if(!shp->subshell && (sig=sh_fork(shp,0,NIL(int*))))
538 		{
539 			job.curpgid = 0;
540 			job.parent = (pid_t)-1;
541 			job_wait(sig);
542 			shp->forked = 0;
543 			job.parent = 0;
544 			shp->sigflag[SIGTSTP] = 0;
545 			/* wait for child to stop */
546 			shp->exitval = (SH_EXITSIG|SIGTSTP);
547 			/* return to prompt mode */
548 			pp->mode = SH_JMPERREXIT;
549 		}
550 		else
551 		{
552 			if(shp->subshell)
553 				sh_subfork();
554 			/* child process, put to sleep */
555 			sh_offstate(SH_STOPOK);
556 			sh_offstate(SH_MONITOR);
557 			shp->sigflag[SIGTSTP] = 0;
558 			/* stop child job */
559 			killpg(job.curpgid,SIGTSTP);
560 			/* child resumes */
561 			job_clear();
562 			shp->exitval = (xno&SH_EXITMASK);
563 			return;
564 		}
565 	}
566 #endif /* SIGTSTP */
567 	/* unlock output pool */
568 	sh_offstate(SH_NOTRACK);
569 	if(!(pool=sfpool(NIL(Sfio_t*),shp->outpool,SF_WRITE)))
570 		pool = shp->outpool; /* can't happen? */
571 	sfclrlock(pool);
572 #ifdef SIGPIPE
573 	if(shp->lastsig==SIGPIPE)
574 		sfpurge(pool);
575 #endif /* SIGPIPE */
576 	sfclrlock(sfstdin);
577 	if(!pp)
578 		sh_done(shp,sig);
579 	shp->prefix = 0;
580 #if SHOPT_TYPEDEF
581 	shp->mktype = 0;
582 #endif /* SHOPT_TYPEDEF*/
583 	if(job.in_critical)
584 		job_unlock();
585 	if(pp->mode == SH_JMPSCRIPT && !pp->prev)
586 		sh_done(shp,sig);
587 	if(pp->mode)
588 		siglongjmp(pp->buff,pp->mode);
589 }
590 
591 static void array_notify(Namval_t *np, void *data)
592 {
593 	Namarr_t	*ap = nv_arrayptr(np);
594 	NOT_USED(data);
595 	if(ap && ap->fun)
596 		(*ap->fun)(np, 0, NV_AFREE);
597 }
598 
599 /*
600  * This is the exit routine for the shell
601  */
602 
603 void sh_done(void *ptr, register int sig)
604 {
605 	Shell_t	*shp = (Shell_t*)ptr;
606 	register char *t;
607 	register int savxit = shp->exitval;
608 	shp->trapnote = 0;
609 	indone=1;
610 	if(sig)
611 		savxit = SH_EXITSIG|sig;
612 	if(shp->userinit)
613 		(*shp->userinit)(shp, -1);
614 	if(t=shp->st.trapcom[0])
615 	{
616 		shp->st.trapcom[0]=0; /*should free but not long */
617 		shp->oldexit = savxit;
618 		sh_trap(t,0);
619 		savxit = shp->exitval;
620 	}
621 	else
622 	{
623 		/* avoid recursive call for set -e */
624 		sh_offstate(SH_ERREXIT);
625 		sh_chktrap(shp);
626 	}
627 	nv_scan(shp->var_tree,array_notify,(void*)0,NV_ARRAY,NV_ARRAY);
628 	sh_freeup(shp);
629 #if SHOPT_ACCT
630 	sh_accend();
631 #endif	/* SHOPT_ACCT */
632 #if SHOPT_VSH || SHOPT_ESH
633 	if(mbwide()||sh_isoption(SH_EMACS)||sh_isoption(SH_VI)||sh_isoption(SH_GMACS))
634 		tty_cooked(-1);
635 #endif
636 #ifdef JOBS
637 	if((sh_isoption(SH_INTERACTIVE) && shp->login_sh) || (!sh_isoption(SH_INTERACTIVE) && (sig==SIGHUP)))
638 		job_walk(sfstderr, job_hup, SIGHUP, NIL(char**));
639 #endif	/* JOBS */
640 	job_close(shp);
641 	if(nv_search("VMTRACE", shp->var_tree,0))
642 		strmatch((char*)0,(char*)0);
643 	sfsync((Sfio_t*)sfstdin);
644 	sfsync((Sfio_t*)shp->outpool);
645 	sfsync((Sfio_t*)sfstdout);
646 	if(savxit&SH_EXITSIG)
647 		sig = savxit&SH_EXITMASK;
648 	if(sig)
649 	{
650 		/* generate fault termination code */
651 		if(RLIMIT_CORE!=RLIMIT_UNKNOWN)
652 		{
653 #ifdef _lib_getrlimit
654 			struct rlimit rlp;
655 			getrlimit(RLIMIT_CORE,&rlp);
656 			rlp.rlim_cur = 0;
657 			setrlimit(RLIMIT_CORE,&rlp);
658 #else
659 			vlimit(RLIMIT_CORE,0);
660 #endif
661 		}
662 		signal(sig,SIG_DFL);
663 		sigrelease(sig);
664 		kill(getpid(),sig);
665 		pause();
666 	}
667 #if SHOPT_KIA
668 	if(sh_isoption(SH_NOEXEC))
669 		kiaclose((Lex_t*)shp->lex_context);
670 #endif /* SHOPT_KIA */
671 	exit(savxit&SH_EXITMASK);
672 }
673 
674