xref: /openbsd/lib/libc/gen/exec.c (revision e9b2b68c)
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.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #if defined(LIBC_SCCS) && !defined(lint)
35 static char rcsid[] = "$OpenBSD: exec.c,v 1.3 1996/08/19 08:22:40 tholo Exp $";
36 #endif /* LIBC_SCCS and not lint */
37 
38 #include <sys/param.h>
39 #include <sys/types.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 #if __STDC__
48 #include <stdarg.h>
49 #else
50 #include <varargs.h>
51 #endif
52 
53 extern char **environ;
54 
55 int
56 #if __STDC__
57 execl(const char *name, const char *arg, ...)
58 #else
59 execl(name, arg, va_alist)
60 	const char *name;
61 	const char *arg;
62 	va_dcl
63 #endif
64 {
65 	va_list ap;
66 	char **argv;
67 	int i;
68 
69 #if __STDC__
70 	va_start(ap, arg);
71 #else
72 	va_start(ap);
73 #endif
74 	for (i = 1; va_arg(ap, char *) != NULL; i++)
75 		;
76 	va_end(ap);
77 
78 	argv = alloca (i * sizeof (char *));
79 
80 #if __STDC__
81 	va_start(ap, arg);
82 #else
83 	va_start(ap);
84 #endif
85 	argv[0] = (char *) arg;
86 	for (i = 1; (argv[i] = (char *) va_arg(ap, char *)) != NULL; i++)
87 		;
88 	va_end(ap);
89 
90 	return execve(name, argv, environ);
91 }
92 
93 int
94 #if __STDC__
95 execle(const char *name, const char *arg, ...)
96 #else
97 execle(name, arg, va_alist)
98 	const char *name;
99 	const char *arg;
100 	va_dcl
101 #endif
102 {
103 	va_list ap;
104 	char **argv, **envp;
105 	int i;
106 
107 #if __STDC__
108 	va_start(ap, arg);
109 #else
110 	va_start(ap);
111 #endif
112 	for (i = 1; va_arg(ap, char *) != NULL; i++)
113 		;
114 	va_end(ap);
115 
116 	argv = alloca (i * sizeof (char *));
117 
118 #if __STDC__
119 	va_start(ap, arg);
120 #else
121 	va_start(ap);
122 #endif
123 	argv[0] = (char *) arg;
124 	for (i = 1; (argv[i] = (char *) va_arg(ap, char *)) != NULL; i++)
125 		;
126 	envp = (char **) va_arg(ap, char **);
127 	va_end(ap);
128 
129 	return execve(name, argv, envp);
130 }
131 
132 int
133 #if __STDC__
134 execlp(const char *name, const char *arg, ...)
135 #else
136 execlp(name, arg, va_alist)
137 	const char *name;
138 	const char *arg;
139 	va_dcl
140 #endif
141 {
142 	va_list ap;
143 	char **argv;
144 	int i;
145 
146 #if __STDC__
147 	va_start(ap, arg);
148 #else
149 	va_start(ap);
150 #endif
151 	for (i = 1; va_arg(ap, char *) != NULL; i++)
152 		;
153 	va_end(ap);
154 
155 	argv = alloca (i * sizeof (char *));
156 
157 #if __STDC__
158 	va_start(ap, arg);
159 #else
160 	va_start(ap);
161 #endif
162 	argv[0] = (char *) arg;
163 	for (i = 1; (argv[i] = va_arg(ap, char *)) != NULL; i++)
164 		;
165 	va_end(ap);
166 
167 	return execvp(name, argv);
168 }
169 
170 int
171 execv(name, argv)
172 	const char *name;
173 	char * const *argv;
174 {
175 	return execve(name, argv, environ);
176 }
177 
178 int
179 execvp(name, argv)
180 	const char *name;
181 	char * const *argv;
182 {
183 	static int memsize;
184 	static char **memp;
185 	register int cnt, lp, ln;
186 	register char *p;
187 	int eacces = 0, etxtbsy = 0;
188 	char *bp, *cur, *path, buf[MAXPATHLEN];
189 
190 	/* If it's an absolute or relative path name, it's easy. */
191 	if (strchr(name, '/')) {
192 		bp = (char *)name;
193 		cur = path = NULL;
194 		goto retry;
195 	}
196 	bp = buf;
197 
198 	/* Get the path we're searching. */
199 	if (!(path = getenv("PATH")))
200 		path = _PATH_DEFPATH;
201 	cur = path = strdup(path);
202 
203 	while (p = strsep(&cur, ":")) {
204 		/*
205 		 * It's a SHELL path -- double, leading and trailing colons
206 		 * mean the current directory.
207 		 */
208 		if (!*p) {
209 			p = ".";
210 			lp = 1;
211 		} else
212 			lp = strlen(p);
213 		ln = strlen(name);
214 
215 		/*
216 		 * If the path is too long complain.  This is a possible
217 		 * security issue; given a way to make the path too long
218 		 * the user may execute the wrong program.
219 		 */
220 		if (lp + ln + 2 > sizeof(buf)) {
221 			(void)write(STDERR_FILENO, "execvp: ", 8);
222 			(void)write(STDERR_FILENO, p, lp);
223 			(void)write(STDERR_FILENO, ": path too long\n", 16);
224 			continue;
225 		}
226 		bcopy(p, buf, lp);
227 		buf[lp] = '/';
228 		bcopy(name, buf + lp + 1, ln);
229 		buf[lp + ln + 1] = '\0';
230 
231 retry:		(void)execve(bp, argv, environ);
232 		switch(errno) {
233 		case EACCES:
234 			eacces = 1;
235 			break;
236 		case ENOENT:
237 			break;
238 		case ENOEXEC:
239 			for (cnt = 0; argv[cnt]; ++cnt);
240 			if ((cnt + 2) * sizeof(char *) > memsize) {
241 				memsize = (cnt + 2) * sizeof(char *);
242 				if ((memp = realloc(memp, memsize)) == NULL) {
243 					memsize = 0;
244 					goto done;
245 				}
246 			}
247 			memp[0] = "sh";
248 			memp[1] = bp;
249 			bcopy(argv + 1, memp + 2, cnt * sizeof(char *));
250 			(void)execve(_PATH_BSHELL, memp, environ);
251 			goto done;
252 		case ETXTBSY:
253 			if (etxtbsy < 3)
254 				(void)sleep(++etxtbsy);
255 			goto retry;
256 		default:
257 			goto done;
258 		}
259 	}
260 	if (eacces)
261 		errno = EACCES;
262 	else if (!errno)
263 		errno = ENOENT;
264 done:	if (path)
265 		free(path);
266 	return (-1);
267 }
268