setgroups check int > NGROUPS, so negative would fail; minor cleanup
[unix-history] / usr / src / sys / kern / kern_exec.c
index bb9ed6a..175c7c5 100644 (file)
@@ -1,24 +1,23 @@
 /*
 /*
- * Copyright (c) 1982 Regents of the University of California.
- * All rights reserved.  The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+ * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
+ * All rights reserved.
  *
  *
- *     @(#)kern_exec.c 6.17 (Berkeley) %G%
+ * %sccs.include.redist.c%
+ *
+ *     @(#)kern_exec.c 7.30 (Berkeley) %G%
  */
 
  */
 
-#include "../machine/reg.h"
-#include "../machine/pte.h"
-#include "../machine/psl.h"
-
 #include "param.h"
 #include "systm.h"
 #include "map.h"
 #include "param.h"
 #include "systm.h"
 #include "map.h"
-#include "dir.h"
 #include "user.h"
 #include "kernel.h"
 #include "proc.h"
 #include "user.h"
 #include "kernel.h"
 #include "proc.h"
+#include "mount.h"
+#include "ucred.h"
+#include "malloc.h"
 #include "buf.h"
 #include "buf.h"
-#include "inode.h"
+#include "vnode.h"
 #include "seg.h"
 #include "vm.h"
 #include "text.h"
 #include "seg.h"
 #include "vm.h"
 #include "text.h"
 #include "acct.h"
 #include "exec.h"
 
 #include "acct.h"
 #include "exec.h"
 
-#ifdef vax
-#include "../vax/mtpr.h"
+#include "machine/reg.h"
+#include "machine/pte.h"
+#include "machine/psl.h"
+#include "machine/mtpr.h"
+
+#ifdef HPUXCOMPAT
+#include "../hpux/hpux_exec.h"
 #endif
 
 /*
  * exec system call, with and without environments.
  */
 #endif
 
 /*
  * exec system call, with and without environments.
  */
-struct execa {
-       char    *fname;
-       char    **argp;
-       char    **envp;
-};
-
-execv()
+execv(p, uap, retval)
+       struct proc *p;
+       struct args {
+               char    *fname;
+               char    **argp;
+               char    **envp;
+       } *uap;
+       int *retval;
 {
 {
-       ((struct execa *)u.u_ap)->envp = NULL;
-       execve();
+
+       uap->envp = NULL;
+       return (execve(p, uap, retval));
 }
 
 }
 
-execve()
+/* ARGSUSED */
+execve(p, uap, retval)
+       register struct proc *p;
+       register struct args {
+               char    *fname;
+               char    **argp;
+               char    **envp;
+       } *uap;
+       int *retval;
 {
        register nc;
        register char *cp;
        register struct buf *bp;
 {
        register nc;
        register char *cp;
        register struct buf *bp;
-       register struct execa *uap;
+       struct buf *tbp;
        int na, ne, ucp, ap, cc;
        unsigned len;
        int indir, uid, gid;
        char *sharg;
        int na, ne, ucp, ap, cc;
        unsigned len;
        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];
-#define        SHSIZE  32
-       char cfarg[SHSIZE];
+       char cfarg[MAXINTERP];
        union {
        union {
-               char    ex_shell[SHSIZE];       /* #! and name of interpreter */
+               char    ex_shell[MAXINTERP];    /* #! and interpreter name */
                struct  exec ex_exec;
                struct  exec ex_exec;
+#ifdef HPUXCOMPAT
+               struct  hpux_exec ex_hexec;
+#endif
        } exdata;
        } exdata;
+#ifdef HPUXCOMPAT
+       struct hpux_exec hhead;
+#endif
+       register struct ucred *cred = u.u_cred;
        register struct nameidata *ndp = &u.u_nd;
        register struct nameidata *ndp = &u.u_nd;
-       int resid, error;
+       int resid, error, flags = 0;
+#ifdef SECSIZE
+       extern long argdbsize;                  /* XXX */
+#endif SECSIZE
 
 
-       ndp->ni_nameiop = LOOKUP | FOLLOW;
+  start:
+       ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
        ndp->ni_segflg = UIO_USERSPACE;
        ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = ((struct execa *)u.u_ap)->fname;
-       if ((ip = namei(ndp)) == NULL)
-               return;
+       ndp->ni_dirp = uap->fname;
+       if (error = namei(ndp))
+               return (error);
+       vp = ndp->ni_vp;
        bno = 0;
        bp = 0;
        indir = 0;
        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;
+       uid = cred->cr_uid;
+       gid = cred->cr_gid;
+       if (error = VOP_GETATTR(vp, &vattr, cred))
+               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))
                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)))
                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;
        }
 
        /*
         * Read in first few bytes of file for segment sizes, magic number:
                goto bad;
        }
 
        /*
         * Read in first few bytes of file for segment sizes, magic number:
-        *      407 = plain executable
-        *      410 = RO text
-        *      413 = demand paged RO text
+        *      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.
@@ -109,28 +143,93 @@ execve()
         * THE ASCII LINE.
         */
        exdata.ex_shell[0] = '\0';      /* for zero length files */
         * THE ASCII LINE.
         */
        exdata.ex_shell[0] = '\0';      /* for zero length files */
-       u.u_error = rdwri(UIO_READ, ip, (caddr_t)&exdata, sizeof (exdata),
-           (off_t)0, 1, &resid);
-       if (u.u_error)
+       error = vn_rdwr(UIO_READ, vp, (caddr_t)&exdata, sizeof (exdata),
+           (off_t)0, UIO_SYSSPACE, (IO_UNIT|IO_NODELOCKED), cred, &resid);
+       if (error)
                goto bad;
 #ifndef lint
        if (resid > sizeof(exdata) - sizeof(exdata.ex_exec) &&
            exdata.ex_shell[0] != '#') {
                goto bad;
 #ifndef lint
        if (resid > sizeof(exdata) - sizeof(exdata.ex_exec) &&
            exdata.ex_shell[0] != '#') {
-               u.u_error = ENOEXEC;
+               error = ENOEXEC;
                goto bad;
        }
                goto bad;
        }
+#endif
+#if defined(hp300)
+       switch ((int)exdata.ex_exec.a_mid) {
+
+       /*
+        * An ancient hp200 or hp300 binary, shouldn't happen anymore.
+        * Mark as invalid.
+        */
+       case MID_ZERO:
+               exdata.ex_exec.a_magic = 0;
+               break;
+
+       /*
+        * 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)
+                       flags |= SHPUX;
+               /*
+                * 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) {
 
 #endif
        switch ((int)exdata.ex_exec.a_magic) {
 
-       case 0407:
+       case OMAGIC:
                exdata.ex_exec.a_data += exdata.ex_exec.a_text;
                exdata.ex_exec.a_text = 0;
                break;
 
                exdata.ex_exec.a_data += exdata.ex_exec.a_text;
                exdata.ex_exec.a_text = 0;
                break;
 
-       case 0413:
-       case 0410:
+       case ZMAGIC:
+               flags |= SPAGV;
+       case NMAGIC:
                if (exdata.ex_exec.a_text == 0) {
                if (exdata.ex_exec.a_text == 0) {
-                       u.u_error = ENOEXEC;
+                       error = ENOEXEC;
                        goto bad;
                }
                break;
                        goto bad;
                }
                break;
@@ -139,22 +238,20 @@ execve()
                if (exdata.ex_shell[0] != '#' ||
                    exdata.ex_shell[1] != '!' ||
                    indir) {
                if (exdata.ex_shell[0] != '#' ||
                    exdata.ex_shell[1] != '!' ||
                    indir) {
-                       u.u_error = ENOEXEC;
+                       error = ENOEXEC;
                        goto bad;
                }
                        goto bad;
                }
-               cp = &exdata.ex_shell[2];               /* skip "#!" */
-               while (cp < &exdata.ex_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 = &exdata.ex_shell[2];
                while (*cp == ' ')
                }
                cp = &exdata.ex_shell[2];
                while (*cp == ' ')
@@ -168,20 +265,40 @@ execve()
                        while (*cp == ' ')
                                cp++;
                        if (*cp)
                        while (*cp == ' ')
                                cp++;
                        if (*cp)
-                               bcopy((caddr_t)cp, (caddr_t)cfarg, SHSIZE);
+                               bcopy((caddr_t)cp, (caddr_t)cfarg, MAXINTERP);
                }
                indir = 1;
                }
                indir = 1;
-               iput(ip);
-               ndp->ni_nameiop = LOOKUP | FOLLOW;
+               vput(vp);
+               ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
                ndp->ni_segflg = UIO_SYSSPACE;
                ndp->ni_segflg = UIO_SYSSPACE;
-               ip = namei(ndp);
-               if (ip == NULL)
-                       return;
+               if (error = namei(ndp))
+                       return (error);
+               vp = ndp->ni_vp;
+               if (error = VOP_GETATTR(vp, &vattr, cred))
+                       goto bad;
                bcopy((caddr_t)ndp->ni_dent.d_name, (caddr_t)cfname,
                    MAXCOMLEN);
                cfname[MAXCOMLEN] = '\0';
                bcopy((caddr_t)ndp->ni_dent.d_name, (caddr_t)cfname,
                    MAXCOMLEN);
                cfname[MAXCOMLEN] = '\0';
+               uid = cred->cr_uid;     /* shell scripts can't be setuid */
+               gid = cred->cr_gid;
                goto again;
        }
                goto again;
        }
+       /*
+        * If the vnode has been modified since we last used it,
+        * then throw away all its pages and its text table entry.
+        */
+       if (vp->v_text && vp->v_text->x_mtime != vattr.va_mtime.tv_sec) {
+               /*
+                * Try once to release, if it is still busy
+                * take more drastic action.
+                */
+               xrele(vp);
+               if (vp->v_flag & VTEXT) {
+                       vput(vp);
+                       vgone(vp);
+                       goto start;
+               }
+       }
 
        /*
         * Collect arguments on "file" in swap space.
 
        /*
         * Collect arguments on "file" in swap space.
@@ -190,14 +307,21 @@ execve()
        ne = 0;
        nc = 0;
        cc = 0;
        ne = 0;
        nc = 0;
        cc = 0;
-       uap = (struct execa *)u.u_ap;
+#ifdef SECSIZE
+       bno = rmalloc(argmap, (clrnd((int)btoc(NCARGS))) * CLBYTES / argdbsize);
+#else SECSIZE
        bno = rmalloc(argmap, (long)ctod(clrnd((int)btoc(NCARGS))));
        bno = rmalloc(argmap, (long)ctod(clrnd((int)btoc(NCARGS))));
+#endif SECSIZE
        if (bno == 0) {
        if (bno == 0) {
-               swkill(u.u_procp, "exec: no swap space");
+               swkill(p, "exec: no swap space");
                goto bad;
        }
        if (bno % CLSIZE)
                panic("execa rmalloc");
                goto bad;
        }
        if (bno % CLSIZE)
                panic("execa rmalloc");
+#ifdef GENERIC
+       if (rootdev == dumpdev)
+               bno += 4096;
+#endif
        /*
         * Copy arguments into file in argdev area.
         */
        /*
         * Copy arguments into file in argdev area.
         */
