Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: [PATCH] exec compatibility



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 <pws@xxxxxxx>                  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



Messages sorted by: Reverse Date, Date, Thread, Author