Commit | Line | Data |
---|---|---|
da7c5cc6 | 1 | /* |
9302ea08 KB |
2 | * Copyright (c) 1982, 1986, 1989, 1993 |
3 | * The Regents of the University of California. All rights reserved. | |
adb35f79 KB |
4 | * (c) UNIX System Laboratories, Inc. |
5 | * All or some portions of this file are derived from material licensed | |
6 | * to the University of California by American Telephone and Telegraph | |
7 | * Co. or Unix System Laboratories, Inc. and are reproduced herein with | |
8 | * the permission of UNIX System Laboratories, Inc. | |
da7c5cc6 | 9 | * |
dbf0c423 | 10 | * %sccs.include.redist.c% |
c4ec2128 | 11 | * |
adb35f79 | 12 | * @(#)sys_generic.c 8.5 (Berkeley) %G% |
da7c5cc6 | 13 | */ |
ffe28cfe | 14 | |
38a01dbe KB |
15 | #include <sys/param.h> |
16 | #include <sys/systm.h> | |
17 | #include <sys/filedesc.h> | |
18 | #include <sys/ioctl.h> | |
19 | #include <sys/file.h> | |
20 | #include <sys/proc.h> | |
21 | #include <sys/socketvar.h> | |
22 | #include <sys/uio.h> | |
23 | #include <sys/kernel.h> | |
24 | #include <sys/stat.h> | |
25 | #include <sys/malloc.h> | |
46814581 | 26 | #ifdef KTRACE |
38a01dbe | 27 | #include <sys/ktrace.h> |
46814581 | 28 | #endif |
ffe28cfe BJ |
29 | |
30 | /* | |
31 | * Read system call. | |
32 | */ | |
1d369105 | 33 | struct read_args { |
7121fdf0 KB |
34 | int fd; |
35 | char *buf; | |
36 | u_int nbyte; | |
1d369105 | 37 | }; |
25ed1cf1 | 38 | /* ARGSUSED */ |
c9714ae3 KM |
39 | read(p, uap, retval) |
40 | struct proc *p; | |
1d369105 | 41 | register struct read_args *uap; |
c9714ae3 KM |
42 | int *retval; |
43 | { | |
c4ec2128 | 44 | register struct file *fp; |
5e00df3b | 45 | register struct filedesc *fdp = p->p_fd; |
32a43ee2 BJ |
46 | struct uio auio; |
47 | struct iovec aiov; | |
c4ec2128 KM |
48 | long cnt, error = 0; |
49 | #ifdef KTRACE | |
50 | struct iovec ktriov; | |
51 | #endif | |
ffe28cfe | 52 | |
7121fdf0 KB |
53 | if (((u_int)uap->fd) >= fdp->fd_nfiles || |
54 | (fp = fdp->fd_ofiles[uap->fd]) == NULL || | |
c4ec2128 | 55 | (fp->f_flag & FREAD) == 0) |
d9c2f47f | 56 | return (EBADF); |
7121fdf0 KB |
57 | aiov.iov_base = (caddr_t)uap->buf; |
58 | aiov.iov_len = uap->nbyte; | |
32a43ee2 BJ |
59 | auio.uio_iov = &aiov; |
60 | auio.uio_iovcnt = 1; | |
7121fdf0 | 61 | auio.uio_resid = uap->nbyte; |
c4ec2128 KM |
62 | auio.uio_rw = UIO_READ; |
63 | auio.uio_segflg = UIO_USERSPACE; | |
221dba7d | 64 | auio.uio_procp = p; |
c4ec2128 KM |
65 | #ifdef KTRACE |
66 | /* | |
67 | * if tracing, save a copy of iovec | |
68 | */ | |
c9714ae3 | 69 | if (KTRPOINT(p, KTR_GENIO)) |
c4ec2128 KM |
70 | ktriov = aiov; |
71 | #endif | |
7121fdf0 | 72 | cnt = uap->nbyte; |
9754d709 MK |
73 | if (error = (*fp->f_ops->fo_read)(fp, &auio, fp->f_cred)) |
74 | if (auio.uio_resid != cnt && (error == ERESTART || | |
75 | error == EINTR || error == EWOULDBLOCK)) | |
76 | error = 0; | |
c4ec2128 KM |
77 | cnt -= auio.uio_resid; |
78 | #ifdef KTRACE | |
c9714ae3 | 79 | if (KTRPOINT(p, KTR_GENIO) && error == 0) |
7121fdf0 | 80 | ktrgenio(p->p_tracep, uap->fd, UIO_READ, &ktriov, cnt, error); |
c4ec2128 | 81 | #endif |
c9714ae3 | 82 | *retval = cnt; |
d9c2f47f | 83 | return (error); |
b9429893 BJ |
84 | } |
85 | ||
c9714ae3 KM |
86 | /* |
87 | * Scatter read system call. | |
88 | */ | |
1d369105 CT |
89 | struct readv_args { |
90 | int fdes; | |
91 | struct iovec *iovp; | |
7121fdf0 | 92 | u_int iovcnt; |
1d369105 | 93 | }; |
c9714ae3 KM |
94 | readv(p, uap, retval) |
95 | struct proc *p; | |
1d369105 | 96 | register struct readv_args *uap; |
c9714ae3 KM |
97 | int *retval; |
98 | { | |
c4ec2128 | 99 | register struct file *fp; |
5e00df3b | 100 | register struct filedesc *fdp = p->p_fd; |
b9429893 | 101 | struct uio auio; |
c4ec2128 | 102 | register struct iovec *iov; |
7b7210d3 | 103 | struct iovec *needfree; |
c4ec2128 KM |
104 | struct iovec aiov[UIO_SMALLIOV]; |
105 | long i, cnt, error = 0; | |
7121fdf0 | 106 | u_int iovlen; |
c4ec2128 KM |
107 | #ifdef KTRACE |
108 | struct iovec *ktriov = NULL; | |
109 | #endif | |
b9429893 | 110 | |
7121fdf0 | 111 | if (((u_int)uap->fdes) >= fdp->fd_nfiles || |
43ed8e9d | 112 | (fp = fdp->fd_ofiles[uap->fdes]) == NULL || |
c4ec2128 | 113 | (fp->f_flag & FREAD) == 0) |
d9c2f47f | 114 | return (EBADF); |
c9773de9 MK |
115 | /* note: can't use iovlen until iovcnt is validated */ |
116 | iovlen = uap->iovcnt * sizeof (struct iovec); | |
46814581 | 117 | if (uap->iovcnt > UIO_SMALLIOV) { |
c4ec2128 | 118 | if (uap->iovcnt > UIO_MAXIOV) |
d9c2f47f | 119 | return (EINVAL); |
c9773de9 | 120 | MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK); |
7b7210d3 CT |
121 | needfree = iov; |
122 | } else { | |
46814581 | 123 | iov = aiov; |
7b7210d3 CT |
124 | needfree = NULL; |
125 | } | |
46814581 | 126 | auio.uio_iov = iov; |
b9429893 | 127 | auio.uio_iovcnt = uap->iovcnt; |
c4ec2128 KM |
128 | auio.uio_rw = UIO_READ; |
129 | auio.uio_segflg = UIO_USERSPACE; | |
221dba7d | 130 | auio.uio_procp = p; |
c9773de9 | 131 | if (error = copyin((caddr_t)uap->iovp, (caddr_t)iov, iovlen)) |
46814581 | 132 | goto done; |
c4ec2128 KM |
133 | auio.uio_resid = 0; |
134 | for (i = 0; i < uap->iovcnt; i++) { | |
135 | if (iov->iov_len < 0) { | |
136 | error = EINVAL; | |
137 | goto done; | |
138 | } | |
139 | auio.uio_resid += iov->iov_len; | |
140 | if (auio.uio_resid < 0) { | |
141 | error = EINVAL; | |
142 | goto done; | |
143 | } | |
144 | iov++; | |
145 | } | |
146 | #ifdef KTRACE | |
147 | /* | |
148 | * if tracing, save a copy of iovec | |
149 | */ | |
c9714ae3 | 150 | if (KTRPOINT(p, KTR_GENIO)) { |
c4ec2128 KM |
151 | MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK); |
152 | bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen); | |
153 | } | |
154 | #endif | |
155 | cnt = auio.uio_resid; | |
9754d709 MK |
156 | if (error = (*fp->f_ops->fo_read)(fp, &auio, fp->f_cred)) |
157 | if (auio.uio_resid != cnt && (error == ERESTART || | |
158 | error == EINTR || error == EWOULDBLOCK)) | |
159 | error = 0; | |
c4ec2128 KM |
160 | cnt -= auio.uio_resid; |
161 | #ifdef KTRACE | |
162 | if (ktriov != NULL) { | |
e64d087d | 163 | if (error == 0) |
51322105 KM |
164 | ktrgenio(p->p_tracep, uap->fdes, UIO_READ, ktriov, |
165 | cnt, error); | |
c4ec2128 KM |
166 | FREE(ktriov, M_TEMP); |
167 | } | |
168 | #endif | |
c9714ae3 | 169 | *retval = cnt; |
46814581 | 170 | done: |
7b7210d3 CT |
171 | if (needfree) |
172 | FREE(needfree, M_IOV); | |
d9c2f47f | 173 | return (error); |
ffe28cfe BJ |
174 | } |
175 | ||
176 | /* | |
177 | * Write system call | |
178 | */ | |
1d369105 | 179 | struct write_args { |
7121fdf0 KB |
180 | int fd; |
181 | char *buf; | |
182 | u_int nbyte; | |
1d369105 | 183 | }; |
c9714ae3 KM |
184 | write(p, uap, retval) |
185 | struct proc *p; | |
1d369105 | 186 | register struct write_args *uap; |
c9714ae3 KM |
187 | int *retval; |
188 | { | |
c4ec2128 | 189 | register struct file *fp; |
5e00df3b | 190 | register struct filedesc *fdp = p->p_fd; |
b9429893 BJ |
191 | struct uio auio; |
192 | struct iovec aiov; | |
c4ec2128 KM |
193 | long cnt, error = 0; |
194 | #ifdef KTRACE | |
195 | struct iovec ktriov; | |
196 | #endif | |
ffe28cfe | 197 | |
7121fdf0 KB |
198 | if (((u_int)uap->fd) >= fdp->fd_nfiles || |
199 | (fp = fdp->fd_ofiles[uap->fd]) == NULL || | |
c4ec2128 | 200 | (fp->f_flag & FWRITE) == 0) |
d9c2f47f | 201 | return (EBADF); |
7121fdf0 KB |
202 | aiov.iov_base = (caddr_t)uap->buf; |
203 | aiov.iov_len = uap->nbyte; | |
b9429893 BJ |
204 | auio.uio_iov = &aiov; |
205 | auio.uio_iovcnt = 1; | |
7121fdf0 | 206 | auio.uio_resid = uap->nbyte; |
c4ec2128 KM |
207 | auio.uio_rw = UIO_WRITE; |
208 | auio.uio_segflg = UIO_USERSPACE; | |
221dba7d | 209 | auio.uio_procp = p; |
c4ec2128 KM |
210 | #ifdef KTRACE |
211 | /* | |
212 | * if tracing, save a copy of iovec | |
213 | */ | |
c9714ae3 | 214 | if (KTRPOINT(p, KTR_GENIO)) |
c4ec2128 KM |
215 | ktriov = aiov; |
216 | #endif | |
7121fdf0 | 217 | cnt = uap->nbyte; |
9754d709 MK |
218 | if (error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred)) { |
219 | if (auio.uio_resid != cnt && (error == ERESTART || | |
220 | error == EINTR || error == EWOULDBLOCK)) | |
221 | error = 0; | |
222 | if (error == EPIPE) | |
c9714ae3 | 223 | psignal(p, SIGPIPE); |
9754d709 | 224 | } |
c4ec2128 KM |
225 | cnt -= auio.uio_resid; |
226 | #ifdef KTRACE | |
c9714ae3 | 227 | if (KTRPOINT(p, KTR_GENIO) && error == 0) |
7121fdf0 | 228 | ktrgenio(p->p_tracep, uap->fd, UIO_WRITE, |
51322105 | 229 | &ktriov, cnt, error); |
c4ec2128 | 230 | #endif |
c9714ae3 | 231 | *retval = cnt; |
d9c2f47f | 232 | return (error); |
b9429893 BJ |
233 | } |
234 | ||
c9714ae3 KM |
235 | /* |
236 | * Gather write system call | |
237 | */ | |
1d369105 | 238 | struct writev_args { |
7121fdf0 | 239 | int fd; |
1d369105 | 240 | struct iovec *iovp; |
7121fdf0 | 241 | u_int iovcnt; |
1d369105 | 242 | }; |
c9714ae3 KM |
243 | writev(p, uap, retval) |
244 | struct proc *p; | |
1d369105 | 245 | register struct writev_args *uap; |
c9714ae3 KM |
246 | int *retval; |
247 | { | |
c4ec2128 | 248 | register struct file *fp; |
5e00df3b | 249 | register struct filedesc *fdp = p->p_fd; |
b9429893 | 250 | struct uio auio; |
c4ec2128 | 251 | register struct iovec *iov; |
7b7210d3 | 252 | struct iovec *needfree; |
c4ec2128 KM |
253 | struct iovec aiov[UIO_SMALLIOV]; |
254 | long i, cnt, error = 0; | |
7121fdf0 | 255 | u_int iovlen; |
c4ec2128 KM |
256 | #ifdef KTRACE |
257 | struct iovec *ktriov = NULL; | |
258 | #endif | |
b9429893 | 259 | |
7121fdf0 KB |
260 | if (((u_int)uap->fd) >= fdp->fd_nfiles || |
261 | (fp = fdp->fd_ofiles[uap->fd]) == NULL || | |
c4ec2128 | 262 | (fp->f_flag & FWRITE) == 0) |
d9c2f47f | 263 | return (EBADF); |
c9773de9 MK |
264 | /* note: can't use iovlen until iovcnt is validated */ |
265 | iovlen = uap->iovcnt * sizeof (struct iovec); | |
46814581 | 266 | if (uap->iovcnt > UIO_SMALLIOV) { |
c4ec2128 | 267 | if (uap->iovcnt > UIO_MAXIOV) |
d9c2f47f | 268 | return (EINVAL); |
c9773de9 | 269 | MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK); |
7b7210d3 CT |
270 | needfree = iov; |
271 | } else { | |
46814581 | 272 | iov = aiov; |
7b7210d3 CT |
273 | needfree = NULL; |
274 | } | |
46814581 | 275 | auio.uio_iov = iov; |
b9429893 | 276 | auio.uio_iovcnt = uap->iovcnt; |
c4ec2128 KM |
277 | auio.uio_rw = UIO_WRITE; |
278 | auio.uio_segflg = UIO_USERSPACE; | |
221dba7d | 279 | auio.uio_procp = p; |
c9773de9 | 280 | if (error = copyin((caddr_t)uap->iovp, (caddr_t)iov, iovlen)) |
46814581 | 281 | goto done; |
c4ec2128 KM |
282 | auio.uio_resid = 0; |
283 | for (i = 0; i < uap->iovcnt; i++) { | |
b9429893 | 284 | if (iov->iov_len < 0) { |
c4ec2128 KM |
285 | error = EINVAL; |
286 | goto done; | |
b9429893 | 287 | } |
c4ec2128 KM |
288 | auio.uio_resid += iov->iov_len; |
289 | if (auio.uio_resid < 0) { | |
290 | error = EINVAL; | |
291 | goto done; | |
b9429893 | 292 | } |
2a0114a8 | 293 | iov++; |
b9429893 | 294 | } |
46814581 | 295 | #ifdef KTRACE |
c4ec2128 KM |
296 | /* |
297 | * if tracing, save a copy of iovec | |
298 | */ | |
c9714ae3 | 299 | if (KTRPOINT(p, KTR_GENIO)) { |
46814581 | 300 | MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK); |
c4ec2128 | 301 | bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen); |
46814581 MK |
302 | } |
303 | #endif | |
c4ec2128 | 304 | cnt = auio.uio_resid; |
9754d709 MK |
305 | if (error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred)) { |
306 | if (auio.uio_resid != cnt && (error == ERESTART || | |
307 | error == EINTR || error == EWOULDBLOCK)) | |
308 | error = 0; | |
309 | if (error == EPIPE) | |
c9714ae3 | 310 | psignal(p, SIGPIPE); |
9754d709 | 311 | } |
c4ec2128 | 312 | cnt -= auio.uio_resid; |
46814581 MK |
313 | #ifdef KTRACE |
314 | if (ktriov != NULL) { | |
e64d087d | 315 | if (error == 0) |
7121fdf0 | 316 | ktrgenio(p->p_tracep, uap->fd, UIO_WRITE, |
51322105 | 317 | ktriov, cnt, error); |
46814581 MK |
318 | FREE(ktriov, M_TEMP); |
319 | } | |
320 | #endif | |
c9714ae3 | 321 | *retval = cnt; |
c4ec2128 | 322 | done: |
7b7210d3 CT |
323 | if (needfree) |
324 | FREE(needfree, M_IOV); | |
d9c2f47f | 325 | return (error); |
4147b3f6 | 326 | } |
ffe28cfe BJ |
327 | |
328 | /* | |
329 | * Ioctl system call | |
ffe28cfe | 330 | */ |
1d369105 | 331 | struct ioctl_args { |
7121fdf0 KB |
332 | int fd; |
333 | int com; | |
334 | caddr_t data; | |
1d369105 | 335 | }; |
c9714ae3 KM |
336 | /* ARGSUSED */ |
337 | ioctl(p, uap, retval) | |
338 | struct proc *p; | |
1d369105 | 339 | register struct ioctl_args *uap; |
c9714ae3 KM |
340 | int *retval; |
341 | { | |
342 | register struct file *fp; | |
cb84e0ab | 343 | register struct filedesc *fdp; |
9754d709 | 344 | register int com, error; |
b9429893 | 345 | register u_int size; |
cb84e0ab KB |
346 | caddr_t data, memp; |
347 | int tmp; | |
c0bb7b0e | 348 | #define STK_PARAMS 128 |
08eb908c | 349 | char stkbuf[STK_PARAMS]; |
ffe28cfe | 350 | |
cb84e0ab | 351 | fdp = p->p_fd; |
7121fdf0 KB |
352 | if ((u_int)uap->fd >= fdp->fd_nfiles || |
353 | (fp = fdp->fd_ofiles[uap->fd]) == NULL) | |
d9c2f47f | 354 | return (EBADF); |
cb84e0ab KB |
355 | |
356 | if ((fp->f_flag & (FREAD | FWRITE)) == 0) | |
d9c2f47f | 357 | return (EBADF); |
4b72e2f9 | 358 | |
cb84e0ab KB |
359 | switch (com = uap->com) { |
360 | case FIONCLEX: | |
7121fdf0 | 361 | fdp->fd_ofileflags[uap->fd] &= ~UF_EXCLOSE; |
d9c2f47f | 362 | return (0); |
cb84e0ab KB |
363 | case FIOCLEX: |
364 | fdp->fd_ofileflags[uap->fd] |= UF_EXCLOSE; | |
365 | return (0); | |
ffe28cfe | 366 | } |
4b72e2f9 SL |
367 | |
368 | /* | |
cb84e0ab KB |
369 | * Interpret high order word to find amount of data to be |
370 | * copied to/from the user's address space. | |
4b72e2f9 | 371 | */ |
c0bb7b0e | 372 | size = IOCPARM_LEN(com); |
9754d709 | 373 | if (size > IOCPARM_MAX) |
d9c2f47f | 374 | return (ENOTTY); |
cb84e0ab | 375 | memp = NULL; |
08eb908c | 376 | if (size > sizeof (stkbuf)) { |
f452da3a | 377 | memp = (caddr_t)malloc((u_long)size, M_IOCTLOPS, M_WAITOK); |
e0b18aec | 378 | data = memp; |
cb84e0ab KB |
379 | } else |
380 | data = stkbuf; | |
471f17ed SL |
381 | if (com&IOC_IN) { |
382 | if (size) { | |
7121fdf0 | 383 | error = copyin(uap->data, data, (u_int)size); |
9754d709 | 384 | if (error) { |
e0b18aec KM |
385 | if (memp) |
386 | free(memp, M_IOCTLOPS); | |
d9c2f47f | 387 | return (error); |
e0b18aec | 388 | } |
471f17ed | 389 | } else |
7121fdf0 | 390 | *(caddr_t *)data = uap->data; |
471f17ed SL |
391 | } else if ((com&IOC_OUT) && size) |
392 | /* | |
46814581 MK |
393 | * Zero the buffer so the user always |
394 | * gets back something deterministic. | |
471f17ed | 395 | */ |
c0bb7b0e | 396 | bzero(data, size); |
a76b60f6 | 397 | else if (com&IOC_VOID) |
7121fdf0 | 398 | *(caddr_t *)data = uap->data; |
4b72e2f9 | 399 | |
88a7a62a SL |
400 | switch (com) { |
401 | ||
402 | case FIONBIO: | |
221dba7d | 403 | if (tmp = *(int *)data) |
93080c46 | 404 | fp->f_flag |= FNONBLOCK; |
221dba7d | 405 | else |
93080c46 | 406 | fp->f_flag &= ~FNONBLOCK; |
221dba7d | 407 | error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p); |
c0bb7b0e | 408 | break; |
88a7a62a SL |
409 | |
410 | case FIOASYNC: | |
221dba7d KM |
411 | if (tmp = *(int *)data) |
412 | fp->f_flag |= FASYNC; | |
413 | else | |
414 | fp->f_flag &= ~FASYNC; | |
415 | error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, (caddr_t)&tmp, p); | |
c0bb7b0e | 416 | break; |
88a7a62a SL |
417 | |
418 | case FIOSETOWN: | |
221dba7d KM |
419 | tmp = *(int *)data; |
420 | if (fp->f_type == DTYPE_SOCKET) { | |
421 | ((struct socket *)fp->f_data)->so_pgid = tmp; | |
422 | error = 0; | |
423 | break; | |
424 | } | |
425 | if (tmp <= 0) { | |
426 | tmp = -tmp; | |
427 | } else { | |
428 | struct proc *p1 = pfind(tmp); | |
429 | if (p1 == 0) { | |
430 | error = ESRCH; | |
431 | break; | |
432 | } | |
433 | tmp = p1->p_pgrp->pg_id; | |
434 | } | |
435 | error = (*fp->f_ops->fo_ioctl) | |
436 | (fp, (int)TIOCSPGRP, (caddr_t)&tmp, p); | |
c0bb7b0e | 437 | break; |
4b72e2f9 | 438 | |
88a7a62a | 439 | case FIOGETOWN: |
221dba7d KM |
440 | if (fp->f_type == DTYPE_SOCKET) { |
441 | error = 0; | |
442 | *(int *)data = ((struct socket *)fp->f_data)->so_pgid; | |
443 | break; | |
444 | } | |
445 | error = (*fp->f_ops->fo_ioctl)(fp, (int)TIOCGPGRP, data, p); | |
446 | *(int *)data = -*(int *)data; | |
c0bb7b0e | 447 | break; |
221dba7d | 448 | |
c0bb7b0e | 449 | default: |
8429d022 | 450 | error = (*fp->f_ops->fo_ioctl)(fp, com, data, p); |
c0bb7b0e MK |
451 | /* |
452 | * Copy any data to user, size was | |
453 | * already set and checked above. | |
454 | */ | |
9754d709 | 455 | if (error == 0 && (com&IOC_OUT) && size) |
7121fdf0 | 456 | error = copyout(data, uap->data, (u_int)size); |
c0bb7b0e | 457 | break; |
88a7a62a | 458 | } |
e0b18aec KM |
459 | if (memp) |
460 | free(memp, M_IOCTLOPS); | |
d9c2f47f | 461 | return (error); |
ffe28cfe BJ |
462 | } |
463 | ||
44adcf01 | 464 | int selwait, nselcoll; |
d441e5bc | 465 | |
ffe28cfe | 466 | /* |
88a7a62a | 467 | * Select system call. |
ffe28cfe | 468 | */ |
1d369105 | 469 | struct select_args { |
a298f08c | 470 | u_int nd; |
1d369105 CT |
471 | fd_set *in, *ou, *ex; |
472 | struct timeval *tv; | |
473 | }; | |
c9714ae3 KM |
474 | select(p, uap, retval) |
475 | register struct proc *p; | |
1d369105 | 476 | register struct select_args *uap; |
c9714ae3 KM |
477 | int *retval; |
478 | { | |
b8e71e77 | 479 | fd_set ibits[3], obits[3]; |
88a7a62a | 480 | struct timeval atv; |
a298f08c KM |
481 | int s, ncoll, error = 0, timo; |
482 | u_int ni; | |
88a7a62a | 483 | |
01b0e233 MK |
484 | bzero((caddr_t)ibits, sizeof(ibits)); |
485 | bzero((caddr_t)obits, sizeof(obits)); | |
a298f08c KM |
486 | if (uap->nd > FD_SETSIZE) |
487 | return (EINVAL); | |
8429d022 MK |
488 | if (uap->nd > p->p_fd->fd_nfiles) |
489 | uap->nd = p->p_fd->fd_nfiles; /* forgiving; slightly wrong */ | |
a298f08c | 490 | ni = howmany(uap->nd, NFDBITS) * sizeof(fd_mask); |
88a7a62a SL |
491 | |
492 | #define getbits(name, x) \ | |
a298f08c KM |
493 | if (uap->name && \ |
494 | (error = copyin((caddr_t)uap->name, (caddr_t)&ibits[x], ni))) \ | |
495 | goto done; | |
88a7a62a SL |
496 | getbits(in, 0); |
497 | getbits(ou, 1); | |
498 | getbits(ex, 2); | |
499 | #undef getbits | |
500 | ||
501 | if (uap->tv) { | |
9754d709 | 502 | error = copyin((caddr_t)uap->tv, (caddr_t)&atv, |
88a7a62a | 503 | sizeof (atv)); |
9754d709 | 504 | if (error) |
88a7a62a SL |
505 | goto done; |
506 | if (itimerfix(&atv)) { | |
9754d709 | 507 | error = EINVAL; |
88a7a62a SL |
508 | goto done; |
509 | } | |
2b6d0fc1 CT |
510 | s = splclock(); |
511 | timevaladd(&atv, (struct timeval *)&time); | |
9754d709 | 512 | timo = hzto(&atv); |
4fc80098 KM |
513 | /* |
514 | * Avoid inadvertently sleeping forever. | |
515 | */ | |
516 | if (timo == 0) | |
517 | timo = 1; | |
856f902f | 518 | splx(s); |
9754d709 MK |
519 | } else |
520 | timo = 0; | |
88a7a62a SL |
521 | retry: |
522 | ncoll = nselcoll; | |
cf5ef508 | 523 | p->p_flag |= P_SELECT; |
8429d022 | 524 | error = selscan(p, ibits, obits, uap->nd, retval); |
c9714ae3 | 525 | if (error || *retval) |
88a7a62a | 526 | goto done; |
c4e1f1e5 | 527 | s = splhigh(); |
e394e134 SL |
528 | /* this should be timercmp(&time, &atv, >=) */ |
529 | if (uap->tv && (time.tv_sec > atv.tv_sec || | |
530 | time.tv_sec == atv.tv_sec && time.tv_usec >= atv.tv_usec)) { | |
88a7a62a SL |
531 | splx(s); |
532 | goto done; | |
533 | } | |
cf5ef508 | 534 | if ((p->p_flag & P_SELECT) == 0 || nselcoll != ncoll) { |
88a7a62a SL |
535 | splx(s); |
536 | goto retry; | |
537 | } | |
cf5ef508 | 538 | p->p_flag &= ~P_SELECT; |
9754d709 | 539 | error = tsleep((caddr_t)&selwait, PSOCK | PCATCH, "select", timo); |
88a7a62a | 540 | splx(s); |
9754d709 MK |
541 | if (error == 0) |
542 | goto retry; | |
88a7a62a | 543 | done: |
cf5ef508 | 544 | p->p_flag &= ~P_SELECT; |
9754d709 MK |
545 | /* select is not restarted after signals... */ |
546 | if (error == ERESTART) | |
547 | error = EINTR; | |
548 | if (error == EWOULDBLOCK) | |
549 | error = 0; | |
88a7a62a | 550 | #define putbits(name, x) \ |
a298f08c KM |
551 | if (uap->name && \ |
552 | (error2 = copyout((caddr_t)&obits[x], (caddr_t)uap->name, ni))) \ | |
553 | error = error2; | |
9754d709 | 554 | if (error == 0) { |
a298f08c KM |
555 | int error2; |
556 | ||
79f403fc MK |
557 | putbits(in, 0); |
558 | putbits(ou, 1); | |
559 | putbits(ex, 2); | |
88a7a62a | 560 | #undef putbits |
79f403fc | 561 | } |
d9c2f47f | 562 | return (error); |
88a7a62a SL |
563 | } |
564 | ||
8429d022 MK |
565 | selscan(p, ibits, obits, nfd, retval) |
566 | struct proc *p; | |
b8e71e77 | 567 | fd_set *ibits, *obits; |
c9714ae3 | 568 | int nfd, *retval; |
88a7a62a | 569 | { |
8429d022 | 570 | register struct filedesc *fdp = p->p_fd; |
7b7210d3 | 571 | register int msk, i, j, fd; |
b8e71e77 | 572 | register fd_mask bits; |
88a7a62a | 573 | struct file *fp; |
7b7210d3 CT |
574 | int n = 0; |
575 | static int flag[3] = { FREAD, FWRITE, 0 }; | |
88a7a62a | 576 | |
7b7210d3 | 577 | for (msk = 0; msk < 3; msk++) { |
b8e71e77 | 578 | for (i = 0; i < nfd; i += NFDBITS) { |
7b7210d3 CT |
579 | bits = ibits[msk].fds_bits[i/NFDBITS]; |
580 | while ((j = ffs(bits)) && (fd = i + --j) < nfd) { | |
d441e5bc | 581 | bits &= ~(1 << j); |
7b7210d3 CT |
582 | fp = fdp->fd_ofiles[fd]; |
583 | if (fp == NULL) | |
584 | return (EBADF); | |
585 | if ((*fp->f_ops->fo_select)(fp, flag[msk], p)) { | |
586 | FD_SET(fd, &obits[msk]); | |
d441e5bc MK |
587 | n++; |
588 | } | |
88a7a62a SL |
589 | } |
590 | } | |
591 | } | |
c9714ae3 | 592 | *retval = n; |
7b7210d3 | 593 | return (0); |
88a7a62a SL |
594 | } |
595 | ||
ffe28cfe | 596 | /*ARGSUSED*/ |
8429d022 | 597 | seltrue(dev, flag, p) |
88a7a62a SL |
598 | dev_t dev; |
599 | int flag; | |
8429d022 | 600 | struct proc *p; |
ffe28cfe BJ |
601 | { |
602 | ||
88a7a62a | 603 | return (1); |
ffe28cfe | 604 | } |
1edb1cf8 | 605 | |
4a4fcc2c KM |
606 | /* |
607 | * Record a select request. | |
608 | */ | |
609 | void | |
610 | selrecord(selector, sip) | |
611 | struct proc *selector; | |
612 | struct selinfo *sip; | |
613 | { | |
614 | struct proc *p; | |
615 | pid_t mypid; | |
616 | ||
617 | mypid = selector->p_pid; | |
618 | if (sip->si_pid == mypid) | |
619 | return; | |
620 | if (sip->si_pid && (p = pfind(sip->si_pid)) && | |
621 | p->p_wchan == (caddr_t)&selwait) | |
622 | sip->si_flags |= SI_COLL; | |
623 | else | |
624 | sip->si_pid = mypid; | |
625 | } | |
626 | ||
627 | /* | |
628 | * Do a wakeup when a selectable event occurs. | |
629 | */ | |
630 | void | |
631 | selwakeup(sip) | |
632 | register struct selinfo *sip; | |
1edb1cf8 | 633 | { |
4a4fcc2c KM |
634 | register struct proc *p; |
635 | int s; | |
1edb1cf8 | 636 | |
4a4fcc2c KM |
637 | if (sip->si_pid == 0) |
638 | return; | |
639 | if (sip->si_flags & SI_COLL) { | |
88a7a62a | 640 | nselcoll++; |
4a4fcc2c | 641 | sip->si_flags &= ~SI_COLL; |
88a7a62a SL |
642 | wakeup((caddr_t)&selwait); |
643 | } | |
9c2b41ec KM |
644 | p = pfind(sip->si_pid); |
645 | sip->si_pid = 0; | |
646 | if (p != NULL) { | |
4a4fcc2c | 647 | s = splhigh(); |
6bc3aba9 MK |
648 | if (p->p_wchan == (caddr_t)&selwait) { |
649 | if (p->p_stat == SSLEEP) | |
cb84e0ab | 650 | setrunnable(p); |
6bc3aba9 MK |
651 | else |
652 | unsleep(p); | |
cf5ef508 KB |
653 | } else if (p->p_flag & P_SELECT) |
654 | p->p_flag &= ~P_SELECT; | |
88a7a62a SL |
655 | splx(s); |
656 | } | |
1edb1cf8 | 657 | } |