]> git.ipfire.org Git - thirdparty/util-linux.git/blob - misc-utils/wipefs.c
libblkid: export info about PT magic strings
[thirdparty/util-linux.git] / misc-utils / wipefs.c
1 /*
2 * wipefs - utility to wipe filesystems from device
3 *
4 * Copyright (C) 2009 Red Hat, Inc. All rights reserved.
5 * Written by Karel Zak <kzak@redhat.com>
6 *
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.
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>
30 #include <string.h>
31 #include <limits.h>
32
33 #include <blkid.h>
34
35 #include "nls.h"
36 #include "xalloc.h"
37 #include "strutils.h"
38 #include "writeall.h"
39 #include "c.h"
40
41 struct 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
52 int on_disk;
53
54 struct wipe_desc *next;
55 };
56
57 #define WP_MODE_PRETTY 0 /* default */
58 #define WP_MODE_PARSABLE 1
59
60 static void
61 print_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
77 static void
78 print_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
103 static void
104 print_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
121 static struct wipe_desc *
122 add_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
142 static struct wipe_desc *
143 get_desc_for_probe(struct wipe_desc *wp, blkid_probe pr)
144 {
145 const char *off, *type, *mag, *p, *usage = NULL;
146 size_t len;
147 loff_t offset;
148 int rc;
149
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;
157
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;
168
169 offset = strtoll(off, NULL, 10);
170
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)
176 wp->usage = xstrdup(usage);
177
178 wp->type = xstrdup(type);
179 wp->on_disk = 1;
180
181 wp->magic = xmalloc(len);
182 memcpy(wp->magic, mag, len);
183 wp->len = len;
184
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);
190
191 return wp;
192 }
193
194 static blkid_probe
195 new_probe(const char *devname, int mode)
196 {
197 blkid_probe pr;
198
199 if (!devname)
200 return NULL;
201
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
213 if (!pr)
214 goto error;
215
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
221 blkid_probe_enable_partitions(pr, 1);
222 blkid_probe_set_partitions_flags(pr, BLKID_PARTS_MAGIC);
223
224 return pr;
225 error:
226 err(EXIT_FAILURE, _("error: %s: probing initialization failed"), devname);
227 return NULL;
228 }
229
230 static struct wipe_desc *
231 read_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
238 while (blkid_do_probe(pr) == 0) {
239 wp = get_desc_for_probe(wp, pr);
240 if (!wp)
241 break;
242 }
243
244 blkid_free_probe(pr);
245 return wp;
246 }
247
248 static struct wipe_desc *
249 do_wipe(struct wipe_desc *wp, const char *devname, int noact, int all)
250 {
251 blkid_probe pr = new_probe(devname, O_RDWR);
252 struct wipe_desc *w;
253
254 if (!pr)
255 return NULL;
256
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 }
284 }
285
286 for (w = wp; w != NULL; w = w->next) {
287 if (!w->on_disk)
288 warnx(_("offset 0x%jx not found"), w->offset);
289 }
290
291 fsync(blkid_probe_get_fd(pr));
292 close(blkid_probe_get_fd(pr));
293 blkid_free_probe(pr);
294
295 return wp;
296 }
297
298 static void
299 free_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
315 static loff_t
316 strtoll_offset(const char *str)
317 {
318 uintmax_t sz;
319
320 if (strtosize(str, &sz))
321 errx(EXIT_FAILURE, _("invalid offset value '%s' specified"), str);
322 return sz;
323 }
324
325
326 static void __attribute__((__noreturn__))
327 usage(FILE *out)
328 {
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);
340
341 fprintf(out, _("\nFor more information see wipefs(8).\n"));
342
343 exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
344 }
345
346
347 int
348 main(int argc, char **argv)
349 {
350 struct wipe_desc *wp = NULL;
351 int c, all = 0, has_offset = 0, noact = 0, mode = 0;
352 const char *devname;
353
354 static const struct option longopts[] = {
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' },
360 { "version", 0, 0, 'V' },
361 { NULL, 0, 0, 0 }
362 };
363
364 setlocale(LC_ALL, "");
365 bindtextdomain(PACKAGE, LOCALEDIR);
366 textdomain(PACKAGE);
367
368 while ((c = getopt_long(argc, argv, "ahno:pV", longopts, NULL)) != -1) {
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;
386 case 'V':
387 printf(_("%s from %s\n"), program_invocation_short_name,
388 PACKAGE_STRING);
389 return EXIT_SUCCESS;
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
401 devname = argv[optind++];
402
403 if (optind != argc)
404 errx(EXIT_FAILURE, _("only one device as argument is currently supported."));
405
406 if (!all && !has_offset) {
407 /*
408 * Print only
409 */
410 wp = read_offsets(wp, devname);
411 if (wp)
412 print_all(wp, mode);
413 } else {
414 /*
415 * Erase
416 */
417 wp = do_wipe(wp, devname, noact, all);
418 }
419
420 free_wipe(wp);
421 return EXIT_SUCCESS;
422 }