1 /* -----------------------------------------------------------------------------
2    (c) The University of Glasgow 1995-2004
3 
4    Our low-level exec() variant.
5 
6    Note: __hsunix_execvpe() is very similiar to the function
7          execvpe(3) as provided by glibc 2.11 and later. However, if
8          execvpe(3) is available, we use that instead.
9 
10    -------------------------------------------------------------------------- */
11 
12 #include "HsUnixConfig.h"
13 
14 #include <errno.h>
15 #include <sys/types.h>
16 #if HAVE_SYS_WAIT_H
17 # include <sys/wait.h>
18 #endif
19 #include <unistd.h>
20 #include <sys/time.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <errno.h>
24 
25 #define HSUNIX_EXECVPE_H_NO_COMPAT
26 #include "execvpe.h"
27 
28 #if !defined(execvpe) && !HAVE_DECL_EXECVPE
29 // On some archs such as AIX, the prototype may be missing
30 int execvpe(const char *file, char *const argv[], char *const envp[]);
31 #endif
32 
33 /*
34  * We want the search semantics of execvp, but we want to provide our
35  * own environment, like execve.  The following copyright applies to
36  * this code, as it is a derivative of execvp:
37  *-
38  * Copyright (c) 1991 The Regents of the University of California.
39  * All rights reserved.
40  *
41  * Redistribution and use in source and binary forms, with or without
42  * modification, are permitted provided that the following conditions
43  * are met:
44  * 1. Redistributions of source code must retain the above copyright
45  *    notice, this list of conditions and the following disclaimer.
46  * 2. Redistributions in binary form must reproduce the above copyright
47  *    notice, this list of conditions and the following disclaimer in the
48  *    documentation and/or other materials provided with the distribution.
49  * 3. All advertising materials mentioning features or use of this software
50  *    must display the following acknowledgement:
51  *	This product includes software developed by the University of
52  *	California, Berkeley and its contributors.
53  * 4. Neither the name of the University nor the names of its contributors
54  *    may be used to endorse or promote products derived from this software
55  *    without specific prior written permission.
56  *
57  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
58  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
59  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
60  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
61  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
62  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
63  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
64  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
65  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
66  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
67  * SUCH DAMAGE.
68  */
69 
70 int
__hsunix_execvpe(const char * name,char * const argv[],char * const envp[])71 __hsunix_execvpe(const char *name, char *const argv[], char *const envp[])
72 {
73 #if HAVE_EXECVPE
74     return execvpe(name, argv, envp);
75 #else
76     register int lp, ln;
77     register char *p;
78     int eacces=0, etxtbsy=0;
79     char *bp, *cur, *path, *buf = 0;
80 
81     /* If it's an absolute or relative path name, it's easy. */
82     if (strchr(name, '/')) {
83 	bp = (char *) name;
84 	cur = path = buf = NULL;
85 	goto retry;
86     }
87 
88     /* Get the path we're searching. */
89     if (!(path = getenv("PATH"))) {
90 # ifdef HAVE_CONFSTR
91         ln = confstr(_CS_PATH, NULL, 0);
92         if ((cur = path = malloc(ln + 1)) != NULL) {
93 	    path[0] = ':';
94 	    (void) confstr (_CS_PATH, path + 1, ln);
95 	}
96 # else
97         if ((cur = path = malloc(1 + 1)) != NULL) {
98 	    path[0] = ':';
99 	    path[1] = '\0';
100 	}
101 # endif
102     } else
103 	cur = path = strdup(path);
104 
105     if (path == NULL || (bp = buf = malloc(strlen(path)+strlen(name)+2)) == NULL)
106 	goto done;
107 
108     while (cur != NULL) {
109 	p = cur;
110         if ((cur = strchr(cur, ':')) != NULL)
111 	    *cur++ = '\0';
112 
113 	/*
114 	 * It's a SHELL path -- double, leading and trailing colons mean the current
115 	 * directory.
116 	 */
117 	if (!*p) {
118 	    p = ".";
119 	    lp = 1;
120 	} else
121 	    lp = strlen(p);
122 	ln = strlen(name);
123 
124 	memcpy(buf, p, lp);
125 	buf[lp] = '/';
126 	memcpy(buf + lp + 1, name, ln);
127 	buf[lp + ln + 1] = '\0';
128 
129       retry:
130         (void) execve(bp, argv, envp);
131 	switch (errno) {
132 	case EACCES:
133 	    eacces = 1;
134 	    break;
135 	case ENOTDIR:
136 	case ENOENT:
137 	    break;
138 	case ENOEXEC:
139 	    {
140 		register size_t cnt;
141 		register char **ap;
142 
143 		for (cnt = 0, ap = (char **) argv; *ap; ++ap, ++cnt)
144 		    ;
145 		if ((ap = malloc((cnt + 2) * sizeof(char *))) != NULL) {
146 		    memcpy(ap + 2, argv + 1, cnt * sizeof(char *));
147 
148 		    ap[0] = "sh";
149 		    ap[1] = bp;
150 		    (void) execve("/bin/sh", ap, envp);
151 		    free(ap);
152 		}
153 		goto done;
154 	    }
155 	case ETXTBSY:
156 	    if (etxtbsy < 3)
157 		(void) sleep(++etxtbsy);
158 	    goto retry;
159 	default:
160 	    goto done;
161 	}
162     }
163     if (eacces)
164 	errno = EACCES;
165     else if (!errno)
166 	errno = ENOENT;
167   done:
168     if (path)
169 	free(path);
170     if (buf)
171 	free(buf);
172     return (-1);
173 #endif
174 }
175