1*8564Sroot /* sys_generic.c 5.17 82/10/17 */ 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/conf.h" 137423Sroot #include "../h/socket.h" 147423Sroot #include "../h/socketvar.h" 157423Sroot #include "../h/fs.h" 167487Skre #ifdef MUSH 177487Skre #include "../h/quota.h" 187487Skre #include "../h/share.h" 197487Skre #else 207487Skre #define CHARGE(nothing) 217487Skre #endif 227500Sroot #include "../h/descrip.h" 237714Sroot #include "../h/uio.h" 247423Sroot 257423Sroot /* 267423Sroot * Read system call. 277423Sroot */ 287423Sroot read() 297423Sroot { 307423Sroot register struct a { 317423Sroot int fdes; 327423Sroot char *cbuf; 337423Sroot unsigned count; 347820Sroot } *uap = (struct a *)u.u_ap; 357746Sroot struct uio auio; 367746Sroot struct iovec aiov; 377423Sroot 387820Sroot aiov.iov_base = (caddr_t)uap->cbuf; 397820Sroot aiov.iov_len = uap->count; 407820Sroot auio.uio_iov = &aiov; 417820Sroot auio.uio_iovcnt = 1; 427820Sroot rwuio(&auio, UIO_READ); 437820Sroot } 447820Sroot 457820Sroot readv() 467820Sroot { 477820Sroot register struct a { 487820Sroot int fdes; 497820Sroot struct iovec *iovp; 507820Sroot int iovcnt; 517820Sroot } *uap = (struct a *)u.u_ap; 527820Sroot struct uio auio; 537820Sroot struct iovec aiov[16]; /* XXX */ 547820Sroot 557820Sroot if (uap->iovcnt <= 0 || uap->iovcnt > sizeof(aiov)/sizeof(aiov[0])) { 567423Sroot u.u_error = EINVAL; 577423Sroot return; 587423Sroot } 597820Sroot auio.uio_iov = aiov; 607820Sroot auio.uio_iovcnt = uap->iovcnt; 617820Sroot if (copyin((caddr_t)uap->iovp, (caddr_t)aiov, 627820Sroot (unsigned)(uap->iovcnt * sizeof (struct iovec)))) { 637820Sroot u.u_error = EFAULT; 647423Sroot return; 657423Sroot } 667820Sroot rwuio(&auio, UIO_READ); 677423Sroot } 687423Sroot 697423Sroot /* 707423Sroot * Write system call 717423Sroot */ 727423Sroot write() 737423Sroot { 747423Sroot register struct a { 757423Sroot int fdes; 767423Sroot char *cbuf; 777820Sroot int count; 787820Sroot } *uap = (struct a *)u.u_ap; 797820Sroot struct uio auio; 807820Sroot struct iovec aiov; 817423Sroot 827820Sroot auio.uio_iov = &aiov; 837820Sroot auio.uio_iovcnt = 1; 847820Sroot aiov.iov_base = uap->cbuf; 857820Sroot aiov.iov_len = uap->count; 867820Sroot rwuio(&auio, UIO_WRITE); 877820Sroot } 887820Sroot 897820Sroot writev() 907820Sroot { 917820Sroot register struct a { 927820Sroot int fdes; 937820Sroot struct iovec *iovp; 947820Sroot int iovcnt; 957820Sroot } *uap = (struct a *)u.u_ap; 967820Sroot struct uio auio; 977820Sroot struct iovec aiov[16]; /* XXX */ 987820Sroot 997820Sroot if (uap->iovcnt <= 0 || uap->iovcnt > sizeof(aiov)/sizeof(aiov[0])) { 1007423Sroot u.u_error = EINVAL; 1017423Sroot return; 1027423Sroot } 1037820Sroot auio.uio_iov = aiov; 1047820Sroot auio.uio_iovcnt = uap->iovcnt; 1057820Sroot if (copyin((caddr_t)uap->iovp, (caddr_t)aiov, 1067820Sroot (unsigned)(uap->iovcnt * sizeof (struct iovec)))) { 1077820Sroot u.u_error = EFAULT; 1087820Sroot return; 1097820Sroot } 1107820Sroot rwuio(&auio, UIO_WRITE); 1117820Sroot } 1127820Sroot 1137820Sroot rwuio(uio, rw) 1147820Sroot register struct uio *uio; 1157820Sroot enum uio_rw rw; 1167820Sroot { 1177820Sroot struct a { 1187820Sroot int fdes; 1197820Sroot }; 1207820Sroot register struct file *fp; 1217820Sroot register struct iovec *iov; 1227820Sroot register struct inode *ip; 1237820Sroot int i, count; 1247820Sroot 1257820Sroot GETF(fp, ((struct a *)u.u_ap)->fdes); 1267820Sroot if ((fp->f_flag&(rw==UIO_READ ? FREAD : FWRITE)) == 0) { 1277423Sroot u.u_error = EBADF; 1287423Sroot return; 1297423Sroot } 1307820Sroot uio->uio_resid = 0; 1317820Sroot uio->uio_segflg = 0; 1327820Sroot iov = uio->uio_iov; 1337820Sroot for (i = 0; i < uio->uio_iovcnt; i++) { 1347820Sroot if (iov->iov_len < 0) { 1357820Sroot u.u_error = EINVAL; 1367820Sroot return; 1377820Sroot } 1387820Sroot uio->uio_resid += iov->iov_len; 1397820Sroot if (uio->uio_resid < 0) { 1407820Sroot u.u_error = EINVAL; 1417820Sroot return; 1427820Sroot } 1437820Sroot } 1447820Sroot count = uio->uio_resid; 1458118Sroot if ((u.u_procp->p_flag&SNUSIG) && setjmp(&u.u_qsave)) { 1467820Sroot if (uio->uio_resid == count) 1477423Sroot u.u_eosys = RESTARTSYS; 1487820Sroot } else if (fp->f_type == DTYPE_SOCKET) { 1497820Sroot int sosend(), soreceive(); 1507820Sroot u.u_error = 1517820Sroot (*(rw==UIO_READ?soreceive:sosend)) 1528449Sroot (fp->f_socket, (struct sockaddr *)0, uio, 0); 1537820Sroot } else { 1547423Sroot ip = fp->f_inode; 1557820Sroot uio->uio_offset = fp->f_offset; 1567423Sroot if ((ip->i_mode&IFMT) == IFREG) { 1578449Sroot ILOCK(ip); 1587820Sroot u.u_error = rwip(ip, uio, rw); 1598449Sroot IUNLOCK(ip); 1607423Sroot } else 1617820Sroot u.u_error = rwip(ip, uio, rw); 1627820Sroot fp->f_offset += count - uio->uio_resid; 1637423Sroot } 1647820Sroot u.u_r.r_val1 = count - uio->uio_resid; 1657423Sroot } 1667423Sroot 1677820Sroot rdwri(rw, ip, base, len, offset, segflg, aresid) 1687820Sroot struct inode *ip; 1697820Sroot caddr_t base; 1707820Sroot int len, offset, segflg; 1717820Sroot int *aresid; 1727820Sroot enum uio_rw rw; 1737500Sroot { 1747820Sroot struct uio auio; 1757820Sroot struct iovec aiov; 1767820Sroot int error; 1777423Sroot 1787820Sroot auio.uio_iov = &aiov; 1797820Sroot auio.uio_iovcnt = 1; 1807820Sroot aiov.iov_base = base; 1817820Sroot aiov.iov_len = len; 1827820Sroot auio.uio_resid = len; 1837820Sroot auio.uio_offset = offset; 1847820Sroot auio.uio_segflg = segflg; 1857820Sroot error = rwip(ip, &auio, rw); 1867820Sroot if (aresid) 1877820Sroot *aresid = auio.uio_resid; 1887820Sroot else 1897820Sroot if (auio.uio_resid) 1907820Sroot error = EIO; 1917820Sroot return (error); 1927500Sroot } 1937500Sroot 1947820Sroot rwip(ip, uio, rw) 1957820Sroot register struct inode *ip; 1967820Sroot register struct uio *uio; 1977820Sroot enum uio_rw rw; 1987500Sroot { 1997820Sroot dev_t dev = (dev_t)ip->i_rdev; 2007820Sroot struct buf *bp; 2017820Sroot struct fs *fs; 2027820Sroot daddr_t lbn, bn; 2037820Sroot register int on, type; 2047820Sroot register unsigned n; 2057820Sroot int size; 2067820Sroot long bsize; 2077820Sroot extern int mem_no; 2087820Sroot int error = 0; 2097500Sroot 2107820Sroot if (rw != UIO_READ && rw != UIO_WRITE) 2117820Sroot panic("rwip"); 2127820Sroot if (uio->uio_offset < 0 && 2137820Sroot ((ip->i_mode&IFMT) != IFCHR || mem_no != major(dev))) 2147820Sroot return (EINVAL); if (rw == UIO_READ) 2157820Sroot ip->i_flag |= IACC; 2167820Sroot type = ip->i_mode&IFMT; 2177820Sroot if (type == IFCHR) { 2187820Sroot #ifdef QUOTA 2197820Sroot register c = uio->uio_resid; 2207820Sroot #endif 2217820Sroot if (rw == UIO_READ) 2228519Sroot u.u_error = (*cdevsw[major(dev)].d_read)(dev, uio); 2237820Sroot else { 2247820Sroot ip->i_flag |= IUPD|ICHG; 2258519Sroot u.u_error = (*cdevsw[major(dev)].d_write)(dev, uio); 2267820Sroot } 2277820Sroot CHARGE(sc_tio * (c - uio->uio_resid)); 2287820Sroot return (u.u_error); 2297820Sroot } 2307820Sroot if (rw == UIO_WRITE && type == IFREG && 2318036Sroot uio->uio_offset + uio->uio_resid > 2328036Sroot u.u_rlimit[RLIMIT_FSIZE].rlim_cur) { 2337820Sroot psignal(u.u_procp, SIGXFSZ); 2347820Sroot return (EMFILE); 2357820Sroot } 2367820Sroot if (type != IFBLK) { 2377820Sroot dev = ip->i_dev; 2387820Sroot fs = ip->i_fs; 2397820Sroot bsize = fs->fs_bsize; 2407820Sroot } else 2417820Sroot bsize = BLKDEV_IOSIZE; 2427820Sroot do { 2437820Sroot lbn = uio->uio_offset / bsize; 2447820Sroot on = uio->uio_offset % bsize; 2457820Sroot n = MIN((unsigned)(bsize - on), uio->uio_resid); 2467820Sroot if (type != IFBLK) { 2477820Sroot if (rw == UIO_READ) { 2487820Sroot int diff = ip->i_size - uio->uio_offset; 2497820Sroot if (diff <= 0) 2507820Sroot return (0); 2517820Sroot if (diff < n) 2527820Sroot n = diff; 2537820Sroot } 2547820Sroot bn = fsbtodb(fs, 2557820Sroot bmap(ip, lbn, rw == UIO_WRITE ? B_WRITE: B_READ, (int)(on+n))); 2567820Sroot if (u.u_error || rw == UIO_WRITE && (long)bn<0) 2577820Sroot return (u.u_error); 2587820Sroot if (rw == UIO_WRITE && uio->uio_offset + n > ip->i_size && 2597820Sroot (type == IFDIR || type == IFREG || type == IFLNK)) 2607820Sroot ip->i_size = uio->uio_offset + n; 2617820Sroot size = blksize(fs, ip, lbn); 2627820Sroot } else { 2637820Sroot bn = lbn * (BLKDEV_IOSIZE/DEV_BSIZE); 2647820Sroot rablock = bn + (BLKDEV_IOSIZE/DEV_BSIZE); 2657820Sroot rasize = size = bsize; 2667820Sroot } 2677820Sroot if (rw == UIO_READ) { 2687820Sroot if ((long)bn<0) { 2697820Sroot bp = geteblk(size); 2707820Sroot clrbuf(bp); 2717820Sroot } else if (ip->i_lastr + 1 == lbn) 2727820Sroot bp = breada(dev, bn, size, rablock, rasize); 2737820Sroot else 2747820Sroot bp = bread(dev, bn, size); 2757820Sroot ip->i_lastr = lbn; 2767820Sroot } else { 2777820Sroot int i, count; 2787820Sroot 2797820Sroot count = howmany(size, DEV_BSIZE); 2807820Sroot for (i = 0; i < count; i += CLSIZE) 2817820Sroot if (mfind(dev, bn + i)) 2827820Sroot munhash(dev, bn + i); 2837820Sroot if (n == bsize) 2847820Sroot bp = getblk(dev, bn, size); 2857820Sroot else 2867820Sroot bp = bread(dev, bn, size); 2877820Sroot } 2887820Sroot n = MIN(n, size - bp->b_resid); 2897820Sroot if (bp->b_flags & B_ERROR) { 2907820Sroot error = EIO; 2917820Sroot brelse(bp); 2927820Sroot goto bad; 2937820Sroot } 2947820Sroot u.u_error = 2957820Sroot uiomove(bp->b_un.b_addr+on, (u_int)n, rw, uio); 2967820Sroot if (rw == UIO_READ) { 2977820Sroot if (n + on == bsize || uio->uio_offset == ip->i_size) 2987820Sroot bp->b_flags |= B_AGE; 2997820Sroot brelse(bp); 3007820Sroot } else { 3017820Sroot if ((ip->i_mode&IFMT) == IFDIR) 3027820Sroot bwrite(bp); 3037820Sroot else if (n + on == bsize) { 3047820Sroot bp->b_flags |= B_AGE; 3057820Sroot bawrite(bp); 3067820Sroot } else 3077820Sroot bdwrite(bp); 3087820Sroot ip->i_flag |= IUPD|ICHG; 3097820Sroot if (u.u_ruid != 0) 3107820Sroot ip->i_mode &= ~(ISUID|ISGID); 3117820Sroot } 3127820Sroot } while (u.u_error == 0 && uio->uio_resid > 0 && n != 0); 3137820Sroot bad: 3147820Sroot return (error); 3157500Sroot } 3167500Sroot 3177820Sroot uiomove(cp, n, rw, uio) 3187820Sroot register caddr_t cp; 3197820Sroot register int n; 3207820Sroot enum uio_rw rw; 3217820Sroot register struct uio *uio; 3227820Sroot { 3237820Sroot register struct iovec *iov; 3247820Sroot int error; 3257820Sroot u_int cnt; 3267820Sroot 3277820Sroot while (n > 0 && uio->uio_resid) { 3287820Sroot iov = uio->uio_iov; 3297820Sroot cnt = iov->iov_len; 3307820Sroot if (cnt == 0) { 3317820Sroot uio->uio_iov++; 3327820Sroot uio->uio_iovcnt--; 3337820Sroot continue; 3347820Sroot } 3357820Sroot if (cnt > n) 3367820Sroot cnt = n; 3377820Sroot switch (uio->uio_segflg) { 3387820Sroot 3397820Sroot case 0: 3407820Sroot case 2: 3417820Sroot if (rw == UIO_READ) 3427820Sroot error = copyout(cp, iov->iov_base, cnt); 3437820Sroot else 3447820Sroot error = copyin(iov->iov_base, cp, cnt); 3457820Sroot if (error) 3467820Sroot return (error); 3477820Sroot break; 3487820Sroot 3497820Sroot case 1: 3507820Sroot if (rw == UIO_READ) 3517820Sroot bcopy((caddr_t)cp, iov->iov_base, cnt); 3527820Sroot else 3537820Sroot bcopy(iov->iov_base, (caddr_t)cp, cnt); 3547820Sroot break; 3557820Sroot } 3567820Sroot iov->iov_base += cnt; 3577820Sroot iov->iov_len -= cnt; 3587820Sroot uio->uio_resid -= cnt; 3597820Sroot uio->uio_offset += cnt; 3607820Sroot cp += cnt; 3617820Sroot n -= cnt; 3627820Sroot } 3637820Sroot return (error); 3647820Sroot } 3657820Sroot 3667423Sroot /* 3677820Sroot * Give next character to user as result of read. 3687820Sroot */ 3697820Sroot ureadc(c, uio) 3707820Sroot register int c; 3717820Sroot register struct uio *uio; 3727820Sroot { 3737820Sroot register struct iovec *iov; 3747820Sroot 3757820Sroot again: 3767820Sroot if (uio->uio_iovcnt == 0) 3777820Sroot panic("ureadc"); 3787820Sroot iov = uio->uio_iov; 3797820Sroot if (iov->iov_len <= 0 || uio->uio_resid <= 0) { 3807820Sroot uio->uio_iovcnt--; 3817820Sroot uio->uio_iov++; 3827820Sroot goto again; 3837820Sroot } 3847820Sroot switch (uio->uio_segflg) { 3857820Sroot 3867820Sroot case 0: 3877820Sroot if (subyte(iov->iov_base, c) < 0) 3887820Sroot return (EFAULT); 3897820Sroot break; 3907820Sroot 3917820Sroot case 1: 3927820Sroot *iov->iov_base = c; 3937820Sroot break; 3947820Sroot 3957820Sroot case 2: 3967820Sroot if (suibyte(iov->iov_base, c) < 0) 3977820Sroot return (EFAULT); 3987820Sroot break; 3997820Sroot } 4007820Sroot iov->iov_base++; 4017820Sroot iov->iov_len--; 4027820Sroot uio->uio_resid--; 4037820Sroot uio->uio_offset++; 4047820Sroot return (0); 4057820Sroot } 4067820Sroot 4077820Sroot /* 4087820Sroot * Get next character written in by user from uio. 4097820Sroot */ 4107820Sroot uwritec(uio) 4117820Sroot struct uio *uio; 4127820Sroot { 4137820Sroot register struct iovec *iov; 4147820Sroot register int c; 4157820Sroot 4167820Sroot again: 4177820Sroot if (uio->uio_iovcnt <= 0 || uio->uio_resid <= 0) 4187820Sroot panic("uwritec"); 4197820Sroot iov = uio->uio_iov; 4207820Sroot if (iov->iov_len == 0) { 4217820Sroot uio->uio_iovcnt--; 4227820Sroot uio->uio_iov++; 4237820Sroot goto again; 4247820Sroot } 4257820Sroot switch (uio->uio_segflg) { 4267820Sroot 4277820Sroot case 0: 4287820Sroot c = fubyte(iov->iov_base); 4297820Sroot break; 4307820Sroot 4317820Sroot case 1: 4327820Sroot c = *iov->iov_base & 0377; 4337820Sroot break; 4347820Sroot 4357820Sroot case 2: 4367820Sroot c = fuibyte(iov->iov_base); 4377820Sroot break; 4387820Sroot } 4397820Sroot if (c < 0) 4407820Sroot return (-1); 4417820Sroot iov->iov_base++; 4427820Sroot iov->iov_len--; 4437820Sroot uio->uio_resid--; 4447820Sroot uio->uio_offset++; 4457820Sroot return (c & 0377); 4467820Sroot } 4477820Sroot 4487820Sroot /* 4497423Sroot * Ioctl system call 4507624Ssam * Check legality, execute common code, 4517624Ssam * and switch out to individual device routine. 4527423Sroot */ 4537423Sroot ioctl() 4547423Sroot { 4557423Sroot register struct file *fp; 4567624Ssam struct a { 4577423Sroot int fdes; 4587423Sroot int cmd; 4597423Sroot caddr_t cmarg; 4607423Sroot } *uap; 4617820Sroot register int com; 4627820Sroot register u_int size; 4637624Ssam char data[IOCPARM_MASK+1]; 4647423Sroot 4657423Sroot uap = (struct a *)u.u_ap; 4667423Sroot if ((fp = getf(uap->fdes)) == NULL) 4677423Sroot return; 4687423Sroot if ((fp->f_flag & (FREAD|FWRITE)) == 0) { 4697423Sroot u.u_error = EBADF; 4707423Sroot return; 4717423Sroot } 4727624Ssam com = uap->cmd; 4737624Ssam 4747699Ssam #ifndef NOCOMPAT 4757624Ssam /* 4767624Ssam * Map old style ioctl's into new for the 4777624Ssam * sake of backwards compatibility (sigh). 4787624Ssam */ 4797624Ssam if ((com&~0xffff) == 0) { 4807624Ssam com = mapioctl(com); 4817624Ssam if (com == 0) { 4827624Ssam u.u_error = EINVAL; 4837624Ssam return; 4847624Ssam } 4857624Ssam } 4867624Ssam #endif 4877624Ssam if (com == FIOCLEX) { 4887423Sroot u.u_pofile[uap->fdes] |= EXCLOSE; 4897423Sroot return; 4907423Sroot } 4917624Ssam if (com == FIONCLEX) { 4927423Sroot u.u_pofile[uap->fdes] &= ~EXCLOSE; 4937423Sroot return; 4947423Sroot } 4957624Ssam 4967624Ssam /* 4977624Ssam * Interpret high order word to find 4987624Ssam * amount of data to be copied to/from the 4997624Ssam * user's address space. 5007624Ssam */ 5017624Ssam size = (com &~ (IOC_INOUT|IOC_VOID)) >> 16; 5027624Ssam if (size > sizeof (data)) { 5037624Ssam u.u_error = EFAULT; 5047423Sroot return; 5057423Sroot } 5067699Ssam if (com&IOC_IN && size) { 5077820Sroot if (copyin(uap->cmarg, (caddr_t)data, (u_int)size)) { 5087624Ssam u.u_error = EFAULT; 5097624Ssam return; 5107624Ssam } 5117624Ssam } else 5127624Ssam *(caddr_t *)data = uap->cmarg; 5137624Ssam /* 5147624Ssam * Zero the buffer on the stack so the user 5157624Ssam * always gets back something deterministic. 5167624Ssam */ 5177624Ssam if ((com&IOC_OUT) && size) 5187624Ssam bzero((caddr_t)data, size); 5197423Sroot 5207624Ssam if (fp->f_type == DTYPE_SOCKET) 521*8564Sroot u.u_error = soioctl(fp->f_socket, com, data); 5227624Ssam else { 5237624Ssam register struct inode *ip = fp->f_inode; 5247624Ssam int fmt = ip->i_mode & IFMT; 5257624Ssam dev_t dev; 5267624Ssam 5277624Ssam if (fmt != IFCHR) { 5287624Ssam if (com == FIONREAD && (fmt == IFREG || fmt == IFDIR)) { 5297624Ssam *(off_t *)data = ip->i_size - fp->f_offset; 5307624Ssam goto returndata; 5317624Ssam } 5327624Ssam if (com != FIONBIO && com != FIOASYNC) 5337624Ssam u.u_error = ENOTTY; 5347423Sroot return; 5357624Ssam } 5367624Ssam dev = ip->i_rdev; 5377624Ssam u.u_r.r_val1 = 0; 5388118Sroot if ((u.u_procp->p_flag&SNUSIG) && setjmp(&u.u_qsave)) { 5397624Ssam u.u_eosys = RESTARTSYS; 5407624Ssam return; 5417624Ssam } 542*8564Sroot u.u_error = (*cdevsw[major(dev)].d_ioctl)(dev, com, data, 0); 5437423Sroot } 5447624Ssam 5457624Ssam returndata: 5467624Ssam /* 5477624Ssam * Copy any data to user, size was 5487624Ssam * already set and checked above. 5497624Ssam */ 5507820Sroot if (u.u_error == 0 && (com&IOC_OUT)) 5517820Sroot if (size && copyout(data, uap->cmarg, (u_int)size)) 5527699Ssam u.u_error = EFAULT; 5537423Sroot } 5547423Sroot 5557423Sroot /* 5567423Sroot * Do nothing specific version of line 5577423Sroot * discipline specific ioctl command. 5587423Sroot */ 5597423Sroot /*ARGSUSED*/ 5607624Ssam nullioctl(tp, cmd, data, flags) 5617423Sroot struct tty *tp; 5627624Ssam char *data; 5637624Ssam int flags; 5647423Sroot { 5657423Sroot 5667624Ssam #ifdef lint 5677624Ssam tp = tp; data = data; flags = flags; 5687624Ssam #endif 569*8564Sroot return (-1); 5707423Sroot } 5718103Sroot 5728103Sroot ostty() 5738103Sroot { 5748103Sroot 5758103Sroot } 5768103Sroot 5778103Sroot ogtty() 5788103Sroot { 5798103Sroot 5808103Sroot } 581