Subversion Repositories HelenOS

Rev

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

Rev Author Line No. Line
2714 cejka 1
/*  $NetBSD: trap.c,v 1.24 2000/05/22 10:18:47 elric 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. All advertising materials mentioning features or use of this software
19
 *    must display the following acknowledgement:
20
 *  This product includes software developed by the University of
21
 *  California, Berkeley and its contributors.
22
 * 4. Neither the name of the University nor the names of its contributors
23
 *    may be used to endorse or promote products derived from this software
24
 *    without specific prior written permission.
25
 *
26
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36
 * SUCH DAMAGE.
37
 */
38
 
39
#include <sys/cdefs.h>
40
#ifndef lint
41
#if 0
42
static char sccsid[] = "@(#)trap.c  8.5 (Berkeley) 6/5/95";
43
#else
44
__RCSID("$NetBSD: trap.c,v 1.24 2000/05/22 10:18:47 elric Exp $");
45
#endif
46
#endif /* not lint */
47
 
48
#include <signal.h>
49
#include <unistd.h>
50
#include <stdlib.h>
51
 
52
#include "shell.h"
53
#include "main.h"
54
#include "nodes.h"  /* for other headers */
55
#include "eval.h"
56
#include "jobs.h"
57
#include "show.h"
58
#include "options.h"
59
#include "syntax.h"
60
#include "output.h"
61
#include "memalloc.h"
62
#include "error.h"
63
#include "trap.h"
64
#include "mystring.h"
65
#include "mail.h"
66
 
67
#ifdef HETIO
68
#include "hetio.h"
69
#endif
70
 
71
/*
72
 * Sigmode records the current value of the signal handlers for the various
73
 * modes.  A value of zero means that the current handler is not known.
74
 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
75
 */
76
 
77
#define S_DFL 1         /* default signal handling (SIG_DFL) */
78
#define S_CATCH 2       /* signal is caught */
79
#define S_IGN 3         /* signal is ignored (SIG_IGN) */
80
#define S_HARD_IGN 4        /* signal is ignored permenantly */
81
#define S_RESET 5       /* temporary - to reset a hard ignored sig */
82
 
83
 
84
extern char nullstr[1];     /* null string */
85
 
86
char *trap[NSIG+1];     /* trap handler commands */
87
MKINIT char sigmode[NSIG];  /* current value of signal */
88
char gotsig[NSIG];      /* indicates specified signal received */
89
int pendingsigs;            /* indicates some signal received */
90
 
91
extern char *signal_names[];
92
 
93
/*
94
 * The trap builtin.
95
 */
96
 
97
int
98
trapcmd(argc, argv)
99
    int argc;
100
    char **argv;
101
{
102
    char *action;
103
    char **ap;
104
    int signo;
105
 
106
    if (argc <= 1) {
107
        for (signo = 0 ; signo <= NSIG ; signo++) {
108
            if (trap[signo] != NULL)
109
                out1fmt("%d: %s\n", signo, trap[signo]);
110
        }
111
        return 0;
112
    }
113
    ap = argv + 1;
114
    if (argc == 2)
115
        action = NULL;
116
    else
117
        action = *ap++;
118
    while (*ap) {
119
        if ((signo = decode_signal(*ap)) < 0)
120
            error("%s: bad trap", *ap);
121
        INTOFF;
122
        if (action) {
123
            if (action[0] == '-' && action[1] == '\0')
124
                action = NULL;
125
            else
126
                action = savestr(action);
127
        }
128
        if (trap[signo])
129
            ckfree(trap[signo]);
130
        trap[signo] = action;
131
        if (signo != 0)
132
            setsignal(signo);
133
        INTON;
134
        ap++;
135
    }
136
    return 0;
137
}
138
 
139
 
140
 
141
/*
142
 * Clear traps on a fork.
143
 */
144
 
145
void
146
clear_traps() {
147
    char **tp;
148
 
149
    for (tp = trap ; tp <= &trap[NSIG] ; tp++) {
150
        if (*tp && **tp) {  /* trap not NULL or SIG_IGN */
151
            INTOFF;
152
            ckfree(*tp);
153
            *tp = NULL;
154
            if (tp != &trap[0])
155
                setsignal(tp - trap);
156
            INTON;
157
        }
158
    }
159
}
160
 
161
 
162
 
163
/*
164
 * Set the signal handler for the specified signal.  The routine figures
165
 * out what it should be set to.
166
 */
167
 
168
void
169
setsignal(signo)
170
    int signo;
