* Copyright (c) 1982, 1986, 1989, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
* %sccs.include.redist.c%
* @(#)sys_generic.c 8.9 (Berkeley) %G%
#include <sys/filedesc.h>
#include <sys/socketvar.h>
#include <sys/syscallargs.h>
register struct read_args
/* {
register struct file
*fp
;
register struct filedesc
*fdp
= p
->p_fd
;
if (((u_int
)SCARG(uap
, fd
)) >= fdp
->fd_nfiles
||
(fp
= fdp
->fd_ofiles
[SCARG(uap
, fd
)]) == NULL
||
(fp
->f_flag
& FREAD
) == 0)
aiov
.iov_base
= (caddr_t
)SCARG(uap
, buf
);
aiov
.iov_len
= SCARG(uap
, nbyte
);
auio
.uio_resid
= SCARG(uap
, nbyte
);
auio
.uio_segflg
= UIO_USERSPACE
;
* if tracing, save a copy of iovec
if (KTRPOINT(p
, KTR_GENIO
))
if (error
= (*fp
->f_ops
->fo_read
)(fp
, &auio
, fp
->f_cred
))
if (auio
.uio_resid
!= cnt
&& (error
== ERESTART
||
error
== EINTR
|| error
== EWOULDBLOCK
))
if (KTRPOINT(p
, KTR_GENIO
) && error
== 0)
ktrgenio(p
->p_tracep
, SCARG(uap
, fd
), UIO_READ
, &ktriov
,
* Scatter read system call.
register struct readv_args
/* {
syscallarg(struct iovec *) iovp;
syscallarg(u_int) iovcnt;
register struct file
*fp
;
register struct filedesc
*fdp
= p
->p_fd
;
register struct iovec
*iov
;
struct iovec aiov
[UIO_SMALLIOV
];
struct iovec
*ktriov
= NULL
;
if (((u_int
)SCARG(uap
, fd
)) >= fdp
->fd_nfiles
||
(fp
= fdp
->fd_ofiles
[SCARG(uap
, fd
)]) == NULL
||
(fp
->f_flag
& FREAD
) == 0)
/* note: can't use iovlen until iovcnt is validated */
iovlen
= SCARG(uap
, iovcnt
) * sizeof (struct iovec
);
if (SCARG(uap
, iovcnt
) > UIO_SMALLIOV
) {
if (SCARG(uap
, iovcnt
) > UIO_MAXIOV
)
MALLOC(iov
, struct iovec
*, iovlen
, M_IOV
, M_WAITOK
);
auio
.uio_iovcnt
= SCARG(uap
, iovcnt
);
auio
.uio_segflg
= UIO_USERSPACE
;
if (error
= copyin((caddr_t
)SCARG(uap
, iovp
), (caddr_t
)iov
, iovlen
))
for (i
= 0; i
< SCARG(uap
, iovcnt
); i
++) {
if (auio
.uio_resid
+ iov
->iov_len
< auio
.uio_resid
) {
auio
.uio_resid
+= iov
->iov_len
;
* if tracing, save a copy of iovec
if (KTRPOINT(p
, KTR_GENIO
)) {
MALLOC(ktriov
, struct iovec
*, iovlen
, M_TEMP
, M_WAITOK
);
bcopy((caddr_t
)auio
.uio_iov
, (caddr_t
)ktriov
, iovlen
);
if (error
= (*fp
->f_ops
->fo_read
)(fp
, &auio
, fp
->f_cred
))
if (auio
.uio_resid
!= cnt
&& (error
== ERESTART
||
error
== EINTR
|| error
== EWOULDBLOCK
))
ktrgenio(p
->p_tracep
, SCARG(uap
, fd
), UIO_READ
, ktriov
,
register struct write_args
/* {
register struct file
*fp
;
register struct filedesc
*fdp
= p
->p_fd
;
if (((u_int
)SCARG(uap
, fd
)) >= fdp
->fd_nfiles
||
(fp
= fdp
->fd_ofiles
[SCARG(uap
, fd
)]) == NULL
||
(fp
->f_flag
& FWRITE
) == 0)
aiov
.iov_base
= (caddr_t
)SCARG(uap
, buf
);
aiov
.iov_len
= SCARG(uap
, nbyte
);
auio
.uio_resid
= SCARG(uap
, nbyte
);
auio
.uio_segflg
= UIO_USERSPACE
;
* if tracing, save a copy of iovec
if (KTRPOINT(p
, KTR_GENIO
))
if (error
= (*fp
->f_ops
->fo_write
)(fp
, &auio
, fp
->f_cred
)) {
if (auio
.uio_resid
!= cnt
&& (error
== ERESTART
||
error
== EINTR
|| error
== EWOULDBLOCK
))
if (KTRPOINT(p
, KTR_GENIO
) && error
== 0)
ktrgenio(p
->p_tracep
, SCARG(uap
, fd
), UIO_WRITE
,
* Gather write system call
register struct writev_args
/* {
syscallarg(struct iovec *) iovp;
syscallarg(u_int) iovcnt;
register struct file
*fp
;
register struct filedesc
*fdp
= p
->p_fd
;
register struct iovec
*iov
;
struct iovec aiov
[UIO_SMALLIOV
];
struct iovec
*ktriov
= NULL
;
if (((u_int
)SCARG(uap
, fd
)) >= fdp
->fd_nfiles
||
(fp
= fdp
->fd_ofiles
[SCARG(uap
, fd
)]) == NULL
||
(fp
->f_flag
& FWRITE
) == 0)
/* note: can't use iovlen until iovcnt is validated */
iovlen
= SCARG(uap
, iovcnt
) * sizeof (struct iovec
);
if (SCARG(uap
, iovcnt
) > UIO_SMALLIOV
) {
if (SCARG(uap
, iovcnt
) > UIO_MAXIOV
)
MALLOC(iov
, struct iovec
*, iovlen
, M_IOV
, M_WAITOK
);
auio
.uio_iovcnt
= SCARG(uap
, iovcnt
);
auio
.uio_segflg
= UIO_USERSPACE
;
if (error
= copyin((caddr_t
)SCARG(uap
, iovp
), (caddr_t
)iov
, iovlen
))
for (i
= 0; i
< SCARG(uap
, iovcnt
); i
++) {
if (auio
.uio_resid
+ iov
->iov_len
< auio
.uio_resid
) {
auio
.uio_resid
+= iov
->iov_len
;
* if tracing, save a copy of iovec
if (KTRPOINT(p
, KTR_GENIO
)) {
MALLOC(ktriov
, struct iovec
*, iovlen
, M_TEMP
, M_WAITOK
);
bcopy((caddr_t
)auio
.uio_iov
, (caddr_t
)ktriov
, iovlen
);
if (error
= (*fp
->f_ops
->fo_write
)(fp
, &auio
, fp
->f_cred
)) {
if (auio
.uio_resid
!= cnt
&& (error
== ERESTART
||
error
== EINTR
|| error
== EWOULDBLOCK
))
ktrgenio(p
->p_tracep
, SCARG(uap
, fd
), UIO_WRITE
,
register struct ioctl_args
/* {
syscallarg(caddr_t) data;
register struct file
*fp
;
register struct filedesc
*fdp
;
if ((u_int
)SCARG(uap
, fd
) >= fdp
->fd_nfiles
||
(fp
= fdp
->fd_ofiles
[SCARG(uap
, fd
)]) == NULL
)
if ((fp
->f_flag
& (FREAD
| FWRITE
)) == 0)
switch (com
= SCARG(uap
, com
)) {
fdp
->fd_ofileflags
[SCARG(uap
, fd
)] &= ~UF_EXCLOSE
;
fdp
->fd_ofileflags
[SCARG(uap
, fd
)] |= UF_EXCLOSE
;
* Interpret high order word to find amount of data to be
* copied to/from the user's address space.
if (size
> sizeof (stkbuf
)) {
memp
= (caddr_t
)malloc((u_long
)size
, M_IOCTLOPS
, M_WAITOK
);
error
= copyin(SCARG(uap
, data
), data
, (u_int
)size
);
*(caddr_t
*)data
= SCARG(uap
, data
);
} else if ((com
&IOC_OUT
) && size
)
* Zero the buffer so the user always
* gets back something deterministic.
*(caddr_t
*)data
= SCARG(uap
, data
);
fp
->f_flag
&= ~FNONBLOCK
;
error
= (*fp
->f_ops
->fo_ioctl
)(fp
, FIONBIO
, (caddr_t
)&tmp
, p
);
error
= (*fp
->f_ops
->fo_ioctl
)(fp
, FIOASYNC
, (caddr_t
)&tmp
, p
);
if (fp
->f_type
== DTYPE_SOCKET
) {
((struct socket
*)fp
->f_data
)->so_pgid
= tmp
;
struct proc
*p1
= pfind(tmp
);
error
= (*fp
->f_ops
->fo_ioctl
)
(fp
, TIOCSPGRP
, (caddr_t
)&tmp
, p
);
if (fp
->f_type
== DTYPE_SOCKET
) {
*(int *)data
= ((struct socket
*)fp
->f_data
)->so_pgid
;
error
= (*fp
->f_ops
->fo_ioctl
)(fp
, TIOCGPGRP
, data
, p
);
*(int *)data
= -*(int *)data
;
error
= (*fp
->f_ops
->fo_ioctl
)(fp
, com
, data
, p
);
* Copy any data to user, size was
* already set and checked above.
if (error
== 0 && (com
&IOC_OUT
) && size
)
error
= copyout(data
, SCARG(uap
, data
), (u_int
)size
);
register struct select_args
/* {
syscallarg(struct timeval *) tv;
fd_set ibits
[3], obits
[3];
int s
, ncoll
, error
, timo
= 0;
bzero((caddr_t
)ibits
, sizeof(ibits
));
bzero((caddr_t
)obits
, sizeof(obits
));
if (SCARG(uap
, nd
) > FD_SETSIZE
)
if (SCARG(uap
, nd
) > p
->p_fd
->fd_nfiles
) {
/* forgiving; slightly wrong */
SCARG(uap
, nd
) = p
->p_fd
->fd_nfiles
;
ni
= howmany(SCARG(uap
, nd
), NFDBITS
) * sizeof(fd_mask
);
#define getbits(name, x) \
if (SCARG(uap, name) && (error = copyin((caddr_t)SCARG(uap, name), \
(caddr_t)&ibits[x], ni))) \
error
= copyin((caddr_t
)SCARG(uap
, tv
), (caddr_t
)&atv
,
timevaladd(&atv
, (struct timeval
*)&time
);
error
= selscan(p
, ibits
, obits
, SCARG(uap
, nd
), retval
);
if (timercmp(&time
, &atv
, >=)) {
* If poll wait was tiny, this could be zero; we will
* have to round it up to avoid sleeping forever. If
* we retry below, the timercmp above will get us out.
* Note that if wait was 0, the timercmp will prevent
* us from getting here the first time.
if ((p
->p_flag
& P_SELECT
) == 0 || nselcoll
!= ncoll
) {
error
= tsleep((caddr_t
)&selwait
, PSOCK
| PCATCH
, "select", timo
);
/* select is not restarted after signals... */
if (error
== EWOULDBLOCK
)
#define putbits(name, x) \
if (SCARG(uap, name) && (error2 = copyout((caddr_t)&obits[x], \
(caddr_t)SCARG(uap, name), ni))) \
selscan(p
, ibits
, obits
, nfd
, retval
)
register struct filedesc
*fdp
= p
->p_fd
;
register int msk
, i
, j
, fd
;
static int flag
[3] = { FREAD
, FWRITE
, 0 };
for (msk
= 0; msk
< 3; msk
++) {
for (i
= 0; i
< nfd
; i
+= NFDBITS
) {
bits
= ibits
[msk
].fds_bits
[i
/NFDBITS
];
while ((j
= ffs(bits
)) && (fd
= i
+ --j
) < nfd
) {
if ((*fp
->f_ops
->fo_select
)(fp
, flag
[msk
], p
)) {
* Record a select request.
if (sip
->si_pid
== mypid
)
if (sip
->si_pid
&& (p
= pfind(sip
->si_pid
)) &&
p
->p_wchan
== (caddr_t
)&selwait
)
sip
->si_flags
|= SI_COLL
;
* Do a wakeup when a selectable event occurs.
register struct selinfo
*sip
;
if (sip
->si_flags
& SI_COLL
) {
sip
->si_flags
&= ~SI_COLL
;
wakeup((caddr_t
)&selwait
);
if (p
->p_wchan
== (caddr_t
)&selwait
) {
} else if (p
->p_flag
& P_SELECT
)