This is an automated email from the ASF dual-hosted git repository.

xiaoxiang781216 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx-apps.git

commit 0d35e2e0bb7fb4504f864cf445b7c0ae262795b1
Author: cuiziwei <[email protected]>
AuthorDate: Tue Apr 28 17:00:56 2026 +0800

    system/popen: add dpopen/dpclose fd-based interface
    
    Add dpopen()/dpclose() as the descriptor-based counterpart of
    popen()/pclose(), analogous to how dprintf() relates to fprintf().
    dpopen() returns a raw file descriptor instead of a FILE stream,
    avoiding the stdio.h dependency for callers that only need an fd.
    
    Refactor popen() as a thin wrapper: dpopen() + fdopen() + FILE
    container.  All pipe creation and process spawning logic now lives
    in dpopen.c.
    
    Also remove the hard dependency on NSH_LIBRARY from SYSTEM_POPEN.
    When NSH is available, commands are executed through sh -c with full
    shell syntax support.  When NSH is not available, commands are split
    by whitespace and executed directly via posix_spawnp().
    
    Add CONFIG_SYSTEM_POPEN_MAXARGUMENTS (default 7) to control the
    argv array size for the no-shell path.
    
    Signed-off-by: cuiziwei <[email protected]>
---
 system/popen/CMakeLists.txt |   2 +-
 system/popen/Kconfig        |  19 ++-
 system/popen/Makefile       |   4 +-
 system/popen/dpopen.c       | 321 ++++++++++++++++++++++++++++++++++++++++++++
 system/popen/popen.c        | 298 ++++++----------------------------------
 5 files changed, 379 insertions(+), 265 deletions(-)

diff --git a/system/popen/CMakeLists.txt b/system/popen/CMakeLists.txt
index 78add77e6..353205d24 100644
--- a/system/popen/CMakeLists.txt
+++ b/system/popen/CMakeLists.txt
@@ -21,5 +21,5 @@
 # 
##############################################################################
 
 if(CONFIG_SYSTEM_POPEN)
-  target_sources(apps PRIVATE popen.c)
+  target_sources(apps PRIVATE dpopen.c popen.c)
 endif()
diff --git a/system/popen/Kconfig b/system/popen/Kconfig
index 94041b0e0..606efa032 100644
--- a/system/popen/Kconfig
+++ b/system/popen/Kconfig
@@ -4,14 +4,25 @@
 #
 
 config SYSTEM_POPEN
-       bool "popen()/pclose() Functions"
+       bool "popen()/pclose()/dpopen()/dpclose() Functions"
        default n
        select SCHED_WAITPID
        depends on NSH_LIBRARY && PIPES
        ---help---
-               Enable support for the popen() and pclose() interfaces.
-               This will support execution of NSH commands from C code with
-               pipe communications with the shell.
+               Enable support for the popen(), pclose(), dpopen(), and
+               dpclose() interfaces.
+
+               dpopen()/dpclose() are the descriptor-based counterparts
+               of popen()/pclose(), analogous to how dprintf() relates
+               to fprintf().  They return a raw file descriptor instead
+               of a FILE stream, avoiding the stdio.h dependency.
+
+               popen()/pclose() are thin wrappers around dpopen()/dpclose()
+               that additionally wrap the fd in a FILE stream.
+
+               Commands are executed through the NSH shell (sh -c command),
+               supporting full shell syntax including pipes, redirects,
+               and globbing.
 
 if SYSTEM_POPEN
 
diff --git a/system/popen/Makefile b/system/popen/Makefile
index fbd958274..7e8887de6 100644
--- a/system/popen/Makefile
+++ b/system/popen/Makefile
@@ -22,8 +22,8 @@
 
 include $(APPDIR)/Make.defs
 
-# popen()/pclose functions
+# dpopen()/dpclose() core and popen()/pclose() FILE wrappers
 
-CSRCS = popen.c
+CSRCS = dpopen.c popen.c
 
 include $(APPDIR)/Application.mk
