]>
Commit | Line | Data |
---|---|---|
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 | * | |
7cebf0bb SK |
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. | |
c49057d2 KZ |
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" |
e12c9866 | 38 | #include "all-io.h" |
f126cd46 | 39 | #include "match.h" |
eb76ca98 | 40 | #include "c.h" |
c05a80ca | 41 | #include "closestream.h" |
58f0252a | 42 | #include "optutils.h" |
c49057d2 KZ |
43 | |
44 | struct wipe_desc { | |
45 | loff_t offset; /* magic string offset */ | |
46 | size_t len; /* length of magic string */ | |
47 | unsigned char *magic; /* magic string */ | |
48 | ||
49 | int zap; /* zap this offset? */ | |
50 | char *usage; /* raid, filesystem, ... */ | |
51 | char *type; /* FS type */ | |
52 | char *label; /* FS label */ | |
53 | char *uuid; /* FS uuid */ | |
54 | ||
6611a3dd KZ |
55 | int on_disk; |
56 | ||
c49057d2 KZ |
57 | struct wipe_desc *next; |
58 | }; | |
59 | ||
4f053737 SK |
60 | enum { |
61 | WP_MODE_PRETTY, /* default */ | |
62 | WP_MODE_PARSABLE | |
63 | }; | |
c49057d2 | 64 | |
f126cd46 KZ |
65 | static const char *type_pattern; |
66 | ||
c49057d2 KZ |
67 | static void |
68 | print_pretty(struct wipe_desc *wp, int line) | |
69 | { | |
70 | if (!line) { | |
71 | printf("offset type\n"); | |
72 | printf("----------------------------------------------------------------\n"); | |
73 | } | |
74 | ||
75 | printf("0x%-17jx %s [%s]", wp->offset, wp->type, wp->usage); | |
76 | ||
77 | if (wp->label && *wp->label) | |
78 | printf("\n%27s %s", "LABEL:", wp->label); | |
79 | if (wp->uuid) | |
80 | printf("\n%27s %s", "UUID: ", wp->uuid); | |
81 | puts("\n"); | |
82 | } | |
83 | ||
84 | static void | |
85 | print_parsable(struct wipe_desc *wp, int line) | |
86 | { | |
87 | char enc[256]; | |
88 | ||
89 | if (!line) | |
90 | printf("# offset,uuid,label,type\n"); | |
91 | ||
92 | printf("0x%jx,", wp->offset); | |
93 | ||
94 | if (wp->uuid) { | |
95 | blkid_encode_string(wp->uuid, enc, sizeof(enc)); | |
96 | printf("%s,", enc); | |
97 | } else | |
98 | fputc(',', stdout); | |
99 | ||
100 | if (wp->label) { | |
101 | blkid_encode_string(wp->label, enc, sizeof(enc)); | |
102 | printf("%s,", enc); | |
103 | } else | |
104 | fputc(',', stdout); | |
105 | ||
106 | blkid_encode_string(wp->type, enc, sizeof(enc)); | |
107 | printf("%s\n", enc); | |
108 | } | |
109 | ||
110 | static void | |
111 | print_all(struct wipe_desc *wp, int mode) | |
112 | { | |
113 | int n = 0; | |
114 | ||
115 | while (wp) { | |
116 | switch (mode) { | |
117 | case WP_MODE_PRETTY: | |
118 | print_pretty(wp, n++); | |
119 | break; | |
120 | case WP_MODE_PARSABLE: | |
121 | print_parsable(wp, n++); | |
122 | break; | |
4f053737 SK |
123 | default: |
124 | abort(); | |
c49057d2 KZ |
125 | } |
126 | wp = wp->next; | |
127 | } | |
128 | } | |
129 | ||
130 | static struct wipe_desc * | |
131 | add_offset(struct wipe_desc *wp0, loff_t offset, int zap) | |
132 | { | |
133 | struct wipe_desc *wp = wp0; | |
134 | ||
135 | while (wp) { | |
136 | if (wp->offset == offset) | |
137 | return wp; | |
138 | wp = wp->next; | |
139 | } | |
140 | ||
a2f5c221 | 141 | wp = xcalloc(1, sizeof(struct wipe_desc)); |
c49057d2 KZ |
142 | wp->offset = offset; |
143 | wp->next = wp0; | |
144 | wp->zap = zap; | |
145 | return wp; | |
146 | } | |
147 | ||
c10695f8 MB |
148 | static struct wipe_desc * |
149 | clone_offset(struct wipe_desc *wp0) | |
150 | { | |
151 | struct wipe_desc *wp = NULL; | |
152 | ||
153 | while(wp0) { | |
154 | wp = add_offset(wp, wp0->offset, wp0->zap); | |
155 | wp0 = wp0->next; | |
156 | } | |
157 | ||
158 | return wp; | |
159 | } | |
160 | ||
c49057d2 | 161 | static struct wipe_desc * |
6611a3dd | 162 | get_desc_for_probe(struct wipe_desc *wp, blkid_probe pr) |
c49057d2 | 163 | { |
44765fdd | 164 | const char *off, *type, *mag, *p, *usage = NULL; |
c49057d2 | 165 | size_t len; |
44765fdd KZ |
166 | loff_t offset; |
167 | int rc; | |
c49057d2 | 168 | |
44765fdd KZ |
169 | /* superblocks */ |
170 | if (blkid_probe_lookup_value(pr, "TYPE", &type, NULL) == 0) { | |
171 | rc = blkid_probe_lookup_value(pr, "SBMAGIC_OFFSET", &off, NULL); | |
172 | if (!rc) | |
173 | rc = blkid_probe_lookup_value(pr, "SBMAGIC", &mag, &len); | |
174 | if (rc) | |
175 | return wp; | |
c49057d2 | 176 | |
44765fdd KZ |
177 | /* partitions */ |
178 | } else if (blkid_probe_lookup_value(pr, "PTTYPE", &type, NULL) == 0) { | |
179 | rc = blkid_probe_lookup_value(pr, "PTMAGIC_OFFSET", &off, NULL); | |
180 | if (!rc) | |
181 | rc = blkid_probe_lookup_value(pr, "PTMAGIC", &mag, &len); | |
182 | if (rc) | |
183 | return wp; | |
184 | usage = "partition table"; | |
185 | } else | |
186 | return wp; | |
c49057d2 | 187 | |
f126cd46 KZ |
188 | if (type_pattern && !match_fstype(type, type_pattern)) |
189 | return wp; | |
190 | ||
44765fdd | 191 | offset = strtoll(off, NULL, 10); |
c49057d2 | 192 | |
44765fdd KZ |
193 | wp = add_offset(wp, offset, 0); |
194 | if (!wp) | |
195 | return NULL; | |
196 | ||
197 | if (usage || blkid_probe_lookup_value(pr, "USAGE", &usage, NULL) == 0) | |
c49057d2 | 198 | wp->usage = xstrdup(usage); |
c49057d2 | 199 | |
44765fdd KZ |
200 | wp->type = xstrdup(type); |
201 | wp->on_disk = 1; | |
c49057d2 | 202 | |
44765fdd KZ |
203 | wp->magic = xmalloc(len); |
204 | memcpy(wp->magic, mag, len); | |
205 | wp->len = len; | |
c49057d2 | 206 | |
44765fdd KZ |
207 | if (blkid_probe_lookup_value(pr, "LABEL", &p, NULL) == 0) |
208 | wp->label = xstrdup(p); | |
209 | ||
210 | if (blkid_probe_lookup_value(pr, "UUID", &p, NULL) == 0) | |
211 | wp->uuid = xstrdup(p); | |
c49057d2 KZ |
212 | |
213 | return wp; | |
214 | } | |
215 | ||
6611a3dd KZ |
216 | static blkid_probe |
217 | new_probe(const char *devname, int mode) | |
c49057d2 KZ |
218 | { |
219 | blkid_probe pr; | |
220 | ||
6611a3dd | 221 | if (!devname) |
c49057d2 KZ |
222 | return NULL; |
223 | ||
6611a3dd KZ |
224 | if (mode) { |
225 | int fd = open(devname, mode); | |
226 | if (fd < 0) | |
227 | goto error; | |
228 | ||
229 | pr = blkid_new_probe(); | |
230 | if (pr && blkid_probe_set_device(pr, fd, 0, 0)) | |
231 | goto error; | |
232 | } else | |
233 | pr = blkid_new_probe_from_filename(devname); | |
234 | ||
c49057d2 | 235 | if (!pr) |
6611a3dd | 236 | goto error; |
269c1a2a | 237 | |
c49057d2 KZ |
238 | blkid_probe_enable_superblocks(pr, 1); |
239 | blkid_probe_set_superblocks_flags(pr, BLKID_SUBLKS_MAGIC | | |
240 | BLKID_SUBLKS_TYPE | BLKID_SUBLKS_USAGE | | |
241 | BLKID_SUBLKS_LABEL | BLKID_SUBLKS_UUID); | |
242 | ||
44765fdd KZ |
243 | blkid_probe_enable_partitions(pr, 1); |
244 | blkid_probe_set_partitions_flags(pr, BLKID_PARTS_MAGIC); | |
245 | ||
6611a3dd KZ |
246 | return pr; |
247 | error: | |
248 | err(EXIT_FAILURE, _("error: %s: probing initialization failed"), devname); | |
249 | return NULL; | |
250 | } | |
251 | ||
252 | static struct wipe_desc * | |
253 | read_offsets(struct wipe_desc *wp, const char *devname) | |
254 | { | |
255 | blkid_probe pr = new_probe(devname, 0); | |
256 | ||
257 | if (!pr) | |
258 | return NULL; | |
259 | ||
c49057d2 | 260 | while (blkid_do_probe(pr) == 0) { |
6611a3dd | 261 | wp = get_desc_for_probe(wp, pr); |
c49057d2 KZ |
262 | if (!wp) |
263 | break; | |
264 | } | |
265 | ||
266 | blkid_free_probe(pr); | |
267 | return wp; | |
268 | } | |
269 | ||
24df2633 MB |
270 | static void |
271 | free_wipe(struct wipe_desc *wp) | |
272 | { | |
273 | while (wp) { | |
274 | struct wipe_desc *next = wp->next; | |
275 | ||
276 | free(wp->usage); | |
277 | free(wp->type); | |
278 | free(wp->magic); | |
279 | free(wp->label); | |
280 | free(wp->uuid); | |
281 | free(wp); | |
282 | ||
283 | wp = next; | |
284 | } | |
285 | } | |
286 | ||
287 | static void do_wipe_real(blkid_probe pr, const char *devname, struct wipe_desc *w, int noact, int quiet) | |
288 | { | |
289 | size_t i; | |
290 | ||
291 | if (blkid_do_wipe(pr, noact)) | |
292 | warn(_("%s: failed to erase %s magic string at offset 0x%08jx"), | |
293 | devname, w->type, w->offset); | |
294 | ||
295 | if (quiet) | |
296 | return; | |
297 | ||
298 | printf(_("%s: %zd bytes were erased at offset 0x%08jx (%s): "), | |
299 | devname, w->len, w->offset, w->type); | |
300 | ||
301 | for (i = 0; i < w->len; i++) { | |
302 | printf("%02x", w->magic[i]); | |
303 | if (i + 1 < w->len) | |
304 | fputc(' ', stdout); | |
305 | } | |
306 | putchar('\n'); | |
307 | } | |
308 | ||
6611a3dd | 309 | static struct wipe_desc * |
2968c3fc | 310 | do_wipe(struct wipe_desc *wp, const char *devname, int noact, int all, int quiet, int force) |
c49057d2 | 311 | { |
2968c3fc RJ |
312 | int flags; |
313 | blkid_probe pr; | |
24df2633 MB |
314 | struct wipe_desc *w, *wp0 = clone_offset(wp); |
315 | int zap = all ? 1 : wp->zap; | |
c49057d2 | 316 | |
2968c3fc RJ |
317 | flags = O_RDWR; |
318 | if (!force) | |
319 | flags |= O_EXCL; | |
320 | pr = new_probe(devname, flags); | |
6611a3dd KZ |
321 | if (!pr) |
322 | return NULL; | |
c49057d2 | 323 | |
6611a3dd | 324 | while (blkid_do_probe(pr) == 0) { |
24df2633 MB |
325 | wp = get_desc_for_probe(wp, pr); |
326 | if (!wp) | |
6611a3dd | 327 | break; |
24df2633 MB |
328 | |
329 | /* Check if offset is in provided list */ | |
330 | w = wp0; | |
331 | while(w && w->offset != wp->offset) | |
332 | w = w->next; | |
333 | if (wp0 && !w) | |
6611a3dd | 334 | continue; |
24df2633 MB |
335 | |
336 | /* Mark done if found in provided list */ | |
337 | if (w) | |
338 | w->on_disk = wp->on_disk; | |
339 | ||
340 | if (!wp->on_disk) | |
6611a3dd KZ |
341 | continue; |
342 | ||
24df2633 MB |
343 | if (zap) |
344 | do_wipe_real(pr, devname, wp, noact, quiet); | |
c49057d2 KZ |
345 | } |
346 | ||
24df2633 | 347 | for (w = wp0; w != NULL; w = w->next) { |
0fd93af6 | 348 | if (!w->on_disk && !quiet) |
c10695f8 | 349 | warnx(_("%s: offset 0x%jx not found"), devname, w->offset); |
c49057d2 KZ |
350 | } |
351 | ||
6611a3dd KZ |
352 | fsync(blkid_probe_get_fd(pr)); |
353 | close(blkid_probe_get_fd(pr)); | |
354 | blkid_free_probe(pr); | |
24df2633 | 355 | free_wipe(wp0); |
6611a3dd KZ |
356 | |
357 | return wp; | |
c49057d2 KZ |
358 | } |
359 | ||
69cc2ec0 | 360 | |
c49057d2 KZ |
361 | static void __attribute__((__noreturn__)) |
362 | usage(FILE *out) | |
363 | { | |
dcd16b0f KZ |
364 | fputs(_("\nUsage:\n"), out); |
365 | fprintf(out, | |
366 | _(" %s [options] <device>\n"), program_invocation_short_name); | |
367 | ||
368 | fputs(_("\nOptions:\n"), out); | |
369 | fputs(_(" -a, --all wipe all magic strings (BE CAREFUL!)\n" | |
2968c3fc | 370 | " -f, --force force erasure\n" |
dcd16b0f KZ |
371 | " -h, --help show this help text\n" |
372 | " -n, --no-act do everything except the actual write() call\n" | |
373 | " -o, --offset <num> offset to erase, in bytes\n" | |
374 | " -p, --parsable print out in parsable instead of printable format\n" | |
0fd93af6 | 375 | " -q, --quiet suppress output messages\n" |
f126cd46 | 376 | " -t, --types <list> limit the set of filesystem, RAIDs or partition tables\n" |
dcd16b0f | 377 | " -V, --version output version information and exit\n"), out); |
c49057d2 | 378 | |
04c94441 | 379 | fprintf(out, _("\nFor more information see wipefs(8).\n")); |
c49057d2 KZ |
380 | |
381 | exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS); | |
382 | } | |
383 | ||
384 | ||
385 | int | |
386 | main(int argc, char **argv) | |
387 | { | |
c10695f8 | 388 | struct wipe_desc *wp0 = NULL, *wp; |
2968c3fc | 389 | int c, all = 0, force = 0, has_offset = 0, noact = 0, quiet = 0; |
4f053737 | 390 | int mode = WP_MODE_PRETTY; |
c49057d2 | 391 | |
6c7d5ae9 | 392 | static const struct option longopts[] = { |
c49057d2 | 393 | { "all", 0, 0, 'a' }, |
2968c3fc | 394 | { "force", 0, 0, 'f' }, |
c49057d2 KZ |
395 | { "help", 0, 0, 'h' }, |
396 | { "no-act", 0, 0, 'n' }, | |
397 | { "offset", 1, 0, 'o' }, | |
398 | { "parsable", 0, 0, 'p' }, | |
0fd93af6 | 399 | { "quiet", 0, 0, 'q' }, |
f126cd46 | 400 | { "types", 1, 0, 't' }, |
11295cd1 | 401 | { "version", 0, 0, 'V' }, |
c49057d2 KZ |
402 | { NULL, 0, 0, 0 } |
403 | }; | |
404 | ||
abb7b98c KZ |
405 | static const ul_excl_t excl[] = { /* rows and cols in in ASCII order */ |
406 | { 'a','o' }, | |
407 | { 0 } | |
408 | }; | |
409 | int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT; | |
410 | ||
c49057d2 KZ |
411 | setlocale(LC_ALL, ""); |
412 | bindtextdomain(PACKAGE, LOCALEDIR); | |
413 | textdomain(PACKAGE); | |
c05a80ca | 414 | atexit(close_stdout); |
c49057d2 | 415 | |
0fd93af6 | 416 | while ((c = getopt_long(argc, argv, "ahno:pqt:V", longopts, NULL)) != -1) { |
abb7b98c KZ |
417 | |
418 | err_exclusive_options(c, longopts, excl, excl_st); | |
419 | ||
c49057d2 KZ |
420 | switch(c) { |
421 | case 'a': | |
422 | all++; | |
423 | break; | |
2968c3fc RJ |
424 | case 'f': |
425 | force++; | |
426 | break; | |
c49057d2 KZ |
427 | case 'h': |
428 | usage(stdout); | |
429 | break; | |
430 | case 'n': | |
431 | noact++; | |
432 | break; | |
433 | case 'o': | |
99727496 | 434 | wp0 = add_offset(wp0, strtosize_or_err(optarg, |
db41a429 | 435 | _("invalid offset argument")), 1); |
c49057d2 KZ |
436 | has_offset++; |
437 | break; | |
438 | case 'p': | |
439 | mode = WP_MODE_PARSABLE; | |
440 | break; | |
0fd93af6 MB |
441 | case 'q': |
442 | quiet++; | |
443 | break; | |
f126cd46 KZ |
444 | case 't': |
445 | type_pattern = optarg; | |
446 | break; | |
11295cd1 | 447 | case 'V': |
e421313d | 448 | printf(UTIL_LINUX_VERSION); |
09467812 | 449 | return EXIT_SUCCESS; |
c49057d2 KZ |
450 | default: |
451 | usage(stderr); | |
452 | break; | |
453 | } | |
454 | } | |
455 | ||
c49057d2 KZ |
456 | if (optind == argc) |
457 | usage(stderr); | |
458 | ||
6611a3dd KZ |
459 | if (!all && !has_offset) { |
460 | /* | |
461 | * Print only | |
462 | */ | |
c10695f8 MB |
463 | while (optind < argc) { |
464 | wp0 = read_offsets(NULL, argv[optind++]); | |
465 | if (wp0) | |
466 | print_all(wp0, mode); | |
467 | free_wipe(wp0); | |
468 | } | |
6611a3dd KZ |
469 | } else { |
470 | /* | |
471 | * Erase | |
472 | */ | |
c10695f8 MB |
473 | while (optind < argc) { |
474 | wp = clone_offset(wp0); | |
2968c3fc RJ |
475 | wp = do_wipe(wp, argv[optind++], noact, all, quiet, |
476 | force); | |
c10695f8 MB |
477 | free_wipe(wp); |
478 | } | |
c49057d2 | 479 | } |
6611a3dd | 480 | |
c49057d2 KZ |
481 | return EXIT_SUCCESS; |
482 | } |