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