Home | History | Annotate | Download | only in bltins
      1 /***********************************************************************
      2 *                                                                      *
      3 *               This software is part of the ast package               *
      4 *          Copyright (c) 1982-2009 AT&T Intellectual Property          *
      5 *                      and is licensed under the                       *
      6 *                  Common Public License, Version 1.0                  *
      7 *                    by AT&T Intellectual Property                     *
      8 *                                                                      *
      9 *                A copy of the License is available at                 *
     10 *            http://www.opensource.org/licenses/cpl1.0.txt             *
     11 *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
     12 *                                                                      *
     13 *              Information and Software Systems Research               *
     14 *                            AT&T Research                             *
     15 *                           Florham Park NJ                            *
     16 *                                                                      *
     17 *                  David Korn <dgk (at) research.att.com>                   *
     18 *                                                                      *
     19 ***********************************************************************/
     20 #pragma prototyped
     21 /*
     22  * trap  [-p]  action sig...
     23  * kill  [-l] [sig...]
     24  * kill  [-s sig] pid...
     25  *
     26  *   David Korn
     27  *   AT&T Labs
     28  *   research!dgk
     29  *
     30  */
     31 
     32 #include	"defs.h"
     33 #include	"jobs.h"
     34 #include	"builtins.h"
     35 
     36 #define L_FLAG	1
     37 #define S_FLAG	2
     38 
     39 static const char trapfmt[] = "trap -- %s %s\n";
     40 
     41 static int	sig_number(const char*);
     42 static void	sig_list(Shell_t*,int);
     43 
     44 int	b_trap(int argc,char *argv[],void *extra)
     45 {
     46 	register char *arg = argv[1];
     47 	register int sig, clear = 0, dflag = 0, pflag = 0;
     48 	register Shell_t *shp = ((Shbltin_t*)extra)->shp;
     49 	NOT_USED(argc);
     50 	while (sig = optget(argv, sh_opttrap)) switch (sig)
     51 	{
     52 	    case 'p':
     53 		pflag=1;
     54 		break;
     55 	    case ':':
     56 		errormsg(SH_DICT,2, "%s", opt_info.arg);
     57 		break;
     58 	    case '?':
     59 		errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg);
     60 		return(2);
     61 		break;
     62 	}
     63 	argv += opt_info.index;
     64 	if(error_info.errors)
     65 		errormsg(SH_DICT,ERROR_usage(2),"%s", optusage((char*)0));
     66 	if(arg = *argv)
     67 	{
     68 		char *action = arg;
     69 		if(!dflag && !pflag)
     70 		{
     71 			/* first argument all digits or - means clear */
     72 			while(isdigit(*arg))
     73 				arg++;
     74 			clear = (arg!=action && *arg==0);
     75 			if(!clear)
     76 			{
     77 				++argv;
     78 				if(*action=='-' && action[1]==0)
     79 					clear++;
     80 				/*
     81 				 * NOTE: 2007-11-26: workaround for tests/signal.sh
     82 				 * if function semantics can be worked out then it
     83 				 * may merit a -d,--default option
     84 				 */
     85 				else if(*action=='+' && action[1]==0 && sh.st.self == &sh.global)
     86 				{
     87 					clear++;
     88 					dflag++;
     89 				}
     90 			}
     91 			if(!argv[0])
     92 				errormsg(SH_DICT,ERROR_exit(1),e_condition);
     93 		}
     94 		while(arg = *argv++)
     95 		{
     96 			sig = sig_number(arg);
     97 			if(sig<0)
     98 			{
     99 				errormsg(SH_DICT,2,e_trap,arg);
    100 				return(1);
    101 			}
    102 			/* internal traps */
    103 			if(sig&SH_TRAP)
    104 			{
    105 				sig &= ~SH_TRAP;
    106 				if(sig>SH_DEBUGTRAP)
    107 				{
    108 					errormsg(SH_DICT,2,e_trap,arg);
    109 					return(1);
    110 				}
    111 				if(pflag)
    112 				{
    113 					if(arg=shp->st.trap[sig])
    114 						sfputr(sfstdout,sh_fmtq(arg),'\n');
    115 					continue;
    116 				}
    117 				if(shp->st.trap[sig])
    118 					free(shp->st.trap[sig]);
    119 				shp->st.trap[sig] = 0;
    120 				if(!clear && *action)
    121 					shp->st.trap[sig] = strdup(action);
    122 				if(sig == SH_DEBUGTRAP)
    123 				{
    124 					if(shp->st.trap[sig])
    125 						shp->trapnote |= SH_SIGTRAP;
    126 					else
    127 						shp->trapnote = 0;
    128 				}
    129 				continue;
    130 			}
    131 			if(sig>shp->sigmax)
    132 			{
    133 				errormsg(SH_DICT,2,e_trap,arg);
    134 				return(1);
    135 			}
    136 			else if(pflag)
    137 			{
    138 				char **trapcom = (shp->st.otrapcom?shp->st.otrapcom:shp->st.trapcom);
    139 				if(arg=trapcom[sig])
    140 					sfputr(sfstdout,arg,'\n');
    141 			}
    142 			else if(clear)
    143 			{
    144 				sh_sigclear(sig);
    145 				if(dflag)
    146 					signal(sig,SIG_DFL);
    147 			}
    148 			else
    149 			{
    150 				if(sig >= shp->st.trapmax)
    151 					shp->st.trapmax = sig+1;
    152 				arg = shp->st.trapcom[sig];
    153 				sh_sigtrap(sig);
    154 				shp->st.trapcom[sig] = (shp->sigflag[sig]&SH_SIGOFF) ? Empty : strdup(action);
    155 				if(arg && arg != Empty)
    156 					free(arg);
    157 			}
    158 		}
    159 	}
    160 	else /* print out current traps */
    161 		sig_list(shp,-1);
    162 	return(0);
    163 }
    164 
    165 int	b_kill(int argc,char *argv[],void *extra)
    166 {
    167 	register char *signame;
    168 	register int sig=SIGTERM, flag=0, n;
    169 	register Shell_t *shp = ((Shbltin_t*)extra)->shp;
    170 	NOT_USED(argc);
    171 	while((n = optget(argv,sh_optkill))) switch(n)
    172 	{
    173 		case ':':
    174 			if((signame=argv[opt_info.index++]) && (sig=sig_number(signame+1))>=0)
    175 				goto endopts;
    176 			opt_info.index--;
    177 			errormsg(SH_DICT,2, "%s", opt_info.arg);
    178 			break;
    179 		case 'n':
    180 			sig = (int)opt_info.num;
    181 			goto endopts;
    182 		case 's':
    183 			flag |= S_FLAG;
    184 			signame = opt_info.arg;
    185 			goto endopts;
    186 		case 'l':
    187 			flag |= L_FLAG;
    188 			break;
    189 		case '?':
    190 			errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg);
    191 			break;
    192 	}
    193 endopts:
    194 	argv += opt_info.index;
    195 	if(*argv && strcmp(*argv,"--")==0 && strcmp(*(argv-1),"--")!=0)
    196 		argv++;
    197 	if(error_info.errors || flag==(L_FLAG|S_FLAG) || (!(*argv) && !(flag&L_FLAG)))
    198 		errormsg(SH_DICT,ERROR_usage(2),"%s", optusage((char*)0));
    199 	/* just in case we send a kill -9 $$ */
    200 	sfsync(sfstderr);
    201 	if(flag&L_FLAG)
    202 	{
    203 		if(!(*argv))
    204 			sig_list(shp,0);
    205 		else while(signame = *argv++)
    206 		{
    207 			if(isdigit(*signame))
    208 				sig_list(shp,((int)strtol(signame, (char**)0, 10)&0177)+1);
    209 			else
    210 			{
    211 				if((sig=sig_number(signame))<0)
    212 				{
    213 					shp->exitval = 2;
    214 					errormsg(SH_DICT,ERROR_exit(1),e_nosignal,signame);
    215 				}
    216 				sfprintf(sfstdout,"%d\n",sig);
    217 			}
    218 		}
    219 		return(shp->exitval);
    220 	}
    221 	if(flag&S_FLAG)
    222 	{
    223 		if((sig=sig_number(signame)) < 0 || sig > shp->sigmax)
    224 			errormsg(SH_DICT,ERROR_exit(1),e_nosignal,signame);
    225 	}
    226 	if(job_walk(sfstdout,job_kill,sig,argv))
    227 		shp->exitval = 1;
    228 	return(shp->exitval);
    229 }
    230 
    231 /*
    232  * Given the name or number of a signal return the signal number
    233  */
    234 
    235 static int sig_number(const char *string)
    236 {
    237 	const Shtable_t	*tp;
    238 	register int	n,o,sig=0;
    239 	char		*last, *name;
    240 	if(isdigit(*string))
    241 	{
    242 		n = strtol(string,&last,10);
    243 		if(*last)
    244 			n = -1;
    245 	}
    246 	else
    247 	{
    248 		register int c;
    249 		o = staktell();
    250 		do
    251 		{
    252 			c = *string++;
    253 			if(islower(c))
    254 				c = toupper(c);
    255 			stakputc(c);
    256 		}
    257 		while(c);
    258 		stakseek(o);
    259 		if(memcmp(stakptr(o),"SIG",3)==0)
    260 		{
    261 			sig = 1;
    262 			o += 3;
    263 			if(isdigit(*stakptr(o)))
    264 			{
    265 				n = strtol(stakptr(o),&last,10);
    266 				if(!*last)
    267 					return(n);
    268 			}
    269 		}
    270 		tp = sh_locate(stakptr(o),(const Shtable_t*)shtab_signals,sizeof(*shtab_signals));
    271 		n = tp->sh_number;
    272 		if(sig==1 && (n>=(SH_TRAP-1) && n < (1<<SH_SIGBITS)))
    273 		{
    274 			/* sig prefix cannot match internal traps */
    275 			n = 0;
    276 			tp = (Shtable_t*)((char*)tp + sizeof(*shtab_signals));
    277 			if(strcmp(stakptr(o),tp->sh_name)==0)
    278 				n = tp->sh_number;
    279 		}
    280 		if((n>>SH_SIGBITS)&SH_SIGRUNTIME)
    281 			n = sh.sigruntime[(n&((1<<SH_SIGBITS)-1))-1];
    282 		else
    283 		{
    284 			n &= (1<<SH_SIGBITS)-1;
    285 			if(n < SH_TRAP)
    286 				n--;
    287 		}
    288 		if(n<0 && sh.sigruntime[1] && (name=stakptr(o)) && *name++=='R' && *name++=='T')
    289 		{
    290 			if(name[0]=='M' && name[1]=='I' && name[2]=='N' && name[3]=='+')
    291 			{
    292 				if((sig=(int)strtol(name+4,&name,10)) >= 0 && !*name)
    293 					n = sh.sigruntime[SH_SIGRTMIN] + sig;
    294 			}
    295 			else if(name[0]=='M' && name[1]=='A' && name[2]=='X' && name[3]=='-')
    296 			{
    297 				if((sig=(int)strtol(name+4,&name,10)) >= 0 && !*name)
    298 					n = sh.sigruntime[SH_SIGRTMAX] - sig;
    299 			}
    300 			else if((sig=(int)strtol(name,&name,10)) > 0 && !*name)
    301 				n = sh.sigruntime[SH_SIGRTMIN] + sig - 1;
    302 			if(n<sh.sigruntime[SH_SIGRTMIN] || n>sh.sigruntime[SH_SIGRTMAX])
    303 				n = -1;
    304 		}
    305 	}
    306 	return(n);
    307 }
    308 
    309 /*
    310  * synthesize signal name for sig in buf
    311  * pfx!=0 prepends SIG to default signal number
    312  */
    313 static char* sig_name(int sig, char* buf, int pfx)
    314 {
    315 	register int	i;
    316 
    317 	i = 0;
    318 	if(sig>sh.sigruntime[SH_SIGRTMIN] && sig<sh.sigruntime[SH_SIGRTMAX])
    319 	{
    320 		buf[i++] = 'R';
    321 		buf[i++] = 'T';
    322 		buf[i++] = 'M';
    323 		if(sig>sh.sigruntime[SH_SIGRTMIN]+(sh.sigruntime[SH_SIGRTMAX]-sh.sigruntime[SH_SIGRTMIN])/2)
    324 		{
    325 			buf[i++] = 'A';
    326 			buf[i++] = 'X';
    327 			buf[i++] = '-';
    328 			sig = sh.sigruntime[SH_SIGRTMAX]-sig;
    329 		}
    330 		else
    331 		{
    332 			buf[i++] = 'I';
    333 			buf[i++] = 'N';
    334 			buf[i++] = '+';
    335 			sig = sig-sh.sigruntime[SH_SIGRTMIN];
    336 		}
    337 	}
    338 	else if(pfx)
    339 	{
    340 		buf[i++] = 'S';
    341 		buf[i++] = 'I';
    342 		buf[i++] = 'G';
    343 	}
    344 	i += sfsprintf(buf+i, 8, "%d", sig);
    345 	buf[i] = 0;
    346 	return buf;
    347 }
    348 
    349 /*
    350  * if <flag> is positive, then print signal name corresponding to <flag>
    351  * if <flag> is zero, then print all signal names
    352  * if <flag> is negative, then print all traps
    353  */
    354 static void sig_list(register Shell_t *shp,register int flag)
    355 {
    356 	register const struct shtable2	*tp;
    357 	register int sig;
    358 	register char *sname;
    359 	char name[10];
    360 	const char *names[SH_TRAP];
    361 	const char *traps[SH_DEBUGTRAP+1];
    362 	tp=shtab_signals;
    363 	if(flag<=0)
    364 	{
    365 		/* not all signals may be defined, so initialize */
    366 		for(sig=shp->sigmax; sig>=0; sig--)
    367 			names[sig] = 0;
    368 		for(sig=SH_DEBUGTRAP; sig>=0; sig--)
    369 			traps[sig] = 0;
    370 	}
    371 	for(; *tp->sh_name; tp++)
    372 	{
    373 		sig = tp->sh_number&((1<<SH_SIGBITS)-1);
    374 		if (((tp->sh_number>>SH_SIGBITS) & SH_SIGRUNTIME) && (sig = sh.sigruntime[sig-1]+1) == 1)
    375 			continue;
    376 		if(sig==flag)
    377 		{
    378 			sfprintf(sfstdout,"%s\n",tp->sh_name);
    379 			return;
    380 		}
    381 		else if(sig&SH_TRAP)
    382 			traps[sig&~SH_TRAP] = (char*)tp->sh_name;
    383 		else if(sig-- && sig < elementsof(names))
    384 			names[sig] = (char*)tp->sh_name;
    385 	}
    386 	if(flag > 0)
    387 		sfputr(sfstdout, sig_name(flag-1,name,0), '\n');
    388 	else if(flag<0)
    389 	{
    390 		/* print the traps */
    391 		register char *trap,**trapcom;
    392 		sig = shp->st.trapmax;
    393 		/* use parent traps if otrapcom is set (for $(trap)  */
    394 		trapcom = (shp->st.otrapcom?shp->st.otrapcom:shp->st.trapcom);
    395 		while(--sig >= 0)
    396 		{
    397 			if(!(trap=trapcom[sig]))
    398 				continue;
    399 			if(sig > shp->sigmax || !(sname=(char*)names[sig]))
    400 				sname = sig_name(sig,name,1);
    401 			sfprintf(sfstdout,trapfmt,sh_fmtq(trap),sname);
    402 		}
    403 		for(sig=SH_DEBUGTRAP; sig>=0; sig--)
    404 		{
    405 			if(!(trap=shp->st.trap[sig]))
    406 				continue;
    407 			sfprintf(sfstdout,trapfmt,sh_fmtq(trap),traps[sig]);
    408 		}
    409 	}
    410 	else
    411 	{
    412 		/* print all the signal names */
    413 		for(sig=1; sig <= shp->sigmax; sig++)
    414 		{
    415 			if(!(sname=(char*)names[sig]))
    416 				sname = sig_name(sig,name,1);
    417 			sfputr(sfstdout,sname,'\n');
    418 		}
    419 	}
    420 }
    421