xref: /titanic_44/usr/src/lib/libshell/common/bltins/trap.c (revision 63ea9ad24896f2939472f8f96f568086d190eb33)
1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1982-2008 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	<ctype.h>
34 #include	"jobs.h"
35 #include	"builtins.h"
36 
37 #define L_FLAG	1
38 #define S_FLAG	2
39 
40 static const char trapfmt[] = "trap -- %s %s\n";
41 
42 static int	sig_number(const char*);
43 static void	sig_list(Shell_t*,int);
44 
45 int	b_trap(int argc,char *argv[],void *extra)
46 {
47 	register char *arg = argv[1];
48 	register int sig, clear = 0, dflag = 0, pflag = 0;
49 	register Shell_t *shp = ((Shbltin_t*)extra)->shp;
50 	NOT_USED(argc);
51 	while (sig = optget(argv, sh_opttrap)) switch (sig)
52 	{
53 	    case 'p':
54 		pflag=1;
55 		break;
56 	    case ':':
57 		errormsg(SH_DICT,2, "%s", opt_info.arg);
58 		break;
59 	    case '?':
60 		errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg);
61 		return(2);
62 		break;
63 	}
64 	argv += opt_info.index;
65 	if(error_info.errors)
66 		errormsg(SH_DICT,ERROR_usage(2),"%s", optusage((char*)0));
67 	if(arg = *argv)
68 	{
69 		char *action = arg;
70 		if(!dflag && !pflag)
71 		{
72 			/* first argument all digits or - means clear */
73 			while(isdigit(*arg))
74 				arg++;
75 			clear = (arg!=action && *arg==0);
76 			if(!clear)
77 			{
78 				++argv;
79 				if(*action=='-' && action[1]==0)
80 					clear++;
81 				/*
82 				 * NOTE: 2007-11-26: workaround for tests/signal.sh
83 				 * if function semantics can be worked out then it
84 				 * may merit a -d,--default option
85 				 */
86 				else if(*action=='+' && action[1]==0 && sh.st.self == &sh.global)
87 				{
88 					clear++;
89 					dflag++;
90 				}
91 			}
92 			if(!argv[0])
93 				errormsg(SH_DICT,ERROR_exit(1),e_condition);
94 		}
95 		while(arg = *argv++)
96 		{
97 			sig = sig_number(arg);
98 			if(sig<0)
99 			{
100 				errormsg(SH_DICT,2,e_trap,arg);
101 				return(1);
102 			}
103 			/* internal traps */
104 			if(sig&SH_TRAP)
105 			{
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=shp->st.trap[sig])
115 						sfputr(sfstdout,sh_fmtq(arg),'\n');
116 					continue;
117 				}
118 				if(shp->st.trap[sig])
119 					free(shp->st.trap[sig]);
120 				shp->st.trap[sig] = 0;
121 				if(!clear && *action)
122 					shp->st.trap[sig] = strdup(action);
123 				if(sig == SH_DEBUGTRAP)
124 				{
125 					if(shp->st.trap[sig])
126 						shp->trapnote |= SH_SIGTRAP;
127 					else
128 						shp->trapnote = 0;
129 				}
130 				continue;
131 			}
132 			if(sig>shp->sigmax)
133 			{
134 				errormsg(SH_DICT,2,e_trap,arg);
135 				return(1);
136 			}
137 			else if(pflag)
138 			{
139 				char **trapcom = (shp->st.otrapcom?shp->st.otrapcom:shp->st.trapcom);
140 				if(arg=trapcom[sig])
141 					sfputr(sfstdout,arg,'\n');
142 			}
143 			else if(clear)
144 			{
145 				sh_sigclear(sig);
146 				if(dflag)
147 					signal(sig,SIG_DFL);
148 			}
149 			else
150 			{
151 				if(sig >= shp->st.trapmax)
152 					shp->st.trapmax = sig+1;
153 				if(arg=shp->st.trapcom[sig])
154 					free(arg);
155 				shp->st.trapcom[sig] = strdup(action);
156 				sh_sigtrap(sig);
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 		}
264 		tp = sh_locate(stakptr(o),(const Shtable_t*)shtab_signals,sizeof(*shtab_signals));
265 		n = tp->sh_number;
266 		if(sig==1 && (n>=(SH_TRAP-1) && n < (1<<SH_SIGBITS)))
267 		{
268 			/* sig prefix cannot match internal traps */
269 			n = 0;
270 			tp = (Shtable_t*)((char*)tp + sizeof(*shtab_signals));
271 			if(strcmp(stakptr(o),tp->sh_name)==0)
272 				n = tp->sh_number;
273 		}
274 		if((n>>SH_SIGBITS)&SH_SIGRUNTIME)
275 			n = sh.sigruntime[(n&((1<<SH_SIGBITS)-1))-1];
276 		else
277 		{
278 			n &= (1<<SH_SIGBITS)-1;
279 			if(n < SH_TRAP)
280 				n--;
281 		}
282 		if(n<0 && (name=stakptr(o)) && *name++=='R' && *name++=='T')
283 		{
284 			if(name[0]=='M' && name[1]=='I' && name[2]=='N' && name[3]=='+')
285 			{
286 				if((sig=(int)strtol(name+4,&name,10)) >= 0 && !*name)
287 					n = sh.sigruntime[SH_SIGRTMIN] + sig;
288 			}
289 			else if(name[0]=='M' && name[1]=='A' && name[2]=='X' && name[3]=='-')
290 			{
291 				if((sig=(int)strtol(name+4,&name,10)) >= 0 && !*name)
292 					n = sh.sigruntime[SH_SIGRTMAX] - sig;
293 			}
294 			else if((sig=(int)strtol(name,&name,10)) > 0 && !*name)
295 				n = sh.sigruntime[SH_SIGRTMIN] + sig - 1;
296 			if(n<sh.sigruntime[SH_SIGRTMIN] || n>sh.sigruntime[SH_SIGRTMAX])
297 				n = -1;
298 		}
299 	}
300 	return(n);
301 }
302 
303 /*
304  * synthesize signal name for sig in buf
305  * pfx!=0 prepends SIG to default signal number
306  */
307 static char* sig_name(int sig, char* buf, int pfx)
308 {
309 	register int	i;
310 
311 	i = 0;
312 	if(sig>sh.sigruntime[SH_SIGRTMIN] && sig<sh.sigruntime[SH_SIGRTMAX])
313 	{
314 		buf[i++] = 'R';
315 		buf[i++] = 'T';
316 		buf[i++] = 'M';
317 		if(sig>sh.sigruntime[SH_SIGRTMIN]+(sh.sigruntime[SH_SIGRTMAX]-sh.sigruntime[SH_SIGRTMIN])/2)
318 		{
319 			buf[i++] = 'A';
320 			buf[i++] = 'X';
321 			buf[i++] = '-';
322 			sig = sh.sigruntime[SH_SIGRTMAX]-sig;
323 		}
324 		else
325 		{
326 			buf[i++] = 'I';
327 			buf[i++] = 'N';
328 			buf[i++] = '+';
329 			sig = sig-sh.sigruntime[SH_SIGRTMIN];
330 		}
331 	}
332 	else if(pfx)
333 	{
334 		buf[i++] = 'S';
335 		buf[i++] = 'I';
336 		buf[i++] = 'G';
337 	}
338 	i += sfsprintf(buf+i, 8, "%d", sig);
339 	buf[i] = 0;
340 	return buf;
341 }
342 
343 /*
344  * if <flag> is positive, then print signal name corresponding to <flag>
345  * if <flag> is zero, then print all signal names
346  * if <flag> is negative, then print all traps
347  */
348 static void sig_list(register Shell_t *shp,register int flag)
349 {
350 	register const struct shtable2	*tp;
351 	register int sig = shp->sigmax+1;
352 	register char *sname;
353 	char name[10];
354 	const char *names[SH_TRAP];
355 	const char *traps[SH_DEBUGTRAP+1];
356 	tp=shtab_signals;
357 	if(flag<=0)
358 	{
359 		/* not all signals may be defined, so initialize */
360 		while(--sig >= 0)
361 			names[sig] = 0;
362 		for(sig=SH_DEBUGTRAP; sig>=0; sig--)
363 			traps[sig] = 0;
364 	}
365 	while(*tp->sh_name)
366 	{
367 		sig = tp->sh_number&((1<<SH_SIGBITS)-1);
368 		if ((tp->sh_number>>SH_SIGBITS) & SH_SIGRUNTIME)
369 			sig = sh.sigruntime[sig-1]+1;
370 		if(sig==flag)
371 		{
372 			sfprintf(sfstdout,"%s\n",tp->sh_name);
373 			return;
374 		}
375 		else if(sig&SH_TRAP)
376 			traps[sig&~SH_TRAP] = (char*)tp->sh_name;
377 		else if(sig < sizeof(names)/sizeof(char*))
378 			names[sig] = (char*)tp->sh_name;
379 		tp++;
380 	}
381 	if(flag > 0)
382 		sfputr(sfstdout, sig_name(flag-1,name,0), '\n');
383 	else if(flag<0)
384 	{
385 		/* print the traps */
386 		register char *trap,**trapcom;
387 		sig = shp->st.trapmax;
388 		/* use parent traps if otrapcom is set (for $(trap)  */
389 		trapcom = (shp->st.otrapcom?shp->st.otrapcom:shp->st.trapcom);
390 		while(--sig >= 0)
391 		{
392 			if(!(trap=trapcom[sig]))
393 				continue;
394 			if(!(sname=(char*)names[sig+1]))
395 				sname = sig_name(sig,name,1);
396 			sfprintf(sfstdout,trapfmt,sh_fmtq(trap),sname);
397 		}
398 		for(sig=SH_DEBUGTRAP; sig>=0; sig--)
399 		{
400 			if(!(trap=shp->st.trap[sig]))
401 				continue;
402 			sfprintf(sfstdout,trapfmt,sh_fmtq(trap),traps[sig]);
403 		}
404 	}
405 	else
406 	{
407 		/* print all the signal names */
408 		for(sig=2; sig <= shp->sigmax; sig++)
409 		{
410 			if(!(sname=(char*)names[sig+1]))
411 				sname = sig_name(sig,name,1);
412 			sfputr(sfstdout,sname,'\n');
413 		}
414 	}
415 }
416