#include <libgen.h>
#include <blkid.h>
+#include <libsmartcols.h>
#include "nls.h"
#include "xalloc.h"
struct wipe_desc *next;
- unsigned int zap : 1,
- on_disk : 1,
+ unsigned int on_disk : 1,
is_parttable : 1;
};
-enum {
- WP_MODE_PRETTY, /* default */
- WP_MODE_PARSABLE
+struct wipe_control {
+ char *devname;
+ const char *type_pattern; /* -t <pattern> */
+
+ struct libscols_table *outtab;
+ struct wipe_desc *offsets; /* -o <offset> -o <offset> ... */
+
+ size_t ndevs; /* number of devices to probe */
+
+ char **reread; /* devices to BLKRRPART */
+ size_t nrereads; /* size of reread */
+
+ unsigned int noact : 1,
+ all : 1,
+ quiet : 1,
+ backup : 1,
+ force : 1,
+ json : 1,
+ no_headings : 1,
+ parsable : 1;
};
+
+/* column IDs */
enum {
- WP_FL_NOACT = (1 << 1),
- WP_FL_ALL = (1 << 2),
- WP_FL_QUIET = (1 << 3),
- WP_FL_BACKUP = (1 << 4),
- WP_FL_FORCE = (1 << 5)
+ COL_UUID = 0,
+ COL_LABEL,
+ COL_LEN,
+ COL_TYPE,
+ COL_OFFSET,
+ COL_USAGE,
+ COL_DEVICE
+};
+
+/* column names */
+struct colinfo {
+ const char *name; /* header */
+ double whint; /* width hint (N < 1 is in percent of termwidth) */
+ int flags; /* SCOLS_FL_* */
+ const char *help;
+};
+
+/* columns descriptions */
+static const struct colinfo infos[] = {
+ [COL_UUID] = {"UUID", 4, 0, N_("partition/filesystem UUID")},
+ [COL_LABEL] = {"LABEL", 5, 0, N_("filesystem LABEL")},
+ [COL_LEN] = {"LENGTH", 6, 0, N_("magic string length")},
+ [COL_TYPE] = {"TYPE", 4, 0, N_("superblok type")},
+ [COL_OFFSET] = {"OFFSET", 5, 0, N_("magic string offset")},
+ [COL_USAGE] = {"USAGE", 5, 0, N_("type description")},
+ [COL_DEVICE] = {"DEVICE", 5, 0, N_("block device name")}
};
-static const char *type_pattern;
+static int columns[ARRAY_SIZE(infos) * 2];
+static size_t ncolumns;
-static void
-print_pretty(struct wipe_desc *wp, int line)
+static int column_name_to_id(const char *name, size_t namesz)
{
- if (!line) {
- printf("offset type\n");
- printf("----------------------------------------------------------------\n");
+ size_t i;
+
+ assert(name);
+
+ for (i = 0; i < ARRAY_SIZE(infos); i++) {
+ const char *cn = infos[i].name;
+ if (!strncasecmp(name, cn, namesz) && !*(cn + namesz))
+ return i;
}
+ warnx(_("unknown column: %s"), name);
+ return -1;
+}
- printf("0x%-17jx %s [%s]", (intmax_t)wp->offset, wp->type, _(wp->usage));
+static int get_column_id(size_t num)
+{
+ assert(num < ncolumns);
+ assert(columns[num] < (int)ARRAY_SIZE(infos));
+ return columns[num];
+}
- if (wp->label && *wp->label)
- printf("\n%27s %s", "LABEL:", wp->label);
- if (wp->uuid)
- printf("\n%27s %s", "UUID: ", wp->uuid);
- puts("\n");
+static const struct colinfo *get_column_info(int num)
+{
+ return &infos[get_column_id(num)];
}
-static void
-print_parsable(struct wipe_desc *wp, int line)
+
+static void init_output(struct wipe_control *ctl)
{
- char enc[256];
+ struct libscols_table *tb;
+ size_t i;
- if (!line)
- printf("# offset,uuid,label,type\n");
+ scols_init_debug(0);
+ tb = scols_new_table();
+ if (!tb)
+ err(EXIT_FAILURE, _("failed to allocate output table"));
- printf("0x%jx,", (intmax_t)wp->offset);
+ if (ctl->json) {
+ scols_table_enable_json(tb, 1);
+ scols_table_set_name(tb, "signatures");
+ }
+ scols_table_enable_noheadings(tb, ctl->no_headings);
- if (wp->uuid) {
- blkid_encode_string(wp->uuid, enc, sizeof(enc));
- printf("%s,", enc);
- } else
- fputc(',', stdout);
+ if (ctl->parsable) {
+ scols_table_enable_raw(tb, 1);
+ scols_table_set_column_separator(tb, ",");
+ }
- if (wp->label) {
- blkid_encode_string(wp->label, enc, sizeof(enc));
- printf("%s,", enc);
- } else
- fputc(',', stdout);
+ for (i = 0; i < ncolumns; i++) {
+ const struct colinfo *col = get_column_info(i);
+ struct libscols_column *cl;
+
+ cl = scols_table_new_column(tb, col->name, col->whint,
+ col->flags);
+ if (!cl)
+ err(EXIT_FAILURE,
+ _("failed to initialize output column"));
+ if (ctl->json) {
+ int id = get_column_id(i);
+
+ if (id == COL_LEN)
+ scols_column_set_json_type(cl, SCOLS_JSON_NUMBER);
+ }
+ }
+ ctl->outtab = tb;
+}
- blkid_encode_string(wp->type, enc, sizeof(enc));
- printf("%s\n", enc);
+static void finalize_output(struct wipe_control *ctl)
+{
+ if (ctl->parsable && !ctl->no_headings
+ && !scols_table_is_empty(ctl->outtab)) {
+ struct libscols_iter *itr = scols_new_iter(SCOLS_ITER_FORWARD);
+ struct libscols_column *cl;
+ int i = 0;
+
+ if (!itr)
+ err_oom();
+
+ fputs("# ", stdout);
+ while (scols_table_next_column(ctl->outtab, itr, &cl) == 0) {
+ struct libscols_cell *hdr = scols_column_get_header(cl);
+ const char *name = scols_cell_get_data(hdr);
+
+ if (i)
+ fputc(',', stdout);
+ fputs(name, stdout);
+ i++;
+ }
+ fputc('\n', stdout);
+ scols_free_iter(itr);
+ }
+ scols_print_table(ctl->outtab);
+ scols_unref_table(ctl->outtab);
}
-static void
-print_all(struct wipe_desc *wp, int mode)
+static void fill_table_row(struct wipe_control *ctl, struct wipe_desc *wp)
{
- int n = 0;
+ static struct libscols_line *ln;
+ size_t i;
- while (wp) {
- switch (mode) {
- case WP_MODE_PRETTY:
- print_pretty(wp, n++);
+ ln = scols_table_new_line(ctl->outtab, NULL);
+ if (!ln)
+ errx(EXIT_FAILURE, _("failed to allocate output line"));
+
+ for (i = 0; i < ncolumns; i++) {
+ char *str = NULL;
+
+ switch (get_column_id(i)) {
+ case COL_UUID:
+ if (wp->uuid)
+ str = xstrdup(wp->uuid);
break;
- case WP_MODE_PARSABLE:
- print_parsable(wp, n++);
+ case COL_LABEL:
+ if (wp->label)
+ str = xstrdup(wp->label);
+ break;
+ case COL_OFFSET:
+ xasprintf(&str, "0x%jx", (intmax_t)wp->offset);
+ break;
+ case COL_LEN:
+ xasprintf(&str, "%zu", wp->len);
+ break;
+ case COL_USAGE:
+ if (wp->usage)
+ str = xstrdup(wp->usage);
+ break;
+ case COL_TYPE:
+ if (wp->type)
+ str = xstrdup(wp->type);
+ break;
+ case COL_DEVICE:
+ if (ctl->devname) {
+ char *dev = xstrdup(ctl->devname);
+ str = xstrdup(basename(dev));
+ free(dev);
+ }
break;
default:
abort();
}
- wp = wp->next;
+
+ if (str && scols_line_refer_data(ln, i, str))
+ errx(EXIT_FAILURE, _("failed to add output data"));
}
}
-static struct wipe_desc *
-add_offset(struct wipe_desc *wp0, loff_t offset, int zap)
+static void add_to_output(struct wipe_control *ctl, struct wipe_desc *wp)
{
- struct wipe_desc *wp = wp0;
+ for (/*nothing*/; wp; wp = wp->next)
+ fill_table_row(ctl, wp);
+}
- while (wp) {
- if (wp->offset == offset)
- return wp;
- wp = wp->next;
+/* Allocates a new wipe_desc and add to the wp0 if not NULL */
+static struct wipe_desc *add_offset(struct wipe_desc **wp0, loff_t offset)
+{
+ struct wipe_desc *wp, *last = NULL;
+
+ if (wp0) {
+ /* check if already exists */
+ for (wp = *wp0; wp; wp = wp->next) {
+ if (wp->offset == offset)
+ return wp;
+ last = wp;
+ }
}
wp = xcalloc(1, sizeof(struct wipe_desc));
wp->offset = offset;
- wp->next = wp0;
- wp->zap = zap ? 1 : 0;
- return wp;
-}
-
-static struct wipe_desc *
-clone_offset(struct wipe_desc *wp0)
-{
- struct wipe_desc *wp = NULL;
-
- while(wp0) {
- wp = add_offset(wp, wp0->offset, wp0->zap);
- wp0 = wp0->next;
- }
+ wp->next = NULL;
+ if (last)
+ last->next = wp;
+ if (wp0 && !*wp0)
+ *wp0 = wp;
return wp;
}
-static struct wipe_desc *
-get_desc_for_probe(struct wipe_desc *wp, blkid_probe pr)
+/* Read data from libblkid and if detected type pass -t and -o filters than:
+ * - allocates a new wipe_desc
+ * - add the new wipe_desc to wp0 list (if not NULL)
+ *
+ * The function always returns offset and len if libblkid detected something.
+ */
+static struct wipe_desc *get_desc_for_probe(struct wipe_control *ctl,
+ struct wipe_desc **wp0,
+ blkid_probe pr,
+ loff_t *offset,
+ size_t *len)
{
- const char *off, *type, *mag, *p, *usage = NULL;
- size_t len;
- loff_t offset;
+ const char *off, *type, *mag, *p, *use = NULL;
+ struct wipe_desc *wp;
int rc, ispt = 0;
+ *len = 0;
+
/* superblocks */
if (blkid_probe_lookup_value(pr, "TYPE", &type, NULL) == 0) {
rc = blkid_probe_lookup_value(pr, "SBMAGIC_OFFSET", &off, NULL);
if (!rc)
- rc = blkid_probe_lookup_value(pr, "SBMAGIC", &mag, &len);
+ rc = blkid_probe_lookup_value(pr, "SBMAGIC", &mag, len);
if (rc)
- return wp;
+ return NULL;
/* partitions */
} else if (blkid_probe_lookup_value(pr, "PTTYPE", &type, NULL) == 0) {
rc = blkid_probe_lookup_value(pr, "PTMAGIC_OFFSET", &off, NULL);
if (!rc)
- rc = blkid_probe_lookup_value(pr, "PTMAGIC", &mag, &len);
+ rc = blkid_probe_lookup_value(pr, "PTMAGIC", &mag, len);
if (rc)
- return wp;
- usage = N_("partition table");
+ return NULL;
+ use = N_("partition-table");
ispt = 1;
} else
- return wp;
+ return NULL;
+
+ *offset = strtoll(off, NULL, 10);
- if (type_pattern && !match_fstype(type, type_pattern))
- return wp;
+ /* Filter out by -t <type> */
+ if (ctl->type_pattern && !match_fstype(type, ctl->type_pattern))
+ return NULL;
+
+ /* Filter out by -o <offset> */
+ if (ctl->offsets) {
+ struct wipe_desc *w = NULL;
- offset = strtoll(off, NULL, 10);
+ for (w = ctl->offsets; w; w = w->next) {
+ if (w->offset == *offset)
+ break;
+ }
+ if (!w)
+ return NULL;
- wp = add_offset(wp, offset, 0);
+ w->on_disk = 1; /* mark as "found" */
+ }
+
+ wp = add_offset(wp0, *offset);
if (!wp)
return NULL;
- if (usage || blkid_probe_lookup_value(pr, "USAGE", &usage, NULL) == 0)
- wp->usage = xstrdup(usage);
+ if (use || blkid_probe_lookup_value(pr, "USAGE", &use, NULL) == 0)
+ wp->usage = xstrdup(use);
wp->type = xstrdup(type);
wp->on_disk = 1;
wp->is_parttable = ispt ? 1 : 0;
- wp->magic = xmalloc(len);
- memcpy(wp->magic, mag, len);
- wp->len = len;
+ wp->magic = xmalloc(*len);
+ memcpy(wp->magic, mag, *len);
+ wp->len = *len;
if (blkid_probe_lookup_value(pr, "LABEL", &p, NULL) == 0)
wp->label = xstrdup(p);
return NULL;
if (mode) {
- int fd = open(devname, mode);
+ int fd = open(devname, mode | O_NONBLOCK);
if (fd < 0)
goto error;
err(EXIT_FAILURE, _("error: %s: probing initialization failed"), devname);
}
-static struct wipe_desc *
-read_offsets(struct wipe_desc *wp, const char *devname)
+static struct wipe_desc *read_offsets(struct wipe_control *ctl)
{
- blkid_probe pr = new_probe(devname, 0);
+ blkid_probe pr = new_probe(ctl->devname, 0);
+ struct wipe_desc *wp0 = NULL;
if (!pr)
return NULL;
while (blkid_do_probe(pr) == 0) {
- wp = get_desc_for_probe(wp, pr);
- if (!wp)
- break;
+ size_t len = 0;
+ loff_t offset = 0;
+
+ /* add a new offset to wp0 */
+ get_desc_for_probe(ctl, &wp0, pr, &offset, &len);
+
+ /* hide last detected signature and scan again */
+ if (len) {
+ blkid_probe_hide_range(pr, offset, len);
+ blkid_probe_step_back(pr);
+ }
}
blkid_free_probe(pr);
- return wp;
+ return wp0;
}
-static void
-free_wipe(struct wipe_desc *wp)
+static void free_wipe(struct wipe_desc *wp)
{
while (wp) {
struct wipe_desc *next = wp->next;
}
}
-static void do_wipe_real(blkid_probe pr, const char *devname,
- struct wipe_desc *w, int flags)
+static void do_wipe_real(struct wipe_control *ctl, blkid_probe pr,
+ struct wipe_desc *w)
{
size_t i;
- if (blkid_do_wipe(pr, (flags & WP_FL_NOACT) != 0))
+ if (blkid_do_wipe(pr, ctl->noact) != 0)
err(EXIT_FAILURE, _("%s: failed to erase %s magic string at offset 0x%08jx"),
- devname, w->type, (intmax_t)w->offset);
+ ctl->devname, w->type, (intmax_t)w->offset);
- if (flags & WP_FL_QUIET)
+ if (ctl->quiet)
return;
printf(P_("%s: %zd byte was erased at offset 0x%08jx (%s): ",
"%s: %zd bytes were erased at offset 0x%08jx (%s): ",
w->len),
- devname, w->len, (intmax_t)w->offset, w->type);
+ ctl->devname, w->len, (intmax_t)w->offset, w->type);
for (i = 0; i < w->len; i++) {
printf("%02x", w->magic[i]);
static void rereadpt(int fd, const char *devname)
{
struct stat st;
+ int try = 0;
if (fstat(fd, &st) || !S_ISBLK(st.st_mode))
return;
- errno = 0;
- ioctl(fd, BLKRRPART);
+ do {
+ /*
+ * Unfortunately, it's pretty common that the first re-read
+ * without delay is uncuccesful. The reason is probably kernel
+ * and/or udevd. Let's wait a moment and try more attempts.
+ */
+ xusleep(25000);
+
+ errno = 0;
+ ioctl(fd, BLKRRPART);
+ if (errno != EBUSY)
+ break;
+ } while (try++ < 4);
+
printf(_("%s: calling ioctl to re-read partition table: %m\n"), devname);
}
#endif
-static struct wipe_desc *
-do_wipe(struct wipe_desc *wp, const char *devname, int flags)
+static int do_wipe(struct wipe_control *ctl)
{
int mode = O_RDWR, reread = 0, need_force = 0;
blkid_probe pr;
- struct wipe_desc *w, *wp0;
- int zap = (flags & WP_FL_ALL) ? 1 : wp->zap;
char *backup = NULL;
+ struct wipe_desc *w;
- if (!(flags & WP_FL_FORCE))
+ if (!ctl->force)
mode |= O_EXCL;
- pr = new_probe(devname, mode);
+
+ pr = new_probe(ctl->devname, mode);
if (!pr)
- return NULL;
+ return -errno;
- if (zap && (flags & WP_FL_BACKUP)) {
+ if (ctl->backup) {
const char *home = getenv ("HOME");
- char *tmp = xstrdup(devname);
+ char *tmp = xstrdup(ctl->devname);
if (!home)
errx(EXIT_FAILURE, _("failed to create a signature backup, $HOME undefined"));
free(tmp);
}
- wp0 = clone_offset(wp);
-
while (blkid_do_probe(pr) == 0) {
- wp = get_desc_for_probe(wp, pr);
- if (!wp)
- break;
+ int wiped = 0;
+ size_t len = 0;
+ loff_t offset = 0;
+ struct wipe_desc *wp;
- /* Check if offset is in provided list */
- w = wp0;
- while(w && w->offset != wp->offset)
- w = w->next;
- if (wp0 && !w)
- continue;
-
- /* Mark done if found in provided list */
- if (w)
- w->on_disk = wp->on_disk;
-
- if (!wp->on_disk)
- continue;
+ wp = get_desc_for_probe(ctl, NULL, pr, &offset, &len);
+ if (!wp)
+ goto done;
- if (!(flags & WP_FL_FORCE)
+ if (!ctl->force
&& wp->is_parttable
&& !blkid_probe_is_wholedisk(pr)) {
warnx(_("%s: ignoring nested \"%s\" partition table "
- "on non-whole disk device"), devname, wp->type);
+ "on non-whole disk device"), ctl->devname, wp->type);
need_force = 1;
- continue;
+ goto done;
}
- if (zap) {
- if (backup)
- do_backup(wp, backup);
- do_wipe_real(pr, devname, wp, flags);
- if (wp->is_parttable)
- reread = 1;
+ if (backup)
+ do_backup(wp, backup);
+ do_wipe_real(ctl, pr, wp);
+ if (wp->is_parttable)
+ reread = 1;
+ wiped = 1;
+ done:
+ if (!wiped && len) {
+ /* if the offset has not been wiped (probably because
+ * filtered out by -t or -o) we need to hide it for
+ * libblkid to try another magic string for the same
+ * superblock, otherwise libblkid will continue with
+ * another superblock. Don't forget that the same
+ * superblock could be detected by more magic strings
+ * */
+ blkid_probe_hide_range(pr, offset, len);
+ blkid_probe_step_back(pr);
}
+ free_wipe(wp);
}
- for (w = wp0; w != NULL; w = w->next) {
- if (!w->on_disk && !(flags & WP_FL_QUIET))
- warnx(_("%s: offset 0x%jx not found"), devname, (uintmax_t)w->offset);
+ for (w = ctl->offsets; w; w = w->next) {
+ if (!w->on_disk && !ctl->quiet)
+ warnx(_("%s: offset 0x%jx not found"),
+ ctl->devname, (uintmax_t)w->offset);
}
if (need_force)
fsync(blkid_probe_get_fd(pr));
#ifdef BLKRRPART
- if (reread && (mode & O_EXCL))
- rereadpt(blkid_probe_get_fd(pr), devname);
+ if (reread && (mode & O_EXCL)) {
+ if (ctl->ndevs > 1) {
+ /*
+ * We're going to probe more device, let's postpone
+ * re-read PT ioctl until all is erased to avoid
+ * situation we erase PT on /dev/sda before /dev/sdaN
+ * devices are processed.
+ */
+ if (!ctl->reread)
+ ctl->reread = xcalloc(ctl->ndevs, sizeof(char *));
+
+ ctl->reread[ctl->nrereads++] = ctl->devname;
+ } else
+ rereadpt(blkid_probe_get_fd(pr), ctl->devname);
+ }
#endif
close(blkid_probe_get_fd(pr));
blkid_free_probe(pr);
- free_wipe(wp0);
free(backup);
-
- return wp;
+ return 0;
}
static void __attribute__((__noreturn__))
usage(void)
{
- FILE *out = stdout;
- fputs(USAGE_HEADER, out);
- fprintf(out,
- _(" %s [options] <device>\n"), program_invocation_short_name);
-
- fputs(USAGE_SEPARATOR, out);
- fputs(_("Wipe signatures from a device.\n"), out);
-
- fputs(USAGE_OPTIONS, out);
- fputs(_(" -a, --all wipe all magic strings (BE CAREFUL!)\n"
- " -b, --backup create a signature backup in $HOME\n"
- " -f, --force force erasure\n"
- " -n, --no-act do everything except the actual write() call\n"
- " -o, --offset <num> offset to erase, in bytes\n"
- " -p, --parsable print out in parsable instead of printable format\n"
- " -q, --quiet suppress output messages\n"
- " -t, --types <list> limit the set of filesystem, RAIDs or partition tables\n"
- ), out);
- print_usage_help_options(21);
-
- fprintf(out, USAGE_MAN_TAIL("wipefs(8)"));
+ size_t i;
+
+ fputs(USAGE_HEADER, stdout);
+ printf(_(" %s [options] <device>\n"), program_invocation_short_name);
+
+ fputs(USAGE_SEPARATOR, stdout);
+ puts(_("Wipe signatures from a device."));
+
+ fputs(USAGE_OPTIONS, stdout);
+ puts(_(" -a, --all wipe all magic strings (BE CAREFUL!)"));
+ puts(_(" -b, --backup create a signature backup in $HOME"));
+ puts(_(" -f, --force force erasure"));
+ puts(_(" -i, --noheadings don't print headings"));
+ puts(_(" -J, --json use JSON output format"));
+ puts(_(" -n, --no-act do everything except the actual write() call"));
+ puts(_(" -o, --offset <num> offset to erase, in bytes"));
+ puts(_(" -O, --output <list> COLUMNS to display (see below)"));
+ puts(_(" -p, --parsable print out in parsable instead of printable format"));
+ puts(_(" -q, --quiet suppress output messages"));
+ puts(_(" -t, --types <list> limit the set of filesystem, RAIDs or partition tables"));
+
+ printf(USAGE_HELP_OPTIONS(21));
+
+ fputs(USAGE_ARGUMENTS, stdout);
+ printf(USAGE_ARG_SIZE(_("<num>")));
+
+ fputs(USAGE_COLUMNS, stdout);
+ for (i = 0; i < ARRAY_SIZE(infos); i++)
+ fprintf(stdout, " %8s %s\n", infos[i].name, _(infos[i].help));
+
+ printf(USAGE_MAN_TAIL("wipefs(8)"));
exit(EXIT_SUCCESS);
}
int
main(int argc, char **argv)
{
- struct wipe_desc *wp0 = NULL, *wp;
- int c, has_offset = 0, flags = 0;
- int mode = WP_MODE_PRETTY;
+ struct wipe_control ctl = { .devname = NULL };
+ int c;
+ char *outarg = NULL;
static const struct option longopts[] = {
{ "all", no_argument, NULL, 'a' },
{ "quiet", no_argument, NULL, 'q' },
{ "types", required_argument, NULL, 't' },
{ "version", no_argument, NULL, 'V' },
+ { "json", no_argument, NULL, 'J'},
+ { "noheadings",no_argument, NULL, 'i'},
+ { "output", required_argument, NULL, 'O'},
{ NULL, 0, NULL, 0 }
};
static const ul_excl_t excl[] = { /* rows and cols in ASCII order */
- { 'a','o' },
+ { 'O','a','o' },
{ 0 }
};
int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
- atexit(close_stdout);
+ close_stdout_atexit();
- while ((c = getopt_long(argc, argv, "abfhno:pqt:V", longopts, NULL)) != -1) {
+ while ((c = getopt_long(argc, argv, "abfhiJnO:o:pqt:V", longopts, NULL)) != -1) {
err_exclusive_options(c, longopts, excl, excl_st);
switch(c) {
case 'a':
- flags |= WP_FL_ALL;
+ ctl.all = 1;
break;
case 'b':
- flags |= WP_FL_BACKUP;
+ ctl.backup = 1;
break;
case 'f':
- flags |= WP_FL_FORCE;
+ ctl.force = 1;
break;
- case 'h':
- usage();
+ case 'J':
+ ctl.json = 1;
+ break;
+ case 'i':
+ ctl.no_headings = 1;
+ break;
+ case 'O':
+ outarg = optarg;
break;
case 'n':
- flags |= WP_FL_NOACT;
+ ctl.noact = 1;
break;
case 'o':
- wp0 = add_offset(wp0, strtosize_or_err(optarg,
- _("invalid offset argument")), 1);
- has_offset++;
+ add_offset(&ctl.offsets, strtosize_or_err(optarg,
+ _("invalid offset argument")));
break;
case 'p':
- mode = WP_MODE_PARSABLE;
+ ctl.parsable = 1;
+ ctl.no_headings = 1;
break;
case 'q':
- flags |= WP_FL_QUIET;
+ ctl.quiet = 1;
break;
case 't':
- type_pattern = optarg;
+ ctl.type_pattern = optarg;
break;
+
+ case 'h':
+ usage();
case 'V':
- printf(UTIL_LINUX_VERSION);
- return EXIT_SUCCESS;
+ print_version(EXIT_SUCCESS);
default:
errtryhelp(EXIT_FAILURE);
}
}
- if ((flags & WP_FL_BACKUP) && !((flags & WP_FL_ALL) || has_offset))
+ if (ctl.backup && !(ctl.all || ctl.offsets))
warnx(_("The --backup option is meaningless in this context"));
- if (!(flags & WP_FL_ALL) && !has_offset) {
+ if (!ctl.all && !ctl.offsets) {
/*
* Print only
*/
+ if (ctl.parsable) {
+ /* keep it backward compatible */
+ columns[ncolumns++] = COL_OFFSET;
+ columns[ncolumns++] = COL_UUID;
+ columns[ncolumns++] = COL_LABEL;
+ columns[ncolumns++] = COL_TYPE;
+ } else {
+ /* default, may be modified by -O <list> */
+ columns[ncolumns++] = COL_DEVICE;
+ columns[ncolumns++] = COL_OFFSET;
+ columns[ncolumns++] = COL_TYPE;
+ columns[ncolumns++] = COL_UUID;
+ columns[ncolumns++] = COL_LABEL;
+ }
+
+ if (outarg
+ && string_add_to_idarray(outarg, columns, ARRAY_SIZE(columns),
+ &ncolumns, column_name_to_id) < 0)
+ return EXIT_FAILURE;
+
+ init_output(&ctl);
+
while (optind < argc) {
- wp0 = read_offsets(NULL, argv[optind++]);
- if (wp0)
- print_all(wp0, mode);
- free_wipe(wp0);
+ struct wipe_desc *wp;
+
+ ctl.devname = argv[optind++];
+ wp = read_offsets(&ctl);
+ if (wp)
+ add_to_output(&ctl, wp);
+ free_wipe(wp);
}
+ finalize_output(&ctl);
} else {
/*
* Erase
*/
+ ctl.ndevs = argc - optind;
+
while (optind < argc) {
- wp = clone_offset(wp0);
- wp = do_wipe(wp, argv[optind++], flags);
- free_wipe(wp);
+ ctl.devname = argv[optind++];
+ do_wipe(&ctl);
+ ctl.ndevs--;
}
- }
+#ifdef BLKRRPART
+ /* Re-read partition tables on whole-disk devices. This is
+ * postponed until all is done to avoid conflicts.
+ */
+ for (size_t i = 0; i < ctl.nrereads; i++) {
+ char *devname = ctl.reread[i];
+ int fd = open(devname, O_RDONLY);
+
+ if (fd >= 0) {
+ rereadpt(fd, devname);
+ close(fd);
+ }
+ }
+ free(ctl.reread);
+#endif
+ }
return EXIT_SUCCESS;
}