]> CyberLeo.Net >> Repos - FreeBSD/stable/8.git/blob - sys/geom/part/g_part_gpt.c
MFC r215118:
[FreeBSD/stable/8.git] / sys / geom / part / g_part_gpt.c
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 #define MBRSIZE         512
56
57 enum gpt_elt {
58         GPT_ELT_PRIHDR,
59         GPT_ELT_PRITBL,
60         GPT_ELT_SECHDR,
61         GPT_ELT_SECTBL,
62         GPT_ELT_COUNT
63 };
64
65 enum gpt_state {
66         GPT_STATE_UNKNOWN,      /* Not determined. */
67         GPT_STATE_MISSING,      /* No signature found. */
68         GPT_STATE_CORRUPT,      /* Checksum mismatch. */
69         GPT_STATE_INVALID,      /* Nonconformant/invalid. */
70         GPT_STATE_OK            /* Perfectly fine. */
71 };
72
73 struct g_part_gpt_table {
74         struct g_part_table     base;
75         u_char                  mbr[MBRSIZE];
76         struct gpt_hdr          *hdr;
77         quad_t                  lba[GPT_ELT_COUNT];
78         enum gpt_state          state[GPT_ELT_COUNT];
79 };
80
81 struct g_part_gpt_entry {
82         struct g_part_entry     base;
83         struct gpt_ent          ent;
84 };
85
86 static void g_gpt_printf_utf16(struct sbuf *, uint16_t *, size_t);
87 static void g_gpt_utf8_to_utf16(const uint8_t *, uint16_t *, size_t);
88 static void g_gpt_set_defaults(struct g_part_table *, struct g_provider *);
89
90 static int g_part_gpt_add(struct g_part_table *, struct g_part_entry *,
91     struct g_part_parms *);
92 static int g_part_gpt_bootcode(struct g_part_table *, struct g_part_parms *);
93 static int g_part_gpt_create(struct g_part_table *, struct g_part_parms *);
94 static int g_part_gpt_destroy(struct g_part_table *, struct g_part_parms *);
95 static void g_part_gpt_dumpconf(struct g_part_table *, struct g_part_entry *,
96     struct sbuf *, const char *);
97 static int g_part_gpt_dumpto(struct g_part_table *, struct g_part_entry *);
98 static int g_part_gpt_modify(struct g_part_table *, struct g_part_entry *,
99     struct g_part_parms *);
100 static const char *g_part_gpt_name(struct g_part_table *, struct g_part_entry *,
101     char *, size_t);
102 static int g_part_gpt_probe(struct g_part_table *, struct g_consumer *);
103 static int g_part_gpt_read(struct g_part_table *, struct g_consumer *);
104 static int g_part_gpt_setunset(struct g_part_table *table,
105     struct g_part_entry *baseentry, const char *attrib, unsigned int set);
106 static const char *g_part_gpt_type(struct g_part_table *, struct g_part_entry *,
107     char *, size_t);
108 static int g_part_gpt_write(struct g_part_table *, struct g_consumer *);
109 static int g_part_gpt_resize(struct g_part_table *, struct g_part_entry *,
110     struct g_part_parms *);
111 static int g_part_gpt_recover(struct g_part_table *);
112
113 static kobj_method_t g_part_gpt_methods[] = {
114         KOBJMETHOD(g_part_add,          g_part_gpt_add),
115         KOBJMETHOD(g_part_bootcode,     g_part_gpt_bootcode),
116         KOBJMETHOD(g_part_create,       g_part_gpt_create),
117         KOBJMETHOD(g_part_destroy,      g_part_gpt_destroy),
118         KOBJMETHOD(g_part_dumpconf,     g_part_gpt_dumpconf),
119         KOBJMETHOD(g_part_dumpto,       g_part_gpt_dumpto),
120         KOBJMETHOD(g_part_modify,       g_part_gpt_modify),
121         KOBJMETHOD(g_part_resize,       g_part_gpt_resize),
122         KOBJMETHOD(g_part_name,         g_part_gpt_name),
123         KOBJMETHOD(g_part_probe,        g_part_gpt_probe),
124         KOBJMETHOD(g_part_read,         g_part_gpt_read),
125         KOBJMETHOD(g_part_recover,      g_part_gpt_recover),
126         KOBJMETHOD(g_part_setunset,     g_part_gpt_setunset),
127         KOBJMETHOD(g_part_type,         g_part_gpt_type),
128         KOBJMETHOD(g_part_write,        g_part_gpt_write),
129         { 0, 0 }
130 };
131
132 static struct g_part_scheme g_part_gpt_scheme = {
133         "GPT",
134         g_part_gpt_methods,
135         sizeof(struct g_part_gpt_table),
136         .gps_entrysz = sizeof(struct g_part_gpt_entry),
137         .gps_minent = 128,
138         .gps_maxent = 4096,
139         .gps_bootcodesz = MBRSIZE,
140 };
141 G_PART_SCHEME_DECLARE(g_part_gpt);
142
143 static struct uuid gpt_uuid_apple_boot = GPT_ENT_TYPE_APPLE_BOOT;
144 static struct uuid gpt_uuid_apple_hfs = GPT_ENT_TYPE_APPLE_HFS;
145 static struct uuid gpt_uuid_apple_label = GPT_ENT_TYPE_APPLE_LABEL;
146 static struct uuid gpt_uuid_apple_raid = GPT_ENT_TYPE_APPLE_RAID;
147 static struct uuid gpt_uuid_apple_raid_offline = GPT_ENT_TYPE_APPLE_RAID_OFFLINE;
148 static struct uuid gpt_uuid_apple_tv_recovery = GPT_ENT_TYPE_APPLE_TV_RECOVERY;
149 static struct uuid gpt_uuid_apple_ufs = GPT_ENT_TYPE_APPLE_UFS;
150 static struct uuid gpt_uuid_bios_boot = GPT_ENT_TYPE_BIOS_BOOT;
151 static struct uuid gpt_uuid_efi = GPT_ENT_TYPE_EFI;
152 static struct uuid gpt_uuid_freebsd = GPT_ENT_TYPE_FREEBSD;
153 static struct uuid gpt_uuid_freebsd_boot = GPT_ENT_TYPE_FREEBSD_BOOT;
154 static struct uuid gpt_uuid_freebsd_swap = GPT_ENT_TYPE_FREEBSD_SWAP;
155 static struct uuid gpt_uuid_freebsd_ufs = GPT_ENT_TYPE_FREEBSD_UFS;
156 static struct uuid gpt_uuid_freebsd_vinum = GPT_ENT_TYPE_FREEBSD_VINUM;
157 static struct uuid gpt_uuid_freebsd_zfs = GPT_ENT_TYPE_FREEBSD_ZFS;
158 static struct uuid gpt_uuid_linux_data = GPT_ENT_TYPE_LINUX_DATA;
159 static struct uuid gpt_uuid_linux_lvm = GPT_ENT_TYPE_LINUX_LVM;
160 static struct uuid gpt_uuid_linux_raid = GPT_ENT_TYPE_LINUX_RAID;
161 static struct uuid gpt_uuid_linux_swap = GPT_ENT_TYPE_LINUX_SWAP;
162 static struct uuid gpt_uuid_ms_basic_data = GPT_ENT_TYPE_MS_BASIC_DATA;
163 static struct uuid gpt_uuid_ms_reserved = GPT_ENT_TYPE_MS_RESERVED;
164 static struct uuid gpt_uuid_ms_ldm_data = GPT_ENT_TYPE_MS_LDM_DATA;
165 static struct uuid gpt_uuid_ms_ldm_metadata = GPT_ENT_TYPE_MS_LDM_METADATA;
166 static struct uuid gpt_uuid_netbsd_ccd = GPT_ENT_TYPE_NETBSD_CCD;
167 static struct uuid gpt_uuid_netbsd_cgd = GPT_ENT_TYPE_NETBSD_CGD;
168 static struct uuid gpt_uuid_netbsd_ffs = GPT_ENT_TYPE_NETBSD_FFS;
169 static struct uuid gpt_uuid_netbsd_lfs = GPT_ENT_TYPE_NETBSD_LFS;
170 static struct uuid gpt_uuid_netbsd_raid = GPT_ENT_TYPE_NETBSD_RAID;
171 static struct uuid gpt_uuid_netbsd_swap = GPT_ENT_TYPE_NETBSD_SWAP;
172 static struct uuid gpt_uuid_mbr = GPT_ENT_TYPE_MBR;
173 static struct uuid gpt_uuid_unused = GPT_ENT_TYPE_UNUSED;
174
175 static struct g_part_uuid_alias {
176         struct uuid *uuid;
177         int alias;
178 } gpt_uuid_alias_match[] = {
179         { &gpt_uuid_apple_boot,         G_PART_ALIAS_APPLE_BOOT },
180         { &gpt_uuid_apple_hfs,          G_PART_ALIAS_APPLE_HFS },
181         { &gpt_uuid_apple_label,        G_PART_ALIAS_APPLE_LABEL },
182         { &gpt_uuid_apple_raid,         G_PART_ALIAS_APPLE_RAID },
183         { &gpt_uuid_apple_raid_offline, G_PART_ALIAS_APPLE_RAID_OFFLINE },
184         { &gpt_uuid_apple_tv_recovery,  G_PART_ALIAS_APPLE_TV_RECOVERY },
185         { &gpt_uuid_apple_ufs,          G_PART_ALIAS_APPLE_UFS },
186         { &gpt_uuid_bios_boot,          G_PART_ALIAS_BIOS_BOOT },
187         { &gpt_uuid_efi,                G_PART_ALIAS_EFI },
188         { &gpt_uuid_freebsd,            G_PART_ALIAS_FREEBSD },
189         { &gpt_uuid_freebsd_boot,       G_PART_ALIAS_FREEBSD_BOOT },
190         { &gpt_uuid_freebsd_swap,       G_PART_ALIAS_FREEBSD_SWAP },
191         { &gpt_uuid_freebsd_ufs,        G_PART_ALIAS_FREEBSD_UFS },
192         { &gpt_uuid_freebsd_vinum,      G_PART_ALIAS_FREEBSD_VINUM },
193         { &gpt_uuid_freebsd_zfs,        G_PART_ALIAS_FREEBSD_ZFS },
194         { &gpt_uuid_linux_data,         G_PART_ALIAS_LINUX_DATA },
195         { &gpt_uuid_linux_lvm,          G_PART_ALIAS_LINUX_LVM },
196         { &gpt_uuid_linux_raid,         G_PART_ALIAS_LINUX_RAID },
197         { &gpt_uuid_linux_swap,         G_PART_ALIAS_LINUX_SWAP },
198         { &gpt_uuid_mbr,                G_PART_ALIAS_MBR },
199         { &gpt_uuid_ms_basic_data,      G_PART_ALIAS_MS_BASIC_DATA },
200         { &gpt_uuid_ms_ldm_data,        G_PART_ALIAS_MS_LDM_DATA },
201         { &gpt_uuid_ms_ldm_metadata,    G_PART_ALIAS_MS_LDM_METADATA },
202         { &gpt_uuid_ms_reserved,        G_PART_ALIAS_MS_RESERVED },
203         { &gpt_uuid_netbsd_ccd,         G_PART_ALIAS_NETBSD_CCD },
204         { &gpt_uuid_netbsd_cgd,         G_PART_ALIAS_NETBSD_CGD },
205         { &gpt_uuid_netbsd_ffs,         G_PART_ALIAS_NETBSD_FFS },
206         { &gpt_uuid_netbsd_lfs,         G_PART_ALIAS_NETBSD_LFS },
207         { &gpt_uuid_netbsd_raid,        G_PART_ALIAS_NETBSD_RAID },
208         { &gpt_uuid_netbsd_swap,        G_PART_ALIAS_NETBSD_SWAP },
209
210         { NULL, 0 }
211 };
212
213 static struct gpt_hdr *
214 gpt_read_hdr(struct g_part_gpt_table *table, struct g_consumer *cp,
215     enum gpt_elt elt)
216 {
217         struct gpt_hdr *buf, *hdr;
218         struct g_provider *pp;
219         quad_t lba, last;
220         int error;
221         uint32_t crc, sz;
222
223         pp = cp->provider;
224         last = (pp->mediasize / pp->sectorsize) - 1;
225         table->state[elt] = GPT_STATE_MISSING;
226         /*
227          * If the primary header is valid look for secondary
228          * header in AlternateLBA, otherwise in the last medium's LBA.
229          */
230         if (elt == GPT_ELT_SECHDR) {
231                 if (table->state[GPT_ELT_PRIHDR] != GPT_STATE_OK)
232                         table->lba[elt] = last;
233         } else
234                 table->lba[elt] = 1;
235         buf = g_read_data(cp, table->lba[elt] * pp->sectorsize, pp->sectorsize,
236             &error);
237         if (buf == NULL)
238                 return (NULL);
239         hdr = NULL;
240         if (memcmp(buf->hdr_sig, GPT_HDR_SIG, sizeof(buf->hdr_sig)) != 0)
241                 goto fail;
242
243         table->state[elt] = GPT_STATE_CORRUPT;
244         sz = le32toh(buf->hdr_size);
245         if (sz < 92 || sz > pp->sectorsize)
246                 goto fail;
247
248         hdr = g_malloc(sz, M_WAITOK | M_ZERO);
249         bcopy(buf, hdr, sz);
250         hdr->hdr_size = sz;
251
252         crc = le32toh(buf->hdr_crc_self);
253         buf->hdr_crc_self = 0;
254         if (crc32(buf, sz) != crc)
255                 goto fail;
256         hdr->hdr_crc_self = crc;
257
258         table->state[elt] = GPT_STATE_INVALID;
259         hdr->hdr_revision = le32toh(buf->hdr_revision);
260         if (hdr->hdr_revision < GPT_HDR_REVISION)
261                 goto fail;
262         hdr->hdr_lba_self = le64toh(buf->hdr_lba_self);
263         if (hdr->hdr_lba_self != table->lba[elt])
264                 goto fail;
265         hdr->hdr_lba_alt = le64toh(buf->hdr_lba_alt);
266         if (hdr->hdr_lba_alt == hdr->hdr_lba_self ||
267             hdr->hdr_lba_alt > last)
268                 goto fail;
269
270         /* Check the managed area. */
271         hdr->hdr_lba_start = le64toh(buf->hdr_lba_start);
272         if (hdr->hdr_lba_start < 2 || hdr->hdr_lba_start >= last)
273                 goto fail;
274         hdr->hdr_lba_end = le64toh(buf->hdr_lba_end);
275         if (hdr->hdr_lba_end < hdr->hdr_lba_start || hdr->hdr_lba_end >= last)
276                 goto fail;
277
278         /* Check the table location and size of the table. */
279         hdr->hdr_entries = le32toh(buf->hdr_entries);
280         hdr->hdr_entsz = le32toh(buf->hdr_entsz);
281         if (hdr->hdr_entries == 0 || hdr->hdr_entsz < 128 ||
282             (hdr->hdr_entsz & 7) != 0)
283                 goto fail;
284         hdr->hdr_lba_table = le64toh(buf->hdr_lba_table);
285         if (hdr->hdr_lba_table < 2 || hdr->hdr_lba_table >= last)
286                 goto fail;
287         if (hdr->hdr_lba_table >= hdr->hdr_lba_start &&
288             hdr->hdr_lba_table <= hdr->hdr_lba_end)
289                 goto fail;
290         lba = hdr->hdr_lba_table +
291             (hdr->hdr_entries * hdr->hdr_entsz + pp->sectorsize - 1) /
292             pp->sectorsize - 1;
293         if (lba >= last)
294                 goto fail;
295         if (lba >= hdr->hdr_lba_start && lba <= hdr->hdr_lba_end)
296                 goto fail;
297
298         table->state[elt] = GPT_STATE_OK;
299         le_uuid_dec(&buf->hdr_uuid, &hdr->hdr_uuid);
300         hdr->hdr_crc_table = le32toh(buf->hdr_crc_table);
301
302         /* save LBA for secondary header */
303         if (elt == GPT_ELT_PRIHDR)
304                 table->lba[GPT_ELT_SECHDR] = hdr->hdr_lba_alt;
305
306         g_free(buf);
307         return (hdr);
308
309  fail:
310         if (hdr != NULL)
311                 g_free(hdr);
312         g_free(buf);
313         return (NULL);
314 }
315
316 static struct gpt_ent *
317 gpt_read_tbl(struct g_part_gpt_table *table, struct g_consumer *cp,
318     enum gpt_elt elt, struct gpt_hdr *hdr)
319 {
320         struct g_provider *pp;
321         struct gpt_ent *ent, *tbl;
322         char *buf, *p;
323         unsigned int idx, sectors, tblsz, size;
324         int error;
325
326         if (hdr == NULL)
327                 return (NULL);
328
329         pp = cp->provider;
330         table->lba[elt] = hdr->hdr_lba_table;
331
332         table->state[elt] = GPT_STATE_MISSING;
333         tblsz = hdr->hdr_entries * hdr->hdr_entsz;
334         sectors = (tblsz + pp->sectorsize - 1) / pp->sectorsize;
335         buf = g_malloc(sectors * pp->sectorsize, M_WAITOK | M_ZERO);
336         for (idx = 0; idx < sectors; idx += MAXPHYS / pp->sectorsize) {
337                 size = (sectors - idx > MAXPHYS / pp->sectorsize) ?  MAXPHYS:
338                     (sectors - idx) * pp->sectorsize;
339                 p = g_read_data(cp, (table->lba[elt] + idx) * pp->sectorsize,
340                     size, &error);
341                 if (p == NULL) {
342                         g_free(buf);
343                         return (NULL);
344                 }
345                 bcopy(p, buf + idx * pp->sectorsize, size);
346                 g_free(p);
347         }
348         table->state[elt] = GPT_STATE_CORRUPT;
349         if (crc32(buf, tblsz) != hdr->hdr_crc_table) {
350                 g_free(buf);
351                 return (NULL);
352         }
353
354         table->state[elt] = GPT_STATE_OK;
355         tbl = g_malloc(hdr->hdr_entries * sizeof(struct gpt_ent),
356             M_WAITOK | M_ZERO);
357
358         for (idx = 0, ent = tbl, p = buf;
359              idx < hdr->hdr_entries;
360              idx++, ent++, p += hdr->hdr_entsz) {
361                 le_uuid_dec(p, &ent->ent_type);
362                 le_uuid_dec(p + 16, &ent->ent_uuid);
363                 ent->ent_lba_start = le64dec(p + 32);
364                 ent->ent_lba_end = le64dec(p + 40);
365                 ent->ent_attr = le64dec(p + 48);
366                 /* Keep UTF-16 in little-endian. */
367                 bcopy(p + 56, ent->ent_name, sizeof(ent->ent_name));
368         }
369
370         g_free(buf);
371         return (tbl);
372 }
373
374 static int
375 gpt_matched_hdrs(struct gpt_hdr *pri, struct gpt_hdr *sec)
376 {
377
378         if (pri == NULL || sec == NULL)
379                 return (0);
380
381         if (!EQUUID(&pri->hdr_uuid, &sec->hdr_uuid))
382                 return (0);
383         return ((pri->hdr_revision == sec->hdr_revision &&
384             pri->hdr_size == sec->hdr_size &&
385             pri->hdr_lba_start == sec->hdr_lba_start &&
386             pri->hdr_lba_end == sec->hdr_lba_end &&
387             pri->hdr_entries == sec->hdr_entries &&
388             pri->hdr_entsz == sec->hdr_entsz &&
389             pri->hdr_crc_table == sec->hdr_crc_table) ? 1 : 0);
390 }
391
392 static int
393 gpt_parse_type(const char *type, struct uuid *uuid)
394 {
395         struct uuid tmp;
396         const char *alias;
397         int error;
398         struct g_part_uuid_alias *uap;
399
400         if (type[0] == '!') {
401                 error = parse_uuid(type + 1, &tmp);
402                 if (error)
403                         return (error);
404                 if (EQUUID(&tmp, &gpt_uuid_unused))
405                         return (EINVAL);
406                 *uuid = tmp;
407                 return (0);
408         }
409         for (uap = &gpt_uuid_alias_match[0]; uap->uuid; uap++) {
410                 alias = g_part_alias_name(uap->alias);
411                 if (!strcasecmp(type, alias)) {
412                         *uuid = *uap->uuid;
413                         return (0);
414                 }
415         }
416         return (EINVAL);
417 }
418
419 static int
420 g_part_gpt_add(struct g_part_table *basetable, struct g_part_entry *baseentry,
421     struct g_part_parms *gpp)
422 {
423         struct g_part_gpt_entry *entry;
424         int error;
425
426         entry = (struct g_part_gpt_entry *)baseentry;
427         error = gpt_parse_type(gpp->gpp_type, &entry->ent.ent_type);
428         if (error)
429                 return (error);
430         kern_uuidgen(&entry->ent.ent_uuid, 1);
431         entry->ent.ent_lba_start = baseentry->gpe_start;
432         entry->ent.ent_lba_end = baseentry->gpe_end;
433         if (baseentry->gpe_deleted) {
434                 entry->ent.ent_attr = 0;
435                 bzero(entry->ent.ent_name, sizeof(entry->ent.ent_name));
436         }
437         if (gpp->gpp_parms & G_PART_PARM_LABEL)
438                 g_gpt_utf8_to_utf16(gpp->gpp_label, entry->ent.ent_name,
439                     sizeof(entry->ent.ent_name) /
440                     sizeof(entry->ent.ent_name[0]));
441         return (0);
442 }
443
444 static int
445 g_part_gpt_bootcode(struct g_part_table *basetable, struct g_part_parms *gpp)
446 {
447         struct g_part_gpt_table *table;
448         size_t codesz;
449
450         codesz = DOSPARTOFF;
451         table = (struct g_part_gpt_table *)basetable;
452         bzero(table->mbr, codesz);
453         codesz = MIN(codesz, gpp->gpp_codesize);
454         if (codesz > 0)
455                 bcopy(gpp->gpp_codeptr, table->mbr, codesz);
456
457         /* Mark the PMBR active since some BIOS require it */
458         table->mbr[DOSPARTOFF] = 0x80;          /* status */
459         return (0);
460 }
461
462 static int
463 g_part_gpt_create(struct g_part_table *basetable, struct g_part_parms *gpp)
464 {
465         struct g_provider *pp;
466         struct g_part_gpt_table *table;
467         quad_t last;
468         size_t tblsz;
469
470         /* We don't nest, which means that our depth should be 0. */
471         if (basetable->gpt_depth != 0)
472                 return (ENXIO);
473
474         table = (struct g_part_gpt_table *)basetable;
475         pp = gpp->gpp_provider;
476         tblsz = (basetable->gpt_entries * sizeof(struct gpt_ent) +
477             pp->sectorsize - 1) / pp->sectorsize;
478         if (pp->sectorsize < MBRSIZE ||
479             pp->mediasize < (3 + 2 * tblsz + basetable->gpt_entries) *
480             pp->sectorsize)
481                 return (ENOSPC);
482
483         last = (pp->mediasize / pp->sectorsize) - 1;
484
485         le16enc(table->mbr + DOSMAGICOFFSET, DOSMAGIC);
486         table->mbr[DOSPARTOFF + 1] = 0x01;              /* shd */
487         table->mbr[DOSPARTOFF + 2] = 0x01;              /* ssect */
488         table->mbr[DOSPARTOFF + 3] = 0x00;              /* scyl */
489         table->mbr[DOSPARTOFF + 4] = 0xee;              /* typ */
490         table->mbr[DOSPARTOFF + 5] = 0xff;              /* ehd */
491         table->mbr[DOSPARTOFF + 6] = 0xff;              /* esect */
492         table->mbr[DOSPARTOFF + 7] = 0xff;              /* ecyl */
493         le32enc(table->mbr + DOSPARTOFF + 8, 1);        /* start */
494         le32enc(table->mbr + DOSPARTOFF + 12, MIN(last, UINT32_MAX));
495
496         /* Allocate space for the header */
497         table->hdr = g_malloc(sizeof(struct gpt_hdr), M_WAITOK | M_ZERO);
498
499         bcopy(GPT_HDR_SIG, table->hdr->hdr_sig, sizeof(table->hdr->hdr_sig));
500         table->hdr->hdr_revision = GPT_HDR_REVISION;
501         table->hdr->hdr_size = offsetof(struct gpt_hdr, padding);
502         kern_uuidgen(&table->hdr->hdr_uuid, 1);
503         table->hdr->hdr_entries = basetable->gpt_entries;
504         table->hdr->hdr_entsz = sizeof(struct gpt_ent);
505
506         g_gpt_set_defaults(basetable, pp);
507         return (0);
508 }
509
510 static int
511 g_part_gpt_destroy(struct g_part_table *basetable, struct g_part_parms *gpp)
512 {
513         struct g_part_gpt_table *table;
514         struct g_provider *pp;
515
516         table = (struct g_part_gpt_table *)basetable;
517         pp = LIST_FIRST(&basetable->gpt_gp->consumer)->provider;
518         g_free(table->hdr);
519         table->hdr = NULL;
520
521         /*
522          * Wipe the first 2 sectors to clear the partitioning. Wipe the last
523          * sector only if it has valid secondary header.
524          */
525         basetable->gpt_smhead |= 3;
526         if (table->state[GPT_ELT_SECHDR] == GPT_STATE_OK &&
527             table->lba[GPT_ELT_SECHDR] == pp->mediasize / pp->sectorsize - 1)
528                 basetable->gpt_smtail |= 1;
529         return (0);
530 }
531
532 static void
533 g_part_gpt_dumpconf(struct g_part_table *table, struct g_part_entry *baseentry, 
534     struct sbuf *sb, const char *indent)
535 {
536         struct g_part_gpt_entry *entry;
537  
538         entry = (struct g_part_gpt_entry *)baseentry;
539         if (indent == NULL) {
540                 /* conftxt: libdisk compatibility */
541                 sbuf_printf(sb, " xs GPT xt ");
542                 sbuf_printf_uuid(sb, &entry->ent.ent_type);
543         } else if (entry != NULL) {
544                 /* confxml: partition entry information */
545                 sbuf_printf(sb, "%s<label>", indent);
546                 g_gpt_printf_utf16(sb, entry->ent.ent_name,
547                     sizeof(entry->ent.ent_name) >> 1);
548                 sbuf_printf(sb, "</label>\n");
549                 if (entry->ent.ent_attr & GPT_ENT_ATTR_BOOTME)
550                         sbuf_printf(sb, "%s<attrib>bootme</attrib>\n", indent);
551                 if (entry->ent.ent_attr & GPT_ENT_ATTR_BOOTONCE) {
552                         sbuf_printf(sb, "%s<attrib>bootonce</attrib>\n",
553                             indent);
554                 }
555                 if (entry->ent.ent_attr & GPT_ENT_ATTR_BOOTFAILED) {
556                         sbuf_printf(sb, "%s<attrib>bootfailed</attrib>\n",
557                             indent);
558                 }
559                 sbuf_printf(sb, "%s<rawtype>", indent);
560                 sbuf_printf_uuid(sb, &entry->ent.ent_type);
561                 sbuf_printf(sb, "</rawtype>\n");
562                 sbuf_printf(sb, "%s<rawuuid>", indent);
563                 sbuf_printf_uuid(sb, &entry->ent.ent_uuid);
564                 sbuf_printf(sb, "</rawuuid>\n");
565         } else {
566                 /* confxml: scheme information */
567         }
568 }
569
570 static int
571 g_part_gpt_dumpto(struct g_part_table *table, struct g_part_entry *baseentry)  
572 {
573         struct g_part_gpt_entry *entry;
574
575         entry = (struct g_part_gpt_entry *)baseentry;
576         return ((EQUUID(&entry->ent.ent_type, &gpt_uuid_freebsd_swap) ||
577             EQUUID(&entry->ent.ent_type, &gpt_uuid_linux_swap)) ? 1 : 0);
578 }
579
580 static int
581 g_part_gpt_modify(struct g_part_table *basetable,
582     struct g_part_entry *baseentry, struct g_part_parms *gpp)
583 {
584         struct g_part_gpt_entry *entry;
585         int error;
586
587         entry = (struct g_part_gpt_entry *)baseentry;
588         if (gpp->gpp_parms & G_PART_PARM_TYPE) {
589                 error = gpt_parse_type(gpp->gpp_type, &entry->ent.ent_type);
590                 if (error)
591                         return (error);
592         }
593         if (gpp->gpp_parms & G_PART_PARM_LABEL)
594                 g_gpt_utf8_to_utf16(gpp->gpp_label, entry->ent.ent_name,
595                     sizeof(entry->ent.ent_name) /
596                     sizeof(entry->ent.ent_name[0]));
597         return (0);
598 }
599
600 static int
601 g_part_gpt_resize(struct g_part_table *basetable,
602     struct g_part_entry *baseentry, struct g_part_parms *gpp)
603 {
604         struct g_part_gpt_entry *entry;
605         entry = (struct g_part_gpt_entry *)baseentry;
606
607         baseentry->gpe_end = baseentry->gpe_start + gpp->gpp_size - 1;
608         entry->ent.ent_lba_end = baseentry->gpe_end;
609
610         return (0);
611 }
612
613 static const char *
614 g_part_gpt_name(struct g_part_table *table, struct g_part_entry *baseentry,
615     char *buf, size_t bufsz)
616 {
617         struct g_part_gpt_entry *entry;
618         char c;
619
620         entry = (struct g_part_gpt_entry *)baseentry;
621         c = (EQUUID(&entry->ent.ent_type, &gpt_uuid_freebsd)) ? 's' : 'p';
622         snprintf(buf, bufsz, "%c%d", c, baseentry->gpe_index);
623         return (buf);
624 }
625
626 static int
627 g_part_gpt_probe(struct g_part_table *table, struct g_consumer *cp)
628 {
629         struct g_provider *pp;
630         char *buf;
631         int error, res;
632
633         /* We don't nest, which means that our depth should be 0. */
634         if (table->gpt_depth != 0)
635                 return (ENXIO);
636
637         pp = cp->provider;
638
639         /*
640          * Sanity-check the provider. Since the first sector on the provider
641          * must be a PMBR and a PMBR is 512 bytes large, the sector size
642          * must be at least 512 bytes.  Also, since the theoretical minimum
643          * number of sectors needed by GPT is 6, any medium that has less
644          * than 6 sectors is never going to be able to hold a GPT. The
645          * number 6 comes from:
646          *      1 sector for the PMBR
647          *      2 sectors for the GPT headers (each 1 sector)
648          *      2 sectors for the GPT tables (each 1 sector)
649          *      1 sector for an actual partition
650          * It's better to catch this pathological case early than behaving
651          * pathologically later on...
652          */
653         if (pp->sectorsize < MBRSIZE || pp->mediasize < 6 * pp->sectorsize)
654                 return (ENOSPC);
655
656         /* Check that there's a MBR. */
657         buf = g_read_data(cp, 0L, pp->sectorsize, &error);
658         if (buf == NULL)
659                 return (error);
660         res = le16dec(buf + DOSMAGICOFFSET);
661         g_free(buf);
662         if (res != DOSMAGIC) 
663                 return (ENXIO);
664
665         /* Check that there's a primary header. */
666         buf = g_read_data(cp, pp->sectorsize, pp->sectorsize, &error);
667         if (buf == NULL)
668                 return (error);
669         res = memcmp(buf, GPT_HDR_SIG, 8);
670         g_free(buf);
671         if (res == 0)
672                 return (G_PART_PROBE_PRI_HIGH);
673
674         /* No primary? Check that there's a secondary. */
675         buf = g_read_data(cp, pp->mediasize - pp->sectorsize, pp->sectorsize,
676             &error);
677         if (buf == NULL)
678                 return (error);
679         res = memcmp(buf, GPT_HDR_SIG, 8); 
680         g_free(buf);
681         return ((res == 0) ? G_PART_PROBE_PRI_HIGH : ENXIO);
682 }
683
684 static int
685 g_part_gpt_read(struct g_part_table *basetable, struct g_consumer *cp)
686 {
687         struct gpt_hdr *prihdr, *sechdr;
688         struct gpt_ent *tbl, *pritbl, *sectbl;
689         struct g_provider *pp;
690         struct g_part_gpt_table *table;
691         struct g_part_gpt_entry *entry;
692         u_char *buf;
693         uint64_t last;
694         int error, index;
695
696         table = (struct g_part_gpt_table *)basetable;
697         pp = cp->provider;
698         last = (pp->mediasize / pp->sectorsize) - 1;
699
700         /* Read the PMBR */
701         buf = g_read_data(cp, 0, pp->sectorsize, &error);
702         if (buf == NULL)
703                 return (error);
704         bcopy(buf, table->mbr, MBRSIZE);
705         g_free(buf);
706
707         /* Read the primary header and table. */
708         prihdr = gpt_read_hdr(table, cp, GPT_ELT_PRIHDR);
709         if (table->state[GPT_ELT_PRIHDR] == GPT_STATE_OK) {
710                 pritbl = gpt_read_tbl(table, cp, GPT_ELT_PRITBL, prihdr);
711         } else {
712                 table->state[GPT_ELT_PRITBL] = GPT_STATE_MISSING;
713                 pritbl = NULL;
714         }
715
716         /* Read the secondary header and table. */
717         sechdr = gpt_read_hdr(table, cp, GPT_ELT_SECHDR);
718         if (table->state[GPT_ELT_SECHDR] == GPT_STATE_OK) {
719                 sectbl = gpt_read_tbl(table, cp, GPT_ELT_SECTBL, sechdr);
720         } else {
721                 table->state[GPT_ELT_SECTBL] = GPT_STATE_MISSING;
722                 sectbl = NULL;
723         }
724
725         /* Fail if we haven't got any good tables at all. */
726         if (table->state[GPT_ELT_PRITBL] != GPT_STATE_OK &&
727             table->state[GPT_ELT_SECTBL] != GPT_STATE_OK) {
728                 printf("GEOM: %s: corrupt or invalid GPT detected.\n",
729                     pp->name);
730                 printf("GEOM: %s: GPT rejected -- may not be recoverable.\n",
731                     pp->name);
732                 return (EINVAL);
733         }
734
735         /*
736          * If both headers are good but they disagree with each other,
737          * then invalidate one. We prefer to keep the primary header,
738          * unless the primary table is corrupt.
739          */
740         if (table->state[GPT_ELT_PRIHDR] == GPT_STATE_OK &&
741             table->state[GPT_ELT_SECHDR] == GPT_STATE_OK &&
742             !gpt_matched_hdrs(prihdr, sechdr)) {
743                 if (table->state[GPT_ELT_PRITBL] == GPT_STATE_OK) {
744                         table->state[GPT_ELT_SECHDR] = GPT_STATE_INVALID;
745                         table->state[GPT_ELT_SECTBL] = GPT_STATE_MISSING;
746                         g_free(sechdr);
747                         sechdr = NULL;
748                 } else {
749                         table->state[GPT_ELT_PRIHDR] = GPT_STATE_INVALID;
750                         table->state[GPT_ELT_PRITBL] = GPT_STATE_MISSING;
751                         g_free(prihdr);
752                         prihdr = NULL;
753                 }
754         }
755
756         if (table->state[GPT_ELT_PRITBL] != GPT_STATE_OK) {
757                 printf("GEOM: %s: the primary GPT table is corrupt or "
758                     "invalid.\n", pp->name);
759                 printf("GEOM: %s: using the secondary instead -- recovery "
760                     "strongly advised.\n", pp->name);
761                 table->hdr = sechdr;
762                 basetable->gpt_corrupt = 1;
763                 if (prihdr != NULL)
764                         g_free(prihdr);
765                 tbl = sectbl;
766                 if (pritbl != NULL)
767                         g_free(pritbl);
768         } else {
769                 if (table->state[GPT_ELT_SECTBL] != GPT_STATE_OK) {
770                         printf("GEOM: %s: the secondary GPT table is corrupt "
771                             "or invalid.\n", pp->name);
772                         printf("GEOM: %s: using the primary only -- recovery "
773                             "suggested.\n", pp->name);
774                         basetable->gpt_corrupt = 1;
775                 } else if (table->lba[GPT_ELT_SECHDR] != last) {
776                         printf( "GEOM: %s: the secondary GPT header is not in "
777                             "the last LBA.\n", pp->name);
778                         basetable->gpt_corrupt = 1;
779                 }
780                 table->hdr = prihdr;
781                 if (sechdr != NULL)
782                         g_free(sechdr);
783                 tbl = pritbl;
784                 if (sectbl != NULL)
785                         g_free(sectbl);
786         }
787
788         basetable->gpt_first = table->hdr->hdr_lba_start;
789         basetable->gpt_last = table->hdr->hdr_lba_end;
790         basetable->gpt_entries = table->hdr->hdr_entries;
791
792         for (index = basetable->gpt_entries - 1; index >= 0; index--) {
793                 if (EQUUID(&tbl[index].ent_type, &gpt_uuid_unused))
794                         continue;
795                 entry = (struct g_part_gpt_entry *)g_part_new_entry(
796                     basetable, index + 1, tbl[index].ent_lba_start,
797                     tbl[index].ent_lba_end);
798                 entry->ent = tbl[index];
799         }
800
801         g_free(tbl);
802         return (0);
803 }
804
805 static int
806 g_part_gpt_recover(struct g_part_table *basetable)
807 {
808
809         g_gpt_set_defaults(basetable,
810             LIST_FIRST(&basetable->gpt_gp->consumer)->provider);
811         basetable->gpt_corrupt = 0;
812         return (0);
813 }
814
815 static int
816 g_part_gpt_setunset(struct g_part_table *table, struct g_part_entry *baseentry,
817     const char *attrib, unsigned int set)
818 {
819         struct g_part_entry *iter;
820         struct g_part_gpt_entry *entry;
821         int changed, bootme, bootonce, bootfailed;
822
823         bootme = bootonce = bootfailed = 0;
824         if (strcasecmp(attrib, "bootme") == 0) {
825                 bootme = 1;
826         } else if (strcasecmp(attrib, "bootonce") == 0) {
827                 /* BOOTME is set automatically with BOOTONCE, but not unset. */
828                 bootonce = 1;
829                 if (set)
830                         bootme = 1;
831         } else if (strcasecmp(attrib, "bootfailed") == 0) {
832                 /*
833                  * It should only be possible to unset BOOTFAILED, but it might
834                  * be useful for test purposes to also be able to set it.
835                  */
836                 bootfailed = 1;
837         }
838         if (!bootme && !bootonce && !bootfailed)
839                 return (EINVAL);
840
841         LIST_FOREACH(iter, &table->gpt_entry, gpe_entry) {
842                 if (iter->gpe_deleted)
843                         continue;
844                 if (iter != baseentry)
845                         continue;
846                 changed = 0;
847                 entry = (struct g_part_gpt_entry *)iter;
848                 if (set) {
849                         if (bootme &&
850                             !(entry->ent.ent_attr & GPT_ENT_ATTR_BOOTME)) {
851                                 entry->ent.ent_attr |= GPT_ENT_ATTR_BOOTME;
852                                 changed = 1;
853                         }
854                         if (bootonce &&
855                             !(entry->ent.ent_attr & GPT_ENT_ATTR_BOOTONCE)) {
856                                 entry->ent.ent_attr |= GPT_ENT_ATTR_BOOTONCE;
857                                 changed = 1;
858                         }
859                         if (bootfailed &&
860                             !(entry->ent.ent_attr & GPT_ENT_ATTR_BOOTFAILED)) {
861                                 entry->ent.ent_attr |= GPT_ENT_ATTR_BOOTFAILED;
862                                 changed = 1;
863                         }
864                 } else {
865                         if (bootme &&
866                             (entry->ent.ent_attr & GPT_ENT_ATTR_BOOTME)) {
867                                 entry->ent.ent_attr &= ~GPT_ENT_ATTR_BOOTME;
868                                 changed = 1;
869                         }
870                         if (bootonce &&
871                             (entry->ent.ent_attr & GPT_ENT_ATTR_BOOTONCE)) {
872                                 entry->ent.ent_attr &= ~GPT_ENT_ATTR_BOOTONCE;
873                                 changed = 1;
874                         }
875                         if (bootfailed &&
876                             (entry->ent.ent_attr & GPT_ENT_ATTR_BOOTFAILED)) {
877                                 entry->ent.ent_attr &= ~GPT_ENT_ATTR_BOOTFAILED;
878                                 changed = 1;
879                         }
880                 }
881                 if (changed && !iter->gpe_created)
882                         iter->gpe_modified = 1;
883         }
884         return (0);
885 }
886
887 static const char *
888 g_part_gpt_type(struct g_part_table *basetable, struct g_part_entry *baseentry, 
889     char *buf, size_t bufsz)
890 {
891         struct g_part_gpt_entry *entry;
892         struct uuid *type;
893         struct g_part_uuid_alias *uap;
894  
895         entry = (struct g_part_gpt_entry *)baseentry;
896         type = &entry->ent.ent_type;
897         for (uap = &gpt_uuid_alias_match[0]; uap->uuid; uap++)
898                 if (EQUUID(type, uap->uuid))
899                         return (g_part_alias_name(uap->alias));
900         buf[0] = '!';
901         snprintf_uuid(buf + 1, bufsz - 1, type);
902
903         return (buf);
904 }
905
906 static int
907 g_part_gpt_write(struct g_part_table *basetable, struct g_consumer *cp)
908 {
909         unsigned char *buf, *bp;
910         struct g_provider *pp;
911         struct g_part_entry *baseentry;
912         struct g_part_gpt_entry *entry;
913         struct g_part_gpt_table *table;
914         size_t tblsz;
915         uint32_t crc;
916         int error, index;
917
918         pp = cp->provider;
919         table = (struct g_part_gpt_table *)basetable;
920         tblsz = (table->hdr->hdr_entries * table->hdr->hdr_entsz +
921             pp->sectorsize - 1) / pp->sectorsize;
922
923         /* Write the PMBR */
924         buf = g_malloc(pp->sectorsize, M_WAITOK | M_ZERO);
925         bcopy(table->mbr, buf, MBRSIZE);
926         error = g_write_data(cp, 0, buf, pp->sectorsize);
927         g_free(buf);
928         if (error)
929                 return (error);
930
931         /* Allocate space for the header and entries. */
932         buf = g_malloc((tblsz + 1) * pp->sectorsize, M_WAITOK | M_ZERO);
933
934         memcpy(buf, table->hdr->hdr_sig, sizeof(table->hdr->hdr_sig));
935         le32enc(buf + 8, table->hdr->hdr_revision);
936         le32enc(buf + 12, table->hdr->hdr_size);
937         le64enc(buf + 40, table->hdr->hdr_lba_start);
938         le64enc(buf + 48, table->hdr->hdr_lba_end);
939         le_uuid_enc(buf + 56, &table->hdr->hdr_uuid);
940         le32enc(buf + 80, table->hdr->hdr_entries);
941         le32enc(buf + 84, table->hdr->hdr_entsz);
942
943         LIST_FOREACH(baseentry, &basetable->gpt_entry, gpe_entry) {
944                 if (baseentry->gpe_deleted)
945                         continue;
946                 entry = (struct g_part_gpt_entry *)baseentry;
947                 index = baseentry->gpe_index - 1;
948                 bp = buf + pp->sectorsize + table->hdr->hdr_entsz * index;
949                 le_uuid_enc(bp, &entry->ent.ent_type);
950                 le_uuid_enc(bp + 16, &entry->ent.ent_uuid);
951                 le64enc(bp + 32, entry->ent.ent_lba_start);
952                 le64enc(bp + 40, entry->ent.ent_lba_end);
953                 le64enc(bp + 48, entry->ent.ent_attr);
954                 memcpy(bp + 56, entry->ent.ent_name,
955                     sizeof(entry->ent.ent_name));
956         }
957
958         crc = crc32(buf + pp->sectorsize,
959             table->hdr->hdr_entries * table->hdr->hdr_entsz);
960         le32enc(buf + 88, crc);
961
962         /* Write primary meta-data. */
963         le32enc(buf + 16, 0);   /* hdr_crc_self. */
964         le64enc(buf + 24, table->lba[GPT_ELT_PRIHDR]);  /* hdr_lba_self. */
965         le64enc(buf + 32, table->lba[GPT_ELT_SECHDR]);  /* hdr_lba_alt. */
966         le64enc(buf + 72, table->lba[GPT_ELT_PRITBL]);  /* hdr_lba_table. */
967         crc = crc32(buf, table->hdr->hdr_size);
968         le32enc(buf + 16, crc);
969
970         for (index = 0; index < tblsz; index += MAXPHYS / pp->sectorsize) {
971                 error = g_write_data(cp,
972                     (table->lba[GPT_ELT_PRITBL] + index) * pp->sectorsize,
973                     buf + (index + 1) * pp->sectorsize,
974                     (tblsz - index > MAXPHYS / pp->sectorsize) ? MAXPHYS:
975                     (tblsz - index) * pp->sectorsize);
976                 if (error)
977                         goto out;
978         }
979         error = g_write_data(cp, table->lba[GPT_ELT_PRIHDR] * pp->sectorsize,
980             buf, pp->sectorsize);
981         if (error)
982                 goto out;
983
984         /* Write secondary meta-data. */
985         le32enc(buf + 16, 0);   /* hdr_crc_self. */
986         le64enc(buf + 24, table->lba[GPT_ELT_SECHDR]);  /* hdr_lba_self. */
987         le64enc(buf + 32, table->lba[GPT_ELT_PRIHDR]);  /* hdr_lba_alt. */
988         le64enc(buf + 72, table->lba[GPT_ELT_SECTBL]);  /* hdr_lba_table. */
989         crc = crc32(buf, table->hdr->hdr_size);
990         le32enc(buf + 16, crc);
991
992         for (index = 0; index < tblsz; index += MAXPHYS / pp->sectorsize) {
993                 error = g_write_data(cp,
994                     (table->lba[GPT_ELT_SECTBL] + index) * pp->sectorsize,
995                     buf + (index + 1) * pp->sectorsize,
996                     (tblsz - index > MAXPHYS / pp->sectorsize) ? MAXPHYS:
997                     (tblsz - index) * pp->sectorsize);
998                 if (error)
999                         goto out;
1000         }
1001         error = g_write_data(cp, table->lba[GPT_ELT_SECHDR] * pp->sectorsize,
1002             buf, pp->sectorsize);
1003
1004  out:
1005         g_free(buf);
1006         return (error);
1007 }
1008
1009 static void
1010 g_gpt_set_defaults(struct g_part_table *basetable, struct g_provider *pp)
1011 {
1012         struct g_part_gpt_table *table;
1013         quad_t last;
1014         size_t tblsz;
1015
1016         table = (struct g_part_gpt_table *)basetable;
1017         last = pp->mediasize / pp->sectorsize - 1;
1018         tblsz = (basetable->gpt_entries * sizeof(struct gpt_ent) +
1019             pp->sectorsize - 1) / pp->sectorsize;
1020
1021         table->lba[GPT_ELT_PRIHDR] = 1;
1022         table->lba[GPT_ELT_PRITBL] = 2;
1023         table->lba[GPT_ELT_SECHDR] = last;
1024         table->lba[GPT_ELT_SECTBL] = last - tblsz;
1025         table->state[GPT_ELT_PRIHDR] = GPT_STATE_OK;
1026         table->state[GPT_ELT_PRITBL] = GPT_STATE_OK;
1027         table->state[GPT_ELT_SECHDR] = GPT_STATE_OK;
1028         table->state[GPT_ELT_SECTBL] = GPT_STATE_OK;
1029
1030         table->hdr->hdr_lba_start = 2 + tblsz;
1031         table->hdr->hdr_lba_end = last - tblsz - 1;
1032
1033         basetable->gpt_first = table->hdr->hdr_lba_start;
1034         basetable->gpt_last = table->hdr->hdr_lba_end;
1035 }
1036
1037 static void
1038 g_gpt_printf_utf16(struct sbuf *sb, uint16_t *str, size_t len)
1039 {
1040         u_int bo;
1041         uint32_t ch;
1042         uint16_t c;
1043
1044         bo = LITTLE_ENDIAN;     /* GPT is little-endian */
1045         while (len > 0 && *str != 0) {
1046                 ch = (bo == BIG_ENDIAN) ? be16toh(*str) : le16toh(*str);
1047                 str++, len--;
1048                 if ((ch & 0xf800) == 0xd800) {
1049                         if (len > 0) {
1050                                 c = (bo == BIG_ENDIAN) ? be16toh(*str)
1051                                     : le16toh(*str);
1052                                 str++, len--;
1053                         } else
1054                                 c = 0xfffd;
1055                         if ((ch & 0x400) == 0 && (c & 0xfc00) == 0xdc00) {
1056                                 ch = ((ch & 0x3ff) << 10) + (c & 0x3ff);
1057                                 ch += 0x10000;
1058                         } else
1059                                 ch = 0xfffd;
1060                 } else if (ch == 0xfffe) { /* BOM (U+FEFF) swapped. */
1061                         bo = (bo == BIG_ENDIAN) ? LITTLE_ENDIAN : BIG_ENDIAN;
1062                         continue;
1063                 } else if (ch == 0xfeff) /* BOM (U+FEFF) unswapped. */
1064                         continue;
1065
1066                 /* Write the Unicode character in UTF-8 */
1067                 if (ch < 0x80)
1068                         sbuf_printf(sb, "%c", ch);
1069                 else if (ch < 0x800)
1070                         sbuf_printf(sb, "%c%c", 0xc0 | (ch >> 6),
1071                             0x80 | (ch & 0x3f));
1072                 else if (ch < 0x10000)
1073                         sbuf_printf(sb, "%c%c%c", 0xe0 | (ch >> 12),
1074                             0x80 | ((ch >> 6) & 0x3f), 0x80 | (ch & 0x3f));
1075                 else if (ch < 0x200000)
1076                         sbuf_printf(sb, "%c%c%c%c", 0xf0 | (ch >> 18),
1077                             0x80 | ((ch >> 12) & 0x3f),
1078                             0x80 | ((ch >> 6) & 0x3f), 0x80 | (ch & 0x3f));
1079         }
1080 }
1081
1082 static void
1083 g_gpt_utf8_to_utf16(const uint8_t *s8, uint16_t *s16, size_t s16len)
1084 {
1085         size_t s16idx, s8idx;
1086         uint32_t utfchar;
1087         unsigned int c, utfbytes;
1088
1089         s8idx = s16idx = 0;
1090         utfchar = 0;
1091         utfbytes = 0;
1092         bzero(s16, s16len << 1);
1093         while (s8[s8idx] != 0 && s16idx < s16len) {
1094                 c = s8[s8idx++];
1095                 if ((c & 0xc0) != 0x80) {
1096                         /* Initial characters. */
1097                         if (utfbytes != 0) {
1098                                 /* Incomplete encoding of previous char. */
1099                                 s16[s16idx++] = htole16(0xfffd);
1100                         }
1101                         if ((c & 0xf8) == 0xf0) {
1102                                 utfchar = c & 0x07;
1103                                 utfbytes = 3;
1104                         } else if ((c & 0xf0) == 0xe0) {
1105                                 utfchar = c & 0x0f;
1106                                 utfbytes = 2;
1107                         } else if ((c & 0xe0) == 0xc0) {
1108                                 utfchar = c & 0x1f;
1109                                 utfbytes = 1;
1110                         } else {
1111                                 utfchar = c & 0x7f;
1112                                 utfbytes = 0;
1113                         }
1114                 } else {
1115                         /* Followup characters. */
1116                         if (utfbytes > 0) {
1117                                 utfchar = (utfchar << 6) + (c & 0x3f);
1118                                 utfbytes--;
1119                         } else if (utfbytes == 0)
1120                                 utfbytes = ~0;
1121                 }
1122                 /*
1123                  * Write the complete Unicode character as UTF-16 when we
1124                  * have all the UTF-8 charactars collected.
1125                  */
1126                 if (utfbytes == 0) {
1127                         /*
1128                          * If we need to write 2 UTF-16 characters, but
1129                          * we only have room for 1, then we truncate the
1130                          * string by writing a 0 instead.
1131                          */
1132                         if (utfchar >= 0x10000 && s16idx < s16len - 1) {
1133                                 s16[s16idx++] =
1134                                     htole16(0xd800 | ((utfchar >> 10) - 0x40));
1135                                 s16[s16idx++] =
1136                                     htole16(0xdc00 | (utfchar & 0x3ff));
1137                         } else
1138                                 s16[s16idx++] = (utfchar >= 0x10000) ? 0 :
1139                                     htole16(utfchar);
1140                 }
1141         }
1142         /*
1143          * If our input string was truncated, append an invalid encoding
1144          * character to the output string.
1145          */
1146         if (utfbytes != 0 && s16idx < s16len)
1147                 s16[s16idx++] = htole16(0xfffd);
1148 }