#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)exec.c 8.1 (Berkeley) 6/4/93";
#endif
#include <sys/cdefs.h>
__FBSDID("$FreeBSD: src/lib/libc/gen/exec.c,v 1.27 2009/12/05 18:55:16 ed Exp $");
#include "namespace.h"
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <paths.h>
#include <stdarg.h>
#include "un-namespace.h"
#include "libc_private.h"
#include <crt_externs.h>
#define environ (*_NSGetEnviron())
int
_execvpe(const char *name, char * const argv[], char * const envp[]);
int
execl(const char *name, const char *arg, ...)
{
va_list ap;
const char **argv;
int n;
va_start(ap, arg);
n = 1;
while (va_arg(ap, char *) != NULL)
n++;
va_end(ap);
argv = alloca((n + 1) * sizeof(*argv));
if (argv == NULL) {
errno = ENOMEM;
return (-1);
}
va_start(ap, arg);
n = 1;
argv[0] = arg;
while ((argv[n] = va_arg(ap, char *)) != NULL)
n++;
va_end(ap);
return (_execve(name, __DECONST(char **, argv), environ));
}
int
execle(const char *name, const char *arg, ...)
{
va_list ap;
const char **argv;
char **envp;
int n;
va_start(ap, arg);
n = 1;
while (va_arg(ap, char *) != NULL)
n++;
va_end(ap);
argv = alloca((n + 1) * sizeof(*argv));
if (argv == NULL) {
errno = ENOMEM;
return (-1);
}
va_start(ap, arg);
n = 1;
argv[0] = arg;
while ((argv[n] = va_arg(ap, char *)) != NULL)
n++;
envp = va_arg(ap, char **);
va_end(ap);
return (_execve(name, __DECONST(char **, argv), envp));
}
int
execlp(const char *name, const char *arg, ...)
{
va_list ap;
const char **argv;
int n;
va_start(ap, arg);
n = 1;
while (va_arg(ap, char *) != NULL)
n++;
va_end(ap);
argv = alloca((n + 1) * sizeof(*argv));
if (argv == NULL) {
errno = ENOMEM;
return (-1);
}
va_start(ap, arg);
n = 1;
argv[0] = arg;
while ((argv[n] = va_arg(ap, char *)) != NULL)
n++;
va_end(ap);
return (execvp(name, __DECONST(char **, argv)));
}
int
execv(name, argv)
const char *name;
char * const *argv;
{
(void)_execve(name, argv, environ);
return (-1);
}
int
execvp(const char *name, char * const *argv)
{
return (_execvpe(name, argv, environ));
}
static int
execvPe(const char *name, const char *path, char * const *argv,
char * const *envp)
{
const char **memp;
size_t cnt, lp, ln;
int eacces, save_errno;
char *cur, buf[MAXPATHLEN];
const char *p, *bp;
struct stat sb;
eacces = 0;
if (index(name, '/')) {
bp = name;
cur = NULL;
goto retry;
}
bp = buf;
if (*name == '\0') {
errno = ENOENT;
return (-1);
}
cur = alloca(strlen(path) + 1);
if (cur == NULL) {
errno = ENOMEM;
return (-1);
}
strcpy(cur, path);
while ((p = strsep(&cur, ":")) != NULL) {
if (*p == '\0') {
p = ".";
lp = 1;
} else
lp = strlen(p);
ln = strlen(name);
if (lp + ln + 2 > sizeof(buf)) {
(void)_write(STDERR_FILENO, "execvP: ", 8);
(void)_write(STDERR_FILENO, p, lp);
(void)_write(STDERR_FILENO, ": path too long\n",
16);
continue;
}
bcopy(p, buf, lp);
buf[lp] = '/';
bcopy(name, buf + lp + 1, ln);
buf[lp + ln + 1] = '\0';
retry: (void)_execve(bp, argv, envp);
switch (errno) {
case E2BIG:
goto done;
case ELOOP:
case ENAMETOOLONG:
case ENOENT:
break;
case ENOEXEC:
for (cnt = 0; argv[cnt]; ++cnt)
;
memp = alloca((cnt + 2) * sizeof(char *));
if (memp == NULL) {
goto done;
}
memp[0] = "sh";
memp[1] = bp;
bcopy(argv + 1, memp + 2, cnt * sizeof(char *));
(void)_execve(_PATH_BSHELL,
__DECONST(char **, memp), envp);
goto done;
case ENOMEM:
goto done;
case ENOTDIR:
break;
case ETXTBSY:
goto done;
default:
save_errno = errno;
if (stat(bp, &sb) != 0)
break;
if (save_errno == EACCES) {
eacces = 1;
continue;
}
errno = save_errno;
goto done;
}
}
if (eacces)
errno = EACCES;
else if (cur)
errno = ENOENT;
done:
return (-1);
}
int
execvP(const char *name, const char *path, char * const argv[])
{
return execvPe(name, path, argv, environ);
}
__private_extern__ int
_execvpe(const char *name, char * const argv[], char * const envp[])
{
const char *path;
if ((path = getenv("PATH")) == NULL)
path = _PATH_DEFPATH;
return (execvPe(name, path, argv, envp));
}