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