Subversion Repositories HelenOS

Rev

Rev 2714 | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 2714 Rev 2782
1
/*  $NetBSD: main.c,v 1.39 2000/11/01 19:56:01 christos Exp $   */
1
/*  $NetBSD: main.c,v 1.39 2000/11/01 19:56:01 christos Exp $   */
2
 
2
 
3
/*-
3
/*-
4
 * Copyright (c) 1991, 1993
4
 * Copyright (c) 1991, 1993
5
 *  The Regents of the University of California.  All rights reserved.
5
 *  The Regents of the University of California.  All rights reserved.
6
 *
6
 *
7
 * This code is derived from software contributed to Berkeley by
7
 * This code is derived from software contributed to Berkeley by
8
 * Kenneth Almquist.
8
 * Kenneth Almquist.
9
 *
9
 *
10
 * Redistribution and use in source and binary forms, with or without
10
 * Redistribution and use in source and binary forms, with or without
11
 * modification, are permitted provided that the following conditions
11
 * modification, are permitted provided that the following conditions
12
 * are met:
12
 * are met:
13
 * 1. Redistributions of source code must retain the above copyright
13
 * 1. Redistributions of source code must retain the above copyright
14
 *    notice, this list of conditions and the following disclaimer.
14
 *    notice, this list of conditions and the following disclaimer.
15
 * 2. Redistributions in binary form must reproduce the above copyright
15
 * 2. Redistributions in binary form must reproduce the above copyright
16
 *    notice, this list of conditions and the following disclaimer in the
16
 *    notice, this list of conditions and the following disclaimer in the
17
 *    documentation and/or other materials provided with the distribution.
17
 *    documentation and/or other materials provided with the distribution.
18
 * 3. All advertising materials mentioning features or use of this software
18
 * 3. All advertising materials mentioning features or use of this software
19
 *    must display the following acknowledgement:
19
 *    must display the following acknowledgement:
20
 *  This product includes software developed by the University of
20
 *  This product includes software developed by the University of
21
 *  California, Berkeley and its contributors.
21
 *  California, Berkeley and its contributors.
22
 * 4. Neither the name of the University nor the names of 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
23
 *    may be used to endorse or promote products derived from this software
24
 *    without specific prior written permission.
24
 *    without specific prior written permission.
25
 *
25
 *
26
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
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
27
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
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
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
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
35
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36
 * SUCH DAMAGE.
36
 * SUCH DAMAGE.
37
 */
37
 */
38
 
38
 
