1 /*- 2 * Copyright (c) 1991 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #if defined(LIBC_SCCS) && !defined(lint) 9 static char sccsid[] = "@(#)exec.c 5.5 (Berkeley) 02/23/91"; 10 #endif /* LIBC_SCCS and not lint */ 11 12 #include <sys/param.h> 13 #include <sys/types.h> 14 #include <errno.h> 15 #include <unistd.h> 16 #include <stdlib.h> 17 #include <stdarg.h> 18 #include <string.h> 19 #include <stdio.h> 20 #include <paths.h> 21 22 extern char **environ; 23 24 static char **buildargv(va_list ap, const char *arg, char ***envpp) 25 { 26 register size_t max, off; 27 register char **argv; 28 29 for (off = max = 0;; ++off) { 30 if (off >= max) { 31 max += 50; /* Starts out at 0. */ 32 max *= 2; /* Ramp up fast. */ 33 if (!(argv = realloc(argv, max * sizeof(char *)))) 34 return(NULL); 35 if (off == 0) { 36 argv[0] = (char *)arg; 37 off = 1; 38 } 39 } 40 if (!(argv[off] = va_arg(ap, char *))) 41 break; 42 } 43 /* Get environment pointer if need user supposed to provide one. */ 44 if (envpp) 45 *envpp = va_arg(ap, char **); 46 return(argv); 47 } 48 49 int execl(const char *name, const char *arg, ...) 50 { 51 va_list ap; 52 int sverrno; 53 char **argv; 54 55 va_start(ap, arg); 56 if (argv = buildargv(ap, arg, (char ***)NULL)) 57 (void)execve(name, argv, environ); 58 va_end(ap); 59 sverrno = errno; 60 free(argv); 61 errno = sverrno; 62 return(-1); 63 } 64 65 int execle(const char *name, const char *arg, ...) 66 { 67 va_list ap; 68 int sverrno; 69 char **argv, **envp; 70 71 va_start(ap, arg); 72 if (argv = buildargv(ap, arg, &envp)) 73 (void)execve(name, argv, envp); 74 va_end(ap); 75 sverrno = errno; 76 free(argv); 77 errno = sverrno; 78 return(-1); 79 } 80 81 int execlp(const char *name, const char *arg, ...) 82 { 83 va_list ap; 84 int sverrno; 85 char **argv; 86 87 va_start(ap, arg); 88 if (argv = buildargv(ap, arg, (char ***)NULL)) 89 (void)execvp(name, argv); 90 va_end(ap); 91 sverrno = errno; 92 free(argv); 93 errno = sverrno; 94 return(-1); 95 } 96 97 int execv(const char *name, char * const *argv) 98 { 99 (void)execve(name, argv, environ); 100 return(-1); 101 } 102 103 int execvp(const char *name, char * const *argv) 104 { 105 register char *p; 106 int eacces, etxtbsy; 107 char *cur, *path, buf[MAXPATHLEN]; 108 109 /* If it's an absolute or relative path name, it's easy. */ 110 if (index(name, '/')) { 111 (void)execve(name, argv, environ); 112 return(-1); 113 } 114 115 /* Get the path we're searching. */ 116 if (!(path = getenv("PATH"))) 117 path = _PATH_DEFPATH; 118 cur = path = strdup(path); 119 120 eacces = etxtbsy = 0; 121 while (p = strsep(&cur, ":")) { 122 /* 123 * It's a SHELL path -- double, leading and trailing colons 124 * mean the current directory. 125 */ 126 if (!*p) 127 p = "."; 128 (void)snprintf(buf, sizeof(buf), "%s/%s", p, name); 129 130 retry: (void)execve(buf, argv, environ); 131 switch(errno) { 132 case EACCES: 133 eacces = 1; 134 break; 135 case ENOENT: 136 break; 137 case ENOEXEC: { 138 register size_t cnt; 139 register char **ap; 140 141 for (cnt = 0, ap = (char **)argv; *ap; ++ap, ++cnt); 142 if (ap = malloc((cnt + 2) * sizeof(char *))) { 143 bcopy(argv, ap + 2, cnt * sizeof(char *)); 144 ap[0] = "sh"; 145 ap[1] = buf; 146 (void)execve(_PATH_BSHELL, ap, environ); 147 free(ap); 148 } 149 goto done; 150 } 151 case ETXTBSY: 152 if (etxtbsy < 3) 153 (void)sleep(++etxtbsy); 154 goto retry; 155 default: 156 goto done; 157 } 158 } 159 if (eacces) 160 errno = EACCES; 161 else if (!errno) 162 errno = ENOENT; 163 done: free(path); 164 return(-1); 165 } 166