ensure bmap run list is initialised
[unix-history] / usr / src / sys / miscfs / procfs / procfs_vnops.c
index 39aff3b..5d9dee5 100644 (file)
@@ -1,14 +1,14 @@
 /*
 /*
- * Copyright (c) 1993 The Regents of the University of California.
  * Copyright (c) 1993 Jan-Simon Pendry
  * Copyright (c) 1993 Jan-Simon Pendry
- * All rights reserved.
+ * Copyright (c) 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * Jan-Simon Pendry.
  *
  * %sccs.include.redist.c%
  *
  *
  * This code is derived from software contributed to Berkeley by
  * Jan-Simon Pendry.
  *
  * %sccs.include.redist.c%
  *
- *     @(#)procfs_vnops.c      8.3 (Berkeley) %G%
+ *     @(#)procfs_vnops.c      8.11 (Berkeley) %G%
  *
  * From:
  *     $Id: procfs_vnops.c,v 3.2 1993/12/15 09:40:17 jsp Exp $
  *
  * From:
  *     $Id: procfs_vnops.c,v 3.2 1993/12/15 09:40:17 jsp Exp $
@@ -29,8 +29,9 @@
 #include <sys/malloc.h>
 #include <sys/dirent.h>
 #include <sys/resourcevar.h>
 #include <sys/malloc.h>
 #include <sys/dirent.h>
 #include <sys/resourcevar.h>
-#include <miscfs/procfs/procfs.h>
 #include <vm/vm.h>     /* for PAGE_SIZE */
 #include <vm/vm.h>     /* for PAGE_SIZE */
+#include <machine/reg.h>
+#include <miscfs/procfs/procfs.h>
 
 /*
  * Vnode Operations.
 
 /*
  * Vnode Operations.
  * used in procfs_lookup and procfs_readdir
  */
 static struct pfsnames {
  * used in procfs_lookup and procfs_readdir
  */
 static struct pfsnames {
-       u_short d_namlen;
+       u_char  d_type;
+       u_char  d_namlen;
        char    d_name[PROCFS_NAMELEN];
        pfstype d_pfstype;
        char    d_name[PROCFS_NAMELEN];
        pfstype d_pfstype;
+       int     (*d_valid) __P((struct proc *p));
 } procent[] = {
 #define N(s) sizeof(s)-1, s
        /* namlen, nam, type */
 } procent[] = {
 #define N(s) sizeof(s)-1, s
        /* namlen, nam, type */
-       {  N("file"),   Pfile },
-       {  N("mem"),    Pmem },
-       {  N("regs"),   Pregs },
-       {  N("ctl"),    Pctl },
-       {  N("status"), Pstatus },
-       {  N("note"),   Pnote },
-       {  N("notepg"), Pnotepg },
+       { DT_DIR, N("."),       Pproc,          NULL },
+       { DT_DIR, N(".."),      Proot,          NULL },
+       { DT_REG, N("file"),    Pfile,          procfs_validfile },
+       { DT_REG, N("mem"),     Pmem,           NULL },
+       { DT_REG, N("regs"),    Pregs,          procfs_validregs },
+       { DT_REG, N("fpregs"),  Pfpregs,        procfs_validfpregs },
+       { DT_REG, N("ctl"),     Pctl,           NULL },
+       { DT_REG, N("status"),  Pstatus,        NULL },
+       { DT_REG, N("note"),    Pnote,          NULL },
+       { DT_REG, N("notepg"),  Pnotepg,        NULL },
 #undef N
 };
 #define Nprocent (sizeof(procent)/sizeof(procent[0]))
 #undef N
 };
 #define Nprocent (sizeof(procent)/sizeof(procent[0]))
@@ -74,7 +80,12 @@ static pid_t atopid __P((const char *, u_int));
  * memory images.
  */
 procfs_open(ap)
  * memory images.
  */
 procfs_open(ap)
