]>
Commit | Line | Data |
---|---|---|
b80f6443 | 1 | /* Copyright (C) 1996-2003 Free Software Foundation, Inc. |
ccc6cda3 JA |
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) | |
22 | # include <unistd.h> | |
23 | #endif | |
24 | ||
d166f048 | 25 | #include "../bashtypes.h" |
bb70624e JA |
26 | #include "posixstat.h" |
27 | #include "filecntl.h" | |
ccc6cda3 JA |
28 | |
29 | #include <stdio.h> | |
30 | #include <signal.h> | |
31 | #include <errno.h> | |
32 | ||
33 | #include "../bashansi.h" | |
b80f6443 | 34 | #include "../bashintl.h" |
ccc6cda3 JA |
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" | |
42 | ||
43 | #if defined (HISTORY) | |
44 | # include "../bashhist.h" | |
45 | #endif | |
46 | ||
47 | #include "common.h" | |
48 | ||
49 | #if !defined (errno) | |
50 | extern int errno; | |
51 | #endif | |
52 | ||
53 | /* Flags for _evalfile() */ | |
54 | #define FEVAL_ENOENTOK 0x001 | |
55 | #define FEVAL_BUILTIN 0x002 | |
56 | #define FEVAL_UNWINDPROT 0x004 | |
57 | #define FEVAL_NONINT 0x008 | |
58 | #define FEVAL_LONGJMP 0x010 | |
d166f048 | 59 | #define FEVAL_HISTORY 0x020 |
28ef6c31 | 60 | #define FEVAL_CHECKBINARY 0x040 |
f73dda09 | 61 | #define FEVAL_REGFILE 0x080 |
b80f6443 | 62 | #define FEVAL_NOPUSHARGS 0x100 |
ccc6cda3 | 63 | |
f73dda09 | 64 | extern int posixly_correct; |
ccc6cda3 JA |
65 | extern int indirection_level, startup_state, subshell_environment; |
66 | extern int return_catch_flag, return_catch_value; | |
67 | extern int last_command_exit_value; | |
68 | ||
69 | /* How many `levels' of sourced files we have. */ | |
70 | int sourcelevel = 0; | |
71 | ||
72 | static int | |
73 | _evalfile (filename, flags) | |
f73dda09 | 74 | const char *filename; |
ccc6cda3 JA |
75 | int flags; |
76 | { | |
77 | volatile int old_interactive; | |
78 | procenv_t old_return_catch; | |
d166f048 | 79 | int return_val, fd, result, pflags; |
ccc6cda3 JA |
80 | char *string; |
81 | struct stat finfo; | |
cce855bc | 82 | size_t file_size; |
f73dda09 | 83 | sh_vmsg_func_t *errfunc; |
b80f6443 JA |
84 | #if defined (ARRAY_VARS) |
85 | SHELL_VAR *funcname_v, *bash_source_v, *bash_lineno_v; | |
86 | ARRAY *funcname_a, *bash_source_a, *bash_lineno_a; | |
87 | # if defined (DEBUGGER) | |
88 | SHELL_VAR *bash_argv_v, *bash_argc_v; | |
89 | ARRAY *bash_argv_a, *bash_argc_a; | |
90 | # endif | |
91 | char *t, tt[2]; | |
92 | #endif | |
f73dda09 JA |
93 | |
94 | USE_VAR(pflags); | |
ccc6cda3 | 95 | |
b80f6443 JA |
96 | #if defined (ARRAY_VARS) |
97 | GET_ARRAY_FROM_VAR ("FUNCNAME", funcname_v, funcname_a); | |
98 | GET_ARRAY_FROM_VAR ("BASH_SOURCE", bash_source_v, bash_source_a); | |
99 | GET_ARRAY_FROM_VAR ("BASH_LINENO", bash_lineno_v, bash_lineno_a); | |
100 | # if defined (DEBUGGER) | |
101 | GET_ARRAY_FROM_VAR ("BASH_ARGV", bash_argv_v, bash_argv_a); | |
102 | GET_ARRAY_FROM_VAR ("BASH_ARGC", bash_argc_v, bash_argc_a); | |
103 | # endif | |
104 | #endif | |
105 | ||
ccc6cda3 JA |
106 | fd = open (filename, O_RDONLY); |
107 | ||
108 | if (fd < 0 || (fstat (fd, &finfo) == -1)) | |
109 | { | |
110 | file_error_and_exit: | |
111 | if (((flags & FEVAL_ENOENTOK) == 0) || errno != ENOENT) | |
112 | file_error (filename); | |
113 | ||
114 | if (flags & FEVAL_LONGJMP) | |
28ef6c31 | 115 | { |
ccc6cda3 JA |
116 | last_command_exit_value = 1; |
117 | jump_to_top_level (EXITPROG); | |
118 | } | |
119 | ||
120 | return ((flags & FEVAL_BUILTIN) ? EXECUTION_FAILURE | |
121 | : ((errno == ENOENT) ? 0 : -1)); | |
122 | } | |
123 | ||
f73dda09 | 124 | errfunc = ((flags & FEVAL_BUILTIN) ? builtin_error : internal_error); |
ccc6cda3 JA |
125 | |
126 | if (S_ISDIR (finfo.st_mode)) | |
127 | { | |
b80f6443 | 128 | (*errfunc) (_("%s: is a directory"), filename); |
ccc6cda3 JA |
129 | return ((flags & FEVAL_BUILTIN) ? EXECUTION_FAILURE : -1); |
130 | } | |
f73dda09 | 131 | else if ((flags & FEVAL_REGFILE) && S_ISREG (finfo.st_mode) == 0) |
ccc6cda3 | 132 | { |
b80f6443 | 133 | (*errfunc) (_("%s: not a regular file"), filename); |
ccc6cda3 JA |
134 | return ((flags & FEVAL_BUILTIN) ? EXECUTION_FAILURE : -1); |
135 | } | |
136 | ||
cce855bc JA |
137 | file_size = (size_t)finfo.st_size; |
138 | /* Check for overflow with large files. */ | |
139 | if (file_size != finfo.st_size || file_size + 1 < file_size) | |
140 | { | |
b80f6443 | 141 | (*errfunc) (_("%s: file is too large"), filename); |
cce855bc JA |
142 | return ((flags & FEVAL_BUILTIN) ? EXECUTION_FAILURE : -1); |
143 | } | |
28ef6c31 JA |
144 | |
145 | #if defined (__CYGWIN__) && defined (O_TEXT) | |
146 | setmode (fd, O_TEXT); | |
147 | #endif | |
148 | ||
f73dda09 | 149 | string = (char *)xmalloc (1 + file_size); |
cce855bc | 150 | result = read (fd, string, file_size); |
ccc6cda3 JA |
151 | string[result] = '\0'; |
152 | ||
153 | return_val = errno; | |
154 | close (fd); | |
155 | errno = return_val; | |
156 | ||
cce855bc | 157 | if (result < 0) /* XXX was != file_size, not < 0 */ |
ccc6cda3 JA |
158 | { |
159 | free (string); | |
160 | goto file_error_and_exit; | |
161 | } | |
162 | ||
cce855bc JA |
163 | if (result == 0) |
164 | { | |
165 | free (string); | |
166 | return ((flags & FEVAL_BUILTIN) ? EXECUTION_SUCCESS : 1); | |
167 | } | |
168 | ||
28ef6c31 | 169 | if ((flags & FEVAL_CHECKBINARY) && |
f73dda09 | 170 | check_binary_file (string, (result > 80) ? 80 : result)) |
ccc6cda3 JA |
171 | { |
172 | free (string); | |
173 | (*errfunc) ("%s: cannot execute binary file", filename); | |
174 | return ((flags & FEVAL_BUILTIN) ? EX_BINARY_FILE : -1); | |
175 | } | |
176 | ||
177 | if (flags & FEVAL_UNWINDPROT) | |
178 | { | |
179 | begin_unwind_frame ("_evalfile"); | |
180 | ||
181 | unwind_protect_int (return_catch_flag); | |
182 | unwind_protect_jmp_buf (return_catch); | |
183 | if (flags & FEVAL_NONINT) | |
184 | unwind_protect_int (interactive); | |
185 | unwind_protect_int (sourcelevel); | |
186 | } | |
187 | else | |
188 | { | |
189 | COPY_PROCENV (return_catch, old_return_catch); | |
190 | if (flags & FEVAL_NONINT) | |
191 | old_interactive = interactive; | |
192 | } | |
193 | ||
194 | if (flags & FEVAL_NONINT) | |
195 | interactive = 0; | |
196 | ||
197 | return_catch_flag++; | |
198 | sourcelevel++; | |
199 | ||
b80f6443 JA |
200 | #if defined (ARRAY_VARS) |
201 | array_push (bash_source_a, (char *)filename); | |
202 | t = itos (executing_line_number ()); | |
203 | array_push (bash_lineno_a, t); | |
204 | free (t); | |
205 | array_push (funcname_a, "source"); /* not exactly right */ | |
206 | # if defined (DEBUGGER) | |
207 | /* Have to figure out a better way to do this when `source' is supplied | |
208 | arguments */ | |
209 | if ((flags & FEVAL_NOPUSHARGS) == 0) | |
210 | { | |
211 | array_push (bash_argv_a, (char *)filename); | |
212 | tt[0] = '1'; tt[1] = '\0'; | |
213 | array_push (bash_argc_a, tt); | |
214 | } | |
215 | # endif | |
216 | #endif | |
217 | ||
d166f048 | 218 | /* set the flags to be passed to parse_and_execute */ |
b80f6443 JA |
219 | pflags = SEVAL_RESETLINE; |
220 | pflags |= (flags & FEVAL_HISTORY) ? 0 : SEVAL_NOHIST; | |
d166f048 | 221 | |
ccc6cda3 JA |
222 | if (flags & FEVAL_BUILTIN) |
223 | result = EXECUTION_SUCCESS; | |
224 | ||
225 | return_val = setjmp (return_catch); | |
226 | ||
227 | /* If `return' was seen outside of a function, but in the script, then | |
228 | force parse_and_execute () to clean up. */ | |
229 | if (return_val) | |
230 | { | |
231 | parse_and_execute_cleanup (); | |
232 | result = return_catch_value; | |
233 | } | |
234 | else | |
d166f048 | 235 | result = parse_and_execute (string, filename, pflags); |
ccc6cda3 JA |
236 | |
237 | if (flags & FEVAL_UNWINDPROT) | |
238 | run_unwind_frame ("_evalfile"); | |
239 | else | |
240 | { | |
241 | if (flags & FEVAL_NONINT) | |
242 | interactive = old_interactive; | |
243 | return_catch_flag--; | |
244 | sourcelevel--; | |
245 | COPY_PROCENV (old_return_catch, return_catch); | |
246 | } | |
247 | ||
b80f6443 JA |
248 | #if defined (ARRAY_VARS) |
249 | array_pop (bash_source_a); | |
250 | array_pop (bash_lineno_a); | |
251 | array_pop (funcname_a); | |
252 | # if defined (DEBUGGER) | |
253 | if ((flags & FEVAL_NOPUSHARGS) == 0) | |
254 | { | |
255 | array_pop (bash_argc_a); | |
256 | array_pop (bash_argv_a); | |
257 | } | |
258 | # endif | |
259 | #endif | |
260 | ||
ccc6cda3 JA |
261 | return ((flags & FEVAL_BUILTIN) ? result : 1); |
262 | } | |
263 | ||
264 | int | |
265 | maybe_execute_file (fname, force_noninteractive) | |
f73dda09 | 266 | const char *fname; |
ccc6cda3 JA |
267 | int force_noninteractive; |
268 | { | |
269 | char *filename; | |
270 | int result, flags; | |
271 | ||
7117c2d2 | 272 | filename = bash_tilde_expand (fname, 0); |
ccc6cda3 JA |
273 | flags = FEVAL_ENOENTOK; |
274 | if (force_noninteractive) | |
275 | flags |= FEVAL_NONINT; | |
276 | result = _evalfile (filename, flags); | |
277 | free (filename); | |
278 | return result; | |
279 | } | |
280 | ||
d166f048 JA |
281 | #if defined (HISTORY) |
282 | int | |
283 | fc_execute_file (filename) | |
f73dda09 | 284 | const char *filename; |
d166f048 JA |
285 | { |
286 | int flags; | |
287 | ||
288 | /* We want these commands to show up in the history list if | |
289 | remember_on_history is set. */ | |
f73dda09 | 290 | flags = FEVAL_ENOENTOK|FEVAL_HISTORY|FEVAL_REGFILE; |
d166f048 JA |
291 | return (_evalfile (filename, flags)); |
292 | } | |
293 | #endif /* HISTORY */ | |
294 | ||
ccc6cda3 | 295 | int |
b80f6443 | 296 | source_file (filename, sflags) |
f73dda09 | 297 | const char *filename; |
b80f6443 | 298 | int sflags; |
ccc6cda3 | 299 | { |
b80f6443 | 300 | int flags, rval; |
ccc6cda3 JA |
301 | |
302 | flags = FEVAL_BUILTIN|FEVAL_UNWINDPROT|FEVAL_NONINT; | |
b80f6443 JA |
303 | if (sflags) |
304 | flags |= FEVAL_NOPUSHARGS; | |
ccc6cda3 JA |
305 | /* POSIX shells exit if non-interactive and file error. */ |
306 | if (posixly_correct && !interactive_shell) | |
307 | flags |= FEVAL_LONGJMP; | |
b80f6443 JA |
308 | rval = _evalfile (filename, flags); |
309 | ||
310 | run_return_trap (); | |
311 | return rval; | |
ccc6cda3 | 312 | } |