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