39
#include <sys/cdefs.h>
39
#include <sys/cdefs.h>
40
#ifndef lint
40
#ifndef lint
41
__COPYRIGHT("@(#) Copyright (c) 1991, 1993\n\
41
__COPYRIGHT("@(#) Copyright (c) 1991, 1993\n\
42
    The Regents of the University of California.  All rights reserved.\n");
42
    The Regents of the University of California.  All rights reserved.\n");
43
#endif /* not lint */
43
#endif /* not lint */
44
 
44
 
45
#ifndef lint
45
#ifndef lint
46
#if 0
46
#if 0
47
static char sccsid[] = "@(#)main.c  8.7 (Berkeley) 7/19/95";
47
static char sccsid[] = "@(#)main.c  8.7 (Berkeley) 7/19/95";
48
#else
48
#else
49
__RCSID("$NetBSD: main.c,v 1.39 2000/11/01 19:56:01 christos Exp $");
49
__RCSID("$NetBSD: main.c,v 1.39 2000/11/01 19:56:01 christos Exp $");
50
#endif
50
#endif
51
#endif /* not lint */
51
#endif /* not lint */
52
 
52
 
53
#include <errno.h>
53
#include <errno.h>
54
#include <stdio.h>
54
#include <stdio.h>
55
#include <signal.h>
55
#include <signal.h>
56
#include <sys/stat.h>
56
#include <sys/stat.h>
57
#include <unistd.h>
57
#include <unistd.h>
58
#include <fcntl.h>
58
#include <fcntl.h>
59
 
59
 
60
 
60
 
61
#include "shell.h"
61
#include "shell.h"
62
#include "main.h"
62
#include "main.h"
63
#include "mail.h"
63
#include "mail.h"
64
#include "options.h"
64
#include "options.h"
65
#include "output.h"
65
#include "output.h"
66
#include "parser.h"
66
#include "parser.h"
67
#include "nodes.h"
67
#include "nodes.h"
68
#include "expand.h"
68
#include "expand.h"
69
#include "eval.h"
69
#include "eval.h"
70
#include "jobs.h"
70
#include "jobs.h"
71
#include "input.h"
71
#include "input.h"
72
#include "trap.h"
72
#include "trap.h"
73
#include "var.h"
73
#include "var.h"
74
#include "show.h"
74
#include "show.h"
75
#include "memalloc.h"
75
#include "memalloc.h"
76
#include "error.h"
76
#include "error.h"
77
#include "init.h"
77
#include "init.h"
78
#include "mystring.h"
78
#include "mystring.h"
79
#include "exec.h"
79
#include "exec.h"
80
#include "cd.h"
80
#include "cd.h"
81
 
81
 
82
#ifdef HETIO
82
#ifdef HETIO
83
#include "hetio.h"
83
#include "hetio.h"
84
#endif
84
#endif
85
 
85
 
86
#define PROFILE 0
86
#define PROFILE 0
87
 
87
 
88
int rootpid;
88
int rootpid;
89
int rootshell;
89
int rootshell;
90
STATIC union node *curcmd;
90
STATIC union node *curcmd;
91
STATIC union node *prevcmd;
91
STATIC union node *prevcmd;
92
#if PROFILE
92
#if PROFILE
93
short profile_buf[16384];
93
short profile_buf[16384];
94
extern int etext();
94
extern int etext();
95
#endif
95
#endif
96
 
96
 
97
STATIC void read_profile (const char *);
97
STATIC void read_profile (const char *);
98
STATIC char *find_dot_file (char *);
98
STATIC char *find_dot_file (char *);
99
int main (int, char **);
99
int main (int, char **);
100
 
100
 
101
/*
101
/*
102
 * Main routine.  We initialize things, parse the arguments, execute
102
 * Main routine.  We initialize things, parse the arguments, execute
103
 * profiles if we're a login shell, and then call cmdloop to execute
103
 * profiles if we're a login shell, and then call cmdloop to execute
104
 * commands.  The setjmp call sets up the location to jump to when an
104
 * commands.  The setjmp call sets up the location to jump to when an
105
 * exception occurs.  When an exception occurs the variable "state"
105
 * exception occurs.  When an exception occurs the variable "state"
106
 * is used to figure out how far we had gotten.
106
 * is used to figure out how far we had gotten.
107
 */
107
 */
108
 
108
 
109
int
109
int
110
main(argc, argv)
110
main(argc, argv)
111
    int argc;
111
    int argc;
112
    char **argv;
112
    char **argv;
113
{
113
{
114
    struct jmploc jmploc;
114
    struct jmploc jmploc;
115
    struct stackmark smark;
115
    struct stackmark smark;
116
    volatile int state;
116
    volatile int state;
117
    char *shinit;
117
    char *shinit;
118
    int priviliged;
118
    int priviliged;
119
 
119
 
120
    priviliged = getuid() != geteuid() || getgid() != getegid();
120
    priviliged = getuid() != geteuid() || getgid() != getegid();
121
 
121
 
122
#if PROFILE
122
#if PROFILE
123
    monitor(4, etext, profile_buf, sizeof profile_buf, 50);
123
    monitor(4, etext, profile_buf, sizeof profile_buf, 50);
124
#endif
124
#endif
125
#if defined(linux) || defined(__GNU__)
125
#if defined(linux) || defined(__GNU__)
126
    signal(SIGCHLD, SIG_DFL);
126
    signal(SIGCHLD, SIG_DFL);
127
#endif
127
#endif
128
    state = 0;
128
    state = 0;
129
    if (setjmp(jmploc.loc)) {
129
    if (setjmp(jmploc.loc)) {
130
        /*
130
        /*
131
         * When a shell procedure is executed, we raise the
131
         * When a shell procedure is executed, we raise the
132
         * exception EXSHELLPROC to clean up before executing
132
         * exception EXSHELLPROC to clean up before executing
133
         * the shell procedure.
133
         * the shell procedure.
134
         */
134
         */
135
        switch (exception) {
135
        switch (exception) {
136
        case EXSHELLPROC:
136
        case EXSHELLPROC:
137
            rootpid = getpid();
137
            rootpid = getpid();
138
            rootshell = 1;
138
            rootshell = 1;
139
            minusc = NULL;
139
            minusc = NULL;
140
            state = 3;
140
            state = 3;
141
            break;
141
            break;
142
 
142
 
143
        case EXEXEC:
143
        case EXEXEC:
144
            exitstatus = exerrno;
144
            exitstatus = exerrno;
145
            break;
145
            break;
146
 
146
 
147
        case EXERROR:
147
        case EXERROR:
148
            exitstatus = 2;
148
            exitstatus = 2;
149
            break;
149
            break;
150
 
150
 
151
        default:
151
        default:
152
            break;
152
            break;
153
        }
153
        }
154
 
154
 
155
        if (exception != EXSHELLPROC) {
155
        if (exception != EXSHELLPROC) {
156
            if (state == 0 || iflag == 0 || ! rootshell)
156
            if (state == 0 || iflag == 0 || ! rootshell)
157
                exitshell(exitstatus);
157
                exitshell(exitstatus);
158
        }
158
        }
159
        reset();
159
        reset();
160
        if (exception == EXINT
160
        if (exception == EXINT
161
#if ATTY
161
#if ATTY
162
         && (! attyset() || equal(termval(), "emacs"))
162
         && (! attyset() || equal(termval(), "emacs"))
163
#endif
163
#endif
164
         ) {
164
         ) {
165
            out2c('\n');
165
            out2c('\n');
166
            flushout(&errout);
166
            flushout(&errout);
167
        }
167
        }
168
        popstackmark(&smark);
168
        popstackmark(&smark);
169
        FORCEINTON;             /* enable interrupts */
169
        FORCEINTON;             /* enable interrupts */
170
        if (state == 1)
170
        if (state == 1)
171
            goto state1;
171
            goto state1;
172
        else if (state == 2)
172
        else if (state == 2)
173
            goto state2;
173
            goto state2;
174
        else if (state == 3)
174
        else if (state == 3)
175
            goto state3;
175
            goto state3;
176
        else
176
        else
177
            goto state4;
177
            goto state4;
178
    }
178
    }
179
    handler = &jmploc;
179
    handler = &jmploc;
180
#ifdef DEBUG
180
#ifdef DEBUG
181
    opentrace();
181
    opentrace();
182
    trputs("Shell args:  ");  trargs(argv);
182
    trputs("Shell args:  ");  trargs(argv);
183
#endif
183
#endif
184
    rootpid = getpid();
184
    rootpid = getpid();
185
    rootshell = 1;
185
    rootshell = 1;
186
    init();
186
    init();
187
    setstackmark(&smark);
187
    setstackmark(&smark);
188
    procargs(argc, argv);
188
    procargs(argc, argv);
189
    if (argv[0] && argv[0][0] == '-') {
189
    if (argv[0] && argv[0][0] == '-') {
190
        state = 1;
190
        state = 1;
191
        read_profile("/etc/profile");
191
        read_profile("/etc/profile");
192
state1:
192
state1:
193
        state = 2;
193
        state = 2;
194
        if (priviliged == 0)
194
        if (priviliged == 0)
195
            read_profile(".profile");
195
            read_profile(".profile");
196
        else
196
        else
197
            read_profile("/etc/suid_profile");
197
            read_profile("/etc/suid_profile");
198
    }
198
    }
199
state2:
199
state2:
200
    state = 3;
200
    state = 3;
201
    if (iflag && !priviliged) {
201
    if (iflag && !priviliged) {
202
        if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
202
        if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
203
            state = 3;
203
            state = 3;
204
            read_profile(shinit);
204
            read_profile(shinit);
205
        }
205
        }
206
    }
206
    }
207
state3:
207
state3:
208
    state = 4;
208
    state = 4;
209
    if (sflag == 0 || minusc) {
209
    if (sflag == 0 || minusc) {
210
        static int sigs[] =  {
210
        static int sigs[] =  {
211
            SIGINT, SIGQUIT, SIGHUP,
211
            SIGINT, SIGQUIT, SIGHUP,
212
#ifdef SIGTSTP
212
#ifdef SIGTSTP
213
            SIGTSTP,
213
            SIGTSTP,
214
#endif
214
#endif
215
            SIGPIPE
215
            SIGPIPE
216
        };
216
        };
217
#define SIGSSIZE (sizeof(sigs)/sizeof(sigs[0]))
217
#define SIGSSIZE (sizeof(sigs)/sizeof(sigs[0]))
218
        int i;
218
        int i;
219
 
219
 
220
        for (i = 0; i < SIGSSIZE; i++)
220
        for (i = 0; i < SIGSSIZE; i++)
221
            setsignal(sigs[i]);
221
            setsignal(sigs[i]);
222
    }
222
    }
223
 
223
 
224
    if (minusc)
224
    if (minusc)
225
        evalstring(minusc, 0);
225
        evalstring(minusc, 0);
226
 
226
 
227
    if (sflag || minusc == NULL) {
227
    if (sflag || minusc == NULL) {
228
state4: /* XXX ??? - why isn't this before the "if" statement */
228
state4: /* XXX ??? - why isn't this before the "if" statement */
229
        cmdloop(1);
229
        cmdloop(1);
230
    }
230
    }
231
#if PROFILE
231
#if PROFILE
232
    monitor(0);
232
    monitor(0);
233
#endif
233
#endif
234
    exitshell(exitstatus);
234
    exitshell(exitstatus);
235
    /* NOTREACHED */
235
    /* NOTREACHED */
236
}
236
}
237
 
