Minix2.0/src/lib/posix/_exec.c
#include <lib.h>
#define execl _execl
#define execle _execle
#define execv _execv
#define execve _execve
#define sbrk _sbrk
#include <minix/minlib.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
extern char **environ;
#define PTRSIZE (sizeof(char *))
#ifdef _ANSI
PUBLIC int execl(const char *name, const char *arg, ...)
#else
PUBLIC int execl(name)
char *name;
#endif
{
va_list argp;
int result;
va_start(argp, name);
/* The following cast of argp is not portable. Doing it right by copying
* the args to a true array will cost as much as ARG_MAX bytes of space.
*/
result = execve(name, (char **) argp, environ);
va_end(argp);
return(result);
}
#ifdef _ANSI
PUBLIC int execle(const char *name, const char *arg, ...)
#else
PUBLIC int execle(name)
char *name;
#endif
{
va_list argp;
char **p;
int result;
va_start(argp, name);
/* The following cast of argp is not portable, as for execl(). */
p = (char **) argp;
while (*p++ != NIL_PTR)
; /* null statement */
result = execve(name, (char **) argp, (char **) *p);
va_end(argp);
return(result);
}
PUBLIC int execv(name, argv)
_CONST char *name;
char * _CONST argv[];
{
return(execve(name, argv, environ));
}
PUBLIC int execve(path, argv, envp)
_CONST char *path; /* pointer to name of file to be executed */
char * _CONST argv[]; /* pointer to argument array */
char * _CONST envp[]; /* pointer to environment */
{
int i, j;
/* Count the argument pointers and environment pointers. */
i = 0;
if (argv != NULL)
{
while (argv[i] != NULL) i++;
}
j = 0;
if (envp != NULL)
{
while (envp[j] != NULL) j++;
}
return(__execve(path, argv, envp, i, j));
}
PUBLIC int __execve(path, argv, envp, nargs, nenvps)
_CONST char *path; /* pointer to name of file to be executed */
char * _CONST argv[]; /* pointer to argument array */
char * _CONST envp[]; /* pointer to environment */
int nargs; /* number of args */
int nenvps; /* number of environment strings */
{
/* This is split off from execve to be called from execvp, so execvp does not
* have to allocate up to ARG_MAX bytes just to prepend "sh" to the arg array.
*/
char *hp, **ap, *p;
int i, stackbytes, npointers, overflow, temp;
char *stack;
message m;
/* Decide how big a stack is needed. Be paranoid about overflow. */
overflow = FALSE;
npointers = 1 + nargs + 1 + nenvps + 1; /* 1's for argc and NULLs */
stackbytes = nargs + nenvps; /* 1 byte for each null in strings */
if (nargs < 0 || nenvps < 0 || stackbytes < nargs || npointers < stackbytes)
overflow = TRUE;
for (i = PTRSIZE; i != 0; i--) {
temp = stackbytes + npointers;
if (temp < stackbytes) overflow = TRUE;
stackbytes = temp;
}
ap = (char **) argv;
for (i = 0; i < nargs; i++) {
temp = stackbytes + strlen(*ap++);
if (temp < stackbytes) overflow = TRUE;
stackbytes = temp;
}
ap = (char **) envp;
for (i = 0; i < nenvps; i++) {
temp = stackbytes + strlen(*ap++);
if (temp < stackbytes) overflow = TRUE;
stackbytes = temp;
}
temp = stackbytes + PTRSIZE - 1;
if (temp < stackbytes) overflow = TRUE;
stackbytes = (temp / PTRSIZE) * PTRSIZE;
/* Check for overflow before committing sbrk. */
if (overflow) {
errno = E2BIG;
return(-1);
}
/* Allocate the stack. */
stack = sbrk(stackbytes);
if (stack == (char *) -1) {
errno = E2BIG;
return(-1);
}
/* Prepare the stack vector and argc. */
ap = (char **) stack;
hp = &stack[npointers * PTRSIZE];
*ap++ = (char *) nargs;
/* Prepare the argument pointers and strings. */
for (i = 0; i < nargs; i++) {
*ap++ = (char *) (hp - stack);
p = *argv++;
while ( (*hp++ = *p++) != 0)
;
}
*ap++ = (char *) NULL;
/* Prepare the environment pointers and strings. */
for (i = 0; i < nenvps; i++) {
*ap++ = (char *) (hp - stack);
p = *envp++;
while ( (*hp++ = *p++) != 0)
;
}
*ap++ = (char *) NULL;
/* Do the real work. */
m.m1_i1 = strlen(path) + 1;
m.m1_i2 = stackbytes;
m.m1_p1 = (char *) path;
m.m1_p2 = stack;
(void) _syscall(MM, EXEC, &m);
/* The exec failed. */
sbrk(-stackbytes);
return(m.m_type);
}