]>
Commit | Line | Data |
---|---|---|
726f6388 JA |
1 | This file is exec.def, from which is created exec.c. |
2 | It implements the builtin "exec" in Bash. | |
3 | ||
495aee44 | 4 | Copyright (C) 1987-2010 Free Software Foundation, Inc. |
726f6388 JA |
5 | |
6 | This file is part of GNU Bash, the Bourne Again SHell. | |
7 | ||
3185942a JA |
8 | Bash is free software: you can redistribute it and/or modify |
9 | it under the terms of the GNU General Public License as published by | |
10 | the Free Software Foundation, either version 3 of the License, or | |
11 | (at your option) any later version. | |
726f6388 | 12 | |
3185942a JA |
13 | Bash is distributed in the hope that it will be useful, |
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | GNU General Public License for more details. | |
726f6388 | 17 | |
3185942a JA |
18 | You should have received a copy of the GNU General Public License |
19 | along with Bash. If not, see <http://www.gnu.org/licenses/>. | |
726f6388 JA |
20 | |
21 | $PRODUCES exec.c | |
22 | ||
23 | $BUILTIN exec | |
24 | $FUNCTION exec_builtin | |
3185942a JA |
25 | $SHORT_DOC exec [-cl] [-a name] [command [arguments ...]] [redirection ...] |
26 | Replace the shell with the given command. | |
27 | ||
28 | Execute COMMAND, replacing this shell with the specified program. | |
29 | ARGUMENTS become the arguments to COMMAND. If COMMAND is not specified, | |
30 | any redirections take effect in the current shell. | |
31 | ||
32 | Options: | |
33 | -a name pass NAME as the zeroth argument to COMMAND | |
34 | -c execute COMMAND with an empty environment | |
35 | -l place a dash in the zeroth argument to COMMAND | |
36 | ||
37 | If the command cannot be executed, a non-interactive shell exits, unless | |
38 | the shell option `execfail' is set. | |
39 | ||
40 | Exit Status: | |
41 | Returns success unless COMMAND is not found or a redirection error occurs. | |
726f6388 JA |
42 | $END |
43 | ||
ccc6cda3 JA |
44 | #include <config.h> |
45 | ||
d166f048 | 46 | #include "../bashtypes.h" |
bb70624e | 47 | #include "posixstat.h" |
726f6388 JA |
48 | #include <signal.h> |
49 | #include <errno.h> | |
50 | ||
ccc6cda3 JA |
51 | #if defined (HAVE_UNISTD_H) |
52 | # include <unistd.h> | |
53 | #endif | |
54 | ||
55 | #include "../bashansi.h" | |
b80f6443 | 56 | #include "../bashintl.h" |
ccc6cda3 JA |
57 | |
58 | #include "../shell.h" | |
726f6388 | 59 | #include "../execute_cmd.h" |
cce855bc | 60 | #include "../findcmd.h" |
ccc6cda3 JA |
61 | #if defined (JOB_CONTROL) |
62 | # include "../jobs.h" | |
63 | #endif | |
726f6388 | 64 | #include "../flags.h" |
ccc6cda3 JA |
65 | #include "../trap.h" |
66 | #if defined (HISTORY) | |
67 | # include "../bashhist.h" | |
68 | #endif | |
69 | #include "common.h" | |
70 | #include "bashgetopt.h" | |
726f6388 JA |
71 | |
72 | /* Not all systems declare ERRNO in errno.h... and some systems #define it! */ | |
73 | #if !defined (errno) | |
74 | extern int errno; | |
75 | #endif /* !errno */ | |
ccc6cda3 | 76 | |
f73dda09 | 77 | extern int subshell_environment; |
726f6388 | 78 | extern REDIRECT *redirection_undo_list; |
495aee44 | 79 | extern char *exec_argv0; |
726f6388 | 80 | |
ccc6cda3 JA |
81 | int no_exit_on_failed_exec; |
82 | ||
83 | /* If the user wants this to look like a login shell, then | |
84 | prepend a `-' onto NAME and return the new name. */ | |
85 | static char * | |
86 | mkdashname (name) | |
87 | char *name; | |
88 | { | |
89 | char *ret; | |
90 | ||
f73dda09 | 91 | ret = (char *)xmalloc (2 + strlen (name)); |
ccc6cda3 JA |
92 | ret[0] = '-'; |
93 | strcpy (ret + 1, name); | |
94 | return ret; | |
95 | } | |
96 | ||
726f6388 JA |
97 | int |
98 | exec_builtin (list) | |
99 | WORD_LIST *list; | |
100 | { | |
101 | int exit_value = EXECUTION_FAILURE; | |
ccc6cda3 | 102 | int cleanenv, login, opt; |
d166f048 | 103 | char *argv0, *command, **args, **env, *newname, *com2; |
726f6388 | 104 | |
ccc6cda3 | 105 | cleanenv = login = 0; |
495aee44 | 106 | exec_argv0 = argv0 = (char *)NULL; |
ccc6cda3 JA |
107 | |
108 | reset_internal_getopt (); | |
109 | while ((opt = internal_getopt (list, "cla:")) != -1) | |
110 | { | |
111 | switch (opt) | |
112 | { | |
113 | case 'c': | |
114 | cleanenv = 1; | |
115 | break; | |
116 | case 'l': | |
117 | login = 1; | |
118 | break; | |
119 | case 'a': | |
120 | argv0 = list_optarg; | |
121 | break; | |
122 | default: | |
123 | builtin_usage (); | |
124 | return (EX_USAGE); | |
125 | } | |
126 | } | |
127 | list = loptend; | |
726f6388 JA |
128 | |
129 | /* First, let the redirections remain. */ | |
130 | dispose_redirects (redirection_undo_list); | |
131 | redirection_undo_list = (REDIRECT *)NULL; | |
132 | ||
ccc6cda3 | 133 | if (list == 0) |
726f6388 | 134 | return (EXECUTION_SUCCESS); |
ccc6cda3 JA |
135 | |
136 | #if defined (RESTRICTED_SHELL) | |
137 | if (restricted) | |
726f6388 | 138 | { |
7117c2d2 | 139 | sh_restricted ((char *)NULL); |
ccc6cda3 JA |
140 | return (EXECUTION_FAILURE); |
141 | } | |
142 | #endif /* RESTRICTED_SHELL */ | |
726f6388 | 143 | |
7117c2d2 | 144 | args = strvec_from_word_list (list, 1, 0, (int *)NULL); |
726f6388 | 145 | |
ccc6cda3 JA |
146 | /* A command with a slash anywhere in its name is not looked up in $PATH. */ |
147 | command = absolute_program (args[0]) ? args[0] : search_for_command (args[0]); | |
726f6388 | 148 | |
ccc6cda3 JA |
149 | if (command == 0) |
150 | { | |
495aee44 CR |
151 | if (file_isdir (args[0])) |
152 | { | |
153 | #if defined (EISDIR) | |
154 | builtin_error (_("%s: cannot execute: %s"), args[0], strerror (EISDIR)); | |
155 | #else | |
156 | builtin_error (_("%s: cannot execute: %s"), args[0], strerror (errno)); | |
157 | #endif | |
158 | exit_value = EX_NOEXEC; | |
159 | } | |
160 | else | |
161 | { | |
162 | sh_notfound (args[0]); | |
163 | exit_value = EX_NOTFOUND; /* As per Posix.2, 3.14.6 */ | |
164 | } | |
ccc6cda3 JA |
165 | goto failed_exec; |
166 | } | |
726f6388 | 167 | |
d166f048 JA |
168 | com2 = full_pathname (command); |
169 | if (com2) | |
170 | { | |
171 | if (command != args[0]) | |
172 | free (command); | |
173 | command = com2; | |
174 | } | |
726f6388 | 175 | |
ccc6cda3 JA |
176 | if (argv0) |
177 | { | |
178 | free (args[0]); | |
179 | args[0] = login ? mkdashname (argv0) : savestring (argv0); | |
495aee44 | 180 | exec_argv0 = savestring (args[0]); |
ccc6cda3 JA |
181 | } |
182 | else if (login) | |
183 | { | |
184 | newname = mkdashname (args[0]); | |
185 | free (args[0]); | |
186 | args[0] = newname; | |
187 | } | |
726f6388 | 188 | |
ccc6cda3 JA |
189 | /* Decrement SHLVL by 1 so a new shell started here has the same value, |
190 | preserving the appearance. After we do that, we need to change the | |
191 | exported environment to include the new value. */ | |
192 | if (cleanenv == 0) | |
193 | adjust_shell_level (-1); | |
726f6388 | 194 | |
ccc6cda3 JA |
195 | if (cleanenv) |
196 | env = (char **)NULL; | |
197 | else | |
198 | { | |
726f6388 | 199 | maybe_make_export_env (); |
ccc6cda3 JA |
200 | env = export_env; |
201 | } | |
726f6388 JA |
202 | |
203 | #if defined (HISTORY) | |
d166f048 JA |
204 | if (interactive_shell && subshell_environment == 0) |
205 | maybe_save_shell_history (); | |
726f6388 | 206 | #endif /* HISTORY */ |
ccc6cda3 JA |
207 | |
208 | restore_original_signals (); | |
726f6388 JA |
209 | |
210 | #if defined (JOB_CONTROL) | |
ccc6cda3 JA |
211 | if (subshell_environment == 0) |
212 | end_job_control (); | |
726f6388 JA |
213 | #endif /* JOB_CONTROL */ |
214 | ||
495aee44 | 215 | exit_value = shell_execve (command, args, env); |
bc4cd23c JA |
216 | |
217 | /* We have to set this to NULL because shell_execve has called realloc() | |
218 | to stuff more items at the front of the array, which may have caused | |
219 | the memory to be freed by realloc(). We don't want to free it twice. */ | |
220 | args = (char **)NULL; | |
ccc6cda3 JA |
221 | if (cleanenv == 0) |
222 | adjust_shell_level (1); | |
726f6388 | 223 | |
495aee44 CR |
224 | if (exit_value == EX_NOTFOUND) /* no duplicate error message */ |
225 | goto failed_exec; | |
226 | else if (executable_file (command) == 0) | |
ccc6cda3 | 227 | { |
b80f6443 | 228 | builtin_error (_("%s: cannot execute: %s"), command, strerror (errno)); |
ccc6cda3 JA |
229 | exit_value = EX_NOEXEC; /* As per Posix.2, 3.14.6 */ |
230 | } | |
231 | else | |
232 | file_error (command); | |
726f6388 | 233 | |
ccc6cda3 | 234 | failed_exec: |
b80f6443 | 235 | FREE (command); |
726f6388 | 236 | |
ccc6cda3 JA |
237 | if (subshell_environment || (interactive == 0 && no_exit_on_failed_exec == 0)) |
238 | exit_shell (exit_value); | |
726f6388 | 239 | |
d166f048 | 240 | if (args) |
7117c2d2 | 241 | strvec_dispose (args); |
d166f048 | 242 | |
ccc6cda3 | 243 | initialize_traps (); |
7117c2d2 | 244 | initialize_signals (1); |
726f6388 JA |
245 | |
246 | #if defined (JOB_CONTROL) | |
95732b49 JA |
247 | if (interactive_shell || job_control) |
248 | restart_job_control (); | |
726f6388 JA |
249 | #endif /* JOB_CONTROL */ |
250 | ||
ccc6cda3 | 251 | return (exit_value); |
726f6388 | 252 | } |