xref: /freebsd/sys/geom/part/g_part_gpt.c (revision b28624fde638caadd4a89f50c9b7e7da0f98c4d2)
1 /*-
2  * Copyright (c) 2002, 2005, 2006, 2007 Marcel Moolenaar
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29 
30 #include <sys/param.h>
31 #include <sys/bio.h>
32 #include <sys/diskmbr.h>
33 #include <sys/endian.h>
34 #include <sys/gpt.h>
35 #include <sys/kernel.h>
36 #include <sys/kobj.h>
37 #include <sys/limits.h>
38 #include <sys/lock.h>
39 #include <sys/malloc.h>
40 #include <sys/mutex.h>
41 #include <sys/queue.h>
42 #include <sys/sbuf.h>
43 #include <sys/systm.h>
44 #include <sys/uuid.h>
45 #include <geom/geom.h>
46 #include <geom/part/g_part.h>
47 
48 #include "g_part_if.h"
49 
50 CTASSERT(offsetof(struct gpt_hdr, padding) == 92);
51 CTASSERT(sizeof(struct gpt_ent) == 128);
52 
53 #define	EQUUID(a,b)	(memcmp(a, b, sizeof(struct uuid)) == 0)
54 
55 enum gpt_elt {
56 	GPT_ELT_PRIHDR,
57 	GPT_ELT_PRITBL,
58 	GPT_ELT_SECHDR,
59 	GPT_ELT_SECTBL,
60 	GPT_ELT_COUNT
61 };
62 
63 enum gpt_state {
64 	GPT_STATE_UNKNOWN,	/* Not determined. */
65 	GPT_STATE_MISSING,	/* No signature found. */
66 	GPT_STATE_CORRUPT,	/* Checksum mismatch. */
67 	GPT_STATE_INVALID,	/* Nonconformant/invalid. */
68 	GPT_STATE_OK		/* Perfectly fine. */
69 };
70 
71 struct g_part_gpt_table {
72 	struct g_part_table	base;
73 	struct gpt_hdr		hdr;
74 	quad_t			lba[GPT_ELT_COUNT];
75 	enum gpt_state		state[GPT_ELT_COUNT];
76 };
77 
78 struct g_part_gpt_entry {
79 	struct g_part_entry	base;
80 	struct gpt_ent		ent;
81 };
82 
83 static int g_part_gpt_add(struct g_part_table *, struct g_part_entry *,
84     struct g_part_parms *);
85 static int g_part_gpt_create(struct g_part_table *, struct g_part_parms *);
86 static int g_part_gpt_destroy(struct g_part_table *, struct g_part_parms *);
87 static int g_part_gpt_dumpto(struct g_part_table *, struct g_part_entry *);
88 static int g_part_gpt_modify(struct g_part_table *, struct g_part_entry *,
89     struct g_part_parms *);
90 static char *g_part_gpt_name(struct g_part_table *, struct g_part_entry *,
91     char *, size_t);
92 static int g_part_gpt_probe(struct g_part_table *, struct g_consumer *);
93 static int g_part_gpt_read(struct g_part_table *, struct g_consumer *);
94 static const char *g_part_gpt_type(struct g_part_table *, struct g_part_entry *,
95     char *, size_t);
96 static int g_part_gpt_write(struct g_part_table *, struct g_consumer *);
97 
98 static kobj_method_t g_part_gpt_methods[] = {
99 	KOBJMETHOD(g_part_add,		g_part_gpt_add),
100 	KOBJMETHOD(g_part_create,	g_part_gpt_create),
101 	KOBJMETHOD(g_part_destroy,	g_part_gpt_destroy),
102 	KOBJMETHOD(g_part_dumpto,	g_part_gpt_dumpto),
103 	KOBJMETHOD(g_part_modify,	g_part_gpt_modify),
104 	KOBJMETHOD(g_part_name,		g_part_gpt_name),
105 	KOBJMETHOD(g_part_probe,	g_part_gpt_probe),
106 	KOBJMETHOD(g_part_read,		g_part_gpt_read),
107 	KOBJMETHOD(g_part_type,		g_part_gpt_type),
108 	KOBJMETHOD(g_part_write,	g_part_gpt_write),
109 	{ 0, 0 }
110 };
111 
112 static struct g_part_scheme g_part_gpt_scheme = {
113 	"GPT",
114 	g_part_gpt_methods,
115 	sizeof(struct g_part_gpt_table),
116 	.gps_entrysz = sizeof(struct g_part_gpt_entry),
117 	.gps_minent = 128,
118 	.gps_maxent = INT_MAX,
119 };
120 G_PART_SCHEME_DECLARE(g_part_gpt_scheme);
121 
122 static struct uuid gpt_uuid_efi = GPT_ENT_TYPE_EFI;
123 static struct uuid gpt_uuid_freebsd = GPT_ENT_TYPE_FREEBSD;
124 static struct uuid gpt_uuid_freebsd_swap = GPT_ENT_TYPE_FREEBSD_SWAP;
125 static struct uuid gpt_uuid_freebsd_ufs = GPT_ENT_TYPE_FREEBSD_UFS;
126 static struct uuid gpt_uuid_freebsd_vinum = GPT_ENT_TYPE_FREEBSD_VINUM;
127 static struct uuid gpt_uuid_linux_swap = GPT_ENT_TYPE_LINUX_SWAP;
128 static struct uuid gpt_uuid_mbr = GPT_ENT_TYPE_MBR;
129 static struct uuid gpt_uuid_unused = GPT_ENT_TYPE_UNUSED;
130 
131 static void
132 gpt_read_hdr(struct g_part_gpt_table *table, struct g_consumer *cp,
133     enum gpt_elt elt, struct gpt_hdr *hdr)
134 {
135 	struct uuid uuid;
136 	struct g_provider *pp;
137 	char *buf;
138 	quad_t lba, last;
139 	int error;
140 	uint32_t crc, sz;
141 
142 	pp = cp->provider;
143 	last = (pp->mediasize / pp->sectorsize) - 1;
144 	table->lba[elt] = (elt == GPT_ELT_PRIHDR) ? 1 : last;
145 	table->state[elt] = GPT_STATE_MISSING;
146 	buf = g_read_data(cp, table->lba[elt] * pp->sectorsize, pp->sectorsize,
147 	    &error);
148 	if (buf == NULL)
149 		return;
150 	bcopy(buf, hdr, sizeof(*hdr));
151 	if (memcmp(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig)) != 0)
152 		return;
153 
154 	table->state[elt] = GPT_STATE_CORRUPT;
155 	sz = le32toh(hdr->hdr_size);
156 	if (sz < 92 || sz > pp->sectorsize)
157 		return;
158 	crc = le32toh(hdr->hdr_crc_self);
159 	hdr->hdr_crc_self = 0;
160 	if (crc32(hdr, sz) != crc)
161 		return;
162 	hdr->hdr_size = sz;
163 	hdr->hdr_crc_self = crc;
164 
165 	table->state[elt] = GPT_STATE_INVALID;
166 	hdr->hdr_revision = le32toh(hdr->hdr_revision);
167 	if (hdr->hdr_revision < 0x00010000)
168 		return;
169 	hdr->hdr_lba_self = le64toh(hdr->hdr_lba_self);
170 	if (hdr->hdr_lba_self != table->lba[elt])
171 		return;
172 	hdr->hdr_lba_alt = le64toh(hdr->hdr_lba_alt);
173 
174 	/* Check the managed area. */
175 	hdr->hdr_lba_start = le64toh(hdr->hdr_lba_start);
176 	if (hdr->hdr_lba_start < 2 || hdr->hdr_lba_start >= last)
177 		return;
178 	hdr->hdr_lba_end = le64toh(hdr->hdr_lba_end);
179 	if (hdr->hdr_lba_end < hdr->hdr_lba_start || hdr->hdr_lba_end >= last)
180 		return;
181 
182 	/* Check the table location and size of the table. */
183 	hdr->hdr_entries = le32toh(hdr->hdr_entries);
184 	hdr->hdr_entsz = le32toh(hdr->hdr_entsz);
185 	if (hdr->hdr_entries == 0 || hdr->hdr_entsz < 128 ||
186 	    (hdr->hdr_entsz & 7) != 0)
187 		return;
188 	hdr->hdr_lba_table = le64toh(hdr->hdr_lba_table);
189 	if (hdr->hdr_lba_table < 2 || hdr->hdr_lba_table >= last)
190 		return;
191 	if (hdr->hdr_lba_table >= hdr->hdr_lba_start &&
192 	    hdr->hdr_lba_table <= hdr->hdr_lba_end)
193 		return;
194 	lba = hdr->hdr_lba_table +
195 	    (hdr->hdr_entries * hdr->hdr_entsz + pp->sectorsize - 1) /
196 	    pp->sectorsize - 1;
197 	if (lba >= last)
198 		return;
199 	if (lba >= hdr->hdr_lba_start && lba <= hdr->hdr_lba_end)
200 		return;
201 
202 	table->state[elt] = GPT_STATE_OK;
203 	le_uuid_dec(&hdr->hdr_uuid, &uuid);
204 	hdr->hdr_uuid = uuid;
205 	hdr->hdr_crc_table = le32toh(hdr->hdr_crc_table);
206 }
207 
208 static struct gpt_ent *
209 gpt_read_tbl(struct g_part_gpt_table *table, struct g_consumer *cp,
210     enum gpt_elt elt, struct gpt_hdr *hdr)
211 {
212 	struct g_provider *pp;
213 	struct gpt_ent *ent, *tbl;
214 	char *buf, *p;
215 	unsigned int idx, sectors, tblsz;
216 	int error;
217 	uint16_t ch;
218 
219 	pp = cp->provider;
220 	table->lba[elt] = hdr->hdr_lba_table;
221 
222 	table->state[elt] = GPT_STATE_MISSING;
223 	tblsz = hdr->hdr_entries * hdr->hdr_entsz;
224 	sectors = (tblsz + pp->sectorsize - 1) / pp->sectorsize;
225 	buf = g_read_data(cp, table->lba[elt] * pp->sectorsize,
226 	    sectors * pp->sectorsize, &error);
227 	if (buf == NULL)
228 		return (NULL);
229 
230 	table->state[elt] = GPT_STATE_CORRUPT;
231 	if (crc32(buf, tblsz) != hdr->hdr_crc_table) {
232 		g_free(buf);
233 		return (NULL);
234 	}
235 
236 	table->state[elt] = GPT_STATE_OK;
237 	tbl = g_malloc(hdr->hdr_entries * sizeof(struct gpt_ent),
238 	    M_WAITOK | M_ZERO);
239 
240 	for (idx = 0, ent = tbl, p = buf;
241 	     idx < hdr->hdr_entries;
242 	     idx++, ent++, p += hdr->hdr_entsz) {
243 		le_uuid_dec(p, &ent->ent_type);
244 		le_uuid_dec(p + 16, &ent->ent_uuid);
245 		ent->ent_lba_start = le64dec(p + 32);
246 		ent->ent_lba_end = le64dec(p + 40);
247 		ent->ent_attr = le64dec(p + 48);
248 		for (ch = 0; ch < sizeof(ent->ent_name)/2; ch++)
249 			ent->ent_name[ch] = le16dec(p + 56 + ch * 2);
250 	}
251 
252 	g_free(buf);
253 	return (tbl);
254 }
255 
256 static int
257 gpt_matched_hdrs(struct gpt_hdr *pri, struct gpt_hdr *sec)
258 {
259 
260 	if (!EQUUID(&pri->hdr_uuid, &sec->hdr_uuid))
261 		return (0);
262 	return ((pri->hdr_revision == sec->hdr_revision &&
263 	    pri->hdr_size == sec->hdr_size &&
264 	    pri->hdr_lba_start == sec->hdr_lba_start &&
265 	    pri->hdr_lba_end == sec->hdr_lba_end &&
266 	    pri->hdr_entries == sec->hdr_entries &&
267 	    pri->hdr_entsz == sec->hdr_entsz &&
268 	    pri->hdr_crc_table == sec->hdr_crc_table) ? 1 : 0);
269 }
270 
271 static int
272 gpt_parse_type(const char *type, struct uuid *uuid)
273 {
274 	struct uuid tmp;
275 	const char *alias;
276 	int error;
277 
278 	if (type[0] == '!') {
279 		error = parse_uuid(type + 1, &tmp);
280 		if (error)
281 			return (error);
282 		if (EQUUID(&tmp, &gpt_uuid_unused))
283 			return (EINVAL);
284 		*uuid = tmp;
285 		return (0);
286 	}
287 	alias = g_part_alias_name(G_PART_ALIAS_EFI);
288 	if (!strcasecmp(type, alias)) {
289 		*uuid = gpt_uuid_efi;
290 		return (0);
291 	}
292 	alias = g_part_alias_name(G_PART_ALIAS_FREEBSD);
293 	if (!strcasecmp(type, alias)) {
294 		*uuid = gpt_uuid_freebsd;
295 		return (0);
296 	}
297 	alias = g_part_alias_name(G_PART_ALIAS_FREEBSD_SWAP);
298 	if (!strcasecmp(type, alias)) {
299 		*uuid = gpt_uuid_freebsd_swap;
300 		return (0);
301 	}
302 	alias = g_part_alias_name(G_PART_ALIAS_FREEBSD_UFS);
303 	if (!strcasecmp(type, alias)) {
304 		*uuid = gpt_uuid_freebsd_ufs;
305 		return (0);
306 	}
307 	alias = g_part_alias_name(G_PART_ALIAS_FREEBSD_VINUM);
308 	if (!strcasecmp(type, alias)) {
309 		*uuid = gpt_uuid_freebsd_vinum;
310 		return (0);
311 	}
312 	alias = g_part_alias_name(G_PART_ALIAS_MBR);
313 	if (!strcasecmp(type, alias)) {
314 		*uuid = gpt_uuid_mbr;
315 		return (0);
316 	}
317 	return (EINVAL);
318 }
319 
320 static int
321 g_part_gpt_add(struct g_part_table *basetable, struct g_part_entry *baseentry,
322     struct g_part_parms *gpp)
323 {
324 	struct g_part_gpt_entry *entry;
325 	int error;
326 
327 	entry = (struct g_part_gpt_entry *)baseentry;
328 	error = gpt_parse_type(gpp->gpp_type, &entry->ent.ent_type);
329 	if (error)
330 		return (error);
331 	kern_uuidgen(&entry->ent.ent_uuid, 1);
332 	entry->ent.ent_lba_start = baseentry->gpe_start;
333 	entry->ent.ent_lba_end = baseentry->gpe_end;
334 	if (baseentry->gpe_deleted) {
335 		entry->ent.ent_attr = 0;
336 		bzero(entry->ent.ent_name, sizeof(entry->ent.ent_name));
337 	}
338 	/* XXX label */
339 	return (0);
340 }
341 
342 static int
343 g_part_gpt_create(struct g_part_table *basetable, struct g_part_parms *gpp)
344 {
345 	struct g_provider *pp;
346 	struct g_part_gpt_table *table;
347 	quad_t last;
348 	size_t tblsz;
349 
350 	table = (struct g_part_gpt_table *)basetable;
351 	pp = gpp->gpp_provider;
352 	tblsz = (basetable->gpt_entries * sizeof(struct gpt_ent) +
353 	    pp->sectorsize - 1) / pp->sectorsize;
354 	if (pp->sectorsize < 512 ||
355 	    pp->mediasize < (3 + 2 * tblsz + basetable->gpt_entries) *
356 	    pp->sectorsize)
357 		return (ENOSPC);
358 
359 	last = (pp->mediasize / pp->sectorsize) - 1;
360 
361 	table->lba[GPT_ELT_PRIHDR] = 1;
362 	table->lba[GPT_ELT_PRITBL] = 2;
363 	table->lba[GPT_ELT_SECHDR] = last;
364 	table->lba[GPT_ELT_SECTBL] = last - tblsz;
365 
366 	bcopy(GPT_HDR_SIG, table->hdr.hdr_sig, sizeof(table->hdr.hdr_sig));
367 	table->hdr.hdr_revision = GPT_HDR_REVISION;
368 	table->hdr.hdr_size = offsetof(struct gpt_hdr, padding);
369 	table->hdr.hdr_lba_start = 2 + tblsz;
370 	table->hdr.hdr_lba_end = last - tblsz - 1;
371 	kern_uuidgen(&table->hdr.hdr_uuid, 1);
372 	table->hdr.hdr_entries = basetable->gpt_entries;
373 	table->hdr.hdr_entsz = sizeof(struct gpt_ent);
374 
375 	basetable->gpt_first = table->hdr.hdr_lba_start;
376 	basetable->gpt_last = table->hdr.hdr_lba_end;
377 	return (0);
378 }
379 
380 static int
381 g_part_gpt_destroy(struct g_part_table *basetable, struct g_part_parms *gpp)
382 {
383 
384 	/*
385 	 * Wipe the first 2 sectors as well as the last to clear the
386 	 * partitioning.
387 	 */
388 	basetable->gpt_smhead |= 3;
389 	basetable->gpt_smtail |= 1;
390 	return (0);
391 }
392 
393 static int
394 g_part_gpt_dumpto(struct g_part_table *table, struct g_part_entry *baseentry)
395 {
396 	struct g_part_gpt_entry *entry;
397 
398 	entry = (struct g_part_gpt_entry *)baseentry;
399 	return ((EQUUID(&entry->ent.ent_type, &gpt_uuid_freebsd_swap) ||
400 	    EQUUID(&entry->ent.ent_type, &gpt_uuid_linux_swap)) ? 1 : 0);
401 }
402 
403 static int
404 g_part_gpt_modify(struct g_part_table *basetable,
405     struct g_part_entry *baseentry, struct g_part_parms *gpp)
406 {
407 	struct g_part_gpt_entry *entry;
408 	int error;
409 
410 	entry = (struct g_part_gpt_entry *)baseentry;
411 	if (gpp->gpp_parms & G_PART_PARM_TYPE) {
412 		error = gpt_parse_type(gpp->gpp_type, &entry->ent.ent_type);
413 		if (error)
414 			return (error);
415 	}
416 	/* XXX label */
417 	return (0);
418 }
419 
420 static char *
421 g_part_gpt_name(struct g_part_table *table, struct g_part_entry *baseentry,
422     char *buf, size_t bufsz)
423 {
424 	struct g_part_gpt_entry *entry;
425 	char c;
426 
427 	entry = (struct g_part_gpt_entry *)baseentry;
428 	c = (EQUUID(&entry->ent.ent_type, &gpt_uuid_freebsd)) ? 's' : 'p';
429 	snprintf(buf, bufsz, "%c%d", c, baseentry->gpe_index);
430 	return (buf);
431 }
432 
433 static int
434 g_part_gpt_probe(struct g_part_table *table, struct g_consumer *cp)
435 {
436 	struct g_provider *pp;
437 	char *buf;
438 	int error, res;
439 
440 	/* We don't nest, which means that our depth should be 0. */
441 	if (table->gpt_depth != 0)
442 		return (ENXIO);
443 
444 	pp = cp->provider;
445 
446 	/*
447 	 * Sanity-check the provider. Since the first sector on the provider
448 	 * must be a PMBR and a PMBR is 512 bytes large, the sector size
449 	 * must be at least 512 bytes.  Also, since the theoretical minimum
450 	 * number of sectors needed by GPT is 6, any medium that has less
451 	 * than 6 sectors is never going to be able to hold a GPT. The
452 	 * number 6 comes from:
453 	 *	1 sector for the PMBR
454 	 *	2 sectors for the GPT headers (each 1 sector)
455 	 *	2 sectors for the GPT tables (each 1 sector)
456 	 *	1 sector for an actual partition
457 	 * It's better to catch this pathological case early than behaving
458 	 * pathologically later on...
459 	 */
460 	if (pp->sectorsize < 512 || pp->mediasize < 6 * pp->sectorsize)
461 		return (ENOSPC);
462 
463 	/* Check that there's a MBR. */
464 	buf = g_read_data(cp, 0L, pp->sectorsize, &error);
465 	if (buf == NULL)
466 		return (error);
467 	res = le16dec(buf + DOSMAGICOFFSET);
468 	g_free(buf);
469 	if (res != DOSMAGIC)
470 		return (ENXIO);
471 
472 	/* Check that there's a primary header. */
473 	buf = g_read_data(cp, pp->sectorsize, pp->sectorsize, &error);
474 	if (buf == NULL)
475 		return (error);
476 	res = memcmp(buf, GPT_HDR_SIG, 8);
477 	g_free(buf);
478 	if (res == 0)
479 		return (G_PART_PROBE_PRI_HIGH);
480 
481 	/* No primary? Check that there's a secondary. */
482 	buf = g_read_data(cp, pp->mediasize - pp->sectorsize, pp->sectorsize,
483 	    &error);
484 	if (buf == NULL)
485 		return (error);
486 	res = memcmp(buf, GPT_HDR_SIG, 8);
487 	g_free(buf);
488 	return ((res == 0) ? G_PART_PROBE_PRI_HIGH : ENXIO);
489 }
490 
491 static int
492 g_part_gpt_read(struct g_part_table *basetable, struct g_consumer *cp)
493 {
494 	struct gpt_hdr prihdr, sechdr;
495 	struct gpt_ent *tbl, *pritbl, *sectbl;
496 	struct g_provider *pp;
497 	struct g_part_gpt_table *table;
498 	struct g_part_gpt_entry *entry;
499 	int index;
500 
501 	table = (struct g_part_gpt_table *)basetable;
502 	pp = cp->provider;
503 
504 	/* Read the primary header and table. */
505 	gpt_read_hdr(table, cp, GPT_ELT_PRIHDR, &prihdr);
506 	if (table->state[GPT_ELT_PRIHDR] == GPT_STATE_OK) {
507 		pritbl = gpt_read_tbl(table, cp, GPT_ELT_PRITBL, &prihdr);
508 	} else {
509 		table->state[GPT_ELT_PRITBL] = GPT_STATE_MISSING;
510 		pritbl = NULL;
511 	}
512 
513 	/* Read the secondary header and table. */
514 	gpt_read_hdr(table, cp, GPT_ELT_SECHDR, &sechdr);
515 	if (table->state[GPT_ELT_SECHDR] == GPT_STATE_OK) {
516 		sectbl = gpt_read_tbl(table, cp, GPT_ELT_SECTBL, &sechdr);
517 	} else {
518 		table->state[GPT_ELT_SECTBL] = GPT_STATE_MISSING;
519 		sectbl = NULL;
520 	}
521 
522 	/* Fail if we haven't got any good tables at all. */
523 	if (table->state[GPT_ELT_PRITBL] != GPT_STATE_OK &&
524 	    table->state[GPT_ELT_SECTBL] != GPT_STATE_OK) {
525 		printf("GEOM: %s: corrupt or invalid GPT detected.\n",
526 		    pp->name);
527 		printf("GEOM: %s: GPT rejected -- may not be recoverable.\n",
528 		    pp->name);
529 		return (EINVAL);
530 	}
531 
532 	/*
533 	 * If both headers are good but they disagree with each other,
534 	 * then invalidate one. We prefer to keep the primary header,
535 	 * unless the primary table is corrupt.
536 	 */
537 	if (table->state[GPT_ELT_PRIHDR] == GPT_STATE_OK &&
538 	    table->state[GPT_ELT_SECHDR] == GPT_STATE_OK &&
539 	    !gpt_matched_hdrs(&prihdr, &sechdr)) {
540 		if (table->state[GPT_ELT_PRITBL] == GPT_STATE_OK)
541 			table->state[GPT_ELT_SECHDR] = GPT_STATE_INVALID;
542 		else
543 			table->state[GPT_ELT_PRIHDR] = GPT_STATE_INVALID;
544 	}
545 
546 	if (table->state[GPT_ELT_PRIHDR] != GPT_STATE_OK) {
547 		printf("GEOM: %s: the primary GPT table is corrupt or "
548 		    "invalid.\n", pp->name);
549 		printf("GEOM: %s: using the secondary instead -- recovery "
550 		    "strongly advised.\n", pp->name);
551 		table->hdr = sechdr;
552 		tbl = sectbl;
553 		if (pritbl != NULL)
554 			g_free(pritbl);
555 	} else {
556 		if (table->state[GPT_ELT_SECHDR] != GPT_STATE_OK) {
557 			printf("GEOM: %s: the secondary GPT table is corrupt "
558 			    "or invalid.\n", pp->name);
559 			printf("GEOM: %s: using the primary only -- recovery "
560 			    "suggested.\n", pp->name);
561 		}
562 		table->hdr = prihdr;
563 		tbl = pritbl;
564 		if (sectbl != NULL)
565 			g_free(sectbl);
566 	}
567 
568 	basetable->gpt_first = table->hdr.hdr_lba_start;
569 	basetable->gpt_last = table->hdr.hdr_lba_end;
570 	basetable->gpt_entries = table->hdr.hdr_entries;
571 
572 	for (index = basetable->gpt_entries - 1; index >= 0; index--) {
573 		if (EQUUID(&tbl[index].ent_type, &gpt_uuid_unused))
574 			continue;
575 		entry = (struct g_part_gpt_entry *)g_part_new_entry(basetable,
576 		    index+1, tbl[index].ent_lba_start, tbl[index].ent_lba_end);
577 		entry->ent = tbl[index];
578 	}
579 
580 	g_free(tbl);
581 	return (0);
582 }
583 
584 static const char *
585 g_part_gpt_type(struct g_part_table *basetable, struct g_part_entry *baseentry,
586     char *buf, size_t bufsz)
587 {
588 	struct g_part_gpt_entry *entry;
589 	struct uuid *type;
590 
591 	entry = (struct g_part_gpt_entry *)baseentry;
592 	type = &entry->ent.ent_type;
593 	if (EQUUID(type, &gpt_uuid_efi))
594 		return (g_part_alias_name(G_PART_ALIAS_EFI));
595 	if (EQUUID(type, &gpt_uuid_freebsd))
596 		return (g_part_alias_name(G_PART_ALIAS_FREEBSD));
597 	if (EQUUID(type, &gpt_uuid_freebsd_swap))
598 		return (g_part_alias_name(G_PART_ALIAS_FREEBSD_SWAP));
599 	if (EQUUID(type, &gpt_uuid_freebsd_ufs))
600 		return (g_part_alias_name(G_PART_ALIAS_FREEBSD_UFS));
601 	if (EQUUID(type, &gpt_uuid_freebsd_vinum))
602 		return (g_part_alias_name(G_PART_ALIAS_FREEBSD_VINUM));
603 	if (EQUUID(type, &gpt_uuid_mbr))
604 		return (g_part_alias_name(G_PART_ALIAS_MBR));
605 	buf[0] = '!';
606 	snprintf_uuid(buf + 1, bufsz - 1, type);
607 	return (buf);
608 }
609 
610 static int
611 g_part_gpt_write(struct g_part_table *basetable, struct g_consumer *cp)
612 {
613 	unsigned char *buf, *bp;
614 	struct g_provider *pp;
615 	struct g_part_entry *baseentry;
616 	struct g_part_gpt_entry *entry;
617 	struct g_part_gpt_table *table;
618 	size_t tlbsz;
619 	uint32_t crc;
620 	int error, index;
621 
622 	pp = cp->provider;
623 	table = (struct g_part_gpt_table *)basetable;
624 	tlbsz = (table->hdr.hdr_entries * table->hdr.hdr_entsz +
625 	    pp->sectorsize - 1) / pp->sectorsize;
626 
627 	if (basetable->gpt_created) {
628 		buf = g_malloc(pp->sectorsize, M_WAITOK | M_ZERO);
629 		le16enc(buf + DOSMAGICOFFSET, DOSMAGIC);
630 		buf[DOSPARTOFF + 1] = 0xff;		/* shd */
631 		buf[DOSPARTOFF + 2] = 0xff;		/* ssect */
632 		buf[DOSPARTOFF + 3] = 0xff;		/* scyl */
633 		buf[DOSPARTOFF + 4] = 0xee;		/* typ */
634 		buf[DOSPARTOFF + 5] = 0xff;		/* ehd */
635 		buf[DOSPARTOFF + 6] = 0xff;		/* esect */
636 		buf[DOSPARTOFF + 7] = 0xff;		/* ecyl */
637 		le32enc(buf + DOSPARTOFF + 8, 1);	/* start */
638 		le32enc(buf + DOSPARTOFF + 12,
639 		    MIN(pp->mediasize / pp->sectorsize - 1, 0xffffffffLL));
640 		error = g_write_data(cp, 0, buf, pp->sectorsize);
641 		g_free(buf);
642 		if (error)
643 			return (error);
644 	}
645 
646 	/* Allocate space for the header and entries. */
647 	buf = g_malloc((tlbsz + 1) * pp->sectorsize, M_WAITOK | M_ZERO);
648 
649 	memcpy(buf, table->hdr.hdr_sig, sizeof(table->hdr.hdr_sig));
650 	le32enc(buf + 8, table->hdr.hdr_revision);
651 	le32enc(buf + 12, table->hdr.hdr_size);
652 	le64enc(buf + 40, table->hdr.hdr_lba_start);
653 	le64enc(buf + 48, table->hdr.hdr_lba_end);
654 	le_uuid_enc(buf + 56, &table->hdr.hdr_uuid);
655 	le32enc(buf + 80, table->hdr.hdr_entries);
656 	le32enc(buf + 84, table->hdr.hdr_entsz);
657 
658 	LIST_FOREACH(baseentry, &basetable->gpt_entry, gpe_entry) {
659 		if (baseentry->gpe_deleted)
660 			continue;
661 		entry = (struct g_part_gpt_entry *)baseentry;
662 		index = baseentry->gpe_index - 1;
663 		bp = buf + pp->sectorsize + table->hdr.hdr_entsz * index;
664 		le_uuid_enc(bp, &entry->ent.ent_type);
665 		le_uuid_enc(bp + 16, &entry->ent.ent_uuid);
666 		le64enc(bp + 32, entry->ent.ent_lba_start);
667 		le64enc(bp + 40, entry->ent.ent_lba_end);
668 		le64enc(bp + 48, entry->ent.ent_attr);
669 		memcpy(bp + 56, entry->ent.ent_name,
670 		    sizeof(entry->ent.ent_name));
671 	}
672 
673 	crc = crc32(buf + pp->sectorsize,
674 	    table->hdr.hdr_entries * table->hdr.hdr_entsz);
675 	le32enc(buf + 88, crc);
676 
677 	/* Write primary meta-data. */
678 	le32enc(buf + 16, 0);	/* hdr_crc_self. */
679 	le64enc(buf + 24, table->lba[GPT_ELT_PRIHDR]);	/* hdr_lba_self. */
680 	le64enc(buf + 32, table->lba[GPT_ELT_SECHDR]);	/* hdr_lba_alt. */
681 	le64enc(buf + 72, table->lba[GPT_ELT_PRITBL]);	/* hdr_lba_table. */
682 	crc = crc32(buf, table->hdr.hdr_size);
683 	le32enc(buf + 16, crc);
684 
685 	error = g_write_data(cp, table->lba[GPT_ELT_PRITBL] * pp->sectorsize,
686 	    buf + pp->sectorsize, tlbsz * pp->sectorsize);
687 	if (error)
688 		goto out;
689 	error = g_write_data(cp, table->lba[GPT_ELT_PRIHDR] * pp->sectorsize,
690 	    buf, pp->sectorsize);
691 	if (error)
692 		goto out;
693 
694 	/* Write secondary meta-data. */
695 	le32enc(buf + 16, 0);	/* hdr_crc_self. */
696 	le64enc(buf + 24, table->lba[GPT_ELT_SECHDR]);	/* hdr_lba_self. */
697 	le64enc(buf + 32, table->lba[GPT_ELT_PRIHDR]);	/* hdr_lba_alt. */
698 	le64enc(buf + 72, table->lba[GPT_ELT_SECTBL]);	/* hdr_lba_table. */
699 	crc = crc32(buf, table->hdr.hdr_size);
700 	le32enc(buf + 16, crc);
701 
702 	error = g_write_data(cp, table->lba[GPT_ELT_SECTBL] * pp->sectorsize,
703 	    buf + pp->sectorsize, tlbsz * pp->sectorsize);
704 	if (error)
705 		goto out;
706 	error = g_write_data(cp, table->lba[GPT_ELT_SECHDR] * pp->sectorsize,
707 	    buf, pp->sectorsize);
708 
709  out:
710 	g_free(buf);
711 	return (error);
712 }
713 
714 #if 0
715 static void
716 g_gpt_to_utf8(struct sbuf *sb, uint16_t *str, size_t len)
717 {
718 	u_int bo;
719 	uint32_t ch;
720 	uint16_t c;
721 
722 	bo = BYTE_ORDER;
723 	while (len > 0 && *str != 0) {
724 		ch = (bo == BIG_ENDIAN) ? be16toh(*str) : le16toh(*str);
725 		str++, len--;
726 		if ((ch & 0xf800) == 0xd800) {
727 			if (len > 0) {
728 				c = (bo == BIG_ENDIAN) ? be16toh(*str)
729 				    : le16toh(*str);
730 				str++, len--;
731 			} else
732 				c = 0xfffd;
733 			if ((ch & 0x400) == 0 && (c & 0xfc00) == 0xdc00) {
734 				ch = ((ch & 0x3ff) << 10) + (c & 0x3ff);
735 				ch += 0x10000;
736 			} else
737 				ch = 0xfffd;
738 		} else if (ch == 0xfffe) { /* BOM (U+FEFF) swapped. */
739 			bo = (bo == BIG_ENDIAN) ? LITTLE_ENDIAN : BIG_ENDIAN;
740 			continue;
741 		} else if (ch == 0xfeff) /* BOM (U+FEFF) unswapped. */
742 			continue;
743 
744 		if (ch < 0x80)
745 			sbuf_printf(sb, "%c", ch);
746 		else if (ch < 0x800)
747 			sbuf_printf(sb, "%c%c", 0xc0 | (ch >> 6),
748 			    0x80 | (ch & 0x3f));
749 		else if (ch < 0x10000)
750 			sbuf_printf(sb, "%c%c%c", 0xe0 | (ch >> 12),
751 			    0x80 | ((ch >> 6) & 0x3f), 0x80 | (ch & 0x3f));
752 		else if (ch < 0x200000)
753 			sbuf_printf(sb, "%c%c%c%c", 0xf0 | (ch >> 18),
754 			    0x80 | ((ch >> 12) & 0x3f),
755 			    0x80 | ((ch >> 6) & 0x3f), 0x80 | (ch & 0x3f));
756 	}
757 }
758 #endif
759