gpt.c revision 1.58 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.58 2015/12/02 20:09:33 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++] = utfchar;
148 } else if (utfchar < 0x800) {
149 if (s8idx + 2 >= s8len)
150 break;
151 s8[s8idx++] = 0xc0 | (utfchar >> 6);
152 s8[s8idx++] = 0x80 | (utfchar & 0x3f);
153 } else if (utfchar < 0x10000) {
154 if (s8idx + 3 >= s8len)
155 break;
156 s8[s8idx++] = 0xe0 | (utfchar >> 12);
157 s8[s8idx++] = 0x80 | ((utfchar >> 6) & 0x3f);
158 s8[s8idx++] = 0x80 | (utfchar & 0x3f);
159 } else if (utfchar < 0x200000) {
160 if (s8idx + 4 >= s8len)
161 break;
162 s8[s8idx++] = 0xf0 | (utfchar >> 18);
163 s8[s8idx++] = 0x80 | ((utfchar >> 12) & 0x3f);
164 s8[s8idx++] = 0x80 | ((utfchar >> 6) & 0x3f);
165 s8[s8idx++] = 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 = -1;
215 }
216 if (utfbytes == 0) {
217 if (utfchar >= 0x10000 && s16idx + 2 >= s16len)
218 utfchar = 0xfffd;
219 if (utfchar >= 0x10000) {
220 s16[s16idx++] =
221 htole16(0xd800 | ((utfchar>>10)-0x40));
222 s16[s16idx++] =
223 htole16(0xdc00 | (utfchar & 0x3ff));
224 } else
225 s16[s16idx++] = htole16(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 = 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);
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);
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 // XXX: map add with non-allocated memory
344 m = map_add(gpt, start, size, MAP_TYPE_MBR_PART, p);
345 if (m == NULL)
346 return -1;
347 m->map_index = i + 1;
348 } else {
349 if (gpt_mbr(gpt, start) == -1)
350 return -1;
351 }
352 }
353 return 0;
354 out:
355 if (p == NULL) {
356 free(mbr);
357 return -1;
358 }
359 return 0;
360 }
361
362 int
363 gpt_gpt(gpt_t gpt, off_t lba, int found)
364 {
365 off_t size;
366 struct gpt_ent *ent;
367 struct gpt_hdr *hdr;
368 char *p;
369 map_t m;
370 size_t blocks, tblsz;
371 unsigned int i;
372 uint32_t crc;
373
374 hdr = gpt_read(gpt, lba, 1);
375 if (hdr == NULL)
376 return -1;
377
378 if (memcmp(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig)))
379 goto fail_hdr;
380
381 crc = le32toh(hdr->hdr_crc_self);
382 hdr->hdr_crc_self = 0;
383 if (crc32(hdr, le32toh(hdr->hdr_size)) != crc) {
384 if (gpt->verbose)
385 gpt_msg(gpt, "Bad CRC in GPT header at sector %ju",
386 (uintmax_t)lba);
387 goto fail_hdr;
388 }
389
390 tblsz = le32toh(hdr->hdr_entries) * le32toh(hdr->hdr_entsz);
391 blocks = tblsz / gpt->secsz + ((tblsz % gpt->secsz) ? 1 : 0);
392
393 /* Use generic pointer to deal with hdr->hdr_entsz != sizeof(*ent). */
394 p = gpt_read(gpt, le64toh(hdr->hdr_lba_table), blocks);
395 if (p == NULL) {
396 if (found) {
397 if (gpt->verbose)
398 gpt_msg(gpt,
399 "Cannot read LBA table at sector %ju",
400 (uintmax_t)le64toh(hdr->hdr_lba_table));
401 return -1;
402 }
403 goto fail_hdr;
404 }
405
406 if (crc32(p, tblsz) != le32toh(hdr->hdr_crc_table)) {
407 if (gpt->verbose)
408 gpt_msg(gpt, "Bad CRC in GPT table at sector %ju",
409 (uintmax_t)le64toh(hdr->hdr_lba_table));
410 goto fail_ent;
411 }
412
413 if (gpt->verbose > 1)
414 gpt_msg(gpt, "%s GPT at sector %ju",
415 (lba == 1) ? "Pri" : "Sec", (uintmax_t)lba);
416
417 m = map_add(gpt, lba, 1, (lba == 1)
418 ? MAP_TYPE_PRI_GPT_HDR : MAP_TYPE_SEC_GPT_HDR, hdr);
419 if (m == NULL)
420 return (-1);
421
422 m = map_add(gpt, le64toh(hdr->hdr_lba_table), blocks, (lba == 1)
423 ? MAP_TYPE_PRI_GPT_TBL : MAP_TYPE_SEC_GPT_TBL, p);
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 = le64toh(ent->ent_lba_end) - le64toh(ent->ent_lba_start) +
436 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 // XXX: map add with not allocated memory.
447 m = map_add(gpt, le64toh(ent->ent_lba_start), size,
448 MAP_TYPE_GPT_PART, ent);
449 if (m == NULL)
450 return (-1);
451 m->map_index = i + 1;
452 }
453 return (1);
454
455 fail_ent:
456 free(p);
457
458 fail_hdr:
459 free(hdr);
460 return (0);
461 }
462
463 gpt_t
464 gpt_open(const char *dev, int flags, int verbose, off_t mediasz, u_int secsz)
465 {
466 int mode, found;
467 off_t devsz;
468 gpt_t gpt;
469
470
471 if ((gpt = calloc(1, sizeof(*gpt))) == NULL) {
472 if (!(flags & GPT_QUIET))
473 warn("Cannot allocate `%s'", dev);
474 return NULL;
475 }
476 gpt->flags = flags;
477 gpt->verbose = verbose;
478 gpt->mediasz = mediasz;
479 gpt->secsz = secsz;
480
481 mode = (gpt->flags & GPT_READONLY) ? O_RDONLY : O_RDWR|O_EXCL;
482
483 gpt->fd = opendisk(dev, mode, gpt->device_name,
484 sizeof(gpt->device_name), 0);
485 if (gpt->fd == -1) {
486 strlcpy(gpt->device_name, dev, sizeof(gpt->device_name));
487 gpt_warn(gpt, "Cannot open");
488 goto close;
489 }
490
491 if (fstat(gpt->fd, &gpt->sb) == -1) {
492 gpt_warn(gpt, "Cannot stat");
493 goto close;
494 }
495
496 if ((gpt->sb.st_mode & S_IFMT) != S_IFREG) {
497 if (gpt->secsz == 0) {
498 #ifdef DIOCGSECTORSIZE
499 if (ioctl(gpt->fd, DIOCGSECTORSIZE, &gpt->secsz) == -1) {
500 gpt_warn(gpt, "Cannot get sector size");
501 goto close;
502 }
503 #endif
504 if (gpt->secsz == 0) {
505 gpt_warnx(gpt, "Sector size can't be 0");
506 goto close;
507 }
508 }
509 if (gpt->mediasz == 0) {
510 #ifdef DIOCGMEDIASIZE
511 if (ioctl(gpt->fd, DIOCGMEDIASIZE, &gpt->mediasz) == -1) {
512 gpt_warn(gpt, "Cannot get media size");
513 goto close;
514 }
515 #endif
516 if (gpt->mediasz == 0) {
517 gpt_warnx(gpt, "Media size can't be 0");
518 goto close;
519 }
520 }
521 } else {
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 sectorso, 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 gpt_msg(gpt, "You need to run \"dkctl %s makewedges\""
588 " for the changes to take effect\n", gpt->device_name);
589
590 out:
591 close(gpt->fd);
592 }
593
594 void
595 gpt_warnx(gpt_t gpt, const char *fmt, ...)
596 {
597 va_list ap;
598
599 if (gpt->flags & GPT_QUIET)
600 return;
601 fprintf(stderr, "%s: %s: ", getprogname(), gpt->device_name);
602 va_start(ap, fmt);
603 vfprintf(stderr, fmt, ap);
604 va_end(ap);
605 fprintf(stderr, "\n");
606 }
607
608 void
609 gpt_warn(gpt_t gpt, const char *fmt, ...)
610 {
611 va_list ap;
612 int e = errno;
613
614 if (gpt->flags & GPT_QUIET)
615 return;
616 fprintf(stderr, "%s: %s: ", getprogname(), gpt->device_name);
617 va_start(ap, fmt);
618 vfprintf(stderr, fmt, ap);
619 va_end(ap);
620 fprintf(stderr, " (%s)\n", strerror(e));
621 errno = e;
622 }
623
624 void
625 gpt_msg(gpt_t gpt, const char *fmt, ...)
626 {
627 va_list ap;
628
629 if (gpt->flags & GPT_QUIET)
630 return;
631 printf("%s: ", gpt->device_name);
632 va_start(ap, fmt);
633 vprintf(fmt, ap);
634 va_end(ap);
635 printf("\n");
636 }
637
638 struct gpt_hdr *
639 gpt_hdr(gpt_t gpt)
640 {
641 gpt->gpt = map_find(gpt, MAP_TYPE_PRI_GPT_HDR);
642 if (gpt->gpt == NULL) {
643 gpt_warnx(gpt, "No primary GPT header; run create or recover");
644 return NULL;
645 }
646
647 gpt->tpg = map_find(gpt, MAP_TYPE_SEC_GPT_HDR);
648 if (gpt->tpg == NULL) {
649 gpt_warnx(gpt, "No secondary GPT header; run recover");
650 return NULL;
651 }
652
653 gpt->tbl = map_find(gpt, MAP_TYPE_PRI_GPT_TBL);
654 gpt->lbt = map_find(gpt, MAP_TYPE_SEC_GPT_TBL);
655 if (gpt->tbl == NULL || gpt->lbt == NULL) {
656 gpt_warnx(gpt, "Corrupt maps, run recover");
657 return NULL;
658 }
659
660 return gpt->gpt->map_data;
661 }
662
663 int
664 gpt_write_crc(gpt_t gpt, map_t map, map_t tbl)
665 {
666 struct gpt_hdr *hdr = map->map_data;
667
668 hdr->hdr_crc_table = htole32(crc32(tbl->map_data,
669 le32toh(hdr->hdr_entries) * le32toh(hdr->hdr_entsz)));
670 hdr->hdr_crc_self = 0;
671 hdr->hdr_crc_self = htole32(crc32(hdr, le32toh(hdr->hdr_size)));
672
673 if (gpt_write(gpt, map) == -1) {
674 gpt_warn(gpt, "Error writing crc map");
675 return -1;
676 }
677
678 if (gpt_write(gpt, tbl) == -1) {
679 gpt_warn(gpt, "Error writing crc table");
680 return -1;
681 }
682
683 return 0;
684 }
685
686 int
687 gpt_write_primary(gpt_t gpt)
688 {
689 return gpt_write_crc(gpt, gpt->gpt, gpt->tbl);
690 }
691
692
693 int
694 gpt_write_backup(gpt_t gpt)
695 {
696 return gpt_write_crc(gpt, gpt->tpg, gpt->lbt);
697 }
698
699 void
700 gpt_create_pmbr_part(struct mbr_part *part, off_t last)
701 {
702 part->part_shd = 0x00;
703 part->part_ssect = 0x02;
704 part->part_scyl = 0x00;
705 part->part_typ = MBR_PTYPE_PMBR;
706 part->part_ehd = 0xfe;
707 part->part_esect = 0xff;
708 part->part_ecyl = 0xff;
709 part->part_start_lo = htole16(1);
710 if (last > 0xffffffff) {
711 part->part_size_lo = htole16(0xffff);
712 part->part_size_hi = htole16(0xffff);
713 } else {
714 part->part_size_lo = htole16(last);
715 part->part_size_hi = htole16(last >> 16);
716 }
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 int
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 = (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 ((p = calloc(1, gpt->secsz)) == NULL) {
833 gpt_warnx(gpt, "Can't allocate the primary GPT");
834 return -1;
835 }
836 if ((gpt->gpt = map_add(gpt, 1LL, 1LL,
837 MAP_TYPE_PRI_GPT_HDR, p)) == NULL) {
838 free(p);
839 gpt_warnx(gpt, "Can't add the primary GPT");
840 return -1;
841 }
842
843 if ((p = calloc(blocks, gpt->secsz)) == NULL) {
844 gpt_warnx(gpt, "Can't allocate the primary GPT table");
845 return -1;
846 }
847 if ((gpt->tbl = map_add(gpt, 2LL, blocks,
848 MAP_TYPE_PRI_GPT_TBL, p)) == NULL) {
849 free(p);
850 gpt_warnx(gpt, "Can't add the primary GPT table");
851 return -1;
852 }
853
854 hdr = gpt->gpt->map_data;
855 memcpy(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig));
856
857 /*
858 * XXX struct gpt_hdr is not a multiple of 8 bytes in size and thus
859 * contains padding we must not include in the size.
860 */
861 hdr->hdr_revision = htole32(GPT_HDR_REVISION);
862 hdr->hdr_size = htole32(GPT_HDR_SIZE);
863 hdr->hdr_lba_self = htole64(gpt->gpt->map_start);
864 hdr->hdr_lba_alt = htole64(last);
865 hdr->hdr_lba_start = htole64(gpt->tbl->map_start + blocks);
866 hdr->hdr_lba_end = htole64(last - blocks - 1LL);
867 if (gpt_uuid_generate(gpt, hdr->hdr_guid) == -1)
868 return -1;
869 hdr->hdr_lba_table = htole64(gpt->tbl->map_start);
870 hdr->hdr_entries = htole32((blocks * gpt->secsz) /
871 sizeof(struct gpt_ent));
872 if (le32toh(hdr->hdr_entries) > parts)
873 hdr->hdr_entries = htole32(parts);
874 hdr->hdr_entsz = htole32(sizeof(struct gpt_ent));
875
876 ent = gpt->tbl->map_data;
877 for (i = 0; i < le32toh(hdr->hdr_entries); i++) {
878 if (gpt_uuid_generate(gpt, ent[i].ent_guid) == -1)
879 return -1;
880 }
881
882 /*
883 * Create backup GPT if the user didn't suppress it.
884 */
885 if (primary_only)
886 return last;
887
888 if ((p = calloc(1, gpt->secsz)) == NULL) {
889 gpt_warnx(gpt, "Can't allocate the secondary GPT");
890 return -1;
891 }
892
893 if ((gpt->tpg = map_add(gpt, last, 1LL,
894 MAP_TYPE_SEC_GPT_HDR, p)) == NULL) {
895 gpt_warnx(gpt, "Can't add the secondary GPT");
896 return -1;
897 }
898
899 if ((gpt->lbt = map_add(gpt, last - blocks, blocks,
900 MAP_TYPE_SEC_GPT_TBL, gpt->tbl->map_data)) == NULL) {
901 gpt_warnx(gpt, "Can't add the secondary GPT table");
902 return -1;
903 }
904
905 memcpy(gpt->tpg->map_data, gpt->gpt->map_data, gpt->secsz);
906
907 hdr = gpt->tpg->map_data;
908 hdr->hdr_lba_self = htole64(gpt->tpg->map_start);
909 hdr->hdr_lba_alt = htole64(gpt->gpt->map_start);
910 hdr->hdr_lba_table = htole64(gpt->lbt->map_start);
911 return last;
912 }
913
914 static int
915 gpt_size_get(gpt_t gpt, off_t *size)
916 {
917 off_t sectors;
918 int64_t human_num;
919 char *p;
920
921 if (*size > 0)
922 return -1;
923 sectors = strtoll(optarg, &p, 10);
924 if (sectors < 1)
925 return -1;
926 if (*p == '\0' || ((*p == 's' || *p == 'S') && p[1] == '\0')) {
927 *size = sectors * gpt->secsz;
928 return 0;
929 }
930 if ((*p == 'b' || *p == 'B') && p[1] == '\0') {
931 *size = sectors;
932 return 0;
933 }
934 if (dehumanize_number(optarg, &human_num) < 0)
935 return -1;
936 *size = human_num;
937 return 0;
938 }
939
940 int
941 gpt_human_get(off_t *human)
942 {
943 int64_t human_num;
944
945 if (*human > 0)
946 return -1;
947 if (dehumanize_number(optarg, &human_num) < 0)
948 return -1;
949 *human = human_num;
950 if (*human < 1)
951 return -1;
952 return 0;
953 }
954
955 int
956 gpt_add_find(gpt_t gpt, struct gpt_find *find, int ch)
957 {
958 switch (ch) {
959 case 'a':
960 if (find->all > 0)
961 return -1;
962 find->all = 1;
963 break;
964 case 'b':
965 if (gpt_human_get(&find->block) == -1)
966 return -1;
967 break;
968 case 'i':
969 if (gpt_entry_get(&find->entry) == -1)
970 return -1;
971 break;
972 case 'L':
973 if (gpt_name_get(gpt, &find->label) == -1)
974 return -1;
975 break;
976 case 's':
977 if (gpt_size_get(gpt, &find->size) == -1)
978 return -1;
979 break;
980 case 't':
981 if (!gpt_uuid_is_nil(find->type))
982 return -1;
983 if (gpt_uuid_parse(optarg, find->type) != 0)
984 return -1;
985 break;
986 default:
987 return -1;
988 }
989 return 0;
990 }
991
992 int
993 gpt_change_ent(gpt_t gpt, const struct gpt_find *find,
994 void (*cfn)(struct gpt_ent *, void *), void *v)
995 {
996 map_t m;
997 struct gpt_hdr *hdr;
998 struct gpt_ent *ent;
999 unsigned int i;
1000 uint8_t utfbuf[__arraycount(ent->ent_name) * 3 + 1];
1001
1002 if (!find->all ^
1003 (find->block > 0 || find->entry > 0 || find->label != NULL
1004 || find->size > 0 || !gpt_uuid_is_nil(find->type)))
1005 return -1;
1006
1007 if ((hdr = gpt_hdr(gpt)) == NULL)
1008 return -1;
1009
1010 /* Relabel all matching entries in the map. */
1011 for (m = map_first(gpt); m != NULL; m = m->map_next) {
1012 if (m->map_type != MAP_TYPE_GPT_PART || m->map_index < 1)
1013 continue;
1014 if (find->entry > 0 && find->entry != m->map_index)
1015 continue;
1016 if (find->block > 0 && find->block != m->map_start)
1017 continue;
1018 if (find->size > 0 && find->size != m->map_size)
1019 continue;
1020
1021 i = m->map_index - 1;
1022
1023 ent = gpt_ent_primary(gpt, i);
1024 if (find->label != NULL) {
1025 utf16_to_utf8(ent->ent_name, utfbuf, sizeof(utfbuf));
1026 if (strcmp((char *)find->label, (char *)utfbuf) == 0)
1027 continue;
1028 }
1029
1030 if (!gpt_uuid_is_nil(find->type) &&
1031 !gpt_uuid_equal(find->type, ent->ent_type))
1032 continue;
1033
1034 /* Change the primary entry. */
1035 (*cfn)(ent, v);
1036
1037 if (gpt_write_primary(gpt) == -1)
1038 return -1;
1039
1040 ent = gpt_ent_backup(gpt, i);
1041 /* Change the secondary entry. */
1042 (*cfn)(ent, v);
1043
1044 if (gpt_write_backup(gpt) == -1)
1045 return -1;
1046
1047 gpt_msg(gpt, "Partition %d %s", m->map_index, find->msg);
1048 }
1049 return 0;
1050 }
1051
1052 int
1053 gpt_add_ais(gpt_t gpt, off_t *alignment, u_int *entry, off_t *size, int ch)
1054 {
1055 switch (ch) {
1056 case 'a':
1057 if (gpt_human_get(alignment) == -1)
1058 return -1;
1059 return 0;
1060 case 'i':
1061 if (gpt_entry_get(entry) == -1)
1062 return -1;
1063 return 0;
1064 case 's':
1065 if (gpt_size_get(gpt, size) == -1)
1066 return -1;
1067 return 0;
1068 default:
1069 return -1;
1070 }
1071 }
1072
1073 off_t
1074 gpt_check_ais(gpt_t gpt, off_t alignment, u_int entry, off_t size)
1075 {
1076 if (entry == 0) {
1077 gpt_warnx(gpt, "Entry not specified");
1078 return -1;
1079 }
1080 if (alignment % gpt->secsz != 0) {
1081 gpt_warnx(gpt, "Alignment (%#jx) must be a multiple of "
1082 "sector size (%#x)", (uintmax_t)alignment, gpt->secsz);
1083 return -1;
1084 }
1085
1086 if (size % gpt->secsz != 0) {
1087 gpt_warnx(gpt, "Size (%#jx) must be a multiple of "
1088 "sector size (%#x)", (uintmax_t)size, gpt->secsz);
1089 return -1;
1090 }
1091 if (size > 0)
1092 return size / gpt->secsz;
1093 return 0;
1094 }
1095 int
1096 gpt_attr_get(uint64_t *attributes)
1097 {
1098 if (strcmp(optarg, "biosboot") == 0)
1099 *attributes |= GPT_ENT_ATTR_LEGACY_BIOS_BOOTABLE;
1100 else if (strcmp(optarg, "bootme") == 0)
1101 *attributes |= GPT_ENT_ATTR_BOOTME;
1102 else if (strcmp(optarg, "bootonce") == 0)
1103 *attributes |= GPT_ENT_ATTR_BOOTONCE;
1104 else if (strcmp(optarg, "bootfailed") == 0)
1105 *attributes |= GPT_ENT_ATTR_BOOTFAILED;
1106 else
1107 return -1;
1108 return 0;
1109 }
1110 int
1111 gpt_attr_update(gpt_t gpt, u_int entry, uint64_t set, uint64_t clr)
1112 {
1113 struct gpt_hdr *hdr;
1114 struct gpt_ent *ent;
1115 unsigned int i;
1116
1117 if (entry == 0 || (set == 0 && clr == 0))
1118 return -1;
1119
1120 if ((hdr = gpt_hdr(gpt)) == NULL)
1121 return -1;
1122
1123 if (entry > le32toh(hdr->hdr_entries)) {
1124 gpt_warnx(gpt, "Index %u out of range (%u max)",
1125 entry, le32toh(hdr->hdr_entries));
1126 return -1;
1127 }
1128
1129 i = entry - 1;
1130 ent = gpt_ent_primary(gpt, i);
1131 if (gpt_uuid_is_nil(ent->ent_type)) {
1132 gpt_warnx(gpt, "Entry at index %u is unused", entry);
1133 return -1;
1134 }
1135
1136 ent->ent_attr &= ~clr;
1137 ent->ent_attr |= set;
1138
1139 if (gpt_write_primary(gpt) == -1)
1140 return -1;
1141
1142 ent = gpt_ent_backup(gpt, i);
1143 ent->ent_attr &= ~clr;
1144 ent->ent_attr |= set;
1145
1146 if (gpt_write_backup(gpt) == -1)
1147 return -1;
1148 gpt_msg(gpt, "Partition %d attributes updated", entry);
1149 return 0;
1150 }
1151
1152 int
1153 gpt_entry_get(u_int *entry)
1154 {
1155 char *p;
1156 if (*entry > 0)
1157 return -1;
1158 *entry = strtoul(optarg, &p, 10);
1159 if (*p != 0 || *entry < 1)
1160 return -1;
1161 return 0;
1162 }
1163 int
1164 gpt_uuid_get(gpt_t gpt, gpt_uuid_t *uuid)
1165 {
1166 if (!gpt_uuid_is_nil(*uuid))
1167 return -1;
1168 if (gpt_uuid_parse(optarg, *uuid) != 0) {
1169 gpt_warn(gpt, "Can't parse uuid");
1170 return -1;
1171 }
1172 return 0;
1173 }
1174
1175 int
1176 gpt_name_get(gpt_t gpt, void *v)
1177 {
1178 char **name = v;
1179 if (*name != NULL)
1180 return -1;
1181 *name = strdup(optarg);
1182 if (*name == NULL) {
1183 gpt_warn(gpt, "Can't copy string");
1184 return -1;
1185 }
1186 return 0;
1187 }
1188