Berkeley copyright notice
[unix-history] / usr / src / sys / kern / kern_exec.c
index f261fc6..d4499f7 100644 (file)
@@ -1,25 +1,45 @@
-/*     kern_exec.c     4.2     83/06/02        */
+/*
+ * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ *     @(#)kern_exec.c 7.10 (Berkeley) %G%
+ */
 
 
-#include "../machine/reg.h"
-#include "../machine/pte.h"
-#include "../machine/psl.h"
+#include "param.h"
+#include "systm.h"
+#include "map.h"
+#include "user.h"
+#include "kernel.h"
+#include "proc.h"
+#include "mount.h"
+#include "ucred.h"
+#include "malloc.h"
+#include "buf.h"
+#include "vnode.h"
+#include "seg.h"
+#include "vm.h"
+#include "text.h"
+#include "file.h"
+#include "uio.h"
+#include "acct.h"
+#include "exec.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/reg.h"
+#include "machine/pte.h"
+#include "machine/psl.h"
+#include "machine/mtpr.h"
 
 /*
  * exec system call, with and without environments.
 
 /*
  * exec system call, with and without environments.
@@ -41,44 +61,69 @@ execve()
        register nc;
        register char *cp;
        register struct buf *bp;
        register nc;
        register char *cp;
        register struct buf *bp;
+       struct buf *tbp;
        register struct execa *uap;
        register struct execa *uap;
-       int na, ne, ucp, ap, c;
+       int na, ne, ucp, ap, cc;
+       unsigned len;
        int indir, uid, gid;
        char *sharg;
        int indir, uid, gid;
        char *sharg;
-       struct inode *ip;
+       struct vnode *vp;
        swblk_t bno;
        swblk_t bno;
+       struct vattr vattr;
        char cfname[MAXCOMLEN + 1];
        char cfname[MAXCOMLEN + 1];
-       char cfarg[SHSIZE];
-       int resid;
+       char cfarg[MAXINTERP];
+       union {
+               char    ex_shell[MAXINTERP];    /* #! and interpreter name */
+               struct  exec ex_exec;
+       } exdata;
+       register struct nameidata *ndp = &u.u_nd;
+       int resid, error;
+#ifdef SECSIZE
+       extern long argdbsize;                  /* XXX */
+#endif SECSIZE
 
 
-       if ((ip = namei(uchar, LOOKUP, 1)) == NULL)
+       ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
+       ndp->ni_segflg = UIO_USERSPACE;
+       ndp->ni_dirp = ((struct execa *)u.u_ap)->fname;
+       if (u.u_error = namei(ndp)) {
                return;
                return;
+       }
+       vp = ndp->ni_vp;
        bno = 0;
        bp = 0;
        indir = 0;
        uid = u.u_uid;
        gid = u.u_gid;
        bno = 0;
        bp = 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;
+       if (u.u_error = VOP_GETATTR(vp, &vattr, u.u_cred))
+               goto bad;
+       if (vp->v_mount->m_flag & M_NOEXEC) {
+               u.u_error = ENOEXEC;
+               goto bad;
+       }
+       if ((vp->v_mount->m_flag & M_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 (u.u_error = vn_access(vp, VEXEC, u.u_cred))
                goto bad;
                goto bad;
-       if ((u.u_procp->p_flag&STRC) && access(ip, IREAD))
+       if ((u.u_procp->p_flag & STRC) &&
+           (u.u_error = vn_access(vp, VREAD, u.u_cred)))
                goto bad;
                goto bad;
-       if ((ip->i_mode & IFMT) != IFREG ||
-          (ip->i_mode & (IEXEC|(IEXEC>>3)|(IEXEC>>6))) == 0) {
+       if (vp->v_type != VREG ||
+           (vattr.va_mode & (VEXEC|(VEXEC>>3)|(VEXEC>>6))) == 0) {
                u.u_error = EACCES;
                goto bad;
        }
 
        /*
                u.u_error = EACCES;
                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 +133,80 @@ 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);
+       exdata.ex_shell[0] = '\0';      /* for zero length files */
+       u.u_error = vn_rdwr(UIO_READ, vp, (caddr_t)&exdata, sizeof (exdata),
+           (off_t)0, UIO_SYSSPACE, (IO_UNIT|IO_NODELOCKED), u.u_cred, &resid);
        if (u.u_error)
                goto bad;
        if (u.u_error)
                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] != '#') {
+       if (resid > sizeof(exdata) - sizeof(exdata.ex_exec) &&
+           exdata.ex_shell[0] != '#') {
                u.u_error = ENOEXEC;
                goto bad;
        }
 #endif
                u.u_error = ENOEXEC;
                goto bad;
        }
 #endif
-       switch (u.u_exdata.ux_mag) {
+       switch ((int)exdata.ex_exec.a_magic) {
 
 
-       case 0407:
-               u.u_exdata.ux_dsize += u.u_exdata.ux_tsize;
-               u.u_exdata.ux_tsize = 0;
+       case OMAGIC:
+               exdata.ex_exec.a_data += exdata.ex_exec.a_text;
+               exdata.ex_exec.a_text = 0;
                break;
 
                break;
 
-       case 0413:
-       case 0410:
-               if (u.u_exdata.ux_tsize == 0) {
+       case ZMAGIC:
+       case NMAGIC:
+               if (exdata.ex_exec.a_text == 0) {
                        u.u_error = ENOEXEC;
                        goto bad;
                }
                break;
 
        default:
                        u.u_error = ENOEXEC;
                        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) {
                        u.u_error = ENOEXEC;
                        goto bad;
                }
                    indir) {
                        u.u_error = ENOEXEC;
                        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]) {
+                               u.u_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;
+               ndp->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)
+               vput(vp);
+               ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
+               ndp->ni_segflg = UIO_SYSSPACE;
+               if (u.u_error = namei(ndp))
                        return;
                        return;
+               vp = ndp->ni_vp;
+               if (u.u_error = VOP_GETATTR(vp, &vattr, u.u_cred))
+                       goto bad;
+               bcopy((caddr_t)ndp->ni_dent.d_name, (caddr_t)cfname,
+                   MAXCOMLEN);
+               cfname[MAXCOMLEN] = '\0';
+               uid = u.u_uid;          /* shell scripts can't be setuid */
+               gid = u.u_gid;
                goto again;
        }
 
                goto again;
        }
 
