1*65524Spendry /* 2*65524Spendry * Copyright (c) 1993 The Regents of the University of California. 3*65524Spendry * Copyright (c) 1993 Jan-Simon Pendry 4*65524Spendry * All rights reserved. 5*65524Spendry * 6*65524Spendry * This code is derived from software contributed to Berkeley by 7*65524Spendry * Jan-Simon Pendry. 8*65524Spendry * 9*65524Spendry * %sccs.include.redist.c% 10*65524Spendry * 11*65524Spendry * @(#)procfs_vnops.c 8.1 (Berkeley) 01/05/94 12*65524Spendry * 13*65524Spendry * From: 14*65524Spendry * $Id: procfs_vnops.c,v 3.2 1993/12/15 09:40:17 jsp Exp $ 15*65524Spendry */ 16*65524Spendry 17*65524Spendry /* 18*65524Spendry * procfs vnode interface 19*65524Spendry */ 20*65524Spendry 21*65524Spendry #include <sys/param.h> 22*65524Spendry #include <sys/systm.h> 23*65524Spendry #include <sys/time.h> 24*65524Spendry #include <sys/kernel.h> 25*65524Spendry #include <sys/file.h> 26*65524Spendry #include <sys/proc.h> 27*65524Spendry #include <sys/vnode.h> 28*65524Spendry #include <sys/namei.h> 29*65524Spendry #include <sys/malloc.h> 30*65524Spendry #include <sys/dirent.h> 31*65524Spendry #include <sys/resourcevar.h> 32*65524Spendry #include <miscfs/procfs/procfs.h> 33*65524Spendry #include <vm/vm.h> /* for PAGE_SIZE */ 34*65524Spendry 35*65524Spendry /* 36*65524Spendry * Vnode Operations. 37*65524Spendry * 38*65524Spendry */ 39*65524Spendry 40*65524Spendry /* 41*65524Spendry * This is a list of the valid names in the 42*65524Spendry * process-specific sub-directories. It is 43*65524Spendry * used in procfs_lookup and procfs_readdir 44*65524Spendry */ 45*65524Spendry static struct pfsnames { 46*65524Spendry u_short d_namlen; 47*65524Spendry char d_name[PROCFS_NAMELEN]; 48*65524Spendry pfstype d_pfstype; 49*65524Spendry } procent[] = { 50*65524Spendry #define N(s) sizeof(s)-1, s 51*65524Spendry /* namlen, nam, type */ 52*65524Spendry { N("file"), Pfile }, 53*65524Spendry { N("mem"), Pmem }, 54*65524Spendry { N("regs"), Pregs }, 55*65524Spendry { N("ctl"), Pctl }, 56*65524Spendry { N("status"), Pstatus }, 57*65524Spendry { N("note"), Pnote }, 58*65524Spendry { N("notepg"), Pnotepg }, 59*65524Spendry #undef N 60*65524Spendry }; 61*65524Spendry #define Nprocent (sizeof(procent)/sizeof(procent[0])) 62*65524Spendry 63*65524Spendry static pid_t atopid __P((const char *, u_int)); 64*65524Spendry 65*65524Spendry /* 66*65524Spendry * set things up for doing i/o on 67*65524Spendry * the pfsnode (vp). (vp) is locked 68*65524Spendry * on entry, and should be left locked 69*65524Spendry * on exit. 70*65524Spendry * 71*65524Spendry * for procfs we don't need to do anything 72*65524Spendry * in particular for i/o. all that is done 73*65524Spendry * is to support exclusive open on process 74*65524Spendry * memory images. 75*65524Spendry */ 76*65524Spendry procfs_open(ap) 77*65524Spendry struct vop_open_args *ap; 78*65524Spendry { 79*65524Spendry struct pfsnode *pfs = VTOPFS(ap->a_vp); 80*65524Spendry 81*65524Spendry switch (pfs->pfs_type) { 82*65524Spendry case Pmem: 83*65524Spendry if (PFIND(pfs->pfs_pid) == 0) 84*65524Spendry return (ENOENT); /* was ESRCH, jsp */ 85*65524Spendry 86*65524Spendry if ((pfs->pfs_flags & FWRITE) && (ap->a_mode & O_EXCL) || 87*65524Spendry (pfs->pfs_flags & O_EXCL) && (ap->a_mode & FWRITE)) 88*65524Spendry return (EBUSY); 89*65524Spendry 90*65524Spendry 91*65524Spendry if (ap->a_mode & FWRITE) 92*65524Spendry pfs->pfs_flags = ap->a_mode & (FWRITE|O_EXCL); 93*65524Spendry 94*65524Spendry return (0); 95*65524Spendry 96*65524Spendry default: 97*65524Spendry break; 98*65524Spendry } 99*65524Spendry 100*65524Spendry return (0); 101*65524Spendry } 102*65524Spendry 103*65524Spendry /* 104*65524Spendry * close the pfsnode (vp) after doing i/o. 105*65524Spendry * (vp) is not locked on entry or exit. 106*65524Spendry * 107*65524Spendry * nothing to do for procfs other than undo 108*65524Spendry * any exclusive open flag (see _open above). 109*65524Spendry */ 110*65524Spendry procfs_close(ap) 111*65524Spendry struct vop_close_args *ap; 112*65524Spendry { 113*65524Spendry struct pfsnode *pfs = VTOPFS(ap->a_vp); 114*65524Spendry 115*65524Spendry switch (pfs->pfs_type) { 116*65524Spendry case Pmem: 117*65524Spendry if ((ap->a_fflag & FWRITE) && (pfs->pfs_flags & O_EXCL)) 118*65524Spendry pfs->pfs_flags &= ~(FWRITE|O_EXCL); 119*65524Spendry break; 120*65524Spendry } 121*65524Spendry 122*65524Spendry return (0); 123*65524Spendry } 124*65524Spendry 125*65524Spendry /* 126*65524Spendry * do an ioctl operation on pfsnode (vp). 127*65524Spendry * (vp) is not locked on entry or exit. 128*65524Spendry */ 129*65524Spendry procfs_ioctl(ap) 130*65524Spendry struct vop_ioctl_args *ap; 131*65524Spendry { 132*65524Spendry 133*65524Spendry return (ENOTTY); 134*65524Spendry } 135*65524Spendry 136*65524Spendry /* 137*65524Spendry * do block mapping for pfsnode (vp). 138*65524Spendry * since we don't use the buffer cache 139*65524Spendry * for procfs this function should never 140*65524Spendry * be called. in any case, it's not clear 141*65524Spendry * what part of the kernel ever makes use 142*65524Spendry * of this function. for sanity, this is the 143*65524Spendry * usual no-op bmap, although returning 144*65524Spendry * (EIO) would be a reasonable alternative. 145*65524Spendry */ 146*65524Spendry procfs_bmap(ap) 147*65524Spendry struct vop_bmap_args *ap; 148*65524Spendry { 149*65524Spendry 150*65524Spendry if (ap->a_vpp != NULL) 151*65524Spendry *ap->a_vpp = ap->a_vp; 152*65524Spendry if (ap->a_bnp != NULL) 153*65524Spendry *ap->a_bnp = ap->a_bn; 154*65524Spendry return (0); 155*65524Spendry } 156*65524Spendry 157*65524Spendry /* 158*65524Spendry * _inactive is called when the pfsnode 159*65524Spendry * is vrele'd and the reference count goes 160*65524Spendry * to zero. (vp) will be on the vnode free 161*65524Spendry * list, so to get it back vget() must be 162*65524Spendry * used. 163*65524Spendry * 164*65524Spendry * for procfs, check if the process is still 165*65524Spendry * alive and if it isn't then just throw away 166*65524Spendry * the vnode by calling vgone(). this may 167*65524Spendry * be overkill and a waste of time since the 168*65524Spendry * chances are that the process will still be 169*65524Spendry * there and PFIND is not free. 170*65524Spendry * 171*65524Spendry * (vp) is not locked on entry or exit. 172*65524Spendry */ 173*65524Spendry procfs_inactive(ap) 174*65524Spendry struct vop_inactive_args *ap; 175*65524Spendry { 176*65524Spendry struct pfsnode *pfs = VTOPFS(ap->a_vp); 177*65524Spendry 178*65524Spendry if (PFIND(pfs->pfs_pid) == 0) 179*65524Spendry vgone(ap->a_vp); 180*65524Spendry 181*65524Spendry return (0); 182*65524Spendry } 183*65524Spendry 184*65524Spendry /* 185*65524Spendry * _reclaim is called when getnewvnode() 186*65524Spendry * wants to make use of an entry on the vnode 187*65524Spendry * free list. at this time the filesystem needs 188*65524Spendry * to free any private data and remove the node 189*65524Spendry * from any private lists. 190*65524Spendry */ 191*65524Spendry procfs_reclaim(ap) 192*65524Spendry struct vop_reclaim_args *ap; 193*65524Spendry { 194*65524Spendry int error; 195*65524Spendry 196*65524Spendry error = procfs_freevp(ap->a_vp); 197*65524Spendry return (error); 198*65524Spendry } 199*65524Spendry 200*65524Spendry /* 201*65524Spendry * _print is used for debugging. 202*65524Spendry * just print a readable description 203*65524Spendry * of (vp). 204*65524Spendry */ 205*65524Spendry procfs_print(ap) 206*65524Spendry struct vop_print_args *ap; 207*65524Spendry { 208*65524Spendry struct pfsnode *pfs = VTOPFS(ap->a_vp); 209*65524Spendry 210*65524Spendry printf("tag VT_PROCFS, pid %d, mode %x, flags %x\n", 211*65524Spendry pfs->pfs_pid, 212*65524Spendry pfs->pfs_mode, pfs->pfs_flags); 213*65524Spendry } 214*65524Spendry 215*65524Spendry /* 216*65524Spendry * _abortop is called when operations such as 217*65524Spendry * rename and create fail. this entry is responsible 218*65524Spendry * for undoing any side-effects caused by the lookup. 219*65524Spendry * this will always include freeing the pathname buffer. 220*65524Spendry */ 221*65524Spendry procfs_abortop(ap) 222*65524Spendry struct vop_abortop_args *ap; 223*65524Spendry { 224*65524Spendry 225*65524Spendry if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF) 226*65524Spendry FREE(ap->a_cnp->cn_pnbuf, M_NAMEI); 227*65524Spendry return (0); 228*65524Spendry } 229*65524Spendry 230*65524Spendry /* 231*65524Spendry * generic entry point for unsupported operations 232*65524Spendry */ 233*65524Spendry procfs_badop() 234*65524Spendry { 235*65524Spendry 236*65524Spendry return (EIO); 237*65524Spendry } 238*65524Spendry 239*65524Spendry /* 240*65524Spendry * Invent attributes for pfsnode (vp) and store 241*65524Spendry * them in (vap). 242*65524Spendry * Directories lengths are returned as zero since 243*65524Spendry * any real length would require the genuine size 244*65524Spendry * to be computed, and nothing cares anyway. 245*65524Spendry * 246*65524Spendry * this is relatively minimal for procfs. 247*65524Spendry */ 248*65524Spendry procfs_getattr(ap) 249*65524Spendry struct vop_getattr_args *ap; 250*65524Spendry { 251*65524Spendry struct pfsnode *pfs = VTOPFS(ap->a_vp); 252*65524Spendry struct proc *procp; 253*65524Spendry int error; 254*65524Spendry 255*65524Spendry /* first check the process still exists */ 256*65524Spendry procp = PFIND(pfs->pfs_pid); 257*65524Spendry if (procp == 0) 258*65524Spendry return (ENOENT); 259*65524Spendry 260*65524Spendry error = 0; 261*65524Spendry 262*65524Spendry /* start by zeroing out the attributes */ 263*65524Spendry VATTR_NULL(ap->a_vap); 264*65524Spendry 265*65524Spendry /* next do all the common fields */ 266*65524Spendry (ap->a_vap)->va_type = ap->a_vp->v_type; 267*65524Spendry (ap->a_vap)->va_mode = pfs->pfs_mode; 268*65524Spendry (ap->a_vap)->va_fileid = pfs->pfs_fileno; 269*65524Spendry (ap->a_vap)->va_flags = 0; 270*65524Spendry (ap->a_vap)->va_blocksize = PAGE_SIZE; 271*65524Spendry (ap->a_vap)->va_bytes = ap->a_vap->va_size = 0; 272*65524Spendry 273*65524Spendry /* 274*65524Spendry * Make all times be current TOD. 275*65524Spendry * It would be possible to get the process start 276*65524Spendry * time from the p_stat structure, but there's 277*65524Spendry * no "file creation" time stamp anyway, and the 278*65524Spendry * p_stat structure is not addressible if u. gets 279*65524Spendry * swapped out for that process. 280*65524Spendry */ 281*65524Spendry microtime(&(ap->a_vap)->va_ctime); 282*65524Spendry (ap->a_vap)->va_atime = ap->a_vap->va_mtime = ap->a_vap->va_ctime; 283*65524Spendry 284*65524Spendry /* 285*65524Spendry * now do the object specific fields 286*65524Spendry * 287*65524Spendry * The size could be set from struct reg, but it's hardly 288*65524Spendry * worth the trouble, and it puts some (potentially) machine 289*65524Spendry * dependent data into this machine-independent code. If it 290*65524Spendry * becomes important then this function should break out into 291*65524Spendry * a per-file stat function in the corresponding .c file. 292*65524Spendry */ 293*65524Spendry 294*65524Spendry switch (pfs->pfs_type) { 295*65524Spendry case Proot: 296*65524Spendry ap->a_vap->va_nlink = 2; 297*65524Spendry ap->a_vap->va_uid = 0; 298*65524Spendry ap->a_vap->va_gid = 0; 299*65524Spendry break; 300*65524Spendry 301*65524Spendry case Pproc: 302*65524Spendry ap->a_vap->va_nlink = 2; 303*65524Spendry ap->a_vap->va_uid = procp->p_ucred->cr_uid; 304*65524Spendry ap->a_vap->va_gid = procp->p_ucred->cr_gid; 305*65524Spendry break; 306*65524Spendry 307*65524Spendry case Pfile: 308*65524Spendry error = EOPNOTSUPP; 309*65524Spendry break; 310*65524Spendry 311*65524Spendry case Pmem: 312*65524Spendry ap->a_vap->va_nlink = 1; 313*65524Spendry ap->a_vap->va_bytes = ap->a_vap->va_size = 314*65524Spendry ctob(procp->p_vmspace->vm_tsize + 315*65524Spendry procp->p_vmspace->vm_dsize + 316*65524Spendry procp->p_vmspace->vm_ssize); 317*65524Spendry ap->a_vap->va_uid = procp->p_ucred->cr_uid; 318*65524Spendry ap->a_vap->va_gid = procp->p_ucred->cr_gid; 319*65524Spendry break; 320*65524Spendry 321*65524Spendry case Pregs: 322*65524Spendry case Pctl: 323*65524Spendry case Pstatus: 324*65524Spendry case Pnote: 325*65524Spendry case Pnotepg: 326*65524Spendry ap->a_vap->va_nlink = 1; 327*65524Spendry ap->a_vap->va_uid = procp->p_ucred->cr_uid; 328*65524Spendry ap->a_vap->va_gid = procp->p_ucred->cr_gid; 329*65524Spendry break; 330*65524Spendry 331*65524Spendry default: 332*65524Spendry panic("procfs_getattr"); 333*65524Spendry } 334*65524Spendry 335*65524Spendry return (error); 336*65524Spendry } 337*65524Spendry 338*65524Spendry procfs_setattr(ap) 339*65524Spendry struct vop_setattr_args *ap; 340*65524Spendry { 341*65524Spendry /* 342*65524Spendry * just fake out attribute setting 343*65524Spendry * it's not good to generate an error 344*65524Spendry * return, otherwise things like creat() 345*65524Spendry * will fail when they try to set the 346*65524Spendry * file length to 0. worse, this means 347*65524Spendry * that echo $note > /proc/$pid/note will fail. 348*65524Spendry */ 349*65524Spendry 350*65524Spendry return (0); 351*65524Spendry } 352*65524Spendry 353*65524Spendry /* 354*65524Spendry * implement access checking. 355*65524Spendry * 356*65524Spendry * something very similar to this code is duplicated 357*65524Spendry * throughout the 4bsd kernel and should be moved 358*65524Spendry * into kern/vfs_subr.c sometime. 359*65524Spendry * 360*65524Spendry * actually, the check for super-user is slightly 361*65524Spendry * broken since it will allow read access to write-only 362*65524Spendry * objects. this doesn't cause any particular trouble 363*65524Spendry * but does mean that the i/o entry points need to check 364*65524Spendry * that the operation really does make sense. 365*65524Spendry */ 366*65524Spendry procfs_access(ap) 367*65524Spendry struct vop_access_args *ap; 368*65524Spendry { 369*65524Spendry struct vattr *vap; 370*65524Spendry struct vattr vattr; 371*65524Spendry int error; 372*65524Spendry 373*65524Spendry /* 374*65524Spendry * If you're the super-user, 375*65524Spendry * you always get access. 376*65524Spendry */ 377*65524Spendry if (ap->a_cred->cr_uid == (uid_t) 0) 378*65524Spendry return (0); 379*65524Spendry vap = &vattr; 380*65524Spendry if (error = VOP_GETATTR(ap->a_vp, vap, ap->a_cred, ap->a_p)) 381*65524Spendry return (error); 382*65524Spendry 383*65524Spendry /* 384*65524Spendry * Access check is based on only one of owner, group, public. 385*65524Spendry * If not owner, then check group. If not a member of the 386*65524Spendry * group, then check public access. 387*65524Spendry */ 388*65524Spendry if (ap->a_cred->cr_uid != vap->va_uid) { 389*65524Spendry gid_t *gp; 390*65524Spendry int i; 391*65524Spendry 392*65524Spendry (ap->a_mode) >>= 3; 393*65524Spendry gp = ap->a_cred->cr_groups; 394*65524Spendry for (i = 0; i < ap->a_cred->cr_ngroups; i++, gp++) 395*65524Spendry if (vap->va_gid == *gp) 396*65524Spendry goto found; 397*65524Spendry ap->a_mode >>= 3; 398*65524Spendry found: 399*65524Spendry ; 400*65524Spendry } 401*65524Spendry 402*65524Spendry if ((vap->va_mode & ap->a_mode) == ap->a_mode) 403*65524Spendry return (0); 404*65524Spendry 405*65524Spendry return (EACCES); 406*65524Spendry } 407*65524Spendry 408*65524Spendry /* 409*65524Spendry * lookup. this is incredibly complicated in the 410*65524Spendry * general case, however for most pseudo-filesystems 411*65524Spendry * very little needs to be done. 412*65524Spendry * 413*65524Spendry * unless you want to get a migraine, just make sure your 414*65524Spendry * filesystem doesn't do any locking of its own. otherwise 415*65524Spendry * read and inwardly digest ufs_lookup(). 416*65524Spendry */ 417*65524Spendry procfs_lookup(ap) 418*65524Spendry struct vop_lookup_args *ap; 419*65524Spendry { 420*65524Spendry struct componentname *cnp = ap->a_cnp; 421*65524Spendry struct vnode **vpp = ap->a_vpp; 422*65524Spendry struct vnode *dvp = ap->a_dvp; 423*65524Spendry char *pname = cnp->cn_nameptr; 424*65524Spendry int error = 0; 425*65524Spendry int flag; 426*65524Spendry pid_t pid; 427*65524Spendry struct vnode *nvp; 428*65524Spendry struct pfsnode *pfs; 429*65524Spendry struct proc *procp; 430*65524Spendry int mode; 431*65524Spendry pfstype pfs_type; 432*65524Spendry int i; 433*65524Spendry 434*65524Spendry if (cnp->cn_namelen == 1 && *pname == '.') { 435*65524Spendry *vpp = dvp; 436*65524Spendry VREF(dvp); 437*65524Spendry /*VOP_LOCK(dvp);*/ 438*65524Spendry return (0); 439*65524Spendry } 440*65524Spendry 441*65524Spendry *vpp = NULL; 442*65524Spendry 443*65524Spendry pfs = VTOPFS(dvp); 444*65524Spendry switch (pfs->pfs_type) { 445*65524Spendry case Proot: 446*65524Spendry if (cnp->cn_flags & ISDOTDOT) 447*65524Spendry return (EIO); 448*65524Spendry 449*65524Spendry if (CNEQ(cnp, "curproc", 7)) 450*65524Spendry pid = cnp->cn_proc->p_pid; 451*65524Spendry else 452*65524Spendry pid = atopid(pname, cnp->cn_namelen); 453*65524Spendry if (pid == NO_PID) 454*65524Spendry return (ENOENT); 455*65524Spendry 456*65524Spendry procp = PFIND(pid); 457*65524Spendry if (procp == 0) 458*65524Spendry return (ENOENT); 459*65524Spendry 460*65524Spendry error = procfs_allocvp(dvp->v_mount, &nvp, pid, Pproc); 461*65524Spendry if (error) 462*65524Spendry return (error); 463*65524Spendry 464*65524Spendry nvp->v_type = VDIR; 465*65524Spendry pfs = VTOPFS(nvp); 466*65524Spendry 467*65524Spendry *vpp = nvp; 468*65524Spendry return (0); 469*65524Spendry 470*65524Spendry case Pproc: 471*65524Spendry if (cnp->cn_flags & ISDOTDOT) { 472*65524Spendry error = procfs_root(dvp->v_mount, vpp); 473*65524Spendry return (error); 474*65524Spendry } 475*65524Spendry 476*65524Spendry procp = PFIND(pfs->pfs_pid); 477*65524Spendry if (procp == 0) 478*65524Spendry return (ENOENT); 479*65524Spendry 480*65524Spendry for (i = 0; i < Nprocent; i++) { 481*65524Spendry struct pfsnames *dp = &procent[i]; 482*65524Spendry 483*65524Spendry if (cnp->cn_namelen == dp->d_namlen && 484*65524Spendry bcmp(pname, dp->d_name, dp->d_namlen) == 0) { 485*65524Spendry pfs_type = dp->d_pfstype; 486*65524Spendry goto found; 487*65524Spendry } 488*65524Spendry } 489*65524Spendry return (ENOENT); 490*65524Spendry 491*65524Spendry found: 492*65524Spendry if (pfs_type == Pfile) { 493*65524Spendry nvp = procfs_findtextvp(procp); 494*65524Spendry if (nvp) { 495*65524Spendry VREF(nvp); 496*65524Spendry VOP_LOCK(nvp); 497*65524Spendry } else { 498*65524Spendry error = ENXIO; 499*65524Spendry } 500*65524Spendry } else { 501*65524Spendry error = procfs_allocvp(dvp->v_mount, &nvp, 502*65524Spendry pfs->pfs_pid, pfs_type); 503*65524Spendry if (error) 504*65524Spendry return (error); 505*65524Spendry 506*65524Spendry nvp->v_type = VREG; 507*65524Spendry pfs = VTOPFS(nvp); 508*65524Spendry } 509*65524Spendry *vpp = nvp; 510*65524Spendry return (error); 511*65524Spendry 512*65524Spendry default: 513*65524Spendry return (ENOTDIR); 514*65524Spendry } 515*65524Spendry } 516*65524Spendry 517*65524Spendry /* 518*65524Spendry * readdir returns directory entries from pfsnode (vp). 519*65524Spendry * 520*65524Spendry * the strategy here with procfs is to generate a single 521*65524Spendry * directory entry at a time (struct pfsdent) and then 522*65524Spendry * copy that out to userland using uiomove. a more efficent 523*65524Spendry * though more complex implementation, would try to minimize 524*65524Spendry * the number of calls to uiomove(). for procfs, this is 525*65524Spendry * hardly worth the added code complexity. 526*65524Spendry * 527*65524Spendry * this should just be done through read() 528*65524Spendry */ 529*65524Spendry procfs_readdir(ap) 530*65524Spendry struct vop_readdir_args *ap; 531*65524Spendry { 532*65524Spendry struct uio *uio = ap->a_uio; 533*65524Spendry struct pfsdent d; 534*65524Spendry struct pfsdent *dp = &d; 535*65524Spendry struct pfsnode *pfs; 536*65524Spendry int error; 537*65524Spendry int count; 538*65524Spendry int i; 539*65524Spendry 540*65524Spendry pfs = VTOPFS(ap->a_vp); 541*65524Spendry 542*65524Spendry if (uio->uio_resid < UIO_MX) 543*65524Spendry return (EINVAL); 544*65524Spendry if (uio->uio_offset & (UIO_MX-1)) 545*65524Spendry return (EINVAL); 546*65524Spendry if (uio->uio_offset < 0) 547*65524Spendry return (EINVAL); 548*65524Spendry 549*65524Spendry error = 0; 550*65524Spendry count = 0; 551*65524Spendry i = uio->uio_offset / UIO_MX; 552*65524Spendry 553*65524Spendry switch (pfs->pfs_type) { 554*65524Spendry /* 555*65524Spendry * this is for the process-specific sub-directories. 556*65524Spendry * all that is needed to is copy out all the entries 557*65524Spendry * from the procent[] table (top of this file). 558*65524Spendry */ 559*65524Spendry case Pproc: { 560*65524Spendry while (uio->uio_resid >= UIO_MX) { 561*65524Spendry struct pfsnames *dt; 562*65524Spendry 563*65524Spendry if (i >= Nprocent) 564*65524Spendry break; 565*65524Spendry 566*65524Spendry dt = &procent[i]; 567*65524Spendry 568*65524Spendry dp->d_reclen = UIO_MX; 569*65524Spendry dp->d_fileno = PROCFS_FILENO(pfs->pfs_pid, dt->d_pfstype); 570*65524Spendry dp->d_type = DT_REG; 571*65524Spendry dp->d_namlen = dt->d_namlen; 572*65524Spendry bcopy(dt->d_name, dp->d_name, sizeof(dt->d_name)-1); 573*65524Spendry error = uiomove((caddr_t) dp, UIO_MX, uio); 574*65524Spendry if (error) 575*65524Spendry break; 576*65524Spendry count += UIO_MX; 577*65524Spendry i++; 578*65524Spendry } 579*65524Spendry 580*65524Spendry break; 581*65524Spendry 582*65524Spendry } 583*65524Spendry 584*65524Spendry /* 585*65524Spendry * this is for the root of the procfs filesystem 586*65524Spendry * what is needed is a special entry for "curproc" 587*65524Spendry * followed by an entry for each process on allproc 588*65524Spendry #ifdef PROCFS_ZOMBIE 589*65524Spendry * and zombproc. 590*65524Spendry #endif 591*65524Spendry */ 592*65524Spendry 593*65524Spendry case Proot: { 594*65524Spendry int pcnt; 595*65524Spendry #ifdef PROCFS_ZOMBIE 596*65524Spendry int doingzomb = 0; 597*65524Spendry #endif 598*65524Spendry volatile struct proc *p; 599*65524Spendry 600*65524Spendry p = allproc; 601*65524Spendry 602*65524Spendry #define PROCFS_XFILES 1 /* number of other entries, like "curproc" */ 603*65524Spendry pcnt = PROCFS_XFILES; 604*65524Spendry 605*65524Spendry while (p && uio->uio_resid >= UIO_MX) { 606*65524Spendry bzero((char *) dp, UIO_MX); 607*65524Spendry dp->d_type = DT_DIR; 608*65524Spendry dp->d_reclen = UIO_MX; 609*65524Spendry 610*65524Spendry switch (i) { 611*65524Spendry case 0: 612*65524Spendry /* ship out entry for "curproc" */ 613*65524Spendry dp->d_fileno = PROCFS_FILENO(PID_MAX+1, Pproc); 614*65524Spendry dp->d_namlen = 7; 615*65524Spendry bcopy("curproc", dp->d_name, dp->d_namlen+1); 616*65524Spendry break; 617*65524Spendry 618*65524Spendry default: 619*65524Spendry if (pcnt >= i) { 620*65524Spendry dp->d_fileno = PROCFS_FILENO(p->p_pid, Pproc); 621*65524Spendry dp->d_namlen = sprintf(dp->d_name, "%ld", (long) p->p_pid); 622*65524Spendry } 623*65524Spendry 624*65524Spendry p = p->p_next; 625*65524Spendry 626*65524Spendry #ifdef PROCFS_ZOMBIE 627*65524Spendry if (p == 0 && doingzomb == 0) { 628*65524Spendry doingzomb = 1; 629*65524Spendry p = zombproc; 630*65524Spendry } 631*65524Spendry #endif 632*65524Spendry 633*65524Spendry if (pcnt++ < i) 634*65524Spendry continue; 635*65524Spendry 636*65524Spendry break; 637*65524Spendry } 638*65524Spendry error = uiomove((caddr_t) dp, UIO_MX, uio); 639*65524Spendry if (error) 640*65524Spendry break; 641*65524Spendry count += UIO_MX; 642*65524Spendry i++; 643*65524Spendry } 644*65524Spendry 645*65524Spendry break; 646*65524Spendry 647*65524Spendry } 648*65524Spendry 649*65524Spendry default: 650*65524Spendry error = ENOTDIR; 651*65524Spendry break; 652*65524Spendry } 653*65524Spendry 654*65524Spendry uio->uio_offset = i * UIO_MX; 655*65524Spendry 656*65524Spendry return (error); 657*65524Spendry } 658*65524Spendry 659*65524Spendry /* 660*65524Spendry * convert decimal ascii to pid_t 661*65524Spendry */ 662*65524Spendry static pid_t 663*65524Spendry atopid(b, len) 664*65524Spendry const char *b; 665*65524Spendry u_int len; 666*65524Spendry { 667*65524Spendry pid_t p = 0; 668*65524Spendry 669*65524Spendry while (len--) { 670*65524Spendry char c = *b++; 671*65524Spendry if (c < '0' || c > '9') 672*65524Spendry return (NO_PID); 673*65524Spendry p = 10 * p + (c - '0'); 674*65524Spendry if (p > PID_MAX) 675*65524Spendry return (NO_PID); 676*65524Spendry } 677*65524Spendry 678*65524Spendry return (p); 679*65524Spendry } 680*65524Spendry 681*65524Spendry /* 682*65524Spendry * procfs vnode operations. 683*65524Spendry */ 684*65524Spendry int (**procfs_vnodeop_p)(); 685*65524Spendry struct vnodeopv_entry_desc procfs_vnodeop_entries[] = { 686*65524Spendry { &vop_default_desc, vn_default_error }, 687*65524Spendry { &vop_lookup_desc, procfs_lookup }, /* lookup */ 688*65524Spendry { &vop_create_desc, procfs_create }, /* create */ 689*65524Spendry { &vop_mknod_desc, procfs_mknod }, /* mknod */ 690*65524Spendry { &vop_open_desc, procfs_open }, /* open */ 691*65524Spendry { &vop_close_desc, procfs_close }, /* close */ 692*65524Spendry { &vop_access_desc, procfs_access }, /* access */ 693*65524Spendry { &vop_getattr_desc, procfs_getattr }, /* getattr */ 694*65524Spendry { &vop_setattr_desc, procfs_setattr }, /* setattr */ 695*65524Spendry { &vop_read_desc, procfs_read }, /* read */ 696*65524Spendry { &vop_write_desc, procfs_write }, /* write */ 697*65524Spendry { &vop_ioctl_desc, procfs_ioctl }, /* ioctl */ 698*65524Spendry { &vop_select_desc, procfs_select }, /* select */ 699*65524Spendry { &vop_mmap_desc, procfs_mmap }, /* mmap */ 700*65524Spendry { &vop_fsync_desc, procfs_fsync }, /* fsync */ 701*65524Spendry { &vop_seek_desc, procfs_seek }, /* seek */ 702*65524Spendry { &vop_remove_desc, procfs_remove }, /* remove */ 703*65524Spendry { &vop_link_desc, procfs_link }, /* link */ 704*65524Spendry { &vop_rename_desc, procfs_rename }, /* rename */ 705*65524Spendry { &vop_mkdir_desc, procfs_mkdir }, /* mkdir */ 706*65524Spendry { &vop_rmdir_desc, procfs_rmdir }, /* rmdir */ 707*65524Spendry { &vop_symlink_desc, procfs_symlink }, /* symlink */ 708*65524Spendry { &vop_readdir_desc, procfs_readdir }, /* readdir */ 709*65524Spendry { &vop_readlink_desc, procfs_readlink }, /* readlink */ 710*65524Spendry { &vop_abortop_desc, procfs_abortop }, /* abortop */ 711*65524Spendry { &vop_inactive_desc, procfs_inactive }, /* inactive */ 712*65524Spendry { &vop_reclaim_desc, procfs_reclaim }, /* reclaim */ 713*65524Spendry { &vop_lock_desc, procfs_lock }, /* lock */ 714*65524Spendry { &vop_unlock_desc, procfs_unlock }, /* unlock */ 715*65524Spendry { &vop_bmap_desc, procfs_bmap }, /* bmap */ 716*65524Spendry { &vop_strategy_desc, procfs_strategy }, /* strategy */ 717*65524Spendry { &vop_print_desc, procfs_print }, /* print */ 718*65524Spendry { &vop_islocked_desc, procfs_islocked }, /* islocked */ 719*65524Spendry { &vop_pathconf_desc, procfs_pathconf }, /* pathconf */ 720*65524Spendry { &vop_advlock_desc, procfs_advlock }, /* advlock */ 721*65524Spendry { &vop_blkatoff_desc, procfs_blkatoff }, /* blkatoff */ 722*65524Spendry { &vop_valloc_desc, procfs_valloc }, /* valloc */ 723*65524Spendry { &vop_vfree_desc, procfs_vfree }, /* vfree */ 724*65524Spendry { &vop_truncate_desc, procfs_truncate }, /* truncate */ 725*65524Spendry { &vop_update_desc, procfs_update }, /* update */ 726*65524Spendry { (struct vnodeop_desc*)NULL, (int(*)())NULL } 727*65524Spendry }; 728*65524Spendry struct vnodeopv_desc procfs_vnodeop_opv_desc = 729*65524Spendry { &procfs_vnodeop_p, procfs_vnodeop_entries }; 730