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