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