xref: /titanic_50/usr/src/lib/libshell/common/bltins/trap.c (revision 3fbbb872ea33adea240e8fd8c692f6d3131cc69b)
1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *           Copyright (c) 1982-2007 AT&T Knowledge Ventures            *
5 *                      and is licensed under the                       *
6 *                  Common Public License, Version 1.0                  *
7 *                      by AT&T Knowledge Ventures                      *
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, pflag = 0;
49 	register Shell_t *shp = (Shell_t*)extra;
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 		register int	clear;
70 		char *action = arg;
71 		if(!pflag)
72 		{
73 			/* first argument all digits or - means clear */
74 			while(isdigit(*arg))
75 				arg++;
76 			clear = (arg!=action && *arg==0);
77 			if(!clear)
78 			{
79 				++argv;
80 				if(*action=='-' && action[1]==0)
81 					clear++;
82 			}
83 			while(!argv[0])
84 				errormsg(SH_DICT,ERROR_exit(1),e_condition);
85 		}
86 		while(arg = *argv++)
87 		{
88 			sig = sig_number(arg);
89 			if(sig<0)
90 			{
91 				errormsg(SH_DICT,2,e_trap,arg);
92 				return(1);
93 			}
94 			/* internal traps */
95 			if(sig&SH_TRAP)
96 			{
97 				sig &= ~SH_TRAP;
98 				if(sig>SH_DEBUGTRAP)
99 				{
100 					errormsg(SH_DICT,2,e_trap,arg);
101 					return(1);
102 				}
103 				if(pflag)
104 				{
105 					if(arg=shp->st.trap[sig])
106 						sfputr(sfstdout,sh_fmtq(arg),'\n');
107 					continue;
108 				}
109 				if(shp->st.trap[sig])
110 					free(shp->st.trap[sig]);
111 				shp->st.trap[sig] = 0;
112 				if(!clear && *action)
113 					shp->st.trap[sig] = strdup(action);
114 				if(sig == SH_DEBUGTRAP)
115 				{
116 					if(shp->st.trap[sig])
117 						shp->trapnote |= SH_SIGTRAP;
118 					else
119 						shp->trapnote = 0;
120 				}
121 				continue;
122 			}
123 			if(sig>shp->sigmax)
124 			{
125 				errormsg(SH_DICT,2,e_trap,arg);
126 				return(1);
127 			}
128 			else if(pflag)
129 			{
130 				char **trapcom = (shp->st.otrapcom?shp->st.otrapcom:shp->st.trapcom);
131 				if(arg=trapcom[sig])
132 					sfputr(sfstdout,arg,'\n');
133 			}
134 			else if(clear)
135 				sh_sigclear(sig);
136 			else
137 			{
138 				if(sig >= shp->st.trapmax)
139 					shp->st.trapmax = sig+1;
140 				if(arg=shp->st.trapcom[sig])
141 					free(arg);
142 				shp->st.trapcom[sig] = strdup(action);
143 				sh_sigtrap(sig);
144 			}
145 		}
146 	}
147 	else /* print out current traps */
148 		sig_list(shp,-1);
149 	return(0);
150 }
151 
152 int	b_kill(int argc,char *argv[],void *extra)
153 {
154 	register char *signame;
155 	register int sig=SIGTERM, flag=0, n;
156 	register Shell_t *shp = (Shell_t*)extra;
157 	NOT_USED(argc);
158 	while((n = optget(argv,sh_optkill))) switch(n)
159 	{
160 		case ':':
161 			if((signame=argv[opt_info.index++]) && (sig=sig_number(signame+1))>=0)
162 				goto endopts;
163 			opt_info.index--;
164 			errormsg(SH_DICT,2, "%s", opt_info.arg);
165 			break;
166 		case 'n':
167 			sig = (int)opt_info.num;
168 			goto endopts;
169 		case 's':
170 			flag |= S_FLAG;
171 			signame = opt_info.arg;
172 			goto endopts;
173 		case 'l':
174 			flag |= L_FLAG;
175 			break;
176 		case '?':
177 			errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg);
178 			break;
179 	}
180 endopts:
181 	argv += opt_info.index;
182 	if(*argv && strcmp(*argv,"--")==0 && strcmp(*(argv-1),"--")!=0)
183 		argv++;
184 	if(error_info.errors || flag==(L_FLAG|S_FLAG) || (!(*argv) && !(flag&L_FLAG)))
185 		errormsg(SH_DICT,ERROR_usage(2),"%s", optusage((char*)0));
186 	/* just in case we send a kill -9 $$ */
187 	sfsync(sfstderr);
188 	if(flag&L_FLAG)
189 	{
190 		if(!(*argv))
191 			sig_list(shp,0);
192 		else while(signame = *argv++)
193 		{
194 			if(isdigit(*signame))
195 				sig_list(shp,((int)strtol(signame, (char**)0, 10)&0177)+1);
196 			else
197 			{
198 				if((sig=sig_number(signame))<0)
199 				{
200 					shp->exitval = 2;
201 					errormsg(SH_DICT,ERROR_exit(1),e_nosignal,signame);
202 				}
203 				sfprintf(sfstdout,"%d\n",sig);
204 			}
205 		}
206 		return(shp->exitval);
207 	}
208 	if(flag&S_FLAG)
209 	{
210 		if((sig=sig_number(signame)) < 0 || sig > shp->sigmax)
211 			errormsg(SH_DICT,ERROR_exit(1),e_nosignal,signame);
212 	}
213 	if(job_walk(sfstdout,job_kill,sig,argv))
214 		shp->exitval = 1;
215 	return(shp->exitval);
216 }
217 
218 /*
219  * Given the name or number of a signal return the signal number
220  */
221 
222 static int sig_number(const char *string)
223 {
224 	const Shtable_t	*tp;
225 	register int	n,sig=0;
226 	char		*last;
227 	if(isdigit(*string))
228 	{
229 		n = strtol(string,&last,10);
230 		if(*last)
231 			n = -1;
232 	}
233 	else
234 	{
235 		register int c;
236 		n = staktell();
237 		do
238 		{
239 			c = *string++;
240 			if(islower(c))
241 				c = toupper(c);
242 			stakputc(c);
243 		}
244 		while(c);
245 		stakseek(n);
246 		if(memcmp(stakptr(n),"SIG",3)==0)
247 		{
248 			sig = 1;
249 			n += 3;
250 		}
251 		tp = sh_locate(stakptr(n),(const Shtable_t*)shtab_signals,sizeof(*shtab_signals));
252 		n = tp->sh_number;
253 		if(sig==1 && (n>=(SH_TRAP-1) && n < (1<<SH_SIGBITS)))
254 		{
255 			/* sig prefix cannot match internal traps */
256 			n = 0;
257 			tp = (Shtable_t*)((char*)tp + sizeof(*shtab_signals));
258 			if(strcmp(stakptr(n),tp->sh_name)==0)
259 				n = tp->sh_number;
260 		}
261 		n &= (1<<SH_SIGBITS)-1;
262 		if(n < SH_TRAP)
263 			n--;
264 	}
265 	return(n);
266 }
267 
268 /*
269  * if <flag> is positive, then print signal name corresponding to <flag>
270  * if <flag> is zero, then print all signal names
271  * if <flag> is negative, then print all traps
272  */
273 static void sig_list(register Shell_t *shp,register int flag)
274 {
275 	register const struct shtable2	*tp;
276 	register int sig = shp->sigmax+1;
277 	const char *names[SH_TRAP];
278 	const char *traps[SH_DEBUGTRAP+1];
279 	tp=shtab_signals;
280 	if(flag==0)
281 	{
282 		/* not all signals may be defined, so initialize */
283 		while(--sig >= 0)
284 			names[sig] = 0;
285 		for(sig=SH_DEBUGTRAP; sig>=0; sig--)
286 			traps[sig] = 0;
287 	}
288 	while(*tp->sh_name)
289 	{
290 		sig = tp->sh_number;
291 		sig &= ((1<<SH_SIGBITS)-1);
292 		if(sig==flag)
293 		{
294 			sfprintf(sfstdout,"%s\n",tp->sh_name);
295 			return;
296 		}
297 		else if(sig&SH_TRAP)
298 			traps[sig&~SH_TRAP] = (char*)tp->sh_name;
299 		else if(sig < sizeof(names)/sizeof(char*))
300 			names[sig] = (char*)tp->sh_name;
301 		tp++;
302 	}
303 	if(flag > 0)
304 		sfprintf(sfstdout,"%d\n",flag-1);
305 	else if(flag<0)
306 	{
307 		/* print the traps */
308 		register char *trap,*sname,**trapcom;
309 		char name[6];
310 		sig = shp->st.trapmax;
311 		/* use parent traps if otrapcom is set (for $(trap)  */
312 		trapcom = (shp->st.otrapcom?shp->st.otrapcom:shp->st.trapcom);
313 		while(--sig >= 0)
314 		{
315 			if(!(trap=trapcom[sig]))
316 				continue;
317 			if(!(sname=(char*)names[sig+1]))
318 			{
319 				sname = name;
320 				sname[0] = 'S';
321 				sname[1] = 'I';
322 				sname[2] = 'G';
323 				sname[3] = (sig/10)+'0';
324 				sname[4] = (sig%10)+'0';
325 			}
326 			sfprintf(sfstdout,trapfmt,sh_fmtq(trap),sname);
327 		}
328 		for(sig=SH_DEBUGTRAP; sig>=0; sig--)
329 		{
330 			if(!(trap=shp->st.trap[sig]))
331 				continue;
332 			sfprintf(sfstdout,trapfmt,sh_fmtq(trap),traps[sig]);
333 		}
334 	}
335 	else
336 	{
337 		/* print all the signal names */
338 		for(sig=2; sig <= shp->sigmax; sig++)
339 		{
340 			if(names[sig])
341 				sfputr(sfstdout,names[sig],'\n');
342 			else
343 				sfprintf(sfstdout,"SIG%d\n",sig-1);
344 		}
345 	}
346 }
347 
348