1This file is source.def, from which is created source.c.
2It implements the builtins "." and  "source" in Bash.
3
4Copyright (C) 1987-2020 Free Software Foundation, Inc.
5
6This file is part of GNU Bash, the Bourne Again SHell.
7
8Bash is free software: you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
10the Free Software Foundation, either version 3 of the License, or
11(at your option) any later version.
12
13Bash is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
19along with Bash.  If not, see <http://www.gnu.org/licenses/>.
20
21$PRODUCES source.c
22
23$BUILTIN source
24$FUNCTION source_builtin
25$SHORT_DOC source filename [arguments]
26Execute commands from a file in the current shell.
27
28Read and execute commands from FILENAME in the current shell.  The
29entries in $PATH are used to find the directory containing FILENAME.
30If any ARGUMENTS are supplied, they become the positional parameters
31when FILENAME is executed.
32
33Exit Status:
34Returns the status of the last command executed in FILENAME; fails if
35FILENAME cannot be read.
36$END
37
38$BUILTIN .
39$DOCNAME dot
40$FUNCTION source_builtin
41$SHORT_DOC . filename [arguments]
42Execute commands from a file in the current shell.
43
44Read and execute commands from FILENAME in the current shell.  The
45entries in $PATH are used to find the directory containing FILENAME.
46If any ARGUMENTS are supplied, they become the positional parameters
47when FILENAME is executed.
48
49Exit Status:
50Returns the status of the last command executed in FILENAME; fails if
51FILENAME cannot be read.
52$END
53
54#include <config.h>
55
56#include "../bashtypes.h"
57#include "posixstat.h"
58#include "filecntl.h"
59#if ! defined(_MINIX) && defined (HAVE_SYS_FILE_H)
60#  include <sys/file.h>
61#endif
62#include <errno.h>
63
64#if defined (HAVE_UNISTD_H)
65#  include <unistd.h>
66#endif
67
68#include "../bashansi.h"
69#include "../bashintl.h"
70
71#include "../shell.h"
72#include "../execute_cmd.h"
73#include "../flags.h"
74#include "../findcmd.h"
75#include "common.h"
76#include "bashgetopt.h"
77#include "../trap.h"
78
79#if !defined (errno)
80extern int errno;
81#endif /* !errno */
82
83static void maybe_pop_dollar_vars PARAMS((void));
84
85/* If non-zero, `.' uses $PATH to look up the script to be sourced. */
86int source_uses_path = 1;
87
88/* If non-zero, `.' looks in the current directory if the filename argument
89   is not found in the $PATH. */
90int source_searches_cwd = 1;
91
92/* If this . script is supplied arguments, we save the dollar vars and
93   replace them with the script arguments for the duration of the script's
94   execution.  If the script does not change the dollar vars, we restore
95   what we saved.  If the dollar vars are changed in the script, and we are
96   not executing a shell function, we leave the new values alone and free
97   the saved values. */
98static void
99maybe_pop_dollar_vars ()
100{
101  if (variable_context == 0 && (dollar_vars_changed () & ARGS_SETBLTIN))
102    dispose_saved_dollar_vars ();
103  else
104    pop_dollar_vars ();
105  if (debugging_mode)
106    pop_args ();	/* restore BASH_ARGC and BASH_ARGV */
107  set_dollar_vars_unchanged ();
108  invalidate_cached_quoted_dollar_at ();	/* just invalidate to be safe */
109}
110
111/* Read and execute commands from the file passed as argument.  Guess what.
112   This cannot be done in a subshell, since things like variable assignments
113   take place in there.  So, I open the file, place it into a large string,
114   close the file, and then execute the string. */
115int
116source_builtin (list)
117     WORD_LIST *list;
118{
119  int result;
120  char *filename, *debug_trap, *x;
121
122  if (no_options (list))
123    return (EX_USAGE);
124  list = loptend;
125
126  if (list == 0)
127    {
128      builtin_error (_("filename argument required"));
129      builtin_usage ();
130      return (EX_USAGE);
131    }
132
133#if defined (RESTRICTED_SHELL)
134  if (restricted && strchr (list->word->word, '/'))
135    {
136      sh_restricted (list->word->word);
137      return (EXECUTION_FAILURE);
138    }
139#endif
140
141  filename = (char *)NULL;
142  /* XXX -- should this be absolute_pathname? */
143  if (posixly_correct && strchr (list->word->word, '/'))
144    filename = savestring (list->word->word);
145  else if (absolute_pathname (list->word->word))
146    filename = savestring (list->word->word);
147  else if (source_uses_path)
148    filename = find_path_file (list->word->word);
149  if (filename == 0)
150    {
151      if (source_searches_cwd == 0)
152	{
153	  x = printable_filename (list->word->word, 0);
154	  builtin_error (_("%s: file not found"), x);
155	  if (x != list->word->word)
156	    free (x);
157	  if (posixly_correct && interactive_shell == 0 && executing_command_builtin == 0)
158	    {
159	      last_command_exit_value = EXECUTION_FAILURE;
160	      jump_to_top_level (EXITPROG);
161	    }
162	  return (EXECUTION_FAILURE);
163	}
164      else
165	filename = savestring (list->word->word);
166    }
167
168  begin_unwind_frame ("source");
169  add_unwind_protect (xfree, filename);
170
171  if (list->next)
172    {
173      push_dollar_vars ();
174      add_unwind_protect ((Function *)maybe_pop_dollar_vars, (char *)NULL);
175      if (debugging_mode || shell_compatibility_level <= 44)
176	init_bash_argv ();	/* Initialize BASH_ARGV and BASH_ARGC */
177      remember_args (list->next, 1);
178      if (debugging_mode)
179	push_args (list->next);	/* Update BASH_ARGV and BASH_ARGC */
180    }
181  set_dollar_vars_unchanged ();
182
183  /* Don't inherit the DEBUG trap unless function_trace_mode (overloaded)
184     is set.  XXX - should sourced files inherit the RETURN trap?  Functions
185     don't. */
186  debug_trap = TRAP_STRING (DEBUG_TRAP);
187  if (debug_trap && function_trace_mode == 0)
188    {
189      debug_trap = savestring (debug_trap);
190      add_unwind_protect (xfree, debug_trap);
191      add_unwind_protect (maybe_set_debug_trap, debug_trap);
192      restore_default_signal (DEBUG_TRAP);
193    }
194
195  result = source_file (filename, (list && list->next));
196
197  run_unwind_frame ("source");
198
199  return (result);
200}
201