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