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
46extern 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
53void 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	}
82out:
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
89void 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
103void 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
117void *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
136char *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 */
158int 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
169static 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
190int 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
275int 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
292void 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
325void 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
342void 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
361void 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
397static _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
404void 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
472void 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
485void 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
499void 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
513void 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
527void 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
537blk64_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
602cleanup:
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 */
613int 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 */
643int 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 */
680int 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 */
726int 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
745void 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
758errcode_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
771void 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
785errcode_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
799errcode_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
813errcode_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 */
828unsigned 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