@@ -172,71 +216,104 @@ execve()
        na = 0;
        ne = 0;
        nc = 0;
        na = 0;
        ne = 0;
        nc = 0;
+       cc = 0;
        uap = (struct execa *)u.u_ap;
        uap = (struct execa *)u.u_ap;
-       if ((bno = rmalloc(argmap, (long)ctod(clrnd((int)btoc(NCARGS))))) == 0) {
-               swkill(u.u_procp, "exece");
+#ifdef SECSIZE
+       bno = rmalloc(argmap, (clrnd((int)btoc(NCARGS))) * CLBYTES / argdbsize);
+#else SECSIZE
+       bno = rmalloc(argmap, (long)ctod(clrnd((int)btoc(NCARGS))));
+#endif SECSIZE
+       if (bno == 0) {
+               swkill(u.u_procp, "exec: no swap space");
                goto bad;
        }
        if (bno % CLSIZE)
                panic("execa rmalloc");
                goto bad;
        }
        if (bno % CLSIZE)
                panic("execa rmalloc");
+       /*
+        * 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 = cfname;
+                       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)
+               if (ap == -1) {
                        u.u_error = EFAULT;
                        u.u_error = EFAULT;
+                       break;
+               }
                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 % (CLSIZE*NBPG) == 0) {
+                       if (cc <= 0) {
+                               /*
+                                * We depend on NCARGS being a multiple of
+                                * CLBYTES.  This way we need only check
+                                * overflow before each buffer allocation.
+                                */
+                               if (nc >= NCARGS-1) {
+                                       error = E2BIG;
+                                       break;
+                               }
                                if (bp)
                                        bdwrite(bp);
                                if (bp)
                                        bdwrite(bp);
-                               bp = getblk(argdev, bno + ctod(nc / NBPG),
-                                   CLSIZE*NBPG);
+                               cc = CLBYTES;
+#ifdef SECSIZE
+                               bp = getblk(argdev, bno + nc / argdbsize, cc,
+                                   argdbsize);
+#else SECSIZE
+                               bp = getblk(argdev_vp, bno + ctod(nc/NBPG), cc);
+#endif SECSIZE
                                cp = bp->b_un.b_addr;
                        }
                                cp = bp->b_un.b_addr;
                        }
-                       nc++;
-                       *cp++ = c;
-               } while (c > 0);
+                       if (sharg) {
+                               error = copystr(sharg, cp, (unsigned)cc, &len);
+                               sharg += len;
+                       } else {
+                               error = copyinstr((caddr_t)ap, cp, (unsigned)cc,
+                                   &len);
+                               ap += len;
+                       }
+                       cp += len;
+                       nc += len;
+                       cc -= len;
+               } while (error == ENOENT);
+               if (error) {
+                       u.u_error = error;
+                       if (bp)
+                               brelse(bp);
+                       bp = 0;
+                       goto badarg;
+               }
        }
        if (bp)
                bdwrite(bp);
        bp = 0;
        nc = (nc + NBPW-1) & ~(NBPW-1);
        }
        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));
