From: Justin Cinkelj <justin.cink...@xlab.si>
Committer: Nadav Har'El <n...@scylladb.com>
Branch: master

busybox ash: do not exit if command doesn't exist

0004 patch prevents poping up spurious error message 'command not found'
when running in ash say 'ls /'. It requires patch to osv_execve to be
applied - osv_execve should clear errno on success, and set errno on
failure.

0005 patch prevent ash exit when non-existent command is tried.

As @nyh suggested, symlink /usr/bin -> /usr/lib is added, so that
ash works without adding /usr/lib to PATH environ.

Signed-off-by: Justin Cinkelj <justin.cink...@xlab.si>
Message-Id: <20170818120212.5470-1-justin.cink...@xlab.si>

---
diff --git a/busybox/GET b/busybox/GET
--- a/busybox/GET
+++ b/busybox/GET
@@ -34,7 +34,10 @@ cat <<EOF > usr.manifest
 /usr/lib/echo: ->/usr/lib/busybox
 /usr/lib/ping: ->/usr/lib/busybox
 #
+# Link /usr/bin (in ash's default PATH) to /usr/lib where we put the executables
+/usr/bin: ->/usr/lib
+#
 # test scripts
 ## /**: \${MODULE_DIR}/test-script/**

-EOF
\ No newline at end of file
+EOF
diff --git a/busybox/patches/0004-OSv-ash-fix-command-not-found-error-message-when-com.patch b/busybox/patches/0004-OSv-ash-fix-command-not-found-error-message-when-com.patch --- a/busybox/patches/0004-OSv-ash-fix-command-not-found-error-message-when-com.patch +++ b/busybox/patches/0004-OSv-ash-fix-command-not-found-error-message-when-com.patch
@@ -0,0 +1,39 @@
+From 1512e2b29f3d5c19d0735470d74c546bd15ed15a Mon Sep 17 00:00:00 2001
+From: Justin Cinkelj <justin.cink...@xlab.si>
+Date: Fri, 18 Aug 2017 07:01:58 +0200
+Subject: [PATCH 4/5] OSv ash: fix command not found error message when command
+ was found
+
+Running simple 'ls' in ash showed directory content. But at the end,
+spurious error message 'command not found' was shown. This was due to
+errno not being cleared by osv_execve. This was fixed in osv_execve, now
+it clears errno on success, or sets it to meanigful value (currently
+always ENOENT).
+
+Signed-off-by: Justin Cinkelj <justin.cink...@xlab.si>
+---
+ shell/ash.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/shell/ash.c b/shell/ash.c
+index bc16394..dc88bd8 100644
+--- a/shell/ash.c
++++ b/shell/ash.c
+@@ -7731,10 +7731,10 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **
+               int ret = 0;
+               pid_t ch_pid = -1;
+               ret = osv_execve(cmd, argv, envp, (long*)&ch_pid, -1);
+-              //errno = 0; // osv_execve should clear errno on success
+-              if(ret)
+-                      errno = ENOSYS;
+-              osv_waittid(ch_pid, NULL, 0);
++              // osv_execve now clears errno on success, as expected by 
caller.
++              if(ret == 0) {
++                      osv_waittid(ch_pid, NULL, 0);
++              }
+               return;
+       }
+ #endif
+--
+2.9.4
+
diff --git a/busybox/patches/0005-OSv-ash-do-not-exit-if-program-to-be-run-fails-to-st.patch b/busybox/patches/0005-OSv-ash-do-not-exit-if-program-to-be-run-fails-to-st.patch --- a/busybox/patches/0005-OSv-ash-do-not-exit-if-program-to-be-run-fails-to-st.patch +++ b/busybox/patches/0005-OSv-ash-do-not-exit-if-program-to-be-run-fails-to-st.patch
@@ -0,0 +1,140 @@
+From 1009e202f7c1214e7ab6185782f1033506a634a8 Mon Sep 17 00:00:00 2001
+From: Justin Cinkelj <justin.cink...@xlab.si>
+Date: Fri, 18 Aug 2017 07:26:12 +0200
+Subject: [PATCH 5/5] OSv ash: do not exit if program to be run fails to start
+
+If program to be started fails to start (executable file not found), ash
+should not return from its main loop, as this terminates shell.
+
+ash_main interceps exception from raise_exception, and exits because
+exception_type == EXEXIT. The exit is avoided if instead of returning from
+ash_main, code just continues with cmdloop(). Important detail - we have
+to first call popstackmark, and there re-execute setjmp, so that longjmp
+will work.
+
+As EXEXIT is used for both abnormal exit (exception handling, like
+file not found) and normal exit (entering 'exit' cmd into ash), this
+breaks 'exit' cmd. Thus we have to separete the two cases.
+This is done by replacing EXEXIT with:
+ - EXEXIT_CMD, when 'exit' was passed to ash interpreter.
+ - EXEXIT_VAR, for all other reasons.
+
+Signed-off-by: Justin Cinkelj <justin.cink...@xlab.si>
+---
+ shell/ash.c | 44 +++++++++++++++++++++++++++++++++++++-------
+ 1 file changed, 37 insertions(+), 7 deletions(-)
+
+diff --git a/shell/ash.c b/shell/ash.c
+index dc88bd8..d8111c0 100644
+--- a/shell/ash.c
++++ b/shell/ash.c
+@@ -324,7 +324,9 @@ struct globals_misc {
+       /* exceptions */
+ #define EXINT 0         /* SIGINT received */
+ #define EXERROR 1       /* a generic error */
+-#define EXEXIT 4        /* exit the shell */
++//#define EXEXIT 4        /* exit the shell */
++#define EXEXIT_CMD 4    /* exit the shell, due to exit command */
++#define EXEXIT_VAR 5    /* exit the shell, due to other reasons */
+
+       smallint isloginsh;
+       char nullstr[1];        /* zero length string */
+@@ -7831,7 +7833,7 @@ static void shellexec(char *prog, char **argv, const char *path, int idx)
+       exitstatus = exerrno;
+       TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
+               prog, e, suppress_int));
+-      ash_msg_and_raise(EXEXIT, "%s: %s", prog, errmsg(e, "not found"));
++      ash_msg_and_raise(EXEXIT_VAR, "%s: %s", prog, errmsg(e, "not found"));
+       /* NOTREACHED */
+ }
+
+@@ -8850,9 +8852,9 @@ evaltree(union node *n, int flags)
+       dotrap();
+
+       if (checkexit & status)
+-              raise_exception(EXEXIT);
++              raise_exception(EXEXIT_VAR);
+       if (flags & EV_EXIT)
+-              raise_exception(EXEXIT);
++              raise_exception(EXEXIT_VAR);
+
+       TRACE(("leaving evaltree (no interrupts)\n"));
+       return exitstatus;
+@@ -12756,7 +12758,7 @@ exitcmd(int argc UNUSED_PARAM, char **argv)
+               return 0;
+       if (argv[1])
+               exitstatus = number(argv[1]);
+-      raise_exception(EXEXIT);
++      raise_exception(EXEXIT_CMD);
+       /* NOTREACHED */
+ }
+
+@@ -13404,7 +13406,7 @@ exitshell(void)
+       status = exitstatus;
+       TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
+       if (setjmp(loc.loc)) {
+-              if (exception_type == EXEXIT)
++              if (exception_type == EXEXIT_CMD || exception_type == 
EXEXIT_VAR)
+                       status = exitstatus;
+               goto out;
+       }
+@@ -13624,6 +13626,8 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
+       line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
+ #endif
+       state = 0;
++do_setjmp:
++ // fprintf(stderr, "DBG BEFORE setjmp state=%d...\n", state); fflush(stderr);
+       if (setjmp(jmploc.loc)) {
+               smallint e;
+               smallint s;
+@@ -13632,10 +13636,30 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
+
+               e = exception_type;
+               s = state;
+-              if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
++ // fprintf(stderr, "DBG AFTER setjmp, ret=true e=%d state=%d iflag=%d shlvl=%d\n", e,s,iflag,shlvl); fflush(stderr);
++              if (e == EXEXIT_CMD) {
++                      // exit was explicitly requested, so do it.
++ // TODO - whas it requested in top level shell, or in subshell/interpreted script?
++                      // exit in called script should not terminate parent 
shell.
+                       exitshell();
+                       return 0; // for OSv only
+               }
++              if (e == EXEXIT_VAR || s == 0 || iflag == 0 || shlvl) {
++                      exitshell();
++                      /*
++                      After exception, we went out of cmdloop via longjmp.
++                      In OSv, return would terminate the only thread we have 
(while
++                      in linux, it would terminate a subprocess).
++                      Do not return, just let current thread continue, and
++                      it will go back into cmdloop.
++
++                      "let current thread continue" - this requires to 
re-execute setjmp.
++ Then, we have to go into state4 (as s == 4) - we have to skip states 1,2,3.
++                      */
++                      popstackmark(&smark);
++                      goto do_setjmp;
++
++              }
+               if (e == EXINT) {
+                       newline_and_flush(stderr);
+               }
+@@ -13650,9 +13674,15 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
+                       goto state3;
+               goto state4;
+       }
++ // fprintf(stderr, "DBG AFTER setjmp, ret=false iflag=%d...\n", iflag); fflush(stderr);
++
+       exception_handler = &jmploc;
+       rootpid = getpid();
+
++      if (state == 4)
++              goto state4; // OSv special case
++      assert(state == 0); // normal, initial execution path
++
+       init();
+       setstackmark(&smark);
+       procargs(argv);
+--
+2.9.4
+
diff --git a/busybox/test-script/cmd0.sh b/busybox/test-script/cmd0.sh
--- a/busybox/test-script/cmd0.sh
+++ b/busybox/test-script/cmd0.sh
null

--
You received this message because you are subscribed to the Google Groups "OSv 
Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to osv-dev+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to