]>
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) | |
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" | |
34 | ||
35 | #include "../shell.h" | |
36 | #include "../jobs.h" | |
37 | #include "../builtins.h" | |
38 | #include "../flags.h" | |
39 | #include "../input.h" | |
40 | #include "../execute_cmd.h" | |
41 | ||
42 | #if defined (HISTORY) | |
43 | # include "../bashhist.h" | |
44 | #endif | |
45 | ||
46 | #include "common.h" | |
47 | ||
48 | #if !defined (errno) | |
49 | extern int errno; | |
50 | #endif | |
51 | ||
52 | /* Flags for _evalfile() */ | |
53 | #define FEVAL_ENOENTOK 0x001 | |
54 | #define FEVAL_BUILTIN 0x002 | |
55 | #define FEVAL_UNWINDPROT 0x004 | |
56 | #define FEVAL_NONINT 0x008 | |
57 | #define FEVAL_LONGJMP 0x010 | |
d166f048 | 58 | #define FEVAL_HISTORY 0x020 |
28ef6c31 | 59 | #define FEVAL_CHECKBINARY 0x040 |
ccc6cda3 JA |
60 | |
61 | extern int interactive, interactive_shell, posixly_correct; | |
62 | extern int indirection_level, startup_state, subshell_environment; | |
63 | extern int return_catch_flag, return_catch_value; | |
64 | extern int last_command_exit_value; | |
65 | ||
66 | /* How many `levels' of sourced files we have. */ | |
67 | int sourcelevel = 0; | |
68 | ||
69 | static int | |
70 | _evalfile (filename, flags) | |
71 | char *filename; | |
72 | int flags; | |
73 | { | |
74 | volatile int old_interactive; | |
75 | procenv_t old_return_catch; | |
d166f048 | 76 | int return_val, fd, result, pflags; |
ccc6cda3 JA |
77 | char *string; |
78 | struct stat finfo; | |
cce855bc | 79 | size_t file_size; |
ccc6cda3 JA |
80 | VFunction *errfunc; |
81 | ||
82 | fd = open (filename, O_RDONLY); | |
83 | ||
84 | if (fd < 0 || (fstat (fd, &finfo) == -1)) | |
85 | { | |
86 | file_error_and_exit: | |
87 | if (((flags & FEVAL_ENOENTOK) == 0) || errno != ENOENT) | |
88 | file_error (filename); | |
89 | ||
90 | if (flags & FEVAL_LONGJMP) | |
28ef6c31 | 91 | { |
ccc6cda3 JA |
92 | last_command_exit_value = 1; |
93 | jump_to_top_level (EXITPROG); | |
94 | } | |
95 | ||
96 | return ((flags & FEVAL_BUILTIN) ? EXECUTION_FAILURE | |
97 | : ((errno == ENOENT) ? 0 : -1)); | |
98 | } | |
99 | ||
100 | errfunc = (VFunction *)((flags & FEVAL_BUILTIN) ? builtin_error : internal_error); | |
101 | ||
102 | if (S_ISDIR (finfo.st_mode)) | |
103 | { | |
104 | (*errfunc) ("%s: is a directory", filename); | |
105 | return ((flags & FEVAL_BUILTIN) ? EXECUTION_FAILURE : -1); | |
106 | } | |
107 | else if (S_ISREG (finfo.st_mode) == 0) | |
108 | { | |
109 | (*errfunc) ("%s: not a regular file", filename); | |
110 | return ((flags & FEVAL_BUILTIN) ? EXECUTION_FAILURE : -1); | |
111 | } | |
112 | ||
cce855bc JA |
113 | file_size = (size_t)finfo.st_size; |
114 | /* Check for overflow with large files. */ | |
115 | if (file_size != finfo.st_size || file_size + 1 < file_size) | |
116 | { | |
117 | (*errfunc) ("%s: file is too large", filename); | |
118 | return ((flags & FEVAL_BUILTIN) ? EXECUTION_FAILURE : -1); | |
119 | } | |
28ef6c31 JA |
120 | |
121 | #if defined (__CYGWIN__) && defined (O_TEXT) | |
122 | setmode (fd, O_TEXT); | |
123 | #endif | |
124 | ||
cce855bc JA |
125 | string = xmalloc (1 + file_size); |
126 | result = read (fd, string, file_size); | |
ccc6cda3 JA |
127 | string[result] = '\0'; |
128 | ||
129 | return_val = errno; | |
130 | close (fd); | |
131 | errno = return_val; | |
132 | ||
cce855bc | 133 | if (result < 0) /* XXX was != file_size, not < 0 */ |
ccc6cda3 JA |
134 | { |
135 | free (string); | |
136 | goto file_error_and_exit; | |
137 | } | |
138 | ||
cce855bc JA |
139 | if (result == 0) |
140 | { | |
141 | free (string); | |
142 | return ((flags & FEVAL_BUILTIN) ? EXECUTION_SUCCESS : 1); | |
143 | } | |
144 | ||
28ef6c31 JA |
145 | if ((flags & FEVAL_CHECKBINARY) && |
146 | check_binary_file ((unsigned char *)string, (result > 80) ? 80 : result)) | |
ccc6cda3 JA |
147 | { |
148 | free (string); | |
149 | (*errfunc) ("%s: cannot execute binary file", filename); | |
150 | return ((flags & FEVAL_BUILTIN) ? EX_BINARY_FILE : -1); | |
151 | } | |
152 | ||
153 | if (flags & FEVAL_UNWINDPROT) | |
154 | { | |
155 | begin_unwind_frame ("_evalfile"); | |
156 | ||
157 | unwind_protect_int (return_catch_flag); | |
158 | unwind_protect_jmp_buf (return_catch); | |
159 | if (flags & FEVAL_NONINT) | |
160 | unwind_protect_int (interactive); | |
161 | unwind_protect_int (sourcelevel); | |
162 | } | |
163 | else | |
164 | { | |
165 | COPY_PROCENV (return_catch, old_return_catch); | |
166 | if (flags & FEVAL_NONINT) | |
167 | old_interactive = interactive; | |
168 | } | |
169 | ||
170 | if (flags & FEVAL_NONINT) | |
171 | interactive = 0; | |
172 | ||
173 | return_catch_flag++; | |
174 | sourcelevel++; | |
175 | ||
d166f048 JA |
176 | /* set the flags to be passed to parse_and_execute */ |
177 | pflags = (flags & FEVAL_HISTORY) ? 0 : SEVAL_NOHIST; | |
178 | ||
ccc6cda3 JA |
179 | if (flags & FEVAL_BUILTIN) |
180 | result = EXECUTION_SUCCESS; | |
181 | ||
182 | return_val = setjmp (return_catch); | |
183 | ||
184 | /* If `return' was seen outside of a function, but in the script, then | |
185 | force parse_and_execute () to clean up. */ | |
186 | if (return_val) | |
187 | { | |
188 | parse_and_execute_cleanup (); | |
189 | result = return_catch_value; | |
190 | } | |
191 | else | |
d166f048 | 192 | result = parse_and_execute (string, filename, pflags); |
ccc6cda3 JA |
193 | |
194 | if (flags & FEVAL_UNWINDPROT) | |
195 | run_unwind_frame ("_evalfile"); | |
196 | else | |
197 | { | |
198 | if (flags & FEVAL_NONINT) | |
199 | interactive = old_interactive; | |
200 | return_catch_flag--; | |
201 | sourcelevel--; | |
202 | COPY_PROCENV (old_return_catch, return_catch); | |
203 | } | |
204 | ||
205 | return ((flags & FEVAL_BUILTIN) ? result : 1); | |
206 | } | |
207 | ||
208 | int | |
209 | maybe_execute_file (fname, force_noninteractive) | |
210 | char *fname; | |
211 | int force_noninteractive; | |
212 | { | |
213 | char *filename; | |
214 | int result, flags; | |
215 | ||
216 | filename = bash_tilde_expand (fname); | |
217 | flags = FEVAL_ENOENTOK; | |
218 | if (force_noninteractive) | |
219 | flags |= FEVAL_NONINT; | |
220 | result = _evalfile (filename, flags); | |
221 | free (filename); | |
222 | return result; | |
223 | } | |
224 | ||
d166f048 JA |
225 | #if defined (HISTORY) |
226 | int | |
227 | fc_execute_file (filename) | |
228 | char *filename; | |
229 | { | |
230 | int flags; | |
231 | ||
232 | /* We want these commands to show up in the history list if | |
233 | remember_on_history is set. */ | |
234 | flags = FEVAL_ENOENTOK|FEVAL_HISTORY; | |
235 | return (_evalfile (filename, flags)); | |
236 | } | |
237 | #endif /* HISTORY */ | |
238 | ||
ccc6cda3 JA |
239 | int |
240 | source_file (filename) | |
241 | char *filename; | |
242 | { | |
243 | int flags; | |
244 | ||
245 | flags = FEVAL_BUILTIN|FEVAL_UNWINDPROT|FEVAL_NONINT; | |
246 | /* POSIX shells exit if non-interactive and file error. */ | |
247 | if (posixly_correct && !interactive_shell) | |
248 | flags |= FEVAL_LONGJMP; | |
249 | return (_evalfile (filename, flags)); | |
250 | } |