-       struct vop_open_args *ap;
+       struct vop_open_args /* {
+               struct vnode *a_vp;
+               int  a_mode;
+               struct ucred *a_cred;
+               struct proc *a_p;
+       } */ *ap;
 {
        struct pfsnode *pfs = VTOPFS(ap->a_vp);
 
 {
        struct pfsnode *pfs = VTOPFS(ap->a_vp);
 
@@ -84,10 +95,9 @@ procfs_open(ap)
                        return (ENOENT);        /* was ESRCH, jsp */
 
                if ((pfs->pfs_flags & FWRITE) && (ap->a_mode & O_EXCL) ||
                        return (ENOENT);        /* was ESRCH, jsp */
 
                if ((pfs->pfs_flags & FWRITE) && (ap->a_mode & O_EXCL) ||
-                               (pfs->pfs_flags & O_EXCL) && (ap->a_mode & FWRITE))
+                   (pfs->pfs_flags & O_EXCL) && (ap->a_mode & FWRITE))
                        return (EBUSY);
 
                        return (EBUSY);
 
-
                if (ap->a_mode & FWRITE)
                        pfs->pfs_flags = ap->a_mode & (FWRITE|O_EXCL);
 
                if (ap->a_mode & FWRITE)
                        pfs->pfs_flags = ap->a_mode & (FWRITE|O_EXCL);
 
@@ -108,7 +118,12 @@ procfs_open(ap)
  * any exclusive open flag (see _open above).
  */
 procfs_close(ap)
  * any exclusive open flag (see _open above).
  */
 procfs_close(ap)
-       struct vop_close_args *ap;
+       struct vop_close_args /* {
+               struct vnode *a_vp;
+               int  a_fflag;
+               struct ucred *a_cred;
+               struct proc *a_p;
+       } */ *ap;
 {
        struct pfsnode *pfs = VTOPFS(ap->a_vp);
 
 {
        struct pfsnode *pfs = VTOPFS(ap->a_vp);
 
@@ -127,7 +142,14 @@ procfs_close(ap)
  * (vp) is not locked on entry or exit.
  */
 procfs_ioctl(ap)
  * (vp) is not locked on entry or exit.
  */
 procfs_ioctl(ap)
-       struct vop_ioctl_args *ap;
+       struct vop_ioctl_args /* {
+               struct vnode *a_vp;
+               int a_command;
+               caddr_t a_data;
+               int a_fflag;
+               struct ucred *a_cred;
+               struct proc *a_p;
+       } */ *ap;
 {
 
        return (ENOTTY);
 {
 
        return (ENOTTY);
@@ -144,13 +166,20 @@ procfs_ioctl(ap)
  * (EIO) would be a reasonable alternative.
  */
 procfs_bmap(ap)
  * (EIO) would be a reasonable alternative.
  */
 procfs_bmap(ap)
-       struct vop_bmap_args *ap;
+       struct vop_bmap_args /* {
+               struct vnode *a_vp;
+               daddr_t  a_bn;
+               struct vnode **a_vpp;
+               daddr_t *a_bnp;
+       } */ *ap;
 {
 
        if (ap->a_vpp != NULL)
                *ap->a_vpp = ap->a_vp;
        if (ap->a_bnp != NULL)
                *ap->a_bnp = ap->a_bn;
 {
 
        if (ap->a_vpp != NULL)
                *ap->a_vpp = ap->a_vp;
        if (ap->a_bnp != NULL)
                *ap->a_bnp = ap->a_bn;
+       if (ap->a_runp != NULL)
+               *ap->a_runp = 0;
        return (0);
 }
 
        return (0);
 }
 
@@ -171,7 +200,9 @@ procfs_bmap(ap)
  * (vp) is not locked on entry or exit.
  */
 procfs_inactive(ap)
  * (vp) is not locked on entry or exit.
  */
 procfs_inactive(ap)
-       struct vop_inactive_args *ap;
+       struct vop_inactive_args /* {
+               struct vnode *a_vp;
+       } */ *ap;
 {
        struct pfsnode *pfs = VTOPFS(ap->a_vp);
 
 {
        struct pfsnode *pfs = VTOPFS(ap->a_vp);
 
@@ -189,12 +220,12 @@ procfs_inactive(ap)
  * from any private lists.
  */
 procfs_reclaim(ap)
  * from any private lists.
  */
 procfs_reclaim(ap)
-       struct vop_reclaim_args *ap;
+       struct vop_reclaim_args /* {
+               struct vnode *a_vp;
+       } */ *ap;
 {
 {
-       int error;
 
 
-       error = procfs_freevp(ap->a_vp);
-       return (error);
+       return (procfs_freevp(ap->a_vp));
 }
 
 /*
 }
 
 /*
@@ -239,13 +270,14 @@ procfs_pathconf(ap)
  * of (vp).
  */
 procfs_print(ap)
  * of (vp).
  */
 procfs_print(ap)
-       struct vop_print_args *ap;
+       struct vop_print_args /* {
+               struct vnode *a_vp;
+       } */ *ap;
 {
        struct pfsnode *pfs = VTOPFS(ap->a_vp);
 
 {
        struct pfsnode *pfs = VTOPFS(ap->a_vp);
 
-       printf("tag VT_PROCFS, pid %d, mode %x, flags %x\n",
-               pfs->pfs_pid,
-               pfs->pfs_mode, pfs->pfs_flags);
+       printf("tag VT_PROCFS, type %s, pid %d, mode %x, flags %x\n",
+           pfs->pfs_type, pfs->pfs_pid, pfs->pfs_mode, pfs->pfs_flags);
 }
 
 /*
 }
 
 /*
@@ -255,7 +287,10 @@ procfs_print(ap)
  * this will always include freeing the pathname buffer.
  */
 procfs_abortop(ap)
  * this will always include freeing the pathname buffer.
  */
 procfs_abortop(ap)
-       struct vop_abortop_args *ap;
+       struct vop_abortop_args /* {
+               struct vnode *a_dvp;
+               struct componentname *a_cnp;
+       } */ *ap;
 {
 
        if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF)
 {
 
        if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF)
@@ -282,17 +317,31 @@ procfs_badop()
  * this is relatively minimal for procfs.
  */
 procfs_getattr(ap)
  * this is relatively minimal for procfs.
  */
 procfs_getattr(ap)
-       struct vop_getattr_args *ap;
+       struct vop_getattr_args /* {
+               struct vnode *a_vp;
+               struct vattr *a_vap;
+               struct ucred *a_cred;
+               struct proc *a_p;
+       } */ *ap;
 {
        struct pfsnode *pfs = VTOPFS(ap->a_vp);
        struct vattr *vap = ap->a_vap;
        struct proc *procp;
 {
        struct pfsnode *pfs = VTOPFS(ap->a_vp);
        struct vattr *vap = ap->a_vap;
        struct proc *procp;
+       struct timeval tv;
        int error;
 
        /* first check the process still exists */
        int error;
 
        /* first check the process still exists */
-       procp = PFIND(pfs->pfs_pid);
-       if (procp == 0)
-               return (ENOENT);
+       switch (pfs->pfs_type) {
+       case Proot:
+       case Pcurproc:
+               procp = 0;
+               break;
+
+       default:
+               procp = PFIND(pfs->pfs_pid);
+               if (procp == 0)
+                       return (ENOENT);
+       }
 
        error = 0;
 
 
        error = 0;
 
@@ -315,9 +364,33 @@ procfs_getattr(ap)
         * p_stat structure is not addressible if u. gets
         * swapped out for that process.
         */
         * p_stat structure is not addressible if u. gets
         * swapped out for that process.
         */
-       microtime(&vap->va_ctime);
+       microtime(&tv);
+       TIMEVAL_TO_TIMESPEC(&tv, &vap->va_ctime);
        vap->va_atime = vap->va_mtime = vap->va_ctime;
 
        vap->va_atime = vap->va_mtime = vap->va_ctime;
 
+       /*
+        * If the process has exercised some setuid or setgid
+        * privilege, then rip away read/write permission so
+        * that only root can gain access.
+        */
+       switch (pfs->pfs_type) {
+       case Pmem:
+       case Pregs:
+       case Pfpregs:
+               if (procp->p_flag & P_SUGID)
+                       vap->va_mode &= ~((VREAD|VWRITE)|
+                                         ((VREAD|VWRITE)>>3)|
+                                         ((VREAD|VWRITE)>>6));
+       case Pctl:
+       case Pstatus:
+       case Pnote:
+       case Pnotepg:
+               vap->va_nlink = 1;
+               vap->va_uid = procp->p_ucred->cr_uid;
+               vap->va_gid = procp->p_ucred->cr_gid;
+               break;
+       }
+
        /*
         * now do the object specific fields
         *
        /*
         * now do the object specific fields
         *
@@ -330,15 +403,30 @@ procfs_getattr(ap)
 
        switch (pfs->pfs_type) {
        case Proot:
 
        switch (pfs->pfs_type) {
        case Proot:
-               vap->va_nlink = 2;
+               /*
+                * Set nlink to 1 to tell fts(3) we don't actually know.
+                */
+               vap->va_nlink = 1;
+               vap->va_uid = 0;
+               vap->va_gid = 0;
+               vap->va_size = vap->va_bytes = DEV_BSIZE;
+               break;
+
+       case Pcurproc: {
+               char buf[16];           /* should be enough */
+               vap->va_nlink = 1;
                vap->va_uid = 0;
                vap->va_gid = 0;
                vap->va_uid = 0;
                vap->va_gid = 0;
+               vap->va_size = vap->va_bytes =
+                   sprintf(buf, "%ld", (long)curproc->p_pid);
                break;
                break;
+       }
 
        case Pproc:
                vap->va_nlink = 2;
                vap->va_uid = procp->p_ucred->cr_uid;
                vap->va_gid = procp->p_ucred->cr_gid;
 
        case Pproc:
                vap->va_nlink = 2;
                vap->va_uid = procp->p_ucred->cr_uid;
                vap->va_gid = procp->p_ucred->cr_gid;
+               vap->va_size = vap->va_bytes = DEV_BSIZE;
                break;
 
        case Pfile:
                break;
 
        case Pfile:
@@ -346,23 +434,24 @@ procfs_getattr(ap)
                break;
 
        case Pmem:
                break;
 
        case Pmem:
-               vap->va_nlink = 1;
                vap->va_bytes = vap->va_size =
                        ctob(procp->p_vmspace->vm_tsize +
                                    procp->p_vmspace->vm_dsize +
                                    procp->p_vmspace->vm_ssize);
                vap->va_bytes = vap->va_size =
                        ctob(procp->p_vmspace->vm_tsize +
                                    procp->p_vmspace->vm_dsize +
                                    procp->p_vmspace->vm_ssize);
-               vap->va_uid = procp->p_ucred->cr_uid;
-               vap->va_gid = procp->p_ucred->cr_gid;
                break;
 
        case Pregs:
                break;
 
        case Pregs:
+               vap->va_bytes = vap->va_size = sizeof(struct reg);
+               break;
+
+       case Pfpregs:
+               vap->va_bytes = vap->va_size = sizeof(struct fpreg);
+               break;
+
        case Pctl:
        case Pstatus:
        case Pnote:
        case Pnotepg:
        case Pctl:
        case Pstatus:
        case Pnote:
        case Pnotepg:
-               vap->va_nlink = 1;
-               vap->va_uid = procp->p_ucred->cr_uid;
-               vap->va_gid = procp->p_ucred->cr_gid;
                break;
 
        default:
                break;
 
        default:
@@ -373,7 +462,12 @@ procfs_getattr(ap)
 }
 
 procfs_setattr(ap)
 }
 
 procfs_setattr(ap)
-       struct vop_setattr_args *ap;
+       struct vop_setattr_args /* {
+               struct vnode *a_vp;
+               struct vattr *a_vap;
+               struct ucred *a_cred;
+               struct proc *a_p;
+       } */ *ap;
 {
        /*
         * just fake out attribute setting
 {
        /*
         * just fake out attribute setting
@@ -401,7 +495,12 @@ procfs_setattr(ap)
  * that the operation really does make sense.
  */
 procfs_access(ap)
  * that the operation really does make sense.
  */
 procfs_access(ap)
-       struct vop_access_args *ap;
+       struct vop_access_args /* {
+               struct vnode *a_vp;
+               int a_mode;
+               struct ucred *a_cred;
+               struct proc *a_p;
+       } */ *ap;
 {
        struct vattr *vap;
        struct vattr vattr;
 {
        struct vattr *vap;
        struct vattr vattr;
@@ -411,8 +510,9 @@ procfs_access(ap)
         * If you're the super-user,
         * you always get access.
         */
         * If you're the super-user,
         * you always get access.
         */
-       if (ap->a_cred->cr_uid == (uid_t) 0)
+       if (ap->a_cred->cr_uid == 0)
                return (0);
                return (0);
+
        vap = &vattr;
        if (error = VOP_GETATTR(ap->a_vp, vap, ap->a_cred, ap->a_p))
                return (error);
        vap = &vattr;
        if (error = VOP_GETATTR(ap->a_vp, vap, ap->a_cred, ap->a_p))
                return (error);
@@ -426,7 +526,7 @@ procfs_access(ap)
                gid_t *gp;
                int i;
 
                gid_t *gp;
                int i;
 
-               (ap->a_mode) >>= 3;
+               ap->a_mode >>= 3;
                gp = ap->a_cred->cr_groups;
                for (i = 0; i < ap->a_cred->cr_ngroups; i++, gp++)
                        if (vap->va_gid == *gp)
                gp = ap->a_cred->cr_groups;
                for (i = 0; i < ap->a_cred->cr_ngroups; i++, gp++)
                        if (vap->va_gid == *gp)
@@ -452,7 +552,11 @@ found:
  * read and inwardly digest ufs_lookup().
  */
 procfs_lookup(ap)
  * read and inwardly digest ufs_lookup().
  */
 procfs_lookup(ap)
-       struct vop_lookup_args *ap;
+       struct vop_lookup_args /* {
+               struct vnode * a_dvp;
+               struct vnode ** a_vpp;
+               struct componentname * a_cnp;
+       } */ *ap;
 {
        struct componentname *cnp = ap->a_cnp;
        struct vnode **vpp = ap->a_vpp;
 {
        struct componentname *cnp = ap->a_cnp;
        struct vnode **vpp = ap->a_vpp;
@@ -482,9 +586,9 @@ procfs_lookup(ap)
                        return (EIO);
 
                if (CNEQ(cnp, "curproc", 7))
                        return (EIO);
 
                if (CNEQ(cnp, "curproc", 7))
-                       pid = cnp->cn_proc->p_pid;
-               else
-                       pid = atopid(pname, cnp->cn_namelen);
+                       return (procfs_allocvp(dvp->v_mount, vpp, 0, Pcurproc));
+
+               pid = atopid(pname, cnp->cn_namelen);
                if (pid == NO_PID)
                        return (ENOENT);
 
                if (pid == NO_PID)
                        return (ENOENT);
 
@@ -492,15 +596,7 @@ procfs_lookup(ap)
                if (procp == 0)
                        return (ENOENT);
 
                if (procp == 0)
                        return (ENOENT);
 
-               error = procfs_allocvp(dvp->v_mount, &nvp, pid, Pproc);
-               if (error)
-                       return (error);
-
-               nvp->v_type = VDIR;
-               pfs = VTOPFS(nvp);
-
-               *vpp = nvp;
-               return (0);
+               return (procfs_allocvp(dvp->v_mount, vpp, pid, Pproc));
 
        case Pproc:
                if (cnp->cn_flags & ISDOTDOT) {
 
        case Pproc:
                if (cnp->cn_flags & ISDOTDOT) {
@@ -516,7 +612,8 @@ procfs_lookup(ap)
                        struct pfsnames *dp = &procent[i];
 
                        if (cnp->cn_namelen == dp->d_namlen &&
                        struct pfsnames *dp = &procent[i];
 
                        if (cnp->cn_namelen == dp->d_namlen &&
-                           bcmp(pname, dp->d_name, dp->d_namlen) == 0) {
+                           bcmp(pname, dp->d_name, dp->d_namlen) == 0 &&
+                           (dp->d_valid == NULL || (*dp->d_valid)(procp))) {
                                pfs_type = dp->d_pfstype;
                                goto found;
                        }
                                pfs_type = dp->d_pfstype;
                                goto found;
                        }
@@ -526,29 +623,30 @@ procfs_lookup(ap)
        found:
                if (pfs_type == Pfile) {
                        nvp = procfs_findtextvp(procp);
        found:
                if (pfs_type == Pfile) {
                        nvp = procfs_findtextvp(procp);
-                       if (nvp) {
-                               VREF(nvp);
-                               VOP_LOCK(nvp);
-                       } else {
-                               error = ENXIO;
-                       }
-               } else {
-                       error = procfs_allocvp(dvp->v_mount, &nvp,
-                                       pfs->pfs_pid, pfs_type);
-                       if (error)
-                               return (error);
-
-                       nvp->v_type = VREG;
-                       pfs = VTOPFS(nvp);
+                       if (nvp == NULLVP)
+                               return (ENXIO);
+                       VREF(nvp);
+                       VOP_LOCK(nvp);
+                       *vpp = nvp;
+                       return (0);
                }
                }
-               *vpp = nvp;
-               return (error);
+
+               return (procfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid,
+                   pfs_type));
 
        default:
                return (ENOTDIR);
        }
 }
 
 
        default:
                return (ENOTDIR);
        }
 }
 
+int
+procfs_validfile(p)
+       struct proc *p;
+{
+
+       return (procfs_findtextvp(p) != NULLVP);
+}
+
 /*
  * readdir returns directory entries from pfsnode (vp).
  *
 /*
  * readdir returns directory entries from pfsnode (vp).
  *
@@ -562,7 +660,14 @@ procfs_lookup(ap)
  * this should just be done through read()
  */
 procfs_readdir(ap)
  * this should just be done through read()
  */
 procfs_readdir(ap)
-       struct vop_readdir_args *ap;
+       struct vop_readdir_args /* {
+               struct vnode *a_vp;
+               struct uio *a_uio;
+               struct ucred *a_cred;
+               int *a_eofflag;
+               u_long *a_cookies;
+               int a_ncookies;
+       } */ *ap;
 {
        struct uio *uio = ap->a_uio;
        struct pfsdent d;
 {
        struct uio *uio = ap->a_uio;
        struct pfsdent d;
@@ -572,6 +677,13 @@ procfs_readdir(ap)
        int count;
        int i;
 
        int count;
        int i;
 
+       /*
+        * We don't allow exporting procfs mounts, and currently local
+        * requests do not need cookies.
+        */
+       if (ap->a_ncookies)
+               panic("procfs_readdir: not hungry");
+
        pfs = VTOPFS(ap->a_vp);
 
        if (uio->uio_resid < UIO_MX)
        pfs = VTOPFS(ap->a_vp);
 
        if (uio->uio_resid < UIO_MX)
@@ -592,24 +704,27 @@ procfs_readdir(ap)
         * from the procent[] table (top of this file).
         */
        case Pproc: {
         * from the procent[] table (top of this file).
         */
        case Pproc: {
-               while (uio->uio_resid >= UIO_MX) {
-                       struct pfsnames *dt;
+               pid_t pid = pfs->pfs_pid;
+               struct pfsnames *dt;
+
+               for (dt = &procent[i]; i < Nprocent && uio->uio_resid >= UIO_MX;
+                    dt++, i++) {
+                       struct proc *p = PFIND(pid);
 
 
-                       if (i >= Nprocent)
+                       if (p == NULL)
                                break;
 
                                break;
 
-                       dt = &procent[i];
+                       if (dt->d_valid && (*dt->d_valid)(p) == 0)
+                               continue;
                        
                        dp->d_reclen = UIO_MX;
                        
                        dp->d_reclen = UIO_MX;
-                       dp->d_fileno = PROCFS_FILENO(pfs->pfs_pid, dt->d_pfstype);
-                       dp->d_type = DT_REG;
+                       dp->d_fileno = PROCFS_FILENO(pid, dt->d_pfstype);
                        dp->d_namlen = dt->d_namlen;
                        dp->d_namlen = dt->d_namlen;
-                       bcopy(dt->d_name, dp->d_name, sizeof(dt->d_name)-1);
-                       error = uiomove((caddr_t) dp, UIO_MX, uio);
-                       if (error)
+                       bcopy(dt->d_name, dp->d_name, dt->d_namlen + 1);
+                       dp->d_type = dt->d_type;
+
+                       if (error = uiomove((caddr_t)dp, UIO_MX, uio))
                                break;
                                break;
-                       count += UIO_MX;
-                       i++;
                }
 
                break;
                }
 
                break;
@@ -626,55 +741,61 @@ procfs_readdir(ap)
         */
 
        case Proot: {
         */
 
        case Proot: {
-               int pcnt;
 #ifdef PROCFS_ZOMBIE
                int doingzomb = 0;
 #endif
 #ifdef PROCFS_ZOMBIE
                int doingzomb = 0;
 #endif
-               volatile struct proc *p;
-
-               p = allproc;
+               int pcnt = 0;
+               volatile struct proc *p = allproc.lh_first;
 
 
-#define PROCFS_XFILES  1       /* number of other entries, like "curproc" */
-               pcnt = PROCFS_XFILES;
-
-               while (p && uio->uio_resid >= UIO_MX) {
+       again:
+               for (; p && uio->uio_resid >= UIO_MX; i++, pcnt++) {
                        bzero((char *) dp, UIO_MX);
                        bzero((char *) dp, UIO_MX);
-                       dp->d_type = DT_DIR;
                        dp->d_reclen = UIO_MX;
 
                        switch (i) {
                        dp->d_reclen = UIO_MX;
 
                        switch (i) {
-                       case 0:
-                               /* ship out entry for "curproc" */
-                               dp->d_fileno = PROCFS_FILENO(PID_MAX+1, Pproc);
-                               dp->d_namlen = sprintf(dp->d_name, "curproc");
+                       case 0:         /* `.' */
+                       case 1:         /* `..' */
+                               dp->d_fileno = PROCFS_FILENO(0, Proot);
+                               dp->d_namlen = i + 1;
+                               bcopy("..", dp->d_name, dp->d_namlen);
+                               dp->d_name[i + 1] = '\0';
+                               dp->d_type = DT_DIR;
                                break;
 
                                break;
 
-                       default:
-                               if (pcnt >= i) {
-                                       dp->d_fileno = PROCFS_FILENO(p->p_pid, Pproc);
-                                       dp->d_namlen = sprintf(dp->d_name, "%ld", (long) p->p_pid);
-                               }
-
-                               p = p->p_next;
+                       case 2:
+                               dp->d_fileno = PROCFS_FILENO(0, Pcurproc);
+                               dp->d_namlen = 7;
+                               bcopy("curproc", dp->d_name, 8);
+                               dp->d_type = DT_LNK;
+                               break;
 
 
-#ifdef PROCFS_ZOMBIE
-                               if (p == 0 && doingzomb == 0) {
-                                       doingzomb = 1;
-                                       p = zombproc;
+                       default:
+                               while (pcnt < i) {
+                                       pcnt++;
+                                       p = p->p_list.le_next;
+                                       if (!p)
+                                               goto done;
                                }
                                }
-#endif
-
-                               if (pcnt++ < i)
-                                       continue;
-
+                               dp->d_fileno = PROCFS_FILENO(p->p_pid, Pproc);
+                               dp->d_namlen = sprintf(dp->d_name, "%ld",
+                                   (long)p->p_pid);
+                               dp->d_type = DT_REG;
+                               p = p->p_list.le_next;
                                break;
                        }
                                break;
                        }
-                       error = uiomove((caddr_t) dp, UIO_MX, uio);
-                       if (error)
+
+                       if (error = uiomove((caddr_t)dp, UIO_MX, uio))
                                break;
                                break;
-                       count += UIO_MX;
-                       i++;
                }
                }
+       done:
+
+#ifdef PROCFS_ZOMBIE
+               if (p == 0 && doingzomb == 0) {
+                       doingzomb = 1;
+                       p = zombproc.lh_first;
+                       goto again;
+               }
+#endif
 
                break;
 
 
                break;
 
@@ -690,6 +811,24 @@ procfs_readdir(ap)
        return (error);
 }
 
        return (error);
 }
 
+/*
+ * readlink reads the link of `curproc'
+ */
+procfs_readlink(ap)
+       struct vop_readlink_args *ap;
+{
+       struct uio *uio = ap->a_uio;
+       char buf[16];           /* should be enough */
+       int len;
+
+       if (VTOPFS(ap->a_vp)->pfs_fileno != PROCFS_FILENO(0, Pcurproc))
+               return (EINVAL);
+
+       len = sprintf(buf, "%ld", (long)curproc->p_pid);
+
+       return (uiomove((caddr_t)buf, len, ap->a_uio));
+}
+
 /*
  * convert decimal ascii to pid_t
  */
 /*
  * convert decimal ascii to pid_t
  */