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

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

commit c052bd8377dd2d6c8d1e16c56afd18b590b12410
Author: wangjianyu3 <[email protected]>
AuthorDate: Mon Oct 14 20:44:27 2024 +0800

    nsh: Add pipeline support for nsh commandline
    
    And nested pipeline supported.
    
    Test
      1. Redirect in
        cat < /etc/init.d/rc.sysinit
    
      2. Simple pipeline
        ls | cat
    
      3. Nested pipeline
        ls | dd | cat | dd | cat
    
    Signed-off-by: wangjianyu3 <[email protected]>
---
 builtin/exec_builtin.c |  26 ++++++++++
 nshlib/Kconfig         |   7 +++
 nshlib/nsh_fileapps.c  |  28 +++++++++++
 nshlib/nsh_parse.c     | 126 ++++++++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 186 insertions(+), 1 deletion(-)

diff --git a/builtin/exec_builtin.c b/builtin/exec_builtin.c
index 6287cf07c..2bf28b8f4 100644
--- a/builtin/exec_builtin.c
+++ b/builtin/exec_builtin.c
@@ -158,6 +158,19 @@ int exec_builtin(FAR const char *appname, FAR char * const 
*argv,
               goto errout_with_actions;
             }
         }
+#ifdef CONFIG_NSH_PIPELINE
+      else if (param->fd_in != -1)
+        {
+          ret = posix_spawn_file_actions_adddup2(&file_actions,
+                                                 param->fd_in, 0);
+          if (ret != 0)
+            {
+              serr("ERROR: posix_spawn_file_actions_adddup2 failed: %d\n",
+                   ret);
+              goto errout_with_actions;
+            }
+        }
+#endif
 
       /* Is output being redirected? */
 
@@ -175,6 +188,19 @@ int exec_builtin(FAR const char *appname, FAR char * const 
*argv,
               goto errout_with_actions;
             }
         }
+#ifdef CONFIG_NSH_PIPELINE
+      else if (param->fd_out != -1)
+        {
+          ret = posix_spawn_file_actions_adddup2(&file_actions,
+                                                 param->fd_out, 1);
+          if (ret != 0)
+            {
+              serr("ERROR: posix_spawn_file_actions_adddup2 failed: %d\n",
+                   ret);
+              goto errout_with_actions;
+            }
+        }
+#endif
     }
 
 #ifdef CONFIG_LIBC_EXECFUNCS
diff --git a/nshlib/Kconfig b/nshlib/Kconfig
index 57328e2af..be6ac1b55 100644
--- a/nshlib/Kconfig
+++ b/nshlib/Kconfig
@@ -231,6 +231,13 @@ config NSH_ALIAS_MAX_AMOUNT
 
 endif # NSH_ALIAS
 
+config NSH_PIPELINE
+       bool "Enable pipeline support"
+       default !DEFAULT_SMALL
+       depends on PIPES
+       ---help---
+               Enable pipeline support for nsh.
+
 endmenu # Command Line Configuration
 
 config NSH_BUILTIN_APPS
diff --git a/nshlib/nsh_fileapps.c b/nshlib/nsh_fileapps.c
index 6aa4f5030..d49810a9d 100644
--- a/nshlib/nsh_fileapps.c
+++ b/nshlib/nsh_fileapps.c
@@ -126,6 +126,20 @@ int nsh_fileapp(FAR struct nsh_vtbl_s *vtbl, FAR const 
char *cmd,
               goto errout_with_actions;
             }
         }
+#ifdef CONFIG_NSH_PIPELINE
+      else if (param->fd_in != -1)
+        {
+          ret = posix_spawn_file_actions_adddup2(&file_actions,
+                                                 param->fd_in, 0);
+          if (ret != 0)
+            {
+              nsh_error(vtbl, g_fmtcmdfailed, cmd,
+                        "posix_spawn_file_actions_adddup2",
+                        NSH_ERRNO);
+              goto errout_with_actions;
+            }
+        }
+#endif
 
       /* Handle re-direction of output */
 
