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 |