1 /* 2 * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. 3 */ 4 5 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 6 /* All Rights Reserved */ 7 8 /* 9 * Copyright (c) 1980, 1986, 1990 The Regents of the University of California. 10 * All rights reserved. 11 * 12 * Redistribution and use in source and binary forms are permitted 13 * provided that: (1) source distributions retain this entire copyright 14 * notice and comment, and (2) distributions including binaries display 15 * the following acknowledgement: ``This product includes software 16 * developed by the University of California, Berkeley and its contributors'' 17 * in the documentation or other materials provided with the distribution 18 * and in all advertising materials mentioning features or use of this 19 * software. Neither the name of the University nor the names of its 20 * contributors may be used to endorse or promote products derived 21 * from this software without specific prior written permission. 22 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 24 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 25 */ 26 27 #include <stdio.h> 28 #include <fcntl.h> 29 #include <errno.h> 30 #include <unistd.h> 31 #include <stdlib.h> 32 #include <stdarg.h> 33 #include <fcntl.h> 34 #include <string.h> 35 #include <strings.h> 36 #include <ctype.h> 37 #include <malloc.h> 38 #include <signal.h> 39 #include <sys/param.h> 40 #include <sys/types.h> 41 #include <sys/mntent.h> 42 #include <sys/filio.h> 43 #include <sys/vnode.h> 44 #include <sys/mnttab.h> 45 #include <sys/types.h> 46 #include <sys/stat.h> 47 #include <sys/vfstab.h> 48 #include <sys/sysmacros.h> 49 #include <sys/fs/udf_volume.h> 50 #include "fsck.h" 51 #include <sys/lockfs.h> 52 #include <locale.h> 53 54 static struct bufarea bufhead; 55 56 extern int32_t verifytag(struct tag *, uint32_t, struct tag *, int); 57 extern char *tagerrs[]; 58 extern void maketag(struct tag *, struct tag *); 59 extern char *hasvfsopt(struct vfstab *, char *); 60 static struct bufarea *getdatablk(daddr_t, long); 61 static struct bufarea *getblk(struct bufarea *, daddr_t, long); 62 63 void flush(int32_t, struct bufarea *); 64 int32_t bread(int32_t, char *, daddr_t, long); 65 void bwrite(int, char *, daddr_t, long); 66 static int32_t getaline(FILE *, char *, int32_t); 67 void errexit(char *, ...) __NORETURN; 68 static long diskreads, totalreads; /* Disk cache statistics */ 69 offset_t llseek(); 70 extern unsigned int largefile_count; 71 72 /* 73 * An unexpected inconsistency occured. 74 * Die if preening, otherwise just print message and continue. 75 */ 76 /* VARARGS1 */ 77 void 78 pfatal(char *fmt, ...) 79 { 80 va_list args; 81 va_start(args, fmt); 82 if (preen) { 83 (void) printf("%s: ", devname); 84 (void) vprintf(fmt, args); 85 (void) printf("\n"); 86 (void) printf( 87 gettext("%s: UNEXPECTED INCONSISTENCY; RUN fsck " 88 "MANUALLY.\n"), devname); 89 va_end(args); 90 exit(36); 91 } 92 (void) vprintf(fmt, args); 93 va_end(args); 94 } 95 96 /* 97 * Pwarn just prints a message when not preening, 98 * or a warning (preceded by filename) when preening. 99 */ 100 /* VARARGS1 */ 101 void 102 pwarn(char *fmt, ...) 103 { 104 va_list args; 105 va_start(args, fmt); 106 if (preen) 107 (void) printf("%s: ", devname); 108 (void) vprintf(fmt, args); 109 va_end(args); 110 } 111 112 113 /* VARARGS1 */ 114 void 115 errexit(char *fmt, ...) 116 { 117 va_list args; 118 va_start(args, fmt); 119 (void) vprintf(fmt, args); 120 va_end(args); 121 exit(39); 122 } 123 124 void 125 markbusy(daddr_t block, long count) 126 { 127 register int i; 128 129 count = roundup(count, secsize) / secsize; 130 for (i = 0; i < count; i++, block++) { 131 if ((unsigned)block > part_len) { 132 pwarn(gettext("Block %lx out of range\n"), block); 133 break; 134 } 135 if (testbusy(block)) 136 pwarn(gettext("Dup block %lx\n"), block); 137 else { 138 n_blks++; 139 setbusy(block); 140 } 141 } 142 } 143 144 void 145 printfree() 146 { 147 int i, startfree, endfree; 148 149 startfree = -1; 150 endfree = -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 (getaline(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 getaline(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 } 285 286 /* 287 * Manage a cache of directory blocks. 288 */ 289 static struct bufarea * 290 getdatablk(daddr_t blkno, long size) 291 { 292 register struct bufarea *bp; 293 294 for (bp = bufhead.b_next; bp != &bufhead; bp = bp->b_next) 295 if (bp->b_bno == fsbtodb(blkno)) 296 goto foundit; 297 for (bp = bufhead.b_prev; bp != &bufhead; bp = bp->b_prev) 298 if ((bp->b_flags & B_INUSE) == 0) 299 break; 300 if (bp == &bufhead) 301 errexit(gettext("deadlocked buffer pool\n")); 302 (void) getblk(bp, blkno, size); 303 /* fall through */ 304 foundit: 305 totalreads++; 306 bp->b_prev->b_next = bp->b_next; 307 bp->b_next->b_prev = bp->b_prev; 308 bp->b_prev = &bufhead; 309 bp->b_next = bufhead.b_next; 310 bufhead.b_next->b_prev = bp; 311 bufhead.b_next = bp; 312 bp->b_flags |= B_INUSE; 313 return (bp); 314 } 315 316 static struct bufarea * 317 getblk(struct bufarea *bp, daddr_t blk, long size) 318 { 319 daddr_t dblk; 320 321 dblk = fsbtodb(blk); 322 if (bp->b_bno == dblk) 323 return (bp); 324 flush(fswritefd, bp); 325 diskreads++; 326 bp->b_errs = bread(fsreadfd, bp->b_un.b_buf, dblk, size); 327 bp->b_bno = dblk; 328 bp->b_size = size; 329 return (bp); 330 } 331 332 void 333 flush(int32_t fd, struct bufarea *bp) 334 { 335 if (!bp->b_dirty) 336 return; 337 if (bp->b_errs != 0) 338 pfatal(gettext("WRITING ZERO'ED BLOCK %d TO DISK\n"), 339 bp->b_bno); 340 bp->b_dirty = 0; 341 bp->b_errs = 0; 342 bwrite(fd, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size); 343 } 344 345 static void 346 rwerror(char *mesg, daddr_t blk) 347 { 348 349 if (preen == 0) 350 (void) printf("\n"); 351 pfatal(gettext("CANNOT %s: BLK %ld"), mesg, blk); 352 if (reply(gettext("CONTINUE")) == 0) 353 errexit(gettext("Program terminated\n")); 354 } 355 356 void 357 ckfini() 358 { 359 struct bufarea *bp, *nbp; 360 int cnt = 0; 361 362 for (bp = bufhead.b_prev; bp && bp != &bufhead; bp = nbp) { 363 cnt++; 364 flush(fswritefd, bp); 365 nbp = bp->b_prev; 366 free(bp->b_un.b_buf); 367 free((char *)bp); 368 } 369 if (bufhead.b_size != cnt) 370 errexit(gettext("Panic: lost %d buffers\n"), 371 bufhead.b_size - cnt); 372 if (debug) 373 (void) printf("cache missed %ld of %ld (%ld%%)\n", 374 diskreads, totalreads, 375 totalreads ? diskreads * 100 / totalreads : 0); 376 (void) close(fsreadfd); 377 (void) close(fswritefd); 378 } 379 380 int32_t 381 bread(int fd, char *buf, daddr_t blk, long size) 382 { 383 char *cp; 384 int i, errs; 385 offset_t offset = ldbtob(blk); 386 offset_t addr; 387 388 if (llseek(fd, offset, 0) < 0) 389 rwerror(gettext("SEEK"), blk); 390 else if (read(fd, buf, (int)size) == size) 391 return (0); 392 rwerror(gettext("READ"), blk); 393 if (llseek(fd, offset, 0) < 0) 394 rwerror(gettext("SEEK"), blk); 395 errs = 0; 396 bzero(buf, (int)size); 397 pwarn(gettext("THE FOLLOWING SECTORS COULD NOT BE READ:")); 398 for (cp = buf, i = 0; i < btodb(size); i++, cp += DEV_BSIZE) { 399 addr = ldbtob(blk + i); 400 if (llseek(fd, addr, SEEK_CUR) < 0 || 401 read(fd, cp, (int)secsize) < 0) { 402 (void) printf(" %ld", blk + i); 403 errs++; 404 } 405 } 406 (void) printf("\n"); 407 return (errs); 408 } 409 410 void 411 bwrite(int fd, char *buf, daddr_t blk, long size) 412 { 413 int i, n; 414 char *cp; 415 offset_t offset = ldbtob(blk); 416 offset_t addr; 417 418 if (fd < 0) 419 return; 420 if (llseek(fd, offset, 0) < 0) 421 rwerror(gettext("SEEK"), blk); 422 else if (write(fd, buf, (int)size) == size) { 423 fsmodified = 1; 424 return; 425 } 426 rwerror(gettext("WRITE"), blk); 427 if (llseek(fd, offset, 0) < 0) 428 rwerror(gettext("SEEK"), blk); 429 pwarn(gettext("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:")); 430 for (cp = buf, i = 0; i < btodb(size); i++, cp += DEV_BSIZE) { 431 n = 0; 432 addr = ldbtob(blk + i); 433 if (llseek(fd, addr, SEEK_CUR) < 0 || 434 (n = write(fd, cp, DEV_BSIZE)) < 0) { 435 (void) printf(" %ld", blk + i); 436 } else if (n > 0) { 437 fsmodified = 1; 438 } 439 440 } 441 (void) printf("\n"); 442 } 443 444 void 445 catch() 446 { 447 ckfini(); 448 exit(37); 449 } 450 451 /* 452 * When preening, allow a single quit to signal 453 * a special exit after filesystem checks complete 454 * so that reboot sequence may be interrupted. 455 */ 456 void 457 catchquit() 458 { 459 extern int returntosingle; 460 461 (void) printf(gettext("returning to single-user after filesystem " 462 "check\n")); 463 returntosingle = 1; 464 (void) signal(SIGQUIT, SIG_DFL); 465 } 466 467 /* 468 * determine whether an inode should be fixed. 469 */ 470 /* ARGSUSED1 */ 471 int32_t 472 dofix(struct inodesc *idesc, char *msg) 473 { 474 475 switch (idesc->id_fix) { 476 477 case DONTKNOW: 478 pwarn(msg); 479 if (preen) { 480 (void) printf(gettext(" (SALVAGED)\n")); 481 idesc->id_fix = FIX; 482 return (ALTERED); 483 } 484 if (reply(gettext("SALVAGE")) == 0) { 485 idesc->id_fix = NOFIX; 486 return (0); 487 } 488 idesc->id_fix = FIX; 489 return (ALTERED); 490 491 case FIX: 492 return (ALTERED); 493 494 case NOFIX: 495 return (0); 496 497 default: 498 errexit(gettext("UNKNOWN INODESC FIX MODE %d\n"), 499 idesc->id_fix); 500 } 501 /* NOTREACHED */ 502 } 503 504 /* 505 * Check to see if unraw version of name is already mounted. 506 * Since we do not believe /etc/mnttab, we stat the mount point 507 * to see if it is really looks mounted. 508 */ 509 int 510 mounted(char *name) 511 { 512 int found = 0; 513 struct mnttab mnt; 514 FILE *mnttab; 515 struct stat device_stat, mount_stat; 516 char *blkname, *unrawname(); 517 int err; 518 519 mnttab = fopen(MNTTAB, "r"); 520 if (mnttab == NULL) { 521 (void) printf(gettext("can't open %s\n"), MNTTAB); 522 return (0); 523 } 524 blkname = unrawname(name); 525 while ((getmntent(mnttab, &mnt)) == 0) { 526 if (strcmp(mnt.mnt_fstype, MNTTYPE_UDFS) != 0) { 527 continue; 528 } 529 if (strcmp(blkname, mnt.mnt_special) == 0) { 530 err = stat(mnt.mnt_mountp, &mount_stat); 531 err |= stat(mnt.mnt_special, &device_stat); 532 if (err < 0) 533 continue; 534 if (device_stat.st_rdev == mount_stat.st_dev) { 535 (void) strncpy(mnt.mnt_mountp, mountpoint, 536 sizeof (mountpoint)); 537 if (hasmntopt(&mnt, MNTOPT_RO) != 0) 538 found = 2; /* mounted as RO */ 539 else 540 found = 1; /* mounted as R/W */ 541 } 542 break; 543 } 544 } 545 (void) fclose(mnttab); 546 return (found); 547 } 548 549 /* 550 * Check to see if name corresponds to an entry in vfstab, and that the entry 551 * does not have option ro. 552 */ 553 int 554 writable(char *name) 555 { 556 int rw = 1; 557 struct vfstab vfsbuf; 558 FILE *vfstab; 559 char *blkname, *unrawname(); 560 561 vfstab = fopen(VFSTAB, "r"); 562 if (vfstab == NULL) { 563 (void) printf(gettext("can't open %s\n"), VFSTAB); 564 return (1); 565 } 566 blkname = unrawname(name); 567 if ((getvfsspec(vfstab, &vfsbuf, blkname) == 0) && 568 (vfsbuf.vfs_fstype != NULL) && 569 (strcmp(vfsbuf.vfs_fstype, MNTTYPE_UDFS) == 0) && 570 (hasvfsopt(&vfsbuf, MNTOPT_RO))) { 571 rw = 0; 572 } 573 (void) fclose(vfstab); 574 return (rw); 575 } 576 577 /* 578 * print out clean info 579 */ 580 void 581 printclean() 582 { 583 char *s; 584 585 switch (lvintp->lvid_int_type) { 586 587 case LVI_CLOSE: 588 s = gettext("clean"); 589 break; 590 591 case LVI_OPEN: 592 s = gettext("active"); 593 break; 594 595 default: 596 s = gettext("unknown"); 597 } 598 599 if (preen) 600 pwarn(gettext("is %s.\n"), s); 601 else 602 (void) printf("** %s is %s.\n", devname, s); 603 } 604