1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1982-2010 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@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