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