1 /* 2 * Copyright (c) 1982, 1986 Regents of the University of California. 3 * All rights reserved. The Berkeley software License Agreement 4 * specifies the terms and conditions for redistribution. 5 * 6 * @(#)sys.c 7.4 (Berkeley) 04/17/87 7 */ 8 9 #include "param.h" 10 #include "inode.h" 11 #include "fs.h" 12 #include "dir.h" 13 #include "reboot.h" 14 #include "saio.h" 15 16 ino_t dlook(); 17 18 struct dirstuff { 19 int loc; 20 struct iob *io; 21 }; 22 23 static 24 openi(n, io) 25 register struct iob *io; 26 { 27 register struct dinode *dp; 28 int cc; 29 30 io->i_offset = 0; 31 io->i_bn = fsbtodb(&io->i_fs, itod(&io->i_fs, n)) + io->i_boff; 32 io->i_cc = io->i_fs.fs_bsize; 33 io->i_ma = io->i_buf; 34 cc = devread(io); 35 dp = (struct dinode *)io->i_buf; 36 io->i_ino.i_ic = dp[itoo(&io->i_fs, n)].di_ic; 37 return (cc); 38 } 39 40 static 41 find(path, file) 42 register char *path; 43 struct iob *file; 44 { 45 register char *q; 46 char *dir; 47 char c; 48 int n; 49 50 if (path==NULL || *path=='\0') { 51 printf("null path\n"); 52 return (0); 53 } 54 55 if (openi((ino_t) ROOTINO, file) < 0) { 56 printf("can't read root inode\n"); 57 return (0); 58 } 59 dir = path; 60 while (*path) { 61 while (*path == '/') 62 path++; 63 q = path; 64 while(*q != '/' && *q != '\0') 65 q++; 66 c = *q; 67 *q = '\0'; 68 if (q == path) path = "." ; /* "/" means "/." */ 69 70 if ((n = dlook(path, file, dir)) != 0) { 71 if (c == '\0') 72 break; 73 if (openi(n, file) < 0) 74 return (0); 75 *q = c; 76 path = q; 77 continue; 78 } else { 79 printf("%s: not found\n", path); 80 return (0); 81 } 82 } 83 return (n); 84 } 85 86 static daddr_t 87 sbmap(io, bn) 88 register struct iob *io; 89 daddr_t bn; 90 { 91 register struct inode *ip; 92 int i, j, sh; 93 daddr_t nb, *bap; 94 95 ip = &io->i_ino; 96 if (bn < 0) { 97 printf("bn negative\n"); 98 return ((daddr_t)0); 99 } 100 101 /* 102 * blocks 0..NDADDR are direct blocks 103 */ 104 if(bn < NDADDR) { 105 nb = ip->i_db[bn]; 106 return (nb); 107 } 108 109 /* 110 * addresses NIADDR have single and double indirect blocks. 111 * the first step is to determine how many levels of indirection. 112 */ 113 sh = 1; 114 bn -= NDADDR; 115 for (j = NIADDR; j > 0; j--) { 116 sh *= NINDIR(&io->i_fs); 117 if (bn < sh) 118 break; 119 bn -= sh; 120 } 121 if (j == 0) { 122 printf("bn ovf %D\n", bn); 123 return ((daddr_t)0); 124 } 125 126 /* 127 * fetch the first indirect block address from the inode 128 */ 129 nb = ip->i_ib[NIADDR - j]; 130 if (nb == 0) { 131 printf("bn void %D\n",bn); 132 return ((daddr_t)0); 133 } 134 135 /* 136 * fetch through the indirect blocks 137 */ 138 for (; j <= NIADDR; j++) { 139 if (blknos[j] != nb) { 140 io->i_bn = fsbtodb(&io->i_fs, nb) + io->i_boff; 141 io->i_ma = b[j]; 142 io->i_cc = io->i_fs.fs_bsize; 143 if (devread(io) != io->i_fs.fs_bsize) { 144 if (io->i_error) 145 errno = io->i_error; 146 printf("bn %D: read error\n", io->i_bn); 147 return ((daddr_t)0); 148 } 149 blknos[j] = nb; 150 } 151 bap = (daddr_t *)b[j]; 152 sh /= NINDIR(&io->i_fs); 153 i = (bn / sh) % NINDIR(&io->i_fs); 154 nb = bap[i]; 155 if(nb == 0) { 156 printf("bn void %D\n",bn); 157 return ((daddr_t)0); 158 } 159 } 160 return (nb); 161 } 162 163 static ino_t 164 dlook(s, io, dir) 165 char *s; 166 register struct iob *io; 167 char *dir; 168 { 169 register struct direct *dp; 170 register struct inode *ip; 171 struct dirstuff dirp; 172 int len; 173 174 if (s == NULL || *s == '\0') 175 return (0); 176 ip = &io->i_ino; 177 if ((ip->i_mode&IFMT) != IFDIR) { 178 printf("not a directory\n"); 179 printf("%s: not a directory\n", dir); 180 return (0); 181 } 182 if (ip->i_size == 0) { 183 printf("%s: zero length directory\n", dir); 184 return (0); 185 } 186 len = strlen(s); 187 dirp.loc = 0; 188 dirp.io = io; 189 for (dp = readdir(&dirp); dp != NULL; dp = readdir(&dirp)) { 190 if(dp->d_ino == 0) 191 continue; 192 if (dp->d_namlen == len && !strcmp(s, dp->d_name)) 193 return (dp->d_ino); 194 } 195 return (0); 196 } 197 198 /* 199 * get next entry in a directory. 200 */ 201 struct direct * 202 readdir(dirp) 203 register struct dirstuff *dirp; 204 { 205 register struct direct *dp; 206 register struct iob *io; 207 daddr_t lbn, d; 208 int off; 209 210 io = dirp->io; 211 for(;;) { 212 if (dirp->loc >= io->i_ino.i_size) 213 return (NULL); 214 off = blkoff(&io->i_fs, dirp->loc); 215 if (off == 0) { 216 lbn = lblkno(&io->i_fs, dirp->loc); 217 d = sbmap(io, lbn); 218 if(d == 0) 219 return NULL; 220 io->i_bn = fsbtodb(&io->i_fs, d) + io->i_boff; 221 io->i_ma = io->i_buf; 222 io->i_cc = blksize(&io->i_fs, &io->i_ino, lbn); 223 if (devread(io) < 0) { 224 errno = io->i_error; 225 printf("bn %D: directory read error\n", 226 io->i_bn); 227 return (NULL); 228 } 229 } 230 dp = (struct direct *)(io->i_buf + off); 231 dirp->loc += dp->d_reclen; 232 if (dp->d_ino == 0) 233 continue; 234 return (dp); 235 } 236 } 237 238 lseek(fdesc, addr, ptr) 239 int fdesc, ptr; 240 off_t addr; 241 { 242 register struct iob *io; 243 244 #ifndef SMALL 245 if (ptr != 0) { 246 printf("Seek not from beginning of file\n"); 247 errno = EOFFSET; 248 return (-1); 249 } 250 #endif SMALL 251 fdesc -= 3; 252 if (fdesc < 0 || fdesc >= NFILES || 253 ((io = &iob[fdesc])->i_flgs & F_ALLOC) == 0) { 254 errno = EBADF; 255 return (-1); 256 } 257 io->i_offset = addr; 258 io->i_bn = addr / DEV_BSIZE; 259 io->i_cc = 0; 260 return (0); 261 } 262 263 getc(fdesc) 264 int fdesc; 265 { 266 register struct iob *io; 267 register struct fs *fs; 268 register char *p; 269 int c, lbn, off, size, diff; 270 271 272 if (fdesc >= 0 && fdesc <= 2) 273 return (getchar()); 274 fdesc -= 3; 275 if (fdesc < 0 || fdesc >= NFILES || 276 ((io = &iob[fdesc])->i_flgs&F_ALLOC) == 0) { 277 errno = EBADF; 278 return (-1); 279 } 280 p = io->i_ma; 281 if (io->i_cc <= 0) { 282 if ((io->i_flgs & F_FILE) != 0) { 283 diff = io->i_ino.i_size - io->i_offset; 284 if (diff <= 0) 285 return (-1); 286 fs = &io->i_fs; 287 lbn = lblkno(fs, io->i_offset); 288 io->i_bn = fsbtodb(fs, sbmap(io, lbn)) + io->i_boff; 289 off = blkoff(fs, io->i_offset); 290 size = blksize(fs, &io->i_ino, lbn); 291 } else { 292 io->i_bn = io->i_offset / DEV_BSIZE; 293 off = 0; 294 size = DEV_BSIZE; 295 } 296 io->i_ma = io->i_buf; 297 io->i_cc = size; 298 if (devread(io) < 0) { 299 errno = io->i_error; 300 return (-1); 301 } 302 if ((io->i_flgs & F_FILE) != 0) { 303 if (io->i_offset - off + size >= io->i_ino.i_size) 304 io->i_cc = diff + off; 305 io->i_cc -= off; 306 } 307 p = &io->i_buf[off]; 308 } 309 io->i_cc--; 310 io->i_offset++; 311 c = (unsigned)*p++; 312 io->i_ma = p; 313 return (c); 314 } 315 316 int errno; 317 318 read(fdesc, buf, count) 319 int fdesc, count; 320 char *buf; 321 { 322 register i, size; 323 register struct iob *file; 324 register struct fs *fs; 325 int lbn, off; 326 327 errno = 0; 328 if (fdesc >= 0 & fdesc <= 2) { 329 i = count; 330 do { 331 *buf = getchar(); 332 } while (--i && *buf++ != '\n'); 333 return (count - i); 334 } 335 fdesc -= 3; 336 if (fdesc < 0 || fdesc >= NFILES || 337 ((file = &iob[fdesc])->i_flgs&F_ALLOC) == 0) { 338 errno = EBADF; 339 return (-1); 340 } 341 if ((file->i_flgs&F_READ) == 0) { 342 errno = EBADF; 343 return (-1); 344 } 345 #ifndef SMALL 346 if ((file->i_flgs & F_FILE) == 0) { 347 file->i_cc = count; 348 file->i_ma = buf; 349 file->i_bn = file->i_boff + (file->i_offset / DEV_BSIZE); 350 i = devread(file); 351 if (i < 0) 352 errno = file->i_error; 353 else 354 file->i_offset += i; 355 return (i); 356 } 357 #endif SMALL 358 if (file->i_offset+count > file->i_ino.i_size) 359 count = file->i_ino.i_size - file->i_offset; 360 if ((i = count) <= 0) 361 return (0); 362 /* 363 * While reading full blocks, do I/O into user buffer. 364 * Anything else uses getc(). 365 */ 366 fs = &file->i_fs; 367 while (i) { 368 off = blkoff(fs, file->i_offset); 369 lbn = lblkno(fs, file->i_offset); 370 size = blksize(fs, &file->i_ino, lbn); 371 if (off == 0 && size <= i) { 372 file->i_bn = fsbtodb(fs, sbmap(file, lbn)) + 373 file->i_boff; 374 file->i_cc = size; 375 file->i_ma = buf; 376 if (devread(file) < 0) { 377 errno = file->i_error; 378 return (-1); 379 } 380 file->i_offset += size; 381 file->i_cc = 0; 382 buf += size; 383 i -= size; 384 } else { 385 size -= off; 386 if (size > i) 387 size = i; 388 i -= size; 389 do { 390 *buf++ = getc(fdesc+3); 391 } while (--size); 392 } 393 } 394 return (count); 395 } 396 397 #ifndef SMALL 398 write(fdesc, buf, count) 399 int fdesc, count; 400 char *buf; 401 { 402 register i; 403 register struct iob *file; 404 405 errno = 0; 406 if (fdesc >= 0 && fdesc <= 2) { 407 i = count; 408 while (i--) 409 putchar(*buf++); 410 return (count); 411 } 412 fdesc -= 3; 413 if (fdesc < 0 || fdesc >= NFILES || 414 ((file = &iob[fdesc])->i_flgs&F_ALLOC) == 0) { 415 errno = EBADF; 416 return (-1); 417 } 418 if ((file->i_flgs&F_WRITE) == 0) { 419 errno = EBADF; 420 return (-1); 421 } 422 file->i_cc = count; 423 file->i_ma = buf; 424 file->i_bn = file->i_boff + (file->i_offset / DEV_BSIZE); 425 i = devwrite(file); 426 file->i_offset += count; 427 if (i < 0) 428 errno = file->i_error; 429 return (i); 430 } 431 #endif SMALL 432 433 int openfirst = 1; 434 unsigned opendev; /* last device opened */ 435 extern unsigned bootdev; 436 437 open(str, how) 438 char *str; 439 int how; 440 { 441 register char *cp; 442 register int i; 443 register struct iob *file; 444 int fdesc; 445 long atol(); 446 447 if (openfirst) { 448 for (i = 0; i < NFILES; i++) 449 iob[i].i_flgs = 0; 450 openfirst = 0; 451 } 452 453 for (fdesc = 0; fdesc < NFILES; fdesc++) 454 if (iob[fdesc].i_flgs == 0) 455 goto gotfile; 456 _stop("No more file slots"); 457 gotfile: 458 (file = &iob[fdesc])->i_flgs |= F_ALLOC; 459 460 #ifndef SMALL 461 for (cp = str; *cp && *cp != '/' && *cp != ':' && *cp != '('; cp++) 462 ; 463 if (*cp == '(') { 464 if ((file->i_ino.i_dev = getdev(str, cp - str)) == -1) 465 goto bad; 466 cp++; 467 if ((file->i_unit = getunit(cp)) == -1) 468 goto bad; 469 for (; *cp != ','; cp++) 470 if (*cp == NULL) { 471 errno = EOFFSET; 472 goto badspec; 473 } 474 file->i_boff = atol(++cp); 475 for (;;) { 476 if (*cp == ')') 477 break; 478 if (*cp++) 479 continue; 480 goto badspec; 481 } 482 cp++; 483 } else if (*cp != ':') { 484 #endif 485 /* default bootstrap unit and device */ 486 file->i_ino.i_dev = (bootdev >> B_TYPESHIFT) & B_TYPEMASK; 487 file->i_unit = ((bootdev >> B_UNITSHIFT) & B_UNITMASK) + 488 (8 * ((bootdev >> B_ADAPTORSHIFT) & B_ADAPTORMASK)); 489 file->i_boff = (bootdev >> B_PARTITIONSHIFT) & B_PARTITIONMASK; 490 cp = str; 491 #ifndef SMALL 492 } else { 493 # define isdigit(n) ((n>='0') && (n<='9')) 494 if (cp == str) 495 goto badspec; 496 /* 497 * syntax for possible device name: 498 * <alpha-string><digit-string><letter>: 499 */ 500 for (cp = str; *cp != ':' && !isdigit(*cp); cp++) 501 ; 502 if ((file->i_ino.i_dev = getdev(str, cp - str)) == -1) 503 goto bad; 504 if ((file->i_unit = getunit(cp)) == -1) 505 goto bad; 506 while (isdigit(*cp)) 507 cp++; 508 file->i_boff = 0; 509 if (*cp >= 'a' && *cp <= 'h') 510 file->i_boff = *cp++ - 'a'; 511 if (*cp++ != ':') { 512 errno = EOFFSET; 513 goto badspec; 514 } 515 } 516 #endif 517 opendev = file->i_ino.i_dev << B_TYPESHIFT; 518 opendev |= ((file->i_unit % 8) << B_UNITSHIFT); 519 opendev |= ((file->i_unit / 8) << B_ADAPTORSHIFT); 520 opendev |= file->i_boff << B_PARTITIONSHIFT; 521 opendev |= B_DEVMAGIC; 522 if (errno = devopen(file)) 523 goto bad; 524 if (cp != str && *cp == '\0') { 525 file->i_flgs |= how+1; 526 file->i_cc = 0; 527 file->i_offset = 0; 528 return (fdesc+3); 529 } 530 file->i_ma = (char *)(&file->i_fs); 531 file->i_cc = SBSIZE; 532 file->i_bn = SBOFF / DEV_BSIZE + file->i_boff; 533 file->i_offset = 0; 534 if (devread(file) < 0) { 535 errno = file->i_error; 536 printf("super block read error\n"); 537 goto bad; 538 } 539 if ((i = find(cp, file)) == 0) { 540 errno = ESRCH; 541 goto bad; 542 } 543 #ifndef SMALL 544 if (how != 0) { 545 printf("Can't write files yet.. Sorry\n"); 546 errno = EIO; 547 goto bad; 548 } 549 #endif SMALL 550 if (openi(i, file) < 0) { 551 errno = file->i_error; 552 goto bad; 553 } 554 file->i_offset = 0; 555 file->i_cc = 0; 556 file->i_flgs |= F_FILE | (how+1); 557 return (fdesc+3); 558 559 badspec: 560 printf("malformed device specification\n"); 561 bad: 562 file->i_flgs = 0; 563 return (-1); 564 } 565 566 #ifndef SMALL 567 static 568 getdev(str, len) 569 char *str; 570 int len; 571 { 572 register struct devsw *dp; 573 574 for (dp = devsw; dp->dv_name; dp++) { 575 if (!strncmp(str, dp->dv_name, len)) 576 return (dp - devsw); 577 } 578 printf("Unknown device\n"); 579 errno = ENXIO; 580 return (-1); 581 } 582 583 static 584 getunit(cp) 585 register char *cp; 586 { 587 register int i = 0; 588 589 while (*cp >= '0' && *cp <= '9') 590 i = i * 10 + *cp++ - '0'; 591 if ((unsigned) i > 255) { 592 printf("minor device number out of range (0-255)\n"); 593 errno = EUNIT; 594 i = -1; 595 } 596 return (i); 597 } 598 #endif 599 600 close(fdesc) 601 int fdesc; 602 { 603 struct iob *file; 604 605 fdesc -= 3; 606 if (fdesc < 0 || fdesc >= NFILES || 607 ((file = &iob[fdesc])->i_flgs&F_ALLOC) == 0) { 608 errno = EBADF; 609 return (-1); 610 } 611 if ((file->i_flgs&F_FILE) == 0) 612 devclose(file); 613 file->i_flgs = 0; 614 return (0); 615 } 616 617 #ifndef SMALL 618 ioctl(fdesc, cmd, arg) 619 int fdesc, cmd; 620 char *arg; 621 { 622 register struct iob *file; 623 int error = 0; 624 625 fdesc -= 3; 626 if (fdesc < 0 || fdesc >= NFILES || 627 ((file = &iob[fdesc])->i_flgs&F_ALLOC) == 0) { 628 errno = EBADF; 629 return (-1); 630 } 631 switch (cmd) { 632 633 case SAIOHDR: 634 file->i_flgs |= F_HDR; 635 break; 636 637 case SAIOCHECK: 638 file->i_flgs |= F_CHECK; 639 break; 640 641 case SAIOHCHECK: 642 file->i_flgs |= F_HCHECK; 643 break; 644 645 case SAIONOBAD: 646 file->i_flgs |= F_NBSF; 647 break; 648 649 case SAIODOBAD: 650 file->i_flgs &= ~F_NBSF; 651 break; 652 653 default: 654 error = devioctl(file, cmd, arg); 655 break; 656 } 657 if (error < 0) 658 errno = file->i_error; 659 return (error); 660 } 661 #endif SMALL 662 663 exit() 664 { 665 _stop("Exit called"); 666 } 667 668 _stop(s) 669 char *s; 670 { 671 int i; 672 673 for (i = 0; i < NFILES; i++) 674 if (iob[i].i_flgs != 0) 675 close(i); 676 printf("%s\n", s); 677 _rtt(); 678 } 679