~ubuntu-branches/ubuntu/hardy/klibc/hardy-updates

« back to all changes in this revision

Viewing changes to ash/trap.c

  • Committer: Bazaar Package Importer
  • Author(s): Jeff Bailey
  • Date: 2006-01-04 20:24:52 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20060104202452-ec4v3n829rymukuv
Tags: 1.1.15-0ubuntu1
* New upstream version.

* Patch to fix compilation on parisc64 kernels.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*      $NetBSD: trap.c,v 1.30 2003/08/26 18:13:25 jmmv Exp $   */
2
 
 
3
 
/*-
4
 
 * Copyright (c) 1991, 1993
5
 
 *      The Regents of the University of California.  All rights reserved.
6
 
 *
7
 
 * This code is derived from software contributed to Berkeley by
8
 
 * Kenneth Almquist.
9
 
 *
10
 
 * Redistribution and use in source and binary forms, with or without
11
 
 * modification, are permitted provided that the following conditions
12
 
 * are met:
13
 
 * 1. Redistributions of source code must retain the above copyright
14
 
 *    notice, this list of conditions and the following disclaimer.
15
 
 * 2. Redistributions in binary form must reproduce the above copyright
16
 
 *    notice, this list of conditions and the following disclaimer in the
17
 
 *    documentation and/or other materials provided with the distribution.
18
 
 * 3. Neither the name of the University nor the names of its contributors
19
 
 *    may be used to endorse or promote products derived from this software
20
 
 *    without specific prior written permission.
21
 
 *
22
 
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23
 
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
 
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
 
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26
 
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27
 
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28
 
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29
 
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30
 
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31
 
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32
 
 * SUCH DAMAGE.
33
 
 */
34
 
 
35
 
#ifndef __KLIBC__
36
 
#include <sys/cdefs.h>
37
 
#endif
38
 
#ifndef __RCSID
39
 
#define __RCSID(arg)
40
 
#endif
41
 
#ifndef lint
42
 
#if 0
43
 
static char sccsid[] = "@(#)trap.c      8.5 (Berkeley) 6/5/95";
44
 
#else
45
 
__RCSID("$NetBSD: trap.c,v 1.30 2003/08/26 18:13:25 jmmv Exp $");
46
 
#endif
47
 
#endif /* not lint */
48
 
 
49
 
#include <signal.h>
50
 
#include <unistd.h>
51
 
#include <stdlib.h>
52
 
 
53
 
#include "shell.h"
54
 
#include "main.h"
55
 
#include "nodes.h"      /* for other headers */
56
 
#include "eval.h"
57
 
#include "jobs.h"
58
 
#include "show.h"
59
 
#include "options.h"
60
 
#include "syntax.h"
61
 
#include "output.h"
62
 
#include "memalloc.h"
63
 
#include "error.h"
64
 
#include "trap.h"
65
 
#include "mystring.h"
66
 
 
67
 
#ifdef __KLIBC__
68
 
typedef __sighandler_t sig_t;
69
 
#define POSIX_SIGNALS
70
 
#undef _GNU_SOURCE
71
 
#define sys_signame sys_siglist
72
 
#endif
73
 
 
74
 
/*
75
 
 * Sigmode records the current value of the signal handlers for the various
76
 
 * modes.  A value of zero means that the current handler is not known.
77
 
 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
78
 
 */
79
 
 
80
 
#define S_DFL 1                 /* default signal handling (SIG_DFL) */
81
 
#define S_CATCH 2               /* signal is caught */
82
 
#define S_IGN 3                 /* signal is ignored (SIG_IGN) */
83
 
#define S_HARD_IGN 4            /* signal is ignored permenantly */
84
 
#define S_RESET 5               /* temporary - to reset a hard ignored sig */
85
 
 
86
 
 
87
 
char *trap[NSIG+1];             /* trap handler commands */
88
 
MKINIT char sigmode[NSIG];      /* current value of signal */
89
 
char gotsig[NSIG];              /* indicates specified signal received */
90
 
int pendingsigs;                /* indicates some signal received */
91
 
 
92
 
static int getsigaction(int, sig_t *);
93
 
 
94
 
/*
95
 
 * return the signal number described by `p' (as a number or a name)
96
 
 * or -1 if it isn't one
97
 
 */
98
 
 
99
 
static int
100
 
