On Fri, Aug 13, 2010 at 12:18:23PM +0200, Werner Fink wrote:
> On Thu, Aug 12, 2010 at 05:37:55PM -0500, lstee...@gmail.com wrote:
> > #!/bin/bash
> > #
> > # A script to test PIPESTATUS and pipefail
> > #
> > echo "   cmd: set +o pipefail"
> > echo "  pipe: ps -ef 2>&1 | grep "^\$USR" >/dev/null"
> > set +o pipefail
> > ps -ef 2>&1 | grep "^$USR" >/dev/null
> > echo "expect: PIPESTATUS = 1 0 \$? = 0; got: PIPESTATUS = ${PIPESTATUS[*]} 
> > \$? = $?"
> > echo
> > echo "   cmd: set -o pipefail"
> > echo "  pipe: ps -ef 2>&1 | grep "^\$USR" >/dev/null"
> > set -o pipefail
> > ps -ef 2>&1 | grep "^$USR" >/dev/null
> > echo "expect: PIPESTATUS = 1 0 \$? = 1; got: PIPESTATUS = ${PIPESTATUS[*]} 
> > \$? = $?"
> > echo
> > echo "  pipe: ps aux 2>&1 | grep "^\$USER" >/dev/null"
> > ps aux 2>&1 | grep "^$USER" >/dev/null
> > echo "expect: PIPESTATUS = 0 0 \$? = 0; got: PIPESTATUS = ${PIPESTATUS[*]} 
> > \$? = $?"
> > echo "expect: PIPESTATUS = 0 \$? = 0; got: PIPESTATUS = ${PIPESTATUS[*]} 
> > \$? = $?"
> > #
> > # End of script
> > 
> > None of the 'got' results 'expect'ing multiple PIPESTATUS results work.
> 
> Question: could it be that you're using the bash from
> http://download.opensuse.org/repositories/shells/ or
> http://download.opensuse.org/factory/ ?
> 
> Then you may see a side effect of the patch enabling that a pipe uses
> only subshells left from that last pipe symbol.  This makes things
> work like
> 
>  bash> echo 1 2 | read a b; echo $a $b
>  1 2
> 
> ... please report such problems on the channels for opensuse.org.
> 
> Sorry Chet for the noise

The attached patch should do a better job, nevertheless IMHO there
could be a better solution.  This could require some more work
on the COMMAND API to avoid things like

         add_process((char*)0, getpid());

in execute_cmd.c, also the addjstatus() function is more like
a workaround to get the status back into the JOB/PROCESS API. 


   Werner

-- 
  "Having a smoking section in a restaurant is like having
          a peeing section in a swimming pool." -- Edward Burr
