xref: /aosp_15_r20/external/e2fsprogs/e2fsck/util.c (revision 6a54128f25917bfc36a8a6e9d722c04a0b4641b6)
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 
42 extern 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 
fatal_error(e2fsck_t ctx,const char * msg)49 void 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 	}
78 out:
79 	ctx->flags |= E2F_FLAG_ABORT;
80 	if (ctx->flags & E2F_FLAG_SETJMP_OK)
81 		longjmp(ctx->abort_loc, 1);
82 	if (ctx->logf)
83 		fprintf(ctx->logf, "Exit status: %d\n", exit_value);
84 	exit(exit_value);
85 }
86 
log_out(e2fsck_t ctx,const char * fmt,...)87 void log_out(e2fsck_t ctx, const char *fmt, ...)
88 {
89 	va_list pvar;
90 
91 	va_start(pvar, fmt);
92 	vprintf(fmt, pvar);
93 	va_end(pvar);
94 	if (ctx->logf) {
95 		va_start(pvar, fmt);
96 		vfprintf(ctx->logf, fmt, pvar);
97 		va_end(pvar);
98 	}
99 }
100 
log_err(e2fsck_t ctx,const char * fmt,...)101 void log_err(e2fsck_t ctx, const char *fmt, ...)
102 {
103 	va_list pvar;
104 
105 	va_start(pvar, fmt);
106 	vfprintf(stderr, fmt, pvar);
107 	va_end(pvar);
108 	if (ctx->logf) {
109 		va_start(pvar, fmt);
110 		vfprintf(ctx->logf, fmt, pvar);
111 		va_end(pvar);
112 	}
113 }
114 
e2fsck_allocate_memory(e2fsck_t ctx,unsigned long size,const char * description)115 void *e2fsck_allocate_memory(e2fsck_t ctx, unsigned long size,
116 			     const char *description)
117 {
118 	void *ret;
119 	char buf[256];
120 
121 #ifdef DEBUG_ALLOCATE_MEMORY
122 	printf("Allocating %lu bytes for %s...\n", size, description);
123 #endif
124 	if (ext2fs_get_memzero(size, &ret)) {
125 		sprintf(buf, "Can't allocate %lu bytes for %s\n",
126 			size, description);
127 		fatal_error(ctx, buf);
128 	}
129 
130 	return ret;
131 }
132 
string_copy(e2fsck_t ctx EXT2FS_ATTR ((unused)),const char * str,size_t len)133 char *string_copy(e2fsck_t ctx EXT2FS_ATTR((unused)),
134 		  const char *str, size_t len)
135 {
136 	char	*ret;
137 
138 	if (!str)
139 		return NULL;
140 	if (!len)
141 		len = strlen(str);
142 	ret = malloc(len+1);
143 	if (ret) {
144 		strncpy(ret, str, len);
145 		ret[len] = 0;
146 	}
147 	return ret;
148 }
149 
150 #ifndef HAVE_STRNLEN
151 /*
152  * Incredibly, libc5 doesn't appear to have strnlen.  So we have to
153  * provide our own.
154  */
e2fsck_strnlen(const char * s,int count)155 int e2fsck_strnlen(const char * s, int count)
156 {
157 	const char *cp = s;
158 
159 	while (count-- && *cp)
160 		cp++;
161 	return cp - s;
162 }
163 #endif
164 
165 #ifndef HAVE_CONIO_H
read_a_char(void)166 static int read_a_char(void)
167 {
168 	char	c;
169 	int	r;
170 	int	fail = 0;
171 
172 	while(1) {
173 		if (e2fsck_global_ctx &&
174 		    (e2fsck_global_ctx->flags & E2F_FLAG_CANCEL)) {
175 			return 3;
176 		}
177 		r = read(0, &c, 1);
178 		if (r == 1)
179 			return c;
180 		if (fail++ > 100)
181 			break;
182 	}
183 	return EOF;
184 }
185 #endif
186 
ask_yn(e2fsck_t ctx,const char * string,int def)187 int ask_yn(e2fsck_t ctx, const char * string, int def)
188 {
189 	int		c;
190 	const char	*defstr;
191 	const char	*short_yes = _("yY");
192 	const char	*short_no = _("nN");
193 	const char	*short_yesall = _("aA");
194 	const char	*english_yes = "yY";
195 	const char	*english_no = "nN";
196 	const char	*english_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 	if (tcgetattr (0, &termios) < 0)
205 		memset(&termios, 0, sizeof(termios));
206 	tmp = termios;
207 	tmp.c_lflag &= ~(ICANON | ECHO);
208 	tmp.c_cc[VMIN] = 1;
209 	tmp.c_cc[VTIME] = 0;
210 	tcsetattr (0, TCSANOW, &tmp);
211 #endif
212 
213 	if (def == 1)
214 		defstr = _(_("<y>"));
215 	else if (def == 0)
216 		defstr = _(_("<n>"));
217 	else
218 		defstr = _(" (y/n)");
219 	/*
220 	 * If the user presses 'y' more than 8 (but less than 12) times in
221 	 * succession without pressing anything else, display a hint about
222 	 * yes-to-all mode.
223 	 */
224 	if (yes_answers > 12)
225 		yes_answers = -1;
226 	else if (yes_answers > 8)
227 		extra_prompt = yesall_prompt;
228 	log_out(ctx, "%s%s%s? ", string, extra_prompt, defstr);
229 	while (1) {
230 		fflush (stdout);
231 		if ((c = read_a_char()) == EOF)
232 			break;
233 		if (c == 3) {
234 #ifdef HAVE_TERMIOS_H
235 			tcsetattr (0, TCSANOW, &termios);
236 #endif
237 			if (ctx->flags & E2F_FLAG_SETJMP_OK) {
238 				log_out(ctx, "\n");
239 				longjmp(e2fsck_global_ctx->abort_loc, 1);
240 			}
241 			log_out(ctx, "%s", _("cancelled!\n"));
242 			yes_answers = 0;
243 			return 0;
244 		}
245 		if (strchr(short_yes, (char) c)) {
246 		do_yes:
247 			def = 1;
248 			if (yes_answers >= 0)
249 				yes_answers++;
250 			break;
251 		} else if (strchr(short_no, (char) c)) {
252 		do_no:
253 			def = 0;
254 			yes_answers = -1;
255 			break;
256 		} else if (strchr(short_yesall, (char)c)) {
257 		do_all:
258 			def = 2;
259 			yes_answers = -1;
260 			ctx->options |= E2F_OPT_YES;
261 			break;
262 		} else if (strchr(english_yes, (char) c)) {
263 			goto do_yes;
264 		} else if (strchr(english_no, (char) c)) {
265 			goto do_no;
266 		} else if (strchr(english_yesall, (char) c)) {
267 			goto do_all;
268 		} else if ((c == 27 || c == ' ' || c == '\n') && (def != -1)) {
269 			yes_answers = -1;
270 			break;
271 		}
272 	}
273 	if (def == 2)
274 		log_out(ctx, "%s", _("yes to all\n"));
275 	else if (def)
276 		log_out(ctx, "%s", _("yes\n"));
277 	else
278 		log_out(ctx, "%s", _("no\n"));
279 #ifdef HAVE_TERMIOS_H
280 	tcsetattr (0, TCSANOW, &termios);
281 #endif
282 	return def;
283 }
284 
ask(e2fsck_t ctx,const char * string,int def)285 int ask (e2fsck_t ctx, const char * string, int def)
286 {
287 	if (ctx->options & E2F_OPT_NO) {
288 		log_out(ctx, _("%s? no\n\n"), string);
289 		return 0;
290 	}
291 	if (ctx->options & E2F_OPT_YES) {
292 		log_out(ctx, _("%s? yes\n\n"), string);
293 		return 1;
294 	}
295 	if (ctx->options & E2F_OPT_PREEN) {
296 		log_out(ctx, "%s? %s\n\n", string, def ? _("yes") : _("no"));
297 		return def;
298 	}
299 	return ask_yn(ctx, string, def);
300 }
301 
e2fsck_read_bitmaps(e2fsck_t ctx)302 void e2fsck_read_bitmaps(e2fsck_t ctx)
303 {
304 	ext2_filsys fs = ctx->fs;
305 	errcode_t	retval;
306 	const char	*old_op;
307 	unsigned int	save_type;
308 	int		flags;
309 
310 	if (ctx->invalid_bitmaps) {
311 		com_err(ctx->program_name, 0,
312 		    _("e2fsck_read_bitmaps: illegal bitmap block(s) for %s"),
313 			ctx->device_name);
314 		fatal_error(ctx, 0);
315 	}
316 
317 	old_op = ehandler_operation(_("reading inode and block bitmaps"));
318 	e2fsck_set_bitmap_type(fs, EXT2FS_BMAP64_RBTREE, "fs_bitmaps",
319 			       &save_type);
320 	flags = ctx->fs->flags;
321 	ctx->fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
322 	retval = ext2fs_read_bitmaps(fs);
323 	ctx->fs->flags = (flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) |
324 			 (ctx->fs->flags & ~EXT2_FLAG_IGNORE_CSUM_ERRORS);
325 	fs->default_bitmap_type = save_type;
326 	ehandler_operation(old_op);
327 	if (retval) {
328 		com_err(ctx->program_name, retval,
329 			_("while retrying to read bitmaps for %s"),
330 			ctx->device_name);
331 		fatal_error(ctx, 0);
332 	}
333 }
334 
e2fsck_write_bitmaps(e2fsck_t ctx)335 void e2fsck_write_bitmaps(e2fsck_t ctx)
336 {
337 	ext2_filsys fs = ctx->fs;
338 	errcode_t	retval;
339 	const char	*old_op;
340 
341 	old_op = ehandler_operation(_("writing block and inode bitmaps"));
342 	retval = ext2fs_write_bitmaps(fs);
343 	ehandler_operation(old_op);
344 	if (retval) {
345 		com_err(ctx->program_name, retval,
346 			_("while rewriting block and inode bitmaps for %s"),
347 			ctx->device_name);
348 		fatal_error(ctx, 0);
349 	}
350 }
351 
preenhalt(e2fsck_t ctx)352 void preenhalt(e2fsck_t ctx)
353 {
354 	ext2_filsys fs = ctx->fs;
355 
356 	if (!(ctx->options & E2F_OPT_PREEN))
357 		return;
358 	log_err(ctx, _("\n\n%s: UNEXPECTED INCONSISTENCY; "
359 		"RUN fsck MANUALLY.\n\t(i.e., without -a or -p options)\n"),
360 	       ctx->device_name);
361 	ctx->flags |= E2F_FLAG_EXITING;
362 	if (fs != NULL) {
363 		fs->super->s_state |= EXT2_ERROR_FS;
364 		ext2fs_mark_super_dirty(fs);
365 		ext2fs_close_free(&fs);
366 	}
367 	exit(FSCK_UNCORRECTED);
368 }
369 
370 #ifdef RESOURCE_TRACK
init_resource_track(struct resource_track * track,io_channel channel)371 void init_resource_track(struct resource_track *track, io_channel channel)
372 {
373 #ifdef HAVE_GETRUSAGE
374 	struct rusage r;
375 #endif
376 	io_stats io_start = 0;
377 
378 	track->brk_start = sbrk(0);
379 	gettimeofday(&track->time_start, 0);
380 #ifdef HAVE_GETRUSAGE
381 #ifdef sun
382 	memset(&r, 0, sizeof(struct rusage));
383 #endif
384 	getrusage(RUSAGE_SELF, &r);
385 	track->user_start = r.ru_utime;
386 	track->system_start = r.ru_stime;
387 #else
388 	track->user_start.tv_sec = track->user_start.tv_usec = 0;
389 	track->system_start.tv_sec = track->system_start.tv_usec = 0;
390 #endif
391 	track->bytes_read = 0;
392 	track->bytes_written = 0;
393 	if (channel && channel->manager && channel->manager->get_stats)
394 		channel->manager->get_stats(channel, &io_start);
395 	if (io_start) {
396 		track->bytes_read = io_start->bytes_read;
397 		track->bytes_written = io_start->bytes_written;
398 	}
399 }
400 
401 #ifdef __GNUC__
402 #define _INLINE_ __inline__
403 #else
404 #define _INLINE_
405 #endif
406 
timeval_subtract(struct timeval * tv1,struct timeval * tv2)407 static _INLINE_ float timeval_subtract(struct timeval *tv1,
408 				       struct timeval *tv2)
409 {
410 	return ((tv1->tv_sec - tv2->tv_sec) +
411 		((float) (tv1->tv_usec - tv2->tv_usec)) / 1000000);
412 }
413 
print_resource_track(e2fsck_t ctx,const char * desc,struct resource_track * track,io_channel channel)414 void print_resource_track(e2fsck_t ctx, const char *desc,
415 			  struct resource_track *track, io_channel channel)
416 {
417 #ifdef HAVE_GETRUSAGE
418 	struct rusage r;
419 #endif
420 	struct timeval time_end;
421 
422 	if ((desc && !(ctx->options & E2F_OPT_TIME2)) ||
423 	    (!desc && !(ctx->options & E2F_OPT_TIME)))
424 		return;
425 
426 	e2fsck_clear_progbar(ctx);
427 	gettimeofday(&time_end, 0);
428 
429 	if (desc)
430 		log_out(ctx, "%s: ", desc);
431 
432 #define kbytes(x)	(((unsigned long long)(x) + 1023) / 1024)
433 #ifdef HAVE_MALLINFO2
434 	if (1) {
435 		struct mallinfo2 malloc_info = mallinfo2();
436 
437 		log_out(ctx, _("Memory used: %lluk/%lluk (%lluk/%lluk), "),
438 			kbytes(malloc_info.arena), kbytes(malloc_info.hblkhd),
439 			kbytes(malloc_info.uordblks),
440 			kbytes(malloc_info.fordblks));
441 	} else
442 #elif defined HAVE_MALLINFO
443 	/* don't use mallinfo() if over 2GB used, since it returns "int" */
444 	if ((char *)sbrk(0) - (char *)track->brk_start < 2LL << 30) {
445 		struct mallinfo	malloc_info = mallinfo();
446 
447 		log_out(ctx, _("Memory used: %lluk/%lluk (%lluk/%lluk), "),
448 			kbytes(malloc_info.arena), kbytes(malloc_info.hblkhd),
449 			kbytes(malloc_info.uordblks),
450 			kbytes(malloc_info.fordblks));
451 	} else
452 #endif
453 	log_out(ctx, _("Memory used: %lluk, "),
454 		kbytes(((char *)sbrk(0)) - ((char *)track->brk_start)));
455 
456 #ifdef HAVE_GETRUSAGE
457 	getrusage(RUSAGE_SELF, &r);
458 
459 	log_out(ctx, _("time: %5.2f/%5.2f/%5.2f\n"),
460 		timeval_subtract(&time_end, &track->time_start),
461 		timeval_subtract(&r.ru_utime, &track->user_start),
462 		timeval_subtract(&r.ru_stime, &track->system_start));
463 #else
464 	log_out(ctx, _("elapsed time: %6.3f\n"),
465 		timeval_subtract(&time_end, &track->time_start));
466 #endif
467 #define mbytes(x)	(((x) + 1048575) / 1048576)
468 	if (channel && channel->manager && channel->manager->get_stats) {
469 		io_stats delta = 0;
470 		unsigned long long bytes_read = 0;
471 		unsigned long long bytes_written = 0;
472 
473 		if (desc)
474 			log_out(ctx, "%s: ", desc);
475 
476 		channel->manager->get_stats(channel, &delta);
477 		if (delta) {
478 			bytes_read = delta->bytes_read - track->bytes_read;
479 			bytes_written = delta->bytes_written -
480 				track->bytes_written;
481 		}
482 		log_out(ctx, "I/O read: %lluMB, write: %lluMB, "
483 			"rate: %.2fMB/s\n",
484 			mbytes(bytes_read), mbytes(bytes_written),
485 			(double)mbytes(bytes_read + bytes_written) /
486 			timeval_subtract(&time_end, &track->time_start));
487 	}
488 }
489 #endif /* RESOURCE_TRACK */
490 
e2fsck_read_inode(e2fsck_t ctx,unsigned long ino,struct ext2_inode * inode,const char * proc)491 void e2fsck_read_inode(e2fsck_t ctx, unsigned long ino,
492 			      struct ext2_inode * inode, const char *proc)
493 {
494 	errcode_t retval;
495 
496 	retval = ext2fs_read_inode(ctx->fs, ino, inode);
497 	if (retval) {
498 		com_err("ext2fs_read_inode", retval,
499 			_("while reading inode %lu in %s"), ino, proc);
500 		fatal_error(ctx, 0);
501 	}
502 }
503 
e2fsck_read_inode_full(e2fsck_t ctx,unsigned long ino,struct ext2_inode * inode,int bufsize,const char * proc)504 void e2fsck_read_inode_full(e2fsck_t ctx, unsigned long ino,
505 			    struct ext2_inode *inode, int bufsize,
506 			    const char *proc)
507 {
508 	errcode_t retval;
509 
510 	retval = ext2fs_read_inode_full(ctx->fs, ino, inode, bufsize);
511 	if (retval) {
512 		com_err("ext2fs_read_inode_full", retval,
513 			_("while reading inode %lu in %s"), ino, proc);
514 		fatal_error(ctx, 0);
515 	}
516 }
517 
e2fsck_write_inode_full(e2fsck_t ctx,unsigned long ino,struct ext2_inode * inode,int bufsize,const char * proc)518 void e2fsck_write_inode_full(e2fsck_t ctx, unsigned long ino,
519 			     struct ext2_inode * inode, int bufsize,
520 			     const char *proc)
521 {
522 	errcode_t retval;
523 
524 	retval = ext2fs_write_inode_full(ctx->fs, ino, inode, bufsize);
525 	if (retval) {
526 		com_err("ext2fs_write_inode", retval,
527 			_("while writing inode %lu in %s"), ino, proc);
528 		fatal_error(ctx, 0);
529 	}
530 }
531 
e2fsck_write_inode(e2fsck_t ctx,unsigned long ino,struct ext2_inode * inode,const char * proc)532 void e2fsck_write_inode(e2fsck_t ctx, unsigned long ino,
533 			struct ext2_inode * inode, const char *proc)
534 {
535 	errcode_t retval;
536 
537 	retval = ext2fs_write_inode(ctx->fs, ino, inode);
538 	if (retval) {
539 		com_err("ext2fs_write_inode", retval,
540 			_("while writing inode %lu in %s"), ino, proc);
541 		fatal_error(ctx, 0);
542 	}
543 }
544 
545 #ifdef MTRACE
mtrace_print(char * mesg)546 void mtrace_print(char *mesg)
547 {
548 	FILE	*malloc_get_mallstream();
549 	FILE	*f = malloc_get_mallstream();
550 
551 	if (f)
552 		fprintf(f, "============= %s\n", mesg);
553 }
554 #endif
555 
get_backup_sb(e2fsck_t ctx,ext2_filsys fs,const char * name,io_manager manager)556 blk64_t get_backup_sb(e2fsck_t ctx, ext2_filsys fs, const char *name,
557 		      io_manager manager)
558 {
559 	struct ext2_super_block *sb;
560 	io_channel		io = NULL;
561 	void			*buf = NULL;
562 	int			blocksize;
563 	blk64_t			superblock, ret_sb = 8193;
564 
565 	if (fs && fs->super) {
566 		ret_sb = (fs->super->s_blocks_per_group +
567 			  fs->super->s_first_data_block);
568 		if (ctx) {
569 			ctx->superblock = ret_sb;
570 			ctx->blocksize = fs->blocksize;
571 		}
572 		return ret_sb;
573 	}
574 
575 	if (ctx) {
576 		if (ctx->blocksize) {
577 			ret_sb = ctx->blocksize * 8;
578 			if (ctx->blocksize == 1024)
579 				ret_sb++;
580 			ctx->superblock = ret_sb;
581 			return ret_sb;
582 		}
583 		ctx->superblock = ret_sb;
584 		ctx->blocksize = 1024;
585 	}
586 
587 	if (!name || !manager)
588 		goto cleanup;
589 
590 	if (manager->open(name, 0, &io) != 0)
591 		goto cleanup;
592 
593 	if (ext2fs_get_mem(SUPERBLOCK_SIZE, &buf))
594 		goto cleanup;
595 	sb = (struct ext2_super_block *) buf;
596 
597 	for (blocksize = EXT2_MIN_BLOCK_SIZE;
598 	     blocksize <= EXT2_MAX_BLOCK_SIZE ; blocksize *= 2) {
599 		superblock = blocksize*8;
600 		if (blocksize == 1024)
601 			superblock++;
602 		io_channel_set_blksize(io, blocksize);
603 		if (io_channel_read_blk64(io, superblock,
604 					-SUPERBLOCK_SIZE, buf))
605 			continue;
606 #ifdef WORDS_BIGENDIAN
607 		if (sb->s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC))
608 			ext2fs_swap_super(sb);
609 #endif
610 		if ((sb->s_magic == EXT2_SUPER_MAGIC) &&
611 		    (EXT2_BLOCK_SIZE(sb) == blocksize)) {
612 			ret_sb = superblock;
613 			if (ctx) {
614 				ctx->superblock = superblock;
615 				ctx->blocksize = blocksize;
616 			}
617 			break;
618 		}
619 	}
620 
621 cleanup:
622 	if (io)
623 		io_channel_close(io);
624 	if (buf)
625 		ext2fs_free_mem(&buf);
626 	return (ret_sb);
627 }
628 
629 /*
630  * Given a mode, return the ext2 file type
631  */
ext2_file_type(unsigned int mode)632 int ext2_file_type(unsigned int mode)
633 {
634 	if (LINUX_S_ISREG(mode))
635 		return EXT2_FT_REG_FILE;
636 
637 	if (LINUX_S_ISDIR(mode))
638 		return EXT2_FT_DIR;
639 
640 	if (LINUX_S_ISCHR(mode))
641 		return EXT2_FT_CHRDEV;
642 
643 	if (LINUX_S_ISBLK(mode))
644 		return EXT2_FT_BLKDEV;
645 
646 	if (LINUX_S_ISLNK(mode))
647 		return EXT2_FT_SYMLINK;
648 
649 	if (LINUX_S_ISFIFO(mode))
650 		return EXT2_FT_FIFO;
651 
652 	if (LINUX_S_ISSOCK(mode))
653 		return EXT2_FT_SOCK;
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  */
fs_proc_check(const char * fs_name)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  */
check_for_modules(const char * fs_name)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 EAGAIN/EINTR error.
744  */
write_all(int fd,char * buf,size_t count)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 
dump_mmp_msg(struct mmp_struct * mmp,const char * fmt,...)764 void dump_mmp_msg(struct mmp_struct *mmp, const char *fmt, ...)
765 {
766 	va_list pvar;
767 
768 	if (fmt) {
769 		printf("MMP check failed: ");
770 		va_start(pvar, fmt);
771 		vprintf(fmt, pvar);
772 		va_end(pvar);
773 	}
774 	if (mmp) {
775 		time_t t = mmp->mmp_time;
776 
777 		printf("MMP_block:\n");
778 		printf("    mmp_magic: 0x%x\n", mmp->mmp_magic);
779 		printf("    mmp_check_interval: %d\n",
780 		       mmp->mmp_check_interval);
781 		printf("    mmp_sequence: %08x\n", mmp->mmp_seq);
782 		printf("    mmp_update_date: %s", ctime(&t));
783 		printf("    mmp_update_time: %lld\n",
784 		       (long long) mmp->mmp_time);
785 		printf("    mmp_node_name: %.*s\n",
786 		       EXT2_LEN_STR(mmp->mmp_nodename));
787 		printf("    mmp_device_name: %.*s\n",
788 		       EXT2_LEN_STR(mmp->mmp_bdevname));
789 	}
790 }
791 
e2fsck_mmp_update(ext2_filsys fs)792 errcode_t e2fsck_mmp_update(ext2_filsys fs)
793 {
794 	errcode_t retval;
795 
796 	retval = ext2fs_mmp_update(fs);
797 	if (retval == EXT2_ET_MMP_CHANGE_ABORT)
798 		dump_mmp_msg(fs->mmp_cmp,
799 			     _("UNEXPECTED INCONSISTENCY: the filesystem is "
800 			       "being modified while fsck is running.\n"));
801 
802 	return retval;
803 }
804 
e2fsck_set_bitmap_type(ext2_filsys fs,unsigned int default_type,const char * profile_name,unsigned int * old_type)805 void e2fsck_set_bitmap_type(ext2_filsys fs, unsigned int default_type,
806 			    const char *profile_name, unsigned int *old_type)
807 {
808 	unsigned type;
809 	e2fsck_t ctx = (e2fsck_t) fs->priv_data;
810 
811 	if (old_type)
812 		*old_type = fs->default_bitmap_type;
813 	profile_get_uint(ctx->profile, "bitmaps", profile_name, 0,
814 			 default_type, &type);
815 	profile_get_uint(ctx->profile, "bitmaps", "all", 0, type, &type);
816 	fs->default_bitmap_type = type ? type : default_type;
817 }
818 
e2fsck_allocate_inode_bitmap(ext2_filsys fs,const char * descr,int deftype,const char * name,ext2fs_inode_bitmap * ret)819 errcode_t e2fsck_allocate_inode_bitmap(ext2_filsys fs, const char *descr,
820 				       int deftype,
821 				       const char *name,
822 				       ext2fs_inode_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_inode_bitmap(fs, descr, ret);
829 	fs->default_bitmap_type = save_type;
830 	return retval;
831 }
832 
e2fsck_allocate_block_bitmap(ext2_filsys fs,const char * descr,int deftype,const char * name,ext2fs_block_bitmap * ret)833 errcode_t e2fsck_allocate_block_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_block_bitmap(fs, descr, ret);
843 	fs->default_bitmap_type = save_type;
844 	return retval;
845 }
846 
e2fsck_allocate_subcluster_bitmap(ext2_filsys fs,const char * descr,int deftype,const char * name,ext2fs_block_bitmap * ret)847 errcode_t e2fsck_allocate_subcluster_bitmap(ext2_filsys fs, const char *descr,
848 					    int deftype,
849 					    const char *name,
850 					    ext2fs_block_bitmap *ret)
851 {
852 	errcode_t	retval;
853 	unsigned int	save_type;
854 
855 	e2fsck_set_bitmap_type(fs, deftype, name, &save_type);
856 	retval = ext2fs_allocate_subcluster_bitmap(fs, descr, ret);
857 	fs->default_bitmap_type = save_type;
858 	return retval;
859 }
860 
861 /* Return memory size in bytes */
get_memory_size(void)862 unsigned long long get_memory_size(void)
863 {
864 #if defined(_SC_PHYS_PAGES)
865 # if defined(_SC_PAGESIZE)
866 	return (unsigned long long)sysconf(_SC_PHYS_PAGES) *
867 	       (unsigned long long)sysconf(_SC_PAGESIZE);
868 # elif defined(_SC_PAGE_SIZE)
869 	return (unsigned long long)sysconf(_SC_PHYS_PAGES) *
870 	       (unsigned long long)sysconf(_SC_PAGE_SIZE);
871 # endif
872 #elif defined(CTL_HW)
873 # if (defined(HW_MEMSIZE) || defined(HW_PHYSMEM64))
874 #  define CTL_HW_INT64
875 # elif (defined(HW_PHYSMEM) || defined(HW_REALMEM))
876 #  define CTL_HW_UINT
877 # endif
878 	int mib[2];
879 
880 	mib[0] = CTL_HW;
881 # if defined(HW_MEMSIZE)
882 	mib[1] = HW_MEMSIZE;
883 # elif defined(HW_PHYSMEM64)
884 	mib[1] = HW_PHYSMEM64;
885 # elif defined(HW_REALMEM)
886 	mib[1] = HW_REALMEM;
887 # elif defined(HW_PYSMEM)
888 	mib[1] = HW_PHYSMEM;
889 # endif
890 # if defined(CTL_HW_INT64)
891 	unsigned long long size = 0;
892 # elif defined(CTL_HW_UINT)
893 	unsigned int size = 0;
894 # endif
895 	return 0;
896 #else
897 # warning "Don't know how to detect memory on your platform?"
898 	return 0;
899 #endif
900 }
901