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