📄 execute_cmd.c
字号:
/* execute_cmd.c -- Execute a COMMAND structure. *//* Copyright (C) 1987-2010 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. Bash is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Bash is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Bash. If not, see <http://www.gnu.org/licenses/>.*/#include "config.h"#if !defined (__GNUC__) && !defined (HAVE_ALLOCA_H) && defined (_AIX) #pragma alloca#endif /* _AIX && RISC6000 && !__GNUC__ */#include <stdio.h>#include "chartypes.h"#include "bashtypes.h"#if !defined (_MINIX) && defined (HAVE_SYS_FILE_H)# include <sys/file.h>#endif#include "filecntl.h"#include "posixstat.h"#include <signal.h>#ifndef _MINIX# include <sys/param.h>#endif#if defined (HAVE_UNISTD_H)# include <unistd.h>#endif#include "posixtime.h"#if defined (HAVE_SYS_RESOURCE_H) && !defined (RLIMTYPE)# include <sys/resource.h>#endif#if defined (HAVE_SYS_TIMES_H) && defined (HAVE_TIMES)# include <sys/times.h>#endif#include <errno.h>#if !defined (errno)extern int errno;#endif#define NEED_FPURGE_DECL#include "bashansi.h"#include "bashintl.h"#include "memalloc.h"#include "shell.h"#include <y.tab.h> /* use <...> so we pick it up from the build directory */#include "flags.h"#include "builtins.h"#include "hashlib.h"#include "jobs.h"#include "execute_cmd.h"#include "findcmd.h"#include "redir.h"#include "trap.h"#include "pathexp.h"#include "hashcmd.h"#if defined (COND_COMMAND)# include "test.h"#endif#include "builtins/common.h"#include "builtins/builtext.h" /* list of builtins */#include <glob/strmatch.h>#include <tilde/tilde.h>#if defined (BUFFERED_INPUT)# include "input.h"#endif#if defined (ALIAS)# include "alias.h"#endif#if defined (HISTORY)# include "bashhist.h"#endifextern int dollar_dollar_pid;extern int posixly_correct;extern int expand_aliases;extern int autocd;extern int breaking, continuing, loop_level;extern int parse_and_execute_level, running_trap, sourcelevel;extern int command_string_index, line_number;extern int dot_found_in_search;extern int already_making_children;extern int tempenv_assign_error;extern char *the_printed_command, *shell_name;extern pid_t last_command_subst_pid;extern sh_builtin_func_t *last_shell_builtin, *this_shell_builtin;extern char **subshell_argv, **subshell_envp;extern int subshell_argc;extern time_t shell_start_time;#if 0extern char *glob_argv_flags;#endifextern int close __P((int));/* Static functions defined and used in this file. */static void close_pipes __P((int, int));static void do_piping __P((int, int));static void bind_lastarg __P((char *));static int shell_control_structure __P((enum command_type));static void cleanup_redirects __P((REDIRECT *));#if defined (JOB_CONTROL)static int restore_signal_mask __P((sigset_t *));#endifstatic void async_redirect_stdin __P((void));static int builtin_status __P((int));static int execute_for_command __P((FOR_COM *));#if defined (SELECT_COMMAND)static int displen __P((const char *));static int print_index_and_element __P((int, int, WORD_LIST *));static void indent __P((int, int));static void print_select_list __P((WORD_LIST *, int, int, int));static char *select_query __P((WORD_LIST *, int, char *, int));static int execute_select_command __P((SELECT_COM *));#endif#if defined (DPAREN_ARITHMETIC)static int execute_arith_command __P((ARITH_COM *));#endif#if defined (COND_COMMAND)static int execute_cond_node __P((COND_COM *));static int execute_cond_command __P((COND_COM *));#endif#if defined (COMMAND_TIMING)static int mkfmt __P((char *, int, int, time_t, int));static void print_formatted_time __P((FILE *, char *, time_t, int, time_t, int, time_t, int, int));static int time_command __P((COMMAND *, int, int, int, struct fd_bitmap *));#endif#if defined (ARITH_FOR_COMMAND)static intmax_t eval_arith_for_expr __P((WORD_LIST *, int *));static int execute_arith_for_command __P((ARITH_FOR_COM *));#endifstatic int execute_case_command __P((CASE_COM *));static int execute_while_command __P((WHILE_COM *));static int execute_until_command __P((WHILE_COM *));static int execute_while_or_until __P((WHILE_COM *, int));static int execute_if_command __P((IF_COM *));static int execute_null_command __P((REDIRECT *, int, int, int));static void fix_assignment_words __P((WORD_LIST *));static int execute_simple_command __P((SIMPLE_COM *, int, int, int, struct fd_bitmap *));static int execute_builtin __P((sh_builtin_func_t *, WORD_LIST *, int, int));static int execute_function __P((SHELL_VAR *, WORD_LIST *, int, struct fd_bitmap *, int, int));static int execute_builtin_or_function __P((WORD_LIST *, sh_builtin_func_t *, SHELL_VAR *, REDIRECT *, struct fd_bitmap *, int));static void execute_subshell_builtin_or_function __P((WORD_LIST *, REDIRECT *, sh_builtin_func_t *, SHELL_VAR *, int, int, int, struct fd_bitmap *, int));static int execute_disk_command __P((WORD_LIST *, REDIRECT *, char *, int, int, int, struct fd_bitmap *, int));static char *getinterp __P((char *, int, int *));static void initialize_subshell __P((void));static int execute_in_subshell __P((COMMAND *, int, int, int, struct fd_bitmap *));#if defined (COPROCESS_SUPPORT)static int execute_coproc __P((COMMAND *, int, int, struct fd_bitmap *));#endifstatic int execute_pipeline __P((COMMAND *, int, int, int, struct fd_bitmap *));static int execute_connection __P((COMMAND *, int, int, int, struct fd_bitmap *));static int execute_intern_function __P((WORD_DESC *, COMMAND *));/* Set to 1 if fd 0 was the subject of redirection to a subshell. Global so that reader_loop can set it to zero before executing a command. */int stdin_redir;/* The name of the command that is currently being executed. `test' needs this, for example. */char *this_command_name;/* The printed representation of the currently-executing command (same as the_printed_command), except when a trap is being executed. Useful for a debugger to know where exactly the program is currently executing. */char *the_printed_command_except_trap;/* For catching RETURN in a function. */int return_catch_flag;int return_catch_value;procenv_t return_catch;/* The value returned by the last synchronous command. */int last_command_exit_value;/* Whether or not the last command (corresponding to last_command_exit_value) was terminated by a signal, and, if so, which one. */int last_command_exit_signal;/* The list of redirections to perform which will undo the redirections that I made in the shell. */REDIRECT *redirection_undo_list = (REDIRECT *)NULL;/* The list of redirections to perform which will undo the internal redirections performed by the `exec' builtin. These are redirections that must be undone even when exec discards redirection_undo_list. */REDIRECT *exec_redirection_undo_list = (REDIRECT *)NULL;/* When greater than zero, value is the `level' of builtins we are currently executing (e.g. `eval echo a' would have it set to 2). */int executing_builtin = 0;/* Non-zero if we are executing a command list (a;b;c, etc.) */int executing_list = 0;/* Non-zero if failing commands in a command substitution should not exit the shell even if -e is set. Used to pass the CMD_IGNORE_RETURN flag down to commands run in command substitutions by parse_and_execute. */int comsub_ignore_return = 0;/* Non-zero if we have just forked and are currently running in a subshell environment. */int subshell_environment;/* Count of nested subshells, like SHLVL. Available via $BASH_SUBSHELL */int subshell_level = 0;/* Currently-executing shell function. */SHELL_VAR *this_shell_function;/* If non-zero, matches in case and [[ ... ]] are case-insensitive */int match_ignore_case = 0;int executing_command_builtin = 0;struct stat SB; /* used for debugging */static int special_builtin_failed;static COMMAND *currently_executing_command;/* The line number that the currently executing function starts on. */static int function_line_number;/* XXX - set to 1 if we're running the DEBUG trap and we want to show the line number containing the function name. Used by executing_line_number to report the correct line number. Kind of a hack. */static int showing_function_line;static int line_number_for_err_trap;/* A sort of function nesting level counter */int funcnest = 0;int funcnest_max = 0; /* XXX - bash-4.2 */int lastpipe_opt = 0;struct fd_bitmap *current_fds_to_close = (struct fd_bitmap *)NULL;#define FD_BITMAP_DEFAULT_SIZE 32/* Functions to allocate and deallocate the structures used to pass information from the shell to its children about file descriptors to close. */struct fd_bitmap *new_fd_bitmap (size) int size;{ struct fd_bitmap *ret; ret = (struct fd_bitmap *)xmalloc (sizeof (struct fd_bitmap)); ret->size = size; if (size) { ret->bitmap = (char *)xmalloc (size); memset (ret->bitmap, '\0', size); } else ret->bitmap = (char *)NULL; return (ret);}voiddispose_fd_bitmap (fdbp) struct fd_bitmap *fdbp;{ FREE (fdbp->bitmap); free (fdbp);}voidclose_fd_bitmap (fdbp) struct fd_bitmap *fdbp;{ register int i; if (fdbp) { for (i = 0; i < fdbp->size; i++) if (fdbp->bitmap[i]) { close (i); fdbp->bitmap[i] = 0; } }}/* Return the line number of the currently executing command. */intexecuting_line_number (){ if (executing && showing_function_line == 0 && (variable_context == 0 || interactive_shell == 0) && currently_executing_command) {#if defined (COND_COMMAND) if (currently_executing_command->type == cm_cond) return currently_executing_command->value.Cond->line;#endif#if defined (DPAREN_ARITHMETIC) else if (currently_executing_command->type == cm_arith) return currently_executing_command->value.Arith->line;#endif#if defined (ARITH_FOR_COMMAND) else if (currently_executing_command->type == cm_arith_for) return currently_executing_command->value.ArithFor->line;#endif return line_number; } else return line_number;}/* Execute the command passed in COMMAND. COMMAND is exactly what read_command () places into GLOBAL_COMMAND. See "command.h" for the details of the command structure. EXECUTION_SUCCESS or EXECUTION_FAILURE are the only possible return values. Executing a command with nothing in it returns EXECUTION_SUCCESS. */intexecute_command (command) COMMAND *command;{ struct fd_bitmap *bitmap; int result; current_fds_to_close = (struct fd_bitmap *)NULL; bitmap = new_fd_bitmap (FD_BITMAP_DEFAULT_SIZE); begin_unwind_frame ("execute-command"); add_unwind_protect (dispose_fd_bitmap, (char *)bitmap); /* Just do the command, but not asynchronously. */ result = execute_command_internal (command, 0, NO_PIPE, NO_PIPE, bitmap); dispose_fd_bitmap (bitmap); discard_unwind_frame ("execute-command");#if defined (PROCESS_SUBSTITUTION) /* don't unlink fifos if we're in a shell function; wait until the function returns. */ if (variable_context == 0) unlink_fifo_list ();#endif /* PROCESS_SUBSTITUTION */ QUIT; return (result);}/* Return 1 if TYPE is a shell control structure type. */static intshell_control_structure (type) enum command_type type;{ switch (type) {#if defined (ARITH_FOR_COMMAND) case cm_arith_for:#endif#if defined (SELECT_COMMAND) case cm_select:#endif#if defined (DPAREN_ARITHMETIC) case cm_arith:#endif#if defined (COND_COMMAND) case cm_cond:#endif case cm_case: case cm_while: case cm_until: case cm_if: case cm_for: case cm_group: case cm_function_def: return (1); default: return (0); }}/* A function to use to unwind_protect the redirection undo list for loops. */static voidcleanup_redirects (list) REDIRECT *list;{ do_redirections (list, RX_ACTIVE); dispose_redirects (list);}#if 0/* Function to unwind_protect the redirections for functions and builtins. */static voidcleanup_func_redirects (list) REDIRECT *list;{ do_redirections (list, RX_ACTIVE);}#endifvoiddispose_exec_redirects (){ if (exec_redirection_undo_list) { dispose_redirects (exec_redirection_undo_list); exec_redirection_undo_list = (REDIRECT *)NULL; }}#if defined (JOB_CONTROL)/* A function to restore the signal mask to its proper value when the shell is interrupted or errors occur while creating a pipeline. */static intrestore_signal_mask (set) sigset_t *set;{ return (sigprocmask (SIG_SETMASK, set, (sigset_t *)NULL));}#endif /* JOB_CONTROL */#ifdef DEBUG/* A debugging function that can be called from gdb, for instance. */void
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -