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