11573Srgrimes/*-
21573Srgrimes * Copyright (c) 1991, 1993
31573Srgrimes *	The Regents of the University of California.  All rights reserved.
41573Srgrimes *
51573Srgrimes * Redistribution and use in source and binary forms, with or without
61573Srgrimes * modification, are permitted provided that the following conditions
71573Srgrimes * are met:
81573Srgrimes * 1. Redistributions of source code must retain the above copyright
91573Srgrimes *    notice, this list of conditions and the following disclaimer.
101573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111573Srgrimes *    notice, this list of conditions and the following disclaimer in the
121573Srgrimes *    documentation and/or other materials provided with the distribution.
131573Srgrimes * 4. Neither the name of the University nor the names of its contributors
141573Srgrimes *    may be used to endorse or promote products derived from this software
151573Srgrimes *    without specific prior written permission.
161573Srgrimes *
171573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
181573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201573Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
211573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271573Srgrimes * SUCH DAMAGE.
281573Srgrimes */
291573Srgrimes
301573Srgrimes#if defined(LIBC_SCCS) && !defined(lint)
311573Srgrimesstatic char sccsid[] = "@(#)exec.c	8.1 (Berkeley) 6/4/93";
321573Srgrimes#endif /* LIBC_SCCS and not lint */
3390041Sobrien#include <sys/cdefs.h>
3490041Sobrien__FBSDID("$FreeBSD$");
351573Srgrimes
3671579Sdeischen#include "namespace.h"
371573Srgrimes#include <sys/param.h>
381573Srgrimes#include <sys/types.h>
3930399Sbde#include <sys/stat.h>
401573Srgrimes#include <errno.h>
411573Srgrimes#include <unistd.h>
421573Srgrimes#include <stdlib.h>
431573Srgrimes#include <string.h>
441573Srgrimes#include <stdio.h>
451573Srgrimes#include <paths.h>
461573Srgrimes
471573Srgrimes#include <stdarg.h>
4871579Sdeischen#include "un-namespace.h"
49179947Sed#include "libc_private.h"
501573Srgrimes
511573Srgrimesextern char **environ;
521573Srgrimes
531573Srgrimesint
541573Srgrimesexecl(const char *name, const char *arg, ...)
551573Srgrimes{
561573Srgrimes	va_list ap;
57200136Sed	const char **argv;
5840356Sdes	int n;
591573Srgrimes
601573Srgrimes	va_start(ap, arg);
6140357Sdes	n = 1;
6240356Sdes	while (va_arg(ap, char *) != NULL)
6340396Sdes		n++;
641573Srgrimes	va_end(ap);
6540396Sdes	argv = alloca((n + 1) * sizeof(*argv));
6644974Speter	if (argv == NULL) {
6744974Speter		errno = ENOMEM;
6840356Sdes		return (-1);
6944974Speter	}
7040356Sdes	va_start(ap, arg);
7140357Sdes	n = 1;
72200136Sed	argv[0] = arg;
7340356Sdes	while ((argv[n] = va_arg(ap, char *)) != NULL)
7440356Sdes		n++;
7540356Sdes	va_end(ap);
76200136Sed	return (_execve(name, __DECONST(char **, argv), environ));
771573Srgrimes}
781573Srgrimes
791573Srgrimesint
801573Srgrimesexecle(const char *name, const char *arg, ...)
811573Srgrimes{
821573Srgrimes	va_list ap;
83200136Sed	const char **argv;
84200136Sed	char **envp;
8540396Sdes	int n;
861573Srgrimes
871573Srgrimes	va_start(ap, arg);
8840396Sdes	n = 1;
8940396Sdes	while (va_arg(ap, char *) != NULL)
9040396Sdes		n++;
911573Srgrimes	va_end(ap);
9240396Sdes	argv = alloca((n + 1) * sizeof(*argv));
9344974Speter	if (argv == NULL) {
9444974Speter		errno = ENOMEM;
9540396Sdes		return (-1);
9644974Speter	}
9740396Sdes	va_start(ap, arg);
9840396Sdes	n = 1;
99200136Sed	argv[0] = arg;
10040396Sdes	while ((argv[n] = va_arg(ap, char *)) != NULL)
10140396Sdes		n++;
10240396Sdes	envp = va_arg(ap, char **);
10340396Sdes	va_end(ap);
104200136Sed	return (_execve(name, __DECONST(char **, argv), envp));
1051573Srgrimes}
1061573Srgrimes
1071573Srgrimesint
1081573Srgrimesexeclp(const char *name, const char *arg, ...)
1091573Srgrimes{
1101573Srgrimes	va_list ap;
111200136Sed	const char **argv;
11244974Speter	int n;
1131573Srgrimes
1141573Srgrimes	va_start(ap, arg);
11544974Speter	n = 1;
11644974Speter	while (va_arg(ap, char *) != NULL)
11744974Speter		n++;
1181573Srgrimes	va_end(ap);
11944974Speter	argv = alloca((n + 1) * sizeof(*argv));
12044974Speter	if (argv == NULL) {
12144974Speter		errno = ENOMEM;
12244974Speter		return (-1);
12344974Speter	}
12444974Speter	va_start(ap, arg);
12544974Speter	n = 1;
126200136Sed	argv[0] = arg;
12744974Speter	while ((argv[n] = va_arg(ap, char *)) != NULL)
12844974Speter		n++;
12944974Speter	va_end(ap);
130200136Sed	return (execvp(name, __DECONST(char **, argv)));
1311573Srgrimes}
1321573Srgrimes
1331573Srgrimesint
1341573Srgrimesexecv(name, argv)
1351573Srgrimes	const char *name;
1361573Srgrimes	char * const *argv;
1371573Srgrimes{
13871579Sdeischen	(void)_execve(name, argv, environ);
1391573Srgrimes	return (-1);
1401573Srgrimes}
1411573Srgrimes
1421573Srgrimesint
143117111Sbdeexecvp(const char *name, char * const *argv)
144117030Sgordon{
145179947Sed	return (_execvpe(name, argv, environ));
146117030Sgordon}
147117030Sgordon
148179838Sdavidxustatic int
149200136SedexecvPe(const char *name, const char *path, char * const *argv,
150200136Sed    char * const *envp)
1511573Srgrimes{
152200136Sed	const char **memp;
153200136Sed	size_t cnt, lp, ln;
15430399Sbde	int eacces, save_errno;
155200136Sed	char *cur, buf[MAXPATHLEN];
156200136Sed	const char *p, *bp;
15730399Sbde	struct stat sb;
1581573Srgrimes
15930399Sbde	eacces = 0;
16019850Sbde
1611573Srgrimes	/* If it's an absolute or relative path name, it's easy. */
162229403Sed	if (strchr(name, '/')) {
163200136Sed		bp = name;
164117030Sgordon		cur = NULL;
1651573Srgrimes		goto retry;
1661573Srgrimes	}
1671573Srgrimes	bp = buf;
1681573Srgrimes
16919852Sbde	/* If it's an empty path name, fail in the usual POSIX way. */
17019852Sbde	if (*name == '\0') {
17119852Sbde		errno = ENOENT;
17219852Sbde		return (-1);
17319852Sbde	}
17419852Sbde
17544974Speter	cur = alloca(strlen(path) + 1);
17644974Speter	if (cur == NULL) {
17744974Speter		errno = ENOMEM;
17844974Speter		return (-1);
17944974Speter	}
18044974Speter	strcpy(cur, path);
181117111Sbde	while ((p = strsep(&cur, ":")) != NULL) {
1821573Srgrimes		/*
1831573Srgrimes		 * It's a SHELL path -- double, leading and trailing colons
1841573Srgrimes		 * mean the current directory.
1851573Srgrimes		 */
186117111Sbde		if (*p == '\0') {
1871573Srgrimes			p = ".";
1881573Srgrimes			lp = 1;
1891573Srgrimes		} else
1901573Srgrimes			lp = strlen(p);
1911573Srgrimes		ln = strlen(name);
1921573Srgrimes
1931573Srgrimes		/*
1941573Srgrimes		 * If the path is too long complain.  This is a possible
1951573Srgrimes		 * security issue; given a way to make the path too long
1961573Srgrimes		 * the user may execute the wrong program.
1971573Srgrimes		 */
1981573Srgrimes		if (lp + ln + 2 > sizeof(buf)) {
199117030Sgordon			(void)_write(STDERR_FILENO, "execvP: ", 8);
20056698Sjasone			(void)_write(STDERR_FILENO, p, lp);
20156698Sjasone			(void)_write(STDERR_FILENO, ": path too long\n",
20255837Sjasone			    16);
2031573Srgrimes			continue;
2041573Srgrimes		}
2051573Srgrimes		bcopy(p, buf, lp);
2061573Srgrimes		buf[lp] = '/';
2071573Srgrimes		bcopy(name, buf + lp + 1, ln);
2081573Srgrimes		buf[lp + ln + 1] = '\0';
2091573Srgrimes
210199862Sedretry:		(void)_execve(bp, argv, envp);
211117111Sbde		switch (errno) {
21230399Sbde		case E2BIG:
21330399Sbde			goto done;
21430399Sbde		case ELOOP:
21530399Sbde		case ENAMETOOLONG:
2161573Srgrimes		case ENOENT:
2171573Srgrimes			break;
2181573Srgrimes		case ENOEXEC:
2195070Sbde			for (cnt = 0; argv[cnt]; ++cnt)
2205070Sbde				;
22144984Speter			memp = alloca((cnt + 2) * sizeof(char *));
22244974Speter			if (memp == NULL) {
22344974Speter				/* errno = ENOMEM; XXX override ENOEXEC? */
2245070Sbde				goto done;
22544974Speter			}
2261573Srgrimes			memp[0] = "sh";
2271573Srgrimes			memp[1] = bp;
2281573Srgrimes			bcopy(argv + 1, memp + 2, cnt * sizeof(char *));
229200136Sed 			(void)_execve(_PATH_BSHELL,
230200136Sed			    __DECONST(char **, memp), envp);
2311573Srgrimes			goto done;
23230399Sbde		case ENOMEM:
23330399Sbde			goto done;
23430399Sbde		case ENOTDIR:
23530399Sbde			break;
2361573Srgrimes		case ETXTBSY:
23730399Sbde			/*
23830399Sbde			 * We used to retry here, but sh(1) doesn't.
23930399Sbde			 */
24030399Sbde			goto done;
2411573Srgrimes		default:
24230399Sbde			/*
24330399Sbde			 * EACCES may be for an inaccessible directory or
24430399Sbde			 * a non-executable file.  Call stat() to decide
24530399Sbde			 * which.  This also handles ambiguities for EFAULT
24630399Sbde			 * and EIO, and undocumented errors like ESTALE.
24730399Sbde			 * We hope that the race for a stat() is unimportant.
24830399Sbde			 */
24930399Sbde			save_errno = errno;
25031309Sbde			if (stat(bp, &sb) != 0)
25130399Sbde				break;
25230399Sbde			if (save_errno == EACCES) {
25330399Sbde				eacces = 1;
25430399Sbde				continue;
25530399Sbde			}
25630399Sbde			errno = save_errno;
2571573Srgrimes			goto done;
2581573Srgrimes		}
2591573Srgrimes	}
2601573Srgrimes	if (eacces)
2611573Srgrimes		errno = EACCES;
26230399Sbde	else
2631573Srgrimes		errno = ENOENT;
26444974Speterdone:
2651573Srgrimes	return (-1);
2661573Srgrimes}
267179838Sdavidxu
268179838Sdavidxuint
269179838SdavidxuexecvP(const char *name, const char *path, char * const argv[])
270179838Sdavidxu{
271179838Sdavidxu	return execvPe(name, path, argv, environ);
272179838Sdavidxu}
273179838Sdavidxu
274179838Sdavidxuint
275179947Sed_execvpe(const char *name, char * const argv[], char * const envp[])
276179838Sdavidxu{
277179838Sdavidxu	const char *path;
278179838Sdavidxu
279179838Sdavidxu	/* Get the path we're searching. */
280179838Sdavidxu	if ((path = getenv("PATH")) == NULL)
281179838Sdavidxu		path = _PATH_DEFPATH;
282179838Sdavidxu
283179838Sdavidxu	return (execvPe(name, path, argv, envp));
284179838Sdavidxu}
285