2 * util.c --- miscellaneous utilities
4 * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o.
7 * This file may be redistributed under the terms of the GNU Public
19 #include <sys/utsname.h>
25 #define read_a_char() getch()
40 #ifdef HAVE_SYS_SYSCTL_H
41 #include <sys/sysctl.h>
46 extern e2fsck_t e2fsck_global_ctx; /* Try your very best not to use this! */
51 #include <sys/resource.h>
53 void fatal_error(e2fsck_t ctx, const char *msg)
55 ext2_filsys fs = ctx->fs;
56 int exit_value = FSCK_ERROR;
59 fprintf (stderr, "e2fsck: %s\n", msg);
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);
67 log_err(ctx, "e2fsck: io manager magic bad!\n");
69 if (ext2fs_test_changed(fs)) {
70 exit_value |= FSCK_NONDESTRUCT;
71 log_out(ctx, _("\n%s: ***** FILE SYSTEM WAS MODIFIED *****\n"),
73 if (ctx->mount_flags & EXT2_MF_ISROOT)
74 exit_value |= FSCK_REBOOT;
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;
83 ctx->flags |= E2F_FLAG_ABORT;
84 if (ctx->flags & E2F_FLAG_SETJMP_OK)
85 longjmp(ctx->abort_loc, 1);
89 void log_out(e2fsck_t ctx, const char *fmt, ...)
98 vfprintf(ctx->logf, fmt, pvar);
103 void log_err(e2fsck_t ctx, const char *fmt, ...)
108 vfprintf(stderr, fmt, pvar);
112 vfprintf(ctx->logf, fmt, pvar);
117 void *e2fsck_allocate_memory(e2fsck_t ctx, unsigned int size,
118 const char *description)
123 #ifdef DEBUG_ALLOCATE_MEMORY
124 printf("Allocating %u bytes for %s...\n", size, description);
128 sprintf(buf, "Can't allocate %u bytes for %s\n",
130 fatal_error(ctx, buf);
132 memset(ret, 0, size);
136 char *string_copy(e2fsck_t ctx EXT2FS_ATTR((unused)),
137 const char *str, int len)
147 strncpy(ret, str, len);
155 * Incredibly, libc5 doesn't appear to have strnlen. So we have to
158 int e2fsck_strnlen(const char * s, int count)
162 while (count-- && *cp)
169 static int read_a_char(void)
176 if (e2fsck_global_ctx &&
177 (e2fsck_global_ctx->flags & E2F_FLAG_CANCEL)) {
190 int ask_yn(e2fsck_t ctx, const char * string, int def)
194 const char *short_yes = _("yY");
195 const char *short_no = _("nN");
196 const char *short_yesall = _("aA");
197 const char *yesall_prompt = _(" ('a' enables 'yes' to all) ");
198 const char *extra_prompt = "";
199 static int yes_answers;
201 #ifdef HAVE_TERMIOS_H
202 struct termios termios, tmp;
204 tcgetattr (0, &termios);
206 tmp.c_lflag &= ~(ICANON | ECHO);
209 tcsetattr (0, TCSANOW, &tmp);
213 defstr = _(_("<y>"));
215 defstr = _(_("<n>"));
217 defstr = _(" (y/n)");
219 * If the user presses 'y' more than 8 (but less than 12) times in
220 * succession without pressing anything else, display a hint about
223 if (yes_answers > 12)
225 else if (yes_answers > 8)
226 extra_prompt = yesall_prompt;
227 log_out(ctx, "%s%s%s? ", string, extra_prompt, defstr);
230 if ((c = read_a_char()) == EOF)
233 #ifdef HAVE_TERMIOS_H
234 tcsetattr (0, TCSANOW, &termios);
236 if (ctx->flags & E2F_FLAG_SETJMP_OK) {
238 longjmp(e2fsck_global_ctx->abort_loc, 1);
240 log_out(ctx, "%s", _("cancelled!\n"));
244 if (strchr(short_yes, (char) c)) {
246 if (yes_answers >= 0)
249 } else if (strchr(short_no, (char) c)) {
253 } else if (strchr(short_yesall, (char)c)) {
256 ctx->options |= E2F_OPT_YES;
258 } else if ((c == 27 || c == ' ' || c == '\n') && (def != -1)) {
264 log_out(ctx, "%s", _("yes to all\n"));
266 log_out(ctx, "%s", _("yes\n"));
268 log_out(ctx, "%s", _("no\n"));
269 #ifdef HAVE_TERMIOS_H
270 tcsetattr (0, TCSANOW, &termios);
275 int ask (e2fsck_t ctx, const char * string, int def)
277 if (ctx->options & E2F_OPT_NO) {
278 log_out(ctx, _("%s? no\n\n"), string);
281 if (ctx->options & E2F_OPT_YES) {
282 log_out(ctx, _("%s? yes\n\n"), string);
285 if (ctx->options & E2F_OPT_PREEN) {
286 log_out(ctx, "%s? %s\n\n", string, def ? _("yes") : _("no"));
289 return ask_yn(ctx, string, def);
292 void e2fsck_read_bitmaps(e2fsck_t ctx)
294 ext2_filsys fs = ctx->fs;
297 unsigned int save_type;
300 if (ctx->invalid_bitmaps) {
301 com_err(ctx->program_name, 0,
302 _("e2fsck_read_bitmaps: illegal bitmap block(s) for %s"),
307 old_op = ehandler_operation(_("reading inode and block bitmaps"));
308 e2fsck_set_bitmap_type(fs, EXT2FS_BMAP64_RBTREE, "fs_bitmaps",
310 flags = ctx->fs->flags;
311 ctx->fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
312 retval = ext2fs_read_bitmaps(fs);
313 ctx->fs->flags = (flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) |
314 (ctx->fs->flags & ~EXT2_FLAG_IGNORE_CSUM_ERRORS);
315 fs->default_bitmap_type = save_type;
316 ehandler_operation(old_op);
318 com_err(ctx->program_name, retval,
319 _("while retrying to read bitmaps for %s"),
325 void e2fsck_write_bitmaps(e2fsck_t ctx)
327 ext2_filsys fs = ctx->fs;
331 old_op = ehandler_operation(_("writing block and inode bitmaps"));
332 retval = ext2fs_write_bitmaps(fs);
333 ehandler_operation(old_op);
335 com_err(ctx->program_name, retval,
336 _("while rewriting block and inode bitmaps for %s"),
342 void preenhalt(e2fsck_t ctx)
344 ext2_filsys fs = ctx->fs;
346 if (!(ctx->options & E2F_OPT_PREEN))
348 log_err(ctx, _("\n\n%s: UNEXPECTED INCONSISTENCY; "
349 "RUN fsck MANUALLY.\n\t(i.e., without -a or -p options)\n"),
351 ctx->flags |= E2F_FLAG_EXITING;
353 fs->super->s_state |= EXT2_ERROR_FS;
354 ext2fs_mark_super_dirty(fs);
355 ext2fs_close_free(&fs);
357 exit(FSCK_UNCORRECTED);
360 #ifdef RESOURCE_TRACK
361 void init_resource_track(struct resource_track *track, io_channel channel)
363 #ifdef HAVE_GETRUSAGE
366 io_stats io_start = 0;
368 track->brk_start = sbrk(0);
369 gettimeofday(&track->time_start, 0);
370 #ifdef HAVE_GETRUSAGE
372 memset(&r, 0, sizeof(struct rusage));
374 getrusage(RUSAGE_SELF, &r);
375 track->user_start = r.ru_utime;
376 track->system_start = r.ru_stime;
378 track->user_start.tv_sec = track->user_start.tv_usec = 0;
379 track->system_start.tv_sec = track->system_start.tv_usec = 0;
381 track->bytes_read = 0;
382 track->bytes_written = 0;
383 if (channel && channel->manager && channel->manager->get_stats)
384 channel->manager->get_stats(channel, &io_start);
386 track->bytes_read = io_start->bytes_read;
387 track->bytes_written = io_start->bytes_written;
392 #define _INLINE_ __inline__
397 static _INLINE_ float timeval_subtract(struct timeval *tv1,
400 return ((tv1->tv_sec - tv2->tv_sec) +
401 ((float) (tv1->tv_usec - tv2->tv_usec)) / 1000000);
404 void print_resource_track(e2fsck_t ctx, const char *desc,
405 struct resource_track *track, io_channel channel)
407 #ifdef HAVE_GETRUSAGE
411 struct mallinfo malloc_info;
413 struct timeval time_end;
415 if ((desc && !(ctx->options & E2F_OPT_TIME2)) ||
416 (!desc && !(ctx->options & E2F_OPT_TIME)))
419 e2fsck_clear_progbar(ctx);
420 gettimeofday(&time_end, 0);
423 log_out(ctx, "%s: ", desc);
426 #define kbytes(x) (((unsigned long)(x) + 1023) / 1024)
428 malloc_info = mallinfo();
429 log_out(ctx, _("Memory used: %luk/%luk (%luk/%luk), "),
430 kbytes(malloc_info.arena), kbytes(malloc_info.hblkhd),
431 kbytes(malloc_info.uordblks), kbytes(malloc_info.fordblks));
433 log_out(ctx, _("Memory used: %lu, "),
434 (unsigned long) (((char *) sbrk(0)) -
435 ((char *) track->brk_start)));
437 #ifdef HAVE_GETRUSAGE
438 getrusage(RUSAGE_SELF, &r);
440 log_out(ctx, _("time: %5.2f/%5.2f/%5.2f\n"),
441 timeval_subtract(&time_end, &track->time_start),
442 timeval_subtract(&r.ru_utime, &track->user_start),
443 timeval_subtract(&r.ru_stime, &track->system_start));
445 log_out(ctx, _("elapsed time: %6.3f\n"),
446 timeval_subtract(&time_end, &track->time_start));
448 #define mbytes(x) (((x) + 1048575) / 1048576)
449 if (channel && channel->manager && channel->manager->get_stats) {
451 unsigned long long bytes_read = 0;
452 unsigned long long bytes_written = 0;
455 log_out(ctx, "%s: ", desc);
457 channel->manager->get_stats(channel, &delta);
459 bytes_read = delta->bytes_read - track->bytes_read;
460 bytes_written = delta->bytes_written -
461 track->bytes_written;
463 log_out(ctx, "I/O read: %lluMB, write: %lluMB, "
465 mbytes(bytes_read), mbytes(bytes_written),
466 (double)mbytes(bytes_read + bytes_written) /
467 timeval_subtract(&time_end, &track->time_start));
470 #endif /* RESOURCE_TRACK */
472 void e2fsck_read_inode(e2fsck_t ctx, unsigned long ino,
473 struct ext2_inode * inode, const char *proc)
477 retval = ext2fs_read_inode(ctx->fs, ino, inode);
479 com_err("ext2fs_read_inode", retval,
480 _("while reading inode %lu in %s"), ino, proc);
485 void e2fsck_read_inode_full(e2fsck_t ctx, unsigned long ino,
486 struct ext2_inode *inode, int bufsize,
491 retval = ext2fs_read_inode_full(ctx->fs, ino, inode, bufsize);
493 com_err("ext2fs_read_inode_full", retval,
494 _("while reading inode %lu in %s"), ino, proc);
499 void e2fsck_write_inode_full(e2fsck_t ctx, unsigned long ino,
500 struct ext2_inode * inode, int bufsize,
505 retval = ext2fs_write_inode_full(ctx->fs, ino, inode, bufsize);
507 com_err("ext2fs_write_inode", retval,
508 _("while writing inode %lu in %s"), ino, proc);
513 void e2fsck_write_inode(e2fsck_t ctx, unsigned long ino,
514 struct ext2_inode * inode, const char *proc)
518 retval = ext2fs_write_inode(ctx->fs, ino, inode);
520 com_err("ext2fs_write_inode", retval,
521 _("while writing inode %lu in %s"), ino, proc);
527 void mtrace_print(char *mesg)
529 FILE *malloc_get_mallstream();
530 FILE *f = malloc_get_mallstream();
533 fprintf(f, "============= %s\n", mesg);
537 blk64_t get_backup_sb(e2fsck_t ctx, ext2_filsys fs, const char *name,
540 struct ext2_super_block *sb;
541 io_channel io = NULL;
544 blk64_t superblock, ret_sb = 8193;
546 if (fs && fs->super) {
547 ret_sb = (fs->super->s_blocks_per_group +
548 fs->super->s_first_data_block);
550 ctx->superblock = ret_sb;
551 ctx->blocksize = fs->blocksize;
557 if (ctx->blocksize) {
558 ret_sb = ctx->blocksize * 8;
559 if (ctx->blocksize == 1024)
561 ctx->superblock = ret_sb;
564 ctx->superblock = ret_sb;
565 ctx->blocksize = 1024;
568 if (!name || !manager)
571 if (manager->open(name, 0, &io) != 0)
574 if (ext2fs_get_mem(SUPERBLOCK_SIZE, &buf))
576 sb = (struct ext2_super_block *) buf;
578 for (blocksize = EXT2_MIN_BLOCK_SIZE;
579 blocksize <= EXT2_MAX_BLOCK_SIZE ; blocksize *= 2) {
580 superblock = blocksize*8;
581 if (blocksize == 1024)
583 io_channel_set_blksize(io, blocksize);
584 if (io_channel_read_blk64(io, superblock,
585 -SUPERBLOCK_SIZE, buf))
587 #ifdef WORDS_BIGENDIAN
588 if (sb->s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC))
589 ext2fs_swap_super(sb);
591 if ((sb->s_magic == EXT2_SUPER_MAGIC) &&
592 (EXT2_BLOCK_SIZE(sb) == blocksize)) {
595 ctx->superblock = superblock;
596 ctx->blocksize = blocksize;
604 io_channel_close(io);
606 ext2fs_free_mem(&buf);
611 * Given a mode, return the ext2 file type
613 int ext2_file_type(unsigned int mode)
615 if (LINUX_S_ISREG(mode))
616 return EXT2_FT_REG_FILE;
618 if (LINUX_S_ISDIR(mode))
621 if (LINUX_S_ISCHR(mode))
622 return EXT2_FT_CHRDEV;
624 if (LINUX_S_ISBLK(mode))
625 return EXT2_FT_BLKDEV;
627 if (LINUX_S_ISLNK(mode))
628 return EXT2_FT_SYMLINK;
630 if (LINUX_S_ISFIFO(mode))
633 if (LINUX_S_ISSOCK(mode))
640 * Check to see if a filesystem is in /proc/filesystems.
641 * Returns 1 if found, 0 if not
643 int fs_proc_check(const char *fs_name)
646 char buf[80], *cp, *t;
648 f = fopen("/proc/filesystems", "r");
652 if (!fgets(buf, sizeof(buf), f))
656 while (*cp && !isspace(*cp))
659 while (*cp && isspace(*cp))
661 if ((t = strchr(cp, '\n')) != NULL)
663 if ((t = strchr(cp, '\t')) != NULL)
665 if ((t = strchr(cp, ' ')) != NULL)
667 if (!strcmp(fs_name, cp)) {
677 * Check to see if a filesystem is available as a module
678 * Returns 1 if found, 0 if not
680 int check_for_modules(const char *fs_name)
685 char buf[1024], *cp, *t;
690 snprintf(buf, sizeof(buf), "/lib/modules/%s/modules.dep", uts.release);
696 if (!fgets(buf, sizeof(buf), f))
698 if ((cp = strchr(buf, ':')) != NULL)
702 if ((cp = strrchr(buf, '/')) != NULL)
709 if (!strcmp(t, ".ko"))
712 if (!strcmp(cp, fs_name)) {
718 #endif /* __linux__ */
723 * Helper function that does the right thing if write returns a
724 * partial write, or an EGAIN/EINTR error.
726 int write_all(int fd, char *buf, size_t count)
732 ret = write(fd, buf, count);
734 if ((errno == EAGAIN) || (errno == EINTR))
745 void dump_mmp_msg(struct mmp_struct *mmp, const char *msg)
749 printf("MMP check failed: %s\n", msg);
751 time_t t = mmp->mmp_time;
753 printf("MMP error info: last update: %s node: %s device: %s\n",
754 ctime(&t), mmp->mmp_nodename, mmp->mmp_bdevname);
758 errcode_t e2fsck_mmp_update(ext2_filsys fs)
762 retval = ext2fs_mmp_update(fs);
763 if (retval == EXT2_ET_MMP_CHANGE_ABORT)
764 dump_mmp_msg(fs->mmp_cmp,
765 _("UNEXPECTED INCONSISTENCY: the filesystem is "
766 "being modified while fsck is running.\n"));
771 void e2fsck_set_bitmap_type(ext2_filsys fs, unsigned int default_type,
772 const char *profile_name, unsigned int *old_type)
775 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
778 *old_type = fs->default_bitmap_type;
779 profile_get_uint(ctx->profile, "bitmaps", profile_name, 0,
780 default_type, &type);
781 profile_get_uint(ctx->profile, "bitmaps", "all", 0, type, &type);
782 fs->default_bitmap_type = type ? type : default_type;
785 errcode_t e2fsck_allocate_inode_bitmap(ext2_filsys fs, const char *descr,
788 ext2fs_inode_bitmap *ret)
791 unsigned int save_type;
793 e2fsck_set_bitmap_type(fs, deftype, name, &save_type);
794 retval = ext2fs_allocate_inode_bitmap(fs, descr, ret);
795 fs->default_bitmap_type = save_type;
799 errcode_t e2fsck_allocate_block_bitmap(ext2_filsys fs, const char *descr,
802 ext2fs_block_bitmap *ret)
805 unsigned int save_type;
807 e2fsck_set_bitmap_type(fs, deftype, name, &save_type);
808 retval = ext2fs_allocate_block_bitmap(fs, descr, ret);
809 fs->default_bitmap_type = save_type;
813 errcode_t e2fsck_allocate_subcluster_bitmap(ext2_filsys fs, const char *descr,
816 ext2fs_block_bitmap *ret)
819 unsigned int save_type;
821 e2fsck_set_bitmap_type(fs, deftype, name, &save_type);
822 retval = ext2fs_allocate_subcluster_bitmap(fs, descr, ret);
823 fs->default_bitmap_type = save_type;
827 /* Return memory size in bytes */
828 unsigned long long get_memory_size(void)
830 #if defined(_SC_PHYS_PAGES)
831 # if defined(_SC_PAGESIZE)
832 return (unsigned long long)sysconf(_SC_PHYS_PAGES) *
833 (unsigned long long)sysconf(_SC_PAGESIZE);
834 # elif defined(_SC_PAGE_SIZE)
835 return (unsigned long long)sysconf(_SC_PHYS_PAGES) *
836 (unsigned long long)sysconf(_SC_PAGE_SIZE);
838 #elif defined(CTL_HW)
839 # if (defined(HW_MEMSIZE) || defined(HW_PHYSMEM64))
840 # define CTL_HW_INT64
841 # elif (defined(HW_PHYSMEM) || defined(HW_REALMEM))
847 # if defined(HW_MEMSIZE)
849 # elif defined(HW_PHYSMEM64)
850 mib[1] = HW_PHYSMEM64;
851 # elif defined(HW_REALMEM)
853 # elif defined(HW_PYSMEM)
856 # if defined(CTL_HW_INT64)
857 unsigned long long size = 0;
858 # elif defined(CTL_HW_UINT)
859 unsigned int size = 0;
861 # if defined(CTL_HW_INT64) || defined(CTL_HW_UINT)
862 size_t len = sizeof(size);
864 if (sysctl(mib, 2, &size, &len, NULL, 0) == 0)
865 return (unsigned long long)size;
869 # warning "Don't know how to detect memory on your platform?"