14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*8462SApril.Chin@Sun.COM *          Copyright (c) 1982-2008 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
7*8462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
84887Schin *                                                                      *
94887Schin *                A copy of the License is available at                 *
104887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
114887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
124887Schin *                                                                      *
134887Schin *              Information and Software Systems Research               *
144887Schin *                            AT&T Research                             *
154887Schin *                           Florham Park NJ                            *
164887Schin *                                                                      *
174887Schin *                  David Korn <dgk@research.att.com>                   *
184887Schin *                                                                      *
194887Schin ***********************************************************************/
204887Schin #pragma prototyped
214887Schin /*
224887Schin  * trap  [-p]  action sig...
234887Schin  * kill  [-l] [sig...]
244887Schin  * kill  [-s sig] pid...
254887Schin  *
264887Schin  *   David Korn
274887Schin  *   AT&T Labs
284887Schin  *   research!dgk
294887Schin  *
304887Schin  */
314887Schin 
324887Schin #include	"defs.h"
334887Schin #include	<ctype.h>
344887Schin #include	"jobs.h"
354887Schin #include	"builtins.h"
364887Schin 
374887Schin #define L_FLAG	1
384887Schin #define S_FLAG	2
394887Schin 
404887Schin static const char trapfmt[] = "trap -- %s %s\n";
414887Schin 
424887Schin static int	sig_number(const char*);
434887Schin static void	sig_list(Shell_t*,int);
444887Schin 
454887Schin int	b_trap(int argc,char *argv[],void *extra)
464887Schin {
474887Schin 	register char *arg = argv[1];
48*8462SApril.Chin@Sun.COM 	register int sig, clear = 0, dflag = 0, pflag = 0;
49*8462SApril.Chin@Sun.COM 	register Shell_t *shp = ((Shbltin_t*)extra)->shp;
504887Schin 	NOT_USED(argc);
514887Schin 	while (sig = optget(argv, sh_opttrap)) switch (sig)
524887Schin 	{
534887Schin 	    case 'p':
544887Schin 		pflag=1;
554887Schin 		break;
564887Schin 	    case ':':
574887Schin 		errormsg(SH_DICT,2, "%s", opt_info.arg);
584887Schin 		break;
594887Schin 	    case '?':
604887Schin 		errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg);
614887Schin 		return(2);
624887Schin 		break;
634887Schin 	}
644887Schin 	argv += opt_info.index;
654887Schin 	if(error_info.errors)
664887Schin 		errormsg(SH_DICT,ERROR_usage(2),"%s", optusage((char*)0));
674887Schin 	if(arg = *argv)
684887Schin 	{
694887Schin 		char *action = arg;
70*8462SApril.Chin@Sun.COM 		if(!dflag && !pflag)
714887Schin 		{
724887Schin 			/* first argument all digits or - means clear */
734887Schin 			while(isdigit(*arg))
744887Schin 				arg++;
754887Schin 			clear = (arg!=action && *arg==0);
764887Schin 			if(!clear)
774887Schin 			{
784887Schin 				++argv;
794887Schin 				if(*action=='-' && action[1]==0)
804887Schin 					clear++;
81*8462SApril.Chin@Sun.COM 				/*
82*8462SApril.Chin@Sun.COM 				 * NOTE: 2007-11-26: workaround for tests/signal.sh
83*8462SApril.Chin@Sun.COM 				 * if function semantics can be worked out then it
84*8462SApril.Chin@Sun.COM 				 * may merit a -d,--default option
85*8462SApril.Chin@Sun.COM 				 */
86*8462SApril.Chin@Sun.COM 				else if(*action=='+' && action[1]==0 && sh.st.self == &sh.global)
87*8462SApril.Chin@Sun.COM 				{
88*8462SApril.Chin@Sun.COM 					clear++;
89*8462SApril.Chin@Sun.COM 					dflag++;
90*8462SApril.Chin@Sun.COM 				}
914887Schin 			}
92*8462SApril.Chin@Sun.COM 			if(!argv[0])
934887Schin 				errormsg(SH_DICT,ERROR_exit(1),e_condition);
944887Schin 		}
954887Schin 		while(arg = *argv++)
964887Schin 		{
974887Schin 			sig = sig_number(arg);
984887Schin 			if(sig<0)
994887Schin 			{
1004887Schin 				errormsg(SH_DICT,2,e_trap,arg);
1014887Schin 				return(1);
1024887Schin 			}
1034887Schin 			/* internal traps */
1044887Schin 			if(sig&SH_TRAP)
1054887Schin 			{
1064887Schin 				sig &= ~SH_TRAP;
1074887Schin 				if(sig>SH_DEBUGTRAP)
1084887Schin 				{
1094887Schin 					errormsg(SH_DICT,2,e_trap,arg);
1104887Schin 					return(1);
1114887Schin 				}
1124887Schin 				if(pflag)
1134887Schin 				{
1144887Schin 					if(arg=shp->st.trap[sig])
1154887Schin 						sfputr(sfstdout,sh_fmtq(arg),'\n');
1164887Schin 					continue;
1174887Schin 				}
1184887Schin 				if(shp->st.trap[sig])
1194887Schin 					free(shp->st.trap[sig]);
1204887Schin 				shp->st.trap[sig] = 0;
1214887Schin 				if(!clear && *action)
1224887Schin 					shp->st.trap[sig] = strdup(action);
1234887Schin 				if(sig == SH_DEBUGTRAP)
1244887Schin 				{
1254887Schin 					if(shp->st.trap[sig])
1264887Schin 						shp->trapnote |= SH_SIGTRAP;
1274887Schin 					else
1284887Schin 						shp->trapnote = 0;
1294887Schin 				}
1304887Schin 				continue;
1314887Schin 			}
1324887Schin 			if(sig>shp->sigmax)
1334887Schin 			{
1344887Schin 				errormsg(SH_DICT,2,e_trap,arg);
1354887Schin 				return(1);
1364887Schin 			}
1374887Schin 			else if(pflag)
1384887Schin 			{
1394887Schin 				char **trapcom = (shp->st.otrapcom?shp->st.otrapcom:shp->st.trapcom);
1404887Schin 				if(arg=trapcom[sig])
1414887Schin 					sfputr(sfstdout,arg,'\n');
1424887Schin 			}
1434887Schin 			else if(clear)
144*8462SApril.Chin@Sun.COM 			{
1454887Schin 				sh_sigclear(sig);
146*8462SApril.Chin@Sun.COM 				if(dflag)
147*8462SApril.Chin@Sun.COM 					signal(sig,SIG_DFL);
148*8462SApril.Chin@Sun.COM 			}
1494887Schin 			else
1504887Schin 			{
1514887Schin 				if(sig >= shp->st.trapmax)
1524887Schin 					shp->st.trapmax = sig+1;
1534887Schin 				if(arg=shp->st.trapcom[sig])
1544887Schin 					free(arg);
1554887Schin 				shp->st.trapcom[sig] = strdup(action);
1564887Schin 				sh_sigtrap(sig);
1574887Schin 			}
1584887Schin 		}
1594887Schin 	}
1604887Schin 	else /* print out current traps */
1614887Schin 		sig_list(shp,-1);
1624887Schin 	return(0);
1634887Schin }
1644887Schin 
1654887Schin int	b_kill(int argc,char *argv[],void *extra)
1664887Schin {
1674887Schin 	register char *signame;
1684887Schin 	register int sig=SIGTERM, flag=0, n;
169*8462SApril.Chin@Sun.COM 	register Shell_t *shp = ((Shbltin_t*)extra)->shp;
1704887Schin 	NOT_USED(argc);
1714887Schin 	while((n = optget(argv,sh_optkill))) switch(n)
1724887Schin 	{
1734887Schin 		case ':':
1744887Schin 			if((signame=argv[opt_info.index++]) && (sig=sig_number(signame+1))>=0)
1754887Schin 				goto endopts;
1764887Schin 			opt_info.index--;
1774887Schin 			errormsg(SH_DICT,2, "%s", opt_info.arg);
1784887Schin 			break;
1794887Schin 		case 'n':
1804887Schin 			sig = (int)opt_info.num;
1814887Schin 			goto endopts;
1824887Schin 		case 's':
1834887Schin 			flag |= S_FLAG;
1844887Schin 			signame = opt_info.arg;
1854887Schin 			goto endopts;
1864887Schin 		case 'l':
1874887Schin 			flag |= L_FLAG;
1884887Schin 			break;
1894887Schin 		case '?':
1904887Schin 			errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg);
1914887Schin 			break;
1924887Schin 	}
1934887Schin endopts:
1944887Schin 	argv += opt_info.index;
1954887Schin 	if(*argv && strcmp(*argv,"--")==0 && strcmp(*(argv-1),"--")!=0)
1964887Schin 		argv++;
1974887Schin 	if(error_info.errors || flag==(L_FLAG|S_FLAG) || (!(*argv) && !(flag&L_FLAG)))
1984887Schin 		errormsg(SH_DICT,ERROR_usage(2),"%s", optusage((char*)0));
1994887Schin 	/* just in case we send a kill -9 $$ */
2004887Schin 	sfsync(sfstderr);
2014887Schin 	if(flag&L_FLAG)
2024887Schin 	{
2034887Schin 		if(!(*argv))
2044887Schin 			sig_list(shp,0);
2054887Schin 		else while(signame = *argv++)
2064887Schin 		{
2074887Schin 			if(isdigit(*signame))
2084887Schin 				sig_list(shp,((int)strtol(signame, (char**)0, 10)&0177)+1);
2094887Schin 			else
2104887Schin 			{
2114887Schin 				if((sig=sig_number(signame))<0)
2124887Schin 				{
2134887Schin 					shp->exitval = 2;
2144887Schin 					errormsg(SH_DICT,ERROR_exit(1),e_nosignal,signame);
2154887Schin 				}
2164887Schin 				sfprintf(sfstdout,"%d\n",sig);
2174887Schin 			}
2184887Schin 		}
2194887Schin 		return(shp->exitval);
2204887Schin 	}
2214887Schin 	if(flag&S_FLAG)
2224887Schin 	{
2234887Schin 		if((sig=sig_number(signame)) < 0 || sig > shp->sigmax)
2244887Schin 			errormsg(SH_DICT,ERROR_exit(1),e_nosignal,signame);
2254887Schin 	}
2264887Schin 	if(job_walk(sfstdout,job_kill,sig,argv))
2274887Schin 		shp->exitval = 1;
2284887Schin 	return(shp->exitval);
2294887Schin }
2304887Schin 
2314887Schin /*
2324887Schin  * Given the name or number of a signal return the signal number
2334887Schin  */
2344887Schin 
2354887Schin static int sig_number(const char *string)
2364887Schin {
2374887Schin 	const Shtable_t	*tp;
238*8462SApril.Chin@Sun.COM 	register int	n,o,sig=0;
239*8462SApril.Chin@Sun.COM 	char		*last, *name;
2404887Schin 	if(isdigit(*string))
2414887Schin 	{
2424887Schin 		n = strtol(string,&last,10);
2434887Schin 		if(*last)
2444887Schin 			n = -1;
2454887Schin 	}
2464887Schin 	else
2474887Schin 	{
2484887Schin 		register int c;
249*8462SApril.Chin@Sun.COM 		o = staktell();
2504887Schin 		do
2514887Schin 		{
2524887Schin 			c = *string++;
2534887Schin 			if(islower(c))
2544887Schin 				c = toupper(c);
2554887Schin 			stakputc(c);
2564887Schin 		}
2574887Schin 		while(c);
258*8462SApril.Chin@Sun.COM 		stakseek(o);
259*8462SApril.Chin@Sun.COM 		if(memcmp(stakptr(o),"SIG",3)==0)
2604887Schin 		{
2614887Schin 			sig = 1;
262*8462SApril.Chin@Sun.COM 			o += 3;
2634887Schin 		}
264*8462SApril.Chin@Sun.COM 		tp = sh_locate(stakptr(o),(const Shtable_t*)shtab_signals,sizeof(*shtab_signals));
2654887Schin 		n = tp->sh_number;
2664887Schin 		if(sig==1 && (n>=(SH_TRAP-1) && n < (1<<SH_SIGBITS)))
2674887Schin 		{
2684887Schin 			/* sig prefix cannot match internal traps */
2694887Schin 			n = 0;
2704887Schin 			tp = (Shtable_t*)((char*)tp + sizeof(*shtab_signals));
271*8462SApril.Chin@Sun.COM 			if(strcmp(stakptr(o),tp->sh_name)==0)
2724887Schin 				n = tp->sh_number;
2734887Schin 		}
274*8462SApril.Chin@Sun.COM 		if((n>>SH_SIGBITS)&SH_SIGRUNTIME)
275*8462SApril.Chin@Sun.COM 			n = sh.sigruntime[(n&((1<<SH_SIGBITS)-1))-1];
276*8462SApril.Chin@Sun.COM 		else
277*8462SApril.Chin@Sun.COM 		{
278*8462SApril.Chin@Sun.COM 			n &= (1<<SH_SIGBITS)-1;
279*8462SApril.Chin@Sun.COM 			if(n < SH_TRAP)
280*8462SApril.Chin@Sun.COM 				n--;
281*8462SApril.Chin@Sun.COM 		}
282*8462SApril.Chin@Sun.COM 		if(n<0 && (name=stakptr(o)) && *name++=='R' && *name++=='T')
283*8462SApril.Chin@Sun.COM 		{
284*8462SApril.Chin@Sun.COM 			if(name[0]=='M' && name[1]=='I' && name[2]=='N' && name[3]=='+')
285*8462SApril.Chin@Sun.COM 			{
286*8462SApril.Chin@Sun.COM 				if((sig=(int)strtol(name+4,&name,10)) >= 0 && !*name)
287*8462SApril.Chin@Sun.COM 					n = sh.sigruntime[SH_SIGRTMIN] + sig;
288*8462SApril.Chin@Sun.COM 			}
289*8462SApril.Chin@Sun.COM 			else if(name[0]=='M' && name[1]=='A' && name[2]=='X' && name[3]=='-')
290*8462SApril.Chin@Sun.COM 			{
291*8462SApril.Chin@Sun.COM 				if((sig=(int)strtol(name+4,&name,10)) >= 0 && !*name)
292*8462SApril.Chin@Sun.COM 					n = sh.sigruntime[SH_SIGRTMAX] - sig;
293*8462SApril.Chin@Sun.COM 			}
294*8462SApril.Chin@Sun.COM 			else if((sig=(int)strtol(name,&name,10)) > 0 && !*name)
295*8462SApril.Chin@Sun.COM 				n = sh.sigruntime[SH_SIGRTMIN] + sig - 1;
296*8462SApril.Chin@Sun.COM 			if(n<sh.sigruntime[SH_SIGRTMIN] || n>sh.sigruntime[SH_SIGRTMAX])
297*8462SApril.Chin@Sun.COM 				n = -1;
298*8462SApril.Chin@Sun.COM 		}
2994887Schin 	}
3004887Schin 	return(n);
3014887Schin }
3024887Schin 
3034887Schin /*
304*8462SApril.Chin@Sun.COM  * synthesize signal name for sig in buf
305*8462SApril.Chin@Sun.COM  * pfx!=0 prepends SIG to default signal number
306*8462SApril.Chin@Sun.COM  */
307*8462SApril.Chin@Sun.COM static char* sig_name(int sig, char* buf, int pfx)
308*8462SApril.Chin@Sun.COM {
309*8462SApril.Chin@Sun.COM 	register int	i;
310*8462SApril.Chin@Sun.COM 
311*8462SApril.Chin@Sun.COM 	i = 0;
312*8462SApril.Chin@Sun.COM 	if(sig>sh.sigruntime[SH_SIGRTMIN] && sig<sh.sigruntime[SH_SIGRTMAX])
313*8462SApril.Chin@Sun.COM 	{
314*8462SApril.Chin@Sun.COM 		buf[i++] = 'R';
315*8462SApril.Chin@Sun.COM 		buf[i++] = 'T';
316*8462SApril.Chin@Sun.COM 		buf[i++] = 'M';
317*8462SApril.Chin@Sun.COM 		if(sig>sh.sigruntime[SH_SIGRTMIN]+(sh.sigruntime[SH_SIGRTMAX]-sh.sigruntime[SH_SIGRTMIN])/2)
318*8462SApril.Chin@Sun.COM 		{
319*8462SApril.Chin@Sun.COM 			buf[i++] = 'A';
320*8462SApril.Chin@Sun.COM 			buf[i++] = 'X';
321*8462SApril.Chin@Sun.COM 			buf[i++] = '-';
322*8462SApril.Chin@Sun.COM 			sig = sh.sigruntime[SH_SIGRTMAX]-sig;
323*8462SApril.Chin@Sun.COM 		}
324*8462SApril.Chin@Sun.COM 		else
325*8462SApril.Chin@Sun.COM 		{
326*8462SApril.Chin@Sun.COM 			buf[i++] = 'I';
327*8462SApril.Chin@Sun.COM 			buf[i++] = 'N';
328*8462SApril.Chin@Sun.COM 			buf[i++] = '+';
329*8462SApril.Chin@Sun.COM 			sig = sig-sh.sigruntime[SH_SIGRTMIN];
330*8462SApril.Chin@Sun.COM 		}
331*8462SApril.Chin@Sun.COM 	}
332*8462SApril.Chin@Sun.COM 	else if(pfx)
333*8462SApril.Chin@Sun.COM 	{
334*8462SApril.Chin@Sun.COM 		buf[i++] = 'S';
335*8462SApril.Chin@Sun.COM 		buf[i++] = 'I';
336*8462SApril.Chin@Sun.COM 		buf[i++] = 'G';
337*8462SApril.Chin@Sun.COM 	}
338*8462SApril.Chin@Sun.COM 	i += sfsprintf(buf+i, 8, "%d", sig);
339*8462SApril.Chin@Sun.COM 	buf[i] = 0;
340*8462SApril.Chin@Sun.COM 	return buf;
341*8462SApril.Chin@Sun.COM }
342*8462SApril.Chin@Sun.COM 
343*8462SApril.Chin@Sun.COM /*
3444887Schin  * if <flag> is positive, then print signal name corresponding to <flag>
3454887Schin  * if <flag> is zero, then print all signal names
3464887Schin  * if <flag> is negative, then print all traps
3474887Schin  */
3484887Schin static void sig_list(register Shell_t *shp,register int flag)
3494887Schin {
3504887Schin 	register const struct shtable2	*tp;
3514887Schin 	register int sig = shp->sigmax+1;
352*8462SApril.Chin@Sun.COM 	register char *sname;
353*8462SApril.Chin@Sun.COM 	char name[10];
3544887Schin 	const char *names[SH_TRAP];
3554887Schin 	const char *traps[SH_DEBUGTRAP+1];
3564887Schin 	tp=shtab_signals;
357*8462SApril.Chin@Sun.COM 	if(flag<=0)
3584887Schin 	{
3594887Schin 		/* not all signals may be defined, so initialize */
3604887Schin 		while(--sig >= 0)
3614887Schin 			names[sig] = 0;
3624887Schin 		for(sig=SH_DEBUGTRAP; sig>=0; sig--)
3634887Schin 			traps[sig] = 0;
3644887Schin 	}
3654887Schin 	while(*tp->sh_name)
3664887Schin 	{
367*8462SApril.Chin@Sun.COM 		sig = tp->sh_number&((1<<SH_SIGBITS)-1);
368*8462SApril.Chin@Sun.COM 		if ((tp->sh_number>>SH_SIGBITS) & SH_SIGRUNTIME)
369*8462SApril.Chin@Sun.COM 			sig = sh.sigruntime[sig-1]+1;
3704887Schin 		if(sig==flag)
3714887Schin 		{
3724887Schin 			sfprintf(sfstdout,"%s\n",tp->sh_name);
3734887Schin 			return;
3744887Schin 		}
3754887Schin 		else if(sig&SH_TRAP)
3764887Schin 			traps[sig&~SH_TRAP] = (char*)tp->sh_name;
3774887Schin 		else if(sig < sizeof(names)/sizeof(char*))
3784887Schin 			names[sig] = (char*)tp->sh_name;
3794887Schin 		tp++;
3804887Schin 	}
3814887Schin 	if(flag > 0)
382*8462SApril.Chin@Sun.COM 		sfputr(sfstdout, sig_name(flag-1,name,0), '\n');
3834887Schin 	else if(flag<0)
3844887Schin 	{
3854887Schin 		/* print the traps */
386*8462SApril.Chin@Sun.COM 		register char *trap,**trapcom;
3874887Schin 		sig = shp->st.trapmax;
3884887Schin 		/* use parent traps if otrapcom is set (for $(trap)  */
3894887Schin 		trapcom = (shp->st.otrapcom?shp->st.otrapcom:shp->st.trapcom);
3904887Schin 		while(--sig >= 0)
3914887Schin 		{
3924887Schin 			if(!(trap=trapcom[sig]))
3934887Schin 				continue;
3944887Schin 			if(!(sname=(char*)names[sig+1]))
395*8462SApril.Chin@Sun.COM 				sname = sig_name(sig,name,1);
3964887Schin 			sfprintf(sfstdout,trapfmt,sh_fmtq(trap),sname);
3974887Schin 		}
3984887Schin 		for(sig=SH_DEBUGTRAP; sig>=0; sig--)
3994887Schin 		{
4004887Schin 			if(!(trap=shp->st.trap[sig]))
4014887Schin 				continue;
4024887Schin 			sfprintf(sfstdout,trapfmt,sh_fmtq(trap),traps[sig]);
4034887Schin 		}
4044887Schin 	}
4054887Schin 	else
4064887Schin 	{
4074887Schin 		/* print all the signal names */
4084887Schin 		for(sig=2; sig <= shp->sigmax; sig++)
4094887Schin 		{
410*8462SApril.Chin@Sun.COM 			if(!(sname=(char*)names[sig+1]))
411*8462SApril.Chin@Sun.COM 				sname = sig_name(sig,name,1);
412*8462SApril.Chin@Sun.COM 			sfputr(sfstdout,sname,'\n');
4134887Schin 		}
4144887Schin 	}
4154887Schin }
416