@@ -226,14 +350,18 @@ execve()
                        break;
                na++;
                if (ap == -1) {
                        break;
                na++;
                if (ap == -1) {
-                       u.u_error = EFAULT;
-                       break;
+                       error = EFAULT;
+                       if (bp) {
+                               brelse(bp);
+                               bp = 0;
+                       }
+                       goto badarg;
                }
                do {
                        if (cc <= 0) {
                                /*
                                 * We depend on NCARGS being a multiple of
                }
                do {
                        if (cc <= 0) {
                                /*
                                 * We depend on NCARGS being a multiple of
-                                * CLSIZE*NBPG.  This way we need only check
+                                * CLBYTES.  This way we need only check
                                 * overflow before each buffer allocation.
                                 */
                                if (nc >= NCARGS-1) {
                                 * overflow before each buffer allocation.
                                 */
                                if (nc >= NCARGS-1) {
@@ -242,8 +370,13 @@ execve()
                                }
                                if (bp)
                                        bdwrite(bp);
                                }
                                if (bp)
                                        bdwrite(bp);
-                               cc = CLSIZE*NBPG;
-                               bp = getblk(argdev, bno + ctod(nc/NBPG), cc);
+                               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;
                        }
                        if (sharg) {
                                cp = bp->b_un.b_addr;
                        }
                        if (sharg) {
@@ -259,7 +392,6 @@ execve()
                        cc -= len;
                } while (error == ENOENT);
                if (error) {
                        cc -= len;
                } while (error == ENOENT);
                if (error) {
-                       u.u_error = error;
                        if (bp)
                                brelse(bp);
                        bp = 0;
                        if (bp)
                                brelse(bp);
                        bp = 0;
@@ -270,22 +402,37 @@ execve()
                bdwrite(bp);
        bp = 0;
        nc = (nc + NBPW-1) & ~(NBPW-1);
                bdwrite(bp);
        bp = 0;
        nc = (nc + NBPW-1) & ~(NBPW-1);
-       getxfile(ip, &exdata.ex_exec, nc + (na+4)*NBPW, uid, gid);
-       if (u.u_error) {
+       error = getxfile(p, vp, &exdata.ex_exec, flags, nc + (na+4)*NBPW,
+           uid, gid);
+       if (error) {
 badarg:
 badarg:
-               for (cc = 0; cc < nc; cc += CLSIZE*NBPG) {
-                       bp = baddr(argdev, bno + ctod(cc/NBPG), CLSIZE*NBPG);
+               for (cc = 0; cc < nc; cc += CLBYTES) {
+                       (void) baddr(argdev_vp, bno + ctod(cc/NBPG),
+                               CLBYTES, NOCRED, &tbp);
+                       bp = tbp;
+#endif SECSIZE
                        if (bp) {
                        if (bp) {
-                               bp->b_flags |= B_AGE;           /* throw away */
-                               bp->b_flags &= ~B_DELWRI;       /* cancel io */
+                               bp->b_flags |= B_INVAL;         /* throw away */
                                brelse(bp);
                                bp = 0;
                        }
                }
                goto bad;
        }
                                brelse(bp);
                                bp = 0;
                        }
                }
                goto bad;
        }
-       iput(ip);
-       ip = NULL;
+       if (vp->v_text)
+               vp->v_text->x_mtime = vattr.va_mtime.tv_sec;
+       vput(vp);
+       vp = NULL;
+
+#ifdef HPUXCOMPAT
+       /*
+        * 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()
+        */
+       if (u.u_pcb.pcb_flags & PCB_HPUXBIN)
+               bcopy((caddr_t)&hhead,
+                     (caddr_t)u.u_pcb.pcb_exec, sizeof hhead);
+#endif
 
        /*
         * Copy back arglist.
 
        /*
         * Copy back arglist.
@@ -309,10 +456,17 @@ badarg:
                        if (cc <= 0) {
                                if (bp)
                                        brelse(bp);
                        if (cc <= 0) {
                                if (bp)
                                        brelse(bp);
-                               cc = CLSIZE*NBPG;
-                               bp = bread(argdev, bno + ctod(nc / NBPG), cc);
-                               bp->b_flags |= B_AGE;           /* throw away */
-                               bp->b_flags &= ~B_DELWRI;       /* cancel io */
+                               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,
+                                   NOCRED, &tbp);
+                               bp = tbp;
+#endif SECSIZE
+                               bp->b_flags |= B_INVAL;         /* throw away */
                                cp = bp->b_un.b_addr;
                        }
                        error = copyoutstr(cp, (caddr_t)ucp, (unsigned)cc,
                                cp = bp->b_un.b_addr;
                        }
                        error = copyoutstr(cp, (caddr_t)ucp, (unsigned)cc,
@@ -327,26 +481,11 @@ badarg:
        }
        (void) suword((caddr_t)ap, 0);
 
        }
        (void) suword((caddr_t)ap, 0);
 
-       /*
-        * 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;
+       execsigs(p);
 
        for (nc = u.u_lastfile; nc >= 0; --nc) {
                if (u.u_pofile[nc] & UF_EXCLOSE) {
 
        for (nc = u.u_lastfile; nc >= 0; --nc) {
                if (u.u_pofile[nc] & UF_EXCLOSE) {
-                       closef(u.u_ofile[nc]);
+                       (void) closef(u.u_ofile[nc]);
                        u.u_ofile[nc] = NULL;
                        u.u_pofile[nc] = 0;
                }
                        u.u_ofile[nc] = NULL;
                        u.u_pofile[nc] = 0;
                }
@@ -354,58 +493,66 @@ badarg:
        }
        while (u.u_lastfile >= 0 && u.u_ofile[u.u_lastfile] == NULL)
                u.u_lastfile--;
        }
        while (u.u_lastfile >= 0 && u.u_ofile[u.u_lastfile] == NULL)
                u.u_lastfile--;
-       setregs(exdata.ex_exec.a_entry);
+       setregs(exdata.ex_exec.a_entry, retval);
        /*
         * Remember file name for accounting.
         */
        u.u_acflag &= ~AFORK;
        if (indir)
        /*
         * Remember file name for accounting.
         */
        u.u_acflag &= ~AFORK;
        if (indir)
