Imported from ../bash-2.05.tar.gz.
[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
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;
76   int return_val, fd, result, pflags;
77   char *string;
78   struct stat finfo;
79   size_t file_size;
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)
91         {
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
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     }      
120
121 #if defined (__CYGWIN__) && defined (O_TEXT)
122   setmode (fd, O_TEXT);
123 #endif
124
125   string = xmalloc (1 + file_size);
126   result = read (fd, string, file_size);
127   string[result] = '\0';
128
129   return_val = errno;
130   close (fd);
131   errno = return_val;
132
133   if (result < 0)               /* XXX was != file_size, not < 0 */
134     {
135       free (string);
136       goto file_error_and_exit;
137     }
138
139   if (result == 0)
140     {
141       free (string);
142       return ((flags & FEVAL_BUILTIN) ? EXECUTION_SUCCESS : 1);
143     }
144       
145   if ((flags & FEVAL_CHECKBINARY) && 
146       check_binary_file ((unsigned char *)string, (result > 80) ? 80 : result))
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
176   /* set the flags to be passed to parse_and_execute */
177   pflags = (flags & FEVAL_HISTORY) ? 0 : SEVAL_NOHIST;
178
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
192     result = parse_and_execute (string, filename, pflags);
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
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
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 }