exec.c revision 50476
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#if 0
36static char sccsid[] = "@(#)exec.c	8.1 (Berkeley) 6/4/93";
37#endif
38static const char rcsid[] =
39  "$FreeBSD: head/lib/libc/gen/exec.c 50476 1999-08-28 00:22:10Z peter $";
40#endif /* LIBC_SCCS and not lint */
41
42#include <sys/param.h>
43#include <sys/types.h>
44#include <sys/stat.h>
45#include <errno.h>
46#include <unistd.h>
47#include <stdlib.h>
48#include <string.h>
49#include <stdio.h>
50#include <paths.h>
51
52#if __STDC__
53#include <stdarg.h>
54#else
55#include <varargs.h>
56#endif
57
58extern char **environ;
59
60int
61#if __STDC__
62execl(const char *name, const char *arg, ...)
63#else
64execl(name, arg, va_alist)
65	const char *name;
66	const char *arg;
67	va_dcl
68#endif
69{
70	va_list ap;
71	char **argv;
72	int n;
73
74#if __STDC__
75	va_start(ap, arg);
76#else
77	va_start(ap);
78#endif
79	n = 1;
80	while (va_arg(ap, char *) != NULL)
81		n++;
82	va_end(ap);
83	argv = alloca((n + 1) * sizeof(*argv));
84	if (argv == NULL) {
85		errno = ENOMEM;
86		return (-1);
87	}
88#if __STDC__
89	va_start(ap, arg);
90#else
91	va_start(ap);
92#endif
93	n = 1;
94	argv[0] = (char *)arg;
95	while ((argv[n] = va_arg(ap, char *)) != NULL)
96		n++;
97	va_end(ap);
98	return (execve(name, argv, environ));
99}
100
101int
102#if __STDC__
103execle(const char *name, const char *arg, ...)
104#else
105execle(name, arg, va_alist)
106	const char *name;
107	const char *arg;
108	va_dcl
109#endif
110{
111	va_list ap;
112	char **argv, **envp;
113	int n;
114
115#if __STDC__
116	va_start(ap, arg);
117#else
118	va_start(ap);
119#endif
120	n = 1;
121	while (va_arg(ap, char *) != NULL)
122		n++;
123	va_end(ap);
124	argv = alloca((n + 1) * sizeof(*argv));
125	if (argv == NULL) {
126		errno = ENOMEM;
127		return (-1);
128	}
129#if __STDC__
130	va_start(ap, arg);
131#else
132	va_start(ap);
133#endif
134	n = 1;
135	argv[0] = (char *)arg;
136	while ((argv[n] = va_arg(ap, char *)) != NULL)
137		n++;
138	envp = va_arg(ap, char **);
139	va_end(ap);
140	return (execve(name, argv, envp));
141}
142
143int
144#if __STDC__
145execlp(const char *name, const char *arg, ...)
146#else
147execlp(name, arg, va_alist)
148	const char *name;
149	const char *arg;
150	va_dcl
151#endif
152{
153	va_list ap;
154	int sverrno;
155	char **argv;
156	int n;
157
158#if __STDC__
159	va_start(ap, arg);
160#else
161	va_start(ap);
162#endif
163	n = 1;
164	while (va_arg(ap, char *) != NULL)
165		n++;
166	va_end(ap);
167	argv = alloca((n + 1) * sizeof(*argv));
168	if (argv == NULL) {
169		errno = ENOMEM;
170		return (-1);
171	}
172#if __STDC__
173	va_start(ap, arg);
174#else
175	va_start(ap);
176#endif
177	n = 1;
178	argv[0] = (char *)arg;
179	while ((argv[n] = va_arg(ap, char *)) != NULL)
180		n++;
181	va_end(ap);
182	return (execvp(name, argv));
183}
184
185int
186execv(name, argv)
187	const char *name;
188	char * const *argv;
189{
190	(void)execve(name, argv, environ);
191	return (-1);
192}
193
194int
195execvp(name, argv)
196	const char *name;
197	char * const *argv;
198{
199	char **memp;
200	register int cnt, lp, ln;
201	register char *p;
202	int eacces, save_errno;
203	char *bp, *cur, *path, buf[MAXPATHLEN];
204	struct stat sb;
205
206	eacces = 0;
207
208	/* If it's an absolute or relative path name, it's easy. */
209	if (index(name, '/')) {
210		bp = (char *)name;
211		cur = path = NULL;
212		goto retry;
213	}
214	bp = buf;
215
216	/* If it's an empty path name, fail in the usual POSIX way. */
217	if (*name == '\0') {
218		errno = ENOENT;
219		return (-1);
220	}
221
222	/* Get the path we're searching. */
223	if (!(path = getenv("PATH")))
224		path = _PATH_DEFPATH;
225	cur = alloca(strlen(path) + 1);
226	if (cur == NULL) {
227		errno = ENOMEM;
228		return (-1);
229	}
230	strcpy(cur, path);
231	path = cur;
232	while ( (p = strsep(&cur, ":")) ) {
233		/*
234		 * It's a SHELL path -- double, leading and trailing colons
235		 * mean the current directory.
236		 */
237		if (!*p) {
238			p = ".";
239			lp = 1;
240		} else
241			lp = strlen(p);
242		ln = strlen(name);
243
244		/*
245		 * If the path is too long complain.  This is a possible
246		 * security issue; given a way to make the path too long
247		 * the user may execute the wrong program.
248		 */
249		if (lp + ln + 2 > sizeof(buf)) {
250			(void)write(STDERR_FILENO, "execvp: ", 8);
251			(void)write(STDERR_FILENO, p, lp);
252			(void)write(STDERR_FILENO, ": path too long\n", 16);
253			continue;
254		}
255		bcopy(p, buf, lp);
256		buf[lp] = '/';
257		bcopy(name, buf + lp + 1, ln);
258		buf[lp + ln + 1] = '\0';
259
260retry:		(void)execve(bp, argv, environ);
261		switch(errno) {
262		case E2BIG:
263			goto done;
264		case ELOOP:
265		case ENAMETOOLONG:
266		case ENOENT:
267			break;
268		case ENOEXEC:
269			for (cnt = 0; argv[cnt]; ++cnt)
270				;
271			memp = alloca((cnt + 2) * sizeof(char *));
272			if (memp == NULL) {
273				/* errno = ENOMEM; XXX override ENOEXEC? */
274				goto done;
275			}
276			memp[0] = "sh";
277			memp[1] = bp;
278			bcopy(argv + 1, memp + 2, cnt * sizeof(char *));
279			(void)execve(_PATH_BSHELL, memp, environ);
280			goto done;
281		case ENOMEM:
282			goto done;
283		case ENOTDIR:
284			break;
285		case ETXTBSY:
286			/*
287			 * We used to retry here, but sh(1) doesn't.
288			 */
289			goto done;
290		default:
291			/*
292			 * EACCES may be for an inaccessible directory or
293			 * a non-executable file.  Call stat() to decide
294			 * which.  This also handles ambiguities for EFAULT
295			 * and EIO, and undocumented errors like ESTALE.
296			 * We hope that the race for a stat() is unimportant.
297			 */
298			save_errno = errno;
299			if (stat(bp, &sb) != 0)
300				break;
301			if (save_errno == EACCES) {
302				eacces = 1;
303				continue;
304			}
305			errno = save_errno;
306			goto done;
307		}
308	}
309	if (eacces)
310		errno = EACCES;
311	else
312		errno = ENOENT;
313done:
314	return (-1);
315}
316