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 */
procfs_badop()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
procfs_validfile(p)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
atopid(b,len)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