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