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