]>
Commit | Line | Data |
---|---|---|
ccc6cda3 JA |
1 | /* Copyright (C) 1996 Free Software Foundation, Inc. |
2 | ||
3 | This file is part of GNU Bash, the Bourne Again SHell. | |
4 | ||
5 | Bash is free software; you can redistribute it and/or modify it under | |
6 | the terms of the GNU General Public License as published by the Free | |
bb70624e | 7 | Software Foundation; either version 2, or (at your option) any later |
ccc6cda3 JA |
8 | version. |
9 | ||
10 | Bash is distributed in the hope that it will be useful, but WITHOUT ANY | |
11 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
12 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
13 | for more details. | |
14 | ||
15 | You should have received a copy of the GNU General Public License along | |
16 | with Bash; see the file COPYING. If not, write to the Free Software | |
bb70624e | 17 | Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ |
ccc6cda3 JA |
18 | |
19 | #include <config.h> | |
20 | ||
21 | #if defined (HAVE_UNISTD_H) | |
cce855bc JA |
22 | # ifdef _MINIX |
23 | # include <sys/types.h> | |
24 | # endif | |
ccc6cda3 JA |
25 | # include <unistd.h> |
26 | #endif | |
27 | ||
28 | #include <stdio.h> | |
29 | #include <signal.h> | |
30 | ||
cce855bc JA |
31 | #include <errno.h> |
32 | ||
bb70624e | 33 | #include "filecntl.h" |
ccc6cda3 JA |
34 | #include "../bashansi.h" |
35 | ||
36 | #include "../shell.h" | |
37 | #include "../jobs.h" | |
38 | #include "../builtins.h" | |
39 | #include "../flags.h" | |
40 | #include "../input.h" | |
41 | #include "../execute_cmd.h" | |
cce855bc | 42 | #include "../redir.h" |
ccc6cda3 JA |
43 | |
44 | #if defined (HISTORY) | |
45 | # include "../bashhist.h" | |
46 | #endif | |
47 | ||
48 | #include "common.h" | |
49 | ||
cce855bc JA |
50 | #if !defined (errno) |
51 | extern int errno; | |
52 | #endif | |
53 | ||
b72432fd JA |
54 | #define IS_BUILTIN(s) (builtin_address_internal(s, 0) != (struct builtin *)NULL) |
55 | ||
d166f048 | 56 | extern void run_trap_cleanup (); |
bb70624e | 57 | extern int zwrite (); |
d166f048 | 58 | |
ccc6cda3 JA |
59 | extern int interactive, interactive_shell; |
60 | extern int indirection_level, startup_state, subshell_environment; | |
61 | extern int line_number; | |
62 | extern int last_command_exit_value; | |
63 | extern int running_trap; | |
cce855bc | 64 | extern int posixly_correct; |
ccc6cda3 JA |
65 | extern COMMAND *global_command; |
66 | ||
67 | int parse_and_execute_level = 0; | |
68 | ||
cce855bc JA |
69 | static int cat_file (); |
70 | ||
ccc6cda3 JA |
71 | /* How to force parse_and_execute () to clean up after itself. */ |
72 | void | |
73 | parse_and_execute_cleanup () | |
74 | { | |
75 | if (running_trap) | |
76 | { | |
77 | run_trap_cleanup (running_trap - 1); | |
78 | unfreeze_jobs_list (); | |
79 | } | |
80 | run_unwind_frame ("parse_and_execute_top"); | |
81 | } | |
82 | ||
83 | /* Parse and execute the commands in STRING. Returns whatever | |
d166f048 JA |
84 | execute_command () returns. This frees STRING. FLAGS is a |
85 | flags word; look in common.h for the possible values. Actions | |
86 | are: | |
87 | (flags & SEVAL_NONINT) -> interactive = 0; | |
88 | (flags & SEVAL_INTERACT) -> interactive = 1; | |
89 | (flags & SEVAL_NOHIST) -> call bash_history_disable () | |
90 | */ | |
91 | ||
ccc6cda3 | 92 | int |
d166f048 | 93 | parse_and_execute (string, from_file, flags) |
ccc6cda3 JA |
94 | char *string; |
95 | char *from_file; | |
d166f048 | 96 | int flags; |
ccc6cda3 | 97 | { |
bb70624e | 98 | int code, x; |
ccc6cda3 JA |
99 | volatile int should_jump_to_top_level, last_result; |
100 | char *orig_string; | |
101 | COMMAND *volatile command; | |
102 | ||
103 | orig_string = string; | |
104 | /* Unwind protect this invocation of parse_and_execute (). */ | |
105 | begin_unwind_frame ("parse_and_execute_top"); | |
106 | unwind_protect_int (parse_and_execute_level); | |
107 | unwind_protect_jmp_buf (top_level); | |
108 | unwind_protect_int (indirection_level); | |
109 | unwind_protect_int (line_number); | |
d166f048 | 110 | if (flags & (SEVAL_NONINT|SEVAL_INTERACT)) |
ccc6cda3 JA |
111 | unwind_protect_int (interactive); |
112 | ||
113 | #if defined (HISTORY) | |
d166f048 JA |
114 | unwind_protect_int (remember_on_history); /* can be used in scripts */ |
115 | # if defined (BANG_HISTORY) | |
ccc6cda3 JA |
116 | if (interactive_shell) |
117 | { | |
ccc6cda3 | 118 | unwind_protect_int (history_expansion_inhibited); |
ccc6cda3 | 119 | } |
d166f048 | 120 | # endif /* BANG_HISTORY */ |
ccc6cda3 JA |
121 | #endif /* HISTORY */ |
122 | ||
bb70624e JA |
123 | if (interactive_shell) |
124 | { | |
125 | x = get_current_prompt_level (); | |
126 | add_unwind_protect (set_current_prompt_level, x); | |
127 | } | |
128 | ||
ccc6cda3 JA |
129 | add_unwind_protect (pop_stream, (char *)NULL); |
130 | if (orig_string) | |
131 | add_unwind_protect (xfree, orig_string); | |
132 | end_unwind_frame (); | |
133 | ||
134 | parse_and_execute_level++; | |
135 | push_stream (1); /* reset the line number */ | |
136 | indirection_level++; | |
d166f048 JA |
137 | if (flags & (SEVAL_NONINT|SEVAL_INTERACT)) |
138 | interactive = (flags & SEVAL_NONINT) ? 0 : 1; | |
ccc6cda3 JA |
139 | |
140 | #if defined (HISTORY) | |
d166f048 JA |
141 | if (flags & SEVAL_NOHIST) |
142 | bash_history_disable (); | |
ccc6cda3 JA |
143 | #endif /* HISTORY */ |
144 | ||
145 | code = should_jump_to_top_level = 0; | |
146 | last_result = EXECUTION_SUCCESS; | |
147 | command = (COMMAND *)NULL; | |
148 | ||
149 | with_input_from_string (string, from_file); | |
150 | while (*(bash_input.location.string)) | |
151 | { | |
152 | if (interrupt_state) | |
153 | { | |
154 | last_result = EXECUTION_FAILURE; | |
155 | break; | |
156 | } | |
157 | ||
158 | /* Provide a location for functions which `longjmp (top_level)' to | |
159 | jump to. This prevents errors in substitution from restarting | |
160 | the reader loop directly, for example. */ | |
161 | code = setjmp (top_level); | |
162 | ||
163 | if (code) | |
164 | { | |
165 | should_jump_to_top_level = 0; | |
166 | switch (code) | |
167 | { | |
168 | case FORCE_EOF: | |
169 | case EXITPROG: | |
170 | run_unwind_frame ("pe_dispose"); | |
171 | /* Remember to call longjmp (top_level) after the old | |
172 | value for it is restored. */ | |
173 | should_jump_to_top_level = 1; | |
174 | goto out; | |
175 | ||
176 | case DISCARD: | |
177 | run_unwind_frame ("pe_dispose"); | |
178 | last_command_exit_value = 1; /* XXX */ | |
179 | if (subshell_environment) | |
180 | { | |
181 | should_jump_to_top_level = 1; | |
182 | goto out; | |
183 | } | |
184 | else | |
185 | { | |
e8ce775d JA |
186 | #if 0 |
187 | dispose_command (command); /* pe_dispose does this */ | |
188 | #endif | |
ccc6cda3 JA |
189 | continue; |
190 | } | |
191 | ||
192 | default: | |
b72432fd | 193 | command_error ("parse_and_execute", CMDERR_BADJUMP, code, 0); |
ccc6cda3 JA |
194 | break; |
195 | } | |
196 | } | |
197 | ||
198 | if (parse_command () == 0) | |
199 | { | |
200 | if (interactive_shell == 0 && read_but_dont_execute) | |
201 | { | |
202 | last_result = EXECUTION_SUCCESS; | |
203 | dispose_command (global_command); | |
204 | global_command = (COMMAND *)NULL; | |
205 | } | |
206 | else if (command = global_command) | |
207 | { | |
208 | struct fd_bitmap *bitmap; | |
209 | ||
210 | bitmap = new_fd_bitmap (FD_BITMAP_SIZE); | |
211 | begin_unwind_frame ("pe_dispose"); | |
212 | add_unwind_protect (dispose_fd_bitmap, bitmap); | |
d166f048 | 213 | add_unwind_protect (dispose_command, command); /* XXX */ |
ccc6cda3 JA |
214 | |
215 | global_command = (COMMAND *)NULL; | |
216 | ||
217 | #if defined (ONESHOT) | |
b72432fd JA |
218 | /* |
219 | * IF | |
220 | * we were invoked as `bash -c' (startup_state == 2) AND | |
221 | * parse_and_execute has not been called recursively AND | |
222 | * we have parsed the full command (string == '\0') AND | |
223 | * we have a simple command without redirections AND | |
224 | * the command is not being timed | |
225 | * THEN | |
226 | * tell the execution code that we don't need to fork | |
227 | */ | |
228 | if (startup_state == 2 && parse_and_execute_level == 1 && | |
229 | *bash_input.location.string == '\0' && | |
230 | command->type == cm_simple && | |
231 | !command->redirects && !command->value.Simple->redirects && | |
e8ce775d | 232 | ((command->flags & CMD_TIME_PIPELINE) == 0)) |
ccc6cda3 JA |
233 | { |
234 | command->flags |= CMD_NO_FORK; | |
235 | command->value.Simple->flags |= CMD_NO_FORK; | |
236 | } | |
237 | #endif /* ONESHOT */ | |
238 | ||
cce855bc JA |
239 | /* See if this is a candidate for $( <file ). */ |
240 | if (startup_state == 2 && | |
241 | subshell_environment == SUBSHELL_COMSUB && | |
242 | *bash_input.location.string == '\0' && | |
243 | command->type == cm_simple && !command->redirects && | |
244 | (command->flags & CMD_TIME_PIPELINE) == 0 && | |
245 | command->value.Simple->words == 0 && | |
246 | command->value.Simple->redirects && | |
247 | command->value.Simple->redirects->next == 0 && | |
248 | command->value.Simple->redirects->instruction == r_input_direction) | |
249 | { | |
250 | int r; | |
251 | r = cat_file (command->value.Simple->redirects); | |
252 | last_result = (r < 0) ? EXECUTION_FAILURE : EXECUTION_SUCCESS; | |
253 | } | |
254 | else | |
255 | last_result = execute_command_internal | |
ccc6cda3 JA |
256 | (command, 0, NO_PIPE, NO_PIPE, bitmap); |
257 | ||
258 | dispose_command (command); | |
259 | dispose_fd_bitmap (bitmap); | |
260 | discard_unwind_frame ("pe_dispose"); | |
261 | } | |
262 | } | |
263 | else | |
264 | { | |
265 | last_result = EXECUTION_FAILURE; | |
266 | ||
267 | /* Since we are shell compatible, syntax errors in a script | |
268 | abort the execution of the script. Right? */ | |
269 | break; | |
270 | } | |
271 | } | |
272 | ||
273 | out: | |
274 | ||
275 | run_unwind_frame ("parse_and_execute_top"); | |
276 | ||
277 | if (interrupt_state && parse_and_execute_level == 0) | |
278 | { | |
279 | /* An interrupt during non-interactive execution in an | |
280 | interactive shell (e.g. via $PROMPT_COMMAND) should | |
281 | not cause the shell to exit. */ | |
282 | interactive = interactive_shell; | |
283 | throw_to_top_level (); | |
284 | } | |
285 | ||
286 | if (should_jump_to_top_level) | |
287 | jump_to_top_level (code); | |
288 | ||
289 | return (last_result); | |
290 | } | |
cce855bc | 291 | |
cce855bc JA |
292 | /* Handle a $( < file ) command substitution. This expands the filename, |
293 | returning errors as appropriate, then just cats the file to the standard | |
294 | output. */ | |
295 | static int | |
296 | cat_file (r) | |
297 | REDIRECT *r; | |
298 | { | |
299 | char lbuf[128], *fn; | |
300 | int nr, fd, rval; | |
301 | ||
302 | if (r->instruction != r_input_direction) | |
303 | return -1; | |
304 | ||
305 | /* Get the filename. */ | |
306 | if (posixly_correct && !interactive_shell) | |
307 | disallow_filename_globbing++; | |
308 | fn = redirection_expand (r->redirectee.filename); | |
309 | if (posixly_correct && !interactive_shell) | |
310 | disallow_filename_globbing--; | |
311 | ||
312 | if (fn == 0) | |
313 | { | |
314 | redirection_error (r, AMBIGUOUS_REDIRECT); | |
315 | return -1; | |
316 | } | |
317 | ||
318 | fd = open(fn, O_RDONLY); | |
319 | if (fd < 0) | |
320 | { | |
321 | file_error (fn); | |
322 | free (fn); | |
323 | return -1; | |
324 | } | |
325 | ||
326 | rval = 0; | |
327 | while (1) | |
328 | { | |
bb70624e | 329 | nr = zread (fd, lbuf, sizeof(lbuf)); |
cce855bc JA |
330 | if (nr == 0) |
331 | break; | |
332 | else if (nr < 0) | |
333 | { | |
334 | rval = -1; | |
335 | break; | |
336 | } | |
337 | if (zwrite (1, lbuf, nr) < 0) | |
338 | { | |
339 | rval = -1; | |
340 | break; | |
341 | } | |
342 | } | |
343 | ||
344 | free (fn); | |
345 | close (fd); | |
346 | ||
347 | return (0); | |
348 | } |