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