Blame gfs2/fsck/main.c

Packit Service 360c39
#include "clusterautoconfig.h"
Packit Service 360c39
Packit Service 360c39
#include <unistd.h>
Packit Service 360c39
#include <stdio.h>
Packit Service 360c39
#include <stdint.h>
Packit Service 360c39
#include <stdlib.h>
Packit Service 360c39
#include <libgen.h>
Packit Service 360c39
#include <string.h>
Packit Service 360c39
#include <stdarg.h>
Packit Service 360c39
#include <ctype.h>
Packit Service 360c39
#include <signal.h>
Packit Service 360c39
#include <libintl.h>
Packit Service 360c39
#include <locale.h>
Packit Service 360c39
#include <sys/time.h>
Packit Service 360c39
#include <time.h>
Packit Service 360c39
#define _(String) gettext(String)
Packit Service 360c39
#include <syslog.h>
Packit Service 360c39
Packit Service 360c39
#include <logging.h>
Packit Service 360c39
#include "copyright.cf"
Packit Service 360c39
#include "libgfs2.h"
Packit Service 360c39
#include "fsck.h"
Packit Service 360c39
#include "link.h"
Packit Service 360c39
#include "osi_list.h"
Packit Service 360c39
#include "metawalk.h"
Packit Service 360c39
#include "util.h"
Packit Service 360c39
Packit Service 360c39
struct gfs2_options opts = {0};
Packit Service 360c39
struct gfs2_inode *lf_dip = NULL; /* Lost and found directory inode */
Packit Service 360c39
int lf_was_created = 0;
Packit Service 360c39
uint64_t last_fs_block, last_reported_block = -1;
Packit Service 360c39
int64_t last_reported_fblock = -1000000;
Packit Service 360c39
int skip_this_pass = FALSE, fsck_abort = FALSE;
Packit Service 360c39
int errors_found = 0, errors_corrected = 0;
Packit Service 360c39
const char *pass = "";
Packit Service 360c39
uint64_t last_data_block;
Packit Service 360c39
uint64_t first_data_block;
Packit Service 360c39
int preen = 0, force_check = 0;
Packit Service 360c39
struct osi_root dup_blocks;
Packit Service 360c39
struct osi_root dirtree;
Packit Service 360c39
struct osi_root inodetree;
Packit Service 360c39
int dups_found = 0, dups_found_first = 0;
Packit Service 360c39
struct gfs_sb *sbd1 = NULL;
Packit Service 360c39
int sb_fixed = 0;
Packit Service 360c39
int print_level = MSG_NOTICE;
Packit Service 360c39
Packit Service 360c39
/* This function is for libgfs2's sake.                                      */
Packit Service 360c39
void print_it(const char *label, const char *fmt, const char *fmt2, ...)
Packit Service 360c39
{
Packit Service 360c39
	va_list args;
Packit Service 360c39
Packit Service 360c39
	va_start(args, fmt2);
Packit Service 360c39
	printf("%s: ", label);
Packit Service 360c39
	vprintf(fmt, args);
Packit Service 360c39
	va_end(args);
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static void usage(char *name)
Packit Service 360c39
{
Packit Service 360c39
	printf("Usage: %s [-afhnpqvVy] <device> \n", basename(name));
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static void version(void)
Packit Service 360c39
{
Packit Service 360c39
	printf( _("GFS2 fsck %s (built %s %s)\n"),
Packit Service 360c39
	       VERSION, __DATE__, __TIME__);
Packit Service 360c39
	printf(REDHAT_COPYRIGHT "\n");
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int read_cmdline(int argc, char **argv, struct gfs2_options *gopts)
Packit Service 360c39
{
Packit Service 360c39
	int c;
Packit Service 360c39
Packit Service 360c39
	while ((c = getopt(argc, argv, "afhnpqvyV")) != -1) {
Packit Service 360c39
		switch(c) {
Packit Service 360c39
Packit Service 360c39
		case 'a':
Packit Service 360c39
		case 'p':
Packit Service 360c39
			if (gopts->yes || gopts->no) {
Packit Service 360c39
				fprintf(stderr, _("Options -p/-a, -y and -n may not be used together\n"));
Packit Service 360c39
				return FSCK_USAGE;
Packit Service 360c39
			}
Packit Service 360c39
			preen = 1;
Packit Service 360c39
			gopts->yes = 1;
Packit Service 360c39
			break;
Packit Service 360c39
		case 'f':
Packit Service 360c39
			force_check = 1;
Packit Service 360c39
			break;
Packit Service 360c39
		case 'h':
Packit Service 360c39
			usage(argv[0]);
Packit Service 360c39
			exit(FSCK_OK);
Packit Service 360c39
			break;
Packit Service 360c39
		case 'n':
Packit Service 360c39
			if (gopts->yes || preen) {
Packit Service 360c39
				fprintf(stderr, _("Options -p/-a, -y and -n may not be used together\n"));
Packit Service 360c39
				return FSCK_USAGE;
Packit Service 360c39
			}
Packit Service 360c39
			gopts->no = 1;
Packit Service 360c39
			break;
Packit Service 360c39
		case 'q':
Packit Service 360c39
			decrease_verbosity();
Packit Service 360c39
			break;
Packit Service 360c39
		case 'v':
Packit Service 360c39
			increase_verbosity();
Packit Service 360c39
			break;
Packit Service 360c39
		case 'V':
Packit Service 360c39
			version();
Packit Service 360c39
			exit(FSCK_OK);
Packit Service 360c39
			break;
Packit Service 360c39
		case 'y':
Packit Service 360c39
			if (gopts->no || preen) {
Packit Service 360c39
				fprintf(stderr, _("Options -p/-a, -y and -n may not be used together\n"));
Packit Service 360c39
				return FSCK_USAGE;
Packit Service 360c39
			}
Packit Service 360c39
			gopts->yes = 1;
Packit Service 360c39
			break;
Packit Service 360c39
		case ':':
Packit Service 360c39
		case '?':
Packit Service 360c39
			fprintf(stderr, _("Please use '-h' for help.\n"));
Packit Service 360c39
			return FSCK_USAGE;
Packit Service 360c39
		default:
Packit Service 360c39
			fprintf(stderr, _("Invalid option %c\n"), c);
Packit Service 360c39
			return FSCK_USAGE;
Packit Service 360c39
Packit Service 360c39
		}
Packit Service 360c39
	}
Packit Service 360c39
	if (argc > optind) {
Packit Service 360c39
		gopts->device = (argv[optind]);
Packit Service 360c39
		if (!gopts->device) {
Packit Service 360c39
			fprintf(stderr, _("Please use '-h' for help.\n"));
Packit Service 360c39
			return FSCK_USAGE;
Packit Service 360c39
		}
Packit Service 360c39
	} else {
Packit Service 360c39
		fprintf(stderr, _("No device specified (Please use '-h' for help)\n"));
Packit Service 360c39
		return FSCK_USAGE;
Packit Service 360c39
	}
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static void interrupt(int sig)
Packit Service 360c39
{
Packit Service 360c39
	char response;
Packit Service 360c39
	char progress[PATH_MAX];
Packit Service 360c39
Packit Service 360c39
	if (!last_reported_block || last_reported_block == last_fs_block)
Packit Service 360c39
		sprintf(progress, _("progress unknown.\n"));
Packit Service 360c39
	else
Packit Service 360c39
		sprintf(progress, _("processing block %llu out of %llu\n"),
Packit Service 360c39
			(unsigned long long)last_reported_block,
Packit Service 360c39
			(unsigned long long)last_fs_block);
Packit Service 360c39
	
Packit Service 360c39
	response = generic_interrupt("fsck.gfs2", pass, progress,
Packit Service 360c39
				     _("Do you want to abort fsck.gfs2, skip " \
Packit Service 360c39
				     "the rest of this pass or continue " \
Packit Service 360c39
				     "(a/s/c)?"), "asc");
Packit Service 360c39
	if (tolower(response) == 's') {
Packit Service 360c39
		skip_this_pass = TRUE;
Packit Service 360c39
		return;
Packit Service 360c39
	}
Packit Service 360c39
	else if (tolower(response) == 'a') {
Packit Service 360c39
		fsck_abort = TRUE;
Packit Service 360c39
		return;
Packit Service 360c39
	}
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int check_statfs(struct gfs2_sbd *sdp)
Packit Service 360c39
{
Packit Service 360c39
	struct osi_node *n, *next = NULL;
Packit Service 360c39
	struct rgrp_tree *rgd;
Packit Service 360c39
	struct gfs2_rindex *ri;
Packit Service 360c39
	struct gfs2_statfs_change sc = {0,};
Packit Service 360c39
	char buf[sizeof(struct gfs2_statfs_change)];
Packit Service 360c39
	int count;
Packit Service 360c39
Packit Service 360c39
	if (sdp->gfs1 && !sdp->md.statfs->i_di.di_size) {
Packit Service 360c39
		log_info("This GFS1 file system is not using fast_statfs.\n");
Packit Service 360c39
		return 0;
Packit Service 360c39
	}
Packit Service 360c39
	/* Read the current statfs values */
Packit Service 360c39
	count = gfs2_readi(sdp->md.statfs, buf, 0,
Packit Service 360c39
			   sdp->md.statfs->i_di.di_size);
Packit Service 360c39
	if (count != sizeof(struct gfs2_statfs_change)) {
Packit Service 360c39
		log_err(_("Failed to read statfs values (%d of %"PRIu64" read)\n"),
Packit Service 360c39
		        count, (uint64_t)sdp->md.statfs->i_di.di_size);
Packit Service 360c39
		return FSCK_ERROR;
Packit Service 360c39
	}
Packit Service 360c39
	gfs2_statfs_change_in(&sc, buf);
Packit Service 360c39
	/* Calculate the real values from the rgrp information */
Packit Service 360c39
	sdp->blks_total = 0;
Packit Service 360c39
	sdp->blks_alloced = 0;
Packit Service 360c39
	sdp->dinodes_alloced = 0;
Packit Service 360c39
Packit Service 360c39
	for (n = osi_first(&sdp->rgtree); n; n = next) {
Packit Service 360c39
		next = osi_next(n);
Packit Service 360c39
		rgd = (struct rgrp_tree *)n;
Packit Service 360c39
		ri = &rgd->ri;
Packit Service 360c39
		sdp->blks_total += ri->ri_data;
Packit Service 360c39
		sdp->blks_alloced += (ri->ri_data - rgd->rg.rg_free);
Packit Service 360c39
		sdp->dinodes_alloced += rgd->rg.rg_dinodes;
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	/* See if they match */
Packit Service 360c39
	if (sc.sc_total == sdp->blks_total &&
Packit Service 360c39
	    sc.sc_free == (sdp->blks_total - sdp->blks_alloced) &&
Packit Service 360c39
	    sc.sc_dinodes == sdp->dinodes_alloced) {
Packit Service 360c39
		log_info( _("The statfs file is accurate.\n"));
Packit Service 360c39
		return 0;
Packit Service 360c39
	}
Packit Service 360c39
	log_err( _("The statfs file is wrong:\n\n"));
Packit Service 360c39
	log_err( _("Current statfs values:\n"));
Packit Service 360c39
	log_err( _("blocks:  %lld (0x%llx)\n"),
Packit Service 360c39
		 (unsigned long long)sc.sc_total,
Packit Service 360c39
		 (unsigned long long)sc.sc_total);
Packit Service 360c39
	log_err( _("free:    %lld (0x%llx)\n"),
Packit Service 360c39
		 (unsigned long long)sc.sc_free,
Packit Service 360c39
		 (unsigned long long)sc.sc_free);
Packit Service 360c39
	log_err( _("dinodes: %lld (0x%llx)\n\n"),
Packit Service 360c39
		 (unsigned long long)sc.sc_dinodes,
Packit Service 360c39
		 (unsigned long long)sc.sc_dinodes);
Packit Service 360c39
Packit Service 360c39
	log_err( _("Calculated statfs values:\n"));
Packit Service 360c39
	log_err( _("blocks:  %lld (0x%llx)\n"),
Packit Service 360c39
		 (unsigned long long)sdp->blks_total,
Packit Service 360c39
		 (unsigned long long)sdp->blks_total);
Packit Service 360c39
	log_err( _("free:    %lld (0x%llx)\n"),
Packit Service 360c39
		 (unsigned long long)(sdp->blks_total - sdp->blks_alloced),
Packit Service 360c39
		 (unsigned long long)(sdp->blks_total - sdp->blks_alloced));
Packit Service 360c39
	log_err( _("dinodes: %lld (0x%llx)\n"),
Packit Service 360c39
		 (unsigned long long)sdp->dinodes_alloced,
Packit Service 360c39
		 (unsigned long long)sdp->dinodes_alloced);
Packit Service 360c39
Packit Service 360c39
	errors_found++;
Packit Service 360c39
	if (!query( _("Okay to fix the master statfs file? (y/n)"))) {
Packit Service 360c39
		log_err( _("The statfs file was not fixed.\n"));
Packit Service 360c39
		return 0;
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	do_init_statfs(sdp);
Packit Service 360c39
	log_err( _("The statfs file was fixed.\n"));
Packit Service 360c39
	errors_corrected++;
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static const struct fsck_pass passes[] = {
Packit Service 360c39
	{ .name = "pass1",  .f = pass1 },
Packit Service 360c39
	{ .name = "pass1b", .f = pass1b },
Packit Service 360c39
	{ .name = "pass2",  .f = pass2 },
Packit Service 360c39
	{ .name = "pass3",  .f = pass3 },
Packit Service 360c39
	{ .name = "pass4",  .f = pass4 },
Packit Service 360c39
	{ .name = "check_statfs", .f = check_statfs },
Packit Service 360c39
	{ .name = NULL, }
Packit Service 360c39
};
Packit Service 360c39
Packit Service 360c39
static int fsck_pass(const struct fsck_pass *p, struct gfs2_sbd *sdp)
Packit Service 360c39
{
Packit Service 360c39
	int ret;
Packit Service 360c39
	struct timeval timer;
Packit Service 360c39
Packit Service 360c39
	if (fsck_abort)
Packit Service 360c39
		return FSCK_CANCELED;
Packit Service 360c39
	pass = p->name;
Packit Service 360c39
Packit Service 360c39
	log_notice( _("Starting %s\n"), p->name);
Packit Service 360c39
	gettimeofday(&timer, NULL);
Packit Service 360c39
Packit Service 360c39
	ret = p->f(sdp);
Packit Service 360c39
	if (ret)
Packit Service 360c39
		exit(ret);
Packit Service 360c39
	if (skip_this_pass || fsck_abort) {
Packit Service 360c39
		skip_this_pass = 0;
Packit Service 360c39
		log_notice( _("%s interrupted   \n"), p->name);
Packit Service 360c39
		return FSCK_CANCELED;
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	print_pass_duration(p->name, &timer;;
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static void exitlog(int status, void *unused)
Packit Service 360c39
{
Packit Service 360c39
	syslog(LOG_INFO, "exit: %d", status);
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static void startlog(int argc, char **argv)
Packit Service 360c39
{
Packit Service 360c39
	int i;
Packit Service 360c39
	char *cmd, *p;
Packit Service 360c39
	size_t len;
Packit Service 360c39
Packit Service 360c39
	for (len = i = 0; i < argc; i++)
Packit Service 360c39
		len += strlen(argv[i]);
Packit Service 360c39
	len += argc; /* Add spaces and '\0' */
Packit Service 360c39
Packit Service 360c39
	cmd = malloc(len);
Packit Service 360c39
	if (cmd == NULL) {
Packit Service 360c39
		perror(argv[0]);
Packit Service 360c39
		exit(FSCK_ERROR);
Packit Service 360c39
	}
Packit Service 360c39
	p = cmd;
Packit Service 360c39
	for (i = 0; i < argc; i++, p++) {
Packit Service 360c39
		p = stpcpy(p, argv[i]);
Packit Service 360c39
		*p = ' ';
Packit Service 360c39
	}
Packit Service 360c39
	*(--p) = '\0';
Packit Service 360c39
	syslog(LOG_INFO, "started: %s", cmd);
Packit Service 360c39
	free(cmd);
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
int main(int argc, char **argv)
Packit Service 360c39
{
Packit Service 360c39
	struct gfs2_sbd sb;
Packit Service 360c39
	struct gfs2_sbd *sdp = &sb;
Packit Service 360c39
	int j;
Packit Service 360c39
	int i;
Packit Service 360c39
	int error = 0;
Packit Service 360c39
	int all_clean = 0;
Packit Service 360c39
	struct sigaction act = { .sa_handler = interrupt, };
Packit Service 360c39
Packit Service 360c39
	setlocale(LC_ALL, "");
Packit Service 360c39
	textdomain("gfs2-utils");
Packit Service 360c39
Packit Service 360c39
	openlog("fsck.gfs2", LOG_CONS|LOG_PID, LOG_USER);
Packit Service 360c39
	startlog(argc - 1, &argv[1]);
Packit Service 360c39
	on_exit(exitlog, NULL);
Packit Service 360c39
Packit Service 360c39
	memset(sdp, 0, sizeof(*sdp));
Packit Service 360c39
Packit Service 360c39
	if ((error = read_cmdline(argc, argv, &opts)))
Packit Service 360c39
		exit(error);
Packit Service 360c39
	setbuf(stdout, NULL);
Packit Service 360c39
	log_notice( _("Initializing fsck\n"));
Packit Service 360c39
	if ((error = initialize(sdp, force_check, preen, &all_clean)))
Packit Service 360c39
		exit(error);
Packit Service 360c39
Packit Service 360c39
	if (!force_check && all_clean && preen) {
Packit Service 360c39
		log_err( _("%s: clean.\n"), opts.device);
Packit Service 360c39
		destroy(sdp);
Packit Service 360c39
		exit(FSCK_OK);
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	sigaction(SIGINT, &act, NULL);
Packit Service 360c39
Packit Service 360c39
	for (i = 0; passes[i].name; i++)
Packit Service 360c39
		error = fsck_pass(passes + i, sdp);
Packit Service 360c39
Packit Service 360c39
	/* Free up our system inodes */
Packit Service 360c39
	if (!sdp->gfs1)
Packit Service 360c39
		inode_put(&sdp->md.inum);
Packit Service 360c39
	inode_put(&sdp->md.statfs);
Packit Service 360c39
	for (j = 0; j < sdp->md.journals; j++)
Packit Service 360c39
		inode_put(&sdp->md.journal[j]);
Packit Service 360c39
	free(sdp->md.journal);
Packit Service 360c39
	sdp->md.journal = NULL;
Packit Service 360c39
	inode_put(&sdp->md.jiinode);
Packit Service 360c39
	inode_put(&sdp->md.riinode);
Packit Service 360c39
	inode_put(&sdp->md.qinode);
Packit Service 360c39
	if (!sdp->gfs1)
Packit Service 360c39
		inode_put(&sdp->md.pinode);
Packit Service 360c39
	inode_put(&sdp->md.rooti);
Packit Service 360c39
	if (!sdp->gfs1)
Packit Service 360c39
		inode_put(&sdp->master_dir);
Packit Service 360c39
	if (lf_dip)
Packit Service 360c39
		inode_put(&lf_dip);
Packit Service 360c39
Packit Service 360c39
	if (!opts.no && errors_corrected)
Packit Service 360c39
		log_notice( _("Writing changes to disk\n"));
Packit Service 360c39
	fsync(sdp->device_fd);
Packit Service 360c39
	link1_destroy(&nlink1map);
Packit Service 360c39
	link1_destroy(&clink1map);
Packit Service 360c39
	destroy(sdp);
Packit Service 360c39
	if (sb_fixed)
Packit Service 360c39
		log_warn(_("Superblock was reset. Use tunegfs2 to manually "
Packit Service 360c39
		           "set lock table before mounting.\n"));
Packit Service 360c39
	log_notice( _("fsck.gfs2 complete\n"));
Packit Service 360c39
Packit Service 360c39
	if (!error) {
Packit Service 360c39
		if (!errors_found)
Packit Service 360c39
			error = FSCK_OK;
Packit Service 360c39
		else if (errors_found == errors_corrected)
Packit Service 360c39
			error = FSCK_NONDESTRUCT;
Packit Service 360c39
		else
Packit Service 360c39
			error = FSCK_UNCORRECTED;
Packit Service 360c39
	}
Packit Service 360c39
	exit(error);
Packit Service 360c39
}