xref: /csrg-svn/lib/libc/gen/exec.c (revision 50056)
146592Sbostic /*-
246592Sbostic  * Copyright (c) 1991 The Regents of the University of California.
346592Sbostic  * All rights reserved.
446592Sbostic  *
546592Sbostic  * %sccs.include.redist.c%
646592Sbostic  */
746592Sbostic 
826549Sdonn #if defined(LIBC_SCCS) && !defined(lint)
9*50056Sbostic static char sccsid[] = "@(#)exec.c	5.9 (Berkeley) 06/17/91";
1046592Sbostic #endif /* LIBC_SCCS and not lint */
1122086Smckusick 
1246592Sbostic #include <sys/param.h>
1346592Sbostic #include <sys/types.h>
141965Swnj #include <errno.h>
1546592Sbostic #include <unistd.h>
1646572Sdonn #include <stdlib.h>
17*50056Sbostic #include <string.h>
18*50056Sbostic #include <stdio.h>
19*50056Sbostic #include <paths.h>
20*50056Sbostic 
2146598Sdonn #if __STDC__
2246592Sbostic #include <stdarg.h>
2346598Sdonn #else
2446598Sdonn #include <varargs.h>
2546598Sdonn #endif
261965Swnj 
2746592Sbostic extern char **environ;
281965Swnj 
2946598Sdonn static char **
3046598Sdonn buildargv(ap, arg, envpp)
3146598Sdonn 	va_list ap;
3246598Sdonn 	const char *arg;
3346598Sdonn 	char ***envpp;
341965Swnj {
3546592Sbostic 	register size_t max, off;
3647039Sbostic 	register char **argv = NULL;
3746592Sbostic 
3846592Sbostic 	for (off = max = 0;; ++off) {
3946592Sbostic 		if (off >= max) {
4046592Sbostic 			max += 50;	/* Starts out at 0. */
4146592Sbostic 			max *= 2;	/* Ramp up fast. */
4246592Sbostic 			if (!(argv = realloc(argv, max * sizeof(char *))))
4346592Sbostic 				return(NULL);
4446592Sbostic 			if (off == 0) {
4546592Sbostic 				argv[0] = (char *)arg;
4646592Sbostic 				off = 1;
4746592Sbostic 			}
4846592Sbostic 		}
4946592Sbostic 		if (!(argv[off] = va_arg(ap, char *)))
5046592Sbostic 			break;
5146592Sbostic 	}
52*50056Sbostic 	/* Get environment pointer if user supposed to provide one. */
5346592Sbostic 	if (envpp)
5446592Sbostic 		*envpp = va_arg(ap, char **);
5546592Sbostic 	return(argv);
561965Swnj }
571965Swnj 
5846598Sdonn int
5946598Sdonn #if __STDC__
6046598Sdonn execl(const char *name, const char *arg, ...)
6146598Sdonn #else
6246598Sdonn execl(name, arg, va_alist)
6346598Sdonn 	const char *name;
6446598Sdonn 	const char *arg;
6546598Sdonn 	va_dcl
6646598Sdonn #endif
671965Swnj {
6846592Sbostic 	va_list ap;
6946592Sbostic 	int sverrno;
7046592Sbostic 	char **argv;
711965Swnj 
7246598Sdonn #if __STDC__
7346592Sbostic 	va_start(ap, arg);
7446598Sdonn #else
7546598Sdonn 	va_start(ap);
7646598Sdonn #endif
7746592Sbostic 	if (argv = buildargv(ap, arg, (char ***)NULL))
7846592Sbostic 		(void)execve(name, argv, environ);
7946592Sbostic 	va_end(ap);
8046592Sbostic 	sverrno = errno;
8146592Sbostic 	free(argv);
8246592Sbostic 	errno = sverrno;
8346592Sbostic 	return(-1);
8446592Sbostic }
851965Swnj 
8646598Sdonn int
8746598Sdonn #if __STDC__
8846598Sdonn execle(const char *name, const char *arg, ...)
8946598Sdonn #else
9046598Sdonn execle(name, arg, va_alist)
9146598Sdonn 	const char *name;
9246598Sdonn 	const char *arg;
9346598Sdonn 	va_dcl
9446598Sdonn #endif
9546592Sbostic {
9646592Sbostic 	va_list ap;
9746592Sbostic 	int sverrno;
9846592Sbostic 	char **argv, **envp;
9946592Sbostic 
10046598Sdonn #if __STDC__
10146592Sbostic 	va_start(ap, arg);
10246598Sdonn #else
10346598Sdonn 	va_start(ap);
10446598Sdonn #endif
10546592Sbostic 	if (argv = buildargv(ap, arg, &envp))
10646592Sbostic 		(void)execve(name, argv, envp);
10746592Sbostic 	va_end(ap);
10846592Sbostic 	sverrno = errno;
10946592Sbostic 	free(argv);
11046592Sbostic 	errno = sverrno;
11146592Sbostic 	return(-1);
11246592Sbostic }
11346592Sbostic 
11446598Sdonn int
11546598Sdonn #if __STDC__
11646598Sdonn execlp(const char *name, const char *arg, ...)
11746598Sdonn #else
11846598Sdonn execlp(name, arg, va_alist)
11946598Sdonn 	const char *name;
12046598Sdonn 	const char *arg;
12146598Sdonn 	va_dcl
12246598Sdonn #endif
12346592Sbostic {
12446592Sbostic 	va_list ap;
12546592Sbostic 	int sverrno;
12646592Sbostic 	char **argv;
12746592Sbostic 
12846598Sdonn #if __STDC__
12946592Sbostic 	va_start(ap, arg);
13046598Sdonn #else
13146598Sdonn 	va_start(ap);
13246598Sdonn #endif
13346592Sbostic 	if (argv = buildargv(ap, arg, (char ***)NULL))
13446592Sbostic 		(void)execvp(name, argv);
13546592Sbostic 	va_end(ap);
13646592Sbostic 	sverrno = errno;
13746592Sbostic 	free(argv);
13846592Sbostic 	errno = sverrno;
13946592Sbostic 	return(-1);
14046592Sbostic }
14146592Sbostic 
14246598Sdonn int
14346598Sdonn execv(name, argv)
14446598Sdonn 	const char *name;
14546598Sdonn 	char * const *argv;
14646592Sbostic {
14746592Sbostic 	(void)execve(name, argv, environ);
14846592Sbostic 	return(-1);
14946592Sbostic }
15046592Sbostic 
15146598Sdonn int
15246598Sdonn execvp(name, argv)
15346598Sdonn 	const char *name;
15446598Sdonn 	char * const *argv;
15546592Sbostic {
156*50056Sbostic 	register int lp, ln;
15746592Sbostic 	register char *p;
15846592Sbostic 	int eacces, etxtbsy;
15947448Sbostic 	char *bp, *cur, *path, buf[MAXPATHLEN];
16046592Sbostic 
16146592Sbostic 	/* If it's an absolute or relative path name, it's easy. */
16246592Sbostic 	if (index(name, '/')) {
16347448Sbostic 		bp = (char *)name;
16447448Sbostic 		cur = path = NULL;
16547448Sbostic 		goto retry;
16646592Sbostic 	}
16747448Sbostic 	bp = buf;
16846592Sbostic 
16946592Sbostic 	/* Get the path we're searching. */
17046592Sbostic 	if (!(path = getenv("PATH")))
17146592Sbostic 		path = _PATH_DEFPATH;
17246592Sbostic 	cur = path = strdup(path);
17346592Sbostic 
17446592Sbostic 	eacces = etxtbsy = 0;
17546592Sbostic 	while (p = strsep(&cur, ":")) {
17646592Sbostic 		/*
17746592Sbostic 		 * It's a SHELL path -- double, leading and trailing colons
17846592Sbostic 		 * mean the current directory.
17946592Sbostic 		 */
180*50056Sbostic 		if (!*p) {
18146592Sbostic 			p = ".";
182*50056Sbostic 			lp = 1;
183*50056Sbostic 		} else
184*50056Sbostic 			lp = strlen(p);
185*50056Sbostic 		ln = strlen(name);
18646592Sbostic 
187*50056Sbostic 		/*
188*50056Sbostic 		 * If the path is too long complain.  This is a possible
189*50056Sbostic 		 * security issue; given a way to make the path too long
190*50056Sbostic 		 * the user may execute the wrong program.
191*50056Sbostic 		 */
192*50056Sbostic 		if (lp + ln + 2 > sizeof(buf)) {
193*50056Sbostic 			(void)write(STDERR_FILENO, "execvp: ", 8);
194*50056Sbostic 			(void)write(STDERR_FILENO, p, lp);
195*50056Sbostic 			(void)write(STDERR_FILENO, ": path too long\n", 16);
196*50056Sbostic 			continue;
197*50056Sbostic 		}
198*50056Sbostic 		bcopy(p, buf, lp);
199*50056Sbostic 		buf[lp] = '/';
200*50056Sbostic 		bcopy(name, buf + lp + 1, ln);
201*50056Sbostic 		buf[lp + ln + 1] = '\0';
202*50056Sbostic 
20347448Sbostic retry:		(void)execve(bp, argv, environ);
2041965Swnj 		switch(errno) {
20546592Sbostic 		case EACCES:
20646592Sbostic 			eacces = 1;
20746592Sbostic 			break;
20846592Sbostic 		case ENOENT:
20946592Sbostic 			break;
21046592Sbostic 		case ENOEXEC: {
21146592Sbostic 			register size_t cnt;
21246592Sbostic 			register char **ap;
21346592Sbostic 
21446592Sbostic 			for (cnt = 0, ap = (char **)argv; *ap; ++ap, ++cnt);
21546592Sbostic 			if (ap = malloc((cnt + 2) * sizeof(char *))) {
21647448Sbostic 				bcopy(argv + 1, ap + 2, cnt * sizeof(char *));
21746592Sbostic 				ap[0] = "sh";
21847448Sbostic 				ap[1] = bp;
21946592Sbostic 				(void)execve(_PATH_BSHELL, ap, environ);
22046592Sbostic 				free(ap);
2211965Swnj 			}
22246592Sbostic 			goto done;
22346592Sbostic 		}
2241965Swnj 		case ETXTBSY:
22546592Sbostic 			if (etxtbsy < 3)
22646592Sbostic 				(void)sleep(++etxtbsy);
2271965Swnj 			goto retry;
22846592Sbostic 		default:
22946592Sbostic 			goto done;
2301965Swnj 		}
23146592Sbostic 	}
2321965Swnj 	if (eacces)
2331965Swnj 		errno = EACCES;
23446592Sbostic 	else if (!errno)
23546592Sbostic 		errno = ENOENT;
23647448Sbostic done:	if (path)
23747448Sbostic 		free(path);
2381965Swnj 	return(-1);
2391965Swnj }
240