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