1*65523Spendry /* 2*65523Spendry * Copyright (c) 1993 The Regents of the University of California. 3*65523Spendry * Copyright (c) 1993 Jan-Simon Pendry 4*65523Spendry * All rights reserved. 5*65523Spendry * 6*65523Spendry * This code is derived from software contributed to Berkeley by 7*65523Spendry * Jan-Simon Pendry. 8*65523Spendry * 9*65523Spendry * %sccs.include.redist.c% 10*65523Spendry * 11*65523Spendry * @(#)procfs_subr.c 8.1 (Berkeley) 01/05/94 12*65523Spendry * 13*65523Spendry * From: 14*65523Spendry * $Id: procfs_subr.c,v 3.2 1993/12/15 09:40:17 jsp Exp $ 15*65523Spendry */ 16*65523Spendry 17*65523Spendry #include <sys/param.h> 18*65523Spendry #include <sys/systm.h> 19*65523Spendry #include <sys/time.h> 20*65523Spendry #include <sys/kernel.h> 21*65523Spendry #include <sys/proc.h> 22*65523Spendry #include <sys/vnode.h> 23*65523Spendry #include <sys/malloc.h> 24*65523Spendry #include <miscfs/procfs/procfs.h> 25*65523Spendry 26*65523Spendry static struct pfsnode *pfshead; 27*65523Spendry static int pfsvplock; 28*65523Spendry 29*65523Spendry /* 30*65523Spendry * allocate a pfsnode/vnode pair. the vnode is 31*65523Spendry * referenced, but not locked. 32*65523Spendry * 33*65523Spendry * the pid, pfs_type, and mount point uniquely 34*65523Spendry * identify a pfsnode. the mount point is needed 35*65523Spendry * because someone might mount this filesystem 36*65523Spendry * twice. 37*65523Spendry * 38*65523Spendry * all pfsnodes are maintained on a singly-linked 39*65523Spendry * list. new nodes are only allocated when they cannot 40*65523Spendry * be found on this list. entries on the list are 41*65523Spendry * removed when the vfs reclaim entry is called. 42*65523Spendry * 43*65523Spendry * a single lock is kept for the entire list. this is 44*65523Spendry * needed because the getnewvnode() function can block 45*65523Spendry * waiting for a vnode to become free, in which case there 46*65523Spendry * may be more than one process trying to get the same 47*65523Spendry * vnode. this lock is only taken if we are going to 48*65523Spendry * call getnewvnode, since the kernel itself is single-threaded. 49*65523Spendry * 50*65523Spendry * if an entry is found on the list, then call vget() to 51*65523Spendry * take a reference. this is done because there may be 52*65523Spendry * zero references to it and so it needs to removed from 53*65523Spendry * the vnode free list. 54*65523Spendry */ 55*65523Spendry int 56*65523Spendry procfs_allocvp(mp, vpp, pid, pfs_type) 57*65523Spendry struct mount *mp; 58*65523Spendry struct vnode **vpp; 59*65523Spendry long pid; 60*65523Spendry pfstype pfs_type; 61*65523Spendry { 62*65523Spendry int error; 63*65523Spendry struct pfsnode *pfs; 64*65523Spendry struct pfsnode **pp; 65*65523Spendry 66*65523Spendry loop: 67*65523Spendry for (pfs = pfshead; pfs != 0; pfs = pfs->pfs_next) { 68*65523Spendry if (pfs->pfs_pid == pid && 69*65523Spendry pfs->pfs_type == pfs_type && 70*65523Spendry PFSTOV(pfs)->v_mount == mp) { 71*65523Spendry if (vget(pfs->pfs_vnode, 1)) 72*65523Spendry goto loop; 73*65523Spendry VOP_UNLOCK(pfs->pfs_vnode); 74*65523Spendry *vpp = pfs->pfs_vnode; 75*65523Spendry return (0); 76*65523Spendry } 77*65523Spendry } 78*65523Spendry 79*65523Spendry /* 80*65523Spendry * otherwise lock the vp list while we call getnewvnode 81*65523Spendry * since that can block. 82*65523Spendry */ 83*65523Spendry if (pfsvplock & PROCFS_LOCKED) { 84*65523Spendry pfsvplock |= PROCFS_WANT; 85*65523Spendry sleep((caddr_t) &pfsvplock, PINOD); 86*65523Spendry goto loop; 87*65523Spendry } 88*65523Spendry pfsvplock |= PROCFS_LOCKED; 89*65523Spendry 90*65523Spendry error = getnewvnode(VT_PROCFS, mp, procfs_vnodeop_p, vpp); 91*65523Spendry if (error) 92*65523Spendry goto out; 93*65523Spendry 94*65523Spendry MALLOC((*vpp)->v_data, void *, sizeof(struct pfsnode), 95*65523Spendry M_TEMP, M_WAITOK); 96*65523Spendry 97*65523Spendry pfs = VTOPFS(*vpp); 98*65523Spendry pfs->pfs_next = 0; 99*65523Spendry pfs->pfs_pid = (pid_t) pid; 100*65523Spendry pfs->pfs_type = pfs_type; 101*65523Spendry pfs->pfs_vnode = *vpp; 102*65523Spendry pfs->pfs_flags = 0; 103*65523Spendry pfs->pfs_fileno = PROCFS_FILENO(pid, pfs_type); 104*65523Spendry 105*65523Spendry switch (pfs_type) { 106*65523Spendry case Proot: /* /proc = dr-xr-xr-x */ 107*65523Spendry pfs->pfs_mode = (VREAD|VEXEC) | 108*65523Spendry (VREAD|VEXEC) >> 3 | 109*65523Spendry (VREAD|VEXEC) >> 6; 110*65523Spendry break; 111*65523Spendry 112*65523Spendry case Pproc: 113*65523Spendry pfs->pfs_mode = (VREAD|VEXEC) | 114*65523Spendry (VREAD|VEXEC) >> 3 | 115*65523Spendry (VREAD|VEXEC) >> 6; 116*65523Spendry break; 117*65523Spendry 118*65523Spendry case Pfile: 119*65523Spendry pfs->pfs_mode = (VREAD|VWRITE); 120*65523Spendry break; 121*65523Spendry 122*65523Spendry case Pmem: 123*65523Spendry pfs->pfs_mode = (VREAD|VWRITE); 124*65523Spendry break; 125*65523Spendry 126*65523Spendry case Pregs: 127*65523Spendry pfs->pfs_mode = (VREAD|VWRITE); 128*65523Spendry break; 129*65523Spendry 130*65523Spendry case Pctl: 131*65523Spendry pfs->pfs_mode = (VWRITE); 132*65523Spendry break; 133*65523Spendry 134*65523Spendry case Pstatus: 135*65523Spendry pfs->pfs_mode = (VREAD) | 136*65523Spendry (VREAD >> 3) | 137*65523Spendry (VREAD >> 6); 138*65523Spendry break; 139*65523Spendry 140*65523Spendry case Pnote: 141*65523Spendry pfs->pfs_mode = (VWRITE); 142*65523Spendry break; 143*65523Spendry 144*65523Spendry case Pnotepg: 145*65523Spendry pfs->pfs_mode = (VWRITE); 146*65523Spendry break; 147*65523Spendry 148*65523Spendry default: 149*65523Spendry panic("procfs_allocvp"); 150*65523Spendry } 151*65523Spendry 152*65523Spendry /* add to procfs vnode list */ 153*65523Spendry for (pp = &pfshead; *pp; pp = &(*pp)->pfs_next) 154*65523Spendry continue; 155*65523Spendry *pp = pfs; 156*65523Spendry 157*65523Spendry out: 158*65523Spendry pfsvplock &= ~PROCFS_LOCKED; 159*65523Spendry 160*65523Spendry if (pfsvplock & PROCFS_WANT) { 161*65523Spendry pfsvplock &= ~PROCFS_WANT; 162*65523Spendry wakeup((caddr_t) &pfsvplock); 163*65523Spendry } 164*65523Spendry 165*65523Spendry return (error); 166*65523Spendry } 167*65523Spendry 168*65523Spendry int 169*65523Spendry procfs_freevp(vp) 170*65523Spendry struct vnode *vp; 171*65523Spendry { 172*65523Spendry struct pfsnode **pfspp; 173*65523Spendry struct pfsnode *pfs = VTOPFS(vp); 174*65523Spendry 175*65523Spendry for (pfspp = &pfshead; *pfspp != 0; pfspp = &(*pfspp)->pfs_next) { 176*65523Spendry if (*pfspp == pfs) { 177*65523Spendry *pfspp = pfs->pfs_next; 178*65523Spendry break; 179*65523Spendry } 180*65523Spendry } 181*65523Spendry 182*65523Spendry FREE(vp->v_data, M_TEMP); 183*65523Spendry vp->v_data = 0; 184*65523Spendry return (0); 185*65523Spendry } 186*65523Spendry 187*65523Spendry int 188*65523Spendry procfs_rw(ap) 189*65523Spendry struct vop_read_args *ap; 190*65523Spendry { 191*65523Spendry struct vnode *vp = ap->a_vp; 192*65523Spendry struct uio *uio = ap->a_uio; 193*65523Spendry struct proc *curp = uio->uio_procp; 194*65523Spendry struct pfsnode *pfs = VTOPFS(vp); 195*65523Spendry struct proc *p; 196*65523Spendry 197*65523Spendry p = PFIND(pfs->pfs_pid); 198*65523Spendry if (p == 0) 199*65523Spendry return (EINVAL); 200*65523Spendry 201*65523Spendry switch (pfs->pfs_type) { 202*65523Spendry case Pnote: 203*65523Spendry case Pnotepg: 204*65523Spendry return (procfs_donote(curp, p, pfs, uio)); 205*65523Spendry 206*65523Spendry case Pregs: 207*65523Spendry return (procfs_doregs(curp, p, pfs, uio)); 208*65523Spendry 209*65523Spendry case Pctl: 210*65523Spendry return (procfs_doctl(curp, p, pfs, uio)); 211*65523Spendry 212*65523Spendry case Pstatus: 213*65523Spendry return (procfs_dostatus(curp, p, pfs, uio)); 214*65523Spendry 215*65523Spendry case Pmem: 216*65523Spendry return (procfs_domem(curp, p, pfs, uio)); 217*65523Spendry 218*65523Spendry default: 219*65523Spendry return (EOPNOTSUPP); 220*65523Spendry } 221*65523Spendry } 222*65523Spendry 223*65523Spendry /* 224*65523Spendry * Get a string from userland into (buf). Strip a trailing 225*65523Spendry * nl character (to allow easy access from the shell). 226*65523Spendry * The buffer should be *buflenp + 1 chars long. vfs_getuserstr 227*65523Spendry * will automatically add a nul char at the end. 228*65523Spendry * 229*65523Spendry * Returns 0 on success or the following errors 230*65523Spendry * 231*65523Spendry * EINVAL: file offset is non-zero. 232*65523Spendry * EMSGSIZE: message is longer than kernel buffer 233*65523Spendry * EFAULT: user i/o buffer is not addressable 234*65523Spendry */ 235*65523Spendry int 236*65523Spendry vfs_getuserstr(uio, buf, buflenp) 237*65523Spendry struct uio *uio; 238*65523Spendry char *buf; 239*65523Spendry int *buflenp; 240*65523Spendry { 241*65523Spendry int xlen; 242*65523Spendry int error; 243*65523Spendry 244*65523Spendry if (uio->uio_offset != 0) 245*65523Spendry return (EINVAL); 246*65523Spendry 247*65523Spendry xlen = *buflenp; 248*65523Spendry 249*65523Spendry /* must be able to read the whole string in one go */ 250*65523Spendry if (xlen < uio->uio_resid) 251*65523Spendry return (EMSGSIZE); 252*65523Spendry xlen = uio->uio_resid; 253*65523Spendry 254*65523Spendry error = uiomove(buf, xlen, uio); 255*65523Spendry if (error) 256*65523Spendry return (error); 257*65523Spendry 258*65523Spendry /* allow multiple writes without seeks */ 259*65523Spendry uio->uio_offset = 0; 260*65523Spendry 261*65523Spendry /* cleanup string and remove trailing newline */ 262*65523Spendry buf[xlen] = '\0'; 263*65523Spendry xlen = strlen(buf); 264*65523Spendry if (xlen > 0 && buf[xlen-1] == '\n') 265*65523Spendry buf[--xlen] = '\0'; 266*65523Spendry *buflenp = xlen; 267*65523Spendry 268*65523Spendry return (0); 269*65523Spendry } 270*65523Spendry 271*65523Spendry vfs_namemap_t * 272*65523Spendry vfs_findname(nm, buf, buflen) 273*65523Spendry vfs_namemap_t *nm; 274*65523Spendry char *buf; 275*65523Spendry int buflen; 276*65523Spendry { 277*65523Spendry for (; nm->nm_name; nm++) 278*65523Spendry if (bcmp(buf, (char *) nm->nm_name, buflen+1) == 0) 279*65523Spendry return (nm); 280*65523Spendry 281*65523Spendry return (0); 282*65523Spendry } 283