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