]>
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 | |
7 | Software Foundation; either version 1, or (at your option) any later | |
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 | |
17 | Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
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 | ||
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 | ||
d166f048 JA |
54 | extern void run_trap_cleanup (); |
55 | ||
ccc6cda3 JA |
56 | extern int interactive, interactive_shell; |
57 | extern int indirection_level, startup_state, subshell_environment; | |
58 | extern int line_number; | |
59 | extern int last_command_exit_value; | |
60 | extern int running_trap; | |
cce855bc | 61 | extern int posixly_correct; |
ccc6cda3 JA |
62 | extern COMMAND *global_command; |
63 | ||
64 | int parse_and_execute_level = 0; | |
65 | ||
cce855bc JA |
66 | static int cat_file (); |
67 | ||
ccc6cda3 JA |
68 | /* How to force parse_and_execute () to clean up after itself. */ |
69 | void | |
70 | parse_and_execute_cleanup () | |
71 | { | |
72 | if (running_trap) | |
73 | { | |
74 | run_trap_cleanup (running_trap - 1); | |
75 | unfreeze_jobs_list (); | |
76 | } | |
77 | run_unwind_frame ("parse_and_execute_top"); | |
78 | } | |
79 | ||
80 | /* Parse and execute the commands in STRING. Returns whatever | |
d166f048 JA |
81 | execute_command () returns. This frees STRING. FLAGS is a |
82 | flags word; look in common.h for the possible values. Actions | |
83 | are: | |
84 | (flags & SEVAL_NONINT) -> interactive = 0; | |
85 | (flags & SEVAL_INTERACT) -> interactive = 1; | |
86 | (flags & SEVAL_NOHIST) -> call bash_history_disable () | |
87 | */ | |
88 | ||
ccc6cda3 | 89 | int |
d166f048 | 90 | parse_and_execute (string, from_file, flags) |
ccc6cda3 JA |
91 | char *string; |
92 | char *from_file; | |
d166f048 | 93 | int flags; |
ccc6cda3 JA |
94 | { |
95 | int code; | |
96 | volatile int should_jump_to_top_level, last_result; | |
97 | char *orig_string; | |
98 | COMMAND *volatile command; | |
99 | ||
100 | orig_string = string; | |
101 | /* Unwind protect this invocation of parse_and_execute (). */ | |
102 | begin_unwind_frame ("parse_and_execute_top"); | |
103 | unwind_protect_int (parse_and_execute_level); | |
104 | unwind_protect_jmp_buf (top_level); | |
105 | unwind_protect_int (indirection_level); | |
106 | unwind_protect_int (line_number); | |
d166f048 | 107 | if (flags & (SEVAL_NONINT|SEVAL_INTERACT)) |
ccc6cda3 JA |
108 | unwind_protect_int (interactive); |
109 | ||
110 | #if defined (HISTORY) | |
d166f048 JA |
111 | unwind_protect_int (remember_on_history); /* can be used in scripts */ |
112 | # if defined (BANG_HISTORY) | |
ccc6cda3 JA |
113 | if (interactive_shell) |
114 | { | |
ccc6cda3 | 115 | unwind_protect_int (history_expansion_inhibited); |
ccc6cda3 | 116 | } |
d166f048 | 117 | # endif /* BANG_HISTORY */ |
ccc6cda3 JA |
118 | #endif /* HISTORY */ |
119 | ||
120 | add_unwind_protect (pop_stream, (char *)NULL); | |
121 | if (orig_string) | |
122 | add_unwind_protect (xfree, orig_string); | |
123 | end_unwind_frame (); | |
124 | ||
125 | parse_and_execute_level++; | |
126 | push_stream (1); /* reset the line number */ | |
127 | indirection_level++; | |
d166f048 JA |
128 | if (flags & (SEVAL_NONINT|SEVAL_INTERACT)) |
129 | interactive = (flags & SEVAL_NONINT) ? 0 : 1; | |
ccc6cda3 JA |
130 | |
131 | #if defined (HISTORY) | |
d166f048 JA |
132 | if (flags & SEVAL_NOHIST) |
133 | bash_history_disable (); | |
ccc6cda3 JA |
134 | #endif /* HISTORY */ |
135 | ||
136 | code = should_jump_to_top_level = 0; | |
137 | last_result = EXECUTION_SUCCESS; | |
138 | command = (COMMAND *)NULL; | |
139 | ||
140 | with_input_from_string (string, from_file); | |
141 | while (*(bash_input.location.string)) | |
142 | { | |
143 | if (interrupt_state) | |
144 | { | |
145 | last_result = EXECUTION_FAILURE; | |
146 | break; | |
147 | } | |
148 | ||
149 | /* Provide a location for functions which `longjmp (top_level)' to | |
150 | jump to. This prevents errors in substitution from restarting | |
151 | the reader loop directly, for example. */ | |
152 | code = setjmp (top_level); | |
153 | ||
154 | if (code) | |
155 | { | |
156 | should_jump_to_top_level = 0; | |
157 | switch (code) | |
158 | { | |
159 | case FORCE_EOF: | |
160 | case EXITPROG: | |
161 | run_unwind_frame ("pe_dispose"); | |
162 | /* Remember to call longjmp (top_level) after the old | |
163 | value for it is restored. */ | |
164 | should_jump_to_top_level = 1; | |
165 | goto out; | |
166 | ||
167 | case DISCARD: | |
168 | run_unwind_frame ("pe_dispose"); | |
169 | last_command_exit_value = 1; /* XXX */ | |
170 | if (subshell_environment) | |
171 | { | |
172 | should_jump_to_top_level = 1; | |
173 | goto out; | |
174 | } | |
175 | else | |
176 | { | |
e8ce775d JA |
177 | #if 0 |
178 | dispose_command (command); /* pe_dispose does this */ | |
179 | #endif | |
ccc6cda3 JA |
180 | continue; |
181 | } | |
182 | ||
183 | default: | |
184 | programming_error ("parse_and_execute: bad jump: code %d", code); | |
185 | break; | |
186 | } | |
187 | } | |
188 | ||
189 | if (parse_command () == 0) | |
190 | { | |
191 | if (interactive_shell == 0 && read_but_dont_execute) | |
192 | { | |
193 | last_result = EXECUTION_SUCCESS; | |
194 | dispose_command (global_command); | |
195 | global_command = (COMMAND *)NULL; | |
196 | } | |
197 | else if (command = global_command) | |
198 | { | |
199 | struct fd_bitmap *bitmap; | |
200 | ||
201 | bitmap = new_fd_bitmap (FD_BITMAP_SIZE); | |
202 | begin_unwind_frame ("pe_dispose"); | |
203 | add_unwind_protect (dispose_fd_bitmap, bitmap); | |
d166f048 | 204 | add_unwind_protect (dispose_command, command); /* XXX */ |
ccc6cda3 JA |
205 | |
206 | global_command = (COMMAND *)NULL; | |
207 | ||
208 | #if defined (ONESHOT) | |
209 | if (startup_state == 2 && *bash_input.location.string == '\0' && | |
210 | command->type == cm_simple && !command->redirects && | |
e8ce775d JA |
211 | !command->value.Simple->redirects && |
212 | ((command->flags & CMD_TIME_PIPELINE) == 0)) | |
ccc6cda3 JA |
213 | { |
214 | command->flags |= CMD_NO_FORK; | |
215 | command->value.Simple->flags |= CMD_NO_FORK; | |
216 | } | |
217 | #endif /* ONESHOT */ | |
218 | ||
cce855bc JA |
219 | /* See if this is a candidate for $( <file ). */ |
220 | if (startup_state == 2 && | |
221 | subshell_environment == SUBSHELL_COMSUB && | |
222 | *bash_input.location.string == '\0' && | |
223 | command->type == cm_simple && !command->redirects && | |
224 | (command->flags & CMD_TIME_PIPELINE) == 0 && | |
225 | command->value.Simple->words == 0 && | |
226 | command->value.Simple->redirects && | |
227 | command->value.Simple->redirects->next == 0 && | |
228 | command->value.Simple->redirects->instruction == r_input_direction) | |
229 | { | |
230 | int r; | |
231 | r = cat_file (command->value.Simple->redirects); | |
232 | last_result = (r < 0) ? EXECUTION_FAILURE : EXECUTION_SUCCESS; | |
233 | } | |
234 | else | |
235 | last_result = execute_command_internal | |
ccc6cda3 JA |
236 | (command, 0, NO_PIPE, NO_PIPE, bitmap); |
237 | ||
238 | dispose_command (command); | |
239 | dispose_fd_bitmap (bitmap); | |
240 | discard_unwind_frame ("pe_dispose"); | |
241 | } | |
242 | } | |
243 | else | |
244 | { | |
245 | last_result = EXECUTION_FAILURE; | |
246 | ||
247 | /* Since we are shell compatible, syntax errors in a script | |
248 | abort the execution of the script. Right? */ | |
249 | break; | |
250 | } | |
251 | } | |
252 | ||
253 | out: | |
254 | ||
255 | run_unwind_frame ("parse_and_execute_top"); | |
256 | ||
257 | if (interrupt_state && parse_and_execute_level == 0) | |
258 | { | |
259 | /* An interrupt during non-interactive execution in an | |
260 | interactive shell (e.g. via $PROMPT_COMMAND) should | |
261 | not cause the shell to exit. */ | |
262 | interactive = interactive_shell; | |
263 | throw_to_top_level (); | |
264 | } | |
265 | ||
266 | if (should_jump_to_top_level) | |
267 | jump_to_top_level (code); | |
268 | ||
269 | return (last_result); | |
270 | } | |
cce855bc JA |
271 | |
272 | /* Write NB bytes from BUF to file descriptor FD, retrying the write if | |
273 | it is interrupted. We retry three times if we get a zero-length | |
274 | write. Any other signal causes this function to return prematurely. */ | |
275 | static int | |
276 | zwrite (fd, buf, nb) | |
277 | int fd; | |
278 | unsigned char *buf; | |
279 | int nb; | |
280 | { | |
281 | int n, i, nt; | |
282 | ||
283 | for (n = nb, nt = 0;;) | |
284 | { | |
285 | i = write (fd, buf, n); | |
286 | if (i > 0) | |
287 | { | |
288 | n -= i; | |
289 | if (n <= 0) | |
290 | return nb; | |
291 | } | |
292 | else if (i == 0) | |
293 | { | |
294 | if (++nt > 3) | |
295 | return (nb - n); | |
296 | } | |
297 | else if (errno != EINTR) | |
298 | return -1; | |
299 | } | |
300 | } | |
301 | ||
302 | /* Handle a $( < file ) command substitution. This expands the filename, | |
303 | returning errors as appropriate, then just cats the file to the standard | |
304 | output. */ | |
305 | static int | |
306 | cat_file (r) | |
307 | REDIRECT *r; | |
308 | { | |
309 | char lbuf[128], *fn; | |
310 | int nr, fd, rval; | |
311 | ||
312 | if (r->instruction != r_input_direction) | |
313 | return -1; | |
314 | ||
315 | /* Get the filename. */ | |
316 | if (posixly_correct && !interactive_shell) | |
317 | disallow_filename_globbing++; | |
318 | fn = redirection_expand (r->redirectee.filename); | |
319 | if (posixly_correct && !interactive_shell) | |
320 | disallow_filename_globbing--; | |
321 | ||
322 | if (fn == 0) | |
323 | { | |
324 | redirection_error (r, AMBIGUOUS_REDIRECT); | |
325 | return -1; | |
326 | } | |
327 | ||
328 | fd = open(fn, O_RDONLY); | |
329 | if (fd < 0) | |
330 | { | |
331 | file_error (fn); | |
332 | free (fn); | |
333 | return -1; | |
334 | } | |
335 | ||
336 | rval = 0; | |
337 | while (1) | |
338 | { | |
339 | /* Retry the reads on EINTR. Any other error causes a break from the | |
340 | loop. */ | |
341 | while ((nr = read (fd, lbuf, sizeof(lbuf))) < 0 && errno == EINTR) | |
342 | ; | |
343 | if (nr == 0) | |
344 | break; | |
345 | else if (nr < 0) | |
346 | { | |
347 | rval = -1; | |
348 | break; | |
349 | } | |
350 | if (zwrite (1, lbuf, nr) < 0) | |
351 | { | |
352 | rval = -1; | |
353 | break; | |
354 | } | |
355 | } | |
356 | ||
357 | free (fn); | |
358 | close (fd); | |
359 | ||
360 | return (0); | |
361 | } |