xref: /openbsd/lib/libc/gen/exec.c (revision bc757068)
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.4 1996/10/27 23:02:23 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 	/*
191 	 * Do not allow null name
192 	 */
193 	if (name == NULL || *name == '\0') {
194 		errno = ENOENT;
195 		return (-1);
196 	}
197 
198 	/* If it's an absolute or relative path name, it's easy. */
199 	if (strchr(name, '/')) {
200 		bp = (char *)name;
201 		cur = path = NULL;
202 		goto retry;
203 	}
204 	bp = buf;
205 
206 	/* Get the path we're searching. */
207 	if (!(path = getenv("PATH")))
208 		path = _PATH_DEFPATH;
209 	cur = path = strdup(path);
210 
211 	while (p = strsep(&cur, ":")) {
212 		/*
213 		 * It's a SHELL path -- double, leading and trailing colons
214 		 * mean the current directory.
215 		 */
216 		if (!*p) {
217 			p = ".";
218 			lp = 1;
219 		} else
220 			lp = strlen(p);
221 		ln = strlen(name);
222 
223 		/*
224 		 * If the path is too long complain.  This is a possible
225 		 * security issue; given a way to make the path too long
226 		 * the user may execute the wrong program.
227 		 */
228 		if (lp + ln + 2 > sizeof(buf)) {
229 			(void)write(STDERR_FILENO, "execvp: ", 8);
230 			(void)write(STDERR_FILENO, p, lp);
231 			(void)write(STDERR_FILENO, ": path too long\n", 16);
232 			continue;
233 		}
234 		bcopy(p, buf, lp);
235 		buf[lp] = '/';
236 		bcopy(name, buf + lp + 1, ln);
237 		buf[lp + ln + 1] = '\0';
238 
239 retry:		(void)execve(bp, argv, environ);
240 		switch(errno) {
241 		case EACCES:
242 			eacces = 1;
243 			break;
244 		case ENOENT:
245 			break;
246 		case ENOEXEC:
247 			for (cnt = 0; argv[cnt]; ++cnt);
248 			if ((cnt + 2) * sizeof(char *) > memsize) {
249 				memsize = (cnt + 2) * sizeof(char *);
250 				if ((memp = realloc(memp, memsize)) == NULL) {
251 					memsize = 0;
252 					goto done;
253 				}
254 			}
255 			memp[0] = "sh";
256 			memp[1] = bp;
257 			bcopy(argv + 1, memp + 2, cnt * sizeof(char *));
258 			(void)execve(_PATH_BSHELL, memp, environ);
259 			goto done;
260 		case ETXTBSY:
261 			if (etxtbsy < 3)
262 				(void)sleep(++etxtbsy);
263 			goto retry;
264 		default:
265 			goto done;
266 		}
267 	}
268 	if (eacces)
269 		errno = EACCES;
270 	else if (!errno)
271 		errno = ENOENT;
272 done:	if (path)
273 		free(path);
274 	return (-1);
275 }
276