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 * 4. Neither the name of the University nor the names of its contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#if defined(LIBC_SCCS) && !defined(lint)
31static char sccsid[] = "@(#)exec.c	8.1 (Berkeley) 6/4/93";
32#endif /* LIBC_SCCS and not lint */
33#include <sys/cdefs.h>
34__FBSDID("$FreeBSD$");
35
36#include "namespace.h"
37#include <sys/param.h>
38#include <sys/types.h>
39#include <sys/stat.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#include <stdarg.h>
48#include "un-namespace.h"
49#include "libc_private.h"
50
51extern char **environ;
52
53int
54execl(const char *name, const char *arg, ...)
55{
56	va_list ap;
57	const char **argv;
58	int n;
59
60	va_start(ap, arg);
61	n = 1;
62	while (va_arg(ap, char *) != NULL)
63		n++;
64	va_end(ap);
65	argv = alloca((n + 1) * sizeof(*argv));
66	if (argv == NULL) {
67		errno = ENOMEM;
68		return (-1);
69	}
70	va_start(ap, arg);
71	n = 1;
72	argv[0] = arg;
73	while ((argv[n] = va_arg(ap, char *)) != NULL)
74		n++;
75	va_end(ap);
76	return (_execve(name, __DECONST(char **, argv), environ));
77}
78
79int
80execle(const char *name, const char *arg, ...)
81{
82	va_list ap;
83	const char **argv;
84	char **envp;
85	int n;
86
87	va_start(ap, arg);
88	n = 1;
89	while (va_arg(ap, char *) != NULL)
90		n++;
91	va_end(ap);
92	argv = alloca((n + 1) * sizeof(*argv));
93	if (argv == NULL) {
94		errno = ENOMEM;
95		return (-1);
96	}
97	va_start(ap, arg);
98	n = 1;
99	argv[0] = arg;
100	while ((argv[n] = va_arg(ap, char *)) != NULL)
101		n++;
102	envp = va_arg(ap, char **);
103	va_end(ap);
104	return (_execve(name, __DECONST(char **, argv), envp));
105}
106
107int
108execlp(const char *name, const char *arg, ...)
109{
110	va_list ap;
111	const char **argv;
112	int n;
113
114	va_start(ap, arg);
115	n = 1;
116	while (va_arg(ap, char *) != NULL)
117		n++;
118	va_end(ap);
119	argv = alloca((n + 1) * sizeof(*argv));
120	if (argv == NULL) {
121		errno = ENOMEM;
122		return (-1);
123	}
124	va_start(ap, arg);
125	n = 1;
126	argv[0] = arg;
127	while ((argv[n] = va_arg(ap, char *)) != NULL)
128		n++;
129	va_end(ap);
130	return (execvp(name, __DECONST(char **, argv)));
131}
132
133int
134execv(name, argv)
135	const char *name;
136	char * const *argv;
137{
138	(void)_execve(name, argv, environ);
139	return (-1);
140}
141
142int
143execvp(const char *name, char * const *argv)
144{
145	return (_execvpe(name, argv, environ));
146}
147
148static int
149execvPe(const char *name, const char *path, char * const *argv,
150    char * const *envp)
151{
152	const char **memp;
153	size_t cnt, lp, ln;
154	int eacces, save_errno;
155	char *cur, buf[MAXPATHLEN];
156	const char *p, *bp;
157	struct stat sb;
158
159	eacces = 0;
160
161	/* If it's an absolute or relative path name, it's easy. */
162	if (strchr(name, '/')) {
163		bp = name;
164		cur = NULL;
165		goto retry;
166	}
167	bp = buf;
168
169	/* If it's an empty path name, fail in the usual POSIX way. */
170	if (*name == '\0') {
171		errno = ENOENT;
172		return (-1);
173	}
174
175	cur = alloca(strlen(path) + 1);
176	if (cur == NULL) {
177		errno = ENOMEM;
178		return (-1);
179	}
180	strcpy(cur, path);
181	while ((p = strsep(&cur, ":")) != NULL) {
182		/*
183		 * It's a SHELL path -- double, leading and trailing colons
184		 * mean the current directory.
185		 */
186		if (*p == '\0') {
187			p = ".";
188			lp = 1;
189		} else
190			lp = strlen(p);
191		ln = strlen(name);
192
193		/*
194		 * If the path is too long complain.  This is a possible
195		 * security issue; given a way to make the path too long
196		 * the user may execute the wrong program.
197		 */
198		if (lp + ln + 2 > sizeof(buf)) {
199			(void)_write(STDERR_FILENO, "execvP: ", 8);
200			(void)_write(STDERR_FILENO, p, lp);
201			(void)_write(STDERR_FILENO, ": path too long\n",
202			    16);
203			continue;
204		}
205		bcopy(p, buf, lp);
206		buf[lp] = '/';
207		bcopy(name, buf + lp + 1, ln);
208		buf[lp + ln + 1] = '\0';
209
210retry:		(void)_execve(bp, argv, envp);
211		switch (errno) {
212		case E2BIG:
213			goto done;
214		case ELOOP:
215		case ENAMETOOLONG:
216		case ENOENT:
217			break;
218		case ENOEXEC:
219			for (cnt = 0; argv[cnt]; ++cnt)
220				;
221			memp = alloca((cnt + 2) * sizeof(char *));
222			if (memp == NULL) {
223				/* errno = ENOMEM; XXX override ENOEXEC? */
224				goto done;
225			}
226			memp[0] = "sh";
227			memp[1] = bp;
228			bcopy(argv + 1, memp + 2, cnt * sizeof(char *));
229 			(void)_execve(_PATH_BSHELL,
230			    __DECONST(char **, memp), envp);
231			goto done;
232		case ENOMEM:
233			goto done;
234		case ENOTDIR:
235			break;
236		case ETXTBSY:
237			/*
238			 * We used to retry here, but sh(1) doesn't.
239			 */
240			goto done;
241		default:
242			/*
243			 * EACCES may be for an inaccessible directory or
244			 * a non-executable file.  Call stat() to decide
245			 * which.  This also handles ambiguities for EFAULT
246			 * and EIO, and undocumented errors like ESTALE.
247			 * We hope that the race for a stat() is unimportant.
248			 */
249			save_errno = errno;
250			if (stat(bp, &sb) != 0)
251				break;
252			if (save_errno == EACCES) {
253				eacces = 1;
254				continue;
255			}
256			errno = save_errno;
257			goto done;
258		}
259	}
260	if (eacces)
261		errno = EACCES;
262	else
263		errno = ENOENT;
264done:
265	return (-1);
266}
267
268int
269execvP(const char *name, const char *path, char * const argv[])
270{
271	return execvPe(name, path, argv, environ);
272}
273
274int
275_execvpe(const char *name, char * const argv[], char * const envp[])
276{
277	const char *path;
278
279	/* Get the path we're searching. */
280	if ((path = getenv("PATH")) == NULL)
281		path = _PATH_DEFPATH;
282
283	return (execvPe(name, path, argv, envp));
284}
285