123384Smckusick /* 223384Smckusick * Copyright (c) 1982 Regents of the University of California. 323384Smckusick * All rights reserved. The Berkeley software License Agreement 423384Smckusick * specifies the terms and conditions for redistribution. 523384Smckusick * 6*26070Skarels * @(#)sys_generic.c 6.13 (Berkeley) 02/04/86 723384Smckusick */ 87423Sroot 917094Sbloom #include "param.h" 1017094Sbloom #include "systm.h" 1117094Sbloom #include "dir.h" 1217094Sbloom #include "user.h" 1317094Sbloom #include "ioctl.h" 1417094Sbloom #include "file.h" 1517094Sbloom #include "proc.h" 1617094Sbloom #include "uio.h" 1717094Sbloom #include "kernel.h" 1817094Sbloom #include "stat.h" 197423Sroot 207423Sroot /* 217423Sroot * Read system call. 227423Sroot */ 237423Sroot read() 247423Sroot { 257423Sroot register struct a { 267423Sroot int fdes; 277423Sroot char *cbuf; 287423Sroot unsigned count; 297820Sroot } *uap = (struct a *)u.u_ap; 307746Sroot struct uio auio; 317746Sroot struct iovec aiov; 327423Sroot 337820Sroot aiov.iov_base = (caddr_t)uap->cbuf; 347820Sroot aiov.iov_len = uap->count; 357820Sroot auio.uio_iov = &aiov; 367820Sroot auio.uio_iovcnt = 1; 377820Sroot rwuio(&auio, UIO_READ); 387820Sroot } 397820Sroot 407820Sroot readv() 417820Sroot { 427820Sroot register struct a { 437820Sroot int fdes; 447820Sroot struct iovec *iovp; 457820Sroot int iovcnt; 467820Sroot } *uap = (struct a *)u.u_ap; 477820Sroot struct uio auio; 487820Sroot struct iovec aiov[16]; /* XXX */ 497820Sroot 507820Sroot if (uap->iovcnt <= 0 || uap->iovcnt > sizeof(aiov)/sizeof(aiov[0])) { 517423Sroot u.u_error = EINVAL; 527423Sroot return; 537423Sroot } 547820Sroot auio.uio_iov = aiov; 557820Sroot auio.uio_iovcnt = uap->iovcnt; 569999Ssam u.u_error = copyin((caddr_t)uap->iovp, (caddr_t)aiov, 579999Ssam (unsigned)(uap->iovcnt * sizeof (struct iovec))); 589999Ssam if (u.u_error) 597423Sroot return; 607820Sroot rwuio(&auio, UIO_READ); 617423Sroot } 627423Sroot 637423Sroot /* 647423Sroot * Write system call 657423Sroot */ 667423Sroot write() 677423Sroot { 687423Sroot register struct a { 697423Sroot int fdes; 707423Sroot char *cbuf; 717820Sroot int count; 727820Sroot } *uap = (struct a *)u.u_ap; 737820Sroot struct uio auio; 747820Sroot struct iovec aiov; 757423Sroot 767820Sroot auio.uio_iov = &aiov; 777820Sroot auio.uio_iovcnt = 1; 787820Sroot aiov.iov_base = uap->cbuf; 797820Sroot aiov.iov_len = uap->count; 807820Sroot rwuio(&auio, UIO_WRITE); 817820Sroot } 827820Sroot 837820Sroot writev() 847820Sroot { 857820Sroot register struct a { 867820Sroot int fdes; 877820Sroot struct iovec *iovp; 887820Sroot int iovcnt; 897820Sroot } *uap = (struct a *)u.u_ap; 907820Sroot struct uio auio; 917820Sroot struct iovec aiov[16]; /* XXX */ 927820Sroot 937820Sroot if (uap->iovcnt <= 0 || uap->iovcnt > sizeof(aiov)/sizeof(aiov[0])) { 947423Sroot u.u_error = EINVAL; 957423Sroot return; 967423Sroot } 977820Sroot auio.uio_iov = aiov; 987820Sroot auio.uio_iovcnt = uap->iovcnt; 999999Ssam u.u_error = copyin((caddr_t)uap->iovp, (caddr_t)aiov, 1009999Ssam (unsigned)(uap->iovcnt * sizeof (struct iovec))); 1019999Ssam if (u.u_error) 1027820Sroot return; 1037820Sroot rwuio(&auio, UIO_WRITE); 1047820Sroot } 1057820Sroot 1067820Sroot rwuio(uio, rw) 1077820Sroot register struct uio *uio; 1087820Sroot enum uio_rw rw; 1097820Sroot { 1107820Sroot struct a { 1117820Sroot int fdes; 1127820Sroot }; 1137820Sroot register struct file *fp; 1147820Sroot register struct iovec *iov; 1157820Sroot int i, count; 1167820Sroot 1177820Sroot GETF(fp, ((struct a *)u.u_ap)->fdes); 1187820Sroot if ((fp->f_flag&(rw==UIO_READ ? FREAD : FWRITE)) == 0) { 1197423Sroot u.u_error = EBADF; 1207423Sroot return; 1217423Sroot } 1227820Sroot uio->uio_resid = 0; 12316702Smckusick uio->uio_segflg = UIO_USERSPACE; 1247820Sroot iov = uio->uio_iov; 1257820Sroot for (i = 0; i < uio->uio_iovcnt; i++) { 1267820Sroot if (iov->iov_len < 0) { 1277820Sroot u.u_error = EINVAL; 1287820Sroot return; 1297820Sroot } 1307820Sroot uio->uio_resid += iov->iov_len; 1317820Sroot if (uio->uio_resid < 0) { 1327820Sroot u.u_error = EINVAL; 1337820Sroot return; 1347820Sroot } 13513270Ssam iov++; 1367820Sroot } 1377820Sroot count = uio->uio_resid; 13812751Ssam uio->uio_offset = fp->f_offset; 13918309Smckusick if (setjmp(&u.u_qsave)) { 14018309Smckusick if (uio->uio_resid == count) { 14121009Smckusick if ((u.u_sigintr & sigmask(u.u_procp->p_cursig)) != 0) 14218309Smckusick u.u_error = EINTR; 14318309Smckusick else 14418309Smckusick u.u_eosys = RESTARTSYS; 14518309Smckusick } 14612751Ssam } else 14712751Ssam u.u_error = (*fp->f_ops->fo_rw)(fp, rw, uio); 1487820Sroot u.u_r.r_val1 = count - uio->uio_resid; 14912751Ssam fp->f_offset += u.u_r.r_val1; 1507423Sroot } 1517423Sroot 1527423Sroot /* 1537423Sroot * Ioctl system call 1547423Sroot */ 1557423Sroot ioctl() 1567423Sroot { 1577423Sroot register struct file *fp; 1587624Ssam struct a { 1597423Sroot int fdes; 1607423Sroot int cmd; 1617423Sroot caddr_t cmarg; 1627423Sroot } *uap; 1637820Sroot register int com; 1647820Sroot register u_int size; 1657624Ssam char data[IOCPARM_MASK+1]; 1667423Sroot 1677423Sroot uap = (struct a *)u.u_ap; 16817004Smckusick GETF(fp, uap->fdes); 1697423Sroot if ((fp->f_flag & (FREAD|FWRITE)) == 0) { 1707423Sroot u.u_error = EBADF; 1717423Sroot return; 1727423Sroot } 1737624Ssam com = uap->cmd; 1747624Ssam 17513228Ssam #if defined(vax) && defined(COMPAT) 1767624Ssam /* 1777624Ssam * Map old style ioctl's into new for the 1787624Ssam * sake of backwards compatibility (sigh). 1797624Ssam */ 1807624Ssam if ((com&~0xffff) == 0) { 1817624Ssam com = mapioctl(com); 1827624Ssam if (com == 0) { 1837624Ssam u.u_error = EINVAL; 1847624Ssam return; 1857624Ssam } 1867624Ssam } 1877624Ssam #endif 1887624Ssam if (com == FIOCLEX) { 1899592Ssam u.u_pofile[uap->fdes] |= UF_EXCLOSE; 1907423Sroot return; 1917423Sroot } 1927624Ssam if (com == FIONCLEX) { 1939592Ssam u.u_pofile[uap->fdes] &= ~UF_EXCLOSE; 1947423Sroot return; 1957423Sroot } 1967624Ssam 1977624Ssam /* 1987624Ssam * Interpret high order word to find 1997624Ssam * amount of data to be copied to/from the 2007624Ssam * user's address space. 2017624Ssam */ 2027624Ssam size = (com &~ (IOC_INOUT|IOC_VOID)) >> 16; 2037624Ssam if (size > sizeof (data)) { 2047624Ssam u.u_error = EFAULT; 2057423Sroot return; 2067423Sroot } 20710601Ssam if (com&IOC_IN) { 20810601Ssam if (size) { 20910601Ssam u.u_error = 21010601Ssam copyin(uap->cmarg, (caddr_t)data, (u_int)size); 21110601Ssam if (u.u_error) 21210601Ssam return; 21310601Ssam } else 21410601Ssam *(caddr_t *)data = uap->cmarg; 21510601Ssam } else if ((com&IOC_OUT) && size) 21610601Ssam /* 21710601Ssam * Zero the buffer on the stack so the user 21810601Ssam * always gets back something deterministic. 21910601Ssam */ 2207624Ssam bzero((caddr_t)data, size); 22111284Ssam else if (com&IOC_VOID) 22211284Ssam *(caddr_t *)data = uap->cmarg; 2237423Sroot 22412751Ssam switch (com) { 2257624Ssam 22612751Ssam case FIONBIO: 22712751Ssam u.u_error = fset(fp, FNDELAY, *(int *)data); 22812751Ssam return; 22912751Ssam 23012751Ssam case FIOASYNC: 23112751Ssam u.u_error = fset(fp, FASYNC, *(int *)data); 23212751Ssam return; 23312751Ssam 23412751Ssam case FIOSETOWN: 23512751Ssam u.u_error = fsetown(fp, *(int *)data); 23612751Ssam return; 23712751Ssam 23812751Ssam case FIOGETOWN: 23912751Ssam u.u_error = fgetown(fp, (int *)data); 24012751Ssam return; 2417423Sroot } 24212751Ssam u.u_error = (*fp->f_ops->fo_ioctl)(fp, com, data); 2437624Ssam /* 2447624Ssam * Copy any data to user, size was 2457624Ssam * already set and checked above. 2467624Ssam */ 2479999Ssam if (u.u_error == 0 && (com&IOC_OUT) && size) 2489999Ssam u.u_error = copyout(data, uap->cmarg, (u_int)size); 2497423Sroot } 2507423Sroot 25112751Ssam int unselect(); 25212751Ssam int nselcoll; 25317593Skarels 2547423Sroot /* 25512751Ssam * Select system call. 2567423Sroot */ 25712751Ssam select() 25812751Ssam { 25912751Ssam register struct uap { 26012751Ssam int nd; 26123523Skarels fd_set *in, *ou, *ex; 26212751Ssam struct timeval *tv; 26312751Ssam } *uap = (struct uap *)u.u_ap; 26423523Skarels fd_set ibits[3], obits[3]; 26512751Ssam struct timeval atv; 26617593Skarels int s, ncoll, ni; 26712751Ssam label_t lqsave; 26812751Ssam 26917593Skarels bzero(ibits, sizeof(ibits)); 27017593Skarels bzero(obits, sizeof(obits)); 27112751Ssam if (uap->nd > NOFILE) 27212751Ssam uap->nd = NOFILE; /* forgiving, if slightly wrong */ 27323523Skarels ni = howmany(uap->nd, NFDBITS); 27412751Ssam 27512751Ssam #define getbits(name, x) \ 27612751Ssam if (uap->name) { \ 27723523Skarels u.u_error = copyin((caddr_t)uap->name, (caddr_t)&ibits[x], \ 27823523Skarels ni * sizeof(fd_mask)); \ 27912751Ssam if (u.u_error) \ 28012751Ssam goto done; \ 28117593Skarels } 28212751Ssam getbits(in, 0); 28312751Ssam getbits(ou, 1); 28412751Ssam getbits(ex, 2); 28512751Ssam #undef getbits 28612751Ssam 28712751Ssam if (uap->tv) { 28812751Ssam u.u_error = copyin((caddr_t)uap->tv, (caddr_t)&atv, 28912751Ssam sizeof (atv)); 29012751Ssam if (u.u_error) 29112751Ssam goto done; 29212751Ssam if (itimerfix(&atv)) { 29312751Ssam u.u_error = EINVAL; 29412751Ssam goto done; 29512751Ssam } 29617934Skarels s = splhigh(); timevaladd(&atv, &time); splx(s); 29712751Ssam } 29812751Ssam retry: 29912751Ssam ncoll = nselcoll; 30012751Ssam u.u_procp->p_flag |= SSEL; 30117593Skarels u.u_r.r_val1 = selscan(ibits, obits, uap->nd); 30212751Ssam if (u.u_error || u.u_r.r_val1) 30312751Ssam goto done; 30417934Skarels s = splhigh(); 30512971Ssam /* this should be timercmp(&time, &atv, >=) */ 30612971Ssam if (uap->tv && (time.tv_sec > atv.tv_sec || 30712971Ssam time.tv_sec == atv.tv_sec && time.tv_usec >= atv.tv_usec)) { 30812751Ssam splx(s); 30912751Ssam goto done; 31012751Ssam } 31112751Ssam if ((u.u_procp->p_flag & SSEL) == 0 || nselcoll != ncoll) { 31212751Ssam u.u_procp->p_flag &= ~SSEL; 31312751Ssam splx(s); 31412751Ssam goto retry; 31512751Ssam } 31612751Ssam u.u_procp->p_flag &= ~SSEL; 31712751Ssam if (uap->tv) { 31812751Ssam lqsave = u.u_qsave; 31912751Ssam if (setjmp(&u.u_qsave)) { 32012751Ssam untimeout(unselect, (caddr_t)u.u_procp); 32112751Ssam u.u_error = EINTR; 32212751Ssam splx(s); 32312751Ssam goto done; 32412751Ssam } 32512751Ssam timeout(unselect, (caddr_t)u.u_procp, hzto(&atv)); 32612751Ssam } 32712751Ssam sleep((caddr_t)&selwait, PZERO+1); 32812751Ssam if (uap->tv) { 32912751Ssam u.u_qsave = lqsave; 33012751Ssam untimeout(unselect, (caddr_t)u.u_procp); 33112751Ssam } 33212751Ssam splx(s); 33312751Ssam goto retry; 33412751Ssam done: 33512751Ssam #define putbits(name, x) \ 33612751Ssam if (uap->name) { \ 33723523Skarels int error = copyout((caddr_t)&obits[x], (caddr_t)uap->name, \ 33823523Skarels ni * sizeof(fd_mask)); \ 33912751Ssam if (error) \ 34012751Ssam u.u_error = error; \ 34112751Ssam } 342*26070Skarels if (u.u_error == 0) { 34321106Skarels putbits(in, 0); 34421106Skarels putbits(ou, 1); 34521106Skarels putbits(ex, 2); 34612751Ssam #undef putbits 34721106Skarels } 34812751Ssam } 34912751Ssam 35012751Ssam unselect(p) 35112751Ssam register struct proc *p; 35212751Ssam { 35317934Skarels register int s = splhigh(); 35412751Ssam 35512751Ssam switch (p->p_stat) { 35612751Ssam 35712751Ssam case SSLEEP: 35812751Ssam setrun(p); 35912751Ssam break; 36012751Ssam 36112751Ssam case SSTOP: 36212751Ssam unsleep(p); 36312751Ssam break; 36412751Ssam } 36512751Ssam splx(s); 36612751Ssam } 36712751Ssam 36817593Skarels selscan(ibits, obits, nfd) 36923523Skarels fd_set *ibits, *obits; 37012751Ssam { 37123523Skarels register int which, i, j; 37223523Skarels register fd_mask bits; 37312751Ssam int flag; 37412751Ssam struct file *fp; 37512751Ssam int n = 0; 37612751Ssam 37712751Ssam for (which = 0; which < 3; which++) { 37812751Ssam switch (which) { 37912751Ssam 38012751Ssam case 0: 38112751Ssam flag = FREAD; break; 38212751Ssam 38312751Ssam case 1: 38412751Ssam flag = FWRITE; break; 38512751Ssam 38612751Ssam case 2: 38712751Ssam flag = 0; break; 38812751Ssam } 38923523Skarels for (i = 0; i < nfd; i += NFDBITS) { 39023523Skarels bits = ibits[which].fds_bits[i/NFDBITS]; 39117593Skarels while ((j = ffs(bits)) && i + --j < nfd) { 39217593Skarels bits &= ~(1 << j); 39317593Skarels fp = u.u_ofile[i + j]; 39417593Skarels if (fp == NULL) { 39517593Skarels u.u_error = EBADF; 39617593Skarels break; 39717593Skarels } 39817593Skarels if ((*fp->f_ops->fo_select)(fp, flag)) { 39923523Skarels FD_SET(i + j, &obits[which]); 40017593Skarels n++; 40117593Skarels } 40212751Ssam } 40312751Ssam } 40412751Ssam } 40512751Ssam return (n); 40612751Ssam } 40712751Ssam 4087423Sroot /*ARGSUSED*/ 40912751Ssam seltrue(dev, flag) 41012751Ssam dev_t dev; 41112751Ssam int flag; 4127423Sroot { 4137423Sroot 41412751Ssam return (1); 4157423Sroot } 4168103Sroot 41712751Ssam selwakeup(p, coll) 41812751Ssam register struct proc *p; 41912751Ssam int coll; 4208103Sroot { 4218103Sroot 42212751Ssam if (coll) { 42312751Ssam nselcoll++; 42412751Ssam wakeup((caddr_t)&selwait); 42512751Ssam } 42612751Ssam if (p) { 42717934Skarels int s = splhigh(); 42817270Skarels if (p->p_wchan == (caddr_t)&selwait) { 42917270Skarels if (p->p_stat == SSLEEP) 43017270Skarels setrun(p); 43117270Skarels else 43217270Skarels unsleep(p); 43317270Skarels } else if (p->p_flag & SSEL) 43412751Ssam p->p_flag &= ~SSEL; 43512751Ssam splx(s); 43612751Ssam } 4378103Sroot } 438