]> git.ipfire.org Git - thirdparty/util-linux.git/blame - misc-utils/wipefs.c
lib,match: split match_fstype() from libmount
[thirdparty/util-linux.git] / misc-utils / wipefs.c
CommitLineData
c49057d2 1/*
870768ad 2 * wipefs - utility to wipe filesystems from device
c49057d2
KZ
3 *
4 * Copyright (C) 2009 Red Hat, Inc. All rights reserved.
5 * Written by Karel Zak <kzak@redhat.com>
6 *
bfbe2933
KZ
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.
c49057d2
KZ
11 *
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.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software Foundation,
19 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21#include <sys/stat.h>
22#include <sys/types.h>
23#include <ctype.h>
24#include <errno.h>
25#include <fcntl.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <unistd.h>
29#include <getopt.h>
c49057d2
KZ
30#include <string.h>
31#include <limits.h>
32
33#include <blkid.h>
34
35#include "nls.h"
87f3feac 36#include "xalloc.h"
8abcf290 37#include "strutils.h"
0239ac01 38#include "writeall.h"
eb76ca98 39#include "c.h"
c49057d2
KZ
40
41struct wipe_desc {
42 loff_t offset; /* magic string offset */
43 size_t len; /* length of magic string */
44 unsigned char *magic; /* magic string */
45
46 int zap; /* zap this offset? */
47 char *usage; /* raid, filesystem, ... */
48 char *type; /* FS type */
49 char *label; /* FS label */
50 char *uuid; /* FS uuid */
51
6611a3dd
KZ
52 int on_disk;
53
c49057d2
KZ
54 struct wipe_desc *next;
55};
56
57#define WP_MODE_PRETTY 0 /* default */
58#define WP_MODE_PARSABLE 1
59
60static void
61print_pretty(struct wipe_desc *wp, int line)
62{
63 if (!line) {
64 printf("offset type\n");
65 printf("----------------------------------------------------------------\n");
66 }
67
68 printf("0x%-17jx %s [%s]", wp->offset, wp->type, wp->usage);
69
70 if (wp->label && *wp->label)
71 printf("\n%27s %s", "LABEL:", wp->label);
72 if (wp->uuid)
73 printf("\n%27s %s", "UUID: ", wp->uuid);
74 puts("\n");
75}
76
77static void
78print_parsable(struct wipe_desc *wp, int line)
79{
80 char enc[256];
81
82 if (!line)
83 printf("# offset,uuid,label,type\n");
84
85 printf("0x%jx,", wp->offset);
86
87 if (wp->uuid) {
88 blkid_encode_string(wp->uuid, enc, sizeof(enc));
89 printf("%s,", enc);
90 } else
91 fputc(',', stdout);
92
93 if (wp->label) {
94 blkid_encode_string(wp->label, enc, sizeof(enc));
95 printf("%s,", enc);
96 } else
97 fputc(',', stdout);
98
99 blkid_encode_string(wp->type, enc, sizeof(enc));
100 printf("%s\n", enc);
101}
102
103static void
104print_all(struct wipe_desc *wp, int mode)
105{
106 int n = 0;
107
108 while (wp) {
109 switch (mode) {
110 case WP_MODE_PRETTY:
111 print_pretty(wp, n++);
112 break;
113 case WP_MODE_PARSABLE:
114 print_parsable(wp, n++);
115 break;
116 }
117 wp = wp->next;
118 }
119}
120
121static struct wipe_desc *
122add_offset(struct wipe_desc *wp0, loff_t offset, int zap)
123{
124 struct wipe_desc *wp = wp0;
125
126 while (wp) {
127 if (wp->offset == offset)
128 return wp;
129 wp = wp->next;
130 }
131
132 wp = calloc(1, sizeof(struct wipe_desc));
133 if (!wp)
134 err(EXIT_FAILURE, _("calloc failed"));
135
136 wp->offset = offset;
137 wp->next = wp0;
138 wp->zap = zap;
139 return wp;
140}
141
c49057d2 142static struct wipe_desc *
6611a3dd 143get_desc_for_probe(struct wipe_desc *wp, blkid_probe pr)
c49057d2 144{
44765fdd 145 const char *off, *type, *mag, *p, *usage = NULL;
c49057d2 146 size_t len;
44765fdd
KZ
147 loff_t offset;
148 int rc;
c49057d2 149
44765fdd
KZ
150 /* superblocks */
151 if (blkid_probe_lookup_value(pr, "TYPE", &type, NULL) == 0) {
152 rc = blkid_probe_lookup_value(pr, "SBMAGIC_OFFSET", &off, NULL);
153 if (!rc)
154 rc = blkid_probe_lookup_value(pr, "SBMAGIC", &mag, &len);
155 if (rc)
156 return wp;
c49057d2 157
44765fdd
KZ
158 /* partitions */
159 } else if (blkid_probe_lookup_value(pr, "PTTYPE", &type, NULL) == 0) {
160 rc = blkid_probe_lookup_value(pr, "PTMAGIC_OFFSET", &off, NULL);
161 if (!rc)
162 rc = blkid_probe_lookup_value(pr, "PTMAGIC", &mag, &len);
163 if (rc)
164 return wp;
165 usage = "partition table";
166 } else
167 return wp;
c49057d2 168
44765fdd 169 offset = strtoll(off, NULL, 10);
c49057d2 170
44765fdd
KZ
171 wp = add_offset(wp, offset, 0);
172 if (!wp)
173 return NULL;
174
175 if (usage || blkid_probe_lookup_value(pr, "USAGE", &usage, NULL) == 0)
c49057d2 176 wp->usage = xstrdup(usage);
c49057d2 177
44765fdd
KZ
178 wp->type = xstrdup(type);
179 wp->on_disk = 1;
c49057d2 180
44765fdd
KZ
181 wp->magic = xmalloc(len);
182 memcpy(wp->magic, mag, len);
183 wp->len = len;
c49057d2 184
44765fdd
KZ
185 if (blkid_probe_lookup_value(pr, "LABEL", &p, NULL) == 0)
186 wp->label = xstrdup(p);
187
188 if (blkid_probe_lookup_value(pr, "UUID", &p, NULL) == 0)
189 wp->uuid = xstrdup(p);
c49057d2
KZ
190
191 return wp;
192}
193
6611a3dd
KZ
194static blkid_probe
195new_probe(const char *devname, int mode)
c49057d2
KZ
196{
197 blkid_probe pr;
198
6611a3dd 199 if (!devname)
c49057d2
KZ
200 return NULL;
201
6611a3dd
KZ
202 if (mode) {
203 int fd = open(devname, mode);
204 if (fd < 0)
205 goto error;
206
207 pr = blkid_new_probe();
208 if (pr && blkid_probe_set_device(pr, fd, 0, 0))
209 goto error;
210 } else
211 pr = blkid_new_probe_from_filename(devname);
212
c49057d2 213 if (!pr)
6611a3dd 214 goto error;
269c1a2a 215
c49057d2
KZ
216 blkid_probe_enable_superblocks(pr, 1);
217 blkid_probe_set_superblocks_flags(pr, BLKID_SUBLKS_MAGIC |
218 BLKID_SUBLKS_TYPE | BLKID_SUBLKS_USAGE |
219 BLKID_SUBLKS_LABEL | BLKID_SUBLKS_UUID);
220
44765fdd
KZ
221 blkid_probe_enable_partitions(pr, 1);
222 blkid_probe_set_partitions_flags(pr, BLKID_PARTS_MAGIC);
223
6611a3dd
KZ
224 return pr;
225error:
226 err(EXIT_FAILURE, _("error: %s: probing initialization failed"), devname);
227 return NULL;
228}
229
230static struct wipe_desc *
231read_offsets(struct wipe_desc *wp, const char *devname)
232{
233 blkid_probe pr = new_probe(devname, 0);
234
235 if (!pr)
236 return NULL;
237
c49057d2 238 while (blkid_do_probe(pr) == 0) {
6611a3dd 239 wp = get_desc_for_probe(wp, pr);
c49057d2
KZ
240 if (!wp)
241 break;
242 }
243
244 blkid_free_probe(pr);
245 return wp;
246}
247
6611a3dd
KZ
248static struct wipe_desc *
249do_wipe(struct wipe_desc *wp, const char *devname, int noact, int all)
c49057d2 250{
6611a3dd
KZ
251 blkid_probe pr = new_probe(devname, O_RDWR);
252 struct wipe_desc *w;
c49057d2 253
6611a3dd
KZ
254 if (!pr)
255 return NULL;
c49057d2 256
6611a3dd
KZ
257 while (blkid_do_probe(pr) == 0) {
258 w = get_desc_for_probe(wp, pr);
259 if (!w)
260 break;
261 wp = w;
262 if (!wp->on_disk)
263 continue;
264 wp->zap = all ? 1 : wp->zap;
265 if (!wp->zap)
266 continue;
267
268 if (blkid_do_wipe(pr, noact))
269 warn(_("failed to erase %s magic string at offset 0x%08jx"),
270 wp->type, wp->offset);
271 else {
272 size_t i;
273
274 printf(_("%zd bytes were erased at offset 0x%08jx (%s): "),
275 wp->len, wp->offset, wp->type);
276
277 for (i = 0; i < wp->len; i++) {
278 printf("%02x", wp->magic[i]);
279 if (i + 1 < wp->len)
280 fputc(' ', stdout);
281 }
282 putchar('\n');
283 }
c49057d2
KZ
284 }
285
6611a3dd
KZ
286 for (w = wp; w != NULL; w = w->next) {
287 if (!w->on_disk)
288 warnx(_("offset 0x%jx not found"), w->offset);
c49057d2
KZ
289 }
290
6611a3dd
KZ
291 fsync(blkid_probe_get_fd(pr));
292 close(blkid_probe_get_fd(pr));
293 blkid_free_probe(pr);
294
295 return wp;
c49057d2
KZ
296}
297
770af396
KZ
298static void
299free_wipe(struct wipe_desc *wp)
300{
301 while (wp) {
302 struct wipe_desc *next = wp->next;
303
304 free(wp->usage);
305 free(wp->type);
306 free(wp->magic);
307 free(wp->label);
308 free(wp->uuid);
309 free(wp);
310
311 wp = next;
312 }
313}
314
c49057d2
KZ
315static loff_t
316strtoll_offset(const char *str)
317{
69cc2ec0 318 uintmax_t sz;
c49057d2 319
69cc2ec0 320 if (strtosize(str, &sz))
d0bb6987 321 errx(EXIT_FAILURE, _("invalid offset value '%s' specified"), str);
69cc2ec0 322 return sz;
c49057d2
KZ
323}
324
69cc2ec0 325
c49057d2
KZ
326static void __attribute__((__noreturn__))
327usage(FILE *out)
328{
dcd16b0f
KZ
329 fputs(_("\nUsage:\n"), out);
330 fprintf(out,
331 _(" %s [options] <device>\n"), program_invocation_short_name);
332
333 fputs(_("\nOptions:\n"), out);
334 fputs(_(" -a, --all wipe all magic strings (BE CAREFUL!)\n"
335 " -h, --help show this help text\n"
336 " -n, --no-act do everything except the actual write() call\n"
337 " -o, --offset <num> offset to erase, in bytes\n"
338 " -p, --parsable print out in parsable instead of printable format\n"
339 " -V, --version output version information and exit\n"), out);
c49057d2 340
04c94441 341 fprintf(out, _("\nFor more information see wipefs(8).\n"));
c49057d2
KZ
342
343 exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
344}
345
346
347int
348main(int argc, char **argv)
349{
350 struct wipe_desc *wp = NULL;
351 int c, all = 0, has_offset = 0, noact = 0, mode = 0;
6611a3dd 352 const char *devname;
c49057d2 353
6c7d5ae9 354 static const struct option longopts[] = {
c49057d2
KZ
355 { "all", 0, 0, 'a' },
356 { "help", 0, 0, 'h' },
357 { "no-act", 0, 0, 'n' },
358 { "offset", 1, 0, 'o' },
359 { "parsable", 0, 0, 'p' },
11295cd1 360 { "version", 0, 0, 'V' },
c49057d2
KZ
361 { NULL, 0, 0, 0 }
362 };
363
364 setlocale(LC_ALL, "");
365 bindtextdomain(PACKAGE, LOCALEDIR);
366 textdomain(PACKAGE);
367
11295cd1 368 while ((c = getopt_long(argc, argv, "ahno:pV", longopts, NULL)) != -1) {
c49057d2
KZ
369 switch(c) {
370 case 'a':
371 all++;
372 break;
373 case 'h':
374 usage(stdout);
375 break;
376 case 'n':
377 noact++;
378 break;
379 case 'o':
380 wp = add_offset(wp, strtoll_offset(optarg), 1);
381 has_offset++;
382 break;
383 case 'p':
384 mode = WP_MODE_PARSABLE;
385 break;
11295cd1 386 case 'V':
09467812
SK
387 printf(_("%s from %s\n"), program_invocation_short_name,
388 PACKAGE_STRING);
389 return EXIT_SUCCESS;
c49057d2
KZ
390 default:
391 usage(stderr);
392 break;
393 }
394 }
395
396 if (wp && all)
397 errx(EXIT_FAILURE, _("--offset and --all are mutually exclusive"));
398 if (optind == argc)
399 usage(stderr);
400
6611a3dd 401 devname = argv[optind++];
c49057d2 402
6ebe8f63
MB
403 if (optind != argc)
404 errx(EXIT_FAILURE, _("only one device as argument is currently supported."));
405
6611a3dd
KZ
406 if (!all && !has_offset) {
407 /*
408 * Print only
409 */
410 wp = read_offsets(wp, devname);
411 if (wp)
c49057d2 412 print_all(wp, mode);
6611a3dd
KZ
413 } else {
414 /*
415 * Erase
416 */
417 wp = do_wipe(wp, devname, noact, all);
c49057d2 418 }
6611a3dd
KZ
419
420 free_wipe(wp);
c49057d2
KZ
421 return EXIT_SUCCESS;
422}