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