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)) {
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
);
272 static struct wipe_desc
*
273 read_offsets(struct wipe_desc
*wp
, const char *devname
)
275 blkid_probe pr
= new_probe(devname
, 0);
280 while (blkid_do_probe(pr
) == 0) {
281 wp
= get_desc_for_probe(wp
, pr
);
286 blkid_free_probe(pr
);
291 free_wipe(struct wipe_desc
*wp
)
294 struct wipe_desc
*next
= wp
->next
;
307 static void do_wipe_real(blkid_probe pr
, const char *devname
,
308 struct wipe_desc
*w
, int flags
)
312 if (blkid_do_wipe(pr
, (flags
& WP_FL_NOACT
) != 0))
313 warn(_("%s: failed to erase %s magic string at offset 0x%08jx"),
314 devname
, w
->type
, w
->offset
);
316 if (flags
& WP_FL_QUIET
)
319 printf(P_("%s: %zd byte was erased at offset 0x%08jx (%s): ",
320 "%s: %zd bytes were erased at offset 0x%08jx (%s): ",
322 devname
, w
->len
, w
->offset
, w
->type
);
324 for (i
= 0; i
< w
->len
; i
++) {
325 printf("%02x", w
->magic
[i
]);
332 static void do_backup(struct wipe_desc
*wp
, const char *base
)
337 xasprintf(&fname
, "%s0x%08jx.bak", base
, wp
->offset
);
339 fd
= open(fname
, O_CREAT
| O_WRONLY
, S_IRUSR
| S_IWUSR
);
342 if (write_all(fd
, wp
->magic
, wp
->len
) != 0)
348 err(EXIT_FAILURE
, _("%s: failed to create a signature backup"), fname
);
351 static void rereadpt(int fd
, const char *devname
)
356 if (fstat(fd
, &st
) || !S_ISBLK(st
.st_mode
))
360 ioctl(fd
, BLKRRPART
);
361 printf(_("%s: calling ioctl to re-read partition table: %m\n"), devname
);
365 static struct wipe_desc
*
366 do_wipe(struct wipe_desc
*wp
, const char *devname
, int flags
)
368 int mode
= O_RDWR
, reread
= 0, need_force
= 0;
370 struct wipe_desc
*w
, *wp0
;
371 int zap
= (flags
& WP_FL_ALL
) ? 1 : wp
->zap
;
374 if (!(flags
& WP_FL_FORCE
))
376 pr
= new_probe(devname
, mode
);
380 if (zap
&& (flags
& WP_FL_BACKUP
)) {
381 const char *home
= getenv ("HOME");
383 errx(EXIT_FAILURE
, _("failed to create a signature backup, $HOME undefined"));
384 xasprintf (&backup
, "%s/wipefs-%s-", home
, basename(devname
));
387 wp0
= clone_offset(wp
);
389 while (blkid_do_probe(pr
) == 0) {
390 wp
= get_desc_for_probe(wp
, pr
);
394 /* Check if offset is in provided list */
396 while(w
&& w
->offset
!= wp
->offset
)
401 /* Mark done if found in provided list */
403 w
->on_disk
= wp
->on_disk
;
408 if (!(flags
& WP_FL_FORCE
)
410 && !blkid_probe_is_wholedisk(pr
)) {
411 warnx(_("%s: ignoring nested \"%s\" partition table "
412 "on non-whole disk device"), devname
, wp
->type
);
419 do_backup(wp
, backup
);
420 do_wipe_real(pr
, devname
, wp
, flags
);
421 if (wp
->is_parttable
)
426 for (w
= wp0
; w
!= NULL
; w
= w
->next
) {
427 if (!w
->on_disk
&& !(flags
& WP_FL_QUIET
))
428 warnx(_("%s: offset 0x%jx not found"), devname
, w
->offset
);
432 warnx(_("Use the --force option to force erase."));
434 fsync(blkid_probe_get_fd(pr
));
436 if (reread
&& (mode
& O_EXCL
))
437 rereadpt(blkid_probe_get_fd(pr
), devname
);
439 close(blkid_probe_get_fd(pr
));
440 blkid_free_probe(pr
);
448 static void __attribute__((__noreturn__
))
451 fputs(_("\nUsage:\n"), out
);
453 _(" %s [options] <device>\n"), program_invocation_short_name
);
455 fputs(_("\nOptions:\n"), out
);
456 fputs(_(" -a, --all wipe all magic strings (BE CAREFUL!)\n"
457 " -b, --backup create a signature backup in $HOME\n"
458 " -f, --force force erasure\n"
459 " -h, --help show this help text\n"
460 " -n, --no-act do everything except the actual write() call\n"
461 " -o, --offset <num> offset to erase, in bytes\n"
462 " -p, --parsable print out in parsable instead of printable format\n"
463 " -q, --quiet suppress output messages\n"
464 " -t, --types <list> limit the set of filesystem, RAIDs or partition tables\n"
465 " -V, --version output version information and exit\n"), out
);
467 fprintf(out
, _("\nFor more information see wipefs(8).\n"));
469 exit(out
== stderr
? EXIT_FAILURE
: EXIT_SUCCESS
);
474 main(int argc
, char **argv
)
476 struct wipe_desc
*wp0
= NULL
, *wp
;
477 int c
, has_offset
= 0, flags
= 0;
478 int mode
= WP_MODE_PRETTY
;
480 static const struct option longopts
[] = {
481 { "all", 0, 0, 'a' },
482 { "backup", 0, 0, 'b' },
483 { "force", 0, 0, 'f' },
484 { "help", 0, 0, 'h' },
485 { "no-act", 0, 0, 'n' },
486 { "offset", 1, 0, 'o' },
487 { "parsable", 0, 0, 'p' },
488 { "quiet", 0, 0, 'q' },
489 { "types", 1, 0, 't' },
490 { "version", 0, 0, 'V' },
494 static const ul_excl_t excl
[] = { /* rows and cols in in ASCII order */
498 int excl_st
[ARRAY_SIZE(excl
)] = UL_EXCL_STATUS_INIT
;
500 setlocale(LC_ALL
, "");
501 bindtextdomain(PACKAGE
, LOCALEDIR
);
503 atexit(close_stdout
);
505 while ((c
= getopt_long(argc
, argv
, "afhno:pqt:V", longopts
, NULL
)) != -1) {
507 err_exclusive_options(c
, longopts
, excl
, excl_st
);
514 flags
|= WP_FL_BACKUP
;
517 flags
|= WP_FL_FORCE
;
523 flags
|= WP_FL_NOACT
;
526 wp0
= add_offset(wp0
, strtosize_or_err(optarg
,
527 _("invalid offset argument")), 1);
531 mode
= WP_MODE_PARSABLE
;
534 flags
|= WP_FL_QUIET
;
537 type_pattern
= optarg
;
540 printf(UTIL_LINUX_VERSION
);
551 if ((flags
& WP_FL_BACKUP
) && !((flags
& WP_FL_ALL
) || has_offset
))
552 warnx(_("The --backup option is meaningless in this context"));
554 if (!(flags
& WP_FL_ALL
) && !has_offset
) {
558 while (optind
< argc
) {
559 wp0
= read_offsets(NULL
, argv
[optind
++]);
561 print_all(wp0
, mode
);
568 while (optind
< argc
) {
569 wp
= clone_offset(wp0
);
570 wp
= do_wipe(wp
, argv
[optind
++], flags
);