1 /* sys_generic.c 5.3 82/07/24 */ 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/fcntl.h" 9 #include "../h/file.h" 10 #include "../h/inode.h" 11 #include "../h/buf.h" 12 #include "../h/proc.h" 13 #include "../h/inline.h" 14 #include "../h/conf.h" 15 #include "../h/socket.h" 16 #include "../h/socketvar.h" 17 #include "../h/cmap.h" 18 #include "../h/vlimit.h" 19 #include "../h/fs.h" 20 #ifdef MUSH 21 #include "../h/quota.h" 22 #include "../h/share.h" 23 #else 24 #define CHARGE(nothing) 25 #endif 26 #include "../h/descrip.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 & O_APPEND) 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, and switch out to individual 133 * device routine. 134 */ 135 ioctl() 136 { 137 register struct file *fp; 138 register struct inode *ip; 139 register struct a { 140 int fdes; 141 int cmd; 142 caddr_t cmarg; 143 } *uap; 144 register dev_t dev; 145 register fmt; 146 147 uap = (struct a *)u.u_ap; 148 if ((fp = getf(uap->fdes)) == NULL) 149 return; 150 if ((fp->f_flag & (FREAD|FWRITE)) == 0) { 151 u.u_error = EBADF; 152 return; 153 } 154 if (uap->cmd==FIOCLEX) { 155 u.u_pofile[uap->fdes] |= EXCLOSE; 156 return; 157 } 158 if (uap->cmd==FIONCLEX) { 159 u.u_pofile[uap->fdes] &= ~EXCLOSE; 160 return; 161 } 162 if (fp->f_type == DTYPE_SOCKET) { 163 soioctl(fp->f_socket, uap->cmd, uap->cmarg); 164 return; 165 } 166 ip = fp->f_inode; 167 fmt = ip->i_mode & IFMT; 168 if (fmt != IFCHR) { 169 if (uap->cmd==FIONREAD && (fmt == IFREG || fmt == IFDIR)) { 170 off_t nread = ip->i_size - fp->f_offset; 171 172 if (copyout((caddr_t)&nread, uap->cmarg, sizeof(off_t))) 173 u.u_error = EFAULT; 174 } else if (uap->cmd == FIONBIO || uap->cmd == FIOASYNC) 175 return; 176 else 177 u.u_error = ENOTTY; 178 return; 179 } 180 dev = ip->i_rdev; 181 u.u_r.r_val1 = 0; 182 if ((u.u_procp->p_flag&SNUSIG) && setjmp(u.u_qsav)) { 183 u.u_eosys = RESTARTSYS; 184 return; 185 } 186 (*cdevsw[major(dev)].d_ioctl)(dev, uap->cmd, uap->cmarg, 0); 187 } 188 189 /* 190 * Do nothing specific version of line 191 * discipline specific ioctl command. 192 */ 193 /*ARGSUSED*/ 194 nullioctl(tp, cmd, addr) 195 struct tty *tp; 196 caddr_t addr; 197 { 198 199 return (cmd); 200 } 201 202 /* 203 * Read the file corresponding to 204 * the inode pointed at by the argument. 205 * The actual read arguments are found 206 * in the variables: 207 * u_base core address for destination 208 * u_offset byte offset in file 209 * u_count number of bytes to read 210 * u_segflg read to kernel/user/user I 211 */ 212 readi(ip) 213 register struct inode *ip; 214 { 215 struct buf *bp; 216 struct fs *fs; 217 dev_t dev; 218 daddr_t lbn, bn; 219 off_t diff; 220 register int on, type; 221 register unsigned n; 222 int size; 223 long bsize; 224 extern int mem_no; 225 226 if (u.u_count == 0) 227 return; 228 dev = (dev_t)ip->i_rdev; 229 if (u.u_offset < 0 && ((ip->i_mode&IFMT) != IFCHR || 230 mem_no != major(dev))) { 231 u.u_error = EINVAL; 232 return; 233 } 234 ip->i_flag |= IACC; 235 type = ip->i_mode&IFMT; 236 if (type == IFCHR) { 237 register c = u.u_count; 238 (*cdevsw[major(dev)].d_read)(dev); 239 CHARGE(sc_tio * (c - u.u_count)); 240 return; 241 } 242 if (type != IFBLK) { 243 dev = ip->i_dev; 244 fs = ip->i_fs; 245 bsize = fs->fs_bsize; 246 } else 247 bsize = BLKDEV_IOSIZE; 248 do { 249 lbn = u.u_offset / bsize; 250 on = u.u_offset % bsize; 251 n = MIN((unsigned)(bsize - on), u.u_count); 252 if (type != IFBLK) { 253 diff = ip->i_size - u.u_offset; 254 if (diff <= 0) 255 return; 256 if (diff < n) 257 n = diff; 258 bn = fsbtodb(fs, bmap(ip, lbn, B_READ)); 259 if (u.u_error) 260 return; 261 size = blksize(fs, ip, lbn); 262 } else { 263 size = bsize; 264 bn = lbn * (BLKDEV_IOSIZE/DEV_BSIZE); 265 rablock = bn + (BLKDEV_IOSIZE/DEV_BSIZE); 266 rasize = bsize; 267 } 268 if ((long)bn<0) { 269 bp = geteblk(size); 270 clrbuf(bp); 271 } else if (ip->i_lastr + 1 == lbn) 272 bp = breada(dev, bn, size, rablock, rasize); 273 else 274 bp = bread(dev, bn, size); 275 ip->i_lastr = lbn; 276 n = MIN(n, size - bp->b_resid); 277 if (n != 0) { 278 #ifdef UNFAST 279 iomove(bp->b_un.b_addr + on, n, B_READ); 280 #else 281 if (u.u_segflg != 1) { 282 if (copyout(bp->b_un.b_addr+on, u.u_base, n)) { 283 u.u_error = EFAULT; 284 goto bad; 285 } 286 } else 287 bcopy(bp->b_un.b_addr + on, u.u_base, n); 288 u.u_base += n; 289 u.u_offset += n; 290 u.u_count -= n; 291 bad: 292 ; 293 #endif 294 } 295 if (n + on == bsize || u.u_offset == ip->i_size) 296 bp->b_flags |= B_AGE; 297 brelse(bp); 298 } while (u.u_error == 0 && u.u_count != 0 && n != 0); 299 } 300 301 /* 302 * Write the file corresponding to 303 * the inode pointed at by the argument. 304 * The actual write arguments are found 305 * in the variables: 306 * u_base core address for source 307 * u_offset byte offset in file 308 * u_count number of bytes to write 309 * u_segflg write to kernel/user/user I 310 */ 311 writei(ip) 312 register struct inode *ip; 313 { 314 struct buf *bp; 315 register struct fs *fs; 316 dev_t dev; 317 daddr_t lbn, bn; 318 register int on, type; 319 register unsigned n; 320 long bsize; 321 int size, i, count; 322 extern int mem_no; 323 324 dev = (dev_t)ip->i_rdev; 325 if (u.u_offset < 0 && ((ip->i_mode&IFMT) != IFCHR || 326 mem_no != major(dev)) ) { 327 u.u_error = EINVAL; 328 return; 329 } 330 type = ip->i_mode & IFMT; 331 if (type == IFCHR) { 332 ip->i_flag |= IUPD|ICHG; 333 CHARGE(sc_tio * u.u_count); 334 (*cdevsw[major(dev)].d_write)(dev); 335 return; 336 } 337 if (u.u_count == 0) 338 return; 339 if ((ip->i_mode & IFMT) == IFREG && 340 u.u_offset + u.u_count > u.u_limit[LIM_FSIZE]) { 341 psignal(u.u_procp, SIGXFSZ); 342 u.u_error = EMFILE; 343 return; 344 } 345 if (type!=IFBLK) { 346 dev = ip->i_dev; 347 fs = ip->i_fs; 348 bsize = fs->fs_bsize; 349 } else { 350 bsize = BLKDEV_IOSIZE; 351 } 352 do { 353 lbn = u.u_offset / bsize; 354 on = u.u_offset % bsize; 355 n = MIN((unsigned)(bsize - on), u.u_count); 356 if (type != IFBLK) { 357 bn = fsbtodb(fs, bmap(ip, lbn, B_WRITE, (int)(on + n))); 358 if ((long)bn<0) 359 return; 360 if(u.u_offset + n > ip->i_size && 361 (type == IFDIR || type == IFREG || type == IFLNK)) 362 ip->i_size = u.u_offset + n; 363 size = blksize(fs, ip, lbn); 364 } else { 365 size = bsize; 366 bn = lbn * (BLKDEV_IOSIZE/DEV_BSIZE); 367 } 368 if (bn) { 369 count = howmany(size, DEV_BSIZE); 370 for (i = 0; i < count; i += CLSIZE) { 371 if (mfind(dev, bn + i)) 372 munhash(dev, bn + i); 373 } 374 } 375 if(n == bsize) 376 bp = getblk(dev, bn, size); 377 else 378 bp = bread(dev, bn, size); 379 #ifdef UNFAST 380 iomove(bp->b_un.b_addr + on, n, B_WRITE); 381 #else 382 if (u.u_segflg != 1) { 383 if (copyin(u.u_base, bp->b_un.b_addr + on, n)) { 384 u.u_error = EFAULT; 385 goto bad; 386 } 387 } else 388 bcopy(u.u_base, bp->b_un.b_addr + on, n); 389 u.u_base += n; 390 u.u_offset += n; 391 u.u_count -= n; 392 bad: 393 ; 394 #endif 395 if (u.u_error != 0) 396 brelse(bp); 397 else { 398 if ((ip->i_mode&IFMT) == IFDIR) 399 /* 400 * Writing to clear a directory entry. 401 * Must insure the write occurs before 402 * the inode is freed, or may end up 403 * pointing at a new (different) file 404 * if inode is quickly allocated again 405 * and system crashes. 406 */ 407 bwrite(bp); 408 else if (n + on == bsize) { 409 bp->b_flags |= B_AGE; 410 bawrite(bp); 411 } else 412 bdwrite(bp); 413 } 414 ip->i_flag |= IUPD|ICHG; 415 if (u.u_ruid != 0) 416 ip->i_mode &= ~(ISUID|ISGID); 417 } while (u.u_error == 0 && u.u_count != 0); 418 } 419 420 /* 421 * Move n bytes at byte location 422 * &bp->b_un.b_addr[o] to/from (flag) the 423 * user/kernel (u.segflg) area starting at u.base. 424 * Update all the arguments by the number 425 * of bytes moved. 426 */ 427 iomove(cp, n, flag) 428 register caddr_t cp; 429 register unsigned n; 430 { 431 register int t; 432 433 if (n==0) 434 return; 435 if (u.u_segflg != 1) { 436 if (flag==B_WRITE) 437 t = copyin(u.u_base, (caddr_t)cp, n); 438 else 439 t = copyout((caddr_t)cp, u.u_base, n); 440 if (t) { 441 u.u_error = EFAULT; 442 return; 443 } 444 } else 445 if (flag == B_WRITE) 446 bcopy(u.u_base, (caddr_t)cp, n); 447 else 448 bcopy((caddr_t)cp, u.u_base, n); 449 u.u_base += n; 450 u.u_offset += n; 451 u.u_count -= n; 452 } 453