select routines don't return errors
[unix-history] / usr / src / sys / kern / sys_generic.c
CommitLineData
da7c5cc6 1/*
c4ec2128
KM
2 * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
3 * All rights reserved.
da7c5cc6 4 *
c4ec2128
KM
5 * Redistribution and use in source and binary forms are permitted
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16 *
c9714ae3 17 * @(#)sys_generic.c 7.17 (Berkeley) %G%
da7c5cc6 18 */
ffe28cfe 19
94368568
JB
20#include "param.h"
21#include "systm.h"
c4ec2128 22#include "syscontext.h"
94368568
JB
23#include "ioctl.h"
24#include "file.h"
25#include "proc.h"
26#include "uio.h"
27#include "kernel.h"
28#include "stat.h"
e0b18aec 29#include "malloc.h"
46814581
MK
30#ifdef KTRACE
31#include "ktrace.h"
32#endif
ffe28cfe
BJ
33
34/*
35 * Read system call.
36 */
c9714ae3
KM
37read(p, uap, retval)
38 struct proc *p;
39 register struct args {
ffe28cfe
BJ
40 int fdes;
41 char *cbuf;
42 unsigned count;
c9714ae3
KM
43 } *uap;
44 int *retval;
45{
c4ec2128 46 register struct file *fp;
32a43ee2
BJ
47 struct uio auio;
48 struct iovec aiov;
c4ec2128
KM
49 long cnt, error = 0;
50#ifdef KTRACE
51 struct iovec ktriov;
52#endif
ffe28cfe 53
c4ec2128
KM
54 if (((unsigned)uap->fdes) >= NOFILE ||
55 (fp = u.u_ofile[uap->fdes]) == NULL ||
56 (fp->f_flag & FREAD) == 0)
57 RETURN (EBADF);
32a43ee2
BJ
58 aiov.iov_base = (caddr_t)uap->cbuf;
59 aiov.iov_len = uap->count;
60 auio.uio_iov = &aiov;
61 auio.uio_iovcnt = 1;
c4ec2128
KM
62 auio.uio_resid = uap->count;
63 auio.uio_rw = UIO_READ;
64 auio.uio_segflg = UIO_USERSPACE;
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
72 cnt = uap->count;
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
KM
79 if (KTRPOINT(p, KTR_GENIO) && error == 0)
80 ktrgenio(p->p_tracep, uap->fdes, UIO_READ, &ktriov, cnt);
c4ec2128 81#endif
c9714ae3 82 *retval = cnt;
c4ec2128 83 RETURN (error);
b9429893
BJ
84}
85
c9714ae3
KM
86/*
87 * Scatter read system call.
88 */
89readv(p, uap, retval)
90 struct proc *p;
91 register struct args {
b9429893
BJ
92 int fdes;
93 struct iovec *iovp;
31286ce2 94 unsigned iovcnt;
c9714ae3
KM
95 } *uap;
96 int *retval;
97{
c4ec2128 98 register struct file *fp;
b9429893 99 struct uio auio;
c4ec2128
KM
100 register struct iovec *iov;
101 struct iovec aiov[UIO_SMALLIOV];
102 long i, cnt, error = 0;
103#ifdef KTRACE
104 struct iovec *ktriov = NULL;
105#endif
b9429893 106
c4ec2128
KM
107 if (((unsigned)uap->fdes) >= NOFILE ||
108 (fp = u.u_ofile[uap->fdes]) == NULL ||
109 (fp->f_flag & FREAD) == 0)
110 RETURN (EBADF);
46814581 111 if (uap->iovcnt > UIO_SMALLIOV) {
c4ec2128
KM
112 if (uap->iovcnt > UIO_MAXIOV)
113 RETURN (EINVAL);
46814581
MK
114 MALLOC(iov, struct iovec *,
115 sizeof(struct iovec) * uap->iovcnt, M_IOV, M_WAITOK);
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;
122 if (error = copyin((caddr_t)uap->iovp, (caddr_t)iov,
123 uap->iovcnt * sizeof (struct iovec)))
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)) {
92e1705e 143 unsigned iovlen = auio.uio_iovcnt * sizeof (struct iovec);
c4ec2128
KM
144
145 MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
146 bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
147 }
148#endif
149 cnt = auio.uio_resid;
9754d709
MK
150 if (error = (*fp->f_ops->fo_read)(fp, &auio, fp->f_cred))
151 if (auio.uio_resid != cnt && (error == ERESTART ||
152 error == EINTR || error == EWOULDBLOCK))
153 error = 0;
c4ec2128
KM
154 cnt -= auio.uio_resid;
155#ifdef KTRACE
156 if (ktriov != NULL) {
e64d087d 157 if (error == 0)
c9714ae3 158 ktrgenio(p->p_tracep, uap->fdes, UIO_READ, ktriov, cnt);
c4ec2128
KM
159 FREE(ktriov, M_TEMP);
160 }
161#endif
c9714ae3 162 *retval = cnt;
46814581 163done:
c4ec2128 164 if (uap->iovcnt > UIO_SMALLIOV)
46814581 165 FREE(iov, M_IOV);
c4ec2128 166 RETURN (error);
ffe28cfe
BJ
167}
168
169/*
170 * Write system call
171 */
c9714ae3
KM
172write(p, uap, retval)
173 struct proc *p;
174 register struct args {
ffe28cfe
BJ
175 int fdes;
176 char *cbuf;
31286ce2 177 unsigned count;
c9714ae3
KM
178 } *uap;
179 int *retval;
180{
c4ec2128 181 register struct file *fp;
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
c4ec2128
KM
189 if (((unsigned)uap->fdes) >= NOFILE ||
190 (fp = u.u_ofile[uap->fdes]) == NULL ||
191 (fp->f_flag & FWRITE) == 0)
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;
200#ifdef KTRACE
201 /*
202 * if tracing, save a copy of iovec
203 */
c9714ae3 204 if (KTRPOINT(p, KTR_GENIO))
c4ec2128
KM
205 ktriov = aiov;
206#endif
207 cnt = uap->count;
9754d709
MK
208 if (error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred)) {
209 if (auio.uio_resid != cnt && (error == ERESTART ||
210 error == EINTR || error == EWOULDBLOCK))
211 error = 0;
212 if (error == EPIPE)
c9714ae3 213 psignal(p, SIGPIPE);
9754d709 214 }
c4ec2128
KM
215 cnt -= auio.uio_resid;
216#ifdef KTRACE
c9714ae3
KM
217 if (KTRPOINT(p, KTR_GENIO) && error == 0)
218 ktrgenio(p->p_tracep, uap->fdes, UIO_WRITE,
9fcd9e42 219 &ktriov, cnt);
c4ec2128 220#endif
c9714ae3 221 *retval = cnt;
c4ec2128 222 RETURN (error);
b9429893
BJ
223}
224
c9714ae3
KM
225/*
226 * Gather write system call
227 */
228writev(p, uap, retval)
229 struct proc *p;
230 register struct args {
b9429893
BJ
231 int fdes;
232 struct iovec *iovp;
31286ce2 233 unsigned iovcnt;
c9714ae3
KM
234 } *uap;
235 int *retval;
236{
c4ec2128 237 register struct file *fp;
b9429893 238 struct uio auio;
c4ec2128
KM
239 register struct iovec *iov;
240 struct iovec aiov[UIO_SMALLIOV];
241 long i, cnt, error = 0;
242#ifdef KTRACE
243 struct iovec *ktriov = NULL;
244#endif
b9429893 245
c4ec2128
KM
246 if (((unsigned)uap->fdes) >= NOFILE ||
247 (fp = u.u_ofile[uap->fdes]) == NULL ||
248 (fp->f_flag & FWRITE) == 0)
249 RETURN (EBADF);
46814581 250 if (uap->iovcnt > UIO_SMALLIOV) {
c4ec2128
KM
251 if (uap->iovcnt > UIO_MAXIOV)
252 RETURN (EINVAL);
46814581
MK
253 MALLOC(iov, struct iovec *,
254 sizeof(struct iovec) * uap->iovcnt, M_IOV, M_WAITOK);
46814581
MK
255 } else
256 iov = aiov;
257 auio.uio_iov = iov;
b9429893 258 auio.uio_iovcnt = uap->iovcnt;
c4ec2128
KM
259 auio.uio_rw = UIO_WRITE;
260 auio.uio_segflg = UIO_USERSPACE;
261 if (error = copyin((caddr_t)uap->iovp, (caddr_t)iov,
262 uap->iovcnt * sizeof (struct iovec)))
46814581 263 goto done;
c4ec2128
KM
264 auio.uio_resid = 0;
265 for (i = 0; i < uap->iovcnt; i++) {
b9429893 266 if (iov->iov_len < 0) {
c4ec2128
KM
267 error = EINVAL;
268 goto done;
b9429893 269 }
c4ec2128
KM
270 auio.uio_resid += iov->iov_len;
271 if (auio.uio_resid < 0) {
272 error = EINVAL;
273 goto done;
b9429893 274 }
2a0114a8 275 iov++;
b9429893 276 }
46814581 277#ifdef KTRACE
c4ec2128
KM
278 /*
279 * if tracing, save a copy of iovec
280 */
c9714ae3 281 if (KTRPOINT(p, KTR_GENIO)) {
92e1705e 282 unsigned iovlen = auio.uio_iovcnt * sizeof (struct iovec);
46814581
MK
283
284 MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
c4ec2128 285 bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
46814581
MK
286 }
287#endif
c4ec2128 288 cnt = auio.uio_resid;
9754d709
MK
289 if (error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred)) {
290 if (auio.uio_resid != cnt && (error == ERESTART ||
291 error == EINTR || error == EWOULDBLOCK))
292 error = 0;
293 if (error == EPIPE)
c9714ae3 294 psignal(p, SIGPIPE);
9754d709 295 }
c4ec2128 296 cnt -= auio.uio_resid;
46814581
MK
297#ifdef KTRACE
298 if (ktriov != NULL) {
e64d087d 299 if (error == 0)
c9714ae3 300 ktrgenio(p->p_tracep, uap->fdes, UIO_WRITE,
e64d087d 301 ktriov, cnt);
46814581
MK
302 FREE(ktriov, M_TEMP);
303 }
304#endif
c9714ae3 305 *retval = cnt;
c4ec2128
KM
306done:
307 if (uap->iovcnt > UIO_SMALLIOV)
308 FREE(iov, M_IOV);
309 RETURN (error);
4147b3f6 310}
ffe28cfe
BJ
311
312/*
313 * Ioctl system call
ffe28cfe 314 */
c9714ae3
KM
315/* ARGSUSED */
316ioctl(p, uap, retval)
317 struct proc *p;
318 register struct args {
ffe28cfe
BJ
319 int fdes;
320 int cmd;
321 caddr_t cmarg;
c9714ae3
KM
322 } *uap;
323 int *retval;
324{
325 register struct file *fp;
9754d709 326 register int com, error;
b9429893 327 register u_int size;
e0b18aec 328 caddr_t memp = 0;
c0bb7b0e 329#define STK_PARAMS 128
08eb908c
MK
330 char stkbuf[STK_PARAMS];
331 caddr_t data = stkbuf;
ffe28cfe 332
c4ec2128
KM
333 if ((unsigned)uap->fdes >= NOFILE ||
334 (fp = u.u_ofile[uap->fdes]) == NULL)
335 RETURN (EBADF);
9754d709
MK
336 if ((fp->f_flag & (FREAD|FWRITE)) == 0)
337 RETURN (EBADF);
4b72e2f9
SL
338 com = uap->cmd;
339
4b72e2f9 340 if (com == FIOCLEX) {
3650c37d 341 u.u_pofile[uap->fdes] |= UF_EXCLOSE;
ffe28cfe
BJ
342 return;
343 }
4b72e2f9 344 if (com == FIONCLEX) {
3650c37d 345 u.u_pofile[uap->fdes] &= ~UF_EXCLOSE;
9754d709 346 RETURN (0);
ffe28cfe 347 }
4b72e2f9
SL
348
349 /*
350 * Interpret high order word to find
351 * amount of data to be copied to/from the
352 * user's address space.
4b72e2f9 353 */
c0bb7b0e 354 size = IOCPARM_LEN(com);
9754d709
MK
355 if (size > IOCPARM_MAX)
356 RETURN (ENOTTY);
08eb908c 357 if (size > sizeof (stkbuf)) {
46814581 358 memp = (caddr_t)malloc((u_long)IOCPARM_LEN(com), M_IOCTLOPS,
5adcb337 359 M_WAITOK);
e0b18aec 360 data = memp;
c0bb7b0e 361 }
471f17ed
SL
362 if (com&IOC_IN) {
363 if (size) {
9754d709
MK
364 error = copyin(uap->cmarg, data, (u_int)size);
365 if (error) {
e0b18aec
KM
366 if (memp)
367 free(memp, M_IOCTLOPS);
9754d709 368 RETURN (error);
e0b18aec 369 }
471f17ed
SL
370 } else
371 *(caddr_t *)data = uap->cmarg;
372 } else if ((com&IOC_OUT) && size)
373 /*
46814581
MK
374 * Zero the buffer so the user always
375 * gets back something deterministic.
471f17ed 376 */
c0bb7b0e 377 bzero(data, size);
a76b60f6
SL
378 else if (com&IOC_VOID)
379 *(caddr_t *)data = uap->cmarg;
4b72e2f9 380
88a7a62a
SL
381 switch (com) {
382
383 case FIONBIO:
9754d709 384 error = fset(fp, FNDELAY, *(int *)data);
c0bb7b0e 385 break;
88a7a62a
SL
386
387 case FIOASYNC:
9754d709 388 error = fset(fp, FASYNC, *(int *)data);
c0bb7b0e 389 break;
88a7a62a
SL
390
391 case FIOSETOWN:
9754d709 392 error = fsetown(fp, *(int *)data);
c0bb7b0e 393 break;
4b72e2f9 394
88a7a62a 395 case FIOGETOWN:
9754d709 396 error = fgetown(fp, (int *)data);
c0bb7b0e
MK
397 break;
398 default:
9754d709 399 error = (*fp->f_ops->fo_ioctl)(fp, com, data);
c0bb7b0e
MK
400 /*
401 * Copy any data to user, size was
402 * already set and checked above.
403 */
9754d709
MK
404 if (error == 0 && (com&IOC_OUT) && size)
405 error = copyout(data, uap->cmarg, (u_int)size);
c0bb7b0e 406 break;
88a7a62a 407 }
e0b18aec
KM
408 if (memp)
409 free(memp, M_IOCTLOPS);
9754d709 410 RETURN (error);
ffe28cfe
BJ
411}
412
88a7a62a 413int nselcoll;
d441e5bc 414
ffe28cfe 415/*
88a7a62a 416 * Select system call.
ffe28cfe 417 */
c9714ae3
KM
418select(p, uap, retval)
419 register struct proc *p;
420 register struct args {
88a7a62a 421 int nd;
b8e71e77 422 fd_set *in, *ou, *ex;
88a7a62a 423 struct timeval *tv;
c9714ae3
KM
424 } *uap;
425 int *retval;
426{
b8e71e77 427 fd_set ibits[3], obits[3];
88a7a62a 428 struct timeval atv;
9754d709 429 int s, ncoll, ni, error = 0, timo;
88a7a62a 430
01b0e233
MK
431 bzero((caddr_t)ibits, sizeof(ibits));
432 bzero((caddr_t)obits, sizeof(obits));
88a7a62a
SL
433 if (uap->nd > NOFILE)
434 uap->nd = NOFILE; /* forgiving, if slightly wrong */
b8e71e77 435 ni = howmany(uap->nd, NFDBITS);
88a7a62a
SL
436
437#define getbits(name, x) \
438 if (uap->name) { \
9754d709 439 error = copyin((caddr_t)uap->name, (caddr_t)&ibits[x], \
01b0e233 440 (unsigned)(ni * sizeof(fd_mask))); \
9754d709 441 if (error) \
88a7a62a 442 goto done; \
d441e5bc 443 }
88a7a62a
SL
444 getbits(in, 0);
445 getbits(ou, 1);
446 getbits(ex, 2);
447#undef getbits
448
449 if (uap->tv) {
9754d709 450 error = copyin((caddr_t)uap->tv, (caddr_t)&atv,
88a7a62a 451 sizeof (atv));
9754d709 452 if (error)
88a7a62a
SL
453 goto done;
454 if (itimerfix(&atv)) {
9754d709 455 error = EINVAL;
88a7a62a
SL
456 goto done;
457 }
c4e1f1e5 458 s = splhigh(); timevaladd(&atv, &time); splx(s);
9754d709
MK
459 timo = hzto(&atv);
460 } else
461 timo = 0;
88a7a62a
SL
462retry:
463 ncoll = nselcoll;
c9714ae3
KM
464 p->p_flag |= SSEL;
465 error = selscan(ibits, obits, uap->nd, retval);
9754d709
MK
466 if (error == 0)
467 error = u.u_error; /* XXX */
c9714ae3 468 if (error || *retval)
88a7a62a 469 goto done;
c4e1f1e5 470 s = splhigh();
e394e134
SL
471 /* this should be timercmp(&time, &atv, >=) */
472 if (uap->tv && (time.tv_sec > atv.tv_sec ||
473 time.tv_sec == atv.tv_sec && time.tv_usec >= atv.tv_usec)) {
88a7a62a
SL
474 splx(s);
475 goto done;
476 }
c9714ae3 477 if ((p->p_flag & SSEL) == 0 || nselcoll != ncoll) {
88a7a62a
SL
478 splx(s);
479 goto retry;
480 }
c9714ae3 481 p->p_flag &= ~SSEL;
9754d709 482 error = tsleep((caddr_t)&selwait, PSOCK | PCATCH, "select", timo);
88a7a62a 483 splx(s);
9754d709
MK
484 if (error == 0)
485 goto retry;
88a7a62a 486done:
c9714ae3 487 p->p_flag &= ~SSEL;
9754d709
MK
488 /* select is not restarted after signals... */
489 if (error == ERESTART)
490 error = EINTR;
491 if (error == EWOULDBLOCK)
492 error = 0;
88a7a62a
SL
493#define putbits(name, x) \
494 if (uap->name) { \
9754d709 495 int error2 = copyout((caddr_t)&obits[x], (caddr_t)uap->name, \
01b0e233 496 (unsigned)(ni * sizeof(fd_mask))); \
9754d709
MK
497 if (error2) \
498 error = error2; \
88a7a62a 499 }
9754d709 500 if (error == 0) {
79f403fc
MK
501 putbits(in, 0);
502 putbits(ou, 1);
503 putbits(ex, 2);
88a7a62a 504#undef putbits
79f403fc 505 }
9754d709 506 RETURN (error);
88a7a62a
SL
507}
508
c9714ae3 509selscan(ibits, obits, nfd, retval)
b8e71e77 510 fd_set *ibits, *obits;
c9714ae3 511 int nfd, *retval;
88a7a62a 512{
b8e71e77
MK
513 register int which, i, j;
514 register fd_mask bits;
88a7a62a
SL
515 int flag;
516 struct file *fp;
c9714ae3 517 int error = 0, n = 0;
88a7a62a
SL
518
519 for (which = 0; which < 3; which++) {
88a7a62a
SL
520 switch (which) {
521
522 case 0:
523 flag = FREAD; break;
524
525 case 1:
526 flag = FWRITE; break;
527
528 case 2:
529 flag = 0; break;
530 }
b8e71e77
MK
531 for (i = 0; i < nfd; i += NFDBITS) {
532 bits = ibits[which].fds_bits[i/NFDBITS];
d441e5bc
MK
533 while ((j = ffs(bits)) && i + --j < nfd) {
534 bits &= ~(1 << j);
535 fp = u.u_ofile[i + j];
536 if (fp == NULL) {
c9714ae3 537 error = EBADF;
d441e5bc
MK
538 break;
539 }
540 if ((*fp->f_ops->fo_select)(fp, flag)) {
b8e71e77 541 FD_SET(i + j, &obits[which]);
d441e5bc
MK
542 n++;
543 }
88a7a62a
SL
544 }
545 }
546 }
c9714ae3
KM
547 *retval = n;
548 return (error);
88a7a62a
SL
549}
550
ffe28cfe 551/*ARGSUSED*/
88a7a62a
SL
552seltrue(dev, flag)
553 dev_t dev;
554 int flag;
ffe28cfe
BJ
555{
556
88a7a62a 557 return (1);
ffe28cfe 558}
1edb1cf8 559
88a7a62a
SL
560selwakeup(p, coll)
561 register struct proc *p;
562 int coll;
1edb1cf8
BJ
563{
564
88a7a62a
SL
565 if (coll) {
566 nselcoll++;
567 wakeup((caddr_t)&selwait);
568 }
569 if (p) {
c4e1f1e5 570 int s = splhigh();
6bc3aba9
MK
571 if (p->p_wchan == (caddr_t)&selwait) {
572 if (p->p_stat == SSLEEP)
573 setrun(p);
574 else
575 unsleep(p);
576 } else if (p->p_flag & SSEL)
88a7a62a
SL
577 p->p_flag &= ~SSEL;
578 splx(s);
579 }
1edb1cf8 580}