|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* $NetBSD: procfs_vnops.c,v 1.32 1995/02/03 16:18:55 mycroft Exp $ */ ! 23: ! 24: /* ! 25: * Copyright (c) 1993 Jan-Simon Pendry ! 26: * Copyright (c) 1993 ! 27: * The Regents of the University of California. All rights reserved. ! 28: * ! 29: * This code is derived from software contributed to Berkeley by ! 30: * Jan-Simon Pendry. ! 31: * ! 32: * Redistribution and use in source and binary forms, with or without ! 33: * modification, are permitted provided that the following conditions ! 34: * are met: ! 35: * 1. Redistributions of source code must retain the above copyright ! 36: * notice, this list of conditions and the following disclaimer. ! 37: * 2. Redistributions in binary form must reproduce the above copyright ! 38: * notice, this list of conditions and the following disclaimer in the ! 39: * documentation and/or other materials provided with the distribution. ! 40: * 3. All advertising materials mentioning features or use of this software ! 41: * must display the following acknowledgement: ! 42: * This product includes software developed by the University of ! 43: * California, Berkeley and its contributors. ! 44: * 4. Neither the name of the University nor the names of its contributors ! 45: * may be used to endorse or promote products derived from this software ! 46: * without specific prior written permission. ! 47: * ! 48: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 49: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 50: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 51: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 52: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 53: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 54: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 55: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 56: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 57: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 58: * SUCH DAMAGE. ! 59: * ! 60: * @(#)procfs_vnops.c 8.8 (Berkeley) 6/15/94 ! 61: */ ! 62: ! 63: /* ! 64: * procfs vnode interface ! 65: */ ! 66: ! 67: #include <sys/param.h> ! 68: #include <sys/systm.h> ! 69: #include <sys/time.h> ! 70: #include <sys/kernel.h> ! 71: #include <sys/file.h> ! 72: #include <sys/proc.h> ! 73: #include <sys/vnode.h> ! 74: #include <sys/namei.h> ! 75: #include <sys/malloc.h> ! 76: #include <sys/dirent.h> ! 77: #include <sys/resourcevar.h> ! 78: #include <sys/ptrace.h> ! 79: #include <vm/vm.h> /* for PAGE_SIZE */ ! 80: #include <machine/reg.h> ! 81: #include <vfs/vfs_support.h> ! 82: #include <miscfs/procfs/procfs.h> ! 83: ! 84: /* ! 85: * Vnode Operations. ! 86: * ! 87: */ ! 88: ! 89: /* ! 90: * This is a list of the valid names in the ! 91: * process-specific sub-directories. It is ! 92: * used in procfs_lookup and procfs_readdir ! 93: */ ! 94: struct proc_target { ! 95: u_char pt_type; ! 96: u_char pt_namlen; ! 97: char *pt_name; ! 98: pfstype pt_pfstype; ! 99: int (*pt_valid) __P((struct proc *p)); ! 100: } proc_targets[] = { ! 101: #define N(s) sizeof(s)-1, s ! 102: /* name type validp */ ! 103: { DT_DIR, N("."), Pproc, NULL }, ! 104: { DT_DIR, N(".."), Proot, NULL }, ! 105: { DT_REG, N("file"), Pfile, procfs_validfile }, ! 106: { DT_REG, N("mem"), Pmem, NULL }, ! 107: { DT_REG, N("regs"), Pregs, procfs_validregs }, ! 108: { DT_REG, N("fpregs"), Pfpregs, procfs_validfpregs }, ! 109: { DT_REG, N("ctl"), Pctl, NULL }, ! 110: { DT_REG, N("status"), Pstatus, NULL }, ! 111: { DT_REG, N("note"), Pnote, NULL }, ! 112: { DT_REG, N("notepg"), Pnotepg, NULL }, ! 113: #undef N ! 114: }; ! 115: static int nproc_targets = sizeof(proc_targets) / sizeof(proc_targets[0]); ! 116: ! 117: static pid_t atopid __P((const char *, u_int)); ! 118: ! 119: /* ! 120: * set things up for doing i/o on ! 121: * the pfsnode (vp). (vp) is locked ! 122: * on entry, and should be left locked ! 123: * on exit. ! 124: * ! 125: * for procfs we don't need to do anything ! 126: * in particular for i/o. all that is done ! 127: * is to support exclusive open on process ! 128: * memory images. ! 129: */ ! 130: procfs_open(ap) ! 131: struct vop_open_args /* { ! 132: struct vnode *a_vp; ! 133: int a_mode; ! 134: struct ucred *a_cred; ! 135: struct proc *a_p; ! 136: } */ *ap; ! 137: { ! 138: struct pfsnode *pfs = VTOPFS(ap->a_vp); ! 139: ! 140: switch (pfs->pfs_type) { ! 141: case Pmem: ! 142: if (PFIND(pfs->pfs_pid) == 0) ! 143: return (ENOENT); /* was ESRCH, jsp */ ! 144: ! 145: if ((pfs->pfs_flags & FWRITE) && (ap->a_mode & O_EXCL) || ! 146: (pfs->pfs_flags & O_EXCL) && (ap->a_mode & FWRITE)) ! 147: return (EBUSY); ! 148: ! 149: if (ap->a_mode & FWRITE) ! 150: pfs->pfs_flags = ap->a_mode & (FWRITE|O_EXCL); ! 151: ! 152: return (0); ! 153: ! 154: default: ! 155: break; ! 156: } ! 157: ! 158: return (0); ! 159: } ! 160: ! 161: /* ! 162: * close the pfsnode (vp) after doing i/o. ! 163: * (vp) is not locked on entry or exit. ! 164: * ! 165: * nothing to do for procfs other than undo ! 166: * any exclusive open flag (see _open above). ! 167: */ ! 168: procfs_close(ap) ! 169: struct vop_close_args /* { ! 170: struct vnode *a_vp; ! 171: int a_fflag; ! 172: struct ucred *a_cred; ! 173: struct proc *a_p; ! 174: } */ *ap; ! 175: { ! 176: struct pfsnode *pfs = VTOPFS(ap->a_vp); ! 177: ! 178: switch (pfs->pfs_type) { ! 179: case Pmem: ! 180: if ((ap->a_fflag & FWRITE) && (pfs->pfs_flags & O_EXCL)) ! 181: pfs->pfs_flags &= ~(FWRITE|O_EXCL); ! 182: break; ! 183: } ! 184: ! 185: return (0); ! 186: } ! 187: ! 188: /* ! 189: * do an ioctl operation on pfsnode (vp). ! 190: * (vp) is not locked on entry or exit. ! 191: */ ! 192: procfs_ioctl(ap) ! 193: struct vop_ioctl_args /* { ! 194: struct vnode *a_vp; ! 195: u_long a_command; ! 196: caddr_t a_data; ! 197: int a_fflag; ! 198: struct ucred *a_cred; ! 199: struct proc *a_p; ! 200: } */ *ap; ! 201: { ! 202: ! 203: return (ENOTTY); ! 204: } ! 205: ! 206: /* ! 207: * do block mapping for pfsnode (vp). ! 208: * since we don't use the buffer cache ! 209: * for procfs this function should never ! 210: * be called. in any case, it's not clear ! 211: * what part of the kernel ever makes use ! 212: * of this function. for sanity, this is the ! 213: * usual no-op bmap, although returning ! 214: * (EIO) would be a reasonable alternative. ! 215: */ ! 216: procfs_bmap(ap) ! 217: struct vop_bmap_args /* { ! 218: struct vnode *a_vp; ! 219: daddr_t a_bn; ! 220: struct vnode **a_vpp; ! 221: daddr_t *a_bnp; ! 222: } */ *ap; ! 223: { ! 224: ! 225: if (ap->a_vpp != NULL) ! 226: *ap->a_vpp = ap->a_vp; ! 227: if (ap->a_bnp != NULL) ! 228: *ap->a_bnp = ap->a_bn; ! 229: return (0); ! 230: } ! 231: ! 232: /* ! 233: * _inactive is called when the pfsnode ! 234: * is vrele'd and the reference count goes ! 235: * to zero. (vp) will be on the vnode free ! 236: * list, so to get it back vget() must be ! 237: * used. ! 238: * ! 239: * for procfs, check if the process is still ! 240: * alive and if it isn't then just throw away ! 241: * the vnode by calling vgone(). this may ! 242: * be overkill and a waste of time since the ! 243: * chances are that the process will still be ! 244: * there and PFIND is not free. ! 245: * ! 246: * (vp) is not locked on entry or exit. ! 247: */ ! 248: procfs_inactive(ap) ! 249: struct vop_inactive_args /* { ! 250: struct vnode *a_vp; ! 251: } */ *ap; ! 252: { ! 253: struct pfsnode *pfs = VTOPFS(ap->a_vp); ! 254: ! 255: if (PFIND(pfs->pfs_pid) == 0) ! 256: vgone(ap->a_vp); ! 257: ! 258: return (0); ! 259: } ! 260: ! 261: /* ! 262: * _reclaim is called when getnewvnode() ! 263: * wants to make use of an entry on the vnode ! 264: * free list. at this time the filesystem needs ! 265: * to free any private data and remove the node ! 266: * from any private lists. ! 267: */ ! 268: procfs_reclaim(ap) ! 269: struct vop_reclaim_args /* { ! 270: struct vnode *a_vp; ! 271: } */ *ap; ! 272: { ! 273: ! 274: return (procfs_freevp(ap->a_vp)); ! 275: } ! 276: ! 277: /* ! 278: * Return POSIX pathconf information applicable to special devices. ! 279: */ ! 280: procfs_pathconf(ap) ! 281: struct vop_pathconf_args /* { ! 282: struct vnode *a_vp; ! 283: int a_name; ! 284: register_t *a_retval; ! 285: } */ *ap; ! 286: { ! 287: ! 288: switch (ap->a_name) { ! 289: case _PC_LINK_MAX: ! 290: *ap->a_retval = LINK_MAX; ! 291: return (0); ! 292: case _PC_MAX_CANON: ! 293: *ap->a_retval = MAX_CANON; ! 294: return (0); ! 295: case _PC_MAX_INPUT: ! 296: *ap->a_retval = MAX_INPUT; ! 297: return (0); ! 298: case _PC_PIPE_BUF: ! 299: *ap->a_retval = PIPE_BUF; ! 300: return (0); ! 301: case _PC_CHOWN_RESTRICTED: ! 302: *ap->a_retval = 1; ! 303: return (0); ! 304: case _PC_VDISABLE: ! 305: *ap->a_retval = _POSIX_VDISABLE; ! 306: return (0); ! 307: default: ! 308: return (EINVAL); ! 309: } ! 310: /* NOTREACHED */ ! 311: } ! 312: ! 313: /* ! 314: * _print is used for debugging. ! 315: * just print a readable description ! 316: * of (vp). ! 317: */ ! 318: procfs_print(ap) ! 319: struct vop_print_args /* { ! 320: struct vnode *a_vp; ! 321: } */ *ap; ! 322: { ! 323: struct pfsnode *pfs = VTOPFS(ap->a_vp); ! 324: ! 325: printf("tag VT_PROCFS, type %s, pid %d, mode %x, flags %x\n", ! 326: pfs->pfs_type, pfs->pfs_pid, pfs->pfs_mode, pfs->pfs_flags); ! 327: } ! 328: ! 329: /* ! 330: * _abortop is called when operations such as ! 331: * rename and create fail. this entry is responsible ! 332: * for undoing any side-effects caused by the lookup. ! 333: * this will always include freeing the pathname buffer. ! 334: */ ! 335: procfs_abortop(ap) ! 336: struct vop_abortop_args /* { ! 337: struct vnode *a_dvp; ! 338: struct componentname *a_cnp; ! 339: } */ *ap; ! 340: { ! 341: ! 342: if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF) ! 343: FREE_ZONE(ap->a_cnp->cn_pnbuf, ap->a_cnp->cn_pnlen, M_NAMEI); ! 344: return (0); ! 345: } ! 346: ! 347: /* ! 348: * generic entry point for unsupported operations ! 349: */ ! 350: procfs_badop() ! 351: { ! 352: ! 353: return (EIO); ! 354: } ! 355: ! 356: /* ! 357: * Invent attributes for pfsnode (vp) and store ! 358: * them in (vap). ! 359: * Directories lengths are returned as zero since ! 360: * any real length would require the genuine size ! 361: * to be computed, and nothing cares anyway. ! 362: * ! 363: * this is relatively minimal for procfs. ! 364: */ ! 365: procfs_getattr(ap) ! 366: struct vop_getattr_args /* { ! 367: struct vnode *a_vp; ! 368: struct vattr *a_vap; ! 369: struct ucred *a_cred; ! 370: struct proc *a_p; ! 371: } */ *ap; ! 372: { ! 373: struct pfsnode *pfs = VTOPFS(ap->a_vp); ! 374: struct vattr *vap = ap->a_vap; ! 375: struct proc *procp; ! 376: int error; ! 377: ! 378: /* first check the process still exists */ ! 379: switch (pfs->pfs_type) { ! 380: case Proot: ! 381: case Pcurproc: ! 382: procp = 0; ! 383: break; ! 384: ! 385: default: ! 386: procp = PFIND(pfs->pfs_pid); ! 387: if (procp == 0) ! 388: return (ENOENT); ! 389: } ! 390: ! 391: error = 0; ! 392: ! 393: /* start by zeroing out the attributes */ ! 394: VATTR_NULL(vap); ! 395: ! 396: /* next do all the common fields */ ! 397: vap->va_type = ap->a_vp->v_type; ! 398: vap->va_mode = pfs->pfs_mode; ! 399: vap->va_fileid = pfs->pfs_fileno; ! 400: vap->va_flags = 0; ! 401: vap->va_blocksize = PAGE_SIZE; ! 402: vap->va_bytes = vap->va_size = 0; ! 403: ! 404: /* ! 405: * Make all times be current TOD. ! 406: * It would be possible to get the process start ! 407: * time from the p_stat structure, but there's ! 408: * no "file creation" time stamp anyway, and the ! 409: * p_stat structure is not addressible if u. gets ! 410: * swapped out for that process. ! 411: * ! 412: * XXX ! 413: * Note that microtime() returns a timeval, not a timespec. ! 414: */ ! 415: microtime(&vap->va_ctime); ! 416: vap->va_atime = vap->va_mtime = vap->va_ctime; ! 417: ! 418: /* ! 419: * If the process has exercised some setuid or setgid ! 420: * privilege, then rip away read/write permission so ! 421: * that only root can gain access. ! 422: */ ! 423: switch (pfs->pfs_type) { ! 424: case Pmem: ! 425: case Pregs: ! 426: case Pfpregs: ! 427: if (procp->p_flag & P_SUGID) ! 428: vap->va_mode &= ~((VREAD|VWRITE)| ! 429: ((VREAD|VWRITE)>>3)| ! 430: ((VREAD|VWRITE)>>6)); ! 431: case Pctl: ! 432: case Pstatus: ! 433: case Pnote: ! 434: case Pnotepg: ! 435: vap->va_nlink = 1; ! 436: vap->va_uid = procp->p_ucred->cr_uid; ! 437: vap->va_gid = procp->p_ucred->cr_gid; ! 438: break; ! 439: } ! 440: ! 441: /* ! 442: * now do the object specific fields ! 443: * ! 444: * The size could be set from struct reg, but it's hardly ! 445: * worth the trouble, and it puts some (potentially) machine ! 446: * dependent data into this machine-independent code. If it ! 447: * becomes important then this function should break out into ! 448: * a per-file stat function in the corresponding .c file. ! 449: */ ! 450: ! 451: switch (pfs->pfs_type) { ! 452: case Proot: ! 453: /* ! 454: * Set nlink to 1 to tell fts(3) we don't actually know. ! 455: */ ! 456: vap->va_nlink = 1; ! 457: vap->va_uid = 0; ! 458: vap->va_gid = 0; ! 459: vap->va_size = vap->va_bytes = DEV_BSIZE; ! 460: break; ! 461: ! 462: case Pcurproc: { ! 463: char buf[16]; /* should be enough */ ! 464: vap->va_nlink = 1; ! 465: vap->va_uid = 0; ! 466: vap->va_gid = 0; ! 467: vap->va_size = vap->va_bytes = ! 468: sprintf(buf, "%ld", (long)curproc->p_pid); ! 469: break; ! 470: } ! 471: ! 472: case Pproc: ! 473: vap->va_nlink = 2; ! 474: vap->va_uid = procp->p_ucred->cr_uid; ! 475: vap->va_gid = procp->p_ucred->cr_gid; ! 476: vap->va_size = vap->va_bytes = DEV_BSIZE; ! 477: break; ! 478: ! 479: case Pfile: ! 480: error = EOPNOTSUPP; ! 481: break; ! 482: ! 483: case Pmem: ! 484: vap->va_bytes = vap->va_size = ! 485: ctob(procp->p_vmspace->vm_tsize + ! 486: procp->p_vmspace->vm_dsize + ! 487: procp->p_vmspace->vm_ssize); ! 488: break; ! 489: ! 490: #if defined(PT_GETREGS) || defined(PT_SETREGS) ! 491: case Pregs: ! 492: vap->va_bytes = vap->va_size = sizeof(struct reg); ! 493: break; ! 494: #endif ! 495: ! 496: #if defined(PT_GETFPREGS) || defined(PT_SETFPREGS) ! 497: case Pfpregs: ! 498: vap->va_bytes = vap->va_size = sizeof(struct fpreg); ! 499: break; ! 500: #endif ! 501: ! 502: case Pctl: ! 503: case Pstatus: ! 504: case Pnote: ! 505: case Pnotepg: ! 506: break; ! 507: ! 508: default: ! 509: panic("procfs_getattr"); ! 510: } ! 511: ! 512: return (error); ! 513: } ! 514: ! 515: procfs_setattr(ap) ! 516: struct vop_setattr_args /* { ! 517: struct vnode *a_vp; ! 518: struct vattr *a_vap; ! 519: struct ucred *a_cred; ! 520: struct proc *a_p; ! 521: } */ *ap; ! 522: { ! 523: /* ! 524: * just fake out attribute setting ! 525: * it's not good to generate an error ! 526: * return, otherwise things like creat() ! 527: * will fail when they try to set the ! 528: * file length to 0. worse, this means ! 529: * that echo $note > /proc/$pid/note will fail. ! 530: */ ! 531: ! 532: return (0); ! 533: } ! 534: ! 535: /* ! 536: * implement access checking. ! 537: * ! 538: * actually, the check for super-user is slightly ! 539: * broken since it will allow read access to write-only ! 540: * objects. this doesn't cause any particular trouble ! 541: * but does mean that the i/o entry points need to check ! 542: * that the operation really does make sense. ! 543: */ ! 544: procfs_access(ap) ! 545: struct vop_access_args /* { ! 546: struct vnode *a_vp; ! 547: int a_mode; ! 548: struct ucred *a_cred; ! 549: struct proc *a_p; ! 550: } */ *ap; ! 551: { ! 552: struct vattr va; ! 553: int error; ! 554: ! 555: if (error = VOP_GETATTR(ap->a_vp, &va, ap->a_cred, ap->a_p)) ! 556: return (error); ! 557: ! 558: return (vaccess(va.va_mode, va.va_uid, va.va_gid, ap->a_mode, ! 559: ap->a_cred)); ! 560: } ! 561: ! 562: /* ! 563: * lookup. this is incredibly complicated in the ! 564: * general case, however for most pseudo-filesystems ! 565: * very little needs to be done. ! 566: * ! 567: * unless you want to get a migraine, just make sure your ! 568: * filesystem doesn't do any locking of its own. otherwise ! 569: * read and inwardly digest ufs_lookup(). ! 570: */ ! 571: procfs_lookup(ap) ! 572: struct vop_lookup_args /* { ! 573: struct vnode * a_dvp; ! 574: struct vnode ** a_vpp; ! 575: struct componentname * a_cnp; ! 576: } */ *ap; ! 577: { ! 578: struct componentname *cnp = ap->a_cnp; ! 579: struct vnode **vpp = ap->a_vpp; ! 580: struct vnode *dvp = ap->a_dvp; ! 581: char *pname = cnp->cn_nameptr; ! 582: struct proc_target *pt; ! 583: struct vnode *fvp; ! 584: pid_t pid; ! 585: struct pfsnode *pfs; ! 586: struct proc *p; ! 587: int i; ! 588: ! 589: *vpp = NULL; ! 590: ! 591: if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) ! 592: return (EROFS); ! 593: ! 594: if (cnp->cn_namelen == 1 && *pname == '.') { ! 595: *vpp = dvp; ! 596: VREF(dvp); ! 597: /*VOP_LOCK(dvp);*/ ! 598: return (0); ! 599: } ! 600: ! 601: pfs = VTOPFS(dvp); ! 602: switch (pfs->pfs_type) { ! 603: case Proot: ! 604: if (cnp->cn_flags & ISDOTDOT) ! 605: return (EIO); ! 606: ! 607: if (CNEQ(cnp, "curproc", 7)) ! 608: return (procfs_allocvp(dvp->v_mount, vpp, 0, Pcurproc)); ! 609: ! 610: pid = atopid(pname, cnp->cn_namelen); ! 611: if (pid == NO_PID) ! 612: break; ! 613: ! 614: p = PFIND(pid); ! 615: if (p == 0) ! 616: break; ! 617: ! 618: return (procfs_allocvp(dvp->v_mount, vpp, pid, Pproc)); ! 619: ! 620: case Pproc: ! 621: if (cnp->cn_flags & ISDOTDOT) ! 622: return (procfs_root(dvp->v_mount, vpp)); ! 623: ! 624: p = PFIND(pfs->pfs_pid); ! 625: if (p == 0) ! 626: break; ! 627: ! 628: for (pt = proc_targets, i = 0; i < nproc_targets; pt++, i++) { ! 629: if (cnp->cn_namelen == pt->pt_namlen && ! 630: bcmp(pt->pt_name, pname, cnp->cn_namelen) == 0 && ! 631: (pt->pt_valid == NULL || (*pt->pt_valid)(p))) ! 632: goto found; ! 633: } ! 634: break; ! 635: ! 636: found: ! 637: if (pt->pt_pfstype == Pfile) { ! 638: fvp = procfs_findtextvp(p); ! 639: /* We already checked that it exists. */ ! 640: VREF(fvp); ! 641: VOP_LOCK(fvp); ! 642: *vpp = fvp; ! 643: return (0); ! 644: } ! 645: ! 646: return (procfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid, ! 647: pt->pt_pfstype)); ! 648: ! 649: default: ! 650: return (ENOTDIR); ! 651: } ! 652: ! 653: return (cnp->cn_nameiop == LOOKUP ? ENOENT : EROFS); ! 654: } ! 655: ! 656: int ! 657: procfs_validfile(p) ! 658: struct proc *p; ! 659: { ! 660: ! 661: return (procfs_findtextvp(p) != NULLVP); ! 662: } ! 663: ! 664: /* ! 665: * readdir returns directory entries from pfsnode (vp). ! 666: * ! 667: * the strategy here with procfs is to generate a single ! 668: * directory entry at a time (struct pfsdent) and then ! 669: * copy that out to userland using uiomove. a more efficent ! 670: * though more complex implementation, would try to minimize ! 671: * the number of calls to uiomove(). for procfs, this is ! 672: * hardly worth the added code complexity. ! 673: * ! 674: * this should just be done through read() ! 675: */ ! 676: procfs_readdir(ap) ! 677: struct vop_readdir_args /* { ! 678: struct vnode *a_vp; ! 679: struct uio *a_uio; ! 680: struct ucred *a_cred; ! 681: int *a_eofflag; ! 682: u_long *a_cookies; ! 683: int a_ncookies; ! 684: } */ *ap; ! 685: { ! 686: struct uio *uio = ap->a_uio; ! 687: struct pfsdent d; ! 688: struct pfsdent *dp = &d; ! 689: struct pfsnode *pfs; ! 690: int error; ! 691: int count; ! 692: int i; ! 693: ! 694: /* ! 695: * We don't allow exporting procfs mounts, and currently local ! 696: * requests do not need cookies. ! 697: */ ! 698: if (ap->a_ncookies) ! 699: panic("procfs_readdir: not hungry"); ! 700: ! 701: pfs = VTOPFS(ap->a_vp); ! 702: ! 703: if (uio->uio_resid < UIO_MX) ! 704: return (EINVAL); ! 705: if (uio->uio_offset & (UIO_MX-1)) ! 706: return (EINVAL); ! 707: if (uio->uio_offset < 0) ! 708: return (EINVAL); ! 709: ! 710: error = 0; ! 711: count = 0; ! 712: i = uio->uio_offset / UIO_MX; ! 713: ! 714: switch (pfs->pfs_type) { ! 715: /* ! 716: * this is for the process-specific sub-directories. ! 717: * all that is needed to is copy out all the entries ! 718: * from the procent[] table (top of this file). ! 719: */ ! 720: case Pproc: { ! 721: struct proc *p; ! 722: struct proc_target *pt; ! 723: ! 724: p = PFIND(pfs->pfs_pid); ! 725: if (p == NULL) ! 726: break; ! 727: ! 728: for (pt = &proc_targets[i]; ! 729: uio->uio_resid >= UIO_MX && i < nproc_targets; pt++, i++) { ! 730: if (pt->pt_valid && (*pt->pt_valid)(p) == 0) ! 731: continue; ! 732: ! 733: dp->d_reclen = UIO_MX; ! 734: dp->d_fileno = PROCFS_FILENO(pfs->pfs_pid, pt->pt_pfstype); ! 735: dp->d_namlen = pt->pt_namlen; ! 736: bcopy(pt->pt_name, dp->d_name, pt->pt_namlen + 1); ! 737: dp->d_type = pt->pt_type; ! 738: ! 739: if (error = uiomove((caddr_t)dp, UIO_MX, uio)) ! 740: break; ! 741: } ! 742: ! 743: break; ! 744: } ! 745: ! 746: /* ! 747: * this is for the root of the procfs filesystem ! 748: * what is needed is a special entry for "curproc" ! 749: * followed by an entry for each process on allproc ! 750: #ifdef PROCFS_ZOMBIE ! 751: * and zombproc. ! 752: #endif ! 753: */ ! 754: ! 755: case Proot: { ! 756: #ifdef PROCFS_ZOMBIE ! 757: int doingzomb = 0; ! 758: #endif ! 759: int pcnt = 0; ! 760: volatile struct proc *p = allproc.lh_first; ! 761: ! 762: again: ! 763: for (; p && uio->uio_resid >= UIO_MX; i++, pcnt++) { ! 764: bzero((char *) dp, UIO_MX); ! 765: dp->d_reclen = UIO_MX; ! 766: ! 767: switch (i) { ! 768: case 0: /* `.' */ ! 769: case 1: /* `..' */ ! 770: dp->d_fileno = PROCFS_FILENO(0, Proot); ! 771: dp->d_namlen = i + 1; ! 772: bcopy("..", dp->d_name, dp->d_namlen); ! 773: dp->d_name[i + 1] = '\0'; ! 774: dp->d_type = DT_DIR; ! 775: break; ! 776: ! 777: case 2: ! 778: dp->d_fileno = PROCFS_FILENO(0, Pcurproc); ! 779: dp->d_namlen = 7; ! 780: bcopy("curproc", dp->d_name, 8); ! 781: dp->d_type = DT_LNK; ! 782: break; ! 783: ! 784: default: ! 785: while (pcnt < i) { ! 786: pcnt++; ! 787: p = p->p_list.le_next; ! 788: if (!p) ! 789: goto done; ! 790: } ! 791: dp->d_fileno = PROCFS_FILENO(p->p_pid, Pproc); ! 792: dp->d_namlen = sprintf(dp->d_name, "%ld", ! 793: (long)p->p_pid); ! 794: dp->d_type = DT_REG; ! 795: p = p->p_list.le_next; ! 796: break; ! 797: } ! 798: ! 799: if (error = uiomove((caddr_t)dp, UIO_MX, uio)) ! 800: break; ! 801: } ! 802: done: ! 803: ! 804: #ifdef PROCFS_ZOMBIE ! 805: if (p == 0 && doingzomb == 0) { ! 806: doingzomb = 1; ! 807: p = zombproc.lh_first; ! 808: goto again; ! 809: } ! 810: #endif ! 811: ! 812: break; ! 813: ! 814: } ! 815: ! 816: default: ! 817: error = ENOTDIR; ! 818: break; ! 819: } ! 820: ! 821: uio->uio_offset = i * UIO_MX; ! 822: ! 823: return (error); ! 824: } ! 825: ! 826: /* ! 827: * readlink reads the link of `curproc' ! 828: */ ! 829: procfs_readlink(ap) ! 830: struct vop_readlink_args *ap; ! 831: { ! 832: struct uio *uio = ap->a_uio; ! 833: char buf[16]; /* should be enough */ ! 834: int len; ! 835: ! 836: if (VTOPFS(ap->a_vp)->pfs_fileno != PROCFS_FILENO(0, Pcurproc)) ! 837: return (EINVAL); ! 838: ! 839: len = sprintf(buf, "%ld", (long)curproc->p_pid); ! 840: ! 841: return (uiomove((caddr_t)buf, len, ap->a_uio)); ! 842: } ! 843: ! 844: /* ! 845: * convert decimal ascii to pid_t ! 846: */ ! 847: static pid_t ! 848: atopid(b, len) ! 849: const char *b; ! 850: u_int len; ! 851: { ! 852: pid_t p = 0; ! 853: ! 854: while (len--) { ! 855: char c = *b++; ! 856: if (c < '0' || c > '9') ! 857: return (NO_PID); ! 858: p = 10 * p + (c - '0'); ! 859: if (p > PID_MAX) ! 860: return (NO_PID); ! 861: } ! 862: ! 863: return (p); ! 864: } ! 865: ! 866: /* ! 867: * procfs vnode operations. ! 868: */ ! 869: int (**procfs_vnodeop_p)(); ! 870: struct vnodeopv_entry_desc procfs_vnodeop_entries[] = { ! 871: { &vop_default_desc, vn_default_error }, ! 872: { &vop_lookup_desc, procfs_lookup }, /* lookup */ ! 873: { &vop_create_desc, procfs_create }, /* create */ ! 874: { &vop_mknod_desc, procfs_mknod }, /* mknod */ ! 875: { &vop_open_desc, procfs_open }, /* open */ ! 876: { &vop_close_desc, procfs_close }, /* close */ ! 877: { &vop_access_desc, procfs_access }, /* access */ ! 878: { &vop_getattr_desc, procfs_getattr }, /* getattr */ ! 879: { &vop_setattr_desc, procfs_setattr }, /* setattr */ ! 880: { &vop_read_desc, procfs_read }, /* read */ ! 881: { &vop_write_desc, procfs_write }, /* write */ ! 882: { &vop_ioctl_desc, procfs_ioctl }, /* ioctl */ ! 883: { &vop_select_desc, procfs_select }, /* select */ ! 884: { &vop_mmap_desc, procfs_mmap }, /* mmap */ ! 885: { &vop_fsync_desc, procfs_fsync }, /* fsync */ ! 886: { &vop_seek_desc, procfs_seek }, /* seek */ ! 887: { &vop_remove_desc, procfs_remove }, /* remove */ ! 888: { &vop_link_desc, procfs_link }, /* link */ ! 889: { &vop_rename_desc, procfs_rename }, /* rename */ ! 890: { &vop_mkdir_desc, procfs_mkdir }, /* mkdir */ ! 891: { &vop_rmdir_desc, procfs_rmdir }, /* rmdir */ ! 892: { &vop_symlink_desc, procfs_symlink }, /* symlink */ ! 893: { &vop_readdir_desc, procfs_readdir }, /* readdir */ ! 894: { &vop_readlink_desc, procfs_readlink }, /* readlink */ ! 895: { &vop_abortop_desc, procfs_abortop }, /* abortop */ ! 896: { &vop_inactive_desc, procfs_inactive }, /* inactive */ ! 897: { &vop_reclaim_desc, procfs_reclaim }, /* reclaim */ ! 898: { &vop_lock_desc, procfs_lock }, /* lock */ ! 899: { &vop_unlock_desc, procfs_unlock }, /* unlock */ ! 900: { &vop_bmap_desc, procfs_bmap }, /* bmap */ ! 901: { &vop_strategy_desc, procfs_strategy }, /* strategy */ ! 902: { &vop_print_desc, procfs_print }, /* print */ ! 903: { &vop_islocked_desc, procfs_islocked }, /* islocked */ ! 904: { &vop_pathconf_desc, procfs_pathconf }, /* pathconf */ ! 905: { &vop_advlock_desc, procfs_advlock }, /* advlock */ ! 906: { &vop_blkatoff_desc, procfs_blkatoff }, /* blkatoff */ ! 907: { &vop_valloc_desc, procfs_valloc }, /* valloc */ ! 908: { &vop_vfree_desc, procfs_vfree }, /* vfree */ ! 909: { &vop_truncate_desc, procfs_truncate }, /* truncate */ ! 910: { &vop_update_desc, procfs_update }, /* update */ ! 911: { &vop_copyfile_desc, err_copyfile }, /* Copyfile */ ! 912: { (struct vnodeop_desc*)NULL, (int(*)())NULL } ! 913: }; ! 914: struct vnodeopv_desc procfs_vnodeop_opv_desc = ! 915: { &procfs_vnodeop_p, procfs_vnodeop_entries };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.