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