2 * wipefs - utility to wipe filesystems from device
4 * Copyright (C) 2009 Red Hat, Inc. All rights reserved.
5 * Written by Karel Zak <kzak@redhat.com>
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.
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.
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.
22 #include <sys/types.h>
41 #include "closestream.h"
46 loff_t offset
; /* magic string offset */
47 size_t len
; /* length of magic string */
48 unsigned char *magic
; /* magic string */
50 char *usage
; /* raid, filesystem, ... */
51 char *type
; /* FS type */
52 char *label
; /* FS label */
53 char *uuid
; /* FS uuid */
55 struct wipe_desc
*next
;
64 WP_MODE_PRETTY
, /* default */
69 WP_FL_NOACT
= (1 << 1),
71 WP_FL_QUIET
= (1 << 3),
72 WP_FL_BACKUP
= (1 << 4),
73 WP_FL_FORCE
= (1 << 5)
76 static const char *type_pattern
;
79 print_pretty(struct wipe_desc
*wp
, int line
)
82 printf("offset type\n");
83 printf("----------------------------------------------------------------\n");
86 printf("0x%-17jx %s [%s]", wp
->offset
, wp
->type
, _(wp
->usage
));
88 if (wp
->label
&& *wp
->label
)
89 printf("\n%27s %s", "LABEL:", wp
->label
);
91 printf("\n%27s %s", "UUID: ", wp
->uuid
);
96 print_parsable(struct wipe_desc
*wp
, int line
)
101 printf("# offset,uuid,label,type\n");
103 printf("0x%jx,", wp
->offset
);
106 blkid_encode_string(wp
->uuid
, enc
, sizeof(enc
));
112 blkid_encode_string(wp
->label
, enc
, sizeof(enc
));
117 blkid_encode_string(wp
->type
, enc
, sizeof(enc
));
122 print_all(struct wipe_desc
*wp
, int mode
)
129 print_pretty(wp
, n
++);
131 case WP_MODE_PARSABLE
:
132 print_parsable(wp
, n
++);
141 static struct wipe_desc
*
142 add_offset(struct wipe_desc
*wp0
, loff_t offset
, int zap
)
144 struct wipe_desc
*wp
= wp0
;
147 if (wp
->offset
== offset
)
152 wp
= xcalloc(1, sizeof(struct wipe_desc
));
155 wp
->zap
= zap
? 1 : 0;
159 static struct wipe_desc
*
160 clone_offset(struct wipe_desc
*wp0
)
162 struct wipe_desc
*wp
= NULL
;
165 wp
= add_offset(wp
, wp0
->offset
, wp0
->zap
);
172 static struct wipe_desc
*
173 get_desc_for_probe(struct wipe_desc
*wp
, blkid_probe pr
)
175 const char *off
, *type
, *mag
, *p
, *usage
= NULL
;
181 if (blkid_probe_lookup_value(pr
, "TYPE", &type
, NULL
) == 0) {
182 rc
= blkid_probe_lookup_value(pr
, "SBMAGIC_OFFSET", &off
, NULL
);
184 rc
= blkid_probe_lookup_value(pr
, "SBMAGIC", &mag
, &len
);
189 } else if (blkid_probe_lookup_value(pr
, "PTTYPE", &type
, NULL
) == 0) {
190 rc
= blkid_probe_lookup_value(pr
, "PTMAGIC_OFFSET", &off
, NULL
);
192 rc
= blkid_probe_lookup_value(pr
, "PTMAGIC", &mag
, &len
);
195 usage
= N_("partition table");
200 if (type_pattern
&& !match_fstype(type
, type_pattern
))
203 offset
= strtoll(off
, NULL
, 10);
205 wp
= add_offset(wp
, offset
, 0);
209 if (usage
|| blkid_probe_lookup_value(pr
, "USAGE", &usage
, NULL
) == 0)
210 wp
->usage
= xstrdup(usage
);
212 wp
->type
= xstrdup(type
);
214 wp
->is_parttable
= ispt
? 1 : 0;
216 wp
->magic
= xmalloc(len
);
217 memcpy(wp
->magic
, mag
, len
);
220 if (blkid_probe_lookup_value(pr
, "LABEL", &p
, NULL
) == 0)
221 wp
->label
= xstrdup(p
);
223 if (blkid_probe_lookup_value(pr
, "UUID", &p
, NULL
) == 0)
224 wp
->uuid
= xstrdup(p
);
230 new_probe(const char *devname
, int mode
)
232 blkid_probe pr
= NULL
;
238 int fd
= open(devname
, mode
);
242 pr
= blkid_new_probe();
243 if (!pr
|| blkid_probe_set_device(pr
, fd
, 0, 0) != 0) {
248 pr
= blkid_new_probe_from_filename(devname
);
253 blkid_probe_enable_superblocks(pr
, 1);
254 blkid_probe_set_superblocks_flags(pr
,
255 BLKID_SUBLKS_MAGIC
| /* return magic string and offset */
256 BLKID_SUBLKS_TYPE
| /* return superblock type */
257 BLKID_SUBLKS_USAGE
| /* return USAGE= */
258 BLKID_SUBLKS_LABEL
| /* return LABEL= */
259 BLKID_SUBLKS_UUID
| /* return UUID= */
260 BLKID_SUBLKS_BADCSUM
); /* accept bad checksums */
262 blkid_probe_enable_partitions(pr
, 1);
263 blkid_probe_set_partitions_flags(pr
, BLKID_PARTS_MAGIC
);
267 blkid_free_probe(pr
);
268 err(EXIT_FAILURE
, _("error: %s: probing initialization failed"), devname
);
271 static struct wipe_desc
*
272 read_offsets(struct wipe_desc
*wp
, const char *devname
)
274 blkid_probe pr
= new_probe(devname
, 0);
279 while (blkid_do_probe(pr
) == 0) {
280 wp
= get_desc_for_probe(wp
, pr
);
285 blkid_free_probe(pr
);
290 free_wipe(struct wipe_desc
*wp
)
293 struct wipe_desc
*next
= wp
->next
;
306 static void do_wipe_real(blkid_probe pr
, const char *devname
,
307 struct wipe_desc
*w
, int flags
)
311 if (blkid_do_wipe(pr
, (flags
& WP_FL_NOACT
) != 0))
312 warn(_("%s: failed to erase %s magic string at offset 0x%08jx"),
313 devname
, w
->type
, w
->offset
);
315 if (flags
& WP_FL_QUIET
)
318 printf(P_("%s: %zd byte was erased at offset 0x%08jx (%s): ",
319 "%s: %zd bytes were erased at offset 0x%08jx (%s): ",
321 devname
, w
->len
, w
->offset
, w
->type
);
323 for (i
= 0; i
< w
->len
; i
++) {
324 printf("%02x", w
->magic
[i
]);
331 static void do_backup(struct wipe_desc
*wp
, const char *base
)
336 xasprintf(&fname
, "%s0x%08jx.bak", base
, wp
->offset
);
338 fd
= open(fname
, O_CREAT
| O_WRONLY
, S_IRUSR
| S_IWUSR
);
341 if (write_all(fd
, wp
->magic
, wp
->len
) != 0)
347 err(EXIT_FAILURE
, _("%s: failed to create a signature backup"), fname
);
350 static void rereadpt(int fd
, const char *devname
)
355 if (fstat(fd
, &st
) || !S_ISBLK(st
.st_mode
))
359 ioctl(fd
, BLKRRPART
);
360 printf(_("%s: calling ioctl to re-read partition table: %m\n"), devname
);
364 static struct wipe_desc
*
365 do_wipe(struct wipe_desc
*wp
, const char *devname
, int flags
)
367 int mode
= O_RDWR
, reread
= 0, need_force
= 0;
369 struct wipe_desc
*w
, *wp0
;
370 int zap
= (flags
& WP_FL_ALL
) ? 1 : wp
->zap
;
373 if (!(flags
& WP_FL_FORCE
))
375 pr
= new_probe(devname
, mode
);
379 if (zap
&& (flags
& WP_FL_BACKUP
)) {
380 const char *home
= getenv ("HOME");
382 errx(EXIT_FAILURE
, _("failed to create a signature backup, $HOME undefined"));
383 xasprintf (&backup
, "%s/wipefs-%s-", home
, basename(devname
));
386 wp0
= clone_offset(wp
);
388 while (blkid_do_probe(pr
) == 0) {
389 wp
= get_desc_for_probe(wp
, pr
);
393 /* Check if offset is in provided list */
395 while(w
&& w
->offset
!= wp
->offset
)
400 /* Mark done if found in provided list */
402 w
->on_disk
= wp
->on_disk
;
407 if (!(flags
& WP_FL_FORCE
)
409 && !blkid_probe_is_wholedisk(pr
)) {
410 warnx(_("%s: ignoring nested \"%s\" partition table "
411 "on non-whole disk device"), devname
, wp
->type
);
418 do_backup(wp
, backup
);
419 do_wipe_real(pr
, devname
, wp
, flags
);
420 if (wp
->is_parttable
)
425 for (w
= wp0
; w
!= NULL
; w
= w
->next
) {
426 if (!w
->on_disk
&& !(flags
& WP_FL_QUIET
))
427 warnx(_("%s: offset 0x%jx not found"), devname
, w
->offset
);
431 warnx(_("Use the --force option to force erase."));
433 fsync(blkid_probe_get_fd(pr
));
435 if (reread
&& (mode
& O_EXCL
))
436 rereadpt(blkid_probe_get_fd(pr
), devname
);
438 close(blkid_probe_get_fd(pr
));
439 blkid_free_probe(pr
);
447 static void __attribute__((__noreturn__
))
450 fputs(USAGE_HEADER
, out
);
452 _(" %s [options] <device>\n"), program_invocation_short_name
);
454 fputs(USAGE_SEPARATOR
, out
);
455 fputs(_("Wipe signatures from a device.\n"), out
);
457 fputs(USAGE_OPTIONS
, out
);
458 fputs(_(" -a, --all wipe all magic strings (BE CAREFUL!)\n"
459 " -b, --backup create a signature backup in $HOME\n"
460 " -f, --force force erasure\n"
461 " -h, --help show this help text\n"
462 " -n, --no-act do everything except the actual write() call\n"
463 " -o, --offset <num> offset to erase, in bytes\n"
464 " -p, --parsable print out in parsable instead of printable format\n"
465 " -q, --quiet suppress output messages\n"
466 " -t, --types <list> limit the set of filesystem, RAIDs or partition tables\n"
467 " -V, --version output version information and exit\n"), out
);
469 fprintf(out
, USAGE_MAN_TAIL("wipefs(8)"));
471 exit(out
== stderr
? EXIT_FAILURE
: EXIT_SUCCESS
);
476 main(int argc
, char **argv
)
478 struct wipe_desc
*wp0
= NULL
, *wp
;
479 int c
, has_offset
= 0, flags
= 0;
480 int mode
= WP_MODE_PRETTY
;
482 static const struct option longopts
[] = {
483 { "all", 0, 0, 'a' },
484 { "backup", 0, 0, 'b' },
485 { "force", 0, 0, 'f' },
486 { "help", 0, 0, 'h' },
487 { "no-act", 0, 0, 'n' },
488 { "offset", 1, 0, 'o' },
489 { "parsable", 0, 0, 'p' },
490 { "quiet", 0, 0, 'q' },
491 { "types", 1, 0, 't' },
492 { "version", 0, 0, 'V' },
496 static const ul_excl_t excl
[] = { /* rows and cols in in ASCII order */
500 int excl_st
[ARRAY_SIZE(excl
)] = UL_EXCL_STATUS_INIT
;
502 setlocale(LC_ALL
, "");
503 bindtextdomain(PACKAGE
, LOCALEDIR
);
505 atexit(close_stdout
);
507 while ((c
= getopt_long(argc
, argv
, "abfhno:pqt:V", longopts
, NULL
)) != -1) {
509 err_exclusive_options(c
, longopts
, excl
, excl_st
);
516 flags
|= WP_FL_BACKUP
;
519 flags
|= WP_FL_FORCE
;
525 flags
|= WP_FL_NOACT
;
528 wp0
= add_offset(wp0
, strtosize_or_err(optarg
,
529 _("invalid offset argument")), 1);
533 mode
= WP_MODE_PARSABLE
;
536 flags
|= WP_FL_QUIET
;
539 type_pattern
= optarg
;
542 printf(UTIL_LINUX_VERSION
);
553 if ((flags
& WP_FL_BACKUP
) && !((flags
& WP_FL_ALL
) || has_offset
))
554 warnx(_("The --backup option is meaningless in this context"));
556 if (!(flags
& WP_FL_ALL
) && !has_offset
) {
560 while (optind
< argc
) {
561 wp0
= read_offsets(NULL
, argv
[optind
++]);
563 print_all(wp0
, mode
);
570 while (optind
< argc
) {
571 wp
= clone_offset(wp0
);
572 wp
= do_wipe(wp
, argv
[optind
++], flags
);