Commit | Line | Data |
---|---|---|
da7c5cc6 | 1 | /* |
46814581 | 2 | * Copyright (c) 1982, 1986, 1988 Regents of the University of California. |
da7c5cc6 KM |
3 | * All rights reserved. The Berkeley software License Agreement |
4 | * specifies the terms and conditions for redistribution. | |
5 | * | |
46814581 | 6 | * @(#)sys_generic.c 7.9 (Berkeley) %G% |
da7c5cc6 | 7 | */ |
ffe28cfe | 8 | |
94368568 JB |
9 | #include "param.h" |
10 | #include "systm.h" | |
11 | #include "dir.h" | |
12 | #include "user.h" | |
13 | #include "ioctl.h" | |
14 | #include "file.h" | |
15 | #include "proc.h" | |
16 | #include "uio.h" | |
17 | #include "kernel.h" | |
18 | #include "stat.h" | |
e0b18aec | 19 | #include "malloc.h" |
46814581 MK |
20 | #ifdef KTRACE |
21 | #include "ktrace.h" | |
22 | #endif | |
ffe28cfe BJ |
23 | |
24 | /* | |
25 | * Read system call. | |
26 | */ | |
27 | read() | |
28 | { | |
ffe28cfe BJ |
29 | register struct a { |
30 | int fdes; | |
31 | char *cbuf; | |
32 | unsigned count; | |
b9429893 | 33 | } *uap = (struct a *)u.u_ap; |
32a43ee2 BJ |
34 | struct uio auio; |
35 | struct iovec aiov; | |
ffe28cfe | 36 | |
32a43ee2 BJ |
37 | aiov.iov_base = (caddr_t)uap->cbuf; |
38 | aiov.iov_len = uap->count; | |
39 | auio.uio_iov = &aiov; | |
40 | auio.uio_iovcnt = 1; | |
b9429893 BJ |
41 | rwuio(&auio, UIO_READ); |
42 | } | |
43 | ||
44 | readv() | |
45 | { | |
46 | register struct a { | |
47 | int fdes; | |
48 | struct iovec *iovp; | |
31286ce2 | 49 | unsigned iovcnt; |
b9429893 BJ |
50 | } *uap = (struct a *)u.u_ap; |
51 | struct uio auio; | |
46814581 | 52 | struct iovec aiov[UIO_SMALLIOV], *iov; |
b9429893 | 53 | |
46814581 MK |
54 | if (uap->iovcnt > UIO_SMALLIOV) { |
55 | if (uap->iovcnt > UIO_MAXIOV) { | |
56 | u.u_error = EINVAL; | |
57 | return; | |
58 | } | |
59 | MALLOC(iov, struct iovec *, | |
60 | sizeof(struct iovec) * uap->iovcnt, M_IOV, M_WAITOK); | |
61 | if (iov == NULL) { | |
62 | u.u_error = ENOMEM; | |
63 | return; | |
64 | } | |
65 | } else | |
66 | iov = aiov; | |
67 | auio.uio_iov = iov; | |
b9429893 | 68 | auio.uio_iovcnt = uap->iovcnt; |
46814581 | 69 | u.u_error = copyin((caddr_t)uap->iovp, (caddr_t)auio.uio_iov, |
31286ce2 | 70 | uap->iovcnt * sizeof (struct iovec)); |
127f7d76 | 71 | if (u.u_error) |
46814581 | 72 | goto done; |
b9429893 | 73 | rwuio(&auio, UIO_READ); |
46814581 MK |
74 | done: |
75 | if (iov != aiov) | |
76 | FREE(iov, M_IOV); | |
ffe28cfe BJ |
77 | } |
78 | ||
79 | /* | |
80 | * Write system call | |
81 | */ | |
82 | write() | |
83 | { | |
ffe28cfe BJ |
84 | register struct a { |
85 | int fdes; | |
86 | char *cbuf; | |
31286ce2 | 87 | unsigned count; |
b9429893 BJ |
88 | } *uap = (struct a *)u.u_ap; |
89 | struct uio auio; | |
90 | struct iovec aiov; | |
ffe28cfe | 91 | |
b9429893 BJ |
92 | auio.uio_iov = &aiov; |
93 | auio.uio_iovcnt = 1; | |
94 | aiov.iov_base = uap->cbuf; | |
95 | aiov.iov_len = uap->count; | |
96 | rwuio(&auio, UIO_WRITE); | |
97 | } | |
98 | ||
99 | writev() | |
100 | { | |
101 | register struct a { | |
102 | int fdes; | |
103 | struct iovec *iovp; | |
31286ce2 | 104 | unsigned iovcnt; |
b9429893 BJ |
105 | } *uap = (struct a *)u.u_ap; |
106 | struct uio auio; | |
46814581 | 107 | struct iovec aiov[UIO_SMALLIOV], *iov; |
b9429893 | 108 | |
46814581 MK |
109 | if (uap->iovcnt > UIO_SMALLIOV) { |
110 | if (uap->iovcnt > UIO_MAXIOV) { | |
111 | u.u_error = EINVAL; | |
112 | return; | |
113 | } | |
114 | MALLOC(iov, struct iovec *, | |
115 | sizeof(struct iovec) * uap->iovcnt, M_IOV, M_WAITOK); | |
116 | if (iov == NULL) { | |
117 | u.u_error = ENOMEM; | |
118 | return; | |
119 | } | |
120 | } else | |
121 | iov = aiov; | |
122 | auio.uio_iov = iov; | |
b9429893 | 123 | auio.uio_iovcnt = uap->iovcnt; |
46814581 | 124 | u.u_error = copyin((caddr_t)uap->iovp, (caddr_t)auio.uio_iov, |
31286ce2 | 125 | uap->iovcnt * sizeof (struct iovec)); |
127f7d76 | 126 | if (u.u_error) |
46814581 | 127 | goto done; |
b9429893 | 128 | rwuio(&auio, UIO_WRITE); |
46814581 MK |
129 | done: |
130 | if (iov != aiov) | |
131 | FREE(iov, M_IOV); | |
b9429893 BJ |
132 | } |
133 | ||
134 | rwuio(uio, rw) | |
135 | register struct uio *uio; | |
136 | enum uio_rw rw; | |
137 | { | |
138 | struct a { | |
139 | int fdes; | |
140 | }; | |
141 | register struct file *fp; | |
142 | register struct iovec *iov; | |
b9429893 | 143 | int i, count; |
46814581 MK |
144 | #ifdef KTRACE |
145 | struct iovec *ktriov = NULL; | |
146 | #endif | |
147 | ||
b9429893 BJ |
148 | |
149 | GETF(fp, ((struct a *)u.u_ap)->fdes); | |
150 | if ((fp->f_flag&(rw==UIO_READ ? FREAD : FWRITE)) == 0) { | |
ffe28cfe BJ |
151 | u.u_error = EBADF; |
152 | return; | |
153 | } | |
b9429893 | 154 | uio->uio_resid = 0; |
c41770c0 | 155 | uio->uio_segflg = UIO_USERSPACE; |
b9429893 BJ |
156 | iov = uio->uio_iov; |
157 | for (i = 0; i < uio->uio_iovcnt; i++) { | |
158 | if (iov->iov_len < 0) { | |
159 | u.u_error = EINVAL; | |
160 | return; | |
161 | } | |
162 | uio->uio_resid += iov->iov_len; | |
163 | if (uio->uio_resid < 0) { | |
164 | u.u_error = EINVAL; | |
165 | return; | |
166 | } | |
2a0114a8 | 167 | iov++; |
b9429893 BJ |
168 | } |
169 | count = uio->uio_resid; | |
46814581 MK |
170 | #ifdef KTRACE |
171 | /* if tracing, save a copy of iovec */ | |
172 | if (KTRPOINT(u.u_procp, KTR_GENIO)) { | |
173 | int iovlen = uio->uio_iovcnt * sizeof (struct iovec); | |
174 | ||
175 | MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK); | |
176 | if (ktriov != NULL) | |
177 | bcopy((caddr_t)uio->uio_iov, (caddr_t)ktriov, iovlen); | |
178 | } | |
179 | #endif | |
fe7f81f4 KM |
180 | if (setjmp(&u.u_qsave)) { |
181 | if (uio->uio_resid == count) { | |
9f49ba41 | 182 | if ((u.u_sigintr & sigmask(u.u_procp->p_cursig)) != 0) |
fe7f81f4 KM |
183 | u.u_error = EINTR; |
184 | else | |
185 | u.u_eosys = RESTARTSYS; | |
186 | } | |
b9429893 | 187 | } else |
88a7a62a SL |
188 | u.u_error = (*fp->f_ops->fo_rw)(fp, rw, uio); |
189 | u.u_r.r_val1 = count - uio->uio_resid; | |
46814581 MK |
190 | #ifdef KTRACE |
191 | if (ktriov != NULL) { | |
192 | ktrgenio(u.u_procp->p_tracep, ((struct a *)u.u_ap)->fdes, | |
193 | rw, ktriov, u.u_r.r_val1); | |
194 | FREE(ktriov, M_TEMP); | |
195 | } | |
196 | #endif | |
4147b3f6 | 197 | } |
ffe28cfe BJ |
198 | |
199 | /* | |
200 | * Ioctl system call | |
ffe28cfe BJ |
201 | */ |
202 | ioctl() | |
203 | { | |
204 | register struct file *fp; | |
4b72e2f9 | 205 | struct a { |
ffe28cfe BJ |
206 | int fdes; |
207 | int cmd; | |
208 | caddr_t cmarg; | |
209 | } *uap; | |
b9429893 BJ |
210 | register int com; |
211 | register u_int size; | |
e0b18aec | 212 | caddr_t memp = 0; |
c0bb7b0e | 213 | #define STK_PARAMS 128 |
08eb908c MK |
214 | char stkbuf[STK_PARAMS]; |
215 | caddr_t data = stkbuf; | |
ffe28cfe BJ |
216 | |
217 | uap = (struct a *)u.u_ap; | |
21e0a474 | 218 | GETF(fp, uap->fdes); |
ffe28cfe BJ |
219 | if ((fp->f_flag & (FREAD|FWRITE)) == 0) { |
220 | u.u_error = EBADF; | |
221 | return; | |
222 | } | |
4b72e2f9 SL |
223 | com = uap->cmd; |
224 | ||
4b72e2f9 | 225 | if (com == FIOCLEX) { |
3650c37d | 226 | u.u_pofile[uap->fdes] |= UF_EXCLOSE; |
ffe28cfe BJ |
227 | return; |
228 | } | |
4b72e2f9 | 229 | if (com == FIONCLEX) { |
3650c37d | 230 | u.u_pofile[uap->fdes] &= ~UF_EXCLOSE; |
ffe28cfe BJ |
231 | return; |
232 | } | |
4b72e2f9 SL |
233 | |
234 | /* | |
235 | * Interpret high order word to find | |
236 | * amount of data to be copied to/from the | |
237 | * user's address space. | |
4b72e2f9 | 238 | */ |
c0bb7b0e MK |
239 | size = IOCPARM_LEN(com); |
240 | if (size > IOCPARM_MAX) { | |
46814581 | 241 | u.u_error = ENOTTY; |
ffe28cfe BJ |
242 | return; |
243 | } | |
08eb908c | 244 | if (size > sizeof (stkbuf)) { |
46814581 | 245 | memp = (caddr_t)malloc((u_long)IOCPARM_LEN(com), M_IOCTLOPS, |
5adcb337 | 246 | M_WAITOK); |
e0b18aec | 247 | data = memp; |
c0bb7b0e | 248 | } |
471f17ed SL |
249 | if (com&IOC_IN) { |
250 | if (size) { | |
46814581 | 251 | u.u_error = copyin(uap->cmarg, data, (u_int)size); |
e0b18aec KM |
252 | if (u.u_error) { |
253 | if (memp) | |
254 | free(memp, M_IOCTLOPS); | |
471f17ed | 255 | return; |
e0b18aec | 256 | } |
471f17ed SL |
257 | } else |
258 | *(caddr_t *)data = uap->cmarg; | |
259 | } else if ((com&IOC_OUT) && size) | |
260 | /* | |
46814581 MK |
261 | * Zero the buffer so the user always |
262 | * gets back something deterministic. | |
471f17ed | 263 | */ |
c0bb7b0e | 264 | bzero(data, size); |
a76b60f6 SL |
265 | else if (com&IOC_VOID) |
266 | *(caddr_t *)data = uap->cmarg; | |
4b72e2f9 | 267 | |
88a7a62a SL |
268 | switch (com) { |
269 | ||
270 | case FIONBIO: | |
271 | u.u_error = fset(fp, FNDELAY, *(int *)data); | |
c0bb7b0e | 272 | break; |
88a7a62a SL |
273 | |
274 | case FIOASYNC: | |
275 | u.u_error = fset(fp, FASYNC, *(int *)data); | |
c0bb7b0e | 276 | break; |
88a7a62a SL |
277 | |
278 | case FIOSETOWN: | |
279 | u.u_error = fsetown(fp, *(int *)data); | |
c0bb7b0e | 280 | break; |
4b72e2f9 | 281 | |
88a7a62a SL |
282 | case FIOGETOWN: |
283 | u.u_error = fgetown(fp, (int *)data); | |
c0bb7b0e MK |
284 | break; |
285 | default: | |
286 | if (setjmp(&u.u_qsave)) | |
287 | u.u_error = EINTR; | |
288 | else | |
289 | u.u_error = (*fp->f_ops->fo_ioctl)(fp, com, data); | |
290 | /* | |
291 | * Copy any data to user, size was | |
292 | * already set and checked above. | |
293 | */ | |
294 | if (u.u_error == 0 && (com&IOC_OUT) && size) | |
295 | u.u_error = copyout(data, uap->cmarg, (u_int)size); | |
296 | break; | |
88a7a62a | 297 | } |
e0b18aec KM |
298 | if (memp) |
299 | free(memp, M_IOCTLOPS); | |
ffe28cfe BJ |
300 | } |
301 | ||
88a7a62a SL |
302 | int unselect(); |
303 | int nselcoll; | |
d441e5bc | 304 | |
ffe28cfe | 305 | /* |
88a7a62a | 306 | * Select system call. |
ffe28cfe | 307 | */ |
88a7a62a SL |
308 | select() |
309 | { | |
310 | register struct uap { | |
311 | int nd; | |
b8e71e77 | 312 | fd_set *in, *ou, *ex; |
88a7a62a SL |
313 | struct timeval *tv; |
314 | } *uap = (struct uap *)u.u_ap; | |
b8e71e77 | 315 | fd_set ibits[3], obits[3]; |
88a7a62a | 316 | struct timeval atv; |
d441e5bc | 317 | int s, ncoll, ni; |
88a7a62a SL |
318 | label_t lqsave; |
319 | ||
01b0e233 MK |
320 | bzero((caddr_t)ibits, sizeof(ibits)); |
321 | bzero((caddr_t)obits, sizeof(obits)); | |
88a7a62a SL |
322 | if (uap->nd > NOFILE) |
323 | uap->nd = NOFILE; /* forgiving, if slightly wrong */ | |
b8e71e77 | 324 | ni = howmany(uap->nd, NFDBITS); |
88a7a62a SL |
325 | |
326 | #define getbits(name, x) \ | |
327 | if (uap->name) { \ | |
b8e71e77 | 328 | u.u_error = copyin((caddr_t)uap->name, (caddr_t)&ibits[x], \ |
01b0e233 | 329 | (unsigned)(ni * sizeof(fd_mask))); \ |
88a7a62a SL |
330 | if (u.u_error) \ |
331 | goto done; \ | |
d441e5bc | 332 | } |
88a7a62a SL |
333 | getbits(in, 0); |
334 | getbits(ou, 1); | |
335 | getbits(ex, 2); | |
336 | #undef getbits | |
337 | ||
338 | if (uap->tv) { | |
339 | u.u_error = copyin((caddr_t)uap->tv, (caddr_t)&atv, | |
340 | sizeof (atv)); | |
341 | if (u.u_error) | |
342 | goto done; | |
343 | if (itimerfix(&atv)) { | |
344 | u.u_error = EINVAL; | |
345 | goto done; | |
346 | } | |
c4e1f1e5 | 347 | s = splhigh(); timevaladd(&atv, &time); splx(s); |
88a7a62a SL |
348 | } |
349 | retry: | |
350 | ncoll = nselcoll; | |
351 | u.u_procp->p_flag |= SSEL; | |
d441e5bc | 352 | u.u_r.r_val1 = selscan(ibits, obits, uap->nd); |
88a7a62a SL |
353 | if (u.u_error || u.u_r.r_val1) |
354 | goto done; | |
c4e1f1e5 | 355 | s = splhigh(); |
e394e134 SL |
356 | /* this should be timercmp(&time, &atv, >=) */ |
357 | if (uap->tv && (time.tv_sec > atv.tv_sec || | |
358 | time.tv_sec == atv.tv_sec && time.tv_usec >= atv.tv_usec)) { | |
88a7a62a SL |
359 | splx(s); |
360 | goto done; | |
361 | } | |
362 | if ((u.u_procp->p_flag & SSEL) == 0 || nselcoll != ncoll) { | |
88a7a62a SL |
363 | splx(s); |
364 | goto retry; | |
365 | } | |
366 | u.u_procp->p_flag &= ~SSEL; | |
367 | if (uap->tv) { | |
368 | lqsave = u.u_qsave; | |
369 | if (setjmp(&u.u_qsave)) { | |
370 | untimeout(unselect, (caddr_t)u.u_procp); | |
371 | u.u_error = EINTR; | |
372 | splx(s); | |
373 | goto done; | |
374 | } | |
375 | timeout(unselect, (caddr_t)u.u_procp, hzto(&atv)); | |
376 | } | |
377 | sleep((caddr_t)&selwait, PZERO+1); | |
378 | if (uap->tv) { | |
379 | u.u_qsave = lqsave; | |
380 | untimeout(unselect, (caddr_t)u.u_procp); | |
381 | } | |
382 | splx(s); | |
383 | goto retry; | |
384 | done: | |
b894ed59 | 385 | u.u_procp->p_flag &= ~SSEL; |
88a7a62a SL |
386 | #define putbits(name, x) \ |
387 | if (uap->name) { \ | |
b8e71e77 | 388 | int error = copyout((caddr_t)&obits[x], (caddr_t)uap->name, \ |
01b0e233 | 389 | (unsigned)(ni * sizeof(fd_mask))); \ |
88a7a62a SL |
390 | if (error) \ |
391 | u.u_error = error; \ | |
392 | } | |
87a3ba07 | 393 | if (u.u_error == 0) { |
79f403fc MK |
394 | putbits(in, 0); |
395 | putbits(ou, 1); | |
396 | putbits(ex, 2); | |
88a7a62a | 397 | #undef putbits |
79f403fc | 398 | } |
88a7a62a SL |
399 | } |
400 | ||
401 | unselect(p) | |
402 | register struct proc *p; | |
403 | { | |
c4e1f1e5 | 404 | register int s = splhigh(); |
88a7a62a SL |
405 | |
406 | switch (p->p_stat) { | |
407 | ||
408 | case SSLEEP: | |
409 | setrun(p); | |
410 | break; | |
411 | ||
412 | case SSTOP: | |
413 | unsleep(p); | |
414 | break; | |
415 | } | |
416 | splx(s); | |
417 | } | |
418 | ||
d441e5bc | 419 | selscan(ibits, obits, nfd) |
b8e71e77 | 420 | fd_set *ibits, *obits; |
88a7a62a | 421 | { |
b8e71e77 MK |
422 | register int which, i, j; |
423 | register fd_mask bits; | |
88a7a62a SL |
424 | int flag; |
425 | struct file *fp; | |
426 | int n = 0; | |
427 | ||
428 | for (which = 0; which < 3; which++) { | |
88a7a62a SL |
429 | switch (which) { |
430 | ||
431 | case 0: | |
432 | flag = FREAD; break; | |
433 | ||
434 | case 1: | |
435 | flag = FWRITE; break; | |
436 | ||
437 | case 2: | |
438 | flag = 0; break; | |
439 | } | |
b8e71e77 MK |
440 | for (i = 0; i < nfd; i += NFDBITS) { |
441 | bits = ibits[which].fds_bits[i/NFDBITS]; | |
d441e5bc MK |
442 | while ((j = ffs(bits)) && i + --j < nfd) { |
443 | bits &= ~(1 << j); | |
444 | fp = u.u_ofile[i + j]; | |
445 | if (fp == NULL) { | |
446 | u.u_error = EBADF; | |
447 | break; | |
448 | } | |
449 | if ((*fp->f_ops->fo_select)(fp, flag)) { | |
b8e71e77 | 450 | FD_SET(i + j, &obits[which]); |
d441e5bc MK |
451 | n++; |
452 | } | |
88a7a62a SL |
453 | } |
454 | } | |
455 | } | |
456 | return (n); | |
457 | } | |
458 | ||
ffe28cfe | 459 | /*ARGSUSED*/ |
88a7a62a SL |
460 | seltrue(dev, flag) |
461 | dev_t dev; | |
462 | int flag; | |
ffe28cfe BJ |
463 | { |
464 | ||
88a7a62a | 465 | return (1); |
ffe28cfe | 466 | } |
1edb1cf8 | 467 | |
88a7a62a SL |
468 | selwakeup(p, coll) |
469 | register struct proc *p; | |
470 | int coll; | |
1edb1cf8 BJ |
471 | { |
472 | ||
88a7a62a SL |
473 | if (coll) { |
474 | nselcoll++; | |
475 | wakeup((caddr_t)&selwait); | |
476 | } | |
477 | if (p) { | |
c4e1f1e5 | 478 | int s = splhigh(); |
6bc3aba9 MK |
479 | if (p->p_wchan == (caddr_t)&selwait) { |
480 | if (p->p_stat == SSLEEP) | |
481 | setrun(p); | |
482 | else | |
483 | unsleep(p); | |
484 | } else if (p->p_flag & SSEL) | |
88a7a62a SL |
485 | p->p_flag &= ~SSEL; |
486 | splx(s); | |
487 | } | |
1edb1cf8 | 488 | } |