237
 
238
 
238
 
239
/*
239
/*
240
 * Read and execute commands.  "Top" is nonzero for the top level command
240
 * Read and execute commands.  "Top" is nonzero for the top level command
241
 * loop; it turns on prompting if the shell is interactive.
241
 * loop; it turns on prompting if the shell is interactive.
242
 */
242
 */
243
 
243
 
244
void
244
void
245
cmdloop(top)
245
cmdloop(top)
246
    int top;
246
    int top;
247
{
247
{
248
    union node *n;
248
    union node *n;
249
    struct stackmark smark;
249
    struct stackmark smark;
250
    int inter;
250
    int inter;
251
    int numeof = 0;
251
    int numeof = 0;
252
 
252
 
253
    TRACE(("cmdloop(%d) called\n", top));
253
    TRACE(("cmdloop(%d) called\n", top));
254
    setstackmark(&smark);
254
    setstackmark(&smark);
255
#ifdef HETIO
255
#ifdef HETIO
256
    if(iflag && top)
256
    if(iflag && top)
257
        hetio_init();
257
        hetio_init();
258
#endif
258
#endif
259
    for (;;) {
259
    for (;;) {
260
        if (pendingsigs)
260
        if (pendingsigs)
261
            dotrap();
261
            dotrap();
262
        inter = 0;
262
        inter = 0;
263
        if (iflag && top) {
263
        if (iflag && top) {
264
            inter++;
264
            inter++;
265
            showjobs(1);
265
            showjobs(1);
266
            chkmail(0);
266
            chkmail(0);
267
            flushout(&output);
267
            flushout(&output);
268
        }
268
        }
269
        n = parsecmd(inter);
269
        n = parsecmd(inter);
270
        /* showtree(n); DEBUG */
270
        /* showtree(n); DEBUG */
271
        if (n == NEOF) {
271
        if (n == NEOF) {
272
            if (!top || numeof >= 50)
272
            if (!top || numeof >= 50)
273
                break;
273
                break;
274
            if (!stoppedjobs()) {
274
            if (!stoppedjobs()) {
275
                if (!Iflag)
275
                if (!Iflag)
276
                    break;
276
                    break;
277
                out2str("\nUse \"exit\" to leave shell.\n");
277
                out2str("\nUse \"exit\" to leave shell.\n");
278
            }
278
            }
279
            numeof++;
279
            numeof++;
280
        } else if (n != NULL && nflag == 0) {
280
        } else if (n != NULL && nflag == 0) {
281
            job_warning = (job_warning == 2) ? 1 : 0;
281
            job_warning = (job_warning == 2) ? 1 : 0;
282
            numeof = 0;
282
            numeof = 0;
283
            evaltree(n, 0);
283
            evaltree(n, 0);
284
        }
284
        }
285
        popstackmark(&smark);
285
        popstackmark(&smark);
286
        setstackmark(&smark);
286
        setstackmark(&smark);
287
        if (evalskip == SKIPFILE) {
287
        if (evalskip == SKIPFILE) {
288
            evalskip = 0;
288
            evalskip = 0;
289
            break;
289
            break;
290
        }
290
        }
291
    }
291
    }
292
    popstackmark(&smark);
292
    popstackmark(&smark);
293
}
293
}
294
 
