lint
[unix-history] / usr / src / sys / kern / kern_exec.c
index b8465c3..4d27e87 100644 (file)
-/*     kern_exec.c     4.1     83/05/27        */
+/*-
+ * Copyright (c) 1982, 1986, 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * %sccs.include.proprietary.c%
+ *
+ *     @(#)kern_exec.c 7.55 (Berkeley) %G%
+ */
 
 
-#include "../machine/reg.h"
-#include "../machine/pte.h"
-#include "../machine/psl.h"
+#include "param.h"
+#include "systm.h"
+#include "filedesc.h"
+#include "kernel.h"
+#include "proc.h"
+#include "mount.h"
+#include "malloc.h"
+#include "namei.h"
+#include "vnode.h"
+#include "file.h"
+#include "acct.h"
+#include "exec.h"
+#include "ktrace.h"
+#include "resourcevar.h"
 
 
-#include "../h/param.h"
-#include "../h/systm.h"
-#include "../h/map.h"
-#include "../h/dir.h"
-#include "../h/user.h"
-#include "../h/kernel.h"
-#include "../h/proc.h"
-#include "../h/buf.h"
-#include "../h/inode.h"
-#include "../h/seg.h"
-#include "../h/vm.h"
-#include "../h/text.h"
-#include "../h/file.h"
-#include "../h/uio.h"
-#include "../h/nami.h"
-#include "../h/acct.h"
+#include "machine/cpu.h"
+#include "machine/reg.h"
 
 
-/*
- * exec system call, with and without environments.
- */
-struct execa {
-       char    *fname;
-       char    **argp;
-       char    **envp;
-};
+#include "mman.h"
+#include "vm/vm.h"
+#include "vm/vm_param.h"
+#include "vm/vm_map.h"
+#include "vm/vm_kern.h"
+#include "vm/vm_pager.h"
 
 
-execv()
-{
-       ((struct execa *)u.u_ap)->envp = NULL;
-       execve();
-}
+#include "signalvar.h"
+#include "kinfo_proc.h"
 
 
-execve()
+#ifdef HPUXCOMPAT
+#include "user.h"                      /* for pcb */
+#include "hp300/hpux/hpux_exec.h"
+#endif
+
+#ifdef COPY_SIGCODE
+extern char sigcode[], esigcode[];
+#define        szsigcode       (esigcode - sigcode)
+#else
+#define        szsigcode       0
+#endif
+
+/*
+ * exec system call
+ */
+/* ARGSUSED */
+execve(p, uap, retval)
+       register struct proc *p;
+       register struct args {
+               char    *fname;
+               char    **argp;
+               char    **envp;
+       } *uap;
+       int *retval;
 {
 {
-       register nc;
+       register struct ucred *cred = p->p_ucred;
+       register struct filedesc *fdp = p->p_fd;
+       int na, ne, ucp, ap, cc, ssize;
        register char *cp;
        register char *cp;
-       register struct buf *bp;
-       register struct execa *uap;
-       int na, ne, ucp, ap, c;
+       register int nc;
+       unsigned len;
        int indir, uid, gid;
        char *sharg;
        int indir, uid, gid;
        char *sharg;
-       struct inode *ip;
-       swblk_t bno;
-       char cfname[MAXCOMLEN + 1];
-       char cfarg[SHSIZE];
-       int resid;
+       struct vnode *vp;
+       int resid, error, paged = 0;
+       vm_offset_t execargs = 0;
+       struct vattr vattr;
+       char cfarg[MAXINTERP];
+       union {
+               char    ex_shell[MAXINTERP];    /* #! and interpreter name */
+               struct  exec ex_exec;
+#ifdef HPUXCOMPAT
+               struct  hpux_exec ex_hexec;
+#endif
+       } exdata;
+#ifdef HPUXCOMPAT
+       struct hpux_exec hhead;
+#endif
+       struct nameidata nd;
+       struct ps_strings ps;
+#ifdef SECSIZE
+       extern long argdbsize;                  /* XXX */
+#endif SECSIZE
 
 
-       if ((ip = namei(uchar, LOOKUP, 1)) == NULL)
-               return;
-       bno = 0;
-       bp = 0;
+       NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | SAVENAME, UIO_USERSPACE,
+               uap->fname, p);
+       if (error = namei(&nd))
+               return (error);
+       vp = nd.ni_vp;
        indir = 0;
        indir = 0;
-       uid = u.u_uid;
-       gid = u.u_gid;
-       if (ip->i_mode & ISUID)
-               uid = ip->i_uid;
-       if (ip->i_mode & ISGID)
-               gid = ip->i_gid;
+       uid = cred->cr_uid;
+       gid = cred->cr_gid;
+       if (error = VOP_GETATTR(vp, &vattr, cred, p))
+               goto bad;
+       if (vp->v_mount->mnt_flag & MNT_NOEXEC) {
+               error = EACCES;
+               goto bad;
+       }
+       if ((vp->v_mount->mnt_flag & MNT_NOSUID) == 0) {
+               if (vattr.va_mode & VSUID)
+                       uid = vattr.va_uid;
+               if (vattr.va_mode & VSGID)
+                       gid = vattr.va_gid;
+       }
 
   again:
 
   again:
-       if (access(ip, IEXEC))
+       if (error = VOP_ACCESS(vp, VEXEC, cred, p))
                goto bad;
                goto bad;
-       if ((u.u_procp->p_flag&STRC) && access(ip, IREAD))
+       if ((p->p_flag & STRC) && (error = VOP_ACCESS(vp, VREAD, cred, p)))
                goto bad;
                goto bad;
-       if ((ip->i_mode & IFMT) != IFREG ||
-          (ip->i_mode & (IEXEC|(IEXEC>>3)|(IEXEC>>6))) == 0) {
-               u.u_error = EACCES;
+       if (vp->v_type != VREG ||
+           (vattr.va_mode & (VEXEC|(VEXEC>>3)|(VEXEC>>6))) == 0) {
+               error = EACCES;
                goto bad;
        }
 
        /*
                goto bad;
        }
 
        /*
-        * Read in first few bytes of file for segment sizes, ux_mag:
-        *      407 = plain executable
-        *      410 = RO text
-        *      413 = demand paged RO text
+        * Read in first few bytes of file for segment sizes, magic number:
+        *      OMAGIC = plain executable
+        *      NMAGIC = RO text
+        *      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.
         * 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.
@@ -88,81 +135,172 @@ execve()
         * ONLY ONE ARGUMENT MAY BE PASSED TO THE SHELL FROM
         * THE ASCII LINE.
         */
         * ONLY ONE ARGUMENT MAY BE PASSED TO THE SHELL FROM
         * THE ASCII LINE.
         */
-       u.u_exdata.ux_shell[0] = 0;     /* for zero length files */
-       u.u_error = rdwri(UIO_READ, ip, (caddr_t)&u.u_exdata, sizeof (u.u_exdata),
-           0, 1, &resid);
-       if (u.u_error)
+       exdata.ex_shell[0] = '\0';      /* for zero length files */
+       error = vn_rdwr(UIO_READ, vp, (caddr_t)&exdata, sizeof (exdata),
+           (off_t)0, UIO_SYSSPACE, (IO_UNIT|IO_NODELOCKED), cred, &resid,
+           (struct proc *)0);
+       if (error)
                goto bad;
                goto bad;
-       u.u_count = resid;
 #ifndef lint
 #ifndef lint
-       if (u.u_count > sizeof(u.u_exdata) - sizeof(u.u_exdata.Ux_A) &&
-           u.u_exdata.ux_shell[0] != '#') {
-               u.u_error = ENOEXEC;
+       if (resid > sizeof(exdata) - sizeof(exdata.ex_exec) &&
+           exdata.ex_shell[0] != '#') {
+               error = ENOEXEC;
                goto bad;
        }
 #endif
                goto bad;
        }
 #endif
-       switch (u.u_exdata.ux_mag) {
+#if defined(hp300)
+       switch ((int)exdata.ex_exec.a_mid) {
 
 
-       case 0407:
-               u.u_exdata.ux_dsize += u.u_exdata.ux_tsize;
-               u.u_exdata.ux_tsize = 0;
+       /*
+        * An ancient hp200 or hp300 binary, shouldn't happen anymore.
+        * Mark as invalid.
+        */
+       case MID_ZERO:
+               exdata.ex_exec.a_magic = 0;
                break;
 
                break;
 
-       case 0413:
-       case 0410:
-               if (u.u_exdata.ux_tsize == 0) {
-                       u.u_error = ENOEXEC;
+       /*
+        * HP200 series has a smaller page size so we cannot
+        * demand-load or even write protect text, so we just
+        * treat as OMAGIC.
+        */
+       case MID_HP200:
+               exdata.ex_exec.a_magic = OMAGIC;
+               break;
+
+       case MID_HP300:
+               break;
+
+#ifdef HPUXCOMPAT
+       case MID_HPUX:
+               /*
+                * Save a.out header.  This is eventually saved in the pcb,
+                * but we cannot do that yet in case the exec fails before
+                * the image is overlayed.
+                */
+               bcopy((caddr_t)&exdata.ex_hexec,
+                     (caddr_t)&hhead, sizeof hhead);
+               /*
+                * If version number is 0x2bad this is a native BSD
+                * binary created via the HPUX SGS.  Should not be
+                * treated as an HPUX binary.
+                */
+               if (exdata.ex_hexec.ha_version != BSDVNUM)
+                       paged |= SHPUX;                         /* XXX */
+               /*
+                * Shuffle important fields to their BSD locations.
+                * Note that the order in which this is done is important.
+                */
+               exdata.ex_exec.a_text = exdata.ex_hexec.ha_text;
+               exdata.ex_exec.a_data = exdata.ex_hexec.ha_data;
+               exdata.ex_exec.a_bss = exdata.ex_hexec.ha_bss;
+               exdata.ex_exec.a_entry = exdata.ex_hexec.ha_entry;
+               /*
+                * For ZMAGIC files, make sizes consistant with those
+                * generated by BSD ld.
+                */
+               if (exdata.ex_exec.a_magic == ZMAGIC) {
+                       exdata.ex_exec.a_text = 
+                               ctob(btoc(exdata.ex_exec.a_text));
+                       nc = exdata.ex_exec.a_data + exdata.ex_exec.a_bss;
+                       exdata.ex_exec.a_data =
+                               ctob(btoc(exdata.ex_exec.a_data));
+                       nc -= (int)exdata.ex_exec.a_data;
+                       exdata.ex_exec.a_bss = (nc < 0) ? 0 : nc;
+               }
+               break;
+#endif
+       }
+#endif
+       switch ((int)exdata.ex_exec.a_magic) {
+
+       case OMAGIC:
+#ifdef COFF
+               if (exdata.ex_exec.ex_fhdr.magic != COFF_MAGIC) {
+                       error = ENOEXEC;
+                       goto bad;
+               }
+#endif
+#ifdef sparc
+               if (exdata.ex_exec.a_mid != MID_SUN_SPARC) {
+                       error = ENOEXEC;
+                       goto bad;
+               }
+#endif
+               exdata.ex_exec.a_data += exdata.ex_exec.a_text;
+               exdata.ex_exec.a_text = 0;
+               break;
+
+       case ZMAGIC:
+#ifdef HPUXCOMPAT
+               paged |= 1;     /* XXX fix me */
+#else
+               paged = 1;
+#endif
+               /* FALLTHROUGH */
+
+       case NMAGIC:
+#ifdef COFF
+               if (exdata.ex_exec.ex_fhdr.magic != COFF_MAGIC) {
+                       error = ENOEXEC;
+                       goto bad;
+               }
+#endif
+#ifdef sparc
+               if (exdata.ex_exec.a_mid != MID_SUN_SPARC) {
+                       error = ENOEXEC;
+                       goto bad;
+               }
+#endif
+               if (exdata.ex_exec.a_text == 0) {
+                       error = ENOEXEC;
                        goto bad;
                }
                break;
 
        default:
                        goto bad;
                }
                break;
 
        default:
-               if (u.u_exdata.ux_shell[0] != '#' ||
-                   u.u_exdata.ux_shell[1] != '!' ||
+               if (exdata.ex_shell[0] != '#' ||
+                   exdata.ex_shell[1] != '!' ||
                    indir) {
                    indir) {
-                       u.u_error = ENOEXEC;
+                       error = ENOEXEC;
                        goto bad;
                }
                        goto bad;
                }
-               cp = &u.u_exdata.ux_shell[2];           /* skip "#!" */
-               while (cp < &u.u_exdata.ux_shell[SHSIZE]) {
-                       if (*cp == '\t')
-                               *cp = ' ';
-                       else if (*cp == '\n') {
+               for (cp = &exdata.ex_shell[2];; ++cp) {
+                       if (cp >= &exdata.ex_shell[MAXINTERP]) {
+                               error = ENOEXEC;
+                               goto bad;
+                       }
+                       if (*cp == '\n') {
                                *cp = '\0';
                                break;
                        }
                                *cp = '\0';
                                break;
                        }
-                       cp++;
-               }
-               if (*cp != '\0') {
-                       u.u_error = ENOEXEC;
-                       goto bad;
+                       if (*cp == '\t')
+                               *cp = ' ';
                }
                }
-               cp = &u.u_exdata.ux_shell[2];
+               cp = &exdata.ex_shell[2];
                while (*cp == ' ')
                        cp++;
                while (*cp == ' ')
                        cp++;
-               u.u_dirp = cp;
+               nd.ni_dirp = cp;
                while (*cp && *cp != ' ')
                        cp++;
                while (*cp && *cp != ' ')
                        cp++;
-               sharg = NULL;
+               cfarg[0] = '\0';
                if (*cp) {
                        *cp++ = '\0';
                        while (*cp == ' ')
                                cp++;
                if (*cp) {
                        *cp++ = '\0';
                        while (*cp == ' ')
                                cp++;
-                       if (*cp) {
-                               bcopy((caddr_t)cp, (caddr_t)cfarg, SHSIZE);
-                               sharg = cfarg;
-                       }
+                       if (*cp)
+                               bcopy((caddr_t)cp, (caddr_t)cfarg, MAXINTERP);
                }
                }
-               if (u.u_dent.d_namlen > MAXCOMLEN)
-                       u.u_dent.d_namlen = MAXCOMLEN;
-               bcopy((caddr_t)u.u_dent.d_name, (caddr_t)cfname,
-                   (unsigned)(u.u_dent.d_namlen + 1));
-               cfname[MAXCOMLEN] = 0;
                indir = 1;
                indir = 1;
-               iput(ip);
-               ip = namei(schar, LOOKUP, 1);
-               if (ip == NULL)
-                       return;
+               vput(vp);
+               nd.ni_segflg = UIO_SYSSPACE;
+               if (error = namei(&nd))
+                       return (error);
+               vp = nd.ni_vp;
+               if (error = VOP_GETATTR(vp, &vattr, cred, p))
+                       goto bad;
+               uid = cred->cr_uid;     /* shell scripts can't be setuid */
+               gid = cred->cr_gid;
                goto again;
        }
 
                goto again;
        }
 
@@ -172,298 +310,425 @@ execve()
        na = 0;
        ne = 0;
        nc = 0;
        na = 0;
        ne = 0;
        nc = 0;
-       uap = (struct execa *)u.u_ap;
-       if ((bno = rmalloc(argmap, (long)ctod(clrnd((int)btoc(NCARGS))))) == 0) {
-               swkill(u.u_procp, "exece");
-               goto bad;
-       }
-       if (bno % CLSIZE)
-               panic("execa rmalloc");
+       cc = NCARGS;
+       execargs = kmem_alloc_wait(exec_map, NCARGS);
+#ifdef DIAGNOSTIC
+       if (execargs == (vm_offset_t)0)
+               panic("execve: kmem_alloc_wait");
+#endif
+       cp = (char *) execargs;
+       /*
+        * Copy arguments into file in argdev area.
+        */
        if (uap->argp) for (;;) {
                ap = NULL;
        if (uap->argp) for (;;) {
                ap = NULL;
-               if (indir && (na == 1 || na == 2 && sharg))
+               sharg = NULL;
+               if (indir && na == 0) {
+                       sharg = nd.ni_cnd.cn_nameptr;
+                       ap = (int)sharg;
+                       uap->argp++;            /* ignore argv[0] */
+               } else if (indir && (na == 1 && cfarg[0])) {
+                       sharg = cfarg;
+                       ap = (int)sharg;
+               } else if (indir && (na == 1 || na == 2 && cfarg[0]))
                        ap = (int)uap->fname;
                else if (uap->argp) {
                        ap = fuword((caddr_t)uap->argp);
                        uap->argp++;
                }
                        ap = (int)uap->fname;
                else if (uap->argp) {
                        ap = fuword((caddr_t)uap->argp);
                        uap->argp++;
                }
-               if (ap==NULL && uap->envp) {
+               if (ap == NULL && uap->envp) {
                        uap->argp = NULL;
                        uap->argp = NULL;
-                       if ((ap = fuword((caddr_t)uap->envp)) == NULL)
-                               break;
-                       uap->envp++;
-                       ne++;
+                       if ((ap = fuword((caddr_t)uap->envp)) != NULL)
+                               uap->envp++, ne++;
                }
                if (ap == NULL)
                        break;
                na++;
                }
                if (ap == NULL)
                        break;
                na++;
-               if (ap == -1)
-                       u.u_error = EFAULT;
+               if (ap == -1) {
+                       error = EFAULT;
+                       goto bad;
+               }
                do {
                do {
-                       if (nc >= NCARGS-1)
-                               u.u_error = E2BIG;
-                       if (indir && na == 2 && sharg != NULL)
-                               c = *sharg++ & 0377;
-                       else if ((c = fubyte((caddr_t)ap++)) < 0)
-                               u.u_error = EFAULT;
-                       if (u.u_error) {
-                               if (bp)
-                                       brelse(bp);
-                               bp = 0;
-                               goto badarg;
+                       if (nc >= NCARGS-1) {
+                               error = E2BIG;
+                               break;
                        }
                        }
-                       if (nc % (CLSIZE*NBPG) == 0) {
-                               if (bp)
-                                       bdwrite(bp);
-                               bp = getblk(argdev, bno + ctod(nc / NBPG),
-                                   CLSIZE*NBPG);
-                               cp = bp->b_un.b_addr;
+                       if (sharg) {
+                               error = copystr(sharg, cp, (unsigned)cc, &len);
+                               sharg += len;
+                       } else {
+                               error = copyinstr((caddr_t)ap, cp, (unsigned)cc,
+                                   &len);
+                               ap += len;
                        }
                        }
-                       nc++;
-                       *cp++ = c;
-               } while (c > 0);
-       }
-       if (bp)
-               bdwrite(bp);
-       bp = 0;
-       nc = (nc + NBPW-1) & ~(NBPW-1);
-       if (indir) {
-               u.u_dent.d_namlen = strlen(cfname);
-               bcopy((caddr_t)cfname, (caddr_t)u.u_dent.d_name,
-                   (unsigned)(u.u_dent.d_namlen + 1));
+                       cp += len;
+                       nc += len;
+                       cc -= len;
+               } while (error == ENAMETOOLONG);
+               if (error)
+                       goto bad;
        }
        }
-       getxfile(ip, nc + (na+4)*NBPW, uid, gid);
-       if (u.u_error) {
-badarg:
-               for (c = 0; c < nc; c += CLSIZE*NBPG) {
-                       bp = baddr(argdev, bno + ctod(c / NBPG), CLSIZE*NBPG);
-                       if (bp) {
-                               bp->b_flags |= B_AGE;           /* throw away */
-                               bp->b_flags &= ~B_DELWRI;       /* cancel io */
-                               brelse(bp);
-                               bp = 0;
-                       }
-               }
+
+       /*
+        * XXX the following is excessively bogus
+        *
+        * Compute initial process stack size and location of argc
+        * and character strings.  `nc' is currently just the number
+        * of characters of arg and env strings.
+        *
+        * nc = size of ps_strings structure +
+        *      size of signal code +
+        *      4 bytes of NULL pointer +
+        *      nc,
+        * rounded to nearest integer;
+        * ucp = USRSTACK - nc;         [user characters pointer]
+        * apsize = padding (if any) +
+        *      4 bytes of NULL pointer +
+        *      ne 4-byte pointers to env strings +
+        *      4 bytes of NULL pointer +
+        *      (na-ne) 4-byte pointers to arg strings +
+        *      4 bytes of argc;
+        * (this is the same as nc + (na+3)*4)
+        * ap = ucp - apsize;   [user address of argc]
+        * ssize = ssize + nc + machine-dependent space;
+        */
+       nc = (sizeof(ps) + szsigcode + 4 + nc + NBPW-1) & ~(NBPW - 1);
+#ifdef sparc
+       ucp = USRSTACK;
+       ssize = (nc + (na + 3) * NBPW + 7) & ~7;
+       ap = ucp - ssize;
+       ucp -= nc;
+       ssize += sizeof(struct rwindow);
+#else
+       ssize = (na + 3) * NBPW;
+       ucp = USRSTACK - nc;
+       ap = ucp - ssize;
+       ssize += nc;
+#endif
+       error = getxfile(p, vp, &exdata.ex_exec, paged, ssize, uid, gid);
+       if (error)
                goto bad;
                goto bad;
-       }
+       vput(vp);
+       vp = NULL;
 
 
+#ifdef HPUXCOMPAT
        /*
        /*
-        * copy back arglist
+        * We are now committed to the exec so we can save the exec
+        * header in the pcb where we can dump it if necessary in core()
         */
         */
-       ucp = USRSTACK - nc - NBPW;
-       ap = ucp - na*NBPW - 3*NBPW;
-       u.u_ar0[SP] = ap;
+       if (p->p_addr->u_pcb.pcb_flags & PCB_HPUXBIN)
+               bcopy((caddr_t)&hhead,
+                     (caddr_t)p->p_addr->u_pcb.pcb_exec, sizeof hhead);
+#endif
+
+       /*
+        * Copy back arglist.
+        */
+       cpu_setstack(p, ap);
        (void) suword((caddr_t)ap, na-ne);
        nc = 0;
        (void) suword((caddr_t)ap, na-ne);
        nc = 0;
+       cp = (char *) execargs;
+       cc = NCARGS;
+       ps.ps_argvstr = (char *)ucp;    /* first argv string */
+       ps.ps_nargvstr = na - ne;       /* argc */
        for (;;) {
                ap += NBPW;
        for (;;) {
                ap += NBPW;
-               if (na==ne) {
+               if (na == ne) {
                        (void) suword((caddr_t)ap, 0);
                        ap += NBPW;
                        (void) suword((caddr_t)ap, 0);
                        ap += NBPW;
+                       ps.ps_envstr = (char *)ucp;
+                       ps.ps_nenvstr = ne;
                }
                if (--na < 0)
                        break;
                (void) suword((caddr_t)ap, ucp);
                do {
                }
                if (--na < 0)
                        break;
                (void) suword((caddr_t)ap, ucp);
                do {
-                       if (nc % (CLSIZE*NBPG) == 0) {
-                               if (bp)
-                                       brelse(bp);
-                               bp = bread(argdev, bno + ctod(nc / NBPG),
-                                   CLSIZE*NBPG);
-                               bp->b_flags |= B_AGE;           /* throw away */
-                               bp->b_flags &= ~B_DELWRI;       /* cancel io */
-                               cp = bp->b_un.b_addr;
-                       }
-                       (void) subyte((caddr_t)ucp++, (c = *cp++));
-                       nc++;
-               } while(c&0377);
+                       error = copyoutstr(cp, (caddr_t)ucp, (unsigned)cc,
+                           &len);
+                       ucp += len;
+                       cp += len;
+                       nc += len;
+                       cc -= len;
+               } while (error == ENAMETOOLONG);
+               if (error == EFAULT)
+                       panic("exec: EFAULT");
        }
        (void) suword((caddr_t)ap, 0);
        }
        (void) suword((caddr_t)ap, 0);
-       setregs();
+       (void) copyout((caddr_t)&ps, (caddr_t)PS_STRINGS, sizeof(ps));
+
+       execsigs(p);
+
+       for (nc = fdp->fd_lastfile; nc >= 0; --nc) {
+               if (fdp->fd_ofileflags[nc] & UF_EXCLOSE) {
+                       (void) closef(fdp->fd_ofiles[nc], p);
+                       fdp->fd_ofiles[nc] = NULL;
+                       fdp->fd_ofileflags[nc] = 0;
+                       if (nc < fdp->fd_freefile)
+                               fdp->fd_freefile = nc;
+               }
+               fdp->fd_ofileflags[nc] &= ~UF_MAPPED;
+       }
+       /*
+        * Adjust fd_lastfile to account for descriptors closed above.
+        * Don't decrement fd_lastfile past 0, as it's unsigned.
+        */
+       while (fdp->fd_lastfile > 0 && fdp->fd_ofiles[fdp->fd_lastfile] == NULL)
+               fdp->fd_lastfile--;
+       setregs(p, exdata.ex_exec.a_entry, retval);
+#ifdef COPY_SIGCODE
+       /*
+        * Install sigcode at top of user stack.
+        */
+       copyout((caddr_t)sigcode, (caddr_t)PS_STRINGS - szsigcode, szsigcode);
+#endif
+       /*
+        * Remember file name for accounting.
+        */
+       p->p_acflag &= ~AFORK;
+       if (nd.ni_cnd.cn_namelen > MAXCOMLEN)
+               nd.ni_cnd.cn_namelen = MAXCOMLEN;
+       bcopy((caddr_t)nd.ni_cnd.cn_nameptr, (caddr_t)p->p_comm,
+           (unsigned)nd.ni_cnd.cn_namelen);
+       p->p_comm[nd.ni_cnd.cn_namelen] = '\0';
+       cpu_exec(p);
 bad:
 bad:
-       if (bp)
-               brelse(bp);
-       if (bno)
-               rmfree(argmap, (long)ctod(clrnd((int) btoc(NCARGS))), bno);
-       iput(ip);
+       FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
+       if (execargs)
+               kmem_free_wakeup(exec_map, execargs, NCARGS);
+#endif SECSIZE
+       if (vp)
+               vput(vp);
+       return (error);
 }
 
 /*
  * Read in and set up memory for executed file.
  */
 }
 
 /*
  * Read in and set up memory for executed file.
  */
