1*8118Sroot /* sys_generic.c 5.14 82/09/08 */ 27423Sroot 37423Sroot #include "../h/param.h" 47423Sroot #include "../h/systm.h" 57423Sroot #include "../h/dir.h" 67423Sroot #include "../h/user.h" 77423Sroot #include "../h/tty.h" 87423Sroot #include "../h/file.h" 97423Sroot #include "../h/inode.h" 107423Sroot #include "../h/buf.h" 117423Sroot #include "../h/proc.h" 127423Sroot #include "../h/inline.h" 137423Sroot #include "../h/conf.h" 147423Sroot #include "../h/socket.h" 157423Sroot #include "../h/socketvar.h" 167423Sroot #include "../h/fs.h" 177487Skre #ifdef MUSH 187487Skre #include "../h/quota.h" 197487Skre #include "../h/share.h" 207487Skre #else 217487Skre #define CHARGE(nothing) 227487Skre #endif 237500Sroot #include "../h/descrip.h" 247714Sroot #include "../h/uio.h" 257423Sroot 267423Sroot /* 277423Sroot * Read system call. 287423Sroot */ 297423Sroot read() 307423Sroot { 317423Sroot register struct a { 327423Sroot int fdes; 337423Sroot char *cbuf; 347423Sroot unsigned count; 357820Sroot } *uap = (struct a *)u.u_ap; 367746Sroot struct uio auio; 377746Sroot struct iovec aiov; 387423Sroot 397820Sroot aiov.iov_base = (caddr_t)uap->cbuf; 407820Sroot aiov.iov_len = uap->count; 417820Sroot auio.uio_iov = &aiov; 427820Sroot auio.uio_iovcnt = 1; 437820Sroot rwuio(&auio, UIO_READ); 447820Sroot } 457820Sroot 467820Sroot readv() 477820Sroot { 487820Sroot register struct a { 497820Sroot int fdes; 507820Sroot struct iovec *iovp; 517820Sroot int iovcnt; 527820Sroot } *uap = (struct a *)u.u_ap; 537820Sroot struct uio auio; 547820Sroot struct iovec aiov[16]; /* XXX */ 557820Sroot 567820Sroot if (uap->iovcnt <= 0 || uap->iovcnt > sizeof(aiov)/sizeof(aiov[0])) { 577423Sroot u.u_error = EINVAL; 587423Sroot return; 597423Sroot } 607820Sroot auio.uio_iov = aiov; 617820Sroot auio.uio_iovcnt = uap->iovcnt; 627820Sroot if (copyin((caddr_t)uap->iovp, (caddr_t)aiov, 637820Sroot (unsigned)(uap->iovcnt * sizeof (struct iovec)))) { 647820Sroot u.u_error = EFAULT; 657423Sroot return; 667423Sroot } 677820Sroot rwuio(&auio, UIO_READ); 687423Sroot } 697423Sroot 707423Sroot /* 717423Sroot * Write system call 727423Sroot */ 737423Sroot write() 747423Sroot { 757423Sroot register struct a { 767423Sroot int fdes; 777423Sroot char *cbuf; 787820Sroot int count; 797820Sroot } *uap = (struct a *)u.u_ap; 807820Sroot struct uio auio; 817820Sroot struct iovec aiov; 827423Sroot 837820Sroot auio.uio_iov = &aiov; 847820Sroot auio.uio_iovcnt = 1; 857820Sroot aiov.iov_base = uap->cbuf; 867820Sroot aiov.iov_len = uap->count; 877820Sroot rwuio(&auio, UIO_WRITE); 887820Sroot } 897820Sroot 907820Sroot writev() 917820Sroot { 927820Sroot register struct a { 937820Sroot int fdes; 947820Sroot struct iovec *iovp; 957820Sroot int iovcnt; 967820Sroot } *uap = (struct a *)u.u_ap; 977820Sroot struct uio auio; 987820Sroot struct iovec aiov[16]; /* XXX */ 997820Sroot 1007820Sroot if (uap->iovcnt <= 0 || uap->iovcnt > sizeof(aiov)/sizeof(aiov[0])) { 1017423Sroot u.u_error = EINVAL; 1027423Sroot return; 1037423Sroot } 1047820Sroot auio.uio_iov = aiov; 1057820Sroot auio.uio_iovcnt = uap->iovcnt; 1067820Sroot if (copyin((caddr_t)uap->iovp, (caddr_t)aiov, 1077820Sroot (unsigned)(uap->iovcnt * sizeof (struct iovec)))) { 1087820Sroot u.u_error = EFAULT; 1097820Sroot return; 1107820Sroot } 1117820Sroot rwuio(&auio, UIO_WRITE); 1127820Sroot } 1137820Sroot 1147820Sroot rwuio(uio, rw) 1157820Sroot register struct uio *uio; 1167820Sroot enum uio_rw rw; 1177820Sroot { 1187820Sroot struct a { 1197820Sroot int fdes; 1207820Sroot }; 1217820Sroot register struct file *fp; 1227820Sroot register struct iovec *iov; 1237820Sroot register struct inode *ip; 1247820Sroot int i, count; 1257820Sroot 1267820Sroot GETF(fp, ((struct a *)u.u_ap)->fdes); 1277820Sroot if ((fp->f_flag&(rw==UIO_READ ? FREAD : FWRITE)) == 0) { 1287423Sroot u.u_error = EBADF; 1297423Sroot return; 1307423Sroot } 1317820Sroot uio->uio_resid = 0; 1327820Sroot uio->uio_segflg = 0; 1337820Sroot iov = uio->uio_iov; 1347820Sroot for (i = 0; i < uio->uio_iovcnt; i++) { 1357820Sroot if (iov->iov_len < 0) { 1367820Sroot u.u_error = EINVAL; 1377820Sroot return; 1387820Sroot } 1397820Sroot uio->uio_resid += iov->iov_len; 1407820Sroot if (uio->uio_resid < 0) { 1417820Sroot u.u_error = EINVAL; 1427820Sroot return; 1437820Sroot } 1447820Sroot } 1457820Sroot count = uio->uio_resid; 146*8118Sroot if ((u.u_procp->p_flag&SNUSIG) && setjmp(&u.u_qsave)) { 1477820Sroot if (uio->uio_resid == count) 1487423Sroot u.u_eosys = RESTARTSYS; 1497820Sroot } else if (fp->f_type == DTYPE_SOCKET) { 1507820Sroot int sosend(), soreceive(); 1517820Sroot u.u_error = 1527820Sroot (*(rw==UIO_READ?soreceive:sosend)) 1537820Sroot (fp->f_socket, (struct sockaddr *)0, uio); 1547820Sroot } else { 1557423Sroot ip = fp->f_inode; 1567820Sroot uio->uio_offset = fp->f_offset; 1577423Sroot if ((ip->i_mode&IFMT) == IFREG) { 1587423Sroot ilock(ip); 1597820Sroot u.u_error = rwip(ip, uio, rw); 1607423Sroot iunlock(ip); 1617423Sroot } else 1627820Sroot u.u_error = rwip(ip, uio, rw); 1637820Sroot fp->f_offset += count - uio->uio_resid; 1647423Sroot } 1657820Sroot u.u_r.r_val1 = count - uio->uio_resid; 1667423Sroot } 1677423Sroot 1687820Sroot rdwri(rw, ip, base, len, offset, segflg, aresid) 1697820Sroot struct inode *ip; 1707820Sroot caddr_t base; 1717820Sroot int len, offset, segflg; 1727820Sroot int *aresid; 1737820Sroot enum uio_rw rw; 1747500Sroot { 1757820Sroot struct uio auio; 1767820Sroot struct iovec aiov; 1777820Sroot int error; 1787423Sroot 1797820Sroot auio.uio_iov = &aiov; 1807820Sroot auio.uio_iovcnt = 1; 1817820Sroot aiov.iov_base = base; 1827820Sroot aiov.iov_len = len; 1837820Sroot auio.uio_resid = len; 1847820Sroot auio.uio_offset = offset; 1857820Sroot auio.uio_segflg = segflg; 1867820Sroot error = rwip(ip, &auio, rw); 1877820Sroot if (aresid) 1887820Sroot *aresid = auio.uio_resid; 1897820Sroot else 1907820Sroot if (auio.uio_resid) 1917820Sroot error = EIO; 1927820Sroot return (error); 1937500Sroot } 1947500Sroot 1957820Sroot rwip(ip, uio, rw) 1967820Sroot register struct inode *ip; 1977820Sroot register struct uio *uio; 1987820Sroot enum uio_rw rw; 1997500Sroot { 2007820Sroot dev_t dev = (dev_t)ip->i_rdev; 2017820Sroot struct buf *bp; 2027820Sroot struct fs *fs; 2037820Sroot daddr_t lbn, bn; 2047820Sroot register int on, type; 2057820Sroot register unsigned n; 2067820Sroot int size; 2077820Sroot long bsize; 2087820Sroot extern int mem_no; 2097820Sroot int error = 0; 2107500Sroot 2117820Sroot if (rw != UIO_READ && rw != UIO_WRITE) 2127820Sroot panic("rwip"); 2137820Sroot if (uio->uio_offset < 0 && 2147820Sroot ((ip->i_mode&IFMT) != IFCHR || mem_no != major(dev))) 2157820Sroot return (EINVAL); if (rw == UIO_READ) 2167820Sroot ip->i_flag |= IACC; 2177820Sroot type = ip->i_mode&IFMT; 2187820Sroot if (type == IFCHR) { 2197820Sroot #ifdef QUOTA 2207820Sroot register c = uio->uio_resid; 2217820Sroot #endif 2227820Sroot if (rw == UIO_READ) 2237820Sroot (*cdevsw[major(dev)].d_read)(dev, uio); 2247820Sroot else { 2257820Sroot ip->i_flag |= IUPD|ICHG; 2267820Sroot (*cdevsw[major(dev)].d_write)(dev, uio); 2277820Sroot } 2287820Sroot CHARGE(sc_tio * (c - uio->uio_resid)); 2297820Sroot return (u.u_error); 2307820Sroot } 2317820Sroot if (rw == UIO_WRITE && type == IFREG && 2328036Sroot uio->uio_offset + uio->uio_resid > 2338036Sroot u.u_rlimit[RLIMIT_FSIZE].rlim_cur) { 2347820Sroot psignal(u.u_procp, SIGXFSZ); 2357820Sroot return (EMFILE); 2367820Sroot } 2377820Sroot if (type != IFBLK) { 2387820Sroot dev = ip->i_dev; 2397820Sroot fs = ip->i_fs; 2407820Sroot bsize = fs->fs_bsize; 2417820Sroot } else 2427820Sroot bsize = BLKDEV_IOSIZE; 2437820Sroot do { 2447820Sroot lbn = uio->uio_offset / bsize; 2457820Sroot on = uio->uio_offset % bsize; 2467820Sroot n = MIN((unsigned)(bsize - on), uio->uio_resid); 2477820Sroot if (type != IFBLK) { 2487820Sroot if (rw == UIO_READ) { 2497820Sroot int diff = ip->i_size - uio->uio_offset; 2507820Sroot if (diff <= 0) 2517820Sroot return (0); 2527820Sroot if (diff < n) 2537820Sroot n = diff; 2547820Sroot } 2557820Sroot bn = fsbtodb(fs, 2567820Sroot bmap(ip, lbn, rw == UIO_WRITE ? B_WRITE: B_READ, (int)(on+n))); 2577820Sroot if (u.u_error || rw == UIO_WRITE && (long)bn<0) 2587820Sroot return (u.u_error); 2597820Sroot if (rw == UIO_WRITE && uio->uio_offset + n > ip->i_size && 2607820Sroot (type == IFDIR || type == IFREG || type == IFLNK)) 2617820Sroot ip->i_size = uio->uio_offset + n; 2627820Sroot size = blksize(fs, ip, lbn); 2637820Sroot } else { 2647820Sroot bn = lbn * (BLKDEV_IOSIZE/DEV_BSIZE); 2657820Sroot rablock = bn + (BLKDEV_IOSIZE/DEV_BSIZE); 2667820Sroot rasize = size = bsize; 2677820Sroot } 2687820Sroot if (rw == UIO_READ) { 2697820Sroot if ((long)bn<0) { 2707820Sroot bp = geteblk(size); 2717820Sroot clrbuf(bp); 2727820Sroot } else if (ip->i_lastr + 1 == lbn) 2737820Sroot bp = breada(dev, bn, size, rablock, rasize); 2747820Sroot else 2757820Sroot bp = bread(dev, bn, size); 2767820Sroot ip->i_lastr = lbn; 2777820Sroot } else { 2787820Sroot int i, count; 2797820Sroot 2807820Sroot count = howmany(size, DEV_BSIZE); 2817820Sroot for (i = 0; i < count; i += CLSIZE) 2827820Sroot if (mfind(dev, bn + i)) 2837820Sroot munhash(dev, bn + i); 2847820Sroot if (n == bsize) 2857820Sroot bp = getblk(dev, bn, size); 2867820Sroot else 2877820Sroot bp = bread(dev, bn, size); 2887820Sroot } 2897820Sroot n = MIN(n, size - bp->b_resid); 2907820Sroot if (bp->b_flags & B_ERROR) { 2917820Sroot error = EIO; 2927820Sroot brelse(bp); 2937820Sroot goto bad; 2947820Sroot } 2957820Sroot u.u_error = 2967820Sroot uiomove(bp->b_un.b_addr+on, (u_int)n, rw, uio); 2977820Sroot if (rw == UIO_READ) { 2987820Sroot if (n + on == bsize || uio->uio_offset == ip->i_size) 2997820Sroot bp->b_flags |= B_AGE; 3007820Sroot brelse(bp); 3017820Sroot } else { 3027820Sroot if ((ip->i_mode&IFMT) == IFDIR) 3037820Sroot bwrite(bp); 3047820Sroot else if (n + on == bsize) { 3057820Sroot bp->b_flags |= B_AGE; 3067820Sroot bawrite(bp); 3077820Sroot } else 3087820Sroot bdwrite(bp); 3097820Sroot ip->i_flag |= IUPD|ICHG; 3107820Sroot if (u.u_ruid != 0) 3117820Sroot ip->i_mode &= ~(ISUID|ISGID); 3127820Sroot } 3137820Sroot } while (u.u_error == 0 && uio->uio_resid > 0 && n != 0); 3147820Sroot bad: 3157820Sroot return (error); 3167500Sroot } 3177500Sroot 3187820Sroot uiomove(cp, n, rw, uio) 3197820Sroot register caddr_t cp; 3207820Sroot register int n; 3217820Sroot enum uio_rw rw; 3227820Sroot register struct uio *uio; 3237820Sroot { 3247820Sroot register struct iovec *iov; 3257820Sroot int error; 3267820Sroot u_int cnt; 3277820Sroot 3287820Sroot while (n > 0 && uio->uio_resid) { 3297820Sroot iov = uio->uio_iov; 3307820Sroot cnt = iov->iov_len; 3317820Sroot if (cnt == 0) { 3327820Sroot uio->uio_iov++; 3337820Sroot uio->uio_iovcnt--; 3347820Sroot continue; 3357820Sroot } 3367820Sroot if (cnt > n) 3377820Sroot cnt = n; 3387820Sroot switch (uio->uio_segflg) { 3397820Sroot 3407820Sroot case 0: 3417820Sroot case 2: 3427820Sroot if (rw == UIO_READ) 3437820Sroot error = copyout(cp, iov->iov_base, cnt); 3447820Sroot else 3457820Sroot error = copyin(iov->iov_base, cp, cnt); 3467820Sroot if (error) 3477820Sroot return (error); 3487820Sroot break; 3497820Sroot 3507820Sroot case 1: 3517820Sroot if (rw == UIO_READ) 3527820Sroot bcopy((caddr_t)cp, iov->iov_base, cnt); 3537820Sroot else 3547820Sroot bcopy(iov->iov_base, (caddr_t)cp, cnt); 3557820Sroot break; 3567820Sroot } 3577820Sroot iov->iov_base += cnt; 3587820Sroot iov->iov_len -= cnt; 3597820Sroot uio->uio_resid -= cnt; 3607820Sroot uio->uio_offset += cnt; 3617820Sroot cp += cnt; 3627820Sroot n -= cnt; 3637820Sroot } 3647820Sroot return (error); 3657820Sroot } 3667820Sroot 3677423Sroot /* 3687820Sroot * Give next character to user as result of read. 3697820Sroot */ 3707820Sroot ureadc(c, uio) 3717820Sroot register int c; 3727820Sroot register struct uio *uio; 3737820Sroot { 3747820Sroot register struct iovec *iov; 3757820Sroot 3767820Sroot again: 3777820Sroot if (uio->uio_iovcnt == 0) 3787820Sroot panic("ureadc"); 3797820Sroot iov = uio->uio_iov; 3807820Sroot if (iov->iov_len <= 0 || uio->uio_resid <= 0) { 3817820Sroot uio->uio_iovcnt--; 3827820Sroot uio->uio_iov++; 3837820Sroot goto again; 3847820Sroot } 3857820Sroot switch (uio->uio_segflg) { 3867820Sroot 3877820Sroot case 0: 3887820Sroot if (subyte(iov->iov_base, c) < 0) 3897820Sroot return (EFAULT); 3907820Sroot break; 3917820Sroot 3927820Sroot case 1: 3937820Sroot *iov->iov_base = c; 3947820Sroot break; 3957820Sroot 3967820Sroot case 2: 3977820Sroot if (suibyte(iov->iov_base, c) < 0) 3987820Sroot return (EFAULT); 3997820Sroot break; 4007820Sroot } 4017820Sroot iov->iov_base++; 4027820Sroot iov->iov_len--; 4037820Sroot uio->uio_resid--; 4047820Sroot uio->uio_offset++; 4057820Sroot return (0); 4067820Sroot } 4077820Sroot 4087820Sroot /* 4097820Sroot * Get next character written in by user from uio. 4107820Sroot */ 4117820Sroot uwritec(uio) 4127820Sroot struct uio *uio; 4137820Sroot { 4147820Sroot register struct iovec *iov; 4157820Sroot register int c; 4167820Sroot 4177820Sroot again: 4187820Sroot if (uio->uio_iovcnt <= 0 || uio->uio_resid <= 0) 4197820Sroot panic("uwritec"); 4207820Sroot iov = uio->uio_iov; 4217820Sroot if (iov->iov_len == 0) { 4227820Sroot uio->uio_iovcnt--; 4237820Sroot uio->uio_iov++; 4247820Sroot goto again; 4257820Sroot } 4267820Sroot switch (uio->uio_segflg) { 4277820Sroot 4287820Sroot case 0: 4297820Sroot c = fubyte(iov->iov_base); 4307820Sroot break; 4317820Sroot 4327820Sroot case 1: 4337820Sroot c = *iov->iov_base & 0377; 4347820Sroot break; 4357820Sroot 4367820Sroot case 2: 4377820Sroot c = fuibyte(iov->iov_base); 4387820Sroot break; 4397820Sroot } 4407820Sroot if (c < 0) 4417820Sroot return (-1); 4427820Sroot iov->iov_base++; 4437820Sroot iov->iov_len--; 4447820Sroot uio->uio_resid--; 4457820Sroot uio->uio_offset++; 4467820Sroot return (c & 0377); 4477820Sroot } 4487820Sroot 4497820Sroot /* 4507423Sroot * Ioctl system call 4517624Ssam * Check legality, execute common code, 4527624Ssam * and switch out to individual device routine. 4537423Sroot */ 4547423Sroot ioctl() 4557423Sroot { 4567423Sroot register struct file *fp; 4577624Ssam struct a { 4587423Sroot int fdes; 4597423Sroot int cmd; 4607423Sroot caddr_t cmarg; 4617423Sroot } *uap; 4627820Sroot register int com; 4637820Sroot register u_int size; 4647624Ssam char data[IOCPARM_MASK+1]; 4657423Sroot 4667423Sroot uap = (struct a *)u.u_ap; 4677423Sroot if ((fp = getf(uap->fdes)) == NULL) 4687423Sroot return; 4697423Sroot if ((fp->f_flag & (FREAD|FWRITE)) == 0) { 4707423Sroot u.u_error = EBADF; 4717423Sroot return; 4727423Sroot } 4737624Ssam com = uap->cmd; 4747624Ssam 4757699Ssam #ifndef NOCOMPAT 4767624Ssam /* 4777624Ssam * Map old style ioctl's into new for the 4787624Ssam * sake of backwards compatibility (sigh). 4797624Ssam */ 4807624Ssam if ((com&~0xffff) == 0) { 4817624Ssam com = mapioctl(com); 4827624Ssam if (com == 0) { 4837624Ssam u.u_error = EINVAL; 4847624Ssam return; 4857624Ssam } 4867624Ssam } 4877624Ssam #endif 4887624Ssam if (com == FIOCLEX) { 4897423Sroot u.u_pofile[uap->fdes] |= EXCLOSE; 4907423Sroot return; 4917423Sroot } 4927624Ssam if (com == FIONCLEX) { 4937423Sroot u.u_pofile[uap->fdes] &= ~EXCLOSE; 4947423Sroot return; 4957423Sroot } 4967624Ssam 4977624Ssam /* 4987624Ssam * Interpret high order word to find 4997624Ssam * amount of data to be copied to/from the 5007624Ssam * user's address space. 5017624Ssam */ 5027624Ssam size = (com &~ (IOC_INOUT|IOC_VOID)) >> 16; 5037624Ssam if (size > sizeof (data)) { 5047624Ssam u.u_error = EFAULT; 5057423Sroot return; 5067423Sroot } 5077699Ssam if (com&IOC_IN && size) { 5087820Sroot if (copyin(uap->cmarg, (caddr_t)data, (u_int)size)) { 5097624Ssam u.u_error = EFAULT; 5107624Ssam return; 5117624Ssam } 5127624Ssam } else 5137624Ssam *(caddr_t *)data = uap->cmarg; 5147624Ssam /* 5157624Ssam * Zero the buffer on the stack so the user 5167624Ssam * always gets back something deterministic. 5177624Ssam */ 5187624Ssam if ((com&IOC_OUT) && size) 5197624Ssam bzero((caddr_t)data, size); 5207423Sroot 5217624Ssam if (fp->f_type == DTYPE_SOCKET) 5227624Ssam soioctl(fp->f_socket, com, data); 5237624Ssam else { 5247624Ssam register struct inode *ip = fp->f_inode; 5257624Ssam int fmt = ip->i_mode & IFMT; 5267624Ssam dev_t dev; 5277624Ssam 5287624Ssam if (fmt != IFCHR) { 5297624Ssam if (com == FIONREAD && (fmt == IFREG || fmt == IFDIR)) { 5307624Ssam *(off_t *)data = ip->i_size - fp->f_offset; 5317624Ssam goto returndata; 5327624Ssam } 5337624Ssam if (com != FIONBIO && com != FIOASYNC) 5347624Ssam u.u_error = ENOTTY; 5357423Sroot return; 5367624Ssam } 5377624Ssam dev = ip->i_rdev; 5387624Ssam u.u_r.r_val1 = 0; 539*8118Sroot if ((u.u_procp->p_flag&SNUSIG) && setjmp(&u.u_qsave)) { 5407624Ssam u.u_eosys = RESTARTSYS; 5417624Ssam return; 5427624Ssam } 5437624Ssam (*cdevsw[major(dev)].d_ioctl)(dev, com, data, 0); 5447423Sroot } 5457624Ssam 5467624Ssam returndata: 5477624Ssam /* 5487624Ssam * Copy any data to user, size was 5497624Ssam * already set and checked above. 5507624Ssam */ 5517820Sroot if (u.u_error == 0 && (com&IOC_OUT)) 5527820Sroot if (size && copyout(data, uap->cmarg, (u_int)size)) 5537699Ssam u.u_error = EFAULT; 5547423Sroot } 5557423Sroot 5567423Sroot /* 5577423Sroot * Do nothing specific version of line 5587423Sroot * discipline specific ioctl command. 5597423Sroot */ 5607423Sroot /*ARGSUSED*/ 5617624Ssam nullioctl(tp, cmd, data, flags) 5627423Sroot struct tty *tp; 5637624Ssam char *data; 5647624Ssam int flags; 5657423Sroot { 5667423Sroot 5677624Ssam #ifdef lint 5687624Ssam tp = tp; data = data; flags = flags; 5697624Ssam #endif 5707423Sroot return (cmd); 5717423Sroot } 5728103Sroot 5738103Sroot ostty() 5748103Sroot { 5758103Sroot 5768103Sroot } 5778103Sroot 5788103Sroot ogtty() 5798103Sroot { 5808103Sroot 5818103Sroot } 582