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*53399Sbostic static char sccsid[] = "@(#)exec.c 5.10 (Berkeley) 05/08/92"; 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 ** 3046598Sdonn buildargv(ap, arg, envpp) 3146598Sdonn va_list ap; 3246598Sdonn const char *arg; 3346598Sdonn char ***envpp; 341965Swnj { 35*53399Sbostic static int memsize; 36*53399Sbostic static char **argv; 37*53399Sbostic register int off; 3846592Sbostic 39*53399Sbostic argv = NULL; 40*53399Sbostic for (off = 0;; ++off) { 41*53399Sbostic if (off >= memsize) { 42*53399Sbostic memsize += 50; /* Starts out at 0. */ 43*53399Sbostic memsize *= 2; /* Ramp up fast. */ 44*53399Sbostic if (!(argv = realloc(argv, memsize * sizeof(char *)))) { 45*53399Sbostic memsize = 0; 46*53399Sbostic return (NULL); 47*53399Sbostic } 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 **); 59*53399Sbostic return (argv); 601965Swnj } 611965Swnj 6246598Sdonn int 6346598Sdonn #if __STDC__ 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 81*53399Sbostic 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; 87*53399Sbostic return (-1); 8846592Sbostic } 891965Swnj 9046598Sdonn int 9146598Sdonn #if __STDC__ 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; 115*53399Sbostic return (-1); 11646592Sbostic } 11746592Sbostic 11846598Sdonn int 11946598Sdonn #if __STDC__ 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 137*53399Sbostic if (argv = buildargv(ap, arg, NULL)) 13846592Sbostic (void)execvp(name, argv); 13946592Sbostic va_end(ap); 14046592Sbostic sverrno = errno; 14146592Sbostic free(argv); 14246592Sbostic errno = sverrno; 143*53399Sbostic return (-1); 14446592Sbostic } 14546592Sbostic 14646598Sdonn int 14746598Sdonn execv(name, argv) 14846598Sdonn const char *name; 14946598Sdonn char * const *argv; 15046592Sbostic { 15146592Sbostic (void)execve(name, argv, environ); 152*53399Sbostic return (-1); 15346592Sbostic } 15446592Sbostic 15546598Sdonn int 15646598Sdonn execvp(name, argv) 15746598Sdonn const char *name; 15846598Sdonn char * const *argv; 15946592Sbostic { 160*53399Sbostic static int memsize; 161*53399Sbostic static char **memp; 162*53399Sbostic 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; 216*53399Sbostic case ENOEXEC: 217*53399Sbostic for (cnt = 0; argv[cnt]; ++cnt); 218*53399Sbostic if ((cnt + 2) * sizeof(char *) > memsize) { 219*53399Sbostic memsize = (cnt + 2) * sizeof(char *); 220*53399Sbostic if ((memp = realloc(memp, memsize)) == NULL) { 221*53399Sbostic memsize = 0; 222*53399Sbostic goto done; 223*53399Sbostic } 2241965Swnj } 225*53399Sbostic memp[0] = "sh"; 226*53399Sbostic memp[1] = bp; 227*53399Sbostic bcopy(argv + 1, memp + 2, cnt * sizeof(char *)); 228*53399Sbostic (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); 244*53399Sbostic return (-1); 2451965Swnj } 246