* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
* This code is derived from software donated to Berkeley by
* %sccs.include.redist.c%
* @(#)fdesc_vnops.c 8.3 (Berkeley) %G%
* $Id: fdesc_vnops.c,v 1.12 1993/04/06 16:17:17 jsp Exp $
#include <sys/kernel.h> /* boottime */
#include <sys/resourcevar.h>
#include <sys/filedesc.h>
#include <miscfs/fdesc/fdesc.h>
#define cttyvp(p) ((p)->p_flag & P_CONTROLT ? (p)->p_session->s_ttyvp : NULL)
static struct vnode
*fdescvp
[FD_MAX
];
#if (FD_STDIN != FD_STDOUT-1) || (FD_STDOUT != FD_STDERR-1)
FD_STDIN
, FD_STDOUT
, FD_STDERR must be a sequence n
, n
+1, n
+2
fdesc_allocvp(ftype
, ix
, mp
, vpp
)
/* get stashed copy of the vnode */
if (ix
>= 0 && ix
< FD_MAX
) {
* otherwise lock the array while we call getnewvnode
if (fdescvplock
& FDL_LOCKED
) {
sleep((caddr_t
) &fdescvplock
, PINOD
);
fdescvplock
|= FDL_LOCKED
;
error
= getnewvnode(VT_UFS
, mp
, fdesc_vnodeop_p
, vpp
);
MALLOC((*vpp
)->v_data
, void *, sizeof(struct fdescnode
), M_TEMP
, M_WAITOK
);
VTOFDESC(*vpp
)->fd_type
= ftype
;
VTOFDESC(*vpp
)->fd_fd
= -1;
VTOFDESC(*vpp
)->fd_link
= 0;
VTOFDESC(*vpp
)->fd_ix
= ix
;
fdescvplock
&= ~FDL_LOCKED
;
if (fdescvplock
& FDL_WANT
) {
fdescvplock
&= ~FDL_WANT
;
wakeup((caddr_t
) &fdescvplock
);
* vp is the current namei directory
* ndp is the name to locate in that directory...
struct vop_lookup_args
/* {
struct componentname * a_cnp;
struct vnode
**vpp
= ap
->a_vpp
;
struct vnode
*dvp
= ap
->a_dvp
;
printf("fdesc_lookup(%x)\n", ap
);
printf("fdesc_lookup(dp = %x, vpp = %x, cnp = %x)\n", dvp
, vpp
, ap
->a_cnp
);
pname
= ap
->a_cnp
->cn_nameptr
;
printf("fdesc_lookup(%s)\n", pname
);
if (ap
->a_cnp
->cn_namelen
== 1 && *pname
== '.') {
nfiles
= p
->p_fd
->fd_nfiles
;
switch (VTOFDESC(dvp
)->fd_type
) {
if (ap
->a_cnp
->cn_namelen
== 2 && bcmp(pname
, "fd", 2) == 0) {
error
= fdesc_allocvp(Fdevfd
, FD_DEVFD
, dvp
->v_mount
, &fvp
);
printf("fdesc_lookup: newvp = %x\n", fvp
);
if (ap
->a_cnp
->cn_namelen
== 3 && bcmp(pname
, "tty", 3) == 0) {
struct vnode
*ttyvp
= cttyvp(p
);
error
= fdesc_allocvp(Fctty
, FD_CTTY
, dvp
->v_mount
, &fvp
);
printf("fdesc_lookup: ttyvp = %x\n", fvp
);
switch (ap
->a_cnp
->cn_namelen
) {
if (bcmp(pname
, "stdin", 5) == 0) {
if (bcmp(pname
, "stdout", 6) == 0) {
if (bcmp(pname
, "stderr", 6) == 0) {
printf("fdesc_lookup: link -> %s\n", ln
);
error
= fdesc_allocvp(Flink
, fd
, dvp
->v_mount
, &fvp
);
VTOFDESC(fvp
)->fd_link
= ln
;
printf("fdesc_lookup: newvp = %x\n", fvp
);
if (ap
->a_cnp
->cn_namelen
== 2 && bcmp(pname
, "..", 2) == 0) {
error
= fdesc_root(dvp
->v_mount
, vpp
);
while (*pname
>= '0' && *pname
<= '9') {
fd
= 10 * fd
+ *pname
++ - '0';
printf("fdesc_lookup: fd = %d, *pname = %x\n", fd
, *pname
);
if (fd
>= nfiles
|| p
->p_fd
->fd_ofiles
[fd
] == NULL
) {
printf("fdesc_lookup: allocate new vnode\n");
error
= fdesc_allocvp(Fdesc
, FD_DESC
+fd
, dvp
->v_mount
, &fvp
);
VTOFDESC(fvp
)->fd_fd
= fd
;
printf("fdesc_lookup: newvp = %x\n", fvp
);
printf("fdesc_lookup: error = %d\n", error
);
struct vop_open_args
/* {
struct vnode
*vp
= ap
->a_vp
;
switch (VTOFDESC(vp
)->fd_type
) {
* XXX Kludge: set p->p_dupfd to contain the value of the
* the file descriptor being sought for duplication. The error
* return ensures that the vnode for this device will be
* released by vn_open. Open will detect this special error and
* take the actions in dupfdopen. Other callers of vn_open or
* VOP_OPEN will simply report the error.
ap
->a_p
->p_dupfd
= VTOFDESC(vp
)->fd_fd
; /* XXX */
error
= cttyopen(devctty
, ap
->a_mode
, 0, ap
->a_p
);
fdesc_attr(fd
, vap
, cred
, p
)
struct filedesc
*fdp
= p
->p_fd
;
printf("fdesc_attr: fd = %d, nfiles = %d\n", fd
, fdp
->fd_nfiles
);
if (fd
>= fdp
->fd_nfiles
|| (fp
= fdp
->fd_ofiles
[fd
]) == NULL
) {
printf("fdesc_attr: fp = %x (EBADF)\n", fp
);
error
= VOP_GETATTR((struct vnode
*) fp
->f_data
, vap
, cred
, p
);
if (error
== 0 && vap
->va_type
== VDIR
) {
* don't allow directories to show up because
* that causes loops in the namespace.
error
= soo_stat((struct socket
*)fp
->f_data
, &stb
);
vap
->va_mode
= stb
.st_mode
;
vap
->va_nlink
= stb
.st_nlink
;
vap
->va_uid
= stb
.st_uid
;
vap
->va_gid
= stb
.st_gid
;
vap
->va_fsid
= stb
.st_dev
;
vap
->va_fileid
= stb
.st_ino
;
vap
->va_size
= stb
.st_size
;
vap
->va_blocksize
= stb
.st_blksize
;
vap
->va_atime
= stb
.st_atimespec
;
vap
->va_mtime
= stb
.st_mtimespec
;
vap
->va_ctime
= stb
.st_ctimespec
;
vap
->va_gen
= stb
.st_gen
;
vap
->va_flags
= stb
.st_flags
;
vap
->va_rdev
= stb
.st_rdev
;
vap
->va_bytes
= stb
.st_blocks
* stb
.st_blksize
;
printf("fdesc_attr: returns error %d\n", error
);
struct vop_getattr_args
/* {
struct vnode
*vp
= ap
->a_vp
;
struct vattr
*vap
= ap
->a_vap
;
printf("fdesc_getattr: stat type = %d\n", VTOFDESC(vp
)->fd_type
);
switch (VTOFDESC(vp
)->fd_type
) {
bzero((caddr_t
) vap
, sizeof(*vap
));
vap
->va_fileid
= VTOFDESC(vp
)->fd_ix
;
switch (VTOFDESC(vp
)->fd_type
) {
vap
->va_mode
= S_IRUSR
|S_IXUSR
|S_IRGRP
|S_IXGRP
|S_IROTH
|S_IXOTH
;
/* vap->va_qsize = strlen(VTOFDESC(vp)->fd_link); */
vap
->va_size
= strlen(VTOFDESC(vp
)->fd_link
);
vap
->va_mode
= S_IRUSR
|S_IWUSR
|S_IRGRP
|S_IWGRP
|S_IROTH
|S_IWOTH
;
vap
->va_mode
= S_IRUSR
|S_IXUSR
|S_IRGRP
|S_IXGRP
|S_IROTH
|S_IXOTH
;
vap
->va_size
= DEV_BSIZE
;
vap
->va_fsid
= vp
->v_mount
->mnt_stat
.f_fsid
.val
[0];
vap
->va_blocksize
= DEV_BSIZE
;
vap
->va_atime
.ts_sec
= boottime
.tv_sec
;
vap
->va_atime
.ts_nsec
= 0;
vap
->va_mtime
= vap
->va_atime
;
vap
->va_ctime
= vap
->va_mtime
;
/* vap->va_qbytes = 0; */
printf("fdesc_getattr: stat desc #%d\n", VTOFDESC(vp
)->fd_fd
);
fd
= VTOFDESC(vp
)->fd_fd
;
error
= fdesc_attr(fd
, vap
, ap
->a_cred
, ap
->a_p
);
vp
->v_type
= vap
->va_type
;
printf("fdesc_getattr: stat returns 0\n");
struct vop_setattr_args
/* {
struct filedesc
*fdp
= ap
->a_p
->p_fd
;
* Can't mess with the root vnode
switch (VTOFDESC(ap
->a_vp
)->fd_type
) {
fd
= VTOFDESC(ap
->a_vp
)->fd_fd
;
printf("fdesc_setattr: fd = %d, nfiles = %d\n", fd
, fdp
->fd_nfiles
);
if (fd
>= fdp
->fd_nfiles
|| (fp
= fdp
->fd_ofiles
[fd
]) == NULL
) {
printf("fdesc_setattr: fp = %x (EBADF)\n", fp
);
* Can setattr the underlying vnode, but not sockets!
error
= VOP_SETATTR((struct vnode
*) fp
->f_data
, ap
->a_vap
, ap
->a_cred
, ap
->a_p
);
printf("fdesc_setattr: returns error %d\n", error
);
{ FD_DEVFD
, UIO_MX
, 2, "fd" },
{ FD_STDIN
, UIO_MX
, 5, "stdin" },
{ FD_STDOUT
, UIO_MX
, 6, "stdout" },
{ FD_STDERR
, UIO_MX
, 6, "stderr" },
{ FD_CTTY
, UIO_MX
, 3, "tty" },
struct vop_readdir_args
/* {
struct uio
*uio
= ap
->a_uio
;
switch (VTOFDESC(ap
->a_vp
)->fd_type
) {
fdp
= uio
->uio_procp
->p_fd
;
if (VTOFDESC(ap
->a_vp
)->fd_type
== Froot
) {
i
= uio
->uio_offset
/ UIO_MX
;
while (uio
->uio_resid
> 0) {
if (cttyvp(uio
->uio_procp
) == NULL
)
if ((dt
->d_fileno
-FD_STDIN
) >= fdp
->fd_nfiles
)
if (fdp
->fd_ofiles
[dt
->d_fileno
-FD_STDIN
] == NULL
)
bzero((caddr_t
) dp
, UIO_MX
);
dp
->d_fileno
= dt
->d_fileno
;
dp
->d_namlen
= dt
->d_namlen
;
dp
->d_reclen
= dt
->d_reclen
;
bcopy(dt
->d_name
, dp
->d_name
, dp
->d_namlen
+1);
error
= uiomove((caddr_t
) dp
, UIO_MX
, uio
);
uio
->uio_offset
= i
* UIO_MX
;
i
= uio
->uio_offset
/ UIO_MX
;
while (uio
->uio_resid
> 0) {
if (i
>= fdp
->fd_nfiles
) {
/* *ap->a_eofflagp = 1; */
if (fdp
->fd_ofiles
[i
] != NULL
) {
bzero((caddr_t
) dp
, UIO_MX
);
dp
->d_namlen
= sprintf(dp
->d_name
, "%d", i
);
* Fill in the remaining fields
dp
->d_fileno
= i
+ FD_STDIN
;
error
= uiomove((caddr_t
) dp
, UIO_MX
, uio
);
uio
->uio_offset
= i
* UIO_MX
;
struct vop_readlink_args
/* {
register struct vnode
*vp
= ap
->a_vp
;
if (VTOFDESC(vp
)->fd_type
== Flink
) {
char *ln
= VTOFDESC(vp
)->fd_link
;
error
= uiomove(ln
, strlen(ln
), ap
->a_uio
);
struct vop_read_args
/* {
switch (VTOFDESC(ap
->a_vp
)->fd_type
) {
error
= cttyread(devctty
, ap
->a_uio
, ap
->a_ioflag
);
struct vop_write_args
/* {
switch (VTOFDESC(ap
->a_vp
)->fd_type
) {
error
= cttywrite(devctty
, ap
->a_uio
, ap
->a_ioflag
);
struct vop_ioctl_args
/* {
printf("fdesc_ioctl: type = %d, command = %x\n",
VTOFDESC(ap
->a_vp
)->fd_type
, ap
->a_command
);
switch (VTOFDESC(ap
->a_vp
)->fd_type
) {
error
= cttyioctl(devctty
, ap
->a_command
, ap
->a_data
,
struct vop_select_args
/* {
switch (VTOFDESC(ap
->a_vp
)->fd_type
) {
error
= cttyselect(devctty
, ap
->a_fflags
, ap
->a_p
);
struct vop_inactive_args
/* {
struct vnode
*vp
= ap
->a_vp
;
* Clear out the v_type field to avoid
* nasty things happening in vgone().
printf("fdesc_inactive(%x)\n", vp
);
struct vop_reclaim_args
/* {
struct vnode
*vp
= ap
->a_vp
;
printf("fdesc_reclaim(%x)\n", vp
);
ix
= VTOFDESC(vp
)->fd_ix
;
if (ix
>= 0 && ix
< FD_MAX
) {
FREE(vp
->v_data
, M_TEMP
);
* Print out the contents of a /dev/fd vnode.
struct vop_print_args
/* {
printf("tag VT_NON, fdesc vnode\n");
struct vop_vfree_args
/* {
* /dev/fd vnode unsupported operation
* /dev/fd "should never get here" operation
* /dev/fd vnode null operation
#define fdesc_create ((int (*) __P((struct vop_create_args *)))fdesc_enotsupp)
#define fdesc_mknod ((int (*) __P((struct vop_mknod_args *)))fdesc_enotsupp)
#define fdesc_close ((int (*) __P((struct vop_close_args *)))nullop)
#define fdesc_access ((int (*) __P((struct vop_access_args *)))nullop)
#define fdesc_mmap ((int (*) __P((struct vop_mmap_args *)))fdesc_enotsupp)
#define fdesc_fsync ((int (*) __P((struct vop_fsync_args *)))nullop)
#define fdesc_seek ((int (*) __P((struct vop_seek_args *)))nullop)
#define fdesc_remove ((int (*) __P((struct vop_remove_args *)))fdesc_enotsupp)
#define fdesc_link ((int (*) __P((struct vop_link_args *)))fdesc_enotsupp)
#define fdesc_rename ((int (*) __P((struct vop_rename_args *)))fdesc_enotsupp)
#define fdesc_mkdir ((int (*) __P((struct vop_mkdir_args *)))fdesc_enotsupp)
#define fdesc_rmdir ((int (*) __P((struct vop_rmdir_args *)))fdesc_enotsupp)
#define fdesc_symlink ((int (*) __P((struct vop_symlink_args *)))fdesc_enotsupp)
#define fdesc_abortop ((int (*) __P((struct vop_abortop_args *)))nullop)
#define fdesc_lock ((int (*) __P((struct vop_lock_args *)))nullop)
#define fdesc_unlock ((int (*) __P((struct vop_unlock_args *)))nullop)
#define fdesc_bmap ((int (*) __P((struct vop_bmap_args *)))fdesc_badop)
#define fdesc_strategy ((int (*) __P((struct vop_strategy_args *)))fdesc_badop)
#define fdesc_islocked ((int (*) __P((struct vop_islocked_args *)))nullop)
#define fdesc_advlock ((int (*) __P((struct vop_advlock_args *)))fdesc_enotsupp)
((int (*) __P((struct vop_blkatoff_args *)))fdesc_enotsupp)
#define fdesc_vget ((int (*) __P((struct vop_vget_args *)))fdesc_enotsupp)
#define fdesc_valloc ((int(*) __P(( \
struct vnode **vpp))) fdesc_enotsupp)
((int (*) __P((struct vop_truncate_args *)))fdesc_enotsupp)
#define fdesc_update ((int (*) __P((struct vop_update_args *)))fdesc_enotsupp)
#define fdesc_bwrite ((int (*) __P((struct vop_bwrite_args *)))fdesc_enotsupp)
int (**fdesc_vnodeop_p
)();
struct vnodeopv_entry_desc fdesc_vnodeop_entries
[] = {
{ &vop_default_desc
, vn_default_error
},
{ &vop_lookup_desc
, fdesc_lookup
}, /* lookup */
{ &vop_create_desc
, fdesc_create
}, /* create */
{ &vop_mknod_desc
, fdesc_mknod
}, /* mknod */
{ &vop_open_desc
, fdesc_open
}, /* open */
{ &vop_close_desc
, fdesc_close
}, /* close */
{ &vop_access_desc
, fdesc_access
}, /* access */
{ &vop_getattr_desc
, fdesc_getattr
}, /* getattr */
{ &vop_setattr_desc
, fdesc_setattr
}, /* setattr */
{ &vop_read_desc
, fdesc_read
}, /* read */
{ &vop_write_desc
, fdesc_write
}, /* write */
{ &vop_ioctl_desc
, fdesc_ioctl
}, /* ioctl */
{ &vop_select_desc
, fdesc_select
}, /* select */
{ &vop_mmap_desc
, fdesc_mmap
}, /* mmap */
{ &vop_fsync_desc
, fdesc_fsync
}, /* fsync */
{ &vop_seek_desc
, fdesc_seek
}, /* seek */
{ &vop_remove_desc
, fdesc_remove
}, /* remove */
{ &vop_link_desc
, fdesc_link
}, /* link */
{ &vop_rename_desc
, fdesc_rename
}, /* rename */
{ &vop_mkdir_desc
, fdesc_mkdir
}, /* mkdir */
{ &vop_rmdir_desc
, fdesc_rmdir
}, /* rmdir */
{ &vop_symlink_desc
, fdesc_symlink
}, /* symlink */
{ &vop_readdir_desc
, fdesc_readdir
}, /* readdir */
{ &vop_readlink_desc
, fdesc_readlink
}, /* readlink */
{ &vop_abortop_desc
, fdesc_abortop
}, /* abortop */
{ &vop_inactive_desc
, fdesc_inactive
}, /* inactive */
{ &vop_reclaim_desc
, fdesc_reclaim
}, /* reclaim */
{ &vop_lock_desc
, fdesc_lock
}, /* lock */
{ &vop_unlock_desc
, fdesc_unlock
}, /* unlock */
{ &vop_bmap_desc
, fdesc_bmap
}, /* bmap */
{ &vop_strategy_desc
, fdesc_strategy
}, /* strategy */
{ &vop_print_desc
, fdesc_print
}, /* print */
{ &vop_islocked_desc
, fdesc_islocked
}, /* islocked */
{ &vop_advlock_desc
, fdesc_advlock
}, /* advlock */
{ &vop_blkatoff_desc
, fdesc_blkatoff
}, /* blkatoff */
{ &vop_valloc_desc
, fdesc_valloc
}, /* valloc */
{ &vop_vfree_desc
, fdesc_vfree
}, /* vfree */
{ &vop_truncate_desc
, fdesc_truncate
}, /* truncate */
{ &vop_update_desc
, fdesc_update
}, /* update */
{ &vop_bwrite_desc
, fdesc_bwrite
}, /* bwrite */
{ (struct vnodeop_desc
*)NULL
, (int(*)())NULL
}
struct vnodeopv_desc fdesc_vnodeop_opv_desc
=
{ &fdesc_vnodeop_p
, fdesc_vnodeop_entries
};