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 <kzak@redhat.com>
This commit is contained in:
Karel Zak 2009-10-05 13:14:07 +02:00
parent 6728c64649
commit c49057d261
5 changed files with 437 additions and 2 deletions

View File

@ -16,3 +16,4 @@ uuidgen
uuidd
findfs
blkid
wipefs

View File

@ -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)

View File

@ -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)

45
misc-utils/wipefs.8 Normal file
View File

@ -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 <kzak@redhat.com>.
.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)

386
misc-utils/wipefs.c Normal file
View File

@ -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 <kzak@redhat.com>
*
* 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 <sys/stat.h>
#include <sys/types.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <getopt.h>
#include <err.h>
#include <string.h>
#include <limits.h>
#include <blkid.h>
#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] <filename>\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 <num> 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;
}