blob: a50185fb7ccbacad84c8a377e16e63d202f1fe02 [file] [log] [blame]
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001/* $OpenBSD: exec.c,v 1.18 2005/08/08 08:05:34 espie Exp $ */
2/*-
3 * Copyright (c) 1991, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the University nor the names of its contributors
15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31#include <sys/param.h>
32#include <sys/types.h>
33#include <sys/uio.h>
34#include <errno.h>
35#include <unistd.h>
36#include <limits.h>
37#include <stdlib.h>
38#include <string.h>
Carl Shapiro2cc2b2b2011-03-21 20:01:03 -070039#include <strings.h>
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080040#include <stdio.h>
41#include <paths.h>
42#include <stdarg.h>
43#include <alloca.h>
44
45extern char **environ;
46
47int
48execl(const char *name, const char *arg, ...)
49{
50 va_list ap;
51 char **argv;
52 int n;
53
54 va_start(ap, arg);
55 n = 1;
56 while (va_arg(ap, char *) != NULL)
57 n++;
58 va_end(ap);
59 argv = alloca((n + 1) * sizeof(*argv));
60 if (argv == NULL) {
61 errno = ENOMEM;
62 return (-1);
63 }
64 va_start(ap, arg);
65 n = 1;
66 argv[0] = (char *)arg;
67 while ((argv[n] = va_arg(ap, char *)) != NULL)
68 n++;
69 va_end(ap);
70 return (execve(name, argv, environ));
71}
72
73int
74execle(const char *name, const char *arg, ...)
75{
76 va_list ap;
77 char **argv, **envp;
78 int n;
79
80 va_start(ap, arg);
81 n = 1;
82 while (va_arg(ap, char *) != NULL)
83 n++;
84 va_end(ap);
85 argv = alloca((n + 1) * sizeof(*argv));
86 if (argv == NULL) {
87 errno = ENOMEM;
88 return (-1);
89 }
90 va_start(ap, arg);
91 n = 1;
92 argv[0] = (char *)arg;
93 while ((argv[n] = va_arg(ap, char *)) != NULL)
94 n++;
95 envp = va_arg(ap, char **);
96 va_end(ap);
97 return (execve(name, argv, envp));
98}
99
100int
101execlp(const char *name, const char *arg, ...)
102{
103 va_list ap;
104 char **argv;
105 int n;
106
107 va_start(ap, arg);
108 n = 1;
109 while (va_arg(ap, char *) != NULL)
110 n++;
111 va_end(ap);
112 argv = alloca((n + 1) * sizeof(*argv));
113 if (argv == NULL) {
114 errno = ENOMEM;
115 return (-1);
116 }
117 va_start(ap, arg);
118 n = 1;
119 argv[0] = (char *)arg;
120 while ((argv[n] = va_arg(ap, char *)) != NULL)
121 n++;
122 va_end(ap);
123 return (execvp(name, argv));
124}
125
126int
127execv(const char *name, char * const *argv)
128{
129 (void)execve(name, argv, environ);
130 return (-1);
131}
132
133int
134execvp(const char *name, char * const *argv)
135{
136 char **memp;
137 int cnt, lp, ln, len;
138 char *p;
139 int eacces = 0;
140 char *bp, *cur, *path, buf[MAXPATHLEN];
141
142 /*
143 * Do not allow null name
144 */
145 if (name == NULL || *name == '\0') {
146 errno = ENOENT;
147 return (-1);
148 }
149
150 /* If it's an absolute or relative path name, it's easy. */
151 if (strchr(name, '/')) {
152 bp = (char *)name;
153 cur = path = NULL;
154 goto retry;
155 }
156 bp = buf;
157
158 /* Get the path we're searching. */
159 if (!(path = getenv("PATH")))
160 path = _PATH_DEFPATH;
161 len = strlen(path) + 1;
162 cur = alloca(len);
163 if (cur == NULL) {
164 errno = ENOMEM;
165 return (-1);
166 }
167 strlcpy(cur, path, len);
168 path = cur;
169 while ((p = strsep(&cur, ":"))) {
170 /*
171 * It's a SHELL path -- double, leading and trailing colons
172 * mean the current directory.
173 */
174 if (!*p) {
175 p = ".";
176 lp = 1;
177 } else
178 lp = strlen(p);
179 ln = strlen(name);
180
181 /*
182 * If the path is too long complain. This is a possible
183 * security issue; given a way to make the path too long
184 * the user may execute the wrong program.
185 */
186 if (lp + ln + 2 > (int)sizeof(buf)) {
187 struct iovec iov[3];
188
189 iov[0].iov_base = "execvp: ";
190 iov[0].iov_len = 8;
191 iov[1].iov_base = p;
192 iov[1].iov_len = lp;
193 iov[2].iov_base = ": path too long\n";
194 iov[2].iov_len = 16;
195 (void)writev(STDERR_FILENO, iov, 3);
196 continue;
197 }
198 bcopy(p, buf, lp);
199 buf[lp] = '/';
200 bcopy(name, buf + lp + 1, ln);
201 buf[lp + ln + 1] = '\0';
202
203retry: (void)execve(bp, argv, environ);
204 switch(errno) {
205 case E2BIG:
206 goto done;
207 case EISDIR:
208 case ELOOP:
209 case ENAMETOOLONG:
210 case ENOENT:
211 break;
212 case ENOEXEC:
213 for (cnt = 0; argv[cnt]; ++cnt)
214 ;
215 memp = alloca((cnt + 2) * sizeof(char *));
216 if (memp == NULL)
217 goto done;
218 memp[0] = "sh";
219 memp[1] = bp;
220 bcopy(argv + 1, memp + 2, cnt * sizeof(char *));
221 (void)execve(_PATH_BSHELL, memp, environ);
222 goto done;
223 case ENOMEM:
224 goto done;
225 case ENOTDIR:
226 break;
227 case ETXTBSY:
228 /*
229 * We used to retry here, but sh(1) doesn't.
230 */
231 goto done;
232 case EACCES:
233 eacces = 1;
234 break;
235 default:
236 goto done;
237 }
238 }
239 if (eacces)
240 errno = EACCES;
241 else if (!errno)
242 errno = ENOENT;
243done:
244 return (-1);
245}