294
 
295
 
295
 
296
 
296
 
297
/*
297
/*
298
 * Read /etc/profile or .profile.  Return on error.
298
 * Read /etc/profile or .profile.  Return on error.
299
 */
299
 */
300
 
300
 
301
STATIC void
301
STATIC void
302
read_profile(name)
302
read_profile(name)
303
    const char *name;
303
    const char *name;
304
{
304
{
305
    int fd;
305
    int fd;
306
    int xflag_set = 0;
306
    int xflag_set = 0;
307
    int vflag_set = 0;
307
    int vflag_set = 0;
308
 
308
 
309
    INTOFF;
309
    INTOFF;
310
    if ((fd = open(name, O_RDONLY)) >= 0)
310
    if ((fd = open(name, O_RDONLY)) >= 0)
311
        setinputfd(fd, 1);
311
        setinputfd(fd, 1);
312
    INTON;
312
    INTON;
313
    if (fd < 0)
313
    if (fd < 0)
314
        return;
314
        return;
315
    /* -q turns off -x and -v just when executing init files */
315
    /* -q turns off -x and -v just when executing init files */
316
    if (qflag)  {
316
    if (qflag)  {
317
        if (xflag)
317
        if (xflag)
318
            xflag = 0, xflag_set = 1;
318
            xflag = 0, xflag_set = 1;
319
        if (vflag)
319
        if (vflag)
320
            vflag = 0, vflag_set = 1;
320
            vflag = 0, vflag_set = 1;
321
    }
321
    }
322
    cmdloop(0);
322
    cmdloop(0);
323
    if (qflag)  {
323
    if (qflag)  {
324
        if (xflag_set)
324
        if (xflag_set)
325
            xflag = 1;
325
            xflag = 1;
326
        if (vflag_set)
326
        if (vflag_set)
327
            vflag = 1;
327
            vflag = 1;
328
    }
328
    }
329
    popfile();
329
    popfile();
330
}
330
}
331
 
