* Copyright (c) 1982, 1986, 1989 Regents of the University of California.
* %sccs.include.redist.c%
* @(#)sys_generic.c 7.38 (Berkeley) %G%
#include <sys/filedesc.h>
#include <sys/socketvar.h>
register struct read_args
*uap
;
register struct file
*fp
;
register struct filedesc
*fdp
= p
->p_fd
;
if (((unsigned)uap
->fdes
) >= fdp
->fd_nfiles
||
(fp
= fdp
->fd_ofiles
[uap
->fdes
]) == NULL
||
(fp
->f_flag
& FREAD
) == 0)
aiov
.iov_base
= (caddr_t
)uap
->cbuf
;
aiov
.iov_len
= uap
->count
;
auio
.uio_resid
= uap
->count
;
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
, uap
->fdes
, UIO_READ
, &ktriov
, cnt
, error
);
* Scatter read system call.
register struct readv_args
*uap
;
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 (((unsigned)uap
->fdes
) >= fdp
->fd_nfiles
||
(fp
= fdp
->fd_ofiles
[uap
->fdes
]) == NULL
||
(fp
->f_flag
& FREAD
) == 0)
/* note: can't use iovlen until iovcnt is validated */
iovlen
= uap
->iovcnt
* sizeof (struct iovec
);
if (uap
->iovcnt
> UIO_SMALLIOV
) {
if (uap
->iovcnt
> UIO_MAXIOV
)
MALLOC(iov
, struct iovec
*, iovlen
, M_IOV
, M_WAITOK
);
auio
.uio_iovcnt
= uap
->iovcnt
;
auio
.uio_segflg
= UIO_USERSPACE
;
if (error
= copyin((caddr_t
)uap
->iovp
, (caddr_t
)iov
, iovlen
))
for (i
= 0; i
< uap
->iovcnt
; i
++) {
auio
.uio_resid
+= iov
->iov_len
;
if (auio
.uio_resid
< 0) {
* 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
, uap
->fdes
, UIO_READ
, ktriov
,
register struct write_args
*uap
;
register struct file
*fp
;
register struct filedesc
*fdp
= p
->p_fd
;
if (((unsigned)uap
->fdes
) >= fdp
->fd_nfiles
||
(fp
= fdp
->fd_ofiles
[uap
->fdes
]) == NULL
||
(fp
->f_flag
& FWRITE
) == 0)
aiov
.iov_base
= (caddr_t
)uap
->cbuf
;
aiov
.iov_len
= uap
->count
;
auio
.uio_resid
= uap
->count
;
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
, uap
->fdes
, UIO_WRITE
,
* Gather write system call
register struct writev_args
*uap
;
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 (((unsigned)uap
->fdes
) >= fdp
->fd_nfiles
||
(fp
= fdp
->fd_ofiles
[uap
->fdes
]) == NULL
||
(fp
->f_flag
& FWRITE
) == 0)
/* note: can't use iovlen until iovcnt is validated */
iovlen
= uap
->iovcnt
* sizeof (struct iovec
);
if (uap
->iovcnt
> UIO_SMALLIOV
) {
if (uap
->iovcnt
> UIO_MAXIOV
)
MALLOC(iov
, struct iovec
*, iovlen
, M_IOV
, M_WAITOK
);
auio
.uio_iovcnt
= uap
->iovcnt
;
auio
.uio_segflg
= UIO_USERSPACE
;
if (error
= copyin((caddr_t
)uap
->iovp
, (caddr_t
)iov
, iovlen
))
for (i
= 0; i
< uap
->iovcnt
; i
++) {
auio
.uio_resid
+= iov
->iov_len
;
if (auio
.uio_resid
< 0) {
* 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
, uap
->fdes
, UIO_WRITE
,
register struct ioctl_args
*uap
;
register struct file
*fp
;
register struct filedesc
*fdp
= p
->p_fd
;
if ((unsigned)uap
->fdes
>= fdp
->fd_nfiles
||
(fp
= fdp
->fd_ofiles
[uap
->fdes
]) == NULL
)
if ((fp
->f_flag
& (FREAD
|FWRITE
)) == 0)
fdp
->fd_ofileflags
[uap
->fdes
] |= UF_EXCLOSE
;
fdp
->fd_ofileflags
[uap
->fdes
] &= ~UF_EXCLOSE
;
* Interpret high order word to find
* amount of data to be copied to/from the
if (size
> sizeof (stkbuf
)) {
memp
= (caddr_t
)malloc((u_long
)size
, M_IOCTLOPS
, M_WAITOK
);
error
= copyin(uap
->cmarg
, data
, (u_int
)size
);
*(caddr_t
*)data
= uap
->cmarg
;
} else if ((com
&IOC_OUT
) && size
)
* Zero the buffer so the user always
* gets back something deterministic.
*(caddr_t
*)data
= uap
->cmarg
;
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
, (int)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
, (int)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
, uap
->cmarg
, (u_int
)size
);
register struct select_args
*uap
;
fd_set ibits
[3], obits
[3];
int s
, ncoll
, ni
, error
= 0, timo
;
bzero((caddr_t
)ibits
, sizeof(ibits
));
bzero((caddr_t
)obits
, sizeof(obits
));
if (uap
->nd
> p
->p_fd
->fd_nfiles
)
uap
->nd
= p
->p_fd
->fd_nfiles
; /* forgiving; slightly wrong */
ni
= howmany(uap
->nd
, NFDBITS
);
#define getbits(name, x) \
error = copyin((caddr_t)uap->name, (caddr_t)&ibits[x], \
(unsigned)(ni * sizeof(fd_mask))); \
error
= copyin((caddr_t
)uap
->tv
, (caddr_t
)&atv
,
timevaladd(&atv
, (struct timeval
*)&time
);
* Avoid inadvertently sleeping forever.
error
= selscan(p
, ibits
, obits
, uap
->nd
, retval
);
/* this should be timercmp(&time, &atv, >=) */
if (uap
->tv
&& (time
.tv_sec
> atv
.tv_sec
||
time
.tv_sec
== atv
.tv_sec
&& time
.tv_usec
>= atv
.tv_usec
)) {
if ((p
->p_flag
& SSEL
) == 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) \
int error2 = copyout((caddr_t)&obits[x], (caddr_t)uap->name, \
(unsigned)(ni * sizeof(fd_mask))); \
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
& SSEL
)