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