Commit | Line | Data |
---|---|---|
15637ed4 RG |
1 | /* |
2 | * Copyright (c) 1982, 1986, 1989 Regents of the University of California. | |
3 | * All rights reserved. | |
4 | * | |
5 | * Redistribution and use in source and binary forms, with or without | |
6 | * modification, are permitted provided that the following conditions | |
7 | * are met: | |
8 | * 1. Redistributions of source code must retain the above copyright | |
9 | * notice, this list of conditions and the following disclaimer. | |
10 | * 2. Redistributions in binary form must reproduce the above copyright | |
11 | * notice, this list of conditions and the following disclaimer in the | |
12 | * documentation and/or other materials provided with the distribution. | |
13 | * 3. All advertising materials mentioning features or use of this software | |
14 | * must display the following acknowledgement: | |
15 | * This product includes software developed by the University of | |
16 | * California, Berkeley and its contributors. | |
17 | * 4. Neither the name of the University nor the names of its contributors | |
18 | * may be used to endorse or promote products derived from this software | |
19 | * without specific prior written permission. | |
20 | * | |
21 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
31 | * SUCH DAMAGE. | |
32 | * | |
600f7f07 | 33 | * from: @(#)sys_generic.c 7.30 (Berkeley) 5/30/91 |
fde1aeb2 | 34 | * $Id: sys_generic.c,v 1.5 1993/11/25 01:33:20 wollman Exp $ |
15637ed4 RG |
35 | */ |
36 | ||
37 | #include "param.h" | |
38 | #include "systm.h" | |
39 | #include "filedesc.h" | |
40 | #include "ioctl.h" | |
41 | #include "file.h" | |
42 | #include "socketvar.h" | |
43 | #include "proc.h" | |
44 | #include "uio.h" | |
45 | #include "kernel.h" | |
46 | #include "stat.h" | |
47 | #include "malloc.h" | |
fde1aeb2 | 48 | #include "signalvar.h" |
15637ed4 RG |
49 | #ifdef KTRACE |
50 | #include "ktrace.h" | |
51 | #endif | |
52 | ||
3c7eb27c DG |
53 | struct read_args { |
54 | int fdes; | |
55 | char *cbuf; | |
56 | unsigned count; | |
57 | }; | |
58 | ||
15637ed4 RG |
59 | /* |
60 | * Read system call. | |
61 | */ | |
62 | /* ARGSUSED */ | |
4c45483e | 63 | int |
15637ed4 RG |
64 | read(p, uap, retval) |
65 | struct proc *p; | |
3c7eb27c | 66 | register struct read_args *uap; |
15637ed4 RG |
67 | int *retval; |
68 | { | |
69 | register struct file *fp; | |
70 | register struct filedesc *fdp = p->p_fd; | |
71 | struct uio auio; | |
72 | struct iovec aiov; | |
73 | long cnt, error = 0; | |
74 | #ifdef KTRACE | |
75 | struct iovec ktriov; | |
76 | #endif | |
77 | ||
78 | if (((unsigned)uap->fdes) >= fdp->fd_nfiles || | |
79 | (fp = fdp->fd_ofiles[uap->fdes]) == NULL || | |
80 | (fp->f_flag & FREAD) == 0) | |
81 | return (EBADF); | |
82 | aiov.iov_base = (caddr_t)uap->cbuf; | |
83 | aiov.iov_len = uap->count; | |
84 | auio.uio_iov = &aiov; | |
85 | auio.uio_iovcnt = 1; | |
86 | auio.uio_resid = uap->count; | |
87 | auio.uio_rw = UIO_READ; | |
88 | auio.uio_segflg = UIO_USERSPACE; | |
89 | auio.uio_procp = p; | |
90 | #ifdef KTRACE | |
91 | /* | |
92 | * if tracing, save a copy of iovec | |
93 | */ | |
94 | if (KTRPOINT(p, KTR_GENIO)) | |
95 | ktriov = aiov; | |
96 | #endif | |
97 | cnt = uap->count; | |
98 | if (error = (*fp->f_ops->fo_read)(fp, &auio, fp->f_cred)) | |
99 | if (auio.uio_resid != cnt && (error == ERESTART || | |
100 | error == EINTR || error == EWOULDBLOCK)) | |
101 | error = 0; | |
102 | cnt -= auio.uio_resid; | |
103 | #ifdef KTRACE | |
104 | if (KTRPOINT(p, KTR_GENIO) && error == 0) | |
105 | ktrgenio(p->p_tracep, uap->fdes, UIO_READ, &ktriov, cnt, error); | |
106 | #endif | |
107 | *retval = cnt; | |
108 | return (error); | |
109 | } | |
110 | ||
111 | /* | |
112 | * Scatter read system call. | |
113 | */ | |
3c7eb27c DG |
114 | |
115 | struct readv_args { | |
116 | int fdes; | |
117 | struct iovec *iovp; | |
118 | unsigned iovcnt; | |
119 | }; | |
120 | ||
15637ed4 | 121 | /* ARGSUSED */ |
4c45483e | 122 | int |
15637ed4 RG |
123 | readv(p, uap, retval) |
124 | struct proc *p; | |
3c7eb27c | 125 | register struct readv_args *uap; |
15637ed4 RG |
126 | int *retval; |
127 | { | |
128 | register struct file *fp; | |
129 | register struct filedesc *fdp = p->p_fd; | |
130 | struct uio auio; | |
131 | register struct iovec *iov; | |
4c45483e | 132 | struct iovec *saveiov = 0; |
15637ed4 RG |
133 | struct iovec aiov[UIO_SMALLIOV]; |
134 | long i, cnt, error = 0; | |
135 | unsigned iovlen; | |
136 | #ifdef KTRACE | |
137 | struct iovec *ktriov = NULL; | |
138 | #endif | |
139 | ||
140 | if (((unsigned)uap->fdes) >= fdp->fd_nfiles || | |
141 | (fp = fdp->fd_ofiles[uap->fdes]) == NULL || | |
142 | (fp->f_flag & FREAD) == 0) | |
143 | return (EBADF); | |
144 | /* note: can't use iovlen until iovcnt is validated */ | |
145 | iovlen = uap->iovcnt * sizeof (struct iovec); | |
146 | if (uap->iovcnt > UIO_SMALLIOV) { | |
147 | if (uap->iovcnt > UIO_MAXIOV) | |
148 | return (EINVAL); | |
149 | MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK); | |
150 | saveiov = iov; | |
151 | } else | |
152 | iov = aiov; | |
153 | auio.uio_iov = iov; | |
154 | auio.uio_iovcnt = uap->iovcnt; | |
155 | auio.uio_rw = UIO_READ; | |
156 | auio.uio_segflg = UIO_USERSPACE; | |
157 | auio.uio_procp = p; | |
158 | if (error = copyin((caddr_t)uap->iovp, (caddr_t)iov, iovlen)) | |
159 | goto done; | |
160 | auio.uio_resid = 0; | |
161 | for (i = 0; i < uap->iovcnt; i++) { | |
162 | if (iov->iov_len < 0) { | |
163 | error = EINVAL; | |
164 | goto done; | |
165 | } | |
166 | auio.uio_resid += iov->iov_len; | |
167 | if (auio.uio_resid < 0) { | |
168 | error = EINVAL; | |
169 | goto done; | |
170 | } | |
171 | iov++; | |
172 | } | |
173 | #ifdef KTRACE | |
174 | /* | |
175 | * if tracing, save a copy of iovec | |
176 | */ | |
177 | if (KTRPOINT(p, KTR_GENIO)) { | |
178 | MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK); | |
179 | bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen); | |
180 | } | |
181 | #endif | |
182 | cnt = auio.uio_resid; | |
183 | if (error = (*fp->f_ops->fo_read)(fp, &auio, fp->f_cred)) | |
184 | if (auio.uio_resid != cnt && (error == ERESTART || | |
185 | error == EINTR || error == EWOULDBLOCK)) | |
186 | error = 0; | |
187 | cnt -= auio.uio_resid; | |
188 | #ifdef KTRACE | |
189 | if (ktriov != NULL) { | |
190 | if (error == 0) | |
191 | ktrgenio(p->p_tracep, uap->fdes, UIO_READ, ktriov, | |
192 | cnt, error); | |
193 | FREE(ktriov, M_TEMP); | |
194 | } | |
195 | #endif | |
196 | *retval = cnt; | |
197 | done: | |
198 | if (uap->iovcnt > UIO_SMALLIOV) | |
199 | FREE(saveiov, M_IOV); | |
200 | return (error); | |
201 | } | |
202 | ||
203 | /* | |
204 | * Write system call | |
205 | */ | |
3c7eb27c DG |
206 | |
207 | struct write_args { | |
208 | int fdes; | |
209 | char *cbuf; | |
210 | unsigned count; | |
211 | }; | |
212 | ||
4c45483e | 213 | int |
15637ed4 RG |
214 | write(p, uap, retval) |
215 | struct proc *p; | |
3c7eb27c | 216 | register struct write_args *uap; |
15637ed4 RG |
217 | int *retval; |
218 | { | |
219 | register struct file *fp; | |
220 | register struct filedesc *fdp = p->p_fd; | |
221 | struct uio auio; | |
222 | struct iovec aiov; | |
223 | long cnt, error = 0; | |
224 | #ifdef KTRACE | |
225 | struct iovec ktriov; | |
226 | #endif | |
227 | ||
228 | if (((unsigned)uap->fdes) >= fdp->fd_nfiles || | |
229 | (fp = fdp->fd_ofiles[uap->fdes]) == NULL || | |
230 | (fp->f_flag & FWRITE) == 0) | |
231 | return (EBADF); | |
232 | aiov.iov_base = (caddr_t)uap->cbuf; | |
233 | aiov.iov_len = uap->count; | |
234 | auio.uio_iov = &aiov; | |
235 | auio.uio_iovcnt = 1; | |
236 | auio.uio_resid = uap->count; | |
237 | auio.uio_rw = UIO_WRITE; | |
238 | auio.uio_segflg = UIO_USERSPACE; | |
239 | auio.uio_procp = p; | |
240 | #ifdef KTRACE | |
241 | /* | |
242 | * if tracing, save a copy of iovec | |
243 | */ | |
244 | if (KTRPOINT(p, KTR_GENIO)) | |
245 | ktriov = aiov; | |
246 | #endif | |
247 | cnt = uap->count; | |
248 | if (error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred)) { | |
249 | if (auio.uio_resid != cnt && (error == ERESTART || | |
250 | error == EINTR || error == EWOULDBLOCK)) | |
251 | error = 0; | |
252 | if (error == EPIPE) | |
253 | psignal(p, SIGPIPE); | |
254 | } | |
255 | cnt -= auio.uio_resid; | |
256 | #ifdef KTRACE | |
257 | if (KTRPOINT(p, KTR_GENIO) && error == 0) | |
258 | ktrgenio(p->p_tracep, uap->fdes, UIO_WRITE, | |
259 | &ktriov, cnt, error); | |
260 | #endif | |
261 | *retval = cnt; | |
262 | return (error); | |
263 | } | |
264 | ||
265 | /* | |
266 | * Gather write system call | |
267 | */ | |
3c7eb27c DG |
268 | |
269 | struct writev_args { | |
270 | int fdes; | |
271 | struct iovec *iovp; | |
272 | unsigned iovcnt; | |
273 | }; | |
274 | ||
4c45483e | 275 | int |
15637ed4 RG |
276 | writev(p, uap, retval) |
277 | struct proc *p; | |
3c7eb27c | 278 | register struct writev_args *uap; |
15637ed4 RG |
279 | int *retval; |
280 | { | |
281 | register struct file *fp; | |
282 | register struct filedesc *fdp = p->p_fd; | |
283 | struct uio auio; | |
284 | register struct iovec *iov; | |
4c45483e | 285 | struct iovec *saveiov = 0; |
15637ed4 RG |
286 | struct iovec aiov[UIO_SMALLIOV]; |
287 | long i, cnt, error = 0; | |
288 | unsigned iovlen; | |
289 | #ifdef KTRACE | |
290 | struct iovec *ktriov = NULL; | |
291 | #endif | |
292 | ||
293 | if (((unsigned)uap->fdes) >= fdp->fd_nfiles || | |
294 | (fp = fdp->fd_ofiles[uap->fdes]) == NULL || | |
295 | (fp->f_flag & FWRITE) == 0) | |
296 | return (EBADF); | |
297 | /* note: can't use iovlen until iovcnt is validated */ | |
298 | iovlen = uap->iovcnt * sizeof (struct iovec); | |
299 | if (uap->iovcnt > UIO_SMALLIOV) { | |
300 | if (uap->iovcnt > UIO_MAXIOV) | |
301 | return (EINVAL); | |
302 | MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK); | |
303 | saveiov = iov; | |
304 | } else | |
305 | iov = aiov; | |
306 | auio.uio_iov = iov; | |
307 | auio.uio_iovcnt = uap->iovcnt; | |
308 | auio.uio_rw = UIO_WRITE; | |
309 | auio.uio_segflg = UIO_USERSPACE; | |
310 | auio.uio_procp = p; | |
311 | if (error = copyin((caddr_t)uap->iovp, (caddr_t)iov, iovlen)) | |
312 | goto done; | |
313 | auio.uio_resid = 0; | |
314 | for (i = 0; i < uap->iovcnt; i++) { | |
315 | if (iov->iov_len < 0) { | |
316 | error = EINVAL; | |
317 | goto done; | |
318 | } | |
319 | auio.uio_resid += iov->iov_len; | |
320 | if (auio.uio_resid < 0) { | |
321 | error = EINVAL; | |
322 | goto done; | |
323 | } | |
324 | iov++; | |
325 | } | |
326 | #ifdef KTRACE | |
327 | /* | |
328 | * if tracing, save a copy of iovec | |
329 | */ | |
330 | if (KTRPOINT(p, KTR_GENIO)) { | |
331 | MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK); | |
332 | bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen); | |
333 | } | |
334 | #endif | |
335 | cnt = auio.uio_resid; | |
336 | if (error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred)) { | |
337 | if (auio.uio_resid != cnt && (error == ERESTART || | |
338 | error == EINTR || error == EWOULDBLOCK)) | |
339 | error = 0; | |
340 | if (error == EPIPE) | |
341 | psignal(p, SIGPIPE); | |
342 | } | |
343 | cnt -= auio.uio_resid; | |
344 | #ifdef KTRACE | |
345 | if (ktriov != NULL) { | |
346 | if (error == 0) | |
347 | ktrgenio(p->p_tracep, uap->fdes, UIO_WRITE, | |
348 | ktriov, cnt, error); | |
349 | FREE(ktriov, M_TEMP); | |
350 | } | |
351 | #endif | |
352 | *retval = cnt; | |
353 | done: | |
354 | if (uap->iovcnt > UIO_SMALLIOV) | |
355 | FREE(saveiov, M_IOV); | |
356 | return (error); | |
357 | } | |
358 | ||
359 | /* | |
360 | * Ioctl system call | |
361 | */ | |
3c7eb27c DG |
362 | |
363 | struct ioctl_args { | |
364 | int fdes; | |
365 | int cmd; | |
366 | caddr_t cmarg; | |
367 | }; | |
368 | ||
15637ed4 | 369 | /* ARGSUSED */ |
4c45483e | 370 | int |
15637ed4 RG |
371 | ioctl(p, uap, retval) |
372 | struct proc *p; | |
3c7eb27c | 373 | register struct ioctl_args *uap; |
15637ed4 RG |
374 | int *retval; |
375 | { | |
376 | register struct file *fp; | |
377 | register struct filedesc *fdp = p->p_fd; | |
378 | register int com, error; | |
379 | register u_int size; | |
380 | caddr_t memp = 0; | |
381 | #define STK_PARAMS 128 | |
382 | char stkbuf[STK_PARAMS]; | |
383 | caddr_t data = stkbuf; | |
384 | int tmp; | |
385 | ||
386 | if ((unsigned)uap->fdes >= fdp->fd_nfiles || | |
387 | (fp = fdp->fd_ofiles[uap->fdes]) == NULL) | |
388 | return (EBADF); | |
389 | if ((fp->f_flag & (FREAD|FWRITE)) == 0) | |
390 | return (EBADF); | |
391 | com = uap->cmd; | |
392 | ||
393 | if (com == FIOCLEX) { | |
394 | fdp->fd_ofileflags[uap->fdes] |= UF_EXCLOSE; | |
395 | return (0); | |
396 | } | |
397 | if (com == FIONCLEX) { | |
398 | fdp->fd_ofileflags[uap->fdes] &= ~UF_EXCLOSE; | |
399 | return (0); | |
400 | } | |
401 | ||
402 | /* | |
403 | * Interpret high order word to find | |
404 | * amount of data to be copied to/from the | |
405 | * user's address space. | |
406 | */ | |
407 | size = IOCPARM_LEN(com); | |
408 | if (size > IOCPARM_MAX) | |
409 | return (ENOTTY); | |
410 | if (size > sizeof (stkbuf)) { | |
411 | memp = (caddr_t)malloc((u_long)size, M_IOCTLOPS, M_WAITOK); | |
412 | data = memp; | |
413 | } | |
414 | if (com&IOC_IN) { | |
415 | if (size) { | |
416 | error = copyin(uap->cmarg, data, (u_int)size); | |
417 | if (error) { | |
418 | if (memp) | |
419 | free(memp, M_IOCTLOPS); | |
420 | return (error); | |
421 | } | |
422 | } else | |
423 | *(caddr_t *)data = uap->cmarg; | |
424 | } else if ((com&IOC_OUT) && size) | |
425 | /* | |
426 | * Zero the buffer so the user always | |
427 | * gets back something deterministic. | |
428 | */ | |
429 | bzero(data, size); | |
430 | else if (com&IOC_VOID) | |
431 | *(caddr_t *)data = uap->cmarg; | |
432 | ||
433 | switch (com) { | |
434 | ||
435 | case FIONBIO: | |
436 | if (tmp = *(int *)data) | |
437 | fp->f_flag |= FNONBLOCK; | |
438 | else | |
439 | fp->f_flag &= ~FNONBLOCK; | |
440 | error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p); | |
441 | break; | |
442 | ||
443 | case FIOASYNC: | |
444 | if (tmp = *(int *)data) | |
445 | fp->f_flag |= FASYNC; | |
446 | else | |
447 | fp->f_flag &= ~FASYNC; | |
448 | error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, (caddr_t)&tmp, p); | |
449 | break; | |
450 | ||
451 | case FIOSETOWN: | |
452 | tmp = *(int *)data; | |
453 | if (fp->f_type == DTYPE_SOCKET) { | |
454 | ((struct socket *)fp->f_data)->so_pgid = tmp; | |
455 | error = 0; | |
456 | break; | |
457 | } | |
458 | if (tmp <= 0) { | |
459 | tmp = -tmp; | |
460 | } else { | |
461 | struct proc *p1 = pfind(tmp); | |
462 | if (p1 == 0) { | |
463 | error = ESRCH; | |
464 | break; | |
465 | } | |
466 | tmp = p1->p_pgrp->pg_id; | |
467 | } | |
468 | error = (*fp->f_ops->fo_ioctl) | |
469 | (fp, (int)TIOCSPGRP, (caddr_t)&tmp, p); | |
470 | break; | |
471 | ||
472 | case FIOGETOWN: | |
473 | if (fp->f_type == DTYPE_SOCKET) { | |
474 | error = 0; | |
475 | *(int *)data = ((struct socket *)fp->f_data)->so_pgid; | |
476 | break; | |
477 | } | |
478 | error = (*fp->f_ops->fo_ioctl)(fp, (int)TIOCGPGRP, data, p); | |
479 | *(int *)data = -*(int *)data; | |
480 | break; | |
481 | ||
482 | default: | |
483 | error = (*fp->f_ops->fo_ioctl)(fp, com, data, p); | |
484 | /* | |
485 | * Copy any data to user, size was | |
486 | * already set and checked above. | |
487 | */ | |
488 | if (error == 0 && (com&IOC_OUT) && size) | |
489 | error = copyout(data, uap->cmarg, (u_int)size); | |
490 | break; | |
491 | } | |
492 | if (memp) | |
493 | free(memp, M_IOCTLOPS); | |
494 | return (error); | |
495 | } | |
496 | ||
497 | int selwait, nselcoll; | |
498 | ||
499 | /* | |
500 | * Select system call. | |
501 | */ | |
3c7eb27c DG |
502 | |
503 | struct select_args { | |
9e177a2e | 504 | u_int nd; |
15637ed4 RG |
505 | fd_set *in, *ou, *ex; |
506 | struct timeval *tv; | |
3c7eb27c DG |
507 | }; |
508 | ||
4c45483e | 509 | int |
3c7eb27c DG |
510 | select(p, uap, retval) |
511 | register struct proc *p; | |
512 | register struct select_args *uap; | |
15637ed4 RG |
513 | int *retval; |
514 | { | |
515 | fd_set ibits[3], obits[3]; | |
516 | struct timeval atv; | |
9e177a2e DG |
517 | int s, ncoll, error = 0, timo; |
518 | u_int ni; | |
15637ed4 RG |
519 | |
520 | bzero((caddr_t)ibits, sizeof(ibits)); | |
521 | bzero((caddr_t)obits, sizeof(obits)); | |
522 | if (uap->nd > p->p_fd->fd_nfiles) | |
523 | uap->nd = p->p_fd->fd_nfiles; /* forgiving; slightly wrong */ | |
524 | ni = howmany(uap->nd, NFDBITS); | |
525 | ||
526 | #define getbits(name, x) \ | |
527 | if (uap->name) { \ | |
528 | error = copyin((caddr_t)uap->name, (caddr_t)&ibits[x], \ | |
529 | (unsigned)(ni * sizeof(fd_mask))); \ | |
530 | if (error) \ | |
531 | goto done; \ | |
532 | } | |
533 | getbits(in, 0); | |
534 | getbits(ou, 1); | |
535 | getbits(ex, 2); | |
536 | #undef getbits | |
537 | ||
538 | if (uap->tv) { | |
539 | error = copyin((caddr_t)uap->tv, (caddr_t)&atv, | |
540 | sizeof (atv)); | |
541 | if (error) | |
542 | goto done; | |
543 | if (itimerfix(&atv)) { | |
544 | error = EINVAL; | |
545 | goto done; | |
546 | } | |
547 | s = splhigh(); timevaladd(&atv, &time); splx(s); | |
548 | timo = hzto(&atv); | |
549 | } else | |
550 | timo = 0; | |
551 | retry: | |
552 | ncoll = nselcoll; | |
553 | p->p_flag |= SSEL; | |
554 | error = selscan(p, ibits, obits, uap->nd, retval); | |
555 | if (error || *retval) | |
556 | goto done; | |
557 | s = splhigh(); | |
558 | /* this should be timercmp(&time, &atv, >=) */ | |
559 | if (uap->tv && (time.tv_sec > atv.tv_sec || | |
560 | time.tv_sec == atv.tv_sec && time.tv_usec >= atv.tv_usec)) { | |
561 | splx(s); | |
562 | goto done; | |
563 | } | |
564 | if ((p->p_flag & SSEL) == 0 || nselcoll != ncoll) { | |
565 | splx(s); | |
566 | goto retry; | |
567 | } | |
568 | p->p_flag &= ~SSEL; | |
569 | error = tsleep((caddr_t)&selwait, PSOCK | PCATCH, "select", timo); | |
570 | splx(s); | |
571 | if (error == 0) | |
572 | goto retry; | |
573 | done: | |
574 | p->p_flag &= ~SSEL; | |
575 | /* select is not restarted after signals... */ | |
576 | if (error == ERESTART) | |
577 | error = EINTR; | |
578 | if (error == EWOULDBLOCK) | |
579 | error = 0; | |
580 | #define putbits(name, x) \ | |
581 | if (uap->name) { \ | |
582 | int error2 = copyout((caddr_t)&obits[x], (caddr_t)uap->name, \ | |
583 | (unsigned)(ni * sizeof(fd_mask))); \ | |
584 | if (error2) \ | |
585 | error = error2; \ | |
586 | } | |
587 | if (error == 0) { | |
588 | putbits(in, 0); | |
589 | putbits(ou, 1); | |
590 | putbits(ex, 2); | |
591 | #undef putbits | |
592 | } | |
593 | return (error); | |
594 | } | |
595 | ||
596 | int | |
597 | selscan(struct proc *p, fd_set *ibits, fd_set *obits, int nfd, int *retval) | |
598 | { | |
599 | register struct filedesc *fdp = p->p_fd; | |
600 | register int which, i, j; | |
601 | register fd_mask bits; | |
602 | int flag; | |
603 | struct file *fp; | |
604 | int error = 0, n = 0; | |
605 | ||
606 | for (which = 0; which < 3; which++) { | |
607 | switch (which) { | |
608 | ||
609 | case 0: | |
610 | flag = FREAD; break; | |
611 | ||
612 | case 1: | |
613 | flag = FWRITE; break; | |
614 | ||
4c45483e | 615 | default: /* pacify GCC */ |
15637ed4 RG |
616 | case 2: |
617 | flag = 0; break; | |
618 | } | |
619 | for (i = 0; i < nfd; i += NFDBITS) { | |
620 | bits = ibits[which].fds_bits[i/NFDBITS]; | |
621 | while ((j = ffs(bits)) && i + --j < nfd) { | |
622 | bits &= ~(1 << j); | |
623 | fp = fdp->fd_ofiles[i + j]; | |
624 | if (fp == NULL) { | |
625 | error = EBADF; | |
626 | break; | |
627 | } | |
628 | if ((*fp->f_ops->fo_select)(fp, flag, p)) { | |
629 | FD_SET(i + j, &obits[which]); | |
630 | n++; | |
631 | } | |
632 | } | |
633 | } | |
634 | } | |
635 | *retval = n; | |
636 | return (error); | |
637 | } | |
638 | ||
639 | /*ARGSUSED*/ | |
640 | int | |
4c45483e | 641 | seltrue(int /*dev_t*/ dev, int which, struct proc *p) |
15637ed4 RG |
642 | { |
643 | ||
644 | return (1); | |
645 | } | |
646 | ||
647 | void | |
4c45483e | 648 | selwakeup(int /*pid_t*/ pid, int coll) |
15637ed4 RG |
649 | { |
650 | register struct proc *p; | |
651 | ||
652 | if (coll) { | |
653 | nselcoll++; | |
654 | wakeup((caddr_t)&selwait); | |
655 | } | |
656 | if (pid && (p = pfind(pid))) { | |
657 | int s = splhigh(); | |
658 | if (p->p_wchan == (caddr_t)&selwait) { | |
659 | if (p->p_stat == SSLEEP) | |
660 | setrun(p); | |
661 | else | |
662 | unsleep(p); | |
663 | } else if (p->p_flag & SSEL) | |
664 | p->p_flag &= ~SSEL; | |
665 | splx(s); | |
666 | } | |
667 | } |