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