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