]>
Commit | Line | Data |
---|---|---|
c49057d2 | 1 | /* |
870768ad | 2 | * wipefs - utility to wipe filesystems from device |
c49057d2 KZ |
3 | * |
4 | * Copyright (C) 2009 Red Hat, Inc. All rights reserved. | |
5 | * Written by Karel Zak <kzak@redhat.com> | |
6 | * | |
bfbe2933 KZ |
7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License as published by | |
9 | * the Free Software Foundation; either version 2 of the License, or | |
10 | * (at your option) any later version. | |
c49057d2 KZ |
11 | * |
12 | * This program is distributed in the hope that it would be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | * GNU General Public License for more details. | |
16 | * | |
7cebf0bb SK |
17 | * You should have received a copy of the GNU General Public License along |
18 | * with this program; if not, write to the Free Software Foundation, Inc., | |
19 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
c49057d2 KZ |
20 | */ |
21 | #include <sys/stat.h> | |
22 | #include <sys/types.h> | |
23 | #include <ctype.h> | |
24 | #include <errno.h> | |
25 | #include <fcntl.h> | |
26 | #include <stdio.h> | |
27 | #include <stdlib.h> | |
28 | #include <unistd.h> | |
29 | #include <getopt.h> | |
c49057d2 KZ |
30 | #include <string.h> |
31 | #include <limits.h> | |
8acff75a | 32 | #include <libgen.h> |
c49057d2 KZ |
33 | |
34 | #include <blkid.h> | |
d9921b2a | 35 | #include <libsmartcols.h> |
c49057d2 KZ |
36 | |
37 | #include "nls.h" | |
87f3feac | 38 | #include "xalloc.h" |
8abcf290 | 39 | #include "strutils.h" |
e12c9866 | 40 | #include "all-io.h" |
f126cd46 | 41 | #include "match.h" |
eb76ca98 | 42 | #include "c.h" |
c05a80ca | 43 | #include "closestream.h" |
58f0252a | 44 | #include "optutils.h" |
081dc33b | 45 | #include "blkdev.h" |
c49057d2 KZ |
46 | |
47 | struct wipe_desc { | |
48 | loff_t offset; /* magic string offset */ | |
49 | size_t len; /* length of magic string */ | |
50 | unsigned char *magic; /* magic string */ | |
51 | ||
c49057d2 KZ |
52 | char *usage; /* raid, filesystem, ... */ |
53 | char *type; /* FS type */ | |
54 | char *label; /* FS label */ | |
55 | char *uuid; /* FS uuid */ | |
56 | ||
57 | struct wipe_desc *next; | |
081dc33b KZ |
58 | |
59 | unsigned int zap : 1, | |
60 | on_disk : 1, | |
61 | is_parttable : 1; | |
62 | ||
c49057d2 KZ |
63 | }; |
64 | ||
4e609281 KZ |
65 | struct wipe_control { |
66 | const char *devname; | |
67 | const char *type_pattern; | |
68 | ||
d9921b2a KZ |
69 | struct libscols_table *outtab; |
70 | ||
4e609281 KZ |
71 | unsigned int noact : 1, |
72 | all : 1, | |
73 | quiet : 1, | |
74 | backup : 1, | |
75 | force : 1, | |
d9921b2a KZ |
76 | json : 1, |
77 | no_headings : 1, | |
4e609281 | 78 | parsable : 1; |
4f053737 | 79 | }; |
c49057d2 | 80 | |
d9921b2a KZ |
81 | |
82 | /* column IDs */ | |
83 | enum { | |
84 | COL_UUID = 0, | |
85 | COL_LABEL, | |
86 | COL_LEN, | |
87 | COL_TYPE, | |
88 | COL_OFFSET, | |
89 | COL_USAGE, | |
90 | COL_DEVICE | |
91 | }; | |
92 | ||
93 | /* column names */ | |
94 | struct colinfo { | |
95 | const char *name; /* header */ | |
96 | double whint; /* width hint (N < 1 is in percent of termwidth) */ | |
97 | int flags; /* SCOLS_FL_* */ | |
98 | const char *help; | |
99 | }; | |
100 | ||
101 | /* columns descriptions */ | |
102 | static const struct colinfo infos[] = { | |
103 | [COL_UUID] = {"UUID", 4, 0, N_("partition/filesystem UUID")}, | |
104 | [COL_LABEL] = {"LABEL", 5, 0, N_("filesystem LABEL")}, | |
105 | [COL_LEN] = {"LENGTH", 6, 0, N_("magic string length")}, | |
106 | [COL_TYPE] = {"TYPE", 4, 0, N_("superblok type")}, | |
107 | [COL_OFFSET] = {"OFFSET", 5, 0, N_("magic string offset")}, | |
108 | [COL_USAGE] = {"USAGE", 5, 0, N_("type description")}, | |
109 | [COL_DEVICE] = {"DEVICE", 5, 0, N_("block device name")} | |
110 | }; | |
111 | ||
112 | static int columns[ARRAY_SIZE(infos) * 2]; | |
113 | static size_t ncolumns; | |
114 | ||
115 | static int column_name_to_id(const char *name, size_t namesz) | |
c49057d2 | 116 | { |
d9921b2a KZ |
117 | size_t i; |
118 | ||
119 | assert(name); | |
120 | ||
121 | for (i = 0; i < ARRAY_SIZE(infos); i++) { | |
122 | const char *cn = infos[i].name; | |
123 | if (!strncasecmp(name, cn, namesz) && !*(cn + namesz)) | |
124 | return i; | |
c49057d2 | 125 | } |
d9921b2a KZ |
126 | warnx(_("unknown column: %s"), name); |
127 | return -1; | |
128 | } | |
c49057d2 | 129 | |
d9921b2a KZ |
130 | static int get_column_id(size_t num) |
131 | { | |
132 | assert(num < ncolumns); | |
133 | assert(columns[num] < (int)ARRAY_SIZE(infos)); | |
134 | return columns[num]; | |
135 | } | |
c49057d2 | 136 | |
d9921b2a KZ |
137 | static const struct colinfo *get_column_info(int num) |
138 | { | |
139 | return &infos[get_column_id(num)]; | |
c49057d2 KZ |
140 | } |
141 | ||
d9921b2a KZ |
142 | |
143 | static void init_output(struct wipe_control *ctl) | |
c49057d2 | 144 | { |
d9921b2a KZ |
145 | struct libscols_table *tb; |
146 | size_t i; | |
c49057d2 | 147 | |
d9921b2a KZ |
148 | scols_init_debug(0); |
149 | tb = scols_new_table(); | |
150 | if (!tb) | |
151 | err(EXIT_FAILURE, _("failed to allocate output table")); | |
c49057d2 | 152 | |
d9921b2a KZ |
153 | if (ctl->json) { |
154 | scols_table_enable_json(tb, 1); | |
155 | scols_table_set_name(tb, "signatures"); | |
156 | } | |
157 | scols_table_enable_noheadings(tb, ctl->no_headings); | |
c49057d2 | 158 | |
d9921b2a KZ |
159 | if (ctl->parsable) { |
160 | scols_table_enable_raw(tb, 1); | |
161 | scols_table_set_column_separator(tb, ","); | |
162 | } | |
c49057d2 | 163 | |
d9921b2a KZ |
164 | for (i = 0; i < ncolumns; i++) { |
165 | const struct colinfo *col = get_column_info(i); | |
c49057d2 | 166 | |
d9921b2a KZ |
167 | if (!scols_table_new_column(tb, col->name, col->whint, |
168 | col->flags)) | |
169 | err(EXIT_FAILURE, | |
170 | _("failed to initialize output column")); | |
171 | } | |
172 | ctl->outtab = tb; | |
c49057d2 KZ |
173 | } |
174 | ||
d9921b2a KZ |
175 | static void finalize_output(struct wipe_control *ctl) |
176 | { | |
177 | if (ctl->parsable && !ctl->no_headings | |
178 | && !scols_table_is_empty(ctl->outtab)) { | |
179 | struct libscols_iter *itr = scols_new_iter(SCOLS_ITER_FORWARD); | |
180 | struct libscols_column *cl; | |
181 | int i = 0; | |
182 | ||
183 | if (!itr) | |
184 | err_oom(); | |
185 | ||
186 | fputs("# ", stdout); | |
187 | while (scols_table_next_column(ctl->outtab, itr, &cl) == 0) { | |
188 | struct libscols_cell *hdr = scols_column_get_header(cl); | |
189 | const char *name = scols_cell_get_data(hdr); | |
190 | ||
191 | if (i) | |
192 | fputc(',', stdout); | |
193 | fputs(name, stdout); | |
194 | i++; | |
195 | } | |
196 | fputc('\n', stdout); | |
197 | scols_free_iter(itr); | |
198 | } | |
199 | scols_print_table(ctl->outtab); | |
200 | scols_unref_table(ctl->outtab); | |
201 | } | |
202 | ||
203 | static void fill_table_row(struct wipe_control *ctl, struct wipe_desc *wp) | |
c49057d2 | 204 | { |
d9921b2a KZ |
205 | static struct libscols_line *ln; |
206 | size_t i; | |
207 | ||
208 | ln = scols_table_new_line(ctl->outtab, NULL); | |
209 | if (!ln) | |
210 | errx(EXIT_FAILURE, _("failed to allocate output line")); | |
211 | ||
212 | for (i = 0; i < ncolumns; i++) { | |
213 | char *str = NULL; | |
214 | ||
215 | switch (get_column_id(i)) { | |
216 | case COL_UUID: | |
217 | if (wp->uuid) | |
218 | str = xstrdup(wp->uuid); | |
219 | break; | |
220 | case COL_LABEL: | |
221 | if (wp->label) | |
222 | str = xstrdup(wp->label); | |
223 | break; | |
224 | case COL_OFFSET: | |
225 | xasprintf(&str, "0x%jx", (intmax_t)wp->offset); | |
226 | break; | |
227 | case COL_LEN: | |
228 | xasprintf(&str, "%zu", wp->len); | |
229 | break; | |
230 | case COL_USAGE: | |
231 | if (wp->usage) | |
232 | str = xstrdup(wp->usage); | |
233 | break; | |
234 | case COL_TYPE: | |
235 | if (wp->type) | |
236 | str = xstrdup(wp->type); | |
237 | break; | |
238 | case COL_DEVICE: | |
239 | if (ctl->devname) { | |
240 | char *dev = xstrdup(ctl->devname); | |
241 | str = xstrdup(basename(dev)); | |
242 | free(dev); | |
243 | } | |
244 | break; | |
245 | default: | |
246 | abort(); | |
247 | } | |
c49057d2 | 248 | |
d9921b2a KZ |
249 | if (str && scols_line_refer_data(ln, i, str)) |
250 | errx(EXIT_FAILURE, _("failed to add output data")); | |
c49057d2 KZ |
251 | } |
252 | } | |
253 | ||
d9921b2a KZ |
254 | static void add_to_output(struct wipe_control *ctl, struct wipe_desc *wp) |
255 | { | |
256 | for (/*nothing*/; wp; wp = wp->next) | |
257 | fill_table_row(ctl, wp); | |
258 | } | |
259 | ||
c49057d2 KZ |
260 | static struct wipe_desc * |
261 | add_offset(struct wipe_desc *wp0, loff_t offset, int zap) | |
262 | { | |
263 | struct wipe_desc *wp = wp0; | |
264 | ||
265 | while (wp) { | |
266 | if (wp->offset == offset) | |
267 | return wp; | |
268 | wp = wp->next; | |
269 | } | |
270 | ||
a2f5c221 | 271 | wp = xcalloc(1, sizeof(struct wipe_desc)); |
c49057d2 KZ |
272 | wp->offset = offset; |
273 | wp->next = wp0; | |
081dc33b | 274 | wp->zap = zap ? 1 : 0; |
c49057d2 KZ |
275 | return wp; |
276 | } | |
277 | ||
c10695f8 MB |
278 | static struct wipe_desc * |
279 | clone_offset(struct wipe_desc *wp0) | |
280 | { | |
281 | struct wipe_desc *wp = NULL; | |
282 | ||
283 | while(wp0) { | |
284 | wp = add_offset(wp, wp0->offset, wp0->zap); | |
285 | wp0 = wp0->next; | |
286 | } | |
287 | ||
288 | return wp; | |
289 | } | |
290 | ||
c49057d2 | 291 | static struct wipe_desc * |
4e609281 | 292 | get_desc_for_probe(struct wipe_control *ctl, struct wipe_desc *wp, blkid_probe pr, int *found) |
c49057d2 | 293 | { |
44765fdd | 294 | const char *off, *type, *mag, *p, *usage = NULL; |
c49057d2 | 295 | size_t len; |
44765fdd | 296 | loff_t offset; |
081dc33b | 297 | int rc, ispt = 0; |
c49057d2 | 298 | |
193d6f27 KZ |
299 | if (found) |
300 | *found = 0; | |
301 | ||
44765fdd KZ |
302 | /* superblocks */ |
303 | if (blkid_probe_lookup_value(pr, "TYPE", &type, NULL) == 0) { | |
304 | rc = blkid_probe_lookup_value(pr, "SBMAGIC_OFFSET", &off, NULL); | |
305 | if (!rc) | |
306 | rc = blkid_probe_lookup_value(pr, "SBMAGIC", &mag, &len); | |
307 | if (rc) | |
308 | return wp; | |
c49057d2 | 309 | |
44765fdd KZ |
310 | /* partitions */ |
311 | } else if (blkid_probe_lookup_value(pr, "PTTYPE", &type, NULL) == 0) { | |
312 | rc = blkid_probe_lookup_value(pr, "PTMAGIC_OFFSET", &off, NULL); | |
313 | if (!rc) | |
314 | rc = blkid_probe_lookup_value(pr, "PTMAGIC", &mag, &len); | |
315 | if (rc) | |
316 | return wp; | |
d9921b2a | 317 | usage = N_("partition-table"); |
081dc33b | 318 | ispt = 1; |
44765fdd KZ |
319 | } else |
320 | return wp; | |
c49057d2 | 321 | |
4e609281 | 322 | if (ctl->type_pattern && !match_fstype(type, ctl->type_pattern)) |
f126cd46 KZ |
323 | return wp; |
324 | ||
44765fdd | 325 | offset = strtoll(off, NULL, 10); |
c49057d2 | 326 | |
44765fdd KZ |
327 | wp = add_offset(wp, offset, 0); |
328 | if (!wp) | |
329 | return NULL; | |
330 | ||
331 | if (usage || blkid_probe_lookup_value(pr, "USAGE", &usage, NULL) == 0) | |
c49057d2 | 332 | wp->usage = xstrdup(usage); |
c49057d2 | 333 | |
44765fdd KZ |
334 | wp->type = xstrdup(type); |
335 | wp->on_disk = 1; | |
081dc33b | 336 | wp->is_parttable = ispt ? 1 : 0; |
c49057d2 | 337 | |
44765fdd KZ |
338 | wp->magic = xmalloc(len); |
339 | memcpy(wp->magic, mag, len); | |
340 | wp->len = len; | |
c49057d2 | 341 | |
44765fdd KZ |
342 | if (blkid_probe_lookup_value(pr, "LABEL", &p, NULL) == 0) |
343 | wp->label = xstrdup(p); | |
344 | ||
345 | if (blkid_probe_lookup_value(pr, "UUID", &p, NULL) == 0) | |
346 | wp->uuid = xstrdup(p); | |
c49057d2 | 347 | |
193d6f27 KZ |
348 | if (found) |
349 | *found = 1; | |
c49057d2 KZ |
350 | return wp; |
351 | } | |
352 | ||
6611a3dd KZ |
353 | static blkid_probe |
354 | new_probe(const char *devname, int mode) | |
c49057d2 | 355 | { |
4e6fc113 | 356 | blkid_probe pr = NULL; |
c49057d2 | 357 | |
6611a3dd | 358 | if (!devname) |
c49057d2 KZ |
359 | return NULL; |
360 | ||
6611a3dd KZ |
361 | if (mode) { |
362 | int fd = open(devname, mode); | |
363 | if (fd < 0) | |
364 | goto error; | |
365 | ||
366 | pr = blkid_new_probe(); | |
f1b64c1c | 367 | if (!pr || blkid_probe_set_device(pr, fd, 0, 0) != 0) { |
4e6fc113 | 368 | close(fd); |
6611a3dd | 369 | goto error; |
4e6fc113 | 370 | } |
6611a3dd KZ |
371 | } else |
372 | pr = blkid_new_probe_from_filename(devname); | |
373 | ||
c49057d2 | 374 | if (!pr) |
6611a3dd | 375 | goto error; |
269c1a2a | 376 | |
c49057d2 | 377 | blkid_probe_enable_superblocks(pr, 1); |
90faf9eb KZ |
378 | blkid_probe_set_superblocks_flags(pr, |
379 | BLKID_SUBLKS_MAGIC | /* return magic string and offset */ | |
380 | BLKID_SUBLKS_TYPE | /* return superblock type */ | |
381 | BLKID_SUBLKS_USAGE | /* return USAGE= */ | |
382 | BLKID_SUBLKS_LABEL | /* return LABEL= */ | |
383 | BLKID_SUBLKS_UUID | /* return UUID= */ | |
384 | BLKID_SUBLKS_BADCSUM); /* accept bad checksums */ | |
c49057d2 | 385 | |
44765fdd | 386 | blkid_probe_enable_partitions(pr, 1); |
949e5c96 KZ |
387 | blkid_probe_set_partitions_flags(pr, BLKID_PARTS_MAGIC | |
388 | BLKID_PARTS_FORCE_GPT); | |
6611a3dd KZ |
389 | return pr; |
390 | error: | |
4e6fc113 | 391 | blkid_free_probe(pr); |
6611a3dd | 392 | err(EXIT_FAILURE, _("error: %s: probing initialization failed"), devname); |
6611a3dd KZ |
393 | } |
394 | ||
395 | static struct wipe_desc * | |
4e609281 | 396 | read_offsets(struct wipe_control *ctl, struct wipe_desc *wp) |
6611a3dd | 397 | { |
4e609281 | 398 | blkid_probe pr = new_probe(ctl->devname, 0); |
6611a3dd KZ |
399 | |
400 | if (!pr) | |
401 | return NULL; | |
402 | ||
c49057d2 | 403 | while (blkid_do_probe(pr) == 0) { |
193d6f27 KZ |
404 | int found = 0; |
405 | ||
4e609281 | 406 | wp = get_desc_for_probe(ctl, wp, pr, &found); |
c49057d2 KZ |
407 | if (!wp) |
408 | break; | |
92296e9b KZ |
409 | |
410 | /* hide last detected signature and scan again */ | |
193d6f27 KZ |
411 | if (found) { |
412 | blkid_probe_hide_range(pr, wp->offset, wp->len); | |
413 | blkid_probe_step_back(pr); | |
414 | } | |
c49057d2 KZ |
415 | } |
416 | ||
417 | blkid_free_probe(pr); | |
418 | return wp; | |
419 | } | |
420 | ||
24df2633 MB |
421 | static void |
422 | free_wipe(struct wipe_desc *wp) | |
423 | { | |
424 | while (wp) { | |
425 | struct wipe_desc *next = wp->next; | |
426 | ||
427 | free(wp->usage); | |
428 | free(wp->type); | |
429 | free(wp->magic); | |
430 | free(wp->label); | |
431 | free(wp->uuid); | |
432 | free(wp); | |
433 | ||
434 | wp = next; | |
435 | } | |
436 | } | |
437 | ||
4e609281 KZ |
438 | static void do_wipe_real(struct wipe_control *ctl, blkid_probe pr, |
439 | struct wipe_desc *w) | |
24df2633 MB |
440 | { |
441 | size_t i; | |
442 | ||
4e609281 | 443 | if (blkid_do_wipe(pr, ctl->noact) != 0) |
6f1507f1 | 444 | err(EXIT_FAILURE, _("%s: failed to erase %s magic string at offset 0x%08jx"), |
4e609281 | 445 | ctl->devname, w->type, (intmax_t)w->offset); |
24df2633 | 446 | |
4e609281 | 447 | if (ctl->quiet) |
24df2633 MB |
448 | return; |
449 | ||
1619e3e7 BS |
450 | printf(P_("%s: %zd byte was erased at offset 0x%08jx (%s): ", |
451 | "%s: %zd bytes were erased at offset 0x%08jx (%s): ", | |
452 | w->len), | |
4e609281 | 453 | ctl->devname, w->len, (intmax_t)w->offset, w->type); |
24df2633 MB |
454 | |
455 | for (i = 0; i < w->len; i++) { | |
456 | printf("%02x", w->magic[i]); | |
457 | if (i + 1 < w->len) | |
458 | fputc(' ', stdout); | |
459 | } | |
460 | putchar('\n'); | |
461 | } | |
462 | ||
7e658c15 OO |
463 | static void do_backup(struct wipe_desc *wp, const char *base) |
464 | { | |
465 | char *fname = NULL; | |
466 | int fd; | |
467 | ||
fdbd7bb9 | 468 | xasprintf(&fname, "%s0x%08jx.bak", base, (intmax_t)wp->offset); |
7e658c15 OO |
469 | |
470 | fd = open(fname, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR); | |
471 | if (fd < 0) | |
472 | goto err; | |
473 | if (write_all(fd, wp->magic, wp->len) != 0) | |
474 | goto err; | |
475 | close(fd); | |
476 | free(fname); | |
477 | return; | |
478 | err: | |
479 | err(EXIT_FAILURE, _("%s: failed to create a signature backup"), fname); | |
480 | } | |
481 | ||
11e88c86 | 482 | #ifdef BLKRRPART |
081dc33b KZ |
483 | static void rereadpt(int fd, const char *devname) |
484 | { | |
081dc33b KZ |
485 | struct stat st; |
486 | ||
487 | if (fstat(fd, &st) || !S_ISBLK(st.st_mode)) | |
488 | return; | |
489 | ||
490 | errno = 0; | |
491 | ioctl(fd, BLKRRPART); | |
a5c523a0 | 492 | printf(_("%s: calling ioctl to re-read partition table: %m\n"), devname); |
081dc33b | 493 | } |
11e88c86 | 494 | #endif |
081dc33b | 495 | |
6611a3dd | 496 | static struct wipe_desc * |
4e609281 | 497 | do_wipe(struct wipe_control *ctl, struct wipe_desc *wp) |
c49057d2 | 498 | { |
24ed0781 | 499 | int mode = O_RDWR, reread = 0, need_force = 0; |
2968c3fc | 500 | blkid_probe pr; |
05ba8c84 | 501 | struct wipe_desc *w, *wp0; |
4e609281 | 502 | int zap = ctl->all ? 1 : wp->zap; |
1666c155 | 503 | char *backup = NULL; |
c49057d2 | 504 | |
4e609281 | 505 | if (!ctl->force) |
1666c155 | 506 | mode |= O_EXCL; |
4e609281 KZ |
507 | |
508 | pr = new_probe(ctl->devname, mode); | |
6611a3dd KZ |
509 | if (!pr) |
510 | return NULL; | |
c49057d2 | 511 | |
4e609281 | 512 | if (zap && ctl->backup) { |
7e658c15 | 513 | const char *home = getenv ("HOME"); |
4e609281 | 514 | char *tmp = xstrdup(ctl->devname); |
8acff75a | 515 | |
7e658c15 OO |
516 | if (!home) |
517 | errx(EXIT_FAILURE, _("failed to create a signature backup, $HOME undefined")); | |
8acff75a RM |
518 | xasprintf (&backup, "%s/wipefs-%s-", home, basename(tmp)); |
519 | free(tmp); | |
7e658c15 OO |
520 | } |
521 | ||
2cd417ea | 522 | /* wp0 is the list of wanted offsets */ |
05ba8c84 KZ |
523 | wp0 = clone_offset(wp); |
524 | ||
6611a3dd | 525 | while (blkid_do_probe(pr) == 0) { |
2cd417ea KZ |
526 | int wiped = 0; |
527 | ||
4e609281 | 528 | wp = get_desc_for_probe(ctl, wp, pr, NULL); |
24df2633 | 529 | if (!wp) |
6611a3dd | 530 | break; |
24df2633 MB |
531 | |
532 | /* Check if offset is in provided list */ | |
533 | w = wp0; | |
534 | while(w && w->offset != wp->offset) | |
535 | w = w->next; | |
4e609281 | 536 | |
24df2633 | 537 | if (wp0 && !w) |
2cd417ea | 538 | goto done; |
24df2633 MB |
539 | |
540 | /* Mark done if found in provided list */ | |
541 | if (w) | |
542 | w->on_disk = wp->on_disk; | |
543 | ||
544 | if (!wp->on_disk) | |
2cd417ea | 545 | goto done; |
6611a3dd | 546 | |
4e609281 | 547 | if (!ctl->force |
24ed0781 KZ |
548 | && wp->is_parttable |
549 | && !blkid_probe_is_wholedisk(pr)) { | |
09af3db4 | 550 | warnx(_("%s: ignoring nested \"%s\" partition table " |
4e609281 | 551 | "on non-whole disk device"), ctl->devname, wp->type); |
24ed0781 | 552 | need_force = 1; |
2cd417ea | 553 | goto done; |
24ed0781 KZ |
554 | } |
555 | ||
7e658c15 | 556 | if (zap) { |
1666c155 KZ |
557 | if (backup) |
558 | do_backup(wp, backup); | |
4e609281 | 559 | do_wipe_real(ctl, pr, wp); |
081dc33b KZ |
560 | if (wp->is_parttable) |
561 | reread = 1; | |
2cd417ea KZ |
562 | wiped = 1; |
563 | } | |
564 | done: | |
565 | if (!wiped) { | |
566 | /* if the offset has not been wiped (probably because | |
567 | * filtered out by -t or -o) we need to hide it for | |
568 | * libblkid to try another magic string for the same | |
569 | * superblock, otherwise libblkid will continue with | |
570 | * another superblock. Don't forget that the same | |
571 | * superblock could be detected by more magic strings | |
572 | * */ | |
573 | blkid_probe_hide_range(pr, wp->offset, wp->len); | |
574 | blkid_probe_step_back(pr); | |
7e658c15 | 575 | } |
2cd417ea | 576 | |
c49057d2 KZ |
577 | } |
578 | ||
24df2633 | 579 | for (w = wp0; w != NULL; w = w->next) { |
4e609281 KZ |
580 | if (!w->on_disk && !ctl->quiet) |
581 | warnx(_("%s: offset 0x%jx not found"), | |
582 | ctl->devname, (uintmax_t)w->offset); | |
c49057d2 KZ |
583 | } |
584 | ||
24ed0781 KZ |
585 | if (need_force) |
586 | warnx(_("Use the --force option to force erase.")); | |
587 | ||
6611a3dd | 588 | fsync(blkid_probe_get_fd(pr)); |
081dc33b | 589 | |
11e88c86 | 590 | #ifdef BLKRRPART |
1577b259 | 591 | if (reread && (mode & O_EXCL)) |
4e609281 | 592 | rereadpt(blkid_probe_get_fd(pr), ctl->devname); |
11e88c86 | 593 | #endif |
081dc33b | 594 | |
6611a3dd KZ |
595 | close(blkid_probe_get_fd(pr)); |
596 | blkid_free_probe(pr); | |
24df2633 | 597 | free_wipe(wp0); |
1666c155 | 598 | free(backup); |
6611a3dd KZ |
599 | |
600 | return wp; | |
c49057d2 KZ |
601 | } |
602 | ||
69cc2ec0 | 603 | |
c49057d2 | 604 | static void __attribute__((__noreturn__)) |
6e1eda6f | 605 | usage(void) |
c49057d2 | 606 | { |
d9921b2a KZ |
607 | size_t i; |
608 | ||
42d2a8b3 KZ |
609 | fputs(USAGE_HEADER, stdout); |
610 | printf(_(" %s [options] <device>\n"), program_invocation_short_name); | |
611 | ||
612 | fputs(USAGE_SEPARATOR, stdout); | |
613 | puts(_("Wipe signatures from a device.")); | |
614 | ||
615 | fputs(USAGE_OPTIONS, stdout); | |
616 | puts(_(" -a, --all wipe all magic strings (BE CAREFUL!)")); | |
617 | puts(_(" -b, --backup create a signature backup in $HOME")); | |
618 | puts(_(" -f, --force force erasure")); | |
619 | puts(_(" -i, --noheadings don't print headings")); | |
620 | puts(_(" -J, --json use JSON output format")); | |
621 | puts(_(" -n, --no-act do everything except the actual write() call")); | |
622 | puts(_(" -o, --offset <num> offset to erase, in bytes")); | |
623 | puts(_(" -O, --output <list> COLUMNS to display (see below)")); | |
624 | puts(_(" -p, --parsable print out in parsable instead of printable format")); | |
625 | puts(_(" -q, --quiet suppress output messages")); | |
626 | puts(_(" -t, --types <list> limit the set of filesystem, RAIDs or partition tables")); | |
d9921b2a | 627 | |
f45f3ec3 | 628 | printf(USAGE_HELP_OPTIONS(21)); |
c49057d2 | 629 | |
d9921b2a KZ |
630 | fputs(USAGE_COLUMNS, stdout); |
631 | for (i = 0; i < ARRAY_SIZE(infos); i++) | |
632 | fprintf(stdout, " %8s %s\n", infos[i].name, _(infos[i].help)); | |
633 | ||
f45f3ec3 | 634 | printf(USAGE_MAN_TAIL("wipefs(8)")); |
6e1eda6f | 635 | exit(EXIT_SUCCESS); |
c49057d2 KZ |
636 | } |
637 | ||
638 | ||
639 | int | |
640 | main(int argc, char **argv) | |
641 | { | |
4e609281 KZ |
642 | struct wipe_control ctl = { .devname = NULL }; |
643 | struct wipe_desc *wp0 = NULL; | |
644 | int c, noffsets = 0; | |
d9921b2a | 645 | char *outarg = NULL; |
c49057d2 | 646 | |
6c7d5ae9 | 647 | static const struct option longopts[] = { |
87918040 SK |
648 | { "all", no_argument, NULL, 'a' }, |
649 | { "backup", no_argument, NULL, 'b' }, | |
650 | { "force", no_argument, NULL, 'f' }, | |
651 | { "help", no_argument, NULL, 'h' }, | |
652 | { "no-act", no_argument, NULL, 'n' }, | |
653 | { "offset", required_argument, NULL, 'o' }, | |
654 | { "parsable", no_argument, NULL, 'p' }, | |
655 | { "quiet", no_argument, NULL, 'q' }, | |
656 | { "types", required_argument, NULL, 't' }, | |
657 | { "version", no_argument, NULL, 'V' }, | |
d9921b2a KZ |
658 | { "json", no_argument, NULL, 'J'}, |
659 | { "noheadings",no_argument, NULL, 'i'}, | |
660 | { "output", required_argument, NULL, 'O'}, | |
87918040 | 661 | { NULL, 0, NULL, 0 } |
c49057d2 KZ |
662 | }; |
663 | ||
a7349ee3 | 664 | static const ul_excl_t excl[] = { /* rows and cols in ASCII order */ |
d9921b2a | 665 | { 'O','a','o' }, |
abb7b98c KZ |
666 | { 0 } |
667 | }; | |
668 | int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT; | |
669 | ||
c49057d2 KZ |
670 | setlocale(LC_ALL, ""); |
671 | bindtextdomain(PACKAGE, LOCALEDIR); | |
672 | textdomain(PACKAGE); | |
c05a80ca | 673 | atexit(close_stdout); |
c49057d2 | 674 | |
d9921b2a | 675 | while ((c = getopt_long(argc, argv, "abfhiJnO:o:pqt:V", longopts, NULL)) != -1) { |
abb7b98c KZ |
676 | |
677 | err_exclusive_options(c, longopts, excl, excl_st); | |
678 | ||
c49057d2 KZ |
679 | switch(c) { |
680 | case 'a': | |
4e609281 | 681 | ctl.all = 1; |
c49057d2 | 682 | break; |
7e658c15 | 683 | case 'b': |
4e609281 | 684 | ctl.backup = 1; |
7e658c15 | 685 | break; |
2968c3fc | 686 | case 'f': |
4e609281 | 687 | ctl.force = 1; |
2968c3fc | 688 | break; |
c49057d2 | 689 | case 'h': |
6e1eda6f | 690 | usage(); |
c49057d2 | 691 | break; |
d9921b2a KZ |
692 | case 'J': |
693 | ctl.json = 1; | |
694 | break; | |
695 | case 'i': | |
696 | ctl.no_headings = 1; | |
697 | break; | |
698 | case 'O': | |
699 | outarg = optarg; | |
700 | break; | |
c49057d2 | 701 | case 'n': |
4e609281 | 702 | ctl.noact = 1; |
c49057d2 KZ |
703 | break; |
704 | case 'o': | |
99727496 | 705 | wp0 = add_offset(wp0, strtosize_or_err(optarg, |
db41a429 | 706 | _("invalid offset argument")), 1); |
4e609281 | 707 | noffsets++; |
c49057d2 KZ |
708 | break; |
709 | case 'p': | |
4e609281 | 710 | ctl.parsable = 1; |
d9921b2a | 711 | ctl.no_headings = 1; |
c49057d2 | 712 | break; |
0fd93af6 | 713 | case 'q': |
4e609281 | 714 | ctl.quiet = 1; |
0fd93af6 | 715 | break; |
f126cd46 | 716 | case 't': |
4e609281 | 717 | ctl.type_pattern = optarg; |
f126cd46 | 718 | break; |
11295cd1 | 719 | case 'V': |
e421313d | 720 | printf(UTIL_LINUX_VERSION); |
09467812 | 721 | return EXIT_SUCCESS; |
c49057d2 | 722 | default: |
677ec86c | 723 | errtryhelp(EXIT_FAILURE); |
c49057d2 KZ |
724 | } |
725 | } | |
726 | ||
6e1eda6f RM |
727 | if (optind == argc) { |
728 | warnx(_("no device specified")); | |
729 | errtryhelp(EXIT_FAILURE); | |
730 | ||
731 | } | |
c49057d2 | 732 | |
4e609281 | 733 | if (ctl.backup && !(ctl.all || noffsets)) |
7e658c15 OO |
734 | warnx(_("The --backup option is meaningless in this context")); |
735 | ||
4e609281 | 736 | if (!ctl.all && !noffsets) { |
6611a3dd KZ |
737 | /* |
738 | * Print only | |
739 | */ | |
d9921b2a KZ |
740 | if (ctl.parsable) { |
741 | /* keep it backward compatible */ | |
742 | columns[ncolumns++] = COL_OFFSET; | |
743 | columns[ncolumns++] = COL_UUID; | |
744 | columns[ncolumns++] = COL_LABEL; | |
745 | columns[ncolumns++] = COL_TYPE; | |
746 | } else { | |
747 | /* default, may be modified by -O <list> */ | |
748 | columns[ncolumns++] = COL_DEVICE; | |
749 | columns[ncolumns++] = COL_OFFSET; | |
750 | columns[ncolumns++] = COL_TYPE; | |
751 | columns[ncolumns++] = COL_UUID; | |
752 | columns[ncolumns++] = COL_LABEL; | |
753 | } | |
754 | ||
755 | if (outarg | |
756 | && string_add_to_idarray(outarg, columns, ARRAY_SIZE(columns), | |
757 | &ncolumns, column_name_to_id) < 0) | |
758 | return EXIT_FAILURE; | |
759 | ||
760 | init_output(&ctl); | |
4e609281 | 761 | |
c10695f8 | 762 | while (optind < argc) { |
4e609281 KZ |
763 | ctl.devname = argv[optind++]; |
764 | wp0 = read_offsets(&ctl, NULL); | |
c10695f8 | 765 | if (wp0) |
d9921b2a | 766 | add_to_output(&ctl, wp0); |
c10695f8 MB |
767 | free_wipe(wp0); |
768 | } | |
d9921b2a | 769 | finalize_output(&ctl); |
6611a3dd KZ |
770 | } else { |
771 | /* | |
772 | * Erase | |
773 | */ | |
c10695f8 | 774 | while (optind < argc) { |
4e609281 KZ |
775 | struct wipe_desc *wp = clone_offset(wp0); |
776 | ||
777 | ctl.devname = argv[optind++]; | |
778 | wp = do_wipe(&ctl, wp); | |
c10695f8 MB |
779 | free_wipe(wp); |
780 | } | |
c49057d2 | 781 | } |
6611a3dd | 782 | |
c49057d2 KZ |
783 | return EXIT_SUCCESS; |
784 | } |