]>
Commit | Line | Data |
---|---|---|
959ef981 | 1 | // SPDX-License-Identifier: GPL-2.0 |
b64af2c4 ES |
2 | /* |
3 | * Copyright (c) 2016 Red Hat, Inc. | |
4 | * All Rights Reserved. | |
b64af2c4 ES |
5 | */ |
6 | ||
7 | #include "libxfs.h" | |
8 | #include "addr.h" | |
9 | #include "command.h" | |
10 | #include "type.h" | |
11 | #include "faddr.h" | |
12 | #include "fprint.h" | |
13 | #include "field.h" | |
14 | #include "flist.h" | |
15 | #include "io.h" | |
16 | #include "init.h" | |
17 | #include "output.h" | |
18 | #include "bit.h" | |
19 | #include "print.h" | |
4a87b332 | 20 | #include "crc.h" |
b64af2c4 ES |
21 | |
22 | static int crc_f(int argc, char **argv); | |
23 | static void crc_help(void); | |
24 | ||
25 | static const cmdinfo_t crc_cmd = | |
26 | { "crc", NULL, crc_f, 0, 1, 0, "[-i|-r|-v]", | |
27 | N_("manipulate crc values for V5 filesystem structures"), crc_help }; | |
28 | ||
29 | void | |
30 | crc_init(void) | |
31 | { | |
2660e653 | 32 | if (xfs_has_crc(mp)) |
b64af2c4 ES |
33 | add_command(&crc_cmd); |
34 | } | |
35 | ||
36 | static void | |
37 | crc_help(void) | |
38 | { | |
39 | dbprintf(_( | |
40 | "\n" | |
41 | " 'crc' validates, invalidates, or recalculates the crc value for\n" | |
42 | " the current on-disk metadata structures in Version 5 filesystems.\n" | |
43 | "\n" | |
44 | " Usage: \"crc [-i|-r|-v]\"\n" | |
45 | "\n" | |
46 | )); | |
47 | ||
48 | } | |
49 | ||
50 | static int | |
51 | crc_f( | |
52 | int argc, | |
53 | char **argv) | |
54 | { | |
55 | const struct xfs_buf_ops *stashed_ops = NULL; | |
a19679ec | 56 | struct xfs_buf_ops nowrite_ops; |
b64af2c4 ES |
57 | extern char *progname; |
58 | const field_t *fields; | |
59 | const ftattr_t *fa; | |
60 | flist_t *fl; | |
61 | int invalidate = 0; | |
62 | int recalculate = 0; | |
63 | int validate = 0; | |
64 | int c; | |
65 | ||
66 | if (cur_typ == NULL) { | |
67 | dbprintf(_("no current type\n")); | |
68 | return 0; | |
69 | } | |
70 | ||
71 | if (cur_typ->fields == NULL) { | |
72 | dbprintf(_("current type (%s) is not a structure\n"), | |
73 | cur_typ->name); | |
74 | return 0; | |
75 | } | |
76 | ||
77 | if (argc) while ((c = getopt(argc, argv, "irv")) != EOF) { | |
78 | switch (c) { | |
79 | case 'i': | |
80 | invalidate = 1; | |
81 | break; | |
82 | case 'r': | |
83 | recalculate = 1; | |
84 | break; | |
85 | case 'v': | |
86 | validate = 1; | |
87 | break; | |
88 | default: | |
89 | dbprintf(_("bad option for crc command\n")); | |
90 | return 0; | |
91 | } | |
92 | } else | |
93 | validate = 1; | |
94 | ||
95 | if (invalidate + recalculate + validate > 1) { | |
96 | dbprintf(_("crc command accepts only one option\n")); | |
97 | return 0; | |
98 | } | |
99 | ||
100 | if ((invalidate || recalculate) && | |
23d88955 | 101 | ((x.flags & LIBXFS_ISREADONLY) || !expert_mode)) { |
b64af2c4 ES |
102 | dbprintf(_("%s not in expert mode, writing disabled\n"), |
103 | progname); | |
104 | return 0; | |
105 | } | |
106 | ||
107 | fields = cur_typ->fields; | |
108 | ||
109 | /* if we're a root field type, go down 1 layer to get field list */ | |
110 | if (fields->name[0] == '\0') { | |
111 | fa = &ftattrtab[fields->ftyp]; | |
112 | ASSERT(fa->ftyp == fields->ftyp); | |
113 | fields = fa->subfld; | |
114 | } | |
115 | ||
116 | /* Search for a CRC field */ | |
a0d79cb3 | 117 | fl = flist_find_ftyp(fields, FLDT_CRC, iocur_top->data, 0); |
b64af2c4 ES |
118 | if (!fl) { |
119 | dbprintf(_("No CRC field found for type %s\n"), cur_typ->name); | |
120 | return 0; | |
121 | } | |
122 | ||
123 | /* run down the field list and set offsets into the data */ | |
124 | if (!flist_parse(fields, fl, iocur_top->data, 0)) { | |
125 | flist_free(fl); | |
126 | dbprintf(_("parsing error\n")); | |
127 | return 0; | |
128 | } | |
129 | ||
130 | if (invalidate) { | |
b64af2c4 ES |
131 | flist_t *sfl; |
132 | int bit_length; | |
133 | int parentoffset; | |
8e1338fb | 134 | uint32_t crc; |
b64af2c4 ES |
135 | |
136 | sfl = fl; | |
137 | parentoffset = 0; | |
138 | while (sfl->child) { | |
139 | parentoffset = sfl->offset; | |
140 | sfl = sfl->child; | |
141 | } | |
142 | ASSERT(sfl->fld->ftyp == FLDT_CRC); | |
143 | ||
144 | bit_length = fsize(sfl->fld, iocur_top->data, parentoffset, 0); | |
145 | bit_length *= fcount(sfl->fld, iocur_top->data, parentoffset); | |
146 | crc = getbitval(iocur_top->data, sfl->offset, bit_length, | |
147 | BVUNSIGNED); | |
8e1338fb ES |
148 | /* Off by one, ignore endianness - we're just corrupting it. */ |
149 | crc++; | |
b64af2c4 ES |
150 | setbitval(iocur_top->data, sfl->offset, bit_length, &crc); |
151 | ||
152 | /* Temporarily remove write verifier to write a bad CRC */ | |
153 | stashed_ops = iocur_top->bp->b_ops; | |
154 | nowrite_ops.verify_read = stashed_ops->verify_read; | |
155 | nowrite_ops.verify_write = xfs_dummy_verify; | |
156 | iocur_top->bp->b_ops = &nowrite_ops; | |
157 | } | |
158 | ||
159 | if (invalidate || recalculate) { | |
160 | if (invalidate) | |
161 | dbprintf(_("Invalidating CRC:\n")); | |
162 | else | |
163 | dbprintf(_("Recalculating CRC:\n")); | |
164 | ||
165 | write_cur(); | |
166 | if (stashed_ops) | |
167 | iocur_top->bp->b_ops = stashed_ops; | |
168 | /* re-verify to get proper b_error state */ | |
169 | iocur_top->bp->b_ops->verify_read(iocur_top->bp); | |
170 | } else | |
171 | dbprintf(_("Verifying CRC:\n")); | |
172 | ||
173 | /* And show us what we've got! */ | |
174 | flist_print(fl); | |
175 | print_flist(fl); | |
176 | flist_free(fl); | |
177 | return 0; | |
178 | } |