331
 
332
 
332
 
333
 
333
 
334
/*
334
/*
335
 * Read a file containing shell functions.
335
 * Read a file containing shell functions.
336
 */
336
 */
337
 
337
 
338
void
338
void
339
readcmdfile(name)
339
readcmdfile(name)
340
    char *name;
340
    char *name;
341
{
341
{
342
    int fd;
342
    int fd;
343
 
343
 
344
    INTOFF;
344
    INTOFF;
345
    if ((fd = open(name, O_RDONLY)) >= 0)
345
    if ((fd = open(name, O_RDONLY)) >= 0)
346
        setinputfd(fd, 1);
346
        setinputfd(fd, 1);
347
    else
347
    else
348
        error("Can't open %s", name);
348
        error("Can't open %s", name);
349
    INTON;
349
    INTON;
350
    cmdloop(0);
350
    cmdloop(0);
351
    popfile();
351
    popfile();
352
}
352
}
353
 
353
 
354
 
354
 
355
 
355
 
356
/*
356
/*
357
 * Take commands from a file.  To be compatable we should do a path
357
 * Take commands from a file.  To be compatable we should do a path
358
 * search for the file, which is necessary to find sub-commands.
358
 * search for the file, which is necessary to find sub-commands.
359
 */
359
 */
360
 
