1/*********************************************************************** 2* * 3* This software is part of the ast package * 4* Copyright (c) 1982-2012 AT&T Intellectual Property * 5* and is licensed under the * 6* Eclipse Public License, Version 1.0 * 7* by AT&T Intellectual Property * 8* * 9* A copy of the License is available at * 10* http://www.eclipse.org/org/documents/epl-v10.html * 11* (with md5 checksum b35adb5213ca9657e911e9befb180842) * 12* * 13* Information and Software Systems Research * 14* AT&T Research * 15* Florham Park NJ * 16* * 17* David Korn <dgk@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 39static const char trapfmt[] = "trap -- %s %s\n"; 40 41static int sig_number(Shell_t*,const char*); 42static void sig_list(Shell_t*,int); 43 44int b_trap(int argc,char *argv[],Shbltin_t *context) 45{ 46 register char *arg = argv[1]; 47 register int sig, clear = 0, dflag = 0, pflag = 0; 48 register Shell_t *shp = context->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 && shp->st.self == &shp->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(shp,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 char **trap = (shp->st.otrap?shp->st.otrap:shp->st.trap); 106 sig &= ~SH_TRAP; 107 if(sig>SH_DEBUGTRAP) 108 { 109 errormsg(SH_DICT,2,e_trap,arg); 110 return(1); 111 } 112 if(pflag) 113 { 114 if(arg=trap[sig]) 115 sfputr(sfstdout,sh_fmtq(arg),'\n'); 116 continue; 117 } 118 shp->st.otrap = 0; 119 if(shp->st.trap[sig]) 120 free(shp->st.trap[sig]); 121 shp->st.trap[sig] = 0; 122 if(!clear && *action) 123 shp->st.trap[sig] = strdup(action); 124 if(sig == SH_DEBUGTRAP) 125 { 126 if(shp->st.trap[sig]) 127 shp->trapnote |= SH_SIGTRAP; 128 else 129 shp->trapnote = 0; 130 } 131 continue; 132 } 133 if(sig>shp->gd->sigmax) 134 { 135 errormsg(SH_DICT,2,e_trap,arg); 136 return(1); 137 } 138 else if(pflag) 139 { 140 char **trapcom = (shp->st.otrapcom?shp->st.otrapcom:shp->st.trapcom); 141 if(arg=trapcom[sig]) 142 sfputr(sfstdout,arg,'\n'); 143 } 144 else if(clear) 145 { 146 sh_sigclear(sig); 147 if(dflag) 148 signal(sig,SIG_DFL); 149 } 150 else 151 { 152 if(sig >= shp->st.trapmax) 153 shp->st.trapmax = sig+1; 154 arg = shp->st.trapcom[sig]; 155 sh_sigtrap(sig); 156 shp->st.trapcom[sig] = (shp->sigflag[sig]&SH_SIGOFF) ? Empty : strdup(action); 157 if(arg && arg != Empty) 158 free(arg); 159 } 160 } 161 } 162 else /* print out current traps */ 163 sig_list(shp,-2); 164 return(0); 165} 166 167int b_kill(int argc,char *argv[],Shbltin_t *context) 168{ 169 register char *signame; 170 register int sig=SIGTERM, flag=0, n; 171 register Shell_t *shp = context->shp; 172 int usemenu = 0; 173 NOT_USED(argc); 174 while((n = optget(argv,sh_optkill))) switch(n) 175 { 176 case ':': 177 if((signame=argv[opt_info.index++]) && (sig=sig_number(shp,signame+1))>=0) 178 goto endopts; 179 opt_info.index--; 180 errormsg(SH_DICT,2, "%s", opt_info.arg); 181 break; 182 case 'n': 183 sig = (int)opt_info.num; 184 goto endopts; 185 case 's': 186 flag |= S_FLAG; 187 signame = opt_info.arg; 188 goto endopts; 189 case 'L': 190 usemenu = -1; 191 case 'l': 192 flag |= L_FLAG; 193 break; 194 case '?': 195 errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg); 196 break; 197 } 198endopts: 199 argv += opt_info.index; 200 if(*argv && strcmp(*argv,"--")==0 && strcmp(*(argv-1),"--")!=0) 201 argv++; 202 if(error_info.errors || flag==(L_FLAG|S_FLAG) || (!(*argv) && !(flag&L_FLAG))) 203 errormsg(SH_DICT,ERROR_usage(2),"%s", optusage((char*)0)); 204 /* just in case we send a kill -9 $$ */ 205 sfsync(sfstderr); 206 if(flag&L_FLAG) 207 { 208 if(!(*argv)) 209 sig_list(shp,usemenu); 210 else while(signame = *argv++) 211 { 212 if(isdigit(*signame)) 213 sig_list(shp,((int)strtol(signame, (char**)0, 10)&0177)+1); 214 else 215 { 216 if((sig=sig_number(shp,signame))<0) 217 { 218 shp->exitval = 2; 219 errormsg(SH_DICT,ERROR_exit(1),e_nosignal,signame); 220 } 221 sfprintf(sfstdout,"%d\n",sig); 222 } 223 } 224 return(shp->exitval); 225 } 226 if(flag&S_FLAG) 227 { 228 if((sig=sig_number(shp,signame)) < 0 || sig > shp->gd->sigmax) 229 errormsg(SH_DICT,ERROR_exit(1),e_nosignal,signame); 230 } 231 if(job_walk(sfstdout,job_kill,sig,argv)) 232 shp->exitval = 1; 233 return(shp->exitval); 234} 235 236/* 237 * Given the name or number of a signal return the signal number 238 */ 239 240static int sig_number(Shell_t *shp,const char *string) 241{ 242 const Shtable_t *tp; 243 register int n,o,sig=0; 244 char *last, *name; 245 if(isdigit(*string)) 246 { 247 n = strtol(string,&last,10); 248 if(*last) 249 n = -1; 250 } 251 else 252 { 253 register int c; 254 o = staktell(); 255 do 256 { 257 c = *string++; 258 if(islower(c)) 259 c = toupper(c); 260 stakputc(c); 261 } 262 while(c); 263 stakseek(o); 264 if(memcmp(stakptr(o),"SIG",3)==0) 265 { 266 sig = 1; 267 o += 3; 268 if(isdigit(*stakptr(o))) 269 { 270 n = strtol(stakptr(o),&last,10); 271 if(!*last) 272 return(n); 273 } 274 } 275 tp = sh_locate(stakptr(o),(const Shtable_t*)shtab_signals,sizeof(*shtab_signals)); 276 n = tp->sh_number; 277 if(sig==1 && (n>=(SH_TRAP-1) && n < (1<<SH_SIGBITS))) 278 { 279 /* sig prefix cannot match internal traps */ 280 n = 0; 281 tp = (Shtable_t*)((char*)tp + sizeof(*shtab_signals)); 282 if(strcmp(stakptr(o),tp->sh_name)==0) 283 n = tp->sh_number; 284 } 285 if((n>>SH_SIGBITS)&SH_SIGRUNTIME) 286 n = shp->gd->sigruntime[(n&((1<<SH_SIGBITS)-1))-1]; 287 else 288 { 289 n &= (1<<SH_SIGBITS)-1; 290 if(n < SH_TRAP) 291 n--; 292 } 293 if(n<0 && shp->gd->sigruntime[1] && (name=stakptr(o)) && *name++=='R' && *name++=='T') 294 { 295 if(name[0]=='M' && name[1]=='I' && name[2]=='N' && name[3]=='+') 296 { 297 if((sig=(int)strtol(name+4,&name,10)) >= 0 && !*name) 298 n = shp->gd->sigruntime[SH_SIGRTMIN] + sig; 299 } 300 else if(name[0]=='M' && name[1]=='A' && name[2]=='X' && name[3]=='-') 301 { 302 if((sig=(int)strtol(name+4,&name,10)) >= 0 && !*name) 303 n = shp->gd->sigruntime[SH_SIGRTMAX] - sig; 304 } 305 else if((sig=(int)strtol(name,&name,10)) > 0 && !*name) 306 n = shp->gd->sigruntime[SH_SIGRTMIN] + sig - 1; 307 if(n<shp->gd->sigruntime[SH_SIGRTMIN] || n>shp->gd->sigruntime[SH_SIGRTMAX]) 308 n = -1; 309 } 310 } 311 return(n); 312} 313 314/* 315 * synthesize signal name for sig in buf 316 * pfx!=0 prepends SIG to default signal number 317 */ 318static char* sig_name(Shell_t *shp,int sig, char* buf, int pfx) 319{ 320 register int i; 321 322 i = 0; 323 if(sig>shp->gd->sigruntime[SH_SIGRTMIN] && sig<shp->gd->sigruntime[SH_SIGRTMAX]) 324 { 325 buf[i++] = 'R'; 326 buf[i++] = 'T'; 327 buf[i++] = 'M'; 328 if(sig>shp->gd->sigruntime[SH_SIGRTMIN]+(shp->gd->sigruntime[SH_SIGRTMAX]-shp->gd->sigruntime[SH_SIGRTMIN])/2) 329 { 330 buf[i++] = 'A'; 331 buf[i++] = 'X'; 332 buf[i++] = '-'; 333 sig = shp->gd->sigruntime[SH_SIGRTMAX]-sig; 334 } 335 else 336 { 337 buf[i++] = 'I'; 338 buf[i++] = 'N'; 339 buf[i++] = '+'; 340 sig = sig-shp->gd->sigruntime[SH_SIGRTMIN]; 341 } 342 } 343 else if(pfx) 344 { 345 buf[i++] = 'S'; 346 buf[i++] = 'I'; 347 buf[i++] = 'G'; 348 } 349 i += sfsprintf(buf+i, 8, "%d", sig); 350 buf[i] = 0; 351 return buf; 352} 353 354/* 355 * if <flag> is positive, then print signal name corresponding to <flag> 356 * if <flag> is zero, then print all signal names 357 * if <flag> is -1, then print all signal names in menu format 358 * if <flag> is <-1, then print all traps 359 */ 360static void sig_list(register Shell_t *shp,register int flag) 361{ 362 register const struct shtable2 *tp; 363 register int sig; 364 register char *sname; 365 char name[10]; 366 const char *names[SH_TRAP]; 367 const char *traps[SH_DEBUGTRAP+1]; 368 tp=shtab_signals; 369 if(flag<=0) 370 { 371 /* not all signals may be defined, so initialize */ 372 for(sig=shp->gd->sigmax; sig>=0; sig--) 373 names[sig] = 0; 374 for(sig=SH_DEBUGTRAP; sig>=0; sig--) 375 traps[sig] = 0; 376 } 377 for(; *tp->sh_name; tp++) 378 { 379 sig = tp->sh_number&((1<<SH_SIGBITS)-1); 380 if (((tp->sh_number>>SH_SIGBITS) & SH_SIGRUNTIME) && (sig = shp->gd->sigruntime[sig-1]+1) == 1) 381 continue; 382 if(sig==flag) 383 { 384 sfprintf(sfstdout,"%s\n",tp->sh_name); 385 return; 386 } 387 else if(sig&SH_TRAP) 388 traps[sig&~SH_TRAP] = (char*)tp->sh_name; 389 else if(sig-- && sig < elementsof(names)) 390 names[sig] = (char*)tp->sh_name; 391 } 392 if(flag > 0) 393 sfputr(sfstdout, sig_name(shp,flag-1,name,0), '\n'); 394 else if(flag<-1) 395 { 396 /* print the traps */ 397 register char *trap,**trapcom; 398 sig = shp->st.trapmax; 399 /* use parent traps if otrapcom is set (for $(trap) */ 400 trapcom = (shp->st.otrapcom?shp->st.otrapcom:shp->st.trapcom); 401 while(--sig >= 0) 402 { 403 if(!(trap=trapcom[sig])) 404 continue; 405 if(sig > shp->gd->sigmax || !(sname=(char*)names[sig])) 406 sname = sig_name(shp,sig,name,1); 407 sfprintf(sfstdout,trapfmt,sh_fmtq(trap),sname); 408 } 409 for(sig=SH_DEBUGTRAP; sig>=0; sig--) 410 { 411 if(!(trap=shp->st.otrap?shp->st.otrap[sig]:shp->st.trap[sig])) 412 continue; 413 sfprintf(sfstdout,trapfmt,sh_fmtq(trap),traps[sig]); 414 } 415 } 416 else 417 { 418 /* print all the signal names */ 419 for(sig=1; sig <= shp->gd->sigmax; sig++) 420 { 421 if(!(sname=(char*)names[sig])) 422 { 423 sname = sig_name(shp,sig,name,1); 424 if(flag) 425 sname = stakcopy(sname); 426 } 427 if(flag) 428 names[sig] = sname; 429 else 430 sfputr(sfstdout,sname,'\n'); 431 } 432 if(flag) 433 { 434 names[sig] = 0; 435 sh_menu(sfstdout,shp->gd->sigmax,(char**)names+1); 436 } 437 } 438} 439