Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/*
2
 * signal handling
3
 */
4
 
5
/* Kludge to avoid bogus re-declaration of sigtraps[] error on AIX 3.2.5 */
6
#define FROM_TRAP_C
7
#include "sh.h"
8
 
9
/* Table is indexed by signal number
10
 *
11
 * The script siglist.sh generates siglist.out, which is a sorted, complete
12
 * list of signals
13
 */
14
Trap sigtraps[SIGNALS+1] = {
15
	{ SIGEXIT_, "EXIT", "Signal 0" },
16
	{ 1 , "HUP", "Hangup" },
17
	{ 2 , "INT", "Interrupt" },
18
	{ 3 , "QUIT", "Quit" },
19
	{ 4 , "ILL", "Illegal instruction" },
20
	{ 5 , "ABRT", "Abort" },
21
	{ 6 , "FPE", "Floating point exception" },
22
	{ 7 , "KILL", "Killed" },
23
	{ 8 , "SEGV", "Memory fault" },
24
	{ 9 , "PIPE", "Broken pipe" },
25
	{ 10 , "ALRM", "Alarm clock" },
26
	{ 11 , "TERM", "Terminated" },
27
	{ 12 , "USR1", "User defined signal 1" },
28
	{ 13 , "USR2", "User defined signal 2" },
29
	{ 14 , "BUS", "Bus error" },
30
	{ 15 , "CHLD", "Child exited" },
31
	{ 16 , "CONT", "Continued" },
32
	{ 17 , "STOP", "Stopped (signal)" },
33
	{ 18 , "TSTP", "Stopped" },
34
	{ 19 , "TTIN", "Stopped (tty input)" },
35
	{ 20 , "TTOU", "Stopped (tty output)" },
36
	{ SIGERR_,  "ERR",  "Error handler" },
37
    };
38
 
39
static struct sigaction Sigact_ign, Sigact_trap;
40
 
41
void
42
inittraps()
43
{
44
#ifdef HAVE_SYS_SIGLIST
45
# ifndef SYS_SIGLIST_DECLARED
46
	extern char	*sys_siglist[];
47
# endif
48
	int	i;
49
 
50
	/* Use system description, if available, for unknown signals... */
51
	for (i = 0; i < NSIG; i++)
52
		if (!sigtraps[i].name && sys_siglist[i] && sys_siglist[i][0])
53
			sigtraps[i].mess = sys_siglist[i];
54
#endif	/* HAVE_SYS_SIGLIST */
55
 
56
	sigemptyset(&Sigact_ign.sa_mask);
57
	Sigact_ign.sa_flags = KSH_SA_FLAGS;
58
	Sigact_ign.sa_handler = SIG_IGN;
59
	Sigact_trap = Sigact_ign;
60
	Sigact_trap.sa_handler = trapsig;
61
 
62
	sigtraps[SIGINT].flags |= TF_DFL_INTR | TF_TTY_INTR;
63
	sigtraps[SIGQUIT].flags |= TF_DFL_INTR | TF_TTY_INTR;
64
	sigtraps[SIGTERM].flags |= TF_DFL_INTR;/* not fatal for interactive */
65
	sigtraps[SIGHUP].flags |= TF_FATAL;
66
	sigtraps[SIGCHLD].flags |= TF_SHELL_USES;
67
 
68
	/* these are always caught so we can clean up any temproary files. */
69
	setsig(&sigtraps[SIGINT], trapsig, SS_RESTORE_ORIG);
70
	setsig(&sigtraps[SIGQUIT], trapsig, SS_RESTORE_ORIG);
71
	setsig(&sigtraps[SIGTERM], trapsig, SS_RESTORE_ORIG);
72
	setsig(&sigtraps[SIGHUP], trapsig, SS_RESTORE_ORIG);
73
}
74
 
75
#ifdef KSH
76
static RETSIGTYPE alarm_catcher ARGS((int sig));
77
 
78
void
79
alarm_init()
80
{
81
	sigtraps[SIGALRM].flags |= TF_SHELL_USES;
82
	setsig(&sigtraps[SIGALRM], alarm_catcher,
83
		SS_RESTORE_ORIG|SS_FORCE|SS_SHTRAP);
84
}
85
 
86
static RETSIGTYPE
87
alarm_catcher(sig)
88
	int sig;
