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