-               bcopy((caddr_t)cfname, (caddr_t)u.u_comm, MAXCOMLEN);
+               bcopy((caddr_t)cfname, (caddr_t)p->p_comm, MAXCOMLEN);
        else {
                if (ndp->ni_dent.d_namlen > MAXCOMLEN)
                        ndp->ni_dent.d_namlen = 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,
+               bcopy((caddr_t)ndp->ni_dent.d_name, (caddr_t)p->p_comm,
                    (unsigned)(ndp->ni_dent.d_namlen + 1));
        }
 bad:
        if (bp)
                brelse(bp);
        if (bno)
                    (unsigned)(ndp->ni_dent.d_namlen + 1));
        }
 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);
-       if (ip)
-               iput(ip);
+#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, ep, nargc, uid, gid)
-       register struct inode *ip;
+getxfile(p, vp, ep, flags, nargc, uid, gid)
+       register struct proc *p;
+       register struct vnode *vp;
        register struct exec *ep;
        register struct exec *ep;
-       int nargc, uid, gid;
+       int flags, nargc, uid, gid;
 {
 {
-       size_t ts, ds, ids, uds, ss;
-       int pagi;
+       segsz_t ts, ds, ids, uds, ss;
+       register struct ucred *cred = u.u_cred;
+       off_t toff;
+       int error;
 
 
-       if (ep->a_magic == 0413)
-               pagi = SPAGI;
+#ifdef HPUXCOMPAT
+       if (ep->a_mid == MID_HPUX)
+               toff = sizeof (struct hpux_exec);
        else
        else
-               pagi = 0;
-       if (ip->i_text && (ip->i_text->x_flag & XTRC)) {
-               u.u_error = ETXTBSY;
-               goto bad;
-       }
-       if (ep->a_text != 0 && (ip->i_flag&ITEXT) == 0 &&
-           ip->i_count != 1) {
+#endif
+       toff = sizeof (struct exec);
+       if (vp->v_text && (vp->v_text->x_flag & XTRC))
+               return (ETXTBSY);
+       if (ep->a_text != 0 && (vp->v_flag & VTEXT) == 0 &&
+           vp->v_usecount != 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)) {
-                               u.u_error = ETXTBSY;
-                               goto bad;
+                           (struct vnode *)fp->f_data == vp &&
+                           (fp->f_flag & FWRITE)) {
+                               return (ETXTBSY);
                        }
                }
        }
                        }
                }
        }
@@ -420,74 +567,109 @@ getxfile(ip, ep, nargc, uid, gid)
        uds = clrnd(btoc(ep->a_bss));
        ds = clrnd(btoc(ep->a_data + ep->a_bss));
        ss = clrnd(SSIZE + btoc(nargc));
        uds = clrnd(btoc(ep->a_bss));
        ds = clrnd(btoc(ep->a_data + ep->a_bss));
        ss = clrnd(SSIZE + btoc(nargc));
-       if (chksize((unsigned)ts, (unsigned)ids, (unsigned)uds, (unsigned)ss))
-               goto bad;
+       if (error =
+           chksize((unsigned)ts, (unsigned)ids, (unsigned)uds, (unsigned)ss))
+               return (error);
 
        /*
         * Make sure enough space to start process.
         */
        u.u_cdmap = zdmap;
        u.u_csmap = zdmap;
 
        /*
         * Make sure enough space to start process.
         */
        u.u_cdmap = zdmap;
        u.u_csmap = zdmap;
-       if (swpexpand(ds, ss, &u.u_cdmap, &u.u_csmap) == NULL)
-               goto bad;
+       if (error = swpexpand(ds, ss, &u.u_cdmap, &u.u_csmap))
+               return (error);
 
        /*
 
        /*
-        * 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
         * parent who will set SVFDONE when he has taken back
         * our resources.
         */
         * 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 ((u.u_procp->p_flag & SVFORK) == 0)
+       if ((p->p_flag & SVFORK) == 0) {
+#ifdef MAPMEM
+               if (u.u_mmap && (error = mmexec(p)))
+                       return (error);
+#endif
                vrelvm();
                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);