-       }
-       getxfile(ip, nc + (na+4)*NBPW, uid, gid);
+       getxfile(vp, &exdata.ex_exec, nc + (na+4)*NBPW, uid, gid, u.u_cred);
        if (u.u_error) {
 badarg:
        if (u.u_error) {
 badarg:
-               for (c = 0; c < nc; c += CLSIZE*NBPG) {
-                       bp = baddr(argdev, bno + ctod(c / NBPG), CLSIZE*NBPG);
+               for (cc = 0; cc < nc; cc += CLBYTES) {
+                       u.u_error = baddr(argdev_vp, bno + ctod(cc/NBPG),
+                               CLBYTES, &tbp);
+                       bp = tbp;
+#endif SECSIZE
                        if (bp) {
                                bp->b_flags |= B_AGE;           /* throw away */
                                bp->b_flags &= ~B_DELWRI;       /* cancel io */
                        if (bp) {
                                bp->b_flags |= B_AGE;           /* throw away */
                                bp->b_flags &= ~B_DELWRI;       /* cancel io */
@@ -246,18 +323,21 @@ badarg:
                }
                goto bad;
        }
                }
                goto bad;
        }
+       vput(vp);
+       vp = NULL;
 
        /*
 
        /*
-        * copy back arglist
+        * Copy back arglist.
         */
        ucp = USRSTACK - nc - NBPW;
        ap = ucp - na*NBPW - 3*NBPW;
        u.u_ar0[SP] = ap;
        (void) suword((caddr_t)ap, na-ne);
        nc = 0;
         */
        ucp = USRSTACK - nc - NBPW;
        ap = ucp - na*NBPW - 3*NBPW;
        u.u_ar0[SP] = ap;
        (void) suword((caddr_t)ap, na-ne);
        nc = 0;
+       cc = 0;
        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;
                }
@@ -265,52 +345,117 @@ badarg:
                        break;
                (void) suword((caddr_t)ap, ucp);
                do {
                        break;
                (void) suword((caddr_t)ap, ucp);
                do {
-                       if (nc % (CLSIZE*NBPG) == 0) {
+                       if (cc <= 0) {
                                if (bp)
                                        brelse(bp);
                                if (bp)
                                        brelse(bp);
-                               bp = bread(argdev, bno + ctod(nc / NBPG),
-                                   CLSIZE*NBPG);
+                               cc = CLBYTES;
+#ifdef SECSIZE
+                               bp = bread(argdev, bno + nc / argdbsize, cc,
+                                   argdbsize);
+#else SECSIZE
+                               error = bread(argdev_vp,
+                                   (daddr_t)(bno + ctod(nc / NBPG)), cc, &tbp);
+                               bp = tbp;
+#endif SECSIZE
                                bp->b_flags |= B_AGE;           /* throw away */
                                bp->b_flags &= ~B_DELWRI;       /* cancel io */
                                cp = bp->b_un.b_addr;
                        }
                                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 == ENOENT);
+               if (error == EFAULT)
+                       panic("exec: EFAULT");
        }
        (void) suword((caddr_t)ap, 0);
        }
        (void) suword((caddr_t)ap, 0);
-       setregs();
+
+       /*
+        * Reset caught signals.  Held signals
+        * remain held through p_sigmask.
+        */
+       while (u.u_procp->p_sigcatch) {
+               nc = ffs((long)u.u_procp->p_sigcatch);
+               u.u_procp->p_sigcatch &= ~sigmask(nc);
+               u.u_signal[nc] = SIG_DFL;
+       }
+       /*
+        * Reset stack state to the user stack.
+        * Clear set of signals caught on the signal stack.
+        */
+       u.u_onstack = 0;
+       u.u_sigsp = 0;
+       u.u_sigonstack = 0;
+
+       for (nc = u.u_lastfile; nc >= 0; --nc) {
+               if (u.u_pofile[nc] & UF_EXCLOSE) {
+                       closef(u.u_ofile[nc]);
+                       u.u_ofile[nc] = NULL;
+                       u.u_pofile[nc] = 0;
+               }
+               u.u_pofile[nc] &= ~UF_MAPPED;
+       }
+       while (u.u_lastfile >= 0 && u.u_ofile[u.u_lastfile] == NULL)
+               u.u_lastfile--;
+       setregs(exdata.ex_exec.a_entry);
+       /*
+        * Remember file name for accounting.
+        */
+       u.u_acflag &= ~AFORK;
+       if (indir)
+               bcopy((caddr_t)cfname, (caddr_t)u.u_comm, MAXCOMLEN);
+       else {
+               if (ndp->ni_dent.d_namlen > MAXCOMLEN)
+                       ndp->ni_dent.d_namlen = MAXCOMLEN;
+               bcopy((caddr_t)ndp->ni_dent.d_name, (caddr_t)u.u_comm,
+                   (unsigned)(ndp->ni_dent.d_namlen + 1));
+       }
 bad:
        if (bp)
                brelse(bp);
        if (bno)
 bad:
        if (bp)
                brelse(bp);
        if (bno)
+#ifdef SECSIZE
+               rmfree(argmap, (clrnd((int)btoc(NCARGS))) * CLBYTES / argdbsize,
+                   bno);
+#else SECSIZE
                rmfree(argmap, (long)ctod(clrnd((int) btoc(NCARGS))), bno);
                rmfree(argmap, (long)ctod(clrnd((int) btoc(NCARGS))), bno);
-       iput(ip);
+#endif SECSIZE
+       if (vp)
+               vput(vp);
 }
 
 /*
  * 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;
+getxfile(vp, ep, nargc, uid, gid, cred)
+       register struct vnode *vp;
+       register struct exec *ep;
        int nargc, uid, gid;
        int nargc, uid, gid;
+       struct ucred *cred;
 {
 {
-       register size_t ts, ds, ss;
+       size_t ts, ds, ids, uds, ss;
        int pagi;
 
        int pagi;
 
-       if (u.u_exdata.ux_mag == 0413)
-               pagi = SPAGI;
+       if (ep->a_magic == ZMAGIC)
+               pagi = SPAGV;
        else
                pagi = 0;
        else
                pagi = 0;
-       if (u.u_exdata.ux_tsize!=0 && (ip->i_flag&ITEXT)==0 &&
-           ip->i_count!=1) {
+       if (vp->v_text && (vp->v_text->x_flag & XTRC)) {
+               u.u_error = ETXTBSY;
+               goto bad;
+       }
+       if (ep->a_text != 0 && (vp->v_flag & VTEXT) == 0 &&
+           vp->v_count != 1) {
                register struct file *fp;
 
                for (fp = file; fp < fileNFILE; fp++) {
                register struct file *fp;
 
                for (fp = file; fp < fileNFILE; fp++) {
-                       if (fp->f_type == DTYPE_INODE &&
+                       if (fp->f_type == DTYPE_VNODE &&
                            fp->f_count > 0 &&
                            fp->f_count > 0 &&
-                           (struct inode *)fp->f_data == ip &&
-                           (fp->f_flag&FWRITE)) {
+                           (struct vnode *)fp->f_data == vp &&
+                           (fp->f_flag & FWRITE)) {
                                u.u_error = ETXTBSY;
                                goto bad;
                        }
                                u.u_error = ETXTBSY;
                                goto bad;
                        }
@@ -319,11 +464,15 @@ getxfile(ip, nargc, uid, gid)
 
        /*
         * Compute text and data sizes and make sure not too large.
 
        /*
         * Compute text and data sizes and make sure not too large.
+        * NB - Check data and bss separately as they may overflow 
+        * when summed together.
         */
         */
