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