]> git.ipfire.org Git - thirdparty/util-linux.git/blame - misc-utils/wipefs.c
misc: consolidate macro style USAGE_HELP_OPTIONS
[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
KZ
58
59 unsigned int zap : 1,
60 on_disk : 1,
61 is_parttable : 1;
62
c49057d2
KZ
63};
64
4e609281
KZ
65struct 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 */
83enum {
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 */
94struct 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 */
102static 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
112static int columns[ARRAY_SIZE(infos) * 2];
113static size_t ncolumns;
114
115static 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
130static 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
137static const struct colinfo *get_column_info(int num)
138{
139 return &infos[get_column_id(num)];
c49057d2
KZ
140}
141
d9921b2a
KZ
142
143static 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
175static 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
203static 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
254static 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
260static struct wipe_desc *
261add_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
278static struct wipe_desc *
279clone_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 291static struct wipe_desc *
4e609281 292get_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
353static blkid_probe
354new_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;
390error:
4e6fc113 391 blkid_free_probe(pr);
6611a3dd 392 err(EXIT_FAILURE, _("error: %s: probing initialization failed"), devname);
6611a3dd
KZ
393}
394
395static struct wipe_desc *
4e609281 396read_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
421static void
422free_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
438static 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
463static 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;
478err:
479 err(EXIT_FAILURE, _("%s: failed to create a signature backup"), fname);
480}
481
11e88c86 482#ifdef BLKRRPART
081dc33b
KZ
483static 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 496static struct wipe_desc *
4e609281 497do_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 604static void __attribute__((__noreturn__))
6e1eda6f 605usage(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
639int
640main(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}