blob: 95161c6dfe6a557afd790ab86f6956de8f32c6ac [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2016 Red Hat, Inc.
* All Rights Reserved.
*/
#include "libxfs.h"
#include "addr.h"
#include "command.h"
#include "type.h"
#include "faddr.h"
#include "fprint.h"
#include "field.h"
#include "flist.h"
#include "io.h"
#include "init.h"
#include "output.h"
#include "bit.h"
#include "print.h"
#include "crc.h"
static int crc_f(int argc, char **argv);
static void crc_help(void);
static const cmdinfo_t crc_cmd =
{ "crc", NULL, crc_f, 0, 1, 0, "[-i|-r|-v]",
N_("manipulate crc values for V5 filesystem structures"), crc_help };
void
crc_init(void)
{
if (xfs_sb_version_hascrc(&mp->m_sb))
add_command(&crc_cmd);
}
static void
crc_help(void)
{
dbprintf(_(
"\n"
" 'crc' validates, invalidates, or recalculates the crc value for\n"
" the current on-disk metadata structures in Version 5 filesystems.\n"
"\n"
" Usage: \"crc [-i|-r|-v]\"\n"
"\n"
));
}
static int
crc_f(
int argc,
char **argv)
{
const struct xfs_buf_ops *stashed_ops = NULL;
extern char *progname;
const field_t *fields;
const ftattr_t *fa;
flist_t *fl;
int invalidate = 0;
int recalculate = 0;
int validate = 0;
int c;
if (cur_typ == NULL) {
dbprintf(_("no current type\n"));
return 0;
}
if (cur_typ->fields == NULL) {
dbprintf(_("current type (%s) is not a structure\n"),
cur_typ->name);
return 0;
}
if (argc) while ((c = getopt(argc, argv, "irv")) != EOF) {
switch (c) {
case 'i':
invalidate = 1;
break;
case 'r':
recalculate = 1;
break;
case 'v':
validate = 1;
break;
default:
dbprintf(_("bad option for crc command\n"));
return 0;
}
} else
validate = 1;
if (invalidate + recalculate + validate > 1) {
dbprintf(_("crc command accepts only one option\n"));
return 0;
}
if ((invalidate || recalculate) &&
((x.isreadonly & LIBXFS_ISREADONLY) || !expert_mode)) {
dbprintf(_("%s not in expert mode, writing disabled\n"),
progname);
return 0;
}
fields = cur_typ->fields;
/* if we're a root field type, go down 1 layer to get field list */
if (fields->name[0] == '\0') {
fa = &ftattrtab[fields->ftyp];
ASSERT(fa->ftyp == fields->ftyp);
fields = fa->subfld;
}
/* Search for a CRC field */
fl = flist_find_ftyp(fields, FLDT_CRC);
if (!fl) {
dbprintf(_("No CRC field found for type %s\n"), cur_typ->name);
return 0;
}
/* run down the field list and set offsets into the data */
if (!flist_parse(fields, fl, iocur_top->data, 0)) {
flist_free(fl);
dbprintf(_("parsing error\n"));
return 0;
}
if (invalidate) {
struct xfs_buf_ops nowrite_ops;
flist_t *sfl;
int bit_length;
int parentoffset;
uint32_t crc;
sfl = fl;
parentoffset = 0;
while (sfl->child) {
parentoffset = sfl->offset;
sfl = sfl->child;
}
ASSERT(sfl->fld->ftyp == FLDT_CRC);
bit_length = fsize(sfl->fld, iocur_top->data, parentoffset, 0);
bit_length *= fcount(sfl->fld, iocur_top->data, parentoffset);
crc = getbitval(iocur_top->data, sfl->offset, bit_length,
BVUNSIGNED);
/* Off by one, ignore endianness - we're just corrupting it. */
crc++;
setbitval(iocur_top->data, sfl->offset, bit_length, &crc);
/* Temporarily remove write verifier to write a bad CRC */
stashed_ops = iocur_top->bp->b_ops;
nowrite_ops.verify_read = stashed_ops->verify_read;
nowrite_ops.verify_write = xfs_dummy_verify;
iocur_top->bp->b_ops = &nowrite_ops;
}
if (invalidate || recalculate) {
if (invalidate)
dbprintf(_("Invalidating CRC:\n"));
else
dbprintf(_("Recalculating CRC:\n"));
write_cur();
if (stashed_ops)
iocur_top->bp->b_ops = stashed_ops;
/* re-verify to get proper b_error state */
iocur_top->bp->b_ops->verify_read(iocur_top->bp);
} else
dbprintf(_("Verifying CRC:\n"));
/* And show us what we've got! */
flist_print(fl);
print_flist(fl);
flist_free(fl);
return 0;
}