89
{
90
	if (ksh_tmout_state == TMOUT_READING) {
91
		int left = alarm(0);
92
 
93
		if (left == 0) {
94
			ksh_tmout_state = TMOUT_LEAVING;
95
			intrsig = 1;
96
		} else
97
			alarm(left);
98
	}
99
	return RETSIGVAL;
100
}
101
#endif /* KSH */
102
 
103
Trap *
104
gettrap(name, igncase)
105
	const char *name;
106
	int igncase;
107
{
108
	int i;
109
	register Trap *p;
110
 
111
	if (digit(*name)) {
112
		int n;
113
 
114
		if (getn(name, &n) && 0 <= n && n < SIGNALS)
115
			return &sigtraps[n];
116
		return NULL;
117
	}
118
	if (strncasecmp(name, "sig", 3) == 0)
119
		name += 3;
120
	for (p = sigtraps, i = SIGNALS+1; --i >= 0; p++)
121
		if (p->name && (igncase ? strcasecmp(p->name, name) == 0
122
					: strcmp(p->name, name) == 0))
123
			return p;
124
	return NULL;
125
}
126
 
127
/*
128
 * trap signal handler
129
 */
130
RETSIGTYPE
131
trapsig(i)
132
	int i;
133
{
134
	Trap *p = &sigtraps[i];
135
 
136
	trap = p->set = 1;
137
	if (p->flags & TF_DFL_INTR)
138
		intrsig = 1;
139
	if ((p->flags & TF_FATAL) && !p->trap) {
140
		fatal_trap = 1;
141
		intrsig = 1;
142
	}
143
	if (p->shtrap)
144
		(*p->shtrap)(i);
145
#ifdef V7_SIGNALS
146
	if (sigtraps[i].cursig == trapsig) /* this for SIGCHLD,SIGALRM */
147
		sigaction(i, &Sigact_trap, (struct sigaction *) 0);
148
#endif /* V7_SIGNALS */
149
	return RETSIGVAL;
150
}
151
 
152
/* called when we want to allow the user to ^C out of something - won't
153
 * work if user has trapped SIGINT.
154
 */
155
void
156
intrcheck()
157
{
158
	if (intrsig)
159
		runtraps(TF_DFL_INTR|TF_FATAL);
160
}
161
 
162
/* called after EINTR to check if a signal with normally causes process
163
 * termination has been received.
164
 */
165
int
166
fatal_trap_check()
167
{
168
	int i;
169
	Trap *p;
170
 
171
	/* todo: should check if signal is fatal, not the TF_DFL_INTR flag */
172
	for (p = sigtraps, i = SIGNALS+1; --i >= 0; p++)
173
		if (p->set && (p->flags & (TF_DFL_INTR|TF_FATAL)))
174
			/* return value is used as an exit code */
175
			return 128 + p->signal;
176
	return 0;
177
}
178
 
179
/* Returns the signal number of any pending traps: ie, a signal which has
180
 * occured for which a trap has been set or for which the TF_DFL_INTR flag
181
 * is set.
182
 */
183
int
184
trap_pending()
185
{
186
	int i;
187
	Trap *p;
188
 
189
	for (p = sigtraps, i = SIGNALS+1; --i >= 0; p++)
190
		if (p->set && ((p->trap && p->trap[0])
191
			       || ((p->flags & (TF_DFL_INTR|TF_FATAL))
192
				   && !p->trap)))
193
			return p->signal;
194
	return 0;
195
}
196
 
197
/*
198
 * run any pending traps.  If intr is set, only run traps that
199
 * can interrupt commands.
200
 */
201
void
202
runtraps(flag)
203
	int flag;
204
{
205
	int i;
206
	register Trap *p;
207
 
208
#ifdef KSH
209
	if (ksh_tmout_state == TMOUT_LEAVING) {
210
		ksh_tmout_state = TMOUT_EXECUTING;
211
		warningf(FALSE, "timed out waiting for input");
212
		unwind(LEXIT);
213
	} else
214
		/* XXX: this means the alarm will have no effect if a trap
215
		 * is caught after the alarm() was started...not good.
216
		 */
217
		ksh_tmout_state = TMOUT_EXECUTING;
218
#endif /* KSH */
219
	if (!flag)
220
		trap = 0;
221
	if (flag & TF_DFL_INTR)
222
		intrsig = 0;
223
	if (flag & TF_FATAL)
224
		fatal_trap = 0;
225
	for (p = sigtraps, i = SIGNALS+1; --i >= 0; p++)
226
		if (p->set && (!flag
227
			       || ((p->flags & flag) && p->trap == (char *) 0)))
228
			runtrap(p);
229
}
230
 
