]> git.ipfire.org Git - thirdparty/e2fsprogs.git/blame - e2fsck/util.c
fix cross-compilation support
[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
3839e657
TT
40#include "e2fsck.h"
41
aa75eccc 42extern e2fsck_t e2fsck_global_ctx; /* Try your very best not to use this! */
542867fb 43
b0e91c89 44#include <stdarg.h>
0f5eba75 45#include <time.h>
50e1e10f
TT
46#include <sys/time.h>
47#include <sys/resource.h>
48
f8188fff 49void fatal_error(e2fsck_t ctx, const char *msg)
3839e657 50{
13dcce8b
ES
51 ext2_filsys fs = ctx->fs;
52 int exit_value = FSCK_ERROR;
53
efc6f628 54 if (msg)
1b6bf175 55 fprintf (stderr, "e2fsck: %s\n", msg);
13dcce8b
ES
56 if (!fs)
57 goto out;
7ff040f3 58 if (fs->io && fs->super) {
0f5eba75 59 ext2fs_mmp_stop(ctx->fs);
e39ac922 60 if (ctx->fs->io->magic == EXT2_ET_MAGIC_IO_CHANNEL)
58a75177
TT
61 io_channel_flush(ctx->fs->io);
62 else
b0e91c89 63 log_err(ctx, "e2fsck: io manager magic bad!\n");
58a75177 64 }
13dcce8b
ES
65 if (ext2fs_test_changed(fs)) {
66 exit_value |= FSCK_NONDESTRUCT;
b0e91c89 67 log_out(ctx, _("\n%s: ***** FILE SYSTEM WAS MODIFIED *****\n"),
13dcce8b
ES
68 ctx->device_name);
69 if (ctx->mount_flags & EXT2_MF_ISROOT)
70 exit_value |= FSCK_REBOOT;
71 }
72 if (!ext2fs_test_valid(fs)) {
b0e91c89
TT
73 log_out(ctx, _("\n%s: ********** WARNING: Filesystem still has "
74 "errors **********\n\n"), ctx->device_name);
13dcce8b
ES
75 exit_value |= FSCK_UNCORRECTED;
76 exit_value &= ~FSCK_NONDESTRUCT;
77 }
78out:
f8188fff
TT
79 ctx->flags |= E2F_FLAG_ABORT;
80 if (ctx->flags & E2F_FLAG_SETJMP_OK)
81 longjmp(ctx->abort_loc, 1);
13dcce8b 82 exit(exit_value);
3839e657
TT
83}
84
b0e91c89
TT
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
f8188fff
TT
113void *e2fsck_allocate_memory(e2fsck_t ctx, unsigned int size,
114 const char *description)
3839e657
TT
115{
116 void *ret;
117 char buf[256];
118
119#ifdef DEBUG_ALLOCATE_MEMORY
611378fe 120 printf("Allocating %u bytes for %s...\n", size, description);
3839e657
TT
121#endif
122 ret = malloc(size);
123 if (!ret) {
bf50beb9
ES
124 sprintf(buf, "Can't allocate %u bytes for %s\n",
125 size, description);
f8188fff 126 fatal_error(ctx, buf);
3839e657
TT
127 }
128 memset(ret, 0, size);
129 return ret;
130}
131
efc6f628 132char *string_copy(e2fsck_t ctx EXT2FS_ATTR((unused)),
54434927 133 const char *str, int len)
f364093b
TT
134{
135 char *ret;
efc6f628 136
f364093b
TT
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
542867fb 164#ifndef HAVE_CONIO_H
3e699064 165static int read_a_char(void)
542867fb
TT
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
b0e91c89 186int ask_yn(e2fsck_t ctx, const char * string, int def)
3839e657
TT
187{
188 int c;
3839e657 189 const char *defstr;
53ef44c4
TT
190 const char *short_yes = _("yY");
191 const char *short_no = _("nN");
3839e657 192
9ecd8bec
TT
193#ifdef HAVE_TERMIOS_H
194 struct termios termios, tmp;
195
3839e657
TT
196 tcgetattr (0, &termios);
197 tmp = termios;
198 tmp.c_lflag &= ~(ICANON | ECHO);
50e1e10f
TT
199 tmp.c_cc[VMIN] = 1;
200 tmp.c_cc[VTIME] = 0;
3839e657 201 tcsetattr (0, TCSANOW, &tmp);
9ecd8bec 202#endif
3839e657
TT
203
204 if (def == 1)
542867fb 205 defstr = _(_("<y>"));
3839e657 206 else if (def == 0)
542867fb 207 defstr = _(_("<n>"));
3839e657 208 else
0c4a0726 209 defstr = _(" (y/n)");
b0e91c89 210 log_out(ctx, "%s%s? ", string, defstr);
3839e657
TT
211 while (1) {
212 fflush (stdout);
e6597048 213 if ((c = read_a_char()) == EOF)
3839e657 214 break;
542867fb
TT
215 if (c == 3) {
216#ifdef HAVE_TERMIOS_H
217 tcsetattr (0, TCSANOW, &termios);
218#endif
b0e91c89
TT
219 if (ctx->flags & E2F_FLAG_SETJMP_OK) {
220 log_out(ctx, "\n");
542867fb
TT
221 longjmp(e2fsck_global_ctx->abort_loc, 1);
222 }
45ff69ff 223 log_out(ctx, "%s", _("cancelled!\n"));
542867fb
TT
224 return 0;
225 }
0c4a0726 226 if (strchr(short_yes, (char) c)) {
3839e657
TT
227 def = 1;
228 break;
229 }
0c4a0726 230 else if (strchr(short_no, (char) c)) {
3839e657
TT
231 def = 0;
232 break;
233 }
1760d167 234 else if ((c == 27 || c == ' ' || c == '\n') && (def != -1))
3839e657
TT
235 break;
236 }
237 if (def)
45ff69ff 238 log_out(ctx, "%s", _("yes\n"));
3839e657 239 else
45ff69ff 240 log_out(ctx, "%s", _("no\n"));
9ecd8bec 241#ifdef HAVE_TERMIOS_H
3839e657 242 tcsetattr (0, TCSANOW, &termios);
9ecd8bec 243#endif
3839e657
TT
244 return def;
245}
246
1b6bf175 247int ask (e2fsck_t ctx, const char * string, int def)
3839e657 248{
1b6bf175 249 if (ctx->options & E2F_OPT_NO) {
b0e91c89 250 log_out(ctx, _("%s? no\n\n"), string);
3839e657
TT
251 return 0;
252 }
1b6bf175 253 if (ctx->options & E2F_OPT_YES) {
b0e91c89 254 log_out(ctx, _("%s? yes\n\n"), string);
3839e657
TT
255 return 1;
256 }
1b6bf175 257 if (ctx->options & E2F_OPT_PREEN) {
b0e91c89 258 log_out(ctx, "%s? %s\n\n", string, def ? _("yes") : _("no"));
3839e657
TT
259 return def;
260 }
b0e91c89 261 return ask_yn(ctx, string, def);
3839e657
TT
262}
263
f8188fff 264void e2fsck_read_bitmaps(e2fsck_t ctx)
3839e657 265{
1b6bf175 266 ext2_filsys fs = ctx->fs;
3839e657 267 errcode_t retval;
e94bc631 268 const char *old_op;
830b44f4 269 unsigned int save_type;
3839e657 270
1b6bf175
TT
271 if (ctx->invalid_bitmaps) {
272 com_err(ctx->program_name, 0,
0c4a0726 273 _("e2fsck_read_bitmaps: illegal bitmap block(s) for %s"),
1b6bf175 274 ctx->device_name);
f8188fff 275 fatal_error(ctx, 0);
3839e657 276 }
f3db3566 277
e94bc631 278 old_op = ehandler_operation(_("reading inode and block bitmaps"));
830b44f4
TT
279 e2fsck_set_bitmap_type(fs, EXT2FS_BMAP64_RBTREE, "fs_bitmaps",
280 &save_type);
f3db3566 281 retval = ext2fs_read_bitmaps(fs);
830b44f4 282 fs->default_bitmap_type = save_type;
e94bc631 283 ehandler_operation(old_op);
f3db3566 284 if (retval) {
1b6bf175 285 com_err(ctx->program_name, retval,
0c4a0726 286 _("while retrying to read bitmaps for %s"),
1b6bf175 287 ctx->device_name);
f8188fff 288 fatal_error(ctx, 0);
3839e657
TT
289 }
290}
291
f8188fff 292void e2fsck_write_bitmaps(e2fsck_t ctx)
3839e657 293{
1b6bf175 294 ext2_filsys fs = ctx->fs;
3839e657 295 errcode_t retval;
e94bc631 296 const char *old_op;
3839e657 297
1bb6f6c8
AD
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);
3839e657
TT
306 }
307}
308
1b6bf175 309void preenhalt(e2fsck_t ctx)
3839e657 310{
1b6bf175
TT
311 ext2_filsys fs = ctx->fs;
312
313 if (!(ctx->options & E2F_OPT_PREEN))
3839e657 314 return;
b0e91c89 315 log_err(ctx, _("\n\n%s: UNEXPECTED INCONSISTENCY; "
0c4a0726 316 "RUN fsck MANUALLY.\n\t(i.e., without -a or -p options)\n"),
1b6bf175 317 ctx->device_name);
79cc3362 318 ctx->flags |= E2F_FLAG_EXITING;
50e1e10f
TT
319 if (fs != NULL) {
320 fs->super->s_state |= EXT2_ERROR_FS;
321 ext2fs_mark_super_dirty(fs);
322 ext2fs_close(fs);
323 }
3839e657
TT
324 exit(FSCK_UNCORRECTED);
325}
326
8bf191e8 327#ifdef RESOURCE_TRACK
6d96b00d 328void init_resource_track(struct resource_track *track, io_channel channel)
3839e657 329{
50e1e10f 330#ifdef HAVE_GETRUSAGE
3839e657 331 struct rusage r;
50e1e10f 332#endif
6d96b00d 333 io_stats io_start = 0;
efc6f628 334
3839e657
TT
335 track->brk_start = sbrk(0);
336 gettimeofday(&track->time_start, 0);
50e1e10f 337#ifdef HAVE_GETRUSAGE
53ef44c4
TT
338#ifdef sun
339 memset(&r, 0, sizeof(struct rusage));
1b6bf175 340#endif
3839e657
TT
341 getrusage(RUSAGE_SELF, &r);
342 track->user_start = r.ru_utime;
343 track->system_start = r.ru_stime;
50e1e10f
TT
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
6d96b00d
TT
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 }
3839e657
TT
356}
357
21c84b71
TT
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)
3839e657
TT
366{
367 return ((tv1->tv_sec - tv2->tv_sec) +
368 ((float) (tv1->tv_usec - tv2->tv_usec)) / 1000000);
369}
370
9facd076
KC
371void print_resource_track(e2fsck_t ctx, const char *desc,
372 struct resource_track *track, io_channel channel)
3839e657 373{
50e1e10f 374#ifdef HAVE_GETRUSAGE
3839e657 375 struct rusage r;
4a9f5936
TT
376#endif
377#ifdef HAVE_MALLINFO
378 struct mallinfo malloc_info;
50e1e10f 379#endif
3839e657
TT
380 struct timeval time_end;
381
9facd076
KC
382 if ((desc && !(ctx->options & E2F_OPT_TIME2)) ||
383 (!desc && !(ctx->options & E2F_OPT_TIME)))
384 return;
385
386 e2fsck_clear_progbar(ctx);
3839e657 387 gettimeofday(&time_end, 0);
1b6bf175
TT
388
389 if (desc)
b0e91c89 390 log_out(ctx, "%s: ", desc);
4a9f5936
TT
391
392#ifdef HAVE_MALLINFO
70eabde9 393#define kbytes(x) (((unsigned long)(x) + 1023) / 1024)
efc6f628 394
4a9f5936 395 malloc_info = mallinfo();
b0e91c89
TT
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));
4a9f5936 399#else
b0e91c89
TT
400 log_out(ctx, _("Memory used: %lu, "),
401 (unsigned long) (((char *) sbrk(0)) -
402 ((char *) track->brk_start)));
efc6f628 403#endif
50e1e10f 404#ifdef HAVE_GETRUSAGE
3839e657
TT
405 getrusage(RUSAGE_SELF, &r);
406
b0e91c89
TT
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));
50e1e10f 411#else
b0e91c89
TT
412 log_out(ctx, _("elapsed time: %6.3f\n"),
413 timeval_subtract(&time_end, &track->time_start));
50e1e10f 414#endif
6d96b00d
TT
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)
b0e91c89 422 log_out(ctx, "%s: ", desc);
6d96b00d
TT
423
424 channel->manager->get_stats(channel, &delta);
425 if (delta) {
426 bytes_read = delta->bytes_read - track->bytes_read;
efc6f628 427 bytes_written = delta->bytes_written -
6d96b00d
TT
428 track->bytes_written;
429 }
b0e91c89
TT
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));
6d96b00d 435 }
3839e657 436}
8bf191e8 437#endif /* RESOURCE_TRACK */
3839e657 438
08b21301 439void e2fsck_read_inode(e2fsck_t ctx, unsigned long ino,
f3db3566
TT
440 struct ext2_inode * inode, const char *proc)
441{
974d57d3 442 errcode_t retval;
f3db3566 443
08b21301 444 retval = ext2fs_read_inode(ctx->fs, ino, inode);
f3db3566
TT
445 if (retval) {
446 com_err("ext2fs_read_inode", retval,
611378fe 447 _("while reading inode %lu in %s"), ino, proc);
f8188fff 448 fatal_error(ctx, 0);
f3db3566
TT
449 }
450}
451
fefaef39
AD
452void e2fsck_read_inode_full(e2fsck_t ctx, unsigned long ino,
453 struct ext2_inode *inode, int bufsize,
454 const char *proc)
455{
974d57d3 456 errcode_t retval;
fefaef39
AD
457
458 retval = ext2fs_read_inode_full(ctx->fs, ino, inode, bufsize);
459 if (retval) {
460 com_err("ext2fs_read_inode_full", retval,
611378fe 461 _("while reading inode %lu in %s"), ino, proc);
fefaef39
AD
462 fatal_error(ctx, 0);
463 }
464}
465
f404167d
TT
466void e2fsck_write_inode_full(e2fsck_t ctx, unsigned long ino,
467 struct ext2_inode * inode, int bufsize,
468 const char *proc)
cebe48a1 469{
974d57d3 470 errcode_t retval;
cebe48a1
TT
471
472 retval = ext2fs_write_inode_full(ctx->fs, ino, inode, bufsize);
473 if (retval) {
474 com_err("ext2fs_write_inode", retval,
611378fe 475 _("while writing inode %lu in %s"), ino, proc);
cebe48a1
TT
476 fatal_error(ctx, 0);
477 }
478}
479
f404167d
TT
480void e2fsck_write_inode(e2fsck_t ctx, unsigned long ino,
481 struct ext2_inode * inode, const char *proc)
f3db3566 482{
974d57d3 483 errcode_t retval;
f3db3566 484
08b21301 485 retval = ext2fs_write_inode(ctx->fs, ino, inode);
f3db3566
TT
486 if (retval) {
487 com_err("ext2fs_write_inode", retval,
611378fe 488 _("while writing inode %lu in %s"), ino, proc);
f8188fff 489 fatal_error(ctx, 0);
f3db3566
TT
490 }
491}
492
3839e657
TT
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
4dbfd79d
DW
504blk64_t get_backup_sb(e2fsck_t ctx, ext2_filsys fs, const char *name,
505 io_manager manager)
1b6bf175 506{
f1a1761d
TT
507 struct ext2_super_block *sb;
508 io_channel io = NULL;
fae9bfaa 509 void *buf = NULL;
f1a1761d 510 int blocksize;
4dbfd79d 511 blk64_t superblock, ret_sb = 8193;
efc6f628 512
f1a1761d
TT
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 }
efc6f628 522
f1a1761d
TT
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
932a489c
AD
545 for (blocksize = EXT2_MIN_BLOCK_SIZE;
546 blocksize <= EXT2_MAX_BLOCK_SIZE ; blocksize *= 2) {
f1a1761d
TT
547 superblock = blocksize*8;
548 if (blocksize == 1024)
549 superblock++;
550 io_channel_set_blksize(io, blocksize);
24a117ab 551 if (io_channel_read_blk64(io, superblock,
f1a1761d
TT
552 -SUPERBLOCK_SIZE, buf))
553 continue;
2eae0930 554#ifdef WORDS_BIGENDIAN
f1a1761d
TT
555 if (sb->s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC))
556 ext2fs_swap_super(sb);
557#endif
e7b5d3c0
DD
558 if ((sb->s_magic == EXT2_SUPER_MAGIC) &&
559 (EXT2_BLOCK_SIZE(sb) == blocksize)) {
557ddb2f
TT
560 ret_sb = superblock;
561 if (ctx) {
562 ctx->superblock = superblock;
563 ctx->blocksize = blocksize;
564 }
f1a1761d
TT
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);
1b6bf175 575}
3839e657 576
6fdc7a32
TT
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;
efc6f628 587
6fdc7a32
TT
588 if (LINUX_S_ISCHR(mode))
589 return EXT2_FT_CHRDEV;
efc6f628 590
6fdc7a32
TT
591 if (LINUX_S_ISBLK(mode))
592 return EXT2_FT_BLKDEV;
efc6f628 593
6fdc7a32
TT
594 if (LINUX_S_ISLNK(mode))
595 return EXT2_FT_SYMLINK;
596
597 if (LINUX_S_ISFIFO(mode))
598 return EXT2_FT_FIFO;
efc6f628 599
6fdc7a32
TT
600 if (LINUX_S_ISSOCK(mode))
601 return EXT2_FT_SOCK;
efc6f628 602
6fdc7a32
TT
603 return 0;
604}
49a7360b
JS
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{
e3507739 620 int j, count;
49a7360b
JS
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) {
45ff69ff 636 com_err("malloc", ENOMEM, "%s",
49a7360b
JS
637 _("while allocating zeroizing buffer"));
638 exit(1);
639 }
640 memset(buf, 0, fs->blocksize * STRIDE_LENGTH);
641 }
642 /* OK, do the write loop */
49a7360b
JS
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;
24a117ab 647 retval = io_channel_write_blk64(fs->io, blk, count, buf);
49a7360b
JS
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}
80875db5
TT
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++;
f2fe5da3
ES
724 else
725 cp = buf;
80875db5
TT
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}
b0258cbc
TT
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}
0f5eba75
AD
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}
830b44f4
TT
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;
93d0db34 795 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
830b44f4
TT
796
797 if (old_type)
798 *old_type = fs->default_bitmap_type;
93d0db34
TT
799 profile_get_uint(ctx->profile, "bitmaps", profile_name, 0,
800 default_type, &type);
801 profile_get_uint(ctx->profile, "bitmaps", "all", 0, type, &type);
830b44f4
TT
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}