* Copyright (c) 1982, 1986, 1989, 1991 Regents of the University of California.
* %sccs.include.redist.c%
* @(#)kern_descrip.c 7.27 (Berkeley) %G%
struct file
*filehead
; /* head of list of open files */
int nfiles
; /* actual number of open files */
* System calls on descriptors.
getdtablesize(p
, uap
, retval
)
*retval
= p
->p_rlimit
[RLIMIT_OFILE
].rlim_cur
;
* Duplicate a file descriptor.
register struct filedesc
*fdp
= p
->p_fd
;
if (uap
->i
&~ 077) { uap
->i
&= 077; return (dup2(p
, uap
, retval
)); }
if ((unsigned)uap
->i
>= fdp
->fd_nfiles
||
(fp
= fdp
->fd_ofiles
[uap
->i
]) == NULL
)
if (error
= fdalloc(p
, 0, &fd
))
fdp
->fd_ofileflags
[fd
] = fdp
->fd_ofileflags
[uap
->i
] &~ UF_EXCLOSE
;
if (fd
> fdp
->fd_lastfile
)
* Duplicate a file descriptor to a particular value.
register struct filedesc
*fdp
= p
->p_fd
;
register struct file
*fp
;
register u_int old
= uap
->from
, new = uap
->to
;
if (old
>= fdp
->fd_nfiles
||
(fp
= fdp
->fd_ofiles
[old
]) == NULL
||
new >= p
->p_rlimit
[RLIMIT_OFILE
].rlim_cur
)
if (new >= fdp
->fd_nfiles
) {
if (error
= fdalloc(p
, new, &i
))
} else if (fdp
->fd_ofiles
[new]) {
if (fdp
->fd_ofileflags
[new] & UF_MAPPED
)
* dup2() must succeed even if the close has an error.
(void) closef(fdp
->fd_ofiles
[new], p
);
fdp
->fd_ofiles
[new] = fp
;
fdp
->fd_ofileflags
[new] = fdp
->fd_ofileflags
[old
] &~ UF_EXCLOSE
;
if (new > fdp
->fd_lastfile
)
* The file control system call.
register struct filedesc
*fdp
= p
->p_fd
;
register struct file
*fp
;
int i
, tmp
, error
, flg
= F_POSIX
;
if ((unsigned)uap
->fd
>= fdp
->fd_nfiles
||
(fp
= fdp
->fd_ofiles
[uap
->fd
]) == NULL
)
pop
= &fdp
->fd_ofileflags
[uap
->fd
];
if ((unsigned)uap
->arg
>= p
->p_rlimit
[RLIMIT_OFILE
].rlim_cur
)
if (error
= fdalloc(p
, uap
->arg
, &i
))
fdp
->fd_ofileflags
[i
] = *pop
&~ UF_EXCLOSE
;
if (i
> fdp
->fd_lastfile
)
*pop
= (*pop
&~ 1) | (uap
->arg
& 1);
*retval
= OFLAGS(fp
->f_flag
);
fp
->f_flag
&= ~FCNTLFLAGS
;
fp
->f_flag
|= FFLAGS(uap
->arg
) & FCNTLFLAGS
;
tmp
= fp
->f_flag
& FNONBLOCK
;
error
= (*fp
->f_ops
->fo_ioctl
)(fp
, FIONBIO
, (caddr_t
)&tmp
, p
);
tmp
= fp
->f_flag
& FASYNC
;
error
= (*fp
->f_ops
->fo_ioctl
)(fp
, FIOASYNC
, (caddr_t
)&tmp
, p
);
fp
->f_flag
&= ~FNONBLOCK
;
(void) (*fp
->f_ops
->fo_ioctl
)(fp
, FIONBIO
, (caddr_t
)&tmp
, p
);
if (fp
->f_type
== DTYPE_SOCKET
) {
*retval
= ((struct socket
*)fp
->f_data
)->so_pgid
;
error
= (*fp
->f_ops
->fo_ioctl
)
(fp
, (int)TIOCGPGRP
, (caddr_t
)retval
, p
);
if (fp
->f_type
== DTYPE_SOCKET
) {
((struct socket
*)fp
->f_data
)->so_pgid
= uap
->arg
;
struct proc
*p1
= pfind(uap
->arg
);
uap
->arg
= p1
->p_pgrp
->pg_id
;
return ((*fp
->f_ops
->fo_ioctl
)
(fp
, (int)TIOCSPGRP
, (caddr_t
)&uap
->arg
, p
));
if (fp
->f_type
!= DTYPE_VNODE
)
vp
= (struct vnode
*)fp
->f_data
;
/* Copy in the lock structure */
error
= copyin((caddr_t
)uap
->arg
, (caddr_t
)&fl
, sizeof (fl
));
if (fl
.l_whence
== SEEK_CUR
)
fl
.l_start
+= fp
->f_offset
;
if ((fp
->f_flag
& FREAD
) == 0)
return (VOP_ADVLOCK(vp
, (caddr_t
)p
, F_SETLK
, &fl
, flg
));
if ((fp
->f_flag
& FWRITE
) == 0)
return (VOP_ADVLOCK(vp
, (caddr_t
)p
, F_SETLK
, &fl
, flg
));
return (VOP_ADVLOCK(vp
, (caddr_t
)p
, F_UNLCK
, &fl
,
if (fp
->f_type
!= DTYPE_VNODE
)
vp
= (struct vnode
*)fp
->f_data
;
/* Copy in the lock structure */
error
= copyin((caddr_t
)uap
->arg
, (caddr_t
)&fl
, sizeof (fl
));
if (fl
.l_whence
== SEEK_CUR
)
fl
.l_start
+= fp
->f_offset
;
if (error
= VOP_ADVLOCK(vp
, (caddr_t
)p
, F_GETLK
, &fl
, F_POSIX
))
return (copyout((caddr_t
)&fl
, (caddr_t
)uap
->arg
, sizeof (fl
)));
* Close a file descriptor.
register struct filedesc
*fdp
= p
->p_fd
;
register struct file
*fp
;
register int fd
= uap
->fd
;
if ((unsigned)fd
>= fdp
->fd_nfiles
||
(fp
= fdp
->fd_ofiles
[fd
]) == NULL
)
pf
= (u_char
*)&fdp
->fd_ofileflags
[fd
];
fdp
->fd_ofiles
[fd
] = NULL
;
while (fdp
->fd_lastfile
> 0 && fdp
->fd_ofiles
[fdp
->fd_lastfile
] == NULL
)
if (fd
< fdp
->fd_freefile
)
* Return status information about a file descriptor.
register struct filedesc
*fdp
= p
->p_fd
;
register struct file
*fp
;
if ((unsigned)uap
->fd
>= fdp
->fd_nfiles
||
(fp
= fdp
->fd_ofiles
[uap
->fd
]) == NULL
)
error
= vn_stat((struct vnode
*)fp
->f_data
, &ub
, p
);
error
= soo_stat((struct socket
*)fp
->f_data
, &ub
);
error
= copyout((caddr_t
)&ub
, (caddr_t
)uap
->sb
, sizeof (ub
));
* Allocate a file descriptor for the process.
register struct filedesc
*fdp
= p
->p_fd
;
* Search for a free descriptor starting at the higher
* of want or fd_freefile. If that fails, consider
* expanding the ofile array.
lim
= p
->p_rlimit
[RLIMIT_OFILE
].rlim_cur
;
last
= min(fdp
->fd_nfiles
, lim
);
if ((i
= want
) < fdp
->fd_freefile
)
if (fdp
->fd_ofiles
[i
] == NULL
) {
fdp
->fd_ofileflags
[i
] = 0;
if (i
> fdp
->fd_lastfile
)
if (want
<= fdp
->fd_freefile
)
* No space in current array. Expand?
if (fdp
->fd_nfiles
>= lim
)
if (fdp
->fd_nfiles
< NDEXTENT
)
nfiles
= 2 * fdp
->fd_nfiles
;
MALLOC(newofile
, struct file
**, nfiles
* OFILESIZE
,
newofileflags
= (char *) &newofile
[nfiles
];
* Copy the existing ofile and ofileflags arrays
* and zero the new portion of each array.
bcopy(fdp
->fd_ofiles
, newofile
,
(i
= sizeof(struct file
*) * fdp
->fd_nfiles
));
bzero((char *)newofile
+ i
, nfiles
* sizeof(struct file
*) - i
);
bcopy(fdp
->fd_ofileflags
, newofileflags
,
(i
= sizeof(char) * fdp
->fd_nfiles
));
bzero(newofileflags
+ i
, nfiles
* sizeof(char) - i
);
if (fdp
->fd_nfiles
> NDFILE
)
FREE(fdp
->fd_ofiles
, M_FILEDESC
);
fdp
->fd_ofiles
= newofile
;
fdp
->fd_ofileflags
= newofileflags
;
* Check to see whether n user file descriptors
* are available to the process p.
register struct filedesc
*fdp
= p
->p_fd
;
register struct file
**fpp
;
if ((i
= p
->p_rlimit
[RLIMIT_OFILE
].rlim_cur
- fdp
->fd_nfiles
) > 0 &&
fpp
= &fdp
->fd_ofiles
[fdp
->fd_freefile
];
for (i
= fdp
->fd_nfiles
- fdp
->fd_freefile
; --i
>= 0; fpp
++)
if (*fpp
== NULL
&& --n
<= 0)
* Create a new open file structure and allocate
* a file decriptor for the process that refers to it.
falloc(p
, resultfp
, resultfd
)
register struct file
*fp
, *fq
, **fpp
;
if (error
= fdalloc(p
, 0, &i
))
if (nfiles
>= maxfiles
) {
* Allocate a new file descriptor.
* If the process has file descriptor zero open, add to the list
* of open files at that point, otherwise put it at the front of
* the list of open files.
MALLOC(fp
, struct file
*, sizeof(struct file
), M_FILE
, M_WAITOK
);
p
->p_fd
->fd_ofiles
[i
] = fp
;
if (fq
= p
->p_fd
->fd_ofiles
[0])
fq
->f_fileb
= &fp
->f_filef
;
* Free a file descriptor.
register struct file
*fp
;
register struct file
*fq
;
fq
->f_fileb
= fp
->f_fileb
;
* Copy a filedesc structure.
register struct filedesc
*newfdp
, *fdp
= p
->p_fd
;
register struct file
**fpp
;
MALLOC(newfdp
, struct filedesc
*, sizeof(struct filedesc0
),
bcopy(fdp
, newfdp
, sizeof(struct filedesc
));
* If the number of open files fits in the internal arrays
* of the open file structure, use them, otherwise allocate
* additional memory for the number of descriptors currently
if (newfdp
->fd_lastfile
< NDFILE
) {
newfdp
->fd_ofiles
= ((struct filedesc0
*) newfdp
)->fd_dfiles
;
((struct filedesc0
*) newfdp
)->fd_dfileflags
;
* Compute the smallest multiple of NDEXTENT needed
* for the file descriptors currently in use,
* allowing the table to shrink.
while (i
> 2 * NDEXTENT
&& i
>= newfdp
->fd_lastfile
* 2)
MALLOC(newfdp
->fd_ofiles
, struct file
**, i
* OFILESIZE
,
newfdp
->fd_ofileflags
= (char *) &newfdp
->fd_ofiles
[i
];
bcopy(fdp
->fd_ofiles
, newfdp
->fd_ofiles
, i
* sizeof(struct file
**));
bcopy(fdp
->fd_ofileflags
, newfdp
->fd_ofileflags
, i
* sizeof(char));
for (i
= newfdp
->fd_lastfile
; i
-- >= 0; fpp
++)
* Release a filedesc structure.
register struct filedesc
*fdp
= p
->p_fd
;
if (--fdp
->fd_refcnt
> 0)
for (i
= fdp
->fd_lastfile
; i
-- >= 0; fpp
++)
if (fdp
->fd_nfiles
> NDFILE
)
FREE(fdp
->fd_ofiles
, M_FILEDESC
);
* Internal form of close.
* Decrement reference count on file structure.
register struct file
*fp
;
* POSIX record locking dictates that any close releases ALL
* locks owned by this process. This is handled by setting
* a flag in the unlock to free ONLY locks obeying POSIX
* semantics, and not to free BSD-style file locks.
if ((p
->p_flag
& SADVLCK
) && fp
->f_type
== DTYPE_VNODE
) {
vp
= (struct vnode
*)fp
->f_data
;
(void) VOP_ADVLOCK(vp
, (caddr_t
)p
, F_UNLCK
, &lf
, F_POSIX
);
panic("closef: count < 0");
if ((fp
->f_flag
& FHASLOCK
) && fp
->f_type
== DTYPE_VNODE
) {
vp
= (struct vnode
*)fp
->f_data
;
(void) VOP_ADVLOCK(vp
, (caddr_t
)fp
, F_UNLCK
, &lf
, F_FLOCK
);
error
= (*fp
->f_ops
->fo_close
)(fp
, p
);
* Apply an advisory lock on a file descriptor.
* Just attempt to get a record lock of the requested type on
* the entire file (l_whence = SEEK_SET, l_start = 0, l_len = 0).
register struct filedesc
*fdp
= p
->p_fd
;
register struct file
*fp
;
if ((unsigned)uap
->fd
>= fdp
->fd_nfiles
||
(fp
= fdp
->fd_ofiles
[uap
->fd
]) == NULL
)
if (fp
->f_type
!= DTYPE_VNODE
)
vp
= (struct vnode
*)fp
->f_data
;
if (uap
->how
& LOCK_UN
) {
return (VOP_ADVLOCK(vp
, (caddr_t
)fp
, F_UNLCK
, &lf
, F_FLOCK
));
else if (uap
->how
& LOCK_SH
)
return (VOP_ADVLOCK(vp
, (caddr_t
)fp
, F_SETLK
, &lf
, F_FLOCK
));
return (VOP_ADVLOCK(vp
, (caddr_t
)fp
, F_SETLK
, &lf
, F_FLOCK
|F_WAIT
));
* File Descriptor pseudo-device driver (/dev/fd/).
* Opening minor device N dup()s the file (if any) connected to file
* descriptor N belonging to the calling process. Note that this driver
* consists of only the ``open()'' routine, because all subsequent
* references to this file will be direct to the other driver.
* XXX Kludge: set curproc->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 below. Other callers of vn_open or VOP_OPEN
* will simply report the error.
curproc
->p_dupfd
= minor(dev
); /* XXX */
* Duplicate the specified descriptor to a free descriptor.
dupfdopen(fdp
, indx
, dfd
, mode
)
register struct filedesc
*fdp
;
register struct file
*wfp
;
* If the to-be-dup'd fd number is greater than the allowed number
* of file descriptors, or the fd to be dup'd has already been
* closed, reject. Note, check for new == old is necessary as
* falloc could allocate an already closed to-be-dup'd descriptor
fp
= fdp
->fd_ofiles
[indx
];
if ((u_int
)dfd
>= fdp
->fd_nfiles
||
(wfp
= fdp
->fd_ofiles
[dfd
]) == NULL
|| fp
== wfp
)
* Check that the mode the file is being opened for is a subset
* of the mode of the existing descriptor.
if (((mode
& (FREAD
|FWRITE
)) | wfp
->f_flag
) != wfp
->f_flag
)
fdp
->fd_ofiles
[indx
] = wfp
;
fdp
->fd_ofileflags
[indx
] = fdp
->fd_ofileflags
[dfd
];
if (indx
> fdp
->fd_lastfile
)