xref: /illumos-gate/usr/src/contrib/ast/src/cmd/ksh93/bltins/trap.c (revision b30d193948be5a7794d7ae3ba0ed9c2f72c88e0f)
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