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