reset optind before getopt() -- fixes 'make -k clean' failure
[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 *
d9c2f47f 17 * @(#)sys_generic.c 7.21 (Berkeley) %G%
da7c5cc6 18 */
ffe28cfe 19
94368568
JB
20#include "param.h"
21#include "systm.h"
d9c2f47f 22#include "user.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)
d9c2f47f 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 79 if (KTRPOINT(p, KTR_GENIO) && error == 0)
51322105 80 ktrgenio(p->p_tracep, uap->fdes, 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 */
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)
d9c2f47f 110 return (EBADF);
46814581 111 if (uap->iovcnt > UIO_SMALLIOV) {
c4ec2128 112 if (uap->iovcnt > UIO_MAXIOV)
d9c2f47f 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)
51322105
KM
158 ktrgenio(p->p_tracep, uap->fdes, UIO_READ, ktriov,
159 cnt, error);
c4ec2128
KM
160 FREE(ktriov, M_TEMP);
161 }
162#endif
c9714ae3 163 *retval = cnt;
46814581 164done:
c4ec2128 165 if (uap->iovcnt > UIO_SMALLIOV)
46814581 166 FREE(iov, M_IOV);
d9c2f47f 167 return (error);
ffe28cfe
BJ
168}
169
170/*
171 * Write system call
172 */
c9714ae3
KM
173write(p, uap, retval)
174 struct proc *p;
175 register struct args {
ffe28cfe
BJ
176 int fdes;
177 char *cbuf;
31286ce2 178 unsigned count;
c9714ae3
KM
179 } *uap;
180 int *retval;
181{
c4ec2128 182 register struct file *fp;
b9429893
BJ
183 struct uio auio;
184 struct iovec aiov;
c4ec2128
KM
185 long cnt, error = 0;
186#ifdef KTRACE
187 struct iovec ktriov;
188#endif
ffe28cfe 189
c4ec2128
KM
190 if (((unsigned)uap->fdes) >= NOFILE ||
191 (fp = u.u_ofile[uap->fdes]) == NULL ||
192 (fp->f_flag & FWRITE) == 0)
d9c2f47f 193 return (EBADF);
c4ec2128
KM
194 aiov.iov_base = (caddr_t)uap->cbuf;
195 aiov.iov_len = uap->count;
b9429893
BJ
196 auio.uio_iov = &aiov;
197 auio.uio_iovcnt = 1;
c4ec2128
KM
198 auio.uio_resid = uap->count;
199 auio.uio_rw = UIO_WRITE;
200 auio.uio_segflg = UIO_USERSPACE;
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 */
229writev(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;
b9429893 239 struct uio auio;
c4ec2128
KM
240 register struct iovec *iov;
241 struct iovec aiov[UIO_SMALLIOV];
242 long i, cnt, error = 0;
243#ifdef KTRACE
244 struct iovec *ktriov = NULL;
245#endif
b9429893 246
c4ec2128
KM
247 if (((unsigned)uap->fdes) >= NOFILE ||
248 (fp = u.u_ofile[uap->fdes]) == NULL ||
249 (fp->f_flag & FWRITE) == 0)
d9c2f47f 250 return (EBADF);
46814581 251 if (uap->iovcnt > UIO_SMALLIOV) {
c4ec2128 252 if (uap->iovcnt > UIO_MAXIOV)
d9c2f47f 253 return (EINVAL);
46814581
MK
254 MALLOC(iov, struct iovec *,
255 sizeof(struct iovec) * uap->iovcnt, M_IOV, M_WAITOK);
46814581
MK
256 } else
257 iov = aiov;
258 auio.uio_iov = iov;
b9429893 259 auio.uio_iovcnt = uap->iovcnt;
c4ec2128
KM
260 auio.uio_rw = UIO_WRITE;
261 auio.uio_segflg = UIO_USERSPACE;
262 if (error = copyin((caddr_t)uap->iovp, (caddr_t)iov,
263 uap->iovcnt * sizeof (struct iovec)))
46814581 264 goto done;
c4ec2128
KM
265 auio.uio_resid = 0;
266 for (i = 0; i < uap->iovcnt; i++) {
b9429893 267 if (iov->iov_len < 0) {
c4ec2128
KM
268 error = EINVAL;
269 goto done;
b9429893 270 }
c4ec2128
KM
271 auio.uio_resid += iov->iov_len;
272 if (auio.uio_resid < 0) {
273 error = EINVAL;
274 goto done;
b9429893 275 }
2a0114a8 276 iov++;
b9429893 277 }
46814581 278#ifdef KTRACE
c4ec2128
KM
279 /*
280 * if tracing, save a copy of iovec
281 */
c9714ae3 282 if (KTRPOINT(p, KTR_GENIO)) {
92e1705e 283 unsigned iovlen = auio.uio_iovcnt * sizeof (struct iovec);
46814581
MK
284
285 MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
c4ec2128 286 bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
46814581
MK
287 }
288#endif
c4ec2128 289 cnt = auio.uio_resid;
9754d709
MK
290 if (error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred)) {
291 if (auio.uio_resid != cnt && (error == ERESTART ||
292 error == EINTR || error == EWOULDBLOCK))
293 error = 0;
294 if (error == EPIPE)
c9714ae3 295 psignal(p, SIGPIPE);
9754d709 296 }
c4ec2128 297 cnt -= auio.uio_resid;
46814581
MK
298#ifdef KTRACE
299 if (ktriov != NULL) {
e64d087d 300 if (error == 0)
c9714ae3 301 ktrgenio(p->p_tracep, uap->fdes, UIO_WRITE,
51322105 302 ktriov, cnt, error);
46814581
MK
303 FREE(ktriov, M_TEMP);
304 }
305#endif
c9714ae3 306 *retval = cnt;
c4ec2128
KM
307done:
308 if (uap->iovcnt > UIO_SMALLIOV)
309 FREE(iov, M_IOV);
d9c2f47f 310 return (error);
4147b3f6 311}
ffe28cfe
BJ
312
313/*
314 * Ioctl system call
ffe28cfe 315 */
c9714ae3
KM
316/* ARGSUSED */
317ioctl(p, uap, retval)
318 struct proc *p;
319 register struct args {
ffe28cfe
BJ
320 int fdes;
321 int cmd;
322 caddr_t cmarg;
c9714ae3
KM
323 } *uap;
324 int *retval;
325{
326 register struct file *fp;
9754d709 327 register int com, error;
b9429893 328 register u_int size;
e0b18aec 329 caddr_t memp = 0;
c0bb7b0e 330#define STK_PARAMS 128
08eb908c
MK
331 char stkbuf[STK_PARAMS];
332 caddr_t data = stkbuf;
ffe28cfe 333
c4ec2128
KM
334 if ((unsigned)uap->fdes >= NOFILE ||
335 (fp = u.u_ofile[uap->fdes]) == NULL)
d9c2f47f 336 return (EBADF);
9754d709 337 if ((fp->f_flag & (FREAD|FWRITE)) == 0)
d9c2f47f 338 return (EBADF);
4b72e2f9
SL
339 com = uap->cmd;
340
4b72e2f9 341 if (com == FIOCLEX) {
3650c37d 342 u.u_pofile[uap->fdes] |= UF_EXCLOSE;
d9c2f47f 343 return (0);
ffe28cfe 344 }
4b72e2f9 345 if (com == FIONCLEX) {
3650c37d 346 u.u_pofile[uap->fdes] &= ~UF_EXCLOSE;
d9c2f47f 347 return (0);
ffe28cfe 348 }
4b72e2f9
SL
349
350 /*
351 * Interpret high order word to find
352 * amount of data to be copied to/from the
353 * user's address space.
4b72e2f9 354 */
c0bb7b0e 355 size = IOCPARM_LEN(com);
9754d709 356 if (size > IOCPARM_MAX)
d9c2f47f 357 return (ENOTTY);
08eb908c 358 if (size > sizeof (stkbuf)) {
f452da3a 359 memp = (caddr_t)malloc((u_long)size, M_IOCTLOPS, 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);
d9c2f47f 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);
d9c2f47f 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);
c9714ae3 466 if (error || *retval)
88a7a62a 467 goto done;
c4e1f1e5 468 s = splhigh();
e394e134
SL
469 /* this should be timercmp(&time, &atv, >=) */
470 if (uap->tv && (time.tv_sec > atv.tv_sec ||
471 time.tv_sec == atv.tv_sec && time.tv_usec >= atv.tv_usec)) {
88a7a62a
SL
472 splx(s);
473 goto done;
474 }
c9714ae3 475 if ((p->p_flag & SSEL) == 0 || nselcoll != ncoll) {
88a7a62a
SL
476 splx(s);
477 goto retry;
478 }
c9714ae3 479 p->p_flag &= ~SSEL;
9754d709 480 error = tsleep((caddr_t)&selwait, PSOCK | PCATCH, "select", timo);
88a7a62a 481 splx(s);
9754d709
MK
482 if (error == 0)
483 goto retry;
88a7a62a 484done:
c9714ae3 485 p->p_flag &= ~SSEL;
9754d709
MK
486 /* select is not restarted after signals... */
487 if (error == ERESTART)
488 error = EINTR;
489 if (error == EWOULDBLOCK)
490 error = 0;
88a7a62a
SL
491#define putbits(name, x) \
492 if (uap->name) { \
9754d709 493 int error2 = copyout((caddr_t)&obits[x], (caddr_t)uap->name, \
01b0e233 494 (unsigned)(ni * sizeof(fd_mask))); \
9754d709
MK
495 if (error2) \
496 error = error2; \
88a7a62a 497 }
9754d709 498 if (error == 0) {
79f403fc
MK
499 putbits(in, 0);
500 putbits(ou, 1);
501 putbits(ex, 2);
88a7a62a 502#undef putbits
79f403fc 503 }
d9c2f47f 504 return (error);
88a7a62a
SL
505}
506
c9714ae3 507selscan(ibits, obits, nfd, retval)
b8e71e77 508 fd_set *ibits, *obits;
c9714ae3 509 int nfd, *retval;
88a7a62a 510{
b8e71e77
MK
511 register int which, i, j;
512 register fd_mask bits;
88a7a62a
SL
513 int flag;
514 struct file *fp;
c9714ae3 515 int error = 0, n = 0;
88a7a62a
SL
516
517 for (which = 0; which < 3; which++) {
88a7a62a
SL
518 switch (which) {
519
520 case 0:
521 flag = FREAD; break;
522
523 case 1:
524 flag = FWRITE; break;
525
526 case 2:
527 flag = 0; break;
528 }
b8e71e77
MK
529 for (i = 0; i < nfd; i += NFDBITS) {
530 bits = ibits[which].fds_bits[i/NFDBITS];
d441e5bc
MK
531 while ((j = ffs(bits)) && i + --j < nfd) {
532 bits &= ~(1 << j);
533 fp = u.u_ofile[i + j];
534 if (fp == NULL) {
c9714ae3 535 error = EBADF;
d441e5bc
MK
536 break;
537 }
538 if ((*fp->f_ops->fo_select)(fp, flag)) {
b8e71e77 539 FD_SET(i + j, &obits[which]);
d441e5bc
MK
540 n++;
541 }
88a7a62a
SL
542 }
543 }
544 }
c9714ae3
KM
545 *retval = n;
546 return (error);
88a7a62a
SL
547}
548
ffe28cfe 549/*ARGSUSED*/
88a7a62a
SL
550seltrue(dev, flag)
551 dev_t dev;
552 int flag;
ffe28cfe
BJ
553{
554
88a7a62a 555 return (1);
ffe28cfe 556}
1edb1cf8 557
88a7a62a
SL
558selwakeup(p, coll)
559 register struct proc *p;
560 int coll;
1edb1cf8
BJ
561{
562
88a7a62a
SL
563 if (coll) {
564 nselcoll++;
565 wakeup((caddr_t)&selwait);
566 }
567 if (p) {
c4e1f1e5 568 int s = splhigh();
6bc3aba9
MK
569 if (p->p_wchan == (caddr_t)&selwait) {
570 if (p->p_stat == SSLEEP)
571 setrun(p);
572 else
573 unsleep(p);
574 } else if (p->p_flag & SSEL)
88a7a62a
SL
575 p->p_flag &= ~SSEL;
576 splx(s);
577 }
1edb1cf8 578}