1 /* 2 * util.c --- miscellaneous utilities 3 * 4 * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o. 5 * 6 * %Begin-Header% 7 * This file may be redistributed under the terms of the GNU Public 8 * License. 9 * %End-Header% 10 */ 11 12 #include <stdlib.h> 13 #include <stdio.h> 14 #include <unistd.h> 15 #include <string.h> 16 #include <ctype.h> 17 #ifdef __linux__ 18 #include <sys/utsname.h> 19 #endif 20 21 #ifdef HAVE_CONIO_H 22 #undef HAVE_TERMIOS_H 23 #include <conio.h> 24 #define read_a_char() getch() 25 #else 26 #ifdef HAVE_TERMIOS_H 27 #include <termios.h> 28 #endif 29 #endif 30 31 #ifdef HAVE_MALLOC_H 32 #include <malloc.h> 33 #endif 34 35 #ifdef HAVE_ERRNO_H 36 #include <errno.h> 37 #endif 38 39 #include "e2fsck.h" 40 41 extern e2fsck_t e2fsck_global_ctx; /* Try your very best not to use this! */ 42 43 #include <stdarg.h> 44 #include <time.h> 45 #include <sys/time.h> 46 #include <sys/resource.h> 47 48 void fatal_error(e2fsck_t ctx, const char *msg) 49 { 50 ext2_filsys fs = ctx->fs; 51 int exit_value = FSCK_ERROR; 52 53 if (msg) 54 fprintf (stderr, "e2fsck: %s\n", msg); 55 if (!fs) 56 goto out; 57 if (fs->io && fs->super) { 58 ext2fs_mmp_stop(ctx->fs); 59 if (ctx->fs->io->magic == EXT2_ET_MAGIC_IO_CHANNEL) 60 io_channel_flush(ctx->fs->io); 61 else 62 log_err(ctx, "e2fsck: io manager magic bad!\n"); 63 } 64 if (ext2fs_test_changed(fs)) { 65 exit_value |= FSCK_NONDESTRUCT; 66 log_out(ctx, _("\n%s: ***** FILE SYSTEM WAS MODIFIED *****\n"), 67 ctx->device_name); 68 if (ctx->mount_flags & EXT2_MF_ISROOT) 69 exit_value |= FSCK_REBOOT; 70 } 71 if (!ext2fs_test_valid(fs)) { 72 log_out(ctx, _("\n%s: ********** WARNING: Filesystem still has " 73 "errors **********\n\n"), ctx->device_name); 74 exit_value |= FSCK_UNCORRECTED; 75 exit_value &= ~FSCK_NONDESTRUCT; 76 } 77 out: 78 ctx->flags |= E2F_FLAG_ABORT; 79 if (ctx->flags & E2F_FLAG_SETJMP_OK) 80 longjmp(ctx->abort_loc, 1); 81 exit(exit_value); 82 } 83 84 void log_out(e2fsck_t ctx, const char *fmt, ...) 85 { 86 va_list pvar; 87 88 va_start(pvar, fmt); 89 vprintf(fmt, pvar); 90 va_end(pvar); 91 if (ctx->logf) { 92 va_start(pvar, fmt); 93 vfprintf(ctx->logf, fmt, pvar); 94 va_end(pvar); 95 } 96 } 97 98 void log_err(e2fsck_t ctx, const char *fmt, ...) 99 { 100 va_list pvar; 101 102 va_start(pvar, fmt); 103 vfprintf(stderr, fmt, pvar); 104 va_end(pvar); 105 if (ctx->logf) { 106 va_start(pvar, fmt); 107 vfprintf(ctx->logf, fmt, pvar); 108 va_end(pvar); 109 } 110 } 111 112 void *e2fsck_allocate_memory(e2fsck_t ctx, unsigned int size, 113 const char *description) 114 { 115 void *ret; 116 char buf[256]; 117 118 #ifdef DEBUG_ALLOCATE_MEMORY 119 printf("Allocating %u bytes for %s...\n", size, description); 120 #endif 121 ret = malloc(size); 122 if (!ret) { 123 sprintf(buf, "Can't allocate %u bytes for %s\n", 124 size, description); 125 fatal_error(ctx, buf); 126 } 127 memset(ret, 0, size); 128 return ret; 129 } 130 131 char *string_copy(e2fsck_t ctx EXT2FS_ATTR((unused)), 132 const char *str, int len) 133 { 134 char *ret; 135 136 if (!str) 137 return NULL; 138 if (!len) 139 len = strlen(str); 140 ret = malloc(len+1); 141 if (ret) { 142 strncpy(ret, str, len); 143 ret[len] = 0; 144 } 145 return ret; 146 } 147 148 #ifndef HAVE_STRNLEN 149 /* 150 * Incredibly, libc5 doesn't appear to have strnlen. So we have to 151 * provide our own. 152 */ 153 int e2fsck_strnlen(const char * s, int count) 154 { 155 const char *cp = s; 156 157 while (count-- && *cp) 158 cp++; 159 return cp - s; 160 } 161 #endif 162 163 #ifndef HAVE_CONIO_H 164 static int read_a_char(void) 165 { 166 char c; 167 int r; 168 int fail = 0; 169 170 while(1) { 171 if (e2fsck_global_ctx && 172 (e2fsck_global_ctx->flags & E2F_FLAG_CANCEL)) { 173 return 3; 174 } 175 r = read(0, &c, 1); 176 if (r == 1) 177 return c; 178 if (fail++ > 100) 179 break; 180 } 181 return EOF; 182 } 183 #endif 184 185 int ask_yn(e2fsck_t ctx, const char * string, int def) 186 { 187 int c; 188 const char *defstr; 189 const char *short_yes = _("yY"); 190 const char *short_no = _("nN"); 191 192 #ifdef HAVE_TERMIOS_H 193 struct termios termios, tmp; 194 195 tcgetattr (0, &termios); 196 tmp = termios; 197 tmp.c_lflag &= ~(ICANON | ECHO); 198 tmp.c_cc[VMIN] = 1; 199 tmp.c_cc[VTIME] = 0; 200 tcsetattr (0, TCSANOW, &tmp); 201 #endif 202 203 if (def == 1) 204 defstr = _(_("<y>")); 205 else if (def == 0) 206 defstr = _(_("<n>")); 207 else 208 defstr = _(" (y/n)"); 209 log_out(ctx, "%s%s? ", string, defstr); 210 while (1) { 211 fflush (stdout); 212 if ((c = read_a_char()) == EOF) 213 break; 214 if (c == 3) { 215 #ifdef HAVE_TERMIOS_H 216 tcsetattr (0, TCSANOW, &termios); 217 #endif 218 if (ctx->flags & E2F_FLAG_SETJMP_OK) { 219 log_out(ctx, "\n"); 220 longjmp(e2fsck_global_ctx->abort_loc, 1); 221 } 222 log_out(ctx, "%s", _("cancelled!\n")); 223 return 0; 224 } 225 if (strchr(short_yes, (char) c)) { 226 def = 1; 227 break; 228 } 229 else if (strchr(short_no, (char) c)) { 230 def = 0; 231 break; 232 } 233 else if ((c == 27 || c == ' ' || c == '\n') && (def != -1)) 234 break; 235 } 236 if (def) 237 log_out(ctx, "%s", _("yes\n")); 238 else 239 log_out(ctx, "%s", _("no\n")); 240 #ifdef HAVE_TERMIOS_H 241 tcsetattr (0, TCSANOW, &termios); 242 #endif 243 return def; 244 } 245 246 int ask (e2fsck_t ctx, const char * string, int def) 247 { 248 if (ctx->options & E2F_OPT_NO) { 249 log_out(ctx, _("%s? no\n\n"), string); 250 return 0; 251 } 252 if (ctx->options & E2F_OPT_YES) { 253 log_out(ctx, _("%s? yes\n\n"), string); 254 return 1; 255 } 256 if (ctx->options & E2F_OPT_PREEN) { 257 log_out(ctx, "%s? %s\n\n", string, def ? _("yes") : _("no")); 258 return def; 259 } 260 return ask_yn(ctx, string, def); 261 } 262 263 void e2fsck_read_bitmaps(e2fsck_t ctx) 264 { 265 ext2_filsys fs = ctx->fs; 266 errcode_t retval; 267 const char *old_op; 268 unsigned int save_type; 269 270 if (ctx->invalid_bitmaps) { 271 com_err(ctx->program_name, 0, 272 _("e2fsck_read_bitmaps: illegal bitmap block(s) for %s"), 273 ctx->device_name); 274 fatal_error(ctx, 0); 275 } 276 277 old_op = ehandler_operation(_("reading inode and block bitmaps")); 278 e2fsck_set_bitmap_type(fs, EXT2FS_BMAP64_RBTREE, "fs_bitmaps", 279 &save_type); 280 retval = ext2fs_read_bitmaps(fs); 281 fs->default_bitmap_type = save_type; 282 ehandler_operation(old_op); 283 if (retval) { 284 com_err(ctx->program_name, retval, 285 _("while retrying to read bitmaps for %s"), 286 ctx->device_name); 287 fatal_error(ctx, 0); 288 } 289 } 290 291 void e2fsck_write_bitmaps(e2fsck_t ctx) 292 { 293 ext2_filsys fs = ctx->fs; 294 errcode_t retval; 295 const char *old_op; 296 297 old_op = ehandler_operation(_("writing block and inode bitmaps")); 298 retval = ext2fs_write_bitmaps(fs); 299 ehandler_operation(old_op); 300 if (retval) { 301 com_err(ctx->program_name, retval, 302 _("while rewriting block and inode bitmaps for %s"), 303 ctx->device_name); 304 fatal_error(ctx, 0); 305 } 306 } 307 308 void preenhalt(e2fsck_t ctx) 309 { 310 ext2_filsys fs = ctx->fs; 311 312 if (!(ctx->options & E2F_OPT_PREEN)) 313 return; 314 log_err(ctx, _("\n\n%s: UNEXPECTED INCONSISTENCY; " 315 "RUN fsck MANUALLY.\n\t(i.e., without -a or -p options)\n"), 316 ctx->device_name); 317 ctx->flags |= E2F_FLAG_EXITING; 318 if (fs != NULL) { 319 fs->super->s_state |= EXT2_ERROR_FS; 320 ext2fs_mark_super_dirty(fs); 321 ext2fs_close(fs); 322 } 323 exit(FSCK_UNCORRECTED); 324 } 325 326 #ifdef RESOURCE_TRACK 327 void init_resource_track(struct resource_track *track, io_channel channel) 328 { 329 #ifdef HAVE_GETRUSAGE 330 struct rusage r; 331 #endif 332 io_stats io_start = 0; 333 334 track->brk_start = sbrk(0); 335 gettimeofday(&track->time_start, 0); 336 #ifdef HAVE_GETRUSAGE 337 #ifdef sun 338 memset(&r, 0, sizeof(struct rusage)); 339 #endif 340 getrusage(RUSAGE_SELF, &r); 341 track->user_start = r.ru_utime; 342 track->system_start = r.ru_stime; 343 #else 344 track->user_start.tv_sec = track->user_start.tv_usec = 0; 345 track->system_start.tv_sec = track->system_start.tv_usec = 0; 346 #endif 347 track->bytes_read = 0; 348 track->bytes_written = 0; 349 if (channel && channel->manager && channel->manager->get_stats) 350 channel->manager->get_stats(channel, &io_start); 351 if (io_start) { 352 track->bytes_read = io_start->bytes_read; 353 track->bytes_written = io_start->bytes_written; 354 } 355 } 356 357 #ifdef __GNUC__ 358 #define _INLINE_ __inline__ 359 #else 360 #define _INLINE_ 361 #endif 362 363 static _INLINE_ float timeval_subtract(struct timeval *tv1, 364 struct timeval *tv2) 365 { 366 return ((tv1->tv_sec - tv2->tv_sec) + 367 ((float) (tv1->tv_usec - tv2->tv_usec)) / 1000000); 368 } 369 370 void print_resource_track(e2fsck_t ctx, const char *desc, 371 struct resource_track *track, io_channel channel) 372 { 373 #ifdef HAVE_GETRUSAGE 374 struct rusage r; 375 #endif 376 #ifdef HAVE_MALLINFO 377 struct mallinfo malloc_info; 378 #endif 379 struct timeval time_end; 380 381 if ((desc && !(ctx->options & E2F_OPT_TIME2)) || 382 (!desc && !(ctx->options & E2F_OPT_TIME))) 383 return; 384 385 e2fsck_clear_progbar(ctx); 386 gettimeofday(&time_end, 0); 387 388 if (desc) 389 log_out(ctx, "%s: ", desc); 390 391 #ifdef HAVE_MALLINFO 392 #define kbytes(x) (((unsigned long)(x) + 1023) / 1024) 393 394 malloc_info = mallinfo(); 395 log_out(ctx, _("Memory used: %luk/%luk (%luk/%luk), "), 396 kbytes(malloc_info.arena), kbytes(malloc_info.hblkhd), 397 kbytes(malloc_info.uordblks), kbytes(malloc_info.fordblks)); 398 #else 399 log_out(ctx, _("Memory used: %lu, "), 400 (unsigned long) (((char *) sbrk(0)) - 401 ((char *) track->brk_start))); 402 #endif 403 #ifdef HAVE_GETRUSAGE 404 getrusage(RUSAGE_SELF, &r); 405 406 log_out(ctx, _("time: %5.2f/%5.2f/%5.2f\n"), 407 timeval_subtract(&time_end, &track->time_start), 408 timeval_subtract(&r.ru_utime, &track->user_start), 409 timeval_subtract(&r.ru_stime, &track->system_start)); 410 #else 411 log_out(ctx, _("elapsed time: %6.3f\n"), 412 timeval_subtract(&time_end, &track->time_start)); 413 #endif 414 #define mbytes(x) (((x) + 1048575) / 1048576) 415 if (channel && channel->manager && channel->manager->get_stats) { 416 io_stats delta = 0; 417 unsigned long long bytes_read = 0; 418 unsigned long long bytes_written = 0; 419 420 if (desc) 421 log_out(ctx, "%s: ", desc); 422 423 channel->manager->get_stats(channel, &delta); 424 if (delta) { 425 bytes_read = delta->bytes_read - track->bytes_read; 426 bytes_written = delta->bytes_written - 427 track->bytes_written; 428 } 429 log_out(ctx, "I/O read: %lluMB, write: %lluMB, " 430 "rate: %.2fMB/s\n", 431 mbytes(bytes_read), mbytes(bytes_written), 432 (double)mbytes(bytes_read + bytes_written) / 433 timeval_subtract(&time_end, &track->time_start)); 434 } 435 } 436 #endif /* RESOURCE_TRACK */ 437 438 void e2fsck_read_inode(e2fsck_t ctx, unsigned long ino, 439 struct ext2_inode * inode, const char *proc) 440 { 441 errcode_t retval; 442 443 retval = ext2fs_read_inode(ctx->fs, ino, inode); 444 if (retval) { 445 com_err("ext2fs_read_inode", retval, 446 _("while reading inode %lu in %s"), ino, proc); 447 fatal_error(ctx, 0); 448 } 449 } 450 451 void e2fsck_read_inode_full(e2fsck_t ctx, unsigned long ino, 452 struct ext2_inode *inode, int bufsize, 453 const char *proc) 454 { 455 errcode_t retval; 456 457 retval = ext2fs_read_inode_full(ctx->fs, ino, inode, bufsize); 458 if (retval) { 459 com_err("ext2fs_read_inode_full", retval, 460 _("while reading inode %lu in %s"), ino, proc); 461 fatal_error(ctx, 0); 462 } 463 } 464 465 void e2fsck_write_inode_full(e2fsck_t ctx, unsigned long ino, 466 struct ext2_inode * inode, int bufsize, 467 const char *proc) 468 { 469 errcode_t retval; 470 471 retval = ext2fs_write_inode_full(ctx->fs, ino, inode, bufsize); 472 if (retval) { 473 com_err("ext2fs_write_inode", retval, 474 _("while writing inode %lu in %s"), ino, proc); 475 fatal_error(ctx, 0); 476 } 477 } 478 479 void e2fsck_write_inode(e2fsck_t ctx, unsigned long ino, 480 struct ext2_inode * inode, const char *proc) 481 { 482 errcode_t retval; 483 484 retval = ext2fs_write_inode(ctx->fs, ino, inode); 485 if (retval) { 486 com_err("ext2fs_write_inode", retval, 487 _("while writing inode %lu in %s"), ino, proc); 488 fatal_error(ctx, 0); 489 } 490 } 491 492 #ifdef MTRACE 493 void mtrace_print(char *mesg) 494 { 495 FILE *malloc_get_mallstream(); 496 FILE *f = malloc_get_mallstream(); 497 498 if (f) 499 fprintf(f, "============= %s\n", mesg); 500 } 501 #endif 502 503 blk64_t get_backup_sb(e2fsck_t ctx, ext2_filsys fs, const char *name, 504 io_manager manager) 505 { 506 struct ext2_super_block *sb; 507 io_channel io = NULL; 508 void *buf = NULL; 509 int blocksize; 510 blk64_t superblock, ret_sb = 8193; 511 512 if (fs && fs->super) { 513 ret_sb = (fs->super->s_blocks_per_group + 514 fs->super->s_first_data_block); 515 if (ctx) { 516 ctx->superblock = ret_sb; 517 ctx->blocksize = fs->blocksize; 518 } 519 return ret_sb; 520 } 521 522 if (ctx) { 523 if (ctx->blocksize) { 524 ret_sb = ctx->blocksize * 8; 525 if (ctx->blocksize == 1024) 526 ret_sb++; 527 ctx->superblock = ret_sb; 528 return ret_sb; 529 } 530 ctx->superblock = ret_sb; 531 ctx->blocksize = 1024; 532 } 533 534 if (!name || !manager) 535 goto cleanup; 536 537 if (manager->open(name, 0, &io) != 0) 538 goto cleanup; 539 540 if (ext2fs_get_mem(SUPERBLOCK_SIZE, &buf)) 541 goto cleanup; 542 sb = (struct ext2_super_block *) buf; 543 544 for (blocksize = EXT2_MIN_BLOCK_SIZE; 545 blocksize <= EXT2_MAX_BLOCK_SIZE ; blocksize *= 2) { 546 superblock = blocksize*8; 547 if (blocksize == 1024) 548 superblock++; 549 io_channel_set_blksize(io, blocksize); 550 if (io_channel_read_blk64(io, superblock, 551 -SUPERBLOCK_SIZE, buf)) 552 continue; 553 #ifdef WORDS_BIGENDIAN 554 if (sb->s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC)) 555 ext2fs_swap_super(sb); 556 #endif 557 if ((sb->s_magic == EXT2_SUPER_MAGIC) && 558 (EXT2_BLOCK_SIZE(sb) == blocksize)) { 559 ret_sb = superblock; 560 if (ctx) { 561 ctx->superblock = superblock; 562 ctx->blocksize = blocksize; 563 } 564 break; 565 } 566 } 567 568 cleanup: 569 if (io) 570 io_channel_close(io); 571 if (buf) 572 ext2fs_free_mem(&buf); 573 return (ret_sb); 574 } 575 576 /* 577 * Given a mode, return the ext2 file type 578 */ 579 int ext2_file_type(unsigned int mode) 580 { 581 if (LINUX_S_ISREG(mode)) 582 return EXT2_FT_REG_FILE; 583 584 if (LINUX_S_ISDIR(mode)) 585 return EXT2_FT_DIR; 586 587 if (LINUX_S_ISCHR(mode)) 588 return EXT2_FT_CHRDEV; 589 590 if (LINUX_S_ISBLK(mode)) 591 return EXT2_FT_BLKDEV; 592 593 if (LINUX_S_ISLNK(mode)) 594 return EXT2_FT_SYMLINK; 595 596 if (LINUX_S_ISFIFO(mode)) 597 return EXT2_FT_FIFO; 598 599 if (LINUX_S_ISSOCK(mode)) 600 return EXT2_FT_SOCK; 601 602 return 0; 603 } 604 605 #define STRIDE_LENGTH 8 606 /* 607 * Helper function which zeros out _num_ blocks starting at _blk_. In 608 * case of an error, the details of the error is returned via _ret_blk_ 609 * and _ret_count_ if they are non-NULL pointers. Returns 0 on 610 * success, and an error code on an error. 611 * 612 * As a special case, if the first argument is NULL, then it will 613 * attempt to free the static zeroizing buffer. (This is to keep 614 * programs that check for memory leaks happy.) 615 */ 616 errcode_t e2fsck_zero_blocks(ext2_filsys fs, blk_t blk, int num, 617 blk_t *ret_blk, int *ret_count) 618 { 619 int j, count; 620 static char *buf; 621 errcode_t retval; 622 623 /* If fs is null, clean up the static buffer and return */ 624 if (!fs) { 625 if (buf) { 626 free(buf); 627 buf = 0; 628 } 629 return 0; 630 } 631 /* Allocate the zeroizing buffer if necessary */ 632 if (!buf) { 633 buf = malloc(fs->blocksize * STRIDE_LENGTH); 634 if (!buf) { 635 com_err("malloc", ENOMEM, "%s", 636 _("while allocating zeroizing buffer")); 637 exit(1); 638 } 639 memset(buf, 0, fs->blocksize * STRIDE_LENGTH); 640 } 641 /* OK, do the write loop */ 642 for (j = 0; j < num; j += STRIDE_LENGTH, blk += STRIDE_LENGTH) { 643 count = num - j; 644 if (count > STRIDE_LENGTH) 645 count = STRIDE_LENGTH; 646 retval = io_channel_write_blk64(fs->io, blk, count, buf); 647 if (retval) { 648 if (ret_count) 649 *ret_count = count; 650 if (ret_blk) 651 *ret_blk = blk; 652 return retval; 653 } 654 } 655 return 0; 656 } 657 658 /* 659 * Check to see if a filesystem is in /proc/filesystems. 660 * Returns 1 if found, 0 if not 661 */ 662 int fs_proc_check(const char *fs_name) 663 { 664 FILE *f; 665 char buf[80], *cp, *t; 666 667 f = fopen("/proc/filesystems", "r"); 668 if (!f) 669 return (0); 670 while (!feof(f)) { 671 if (!fgets(buf, sizeof(buf), f)) 672 break; 673 cp = buf; 674 if (!isspace(*cp)) { 675 while (*cp && !isspace(*cp)) 676 cp++; 677 } 678 while (*cp && isspace(*cp)) 679 cp++; 680 if ((t = strchr(cp, '\n')) != NULL) 681 *t = 0; 682 if ((t = strchr(cp, '\t')) != NULL) 683 *t = 0; 684 if ((t = strchr(cp, ' ')) != NULL) 685 *t = 0; 686 if (!strcmp(fs_name, cp)) { 687 fclose(f); 688 return (1); 689 } 690 } 691 fclose(f); 692 return (0); 693 } 694 695 /* 696 * Check to see if a filesystem is available as a module 697 * Returns 1 if found, 0 if not 698 */ 699 int check_for_modules(const char *fs_name) 700 { 701 #ifdef __linux__ 702 struct utsname uts; 703 FILE *f; 704 char buf[1024], *cp, *t; 705 int i; 706 707 if (uname(&uts)) 708 return (0); 709 snprintf(buf, sizeof(buf), "/lib/modules/%s/modules.dep", uts.release); 710 711 f = fopen(buf, "r"); 712 if (!f) 713 return (0); 714 while (!feof(f)) { 715 if (!fgets(buf, sizeof(buf), f)) 716 break; 717 if ((cp = strchr(buf, ':')) != NULL) 718 *cp = 0; 719 else 720 continue; 721 if ((cp = strrchr(buf, '/')) != NULL) 722 cp++; 723 else 724 cp = buf; 725 i = strlen(cp); 726 if (i > 3) { 727 t = cp + i - 3; 728 if (!strcmp(t, ".ko")) 729 *t = 0; 730 } 731 if (!strcmp(cp, fs_name)) { 732 fclose(f); 733 return (1); 734 } 735 } 736 fclose(f); 737 #endif /* __linux__ */ 738 return (0); 739 } 740 741 /* 742 * Helper function that does the right thing if write returns a 743 * partial write, or an EGAIN/EINTR error. 744 */ 745 int write_all(int fd, char *buf, size_t count) 746 { 747 ssize_t ret; 748 int c = 0; 749 750 while (count > 0) { 751 ret = write(fd, buf, count); 752 if (ret < 0) { 753 if ((errno == EAGAIN) || (errno == EINTR)) 754 continue; 755 return -1; 756 } 757 count -= ret; 758 buf += ret; 759 c += ret; 760 } 761 return c; 762 } 763 764 void dump_mmp_msg(struct mmp_struct *mmp, const char *msg) 765 { 766 767 if (msg) 768 printf("MMP check failed: %s\n", msg); 769 if (mmp) { 770 time_t t = mmp->mmp_time; 771 772 printf("MMP error info: last update: %s node: %s device: %s\n", 773 ctime(&t), mmp->mmp_nodename, mmp->mmp_bdevname); 774 } 775 } 776 777 errcode_t e2fsck_mmp_update(ext2_filsys fs) 778 { 779 errcode_t retval; 780 781 retval = ext2fs_mmp_update(fs); 782 if (retval == EXT2_ET_MMP_CHANGE_ABORT) 783 dump_mmp_msg(fs->mmp_cmp, 784 _("UNEXPECTED INCONSISTENCY: the filesystem is " 785 "being modified while fsck is running.\n")); 786 787 return retval; 788 } 789 790 void e2fsck_set_bitmap_type(ext2_filsys fs, unsigned int default_type, 791 const char *profile_name, unsigned int *old_type) 792 { 793 unsigned type; 794 795 if (old_type) 796 *old_type = fs->default_bitmap_type; 797 #ifdef HAVE_SIGNAL_H 798 profile_get_uint(e2fsck_global_ctx->profile, "bitmaps", 799 profile_name, 0, default_type, &type); 800 profile_get_uint(e2fsck_global_ctx->profile, "bitmaps", 801 "all", 0, type, &type); 802 fs->default_bitmap_type = type ? type : default_type; 803 #else 804 fs->default_bitmap_type = default_type; 805 #endif 806 } 807 808 errcode_t e2fsck_allocate_inode_bitmap(ext2_filsys fs, const char *descr, 809 int deftype, 810 const char *name, 811 ext2fs_inode_bitmap *ret) 812 { 813 errcode_t retval; 814 unsigned int save_type; 815 816 e2fsck_set_bitmap_type(fs, deftype, name, &save_type); 817 retval = ext2fs_allocate_inode_bitmap(fs, descr, ret); 818 fs->default_bitmap_type = save_type; 819 return retval; 820 } 821 822 errcode_t e2fsck_allocate_block_bitmap(ext2_filsys fs, const char *descr, 823 int deftype, 824 const char *name, 825 ext2fs_block_bitmap *ret) 826 { 827 errcode_t retval; 828 unsigned int save_type; 829 830 e2fsck_set_bitmap_type(fs, deftype, name, &save_type); 831 retval = ext2fs_allocate_block_bitmap(fs, descr, ret); 832 fs->default_bitmap_type = save_type; 833 return retval; 834 } 835 836 errcode_t e2fsck_allocate_subcluster_bitmap(ext2_filsys fs, const char *descr, 837 int deftype, 838 const char *name, 839 ext2fs_block_bitmap *ret) 840 { 841 errcode_t retval; 842 unsigned int save_type; 843 844 e2fsck_set_bitmap_type(fs, deftype, name, &save_type); 845 retval = ext2fs_allocate_subcluster_bitmap(fs, descr, ret); 846 fs->default_bitmap_type = save_type; 847 return retval; 848 } 849