1 /* 2 * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 7 /* All Rights Reserved */ 8 9 /* 10 * Copyright (c) 1980, 1986, 1990 The Regents of the University of California. 11 * All rights reserved. 12 * 13 * Redistribution and use in source and binary forms are permitted 14 * provided that: (1) source distributions retain this entire copyright 15 * notice and comment, and (2) distributions including binaries display 16 * the following acknowledgement: ``This product includes software 17 * developed by the University of California, Berkeley and its contributors'' 18 * in the documentation or other materials provided with the distribution 19 * and in all advertising materials mentioning features or use of this 20 * software. Neither the name of the University nor the names of its 21 * contributors may be used to endorse or promote products derived 22 * from this software without specific prior written permission. 23 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 24 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 25 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 26 */ 27 28 #pragma ident "%Z%%M% %I% %E% SMI" 29 30 #include <stdio.h> 31 #include <sys/param.h> 32 #include <sys/types.h> 33 #include <sys/mntent.h> 34 #include <sys/filio.h> 35 36 #define bcopy(f, t, n) memcpy(t, f, n) 37 #define bzero(s, n) memset(s, 0, n) 38 #define bcmp(s, d, n) memcmp(s, d, n) 39 40 #define index(s, r) strchr(s, r) 41 #define rindex(s, r) strrchr(s, r) 42 43 #include <sys/fs/ufs_fs.h> 44 #include <sys/vnode.h> 45 #include <sys/fs/ufs_inode.h> 46 #include <sys/fs/ufs_acl.h> 47 #define _KERNEL 48 #include <sys/fs/ufs_fsdir.h> 49 #undef _KERNEL 50 #include <sys/mnttab.h> 51 #include <sys/types.h> 52 #include <sys/stat.h> 53 #include <sys/signal.h> 54 #include <string.h> 55 #include <ctype.h> 56 #include "fsck.h" 57 #include <sys/vfstab.h> 58 #include <sys/lockfs.h> 59 #include <errno.h> 60 61 int64_t diskreads, totalreads; /* Disk cache statistics */ 62 offset_t llseek(); 63 char *malloc(); 64 char *mount_point = NULL; 65 66 extern int mflag; 67 extern uint_t largefile_count; 68 69 static struct bufarea *alloc_bufarea(); 70 71 ftypeok(dp) 72 struct dinode *dp; 73 { 74 switch (dp->di_mode & IFMT) { 75 76 case IFDIR: 77 case IFREG: 78 case IFBLK: 79 case IFCHR: 80 case IFLNK: 81 case IFSOCK: 82 case IFIFO: 83 case IFSHAD: 84 case IFATTRDIR: 85 return (1); 86 87 default: 88 if (debug) 89 printf("bad file type 0%o\n", dp->di_mode); 90 return (0); 91 } 92 } 93 94 acltypeok(dp) 95 struct dinode *dp; 96 { 97 if (CHECK_ACL_ALLOWED(dp->di_mode & IFMT)) 98 return (1); 99 100 if (debug) 101 printf("bad file type for acl 0%o\n", dp->di_mode); 102 return (0); 103 } 104 105 reply(question) 106 char *question; 107 { 108 char line[80]; 109 110 if (preen) 111 pfatal("INTERNAL ERROR: GOT TO reply()"); 112 113 if (mflag) { 114 printf("\n"); 115 printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n", 116 devname); 117 exit(39); 118 } 119 120 printf("\n%s? ", question); 121 if (nflag || fswritefd < 0) { 122 printf(" no\n\n"); 123 iscorrupt = 1; /* known to be corrupt */ 124 return (0); 125 } 126 if (yflag) { 127 printf(" yes\n\n"); 128 return (1); 129 } 130 if (getline(stdin, line, sizeof (line)) == EOF) 131 errexit("\n"); 132 printf("\n"); 133 if (line[0] == 'y' || line[0] == 'Y') 134 return (1); 135 else { 136 iscorrupt = 1; /* known to be corrupt */ 137 return (0); 138 } 139 } 140 141 getline(fp, loc, maxlen) 142 FILE *fp; 143 char *loc; 144 { 145 int n; 146 char *p, *lastloc; 147 148 p = loc; 149 lastloc = &p[maxlen-1]; 150 while ((n = getc(fp)) != '\n') { 151 if (n == EOF) 152 return (EOF); 153 if (!isspace(n) && p < lastloc) 154 *p++ = n; 155 } 156 *p = 0; 157 return (p - loc); 158 } 159 /* 160 * Malloc buffers and set up cache. 161 */ 162 bufinit() 163 { 164 struct bufarea *bp; 165 int bufcnt, i; 166 char *bufp; 167 168 bufp = malloc((unsigned int)sblock.fs_bsize); 169 if (bufp == 0) 170 errexit("cannot allocate buffer pool\n"); 171 cgblk.b_un.b_buf = bufp; 172 initbarea(&cgblk); 173 bufhead.b_next = bufhead.b_prev = &bufhead; 174 bufcnt = MAXBUFSPACE / sblock.fs_bsize; 175 if (bufcnt < MINBUFS) 176 bufcnt = MINBUFS; 177 for (i = 0; i < bufcnt; i++) { 178 bp = (struct bufarea *)malloc(sizeof (struct bufarea)); 179 bufp = malloc((unsigned int)sblock.fs_bsize); 180 if (bp == NULL || bufp == NULL) { 181 if (bp) 182 free((char *)bp); 183 if (bufp) 184 free(bufp); 185 if (i >= MINBUFS) 186 break; 187 errexit("cannot allocate buffer pool\n"); 188 } 189 bp->b_un.b_buf = bufp; 190 bp->b_prev = &bufhead; 191 bp->b_next = bufhead.b_next; 192 bufhead.b_next->b_prev = bp; 193 bufhead.b_next = bp; 194 initbarea(bp); 195 } 196 bufhead.b_size = i; /* save number of buffers */ 197 pbp = pdirbp = NULL; 198 } 199 200 /* 201 * Manage a cache of directory blocks. 202 */ 203 struct bufarea * 204 getdatablk(blkno, size) 205 daddr32_t blkno; 206 int size; 207 { 208 struct bufarea *bp; 209 210 for (bp = bufhead.b_next; bp != &bufhead; bp = bp->b_next) 211 if (bp->b_bno == fsbtodb(&sblock, blkno)) 212 goto foundit; 213 for (bp = bufhead.b_prev; bp != &bufhead; bp = bp->b_prev) 214 if ((bp->b_flags & B_INUSE) == 0) 215 break; 216 if (bp == &bufhead) { 217 bp = alloc_bufarea(); 218 if (bp == NULL) 219 errexit("deadlocked buffer pool\n"); 220 } 221 getblk(bp, blkno, size); 222 /* fall through */ 223 foundit: 224 totalreads++; 225 bp->b_cnt++; 226 /* 227 * Move the buffer to head of link-list if it isn't 228 * already there. 229 */ 230 if (bufhead.b_next != bp) { 231 bp->b_prev->b_next = bp->b_next; 232 bp->b_next->b_prev = bp->b_prev; 233 bp->b_prev = &bufhead; 234 bp->b_next = bufhead.b_next; 235 bufhead.b_next->b_prev = bp; 236 bufhead.b_next = bp; 237 } 238 bp->b_flags |= B_INUSE; 239 return (bp); 240 } 241 242 int 243 brelse(struct bufarea *bp) 244 { 245 bp->b_cnt--; 246 if (bp->b_cnt == 0) { 247 bp->b_flags &= ~B_INUSE; 248 } 249 } 250 251 struct bufarea * 252 getblk(bp, blk, size) 253 struct bufarea *bp; 254 daddr32_t blk; 255 int size; 256 { 257 diskaddr_t dblk; 258 259 dblk = fsbtodb(&sblock, blk); 260 if (bp->b_bno == dblk) 261 return (bp); 262 flush(fswritefd, bp); 263 diskreads++; 264 bp->b_errs = bread(fsreadfd, bp->b_un.b_buf, dblk, (long)size); 265 bp->b_bno = dblk; 266 bp->b_size = size; 267 return (bp); 268 } 269 270 flush(fd, bp) 271 int fd; 272 struct bufarea *bp; 273 { 274 int i, j; 275 caddr_t sip; 276 long size; 277 278 if (!bp->b_dirty) 279 return; 280 if (bp->b_errs != 0) 281 pfatal("WRITING ZERO'ED BLOCK %lld TO DISK\n", bp->b_bno); 282 bp->b_dirty = 0; 283 bp->b_errs = 0; 284 bwrite(fd, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size); 285 if (bp != &sblk) 286 return; 287 sip = (caddr_t)sblock.fs_u.fs_csp; 288 for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) { 289 size = sblock.fs_cssize - i < sblock.fs_bsize ? 290 sblock.fs_cssize - i : sblock.fs_bsize; 291 bwrite(fswritefd, sip, 292 fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag), 293 size); 294 sip += size; 295 } 296 } 297 298 rwerror(mesg, blk) 299 char *mesg; 300 diskaddr_t blk; 301 { 302 303 if (preen == 0) 304 printf("\n"); 305 pfatal("CANNOT %s: BLK %lld", mesg, blk); 306 if (reply("CONTINUE") == 0) 307 errexit("Program terminated\n"); 308 } 309 310 ckfini() 311 { 312 struct bufarea *bp, *nbp; 313 int cnt = 0; 314 315 /* 316 * Mark the filesystem bad if a re-check is required. 317 */ 318 if (dirholes && havesb) { 319 sblock.fs_clean = FSBAD; 320 sblock.fs_state = -(FSOKAY - (long)sblock.fs_time); 321 sbdirty(); 322 } 323 flush(fswritefd, &sblk); 324 if (havesb && sblk.b_bno != SBOFF / dev_bsize) { 325 sblk.b_bno = SBOFF / dev_bsize; 326 sbdirty(); 327 flush(fswritefd, &sblk); 328 } 329 flush(fswritefd, &cgblk); 330 if (cgblk.b_un.b_buf) { 331 free(cgblk.b_un.b_buf); 332 cgblk.b_un.b_buf = NULL; 333 } 334 for (bp = bufhead.b_prev; bp && bp != &bufhead; bp = nbp) { 335 cnt++; 336 flush(fswritefd, bp); 337 nbp = bp->b_prev; 338 free(bp->b_un.b_buf); 339 free((char *)bp); 340 } 341 pbp = pdirbp = NULL; 342 if (bufhead.b_size != cnt) 343 errexit("Panic: lost %d buffers\n", bufhead.b_size - cnt); 344 if (debug) 345 printf("cache missed %d of %d (%d%%)\n", 346 diskreads, totalreads, 347 totalreads ? diskreads * 100 / totalreads : 0); 348 (void) close(fsreadfd); 349 (void) close(fswritefd); 350 } 351 352 bread(fd, buf, blk, size) 353 int fd; 354 char *buf; 355 diskaddr_t blk; 356 long size; 357 { 358 char *cp; 359 int i; 360 int errs; 361 offset_t offset = ldbtob(blk); 362 offset_t addr; 363 364 if (debug && (blk < SBLOCK)) { 365 char msg[256]; 366 sprintf(msg, "WARNING: fsck bread() passed blkno < %d (%ld)\n", 367 SBLOCK, blk); 368 printf(msg); 369 } 370 if (llseek(fd, offset, 0) < 0) { 371 rwerror("SEEK", blk); 372 } else if (read(fd, buf, (int)size) == size) 373 return (0); 374 rwerror("READ", blk); 375 if (llseek(fd, offset, 0) < 0) { 376 rwerror("SEEK", blk); 377 } 378 errs = 0; 379 bzero(buf, (size_t)size); 380 pwarn("THE FOLLOWING SECTORS COULD NOT BE READ:"); 381 for (cp = buf, i = 0; i < btodb(size); i++, cp += DEV_BSIZE) { 382 addr = ldbtob(blk + i); 383 if (llseek(fd, addr, SEEK_CUR) < 0 || 384 read(fd, cp, (int)secsize) < 0) { 385 printf(" %d", blk + i); 386 errs++; 387 } 388 } 389 printf("\n"); 390 return (errs); 391 } 392 393 bwrite(fd, buf, blk, size) 394 int fd; 395 char *buf; 396 diskaddr_t blk; 397 long size; 398 { 399 int i; 400 int n; 401 char *cp; 402 offset_t offset = ldbtob(blk); 403 offset_t addr; 404 405 if (fd < 0) 406 return; 407 if (blk < SBLOCK) { 408 char msg[256]; 409 sprintf(msg, 410 "WARNING: Attempt to write illegal blkno %lld on %s\n", 411 blk, devname); 412 if (debug) 413 printf(msg); 414 return; 415 } 416 if (llseek(fd, offset, 0) < 0) { 417 rwerror("SEEK", blk); 418 } else if (write(fd, buf, (int)size) == size) { 419 fsmodified = 1; 420 return; 421 } 422 rwerror("WRITE", blk); 423 if (llseek(fd, offset, 0) < 0) { 424 rwerror("SEEK", blk); 425 } 426 pwarn("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:"); 427 for (cp = buf, i = 0; i < btodb(size); i++, cp += DEV_BSIZE) { 428 n = 0; 429 addr = ldbtob(blk + i); 430 if (llseek(fd, addr, SEEK_CUR) < 0 || 431 (n = write(fd, cp, DEV_BSIZE)) < 0) { 432 printf(" %d", blk + i); 433 } else if (n > 0) { 434 fsmodified = 1; 435 } 436 437 } 438 printf("\n"); 439 } 440 441 /* 442 * allocate a data block with the specified number of fragments 443 */ 444 daddr32_t 445 allocblk(frags) 446 int frags; 447 { 448 int i, j, k; 449 450 if (frags <= 0 || frags > sblock.fs_frag) 451 return (0); 452 for (i = 0; i < maxfsblock - sblock.fs_frag; i += sblock.fs_frag) { 453 for (j = 0; j <= sblock.fs_frag - frags; j++) { 454 if (testbmap(i + j)) 455 continue; 456 for (k = 1; k < frags; k++) 457 if (testbmap(i + j + k)) 458 break; 459 if (k < frags) { 460 j += k; 461 continue; 462 } 463 for (k = 0; k < frags; k++) 464 setbmap(i + j + k); 465 n_blks += frags; 466 return (i + j); 467 } 468 } 469 return (0); 470 } 471 472 /* 473 * Free a previously allocated block 474 */ 475 freeblk(blkno, frags) 476 daddr32_t blkno; 477 int frags; 478 { 479 struct inodesc idesc; 480 481 idesc.id_blkno = blkno; 482 idesc.id_numfrags = frags; 483 pass4check(&idesc); 484 } 485 486 /* 487 * Find a pathname 488 */ 489 getpathname(namebuf, curdir, ino) 490 char *namebuf; 491 ino_t curdir, ino; 492 { 493 int len; 494 char *cp; 495 struct inodesc idesc; 496 struct inoinfo *inp; 497 extern int findname(); 498 499 if (statemap[curdir] != DSTATE && statemap[curdir] != DFOUND) { 500 strcpy(namebuf, "?"); 501 return; 502 } 503 bzero((char *)&idesc, sizeof (struct inodesc)); 504 idesc.id_type = DATA; 505 cp = &namebuf[MAXPATHLEN - 1]; 506 *cp = '\0'; 507 if (curdir != ino) { 508 idesc.id_parent = curdir; 509 goto namelookup; 510 } 511 while (ino != UFSROOTINO) { 512 idesc.id_number = ino; 513 idesc.id_func = findino; 514 idesc.id_name = ".."; 515 idesc.id_fix = NOFIX; 516 if ((ckinode(ginode(ino), &idesc) & FOUND) == 0) { 517 inp = getinoinfo(ino); 518 if (inp->i_parent == 0) 519 break; 520 idesc.id_parent = inp->i_parent; 521 } 522 namelookup: 523 idesc.id_number = idesc.id_parent; 524 idesc.id_parent = ino; 525 idesc.id_func = findname; 526 idesc.id_name = namebuf; 527 idesc.id_fix = NOFIX; 528 if ((ckinode(ginode(idesc.id_number), &idesc)&FOUND) == 0) 529 break; 530 len = strlen(namebuf); 531 cp -= len; 532 if (cp < &namebuf[MAXNAMLEN]) 533 break; 534 bcopy(namebuf, cp, len); 535 *--cp = '/'; 536 ino = idesc.id_number; 537 } 538 if (ino != UFSROOTINO) { 539 strcpy(namebuf, "?"); 540 return; 541 } 542 bcopy(cp, namebuf, &namebuf[MAXPATHLEN] - cp); 543 } 544 545 void 546 catch() 547 { 548 ckfini(); 549 exit(37); 550 } 551 552 /* 553 * When preening, allow a single quit to signal 554 * a special exit after filesystem checks complete 555 * so that reboot sequence may be interrupted. 556 */ 557 void 558 catchquit() 559 { 560 extern returntosingle; 561 562 printf("returning to single-user after filesystem check\n"); 563 returntosingle = 1; 564 (void) signal(SIGQUIT, SIG_DFL); 565 } 566 567 /* 568 * Ignore a single quit signal; wait and flush just in case. 569 * Used by child processes in preen. 570 */ 571 void 572 voidquit() 573 { 574 575 sleep(1); 576 (void) signal(SIGQUIT, SIG_IGN); 577 (void) signal(SIGQUIT, SIG_DFL); 578 } 579 580 /* 581 * determine whether an inode should be fixed. 582 */ 583 dofix(idesc, msg) 584 struct inodesc *idesc; 585 char *msg; 586 { 587 588 switch (idesc->id_fix) { 589 590 case DONTKNOW: 591 if (idesc->id_type == DATA) 592 direrror(idesc->id_number, msg); 593 else 594 pwarn(msg); 595 if (preen) { 596 printf(" (SALVAGED)\n"); 597 idesc->id_fix = FIX; 598 return (ALTERED); 599 } 600 if (reply("SALVAGE") == 0) { 601 idesc->id_fix = NOFIX; 602 return (0); 603 } 604 idesc->id_fix = FIX; 605 return (ALTERED); 606 607 case FIX: 608 return (ALTERED); 609 610 case NOFIX: 611 return (0); 612 613 default: 614 errexit("UNKNOWN INODESC FIX MODE %d\n", idesc->id_fix); 615 } 616 /* NOTREACHED */ 617 } 618 619 /* VARARGS1 */ 620 errexit(s1, s2, s3, s4) 621 char *s1; 622 { 623 extern void write_altsb(int); 624 625 if (errorlocked) { 626 if (havesb) { 627 sblock.fs_clean = FSBAD; 628 sblock.fs_state = -(FSOKAY - (long)sblock.fs_time); 629 sbdirty(); 630 write_altsb(fswritefd); 631 flush(fswritefd, &sblk); 632 } 633 } 634 printf(s1, s2, s3, s4); 635 exit(39); 636 } 637 638 /* 639 * An unexpected inconsistency occured. 640 * Die if preening, otherwise just print message and continue. 641 */ 642 /* VARARGS1 */ 643 pfatal(s, a1, a2, a3) 644 char *s; 645 { 646 if (preen) { 647 printf("%s: ", devname); 648 printf(s, a1, a2, a3); 649 printf("\n"); 650 printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n", 651 devname); 652 if (havesb) { 653 sblock.fs_clean = FSBAD; 654 sblock.fs_state = -(FSOKAY - (long)sblock.fs_time); 655 sbdirty(); 656 flush(fswritefd, &sblk); 657 } 658 exit(36); 659 } 660 printf(s, a1, a2, a3); 661 } 662 663 /* 664 * Pwarn just prints a message when not preening, 665 * or a warning (preceded by filename) when preening. 666 */ 667 /* VARARGS1 */ 668 pwarn(s, a1, a2, a3, a4, a5, a6) 669 char *s; 670 { 671 672 if (preen) 673 printf("%s: ", devname); 674 printf(s, a1, a2, a3, a4, a5, a6); 675 } 676 677 #ifndef lint 678 /* 679 * Stub for routines from kernel. 680 */ 681 panic(s) 682 char *s; 683 { 684 685 pfatal("INTERNAL INCONSISTENCY:"); 686 errexit(s); 687 } 688 #define CE_PANIC 3 689 void 690 cmn_err(level, s) 691 int level; 692 char *s; 693 { 694 695 if (level == CE_PANIC) { 696 pfatal("INTERNAL INCONSISTENCY:"); 697 errexit(s); 698 } 699 else 700 printf(s); 701 } 702 #endif 703 704 /* 705 * Check to see if unraw version of name is already mounted. 706 * Since we do not believe /etc/mnttab, we stat the mount point 707 * to see if it is really looks mounted. 708 */ 709 mounted(name) 710 char *name; 711 { 712 int found = 0; 713 struct mnttab mnt; 714 FILE *mnttab; 715 struct stat64 device_stat, mount_stat; 716 char *blkname, *unrawname(); 717 718 mnttab = fopen(MNTTAB, "r"); 719 if (mnttab == NULL) { 720 return (0); 721 } 722 blkname = unrawname(name); 723 while ((getmntent(mnttab, &mnt)) == NULL) { 724 if (strcmp(mnt.mnt_fstype, MNTTYPE_UFS) != 0) { 725 continue; 726 } 727 if (strcmp(blkname, mnt.mnt_special) == 0) { 728 stat64(mnt.mnt_mountp, &mount_stat); 729 stat64(mnt.mnt_special, &device_stat); 730 if (device_stat.st_rdev == mount_stat.st_dev) { 731 if (hasmntopt(&mnt, MNTOPT_RO) != 0) 732 found = 2; /* mounted as RO */ 733 else 734 found = 1; /* mounted as R/W */ 735 } 736 if (mount_point == NULL) { 737 mount_point = strdup(mnt.mnt_mountp); 738 if (mount_point == NULL) { 739 printf("fsck: memory allocation" 740 " failure\n"); 741 exit(39); 742 } 743 } 744 break; 745 } 746 } 747 fclose(mnttab); 748 return (found); 749 } 750 751 /* 752 * Check to see if name corresponds to an entry in vfstab, and that the entry 753 * does not have option ro. 754 */ 755 writable(name) 756 char *name; 757 { 758 int rw = 1; 759 struct vfstab vfsbuf; 760 FILE *vfstab; 761 char *blkname, *unrawname(); 762 763 vfstab = fopen(VFSTAB, "r"); 764 if (vfstab == NULL) { 765 printf("can't open %s\n", VFSTAB); 766 return (1); 767 } 768 blkname = unrawname(name); 769 if ((getvfsspec(vfstab, &vfsbuf, blkname) == 0) && 770 (vfsbuf.vfs_fstype != NULL) && 771 (strcmp(vfsbuf.vfs_fstype, MNTTYPE_UFS) == 0) && 772 (hasvfsopt(&vfsbuf, MNTOPT_RO))) { 773 rw = 0; 774 } 775 fclose(vfstab); 776 return (rw); 777 } 778 779 /* 780 * debugclean 781 */ 782 debugclean() 783 { 784 char s[256]; 785 786 if (debug == 0) 787 return; 788 789 if ((iscorrupt == 0) && (isdirty == 0)) 790 return; 791 792 if ((sblock.fs_clean != FSSTABLE) && (sblock.fs_clean != FSCLEAN) && 793 (sblock.fs_clean != FSLOG || !islog || !islogok)) 794 return; 795 796 if (FSOKAY != (sblock.fs_state + sblock.fs_time) && !errorlocked) 797 return; 798 799 sprintf(s, 800 "WARNING: inconsistencies detected on `%s' filesystem %s", 801 sblock.fs_clean == FSSTABLE ? "stable" : 802 sblock.fs_clean == FSLOG ? "logging" : 803 sblock.fs_clean == FSFIX ? "being fixed" : "clean", devname); 804 printf("%s\n", s); 805 } 806 807 /* 808 * updateclean 809 * Carefully and transparently update the clean flag. 810 */ 811 updateclean() 812 { 813 struct bufarea cleanbuf; 814 int size; 815 daddr32_t bno; 816 int fsclean; 817 int fsreclaim; 818 int fsflags; 819 int r; 820 daddr32_t fslogbno; 821 offset_t sblkoff; 822 time_t t; 823 824 /* 825 * debug stuff 826 */ 827 debugclean(); 828 829 /* 830 * set fsclean to its appropriate value 831 */ 832 fslogbno = sblock.fs_logbno; 833 fsclean = sblock.fs_clean; 834 fsreclaim = sblock.fs_reclaim; 835 fsflags = sblock.fs_flags; 836 if (FSOKAY != (sblock.fs_state + sblock.fs_time) && !errorlocked) 837 fsclean = FSACTIVE; 838 839 /* if ufs log is not okay, clear it */ 840 if (fslogbno && !(islog && islogok)) { 841 fsclean = FSACTIVE; 842 fslogbno = 0; 843 } 844 845 /* 846 * if necessary, update fs_clean and fs_state 847 */ 848 switch (fsclean) { 849 850 case FSACTIVE: 851 if (!iscorrupt) { 852 fsclean = FSSTABLE; 853 fsreclaim = 0; 854 } 855 break; 856 857 case FSCLEAN: 858 case FSSTABLE: 859 if (iscorrupt) 860 fsclean = FSACTIVE; 861 else 862 fsreclaim = 0; 863 break; 864 865 case FSLOG: 866 if (iscorrupt) 867 fsclean = FSACTIVE; 868 else if (!islog) { 869 fsreclaim = 0; 870 fsclean = FSSTABLE; 871 } else if (fflag) 872 fsreclaim = 0; 873 break; 874 875 case FSFIX: 876 fsreclaim = needs_reclaim; 877 fsclean = FSBAD; 878 if (errorlocked && !iscorrupt) { 879 fsclean = islog? FSLOG: FSCLEAN; 880 } 881 break; 882 883 default: 884 if (iscorrupt) 885 fsclean = FSACTIVE; 886 else { 887 fsclean = FSSTABLE; 888 fsreclaim = 0; 889 } 890 } 891 892 if (largefile_count > 0) 893 fsflags |= FSLARGEFILES; 894 else 895 fsflags &= ~FSLARGEFILES; 896 897 /* 898 * fs is unchanged, do nothing 899 */ 900 if (debug) 901 printf("** largefile count=%d, fs.fs_flags=%x\n", 902 largefile_count, sblock.fs_flags); 903 904 if ((!isdirty) && (fsflags == sblock.fs_flags) && 905 (fslogbno == sblock.fs_logbno) && 906 (sblock.fs_clean == fsclean) && (sblock.fs_reclaim == fsreclaim) && 907 (FSOKAY == (sblock.fs_state + sblock.fs_time))) { 908 if (islog && !islogok) 909 (void) ioctl(fswritefd, _FIOLOGRESET, NULL); 910 911 if (errorlocked) { 912 if (!do_errorlock(LOCKFS_ULOCK)) 913 pwarn( 914 "updateclean(unchanged): unlock(LOCKFS_ULOCK) failed\n"); 915 } 916 return; 917 } 918 919 /* 920 * if user allows, update superblock state 921 */ 922 if (!isdirty && !preen && 923 (reply("FILE SYSTEM STATE IN SUPERBLOCK IS WRONG; FIX") == 0)) 924 return; 925 926 (void) time(&t); 927 sblock.fs_time = (time32_t)t; 928 if (debug) 929 printclean(); 930 sblock.fs_logbno = fslogbno; 931 sblock.fs_clean = fsclean; 932 sblock.fs_state = FSOKAY - (long)sblock.fs_time; 933 sblock.fs_reclaim = fsreclaim; 934 sblock.fs_flags = fsflags; 935 936 /* 937 * if superblock can't be written, return 938 */ 939 if (fswritefd < 0) 940 return; 941 942 /* 943 * read private copy of superblock, update clean flag, and write it 944 */ 945 bno = sblk.b_bno; 946 size = sblk.b_size; 947 948 sblkoff = ldbtob(bno); 949 950 if ((cleanbuf.b_un.b_buf = malloc(size)) == NULL) 951 errexit("out of memory"); 952 953 if (llseek(fsreadfd, sblkoff, 0) == -1) 954 return; 955 if (read(fsreadfd, cleanbuf.b_un.b_buf, (int)size) != size) 956 return; 957 958 cleanbuf.b_un.b_fs->fs_logbno = sblock.fs_logbno; 959 cleanbuf.b_un.b_fs->fs_clean = sblock.fs_clean; 960 cleanbuf.b_un.b_fs->fs_state = sblock.fs_state; 961 cleanbuf.b_un.b_fs->fs_time = sblock.fs_time; 962 cleanbuf.b_un.b_fs->fs_reclaim = sblock.fs_reclaim; 963 cleanbuf.b_un.b_fs->fs_flags = sblock.fs_flags; 964 965 if (llseek(fswritefd, sblkoff, 0) == -1) 966 return; 967 if (write(fswritefd, cleanbuf.b_un.b_buf, (int)size) != size) 968 return; 969 970 /* 971 * 1208040 972 * If we had to use -b to grab an alternate superblock, then we 973 * likely had to do so because of unacceptable differences between 974 * the main and alternate superblocks. SO, we had better update 975 * the alternate superblock as well, or we'll just fail again 976 * the next time we attempt to run fsck! 977 */ 978 if (bflag) { 979 extern struct bufarea asblk; 980 981 if (llseek(fswritefd, ldbtob(asblk.b_bno), 0) == -1) 982 return; 983 if (write(fswritefd, cleanbuf.b_un.b_buf, (int)size) != size) 984 return; 985 } 986 987 if (islog && !islogok) 988 (void) ioctl(fswritefd, _FIOLOGRESET, NULL); 989 990 if (errorlocked) { 991 if (!do_errorlock(LOCKFS_ULOCK)) 992 pwarn( 993 "updateclean(changed): unlock(LOCKFS_ULOCK) failed\n"); 994 } 995 } 996 997 /* 998 * print out clean info 999 */ 1000 printclean() 1001 { 1002 char *s; 1003 1004 if (FSOKAY != (sblock.fs_state + sblock.fs_time) && !errorlocked) 1005 s = "unknown"; 1006 else 1007 switch (sblock.fs_clean) { 1008 1009 case FSACTIVE: 1010 s = "active"; 1011 break; 1012 1013 case FSCLEAN: 1014 s = "clean"; 1015 break; 1016 1017 case FSSTABLE: 1018 s = "stable"; 1019 break; 1020 1021 case FSLOG: 1022 s = "logging"; 1023 break; 1024 1025 case FSBAD: 1026 s = "is bad"; 1027 break; 1028 1029 case FSFIX: 1030 s = "being fixed"; 1031 break; 1032 1033 default: 1034 s = "unknown"; 1035 } 1036 1037 if (preen) 1038 pwarn("is %s.\n", s); 1039 else 1040 printf("** %s is %s.\n", devname, s); 1041 } 1042 1043 /* see if all numbers */ 1044 numbers(yp) 1045 char *yp; 1046 { 1047 if (yp == NULL) 1048 return (0); 1049 while ('0' <= *yp && *yp <= '9') 1050 yp++; 1051 if (*yp) 1052 return (0); 1053 return (1); 1054 } 1055 1056 is_errorlocked(char *fs) 1057 { 1058 struct stat64 statb; 1059 char *mountp; 1060 static char *getmountp(char *); 1061 char *unrawname(char *); 1062 1063 mountp = NULL; 1064 1065 if (!fs) 1066 return (0); 1067 1068 if (stat64(fs, &statb) < 0) 1069 return (0); 1070 1071 if (S_ISDIR(statb.st_mode)) { 1072 mountp = fs; 1073 1074 } else if (S_ISBLK(statb.st_mode) || S_ISCHR(statb.st_mode)) { 1075 mountp = getmountp(S_ISCHR(statb.st_mode)? unrawname(fs): fs); 1076 if (!mountp) { 1077 return (0); 1078 } 1079 } else { 1080 return (0); 1081 } 1082 1083 if (elock_combuf == NULL) { 1084 elock_combuf = 1085 (char *)calloc(LOCKFS_MAXCOMMENTLEN, sizeof (char)); 1086 } else { 1087 elock_combuf = 1088 (char *)realloc(elock_combuf, LOCKFS_MAXCOMMENTLEN); 1089 } 1090 1091 if (elock_combuf == NULL) 1092 return (0); 1093 1094 bzero((caddr_t)elock_combuf, LOCKFS_MAXCOMMENTLEN); 1095 1096 elock_mountp = strdup(mountp); 1097 1098 if (mountfd < 0) { 1099 if ((mountfd = open64(mountp, O_RDONLY)) == -1) 1100 return (0); 1101 } 1102 1103 if (!lfp) { 1104 lfp = (struct lockfs *)malloc(sizeof (struct lockfs)); 1105 if (!lfp) 1106 return (0); 1107 bzero((caddr_t)lfp, sizeof (struct lockfs)); 1108 } 1109 1110 lfp->lf_comlen = LOCKFS_MAXCOMMENTLEN; 1111 lfp->lf_comment = elock_combuf; 1112 1113 if (ioctl(mountfd, _FIOLFSS, lfp) == -1) 1114 return (0); 1115 1116 return (LOCKFS_IS_ELOCK(lfp)); 1117 } 1118 1119 static char * 1120 getmountp(char *dev) { 1121 FILE *vfstab; 1122 struct vfstab vfsbuf; 1123 char *mountp; 1124 int rc; 1125 1126 mountp = NULL; 1127 if ((vfstab = fopen(VFSTAB, "r")) == NULL) { 1128 return (NULL); 1129 } 1130 if ((rc = getvfsspec(vfstab, &vfsbuf, dev)) == 0) { 1131 if (!(mountp = malloc(MAXPATHLEN)) || 1132 vfsbuf.vfs_mountp == NULL) 1133 return (NULL); 1134 strcpy(mountp, vfsbuf.vfs_mountp); 1135 } else if (rc == -1) { 1136 return (NULL); 1137 } 1138 fclose(vfstab); 1139 return (mountp); 1140 } 1141 1142 do_errorlock(int lock_type) 1143 { 1144 char *buf; 1145 time_t now; 1146 struct tm *local; 1147 int rc = 0; 1148 1149 if (!elock_combuf) 1150 errexit("do_errorlock(%s, %d): unallocated elock_combuf\n", 1151 elock_mountp? elock_mountp: "<null>", lock_type); 1152 1153 if (!(buf = (char *)calloc(LOCKFS_MAXCOMMENTLEN, sizeof (char)))) 1154 errexit("Couldn't alloc memory for temp. lock status buffer\n"); 1155 1156 if (!lfp) { 1157 errexit("do_errorlock(%s, %d): lockfs status unallocated\n", 1158 elock_mountp, lock_type); 1159 } 1160 1161 bcopy(elock_combuf, buf, LOCKFS_MAXCOMMENTLEN-1); 1162 1163 switch (lock_type) { 1164 case LOCKFS_ELOCK: 1165 if (time(&now) != (time_t)-1) { 1166 if ((local = localtime(&now)) != NULL) 1167 sprintf(buf, 1168 "%s [pid:%d fsck start:%02d/%02d/%02d %02d:%02d:%02d", 1169 elock_combuf, pid, 1170 local->tm_mon+1, local->tm_mday, 1171 (local->tm_year % 100), local->tm_hour, 1172 local->tm_min, local->tm_sec); 1173 else 1174 sprintf(buf, "%s [fsck pid %d", 1175 elock_combuf, pid); 1176 1177 } else { 1178 sprintf(buf, "%s [fsck pid %d", elock_combuf, pid); 1179 } 1180 break; 1181 1182 case LOCKFS_ULOCK: 1183 if (time(&now) != (time_t)-1) { 1184 if ((local = localtime(&now)) != NULL) { 1185 sprintf(buf, 1186 "%s, done:%02d/%02d/%02d %02d:%02d:%02d]", 1187 elock_combuf, 1188 local->tm_mon+1, local->tm_mday, 1189 (local->tm_year % 100), local->tm_hour, 1190 local->tm_min, local->tm_sec); 1191 } else { 1192 sprintf(buf, "%s]", elock_combuf); 1193 } 1194 } else { 1195 sprintf(buf, "%s]", elock_combuf); 1196 } 1197 if ((rc = ioctl(mountfd, _FIOLFSS, lfp)) == -1) { 1198 goto out; 1199 } 1200 break; 1201 1202 default: 1203 break; 1204 } 1205 1206 bcopy(buf, elock_combuf, LOCKFS_MAXCOMMENTLEN-1); 1207 1208 lfp->lf_lock = lock_type; 1209 lfp->lf_comlen = LOCKFS_MAXCOMMENTLEN; 1210 lfp->lf_comment = elock_combuf; 1211 lfp->lf_flags = 0; 1212 errno = 0; 1213 1214 if ((rc = ioctl(mountfd, _FIOLFS, lfp)) == -1) { 1215 if (errno == EINVAL) { 1216 pwarn("Another fsck active?\n"); 1217 iscorrupt = 0; /* don't go away mad, just go away */ 1218 } else { 1219 pwarn( 1220 "do_errorlock(lock_type:%d, %s) failed: errno:%d\n", 1221 lock_type, elock_combuf, errno); 1222 } 1223 } 1224 out: 1225 if (buf) 1226 free(buf); 1227 1228 return (rc != -1); 1229 } 1230 1231 /* 1232 * Shadow inode support. To `register' a shadow with a client is to note 1233 * that an inode (the `client') refers to the shadow. See fsck.h for more 1234 * on how the shadowclientinfo and shadowclients structures are used. 1235 */ 1236 1237 static struct shadowclients * 1238 newshadowclient(struct shadowclients *prev) 1239 { 1240 struct shadowclients *rc; 1241 1242 rc = (struct shadowclients *)malloc(sizeof (*rc)); 1243 if (rc == NULL) 1244 errexit("newshadowclient: cannot malloc (1)"); 1245 1246 rc->next = prev; 1247 rc->nclients = 0; 1248 1249 rc->client = (ino_t *) 1250 malloc(sizeof (ino_t) * maxshadowclients); 1251 if (rc->client == NULL) 1252 errexit("newshadowclient: cannot malloc (2)"); 1253 1254 return (rc); 1255 } 1256 1257 void 1258 registershadowclient(ino_t shadow, ino_t client, struct shadowclientinfo **info) 1259 { 1260 struct shadowclientinfo *sci; 1261 struct shadowclients *scc; 1262 1263 for (sci = *info; sci; sci = sci->next) 1264 if (sci->shadow == shadow) 1265 break; 1266 if (sci == NULL) { 1267 sci = (struct shadowclientinfo *)malloc(sizeof (*sci)); 1268 if (sci == NULL) 1269 errexit("registershadowclient: cannot malloc"); 1270 sci->next = *info; 1271 *info = sci; 1272 sci->shadow = shadow; 1273 sci->totalClients = 0; 1274 sci->clients = newshadowclient(NULL); 1275 } 1276 1277 sci->totalClients++; 1278 scc = sci->clients; 1279 if (scc->nclients >= maxshadowclients) { 1280 scc = newshadowclient(sci->clients); 1281 sci->clients = scc; 1282 } 1283 1284 scc->client[scc->nclients++] = client; 1285 } 1286 1287 /* 1288 * Allocate more buffer as need arises but allocate one at a time. 1289 * This is done to make sure that fsck does not exit with error if it 1290 * needs more buffer to complete it's task. 1291 */ 1292 static struct bufarea * 1293 alloc_bufarea() 1294 { 1295 struct bufarea *bp; 1296 char *bufp; 1297 1298 bp = (struct bufarea *)malloc(sizeof (struct bufarea)); 1299 bufp = malloc((unsigned int)sblock.fs_bsize); 1300 if (bp == NULL || bufp == NULL) { 1301 if (bp) 1302 free((char *)bp); 1303 if (bufp) 1304 free(bufp); 1305 return (NULL); 1306 } 1307 bp->b_un.b_buf = bufp; 1308 bp->b_prev = &bufhead; 1309 bp->b_next = bufhead.b_next; 1310 bufhead.b_next->b_prev = bp; 1311 bufhead.b_next = bp; 1312 initbarea(bp); 1313 bufhead.b_size++; 1314 return (bp); 1315 } 1316