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