diff -up -rpu10 bash-3.0.orig/config.h.in bash-3.0/config.h.in --- bash-3.0.orig/config.h.in 2004-07-21 13:08:31.000000000 -0700 +++ bash-3.0/config.h.in 2005-07-16 00:30:18.146731600 -0700 @@ -600,20 +600,23 @@ /* Define if you have the pathconf function. */ #undef HAVE_PATHCONF /* Define if you have the putenv function. */ #undef HAVE_PUTENV /* Define if you have the readlink function. */ #undef HAVE_READLINK +/* Define if you have the spawnve function. */ +#undef HAVE_SPAWNVE + /* Define if you have the regcomp function. */ #undef HAVE_REGCOMP /* Define if you have the regexec function. */ #undef HAVE_REGEXEC /* Define if you have the rename function. */ #undef HAVE_RENAME /* Define if you have the sbrk function. */ @@ -926,20 +929,23 @@ /* Define if you have the header file. */ #undef HAVE_FCNTL_H /* Define if you have the header file. */ #undef HAVE_MALLOC_H /* Define if you have the header file. */ #undef HAVE_STDIO_EXT_H +/* Define if you have the header file. */ +#undef HAVE_PROCESS_H + /* Define if you have the `dcgettext' function. */ #undef HAVE_DCGETTEXT /* Define if your system has a working `malloc' function. */ /* #undef HAVE_MALLOC */ /* Define if you have the `mempcpy' function. */ #undef HAVE_MEMPCPY /* Define if you have a working `mmap' system call. */ diff -up -rpu10 bash-3.0.orig/configure.in bash-3.0/configure.in --- bash-3.0.orig/configure.in 2004-07-21 13:06:54.000000000 -0700 +++ bash-3.0/configure.in 2005-07-16 00:25:40.756171300 -0700 @@ -566,21 +566,21 @@ dnl initialize GNU gettext AM_GNU_GETTEXT([no-libtool], [need-ngettext], [lib/intl]) dnl header files AC_HEADER_DIRENT AC_HEADER_TIME BASH_HEADER_INTTYPES AC_CHECK_HEADERS(unistd.h stdlib.h stdarg.h varargs.h limits.h string.h \ memory.h locale.h termcap.h termio.h termios.h dlfcn.h \ - stddef.h stdint.h netdb.h grp.h strings.h regex.h) + stddef.h stdint.h netdb.h grp.h strings.h regex.h process.h) AC_CHECK_HEADERS(sys/ptem.h sys/pte.h sys/stream.h sys/select.h sys/file.h \ sys/resource.h sys/param.h sys/socket.h sys/stat.h \ sys/time.h sys/times.h sys/types.h sys/wait.h) AC_CHECK_HEADERS(netinet/in.h arpa/inet.h) dnl special checks for libc functions AC_FUNC_ALLOCA AC_FUNC_GETPGRP AC_FUNC_SETVBUF_REVERSED AC_FUNC_VPRINTF @@ -621,21 +621,21 @@ AC_CHECK_FUNC(__setostype, AC_DEFINE(HAV AC_CHECK_FUNC(wait3, AC_DEFINE(HAVE_WAIT3)) AC_CHECK_FUNC(isinf, AC_DEFINE(HAVE_ISINF_IN_LIBC)) dnl checks for missing libc functions AC_CHECK_FUNC(mkfifo,AC_DEFINE(HAVE_MKFIFO),AC_DEFINE(MKFIFO_MISSING)) dnl checks for system calls AC_CHECK_FUNCS(dup2 select getdtablesize getgroups gethostname \ setdtablesize getpagesize killpg lstat getpeername sbrk \ getrlimit getrusage gettimeofday waitpid tcgetpgrp \ - readlink) + readlink spawnve) AC_REPLACE_FUNCS(rename) dnl checks for c library functions AC_CHECK_FUNCS(bcopy bzero confstr sysconf pathconf setenv putenv unsetenv \ setlinebuf setvbuf setlocale strchr tcgetattr uname \ ulimit tzset siginterrupt memmove ttyname times \ getaddrinfo gethostbyname getservbyname getservent inet_aton \ vsnprintf snprintf vasprintf asprintf fnmatch regcomp regexec) AC_CHECK_FUNCS(isascii isblank isgraph isprint isspace isxdigit) AC_REPLACE_FUNCS(getcwd strcasecmp strerror strftime strpbrk memset strstr) diff -up -rpu10 bash-3.0.orig/execute_cmd.c bash-3.0/execute_cmd.c --- bash-3.0.orig/execute_cmd.c 2004-07-04 11:12:58.000000000 -0700 +++ bash-3.0/execute_cmd.c 2005-07-16 00:34:51.692799100 -0700 @@ -167,21 +167,21 @@ static int execute_builtin __P((sh_built 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 void execute_disk_command __P((WORD_LIST *, REDIRECT *, char *, +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 *)); static int execute_pipeline __P((COMMAND *, int, int, int, struct fd_bitmap *)); static int execute_connection __P((COMMAND *, int, int, int, struct fd_bitmap *)); @@ -2974,22 +2974,22 @@ execute_simple_command (simple_command, set_pipestatus_from_exit (result); goto return_result; } } if (command_line == 0) command_line = savestring (the_printed_command); - execute_disk_command (words, simple_command->redirects, command_line, - pipe_in, pipe_out, async, fds_to_close, + result = execute_disk_command (words, simple_command->redirects, + command_line, pipe_in, pipe_out, async, fds_to_close, simple_command->flags); return_result: bind_lastarg (lastarg); FREE (command_line); dispose_words (words); discard_unwind_frame ("simple-command"); this_command_name = (char *)NULL; /* points to freed memory now */ return (result); } @@ -3499,67 +3499,96 @@ setup_async_signals () 6) If the execve failed, see if the file has executable mode set. If so, and it isn't a directory, then execute its contents as a shell script. Note that the filename hashing stuff has to take place up here, in the parent. This is probably why the Bourne style shells don't handle it, since that would require them to go through this gnarly hair, for no good reason. NOTE: callers expect this to fork or exit(). */ -static void +static int execute_disk_command (words, redirects, command_line, pipe_in, pipe_out, async, fds_to_close, cmdflags) WORD_LIST *words; REDIRECT *redirects; char *command_line; int pipe_in, pipe_out, async; struct fd_bitmap *fds_to_close; int cmdflags; { char *pathname, *command, **args; - int nofork; + int nofork = 0; + int spawn = 0; pid_t pid; + int result = EXECUTION_SUCCESS; + + if (pipe_in == NO_PIPE && pipe_out == NO_PIPE) + { + if (cmdflags & CMD_NO_FORK) /* Don't fork, just exec, if no pipes */ + { + nofork = 1; + } +#if defined (HAVE_SPAWNVE) + else if (!async && !redirects && !job_control) + { + int i; + + spawn = 1; + + if (fds_to_close) + { + for (i = 0; i < fds_to_close->size; i++) + { + if (fds_to_close->bitmap[i]) + { + spawn = 0; + break; + } + } + } + } +#endif /* HAVE_SPAWNVE */ + } - nofork = (cmdflags & CMD_NO_FORK); /* Don't fork, just exec, if no pipes */ pathname = words->word->word; #if defined (RESTRICTED_SHELL) command = (char *)NULL; if (restricted && xstrchr (pathname, '/')) { internal_error (_("%s: restricted: cannot specify `/' in command names"), pathname); last_command_exit_value = EXECUTION_FAILURE; /* If we're not going to fork below, we must already be in a child process or a context in which it's safe to call exit(2). */ - if (nofork && pipe_in == NO_PIPE && pipe_out == NO_PIPE) + if (nofork) exit (last_command_exit_value); else goto parent_return; } #endif /* RESTRICTED_SHELL */ command = search_for_command (pathname); if (command) { maybe_make_export_env (); put_command_name_into_env (command); } /* We have to make the child before we check for the non-existence of COMMAND, since we want the error messages to be redirected. */ /* If we can get away without forking and there are no pipes to deal with, don't bother to fork, just directly exec the command. */ - if (nofork && pipe_in == NO_PIPE && pipe_out == NO_PIPE) + if (nofork || spawn) pid = 0; else pid = make_child (savestring (command_line), async); if (pid == 0) { int old_interactive; #if 0 /* This has been disabled for the time being. */ @@ -3616,32 +3645,39 @@ execute_disk_command (words, redirects, if (command == 0) { internal_error (_("%s: command not found"), pathname); exit (EX_NOTFOUND); /* Posix.2 says the exit status is 127 */ } /* Execve expects the command name to be in args[0]. So we leave it there, in the same format that the user used to type it in. */ args = strvec_from_word_list (words, 0, 0, (int *)NULL); - exit (shell_execve (command, args, export_env)); +#if defined (HAVE_SPAWNVE) + if (spawn) + result = spawn_child (command, args, export_env); + else +#endif /* HAVE_SPAWNVE */ + exit (shell_execve (command, args, export_env)); } else { parent_return: /* Make sure that the pipes are closed in the parent. */ close_pipes (pipe_in, pipe_out); #if defined (PROCESS_SUBSTITUTION) && defined (HAVE_DEV_FD) unlink_fifo_list (); #endif FREE (command); } + + return result; } /* CPP defines to decide whether a particular index into the #! line corresponds to a valid interpreter name or argument character, or whitespace. The MSDOS define is to allow \r to be treated the same as \n. */ #if !defined (MSDOS) # define STRINGCHAR(ind) \ (ind < sample_len && !whitespace (sample[ind]) && sample[ind] != '\n') diff -up -rpu10 bash-3.0.orig/jobs.c bash-3.0/jobs.c --- bash-3.0.orig/jobs.c 2004-04-23 13:28:25.000000000 -0700 +++ bash-3.0/jobs.c 2005-07-16 00:31:56.098556100 -0700 @@ -22,20 +22,24 @@ Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ #include "config.h" #include "bashtypes.h" #include "trap.h" #include #include #include +#if defined (HAVE_PROCESS_H) +# include +#endif + #if defined (HAVE_UNISTD_H) # include #endif #include "posixtime.h" #if defined (HAVE_SYS_RESOURCE_H) && defined (HAVE_WAIT3) && !defined (_POSIX_VERSION) && !defined (RLIMTYPE) # include #endif /* !_POSIX_VERSION && HAVE_SYS_RESOURCE_H && HAVE_WAIT3 && !RLIMTYPE */ @@ -1433,20 +1437,55 @@ make_child (command, async_p) last_made_pid = pid; /* Unblock SIGINT and SIGCHLD. */ sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL); } return (pid); } +#if defined (HAVE_SPAWNVE) +int +spawn_child (command, args, export_env) + char *command; + char **args; + char **export_env; +{ + sigset_t child_sig_mask; + sigset_t old_sig_mask; + pid_t pid; + int result = EXECUTION_SUCCESS; + int i; + + /* Restore top-level signal mask, with job control + * signals removed. */ + child_sig_mask = top_level_mask; + sigdelset(&child_sig_mask, SIGTSTP); + sigdelset(&child_sig_mask, SIGTTIN); + sigdelset(&child_sig_mask, SIGTTOU); + sigemptyset(&old_sig_mask); + sigprocmask (SIG_SETMASK, &top_level_mask, &old_sig_mask); + result = spawnve(_P_WAIT, command, (const char * const *) args, + (const char * const *) export_env); + i = errno; + sigprocmask (SIG_SETMASK, &old_sig_mask, (sigset_t *)NULL); + if (result == -1 && i != 0) + { + /* XXX Posix.2 says that exit status is 126 */ + result = ((i == ENOENT) ? EX_NOTFOUND : EX_NOEXEC); + } + + return (result); +} +#endif /* HAVE_SPAWNVE */ + /* These two functions are called only in child processes. */ void ignore_tty_job_signals () { set_signal_handler (SIGTSTP, SIG_IGN); set_signal_handler (SIGTTIN, SIG_IGN); set_signal_handler (SIGTTOU, SIG_IGN); } void diff -up -rpu10 bash-3.0.orig/jobs.h bash-3.0/jobs.h --- bash-3.0.orig/jobs.h 2004-03-17 05:34:15.000000000 -0800 +++ bash-3.0/jobs.h 2005-07-15 23:18:57.986648000 -0700 @@ -140,20 +140,21 @@ extern void describe_pid __P((int)); extern int get_job_by_pid __P((pid_t, int)); extern void describe_pid __P((pid_t)); #endif extern void list_one_job __P((JOB *, int, int, int)); extern void list_all_jobs __P((int)); extern void list_stopped_jobs __P((int)); extern void list_running_jobs __P((int)); extern pid_t make_child __P((char *, int)); +extern int spawn_child __P((char *, char **, char **)); extern int get_tty_state __P((void)); extern int set_tty_state __P((void)); extern int wait_for_single_pid __P((pid_t)); extern void wait_for_background_pids __P((void)); extern int wait_for __P((pid_t)); extern int wait_for_job __P((int)); extern void notify_and_cleanup __P((void));