merge in vnodes
[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 *
17 * @(#)sys_generic.c 7.10 (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 */
37read()
38{
ffe28cfe
BJ
39 register struct a {
40 int fdes;
41 char *cbuf;
42 unsigned count;
b9429893 43 } *uap = (struct a *)u.u_ap;
c4ec2128 44 register struct file *fp;
32a43ee2
BJ
45 struct uio auio;
46 struct iovec aiov;
c4ec2128
KM
47 long cnt, error = 0;
48#ifdef KTRACE
49 struct iovec ktriov;
50#endif
ffe28cfe 51
c4ec2128
KM
52 if (((unsigned)uap->fdes) >= NOFILE ||
53 (fp = u.u_ofile[uap->fdes]) == NULL ||
54 (fp->f_flag & FREAD) == 0)
55 RETURN (EBADF);
56 if (uap->count < 0)
57 RETURN (EINVAL);
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 */
69 if (KTRPOINT(u.u_procp, KTR_GENIO))
70 ktriov = aiov;
71#endif
72 cnt = uap->count;
73 if (setjmp(&u.u_qsave)) {
74 if (auio.uio_resid == cnt) {
75 if ((u.u_sigintr & sigmask(u.u_procp->p_cursig)) != 0)
76 error = EINTR;
77 else
78 u.u_eosys = RESTARTSYS;
79 }
80 } else
81 error = (*fp->f_ops->fo_read)(fp, &auio, u.u_cred);
82 cnt -= auio.uio_resid;
83#ifdef KTRACE
84 if (KTRPOINT(u.u_procp, KTR_GENIO))
85 ktrgenio(u.u_procp->p_tracep, uap->fdes, UIO_READ, ktriov, cnt);
86#endif
87 u.u_r.r_val1 = cnt;
88 RETURN (error);
b9429893
BJ
89}
90
91readv()
92{
93 register struct a {
94 int fdes;
95 struct iovec *iovp;
31286ce2 96 unsigned iovcnt;
b9429893 97 } *uap = (struct a *)u.u_ap;
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 */
142 if (KTRPOINT(u.u_procp, KTR_GENIO)) {
143 int iovlen = auio.uio_iovcnt * sizeof (struct iovec);
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;
150 if (setjmp(&u.u_qsave)) {
151 if (auio.uio_resid == cnt) {
152 if ((u.u_sigintr & sigmask(u.u_procp->p_cursig)) != 0)
153 error = EINTR;
154 else
155 u.u_eosys = RESTARTSYS;
156 }
157 } else
158 error = (*fp->f_ops->fo_read)(fp, &auio, u.u_cred);
159 cnt -= auio.uio_resid;
160#ifdef KTRACE
161 if (ktriov != NULL) {
162 ktrgenio(u.u_procp->p_tracep, uap->fdes, UIO_READ, ktriov, cnt);
163 FREE(ktriov, M_TEMP);
164 }
165#endif
166 u.u_r.r_val1 = cnt;
46814581 167done:
c4ec2128 168 if (uap->iovcnt > UIO_SMALLIOV)
46814581 169 FREE(iov, M_IOV);
c4ec2128 170 RETURN (error);
ffe28cfe
BJ
171}
172
173/*
174 * Write system call
175 */
176write()
177{
ffe28cfe
BJ
178 register struct a {
179 int fdes;
180 char *cbuf;
31286ce2 181 unsigned count;
b9429893 182 } *uap = (struct a *)u.u_ap;
c4ec2128 183 register struct file *fp;
b9429893
BJ
184 struct uio auio;
185 struct iovec aiov;
c4ec2128
KM
186 long cnt, error = 0;
187#ifdef KTRACE
188 struct iovec ktriov;
189#endif
ffe28cfe 190
c4ec2128
KM
191 if (((unsigned)uap->fdes) >= NOFILE ||
192 (fp = u.u_ofile[uap->fdes]) == NULL ||
193 (fp->f_flag & FWRITE) == 0)
194 RETURN (EBADF);
195 if (uap->count < 0)
196 RETURN (EINVAL);
197 aiov.iov_base = (caddr_t)uap->cbuf;
198 aiov.iov_len = uap->count;
b9429893
BJ
199 auio.uio_iov = &aiov;
200 auio.uio_iovcnt = 1;
c4ec2128
KM
201 auio.uio_resid = uap->count;
202 auio.uio_rw = UIO_WRITE;
203 auio.uio_segflg = UIO_USERSPACE;
204#ifdef KTRACE
205 /*
206 * if tracing, save a copy of iovec
207 */
208 if (KTRPOINT(u.u_procp, KTR_GENIO))
209 ktriov = aiov;
210#endif
211 cnt = uap->count;
212 if (setjmp(&u.u_qsave)) {
213 if (auio.uio_resid == cnt) {
214 if ((u.u_sigintr & sigmask(u.u_procp->p_cursig)) != 0)
215 error = EINTR;
216 else
217 u.u_eosys = RESTARTSYS;
218 }
219 } else
220 error = (*fp->f_ops->fo_write)(fp, &auio, u.u_cred);
221 cnt -= auio.uio_resid;
222#ifdef KTRACE
223 if (KTRPOINT(u.u_procp, KTR_GENIO))
224 ktrgenio(u.u_procp->p_tracep, uap->fdes, UIO_WRITE,
225 ktriov, cnt);
226#endif
227 u.u_r.r_val1 = cnt;
228 RETURN (error);
b9429893
BJ
229}
230
231writev()
232{
233 register struct a {
234 int fdes;
235 struct iovec *iovp;
31286ce2 236 unsigned iovcnt;
b9429893 237 } *uap = (struct a *)u.u_ap;
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)
250 RETURN (EBADF);
46814581 251 if (uap->iovcnt > UIO_SMALLIOV) {
c4ec2128
KM
252 if (uap->iovcnt > UIO_MAXIOV)
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 */
46814581 282 if (KTRPOINT(u.u_procp, KTR_GENIO)) {
c4ec2128 283 int 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;
fe7f81f4 290 if (setjmp(&u.u_qsave)) {
c4ec2128 291 if (auio.uio_resid == cnt) {
9f49ba41 292 if ((u.u_sigintr & sigmask(u.u_procp->p_cursig)) != 0)
c4ec2128 293 error = EINTR;
fe7f81f4
KM
294 else
295 u.u_eosys = RESTARTSYS;
296 }
b9429893 297 } else
c4ec2128
KM
298 error = (*fp->f_ops->fo_write)(fp, &auio, u.u_cred);
299 cnt -= auio.uio_resid;
46814581
MK
300#ifdef KTRACE
301 if (ktriov != NULL) {
c4ec2128
KM
302 ktrgenio(u.u_procp->p_tracep, uap->fdes, UIO_WRITE,
303 ktriov, cnt);
46814581
MK
304 FREE(ktriov, M_TEMP);
305 }
306#endif
c4ec2128
KM
307 u.u_r.r_val1 = cnt;
308done:
309 if (uap->iovcnt > UIO_SMALLIOV)
310 FREE(iov, M_IOV);
311 RETURN (error);
4147b3f6 312}
ffe28cfe
BJ
313
314/*
315 * Ioctl system call
ffe28cfe
BJ
316 */
317ioctl()
318{
319 register struct file *fp;
4b72e2f9 320 struct a {
ffe28cfe
BJ
321 int fdes;
322 int cmd;
323 caddr_t cmarg;
c4ec2128 324 } *uap = (struct a *)u.u_ap;
b9429893
BJ
325 register int com;
326 register u_int size;
e0b18aec 327 caddr_t memp = 0;
c0bb7b0e 328#define STK_PARAMS 128
08eb908c
MK
329 char stkbuf[STK_PARAMS];
330 caddr_t data = stkbuf;
ffe28cfe 331
c4ec2128
KM
332 if ((unsigned)uap->fdes >= NOFILE ||
333 (fp = u.u_ofile[uap->fdes]) == NULL)
334 RETURN (EBADF);
ffe28cfe
BJ
335 if ((fp->f_flag & (FREAD|FWRITE)) == 0) {
336 u.u_error = EBADF;
337 return;
338 }
4b72e2f9
SL
339 com = uap->cmd;
340
4b72e2f9 341 if (com == FIOCLEX) {
3650c37d 342 u.u_pofile[uap->fdes] |= UF_EXCLOSE;
ffe28cfe
BJ
343 return;
344 }
4b72e2f9 345 if (com == FIONCLEX) {
3650c37d 346 u.u_pofile[uap->fdes] &= ~UF_EXCLOSE;
ffe28cfe
BJ
347 return;
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
MK
355 size = IOCPARM_LEN(com);
356 if (size > IOCPARM_MAX) {
46814581 357 u.u_error = ENOTTY;
ffe28cfe
BJ
358 return;
359 }
08eb908c 360 if (size > sizeof (stkbuf)) {
46814581 361 memp = (caddr_t)malloc((u_long)IOCPARM_LEN(com), M_IOCTLOPS,
5adcb337 362 M_WAITOK);
e0b18aec 363 data = memp;
c0bb7b0e 364 }
471f17ed
SL
365 if (com&IOC_IN) {
366 if (size) {
46814581 367 u.u_error = copyin(uap->cmarg, data, (u_int)size);
e0b18aec
KM
368 if (u.u_error) {
369 if (memp)
370 free(memp, M_IOCTLOPS);
471f17ed 371 return;
e0b18aec 372 }
471f17ed
SL
373 } else
374 *(caddr_t *)data = uap->cmarg;
375 } else if ((com&IOC_OUT) && size)
376 /*
46814581
MK
377 * Zero the buffer so the user always
378 * gets back something deterministic.
471f17ed 379 */
c0bb7b0e 380 bzero(data, size);
a76b60f6
SL
381 else if (com&IOC_VOID)
382 *(caddr_t *)data = uap->cmarg;
4b72e2f9 383
88a7a62a
SL
384 switch (com) {
385
386 case FIONBIO:
387 u.u_error = fset(fp, FNDELAY, *(int *)data);
c0bb7b0e 388 break;
88a7a62a
SL
389
390 case FIOASYNC:
391 u.u_error = fset(fp, FASYNC, *(int *)data);
c0bb7b0e 392 break;
88a7a62a
SL
393
394 case FIOSETOWN:
395 u.u_error = fsetown(fp, *(int *)data);
c0bb7b0e 396 break;
4b72e2f9 397
88a7a62a
SL
398 case FIOGETOWN:
399 u.u_error = fgetown(fp, (int *)data);
c0bb7b0e
MK
400 break;
401 default:
402 if (setjmp(&u.u_qsave))
403 u.u_error = EINTR;
404 else
405 u.u_error = (*fp->f_ops->fo_ioctl)(fp, com, data);
406 /*
407 * Copy any data to user, size was
408 * already set and checked above.
409 */
410 if (u.u_error == 0 && (com&IOC_OUT) && size)
411 u.u_error = copyout(data, uap->cmarg, (u_int)size);
412 break;
88a7a62a 413 }
e0b18aec
KM
414 if (memp)
415 free(memp, M_IOCTLOPS);
ffe28cfe
BJ
416}
417
88a7a62a
SL
418int unselect();
419int nselcoll;
d441e5bc 420
ffe28cfe 421/*
88a7a62a 422 * Select system call.
ffe28cfe 423 */
88a7a62a
SL
424select()
425{
426 register struct uap {
427 int nd;
b8e71e77 428 fd_set *in, *ou, *ex;
88a7a62a
SL
429 struct timeval *tv;
430 } *uap = (struct uap *)u.u_ap;
b8e71e77 431 fd_set ibits[3], obits[3];
88a7a62a 432 struct timeval atv;
d441e5bc 433 int s, ncoll, ni;
88a7a62a
SL
434 label_t lqsave;
435
01b0e233
MK
436 bzero((caddr_t)ibits, sizeof(ibits));
437 bzero((caddr_t)obits, sizeof(obits));
88a7a62a
SL
438 if (uap->nd > NOFILE)
439 uap->nd = NOFILE; /* forgiving, if slightly wrong */
b8e71e77 440 ni = howmany(uap->nd, NFDBITS);
88a7a62a
SL
441
442#define getbits(name, x) \
443 if (uap->name) { \
b8e71e77 444 u.u_error = copyin((caddr_t)uap->name, (caddr_t)&ibits[x], \
01b0e233 445 (unsigned)(ni * sizeof(fd_mask))); \
88a7a62a
SL
446 if (u.u_error) \
447 goto done; \
d441e5bc 448 }
88a7a62a
SL
449 getbits(in, 0);
450 getbits(ou, 1);
451 getbits(ex, 2);
452#undef getbits
453
454 if (uap->tv) {
455 u.u_error = copyin((caddr_t)uap->tv, (caddr_t)&atv,
456 sizeof (atv));
457 if (u.u_error)
458 goto done;
459 if (itimerfix(&atv)) {
460 u.u_error = EINVAL;
461 goto done;
462 }
c4e1f1e5 463 s = splhigh(); timevaladd(&atv, &time); splx(s);
88a7a62a
SL
464 }
465retry:
466 ncoll = nselcoll;
467 u.u_procp->p_flag |= SSEL;
d441e5bc 468 u.u_r.r_val1 = selscan(ibits, obits, uap->nd);
88a7a62a
SL
469 if (u.u_error || u.u_r.r_val1)
470 goto done;
c4e1f1e5 471 s = splhigh();
e394e134
SL
472 /* this should be timercmp(&time, &atv, >=) */
473 if (uap->tv && (time.tv_sec > atv.tv_sec ||
474 time.tv_sec == atv.tv_sec && time.tv_usec >= atv.tv_usec)) {
88a7a62a
SL
475 splx(s);
476 goto done;
477 }
478 if ((u.u_procp->p_flag & SSEL) == 0 || nselcoll != ncoll) {
88a7a62a
SL
479 splx(s);
480 goto retry;
481 }
482 u.u_procp->p_flag &= ~SSEL;
483 if (uap->tv) {
484 lqsave = u.u_qsave;
485 if (setjmp(&u.u_qsave)) {
486 untimeout(unselect, (caddr_t)u.u_procp);
487 u.u_error = EINTR;
488 splx(s);
489 goto done;
490 }
491 timeout(unselect, (caddr_t)u.u_procp, hzto(&atv));
492 }
493 sleep((caddr_t)&selwait, PZERO+1);
494 if (uap->tv) {
495 u.u_qsave = lqsave;
496 untimeout(unselect, (caddr_t)u.u_procp);
497 }
498 splx(s);
499 goto retry;
500done:
b894ed59 501 u.u_procp->p_flag &= ~SSEL;
88a7a62a
SL
502#define putbits(name, x) \
503 if (uap->name) { \
b8e71e77 504 int error = copyout((caddr_t)&obits[x], (caddr_t)uap->name, \
01b0e233 505 (unsigned)(ni * sizeof(fd_mask))); \
88a7a62a
SL
506 if (error) \
507 u.u_error = error; \
508 }
87a3ba07 509 if (u.u_error == 0) {
79f403fc
MK
510 putbits(in, 0);
511 putbits(ou, 1);
512 putbits(ex, 2);
88a7a62a 513#undef putbits
79f403fc 514 }
88a7a62a
SL
515}
516
517unselect(p)
518 register struct proc *p;
519{
c4e1f1e5 520 register int s = splhigh();
88a7a62a
SL
521
522 switch (p->p_stat) {
523
524 case SSLEEP:
525 setrun(p);
526 break;
527
528 case SSTOP:
529 unsleep(p);
530 break;
531 }
532 splx(s);
533}
534
d441e5bc 535selscan(ibits, obits, nfd)
b8e71e77 536 fd_set *ibits, *obits;
88a7a62a 537{
b8e71e77
MK
538 register int which, i, j;
539 register fd_mask bits;
88a7a62a
SL
540 int flag;
541 struct file *fp;
542 int n = 0;
543
544 for (which = 0; which < 3; which++) {
88a7a62a
SL
545 switch (which) {
546
547 case 0:
548 flag = FREAD; break;
549
550 case 1:
551 flag = FWRITE; break;
552
553 case 2:
554 flag = 0; break;
555 }
b8e71e77
MK
556 for (i = 0; i < nfd; i += NFDBITS) {
557 bits = ibits[which].fds_bits[i/NFDBITS];
d441e5bc
MK
558 while ((j = ffs(bits)) && i + --j < nfd) {
559 bits &= ~(1 << j);
560 fp = u.u_ofile[i + j];
561 if (fp == NULL) {
562 u.u_error = EBADF;
563 break;
564 }
565 if ((*fp->f_ops->fo_select)(fp, flag)) {
b8e71e77 566 FD_SET(i + j, &obits[which]);
d441e5bc
MK
567 n++;
568 }
88a7a62a
SL
569 }
570 }
571 }
572 return (n);
573}
574
ffe28cfe 575/*ARGSUSED*/
88a7a62a
SL
576seltrue(dev, flag)
577 dev_t dev;
578 int flag;
ffe28cfe
BJ
579{
580
88a7a62a 581 return (1);
ffe28cfe 582}
1edb1cf8 583
88a7a62a
SL
584selwakeup(p, coll)
585 register struct proc *p;
586 int coll;
1edb1cf8
BJ
587{
588
88a7a62a
SL
589 if (coll) {
590 nselcoll++;
591 wakeup((caddr_t)&selwait);
592 }
593 if (p) {
c4e1f1e5 594 int s = splhigh();
6bc3aba9
MK
595 if (p->p_wchan == (caddr_t)&selwait) {
596 if (p->p_stat == SSLEEP)
597 setrun(p);
598 else
599 unsleep(p);
600 } else if (p->p_flag & SSEL)
88a7a62a
SL
601 p->p_flag &= ~SSEL;
602 splx(s);
603 }
1edb1cf8 604}