signame_to_signum(const char *p)
101
 
{
102
 
        int i;
103
 
 
104
 
        if (is_number(p))
105
 
                return number(p);
106
 
 
107
 
        if (strcasecmp(p, "exit") == 0 )
108
 
                return 0;
109
 
        
110
 
        if (strncasecmp(p, "sig", 3) == 0)
111
 
                p += 3;
112
 
 
113
 
        for (i = 0; i < NSIG; ++i)
114
 
#ifdef _GNU_SOURCE
115
 
                if (strcasecmp (p, strsignal(i)) == 0)
116
 
#else
117
 
                if (strcasecmp (p, sys_signame[i]) == 0)
118
 
#endif
119
 
                        return i;
120
 
        return -1;
121
 
}
122
 
 
123
 
/*
124
 
 * Print a list of valid signal names
125
 
 */
126
 
static void
127
 
printsignals(void)
128
 
{
129
 
        int n;
130
 
 
131
 
        out1str("EXIT ");
132
 
 
133
 
        for (n = 1; n < NSIG; n++) {
134
 
#ifdef _GNU_SOURCE
135
 
                out1fmt("%s", strsignal(n));
136
 
#else
137
 
                out1fmt("%s", sys_signame[n]);
138
 
#endif
139
 
                if ((n == NSIG/2) ||  n == (NSIG - 1))
140
 
                        out1str("\n");
141
 
                else
142
 
                        out1c(' ');
143
 
        }
144
 
}
145
 
 
146
 
/*
147
 
 * The trap builtin.
148
 
 */
149
 
 
150
 
int
151
 
trapcmd(int argc, char **argv)
152
 
{
153
 
        char *action;
154
 
        char **ap;
155
 
        int signo;
156
 
 
157
 
        if (argc <= 1) {
158
 
                for (signo = 0 ; signo <= NSIG ; signo++) {
159
 
                        if (trap[signo] != NULL)
160
 
#ifdef _GNU_SOURCE
161
 
                                out1fmt("trap -- '%s' %s\n", trap[signo],
162
 
                                    (signo) ? strsignal(signo) : "EXIT");
163
 
#else
164
 
                                out1fmt("trap -- '%s' %s\n", trap[signo],
165
 
                                    (signo) ? sys_signame[signo] : "EXIT");
166
 
#endif
167
 
                }
168
 
                return 0;
169
 
        }
170
 
        ap = argv + 1;
171
 
 
172
 
        action = NULL;
173
 
 
174
 
        if (strcmp(*ap, "--") == 0)
175
 
                if (*++ap == NULL)
176
 
                        return 0;
177
 
 
178
 
        if (signame_to_signum(*ap) == -1) {
179
 
                if ((*ap)[0] == '-') {
180
 
                        if ((*ap)[1] == '\0')
181
 
                                ap++;
182
 
                        else if ((*ap)[1] == 'l' && (*ap)[2] == '\0') {
183
 
                                printsignals();
184
 
                                return 0;
185
 
                        }
186
 
                        else
187
 
                                error("bad option %s\n", *ap);
188
 
                }
189
 
                else
190
 
                        action = *ap++;
191
 
        }
192
 
 
193
 
        while (*ap) {
194
 
                if (is_number(*ap))
195
 
                        signo = number(*ap);
196
 
                else
197
 
                        signo = signame_to_signum(*ap);
198
 
 
199
 
                if (signo < 0 || signo > NSIG)
200
 
                        error("%s: bad trap", *ap);
201
 
 
202
 
                INTOFF;
203
 
                if (action)
204
 
                        action = savestr(action);
205
 
 
206
 
                if (trap[signo])
207
 
                        ckfree(trap[signo]);
208
 
 
209
 
                trap[signo] = action;
210
 
 
211
 
                if (signo != 0)
212
 
                        setsignal(signo, 0);
213
 
                INTON;
214
 
                ap++;
215
 
        }
216
 
        return 0;
217
 
}
218
 
 
219
 
 
220
 
 
221
 
/*
222
 
 * Clear traps on a fork or vfork.
223
 
 * Takes one arg vfork, to tell it to not be destructive of
224
 
 * the parents variables.
225
 
 */
226
 
 
227
 
void
228
 
clear_traps(int vforked)
229
 
