xref: /freebsd/sys/geom/part/g_part_gpt.c (revision 1e413cf93298b5b97441a21d9a50fdcd0ee9945e)
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_boot = GPT_ENT_TYPE_FREEBSD_BOOT;
125 static struct uuid gpt_uuid_freebsd_swap = GPT_ENT_TYPE_FREEBSD_SWAP;
126 static struct uuid gpt_uuid_freebsd_ufs = GPT_ENT_TYPE_FREEBSD_UFS;
127 static struct uuid gpt_uuid_freebsd_vinum = GPT_ENT_TYPE_FREEBSD_VINUM;
128 static struct uuid gpt_uuid_freebsd_zfs = GPT_ENT_TYPE_FREEBSD_ZFS;
129 static struct uuid gpt_uuid_linux_swap = GPT_ENT_TYPE_LINUX_SWAP;
130 static struct uuid gpt_uuid_mbr = GPT_ENT_TYPE_MBR;
131 static struct uuid gpt_uuid_unused = GPT_ENT_TYPE_UNUSED;
132 
133 static void
134 gpt_read_hdr(struct g_part_gpt_table *table, struct g_consumer *cp,
135     enum gpt_elt elt, struct gpt_hdr *hdr)
136 {
137 	struct uuid uuid;
138 	struct g_provider *pp;
139 	char *buf;
140 	quad_t lba, last;
141 	int error;
142 	uint32_t crc, sz;
143 
144 	pp = cp->provider;
145 	last = (pp->mediasize / pp->sectorsize) - 1;
146 	table->lba[elt] = (elt == GPT_ELT_PRIHDR) ? 1 : last;
147 	table->state[elt] = GPT_STATE_MISSING;
148 	buf = g_read_data(cp, table->lba[elt] * pp->sectorsize, pp->sectorsize,
149 	    &error);
150 	if (buf == NULL)
151 		return;
152 	bcopy(buf, hdr, sizeof(*hdr));
153 	if (memcmp(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig)) != 0)
154 		return;
155 
156 	table->state[elt] = GPT_STATE_CORRUPT;
157 	sz = le32toh(hdr->hdr_size);
158 	if (sz < 92 || sz > pp->sectorsize)
159 		return;
160 	crc = le32toh(hdr->hdr_crc_self);
161 	hdr->hdr_crc_self = 0;
162 	if (crc32(hdr, sz) != crc)
163 		return;
164 	hdr->hdr_size = sz;
165 	hdr->hdr_crc_self = crc;
166 
167 	table->state[elt] = GPT_STATE_INVALID;
168 	hdr->hdr_revision = le32toh(hdr->hdr_revision);
169 	if (hdr->hdr_revision < 0x00010000)
170 		return;
171 	hdr->hdr_lba_self = le64toh(hdr->hdr_lba_self);
172 	if (hdr->hdr_lba_self != table->lba[elt])
173 		return;
174 	hdr->hdr_lba_alt = le64toh(hdr->hdr_lba_alt);
175 
176 	/* Check the managed area. */
177 	hdr->hdr_lba_start = le64toh(hdr->hdr_lba_start);
178 	if (hdr->hdr_lba_start < 2 || hdr->hdr_lba_start >= last)
179 		return;
180 	hdr->hdr_lba_end = le64toh(hdr->hdr_lba_end);
181 	if (hdr->hdr_lba_end < hdr->hdr_lba_start || hdr->hdr_lba_end >= last)
182 		return;
183 
184 	/* Check the table location and size of the table. */
185 	hdr->hdr_entries = le32toh(hdr->hdr_entries);
186 	hdr->hdr_entsz = le32toh(hdr->hdr_entsz);
187 	if (hdr->hdr_entries == 0 || hdr->hdr_entsz < 128 ||
188 	    (hdr->hdr_entsz & 7) != 0)
189 		return;
190 	hdr->hdr_lba_table = le64toh(hdr->hdr_lba_table);
191 	if (hdr->hdr_lba_table < 2 || hdr->hdr_lba_table >= last)
192 		return;
193 	if (hdr->hdr_lba_table >= hdr->hdr_lba_start &&
194 	    hdr->hdr_lba_table <= hdr->hdr_lba_end)
195 		return;
196 	lba = hdr->hdr_lba_table +
197 	    (hdr->hdr_entries * hdr->hdr_entsz + pp->sectorsize - 1) /
198 	    pp->sectorsize - 1;
199 	if (lba >= last)
200 		return;
201 	if (lba >= hdr->hdr_lba_start && lba <= hdr->hdr_lba_end)
202 		return;
203 
204 	table->state[elt] = GPT_STATE_OK;
205 	le_uuid_dec(&hdr->hdr_uuid, &uuid);
206 	hdr->hdr_uuid = uuid;
207 	hdr->hdr_crc_table = le32toh(hdr->hdr_crc_table);
208 }
209 
210 static struct gpt_ent *
211 gpt_read_tbl(struct g_part_gpt_table *table, struct g_consumer *cp,
212     enum gpt_elt elt, struct gpt_hdr *hdr)
213 {
214 	struct g_provider *pp;
215 	struct gpt_ent *ent, *tbl;
216 	char *buf, *p;
217 	unsigned int idx, sectors, tblsz;
218 	int error;
219 	uint16_t ch;
220 
221 	pp = cp->provider;
222 	table->lba[elt] = hdr->hdr_lba_table;
223 
224 	table->state[elt] = GPT_STATE_MISSING;
225 	tblsz = hdr->hdr_entries * hdr->hdr_entsz;
226 	sectors = (tblsz + pp->sectorsize - 1) / pp->sectorsize;
227 	buf = g_read_data(cp, table->lba[elt] * pp->sectorsize,
228 	    sectors * pp->sectorsize, &error);
229 	if (buf == NULL)
230 		return (NULL);
231 
232 	table->state[elt] = GPT_STATE_CORRUPT;
233 	if (crc32(buf, tblsz) != hdr->hdr_crc_table) {
234 		g_free(buf);
235 		return (NULL);
236 	}
237 
238 	table->state[elt] = GPT_STATE_OK;
239 	tbl = g_malloc(hdr->hdr_entries * sizeof(struct gpt_ent),
240 	    M_WAITOK | M_ZERO);
241 
242 	for (idx = 0, ent = tbl, p = buf;
243 	     idx < hdr->hdr_entries;
244 	     idx++, ent++, p += hdr->hdr_entsz) {
245 		le_uuid_dec(p, &ent->ent_type);
246 		le_uuid_dec(p + 16, &ent->ent_uuid);
247 		ent->ent_lba_start = le64dec(p + 32);
248 		ent->ent_lba_end = le64dec(p + 40);
249 		ent->ent_attr = le64dec(p + 48);
250 		for (ch = 0; ch < sizeof(ent->ent_name)/2; ch++)
251 			ent->ent_name[ch] = le16dec(p + 56 + ch * 2);
252 	}
253 
254 	g_free(buf);
255 	return (tbl);
256 }
257 
258 static int
259 gpt_matched_hdrs(struct gpt_hdr *pri, struct gpt_hdr *sec)
260 {
261 
262 	if (!EQUUID(&pri->hdr_uuid, &sec->hdr_uuid))
263 		return (0);
264 	return ((pri->hdr_revision == sec->hdr_revision &&
265 	    pri->hdr_size == sec->hdr_size &&
266 	    pri->hdr_lba_start == sec->hdr_lba_start &&
267 	    pri->hdr_lba_end == sec->hdr_lba_end &&
268 	    pri->hdr_entries == sec->hdr_entries &&
269 	    pri->hdr_entsz == sec->hdr_entsz &&
270 	    pri->hdr_crc_table == sec->hdr_crc_table) ? 1 : 0);
271 }
272 
273 static int
274 gpt_parse_type(const char *type, struct uuid *uuid)
275 {
276 	struct uuid tmp;
277 	const char *alias;
278 	int error;
279 
280 	if (type[0] == '!') {
281 		error = parse_uuid(type + 1, &tmp);
282 		if (error)
283 			return (error);
284 		if (EQUUID(&tmp, &gpt_uuid_unused))
285 			return (EINVAL);
286 		*uuid = tmp;
287 		return (0);
288 	}
289 	alias = g_part_alias_name(G_PART_ALIAS_EFI);
290 	if (!strcasecmp(type, alias)) {
291 		*uuid = gpt_uuid_efi;
292 		return (0);
293 	}
294 	alias = g_part_alias_name(G_PART_ALIAS_FREEBSD);
295 	if (!strcasecmp(type, alias)) {
296 		*uuid = gpt_uuid_freebsd;
297 		return (0);
298 	}
299 	alias = g_part_alias_name(G_PART_ALIAS_FREEBSD_BOOT);
300 	if (!strcasecmp(type, alias)) {
301 		*uuid = gpt_uuid_freebsd_boot;
302 		return (0);
303 	}
304 	alias = g_part_alias_name(G_PART_ALIAS_FREEBSD_SWAP);
305 	if (!strcasecmp(type, alias)) {
306 		*uuid = gpt_uuid_freebsd_swap;
307 		return (0);
308 	}
309 	alias = g_part_alias_name(G_PART_ALIAS_FREEBSD_UFS);
310 	if (!strcasecmp(type, alias)) {
311 		*uuid = gpt_uuid_freebsd_ufs;
312 		return (0);
313 	}
314 	alias = g_part_alias_name(G_PART_ALIAS_FREEBSD_VINUM);
315 	if (!strcasecmp(type, alias)) {
316 		*uuid = gpt_uuid_freebsd_vinum;
317 		return (0);
318 	}
319 	alias = g_part_alias_name(G_PART_ALIAS_FREEBSD_ZFS);
320 	if (!strcasecmp(type, alias)) {
321 		*uuid = gpt_uuid_freebsd_zfs;
322 		return (0);
323 	}
324 	alias = g_part_alias_name(G_PART_ALIAS_MBR);
325 	if (!strcasecmp(type, alias)) {
326 		*uuid = gpt_uuid_mbr;
327 		return (0);
328 	}
329 	return (EINVAL);
330 }
331 
332 static int
333 g_part_gpt_add(struct g_part_table *basetable, struct g_part_entry *baseentry,
334     struct g_part_parms *gpp)
335 {
336 	struct g_part_gpt_entry *entry;
337 	int error;
338 
339 	entry = (struct g_part_gpt_entry *)baseentry;
340 	error = gpt_parse_type(gpp->gpp_type, &entry->ent.ent_type);
341 	if (error)
342 		return (error);
343 	kern_uuidgen(&entry->ent.ent_uuid, 1);
344 	entry->ent.ent_lba_start = baseentry->gpe_start;
345 	entry->ent.ent_lba_end = baseentry->gpe_end;
346 	if (baseentry->gpe_deleted) {
347 		entry->ent.ent_attr = 0;
348 		bzero(entry->ent.ent_name, sizeof(entry->ent.ent_name));
349 	}
350 	/* XXX label */
351 	return (0);
352 }
353 
354 static int
355 g_part_gpt_create(struct g_part_table *basetable, struct g_part_parms *gpp)
356 {
357 	struct g_provider *pp;
358 	struct g_part_gpt_table *table;
359 	quad_t last;
360 	size_t tblsz;
361 
362 	table = (struct g_part_gpt_table *)basetable;
363 	pp = gpp->gpp_provider;
364 	tblsz = (basetable->gpt_entries * sizeof(struct gpt_ent) +
365 	    pp->sectorsize - 1) / pp->sectorsize;
366 	if (pp->sectorsize < 512 ||
367 	    pp->mediasize < (3 + 2 * tblsz + basetable->gpt_entries) *
368 	    pp->sectorsize)
369 		return (ENOSPC);
370 
371 	last = (pp->mediasize / pp->sectorsize) - 1;
372 
373 	table->lba[GPT_ELT_PRIHDR] = 1;
374 	table->lba[GPT_ELT_PRITBL] = 2;
375 	table->lba[GPT_ELT_SECHDR] = last;
376 	table->lba[GPT_ELT_SECTBL] = last - tblsz;
377 
378 	bcopy(GPT_HDR_SIG, table->hdr.hdr_sig, sizeof(table->hdr.hdr_sig));
379 	table->hdr.hdr_revision = GPT_HDR_REVISION;
380 	table->hdr.hdr_size = offsetof(struct gpt_hdr, padding);
381 	table->hdr.hdr_lba_start = 2 + tblsz;
382 	table->hdr.hdr_lba_end = last - tblsz - 1;
383 	kern_uuidgen(&table->hdr.hdr_uuid, 1);
384 	table->hdr.hdr_entries = basetable->gpt_entries;
385 	table->hdr.hdr_entsz = sizeof(struct gpt_ent);
386 
387 	basetable->gpt_first = table->hdr.hdr_lba_start;
388 	basetable->gpt_last = table->hdr.hdr_lba_end;
389 	return (0);
390 }
391 
392 static int
393 g_part_gpt_destroy(struct g_part_table *basetable, struct g_part_parms *gpp)
394 {
395 
396 	/*
397 	 * Wipe the first 2 sectors as well as the last to clear the
398 	 * partitioning.
399 	 */
400 	basetable->gpt_smhead |= 3;
401 	basetable->gpt_smtail |= 1;
402 	return (0);
403 }
404 
405 static int
406 g_part_gpt_dumpto(struct g_part_table *table, struct g_part_entry *baseentry)
407 {
408 	struct g_part_gpt_entry *entry;
409 
410 	entry = (struct g_part_gpt_entry *)baseentry;
411 	return ((EQUUID(&entry->ent.ent_type, &gpt_uuid_freebsd_swap) ||
412 	    EQUUID(&entry->ent.ent_type, &gpt_uuid_linux_swap)) ? 1 : 0);
413 }
414 
415 static int
416 g_part_gpt_modify(struct g_part_table *basetable,
417     struct g_part_entry *baseentry, struct g_part_parms *gpp)
418 {
419 	struct g_part_gpt_entry *entry;
420 	int error;
421 
422 	entry = (struct g_part_gpt_entry *)baseentry;
423 	if (gpp->gpp_parms & G_PART_PARM_TYPE) {
424 		error = gpt_parse_type(gpp->gpp_type, &entry->ent.ent_type);
425 		if (error)
426 			return (error);
427 	}
428 	/* XXX label */
429 	return (0);
430 }
431 
432 static char *
433 g_part_gpt_name(struct g_part_table *table, struct g_part_entry *baseentry,
434     char *buf, size_t bufsz)
435 {
436 	struct g_part_gpt_entry *entry;
437 	char c;
438 
439 	entry = (struct g_part_gpt_entry *)baseentry;
440 	c = (EQUUID(&entry->ent.ent_type, &gpt_uuid_freebsd)) ? 's' : 'p';
441 	snprintf(buf, bufsz, "%c%d", c, baseentry->gpe_index);
442 	return (buf);
443 }
444 
445 static int
446 g_part_gpt_probe(struct g_part_table *table, struct g_consumer *cp)
447 {
448 	struct g_provider *pp;
449 	char *buf;
450 	int error, res;
451 
452 	/* We don't nest, which means that our depth should be 0. */
453 	if (table->gpt_depth != 0)
454 		return (ENXIO);
455 
456 	pp = cp->provider;
457 
458 	/*
459 	 * Sanity-check the provider. Since the first sector on the provider
460 	 * must be a PMBR and a PMBR is 512 bytes large, the sector size
461 	 * must be at least 512 bytes.  Also, since the theoretical minimum
462 	 * number of sectors needed by GPT is 6, any medium that has less
463 	 * than 6 sectors is never going to be able to hold a GPT. The
464 	 * number 6 comes from:
465 	 *	1 sector for the PMBR
466 	 *	2 sectors for the GPT headers (each 1 sector)
467 	 *	2 sectors for the GPT tables (each 1 sector)
468 	 *	1 sector for an actual partition
469 	 * It's better to catch this pathological case early than behaving
470 	 * pathologically later on...
471 	 */
472 	if (pp->sectorsize < 512 || pp->mediasize < 6 * pp->sectorsize)
473 		return (ENOSPC);
474 
475 	/* Check that there's a MBR. */
476 	buf = g_read_data(cp, 0L, pp->sectorsize, &error);
477 	if (buf == NULL)
478 		return (error);
479 	res = le16dec(buf + DOSMAGICOFFSET);
480 	g_free(buf);
481 	if (res != DOSMAGIC)
482 		return (ENXIO);
483 
484 	/* Check that there's a primary header. */
485 	buf = g_read_data(cp, pp->sectorsize, pp->sectorsize, &error);
486 	if (buf == NULL)
487 		return (error);
488 	res = memcmp(buf, GPT_HDR_SIG, 8);
489 	g_free(buf);
490 	if (res == 0)
491 		return (G_PART_PROBE_PRI_HIGH);
492 
493 	/* No primary? Check that there's a secondary. */
494 	buf = g_read_data(cp, pp->mediasize - pp->sectorsize, pp->sectorsize,
495 	    &error);
496 	if (buf == NULL)
497 		return (error);
498 	res = memcmp(buf, GPT_HDR_SIG, 8);
499 	g_free(buf);
500 	return ((res == 0) ? G_PART_PROBE_PRI_HIGH : ENXIO);
501 }
502 
503 static int
504 g_part_gpt_read(struct g_part_table *basetable, struct g_consumer *cp)
505 {
506 	struct gpt_hdr prihdr, sechdr;
507 	struct gpt_ent *tbl, *pritbl, *sectbl;
508 	struct g_provider *pp;
509 	struct g_part_gpt_table *table;
510 	struct g_part_gpt_entry *entry;
511 	int index;
512 
513 	table = (struct g_part_gpt_table *)basetable;
514 	pp = cp->provider;
515 
516 	/* Read the primary header and table. */
517 	gpt_read_hdr(table, cp, GPT_ELT_PRIHDR, &prihdr);
518 	if (table->state[GPT_ELT_PRIHDR] == GPT_STATE_OK) {
519 		pritbl = gpt_read_tbl(table, cp, GPT_ELT_PRITBL, &prihdr);
520 	} else {
521 		table->state[GPT_ELT_PRITBL] = GPT_STATE_MISSING;
522 		pritbl = NULL;
523 	}
524 
525 	/* Read the secondary header and table. */
526 	gpt_read_hdr(table, cp, GPT_ELT_SECHDR, &sechdr);
527 	if (table->state[GPT_ELT_SECHDR] == GPT_STATE_OK) {
528 		sectbl = gpt_read_tbl(table, cp, GPT_ELT_SECTBL, &sechdr);
529 	} else {
530 		table->state[GPT_ELT_SECTBL] = GPT_STATE_MISSING;
531 		sectbl = NULL;
532 	}
533 
534 	/* Fail if we haven't got any good tables at all. */
535 	if (table->state[GPT_ELT_PRITBL] != GPT_STATE_OK &&
536 	    table->state[GPT_ELT_SECTBL] != GPT_STATE_OK) {
537 		printf("GEOM: %s: corrupt or invalid GPT detected.\n",
538 		    pp->name);
539 		printf("GEOM: %s: GPT rejected -- may not be recoverable.\n",
540 		    pp->name);
541 		return (EINVAL);
542 	}
543 
544 	/*
545 	 * If both headers are good but they disagree with each other,
546 	 * then invalidate one. We prefer to keep the primary header,
547 	 * unless the primary table is corrupt.
548 	 */
549 	if (table->state[GPT_ELT_PRIHDR] == GPT_STATE_OK &&
550 	    table->state[GPT_ELT_SECHDR] == GPT_STATE_OK &&
551 	    !gpt_matched_hdrs(&prihdr, &sechdr)) {
552 		if (table->state[GPT_ELT_PRITBL] == GPT_STATE_OK)
553 			table->state[GPT_ELT_SECHDR] = GPT_STATE_INVALID;
554 		else
555 			table->state[GPT_ELT_PRIHDR] = GPT_STATE_INVALID;
556 	}
557 
558 	if (table->state[GPT_ELT_PRIHDR] != GPT_STATE_OK) {
559 		printf("GEOM: %s: the primary GPT table is corrupt or "
560 		    "invalid.\n", pp->name);
561 		printf("GEOM: %s: using the secondary instead -- recovery "
562 		    "strongly advised.\n", pp->name);
563 		table->hdr = sechdr;
564 		tbl = sectbl;
565 		if (pritbl != NULL)
566 			g_free(pritbl);
567 	} else {
568 		if (table->state[GPT_ELT_SECHDR] != GPT_STATE_OK) {
569 			printf("GEOM: %s: the secondary GPT table is corrupt "
570 			    "or invalid.\n", pp->name);
571 			printf("GEOM: %s: using the primary only -- recovery "
572 			    "suggested.\n", pp->name);
573 		}
574 		table->hdr = prihdr;
575 		tbl = pritbl;
576 		if (sectbl != NULL)
577 			g_free(sectbl);
578 	}
579 
580 	basetable->gpt_first = table->hdr.hdr_lba_start;
581 	basetable->gpt_last = table->hdr.hdr_lba_end;
582 	basetable->gpt_entries = table->hdr.hdr_entries;
583 
584 	for (index = basetable->gpt_entries - 1; index >= 0; index--) {
585 		if (EQUUID(&tbl[index].ent_type, &gpt_uuid_unused))
586 			continue;
587 		entry = (struct g_part_gpt_entry *)g_part_new_entry(basetable,
588 		    index+1, tbl[index].ent_lba_start, tbl[index].ent_lba_end);
589 		entry->ent = tbl[index];
590 	}
591 
592 	g_free(tbl);
593 	return (0);
594 }
595 
596 static const char *
597 g_part_gpt_type(struct g_part_table *basetable, struct g_part_entry *baseentry,
598     char *buf, size_t bufsz)
599 {
600 	struct g_part_gpt_entry *entry;
601 	struct uuid *type;
602 
603 	entry = (struct g_part_gpt_entry *)baseentry;
604 	type = &entry->ent.ent_type;
605 	if (EQUUID(type, &gpt_uuid_efi))
606 		return (g_part_alias_name(G_PART_ALIAS_EFI));
607 	if (EQUUID(type, &gpt_uuid_freebsd))
608 		return (g_part_alias_name(G_PART_ALIAS_FREEBSD));
609 	if (EQUUID(type, &gpt_uuid_freebsd_boot))
610 		return (g_part_alias_name(G_PART_ALIAS_FREEBSD_BOOT));
611 	if (EQUUID(type, &gpt_uuid_freebsd_swap))
612 		return (g_part_alias_name(G_PART_ALIAS_FREEBSD_SWAP));
613 	if (EQUUID(type, &gpt_uuid_freebsd_ufs))
614 		return (g_part_alias_name(G_PART_ALIAS_FREEBSD_UFS));
615 	if (EQUUID(type, &gpt_uuid_freebsd_vinum))
616 		return (g_part_alias_name(G_PART_ALIAS_FREEBSD_VINUM));
617 	if (EQUUID(type, &gpt_uuid_freebsd_zfs))
618 		return (g_part_alias_name(G_PART_ALIAS_FREEBSD_ZFS));
619 	if (EQUUID(type, &gpt_uuid_mbr))
620 		return (g_part_alias_name(G_PART_ALIAS_MBR));
621 	buf[0] = '!';
622 	snprintf_uuid(buf + 1, bufsz - 1, type);
623 	return (buf);
624 }
625 
626 static int
627 g_part_gpt_write(struct g_part_table *basetable, struct g_consumer *cp)
628 {
629 	unsigned char *buf, *bp;
630 	struct g_provider *pp;
631 	struct g_part_entry *baseentry;
632 	struct g_part_gpt_entry *entry;
633 	struct g_part_gpt_table *table;
634 	size_t tlbsz;
635 	uint32_t crc;
636 	int error, index;
637 
638 	pp = cp->provider;
639 	table = (struct g_part_gpt_table *)basetable;
640 	tlbsz = (table->hdr.hdr_entries * table->hdr.hdr_entsz +
641 	    pp->sectorsize - 1) / pp->sectorsize;
642 
643 	if (basetable->gpt_created) {
644 		buf = g_malloc(pp->sectorsize, M_WAITOK | M_ZERO);
645 		le16enc(buf + DOSMAGICOFFSET, DOSMAGIC);
646 		buf[DOSPARTOFF + 1] = 0xff;		/* shd */
647 		buf[DOSPARTOFF + 2] = 0xff;		/* ssect */
648 		buf[DOSPARTOFF + 3] = 0xff;		/* scyl */
649 		buf[DOSPARTOFF + 4] = 0xee;		/* typ */
650 		buf[DOSPARTOFF + 5] = 0xff;		/* ehd */
651 		buf[DOSPARTOFF + 6] = 0xff;		/* esect */
652 		buf[DOSPARTOFF + 7] = 0xff;		/* ecyl */
653 		le32enc(buf + DOSPARTOFF + 8, 1);	/* start */
654 		le32enc(buf + DOSPARTOFF + 12,
655 		    MIN(pp->mediasize / pp->sectorsize - 1, 0xffffffffLL));
656 		error = g_write_data(cp, 0, buf, pp->sectorsize);
657 		g_free(buf);
658 		if (error)
659 			return (error);
660 	}
661 
662 	/* Allocate space for the header and entries. */
663 	buf = g_malloc((tlbsz + 1) * pp->sectorsize, M_WAITOK | M_ZERO);
664 
665 	memcpy(buf, table->hdr.hdr_sig, sizeof(table->hdr.hdr_sig));
666 	le32enc(buf + 8, table->hdr.hdr_revision);
667 	le32enc(buf + 12, table->hdr.hdr_size);
668 	le64enc(buf + 40, table->hdr.hdr_lba_start);
669 	le64enc(buf + 48, table->hdr.hdr_lba_end);
670 	le_uuid_enc(buf + 56, &table->hdr.hdr_uuid);
671 	le32enc(buf + 80, table->hdr.hdr_entries);
672 	le32enc(buf + 84, table->hdr.hdr_entsz);
673 
674 	LIST_FOREACH(baseentry, &basetable->gpt_entry, gpe_entry) {
675 		if (baseentry->gpe_deleted)
676 			continue;
677 		entry = (struct g_part_gpt_entry *)baseentry;
678 		index = baseentry->gpe_index - 1;
679 		bp = buf + pp->sectorsize + table->hdr.hdr_entsz * index;
680 		le_uuid_enc(bp, &entry->ent.ent_type);
681 		le_uuid_enc(bp + 16, &entry->ent.ent_uuid);
682 		le64enc(bp + 32, entry->ent.ent_lba_start);
683 		le64enc(bp + 40, entry->ent.ent_lba_end);
684 		le64enc(bp + 48, entry->ent.ent_attr);
685 		memcpy(bp + 56, entry->ent.ent_name,
686 		    sizeof(entry->ent.ent_name));
687 	}
688 
689 	crc = crc32(buf + pp->sectorsize,
690 	    table->hdr.hdr_entries * table->hdr.hdr_entsz);
691 	le32enc(buf + 88, crc);
692 
693 	/* Write primary meta-data. */
694 	le32enc(buf + 16, 0);	/* hdr_crc_self. */
695 	le64enc(buf + 24, table->lba[GPT_ELT_PRIHDR]);	/* hdr_lba_self. */
696 	le64enc(buf + 32, table->lba[GPT_ELT_SECHDR]);	/* hdr_lba_alt. */
697 	le64enc(buf + 72, table->lba[GPT_ELT_PRITBL]);	/* hdr_lba_table. */
698 	crc = crc32(buf, table->hdr.hdr_size);
699 	le32enc(buf + 16, crc);
700 
701 	error = g_write_data(cp, table->lba[GPT_ELT_PRITBL] * pp->sectorsize,
702 	    buf + pp->sectorsize, tlbsz * pp->sectorsize);
703 	if (error)
704 		goto out;
705 	error = g_write_data(cp, table->lba[GPT_ELT_PRIHDR] * pp->sectorsize,
706 	    buf, pp->sectorsize);
707 	if (error)
708 		goto out;
709 
710 	/* Write secondary meta-data. */
711 	le32enc(buf + 16, 0);	/* hdr_crc_self. */
712 	le64enc(buf + 24, table->lba[GPT_ELT_SECHDR]);	/* hdr_lba_self. */
713 	le64enc(buf + 32, table->lba[GPT_ELT_PRIHDR]);	/* hdr_lba_alt. */
714 	le64enc(buf + 72, table->lba[GPT_ELT_SECTBL]);	/* hdr_lba_table. */
715 	crc = crc32(buf, table->hdr.hdr_size);
716 	le32enc(buf + 16, crc);
717 
718 	error = g_write_data(cp, table->lba[GPT_ELT_SECTBL] * pp->sectorsize,
719 	    buf + pp->sectorsize, tlbsz * pp->sectorsize);
720 	if (error)
721 		goto out;
722 	error = g_write_data(cp, table->lba[GPT_ELT_SECHDR] * pp->sectorsize,
723 	    buf, pp->sectorsize);
724 
725  out:
726 	g_free(buf);
727 	return (error);
728 }
729 
730 #if 0
731 static void
732 g_gpt_to_utf8(struct sbuf *sb, uint16_t *str, size_t len)
733 {
734 	u_int bo;
735 	uint32_t ch;
736 	uint16_t c;
737 
738 	bo = BYTE_ORDER;
739 	while (len > 0 && *str != 0) {
740 		ch = (bo == BIG_ENDIAN) ? be16toh(*str) : le16toh(*str);
741 		str++, len--;
742 		if ((ch & 0xf800) == 0xd800) {
743 			if (len > 0) {
744 				c = (bo == BIG_ENDIAN) ? be16toh(*str)
745 				    : le16toh(*str);
746 				str++, len--;
747 			} else
748 				c = 0xfffd;
749 			if ((ch & 0x400) == 0 && (c & 0xfc00) == 0xdc00) {
750 				ch = ((ch & 0x3ff) << 10) + (c & 0x3ff);
751 				ch += 0x10000;
752 			} else
753 				ch = 0xfffd;
754 		} else if (ch == 0xfffe) { /* BOM (U+FEFF) swapped. */
755 			bo = (bo == BIG_ENDIAN) ? LITTLE_ENDIAN : BIG_ENDIAN;
756 			continue;
757 		} else if (ch == 0xfeff) /* BOM (U+FEFF) unswapped. */
758 			continue;
759 
760 		if (ch < 0x80)
761 			sbuf_printf(sb, "%c", ch);
762 		else if (ch < 0x800)
763 			sbuf_printf(sb, "%c%c", 0xc0 | (ch >> 6),
764 			    0x80 | (ch & 0x3f));
765 		else if (ch < 0x10000)
766 			sbuf_printf(sb, "%c%c%c", 0xe0 | (ch >> 12),
767 			    0x80 | ((ch >> 6) & 0x3f), 0x80 | (ch & 0x3f));
768 		else if (ch < 0x200000)
769 			sbuf_printf(sb, "%c%c%c%c", 0xf0 | (ch >> 18),
770 			    0x80 | ((ch >> 12) & 0x3f),
771 			    0x80 | ((ch >> 6) & 0x3f), 0x80 | (ch & 0x3f));
772 	}
773 }
774 #endif
775