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. | |
da7c5cc6 | 4 | * |
dbf0c423 | 5 | * %sccs.include.redist.c% |
c4ec2128 | 6 | * |
cf5ef508 | 7 | * @(#)sys_generic.c 8.4 (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 | 28 | struct read_args { |
7121fdf0 KB |
29 | int fd; |
30 | char *buf; | |
31 | u_int nbyte; | |
1d369105 | 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 | |
7121fdf0 KB |
48 | if (((u_int)uap->fd) >= fdp->fd_nfiles || |
49 | (fp = fdp->fd_ofiles[uap->fd]) == NULL || | |
c4ec2128 | 50 | (fp->f_flag & FREAD) == 0) |
d9c2f47f | 51 | return (EBADF); |
7121fdf0 KB |
52 | aiov.iov_base = (caddr_t)uap->buf; |
53 | aiov.iov_len = uap->nbyte; | |
32a43ee2 BJ |
54 | auio.uio_iov = &aiov; |
55 | auio.uio_iovcnt = 1; | |
7121fdf0 | 56 | auio.uio_resid = uap->nbyte; |
c4ec2128 KM |
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 | |
7121fdf0 | 67 | cnt = uap->nbyte; |
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) |
7121fdf0 | 75 | ktrgenio(p->p_tracep, uap->fd, 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; | |
7121fdf0 | 87 | u_int iovcnt; |
1d369105 | 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; | |
7121fdf0 | 101 | u_int iovlen; |
c4ec2128 KM |
102 | #ifdef KTRACE |
103 | struct iovec *ktriov = NULL; | |
104 | #endif | |
b9429893 | 105 | |
7121fdf0 | 106 | if (((u_int)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 | 174 | struct write_args { |
7121fdf0 KB |
175 | int fd; |
176 | char *buf; | |
177 | u_int nbyte; | |
1d369105 | 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 | |
7121fdf0 KB |
193 | if (((u_int)uap->fd) >= fdp->fd_nfiles || |
194 | (fp = fdp->fd_ofiles[uap->fd]) == NULL || | |
c4ec2128 | 195 | (fp->f_flag & FWRITE) == 0) |
d9c2f47f | 196 | return (EBADF); |
7121fdf0 KB |
197 | aiov.iov_base = (caddr_t)uap->buf; |
198 | aiov.iov_len = uap->nbyte; | |
b9429893 BJ |
199 | auio.uio_iov = &aiov; |
200 | auio.uio_iovcnt = 1; | |
7121fdf0 | 201 | auio.uio_resid = uap->nbyte; |
c4ec2128 KM |
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 | |
7121fdf0 | 212 | cnt = uap->nbyte; |
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 | 222 | if (KTRPOINT(p, KTR_GENIO) && error == 0) |
7121fdf0 | 223 | ktrgenio(p->p_tracep, uap->fd, 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 | 233 | struct writev_args { |
7121fdf0 | 234 | int fd; |
1d369105 | 235 | struct iovec *iovp; |
7121fdf0 | 236 | u_int iovcnt; |
1d369105 | 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; | |
7121fdf0 | 250 | u_int iovlen; |
c4ec2128 KM |
251 | #ifdef KTRACE |
252 | struct iovec *ktriov = NULL; | |
253 | #endif | |
b9429893 | 254 | |
7121fdf0 KB |
255 | if (((u_int)uap->fd) >= fdp->fd_nfiles || |
256 | (fp = fdp->fd_ofiles[uap->fd]) == 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) |
7121fdf0 | 311 | ktrgenio(p->p_tracep, uap->fd, 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 | 326 | struct ioctl_args { |
7121fdf0 KB |
327 | int fd; |
328 | int com; | |
329 | caddr_t data; | |
1d369105 | 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; | |
cb84e0ab | 338 | register struct filedesc *fdp; |
9754d709 | 339 | register int com, error; |
b9429893 | 340 | register u_int size; |
cb84e0ab KB |
341 | caddr_t data, memp; |
342 | int tmp; | |
c0bb7b0e | 343 | #define STK_PARAMS 128 |
08eb908c | 344 | char stkbuf[STK_PARAMS]; |
ffe28cfe | 345 | |
cb84e0ab | 346 | fdp = p->p_fd; |
7121fdf0 KB |
347 | if ((u_int)uap->fd >= fdp->fd_nfiles || |
348 | (fp = fdp->fd_ofiles[uap->fd]) == NULL) | |
d9c2f47f | 349 | return (EBADF); |
cb84e0ab KB |
350 | |
351 | if ((fp->f_flag & (FREAD | FWRITE)) == 0) | |
d9c2f47f | 352 | return (EBADF); |
4b72e2f9 | 353 | |
cb84e0ab KB |
354 | switch (com = uap->com) { |
355 | case FIONCLEX: | |
7121fdf0 | 356 | fdp->fd_ofileflags[uap->fd] &= ~UF_EXCLOSE; |
d9c2f47f | 357 | return (0); |
cb84e0ab KB |
358 | case FIOCLEX: |
359 | fdp->fd_ofileflags[uap->fd] |= UF_EXCLOSE; | |
360 | return (0); | |
ffe28cfe | 361 | } |
4b72e2f9 SL |
362 | |
363 | /* | |
cb84e0ab KB |
364 | * Interpret high order word to find amount of data to be |
365 | * copied to/from the user's address space. | |
4b72e2f9 | 366 | */ |
c0bb7b0e | 367 | size = IOCPARM_LEN(com); |
9754d709 | 368 | if (size > IOCPARM_MAX) |
d9c2f47f | 369 | return (ENOTTY); |
cb84e0ab | 370 | memp = NULL; |
08eb908c | 371 | if (size > sizeof (stkbuf)) { |
f452da3a | 372 | memp = (caddr_t)malloc((u_long)size, M_IOCTLOPS, M_WAITOK); |
e0b18aec | 373 | data = memp; |
cb84e0ab KB |
374 | } else |
375 | data = stkbuf; | |
471f17ed SL |
376 | if (com&IOC_IN) { |
377 | if (size) { | |
7121fdf0 | 378 | error = copyin(uap->data, data, (u_int)size); |
9754d709 | 379 | if (error) { |
e0b18aec KM |
380 | if (memp) |
381 | free(memp, M_IOCTLOPS); | |
d9c2f47f | 382 | return (error); |
e0b18aec | 383 | } |
471f17ed | 384 | } else |
7121fdf0 | 385 | *(caddr_t *)data = uap->data; |
471f17ed SL |
386 | } else if ((com&IOC_OUT) && size) |
387 | /* | |
46814581 MK |
388 | * Zero the buffer so the user always |
389 | * gets back something deterministic. | |
471f17ed | 390 | */ |
c0bb7b0e | 391 | bzero(data, size); |
a76b60f6 | 392 | else if (com&IOC_VOID) |
7121fdf0 | 393 | *(caddr_t *)data = uap->data; |
4b72e2f9 | 394 | |
88a7a62a SL |
395 | switch (com) { |
396 | ||
397 | case FIONBIO: | |
221dba7d | 398 | if (tmp = *(int *)data) |
93080c46 | 399 | fp->f_flag |= FNONBLOCK; |
221dba7d | 400 | else |
93080c46 | 401 | fp->f_flag &= ~FNONBLOCK; |
221dba7d | 402 | error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p); |
c0bb7b0e | 403 | break; |
88a7a62a SL |
404 | |
405 | case FIOASYNC: | |
221dba7d KM |
406 | if (tmp = *(int *)data) |
407 | fp->f_flag |= FASYNC; | |
408 | else | |
409 | fp->f_flag &= ~FASYNC; | |
410 | error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, (caddr_t)&tmp, p); | |
c0bb7b0e | 411 | break; |
88a7a62a SL |
412 | |
413 | case FIOSETOWN: | |
221dba7d KM |
414 | tmp = *(int *)data; |
415 | if (fp->f_type == DTYPE_SOCKET) { | |
416 | ((struct socket *)fp->f_data)->so_pgid = tmp; | |
417 | error = 0; | |
418 | break; | |
419 | } | |
420 | if (tmp <= 0) { | |
421 | tmp = -tmp; | |
422 | } else { | |
423 | struct proc *p1 = pfind(tmp); | |
424 | if (p1 == 0) { | |
425 | error = ESRCH; | |
426 | break; | |
427 | } | |
428 | tmp = p1->p_pgrp->pg_id; | |
429 | } | |
430 | error = (*fp->f_ops->fo_ioctl) | |
431 | (fp, (int)TIOCSPGRP, (caddr_t)&tmp, p); | |
c0bb7b0e | 432 | break; |
4b72e2f9 | 433 | |
88a7a62a | 434 | case FIOGETOWN: |
221dba7d KM |
435 | if (fp->f_type == DTYPE_SOCKET) { |
436 | error = 0; | |
437 | *(int *)data = ((struct socket *)fp->f_data)->so_pgid; | |
438 | break; | |
439 | } | |
440 | error = (*fp->f_ops->fo_ioctl)(fp, (int)TIOCGPGRP, data, p); | |
441 | *(int *)data = -*(int *)data; | |
c0bb7b0e | 442 | break; |
221dba7d | 443 | |
c0bb7b0e | 444 | default: |
8429d022 | 445 | error = (*fp->f_ops->fo_ioctl)(fp, com, data, p); |
c0bb7b0e MK |
446 | /* |
447 | * Copy any data to user, size was | |
448 | * already set and checked above. | |
449 | */ | |
9754d709 | 450 | if (error == 0 && (com&IOC_OUT) && size) |
7121fdf0 | 451 | error = copyout(data, uap->data, (u_int)size); |
c0bb7b0e | 452 | break; |
88a7a62a | 453 | } |
e0b18aec KM |
454 | if (memp) |
455 | free(memp, M_IOCTLOPS); | |
d9c2f47f | 456 | return (error); |
ffe28cfe BJ |
457 | } |
458 | ||
44adcf01 | 459 | int selwait, nselcoll; |
d441e5bc | 460 | |
ffe28cfe | 461 | /* |
88a7a62a | 462 | * Select system call. |
ffe28cfe | 463 | */ |
1d369105 | 464 | struct select_args { |
a298f08c | 465 | u_int nd; |
1d369105 CT |
466 | fd_set *in, *ou, *ex; |
467 | struct timeval *tv; | |
468 | }; | |
c9714ae3 KM |
469 | select(p, uap, retval) |
470 | register struct proc *p; | |
1d369105 | 471 | register struct select_args *uap; |
c9714ae3 KM |
472 | int *retval; |
473 | { | |
b8e71e77 | 474 | fd_set ibits[3], obits[3]; |
88a7a62a | 475 | struct timeval atv; |
a298f08c KM |
476 | int s, ncoll, error = 0, timo; |
477 | u_int ni; | |
88a7a62a | 478 | |
01b0e233 MK |
479 | bzero((caddr_t)ibits, sizeof(ibits)); |
480 | bzero((caddr_t)obits, sizeof(obits)); | |
a298f08c KM |
481 | if (uap->nd > FD_SETSIZE) |
482 | return (EINVAL); | |
8429d022 MK |
483 | if (uap->nd > p->p_fd->fd_nfiles) |
484 | uap->nd = p->p_fd->fd_nfiles; /* forgiving; slightly wrong */ | |
a298f08c | 485 | ni = howmany(uap->nd, NFDBITS) * sizeof(fd_mask); |
88a7a62a SL |
486 | |
487 | #define getbits(name, x) \ | |
a298f08c KM |
488 | if (uap->name && \ |
489 | (error = copyin((caddr_t)uap->name, (caddr_t)&ibits[x], ni))) \ | |
490 | goto done; | |
88a7a62a SL |
491 | getbits(in, 0); |
492 | getbits(ou, 1); | |
493 | getbits(ex, 2); | |
494 | #undef getbits | |
495 | ||
496 | if (uap->tv) { | |
9754d709 | 497 | error = copyin((caddr_t)uap->tv, (caddr_t)&atv, |
88a7a62a | 498 | sizeof (atv)); |
9754d709 | 499 | if (error) |
88a7a62a SL |
500 | goto done; |
501 | if (itimerfix(&atv)) { | |
9754d709 | 502 | error = EINVAL; |
88a7a62a SL |
503 | goto done; |
504 | } | |
2b6d0fc1 CT |
505 | s = splclock(); |
506 | timevaladd(&atv, (struct timeval *)&time); | |
9754d709 | 507 | timo = hzto(&atv); |
4fc80098 KM |
508 | /* |
509 | * Avoid inadvertently sleeping forever. | |
510 | */ | |
511 | if (timo == 0) | |
512 | timo = 1; | |
856f902f | 513 | splx(s); |
9754d709 MK |
514 | } else |
515 | timo = 0; | |
88a7a62a SL |
516 | retry: |
517 | ncoll = nselcoll; | |
cf5ef508 | 518 | p->p_flag |= P_SELECT; |
8429d022 | 519 | error = selscan(p, ibits, obits, uap->nd, retval); |
c9714ae3 | 520 | if (error || *retval) |
88a7a62a | 521 | goto done; |
c4e1f1e5 | 522 | s = splhigh(); |
e394e134 SL |
523 | /* this should be timercmp(&time, &atv, >=) */ |
524 | if (uap->tv && (time.tv_sec > atv.tv_sec || | |
525 | time.tv_sec == atv.tv_sec && time.tv_usec >= atv.tv_usec)) { | |
88a7a62a SL |
526 | splx(s); |
527 | goto done; | |
528 | } | |
cf5ef508 | 529 | if ((p->p_flag & P_SELECT) == 0 || nselcoll != ncoll) { |
88a7a62a SL |
530 | splx(s); |
531 | goto retry; | |
532 | } | |
cf5ef508 | 533 | p->p_flag &= ~P_SELECT; |
9754d709 | 534 | error = tsleep((caddr_t)&selwait, PSOCK | PCATCH, "select", timo); |
88a7a62a | 535 | splx(s); |
9754d709 MK |
536 | if (error == 0) |
537 | goto retry; | |
88a7a62a | 538 | done: |
cf5ef508 | 539 | p->p_flag &= ~P_SELECT; |
9754d709 MK |
540 | /* select is not restarted after signals... */ |
541 | if (error == ERESTART) | |
542 | error = EINTR; | |
543 | if (error == EWOULDBLOCK) | |
544 | error = 0; | |
88a7a62a | 545 | #define putbits(name, x) \ |
a298f08c KM |
546 | if (uap->name && \ |
547 | (error2 = copyout((caddr_t)&obits[x], (caddr_t)uap->name, ni))) \ | |
548 | error = error2; | |
9754d709 | 549 | if (error == 0) { |
a298f08c KM |
550 | int error2; |
551 | ||
79f403fc MK |
552 | putbits(in, 0); |
553 | putbits(ou, 1); | |
554 | putbits(ex, 2); | |
88a7a62a | 555 | #undef putbits |
79f403fc | 556 | } |
d9c2f47f | 557 | return (error); |
88a7a62a SL |
558 | } |
559 | ||
8429d022 MK |
560 | selscan(p, ibits, obits, nfd, retval) |
561 | struct proc *p; | |
b8e71e77 | 562 | fd_set *ibits, *obits; |
c9714ae3 | 563 | int nfd, *retval; |
88a7a62a | 564 | { |
8429d022 | 565 | register struct filedesc *fdp = p->p_fd; |
7b7210d3 | 566 | register int msk, i, j, fd; |
b8e71e77 | 567 | register fd_mask bits; |
88a7a62a | 568 | struct file *fp; |
7b7210d3 CT |
569 | int n = 0; |
570 | static int flag[3] = { FREAD, FWRITE, 0 }; | |
88a7a62a | 571 | |
7b7210d3 | 572 | for (msk = 0; msk < 3; msk++) { |
b8e71e77 | 573 | for (i = 0; i < nfd; i += NFDBITS) { |
7b7210d3 CT |
574 | bits = ibits[msk].fds_bits[i/NFDBITS]; |
575 | while ((j = ffs(bits)) && (fd = i + --j) < nfd) { | |
d441e5bc | 576 | bits &= ~(1 << j); |
7b7210d3 CT |
577 | fp = fdp->fd_ofiles[fd]; |
578 | if (fp == NULL) | |
579 | return (EBADF); | |
580 | if ((*fp->f_ops->fo_select)(fp, flag[msk], p)) { | |
581 | FD_SET(fd, &obits[msk]); | |
d441e5bc MK |
582 | n++; |
583 | } | |
88a7a62a SL |
584 | } |
585 | } | |
586 | } | |
c9714ae3 | 587 | *retval = n; |
7b7210d3 | 588 | return (0); |
88a7a62a SL |
589 | } |
590 | ||
ffe28cfe | 591 | /*ARGSUSED*/ |
8429d022 | 592 | seltrue(dev, flag, p) |
88a7a62a SL |
593 | dev_t dev; |
594 | int flag; | |
8429d022 | 595 | struct proc *p; |
ffe28cfe BJ |
596 | { |
597 | ||
88a7a62a | 598 | return (1); |
ffe28cfe | 599 | } |
1edb1cf8 | 600 | |
4a4fcc2c KM |
601 | /* |
602 | * Record a select request. | |
603 | */ | |
604 | void | |
605 | selrecord(selector, sip) | |
606 | struct proc *selector; | |
607 | struct selinfo *sip; | |
608 | { | |
609 | struct proc *p; | |
610 | pid_t mypid; | |
611 | ||
612 | mypid = selector->p_pid; | |
613 | if (sip->si_pid == mypid) | |
614 | return; | |
615 | if (sip->si_pid && (p = pfind(sip->si_pid)) && | |
616 | p->p_wchan == (caddr_t)&selwait) | |
617 | sip->si_flags |= SI_COLL; | |
618 | else | |
619 | sip->si_pid = mypid; | |
620 | } | |
621 | ||
622 | /* | |
623 | * Do a wakeup when a selectable event occurs. | |
624 | */ | |
625 | void | |
626 | selwakeup(sip) | |
627 | register struct selinfo *sip; | |
1edb1cf8 | 628 | { |
4a4fcc2c KM |
629 | register struct proc *p; |
630 | int s; | |
1edb1cf8 | 631 | |
4a4fcc2c KM |
632 | if (sip->si_pid == 0) |
633 | return; | |
634 | if (sip->si_flags & SI_COLL) { | |
88a7a62a | 635 | nselcoll++; |
4a4fcc2c | 636 | sip->si_flags &= ~SI_COLL; |
88a7a62a SL |
637 | wakeup((caddr_t)&selwait); |
638 | } | |
9c2b41ec KM |
639 | p = pfind(sip->si_pid); |
640 | sip->si_pid = 0; | |
641 | if (p != NULL) { | |
4a4fcc2c | 642 | s = splhigh(); |
6bc3aba9 MK |
643 | if (p->p_wchan == (caddr_t)&selwait) { |
644 | if (p->p_stat == SSLEEP) | |
cb84e0ab | 645 | setrunnable(p); |
6bc3aba9 MK |
646 | else |
647 | unsleep(p); | |
cf5ef508 KB |
648 | } else if (p->p_flag & P_SELECT) |
649 | p->p_flag &= ~P_SELECT; | |
88a7a62a SL |
650 | splx(s); |
651 | } | |
1edb1cf8 | 652 | } |