171
{
172
    int action;
173
    char *t;
174
    struct sigaction act;
175
 
176
    if ((t = trap[signo]) == NULL)
177
        action = S_DFL;
178
    else if (*t != '\0')
179
        action = S_CATCH;
180
    else
181
        action = S_IGN;
182
    if (rootshell && action == S_DFL) {
183
        switch (signo) {
184
        case SIGINT:
185
            if (iflag || minusc || sflag == 0)
186
                action = S_CATCH;
187
            break;
188
        case SIGQUIT:
189
#ifdef DEBUG
190
            {
191
            extern int debug;
192
 
193
            if (debug)
194
                break;
195
            }
196
#endif
197
            /* FALLTHROUGH */
198
        case SIGTERM:
199
            if (iflag)
200
                action = S_IGN;
201
            break;
202
#if JOBS
203
        case SIGTSTP:
204
        case SIGTTOU:
205
            if (mflag)
206
                action = S_IGN;
207
            break;
208
#endif
209
        }
210
    }
211
 
212
    t = &sigmode[signo - 1];
213
    if (*t == 0) {
214
        /*
215
         * current setting unknown
216
         */
217
        if (sigaction(signo, 0, &act) == -1) {
218
            /*
219
             * Pretend it worked; maybe we should give a warning
220
             * here, but other shells don't. We don't alter
221
             * sigmode, so that we retry every time.
222
             */
223
            return;
224
        }
225
        if (act.sa_handler == SIG_IGN) {
226
            if (mflag && (signo == SIGTSTP ||
227
                 signo == SIGTTIN || signo == SIGTTOU)) {
228
                *t = S_IGN; /* don't hard ignore these */
229
            } else
230
                *t = S_HARD_IGN;
231
        } else {
232
            *t = S_RESET;   /* force to be set */
233
        }
234
    }
235
    if (*t == S_HARD_IGN || *t == action)
236
        return;
237
    switch (action) {
238
    case S_CATCH:
239
        act.sa_handler = onsig;
240
        break;
241
    case S_IGN:
242
        act.sa_handler = SIG_IGN;
243
        break;
244
    default:
245
        act.sa_handler = SIG_DFL;
246
    }
247
    *t = action;
248
    act.sa_flags = 0;
249
    sigemptyset(&act.sa_mask);
250
    sigaction(signo, &act, 0);
251
}
252
 
253
/*
254
 * Ignore a signal.
255
 */
256
 
257
void
258
ignoresig(signo)
259
    int signo;
260
{
261
    if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
262
        signal(signo, SIG_IGN);
263
    }
264
    sigmode[signo - 1] = S_HARD_IGN;
265
}
266
 
267
 
268
#ifdef mkinit
269
INCLUDE <signal.h>
270
INCLUDE "trap.h"
271
 
272
SHELLPROC {
273
    char *sm;
274
 
275
    clear_traps();
276
    for (sm = sigmode ; sm < sigmode + NSIG ; sm++) {
277
        if (*sm == S_IGN)
278
            *sm = S_HARD_IGN;
279
    }
280
}
281
#endif
282
 
283
 
284
 
285
/*
286
 * Signal handler.
287
 */
288
 
289
void
290
onsig(signo)
291
    int signo;
292
{
293
    signal(signo, onsig);
294
    if (signo == SIGINT && trap[SIGINT] == NULL) {
295
        onint();
296
        return;
297
    }
298
    gotsig[signo - 1] = 1;
299
    pendingsigs++;
300
}
301
 
302
 
303
 
304
/*
305
 * Called to execute a trap.  Perhaps we should avoid entering new trap
306
 * handlers while we are executing a trap handler.
307
 */
308
 
309
void
310
dotrap() {
311
    int i;
312
    int savestatus;
313
 
314
    for (;;) {
315
        for (i = 1 ; ; i++) {
316
            if (gotsig[i - 1])
317
                break;
318
            if (i >= NSIG)
319
                goto done;
320
        }
321
        gotsig[i - 1] = 0;
322
        savestatus=exitstatus;
323
        evalstring(trap[i], 0);
324
        exitstatus=savestatus;
325
    }
326
done:
327
    pendingsigs = 0;
328
}
329
 
330
 
331
 
332
/*
333
 * Controls whether the shell is interactive or not.
334
 */
335
 
336
 
337
void
338
setinteractive(on)
339
    int on;
340
{
341
    static int is_interactive;
342
 
343
    if (on == is_interactive)
344
        return;
345
    setsignal(SIGINT);
346
    setsignal(SIGQUIT);
347
    setsignal(SIGTERM);
348
    chkmail(1);
349
    is_interactive = on;
350
}
351
 
352
 
353
 
354
/*
355
 * Called to exit the shell.
356
 */
357
 
358
void
359
exitshell(status)
360
    int status;
361
{
362
    struct jmploc loc1, loc2;
363
    char *p;
364
 
365
    TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
366
#ifdef HETIO
367
    hetio_reset_term();
368
#endif
369
    if (setjmp(loc1.loc)) {
370
        goto l1;
371
    }
372
    if (setjmp(loc2.loc)) {
373
        goto l2;
374
    }
375
    handler = &loc1;
376
    if ((p = trap[0]) != NULL && *p != '\0') {
377
        trap[0] = NULL;
378
        evalstring(p, 0);
379
    }
380
l1:   handler = &loc2;          /* probably unnecessary */
381
    flushall();
382
#if JOBS
383
    setjobctl(0);
384
#endif
385
l2:   _exit(status);
386
    /* NOTREACHED */
387
}
388
 
389
int decode_signal(const char *string)
390
{
391
    int signo;
392
 
393
    if (is_number(string)) return atoi(string);
394
 
395
    for (signo=0; signo < NSIG; signo++)
396
        if (strcasecmp(string, signal_names[signo]) == 0 ||
397
            strcasecmp(string, &(signal_names[signo])[3]) == 0)
398
            return signo;
399
 
400
    return -1;
401
}