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.8 (Berkeley) 03/15/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 #if __STDC__ 18 #include <stdarg.h> 19 #else 20 #include <varargs.h> 21 #endif 22 #include <string.h> 23 #include <stdio.h> 24 #include <paths.h> 25 26 extern char **environ; 27 28 static char ** 29 buildargv(ap, arg, envpp) 30 va_list ap; 31 const char *arg; 32 char ***envpp; 33 { 34 register size_t max, off; 35 register char **argv = NULL; 36 37 for (off = max = 0;; ++off) { 38 if (off >= max) { 39 max += 50; /* Starts out at 0. */ 40 max *= 2; /* Ramp up fast. */ 41 if (!(argv = realloc(argv, max * sizeof(char *)))) 42 return(NULL); 43 if (off == 0) { 44 argv[0] = (char *)arg; 45 off = 1; 46 } 47 } 48 if (!(argv[off] = va_arg(ap, char *))) 49 break; 50 } 51 /* Get environment pointer if need user supposed to provide one. */ 52 if (envpp) 53 *envpp = va_arg(ap, char **); 54 return(argv); 55 } 56 57 int 58 #if __STDC__ 59 execl(const char *name, const char *arg, ...) 60 #else 61 execl(name, arg, va_alist) 62 const char *name; 63 const char *arg; 64 va_dcl 65 #endif 66 { 67 va_list ap; 68 int sverrno; 69 char **argv; 70 71 #if __STDC__ 72 va_start(ap, arg); 73 #else 74 va_start(ap); 75 #endif 76 if (argv = buildargv(ap, arg, (char ***)NULL)) 77 (void)execve(name, argv, environ); 78 va_end(ap); 79 sverrno = errno; 80 free(argv); 81 errno = sverrno; 82 return(-1); 83 } 84 85 int 86 #if __STDC__ 87 execle(const char *name, const char *arg, ...) 88 #else 89 execle(name, arg, va_alist) 90 const char *name; 91 const char *arg; 92 va_dcl 93 #endif 94 { 95 va_list ap; 96 int sverrno; 97 char **argv, **envp; 98 99 #if __STDC__ 100 va_start(ap, arg); 101 #else 102 va_start(ap); 103 #endif 104 if (argv = buildargv(ap, arg, &envp)) 105 (void)execve(name, argv, envp); 106 va_end(ap); 107 sverrno = errno; 108 free(argv); 109 errno = sverrno; 110 return(-1); 111 } 112 113 int 114 #if __STDC__ 115 execlp(const char *name, const char *arg, ...) 116 #else 117 execlp(name, arg, va_alist) 118 const char *name; 119 const char *arg; 120 va_dcl 121 #endif 122 { 123 va_list ap; 124 int sverrno; 125 char **argv; 126 127 #if __STDC__ 128 va_start(ap, arg); 129 #else 130 va_start(ap); 131 #endif 132 if (argv = buildargv(ap, arg, (char ***)NULL)) 133 (void)execvp(name, argv); 134 va_end(ap); 135 sverrno = errno; 136 free(argv); 137 errno = sverrno; 138 return(-1); 139 } 140 141 int 142 execv(name, argv) 143 const char *name; 144 char * const *argv; 145 { 146 (void)execve(name, argv, environ); 147 return(-1); 148 } 149 150 int 151 execvp(name, argv) 152 const char *name; 153 char * const *argv; 154 { 155 register char *p; 156 int eacces, etxtbsy; 157 char *bp, *cur, *path, buf[MAXPATHLEN]; 158 159 /* If it's an absolute or relative path name, it's easy. */ 160 if (index(name, '/')) { 161 bp = (char *)name; 162 cur = path = NULL; 163 goto retry; 164 } 165 bp = buf; 166 167 /* Get the path we're searching. */ 168 if (!(path = getenv("PATH"))) 169 path = _PATH_DEFPATH; 170 cur = path = strdup(path); 171 172 eacces = etxtbsy = 0; 173 while (p = strsep(&cur, ":")) { 174 /* 175 * It's a SHELL path -- double, leading and trailing colons 176 * mean the current directory. 177 */ 178 if (!*p) 179 p = "."; 180 (void)snprintf(buf, sizeof(buf), "%s/%s", p, name); 181 182 retry: (void)execve(bp, argv, environ); 183 switch(errno) { 184 case EACCES: 185 eacces = 1; 186 break; 187 case ENOENT: 188 break; 189 case ENOEXEC: { 190 register size_t cnt; 191 register char **ap; 192 193 for (cnt = 0, ap = (char **)argv; *ap; ++ap, ++cnt); 194 if (ap = malloc((cnt + 2) * sizeof(char *))) { 195 bcopy(argv + 1, ap + 2, cnt * sizeof(char *)); 196 ap[0] = "sh"; 197 ap[1] = bp; 198 (void)execve(_PATH_BSHELL, ap, environ); 199 free(ap); 200 } 201 goto done; 202 } 203 case ETXTBSY: 204 if (etxtbsy < 3) 205 (void)sleep(++etxtbsy); 206 goto retry; 207 default: 208 goto done; 209 } 210 } 211 if (eacces) 212 errno = EACCES; 213 else if (!errno) 214 errno = ENOENT; 215 done: if (path) 216 free(path); 217 return(-1); 218 } 219