Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
[PATCH] exec compatibility
- X-seq: zsh-workers 23368
- From: Phil Pennock <zsh-workers+phil.pennock@xxxxxxxxxxxx>
- To: zsh-workers@xxxxxxxxxx
- Subject: [PATCH] exec compatibility
- Date: Mon, 30 Apr 2007 17:26:20 -0700
- Domainkey-signature: a=rsa-sha1; q=dns; c=nofws; s=first1; d=spodhuis.org; h=Received:Date:From:To:Subject:Message-ID:Mail-Followup-To:MIME-Version:Content-Type:Content-Disposition; b=N+d2SnwxhwSOZaKjtRldlNoMgxwilhdcHJRH2rJiXGGugpltEB9W6c82bab7X6wLzGEI2UTmXCIrWrGFmoVs+rUNUgppH6mdbzhlBTMRuGPOMJC1Jiqzvehn2cM4SXTFPYUm/oXkUkRWeIKOkN4WBSneGxkKMyDSRbhYyPgDWPQ=;
- Mail-followup-to: zsh-workers@xxxxxxxxxx
- Mailing-list: contact zsh-workers-help@xxxxxxxxxx; run by ezmlm
I saw two options for cleaning the env:
(1) *environ = NULL;
in zexecve, make setting $_ conditional upon there being any
environmental variables at all
(2) pass a new envp around, which if NULL is new environ.
The second is more intrusive but doesn't have an ugly hack and it does
let _exactly_ the environment specified be passed. I decided that "env"
could easily be a shell builtin if an explicit envp is passed, so
decided in favour of intrusiveness against hackiness.
I think that env-as-builtin is best left pending BINF-handler functions.
So this just leaves the way open.
I know that using a static data-segment variable for an envp is normally
not the best of ideas, I'm relying upon nothing messing with the explict
non-current newenvp before an execve().
-Phil
diff -ur zsh-head/Doc/Zsh/builtins.yo zsh-exec/Doc/Zsh/builtins.yo
--- zsh-head/Doc/Zsh/builtins.yo Fri Mar 23 10:14:05 2007
+++ zsh-exec/Doc/Zsh/builtins.yo Sun Apr 29 21:17:32 2007
@@ -375,7 +375,24 @@
Read the arguments as input to the shell and execute the resulting
command in the current shell process.
)
-prefix(exec)
+findex(exec)
+item(tt(exec) [ tt(-cl) ] [ tt(-a) var(argv0) ] var(simple command))(
+The simple command argument is run in place of the current process,
+rather than as a sub-process. The shell does not fork and is replaced.
+The shell does not invoke tT(TRAPEXIT), nor does it source tt(zlogout)
+files.
+The options are provided for compatibility with other shells.
+The tt(-c) flag clears the environment.
+The tt(-l) flag is equivalent to the tt(-) precommand modifier, to
+treat the replacement command as a login shell; the command is executed
+with a tt(-) prepended to its argv[0] string. This flag has no effect
+if used together with the tt(-a) option.
+The tt(-a) option is used to explicitly specify the argv[0] string to be
+used by the replacement command and is directly equivalent to putting
+the tt($ARGV0) variable into the environment.
+
+See also noderef(Precommand Modifiers).
+)
findex(exit)
item(tt(exit) [ var(n) ])(
Exit the shell with the exit status specified by var(n); if none
diff -ur zsh-head/Src/exec.c zsh-exec/Src/exec.c
--- zsh-head/Src/exec.c Wed Feb 14 00:21:58 2007
+++ zsh-exec/Src/exec.c Mon Apr 30 17:08:57 2007
@@ -144,6 +144,7 @@
static int doneps4;
static char *STTYval;
+static char *blank_env[] = { NULL };
/* Execution functions. */
@@ -361,7 +362,7 @@
/**/
static int
-zexecve(char *pth, char **argv)
+zexecve(char *pth, char **argv, char **newenvp)
{
int eno;
static char buf[PATH_MAX * 2];
@@ -379,7 +380,10 @@
sprintf(buf + 2, "%s/%s", pwd, pth);
zputenv(buf);
closedumps();
- execve(pth, argv, environ);
+
+ if (newenvp == NULL)
+ newenvp = environ;
+ execve(pth, argv, newenvp);
/* If the execve returns (which in general shouldn't happen), *
* then check for an errno equal to ENOEXEC. This errno is set *
@@ -414,14 +418,14 @@
*ptr = '\0';
argv[-2] = ptr2;
argv[-1] = ptr + 1;
- execve(ptr2, argv - 2, environ);
+ execve(ptr2, argv - 2, newenvp);
} else {
argv[-1] = ptr2;
- execve(ptr2, argv - 1, environ);
+ execve(ptr2, argv - 1, newenvp);
}
} else if (eno == ENOEXEC) {
argv[-1] = "sh";
- execve("/bin/sh", argv - 1, environ);
+ execve("/bin/sh", argv - 1, newenvp);
}
} else if (eno == ENOEXEC) {
for (t0 = 0; t0 != ct; t0++)
@@ -429,7 +433,7 @@
break;
if (t0 == ct) {
argv[-1] = "sh";
- execve("/bin/sh", argv - 1, environ);
+ execve("/bin/sh", argv - 1, newenvp);
}
}
} else
@@ -467,13 +471,13 @@
/* execute an external command */
/**/
-void
-execute(LinkList args, int dash, int defpath)
+static void
+execute(LinkList args, int flags, int defpath)
{
Cmdnam cn;
char buf[MAXCMDLEN], buf2[MAXCMDLEN];
char *s, *z, *arg0;
- char **argv, **pp;
+ char **argv, **pp, **newenvp = NULL;
int eno = 0, ee;
arg0 = (char *) peekfirst(args);
@@ -502,7 +506,7 @@
if (unset(RESTRICTED) && (z = zgetenv("ARGV0"))) {
setdata(firstnode(args), (void *) ztrdup(z));
delenvvalue(z - 6);
- } else if (dash) {
+ } else if (flags & BINF_DASH) {
/* Else if the pre-command `-' was given, we add `-' *
* to the front of argv[0] for this command. */
sprintf(buf2, "-%s", arg0);
@@ -510,6 +514,9 @@
}
argv = makecline(args);
+ if (flags & BINF_CLEARENV)
+ newenvp = blank_env;
+
/*
* Note that we don't close fd's attached to process substitution
* here, which should be visible to external processes.
@@ -522,7 +529,7 @@
}
for (s = arg0; *s; s++)
if (*s == '/') {
- int lerrno = zexecve(arg0, argv);
+ int lerrno = zexecve(arg0, argv, newenvp);
if (arg0 == s || unset(PATHDIRS) ||
(arg0[0] == '.' && (arg0 + 1 == s ||
(arg0[1] == '.' && arg0 + 2 == s)))) {
@@ -559,7 +566,7 @@
_exit(127);
}
- ee = zexecve(pbuf, argv);
+ ee = zexecve(pbuf, argv, newenvp);
if ((dptr = strrchr(pbuf, '/')))
*dptr = '\0';
@@ -576,7 +583,7 @@
else {
for (pp = path; pp < cn->u.name; pp++)
if (!**pp || (**pp == '.' && (*pp)[1] == '\0')) {
- ee = zexecve(arg0, argv);
+ ee = zexecve(arg0, argv, newenvp);
if (isgooderr(ee, *pp))
eno = ee;
} else if (**pp != '/') {
@@ -584,7 +591,7 @@
strucpy(&z, *pp);
*z++ = '/';
strcpy(z, arg0);
- ee = zexecve(buf, argv);
+ ee = zexecve(buf, argv, newenvp);
if (isgooderr(ee, *pp))
eno = ee;
}
@@ -592,7 +599,7 @@
strcat(nn, "/");
strcat(nn, cn->node.nam);
}
- ee = zexecve(nn, argv);
+ ee = zexecve(nn, argv, newenvp);
if ((dptr = strrchr(nn, '/')))
*dptr = '\0';
@@ -601,7 +608,7 @@
}
for (pp = path; *pp; pp++)
if (!(*pp)[0] || ((*pp)[0] == '.' && !(*pp)[1])) {
- ee = zexecve(arg0, argv);
+ ee = zexecve(arg0, argv, newenvp);
if (isgooderr(ee, *pp))
eno = ee;
} else {
@@ -609,7 +616,7 @@
strucpy(&z, *pp);
*z++ = '/';
strcpy(z, arg0);
- ee = zexecve(buf, argv);
+ ee = zexecve(buf, argv, newenvp);
if (isgooderr(ee, *pp))
eno = ee;
}
@@ -2026,6 +2033,49 @@
if (!strcmp(next, "--"))
uremnode(args, firstnode(args));
}
+ if (cflags & BINF_EXEC && nextnode(firstnode(args))) {
+ /* check for compatibility options to exec builtin */
+ char *next = (char *) getdata(nextnode(firstnode(args)));
+ char *cmdopt, *exec_argv0 = NULL;
+ while (next && *next == '-' && strlen(next) >= 2) {
+ uremnode(args, firstnode(args));
+ if (!strcmp(next, "--"))
+ break;
+ for (cmdopt = &next[1]; *cmdopt; ++cmdopt) {
+ switch (*cmdopt) {
+ case 'a':
+ exec_argv0 = (char *) getdata(nextnode(firstnode(args)));
+ if (!exec_argv0) {
+ zerr("exec flag -a requires a parameter");
+ errflag = lastval = 1;
+ return;
+ }
+ uremnode(args, firstnode(args));
+ break;
+ case 'c':
+ cflags |= BINF_CLEARENV;
+ break;
+ case 'l':
+ cflags |= BINF_DASH;
+ break;
+ default:
+ zerr("unknown exec flag -%c", *cmdopt);
+ errflag = lastval = 1;
+ return;
+ }
+ }
+ next = (char *) getdata(nextnode(firstnode(args)));
+ }
+ if (exec_argv0) {
+ char *str, *s;
+ size_t sz = strlen(exec_argv0);
+ str = s = zalloc(5 + 1 + sz + 1);
+ strcpy(s, "ARGV0=");
+ s+=6;
+ strcpy(s, exec_argv0);
+ zputenv(str);
+ }
+ }
uremnode(args, firstnode(args));
hn = NULL;
if ((cflags & BINF_COMMAND) && unset(POSIXBUILTINS))
@@ -2726,7 +2776,7 @@
zsfree(STTYval);
STTYval = 0;
}
- execute(args, cflags & BINF_DASH, use_defpath);
+ execute(args, cflags, use_defpath);
} else { /* ( ... ) */
DPUTS(varspc,
"BUG: assignment before complex command");
diff -ur zsh-head/Src/zsh.h zsh-exec/Src/zsh.h
--- zsh-head/Src/zsh.h Thu Mar 29 14:35:39 2007
+++ zsh-exec/Src/zsh.h Mon Apr 30 16:32:26 2007
@@ -1143,6 +1143,7 @@
#define BINF_KEEPNUM (1<<13) /* `[-+]NUM' can be an option */
#define BINF_SKIPDASH (1<<14) /* Treat `-' as argument (maybe `+') */
#define BINF_DASHDASHVALID (1<<15) /* Handle `--' even if SKIPINVALD */
+#define BINF_CLEARENV (1<<16) /* new process started with cleared env */
struct module {
char *nam;
Messages sorted by:
Reverse Date,
Date,
Thread,
Author