gpt.c revision 1.46 1 1.1 christos /*-
2 1.1 christos * Copyright (c) 2002 Marcel Moolenaar
3 1.1 christos * All rights reserved.
4 1.1 christos *
5 1.1 christos * Redistribution and use in source and binary forms, with or without
6 1.1 christos * modification, are permitted provided that the following conditions
7 1.1 christos * are met:
8 1.1 christos *
9 1.1 christos * 1. Redistributions of source code must retain the above copyright
10 1.1 christos * notice, this list of conditions and the following disclaimer.
11 1.1 christos * 2. Redistributions in binary form must reproduce the above copyright
12 1.1 christos * notice, this list of conditions and the following disclaimer in the
13 1.1 christos * documentation and/or other materials provided with the distribution.
14 1.1 christos *
15 1.1 christos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 1.1 christos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 1.1 christos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 1.1 christos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 1.1 christos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 1.1 christos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 1.1 christos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 1.1 christos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 1.1 christos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 1.1 christos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 1.1 christos *
26 1.1 christos * CRC32 code derived from work by Gary S. Brown.
27 1.1 christos */
28 1.1 christos
29 1.31 christos #if HAVE_NBTOOL_CONFIG_H
30 1.31 christos #include "nbtool_config.h"
31 1.31 christos #endif
32 1.31 christos
33 1.1 christos #include <sys/cdefs.h>
34 1.2 christos #ifdef __FBSDID
35 1.1 christos __FBSDID("$FreeBSD: src/sbin/gpt/gpt.c,v 1.16 2006/07/07 02:44:23 marcel Exp $");
36 1.2 christos #endif
37 1.2 christos #ifdef __RCSID
38 1.46 christos __RCSID("$NetBSD: gpt.c,v 1.46 2015/11/30 19:59:34 christos Exp $");
39 1.2 christos #endif
40 1.1 christos
41 1.1 christos #include <sys/param.h>
42 1.1 christos #include <sys/types.h>
43 1.1 christos #include <sys/stat.h>
44 1.2 christos #include <sys/ioctl.h>
45 1.25 jakllsch #include <sys/bootblock.h>
46 1.1 christos
47 1.1 christos #include <err.h>
48 1.1 christos #include <errno.h>
49 1.1 christos #include <fcntl.h>
50 1.1 christos #include <paths.h>
51 1.1 christos #include <stddef.h>
52 1.42 christos #include <stdarg.h>
53 1.1 christos #include <stdio.h>
54 1.1 christos #include <stdlib.h>
55 1.1 christos #include <string.h>
56 1.1 christos #include <unistd.h>
57 1.32 christos #include <ctype.h>
58 1.1 christos
59 1.1 christos #include "map.h"
60 1.1 christos #include "gpt.h"
61 1.1 christos
62 1.1 christos char device_path[MAXPATHLEN];
63 1.9 uebayasi const char *device_arg;
64 1.39 mlelstv const char *device_name;
65 1.1 christos
66 1.1 christos off_t mediasz;
67 1.1 christos
68 1.1 christos u_int parts;
69 1.1 christos u_int secsz;
70 1.1 christos
71 1.46 christos int readonly, verbose, quiet, nosync;
72 1.46 christos
73 1.46 christos static int modified;
74 1.1 christos
75 1.1 christos static uint32_t crc32_tab[] = {
76 1.1 christos 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
77 1.1 christos 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
78 1.1 christos 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
79 1.1 christos 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
80 1.1 christos 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
81 1.1 christos 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
82 1.1 christos 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
83 1.1 christos 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
84 1.1 christos 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
85 1.1 christos 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
86 1.1 christos 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
87 1.1 christos 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
88 1.1 christos 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
89 1.1 christos 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
90 1.1 christos 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
91 1.1 christos 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
92 1.1 christos 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
93 1.1 christos 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
94 1.1 christos 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
95 1.1 christos 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
96 1.1 christos 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
97 1.1 christos 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
98 1.1 christos 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
99 1.1 christos 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
100 1.1 christos 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
101 1.1 christos 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
102 1.1 christos 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
103 1.1 christos 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
104 1.1 christos 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
105 1.1 christos 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
106 1.1 christos 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
107 1.1 christos 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
108 1.1 christos 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
109 1.1 christos 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
110 1.1 christos 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
111 1.1 christos 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
112 1.1 christos 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
113 1.1 christos 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
114 1.1 christos 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
115 1.1 christos 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
116 1.1 christos 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
117 1.1 christos 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
118 1.1 christos 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
119 1.1 christos };
120 1.1 christos
121 1.1 christos uint32_t
122 1.1 christos crc32(const void *buf, size_t size)
123 1.1 christos {
124 1.1 christos const uint8_t *p;
125 1.1 christos uint32_t crc;
126 1.1 christos
127 1.1 christos p = buf;
128 1.1 christos crc = ~0U;
129 1.1 christos
130 1.1 christos while (size--)
131 1.1 christos crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
132 1.1 christos
133 1.1 christos return crc ^ ~0U;
134 1.1 christos }
135 1.1 christos
136 1.1 christos uint8_t *
137 1.1 christos utf16_to_utf8(uint16_t *s16)
138 1.1 christos {
139 1.1 christos static uint8_t *s8 = NULL;
140 1.1 christos static size_t s8len = 0;
141 1.1 christos size_t s8idx, s16idx, s16len;
142 1.1 christos uint32_t utfchar;
143 1.1 christos unsigned int c;
144 1.1 christos
145 1.1 christos s16len = 0;
146 1.1 christos while (s16[s16len++] != 0)
147 1.1 christos ;
148 1.1 christos if (s8len < s16len * 3) {
149 1.1 christos if (s8 != NULL)
150 1.1 christos free(s8);
151 1.1 christos s8len = s16len * 3;
152 1.1 christos s8 = calloc(s16len, 3);
153 1.1 christos }
154 1.1 christos s8idx = s16idx = 0;
155 1.1 christos while (s16idx < s16len) {
156 1.1 christos utfchar = le16toh(s16[s16idx++]);
157 1.1 christos if ((utfchar & 0xf800) == 0xd800) {
158 1.1 christos c = le16toh(s16[s16idx]);
159 1.1 christos if ((utfchar & 0x400) != 0 || (c & 0xfc00) != 0xdc00)
160 1.1 christos utfchar = 0xfffd;
161 1.1 christos else
162 1.1 christos s16idx++;
163 1.1 christos }
164 1.1 christos if (utfchar < 0x80) {
165 1.1 christos s8[s8idx++] = utfchar;
166 1.1 christos } else if (utfchar < 0x800) {
167 1.1 christos s8[s8idx++] = 0xc0 | (utfchar >> 6);
168 1.1 christos s8[s8idx++] = 0x80 | (utfchar & 0x3f);
169 1.1 christos } else if (utfchar < 0x10000) {
170 1.1 christos s8[s8idx++] = 0xe0 | (utfchar >> 12);
171 1.1 christos s8[s8idx++] = 0x80 | ((utfchar >> 6) & 0x3f);
172 1.1 christos s8[s8idx++] = 0x80 | (utfchar & 0x3f);
173 1.1 christos } else if (utfchar < 0x200000) {
174 1.1 christos s8[s8idx++] = 0xf0 | (utfchar >> 18);
175 1.1 christos s8[s8idx++] = 0x80 | ((utfchar >> 12) & 0x3f);
176 1.1 christos s8[s8idx++] = 0x80 | ((utfchar >> 6) & 0x3f);
177 1.1 christos s8[s8idx++] = 0x80 | (utfchar & 0x3f);
178 1.1 christos }
179 1.1 christos }
180 1.1 christos return (s8);
181 1.1 christos }
182 1.1 christos
183 1.1 christos void
184 1.1 christos utf8_to_utf16(const uint8_t *s8, uint16_t *s16, size_t s16len)
185 1.1 christos {
186 1.1 christos size_t s16idx, s8idx, s8len;
187 1.2 christos uint32_t utfchar = 0;
188 1.1 christos unsigned int c, utfbytes;
189 1.1 christos
190 1.1 christos s8len = 0;
191 1.1 christos while (s8[s8len++] != 0)
192 1.1 christos ;
193 1.1 christos s8idx = s16idx = 0;
194 1.1 christos utfbytes = 0;
195 1.1 christos do {
196 1.1 christos c = s8[s8idx++];
197 1.1 christos if ((c & 0xc0) != 0x80) {
198 1.1 christos /* Initial characters. */
199 1.1 christos if (utfbytes != 0) {
200 1.1 christos /* Incomplete encoding. */
201 1.17 matt s16[s16idx++] = htole16(0xfffd);
202 1.1 christos if (s16idx == s16len) {
203 1.1 christos s16[--s16idx] = 0;
204 1.1 christos return;
205 1.1 christos }
206 1.1 christos }
207 1.1 christos if ((c & 0xf8) == 0xf0) {
208 1.1 christos utfchar = c & 0x07;
209 1.1 christos utfbytes = 3;
210 1.1 christos } else if ((c & 0xf0) == 0xe0) {
211 1.1 christos utfchar = c & 0x0f;
212 1.1 christos utfbytes = 2;
213 1.1 christos } else if ((c & 0xe0) == 0xc0) {
214 1.1 christos utfchar = c & 0x1f;
215 1.1 christos utfbytes = 1;
216 1.1 christos } else {
217 1.1 christos utfchar = c & 0x7f;
218 1.1 christos utfbytes = 0;
219 1.1 christos }
220 1.1 christos } else {
221 1.1 christos /* Followup characters. */
222 1.1 christos if (utfbytes > 0) {
223 1.1 christos utfchar = (utfchar << 6) + (c & 0x3f);
224 1.1 christos utfbytes--;
225 1.1 christos } else if (utfbytes == 0)
226 1.1 christos utfbytes = -1;
227 1.1 christos }
228 1.1 christos if (utfbytes == 0) {
229 1.1 christos if (utfchar >= 0x10000 && s16idx + 2 >= s16len)
230 1.17 matt utfchar = 0xfffd;
231 1.1 christos if (utfchar >= 0x10000) {
232 1.16 matt s16[s16idx++] =
233 1.16 matt htole16(0xd800 | ((utfchar>>10)-0x40));
234 1.16 matt s16[s16idx++] =
235 1.16 matt htole16(0xdc00 | (utfchar & 0x3ff));
236 1.1 christos } else
237 1.16 matt s16[s16idx++] = htole16(utfchar);
238 1.1 christos if (s16idx == s16len) {
239 1.1 christos s16[--s16idx] = 0;
240 1.1 christos return;
241 1.1 christos }
242 1.1 christos }
243 1.1 christos } while (c != 0);
244 1.1 christos }
245 1.1 christos
246 1.1 christos void*
247 1.1 christos gpt_read(int fd, off_t lba, size_t count)
248 1.1 christos {
249 1.1 christos off_t ofs;
250 1.1 christos void *buf;
251 1.1 christos
252 1.1 christos count *= secsz;
253 1.1 christos buf = malloc(count);
254 1.1 christos if (buf == NULL)
255 1.1 christos return (NULL);
256 1.1 christos
257 1.1 christos ofs = lba * secsz;
258 1.1 christos if (lseek(fd, ofs, SEEK_SET) == ofs &&
259 1.1 christos read(fd, buf, count) == (ssize_t)count)
260 1.1 christos return (buf);
261 1.1 christos
262 1.1 christos free(buf);
263 1.1 christos return (NULL);
264 1.1 christos }
265 1.1 christos
266 1.1 christos int
267 1.1 christos gpt_write(int fd, map_t *map)
268 1.1 christos {
269 1.1 christos off_t ofs;
270 1.1 christos size_t count;
271 1.1 christos
272 1.1 christos count = map->map_size * secsz;
273 1.1 christos ofs = map->map_start * secsz;
274 1.46 christos if (lseek(fd, ofs, SEEK_SET) != ofs ||
275 1.46 christos write(fd, map->map_data, count) != (ssize_t)count)
276 1.46 christos return -1;
277 1.46 christos modified = 1;
278 1.46 christos return 0;
279 1.1 christos }
280 1.1 christos
281 1.1 christos static int
282 1.1 christos gpt_mbr(int fd, off_t lba)
283 1.1 christos {
284 1.1 christos struct mbr *mbr;
285 1.1 christos map_t *m, *p;
286 1.1 christos off_t size, start;
287 1.1 christos unsigned int i, pmbr;
288 1.1 christos
289 1.1 christos mbr = gpt_read(fd, lba, 1);
290 1.42 christos if (mbr == NULL) {
291 1.42 christos if (!quiet)
292 1.42 christos warn("%s: read failed", device_name);
293 1.1 christos return (-1);
294 1.42 christos }
295 1.1 christos
296 1.1 christos if (mbr->mbr_sig != htole16(MBR_SIG)) {
297 1.1 christos if (verbose)
298 1.42 christos gpt_msg("MBR not found at sector %ju", (uintmax_t)lba);
299 1.1 christos free(mbr);
300 1.1 christos return (0);
301 1.1 christos }
302 1.1 christos
303 1.1 christos /*
304 1.1 christos * Differentiate between a regular MBR and a PMBR. This is more
305 1.1 christos * convenient in general. A PMBR is one with a single partition
306 1.1 christos * of type 0xee.
307 1.1 christos */
308 1.1 christos pmbr = 0;
309 1.1 christos for (i = 0; i < 4; i++) {
310 1.25 jakllsch if (mbr->mbr_part[i].part_typ == MBR_PTYPE_UNUSED)
311 1.1 christos continue;
312 1.25 jakllsch if (mbr->mbr_part[i].part_typ == MBR_PTYPE_PMBR)
313 1.1 christos pmbr++;
314 1.1 christos else
315 1.1 christos break;
316 1.1 christos }
317 1.1 christos if (pmbr && i == 4 && lba == 0) {
318 1.42 christos if (pmbr != 1 && !quiet)
319 1.42 christos warnx("%s: Suspicious PMBR at sector %ju",
320 1.42 christos device_name, (uintmax_t)lba);
321 1.1 christos else if (verbose > 1)
322 1.42 christos gpt_msg("PMBR at sector %ju", (uintmax_t)lba);
323 1.1 christos p = map_add(lba, 1LL, MAP_TYPE_PMBR, mbr);
324 1.1 christos return ((p == NULL) ? -1 : 0);
325 1.1 christos }
326 1.42 christos if (pmbr && !quiet)
327 1.42 christos warnx("%s: Suspicious MBR at sector %ju", device_name,
328 1.42 christos (uintmax_t)lba);
329 1.1 christos else if (verbose > 1)
330 1.42 christos gpt_msg("MBR at sector %ju", (uintmax_t)lba);
331 1.1 christos
332 1.1 christos p = map_add(lba, 1LL, MAP_TYPE_MBR, mbr);
333 1.1 christos if (p == NULL)
334 1.1 christos return (-1);
335 1.1 christos for (i = 0; i < 4; i++) {
336 1.25 jakllsch if (mbr->mbr_part[i].part_typ == MBR_PTYPE_UNUSED ||
337 1.25 jakllsch mbr->mbr_part[i].part_typ == MBR_PTYPE_PMBR)
338 1.1 christos continue;
339 1.1 christos start = le16toh(mbr->mbr_part[i].part_start_hi);
340 1.1 christos start = (start << 16) + le16toh(mbr->mbr_part[i].part_start_lo);
341 1.1 christos size = le16toh(mbr->mbr_part[i].part_size_hi);
342 1.1 christos size = (size << 16) + le16toh(mbr->mbr_part[i].part_size_lo);
343 1.1 christos if (start == 0 && size == 0) {
344 1.1 christos warnx("%s: Malformed MBR at sector %llu", device_name,
345 1.1 christos (long long)lba);
346 1.1 christos continue;
347 1.1 christos }
348 1.1 christos /* start is relative to the offset of the MBR itself. */
349 1.1 christos start += lba;
350 1.1 christos if (verbose > 2)
351 1.42 christos gpt_msg("MBR part: type=%d, start=%ju, size=%ju",
352 1.42 christos mbr->mbr_part[i].part_typ,
353 1.42 christos (uintmax_t)start, (uintmax_t)size);
354 1.25 jakllsch if (mbr->mbr_part[i].part_typ != MBR_PTYPE_EXT_LBA) {
355 1.1 christos m = map_add(start, size, MAP_TYPE_MBR_PART, p);
356 1.1 christos if (m == NULL)
357 1.1 christos return (-1);
358 1.1 christos m->map_index = i + 1;
359 1.1 christos } else {
360 1.1 christos if (gpt_mbr(fd, start) == -1)
361 1.1 christos return (-1);
362 1.1 christos }
363 1.1 christos }
364 1.1 christos return (0);
365 1.1 christos }
366 1.1 christos
367 1.29 jnemeth int
368 1.11 christos gpt_gpt(int fd, off_t lba, int found)
369 1.1 christos {
370 1.1 christos off_t size;
371 1.1 christos struct gpt_ent *ent;
372 1.1 christos struct gpt_hdr *hdr;
373 1.34 christos char *p;
374 1.1 christos map_t *m;
375 1.1 christos size_t blocks, tblsz;
376 1.1 christos unsigned int i;
377 1.1 christos uint32_t crc;
378 1.1 christos
379 1.1 christos hdr = gpt_read(fd, lba, 1);
380 1.1 christos if (hdr == NULL)
381 1.1 christos return (-1);
382 1.1 christos
383 1.1 christos if (memcmp(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig)))
384 1.1 christos goto fail_hdr;
385 1.1 christos
386 1.1 christos crc = le32toh(hdr->hdr_crc_self);
387 1.1 christos hdr->hdr_crc_self = 0;
388 1.1 christos if (crc32(hdr, le32toh(hdr->hdr_size)) != crc) {
389 1.1 christos if (verbose)
390 1.1 christos warnx("%s: Bad CRC in GPT header at sector %llu",
391 1.1 christos device_name, (long long)lba);
392 1.1 christos goto fail_hdr;
393 1.1 christos }
394 1.1 christos
395 1.1 christos tblsz = le32toh(hdr->hdr_entries) * le32toh(hdr->hdr_entsz);
396 1.1 christos blocks = tblsz / secsz + ((tblsz % secsz) ? 1 : 0);
397 1.1 christos
398 1.1 christos /* Use generic pointer to deal with hdr->hdr_entsz != sizeof(*ent). */
399 1.1 christos p = gpt_read(fd, le64toh(hdr->hdr_lba_table), blocks);
400 1.11 christos if (p == NULL) {
401 1.11 christos if (found) {
402 1.11 christos if (verbose)
403 1.11 christos warn("%s: Cannot read LBA table at sector %llu",
404 1.12 christos device_name, (unsigned long long)
405 1.12 christos le64toh(hdr->hdr_lba_table));
406 1.11 christos return (-1);
407 1.11 christos }
408 1.11 christos goto fail_hdr;
409 1.11 christos }
410 1.1 christos
411 1.1 christos if (crc32(p, tblsz) != le32toh(hdr->hdr_crc_table)) {
412 1.1 christos if (verbose)
413 1.1 christos warnx("%s: Bad CRC in GPT table at sector %llu",
414 1.1 christos device_name,
415 1.1 christos (long long)le64toh(hdr->hdr_lba_table));
416 1.1 christos goto fail_ent;
417 1.1 christos }
418 1.1 christos
419 1.1 christos if (verbose > 1)
420 1.1 christos warnx("%s: %s GPT at sector %llu", device_name,
421 1.1 christos (lba == 1) ? "Pri" : "Sec", (long long)lba);
422 1.1 christos
423 1.1 christos m = map_add(lba, 1, (lba == 1)
424 1.1 christos ? MAP_TYPE_PRI_GPT_HDR : MAP_TYPE_SEC_GPT_HDR, hdr);
425 1.1 christos if (m == NULL)
426 1.1 christos return (-1);
427 1.1 christos
428 1.1 christos m = map_add(le64toh(hdr->hdr_lba_table), blocks, (lba == 1)
429 1.1 christos ? MAP_TYPE_PRI_GPT_TBL : MAP_TYPE_SEC_GPT_TBL, p);
430 1.1 christos if (m == NULL)
431 1.1 christos return (-1);
432 1.1 christos
433 1.1 christos if (lba != 1)
434 1.11 christos return (1);
435 1.1 christos
436 1.1 christos for (i = 0; i < le32toh(hdr->hdr_entries); i++) {
437 1.1 christos ent = (void*)(p + i * le32toh(hdr->hdr_entsz));
438 1.34 christos if (gpt_uuid_is_nil(ent->ent_type))
439 1.1 christos continue;
440 1.1 christos
441 1.1 christos size = le64toh(ent->ent_lba_end) - le64toh(ent->ent_lba_start) +
442 1.1 christos 1LL;
443 1.1 christos if (verbose > 2) {
444 1.34 christos char buf[128];
445 1.34 christos gpt_uuid_snprintf(buf, sizeof(buf), "%s",
446 1.34 christos ent->ent_type);
447 1.34 christos warnx("%s: GPT partition: type=%s, start=%llu, "
448 1.34 christos "size=%llu", device_name, buf,
449 1.1 christos (long long)le64toh(ent->ent_lba_start),
450 1.1 christos (long long)size);
451 1.1 christos }
452 1.1 christos m = map_add(le64toh(ent->ent_lba_start), size,
453 1.1 christos MAP_TYPE_GPT_PART, ent);
454 1.1 christos if (m == NULL)
455 1.1 christos return (-1);
456 1.1 christos m->map_index = i + 1;
457 1.1 christos }
458 1.11 christos return (1);
459 1.1 christos
460 1.1 christos fail_ent:
461 1.1 christos free(p);
462 1.1 christos
463 1.1 christos fail_hdr:
464 1.1 christos free(hdr);
465 1.1 christos return (0);
466 1.1 christos }
467 1.1 christos
468 1.1 christos int
469 1.42 christos gpt_open(const char *dev, int flags)
470 1.1 christos {
471 1.1 christos struct stat sb;
472 1.11 christos int fd, mode, found;
473 1.45 christos off_t devsz;
474 1.1 christos
475 1.1 christos mode = readonly ? O_RDONLY : O_RDWR|O_EXCL;
476 1.1 christos
477 1.39 mlelstv device_arg = device_name = dev;
478 1.2 christos fd = opendisk(dev, mode, device_path, sizeof(device_path), 0);
479 1.42 christos if (fd == -1) {
480 1.42 christos if (!quiet)
481 1.42 christos warn("Cannot open `%s'", device_name);
482 1.2 christos return -1;
483 1.42 christos }
484 1.42 christos device_name = device_path;
485 1.1 christos
486 1.42 christos if (fstat(fd, &sb) == -1) {
487 1.42 christos if (!quiet)
488 1.42 christos warn("Cannot stat `%s'", device_name);
489 1.1 christos goto close;
490 1.42 christos }
491 1.1 christos
492 1.1 christos if ((sb.st_mode & S_IFMT) != S_IFREG) {
493 1.44 christos if (secsz == 0) {
494 1.43 jnemeth #ifdef DIOCGSECTORSIZE
495 1.44 christos if (ioctl(fd, DIOCGSECTORSIZE, &secsz) == -1) {
496 1.44 christos if (!quiet)
497 1.44 christos warn("Cannot get sector size for `%s'",
498 1.44 christos device_name);
499 1.44 christos goto close;
500 1.44 christos }
501 1.44 christos #endif
502 1.44 christos if (secsz == 0) {
503 1.44 christos if (!quiet)
504 1.44 christos warnx("Sector size for `%s' can't be 0",
505 1.44 christos device_name);
506 1.44 christos goto close;
507 1.44 christos }
508 1.42 christos }
509 1.44 christos if (mediasz == 0) {
510 1.44 christos #ifdef DIOCGMEDIASIZE
511 1.44 christos if (ioctl(fd, DIOCGMEDIASIZE, &mediasz) == -1) {
512 1.44 christos if (!quiet)
513 1.44 christos warn("Cannot get media size for `%s'",
514 1.44 christos device_name);
515 1.44 christos goto close;
516 1.44 christos }
517 1.43 jnemeth #endif
518 1.44 christos if (mediasz == 0) {
519 1.44 christos if (!quiet)
520 1.44 christos warnx("Media size for `%s' can't be 0",
521 1.44 christos device_name);
522 1.44 christos goto close;
523 1.44 christos }
524 1.44 christos }
525 1.1 christos } else {
526 1.36 christos if (secsz == 0)
527 1.36 christos secsz = 512; /* Fixed size for files. */
528 1.36 christos if (mediasz == 0) {
529 1.36 christos if (sb.st_size % secsz) {
530 1.36 christos errno = EINVAL;
531 1.36 christos goto close;
532 1.36 christos }
533 1.36 christos mediasz = sb.st_size;
534 1.1 christos }
535 1.1 christos }
536 1.1 christos
537 1.1 christos /*
538 1.1 christos * We require an absolute minimum of 6 sectors. One for the MBR,
539 1.1 christos * 2 for the GPT header, 2 for the GPT table and one to hold some
540 1.1 christos * user data. Let's catch this extreme border case here so that
541 1.1 christos * we don't have to worry about it later.
542 1.1 christos */
543 1.45 christos devsz = mediasz / secsz;
544 1.45 christos if (devsz < 6) {
545 1.42 christos if (!quiet)
546 1.45 christos warnx("Need 6 sectors on '%s' we have %ju",
547 1.45 christos device_name, (uintmax_t)devsz);
548 1.1 christos goto close;
549 1.1 christos }
550 1.1 christos
551 1.42 christos if (verbose) {
552 1.42 christos gpt_msg("mediasize=%ju; sectorsize=%u; blocks=%ju",
553 1.45 christos (uintmax_t)mediasz, secsz, (uintmax_t)devsz);
554 1.42 christos }
555 1.1 christos
556 1.45 christos map_init(devsz);
557 1.1 christos
558 1.1 christos if (gpt_mbr(fd, 0LL) == -1)
559 1.1 christos goto close;
560 1.11 christos if ((found = gpt_gpt(fd, 1LL, 1)) == -1)
561 1.1 christos goto close;
562 1.45 christos if (gpt_gpt(fd, devsz - 1LL, found) == -1)
563 1.1 christos goto close;
564 1.1 christos
565 1.1 christos return (fd);
566 1.1 christos
567 1.1 christos close:
568 1.1 christos close(fd);
569 1.1 christos return (-1);
570 1.1 christos }
571 1.1 christos
572 1.1 christos void
573 1.1 christos gpt_close(int fd)
574 1.1 christos {
575 1.46 christos int bits;
576 1.46 christos
577 1.46 christos if (modified && !nosync)
578 1.46 christos if (ioctl(fd, DIOCMWEDGES, &bits) == -1)
579 1.46 christos warn("Can't update wedge information");
580 1.46 christos
581 1.1 christos /* XXX post processing? */
582 1.1 christos close(fd);
583 1.1 christos }
584 1.1 christos
585 1.42 christos void
586 1.42 christos gpt_msg(const char *fmt, ...)
587 1.42 christos {
588 1.42 christos va_list ap;
589 1.42 christos printf("%s: ", device_name);
590 1.42 christos va_start(ap, fmt);
591 1.42 christos vprintf(fmt, ap);
592 1.42 christos va_end(ap);
593 1.42 christos printf("\n");
594 1.42 christos }
595