#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); }