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