--- command.h
+++ command.h	2010-08-13 16:48:35.739125676 +0200
@@ -168,6 +168,7 @@ typedef struct element {
 #define CMD_STDIN_REDIR	   0x400 /* async command needs implicit </dev/null */
 #define CMD_COMMAND_BUILTIN 0x0800 /* command executed by `command' builtin */
 #define CMD_COPROC_SUBSHELL 0x1000
+#define CMD_SYNC_PIPE       0x2000
 
 /* What a command looks like. */
 typedef struct command {
--- execute_cmd.c
+++ execute_cmd.c	2010-08-16 15:40:41.975126155 +0200
@@ -256,6 +256,8 @@ int match_ignore_case = 0;
 
 struct stat SB;		/* used for debugging */
 
+extern void addjstatus(COMMAND *, int);
+
 static int special_builtin_failed;
 
 static COMMAND *currently_executing_command;
@@ -1525,7 +1527,7 @@ static struct cpelement *cpl_search __P(
 static struct cpelement *cpl_searchbyname __P((char *));
 static void cpl_prune __P((void));
 
-Coproc sh_coproc = { 0, NO_PID, -1, -1, 0, 0 };
+Coproc sh_coproc = { 0, NO_PID, -1, -1, 0, 0, 0, 0 };
 
 cplist_t coproc_list = {0, 0, 0};
 
@@ -2047,13 +2049,19 @@ execute_coproc (command, pipe_in, pipe_o
 }
 #endif
 
+static void restore_stdin(int lstdin)
+{
+  dup2(lstdin, 0);
+  close(lstdin);
+}
+
 static int
 execute_pipeline (command, asynchronous, pipe_in, pipe_out, fds_to_close)
      COMMAND *command;
      int asynchronous, pipe_in, pipe_out;
      struct fd_bitmap *fds_to_close;
 {
-  int prev, fildes[2], new_bitmap_size, dummyfd, ignore_return, exec_result;
+  int lstdin, prev, fildes[2], new_bitmap_size, dummyfd, ignore_return, exec_result;
   COMMAND *cmd;
   struct fd_bitmap *fd_bitmap;
 
@@ -2148,15 +2156,52 @@ execute_pipeline (command, asynchronous,
   /* Now execute the rightmost command in the pipeline.  */
   if (ignore_return && cmd)
     cmd->flags |= CMD_IGNORE_RETURN;
+
+  begin_unwind_frame ("pipe-file-descriptors");
+  lstdin = -1;
+#if 1
+  if (!asynchronous && pipe_out == NO_PIPE && prev > 0
+      && cmd->type != cm_subshell && ((cmd->flags & CMD_WANT_SUBSHELL) == 0))
+    {
+      lstdin = move_to_high_fd(0, 0, 255);
+      if (lstdin > 0)
+	{
+	  dup2(prev, 0);
+	  close(prev);
+	  prev = NO_PIPE;
+	  cmd->flags |= CMD_SYNC_PIPE;
+	  add_process((char*)0, getpid());
+	  stop_pipeline (0, cmd);
+	  add_unwind_protect (restore_stdin, lstdin);
+	}
+    }
+#endif
+  if (prev >= 0)
+    add_unwind_protect (close, prev);
+
   exec_result = execute_command_internal (cmd, asynchronous, prev, pipe_out, fds_to_close);
 
+  if (lstdin > 0)
+    {
+      dup2(lstdin, 0);
+      close(lstdin);
+    }
+
   if (prev >= 0)
     close (prev);
 
+  discard_unwind_frame ("pipe-file-descriptors");
+
 #if defined (JOB_CONTROL)
   UNBLOCK_CHILD (oset);
 #endif
 
+  if (cmd->flags & CMD_SYNC_PIPE)
+    {
+      addjstatus(cmd, exec_result);
+      cmd->flags &= ~CMD_SYNC_PIPE;
+    }
+
   QUIT;
   return (exec_result);
 }
--- jobs.c
+++ jobs.c	2010-08-16 15:48:19.479125702 +0200
@@ -260,7 +260,6 @@ static int processes_in_job __P((int));
 static void realloc_jobs_list __P((void));
 static int compact_jobs_list __P((int));
 static int discard_pipeline __P((PROCESS *));
-static void add_process __P((char *, pid_t));
 static void print_pipeline __P((PROCESS *, int, int, FILE *));
 static void pretty_print_job __P((int, int, FILE *));
 static void set_current_job __P((int));
@@ -1065,7 +1064,7 @@ nohup_job (job_index)
   if (js.j_jobslots == 0)
     return;
 
-  if (temp = jobs[job_index])
+  if ((temp = jobs[job_index]))
     temp->flags |= J_NOHUP;
 }
 
@@ -1095,7 +1094,7 @@ discard_pipeline (chain)
 /* Add this process to the chain being built in the_pipeline.
    NAME is the command string that will be exec'ed later.
    PID is the process id of the child. */
-static void
+void
 add_process (name, pid)
      char *name;
      pid_t pid;
@@ -3396,6 +3395,34 @@ setjstatus (j)
 #endif
 }
 
+
+void
+addjstatus(COMMAND *deferred, int status)
+{
+#if defined (ARRAY_VARS)
+  int i;
+  JOB *j;
+  for (j = jobs[(i = 0)]; j && j->deferred != deferred; j = jobs[(++i)])
+    ;
+  if (!j || !j->deferred)
+    return;
+  j->deferred = (COMMAND*)0;
+  if (status)
+    {
+      PROCESS *p, *l;
+      p = j->pipe;
+      do
+	{
+	  l = p;
+	  p = p->next;
+	}
+      while (p != j->pipe);
+      l->status = status << 8;
+    }
+  setjstatus(i);
+#endif
+}
+
 void
 run_sigchld_trap (nchild)
      int nchild;
--- jobs.h
+++ jobs.h	2010-08-16 15:47:22.463125472 +0200
@@ -177,6 +177,8 @@ extern void save_pipeline __P((int));
 extern void restore_pipeline __P((int));
 extern void start_pipeline __P((void));
 extern int stop_pipeline __P((int, COMMAND *));
+extern void add_process __P((char *, pid_t));
+extern void addjstatus __P((COMMAND *, int));
 
 extern void delete_job __P((int, int));
 extern void nohup_job __P((int));

Reply via email to