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 <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