{
230
 
        char **tp;
231
 
 
232
 
        for (tp = trap ; tp <= &trap[NSIG] ; tp++) {
233
 
                if (*tp && **tp) {      /* trap not NULL or SIG_IGN */
234
 
                        INTOFF;
235
 
                        if (!vforked) {
236
 
                                ckfree(*tp);
237
 
                                *tp = NULL;
238
 
                        }
239
 
                        if (tp != &trap[0])
240
 
                                setsignal(tp - trap, vforked);
241
 
                        INTON;
242
 
                }
243
 
        }
244
 
}
245
 
 
246
 
 
247
 
 
248
 
/*
249
 
 * Set the signal handler for the specified signal.  The routine figures
250
 
 * out what it should be set to.
251
 
 */
252
 
 
253
 
long
254
 
setsignal(int signo, int vforked)
255
 
{
256
 
        int action;
257
 
        sig_t sigact = SIG_DFL;
258
 
#ifdef POSIX_SIGNALS
259
 
        struct sigaction act, oact;
260
 
#endif
261
 
        char *t, tsig;
262
 
 
263
 
        if ((t = trap[signo]) == NULL)
264
 
                action = S_DFL;
265
 
        else if (*t != '\0')
266
 
                action = S_CATCH;
267
 
        else
268
 
                action = S_IGN;
269
 
        if (rootshell && !vforked && action == S_DFL) {
270
 
                switch (signo) {
271
 
                case SIGINT:
272
 
                        if (iflag || minusc || sflag == 0)
273
 
                                action = S_CATCH;
274
 
                        break;
275
 
                case SIGQUIT:
276
 
#ifdef DEBUG
277
 
                        if (debug)
278
 
                                break;
279
 
#endif
280
 
                        /* FALLTHROUGH */
281
 
                case SIGTERM:
282
 
                        if (iflag)
283
 
                                action = S_IGN;
284
 
                        break;
285
 
#if JOBS
286
 
                case SIGTSTP:
287
 
                case SIGTTOU:
288
 
                        if (mflag)
289
 
                                action = S_IGN;
290
 
                        break;
291
 
#endif
292
 
                }
293
 
        }
294
 
 
295
 
        t = &sigmode[signo - 1];
296
 
        tsig = *t;
297
 
        if (tsig == 0) {
298
 
                /*
299
 
                 * current setting unknown
300
 
                 */
301
 
                if (!getsigaction(signo, &sigact)) {
302
 
                        /*
303
 
                         * Pretend it worked; maybe we should give a warning
304
 
                         * here, but other shells don't. We don't alter
305
 
                         * sigmode, so that we retry every time.
306
 
                         */
307
 
                        return 0;
308
 
                }
309
 
                if (sigact == SIG_IGN) {
310
 
                        if (mflag && (signo == SIGTSTP ||
311
 
                             signo == SIGTTIN || signo == SIGTTOU)) {
312
 
                                tsig = S_IGN;   /* don't hard ignore these */
313
 
                        } else
314
 
                                tsig = S_HARD_IGN;
315
 
                } else {
316
 
                        tsig = S_RESET; /* force to be set */
317
 
                }
318
 
        }
319
 
        if (tsig == S_HARD_IGN || tsig == action)
320
 
                return 0;
321
 
        switch (action) {
322
 
                case S_DFL:     sigact = SIG_DFL;       break;
323
 
                case S_CATCH:   sigact = onsig;         break;
324
 
                case S_IGN:     sigact = SIG_IGN;       break;
325
 
        }
326
 
        if (!vforked)
327
 
                *t = action;
328
 
#ifdef POSIX_SIGNALS
329
 
        act.sa_handler = sigact;
330
 
        sigemptyset(&act.sa_mask);
331
 
        act.sa_flags = 0;
332
 
#ifdef SA_INTERRUPT
333
 
        act.sa_flags |= SA_INTERRUPT;
334
 
#endif
335
 
        if (sigaction(signo, &act, &oact) < 0) 
336
 
                return (long)SIG_ERR;
337
 
        return (long)oact.sa_handler;
338
 
#else
339
 
        siginterrupt(signo, 1);
340
 
        return (long)signal(signo, sigact);
341
 
#endif
342
 
}
343
 
 
344
 
/*
345
 
 * Return the current setting for sig w/o changing it.
346
 
 */
347
 
static int
348
 
getsigaction(int signo, sig_t *sigact)
349
 
