1 /* sys_generic.c 5.9 82/08/14 */ 2 3 #include "../h/param.h" 4 #include "../h/systm.h" 5 #include "../h/dir.h" 6 #include "../h/user.h" 7 #include "../h/tty.h" 8 #include "../h/file.h" 9 #include "../h/inode.h" 10 #include "../h/buf.h" 11 #include "../h/proc.h" 12 #include "../h/inline.h" 13 #include "../h/conf.h" 14 #include "../h/socket.h" 15 #include "../h/socketvar.h" 16 #include "../h/cmap.h" 17 #include "../h/vlimit.h" 18 #include "../h/fs.h" 19 #ifdef MUSH 20 #include "../h/quota.h" 21 #include "../h/share.h" 22 #else 23 #define CHARGE(nothing) 24 #endif 25 #include "../h/descrip.h" 26 #include "../h/uio.h" 27 28 /* 29 * Read system call. 30 */ 31 read() 32 { 33 register struct file *fp; 34 register struct inode *ip; 35 register struct a { 36 int fdes; 37 char *cbuf; 38 unsigned count; 39 } *uap; 40 struct uio auio; 41 struct iovec aiov; 42 43 uap = (struct a *)u.u_ap; 44 if ((int)uap->count < 0) { 45 u.u_error = EINVAL; 46 return; 47 } 48 GETF(fp, uap->fdes); 49 if ((fp->f_flag&FREAD) == 0) { 50 u.u_error = EBADF; 51 return; 52 } 53 aiov.iov_base = (caddr_t)uap->cbuf; 54 aiov.iov_len = uap->count; 55 auio.uio_iov = &aiov; 56 auio.uio_iovcnt = 1; 57 auio.uio_segflg = 0; 58 auio.uio_resid = uap->count; 59 u.u_base = (caddr_t)0xc0000000; 60 u.u_count = 0x40000000; 61 if ((u.u_procp->p_flag&SNUSIG) && setjmp(u.u_qsav)) { 62 if (auio.uio_resid == uap->count) 63 u.u_eosys = RESTARTSYS; 64 } else if (fp->f_type == DTYPE_SOCKET) 65 u.u_error = soreceive(fp->f_socket, (struct sockaddr *)0, &auio); 66 else { 67 ip = fp->f_inode; 68 auio.uio_offset = fp->f_offset; 69 if ((ip->i_mode&IFMT) == IFREG) { 70 ilock(ip); 71 u.u_error = readip(ip, &auio); 72 iunlock(ip); 73 } else 74 u.u_error = readip(ip, &auio); 75 fp->f_offset += uap->count - auio.uio_resid; 76 } 77 u.u_r.r_val1 = uap->count - auio.uio_resid; 78 } 79 80 /* 81 * Write system call 82 */ 83 write() 84 { 85 register struct file *fp; 86 register struct inode *ip; 87 register struct a { 88 int fdes; 89 char *cbuf; 90 unsigned count; 91 } *uap; 92 93 uap = (struct a *)u.u_ap; 94 if ((int)uap->count < 0) { 95 u.u_error = EINVAL; 96 return; 97 } 98 GETF(fp, uap->fdes); 99 if ((fp->f_flag&FWRITE) == 0) { 100 u.u_error = EBADF; 101 return; 102 } 103 u.u_base = (caddr_t)uap->cbuf; 104 u.u_count = uap->count; 105 u.u_segflg = 0; 106 if ((u.u_procp->p_flag&SNUSIG) && setjmp(u.u_qsav)) { 107 if (u.u_count == uap->count) 108 u.u_eosys = RESTARTSYS; 109 } else if (fp->f_type == DTYPE_SOCKET) 110 u.u_error = sosend(fp->f_socket, (struct sockaddr *)0); 111 else { 112 ip = fp->f_inode; 113 if (fp->f_flag&FAPPEND) 114 fp->f_offset = ip->i_size; 115 u.u_offset = fp->f_offset; 116 if ((ip->i_mode&IFMT) == IFREG) { 117 ilock(ip); 118 writei(ip); 119 iunlock(ip); 120 } else 121 writei(ip); 122 fp->f_offset += uap->count - u.u_count; 123 } 124 u.u_r.r_val1 = uap->count - u.u_count; 125 } 126 127 readv() 128 { 129 130 } 131 132 writev() 133 { 134 135 } 136 137 /* 138 * Ioctl system call 139 * Check legality, execute common code, 140 * and switch out to individual device routine. 141 */ 142 ioctl() 143 { 144 register struct file *fp; 145 struct a { 146 int fdes; 147 int cmd; 148 caddr_t cmarg; 149 } *uap; 150 register int com, size; 151 char data[IOCPARM_MASK+1]; 152 153 uap = (struct a *)u.u_ap; 154 if ((fp = getf(uap->fdes)) == NULL) 155 return; 156 if ((fp->f_flag & (FREAD|FWRITE)) == 0) { 157 u.u_error = EBADF; 158 return; 159 } 160 com = uap->cmd; 161 162 #ifndef NOCOMPAT 163 /* 164 * Map old style ioctl's into new for the 165 * sake of backwards compatibility (sigh). 166 */ 167 if ((com&~0xffff) == 0) { 168 com = mapioctl(com); 169 if (com == 0) { 170 u.u_error = EINVAL; 171 return; 172 } 173 } 174 #endif 175 if (com == FIOCLEX) { 176 u.u_pofile[uap->fdes] |= EXCLOSE; 177 return; 178 } 179 if (com == FIONCLEX) { 180 u.u_pofile[uap->fdes] &= ~EXCLOSE; 181 return; 182 } 183 184 /* 185 * Interpret high order word to find 186 * amount of data to be copied to/from the 187 * user's address space. 188 * (this'll have to change if we have in+out ioctls) 189 */ 190 size = (com &~ (IOC_INOUT|IOC_VOID)) >> 16; 191 if (size > sizeof (data)) { 192 u.u_error = EFAULT; 193 return; 194 } 195 if (com&IOC_IN && size) { 196 if (copyin(uap->cmarg, (caddr_t)data, size)) { 197 u.u_error = EFAULT; 198 return; 199 } 200 } else 201 *(caddr_t *)data = uap->cmarg; 202 /* 203 * Zero the buffer on the stack so the user 204 * always gets back something deterministic. 205 */ 206 if ((com&IOC_OUT) && size) 207 bzero((caddr_t)data, size); 208 209 if (fp->f_type == DTYPE_SOCKET) 210 soioctl(fp->f_socket, com, data); 211 else { 212 register struct inode *ip = fp->f_inode; 213 int fmt = ip->i_mode & IFMT; 214 dev_t dev; 215 216 if (fmt != IFCHR) { 217 if (com == FIONREAD && (fmt == IFREG || fmt == IFDIR)) { 218 *(off_t *)data = ip->i_size - fp->f_offset; 219 goto returndata; 220 } 221 if (com != FIONBIO && com != FIOASYNC) 222 u.u_error = ENOTTY; 223 return; 224 } 225 dev = ip->i_rdev; 226 u.u_r.r_val1 = 0; 227 if ((u.u_procp->p_flag&SNUSIG) && setjmp(u.u_qsav)) { 228 u.u_eosys = RESTARTSYS; 229 return; 230 } 231 (*cdevsw[major(dev)].d_ioctl)(dev, com, data, 0); 232 } 233 234 returndata: 235 /* 236 * Copy any data to user, size was 237 * already set and checked above. 238 */ 239 if (u.u_error == 0 && com&IOC_OUT) 240 if (size && copyout(data, uap->cmarg, size)) 241 u.u_error = EFAULT; 242 } 243 244 /* 245 * Do nothing specific version of line 246 * discipline specific ioctl command. 247 */ 248 /*ARGSUSED*/ 249 nullioctl(tp, cmd, data, flags) 250 struct tty *tp; 251 char *data; 252 int flags; 253 { 254 255 #ifdef lint 256 tp = tp; data = data; flags = flags; 257 #endif 258 return (cmd); 259 } 260 261 /* 262 * Read the file corresponding to 263 * the inode pointed at by the argument. 264 * The actual read arguments are found 265 * in the variables: 266 * u_base core address for destination 267 * u_offset byte offset in file 268 * u_count number of bytes to read 269 * u_segflg read to kernel/user/user I 270 */ 271 readi(ip) 272 register struct inode *ip; 273 { 274 struct buf *bp; 275 struct fs *fs; 276 dev_t dev; 277 daddr_t lbn, bn; 278 off_t diff; 279 register int on, type; 280 register unsigned n; 281 int size; 282 long bsize; 283 extern int mem_no; 284 285 if (u.u_count == 0) 286 return; 287 dev = (dev_t)ip->i_rdev; 288 if (u.u_offset < 0 && ((ip->i_mode&IFMT) != IFCHR || 289 mem_no != major(dev))) { 290 u.u_error = EINVAL; 291 return; 292 } 293 ip->i_flag |= IACC; 294 type = ip->i_mode&IFMT; 295 if (type == IFCHR) { 296 register c = u.u_count; 297 struct uio auio; 298 struct iovec aiov; 299 auio.uio_iov = &aiov; 300 auio.uio_iovcnt = 1; 301 aiov.iov_base = u.u_base; 302 aiov.iov_len = u.u_count; 303 auio.uio_offset = u.u_offset; 304 auio.uio_segflg = u.u_segflg; 305 auio.uio_resid = u.u_count; 306 (*cdevsw[major(dev)].d_read)(dev, &auio); 307 CHARGE(sc_tio * (c - auio.uio_resid)); 308 u.u_count = auio.uio_resid; 309 return; 310 } 311 if (type != IFBLK) { 312 dev = ip->i_dev; 313 fs = ip->i_fs; 314 bsize = fs->fs_bsize; 315 } else 316 bsize = BLKDEV_IOSIZE; 317 do { 318 lbn = u.u_offset / bsize; 319 on = u.u_offset % bsize; 320 n = MIN((unsigned)(bsize - on), u.u_count); 321 if (type != IFBLK) { 322 diff = ip->i_size - u.u_offset; 323 if (diff <= 0) 324 return; 325 if (diff < n) 326 n = diff; 327 bn = fsbtodb(fs, bmap(ip, lbn, B_READ)); 328 if (u.u_error) 329 return; 330 size = blksize(fs, ip, lbn); 331 } else { 332 size = bsize; 333 bn = lbn * (BLKDEV_IOSIZE/DEV_BSIZE); 334 rablock = bn + (BLKDEV_IOSIZE/DEV_BSIZE); 335 rasize = bsize; 336 } 337 if ((long)bn<0) { 338 bp = geteblk(size); 339 clrbuf(bp); 340 } else if (ip->i_lastr + 1 == lbn) 341 bp = breada(dev, bn, size, rablock, rasize); 342 else 343 bp = bread(dev, bn, size); 344 ip->i_lastr = lbn; 345 n = MIN(n, size - bp->b_resid); 346 if (n != 0) { 347 if (u.u_segflg != 1) { 348 if (copyout(bp->b_un.b_addr+on, u.u_base, n)) { 349 u.u_error = EFAULT; 350 goto bad; 351 } 352 } else 353 bcopy(bp->b_un.b_addr + on, u.u_base, n); 354 u.u_base += n; 355 u.u_offset += n; 356 u.u_count -= n; 357 bad: 358 ; 359 } 360 if (n + on == bsize || u.u_offset == ip->i_size) 361 bp->b_flags |= B_AGE; 362 brelse(bp); 363 } while (u.u_error == 0 && u.u_count != 0 && n != 0); 364 } 365 366 /* 367 * Write the file corresponding to 368 * the inode pointed at by the argument. 369 * The actual write arguments are found 370 * in the variables: 371 * u_base core address for source 372 * u_offset byte offset in file 373 * u_count number of bytes to write 374 * u_segflg write to kernel/user/user I 375 */ 376 writei(ip) 377 register struct inode *ip; 378 { 379 struct buf *bp; 380 register struct fs *fs; 381 dev_t dev; 382 daddr_t lbn, bn; 383 register int on, type; 384 register unsigned n; 385 long bsize; 386 int size, i, count; 387 extern int mem_no; 388 389 dev = (dev_t)ip->i_rdev; 390 if (u.u_offset < 0 && ((ip->i_mode&IFMT) != IFCHR || 391 mem_no != major(dev)) ) { 392 u.u_error = EINVAL; 393 return; 394 } 395 type = ip->i_mode & IFMT; 396 if (type == IFCHR) { 397 ip->i_flag |= IUPD|ICHG; 398 CHARGE(sc_tio * u.u_count); 399 (*cdevsw[major(dev)].d_write)(dev); 400 return; 401 } 402 if (u.u_count == 0) 403 return; 404 if ((ip->i_mode & IFMT) == IFREG && 405 u.u_offset + u.u_count > u.u_limit[LIM_FSIZE]) { 406 psignal(u.u_procp, SIGXFSZ); 407 u.u_error = EMFILE; 408 return; 409 } 410 if (type!=IFBLK) { 411 dev = ip->i_dev; 412 fs = ip->i_fs; 413 bsize = fs->fs_bsize; 414 } else 415 bsize = BLKDEV_IOSIZE; 416 do { 417 lbn = u.u_offset / bsize; 418 on = u.u_offset % bsize; 419 n = MIN((unsigned)(bsize - on), u.u_count); 420 if (type != IFBLK) { 421 bn = fsbtodb(fs, bmap(ip, lbn, B_WRITE, (int)(on + n))); 422 if (u.u_error || (long)bn<0) 423 return; 424 if(u.u_offset + n > ip->i_size && 425 (type == IFDIR || type == IFREG || type == IFLNK)) 426 ip->i_size = u.u_offset + n; 427 size = blksize(fs, ip, lbn); 428 } else { 429 size = bsize; 430 bn = lbn * (BLKDEV_IOSIZE/DEV_BSIZE); 431 } 432 count = howmany(size, DEV_BSIZE); 433 for (i = 0; i < count; i += CLSIZE) 434 if (mfind(dev, bn + i)) 435 munhash(dev, bn + i); 436 if (n == bsize) 437 bp = getblk(dev, bn, size); 438 else 439 bp = bread(dev, bn, size); 440 if (u.u_segflg != 1) { 441 if (copyin(u.u_base, bp->b_un.b_addr + on, n)) { 442 u.u_error = EFAULT; 443 goto bad; 444 } 445 } else 446 bcopy(u.u_base, bp->b_un.b_addr + on, n); 447 u.u_base += n; 448 u.u_offset += n; 449 u.u_count -= n; 450 bad: 451 ; 452 if (u.u_error != 0) 453 brelse(bp); 454 else { 455 if ((ip->i_mode&IFMT) == IFDIR) 456 /* 457 * Writing to clear a directory entry. 458 * Must insure the write occurs before 459 * the inode is freed, or may end up 460 * pointing at a new (different) file 461 * if inode is quickly allocated again 462 * and system crashes. 463 */ 464 bwrite(bp); 465 else if (n + on == bsize) { 466 bp->b_flags |= B_AGE; 467 bawrite(bp); 468 } else 469 bdwrite(bp); 470 } 471 ip->i_flag |= IUPD|ICHG; 472 if (u.u_ruid != 0) 473 ip->i_mode &= ~(ISUID|ISGID); 474 } while (u.u_error == 0 && u.u_count != 0); 475 } 476 477 /* 478 * Move n bytes at byte location 479 * &bp->b_un.b_addr[o] to/from (flag) the 480 * user/kernel (u.segflg) area starting at u.base. 481 * Update all the arguments by the number 482 * of bytes moved. 483 */ 484 iomove(cp, n, flag) 485 register caddr_t cp; 486 register unsigned n; 487 { 488 register int t; 489 490 if (n==0) 491 return; 492 if (u.u_segflg != 1) { 493 if (flag==B_WRITE) 494 t = copyin(u.u_base, (caddr_t)cp, n); 495 else 496 t = copyout((caddr_t)cp, u.u_base, n); 497 if (t) { 498 u.u_error = EFAULT; 499 return; 500 } 501 } else 502 if (flag == B_WRITE) 503 bcopy(u.u_base, (caddr_t)cp, n); 504 else 505 bcopy((caddr_t)cp, u.u_base, n); 506 u.u_base += n; 507 u.u_offset += n; 508 u.u_count -= n; 509 } 510 511 readip(ip, uio) 512 register struct inode *ip; 513 register struct uio *uio; 514 { 515 register struct iovec *iov; 516 struct buf *bp; 517 struct fs *fs; 518 dev_t dev; 519 daddr_t lbn, bn; 520 off_t diff; 521 register int on, type; 522 register unsigned n; 523 int size; 524 long bsize; 525 extern int mem_no; 526 int error = 0; 527 528 dev = (dev_t)ip->i_rdev; 529 if (uio->uio_offset < 0 && 530 ((ip->i_mode&IFMT) != IFCHR || mem_no != major(dev))) 531 return (EINVAL); 532 ip->i_flag |= IACC; 533 type = ip->i_mode&IFMT; 534 if (type == IFCHR) { 535 register c = u.u_count; 536 (*cdevsw[major(dev)].d_read)(dev, uio); 537 CHARGE(sc_tio * (c - uio->uio_resid)); 538 return (u.u_error); 539 } 540 if (type != IFBLK) { 541 dev = ip->i_dev; 542 fs = ip->i_fs; 543 bsize = fs->fs_bsize; 544 } else 545 bsize = BLKDEV_IOSIZE; 546 nextiov: 547 if (uio->uio_iovcnt == 0) 548 return (0); 549 iov = uio->uio_iov; 550 if (iov->iov_len > 0) 551 do { 552 lbn = uio->uio_offset / bsize; 553 on = uio->uio_offset % bsize; 554 n = MIN((unsigned)(bsize - on), iov->iov_len); 555 if (type != IFBLK) { 556 diff = ip->i_size - uio->uio_offset; 557 if (diff <= 0) 558 return; 559 if (diff < n) 560 n = diff; 561 bn = fsbtodb(fs, bmap(ip, lbn, B_READ)); 562 if (u.u_error) 563 return (u.u_error); 564 size = blksize(fs, ip, lbn); 565 } else { 566 size = bsize; 567 bn = lbn * (BLKDEV_IOSIZE/DEV_BSIZE); 568 rablock = bn + (BLKDEV_IOSIZE/DEV_BSIZE); 569 rasize = bsize; 570 } 571 if ((long)bn<0) { 572 bp = geteblk(size); 573 clrbuf(bp); 574 } else if (ip->i_lastr + 1 == lbn) 575 bp = breada(dev, bn, size, rablock, rasize); 576 else 577 bp = bread(dev, bn, size); 578 ip->i_lastr = lbn; 579 n = MIN(n, size - bp->b_resid); 580 if (n != 0) { 581 if (uio->uio_segflg != 1) { 582 if (copyout(bp->b_un.b_addr+on, iov->iov_base, n)) { 583 brelse(bp); 584 return (EFAULT); 585 } 586 } else 587 bcopy(bp->b_un.b_addr + on, iov->iov_base, n); 588 iov->iov_base += n; 589 uio->uio_offset += n; 590 iov->iov_len -= n; 591 uio->uio_resid -= n; 592 } 593 if (n + on == bsize || uio->uio_offset == ip->i_size) 594 bp->b_flags |= B_AGE; 595 brelse(bp); 596 } while (u.u_error == 0 && iov->iov_len != 0 && n != 0); 597 if (u.u_error == 0 && iov->iov_len == 0) { 598 uio->uio_iov++; 599 uio->uio_iovcnt--; 600 goto nextiov; 601 } 602 return (error); 603 } 604 605 uiomove(cp, n, dir, uio) 606 register caddr_t cp; 607 register unsigned n; 608 enum uio_direction dir; 609 struct uio *uio; 610 { 611 register struct iovec *iov; 612 int bad, cnt; 613 614 if (n == 0) 615 return (0); 616 if (uio->uio_segflg != 1) { 617 if (dir == UIO_READFROM) 618 #ifdef notdef 619 bad = copyuin(uio, (caddr_t)cp, n); 620 #else 621 panic("uiomove"); 622 #endif 623 else 624 bad = copyuout((caddr_t)cp, n, uio); 625 if (bad) 626 return (EFAULT); 627 } else { 628 while (n > 0 && uio->uio_iovcnt) { 629 iov = uio->uio_iov; 630 cnt = iov->iov_len; 631 if (cnt > n) 632 cnt = n; 633 if (dir == UIO_READFROM) 634 bcopy(iov->iov_base, (caddr_t)cp, cnt); 635 else 636 bcopy((caddr_t)cp, iov->iov_base, cnt); 637 iov->iov_base += cnt; 638 iov->iov_len -= cnt; 639 uio->uio_resid -= cnt; 640 n -= cnt; 641 } 642 } 643 return (0); 644 } 645