gpt.c revision 1.64 1 /*-
2 * Copyright (c) 2002 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 * CRC32 code derived from work by Gary S. Brown.
27 */
28
29 #if HAVE_NBTOOL_CONFIG_H
30 #include "nbtool_config.h"
31 #endif
32
33 #include <sys/cdefs.h>
34 #ifdef __FBSDID
35 __FBSDID("$FreeBSD: src/sbin/gpt/gpt.c,v 1.16 2006/07/07 02:44:23 marcel Exp $");
36 #endif
37 #ifdef __RCSID
38 __RCSID("$NetBSD: gpt.c,v 1.64 2015/12/06 00:39:26 christos Exp $");
39 #endif
40
41 #include <sys/param.h>
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <sys/ioctl.h>
45 #include <sys/bootblock.h>
46
47 #include <err.h>
48 #include <errno.h>
49 #include <fcntl.h>
50 #include <paths.h>
51 #include <stddef.h>
52 #include <stdarg.h>
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <string.h>
56 #include <unistd.h>
57 #include <ctype.h>
58
59 #include "map.h"
60 #include "gpt.h"
61 #include "gpt_private.h"
62
63 static uint32_t crc32_tab[] = {
64 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
65 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
66 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
67 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
68 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
69 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
70 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
71 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
72 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
73 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
74 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
75 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
76 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
77 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
78 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
79 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
80 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
81 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
82 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
83 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
84 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
85 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
86 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
87 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
88 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
89 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
90 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
91 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
92 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
93 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
94 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
95 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
96 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
97 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
98 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
99 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
100 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
101 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
102 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
103 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
104 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
105 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
106 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
107 };
108
109 uint32_t
110 crc32(const void *buf, size_t size)
111 {
112 const uint8_t *p;
113 uint32_t crc;
114
115 p = buf;
116 crc = ~0U;
117
118 while (size--)
119 crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
120
121 return crc ^ ~0U;
122 }
123
124 void
125 utf16_to_utf8(const uint16_t *s16, uint8_t *s8, size_t s8len)
126 {
127 size_t s8idx, s16idx, s16len;
128 uint32_t utfchar;
129 unsigned int c;
130
131 s16len = 0;
132 while (s16[s16len++] != 0)
133 continue;
134 s8idx = s16idx = 0;
135 while (s16idx < s16len) {
136 utfchar = le16toh(s16[s16idx++]);
137 if ((utfchar & 0xf800) == 0xd800) {
138 c = le16toh(s16[s16idx]);
139 if ((utfchar & 0x400) != 0 || (c & 0xfc00) != 0xdc00)
140 utfchar = 0xfffd;
141 else
142 s16idx++;
143 }
144 if (utfchar < 0x80) {
145 if (s8idx + 1 >= s8len)
146 break;
147 s8[s8idx++] = (uint8_t)utfchar;
148 } else if (utfchar < 0x800) {
149 if (s8idx + 2 >= s8len)
150 break;
151 s8[s8idx++] = (uint8_t)(0xc0 | (utfchar >> 6));
152 s8[s8idx++] = (uint8_t)(0x80 | (utfchar & 0x3f));
153 } else if (utfchar < 0x10000) {
154 if (s8idx + 3 >= s8len)
155 break;
156 s8[s8idx++] = (uint8_t)(0xe0 | (utfchar >> 12));
157 s8[s8idx++] = (uint8_t)(0x80 | ((utfchar >> 6) & 0x3f));
158 s8[s8idx++] = (uint8_t)(0x80 | (utfchar & 0x3f));
159 } else if (utfchar < 0x200000) {
160 if (s8idx + 4 >= s8len)
161 break;
162 s8[s8idx++] = (uint8_t)(0xf0 | (utfchar >> 18));
163 s8[s8idx++] = (uint8_t)(0x80 | ((utfchar >> 12) & 0x3f));
164 s8[s8idx++] = (uint8_t)(0x80 | ((utfchar >> 6) & 0x3f));
165 s8[s8idx++] = (uint8_t)(0x80 | (utfchar & 0x3f));
166 }
167 }
168 s8[s8idx] = 0;
169 }
170
171 void
172 utf8_to_utf16(const uint8_t *s8, uint16_t *s16, size_t s16len)
173 {
174 size_t s16idx, s8idx, s8len;
175 uint32_t utfchar = 0;
176 unsigned int c, utfbytes;
177
178 s8len = 0;
179 while (s8[s8len++] != 0)
180 ;
181 s8idx = s16idx = 0;
182 utfbytes = 0;
183 do {
184 c = s8[s8idx++];
185 if ((c & 0xc0) != 0x80) {
186 /* Initial characters. */
187 if (utfbytes != 0) {
188 /* Incomplete encoding. */
189 s16[s16idx++] = htole16(0xfffd);
190 if (s16idx == s16len) {
191 s16[--s16idx] = 0;
192 return;
193 }
194 }
195 if ((c & 0xf8) == 0xf0) {
196 utfchar = c & 0x07;
197 utfbytes = 3;
198 } else if ((c & 0xf0) == 0xe0) {
199 utfchar = c & 0x0f;
200 utfbytes = 2;
201 } else if ((c & 0xe0) == 0xc0) {
202 utfchar = c & 0x1f;
203 utfbytes = 1;
204 } else {
205 utfchar = c & 0x7f;
206 utfbytes = 0;
207 }
208 } else {
209 /* Followup characters. */
210 if (utfbytes > 0) {
211 utfchar = (utfchar << 6) + (c & 0x3f);
212 utfbytes--;
213 } else if (utfbytes == 0)
214 utfbytes = (u_int)~0;
215 }
216 if (utfbytes == 0) {
217 if (utfchar >= 0x10000 && s16idx + 2 >= s16len)
218 utfchar = 0xfffd;
219 if (utfchar >= 0x10000) {
220 s16[s16idx++] = htole16((uint16_t)
221 (0xd800 | ((utfchar>>10) - 0x40)));
222 s16[s16idx++] = htole16((uint16_t)
223 (0xdc00 | (utfchar & 0x3ff)));
224 } else
225 s16[s16idx++] = htole16((uint16_t)utfchar);
226 if (s16idx == s16len) {
227 s16[--s16idx] = 0;
228 return;
229 }
230 }
231 } while (c != 0);
232 }
233
234 void *
235 gpt_read(gpt_t gpt, off_t lba, size_t count)
236 {
237 off_t ofs;
238 void *buf;
239
240 count *= gpt->secsz;
241 buf = malloc(count);
242 if (buf == NULL)
243 return NULL;
244
245 ofs = lba * gpt->secsz;
246 if (lseek(gpt->fd, ofs, SEEK_SET) == ofs &&
247 read(gpt->fd, buf, count) == (ssize_t)count)
248 return buf;
249
250 free(buf);
251 return NULL;
252 }
253
254 int
255 gpt_write(gpt_t gpt, map_t map)
256 {
257 off_t ofs;
258 size_t count;
259
260 count = (size_t)(map->map_size * gpt->secsz);
261 ofs = map->map_start * gpt->secsz;
262 if (lseek(gpt->fd, ofs, SEEK_SET) != ofs ||
263 write(gpt->fd, map->map_data, count) != (ssize_t)count)
264 return -1;
265 gpt->flags |= GPT_MODIFIED;
266 return 0;
267 }
268
269 static int
270 gpt_mbr(gpt_t gpt, off_t lba)
271 {
272 struct mbr *mbr;
273 map_t m, p;
274 off_t size, start;
275 unsigned int i, pmbr;
276
277 mbr = gpt_read(gpt, lba, 1);
278 if (mbr == NULL) {
279 gpt_warn(gpt, "Read failed");
280 return -1;
281 }
282
283 if (mbr->mbr_sig != htole16(MBR_SIG)) {
284 if (gpt->verbose)
285 gpt_msg(gpt,
286 "MBR not found at sector %ju", (uintmax_t)lba);
287 free(mbr);
288 return 0;
289 }
290
291 /*
292 * Differentiate between a regular MBR and a PMBR. This is more
293 * convenient in general. A PMBR is one with a single partition
294 * of type 0xee.
295 */
296 pmbr = 0;
297 for (i = 0; i < 4; i++) {
298 if (mbr->mbr_part[i].part_typ == MBR_PTYPE_UNUSED)
299 continue;
300 if (mbr->mbr_part[i].part_typ == MBR_PTYPE_PMBR)
301 pmbr++;
302 else
303 break;
304 }
305 if (pmbr && i == 4 && lba == 0) {
306 if (pmbr != 1)
307 gpt_warnx(gpt, "Suspicious PMBR at sector %ju",
308 (uintmax_t)lba);
309 else if (gpt->verbose > 1)
310 gpt_msg(gpt, "PMBR at sector %ju", (uintmax_t)lba);
311 p = map_add(gpt, lba, 1LL, MAP_TYPE_PMBR, mbr, 1);
312 goto out;
313 }
314 if (pmbr)
315 gpt_warnx(gpt, "Suspicious MBR at sector %ju", (uintmax_t)lba);
316 else if (gpt->verbose > 1)
317 gpt_msg(gpt, "MBR at sector %ju", (uintmax_t)lba);
318
319 p = map_add(gpt, lba, 1LL, MAP_TYPE_MBR, mbr, 1);
320 if (p == NULL)
321 goto out;
322
323 for (i = 0; i < 4; i++) {
324 if (mbr->mbr_part[i].part_typ == MBR_PTYPE_UNUSED ||
325 mbr->mbr_part[i].part_typ == MBR_PTYPE_PMBR)
326 continue;
327 start = le16toh(mbr->mbr_part[i].part_start_hi);
328 start = (start << 16) + le16toh(mbr->mbr_part[i].part_start_lo);
329 size = le16toh(mbr->mbr_part[i].part_size_hi);
330 size = (size << 16) + le16toh(mbr->mbr_part[i].part_size_lo);
331 if (start == 0 && size == 0) {
332 gpt_warnx(gpt, "Malformed MBR at sector %ju",
333 (uintmax_t)lba);
334 continue;
335 }
336 /* start is relative to the offset of the MBR itself. */
337 start += lba;
338 if (gpt->verbose > 2)
339 gpt_msg(gpt, "MBR part: type=%d, start=%ju, size=%ju",
340 mbr->mbr_part[i].part_typ,
341 (uintmax_t)start, (uintmax_t)size);
342 if (mbr->mbr_part[i].part_typ != MBR_PTYPE_EXT_LBA) {
343 m = map_add(gpt, start, size, MAP_TYPE_MBR_PART, p, 0);
344 if (m == NULL)
345 return -1;
346 m->map_index = i + 1;
347 } else {
348 if (gpt_mbr(gpt, start) == -1)
349 return -1;
350 }
351 }
352 return 0;
353 out:
354 if (p == NULL) {
355 free(mbr);
356 return -1;
357 }
358 return 0;
359 }
360
361 int
362 gpt_gpt(gpt_t gpt, off_t lba, int found)
363 {
364 off_t size;
365 struct gpt_ent *ent;
366 struct gpt_hdr *hdr;
367 char *p;
368 map_t m;
369 size_t blocks, tblsz;
370 unsigned int i;
371 uint32_t crc;
372
373 hdr = gpt_read(gpt, lba, 1);
374 if (hdr == NULL)
375 return -1;
376
377 if (memcmp(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig)))
378 goto fail_hdr;
379
380 crc = le32toh(hdr->hdr_crc_self);
381 hdr->hdr_crc_self = 0;
382 if (crc32(hdr, le32toh(hdr->hdr_size)) != crc) {
383 if (gpt->verbose)
384 gpt_msg(gpt, "Bad CRC in GPT header at sector %ju",
385 (uintmax_t)lba);
386 goto fail_hdr;
387 }
388
389 tblsz = le32toh(hdr->hdr_entries) * le32toh(hdr->hdr_entsz);
390 blocks = tblsz / gpt->secsz + ((tblsz % gpt->secsz) ? 1 : 0);
391
392 /* Use generic pointer to deal with hdr->hdr_entsz != sizeof(*ent). */
393 p = gpt_read(gpt, (off_t)le64toh((uint64_t)hdr->hdr_lba_table), blocks);
394 if (p == NULL) {
395 if (found) {
396 if (gpt->verbose)
397 gpt_msg(gpt,
398 "Cannot read LBA table at sector %ju",
399 (uintmax_t)le64toh(hdr->hdr_lba_table));
400 return -1;
401 }
402 goto fail_hdr;
403 }
404
405 if (crc32(p, tblsz) != le32toh(hdr->hdr_crc_table)) {
406 if (gpt->verbose)
407 gpt_msg(gpt, "Bad CRC in GPT table at sector %ju",
408 (uintmax_t)le64toh(hdr->hdr_lba_table));
409 goto fail_ent;
410 }
411
412 if (gpt->verbose > 1)
413 gpt_msg(gpt, "%s GPT at sector %ju",
414 (lba == 1) ? "Pri" : "Sec", (uintmax_t)lba);
415
416 m = map_add(gpt, lba, 1, (lba == 1)
417 ? MAP_TYPE_PRI_GPT_HDR : MAP_TYPE_SEC_GPT_HDR, hdr, 1);
418 if (m == NULL)
419 return (-1);
420
421 m = map_add(gpt, (off_t)le64toh((uint64_t)hdr->hdr_lba_table),
422 (off_t)blocks,
423 lba == 1 ? MAP_TYPE_PRI_GPT_TBL : MAP_TYPE_SEC_GPT_TBL, p, 1);
424 if (m == NULL)
425 return (-1);
426
427 if (lba != 1)
428 return (1);
429
430 for (i = 0; i < le32toh(hdr->hdr_entries); i++) {
431 ent = (void*)(p + i * le32toh(hdr->hdr_entsz));
432 if (gpt_uuid_is_nil(ent->ent_type))
433 continue;
434
435 size = (off_t)(le64toh((uint64_t)ent->ent_lba_end) -
436 le64toh((uint64_t)ent->ent_lba_start) + 1LL);
437 if (gpt->verbose > 2) {
438 char buf[128];
439 gpt_uuid_snprintf(buf, sizeof(buf), "%s",
440 ent->ent_type);
441 gpt_msg(gpt, "GPT partition: type=%s, start=%ju, "
442 "size=%ju", buf,
443 (uintmax_t)le64toh(ent->ent_lba_start),
444 (uintmax_t)size);
445 }
446 m = map_add(gpt, (off_t)le64toh((uint64_t)ent->ent_lba_start),
447 size, MAP_TYPE_GPT_PART, ent, 0);
448 if (m == NULL)
449 return (-1);
450 m->map_index = i + 1;
451 }
452 return (1);
453
454 fail_ent:
455 free(p);
456
457 fail_hdr:
458 free(hdr);
459 return (0);
460 }
461
462 gpt_t
463 gpt_open(const char *dev, int flags, int verbose, off_t mediasz, u_int secsz)
464 {
465 int mode, found;
466 off_t devsz;
467 gpt_t gpt;
468
469
470 if ((gpt = calloc(1, sizeof(*gpt))) == NULL) {
471 if (!(flags & GPT_QUIET))
472 warn("Cannot allocate `%s'", dev);
473 return NULL;
474 }
475 gpt->flags = flags;
476 gpt->verbose = verbose;
477 gpt->mediasz = mediasz;
478 gpt->secsz = secsz;
479
480 mode = (gpt->flags & GPT_READONLY) ? O_RDONLY : O_RDWR|O_EXCL;
481
482 gpt->fd = opendisk(dev, mode, gpt->device_name,
483 sizeof(gpt->device_name), 0);
484 if (gpt->fd == -1) {
485 strlcpy(gpt->device_name, dev, sizeof(gpt->device_name));
486 gpt_warn(gpt, "Cannot open");
487 goto close;
488 }
489
490 if (fstat(gpt->fd, &gpt->sb) == -1) {
491 gpt_warn(gpt, "Cannot stat");
492 goto close;
493 }
494
495 if ((gpt->sb.st_mode & S_IFMT) != S_IFREG) {
496 if (gpt->secsz == 0) {
497 #ifdef DIOCGSECTORSIZE
498 if (ioctl(gpt->fd, DIOCGSECTORSIZE, &gpt->secsz) == -1) {
499 gpt_warn(gpt, "Cannot get sector size");
500 goto close;
501 }
502 #endif
503 if (gpt->secsz == 0) {
504 gpt_warnx(gpt, "Sector size can't be 0");
505 goto close;
506 }
507 }
508 if (gpt->mediasz == 0) {
509 #ifdef DIOCGMEDIASIZE
510 if (ioctl(gpt->fd, DIOCGMEDIASIZE, &gpt->mediasz) == -1) {
511 gpt_warn(gpt, "Cannot get media size");
512 goto close;
513 }
514 #endif
515 if (gpt->mediasz == 0) {
516 gpt_warnx(gpt, "Media size can't be 0");
517 goto close;
518 }
519 }
520 } else {
521 gpt->flags |= GPT_FILE;
522 if (gpt->secsz == 0)
523 gpt->secsz = 512; /* Fixed size for files. */
524 if (gpt->mediasz == 0) {
525 if (gpt->sb.st_size % gpt->secsz) {
526 errno = EINVAL;
527 goto close;
528 }
529 gpt->mediasz = gpt->sb.st_size;
530 }
531 gpt->flags |= GPT_NOSYNC;
532 }
533
534 /*
535 * We require an absolute minimum of 6 sectors. One for the MBR,
536 * 2 for the GPT header, 2 for the GPT table and one to hold some
537 * user data. Let's catch this extreme border case here so that
538 * we don't have to worry about it later.
539 */
540 devsz = gpt->mediasz / gpt->secsz;
541 if (devsz < 6) {
542 gpt_warnx(gpt, "Need 6 sectors, we have %ju",
543 (uintmax_t)devsz);
544 goto close;
545 }
546
547 if (gpt->verbose) {
548 gpt_msg(gpt, "mediasize=%ju; sectorsize=%u; blocks=%ju",
549 (uintmax_t)gpt->mediasz, gpt->secsz, (uintmax_t)devsz);
550 }
551
552 if (map_init(gpt, devsz) == -1)
553 goto close;
554
555 if (gpt_mbr(gpt, 0LL) == -1)
556 goto close;
557 if ((found = gpt_gpt(gpt, 1LL, 1)) == -1)
558 goto close;
559 if (gpt_gpt(gpt, devsz - 1LL, found) == -1)
560 goto close;
561
562 return gpt;
563
564 close:
565 if (gpt->fd != -1)
566 close(gpt->fd);
567 free(gpt);
568 return NULL;
569 }
570
571 void
572 gpt_close(gpt_t gpt)
573 {
574
575 if (!(gpt->flags & GPT_MODIFIED))
576 goto out;
577
578 if (!(gpt->flags & GPT_NOSYNC)) {
579 #ifdef DIOCMWEDGES
580 int bits;
581 if (ioctl(gpt->fd, DIOCMWEDGES, &bits) == -1)
582 gpt_warn(gpt, "Can't update wedge information");
583 else
584 goto out;
585 #endif
586 }
587 if (!(gpt->flags & GPT_FILE))
588 gpt_msg(gpt, "You need to run \"dkctl %s makewedges\""
589 " for the changes to take effect\n", gpt->device_name);
590
591 out:
592 close(gpt->fd);
593 }
594
595 void
596 gpt_warnx(gpt_t gpt, const char *fmt, ...)
597 {
598 va_list ap;
599
600 if (gpt->flags & GPT_QUIET)
601 return;
602 fprintf(stderr, "%s: %s: ", getprogname(), gpt->device_name);
603 va_start(ap, fmt);
604 vfprintf(stderr, fmt, ap);
605 va_end(ap);
606 fprintf(stderr, "\n");
607 }
608
609 void
610 gpt_warn(gpt_t gpt, const char *fmt, ...)
611 {
612 va_list ap;
613 int e = errno;
614
615 if (gpt->flags & GPT_QUIET)
616 return;
617 fprintf(stderr, "%s: %s: ", getprogname(), gpt->device_name);
618 va_start(ap, fmt);
619 vfprintf(stderr, fmt, ap);
620 va_end(ap);
621 fprintf(stderr, " (%s)\n", strerror(e));
622 errno = e;
623 }
624
625 void
626 gpt_msg(gpt_t gpt, const char *fmt, ...)
627 {
628 va_list ap;
629
630 if (gpt->flags & GPT_QUIET)
631 return;
632 printf("%s: ", gpt->device_name);
633 va_start(ap, fmt);
634 vprintf(fmt, ap);
635 va_end(ap);
636 printf("\n");
637 }
638
639 struct gpt_hdr *
640 gpt_hdr(gpt_t gpt)
641 {
642 gpt->gpt = map_find(gpt, MAP_TYPE_PRI_GPT_HDR);
643 if (gpt->gpt == NULL) {
644 gpt_warnx(gpt, "No primary GPT header; run create or recover");
645 return NULL;
646 }
647
648 gpt->tpg = map_find(gpt, MAP_TYPE_SEC_GPT_HDR);
649 if (gpt->tpg == NULL) {
650 gpt_warnx(gpt, "No secondary GPT header; run recover");
651 return NULL;
652 }
653
654 gpt->tbl = map_find(gpt, MAP_TYPE_PRI_GPT_TBL);
655 gpt->lbt = map_find(gpt, MAP_TYPE_SEC_GPT_TBL);
656 if (gpt->tbl == NULL || gpt->lbt == NULL) {
657 gpt_warnx(gpt, "Corrupt maps, run recover");
658 return NULL;
659 }
660
661 return gpt->gpt->map_data;
662 }
663
664 int
665 gpt_write_crc(gpt_t gpt, map_t map, map_t tbl)
666 {
667 struct gpt_hdr *hdr = map->map_data;
668
669 hdr->hdr_crc_table = htole32(crc32(tbl->map_data,
670 le32toh(hdr->hdr_entries) * le32toh(hdr->hdr_entsz)));
671 hdr->hdr_crc_self = 0;
672 hdr->hdr_crc_self = htole32(crc32(hdr, le32toh(hdr->hdr_size)));
673
674 if (gpt_write(gpt, map) == -1) {
675 gpt_warn(gpt, "Error writing crc map");
676 return -1;
677 }
678
679 if (gpt_write(gpt, tbl) == -1) {
680 gpt_warn(gpt, "Error writing crc table");
681 return -1;
682 }
683
684 return 0;
685 }
686
687 int
688 gpt_write_primary(gpt_t gpt)
689 {
690 return gpt_write_crc(gpt, gpt->gpt, gpt->tbl);
691 }
692
693
694 int
695 gpt_write_backup(gpt_t gpt)
696 {
697 return gpt_write_crc(gpt, gpt->tpg, gpt->lbt);
698 }
699
700 void
701 gpt_create_pmbr_part(struct mbr_part *part, off_t last)
702 {
703 part->part_shd = 0x00;
704 part->part_ssect = 0x02;
705 part->part_scyl = 0x00;
706 part->part_typ = MBR_PTYPE_PMBR;
707 part->part_ehd = 0xfe;
708 part->part_esect = 0xff;
709 part->part_ecyl = 0xff;
710 part->part_start_lo = htole16(1);
711 if (last > 0xffffffff) {
712 part->part_size_lo = htole16(0xffff);
713 part->part_size_hi = htole16(0xffff);
714 } else {
715 part->part_size_lo = htole16((uint16_t)last);
716 part->part_size_hi = htole16((uint16_t)(last >> 16));
717 }
718 }
719
720 struct gpt_ent *
721 gpt_ent(map_t map, map_t tbl, unsigned int i)
722 {
723 struct gpt_hdr *hdr = map->map_data;
724 return (void *)((char *)tbl->map_data + i * le32toh(hdr->hdr_entsz));
725 }
726
727 struct gpt_ent *
728 gpt_ent_primary(gpt_t gpt, unsigned int i)
729 {
730 return gpt_ent(gpt->gpt, gpt->tbl, i);
731 }
732
733 struct gpt_ent *
734 gpt_ent_backup(gpt_t gpt, unsigned int i)
735 {
736 return gpt_ent(gpt->tpg, gpt->lbt, i);
737 }
738
739 int
740 gpt_usage(const char *prefix, const struct gpt_cmd *cmd)
741 {
742 const char **a = cmd->help;
743 size_t hlen = cmd->hlen;
744 size_t i;
745
746 if (prefix == NULL) {
747 const char *pname = getprogname();
748 const char *d1, *d2, *d = " <device>";
749 int len = (int)strlen(pname);
750 if (strcmp(pname, "gpt") == 0) {
751 d1 = "";
752 d2 = d;
753 } else {
754 d2 = "";
755 d1 = d;
756 }
757 fprintf(stderr, "Usage: %s%s %s %s%s\n", pname,
758 d1, cmd->name, a[0], d2);
759 for (i = 1; i < hlen; i++) {
760 fprintf(stderr,
761 " %*s%s %s %s%s\n", len, "",
762 d1, cmd->name, a[i], d2);
763 }
764 } else {
765 for (i = 0; i < hlen; i++)
766 fprintf(stderr, "%s%s %s\n", prefix, cmd->name, a[i]);
767 }
768 return -1;
769 }
770
771 off_t
772 gpt_last(gpt_t gpt)
773 {
774 return gpt->mediasz / gpt->secsz - 1LL;
775 }
776
777 off_t
778 gpt_create(gpt_t gpt, off_t last, u_int parts, int primary_only)
779 {
780 off_t blocks;
781 map_t map;
782 struct gpt_hdr *hdr;
783 struct gpt_ent *ent;
784 unsigned int i;
785 void *p;
786
787 if (map_find(gpt, MAP_TYPE_PRI_GPT_HDR) != NULL ||
788 map_find(gpt, MAP_TYPE_SEC_GPT_HDR) != NULL) {
789 gpt_warnx(gpt, "Device already contains a GPT");
790 return -1;
791 }
792
793 /* Get the amount of free space after the MBR */
794 blocks = map_free(gpt, 1LL, 0LL);
795 if (blocks == 0LL) {
796 gpt_warnx(gpt, "No room for the GPT header");
797 return -1;
798 }
799
800 /* Don't create more than parts entries. */
801 if ((uint64_t)(blocks - 1) * gpt->secsz >
802 parts * sizeof(struct gpt_ent)) {
803 blocks = (off_t)((parts * sizeof(struct gpt_ent)) / gpt->secsz);
804 if ((parts * sizeof(struct gpt_ent)) % gpt->secsz)
805 blocks++;
806 blocks++; /* Don't forget the header itself */
807 }
808
809 /* Never cross the median of the device. */
810 if ((blocks + 1LL) > ((last + 1LL) >> 1))
811 blocks = ((last + 1LL) >> 1) - 1LL;
812
813 /*
814 * Get the amount of free space at the end of the device and
815 * calculate the size for the GPT structures.
816 */
817 map = map_last(gpt);
818 if (map->map_type != MAP_TYPE_UNUSED) {
819 gpt_warnx(gpt, "No room for the backup header");
820 return -1;
821 }
822
823 if (map->map_size < blocks)
824 blocks = map->map_size;
825 if (blocks == 1LL) {
826 gpt_warnx(gpt, "No room for the GPT table");
827 return -1;
828 }
829
830 blocks--; /* Number of blocks in the GPT table. */
831
832 if (gpt_add_hdr(gpt, MAP_TYPE_PRI_GPT_HDR, 1) == -1)
833 return -1;
834
835 if ((p = calloc((size_t)blocks, gpt->secsz)) == NULL) {
836 gpt_warnx(gpt, "Can't allocate the primary GPT table");
837 return -1;
838 }
839 if ((gpt->tbl = map_add(gpt, 2LL, blocks,
840 MAP_TYPE_PRI_GPT_TBL, p, 1)) == NULL) {
841 free(p);
842 gpt_warnx(gpt, "Can't add the primary GPT table");
843 return -1;
844 }
845
846 hdr = gpt->gpt->map_data;
847 memcpy(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig));
848
849 /*
850 * XXX struct gpt_hdr is not a multiple of 8 bytes in size and thus
851 * contains padding we must not include in the size.
852 */
853 hdr->hdr_revision = htole32(GPT_HDR_REVISION);
854 hdr->hdr_size = htole32(GPT_HDR_SIZE);
855 hdr->hdr_lba_self = htole64((uint64_t)gpt->gpt->map_start);
856 hdr->hdr_lba_alt = htole64((uint64_t)last);
857 hdr->hdr_lba_start = htole64((uint64_t)(gpt->tbl->map_start + blocks));
858 hdr->hdr_lba_end = htole64((uint64_t)(last - blocks - 1LL));
859 if (gpt_uuid_generate(gpt, hdr->hdr_guid) == -1)
860 return -1;
861 hdr->hdr_lba_table = htole64((uint64_t)(gpt->tbl->map_start));
862 hdr->hdr_entries = htole32((uint32_t)(((uint64_t)blocks * gpt->secsz) /
863 sizeof(struct gpt_ent)));
864 if (le32toh(hdr->hdr_entries) > parts)
865 hdr->hdr_entries = htole32(parts);
866 hdr->hdr_entsz = htole32(sizeof(struct gpt_ent));
867
868 ent = gpt->tbl->map_data;
869 for (i = 0; i < le32toh(hdr->hdr_entries); i++) {
870 if (gpt_uuid_generate(gpt, ent[i].ent_guid) == -1)
871 return -1;
872 }
873
874 /*
875 * Create backup GPT if the user didn't suppress it.
876 */
877 if (primary_only)
878 return last;
879
880 if (gpt_add_hdr(gpt, MAP_TYPE_SEC_GPT_HDR, last) == -1)
881 return -1;
882
883 if ((gpt->lbt = map_add(gpt, last - blocks, blocks,
884 MAP_TYPE_SEC_GPT_TBL, gpt->tbl->map_data, 0)) == NULL) {
885 gpt_warnx(gpt, "Can't add the secondary GPT table");
886 return -1;
887 }
888
889 memcpy(gpt->tpg->map_data, gpt->gpt->map_data, gpt->secsz);
890
891 hdr = gpt->tpg->map_data;
892 hdr->hdr_lba_self = htole64((uint64_t)gpt->tpg->map_start);
893 hdr->hdr_lba_alt = htole64((uint64_t)gpt->gpt->map_start);
894 hdr->hdr_lba_table = htole64((uint64_t)gpt->lbt->map_start);
895 return last;
896 }
897
898 static int
899 gpt_size_get(gpt_t gpt, off_t *size)
900 {
901 off_t sectors;
902 int64_t human_num;
903 char *p;
904
905 if (*size > 0)
906 return -1;
907 sectors = strtoll(optarg, &p, 10);
908 if (sectors < 1)
909 return -1;
910 if (*p == '\0' || ((*p == 's' || *p == 'S') && p[1] == '\0')) {
911 *size = sectors * gpt->secsz;
912 return 0;
913 }
914 if ((*p == 'b' || *p == 'B') && p[1] == '\0') {
915 *size = sectors;
916 return 0;
917 }
918 if (dehumanize_number(optarg, &human_num) < 0)
919 return -1;
920 *size = human_num;
921 return 0;
922 }
923
924 int
925 gpt_human_get(off_t *human)
926 {
927 int64_t human_num;
928
929 if (*human > 0)
930 return -1;
931 if (dehumanize_number(optarg, &human_num) < 0)
932 return -1;
933 *human = human_num;
934 if (*human < 1)
935 return -1;
936 return 0;
937 }
938
939 int
940 gpt_add_find(gpt_t gpt, struct gpt_find *find, int ch)
941 {
942 switch (ch) {
943 case 'a':
944 if (find->all > 0)
945 return -1;
946 find->all = 1;
947 break;
948 case 'b':
949 if (gpt_human_get(&find->block) == -1)
950 return -1;
951 break;
952 case 'i':
953 if (gpt_uint_get(&find->entry) == -1)
954 return -1;
955 break;
956 case 'L':
957 if (gpt_name_get(gpt, &find->label) == -1)
958 return -1;
959 break;
960 case 's':
961 if (gpt_size_get(gpt, &find->size) == -1)
962 return -1;
963 break;
964 case 't':
965 if (!gpt_uuid_is_nil(find->type))
966 return -1;
967 if (gpt_uuid_parse(optarg, find->type) != 0)
968 return -1;
969 break;
970 default:
971 return -1;
972 }
973 return 0;
974 }
975
976 int
977 gpt_change_ent(gpt_t gpt, const struct gpt_find *find,
978 void (*cfn)(struct gpt_ent *, void *), void *v)
979 {
980 map_t m;
981 struct gpt_hdr *hdr;
982 struct gpt_ent *ent;
983 unsigned int i;
984 uint8_t utfbuf[__arraycount(ent->ent_name) * 3 + 1];
985
986 if (!find->all ^
987 (find->block > 0 || find->entry > 0 || find->label != NULL
988 || find->size > 0 || !gpt_uuid_is_nil(find->type)))
989 return -1;
990
991 if ((hdr = gpt_hdr(gpt)) == NULL)
992 return -1;
993
994 /* Relabel all matching entries in the map. */
995 for (m = map_first(gpt); m != NULL; m = m->map_next) {
996 if (m->map_type != MAP_TYPE_GPT_PART || m->map_index < 1)
997 continue;
998 if (find->entry > 0 && find->entry != m->map_index)
999 continue;
1000 if (find->block > 0 && find->block != m->map_start)
1001 continue;
1002 if (find->size > 0 && find->size != m->map_size)
1003 continue;
1004
1005 i = m->map_index - 1;
1006
1007 ent = gpt_ent_primary(gpt, i);
1008 if (find->label != NULL) {
1009 utf16_to_utf8(ent->ent_name, utfbuf, sizeof(utfbuf));
1010 if (strcmp((char *)find->label, (char *)utfbuf) == 0)
1011 continue;
1012 }
1013
1014 if (!gpt_uuid_is_nil(find->type) &&
1015 !gpt_uuid_equal(find->type, ent->ent_type))
1016 continue;
1017
1018 /* Change the primary entry. */
1019 (*cfn)(ent, v);
1020
1021 if (gpt_write_primary(gpt) == -1)
1022 return -1;
1023
1024 ent = gpt_ent_backup(gpt, i);
1025 /* Change the secondary entry. */
1026 (*cfn)(ent, v);
1027
1028 if (gpt_write_backup(gpt) == -1)
1029 return -1;
1030
1031 gpt_msg(gpt, "Partition %d %s", m->map_index, find->msg);
1032 }
1033 return 0;
1034 }
1035
1036 int
1037 gpt_add_ais(gpt_t gpt, off_t *alignment, u_int *entry, off_t *size, int ch)
1038 {
1039 switch (ch) {
1040 case 'a':
1041 if (gpt_human_get(alignment) == -1)
1042 return -1;
1043 return 0;
1044 case 'i':
1045 if (gpt_uint_get(entry) == -1)
1046 return -1;
1047 return 0;
1048 case 's':
1049 if (gpt_size_get(gpt, size) == -1)
1050 return -1;
1051 return 0;
1052 default:
1053 return -1;
1054 }
1055 }
1056
1057 off_t
1058 gpt_check_ais(gpt_t gpt, off_t alignment, u_int entry, off_t size)
1059 {
1060 if (entry == 0) {
1061 gpt_warnx(gpt, "Entry not specified");
1062 return -1;
1063 }
1064 if (alignment % gpt->secsz != 0) {
1065 gpt_warnx(gpt, "Alignment (%#jx) must be a multiple of "
1066 "sector size (%#x)", (uintmax_t)alignment, gpt->secsz);
1067 return -1;
1068 }
1069
1070 if (size % gpt->secsz != 0) {
1071 gpt_warnx(gpt, "Size (%#jx) must be a multiple of "
1072 "sector size (%#x)", (uintmax_t)size, gpt->secsz);
1073 return -1;
1074 }
1075 if (size > 0)
1076 return size / gpt->secsz;
1077 return 0;
1078 }
1079
1080 static const struct nvd {
1081 const char *name;
1082 uint64_t mask;
1083 const char *description;
1084 } gpt_attr[] = {
1085 {
1086 "biosboot",
1087 GPT_ENT_ATTR_LEGACY_BIOS_BOOTABLE,
1088 "Legacy BIOS boot partition",
1089 },
1090 {
1091 "bootme",
1092 GPT_ENT_ATTR_BOOTME,
1093 "Bootable partition",
1094 },
1095 {
1096 "bootfailed",
1097 GPT_ENT_ATTR_BOOTFAILED,
1098 "Partition that marked bootonce failed to boot",
1099 },
1100 {
1101 "bootonce",
1102 GPT_ENT_ATTR_BOOTONCE,
1103 "Attempt to boot this partition only once",
1104 },
1105 {
1106 "noblockio",
1107 GPT_ENT_ATTR_NO_BLOCK_IO_PROTOCOL,
1108 "UEFI won't recognize file system for block I/O",
1109 },
1110 {
1111 "required",
1112 GPT_ENT_ATTR_REQUIRED_PARTITION,
1113 "Partition required for platform to function",
1114 },
1115 };
1116
1117 int
1118 gpt_attr_get(gpt_t gpt, uint64_t *attributes)
1119 {
1120 size_t i;
1121 int rv = 0;
1122 char *ptr;
1123
1124 *attributes = 0;
1125
1126 for (ptr = strtok(optarg, ","); ptr; ptr = strtok(NULL, ",")) {
1127 for (i = 0; i < __arraycount(gpt_attr); i++)
1128 if (strcmp(gpt_attr[i].name, ptr) == 0)
1129 break;
1130 if (i == __arraycount(gpt_attr)) {
1131 gpt_warnx(gpt, "Unregognized attribute `%s'", ptr);
1132 rv = -1;
1133 } else
1134 *attributes |= gpt_attr[i].mask;
1135 }
1136 return rv;
1137 }
1138
1139 void
1140 gpt_attr_help(const char *prefix)
1141 {
1142 size_t i;
1143
1144 for (i = 0; i < __arraycount(gpt_attr); i++)
1145 printf("%s%10.10s\t%s\n", prefix, gpt_attr[i].name,
1146 gpt_attr[i].description);
1147 }
1148
1149 const char *
1150 gpt_attr_list(char *buf, size_t len, uint64_t attributes)
1151 {
1152 size_t i;
1153 strlcpy(buf, "", len);
1154
1155 for (i = 0; i < __arraycount(gpt_attr); i++)
1156 if (attributes & gpt_attr[i].mask) {
1157 strlcat(buf, buf[0] ? "," : "", len);
1158 strlcat(buf, gpt_attr[i].name, len);
1159 }
1160 return buf;
1161 }
1162
1163 int
1164 gpt_attr_update(gpt_t gpt, u_int entry, uint64_t set, uint64_t clr)
1165 {
1166 struct gpt_hdr *hdr;
1167 struct gpt_ent *ent;
1168 unsigned int i;
1169
1170 if (entry == 0 || (set == 0 && clr == 0))
1171 return -1;
1172
1173 if ((hdr = gpt_hdr(gpt)) == NULL)
1174 return -1;
1175
1176 if (entry > le32toh(hdr->hdr_entries)) {
1177 gpt_warnx(gpt, "Index %u out of range (%u max)",
1178 entry, le32toh(hdr->hdr_entries));
1179 return -1;
1180 }
1181
1182 i = entry - 1;
1183 ent = gpt_ent_primary(gpt, i);
1184 if (gpt_uuid_is_nil(ent->ent_type)) {
1185 gpt_warnx(gpt, "Entry at index %u is unused", entry);
1186 return -1;
1187 }
1188
1189 ent->ent_attr &= ~clr;
1190 ent->ent_attr |= set;
1191
1192 if (gpt_write_primary(gpt) == -1)
1193 return -1;
1194
1195 ent = gpt_ent_backup(gpt, i);
1196 ent->ent_attr &= ~clr;
1197 ent->ent_attr |= set;
1198
1199 if (gpt_write_backup(gpt) == -1)
1200 return -1;
1201 gpt_msg(gpt, "Partition %d attributes updated", entry);
1202 return 0;
1203 }
1204
1205 int
1206 gpt_uint_get(u_int *entry)
1207 {
1208 char *p;
1209 if (*entry > 0)
1210 return -1;
1211 *entry = (u_int)strtoul(optarg, &p, 10);
1212 if (*p != 0 || *entry < 1)
1213 return -1;
1214 return 0;
1215 }
1216 int
1217 gpt_uuid_get(gpt_t gpt, gpt_uuid_t *uuid)
1218 {
1219 if (!gpt_uuid_is_nil(*uuid))
1220 return -1;
1221 if (gpt_uuid_parse(optarg, *uuid) != 0) {
1222 gpt_warn(gpt, "Can't parse uuid");
1223 return -1;
1224 }
1225 return 0;
1226 }
1227
1228 int
1229 gpt_name_get(gpt_t gpt, void *v)
1230 {
1231 char **name = v;
1232 if (*name != NULL)
1233 return -1;
1234 *name = strdup(optarg);
1235 if (*name == NULL) {
1236 gpt_warn(gpt, "Can't copy string");
1237 return -1;
1238 }
1239 return 0;
1240 }
1241
1242 void
1243 gpt_show_num(const char *prompt, uintmax_t num)
1244 {
1245 #ifdef HN_AUTOSCALE
1246 char human_num[5];
1247 if (humanize_number(human_num, 5, (int64_t)num ,
1248 "", HN_AUTOSCALE, HN_NOSPACE|HN_B) < 0)
1249 human_num[0] = '\0';
1250 #endif
1251 printf("%s: %ju", prompt, num);
1252 #ifdef HN_AUTOSCALE
1253 if (human_num[0] != '\0')
1254 printf(" (%s)", human_num);
1255 #endif
1256 printf("\n");
1257 }
1258
1259 int
1260 gpt_add_hdr(gpt_t gpt, int type, off_t loc)
1261 {
1262 void *p;
1263 map_t *t;
1264 const char *msg;
1265
1266 switch (type) {
1267 case MAP_TYPE_PRI_GPT_HDR:
1268 t = &gpt->gpt;
1269 msg = "primary";
1270 break;
1271 case MAP_TYPE_SEC_GPT_HDR:
1272 t = &gpt->tpg;
1273 msg = "secondary";
1274 break;
1275 default:
1276 gpt_warnx(gpt, "Unknown GPT header type %d", type);
1277 return -1;
1278 }
1279
1280 if ((p = calloc(1, gpt->secsz)) == NULL) {
1281 gpt_warn(gpt, "Error allocating %s GPT header", msg);
1282 return -1;
1283 }
1284
1285 *t = map_add(gpt, loc, 1LL, type, p, 1);
1286 if (*t == NULL) {
1287 gpt_warn(gpt, "Error adding %s GPT header", msg);
1288 free(p);
1289 return -1;
1290 }
1291 return 0;
1292 }
1293