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