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