/*********************************************************************** * * * This software is part of the ast package * * Copyright (c) 1982-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * * * * Information and Software Systems Research * * AT&T Research * * Florham Park NJ * * * * David Korn * * * ***********************************************************************/ #pragma prototyped /* * trap [-p] action sig... * kill [-l] [sig...] * kill [-s sig] pid... * * David Korn * AT&T Labs * research!dgk * */ #include "defs.h" #include "jobs.h" #include "builtins.h" #define L_FLAG 1 #define S_FLAG 2 static const char trapfmt[] = "trap -- %s %s\n"; static int sig_number(const char*); static void sig_list(Shell_t*,int); int b_trap(int argc,char *argv[],void *extra) { register char *arg = argv[1]; register int sig, clear = 0, dflag = 0, pflag = 0; register Shell_t *shp = ((Shbltin_t*)extra)->shp; NOT_USED(argc); while (sig = optget(argv, sh_opttrap)) switch (sig) { case 'p': pflag=1; break; case ':': errormsg(SH_DICT,2, "%s", opt_info.arg); break; case '?': errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg); return(2); break; } argv += opt_info.index; if(error_info.errors) errormsg(SH_DICT,ERROR_usage(2),"%s", optusage((char*)0)); if(arg = *argv) { char *action = arg; if(!dflag && !pflag) { /* first argument all digits or - means clear */ while(isdigit(*arg)) arg++; clear = (arg!=action && *arg==0); if(!clear) { ++argv; if(*action=='-' && action[1]==0) clear++; /* * NOTE: 2007-11-26: workaround for tests/signal.sh * if function semantics can be worked out then it * may merit a -d,--default option */ else if(*action=='+' && action[1]==0 && sh.st.self == &sh.global) { clear++; dflag++; } } if(!argv[0]) errormsg(SH_DICT,ERROR_exit(1),e_condition); } while(arg = *argv++) { sig = sig_number(arg); if(sig<0) { errormsg(SH_DICT,2,e_trap,arg); return(1); } /* internal traps */ if(sig&SH_TRAP) { sig &= ~SH_TRAP; if(sig>SH_DEBUGTRAP) { errormsg(SH_DICT,2,e_trap,arg); return(1); } if(pflag) { if(arg=shp->st.trap[sig]) sfputr(sfstdout,sh_fmtq(arg),'\n'); continue; } if(shp->st.trap[sig]) free(shp->st.trap[sig]); shp->st.trap[sig] = 0; if(!clear && *action) shp->st.trap[sig] = strdup(action); if(sig == SH_DEBUGTRAP) { if(shp->st.trap[sig]) shp->trapnote |= SH_SIGTRAP; else shp->trapnote = 0; } continue; } if(sig>shp->sigmax) { errormsg(SH_DICT,2,e_trap,arg); return(1); } else if(pflag) { char **trapcom = (shp->st.otrapcom?shp->st.otrapcom:shp->st.trapcom); if(arg=trapcom[sig]) sfputr(sfstdout,arg,'\n'); } else if(clear) { sh_sigclear(sig); if(dflag) signal(sig,SIG_DFL); } else { if(sig >= shp->st.trapmax) shp->st.trapmax = sig+1; arg = shp->st.trapcom[sig]; sh_sigtrap(sig); shp->st.trapcom[sig] = (shp->sigflag[sig]&SH_SIGOFF) ? Empty : strdup(action); if(arg && arg != Empty) free(arg); } } } else /* print out current traps */ sig_list(shp,-1); return(0); } int b_kill(int argc,char *argv[],void *extra) { register char *signame; register int sig=SIGTERM, flag=0, n; register Shell_t *shp = ((Shbltin_t*)extra)->shp; NOT_USED(argc); while((n = optget(argv,sh_optkill))) switch(n) { case ':': if((signame=argv[opt_info.index++]) && (sig=sig_number(signame+1))>=0) goto endopts; opt_info.index--; errormsg(SH_DICT,2, "%s", opt_info.arg); break; case 'n': sig = (int)opt_info.num; goto endopts; case 's': flag |= S_FLAG; signame = opt_info.arg; goto endopts; case 'l': flag |= L_FLAG; break; case '?': errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg); break; } endopts: argv += opt_info.index; if(*argv && strcmp(*argv,"--")==0 && strcmp(*(argv-1),"--")!=0) argv++; if(error_info.errors || flag==(L_FLAG|S_FLAG) || (!(*argv) && !(flag&L_FLAG))) errormsg(SH_DICT,ERROR_usage(2),"%s", optusage((char*)0)); /* just in case we send a kill -9 $$ */ sfsync(sfstderr); if(flag&L_FLAG) { if(!(*argv)) sig_list(shp,0); else while(signame = *argv++) { if(isdigit(*signame)) sig_list(shp,((int)strtol(signame, (char**)0, 10)&0177)+1); else { if((sig=sig_number(signame))<0) { shp->exitval = 2; errormsg(SH_DICT,ERROR_exit(1),e_nosignal,signame); } sfprintf(sfstdout,"%d\n",sig); } } return(shp->exitval); } if(flag&S_FLAG) { if((sig=sig_number(signame)) < 0 || sig > shp->sigmax) errormsg(SH_DICT,ERROR_exit(1),e_nosignal,signame); } if(job_walk(sfstdout,job_kill,sig,argv)) shp->exitval = 1; return(shp->exitval); } /* * Given the name or number of a signal return the signal number */ static int sig_number(const char *string) { const Shtable_t *tp; register int n,o,sig=0; char *last, *name; if(isdigit(*string)) { n = strtol(string,&last,10); if(*last) n = -1; } else { register int c; o = staktell(); do { c = *string++; if(islower(c)) c = toupper(c); stakputc(c); } while(c); stakseek(o); if(memcmp(stakptr(o),"SIG",3)==0) { sig = 1; o += 3; if(isdigit(*stakptr(o))) { n = strtol(stakptr(o),&last,10); if(!*last) return(n); } } tp = sh_locate(stakptr(o),(const Shtable_t*)shtab_signals,sizeof(*shtab_signals)); n = tp->sh_number; if(sig==1 && (n>=(SH_TRAP-1) && n < (1<sh_name)==0) n = tp->sh_number; } if((n>>SH_SIGBITS)&SH_SIGRUNTIME) n = sh.sigruntime[(n&((1<= 0 && !*name) n = sh.sigruntime[SH_SIGRTMIN] + sig; } else if(name[0]=='M' && name[1]=='A' && name[2]=='X' && name[3]=='-') { if((sig=(int)strtol(name+4,&name,10)) >= 0 && !*name) n = sh.sigruntime[SH_SIGRTMAX] - sig; } else if((sig=(int)strtol(name,&name,10)) > 0 && !*name) n = sh.sigruntime[SH_SIGRTMIN] + sig - 1; if(nsh.sigruntime[SH_SIGRTMAX]) n = -1; } } return(n); } /* * synthesize signal name for sig in buf * pfx!=0 prepends SIG to default signal number */ static char* sig_name(int sig, char* buf, int pfx) { register int i; i = 0; if(sig>sh.sigruntime[SH_SIGRTMIN] && sigsh.sigruntime[SH_SIGRTMIN]+(sh.sigruntime[SH_SIGRTMAX]-sh.sigruntime[SH_SIGRTMIN])/2) { buf[i++] = 'A'; buf[i++] = 'X'; buf[i++] = '-'; sig = sh.sigruntime[SH_SIGRTMAX]-sig; } else { buf[i++] = 'I'; buf[i++] = 'N'; buf[i++] = '+'; sig = sig-sh.sigruntime[SH_SIGRTMIN]; } } else if(pfx) { buf[i++] = 'S'; buf[i++] = 'I'; buf[i++] = 'G'; } i += sfsprintf(buf+i, 8, "%d", sig); buf[i] = 0; return buf; } /* * if is positive, then print signal name corresponding to * if is zero, then print all signal names * if is negative, then print all traps */ static void sig_list(register Shell_t *shp,register int flag) { register const struct shtable2 *tp; register int sig; register char *sname; char name[10]; const char *names[SH_TRAP]; const char *traps[SH_DEBUGTRAP+1]; tp=shtab_signals; if(flag<=0) { /* not all signals may be defined, so initialize */ for(sig=shp->sigmax; sig>=0; sig--) names[sig] = 0; for(sig=SH_DEBUGTRAP; sig>=0; sig--) traps[sig] = 0; } for(; *tp->sh_name; tp++) { sig = tp->sh_number&((1<sh_number>>SH_SIGBITS) & SH_SIGRUNTIME) && (sig = sh.sigruntime[sig-1]+1) == 1) continue; if(sig==flag) { sfprintf(sfstdout,"%s\n",tp->sh_name); return; } else if(sig&SH_TRAP) traps[sig&~SH_TRAP] = (char*)tp->sh_name; else if(sig-- && sig < elementsof(names)) names[sig] = (char*)tp->sh_name; } if(flag > 0) sfputr(sfstdout, sig_name(flag-1,name,0), '\n'); else if(flag<0) { /* print the traps */ register char *trap,**trapcom; sig = shp->st.trapmax; /* use parent traps if otrapcom is set (for $(trap) */ trapcom = (shp->st.otrapcom?shp->st.otrapcom:shp->st.trapcom); while(--sig >= 0) { if(!(trap=trapcom[sig])) continue; if(sig > shp->sigmax || !(sname=(char*)names[sig])) sname = sig_name(sig,name,1); sfprintf(sfstdout,trapfmt,sh_fmtq(trap),sname); } for(sig=SH_DEBUGTRAP; sig>=0; sig--) { if(!(trap=shp->st.trap[sig])) continue; sfprintf(sfstdout,trapfmt,sh_fmtq(trap),traps[sig]); } } else { /* print all the signal names */ for(sig=1; sig <= shp->sigmax; sig++) { if(!(sname=(char*)names[sig])) sname = sig_name(sig,name,1); sfputr(sfstdout,sname,'\n'); } } }