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 * $FreeBSD$ 34 */ 35 36 #if defined(LIBC_SCCS) && !defined(lint) 37 #if 0 38 static char sccsid[] = "@(#)exec.c 8.1 (Berkeley) 6/4/93"; 39 #endif 40 static const char rcsid[] = 41 "$FreeBSD$"; 42 #endif /* LIBC_SCCS and not lint */ 43 44 #include <sys/param.h> 45 #include <sys/types.h> 46 #include <sys/stat.h> 47 #include <errno.h> 48 #include <unistd.h> 49 #include <stdlib.h> 50 #include <string.h> 51 #include <stdio.h> 52 #include <paths.h> 53 54 #if __STDC__ 55 #include <stdarg.h> 56 #else 57 #include <varargs.h> 58 #endif 59 60 extern char **environ; 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 char **argv; 74 int n; 75 76 #if __STDC__ 77 va_start(ap, arg); 78 #else 79 va_start(ap); 80 #endif 81 n = 1; 82 while (va_arg(ap, char *) != NULL) 83 n++; 84 va_end(ap); 85 argv = alloca((n + 1) * sizeof(*argv)); 86 if (argv == NULL) { 87 errno = ENOMEM; 88 return (-1); 89 } 90 #if __STDC__ 91 va_start(ap, arg); 92 #else 93 va_start(ap); 94 #endif 95 n = 1; 96 argv[0] = (char *)arg; 97 while ((argv[n] = va_arg(ap, char *)) != NULL) 98 n++; 99 va_end(ap); 100 return (execve(name, argv, environ)); 101 } 102 103 int 104 #if __STDC__ 105 execle(const char *name, const char *arg, ...) 106 #else 107 execle(name, arg, va_alist) 108 const char *name; 109 const char *arg; 110 va_dcl 111 #endif 112 { 113 va_list ap; 114 char **argv, **envp; 115 int n; 116 117 #if __STDC__ 118 va_start(ap, arg); 119 #else 120 va_start(ap); 121 #endif 122 n = 1; 123 while (va_arg(ap, char *) != NULL) 124 n++; 125 va_end(ap); 126 argv = alloca((n + 1) * sizeof(*argv)); 127 if (argv == NULL) { 128 errno = ENOMEM; 129 return (-1); 130 } 131 #if __STDC__ 132 va_start(ap, arg); 133 #else 134 va_start(ap); 135 #endif 136 n = 1; 137 argv[0] = (char *)arg; 138 while ((argv[n] = va_arg(ap, char *)) != NULL) 139 n++; 140 envp = va_arg(ap, char **); 141 va_end(ap); 142 return (execve(name, argv, envp)); 143 } 144 145 int 146 #if __STDC__ 147 execlp(const char *name, const char *arg, ...) 148 #else 149 execlp(name, arg, va_alist) 150 const char *name; 151 const char *arg; 152 va_dcl 153 #endif 154 { 155 va_list ap; 156 int sverrno; 157 char **argv; 158 int n; 159 160 #if __STDC__ 161 va_start(ap, arg); 162 #else 163 va_start(ap); 164 #endif 165 n = 1; 166 while (va_arg(ap, char *) != NULL) 167 n++; 168 va_end(ap); 169 argv = alloca((n + 1) * sizeof(*argv)); 170 if (argv == NULL) { 171 errno = ENOMEM; 172 return (-1); 173 } 174 #if __STDC__ 175 va_start(ap, arg); 176 #else 177 va_start(ap); 178 #endif 179 n = 1; 180 argv[0] = (char *)arg; 181 while ((argv[n] = va_arg(ap, char *)) != NULL) 182 n++; 183 va_end(ap); 184 return (execvp(name, argv)); 185 } 186 187 int 188 execv(name, argv) 189 const char *name; 190 char * const *argv; 191 { 192 (void)execve(name, argv, environ); 193 return (-1); 194 } 195 196 int 197 execvp(name, argv) 198 const char *name; 199 char * const *argv; 200 { 201 char **memp; 202 register int cnt, lp, ln; 203 register char *p; 204 int eacces, save_errno; 205 char *bp, *cur, *path, buf[MAXPATHLEN]; 206 struct stat sb; 207 208 eacces = 0; 209 210 /* If it's an absolute or relative path name, it's easy. */ 211 if (index(name, '/')) { 212 bp = (char *)name; 213 cur = path = NULL; 214 goto retry; 215 } 216 bp = buf; 217 218 /* If it's an empty path name, fail in the usual POSIX way. */ 219 if (*name == '\0') { 220 errno = ENOENT; 221 return (-1); 222 } 223 224 /* Get the path we're searching. */ 225 if (!(path = getenv("PATH"))) 226 path = _PATH_DEFPATH; 227 cur = alloca(strlen(path) + 1); 228 if (cur == NULL) { 229 errno = ENOMEM; 230 return (-1); 231 } 232 strcpy(cur, path); 233 path = cur; 234 while ( (p = strsep(&cur, ":")) ) { 235 /* 236 * It's a SHELL path -- double, leading and trailing colons 237 * mean the current directory. 238 */ 239 if (!*p) { 240 p = "."; 241 lp = 1; 242 } else 243 lp = strlen(p); 244 ln = strlen(name); 245 246 /* 247 * If the path is too long complain. This is a possible 248 * security issue; given a way to make the path too long 249 * the user may execute the wrong program. 250 */ 251 if (lp + ln + 2 > sizeof(buf)) { 252 (void)_write(STDERR_FILENO, "execvp: ", 8); 253 (void)_write(STDERR_FILENO, p, lp); 254 (void)_write(STDERR_FILENO, ": path too long\n", 255 16); 256 continue; 257 } 258 bcopy(p, buf, lp); 259 buf[lp] = '/'; 260 bcopy(name, buf + lp + 1, ln); 261 buf[lp + ln + 1] = '\0'; 262 263 retry: (void)execve(bp, argv, environ); 264 switch(errno) { 265 case E2BIG: 266 goto done; 267 case ELOOP: 268 case ENAMETOOLONG: 269 case ENOENT: 270 break; 271 case ENOEXEC: 272 for (cnt = 0; argv[cnt]; ++cnt) 273 ; 274 memp = alloca((cnt + 2) * sizeof(char *)); 275 if (memp == NULL) { 276 /* errno = ENOMEM; XXX override ENOEXEC? */ 277 goto done; 278 } 279 memp[0] = "sh"; 280 memp[1] = bp; 281 bcopy(argv + 1, memp + 2, cnt * sizeof(char *)); 282 (void)execve(_PATH_BSHELL, memp, environ); 283 goto done; 284 case ENOMEM: 285 goto done; 286 case ENOTDIR: 287 break; 288 case ETXTBSY: 289 /* 290 * We used to retry here, but sh(1) doesn't. 291 */ 292 goto done; 293 default: 294 /* 295 * EACCES may be for an inaccessible directory or 296 * a non-executable file. Call stat() to decide 297 * which. This also handles ambiguities for EFAULT 298 * and EIO, and undocumented errors like ESTALE. 299 * We hope that the race for a stat() is unimportant. 300 */ 301 save_errno = errno; 302 if (stat(bp, &sb) != 0) 303 break; 304 if (save_errno == EACCES) { 305 eacces = 1; 306 continue; 307 } 308 errno = save_errno; 309 goto done; 310 } 311 } 312 if (eacces) 313 errno = EACCES; 314 else 315 errno = ENOENT; 316 done: 317 return (-1); 318 } 319