]> git.ipfire.org Git - thirdparty/e2fsprogs.git/blame - e2fsck/util.c
e2fsck: if user declines to fix s_inodes_acount, abort
[thirdparty/e2fsprogs.git] / e2fsck / util.c
CommitLineData
3839e657
TT
1/*
2 * util.c --- miscellaneous utilities
efc6f628 3 *
21c84b71
TT
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%
3839e657
TT
10 */
11
d1154eb4 12#include "config.h"
3839e657 13#include <stdlib.h>
80875db5 14#include <stdio.h>
3839e657
TT
15#include <unistd.h>
16#include <string.h>
17#include <ctype.h>
80875db5
TT
18#ifdef __linux__
19#include <sys/utsname.h>
20#endif
9ecd8bec
TT
21
22#ifdef HAVE_CONIO_H
23#undef HAVE_TERMIOS_H
24#include <conio.h>
e6597048 25#define read_a_char() getch()
9ecd8bec
TT
26#else
27#ifdef HAVE_TERMIOS_H
3839e657 28#include <termios.h>
9ecd8bec
TT
29#endif
30#endif
31
4a9f5936
TT
32#ifdef HAVE_MALLOC_H
33#include <malloc.h>
34#endif
3839e657 35
49a7360b
JS
36#ifdef HAVE_ERRNO_H
37#include <errno.h>
38#endif
39
79614b27
DW
40#ifdef HAVE_SYS_SYSCTL_H
41#include <sys/sysctl.h>
42#endif
43
3839e657
TT
44#include "e2fsck.h"
45
aa75eccc 46extern e2fsck_t e2fsck_global_ctx; /* Try your very best not to use this! */
542867fb 47
b0e91c89 48#include <stdarg.h>
0f5eba75 49#include <time.h>
50e1e10f
TT
50#include <sys/time.h>
51#include <sys/resource.h>
52
f8188fff 53void fatal_error(e2fsck_t ctx, const char *msg)
3839e657 54{
13dcce8b
ES
55 ext2_filsys fs = ctx->fs;
56 int exit_value = FSCK_ERROR;
57
efc6f628 58 if (msg)
1b6bf175 59 fprintf (stderr, "e2fsck: %s\n", msg);
13dcce8b
ES
60 if (!fs)
61 goto out;
7ff040f3 62 if (fs->io && fs->super) {
0f5eba75 63 ext2fs_mmp_stop(ctx->fs);
e39ac922 64 if (ctx->fs->io->magic == EXT2_ET_MAGIC_IO_CHANNEL)
58a75177
TT
65 io_channel_flush(ctx->fs->io);
66 else
b0e91c89 67 log_err(ctx, "e2fsck: io manager magic bad!\n");
58a75177 68 }
13dcce8b
ES
69 if (ext2fs_test_changed(fs)) {
70 exit_value |= FSCK_NONDESTRUCT;
b0e91c89 71 log_out(ctx, _("\n%s: ***** FILE SYSTEM WAS MODIFIED *****\n"),
13dcce8b
ES
72 ctx->device_name);
73 if (ctx->mount_flags & EXT2_MF_ISROOT)
74 exit_value |= FSCK_REBOOT;
75 }
76 if (!ext2fs_test_valid(fs)) {
b0e91c89
TT
77 log_out(ctx, _("\n%s: ********** WARNING: Filesystem still has "
78 "errors **********\n\n"), ctx->device_name);
13dcce8b
ES
79 exit_value |= FSCK_UNCORRECTED;
80 exit_value &= ~FSCK_NONDESTRUCT;
81 }
82out:
f8188fff
TT
83 ctx->flags |= E2F_FLAG_ABORT;
84 if (ctx->flags & E2F_FLAG_SETJMP_OK)
85 longjmp(ctx->abort_loc, 1);
7a2a0145
TT
86 if (ctx->logf)
87 fprintf(ctx->logf, "Exit status: %d\n", exit_value);
13dcce8b 88 exit(exit_value);
3839e657
TT
89}
90
b0e91c89
TT
91void log_out(e2fsck_t ctx, const char *fmt, ...)
92{
93 va_list pvar;
94
95 va_start(pvar, fmt);
96 vprintf(fmt, pvar);
97 va_end(pvar);
98 if (ctx->logf) {
99 va_start(pvar, fmt);
100 vfprintf(ctx->logf, fmt, pvar);
101 va_end(pvar);
102 }
103}
104
105void log_err(e2fsck_t ctx, const char *fmt, ...)
106{
107 va_list pvar;
108
109 va_start(pvar, fmt);
110 vfprintf(stderr, fmt, pvar);
111 va_end(pvar);
112 if (ctx->logf) {
113 va_start(pvar, fmt);
114 vfprintf(ctx->logf, fmt, pvar);
115 va_end(pvar);
116 }
117}
118
f8188fff
TT
119void *e2fsck_allocate_memory(e2fsck_t ctx, unsigned int size,
120 const char *description)
3839e657
TT
121{
122 void *ret;
123 char buf[256];
124
125#ifdef DEBUG_ALLOCATE_MEMORY
611378fe 126 printf("Allocating %u bytes for %s...\n", size, description);
3839e657
TT
127#endif
128 ret = malloc(size);
129 if (!ret) {
bf50beb9
ES
130 sprintf(buf, "Can't allocate %u bytes for %s\n",
131 size, description);
f8188fff 132 fatal_error(ctx, buf);
3839e657
TT
133 }
134 memset(ret, 0, size);
135 return ret;
136}
137
efc6f628 138char *string_copy(e2fsck_t ctx EXT2FS_ATTR((unused)),
54434927 139 const char *str, int len)
f364093b
TT
140{
141 char *ret;
efc6f628 142
f364093b
TT
143 if (!str)
144 return NULL;
145 if (!len)
146 len = strlen(str);
147 ret = malloc(len+1);
148 if (ret) {
149 strncpy(ret, str, len);
150 ret[len] = 0;
151 }
152 return ret;
153}
154
155#ifndef HAVE_STRNLEN
156/*
157 * Incredibly, libc5 doesn't appear to have strnlen. So we have to
158 * provide our own.
159 */
160int e2fsck_strnlen(const char * s, int count)
161{
162 const char *cp = s;
163
164 while (count-- && *cp)
165 cp++;
166 return cp - s;
167}
168#endif
169
542867fb 170#ifndef HAVE_CONIO_H
3e699064 171static int read_a_char(void)
542867fb
TT
172{
173 char c;
174 int r;
175 int fail = 0;
176
177 while(1) {
178 if (e2fsck_global_ctx &&
179 (e2fsck_global_ctx->flags & E2F_FLAG_CANCEL)) {
180 return 3;
181 }
182 r = read(0, &c, 1);
183 if (r == 1)
184 return c;
185 if (fail++ > 100)
186 break;
187 }
188 return EOF;
189}
190#endif
191
b0e91c89 192int ask_yn(e2fsck_t ctx, const char * string, int def)
3839e657
TT
193{
194 int c;
3839e657 195 const char *defstr;
53ef44c4
TT
196 const char *short_yes = _("yY");
197 const char *short_no = _("nN");
aeb933b3 198 const char *short_yesall = _("aA");
9f8a1826
TT
199 const char *english_yes = "yY";
200 const char *english_no = "nN";
201 const char *english_yesall = "aA";
aeb933b3
DW
202 const char *yesall_prompt = _(" ('a' enables 'yes' to all) ");
203 const char *extra_prompt = "";
204 static int yes_answers;
3839e657 205
9ecd8bec 206#ifdef HAVE_TERMIOS_H
ac3256fd 207 struct termios termios, tmp;
9ecd8bec 208
ac3256fd
TT
209 if (tcgetattr (0, &termios) < 0)
210 memset(&termios, 0, sizeof(termios));
3839e657
TT
211 tmp = termios;
212 tmp.c_lflag &= ~(ICANON | ECHO);
50e1e10f
TT
213 tmp.c_cc[VMIN] = 1;
214 tmp.c_cc[VTIME] = 0;
3839e657 215 tcsetattr (0, TCSANOW, &tmp);
9ecd8bec 216#endif
3839e657
TT
217
218 if (def == 1)
542867fb 219 defstr = _(_("<y>"));
3839e657 220 else if (def == 0)
542867fb 221 defstr = _(_("<n>"));
3839e657 222 else
0c4a0726 223 defstr = _(" (y/n)");
aeb933b3
DW
224 /*
225 * If the user presses 'y' more than 8 (but less than 12) times in
226 * succession without pressing anything else, display a hint about
227 * yes-to-all mode.
228 */
229 if (yes_answers > 12)
230 yes_answers = -1;
231 else if (yes_answers > 8)
232 extra_prompt = yesall_prompt;
233 log_out(ctx, "%s%s%s? ", string, extra_prompt, defstr);
3839e657
TT
234 while (1) {
235 fflush (stdout);
e6597048 236 if ((c = read_a_char()) == EOF)
3839e657 237 break;
542867fb
TT
238 if (c == 3) {
239#ifdef HAVE_TERMIOS_H
240 tcsetattr (0, TCSANOW, &termios);
241#endif
b0e91c89
TT
242 if (ctx->flags & E2F_FLAG_SETJMP_OK) {
243 log_out(ctx, "\n");
542867fb
TT
244 longjmp(e2fsck_global_ctx->abort_loc, 1);
245 }
45ff69ff 246 log_out(ctx, "%s", _("cancelled!\n"));
aeb933b3 247 yes_answers = 0;
542867fb
TT
248 return 0;
249 }
0c4a0726 250 if (strchr(short_yes, (char) c)) {
9f8a1826 251 do_yes:
3839e657 252 def = 1;
aeb933b3
DW
253 if (yes_answers >= 0)
254 yes_answers++;
3839e657 255 break;
aeb933b3 256 } else if (strchr(short_no, (char) c)) {
9f8a1826 257 do_no:
3839e657 258 def = 0;
aeb933b3 259 yes_answers = -1;
3839e657 260 break;
aeb933b3 261 } else if (strchr(short_yesall, (char)c)) {
9f8a1826 262 do_all:
aeb933b3
DW
263 def = 2;
264 yes_answers = -1;
265 ctx->options |= E2F_OPT_YES;
3839e657 266 break;
9f8a1826
TT
267 } else if (strchr(english_yes, (char) c)) {
268 goto do_yes;
269 } else if (strchr(english_no, (char) c)) {
270 goto do_no;
271 } else if (strchr(english_yesall, (char) c)) {
272 goto do_all;
aeb933b3
DW
273 } else if ((c == 27 || c == ' ' || c == '\n') && (def != -1)) {
274 yes_answers = -1;
275 break;
276 }
3839e657 277 }
aeb933b3
DW
278 if (def == 2)
279 log_out(ctx, "%s", _("yes to all\n"));
280 else if (def)
45ff69ff 281 log_out(ctx, "%s", _("yes\n"));
3839e657 282 else
45ff69ff 283 log_out(ctx, "%s", _("no\n"));
9ecd8bec 284#ifdef HAVE_TERMIOS_H
3839e657 285 tcsetattr (0, TCSANOW, &termios);
9ecd8bec 286#endif
3839e657
TT
287 return def;
288}
289
1b6bf175 290int ask (e2fsck_t ctx, const char * string, int def)
3839e657 291{
1b6bf175 292 if (ctx->options & E2F_OPT_NO) {
b0e91c89 293 log_out(ctx, _("%s? no\n\n"), string);
3839e657
TT
294 return 0;
295 }
1b6bf175 296 if (ctx->options & E2F_OPT_YES) {
b0e91c89 297 log_out(ctx, _("%s? yes\n\n"), string);
3839e657
TT
298 return 1;
299 }
1b6bf175 300 if (ctx->options & E2F_OPT_PREEN) {
b0e91c89 301 log_out(ctx, "%s? %s\n\n", string, def ? _("yes") : _("no"));
3839e657
TT
302 return def;
303 }
b0e91c89 304 return ask_yn(ctx, string, def);
3839e657
TT
305}
306
f8188fff 307void e2fsck_read_bitmaps(e2fsck_t ctx)
3839e657 308{
1b6bf175 309 ext2_filsys fs = ctx->fs;
3839e657 310 errcode_t retval;
e94bc631 311 const char *old_op;
830b44f4 312 unsigned int save_type;
2e9d8391 313 int flags;
3839e657 314
1b6bf175
TT
315 if (ctx->invalid_bitmaps) {
316 com_err(ctx->program_name, 0,
0c4a0726 317 _("e2fsck_read_bitmaps: illegal bitmap block(s) for %s"),
1b6bf175 318 ctx->device_name);
f8188fff 319 fatal_error(ctx, 0);
3839e657 320 }
f3db3566 321
e94bc631 322 old_op = ehandler_operation(_("reading inode and block bitmaps"));
830b44f4
TT
323 e2fsck_set_bitmap_type(fs, EXT2FS_BMAP64_RBTREE, "fs_bitmaps",
324 &save_type);
2e9d8391 325 flags = ctx->fs->flags;
d1b9d835 326 ctx->fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
f3db3566 327 retval = ext2fs_read_bitmaps(fs);
2e9d8391
DW
328 ctx->fs->flags = (flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) |
329 (ctx->fs->flags & ~EXT2_FLAG_IGNORE_CSUM_ERRORS);
830b44f4 330 fs->default_bitmap_type = save_type;
e94bc631 331 ehandler_operation(old_op);
f3db3566 332 if (retval) {
1b6bf175 333 com_err(ctx->program_name, retval,
0c4a0726 334 _("while retrying to read bitmaps for %s"),
1b6bf175 335 ctx->device_name);
f8188fff 336 fatal_error(ctx, 0);
3839e657
TT
337 }
338}
339
f8188fff 340void e2fsck_write_bitmaps(e2fsck_t ctx)
3839e657 341{
1b6bf175 342 ext2_filsys fs = ctx->fs;
3839e657 343 errcode_t retval;
e94bc631 344 const char *old_op;
3839e657 345
1bb6f6c8
AD
346 old_op = ehandler_operation(_("writing block and inode bitmaps"));
347 retval = ext2fs_write_bitmaps(fs);
348 ehandler_operation(old_op);
349 if (retval) {
350 com_err(ctx->program_name, retval,
351 _("while rewriting block and inode bitmaps for %s"),
352 ctx->device_name);
353 fatal_error(ctx, 0);
3839e657
TT
354 }
355}
356
1b6bf175 357void preenhalt(e2fsck_t ctx)
3839e657 358{
1b6bf175
TT
359 ext2_filsys fs = ctx->fs;
360
361 if (!(ctx->options & E2F_OPT_PREEN))
3839e657 362 return;
b0e91c89 363 log_err(ctx, _("\n\n%s: UNEXPECTED INCONSISTENCY; "
0c4a0726 364 "RUN fsck MANUALLY.\n\t(i.e., without -a or -p options)\n"),
1b6bf175 365 ctx->device_name);
79cc3362 366 ctx->flags |= E2F_FLAG_EXITING;
50e1e10f
TT
367 if (fs != NULL) {
368 fs->super->s_state |= EXT2_ERROR_FS;
369 ext2fs_mark_super_dirty(fs);
47fee2ef 370 ext2fs_close_free(&fs);
50e1e10f 371 }
3839e657
TT
372 exit(FSCK_UNCORRECTED);
373}
374
8bf191e8 375#ifdef RESOURCE_TRACK
6d96b00d 376void init_resource_track(struct resource_track *track, io_channel channel)
3839e657 377{
50e1e10f 378#ifdef HAVE_GETRUSAGE
3839e657 379 struct rusage r;
50e1e10f 380#endif
6d96b00d 381 io_stats io_start = 0;
efc6f628 382
3839e657
TT
383 track->brk_start = sbrk(0);
384 gettimeofday(&track->time_start, 0);
50e1e10f 385#ifdef HAVE_GETRUSAGE
53ef44c4
TT
386#ifdef sun
387 memset(&r, 0, sizeof(struct rusage));
1b6bf175 388#endif
3839e657
TT
389 getrusage(RUSAGE_SELF, &r);
390 track->user_start = r.ru_utime;
391 track->system_start = r.ru_stime;
50e1e10f
TT
392#else
393 track->user_start.tv_sec = track->user_start.tv_usec = 0;
394 track->system_start.tv_sec = track->system_start.tv_usec = 0;
395#endif
6d96b00d
TT
396 track->bytes_read = 0;
397 track->bytes_written = 0;
398 if (channel && channel->manager && channel->manager->get_stats)
399 channel->manager->get_stats(channel, &io_start);
400 if (io_start) {
401 track->bytes_read = io_start->bytes_read;
402 track->bytes_written = io_start->bytes_written;
403 }
3839e657
TT
404}
405
21c84b71
TT
406#ifdef __GNUC__
407#define _INLINE_ __inline__
408#else
409#define _INLINE_
410#endif
411
412static _INLINE_ float timeval_subtract(struct timeval *tv1,
413 struct timeval *tv2)
3839e657
TT
414{
415 return ((tv1->tv_sec - tv2->tv_sec) +
416 ((float) (tv1->tv_usec - tv2->tv_usec)) / 1000000);
417}
418
9facd076
KC
419void print_resource_track(e2fsck_t ctx, const char *desc,
420 struct resource_track *track, io_channel channel)
3839e657 421{
50e1e10f 422#ifdef HAVE_GETRUSAGE
3839e657 423 struct rusage r;
4a9f5936
TT
424#endif
425#ifdef HAVE_MALLINFO
426 struct mallinfo malloc_info;
50e1e10f 427#endif
3839e657
TT
428 struct timeval time_end;
429
9facd076
KC
430 if ((desc && !(ctx->options & E2F_OPT_TIME2)) ||
431 (!desc && !(ctx->options & E2F_OPT_TIME)))
432 return;
433
434 e2fsck_clear_progbar(ctx);
3839e657 435 gettimeofday(&time_end, 0);
1b6bf175
TT
436
437 if (desc)
b0e91c89 438 log_out(ctx, "%s: ", desc);
4a9f5936
TT
439
440#ifdef HAVE_MALLINFO
70eabde9 441#define kbytes(x) (((unsigned long)(x) + 1023) / 1024)
efc6f628 442
4a9f5936 443 malloc_info = mallinfo();
b0e91c89
TT
444 log_out(ctx, _("Memory used: %luk/%luk (%luk/%luk), "),
445 kbytes(malloc_info.arena), kbytes(malloc_info.hblkhd),
446 kbytes(malloc_info.uordblks), kbytes(malloc_info.fordblks));
4a9f5936 447#else
b0e91c89
TT
448 log_out(ctx, _("Memory used: %lu, "),
449 (unsigned long) (((char *) sbrk(0)) -
450 ((char *) track->brk_start)));
efc6f628 451#endif
50e1e10f 452#ifdef HAVE_GETRUSAGE
3839e657
TT
453 getrusage(RUSAGE_SELF, &r);
454
b0e91c89
TT
455 log_out(ctx, _("time: %5.2f/%5.2f/%5.2f\n"),
456 timeval_subtract(&time_end, &track->time_start),
457 timeval_subtract(&r.ru_utime, &track->user_start),
458 timeval_subtract(&r.ru_stime, &track->system_start));
50e1e10f 459#else
b0e91c89
TT
460 log_out(ctx, _("elapsed time: %6.3f\n"),
461 timeval_subtract(&time_end, &track->time_start));
50e1e10f 462#endif
6d96b00d
TT
463#define mbytes(x) (((x) + 1048575) / 1048576)
464 if (channel && channel->manager && channel->manager->get_stats) {
465 io_stats delta = 0;
466 unsigned long long bytes_read = 0;
467 unsigned long long bytes_written = 0;
468
469 if (desc)
b0e91c89 470 log_out(ctx, "%s: ", desc);
6d96b00d
TT
471
472 channel->manager->get_stats(channel, &delta);
473 if (delta) {
474 bytes_read = delta->bytes_read - track->bytes_read;
efc6f628 475 bytes_written = delta->bytes_written -
6d96b00d
TT
476 track->bytes_written;
477 }
b0e91c89
TT
478 log_out(ctx, "I/O read: %lluMB, write: %lluMB, "
479 "rate: %.2fMB/s\n",
480 mbytes(bytes_read), mbytes(bytes_written),
481 (double)mbytes(bytes_read + bytes_written) /
482 timeval_subtract(&time_end, &track->time_start));
6d96b00d 483 }
3839e657 484}
8bf191e8 485#endif /* RESOURCE_TRACK */
3839e657 486
08b21301 487void e2fsck_read_inode(e2fsck_t ctx, unsigned long ino,
f3db3566
TT
488 struct ext2_inode * inode, const char *proc)
489{
974d57d3 490 errcode_t retval;
f3db3566 491
08b21301 492 retval = ext2fs_read_inode(ctx->fs, ino, inode);
f3db3566
TT
493 if (retval) {
494 com_err("ext2fs_read_inode", retval,
611378fe 495 _("while reading inode %lu in %s"), ino, proc);
f8188fff 496 fatal_error(ctx, 0);
f3db3566
TT
497 }
498}
499
fefaef39
AD
500void e2fsck_read_inode_full(e2fsck_t ctx, unsigned long ino,
501 struct ext2_inode *inode, int bufsize,
502 const char *proc)
503{
974d57d3 504 errcode_t retval;
fefaef39
AD
505
506 retval = ext2fs_read_inode_full(ctx->fs, ino, inode, bufsize);
507 if (retval) {
508 com_err("ext2fs_read_inode_full", retval,
611378fe 509 _("while reading inode %lu in %s"), ino, proc);
fefaef39
AD
510 fatal_error(ctx, 0);
511 }
512}
513
f404167d
TT
514void e2fsck_write_inode_full(e2fsck_t ctx, unsigned long ino,
515 struct ext2_inode * inode, int bufsize,
516 const char *proc)
cebe48a1 517{
974d57d3 518 errcode_t retval;
cebe48a1
TT
519
520 retval = ext2fs_write_inode_full(ctx->fs, ino, inode, bufsize);
521 if (retval) {
522 com_err("ext2fs_write_inode", retval,
611378fe 523 _("while writing inode %lu in %s"), ino, proc);
cebe48a1
TT
524 fatal_error(ctx, 0);
525 }
526}
527
f404167d
TT
528void e2fsck_write_inode(e2fsck_t ctx, unsigned long ino,
529 struct ext2_inode * inode, const char *proc)
f3db3566 530{
974d57d3 531 errcode_t retval;
f3db3566 532
08b21301 533 retval = ext2fs_write_inode(ctx->fs, ino, inode);
f3db3566
TT
534 if (retval) {
535 com_err("ext2fs_write_inode", retval,
611378fe 536 _("while writing inode %lu in %s"), ino, proc);
f8188fff 537 fatal_error(ctx, 0);
f3db3566
TT
538 }
539}
540
3839e657
TT
541#ifdef MTRACE
542void mtrace_print(char *mesg)
543{
544 FILE *malloc_get_mallstream();
545 FILE *f = malloc_get_mallstream();
546
547 if (f)
548 fprintf(f, "============= %s\n", mesg);
549}
550#endif
551
4dbfd79d
DW
552blk64_t get_backup_sb(e2fsck_t ctx, ext2_filsys fs, const char *name,
553 io_manager manager)
1b6bf175 554{
f1a1761d
TT
555 struct ext2_super_block *sb;
556 io_channel io = NULL;
fae9bfaa 557 void *buf = NULL;
f1a1761d 558 int blocksize;
4dbfd79d 559 blk64_t superblock, ret_sb = 8193;
efc6f628 560
f1a1761d
TT
561 if (fs && fs->super) {
562 ret_sb = (fs->super->s_blocks_per_group +
563 fs->super->s_first_data_block);
564 if (ctx) {
565 ctx->superblock = ret_sb;
566 ctx->blocksize = fs->blocksize;
567 }
568 return ret_sb;
569 }
efc6f628 570
f1a1761d
TT
571 if (ctx) {
572 if (ctx->blocksize) {
573 ret_sb = ctx->blocksize * 8;
574 if (ctx->blocksize == 1024)
575 ret_sb++;
576 ctx->superblock = ret_sb;
577 return ret_sb;
578 }
579 ctx->superblock = ret_sb;
580 ctx->blocksize = 1024;
581 }
582
583 if (!name || !manager)
584 goto cleanup;
585
586 if (manager->open(name, 0, &io) != 0)
587 goto cleanup;
588
589 if (ext2fs_get_mem(SUPERBLOCK_SIZE, &buf))
590 goto cleanup;
591 sb = (struct ext2_super_block *) buf;
592
932a489c
AD
593 for (blocksize = EXT2_MIN_BLOCK_SIZE;
594 blocksize <= EXT2_MAX_BLOCK_SIZE ; blocksize *= 2) {
f1a1761d
TT
595 superblock = blocksize*8;
596 if (blocksize == 1024)
597 superblock++;
598 io_channel_set_blksize(io, blocksize);
24a117ab 599 if (io_channel_read_blk64(io, superblock,
f1a1761d
TT
600 -SUPERBLOCK_SIZE, buf))
601 continue;
2eae0930 602#ifdef WORDS_BIGENDIAN
f1a1761d
TT
603 if (sb->s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC))
604 ext2fs_swap_super(sb);
605#endif
e7b5d3c0
DD
606 if ((sb->s_magic == EXT2_SUPER_MAGIC) &&
607 (EXT2_BLOCK_SIZE(sb) == blocksize)) {
557ddb2f
TT
608 ret_sb = superblock;
609 if (ctx) {
610 ctx->superblock = superblock;
611 ctx->blocksize = blocksize;
612 }
f1a1761d
TT
613 break;
614 }
615 }
616
617cleanup:
618 if (io)
619 io_channel_close(io);
620 if (buf)
621 ext2fs_free_mem(&buf);
622 return (ret_sb);
1b6bf175 623}
3839e657 624
6fdc7a32
TT
625/*
626 * Given a mode, return the ext2 file type
627 */
628int ext2_file_type(unsigned int mode)
629{
630 if (LINUX_S_ISREG(mode))
631 return EXT2_FT_REG_FILE;
632
633 if (LINUX_S_ISDIR(mode))
634 return EXT2_FT_DIR;
efc6f628 635
6fdc7a32
TT
636 if (LINUX_S_ISCHR(mode))
637 return EXT2_FT_CHRDEV;
efc6f628 638
6fdc7a32
TT
639 if (LINUX_S_ISBLK(mode))
640 return EXT2_FT_BLKDEV;
efc6f628 641
6fdc7a32
TT
642 if (LINUX_S_ISLNK(mode))
643 return EXT2_FT_SYMLINK;
644
645 if (LINUX_S_ISFIFO(mode))
646 return EXT2_FT_FIFO;
efc6f628 647
6fdc7a32
TT
648 if (LINUX_S_ISSOCK(mode))
649 return EXT2_FT_SOCK;
efc6f628 650
6fdc7a32
TT
651 return 0;
652}
49a7360b 653
80875db5
TT
654/*
655 * Check to see if a filesystem is in /proc/filesystems.
656 * Returns 1 if found, 0 if not
657 */
658int fs_proc_check(const char *fs_name)
659{
660 FILE *f;
661 char buf[80], *cp, *t;
662
663 f = fopen("/proc/filesystems", "r");
664 if (!f)
665 return (0);
666 while (!feof(f)) {
667 if (!fgets(buf, sizeof(buf), f))
668 break;
669 cp = buf;
670 if (!isspace(*cp)) {
671 while (*cp && !isspace(*cp))
672 cp++;
673 }
674 while (*cp && isspace(*cp))
675 cp++;
676 if ((t = strchr(cp, '\n')) != NULL)
677 *t = 0;
678 if ((t = strchr(cp, '\t')) != NULL)
679 *t = 0;
680 if ((t = strchr(cp, ' ')) != NULL)
681 *t = 0;
682 if (!strcmp(fs_name, cp)) {
683 fclose(f);
684 return (1);
685 }
686 }
687 fclose(f);
688 return (0);
689}
690
691/*
692 * Check to see if a filesystem is available as a module
693 * Returns 1 if found, 0 if not
694 */
695int check_for_modules(const char *fs_name)
696{
697#ifdef __linux__
698 struct utsname uts;
699 FILE *f;
700 char buf[1024], *cp, *t;
701 int i;
702
703 if (uname(&uts))
704 return (0);
705 snprintf(buf, sizeof(buf), "/lib/modules/%s/modules.dep", uts.release);
706
707 f = fopen(buf, "r");
708 if (!f)
709 return (0);
710 while (!feof(f)) {
711 if (!fgets(buf, sizeof(buf), f))
712 break;
713 if ((cp = strchr(buf, ':')) != NULL)
714 *cp = 0;
715 else
716 continue;
717 if ((cp = strrchr(buf, '/')) != NULL)
718 cp++;
f2fe5da3
ES
719 else
720 cp = buf;
80875db5
TT
721 i = strlen(cp);
722 if (i > 3) {
723 t = cp + i - 3;
724 if (!strcmp(t, ".ko"))
725 *t = 0;
726 }
727 if (!strcmp(cp, fs_name)) {
728 fclose(f);
729 return (1);
730 }
731 }
732 fclose(f);
733#endif /* __linux__ */
734 return (0);
735}
b0258cbc
TT
736
737/*
738 * Helper function that does the right thing if write returns a
055866d8 739 * partial write, or an EAGAIN/EINTR error.
b0258cbc
TT
740 */
741int write_all(int fd, char *buf, size_t count)
742{
743 ssize_t ret;
744 int c = 0;
745
746 while (count > 0) {
747 ret = write(fd, buf, count);
748 if (ret < 0) {
749 if ((errno == EAGAIN) || (errno == EINTR))
750 continue;
751 return -1;
752 }
753 count -= ret;
754 buf += ret;
755 c += ret;
756 }
757 return c;
758}
0f5eba75 759
32b8802a 760void dump_mmp_msg(struct mmp_struct *mmp, const char *fmt, ...)
0f5eba75 761{
32b8802a 762 va_list pvar;
0f5eba75 763
32b8802a
SI
764 if (fmt) {
765 printf("MMP check failed: ");
766 va_start(pvar, fmt);
767 vprintf(fmt, pvar);
768 va_end(pvar);
769 }
0f5eba75
AD
770 if (mmp) {
771 time_t t = mmp->mmp_time;
772
32b8802a
SI
773 printf("MMP_block:\n");
774 printf(" mmp_magic: 0x%x\n", mmp->mmp_magic);
775 printf(" mmp_check_interval: %d\n",
776 mmp->mmp_check_interval);
777 printf(" mmp_sequence: %08x\n", mmp->mmp_seq);
778 printf(" mmp_update_date: %s", ctime(&t));
779 printf(" mmp_update_time: %lld\n", mmp->mmp_time);
780 printf(" mmp_node_name: %s\n", mmp->mmp_nodename);
781 printf(" mmp_device_name: %s\n", mmp->mmp_bdevname);
0f5eba75
AD
782 }
783}
784
785errcode_t e2fsck_mmp_update(ext2_filsys fs)
786{
787 errcode_t retval;
788
789 retval = ext2fs_mmp_update(fs);
790 if (retval == EXT2_ET_MMP_CHANGE_ABORT)
791 dump_mmp_msg(fs->mmp_cmp,
792 _("UNEXPECTED INCONSISTENCY: the filesystem is "
793 "being modified while fsck is running.\n"));
794
795 return retval;
796}
830b44f4
TT
797
798void e2fsck_set_bitmap_type(ext2_filsys fs, unsigned int default_type,
799 const char *profile_name, unsigned int *old_type)
800{
801 unsigned type;
93d0db34 802 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
830b44f4
TT
803
804 if (old_type)
805 *old_type = fs->default_bitmap_type;
93d0db34
TT
806 profile_get_uint(ctx->profile, "bitmaps", profile_name, 0,
807 default_type, &type);
808 profile_get_uint(ctx->profile, "bitmaps", "all", 0, type, &type);
830b44f4
TT
809 fs->default_bitmap_type = type ? type : default_type;
810}
811
812errcode_t e2fsck_allocate_inode_bitmap(ext2_filsys fs, const char *descr,
813 int deftype,
814 const char *name,
815 ext2fs_inode_bitmap *ret)
816{
817 errcode_t retval;
818 unsigned int save_type;
819
820 e2fsck_set_bitmap_type(fs, deftype, name, &save_type);
821 retval = ext2fs_allocate_inode_bitmap(fs, descr, ret);
822 fs->default_bitmap_type = save_type;
823 return retval;
824}
825
826errcode_t e2fsck_allocate_block_bitmap(ext2_filsys fs, const char *descr,
827 int deftype,
828 const char *name,
829 ext2fs_block_bitmap *ret)
830{
831 errcode_t retval;
832 unsigned int save_type;
833
834 e2fsck_set_bitmap_type(fs, deftype, name, &save_type);
835 retval = ext2fs_allocate_block_bitmap(fs, descr, ret);
836 fs->default_bitmap_type = save_type;
837 return retval;
838}
839
840errcode_t e2fsck_allocate_subcluster_bitmap(ext2_filsys fs, const char *descr,
841 int deftype,
842 const char *name,
843 ext2fs_block_bitmap *ret)
844{
845 errcode_t retval;
846 unsigned int save_type;
847
848 e2fsck_set_bitmap_type(fs, deftype, name, &save_type);
849 retval = ext2fs_allocate_subcluster_bitmap(fs, descr, ret);
850 fs->default_bitmap_type = save_type;
851 return retval;
852}
79614b27
DW
853
854/* Return memory size in bytes */
855unsigned long long get_memory_size(void)
856{
857#if defined(_SC_PHYS_PAGES)
858# if defined(_SC_PAGESIZE)
859 return (unsigned long long)sysconf(_SC_PHYS_PAGES) *
860 (unsigned long long)sysconf(_SC_PAGESIZE);
861# elif defined(_SC_PAGE_SIZE)
862 return (unsigned long long)sysconf(_SC_PHYS_PAGES) *
863 (unsigned long long)sysconf(_SC_PAGE_SIZE);
864# endif
865#elif defined(CTL_HW)
866# if (defined(HW_MEMSIZE) || defined(HW_PHYSMEM64))
867# define CTL_HW_INT64
868# elif (defined(HW_PHYSMEM) || defined(HW_REALMEM))
869# define CTL_HW_UINT
870# endif
871 int mib[2];
872
873 mib[0] = CTL_HW;
874# if defined(HW_MEMSIZE)
875 mib[1] = HW_MEMSIZE;
876# elif defined(HW_PHYSMEM64)
877 mib[1] = HW_PHYSMEM64;
878# elif defined(HW_REALMEM)
879 mib[1] = HW_REALMEM;
880# elif defined(HW_PYSMEM)
881 mib[1] = HW_PHYSMEM;
882# endif
883# if defined(CTL_HW_INT64)
884 unsigned long long size = 0;
885# elif defined(CTL_HW_UINT)
886 unsigned int size = 0;
887# endif
888# if defined(CTL_HW_INT64) || defined(CTL_HW_UINT)
889 size_t len = sizeof(size);
890
891 if (sysctl(mib, 2, &size, &len, NULL, 0) == 0)
892 return (unsigned long long)size;
893# endif
894 return 0;
895#else
896# warning "Don't know how to detect memory on your platform?"
897 return 0;
898#endif
899}