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

Generated by: LCOV version 1.14