231
void
232
runtrap(p)
233
	Trap *p;
234
{
235
	int	i = p->signal;
236
	char	*trapstr = p->trap;
237
	int	oexstat;
238
	int	UNINITIALIZED(old_changed);
239
 
240
	p->set = 0;
241
	if (trapstr == (char *) 0) { /* SIG_DFL */
242
		if (p->flags & TF_FATAL) {
243
			/* eg, SIGHUP */
244
			exstat = 128 + i;
245
			unwind(LLEAVE);
246
		}
247
		if (p->flags & TF_DFL_INTR) {
248
			/* eg, SIGINT, SIGQUIT, SIGTERM, etc. */
249
			exstat = 128 + i;
250
			unwind(LINTR);
251
		}
252
		return;
253
	}
254
	if (trapstr[0] == '\0') /* SIG_IGN */
255
		return;
256
	if (i == SIGEXIT_ || i == SIGERR_) {	/* avoid recursion on these */
257
		old_changed = p->flags & TF_CHANGED;
258
		p->flags &= ~TF_CHANGED;
259
		p->trap = (char *) 0;
260
	}
261
	oexstat = exstat;
262
	/* Note: trapstr is fully parsed before anything is executed, thus
263
	 * no problem with afree(p->trap) in settrap() while still in use.
264
	 */
265
	command(trapstr);
266
	exstat = oexstat;
267
	if (i == SIGEXIT_ || i == SIGERR_) {
268
		if (p->flags & TF_CHANGED)
269
			/* don't clear TF_CHANGED */
270
			afree(trapstr, APERM);
271
		else
272
			p->trap = trapstr;
273
		p->flags |= old_changed;
274
	}
275
}
276
 
277
/* clear pending traps and reset user's trap handlers; used after fork(2) */
278
void
279
cleartraps()
280
{
281
	int i;
282
	Trap *p;
283
 
284
	trap = 0;
285
	intrsig = 0;
286
	fatal_trap = 0;
287
	for (i = SIGNALS+1, p = sigtraps; --i >= 0; p++) {
288
		p->set = 0;
289
		if ((p->flags & TF_USER_SET) && (p->trap && p->trap[0]))
290
			settrap(p, (char *) 0);
291
	}
292
}
293
 
294
/* restore signals just before an exec(2) */
295
void
296
restoresigs()
297
{
298
	int i;
299
	Trap *p;
300
 
301
	for (i = SIGNALS+1, p = sigtraps; --i >= 0; p++)
302
		if (p->flags & (TF_EXEC_IGN|TF_EXEC_DFL))
303
			setsig(p, (p->flags & TF_EXEC_IGN) ? SIG_IGN : SIG_DFL,
304
				SS_RESTORE_CURR|SS_FORCE);
305
}
306
 
307
void
308
settrap(p, s)
309
	Trap *p;
310
	char *s;
311
{
312
	handler_t f;
313
 
314
	if (p->trap)
315
		afree(p->trap, APERM);
316
	p->trap = str_save(s, APERM); /* handles s == 0 */
317
	p->flags |= TF_CHANGED;
318
	f = !s ? SIG_DFL : s[0] ? trapsig : SIG_IGN;
319
 
320
	p->flags |= TF_USER_SET;
321
	if ((p->flags & (TF_DFL_INTR|TF_FATAL)) && f == SIG_DFL)
322
		f = trapsig;
323
	else if (p->flags & TF_SHELL_USES) {
324
		if (!(p->flags & TF_ORIG_IGN) || Flag(FTALKING)) {
325
			/* do what user wants at exec time */
326
			p->flags &= ~(TF_EXEC_IGN|TF_EXEC_DFL);
327
			if (f == SIG_IGN)
328
				p->flags |= TF_EXEC_IGN;
329
			else
330
				p->flags |= TF_EXEC_DFL;
331
		}
332
		/* assumes handler already set to what shell wants it
333
		 * (normally trapsig, but could be j_sigchld() or SIG_IGN)
334
		 */
335
		return;
336
	}
337
 
338
	/* todo: should we let user know signal is ignored? how? */
339
	setsig(p, f, SS_RESTORE_CURR|SS_USER);
340
}
341
 
342
/* Called by c_print() when writing to a co-process to ensure SIGPIPE won't
343
 * kill shell (unless user catches it and exits)
344
 */
