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

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

commit a0618315735c3a470d2a9f283b85c85d10f990c6
Author: Marco Casaroli <[email protected]>
AuthorDate: Sun Oct 18 16:34:35 2026 +0200

    nshlib: Keep the exit status of the last command.
    
    NSH kept only whether the last command failed.  nsh_builtin() and
    nsh_fileapp() returned 1 for any non-zero exit status, $? expanded to 0
    or 1, and "sh -c command" exited with the result of nsh_parse(): 0 or
    255 (-1), never the exit status of the command.
    
    Keep the exit status in np_status.  nsh_builtin() and nsh_fileapp()
    return the exit status of the application, $? expands to it, and
    "sh -c" exits with it, as POSIX requires.  A command line that cannot
    be run still gives EXIT_FAILURE.
    
    Assisted-by: Claude Code:claude-opus-5-5
    Signed-off-by: Marco Casaroli <[email protected]>
---
 nshlib/nsh.h          |  3 ++-
 nshlib/nsh_builtin.c  | 18 +++++-----------
 nshlib/nsh_fileapps.c | 23 ++++++++-------------
 nshlib/nsh_parse.c    | 57 ++++++++++++++++++++++-----------------------------
 nshlib/nsh_session.c  | 12 ++++++++++-
 5 files changed, 51 insertions(+), 62 deletions(-)

diff --git a/nshlib/nsh.h b/nshlib/nsh.h
index 9ac148b94..3ca066867 100644
--- a/nshlib/nsh.h
+++ b/nshlib/nsh.h
@@ -652,10 +652,11 @@ struct nsh_parser_s
   bool     np_redir_out; /* true: Output from the last command was re-directed 
*/
   bool     np_redir_in;  /* true: Input from the last command was re-directed 
*/
   bool     np_redir_err; /* true: Error from the last command was re-directed 
*/
-  bool     np_fail;      /* true: The last command failed */
+  int      np_status;    /* Exit status of the last command */
   pid_t    np_lastpid;   /* Pid of the last command executed */
 #ifdef NSH_HAVE_VARS
   char     np_pids[32];  /* String representation of the last pid */
+  char     np_rcstr[4];  /* String representation of the exit status */
 #endif
 
 #ifndef CONFIG_NSH_DISABLESCRIPT
diff --git a/nshlib/nsh_builtin.c b/nshlib/nsh_builtin.c
index 52085b571..6d1203057 100644
--- a/nshlib/nsh_builtin.c
+++ b/nshlib/nsh_builtin.c
@@ -64,9 +64,9 @@
  *               and successfully started.  If CONFIG_SCHED_WAITPID is
  *               defined, this return value also indicates that the
  *               application returned successful status (EXIT_SUCCESS)
- *    1          If CONFIG_SCHED_WAITPID is defined, then this return value
- *               indicates that the application task was spawned successfully
- *               but returned failure exit status.
+ *   >0          If CONFIG_SCHED_WAITPID is defined, the application task
+ *               was spawned successfully and returned this non-zero exit
+ *               status.
  *
  ****************************************************************************/
 
