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