xref: /titanic_44/usr/src/lib/libshell/common/bltins/trap.c (revision 726fad2a65f16c200a03969c29cb5c86c2d427db)
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