diff options
Diffstat (limited to 'builtins/evalstring.c')
-rw-r--r-- | builtins/evalstring.c | 123 |
1 files changed, 122 insertions, 1 deletions
diff --git a/builtins/evalstring.c b/builtins/evalstring.c index 1a22887d..0063b711 100644 --- a/builtins/evalstring.c +++ b/builtins/evalstring.c @@ -19,12 +19,18 @@ #include <config.h> #if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif # include <unistd.h> #endif #include <stdio.h> #include <signal.h> +#include <errno.h> + +#include "../filecntl.h" #include "../bashansi.h" #include "../shell.h" @@ -33,6 +39,7 @@ #include "../flags.h" #include "../input.h" #include "../execute_cmd.h" +#include "../redir.h" #if defined (HISTORY) # include "../bashhist.h" @@ -40,6 +47,10 @@ #include "common.h" +#if !defined (errno) +extern int errno; +#endif + extern void run_trap_cleanup (); extern int interactive, interactive_shell; @@ -47,10 +58,13 @@ extern int indirection_level, startup_state, subshell_environment; extern int line_number; extern int last_command_exit_value; extern int running_trap; +extern int posixly_correct; extern COMMAND *global_command; int parse_and_execute_level = 0; +static int cat_file (); + /* How to force parse_and_execute () to clean up after itself. */ void parse_and_execute_cleanup () @@ -202,7 +216,23 @@ parse_and_execute (string, from_file, flags) } #endif /* ONESHOT */ - last_result = execute_command_internal + /* See if this is a candidate for $( <file ). */ + if (startup_state == 2 && + subshell_environment == SUBSHELL_COMSUB && + *bash_input.location.string == '\0' && + command->type == cm_simple && !command->redirects && + (command->flags & CMD_TIME_PIPELINE) == 0 && + command->value.Simple->words == 0 && + command->value.Simple->redirects && + command->value.Simple->redirects->next == 0 && + command->value.Simple->redirects->instruction == r_input_direction) + { + int r; + r = cat_file (command->value.Simple->redirects); + last_result = (r < 0) ? EXECUTION_FAILURE : EXECUTION_SUCCESS; + } + else + last_result = execute_command_internal (command, 0, NO_PIPE, NO_PIPE, bitmap); dispose_command (command); @@ -238,3 +268,94 @@ parse_and_execute (string, from_file, flags) return (last_result); } + +/* Write NB bytes from BUF to file descriptor FD, retrying the write if + it is interrupted. We retry three times if we get a zero-length + write. Any other signal causes this function to return prematurely. */ +static int +zwrite (fd, buf, nb) + int fd; + unsigned char *buf; + int nb; +{ + int n, i, nt; + + for (n = nb, nt = 0;;) + { + i = write (fd, buf, n); + if (i > 0) + { + n -= i; + if (n <= 0) + return nb; + } + else if (i == 0) + { + if (++nt > 3) + return (nb - n); + } + else if (errno != EINTR) + return -1; + } +} + +/* Handle a $( < file ) command substitution. This expands the filename, + returning errors as appropriate, then just cats the file to the standard + output. */ +static int +cat_file (r) + REDIRECT *r; +{ + char lbuf[128], *fn; + int nr, fd, rval; + + if (r->instruction != r_input_direction) + return -1; + + /* Get the filename. */ + if (posixly_correct && !interactive_shell) + disallow_filename_globbing++; + fn = redirection_expand (r->redirectee.filename); + if (posixly_correct && !interactive_shell) + disallow_filename_globbing--; + + if (fn == 0) + { + redirection_error (r, AMBIGUOUS_REDIRECT); + return -1; + } + + fd = open(fn, O_RDONLY); + if (fd < 0) + { + file_error (fn); + free (fn); + return -1; + } + + rval = 0; + while (1) + { + /* Retry the reads on EINTR. Any other error causes a break from the + loop. */ + while ((nr = read (fd, lbuf, sizeof(lbuf))) < 0 && errno == EINTR) + ; + if (nr == 0) + break; + else if (nr < 0) + { + rval = -1; + break; + } + if (zwrite (1, lbuf, nr) < 0) + { + rval = -1; + break; + } + } + + free (fn); + close (fd); + + return (0); +} |