2 * Copyright (c) 2000 Dag-Erling Coïdan Smørgrav
3 * Copyright (c) 1999 Pierre Beyssac
4 * Copyright (c) 1993, 1995 Jan-Simon Pendry
5 * Copyright (c) 1993, 1995
6 * The Regents of the University of California. All rights reserved.
8 * This code is derived from software contributed to Berkeley by
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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.
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
39 * @(#)procfs_vnops.c 8.18 (Berkeley) 5/21/95
41 * $FreeBSD: src/sys/i386/linux/linprocfs/linprocfs_vnops.c,v 1.3.2.5 2001/08/12 14:29:19 rwatson Exp $
45 * procfs vnode interface
48 #include <sys/param.h>
49 #include <sys/systm.h>
51 #include <sys/kernel.h>
53 #include <sys/fcntl.h>
56 #include <sys/signalvar.h>
57 #include <sys/vnode.h>
58 #include <sys/mount.h>
59 #include <sys/namei.h>
60 #include <sys/dirent.h>
61 #include <sys/malloc.h>
64 #include <vm/vm_zone.h>
65 #include "linprocfs.h"
66 #include <sys/pioctl.h>
67 #include <sys/spinlock2.h>
69 #include <machine/limits.h>
71 extern struct vnode
*procfs_findtextvp (struct proc
*);
73 static int linprocfs_access (struct vop_access_args
*);
74 static int linprocfs_badop (struct vop_generic_args
*);
75 static int linprocfs_bmap (struct vop_bmap_args
*);
76 static int linprocfs_close (struct vop_close_args
*);
77 static int linprocfs_getattr (struct vop_getattr_args
*);
78 static int linprocfs_inactive (struct vop_inactive_args
*);
79 static int linprocfs_ioctl (struct vop_ioctl_args
*);
80 static int linprocfs_lookup (struct vop_old_lookup_args
*);
81 static int linprocfs_open (struct vop_open_args
*);
82 static int linprocfs_print (struct vop_print_args
*);
83 static int linprocfs_readdir (struct vop_readdir_args
*);
84 static int linprocfs_readlink (struct vop_readlink_args
*);
85 static int linprocfs_reclaim (struct vop_reclaim_args
*);
86 static int linprocfs_setattr (struct vop_setattr_args
*);
88 static int linprocfs_readdir_proc(struct vop_readdir_args
*);
89 static int linprocfs_readdir_root(struct vop_readdir_args
*);
90 static int linprocfs_readdir_net(struct vop_readdir_args
*ap
);
91 static int linprocfs_readdir_sys(struct vop_readdir_args
*ap
);
92 static int linprocfs_readdir_syskernel(struct vop_readdir_args
*ap
);
95 * procfs vnode operations.
97 struct vop_ops linprocfs_vnode_vops
= {
98 .vop_default
= vop_defaultop
,
99 .vop_access
= linprocfs_access
,
100 .vop_advlock
= (void *)linprocfs_badop
,
101 .vop_bmap
= linprocfs_bmap
,
102 .vop_close
= linprocfs_close
,
103 .vop_old_create
= (void *)linprocfs_badop
,
104 .vop_getattr
= linprocfs_getattr
,
105 .vop_inactive
= linprocfs_inactive
,
106 .vop_old_link
= (void *)linprocfs_badop
,
107 .vop_old_lookup
= linprocfs_lookup
,
108 .vop_old_mkdir
= (void *)linprocfs_badop
,
109 .vop_old_mknod
= (void *)linprocfs_badop
,
110 .vop_open
= linprocfs_open
,
111 .vop_pathconf
= vop_stdpathconf
,
112 .vop_print
= linprocfs_print
,
113 .vop_read
= (void *)linprocfs_rw
,
114 .vop_readdir
= linprocfs_readdir
,
115 .vop_readlink
= linprocfs_readlink
,
116 .vop_reclaim
= linprocfs_reclaim
,
117 .vop_old_remove
= (void *)linprocfs_badop
,
118 .vop_old_rename
= (void *)linprocfs_badop
,
119 .vop_old_rmdir
= (void *)linprocfs_badop
,
120 .vop_setattr
= linprocfs_setattr
,
121 .vop_old_symlink
= (void *)linprocfs_badop
,
122 .vop_write
= (void *)linprocfs_rw
,
123 .vop_ioctl
= linprocfs_ioctl
127 * This is a list of the valid names in the
128 * process-specific sub-directories. It is
129 * used in linprocfs_lookup and linprocfs_readdir
131 static struct proc_target
{
136 int (*pt_valid
) (struct proc
*p
);
138 #define N(s) sizeof(s)-1, s
139 /* name type validp */
140 { DT_DIR
, N("."), Pproc
, NULL
},
141 { DT_DIR
, N(".."), Proot
, NULL
},
142 { DT_REG
, N("mem"), Pmem
, NULL
},
144 { DT_LNK
, N("exe"), Pexe
, NULL
},
145 { DT_LNK
, N("cwd"), Pcwd
, NULL
},
146 { DT_LNK
, N("root"), Pprocroot
, NULL
},
147 { DT_LNK
, N("fd"), Pfd
, NULL
},
149 { DT_REG
, N("stat"), Pprocstat
, NULL
},
150 { DT_REG
, N("status"), Pprocstatus
, NULL
},
151 { DT_REG
, N("maps"), Pmaps
, NULL
},
152 { DT_REG
, N("statm"), Pstatm
, NULL
},
154 { DT_REG
, N("cmdline"), Pcmdline
, NULL
},
155 { DT_REG
, N("environ"), Penviron
, NULL
},
159 static const int nproc_targets
= NELEM(proc_targets
);
161 static pid_t
atopid (const char *, u_int
);
164 * set things up for doing i/o on
165 * the pfsnode (vp). (vp) is locked
166 * on entry, and should be left locked
169 * for procfs we don't need to do anything
170 * in particular for i/o. all that is done
171 * is to support exclusive open on process
175 linprocfs_open(struct vop_open_args
*ap
)
177 struct pfsnode
*pfs
= VTOPFS(ap
->a_vp
);
181 p2
= linprocfs_pfind(pfs
->pfs_pid
);
184 } else if (pfs
->pfs_pid
&& !PRISON_CHECK(ap
->a_cred
, p2
->p_ucred
)) {
189 switch (pfs
->pfs_type
) {
191 if (((pfs
->pfs_flags
& FWRITE
) &&
192 (ap
->a_mode
& O_EXCL
)) ||
193 ((pfs
->pfs_flags
& O_EXCL
) &&
194 (ap
->a_mode
& FWRITE
))) {
199 if (p_trespass(ap
->a_cred
, p2
->p_ucred
)) {
203 if (ap
->a_mode
& FWRITE
)
204 pfs
->pfs_flags
= ap
->a_mode
& (FWRITE
|O_EXCL
);
211 error
= vop_stdopen(ap
);
218 * close the pfsnode (vp) after doing i/o.
219 * (vp) is not locked on entry or exit.
221 * nothing to do for procfs other than undo
222 * any exclusive open flag (see _open above).
225 linprocfs_close(struct vop_close_args
*ap
)
227 struct pfsnode
*pfs
= VTOPFS(ap
->a_vp
);
230 switch (pfs
->pfs_type
) {
232 if ((ap
->a_fflag
& FWRITE
) && (pfs
->pfs_flags
& O_EXCL
))
233 pfs
->pfs_flags
&= ~(FWRITE
|O_EXCL
);
235 * If this is the last close, then it checks to see if
236 * the target process has PF_LINGER set in p_pfsflags,
237 * if this is *not* the case, then the process' stop flags
238 * are cleared, and the process is woken up. This is
239 * to help prevent the case where a process has been
240 * told to stop on an event, but then the requesting process
241 * has gone away or forgotten about it.
244 if ((ap
->a_vp
->v_opencount
< 2)
245 && (p
= linprocfs_pfind(pfs
->pfs_pid
))
246 && !(p
->p_pfsflags
& PF_LINGER
)) {
247 spin_lock(&p
->p_spin
);
250 spin_unlock(&p
->p_spin
);
259 return (vop_stdclose(ap
));
263 * do an ioctl operation on a pfsnode (vp).
264 * (vp) is not locked on entry or exit.
267 linprocfs_ioctl(struct vop_ioctl_args
*ap
)
269 struct pfsnode
*pfs
= VTOPFS(ap
->a_vp
);
273 struct procfs_status
*psp
;
276 procp
= linprocfs_pfind(pfs
->pfs_pid
);
280 if (p_trespass(ap
->a_cred
, procp
->p_ucred
)) {
285 switch (ap
->a_command
) {
287 procp
->p_stops
|= *(unsigned int*)ap
->a_data
;
290 procp
->p_stops
&= ~*(unsigned int*)ap
->a_data
;
294 * NFLAGS is "non-suser_xxx flags" -- currently, only
295 * PFS_ISUGID ("ignore set u/g id");
297 #define NFLAGS (PF_ISUGID)
298 flags
= (unsigned char)*(unsigned int*)ap
->a_data
;
299 if (flags
& NFLAGS
&& (error
= priv_check_cred(ap
->a_cred
, PRIV_ROOT
, 0)))
301 procp
->p_pfsflags
= flags
;
304 *(unsigned int*)ap
->a_data
= (unsigned int)procp
->p_pfsflags
;
306 psp
= (struct procfs_status
*)ap
->a_data
;
307 psp
->flags
= procp
->p_pfsflags
;
308 psp
->events
= procp
->p_stops
;
309 spin_lock(&procp
->p_spin
);
312 psp
->why
= procp
->p_stype
;
313 psp
->val
= procp
->p_xstat
;
314 spin_unlock(&procp
->p_spin
);
317 spin_unlock(&procp
->p_spin
);
318 psp
->why
= 0; /* Not defined values */
319 psp
->val
= 0; /* Not defined values */
323 psp
= (struct procfs_status
*)ap
->a_data
;
324 spin_lock(&procp
->p_spin
);
325 if (procp
->p_step
== 0) {
326 tsleep_interlock(&procp
->p_stype
, PCATCH
);
327 spin_unlock(&procp
->p_spin
);
328 if (procp
->p_stops
== 0) {
332 if (procp
->p_flags
& P_POSTEXIT
) {
336 if (procp
->p_flags
& P_INEXEC
) {
340 error
= tsleep(&procp
->p_stype
, PCATCH
| PINTERLOCKED
,
345 spin_unlock(&procp
->p_spin
);
347 psp
->state
= 1; /* It stopped */
348 psp
->flags
= procp
->p_pfsflags
;
349 psp
->events
= procp
->p_stops
;
350 psp
->why
= procp
->p_stype
; /* why it stopped */
351 psp
->val
= procp
->p_xstat
; /* any extra info */
353 case PIOCCONT
: /* Restart a proc */
354 if (procp
->p_step
== 0) {
355 error
= EINVAL
; /* Can only start a stopped process */
358 if ((signo
= *(int*)ap
->a_data
) != 0) {
359 if (signo
>= NSIG
|| signo
<= 0) {
363 ksignal(procp
, signo
);
366 wakeup(&procp
->p_step
);
380 * do block mapping for pfsnode (vp).
381 * since we don't use the buffer cache
382 * for procfs this function should never
383 * be called. in any case, it's not clear
384 * what part of the kernel ever makes use
385 * of this function. for sanity, this is the
386 * usual no-op bmap, although returning
387 * (EIO) would be a reasonable alternative.
390 linprocfs_bmap(struct vop_bmap_args
*ap
)
392 if (ap
->a_doffsetp
!= NULL
)
393 *ap
->a_doffsetp
= ap
->a_loffset
;
394 if (ap
->a_runp
!= NULL
)
396 if (ap
->a_runb
!= NULL
)
402 * linprocfs_inactive is called when the pfsnode
403 * is vrele'd and the reference count is about
404 * to go to zero. (vp) will be on the vnode free
405 * list, so to get it back vget() must be
408 * (vp) is locked on entry and must remain locked
412 linprocfs_inactive(struct vop_inactive_args
*ap
)
414 struct pfsnode
*pfs
= VTOPFS(ap
->a_vp
);
416 if (pfs
->pfs_pid
& PFS_DEAD
)
422 * _reclaim is called when getnewvnode()
423 * wants to make use of an entry on the vnode
424 * free list. at this time the filesystem needs
425 * to free any private data and remove the node
426 * from any private lists.
429 linprocfs_reclaim(struct vop_reclaim_args
*ap
)
431 return (linprocfs_freevp(ap
->a_vp
));
435 * _print is used for debugging.
436 * just print a readable description
440 linprocfs_print(struct vop_print_args
*ap
)
442 struct pfsnode
*pfs
= VTOPFS(ap
->a_vp
);
444 kprintf("tag VT_PROCFS, type %d, pid %ld, mode %x, flags %lx\n",
445 pfs
->pfs_type
, (long)pfs
->pfs_pid
, pfs
->pfs_mode
, pfs
->pfs_flags
);
450 * generic entry point for unsupported operations
453 linprocfs_badop(struct vop_generic_args
*ap __unused
)
460 * Invent attributes for pfsnode (vp) and store
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.
466 * this is relatively minimal for procfs.
469 linprocfs_getattr(struct vop_getattr_args
*ap
)
471 struct pfsnode
*pfs
= VTOPFS(ap
->a_vp
);
472 struct vattr
*vap
= ap
->a_vap
;
477 * First make sure that the process and its credentials
480 switch (pfs
->pfs_type
) {
487 procp
= linprocfs_pfind(pfs
->pfs_pid
);
488 if (procp
== NULL
|| procp
->p_ucred
== NULL
) {
496 /* start by zeroing out the attributes */
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
;
504 vap
->va_blocksize
= PAGE_SIZE
;
505 vap
->va_bytes
= vap
->va_size
= 0;
506 vap
->va_fsid
= ap
->a_vp
->v_mount
->mnt_stat
.f_fsid
.val
[0];
509 * Make all times be current TOD.
510 * It would be possible to get the process start
511 * time from the p_stat structure, but there's
512 * no "file creation" time stamp anyway, and the
513 * p_stat structure is not addressible if u. gets
514 * swapped out for that process.
516 nanotime(&vap
->va_ctime
);
517 vap
->va_atime
= vap
->va_mtime
= vap
->va_ctime
;
520 * now do the object specific fields
522 * The size could be set from struct reg, but it's hardly
523 * worth the trouble, and it puts some (potentially) machine
524 * dependent data into this machine-independent code. If it
525 * becomes important then this function should break out into
526 * a per-file stat function in the corresponding .c file.
531 vap
->va_uid
= procp
->p_ucred
->cr_uid
;
532 vap
->va_gid
= procp
->p_ucred
->cr_gid
;
535 switch (pfs
->pfs_type
) {
541 * Set nlink to 1 to tell fts(3) we don't actually know.
546 vap
->va_size
= vap
->va_bytes
= DEV_BSIZE
;
550 char buf
[16]; /* should be enough */
553 vap
->va_size
= vap
->va_bytes
=
554 ksnprintf(buf
, sizeof(buf
), "%ld", (long)curproc
->p_pid
);
559 vap
->va_nlink
= nproc_targets
;
560 vap
->va_size
= vap
->va_bytes
= DEV_BSIZE
;
564 char *fullpath
, *freepath
;
565 error
= cache_fullpath(procp
, &procp
->p_textnch
, NULL
,
566 &fullpath
, &freepath
, 0);
567 /* error = vn_fullpath(procp, NULL, &fullpath, &freepath); */
569 vap
->va_size
= strlen(fullpath
);
570 kfree(freepath
, M_TEMP
);
572 vap
->va_size
= sizeof("unknown") - 1;
575 vap
->va_bytes
= vap
->va_size
;
579 char *fullpath
, *freepath
;
580 error
= cache_fullpath(procp
, &procp
->p_fd
->fd_ncdir
, NULL
,
581 &fullpath
, &freepath
, 0);
583 vap
->va_size
= strlen(fullpath
);
584 kfree(freepath
, M_TEMP
);
586 vap
->va_size
= sizeof("unknown") - 1;
589 vap
->va_bytes
= vap
->va_size
;
593 struct nchandle
*nchp
;
594 char *fullpath
, *freepath
;
595 nchp
= jailed(procp
->p_ucred
) ? &procp
->p_fd
->fd_njdir
: &procp
->p_fd
->fd_nrdir
;
596 error
= cache_fullpath(procp
, nchp
, NULL
,
597 &fullpath
, &freepath
, 0);
599 vap
->va_size
= strlen(fullpath
);
600 kfree(freepath
, M_TEMP
);
602 vap
->va_size
= sizeof("unknown") - 1;
605 vap
->va_bytes
= vap
->va_size
;
609 if (procp
== curproc
) {
610 vap
->va_size
= sizeof("/dev/fd") - 1;
613 vap
->va_size
= sizeof("unknown") - 1;
616 vap
->va_bytes
= vap
->va_size
;
632 vap
->va_bytes
= vap
->va_size
= 0;
639 * If we denied owner access earlier, then we have to
640 * change the owner to root - otherwise 'ps' and friends
641 * will break even though they are setgid kmem. *SIGH*
643 if (procp
->p_flags
& P_SUGID
)
646 vap
->va_uid
= procp
->p_ucred
->cr_uid
;
655 vap
->va_bytes
= vap
->va_size
= 0;
656 /* uid, gid are already set */
660 panic("linprocfs_getattr");
669 linprocfs_setattr(struct vop_setattr_args
*ap
)
672 if (ap
->a_vap
->va_flags
!= VNOVAL
)
676 * just fake out attribute setting
677 * it's not good to generate an error
678 * return, otherwise things like creat()
679 * will fail when they try to set the
680 * file length to 0. worse, this means
681 * that echo $note > /proc/$pid/note will fail.
688 * implement access checking.
690 * something very similar to this code is duplicated
691 * throughout the 4bsd kernel and should be moved
692 * into kern/vfs_subr.c sometime.
694 * actually, the check for super-user is slightly
695 * broken since it will allow read access to write-only
696 * objects. this doesn't cause any particular trouble
697 * but does mean that the i/o entry points need to check
698 * that the operation really does make sense.
701 linprocfs_access(struct vop_access_args
*ap
)
708 * If you're the super-user,
709 * you always get access.
711 if (ap
->a_cred
->cr_uid
== 0)
715 error
= VOP_GETATTR(ap
->a_vp
, vap
);
720 * Access check is based on only one of owner, group, public.
721 * If not owner, then check group. If not a member of the
722 * group, then check public access.
724 if (ap
->a_cred
->cr_uid
!= vap
->va_uid
) {
729 gp
= ap
->a_cred
->cr_groups
;
730 for (i
= 0; i
< ap
->a_cred
->cr_ngroups
; i
++, gp
++)
731 if (vap
->va_gid
== *gp
)
738 if ((vap
->va_mode
& ap
->a_mode
) == ap
->a_mode
)
745 * lookup. this is incredibly complicated in the general case, however
746 * for most pseudo-filesystems very little needs to be done.
749 linprocfs_lookup(struct vop_old_lookup_args
*ap
)
751 struct componentname
*cnp
= ap
->a_cnp
;
752 struct vnode
**vpp
= ap
->a_vpp
;
753 struct vnode
*dvp
= ap
->a_dvp
;
754 char *pname
= cnp
->cn_nameptr
;
755 struct proc_target
*pt
;
765 if (cnp
->cn_nameiop
== NAMEI_DELETE
||
766 cnp
->cn_nameiop
== NAMEI_RENAME
||
767 cnp
->cn_nameiop
== NAMEI_CREATE
) {
773 if (cnp
->cn_namelen
== 1 && *pname
== '.') {
780 switch (pfs
->pfs_type
) {
782 if (cnp
->cn_flags
& CNP_ISDOTDOT
) {
783 error
= linprocfs_root(dvp
->v_mount
, vpp
);
786 if (CNEQ(cnp
, "kernel", 6)) {
787 error
= linprocfs_allocvp(dvp
->v_mount
, vpp
, 0, Psyskernel
);
792 if (cnp
->cn_flags
& CNP_ISDOTDOT
) {
793 error
= linprocfs_root(dvp
->v_mount
, vpp
);
796 if (CNEQ(cnp
, "dev", 3)) {
797 error
= linprocfs_allocvp(dvp
->v_mount
, vpp
, 0, Pnetdev
);
802 if (cnp
->cn_flags
& CNP_ISDOTDOT
) {
803 /* XXX: this is wrong, wrong, wrong. */
804 error
= linprocfs_root(dvp
->v_mount
, vpp
);
807 if (CNEQ(cnp
, "osrelease", 9)) {
808 error
= linprocfs_allocvp(dvp
->v_mount
, vpp
, 0, Posrelease
);
811 if (CNEQ(cnp
, "ostype", 6)) {
812 error
= linprocfs_allocvp(dvp
->v_mount
, vpp
, 0, Postype
);
815 if (CNEQ(cnp
, "pid_max", 7)) {
816 error
= linprocfs_allocvp(dvp
->v_mount
, vpp
, 0, Ppidmax
);
819 if (CNEQ(cnp
, "version", 7)) {
820 error
= linprocfs_allocvp(dvp
->v_mount
, vpp
, 0, Pversion
);
826 if (cnp
->cn_flags
& CNP_ISDOTDOT
)
829 if (CNEQ(cnp
, "self", 4)) {
830 error
= linprocfs_allocvp(dvp
->v_mount
, vpp
, 0, Pself
);
833 if (CNEQ(cnp
, "meminfo", 7)) {
834 error
= linprocfs_allocvp(dvp
->v_mount
, vpp
, 0, Pmeminfo
);
837 if (CNEQ(cnp
, "cpuinfo", 7)) {
838 error
= linprocfs_allocvp(dvp
->v_mount
, vpp
, 0, Pcpuinfo
);
841 if (CNEQ(cnp
, "mounts", 6)) {
842 error
= linprocfs_allocvp(dvp
->v_mount
, vpp
, 0, Pmounts
);
845 if (CNEQ(cnp
, "stat", 4)) {
846 error
= linprocfs_allocvp(dvp
->v_mount
, vpp
, 0, Pstat
);
849 if (CNEQ(cnp
, "uptime", 6)) {
850 error
= linprocfs_allocvp(dvp
->v_mount
, vpp
, 0, Puptime
);
853 if (CNEQ(cnp
, "version", 7)) {
854 error
= linprocfs_allocvp(dvp
->v_mount
, vpp
, 0, Pversion
);
857 if (CNEQ(cnp
, "loadavg", 7)) {
858 error
= linprocfs_allocvp(dvp
->v_mount
, vpp
, 0, Ploadavg
);
861 if (CNEQ(cnp
, "net", 3)) {
862 error
= linprocfs_allocvp(dvp
->v_mount
, vpp
, 0, Pnet
);
865 if (CNEQ(cnp
, "sys", 3)) {
866 error
= linprocfs_allocvp(dvp
->v_mount
, vpp
, 0, Psys
);
869 if (CNEQ(cnp
, "devices", 7)) {
870 error
= linprocfs_allocvp(dvp
->v_mount
, vpp
, 0, Pdevices
);
874 pid
= atopid(pname
, cnp
->cn_namelen
);
878 p
= linprocfs_pfind(pid
);
882 if (!PRISON_CHECK(ap
->a_cnp
->cn_cred
, p
->p_ucred
))
885 if (ps_showallprocs
== 0 && ap
->a_cnp
->cn_cred
->cr_uid
!= 0 &&
886 ap
->a_cnp
->cn_cred
->cr_uid
!= p
->p_ucred
->cr_uid
)
889 error
= linprocfs_allocvp(dvp
->v_mount
, vpp
, pid
, Pproc
);
893 if (cnp
->cn_flags
& CNP_ISDOTDOT
) {
894 error
= linprocfs_root(dvp
->v_mount
, vpp
);
898 p
= linprocfs_pfind(pfs
->pfs_pid
);
902 if (!PRISON_CHECK(ap
->a_cnp
->cn_cred
, p
->p_ucred
))
905 if (ps_showallprocs
== 0 && ap
->a_cnp
->cn_cred
->cr_uid
!= 0 &&
906 ap
->a_cnp
->cn_cred
->cr_uid
!= p
->p_ucred
->cr_uid
)
909 for (pt
= proc_targets
, i
= 0; i
< nproc_targets
; pt
++, i
++) {
910 if (cnp
->cn_namelen
== pt
->pt_namlen
&&
911 bcmp(pt
->pt_name
, pname
, cnp
->cn_namelen
) == 0 &&
912 (pt
->pt_valid
== NULL
|| (*pt
->pt_valid
)(p
)))
918 error
= linprocfs_allocvp(dvp
->v_mount
, vpp
, pfs
->pfs_pid
,
927 if (cnp
->cn_nameiop
== NAMEI_LOOKUP
)
933 * If no error occured *vpp will hold a referenced locked vnode.
934 * dvp was passed to us locked and *vpp must be returned locked
935 * so if dvp != *vpp and CNP_LOCKPARENT is not set, unlock dvp.
941 if (*vpp
!= dvp
&& (cnp
->cn_flags
& CNP_LOCKPARENT
) == 0) {
942 cnp
->cn_flags
|= CNP_PDIRUNLOCK
;
950 * Does this process have a text file?
953 linprocfs_validfile(struct proc
*p
)
956 return (procfs_findtextvp(p
) != NULLVP
);
960 * readdir() returns directory entries from pfsnode (vp).
962 * We generate just one directory entry at a time, as it would probably
963 * not pay off to buffer several entries locally to save uiomove calls.
965 * linprocfs_readdir(struct vnode *a_vp, struct uio *a_uio,
966 * struct ucred *a_cred, int *a_eofflag,
967 * int *a_ncookies, off_t **a_cookies)
970 linprocfs_readdir(struct vop_readdir_args
*ap
)
975 if (ap
->a_uio
->uio_offset
< 0 || ap
->a_uio
->uio_offset
> INT_MAX
)
978 pfs
= VTOPFS(ap
->a_vp
);
979 error
= vn_lock(ap
->a_vp
, LK_EXCLUSIVE
| LK_RETRY
| LK_FAILRECLAIM
);
983 switch (pfs
->pfs_type
) {
986 * This is for the process-specific sub-directories.
987 * all that is needed to is copy out all the entries
988 * from the procent[] table (top of this file).
990 error
= linprocfs_readdir_proc(ap
);
994 * This is for the root of the procfs filesystem
995 * what is needed is a special entry for "self"
996 * followed by an entry for each process on allproc
998 error
= linprocfs_readdir_root(ap
);
1001 error
= linprocfs_readdir_net(ap
);
1004 error
= linprocfs_readdir_sys(ap
);
1007 error
= linprocfs_readdir_syskernel(ap
);
1013 vn_unlock(ap
->a_vp
);
1019 linprocfs_readdir_proc(struct vop_readdir_args
*ap
)
1021 struct pfsnode
*pfs
;
1022 int error
, i
, retval
;
1024 struct proc_target
*pt
;
1025 struct uio
*uio
= ap
->a_uio
;
1027 pfs
= VTOPFS(ap
->a_vp
);
1028 p
= linprocfs_pfind(pfs
->pfs_pid
);
1031 if (!PRISON_CHECK(ap
->a_cred
, p
->p_ucred
)) {
1037 i
= uio
->uio_offset
;
1039 for (pt
= &proc_targets
[i
];
1040 !error
&& uio
->uio_resid
> 0 && i
< nproc_targets
; pt
++, i
++) {
1041 if (pt
->pt_valid
&& (*pt
->pt_valid
)(p
) == 0)
1044 retval
= vop_write_dirent(&error
, uio
,
1045 PROCFS_FILENO(pfs
->pfs_pid
, pt
->pt_pfstype
), pt
->pt_type
,
1046 pt
->pt_namlen
, pt
->pt_name
);
1051 uio
->uio_offset
= i
;
1057 struct linprocfs_readdir_root_info
{
1066 * Scan the root directory by scanning all process
1068 static int linprocfs_readdir_root_callback(struct proc
*p
, void *data
);
1071 linprocfs_readdir_root(struct vop_readdir_args
*ap
)
1073 struct linprocfs_readdir_root_info info
;
1074 struct uio
*uio
= ap
->a_uio
;
1078 info
.i
= uio
->uio_offset
;
1081 info
.cred
= ap
->a_cred
;
1083 while (info
.pcnt
< 13) {
1084 res
= linprocfs_readdir_root_callback(NULL
, &info
);
1089 allproc_scan(linprocfs_readdir_root_callback
, &info
);
1091 uio
->uio_offset
= info
.i
;
1096 linprocfs_readdir_root_callback(struct proc
*p
, void *data
)
1098 struct linprocfs_readdir_root_info
*info
= data
;
1100 struct uio
*uio
= info
->uio
;
1103 char d_name_pid
[20];
1107 switch (info
->pcnt
) {
1109 d_ino
= PROCFS_FILENO(0, Proot
);
1115 d_ino
= PROCFS_FILENO(0, Proot
);
1122 d_ino
= PROCFS_FILENO(0, Proot
);
1129 d_ino
= PROCFS_FILENO(0, Pmeminfo
);
1136 d_ino
= PROCFS_FILENO(0, Pcpuinfo
);
1143 d_ino
= PROCFS_FILENO(0, Pstat
);
1150 d_ino
= PROCFS_FILENO(0, Puptime
);
1157 d_ino
= PROCFS_FILENO(0, Pversion
);
1164 d_ino
= PROCFS_FILENO(0, Ploadavg
);
1170 d_ino
= PROCFS_FILENO(0, Pnet
);
1176 d_ino
= PROCFS_FILENO(0, Psys
);
1182 d_ino
= PROCFS_FILENO(0, Pmounts
);
1188 d_ino
= PROCFS_FILENO(0, Pdevices
);
1195 * Ignore processes that aren't in our prison
1197 if (PRISON_CHECK(info
->cred
, p
->p_ucred
) == 0)
1201 * Ignore processes that we do not want to be visible.
1203 if (ps_showallprocs
== 0 &&
1204 info
->cred
->cr_uid
!= 0 &&
1205 info
->cred
->cr_uid
!= p
->p_ucred
->cr_uid
) {
1210 * Skip processes we have already read (optimization)
1212 if (info
->pcnt
< info
->i
) {
1216 d_ino
= PROCFS_FILENO(p
->p_pid
, Pproc
);
1217 d_namlen
= ksnprintf(d_name_pid
, sizeof(d_name_pid
),
1218 "%ld", (long)p
->p_pid
);
1219 d_name
= d_name_pid
;
1225 * Skip processes we have already read
1227 if (info
->pcnt
< info
->i
) {
1231 retval
= vop_write_dirent(&info
->error
, info
->uio
,
1232 d_ino
, d_type
, d_namlen
, d_name
);
1234 ++info
->pcnt
; /* iterate proc candidates scanned */
1235 ++info
->i
; /* iterate entries written */
1237 if (retval
|| info
->error
|| uio
->uio_resid
<= 0)
1243 * Scan the root directory by scanning all process
1245 static int linprocfs_readdir_net_callback(struct proc
*p
, void *data
);
1248 linprocfs_readdir_net(struct vop_readdir_args
*ap
)
1250 struct linprocfs_readdir_root_info info
;
1251 struct uio
*uio
= ap
->a_uio
;
1255 info
.i
= uio
->uio_offset
;
1258 info
.cred
= ap
->a_cred
;
1260 while (info
.pcnt
< 3) {
1261 res
= linprocfs_readdir_net_callback(NULL
, &info
);
1266 uio
->uio_offset
= info
.i
;
1271 linprocfs_readdir_net_callback(struct proc
*p
, void *data
)
1273 struct linprocfs_readdir_root_info
*info
= data
;
1275 struct uio
*uio
= info
->uio
;
1281 switch (info
->pcnt
) {
1283 d_ino
= PROCFS_FILENO(0, Pnet
);
1289 d_ino
= PROCFS_FILENO(0, Proot
);
1296 d_ino
= PROCFS_FILENO(0, Pnet
);
1310 * Skip processes we have already read
1312 if (info
->pcnt
< info
->i
) {
1316 retval
= vop_write_dirent(&info
->error
, info
->uio
,
1317 d_ino
, d_type
, d_namlen
, d_name
);
1319 ++info
->pcnt
; /* iterate proc candidates scanned */
1320 ++info
->i
; /* iterate entries written */
1322 if (retval
|| info
->error
|| uio
->uio_resid
<= 0)
1334 * Scan the root directory by scanning all process
1336 static int linprocfs_readdir_sys_callback(struct proc
*p
, void *data
);
1339 linprocfs_readdir_sys(struct vop_readdir_args
*ap
)
1341 struct linprocfs_readdir_root_info info
;
1342 struct uio
*uio
= ap
->a_uio
;
1346 info
.i
= uio
->uio_offset
;
1349 info
.cred
= ap
->a_cred
;
1351 while (info
.pcnt
< 3) {
1352 res
= linprocfs_readdir_sys_callback(NULL
, &info
);
1357 uio
->uio_offset
= info
.i
;
1362 linprocfs_readdir_sys_callback(struct proc
*p
, void *data
)
1364 struct linprocfs_readdir_root_info
*info
= data
;
1366 struct uio
*uio
= info
->uio
;
1372 switch (info
->pcnt
) {
1374 d_ino
= PROCFS_FILENO(0, Psys
);
1380 d_ino
= PROCFS_FILENO(0, Proot
);
1387 d_ino
= PROCFS_FILENO(0, Psyskernel
);
1401 * Skip processes we have already read
1403 if (info
->pcnt
< info
->i
) {
1407 retval
= vop_write_dirent(&info
->error
, info
->uio
,
1408 d_ino
, d_type
, d_namlen
, d_name
);
1410 ++info
->pcnt
; /* iterate proc candidates scanned */
1411 ++info
->i
; /* iterate entries written */
1413 if (retval
|| info
->error
|| uio
->uio_resid
<= 0)
1423 * Scan the root directory by scanning all process
1425 static int linprocfs_readdir_syskernel_callback(struct proc
*p
, void *data
);
1428 linprocfs_readdir_syskernel(struct vop_readdir_args
*ap
)
1430 struct linprocfs_readdir_root_info info
;
1431 struct uio
*uio
= ap
->a_uio
;
1435 info
.i
= uio
->uio_offset
;
1438 info
.cred
= ap
->a_cred
;
1440 while (info
.pcnt
< 6) {
1441 res
= linprocfs_readdir_syskernel_callback(NULL
, &info
);
1446 uio
->uio_offset
= info
.i
;
1451 linprocfs_readdir_syskernel_callback(struct proc
*p
, void *data
)
1453 struct linprocfs_readdir_root_info
*info
= data
;
1455 struct uio
*uio
= info
->uio
;
1461 switch (info
->pcnt
) {
1463 d_ino
= PROCFS_FILENO(0, Psyskernel
);
1469 d_ino
= PROCFS_FILENO(0, Psys
);
1476 d_ino
= PROCFS_FILENO(0, Posrelease
);
1478 d_name
= "osrelease";
1483 d_ino
= PROCFS_FILENO(0, Postype
);
1490 d_ino
= PROCFS_FILENO(0, Pversion
);
1497 d_ino
= PROCFS_FILENO(0, Ppidmax
);
1511 * Skip processes we have already read
1513 if (info
->pcnt
< info
->i
) {
1517 retval
= vop_write_dirent(&info
->error
, info
->uio
,
1518 d_ino
, d_type
, d_namlen
, d_name
);
1520 ++info
->pcnt
; /* iterate proc candidates scanned */
1521 ++info
->i
; /* iterate entries written */
1523 if (retval
|| info
->error
|| uio
->uio_resid
<= 0)
1529 * readlink reads the link of `self' or `exe'
1532 linprocfs_readlink(struct vop_readlink_args
*ap
)
1534 char buf
[16]; /* should be enough */
1536 struct vnode
*vp
= ap
->a_vp
;
1537 struct nchandle
*nchp
;
1538 struct pfsnode
*pfs
= VTOPFS(vp
);
1539 char *fullpath
, *freepath
;
1545 switch (pfs
->pfs_type
) {
1547 if (pfs
->pfs_fileno
!= PROCFS_FILENO(0, Pself
))
1550 len
= ksnprintf(buf
, sizeof(buf
), "%ld", (long)curproc
->p_pid
);
1552 error
= uiomove(buf
, len
, ap
->a_uio
);
1555 * There _should_ be no way for an entire process to disappear
1559 procp
= linprocfs_pfind(pfs
->pfs_pid
);
1560 if (procp
== NULL
|| procp
->p_ucred
== NULL
) {
1561 kprintf("linprocfs_readlink: pid %d disappeared\n",
1563 error
= uiomove("unknown", sizeof("unknown") - 1,
1567 error
= cache_fullpath(procp
, &procp
->p_textnch
, NULL
,
1568 &fullpath
, &freepath
, 0);
1570 error
= uiomove("unknown", sizeof("unknown") - 1,
1574 error
= uiomove(fullpath
, strlen(fullpath
), ap
->a_uio
);
1575 kfree(freepath
, M_TEMP
);
1578 procp
= linprocfs_pfind(pfs
->pfs_pid
);
1579 if (procp
== NULL
|| procp
->p_ucred
== NULL
) {
1580 kprintf("linprocfs_readlink: pid %d disappeared\n",
1582 error
= uiomove("unknown", sizeof("unknown") - 1,
1586 error
= cache_fullpath(procp
, &procp
->p_fd
->fd_ncdir
, NULL
,
1587 &fullpath
, &freepath
, 0);
1589 error
= uiomove("unknown", sizeof("unknown") - 1,
1593 error
= uiomove(fullpath
, strlen(fullpath
), ap
->a_uio
);
1594 kfree(freepath
, M_TEMP
);
1597 procp
= linprocfs_pfind(pfs
->pfs_pid
);
1598 if (procp
== NULL
|| procp
->p_ucred
== NULL
) {
1599 kprintf("linprocfs_readlink: pid %d disappeared\n",
1601 error
= uiomove("unknown", sizeof("unknown") - 1,
1605 nchp
= jailed(procp
->p_ucred
) ? &procp
->p_fd
->fd_njdir
: &procp
->p_fd
->fd_nrdir
;
1606 error
= cache_fullpath(procp
, nchp
, NULL
,
1607 &fullpath
, &freepath
, 0);
1609 error
= uiomove("unknown", sizeof("unknown") - 1,
1613 error
= uiomove(fullpath
, strlen(fullpath
), ap
->a_uio
);
1614 kfree(freepath
, M_TEMP
);
1617 procp
= linprocfs_pfind(pfs
->pfs_pid
);
1618 if (procp
== NULL
|| procp
->p_ucred
== NULL
) {
1619 kprintf("linprocfs_readlink: pid %d disappeared\n",
1621 error
= uiomove("unknown", sizeof("unknown") - 1,
1625 if (procp
== curproc
) {
1626 error
= uiomove("/dev/fd", sizeof("/dev/fd") - 1,
1630 error
= uiomove("unknown", sizeof("unknown") - 1,
1646 * convert decimal ascii to pid_t
1649 atopid(const char *b
, u_int len
)
1655 if (c
< '0' || c
> '9')
1657 p
= 10 * p
+ (c
- '0');