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