* Copyright (c) 1993 Paul Kranenburg
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Paul Kranenburg.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software withough specific prior written permission
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* $Id: procfs_vnops.c,v 1.6 1994/01/31 04:19:20 davidg Exp $
* PROCFS vnode interface routines
#include "machine/vmparam.h"
* procfs vnode operations.
struct vnodeops pfs_vnodeops
= {
pfs_getattr
, /* getattr */
pfs_setattr
, /* setattr */
pfs_symlink
, /* symlink */
pfs_readdir
, /* readdir */
pfs_readlink
, /* readlink */
pfs_abortop
, /* abortop */
pfs_inactive
, /* inactive */
pfs_reclaim
, /* reclaim */
pfs_strategy
, /* strategy */
pfs_islocked
, /* islocked */
pfs_advlock
, /* advlock */
pfs_open(vp
, mode
, cred
, p
)
register struct vnode
*vp
;
struct pfsnode
*pfsp
= VTOPFS(vp
);
printf("pfs_open: vp 0x%x, proc %d\n", vp
, p
->p_pid
);
if ( (procp
= (pfsp
->pfs_pid
?pfind(pfsp
->pfs_pid
):&proc0
)) == NULL
)
if ( (pfsp
->pfs_flags
& FWRITE
) && (mode
& O_EXCL
) ||
(pfsp
->pfs_flags
& O_EXCL
) && (mode
& FWRITE
) )
pfsp
->pfs_flags
= (mode
& (FWRITE
|O_EXCL
));
procp
->p_vmspace
->vm_refcnt
++;
pfsp
->pfs_vs
= procp
->p_vmspace
;
* /proc filesystem close routine
pfs_close(vp
, flag
, cred
, p
)
register struct vnode
*vp
;
struct pfsnode
*pfsp
= VTOPFS(vp
);
printf("pfs_close: vp 0x%x proc %d\n", vp
, p
->p_pid
);
if ((flag
& FWRITE
) && (pfsp
->pfs_flags
& O_EXCL
))
pfsp
->pfs_flags
&= ~(FWRITE
|O_EXCL
);
vmspace_free(pfsp
->pfs_vs
);
pfs_ioctl(vp
, com
, data
, fflag
, cred
, p
)
struct pfsnode
*pfsp
= VTOPFS(vp
);
procp
= pfsp
->pfs_pid
?pfind(pfsp
->pfs_pid
):&proc0
;
int copysize
= sizeof(struct kinfo_proc
), needed
;
kinfo_doproc(KINFO_PROC_PID
, data
, ©size
,
#ifdef notyet /* Changes to proc.h needed */
procp
->p_psigset
= *(sigset_t
*)data
;
*(sigset_t
*)data
= procp
->p_psigset
;
procp
->p_pfltset
= *(sigflt_t
*)data
;
*(fltset_t
*)data
= procp
->p_pfltset
;
error
= pfs_vmfd(procp
, pfsp
, (struct vmfd
*)data
, p
);
*(int *)data
= pfs_vm_nentries(procp
, pfsp
);
error
= pfs_vmmap(procp
, pfsp
, *(struct procmap
*)data
);
*(int *)data
= pfs_vminfo_nentries(procp
, pfsp
);
error
= pfs_vminfo(procp
, pfsp
, *(struct procvminfo
*)data
);
* Pass I/O requests to the memory filesystem process.
struct proc
*p
= curproc
; /* XXX */
* This is a noop, simply returning what one has been given.
pfs_bmap(vp
, bn
, vpp
, bnp
)
* /proc filesystem inactive routine
struct pfsnode
*pfsp
= VTOPFS(vp
);
if ((pfsp
->pfs_pid
?pfind(pfsp
->pfs_pid
):&proc0
) == NULL
* /proc filesystem reclaim routine
struct pfsnode
**pp
, *pfsp
= VTOPFS(vp
);
for (pp
= &pfshead
; *pp
; pp
= &(*pp
)->pfs_next
) {
* Print out the contents of an pfsnode.
struct pfsnode
*pfsp
= VTOPFS(vp
);
printf("tag VT_PROCFS, pid %d, uid %d, gid %d, mode %x, flags %x\n",
pfsp
->pfs_uid
, pfsp
->pfs_gid
,
pfsp
->pfs_mode
, pfsp
->pfs_flags
);
printf("pfs_badop called\n");
* Make up some attributes for a process file
pfs_getattr (vp
, vap
, cred
, p
)
struct pfsnode
*pfsp
= VTOPFS(vp
);
vap
->va_type
= vp
->v_type
;
vap
->va_flags
= pfsp
->pfs_vflags
;
if (vp
->v_flag
& VROOT
) {
vap
->va_mode
= 0750; /* /proc = rwxr-x--- */
roundup((2+nprocs
)*sizeof(struct pfsdent
), DIRBLKSIZ
);
vap
->va_gid
= 2; /* XXX group kmem */
vap
->va_atime
= vap
->va_mtime
= vap
->va_ctime
= time
; /*XXX*/
vap
->va_rdev
= makedev(255, 255);
vap
->va_rdev
= makedev(255, pfsp
->pfs_pid
);
procp
= pfsp
->pfs_pid
?pfind(pfsp
->pfs_pid
):&proc0
;
vap
->va_size
= ctob( procp
->p_vmspace
->vm_tsize
+
procp
->p_vmspace
->vm_dsize
+
procp
->p_vmspace
->vm_ssize
);
vap
->va_blocksize
= PAGE_SIZE
;
vap
->va_uid
= procp
->p_ucred
->cr_uid
;
vap
->va_gid
= procp
->p_ucred
->cr_gid
;
if (vap
->va_uid
!= procp
->p_cred
->p_ruid
)
if (vap
->va_gid
!= procp
->p_cred
->p_rgid
)
if (procp
->p_flag
& SLOAD
) {
vap
->va_atime
= vap
->va_mtime
= vap
->va_ctime
=
* Set some attributes for a process file
pfs_setattr (vp
, vap
, cred
, p
)
struct pfsnode
*pfsp
= VTOPFS(vp
);
procp
= pfsp
->pfs_pid
?pfind(pfsp
->pfs_pid
):&proc0
;
* Check for unsetable attributes.
if ((vap
->va_type
!= VNON
) || (vap
->va_nlink
!= (short)VNOVAL
) ||
(vap
->va_fsid
!= (long)VNOVAL
) ||
(vap
->va_fileid
!= (long)VNOVAL
) ||
(vap
->va_blocksize
!= (long)VNOVAL
) ||
(vap
->va_rdev
!= (dev_t
)VNOVAL
) ||
((int)vap
->va_bytes
!= (u_long
)VNOVAL
) ||
((int)vap
->va_bytes_rsv
!= (u_long
)VNOVAL
) ||
((int)vap
->va_size
!= (u_long
)VNOVAL
) ||
((int)vap
->va_size_rsv
!= (u_long
)VNOVAL
) ||
(vap
->va_gen
!= (long)VNOVAL
) ||
((int)vap
->va_atime
.tv_sec
!= (u_long
)VNOVAL
) ||
((int)vap
->va_mtime
.tv_sec
!= (u_long
)VNOVAL
) ||
((int)vap
->va_ctime
.tv_sec
!= (u_long
)VNOVAL
) ||
(( (vap
->va_uid
!= (uid_t
)VNOVAL
) ||
(vap
->va_gid
!= (gid_t
)VNOVAL
)) && !(vp
->v_flag
& VROOT
)) ) {
/* set mode bits, only rwx bits are modified */
if (vap
->va_mode
!= (u_short
)VNOVAL
) {
if (cred
->cr_uid
!= pfsp
->pfs_uid
&&
(error
= suser(cred
, &p
->p_acflag
)))
pfsp
->pfs_mode
= vap
->va_mode
& 0777;
/* For now, only allow to change ownership of "/proc" itself */
if ((vp
->v_flag
& VROOT
) && vap
->va_uid
!= (uid_t
)VNOVAL
) {
if ((error
= suser(cred
, &p
->p_acflag
)))
pfsp
->pfs_uid
= vap
->va_uid
;
if ((vp
->v_flag
& VROOT
) && vap
->va_gid
!= (gid_t
)VNOVAL
) {
if ((cred
->cr_uid
!= pfsp
->pfs_uid
||
!groupmember(vap
->va_gid
, cred
)) &&
(error
= suser(cred
, &p
->p_acflag
)))
pfsp
->pfs_gid
= vap
->va_gid
;
if (vap
->va_flags
!= (u_long
)VNOVAL
) {
if (cred
->cr_uid
!= pfsp
->pfs_uid
&&
(error
= suser(cred
, &p
->p_acflag
)))
pfsp
->pfs_vflags
= vap
->va_flags
;
pfsp
->pfs_vflags
&= 0xffff0000ul
;
pfsp
->pfs_vflags
|= (vap
->va_flags
& 0xffff);
pfs_access (vp
, mode
, cred
, p
)
register struct vattr
*vap
;
* If you're the super-user,
if (cred
->cr_uid
== (uid_t
)0)
if (error
= pfs_getattr(vp
, vap
, cred
, p
))
* Access check is based on only one of owner, group, public.
* If not owner, then check group. If not a member of the
* group, then check public access.
if (cred
->cr_uid
!= vap
->va_uid
) {
for (i
= 0; i
< cred
->cr_ngroups
; i
++, gp
++)
if ((vap
->va_mode
& mode
) != 0)
register struct vnode
*vp
;
register struct nameidata
*ndp
;
int lockparent
, wantparent
, flag
, error
= 0;
printf("pfs_lookup: vp 0x%x name %s proc %d\n",
vp
, ndp
->ni_ptr
, p
->p_pid
);
lockparent
= ndp
->ni_nameiop
& LOCKPARENT
;
flag
= ndp
->ni_nameiop
& OPMASK
;
wantparent
= ndp
->ni_nameiop
& (LOCKPARENT
|WANTPARENT
);
printf("pfs_lookup: vp 0x%x: dotdot\n", vp
);
if (ndp
->ni_namelen
== 1 && *ndp
->ni_ptr
== '.') {
pid
= (pid_t
)atoi(ndp
->ni_ptr
, ndp
->ni_namelen
);
if ((procp
= pid
?pfind(pid
):&proc0
) == NULL
)
/* Search pfs node list first */
for (pfsp
= pfshead
; pfsp
!= NULL
; pfsp
= pfsp
->pfs_next
) {
if (pfsp
->pfs_pid
== pid
)
error
= getnewvnode(VT_PROCFS
, vp
->v_mount
, &pfs_vnodeops
, &nvp
);
pfsp
->pfs_uid
= procp
->p_ucred
->cr_uid
;
pfsp
->pfs_gid
= procp
->p_ucred
->cr_gid
;
pfsp
->pfs_mode
= 0700; /* Initial access bits */
/* Append to pfs node list */
pfsp
->pfs_next
= pfshead
;
if (vget(pfsp
->pfs_vnode
))
VOP_UNLOCK(pfsp
->pfs_vnode
);
ndp
->ni_vp
= pfsp
->pfs_vnode
;
pfs_readdir(vp
, uio
, cred
, eofflagp
)
register struct uio
*uio
;
int count
, lost
, pcnt
, skipcnt
, doingzomb
= 0;
printf("pfs_readdir: vp 0x%x proc %d\n",
vp
, uio
->uio_procp
->p_pid
);
count
&= ~(DIRBLKSIZ
- 1);
lost
= uio
->uio_resid
- count
;
if (count
< DIRBLKSIZ
|| (uio
->uio_offset
& (DIRBLKSIZ
-1)))
uio
->uio_iov
->iov_len
= count
;
skipcnt
= uio
->uio_offset
/ sizeof(struct pfsdent
);
/* Fake "." and ".." entries? */
dent
.d_fileno
= 2; /* XXX - Filesystem root */
dent
.d_reclen
= sizeof(struct pfsdent
);
error
= uiomove((char *)&dent
, sizeof(struct pfsdent
) , uio
);
error
= uiomove((char *)&dent
, sizeof(struct pfsdent
) , uio
);
count
+= 2*dent
.d_reclen
;
p
= (struct proc
*)allproc
;
for (pcnt
= 0; p
&& uio
->uio_resid
; pcnt
++) {
if (p
== NULL
&& doingzomb
== 0) {
/* "inode" is process slot (actually position on list) */
dent
.d_fileno
= (unsigned long)(pcnt
+1);
dent
.d_namlen
= itos((unsigned int)p
->p_pid
, dent
.d_nam
);
dent
.d_nam
[dent
.d_namlen
] = '\0';
if (p
== NULL
&& doingzomb
== 0) {
/* Extend 'reclen' to end of block */;
dent
.d_reclen
= DIRBLKSIZ
- (count
& (DIRBLKSIZ
- 1));
dent
.d_reclen
= sizeof(struct pfsdent
);
error
= uiomove((char *)&dent
, dent
.d_reclen
, uio
);
* convert n to decimal representation in character array b
* return number of decimal digits produced.
int m
= (n
<BASE
)?0:itos(n
/BASE
, b
);
*(b
+m
) = "0123456789abcdef"[n
%BASE
];
* convert decimal ascii representation in b of length len to integer