360
 
361
 
361
 
362
STATIC char *
362
STATIC char *
363
find_dot_file(basename)
363
find_dot_file(basename)
364
    char *basename;
364
    char *basename;
365
{
365
{
366
    char *fullname;
366
    char *fullname;
367
    const char *path = pathval();
367
    const char *path = pathval();
368
    struct stat statb;
368
    struct stat statb;
369
 
369
 
370
    /* don't try this for absolute or relative paths */
370
    /* don't try this for absolute or relative paths */
371
    if (strchr(basename, '/'))
371
    if (strchr(basename, '/'))
372
        return basename;
372
        return basename;
373
 
373
 
374
    while ((fullname = padvance(&path, basename)) != NULL) {
374
    while ((fullname = padvance(&path, basename)) != NULL) {
375
        if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
375
        if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
376
            /*
376
            /*
377
             * Don't bother freeing here, since it will
377
             * Don't bother freeing here, since it will
378
             * be freed by the caller.
378
             * be freed by the caller.
379
             */
379
             */
380
            return fullname;
380
            return fullname;
381
        }
381
        }
382
        stunalloc(fullname);
382
        stunalloc(fullname);
383
    }
383
    }
384
 
384
 
385
    /* not found in the PATH */
385
    /* not found in the PATH */
386
    error("%s: not found", basename);
386
    error("%s: not found", basename);
387
    /* NOTREACHED */
387
    /* NOTREACHED */
388
}
388
}
389
 
389
 
390
int
390
int
391
dotcmd(argc, argv)
391
dotcmd(argc, argv)
392
    int argc;
392
    int argc;
393
    char **argv;
393
    char **argv;
394
{
394
{
395
    struct strlist *sp;
395
    struct strlist *sp;
396
    exitstatus = 0;
396
    exitstatus = 0;
397
 
397
 
398
    for (sp = cmdenviron; sp ; sp = sp->next)
398
    for (sp = cmdenviron; sp ; sp = sp->next)
399
        setvareq(savestr(sp->text), VSTRFIXED|VTEXTFIXED);
399
        setvareq(savestr(sp->text), VSTRFIXED|VTEXTFIXED);
400
 
400
 
401
    if (argc >= 2) {        /* That's what SVR2 does */
401
    if (argc >= 2) {        /* That's what SVR2 does */
402
        char *fullname;
402
        char *fullname;
403
        struct stackmark smark;
403
        struct stackmark smark;
404
 
404
 
405
        setstackmark(&smark);
405
        setstackmark(&smark);
406
        fullname = find_dot_file(argv[1]);
406
        fullname = find_dot_file(argv[1]);
407
        setinputfile(fullname, 1);
407
        setinputfile(fullname, 1);
408
        commandname = fullname;
408
        commandname = fullname;
409
        cmdloop(0);
409
        cmdloop(0);
410
        popfile();
410
        popfile();
411
        popstackmark(&smark);
411
        popstackmark(&smark);
412
    }
412
    }
413
    return exitstatus;
413
    return exitstatus;
414
}
414
}
415
 
415
 
416
 
416
 
417
int
417
int
418
exitcmd(argc, argv)
418
exitcmd(argc, argv)
419
    int argc;
419
    int argc;
420
    char **argv;
420
    char **argv;
421
{
421
{
422
    extern int oexitstatus;
422
    extern int oexitstatus;
423
 
423
 
424
    if (stoppedjobs())
424
    if (stoppedjobs())
425
        return 0;
425
        return 0;
426
    if (argc > 1)
426
    if (argc > 1)
427
        exitstatus = number(argv[1]);
427
        exitstatus = number(argv[1]);
428
    else
428
    else
429
        exitstatus = oexitstatus;
429
        exitstatus = oexitstatus;
430
    exitshell(exitstatus);
430
    exitshell(exitstatus);
431
    /* NOTREACHED */
431
    /* NOTREACHED */
432
}
432
}
433
 
433