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