| // 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_has_crc(mp)) |
| 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; |
| struct xfs_buf_ops nowrite_ops; |
| 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, iocur_top->data, 0); |
| 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) { |
| 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; |
| } |