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