Whamcloud - gitweb
unix.c (check_mount): Remove the code in e2fsck which tested for the
[tools/e2fsprogs.git] / e2fsck / unix.c
1 /*
2  * unix.c - The unix-specific code for e2fsck
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 <stdio.h>
13 #ifdef HAVE_STDLIB_H
14 #include <stdlib.h>
15 #endif
16 #include <string.h>
17 #include <fcntl.h>
18 #include <ctype.h>
19 #include <time.h>
20 #ifdef HAVE_SIGNAL_H
21 #include <signal.h>
22 #endif
23 #ifdef HAVE_GETOPT_H
24 #include <getopt.h>
25 #else
26 extern char *optarg;
27 extern int optind;
28 #endif
29 #include <unistd.h>
30 #ifdef HAVE_ERRNO_H
31 #include <errno.h>
32 #endif
33 #ifdef HAVE_MNTENT_H
34 #include <mntent.h>
35 #endif
36 #include <sys/ioctl.h>
37 #include <malloc.h>
38
39 #include "et/com_err.h"
40 #include "e2fsck.h"
41 #include "problem.h"
42 #include "../version.h"
43
44 /* Command line options */
45 static int blocksize = 0;
46 static int swapfs = 0;
47 static int normalize_swapfs = 0;
48 static int cflag = 0;           /* check disk */
49 static int show_version_only = 0;
50 static int force = 0;
51 static int verbose = 0;
52
53 static int replace_bad_blocks = 0;
54 static char *bad_blocks_file = 0;
55
56 static int possible_block_sizes[] = { 1024, 2048, 4096, 8192, 0};
57
58 static int root_filesystem = 0;
59 static int read_only_root = 0;
60
61 e2fsck_t e2fsck_global_ctx;     /* Try your very best not to use this! */
62
63 static void usage(e2fsck_t ctx)
64 {
65         fprintf(stderr,
66                 _("Usage: %s [-panyrcdfvstFSV] [-b superblock] [-B blocksize]\n"
67                 "\t\t[-I inode_buffer_blocks] [-P process_inode_size]\n"
68                 "\t\t[-l|-L bad_blocks_file] [-C fd] [-j ext-journal] device\n"),
69                 ctx->program_name);
70
71         fprintf(stderr, _("\nEmergency help:\n"
72                 " -p                   Automatic repair (no questions)\n"
73                 " -n                   Make no changes to the filesystem\n"
74                 " -y                   Assume \"yes\" to all questions\n"
75                 " -c                   Check for bad blocks\n"
76                 " -f                   Force checking even if filesystem is marked clean\n"));
77         fprintf(stderr, _(""
78                 " -v                   Be verbose\n"
79                 " -b superblock        Use alternative superblock\n"
80                 " -B blocksize         Force blocksize when looking for superblock\n"
81                 " -j external-journal  Set location of the external journal\n"
82                 " -l bad_blocks_file   Add to badblocks list\n"
83                 " -L bad_blocks_file   Set badblocks list\n"
84                 ));
85
86         exit(FSCK_USAGE);
87 }
88
89 static void show_stats(e2fsck_t ctx)
90 {
91         ext2_filsys fs = ctx->fs;
92         int inodes, inodes_used, blocks, blocks_used;
93         int dir_links;
94         int num_files, num_links;
95         int frag_percent;
96
97         dir_links = 2 * ctx->fs_directory_count - 1;
98         num_files = ctx->fs_total_count - dir_links;
99         num_links = ctx->fs_links_count - dir_links;
100         inodes = fs->super->s_inodes_count;
101         inodes_used = (fs->super->s_inodes_count -
102                        fs->super->s_free_inodes_count);
103         blocks = fs->super->s_blocks_count;
104         blocks_used = (fs->super->s_blocks_count -
105                        fs->super->s_free_blocks_count);
106
107         frag_percent = (10000 * ctx->fs_fragmented) / inodes_used;
108         frag_percent = (frag_percent + 5) / 10;
109         
110         if (!verbose) {
111                 printf(_("%s: %d/%d files (%0d.%d%% non-contiguous), %d/%d blocks\n"),
112                        ctx->device_name, inodes_used, inodes,
113                        frag_percent / 10, frag_percent % 10,
114                        blocks_used, blocks);
115                 return;
116         }
117         /*
118          * This is a bit ugly. But I think there will nearly always be more
119          * than one "thing" to report about, so I won't try writing complex
120          * code to handle one/two/many forms of all words.
121          * Some languages (Italian, at least) never uses the plural form
122          * of foreign words, so in real life this could not be a problem.
123          * md@linux.it - 2000-1-15
124          */
125 #ifdef ENABLE_NLS
126         printf (_("\n%8d inodes used (%d%%)\n"), inodes_used,
127                 (inodes_used != 1), 100 * inodes_used / inodes);
128         printf (_("%8d non-contiguous inodes (%0d.%d%%)\n"),
129                 ctx->fs_fragmented, frag_percent / 10, frag_percent % 10);
130         printf (_("         # of inodes with ind/dind/tind blocks: %d/%d/%d\n"),
131                 ctx->fs_ind_count, ctx->fs_dind_count, ctx->fs_tind_count);
132         printf (_("%8d blocks used (%d%%)\n"
133                 "%8d bad blocks\n"), blocks_used,
134                 (int) ((long long) 100 * blocks_used / blocks),
135                 ctx->fs_badblocks_count);
136         printf (_("\n%8d regular files\n"
137                 "%8d directories\n"
138                 "%8d character device files\n"
139                 "%8d block device files\n"
140                 "%8d fifos\n"
141                 "%8d links\n"
142                 "%8d symbolic links (%d fast symbolic links)\n"
143                 "%8d sockets\n"
144                 "--------\n"
145                 "%8d files\n"),
146                 ctx->fs_regular_count,
147                 ctx->fs_directory_count,
148                 ctx->fs_chardev_count,
149                 ctx->fs_blockdev_count,
150                 ctx->fs_fifo_count,
151                 ctx->fs_links_count - dir_links,
152                 ctx->fs_symlinks_count,
153                 ctx->fs_fast_symlinks_count,
154                 ctx->fs_sockets_count,
155                 ctx->fs_total_count - dir_links);
156 #else
157         printf ("\n%8d inode%s used (%d%%)\n", inodes_used,
158                 (inodes_used != 1) ? "s" : "",
159                 100 * inodes_used / inodes);
160         printf ("%8d non-contiguous inodes (%0d.%d%%)\n",
161                 ctx->fs_fragmented, frag_percent / 10, frag_percent % 10);
162         printf ("         # of inodes with ind/dind/tind blocks: %d/%d/%d\n",
163                 ctx->fs_ind_count, ctx->fs_dind_count, ctx->fs_tind_count);
164         printf ("%8d block%s used (%d%%)\n"
165                 "%8d bad block%s\n", blocks_used,
166                 (blocks_used != 1) ? "s" : "",
167                 100 * blocks_used / blocks, ctx->fs_badblocks_count,
168                 ctx->fs_badblocks_count != 1 ? "s" : "");
169         printf ("\n%8d regular file%s\n"
170                 "%8d director%s\n"
171                 "%8d character device file%s\n"
172                 "%8d block device file%s\n"
173                 "%8d fifo%s\n"
174                 "%8d link%s\n"
175                 "%8d symbolic link%s (%d fast symbolic link%s)\n"
176                 "%8d socket%s\n"
177                 "--------\n"
178                 "%8d file%s\n",
179                 ctx->fs_regular_count,
180                 (ctx->fs_regular_count != 1) ? "s" : "",
181                 ctx->fs_directory_count,
182                 (ctx->fs_directory_count != 1) ? "ies" : "y",
183                 ctx->fs_chardev_count,
184                 (ctx->fs_chardev_count != 1) ? "s" : "",
185                 ctx->fs_blockdev_count,
186                 (ctx->fs_blockdev_count != 1) ? "s" : "",
187                 ctx->fs_fifo_count,
188                 (ctx->fs_fifo_count != 1) ? "s" : "",
189                 ctx->fs_links_count - dir_links,
190                 ((ctx->fs_links_count - dir_links) != 1) ? "s" : "",
191                 ctx->fs_symlinks_count,
192                 (ctx->fs_symlinks_count != 1) ? "s" : "",
193                 ctx->fs_fast_symlinks_count,
194                 (ctx->fs_fast_symlinks_count != 1) ? "s" : "",
195                 ctx->fs_sockets_count, (ctx->fs_sockets_count != 1) ? "s" : "",
196                 ctx->fs_total_count - dir_links,
197                 ((ctx->fs_total_count - dir_links) != 1) ? "s" : "");
198 #endif
199 }
200
201 static void check_mount(e2fsck_t ctx)
202 {
203         errcode_t       retval;
204         int             mount_flags, cont, fd;
205
206         retval = ext2fs_check_if_mounted(ctx->filesystem_name, &mount_flags);
207         if (retval) {
208                 com_err("ext2fs_check_if_mount", retval,
209                         _("while determining whether %s is mounted."),
210                         ctx->filesystem_name);
211                 return;
212         }
213
214         /*
215          * If the filesystem isn't mounted, or it's the root filesystem
216          * and it's mounted read-only, then everything's fine.
217          */
218         if ((!(mount_flags & EXT2_MF_MOUNTED)) ||
219             ((mount_flags & EXT2_MF_ISROOT) &&
220              (mount_flags & EXT2_MF_READONLY)))
221                 return;
222
223         if (ctx->options & E2F_OPT_READONLY) {
224                 printf(_("Warning!  %s is mounted.\n"), ctx->filesystem_name);
225                 return;
226         }
227
228         printf(_("%s is mounted.  "), ctx->filesystem_name);
229         if (!isatty(0) || !isatty(1))
230                 fatal_error(ctx, _("Cannot continue, aborting.\n\n"));
231         printf(_("\n\n\007\007\007\007WARNING!!!  "
232                "Running e2fsck on a mounted filesystem may cause\n"
233                "SEVERE filesystem damage.\007\007\007\n\n"));
234         cont = ask_yn(_("Do you really want to continue"), -1);
235         if (!cont) {
236                 printf (_("check aborted.\n"));
237                 exit (0);
238         }
239         return;
240 }
241
242 /*
243  * This routine checks to see if a filesystem can be skipped; if so,
244  * it will exit with E2FSCK_OK.  Under some conditions it will print a
245  * message explaining why a check is being forced.
246  */
247 static void check_if_skip(e2fsck_t ctx)
248 {
249         ext2_filsys fs = ctx->fs;
250         const char *reason = NULL;
251         unsigned int reason_arg = 0;
252         
253         if (force || bad_blocks_file || cflag || swapfs)
254                 return;
255         
256         if (fs->super->s_state & EXT2_ERROR_FS)
257                 reason = _(" contains a file system with errors");
258         else if ((fs->super->s_state & EXT2_VALID_FS) == 0)
259                 reason = _(" was not cleanly unmounted");
260         else if ((fs->super->s_max_mnt_count > 0) &&
261                  (fs->super->s_mnt_count >=
262                   (unsigned) fs->super->s_max_mnt_count)) {
263                 reason = _(" has been mounted %u times without being checked");
264                 reason_arg = fs->super->s_mnt_count;
265         } else if (fs->super->s_checkinterval &&
266                  time(0) >= (fs->super->s_lastcheck +
267                              fs->super->s_checkinterval)) {
268                 reason = _(" has gone %u days without being checked");
269                 reason_arg = (time(0) - fs->super->s_lastcheck)/(3600*24);
270         }
271         if (reason) {
272                 fputs(ctx->device_name, stdout);
273                 printf(reason, reason_arg);
274                 fputs(_(", check forced.\n"), stdout);
275                 return;
276         }
277         printf(_("%s: clean, %d/%d files, %d/%d blocks\n"), ctx->device_name,
278                fs->super->s_inodes_count - fs->super->s_free_inodes_count,
279                fs->super->s_inodes_count,
280                fs->super->s_blocks_count - fs->super->s_free_blocks_count,
281                fs->super->s_blocks_count);
282         ext2fs_close(fs);
283         ctx->fs = NULL;
284         e2fsck_free_context(ctx);
285         exit(FSCK_OK);
286 }
287
288 /*
289  * For completion notice
290  */
291 struct percent_tbl {
292         int     max_pass;
293         int     table[32];
294 };
295 struct percent_tbl e2fsck_tbl = {
296         5, { 0, 70, 90, 92,  95, 100 }
297 };
298 static char bar[] =
299         "==============================================================="
300         "===============================================================";
301 static char spaces[] =
302         "                                                               "
303         "                                                               ";
304
305 static float calc_percent(struct percent_tbl *tbl, int pass, int curr,
306                           int max)
307 {
308         float   percent;
309         
310         if (pass <= 0)
311                 return 0.0;
312         if (pass > tbl->max_pass || max == 0)
313                 return 100.0;
314         percent = ((float) curr) / ((float) max);
315         return ((percent * (tbl->table[pass] - tbl->table[pass-1]))
316                 + tbl->table[pass-1]);
317 }
318
319 extern void e2fsck_clear_progbar(e2fsck_t ctx)
320 {
321         if (!(ctx->flags & E2F_FLAG_PROG_BAR))
322                 return;
323         
324         printf("%s\r", spaces + (sizeof(spaces) - 80));
325         ctx->flags &= ~E2F_FLAG_PROG_BAR;
326 }
327
328 static int e2fsck_update_progress(e2fsck_t ctx, int pass,
329                                   unsigned long cur, unsigned long max)
330 {
331         static const char spinner[] = "\\|/-";
332         char buf[80];
333         int     i;
334         float percent;
335         int     tick;
336         struct timeval  tv;
337         static int dpywidth = 0;
338
339         if (pass == 0)
340                 return 0;
341         
342         if (ctx->progress_fd) {
343                 sprintf(buf, "%d %lu %lu\n", pass, cur, max);
344                 write(ctx->progress_fd, buf, strlen(buf));
345         } else {
346                 if (ctx->flags & E2F_FLAG_PROG_SUPPRESS)
347                         return 0;
348                 if (dpywidth == 0) {
349                         dpywidth = 66 - strlen(ctx->device_name);
350                         dpywidth = 8 * (dpywidth / 8);
351                 }
352                 /*
353                  * Calculate the new progress position.  If the
354                  * percentage hasn't changed, then we skip out right
355                  * away. 
356                  */
357                 percent = calc_percent(&e2fsck_tbl, pass, cur, max);
358                 if (ctx->progress_last_percent == (int) 10 * percent)
359                         return 0;
360                 ctx->progress_last_percent = (int) 10 * percent;
361
362                 /*
363                  * If we've already updated the spinner once within
364                  * the last 1/8th of a second, no point doing it
365                  * again.
366                  */
367                 gettimeofday(&tv, NULL);
368                 tick = (tv.tv_sec << 3) + (tv.tv_usec / (1000000 / 8));
369                 if ((tick == ctx->progress_last_time) &&
370                     (cur != max) && (cur != 0))
371                         return 0;
372                 ctx->progress_last_time = tick;
373
374                 /*
375                  * Advance the spinner, and note that the progress bar
376                  * will be on the screen
377                  */
378                 ctx->progress_pos = (ctx->progress_pos+1) & 3;
379                 ctx->flags |= E2F_FLAG_PROG_BAR;
380                 
381                 i = ((percent * dpywidth) + 50) / 100;
382                 printf("%s: |%s%s", ctx->device_name,
383                        bar + (sizeof(bar) - (i+1)),
384                        spaces + (sizeof(spaces) - (dpywidth - i + 1)));
385                 if (percent == 100.0)
386                         fputc('|', stdout);
387                 else
388                         fputc(spinner[ctx->progress_pos & 3], stdout);
389                 printf(" %4.1f%%   \r", percent);
390                 if (percent == 100.0)
391                         e2fsck_clear_progbar(ctx);
392                 fflush(stdout);
393         }
394         return 0;
395 }
396
397 #define PATH_SET "PATH=/sbin"
398
399 static void reserve_stdio_fds(void)
400 {
401         int     fd;
402
403         while (1) {
404                 fd = open("/dev/null", O_RDWR);
405                 if (fd > 2)
406                         break;
407                 if (fd < 0) {
408                         fprintf(stderr, _("ERROR: Couldn't open "
409                                 "/dev/null (%s)\n"),
410                                 strerror(errno));
411                         break;
412                 }
413         }
414         close(fd);
415 }
416
417 #ifdef HAVE_SIGNAL_H
418 static void signal_progress_on(int sig)
419 {
420         e2fsck_t ctx = e2fsck_global_ctx;
421
422         if (!ctx)
423                 return;
424
425         ctx->progress = e2fsck_update_progress;
426         ctx->progress_fd = 0;
427 }
428
429 static void signal_progress_off(int sig)
430 {
431         e2fsck_t ctx = e2fsck_global_ctx;
432
433         if (!ctx)
434                 return;
435
436         e2fsck_clear_progbar(ctx);
437         ctx->progress = 0;
438 }
439 #endif
440
441 static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx)
442 {
443         int             flush = 0;
444         int             c, fd;
445 #ifdef MTRACE
446         extern void     *mallwatch;
447 #endif
448         e2fsck_t        ctx;
449         errcode_t       retval;
450 #ifdef HAVE_SIGNAL_H
451         struct sigaction        sa;
452 #endif
453
454         retval = e2fsck_allocate_context(&ctx);
455         if (retval)
456                 return retval;
457
458         *ret_ctx = ctx;
459
460         setbuf(stdout, NULL);
461         setbuf(stderr, NULL);
462         initialize_ext2_error_table();
463         
464         if (argc && *argv)
465                 ctx->program_name = *argv;
466         else
467                 ctx->program_name = "e2fsck";
468         while ((c = getopt (argc, argv, "panyrcC:B:dfvtFVM:b:I:j:P:l:L:N:Ss")) != EOF)
469                 switch (c) {
470                 case 'C':
471                         ctx->progress = e2fsck_update_progress;
472                         ctx->progress_fd = atoi(optarg);
473                         if (!ctx->progress_fd)
474                                 break;
475                         /* Validate the file descriptor to avoid disasters */
476                         fd = dup(ctx->progress_fd);
477                         if (fd < 0) {
478                                 fprintf(stderr,
479                                 _("Error validating file descriptor %d: %s\n"),
480                                         ctx->progress_fd,
481                                         error_message(errno));
482                                 fatal_error(ctx,
483                         _("Invalid completion information file descriptor"));
484                         } else
485                                 close(fd);
486                         break;
487                 case 'p':
488                 case 'a':
489                         ctx->options |= E2F_OPT_PREEN;
490                         ctx->options &= ~(E2F_OPT_YES|E2F_OPT_NO);
491                         break;
492                 case 'n':
493                         ctx->options |= E2F_OPT_NO;
494                         ctx->options &= ~(E2F_OPT_YES|E2F_OPT_PREEN);
495                         break;
496                 case 'y':
497                         ctx->options |= E2F_OPT_YES;
498                         ctx->options &= ~(E2F_OPT_PREEN|E2F_OPT_NO);
499                         break;
500                 case 't':
501 #ifdef RESOURCE_TRACK
502                         if (ctx->options & E2F_OPT_TIME)
503                                 ctx->options |= E2F_OPT_TIME2;
504                         else
505                                 ctx->options |= E2F_OPT_TIME;
506 #else
507                         fprintf(stderr, _("The -t option is not "
508                                 "supported on this version of e2fsck.\n"));
509 #endif
510                         break;
511                 case 'c':
512                         cflag++;
513                         ctx->options |= E2F_OPT_CHECKBLOCKS;
514                         break;
515                 case 'r':
516                         /* What we do by default, anyway! */
517                         break;
518                 case 'b':
519                         ctx->use_superblock = atoi(optarg);
520                         break;
521                 case 'B':
522                         blocksize = atoi(optarg);
523                         break;
524                 case 'I':
525                         ctx->inode_buffer_blocks = atoi(optarg);
526                         break;
527                 case 'j':
528                         ctx->journal_name = optarg;
529                         break;
530                 case 'P':
531                         ctx->process_inode_size = atoi(optarg);
532                         break;
533                 case 'L':
534                         replace_bad_blocks++;
535                 case 'l':
536                         bad_blocks_file = (char *) malloc(strlen(optarg)+1);
537                         if (!bad_blocks_file)
538                                 fatal_error(ctx,
539                                             "Couldn't malloc bad_blocks_file");
540                         strcpy(bad_blocks_file, optarg);
541                         break;
542                 case 'd':
543                         ctx->options |= E2F_OPT_DEBUG;
544                         break;
545                 case 'f':
546                         force = 1;
547                         break;
548                 case 'F':
549                         flush = 1;
550                         break;
551                 case 'v':
552                         verbose = 1;
553                         break;
554                 case 'V':
555                         show_version_only = 1;
556                         break;
557 #ifdef MTRACE
558                 case 'M':
559                         mallwatch = (void *) strtol(optarg, NULL, 0);
560                         break;
561 #endif
562                 case 'N':
563                         ctx->device_name = optarg;
564                         break;
565 #ifdef ENABLE_SWAPFS
566                 case 's':
567                         normalize_swapfs = 1;
568                 case 'S':
569                         swapfs = 1;
570                         break;
571 #else
572                 case 's':
573                 case 'S':
574                         fprintf(stderr, _("Byte-swapping filesystems "
575                                           "not compiled in this version "
576                                           "of e2fsck\n"));
577                         exit(1);
578 #endif
579                 default:
580                         usage(ctx);
581                 }
582         if (show_version_only)
583                 return 0;
584         if (optind != argc - 1)
585                 usage(ctx);
586         if ((ctx->options & E2F_OPT_NO) && !bad_blocks_file &&
587             !cflag && !swapfs)
588                 ctx->options |= E2F_OPT_READONLY;
589         ctx->filesystem_name = argv[optind];
590         if (flush) {
591                 int     fd = open(ctx->filesystem_name, O_RDONLY, 0);
592
593                 if (fd < 0) {
594                         com_err("open", errno,
595                                 _("while opening %s for flushing"),
596                                 ctx->filesystem_name);
597                         fatal_error(ctx, 0);
598                 }
599                 if ((retval = ext2fs_sync_device(fd, 1))) {
600                         com_err("ext2fs_sync_device", retval,
601                                 _("while trying to flush %s"),
602                                 ctx->filesystem_name);
603                         fatal_error(ctx, 0);
604                 }
605                 close(fd);
606         }
607 #ifdef ENABLE_SWAPFS
608         if (swapfs) {
609                 if (cflag || bad_blocks_file) {
610                         fprintf(stderr, _("Incompatible options not "
611                                 "allowed when byte-swapping.\n"));
612                         exit(FSCK_USAGE);
613                 }
614         }
615 #endif
616 #ifdef HAVE_SIGNAL_H
617         /*
618          * Set up signal action
619          */
620         memset(&sa, 0, sizeof(struct sigaction));
621 #ifdef SA_RESTART
622         sa.sa_flags = SA_RESTART;
623 #endif
624         e2fsck_global_ctx = ctx;
625         sa.sa_handler = signal_progress_on;
626         sigaction(SIGUSR1, &sa, 0);
627         sa.sa_handler = signal_progress_off;
628         sigaction(SIGUSR2, &sa, 0);
629 #endif
630
631         /* Update our PATH to include /sbin if we need to run badblocks  */
632         if (cflag) {
633                 char *oldpath = getenv("PATH");
634                 if (oldpath) {
635                         char *newpath;
636
637                         newpath = (char *) malloc(sizeof (PATH_SET) + 1 +
638                                                   strlen (oldpath));
639                         if (!newpath)
640                                 fatal_error(ctx, "Couldn't malloc() newpath");
641                         strcpy (newpath, PATH_SET);
642                         strcat (newpath, ":");
643                         strcat (newpath, oldpath);
644                         putenv (newpath);
645                 } else
646                         putenv (PATH_SET);
647         }
648         return 0;
649 }
650
651 static const char *my_ver_string = E2FSPROGS_VERSION;
652 static const char *my_ver_date = E2FSPROGS_DATE;
653                                         
654 int main (int argc, char *argv[])
655 {
656         errcode_t       retval = 0;
657         int             exit_value = FSCK_OK;
658         int             i;
659         ext2_filsys     fs = 0;
660         io_manager      io_ptr;
661         struct ext2_super_block *sb;
662         const char      *lib_ver_date;
663         int             my_ver, lib_ver;
664         e2fsck_t        ctx;
665         struct problem_context pctx;
666         int flags, run_result;
667         
668         clear_problem_context(&pctx);
669 #ifdef MTRACE
670         mtrace();
671 #endif
672 #ifdef MCHECK
673         mcheck(0);
674 #endif
675 #ifdef ENABLE_NLS
676         setlocale(LC_MESSAGES, "");
677         bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
678         textdomain(NLS_CAT_NAME);
679 #endif
680         my_ver = ext2fs_parse_version_string(my_ver_string);
681         lib_ver = ext2fs_get_library_version(0, &lib_ver_date);
682         if (my_ver > lib_ver) {
683                 fprintf( stderr, _("Error: ext2fs library version "
684                         "out of date!\n"));
685                 show_version_only++;
686         }
687         
688         retval = PRS(argc, argv, &ctx);
689         if (retval) {
690                 com_err("e2fsck", retval,
691                         _("while trying to initialize program"));
692                 exit(FSCK_ERROR);
693         }
694         reserve_stdio_fds();
695         
696 #ifdef RESOURCE_TRACK
697         init_resource_track(&ctx->global_rtrack);
698 #endif
699
700         if (!(ctx->options & E2F_OPT_PREEN) || show_version_only)
701                 fprintf (stderr, _("e2fsck %s, %s for EXT2 FS %s, %s\n"),
702                          my_ver_string, my_ver_date, EXT2FS_VERSION,
703                          EXT2FS_DATE);
704
705         if (show_version_only) {
706                 fprintf(stderr, _("\tUsing %s, %s\n"),
707                         error_message(EXT2_ET_BASE), lib_ver_date);
708                 exit(FSCK_OK);
709         }
710         
711         check_mount(ctx);
712         
713         if (!(ctx->options & E2F_OPT_PREEN) &&
714             !(ctx->options & E2F_OPT_NO) &&
715             !(ctx->options & E2F_OPT_YES)) {
716                 if (!isatty (0) || !isatty (1))
717                         fatal_error(ctx,
718                                     _("need terminal for interactive repairs"));
719         }
720         ctx->superblock = ctx->use_superblock;
721 restart:
722 #if 1
723         io_ptr = unix_io_manager;
724 #else
725         io_ptr = test_io_manager;
726         test_io_backing_manager = unix_io_manager;
727 #endif
728         flags = 0;
729         if ((ctx->options & E2F_OPT_READONLY) == 0)
730                 flags |= EXT2_FLAG_RW;
731
732         if (ctx->superblock && blocksize) {
733                 retval = ext2fs_open(ctx->filesystem_name, flags,
734                                      ctx->superblock, blocksize, io_ptr, &fs);
735         } else if (ctx->superblock) {
736                 for (i=0; possible_block_sizes[i]; i++) {
737                         retval = ext2fs_open(ctx->filesystem_name, flags,
738                                              ctx->superblock,
739                                              possible_block_sizes[i],
740                                              io_ptr, &fs);
741                         if (!retval)
742                                 break;
743                 }
744         } else 
745                 retval = ext2fs_open(ctx->filesystem_name, flags, 
746                                      0, 0, io_ptr, &fs);
747         if (!ctx->superblock && !(ctx->options & E2F_OPT_PREEN) && 
748             ((retval == EXT2_ET_BAD_MAGIC) ||
749              ((retval == 0) && ext2fs_check_desc(fs)))) {
750                 if (!fs || (fs->group_desc_count > 1)) {
751                         printf(_("%s trying backup blocks...\n"),
752                                retval ? _("Couldn't find ext2 superblock,") :
753                                _("Group descriptors look bad..."));
754                         ctx->superblock = get_backup_sb(fs);
755                         if (fs)
756                                 ext2fs_close(fs);
757                         goto restart;
758                 }
759         }
760         if (retval) {
761                 com_err(ctx->program_name, retval, _("while trying to open %s"),
762                         ctx->filesystem_name);
763                 if (retval == EXT2_ET_REV_TOO_HIGH) {
764                         printf(_("The filesystem revision is apparently "
765                                "too high for this version of e2fsck.\n"
766                                "(Or the filesystem superblock "
767                                "is corrupt)\n\n"));
768                         fix_problem(ctx, PR_0_SB_CORRUPT, &pctx);
769                 } else if (retval == EXT2_ET_SHORT_READ)
770                         printf(_("Could this be a zero-length partition?\n"));
771                 else if ((retval == EPERM) || (retval == EACCES))
772                         printf(_("You must have %s access to the "
773                                "filesystem or be root\n"),
774                                (ctx->options & E2F_OPT_READONLY) ?
775                                "r/o" : "r/w");
776                 else if (retval == ENXIO)
777                         printf(_("Possibly non-existent or swap device?\n"));
778 #ifdef EROFS
779                 else if (retval == EROFS)
780                         printf(_("Disk write-protected; use the -n option "
781                                "to do a read-only\n"
782                                "check of the device.\n"));
783 #endif
784                 else
785                         fix_problem(ctx, PR_0_SB_CORRUPT, &pctx);
786                 fatal_error(ctx, 0);
787         }
788         ctx->fs = fs;
789         fs->priv_data = ctx;
790         sb = fs->super;
791         if (sb->s_rev_level > E2FSCK_CURRENT_REV) {
792                 com_err(ctx->program_name, EXT2_ET_REV_TOO_HIGH,
793                         _("while trying to open %s"),
794                         ctx->filesystem_name);
795         get_newer:
796                 fatal_error(ctx, _("Get a newer version of e2fsck!"));
797         }
798
799         /*
800          * Set the device name, which is used whenever we print error
801          * or informational messages to the user.
802          */
803         if (ctx->device_name == 0 &&
804             (sb->s_volume_name[0] != 0)) {
805                 char *cp = malloc(sizeof(sb->s_volume_name)+1);
806                 if (cp) {
807                         strncpy(cp, sb->s_volume_name,
808                                 sizeof(sb->s_volume_name));
809                         cp[sizeof(sb->s_volume_name)] = 0;
810                         ctx->device_name = cp;
811                 }
812         }
813         if (ctx->device_name == 0)
814                 ctx->device_name = ctx->filesystem_name;
815
816         /*
817          * Make sure the ext3 superblock fields are consistent.
818          */
819         retval = e2fsck_check_ext3_journal(ctx);
820         if (retval) {
821                 com_err(ctx->program_name, retval,
822                         _("while checking ext3 journal for %s"),
823                         ctx->device_name);
824                 ext2fs_close(ctx->fs);
825                 fatal_error(ctx, 0);
826         }
827
828         /*
829          * Check to see if we need to do ext3-style recovery.  If so,
830          * do it, and then restart the fsck.
831          */
832         if (sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) {
833                 if (ctx->options & E2F_OPT_READONLY) {
834                         printf(_("Warning: skipping journal recovery "
835                                  "because doing a read-only filesystem "
836                                  "check.\n"));
837                         io_channel_flush(ctx->fs->io);
838                 } else {
839                         retval = e2fsck_run_ext3_journal(ctx);
840                         if (retval) {
841                                 com_err(ctx->program_name, retval,
842                                 _("while recovering ext3 journal of %s"),
843                                         ctx->device_name);
844                                 fatal_error(ctx, 0);
845                         }
846                         ext2fs_close(ctx->fs);
847                         ctx->fs = 0;
848                         goto restart;
849                 }
850         }
851
852         /*
853          * Check for compatibility with the feature sets.  We need to
854          * be more stringent than ext2fs_open().
855          */
856         if ((sb->s_feature_compat & ~EXT2_LIB_FEATURE_COMPAT_SUPP) ||
857             (sb->s_feature_incompat & ~EXT2_LIB_FEATURE_INCOMPAT_SUPP)) {
858                 com_err(ctx->program_name, EXT2_ET_UNSUPP_FEATURE,
859                         "(%s)", ctx->device_name);
860                 goto get_newer;
861         }
862         if (sb->s_feature_ro_compat & ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP) {
863                 com_err(ctx->program_name, EXT2_ET_RO_UNSUPP_FEATURE,
864                         "(%s)", ctx->device_name);
865                 goto get_newer;
866         }
867 #ifdef ENABLE_COMPRESSION
868         if (sb->s_feature_incompat & EXT2_FEATURE_INCOMPAT_COMPRESSION)
869                 com_err(ctx->program_name, 0,
870                         _("Warning: compression support is experimental.\n"));
871 #endif
872         
873         /*
874          * If the user specified a specific superblock, presumably the
875          * master superblock has been trashed.  So we mark the
876          * superblock as dirty, so it can be written out.
877          */
878         if (ctx->superblock &&
879             !(ctx->options & E2F_OPT_READONLY))
880                 ext2fs_mark_super_dirty(fs);
881
882         /*
883          * Don't overwrite the backup superblock and block
884          * descriptors, until we're sure the filesystem is OK....
885          */
886         fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
887
888         ehandler_init(fs->io);
889
890         if (ctx->superblock)
891                 set_latch_flags(PR_LATCH_RELOC, PRL_LATCHED, 0);
892         check_super_block(ctx);
893         if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
894                 fatal_error(ctx, 0);
895         check_if_skip(ctx);
896         if (bad_blocks_file)
897                 read_bad_blocks_file(ctx, bad_blocks_file, replace_bad_blocks);
898         else if (cflag)
899                 test_disk(ctx);
900         if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
901                 fatal_error(ctx, 0);
902 #ifdef ENABLE_SWAPFS
903         if (normalize_swapfs) {
904                 if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ==
905                     ext2fs_native_flag()) {
906                         fprintf(stderr, _("%s: Filesystem byte order "
907                                 "already normalized.\n"), ctx->device_name);
908                         fatal_error(ctx, 0);
909                 }
910         }
911         if (swapfs) {
912                 swap_filesys(ctx);
913                 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
914                         fatal_error(ctx, 0);
915         }
916 #endif
917
918         /*
919          * Mark the system as valid, 'til proven otherwise
920          */
921         ext2fs_mark_valid(fs);
922
923         retval = ext2fs_read_bb_inode(fs, &fs->badblocks);
924         if (retval) {
925                 com_err(ctx->program_name, retval,
926                         _("while reading bad blocks inode"));
927                 preenhalt(ctx);
928                 printf(_("This doesn't bode well,"
929                          " but we'll try to go on...\n"));
930         }
931
932         run_result = e2fsck_run(ctx);
933         e2fsck_clear_progbar(ctx);
934         if (run_result == E2F_FLAG_RESTART) {
935                 printf(_("Restarting e2fsck from the beginning...\n"));
936                 retval = e2fsck_reset_context(ctx);
937                 if (retval) {
938                         com_err(ctx->program_name, retval,
939                                 _("while resetting context"));
940                         fatal_error(ctx, 0);
941                 }
942                 ext2fs_close(fs);
943                 goto restart;
944         }
945         if (run_result & E2F_FLAG_SIGNAL_MASK)
946                 fatal_error(ctx, 0);
947         if (run_result & E2F_FLAG_CANCEL)
948                 ext2fs_unmark_valid(fs);
949
950 #ifdef MTRACE
951         mtrace_print("Cleanup");
952 #endif
953         if (ext2fs_test_changed(fs)) {
954                 exit_value = FSCK_NONDESTRUCT;
955                 if (!(ctx->options & E2F_OPT_PREEN))
956                     printf(_("\n%s: ***** FILE SYSTEM WAS MODIFIED *****\n"),
957                                ctx->device_name);
958                 if (root_filesystem && !read_only_root) {
959                         printf(_("%s: ***** REBOOT LINUX *****\n"),
960                                ctx->device_name);
961                         exit_value = FSCK_REBOOT;
962                 }
963         }
964         if (ext2fs_test_valid(fs))
965                 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
966         else {
967                 printf(_("\n%s: ********** WARNING: Filesystem still has "
968                          "errors **********\n\n"), ctx->device_name);
969                 exit_value = FSCK_UNCORRECTED;
970         }
971         if (!(ctx->options & E2F_OPT_READONLY)) {
972                 if (ext2fs_test_valid(fs)) {
973                         if (!(sb->s_state & EXT2_VALID_FS))
974                                 exit_value = FSCK_NONDESTRUCT;
975                         sb->s_state = EXT2_VALID_FS;
976                 } else
977                         sb->s_state &= ~EXT2_VALID_FS;
978                 sb->s_mnt_count = 0;
979                 sb->s_lastcheck = time(NULL);
980                 ext2fs_mark_super_dirty(fs);
981         }
982         show_stats(ctx);
983
984         e2fsck_write_bitmaps(ctx);
985         
986         ext2fs_close(fs);
987         ctx->fs = NULL;
988         e2fsck_free_context(ctx);
989         
990 #ifdef RESOURCE_TRACK
991         if (ctx->options & E2F_OPT_TIME)
992                 print_resource_track(NULL, &ctx->global_rtrack);
993 #endif
994
995         return exit_value;
996 }