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>
42 #include "closestream.h"
47 loff_t offset
; /* magic string offset */
48 size_t len
; /* length of magic string */
49 unsigned char *magic
; /* magic string */
51 char *usage
; /* raid, filesystem, ... */
52 char *type
; /* FS type */
53 char *label
; /* FS label */
54 char *uuid
; /* FS uuid */
56 struct wipe_desc
*next
;
65 WP_MODE_PRETTY
, /* default */
70 WP_FL_NOACT
= (1 << 1),
72 WP_FL_QUIET
= (1 << 3),
73 WP_FL_BACKUP
= (1 << 4),
74 WP_FL_FORCE
= (1 << 5)
77 static const char *type_pattern
;
80 print_pretty(struct wipe_desc
*wp
, int line
)
83 printf("offset type\n");
84 printf("----------------------------------------------------------------\n");
87 printf("0x%-17jx %s [%s]", (intmax_t)wp
->offset
, wp
->type
, _(wp
->usage
));
89 if (wp
->label
&& *wp
->label
)
90 printf("\n%27s %s", "LABEL:", wp
->label
);
92 printf("\n%27s %s", "UUID: ", wp
->uuid
);
97 print_parsable(struct wipe_desc
*wp
, int line
)
102 printf("# offset,uuid,label,type\n");
104 printf("0x%jx,", (intmax_t)wp
->offset
);
107 blkid_encode_string(wp
->uuid
, enc
, sizeof(enc
));
113 blkid_encode_string(wp
->label
, enc
, sizeof(enc
));
118 blkid_encode_string(wp
->type
, enc
, sizeof(enc
));
123 print_all(struct wipe_desc
*wp
, int mode
)
130 print_pretty(wp
, n
++);
132 case WP_MODE_PARSABLE
:
133 print_parsable(wp
, n
++);
142 static struct wipe_desc
*
143 add_offset(struct wipe_desc
*wp0
, loff_t offset
, int zap
)
145 struct wipe_desc
*wp
= wp0
;
148 if (wp
->offset
== offset
)
153 wp
= xcalloc(1, sizeof(struct wipe_desc
));
156 wp
->zap
= zap
? 1 : 0;
160 static struct wipe_desc
*
161 clone_offset(struct wipe_desc
*wp0
)
163 struct wipe_desc
*wp
= NULL
;
166 wp
= add_offset(wp
, wp0
->offset
, wp0
->zap
);
173 static struct wipe_desc
*
174 get_desc_for_probe(struct wipe_desc
*wp
, blkid_probe pr
)
176 const char *off
, *type
, *mag
, *p
, *usage
= NULL
;
182 if (blkid_probe_lookup_value(pr
, "TYPE", &type
, NULL
) == 0) {
183 rc
= blkid_probe_lookup_value(pr
, "SBMAGIC_OFFSET", &off
, NULL
);
185 rc
= blkid_probe_lookup_value(pr
, "SBMAGIC", &mag
, &len
);
190 } else if (blkid_probe_lookup_value(pr
, "PTTYPE", &type
, NULL
) == 0) {
191 rc
= blkid_probe_lookup_value(pr
, "PTMAGIC_OFFSET", &off
, NULL
);
193 rc
= blkid_probe_lookup_value(pr
, "PTMAGIC", &mag
, &len
);
196 usage
= N_("partition table");
201 if (type_pattern
&& !match_fstype(type
, type_pattern
))
204 offset
= strtoll(off
, NULL
, 10);
206 wp
= add_offset(wp
, offset
, 0);
210 if (usage
|| blkid_probe_lookup_value(pr
, "USAGE", &usage
, NULL
) == 0)
211 wp
->usage
= xstrdup(usage
);
213 wp
->type
= xstrdup(type
);
215 wp
->is_parttable
= ispt
? 1 : 0;
217 wp
->magic
= xmalloc(len
);
218 memcpy(wp
->magic
, mag
, len
);
221 if (blkid_probe_lookup_value(pr
, "LABEL", &p
, NULL
) == 0)
222 wp
->label
= xstrdup(p
);
224 if (blkid_probe_lookup_value(pr
, "UUID", &p
, NULL
) == 0)
225 wp
->uuid
= xstrdup(p
);
231 new_probe(const char *devname
, int mode
)
233 blkid_probe pr
= NULL
;
239 int fd
= open(devname
, mode
);
243 pr
= blkid_new_probe();
244 if (!pr
|| blkid_probe_set_device(pr
, fd
, 0, 0) != 0) {
249 pr
= blkid_new_probe_from_filename(devname
);
254 blkid_probe_enable_superblocks(pr
, 1);
255 blkid_probe_set_superblocks_flags(pr
,
256 BLKID_SUBLKS_MAGIC
| /* return magic string and offset */
257 BLKID_SUBLKS_TYPE
| /* return superblock type */
258 BLKID_SUBLKS_USAGE
| /* return USAGE= */
259 BLKID_SUBLKS_LABEL
| /* return LABEL= */
260 BLKID_SUBLKS_UUID
| /* return UUID= */
261 BLKID_SUBLKS_BADCSUM
); /* accept bad checksums */
263 blkid_probe_enable_partitions(pr
, 1);
264 blkid_probe_set_partitions_flags(pr
, BLKID_PARTS_MAGIC
|
265 BLKID_PARTS_FORCE_GPT
);
268 blkid_free_probe(pr
);
269 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
, (intmax_t)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
, (intmax_t)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
, (intmax_t)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
);
352 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");
382 char *tmp
= xstrdup(devname
);
385 errx(EXIT_FAILURE
, _("failed to create a signature backup, $HOME undefined"));
386 xasprintf (&backup
, "%s/wipefs-%s-", home
, basename(tmp
));
390 wp0
= clone_offset(wp
);
392 while (blkid_do_probe(pr
) == 0) {
393 wp
= get_desc_for_probe(wp
, pr
);
397 /* Check if offset is in provided list */
399 while(w
&& w
->offset
!= wp
->offset
)
404 /* Mark done if found in provided list */
406 w
->on_disk
= wp
->on_disk
;
411 if (!(flags
& WP_FL_FORCE
)
413 && !blkid_probe_is_wholedisk(pr
)) {
414 warnx(_("%s: ignoring nested \"%s\" partition table "
415 "on non-whole disk device"), devname
, wp
->type
);
422 do_backup(wp
, backup
);
423 do_wipe_real(pr
, devname
, wp
, flags
);
424 if (wp
->is_parttable
)
429 for (w
= wp0
; w
!= NULL
; w
= w
->next
) {
430 if (!w
->on_disk
&& !(flags
& WP_FL_QUIET
))
431 warnx(_("%s: offset 0x%jx not found"), devname
, (uintmax_t)w
->offset
);
435 warnx(_("Use the --force option to force erase."));
437 fsync(blkid_probe_get_fd(pr
));
440 if (reread
&& (mode
& O_EXCL
))
441 rereadpt(blkid_probe_get_fd(pr
), devname
);
444 close(blkid_probe_get_fd(pr
));
445 blkid_free_probe(pr
);
453 static void __attribute__((__noreturn__
))
456 fputs(USAGE_HEADER
, out
);
458 _(" %s [options] <device>\n"), program_invocation_short_name
);
460 fputs(USAGE_SEPARATOR
, out
);
461 fputs(_("Wipe signatures from a device.\n"), out
);
463 fputs(USAGE_OPTIONS
, out
);
464 fputs(_(" -a, --all wipe all magic strings (BE CAREFUL!)\n"
465 " -b, --backup create a signature backup in $HOME\n"
466 " -f, --force force erasure\n"
467 " -h, --help show this help text\n"
468 " -n, --no-act do everything except the actual write() call\n"
469 " -o, --offset <num> offset to erase, in bytes\n"
470 " -p, --parsable print out in parsable instead of printable format\n"
471 " -q, --quiet suppress output messages\n"
472 " -t, --types <list> limit the set of filesystem, RAIDs or partition tables\n"
473 " -V, --version output version information and exit\n"), out
);
475 fprintf(out
, USAGE_MAN_TAIL("wipefs(8)"));
477 exit(out
== stderr
? EXIT_FAILURE
: EXIT_SUCCESS
);
482 main(int argc
, char **argv
)
484 struct wipe_desc
*wp0
= NULL
, *wp
;
485 int c
, has_offset
= 0, flags
= 0;
486 int mode
= WP_MODE_PRETTY
;
488 static const struct option longopts
[] = {
489 { "all", 0, 0, 'a' },
490 { "backup", 0, 0, 'b' },
491 { "force", 0, 0, 'f' },
492 { "help", 0, 0, 'h' },
493 { "no-act", 0, 0, 'n' },
494 { "offset", 1, 0, 'o' },
495 { "parsable", 0, 0, 'p' },
496 { "quiet", 0, 0, 'q' },
497 { "types", 1, 0, 't' },
498 { "version", 0, 0, 'V' },
502 static const ul_excl_t excl
[] = { /* rows and cols in in ASCII order */
506 int excl_st
[ARRAY_SIZE(excl
)] = UL_EXCL_STATUS_INIT
;
508 setlocale(LC_ALL
, "");
509 bindtextdomain(PACKAGE
, LOCALEDIR
);
511 atexit(close_stdout
);
513 while ((c
= getopt_long(argc
, argv
, "abfhno:pqt:V", longopts
, NULL
)) != -1) {
515 err_exclusive_options(c
, longopts
, excl
, excl_st
);
522 flags
|= WP_FL_BACKUP
;
525 flags
|= WP_FL_FORCE
;
531 flags
|= WP_FL_NOACT
;
534 wp0
= add_offset(wp0
, strtosize_or_err(optarg
,
535 _("invalid offset argument")), 1);
539 mode
= WP_MODE_PARSABLE
;
542 flags
|= WP_FL_QUIET
;
545 type_pattern
= optarg
;
548 printf(UTIL_LINUX_VERSION
);
551 errtryhelp(EXIT_FAILURE
);
558 if ((flags
& WP_FL_BACKUP
) && !((flags
& WP_FL_ALL
) || has_offset
))
559 warnx(_("The --backup option is meaningless in this context"));
561 if (!(flags
& WP_FL_ALL
) && !has_offset
) {
565 while (optind
< argc
) {
566 wp0
= read_offsets(NULL
, argv
[optind
++]);
568 print_all(wp0
, mode
);
575 while (optind
< argc
) {
576 wp
= clone_offset(wp0
);
577 wp
= do_wipe(wp
, argv
[optind
++], flags
);