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