1 /*- 2 * Copyright (c) 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #if defined(LIBC_SCCS) && !defined(lint) 35 #if 0 36 static char sccsid[] = "@(#)exec.c 8.1 (Berkeley) 6/4/93"; 37 #endif 38 static const char rcsid[] = 39 "$Id: exec.c,v 1.6 1997/10/14 07:23:16 bde Exp $"; 40 #endif /* LIBC_SCCS and not lint */ 41 42 #include <sys/param.h> 43 #include <sys/types.h> 44 #include <sys/stat.h> 45 #include <errno.h> 46 #include <unistd.h> 47 #include <stdlib.h> 48 #include <string.h> 49 #include <stdio.h> 50 #include <paths.h> 51 52 #if __STDC__ 53 #include <stdarg.h> 54 #else 55 #include <varargs.h> 56 #endif 57 58 extern char **environ; 59 60 static char ** 61 buildargv(ap, arg, envpp) 62 va_list ap; 63 const char *arg; 64 char ***envpp; 65 { 66 register char **argv, **nargv; 67 register int memsize, off; 68 69 argv = NULL; 70 for (off = memsize = 0;; ++off) { 71 if (off >= memsize) { 72 memsize += 50; /* Starts out at 0. */ 73 memsize *= 2; /* Ramp up fast. */ 74 nargv = realloc(argv, memsize * sizeof(char *)); 75 if (nargv == NULL) { 76 free(argv); 77 return (NULL); 78 } 79 argv = nargv; 80 if (off == 0) { 81 argv[0] = (char *)arg; 82 off = 1; 83 } 84 } 85 if (!(argv[off] = va_arg(ap, char *))) 86 break; 87 } 88 /* Get environment pointer if user supposed to provide one. */ 89 if (envpp) 90 *envpp = va_arg(ap, char **); 91 return (argv); 92 } 93 94 int 95 #if __STDC__ 96 execl(const char *name, const char *arg, ...) 97 #else 98 execl(name, arg, va_alist) 99 const char *name; 100 const char *arg; 101 va_dcl 102 #endif 103 { 104 va_list ap; 105 int sverrno; 106 char **argv; 107 108 #if __STDC__ 109 va_start(ap, arg); 110 #else 111 va_start(ap); 112 #endif 113 if ( (argv = buildargv(ap, arg, NULL)) ) 114 (void)execve(name, argv, environ); 115 va_end(ap); 116 sverrno = errno; 117 free(argv); 118 errno = sverrno; 119 return (-1); 120 } 121 122 int 123 #if __STDC__ 124 execle(const char *name, const char *arg, ...) 125 #else 126 execle(name, arg, va_alist) 127 const char *name; 128 const char *arg; 129 va_dcl 130 #endif 131 { 132 va_list ap; 133 int sverrno; 134 char **argv, **envp; 135 136 #if __STDC__ 137 va_start(ap, arg); 138 #else 139 va_start(ap); 140 #endif 141 if ( (argv = buildargv(ap, arg, &envp)) ) 142 (void)execve(name, argv, envp); 143 va_end(ap); 144 sverrno = errno; 145 free(argv); 146 errno = sverrno; 147 return (-1); 148 } 149 150 int 151 #if __STDC__ 152 execlp(const char *name, const char *arg, ...) 153 #else 154 execlp(name, arg, va_alist) 155 const char *name; 156 const char *arg; 157 va_dcl 158 #endif 159 { 160 va_list ap; 161 int sverrno; 162 char **argv; 163 164 #if __STDC__ 165 va_start(ap, arg); 166 #else 167 va_start(ap); 168 #endif 169 if ( (argv = buildargv(ap, arg, NULL)) ) 170 (void)execvp(name, argv); 171 va_end(ap); 172 sverrno = errno; 173 free(argv); 174 errno = sverrno; 175 return (-1); 176 } 177 178 int 179 execv(name, argv) 180 const char *name; 181 char * const *argv; 182 { 183 (void)execve(name, argv, environ); 184 return (-1); 185 } 186 187 int 188 execvp(name, argv) 189 const char *name; 190 char * const *argv; 191 { 192 char **memp; 193 register int cnt, lp, ln; 194 register char *p; 195 int eacces, save_errno; 196 char *bp, *cur, *path, buf[MAXPATHLEN]; 197 struct stat sb; 198 199 eacces = 0; 200 201 /* If it's an absolute or relative path name, it's easy. */ 202 if (index(name, '/')) { 203 bp = (char *)name; 204 cur = path = NULL; 205 goto retry; 206 } 207 bp = buf; 208 209 /* If it's an empty path name, fail in the usual POSIX way. */ 210 if (*name == '\0') { 211 errno = ENOENT; 212 return (-1); 213 } 214 215 /* Get the path we're searching. */ 216 if (!(path = getenv("PATH"))) 217 path = _PATH_DEFPATH; 218 cur = path = strdup(path); 219 220 while ( (p = strsep(&cur, ":")) ) { 221 /* 222 * It's a SHELL path -- double, leading and trailing colons 223 * mean the current directory. 224 */ 225 if (!*p) { 226 p = "."; 227 lp = 1; 228 } else 229 lp = strlen(p); 230 ln = strlen(name); 231 232 /* 233 * If the path is too long complain. This is a possible 234 * security issue; given a way to make the path too long 235 * the user may execute the wrong program. 236 */ 237 if (lp + ln + 2 > sizeof(buf)) { 238 (void)write(STDERR_FILENO, "execvp: ", 8); 239 (void)write(STDERR_FILENO, p, lp); 240 (void)write(STDERR_FILENO, ": path too long\n", 16); 241 continue; 242 } 243 bcopy(p, buf, lp); 244 buf[lp] = '/'; 245 bcopy(name, buf + lp + 1, ln); 246 buf[lp + ln + 1] = '\0'; 247 248 retry: (void)execve(bp, argv, environ); 249 switch(errno) { 250 case E2BIG: 251 goto done; 252 case ELOOP: 253 case ENAMETOOLONG: 254 case ENOENT: 255 break; 256 case ENOEXEC: 257 for (cnt = 0; argv[cnt]; ++cnt) 258 ; 259 memp = malloc((cnt + 2) * sizeof(char *)); 260 if (memp == NULL) 261 goto done; 262 memp[0] = "sh"; 263 memp[1] = bp; 264 bcopy(argv + 1, memp + 2, cnt * sizeof(char *)); 265 (void)execve(_PATH_BSHELL, memp, environ); 266 free(memp); 267 goto done; 268 case ENOMEM: 269 goto done; 270 case ENOTDIR: 271 break; 272 case ETXTBSY: 273 /* 274 * We used to retry here, but sh(1) doesn't. 275 */ 276 goto done; 277 default: 278 /* 279 * EACCES may be for an inaccessible directory or 280 * a non-executable file. Call stat() to decide 281 * which. This also handles ambiguities for EFAULT 282 * and EIO, and undocumented errors like ESTALE. 283 * We hope that the race for a stat() is unimportant. 284 */ 285 save_errno = errno; 286 if (stat(bp, &sb) != 0) 287 break; 288 if (save_errno == EACCES) { 289 eacces = 1; 290 continue; 291 } 292 errno = save_errno; 293 goto done; 294 } 295 } 296 if (eacces) 297 errno = EACCES; 298 else 299 errno = ENOENT; 300 done: if (path) 301 free(path); 302 return (-1); 303 } 304