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;