]> git.saurik.com Git - apple/libc.git/blob - gen/FreeBSD/exec.c
Libc-1353.11.2.tar.gz
[apple/libc.git] / gen / FreeBSD / exec.c
1 /*-
2 * Copyright (c) 1991, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 4. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30 #if defined(LIBC_SCCS) && !defined(lint)
31 static char sccsid[] = "@(#)exec.c 8.1 (Berkeley) 6/4/93";
32 #endif /* LIBC_SCCS and not lint */
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD: src/lib/libc/gen/exec.c,v 1.27 2009/12/05 18:55:16 ed Exp $");
35
36 #include "namespace.h"
37 #include <sys/param.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <errno.h>
41 #include <unistd.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <stdio.h>
45 #include <paths.h>
46
47 #include <stdarg.h>
48 #include "un-namespace.h"
49 #include "libc_private.h"
50
51 #include <crt_externs.h>
52 #define environ (*_NSGetEnviron())
53
54 int
55 _execvpe(const char *name, char * const argv[], char * const envp[]);
56
57 int
58 execl(const char *name, const char *arg, ...)
59 {
60 va_list ap;
61 const char **argv;
62 int n;
63
64 va_start(ap, arg);
65 n = 1;
66 while (va_arg(ap, char *) != NULL)
67 n++;
68 va_end(ap);
69 argv = alloca((n + 1) * sizeof(*argv));
70 if (argv == NULL) {
71 errno = ENOMEM;
72 return (-1);
73 }
74 va_start(ap, arg);
75 n = 1;
76 argv[0] = arg;
77 while ((argv[n] = va_arg(ap, char *)) != NULL)
78 n++;
79 va_end(ap);
80 return (_execve(name, __DECONST(char **, argv), environ));
81 }
82
83 int
84 execle(const char *name, const char *arg, ...)
85 {
86 va_list ap;
87 const char **argv;
88 char **envp;
89 int n;
90
91 va_start(ap, arg);
92 n = 1;
93 while (va_arg(ap, char *) != NULL)
94 n++;
95 va_end(ap);
96 argv = alloca((n + 1) * sizeof(*argv));
97 if (argv == NULL) {
98 errno = ENOMEM;
99 return (-1);
100 }
101 va_start(ap, arg);
102 n = 1;
103 argv[0] = arg;
104 while ((argv[n] = va_arg(ap, char *)) != NULL)
105 n++;
106 envp = va_arg(ap, char **);
107 va_end(ap);
108 return (_execve(name, __DECONST(char **, argv), envp));
109 }
110
111 int
112 execlp(const char *name, const char *arg, ...)
113 {
114 va_list ap;
115 const char **argv;
116 int n;
117
118 va_start(ap, arg);
119 n = 1;
120 while (va_arg(ap, char *) != NULL)
121 n++;
122 va_end(ap);
123 argv = alloca((n + 1) * sizeof(*argv));
124 if (argv == NULL) {
125 errno = ENOMEM;
126 return (-1);
127 }
128 va_start(ap, arg);
129 n = 1;
130 argv[0] = arg;
131 while ((argv[n] = va_arg(ap, char *)) != NULL)
132 n++;
133 va_end(ap);
134 return (execvp(name, __DECONST(char **, argv)));
135 }
136
137 int
138 execv(name, argv)
139 const char *name;
140 char * const *argv;
141 {
142 (void)_execve(name, argv, environ);
143 return (-1);
144 }
145
146 int
147 execvp(const char *name, char * const *argv)
148 {
149 return (_execvpe(name, argv, environ));
150 }
151
152 static int
153 execvPe(const char *name, const char *path, char * const *argv,
154 char * const *envp)
155 {
156 const char **memp;
157 size_t cnt, lp, ln;
158 int eacces, save_errno;
159 char *cur, buf[MAXPATHLEN];
160 const char *p, *bp;
161 struct stat sb;
162
163 eacces = 0;
164
165 /* If it's an absolute or relative path name, it's easy. */
166 if (index(name, '/')) {
167 bp = name;
168 cur = NULL;
169 goto retry;
170 }
171 bp = buf;
172
173 /* If it's an empty path name, fail in the usual POSIX way. */
174 if (*name == '\0') {
175 errno = ENOENT;
176 return (-1);
177 }
178
179 cur = alloca(strlen(path) + 1);
180 if (cur == NULL) {
181 errno = ENOMEM;
182 return (-1);
183 }
184 strcpy(cur, path);
185 while ((p = strsep(&cur, ":")) != NULL) {
186 /*
187 * It's a SHELL path -- double, leading and trailing colons
188 * mean the current directory.
189 */
190 if (*p == '\0') {
191 p = ".";
192 lp = 1;
193 } else
194 lp = strlen(p);
195 ln = strlen(name);
196
197 /*
198 * If the path is too long complain. This is a possible
199 * security issue; given a way to make the path too long
200 * the user may execute the wrong program.
201 */
202 if (lp + ln + 2 > sizeof(buf)) {
203 (void)_write(STDERR_FILENO, "execvP: ", 8);
204 (void)_write(STDERR_FILENO, p, lp);
205 (void)_write(STDERR_FILENO, ": path too long\n",
206 16);
207 continue;
208 }
209 bcopy(p, buf, lp);
210 buf[lp] = '/';
211 bcopy(name, buf + lp + 1, ln);
212 buf[lp + ln + 1] = '\0';
213
214 retry: (void)_execve(bp, argv, envp);
215 switch (errno) {
216 case E2BIG:
217 goto done;
218 case ELOOP:
219 case ENAMETOOLONG:
220 case ENOENT:
221 break;
222 case ENOEXEC:
223 for (cnt = 0; argv[cnt]; ++cnt)
224 ;
225 memp = alloca((cnt + 2) * sizeof(char *));
226 if (memp == NULL) {
227 /* errno = ENOMEM; XXX override ENOEXEC? */
228 goto done;
229 }
230 memp[0] = "sh";
231 memp[1] = bp;
232 bcopy(argv + 1, memp + 2, cnt * sizeof(char *));
233 (void)_execve(_PATH_BSHELL,
234 __DECONST(char **, memp), envp);
235 goto done;
236 case ENOMEM:
237 goto done;
238 case ENOTDIR:
239 break;
240 case ETXTBSY:
241 /*
242 * We used to retry here, but sh(1) doesn't.
243 */
244 goto done;
245 default:
246 /*
247 * EACCES may be for an inaccessible directory or
248 * a non-executable file. Call stat() to decide
249 * which. This also handles ambiguities for EFAULT
250 * and EIO, and undocumented errors like ESTALE.
251 * We hope that the race for a stat() is unimportant.
252 */
253 save_errno = errno;
254 if (stat(bp, &sb) != 0)
255 break;
256 if (save_errno == EACCES) {
257 eacces = 1;
258 continue;
259 }
260 errno = save_errno;
261 goto done;
262 }
263 }
264 if (eacces)
265 errno = EACCES;
266 else if (cur)
267 errno = ENOENT;
268 /* else use existing errno from _execve */
269 done:
270 return (-1);
271 }
272
273 int
274 execvP(const char *name, const char *path, char * const argv[])
275 {
276 return execvPe(name, path, argv, environ);
277 }
278
279 __private_extern__ int
280 _execvpe(const char *name, char * const argv[], char * const envp[])
281 {
282 const char *path;
283
284 /* Get the path we're searching. */
285 if ((path = getenv("PATH")) == NULL)
286 path = _PATH_DEFPATH;
287
288 return (execvPe(name, path, argv, envp));
289 }