]>
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 | ||
3185942a | 4 | Copyright (C) 1987-2009 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 JA |
78 | extern REDIRECT *redirection_undo_list; |
79 | ||
ccc6cda3 JA |
80 | int no_exit_on_failed_exec; |
81 | ||
82 | /* If the user wants this to look like a login shell, then | |
83 | prepend a `-' onto NAME and return the new name. */ | |
84 | static char * | |
85 | mkdashname (name) | |
86 | char *name; | |
87 | { | |
88 | char *ret; | |
89 | ||
f73dda09 | 90 | ret = (char *)xmalloc (2 + strlen (name)); |
ccc6cda3 JA |
91 | ret[0] = '-'; |
92 | strcpy (ret + 1, name); | |
93 | return ret; | |
94 | } | |
95 | ||
726f6388 JA |
96 | int |
97 | exec_builtin (list) | |
98 | WORD_LIST *list; | |
99 | { | |
100 | int exit_value = EXECUTION_FAILURE; | |
ccc6cda3 | 101 | int cleanenv, login, opt; |
d166f048 | 102 | char *argv0, *command, **args, **env, *newname, *com2; |
726f6388 | 103 | |
ccc6cda3 JA |
104 | cleanenv = login = 0; |
105 | argv0 = (char *)NULL; | |
106 | ||
107 | reset_internal_getopt (); | |
108 | while ((opt = internal_getopt (list, "cla:")) != -1) | |
109 | { | |
110 | switch (opt) | |
111 | { | |
112 | case 'c': | |
113 | cleanenv = 1; | |
114 | break; | |
115 | case 'l': | |
116 | login = 1; | |
117 | break; | |
118 | case 'a': | |
119 | argv0 = list_optarg; | |
120 | break; | |
121 | default: | |
122 | builtin_usage (); | |
123 | return (EX_USAGE); | |
124 | } | |
125 | } | |
126 | list = loptend; | |
726f6388 JA |
127 | |
128 | /* First, let the redirections remain. */ | |
129 | dispose_redirects (redirection_undo_list); | |
130 | redirection_undo_list = (REDIRECT *)NULL; | |
131 | ||
ccc6cda3 | 132 | if (list == 0) |
726f6388 | 133 | return (EXECUTION_SUCCESS); |
ccc6cda3 JA |
134 | |
135 | #if defined (RESTRICTED_SHELL) | |
136 | if (restricted) | |
726f6388 | 137 | { |
7117c2d2 | 138 | sh_restricted ((char *)NULL); |
ccc6cda3 JA |
139 | return (EXECUTION_FAILURE); |
140 | } | |
141 | #endif /* RESTRICTED_SHELL */ | |
726f6388 | 142 | |
7117c2d2 | 143 | args = strvec_from_word_list (list, 1, 0, (int *)NULL); |
726f6388 | 144 | |
ccc6cda3 JA |
145 | /* A command with a slash anywhere in its name is not looked up in $PATH. */ |
146 | command = absolute_program (args[0]) ? args[0] : search_for_command (args[0]); | |
726f6388 | 147 | |
ccc6cda3 JA |
148 | if (command == 0) |
149 | { | |
7117c2d2 | 150 | sh_notfound (args[0]); |
ccc6cda3 JA |
151 | exit_value = EX_NOTFOUND; /* As per Posix.2, 3.14.6 */ |
152 | goto failed_exec; | |
153 | } | |
726f6388 | 154 | |
d166f048 JA |
155 | com2 = full_pathname (command); |
156 | if (com2) | |
157 | { | |
158 | if (command != args[0]) | |
159 | free (command); | |
160 | command = com2; | |
161 | } | |
726f6388 | 162 | |
ccc6cda3 JA |
163 | if (argv0) |
164 | { | |
165 | free (args[0]); | |
166 | args[0] = login ? mkdashname (argv0) : savestring (argv0); | |
167 | } | |
168 | else if (login) | |
169 | { | |
170 | newname = mkdashname (args[0]); | |
171 | free (args[0]); | |
172 | args[0] = newname; | |
173 | } | |
726f6388 | 174 | |
ccc6cda3 JA |
175 | /* Decrement SHLVL by 1 so a new shell started here has the same value, |
176 | preserving the appearance. After we do that, we need to change the | |
177 | exported environment to include the new value. */ | |
178 | if (cleanenv == 0) | |
179 | adjust_shell_level (-1); | |
726f6388 | 180 | |
ccc6cda3 JA |
181 | if (cleanenv) |
182 | env = (char **)NULL; | |
183 | else | |
184 | { | |
726f6388 | 185 | maybe_make_export_env (); |
ccc6cda3 JA |
186 | env = export_env; |
187 | } | |
726f6388 JA |
188 | |
189 | #if defined (HISTORY) | |
d166f048 JA |
190 | if (interactive_shell && subshell_environment == 0) |
191 | maybe_save_shell_history (); | |
726f6388 | 192 | #endif /* HISTORY */ |
ccc6cda3 JA |
193 | |
194 | restore_original_signals (); | |
726f6388 JA |
195 | |
196 | #if defined (JOB_CONTROL) | |
ccc6cda3 JA |
197 | if (subshell_environment == 0) |
198 | end_job_control (); | |
726f6388 JA |
199 | #endif /* JOB_CONTROL */ |
200 | ||
ccc6cda3 | 201 | shell_execve (command, args, env); |
bc4cd23c JA |
202 | |
203 | /* We have to set this to NULL because shell_execve has called realloc() | |
204 | to stuff more items at the front of the array, which may have caused | |
205 | the memory to be freed by realloc(). We don't want to free it twice. */ | |
206 | args = (char **)NULL; | |
ccc6cda3 JA |
207 | if (cleanenv == 0) |
208 | adjust_shell_level (1); | |
726f6388 | 209 | |
ccc6cda3 JA |
210 | if (executable_file (command) == 0) |
211 | { | |
b80f6443 | 212 | builtin_error (_("%s: cannot execute: %s"), command, strerror (errno)); |
ccc6cda3 JA |
213 | exit_value = EX_NOEXEC; /* As per Posix.2, 3.14.6 */ |
214 | } | |
215 | else | |
216 | file_error (command); | |
726f6388 | 217 | |
ccc6cda3 | 218 | failed_exec: |
b80f6443 | 219 | FREE (command); |
726f6388 | 220 | |
ccc6cda3 JA |
221 | if (subshell_environment || (interactive == 0 && no_exit_on_failed_exec == 0)) |
222 | exit_shell (exit_value); | |
726f6388 | 223 | |
d166f048 | 224 | if (args) |
7117c2d2 | 225 | strvec_dispose (args); |
d166f048 | 226 | |
ccc6cda3 | 227 | initialize_traps (); |
7117c2d2 | 228 | initialize_signals (1); |
726f6388 JA |
229 | |
230 | #if defined (JOB_CONTROL) | |
95732b49 JA |
231 | if (interactive_shell || job_control) |
232 | restart_job_control (); | |
726f6388 JA |
233 | #endif /* JOB_CONTROL */ |
234 | ||
ccc6cda3 | 235 | return (exit_value); |
726f6388 | 236 | } |