@@ -147,6 +161,20 @@ int nsh_fileapp(FAR struct nsh_vtbl_s *vtbl, FAR const 
char *cmd,
               goto errout_with_attrs;
             }
         }
+#ifdef CONFIG_NSH_PIPELINE
+      else if (param->fd_out != -1)
+        {
+          ret = posix_spawn_file_actions_adddup2(&file_actions,
+                                                 param->fd_out, 1);
+          if (ret != 0)
+            {
+              nsh_error(vtbl, g_fmtcmdfailed, cmd,
+                        "posix_spawn_file_actions_adddup2",
+                        NSH_ERRNO);
+              goto errout_with_actions;
+            }
+        }
+#endif
     }
 
 #ifdef CONFIG_BUILTIN
diff --git a/nshlib/nsh_parse.c b/nshlib/nsh_parse.c
index ac99fbf53..a17af110d 100644
--- a/nshlib/nsh_parse.c
+++ b/nshlib/nsh_parse.c
@@ -259,6 +259,9 @@ static const char g_arg_separator[]   = "`$";
 static const char g_redirect_out1[]   = ">";
 static const char g_redirect_out2[]  = ">>";
 static const char g_redirect_in1[]   = "<";
+#ifdef CONFIG_NSH_PIPELINE
+static const char g_pipeline1[]       = "|";
+#endif
 #ifdef NSH_HAVE_VARS
 static const char g_exitstatus[]      = "?";
 static const char g_lastpid[]         = "!";
@@ -1601,6 +1604,16 @@ static FAR char *nsh_argument(FAR struct nsh_vtbl_s 
*vtbl,
       argument = (FAR char *)g_redirect_in1;
     }
 
+#ifdef CONFIG_NSH_PIPELINE
+  /* Does the token begin with '|' -- pipeline? */
+
+  if (*pbegin == '|')
+    {
+      *saveptr = pbegin + 1;
+      argument = (FAR char *)g_pipeline1;
+    }
+#endif
+
   /* Does the token begin with '#' -- comment */
 
   else if (*pbegin == '#')
@@ -2415,6 +2428,13 @@ static int nsh_parse_command(FAR struct nsh_vtbl_s 
*vtbl, FAR char *cmdline)
       .file_out   = NULL
     };
 
+#ifdef CONFIG_NSH_PIPELINE
+  int pipefd[2] =
+    {
+      -1, -1
+    };
+#endif
+
   NSH_MEMLIST_TYPE memlist;
   NSH_ALIASLIST_TYPE alist;
   FAR char *argv[MAX_ARGV_ENTRIES];
@@ -2424,9 +2444,15 @@ static int nsh_parse_command(FAR struct nsh_vtbl_s 
*vtbl, FAR char *cmdline)
   int       ret;
   bool      redirect_out_save = false;
   bool      redirect_in_save = false;
+#ifdef CONFIG_NSH_PIPELINE
+  bool      bg_save = false;
+#endif
   size_t redirect_out1_len = strlen(g_redirect_out1);
   size_t redirect_out2_len = strlen(g_redirect_out2);
   size_t redirect_in1_len = strlen(g_redirect_in1);
+#ifdef CONFIG_NSH_PIPELINE
+  size_t pipeline1_len = strlen(g_pipeline1);
+#endif
 
 #ifdef CONFIG_SCHED_INSTRUMENTATION_DUMP
   char      tracebuf[CONFIG_NSH_LINELEN + 1];
@@ -2647,6 +2673,89 @@ static int nsh_parse_command(FAR struct nsh_vtbl_s 
*vtbl, FAR char *cmdline)
           param.oflags_in       = O_RDONLY;
           param.file_in         = nsh_getfullpath(vtbl, arg);
         }
