]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
stdio: Do not ignore posix_spawn error on popen (BZ #29016)
authorAdhemerval Zanella <adhemerval.zanella@linaro.org>
Tue, 6 Dec 2022 16:28:40 +0000 (13:28 -0300)
committerAdhemerval Zanella <adhemerval.zanella@linaro.org>
Tue, 14 Feb 2023 18:30:35 +0000 (15:30 -0300)
To correctly return error in case of default shell is not present.

Checked on x86_64-linux-gnu.

libio/iopopen.c
stdio-common/Makefile
stdio-common/tst-popen3.c [new file with mode: 0644]

index 10b0503c23be3087c357e6614f6a23605decce97..d0545ad5eae1ecfb1ca2601146b305c05cd1dcbd 100644 (file)
@@ -66,11 +66,12 @@ unlock (void *not_used)
    be close (by transversing the proc_file_chain list) and the insertion of a
    new one after a successful posix_spawn this function should be called
    with proc_file_chain_lock acquired.  */
-static bool
+static int
 spawn_process (posix_spawn_file_actions_t *fa, FILE *fp, const char *command,
               int do_cloexec, int pipe_fds[2], int parent_end, int child_end,
               int child_pipe_fd)
 {
+  int err = 0;
 
   for (struct _IO_proc_file *p = proc_file_chain; p; p = p->next)
     {
@@ -79,15 +80,19 @@ spawn_process (posix_spawn_file_actions_t *fa, FILE *fp, const char *command,
       /* If any stream from previous popen() calls has fileno
         child_pipe_fd, it has been already closed by the adddup2 action
         above.  */
-      if (fd != child_pipe_fd
-         && __posix_spawn_file_actions_addclose (fa, fd) != 0)
-       return false;
+      if (fd != child_pipe_fd)
+       {
+         err = __posix_spawn_file_actions_addclose (fa, fd);
+         if (err != 0)
+           return err;
+       }
     }
 
-  if (__posix_spawn (&((_IO_proc_file *) fp)->pid, _PATH_BSHELL, fa, 0,
-                    (char *const[]){ (char*) "sh", (char*) "-c",
-                    (char *) command, NULL }, __environ) != 0)
-    return false;
+  err = __posix_spawn (&((_IO_proc_file *) fp)->pid, _PATH_BSHELL, fa, 0,
+                      (char *const[]){ (char*) "sh", (char*) "-c",
+                      (char *) command, NULL }, __environ);
+  if (err != 0)
+    return err;
 
   __close_nocancel (pipe_fds[child_end]);
 
@@ -101,7 +106,7 @@ spawn_process (posix_spawn_file_actions_t *fa, FILE *fp, const char *command,
   ((_IO_proc_file *) fp)->next = proc_file_chain;
   proc_file_chain = (_IO_proc_file *) fp;
 
-  return true;
+  return 0;
 }
 
 FILE *
@@ -112,7 +117,7 @@ _IO_new_proc_open (FILE *fp, const char *command, const char *mode)
   int parent_end, child_end;
   int pipe_fds[2];
   int child_pipe_fd;
-  bool spawn_ok;
+  int err;
 
   int do_read = 0;
   int do_write = 0;
@@ -185,16 +190,17 @@ _IO_new_proc_open (FILE *fp, const char *command, const char *mode)
       pipe_fds[child_end] = tmp;
     }
 
-  if (__posix_spawn_file_actions_adddup2 (&fa, pipe_fds[child_end],
-      child_pipe_fd) != 0)
+  err = __posix_spawn_file_actions_adddup2 (&fa, pipe_fds[child_end],
+                                           child_pipe_fd);
+  if (err != 0)
     goto spawn_failure;
 
 #ifdef _IO_MTSAFE_IO
   _IO_cleanup_region_start_noarg (unlock);
   _IO_lock_lock (proc_file_chain_lock);
 #endif
-  spawn_ok = spawn_process (&fa, fp, command, do_cloexec, pipe_fds,
-                           parent_end, child_end, child_pipe_fd);
+  err = spawn_process (&fa, fp, command, do_cloexec, pipe_fds, parent_end,
+                      child_end, child_pipe_fd);
 #ifdef _IO_MTSAFE_IO
   _IO_lock_unlock (proc_file_chain_lock);
   _IO_cleanup_region_end (0);
@@ -202,12 +208,12 @@ _IO_new_proc_open (FILE *fp, const char *command, const char *mode)
 
   __posix_spawn_file_actions_destroy (&fa);
 
-  if (!spawn_ok)
+  if (err != 0)
     {
+      __set_errno (err);
     spawn_failure:
       __close_nocancel (pipe_fds[child_end]);
       __close_nocancel (pipe_fds[parent_end]);
-      __set_errno (ENOMEM);
       return NULL;
     }
 
index 652d9e5f95f909119dfa3a07b4a2b30b7a5ef873..92a3499a94c8678a10256c411be6eefccee44843 100644 (file)
@@ -238,6 +238,9 @@ tests := \
   xbug \
   # tests
 
+tests-container += \
+  tst-popen3
+
 generated += \
   errlist-data-aux-shared.S \
   errlist-data-aux.S \
diff --git a/stdio-common/tst-popen3.c b/stdio-common/tst-popen3.c
new file mode 100644 (file)
index 0000000..add5e97
--- /dev/null
@@ -0,0 +1,38 @@
+/* Check if popen return a correct error code if the default shell does not
+   exists (BZ#29016).
+
+   Copyright (C) 2022 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <paths.h>
+#include <stdio.h>
+#include <errno.h>
+#include <support/check.h>
+#include <support/xunistd.h>
+
+int
+do_test (void)
+{
+  xunlink (_PATH_BSHELL);
+
+  FILE *f = popen ("/non-existent", "r");
+  TEST_VERIFY (f == NULL);
+  TEST_COMPARE (errno, ENOENT);
+  return 0;
+}
+
+#include <support/test-driver.c>