gpt.c revision 1.61 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.61 christos __RCSID("$NetBSD: gpt.c,v 1.61 2015/12/03 21:30:54 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.49 christos #include "gpt_private.h"
62 1.1 christos
63 1.1 christos static uint32_t crc32_tab[] = {
64 1.1 christos 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
65 1.1 christos 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
66 1.1 christos 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
67 1.1 christos 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
68 1.1 christos 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
69 1.1 christos 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
70 1.1 christos 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
71 1.1 christos 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
72 1.1 christos 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
73 1.1 christos 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
74 1.1 christos 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
75 1.1 christos 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
76 1.1 christos 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
77 1.1 christos 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
78 1.1 christos 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
79 1.1 christos 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
80 1.1 christos 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
81 1.1 christos 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
82 1.1 christos 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
83 1.1 christos 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
84 1.1 christos 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
85 1.1 christos 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
86 1.1 christos 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
87 1.1 christos 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
88 1.1 christos 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
89 1.1 christos 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
90 1.1 christos 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
91 1.1 christos 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
92 1.1 christos 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
93 1.1 christos 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
94 1.1 christos 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
95 1.1 christos 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
96 1.1 christos 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
97 1.1 christos 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
98 1.1 christos 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
99 1.1 christos 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
100 1.1 christos 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
101 1.1 christos 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
102 1.1 christos 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
103 1.1 christos 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
104 1.1 christos 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
105 1.1 christos 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
106 1.1 christos 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
107 1.1 christos };
108 1.1 christos
109 1.1 christos uint32_t
110 1.1 christos crc32(const void *buf, size_t size)
111 1.1 christos {
112 1.1 christos const uint8_t *p;
113 1.1 christos uint32_t crc;
114 1.1 christos
115 1.1 christos p = buf;
116 1.1 christos crc = ~0U;
117 1.1 christos
118 1.1 christos while (size--)
119 1.1 christos crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
120 1.1 christos
121 1.1 christos return crc ^ ~0U;
122 1.1 christos }
123 1.1 christos
124 1.53 christos void
125 1.53 christos utf16_to_utf8(const uint16_t *s16, uint8_t *s8, size_t s8len)
126 1.1 christos {
127 1.1 christos size_t s8idx, s16idx, s16len;
128 1.1 christos uint32_t utfchar;
129 1.1 christos unsigned int c;
130 1.1 christos
131 1.1 christos s16len = 0;
132 1.1 christos while (s16[s16len++] != 0)
133 1.53 christos continue;
134 1.1 christos s8idx = s16idx = 0;
135 1.1 christos while (s16idx < s16len) {
136 1.1 christos utfchar = le16toh(s16[s16idx++]);
137 1.1 christos if ((utfchar & 0xf800) == 0xd800) {
138 1.1 christos c = le16toh(s16[s16idx]);
139 1.1 christos if ((utfchar & 0x400) != 0 || (c & 0xfc00) != 0xdc00)
140 1.1 christos utfchar = 0xfffd;
141 1.1 christos else
142 1.1 christos s16idx++;
143 1.1 christos }
144 1.1 christos if (utfchar < 0x80) {
145 1.53 christos if (s8idx + 1 >= s8len)
146 1.53 christos break;
147 1.59 christos s8[s8idx++] = (uint8_t)utfchar;
148 1.1 christos } else if (utfchar < 0x800) {
149 1.53 christos if (s8idx + 2 >= s8len)
150 1.53 christos break;
151 1.59 christos s8[s8idx++] = (uint8_t)(0xc0 | (utfchar >> 6));
152 1.59 christos s8[s8idx++] = (uint8_t)(0x80 | (utfchar & 0x3f));
153 1.1 christos } else if (utfchar < 0x10000) {
154 1.53 christos if (s8idx + 3 >= s8len)
155 1.53 christos break;
156 1.59 christos s8[s8idx++] = (uint8_t)(0xe0 | (utfchar >> 12));
157 1.59 christos s8[s8idx++] = (uint8_t)(0x80 | ((utfchar >> 6) & 0x3f));
158 1.59 christos s8[s8idx++] = (uint8_t)(0x80 | (utfchar & 0x3f));
159 1.1 christos } else if (utfchar < 0x200000) {
160 1.53 christos if (s8idx + 4 >= s8len)
161 1.53 christos break;
162 1.59 christos s8[s8idx++] = (uint8_t)(0xf0 | (utfchar >> 18));
163 1.59 christos s8[s8idx++] = (uint8_t)(0x80 | ((utfchar >> 12) & 0x3f));
164 1.59 christos s8[s8idx++] = (uint8_t)(0x80 | ((utfchar >> 6) & 0x3f));
165 1.59 christos s8[s8idx++] = (uint8_t)(0x80 | (utfchar & 0x3f));
166 1.1 christos }
167 1.1 christos }
168 1.53 christos s8[s8idx] = 0;
169 1.1 christos }
170 1.1 christos
171 1.1 christos void
172 1.1 christos utf8_to_utf16(const uint8_t *s8, uint16_t *s16, size_t s16len)
173 1.1 christos {
174 1.1 christos size_t s16idx, s8idx, s8len;
175 1.2 christos uint32_t utfchar = 0;
176 1.1 christos unsigned int c, utfbytes;
177 1.1 christos
178 1.1 christos s8len = 0;
179 1.1 christos while (s8[s8len++] != 0)
180 1.1 christos ;
181 1.1 christos s8idx = s16idx = 0;
182 1.1 christos utfbytes = 0;
183 1.1 christos do {
184 1.1 christos c = s8[s8idx++];
185 1.1 christos if ((c & 0xc0) != 0x80) {
186 1.1 christos /* Initial characters. */
187 1.1 christos if (utfbytes != 0) {
188 1.1 christos /* Incomplete encoding. */
189 1.17 matt s16[s16idx++] = htole16(0xfffd);
190 1.1 christos if (s16idx == s16len) {
191 1.1 christos s16[--s16idx] = 0;
192 1.1 christos return;
193 1.1 christos }
194 1.1 christos }
195 1.1 christos if ((c & 0xf8) == 0xf0) {
196 1.1 christos utfchar = c & 0x07;
197 1.1 christos utfbytes = 3;
198 1.1 christos } else if ((c & 0xf0) == 0xe0) {
199 1.1 christos utfchar = c & 0x0f;
200 1.1 christos utfbytes = 2;
201 1.1 christos } else if ((c & 0xe0) == 0xc0) {
202 1.1 christos utfchar = c & 0x1f;
203 1.1 christos utfbytes = 1;
204 1.1 christos } else {
205 1.1 christos utfchar = c & 0x7f;
206 1.1 christos utfbytes = 0;
207 1.1 christos }
208 1.1 christos } else {
209 1.1 christos /* Followup characters. */
210 1.1 christos if (utfbytes > 0) {
211 1.1 christos utfchar = (utfchar << 6) + (c & 0x3f);
212 1.1 christos utfbytes--;
213 1.1 christos } else if (utfbytes == 0)
214 1.59 christos utfbytes = (u_int)~0;
215 1.1 christos }
216 1.1 christos if (utfbytes == 0) {
217 1.1 christos if (utfchar >= 0x10000 && s16idx + 2 >= s16len)
218 1.17 matt utfchar = 0xfffd;
219 1.1 christos if (utfchar >= 0x10000) {
220 1.59 christos s16[s16idx++] = htole16((uint16_t)
221 1.59 christos (0xd800 | ((utfchar>>10) - 0x40)));
222 1.59 christos s16[s16idx++] = htole16((uint16_t)
223 1.59 christos (0xdc00 | (utfchar & 0x3ff)));
224 1.1 christos } else
225 1.59 christos s16[s16idx++] = htole16((uint16_t)utfchar);
226 1.1 christos if (s16idx == s16len) {
227 1.1 christos s16[--s16idx] = 0;
228 1.1 christos return;
229 1.1 christos }
230 1.1 christos }
231 1.1 christos } while (c != 0);
232 1.1 christos }
233 1.1 christos
234 1.49 christos void *
235 1.49 christos gpt_read(gpt_t gpt, off_t lba, size_t count)
236 1.1 christos {
237 1.1 christos off_t ofs;
238 1.1 christos void *buf;
239 1.1 christos
240 1.49 christos count *= gpt->secsz;
241 1.1 christos buf = malloc(count);
242 1.1 christos if (buf == NULL)
243 1.49 christos return NULL;
244 1.1 christos
245 1.49 christos ofs = lba * gpt->secsz;
246 1.49 christos if (lseek(gpt->fd, ofs, SEEK_SET) == ofs &&
247 1.49 christos read(gpt->fd, buf, count) == (ssize_t)count)
248 1.49 christos return buf;
249 1.1 christos
250 1.1 christos free(buf);
251 1.49 christos return NULL;
252 1.1 christos }
253 1.1 christos
254 1.1 christos int
255 1.49 christos gpt_write(gpt_t gpt, map_t map)
256 1.1 christos {
257 1.1 christos off_t ofs;
258 1.1 christos size_t count;
259 1.1 christos
260 1.59 christos count = (size_t)(map->map_size * gpt->secsz);
261 1.49 christos ofs = map->map_start * gpt->secsz;
262 1.49 christos if (lseek(gpt->fd, ofs, SEEK_SET) != ofs ||
263 1.49 christos write(gpt->fd, map->map_data, count) != (ssize_t)count)
264 1.46 christos return -1;
265 1.49 christos gpt->flags |= GPT_MODIFIED;
266 1.46 christos return 0;
267 1.1 christos }
268 1.1 christos
269 1.1 christos static int
270 1.49 christos gpt_mbr(gpt_t gpt, off_t lba)
271 1.1 christos {
272 1.1 christos struct mbr *mbr;
273 1.49 christos map_t m, p;
274 1.1 christos off_t size, start;
275 1.1 christos unsigned int i, pmbr;
276 1.1 christos
277 1.49 christos mbr = gpt_read(gpt, lba, 1);
278 1.42 christos if (mbr == NULL) {
279 1.49 christos gpt_warn(gpt, "Read failed");
280 1.49 christos return -1;
281 1.42 christos }
282 1.1 christos
283 1.1 christos if (mbr->mbr_sig != htole16(MBR_SIG)) {
284 1.49 christos if (gpt->verbose)
285 1.49 christos gpt_msg(gpt,
286 1.49 christos "MBR not found at sector %ju", (uintmax_t)lba);
287 1.1 christos free(mbr);
288 1.49 christos return 0;
289 1.1 christos }
290 1.1 christos
291 1.1 christos /*
292 1.1 christos * Differentiate between a regular MBR and a PMBR. This is more
293 1.1 christos * convenient in general. A PMBR is one with a single partition
294 1.1 christos * of type 0xee.
295 1.1 christos */
296 1.1 christos pmbr = 0;
297 1.1 christos for (i = 0; i < 4; i++) {
298 1.25 jakllsch if (mbr->mbr_part[i].part_typ == MBR_PTYPE_UNUSED)
299 1.1 christos continue;
300 1.25 jakllsch if (mbr->mbr_part[i].part_typ == MBR_PTYPE_PMBR)
301 1.1 christos pmbr++;
302 1.1 christos else
303 1.1 christos break;
304 1.1 christos }
305 1.1 christos if (pmbr && i == 4 && lba == 0) {
306 1.49 christos if (pmbr != 1)
307 1.49 christos gpt_warnx(gpt, "Suspicious PMBR at sector %ju",
308 1.49 christos (uintmax_t)lba);
309 1.49 christos else if (gpt->verbose > 1)
310 1.49 christos gpt_msg(gpt, "PMBR at sector %ju", (uintmax_t)lba);
311 1.61 christos p = map_add(gpt, lba, 1LL, MAP_TYPE_PMBR, mbr, 1);
312 1.49 christos goto out;
313 1.49 christos }
314 1.49 christos if (pmbr)
315 1.49 christos gpt_warnx(gpt, "Suspicious MBR at sector %ju", (uintmax_t)lba);
316 1.49 christos else if (gpt->verbose > 1)
317 1.49 christos gpt_msg(gpt, "MBR at sector %ju", (uintmax_t)lba);
318 1.1 christos
319 1.61 christos p = map_add(gpt, lba, 1LL, MAP_TYPE_MBR, mbr, 1);
320 1.1 christos if (p == NULL)
321 1.49 christos goto out;
322 1.49 christos
323 1.1 christos for (i = 0; i < 4; i++) {
324 1.25 jakllsch if (mbr->mbr_part[i].part_typ == MBR_PTYPE_UNUSED ||
325 1.25 jakllsch mbr->mbr_part[i].part_typ == MBR_PTYPE_PMBR)
326 1.1 christos continue;
327 1.1 christos start = le16toh(mbr->mbr_part[i].part_start_hi);
328 1.1 christos start = (start << 16) + le16toh(mbr->mbr_part[i].part_start_lo);
329 1.1 christos size = le16toh(mbr->mbr_part[i].part_size_hi);
330 1.1 christos size = (size << 16) + le16toh(mbr->mbr_part[i].part_size_lo);
331 1.1 christos if (start == 0 && size == 0) {
332 1.49 christos gpt_warnx(gpt, "Malformed MBR at sector %ju",
333 1.49 christos (uintmax_t)lba);
334 1.1 christos continue;
335 1.1 christos }
336 1.1 christos /* start is relative to the offset of the MBR itself. */
337 1.1 christos start += lba;
338 1.49 christos if (gpt->verbose > 2)
339 1.49 christos gpt_msg(gpt, "MBR part: type=%d, start=%ju, size=%ju",
340 1.42 christos mbr->mbr_part[i].part_typ,
341 1.42 christos (uintmax_t)start, (uintmax_t)size);
342 1.25 jakllsch if (mbr->mbr_part[i].part_typ != MBR_PTYPE_EXT_LBA) {
343 1.61 christos m = map_add(gpt, start, size, MAP_TYPE_MBR_PART, p, 0);
344 1.1 christos if (m == NULL)
345 1.49 christos return -1;
346 1.1 christos m->map_index = i + 1;
347 1.1 christos } else {
348 1.49 christos if (gpt_mbr(gpt, start) == -1)
349 1.49 christos return -1;
350 1.1 christos }
351 1.1 christos }
352 1.49 christos return 0;
353 1.49 christos out:
354 1.49 christos if (p == NULL) {
355 1.49 christos free(mbr);
356 1.49 christos return -1;
357 1.49 christos }
358 1.49 christos return 0;
359 1.1 christos }
360 1.1 christos
361 1.29 jnemeth int
362 1.49 christos gpt_gpt(gpt_t gpt, off_t lba, int found)
363 1.1 christos {
364 1.1 christos off_t size;
365 1.1 christos struct gpt_ent *ent;
366 1.1 christos struct gpt_hdr *hdr;
367 1.34 christos char *p;
368 1.49 christos map_t m;
369 1.1 christos size_t blocks, tblsz;
370 1.1 christos unsigned int i;
371 1.1 christos uint32_t crc;
372 1.1 christos
373 1.49 christos hdr = gpt_read(gpt, lba, 1);
374 1.1 christos if (hdr == NULL)
375 1.49 christos return -1;
376 1.1 christos
377 1.1 christos if (memcmp(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig)))
378 1.1 christos goto fail_hdr;
379 1.1 christos
380 1.1 christos crc = le32toh(hdr->hdr_crc_self);
381 1.1 christos hdr->hdr_crc_self = 0;
382 1.1 christos if (crc32(hdr, le32toh(hdr->hdr_size)) != crc) {
383 1.49 christos if (gpt->verbose)
384 1.49 christos gpt_msg(gpt, "Bad CRC in GPT header at sector %ju",
385 1.49 christos (uintmax_t)lba);
386 1.1 christos goto fail_hdr;
387 1.1 christos }
388 1.1 christos
389 1.1 christos tblsz = le32toh(hdr->hdr_entries) * le32toh(hdr->hdr_entsz);
390 1.49 christos blocks = tblsz / gpt->secsz + ((tblsz % gpt->secsz) ? 1 : 0);
391 1.1 christos
392 1.1 christos /* Use generic pointer to deal with hdr->hdr_entsz != sizeof(*ent). */
393 1.59 christos p = gpt_read(gpt, (off_t)le64toh((uint64_t)hdr->hdr_lba_table), blocks);
394 1.11 christos if (p == NULL) {
395 1.11 christos if (found) {
396 1.49 christos if (gpt->verbose)
397 1.49 christos gpt_msg(gpt,
398 1.49 christos "Cannot read LBA table at sector %ju",
399 1.49 christos (uintmax_t)le64toh(hdr->hdr_lba_table));
400 1.49 christos return -1;
401 1.11 christos }
402 1.11 christos goto fail_hdr;
403 1.11 christos }
404 1.1 christos
405 1.1 christos if (crc32(p, tblsz) != le32toh(hdr->hdr_crc_table)) {
406 1.49 christos if (gpt->verbose)
407 1.49 christos gpt_msg(gpt, "Bad CRC in GPT table at sector %ju",
408 1.49 christos (uintmax_t)le64toh(hdr->hdr_lba_table));
409 1.1 christos goto fail_ent;
410 1.1 christos }
411 1.1 christos
412 1.49 christos if (gpt->verbose > 1)
413 1.49 christos gpt_msg(gpt, "%s GPT at sector %ju",
414 1.49 christos (lba == 1) ? "Pri" : "Sec", (uintmax_t)lba);
415 1.1 christos
416 1.49 christos m = map_add(gpt, lba, 1, (lba == 1)
417 1.61 christos ? MAP_TYPE_PRI_GPT_HDR : MAP_TYPE_SEC_GPT_HDR, hdr, 1);
418 1.1 christos if (m == NULL)
419 1.1 christos return (-1);
420 1.1 christos
421 1.59 christos m = map_add(gpt, (off_t)le64toh((uint64_t)hdr->hdr_lba_table),
422 1.59 christos (off_t)blocks,
423 1.61 christos lba == 1 ? MAP_TYPE_PRI_GPT_TBL : MAP_TYPE_SEC_GPT_TBL, p, 1);
424 1.1 christos if (m == NULL)
425 1.1 christos return (-1);
426 1.1 christos
427 1.1 christos if (lba != 1)
428 1.11 christos return (1);
429 1.1 christos
430 1.1 christos for (i = 0; i < le32toh(hdr->hdr_entries); i++) {
431 1.1 christos ent = (void*)(p + i * le32toh(hdr->hdr_entsz));
432 1.34 christos if (gpt_uuid_is_nil(ent->ent_type))
433 1.1 christos continue;
434 1.1 christos
435 1.59 christos size = (off_t)(le64toh((uint64_t)ent->ent_lba_end) -
436 1.59 christos le64toh((uint64_t)ent->ent_lba_start) + 1LL);
437 1.49 christos if (gpt->verbose > 2) {
438 1.34 christos char buf[128];
439 1.34 christos gpt_uuid_snprintf(buf, sizeof(buf), "%s",
440 1.34 christos ent->ent_type);
441 1.49 christos gpt_msg(gpt, "GPT partition: type=%s, start=%ju, "
442 1.49 christos "size=%ju", buf,
443 1.49 christos (uintmax_t)le64toh(ent->ent_lba_start),
444 1.49 christos (uintmax_t)size);
445 1.1 christos }
446 1.59 christos m = map_add(gpt, (off_t)le64toh((uint64_t)ent->ent_lba_start),
447 1.61 christos size, MAP_TYPE_GPT_PART, ent, 0);
448 1.1 christos if (m == NULL)
449 1.1 christos return (-1);
450 1.1 christos m->map_index = i + 1;
451 1.1 christos }
452 1.11 christos return (1);
453 1.1 christos
454 1.1 christos fail_ent:
455 1.1 christos free(p);
456 1.1 christos
457 1.1 christos fail_hdr:
458 1.1 christos free(hdr);
459 1.1 christos return (0);
460 1.1 christos }
461 1.1 christos
462 1.49 christos gpt_t
463 1.49 christos gpt_open(const char *dev, int flags, int verbose, off_t mediasz, u_int secsz)
464 1.1 christos {
465 1.49 christos int mode, found;
466 1.45 christos off_t devsz;
467 1.49 christos gpt_t gpt;
468 1.1 christos
469 1.1 christos
470 1.49 christos if ((gpt = calloc(1, sizeof(*gpt))) == NULL) {
471 1.55 jnemeth if (!(flags & GPT_QUIET))
472 1.49 christos warn("Cannot allocate `%s'", dev);
473 1.49 christos return NULL;
474 1.49 christos }
475 1.49 christos gpt->flags = flags;
476 1.49 christos gpt->verbose = verbose;
477 1.49 christos gpt->mediasz = mediasz;
478 1.49 christos gpt->secsz = secsz;
479 1.49 christos
480 1.49 christos mode = (gpt->flags & GPT_READONLY) ? O_RDONLY : O_RDWR|O_EXCL;
481 1.49 christos
482 1.49 christos gpt->fd = opendisk(dev, mode, gpt->device_name,
483 1.49 christos sizeof(gpt->device_name), 0);
484 1.49 christos if (gpt->fd == -1) {
485 1.49 christos strlcpy(gpt->device_name, dev, sizeof(gpt->device_name));
486 1.49 christos gpt_warn(gpt, "Cannot open");
487 1.49 christos goto close;
488 1.42 christos }
489 1.1 christos
490 1.49 christos if (fstat(gpt->fd, &gpt->sb) == -1) {
491 1.49 christos gpt_warn(gpt, "Cannot stat");
492 1.1 christos goto close;
493 1.42 christos }
494 1.1 christos
495 1.49 christos if ((gpt->sb.st_mode & S_IFMT) != S_IFREG) {
496 1.49 christos if (gpt->secsz == 0) {
497 1.43 jnemeth #ifdef DIOCGSECTORSIZE
498 1.49 christos if (ioctl(gpt->fd, DIOCGSECTORSIZE, &gpt->secsz) == -1) {
499 1.49 christos gpt_warn(gpt, "Cannot get sector size");
500 1.44 christos goto close;
501 1.44 christos }
502 1.44 christos #endif
503 1.49 christos if (gpt->secsz == 0) {
504 1.49 christos gpt_warnx(gpt, "Sector size can't be 0");
505 1.44 christos goto close;
506 1.44 christos }
507 1.42 christos }
508 1.49 christos if (gpt->mediasz == 0) {
509 1.44 christos #ifdef DIOCGMEDIASIZE
510 1.49 christos if (ioctl(gpt->fd, DIOCGMEDIASIZE, &gpt->mediasz) == -1) {
511 1.49 christos gpt_warn(gpt, "Cannot get media size");
512 1.44 christos goto close;
513 1.44 christos }
514 1.43 jnemeth #endif
515 1.49 christos if (gpt->mediasz == 0) {
516 1.49 christos gpt_warnx(gpt, "Media size can't be 0");
517 1.44 christos goto close;
518 1.44 christos }
519 1.44 christos }
520 1.1 christos } else {
521 1.49 christos if (gpt->secsz == 0)
522 1.49 christos gpt->secsz = 512; /* Fixed size for files. */
523 1.49 christos if (gpt->mediasz == 0) {
524 1.49 christos if (gpt->sb.st_size % gpt->secsz) {
525 1.36 christos errno = EINVAL;
526 1.36 christos goto close;
527 1.36 christos }
528 1.49 christos gpt->mediasz = gpt->sb.st_size;
529 1.1 christos }
530 1.56 christos gpt->flags |= GPT_NOSYNC;
531 1.1 christos }
532 1.1 christos
533 1.1 christos /*
534 1.1 christos * We require an absolute minimum of 6 sectors. One for the MBR,
535 1.1 christos * 2 for the GPT header, 2 for the GPT table and one to hold some
536 1.1 christos * user data. Let's catch this extreme border case here so that
537 1.1 christos * we don't have to worry about it later.
538 1.1 christos */
539 1.49 christos devsz = gpt->mediasz / gpt->secsz;
540 1.45 christos if (devsz < 6) {
541 1.49 christos gpt_warnx(gpt, "Need 6 sectorso, we have %ju",
542 1.49 christos (uintmax_t)devsz);
543 1.1 christos goto close;
544 1.1 christos }
545 1.1 christos
546 1.49 christos if (gpt->verbose) {
547 1.49 christos gpt_msg(gpt, "mediasize=%ju; sectorsize=%u; blocks=%ju",
548 1.49 christos (uintmax_t)gpt->mediasz, gpt->secsz, (uintmax_t)devsz);
549 1.42 christos }
550 1.1 christos
551 1.57 christos if (map_init(gpt, devsz) == -1)
552 1.57 christos goto close;
553 1.1 christos
554 1.49 christos if (gpt_mbr(gpt, 0LL) == -1)
555 1.1 christos goto close;
556 1.49 christos if ((found = gpt_gpt(gpt, 1LL, 1)) == -1)
557 1.1 christos goto close;
558 1.49 christos if (gpt_gpt(gpt, devsz - 1LL, found) == -1)
559 1.1 christos goto close;
560 1.1 christos
561 1.49 christos return gpt;
562 1.1 christos
563 1.1 christos close:
564 1.49 christos if (gpt->fd != -1)
565 1.49 christos close(gpt->fd);
566 1.49 christos free(gpt);
567 1.49 christos return NULL;
568 1.1 christos }
569 1.1 christos
570 1.1 christos void
571 1.49 christos gpt_close(gpt_t gpt)
572 1.1 christos {
573 1.46 christos
574 1.49 christos if (!(gpt->flags & GPT_MODIFIED))
575 1.48 christos goto out;
576 1.48 christos
577 1.49 christos if (!(gpt->flags & GPT_NOSYNC)) {
578 1.47 christos #ifdef DIOCMWEDGES
579 1.47 christos int bits;
580 1.49 christos if (ioctl(gpt->fd, DIOCMWEDGES, &bits) == -1)
581 1.49 christos gpt_warn(gpt, "Can't update wedge information");
582 1.48 christos else
583 1.48 christos goto out;
584 1.47 christos #endif
585 1.47 christos }
586 1.49 christos gpt_msg(gpt, "You need to run \"dkctl %s makewedges\""
587 1.49 christos " for the changes to take effect\n", gpt->device_name);
588 1.46 christos
589 1.48 christos out:
590 1.49 christos close(gpt->fd);
591 1.1 christos }
592 1.1 christos
593 1.42 christos void
594 1.49 christos gpt_warnx(gpt_t gpt, const char *fmt, ...)
595 1.42 christos {
596 1.42 christos va_list ap;
597 1.48 christos
598 1.49 christos if (gpt->flags & GPT_QUIET)
599 1.48 christos return;
600 1.49 christos fprintf(stderr, "%s: %s: ", getprogname(), gpt->device_name);
601 1.49 christos va_start(ap, fmt);
602 1.49 christos vfprintf(stderr, fmt, ap);
603 1.49 christos va_end(ap);
604 1.49 christos fprintf(stderr, "\n");
605 1.49 christos }
606 1.49 christos
607 1.49 christos void
608 1.49 christos gpt_warn(gpt_t gpt, const char *fmt, ...)
609 1.49 christos {
610 1.49 christos va_list ap;
611 1.49 christos int e = errno;
612 1.49 christos
613 1.49 christos if (gpt->flags & GPT_QUIET)
614 1.49 christos return;
615 1.49 christos fprintf(stderr, "%s: %s: ", getprogname(), gpt->device_name);
616 1.49 christos va_start(ap, fmt);
617 1.49 christos vfprintf(stderr, fmt, ap);
618 1.49 christos va_end(ap);
619 1.49 christos fprintf(stderr, " (%s)\n", strerror(e));
620 1.49 christos errno = e;
621 1.49 christos }
622 1.49 christos
623 1.49 christos void
624 1.49 christos gpt_msg(gpt_t gpt, const char *fmt, ...)
625 1.49 christos {
626 1.49 christos va_list ap;
627 1.49 christos
628 1.49 christos if (gpt->flags & GPT_QUIET)
629 1.49 christos return;
630 1.49 christos printf("%s: ", gpt->device_name);
631 1.42 christos va_start(ap, fmt);
632 1.42 christos vprintf(fmt, ap);
633 1.42 christos va_end(ap);
634 1.42 christos printf("\n");
635 1.42 christos }
636 1.49 christos
637 1.49 christos struct gpt_hdr *
638 1.49 christos gpt_hdr(gpt_t gpt)
639 1.49 christos {
640 1.49 christos gpt->gpt = map_find(gpt, MAP_TYPE_PRI_GPT_HDR);
641 1.49 christos if (gpt->gpt == NULL) {
642 1.49 christos gpt_warnx(gpt, "No primary GPT header; run create or recover");
643 1.49 christos return NULL;
644 1.49 christos }
645 1.49 christos
646 1.49 christos gpt->tpg = map_find(gpt, MAP_TYPE_SEC_GPT_HDR);
647 1.49 christos if (gpt->tpg == NULL) {
648 1.49 christos gpt_warnx(gpt, "No secondary GPT header; run recover");
649 1.49 christos return NULL;
650 1.49 christos }
651 1.49 christos
652 1.49 christos gpt->tbl = map_find(gpt, MAP_TYPE_PRI_GPT_TBL);
653 1.49 christos gpt->lbt = map_find(gpt, MAP_TYPE_SEC_GPT_TBL);
654 1.49 christos if (gpt->tbl == NULL || gpt->lbt == NULL) {
655 1.49 christos gpt_warnx(gpt, "Corrupt maps, run recover");
656 1.49 christos return NULL;
657 1.49 christos }
658 1.49 christos
659 1.49 christos return gpt->gpt->map_data;
660 1.49 christos }
661 1.49 christos
662 1.49 christos int
663 1.49 christos gpt_write_crc(gpt_t gpt, map_t map, map_t tbl)
664 1.49 christos {
665 1.49 christos struct gpt_hdr *hdr = map->map_data;
666 1.49 christos
667 1.49 christos hdr->hdr_crc_table = htole32(crc32(tbl->map_data,
668 1.49 christos le32toh(hdr->hdr_entries) * le32toh(hdr->hdr_entsz)));
669 1.49 christos hdr->hdr_crc_self = 0;
670 1.49 christos hdr->hdr_crc_self = htole32(crc32(hdr, le32toh(hdr->hdr_size)));
671 1.49 christos
672 1.49 christos if (gpt_write(gpt, map) == -1) {
673 1.49 christos gpt_warn(gpt, "Error writing crc map");
674 1.49 christos return -1;
675 1.49 christos }
676 1.49 christos
677 1.49 christos if (gpt_write(gpt, tbl) == -1) {
678 1.49 christos gpt_warn(gpt, "Error writing crc table");
679 1.49 christos return -1;
680 1.49 christos }
681 1.49 christos
682 1.49 christos return 0;
683 1.49 christos }
684 1.49 christos
685 1.49 christos int
686 1.49 christos gpt_write_primary(gpt_t gpt)
687 1.49 christos {
688 1.49 christos return gpt_write_crc(gpt, gpt->gpt, gpt->tbl);
689 1.49 christos }
690 1.49 christos
691 1.49 christos
692 1.49 christos int
693 1.49 christos gpt_write_backup(gpt_t gpt)
694 1.49 christos {
695 1.49 christos return gpt_write_crc(gpt, gpt->tpg, gpt->lbt);
696 1.49 christos }
697 1.49 christos
698 1.49 christos void
699 1.49 christos gpt_create_pmbr_part(struct mbr_part *part, off_t last)
700 1.49 christos {
701 1.49 christos part->part_shd = 0x00;
702 1.49 christos part->part_ssect = 0x02;
703 1.49 christos part->part_scyl = 0x00;
704 1.49 christos part->part_typ = MBR_PTYPE_PMBR;
705 1.49 christos part->part_ehd = 0xfe;
706 1.49 christos part->part_esect = 0xff;
707 1.49 christos part->part_ecyl = 0xff;
708 1.49 christos part->part_start_lo = htole16(1);
709 1.49 christos if (last > 0xffffffff) {
710 1.49 christos part->part_size_lo = htole16(0xffff);
711 1.49 christos part->part_size_hi = htole16(0xffff);
712 1.49 christos } else {
713 1.59 christos part->part_size_lo = htole16((uint16_t)last);
714 1.59 christos part->part_size_hi = htole16((uint16_t)(last >> 16));
715 1.49 christos }
716 1.49 christos }
717 1.49 christos
718 1.49 christos
719 1.49 christos struct gpt_ent *
720 1.49 christos gpt_ent(map_t map, map_t tbl, unsigned int i)
721 1.49 christos {
722 1.49 christos struct gpt_hdr *hdr = map->map_data;
723 1.49 christos return (void *)((char *)tbl->map_data + i * le32toh(hdr->hdr_entsz));
724 1.49 christos }
725 1.49 christos
726 1.49 christos struct gpt_ent *
727 1.49 christos gpt_ent_primary(gpt_t gpt, unsigned int i)
728 1.49 christos {
729 1.49 christos return gpt_ent(gpt->gpt, gpt->tbl, i);
730 1.49 christos }
731 1.49 christos
732 1.49 christos struct gpt_ent *
733 1.49 christos gpt_ent_backup(gpt_t gpt, unsigned int i)
734 1.49 christos {
735 1.49 christos return gpt_ent(gpt->tpg, gpt->lbt, i);
736 1.49 christos }
737 1.50 christos
738 1.50 christos int
739 1.50 christos gpt_usage(const char *prefix, const struct gpt_cmd *cmd)
740 1.50 christos {
741 1.50 christos const char **a = cmd->help;
742 1.50 christos size_t hlen = cmd->hlen;
743 1.50 christos size_t i;
744 1.50 christos
745 1.50 christos if (prefix == NULL) {
746 1.50 christos const char *pname = getprogname();
747 1.54 christos const char *d1, *d2, *d = " <device>";
748 1.50 christos int len = (int)strlen(pname);
749 1.54 christos if (strcmp(pname, "gpt") == 0) {
750 1.54 christos d1 = "";
751 1.54 christos d2 = d;
752 1.54 christos } else {
753 1.54 christos d2 = "";
754 1.54 christos d1 = d;
755 1.54 christos }
756 1.54 christos fprintf(stderr, "Usage: %s%s %s %s%s\n", pname,
757 1.54 christos d1, cmd->name, a[0], d2);
758 1.50 christos for (i = 1; i < hlen; i++) {
759 1.50 christos fprintf(stderr,
760 1.54 christos " %*s%s %s %s%s\n", len, "",
761 1.54 christos d1, cmd->name, a[i], d2);
762 1.50 christos }
763 1.50 christos } else {
764 1.50 christos for (i = 0; i < hlen; i++)
765 1.50 christos fprintf(stderr, "%s%s %s\n", prefix, cmd->name, a[i]);
766 1.50 christos }
767 1.50 christos return -1;
768 1.50 christos }
769 1.51 christos
770 1.51 christos off_t
771 1.51 christos gpt_last(gpt_t gpt)
772 1.51 christos {
773 1.51 christos return gpt->mediasz / gpt->secsz - 1LL;
774 1.51 christos }
775 1.51 christos
776 1.59 christos off_t
777 1.51 christos gpt_create(gpt_t gpt, off_t last, u_int parts, int primary_only)
778 1.51 christos {
779 1.51 christos off_t blocks;
780 1.51 christos map_t map;
781 1.51 christos struct gpt_hdr *hdr;
782 1.51 christos struct gpt_ent *ent;
783 1.51 christos unsigned int i;
784 1.51 christos void *p;
785 1.51 christos
786 1.51 christos if (map_find(gpt, MAP_TYPE_PRI_GPT_HDR) != NULL ||
787 1.51 christos map_find(gpt, MAP_TYPE_SEC_GPT_HDR) != NULL) {
788 1.51 christos gpt_warnx(gpt, "Device already contains a GPT");
789 1.51 christos return -1;
790 1.51 christos }
791 1.51 christos
792 1.51 christos /* Get the amount of free space after the MBR */
793 1.51 christos blocks = map_free(gpt, 1LL, 0LL);
794 1.51 christos if (blocks == 0LL) {
795 1.51 christos gpt_warnx(gpt, "No room for the GPT header");
796 1.51 christos return -1;
797 1.51 christos }
798 1.51 christos
799 1.51 christos /* Don't create more than parts entries. */
800 1.51 christos if ((uint64_t)(blocks - 1) * gpt->secsz >
801 1.51 christos parts * sizeof(struct gpt_ent)) {
802 1.59 christos blocks = (off_t)((parts * sizeof(struct gpt_ent)) / gpt->secsz);
803 1.51 christos if ((parts * sizeof(struct gpt_ent)) % gpt->secsz)
804 1.51 christos blocks++;
805 1.51 christos blocks++; /* Don't forget the header itself */
806 1.51 christos }
807 1.51 christos
808 1.51 christos /* Never cross the median of the device. */
809 1.51 christos if ((blocks + 1LL) > ((last + 1LL) >> 1))
810 1.51 christos blocks = ((last + 1LL) >> 1) - 1LL;
811 1.51 christos
812 1.51 christos /*
813 1.51 christos * Get the amount of free space at the end of the device and
814 1.51 christos * calculate the size for the GPT structures.
815 1.51 christos */
816 1.51 christos map = map_last(gpt);
817 1.51 christos if (map->map_type != MAP_TYPE_UNUSED) {
818 1.51 christos gpt_warnx(gpt, "No room for the backup header");
819 1.51 christos return -1;
820 1.51 christos }
821 1.51 christos
822 1.51 christos if (map->map_size < blocks)
823 1.51 christos blocks = map->map_size;
824 1.51 christos if (blocks == 1LL) {
825 1.51 christos gpt_warnx(gpt, "No room for the GPT table");
826 1.51 christos return -1;
827 1.51 christos }
828 1.51 christos
829 1.51 christos blocks--; /* Number of blocks in the GPT table. */
830 1.51 christos
831 1.51 christos if ((p = calloc(1, gpt->secsz)) == NULL) {
832 1.51 christos gpt_warnx(gpt, "Can't allocate the primary GPT");
833 1.51 christos return -1;
834 1.51 christos }
835 1.51 christos if ((gpt->gpt = map_add(gpt, 1LL, 1LL,
836 1.61 christos MAP_TYPE_PRI_GPT_HDR, p, 1)) == NULL) {
837 1.51 christos free(p);
838 1.51 christos gpt_warnx(gpt, "Can't add the primary GPT");
839 1.51 christos return -1;
840 1.51 christos }
841 1.51 christos
842 1.59 christos if ((p = calloc((size_t)blocks, gpt->secsz)) == NULL) {
843 1.51 christos gpt_warnx(gpt, "Can't allocate the primary GPT table");
844 1.51 christos return -1;
845 1.51 christos }
846 1.51 christos if ((gpt->tbl = map_add(gpt, 2LL, blocks,
847 1.61 christos MAP_TYPE_PRI_GPT_TBL, p, 1)) == NULL) {
848 1.51 christos free(p);
849 1.51 christos gpt_warnx(gpt, "Can't add the primary GPT table");
850 1.51 christos return -1;
851 1.51 christos }
852 1.51 christos
853 1.51 christos hdr = gpt->gpt->map_data;
854 1.51 christos memcpy(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig));
855 1.51 christos
856 1.51 christos /*
857 1.51 christos * XXX struct gpt_hdr is not a multiple of 8 bytes in size and thus
858 1.51 christos * contains padding we must not include in the size.
859 1.51 christos */
860 1.51 christos hdr->hdr_revision = htole32(GPT_HDR_REVISION);
861 1.51 christos hdr->hdr_size = htole32(GPT_HDR_SIZE);
862 1.59 christos hdr->hdr_lba_self = htole64((uint64_t)gpt->gpt->map_start);
863 1.59 christos hdr->hdr_lba_alt = htole64((uint64_t)last);
864 1.59 christos hdr->hdr_lba_start = htole64((uint64_t)(gpt->tbl->map_start + blocks));
865 1.59 christos hdr->hdr_lba_end = htole64((uint64_t)(last - blocks - 1LL));
866 1.52 christos if (gpt_uuid_generate(gpt, hdr->hdr_guid) == -1)
867 1.52 christos return -1;
868 1.59 christos hdr->hdr_lba_table = htole64((uint64_t)(gpt->tbl->map_start));
869 1.59 christos hdr->hdr_entries = htole32((uint32_t)(((uint64_t)blocks * gpt->secsz) /
870 1.59 christos sizeof(struct gpt_ent)));
871 1.51 christos if (le32toh(hdr->hdr_entries) > parts)
872 1.51 christos hdr->hdr_entries = htole32(parts);
873 1.51 christos hdr->hdr_entsz = htole32(sizeof(struct gpt_ent));
874 1.51 christos
875 1.51 christos ent = gpt->tbl->map_data;
876 1.51 christos for (i = 0; i < le32toh(hdr->hdr_entries); i++) {
877 1.52 christos if (gpt_uuid_generate(gpt, ent[i].ent_guid) == -1)
878 1.52 christos return -1;
879 1.51 christos }
880 1.51 christos
881 1.51 christos /*
882 1.51 christos * Create backup GPT if the user didn't suppress it.
883 1.51 christos */
884 1.51 christos if (primary_only)
885 1.51 christos return last;
886 1.51 christos
887 1.51 christos if ((p = calloc(1, gpt->secsz)) == NULL) {
888 1.51 christos gpt_warnx(gpt, "Can't allocate the secondary GPT");
889 1.51 christos return -1;
890 1.51 christos }
891 1.51 christos
892 1.51 christos if ((gpt->tpg = map_add(gpt, last, 1LL,
893 1.61 christos MAP_TYPE_SEC_GPT_HDR, p, 1)) == NULL) {
894 1.51 christos gpt_warnx(gpt, "Can't add the secondary GPT");
895 1.51 christos return -1;
896 1.51 christos }
897 1.51 christos
898 1.51 christos if ((gpt->lbt = map_add(gpt, last - blocks, blocks,
899 1.61 christos MAP_TYPE_SEC_GPT_TBL, gpt->tbl->map_data, 0)) == NULL) {
900 1.51 christos gpt_warnx(gpt, "Can't add the secondary GPT table");
901 1.51 christos return -1;
902 1.51 christos }
903 1.51 christos
904 1.51 christos memcpy(gpt->tpg->map_data, gpt->gpt->map_data, gpt->secsz);
905 1.51 christos
906 1.51 christos hdr = gpt->tpg->map_data;
907 1.59 christos hdr->hdr_lba_self = htole64((uint64_t)gpt->tpg->map_start);
908 1.59 christos hdr->hdr_lba_alt = htole64((uint64_t)gpt->gpt->map_start);
909 1.59 christos hdr->hdr_lba_table = htole64((uint64_t)gpt->lbt->map_start);
910 1.51 christos return last;
911 1.51 christos }
912 1.51 christos
913 1.52 christos static int
914 1.52 christos gpt_size_get(gpt_t gpt, off_t *size)
915 1.52 christos {
916 1.52 christos off_t sectors;
917 1.52 christos int64_t human_num;
918 1.52 christos char *p;
919 1.52 christos
920 1.52 christos if (*size > 0)
921 1.52 christos return -1;
922 1.52 christos sectors = strtoll(optarg, &p, 10);
923 1.52 christos if (sectors < 1)
924 1.52 christos return -1;
925 1.52 christos if (*p == '\0' || ((*p == 's' || *p == 'S') && p[1] == '\0')) {
926 1.52 christos *size = sectors * gpt->secsz;
927 1.52 christos return 0;
928 1.52 christos }
929 1.52 christos if ((*p == 'b' || *p == 'B') && p[1] == '\0') {
930 1.52 christos *size = sectors;
931 1.52 christos return 0;
932 1.52 christos }
933 1.52 christos if (dehumanize_number(optarg, &human_num) < 0)
934 1.52 christos return -1;
935 1.52 christos *size = human_num;
936 1.52 christos return 0;
937 1.52 christos }
938 1.52 christos
939 1.51 christos int
940 1.52 christos gpt_human_get(off_t *human)
941 1.51 christos {
942 1.51 christos int64_t human_num;
943 1.51 christos
944 1.52 christos if (*human > 0)
945 1.52 christos return -1;
946 1.52 christos if (dehumanize_number(optarg, &human_num) < 0)
947 1.52 christos return -1;
948 1.52 christos *human = human_num;
949 1.52 christos if (*human < 1)
950 1.52 christos return -1;
951 1.52 christos return 0;
952 1.52 christos }
953 1.52 christos
954 1.52 christos int
955 1.52 christos gpt_add_find(gpt_t gpt, struct gpt_find *find, int ch)
956 1.52 christos {
957 1.51 christos switch (ch) {
958 1.51 christos case 'a':
959 1.51 christos if (find->all > 0)
960 1.51 christos return -1;
961 1.51 christos find->all = 1;
962 1.51 christos break;
963 1.51 christos case 'b':
964 1.52 christos if (gpt_human_get(&find->block) == -1)
965 1.51 christos return -1;
966 1.51 christos break;
967 1.51 christos case 'i':
968 1.59 christos if (gpt_uint_get(&find->entry) == -1)
969 1.51 christos return -1;
970 1.51 christos break;
971 1.51 christos case 'L':
972 1.52 christos if (gpt_name_get(gpt, &find->label) == -1)
973 1.51 christos return -1;
974 1.51 christos break;
975 1.51 christos case 's':
976 1.52 christos if (gpt_size_get(gpt, &find->size) == -1)
977 1.51 christos return -1;
978 1.51 christos break;
979 1.51 christos case 't':
980 1.51 christos if (!gpt_uuid_is_nil(find->type))
981 1.51 christos return -1;
982 1.51 christos if (gpt_uuid_parse(optarg, find->type) != 0)
983 1.51 christos return -1;
984 1.51 christos break;
985 1.51 christos default:
986 1.51 christos return -1;
987 1.51 christos }
988 1.51 christos return 0;
989 1.51 christos }
990 1.51 christos
991 1.51 christos int
992 1.51 christos gpt_change_ent(gpt_t gpt, const struct gpt_find *find,
993 1.51 christos void (*cfn)(struct gpt_ent *, void *), void *v)
994 1.51 christos {
995 1.51 christos map_t m;
996 1.51 christos struct gpt_hdr *hdr;
997 1.51 christos struct gpt_ent *ent;
998 1.51 christos unsigned int i;
999 1.53 christos uint8_t utfbuf[__arraycount(ent->ent_name) * 3 + 1];
1000 1.51 christos
1001 1.51 christos if (!find->all ^
1002 1.51 christos (find->block > 0 || find->entry > 0 || find->label != NULL
1003 1.51 christos || find->size > 0 || !gpt_uuid_is_nil(find->type)))
1004 1.51 christos return -1;
1005 1.51 christos
1006 1.51 christos if ((hdr = gpt_hdr(gpt)) == NULL)
1007 1.51 christos return -1;
1008 1.51 christos
1009 1.51 christos /* Relabel all matching entries in the map. */
1010 1.51 christos for (m = map_first(gpt); m != NULL; m = m->map_next) {
1011 1.51 christos if (m->map_type != MAP_TYPE_GPT_PART || m->map_index < 1)
1012 1.51 christos continue;
1013 1.51 christos if (find->entry > 0 && find->entry != m->map_index)
1014 1.51 christos continue;
1015 1.51 christos if (find->block > 0 && find->block != m->map_start)
1016 1.51 christos continue;
1017 1.51 christos if (find->size > 0 && find->size != m->map_size)
1018 1.51 christos continue;
1019 1.51 christos
1020 1.51 christos i = m->map_index - 1;
1021 1.51 christos
1022 1.51 christos ent = gpt_ent_primary(gpt, i);
1023 1.53 christos if (find->label != NULL) {
1024 1.53 christos utf16_to_utf8(ent->ent_name, utfbuf, sizeof(utfbuf));
1025 1.53 christos if (strcmp((char *)find->label, (char *)utfbuf) == 0)
1026 1.51 christos continue;
1027 1.53 christos }
1028 1.51 christos
1029 1.51 christos if (!gpt_uuid_is_nil(find->type) &&
1030 1.51 christos !gpt_uuid_equal(find->type, ent->ent_type))
1031 1.51 christos continue;
1032 1.51 christos
1033 1.51 christos /* Change the primary entry. */
1034 1.51 christos (*cfn)(ent, v);
1035 1.51 christos
1036 1.51 christos if (gpt_write_primary(gpt) == -1)
1037 1.51 christos return -1;
1038 1.51 christos
1039 1.51 christos ent = gpt_ent_backup(gpt, i);
1040 1.51 christos /* Change the secondary entry. */
1041 1.51 christos (*cfn)(ent, v);
1042 1.51 christos
1043 1.51 christos if (gpt_write_backup(gpt) == -1)
1044 1.51 christos return -1;
1045 1.51 christos
1046 1.51 christos gpt_msg(gpt, "Partition %d %s", m->map_index, find->msg);
1047 1.51 christos }
1048 1.51 christos return 0;
1049 1.51 christos }
1050 1.51 christos
1051 1.51 christos int
1052 1.51 christos gpt_add_ais(gpt_t gpt, off_t *alignment, u_int *entry, off_t *size, int ch)
1053 1.51 christos {
1054 1.51 christos switch (ch) {
1055 1.51 christos case 'a':
1056 1.52 christos if (gpt_human_get(alignment) == -1)
1057 1.51 christos return -1;
1058 1.51 christos return 0;
1059 1.51 christos case 'i':
1060 1.59 christos if (gpt_uint_get(entry) == -1)
1061 1.51 christos return -1;
1062 1.51 christos return 0;
1063 1.51 christos case 's':
1064 1.52 christos if (gpt_size_get(gpt, size) == -1)
1065 1.51 christos return -1;
1066 1.51 christos return 0;
1067 1.51 christos default:
1068 1.51 christos return -1;
1069 1.51 christos }
1070 1.51 christos }
1071 1.51 christos
1072 1.51 christos off_t
1073 1.51 christos gpt_check_ais(gpt_t gpt, off_t alignment, u_int entry, off_t size)
1074 1.51 christos {
1075 1.51 christos if (entry == 0) {
1076 1.51 christos gpt_warnx(gpt, "Entry not specified");
1077 1.51 christos return -1;
1078 1.51 christos }
1079 1.51 christos if (alignment % gpt->secsz != 0) {
1080 1.51 christos gpt_warnx(gpt, "Alignment (%#jx) must be a multiple of "
1081 1.51 christos "sector size (%#x)", (uintmax_t)alignment, gpt->secsz);
1082 1.51 christos return -1;
1083 1.51 christos }
1084 1.51 christos
1085 1.51 christos if (size % gpt->secsz != 0) {
1086 1.51 christos gpt_warnx(gpt, "Size (%#jx) must be a multiple of "
1087 1.51 christos "sector size (%#x)", (uintmax_t)size, gpt->secsz);
1088 1.51 christos return -1;
1089 1.51 christos }
1090 1.51 christos if (size > 0)
1091 1.51 christos return size / gpt->secsz;
1092 1.51 christos return 0;
1093 1.51 christos }
1094 1.51 christos int
1095 1.51 christos gpt_attr_get(uint64_t *attributes)
1096 1.51 christos {
1097 1.51 christos if (strcmp(optarg, "biosboot") == 0)
1098 1.51 christos *attributes |= GPT_ENT_ATTR_LEGACY_BIOS_BOOTABLE;
1099 1.51 christos else if (strcmp(optarg, "bootme") == 0)
1100 1.51 christos *attributes |= GPT_ENT_ATTR_BOOTME;
1101 1.51 christos else if (strcmp(optarg, "bootonce") == 0)
1102 1.51 christos *attributes |= GPT_ENT_ATTR_BOOTONCE;
1103 1.51 christos else if (strcmp(optarg, "bootfailed") == 0)
1104 1.51 christos *attributes |= GPT_ENT_ATTR_BOOTFAILED;
1105 1.51 christos else
1106 1.51 christos return -1;
1107 1.51 christos return 0;
1108 1.51 christos }
1109 1.51 christos int
1110 1.51 christos gpt_attr_update(gpt_t gpt, u_int entry, uint64_t set, uint64_t clr)
1111 1.51 christos {
1112 1.51 christos struct gpt_hdr *hdr;
1113 1.51 christos struct gpt_ent *ent;
1114 1.51 christos unsigned int i;
1115 1.51 christos
1116 1.51 christos if (entry == 0 || (set == 0 && clr == 0))
1117 1.51 christos return -1;
1118 1.51 christos
1119 1.51 christos if ((hdr = gpt_hdr(gpt)) == NULL)
1120 1.51 christos return -1;
1121 1.51 christos
1122 1.51 christos if (entry > le32toh(hdr->hdr_entries)) {
1123 1.51 christos gpt_warnx(gpt, "Index %u out of range (%u max)",
1124 1.51 christos entry, le32toh(hdr->hdr_entries));
1125 1.51 christos return -1;
1126 1.51 christos }
1127 1.51 christos
1128 1.51 christos i = entry - 1;
1129 1.51 christos ent = gpt_ent_primary(gpt, i);
1130 1.51 christos if (gpt_uuid_is_nil(ent->ent_type)) {
1131 1.51 christos gpt_warnx(gpt, "Entry at index %u is unused", entry);
1132 1.51 christos return -1;
1133 1.51 christos }
1134 1.51 christos
1135 1.51 christos ent->ent_attr &= ~clr;
1136 1.51 christos ent->ent_attr |= set;
1137 1.51 christos
1138 1.51 christos if (gpt_write_primary(gpt) == -1)
1139 1.51 christos return -1;
1140 1.51 christos
1141 1.51 christos ent = gpt_ent_backup(gpt, i);
1142 1.51 christos ent->ent_attr &= ~clr;
1143 1.51 christos ent->ent_attr |= set;
1144 1.51 christos
1145 1.51 christos if (gpt_write_backup(gpt) == -1)
1146 1.51 christos return -1;
1147 1.51 christos gpt_msg(gpt, "Partition %d attributes updated", entry);
1148 1.51 christos return 0;
1149 1.51 christos }
1150 1.51 christos
1151 1.51 christos int
1152 1.59 christos gpt_uint_get(u_int *entry)
1153 1.51 christos {
1154 1.51 christos char *p;
1155 1.51 christos if (*entry > 0)
1156 1.51 christos return -1;
1157 1.59 christos *entry = (u_int)strtoul(optarg, &p, 10);
1158 1.51 christos if (*p != 0 || *entry < 1)
1159 1.51 christos return -1;
1160 1.51 christos return 0;
1161 1.51 christos }
1162 1.52 christos int
1163 1.52 christos gpt_uuid_get(gpt_t gpt, gpt_uuid_t *uuid)
1164 1.52 christos {
1165 1.52 christos if (!gpt_uuid_is_nil(*uuid))
1166 1.52 christos return -1;
1167 1.52 christos if (gpt_uuid_parse(optarg, *uuid) != 0) {
1168 1.52 christos gpt_warn(gpt, "Can't parse uuid");
1169 1.52 christos return -1;
1170 1.52 christos }
1171 1.52 christos return 0;
1172 1.52 christos }
1173 1.52 christos
1174 1.52 christos int
1175 1.52 christos gpt_name_get(gpt_t gpt, void *v)
1176 1.52 christos {
1177 1.52 christos char **name = v;
1178 1.52 christos if (*name != NULL)
1179 1.52 christos return -1;
1180 1.52 christos *name = strdup(optarg);
1181 1.52 christos if (*name == NULL) {
1182 1.52 christos gpt_warn(gpt, "Can't copy string");
1183 1.52 christos return -1;
1184 1.52 christos }
1185 1.52 christos return 0;
1186 1.52 christos }
1187 1.59 christos
1188 1.59 christos void
1189 1.59 christos gpt_show_num(const char *prompt, uintmax_t num)
1190 1.59 christos {
1191 1.59 christos #ifdef HN_AUTOSCALE
1192 1.59 christos char human_num[5];
1193 1.59 christos if (humanize_number(human_num, 5, (int64_t)num ,
1194 1.59 christos "", HN_AUTOSCALE, HN_NOSPACE|HN_B) < 0)
1195 1.59 christos human_num[0] = '\0';
1196 1.59 christos #endif
1197 1.59 christos printf("%s: %ju", prompt, num);
1198 1.59 christos #ifdef HN_AUTOSCALE
1199 1.59 christos if (human_num[0] != '\0')
1200 1.60 christos printf(" (%s)", human_num);
1201 1.59 christos #endif
1202 1.59 christos printf("\n");
1203 1.59 christos }
1204