diff --git a/system/popen/dpopen.c b/system/popen/dpopen.c
new file mode 100644
index 000000000..dd8bc9b7d
--- /dev/null
+++ b/system/popen/dpopen.c
@@ -0,0 +1,321 @@
+/****************************************************************************
+ * apps/system/popen/dpopen.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/wait.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <sched.h>
+#include <spawn.h>
+#include <debug.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#if defined(CONFIG_NET_LOCAL) && defined(CONFIG_NET_LOCAL_STREAM)
+#  include <sys/socket.h>
+#endif
+
+#include "nshlib/nshlib.h"
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: dpopen
+ *
+ * Description:
+ *   Execute a command and return a raw file descriptor connected to the
+ *   child process via a pipe, along with the child PID.
+ *
+ *   This is the descriptor-based counterpart of popen(), analogous to how
+ *   dprintf() relates to fprintf().  It avoids the FILE stream layer,
+ *   making it suitable for callers that only need a raw fd and want to
+ *   avoid the stdio.h dependency.
+ *
+ *   When NSH is available, commands are executed through the shell
+ *   (sh -c command), supporting full shell syntax.
+ *
+ * Input Parameters:
+ *   command - The command string to execute
+ *   oflag   - O_RDONLY to read child stdout, O_WRONLY to write child stdin,
+ *             O_RDWR for bidirectional socket mode
+ *   pid     - Location to return the child process ID
+ *
+ * Returned Value:
+ *   A valid file descriptor on success, or -1 on failure with errno set.
+ *
+ ****************************************************************************/
+
+int dpopen(FAR const char *command, int oflag, FAR pid_t *pid)
+{
+  struct sched_param param;
+  posix_spawnattr_t attr;
+  posix_spawn_file_actions_t file_actions;
+  FAR char *argv[4];
+  int fd[2];
+  int childfd;
+  int parentfd;
+  int errcode;
+
+  if (command == NULL || pid == NULL)
+    {
+      errno = EINVAL;
+      return -1;
+    }
+
+  /* Create a pipe or socketpair.  fd[0] refers to the read end of the
+   * pipe; fd[1] refers to the write end of the pipe.
+   */
+
+  if ((oflag & O_RDWR) == O_RDWR)
+    {
+#if defined(CONFIG_NET_LOCAL) && defined(CONFIG_NET_LOCAL_STREAM)
+      /* Create a socketpair for bidirectional communication */
+
+      if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, fd) < 0)
+        {
+          return -1;
+        }
+
+      childfd  = fd[0];
+      parentfd = fd[1];
+#else
+      errno = ENOTSUP;
+      return -1;
+#endif
+    }
+  else if (pipe2(fd, O_CLOEXEC) < 0)
+    {
+      return -1;
+    }
+  else if ((oflag & O_ACCMODE) == O_RDONLY)
+    {
+      /* Pipe is the output from the child */
+
+      childfd  = fd[1];  /* Child writes to pipe */
+      parentfd = fd[0];  /* Parent reads from pipe */
+    }
+  else if ((oflag & O_ACCMODE) == O_WRONLY)
+    {
+      /* Pipe is the input to the child */
+
+      childfd  = fd[0];  /* Child reads from pipe */
+      parentfd = fd[1];  /* Parent writes to pipe */
+    }
+  else
+    {
+      errcode = EINVAL;
+      goto errout_with_pipe;
+    }
+
+  /* Initialize attributes for task_spawn() (or posix_spawn()). */
+
+  errcode = posix_spawnattr_init(&attr);
+  if (errcode != 0)
+    {
+      goto errout_with_pipe;
+    }
+
+  errcode = posix_spawn_file_actions_init(&file_actions);
+  if (errcode != 0)
+    {
+      goto errout_with_attr;
+    }
+
+  /* Set the correct stack size and priority */
+
+  param.sched_priority = CONFIG_SYSTEM_POPEN_PRIORITY;
+  errcode = posix_spawnattr_setschedparam(&attr, &param);
+  if (errcode != 0)
+    {
+      goto errout_with_actions;
+    }
+
+#ifndef CONFIG_SYSTEM_POPEN_SHPATH
+  errcode = posix_spawnattr_setstacksize(&attr,
+                                         CONFIG_SYSTEM_POPEN_STACKSIZE);
+  if (errcode != 0)
+    {
+      goto errout_with_actions;
+    }
+#endif
+
+  /* If robin robin scheduling is enabled, then set the scheduling policy
+   * of the new task to SCHED_RR before it has a chance to run.
+   */
+
+#if CONFIG_RR_INTERVAL > 0
+  errcode = posix_spawnattr_setschedpolicy(&attr, SCHED_RR);
+  if (errcode != 0)
+    {
+      goto errout_with_actions;
+    }
+
+  errcode = posix_spawnattr_setflags(&attr,
+                                     POSIX_SPAWN_SETSCHEDPARAM |
+                                     POSIX_SPAWN_SETSCHEDULER);
+  if (errcode != 0)
+    {
+      goto errout_with_actions;
+    }
+
+#else
+  errcode = posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSCHEDPARAM);
+  if (errcode != 0)
+    {
+      goto errout_with_actions;
+    }
+
+#endif
+
+  /* Redirect child's stdin or stdout to the pipe */
+
+  if ((oflag & O_RDWR) == O_RDWR)
+    {
+      errcode = posix_spawn_file_actions_adddup2(&file_actions, childfd,
+                                                 STDIN_FILENO);
+      if (errcode != 0)
+        {
+          goto errout_with_actions;
+        }
+
+      errcode = posix_spawn_file_actions_adddup2(&file_actions, childfd,
+                                                 STDOUT_FILENO);
+      if (errcode != 0)
+        {
+          goto errout_with_actions;
+        }
+    }
+  else
+    {
+      errcode = posix_spawn_file_actions_adddup2(&file_actions, childfd,
+                   (oflag & O_ACCMODE) == O_RDONLY ?
+                   STDOUT_FILENO : STDIN_FILENO);
+      if (errcode != 0)
+        {
+          goto errout_with_actions;
+        }
+    }
+
+  /* Call task_spawn() (or posix_spawn), re-directing stdin or stdout
+   * appropriately.
+   */
+
+  argv[1] = "-c";
+  argv[2] = (FAR char *)command;
+  argv[3] = NULL;
+
+#ifdef CONFIG_SYSTEM_POPEN_SHPATH
+  argv[0] = CONFIG_SYSTEM_POPEN_SHPATH;
+  errcode = posix_spawn(pid, argv[0], &file_actions,
+                        &attr, argv, NULL);
+#else
+  *pid = task_spawn("dpopen", nsh_system, &file_actions,
+                    &attr, argv + 1, NULL);
+  if (*pid < 0)
+    {
+      errcode = -*pid;
+    }
+#endif
+
+  if (errcode != 0)
+    {
+      serr("ERROR: dpopen spawn failed: %d\n", errcode);
+      goto errout_with_pipe;
+    }
+
+  /* Free attributes and file actions */
+
+  posix_spawn_file_actions_destroy(&file_actions);
+  posix_spawnattr_destroy(&attr);
+
+  /* Close the child's end in the parent */
+
+  if (!(oflag & O_CLOEXEC))
+    {
+      ioctl(parentfd, FIONCLEX, 0);
+    }
+
+  close(childfd);
+
+  return parentfd;
+
+errout_with_actions:
+  posix_spawn_file_actions_destroy(&file_actions);
+
+errout_with_attr:
+  posix_spawnattr_destroy(&attr);
+
+errout_with_pipe:
+  close(fd[0]);
+  close(fd[1]);
+  errno = errcode;
+  return -1;
+}
+
+/****************************************************************************
+ * Name: dpclose
+ *
+ * Description:
+ *   Close a file descriptor opened by dpopen() and wait for the child
+ *   process to terminate.
+ *
+ *   This is the descriptor-based counterpart of pclose().
+ *
+ * Input Parameters:
+ *   fd  - The file descriptor returned by dpopen()
+ *   pid - The child process ID returned by dpopen()
+ *
+ * Returned Value:
+ *   The child termination status on success, or -1 on failure with
+ *   errno set.
+ *
+ ****************************************************************************/
+
+int dpclose(int fd, pid_t pid)
+{
+#ifdef CONFIG_SCHED_WAITPID
+  int status;
+  int ret;
+#endif
+
+  if (fd >= 0)
+    {
+      close(fd);
+    }
+
+#ifdef CONFIG_SCHED_WAITPID
+  ret = waitpid(pid, &status, 0);
+  if (ret < 0)
+    {
+      return ERROR;
+    }
+
+  return status;
+#else
+  return 0;
+#endif
+}
diff --git a/system/popen/popen.c b/system/popen/popen.c
index b52fbaafe..4f46e6cd2 100644
--- a/system/popen/popen.c
+++ b/system/popen/popen.c
@@ -26,21 +26,13 @@
 
 #include <nuttx/config.h>
 
