From c49057d261a63235192fadc3d3b782c5c3a2acbf Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Mon, 5 Oct 2009 13:14:07 +0200 Subject: [PATCH] wipefs: new command # ./wipefs /dev/sda4 offset type ---------------------------------------------------------------- 0xff6 swap [other] UUID: da6c54ea-77d9-470a-82f1-e793fd5d9131 0x36 vfat [filesystem] UUID: 497F-3013 # ./wipefs --offset 0x36 /dev/sda4 8 bytes [46 41 54 31 32 20 20 20] erased at offset 0x36 (vfat) Signed-off-by: Karel Zak --- misc-utils/.gitignore | 1 + misc-utils/Makefile.am | 6 +- misc-utils/blkid.8 | 1 + misc-utils/wipefs.8 | 45 +++++ misc-utils/wipefs.c | 386 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 437 insertions(+), 2 deletions(-) create mode 100644 misc-utils/wipefs.8 create mode 100644 misc-utils/wipefs.c diff --git a/misc-utils/.gitignore b/misc-utils/.gitignore index 2242b9201..5d34a50db 100644 --- a/misc-utils/.gitignore +++ b/misc-utils/.gitignore @@ -16,3 +16,4 @@ uuidgen uuidd findfs blkid +wipefs diff --git a/misc-utils/Makefile.am b/misc-utils/Makefile.am index a4f2f44ea..6cd9cf7bb 100644 --- a/misc-utils/Makefile.am +++ b/misc-utils/Makefile.am @@ -33,12 +33,14 @@ endif endif if BUILD_LIBBLKID -sbin_PROGRAMS += blkid findfs -dist_man_MANS += blkid.8 findfs.8 +sbin_PROGRAMS += blkid findfs wipefs +dist_man_MANS += blkid.8 findfs.8 wipefs.8 blkid_LDADD = $(ul_libblkid_la) blkid_CFLAGS = -I$(ul_libblkid_srcdir) findfs_LDADD = $(ul_libblkid_la) findfs_CFLAGS = -I$(ul_libblkid_srcdir) +wipefs_LDADD = $(ul_libblkid_la) +wipefs_CFLAGS = -I$(ul_libblkid_srcdir) if HAVE_STATIC_BLKID sbin_PROGRAMS += blkid.static blkid_static_SOURCES = $(blkid_SOURCES) diff --git a/misc-utils/blkid.8 b/misc-utils/blkid.8 index 801fbdd3b..9fc83937a 100644 --- a/misc-utils/blkid.8 +++ b/misc-utils/blkid.8 @@ -212,3 +212,4 @@ ftp://ftp.kernel.org/pub/linux/utils/util-linux-ng/. .SH "SEE ALSO" .BR libblkid (3) .BR findfs (8) +.BR wipefs (8) diff --git a/misc-utils/wipefs.8 b/misc-utils/wipefs.8 new file mode 100644 index 000000000..3217c101a --- /dev/null +++ b/misc-utils/wipefs.8 @@ -0,0 +1,45 @@ +.\" -*- nroff -*- +.\" Copyright 2009 by Karel Zak. All Rights Reserved. +.\" This file may be copied under the terms of the GNU Public License. +.\" +.TH WIPEFS 8 "October 2009" "Linux" "MAINTENANCE COMMANDS" +.SH NAME +wipefs \- wipe a filesystem signature from a device +.SH SYNOPSIS +.B wipefs +.RB [ \-ahnp ] +.RB [ \-o +.IR offset ] +.I device +.SH DESCRIPTION +.B wipefs +allows to erase filesystem or raid signatures (magic strings) from the +.I device +to make the device invisible for libblkid. +.B wipefs +does not erase the whole filesystem or any other data from the device. +When used without options -a or -o, it lists all visible filesystems and offsets +of their signatures. +.SH OPTIONS +.IP "\fB\-a, \-\-all\fP" +Erase all available signatures. +.IP "\fB\-h, \-\-help\fP" +Print help and exit. +.IP "\fB\-n, \-\-no\-act\fP" +Causes everything to be done except for the write() call. +.IP "\fB\-o, \-\-offset\fP \fIoffset\fP +Specifies location (in bytes) of the signature which should be erased from the +device. The offset number may include a "0x" prefix, and then the number will be +read as a hex value. It is possible to specify multiple -o options. +.IP "\fB\-p, \-\-parsable\fP" +Print out in parsable instead of printable format. Encode all potentially unsafe +characters of a string to the corresponding hex value prefixed by '\\x'. +.SH AUTHOR +Karel Zak . +.SH AVAILABILITY +The wipefs command is part of the util-linux-ng package and is available from +ftp://ftp.kernel.org/pub/linux/utils/util-linux-ng/. +.SH SEE ALSO +.BR blkid (8) +.BR findfs (8) + diff --git a/misc-utils/wipefs.c b/misc-utils/wipefs.c new file mode 100644 index 000000000..b34ecfaef --- /dev/null +++ b/misc-utils/wipefs.c @@ -0,0 +1,386 @@ +/* + * wipefs - utility to wipe filesystems of partition tables from device + * + * Copyright (C) 2009 Red Hat, Inc. All rights reserved. + * Written by Karel Zak + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "nls.h" + +struct wipe_desc { + loff_t offset; /* magic string offset */ + size_t len; /* length of magic string */ + unsigned char *magic; /* magic string */ + + int zap; /* zap this offset? */ + char *usage; /* raid, filesystem, ... */ + char *type; /* FS type */ + char *label; /* FS label */ + char *uuid; /* FS uuid */ + + struct wipe_desc *next; +}; + +#define WP_MODE_PRETTY 0 /* default */ +#define WP_MODE_PARSABLE 1 + +static void +print_pretty(struct wipe_desc *wp, int line) +{ + if (!line) { + printf("offset type\n"); + printf("----------------------------------------------------------------\n"); + } + + printf("0x%-17jx %s [%s]", wp->offset, wp->type, wp->usage); + + 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 void +print_parsable(struct wipe_desc *wp, int line) +{ + char enc[256]; + + if (!line) + printf("# offset,uuid,label,type\n"); + + printf("0x%jx,", wp->offset); + + if (wp->uuid) { + blkid_encode_string(wp->uuid, enc, sizeof(enc)); + printf("%s,", enc); + } else + fputc(',', stdout); + + if (wp->label) { + blkid_encode_string(wp->label, enc, sizeof(enc)); + printf("%s,", enc); + } else + fputc(',', stdout); + + blkid_encode_string(wp->type, enc, sizeof(enc)); + printf("%s\n", enc); +} + +static void +print_all(struct wipe_desc *wp, int mode) +{ + int n = 0; + + while (wp) { + switch (mode) { + case WP_MODE_PRETTY: + print_pretty(wp, n++); + break; + case WP_MODE_PARSABLE: + print_parsable(wp, n++); + break; + } + wp = wp->next; + } +} + +static struct wipe_desc * +add_offset(struct wipe_desc *wp0, loff_t offset, int zap) +{ + struct wipe_desc *wp = wp0; + + while (wp) { + if (wp->offset == offset) + return wp; + wp = wp->next; + } + + wp = calloc(1, sizeof(struct wipe_desc)); + if (!wp) + err(EXIT_FAILURE, _("calloc failed")); + + wp->offset = offset; + wp->next = wp0; + wp->zap = zap; + return wp; +} + +static inline void *xmalloc(size_t sz) +{ + void *x = malloc(sz); + if (!x) + err(EXIT_FAILURE, _("malloc failed")); + return x; +} + +static inline char *xstrdup(const char *s) +{ + char *x = strdup(s); + if (!x) + err(EXIT_FAILURE, _("strdup failed")); + return x; +} + +static struct wipe_desc * +get_offset_from_probe(struct wipe_desc *wp, blkid_probe pr, int zap) +{ + const char *off, *type, *usage, *mag; + size_t len; + + if (blkid_probe_lookup_value(pr, "TYPE", &type, NULL) == 0 && + blkid_probe_lookup_value(pr, "SBMAGIC_OFFSET", &off, NULL) == 0 && + blkid_probe_lookup_value(pr, "SBMAGIC", &mag, &len) == 0 && + blkid_probe_lookup_value(pr, "USAGE", &usage, NULL) == 0) { + + loff_t offset = strtoll(off, NULL, 10); + const char *p; + + wp = add_offset(wp, offset, zap); + if (!wp) + return NULL; + + wp->usage = xstrdup(usage); + wp->type = xstrdup(type); + + wp->magic = xmalloc(wp->len); + memcpy(wp->magic, mag, len); + wp->len = len; + + if (blkid_probe_lookup_value(pr, "LABEL", &p, NULL) == 0) + wp->label = xstrdup(p); + + if (blkid_probe_lookup_value(pr, "UUID", &p, NULL) == 0) + wp->uuid = xstrdup(p); + } + + return wp; +} + +static struct wipe_desc * +read_offsets(struct wipe_desc *wp, const char *fname, int zap) +{ + blkid_probe pr; + + if (!fname) + return NULL; + + pr = blkid_new_probe_from_filename(fname); + if (!pr) + errx(EXIT_FAILURE, _("probing initialization failed")); + + blkid_probe_enable_superblocks(pr, 1); + blkid_probe_set_superblocks_flags(pr, BLKID_SUBLKS_MAGIC | + BLKID_SUBLKS_TYPE | BLKID_SUBLKS_USAGE | + BLKID_SUBLKS_LABEL | BLKID_SUBLKS_UUID); + + while (blkid_do_probe(pr) == 0) { + wp = get_offset_from_probe(wp, pr, zap); + if (!wp) + break; + } + + blkid_free_probe(pr); + return wp; +} + +static int +write_all(int fd, const void *buf, size_t count) +{ + while(count) { + ssize_t tmp; + + errno = 0; + tmp = write(fd, buf, count); + if (tmp > 0) { + count -= tmp; + if (count) + buf += tmp; + } else if (errno != EINTR && errno != EAGAIN) + return -1; + } + return 0; +} + +static int +do_wipe_offset(int fd, struct wipe_desc *wp, const char *fname, int noact) +{ + char buf[BUFSIZ]; + int i; + off_t l; + size_t len; + + if (!wp->type) { + warnx(_("can't found a magic string at offset " + "0x%jx - ignore."), wp->offset); + return 0; + } + + l = lseek(fd, wp->offset, SEEK_SET); + if (l == (off_t) -1) + err(EXIT_FAILURE, _("%s: failed to seek to offset 0x%jx"), + fname, wp->offset); + + len = wp->len > sizeof(buf) ? sizeof(buf) : wp->len; + + memset(buf, 0, len); + if (noact == 0 && write_all(fd, buf, len)) + err(EXIT_FAILURE, _("%s: write failed"), fname); + + printf(_("%zd bytes ["), wp->len); + + for (i = 0; i < len; i++) { + printf("%02x", wp->magic[i]); + if (i + 1 < len) + fputc(' ', stdout); + } + + printf(_("] erased at offset 0x%jx (%s)\n"), wp->offset, wp->type); + return 0; +} + +static int +do_wipe(struct wipe_desc *wp, const char *fname, int noact) +{ + int fd; + + fd = open(fname, O_WRONLY); + if (fd < 0) + err(EXIT_FAILURE, _("%s: open failed"), fname); + + while (wp) { + if (wp->zap) + do_wipe_offset(fd, wp, fname, noact); + wp = wp->next; + } + + close(fd); + return 0; +} + +static loff_t +strtoll_offset(const char *str) +{ + char *end = NULL; + loff_t off; + + errno = 0; + off = strtoll(str, &end, 0); + + if ((errno == ERANGE && (off == LLONG_MAX || off == LONG_MIN)) || + (errno != 0 && off == 0)) + err(EXIT_FAILURE, _("invalid offset '%s' value specified"), str); + + if (*end != '\0') + errx(EXIT_FAILURE, _("invalid offset '%s' value specified"), str); + + return off; +} + +static void __attribute__((__noreturn__)) +usage(FILE *out) +{ + fprintf(out, _("Usage: %s [options] \n\nOptions:\n"), + program_invocation_short_name); + + fprintf(out, _( + " -a, --all wipe all magic strings (BE CAREFUL!)\n" + " -h, --help this help\n" + " -n, --no-act everything to be done except for the write() call\n" + " -o, --offset offset to erase, in bytes\n" + " -p, --parsable print out in parsable instead of printable format\n")); + + fprintf(out, _("\nFor more information see wipefs(1).\n")); + + exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS); +} + + +int +main(int argc, char **argv) +{ + struct wipe_desc *wp = NULL; + int c, all = 0, has_offset = 0, noact = 0, mode = 0; + const char *fname; + + struct option longopts[] = { + { "all", 0, 0, 'a' }, + { "help", 0, 0, 'h' }, + { "no-act", 0, 0, 'n' }, + { "offset", 1, 0, 'o' }, + { "parsable", 0, 0, 'p' }, + { NULL, 0, 0, 0 } + }; + + setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); + + while ((c = getopt_long(argc, argv, "ahno:p", longopts, NULL)) != -1) { + switch(c) { + case 'a': + all++; + break; + case 'h': + usage(stdout); + break; + case 'n': + noact++; + break; + case 'o': + wp = add_offset(wp, strtoll_offset(optarg), 1); + has_offset++; + break; + case 'p': + mode = WP_MODE_PARSABLE; + break; + default: + usage(stderr); + break; + } + } + + if (wp && all) + errx(EXIT_FAILURE, _("--offset and --all are mutually exclusive")); + if (optind == argc) + usage(stderr); + + fname = argv[optind++]; + + wp = read_offsets(wp, fname, all); + + if (wp) { + if (has_offset || all) + do_wipe(wp, fname, noact); + else + print_all(wp, mode); + } + return EXIT_SUCCESS; +}