Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / programs / dtksh / ksh93 / src / cmd / ksh93 / sh / fault.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $XConsortium: fault.c /main/4 1996/08/16 15:31:41 rswiston $ */
24 /***************************************************************
25 *                                                              *
26 *                      AT&T - PROPRIETARY                      *
27 *                                                              *
28 *        THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF        *
29 *                    AT&T BELL LABORATORIES                    *
30 *         AND IS NOT TO BE DISCLOSED OR USED EXCEPT IN         *
31 *            ACCORDANCE WITH APPLICABLE AGREEMENTS             *
32 *                                                              *
33 *                Copyright (c) 1995 AT&T Corp.                 *
34 *              Unpublished & Not for Publication               *
35 *                     All Rights Reserved                      *
36 *                                                              *
37 *       The copyright notice above does not evidence any       *
38 *      actual or intended publication of such source code      *
39 *                                                              *
40 *               This software was created by the               *
41 *           Advanced Software Technology Department            *
42 *                    AT&T Bell Laboratories                    *
43 *                                                              *
44 *               For further information contact                *
45 *                    {research,attmail}!dgk                    *
46 *                                                              *
47 ***************************************************************/
48
49 /* : : generated by proto : : */
50
51 #if !defined(__PROTO__)
52 #if defined(__STDC__) || defined(__cplusplus) || defined(_proto) || defined(c_plusplus)
53 #if defined(__cplusplus)
54 #define __MANGLE__      "C"
55 #else
56 #define __MANGLE__
57 #endif
58 #define __STDARG__
59 #define __PROTO__(x)    x
60 #define __OTORP__(x)
61 #define __PARAM__(n,o)  n
62 #if !defined(__STDC__) && !defined(__cplusplus)
63 #if !defined(c_plusplus)
64 #define const
65 #endif
66 #define signed
67 #define void            int
68 #define volatile
69 #define __V_            char
70 #else
71 #define __V_            void
72 #endif
73 #else
74 #define __PROTO__(x)    ()
75 #define __OTORP__(x)    x
76 #define __PARAM__(n,o)  o
77 #define __MANGLE__
78 #define __V_            char
79 #define const
80 #define signed
81 #define void            int
82 #define volatile
83 #endif
84 #if defined(__cplusplus) || defined(c_plusplus)
85 #define __VARARG__      ...
86 #else
87 #define __VARARG__
88 #endif
89 #if defined(__STDARG__)
90 #define __VA_START__(p,a)       va_start(p,a)
91 #else
92 #define __VA_START__(p,a)       va_start(p)
93 #endif
94 #endif
95 #include        "defs.h"
96 #include        <fcin.h>
97 #include        "io.h"
98 #include        "history.h"
99 #include        "shnodes.h"
100 #include        "jobs.h"
101 #include        "path.h"
102
103 static char     setdone;
104 static char     indone;
105
106 /*
107  * Most signals caught or ignored by the shell come here
108 */
109 void    sh_fault __PARAM__((register int sig), (sig)) __OTORP__(register int sig;){
110         register int    flag;
111         register char   *trap;
112         register struct checkpt *pp = (struct checkpt*)sh.jmplist;
113         /* reset handler */
114         signal(sig, sh_fault);
115         /* handle ignored signals */
116         if((trap=sh.st.trapcom[sig]) && *trap==0)
117                 return;
118         flag = sh.sigflag[sig];
119         if(!trap)
120         {
121                 if(flag&SH_SIGIGNORE)
122                         return;
123                 if(flag&SH_SIGDONE)
124                 {
125                         if((flag&SH_SIGINTERACTIVE) && sh_isstate(SH_INTERACTIVE) && !sh_isstate(SH_FORKED) && ! sh.subshell)
126                                 return;
127                         sh.lastsig = sig;
128                         sigrelease(sig);
129                         if(pp->mode < SH_JMPFUN)
130                                 pp->mode = SH_JMPFUN;
131                         else
132                                 pp->mode = SH_JMPEXIT;
133                         sh_exit(SH_EXITSIG);
134                 }
135         }
136         errno = 0;
137         if(pp->mode==SH_JMPCMD)
138                 sh.lastsig = sig;
139         if(trap)
140         {
141                 /*
142                  * propogage signal to foreground group
143                  */
144                 if(sig==SIGHUP && job.curpgid)
145                         killpg(job.curpgid,SIGHUP);
146                 flag = SH_SIGTRAP;
147         }
148         else
149         {
150                 sh.lastsig = sig;
151                 flag = SH_SIGSET;
152 #ifdef SIGTSTP
153                 if(sig==SIGTSTP)
154                 {
155                         sh.trapnote |= SH_SIGTSTP;
156                         if(pp->mode==SH_JMPCMD && sh_isstate(SH_STOPOK))
157                         {
158                                 sigrelease(sig);
159                                 sh_exit(SH_EXITSIG);
160                                 flag = 0;
161                         }
162                 }
163 #endif /* SIGTSTP */
164         }
165         sh.trapnote |= flag;
166         if(sig < sh.sigmax)
167                 sh.sigflag[sig] |= flag;
168         if(pp->mode==SH_JMPCMD && sh_isstate(SH_STOPOK))
169         {
170                 sigrelease(sig);
171                 sh_exit(SH_EXITSIG);
172         }
173 }
174
175 /*
176  * initialize signal handling
177  */
178 void sh_siginit __PARAM__((void), ()){
179         register int sig, n=SIGTERM+1;
180         register const struct shtable2  *tp = shtab_signals;
181         init_shtab_signals();
182         sig_begin();
183         /* find the largest signal number in the table */
184         while(*tp->sh_name)
185         {
186                 if((sig=tp->sh_number&((1<<SH_SIGBITS)-1))>n && sig<SH_TRAP)
187                         n = sig;
188                 tp++;
189         }
190         sh.sigmax = n;
191         sh.st.trapcom = (char**)calloc(n,sizeof(char*));
192         sh.sigflag = (unsigned char*)calloc(n,1);
193         sh.sigmsg = (char**)calloc(n,sizeof(char*));
194         for(tp=shtab_signals; sig=tp->sh_number; tp++)
195         {
196                 n = (sig>>SH_SIGBITS);
197                 if((sig &= ((1<<SH_SIGBITS)-1)) > sh.sigmax)
198                         continue;
199                 sig--;
200 #if defined(_SC_SIGRT_MIN) && defined(_SIGRTMIN)
201                 if(sig==_SIGRTMIN)
202                         sig = SIGRTMIN;
203 #endif
204 #if defined(_SC_SIGRT_MAX) && defined(_SIGRTMAX)
205                 if(sig==_SIGRTMAX)
206                         sig = SIGRTMAX;
207 #endif
208                 sh.sigflag[sig] = n;
209                 if(*tp->sh_name)
210                         sh.sigmsg[sig] = (char*)tp->sh_value;
211         }
212 }
213
214 /*
215  * Turn on trap handler for signal <sig>
216  */
217 void    sh_sigtrap __PARAM__((register int sig), (sig)) __OTORP__(register int sig;){
218         register int flag;
219         sh.st.otrapcom = 0;
220         if(sig==0)
221                 sh_sigdone();
222         else if(!((flag=sh.sigflag[sig])&(SH_SIGFAULT|SH_SIGOFF)))
223         {
224                 /* don't set signal if already set or off by parent */
225                 if(signal(sig,sh_fault)==SIG_IGN) 
226                 {
227                         signal(sig,SIG_IGN);
228                         flag |= SH_SIGOFF;
229                 }
230                 else
231                         flag |= SH_SIGFAULT;
232                 flag &= ~(SH_SIGSET|SH_SIGTRAP);
233                 sh.sigflag[sig] = flag;
234         }
235 }
236
237 /*
238  * set signal handler so sh_done is called for all caught signals
239  */
240 void    sh_sigdone __PARAM__((void), ()){
241         register int    flag, sig = sh.sigmax;
242         setdone=1;
243         sh.sigflag[0] |= SH_SIGFAULT;
244         while(--sig>0)
245         {
246                 flag = sh.sigflag[sig];
247                 if((flag&(SH_SIGDONE|SH_SIGIGNORE|SH_SIGINTERACTIVE)) && !(flag&(SH_SIGFAULT|SH_SIGOFF)))
248                         sh_sigtrap(sig);
249         }
250 }
251
252 /*
253  * Restore to default signals
254  * Free the trap strings if mode is non-zero
255  * If mode>1 then ignored traps cause signal to be ignored 
256  */
257 void    sh_sigreset __PARAM__((register int mode), (mode)) __OTORP__(register int mode;){
258         register char   *trap;
259         register int    flag, sig=sh.st.trapmax;
260         while(sig-- > 0)
261         {
262                 if(trap=sh.st.trapcom[sig])
263                 {
264                         flag  = sh.sigflag[sig]&~(SH_SIGTRAP|SH_SIGSET);
265                         if(*trap)
266                         {
267                                 if(mode)
268                                         free(trap);
269                                 sh.st.trapcom[sig] = 0;
270                         }
271                         else if(sig && mode>1)
272                         {
273                                 signal(sig,SIG_IGN);
274                                 flag &= ~SH_SIGFAULT;
275                                 flag |= SH_SIGOFF;
276                         }
277                         sh.sigflag[sig] = flag;
278                 }
279         }
280         for(sig=SH_DEBUGTRAP;sig>=0;sig--)
281         {
282                 if(trap=sh.st.trap[sig])
283                 {
284                         if(mode)
285                                 free(trap);
286                         sh.st.trap[sig] = 0;
287                 }
288                 
289         }
290         sh.st.trapcom[0] = 0;
291         if(mode)
292                 sh.st.trapmax = 0;
293         sh.trapnote=0;
294 }
295
296 /*
297  * free up trap if set and restore signal handler if modified
298  */
299 void    sh_sigclear __PARAM__((register int sig), (sig)) __OTORP__(register int sig;){
300         register int flag = sh.sigflag[sig];
301         register char *trap;
302         sh.st.otrapcom=0;
303         if(!(flag&SH_SIGFAULT))
304                 return;
305         flag &= ~(SH_SIGTRAP|SH_SIGSET);
306         if(trap=sh.st.trapcom[sig])
307         {
308                 free(trap);
309                 sh.st.trapcom[sig]=0;
310         }
311         sh.sigflag[sig] = flag;
312 }
313
314 /*
315  * check for traps
316  */
317
318 void    sh_chktrap __PARAM__((void), ()){
319         register int    sig=sh.st.trapmax;
320         register char *trap;
321         if(!sh.trapnote)
322                 sig=0;
323         sh.trapnote &= ~SH_SIGTRAP;
324         /* execute errexit trap first */
325         if(sh_isstate(SH_ERREXIT) && sh.exitval)
326         {
327                 int     sav_trapnote = sh.trapnote;
328                 sh.trapnote &= ~SH_SIGSET;
329                 if(sh.st.trap[SH_ERRTRAP])
330                         sh_trap(sh.st.trap[SH_ERRTRAP],0);
331                 sh.trapnote = sav_trapnote;
332                 if(sh_isoption(SH_ERREXIT))
333                 {
334                         struct checkpt  *pp = (struct checkpt*)sh.jmplist;
335                         pp->mode = SH_JMPEXIT;
336                         sh_exit(sh.exitval);
337                 }
338         }
339         if(sh.sigflag[SIGALRM]&SH_SIGTRAP)
340                 sh_timetraps();
341         while(--sig>=0)
342         {
343                 if(sh.sigflag[sig]&SH_SIGTRAP)
344                 {
345                         sh.sigflag[sig] &= ~SH_SIGTRAP;
346                         if(trap=sh.st.trapcom[sig])
347                                 sh_trap(trap,0);
348                 }
349         }
350 }
351
352
353 /*
354  * parse and execute the given trap string or tree if mode!=0
355  */
356 int sh_trap __PARAM__((const char *trap, int mode), (trap, mode)) __OTORP__(const char *trap; int mode;){
357         int     jmpval, savxit = sh.exitval;
358         int     save_states= sh_isstate(SH_HISTORY|SH_VERBOSE);
359         int     staktop = staktell();
360         char    *savptr = stakfreeze(0);
361         struct  checkpt buff;
362         Fcin_t  savefc;
363         fcsave(&savefc);
364         sh_offstate(SH_HISTORY|SH_VERBOSE);
365         sh.intrap++;
366         sh_pushcontext(&buff,SH_JMPTRAP);
367         jmpval = sigsetjmp(buff.buff,0);
368         if(jmpval == 0)
369         {
370                 if(mode)
371                         sh_exec((union anynode*)trap,sh_isstate(SH_ERREXIT));
372                 else
373                         sh_eval(sfopen(NIL(Sfio_t*),trap,"s"),0);
374         }
375         else if(indone)
376         {
377                 if(jmpval==SH_JMPSCRIPT)
378                         indone=0;
379                 else
380                 {
381                         if(jmpval==SH_JMPEXIT)
382                                 savxit = sh.exitval;
383                         jmpval=SH_JMPTRAP;
384                 }
385         }
386         sh_popcontext(&buff);
387         sh.intrap--;
388         sfsync(sh.outpool);
389         if(jmpval!=SH_JMPEXIT && jmpval!=SH_JMPFUN)
390                 sh.exitval=savxit;
391         stakset(savptr,staktop);
392         fcrestore(&savefc);
393         sh_onstate(save_states);
394         exitset();
395         if(jmpval>SH_JMPTRAP)
396                 siglongjmp(*sh.jmplist,jmpval);
397         return(sh.exitval);
398 }
399
400
401 /*
402  * exit the current scope and jump to an earlier one based on pp->mode
403  */
404 void sh_exit __PARAM__((register int xno), (xno)) __OTORP__(register int xno;){
405         register struct checkpt *pp = (struct checkpt*)sh.jmplist;
406         register int            sig=0;
407         sh.exitval=xno;
408         if(xno==SH_EXITSIG)
409                 sh.exitval |= (sig=sh.lastsig);
410 #ifdef SIGTSTP
411         if(sh.trapnote&SH_SIGTSTP)
412         {
413                 /* ^Z detected by the shell */
414                 sh.trapnote = 0;
415                 sh.sigflag[SIGTSTP] = 0;
416                 if(!sh.subshell && sh_isstate(SH_MONITOR) && !sh_isstate(SH_STOPOK))
417                         return;
418                 if(sh_isstate(SH_TIMING))
419                         return;
420                 /* Handles ^Z for shell builtins, subshells, and functs */
421                 sh.lastsig = 0;
422                 sh_onstate(SH_MONITOR);
423                 sh_offstate(SH_STOPOK);
424                 sh.trapnote = 0;
425                 if(!sh.subshell && (sig=sh_fork(0,NIL(int*))))
426                 {
427                         job.curpgid = 0;
428                         job.parent = (pid_t)-1;
429                         job_wait(sig);
430                         job.parent = 0;
431                         sh.sigflag[SIGTSTP] = 0;
432                         /* wait for child to stop */
433                         sh.exitval = (SH_EXITSIG|SIGTSTP);
434                         /* return to prompt mode */
435                         pp->mode = SH_JMPERREXIT;
436                 }
437                 else
438                 {
439                         if(sh.subshell)
440                                 sh_subfork();
441                         /* child process, put to sleep */
442                         sh_offstate(SH_MONITOR|SH_STOPOK);
443                         sh.sigflag[SIGTSTP] = 0;
444                         /* stop child job */
445                         killpg(job.curpgid,SIGTSTP);
446                         /* child resumes */
447                         job_clear();
448                         sh.forked = 1;
449                         sh.exitval = (xno&SH_EXITMASK);
450                         return;
451                 }
452         }
453 #endif /* SIGTSTP */
454         /* unlock output pool */
455         sh_offstate(SH_NOTRACK);
456         sfclrlock(sfpool(NIL(Sfio_t*),sh.outpool,SF_WRITE));
457 #ifdef SIGPIPE
458         if(sh.lastsig==SIGPIPE)
459                 sfpurge(sfpool(NIL(Sfio_t*),sh.outpool,SF_WRITE));
460 #endif /* SIGPIPE */
461         sfclrlock(sfstdin);
462         if(!pp)
463                 sh_done(sig);
464         sh.prefix = 0;
465         if(pp->mode == SH_JMPSCRIPT && !pp->prev) 
466                 sh_done(sig);
467         siglongjmp(pp->buff,pp->mode);
468 }
469
470 /*
471  * This is the exit routine for the shell
472  */
473
474 void sh_done __PARAM__((register int sig), (sig)) __OTORP__(register int sig;){
475         register char *t;
476         register int savxit = sh.exitval;
477         sh.trapnote = 0;
478         indone=1;
479         if(sig==0)
480                 sig = sh.lastsig;
481         if(t=sh.st.trapcom[0])
482         {
483                 sh.st.trapcom[0]=0; /*should free but not long */
484                 sh.oldexit = savxit;
485                 sh_trap(t,0);
486                 savxit = sh.exitval;
487         }
488         else
489         {
490                 /* avoid recursive call for set -e */
491                 sh_offstate(SH_ERREXIT);
492                 sh_chktrap();
493         }
494         sh_freeup();
495 #ifdef SHOPT_ACCT
496         sh_accend();
497 #endif  /* SHOPT_ACCT */
498 #if SHOPT_VSH || SHOPT_ESH
499         if(sh_isoption(SH_EMACS|SH_VI|SH_GMACS))
500                 tty_cooked(-1);
501 #endif
502 #ifdef JOBS
503         if((sh_isoption(SH_INTERACTIVE) && sh.login_sh) || (!sh_isoption(SH_INTERACTIVE) && (sig==SIGHUP)))
504                 job_walk(sfstderr,job_terminate,SIGHUP,NIL(char**));
505 #endif  /* JOBS */
506         job_close();
507         sfsync((Sfio_t*)sfstdin);
508         sfsync((Sfio_t*)sh.outpool);
509         sfsync((Sfio_t*)sfstdout);
510         if(sig)
511         {
512                 /* generate fault termination code */
513                 signal(sig,SIG_DFL);
514                 sigrelease(sig);
515                 kill(getpid(),sig);
516                 pause();
517         }
518 #ifdef SHOPT_KIA
519         if(sh_isoption(SH_NOEXEC))
520                 kiaclose();
521 #endif /* SHOPT_KIA */
522         exit(savxit&SH_EXITMASK);
523 }
524