1 /* sys_generic.c 5.10 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 * Write the file corresponding to 263 * the inode pointed at by the argument. 264 * The actual write arguments are found 265 * in the variables: 266 * u_base core address for source 267 * u_offset byte offset in file 268 * u_count number of bytes to write 269 * u_segflg write to kernel/user/user I 270 */ 271 writei(ip) 272 register struct inode *ip; 273 { 274 struct buf *bp; 275 register struct fs *fs; 276 dev_t dev; 277 daddr_t lbn, bn; 278 register int on, type; 279 register unsigned n; 280 long bsize; 281 int size, i, count; 282 extern int mem_no; 283 284 dev = (dev_t)ip->i_rdev; 285 if (u.u_offset < 0 && ((ip->i_mode&IFMT) != IFCHR || 286 mem_no != major(dev)) ) { 287 u.u_error = EINVAL; 288 return; 289 } 290 type = ip->i_mode & IFMT; 291 if (type == IFCHR) { 292 ip->i_flag |= IUPD|ICHG; 293 CHARGE(sc_tio * u.u_count); 294 (*cdevsw[major(dev)].d_write)(dev); 295 return; 296 } 297 if (u.u_count == 0) 298 return; 299 if ((ip->i_mode & IFMT) == IFREG && 300 u.u_offset + u.u_count > u.u_limit[LIM_FSIZE]) { 301 psignal(u.u_procp, SIGXFSZ); 302 u.u_error = EMFILE; 303 return; 304 } 305 if (type!=IFBLK) { 306 dev = ip->i_dev; 307 fs = ip->i_fs; 308 bsize = fs->fs_bsize; 309 } else 310 bsize = BLKDEV_IOSIZE; 311 do { 312 lbn = u.u_offset / bsize; 313 on = u.u_offset % bsize; 314 n = MIN((unsigned)(bsize - on), u.u_count); 315 if (type != IFBLK) { 316 bn = fsbtodb(fs, bmap(ip, lbn, B_WRITE, (int)(on + n))); 317 if (u.u_error || (long)bn<0) 318 return; 319 if(u.u_offset + n > ip->i_size && 320 (type == IFDIR || type == IFREG || type == IFLNK)) 321 ip->i_size = u.u_offset + n; 322 size = blksize(fs, ip, lbn); 323 } else { 324 size = bsize; 325 bn = lbn * (BLKDEV_IOSIZE/DEV_BSIZE); 326 } 327 count = howmany(size, DEV_BSIZE); 328 for (i = 0; i < count; i += CLSIZE) 329 if (mfind(dev, bn + i)) 330 munhash(dev, bn + i); 331 if (n == bsize) 332 bp = getblk(dev, bn, size); 333 else 334 bp = bread(dev, bn, size); 335 if (u.u_segflg != 1) { 336 if (copyin(u.u_base, bp->b_un.b_addr + on, n)) { 337 u.u_error = EFAULT; 338 goto bad; 339 } 340 } else 341 bcopy(u.u_base, bp->b_un.b_addr + on, n); 342 u.u_base += n; 343 u.u_offset += n; 344 u.u_count -= n; 345 bad: 346 ; 347 if (u.u_error != 0) 348 brelse(bp); 349 else { 350 if ((ip->i_mode&IFMT) == IFDIR) 351 /* 352 * Writing to clear a directory entry. 353 * Must insure the write occurs before 354 * the inode is freed, or may end up 355 * pointing at a new (different) file 356 * if inode is quickly allocated again 357 * and system crashes. 358 */ 359 bwrite(bp); 360 else if (n + on == bsize) { 361 bp->b_flags |= B_AGE; 362 bawrite(bp); 363 } else 364 bdwrite(bp); 365 } 366 ip->i_flag |= IUPD|ICHG; 367 if (u.u_ruid != 0) 368 ip->i_mode &= ~(ISUID|ISGID); 369 } while (u.u_error == 0 && u.u_count != 0); 370 } 371 372 /* 373 * Move n bytes at byte location 374 * &bp->b_un.b_addr[o] to/from (flag) the 375 * user/kernel (u.segflg) area starting at u.base. 376 * Update all the arguments by the number 377 * of bytes moved. 378 */ 379 iomove(cp, n, flag) 380 register caddr_t cp; 381 register unsigned n; 382 { 383 register int t; 384 385 if (n==0) 386 return; 387 if (u.u_segflg != 1) { 388 if (flag==B_WRITE) 389 t = copyin(u.u_base, (caddr_t)cp, n); 390 else 391 t = copyout((caddr_t)cp, u.u_base, n); 392 if (t) { 393 u.u_error = EFAULT; 394 return; 395 } 396 } else 397 if (flag == B_WRITE) 398 bcopy(u.u_base, (caddr_t)cp, n); 399 else 400 bcopy((caddr_t)cp, u.u_base, n); 401 u.u_base += n; 402 u.u_offset += n; 403 u.u_count -= n; 404 } 405 406 readip1(ip, base, len, offset, segflg, aresid) 407 struct inode *ip; 408 caddr_t base; 409 int len, offset, segflg; 410 int *aresid; 411 { 412 struct uio auio; 413 struct iovec aiov; 414 int error; 415 416 auio.uio_iov = &aiov; 417 auio.uio_iovcnt = 1; 418 aiov.iov_base = base; 419 aiov.iov_len = len; 420 auio.uio_resid = len; 421 auio.uio_offset = offset; 422 auio.uio_segflg = segflg; 423 error = readip(ip, &auio); 424 if (aresid) 425 *aresid = auio.uio_resid; 426 else 427 if (auio.uio_resid) 428 error = EIO; 429 return (error); 430 } 431 432 readip(ip, uio) 433 register struct inode *ip; 434 register struct uio *uio; 435 { 436 register struct iovec *iov; 437 struct buf *bp; 438 struct fs *fs; 439 dev_t dev; 440 daddr_t lbn, bn; 441 off_t diff; 442 register int on, type; 443 register unsigned n; 444 int size; 445 long bsize; 446 extern int mem_no; 447 int error = 0; 448 449 dev = (dev_t)ip->i_rdev; 450 if (uio->uio_offset < 0 && 451 ((ip->i_mode&IFMT) != IFCHR || mem_no != major(dev))) 452 return (EINVAL); 453 ip->i_flag |= IACC; 454 type = ip->i_mode&IFMT; 455 if (type == IFCHR) { 456 register c = u.u_count; 457 (*cdevsw[major(dev)].d_read)(dev, uio); 458 CHARGE(sc_tio * (c - uio->uio_resid)); 459 return (u.u_error); 460 } 461 if (type != IFBLK) { 462 dev = ip->i_dev; 463 fs = ip->i_fs; 464 bsize = fs->fs_bsize; 465 } else 466 bsize = BLKDEV_IOSIZE; 467 nextiov: 468 if (uio->uio_iovcnt == 0) 469 return (0); 470 iov = uio->uio_iov; 471 if (iov->iov_len > 0) 472 do { 473 lbn = uio->uio_offset / bsize; 474 on = uio->uio_offset % bsize; 475 n = MIN((unsigned)(bsize - on), iov->iov_len); 476 if (type != IFBLK) { 477 diff = ip->i_size - uio->uio_offset; 478 if (diff <= 0) 479 return; 480 if (diff < n) 481 n = diff; 482 bn = fsbtodb(fs, bmap(ip, lbn, B_READ)); 483 if (u.u_error) 484 return (u.u_error); 485 size = blksize(fs, ip, lbn); 486 } else { 487 size = bsize; 488 bn = lbn * (BLKDEV_IOSIZE/DEV_BSIZE); 489 rablock = bn + (BLKDEV_IOSIZE/DEV_BSIZE); 490 rasize = bsize; 491 } 492 if ((long)bn<0) { 493 bp = geteblk(size); 494 clrbuf(bp); 495 } else if (ip->i_lastr + 1 == lbn) 496 bp = breada(dev, bn, size, rablock, rasize); 497 else 498 bp = bread(dev, bn, size); 499 ip->i_lastr = lbn; 500 n = MIN(n, size - bp->b_resid); 501 if (n != 0) { 502 if (uio->uio_segflg != 1) { 503 if (copyout(bp->b_un.b_addr+on, iov->iov_base, n)) { 504 brelse(bp); 505 return (EFAULT); 506 } 507 } else 508 bcopy(bp->b_un.b_addr + on, iov->iov_base, n); 509 iov->iov_base += n; 510 uio->uio_offset += n; 511 iov->iov_len -= n; 512 uio->uio_resid -= n; 513 } 514 if (n + on == bsize || uio->uio_offset == ip->i_size) 515 bp->b_flags |= B_AGE; 516 brelse(bp); 517 } while (u.u_error == 0 && iov->iov_len != 0 && n != 0); 518 if (u.u_error == 0 && iov->iov_len == 0) { 519 uio->uio_iov++; 520 uio->uio_iovcnt--; 521 goto nextiov; 522 } 523 return (error); 524 } 525 526 uiomove(cp, n, dir, uio) 527 register caddr_t cp; 528 register unsigned n; 529 enum uio_direction dir; 530 struct uio *uio; 531 { 532 register struct iovec *iov; 533 int bad, cnt; 534 535 if (n == 0) 536 return (0); 537 if (uio->uio_segflg != 1) { 538 if (dir == UIO_READFROM) 539 #ifdef notdef 540 bad = copyuin(uio, (caddr_t)cp, n); 541 #else 542 panic("uiomove"); 543 #endif 544 else 545 bad = copyuout((caddr_t)cp, n, uio); 546 if (bad) 547 return (EFAULT); 548 } else { 549 while (n > 0 && uio->uio_iovcnt) { 550 iov = uio->uio_iov; 551 cnt = iov->iov_len; 552 if (cnt > n) 553 cnt = n; 554 if (dir == UIO_READFROM) 555 bcopy(iov->iov_base, (caddr_t)cp, cnt); 556 else 557 bcopy((caddr_t)cp, iov->iov_base, cnt); 558 iov->iov_base += cnt; 559 iov->iov_len -= cnt; 560 uio->uio_resid -= cnt; 561 n -= cnt; 562 } 563 } 564 return (0); 565 } 566