summaryrefslogtreecommitdiff
path: root/src/cmd/ksh93/bltins/trap.c
diff options
context:
space:
mode:
authorIgor Pashev <pashev.igor@gmail.com>2012-06-24 22:28:35 +0000
committerIgor Pashev <pashev.igor@gmail.com>2012-06-24 22:28:35 +0000
commit3950ffe2a485479f6561c27364d3d7df5a21d124 (patch)
tree468c6e14449d1b1e279222ec32f676b0311917d2 /src/cmd/ksh93/bltins/trap.c
downloadksh-3950ffe2a485479f6561c27364d3d7df5a21d124.tar.gz
Imported Upstream version 93u+upstream
Diffstat (limited to 'src/cmd/ksh93/bltins/trap.c')
-rw-r--r--src/cmd/ksh93/bltins/trap.c420
1 files changed, 420 insertions, 0 deletions
diff --git a/src/cmd/ksh93/bltins/trap.c b/src/cmd/ksh93/bltins/trap.c
new file mode 100644
index 0000000..f5dbedc
--- /dev/null
+++ b/src/cmd/ksh93/bltins/trap.c
@@ -0,0 +1,420 @@
+/***********************************************************************
+* *
+* This software is part of the ast package *
+* Copyright (c) 1982-2012 AT&T Intellectual Property *
+* and is licensed under the *
+* Eclipse Public License, Version 1.0 *
+* by AT&T Intellectual Property *
+* *
+* A copy of the License is available at *
+* http://www.eclipse.org/org/documents/epl-v10.html *
+* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
+* *
+* Information and Software Systems Research *
+* AT&T Research *
+* Florham Park NJ *
+* *
+* David Korn <dgk@research.att.com> *
+* *
+***********************************************************************/
+#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(Shell_t*,const char*);
+static void sig_list(Shell_t*,int);
+
+int b_trap(int argc,char *argv[],Shbltin_t *context)
+{
+ register char *arg = argv[1];
+ register int sig, clear = 0, dflag = 0, pflag = 0;
+ register Shell_t *shp = context->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 && shp->st.self == &shp->global)
+ {
+ clear++;
+ dflag++;
+ }
+ }
+ if(!argv[0])
+ errormsg(SH_DICT,ERROR_exit(1),e_condition);
+ }
+ while(arg = *argv++)
+ {
+ sig = sig_number(shp,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->gd->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[],Shbltin_t *context)
+{
+ register char *signame;
+ register int sig=SIGTERM, flag=0, n;
+ register Shell_t *shp = context->shp;
+ NOT_USED(argc);
+ while((n = optget(argv,sh_optkill))) switch(n)
+ {
+ case ':':
+ if((signame=argv[opt_info.index++]) && (sig=sig_number(shp,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(shp,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(shp,signame)) < 0 || sig > shp->gd->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(Shell_t *shp,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_SIGBITS)))
+ {
+ /* sig prefix cannot match internal traps */
+ n = 0;
+ tp = (Shtable_t*)((char*)tp + sizeof(*shtab_signals));
+ if(strcmp(stakptr(o),tp->sh_name)==0)
+ n = tp->sh_number;
+ }
+ if((n>>SH_SIGBITS)&SH_SIGRUNTIME)
+ n = shp->gd->sigruntime[(n&((1<<SH_SIGBITS)-1))-1];
+ else
+ {
+ n &= (1<<SH_SIGBITS)-1;
+ if(n < SH_TRAP)
+ n--;
+ }
+ if(n<0 && shp->gd->sigruntime[1] && (name=stakptr(o)) && *name++=='R' && *name++=='T')
+ {
+ if(name[0]=='M' && name[1]=='I' && name[2]=='N' && name[3]=='+')
+ {
+ if((sig=(int)strtol(name+4,&name,10)) >= 0 && !*name)
+ n = shp->gd->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 = shp->gd->sigruntime[SH_SIGRTMAX] - sig;
+ }
+ else if((sig=(int)strtol(name,&name,10)) > 0 && !*name)
+ n = shp->gd->sigruntime[SH_SIGRTMIN] + sig - 1;
+ if(n<shp->gd->sigruntime[SH_SIGRTMIN] || n>shp->gd->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(Shell_t *shp,int sig, char* buf, int pfx)
+{
+ register int i;
+
+ i = 0;
+ if(sig>shp->gd->sigruntime[SH_SIGRTMIN] && sig<shp->gd->sigruntime[SH_SIGRTMAX])
+ {
+ buf[i++] = 'R';
+ buf[i++] = 'T';
+ buf[i++] = 'M';
+ if(sig>shp->gd->sigruntime[SH_SIGRTMIN]+(shp->gd->sigruntime[SH_SIGRTMAX]-shp->gd->sigruntime[SH_SIGRTMIN])/2)
+ {
+ buf[i++] = 'A';
+ buf[i++] = 'X';
+ buf[i++] = '-';
+ sig = shp->gd->sigruntime[SH_SIGRTMAX]-sig;
+ }
+ else
+ {
+ buf[i++] = 'I';
+ buf[i++] = 'N';
+ buf[i++] = '+';
+ sig = sig-shp->gd->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 <flag> is positive, then print signal name corresponding to <flag>
+ * if <flag> is zero, then print all signal names
+ * if <flag> 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->gd->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_SIGBITS)-1);
+ if (((tp->sh_number>>SH_SIGBITS) & SH_SIGRUNTIME) && (sig = shp->gd->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(shp,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->gd->sigmax || !(sname=(char*)names[sig]))
+ sname = sig_name(shp,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->gd->sigmax; sig++)
+ {
+ if(!(sname=(char*)names[sig]))
+ sname = sig_name(shp,sig,name,1);
+ sfputr(sfstdout,sname,'\n');
+ }
+ }
+}