1This file is exec.def, from which is created exec.c. 2It implements the builtin "exec" in Bash. 3 4Copyright (C) 1987-2019 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 exec.c 22 23$BUILTIN exec 24$FUNCTION exec_builtin 25$SHORT_DOC exec [-cl] [-a name] [command [argument ...]] [redirection ...] 26Replace the shell with the given command. 27 28Execute COMMAND, replacing this shell with the specified program. 29ARGUMENTS become the arguments to COMMAND. If COMMAND is not specified, 30any redirections take effect in the current shell. 31 32Options: 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 37If the command cannot be executed, a non-interactive shell exits, unless 38the shell option `execfail' is set. 39 40Exit Status: 41Returns success unless COMMAND is not found or a redirection error occurs. 42$END 43 44#include <config.h> 45 46#include "../bashtypes.h" 47#include "posixstat.h" 48#include <signal.h> 49#include <errno.h> 50 51#if defined (HAVE_UNISTD_H) 52# include <unistd.h> 53#endif 54 55#include <stdio.h> 56 57#include "../bashansi.h" 58#include "../bashintl.h" 59 60#include "../shell.h" 61#include "../execute_cmd.h" 62#include "../findcmd.h" 63#if defined (JOB_CONTROL) 64# include "../jobs.h" 65#endif 66#include "../flags.h" 67#include "../trap.h" 68#if defined (HISTORY) 69# include "../bashhist.h" 70#endif 71#include "common.h" 72#include "bashgetopt.h" 73#include "input.h" 74 75/* Not all systems declare ERRNO in errno.h... and some systems #define it! */ 76#if !defined (errno) 77extern int errno; 78#endif /* !errno */ 79 80extern REDIRECT *redirection_undo_list; 81extern char *exec_argv0; 82 83int no_exit_on_failed_exec; 84 85/* If the user wants this to look like a login shell, then 86 prepend a `-' onto NAME and return the new name. */ 87static char * 88mkdashname (name) 89 char *name; 90{ 91 char *ret; 92 93 ret = (char *)xmalloc (2 + strlen (name)); 94 ret[0] = '-'; 95 strcpy (ret + 1, name); 96 return ret; 97} 98 99int 100exec_builtin (list) 101 WORD_LIST *list; 102{ 103 int exit_value = EXECUTION_FAILURE; 104 int cleanenv, login, opt, orig_job_control; 105 char *argv0, *command, **args, **env, *newname, *com2; 106 107 cleanenv = login = 0; 108 exec_argv0 = argv0 = (char *)NULL; 109 110 reset_internal_getopt (); 111 while ((opt = internal_getopt (list, "cla:")) != -1) 112 { 113 switch (opt) 114 { 115 case 'c': 116 cleanenv = 1; 117 break; 118 case 'l': 119 login = 1; 120 break; 121 case 'a': 122 argv0 = list_optarg; 123 break; 124 CASE_HELPOPT; 125 default: 126 builtin_usage (); 127 return (EX_USAGE); 128 } 129 } 130 list = loptend; 131 132 /* First, let the redirections remain. */ 133 dispose_redirects (redirection_undo_list); 134 redirection_undo_list = (REDIRECT *)NULL; 135 136 if (list == 0) 137 return (EXECUTION_SUCCESS); 138 139#if defined (RESTRICTED_SHELL) 140 if (restricted) 141 { 142 sh_restricted ((char *)NULL); 143 return (EXECUTION_FAILURE); 144 } 145#endif /* RESTRICTED_SHELL */ 146 147 args = strvec_from_word_list (list, 1, 0, (int *)NULL); 148 env = (char **)0; 149 150 /* A command with a slash anywhere in its name is not looked up in $PATH. */ 151 command = absolute_program (args[0]) ? args[0] : search_for_command (args[0], 1); 152 153 if (command == 0) 154 { 155 if (file_isdir (args[0])) 156 { 157#if defined (EISDIR) 158 builtin_error (_("%s: cannot execute: %s"), args[0], strerror (EISDIR)); 159#else 160 builtin_error (_("%s: cannot execute: %s"), args[0], strerror (errno)); 161#endif 162 exit_value = EX_NOEXEC; 163 } 164 else 165 { 166 sh_notfound (args[0]); 167 exit_value = EX_NOTFOUND; /* As per Posix.2, 3.14.6 */ 168 } 169 goto failed_exec; 170 } 171 172 com2 = full_pathname (command); 173 if (com2) 174 { 175 if (command != args[0]) 176 free (command); 177 command = com2; 178 } 179 180 if (argv0) 181 { 182 free (args[0]); 183 args[0] = login ? mkdashname (argv0) : savestring (argv0); 184 exec_argv0 = savestring (args[0]); 185 } 186 else if (login) 187 { 188 newname = mkdashname (args[0]); 189 free (args[0]); 190 args[0] = newname; 191 } 192 193 /* Decrement SHLVL by 1 so a new shell started here has the same value, 194 preserving the appearance. After we do that, we need to change the 195 exported environment to include the new value. If we've already forked 196 and are in a subshell, we don't want to decrement the shell level, 197 since we are `increasing' the level */ 198 199 if (cleanenv == 0 && (subshell_environment & SUBSHELL_PAREN) == 0) 200 adjust_shell_level (-1); 201 202 if (cleanenv) 203 { 204 env = strvec_create (1); 205 env[0] = (char *)0; 206 } 207 else 208 { 209 maybe_make_export_env (); 210 env = export_env; 211 } 212 213#if defined (HISTORY) 214 if (interactive_shell && subshell_environment == 0) 215 maybe_save_shell_history (); 216#endif /* HISTORY */ 217 218 restore_original_signals (); 219 220#if defined (JOB_CONTROL) 221 orig_job_control = job_control; /* XXX - was also interactive_shell */ 222 if (subshell_environment == 0) 223 end_job_control (); 224 if (interactive || job_control) 225 default_tty_job_signals (); /* undo initialize_job_signals */ 226#endif /* JOB_CONTROL */ 227 228#if defined (BUFFERED_INPUT) 229 if (default_buffered_input >= 0) 230 sync_buffered_stream (default_buffered_input); 231#endif 232 233 exit_value = shell_execve (command, args, env); 234 235 /* We have to set this to NULL because shell_execve has called realloc() 236 to stuff more items at the front of the array, which may have caused 237 the memory to be freed by realloc(). We don't want to free it twice. */ 238 args = (char **)NULL; 239 if (cleanenv == 0) 240 adjust_shell_level (1); 241 242 if (exit_value == EX_NOTFOUND) /* no duplicate error message */ 243 goto failed_exec; 244 else if (executable_file (command) == 0) 245 { 246 builtin_error (_("%s: cannot execute: %s"), command, strerror (errno)); 247 exit_value = EX_NOEXEC; /* As per Posix.2, 3.14.6 */ 248 } 249 else 250 file_error (command); 251 252failed_exec: 253 FREE (command); 254 255 if (subshell_environment || (interactive == 0 && no_exit_on_failed_exec == 0)) 256 exit_shell (exit_value); 257 258 if (args) 259 strvec_dispose (args); 260 261 if (env && env != export_env) 262 strvec_dispose (env); 263 264 initialize_traps (); 265 initialize_signals (1); 266 267#if defined (JOB_CONTROL) 268 if (orig_job_control) 269 restart_job_control (); 270#endif /* JOB_CONTROL */ 271 272 return (exit_value); 273} 274