gpt.c revision 1.39 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.39 2014/11/17 07:15:28 mlelstv 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 <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <unistd.h>
56 #include <ctype.h>
57 #ifndef HAVE_NBTOOL_CONFIG_H
58 #include <prop/proplib.h>
59 #include <sys/drvctlio.h>
60 #include <sys/disk.h>
61 #endif
62
63 #include "map.h"
64 #include "gpt.h"
65
66 char device_path[MAXPATHLEN];
67 const char *device_arg;
68 const 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 (*sector_size && *media_size)
379 return 0;
380
381 if ((dfd = open("/dev/drvctl", O_RDONLY)) == -1) {
382 warn("%s: /dev/drvctl", __func__);
383 return -1;
384 }
385
386 command_dict = prop_dictionary_create();
387 args_dict = prop_dictionary_create();
388
389 string = prop_string_create_cstring_nocopy("get-properties");
390 prop_dictionary_set(command_dict, "drvctl-command", string);
391 prop_object_release(string);
392
393 if ((dname = strdup(name[0] == 'r' ? name + 1 : name)) == NULL) {
394 (void)close(dfd);
395 return -1;
396 }
397 for (p = dname; *p; p++)
398 continue;
399 for (--p; p >= dname && !isdigit((unsigned char)*p); *p-- = '\0')
400 continue;
401
402 string = prop_string_create_cstring(dname);
403 free(dname);
404 prop_dictionary_set(args_dict, "device-name", string);
405 prop_object_release(string);
406
407 prop_dictionary_set(command_dict, "drvctl-arguments", args_dict);
408 prop_object_release(args_dict);
409
410 res = prop_dictionary_sendrecv_ioctl(command_dict, dfd, DRVCTLCOMMAND,
411 &results_dict);
412 (void)close(dfd);
413 prop_object_release(command_dict);
414 if (res) {
415 warn("%s: prop_dictionary_sendrecv_ioctl", __func__);
416 errno = res;
417 return -1;
418 }
419
420 number = prop_dictionary_get(results_dict, "drvctl-error");
421 if ((errno = prop_number_integer_value(number)) != 0)
422 return -1;
423
424 data_dict = prop_dictionary_get(results_dict, "drvctl-result-data");
425 if (data_dict == NULL)
426 goto out;
427
428 disk_info = prop_dictionary_get(data_dict, "disk-info");
429 if (disk_info == NULL)
430 goto out;
431
432 geometry = prop_dictionary_get(disk_info, "geometry");
433 if (geometry == NULL)
434 goto out;
435
436 number = prop_dictionary_get(geometry, "sector-size");
437 if (number == NULL)
438 goto out;
439
440 if (*sector_size == 0)
441 *sector_size = prop_number_integer_value(number);
442
443 number = prop_dictionary_get(geometry, "sectors-per-unit");
444 if (number == NULL)
445 goto out;
446
447 if (*media_size == 0)
448 *media_size = prop_number_integer_value(number) * *sector_size;
449
450 return 0;
451 out:
452 errno = EINVAL;
453 return -1;
454 }
455 #endif
456
457 int
458 gpt_gpt(int fd, off_t lba, int found)
459 {
460 off_t size;
461 struct gpt_ent *ent;
462 struct gpt_hdr *hdr;
463 char *p;
464 map_t *m;
465 size_t blocks, tblsz;
466 unsigned int i;
467 uint32_t crc;
468
469 hdr = gpt_read(fd, lba, 1);
470 if (hdr == NULL)
471 return (-1);
472
473 if (memcmp(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig)))
474 goto fail_hdr;
475
476 crc = le32toh(hdr->hdr_crc_self);
477 hdr->hdr_crc_self = 0;
478 if (crc32(hdr, le32toh(hdr->hdr_size)) != crc) {
479 if (verbose)
480 warnx("%s: Bad CRC in GPT header at sector %llu",
481 device_name, (long long)lba);
482 goto fail_hdr;
483 }
484
485 tblsz = le32toh(hdr->hdr_entries) * le32toh(hdr->hdr_entsz);
486 blocks = tblsz / secsz + ((tblsz % secsz) ? 1 : 0);
487
488 /* Use generic pointer to deal with hdr->hdr_entsz != sizeof(*ent). */
489 p = gpt_read(fd, le64toh(hdr->hdr_lba_table), blocks);
490 if (p == NULL) {
491 if (found) {
492 if (verbose)
493 warn("%s: Cannot read LBA table at sector %llu",
494 device_name, (unsigned long long)
495 le64toh(hdr->hdr_lba_table));
496 return (-1);
497 }
498 goto fail_hdr;
499 }
500
501 if (crc32(p, tblsz) != le32toh(hdr->hdr_crc_table)) {
502 if (verbose)
503 warnx("%s: Bad CRC in GPT table at sector %llu",
504 device_name,
505 (long long)le64toh(hdr->hdr_lba_table));
506 goto fail_ent;
507 }
508
509 if (verbose > 1)
510 warnx("%s: %s GPT at sector %llu", device_name,
511 (lba == 1) ? "Pri" : "Sec", (long long)lba);
512
513 m = map_add(lba, 1, (lba == 1)
514 ? MAP_TYPE_PRI_GPT_HDR : MAP_TYPE_SEC_GPT_HDR, hdr);
515 if (m == NULL)
516 return (-1);
517
518 m = map_add(le64toh(hdr->hdr_lba_table), blocks, (lba == 1)
519 ? MAP_TYPE_PRI_GPT_TBL : MAP_TYPE_SEC_GPT_TBL, p);
520 if (m == NULL)
521 return (-1);
522
523 if (lba != 1)
524 return (1);
525
526 for (i = 0; i < le32toh(hdr->hdr_entries); i++) {
527 ent = (void*)(p + i * le32toh(hdr->hdr_entsz));
528 if (gpt_uuid_is_nil(ent->ent_type))
529 continue;
530
531 size = le64toh(ent->ent_lba_end) - le64toh(ent->ent_lba_start) +
532 1LL;
533 if (verbose > 2) {
534 char buf[128];
535 gpt_uuid_snprintf(buf, sizeof(buf), "%s",
536 ent->ent_type);
537 warnx("%s: GPT partition: type=%s, start=%llu, "
538 "size=%llu", device_name, buf,
539 (long long)le64toh(ent->ent_lba_start),
540 (long long)size);
541 }
542 m = map_add(le64toh(ent->ent_lba_start), size,
543 MAP_TYPE_GPT_PART, ent);
544 if (m == NULL)
545 return (-1);
546 m->map_index = i + 1;
547 }
548 return (1);
549
550 fail_ent:
551 free(p);
552
553 fail_hdr:
554 free(hdr);
555 return (0);
556 }
557
558 int
559 gpt_open(const char *dev)
560 {
561 struct stat sb;
562 int fd, mode, found;
563
564 mode = readonly ? O_RDONLY : O_RDWR|O_EXCL;
565
566 device_arg = device_name = dev;
567 fd = opendisk(dev, mode, device_path, sizeof(device_path), 0);
568 if (fd == -1)
569 return -1;
570 if (strncmp(device_path, _PATH_DEV, strlen(_PATH_DEV)) == 0)
571 device_name = device_path + strlen(_PATH_DEV);
572 else
573 device_name = device_path;
574
575 if (fstat(fd, &sb) == -1)
576 goto close;
577
578 if ((sb.st_mode & S_IFMT) != S_IFREG) {
579 #ifdef DIOCGSECTORSIZE
580 if ((secsz == 0 && ioctl(fd, DIOCGSECTORSIZE, &secsz) == -1) ||
581 (mediasz == 0 && ioctl(fd, DIOCGMEDIASIZE, &mediasz) == -1))
582 goto close;
583 #endif
584 #ifndef HAVE_NBTOOL_CONFIG_H
585 if (drvctl(device_name, &secsz, &mediasz) == -1)
586 goto close;
587 #endif
588 if (secsz == 0 || mediasz == 0)
589 errx(1, "Please specify sector/media size");
590 } else {
591 if (secsz == 0)
592 secsz = 512; /* Fixed size for files. */
593 if (mediasz == 0) {
594 if (sb.st_size % secsz) {
595 errno = EINVAL;
596 goto close;
597 }
598 mediasz = sb.st_size;
599 }
600 }
601
602 /*
603 * We require an absolute minimum of 6 sectors. One for the MBR,
604 * 2 for the GPT header, 2 for the GPT table and one to hold some
605 * user data. Let's catch this extreme border case here so that
606 * we don't have to worry about it later.
607 */
608 if (mediasz / secsz < 6) {
609 errno = ENODEV;
610 goto close;
611 }
612
613 if (verbose)
614 warnx("%s: mediasize=%llu; sectorsize=%u; blocks=%llu",
615 device_name, (long long)mediasz, secsz,
616 (long long)(mediasz / secsz));
617
618 map_init(mediasz / secsz);
619
620 if (gpt_mbr(fd, 0LL) == -1)
621 goto close;
622 if ((found = gpt_gpt(fd, 1LL, 1)) == -1)
623 goto close;
624 if (gpt_gpt(fd, mediasz / secsz - 1LL, found) == -1)
625 goto close;
626
627 return (fd);
628
629 close:
630 close(fd);
631 return (-1);
632 }
633
634 void
635 gpt_close(int fd)
636 {
637 /* XXX post processing? */
638 close(fd);
639 }
640
641 static struct {
642 int (*fptr)(int, char *[]);
643 const char *name;
644 } cmdsw[] = {
645 { cmd_add, "add" },
646 #ifndef HAVE_NBTOOL_CONFIG_H
647 { cmd_backup, "backup" },
648 #endif
649 { cmd_biosboot, "biosboot" },
650 { cmd_create, "create" },
651 { cmd_destroy, "destroy" },
652 { NULL, "help" },
653 { cmd_label, "label" },
654 { cmd_migrate, "migrate" },
655 { cmd_recover, "recover" },
656 { cmd_remove, "remove" },
657 { NULL, "rename" },
658 { cmd_resize, "resize" },
659 { cmd_resizedisk, "resizedisk" },
660 #ifndef HAVE_NBTOOL_CONFIG_H
661 { cmd_restore, "restore" },
662 #endif
663 { cmd_set, "set" },
664 { cmd_show, "show" },
665 { cmd_type, "type" },
666 { cmd_unset, "unset" },
667 { NULL, "verify" },
668 { NULL, NULL }
669 };
670
671 __dead static void
672 usage(void)
673 {
674 extern const char addmsg1[], addmsg2[], biosbootmsg[];
675 extern const char createmsg[], destroymsg[], labelmsg1[], labelmsg2[];
676 extern const char labelmsg3[], migratemsg[], recovermsg[], removemsg1[];
677 extern const char removemsg2[], resizemsg[], resizediskmsg[];
678 extern const char setmsg[], showmsg[], typemsg1[];
679 extern const char typemsg2[], typemsg3[], unsetmsg[];
680 #ifndef HAVE_NBTOOL_CONFIG_H
681 extern const char backupmsg[], restoremsg[];
682 #endif
683 const char *p = getprogname();
684 const char *f =
685 "[-rv] [-m <mediasize>] [-p <partitionnum>] [-s <sectorsize>]";
686
687 fprintf(stderr,
688 "Usage: %s %s <command> [<args>]\n", p, f);
689 fprintf(stderr,
690 "Commands:\n"
691 #ifndef HAVE_NBTOOL_CONFIG_H
692 " %s\n"
693 " %s\n"
694 #endif
695 " %s\n"
696 " %s\n"
697 " %s\n"
698 " %s\n"
699 " %s\n"
700 " %s\n"
701 " %s\n"
702 " %s\n"
703 " %s\n"
704 " %s\n"
705 " %s\n"
706 " %s\n"
707 " %s\n"
708 " %s\n"
709 " %s\n"
710 " %s\n"
711 " %s\n"
712 " %s\n"
713 " %s\n"
714 " %s\n",
715 addmsg1, addmsg2,
716 #ifndef HAVE_NBTOOL_CONFIG_H
717 backupmsg,
718 #endif
719 biosbootmsg, createmsg, destroymsg,
720 labelmsg1, labelmsg2, labelmsg3,
721 migratemsg, recovermsg,
722 removemsg1, removemsg2,
723 resizemsg, resizediskmsg,
724 #ifndef HAVE_NBTOOL_CONFIG_H
725 restoremsg,
726 #endif
727 setmsg, showmsg,
728 typemsg1, typemsg2, typemsg3,
729 unsetmsg);
730 exit(1);
731 }
732
733 static void
734 prefix(const char *cmd)
735 {
736 char *pfx;
737 const char *prg;
738
739 prg = getprogname();
740 pfx = malloc(strlen(prg) + strlen(cmd) + 2);
741 /* Don't bother failing. It's not important */
742 if (pfx == NULL)
743 return;
744
745 sprintf(pfx, "%s %s", prg, cmd);
746 setprogname(pfx);
747 }
748
749 int
750 main(int argc, char *argv[])
751 {
752 char *cmd, *p;
753 int ch, i;
754
755 /* Get the generic options */
756 while ((ch = getopt(argc, argv, "m:p:rs:v")) != -1) {
757 switch(ch) {
758 case 'm':
759 if (mediasz > 0)
760 usage();
761 mediasz = strtoul(optarg, &p, 10);
762 if (*p != 0 || mediasz < 1)
763 usage();
764 break;
765 case 'p':
766 if (parts > 0)
767 usage();
768 parts = strtoul(optarg, &p, 10);
769 if (*p != 0 || parts < 1)
770 usage();
771 break;
772 case 'r':
773 readonly = 1;
774 break;
775 case 's':
776 if (secsz > 0)
777 usage();
778 secsz = strtoul(optarg, &p, 10);
779 if (*p != 0 || secsz < 1)
780 usage();
781 break;
782 case 'v':
783 verbose++;
784 break;
785 default:
786 usage();
787 }
788 }
789 if (!parts)
790 parts = 128;
791
792 if (argc == optind)
793 usage();
794
795 cmd = argv[optind++];
796 for (i = 0; cmdsw[i].name != NULL && strcmp(cmd, cmdsw[i].name); i++);
797
798 if (cmdsw[i].fptr == NULL)
799 errx(1, "unknown command: %s", cmd);
800
801 prefix(cmd);
802 return ((*cmdsw[i].fptr)(argc, argv));
803 }
804