1) Added proc file system from Paul Kranenburg with changes from
[unix-history] / sys / kern / kern_execve.c
index 22d2ff0..bd08ab7 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 1989, 1990, 1991, 1992 William F. Jolitz, TeleMuse
+ * Copyright (c) 1993, David Greenman
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  *    documentation and/or other materials provided with the distribution.
  * 3. All advertising materials mentioning features or use of this software
  *    must display the following acknowledgement:
  *    documentation and/or other materials provided with the distribution.
  * 3. All advertising materials mentioning features or use of this software
  *    must display the following acknowledgement:
- *     This software is a component of "386BSD" developed by 
- *     William F. Jolitz, TeleMuse.
- * 4. Neither the name of the developer nor the name "386BSD"
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
+ *     This product includes software developed by David Greenman
+ * 4. The name of the developer may be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
  *
  *
- * THIS SOFTWARE IS A COMPONENT OF 386BSD DEVELOPED BY WILLIAM F. JOLITZ 
- * AND IS INTENDED FOR RESEARCH AND EDUCATIONAL PURPOSES ONLY. THIS 
- * SOFTWARE SHOULD NOT BE CONSIDERED TO BE A COMMERCIAL PRODUCT. 
- * THE DEVELOPER URGES THAT USERS WHO REQUIRE A COMMERCIAL PRODUCT 
- * NOT MAKE USE OF THIS WORK.
- *
- * FOR USERS WHO WISH TO UNDERSTAND THE 386BSD SYSTEM DEVELOPED
- * BY WILLIAM F. JOLITZ, WE RECOMMEND THE USER STUDY WRITTEN 
- * REFERENCES SUCH AS THE  "PORTING UNIX TO THE 386" SERIES 
- * (BEGINNING JANUARY 1991 "DR. DOBBS JOURNAL", USA AND BEGINNING 
- * JUNE 1991 "UNIX MAGAZIN", GERMANY) BY WILLIAM F. JOLITZ AND 
- * LYNNE GREER JOLITZ, AS WELL AS OTHER BOOKS ON UNIX AND THE 
- * ON-LINE 386BSD USER MANUAL BEFORE USE. A BOOK DISCUSSING THE INTERNALS 
- * OF 386BSD ENTITLED "386BSD FROM THE INSIDE OUT" WILL BE AVAILABLE LATE 1992.
- *
- * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE DEVELOPER BE LIABLE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * This procedure implements a minimal program execution facility for
- * 386BSD. It interfaces to the BSD kernel as the execve system call.
- * Significant limitations and lack of compatiblity with POSIX are
- * present with this version, to make its basic operation more clear.
- *
- *     $Id: kern_execve.c,v 1.8 1993/10/25 17:26:01 davidg Exp $
+ *     $Id: kern_execve.c,v 1.4 1993/12/11 06:55:33 davidg Exp davidg $
  */
 
 #include "param.h"
 #include "systm.h"
 #include "signalvar.h"
 #include "resourcevar.h"
  */
 
 #include "param.h"
 #include "systm.h"
 #include "signalvar.h"
 #include "resourcevar.h"
-#include "proc.h"
+#include "imgact.h"
 #include "mount.h"
 #include "mount.h"
-#include "namei.h"
-#include "vnode.h"
 #include "file.h"
 #include "acct.h"
 #include "exec.h"
 #include "file.h"
 #include "acct.h"
 #include "exec.h"
@@ -68,6 +44,7 @@
 #include "wait.h"
 #include "mman.h"
 #include "malloc.h"
 #include "wait.h"
 #include "mman.h"
 #include "malloc.h"
+#include "syslog.h"
 
 #include "vm/vm.h"
 #include "vm/vm_param.h"
 
 #include "vm/vm.h"
 #include "vm/vm_param.h"
 
 #include "machine/reg.h"
 
 
 #include "machine/reg.h"
 
-extern int dostacklimits;
-#define        copyinoutstr    copyinstr
+int exec_extract_strings __P((struct image_params *));
+caddr_t exec_copyout_strings __P((struct image_params *));
+
+int exec_aout_imgact __P((struct image_params *));
+int exec_shell_imgact __P((struct image_params *));
+
+struct execsw {
+       int (*imgact) __P((struct image_params *));
+};
+
+struct execsw execsw[] = {
+       { exec_aout_imgact },
+       { exec_shell_imgact },
+       { NULL },
+       { NULL },
+       { NULL },
+       { NULL },
+       { NULL },
+       { NULL },
+};
 
 /*
  * execve() system call.
  */
 
 
 /*
  * execve() system call.
  */
 
