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