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