]> git.saurik.com Git - apple/libc.git/blame - gen/FreeBSD/exec.c
Libc-1082.50.1.tar.gz
[apple/libc.git] / gen / FreeBSD / exec.c
CommitLineData
9385eb3d
A
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.
9385eb3d
A
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)
31static char sccsid[] = "@(#)exec.c 8.1 (Berkeley) 6/4/93";
32#endif /* LIBC_SCCS and not lint */
33#include <sys/cdefs.h>
1f2f436a 34__FBSDID("$FreeBSD: src/lib/libc/gen/exec.c,v 1.27 2009/12/05 18:55:16 ed Exp $");
9385eb3d
A
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"
1f2f436a 49#include "libc_private.h"
9385eb3d 50
ad3c9f2a
A
51#include <crt_externs.h>
52#define environ (*_NSGetEnviron())
53
54int
55_execvpe(const char *name, char * const argv[], char * const envp[]);
9385eb3d
A
56
57int
58execl(const char *name, const char *arg, ...)
59{
60 va_list ap;
1f2f436a 61 const char **argv;
9385eb3d
A
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;
1f2f436a 76 argv[0] = arg;
9385eb3d
A
77 while ((argv[n] = va_arg(ap, char *)) != NULL)
78 n++;
79 va_end(ap);
1f2f436a 80 return (_execve(name, __DECONST(char **, argv), environ));
9385eb3d
A
81}
82
83int
84execle(const char *name, const char *arg, ...)
85{
86 va_list ap;
1f2f436a
A
87 const char **argv;
88 char **envp;
9385eb3d
A
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;
1f2f436a 103 argv[0] = arg;
9385eb3d
A
104 while ((argv[n] = va_arg(ap, char *)) != NULL)
105 n++;
106 envp = va_arg(ap, char **);
107 va_end(ap);
1f2f436a 108 return (_execve(name, __DECONST(char **, argv), envp));
9385eb3d
A
109}
110
111int
112execlp(const char *name, const char *arg, ...)
113{
114 va_list ap;
1f2f436a 115 const char **argv;
9385eb3d
A
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;
1f2f436a 130 argv[0] = arg;
9385eb3d
A
131 while ((argv[n] = va_arg(ap, char *)) != NULL)
132 n++;
133 va_end(ap);
1f2f436a 134 return (execvp(name, __DECONST(char **, argv)));
9385eb3d
A
135}
136
137int
138execv(name, argv)
139 const char *name;
140 char * const *argv;
141{
142 (void)_execve(name, argv, environ);
143 return (-1);
144}
145
146int
3d9156a7
A
147execvp(const char *name, char * const *argv)
148{
1f2f436a 149 return (_execvpe(name, argv, environ));
3d9156a7
A
150}
151
1f2f436a
A
152static int
153execvPe(const char *name, const char *path, char * const *argv,
154 char * const *envp)
9385eb3d 155{
1f2f436a
A
156 const char **memp;
157 size_t cnt, lp, ln;
9385eb3d 158 int eacces, save_errno;
1f2f436a
A
159 char *cur, buf[MAXPATHLEN];
160 const char *p, *bp;
9385eb3d
A
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, '/')) {
1f2f436a 167 bp = name;
3d9156a7 168 cur = NULL;
9385eb3d
A
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
9385eb3d
A
179 cur = alloca(strlen(path) + 1);
180 if (cur == NULL) {
181 errno = ENOMEM;
182 return (-1);
183 }
184 strcpy(cur, path);
3d9156a7 185 while ((p = strsep(&cur, ":")) != NULL) {
9385eb3d
A
186 /*
187 * It's a SHELL path -- double, leading and trailing colons
188 * mean the current directory.
189 */
3d9156a7 190 if (*p == '\0') {
9385eb3d
A
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)) {
3d9156a7 203 (void)_write(STDERR_FILENO, "execvP: ", 8);
9385eb3d
A
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
1f2f436a 214retry: (void)_execve(bp, argv, envp);
3d9156a7 215 switch (errno) {
9385eb3d
A
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 *));
1f2f436a
A
233 (void)_execve(_PATH_BSHELL,
234 __DECONST(char **, memp), envp);
9385eb3d
A
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;
ad3c9f2a 266 else if (cur)
9385eb3d 267 errno = ENOENT;
ad3c9f2a 268 /* else use existing errno from _execve */
9385eb3d
A
269done:
270 return (-1);
271}
1f2f436a
A
272
273int
274execvP(const char *name, const char *path, char * const argv[])
275{
276 return execvPe(name, path, argv, environ);
277}
278
ad3c9f2a 279__private_extern__ int
1f2f436a
A
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}