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: stable/11/lib/libc/gen/exec.c 362281 2020-06-17 16:22:08Z kevans $");
35
36#include "namespace.h"
37#include <sys/param.h>
38#include <sys/stat.h>
39#include <errno.h>
40#include <unistd.h>
41#include <stdlib.h>
42#include <string.h>
43#include <stdio.h>
44#include <paths.h>
45
46#include <stdarg.h>
47#include "un-namespace.h"
48#include "libc_private.h"
49
50extern char **environ;
51
52static const char execvPe_err_preamble[] = "execvP: ";
53static const char execvPe_err_trailer[] = ": path too long\n";
54
55int
56execl(const char *name, const char *arg, ...)
57{
58	va_list ap;
59	const char **argv;
60	int n;
61
62	va_start(ap, arg);
63	n = 1;
64	while (va_arg(ap, char *) != NULL)
65		n++;
66	va_end(ap);
67	argv = alloca((n + 1) * sizeof(*argv));
68	if (argv == NULL) {
69		errno = ENOMEM;
70		return (-1);
71	}
72	va_start(ap, arg);
73	n = 1;
74	argv[0] = arg;
75	while ((argv[n] = va_arg(ap, char *)) != NULL)
76		n++;
77	va_end(ap);
78	return (_execve(name, __DECONST(char **, argv), environ));
79}
80
81int
82execle(const char *name, const char *arg, ...)
83{
84	va_list ap;
85	const char **argv;
86	char **envp;
87	int n;
88
89	va_start(ap, arg);
90	n = 1;
91	while (va_arg(ap, char *) != NULL)
92		n++;
93	va_end(ap);
94	argv = alloca((n + 1) * sizeof(*argv));
95	if (argv == NULL) {
96		errno = ENOMEM;
97		return (-1);
98	}
99	va_start(ap, arg);
100	n = 1;
101	argv[0] = arg;
102	while ((argv[n] = va_arg(ap, char *)) != NULL)
103		n++;
104	envp = va_arg(ap, char **);
105	va_end(ap);
106	return (_execve(name, __DECONST(char **, argv), envp));
107}
108
109int
110execlp(const char *name, const char *arg, ...)
111{
112	va_list ap;
113	const char **argv;
114	int n;
115
116	va_start(ap, arg);
117	n = 1;
118	while (va_arg(ap, char *) != NULL)
119		n++;
120	va_end(ap);
121	argv = alloca((n + 1) * sizeof(*argv));
122	if (argv == NULL) {
123		errno = ENOMEM;
124		return (-1);
125	}
126	va_start(ap, arg);
127	n = 1;
128	argv[0] = arg;
129	while ((argv[n] = va_arg(ap, char *)) != NULL)
130		n++;
131	va_end(ap);
132	return (execvp(name, __DECONST(char **, argv)));
133}
134
135int
136execv(const char *name, 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 buf[MAXPATHLEN];
156	const char *bp, *np, *op, *p;
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		op = 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	op = path;
176	ln = strlen(name);
177	while (op != NULL) {
178		np = strchrnul(op, ':');
179
180		/*
181		 * It's a SHELL path -- double, leading and trailing colons
182		 * mean the current directory.
183		 */
184		if (np == op) {
185			/* Empty component. */
186			p = ".";
187			lp = 1;
188		} else {
189			/* Non-empty component. */
190			p = op;
191			lp = np - op;
192		}
193
194		/* Advance to the next component or terminate after this. */
195		if (*np == '\0')
196			op = NULL;
197		else
198			op = np + 1;
199
200		/*
201		 * If the path is too long complain.  This is a possible
202		 * security issue; given a way to make the path too long
203		 * the user may execute the wrong program.
204		 */
205		if (lp + ln + 2 > sizeof(buf)) {
206			(void)_write(STDERR_FILENO, execvPe_err_preamble,
207			    sizeof(execvPe_err_preamble) - 1);
208			(void)_write(STDERR_FILENO, p, lp);
209			(void)_write(STDERR_FILENO, execvPe_err_trailer,
210			    sizeof(execvPe_err_trailer) - 1);
211			continue;
212		}
213		bcopy(p, buf, lp);
214		buf[lp] = '/';
215		bcopy(name, buf + lp + 1, ln);
216		buf[lp + ln + 1] = '\0';
217
218retry:		(void)_execve(bp, argv, envp);
219		switch (errno) {
220		case E2BIG:
221			goto done;
222		case ELOOP:
223		case ENAMETOOLONG:
224		case ENOENT:
225			break;
226		case ENOEXEC:
227			for (cnt = 0; argv[cnt]; ++cnt)
228				;
229
230			/*
231			 * cnt may be 0 above; always allocate at least
232			 * 3 entries so that we can at least fit "sh", bp, and
233			 * the NULL terminator.  We can rely on cnt to take into
234			 * account the NULL terminator in all other scenarios,
235			 * as we drop argv[0].
236			 */
237			memp = alloca(MAX(3, cnt + 2) * sizeof(char *));
238			if (memp == NULL) {
239				/* errno = ENOMEM; XXX override ENOEXEC? */
240				goto done;
241			}
242			if (cnt > 0) {
243				memp[0] = argv[0];
244				memp[1] = bp;
245				bcopy(argv + 1, memp + 2, cnt * sizeof(char *));
246			} else {
247				memp[0] = "sh";
248				memp[1] = bp;
249				memp[2] = NULL;
250			}
251 			(void)_execve(_PATH_BSHELL,
252			    __DECONST(char **, memp), envp);
253			goto done;
254		case ENOMEM:
255			goto done;
256		case ENOTDIR:
257			break;
258		case ETXTBSY:
259			/*
260			 * We used to retry here, but sh(1) doesn't.
261			 */
262			goto done;
263		default:
264			/*
265			 * EACCES may be for an inaccessible directory or
266			 * a non-executable file.  Call stat() to decide
267			 * which.  This also handles ambiguities for EFAULT
268			 * and EIO, and undocumented errors like ESTALE.
269			 * We hope that the race for a stat() is unimportant.
270			 */
271			save_errno = errno;
272			if (stat(bp, &sb) != 0)
273				break;
274			if (save_errno == EACCES) {
275				eacces = 1;
276				continue;
277			}
278			errno = save_errno;
279			goto done;
280		}
281	}
282	if (eacces)
283		errno = EACCES;
284	else
285		errno = ENOENT;
286done:
287	return (-1);
288}
289
290int
291execvP(const char *name, const char *path, char * const argv[])
292{
293	return execvPe(name, path, argv, environ);
294}
295
296int
297_execvpe(const char *name, char * const argv[], char * const envp[])
298{
299	const char *path;
300
301	/* Get the path we're searching. */
302	if ((path = getenv("PATH")) == NULL)
303		path = _PATH_DEFPATH;
304
305	return (execvPe(name, path, argv, envp));
306}
307