1 /* vfs_syscalls.c 4.26 82/06/10 */ 2 3 #ifdef SIMFS 4 #include "../h/sysrenam.h" 5 #endif 6 #include "../h/param.h" 7 #include "../h/systm.h" 8 #include "../h/dir.h" 9 #include "../h/user.h" 10 #include "../h/file.h" 11 #include "../h/stat.h" 12 #include "../h/inode.h" 13 #include "../h/fs.h" 14 #include "../h/buf.h" 15 #include "../h/proc.h" 16 #include "../h/inline.h" 17 18 chdir() 19 { 20 21 chdirec(&u.u_cdir); 22 } 23 24 chroot() 25 { 26 27 if (suser()) 28 chdirec(&u.u_rdir); 29 } 30 31 chdirec(ipp) 32 register struct inode **ipp; 33 { 34 register struct inode *ip; 35 struct a { 36 char *fname; 37 }; 38 39 ip = namei(uchar, 0, 1); 40 if(ip == NULL) 41 return; 42 if((ip->i_mode&IFMT) != IFDIR) { 43 u.u_error = ENOTDIR; 44 goto bad; 45 } 46 if(access(ip, IEXEC)) 47 goto bad; 48 iunlock(ip); 49 if (*ipp) 50 irele(*ipp); 51 *ipp = ip; 52 return; 53 54 bad: 55 iput(ip); 56 } 57 58 /* 59 * Open system call. 60 */ 61 open() 62 { 63 register struct inode *ip; 64 register struct a { 65 char *fname; 66 int rwmode; 67 } *uap; 68 69 uap = (struct a *)u.u_ap; 70 ip = namei(uchar, 0, 1); 71 if (ip == NULL) 72 return; 73 open1(ip, ++uap->rwmode, 0); 74 } 75 76 /* 77 * Creat system call. 78 */ 79 creat() 80 { 81 register struct inode *ip; 82 register struct a { 83 char *fname; 84 int fmode; 85 } *uap; 86 87 uap = (struct a *)u.u_ap; 88 ip = namei(uchar, 1, 1); 89 if (ip == NULL) { 90 if (u.u_error) 91 return; 92 ip = maknode(uap->fmode&07777&(~ISVTX)); 93 if (ip==NULL) 94 return; 95 open1(ip, FWRITE, 2); 96 } else 97 open1(ip, FWRITE, 1); 98 } 99 100 /* 101 * Common code for open and creat. 102 * Check permissions, allocate an open file structure, 103 * and call the device open routine if any. 104 */ 105 open1(ip, mode, trf) 106 register struct inode *ip; 107 register mode; 108 { 109 register struct file *fp; 110 int i; 111 112 if (trf != 2) { 113 if (mode&FREAD) 114 (void) access(ip, IREAD); 115 if (mode&FWRITE) { 116 (void) access(ip, IWRITE); 117 if ((ip->i_mode&IFMT) == IFDIR) 118 u.u_error = EISDIR; 119 } 120 } 121 if (u.u_error) { 122 iput(ip); 123 return; 124 } 125 if (trf == 1) 126 itrunc(ip); 127 iunlock(ip); 128 if ((fp = falloc()) == NULL) 129 goto out; 130 fp->f_flag = mode&(FREAD|FWRITE); 131 i = u.u_r.r_val1; 132 fp->f_inode = ip; 133 openi(ip, mode&(FREAD|FWRITE)); 134 if (u.u_error == 0) 135 return; 136 u.u_ofile[i] = NULL; 137 fp->f_count--; 138 out: 139 irele(ip); 140 } 141 142 /* 143 * Mknod system call 144 */ 145 mknod() 146 { 147 register struct inode *ip; 148 register struct a { 149 char *fname; 150 int fmode; 151 int dev; 152 } *uap; 153 154 uap = (struct a *)u.u_ap; 155 if (suser()) { 156 ip = namei(uchar, 1, 0); 157 if (ip != NULL) { 158 u.u_error = EEXIST; 159 goto out; 160 } 161 } 162 if (u.u_error) 163 return; 164 ip = maknode(uap->fmode); 165 if (ip == NULL) 166 return; 167 if (uap->dev) { 168 /* 169 * Want to be able to use this to make badblock 170 * inodes, so don't truncate the dev number. 171 */ 172 ip->i_rdev = uap->dev; 173 ip->i_flag |= IACC|IUPD|ICHG; 174 } 175 176 out: 177 iput(ip); 178 } 179 180 /* 181 * link system call 182 */ 183 link() 184 { 185 register struct inode *ip, *xp; 186 register struct a { 187 char *target; 188 char *linkname; 189 } *uap; 190 191 uap = (struct a *)u.u_ap; 192 ip = namei(uchar, 0, 1); /* well, this routine is doomed anyhow */ 193 if (ip == NULL) 194 return; 195 if ((ip->i_mode&IFMT)==IFDIR && !suser()) 196 goto out1; 197 ip->i_nlink++; 198 ip->i_flag |= ICHG; 199 iupdat(ip, &time, &time, 1); 200 iunlock(ip); 201 u.u_dirp = (caddr_t)uap->linkname; 202 xp = namei(uchar, 1, 0); 203 if (xp != NULL) { 204 u.u_error = EEXIST; 205 iput(xp); 206 goto out; 207 } 208 if (u.u_error) 209 goto out; 210 if (u.u_pdir->i_dev != ip->i_dev) { 211 iput(u.u_pdir); 212 u.u_error = EXDEV; 213 goto out; 214 } 215 wdir(ip); 216 out: 217 if (u.u_error) { 218 ip->i_nlink--; 219 ip->i_flag |= ICHG; 220 } 221 out1: 222 irele(ip); 223 } 224 225 /* 226 * symlink -- make a symbolic link 227 */ 228 symlink() 229 { 230 register struct a { 231 char *target; 232 char *linkname; 233 } *uap; 234 register struct inode *ip; 235 register char *tp; 236 register c, nc; 237 238 uap = (struct a *)u.u_ap; 239 tp = uap->target; 240 nc = 0; 241 while (c = fubyte(tp)) { 242 if (c < 0) { 243 u.u_error = EFAULT; 244 return; 245 } 246 tp++; 247 nc++; 248 } 249 u.u_dirp = uap->linkname; 250 ip = namei(uchar, 1, 0); 251 if (ip) { 252 iput(ip); 253 u.u_error = EEXIST; 254 return; 255 } 256 if (u.u_error) 257 return; 258 ip = maknode(IFLNK | 0777); 259 if (ip == NULL) 260 return; 261 u.u_base = uap->target; 262 u.u_count = nc; 263 u.u_offset = 0; 264 u.u_segflg = 0; 265 writei(ip); 266 iput(ip); 267 } 268 269 /* 270 * Unlink system call. 271 * Hard to avoid races here, especially 272 * in unlinking directories. 273 */ 274 unlink() 275 { 276 register struct inode *ip, *pp; 277 struct a { 278 char *fname; 279 }; 280 struct fs *fs; 281 struct buf *bp; 282 int lbn, bn, base; 283 int unlinkingdot = 0; 284 285 pp = namei(uchar, 2, 0); 286 if(pp == NULL) 287 return; 288 /* 289 * Check for unlink(".") 290 * to avoid hanging on the iget 291 */ 292 if (pp->i_number == u.u_dent.d_ino) { 293 ip = pp; 294 ip->i_count++; 295 unlinkingdot++; 296 } else 297 ip = iget(pp->i_dev, pp->i_fs, u.u_dent.d_ino); 298 if(ip == NULL) 299 goto out1; 300 if((ip->i_mode&IFMT)==IFDIR && !suser()) 301 goto out; 302 /* 303 * Don't unlink a mounted file. 304 */ 305 if (ip->i_dev != pp->i_dev) { 306 u.u_error = EBUSY; 307 goto out; 308 } 309 if (ip->i_flag&ITEXT) 310 xrele(ip); /* try once to free text */ 311 /* 312 if ((ip->i_flag&ITEXT) && ip->i_nlink==1) { 313 u.u_error = ETXTBSY; 314 goto out; 315 } 316 */ 317 if (u.u_count == 0) { 318 /* 319 * first entry in block, so set d_ino to zero. 320 */ 321 u.u_base = (caddr_t)&u.u_dent; 322 u.u_count = DIRSIZ(&u.u_dent); 323 u.u_dent.d_ino = 0; 324 writei(pp); 325 } else { 326 /* 327 * updating preceeding entry to skip over current entry. 328 */ 329 fs = pp->i_fs; 330 lbn = lblkno(fs, u.u_offset); 331 base = blkoff(fs, u.u_offset); 332 bn = fsbtodb(fs, bmap(pp, lbn, B_WRITE, base + u.u_count)); 333 bp = bread(pp->i_dev, bn, blksize(fs, pp, lbn)); 334 if (bp->b_flags & B_ERROR) { 335 brelse(bp); 336 goto out; 337 } 338 ((struct direct *)(bp->b_un.b_addr + base))->d_reclen += 339 u.u_dent.d_reclen; 340 bwrite(bp); 341 pp->i_flag |= IUPD|ICHG; 342 } 343 ip->i_nlink--; 344 ip->i_flag |= ICHG; 345 346 out: 347 if (unlinkingdot) 348 irele(ip); 349 else 350 iput(ip); 351 out1: 352 iput(pp); 353 } 354 355 /* 356 * Seek system call 357 */ 358 seek() 359 { 360 register struct file *fp; 361 register struct a { 362 int fdes; 363 off_t off; 364 int sbase; 365 } *uap; 366 367 uap = (struct a *)u.u_ap; 368 fp = getf(uap->fdes); 369 if (fp == NULL) 370 return; 371 if (fp->f_flag&FSOCKET) { 372 u.u_error = ESPIPE; 373 return; 374 } 375 if (uap->sbase == 1) 376 uap->off += fp->f_offset; 377 else if (uap->sbase == 2) 378 uap->off += fp->f_inode->i_size; 379 fp->f_offset = uap->off; 380 u.u_r.r_off = uap->off; 381 } 382 383 /* 384 * Access system call 385 */ 386 saccess() 387 { 388 register svuid, svgid; 389 register struct inode *ip; 390 register struct a { 391 char *fname; 392 int fmode; 393 } *uap; 394 395 uap = (struct a *)u.u_ap; 396 svuid = u.u_uid; 397 svgid = u.u_gid; 398 u.u_uid = u.u_ruid; 399 u.u_gid = u.u_rgid; 400 ip = namei(uchar, 0, 1); 401 if (ip != NULL) { 402 if (uap->fmode&(IREAD>>6)) 403 (void) access(ip, IREAD); 404 if (uap->fmode&(IWRITE>>6)) 405 (void) access(ip, IWRITE); 406 if (uap->fmode&(IEXEC>>6)) 407 (void) access(ip, IEXEC); 408 iput(ip); 409 } 410 u.u_uid = svuid; 411 u.u_gid = svgid; 412 } 413 414 /* 415 * the fstat system call. 416 */ 417 fstat() 418 { 419 register struct file *fp; 420 register struct a { 421 int fdes; 422 struct stat *sb; 423 } *uap; 424 425 uap = (struct a *)u.u_ap; 426 fp = getf(uap->fdes); 427 if (fp == NULL) 428 return; 429 if (fp->f_flag & FSOCKET) 430 u.u_error = sostat(fp->f_socket, uap->sb); 431 else 432 stat1(fp->f_inode, uap->sb); 433 } 434 435 /* 436 * Stat system call. This version follows links. 437 */ 438 stat() 439 { 440 register struct inode *ip; 441 register struct a { 442 char *fname; 443 struct stat *sb; 444 } *uap; 445 446 uap = (struct a *)u.u_ap; 447 ip = namei(uchar, 0, 1); 448 if (ip == NULL) 449 return; 450 stat1(ip, uap->sb); 451 iput(ip); 452 } 453 454 /* 455 * Lstat system call. This version does not follow links. 456 */ 457 lstat() 458 { 459 register struct inode *ip; 460 register struct a { 461 char *fname; 462 struct stat *sb; 463 } *uap; 464 465 uap = (struct a *)u.u_ap; 466 ip = namei(uchar, 0, 0); 467 if (ip == NULL) 468 return; 469 stat1(ip, uap->sb); 470 iput(ip); 471 } 472 473 /* 474 * The basic routine for fstat and stat: 475 * get the inode and pass appropriate parts back. 476 */ 477 stat1(ip, ub) 478 register struct inode *ip; 479 struct stat *ub; 480 { 481 struct stat ds; 482 483 IUPDAT(ip, &time, &time, 0); 484 /* 485 * Copy from inode table 486 */ 487 ds.st_dev = ip->i_dev; 488 ds.st_ino = ip->i_number; 489 ds.st_mode = ip->i_mode; 490 ds.st_nlink = ip->i_nlink; 491 ds.st_uid = ip->i_uid; 492 ds.st_gid = ip->i_gid; 493 ds.st_rdev = (dev_t)ip->i_rdev; 494 ds.st_size = ip->i_size; 495 ds.st_atime = ip->i_atime; 496 ds.st_mtime = ip->i_mtime; 497 ds.st_ctime = ip->i_ctime; 498 ds.st_blksize = ip->i_fs->fs_bsize; 499 if (copyout((caddr_t)&ds, (caddr_t)ub, sizeof(ds)) < 0) 500 u.u_error = EFAULT; 501 } 502 503 /* 504 * Return target name of a symbolic link 505 */ 506 readlink() 507 { 508 register struct inode *ip; 509 register struct a { 510 char *name; 511 char *buf; 512 int count; 513 } *uap; 514 515 ip = namei(uchar, 0, 0); 516 if (ip == NULL) 517 return; 518 if ((ip->i_mode&IFMT) != IFLNK) { 519 u.u_error = ENXIO; 520 goto out; 521 } 522 uap = (struct a *)u.u_ap; 523 u.u_offset = 0; 524 u.u_base = uap->buf; 525 u.u_count = uap->count; 526 u.u_segflg = 0; 527 readi(ip); 528 out: 529 iput(ip); 530 u.u_r.r_val1 = uap->count - u.u_count; 531 } 532 533 chmod() 534 { 535 register struct inode *ip; 536 register struct a { 537 char *fname; 538 int fmode; 539 } *uap; 540 541 uap = (struct a *)u.u_ap; 542 if ((ip = owner(1)) == NULL) 543 return; 544 ip->i_mode &= ~07777; 545 if (u.u_uid) 546 uap->fmode &= ~ISVTX; 547 ip->i_mode |= uap->fmode&07777; 548 ip->i_flag |= ICHG; 549 if (ip->i_flag&ITEXT && (ip->i_mode&ISVTX)==0) 550 xrele(ip); 551 iput(ip); 552 } 553 554 chown() 555 { 556 register struct inode *ip; 557 register struct a { 558 char *fname; 559 int uid; 560 int gid; 561 } *uap; 562 563 uap = (struct a *)u.u_ap; 564 if (!suser() || (ip = owner(0)) == NULL) 565 return; 566 ip->i_uid = uap->uid; 567 ip->i_gid = uap->gid; 568 ip->i_flag |= ICHG; 569 if (u.u_ruid != 0) 570 ip->i_mode &= ~(ISUID|ISGID); 571 iput(ip); 572 } 573 574 /* 575 * Set IUPD and IACC times on file. 576 * Can't set ICHG. 577 */ 578 utime() 579 { 580 register struct a { 581 char *fname; 582 time_t *tptr; 583 } *uap; 584 register struct inode *ip; 585 time_t tv[2]; 586 587 uap = (struct a *)u.u_ap; 588 if ((ip = owner(1)) == NULL) 589 return; 590 if (copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof(tv))) { 591 u.u_error = EFAULT; 592 } else { 593 ip->i_flag |= IACC|IUPD|ICHG; 594 iupdat(ip, &tv[0], &tv[1], 0); 595 } 596 iput(ip); 597 } 598 599 sync() 600 { 601 602 update(0); 603 } 604