-       ts = clrnd(btoc(u.u_exdata.ux_tsize));
-       ds = clrnd(btoc((u.u_exdata.ux_dsize+u.u_exdata.ux_bsize)));
+       ts = clrnd(btoc(ep->a_text));
+       ids = clrnd(btoc(ep->a_data));
+       uds = clrnd(btoc(ep->a_bss));
+       ds = clrnd(btoc(ep->a_data + ep->a_bss));
        ss = clrnd(SSIZE + btoc(nargc));
        ss = clrnd(SSIZE + btoc(nargc));
-       if (chksize((unsigned)ts, (unsigned)ds, (unsigned)ss))
+       if (chksize((unsigned)ts, (unsigned)ids, (unsigned)uds, (unsigned)ss))
                goto bad;
 
        /*
                goto bad;
 
        /*
@@ -335,7 +484,7 @@ getxfile(ip, nargc, uid, gid)
                goto bad;
 
        /*
                goto bad;
 
        /*
-        * At this point, committed to the new image!
+        * At this point, we are 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
         * Release virtual memory resources of old process, and
         * initialize the virtual memory of the new process.
         * If we resulted from vfork(), instead wakeup our
@@ -352,37 +501,50 @@ getxfile(ip, nargc, uid, gid)
                        sleep((caddr_t)u.u_procp, PZERO - 1);
                u.u_procp->p_flag &= ~(SVFDONE|SKEEP);
        }
                        sleep((caddr_t)u.u_procp, PZERO - 1);
                u.u_procp->p_flag &= ~(SVFDONE|SKEEP);
        }
-       u.u_procp->p_flag &= ~(SPAGI|SSEQL|SUANOM|SOUSIG);
-       u.u_procp->p_flag |= pagi;
+       u.u_procp->p_flag &= ~(SPAGV|SSEQL|SUANOM|SOUSIG);
+       u.u_procp->p_flag |= pagi | SEXEC;
        u.u_dmap = u.u_cdmap;
        u.u_smap = u.u_csmap;
        vgetvm(ts, ds, ss);
 
        if (pagi == 0)
        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,
+               u.u_error = vn_rdwr(UIO_READ, vp,
                        (char *)ctob(dptov(u.u_procp, 0)),
                        (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);
+                       (int)ep->a_data,
+                       (off_t)(sizeof (struct exec) + ep->a_text),
+                       UIO_USERSPACE, (IO_UNIT|IO_NODELOCKED), cred, (int *)0);
+       xalloc(vp, ep, pagi, cred);
+#if defined(tahoe)
+       /*
+        * Define new keys.
+        */
+       if (u.u_procp->p_textp == 0) {  /* use existing code key if shared */
+               ckeyrelease(u.u_procp->p_ckey);
+               u.u_procp->p_ckey = getcodekey();
+       }
+       mtpr(CCK, u.u_procp->p_ckey);
+       dkeyrelease(u.u_procp->p_dkey);
+       u.u_procp->p_dkey = getdatakey();
+       mtpr(DCK, u.u_procp->p_dkey);
+#endif
        if (pagi && u.u_procp->p_textp)
                vinifod((struct fpte *)dptopte(u.u_procp, 0),
        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));