{
350
 
        struct sigaction sa;
351
 
 
352
 
        if (sigaction(signo, (struct sigaction *)0, &sa) == -1)
353
 
                return 0;
354
 
        *sigact = (sig_t) sa.sa_handler;
355
 
        return 1;
356
 
}
357
 
 
358
 
/*
359
 
 * Ignore a signal.
360
 
 */
361
 
 
362
 
void
363
 
ignoresig(int signo, int vforked)
364
 
{
365
 
        if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
366
 
                bsd_signal(signo, SIG_IGN);
367
 
        }
368
 
        if (!vforked)
369
 
                sigmode[signo - 1] = S_HARD_IGN;
370
 
}
371
 
 
372
 
 
373
 
#ifdef mkinit
374
 
INCLUDE <signal.h>
375
 
INCLUDE "trap.h"
376
 
 
377
 
SHELLPROC {
378
 
        char *sm;
379
 
 
380
 
        clear_traps(0);
381
 
        for (sm = sigmode ; sm < sigmode + NSIG ; sm++) {
382
 
                if (*sm == S_IGN)
383
 
                        *sm = S_HARD_IGN;
384
 
        }
385
 
}
386
 
#endif
387
 
 
388
 
 
389
 
 
390
 
/*
391
 
 * Signal handler.
392
 
 *
393
 
 * The __cdecl is to work around the fact that the Linux/i386 kernel prior
394
 
 * to 2.6.9-rc2 didn't pass the proper arguments to regparm'd signal handlers.
395
 
 */
396
 
__cdecl void
397
 
onsig(int signo)
398
 
{
399
 
        bsd_signal(signo, onsig);
400
 
        if (signo == SIGINT && trap[SIGINT] == NULL) {
401
 
                onint();
402
 
                return;
403
 
        }
404
 
        gotsig[signo - 1] = 1;
405
 
        pendingsigs++;
406
 
}
407
 
 
408
 
 
409
 
 
410
 
/*
411
 
 * Called to execute a trap.  Perhaps we should avoid entering new trap
412
 
 * handlers while we are executing a trap handler.
413
 
 */
414
 
 
415
 
void
416
 
dotrap(void)
417
 
{
418
 
        int i;
419
 
        int savestatus;
420
 
 
421
 
        for (;;) {
422
 
                for (i = 1 ; ; i++) {
423
 
                        if (gotsig[i - 1])
424
 
                                break;
425
 
                        if (i >= NSIG)
426
 
                                goto done;
427
 
                }
428
 
                gotsig[i - 1] = 0;
429
 
                savestatus=exitstatus;
430
 
                evalstring(trap[i], 0);
431
 
                exitstatus=savestatus;
432
 
        }
433
 
done:
434
 
        pendingsigs = 0;
435
 
}
436
 
 
437
 
 
438
 
 
439
 
/*
440
 
 * Controls whether the shell is interactive or not.
441
 
 */
442
 
 
443
 
 
444
 
void
445
 
setinteractive(int on)
446
 
{
447
 
        static int is_interactive;
448
 
 
449
 
        if (on == is_interactive)
450
 
                return;
451
 
        setsignal(SIGINT, 0);
452
 
        setsignal(SIGQUIT, 0);
453
 
        setsignal(SIGTERM, 0);
454
 
        is_interactive = on;
455
 
}
456
 
 
457
 
 
458
 
 
459
 
/*
460
 
 * Called to exit the shell.
461
 
 */
462
 
 
463
 
void
464
 
exitshell(int status)
465
 
{
466
 
        struct jmploc loc1, loc2;
467
 
        char *p;
468
 
 
469
 
        TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
470
 
        if (setjmp(loc1.loc)) {
471
 
                goto l1;
472
 
        }
473
 
        if (setjmp(loc2.loc)) {
474
 
                goto l2;
475
 
        }
476
 
        handler = &loc1;
477
 
        if ((p = trap[0]) != NULL && *p != '\0') {
478
 
                trap[0] = NULL;
479
 
                evalstring(p, 0);
480
 
        }
481
 
l1:   handler = &loc2;                  /* probably unnecessary */
482
 
        flushall();
483
 
#if JOBS
484
 
        setjobctl(0);
485
 
#endif
486
 
l2:   _exit(status);
487
 
        /* NOTREACHED */
488
 
}