1*9864Ssam /* sys_generic.c 5.27 82/12/21 */ 27423Sroot 37423Sroot #include "../h/param.h" 47423Sroot #include "../h/systm.h" 57423Sroot #include "../h/dir.h" 67423Sroot #include "../h/user.h" 79560Ssam #include "../h/ioctl.h" 87423Sroot #include "../h/tty.h" 97423Sroot #include "../h/file.h" 107423Sroot #include "../h/inode.h" 117423Sroot #include "../h/buf.h" 127423Sroot #include "../h/proc.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" 258668Sroot #include "../h/cmap.h" 267423Sroot 277423Sroot /* 287423Sroot * Read system call. 297423Sroot */ 307423Sroot read() 317423Sroot { 327423Sroot register struct a { 337423Sroot int fdes; 347423Sroot char *cbuf; 357423Sroot unsigned count; 367820Sroot } *uap = (struct a *)u.u_ap; 377746Sroot struct uio auio; 387746Sroot struct iovec aiov; 397423Sroot 407820Sroot aiov.iov_base = (caddr_t)uap->cbuf; 417820Sroot aiov.iov_len = uap->count; 427820Sroot auio.uio_iov = &aiov; 437820Sroot auio.uio_iovcnt = 1; 447820Sroot rwuio(&auio, UIO_READ); 457820Sroot } 467820Sroot 477820Sroot readv() 487820Sroot { 497820Sroot register struct a { 507820Sroot int fdes; 517820Sroot struct iovec *iovp; 527820Sroot int iovcnt; 537820Sroot } *uap = (struct a *)u.u_ap; 547820Sroot struct uio auio; 557820Sroot struct iovec aiov[16]; /* XXX */ 567820Sroot 577820Sroot if (uap->iovcnt <= 0 || uap->iovcnt > sizeof(aiov)/sizeof(aiov[0])) { 587423Sroot u.u_error = EINVAL; 597423Sroot return; 607423Sroot } 617820Sroot auio.uio_iov = aiov; 627820Sroot auio.uio_iovcnt = uap->iovcnt; 637820Sroot if (copyin((caddr_t)uap->iovp, (caddr_t)aiov, 647820Sroot (unsigned)(uap->iovcnt * sizeof (struct iovec)))) { 657820Sroot u.u_error = EFAULT; 667423Sroot return; 677423Sroot } 687820Sroot rwuio(&auio, UIO_READ); 697423Sroot } 707423Sroot 717423Sroot /* 727423Sroot * Write system call 737423Sroot */ 747423Sroot write() 757423Sroot { 767423Sroot register struct a { 777423Sroot int fdes; 787423Sroot char *cbuf; 797820Sroot int count; 807820Sroot } *uap = (struct a *)u.u_ap; 817820Sroot struct uio auio; 827820Sroot struct iovec aiov; 837423Sroot 847820Sroot auio.uio_iov = &aiov; 857820Sroot auio.uio_iovcnt = 1; 867820Sroot aiov.iov_base = uap->cbuf; 877820Sroot aiov.iov_len = uap->count; 887820Sroot rwuio(&auio, UIO_WRITE); 897820Sroot } 907820Sroot 917820Sroot writev() 927820Sroot { 937820Sroot register struct a { 947820Sroot int fdes; 957820Sroot struct iovec *iovp; 967820Sroot int iovcnt; 977820Sroot } *uap = (struct a *)u.u_ap; 987820Sroot struct uio auio; 997820Sroot struct iovec aiov[16]; /* XXX */ 1007820Sroot 1017820Sroot if (uap->iovcnt <= 0 || uap->iovcnt > sizeof(aiov)/sizeof(aiov[0])) { 1027423Sroot u.u_error = EINVAL; 1037423Sroot return; 1047423Sroot } 1057820Sroot auio.uio_iov = aiov; 1067820Sroot auio.uio_iovcnt = uap->iovcnt; 1077820Sroot if (copyin((caddr_t)uap->iovp, (caddr_t)aiov, 1087820Sroot (unsigned)(uap->iovcnt * sizeof (struct iovec)))) { 1097820Sroot u.u_error = EFAULT; 1107820Sroot return; 1117820Sroot } 1127820Sroot rwuio(&auio, UIO_WRITE); 1137820Sroot } 1147820Sroot 1157820Sroot rwuio(uio, rw) 1167820Sroot register struct uio *uio; 1177820Sroot enum uio_rw rw; 1187820Sroot { 1197820Sroot struct a { 1207820Sroot int fdes; 1217820Sroot }; 1227820Sroot register struct file *fp; 1237820Sroot register struct iovec *iov; 1247820Sroot register struct inode *ip; 1257820Sroot int i, count; 1267820Sroot 1277820Sroot GETF(fp, ((struct a *)u.u_ap)->fdes); 1287820Sroot if ((fp->f_flag&(rw==UIO_READ ? FREAD : FWRITE)) == 0) { 1297423Sroot u.u_error = EBADF; 1307423Sroot return; 1317423Sroot } 1327820Sroot uio->uio_resid = 0; 1337820Sroot uio->uio_segflg = 0; 1347820Sroot iov = uio->uio_iov; 1357820Sroot for (i = 0; i < uio->uio_iovcnt; i++) { 1367820Sroot if (iov->iov_len < 0) { 1377820Sroot u.u_error = EINVAL; 1387820Sroot return; 1397820Sroot } 1407820Sroot uio->uio_resid += iov->iov_len; 1417820Sroot if (uio->uio_resid < 0) { 1427820Sroot u.u_error = EINVAL; 1437820Sroot return; 1447820Sroot } 1457820Sroot } 1467820Sroot count = uio->uio_resid; 1478118Sroot if ((u.u_procp->p_flag&SNUSIG) && setjmp(&u.u_qsave)) { 1487820Sroot if (uio->uio_resid == count) 1497423Sroot u.u_eosys = RESTARTSYS; 1507820Sroot } else if (fp->f_type == DTYPE_SOCKET) { 1517820Sroot int sosend(), soreceive(); 1527820Sroot u.u_error = 1537820Sroot (*(rw==UIO_READ?soreceive:sosend)) 1548449Sroot (fp->f_socket, (struct sockaddr *)0, uio, 0); 1557820Sroot } else { 1567423Sroot ip = fp->f_inode; 1577820Sroot uio->uio_offset = fp->f_offset; 1587423Sroot if ((ip->i_mode&IFMT) == IFREG) { 1598449Sroot ILOCK(ip); 1607820Sroot u.u_error = rwip(ip, uio, rw); 1618449Sroot IUNLOCK(ip); 1627423Sroot } else 1637820Sroot u.u_error = rwip(ip, uio, rw); 1647820Sroot fp->f_offset += count - uio->uio_resid; 1657423Sroot } 1667820Sroot u.u_r.r_val1 = count - uio->uio_resid; 1677423Sroot } 1687423Sroot 1697820Sroot rdwri(rw, ip, base, len, offset, segflg, aresid) 1707820Sroot struct inode *ip; 1717820Sroot caddr_t base; 1727820Sroot int len, offset, segflg; 1737820Sroot int *aresid; 1747820Sroot enum uio_rw rw; 1757500Sroot { 1767820Sroot struct uio auio; 1777820Sroot struct iovec aiov; 1787820Sroot int error; 1797423Sroot 1807820Sroot auio.uio_iov = &aiov; 1817820Sroot auio.uio_iovcnt = 1; 1827820Sroot aiov.iov_base = base; 1837820Sroot aiov.iov_len = len; 1847820Sroot auio.uio_resid = len; 1857820Sroot auio.uio_offset = offset; 1867820Sroot auio.uio_segflg = segflg; 1877820Sroot error = rwip(ip, &auio, rw); 1887820Sroot if (aresid) 1897820Sroot *aresid = auio.uio_resid; 1907820Sroot else 1917820Sroot if (auio.uio_resid) 1927820Sroot error = EIO; 1937820Sroot return (error); 1947500Sroot } 1957500Sroot 1967820Sroot rwip(ip, uio, rw) 1977820Sroot register struct inode *ip; 1987820Sroot register struct uio *uio; 1997820Sroot enum uio_rw rw; 2007500Sroot { 2017820Sroot dev_t dev = (dev_t)ip->i_rdev; 2027820Sroot struct buf *bp; 2037820Sroot struct fs *fs; 2047820Sroot daddr_t lbn, bn; 2058668Sroot register int n, on, type; 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"); 2139270Ssam if (rw == UIO_READ && uio->uio_resid == 0) 2149270Ssam return (0); 2157820Sroot if (uio->uio_offset < 0 && 2167820Sroot ((ip->i_mode&IFMT) != IFCHR || mem_no != major(dev))) 2179155Ssam return (EINVAL); 2189155Ssam if (rw == UIO_READ) 2197820Sroot ip->i_flag |= IACC; 2207820Sroot type = ip->i_mode&IFMT; 2217820Sroot if (type == IFCHR) { 2227820Sroot #ifdef QUOTA 2237820Sroot register c = uio->uio_resid; 2247820Sroot #endif 2257820Sroot if (rw == UIO_READ) 2268519Sroot u.u_error = (*cdevsw[major(dev)].d_read)(dev, uio); 2277820Sroot else { 2287820Sroot ip->i_flag |= IUPD|ICHG; 2298519Sroot u.u_error = (*cdevsw[major(dev)].d_write)(dev, uio); 2307820Sroot } 2317820Sroot CHARGE(sc_tio * (c - uio->uio_resid)); 2327820Sroot return (u.u_error); 2337820Sroot } 2349155Ssam if (uio->uio_resid == 0) 2359270Ssam return (0); 2367820Sroot if (rw == UIO_WRITE && type == IFREG && 2378036Sroot uio->uio_offset + uio->uio_resid > 2388036Sroot u.u_rlimit[RLIMIT_FSIZE].rlim_cur) { 2397820Sroot psignal(u.u_procp, SIGXFSZ); 2407820Sroot return (EMFILE); 2417820Sroot } 2427820Sroot if (type != IFBLK) { 2437820Sroot dev = ip->i_dev; 2447820Sroot fs = ip->i_fs; 2457820Sroot bsize = fs->fs_bsize; 2467820Sroot } else 2477820Sroot bsize = BLKDEV_IOSIZE; 2487820Sroot do { 2497820Sroot lbn = uio->uio_offset / bsize; 2507820Sroot on = uio->uio_offset % bsize; 2517820Sroot n = MIN((unsigned)(bsize - on), uio->uio_resid); 2527820Sroot if (type != IFBLK) { 2537820Sroot if (rw == UIO_READ) { 2547820Sroot int diff = ip->i_size - uio->uio_offset; 2557820Sroot if (diff <= 0) 2567820Sroot return (0); 2577820Sroot if (diff < n) 2587820Sroot n = diff; 2597820Sroot } 2607820Sroot bn = fsbtodb(fs, 2617820Sroot bmap(ip, lbn, rw == UIO_WRITE ? B_WRITE: B_READ, (int)(on+n))); 2627820Sroot if (u.u_error || rw == UIO_WRITE && (long)bn<0) 2637820Sroot return (u.u_error); 2647820Sroot if (rw == UIO_WRITE && uio->uio_offset + n > ip->i_size && 2657820Sroot (type == IFDIR || type == IFREG || type == IFLNK)) 2667820Sroot ip->i_size = uio->uio_offset + n; 2677820Sroot size = blksize(fs, ip, lbn); 2687820Sroot } else { 2697820Sroot bn = lbn * (BLKDEV_IOSIZE/DEV_BSIZE); 2707820Sroot rablock = bn + (BLKDEV_IOSIZE/DEV_BSIZE); 2717820Sroot rasize = size = bsize; 2727820Sroot } 2737820Sroot if (rw == UIO_READ) { 2747820Sroot if ((long)bn<0) { 2757820Sroot bp = geteblk(size); 2767820Sroot clrbuf(bp); 2777820Sroot } else if (ip->i_lastr + 1 == lbn) 2787820Sroot bp = breada(dev, bn, size, rablock, rasize); 2797820Sroot else 2807820Sroot bp = bread(dev, bn, size); 2817820Sroot ip->i_lastr = lbn; 2827820Sroot } else { 2837820Sroot int i, count; 2848626Sroot extern struct cmap *mfind(); 2857820Sroot 2867820Sroot count = howmany(size, DEV_BSIZE); 2877820Sroot for (i = 0; i < count; i += CLSIZE) 2887820Sroot if (mfind(dev, bn + i)) 2897820Sroot munhash(dev, bn + i); 2907820Sroot if (n == bsize) 2917820Sroot bp = getblk(dev, bn, size); 2927820Sroot else 2937820Sroot bp = bread(dev, bn, size); 2947820Sroot } 2957820Sroot n = MIN(n, size - bp->b_resid); 2967820Sroot if (bp->b_flags & B_ERROR) { 2977820Sroot error = EIO; 2987820Sroot brelse(bp); 2997820Sroot goto bad; 3007820Sroot } 3017820Sroot u.u_error = 3028791Sroot uiomove(bp->b_un.b_addr+on, n, rw, uio); 3037820Sroot if (rw == UIO_READ) { 3047820Sroot if (n + on == bsize || uio->uio_offset == ip->i_size) 3057820Sroot bp->b_flags |= B_AGE; 3067820Sroot brelse(bp); 3077820Sroot } else { 3087820Sroot if ((ip->i_mode&IFMT) == IFDIR) 3097820Sroot bwrite(bp); 3107820Sroot else if (n + on == bsize) { 3117820Sroot bp->b_flags |= B_AGE; 3127820Sroot bawrite(bp); 3137820Sroot } else 3147820Sroot bdwrite(bp); 3157820Sroot ip->i_flag |= IUPD|ICHG; 3167820Sroot if (u.u_ruid != 0) 3177820Sroot ip->i_mode &= ~(ISUID|ISGID); 3187820Sroot } 3197820Sroot } while (u.u_error == 0 && uio->uio_resid > 0 && n != 0); 3207820Sroot bad: 3217820Sroot return (error); 3227500Sroot } 3237500Sroot 3247820Sroot uiomove(cp, n, rw, uio) 3257820Sroot register caddr_t cp; 3267820Sroot register int n; 3277820Sroot enum uio_rw rw; 3287820Sroot register struct uio *uio; 3297820Sroot { 3307820Sroot register struct iovec *iov; 3317820Sroot u_int cnt; 332*9864Ssam int error = 0; 3337820Sroot 3347820Sroot while (n > 0 && uio->uio_resid) { 3357820Sroot iov = uio->uio_iov; 3367820Sroot cnt = iov->iov_len; 3377820Sroot if (cnt == 0) { 3387820Sroot uio->uio_iov++; 3397820Sroot uio->uio_iovcnt--; 3407820Sroot continue; 3417820Sroot } 3427820Sroot if (cnt > n) 3437820Sroot cnt = n; 3447820Sroot switch (uio->uio_segflg) { 3457820Sroot 3467820Sroot case 0: 3477820Sroot case 2: 3487820Sroot if (rw == UIO_READ) 3497820Sroot error = copyout(cp, iov->iov_base, cnt); 3507820Sroot else 3517820Sroot error = copyin(iov->iov_base, cp, cnt); 3527820Sroot if (error) 3537820Sroot return (error); 3547820Sroot break; 3557820Sroot 3567820Sroot case 1: 3577820Sroot if (rw == UIO_READ) 3587820Sroot bcopy((caddr_t)cp, iov->iov_base, cnt); 3597820Sroot else 3607820Sroot bcopy(iov->iov_base, (caddr_t)cp, cnt); 3617820Sroot break; 3627820Sroot } 3637820Sroot iov->iov_base += cnt; 3647820Sroot iov->iov_len -= cnt; 3657820Sroot uio->uio_resid -= cnt; 3667820Sroot uio->uio_offset += cnt; 3677820Sroot cp += cnt; 3687820Sroot n -= cnt; 3697820Sroot } 3707820Sroot return (error); 3717820Sroot } 3727820Sroot 3737423Sroot /* 3747820Sroot * Give next character to user as result of read. 3757820Sroot */ 3767820Sroot ureadc(c, uio) 3777820Sroot register int c; 3787820Sroot register struct uio *uio; 3797820Sroot { 3807820Sroot register struct iovec *iov; 3817820Sroot 3827820Sroot again: 3837820Sroot if (uio->uio_iovcnt == 0) 3847820Sroot panic("ureadc"); 3857820Sroot iov = uio->uio_iov; 3867820Sroot if (iov->iov_len <= 0 || uio->uio_resid <= 0) { 3877820Sroot uio->uio_iovcnt--; 3887820Sroot uio->uio_iov++; 3897820Sroot goto again; 3907820Sroot } 3917820Sroot switch (uio->uio_segflg) { 3927820Sroot 3937820Sroot case 0: 3947820Sroot if (subyte(iov->iov_base, c) < 0) 3957820Sroot return (EFAULT); 3967820Sroot break; 3977820Sroot 3987820Sroot case 1: 3997820Sroot *iov->iov_base = c; 4007820Sroot break; 4017820Sroot 4027820Sroot case 2: 4037820Sroot if (suibyte(iov->iov_base, c) < 0) 4047820Sroot return (EFAULT); 4057820Sroot break; 4067820Sroot } 4077820Sroot iov->iov_base++; 4087820Sroot iov->iov_len--; 4097820Sroot uio->uio_resid--; 4107820Sroot uio->uio_offset++; 4117820Sroot return (0); 4127820Sroot } 4137820Sroot 4148767Sroot #ifdef notdef 4157820Sroot /* 4167820Sroot * Get next character written in by user from uio. 4177820Sroot */ 4187820Sroot uwritec(uio) 4197820Sroot struct uio *uio; 4207820Sroot { 4217820Sroot register struct iovec *iov; 4227820Sroot register int c; 4237820Sroot 4247820Sroot again: 4257820Sroot if (uio->uio_iovcnt <= 0 || uio->uio_resid <= 0) 4267820Sroot panic("uwritec"); 4277820Sroot iov = uio->uio_iov; 4287820Sroot if (iov->iov_len == 0) { 4297820Sroot uio->uio_iovcnt--; 4307820Sroot uio->uio_iov++; 4317820Sroot goto again; 4327820Sroot } 4337820Sroot switch (uio->uio_segflg) { 4347820Sroot 4357820Sroot case 0: 4367820Sroot c = fubyte(iov->iov_base); 4377820Sroot break; 4387820Sroot 4397820Sroot case 1: 4407820Sroot c = *iov->iov_base & 0377; 4417820Sroot break; 4427820Sroot 4437820Sroot case 2: 4447820Sroot c = fuibyte(iov->iov_base); 4457820Sroot break; 4467820Sroot } 4477820Sroot if (c < 0) 4487820Sroot return (-1); 4497820Sroot iov->iov_base++; 4507820Sroot iov->iov_len--; 4517820Sroot uio->uio_resid--; 4527820Sroot uio->uio_offset++; 4537820Sroot return (c & 0377); 4547820Sroot } 4558767Sroot #endif 4567820Sroot 4577820Sroot /* 4587423Sroot * Ioctl system call 4597624Ssam * Check legality, execute common code, 4607624Ssam * and switch out to individual device routine. 4617423Sroot */ 4627423Sroot ioctl() 4637423Sroot { 4647423Sroot register struct file *fp; 4657624Ssam struct a { 4667423Sroot int fdes; 4677423Sroot int cmd; 4687423Sroot caddr_t cmarg; 4697423Sroot } *uap; 4707820Sroot register int com; 4717820Sroot register u_int size; 4727624Ssam char data[IOCPARM_MASK+1]; 4737423Sroot 4747423Sroot uap = (struct a *)u.u_ap; 4757423Sroot if ((fp = getf(uap->fdes)) == NULL) 4767423Sroot return; 4777423Sroot if ((fp->f_flag & (FREAD|FWRITE)) == 0) { 4787423Sroot u.u_error = EBADF; 4797423Sroot return; 4807423Sroot } 4817624Ssam com = uap->cmd; 4827624Ssam 4837699Ssam #ifndef NOCOMPAT 4847624Ssam /* 4857624Ssam * Map old style ioctl's into new for the 4867624Ssam * sake of backwards compatibility (sigh). 4877624Ssam */ 4887624Ssam if ((com&~0xffff) == 0) { 4897624Ssam com = mapioctl(com); 4907624Ssam if (com == 0) { 4917624Ssam u.u_error = EINVAL; 4927624Ssam return; 4937624Ssam } 4947624Ssam } 4957624Ssam #endif 4967624Ssam if (com == FIOCLEX) { 4979592Ssam u.u_pofile[uap->fdes] |= UF_EXCLOSE; 4987423Sroot return; 4997423Sroot } 5007624Ssam if (com == FIONCLEX) { 5019592Ssam u.u_pofile[uap->fdes] &= ~UF_EXCLOSE; 5027423Sroot return; 5037423Sroot } 5047624Ssam 5057624Ssam /* 5067624Ssam * Interpret high order word to find 5077624Ssam * amount of data to be copied to/from the 5087624Ssam * user's address space. 5097624Ssam */ 5107624Ssam size = (com &~ (IOC_INOUT|IOC_VOID)) >> 16; 5117624Ssam if (size > sizeof (data)) { 5127624Ssam u.u_error = EFAULT; 5137423Sroot return; 5147423Sroot } 5157699Ssam if (com&IOC_IN && size) { 5167820Sroot if (copyin(uap->cmarg, (caddr_t)data, (u_int)size)) { 5177624Ssam u.u_error = EFAULT; 5187624Ssam return; 5197624Ssam } 5207624Ssam } else 5217624Ssam *(caddr_t *)data = uap->cmarg; 5227624Ssam /* 5237624Ssam * Zero the buffer on the stack so the user 5247624Ssam * always gets back something deterministic. 5257624Ssam */ 5267624Ssam if ((com&IOC_OUT) && size) 5277624Ssam bzero((caddr_t)data, size); 5287423Sroot 5297624Ssam if (fp->f_type == DTYPE_SOCKET) 5308564Sroot u.u_error = soioctl(fp->f_socket, com, data); 5317624Ssam else { 5327624Ssam register struct inode *ip = fp->f_inode; 5337624Ssam int fmt = ip->i_mode & IFMT; 5347624Ssam dev_t dev; 5357624Ssam 5367624Ssam if (fmt != IFCHR) { 5377624Ssam if (com == FIONREAD && (fmt == IFREG || fmt == IFDIR)) { 5387624Ssam *(off_t *)data = ip->i_size - fp->f_offset; 5397624Ssam goto returndata; 5407624Ssam } 5417624Ssam if (com != FIONBIO && com != FIOASYNC) 5427624Ssam u.u_error = ENOTTY; 5437423Sroot return; 5447624Ssam } 5457624Ssam dev = ip->i_rdev; 5467624Ssam u.u_r.r_val1 = 0; 5478118Sroot if ((u.u_procp->p_flag&SNUSIG) && setjmp(&u.u_qsave)) { 5487624Ssam u.u_eosys = RESTARTSYS; 5497624Ssam return; 5507624Ssam } 5518564Sroot u.u_error = (*cdevsw[major(dev)].d_ioctl)(dev, com, data, 0); 5527423Sroot } 5537624Ssam 5547624Ssam returndata: 5557624Ssam /* 5567624Ssam * Copy any data to user, size was 5577624Ssam * already set and checked above. 5587624Ssam */ 5597820Sroot if (u.u_error == 0 && (com&IOC_OUT)) 5607820Sroot if (size && copyout(data, uap->cmarg, (u_int)size)) 5617699Ssam u.u_error = EFAULT; 5627423Sroot } 5637423Sroot 5647423Sroot /* 5657423Sroot * Do nothing specific version of line 5667423Sroot * discipline specific ioctl command. 5677423Sroot */ 5687423Sroot /*ARGSUSED*/ 5697624Ssam nullioctl(tp, cmd, data, flags) 5707423Sroot struct tty *tp; 5717624Ssam char *data; 5727624Ssam int flags; 5737423Sroot { 5747423Sroot 5757624Ssam #ifdef lint 5767624Ssam tp = tp; data = data; flags = flags; 5777624Ssam #endif 5788564Sroot return (-1); 5797423Sroot } 5808103Sroot 5818103Sroot ostty() 5828103Sroot { 5838103Sroot 5848103Sroot } 5858103Sroot 5868103Sroot ogtty() 5878103Sroot { 5888103Sroot 5898103Sroot } 590