-#include <sys/wait.h>
-#include <sys/ioctl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
-#include <sched.h>
-#include <spawn.h>
-#include <assert.h>
-#include <nuttx/debug.h>
 #include <fcntl.h>
 #include <errno.h>
 
-#include "nshlib/nshlib.h"
-
 /****************************************************************************
  * Private Types
  ****************************************************************************/
@@ -69,17 +61,9 @@ struct popen_file_s
  *   executed command, and will return a pointer to a stream that can be
  *   used to either read from or write to the pipe.
  *
- *   The environment of the executed command will be as if a child process
- *   were created within the popen() call using the fork() function, and the
- *   child invoked the sh utility using the call:
- *
- *     execl(shell path, "sh", "-c", command, NULL);
- *
- *   where shell path is an unspecified pathname for the sh utility.
- *
- *   The popen() function will ensure that any streams from previous popen()
- *   calls that remain open in the parent process are closed in the new child
- *   process.
+ *   This is a thin wrapper around dpopen() that wraps the returned file
+ *   descriptor in a FILE stream, analogous to how fprintf() relates to
+ *   dprintf().
  *
  *   The mode argument to popen() is a string that specifies I/O mode:
  *
@@ -95,18 +79,12 @@ struct popen_file_s
  *       the stream pointer returned by popen(), will be the writable end of
  *       the pipe.
  *
