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