+#ifdef CONFIG_NSH_PIPELINE
+      else if (!strncmp(argv[argc], g_pipeline1, pipeline1_len))
+        {
+          FAR char *arg;
+          FAR char *sh_argv[4];
+
+          if (argv[argc][pipeline1_len])
+            {
+              arg = &argv[argc][pipeline1_len];
+            }
+          else
+            {
+              arg = nsh_argument(vtbl, &saveptr, &memlist, NULL, &isenvvar);
+            }
+
+          if (!arg)
+            {
+              nsh_error(vtbl, g_fmtarginvalid, cmd);
+              ret = ERROR;
+              goto dynlist_free;
+            }
+
+          for (ret = 0; ret < argc - 1; ret++)
+            {
+              FAR char *p_arg = argv[ret];
+              size_t len = strlen(p_arg);
+
+              /* Restore from split args to concat args. */
+
+              DEBUGASSERT(&p_arg[len + 1] == argv[ret + 1]);
+              p_arg[len] = ' ';
+            }
+
+          sh_argv[0] = "sh";
+          sh_argv[1] = "-c";
+          sh_argv[2] = argv[0];
+          sh_argv[3] = NULL;
+
+          ret = pipe2(pipefd, 0);
+          if (ret < 0)
+            {
+              ret = -errno;
+              goto dynlist_free;
+            }
+
+          redirect_out_save = vtbl->np.np_redir_out;
+          vtbl->np.np_redir_out = true;
+          param.fd_out = pipefd[1];
+
+          bg_save = vtbl->np.np_bg;
+          vtbl->np.np_bg = true;
+
+          ret = nsh_execute(vtbl, 4, sh_argv, &param);
+
+          vtbl->np.np_bg = bg_save;
+
+          if (param.fd_in != -1)
+            {
+              close(param.fd_in);
+              param.fd_in = -1;
+              vtbl->np.np_redir_in = redirect_in_save;
+            }
+
+          if (param.fd_out != -1)
+            {
+              close(param.fd_out);
+              param.fd_out = -1;
+              vtbl->np.np_redir_out = redirect_out_save;
+            }
+
+          redirect_in_save = vtbl->np.np_redir_in;
+          vtbl->np.np_redir_in = true;
+          param.fd_in = pipefd[0];
+
+          argv[0] = arg;
+          argc = 1;
+
+          if (ret == -1)
+            {
+              goto dynlist_free;
+            }
+        }
+#endif
       else
         {
           argc++;
@@ -2678,6 +2787,8 @@ static int nsh_parse_command(FAR struct nsh_vtbl_s *vtbl, 
FAR char *cmdline)
 
   ret = nsh_execute(vtbl, argc, argv, &param);
 
+dynlist_free:
+
   /* Free any allocated resources */
 
   /* Free the redirected output file path */
@@ -2687,6 +2798,13 @@ static int nsh_parse_command(FAR struct nsh_vtbl_s 
*vtbl, FAR char *cmdline)
       nsh_freefullpath((char *)param.file_out);
       vtbl->np.np_redir_out = redirect_out_save;
     }
+#ifdef CONFIG_NSH_PIPELINE
+  else if (param.fd_out != -1)
+    {
+      close(param.fd_out);
+      vtbl->np.np_redir_out = redirect_out_save;
+    }
+#endif
 
   /* Free the redirected input file path */
 
@@ -2695,8 +2813,14 @@ static int nsh_parse_command(FAR struct nsh_vtbl_s 
*vtbl, FAR char *cmdline)
       nsh_freefullpath((char *)param.file_in);
       vtbl->np.np_redir_in = redirect_in_save;
     }
+#ifdef CONFIG_NSH_PIPELINE
+  else if (param.fd_in != -1)
+    {
+      close(param.fd_in);
+      vtbl->np.np_redir_in = redirect_in_save;
+    }
+#endif
 
-dynlist_free:
   NSH_ALIASLIST_FREE(vtbl, &alist);
   NSH_MEMLIST_FREE(&memlist);
 #ifdef CONFIG_SCHED_INSTRUMENTATION_DUMP

Reply via email to