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