+                   PG_FTEXT, u.u_procp->p_textp->x_vptr,
+                   (long)(1 + ts/CLSIZE), (size_t)btoc(ep->a_data));
 
 
-#ifdef vax
+#if defined(vax) || defined(tahoe)
        /* THIS SHOULD BE DONE AT A LOWER LEVEL, IF AT ALL */
        /* THIS SHOULD BE DONE AT A LOWER LEVEL, IF AT ALL */
-#include "../vax/mtpr.h"               /* XXX */
        mtpr(TBIA, 0);
 #endif
 
        if (u.u_error)
        mtpr(TBIA, 0);
 #endif
 
        if (u.u_error)
-               swkill(u.u_procp, "i/o error mapping pages");
+               swkill(u.u_procp, "exec: I/O error mapping pages");
        /*
         * set SUID/SGID protections, if no tracing
         */
        if ((u.u_procp->p_flag&STRC)==0) {
        /*
         * set SUID/SGID protections, if no tracing
         */
        if ((u.u_procp->p_flag&STRC)==0) {
+               if (uid != u.u_uid || gid != u.u_gid)
+                       u.u_cred = crcopy(u.u_cred);
                u.u_uid = uid;
                u.u_procp->p_uid = uid;
                u.u_gid = gid;
                u.u_uid = uid;
                u.u_procp->p_uid = uid;
                u.u_gid = gid;
@@ -391,62 +553,10 @@ getxfile(ip, nargc, uid, gid)
        u.u_tsize = ts;
        u.u_dsize = ds;
        u.u_ssize = ss;
        u.u_tsize = ts;
        u.u_dsize = ds;
        u.u_ssize = ss;
+       u.u_prof.pr_scale = 0;
+#if defined(tahoe)
+       u.u_pcb.pcb_savacc.faddr = (float *)NULL;
+#endif
 bad:
        return;
 }
 bad:
        return;
 }
-
-/*
- * Clear registers on exec
- */
-setregs()
-{
-       register int (**rp)();
-       register int i, sigmask;
-       register struct proc *p = u.u_procp;
-
-       rp = &u.u_signal[1];
-       for (sigmask = 1; rp < &u.u_signal[NSIG]; sigmask <<= 1, rp++)
-               /* disallow masked signals to carry over? */
-               if (p->p_sigcatch & sigmask && (p->p_sigmask & sigmask) == 0) {
-                       (void) spl6();
-                       p->p_sigcatch &= ~sigmask;
-                       *rp = SIG_DFL;
-                       (void) spl0();
-               }
-#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;
-#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;
-       }
-#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;
-               }
-               u.u_pofile[i] &= ~UF_MAPPED;
-       }
-
-       /*
-        * Remember file name for accounting.
-        */
-       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;
-#endif
-}