-getxfile(ip, nargc, uid, gid)
-       register struct inode *ip;
-       int nargc, uid, gid;
+getxfile(p, vp, ep, paged, ssize, uid, gid)
+       register struct proc *p;
+       register struct vnode *vp;
+       register struct exec *ep;
+       int paged, ssize, uid, gid;
 {
 {
-       register size_t ts, ds, ss;
-       int pagi;
+       register struct ucred *cred = p->p_ucred;
+       register struct vmspace *vm = p->p_vmspace;
+       vm_offset_t addr;
+       vm_size_t xts, size;
+       segsz_t ds;
+       off_t toff;
+       int error = 0;
 
 
-       if (u.u_exdata.ux_mag == 0413)
-               pagi = SPAGI;
+#ifdef HPUXCOMPAT
+       int hpux = (paged & SHPUX);
+       paged &= ~SHPUX;
+       if (ep->a_mid == MID_HPUX)
+               toff = paged ? CLBYTES : sizeof(struct hpux_exec);
        else
        else
-               pagi = 0;
-       if (u.u_exdata.ux_tsize!=0 && (ip->i_flag&ITEXT)==0 &&
-           ip->i_count!=1) {
-               register struct file *fp;
-
-               for (fp = file; fp < fileNFILE; fp++) {
-                       if (fp->f_type == DTYPE_INODE &&
-                           fp->f_count > 0 &&
-                           (struct inode *)fp->f_data == ip &&
-                           (fp->f_flag&FWRITE)) {
-                               u.u_error = ETXTBSY;
-                               goto bad;
-                       }
-               }
-       }
+#endif
+#ifdef COFF
+       toff = N_TXTOFF(*ep);
+#else
+#ifdef sparc
+       if (ep->a_mid == MID_SUN_SPARC)
+               toff = paged ? 0 : sizeof(struct exec);
+       else
+#endif
+       if (paged)
+               toff = CLBYTES;
+       else
+               toff = sizeof (struct exec);
+#endif
+       if (ep->a_text != 0 && (vp->v_flag & VTEXT) == 0 &&
+           vp->v_writecount != 0)
+               return (ETXTBSY);
 
        /*
         * Compute text and data sizes and make sure not too large.
 
        /*
         * Compute text and data sizes and make sure not too large.
+        * Text size is rounded to an ``ld page''; data+bss is left
+        * in machine pages.  Check data and bss separately as they
+        * may overflow when summed together.  (XXX not done yet)
         */
         */
-       ts = clrnd(btoc(u.u_exdata.ux_tsize));
-       ds = clrnd(btoc((u.u_exdata.ux_dsize+u.u_exdata.ux_bsize)));
-       ss = clrnd(SSIZE + btoc(nargc));
-       if (chksize((unsigned)ts, (unsigned)ds, (unsigned)ss))
-               goto bad;
+       xts = roundup(ep->a_text, __LDPGSZ);
+       ds = clrnd(btoc(ep->a_data + ep->a_bss));
 
        /*
 
        /*
-        * Make sure enough space to start process.
+        * If we're sharing the address space, allocate a new space
+        * and release our reference to the old one.  Otherwise,
+        * empty out the existing vmspace.
         */
         */
-       u.u_cdmap = zdmap;
-       u.u_csmap = zdmap;
-       if (swpexpand(ds, ss, &u.u_cdmap, &u.u_csmap) == NULL)
-               goto bad;
-
+#ifdef sparc
+       kill_user_windows(p);           /* before addrs go away */
+#endif
+       if (vm->vm_refcnt > 1) {
+               p->p_vmspace = vmspace_alloc(VM_MIN_ADDRESS,
+                   VM_MAXUSER_ADDRESS, 1);
+               vmspace_free(vm);
+               vm = p->p_vmspace;
+       } else {
+#ifdef SYSVSHM
+               if (vm->vm_shm)
+                       shmexit(p);
+#endif
+               (void) vm_map_remove(&vm->vm_map, VM_MIN_ADDRESS,
+                   VM_MAXUSER_ADDRESS);
+       }
        /*
        /*
-        * At this point, committed to the new image!
-        * Release virtual memory resources of old process, and
-        * initialize the virtual memory of the new process.
-        * If we resulted from vfork(), instead wakeup our
-        * parent who will set SVFDONE when he has taken back
-        * our resources.
+        * If parent is waiting for us to exec or exit,
+        * SPPWAIT will be set; clear it and wakeup parent.
         */
         */
-       if ((u.u_procp->p_flag & SVFORK) == 0)
-               vrelvm();
-       else {
-               u.u_procp->p_flag &= ~SVFORK;
-               u.u_procp->p_flag |= SKEEP;
-               wakeup((caddr_t)u.u_procp);
-               while ((u.u_procp->p_flag & SVFDONE) == 0)
-                       sleep((caddr_t)u.u_procp, PZERO - 1);
-               u.u_procp->p_flag &= ~(SVFDONE|SKEEP);
+       if (p->p_flag & SPPWAIT) {
+               p->p_flag &= ~SPPWAIT;
+               wakeup((caddr_t) p->p_pptr);
        }
        }
-       u.u_procp->p_flag &= ~(SPAGI|SSEQL|SUANOM|SNUSIG);
-       u.u_procp->p_flag |= pagi;
-       u.u_dmap = u.u_cdmap;
-       u.u_smap = u.u_csmap;
-       vgetvm(ts, ds, ss);
-
-       if (pagi == 0)
-               u.u_error =
-                   rdwri(UIO_READ, ip,
-                       (char *)ctob(dptov(u.u_procp, 0)),
-                       (int)u.u_exdata.ux_dsize,
-                       (int)(sizeof(u.u_exdata)+u.u_exdata.ux_tsize),
-                       0, (int *)0);
-       xalloc(ip, pagi);
-       if (pagi && u.u_procp->p_textp)
-               vinifod((struct fpte *)dptopte(u.u_procp, 0),
-                   PG_FTEXT, u.u_procp->p_textp->x_iptr,
-                   (long)(1 + ts/CLSIZE), (int)btoc(u.u_exdata.ux_dsize));
-
-#ifdef vax
-       /* THIS SHOULD BE DONE AT A LOWER LEVEL, IF AT ALL */
-#include "../vax/mtpr.h"               /* XXX */
-       mtpr(TBIA, 0);
+#ifdef HPUXCOMPAT
+       p->p_addr->u_pcb.pcb_flags &= ~(PCB_HPUXMMAP|PCB_HPUXBIN);
+       /* remember that we were loaded from an HPUX format file */
+       if (ep->a_mid == MID_HPUX)
+               p->p_addr->u_pcb.pcb_flags |= PCB_HPUXBIN;
+       if (hpux)
+               p->p_flag |= SHPUX;
+       else
+               p->p_flag &= ~SHPUX;
 #endif
 #endif
-
-       if (u.u_error)
-               swkill(u.u_procp, "i/o error mapping pages");
+#ifdef ULTRIXCOMPAT
        /*
        /*
-        * set SUID/SGID protections, if no tracing
+        * Always start out as an ULTRIX process.
+        * A system call in crt0.o will change us to BSD system calls later.
         */
         */
-       if ((u.u_procp->p_flag&STRC)==0) {
-               u.u_uid = uid;
-               u.u_procp->p_uid = uid;
-               u.u_gid = gid;
-       } else
-               psignal(u.u_procp, SIGTRAP);
-       u.u_tsize = ts;
-       u.u_dsize = ds;
-       u.u_ssize = ss;
-bad:
-       return;
-}
-
-/*
- * Clear registers on exec
- */
-setregs()
-{
-       register int (**rp)();
-       register int i, sigmask;
-
-       for (rp = &u.u_signal[1], sigmask = 1; rp < &u.u_signal[NSIG];
-           sigmask <<= 1, rp++) {
-               switch (*rp) {
-
-               case SIG_IGN:
-               case SIG_DFL:
-               case SIG_HOLD:
-                       continue;
-
-               default:
-                       /*
-                        * Normal or deferring catch; revert to default.
-                        */
-                       (void) spl6();
-                       *rp = SIG_DFL;
-                       if ((int)*rp & 1)
-                               u.u_procp->p_siga0 |= sigmask;
-                       else
-                               u.u_procp->p_siga0 &= ~sigmask;
-                       if ((int)*rp & 2)
-                               u.u_procp->p_siga1 |= sigmask;
-                       else
-                               u.u_procp->p_siga1 &= ~sigmask;
-                       (void) spl0();
-                       continue;
-               }
-       }
-#ifdef vax
-/*
-       for (rp = &u.u_ar0[0]; rp < &u.u_ar0[16];)
-               *rp++ = 0;
-*/
-       u.u_ar0[PC] = u.u_exdata.ux_entloc+2;
+       p->p_md.md_flags |= MDP_ULTRIX;
 #endif
 #endif
-#ifdef sun
-       { register struct regs *r = (struct regs *)u.u_ar0;
-         for (i = 0; i < 8; i++) {
-               r->r_dreg[i] = 0;
-               if (&r->r_areg[i] != &r->r_sp)
-                       r->r_areg[i] = 0;
-         }
-         r->r_sr = PSL_USERSET;
-         r->r_pc = u.u_exdata.ux_entloc;
+       p->p_flag |= SEXEC;
+#ifndef COFF
+       addr = VM_MIN_ADDRESS;
+       if (vm_allocate(&vm->vm_map, &addr, xts + ctob(ds), FALSE)) {
+               uprintf("Cannot allocate text+data space\n");
+               error = ENOMEM;                 /* XXX */
+               goto badmap;
        }
        }
+       vm->vm_taddr = (caddr_t)VM_MIN_ADDRESS;
+       vm->vm_daddr = (caddr_t)(VM_MIN_ADDRESS + xts);
+#else /* COFF */
+       addr = (vm_offset_t)ep->ex_aout.codeStart;
+       vm->vm_taddr = (caddr_t)addr;
+       if (vm_allocate(&vm->vm_map, &addr, xts, FALSE)) {
+               uprintf("Cannot allocate text space\n");
+               error = ENOMEM;                 /* XXX */
+               goto badmap;
+       }
+       addr = (vm_offset_t)ep->ex_aout.heapStart;
+       vm->vm_daddr = (caddr_t)addr;
+       if (vm_allocate(&vm->vm_map, &addr, round_page(ctob(ds)), FALSE)) {
+               uprintf("Cannot allocate data space\n");
+               error = ENOMEM;                 /* XXX */
+               goto badmap;
+       }
+#endif /* COFF */
+       size = round_page(MAXSSIZ);             /* XXX */
+#ifdef i386
+       addr = trunc_page(USRSTACK - size) - NBPG;      /* XXX */
+#else
+       addr = trunc_page(USRSTACK - size);
 #endif
 #endif
-       for (i=0; i<NOFILE; i++) {
-               if (u.u_pofile[i]&UF_EXCLOSE) {
-                       closef(u.u_ofile[i], u.u_pofile[i]);
-                       u.u_ofile[i] = NULL;
-                       u.u_pofile[i] = 0;
+       if (vm_allocate(&vm->vm_map, &addr, size, FALSE)) {
+               uprintf("Cannot allocate stack space\n");
+               error = ENOMEM;                 /* XXX */
+               goto badmap;
+       }
+       size -= round_page(p->p_rlimit[RLIMIT_STACK].rlim_cur);
+       if (vm_map_protect(&vm->vm_map, addr, addr+size, VM_PROT_NONE, FALSE)) {
+               uprintf("Cannot protect stack space\n");
+               error = ENOMEM;
+               goto badmap;
+       }
+       vm->vm_maxsaddr = (caddr_t)addr;
+
+       if (paged == 0) {
+               /*
+                * Read in data segment.
+                */
+               (void) vn_rdwr(UIO_READ, vp, vm->vm_daddr, (int) ep->a_data,
+                       (off_t)(toff + ep->a_text), UIO_USERSPACE,
+                       (IO_UNIT|IO_NODELOCKED), cred, (int *)0, p);
+               /*
+                * Read in text segment if necessary (0410),
+                * and read-protect it.
+                */
+               if (ep->a_text > 0) {
+                       error = vn_rdwr(UIO_READ, vp, vm->vm_taddr,
+                           (int)ep->a_text, toff, UIO_USERSPACE,
+                           (IO_UNIT|IO_NODELOCKED), cred, (int *)0, p);
+                       (void) vm_map_protect(&vm->vm_map,
+                           (vm_offset_t)vm->vm_taddr,
+                           (vm_offset_t)vm->vm_taddr + trunc_page(ep->a_text),
+                           VM_PROT_READ|VM_PROT_EXECUTE, FALSE);
                }
                }
-               u.u_pofile[i] &= ~UF_MAPPED;
+       } else {
+               /*
+                * Allocate a region backed by the exec'ed vnode.
+                */
+#ifndef COFF
+               addr = VM_MIN_ADDRESS;
+               size = round_page(xts + ep->a_data);
+               error = vm_mmap(&vm->vm_map, &addr, size, VM_PROT_ALL,
+                       MAP_FILE|MAP_COPY|MAP_FIXED,
+                       (caddr_t)vp, (vm_offset_t)toff);
+               (void) vm_map_protect(&vm->vm_map, addr, addr + xts,
+                       VM_PROT_READ|VM_PROT_EXECUTE, FALSE);
+#else /* COFF */
+               addr = (vm_offset_t)vm->vm_taddr;
+               size = xts;
+               error = vm_mmap(&vm->vm_map, &addr, size,
+                       VM_PROT_READ|VM_PROT_EXECUTE,
+                       MAP_FILE|MAP_COPY|MAP_FIXED,
+                       (caddr_t)vp, (vm_offset_t)toff);
+               toff += size;
+               addr = (vm_offset_t)vm->vm_daddr;
+               size = round_page(ep->a_data);
+               error = vm_mmap(&vm->vm_map, &addr, size, VM_PROT_ALL,
+                       MAP_FILE|MAP_COPY|MAP_FIXED,
+                       (caddr_t)vp, (vm_offset_t)toff);
+#endif /* COFF */
+               vp->v_flag |= VTEXT;
+       }
+       if (error) {
+badmap:
+               printf("pid %d: VM allocation failure\n", p->p_pid);
+               uprintf("sorry, pid %d was killed in exec: VM allocation\n",
+                       p->p_pid);
+               psignal(p, SIGKILL);
+               p->p_flag |= SKEEP;
+               return(error);
        }
 
        /*
        }
 
        /*
-        * Remember file name for accounting.
+        * set SUID/SGID protections, if no tracing
         */
         */
-       u.u_acflag &= ~AFORK;
-       bcopy((caddr_t)u.u_dent.d_name, (caddr_t)u.u_comm,
-           (unsigned)(u.u_dent.d_namlen + 1));
-#ifdef sun
-       u.u_eosys = REALLYRETURN;
+       if ((p->p_flag&STRC)==0) {
+               if (uid != cred->cr_uid || gid != cred->cr_gid) {
+                       p->p_ucred = cred = crcopy(cred);
+                       /*
+                        * If process is being ktraced, turn off - unless
+                        * root set it.
+                        */
+                       if (p->p_tracep && !(p->p_traceflag & KTRFAC_ROOT)) {
+                               vrele(p->p_tracep);
+                               p->p_tracep = NULL;
+                               p->p_traceflag = 0;
+                       }
+                       cred->cr_uid = uid;
+                       cred->cr_gid = gid;
+               }
+       } else
+               psignal(p, SIGTRAP);
+       p->p_cred->p_svuid = cred->cr_uid;
+       p->p_cred->p_svgid = cred->cr_gid;
+       vm->vm_tsize = btoc(xts);
+       vm->vm_dsize = ds;
+       vm->vm_ssize = ssize;
+       p->p_stats->p_prof.pr_scale = 0;
+#if defined(tahoe)
+       /* move this when tahoe cpu_exec is created */
+       p->p_addr->u_pcb.pcb_savacc.faddr = (float *)NULL;
 #endif
 #endif
+       return (0);
 }
 }