summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog7
-rw-r--r--Src/exec.c7
-rw-r--r--Src/init.c20
-rw-r--r--Src/utils.c38
4 files changed, 52 insertions, 20 deletions
diff --git a/ChangeLog b/ChangeLog
index ea4e3673d..600a859d6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2010-07-15  Peter Stephenson  <p.w.stephenson@ntlworld.com>
+
+	* 28073: Src/exec.c, Src/init.c, Src/utils.c: allow #!
+	scripts to search path if interpreter not found.
+
 2010-07-15  Doug Kearns  <dougkearns@gmail.com>
 
 	* 28078: Completion/Unix/Command/_xmlsoft: update.
@@ -13374,5 +13379,5 @@
 
 *****************************************************
 * This is used by the shell to define $ZSH_PATCHLEVEL
-* $Revision: 1.5025 $
+* $Revision: 1.5026 $
 *****************************************************
diff --git a/Src/exec.c b/Src/exec.c
index 6611e9c79..73b4c01a8 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -461,8 +461,15 @@ zexecve(char *pth, char **argv, char **newenvp)
 			for (ptr = execvebuf + 2; *ptr && *ptr == ' '; ptr++);
 			for (ptr2 = ptr; *ptr && *ptr != ' '; ptr++);
 			if (eno == ENOENT) {
+			    char *pprog;
 			    if (*ptr)
 				*ptr = '\0';
+			    if (*ptr2 != '/' &&
+				(pprog = pathprog(ptr2, NULL))) {
+				argv[-2] = ptr2;
+				argv[-1] = ptr + 1;
+				execve(pprog, argv - 2, newenvp);
+			    }
 			    zerr("%s: bad interpreter: %s: %e", pth, ptr2,
 				 eno);
 			} else if (*ptr) {
diff --git a/Src/init.c b/Src/init.c
index 06f177725..e85d3875a 100644
--- a/Src/init.c
+++ b/Src/init.c
@@ -949,25 +949,7 @@ setupshin(char *runscript)
 	     * With the PATHSCRIPT option, search the path if no
 	     * path was given in the script name.
 	     */
-	    char **pp, ppmaxlen = 0, *buf;
-	    for (pp = path; *pp; pp++)
-	    {
-		int len = strlen(*pp);
-		if (len > ppmaxlen)
-		    ppmaxlen = len;
-	    }
-	    buf = zhalloc(ppmaxlen + strlen(runscript) + 2);
-	    for (pp = path; *pp; pp++) {
-		sprintf(buf, "%s/%s", *pp, runscript);
-		/* careful, static buffer used in open() later */
-		funmeta = unmeta(buf);
-		if (access(funmeta, F_OK) == 0 &&
-		    stat(funmeta, &st) >= 0 &&
-		    !S_ISDIR(st.st_mode)) {
-		    sfname = buf;
-		    break;
-		}
-	    }
+	    funmeta = pathprog(runscript, &sfname);
 	}
 	if (!sfname ||
 	    (SHIN = movefd(open(funmeta, O_RDONLY | O_NOCTTY)))
diff --git a/Src/utils.c b/Src/utils.c
index 379f9f738..f311abd05 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -606,6 +606,44 @@ zwcwidth(wint_t wc)
 /**/
 #endif /* MULTIBYTE_SUPPORT */
 
+/*
+ * Search the path for prog and return the file name.
+ * The returned value is unmetafied and in the unmeta storage
+ * area (N.B. should be duplicated if not used immediately and not
+ * equal to *namep).
+ *
+ * If namep is not NULL, *namep is set to the metafied programme
+ * name, which is in heap storage.
+ */
+/**/
+char *
+pathprog(char *prog, char **namep)
+{
+    char **pp, ppmaxlen = 0, *buf, *funmeta;
+    struct stat st;
+
+    for (pp = path; *pp; pp++)
+    {
+	int len = strlen(*pp);
+	if (len > ppmaxlen)
+	    ppmaxlen = len;
+    }
+    buf = zhalloc(ppmaxlen + strlen(prog) + 2);
+    for (pp = path; *pp; pp++) {
+	sprintf(buf, "%s/%s", *pp, prog);
+	funmeta = unmeta(buf);
+	if (access(funmeta, F_OK) == 0 &&
+	    stat(funmeta, &st) >= 0 &&
+	    !S_ISDIR(st.st_mode)) {
+	    if (namep)
+		*namep = buf;
+	    return funmeta;
+	}
+    }
+
+    return NULL;
+}
+
 /* get a symlink-free pathname for s relative to PWD */
 
 /**/