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