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