11573Srgrimes/*- 21573Srgrimes * Copyright (c) 1991, 1993 31573Srgrimes * The Regents of the University of California. All rights reserved. 41573Srgrimes * 51573Srgrimes * Redistribution and use in source and binary forms, with or without 61573Srgrimes * modification, are permitted provided that the following conditions 71573Srgrimes * are met: 81573Srgrimes * 1. Redistributions of source code must retain the above copyright 91573Srgrimes * notice, this list of conditions and the following disclaimer. 101573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111573Srgrimes * notice, this list of conditions and the following disclaimer in the 121573Srgrimes * documentation and/or other materials provided with the distribution. 131573Srgrimes * 4. Neither the name of the University nor the names of its contributors 141573Srgrimes * may be used to endorse or promote products derived from this software 151573Srgrimes * without specific prior written permission. 161573Srgrimes * 171573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201573Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271573Srgrimes * SUCH DAMAGE. 281573Srgrimes */ 291573Srgrimes 301573Srgrimes#if defined(LIBC_SCCS) && !defined(lint) 311573Srgrimesstatic char sccsid[] = "@(#)exec.c 8.1 (Berkeley) 6/4/93"; 321573Srgrimes#endif /* LIBC_SCCS and not lint */ 3390041Sobrien#include <sys/cdefs.h> 3490041Sobrien__FBSDID("$FreeBSD$"); 351573Srgrimes 3671579Sdeischen#include "namespace.h" 371573Srgrimes#include <sys/param.h> 381573Srgrimes#include <sys/types.h> 3930399Sbde#include <sys/stat.h> 401573Srgrimes#include <errno.h> 411573Srgrimes#include <unistd.h> 421573Srgrimes#include <stdlib.h> 431573Srgrimes#include <string.h> 441573Srgrimes#include <stdio.h> 451573Srgrimes#include <paths.h> 461573Srgrimes 471573Srgrimes#include <stdarg.h> 4871579Sdeischen#include "un-namespace.h" 49179947Sed#include "libc_private.h" 501573Srgrimes 511573Srgrimesextern char **environ; 521573Srgrimes 531573Srgrimesint 541573Srgrimesexecl(const char *name, const char *arg, ...) 551573Srgrimes{ 561573Srgrimes va_list ap; 57200136Sed const char **argv; 5840356Sdes int n; 591573Srgrimes 601573Srgrimes va_start(ap, arg); 6140357Sdes n = 1; 6240356Sdes while (va_arg(ap, char *) != NULL) 6340396Sdes n++; 641573Srgrimes va_end(ap); 6540396Sdes argv = alloca((n + 1) * sizeof(*argv)); 6644974Speter if (argv == NULL) { 6744974Speter errno = ENOMEM; 6840356Sdes return (-1); 6944974Speter } 7040356Sdes va_start(ap, arg); 7140357Sdes n = 1; 72200136Sed argv[0] = arg; 7340356Sdes while ((argv[n] = va_arg(ap, char *)) != NULL) 7440356Sdes n++; 7540356Sdes va_end(ap); 76200136Sed return (_execve(name, __DECONST(char **, argv), environ)); 771573Srgrimes} 781573Srgrimes 791573Srgrimesint 801573Srgrimesexecle(const char *name, const char *arg, ...) 811573Srgrimes{ 821573Srgrimes va_list ap; 83200136Sed const char **argv; 84200136Sed char **envp; 8540396Sdes int n; 861573Srgrimes 871573Srgrimes va_start(ap, arg); 8840396Sdes n = 1; 8940396Sdes while (va_arg(ap, char *) != NULL) 9040396Sdes n++; 911573Srgrimes va_end(ap); 9240396Sdes argv = alloca((n + 1) * sizeof(*argv)); 9344974Speter if (argv == NULL) { 9444974Speter errno = ENOMEM; 9540396Sdes return (-1); 9644974Speter } 9740396Sdes va_start(ap, arg); 9840396Sdes n = 1; 99200136Sed argv[0] = arg; 10040396Sdes while ((argv[n] = va_arg(ap, char *)) != NULL) 10140396Sdes n++; 10240396Sdes envp = va_arg(ap, char **); 10340396Sdes va_end(ap); 104200136Sed return (_execve(name, __DECONST(char **, argv), envp)); 1051573Srgrimes} 1061573Srgrimes 1071573Srgrimesint 1081573Srgrimesexeclp(const char *name, const char *arg, ...) 1091573Srgrimes{ 1101573Srgrimes va_list ap; 111200136Sed const char **argv; 11244974Speter int n; 1131573Srgrimes 1141573Srgrimes va_start(ap, arg); 11544974Speter n = 1; 11644974Speter while (va_arg(ap, char *) != NULL) 11744974Speter n++; 1181573Srgrimes va_end(ap); 11944974Speter argv = alloca((n + 1) * sizeof(*argv)); 12044974Speter if (argv == NULL) { 12144974Speter errno = ENOMEM; 12244974Speter return (-1); 12344974Speter } 12444974Speter va_start(ap, arg); 12544974Speter n = 1; 126200136Sed argv[0] = arg; 12744974Speter while ((argv[n] = va_arg(ap, char *)) != NULL) 12844974Speter n++; 12944974Speter va_end(ap); 130200136Sed return (execvp(name, __DECONST(char **, argv))); 1311573Srgrimes} 1321573Srgrimes 1331573Srgrimesint 1341573Srgrimesexecv(name, argv) 1351573Srgrimes const char *name; 1361573Srgrimes char * const *argv; 1371573Srgrimes{ 13871579Sdeischen (void)_execve(name, argv, environ); 1391573Srgrimes return (-1); 1401573Srgrimes} 1411573Srgrimes 1421573Srgrimesint 143117111Sbdeexecvp(const char *name, char * const *argv) 144117030Sgordon{ 145179947Sed return (_execvpe(name, argv, environ)); 146117030Sgordon} 147117030Sgordon 148179838Sdavidxustatic int 149200136SedexecvPe(const char *name, const char *path, char * const *argv, 150200136Sed char * const *envp) 1511573Srgrimes{ 152200136Sed const char **memp; 153200136Sed size_t cnt, lp, ln; 15430399Sbde int eacces, save_errno; 155200136Sed char *cur, buf[MAXPATHLEN]; 156200136Sed const char *p, *bp; 15730399Sbde struct stat sb; 1581573Srgrimes 15930399Sbde eacces = 0; 16019850Sbde 1611573Srgrimes /* If it's an absolute or relative path name, it's easy. */ 162229403Sed if (strchr(name, '/')) { 163200136Sed bp = name; 164117030Sgordon cur = NULL; 1651573Srgrimes goto retry; 1661573Srgrimes } 1671573Srgrimes bp = buf; 1681573Srgrimes 16919852Sbde /* If it's an empty path name, fail in the usual POSIX way. */ 17019852Sbde if (*name == '\0') { 17119852Sbde errno = ENOENT; 17219852Sbde return (-1); 17319852Sbde } 17419852Sbde 17544974Speter cur = alloca(strlen(path) + 1); 17644974Speter if (cur == NULL) { 17744974Speter errno = ENOMEM; 17844974Speter return (-1); 17944974Speter } 18044974Speter strcpy(cur, path); 181117111Sbde while ((p = strsep(&cur, ":")) != NULL) { 1821573Srgrimes /* 1831573Srgrimes * It's a SHELL path -- double, leading and trailing colons 1841573Srgrimes * mean the current directory. 1851573Srgrimes */ 186117111Sbde if (*p == '\0') { 1871573Srgrimes p = "."; 1881573Srgrimes lp = 1; 1891573Srgrimes } else 1901573Srgrimes lp = strlen(p); 1911573Srgrimes ln = strlen(name); 1921573Srgrimes 1931573Srgrimes /* 1941573Srgrimes * If the path is too long complain. This is a possible 1951573Srgrimes * security issue; given a way to make the path too long 1961573Srgrimes * the user may execute the wrong program. 1971573Srgrimes */ 1981573Srgrimes if (lp + ln + 2 > sizeof(buf)) { 199117030Sgordon (void)_write(STDERR_FILENO, "execvP: ", 8); 20056698Sjasone (void)_write(STDERR_FILENO, p, lp); 20156698Sjasone (void)_write(STDERR_FILENO, ": path too long\n", 20255837Sjasone 16); 2031573Srgrimes continue; 2041573Srgrimes } 2051573Srgrimes bcopy(p, buf, lp); 2061573Srgrimes buf[lp] = '/'; 2071573Srgrimes bcopy(name, buf + lp + 1, ln); 2081573Srgrimes buf[lp + ln + 1] = '\0'; 2091573Srgrimes 210199862Sedretry: (void)_execve(bp, argv, envp); 211117111Sbde switch (errno) { 21230399Sbde case E2BIG: 21330399Sbde goto done; 21430399Sbde case ELOOP: 21530399Sbde case ENAMETOOLONG: 2161573Srgrimes case ENOENT: 2171573Srgrimes break; 2181573Srgrimes case ENOEXEC: 2195070Sbde for (cnt = 0; argv[cnt]; ++cnt) 2205070Sbde ; 22144984Speter memp = alloca((cnt + 2) * sizeof(char *)); 22244974Speter if (memp == NULL) { 22344974Speter /* errno = ENOMEM; XXX override ENOEXEC? */ 2245070Sbde goto done; 22544974Speter } 2261573Srgrimes memp[0] = "sh"; 2271573Srgrimes memp[1] = bp; 2281573Srgrimes bcopy(argv + 1, memp + 2, cnt * sizeof(char *)); 229200136Sed (void)_execve(_PATH_BSHELL, 230200136Sed __DECONST(char **, memp), envp); 2311573Srgrimes goto done; 23230399Sbde case ENOMEM: 23330399Sbde goto done; 23430399Sbde case ENOTDIR: 23530399Sbde break; 2361573Srgrimes case ETXTBSY: 23730399Sbde /* 23830399Sbde * We used to retry here, but sh(1) doesn't. 23930399Sbde */ 24030399Sbde goto done; 2411573Srgrimes default: 24230399Sbde /* 24330399Sbde * EACCES may be for an inaccessible directory or 24430399Sbde * a non-executable file. Call stat() to decide 24530399Sbde * which. This also handles ambiguities for EFAULT 24630399Sbde * and EIO, and undocumented errors like ESTALE. 24730399Sbde * We hope that the race for a stat() is unimportant. 24830399Sbde */ 24930399Sbde save_errno = errno; 25031309Sbde if (stat(bp, &sb) != 0) 25130399Sbde break; 25230399Sbde if (save_errno == EACCES) { 25330399Sbde eacces = 1; 25430399Sbde continue; 25530399Sbde } 25630399Sbde errno = save_errno; 2571573Srgrimes goto done; 2581573Srgrimes } 2591573Srgrimes } 2601573Srgrimes if (eacces) 2611573Srgrimes errno = EACCES; 26230399Sbde else 2631573Srgrimes errno = ENOENT; 26444974Speterdone: 2651573Srgrimes return (-1); 2661573Srgrimes} 267179838Sdavidxu 268179838Sdavidxuint 269179838SdavidxuexecvP(const char *name, const char *path, char * const argv[]) 270179838Sdavidxu{ 271179838Sdavidxu return execvPe(name, path, argv, environ); 272179838Sdavidxu} 273179838Sdavidxu 274179838Sdavidxuint 275179947Sed_execvpe(const char *name, char * const argv[], char * const envp[]) 276179838Sdavidxu{ 277179838Sdavidxu const char *path; 278179838Sdavidxu 279179838Sdavidxu /* Get the path we're searching. */ 280179838Sdavidxu if ((path = getenv("PATH")) == NULL) 281179838Sdavidxu path = _PATH_DEFPATH; 282179838Sdavidxu 283179838Sdavidxu return (execvPe(name, path, argv, envp)); 284179838Sdavidxu} 285