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