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