1 /* 2 * Copyright 2005 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 <fcntl.h> 32 #include <errno.h> 33 #include <unistd.h> 34 #include <stdlib.h> 35 #include <stdarg.h> 36 #include <fcntl.h> 37 #include <string.h> 38 #include <strings.h> 39 #include <ctype.h> 40 #include <malloc.h> 41 #include <signal.h> 42 #include <sys/param.h> 43 #include <sys/types.h> 44 #include <sys/mntent.h> 45 #include <sys/filio.h> 46 #include <sys/vnode.h> 47 #include <sys/mnttab.h> 48 #include <sys/types.h> 49 #include <sys/stat.h> 50 #include <sys/vfstab.h> 51 #include <sys/sysmacros.h> 52 #include <sys/fs/udf_volume.h> 53 #include "fsck.h" 54 #include <sys/lockfs.h> 55 #include <locale.h> 56 57 extern int32_t verifytag(struct tag *, uint32_t, struct tag *, int); 58 extern char *tagerrs[]; 59 extern void maketag(struct tag *, struct tag *); 60 extern char *hasvfsopt(struct vfstab *, char *); 61 static struct bufarea *getdatablk(daddr_t, long); 62 static struct bufarea *getblk(struct bufarea *, daddr_t, long); 63 64 void flush(int32_t, struct bufarea *); 65 int32_t bread(int32_t, char *, daddr_t, long); 66 void bwrite(int, char *, daddr_t, long); 67 static int32_t getline(FILE *, char *, int32_t); 68 void errexit(char *, ...) __NORETURN; 69 static long diskreads, totalreads; /* Disk cache statistics */ 70 offset_t llseek(); 71 extern unsigned int largefile_count; 72 73 /* 74 * An unexpected inconsistency occured. 75 * Die if preening, otherwise just print message and continue. 76 */ 77 /* VARARGS1 */ 78 void 79 pfatal(char *fmt, ...) 80 { 81 va_list args; 82 va_start(args, fmt); 83 if (preen) { 84 (void) printf("%s: ", devname); 85 (void) vprintf(fmt, args); 86 (void) printf("\n"); 87 (void) printf( 88 gettext("%s: UNEXPECTED INCONSISTENCY; RUN fsck " 89 "MANUALLY.\n"), devname); 90 va_end(args); 91 exit(36); 92 } 93 (void) vprintf(fmt, args); 94 va_end(args); 95 } 96 97 /* 98 * Pwarn just prints a message when not preening, 99 * or a warning (preceded by filename) when preening. 100 */ 101 /* VARARGS1 */ 102 void 103 pwarn(char *fmt, ...) 104 { 105 va_list args; 106 va_start(args, fmt); 107 if (preen) 108 (void) printf("%s: ", devname); 109 (void) vprintf(fmt, args); 110 va_end(args); 111 } 112 113 114 /* VARARGS1 */ 115 void 116 errexit(char *fmt, ...) 117 { 118 va_list args; 119 va_start(args, fmt); 120 (void) vprintf(fmt, args); 121 va_end(args); 122 exit(39); 123 } 124 125 void 126 markbusy(daddr_t block, long count) 127 { 128 register int i; 129 130 count = roundup(count, secsize) / secsize; 131 for (i = 0; i < count; i++, block++) { 132 if ((unsigned)block > part_len) { 133 pwarn(gettext("Block %lx out of range\n"), block); 134 break; 135 } 136 if (testbusy(block)) 137 pwarn(gettext("Dup block %lx\n"), block); 138 else { 139 n_blks++; 140 setbusy(block); 141 } 142 } 143 } 144 145 void 146 printfree() 147 { 148 int i, startfree, endfree; 149 150 startfree = -1; 151 for (i = 0; i < part_len; i++) { 152 if (!testbusy(i)) { 153 if (startfree <= 0) 154 startfree = i; 155 endfree = i; 156 } else if (startfree >= 0) { 157 (void) printf("free: %x-%x\n", startfree, endfree - 1); 158 startfree = -1; 159 } 160 } 161 if (startfree >= 0) { 162 (void) printf("free: %x-%x\n", startfree, endfree); 163 } 164 } 165 166 struct bufarea * 167 getfilentry(uint32_t block, int len) 168 { 169 struct bufarea *bp; 170 struct file_entry *fp; 171 int err; 172 173 if (len > fsbsize) { 174 (void) printf(gettext("File entry at %x is too long " 175 "(%d bytes)\n"), block, len); 176 len = fsbsize; 177 } 178 bp = getdatablk((daddr_t)(block + part_start), fsbsize); 179 if (bp->b_errs) { 180 bp->b_flags &= ~B_INUSE; 181 return (NULL); 182 } 183 /* LINTED */ 184 fp = (struct file_entry *)bp->b_un.b_buf; 185 err = verifytag(&fp->fe_tag, block, &fp->fe_tag, UD_FILE_ENTRY); 186 if (err) { 187 (void) printf(gettext("Tag error %s or bad file entry, " 188 "tag=%d\n"), tagerrs[err], fp->fe_tag.tag_id); 189 bp->b_flags &= ~B_INUSE; 190 return (NULL); 191 } 192 return (bp); 193 } 194 195 void 196 putfilentry(struct bufarea *bp) 197 { 198 struct file_entry *fp; 199 200 /* LINTED */ 201 fp = (struct file_entry *)bp->b_un.b_buf; 202 maketag(&fp->fe_tag, &fp->fe_tag); 203 } 204 205 206 int32_t 207 reply(char *question) 208 { 209 char line[80]; 210 211 if (preen) 212 pfatal(gettext("INTERNAL ERROR: GOT TO reply()")); 213 (void) printf("\n%s? ", question); 214 if (nflag || fswritefd < 0) { 215 (void) printf(gettext(" no\n\n")); 216 iscorrupt = 1; /* known to be corrupt */ 217 return (0); 218 } 219 if (yflag) { 220 (void) printf(gettext(" yes\n\n")); 221 return (1); 222 } 223 if (getline(stdin, line, sizeof (line)) == EOF) 224 errexit("\n"); 225 (void) printf("\n"); 226 if (line[0] == 'y' || line[0] == 'Y') 227 return (1); 228 else { 229 iscorrupt = 1; /* known to be corrupt */ 230 return (0); 231 } 232 } 233 234 int32_t 235 getline(FILE *fp, char *loc, int32_t maxlen) 236 { 237 int n; 238 register char *p, *lastloc; 239 240 p = loc; 241 lastloc = &p[maxlen-1]; 242 while ((n = getc(fp)) != '\n') { 243 if (n == EOF) 244 return (EOF); 245 if (!isspace(n) && p < lastloc) 246 *p++ = n; 247 } 248 *p = 0; 249 return (p - loc); 250 } 251 /* 252 * Malloc buffers and set up cache. 253 */ 254 void 255 bufinit() 256 { 257 register struct bufarea *bp; 258 long bufcnt, i; 259 char *bufp; 260 261 bufp = malloc((unsigned int)fsbsize); 262 if (bufp == 0) 263 errexit(gettext("cannot allocate buffer pool\n")); 264 bufhead.b_next = bufhead.b_prev = &bufhead; 265 bufcnt = MAXBUFSPACE / fsbsize; 266 if (bufcnt < MINBUFS) 267 bufcnt = MINBUFS; 268 for (i = 0; i < bufcnt; i++) { 269 bp = (struct bufarea *)malloc(sizeof (struct bufarea)); 270 bufp = malloc((unsigned int)fsbsize); 271 if (bp == NULL || bufp == NULL) { 272 if (i >= MINBUFS) 273 break; 274 errexit(gettext("cannot allocate buffer pool\n")); 275 } 276 bp->b_un.b_buf = bufp; 277 bp->b_prev = &bufhead; 278 bp->b_next = bufhead.b_next; 279 bufhead.b_next->b_prev = bp; 280 bufhead.b_next = bp; 281 initbarea(bp); 282 } 283 bufhead.b_size = i; /* save number of buffers */ 284 pbp = pdirbp = NULL; 285 } 286 287 /* 288 * Manage a cache of directory blocks. 289 */ 290 static struct bufarea * 291 getdatablk(daddr_t blkno, long size) 292 { 293 register struct bufarea *bp; 294 295 for (bp = bufhead.b_next; bp != &bufhead; bp = bp->b_next) 296 if (bp->b_bno == fsbtodb(blkno)) 297 goto foundit; 298 for (bp = bufhead.b_prev; bp != &bufhead; bp = bp->b_prev) 299 if ((bp->b_flags & B_INUSE) == 0) 300 break; 301 if (bp == &bufhead) 302 errexit(gettext("deadlocked buffer pool\n")); 303 (void) getblk(bp, blkno, size); 304 /* fall through */ 305 foundit: 306 totalreads++; 307 bp->b_prev->b_next = bp->b_next; 308 bp->b_next->b_prev = bp->b_prev; 309 bp->b_prev = &bufhead; 310 bp->b_next = bufhead.b_next; 311 bufhead.b_next->b_prev = bp; 312 bufhead.b_next = bp; 313 bp->b_flags |= B_INUSE; 314 return (bp); 315 } 316 317 static struct bufarea * 318 getblk(struct bufarea *bp, daddr_t blk, long size) 319 { 320 daddr_t dblk; 321 322 dblk = fsbtodb(blk); 323 if (bp->b_bno == dblk) 324 return (bp); 325 flush(fswritefd, bp); 326 diskreads++; 327 bp->b_errs = bread(fsreadfd, bp->b_un.b_buf, dblk, size); 328 bp->b_bno = dblk; 329 bp->b_size = size; 330 return (bp); 331 } 332 333 void 334 flush(int32_t fd, struct bufarea *bp) 335 { 336 if (!bp->b_dirty) 337 return; 338 if (bp->b_errs != 0) 339 pfatal(gettext("WRITING ZERO'ED BLOCK %d TO DISK\n"), 340 bp->b_bno); 341 bp->b_dirty = 0; 342 bp->b_errs = 0; 343 bwrite(fd, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size); 344 } 345 346 static void 347 rwerror(char *mesg, daddr_t blk) 348 { 349 350 if (preen == 0) 351 (void) printf("\n"); 352 pfatal(gettext("CANNOT %s: BLK %ld"), mesg, blk); 353 if (reply(gettext("CONTINUE")) == 0) 354 errexit(gettext("Program terminated\n")); 355 } 356 357 void 358 ckfini() 359 { 360 struct bufarea *bp, *nbp; 361 int cnt = 0; 362 363 for (bp = bufhead.b_prev; bp && bp != &bufhead; bp = nbp) { 364 cnt++; 365 flush(fswritefd, bp); 366 nbp = bp->b_prev; 367 free(bp->b_un.b_buf); 368 free((char *)bp); 369 } 370 pbp = pdirbp = NULL; 371 if (bufhead.b_size != cnt) 372 errexit(gettext("Panic: lost %d buffers\n"), 373 bufhead.b_size - cnt); 374 if (debug) 375 (void) printf("cache missed %ld of %ld (%ld%%)\n", 376 diskreads, totalreads, 377 totalreads ? diskreads * 100 / totalreads : 0); 378 (void) close(fsreadfd); 379 (void) close(fswritefd); 380 } 381 382 int32_t 383 bread(int fd, char *buf, daddr_t blk, long size) 384 { 385 char *cp; 386 int i, errs; 387 offset_t offset = ldbtob(blk); 388 offset_t addr; 389 390 if (llseek(fd, offset, 0) < 0) 391 rwerror(gettext("SEEK"), blk); 392 else if (read(fd, buf, (int)size) == size) 393 return (0); 394 rwerror(gettext("READ"), blk); 395 if (llseek(fd, offset, 0) < 0) 396 rwerror(gettext("SEEK"), blk); 397 errs = 0; 398 bzero(buf, (int)size); 399 pwarn(gettext("THE FOLLOWING SECTORS COULD NOT BE READ:")); 400 for (cp = buf, i = 0; i < btodb(size); i++, cp += DEV_BSIZE) { 401 addr = ldbtob(blk + i); 402 if (llseek(fd, addr, SEEK_CUR) < 0 || 403 read(fd, cp, (int)secsize) < 0) { 404 (void) printf(" %ld", blk + i); 405 errs++; 406 } 407 } 408 (void) printf("\n"); 409 return (errs); 410 } 411 412 void 413 bwrite(int fd, char *buf, daddr_t blk, long size) 414 { 415 int i, n; 416 char *cp; 417 offset_t offset = ldbtob(blk); 418 offset_t addr; 419 420 if (fd < 0) 421 return; 422 if (llseek(fd, offset, 0) < 0) 423 rwerror(gettext("SEEK"), blk); 424 else if (write(fd, buf, (int)size) == size) { 425 fsmodified = 1; 426 return; 427 } 428 rwerror(gettext("WRITE"), blk); 429 if (llseek(fd, offset, 0) < 0) 430 rwerror(gettext("SEEK"), blk); 431 pwarn(gettext("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:")); 432 for (cp = buf, i = 0; i < btodb(size); i++, cp += DEV_BSIZE) { 433 n = 0; 434 addr = ldbtob(blk + i); 435 if (llseek(fd, addr, SEEK_CUR) < 0 || 436 (n = write(fd, cp, DEV_BSIZE)) < 0) { 437 (void) printf(" %ld", blk + i); 438 } else if (n > 0) { 439 fsmodified = 1; 440 } 441 442 } 443 (void) printf("\n"); 444 } 445 446 void 447 catch() 448 { 449 ckfini(); 450 exit(37); 451 } 452 453 /* 454 * When preening, allow a single quit to signal 455 * a special exit after filesystem checks complete 456 * so that reboot sequence may be interrupted. 457 */ 458 void 459 catchquit() 460 { 461 extern int returntosingle; 462 463 (void) printf(gettext("returning to single-user after filesystem " 464 "check\n")); 465 returntosingle = 1; 466 (void) signal(SIGQUIT, SIG_DFL); 467 } 468 469 /* 470 * determine whether an inode should be fixed. 471 */ 472 /* ARGSUSED1 */ 473 int32_t 474 dofix(struct inodesc *idesc, char *msg) 475 { 476 477 switch (idesc->id_fix) { 478 479 case DONTKNOW: 480 pwarn(msg); 481 if (preen) { 482 (void) printf(gettext(" (SALVAGED)\n")); 483 idesc->id_fix = FIX; 484 return (ALTERED); 485 } 486 if (reply(gettext("SALVAGE")) == 0) { 487 idesc->id_fix = NOFIX; 488 return (0); 489 } 490 idesc->id_fix = FIX; 491 return (ALTERED); 492 493 case FIX: 494 return (ALTERED); 495 496 case NOFIX: 497 return (0); 498 499 default: 500 errexit(gettext("UNKNOWN INODESC FIX MODE %d\n"), 501 idesc->id_fix); 502 } 503 /* NOTREACHED */ 504 } 505 506 /* 507 * Check to see if unraw version of name is already mounted. 508 * Since we do not believe /etc/mnttab, we stat the mount point 509 * to see if it is really looks mounted. 510 */ 511 int 512 mounted(char *name) 513 { 514 int found = 0; 515 struct mnttab mnt; 516 FILE *mnttab; 517 struct stat device_stat, mount_stat; 518 char *blkname, *unrawname(); 519 int err; 520 521 mnttab = fopen(MNTTAB, "r"); 522 if (mnttab == NULL) { 523 (void) printf(gettext("can't open %s\n"), MNTTAB); 524 return (0); 525 } 526 blkname = unrawname(name); 527 while ((getmntent(mnttab, &mnt)) == NULL) { 528 if (strcmp(mnt.mnt_fstype, MNTTYPE_UDFS) != 0) { 529 continue; 530 } 531 if (strcmp(blkname, mnt.mnt_special) == 0) { 532 err = stat(mnt.mnt_mountp, &mount_stat); 533 err |= stat(mnt.mnt_special, &device_stat); 534 if (err < 0) 535 continue; 536 if (device_stat.st_rdev == mount_stat.st_dev) { 537 (void) strncpy(mnt.mnt_mountp, mountpoint, 538 sizeof (mountpoint)); 539 if (hasmntopt(&mnt, MNTOPT_RO) != 0) 540 found = 2; /* mounted as RO */ 541 else 542 found = 1; /* mounted as R/W */ 543 } 544 break; 545 } 546 } 547 (void) fclose(mnttab); 548 return (found); 549 } 550 551 /* 552 * Check to see if name corresponds to an entry in vfstab, and that the entry 553 * does not have option ro. 554 */ 555 int 556 writable(char *name) 557 { 558 int rw = 1; 559 struct vfstab vfsbuf; 560 FILE *vfstab; 561 char *blkname, *unrawname(); 562 563 vfstab = fopen(VFSTAB, "r"); 564 if (vfstab == NULL) { 565 (void) printf(gettext("can't open %s\n"), VFSTAB); 566 return (1); 567 } 568 blkname = unrawname(name); 569 if ((getvfsspec(vfstab, &vfsbuf, blkname) == 0) && 570 (vfsbuf.vfs_fstype != NULL) && 571 (strcmp(vfsbuf.vfs_fstype, MNTTYPE_UDFS) == 0) && 572 (hasvfsopt(&vfsbuf, MNTOPT_RO))) { 573 rw = 0; 574 } 575 (void) fclose(vfstab); 576 return (rw); 577 } 578 579 /* 580 * print out clean info 581 */ 582 void 583 printclean() 584 { 585 char *s; 586 587 switch (lvintp->lvid_int_type) { 588 589 case LVI_CLOSE: 590 s = gettext("clean"); 591 break; 592 593 case LVI_OPEN: 594 s = gettext("active"); 595 break; 596 597 default: 598 s = gettext("unknown"); 599 } 600 601 if (preen) 602 pwarn(gettext("is %s.\n"), s); 603 else 604 (void) printf("** %s is %s.\n", devname, s); 605 } 606