LCOV - code coverage report
Current view: top level - fsck - main.c (source / functions) Hit Total Coverage
Test: gfs2-utils.info Lines: 128 201 63.7 %
Date: 2023-09-27 13:48:55 Functions: 6 9 66.7 %

          Line data    Source code
       1             : #include "clusterautoconfig.h"
       2             : 
       3             : #include <unistd.h>
       4             : #include <stdio.h>
       5             : #include <stdint.h>
       6             : #include <stdlib.h>
       7             : #include <libgen.h>
       8             : #include <string.h>
       9             : #include <stdarg.h>
      10             : #include <ctype.h>
      11             : #include <signal.h>
      12             : #include <libintl.h>
      13             : #include <locale.h>
      14             : #include <sys/time.h>
      15             : #include <time.h>
      16             : #define _(String) gettext(String)
      17             : #include <syslog.h>
      18             : 
      19             : #include <logging.h>
      20             : #include "copyright.cf"
      21             : #include "libgfs2.h"
      22             : #include "fsck.h"
      23             : #include "link.h"
      24             : #include "osi_list.h"
      25             : #include "metawalk.h"
      26             : #include "util.h"
      27             : 
      28             : struct lgfs2_inode *lf_dip = NULL; /* Lost and found directory inode */
      29             : int lf_was_created = 0;
      30             : uint64_t last_fs_block, last_reported_block = -1;
      31             : int64_t last_reported_fblock = -1000000;
      32             : int skip_this_pass = 0, fsck_abort = 0;
      33             : int errors_found = 0, errors_corrected = 0;
      34             : uint64_t last_data_block;
      35             : uint64_t first_data_block;
      36             : int dups_found = 0, dups_found_first = 0;
      37             : int sb_fixed = 0;
      38             : int print_level = MSG_NOTICE;
      39             : 
      40             : static const char *pass_name = "";
      41             : 
      42           0 : static void usage(char *name)
      43             : {
      44           0 :         printf("Usage: %s [-afhnpqvVy] <device> \n", basename(name));
      45           0 : }
      46             : 
      47           0 : static void version(void)
      48             : {
      49           0 :         printf( _("GFS2 fsck %s (built %s %s)\n"),
      50             :                VERSION, __DATE__, __TIME__);
      51           0 :         printf(REDHAT_COPYRIGHT "\n");
      52           0 : }
      53             : 
      54          64 : static int read_cmdline(int argc, char **argv, struct fsck_options *gopts)
      55             : {
      56             :         int c;
      57             : 
      58         127 :         while ((c = getopt(argc, argv, "afhnpqvyV")) != -1) {
      59          70 :                 switch(c) {
      60             : 
      61           4 :                 case 'a':
      62             :                 case 'p':
      63           4 :                         if (gopts->yes || gopts->no) {
      64           2 :                                 fprintf(stderr, _("Options -p/-a, -y and -n may not be used together\n"));
      65           2 :                                 return FSCK_USAGE;
      66             :                         }
      67           2 :                         gopts->preen = 1;
      68           2 :                         gopts->yes = 1;
      69           2 :                         break;
      70           0 :                 case 'f':
      71           0 :                         gopts->force = 1;
      72           0 :                         break;
      73           0 :                 case 'h':
      74           0 :                         usage(argv[0]);
      75           0 :                         exit(FSCK_OK);
      76             :                         break;
      77          46 :                 case 'n':
      78          46 :                         if (gopts->yes || gopts->preen) {
      79           2 :                                 fprintf(stderr, _("Options -p/-a, -y and -n may not be used together\n"));
      80           2 :                                 return FSCK_USAGE;
      81             :                         }
      82          44 :                         gopts->no = 1;
      83          44 :                         break;
      84           0 :                 case 'q':
      85           0 :                         decrease_verbosity();
      86           0 :                         break;
      87           0 :                 case 'v':
      88           0 :                         increase_verbosity();
      89           0 :                         break;
      90           0 :                 case 'V':
      91           0 :                         version();
      92           0 :                         exit(FSCK_OK);
      93             :                         break;
      94          19 :                 case 'y':
      95          19 :                         if (gopts->no || gopts->preen) {
      96           2 :                                 fprintf(stderr, _("Options -p/-a, -y and -n may not be used together\n"));
      97           2 :                                 return FSCK_USAGE;
      98             :                         }
      99          17 :                         gopts->yes = 1;
     100          17 :                         break;
     101           1 :                 case ':':
     102             :                 case '?':
     103           1 :                         fprintf(stderr, _("Please use '-h' for help.\n"));
     104           1 :                         return FSCK_USAGE;
     105           0 :                 default:
     106           0 :                         fprintf(stderr, _("Invalid option %c\n"), c);
     107           0 :                         return FSCK_USAGE;
     108             : 
     109             :                 }
     110             :         }
     111          57 :         if (argc > optind) {
     112          57 :                 gopts->device = (argv[optind]);
     113          57 :                 if (!gopts->device) {
     114           0 :                         fprintf(stderr, _("Please use '-h' for help.\n"));
     115           0 :                         return FSCK_USAGE;
     116             :                 }
     117             :         } else {
     118           0 :                 fprintf(stderr, _("No device specified (Please use '-h' for help)\n"));
     119           0 :                 return FSCK_USAGE;
     120             :         }
     121          57 :         return 0;
     122             : }
     123             : 
     124           0 : static void interrupt(int sig)
     125             : {
     126             :         char response;
     127             :         char progress[1024];
     128             : 
     129           0 :         if (!last_reported_block || last_reported_block == last_fs_block)
     130           0 :                 snprintf(progress, sizeof(progress), _("progress unknown.\n"));
     131             :         else
     132           0 :                 snprintf(progress, sizeof(progress),
     133           0 :                         _("processing block %"PRIu64" out of %"PRIu64"\n"),
     134             :                         last_reported_block, last_fs_block);
     135             : 
     136           0 :         response = generic_interrupt("fsck.gfs2", pass_name, progress,
     137           0 :                                      _("Do you want to abort fsck.gfs2, skip " \
     138             :                                      "the rest of this pass or continue " \
     139             :                                      "(a/s/c)?"), "asc");
     140           0 :         if (tolower(response) == 's') {
     141           0 :                 skip_this_pass = 1;
     142           0 :                 return;
     143             :         }
     144           0 :         else if (tolower(response) == 'a') {
     145           0 :                 fsck_abort = 1;
     146           0 :                 return;
     147             :         }
     148             : }
     149             : 
     150          56 : static int check_statfs(struct fsck_cx *cx)
     151             : {
     152          56 :         struct osi_node *n, *next = NULL;
     153             :         struct lgfs2_rgrp_tree *rgd;
     154             :         struct gfs2_statfs_change sc;
     155          56 :         struct lgfs2_sbd *sdp = cx->sdp;
     156             :         uint64_t sc_total;
     157             :         uint64_t sc_free;
     158             :         uint64_t sc_dinodes;
     159             :         int count;
     160             : 
     161             :         /* Read the current statfs values */
     162          56 :         count = lgfs2_readi(sdp->md.statfs, &sc, 0, sdp->md.statfs->i_size);
     163          56 :         if (count != sizeof(struct gfs2_statfs_change)) {
     164           0 :                 log_err(_("Failed to read statfs values (%d of %"PRIu64" read)\n"),
     165             :                         count, sdp->md.statfs->i_size);
     166           0 :                 return FSCK_ERROR;
     167             :         }
     168          56 :         sc_total = be64_to_cpu(sc.sc_total);
     169          56 :         sc_free = be64_to_cpu(sc.sc_free);
     170          56 :         sc_dinodes = be64_to_cpu(sc.sc_dinodes);
     171             : 
     172             :         /* Calculate the real values from the rgrp information */
     173          56 :         sdp->blks_total = 0;
     174          56 :         sdp->blks_alloced = 0;
     175          56 :         sdp->dinodes_alloced = 0;
     176             : 
     177        4415 :         for (n = osi_first(&sdp->rgtree); n; n = next) {
     178        4359 :                 next = osi_next(n);
     179        4359 :                 rgd = (struct lgfs2_rgrp_tree *)n;
     180        4359 :                 sdp->blks_total += rgd->rt_data;
     181        4359 :                 sdp->blks_alloced += (rgd->rt_data - rgd->rt_free);
     182        4359 :                 sdp->dinodes_alloced += rgd->rt_dinodes;
     183             :         }
     184             : 
     185             :         /* See if they match */
     186          56 :         if (sc_total == sdp->blks_total &&
     187          56 :             sc_free == (sdp->blks_total - sdp->blks_alloced) &&
     188          56 :             sc_dinodes == sdp->dinodes_alloced) {
     189          56 :                 log_info( _("The statfs file is accurate.\n"));
     190          56 :                 return 0;
     191             :         }
     192           0 :         log_err( _("The statfs file is wrong:\n\n"));
     193           0 :         log_err( _("Current statfs values:\n"));
     194           0 :         log_err( _("blocks:  %"PRId64" (0x%"PRIx64")\n"), sc_total, sc_total);
     195           0 :         log_err( _("free:    %"PRId64" (0x%"PRIx64")\n"), sc_free, sc_free);
     196           0 :         log_err( _("dinodes: %"PRId64" (0x%"PRIx64")\n\n"), sc_dinodes, sc_dinodes);
     197           0 :         log_err( _("Calculated statfs values:\n"));
     198           0 :         log_err( _("blocks:  %"PRIu64" (0x%"PRIx64")\n"),
     199             :                 sdp->blks_total, sdp->blks_total);
     200           0 :         log_err( _("free:    %"PRIu64" (0x%"PRIx64")\n"),
     201             :                 (sdp->blks_total - sdp->blks_alloced),
     202             :                 (sdp->blks_total - sdp->blks_alloced));
     203           0 :         log_err( _("dinodes: %"PRIu64" (0x%"PRIx64")\n"),
     204             :                 sdp->dinodes_alloced, sdp->dinodes_alloced);
     205             : 
     206           0 :         errors_found++;
     207           0 :         if (!query(cx, _("Okay to fix the master statfs file? (y/n)"))) {
     208           0 :                 log_err( _("The statfs file was not fixed.\n"));
     209           0 :                 return 0;
     210             :         }
     211             : 
     212           0 :         lgfs2_init_statfs(sdp, NULL);
     213           0 :         log_err( _("The statfs file was fixed.\n"));
     214           0 :         errors_corrected++;
     215           0 :         return 0;
     216             : }
     217             : 
     218             : static const struct fsck_pass passes[] = {
     219             :         { .name = "pass1",  .f = pass1 },
     220             :         { .name = "pass1b", .f = pass1b },
     221             :         { .name = "pass2",  .f = pass2 },
     222             :         { .name = "pass3",  .f = pass3 },
     223             :         { .name = "pass4",  .f = pass4 },
     224             :         { .name = "check_statfs", .f = check_statfs },
     225             :         { .name = NULL, }
     226             : };
     227             : 
     228         336 : static int fsck_pass(const struct fsck_pass *p, struct fsck_cx *cx)
     229             : {
     230             :         int ret;
     231             :         struct timeval timer;
     232             : 
     233         336 :         if (fsck_abort)
     234           0 :                 return FSCK_CANCELED;
     235         336 :         pass_name = p->name;
     236             : 
     237         336 :         log_notice( _("Starting %s\n"), p->name);
     238         336 :         gettimeofday(&timer, NULL);
     239             : 
     240         336 :         ret = p->f(cx);
     241         336 :         if (ret)
     242           0 :                 exit(ret);
     243         336 :         if (skip_this_pass || fsck_abort) {
     244           0 :                 skip_this_pass = 0;
     245           0 :                 log_notice( _("%s interrupted   \n"), p->name);
     246           0 :                 return FSCK_CANCELED;
     247             :         }
     248             : 
     249         336 :         print_pass_duration(p->name, &timer);
     250         336 :         return 0;
     251             : }
     252             : 
     253             : /*
     254             :  * on_exit() is non-standard but useful for reporting the exit status if it's
     255             :  * available.
     256             :  */
     257             : #ifdef HAVE_ON_EXIT
     258          64 : static void exitlog(int status, void *unused)
     259             : {
     260          64 :         syslog(LOG_INFO, "exit: %d", status);
     261          64 : }
     262             : #else
     263             : static void exitlog(void)
     264             : {
     265             :         syslog(LOG_INFO, "exit.");
     266             : }
     267             : #endif
     268             : 
     269          64 : static void startlog(int argc, char **argv)
     270             : {
     271             :         int i;
     272             :         char *cmd, *p;
     273             :         size_t len;
     274             : 
     275         197 :         for (len = i = 0; i < argc; i++)
     276         133 :                 len += strlen(argv[i]);
     277          64 :         len += argc; /* Add spaces and '\0' */
     278             : 
     279          64 :         cmd = malloc(len);
     280          64 :         if (cmd == NULL) {
     281           0 :                 perror(argv[0]);
     282           0 :                 exit(FSCK_ERROR);
     283             :         }
     284          64 :         p = cmd;
     285         197 :         for (i = 0; i < argc; i++, p++) {
     286         133 :                 p = stpcpy(p, argv[i]);
     287         133 :                 *p = ' ';
     288             :         }
     289          64 :         *(--p) = '\0';
     290          64 :         syslog(LOG_INFO, "started: %s", cmd);
     291          64 :         free(cmd);
     292          64 : }
     293             : 
     294             : #ifndef UNITTESTS
     295          64 : int main(int argc, char **argv)
     296             : {
     297          64 :         struct fsck_options opts = {0};
     298             :         struct lgfs2_sbd sb;
     299          64 :         struct fsck_cx cx = {
     300             :                 .sdp = &sb,
     301             :                 .opts = &opts,
     302             :         };
     303             :         int j;
     304             :         int i;
     305          64 :         int error = 0;
     306          64 :         int all_clean = 0;
     307          64 :         struct sigaction act = { .sa_handler = interrupt, };
     308             : 
     309          64 :         setlocale(LC_ALL, "");
     310          64 :         textdomain("gfs2-utils");
     311             : 
     312          64 :         openlog("fsck.gfs2", LOG_CONS|LOG_PID, LOG_USER);
     313          64 :         startlog(argc - 1, &argv[1]);
     314             : #ifdef HAVE_ON_EXIT
     315          64 :         on_exit(exitlog, NULL);
     316             : #else
     317             :         atexit(exitlog);
     318             : #endif
     319             : 
     320          64 :         memset(&sb, 0, sizeof(sb));
     321             : 
     322          64 :         if ((error = read_cmdline(argc, argv, &opts)))
     323           7 :                 exit(error);
     324          57 :         setbuf(stdout, NULL);
     325          57 :         log_notice( _("Initializing fsck\n"));
     326          57 :         if ((error = initialize(&cx, &all_clean)))
     327           1 :                 exit(error);
     328             : 
     329          56 :         if (!opts.force && all_clean && opts.preen) {
     330           0 :                 log_err( _("%s: clean.\n"), opts.device);
     331           0 :                 destroy(&cx);
     332           0 :                 exit(FSCK_OK);
     333             :         }
     334             : 
     335          56 :         sigaction(SIGINT, &act, NULL);
     336             : 
     337         392 :         for (i = 0; passes[i].name; i++)
     338         336 :                 error = fsck_pass(passes + i, &cx);
     339             : 
     340             :         /* Free up our system inodes */
     341          56 :         lgfs2_inode_put(&sb.md.inum);
     342          56 :         lgfs2_inode_put(&sb.md.statfs);
     343         119 :         for (j = 0; j < sb.md.journals; j++)
     344          63 :                 lgfs2_inode_put(&sb.md.journal[j]);
     345          56 :         free(sb.md.journal);
     346          56 :         sb.md.journal = NULL;
     347          56 :         lgfs2_inode_put(&sb.md.jiinode);
     348          56 :         lgfs2_inode_put(&sb.md.riinode);
     349          56 :         lgfs2_inode_put(&sb.md.qinode);
     350          56 :         lgfs2_inode_put(&sb.md.pinode);
     351          56 :         lgfs2_inode_put(&sb.md.rooti);
     352          56 :         lgfs2_inode_put(&sb.master_dir);
     353          56 :         if (lf_dip)
     354           0 :                 lgfs2_inode_put(&lf_dip);
     355             : 
     356          56 :         if (!opts.no && errors_corrected)
     357          14 :                 log_notice( _("Writing changes to disk\n"));
     358          56 :         fsync(sb.device_fd);
     359          56 :         link1_destroy(&nlink1map);
     360          56 :         link1_destroy(&clink1map);
     361          56 :         destroy(&cx);
     362          56 :         if (sb_fixed)
     363           6 :                 log_warn(_("Superblock was reset. Use tunegfs2 to manually "
     364             :                            "set lock table before mounting.\n"));
     365          56 :         log_notice( _("fsck.gfs2 complete\n"));
     366             : 
     367          56 :         if (!error) {
     368          56 :                 if (!errors_found)
     369          42 :                         error = FSCK_OK;
     370          14 :                 else if (errors_found == errors_corrected)
     371          14 :                         error = FSCK_NONDESTRUCT;
     372             :                 else
     373           0 :                         error = FSCK_UNCORRECTED;
     374             :         }
     375          56 :         exit(error);
     376             : }
     377             : #endif /* UNITTESTS */

Generated by: LCOV version 1.14