LCOV - code coverage report
Current view: top level - fsck - main.c (source / functions) Coverage Total Hit
Test: gfs2-utils.info Lines: 63.7 % 201 128
Test Date: 2024-03-07 16:24:06 Functions: 66.7 % 9 6

            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           65 : static int read_cmdline(int argc, char **argv, struct fsck_options *gopts)
      54              : {
      55              :         int c;
      56              : 
      57          129 :         while ((c = getopt(argc, argv, "afhnpqvyV")) != -1) {
      58           71 :                 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           47 :                 case 'n':
      77           47 :                         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           45 :                         gopts->no = 1;
      82           45 :                         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           58 :         if (argc > optind) {
     111           58 :                 gopts->device = (argv[optind]);
     112           58 :                 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           58 :         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           57 : static int check_statfs(struct fsck_cx *cx)
     150              : {
     151           57 :         struct osi_node *n, *next = NULL;
     152              :         struct lgfs2_rgrp_tree *rgd;
     153              :         struct gfs2_statfs_change sc;
     154           57 :         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           57 :         count = lgfs2_readi(sdp->md.statfs, &sc, 0, sdp->md.statfs->i_size);
     162           57 :         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           57 :         sc_total = be64_to_cpu(sc.sc_total);
     168           57 :         sc_free = be64_to_cpu(sc.sc_free);
     169           57 :         sc_dinodes = be64_to_cpu(sc.sc_dinodes);
     170              : 
     171              :         /* Calculate the real values from the rgrp information */
     172           57 :         sdp->blks_total = 0;
     173           57 :         sdp->blks_alloced = 0;
     174           57 :         sdp->dinodes_alloced = 0;
     175              : 
     176         4497 :         for (n = osi_first(&sdp->rgtree); n; n = next) {
     177         4440 :                 next = osi_next(n);
     178         4440 :                 rgd = (struct lgfs2_rgrp_tree *)n;
     179         4440 :                 sdp->blks_total += rgd->rt_data;
     180         4440 :                 sdp->blks_alloced += (rgd->rt_data - rgd->rt_free);
     181         4440 :                 sdp->dinodes_alloced += rgd->rt_dinodes;
     182              :         }
     183              : 
     184              :         /* See if they match */
     185           57 :         if (sc_total == sdp->blks_total &&
     186           57 :             sc_free == (sdp->blks_total - sdp->blks_alloced) &&
     187           57 :             sc_dinodes == sdp->dinodes_alloced) {
     188           57 :                 log_info( _("The statfs file is accurate.\n"));
     189           57 :                 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          342 : static int fsck_pass(const struct fsck_pass *p, struct fsck_cx *cx)
     228              : {
     229              :         int ret;
     230              :         struct timeval timer;
     231              : 
     232          342 :         if (fsck_abort)
     233            0 :                 return FSCK_CANCELED;
     234          342 :         pass_name = p->name;
     235              : 
     236          342 :         log_notice( _("Starting %s\n"), p->name);
     237          342 :         gettimeofday(&timer, NULL);
     238              : 
     239          342 :         ret = p->f(cx);
     240          342 :         if (ret)
     241            0 :                 exit(ret);
     242          342 :         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          342 :         print_pass_duration(p->name, &timer);
     249          342 :         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           65 : static void exitlog(int status, void *unused)
     258              : {
     259           65 :         syslog(LOG_INFO, "exit: %d", status);
     260           65 : }
     261              : #else
     262              : static void exitlog(void)
     263              : {
     264              :         syslog(LOG_INFO, "exit.");
     265              : }
     266              : #endif
     267              : 
     268           65 : static void startlog(int argc, char **argv)
     269              : {
     270              :         int i;
     271              :         char *cmd, *p;
     272              :         size_t len;
     273              : 
     274          200 :         for (len = i = 0; i < argc; i++)
     275          135 :                 len += strlen(argv[i]);
     276           65 :         len += argc; /* Add spaces and '\0' */
     277              : 
     278           65 :         cmd = malloc(len);
     279           65 :         if (cmd == NULL) {
     280            0 :                 perror(argv[0]);
     281            0 :                 exit(FSCK_ERROR);
     282              :         }
     283           65 :         p = cmd;
     284          200 :         for (i = 0; i < argc; i++, p++) {
     285          135 :                 p = stpcpy(p, argv[i]);
     286          135 :                 *p = ' ';
     287              :         }
     288           65 :         *(--p) = '\0';
     289           65 :         syslog(LOG_INFO, "started: %s", cmd);
     290           65 :         free(cmd);
     291           65 : }
     292              : 
     293              : #ifndef UNITTESTS
     294           65 : int main(int argc, char **argv)
     295              : {
     296           65 :         struct fsck_options opts = {0};
     297              :         struct lgfs2_sbd sb;
     298           65 :         struct fsck_cx cx = {
     299              :                 .sdp = &sb,
     300              :                 .opts = &opts,
     301              :         };
     302              :         int j;
     303              :         int i;
     304           65 :         int error = 0;
     305           65 :         int all_clean = 0;
     306           65 :         struct sigaction act = { .sa_handler = interrupt, };
     307              : 
     308           65 :         setlocale(LC_ALL, "");
     309           65 :         textdomain("gfs2-utils");
     310              : 
     311           65 :         openlog("fsck.gfs2", LOG_CONS|LOG_PID, LOG_USER);
     312           65 :         startlog(argc - 1, &argv[1]);
     313              : #ifdef HAVE_ON_EXIT
     314           65 :         on_exit(exitlog, NULL);
     315              : #else
     316              :         atexit(exitlog);
     317              : #endif
     318              : 
     319           65 :         memset(&sb, 0, sizeof(sb));
     320              : 
     321           65 :         if ((error = read_cmdline(argc, argv, &opts)))
     322            7 :                 exit(error);
     323           58 :         setbuf(stdout, NULL);
     324           58 :         log_notice( _("Initializing fsck\n"));
     325           58 :         if ((error = initialize(&cx, &all_clean)))
     326            1 :                 exit(error);
     327              : 
     328           57 :         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           57 :         sigaction(SIGINT, &act, NULL);
     335              : 
     336          399 :         for (i = 0; passes[i].name; i++)
     337          342 :                 error = fsck_pass(passes + i, &cx);
     338              : 
     339              :         /* Free up our system inodes */
     340           57 :         lgfs2_inode_put(&sb.md.inum);
     341           57 :         lgfs2_inode_put(&sb.md.statfs);
     342          121 :         for (j = 0; j < sb.md.journals; j++)
     343           64 :                 lgfs2_inode_put(&sb.md.journal[j]);
     344           57 :         free(sb.md.journal);
     345           57 :         sb.md.journal = NULL;
     346           57 :         lgfs2_inode_put(&sb.md.jiinode);
     347           57 :         lgfs2_inode_put(&sb.md.riinode);
     348           57 :         lgfs2_inode_put(&sb.md.qinode);
     349           57 :         lgfs2_inode_put(&sb.md.pinode);
     350           57 :         lgfs2_inode_put(&sb.md.rooti);
     351           57 :         lgfs2_inode_put(&sb.master_dir);
     352           57 :         if (lf_dip)
     353            0 :                 lgfs2_inode_put(&lf_dip);
     354              : 
     355           57 :         if (!opts.no && errors_corrected)
     356           14 :                 log_notice( _("Writing changes to disk\n"));
     357           57 :         fsync(sb.device_fd);
     358           57 :         link1_destroy(&nlink1map);
     359           57 :         link1_destroy(&clink1map);
     360           57 :         destroy(&cx);
     361           57 :         if (sb_fixed)
     362            6 :                 log_warn(_("Superblock was reset. Use tunegfs2 to manually "
     363              :                            "set lock table before mounting.\n"));
     364           57 :         log_notice( _("fsck.gfs2 complete\n"));
     365              : 
     366           57 :         if (!error) {
     367           57 :                 if (!errors_found)
     368           43 :                         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           57 :         exit(error);
     375              : }
     376              : #endif /* UNITTESTS */
        

Generated by: LCOV version 2.0-1