From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 12160 invoked from network); 4 May 2007 12:00:51 -0000 X-Spam-Checker-Version: SpamAssassin 3.2.0 (2007-05-01) on f.primenet.com.au X-Spam-Level: X-Spam-Status: No, score=-2.5 required=5.0 tests=AWL,BAYES_00 autolearn=no version=3.2.0 Received: from news.dotsrc.org (HELO a.mx.sunsite.dk) (130.225.247.88) by ns1.primenet.com.au with SMTP; 4 May 2007 12:00:51 -0000 Received-SPF: none (ns1.primenet.com.au: domain at sunsite.dk does not designate permitted sender hosts) Received: (qmail 1039 invoked from network); 4 May 2007 12:00:45 -0000 Received: from sunsite.dk (130.225.247.90) by a.mx.sunsite.dk with SMTP; 4 May 2007 12:00:45 -0000 Received: (qmail 15719 invoked by alias); 4 May 2007 12:00:42 -0000 Mailing-List: contact zsh-workers-help@sunsite.dk; run by ezmlm Precedence: bulk X-No-Archive: yes X-Seq: 23391 Received: (qmail 15710 invoked from network); 4 May 2007 12:00:42 -0000 Received: from news.dotsrc.org (HELO a.mx.sunsite.dk) (130.225.247.88) by sunsite.dk with SMTP; 4 May 2007 12:00:42 -0000 Received: (qmail 808 invoked from network); 4 May 2007 12:00:42 -0000 Received: from cluster-d.mailcontrol.com (217.69.20.190) by a.mx.sunsite.dk with SMTP; 4 May 2007 12:00:37 -0000 Received: from cameurexb01.EUROPE.ROOT.PRI ([62.189.241.200]) by rly21d.srv.mailcontrol.com (MailControl) with ESMTP id l44C0NqE013806 for ; Fri, 4 May 2007 13:00:24 +0100 Received: from news01.csr.com ([10.103.143.38]) by cameurexb01.EUROPE.ROOT.PRI with Microsoft SMTPSVC(6.0.3790.1830); Fri, 4 May 2007 13:00:23 +0100 Date: Fri, 4 May 2007 13:00:23 +0100 From: Peter Stephenson To: zsh-workers@sunsite.dk Subject: Re: [PATCH] exec compatibility Message-Id: <20070504130023.df33e042.pws@csr.com> In-Reply-To: <20070501002620.GA95730@redoubt.spodhuis.org> References: <20070501002620.GA95730@redoubt.spodhuis.org> Organization: Cambridge Silicon Radio X-Mailer: Sylpheed version 2.2.10 (GTK+ 2.10.8; i386-redhat-linux-gnu) Mime-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit X-OriginalArrivalTime: 04 May 2007 12:00:23.0579 (UTC) FILETIME=[CBC1FEB0:01C78E43] X-Scanned-By: MailControl A-06-00-00 (www.mailcontrol.com) on 10.68.0.131 This is what I've ended up with for the exec patch. I've tweaked the following: - Add parentheses around (cflags & BINF_EXEC). - Handle "exec -aname" with no space. - Error handling on "exec -a" with no argument tests the presence of the node rather than dereferencing to get the data. - Added a couple of minor comments in exec.c - Tweaked the documentation: moved the exec doc back to the precommand modifiers section, and also moved all findex() markers for precommand modifiers into there---if you looked in the index you just got taken to an entry that said "see Precommand Modifiers", which was stupid (it's always been this way). - Added some tests to A01grammar.ztst. I'm not sure how much to worry about compatibilty with previous uses of "exec -prog" which tried to execute a programme "-prog". This was never very portable, but it was a simple rule. I've added a note to README. It's a bit nasty that other precommand modifiers don't even handle "--" to indicate the next word isn't an option. Maybe if we change exec in this fashion we should at least do that. Index: README =================================================================== RCS file: /cvsroot/zsh/zsh/README,v retrieving revision 1.43 diff -u -r1.43 README --- README 1 May 2007 09:29:35 -0000 1.43 +++ README 4 May 2007 11:56:05 -0000 @@ -40,6 +40,14 @@ applies to expressions with forced splitting such as ${=1+"$@"}, but otherwise the case where SH_WORD_SPLIT is not set is unaffected. +The "exec" precommand modifier now takes various options for compatibility +with other shells. This means that whereas "exec -prog" previously +tried to execute a command name "-prog", it will now report an error +in option handling. "exec -- -prog" will execute "-prog". If +the option EQUALS is set, as it is by default in zsh's native mode, +"exec =-prog" behaves the same way in all versions of zsh provided +the command can be found. + The "unset" builtin now does not regard the unsetting of non-existent variables as an error, so can still return status 0 (depending on the handling of other arguments). This appears to be the standard shell Index: Doc/Zsh/builtins.yo =================================================================== RCS file: /cvsroot/zsh/zsh/Doc/Zsh/builtins.yo,v retrieving revision 1.92 diff -u -r1.92 builtins.yo --- Doc/Zsh/builtins.yo 23 Mar 2007 17:14:05 -0000 1.92 +++ Doc/Zsh/builtins.yo 4 May 2007 11:56:06 -0000 @@ -6,7 +6,6 @@ cindex(builtin commands) cindex(commands, builtin) def(prefix)(1)(\ -findex(ARG1) item(tt(ARG1) var(simple command))( See noderef(Precommand Modifiers). )\ @@ -375,7 +374,9 @@ Read the arguments as input to the shell and execute the resulting command in the current shell process. ) -prefix(exec) +item(tt(exec) [ tt(-cl) ] [ tt(-a) var(argv0) ] var(simple command))( +See noderef(Precommand Modifiers). +) findex(exit) item(tt(exit) [ var(n) ])( Exit the shell with the exit status specified by var(n); if none Index: Doc/Zsh/grammar.yo =================================================================== RCS file: /cvsroot/zsh/zsh/Doc/Zsh/grammar.yo,v retrieving revision 1.12 diff -u -r1.12 grammar.yo --- Doc/Zsh/grammar.yo 19 Jan 2007 21:36:03 -0000 1.12 +++ Doc/Zsh/grammar.yo 4 May 2007 11:56:06 -0000 @@ -105,26 +105,48 @@ a reserved word. startitem() +findex(-) item(tt(-))( The command is executed with a `tt(-)' prepended to its tt(argv[0]) string. ) +findex(noglob) item(tt(noglob))( Filename generation (globbing) is not performed on any of the words. ) +findex(nocorrect) item(tt(nocorrect))( Spelling correction is not done on any of the words. This must appear before any other precommand modifier, as it is interpreted immediately, before any parsing is done. It has no effect in non-interactive shells. ) -item(tt(exec))( -The command is executed in the parent shell without forking. +findex(exec) +item(tt(exec) [ tt(-cl) ] [ tt(-a) var(argv0) ] var(simple command))( +The var(simple command) (a set of commands and arguments) 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) option clears the environment. + +The tt(-l) option 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 tt(argv[0]) string. This flag has no effect +if used together with the tt(-a) option. + +The tt(-a) option is used to specify explicitly the tt(argv[0]) string +(the name of the command as seen by the process itself) to be used by the +replacement command and is directly equivalent to setting a value +for the tt(ARGV0) environment variable. ) +findex(command) item(tt(command))( The command word is taken to be the name of an external command, rather than a shell function or builtin. ) +findex(builtin) item(tt(builtin))( The command word is taken to be the name of a builtin command, rather than a shell function or external command. Index: Src/exec.c =================================================================== RCS file: /cvsroot/zsh/zsh/Src/exec.c,v retrieving revision 1.110 diff -u -r1.110 exec.c --- Src/exec.c 14 Feb 2007 08:21:58 -0000 1.110 +++ Src/exec.c 4 May 2007 11:56:07 -0000 @@ -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; } @@ -2024,7 +2031,63 @@ } } if (!strcmp(next, "--")) - uremnode(args, firstnode(args)); + uremnode(args, firstnode(args)); + } + if ((cflags & BINF_EXEC) && nextnode(firstnode(args))) { + /* + * Check for compatibility options to exec builtin. + * It would be nice to do these more generically, + * but currently we don't have a mechanism for + * precommand modifiers. + */ + 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': + /* argument is ARGV0 string */ + if (cmdopt[1]) { + exec_argv0 = cmdopt+1; + /* position on last non-NULL character */ + cmdopt += strlen(cmdopt+1); + } else { + if (!nextnode(firstnode(args))) { + zerr("exec flag -a requires a parameter"); + errflag = lastval = 1; + return; + } + exec_argv0 = (char *) + getdata(nextnode(firstnode(args))); + 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; @@ -2726,7 +2789,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"); Index: Src/zsh.h =================================================================== RCS file: /cvsroot/zsh/zsh/Src/zsh.h,v retrieving revision 1.113 diff -u -r1.113 zsh.h --- Src/zsh.h 1 May 2007 22:05:06 -0000 1.113 +++ Src/zsh.h 4 May 2007 11:56:07 -0000 @@ -1144,6 +1144,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; Index: Test/A01grammar.ztst =================================================================== RCS file: /cvsroot/zsh/zsh/Test/A01grammar.ztst,v retrieving revision 1.13 diff -u -r1.13 A01grammar.ztst --- Test/A01grammar.ztst 19 Jan 2007 21:36:04 -0000 1.13 +++ Test/A01grammar.ztst 4 May 2007 11:56:07 -0000 @@ -62,6 +62,22 @@ (exec /bin/sh; echo bar) 0:`exec' precommand modifier + (exec -l /bin/sh -c 'echo $0') +0:`exec' with -l option +>-/bin/sh + + (exec -a /bin/SPLATTER /bin/sh -c 'echo $0') +0:`exec' with -a option +>/bin/SPLATTER + + (exec -a/bin/SPLOOSH /bin/sh -c 'echo $0') +0:`exec' with -a option, no space +>/bin/SPLOOSH + + (export FOO=bar; exec -c /bin/sh -c 'echo x${FOO}x') +0:`exec' with -c option +>xx + cat() { echo Function cat executed; } command cat && unfunction cat 0:`command' precommand modifier -- Peter Stephenson Software Engineer CSR PLC, Churchill House, Cambridge Business Park, Cowley Road Cambridge, CB4 0WZ, UK Tel: +44 (0)1223 692070 To access the latest news from CSR copy this link into a web browser: http://www.csr.com/email_sig.php To get further information regarding CSR, please visit our Investor Relations page at http://ir.csr.com/csr/about/overview