This commit was manufactured by cvs2svn to create tag 'FreeBSD-release/1.1'.
[unix-history] / sys / kern / sys_generic.c
CommitLineData
15637ed4
RG
1/*
2 * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
600f7f07 33 * from: @(#)sys_generic.c 7.30 (Berkeley) 5/30/91
fde1aeb2 34 * $Id: sys_generic.c,v 1.5 1993/11/25 01:33:20 wollman Exp $
15637ed4
RG
35 */
36
37#include "param.h"
38#include "systm.h"
39#include "filedesc.h"
40#include "ioctl.h"
41#include "file.h"
42#include "socketvar.h"
43#include "proc.h"
44#include "uio.h"
45#include "kernel.h"
46#include "stat.h"
47#include "malloc.h"
fde1aeb2 48#include "signalvar.h"
15637ed4
RG
49#ifdef KTRACE
50#include "ktrace.h"
51#endif
52
3c7eb27c
DG
53struct read_args {
54 int fdes;
55 char *cbuf;
56 unsigned count;
57};
58
15637ed4
RG
59/*
60 * Read system call.
61 */
62/* ARGSUSED */
4c45483e 63int
15637ed4
RG
64read(p, uap, retval)
65 struct proc *p;
3c7eb27c 66 register struct read_args *uap;
15637ed4
RG
67 int *retval;
68{
69 register struct file *fp;
70 register struct filedesc *fdp = p->p_fd;
71 struct uio auio;
72 struct iovec aiov;
73 long cnt, error = 0;
74#ifdef KTRACE
75 struct iovec ktriov;
76#endif
77
78 if (((unsigned)uap->fdes) >= fdp->fd_nfiles ||
79 (fp = fdp->fd_ofiles[uap->fdes]) == NULL ||
80 (fp->f_flag & FREAD) == 0)
81 return (EBADF);
82 aiov.iov_base = (caddr_t)uap->cbuf;
83 aiov.iov_len = uap->count;
84 auio.uio_iov = &aiov;
85 auio.uio_iovcnt = 1;
86 auio.uio_resid = uap->count;
87 auio.uio_rw = UIO_READ;
88 auio.uio_segflg = UIO_USERSPACE;
89 auio.uio_procp = p;
90#ifdef KTRACE
91 /*
92 * if tracing, save a copy of iovec
93 */
94 if (KTRPOINT(p, KTR_GENIO))
95 ktriov = aiov;
96#endif
97 cnt = uap->count;
98 if (error = (*fp->f_ops->fo_read)(fp, &auio, fp->f_cred))
99 if (auio.uio_resid != cnt && (error == ERESTART ||
100 error == EINTR || error == EWOULDBLOCK))
101 error = 0;
102 cnt -= auio.uio_resid;
103#ifdef KTRACE
104 if (KTRPOINT(p, KTR_GENIO) && error == 0)
105 ktrgenio(p->p_tracep, uap->fdes, UIO_READ, &ktriov, cnt, error);
106#endif
107 *retval = cnt;
108 return (error);
109}
110
111/*
112 * Scatter read system call.
113 */
3c7eb27c
DG
114
115struct readv_args {
116 int fdes;
117 struct iovec *iovp;
118 unsigned iovcnt;
119};
120
15637ed4 121/* ARGSUSED */
4c45483e 122int
15637ed4
RG
123readv(p, uap, retval)
124 struct proc *p;
3c7eb27c 125 register struct readv_args *uap;
15637ed4
RG
126 int *retval;
127{
128 register struct file *fp;
129 register struct filedesc *fdp = p->p_fd;
130 struct uio auio;
131 register struct iovec *iov;
4c45483e 132 struct iovec *saveiov = 0;
15637ed4
RG
133 struct iovec aiov[UIO_SMALLIOV];
134 long i, cnt, error = 0;
135 unsigned iovlen;
136#ifdef KTRACE
137 struct iovec *ktriov = NULL;
138#endif
139
140 if (((unsigned)uap->fdes) >= fdp->fd_nfiles ||
141 (fp = fdp->fd_ofiles[uap->fdes]) == NULL ||
142 (fp->f_flag & FREAD) == 0)
143 return (EBADF);
144 /* note: can't use iovlen until iovcnt is validated */
145 iovlen = uap->iovcnt * sizeof (struct iovec);
146 if (uap->iovcnt > UIO_SMALLIOV) {
147 if (uap->iovcnt > UIO_MAXIOV)
148 return (EINVAL);
149 MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
150 saveiov = iov;
151 } else
152 iov = aiov;
153 auio.uio_iov = iov;
154 auio.uio_iovcnt = uap->iovcnt;
155 auio.uio_rw = UIO_READ;
156 auio.uio_segflg = UIO_USERSPACE;
157 auio.uio_procp = p;
158 if (error = copyin((caddr_t)uap->iovp, (caddr_t)iov, iovlen))
159 goto done;
160 auio.uio_resid = 0;
161 for (i = 0; i < uap->iovcnt; i++) {
162 if (iov->iov_len < 0) {
163 error = EINVAL;
164 goto done;
165 }
166 auio.uio_resid += iov->iov_len;
167 if (auio.uio_resid < 0) {
168 error = EINVAL;
169 goto done;
170 }
171 iov++;
172 }
173#ifdef KTRACE
174 /*
175 * if tracing, save a copy of iovec
176 */
177 if (KTRPOINT(p, KTR_GENIO)) {
178 MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
179 bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
180 }
181#endif
182 cnt = auio.uio_resid;
183 if (error = (*fp->f_ops->fo_read)(fp, &auio, fp->f_cred))
184 if (auio.uio_resid != cnt && (error == ERESTART ||
185 error == EINTR || error == EWOULDBLOCK))
186 error = 0;
187 cnt -= auio.uio_resid;
188#ifdef KTRACE
189 if (ktriov != NULL) {
190 if (error == 0)
191 ktrgenio(p->p_tracep, uap->fdes, UIO_READ, ktriov,
192 cnt, error);
193 FREE(ktriov, M_TEMP);
194 }
195#endif
196 *retval = cnt;
197done:
198 if (uap->iovcnt > UIO_SMALLIOV)
199 FREE(saveiov, M_IOV);
200 return (error);
201}
202
203/*
204 * Write system call
205 */
3c7eb27c
DG
206
207struct write_args {
208 int fdes;
209 char *cbuf;
210 unsigned count;
211};
212
4c45483e 213int
15637ed4
RG
214write(p, uap, retval)
215 struct proc *p;
3c7eb27c 216 register struct write_args *uap;
15637ed4
RG
217 int *retval;
218{
219 register struct file *fp;
220 register struct filedesc *fdp = p->p_fd;
221 struct uio auio;
222 struct iovec aiov;
223 long cnt, error = 0;
224#ifdef KTRACE
225 struct iovec ktriov;
226#endif
227
228 if (((unsigned)uap->fdes) >= fdp->fd_nfiles ||
229 (fp = fdp->fd_ofiles[uap->fdes]) == NULL ||
230 (fp->f_flag & FWRITE) == 0)
231 return (EBADF);
232 aiov.iov_base = (caddr_t)uap->cbuf;
233 aiov.iov_len = uap->count;
234 auio.uio_iov = &aiov;
235 auio.uio_iovcnt = 1;
236 auio.uio_resid = uap->count;
237 auio.uio_rw = UIO_WRITE;
238 auio.uio_segflg = UIO_USERSPACE;
239 auio.uio_procp = p;
240#ifdef KTRACE
241 /*
242 * if tracing, save a copy of iovec
243 */
244 if (KTRPOINT(p, KTR_GENIO))
245 ktriov = aiov;
246#endif
247 cnt = uap->count;
248 if (error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred)) {
249 if (auio.uio_resid != cnt && (error == ERESTART ||
250 error == EINTR || error == EWOULDBLOCK))
251 error = 0;
252 if (error == EPIPE)
253 psignal(p, SIGPIPE);
254 }
255 cnt -= auio.uio_resid;
256#ifdef KTRACE
257 if (KTRPOINT(p, KTR_GENIO) && error == 0)
258 ktrgenio(p->p_tracep, uap->fdes, UIO_WRITE,
259 &ktriov, cnt, error);
260#endif
261 *retval = cnt;
262 return (error);
263}
264
265/*
266 * Gather write system call
267 */
3c7eb27c
DG
268
269struct writev_args {
270 int fdes;
271 struct iovec *iovp;
272 unsigned iovcnt;
273};
274
4c45483e 275int
15637ed4
RG
276writev(p, uap, retval)
277 struct proc *p;
3c7eb27c 278 register struct writev_args *uap;
15637ed4
RG
279 int *retval;
280{
281 register struct file *fp;
282 register struct filedesc *fdp = p->p_fd;
283 struct uio auio;
284 register struct iovec *iov;
4c45483e 285 struct iovec *saveiov = 0;
15637ed4
RG
286 struct iovec aiov[UIO_SMALLIOV];
287 long i, cnt, error = 0;
288 unsigned iovlen;
289#ifdef KTRACE
290 struct iovec *ktriov = NULL;
291#endif
292
293 if (((unsigned)uap->fdes) >= fdp->fd_nfiles ||
294 (fp = fdp->fd_ofiles[uap->fdes]) == NULL ||
295 (fp->f_flag & FWRITE) == 0)
296 return (EBADF);
297 /* note: can't use iovlen until iovcnt is validated */
298 iovlen = uap->iovcnt * sizeof (struct iovec);
299 if (uap->iovcnt > UIO_SMALLIOV) {
300 if (uap->iovcnt > UIO_MAXIOV)
301 return (EINVAL);
302 MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
303 saveiov = iov;
304 } else
305 iov = aiov;
306 auio.uio_iov = iov;
307 auio.uio_iovcnt = uap->iovcnt;
308 auio.uio_rw = UIO_WRITE;
309 auio.uio_segflg = UIO_USERSPACE;
310 auio.uio_procp = p;
311 if (error = copyin((caddr_t)uap->iovp, (caddr_t)iov, iovlen))
312 goto done;
313 auio.uio_resid = 0;
314 for (i = 0; i < uap->iovcnt; i++) {
315 if (iov->iov_len < 0) {
316 error = EINVAL;
317 goto done;
318 }
319 auio.uio_resid += iov->iov_len;
320 if (auio.uio_resid < 0) {
321 error = EINVAL;
322 goto done;
323 }
324 iov++;
325 }
326#ifdef KTRACE
327 /*
328 * if tracing, save a copy of iovec
329 */
330 if (KTRPOINT(p, KTR_GENIO)) {
331 MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
332 bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
333 }
334#endif
335 cnt = auio.uio_resid;
336 if (error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred)) {
337 if (auio.uio_resid != cnt && (error == ERESTART ||
338 error == EINTR || error == EWOULDBLOCK))
339 error = 0;
340 if (error == EPIPE)
341 psignal(p, SIGPIPE);
342 }
343 cnt -= auio.uio_resid;
344#ifdef KTRACE
345 if (ktriov != NULL) {
346 if (error == 0)
347 ktrgenio(p->p_tracep, uap->fdes, UIO_WRITE,
348 ktriov, cnt, error);
349 FREE(ktriov, M_TEMP);
350 }
351#endif
352 *retval = cnt;
353done:
354 if (uap->iovcnt > UIO_SMALLIOV)
355 FREE(saveiov, M_IOV);
356 return (error);
357}
358
359/*
360 * Ioctl system call
361 */
3c7eb27c
DG
362
363struct ioctl_args {
364 int fdes;
365 int cmd;
366 caddr_t cmarg;
367};
368
15637ed4 369/* ARGSUSED */
4c45483e 370int
15637ed4
RG
371ioctl(p, uap, retval)
372 struct proc *p;
3c7eb27c 373 register struct ioctl_args *uap;
15637ed4
RG
374 int *retval;
375{
376 register struct file *fp;
377 register struct filedesc *fdp = p->p_fd;
378 register int com, error;
379 register u_int size;
380 caddr_t memp = 0;
381#define STK_PARAMS 128
382 char stkbuf[STK_PARAMS];
383 caddr_t data = stkbuf;
384 int tmp;
385
386 if ((unsigned)uap->fdes >= fdp->fd_nfiles ||
387 (fp = fdp->fd_ofiles[uap->fdes]) == NULL)
388 return (EBADF);
389 if ((fp->f_flag & (FREAD|FWRITE)) == 0)
390 return (EBADF);
391 com = uap->cmd;
392
393 if (com == FIOCLEX) {
394 fdp->fd_ofileflags[uap->fdes] |= UF_EXCLOSE;
395 return (0);
396 }
397 if (com == FIONCLEX) {
398 fdp->fd_ofileflags[uap->fdes] &= ~UF_EXCLOSE;
399 return (0);
400 }
401
402 /*
403 * Interpret high order word to find
404 * amount of data to be copied to/from the
405 * user's address space.
406 */
407 size = IOCPARM_LEN(com);
408 if (size > IOCPARM_MAX)
409 return (ENOTTY);
410 if (size > sizeof (stkbuf)) {
411 memp = (caddr_t)malloc((u_long)size, M_IOCTLOPS, M_WAITOK);
412 data = memp;
413 }
414 if (com&IOC_IN) {
415 if (size) {
416 error = copyin(uap->cmarg, data, (u_int)size);
417 if (error) {
418 if (memp)
419 free(memp, M_IOCTLOPS);
420 return (error);
421 }
422 } else
423 *(caddr_t *)data = uap->cmarg;
424 } else if ((com&IOC_OUT) && size)
425 /*
426 * Zero the buffer so the user always
427 * gets back something deterministic.
428 */
429 bzero(data, size);
430 else if (com&IOC_VOID)
431 *(caddr_t *)data = uap->cmarg;
432
433 switch (com) {
434
435 case FIONBIO:
436 if (tmp = *(int *)data)
437 fp->f_flag |= FNONBLOCK;
438 else
439 fp->f_flag &= ~FNONBLOCK;
440 error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p);
441 break;
442
443 case FIOASYNC:
444 if (tmp = *(int *)data)
445 fp->f_flag |= FASYNC;
446 else
447 fp->f_flag &= ~FASYNC;
448 error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, (caddr_t)&tmp, p);
449 break;
450
451 case FIOSETOWN:
452 tmp = *(int *)data;
453 if (fp->f_type == DTYPE_SOCKET) {
454 ((struct socket *)fp->f_data)->so_pgid = tmp;
455 error = 0;
456 break;
457 }
458 if (tmp <= 0) {
459 tmp = -tmp;
460 } else {
461 struct proc *p1 = pfind(tmp);
462 if (p1 == 0) {
463 error = ESRCH;
464 break;
465 }
466 tmp = p1->p_pgrp->pg_id;
467 }
468 error = (*fp->f_ops->fo_ioctl)
469 (fp, (int)TIOCSPGRP, (caddr_t)&tmp, p);
470 break;
471
472 case FIOGETOWN:
473 if (fp->f_type == DTYPE_SOCKET) {
474 error = 0;
475 *(int *)data = ((struct socket *)fp->f_data)->so_pgid;
476 break;
477 }
478 error = (*fp->f_ops->fo_ioctl)(fp, (int)TIOCGPGRP, data, p);
479 *(int *)data = -*(int *)data;
480 break;
481
482 default:
483 error = (*fp->f_ops->fo_ioctl)(fp, com, data, p);
484 /*
485 * Copy any data to user, size was
486 * already set and checked above.
487 */
488 if (error == 0 && (com&IOC_OUT) && size)
489 error = copyout(data, uap->cmarg, (u_int)size);
490 break;
491 }
492 if (memp)
493 free(memp, M_IOCTLOPS);
494 return (error);
495}
496
497int selwait, nselcoll;
498
499/*
500 * Select system call.
501 */
3c7eb27c
DG
502
503struct select_args {
9e177a2e 504 u_int nd;
15637ed4
RG
505 fd_set *in, *ou, *ex;
506 struct timeval *tv;
3c7eb27c
DG
507};
508
4c45483e 509int
3c7eb27c
DG
510select(p, uap, retval)
511 register struct proc *p;
512 register struct select_args *uap;
15637ed4
RG
513 int *retval;
514{
515 fd_set ibits[3], obits[3];
516 struct timeval atv;
9e177a2e
DG
517 int s, ncoll, error = 0, timo;
518 u_int ni;
15637ed4
RG
519
520 bzero((caddr_t)ibits, sizeof(ibits));
521 bzero((caddr_t)obits, sizeof(obits));
522 if (uap->nd > p->p_fd->fd_nfiles)
523 uap->nd = p->p_fd->fd_nfiles; /* forgiving; slightly wrong */
524 ni = howmany(uap->nd, NFDBITS);
525
526#define getbits(name, x) \
527 if (uap->name) { \
528 error = copyin((caddr_t)uap->name, (caddr_t)&ibits[x], \
529 (unsigned)(ni * sizeof(fd_mask))); \
530 if (error) \
531 goto done; \
532 }
533 getbits(in, 0);
534 getbits(ou, 1);
535 getbits(ex, 2);
536#undef getbits
537
538 if (uap->tv) {
539 error = copyin((caddr_t)uap->tv, (caddr_t)&atv,
540 sizeof (atv));
541 if (error)
542 goto done;
543 if (itimerfix(&atv)) {
544 error = EINVAL;
545 goto done;
546 }
547 s = splhigh(); timevaladd(&atv, &time); splx(s);
548 timo = hzto(&atv);
549 } else
550 timo = 0;
551retry:
552 ncoll = nselcoll;
553 p->p_flag |= SSEL;
554 error = selscan(p, ibits, obits, uap->nd, retval);
555 if (error || *retval)
556 goto done;
557 s = splhigh();
558 /* this should be timercmp(&time, &atv, >=) */
559 if (uap->tv && (time.tv_sec > atv.tv_sec ||
560 time.tv_sec == atv.tv_sec && time.tv_usec >= atv.tv_usec)) {
561 splx(s);
562 goto done;
563 }
564 if ((p->p_flag & SSEL) == 0 || nselcoll != ncoll) {
565 splx(s);
566 goto retry;
567 }
568 p->p_flag &= ~SSEL;
569 error = tsleep((caddr_t)&selwait, PSOCK | PCATCH, "select", timo);
570 splx(s);
571 if (error == 0)
572 goto retry;
573done:
574 p->p_flag &= ~SSEL;
575 /* select is not restarted after signals... */
576 if (error == ERESTART)
577 error = EINTR;
578 if (error == EWOULDBLOCK)
579 error = 0;
580#define putbits(name, x) \
581 if (uap->name) { \
582 int error2 = copyout((caddr_t)&obits[x], (caddr_t)uap->name, \
583 (unsigned)(ni * sizeof(fd_mask))); \
584 if (error2) \
585 error = error2; \
586 }
587 if (error == 0) {
588 putbits(in, 0);
589 putbits(ou, 1);
590 putbits(ex, 2);
591#undef putbits
592 }
593 return (error);
594}
595
596int
597selscan(struct proc *p, fd_set *ibits, fd_set *obits, int nfd, int *retval)
598{
599 register struct filedesc *fdp = p->p_fd;
600 register int which, i, j;
601 register fd_mask bits;
602 int flag;
603 struct file *fp;
604 int error = 0, n = 0;
605
606 for (which = 0; which < 3; which++) {
607 switch (which) {
608
609 case 0:
610 flag = FREAD; break;
611
612 case 1:
613 flag = FWRITE; break;
614
4c45483e 615 default: /* pacify GCC */
15637ed4
RG
616 case 2:
617 flag = 0; break;
618 }
619 for (i = 0; i < nfd; i += NFDBITS) {
620 bits = ibits[which].fds_bits[i/NFDBITS];
621 while ((j = ffs(bits)) && i + --j < nfd) {
622 bits &= ~(1 << j);
623 fp = fdp->fd_ofiles[i + j];
624 if (fp == NULL) {
625 error = EBADF;
626 break;
627 }
628 if ((*fp->f_ops->fo_select)(fp, flag, p)) {
629 FD_SET(i + j, &obits[which]);
630 n++;
631 }
632 }
633 }
634 }
635 *retval = n;
636 return (error);
637}
638
639/*ARGSUSED*/
640int
4c45483e 641seltrue(int /*dev_t*/ dev, int which, struct proc *p)
15637ed4
RG
642{
643
644 return (1);
645}
646
647void
4c45483e 648selwakeup(int /*pid_t*/ pid, int coll)
15637ed4
RG
649{
650 register struct proc *p;
651
652 if (coll) {
653 nselcoll++;
654 wakeup((caddr_t)&selwait);
655 }
656 if (pid && (p = pfind(pid))) {
657 int s = splhigh();
658 if (p->p_wchan == (caddr_t)&selwait) {
659 if (p->p_stat == SSLEEP)
660 setrun(p);
661 else
662 unsleep(p);
663 } else if (p->p_flag & SSEL)
664 p->p_flag &= ~SSEL;
665 splx(s);
666 }
667}