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