gpt.c revision 1.56 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.56 2015/12/02 12:20:52 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 m = map_add(gpt, start, size, MAP_TYPE_MBR_PART, p);
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, le64toh(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);
418 if (m == NULL)
419 return (-1);
420
421 m = map_add(gpt, le64toh(hdr->hdr_lba_table), blocks, (lba == 1)
422 ? MAP_TYPE_PRI_GPT_TBL : MAP_TYPE_SEC_GPT_TBL, p);
423 if (m == NULL)
424 return (-1);
425
426 if (lba != 1)
427 return (1);
428
429 for (i = 0; i < le32toh(hdr->hdr_entries); i++) {
430 ent = (void*)(p + i * le32toh(hdr->hdr_entsz));
431 if (gpt_uuid_is_nil(ent->ent_type))
432 continue;
433
434 size = le64toh(ent->ent_lba_end) - le64toh(ent->ent_lba_start) +
435 1LL;
436 if (gpt->verbose > 2) {
437 char buf[128];
438 gpt_uuid_snprintf(buf, sizeof(buf), "%s",
439 ent->ent_type);
440 gpt_msg(gpt, "GPT partition: type=%s, start=%ju, "
441 "size=%ju", buf,
442 (uintmax_t)le64toh(ent->ent_lba_start),
443 (uintmax_t)size);
444 }
445 m = map_add(gpt, le64toh(ent->ent_lba_start), size,
446 MAP_TYPE_GPT_PART, ent);
447 if (m == NULL)
448 return (-1);
449 m->map_index = i + 1;
450 }
451 return (1);
452
453 fail_ent:
454 free(p);
455
456 fail_hdr:
457 free(hdr);
458 return (0);
459 }
460
461 gpt_t
462 gpt_open(const char *dev, int flags, int verbose, off_t mediasz, u_int secsz)
463 {
464 int mode, found;
465 off_t devsz;
466 gpt_t gpt;
467
468
469 if ((gpt = calloc(1, sizeof(*gpt))) == NULL) {
470 if (!(flags & GPT_QUIET))
471 warn("Cannot allocate `%s'", dev);
472 return NULL;
473 }
474 gpt->flags = flags;
475 gpt->verbose = verbose;
476 gpt->mediasz = mediasz;
477 gpt->secsz = secsz;
478
479 mode = (gpt->flags & GPT_READONLY) ? O_RDONLY : O_RDWR|O_EXCL;
480
481 gpt->fd = opendisk(dev, mode, gpt->device_name,
482 sizeof(gpt->device_name), 0);
483 if (gpt->fd == -1) {
484 strlcpy(gpt->device_name, dev, sizeof(gpt->device_name));
485 gpt_warn(gpt, "Cannot open");
486 goto close;
487 }
488
489 if (fstat(gpt->fd, &gpt->sb) == -1) {
490 gpt_warn(gpt, "Cannot stat");
491 goto close;
492 }
493
494 if ((gpt->sb.st_mode & S_IFMT) != S_IFREG) {
495 if (gpt->secsz == 0) {
496 #ifdef DIOCGSECTORSIZE
497 if (ioctl(gpt->fd, DIOCGSECTORSIZE, &gpt->secsz) == -1) {
498 gpt_warn(gpt, "Cannot get sector size");
499 goto close;
500 }
501 #endif
502 if (gpt->secsz == 0) {
503 gpt_warnx(gpt, "Sector size can't be 0");
504 goto close;
505 }
506 }
507 if (gpt->mediasz == 0) {
508 #ifdef DIOCGMEDIASIZE
509 if (ioctl(gpt->fd, DIOCGMEDIASIZE, &gpt->mediasz) == -1) {
510 gpt_warn(gpt, "Cannot get media size");
511 goto close;
512 }
513 #endif
514 if (gpt->mediasz == 0) {
515 gpt_warnx(gpt, "Media size can't be 0");
516 goto close;
517 }
518 }
519 } else {
520 if (gpt->secsz == 0)
521 gpt->secsz = 512; /* Fixed size for files. */
522 if (gpt->mediasz == 0) {
523 if (gpt->sb.st_size % gpt->secsz) {
524 errno = EINVAL;
525 goto close;
526 }
527 gpt->mediasz = gpt->sb.st_size;
528 }
529 gpt->flags |= GPT_NOSYNC;
530 }
531
532 /*
533 * We require an absolute minimum of 6 sectors. One for the MBR,
534 * 2 for the GPT header, 2 for the GPT table and one to hold some
535 * user data. Let's catch this extreme border case here so that
536 * we don't have to worry about it later.
537 */
538 devsz = gpt->mediasz / gpt->secsz;
539 if (devsz < 6) {
540 gpt_warnx(gpt, "Need 6 sectorso, we have %ju",
541 (uintmax_t)devsz);
542 goto close;
543 }
544
545 if (gpt->verbose) {
546 gpt_msg(gpt, "mediasize=%ju; sectorsize=%u; blocks=%ju",
547 (uintmax_t)gpt->mediasz, gpt->secsz, (uintmax_t)devsz);
548 }
549
550 map_init(gpt, devsz);
551
552 if (gpt_mbr(gpt, 0LL) == -1)
553 goto close;
554 if ((found = gpt_gpt(gpt, 1LL, 1)) == -1)
555 goto close;
556 if (gpt_gpt(gpt, devsz - 1LL, found) == -1)
557 goto close;
558
559 return gpt;
560
561 close:
562 if (gpt->fd != -1)
563 close(gpt->fd);
564 free(gpt);
565 return NULL;
566 }
567
568 void
569 gpt_close(gpt_t gpt)
570 {
571
572 if (!(gpt->flags & GPT_MODIFIED))
573 goto out;
574
575 if (!(gpt->flags & GPT_NOSYNC)) {
576 #ifdef DIOCMWEDGES
577 int bits;
578 if (ioctl(gpt->fd, DIOCMWEDGES, &bits) == -1)
579 gpt_warn(gpt, "Can't update wedge information");
580 else
581 goto out;
582 #endif
583 }
584 gpt_msg(gpt, "You need to run \"dkctl %s makewedges\""
585 " for the changes to take effect\n", gpt->device_name);
586
587 out:
588 close(gpt->fd);
589 }
590
591 void
592 gpt_warnx(gpt_t gpt, const char *fmt, ...)
593 {
594 va_list ap;
595
596 if (gpt->flags & GPT_QUIET)
597 return;
598 fprintf(stderr, "%s: %s: ", getprogname(), gpt->device_name);
599 va_start(ap, fmt);
600 vfprintf(stderr, fmt, ap);
601 va_end(ap);
602 fprintf(stderr, "\n");
603 }
604
605 void
606 gpt_warn(gpt_t gpt, const char *fmt, ...)
607 {
608 va_list ap;
609 int e = errno;
610
611 if (gpt->flags & GPT_QUIET)
612 return;
613 fprintf(stderr, "%s: %s: ", getprogname(), gpt->device_name);
614 va_start(ap, fmt);
615 vfprintf(stderr, fmt, ap);
616 va_end(ap);
617 fprintf(stderr, " (%s)\n", strerror(e));
618 errno = e;
619 }
620
621 void
622 gpt_msg(gpt_t gpt, const char *fmt, ...)
623 {
624 va_list ap;
625
626 if (gpt->flags & GPT_QUIET)
627 return;
628 printf("%s: ", gpt->device_name);
629 va_start(ap, fmt);
630 vprintf(fmt, ap);
631 va_end(ap);
632 printf("\n");
633 }
634
635 struct gpt_hdr *
636 gpt_hdr(gpt_t gpt)
637 {
638 gpt->gpt = map_find(gpt, MAP_TYPE_PRI_GPT_HDR);
639 if (gpt->gpt == NULL) {
640 gpt_warnx(gpt, "No primary GPT header; run create or recover");
641 return NULL;
642 }
643
644 gpt->tpg = map_find(gpt, MAP_TYPE_SEC_GPT_HDR);
645 if (gpt->tpg == NULL) {
646 gpt_warnx(gpt, "No secondary GPT header; run recover");
647 return NULL;
648 }
649
650 gpt->tbl = map_find(gpt, MAP_TYPE_PRI_GPT_TBL);
651 gpt->lbt = map_find(gpt, MAP_TYPE_SEC_GPT_TBL);
652 if (gpt->tbl == NULL || gpt->lbt == NULL) {
653 gpt_warnx(gpt, "Corrupt maps, run recover");
654 return NULL;
655 }
656
657 return gpt->gpt->map_data;
658 }
659
660 int
661 gpt_write_crc(gpt_t gpt, map_t map, map_t tbl)
662 {
663 struct gpt_hdr *hdr = map->map_data;
664
665 hdr->hdr_crc_table = htole32(crc32(tbl->map_data,
666 le32toh(hdr->hdr_entries) * le32toh(hdr->hdr_entsz)));
667 hdr->hdr_crc_self = 0;
668 hdr->hdr_crc_self = htole32(crc32(hdr, le32toh(hdr->hdr_size)));
669
670 if (gpt_write(gpt, map) == -1) {
671 gpt_warn(gpt, "Error writing crc map");
672 return -1;
673 }
674
675 if (gpt_write(gpt, tbl) == -1) {
676 gpt_warn(gpt, "Error writing crc table");
677 return -1;
678 }
679
680 return 0;
681 }
682
683 int
684 gpt_write_primary(gpt_t gpt)
685 {
686 return gpt_write_crc(gpt, gpt->gpt, gpt->tbl);
687 }
688
689
690 int
691 gpt_write_backup(gpt_t gpt)
692 {
693 return gpt_write_crc(gpt, gpt->tpg, gpt->lbt);
694 }
695
696 void
697 gpt_create_pmbr_part(struct mbr_part *part, off_t last)
698 {
699 part->part_shd = 0x00;
700 part->part_ssect = 0x02;
701 part->part_scyl = 0x00;
702 part->part_typ = MBR_PTYPE_PMBR;
703 part->part_ehd = 0xfe;
704 part->part_esect = 0xff;
705 part->part_ecyl = 0xff;
706 part->part_start_lo = htole16(1);
707 if (last > 0xffffffff) {
708 part->part_size_lo = htole16(0xffff);
709 part->part_size_hi = htole16(0xffff);
710 } else {
711 part->part_size_lo = htole16(last);
712 part->part_size_hi = htole16(last >> 16);
713 }
714 }
715
716
717 struct gpt_ent *
718 gpt_ent(map_t map, map_t tbl, unsigned int i)
719 {
720 struct gpt_hdr *hdr = map->map_data;
721 return (void *)((char *)tbl->map_data + i * le32toh(hdr->hdr_entsz));
722 }
723
724 struct gpt_ent *
725 gpt_ent_primary(gpt_t gpt, unsigned int i)
726 {
727 return gpt_ent(gpt->gpt, gpt->tbl, i);
728 }
729
730 struct gpt_ent *
731 gpt_ent_backup(gpt_t gpt, unsigned int i)
732 {
733 return gpt_ent(gpt->tpg, gpt->lbt, i);
734 }
735
736 int
737 gpt_usage(const char *prefix, const struct gpt_cmd *cmd)
738 {
739 const char **a = cmd->help;
740 size_t hlen = cmd->hlen;
741 size_t i;
742
743 if (prefix == NULL) {
744 const char *pname = getprogname();
745 const char *d1, *d2, *d = " <device>";
746 int len = (int)strlen(pname);
747 if (strcmp(pname, "gpt") == 0) {
748 d1 = "";
749 d2 = d;
750 } else {
751 d2 = "";
752 d1 = d;
753 }
754 fprintf(stderr, "Usage: %s%s %s %s%s\n", pname,
755 d1, cmd->name, a[0], d2);
756 for (i = 1; i < hlen; i++) {
757 fprintf(stderr,
758 " %*s%s %s %s%s\n", len, "",
759 d1, cmd->name, a[i], d2);
760 }
761 } else {
762 for (i = 0; i < hlen; i++)
763 fprintf(stderr, "%s%s %s\n", prefix, cmd->name, a[i]);
764 }
765 return -1;
766 }
767
768 off_t
769 gpt_last(gpt_t gpt)
770 {
771 return gpt->mediasz / gpt->secsz - 1LL;
772 }
773
774 int
775 gpt_create(gpt_t gpt, off_t last, u_int parts, int primary_only)
776 {
777 off_t blocks;
778 map_t map;
779 struct gpt_hdr *hdr;
780 struct gpt_ent *ent;
781 unsigned int i;
782 void *p;
783
784 if (map_find(gpt, MAP_TYPE_PRI_GPT_HDR) != NULL ||
785 map_find(gpt, MAP_TYPE_SEC_GPT_HDR) != NULL) {
786 gpt_warnx(gpt, "Device already contains a GPT");
787 return -1;
788 }
789
790 /* Get the amount of free space after the MBR */
791 blocks = map_free(gpt, 1LL, 0LL);
792 if (blocks == 0LL) {
793 gpt_warnx(gpt, "No room for the GPT header");
794 return -1;
795 }
796
797 /* Don't create more than parts entries. */
798 if ((uint64_t)(blocks - 1) * gpt->secsz >
799 parts * sizeof(struct gpt_ent)) {
800 blocks = (parts * sizeof(struct gpt_ent)) / gpt->secsz;
801 if ((parts * sizeof(struct gpt_ent)) % gpt->secsz)
802 blocks++;
803 blocks++; /* Don't forget the header itself */
804 }
805
806 /* Never cross the median of the device. */
807 if ((blocks + 1LL) > ((last + 1LL) >> 1))
808 blocks = ((last + 1LL) >> 1) - 1LL;
809
810 /*
811 * Get the amount of free space at the end of the device and
812 * calculate the size for the GPT structures.
813 */
814 map = map_last(gpt);
815 if (map->map_type != MAP_TYPE_UNUSED) {
816 gpt_warnx(gpt, "No room for the backup header");
817 return -1;
818 }
819
820 if (map->map_size < blocks)
821 blocks = map->map_size;
822 if (blocks == 1LL) {
823 gpt_warnx(gpt, "No room for the GPT table");
824 return -1;
825 }
826
827 blocks--; /* Number of blocks in the GPT table. */
828
829 if ((p = calloc(1, gpt->secsz)) == NULL) {
830 gpt_warnx(gpt, "Can't allocate the primary GPT");
831 return -1;
832 }
833 if ((gpt->gpt = map_add(gpt, 1LL, 1LL,
834 MAP_TYPE_PRI_GPT_HDR, p)) == NULL) {
835 free(p);
836 gpt_warnx(gpt, "Can't add the primary GPT");
837 return -1;
838 }
839
840 if ((p = calloc(blocks, gpt->secsz)) == NULL) {
841 gpt_warnx(gpt, "Can't allocate the primary GPT table");
842 return -1;
843 }
844 if ((gpt->tbl = map_add(gpt, 2LL, blocks,
845 MAP_TYPE_PRI_GPT_TBL, p)) == NULL) {
846 free(p);
847 gpt_warnx(gpt, "Can't add the primary GPT table");
848 return -1;
849 }
850
851 hdr = gpt->gpt->map_data;
852 memcpy(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig));
853
854 /*
855 * XXX struct gpt_hdr is not a multiple of 8 bytes in size and thus
856 * contains padding we must not include in the size.
857 */
858 hdr->hdr_revision = htole32(GPT_HDR_REVISION);
859 hdr->hdr_size = htole32(GPT_HDR_SIZE);
860 hdr->hdr_lba_self = htole64(gpt->gpt->map_start);
861 hdr->hdr_lba_alt = htole64(last);
862 hdr->hdr_lba_start = htole64(gpt->tbl->map_start + blocks);
863 hdr->hdr_lba_end = htole64(last - blocks - 1LL);
864 if (gpt_uuid_generate(gpt, hdr->hdr_guid) == -1)
865 return -1;
866 hdr->hdr_lba_table = htole64(gpt->tbl->map_start);
867 hdr->hdr_entries = htole32((blocks * gpt->secsz) /
868 sizeof(struct gpt_ent));
869 if (le32toh(hdr->hdr_entries) > parts)
870 hdr->hdr_entries = htole32(parts);
871 hdr->hdr_entsz = htole32(sizeof(struct gpt_ent));
872
873 ent = gpt->tbl->map_data;
874 for (i = 0; i < le32toh(hdr->hdr_entries); i++) {
875 if (gpt_uuid_generate(gpt, ent[i].ent_guid) == -1)
876 return -1;
877 }
878
879 /*
880 * Create backup GPT if the user didn't suppress it.
881 */
882 if (primary_only)
883 return last;
884
885 if ((p = calloc(1, gpt->secsz)) == NULL) {
886 gpt_warnx(gpt, "Can't allocate the secondary GPT");
887 return -1;
888 }
889
890 if ((gpt->tpg = map_add(gpt, last, 1LL,
891 MAP_TYPE_SEC_GPT_HDR, p)) == NULL) {
892 gpt_warnx(gpt, "Can't add the secondary GPT");
893 return -1;
894 }
895
896 if ((gpt->lbt = map_add(gpt, last - blocks, blocks,
897 MAP_TYPE_SEC_GPT_TBL, gpt->tbl->map_data)) == NULL) {
898 gpt_warnx(gpt, "Can't add the secondary GPT table");
899 return -1;
900 }
901
902 memcpy(gpt->tpg->map_data, gpt->gpt->map_data, gpt->secsz);
903
904 hdr = gpt->tpg->map_data;
905 hdr->hdr_lba_self = htole64(gpt->tpg->map_start);
906 hdr->hdr_lba_alt = htole64(gpt->gpt->map_start);
907 hdr->hdr_lba_table = htole64(gpt->lbt->map_start);
908 return last;
909 }
910
911 static int
912 gpt_size_get(gpt_t gpt, off_t *size)
913 {
914 off_t sectors;
915 int64_t human_num;
916 char *p;
917
918 if (*size > 0)
919 return -1;
920 sectors = strtoll(optarg, &p, 10);
921 if (sectors < 1)
922 return -1;
923 if (*p == '\0' || ((*p == 's' || *p == 'S') && p[1] == '\0')) {
924 *size = sectors * gpt->secsz;
925 return 0;
926 }
927 if ((*p == 'b' || *p == 'B') && p[1] == '\0') {
928 *size = sectors;
929 return 0;
930 }
931 if (dehumanize_number(optarg, &human_num) < 0)
932 return -1;
933 *size = human_num;
934 return 0;
935 }
936
937 int
938 gpt_human_get(off_t *human)
939 {
940 int64_t human_num;
941
942 if (*human > 0)
943 return -1;
944 if (dehumanize_number(optarg, &human_num) < 0)
945 return -1;
946 *human = human_num;
947 if (*human < 1)
948 return -1;
949 return 0;
950 }
951
952 int
953 gpt_add_find(gpt_t gpt, struct gpt_find *find, int ch)
954 {
955 switch (ch) {
956 case 'a':
957 if (find->all > 0)
958 return -1;
959 find->all = 1;
960 break;
961 case 'b':
962 if (gpt_human_get(&find->block) == -1)
963 return -1;
964 break;
965 case 'i':
966 if (gpt_entry_get(&find->entry) == -1)
967 return -1;
968 break;
969 case 'L':
970 if (gpt_name_get(gpt, &find->label) == -1)
971 return -1;
972 break;
973 case 's':
974 if (gpt_size_get(gpt, &find->size) == -1)
975 return -1;
976 break;
977 case 't':
978 if (!gpt_uuid_is_nil(find->type))
979 return -1;
980 if (gpt_uuid_parse(optarg, find->type) != 0)
981 return -1;
982 break;
983 default:
984 return -1;
985 }
986 return 0;
987 }
988
989 int
990 gpt_change_ent(gpt_t gpt, const struct gpt_find *find,
991 void (*cfn)(struct gpt_ent *, void *), void *v)
992 {
993 map_t m;
994 struct gpt_hdr *hdr;
995 struct gpt_ent *ent;
996 unsigned int i;
997 uint8_t utfbuf[__arraycount(ent->ent_name) * 3 + 1];
998
999 if (!find->all ^
1000 (find->block > 0 || find->entry > 0 || find->label != NULL
1001 || find->size > 0 || !gpt_uuid_is_nil(find->type)))
1002 return -1;
1003
1004 if ((hdr = gpt_hdr(gpt)) == NULL)
1005 return -1;
1006
1007 /* Relabel all matching entries in the map. */
1008 for (m = map_first(gpt); m != NULL; m = m->map_next) {
1009 if (m->map_type != MAP_TYPE_GPT_PART || m->map_index < 1)
1010 continue;
1011 if (find->entry > 0 && find->entry != m->map_index)
1012 continue;
1013 if (find->block > 0 && find->block != m->map_start)
1014 continue;
1015 if (find->size > 0 && find->size != m->map_size)
1016 continue;
1017
1018 i = m->map_index - 1;
1019
1020 ent = gpt_ent_primary(gpt, i);
1021 if (find->label != NULL) {
1022 utf16_to_utf8(ent->ent_name, utfbuf, sizeof(utfbuf));
1023 if (strcmp((char *)find->label, (char *)utfbuf) == 0)
1024 continue;
1025 }
1026
1027 if (!gpt_uuid_is_nil(find->type) &&
1028 !gpt_uuid_equal(find->type, ent->ent_type))
1029 continue;
1030
1031 /* Change the primary entry. */
1032 (*cfn)(ent, v);
1033
1034 if (gpt_write_primary(gpt) == -1)
1035 return -1;
1036
1037 ent = gpt_ent_backup(gpt, i);
1038 /* Change the secondary entry. */
1039 (*cfn)(ent, v);
1040
1041 if (gpt_write_backup(gpt) == -1)
1042 return -1;
1043
1044 gpt_msg(gpt, "Partition %d %s", m->map_index, find->msg);
1045 }
1046 return 0;
1047 }
1048
1049 int
1050 gpt_add_ais(gpt_t gpt, off_t *alignment, u_int *entry, off_t *size, int ch)
1051 {
1052 switch (ch) {
1053 case 'a':
1054 if (gpt_human_get(alignment) == -1)
1055 return -1;
1056 return 0;
1057 case 'i':
1058 if (gpt_entry_get(entry) == -1)
1059 return -1;
1060 return 0;
1061 case 's':
1062 if (gpt_size_get(gpt, size) == -1)
1063 return -1;
1064 return 0;
1065 default:
1066 return -1;
1067 }
1068 }
1069
1070 off_t
1071 gpt_check_ais(gpt_t gpt, off_t alignment, u_int entry, off_t size)
1072 {
1073 if (entry == 0) {
1074 gpt_warnx(gpt, "Entry not specified");
1075 return -1;
1076 }
1077 if (alignment % gpt->secsz != 0) {
1078 gpt_warnx(gpt, "Alignment (%#jx) must be a multiple of "
1079 "sector size (%#x)", (uintmax_t)alignment, gpt->secsz);
1080 return -1;
1081 }
1082
1083 if (size % gpt->secsz != 0) {
1084 gpt_warnx(gpt, "Size (%#jx) must be a multiple of "
1085 "sector size (%#x)", (uintmax_t)size, gpt->secsz);
1086 return -1;
1087 }
1088 if (size > 0)
1089 return size / gpt->secsz;
1090 return 0;
1091 }
1092 int
1093 gpt_attr_get(uint64_t *attributes)
1094 {
1095 if (strcmp(optarg, "biosboot") == 0)
1096 *attributes |= GPT_ENT_ATTR_LEGACY_BIOS_BOOTABLE;
1097 else if (strcmp(optarg, "bootme") == 0)
1098 *attributes |= GPT_ENT_ATTR_BOOTME;
1099 else if (strcmp(optarg, "bootonce") == 0)
1100 *attributes |= GPT_ENT_ATTR_BOOTONCE;
1101 else if (strcmp(optarg, "bootfailed") == 0)
1102 *attributes |= GPT_ENT_ATTR_BOOTFAILED;
1103 else
1104 return -1;
1105 return 0;
1106 }
1107 int
1108 gpt_attr_update(gpt_t gpt, u_int entry, uint64_t set, uint64_t clr)
1109 {
1110 struct gpt_hdr *hdr;
1111 struct gpt_ent *ent;
1112 unsigned int i;
1113
1114 if (entry == 0 || (set == 0 && clr == 0))
1115 return -1;
1116
1117 if ((hdr = gpt_hdr(gpt)) == NULL)
1118 return -1;
1119
1120 if (entry > le32toh(hdr->hdr_entries)) {
1121 gpt_warnx(gpt, "Index %u out of range (%u max)",
1122 entry, le32toh(hdr->hdr_entries));
1123 return -1;
1124 }
1125
1126 i = entry - 1;
1127 ent = gpt_ent_primary(gpt, i);
1128 if (gpt_uuid_is_nil(ent->ent_type)) {
1129 gpt_warnx(gpt, "Entry at index %u is unused", entry);
1130 return -1;
1131 }
1132
1133 ent->ent_attr &= ~clr;
1134 ent->ent_attr |= set;
1135
1136 if (gpt_write_primary(gpt) == -1)
1137 return -1;
1138
1139 ent = gpt_ent_backup(gpt, i);
1140 ent->ent_attr &= ~clr;
1141 ent->ent_attr |= set;
1142
1143 if (gpt_write_backup(gpt) == -1)
1144 return -1;
1145 gpt_msg(gpt, "Partition %d attributes updated", entry);
1146 return 0;
1147 }
1148
1149 int
1150 gpt_entry_get(u_int *entry)
1151 {
1152 char *p;
1153 if (*entry > 0)
1154 return -1;
1155 *entry = strtoul(optarg, &p, 10);
1156 if (*p != 0 || *entry < 1)
1157 return -1;
1158 return 0;
1159 }
1160 int
1161 gpt_uuid_get(gpt_t gpt, gpt_uuid_t *uuid)
1162 {
1163 if (!gpt_uuid_is_nil(*uuid))
1164 return -1;
1165 if (gpt_uuid_parse(optarg, *uuid) != 0) {
1166 gpt_warn(gpt, "Can't parse uuid");
1167 return -1;
1168 }
1169 return 0;
1170 }
1171
1172 int
1173 gpt_name_get(gpt_t gpt, void *v)
1174 {
1175 char **name = v;
1176 if (*name != NULL)
1177 return -1;
1178 *name = strdup(optarg);
1179 if (*name == NULL) {
1180 gpt_warn(gpt, "Can't copy string");
1181 return -1;
1182 }
1183 return 0;
1184 }
1185