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