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