@@ -200,17 +200,9 @@ int nsh_builtin(FAR struct nsh_vtbl_s *vtbl, FAR const 
char *cmd,
 
           else
             {
-              /* We can't return the exact status (nsh has nowhere to put it)
-               * so just pass back zero/nonzero in a fashion that doesn't
-               * look like an error.
-               */
-
-              ret = (rc == 0) ? OK : 1;
+              /* Return the exit status of the application */
 
-              /* TODO:  Set the environment variable '?' to a string
-               * corresponding to WEXITSTATUS(rc) so that $? will expand to
-               * the exit status of the most recently executed task.
-               */
+              ret = WIFEXITED(rc) ? WEXITSTATUS(rc) : 1;
             }
 
           if (vtbl->isctty && tc == 0)
diff --git a/nshlib/nsh_fileapps.c b/nshlib/nsh_fileapps.c
index 796b167cd..25a9c27c2 100644
--- a/nshlib/nsh_fileapps.c
+++ b/nshlib/nsh_fileapps.c
@@ -65,9 +65,9 @@
  *               and successfully started.  If CONFIG_SCHED_WAITPID is
  *               defined, this return value also indicates that the
  *               application returned successful status (EXIT_SUCCESS)
- *    1          If CONFIG_SCHED_WAITPID is defined, then this return value
- *               indicates that the application task was spawned successfully
- *               but returned failure exit status.
+ *   >0          If CONFIG_SCHED_WAITPID is defined, the application task
+ *               was spawned successfully and returned this non-zero exit
+ *               status.
  *
  ****************************************************************************/
 
@@ -341,14 +341,10 @@ int nsh_fileapp(FAR struct nsh_vtbl_s *vtbl, FAR const 
char *cmd,
 
           else
             {
-              /* Ignore the returned child pid */
+              /* Keep the exit status of the application */
 
               ret = OK;
-
-              /* TODO:  Set the environment variable '?' to a string
-               * corresponding to WEXITSTATUS(rc) so that $? will expand
-               * to the exit status of the most recently executed task.
-               */
+              rc  = WIFEXITED(rc) ? WEXITSTATUS(rc) : 1;
             }
 
           if (vtbl->isctty && tc == 0)
@@ -418,14 +414,11 @@ errout:
 
       ret = ERROR;
     }
-  else if (rc != 0)
+  else
     {
-      /* We can't return the exact status (nsh has nowhere to put it)
-       * so just pass back zero/nonzero in a fashion that doesn't look
-       * like an error.
-       */
+      /* Return the exit status of the application */
 
-      ret = 1;
+      ret = rc;
     }
 
   return ret;
diff --git a/nshlib/nsh_parse.c b/nshlib/nsh_parse.c
index 7cba9cc40..51811c667 100644
--- a/nshlib/nsh_parse.c
+++ b/nshlib/nsh_parse.c
@@ -163,7 +163,7 @@ static void nsh_alist_free(FAR struct nsh_vtbl_s *vtbl,
                            FAR struct nsh_alist_s *alist);
 #endif
 
-static int nsh_saveresult(FAR struct nsh_vtbl_s *vtbl, bool result);
+static int nsh_saveresult(FAR struct nsh_vtbl_s *vtbl, int status);
 static int nsh_execute(FAR struct nsh_vtbl_s *vtbl,
                int argc, FAR char *argv[],
                FAR const struct nsh_param_s *param);
@@ -278,8 +278,6 @@ static const size_t g_pipeline1_len     = 
sizeof(g_pipeline1) - 1;
 #ifdef NSH_HAVE_VARS
 static const char   g_exitstatus[]      = "?";
 static const char   g_lastpid[]         = "!";
-static const char   g_success[]         = "0";
-static const char   g_failure[]         = "1";
 #endif
 #ifdef NEED_NULLSTRING
 static const char   g_nullstring[]      = "";
@@ -445,9 +443,10 @@ static void nsh_alist_free(FAR struct nsh_vtbl_s *vtbl,
  * Name: nsh_saveresult
  ****************************************************************************/
 
-static int nsh_saveresult(FAR struct nsh_vtbl_s *vtbl, bool result)
+static int nsh_saveresult(FAR struct nsh_vtbl_s *vtbl, int status)
 {
   struct nsh_parser_s *np = &vtbl->np;
+  bool result = status != 0;
 
 #ifndef CONFIG_NSH_DISABLESCRIPT
 #ifndef CONFIG_NSH_DISABLE_LOOPS
@@ -462,7 +461,7 @@ static int nsh_saveresult(FAR struct nsh_vtbl_s *vtbl, bool 
result)
 
   if (np->np_lpstate[np->np_lpndx].lp_state == NSH_LOOP_WHILE)
     {
-      np->np_fail = false;
+      np->np_status = 0;
       np->np_lpstate[np->np_lpndx].lp_enable = (result == OK);
       return OK;
     }
@@ -478,7 +477,7 @@ static int nsh_saveresult(FAR struct nsh_vtbl_s *vtbl, bool 
result)
 
   else if (np->np_lpstate[np->np_lpndx].lp_state == NSH_LOOP_UNTIL)
     {
-      np->np_fail = false;
+      np->np_status = 0;
       np->np_lpstate[np->np_lpndx].lp_enable = (result != OK);
       return OK;
     }
@@ -490,7 +489,7 @@ static int nsh_saveresult(FAR struct nsh_vtbl_s *vtbl, bool 
result)
 
   if (np->np_iestate[np->np_iendx].ie_state == NSH_ITEF_IF)
     {
-      np->np_fail = false;
+      np->np_status = 0;
       np->np_iestate[np->np_iendx].ie_ifcond =
         np->np_iestate[np->np_iendx].ie_inverted ^ result;
       return OK;
@@ -499,7 +498,7 @@ static int nsh_saveresult(FAR struct nsh_vtbl_s *vtbl, bool 
result)
 #endif
 #endif
     {
-      np->np_fail = result;
+      np->np_status = status;
       return result ? ERROR : OK;
     }
 }
@@ -544,9 +543,9 @@ static int nsh_execute(FAR struct nsh_vtbl_s *vtbl,
    *               and successfully started.  If CONFIG_SCHED_WAITPID is
    *               defined, this return value also indicates that the
    *               application returned successful status (EXIT_SUCCESS)
-   *    1          If CONFIG_SCHED_WAITPID is defined, then this return value
-   *               indicates that the application task was spawned
-   *               successfully but returned failure exit status.
+   *   >0          If CONFIG_SCHED_WAITPID is defined, the application
+   *               task was spawned successfully and returned this non-zero
+   *               exit status.
    *
    * Note the priority is not effected by nice-ness.
    */
@@ -555,14 +554,14 @@ static int nsh_execute(FAR struct nsh_vtbl_s *vtbl,
   ret = nsh_builtin(vtbl, argv[0], argv, param);
   if (ret >= 0)
     {
-      /* nsh_builtin() returned 0 or 1.  This means that the built-in
-       * command was successfully started (although it may not have ran
-       * successfully).  So certainly it is not an NSH command.
+      /* nsh_builtin() returned 0 or an exit status.  This means that the
+       * built-in command was successfully started (although it may not
+       * have ran successfully).  So certainly it is not an NSH command.
        */
 
-      /* Save the result:  success if 0; failure if 1 */
+      /* Save the exit status:  success if 0 */
 
-      return nsh_saveresult(vtbl, ret != OK);
+      return nsh_saveresult(vtbl, ret);
     }
 
   /* No, not a built in command (or, at least, we were unable to start a
@@ -581,9 +580,9 @@ static int nsh_execute(FAR struct nsh_vtbl_s *vtbl,
    *               and successfully started.  If CONFIG_SCHED_WAITPID is
    *               defined, this return value also indicates that the
    *               application returned successful status (EXIT_SUCCESS)
-   *    1          If CONFIG_SCHED_WAITPID is defined, then this return value
-   *               indicates that the application task was spawned
-   *               successfully but returned failure exit status.
+   *   >0          If CONFIG_SCHED_WAITPID is defined, the application
+   *               task was spawned successfully and returned this non-zero
+   *               exit status.
    *
    * Note the priority is not effected by nice-ness.
    */
@@ -592,14 +591,14 @@ static int nsh_execute(FAR struct nsh_vtbl_s *vtbl,
   ret = nsh_fileapp(vtbl, argv[0], argv, param);
   if (ret >= 0)
     {
-      /* nsh_fileapp() returned 0 or 1.  This means that the built-in
-       * command was successfully started (although it may not have ran
-       * successfully).  So certainly it is not an NSH command.
+      /* nsh_fileapp() returned 0 or an exit status.  This means that the
+       * built-in command was successfully started (although it may not
+       * have ran successfully).  So certainly it is not an NSH command.
        */
 
-      /* Save the result:  success if 0; failure if 1 */
+      /* Save the exit status:  success if 0 */
 
-      return nsh_saveresult(vtbl, ret != OK);
+      return nsh_saveresult(vtbl, ret);
     }
 
   /* No, not a file name command (or, at least, we were unable to start a
@@ -1141,14 +1140,8 @@ static FAR char *nsh_envexpand(FAR struct nsh_vtbl_s 
*vtbl,
 
   if (strcmp(varname, g_exitstatus) == 0)
     {
-      if (vtbl->np.np_fail)
-        {
-          return (FAR char *)g_failure;
-        }
-      else
-        {
-          return (FAR char *)g_success;
-        }
+      itoa(vtbl->np.np_status, vtbl->np.np_rcstr, 10);
+      return vtbl->np.np_rcstr;
     }
   else if (strcmp(varname, g_lastpid) == 0)
     {
diff --git a/nshlib/nsh_session.c b/nshlib/nsh_session.c
index 8d9d7a9f4..46ac1d1cf 100644
--- a/nshlib/nsh_session.c
+++ b/nshlib/nsh_session.c
@@ -158,7 +158,17 @@ int nsh_session(FAR struct console_stdio_s *pstate,
 
           if (argc > 2)
             {
-              return nsh_parse(vtbl, argv[2]);
+              /* Return the exit status of the last command, or a failure
+               * if the command line could not be run.
+               */
+
+              ret = nsh_parse(vtbl, argv[2]);
+              if (vtbl->np.np_status != 0)
+                {
+                  return vtbl->np.np_status;
+                }
+
+              return ret < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
             }
           else
             {

Reply via email to