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.7 (Berkeley) 03/06/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 *cur, *path, buf[MAXPATHLEN]; 158 159 /* If it's an absolute or relative path name, it's easy. */ 160 if (index(name, '/')) { 161 (void)execve(name, argv, environ); 162 return(-1); 163 } 164 165 /* Get the path we're searching. */ 166 if (!(path = getenv("PATH"))) 167 path = _PATH_DEFPATH; 168 cur = path = strdup(path); 169 170 eacces = etxtbsy = 0; 171 while (p = strsep(&cur, ":")) { 172 /* 173 * It's a SHELL path -- double, leading and trailing colons 174 * mean the current directory. 175 */ 176 if (!*p) 177 p = "."; 178 (void)snprintf(buf, sizeof(buf), "%s/%s", p, name); 179 180 retry: (void)execve(buf, argv, environ); 181 switch(errno) { 182 case EACCES: 183 eacces = 1; 184 break; 185 case ENOENT: 186 break; 187 case ENOEXEC: { 188 register size_t cnt; 189 register char **ap; 190 191 for (cnt = 0, ap = (char **)argv; *ap; ++ap, ++cnt); 192 if (ap = malloc((cnt + 2) * sizeof(char *))) { 193 bcopy(argv, ap + 2, cnt * sizeof(char *)); 194 ap[0] = "sh"; 195 ap[1] = buf; 196 (void)execve(_PATH_BSHELL, ap, environ); 197 free(ap); 198 } 199 goto done; 200 } 201 case ETXTBSY: 202 if (etxtbsy < 3) 203 (void)sleep(++etxtbsy); 204 goto retry; 205 default: 206 goto done; 207 } 208 } 209 if (eacces) 210 errno = EACCES; 211 else if (!errno) 212 errno = ENOENT; 213 done: free(path); 214 return(-1); 215 } 216