1*7699Ssam /* sys_generic.c 5.6 82/08/10 */ 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/cmap.h" 177423Sroot #include "../h/vlimit.h" 187423Sroot #include "../h/fs.h" 197487Skre #ifdef MUSH 207487Skre #include "../h/quota.h" 217487Skre #include "../h/share.h" 227487Skre #else 237487Skre #define CHARGE(nothing) 247487Skre #endif 257500Sroot #include "../h/descrip.h" 267423Sroot 277423Sroot /* 287423Sroot * Read system call. 297423Sroot */ 307423Sroot read() 317423Sroot { 327423Sroot register struct file *fp; 337423Sroot register struct inode *ip; 347423Sroot register struct a { 357423Sroot int fdes; 367423Sroot char *cbuf; 377423Sroot unsigned count; 387423Sroot } *uap; 397423Sroot 407423Sroot uap = (struct a *)u.u_ap; 417423Sroot if ((int)uap->count < 0) { 427423Sroot u.u_error = EINVAL; 437423Sroot return; 447423Sroot } 457423Sroot GETF(fp, uap->fdes); 467423Sroot if ((fp->f_flag&FREAD) == 0) { 477423Sroot u.u_error = EBADF; 487423Sroot return; 497423Sroot } 507423Sroot u.u_base = (caddr_t)uap->cbuf; 517423Sroot u.u_count = uap->count; 527423Sroot u.u_segflg = 0; 537423Sroot if ((u.u_procp->p_flag&SNUSIG) && setjmp(u.u_qsav)) { 547423Sroot if (u.u_count == uap->count) 557423Sroot u.u_eosys = RESTARTSYS; 567500Sroot } else if (fp->f_type == DTYPE_SOCKET) 577423Sroot u.u_error = soreceive(fp->f_socket, (struct sockaddr *)0); 587423Sroot else { 597423Sroot ip = fp->f_inode; 607423Sroot u.u_offset = fp->f_offset; 617423Sroot if ((ip->i_mode&IFMT) == IFREG) { 627423Sroot ilock(ip); 637423Sroot readi(ip); 647423Sroot iunlock(ip); 657423Sroot } else 667423Sroot readi(ip); 677423Sroot fp->f_offset += uap->count - u.u_count; 687423Sroot } 697423Sroot u.u_r.r_val1 = uap->count - u.u_count; 707423Sroot } 717423Sroot 727423Sroot /* 737423Sroot * Write system call 747423Sroot */ 757423Sroot write() 767423Sroot { 777423Sroot register struct file *fp; 787423Sroot register struct inode *ip; 797423Sroot register struct a { 807423Sroot int fdes; 817423Sroot char *cbuf; 827423Sroot unsigned count; 837423Sroot } *uap; 847423Sroot 857423Sroot uap = (struct a *)u.u_ap; 867423Sroot if ((int)uap->count < 0) { 877423Sroot u.u_error = EINVAL; 887423Sroot return; 897423Sroot } 907423Sroot GETF(fp, uap->fdes); 917423Sroot if ((fp->f_flag&FWRITE) == 0) { 927423Sroot u.u_error = EBADF; 937423Sroot return; 947423Sroot } 957423Sroot u.u_base = (caddr_t)uap->cbuf; 967423Sroot u.u_count = uap->count; 977423Sroot u.u_segflg = 0; 987423Sroot if ((u.u_procp->p_flag&SNUSIG) && setjmp(u.u_qsav)) { 997423Sroot if (u.u_count == uap->count) 1007423Sroot u.u_eosys = RESTARTSYS; 1017500Sroot } else if (fp->f_type == DTYPE_SOCKET) 1027423Sroot u.u_error = sosend(fp->f_socket, (struct sockaddr *)0); 1037423Sroot else { 1047423Sroot ip = fp->f_inode; 105*7699Ssam if (fp->f_flag&FAPPEND) 1067500Sroot fp->f_offset = ip->i_size; 1077423Sroot u.u_offset = fp->f_offset; 1087423Sroot if ((ip->i_mode&IFMT) == IFREG) { 1097423Sroot ilock(ip); 1107423Sroot writei(ip); 1117423Sroot iunlock(ip); 1127423Sroot } else 1137423Sroot writei(ip); 1147423Sroot fp->f_offset += uap->count - u.u_count; 1157423Sroot } 1167423Sroot u.u_r.r_val1 = uap->count - u.u_count; 1177423Sroot } 1187423Sroot 1197500Sroot readv() 1207500Sroot { 1217423Sroot 1227500Sroot } 1237500Sroot 1247500Sroot writev() 1257500Sroot { 1267500Sroot 1277500Sroot } 1287500Sroot 1297423Sroot /* 1307423Sroot * Ioctl system call 1317624Ssam * Check legality, execute common code, 1327624Ssam * and switch out to individual device routine. 1337423Sroot */ 1347423Sroot ioctl() 1357423Sroot { 1367423Sroot register struct file *fp; 1377624Ssam struct a { 1387423Sroot int fdes; 1397423Sroot int cmd; 1407423Sroot caddr_t cmarg; 1417423Sroot } *uap; 1427624Ssam register int com, size; 1437624Ssam char data[IOCPARM_MASK+1]; 1447423Sroot 1457423Sroot uap = (struct a *)u.u_ap; 1467423Sroot if ((fp = getf(uap->fdes)) == NULL) 1477423Sroot return; 1487423Sroot if ((fp->f_flag & (FREAD|FWRITE)) == 0) { 1497423Sroot u.u_error = EBADF; 1507423Sroot return; 1517423Sroot } 1527624Ssam com = uap->cmd; 1537624Ssam 154*7699Ssam #ifndef NOCOMPAT 1557624Ssam /* 1567624Ssam * Map old style ioctl's into new for the 1577624Ssam * sake of backwards compatibility (sigh). 1587624Ssam */ 1597624Ssam if ((com&~0xffff) == 0) { 1607624Ssam com = mapioctl(com); 1617624Ssam if (com == 0) { 1627624Ssam u.u_error = EINVAL; 1637624Ssam return; 1647624Ssam } 1657624Ssam } 1667624Ssam #endif 1677624Ssam if (com == FIOCLEX) { 1687423Sroot u.u_pofile[uap->fdes] |= EXCLOSE; 1697423Sroot return; 1707423Sroot } 1717624Ssam if (com == FIONCLEX) { 1727423Sroot u.u_pofile[uap->fdes] &= ~EXCLOSE; 1737423Sroot return; 1747423Sroot } 1757624Ssam 1767624Ssam /* 1777624Ssam * Interpret high order word to find 1787624Ssam * amount of data to be copied to/from the 1797624Ssam * user's address space. 1807624Ssam * (this'll have to change if we have in+out ioctls) 1817624Ssam */ 1827624Ssam size = (com &~ (IOC_INOUT|IOC_VOID)) >> 16; 1837624Ssam if (size > sizeof (data)) { 1847624Ssam u.u_error = EFAULT; 1857423Sroot return; 1867423Sroot } 187*7699Ssam if (com&IOC_IN && size) { 1887624Ssam if (copyin(uap->cmarg, (caddr_t)data, size)) { 1897624Ssam u.u_error = EFAULT; 1907624Ssam return; 1917624Ssam } 1927624Ssam } else 1937624Ssam *(caddr_t *)data = uap->cmarg; 1947624Ssam /* 1957624Ssam * Zero the buffer on the stack so the user 1967624Ssam * always gets back something deterministic. 1977624Ssam */ 1987624Ssam if ((com&IOC_OUT) && size) 1997624Ssam bzero((caddr_t)data, size); 2007423Sroot 2017624Ssam if (fp->f_type == DTYPE_SOCKET) 2027624Ssam soioctl(fp->f_socket, com, data); 2037624Ssam else { 2047624Ssam register struct inode *ip = fp->f_inode; 2057624Ssam int fmt = ip->i_mode & IFMT; 2067624Ssam dev_t dev; 2077624Ssam 2087624Ssam if (fmt != IFCHR) { 2097624Ssam if (com == FIONREAD && (fmt == IFREG || fmt == IFDIR)) { 2107624Ssam *(off_t *)data = ip->i_size - fp->f_offset; 2117624Ssam goto returndata; 2127624Ssam } 2137624Ssam if (com != FIONBIO && com != FIOASYNC) 2147624Ssam u.u_error = ENOTTY; 2157423Sroot return; 2167624Ssam } 2177624Ssam dev = ip->i_rdev; 2187624Ssam u.u_r.r_val1 = 0; 2197624Ssam if ((u.u_procp->p_flag&SNUSIG) && setjmp(u.u_qsav)) { 2207624Ssam u.u_eosys = RESTARTSYS; 2217624Ssam return; 2227624Ssam } 2237624Ssam (*cdevsw[major(dev)].d_ioctl)(dev, com, data, 0); 2247423Sroot } 2257624Ssam 2267624Ssam returndata: 2277624Ssam /* 2287624Ssam * Copy any data to user, size was 2297624Ssam * already set and checked above. 2307624Ssam */ 231*7699Ssam if (u.u_error == 0 && com&IOC_OUT) 232*7699Ssam if (size && copyout(data, uap->cmarg, size)) 233*7699Ssam u.u_error = EFAULT; 2347423Sroot } 2357423Sroot 2367423Sroot /* 2377423Sroot * Do nothing specific version of line 2387423Sroot * discipline specific ioctl command. 2397423Sroot */ 2407423Sroot /*ARGSUSED*/ 2417624Ssam nullioctl(tp, cmd, data, flags) 2427423Sroot struct tty *tp; 2437624Ssam char *data; 2447624Ssam int flags; 2457423Sroot { 2467423Sroot 2477624Ssam #ifdef lint 2487624Ssam tp = tp; data = data; flags = flags; 2497624Ssam #endif 2507423Sroot return (cmd); 2517423Sroot } 2527423Sroot 2537423Sroot /* 2547423Sroot * Read the file corresponding to 2557423Sroot * the inode pointed at by the argument. 2567423Sroot * The actual read arguments are found 2577423Sroot * in the variables: 2587423Sroot * u_base core address for destination 2597423Sroot * u_offset byte offset in file 2607423Sroot * u_count number of bytes to read 2617423Sroot * u_segflg read to kernel/user/user I 2627423Sroot */ 2637423Sroot readi(ip) 2647423Sroot register struct inode *ip; 2657423Sroot { 2667423Sroot struct buf *bp; 2677423Sroot struct fs *fs; 2687423Sroot dev_t dev; 2697423Sroot daddr_t lbn, bn; 2707423Sroot off_t diff; 2717423Sroot register int on, type; 2727423Sroot register unsigned n; 2737423Sroot int size; 2747423Sroot long bsize; 2757423Sroot extern int mem_no; 2767423Sroot 2777423Sroot if (u.u_count == 0) 2787423Sroot return; 2797423Sroot dev = (dev_t)ip->i_rdev; 2807423Sroot if (u.u_offset < 0 && ((ip->i_mode&IFMT) != IFCHR || 2817423Sroot mem_no != major(dev))) { 2827423Sroot u.u_error = EINVAL; 2837423Sroot return; 2847423Sroot } 2857423Sroot ip->i_flag |= IACC; 2867423Sroot type = ip->i_mode&IFMT; 2877423Sroot if (type == IFCHR) { 2887487Skre register c = u.u_count; 2897423Sroot (*cdevsw[major(dev)].d_read)(dev); 2907487Skre CHARGE(sc_tio * (c - u.u_count)); 2917423Sroot return; 2927423Sroot } 2937423Sroot if (type != IFBLK) { 2947423Sroot dev = ip->i_dev; 2957423Sroot fs = ip->i_fs; 2967423Sroot bsize = fs->fs_bsize; 2977423Sroot } else 2987423Sroot bsize = BLKDEV_IOSIZE; 2997423Sroot do { 3007423Sroot lbn = u.u_offset / bsize; 3017423Sroot on = u.u_offset % bsize; 3027423Sroot n = MIN((unsigned)(bsize - on), u.u_count); 3037423Sroot if (type != IFBLK) { 3047423Sroot diff = ip->i_size - u.u_offset; 3057423Sroot if (diff <= 0) 3067423Sroot return; 3077423Sroot if (diff < n) 3087423Sroot n = diff; 3097423Sroot bn = fsbtodb(fs, bmap(ip, lbn, B_READ)); 3107423Sroot if (u.u_error) 3117423Sroot return; 3127423Sroot size = blksize(fs, ip, lbn); 3137423Sroot } else { 3147423Sroot size = bsize; 3157423Sroot bn = lbn * (BLKDEV_IOSIZE/DEV_BSIZE); 3167423Sroot rablock = bn + (BLKDEV_IOSIZE/DEV_BSIZE); 3177423Sroot rasize = bsize; 3187423Sroot } 3197423Sroot if ((long)bn<0) { 3207423Sroot bp = geteblk(size); 3217423Sroot clrbuf(bp); 3227423Sroot } else if (ip->i_lastr + 1 == lbn) 3237423Sroot bp = breada(dev, bn, size, rablock, rasize); 3247423Sroot else 3257423Sroot bp = bread(dev, bn, size); 3267423Sroot ip->i_lastr = lbn; 3277423Sroot n = MIN(n, size - bp->b_resid); 3287423Sroot if (n != 0) { 3297423Sroot if (u.u_segflg != 1) { 3307423Sroot if (copyout(bp->b_un.b_addr+on, u.u_base, n)) { 3317423Sroot u.u_error = EFAULT; 3327423Sroot goto bad; 3337423Sroot } 3347423Sroot } else 3357423Sroot bcopy(bp->b_un.b_addr + on, u.u_base, n); 3367423Sroot u.u_base += n; 3377423Sroot u.u_offset += n; 3387423Sroot u.u_count -= n; 3397423Sroot bad: 3407423Sroot ; 3417423Sroot } 3427423Sroot if (n + on == bsize || u.u_offset == ip->i_size) 3437423Sroot bp->b_flags |= B_AGE; 3447423Sroot brelse(bp); 3457423Sroot } while (u.u_error == 0 && u.u_count != 0 && n != 0); 3467423Sroot } 3477423Sroot 3487423Sroot /* 3497423Sroot * Write the file corresponding to 3507423Sroot * the inode pointed at by the argument. 3517423Sroot * The actual write arguments are found 3527423Sroot * in the variables: 3537423Sroot * u_base core address for source 3547423Sroot * u_offset byte offset in file 3557423Sroot * u_count number of bytes to write 3567423Sroot * u_segflg write to kernel/user/user I 3577423Sroot */ 3587423Sroot writei(ip) 3597423Sroot register struct inode *ip; 3607423Sroot { 3617423Sroot struct buf *bp; 3627423Sroot register struct fs *fs; 3637423Sroot dev_t dev; 3647423Sroot daddr_t lbn, bn; 3657423Sroot register int on, type; 3667423Sroot register unsigned n; 3677423Sroot long bsize; 3687423Sroot int size, i, count; 3697423Sroot extern int mem_no; 3707423Sroot 3717423Sroot dev = (dev_t)ip->i_rdev; 3727423Sroot if (u.u_offset < 0 && ((ip->i_mode&IFMT) != IFCHR || 3737423Sroot mem_no != major(dev)) ) { 3747423Sroot u.u_error = EINVAL; 3757423Sroot return; 3767423Sroot } 3777423Sroot type = ip->i_mode & IFMT; 3787423Sroot if (type == IFCHR) { 3797423Sroot ip->i_flag |= IUPD|ICHG; 3807487Skre CHARGE(sc_tio * u.u_count); 3817423Sroot (*cdevsw[major(dev)].d_write)(dev); 3827423Sroot return; 3837423Sroot } 3847423Sroot if (u.u_count == 0) 3857423Sroot return; 3867423Sroot if ((ip->i_mode & IFMT) == IFREG && 3877423Sroot u.u_offset + u.u_count > u.u_limit[LIM_FSIZE]) { 3887423Sroot psignal(u.u_procp, SIGXFSZ); 3897423Sroot u.u_error = EMFILE; 3907423Sroot return; 3917423Sroot } 3927423Sroot if (type!=IFBLK) { 3937423Sroot dev = ip->i_dev; 3947423Sroot fs = ip->i_fs; 3957423Sroot bsize = fs->fs_bsize; 3967532Sroot } else 3977423Sroot bsize = BLKDEV_IOSIZE; 3987423Sroot do { 3997423Sroot lbn = u.u_offset / bsize; 4007423Sroot on = u.u_offset % bsize; 4017423Sroot n = MIN((unsigned)(bsize - on), u.u_count); 4027423Sroot if (type != IFBLK) { 4037423Sroot bn = fsbtodb(fs, bmap(ip, lbn, B_WRITE, (int)(on + n))); 4047532Sroot if (u.u_error || (long)bn<0) 4057423Sroot return; 4067423Sroot if(u.u_offset + n > ip->i_size && 4077423Sroot (type == IFDIR || type == IFREG || type == IFLNK)) 4087423Sroot ip->i_size = u.u_offset + n; 4097423Sroot size = blksize(fs, ip, lbn); 4107423Sroot } else { 4117423Sroot size = bsize; 4127423Sroot bn = lbn * (BLKDEV_IOSIZE/DEV_BSIZE); 4137423Sroot } 4147532Sroot count = howmany(size, DEV_BSIZE); 4157532Sroot for (i = 0; i < count; i += CLSIZE) 4167532Sroot if (mfind(dev, bn + i)) 4177532Sroot munhash(dev, bn + i); 4187532Sroot if (n == bsize) 4197423Sroot bp = getblk(dev, bn, size); 4207423Sroot else 4217423Sroot bp = bread(dev, bn, size); 4227423Sroot if (u.u_segflg != 1) { 4237423Sroot if (copyin(u.u_base, bp->b_un.b_addr + on, n)) { 4247423Sroot u.u_error = EFAULT; 4257423Sroot goto bad; 4267423Sroot } 4277423Sroot } else 4287423Sroot bcopy(u.u_base, bp->b_un.b_addr + on, n); 4297423Sroot u.u_base += n; 4307423Sroot u.u_offset += n; 4317423Sroot u.u_count -= n; 4327423Sroot bad: 4337423Sroot ; 4347423Sroot if (u.u_error != 0) 4357423Sroot brelse(bp); 4367423Sroot else { 4377423Sroot if ((ip->i_mode&IFMT) == IFDIR) 4387423Sroot /* 4397423Sroot * Writing to clear a directory entry. 4407423Sroot * Must insure the write occurs before 4417423Sroot * the inode is freed, or may end up 4427423Sroot * pointing at a new (different) file 4437423Sroot * if inode is quickly allocated again 4447423Sroot * and system crashes. 4457423Sroot */ 4467423Sroot bwrite(bp); 4477423Sroot else if (n + on == bsize) { 4487423Sroot bp->b_flags |= B_AGE; 4497423Sroot bawrite(bp); 4507423Sroot } else 4517423Sroot bdwrite(bp); 4527423Sroot } 4537423Sroot ip->i_flag |= IUPD|ICHG; 4547423Sroot if (u.u_ruid != 0) 4557423Sroot ip->i_mode &= ~(ISUID|ISGID); 4567423Sroot } while (u.u_error == 0 && u.u_count != 0); 4577423Sroot } 4587423Sroot 4597423Sroot /* 4607423Sroot * Move n bytes at byte location 4617423Sroot * &bp->b_un.b_addr[o] to/from (flag) the 4627423Sroot * user/kernel (u.segflg) area starting at u.base. 4637423Sroot * Update all the arguments by the number 4647423Sroot * of bytes moved. 4657423Sroot */ 4667423Sroot iomove(cp, n, flag) 4677423Sroot register caddr_t cp; 4687423Sroot register unsigned n; 4697423Sroot { 4707423Sroot register int t; 4717423Sroot 4727423Sroot if (n==0) 4737423Sroot return; 4747423Sroot if (u.u_segflg != 1) { 4757423Sroot if (flag==B_WRITE) 4767423Sroot t = copyin(u.u_base, (caddr_t)cp, n); 4777423Sroot else 4787423Sroot t = copyout((caddr_t)cp, u.u_base, n); 4797423Sroot if (t) { 4807423Sroot u.u_error = EFAULT; 4817423Sroot return; 4827423Sroot } 4837423Sroot } else 4847423Sroot if (flag == B_WRITE) 4857423Sroot bcopy(u.u_base, (caddr_t)cp, n); 4867423Sroot else 4877423Sroot bcopy((caddr_t)cp, u.u_base, n); 4887423Sroot u.u_base += n; 4897423Sroot u.u_offset += n; 4907423Sroot u.u_count -= n; 4917423Sroot } 492