345
int
346
block_pipe()
347
{
348
	int restore_dfl = 0;
349
	Trap *p = &sigtraps[SIGPIPE];
350
 
351
	if (!(p->flags & (TF_ORIG_IGN|TF_ORIG_DFL))) {
352
		setsig(p, SIG_IGN, SS_RESTORE_CURR);
353
		if (p->flags & TF_ORIG_DFL)
354
			restore_dfl = 1;
355
	} else if (p->cursig == SIG_DFL) {
356
		setsig(p, SIG_IGN, SS_RESTORE_CURR);
357
		restore_dfl = 1; /* restore to SIG_DFL */
358
	}
359
	return restore_dfl;
360
}
361
 
362
/* Called by c_print() to undo whatever block_pipe() did */
363
void
364
restore_pipe(restore_dfl)
365
	int restore_dfl;
366
{
367
	if (restore_dfl)
368
		setsig(&sigtraps[SIGPIPE], SIG_DFL, SS_RESTORE_CURR);
369
}
370
 
371
/* Set action for a signal.  Action may not be set if original
372
 * action was SIG_IGN, depending on the value of flags and
373
 * FTALKING.
374
 */
375
int
376
setsig(p, f, flags)
377
	Trap *p;
378
	handler_t f;
379
	int flags;
380
{
381
	struct sigaction sigact;
382
 
383
	if (p->signal == SIGEXIT_ || p->signal == SIGERR_)
384
		return 1;
385
 
386
	/* First time setting this signal?  If so, get and note the current
387
	 * setting.
388
	 */
389
	if (!(p->flags & (TF_ORIG_IGN|TF_ORIG_DFL))) {
390
		sigaction(p->signal, &Sigact_ign, &sigact);
391
		p->flags |= sigact.sa_handler == SIG_IGN ?
392
					TF_ORIG_IGN : TF_ORIG_DFL;
393
		p->cursig = SIG_IGN;
394
	}
395
 
396
	/* Generally, an ignored signal stays ignored, except if
397
	 *	- the user of an interactive shell wants to change it
398
	 *	- the shell wants for force a change
399
	 */
400
	if ((p->flags & TF_ORIG_IGN) && !(flags & SS_FORCE)
401
	    && (!(flags & SS_USER) || !Flag(FTALKING)))
402
		return 0;
403
 
404
	setexecsig(p, flags & SS_RESTORE_MASK);
405
 
406
	/* This is here 'cause there should be a way of clearing shtraps, but
407
	 * don't know if this is a sane way of doing it.  At the moment,
408
	 * all users of shtrap are lifetime users (SIGCHLD, SIGALRM, SIGWINCH).
409
	 */
410
	if (!(flags & SS_USER))
411
		p->shtrap = (handler_t) 0;
412
	if (flags & SS_SHTRAP) {
413
		p->shtrap = f;
414
		f = trapsig;
415
	}
416
 
417
	if (p->cursig != f) {
418
		p->cursig = f;
419
		sigemptyset(&sigact.sa_mask);
420
		sigact.sa_flags = KSH_SA_FLAGS;
421
		sigact.sa_handler = f;
422
		sigaction(p->signal, &sigact, (struct sigaction *) 0);
423
	}
424
 
425
	return 1;
426
}
427
 
428
/* control what signal is set to before an exec() */
429
void
430
setexecsig(p, restore)
431
	Trap *p;
432
	int restore;
433
{
434
	/* XXX debugging */
435
	if (!(p->flags & (TF_ORIG_IGN|TF_ORIG_DFL)))
436
		internal_errorf(1, "setexecsig: unset signal %d(%s)",
437
			p->signal, p->name);
438
 
439
	/* restore original value for exec'd kids */
440
	p->flags &= ~(TF_EXEC_IGN|TF_EXEC_DFL);
441
	switch (restore & SS_RESTORE_MASK) {
442
	  case SS_RESTORE_CURR: /* leave things as they currently are */
443
		break;
444
	  case SS_RESTORE_ORIG:
445
		p->flags |= p->flags & TF_ORIG_IGN ? TF_EXEC_IGN : TF_EXEC_DFL;
446
		break;
447
	  case SS_RESTORE_DFL:
448
		p->flags |= TF_EXEC_DFL;
449
		break;
450
	  case SS_RESTORE_IGN:
451
		p->flags |= TF_EXEC_IGN;
452
		break;
453
	}
454
}