]> git.saurik.com Git - apple/libc.git/blob - gen/exec.c
606ff40cff2244c66ad3167e6b093cd45088a1db
[apple/libc.git] / gen / exec.c
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /*
26 * Copyright (c) 1991, 1993
27 * The Regents of the University of California. All rights reserved.
28 *
29 * Redistribution and use in source and binary forms, with or without
30 * modification, are permitted provided that the following conditions
31 * are met:
32 * 1. Redistributions of source code must retain the above copyright
33 * notice, this list of conditions and the following disclaimer.
34 * 2. Redistributions in binary form must reproduce the above copyright
35 * notice, this list of conditions and the following disclaimer in the
36 * documentation and/or other materials provided with the distribution.
37 * 3. All advertising materials mentioning features or use of this software
38 * must display the following acknowledgement:
39 * This product includes software developed by the University of
40 * California, Berkeley and its contributors.
41 * 4. Neither the name of the University nor the names of its contributors
42 * may be used to endorse or promote products derived from this software
43 * without specific prior written permission.
44 *
45 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55 * SUCH DAMAGE.
56 */
57
58 #include <sys/param.h>
59 #include <sys/types.h>
60 #include <sys/uio.h>
61 #include <errno.h>
62 #include <unistd.h>
63 #include <stdlib.h>
64 #include <string.h>
65 #include <stdio.h>
66 #include <paths.h>
67
68 #ifdef __STDC__
69 #include <stdarg.h>
70 #else
71 #include <varargs.h>
72 #endif
73
74 #if defined(__APPLE__)
75 #include <crt_externs.h>
76 #define environ (*_NSGetEnviron())
77 #else
78 extern char **environ;
79 #endif
80
81 int
82 #ifdef __STDC__
83 execl(const char *name, const char *arg, ...)
84 #else
85 execl(name, arg, va_alist)
86 const char *name;
87 const char *arg;
88 va_dcl
89 #endif
90 {
91 va_list ap;
92 char **argv;
93 int n;
94
95 #ifdef __STDC__
96 va_start(ap, arg);
97 #else
98 va_start(ap);
99 #endif
100 n = 1;
101 while (va_arg(ap, char *) != NULL)
102 n++;
103 va_end(ap);
104 argv = alloca((n + 1) * sizeof(*argv));
105 if (argv == NULL) {
106 errno = ENOMEM;
107 return (-1);
108 }
109 #ifdef __STDC__
110 va_start(ap, arg);
111 #else
112 va_start(ap);
113 #endif
114 n = 1;
115 argv[0] = (char *)arg;
116 while ((argv[n] = va_arg(ap, char *)) != NULL)
117 n++;
118 va_end(ap);
119 return (execve(name, argv, environ));
120 }
121
122 int
123 #ifdef __STDC__
124 execle(const char *name, const char *arg, ...)
125 #else
126 execle(name, arg, va_alist)
127 const char *name;
128 const char *arg;
129 va_dcl
130 #endif
131 {
132 va_list ap;
133 char **argv, **envp;
134 int n;
135
136 #ifdef __STDC__
137 va_start(ap, arg);
138 #else
139 va_start(ap);
140 #endif
141 n = 1;
142 while (va_arg(ap, char *) != NULL)
143 n++;
144 va_end(ap);
145 argv = alloca((n + 1) * sizeof(*argv));
146 if (argv == NULL) {
147 errno = ENOMEM;
148 return (-1);
149 }
150 #ifdef __STDC__
151 va_start(ap, arg);
152 #else
153 va_start(ap);
154 #endif
155 n = 1;
156 argv[0] = (char *)arg;
157 while ((argv[n] = va_arg(ap, char *)) != NULL)
158 n++;
159 envp = va_arg(ap, char **);
160 va_end(ap);
161 return (execve(name, argv, envp));
162 }
163
164 int
165 #ifdef __STDC__
166 execlp(const char *name, const char *arg, ...)
167 #else
168 execlp(name, arg, va_alist)
169 const char *name;
170 const char *arg;
171 va_dcl
172 #endif
173 {
174 va_list ap;
175 char **argv;
176 int n;
177
178 #ifdef __STDC__
179 va_start(ap, arg);
180 #else
181 va_start(ap);
182 #endif
183 n = 1;
184 while (va_arg(ap, char *) != NULL)
185 n++;
186 va_end(ap);
187 argv = alloca((n + 1) * sizeof(*argv));
188 if (argv == NULL) {
189 errno = ENOMEM;
190 return (-1);
191 }
192 #ifdef __STDC__
193 va_start(ap, arg);
194 #else
195 va_start(ap);
196 #endif
197 n = 1;
198 argv[0] = (char *)arg;
199 while ((argv[n] = va_arg(ap, char *)) != NULL)
200 n++;
201 va_end(ap);
202 return (execvp(name, argv));
203 }
204
205 int
206 execv(name, argv)
207 const char *name;
208 char * const *argv;
209 {
210 (void)execve(name, argv, environ);
211 return (-1);
212 }
213
214 int
215 execvp(name, argv)
216 const char *name;
217 char * const *argv;
218 {
219 char **memp;
220 register int cnt, lp, ln;
221 register char *p;
222 int eacces = 0, etxtbsy = 0;
223 char *bp, *cur, *path, buf[MAXPATHLEN];
224
225 /*
226 * Do not allow null name
227 */
228 if (name == NULL || *name == '\0') {
229 errno = ENOENT;
230 return (-1);
231 }
232
233 /* If it's an absolute or relative path name, it's easy. */
234 if (strchr(name, '/')) {
235 bp = (char *)name;
236 cur = path = NULL;
237 goto retry;
238 }
239 bp = buf;
240
241 /* Get the path we're searching. */
242 if (!(path = getenv("PATH")))
243 path = _PATH_DEFPATH;
244 cur = alloca(strlen(path) + 1);
245 if (cur == NULL) {
246 errno = ENOMEM;
247 return (-1);
248 }
249 strcpy(cur, path);
250 path = cur;
251 while ((p = strsep(&cur, ":"))) {
252 /*
253 * It's a SHELL path -- double, leading and trailing colons
254 * mean the current directory.
255 */
256 if (!*p) {
257 p = ".";
258 lp = 1;
259 } else
260 lp = strlen(p);
261 ln = strlen(name);
262
263 /*
264 * If the path is too long complain. This is a possible
265 * security issue; given a way to make the path too long
266 * the user may execute the wrong program.
267 */
268 if (lp + ln + 2 > sizeof(buf)) {
269 struct iovec iov[3];
270
271 iov[0].iov_base = "execvp: ";
272 iov[0].iov_len = 8;
273 iov[1].iov_base = p;
274 iov[1].iov_len = lp;
275 iov[2].iov_base = ": path too long\n";
276 iov[2].iov_len = 16;
277 (void)writev(STDERR_FILENO, iov, 3);
278 continue;
279 }
280 bcopy(p, buf, lp);
281 buf[lp] = '/';
282 bcopy(name, buf + lp + 1, ln);
283 buf[lp + ln + 1] = '\0';
284
285 retry: (void)execve(bp, argv, environ);
286 switch(errno) {
287 case E2BIG:
288 goto done;
289 case ELOOP:
290 case ENAMETOOLONG:
291 case ENOENT:
292 break;
293 case ENOEXEC:
294 for (cnt = 0; argv[cnt]; ++cnt)
295 ;
296 memp = alloca((cnt + 2) * sizeof(char *));
297 if (memp == NULL)
298 goto done;
299 memp[0] = "sh";
300 memp[1] = bp;
301 bcopy(argv + 1, memp + 2, cnt * sizeof(char *));
302 (void)execve(_PATH_BSHELL, memp, environ);
303 goto done;
304 case ENOMEM:
305 goto done;
306 case ENOTDIR:
307 break;
308 case ETXTBSY:
309 /*
310 * We used to retry here, but sh(1) doesn't.
311 */
312 goto done;
313 case EACCES:
314 eacces = 1;
315 break;
316 default:
317 goto done;
318 }
319 }
320 if (eacces)
321 errno = EACCES;
322 else if (!errno)
323 errno = ENOENT;
324 done:
325 return (-1);
326 }