From 7e57c03a450d2d2bd53912dae10f3f83d0bdd68b Mon Sep 17 00:00:00 2001 From: jpco Date: Sun, 21 Jan 2024 10:34:12 -0800 Subject: [PATCH 1/4] Route all binary fork/execing through the %run hook command (or the $&run primitive, if %run is unset). --- doc/es.1 | 18 +++++++-------- es.h | 1 - eval.c | 65 +++++++++++++++++------------------------------------- prim-sys.c | 41 ++++++++++++++++++++++++++++++++++ 4 files changed, 70 insertions(+), 55 deletions(-) diff --git a/doc/es.1 b/doc/es.1 index 65f39e62..f0f056d1 100644 --- a/doc/es.1 +++ b/doc/es.1 @@ -2514,6 +2514,15 @@ to the name of a file which contains the output of running the command .IR input . .TP +.Cr "%run \fIprogram argv0 args ...\fP" +Run the named program, which is not searched for in +.Cr $path , +with the argument vector set to the remaining arguments. +This builtin can be used to set +.Cr argv[0] +(by convention, the name of the program) +to something other than file name. +.TP .Cr "%seq \fIcmd ...\fP" Runs the commands, in order. .TP @@ -2562,15 +2571,6 @@ rather than .Cr "%newfd" Returns a file descriptor that the shell thinks is not currently in use. .TP -.Cr "%run \fIprogram argv0 args ...\fP" -Run the named program, which is not searched for in -.Cr $path , -with the argument vector set to the remaining arguments. -This builtin can be used to set -.Cr argv[0] -(by convention, the name of the program) -to something other than file name. -.TP .Cr "%split \fIseparator \fR[\fPargs ...\fR]" Splits its arguments into separate strings at every occurrence of any of the characters in the string diff --git a/es.h b/es.h index a8f6f733..42515a7b 100644 --- a/es.h +++ b/es.h @@ -150,7 +150,6 @@ extern Binding *reversebindings(Binding *binding); /* eval.c */ extern Binding *bindargs(Tree *params, List *args, Binding *binding); -extern List *forkexec(char *file, List *list, Boolean inchild); extern List *walk(Tree *tree, Binding *binding, int flags); extern List *eval(List *list, Binding *binding, int flags); extern List *eval1(Term *term, int flags); diff --git a/eval.c b/eval.c index b603a486..eac0dd42 100644 --- a/eval.c +++ b/eval.c @@ -4,47 +4,6 @@ unsigned long evaldepth = 0, maxevaldepth = MAXmaxevaldepth; -static noreturn failexec(char *file, List *args) { - List *fn; - assert(gcisblocked()); - fn = varlookup("fn-%exec-failure", NULL); - if (fn != NULL) { - int olderror = errno; - Ref(List *, list, append(fn, mklist(mkstr(file), args))); - RefAdd(file); - gcenable(); - RefRemove(file); - eval(list, NULL, 0); - RefEnd(list); - errno = olderror; - } - eprint("%s: %s\n", file, esstrerror(errno)); - exit(1); -} - -/* forkexec -- fork (if necessary) and exec */ -extern List *forkexec(char *file, List *list, Boolean inchild) { - int pid, status; - Vector *env; - gcdisable(); - env = mkenv(); - pid = efork(!inchild, FALSE); - if (pid == 0) { - execve(file, vectorize(list)->vector, env->vector); - failexec(file, list); - } - gcenable(); - status = ewaitfor(pid); - if ((status & 0xff) == 0) { - sigint_newline = FALSE; - SIGCHK(); - sigint_newline = TRUE; - } else - SIGCHK(); - printstatus(0, status); - return mklist(mkterm(mkstatus(status), NULL), NULL); -} - /* assign -- bind a list of values to a list of variables */ static List *assign(Tree *varform, Tree *valueform0, Binding *binding0) { Ref(List *, result, NULL); @@ -355,6 +314,22 @@ extern List *pathsearch(Term *term) { return eval(append(search, list), NULL, 0); } +static List *mkrunhook(char *bin, List *list0) { + Ref(List *, list, list0); + Ref(Term *, t, mkstr(bin)); + list = mklist(t, list); + + Ref(List *, run, varlookup("fn-%run", NULL)); + if (run == NULL) { + t = mkterm(NULL, mkclosure(mk(nPrim, "run"), NULL)); + list = mklist(t, list); + } else + list = append(run, list); + + RefEnd2(run, t); + RefReturn(list); +} + /* eval -- evaluate a list, producing a list */ extern List *eval(List *list0, Binding *binding0, int flags) { Closure *volatile cp; @@ -440,9 +415,9 @@ extern List *eval(List *list0, Binding *binding0, int flags) { char *error = checkexecutable(name); if (error != NULL) fail("$&whatis", "%s: %s", name, error); - list = forkexec(name, list, flags & eval_inchild); + list = mkrunhook(name, list); RefPop(name); - goto done; + goto restart; } RefEnd(name); @@ -450,8 +425,8 @@ extern List *eval(List *list0, Binding *binding0, int flags) { if (fn != NULL && fn->next == NULL && (cp = getclosure(fn->term)) == NULL) { char *name = getstr(fn->term); - list = forkexec(name, list, flags & eval_inchild); - goto done; + list = mkrunhook(name, list); + goto restart; } list = append(fn, list->next); diff --git a/prim-sys.c b/prim-sys.c index 9ad53ab6..e8ae882e 100644 --- a/prim-sys.c +++ b/prim-sys.c @@ -66,6 +66,47 @@ PRIM(fork) { return mklist(mkstr(mkstatus(status)), NULL); } +static noreturn failexec(char *file, List *args) { + List *fn; + assert(gcisblocked()); + fn = varlookup("fn-%exec-failure", NULL); + if (fn != NULL) { + int olderror = errno; + Ref(List *, list, append(fn, mklist(mkstr(file), args))); + RefAdd(file); + gcenable(); + RefRemove(file); + eval(list, NULL, 0); + RefEnd(list); + errno = olderror; + } + eprint("%s: %s\n", file, esstrerror(errno)); + exit(1); +} + +/* forkexec -- fork (if necessary) and exec */ +static List *forkexec(char *file, List *list, Boolean inchild) { + int pid, status; + Vector *env; + gcdisable(); + env = mkenv(); + pid = efork(!inchild, FALSE); + if (pid == 0) { + execve(file, vectorize(list)->vector, env->vector); + failexec(file, list); + } + gcenable(); + status = ewaitfor(pid); + if ((status & 0xff) == 0) { + sigint_newline = FALSE; + SIGCHK(); + sigint_newline = TRUE; + } else + SIGCHK(); + printstatus(0, status); + return mklist(mkterm(mkstatus(status), NULL), NULL); +} + PRIM(run) { char *file; if (list == NULL) From 6c83deb83987b885b65b681009f4fa5a2684c9fe Mon Sep 17 00:00:00 2001 From: jpco Date: Mon, 8 Jul 2024 14:45:14 -0700 Subject: [PATCH 2/4] Throw an error if %run is undefined instead of doing anything special. --- eval.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/eval.c b/eval.c index eac0dd42..d2f0f204 100644 --- a/eval.c +++ b/eval.c @@ -314,19 +314,18 @@ extern List *pathsearch(Term *term) { return eval(append(search, list), NULL, 0); } -static List *mkrunhook(char *bin, List *list0) { +static List *mkrunhook(char *bin0, List *list0) { Ref(List *, list, list0); + Ref(char *, bin, bin0); Ref(Term *, t, mkstr(bin)); list = mklist(t, list); Ref(List *, run, varlookup("fn-%run", NULL)); - if (run == NULL) { - t = mkterm(NULL, mkclosure(mk(nPrim, "run"), NULL)); - list = mklist(t, list); - } else - list = append(run, list); + if (run == NULL) + fail("es:eval", "%s: fn %%run undefined", bin); + list = append(run, list); - RefEnd2(run, t); + RefEnd3(run, t, bin); RefReturn(list); } From 44a3d08cb27dc410b7f54060c3d10b937e7bcca2 Mon Sep 17 00:00:00 2001 From: jpco Date: Tue, 8 Oct 2024 22:25:57 -0700 Subject: [PATCH 3/4] Simplify %run hooking. --- eval.c | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/eval.c b/eval.c index 68c6f344..caed82be 100644 --- a/eval.c +++ b/eval.c @@ -314,21 +314,6 @@ extern List *pathsearch(Term *term) { return eval(append(search, list), NULL, 0); } -static List *mkrunhook(char *bin0, List *list0) { - Ref(List *, list, list0); - Ref(char *, bin, bin0); - Ref(Term *, t, mkstr(bin)); - list = mklist(t, list); - - Ref(List *, run, varlookup("fn-%run", NULL)); - if (run == NULL) - fail("es:eval", "%s: fn %%run undefined", bin); - list = append(run, list); - - RefEnd3(run, t, bin); - RefReturn(list); -} - /* eval -- evaluate a list, producing a list */ extern List *eval(List *list0, Binding *binding0, int flags) { Closure *volatile cp; @@ -423,7 +408,9 @@ extern List *eval(List *list0, Binding *binding0, int flags) { char *error = checkexecutable(name); if (error != NULL) fail("$&whatis", "%s: %s", name, error); - list = mkrunhook(name, list); + gcdisable(); + list = mklist(mkstr("%run"), mklist(mkstr(name), list)); + gcenable(); RefPop(name); goto restart; } @@ -433,7 +420,9 @@ extern List *eval(List *list0, Binding *binding0, int flags) { if (fn != NULL && fn->next == NULL && (cp = getclosure(fn->term)) == NULL) { char *name = getstr(fn->term); - list = mkrunhook(name, list); + gcdisable(); + list = mklist(mkstr("%run"), mklist(mkstr(name), list)); + gcenable(); goto restart; } From d70b59b7b3ad5fb781c1c316dbec97a4c7deec65 Mon Sep 17 00:00:00 2001 From: jpco Date: Fri, 1 Nov 2024 14:53:26 -0700 Subject: [PATCH 4/4] noreturn -> Noreturn --- prim-sys.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prim-sys.c b/prim-sys.c index f4b69a67..916ca335 100644 --- a/prim-sys.c +++ b/prim-sys.c @@ -66,7 +66,7 @@ PRIM(fork) { return mklist(mkstr(mkstatus(status)), NULL); } -static noreturn failexec(char *file, List *args) { +static Noreturn failexec(char *file, List *args) { List *fn; assert(gcisblocked()); fn = varlookup("fn-%exec-failure", NULL);