Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/ksh93/sh/fault.c
1810 views
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 <[email protected]> *
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)
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_terminate,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
675