Whamcloud - gitweb
LU-9501 mke2fs: avoid inode number error with large FS
[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_MALLINFO
494         /* don't use mallinfo() if over 2GB used, since it returns "int" */
495         if ((char *)sbrk(0) - (char *)track->brk_start < 2LL << 30) {
496                 struct mallinfo malloc_info = mallinfo();
497
498                 log_out(ctx, _("Memory used: %lluk/%lluk (%lluk/%lluk), "),
499                         kbytes(malloc_info.arena), kbytes(malloc_info.hblkhd),
500                         kbytes(malloc_info.uordblks),
501                         kbytes(malloc_info.fordblks));
502         } else
503 #endif
504         log_out(ctx, _("Memory used: %lluk, "),
505                 kbytes(((char *)sbrk(0)) - ((char *)track->brk_start)));
506
507 #ifdef HAVE_GETRUSAGE
508         getrusage(RUSAGE_SELF, &r);
509
510         log_out(ctx, _("time: %5.2f/%5.2f/%5.2f\n"),
511                 timeval_subtract(&time_end, &track->time_start),
512                 timeval_subtract(&r.ru_utime, &track->user_start),
513                 timeval_subtract(&r.ru_stime, &track->system_start));
514 #else
515         log_out(ctx, _("elapsed time: %6.3f\n"),
516                 timeval_subtract(&time_end, &track->time_start));
517 #endif
518 #define mbytes(x)       (((x) + 1048575) / 1048576)
519         if (channel && channel->manager && channel->manager->get_stats) {
520                 io_stats delta = 0;
521                 unsigned long long bytes_read = 0;
522                 unsigned long long bytes_written = 0;
523
524                 if (desc)
525                         log_out(ctx, "%s: ", desc);
526
527                 channel->manager->get_stats(channel, &delta);
528                 if (delta) {
529                         bytes_read = delta->bytes_read - track->bytes_read;
530                         bytes_written = delta->bytes_written -
531                                 track->bytes_written;
532                 }
533                 log_out(ctx, "I/O read: %lluMB, write: %lluMB, "
534                         "rate: %.2fMB/s\n",
535                         mbytes(bytes_read), mbytes(bytes_written),
536                         (double)mbytes(bytes_read + bytes_written) /
537                         timeval_subtract(&time_end, &track->time_start));
538         }
539 }
540 #endif /* RESOURCE_TRACK */
541
542 void e2fsck_read_inode(e2fsck_t ctx, unsigned long ino,
543                               struct ext2_inode * inode, const char *proc)
544 {
545         errcode_t retval;
546
547         retval = ext2fs_read_inode(ctx->fs, ino, inode);
548         if (retval) {
549                 com_err("ext2fs_read_inode", retval,
550                         _("while reading inode %lu in %s"), ino, proc);
551                 fatal_error(ctx, 0);
552         }
553 }
554
555 void e2fsck_read_inode_full(e2fsck_t ctx, unsigned long ino,
556                             struct ext2_inode *inode, int bufsize,
557                             const char *proc)
558 {
559         errcode_t retval;
560
561         retval = ext2fs_read_inode_full(ctx->fs, ino, inode, bufsize);
562         if (retval) {
563                 com_err("ext2fs_read_inode_full", retval,
564                         _("while reading inode %lu in %s"), ino, proc);
565                 fatal_error(ctx, 0);
566         }
567 }
568
569 #ifdef HAVE_PTHREAD
570 #define e2fsck_get_lock_context(ctx)            \
571         e2fsck_t global_ctx = ctx->global_ctx;  \
572         if (!global_ctx)                        \
573                 global_ctx = ctx;               \
574
575 /**
576  * before we hold write lock, read lock should
577  * has been held.
578  */
579 void e2fsck_pass1_fix_lock(e2fsck_t ctx)
580 {
581         int err;
582
583         if (!ctx->fs_need_locking)
584                 return;
585
586         e2fsck_get_lock_context(ctx);
587         err = pthread_rwlock_trywrlock(&global_ctx->fs_fix_rwlock);
588         assert(err != 0);
589         pthread_rwlock_unlock(&global_ctx->fs_fix_rwlock);
590         pthread_rwlock_wrlock(&global_ctx->fs_fix_rwlock);
591 }
592
593 void e2fsck_pass1_fix_unlock(e2fsck_t ctx)
594 {
595         if (!ctx->fs_need_locking)
596                 return;
597         e2fsck_get_lock_context(ctx);
598         /* unlock write lock */
599         pthread_rwlock_unlock(&global_ctx->fs_fix_rwlock);
600         /* get read lock again */
601         pthread_rwlock_rdlock(&global_ctx->fs_fix_rwlock);
602 }
603
604 void e2fsck_pass1_check_lock(e2fsck_t ctx)
605 {
606         if (!ctx->fs_need_locking)
607                 return;
608         e2fsck_get_lock_context(ctx);
609         pthread_rwlock_rdlock(&global_ctx->fs_fix_rwlock);
610 }
611
612 void e2fsck_pass1_check_unlock(e2fsck_t ctx)
613 {
614         if (!ctx->fs_need_locking)
615                 return;
616         e2fsck_get_lock_context(ctx);
617         pthread_rwlock_unlock(&global_ctx->fs_fix_rwlock);
618 }
619
620 void e2fsck_pass1_block_map_w_lock(e2fsck_t ctx)
621 {
622         if (!ctx->fs_need_locking)
623                 return;
624         e2fsck_get_lock_context(ctx);
625         pthread_rwlock_wrlock(&global_ctx->fs_block_map_rwlock);
626 }
627
628 void e2fsck_pass1_block_map_w_unlock(e2fsck_t ctx)
629 {
630         if (!ctx->fs_need_locking)
631                 return;
632         e2fsck_get_lock_context(ctx);
633         pthread_rwlock_unlock(&global_ctx->fs_block_map_rwlock);
634 }
635
636 void e2fsck_pass1_block_map_r_lock(e2fsck_t ctx)
637 {
638         if (!ctx->fs_need_locking)
639                 return;
640         e2fsck_get_lock_context(ctx);
641         pthread_rwlock_rdlock(&global_ctx->fs_block_map_rwlock);
642 }
643
644 void e2fsck_pass1_block_map_r_unlock(e2fsck_t ctx)
645 {
646         if (!ctx->fs_need_locking)
647                 return;
648         e2fsck_get_lock_context(ctx);
649         pthread_rwlock_unlock(&global_ctx->fs_block_map_rwlock);
650  }
651 #else
652 void e2fsck_pass1_fix_lock(e2fsck_t ctx)
653 {
654
655 }
656
657 void e2fsck_pass1_fix_unlock(e2fsck_t ctx)
658 {
659
660 }
661 void e2fsck_pass1_check_lock(e2fsck_t ctx)
662 {
663
664 }
665 void e2fsck_pass1_check_unlock(e2fsck_t ctx)
666 {
667
668 }
669 void e2fsck_pass1_block_map_w_lock(e2fsck_t ctx)
670 {
671
672 }
673
674 void e2fsck_pass1_block_map_w_unlock(e2fsck_t ctx)
675 {
676
677 }
678
679 void e2fsck_pass1_block_map_r_lock(e2fsck_t ctx)
680 {
681
682 }
683
684 void e2fsck_pass1_block_map_r_unlock(e2fsck_t ctx)
685 {
686
687 }
688 #endif
689
690 void e2fsck_write_inode_full(e2fsck_t ctx, unsigned long ino,
691                              struct ext2_inode * inode, int bufsize,
692                              const char *proc)
693 {
694         errcode_t retval;
695
696         e2fsck_pass1_fix_lock(ctx);
697         retval = ext2fs_write_inode_full(ctx->fs, ino, inode, bufsize);
698         e2fsck_pass1_fix_unlock(ctx);
699         if (retval) {
700                 com_err("ext2fs_write_inode", retval,
701                         _("while writing inode %lu in %s"), ino, proc);
702                 fatal_error(ctx, 0);
703         }
704 }
705
706 void e2fsck_write_inode(e2fsck_t ctx, unsigned long ino,
707                         struct ext2_inode * inode, const char *proc)
708 {
709         errcode_t retval;
710
711         e2fsck_pass1_fix_lock(ctx);
712         retval = ext2fs_write_inode(ctx->fs, ino, inode);
713         e2fsck_pass1_fix_unlock(ctx);
714         if (retval) {
715                 com_err("ext2fs_write_inode", retval,
716                         _("while writing inode %lu in %s"), ino, proc);
717                 fatal_error(ctx, 0);
718         }
719 }
720
721 #ifdef MTRACE
722 void mtrace_print(char *mesg)
723 {
724         FILE    *malloc_get_mallstream();
725         FILE    *f = malloc_get_mallstream();
726
727         if (f)
728                 fprintf(f, "============= %s\n", mesg);
729 }
730 #endif
731
732 blk64_t get_backup_sb(e2fsck_t ctx, ext2_filsys fs, const char *name,
733                       io_manager manager)
734 {
735         struct ext2_super_block *sb;
736         io_channel              io = NULL;
737         void                    *buf = NULL;
738         int                     blocksize;
739         blk64_t                 superblock, ret_sb = 8193;
740
741         if (fs && fs->super) {
742                 ret_sb = (fs->super->s_blocks_per_group +
743                           fs->super->s_first_data_block);
744                 if (ctx) {
745                         ctx->superblock = ret_sb;
746                         ctx->blocksize = fs->blocksize;
747                 }
748                 return ret_sb;
749         }
750
751         if (ctx) {
752                 if (ctx->blocksize) {
753                         ret_sb = ctx->blocksize * 8;
754                         if (ctx->blocksize == 1024)
755                                 ret_sb++;
756                         ctx->superblock = ret_sb;
757                         return ret_sb;
758                 }
759                 ctx->superblock = ret_sb;
760                 ctx->blocksize = 1024;
761         }
762
763         if (!name || !manager)
764                 goto cleanup;
765
766         if (manager->open(name, 0, &io) != 0)
767                 goto cleanup;
768
769         if (ext2fs_get_mem(SUPERBLOCK_SIZE, &buf))
770                 goto cleanup;
771         sb = (struct ext2_super_block *) buf;
772
773         for (blocksize = EXT2_MIN_BLOCK_SIZE;
774              blocksize <= EXT2_MAX_BLOCK_SIZE ; blocksize *= 2) {
775                 superblock = blocksize*8;
776                 if (blocksize == 1024)
777                         superblock++;
778                 io_channel_set_blksize(io, blocksize);
779                 if (io_channel_read_blk64(io, superblock,
780                                         -SUPERBLOCK_SIZE, buf))
781                         continue;
782 #ifdef WORDS_BIGENDIAN
783                 if (sb->s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC))
784                         ext2fs_swap_super(sb);
785 #endif
786                 if ((sb->s_magic == EXT2_SUPER_MAGIC) &&
787                     (EXT2_BLOCK_SIZE(sb) == blocksize)) {
788                         ret_sb = superblock;
789                         if (ctx) {
790                                 ctx->superblock = superblock;
791                                 ctx->blocksize = blocksize;
792                         }
793                         break;
794                 }
795         }
796
797 cleanup:
798         if (io)
799                 io_channel_close(io);
800         if (buf)
801                 ext2fs_free_mem(&buf);
802         return (ret_sb);
803 }
804
805 /*
806  * Given a mode, return the ext2 file type
807  */
808 int ext2_file_type(unsigned int mode)
809 {
810         if (LINUX_S_ISREG(mode))
811                 return EXT2_FT_REG_FILE;
812
813         if (LINUX_S_ISDIR(mode))
814                 return EXT2_FT_DIR;
815
816         if (LINUX_S_ISCHR(mode))
817                 return EXT2_FT_CHRDEV;
818
819         if (LINUX_S_ISBLK(mode))
820                 return EXT2_FT_BLKDEV;
821
822         if (LINUX_S_ISLNK(mode))
823                 return EXT2_FT_SYMLINK;
824
825         if (LINUX_S_ISFIFO(mode))
826                 return EXT2_FT_FIFO;
827
828         if (LINUX_S_ISSOCK(mode))
829                 return EXT2_FT_SOCK;
830
831         return 0;
832 }
833
834 /*
835  * Check to see if a filesystem is in /proc/filesystems.
836  * Returns 1 if found, 0 if not
837  */
838 int fs_proc_check(const char *fs_name)
839 {
840         FILE    *f;
841         char    buf[80], *cp, *t;
842
843         f = fopen("/proc/filesystems", "r");
844         if (!f)
845                 return (0);
846         while (!feof(f)) {
847                 if (!fgets(buf, sizeof(buf), f))
848                         break;
849                 cp = buf;
850                 if (!isspace(*cp)) {
851                         while (*cp && !isspace(*cp))
852                                 cp++;
853                 }
854                 while (*cp && isspace(*cp))
855                         cp++;
856                 if ((t = strchr(cp, '\n')) != NULL)
857                         *t = 0;
858                 if ((t = strchr(cp, '\t')) != NULL)
859                         *t = 0;
860                 if ((t = strchr(cp, ' ')) != NULL)
861                         *t = 0;
862                 if (!strcmp(fs_name, cp)) {
863                         fclose(f);
864                         return (1);
865                 }
866         }
867         fclose(f);
868         return (0);
869 }
870
871 /*
872  * Check to see if a filesystem is available as a module
873  * Returns 1 if found, 0 if not
874  */
875 int check_for_modules(const char *fs_name)
876 {
877 #ifdef __linux__
878         struct utsname  uts;
879         FILE            *f;
880         char            buf[1024], *cp, *t;
881         int             i;
882
883         if (uname(&uts))
884                 return (0);
885         snprintf(buf, sizeof(buf), "/lib/modules/%s/modules.dep", uts.release);
886
887         f = fopen(buf, "r");
888         if (!f)
889                 return (0);
890         while (!feof(f)) {
891                 if (!fgets(buf, sizeof(buf), f))
892                         break;
893                 if ((cp = strchr(buf, ':')) != NULL)
894                         *cp = 0;
895                 else
896                         continue;
897                 if ((cp = strrchr(buf, '/')) != NULL)
898                         cp++;
899                 else
900                         cp = buf;
901                 i = strlen(cp);
902                 if (i > 3) {
903                         t = cp + i - 3;
904                         if (!strcmp(t, ".ko"))
905                                 *t = 0;
906                 }
907                 if (!strcmp(cp, fs_name)) {
908                         fclose(f);
909                         return (1);
910                 }
911         }
912         fclose(f);
913 #endif /* __linux__ */
914         return (0);
915 }
916
917 /*
918  * Helper function that does the right thing if write returns a
919  * partial write, or an EAGAIN/EINTR error.
920  */
921 int write_all(int fd, char *buf, size_t count)
922 {
923         ssize_t ret;
924         int c = 0;
925
926         while (count > 0) {
927                 ret = write(fd, buf, count);
928                 if (ret < 0) {
929                         if ((errno == EAGAIN) || (errno == EINTR))
930                                 continue;
931                         return -1;
932                 }
933                 count -= ret;
934                 buf += ret;
935                 c += ret;
936         }
937         return c;
938 }
939
940 void dump_mmp_msg(struct mmp_struct *mmp, const char *fmt, ...)
941 {
942         va_list pvar;
943
944         if (fmt) {
945                 printf("MMP check failed: ");
946                 va_start(pvar, fmt);
947                 vprintf(fmt, pvar);
948                 va_end(pvar);
949         }
950         if (mmp) {
951                 time_t t = mmp->mmp_time;
952
953                 printf("MMP_block:\n");
954                 printf("    mmp_magic: 0x%x\n", mmp->mmp_magic);
955                 printf("    mmp_check_interval: %d\n",
956                        mmp->mmp_check_interval);
957                 printf("    mmp_sequence: %08x\n", mmp->mmp_seq);
958                 printf("    mmp_update_date: %s", ctime(&t));
959                 printf("    mmp_update_time: %lld\n",
960                        (long long) mmp->mmp_time);
961                 printf("    mmp_node_name: %.*s\n",
962                        EXT2_LEN_STR(mmp->mmp_nodename));
963                 printf("    mmp_device_name: %.*s\n",
964                        EXT2_LEN_STR(mmp->mmp_bdevname));
965         }
966 }
967
968 errcode_t e2fsck_mmp_update(ext2_filsys fs)
969 {
970         errcode_t retval;
971
972         retval = ext2fs_mmp_update(fs);
973         if (retval == EXT2_ET_MMP_CHANGE_ABORT)
974                 dump_mmp_msg(fs->mmp_cmp,
975                              _("UNEXPECTED INCONSISTENCY: the filesystem is "
976                                "being modified while fsck is running.\n"));
977
978         return retval;
979 }
980
981 void e2fsck_set_bitmap_type(ext2_filsys fs, unsigned int default_type,
982                             const char *profile_name, unsigned int *old_type)
983 {
984         unsigned type;
985         e2fsck_t ctx = (e2fsck_t) fs->priv_data;
986
987         if (old_type)
988                 *old_type = fs->default_bitmap_type;
989         profile_get_uint(ctx->profile, "bitmaps", profile_name, 0,
990                          default_type, &type);
991         profile_get_uint(ctx->profile, "bitmaps", "all", 0, type, &type);
992         fs->default_bitmap_type = type ? type : default_type;
993 }
994
995 errcode_t e2fsck_allocate_inode_bitmap(ext2_filsys fs, const char *descr,
996                                        int deftype,
997                                        const char *name,
998                                        ext2fs_inode_bitmap *ret)
999 {
1000         errcode_t       retval;
1001         unsigned int    save_type;
1002
1003         e2fsck_set_bitmap_type(fs, deftype, name, &save_type);
1004         retval = ext2fs_allocate_inode_bitmap(fs, descr, ret);
1005         fs->default_bitmap_type = save_type;
1006         return retval;
1007 }
1008
1009 errcode_t e2fsck_allocate_block_bitmap(ext2_filsys fs, const char *descr,
1010                                        int deftype,
1011                                        const char *name,
1012                                        ext2fs_block_bitmap *ret)
1013 {
1014         errcode_t       retval;
1015         unsigned int    save_type;
1016
1017         e2fsck_set_bitmap_type(fs, deftype, name, &save_type);
1018         retval = ext2fs_allocate_block_bitmap(fs, descr, ret);
1019         fs->default_bitmap_type = save_type;
1020         return retval;
1021 }
1022
1023 errcode_t e2fsck_allocate_subcluster_bitmap(ext2_filsys fs, const char *descr,
1024                                             int deftype,
1025                                             const char *name,
1026                                             ext2fs_block_bitmap *ret)
1027 {
1028         errcode_t       retval;
1029         unsigned int    save_type;
1030
1031         e2fsck_set_bitmap_type(fs, deftype, name, &save_type);
1032         retval = ext2fs_allocate_subcluster_bitmap(fs, descr, ret);
1033         fs->default_bitmap_type = save_type;
1034         return retval;
1035 }
1036
1037 /* Return memory size in bytes */
1038 unsigned long long get_memory_size(void)
1039 {
1040 #if defined(_SC_PHYS_PAGES)
1041 # if defined(_SC_PAGESIZE)
1042         return (unsigned long long)sysconf(_SC_PHYS_PAGES) *
1043                (unsigned long long)sysconf(_SC_PAGESIZE);
1044 # elif defined(_SC_PAGE_SIZE)
1045         return (unsigned long long)sysconf(_SC_PHYS_PAGES) *
1046                (unsigned long long)sysconf(_SC_PAGE_SIZE);
1047 # endif
1048 #elif defined(CTL_HW)
1049 # if (defined(HW_MEMSIZE) || defined(HW_PHYSMEM64))
1050 #  define CTL_HW_INT64
1051 # elif (defined(HW_PHYSMEM) || defined(HW_REALMEM))
1052 #  define CTL_HW_UINT
1053 # endif
1054         int mib[2];
1055
1056         mib[0] = CTL_HW;
1057 # if defined(HW_MEMSIZE)
1058         mib[1] = HW_MEMSIZE;
1059 # elif defined(HW_PHYSMEM64)
1060         mib[1] = HW_PHYSMEM64;
1061 # elif defined(HW_REALMEM)
1062         mib[1] = HW_REALMEM;
1063 # elif defined(HW_PYSMEM)
1064         mib[1] = HW_PHYSMEM;
1065 # endif
1066 # if defined(CTL_HW_INT64)
1067         unsigned long long size = 0;
1068 # elif defined(CTL_HW_UINT)
1069         unsigned int size = 0;
1070 # endif
1071         return 0;
1072 #else
1073 # warning "Don't know how to detect memory on your platform?"
1074         return 0;
1075 #endif
1076 }