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