1*7624Ssam /* sys_generic.c 5.5 82/08/01 */ 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" 87500Sroot #include "../h/fcntl.h" 97423Sroot #include "../h/file.h" 107423Sroot #include "../h/inode.h" 117423Sroot #include "../h/buf.h" 127423Sroot #include "../h/proc.h" 137423Sroot #include "../h/inline.h" 147423Sroot #include "../h/conf.h" 157423Sroot #include "../h/socket.h" 167423Sroot #include "../h/socketvar.h" 177423Sroot #include "../h/cmap.h" 187423Sroot #include "../h/vlimit.h" 197423Sroot #include "../h/fs.h" 207487Skre #ifdef MUSH 217487Skre #include "../h/quota.h" 227487Skre #include "../h/share.h" 237487Skre #else 247487Skre #define CHARGE(nothing) 257487Skre #endif 267500Sroot #include "../h/descrip.h" 277423Sroot 287423Sroot /* 297423Sroot * Read system call. 307423Sroot */ 317423Sroot read() 327423Sroot { 337423Sroot register struct file *fp; 347423Sroot register struct inode *ip; 357423Sroot register struct a { 367423Sroot int fdes; 377423Sroot char *cbuf; 387423Sroot unsigned count; 397423Sroot } *uap; 407423Sroot 417423Sroot uap = (struct a *)u.u_ap; 427423Sroot if ((int)uap->count < 0) { 437423Sroot u.u_error = EINVAL; 447423Sroot return; 457423Sroot } 467423Sroot GETF(fp, uap->fdes); 477423Sroot if ((fp->f_flag&FREAD) == 0) { 487423Sroot u.u_error = EBADF; 497423Sroot return; 507423Sroot } 517423Sroot u.u_base = (caddr_t)uap->cbuf; 527423Sroot u.u_count = uap->count; 537423Sroot u.u_segflg = 0; 547423Sroot if ((u.u_procp->p_flag&SNUSIG) && setjmp(u.u_qsav)) { 557423Sroot if (u.u_count == uap->count) 567423Sroot u.u_eosys = RESTARTSYS; 577500Sroot } else if (fp->f_type == DTYPE_SOCKET) 587423Sroot u.u_error = soreceive(fp->f_socket, (struct sockaddr *)0); 597423Sroot else { 607423Sroot ip = fp->f_inode; 617423Sroot u.u_offset = fp->f_offset; 627423Sroot if ((ip->i_mode&IFMT) == IFREG) { 637423Sroot ilock(ip); 647423Sroot readi(ip); 657423Sroot iunlock(ip); 667423Sroot } else 677423Sroot readi(ip); 687423Sroot fp->f_offset += uap->count - u.u_count; 697423Sroot } 707423Sroot u.u_r.r_val1 = uap->count - u.u_count; 717423Sroot } 727423Sroot 737423Sroot /* 747423Sroot * Write system call 757423Sroot */ 767423Sroot write() 777423Sroot { 787423Sroot register struct file *fp; 797423Sroot register struct inode *ip; 807423Sroot register struct a { 817423Sroot int fdes; 827423Sroot char *cbuf; 837423Sroot unsigned count; 847423Sroot } *uap; 857423Sroot 867423Sroot uap = (struct a *)u.u_ap; 877423Sroot if ((int)uap->count < 0) { 887423Sroot u.u_error = EINVAL; 897423Sroot return; 907423Sroot } 917423Sroot GETF(fp, uap->fdes); 927423Sroot if ((fp->f_flag&FWRITE) == 0) { 937423Sroot u.u_error = EBADF; 947423Sroot return; 957423Sroot } 967423Sroot u.u_base = (caddr_t)uap->cbuf; 977423Sroot u.u_count = uap->count; 987423Sroot u.u_segflg = 0; 997423Sroot if ((u.u_procp->p_flag&SNUSIG) && setjmp(u.u_qsav)) { 1007423Sroot if (u.u_count == uap->count) 1017423Sroot u.u_eosys = RESTARTSYS; 1027500Sroot } else if (fp->f_type == DTYPE_SOCKET) 1037423Sroot u.u_error = sosend(fp->f_socket, (struct sockaddr *)0); 1047423Sroot else { 1057423Sroot ip = fp->f_inode; 1067500Sroot if (fp->f_flag & O_APPEND) 1077500Sroot fp->f_offset = ip->i_size; 1087423Sroot u.u_offset = fp->f_offset; 1097423Sroot if ((ip->i_mode&IFMT) == IFREG) { 1107423Sroot ilock(ip); 1117423Sroot writei(ip); 1127423Sroot iunlock(ip); 1137423Sroot } else 1147423Sroot writei(ip); 1157423Sroot fp->f_offset += uap->count - u.u_count; 1167423Sroot } 1177423Sroot u.u_r.r_val1 = uap->count - u.u_count; 1187423Sroot } 1197423Sroot 1207500Sroot readv() 1217500Sroot { 1227423Sroot 1237500Sroot } 1247500Sroot 1257500Sroot writev() 1267500Sroot { 1277500Sroot 1287500Sroot } 1297500Sroot 1307423Sroot /* 1317423Sroot * Ioctl system call 132*7624Ssam * Check legality, execute common code, 133*7624Ssam * and switch out to individual device routine. 1347423Sroot */ 1357423Sroot ioctl() 1367423Sroot { 1377423Sroot register struct file *fp; 138*7624Ssam struct a { 1397423Sroot int fdes; 1407423Sroot int cmd; 1417423Sroot caddr_t cmarg; 1427423Sroot } *uap; 143*7624Ssam register int com, size; 144*7624Ssam char data[IOCPARM_MASK+1]; 1457423Sroot 1467423Sroot uap = (struct a *)u.u_ap; 1477423Sroot if ((fp = getf(uap->fdes)) == NULL) 1487423Sroot return; 1497423Sroot if ((fp->f_flag & (FREAD|FWRITE)) == 0) { 1507423Sroot u.u_error = EBADF; 1517423Sroot return; 1527423Sroot } 153*7624Ssam com = uap->cmd; 154*7624Ssam 155*7624Ssam #ifndef ONLYNEWIOCTLS 156*7624Ssam /* 157*7624Ssam * Map old style ioctl's into new for the 158*7624Ssam * sake of backwards compatibility (sigh). 159*7624Ssam */ 160*7624Ssam if ((com&~0xffff) == 0) { 161*7624Ssam com = mapioctl(com); 162*7624Ssam if (com == 0) { 163*7624Ssam u.u_error = EINVAL; 164*7624Ssam return; 165*7624Ssam } 166*7624Ssam } 167*7624Ssam #endif 168*7624Ssam if (com == FIOCLEX) { 1697423Sroot u.u_pofile[uap->fdes] |= EXCLOSE; 1707423Sroot return; 1717423Sroot } 172*7624Ssam if (com == FIONCLEX) { 1737423Sroot u.u_pofile[uap->fdes] &= ~EXCLOSE; 1747423Sroot return; 1757423Sroot } 176*7624Ssam 177*7624Ssam /* 178*7624Ssam * Interpret high order word to find 179*7624Ssam * amount of data to be copied to/from the 180*7624Ssam * user's address space. 181*7624Ssam * (this'll have to change if we have in+out ioctls) 182*7624Ssam */ 183*7624Ssam size = (com &~ (IOC_INOUT|IOC_VOID)) >> 16; 184*7624Ssam if (size > sizeof (data)) { 185*7624Ssam u.u_error = EFAULT; 1867423Sroot return; 1877423Sroot } 188*7624Ssam if ((com&IOC_IN) && size) { 189*7624Ssam if (copyin(uap->cmarg, (caddr_t)data, size)) { 190*7624Ssam u.u_error = EFAULT; 191*7624Ssam return; 192*7624Ssam } 193*7624Ssam } else 194*7624Ssam *(caddr_t *)data = uap->cmarg; 195*7624Ssam /* 196*7624Ssam * Zero the buffer on the stack so the user 197*7624Ssam * always gets back something deterministic. 198*7624Ssam */ 199*7624Ssam if ((com&IOC_OUT) && size) 200*7624Ssam bzero((caddr_t)data, size); 2017423Sroot 202*7624Ssam if (fp->f_type == DTYPE_SOCKET) 203*7624Ssam soioctl(fp->f_socket, com, data); 204*7624Ssam else { 205*7624Ssam register struct inode *ip = fp->f_inode; 206*7624Ssam int fmt = ip->i_mode & IFMT; 207*7624Ssam dev_t dev; 208*7624Ssam 209*7624Ssam if (fmt != IFCHR) { 210*7624Ssam if (com == FIONREAD && (fmt == IFREG || fmt == IFDIR)) { 211*7624Ssam *(off_t *)data = ip->i_size - fp->f_offset; 212*7624Ssam goto returndata; 213*7624Ssam } 214*7624Ssam if (com != FIONBIO && com != FIOASYNC) 215*7624Ssam u.u_error = ENOTTY; 2167423Sroot return; 217*7624Ssam } 218*7624Ssam dev = ip->i_rdev; 219*7624Ssam u.u_r.r_val1 = 0; 220*7624Ssam if ((u.u_procp->p_flag&SNUSIG) && setjmp(u.u_qsav)) { 221*7624Ssam u.u_eosys = RESTARTSYS; 222*7624Ssam return; 223*7624Ssam } 224*7624Ssam (*cdevsw[major(dev)].d_ioctl)(dev, com, data, 0); 2257423Sroot } 226*7624Ssam 227*7624Ssam returndata: 228*7624Ssam /* 229*7624Ssam * Copy any data to user, size was 230*7624Ssam * already set and checked above. 231*7624Ssam */ 232*7624Ssam if ((com&IOC_OUT) && size && copyout(data, uap->cmarg, size)) 233*7624Ssam u.u_error = EFAULT; 2347423Sroot } 2357423Sroot 2367423Sroot /* 2377423Sroot * Do nothing specific version of line 2387423Sroot * discipline specific ioctl command. 2397423Sroot */ 2407423Sroot /*ARGSUSED*/ 241*7624Ssam nullioctl(tp, cmd, data, flags) 2427423Sroot struct tty *tp; 243*7624Ssam char *data; 244*7624Ssam int flags; 2457423Sroot { 2467423Sroot 247*7624Ssam #ifdef lint 248*7624Ssam tp = tp; data = data; flags = flags; 249*7624Ssam #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 #ifdef UNFAST 3307423Sroot iomove(bp->b_un.b_addr + on, n, B_READ); 3317423Sroot #else 3327423Sroot if (u.u_segflg != 1) { 3337423Sroot if (copyout(bp->b_un.b_addr+on, u.u_base, n)) { 3347423Sroot u.u_error = EFAULT; 3357423Sroot goto bad; 3367423Sroot } 3377423Sroot } else 3387423Sroot bcopy(bp->b_un.b_addr + on, u.u_base, n); 3397423Sroot u.u_base += n; 3407423Sroot u.u_offset += n; 3417423Sroot u.u_count -= n; 3427423Sroot bad: 3437423Sroot ; 3447423Sroot #endif 3457423Sroot } 3467423Sroot if (n + on == bsize || u.u_offset == ip->i_size) 3477423Sroot bp->b_flags |= B_AGE; 3487423Sroot brelse(bp); 3497423Sroot } while (u.u_error == 0 && u.u_count != 0 && n != 0); 3507423Sroot } 3517423Sroot 3527423Sroot /* 3537423Sroot * Write the file corresponding to 3547423Sroot * the inode pointed at by the argument. 3557423Sroot * The actual write arguments are found 3567423Sroot * in the variables: 3577423Sroot * u_base core address for source 3587423Sroot * u_offset byte offset in file 3597423Sroot * u_count number of bytes to write 3607423Sroot * u_segflg write to kernel/user/user I 3617423Sroot */ 3627423Sroot writei(ip) 3637423Sroot register struct inode *ip; 3647423Sroot { 3657423Sroot struct buf *bp; 3667423Sroot register struct fs *fs; 3677423Sroot dev_t dev; 3687423Sroot daddr_t lbn, bn; 3697423Sroot register int on, type; 3707423Sroot register unsigned n; 3717423Sroot long bsize; 3727423Sroot int size, i, count; 3737423Sroot extern int mem_no; 3747423Sroot 3757423Sroot dev = (dev_t)ip->i_rdev; 3767423Sroot if (u.u_offset < 0 && ((ip->i_mode&IFMT) != IFCHR || 3777423Sroot mem_no != major(dev)) ) { 3787423Sroot u.u_error = EINVAL; 3797423Sroot return; 3807423Sroot } 3817423Sroot type = ip->i_mode & IFMT; 3827423Sroot if (type == IFCHR) { 3837423Sroot ip->i_flag |= IUPD|ICHG; 3847487Skre CHARGE(sc_tio * u.u_count); 3857423Sroot (*cdevsw[major(dev)].d_write)(dev); 3867423Sroot return; 3877423Sroot } 3887423Sroot if (u.u_count == 0) 3897423Sroot return; 3907423Sroot if ((ip->i_mode & IFMT) == IFREG && 3917423Sroot u.u_offset + u.u_count > u.u_limit[LIM_FSIZE]) { 3927423Sroot psignal(u.u_procp, SIGXFSZ); 3937423Sroot u.u_error = EMFILE; 3947423Sroot return; 3957423Sroot } 3967423Sroot if (type!=IFBLK) { 3977423Sroot dev = ip->i_dev; 3987423Sroot fs = ip->i_fs; 3997423Sroot bsize = fs->fs_bsize; 4007532Sroot } else 4017423Sroot bsize = BLKDEV_IOSIZE; 4027423Sroot do { 4037423Sroot lbn = u.u_offset / bsize; 4047423Sroot on = u.u_offset % bsize; 4057423Sroot n = MIN((unsigned)(bsize - on), u.u_count); 4067423Sroot if (type != IFBLK) { 4077423Sroot bn = fsbtodb(fs, bmap(ip, lbn, B_WRITE, (int)(on + n))); 4087532Sroot if (u.u_error || (long)bn<0) 4097423Sroot return; 4107423Sroot if(u.u_offset + n > ip->i_size && 4117423Sroot (type == IFDIR || type == IFREG || type == IFLNK)) 4127423Sroot ip->i_size = u.u_offset + n; 4137423Sroot size = blksize(fs, ip, lbn); 4147423Sroot } else { 4157423Sroot size = bsize; 4167423Sroot bn = lbn * (BLKDEV_IOSIZE/DEV_BSIZE); 4177423Sroot } 4187532Sroot count = howmany(size, DEV_BSIZE); 4197532Sroot for (i = 0; i < count; i += CLSIZE) 4207532Sroot if (mfind(dev, bn + i)) 4217532Sroot munhash(dev, bn + i); 4227532Sroot if (n == bsize) 4237423Sroot bp = getblk(dev, bn, size); 4247423Sroot else 4257423Sroot bp = bread(dev, bn, size); 4267423Sroot #ifdef UNFAST 4277423Sroot iomove(bp->b_un.b_addr + on, n, B_WRITE); 4287423Sroot #else 4297423Sroot if (u.u_segflg != 1) { 4307423Sroot if (copyin(u.u_base, bp->b_un.b_addr + on, n)) { 4317423Sroot u.u_error = EFAULT; 4327423Sroot goto bad; 4337423Sroot } 4347423Sroot } else 4357423Sroot bcopy(u.u_base, bp->b_un.b_addr + on, n); 4367423Sroot u.u_base += n; 4377423Sroot u.u_offset += n; 4387423Sroot u.u_count -= n; 4397423Sroot bad: 4407423Sroot ; 4417423Sroot #endif 4427423Sroot if (u.u_error != 0) 4437423Sroot brelse(bp); 4447423Sroot else { 4457423Sroot if ((ip->i_mode&IFMT) == IFDIR) 4467423Sroot /* 4477423Sroot * Writing to clear a directory entry. 4487423Sroot * Must insure the write occurs before 4497423Sroot * the inode is freed, or may end up 4507423Sroot * pointing at a new (different) file 4517423Sroot * if inode is quickly allocated again 4527423Sroot * and system crashes. 4537423Sroot */ 4547423Sroot bwrite(bp); 4557423Sroot else if (n + on == bsize) { 4567423Sroot bp->b_flags |= B_AGE; 4577423Sroot bawrite(bp); 4587423Sroot } else 4597423Sroot bdwrite(bp); 4607423Sroot } 4617423Sroot ip->i_flag |= IUPD|ICHG; 4627423Sroot if (u.u_ruid != 0) 4637423Sroot ip->i_mode &= ~(ISUID|ISGID); 4647423Sroot } while (u.u_error == 0 && u.u_count != 0); 4657423Sroot } 4667423Sroot 4677423Sroot /* 4687423Sroot * Move n bytes at byte location 4697423Sroot * &bp->b_un.b_addr[o] to/from (flag) the 4707423Sroot * user/kernel (u.segflg) area starting at u.base. 4717423Sroot * Update all the arguments by the number 4727423Sroot * of bytes moved. 4737423Sroot */ 4747423Sroot iomove(cp, n, flag) 4757423Sroot register caddr_t cp; 4767423Sroot register unsigned n; 4777423Sroot { 4787423Sroot register int t; 4797423Sroot 4807423Sroot if (n==0) 4817423Sroot return; 4827423Sroot if (u.u_segflg != 1) { 4837423Sroot if (flag==B_WRITE) 4847423Sroot t = copyin(u.u_base, (caddr_t)cp, n); 4857423Sroot else 4867423Sroot t = copyout((caddr_t)cp, u.u_base, n); 4877423Sroot if (t) { 4887423Sroot u.u_error = EFAULT; 4897423Sroot return; 4907423Sroot } 4917423Sroot } else 4927423Sroot if (flag == B_WRITE) 4937423Sroot bcopy(u.u_base, (caddr_t)cp, n); 4947423Sroot else 4957423Sroot bcopy((caddr_t)cp, u.u_base, n); 4967423Sroot u.u_base += n; 4977423Sroot u.u_offset += n; 4987423Sroot u.u_count -= n; 4997423Sroot } 500