Annotation of sys/kern/sys_generic.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: sys_generic.c,v 1.57 2007/07/25 23:11:52 art Exp $ */
! 2: /* $NetBSD: sys_generic.c,v 1.24 1996/03/29 00:25:32 cgd Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 1996 Theo de Raadt
! 6: * Copyright (c) 1982, 1986, 1989, 1993
! 7: * The Regents of the University of California. All rights reserved.
! 8: * (c) UNIX System Laboratories, Inc.
! 9: * All or some portions of this file are derived from material licensed
! 10: * to the University of California by American Telephone and Telegraph
! 11: * Co. or Unix System Laboratories, Inc. and are reproduced herein with
! 12: * the permission of UNIX System Laboratories, Inc.
! 13: *
! 14: * Redistribution and use in source and binary forms, with or without
! 15: * modification, are permitted provided that the following conditions
! 16: * are met:
! 17: * 1. Redistributions of source code must retain the above copyright
! 18: * notice, this list of conditions and the following disclaimer.
! 19: * 2. Redistributions in binary form must reproduce the above copyright
! 20: * notice, this list of conditions and the following disclaimer in the
! 21: * documentation and/or other materials provided with the distribution.
! 22: * 3. Neither the name of the University nor the names of its contributors
! 23: * may be used to endorse or promote products derived from this software
! 24: * without specific prior written permission.
! 25: *
! 26: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 27: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 28: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 29: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 30: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 31: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 32: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 33: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 34: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 35: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 36: * SUCH DAMAGE.
! 37: *
! 38: * @(#)sys_generic.c 8.5 (Berkeley) 1/21/94
! 39: */
! 40:
! 41: #include <sys/param.h>
! 42: #include <sys/systm.h>
! 43: #include <sys/filedesc.h>
! 44: #include <sys/ioctl.h>
! 45: #include <sys/file.h>
! 46: #include <sys/proc.h>
! 47: #include <sys/resourcevar.h>
! 48: #include <sys/socketvar.h>
! 49: #include <sys/signalvar.h>
! 50: #include <sys/uio.h>
! 51: #include <sys/kernel.h>
! 52: #include <sys/stat.h>
! 53: #include <sys/malloc.h>
! 54: #include <sys/poll.h>
! 55: #ifdef KTRACE
! 56: #include <sys/ktrace.h>
! 57: #endif
! 58: #include <sys/sched.h>
! 59:
! 60: #include <sys/mount.h>
! 61: #include <sys/syscallargs.h>
! 62:
! 63: #include <uvm/uvm_extern.h>
! 64:
! 65: int selscan(struct proc *, fd_set *, fd_set *, int, int, register_t *);
! 66: int seltrue(dev_t, int, struct proc *);
! 67: void pollscan(struct proc *, struct pollfd *, u_int, register_t *);
! 68:
! 69: /*
! 70: * Read system call.
! 71: */
! 72: /* ARGSUSED */
! 73: int
! 74: sys_read(struct proc *p, void *v, register_t *retval)
! 75: {
! 76: struct sys_read_args /* {
! 77: syscallarg(int) fd;
! 78: syscallarg(void *) buf;
! 79: syscallarg(size_t) nbyte;
! 80: } */ *uap = v;
! 81: int fd = SCARG(uap, fd);
! 82: struct file *fp;
! 83: struct filedesc *fdp = p->p_fd;
! 84:
! 85: if ((fp = fd_getfile(fdp, fd)) == NULL)
! 86: return (EBADF);
! 87: if ((fp->f_flag & FREAD) == 0)
! 88: return (EBADF);
! 89:
! 90: FREF(fp);
! 91:
! 92: /* dofileread() will FRELE the descriptor for us */
! 93: return (dofileread(p, fd, fp, SCARG(uap, buf), SCARG(uap, nbyte),
! 94: &fp->f_offset, retval));
! 95: }
! 96:
! 97: int
! 98: dofileread(struct proc *p, int fd, struct file *fp, void *buf, size_t nbyte,
! 99: off_t *offset, register_t *retval)
! 100: {
! 101: struct uio auio;
! 102: struct iovec aiov;
! 103: long cnt, error = 0;
! 104: #ifdef KTRACE
! 105: struct iovec ktriov;
! 106: #endif
! 107:
! 108: aiov.iov_base = buf;
! 109: aiov.iov_len = nbyte;
! 110: auio.uio_iov = &aiov;
! 111: auio.uio_iovcnt = 1;
! 112: auio.uio_resid = nbyte;
! 113: auio.uio_rw = UIO_READ;
! 114: auio.uio_segflg = UIO_USERSPACE;
! 115: auio.uio_procp = p;
! 116:
! 117: /*
! 118: * Reads return ssize_t because -1 is returned on error. Therefore
! 119: * we must restrict the length to SSIZE_MAX to avoid garbage return
! 120: * values.
! 121: */
! 122: if (auio.uio_resid > SSIZE_MAX) {
! 123: error = EINVAL;
! 124: goto out;
! 125: }
! 126:
! 127: #ifdef KTRACE
! 128: /*
! 129: * if tracing, save a copy of iovec
! 130: */
! 131: if (KTRPOINT(p, KTR_GENIO))
! 132: ktriov = aiov;
! 133: #endif
! 134: cnt = auio.uio_resid;
! 135: error = (*fp->f_ops->fo_read)(fp, offset, &auio, fp->f_cred);
! 136: if (error)
! 137: if (auio.uio_resid != cnt && (error == ERESTART ||
! 138: error == EINTR || error == EWOULDBLOCK))
! 139: error = 0;
! 140: cnt -= auio.uio_resid;
! 141:
! 142: fp->f_rxfer++;
! 143: fp->f_rbytes += cnt;
! 144: #ifdef KTRACE
! 145: if (KTRPOINT(p, KTR_GENIO) && error == 0)
! 146: ktrgenio(p, fd, UIO_READ, &ktriov, cnt, error);
! 147: #endif
! 148: *retval = cnt;
! 149: out:
! 150: FRELE(fp);
! 151: return (error);
! 152: }
! 153:
! 154: /*
! 155: * Scatter read system call.
! 156: */
! 157: int
! 158: sys_readv(struct proc *p, void *v, register_t *retval)
! 159: {
! 160: struct sys_readv_args /* {
! 161: syscallarg(int) fd;
! 162: syscallarg(const struct iovec *) iovp;
! 163: syscallarg(int) iovcnt;
! 164: } */ *uap = v;
! 165: int fd = SCARG(uap, fd);
! 166: struct file *fp;
! 167: struct filedesc *fdp = p->p_fd;
! 168:
! 169: if ((fp = fd_getfile(fdp, fd)) == NULL)
! 170: return (EBADF);
! 171: if ((fp->f_flag & FREAD) == 0)
! 172: return (EBADF);
! 173:
! 174: FREF(fp);
! 175:
! 176: /* dofilereadv() will FRELE the descriptor for us */
! 177: return (dofilereadv(p, fd, fp, SCARG(uap, iovp), SCARG(uap, iovcnt),
! 178: &fp->f_offset, retval));
! 179: }
! 180:
! 181: int
! 182: dofilereadv(struct proc *p, int fd, struct file *fp, const struct iovec *iovp,
! 183: int iovcnt, off_t *offset, register_t *retval)
! 184: {
! 185: struct uio auio;
! 186: struct iovec *iov;
! 187: struct iovec *needfree;
! 188: struct iovec aiov[UIO_SMALLIOV];
! 189: long i, cnt, error = 0;
! 190: u_int iovlen;
! 191: #ifdef KTRACE
! 192: struct iovec *ktriov = NULL;
! 193: #endif
! 194:
! 195: /* note: can't use iovlen until iovcnt is validated */
! 196: iovlen = iovcnt * sizeof(struct iovec);
! 197: if ((u_int)iovcnt > UIO_SMALLIOV) {
! 198: if ((u_int)iovcnt > IOV_MAX) {
! 199: error = EINVAL;
! 200: goto out;
! 201: }
! 202: iov = needfree = malloc(iovlen, M_IOV, M_WAITOK);
! 203: } else if ((u_int)iovcnt > 0) {
! 204: iov = aiov;
! 205: needfree = NULL;
! 206: } else {
! 207: error = EINVAL;
! 208: goto out;
! 209: }
! 210:
! 211: auio.uio_iov = iov;
! 212: auio.uio_iovcnt = iovcnt;
! 213: auio.uio_rw = UIO_READ;
! 214: auio.uio_segflg = UIO_USERSPACE;
! 215: auio.uio_procp = p;
! 216: error = copyin(iovp, iov, iovlen);
! 217: if (error)
! 218: goto done;
! 219: auio.uio_resid = 0;
! 220: for (i = 0; i < iovcnt; i++) {
! 221: auio.uio_resid += iov->iov_len;
! 222: /*
! 223: * Reads return ssize_t because -1 is returned on error.
! 224: * Therefore we must restrict the length to SSIZE_MAX to
! 225: * avoid garbage return values.
! 226: */
! 227: if (iov->iov_len > SSIZE_MAX || auio.uio_resid > SSIZE_MAX) {
! 228: error = EINVAL;
! 229: goto done;
! 230: }
! 231: iov++;
! 232: }
! 233: #ifdef KTRACE
! 234: /*
! 235: * if tracing, save a copy of iovec
! 236: */
! 237: if (KTRPOINT(p, KTR_GENIO)) {
! 238: ktriov = malloc(iovlen, M_TEMP, M_WAITOK);
! 239: bcopy(auio.uio_iov, ktriov, iovlen);
! 240: }
! 241: #endif
! 242: cnt = auio.uio_resid;
! 243: error = (*fp->f_ops->fo_read)(fp, offset, &auio, fp->f_cred);
! 244: if (error)
! 245: if (auio.uio_resid != cnt && (error == ERESTART ||
! 246: error == EINTR || error == EWOULDBLOCK))
! 247: error = 0;
! 248: cnt -= auio.uio_resid;
! 249:
! 250: fp->f_rxfer++;
! 251: fp->f_rbytes += cnt;
! 252: #ifdef KTRACE
! 253: if (ktriov != NULL) {
! 254: if (error == 0)
! 255: ktrgenio(p, fd, UIO_READ, ktriov, cnt,
! 256: error);
! 257: free(ktriov, M_TEMP);
! 258: }
! 259: #endif
! 260: *retval = cnt;
! 261: done:
! 262: if (needfree)
! 263: free(needfree, M_IOV);
! 264: out:
! 265: FRELE(fp);
! 266: return (error);
! 267: }
! 268:
! 269: /*
! 270: * Write system call
! 271: */
! 272: int
! 273: sys_write(struct proc *p, void *v, register_t *retval)
! 274: {
! 275: struct sys_write_args /* {
! 276: syscallarg(int) fd;
! 277: syscallarg(const void *) buf;
! 278: syscallarg(size_t) nbyte;
! 279: } */ *uap = v;
! 280: int fd = SCARG(uap, fd);
! 281: struct file *fp;
! 282: struct filedesc *fdp = p->p_fd;
! 283:
! 284: if ((fp = fd_getfile(fdp, fd)) == NULL)
! 285: return (EBADF);
! 286: if ((fp->f_flag & FWRITE) == 0)
! 287: return (EBADF);
! 288:
! 289: FREF(fp);
! 290:
! 291: /* dofilewrite() will FRELE the descriptor for us */
! 292: return (dofilewrite(p, fd, fp, SCARG(uap, buf), SCARG(uap, nbyte),
! 293: &fp->f_offset, retval));
! 294: }
! 295:
! 296: int
! 297: dofilewrite(struct proc *p, int fd, struct file *fp, const void *buf,
! 298: size_t nbyte, off_t *offset, register_t *retval)
! 299: {
! 300: struct uio auio;
! 301: struct iovec aiov;
! 302: long cnt, error = 0;
! 303: #ifdef KTRACE
! 304: struct iovec ktriov;
! 305: #endif
! 306:
! 307: aiov.iov_base = (void *)buf; /* XXX kills const */
! 308: aiov.iov_len = nbyte;
! 309: auio.uio_iov = &aiov;
! 310: auio.uio_iovcnt = 1;
! 311: auio.uio_resid = nbyte;
! 312: auio.uio_rw = UIO_WRITE;
! 313: auio.uio_segflg = UIO_USERSPACE;
! 314: auio.uio_procp = p;
! 315:
! 316: /*
! 317: * Writes return ssize_t because -1 is returned on error. Therefore
! 318: * we must restrict the length to SSIZE_MAX to avoid garbage return
! 319: * values.
! 320: */
! 321: if (auio.uio_resid > SSIZE_MAX) {
! 322: error = EINVAL;
! 323: goto out;
! 324: }
! 325:
! 326: #ifdef KTRACE
! 327: /*
! 328: * if tracing, save a copy of iovec
! 329: */
! 330: if (KTRPOINT(p, KTR_GENIO))
! 331: ktriov = aiov;
! 332: #endif
! 333: cnt = auio.uio_resid;
! 334: error = (*fp->f_ops->fo_write)(fp, offset, &auio, fp->f_cred);
! 335: if (error) {
! 336: if (auio.uio_resid != cnt && (error == ERESTART ||
! 337: error == EINTR || error == EWOULDBLOCK))
! 338: error = 0;
! 339: if (error == EPIPE)
! 340: psignal(p, SIGPIPE);
! 341: }
! 342: cnt -= auio.uio_resid;
! 343:
! 344: fp->f_wxfer++;
! 345: fp->f_wbytes += cnt;
! 346: #ifdef KTRACE
! 347: if (KTRPOINT(p, KTR_GENIO) && error == 0)
! 348: ktrgenio(p, fd, UIO_WRITE, &ktriov, cnt, error);
! 349: #endif
! 350: *retval = cnt;
! 351: out:
! 352: FRELE(fp);
! 353: return (error);
! 354: }
! 355:
! 356: /*
! 357: * Gather write system call
! 358: */
! 359: int
! 360: sys_writev(struct proc *p, void *v, register_t *retval)
! 361: {
! 362: struct sys_writev_args /* {
! 363: syscallarg(int) fd;
! 364: syscallarg(const struct iovec *) iovp;
! 365: syscallarg(int) iovcnt;
! 366: } */ *uap = v;
! 367: int fd = SCARG(uap, fd);
! 368: struct file *fp;
! 369: struct filedesc *fdp = p->p_fd;
! 370:
! 371: if ((fp = fd_getfile(fdp, fd)) == NULL)
! 372: return (EBADF);
! 373: if ((fp->f_flag & FWRITE) == 0)
! 374: return (EBADF);
! 375:
! 376: FREF(fp);
! 377:
! 378: /* dofilewritev() will FRELE the descriptor for us */
! 379: return (dofilewritev(p, fd, fp, SCARG(uap, iovp), SCARG(uap, iovcnt),
! 380: &fp->f_offset, retval));
! 381: }
! 382:
! 383: int
! 384: dofilewritev(struct proc *p, int fd, struct file *fp, const struct iovec *iovp,
! 385: int iovcnt, off_t *offset, register_t *retval)
! 386: {
! 387: struct uio auio;
! 388: struct iovec *iov;
! 389: struct iovec *needfree;
! 390: struct iovec aiov[UIO_SMALLIOV];
! 391: long i, cnt, error = 0;
! 392: u_int iovlen;
! 393: #ifdef KTRACE
! 394: struct iovec *ktriov = NULL;
! 395: #endif
! 396:
! 397: /* note: can't use iovlen until iovcnt is validated */
! 398: iovlen = iovcnt * sizeof(struct iovec);
! 399: if ((u_int)iovcnt > UIO_SMALLIOV) {
! 400: if ((u_int)iovcnt > IOV_MAX) {
! 401: error = EINVAL;
! 402: goto out;
! 403: }
! 404: iov = needfree = malloc(iovlen, M_IOV, M_WAITOK);
! 405: } else if ((u_int)iovcnt > 0) {
! 406: iov = aiov;
! 407: needfree = NULL;
! 408: } else {
! 409: error = EINVAL;
! 410: goto out;
! 411: }
! 412:
! 413: auio.uio_iov = iov;
! 414: auio.uio_iovcnt = iovcnt;
! 415: auio.uio_rw = UIO_WRITE;
! 416: auio.uio_segflg = UIO_USERSPACE;
! 417: auio.uio_procp = p;
! 418: error = copyin(iovp, iov, iovlen);
! 419: if (error)
! 420: goto done;
! 421: auio.uio_resid = 0;
! 422: for (i = 0; i < iovcnt; i++) {
! 423: auio.uio_resid += iov->iov_len;
! 424: /*
! 425: * Writes return ssize_t because -1 is returned on error.
! 426: * Therefore we must restrict the length to SSIZE_MAX to
! 427: * avoid garbage return values.
! 428: */
! 429: if (iov->iov_len > SSIZE_MAX || auio.uio_resid > SSIZE_MAX) {
! 430: error = EINVAL;
! 431: goto done;
! 432: }
! 433: iov++;
! 434: }
! 435: #ifdef KTRACE
! 436: /*
! 437: * if tracing, save a copy of iovec
! 438: */
! 439: if (KTRPOINT(p, KTR_GENIO)) {
! 440: ktriov = malloc(iovlen, M_TEMP, M_WAITOK);
! 441: bcopy(auio.uio_iov, ktriov, iovlen);
! 442: }
! 443: #endif
! 444: cnt = auio.uio_resid;
! 445: error = (*fp->f_ops->fo_write)(fp, offset, &auio, fp->f_cred);
! 446: if (error) {
! 447: if (auio.uio_resid != cnt && (error == ERESTART ||
! 448: error == EINTR || error == EWOULDBLOCK))
! 449: error = 0;
! 450: if (error == EPIPE)
! 451: psignal(p, SIGPIPE);
! 452: }
! 453: cnt -= auio.uio_resid;
! 454:
! 455: fp->f_wxfer++;
! 456: fp->f_wbytes += cnt;
! 457: #ifdef KTRACE
! 458: if (ktriov != NULL) {
! 459: if (error == 0)
! 460: ktrgenio(p, fd, UIO_WRITE, ktriov, cnt, error);
! 461: free(ktriov, M_TEMP);
! 462: }
! 463: #endif
! 464: *retval = cnt;
! 465: done:
! 466: if (needfree)
! 467: free(needfree, M_IOV);
! 468: out:
! 469: FRELE(fp);
! 470: return (error);
! 471: }
! 472:
! 473: /*
! 474: * Ioctl system call
! 475: */
! 476: /* ARGSUSED */
! 477: int
! 478: sys_ioctl(struct proc *p, void *v, register_t *retval)
! 479: {
! 480: struct sys_ioctl_args /* {
! 481: syscallarg(int) fd;
! 482: syscallarg(u_long) com;
! 483: syscallarg(void *) data;
! 484: } */ *uap = v;
! 485: struct file *fp;
! 486: struct filedesc *fdp;
! 487: u_long com;
! 488: int error;
! 489: u_int size;
! 490: caddr_t data, memp;
! 491: int tmp;
! 492: #define STK_PARAMS 128
! 493: char stkbuf[STK_PARAMS];
! 494:
! 495: fdp = p->p_fd;
! 496: if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL)
! 497: return (EBADF);
! 498:
! 499: if ((fp->f_flag & (FREAD | FWRITE)) == 0)
! 500: return (EBADF);
! 501:
! 502: switch (com = SCARG(uap, com)) {
! 503: case FIONCLEX:
! 504: fdp->fd_ofileflags[SCARG(uap, fd)] &= ~UF_EXCLOSE;
! 505: return (0);
! 506: case FIOCLEX:
! 507: fdp->fd_ofileflags[SCARG(uap, fd)] |= UF_EXCLOSE;
! 508: return (0);
! 509: }
! 510:
! 511: /*
! 512: * Interpret high order word to find amount of data to be
! 513: * copied to/from the user's address space.
! 514: */
! 515: size = IOCPARM_LEN(com);
! 516: if (size > IOCPARM_MAX)
! 517: return (ENOTTY);
! 518: FREF(fp);
! 519: memp = NULL;
! 520: if (size > sizeof (stkbuf)) {
! 521: memp = (caddr_t)malloc((u_long)size, M_IOCTLOPS, M_WAITOK);
! 522: data = memp;
! 523: } else
! 524: data = stkbuf;
! 525: if (com&IOC_IN) {
! 526: if (size) {
! 527: error = copyin(SCARG(uap, data), data, (u_int)size);
! 528: if (error) {
! 529: goto out;
! 530: }
! 531: } else
! 532: *(caddr_t *)data = SCARG(uap, data);
! 533: } else if ((com&IOC_OUT) && size)
! 534: /*
! 535: * Zero the buffer so the user always
! 536: * gets back something deterministic.
! 537: */
! 538: bzero(data, size);
! 539: else if (com&IOC_VOID)
! 540: *(caddr_t *)data = SCARG(uap, data);
! 541:
! 542: switch (com) {
! 543:
! 544: case FIONBIO:
! 545: if ((tmp = *(int *)data) != 0)
! 546: fp->f_flag |= FNONBLOCK;
! 547: else
! 548: fp->f_flag &= ~FNONBLOCK;
! 549: error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p);
! 550: break;
! 551:
! 552: case FIOASYNC:
! 553: if ((tmp = *(int *)data) != 0)
! 554: fp->f_flag |= FASYNC;
! 555: else
! 556: fp->f_flag &= ~FASYNC;
! 557: error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, (caddr_t)&tmp, p);
! 558: break;
! 559:
! 560: case FIOSETOWN:
! 561: tmp = *(int *)data;
! 562: if (fp->f_type == DTYPE_SOCKET) {
! 563: struct socket *so = (struct socket *)fp->f_data;
! 564:
! 565: so->so_pgid = tmp;
! 566: so->so_siguid = p->p_cred->p_ruid;
! 567: so->so_sigeuid = p->p_ucred->cr_uid;
! 568: error = 0;
! 569: break;
! 570: }
! 571: if (tmp <= 0) {
! 572: tmp = -tmp;
! 573: } else {
! 574: struct proc *p1 = pfind(tmp);
! 575: if (p1 == 0) {
! 576: error = ESRCH;
! 577: break;
! 578: }
! 579: tmp = p1->p_pgrp->pg_id;
! 580: }
! 581: error = (*fp->f_ops->fo_ioctl)
! 582: (fp, TIOCSPGRP, (caddr_t)&tmp, p);
! 583: break;
! 584:
! 585: case FIOGETOWN:
! 586: if (fp->f_type == DTYPE_SOCKET) {
! 587: error = 0;
! 588: *(int *)data = ((struct socket *)fp->f_data)->so_pgid;
! 589: break;
! 590: }
! 591: error = (*fp->f_ops->fo_ioctl)(fp, TIOCGPGRP, data, p);
! 592: *(int *)data = -*(int *)data;
! 593: break;
! 594:
! 595: default:
! 596: error = (*fp->f_ops->fo_ioctl)(fp, com, data, p);
! 597: break;
! 598: }
! 599: /*
! 600: * Copy any data to user, size was
! 601: * already set and checked above.
! 602: */
! 603: if (error == 0 && (com&IOC_OUT) && size)
! 604: error = copyout(data, SCARG(uap, data), (u_int)size);
! 605: out:
! 606: FRELE(fp);
! 607: if (memp)
! 608: free(memp, M_IOCTLOPS);
! 609: return (error);
! 610: }
! 611:
! 612: int selwait, nselcoll;
! 613:
! 614: /*
! 615: * Select system call.
! 616: */
! 617: int
! 618: sys_select(struct proc *p, void *v, register_t *retval)
! 619: {
! 620: struct sys_select_args /* {
! 621: syscallarg(int) nd;
! 622: syscallarg(fd_set *) in;
! 623: syscallarg(fd_set *) ou;
! 624: syscallarg(fd_set *) ex;
! 625: syscallarg(struct timeval *) tv;
! 626: } */ *uap = v;
! 627: fd_mask bits[6];
! 628: fd_set *pibits[3], *pobits[3];
! 629: struct timeval atv, rtv, ttv;
! 630: int s, ncoll, error = 0, timo;
! 631: u_int nd, ni;
! 632:
! 633: nd = SCARG(uap, nd);
! 634: if (nd > p->p_fd->fd_nfiles) {
! 635: /* forgiving; slightly wrong */
! 636: nd = p->p_fd->fd_nfiles;
! 637: }
! 638: ni = howmany(nd, NFDBITS) * sizeof(fd_mask);
! 639: if (nd > sizeof(bits[0])) {
! 640: caddr_t mbits;
! 641:
! 642: mbits = malloc(ni * 6, M_TEMP, M_WAITOK);
! 643: bzero(mbits, ni * 6);
! 644: pibits[0] = (fd_set *)&mbits[ni * 0];
! 645: pibits[1] = (fd_set *)&mbits[ni * 1];
! 646: pibits[2] = (fd_set *)&mbits[ni * 2];
! 647: pobits[0] = (fd_set *)&mbits[ni * 3];
! 648: pobits[1] = (fd_set *)&mbits[ni * 4];
! 649: pobits[2] = (fd_set *)&mbits[ni * 5];
! 650: } else {
! 651: bzero(bits, sizeof(bits));
! 652: pibits[0] = (fd_set *)&bits[0];
! 653: pibits[1] = (fd_set *)&bits[1];
! 654: pibits[2] = (fd_set *)&bits[2];
! 655: pobits[0] = (fd_set *)&bits[3];
! 656: pobits[1] = (fd_set *)&bits[4];
! 657: pobits[2] = (fd_set *)&bits[5];
! 658: }
! 659:
! 660: #define getbits(name, x) \
! 661: if (SCARG(uap, name) && (error = copyin(SCARG(uap, name), \
! 662: pibits[x], ni))) \
! 663: goto done;
! 664: getbits(in, 0);
! 665: getbits(ou, 1);
! 666: getbits(ex, 2);
! 667: #undef getbits
! 668:
! 669: if (SCARG(uap, tv)) {
! 670: error = copyin(SCARG(uap, tv), &atv, sizeof (atv));
! 671: if (error)
! 672: goto done;
! 673: if (itimerfix(&atv)) {
! 674: error = EINVAL;
! 675: goto done;
! 676: }
! 677: getmicrouptime(&rtv);
! 678: timeradd(&atv, &rtv, &atv);
! 679: } else {
! 680: atv.tv_sec = 0;
! 681: atv.tv_usec = 0;
! 682: }
! 683: timo = 0;
! 684:
! 685: retry:
! 686: ncoll = nselcoll;
! 687: atomic_setbits_int(&p->p_flag, P_SELECT);
! 688: error = selscan(p, pibits[0], pobits[0], nd, ni, retval);
! 689: if (error || *retval)
! 690: goto done;
! 691: if (SCARG(uap, tv)) {
! 692: getmicrouptime(&rtv);
! 693: if (timercmp(&rtv, &atv, >=))
! 694: goto done;
! 695: ttv = atv;
! 696: timersub(&ttv, &rtv, &ttv);
! 697: timo = ttv.tv_sec > 24 * 60 * 60 ?
! 698: 24 * 60 * 60 * hz : tvtohz(&ttv);
! 699: }
! 700: s = splhigh();
! 701: if ((p->p_flag & P_SELECT) == 0 || nselcoll != ncoll) {
! 702: splx(s);
! 703: goto retry;
! 704: }
! 705: atomic_clearbits_int(&p->p_flag, P_SELECT);
! 706: error = tsleep(&selwait, PSOCK | PCATCH, "select", timo);
! 707: splx(s);
! 708: if (error == 0)
! 709: goto retry;
! 710: done:
! 711: atomic_clearbits_int(&p->p_flag, P_SELECT);
! 712: /* select is not restarted after signals... */
! 713: if (error == ERESTART)
! 714: error = EINTR;
! 715: if (error == EWOULDBLOCK)
! 716: error = 0;
! 717: #define putbits(name, x) \
! 718: if (SCARG(uap, name) && (error2 = copyout(pobits[x], \
! 719: SCARG(uap, name), ni))) \
! 720: error = error2;
! 721: if (error == 0) {
! 722: int error2;
! 723:
! 724: putbits(in, 0);
! 725: putbits(ou, 1);
! 726: putbits(ex, 2);
! 727: #undef putbits
! 728: }
! 729:
! 730: if (pibits[0] != (fd_set *)&bits[0])
! 731: free(pibits[0], M_TEMP);
! 732: return (error);
! 733: }
! 734:
! 735: int
! 736: selscan(struct proc *p, fd_set *ibits, fd_set *obits, int nfd, int ni,
! 737: register_t *retval)
! 738: {
! 739: caddr_t cibits = (caddr_t)ibits, cobits = (caddr_t)obits;
! 740: struct filedesc *fdp = p->p_fd;
! 741: int msk, i, j, fd;
! 742: fd_mask bits;
! 743: struct file *fp;
! 744: int n = 0;
! 745: static const int flag[3] = { POLLIN, POLLOUT, POLLPRI };
! 746:
! 747: for (msk = 0; msk < 3; msk++) {
! 748: fd_set *pibits = (fd_set *)&cibits[msk*ni];
! 749: fd_set *pobits = (fd_set *)&cobits[msk*ni];
! 750:
! 751: for (i = 0; i < nfd; i += NFDBITS) {
! 752: bits = pibits->fds_bits[i/NFDBITS];
! 753: while ((j = ffs(bits)) && (fd = i + --j) < nfd) {
! 754: bits &= ~(1 << j);
! 755: if ((fp = fd_getfile(fdp, fd)) == NULL)
! 756: return (EBADF);
! 757: FREF(fp);
! 758: if ((*fp->f_ops->fo_poll)(fp, flag[msk], p)) {
! 759: FD_SET(fd, pobits);
! 760: n++;
! 761: }
! 762: FRELE(fp);
! 763: }
! 764: }
! 765: }
! 766: *retval = n;
! 767: return (0);
! 768: }
! 769:
! 770: /*ARGSUSED*/
! 771: int
! 772: seltrue(dev_t dev, int events, struct proc *p)
! 773: {
! 774:
! 775: return (events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM));
! 776: }
! 777:
! 778: /*
! 779: * Record a select request.
! 780: */
! 781: void
! 782: selrecord(struct proc *selector, struct selinfo *sip)
! 783: {
! 784: struct proc *p;
! 785: pid_t mypid;
! 786:
! 787: mypid = selector->p_pid;
! 788: if (sip->si_selpid == mypid)
! 789: return;
! 790: if (sip->si_selpid && (p = pfind(sip->si_selpid)) &&
! 791: p->p_wchan == (caddr_t)&selwait)
! 792: sip->si_flags |= SI_COLL;
! 793: else
! 794: sip->si_selpid = mypid;
! 795: }
! 796:
! 797: /*
! 798: * Do a wakeup when a selectable event occurs.
! 799: */
! 800: void
! 801: selwakeup(struct selinfo *sip)
! 802: {
! 803: struct proc *p;
! 804: int s;
! 805:
! 806: if (sip->si_selpid == 0)
! 807: return;
! 808: if (sip->si_flags & SI_COLL) {
! 809: nselcoll++;
! 810: sip->si_flags &= ~SI_COLL;
! 811: wakeup(&selwait);
! 812: }
! 813: p = pfind(sip->si_selpid);
! 814: sip->si_selpid = 0;
! 815: if (p != NULL) {
! 816: SCHED_LOCK(s);
! 817: if (p->p_wchan == (caddr_t)&selwait) {
! 818: if (p->p_stat == SSLEEP)
! 819: setrunnable(p);
! 820: else
! 821: unsleep(p);
! 822: } else if (p->p_flag & P_SELECT)
! 823: atomic_clearbits_int(&p->p_flag, P_SELECT);
! 824: SCHED_UNLOCK(s);
! 825: }
! 826: }
! 827:
! 828: void
! 829: pollscan(struct proc *p, struct pollfd *pl, u_int nfd, register_t *retval)
! 830: {
! 831: struct filedesc *fdp = p->p_fd;
! 832: struct file *fp;
! 833: u_int i;
! 834: int n = 0;
! 835:
! 836: for (i = 0; i < nfd; i++, pl++) {
! 837: /* Check the file descriptor. */
! 838: if (pl->fd < 0) {
! 839: pl->revents = 0;
! 840: continue;
! 841: }
! 842: if ((fp = fd_getfile(fdp, pl->fd)) == NULL) {
! 843: pl->revents = POLLNVAL;
! 844: n++;
! 845: continue;
! 846: }
! 847: FREF(fp);
! 848: pl->revents = (*fp->f_ops->fo_poll)(fp, pl->events, p);
! 849: FRELE(fp);
! 850: if (pl->revents != 0)
! 851: n++;
! 852: }
! 853: *retval = n;
! 854: }
! 855:
! 856: /*
! 857: * We are using the same mechanism as select only we encode/decode args
! 858: * differently.
! 859: */
! 860: int
! 861: sys_poll(struct proc *p, void *v, register_t *retval)
! 862: {
! 863: struct sys_poll_args /* {
! 864: syscallarg(struct pollfd *) fds;
! 865: syscallarg(u_int) nfds;
! 866: syscallarg(int) timeout;
! 867: } */ *uap = v;
! 868: size_t sz;
! 869: struct pollfd pfds[4], *pl = pfds;
! 870: int msec = SCARG(uap, timeout);
! 871: struct timeval atv, rtv, ttv;
! 872: int timo, ncoll, i, s, error;
! 873: extern int nselcoll, selwait;
! 874: u_int nfds = SCARG(uap, nfds);
! 875:
! 876: /* Standards say no more than MAX_OPEN; this is possibly better. */
! 877: if (nfds > min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfiles))
! 878: return (EINVAL);
! 879:
! 880: sz = sizeof(struct pollfd) * nfds;
! 881:
! 882: /* optimize for the default case, of a small nfds value */
! 883: if (sz > sizeof(pfds))
! 884: pl = (struct pollfd *) malloc(sz, M_TEMP, M_WAITOK);
! 885:
! 886: if ((error = copyin(SCARG(uap, fds), pl, sz)) != 0)
! 887: goto bad;
! 888:
! 889: for (i = 0; i < nfds; i++)
! 890: pl[i].revents = 0;
! 891:
! 892: if (msec != INFTIM) {
! 893: atv.tv_sec = msec / 1000;
! 894: atv.tv_usec = (msec - (atv.tv_sec * 1000)) * 1000;
! 895:
! 896: if (itimerfix(&atv)) {
! 897: error = EINVAL;
! 898: goto done;
! 899: }
! 900: getmicrouptime(&rtv);
! 901: timeradd(&atv, &rtv, &atv);
! 902: } else {
! 903: atv.tv_sec = 0;
! 904: atv.tv_usec = 0;
! 905: }
! 906: timo = 0;
! 907:
! 908: retry:
! 909: ncoll = nselcoll;
! 910: atomic_setbits_int(&p->p_flag, P_SELECT);
! 911: pollscan(p, pl, nfds, retval);
! 912: if (*retval)
! 913: goto done;
! 914: if (msec != INFTIM) {
! 915: getmicrouptime(&rtv);
! 916: if (timercmp(&rtv, &atv, >=))
! 917: goto done;
! 918: ttv = atv;
! 919: timersub(&ttv, &rtv, &ttv);
! 920: timo = ttv.tv_sec > 24 * 60 * 60 ?
! 921: 24 * 60 * 60 * hz : tvtohz(&ttv);
! 922: }
! 923: s = splhigh();
! 924: if ((p->p_flag & P_SELECT) == 0 || nselcoll != ncoll) {
! 925: splx(s);
! 926: goto retry;
! 927: }
! 928: atomic_clearbits_int(&p->p_flag, P_SELECT);
! 929: error = tsleep(&selwait, PSOCK | PCATCH, "poll", timo);
! 930: splx(s);
! 931: if (error == 0)
! 932: goto retry;
! 933:
! 934: done:
! 935: atomic_clearbits_int(&p->p_flag, P_SELECT);
! 936: /*
! 937: * NOTE: poll(2) is not restarted after a signal and EWOULDBLOCK is
! 938: * ignored (since the whole point is to see what would block).
! 939: */
! 940: switch (error) {
! 941: case ERESTART:
! 942: error = copyout(pl, SCARG(uap, fds), sz);
! 943: if (error == 0)
! 944: error = EINTR;
! 945: break;
! 946: case EWOULDBLOCK:
! 947: case 0:
! 948: error = copyout(pl, SCARG(uap, fds), sz);
! 949: break;
! 950: }
! 951: bad:
! 952: if (pl != pfds)
! 953: free(pl, M_TEMP);
! 954: return (error);
! 955: }
CVSweb