gpt.c revision 1.50 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.50 2015/12/01 16:32:19 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 uint8_t *
125 utf16_to_utf8(uint16_t *s16)
126 {
127 static uint8_t *s8 = NULL;
128 static size_t s8len = 0;
129 size_t s8idx, s16idx, s16len;
130 uint32_t utfchar;
131 unsigned int c;
132
133 s16len = 0;
134 while (s16[s16len++] != 0)
135 ;
136 if (s8len < s16len * 3) {
137 if (s8 != NULL)
138 free(s8);
139 s8len = s16len * 3;
140 s8 = calloc(s16len, 3);
141 }
142 s8idx = s16idx = 0;
143 while (s16idx < s16len) {
144 utfchar = le16toh(s16[s16idx++]);
145 if ((utfchar & 0xf800) == 0xd800) {
146 c = le16toh(s16[s16idx]);
147 if ((utfchar & 0x400) != 0 || (c & 0xfc00) != 0xdc00)
148 utfchar = 0xfffd;
149 else
150 s16idx++;
151 }
152 if (utfchar < 0x80) {
153 s8[s8idx++] = utfchar;
154 } else if (utfchar < 0x800) {
155 s8[s8idx++] = 0xc0 | (utfchar >> 6);
156 s8[s8idx++] = 0x80 | (utfchar & 0x3f);
157 } else if (utfchar < 0x10000) {
158 s8[s8idx++] = 0xe0 | (utfchar >> 12);
159 s8[s8idx++] = 0x80 | ((utfchar >> 6) & 0x3f);
160 s8[s8idx++] = 0x80 | (utfchar & 0x3f);
161 } else if (utfchar < 0x200000) {
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 return (s8);
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 off_t
716 gpt_check(gpt_t gpt, off_t alignment, off_t size)
717 {
718 if (alignment % gpt->secsz != 0) {
719 gpt_warnx(gpt, "Alignment (%#jx) must be a multiple of "
720 "sector size (%#x)", (uintmax_t)alignment, gpt->secsz);
721 return -1;
722 }
723
724 if (size % gpt->secsz != 0) {
725 gpt_warnx(gpt, "Size (%#jx) must be a multiple of "
726 "sector size (%#x)", (uintmax_t)size, gpt->secsz);
727 return -1;
728 }
729 if (size > 0)
730 return size / gpt->secsz;
731 return 0;
732 }
733 struct gpt_ent *
734 gpt_ent(map_t map, map_t tbl, unsigned int i)
735 {
736 struct gpt_hdr *hdr = map->map_data;
737 return (void *)((char *)tbl->map_data + i * le32toh(hdr->hdr_entsz));
738 }
739
740 struct gpt_ent *
741 gpt_ent_primary(gpt_t gpt, unsigned int i)
742 {
743 return gpt_ent(gpt->gpt, gpt->tbl, i);
744 }
745
746 struct gpt_ent *
747 gpt_ent_backup(gpt_t gpt, unsigned int i)
748 {
749 return gpt_ent(gpt->tpg, gpt->lbt, i);
750 }
751
752 int
753 gpt_usage(const char *prefix, const struct gpt_cmd *cmd)
754 {
755 const char **a = cmd->help;
756 size_t hlen = cmd->hlen;
757 size_t i;
758
759 if (prefix == NULL) {
760 const char *pname = getprogname();
761 int len = (int)strlen(pname);
762 fprintf(stderr, "Usage: %s %s %s\n", pname, cmd->name, a[0]);
763 for (i = 1; i < hlen; i++) {
764 fprintf(stderr,
765 " %*s %s %s\n", len, "", cmd->name, a[i]);
766 }
767 } else {
768 for (i = 0; i < hlen; i++)
769 fprintf(stderr, "%s%s %s\n", prefix, cmd->name, a[i]);
770 }
771 return -1;
772 }
773