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