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