146592Sbostic /*-
2*61111Sbostic * Copyright (c) 1991, 1993
3*61111Sbostic * The Regents of the University of California. All rights reserved.
446592Sbostic *
546592Sbostic * %sccs.include.redist.c%
646592Sbostic */
746592Sbostic
826549Sdonn #if defined(LIBC_SCCS) && !defined(lint)
9*61111Sbostic static char sccsid[] = "@(#)exec.c 8.1 (Berkeley) 06/04/93";
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>
1750056Sbostic #include <string.h>
1850056Sbostic #include <stdio.h>
1950056Sbostic #include <paths.h>
2050056Sbostic
2146598Sdonn #if __STDC__
2246592Sbostic #include <stdarg.h>
2346598Sdonn #else
2446598Sdonn #include <varargs.h>
2546598Sdonn #endif
261965Swnj
2746592Sbostic extern char **environ;
281965Swnj
2946598Sdonn static char **
buildargv(ap,arg,envpp)3046598Sdonn buildargv(ap, arg, envpp)
3146598Sdonn va_list ap;
3246598Sdonn const char *arg;
3346598Sdonn char ***envpp;
341965Swnj {
3553399Sbostic static int memsize;
3653399Sbostic static char **argv;
3753399Sbostic register int off;
3846592Sbostic
3953399Sbostic argv = NULL;
4053399Sbostic for (off = 0;; ++off) {
4153399Sbostic if (off >= memsize) {
4253399Sbostic memsize += 50; /* Starts out at 0. */
4353399Sbostic memsize *= 2; /* Ramp up fast. */
4453399Sbostic if (!(argv = realloc(argv, memsize * sizeof(char *)))) {
4553399Sbostic memsize = 0;
4653399Sbostic return (NULL);
4753399Sbostic }
4846592Sbostic if (off == 0) {
4946592Sbostic argv[0] = (char *)arg;
5046592Sbostic off = 1;
5146592Sbostic }
5246592Sbostic }
5346592Sbostic if (!(argv[off] = va_arg(ap, char *)))
5446592Sbostic break;
5546592Sbostic }
5650056Sbostic /* Get environment pointer if user supposed to provide one. */
5746592Sbostic if (envpp)
5846592Sbostic *envpp = va_arg(ap, char **);
5953399Sbostic return (argv);
601965Swnj }
611965Swnj
6246598Sdonn int
6346598Sdonn #if __STDC__
execl(const char * name,const char * arg,...)6446598Sdonn execl(const char *name, const char *arg, ...)
6546598Sdonn #else
6646598Sdonn execl(name, arg, va_alist)
6746598Sdonn const char *name;
6846598Sdonn const char *arg;
6946598Sdonn va_dcl
7046598Sdonn #endif
711965Swnj {
7246592Sbostic va_list ap;
7346592Sbostic int sverrno;
7446592Sbostic char **argv;
751965Swnj
7646598Sdonn #if __STDC__
7746592Sbostic va_start(ap, arg);
7846598Sdonn #else
7946598Sdonn va_start(ap);
8046598Sdonn #endif
8153399Sbostic if (argv = buildargv(ap, arg, NULL))
8246592Sbostic (void)execve(name, argv, environ);
8346592Sbostic va_end(ap);
8446592Sbostic sverrno = errno;
8546592Sbostic free(argv);
8646592Sbostic errno = sverrno;
8753399Sbostic return (-1);
8846592Sbostic }
891965Swnj
9046598Sdonn int
9146598Sdonn #if __STDC__
execle(const char * name,const char * arg,...)9246598Sdonn execle(const char *name, const char *arg, ...)
9346598Sdonn #else
9446598Sdonn execle(name, arg, va_alist)
9546598Sdonn const char *name;
9646598Sdonn const char *arg;
9746598Sdonn va_dcl
9846598Sdonn #endif
9946592Sbostic {
10046592Sbostic va_list ap;
10146592Sbostic int sverrno;
10246592Sbostic char **argv, **envp;
10346592Sbostic
10446598Sdonn #if __STDC__
10546592Sbostic va_start(ap, arg);
10646598Sdonn #else
10746598Sdonn va_start(ap);
10846598Sdonn #endif
10946592Sbostic if (argv = buildargv(ap, arg, &envp))
11046592Sbostic (void)execve(name, argv, envp);
11146592Sbostic va_end(ap);
11246592Sbostic sverrno = errno;
11346592Sbostic free(argv);
11446592Sbostic errno = sverrno;
11553399Sbostic return (-1);
11646592Sbostic }
11746592Sbostic
11846598Sdonn int
11946598Sdonn #if __STDC__
execlp(const char * name,const char * arg,...)12046598Sdonn execlp(const char *name, const char *arg, ...)
12146598Sdonn #else
12246598Sdonn execlp(name, arg, va_alist)
12346598Sdonn const char *name;
12446598Sdonn const char *arg;
12546598Sdonn va_dcl
12646598Sdonn #endif
12746592Sbostic {
12846592Sbostic va_list ap;
12946592Sbostic int sverrno;
13046592Sbostic char **argv;
13146592Sbostic
13246598Sdonn #if __STDC__
13346592Sbostic va_start(ap, arg);
13446598Sdonn #else
13546598Sdonn va_start(ap);
13646598Sdonn #endif
13753399Sbostic if (argv = buildargv(ap, arg, NULL))
13846592Sbostic (void)execvp(name, argv);
13946592Sbostic va_end(ap);
14046592Sbostic sverrno = errno;
14146592Sbostic free(argv);
14246592Sbostic errno = sverrno;
14353399Sbostic return (-1);
14446592Sbostic }
14546592Sbostic
14646598Sdonn int
execv(name,argv)14746598Sdonn execv(name, argv)
14846598Sdonn const char *name;
14946598Sdonn char * const *argv;
15046592Sbostic {
15146592Sbostic (void)execve(name, argv, environ);
15253399Sbostic return (-1);
15346592Sbostic }
15446592Sbostic
15546598Sdonn int
execvp(name,argv)15646598Sdonn execvp(name, argv)
15746598Sdonn const char *name;
15846598Sdonn char * const *argv;
15946592Sbostic {
16053399Sbostic static int memsize;
16153399Sbostic static char **memp;
16253399Sbostic register int cnt, lp, ln;
16346592Sbostic register char *p;
16446592Sbostic int eacces, etxtbsy;
16547448Sbostic char *bp, *cur, *path, buf[MAXPATHLEN];
16646592Sbostic
16746592Sbostic /* If it's an absolute or relative path name, it's easy. */
16846592Sbostic if (index(name, '/')) {
16947448Sbostic bp = (char *)name;
17047448Sbostic cur = path = NULL;
17147448Sbostic goto retry;
17246592Sbostic }
17347448Sbostic bp = buf;
17446592Sbostic
17546592Sbostic /* Get the path we're searching. */
17646592Sbostic if (!(path = getenv("PATH")))
17746592Sbostic path = _PATH_DEFPATH;
17846592Sbostic cur = path = strdup(path);
17946592Sbostic
18046592Sbostic eacces = etxtbsy = 0;
18146592Sbostic while (p = strsep(&cur, ":")) {
18246592Sbostic /*
18346592Sbostic * It's a SHELL path -- double, leading and trailing colons
18446592Sbostic * mean the current directory.
18546592Sbostic */
18650056Sbostic if (!*p) {
18746592Sbostic p = ".";
18850056Sbostic lp = 1;
18950056Sbostic } else
19050056Sbostic lp = strlen(p);
19150056Sbostic ln = strlen(name);
19246592Sbostic
19350056Sbostic /*
19450056Sbostic * If the path is too long complain. This is a possible
19550056Sbostic * security issue; given a way to make the path too long
19650056Sbostic * the user may execute the wrong program.
19750056Sbostic */
19850056Sbostic if (lp + ln + 2 > sizeof(buf)) {
19950056Sbostic (void)write(STDERR_FILENO, "execvp: ", 8);
20050056Sbostic (void)write(STDERR_FILENO, p, lp);
20150056Sbostic (void)write(STDERR_FILENO, ": path too long\n", 16);
20250056Sbostic continue;
20350056Sbostic }
20450056Sbostic bcopy(p, buf, lp);
20550056Sbostic buf[lp] = '/';
20650056Sbostic bcopy(name, buf + lp + 1, ln);
20750056Sbostic buf[lp + ln + 1] = '\0';
20850056Sbostic
20947448Sbostic retry: (void)execve(bp, argv, environ);
2101965Swnj switch(errno) {
21146592Sbostic case EACCES:
21246592Sbostic eacces = 1;
21346592Sbostic break;
21446592Sbostic case ENOENT:
21546592Sbostic break;
21653399Sbostic case ENOEXEC:
21753399Sbostic for (cnt = 0; argv[cnt]; ++cnt);
21853399Sbostic if ((cnt + 2) * sizeof(char *) > memsize) {
21953399Sbostic memsize = (cnt + 2) * sizeof(char *);
22053399Sbostic if ((memp = realloc(memp, memsize)) == NULL) {
22153399Sbostic memsize = 0;
22253399Sbostic goto done;
22353399Sbostic }
2241965Swnj }
22553399Sbostic memp[0] = "sh";
22653399Sbostic memp[1] = bp;
22753399Sbostic bcopy(argv + 1, memp + 2, cnt * sizeof(char *));
22853399Sbostic (void)execve(_PATH_BSHELL, memp, environ);
22946592Sbostic goto done;
2301965Swnj case ETXTBSY:
23146592Sbostic if (etxtbsy < 3)
23246592Sbostic (void)sleep(++etxtbsy);
2331965Swnj goto retry;
23446592Sbostic default:
23546592Sbostic goto done;
2361965Swnj }
23746592Sbostic }
2381965Swnj if (eacces)
2391965Swnj errno = EACCES;
24046592Sbostic else if (!errno)
24146592Sbostic errno = ENOENT;
24247448Sbostic done: if (path)
24347448Sbostic free(path);
24453399Sbostic return (-1);
2451965Swnj }
246