]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - io/scrub.c
xfs_io: set exitcode = 1 on parsing errors in scrub/repair command
[thirdparty/xfsprogs-dev.git] / io / scrub.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (C) 2017 Oracle. All Rights Reserved.
4 * Author: Darrick J. Wong <darrick.wong@oracle.com>
5 */
6
7 #include <sys/uio.h>
8 #include <xfs/xfs.h>
9 #include "command.h"
10 #include "input.h"
11 #include "init.h"
12 #include "libfrog/paths.h"
13 #include "libfrog/fsgeom.h"
14 #include "libfrog/scrub.h"
15 #include "io.h"
16
17 static struct cmdinfo scrub_cmd;
18 static struct cmdinfo repair_cmd;
19
20 static void
21 scrub_help(void)
22 {
23 const struct xfrog_scrub_descr *d;
24 int i;
25
26 printf(_(
27 "\n"
28 " Scrubs a piece of XFS filesystem metadata. The first argument is the type\n"
29 " of metadata to examine. Allocation group metadata types take one AG number\n"
30 " as the second parameter. Inode metadata types act on the currently open file\n"
31 " or (optionally) take an inode number and generation number to act upon as\n"
32 " the second and third parameters.\n"
33 "\n"
34 " Example:\n"
35 " 'scrub inobt 3' - scrub the inode btree in AG 3.\n"
36 " 'scrub bmapbtd 128 13525' - scrubs the extent map of inode 128 gen 13525.\n"
37 "\n"
38 " Known metadata scrub types are:"));
39 for (i = 0, d = xfrog_scrubbers; i < XFS_SCRUB_TYPE_NR; i++, d++)
40 printf(" %s", d->name);
41 printf("\n");
42 }
43
44 static void
45 scrub_ioctl(
46 int fd,
47 int type,
48 uint64_t control,
49 uint32_t control2)
50 {
51 struct xfs_scrub_metadata meta;
52 const struct xfrog_scrub_descr *sc;
53 int error;
54
55 sc = &xfrog_scrubbers[type];
56 memset(&meta, 0, sizeof(meta));
57 meta.sm_type = type;
58 switch (sc->type) {
59 case XFROG_SCRUB_TYPE_AGHEADER:
60 case XFROG_SCRUB_TYPE_PERAG:
61 meta.sm_agno = control;
62 break;
63 case XFROG_SCRUB_TYPE_INODE:
64 meta.sm_ino = control;
65 meta.sm_gen = control2;
66 break;
67 case XFROG_SCRUB_TYPE_NONE:
68 case XFROG_SCRUB_TYPE_FS:
69 /* no control parameters */
70 break;
71 }
72 meta.sm_flags = 0;
73
74 error = ioctl(fd, XFS_IOC_SCRUB_METADATA, &meta);
75 if (error)
76 perror("scrub");
77 if (meta.sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
78 printf(_("Corruption detected.\n"));
79 if (meta.sm_flags & XFS_SCRUB_OFLAG_PREEN)
80 printf(_("Optimization possible.\n"));
81 if (meta.sm_flags & XFS_SCRUB_OFLAG_XFAIL)
82 printf(_("Cross-referencing failed.\n"));
83 if (meta.sm_flags & XFS_SCRUB_OFLAG_XCORRUPT)
84 printf(_("Corruption detected during cross-referencing.\n"));
85 if (meta.sm_flags & XFS_SCRUB_OFLAG_INCOMPLETE)
86 printf(_("Scan was not complete.\n"));
87 }
88
89 static int
90 parse_args(
91 int argc,
92 char **argv,
93 struct cmdinfo *cmdinfo,
94 void (*fn)(int, int, uint64_t, uint32_t))
95 {
96 char *p;
97 int type = -1;
98 int i, c;
99 uint64_t control = 0;
100 uint32_t control2 = 0;
101 const struct xfrog_scrub_descr *d = NULL;
102
103 while ((c = getopt(argc, argv, "")) != EOF) {
104 switch (c) {
105 default:
106 exitcode = 1;
107 return command_usage(cmdinfo);
108 }
109 }
110 if (optind > argc - 1) {
111 exitcode = 1;
112 return command_usage(cmdinfo);
113 }
114
115 for (i = 0, d = xfrog_scrubbers; i < XFS_SCRUB_TYPE_NR; i++, d++) {
116 if (strcmp(d->name, argv[optind]) == 0) {
117 type = i;
118 break;
119 }
120 }
121 if (type < 0) {
122 printf(_("Unknown type '%s'.\n"), argv[optind]);
123 exitcode = 1;
124 return command_usage(cmdinfo);
125 }
126 optind++;
127
128 switch (d->type) {
129 case XFROG_SCRUB_TYPE_INODE:
130 if (optind == argc) {
131 control = 0;
132 control2 = 0;
133 } else if (optind == argc - 2) {
134 control = strtoull(argv[optind], &p, 0);
135 if (*p != '\0') {
136 fprintf(stderr,
137 _("Bad inode number '%s'.\n"),
138 argv[optind]);
139 exitcode = 1;
140 return command_usage(cmdinfo);
141 }
142 control2 = strtoul(argv[optind + 1], &p, 0);
143 if (*p != '\0') {
144 fprintf(stderr,
145 _("Bad generation number '%s'.\n"),
146 argv[optind + 1]);
147 exitcode = 1;
148 return command_usage(cmdinfo);
149 }
150 } else {
151 fprintf(stderr,
152 _("Must specify inode number and generation.\n"));
153 exitcode = 1;
154 return command_usage(cmdinfo);
155 }
156 break;
157 case XFROG_SCRUB_TYPE_AGHEADER:
158 case XFROG_SCRUB_TYPE_PERAG:
159 if (optind != argc - 1) {
160 fprintf(stderr,
161 _("Must specify one AG number.\n"));
162 exitcode = 1;
163 return command_usage(cmdinfo);
164 }
165 control = strtoul(argv[optind], &p, 0);
166 if (*p != '\0') {
167 fprintf(stderr,
168 _("Bad AG number '%s'.\n"), argv[optind]);
169 exitcode = 1;
170 return command_usage(cmdinfo);
171 }
172 break;
173 case XFROG_SCRUB_TYPE_FS:
174 case XFROG_SCRUB_TYPE_NONE:
175 if (optind != argc) {
176 fprintf(stderr,
177 _("No parameters allowed.\n"));
178 exitcode = 1;
179 return command_usage(cmdinfo);
180 }
181 break;
182 default:
183 ASSERT(0);
184 break;
185 }
186 fn(file->fd, type, control, control2);
187
188 return 0;
189 }
190
191 static int
192 scrub_f(
193 int argc,
194 char **argv)
195 {
196 return parse_args(argc, argv, &scrub_cmd, scrub_ioctl);
197 }
198
199 void
200 scrub_init(void)
201 {
202 scrub_cmd.name = "scrub";
203 scrub_cmd.altname = "sc";
204 scrub_cmd.cfunc = scrub_f;
205 scrub_cmd.argmin = 1;
206 scrub_cmd.argmax = -1;
207 scrub_cmd.flags = CMD_NOMAP_OK;
208 scrub_cmd.args = _("type [agno|ino gen]");
209 scrub_cmd.oneline = _("scrubs filesystem metadata");
210 scrub_cmd.help = scrub_help;
211
212 add_command(&scrub_cmd);
213 }
214
215 static void
216 repair_help(void)
217 {
218 const struct xfrog_scrub_descr *d;
219 int i;
220
221 printf(_(
222 "\n"
223 " Repairs a piece of XFS filesystem metadata. The first argument is the type\n"
224 " of metadata to examine. Allocation group metadata types take one AG number\n"
225 " as the second parameter. Inode metadata types act on the currently open file\n"
226 " or (optionally) take an inode number and generation number to act upon as\n"
227 " the second and third parameters.\n"
228 "\n"
229 " Example:\n"
230 " 'repair inobt 3' - repairs the inode btree in AG 3.\n"
231 " 'repair bmapbtd 128 13525' - repairs the extent map of inode 128 gen 13525.\n"
232 "\n"
233 " Known metadata repairs types are:"));
234 for (i = 0, d = xfrog_scrubbers; i < XFS_SCRUB_TYPE_NR; i++, d++)
235 printf(" %s", d->name);
236 printf("\n");
237 }
238
239 static void
240 repair_ioctl(
241 int fd,
242 int type,
243 uint64_t control,
244 uint32_t control2)
245 {
246 struct xfs_scrub_metadata meta;
247 const struct xfrog_scrub_descr *sc;
248 int error;
249
250 sc = &xfrog_scrubbers[type];
251 memset(&meta, 0, sizeof(meta));
252 meta.sm_type = type;
253 switch (sc->type) {
254 case XFROG_SCRUB_TYPE_AGHEADER:
255 case XFROG_SCRUB_TYPE_PERAG:
256 meta.sm_agno = control;
257 break;
258 case XFROG_SCRUB_TYPE_INODE:
259 meta.sm_ino = control;
260 meta.sm_gen = control2;
261 break;
262 case XFROG_SCRUB_TYPE_NONE:
263 case XFROG_SCRUB_TYPE_FS:
264 /* no control parameters */
265 break;
266 }
267 meta.sm_flags = XFS_SCRUB_IFLAG_REPAIR;
268
269 error = ioctl(fd, XFS_IOC_SCRUB_METADATA, &meta);
270 if (error)
271 perror("repair");
272 if (meta.sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
273 printf(_("Corruption remains.\n"));
274 if (meta.sm_flags & XFS_SCRUB_OFLAG_PREEN)
275 printf(_("Optimization possible.\n"));
276 if (meta.sm_flags & XFS_SCRUB_OFLAG_XFAIL)
277 printf(_("Cross-referencing failed.\n"));
278 if (meta.sm_flags & XFS_SCRUB_OFLAG_XCORRUPT)
279 printf(_("Corruption still detected during cross-referencing.\n"));
280 if (meta.sm_flags & XFS_SCRUB_OFLAG_INCOMPLETE)
281 printf(_("Repair was not complete.\n"));
282 if (meta.sm_flags & XFS_SCRUB_OFLAG_NO_REPAIR_NEEDED)
283 printf(_("Metadata did not need repair or optimization.\n"));
284 }
285
286 static int
287 repair_f(
288 int argc,
289 char **argv)
290 {
291 return parse_args(argc, argv, &repair_cmd, repair_ioctl);
292 }
293
294 void
295 repair_init(void)
296 {
297 if (!expert)
298 return;
299 repair_cmd.name = "repair";
300 repair_cmd.altname = "fix";
301 repair_cmd.cfunc = repair_f;
302 repair_cmd.argmin = 1;
303 repair_cmd.argmax = -1;
304 repair_cmd.flags = CMD_NOMAP_OK;
305 repair_cmd.args = _("type [agno|ino gen]");
306 repair_cmd.oneline = _("repairs filesystem metadata");
307 repair_cmd.help = repair_help;
308
309 add_command(&repair_cmd);
310 }