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