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