- *   If mode is any other value, the result is undefined.
- *
- *   After popen(), both the parent and the child process will be capable of
- *   executing independently before either terminates.
- *
- *   Pipe streams are byte-oriented.
- *
  * Input Parameters:
- *   command
+ *   command - The command string to execute
+ *   mode    - "r" or "w"
  *
  * Returned Value:
- *   A non-NULLFILE stream connected to the shell instance is returned on
+ *   A non-NULL FILE stream connected to the child process is returned on
  *   success.  NULL is returned on any failure with the errno variable set
  *   appropriately.
  *
@@ -115,244 +93,67 @@ struct popen_file_s
 FILE *popen(FAR const char *command, FAR const char *mode)
 {
   FAR struct popen_file_s *container;
-  struct sched_param param;
-  posix_spawnattr_t attr;
-  posix_spawn_file_actions_t file_actions;
-  FAR char *argv[4];
-  int fd[2];
-  int oldfd[2];
-  int newfd[2];
-  int retfd;
-  int errcode;
-  int result = 0;
-  bool rw = false;
+  int oflag;
+  int fd;
 
   /* Allocate a container for returned FILE stream */
 
   container = (FAR struct popen_file_s *)malloc(sizeof(struct popen_file_s));
   if (container == NULL)
     {
-      errcode = ENOMEM;
-      goto errout;
+      errno = ENOMEM;
+      return NULL;
     }
 
-  oldfd[1] = 0;
-  newfd[1] = 0;
-
-  /* Create a pipe.  fd[0] refers to the read end of the pipe; fd[1] refers
-   * to the write end of the pipe.
-   * Is the pipe the input to the shell?  Or the output?
-   */
-
-  if (strcmp(mode, "r") == 0 &&
-      (result = pipe2(fd, O_CLOEXEC)) >= 0)
-    {
-      /* Pipe is the output from the shell */
+  /* Map mode string to open flags */
 
-      oldfd[0] = 1;     /* Replace stdout with the write side of the pipe */
-      newfd[0] = fd[1];
-      retfd    = fd[0]; /* Use read side of the pipe to create the return 
stream */
-    }
-  else if (strcmp(mode, "w") == 0 &&
-           (result = pipe2(fd, O_CLOEXEC)) >= 0)
+  if (strstr(mode, "r+") || strstr(mode, "w+"))
     {
-      /* Pipe is the input to the shell */
-
-      oldfd[0] = 0;     /* Replace stdin with the read side of the pipe */
-      newfd[0] = fd[0];
-      retfd    = fd[1]; /* Use write side of the pipe to create the return 
stream */
+      oflag = O_RDWR;
     }
-
-  /* Create a socketpair. Using fd[0] as the input and output to the shell */
-
-#if defined(CONFIG_NET_LOCAL) && defined(CONFIG_NET_LOCAL_STREAM)
-  else if ((strcmp(mode, "r+") == 0 || strcmp(mode, "w+") == 0) &&
-           (result = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC,
-                                0, fd)) >= 0)
+  else if (strstr(mode, "r"))
     {
-      /* Socketpair is the input/output to the shell */
-
-      rw = true;
-      oldfd[0] = 0;     /* Replace stdin with the one side of a socket pair */
-      newfd[0] = fd[0];
-      oldfd[1] = 1;     /* Replace stdout with the one side of a socket pair */
-      newfd[1] = fd[0];
-      retfd    = fd[1]; /* Use other side of the socket pair to create the 
return stream */
+      oflag = O_RDONLY;
     }
