1*9999Ssam /* sys_generic.c 5.29 82/12/28 */ 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; 63*9999Ssam u.u_error = copyin((caddr_t)uap->iovp, (caddr_t)aiov, 64*9999Ssam (unsigned)(uap->iovcnt * sizeof (struct iovec))); 65*9999Ssam if (u.u_error) 667423Sroot return; 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; 106*9999Ssam u.u_error = copyin((caddr_t)uap->iovp, (caddr_t)aiov, 107*9999Ssam (unsigned)(uap->iovcnt * sizeof (struct iovec))); 108*9999Ssam if (u.u_error) 1097820Sroot return; 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; 2038668Sroot register int n, on, type; 2047820Sroot int size; 2057820Sroot long bsize; 2067820Sroot extern int mem_no; 2077820Sroot int error = 0; 2087500Sroot 2097820Sroot if (rw != UIO_READ && rw != UIO_WRITE) 2107820Sroot panic("rwip"); 2119270Ssam if (rw == UIO_READ && uio->uio_resid == 0) 2129270Ssam return (0); 2137820Sroot if (uio->uio_offset < 0 && 2147820Sroot ((ip->i_mode&IFMT) != IFCHR || mem_no != major(dev))) 2159155Ssam return (EINVAL); 2169155Ssam if (rw == UIO_READ) 2177820Sroot ip->i_flag |= IACC; 2187820Sroot type = ip->i_mode&IFMT; 2197820Sroot if (type == IFCHR) { 2207820Sroot #ifdef QUOTA 2217820Sroot register c = uio->uio_resid; 2227820Sroot #endif 2237820Sroot if (rw == UIO_READ) 2248519Sroot u.u_error = (*cdevsw[major(dev)].d_read)(dev, uio); 2257820Sroot else { 2267820Sroot ip->i_flag |= IUPD|ICHG; 2278519Sroot u.u_error = (*cdevsw[major(dev)].d_write)(dev, uio); 2287820Sroot } 2297820Sroot CHARGE(sc_tio * (c - uio->uio_resid)); 2307820Sroot return (u.u_error); 2317820Sroot } 2329155Ssam if (uio->uio_resid == 0) 2339270Ssam return (0); 2347820Sroot if (rw == UIO_WRITE && type == IFREG && 2358036Sroot uio->uio_offset + uio->uio_resid > 2368036Sroot u.u_rlimit[RLIMIT_FSIZE].rlim_cur) { 2377820Sroot psignal(u.u_procp, SIGXFSZ); 2387820Sroot return (EMFILE); 2397820Sroot } 2407820Sroot if (type != IFBLK) { 2417820Sroot dev = ip->i_dev; 2427820Sroot fs = ip->i_fs; 2437820Sroot bsize = fs->fs_bsize; 2447820Sroot } else 2457820Sroot bsize = BLKDEV_IOSIZE; 2467820Sroot do { 2477820Sroot lbn = uio->uio_offset / bsize; 2487820Sroot on = uio->uio_offset % bsize; 2497820Sroot n = MIN((unsigned)(bsize - on), uio->uio_resid); 2507820Sroot if (type != IFBLK) { 2517820Sroot if (rw == UIO_READ) { 2527820Sroot int diff = ip->i_size - uio->uio_offset; 2537820Sroot if (diff <= 0) 2547820Sroot return (0); 2557820Sroot if (diff < n) 2567820Sroot n = diff; 2577820Sroot } 2587820Sroot bn = fsbtodb(fs, 2597820Sroot bmap(ip, lbn, rw == UIO_WRITE ? B_WRITE: B_READ, (int)(on+n))); 2607820Sroot if (u.u_error || rw == UIO_WRITE && (long)bn<0) 2617820Sroot return (u.u_error); 2627820Sroot if (rw == UIO_WRITE && uio->uio_offset + n > ip->i_size && 2637820Sroot (type == IFDIR || type == IFREG || type == IFLNK)) 2647820Sroot ip->i_size = uio->uio_offset + n; 2657820Sroot size = blksize(fs, ip, lbn); 2667820Sroot } else { 2677820Sroot bn = lbn * (BLKDEV_IOSIZE/DEV_BSIZE); 2687820Sroot rablock = bn + (BLKDEV_IOSIZE/DEV_BSIZE); 2697820Sroot rasize = size = bsize; 2707820Sroot } 2717820Sroot if (rw == UIO_READ) { 2727820Sroot if ((long)bn<0) { 2737820Sroot bp = geteblk(size); 2747820Sroot clrbuf(bp); 2757820Sroot } else if (ip->i_lastr + 1 == lbn) 2767820Sroot bp = breada(dev, bn, size, rablock, rasize); 2777820Sroot else 2787820Sroot bp = bread(dev, bn, size); 2797820Sroot ip->i_lastr = lbn; 2807820Sroot } else { 2817820Sroot int i, count; 2828626Sroot extern struct cmap *mfind(); 2837820Sroot 2847820Sroot count = howmany(size, DEV_BSIZE); 2857820Sroot for (i = 0; i < count; i += CLSIZE) 2867820Sroot if (mfind(dev, bn + i)) 2877820Sroot munhash(dev, bn + i); 2887820Sroot if (n == bsize) 2897820Sroot bp = getblk(dev, bn, size); 2907820Sroot else 2917820Sroot bp = bread(dev, bn, size); 2927820Sroot } 2937820Sroot n = MIN(n, size - bp->b_resid); 2947820Sroot if (bp->b_flags & B_ERROR) { 2957820Sroot error = EIO; 2967820Sroot brelse(bp); 2977820Sroot goto bad; 2987820Sroot } 2997820Sroot u.u_error = 3008791Sroot uiomove(bp->b_un.b_addr+on, n, rw, uio); 3017820Sroot if (rw == UIO_READ) { 3027820Sroot if (n + on == bsize || uio->uio_offset == ip->i_size) 3037820Sroot bp->b_flags |= B_AGE; 3047820Sroot brelse(bp); 3057820Sroot } else { 3067820Sroot if ((ip->i_mode&IFMT) == IFDIR) 3077820Sroot bwrite(bp); 3087820Sroot else if (n + on == bsize) { 3097820Sroot bp->b_flags |= B_AGE; 3107820Sroot bawrite(bp); 3117820Sroot } else 3127820Sroot bdwrite(bp); 3137820Sroot ip->i_flag |= IUPD|ICHG; 3147820Sroot if (u.u_ruid != 0) 3157820Sroot ip->i_mode &= ~(ISUID|ISGID); 3167820Sroot } 3177820Sroot } while (u.u_error == 0 && uio->uio_resid > 0 && n != 0); 3187820Sroot bad: 3197820Sroot return (error); 3207500Sroot } 3217500Sroot 3227820Sroot uiomove(cp, n, rw, uio) 3237820Sroot register caddr_t cp; 3247820Sroot register int n; 3257820Sroot enum uio_rw rw; 3267820Sroot register struct uio *uio; 3277820Sroot { 3287820Sroot register struct iovec *iov; 3297820Sroot u_int cnt; 3309864Ssam int error = 0; 3317820Sroot 3327820Sroot while (n > 0 && uio->uio_resid) { 3337820Sroot iov = uio->uio_iov; 3347820Sroot cnt = iov->iov_len; 3357820Sroot if (cnt == 0) { 3367820Sroot uio->uio_iov++; 3377820Sroot uio->uio_iovcnt--; 3387820Sroot continue; 3397820Sroot } 3407820Sroot if (cnt > n) 3417820Sroot cnt = n; 3427820Sroot switch (uio->uio_segflg) { 3437820Sroot 3447820Sroot case 0: 3457820Sroot case 2: 3467820Sroot if (rw == UIO_READ) 3477820Sroot error = copyout(cp, iov->iov_base, cnt); 3487820Sroot else 3497820Sroot error = copyin(iov->iov_base, cp, cnt); 3507820Sroot if (error) 351*9999Ssam return (error); 3527820Sroot break; 3537820Sroot 3547820Sroot case 1: 3557820Sroot if (rw == UIO_READ) 3567820Sroot bcopy((caddr_t)cp, iov->iov_base, cnt); 3577820Sroot else 3587820Sroot bcopy(iov->iov_base, (caddr_t)cp, cnt); 3597820Sroot break; 3607820Sroot } 3617820Sroot iov->iov_base += cnt; 3627820Sroot iov->iov_len -= cnt; 3637820Sroot uio->uio_resid -= cnt; 3647820Sroot uio->uio_offset += cnt; 3657820Sroot cp += cnt; 3667820Sroot n -= cnt; 3677820Sroot } 3687820Sroot return (error); 3697820Sroot } 3707820Sroot 3717423Sroot /* 3727820Sroot * Give next character to user as result of read. 3737820Sroot */ 3747820Sroot ureadc(c, uio) 3757820Sroot register int c; 3767820Sroot register struct uio *uio; 3777820Sroot { 3787820Sroot register struct iovec *iov; 3797820Sroot 3807820Sroot again: 3817820Sroot if (uio->uio_iovcnt == 0) 3827820Sroot panic("ureadc"); 3837820Sroot iov = uio->uio_iov; 3847820Sroot if (iov->iov_len <= 0 || uio->uio_resid <= 0) { 3857820Sroot uio->uio_iovcnt--; 3867820Sroot uio->uio_iov++; 3877820Sroot goto again; 3887820Sroot } 3897820Sroot switch (uio->uio_segflg) { 3907820Sroot 3917820Sroot case 0: 3927820Sroot if (subyte(iov->iov_base, c) < 0) 3937820Sroot return (EFAULT); 3947820Sroot break; 3957820Sroot 3967820Sroot case 1: 3977820Sroot *iov->iov_base = c; 3987820Sroot break; 3997820Sroot 4007820Sroot case 2: 4017820Sroot if (suibyte(iov->iov_base, c) < 0) 4027820Sroot return (EFAULT); 4037820Sroot break; 4047820Sroot } 4057820Sroot iov->iov_base++; 4067820Sroot iov->iov_len--; 4077820Sroot uio->uio_resid--; 4087820Sroot uio->uio_offset++; 4097820Sroot return (0); 4107820Sroot } 4117820Sroot 4128767Sroot #ifdef notdef 4137820Sroot /* 4147820Sroot * Get next character written in by user from uio. 4157820Sroot */ 4167820Sroot uwritec(uio) 4177820Sroot struct uio *uio; 4187820Sroot { 4197820Sroot register struct iovec *iov; 4207820Sroot register int c; 4217820Sroot 4227820Sroot again: 4237820Sroot if (uio->uio_iovcnt <= 0 || uio->uio_resid <= 0) 4247820Sroot panic("uwritec"); 4257820Sroot iov = uio->uio_iov; 4267820Sroot if (iov->iov_len == 0) { 4277820Sroot uio->uio_iovcnt--; 4287820Sroot uio->uio_iov++; 4297820Sroot goto again; 4307820Sroot } 4317820Sroot switch (uio->uio_segflg) { 4327820Sroot 4337820Sroot case 0: 4347820Sroot c = fubyte(iov->iov_base); 4357820Sroot break; 4367820Sroot 4377820Sroot case 1: 4387820Sroot c = *iov->iov_base & 0377; 4397820Sroot break; 4407820Sroot 4417820Sroot case 2: 4427820Sroot c = fuibyte(iov->iov_base); 4437820Sroot break; 4447820Sroot } 4457820Sroot if (c < 0) 4467820Sroot return (-1); 4477820Sroot iov->iov_base++; 4487820Sroot iov->iov_len--; 4497820Sroot uio->uio_resid--; 4507820Sroot uio->uio_offset++; 4517820Sroot return (c & 0377); 4527820Sroot } 4538767Sroot #endif 4547820Sroot 4557820Sroot /* 4567423Sroot * Ioctl system call 4577624Ssam * Check legality, execute common code, 4587624Ssam * and switch out to individual device routine. 4597423Sroot */ 4607423Sroot ioctl() 4617423Sroot { 4627423Sroot register struct file *fp; 4637624Ssam struct a { 4647423Sroot int fdes; 4657423Sroot int cmd; 4667423Sroot caddr_t cmarg; 4677423Sroot } *uap; 4687820Sroot register int com; 4697820Sroot register u_int size; 4707624Ssam char data[IOCPARM_MASK+1]; 4717423Sroot 4727423Sroot uap = (struct a *)u.u_ap; 4737423Sroot if ((fp = getf(uap->fdes)) == NULL) 4747423Sroot return; 4757423Sroot if ((fp->f_flag & (FREAD|FWRITE)) == 0) { 4767423Sroot u.u_error = EBADF; 4777423Sroot return; 4787423Sroot } 4797624Ssam com = uap->cmd; 4807624Ssam 4817699Ssam #ifndef NOCOMPAT 4827624Ssam /* 4837624Ssam * Map old style ioctl's into new for the 4847624Ssam * sake of backwards compatibility (sigh). 4857624Ssam */ 4867624Ssam if ((com&~0xffff) == 0) { 4877624Ssam com = mapioctl(com); 4887624Ssam if (com == 0) { 4897624Ssam u.u_error = EINVAL; 4907624Ssam return; 4917624Ssam } 4927624Ssam } 4937624Ssam #endif 4947624Ssam if (com == FIOCLEX) { 4959592Ssam u.u_pofile[uap->fdes] |= UF_EXCLOSE; 4967423Sroot return; 4977423Sroot } 4987624Ssam if (com == FIONCLEX) { 4999592Ssam u.u_pofile[uap->fdes] &= ~UF_EXCLOSE; 5007423Sroot return; 5017423Sroot } 5027624Ssam 5037624Ssam /* 5047624Ssam * Interpret high order word to find 5057624Ssam * amount of data to be copied to/from the 5067624Ssam * user's address space. 5077624Ssam */ 5087624Ssam size = (com &~ (IOC_INOUT|IOC_VOID)) >> 16; 5097624Ssam if (size > sizeof (data)) { 5107624Ssam u.u_error = EFAULT; 5117423Sroot return; 5127423Sroot } 5137699Ssam if (com&IOC_IN && size) { 514*9999Ssam u.u_error = copyin(uap->cmarg, (caddr_t)data, (u_int)size); 515*9999Ssam if (u.u_error) 5167624Ssam return; 5177624Ssam } else 5187624Ssam *(caddr_t *)data = uap->cmarg; 5197624Ssam /* 5207624Ssam * Zero the buffer on the stack so the user 5217624Ssam * always gets back something deterministic. 5227624Ssam */ 5237624Ssam if ((com&IOC_OUT) && size) 5247624Ssam bzero((caddr_t)data, size); 5257423Sroot 5267624Ssam if (fp->f_type == DTYPE_SOCKET) 5278564Sroot u.u_error = soioctl(fp->f_socket, com, data); 5287624Ssam else { 5297624Ssam register struct inode *ip = fp->f_inode; 5307624Ssam int fmt = ip->i_mode & IFMT; 5317624Ssam dev_t dev; 5327624Ssam 5337624Ssam if (fmt != IFCHR) { 5347624Ssam if (com == FIONREAD && (fmt == IFREG || fmt == IFDIR)) { 5357624Ssam *(off_t *)data = ip->i_size - fp->f_offset; 5367624Ssam goto returndata; 5377624Ssam } 5387624Ssam if (com != FIONBIO && com != FIOASYNC) 5397624Ssam u.u_error = ENOTTY; 5407423Sroot return; 5417624Ssam } 5427624Ssam dev = ip->i_rdev; 5437624Ssam u.u_r.r_val1 = 0; 5448118Sroot if ((u.u_procp->p_flag&SNUSIG) && setjmp(&u.u_qsave)) { 5457624Ssam u.u_eosys = RESTARTSYS; 5467624Ssam return; 5477624Ssam } 5488564Sroot u.u_error = (*cdevsw[major(dev)].d_ioctl)(dev, com, data, 0); 5497423Sroot } 5507624Ssam 5517624Ssam returndata: 5527624Ssam /* 5537624Ssam * Copy any data to user, size was 5547624Ssam * already set and checked above. 5557624Ssam */ 556*9999Ssam if (u.u_error == 0 && (com&IOC_OUT) && size) 557*9999Ssam u.u_error = copyout(data, uap->cmarg, (u_int)size); 5587423Sroot } 5597423Sroot 5607423Sroot /* 5617423Sroot * Do nothing specific version of line 5627423Sroot * discipline specific ioctl command. 5637423Sroot */ 5647423Sroot /*ARGSUSED*/ 5657624Ssam nullioctl(tp, cmd, data, flags) 5667423Sroot struct tty *tp; 5677624Ssam char *data; 5687624Ssam int flags; 5697423Sroot { 5707423Sroot 5717624Ssam #ifdef lint 5727624Ssam tp = tp; data = data; flags = flags; 5737624Ssam #endif 5748564Sroot return (-1); 5757423Sroot } 5768103Sroot 5778103Sroot ostty() 5788103Sroot { 5798103Sroot 5808103Sroot } 5818103Sroot 5828103Sroot ogtty() 5838103Sroot { 5848103Sroot 5858103Sroot } 586