gpt.c revision 1.34 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.34 2014/09/30 17:59:59 christos Exp $");
39 #endif
40
41 #include <sys/param.h>
42 #include <sys/types.h>
43 #include <sys/disk.h>
44 #include <sys/stat.h>
45 #include <sys/ioctl.h>
46 #include <sys/bootblock.h>
47
48 #include <err.h>
49 #include <errno.h>
50 #include <fcntl.h>
51 #include <paths.h>
52 #include <stddef.h>
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <string.h>
56 #include <unistd.h>
57 #include <ctype.h>
58 #ifndef HAVE_NBTOOL_CONFIG_H
59 #include <prop/proplib.h>
60 #include <sys/drvctlio.h>
61 #endif
62
63 #include "map.h"
64 #include "gpt.h"
65
66 char device_path[MAXPATHLEN];
67 const char *device_arg;
68 char *device_name;
69
70 off_t mediasz;
71
72 u_int parts;
73 u_int secsz;
74
75 int readonly, verbose;
76
77 static uint32_t crc32_tab[] = {
78 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
79 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
80 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
81 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
82 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
83 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
84 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
85 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
86 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
87 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
88 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
89 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
90 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
91 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
92 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
93 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
94 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
95 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
96 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
97 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
98 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
99 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
100 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
101 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
102 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
103 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
104 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
105 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
106 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
107 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
108 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
109 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
110 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
111 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
112 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
113 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
114 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
115 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
116 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
117 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
118 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
119 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
120 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
121 };
122
123 uint32_t
124 crc32(const void *buf, size_t size)
125 {
126 const uint8_t *p;
127 uint32_t crc;
128
129 p = buf;
130 crc = ~0U;
131
132 while (size--)
133 crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
134
135 return crc ^ ~0U;
136 }
137
138 uint8_t *
139 utf16_to_utf8(uint16_t *s16)
140 {
141 static uint8_t *s8 = NULL;
142 static size_t s8len = 0;
143 size_t s8idx, s16idx, s16len;
144 uint32_t utfchar;
145 unsigned int c;
146
147 s16len = 0;
148 while (s16[s16len++] != 0)
149 ;
150 if (s8len < s16len * 3) {
151 if (s8 != NULL)
152 free(s8);
153 s8len = s16len * 3;
154 s8 = calloc(s16len, 3);
155 }
156 s8idx = s16idx = 0;
157 while (s16idx < s16len) {
158 utfchar = le16toh(s16[s16idx++]);
159 if ((utfchar & 0xf800) == 0xd800) {
160 c = le16toh(s16[s16idx]);
161 if ((utfchar & 0x400) != 0 || (c & 0xfc00) != 0xdc00)
162 utfchar = 0xfffd;
163 else
164 s16idx++;
165 }
166 if (utfchar < 0x80) {
167 s8[s8idx++] = utfchar;
168 } else if (utfchar < 0x800) {
169 s8[s8idx++] = 0xc0 | (utfchar >> 6);
170 s8[s8idx++] = 0x80 | (utfchar & 0x3f);
171 } else if (utfchar < 0x10000) {
172 s8[s8idx++] = 0xe0 | (utfchar >> 12);
173 s8[s8idx++] = 0x80 | ((utfchar >> 6) & 0x3f);
174 s8[s8idx++] = 0x80 | (utfchar & 0x3f);
175 } else if (utfchar < 0x200000) {
176 s8[s8idx++] = 0xf0 | (utfchar >> 18);
177 s8[s8idx++] = 0x80 | ((utfchar >> 12) & 0x3f);
178 s8[s8idx++] = 0x80 | ((utfchar >> 6) & 0x3f);
179 s8[s8idx++] = 0x80 | (utfchar & 0x3f);
180 }
181 }
182 return (s8);
183 }
184
185 void
186 utf8_to_utf16(const uint8_t *s8, uint16_t *s16, size_t s16len)
187 {
188 size_t s16idx, s8idx, s8len;
189 uint32_t utfchar = 0;
190 unsigned int c, utfbytes;
191
192 s8len = 0;
193 while (s8[s8len++] != 0)
194 ;
195 s8idx = s16idx = 0;
196 utfbytes = 0;
197 do {
198 c = s8[s8idx++];
199 if ((c & 0xc0) != 0x80) {
200 /* Initial characters. */
201 if (utfbytes != 0) {
202 /* Incomplete encoding. */
203 s16[s16idx++] = htole16(0xfffd);
204 if (s16idx == s16len) {
205 s16[--s16idx] = 0;
206 return;
207 }
208 }
209 if ((c & 0xf8) == 0xf0) {
210 utfchar = c & 0x07;
211 utfbytes = 3;
212 } else if ((c & 0xf0) == 0xe0) {
213 utfchar = c & 0x0f;
214 utfbytes = 2;
215 } else if ((c & 0xe0) == 0xc0) {
216 utfchar = c & 0x1f;
217 utfbytes = 1;
218 } else {
219 utfchar = c & 0x7f;
220 utfbytes = 0;
221 }
222 } else {
223 /* Followup characters. */
224 if (utfbytes > 0) {
225 utfchar = (utfchar << 6) + (c & 0x3f);
226 utfbytes--;
227 } else if (utfbytes == 0)
228 utfbytes = -1;
229 }
230 if (utfbytes == 0) {
231 if (utfchar >= 0x10000 && s16idx + 2 >= s16len)
232 utfchar = 0xfffd;
233 if (utfchar >= 0x10000) {
234 s16[s16idx++] =
235 htole16(0xd800 | ((utfchar>>10)-0x40));
236 s16[s16idx++] =
237 htole16(0xdc00 | (utfchar & 0x3ff));
238 } else
239 s16[s16idx++] = htole16(utfchar);
240 if (s16idx == s16len) {
241 s16[--s16idx] = 0;
242 return;
243 }
244 }
245 } while (c != 0);
246 }
247
248 void*
249 gpt_read(int fd, off_t lba, size_t count)
250 {
251 off_t ofs;
252 void *buf;
253
254 count *= secsz;
255 buf = malloc(count);
256 if (buf == NULL)
257 return (NULL);
258
259 ofs = lba * secsz;
260 if (lseek(fd, ofs, SEEK_SET) == ofs &&
261 read(fd, buf, count) == (ssize_t)count)
262 return (buf);
263
264 free(buf);
265 return (NULL);
266 }
267
268 int
269 gpt_write(int fd, map_t *map)
270 {
271 off_t ofs;
272 size_t count;
273
274 count = map->map_size * secsz;
275 ofs = map->map_start * secsz;
276 if (lseek(fd, ofs, SEEK_SET) == ofs &&
277 write(fd, map->map_data, count) == (ssize_t)count)
278 return (0);
279 return (-1);
280 }
281
282 static int
283 gpt_mbr(int fd, off_t lba)
284 {
285 struct mbr *mbr;
286 map_t *m, *p;
287 off_t size, start;
288 unsigned int i, pmbr;
289
290 mbr = gpt_read(fd, lba, 1);
291 if (mbr == NULL)
292 return (-1);
293
294 if (mbr->mbr_sig != htole16(MBR_SIG)) {
295 if (verbose)
296 warnx("%s: MBR not found at sector %llu", device_name,
297 (long long)lba);
298 free(mbr);
299 return (0);
300 }
301
302 /*
303 * Differentiate between a regular MBR and a PMBR. This is more
304 * convenient in general. A PMBR is one with a single partition
305 * of type 0xee.
306 */
307 pmbr = 0;
308 for (i = 0; i < 4; i++) {
309 if (mbr->mbr_part[i].part_typ == MBR_PTYPE_UNUSED)
310 continue;
311 if (mbr->mbr_part[i].part_typ == MBR_PTYPE_PMBR)
312 pmbr++;
313 else
314 break;
315 }
316 if (pmbr && i == 4 && lba == 0) {
317 if (pmbr != 1)
318 warnx("%s: Suspicious PMBR at sector %llu",
319 device_name, (long long)lba);
320 else if (verbose > 1)
321 warnx("%s: PMBR at sector %llu", device_name,
322 (long long)lba);
323 p = map_add(lba, 1LL, MAP_TYPE_PMBR, mbr);
324 return ((p == NULL) ? -1 : 0);
325 }
326 if (pmbr)
327 warnx("%s: Suspicious MBR at sector %llu", device_name,
328 (long long)lba);
329 else if (verbose > 1)
330 warnx("%s: MBR at sector %llu", device_name, (long long)lba);
331
332 p = map_add(lba, 1LL, MAP_TYPE_MBR, mbr);
333 if (p == NULL)
334 return (-1);
335 for (i = 0; i < 4; i++) {
336 if (mbr->mbr_part[i].part_typ == MBR_PTYPE_UNUSED ||
337 mbr->mbr_part[i].part_typ == MBR_PTYPE_PMBR)
338 continue;
339 start = le16toh(mbr->mbr_part[i].part_start_hi);
340 start = (start << 16) + le16toh(mbr->mbr_part[i].part_start_lo);
341 size = le16toh(mbr->mbr_part[i].part_size_hi);
342 size = (size << 16) + le16toh(mbr->mbr_part[i].part_size_lo);
343 if (start == 0 && size == 0) {
344 warnx("%s: Malformed MBR at sector %llu", device_name,
345 (long long)lba);
346 continue;
347 }
348 /* start is relative to the offset of the MBR itself. */
349 start += lba;
350 if (verbose > 2)
351 warnx("%s: MBR part: type=%d, start=%llu, size=%llu",
352 device_name, mbr->mbr_part[i].part_typ,
353 (long long)start, (long long)size);
354 if (mbr->mbr_part[i].part_typ != MBR_PTYPE_EXT_LBA) {
355 m = map_add(start, size, MAP_TYPE_MBR_PART, p);
356 if (m == NULL)
357 return (-1);
358 m->map_index = i + 1;
359 } else {
360 if (gpt_mbr(fd, start) == -1)
361 return (-1);
362 }
363 }
364 return (0);
365 }
366
367 #ifndef HAVE_NBTOOL_CONFIG_H
368 static int
369 drvctl(const char *name, u_int *sector_size, off_t *media_size)
370 {
371 prop_dictionary_t command_dict, args_dict, results_dict, data_dict,
372 disk_info, geometry;
373 prop_string_t string;
374 prop_number_t number;
375 int dfd, res;
376 char *dname, *p;
377
378 if ((dfd = open("/dev/drvctl", O_RDONLY)) == -1) {
379 warn("%s: /dev/drvctl", __func__);
380 return -1;
381 }
382
383 command_dict = prop_dictionary_create();
384 args_dict = prop_dictionary_create();
385
386 string = prop_string_create_cstring_nocopy("get-properties");
387 prop_dictionary_set(command_dict, "drvctl-command", string);
388 prop_object_release(string);
389
390 if ((dname = strdup(name[0] == 'r' ? name + 1 : name)) == NULL) {
391 (void)close(dfd);
392 return -1;
393 }
394 for (p = dname; *p; p++)
395 continue;
396 for (--p; p >= dname && !isdigit((unsigned char)*p); *p-- = '\0')
397 continue;
398
399 string = prop_string_create_cstring(dname);
400 free(dname);
401 prop_dictionary_set(args_dict, "device-name", string);
402 prop_object_release(string);
403
404 prop_dictionary_set(command_dict, "drvctl-arguments", args_dict);
405 prop_object_release(args_dict);
406
407 res = prop_dictionary_sendrecv_ioctl(command_dict, dfd, DRVCTLCOMMAND,
408 &results_dict);
409 (void)close(dfd);
410 prop_object_release(command_dict);
411 if (res) {
412 warn("%s: prop_dictionary_sendrecv_ioctl", __func__);
413 errno = res;
414 return -1;
415 }
416
417 number = prop_dictionary_get(results_dict, "drvctl-error");
418 if ((errno = prop_number_integer_value(number)) != 0)
419 return -1;
420
421 data_dict = prop_dictionary_get(results_dict, "drvctl-result-data");
422 if (data_dict == NULL)
423 goto out;
424
425 disk_info = prop_dictionary_get(data_dict, "disk-info");
426 if (disk_info == NULL)
427 goto out;
428
429 geometry = prop_dictionary_get(disk_info, "geometry");
430 if (geometry == NULL)
431 goto out;
432
433 number = prop_dictionary_get(geometry, "sector-size");
434 if (number == NULL)
435 goto out;
436
437 *sector_size = prop_number_integer_value(number);
438
439 number = prop_dictionary_get(geometry, "sectors-per-unit");
440 if (number == NULL)
441 goto out;
442
443 *media_size = prop_number_integer_value(number) * *sector_size;
444
445 return 0;
446 out:
447 errno = EINVAL;
448 return -1;
449 }
450 #endif
451
452 int
453 gpt_gpt(int fd, off_t lba, int found)
454 {
455 off_t size;
456 struct gpt_ent *ent;
457 struct gpt_hdr *hdr;
458 char *p;
459 map_t *m;
460 size_t blocks, tblsz;
461 unsigned int i;
462 uint32_t crc;
463
464 hdr = gpt_read(fd, lba, 1);
465 if (hdr == NULL)
466 return (-1);
467
468 if (memcmp(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig)))
469 goto fail_hdr;
470
471 crc = le32toh(hdr->hdr_crc_self);
472 hdr->hdr_crc_self = 0;
473 if (crc32(hdr, le32toh(hdr->hdr_size)) != crc) {
474 if (verbose)
475 warnx("%s: Bad CRC in GPT header at sector %llu",
476 device_name, (long long)lba);
477 goto fail_hdr;
478 }
479
480 tblsz = le32toh(hdr->hdr_entries) * le32toh(hdr->hdr_entsz);
481 blocks = tblsz / secsz + ((tblsz % secsz) ? 1 : 0);
482
483 /* Use generic pointer to deal with hdr->hdr_entsz != sizeof(*ent). */
484 p = gpt_read(fd, le64toh(hdr->hdr_lba_table), blocks);
485 if (p == NULL) {
486 if (found) {
487 if (verbose)
488 warn("%s: Cannot read LBA table at sector %llu",
489 device_name, (unsigned long long)
490 le64toh(hdr->hdr_lba_table));
491 return (-1);
492 }
493 goto fail_hdr;
494 }
495
496 if (crc32(p, tblsz) != le32toh(hdr->hdr_crc_table)) {
497 if (verbose)
498 warnx("%s: Bad CRC in GPT table at sector %llu",
499 device_name,
500 (long long)le64toh(hdr->hdr_lba_table));
501 goto fail_ent;
502 }
503
504 if (verbose > 1)
505 warnx("%s: %s GPT at sector %llu", device_name,
506 (lba == 1) ? "Pri" : "Sec", (long long)lba);
507
508 m = map_add(lba, 1, (lba == 1)
509 ? MAP_TYPE_PRI_GPT_HDR : MAP_TYPE_SEC_GPT_HDR, hdr);
510 if (m == NULL)
511 return (-1);
512
513 m = map_add(le64toh(hdr->hdr_lba_table), blocks, (lba == 1)
514 ? MAP_TYPE_PRI_GPT_TBL : MAP_TYPE_SEC_GPT_TBL, p);
515 if (m == NULL)
516 return (-1);
517
518 if (lba != 1)
519 return (1);
520
521 for (i = 0; i < le32toh(hdr->hdr_entries); i++) {
522 ent = (void*)(p + i * le32toh(hdr->hdr_entsz));
523 if (gpt_uuid_is_nil(ent->ent_type))
524 continue;
525
526 size = le64toh(ent->ent_lba_end) - le64toh(ent->ent_lba_start) +
527 1LL;
528 if (verbose > 2) {
529 char buf[128];
530 gpt_uuid_snprintf(buf, sizeof(buf), "%s",
531 ent->ent_type);
532 warnx("%s: GPT partition: type=%s, start=%llu, "
533 "size=%llu", device_name, buf,
534 (long long)le64toh(ent->ent_lba_start),
535 (long long)size);
536 }
537 m = map_add(le64toh(ent->ent_lba_start), size,
538 MAP_TYPE_GPT_PART, ent);
539 if (m == NULL)
540 return (-1);
541 m->map_index = i + 1;
542 }
543 return (1);
544
545 fail_ent:
546 free(p);
547
548 fail_hdr:
549 free(hdr);
550 return (0);
551 }
552
553 int
554 gpt_open(const char *dev)
555 {
556 struct stat sb;
557 int fd, mode, found;
558
559 mode = readonly ? O_RDONLY : O_RDWR|O_EXCL;
560
561 device_arg = dev;
562 fd = opendisk(dev, mode, device_path, sizeof(device_path), 0);
563 if (fd == -1)
564 return -1;
565 if (strncmp(device_path, _PATH_DEV, strlen(_PATH_DEV)) == 0)
566 device_name = device_path + strlen(_PATH_DEV);
567 else
568 device_name = device_path;
569
570 if (fstat(fd, &sb) == -1)
571 goto close;
572
573 if ((sb.st_mode & S_IFMT) != S_IFREG) {
574 #ifdef DIOCGSECTORSIZE
575 if (ioctl(fd, DIOCGSECTORSIZE, &secsz) == -1 ||
576 ioctl(fd, DIOCGMEDIASIZE, &mediasz) == -1)
577 goto close;
578 #endif
579 #ifndef HAVE_NBTOOL_CONFIG_H
580 if (drvctl(device_name, &secsz, &mediasz) == -1)
581 goto close;
582 #endif
583 } else {
584 secsz = 512; /* Fixed size for files. */
585 if (sb.st_size % secsz) {
586 errno = EINVAL;
587 goto close;
588 }
589 mediasz = sb.st_size;
590 }
591
592 /*
593 * We require an absolute minimum of 6 sectors. One for the MBR,
594 * 2 for the GPT header, 2 for the GPT table and one to hold some
595 * user data. Let's catch this extreme border case here so that
596 * we don't have to worry about it later.
597 */
598 if (mediasz / secsz < 6) {
599 errno = ENODEV;
600 goto close;
601 }
602
603 if (verbose)
604 warnx("%s: mediasize=%llu; sectorsize=%u; blocks=%llu",
605 device_name, (long long)mediasz, secsz,
606 (long long)(mediasz / secsz));
607
608 map_init(mediasz / secsz);
609
610 if (gpt_mbr(fd, 0LL) == -1)
611 goto close;
612 if ((found = gpt_gpt(fd, 1LL, 1)) == -1)
613 goto close;
614 if (gpt_gpt(fd, mediasz / secsz - 1LL, found) == -1)
615 goto close;
616
617 return (fd);
618
619 close:
620 close(fd);
621 return (-1);
622 }
623
624 void
625 gpt_close(int fd)
626 {
627 /* XXX post processing? */
628 close(fd);
629 }
630
631 static struct {
632 int (*fptr)(int, char *[]);
633 const char *name;
634 } cmdsw[] = {
635 { cmd_add, "add" },
636 #ifndef HAVE_NBTOOL_CONFIG_H
637 { cmd_backup, "backup" },
638 #endif
639 { cmd_biosboot, "biosboot" },
640 { cmd_create, "create" },
641 { cmd_destroy, "destroy" },
642 { NULL, "help" },
643 { cmd_label, "label" },
644 { cmd_migrate, "migrate" },
645 { cmd_recover, "recover" },
646 { cmd_remove, "remove" },
647 { NULL, "rename" },
648 { cmd_resize, "resize" },
649 { cmd_resizedisk, "resizedisk" },
650 #ifndef HAVE_NBTOOL_CONFIG_H
651 { cmd_restore, "restore" },
652 #endif
653 { cmd_set, "set" },
654 { cmd_show, "show" },
655 { cmd_type, "type" },
656 { cmd_unset, "unset" },
657 { NULL, "verify" },
658 { NULL, NULL }
659 };
660
661 __dead static void
662 usage(void)
663 {
664 extern const char addmsg1[], addmsg2[], biosbootmsg[];
665 extern const char createmsg[], destroymsg[], labelmsg1[], labelmsg2[];
666 extern const char labelmsg3[], migratemsg[], recovermsg[], removemsg1[];
667 extern const char removemsg2[], resizemsg[], resizediskmsg[];
668 extern const char setmsg[], showmsg[], typemsg1[];
669 extern const char typemsg2[], typemsg3[], unsetmsg[];
670 #ifndef HAVE_NBTOOL_CONFIG_H
671 extern const char backupmsg[], restoremsg[];
672 #endif
673
674
675 fprintf(stderr,
676 "usage: %s %s\n"
677 " %s %s\n"
678 #ifndef HAVE_NBTOOL_CONFIG_H
679 " %s %s\n"
680 #endif
681 " %s %s\n"
682 " %s %s\n"
683 " %s %s\n"
684 " %s %s\n"
685 " %s %s\n"
686 " %*s %s\n"
687 " %s %s\n"
688 " %s %s\n"
689 " %s %s\n"
690 " %s %s\n"
691 " %s %s\n"
692 " %s %s\n"
693 " %s %s\n"
694 #ifndef HAVE_NBTOOL_CONFIG_H
695 " %s %s\n"
696 #endif
697 " %s %s\n"
698 " %s %s\n"
699 " %s %s\n"
700 " %*s %s\n"
701 " %s %s\n",
702 getprogname(), addmsg1,
703 getprogname(), addmsg2,
704 #ifndef HAVE_NBTOOL_CONFIG_H
705 getprogname(), backupmsg,
706 #endif
707 getprogname(), biosbootmsg,
708 getprogname(), createmsg,
709 getprogname(), destroymsg,
710 getprogname(), labelmsg1,
711 getprogname(), labelmsg2,
712 (int)strlen(getprogname()), "", labelmsg3,
713 getprogname(), migratemsg,
714 getprogname(), recovermsg,
715 getprogname(), removemsg1,
716 getprogname(), removemsg2,
717 getprogname(), resizemsg,
718 getprogname(), resizediskmsg,
719 #ifndef HAVE_NBTOOL_CONFIG_H
720 getprogname(), restoremsg,
721 #endif
722 getprogname(), setmsg,
723 getprogname(), showmsg,
724 getprogname(), typemsg1,
725 getprogname(), typemsg2,
726 (int)strlen(getprogname()), "", typemsg3,
727 getprogname(), unsetmsg);
728 exit(1);
729 }
730
731 static void
732 prefix(const char *cmd)
733 {
734 char *pfx;
735 const char *prg;
736
737 prg = getprogname();
738 pfx = malloc(strlen(prg) + strlen(cmd) + 2);
739 /* Don't bother failing. It's not important */
740 if (pfx == NULL)
741 return;
742
743 sprintf(pfx, "%s %s", prg, cmd);
744 setprogname(pfx);
745 }
746
747 int
748 main(int argc, char *argv[])
749 {
750 char *cmd, *p;
751 int ch, i;
752
753 /* Get the generic options */
754 while ((ch = getopt(argc, argv, "p:rv")) != -1) {
755 switch(ch) {
756 case 'p':
757 if (parts > 0)
758 usage();
759 parts = strtoul(optarg, &p, 10);
760 if (*p != 0 || parts < 1)
761 usage();
762 break;
763 case 'r':
764 readonly = 1;
765 break;
766 case 'v':
767 verbose++;
768 break;
769 default:
770 usage();
771 }
772 }
773 if (!parts)
774 parts = 128;
775
776 if (argc == optind)
777 usage();
778
779 cmd = argv[optind++];
780 for (i = 0; cmdsw[i].name != NULL && strcmp(cmd, cmdsw[i].name); i++);
781
782 if (cmdsw[i].fptr == NULL)
783 errx(1, "unknown command: %s", cmd);
784
785 prefix(cmd);
786 return ((*cmdsw[i].fptr)(argc, argv));
787 }
788