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