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
b_trap(int argc,char * argv[],Shbltin_t * context)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
b_kill(int argc,char * argv[],Shbltin_t * context)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
sig_number(Shell_t * shp,const char * string)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 */
sig_name(Shell_t * shp,int sig,char * buf,int pfx)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 */
sig_list(register Shell_t * shp,register int flag)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