[PATCH] add exec -a support (preliminary)

Patrick Pief p.pief at zoho.com
Thu Jan 26 23:56:55 UTC 2017


Hello,

There were several times where I thought that having "exec -a" in busybox would
be neat, and while "exec -a" is not POSIX it is still supported in a lot of
shells (see http://unix.stackexchange.com/q/250681/117599 ).

So, here is now my first attempt at adding support for it, I basically made a
copy of shellexec() called shellexeca() with support for a different target
argv0 different than what is executed. I edited execcmd() to call the new
function if the "-a" option gets used. I know that you might not like the
fact that I duplicated that much code but keep in mind that this is my first
attempt and I would first like to know:

1.  Your general feelings on this, e.g. if you are against this feature in
    general and are never going to accept a PATCH adding support for it then
    please let me know.

2.  Whether to hide this using the preprocessor flag and make it an official
    setting.

3.  Whether to make shellexeca() to be the new shellexec() and change all
    invocations of latter (I think this would make hiding it using the
    preprocessor harder).

BTW, to see that it works:

$ (exec -a ARGV0 sh -c 'echo $0')
ARGV0

-Patrick

---
 shell/ash.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 64 insertions(+), 1 deletion(-)

diff --git a/shell/ash.c b/shell/ash.c
index d8f4132..925093d 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -7763,6 +7763,65 @@ shellexec(char **argv, const char *path, int idx)
        /* NOTREACHED */
 }

+static void shellexeca(char **, char *, const char *, int) NORETURN;
+static void
+shellexeca(char **argv, char *zeroarg, const char *path, int idx)
+{
+       char *cmdname;
+       char *realcmd = argv[0];
+       int e;
+       char **envp;
+       int exerrno;
+       int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
+
+       argv[0] = zeroarg;
+       envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL);
+       if (strchr(realcmd, '/') != NULL
+#if ENABLE_FEATURE_SH_STANDALONE
+        || (applet_no = find_applet_by_name(realcmd)) >= 0
+#endif
+       ) {
+               tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) realcmd, argv, envp);
+               if (applet_no >= 0) {
+                       /* We tried execing ourself, but it didn't work.
+                        * Maybe /proc/self/exe doesn't exist?
+                        * Try $PATH search.
+                        */
+                       goto try_PATH;
+               }
+               e = errno;
+       } else {
+ try_PATH:
+               e = ENOENT;
+               while ((cmdname = path_advance(&path, realcmd)) != NULL) {
+                       if (--idx < 0 && pathopt == NULL) {
+                               tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
+                               if (errno != ENOENT && errno != ENOTDIR)
+                                       e = errno;
+                       }
+                       stunalloc(cmdname);
+               }
+       }
+
+       /* Map to POSIX errors */
+       switch (e) {
+       case EACCES:
+               exerrno = 126;
+               break;
+       case ENOENT:
+               exerrno = 127;
+               break;
+       default:
+               exerrno = 2;
+               break;
+       }
+       exitstatus = exerrno;
+       TRACE(("shellexeca failed for %s, errno %d, suppress_int %d\n",
+               realcmd, e, suppress_int));
+       ash_msg_and_raise(EXEXIT, "%s: %s", argv[0], errmsg(e, "not found"));
+       /* NOTREACHED */
+}
+
 static void
 printentry(struct tblentry *cmdp)
 {
@@ -9333,7 +9392,11 @@ execcmd(int argc UNUSED_PARAM, char **argv)
                /*setsignal(SIGTSTP); - unnecessary because of mflag=0 */
                /*setsignal(SIGTTOU); - unnecessary because of mflag=0 */

-               shellexec(argv + 1, pathval(), 0);
+               if (strcmp(argv[1], "-a") == 0 && argv[2]) {
+                       shellexeca(argv + 3, argv[2], pathval(), 0);
+               } else {
+                       shellexec(argv + 1, pathval(), 0);
+               }
                /* NOTREACHED */
        }
        return 0;
--
2.7.4




More information about the busybox mailing list