+       else {
+               p->p_flag &= ~SVFORK;
+               p->p_flag |= SKEEP;
+               wakeup((caddr_t)p);
+               while ((p->p_flag & SVFDONE) == 0)
+                       sleep((caddr_t)p, PZERO - 1);
+               p->p_flag &= ~(SVFDONE|SKEEP);
        }
        }
-       u.u_procp->p_flag &= ~(SPAGI|SSEQL|SUANOM|SOUSIG);
-       u.u_procp->p_flag |= pagi;
+#ifdef hp300
+       u.u_pcb.pcb_flags &= ~(PCB_AST|PCB_HPUXMMAP|PCB_HPUXBIN);
+#ifdef HPUXCOMPAT
+       /* remember that we were loaded from an HPUX format file */
+       if (ep->a_mid == MID_HPUX)
+               u.u_pcb.pcb_flags |= PCB_HPUXBIN;
+#endif
+#endif
+       p->p_flag &= ~(SPAGV|SSEQL|SUANOM|SHPUX);
+       p->p_flag |= flags | SEXEC;
        u.u_dmap = u.u_cdmap;
        u.u_smap = u.u_csmap;
        vgetvm(ts, ds, ss);
 
        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)),
+       if ((flags & SPAGV) == 0)
+               (void) vn_rdwr(UIO_READ, vp,
+                       (char *)ctob(dptov(p, 0)),
                        (int)ep->a_data,
                        (int)ep->a_data,
-                       (off_t)(sizeof (struct exec) + ep->a_text),
-                       0, (int *)0);
-       xalloc(ip, ep, 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), (size_t)btoc(ep->a_data));
+                       (off_t)(toff + ep->a_text),
+                       UIO_USERSPACE, (IO_UNIT|IO_NODELOCKED), cred, (int *)0);
+       xalloc(vp, ep, toff, cred);
+#if defined(tahoe)
+       /*
+        * Define new keys.
+        */
+       if (p->p_textp == 0) {  /* use existing code key if shared */
+               ckeyrelease(p->p_ckey);
+               p->p_ckey = getcodekey();
+       }
+       mtpr(CCK, p->p_ckey);
+       dkeyrelease(p->p_dkey);
+       p->p_dkey = getdatakey();
+       mtpr(DCK, p->p_dkey);
+#endif
+       if ((flags & SPAGV) && p->p_textp)
+               vinifod(p, (struct fpte *)dptopte(p, 0),
+                   PG_FTEXT, p->p_textp->x_vptr,
+                   (long)(1 + ts/CLSIZE), (segsz_t)btoc(ep->a_data));
 
 
-#ifdef vax
+#if defined(vax) || defined(tahoe)
        /* THIS SHOULD BE DONE AT A LOWER LEVEL, IF AT ALL */
        mtpr(TBIA, 0);
 #endif
        /* THIS SHOULD BE DONE AT A LOWER LEVEL, IF AT ALL */
        mtpr(TBIA, 0);
 #endif
+#ifdef hp300
+       TBIAU();
+#endif
+#if defined(i386)
+       tlbflush();
+#endif
 
 
-       if (u.u_error)
-               swkill(u.u_procp, "exec: I/O error mapping pages");
        /*
         * set SUID/SGID protections, if no tracing
         */
        /*
         * set SUID/SGID protections, if no tracing
         */
-       if ((u.u_procp->p_flag&STRC)==0) {
-               u.u_uid = uid;
-               u.u_procp->p_uid = uid;
-               u.u_gid = gid;
+       if ((p->p_flag&STRC)==0) {
+               if (uid != cred->cr_uid || gid != cred->cr_gid)
+                       u.u_cred = cred = crcopy(cred);
+               cred->cr_uid = uid;
+               cred->cr_gid = gid;
+               p->p_uid = uid;
        } else
        } else
-               psignal(u.u_procp, SIGTRAP);
+               psignal(p, SIGTRAP);
+       p->p_svuid = p->p_uid;
+       p->p_svgid = cred->cr_gid;
        u.u_tsize = ts;
        u.u_dsize = ds;
        u.u_ssize = ss;
        u.u_prof.pr_scale = 0;
        u.u_tsize = ts;
        u.u_dsize = ds;
        u.u_ssize = ss;
        u.u_prof.pr_scale = 0;
-bad:
-       return;
+#if defined(tahoe)
+       u.u_pcb.pcb_savacc.faddr = (float *)NULL;
+#endif
+       return (0);
 }
 }