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