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