-struct execve_args {
-       char    *fname;
-       char    **argp;
-       char    **envp;
-};
-
-/* ARGSUSED */
 int
 execve(p, uap, retval)
        struct proc *p;
        register struct execve_args *uap;
        int *retval;
 {
 int
 execve(p, uap, retval)
        struct proc *p;
        register struct execve_args *uap;
        int *retval;
 {
-       register struct nameidata *ndp;
-       struct nameidata nd;
-       char **argbuf, **argbufp, *stringbuf, *stringbufp;
-       char **vectp, *ep;
-       int needsenv, limitonargs, stringlen, addr, size, len,
-               rv, amt, argc = 0, tsize, dsize, bsize, cnt, file_offset,
-               virtual_offset;
+       struct nameidata nd, *ndp;
+       char *stringbase, *stringp, *stack_base;
+       int error, resid, len, i;
+#if 0
+       char image_header[256];
+#endif
+       struct image_params image_params, *iparams;
+       struct vnode *vnodep;
        struct vattr attr;
        struct vattr attr;
-       struct vmspace *vs;
-       caddr_t newframe;
-       char shellname[MAXINTERP];                      /* 05 Aug 92*/
-       char *shellargs = 0;
-       union {
-               char    ex_shell[MAXINTERP];    /* #! and interpreter name */
-               struct  exec ex_hdr;
-       } exdata;
-       int indir = 0;
+       char *image_header;
+
+       iparams = &image_params;
+       bzero((caddr_t)iparams, sizeof(struct image_params));
+       image_header = (char *)0;
 
        /*
 
        /*
-        * Step 1. Lookup filename to see if we have something to execute.
+        * Initialize a few constants in the common area
+        */
+       iparams->proc = p;
+       iparams->uap = uap;
+       iparams->attr = &attr;
+
+       /*
+        * Allocate temporary demand zeroed space for argument and
+        *      environment strings
+        */
+       error = vm_allocate(kernel_map, &iparams->stringbase, ARG_MAX, TRUE);
+       if (error) {
+               log(LOG_WARNING, "execve: failed to allocate string space\n");
+               return (error);
+       }
+
+       if (!iparams->stringbase) {
+               error = ENOMEM;
+               goto exec_fail;
+       }
+       iparams->stringp = iparams->stringbase;
+       iparams->stringspace = ARG_MAX;
+
+       /*
+        * Translate the file name. namei() returns a vnode pointer
+        *      in ni_vp amoung other things.
         */
        ndp = &nd;
         */
        ndp = &nd;
+       ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW | SAVENAME;
        ndp->ni_segflg = UIO_USERSPACE;
        ndp->ni_dirp = uap->fname;
 
        ndp->ni_segflg = UIO_USERSPACE;
        ndp->ni_dirp = uap->fname;
 
-again:                                                 /* 05 Aug 92*/
-       ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW | SAVENAME;
-
-       /* is it there? */
-       if (rv = namei(ndp, p))
-               return (rv);
+interpret:
 
 
-       if (ndp->ni_vp->v_writecount) { /* don't exec if file is busy */
-               rv = EBUSY;
-               goto exec_fail;
+       error = namei(ndp, p);
+       if (error) {
+               vm_deallocate(kernel_map, iparams->stringbase, ARG_MAX);
+               goto exec_fail; 
        }
        }
-       /* does it have any attributes? */
-       rv = VOP_GETATTR(ndp->ni_vp, &attr, p->p_ucred, p);
-       if (rv)
-               goto exec_fail;
 
 
-       if (ndp->ni_vp->v_mount->mnt_flag & MNT_NOEXEC) { /* no exec on fs ?*/
-               rv = EACCES;
-               goto exec_fail;
-       }
+       iparams->vnodep = vnodep = ndp->ni_vp;
 
 
-       /* is it executable, and a regular file? */
-       if ((ndp->ni_vp->v_mount->mnt_flag & MNT_NOEXEC) ||     /* 29 Jul 92*/
-               (VOP_ACCESS(ndp->ni_vp, VEXEC, p->p_ucred, p)) ||
-               ((attr.va_mode & 0111) == 0) ||
-               (attr.va_type != VREG)) {
-               rv = EACCES;
-               goto exec_fail;
+       if (vnodep == NULL) {
+               error = ENOEXEC;
+               goto exec_fail_dealloc;
        }
 
        /*
        }
 
        /*
-        * Step 2. Does the file contain a format we can
-        * understand and execute
-        *
-        * XXX 05 Aug 92
-        * Read in first few bytes of file for segment sizes, magic number:
-        *      ZMAGIC = demand paged RO text
-        * Also an ASCII line beginning with #! is
-        * the file name of a ``shell'' and arguments may be prepended
-        * to the argument list if given here.
+        * Check file permissions (also 'opens' file)
         */
         */
-       exdata.ex_shell[0] = '\0';      /* for zero length files */
-
-       rv = vn_rdwr(UIO_READ, ndp->ni_vp, (caddr_t)&exdata, sizeof(exdata),
-               0, UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &amt, p);
+       error = exec_check_permissions(iparams);
+       if (error)
+               goto exec_fail_dealloc;
 
 
-       /* big enough to hold a header? */
-       if (rv)
-               goto exec_fail;
-
-        if (exdata.ex_hdr.a_text != 0 && (ndp->ni_vp->v_flag & VTEXT) == 0 &&
-           ndp->ni_vp->v_writecount != 0) {
-               rv = ETXTBSY;
-               goto exec_fail;
+#if 0
+       /*
+        * Read the image header from the file.
+        */
+       error = vn_rdwr(UIO_READ,
+                       vnodep,
+                       image_header,
+                       sizeof(image_header),
+                       0,
+                       UIO_SYSSPACE, IO_NODELOCKED,
+                       p->p_ucred,
+                       &resid,
+                       p);
+       if (error)
+               goto exec_fail_dealloc;
+
+       /* Clear out junk in image_header if a partial read (small file) */
+       if (resid)
+               bzero(image_header + (sizeof(image_header) - resid), resid);
+#endif
+       /*
+        * Map the image header (first page) of the file into
+        *      kernel address space
+        */
+       error = vm_mmap(kernel_map,     /* map */
+                   &image_header,      /* address */
+                   NBPG,               /* size */
+                   VM_PROT_READ,       /* protection */
+                   VM_PROT_READ,       /* maximum protection */
+                   MAP_FILE,           /* flags */
+                   vnodep,             /* vnode */
+                   0);                 /* offset */
+       if (error) {
+               printf("mmap filed: %d\n",error);
+               goto exec_fail_dealloc;
        }
        }
-               
-#define SHELLMAGIC     0x2123 /* #! */
-
-       switch (exdata.ex_hdr.a_magic) {
-       case ZMAGIC:
-               virtual_offset = 0;
-               if (exdata.ex_hdr.a_text) {
-                       file_offset = NBPG;
-               } else {
-                       /* Bill's "screwball mode" */
-                       file_offset = 0;
-               }
-               break;
-       case QMAGIC:
-               virtual_offset = NBPG;
-               file_offset = 0;
-               break;
-       default:
-               if ((exdata.ex_hdr.a_magic & 0xffff) != SHELLMAGIC) {
-                       /* NetBSD compatibility */
-                       switch (ntohl(exdata.ex_hdr.a_magic) & 0xffff) {
-                       case ZMAGIC:
-                       case QMAGIC:
-                               virtual_offset = NBPG;
-                               file_offset = 0;
-                               break;
-                       default:
-                               rv = ENOEXEC;
-                               goto exec_fail;
-                       }
-               } else {
-                       char *cp, *sp;
-
-                       if (indir) {
-                               rv = ENOEXEC;
-                               goto exec_fail;
-                       }
-                       for (cp = &exdata.ex_shell[2];; ++cp) {
-                               if (cp >= &exdata.ex_shell[MAXINTERP]) {
-                                       rv = ENOEXEC;
-                                       goto exec_fail;
-                               }
-                               if (*cp == '\n') {
-                                       *cp = '\0';
-                                       break;
-                               }
-                               if (*cp == '\t')
-                                       *cp = ' ';
-                       }
-                       cp = &exdata.ex_shell[2]; /* get shell interpreter name */
-                       while (*cp == ' ')
-                               cp++;
-
-                       sp = shellname;
-                       while (*cp && *cp != ' ')
-                               *sp++ = *cp++;
-                       *sp = '\0';
-
-                       /* copy the args in the #! line */
-                       while (*cp == ' ')
-                         cp++;
-                       if (*cp) {
-                           sp++;
-                           shellargs = sp;
-                           while (*cp)
-                             *sp++ = *cp++;
-                           *sp = '\0';
-                       } else {
-                           shellargs = 0;
-                       }
-
-                       indir = 1;              /* indicate this is a script file */
+       iparams->image_header = image_header;
+
+       /*
+        * Loop through list of image activators, calling each one.
+        *      If there is no match, the activator returns -1. If there
+        *      is a match, but there was an error during the activation,
+        *      the error is returned. Otherwise 0 means success. If the
+        *      image is interpreted, loop back up and try activating
+        *      the interpreter.
+        */
+       for (i = 0; i < sizeof(execsw)/sizeof(execsw[0]); ++i) {
+               if (execsw[i].imgact)
+                       error = (*execsw[i].imgact)(iparams);
+               else
+                       continue;
+
+               if (error == -1)
+                       continue;
+               if (error)
+                       goto exec_fail_dealloc;
+               if (iparams->interpreted) {
+                       /* free old vnode and name buffer */
                        vput(ndp->ni_vp);
                        FREE(ndp->ni_pnbuf, M_NAMEI);
                        vput(ndp->ni_vp);
                        FREE(ndp->ni_pnbuf, M_NAMEI);
+                       if (vm_deallocate(kernel_map, image_header, NBPG))
+                               panic("execve: header dealloc failed (1)");
 
 
-                       ndp->ni_dirp = shellname;       /* find shell interpreter */
+                       /* set new name to that of the interpreter */
                        ndp->ni_segflg = UIO_SYSSPACE;
                        ndp->ni_segflg = UIO_SYSSPACE;
-                       goto again;
+                       ndp->ni_dirp = iparams->interpreter_name;
+                       ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW | SAVENAME;
+                       goto interpret;
                }
                }
-                       /* NOT REACHED */
+               break;
+       }
+       /* If we made it through all the activators and none matched, exit. */
+       if (error == -1) {
+               error = ENOEXEC;
+               goto exec_fail_dealloc;
        }
 
        }
 
-       /* sanity check  "ain't not such thing as a sanity clause" -groucho */
-       rv = ENOMEM;
-       if (/*exdata.ex_hdr.a_text == 0 || */ exdata.ex_hdr.a_text > MAXTSIZ ||
-           exdata.ex_hdr.a_text % NBPG || exdata.ex_hdr.a_text > attr.va_size)
-               goto exec_fail;
+       /*
+        * Copy out strings (args and env) and initialize stack base
+        */
+       stack_base = exec_copyout_strings(iparams);
+       p->p_vmspace->vm_minsaddr = stack_base;
+       p->p_regs[SP] = (int) stack_base;
 
 
-       if (exdata.ex_hdr.a_data == 0 || exdata.ex_hdr.a_data > DFLDSIZ
-               || exdata.ex_hdr.a_data > attr.va_size
-               || exdata.ex_hdr.a_data + exdata.ex_hdr.a_text > attr.va_size)
-               goto exec_fail;
+       p->p_vmspace->vm_ssize = (((caddr_t)USRSTACK - stack_base) >> PAGE_SHIFT) + 1;
 
 
-       if (exdata.ex_hdr.a_bss > MAXDSIZ)
-               goto exec_fail;
-       
-       if (exdata.ex_hdr.a_text + exdata.ex_hdr.a_data + exdata.ex_hdr.a_bss > MAXTSIZ + MAXDSIZ)
-               goto exec_fail;
+       /*
+        * Stuff argument count as first item on stack
+        */
+       p->p_regs[SP] -= sizeof(int);
+       *(int *)(p->p_regs[SP]) = iparams->argc;
 
 
-       if (exdata.ex_hdr.a_data + exdata.ex_hdr.a_bss > p->p_rlimit[RLIMIT_DATA].rlim_cur)
-               goto exec_fail;
+       /* close files on exec, fixup signals */
+       fdcloseexec(p);
+       execsigs(p);
 
 
-       if (exdata.ex_hdr.a_entry > exdata.ex_hdr.a_text + exdata.ex_hdr.a_data)
-               goto exec_fail;
+       /* name this process - nameiexec(p, ndp) */
+       len = MIN(ndp->ni_namelen,MAXCOMLEN);
+       bcopy(ndp->ni_ptr, p->p_comm, len);
+       p->p_comm[len] = 0;
        
        /*
        
        /*
-        * Step 3.  File and header are valid. Now, dig out the strings
-        * out of the old process image.
+        * mark as executable, wakeup any process that was vforked and tell
+        * it that it now has it's own resources back
         */
         */
+       p->p_flag |= SEXEC;
+       if (p->p_pptr && (p->p_flag & SPPWAIT)) {
+               p->p_flag &= ~SPPWAIT;
+               wakeup((caddr_t)p->p_pptr);
+       }
+       
+       /* implement set userid/groupid */
+       if ((attr.va_mode&VSUID) && (p->p_flag & STRC) == 0) {
+               p->p_ucred = crcopy(p->p_ucred);
+               p->p_cred->p_svuid = p->p_ucred->cr_uid = attr.va_uid;
+       }
+       if ((attr.va_mode&VSGID) && (p->p_flag & STRC) == 0) {
+               p->p_ucred = crcopy(p->p_ucred);
+               p->p_cred->p_svgid = p->p_ucred->cr_groups[0] = attr.va_gid;
+       }
+
+       /* mark vnode pure text */
+       ndp->ni_vp->v_flag |= VTEXT;
 
        /*
 
        /*
-        * We implement a single-pass algorithm that builds a new stack
-        * frame within the address space of the "old" process image,
-        * avoiding the second pass entirely. Thus, the new frame is
-        * in position to be run. This consumes much virtual address space,
-        * and two pages more of 'real' memory, such are the costs.
-        * [Also, note the cache wipe that's avoided!]
+        * If tracing the process, trap to debugger so breakpoints
+        *      can be set before the program executes.
         */
         */
+       if (p->p_flag & STRC)
+               psignal(p, SIGTRAP);
 
 
-       /* create anonymous memory region for new stack */
-       vs = p->p_vmspace;
-       if ((unsigned)vs->vm_maxsaddr + MAXSSIZ < USRSTACK)
-               newframe = (caddr_t) USRSTACK - MAXSSIZ;
-       else
-               vs->vm_maxsaddr = newframe = (caddr_t) USRSTACK - 2*MAXSSIZ;
-
-       /* don't do stack limit checking on traps temporarily XXX*/
-       dostacklimits = 0;
-
-       rv = vm_allocate(&vs->vm_map, &newframe, MAXSSIZ, FALSE);
-       if (rv) goto exec_fail;
-
-       /* allocate string buffer and arg buffer */
-       argbuf = (char **) (newframe + MAXSSIZ - 3*ARG_MAX);
-       stringbuf = stringbufp = ((char *)argbuf) + 2*ARG_MAX;
-       argbufp = argbuf;
-
-       /* first, do args */
-       vectp = uap->argp;
-       needsenv = 1;
-       limitonargs = ARG_MAX;
-       cnt = 0;
-
-       /* first, do (shell name if any then) args */
-       if (indir)  {
-               ep = shellname;
-thrice:
-               if (ep) {
-                       /* did we outgrow initial argbuf, if so, die */
-                       if (argbufp >= (char **)stringbuf) {
-                               rv = E2BIG;
-                               goto exec_dealloc;
-                       }
-
-                       if (rv = copyoutstr(ep, stringbufp,
-                               (u_int)limitonargs, (u_int *)&stringlen)) {
-                               if (rv == ENAMETOOLONG)
-                                       rv = E2BIG;
-                               goto exec_dealloc;
-                       }
-                       suword(argbufp++, (int)stringbufp);
-                       cnt++;
-                       stringbufp += stringlen;
-                       limitonargs -= stringlen;
-               }
-
-               if (shellargs) {
-                   ep = shellargs;
-                   shellargs = 0;
-                   goto thrice;
-               }
-
-               if (indir) {
-                       indir = 0;
-                       /* orginal executable is 1st argument with scripts */
-                       ep = uap->fname;
-                       goto thrice;
-               }
-               /* terminate in case no more args to script */
-               suword(argbufp, 0);
-               if (vectp = uap->argp) vectp++; /* manually doing the first
-                                                  argument with scripts */
-       }
+       /* clear "fork but no exec" flag, as we _are_ execing */
+       p->p_acflag &= ~AFORK;
 
 
-do_env_as_well:
-       if(vectp == 0) goto dont_bother;
+       /* Set entry address */
+       setregs(p, iparams->entry_addr);
 
 
-       /* for each envp, copy in string */
-       do {
-               /* did we outgrow initial argbuf, if so, die */
-               if (argbufp == (char **)stringbuf) {
-                       rv = E2BIG;
-                       goto exec_dealloc;
-               }
-       
-               /* get an string pointer */
-               ep = (char *)fuword(vectp++);
-               if (ep == (char *)-1) {
-                       rv = EFAULT;
-                       goto exec_dealloc;
-               }
+       /*
+        * free various allocated resources
+        */
+       if (vm_deallocate(kernel_map, iparams->stringbase, ARG_MAX))
+               panic("execve: string buffer dealloc failed (1)");
+       if (vm_deallocate(kernel_map, image_header, NBPG))
+               panic("execve: header dealloc failed (2)");
+       vput(ndp->ni_vp);
+       FREE(ndp->ni_pnbuf, M_NAMEI);
 
 
-               /* if not a null pointer, copy string */
-               if (ep) {
-                       if (rv = copyinoutstr(ep, stringbufp,
-                               (u_int)limitonargs, (u_int *) &stringlen)) {
-                               if (rv == ENAMETOOLONG)
-                                       rv = E2BIG;
-                               goto exec_dealloc;
-                       }
-                       suword(argbufp++, (int)stringbufp);
-                       cnt++;
-                       stringbufp += stringlen;
-                       limitonargs -= stringlen;
-               } else {
-                       suword(argbufp++, 0);
-                       break;
-               }
-       } while (limitonargs > 0);
+       return (0);
 
 
-dont_bother:
-       if (limitonargs <= 0) {
-               rv = E2BIG;
-               goto exec_dealloc;
-       }
+exec_fail_dealloc:
+       if (iparams->stringbase && iparams->stringbase != (char *)-1)
+               if (vm_deallocate(kernel_map, iparams->stringbase, ARG_MAX))
+                       panic("execve: string buffer dealloc failed (2)");
+       if (iparams->image_header && iparams->image_header != (char *)-1)
+               if (vm_deallocate(kernel_map, image_header, NBPG))
+                       panic("execve: header dealloc failed (3)");
+       vput(ndp->ni_vp);
+       FREE(ndp->ni_pnbuf, M_NAMEI);
 
 
-       /* have we done the environment yet ? */
-       if (needsenv) {
-               /* remember the arg count for later */
-               argc = cnt;
-               vectp = uap->envp;
-               needsenv = 0;
-               goto do_env_as_well;
+exec_fail:
+       if (iparams->vmspace_destroyed) {
+               /* sorry, no more process anymore. exit gracefully */
+#if 0  /* XXX */
+               vm_deallocate(&vs->vm_map, USRSTACK - MAXSSIZ, MAXSSIZ);
+#endif
+               kexit(p, W_EXITCODE(0, SIGABRT));
+               /* NOT REACHED */
+               return(0);
+       } else {
+               return(error);
        }
        }
-       /* At this point, one could optionally implement a
-        * second pass to condense the strings, arguement vectors,
-        * and stack to fit the fewest pages.
-        *
-        * One might selectively do this when copying was cheaper
-        * than leaving allocated two more pages per process.
-        */
+}
 
 
-       /* stuff arg count on top of "new" stack */
-       /* argbuf[-1] = (char *)argc;*/
-       suword(argbuf-1,argc);
+/*
+ * Destroy old address space, and allocate a new stack
+ *     The new stack is only DFLSSIZ large because it is grown
+ *     automatically in trap.c.
+ */
+int
+exec_new_vmspace(iparams)
+       struct image_params *iparams;
+{
+       int error;
+       struct vmspace *vmspace = iparams->proc->p_vmspace;
+       caddr_t stack_addr = (caddr_t) (USRSTACK - DFLSSIZ);
 
 
-       /*
-        * Step 4. Build the new processes image.
-        *
-        * At this point, we are committed -- destroy old executable!
-        */
+       iparams->vmspace_destroyed = 1;
 
 
-       /* blow away all address space, except the stack */
-       rv = vm_deallocate(&vs->vm_map, 0, USRSTACK - 2*MAXSSIZ);
-       if (rv)
-               goto exec_abort;
+       /* Blow away entire process VM */
+       vm_deallocate(&vmspace->vm_map, 0, USRSTACK);
 
 
-       /* destroy "old" stack */
-       if ((unsigned)newframe < USRSTACK - MAXSSIZ) {
-               rv = vm_deallocate(&vs->vm_map, USRSTACK - MAXSSIZ, MAXSSIZ);
-               if (rv)
-                       goto exec_abort;
-       } else {
-               rv = vm_deallocate(&vs->vm_map, USRSTACK - 2*MAXSSIZ, MAXSSIZ);
-               if (rv)
-                       goto exec_abort;
-       }
+       /* Allocate a new stack */
+       error = vm_allocate(&vmspace->vm_map, &stack_addr, DFLSSIZ, FALSE);
+       if (error)
+               return(error);
 
 
-       /* build a new address space */
+       /* Initialize maximum stack address */
+       vmspace->vm_maxsaddr = (char *)USRSTACK - MAXSSIZ;
 
 
+       return(0);
+}
 
 
+/*
+ * Copy out argument and environment strings from the old process
+ *     address space into the temporary string buffer.
+ */
+int
+exec_extract_strings(iparams)
+       struct image_params *iparams;
+{
+       char    **argv, **envv;
+       char    *argp, *envp;
+       int     length;
 
 
-       /* treat text, data, and bss in terms of integral page size */
-       tsize = roundup(exdata.ex_hdr.a_text, NBPG);
-       dsize = roundup(exdata.ex_hdr.a_data, NBPG);
-       bsize = roundup(exdata.ex_hdr.a_bss, NBPG);
+       /*
+        * extract arguments first
+        */
 
 
-       addr = virtual_offset;
+       argv = iparams->uap->argv; 
+
+       if (argv)
+               while (argp = (caddr_t) fuword(argv++)) {
+                       if (argp == (caddr_t) -1)
+                               return (EFAULT);
+                       if (copyinstr(argp, iparams->stringp, iparams->stringspace,
+                               &length) == ENAMETOOLONG)
+                                       return(E2BIG);
+                       iparams->stringspace -= length;
+                       iparams->stringp += length;
+                       iparams->argc++;
+               }
 
 
-       /* map text as being read/execute only and demand paged */
-       rv = vm_mmap(&vs->vm_map, &addr, tsize, VM_PROT_READ|VM_PROT_EXECUTE,
-               VM_PROT_DEFAULT, MAP_FILE|MAP_PRIVATE|MAP_FIXED,
-               (caddr_t)ndp->ni_vp, file_offset);
-       if (rv)
-               goto exec_abort;
+       /*
+        * extract environment strings
+        */
 
 
-       addr = virtual_offset + tsize;
+       envv = iparams->uap->envv; 
+
+       if (envv)
+               while (envp = (caddr_t) fuword(envv++)) {
+                       if (envp == (caddr_t) -1)
+                               return (EFAULT);
+                       if (copyinstr(envp, iparams->stringp, iparams->stringspace,
+                               &length) == ENAMETOOLONG)
+                                       return(E2BIG);
+                       iparams->stringspace -= length;
+                       iparams->stringp += length;
+                       iparams->envc++;
+               }
 
 
-       /* map data as being read/write and demand paged */
-       rv = vm_mmap(&vs->vm_map, &addr, dsize,
-               VM_PROT_READ | VM_PROT_WRITE | (tsize ? 0 : VM_PROT_EXECUTE),
-               VM_PROT_DEFAULT, MAP_FILE|MAP_PRIVATE|MAP_FIXED,
-               (caddr_t)ndp->ni_vp, file_offset + tsize);
-       if (rv)
-               goto exec_abort;
+       return (0);
+}
 
 
-       /* create anonymous memory region for bss */
-       addr = virtual_offset + tsize + dsize;
-       rv = vm_allocate(&vs->vm_map, &addr, bsize, FALSE);
-       if (rv)
-               goto exec_abort;
+/*
+ * Copy strings out to the new process address space, constructing
+ *     new arg and env vector tables. Return a pointer to the base
+ *     so that it can be used as the initial stack pointer.
+ */
+caddr_t
+exec_copyout_strings(iparams)
+       struct image_params *iparams;
+{
+       int argc, envc;
+       char **vectp;
+       char *stack_base, *stringp, *destp;
+       int vect_table_size, string_table_size;
 
        /*
 
        /*
-        * Step 5. Prepare process for execution.
+        * Calculate string base and vector table pointers.
+        */
+       destp = (caddr_t) ((caddr_t)USRSTACK -
+               roundup((ARG_MAX - iparams->stringspace), sizeof(char *)));
+       /*
+        * The '+ 2' is for the null pointers at the end of each of the
+        *      arg and env vector sets
         */
         */
+       vectp = (char **) (destp -
+               (iparams->argc + iparams->envc + 2) * sizeof(char *));
 
 
-       /* touchup process information -- vm system is unfinished! */
-       vs->vm_tsize = tsize/NBPG;              /* text size (pages) XXX */
-       vs->vm_dsize = (dsize+bsize)/NBPG;      /* data size (pages) XXX */
-       vs->vm_taddr = (caddr_t) virtual_offset; /* virtual address of text */
-       vs->vm_daddr = (caddr_t) virtual_offset + tsize; /* virtual address of data */
-       vs->vm_maxsaddr = newframe;     /* user VA at max stack growth XXX */
-       vs->vm_ssize =  ((unsigned)vs->vm_maxsaddr + MAXSSIZ
-               - (unsigned)argbuf)/ NBPG + 1; /* stack size (pages) */
-       dostacklimits = 1;      /* allow stack limits to be enforced XXX */
+       /*
+        * vectp also becomes our initial stack base
+        */
+       stack_base = (caddr_t)vectp;
 
 
-       /* close files on exec, fixup signals */
-       fdcloseexec(p);
-       execsigs(p);
+       stringp = iparams->stringbase;
+       argc = iparams->argc;
+       envc = iparams->envc;
 
 
-       /* name this process - nameiexec(p, ndp) */
-       len = MIN(ndp->ni_namelen,MAXCOMLEN);
-       bcopy(ndp->ni_ptr, p->p_comm, len);
-       p->p_comm[len] = 0;
-       
-       /* mark as executable, wakeup any process that was vforked and tell
-        * it that it now has it's own resources back */
-       p->p_flag |= SEXEC;
-       if (p->p_pptr && (p->p_flag & SPPWAIT)) {
-           p->p_flag &= ~SPPWAIT;
-           wakeup((caddr_t)p->p_pptr);
+       for (; argc > 0; --argc) {
+               *(vectp++) = destp;
+               while (*destp++ = *stringp++);
        }
        }
-       
-       /* implement set userid/groupid */
-       if ((attr.va_mode&VSUID) && (p->p_flag & STRC) == 0) {
-           p->p_ucred = crcopy(p->p_ucred);
-           p->p_cred->p_svuid = p->p_ucred->cr_uid = attr.va_uid;
-       }
-       if ((attr.va_mode&VSGID) && (p->p_flag & STRC) == 0) {
-           p->p_ucred = crcopy(p->p_ucred);
-           p->p_cred->p_svgid = p->p_ucred->cr_groups[0] = attr.va_gid;
+
+       /* a null vector table pointer seperates the argp's from the envp's */
+       *(vectp++) = NULL;
+
+       for (; envc > 0; --envc) {
+               *(vectp++) = destp;
+               while (*destp++ = *stringp++);
        }
 
        }
 
-       /* setup initial register state */
-       p->p_regs[SP] = (unsigned) (argbuf - 1);
-       setregs(p, exdata.ex_hdr.a_entry);
+       /* end of vector table is a null pointer */
+       *vectp = NULL;
 
 
-       ndp->ni_vp->v_flag |= VTEXT;            /* mark vnode pure text */
+       return (stack_base);
+}
 
 
-       vput(ndp->ni_vp);
-       FREE(ndp->ni_pnbuf, M_NAMEI);
+/*
+ * Check permissions of file to execute.
+ *     Return 0 for success or error code on failure.
+ */
+int
+exec_check_permissions(iparams)
+       struct image_params *iparams;
+{
+       struct proc *p = iparams->proc;
+       struct vnode *vnodep = iparams->vnodep;
+       struct vattr *attr = iparams->attr;
+       int error;
 
 
-       /* if tracing process, pass control back to debugger so breakpoints
-          can be set before the program "runs" */
-       if (p->p_flag & STRC)
-               psignal(p, SIGTRAP);
-       p->p_acflag &= ~AFORK;          /* remove fork, but no exec flag */
+       /*
+        * Check number of open-for-writes on the file and deny execution
+        *      if there are any.
+        */
+       if (vnodep->v_writecount) {
+               return (ETXTBSY);
+       }
 
 
-       return (0);
+       /* Get file attributes */
+       error = VOP_GETATTR(vnodep, attr, p->p_ucred, p);
+       if (error)
+               return (error);
 
 
-exec_dealloc:
-       /* remove interim "new" stack frame we were building */
-       vm_deallocate(&vs->vm_map, newframe, MAXSSIZ);
+       /*
+        * 1) Check if file execution is disabled for the filesystem that this
+        *      file resides on.
+        * 2) Insure that at least one execute bit is on - otherwise root
+        *      will always succeed, and we don't want to happen unless the
+        *      file really is executable.
+        * 3) Insure that the file is a regular file.
+        */
+       if ((vnodep->v_mount->mnt_flag & MNT_NOEXEC) ||
+           ((attr->va_mode & 0111) == 0) ||
+           (attr->va_type != VREG)) {
+               return (EACCES);
+       }
 
 
-exec_fail:
-       dostacklimits = 1;
-       vput(ndp->ni_vp);
-       FREE(ndp->ni_pnbuf, M_NAMEI);
+       /*
+        * Disable setuid/setgid if the filesystem prohibits it or if
+        *      the process is being traced.
+        */
+        if ((vnodep->v_mount->mnt_flag & MNT_NOSUID) || (p->p_flag & STRC))
+               attr->va_mode &= ~(VSUID | VSGID);
 
 
-       return(rv);
+       /*
+        *  Check for execute permission to file based on current credentials.
+        *      Then call filesystem specific open routine (which does nothing
+        *      in the general case).
+        */
+       error = VOP_ACCESS(vnodep, VEXEC, p->p_ucred, p);
+       if (error)
+               return (error);
 
 
-exec_abort:
-       /* sorry, no more process anymore. exit gracefully */
-       vm_deallocate(&vs->vm_map, newframe, MAXSSIZ);
-       vput(ndp->ni_vp);
-       FREE(ndp->ni_pnbuf, M_NAMEI);
-       kexit(p, W_EXITCODE(0, SIGABRT));
+       error = VOP_OPEN(vnodep, FREAD, p->p_ucred, p);
+       if (error)
+               return (error);
 
 
-       /* NOTREACHED */
-       return(0);
+       return (0);
 }
 }