-#endif
-  else if (result < 0)
+  else if (strstr(mode, "w"))
     {
-      errcode = errno;
-      goto errout_with_container;
+      oflag = O_WRONLY;
     }
   else
     {
-      errcode = EINVAL;
-      goto errout_with_pipe;
-    }
-
-  /* Create the FILE stream return reference */
-
-  container->original = fdopen(retfd, mode);
-  if (container->original == NULL)
-    {
-      errcode = errno;
-      goto errout_with_pipe;
-    }
-
-  /* Initialize attributes for task_spawn() (or posix_spawn()). */
-
-  errcode = posix_spawnattr_init(&attr);
-  if (errcode != 0)
-    {
-      goto errout_with_stream;
-    }
-
-  errcode = posix_spawn_file_actions_init(&file_actions);
-  if (errcode != 0)
-    {
-      goto errout_with_attrs;
-    }
-
-  /* Set the correct stack size and priority */
-
-  param.sched_priority = CONFIG_SYSTEM_POPEN_PRIORITY;
-  errcode = posix_spawnattr_setschedparam(&attr, &param);
-  if (errcode != 0)
-    {
-      goto errout_with_actions;
-    }
-
-#ifndef CONFIG_SYSTEM_POPEN_SHPATH
-  errcode = posix_spawnattr_setstacksize(&attr,
-                                         CONFIG_SYSTEM_POPEN_STACKSIZE);
-  if (errcode != 0)
-    {
-      goto errout_with_actions;
-    }
-#endif
-
-  /* If robin robin scheduling is enabled, then set the scheduling policy
-   * of the new task to SCHED_RR before it has a chance to run.
-   */
-
-#if CONFIG_RR_INTERVAL > 0
-  errcode = posix_spawnattr_setschedpolicy(&attr, SCHED_RR);
-  if (errcode != 0)
-    {
-      goto errout_with_actions;
+      free(container);
+      errno = EINVAL;
+      return NULL;
     }
 
-  errcode = posix_spawnattr_setflags(&attr,
-                                     POSIX_SPAWN_SETSCHEDPARAM |
-                                     POSIX_SPAWN_SETSCHEDULER);
-  if (errcode != 0)
+  if (strchr(mode, 'e') != NULL)
     {
-      goto errout_with_actions;
+      oflag |= O_CLOEXEC;
     }
 
