This source file includes following definitions.
- procfs_open
- procfs_close
- procfs_ioctl
- procfs_bmap
- procfs_inactive
- procfs_reclaim
- procfs_pathconf
- procfs_print
- procfs_link
- procfs_symlink
- procfs_badop
- procfs_getattr
- procfs_setattr
- procfs_access
- procfs_lookup
- procfs_validfile
- procfs_validfile_linux
- procfs_readdir
- procfs_readlink
- atopid
- procfs_poll
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/time.h>
46 #include <sys/kernel.h>
47 #include <sys/file.h>
48 #include <sys/proc.h>
49 #include <sys/mount.h>
50 #include <sys/vnode.h>
51 #include <sys/namei.h>
52 #include <sys/malloc.h>
53 #include <sys/dirent.h>
54 #include <sys/resourcevar.h>
55 #include <sys/poll.h>
56 #include <sys/ptrace.h>
57 #include <sys/stat.h>
58
59 #include <uvm/uvm_extern.h>
60
61 #include <machine/reg.h>
62
63 #include <miscfs/procfs/procfs.h>
64
65
66
67
68
69 static int procfs_validfile_linux(struct proc *, struct mount *);
70
71
72
73
74
75
76 struct proc_target {
77 u_char pt_type;
78 u_char pt_namlen;
79 char *pt_name;
80 pfstype pt_pfstype;
81 int (*pt_valid)(struct proc *p, struct mount *mp);
82 } proc_targets[] = {
83 #define N(s) sizeof(s)-1, s
84
85 { DT_DIR, N("."), Pproc, NULL },
86 { DT_DIR, N(".."), Proot, NULL },
87 { DT_REG, N("file"), Pfile, procfs_validfile },
88 { DT_REG, N("mem"), Pmem, NULL },
89 { DT_REG, N("ctl"), Pctl, NULL },
90 { DT_REG, N("status"), Pstatus, NULL },
91 { DT_REG, N("note"), Pnote, NULL },
92 { DT_REG, N("notepg"), Pnotepg, NULL },
93 { DT_REG, N("cmdline"), Pcmdline, NULL },
94 { DT_REG, N("exe"), Pfile, procfs_validfile_linux },
95 #undef N
96 };
97 static int nproc_targets = sizeof(proc_targets) / sizeof(proc_targets[0]);
98
99
100
101
102
103 struct proc_target proc_root_targets[] = {
104 #define N(s) sizeof(s)-1, s
105
106 { DT_REG, N("meminfo"), Pmeminfo, procfs_validfile_linux },
107 { DT_REG, N("cpuinfo"), Pcpuinfo, procfs_validfile_linux },
108 #undef N
109 };
110 static int nproc_root_targets =
111 sizeof(proc_root_targets) / sizeof(proc_root_targets[0]);
112
113 static pid_t atopid(const char *, u_int);
114
115
116
117
118 int procfs_badop(void *);
119
120 int procfs_lookup(void *);
121 #define procfs_create procfs_badop
122 #define procfs_mknod procfs_badop
123 int procfs_open(void *);
124 int procfs_close(void *);
125 int procfs_access(void *);
126 int procfs_getattr(void *);
127 int procfs_setattr(void *);
128 #define procfs_read procfs_rw
129 #define procfs_write procfs_rw
130 int procfs_ioctl(void *);
131 #define procfs_fsync procfs_badop
132 #define procfs_remove procfs_badop
133 int procfs_link(void *);
134 #define procfs_rename procfs_badop
135 #define procfs_mkdir procfs_badop
136 #define procfs_rmdir procfs_badop
137 int procfs_symlink(void *);
138 int procfs_readdir(void *);
139 int procfs_readlink(void *);
140 int procfs_inactive(void *);
141 int procfs_reclaim(void *);
142 #define procfs_lock nullop
143 #define procfs_unlock nullop
144 int procfs_bmap(void *);
145 #define procfs_strategy procfs_badop
146 int procfs_print(void *);
147 int procfs_pathconf(void *);
148 #define procfs_islocked nullop
149 #define procfs_advlock procfs_badop
150
151 static pid_t atopid(const char *, u_int);
152
153
154
155
156 int (**procfs_vnodeop_p)(void *);
157 struct vnodeopv_entry_desc procfs_vnodeop_entries[] = {
158 { &vop_default_desc, vn_default_error },
159 { &vop_lookup_desc, procfs_lookup },
160 { &vop_create_desc, procfs_create },
161 { &vop_mknod_desc, procfs_mknod },
162 { &vop_open_desc, procfs_open },
163 { &vop_close_desc, procfs_close },
164 { &vop_access_desc, procfs_access },
165 { &vop_getattr_desc, procfs_getattr },
166 { &vop_setattr_desc, procfs_setattr },
167 { &vop_read_desc, procfs_read },
168 { &vop_write_desc, procfs_write },
169 { &vop_ioctl_desc, procfs_ioctl },
170 { &vop_poll_desc, procfs_poll },
171 { &vop_fsync_desc, procfs_fsync },
172 { &vop_remove_desc, procfs_remove },
173 { &vop_link_desc, procfs_link },
174 { &vop_rename_desc, procfs_rename },
175 { &vop_mkdir_desc, procfs_mkdir },
176 { &vop_rmdir_desc, procfs_rmdir },
177 { &vop_symlink_desc, procfs_symlink },
178 { &vop_readdir_desc, procfs_readdir },
179 { &vop_readlink_desc, procfs_readlink },
180 { &vop_abortop_desc, vop_generic_abortop },
181 { &vop_inactive_desc, procfs_inactive },
182 { &vop_reclaim_desc, procfs_reclaim },
183 { &vop_lock_desc, procfs_lock },
184 { &vop_unlock_desc, procfs_unlock },
185 { &vop_bmap_desc, procfs_bmap },
186 { &vop_strategy_desc, procfs_strategy },
187 { &vop_print_desc, procfs_print },
188 { &vop_islocked_desc, procfs_islocked },
189 { &vop_pathconf_desc, procfs_pathconf },
190 { &vop_advlock_desc, procfs_advlock },
191 { NULL, NULL }
192 };
193 struct vnodeopv_desc procfs_vnodeop_opv_desc =
194 { &procfs_vnodeop_p, procfs_vnodeop_entries };
195
196
197
198
199
200
201
202
203
204
205
206 int
207 procfs_open(void *v)
208 {
209 struct vop_open_args *ap = v;
210 struct pfsnode *pfs = VTOPFS(ap->a_vp);
211 struct proc *p1 = ap->a_p;
212 struct proc *p2;
213 int error;
214
215 if ((p2 = pfind(pfs->pfs_pid)) == 0)
216 return (ENOENT);
217
218 switch (pfs->pfs_type) {
219 case Pmem:
220 if (((pfs->pfs_flags & FWRITE) && (ap->a_mode & O_EXCL)) ||
221 ((pfs->pfs_flags & O_EXCL) && (ap->a_mode & FWRITE)))
222 return (EBUSY);
223
224 if ((error = process_checkioperm(p1, p2)) != 0)
225 return (error);
226
227 if (ap->a_mode & FWRITE)
228 pfs->pfs_flags = ap->a_mode & (FWRITE|O_EXCL);
229
230 return (0);
231
232 default:
233 break;
234 }
235
236 return (0);
237 }
238
239
240
241
242
243
244
245
246 int
247 procfs_close(void *v)
248 {
249 struct vop_close_args *ap = v;
250 struct pfsnode *pfs = VTOPFS(ap->a_vp);
251
252 switch (pfs->pfs_type) {
253 case Pmem:
254 if ((ap->a_fflag & FWRITE) && (pfs->pfs_flags & O_EXCL))
255 pfs->pfs_flags &= ~(FWRITE|O_EXCL);
256 break;
257 case Pctl:
258 case Pstatus:
259 case Pnotepg:
260 case Pnote:
261 case Proot:
262 case Pcurproc:
263 case Pself:
264 case Pproc:
265 case Pfile:
266 case Pregs:
267 case Pfpregs:
268 case Pcmdline:
269 case Pmeminfo:
270 case Pcpuinfo:
271 break;
272 }
273
274 return (0);
275 }
276
277
278
279
280
281
282 int
283 procfs_ioctl(void *v)
284 {
285
286 return (ENOTTY);
287 }
288
289
290
291
292
293
294
295
296
297
298
299 int
300 procfs_bmap(void *v)
301 {
302 struct vop_bmap_args *ap = v;
303
304 if (ap->a_vpp != NULL)
305 *ap->a_vpp = ap->a_vp;
306 if (ap->a_bnp != NULL)
307 *ap->a_bnp = ap->a_bn;
308 return (0);
309 }
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327 int
328 procfs_inactive(void *v)
329 {
330 struct vop_inactive_args *ap = v;
331 struct vnode *vp = ap->a_vp;
332 struct pfsnode *pfs = VTOPFS(vp);
333
334 if (pfind(pfs->pfs_pid) == NULL && !(vp->v_flag & VXLOCK))
335 vgone(vp);
336
337 return (0);
338 }
339
340
341
342
343
344
345
346
347 int
348 procfs_reclaim(void *v)
349 {
350 struct vop_reclaim_args *ap = v;
351
352 return (procfs_freevp(ap->a_vp));
353 }
354
355
356
357
358 int
359 procfs_pathconf(void *v)
360 {
361 struct vop_pathconf_args *ap = v;
362
363 switch (ap->a_name) {
364 case _PC_LINK_MAX:
365 *ap->a_retval = LINK_MAX;
366 return (0);
367 case _PC_MAX_CANON:
368 *ap->a_retval = MAX_CANON;
369 return (0);
370 case _PC_MAX_INPUT:
371 *ap->a_retval = MAX_INPUT;
372 return (0);
373 case _PC_PIPE_BUF:
374 *ap->a_retval = PIPE_BUF;
375 return (0);
376 case _PC_CHOWN_RESTRICTED:
377 *ap->a_retval = 1;
378 return (0);
379 case _PC_VDISABLE:
380 *ap->a_retval = _POSIX_VDISABLE;
381 return (0);
382 default:
383 return (EINVAL);
384 }
385
386 }
387
388
389
390
391
392
393 int
394 procfs_print(void *v)
395 {
396 struct vop_print_args *ap = v;
397 struct pfsnode *pfs = VTOPFS(ap->a_vp);
398
399 printf("tag VT_PROCFS, type %d, pid %d, mode %x, flags %lx\n",
400 pfs->pfs_type, pfs->pfs_pid, pfs->pfs_mode, pfs->pfs_flags);
401 return 0;
402 }
403
404 int
405 procfs_link(void *v)
406 {
407 struct vop_link_args *ap = v;
408
409 VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
410 vput(ap->a_dvp);
411 return (EROFS);
412 }
413
414 int
415 procfs_symlink(void *v)
416 {
417 struct vop_symlink_args *ap = v;
418
419 VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
420 vput(ap->a_dvp);
421 return (EROFS);
422 }
423
424
425
426
427
428
429 int
430 procfs_badop(void *v)
431 {
432
433 return (EIO);
434 }
435
436
437
438
439
440
441
442
443
444
445 int
446 procfs_getattr(void *v)
447 {
448 struct vop_getattr_args *ap = v;
449 struct pfsnode *pfs = VTOPFS(ap->a_vp);
450 struct vattr *vap = ap->a_vap;
451 struct proc *procp;
452 int error;
453
454
455 switch (pfs->pfs_type) {
456 case Proot:
457 case Pcurproc:
458 case Pcpuinfo:
459 case Pmeminfo:
460 procp = 0;
461 break;
462
463 default:
464 procp = pfind(pfs->pfs_pid);
465 if (procp == 0)
466 return (ENOENT);
467 }
468
469 error = 0;
470
471
472 VATTR_NULL(vap);
473
474
475 vap->va_type = ap->a_vp->v_type;
476 vap->va_mode = pfs->pfs_mode;
477 vap->va_fileid = pfs->pfs_fileno;
478 vap->va_flags = 0;
479 vap->va_blocksize = PAGE_SIZE;
480 vap->va_bytes = vap->va_size = 0;
481
482
483
484
485
486
487
488
489
490 getnanotime(&vap->va_ctime);
491 vap->va_atime = vap->va_mtime = vap->va_ctime;
492
493 switch (pfs->pfs_type) {
494 case Pregs:
495 case Pfpregs:
496 #ifndef PTRACE
497 break;
498 #endif
499 case Pmem:
500
501
502
503
504
505 if (procp->p_flag & P_SUGID)
506 vap->va_mode &= ~(S_IRUSR|S_IWUSR);
507
508 case Pctl:
509 case Pstatus:
510 case Pnote:
511 case Pnotepg:
512 case Pcmdline:
513 vap->va_nlink = 1;
514 vap->va_uid = procp->p_ucred->cr_uid;
515 vap->va_gid = procp->p_ucred->cr_gid;
516 break;
517 case Pmeminfo:
518 case Pcpuinfo:
519 vap->va_nlink = 1;
520 vap->va_uid = vap->va_gid = 0;
521 break;
522 case Pproc:
523 case Pfile:
524 case Proot:
525 case Pcurproc:
526 case Pself:
527 break;
528 }
529
530
531
532
533
534
535
536
537
538
539
540 switch (pfs->pfs_type) {
541 case Proot:
542
543
544
545 vap->va_nlink = 1;
546 vap->va_uid = 0;
547 vap->va_gid = 0;
548 vap->va_size = vap->va_bytes = DEV_BSIZE;
549 break;
550
551 case Pcurproc: {
552 char buf[16];
553 int len;
554
555 len = snprintf(buf, sizeof buf, "%ld", (long)curproc->p_pid);
556 if (len == -1 || len >= sizeof buf) {
557 error = EINVAL;
558 break;
559 }
560 vap->va_nlink = 1;
561 vap->va_uid = 0;
562 vap->va_gid = 0;
563 vap->va_size = vap->va_bytes = len;
564 break;
565 }
566
567 case Pself:
568 vap->va_nlink = 1;
569 vap->va_uid = 0;
570 vap->va_gid = 0;
571 vap->va_size = vap->va_bytes = sizeof("curproc");
572 break;
573
574 case Pproc:
575 vap->va_nlink = 2;
576 vap->va_uid = procp->p_ucred->cr_uid;
577 vap->va_gid = procp->p_ucred->cr_gid;
578 vap->va_size = vap->va_bytes = DEV_BSIZE;
579 break;
580
581 case Pfile:
582 error = EOPNOTSUPP;
583 break;
584
585 case Pmem:
586 vap->va_bytes = vap->va_size =
587 ctob(procp->p_vmspace->vm_tsize +
588 procp->p_vmspace->vm_dsize +
589 procp->p_vmspace->vm_ssize);
590 break;
591
592 case Pregs:
593 #ifdef PTRACE
594 vap->va_bytes = vap->va_size = sizeof(struct reg);
595 #endif
596 break;
597
598 case Pfpregs:
599 #if defined(PT_GETFPREGS) || defined(PT_SETFPREGS)
600 #ifdef PTRACE
601 vap->va_bytes = vap->va_size = sizeof(struct fpreg);
602 #endif
603 #endif
604 break;
605
606 case Pctl:
607 case Pstatus:
608 case Pnote:
609 case Pnotepg:
610 case Pcmdline:
611 case Pmeminfo:
612 case Pcpuinfo:
613 vap->va_bytes = vap->va_size = 0;
614 break;
615
616 #ifdef DIAGNOSTIC
617 default:
618 panic("procfs_getattr");
619 #endif
620 }
621
622 return (error);
623 }
624
625
626 int
627 procfs_setattr(void *v)
628 {
629
630
631
632
633
634
635
636
637
638 return (0);
639 }
640
641
642
643
644
645
646
647
648
649
650 int
651 procfs_access(void *v)
652 {
653 struct vop_access_args *ap = v;
654 struct vattr va;
655 int error;
656
657 if ((error = VOP_GETATTR(ap->a_vp, &va, ap->a_cred, ap->a_p)) != 0)
658 return (error);
659
660 return (vaccess(va.va_mode, va.va_uid, va.va_gid, ap->a_mode,
661 ap->a_cred));
662 }
663
664
665
666
667
668
669
670
671
672
673 int
674 procfs_lookup(void *v)
675 {
676 struct vop_lookup_args *ap = v;
677 struct componentname *cnp = ap->a_cnp;
678 struct vnode **vpp = ap->a_vpp;
679 struct vnode *dvp = ap->a_dvp;
680 char *pname = cnp->cn_nameptr;
681 struct proc *curp = curproc;
682 struct proc_target *pt;
683 struct vnode *fvp;
684 pid_t pid;
685 struct pfsnode *pfs;
686 struct proc *p = NULL;
687 int i, error, wantpunlock, iscurproc = 0, isself = 0;
688
689 *vpp = NULL;
690 cnp->cn_flags &= ~PDIRUNLOCK;
691
692 if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)
693 return (EROFS);
694
695 if (cnp->cn_namelen == 1 && *pname == '.') {
696 *vpp = dvp;
697 VREF(dvp);
698 return (0);
699 }
700
701 wantpunlock = (~cnp->cn_flags & (LOCKPARENT | ISLASTCN));
702 pfs = VTOPFS(dvp);
703 switch (pfs->pfs_type) {
704 case Proot:
705 if (cnp->cn_flags & ISDOTDOT)
706 return (EIO);
707
708 iscurproc = CNEQ(cnp, "curproc", 7);
709 isself = CNEQ(cnp, "self", 4);
710
711 if (iscurproc || isself) {
712 error = procfs_allocvp(dvp->v_mount, vpp, 0,
713 iscurproc ? Pcurproc : Pself);
714 if ((error == 0) && (wantpunlock)) {
715 VOP_UNLOCK(dvp, 0, curp);
716 cnp->cn_flags |= PDIRUNLOCK;
717 }
718 return (error);
719 }
720
721 for (i = 0; i < nproc_root_targets; i++) {
722 pt = &proc_root_targets[i];
723 if (cnp->cn_namelen == pt->pt_namlen &&
724 memcmp(pt->pt_name, pname, cnp->cn_namelen) == 0 &&
725 (pt->pt_valid == NULL ||
726 (*pt->pt_valid)(p, dvp->v_mount)))
727 break;
728 }
729
730 if (i != nproc_root_targets) {
731 error = procfs_allocvp(dvp->v_mount, vpp, 0,
732 pt->pt_pfstype);
733 if ((error == 0) && (wantpunlock)) {
734 VOP_UNLOCK(dvp, 0, curp);
735 cnp->cn_flags |= PDIRUNLOCK;
736 }
737 return (error);
738 }
739
740 pid = atopid(pname, cnp->cn_namelen);
741 if (pid == NO_PID)
742 break;
743
744 p = pfind(pid);
745 if (p == 0)
746 break;
747
748 error = procfs_allocvp(dvp->v_mount, vpp, pid, Pproc);
749 if ((error == 0) && wantpunlock) {
750 VOP_UNLOCK(dvp, 0, curp);
751 cnp->cn_flags |= PDIRUNLOCK;
752 }
753 return (error);
754
755 case Pproc:
756
757
758
759
760
761
762 if (cnp->cn_flags & ISDOTDOT) {
763 VOP_UNLOCK(dvp, 0, p);
764 cnp->cn_flags |= PDIRUNLOCK;
765 error = procfs_root(dvp->v_mount, vpp);
766 if ((error == 0) && (wantpunlock == 0) &&
767 ((error = vn_lock(dvp, LK_EXCLUSIVE, curp)) == 0))
768 cnp->cn_flags &= ~PDIRUNLOCK;
769 return (error);
770 }
771
772 p = pfind(pfs->pfs_pid);
773 if (p == 0)
774 break;
775
776 for (pt = proc_targets, i = 0; i < nproc_targets; pt++, i++) {
777 if (cnp->cn_namelen == pt->pt_namlen &&
778 bcmp(pt->pt_name, pname, cnp->cn_namelen) == 0 &&
779 (pt->pt_valid == NULL ||
780 (*pt->pt_valid)(p, dvp->v_mount)))
781 goto found;
782 }
783 break;
784
785 found:
786 if (pt->pt_pfstype == Pfile) {
787 fvp = p->p_textvp;
788
789 VREF(fvp);
790 vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, curp);
791 if (wantpunlock) {
792 VOP_UNLOCK(dvp, 0, curp);
793 cnp->cn_flags |= PDIRUNLOCK;
794 }
795 *vpp = fvp;
796 return (0);
797 }
798
799 error = procfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid,
800 pt->pt_pfstype);
801 if ((error == 0) && (wantpunlock)) {
802 VOP_UNLOCK(dvp, 0, curp);
803 cnp->cn_flags |= PDIRUNLOCK;
804 }
805 return (error);
806
807 default:
808 return (ENOTDIR);
809 }
810
811 return (cnp->cn_nameiop == LOOKUP ? ENOENT : EROFS);
812 }
813
814 int
815 procfs_validfile(struct proc *p, struct mount *mp)
816 {
817
818 return (p->p_textvp != NULLVP);
819 }
820
821 int
822 procfs_validfile_linux(struct proc *p, struct mount *mp)
823 {
824 int flags;
825
826 flags = VFSTOPROC(mp)->pmnt_flags;
827 return ((flags & PROCFSMNT_LINUXCOMPAT) &&
828 (p == NULL || procfs_validfile(p, mp)));
829 }
830
831
832
833
834
835
836
837
838
839
840
841
842
843 int
844 procfs_readdir(void *v)
845 {
846 struct vop_readdir_args *ap = v;
847 struct uio *uio = ap->a_uio;
848 struct dirent d;
849 struct pfsnode *pfs;
850 struct vnode *vp;
851 int i;
852 int error;
853
854 vp = ap->a_vp;
855 pfs = VTOPFS(vp);
856
857 if (uio->uio_resid < UIO_MX)
858 return (EINVAL);
859
860 error = 0;
861 i = uio->uio_offset;
862 if (i < 0)
863 return (EINVAL);
864 bzero(&d, UIO_MX);
865 d.d_reclen = UIO_MX;
866
867 switch (pfs->pfs_type) {
868
869
870
871
872
873 case Pproc: {
874 struct proc *p;
875 struct proc_target *pt;
876
877 p = pfind(pfs->pfs_pid);
878 if (p == NULL)
879 break;
880
881 for (pt = &proc_targets[i];
882 uio->uio_resid >= UIO_MX && i < nproc_targets; pt++, i++) {
883 if (pt->pt_valid &&
884 (*pt->pt_valid)(p, vp->v_mount) == 0)
885 continue;
886
887 d.d_fileno = PROCFS_FILENO(pfs->pfs_pid, pt->pt_pfstype);
888 d.d_namlen = pt->pt_namlen;
889 bcopy(pt->pt_name, d.d_name, pt->pt_namlen + 1);
890 d.d_type = pt->pt_type;
891
892 if ((error = uiomove(&d, UIO_MX, uio)) != 0)
893 break;
894 }
895
896 break;
897 }
898
899
900
901
902
903
904
905
906
907
908 case Proot: {
909 #ifdef PROCFS_ZOMBIE
910 int doingzomb = 0;
911 #endif
912 int pcnt = i;
913 volatile struct proc *p = LIST_FIRST(&allproc);
914
915 if (pcnt > 3)
916 pcnt = 3;
917 #ifdef PROCFS_ZOMBIE
918 again:
919 #endif
920 for (; p && uio->uio_resid >= UIO_MX; i++, pcnt++) {
921 switch (i) {
922 case 0:
923 case 1:
924 d.d_fileno = PROCFS_FILENO(0, Proot);
925 d.d_namlen = i + 1;
926 bcopy("..", d.d_name, d.d_namlen);
927 d.d_name[i + 1] = '\0';
928 d.d_type = DT_DIR;
929 break;
930
931 case 2:
932 d.d_fileno = PROCFS_FILENO(0, Pcurproc);
933 d.d_namlen = 7;
934 bcopy("curproc", d.d_name, 8);
935 d.d_type = DT_LNK;
936 break;
937
938 case 3:
939 d.d_fileno = PROCFS_FILENO(0, Pself);
940 d.d_namlen = 4;
941 bcopy("self", d.d_name, 5);
942 d.d_type = DT_LNK;
943 break;
944
945 case 4:
946 if (VFSTOPROC(vp->v_mount)->pmnt_flags &
947 PROCFSMNT_LINUXCOMPAT) {
948 d.d_fileno = PROCFS_FILENO(0, Pcpuinfo);
949 d.d_namlen = 7;
950 bcopy("cpuinfo", d.d_name, 8);
951 d.d_type = DT_REG;
952 break;
953 }
954
955
956 case 5:
957 if (VFSTOPROC(vp->v_mount)->pmnt_flags &
958 PROCFSMNT_LINUXCOMPAT) {
959 d.d_fileno = PROCFS_FILENO(0, Pmeminfo);
960 d.d_namlen = 7;
961 bcopy("meminfo", d.d_name, 8);
962 d.d_type = DT_REG;
963 break;
964 }
965
966
967 default:
968 while (pcnt < i) {
969 pcnt++;
970 p = LIST_NEXT(p, p_list);
971 if (!p)
972 goto done;
973 }
974 d.d_fileno = PROCFS_FILENO(p->p_pid, Pproc);
975 d.d_namlen = snprintf(d.d_name, sizeof(d.d_name),
976 "%ld", (long)p->p_pid);
977 d.d_type = DT_REG;
978 p = LIST_NEXT(p, p_list);
979 break;
980 }
981
982 if ((error = uiomove(&d, UIO_MX, uio)) != 0)
983 break;
984 }
985 done:
986
987 #ifdef PROCFS_ZOMBIE
988 if (p == 0 && doingzomb == 0) {
989 doingzomb = 1;
990 p = LIST_FIRST(&zombproc);
991 goto again;
992 }
993 #endif
994
995 break;
996
997 }
998
999 default:
1000 error = ENOTDIR;
1001 break;
1002 }
1003
1004 uio->uio_offset = i;
1005 return (error);
1006 }
1007
1008
1009
1010
1011 int
1012 procfs_readlink(void *v)
1013 {
1014 struct vop_readlink_args *ap = v;
1015 char buf[16];
1016 int len;
1017
1018 if (VTOPFS(ap->a_vp)->pfs_fileno == PROCFS_FILENO(0, Pcurproc))
1019 len = snprintf(buf, sizeof buf, "%ld", (long)curproc->p_pid);
1020 else if (VTOPFS(ap->a_vp)->pfs_fileno == PROCFS_FILENO(0, Pself))
1021 len = strlcpy(buf, "curproc", sizeof buf);
1022 else
1023 return (EINVAL);
1024 if (len == -1 || len >= sizeof buf)
1025 return (EINVAL);
1026
1027 return (uiomove(buf, len, ap->a_uio));
1028 }
1029
1030
1031
1032
1033 static pid_t
1034 atopid(const char *b, u_int len)
1035 {
1036 pid_t p = 0;
1037
1038 while (len--) {
1039 char c = *b++;
1040 if (c < '0' || c > '9')
1041 return (NO_PID);
1042 p = 10 * p + (c - '0');
1043 if (p > PID_MAX)
1044 return (NO_PID);
1045 }
1046
1047 return (p);
1048 }
1049 int
1050 procfs_poll(void *v)
1051 {
1052 struct vop_poll_args *ap = v;
1053
1054 return (ap->a_events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM));
1055 }