exec.c revision 40356
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	"$Id: exec.c,v 1.7 1997/11/20 15:09:38 bde Exp $";
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
60static char **
61buildargv(ap, arg, envpp)
62	va_list ap;
63	const char *arg;
64	char ***envpp;
65{
66	register char **argv, **nargv;
67	register int memsize, off;
68
69	argv = NULL;
70	for (off = memsize = 0;; ++off) {
71		if (off >= memsize) {
72			memsize += 50;	/* Starts out at 0. */
73			memsize *= 2;	/* Ramp up fast. */
74			nargv = realloc(argv, memsize * sizeof(char *));
75			if (nargv == NULL) {
76				free(argv);
77				return (NULL);
78			}
79			argv = nargv;
80			if (off == 0) {
81				argv[0] = (char *)arg;
82				off = 1;
83			}
84		}
85		if (!(argv[off] = va_arg(ap, char *)))
86			break;
87	}
88	/* Get environment pointer if user supposed to provide one. */
89	if (envpp)
90		*envpp = va_arg(ap, char **);
91	return (argv);
92}
93
94int
95#if __STDC__
96execl(const char *name, const char *arg, ...)
97#else
98execl(name, arg, va_alist)
99	const char *name;
100	const char *arg;
101	va_dcl
102#endif
103{
104	va_list ap;
105	char **argv;
106	int n;
107
108	/* The following code is ugly, but makes execl() vfork()-safe. */
109
110#if __STDC__
111	va_start(ap, arg);
112#else
113	va_start(ap);
114#endif
115	n = 0;
116	while (va_arg(ap, char *) != NULL)
117		n++ ;
118	va_end(ap);
119	argv = (char **)alloca((n + 1) * sizeof(*argv));
120	if (argv == NULL)
121		return (-1);
122#if __STDC__
123	va_start(ap, arg);
124#else
125	va_start(ap);
126#endif
127	n = 0;
128	while ((argv[n] = va_arg(ap, char *)) != NULL)
129		n++;
130	va_end(ap);
131	return (execve(name, argv, environ));
132}
133
134int
135#if __STDC__
136execle(const char *name, const char *arg, ...)
137#else
138execle(name, arg, va_alist)
139	const char *name;
140	const char *arg;
141	va_dcl
142#endif
143{
144	va_list ap;
145	int sverrno;
146	char **argv, **envp;
147
148#if __STDC__
149	va_start(ap, arg);
150#else
151	va_start(ap);
152#endif
153	if ( (argv = buildargv(ap, arg, &envp)) )
154		(void)execve(name, argv, envp);
155	va_end(ap);
156	sverrno = errno;
157	free(argv);
158	errno = sverrno;
159	return (-1);
160}
161
162int
163#if __STDC__
164execlp(const char *name, const char *arg, ...)
165#else
166execlp(name, arg, va_alist)
167	const char *name;
168	const char *arg;
169	va_dcl
170#endif
171{
172	va_list ap;
173	int sverrno;
174	char **argv;
175
176#if __STDC__
177	va_start(ap, arg);
178#else
179	va_start(ap);
180#endif
181	if ( (argv = buildargv(ap, arg, NULL)) )
182		(void)execvp(name, argv);
183	va_end(ap);
184	sverrno = errno;
185	free(argv);
186	errno = sverrno;
187	return (-1);
188}
189
190int
191execv(name, argv)
192	const char *name;
193	char * const *argv;
194{
195	(void)execve(name, argv, environ);
196	return (-1);
197}
198
199int
200execvp(name, argv)
201	const char *name;
202	char * const *argv;
203{
204	char **memp;
205	register int cnt, lp, ln;
206	register char *p;
207	int eacces, save_errno;
208	char *bp, *cur, *path, buf[MAXPATHLEN];
209	struct stat sb;
210
211	eacces = 0;
212
213	/* If it's an absolute or relative path name, it's easy. */
214	if (index(name, '/')) {
215		bp = (char *)name;
216		cur = path = NULL;
217		goto retry;
218	}
219	bp = buf;
220
221	/* If it's an empty path name, fail in the usual POSIX way. */
222	if (*name == '\0') {
223		errno = ENOENT;
224		return (-1);
225	}
226
227	/* Get the path we're searching. */
228	if (!(path = getenv("PATH")))
229		path = _PATH_DEFPATH;
230	cur = path = strdup(path);
231
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 = malloc((cnt + 2) * sizeof(char *));
272			if (memp == NULL)
273				goto done;
274			memp[0] = "sh";
275			memp[1] = bp;
276			bcopy(argv + 1, memp + 2, cnt * sizeof(char *));
277			(void)execve(_PATH_BSHELL, memp, environ);
278			free(memp);
279			goto done;
280		case ENOMEM:
281			goto done;
282		case ENOTDIR:
283			break;
284		case ETXTBSY:
285			/*
286			 * We used to retry here, but sh(1) doesn't.
287			 */
288			goto done;
289		default:
290			/*
291			 * EACCES may be for an inaccessible directory or
292			 * a non-executable file.  Call stat() to decide
293			 * which.  This also handles ambiguities for EFAULT
294			 * and EIO, and undocumented errors like ESTALE.
295			 * We hope that the race for a stat() is unimportant.
296			 */
297			save_errno = errno;
298			if (stat(bp, &sb) != 0)
299				break;
300			if (save_errno == EACCES) {
301				eacces = 1;
302				continue;
303			}
304			errno = save_errno;
305			goto done;
306		}
307	}
308	if (eacces)
309		errno = EACCES;
310	else
311		errno = ENOENT;
312done:	if (path)
313		free(path);
314	return (-1);
315}
316