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 740fda96302cc6f379907ce03f62d6754c657a1c
Author: cuiziwei <[email protected]>
AuthorDate: Tue Apr 28 17:32:22 2026 +0800

    system/popen: support no-shell mode via posix_spawnp
    
    When NSH_LIBRARY is not available, dpopen()/popen() can still execute
    commands by splitting the command string by whitespace and calling
    posix_spawnp() directly.  Shell syntax (pipes, redirects, globbing)
    is not supported in this mode.
    
    Add CONFIG_SYSTEM_POPEN_MAXARGUMENTS (default 7) to control the
    argv array size for the no-shell path.
    
    Remove the hard dependency on NSH_LIBRARY from SYSTEM_POPEN so the
    feature can be used in minimal configurations without a shell.
    
    Signed-off-by: cuiziwei <[email protected]>
---
 system/popen/Kconfig  | 27 ++++++++++++++++++-----
 system/popen/dpopen.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 78 insertions(+), 8 deletions(-)

diff --git a/system/popen/Kconfig b/system/popen/Kconfig
index 606efa032..6256af7c4 100644
--- a/system/popen/Kconfig
+++ b/system/popen/Kconfig
@@ -7,7 +7,7 @@ config SYSTEM_POPEN
        bool "popen()/pclose()/dpopen()/dpclose() Functions"
        default n
        select SCHED_WAITPID
-       depends on NSH_LIBRARY && PIPES
+       depends on PIPES
        ---help---
                Enable support for the popen(), pclose(), dpopen(), and
                dpclose() interfaces.
@@ -20,16 +20,20 @@ config SYSTEM_POPEN
                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.
+               When NSH is available (NSH_LIBRARY), commands are executed
+               through the shell (sh -c command), supporting full shell
+               syntax including pipes, redirects, and globbing.
+
+               When NSH is not available, commands are executed directly
+               via posix_spawnp(). The command string must be a simple
+               "program arg1 arg2" form without shell syntax.
 
 if SYSTEM_POPEN
 
 config SYSTEM_POPEN_SHPATH
        string "Path to shell command"
        default "/bin/sh"
-       depends on SYSTEM_NSH=m || BUILD_KERNEL
+       depends on (SYSTEM_NSH=m || BUILD_KERNEL) && NSH_LIBRARY
        ---help---
                This is the full path to the program in a mounted file system 
that
                implements the system() command.  That is, a program that 
starts the
@@ -53,4 +57,17 @@ config SYSTEM_POPEN_PRIORITY
        ---help---
                The priority of the shell.
 
+config SYSTEM_POPEN_MAXARGUMENTS
+       int "Maximum number of command arguments (no-shell mode)"
+       default 7
+       depends on !NSH_LIBRARY
+       ---help---
+               When NSH is not available, dpopen()/popen() splits the command
+               string by whitespace into an argv array.  This sets the maximum
+               number of arguments (excluding the program name and the
+               terminating NULL).
+
+               This is analogous to CONFIG_NSH_MAXARGUMENTS but applies
+               only to the no-shell path.
+
 endif
diff --git a/system/popen/dpopen.c b/system/popen/dpopen.c
index dd8bc9b7d..785fcc202 100644
--- a/system/popen/dpopen.c
+++ b/system/popen/dpopen.c
@@ -27,6 +27,7 @@
 #include <sys/wait.h>
 #include <sys/ioctl.h>
 #include <unistd.h>
+#include <string.h>
 #include <sched.h>
 #include <spawn.h>
 #include <debug.h>
@@ -37,7 +38,17 @@
 #  include <sys/socket.h>
 #endif
 
-#include "nshlib/nshlib.h"
+#ifdef CONFIG_NSH_LIBRARY
+#  include "nshlib/nshlib.h"
+#endif
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#ifndef CONFIG_NSH_LIBRARY
+#  define DPOPEN_MAX_ARGV (CONFIG_SYSTEM_POPEN_MAXARGUMENTS + 1)
+#endif
 
 /****************************************************************************
  * Public Functions
@@ -58,6 +69,10 @@
  *   When NSH is available, commands are executed through the shell
  *   (sh -c command), supporting full shell syntax.
  *
+ *   When NSH is not available, the command is split by whitespace and
+ *   executed directly via posix_spawnp().  Shell syntax (pipes, redirects,
+ *   globbing) is not supported in this mode.
+ *
  * Input Parameters:
  *   command - The command string to execute
  *   oflag   - O_RDONLY to read child stdout, O_WRONLY to write child stdin,
@@ -74,7 +89,14 @@ 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;
+#ifdef CONFIG_NSH_LIBRARY
   FAR char *argv[4];
+#else
+  char cmdbuf[PATH_MAX];
+  FAR char *argv[DPOPEN_MAX_ARGV];
+  FAR char *saveptr;
+  int argc = 0;
+#endif
   int fd[2];
   int childfd;
   int parentfd;
@@ -224,21 +246,52 @@ int dpopen(FAR const char *command, int oflag, FAR pid_t 
*pid)
    * appropriately.
    */
 
+#ifdef CONFIG_NSH_LIBRARY
+  /* Shell mode: execute command through sh -c */
+
   argv[1] = "-c";
   argv[2] = (FAR char *)command;
   argv[3] = NULL;
 
-#ifdef CONFIG_SYSTEM_POPEN_SHPATH
+#  ifdef CONFIG_SYSTEM_POPEN_SHPATH
   argv[0] = CONFIG_SYSTEM_POPEN_SHPATH;
   errcode = posix_spawn(pid, argv[0], &file_actions,
                         &attr, argv, NULL);
-#else
+#  else
   *pid = task_spawn("dpopen", nsh_system, &file_actions,
                     &attr, argv + 1, NULL);
   if (*pid < 0)
     {
       errcode = -*pid;
     }
+#  endif
+#else
+  /* No-shell mode: split command and execute directly via posix_spawnp.
+   * The command must be in "program arg1 arg2" form -- no shell syntax.
+   */
+
+  if (strlcpy(cmdbuf, command, sizeof(cmdbuf)) >= sizeof(cmdbuf))
+    {
+      errcode = ENAMETOOLONG;
+      goto errout_with_actions;
+    }
+
+  do
+    {
+      argv[argc] = strtok_r(argc ? NULL : cmdbuf, " \t", &saveptr);
+    }
+  while (argv[argc] != NULL && ++argc < DPOPEN_MAX_ARGV - 1);
+
+  argv[argc] = NULL;
+
+  if (argc == 0)
+    {
+      errcode = EINVAL;
+      goto errout_with_actions;
+    }
+
+  errcode = posix_spawnp(pid, argv[0], &file_actions,
+                         &attr, argv, NULL);
 #endif
 
   if (errcode != 0)

Reply via email to