-#else
-  errcode = posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSCHEDPARAM);
-  if (errcode != 0)
-    {
-      goto errout_with_actions;
-    }
-
-#endif
-
-  /* Redirect input or output as determined by the mode parameter */
-
-  errcode = posix_spawn_file_actions_adddup2(&file_actions,
-                                             newfd[0], oldfd[0]);
-  if (errcode != 0)
-    {
-      goto errout_with_actions;
-    }
-
-  if (rw)
-    {
-      errcode = posix_spawn_file_actions_adddup2(&file_actions,
-                                                 newfd[1], oldfd[1]);
-      if (errcode != 0)
-        {
-          goto errout_with_actions;
-        }
-    }
-
-  /* Call task_spawn() (or posix_spawn), re-directing stdin or stdout
-   * appropriately.
-   */
-
-  argv[1] = "-c";
-  argv[2] = (FAR char *)command;
-  argv[3] = NULL;
-
-#ifdef CONFIG_SYSTEM_POPEN_SHPATH
-  argv[0] = CONFIG_SYSTEM_POPEN_SHPATH;
-  errcode = posix_spawn(&container->shell, argv[0], &file_actions,
-                        &attr, argv, NULL);
-#else
-  container->shell = task_spawn("popen", nsh_system, &file_actions,
-                                &attr, argv + 1, NULL);
-  if (container->shell < 0)
-    {
-      errcode = -container->shell;
-    }
-#endif
-
-  if (errcode != 0)
-    {
-      serr("ERROR: Spawn failed: %d\n", errcode);
-      goto errout_with_actions;
-    }
-
-  /* We can close the 'newfd' now.  It is no longer useful on this side of
-   * the interface.
-   */
-
-  close(newfd[0]);
+  /* Use dpopen() to do the real work */
 
-  if (rw && newfd[0] != newfd[1])
+  fd = dpopen(command, oflag, &container->shell);
+  if (fd < 0)
     {
-      close(newfd[1]);
+      free(container);
+      return NULL;
     }
 
-  /* Free attributes and file actions.  Ignoring return values in the case
-   * of an error.
-   */
+  /* Wrap the raw fd in a FILE stream */
 
-  posix_spawn_file_actions_destroy(&file_actions);
-  posix_spawnattr_destroy(&attr);
-
-  if (strchr(mode, 'e') == NULL)
+  container->original = fdopen(fd, mode);
+  if (container->original == NULL)
     {
-      ioctl(retfd, FIOCLEX, 0);
+      int errcode = errno;
+      dpclose(fd, container->shell);
+      free(container);
+      errno = errcode;
+      return NULL;
     }
 
-  /* Finale and return input input/output stream */
-
   memcpy(&container->copy, container->original, sizeof(FILE));
   return &container->copy;
-
-errout_with_actions:
-  posix_spawn_file_actions_destroy(&file_actions);
-
-errout_with_attrs:
-  posix_spawnattr_destroy(&attr);
-
-errout_with_stream:
-  fclose(container->original);
-
-errout_with_pipe:
-  close(fd[0]);
-  close(fd[1]);
-
-errout_with_container:
-  free(container);
-
-errout:
-  errno = errcode;
-  return NULL;
 }
 
 /****************************************************************************
@@ -388,12 +189,12 @@ errout:
  *   If the argument stream to pclose() is not a pointer to a stream created
  *   by popen(), the result of pclose() is undefined.
  *
- * Description:
+ * Input Parameters:
  *   stream - The stream reference returned by a previous call to popen()
  *
  * Returned Value:
- *   Zero (OK) is returned on success; otherwise -1 (ERROR) is returned and
- *   the errno variable is set appropriately.
+ *   The child termination status on success, or -1 (ERROR) on failure
+ *   with errno set.
  *
  ****************************************************************************/
 
@@ -402,12 +203,7 @@ int pclose(FILE *stream)
   FAR struct popen_file_s *container = (FAR struct popen_file_s *)stream;
   FILE *original;
   pid_t shell;
-#ifdef CONFIG_SCHED_WAITPID
-  int status;
-  int result;
-#endif
 
-  DEBUGASSERT(container != NULL && container->original != NULL);
   original = container->original;
 
   /* Set the state of the original file descriptor to the state of the
@@ -417,7 +213,7 @@ int pclose(FILE *stream)
   memcpy(original, &container->copy, sizeof(FILE));
 
   /* Then close the original and free the container (saving the PID of the
-   * shell process)
+   * shell process).  Pass -1 to dpclose since fclose already closed the fd.
    */
 
   fclose(original);
@@ -425,19 +221,5 @@ int pclose(FILE *stream)
   shell = container->shell;
   free(container);
 
-#ifdef CONFIG_SCHED_WAITPID
-  /* Wait for the shell to exit, retrieving the return value if available. */
-
-  result = waitpid(shell, &status, 0);
-  if (result < 0)
-    {
-      /* The errno has already been set */
-
-      return ERROR;
-    }
-
-  return status;
-#else
-  return OK;
-#endif
+  return dpclose(-1, shell);
 }

Reply via email to