migrate.c revision 1.28 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
27 1.15 christos #if HAVE_NBTOOL_CONFIG_H
28 1.15 christos #include "nbtool_config.h"
29 1.15 christos #endif
30 1.15 christos
31 1.1 christos #include <sys/cdefs.h>
32 1.2 christos #ifdef __FBSDID
33 1.1 christos __FBSDID("$FreeBSD: src/sbin/gpt/migrate.c,v 1.16 2005/09/01 02:42:52 marcel Exp $");
34 1.2 christos #endif
35 1.2 christos #ifdef __RCSID
36 1.28 christos __RCSID("$NetBSD: migrate.c,v 1.28 2015/12/05 18:46:08 christos Exp $");
37 1.2 christos #endif
38 1.1 christos
39 1.1 christos #include <sys/types.h>
40 1.3 he #include <sys/param.h>
41 1.28 christos #define FSTYPENAMES
42 1.28 christos #define MBRPTYPENAMES
43 1.17 christos #ifdef HAVE_NBTOOL_CONFIG_H
44 1.17 christos #include <nbinclude/sys/bootblock.h>
45 1.17 christos #include <nbinclude/sys/disklabel.h>
46 1.17 christos #else
47 1.9 jnemeth #include <sys/bootblock.h>
48 1.1 christos #include <sys/disklabel.h>
49 1.17 christos #endif
50 1.1 christos
51 1.1 christos #include <err.h>
52 1.1 christos #include <stddef.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.1 christos
58 1.1 christos #include "map.h"
59 1.1 christos #include "gpt.h"
60 1.23 christos #include "gpt_private.h"
61 1.1 christos
62 1.1 christos /*
63 1.1 christos * Allow compilation on platforms that do not have a BSD label.
64 1.1 christos * The values are valid for amd64, i386 and ia64 disklabels.
65 1.15 christos * XXX: use disklabel_params from disklabel.c
66 1.1 christos */
67 1.1 christos #ifndef LABELOFFSET
68 1.1 christos #define LABELOFFSET 0
69 1.1 christos #endif
70 1.1 christos #ifndef LABELSECTOR
71 1.1 christos #define LABELSECTOR 1
72 1.1 christos #endif
73 1.15 christos #ifndef RAW_PART
74 1.15 christos #define RAW_PART 3
75 1.15 christos #endif
76 1.1 christos
77 1.10 jnemeth /* FreeBSD filesystem types that don't match corresponding NetBSD types */
78 1.10 jnemeth #define FREEBSD_FS_VINUM 14
79 1.10 jnemeth #define FREEBSD_FS_ZFS 27
80 1.10 jnemeth
81 1.24 christos static int cmd_migrate(gpt_t, int, char *[]);
82 1.4 riz
83 1.24 christos static const char *migratehelp[] = {
84 1.26 christos "[-fs] [-p partitions]",
85 1.24 christos };
86 1.24 christos
87 1.24 christos struct gpt_cmd c_migrate = {
88 1.24 christos "migrate",
89 1.24 christos cmd_migrate,
90 1.24 christos migratehelp, __arraycount(migratehelp),
91 1.24 christos 0,
92 1.24 christos };
93 1.1 christos
94 1.24 christos #define usage() gpt_usage(NULL, &c_migrate)
95 1.1 christos
96 1.28 christos static const char *
97 1.28 christos fstypename(u_int t)
98 1.28 christos {
99 1.28 christos static char buf[64];
100 1.28 christos if (t >= __arraycount(fstypenames)) {
101 1.28 christos snprintf(buf, sizeof(buf), "*%u*", t);
102 1.28 christos return buf;
103 1.28 christos }
104 1.28 christos return fstypenames[t];
105 1.28 christos }
106 1.28 christos
107 1.28 christos static const char *
108 1.28 christos mbrptypename(u_int t)
109 1.28 christos {
110 1.28 christos static char buf[64];
111 1.28 christos size_t i;
112 1.28 christos
113 1.28 christos for (i = 0; i < __arraycount(mbr_ptypes); i++)
114 1.28 christos if ((u_int)mbr_ptypes[i].id == t)
115 1.28 christos return mbr_ptypes[i].name;
116 1.28 christos
117 1.28 christos snprintf(buf, sizeof(buf), "*%u*", t);
118 1.28 christos return buf;
119 1.28 christos }
120 1.28 christos
121 1.23 christos static struct gpt_ent *
122 1.23 christos migrate_disklabel(gpt_t gpt, off_t start, struct gpt_ent *ent)
123 1.1 christos {
124 1.1 christos char *buf;
125 1.1 christos struct disklabel *dl;
126 1.1 christos off_t ofs, rawofs;
127 1.1 christos int i;
128 1.1 christos
129 1.23 christos buf = gpt_read(gpt, start + LABELSECTOR, 1);
130 1.23 christos if (buf == NULL) {
131 1.23 christos gpt_warn(gpt, "Error reading label");
132 1.23 christos return NULL;
133 1.23 christos }
134 1.1 christos dl = (void*)(buf + LABELOFFSET);
135 1.1 christos
136 1.1 christos if (le32toh(dl->d_magic) != DISKMAGIC ||
137 1.1 christos le32toh(dl->d_magic2) != DISKMAGIC) {
138 1.23 christos gpt_warnx(gpt, "FreeBSD slice without disklabel");
139 1.12 christos free(buf);
140 1.1 christos return (ent);
141 1.1 christos }
142 1.1 christos
143 1.1 christos rawofs = le32toh(dl->d_partitions[RAW_PART].p_offset) *
144 1.1 christos le32toh(dl->d_secsize);
145 1.1 christos for (i = 0; i < le16toh(dl->d_npartitions); i++) {
146 1.1 christos if (dl->d_partitions[i].p_fstype == FS_UNUSED)
147 1.1 christos continue;
148 1.1 christos ofs = le32toh(dl->d_partitions[i].p_offset) *
149 1.1 christos le32toh(dl->d_secsize);
150 1.1 christos if (ofs < rawofs)
151 1.1 christos rawofs = 0;
152 1.1 christos }
153 1.23 christos rawofs /= gpt->secsz;
154 1.1 christos
155 1.1 christos for (i = 0; i < le16toh(dl->d_npartitions); i++) {
156 1.1 christos switch (dl->d_partitions[i].p_fstype) {
157 1.1 christos case FS_UNUSED:
158 1.1 christos continue;
159 1.1 christos case FS_SWAP: {
160 1.19 christos gpt_uuid_create(GPT_TYPE_FREEBSD_SWAP, ent->ent_type,
161 1.19 christos ent->ent_name, sizeof(ent->ent_name));
162 1.1 christos break;
163 1.1 christos }
164 1.1 christos case FS_BSDFFS: {
165 1.19 christos gpt_uuid_create(GPT_TYPE_FREEBSD_UFS, ent->ent_type,
166 1.19 christos ent->ent_name, sizeof(ent->ent_name));
167 1.1 christos break;
168 1.1 christos }
169 1.10 jnemeth case FREEBSD_FS_VINUM: {
170 1.19 christos gpt_uuid_create(GPT_TYPE_FREEBSD_VINUM, ent->ent_type,
171 1.19 christos ent->ent_name, sizeof(ent->ent_name));
172 1.1 christos break;
173 1.1 christos }
174 1.10 jnemeth case FREEBSD_FS_ZFS: {
175 1.19 christos gpt_uuid_create(GPT_TYPE_FREEBSD_ZFS, ent->ent_type,
176 1.19 christos ent->ent_name, sizeof(ent->ent_name));
177 1.8 jnemeth break;
178 1.8 jnemeth }
179 1.1 christos default:
180 1.23 christos gpt_warnx(gpt, "Unknown FreeBSD partition (%d)",
181 1.23 christos dl->d_partitions[i].p_fstype);
182 1.1 christos continue;
183 1.1 christos }
184 1.1 christos
185 1.1 christos ofs = (le32toh(dl->d_partitions[i].p_offset) *
186 1.23 christos le32toh(dl->d_secsize)) / gpt->secsz;
187 1.1 christos ofs = (ofs > 0) ? ofs - rawofs : 0;
188 1.27 christos ent->ent_lba_start = htole64((uint64_t)(start + ofs));
189 1.27 christos ent->ent_lba_end = htole64((uint64_t)(start + ofs +
190 1.27 christos (off_t)le32toh((uint64_t)dl->d_partitions[i].p_size)
191 1.27 christos - 1LL));
192 1.1 christos ent++;
193 1.1 christos }
194 1.1 christos
195 1.12 christos free(buf);
196 1.23 christos return ent;
197 1.1 christos }
198 1.1 christos
199 1.9 jnemeth static struct gpt_ent*
200 1.23 christos migrate_netbsd_disklabel(gpt_t gpt, off_t start, struct gpt_ent *ent)
201 1.9 jnemeth {
202 1.9 jnemeth char *buf;
203 1.9 jnemeth struct disklabel *dl;
204 1.9 jnemeth off_t ofs, rawofs;
205 1.28 christos unsigned int i;
206 1.28 christos gpt_type_t type;
207 1.9 jnemeth
208 1.23 christos buf = gpt_read(gpt, start + LABELSECTOR, 1);
209 1.23 christos if (buf == NULL) {
210 1.23 christos gpt_warn(gpt, "Error reading label");
211 1.23 christos return NULL;
212 1.23 christos }
213 1.9 jnemeth dl = (void*)(buf + LABELOFFSET);
214 1.9 jnemeth
215 1.9 jnemeth if (le32toh(dl->d_magic) != DISKMAGIC ||
216 1.9 jnemeth le32toh(dl->d_magic2) != DISKMAGIC) {
217 1.23 christos gpt_warnx(gpt, "NetBSD slice without disklabel");
218 1.12 christos free(buf);
219 1.23 christos return ent;
220 1.9 jnemeth }
221 1.9 jnemeth
222 1.9 jnemeth rawofs = le32toh(dl->d_partitions[RAW_PART].p_offset) *
223 1.9 jnemeth le32toh(dl->d_secsize);
224 1.9 jnemeth for (i = 0; i < le16toh(dl->d_npartitions); i++) {
225 1.9 jnemeth if (dl->d_partitions[i].p_fstype == FS_UNUSED)
226 1.9 jnemeth continue;
227 1.9 jnemeth ofs = le32toh(dl->d_partitions[i].p_offset) *
228 1.9 jnemeth le32toh(dl->d_secsize);
229 1.9 jnemeth if (ofs < rawofs)
230 1.9 jnemeth rawofs = 0;
231 1.9 jnemeth }
232 1.28 christos if (gpt->verbose > 1)
233 1.28 christos gpt_msg(gpt, "rawofs=%ju", (uintmax_t)rawofs);
234 1.23 christos rawofs /= gpt->secsz;
235 1.9 jnemeth
236 1.9 jnemeth for (i = 0; i < le16toh(dl->d_npartitions); i++) {
237 1.28 christos if (gpt->verbose > 1)
238 1.28 christos gpt_msg(gpt, "Disklabel partition %u type %s", i,
239 1.28 christos fstypename(dl->d_partitions[i].p_fstype));
240 1.28 christos
241 1.9 jnemeth switch (dl->d_partitions[i].p_fstype) {
242 1.9 jnemeth case FS_UNUSED:
243 1.9 jnemeth continue;
244 1.28 christos case FS_HFS:
245 1.28 christos type = GPT_TYPE_APPLE_HFS;
246 1.28 christos break;
247 1.28 christos case FS_EX2FS:
248 1.28 christos type = GPT_TYPE_LINUX_DATA;
249 1.28 christos break;
250 1.28 christos case FS_SWAP:
251 1.28 christos type = GPT_TYPE_NETBSD_SWAP;
252 1.9 jnemeth break;
253 1.28 christos case FS_BSDFFS:
254 1.28 christos type = GPT_TYPE_NETBSD_FFS;
255 1.9 jnemeth break;
256 1.28 christos case FS_BSDLFS:
257 1.28 christos type = GPT_TYPE_NETBSD_LFS;
258 1.9 jnemeth break;
259 1.28 christos case FS_RAID:
260 1.28 christos type = GPT_TYPE_NETBSD_RAIDFRAME;
261 1.9 jnemeth break;
262 1.28 christos case FS_CCD:
263 1.28 christos type = GPT_TYPE_NETBSD_CCD;
264 1.9 jnemeth break;
265 1.28 christos case FS_CGD:
266 1.28 christos type = GPT_TYPE_NETBSD_CGD;
267 1.9 jnemeth break;
268 1.9 jnemeth default:
269 1.28 christos gpt_warnx(gpt, "Partition %u unknown type %s, "
270 1.28 christos "using \"Microsoft Basic Data\"", i,
271 1.28 christos fstypename(dl->d_partitions[i].p_fstype));
272 1.28 christos type = GPT_TYPE_MS_BASIC_DATA;
273 1.28 christos break;
274 1.9 jnemeth }
275 1.9 jnemeth
276 1.28 christos gpt_uuid_create(type, ent->ent_type,
277 1.28 christos ent->ent_name, sizeof(ent->ent_name));
278 1.28 christos
279 1.9 jnemeth ofs = (le32toh(dl->d_partitions[i].p_offset) *
280 1.23 christos le32toh(dl->d_secsize)) / gpt->secsz;
281 1.9 jnemeth ofs = (ofs > 0) ? ofs - rawofs : 0;
282 1.27 christos ent->ent_lba_start = htole64((uint64_t)ofs);
283 1.27 christos ent->ent_lba_end = htole64((uint64_t)(ofs +
284 1.27 christos (off_t)le32toh((uint64_t)dl->d_partitions[i].p_size)
285 1.27 christos - 1LL));
286 1.9 jnemeth ent++;
287 1.9 jnemeth }
288 1.9 jnemeth
289 1.12 christos free(buf);
290 1.23 christos return ent;
291 1.9 jnemeth }
292 1.9 jnemeth
293 1.23 christos static int
294 1.26 christos migrate(gpt_t gpt, u_int parts, int force, int slice)
295 1.1 christos {
296 1.25 christos off_t last = gpt_last(gpt);
297 1.23 christos map_t map;
298 1.1 christos struct gpt_ent *ent;
299 1.1 christos struct mbr *mbr;
300 1.1 christos uint32_t start, size;
301 1.1 christos unsigned int i;
302 1.1 christos
303 1.23 christos map = map_find(gpt, MAP_TYPE_MBR);
304 1.1 christos if (map == NULL || map->map_start != 0) {
305 1.28 christos gpt_warnx(gpt, "No MBR in disk to convert");
306 1.23 christos return -1;
307 1.1 christos }
308 1.1 christos
309 1.1 christos mbr = map->map_data;
310 1.1 christos
311 1.25 christos if (gpt_create(gpt, last, parts, 0) == -1)
312 1.23 christos return -1;
313 1.1 christos
314 1.23 christos ent = gpt->tbl->map_data;
315 1.1 christos
316 1.1 christos /* Mirror partitions. */
317 1.1 christos for (i = 0; i < 4; i++) {
318 1.1 christos start = le16toh(mbr->mbr_part[i].part_start_hi);
319 1.1 christos start = (start << 16) + le16toh(mbr->mbr_part[i].part_start_lo);
320 1.1 christos size = le16toh(mbr->mbr_part[i].part_size_hi);
321 1.1 christos size = (size << 16) + le16toh(mbr->mbr_part[i].part_size_lo);
322 1.1 christos
323 1.28 christos if (gpt->verbose > 1)
324 1.28 christos gpt_msg(gpt, "MBR partition %u type %s", i,
325 1.28 christos mbrptypename(mbr->mbr_part[i].part_typ));
326 1.1 christos switch (mbr->mbr_part[i].part_typ) {
327 1.9 jnemeth case MBR_PTYPE_UNUSED:
328 1.1 christos continue;
329 1.9 jnemeth case MBR_PTYPE_386BSD: { /* FreeBSD */
330 1.1 christos if (slice) {
331 1.19 christos gpt_uuid_create(GPT_TYPE_FREEBSD,
332 1.19 christos ent->ent_type, ent->ent_name,
333 1.19 christos sizeof(ent->ent_name));
334 1.1 christos ent->ent_lba_start = htole64((uint64_t)start);
335 1.27 christos ent->ent_lba_end = htole64(
336 1.27 christos (uint64_t)(start + size - 1LL));
337 1.1 christos ent++;
338 1.1 christos } else
339 1.23 christos ent = migrate_disklabel(gpt, start, ent);
340 1.1 christos break;
341 1.1 christos }
342 1.9 jnemeth case MBR_PTYPE_NETBSD:
343 1.23 christos ent = migrate_netbsd_disklabel(gpt, start, ent);
344 1.9 jnemeth break;
345 1.9 jnemeth case MBR_PTYPE_EFI: {
346 1.19 christos gpt_uuid_create(GPT_TYPE_EFI,
347 1.19 christos ent->ent_type, ent->ent_name,
348 1.19 christos sizeof(ent->ent_name));
349 1.1 christos ent->ent_lba_start = htole64((uint64_t)start);
350 1.27 christos ent->ent_lba_end = htole64(
351 1.27 christos (uint64_t)(start + size - 1LL));
352 1.1 christos ent++;
353 1.1 christos break;
354 1.1 christos }
355 1.1 christos default:
356 1.1 christos if (!force) {
357 1.23 christos gpt_warnx(gpt, "unknown partition type (%d)",
358 1.23 christos mbr->mbr_part[i].part_typ);
359 1.23 christos return -1;
360 1.1 christos }
361 1.23 christos break;
362 1.1 christos }
363 1.1 christos }
364 1.1 christos
365 1.23 christos if (gpt_write_primary(gpt) == -1)
366 1.23 christos return -1;
367 1.1 christos
368 1.23 christos if (gpt_write_backup(gpt) == -1)
369 1.23 christos return -1;
370 1.1 christos
371 1.1 christos /*
372 1.1 christos * Turn the MBR into a Protective MBR.
373 1.1 christos */
374 1.16 christos memset(mbr->mbr_part, 0, sizeof(mbr->mbr_part));
375 1.23 christos gpt_create_pmbr_part(mbr->mbr_part, last);
376 1.25 christos if (gpt_write(gpt, map) == -1) {
377 1.25 christos gpt_warn(gpt, "Cant write PMBR");
378 1.25 christos return -1;
379 1.25 christos }
380 1.23 christos return 0;
381 1.1 christos }
382 1.1 christos
383 1.24 christos static int
384 1.23 christos cmd_migrate(gpt_t gpt, int argc, char *argv[])
385 1.1 christos {
386 1.23 christos int ch;
387 1.26 christos int force = 0;
388 1.26 christos int slice = 0;
389 1.26 christos u_int parts = 128;
390 1.1 christos
391 1.1 christos /* Get the migrate options */
392 1.23 christos while ((ch = getopt(argc, argv, "fp:s")) != -1) {
393 1.1 christos switch(ch) {
394 1.1 christos case 'f':
395 1.1 christos force = 1;
396 1.1 christos break;
397 1.23 christos case 'p':
398 1.27 christos if (gpt_uint_get(&parts) == -1)
399 1.27 christos return usage();
400 1.23 christos break;
401 1.1 christos case 's':
402 1.1 christos slice = 1;
403 1.1 christos break;
404 1.1 christos default:
405 1.24 christos return usage();
406 1.1 christos }
407 1.1 christos }
408 1.1 christos
409 1.23 christos if (argc != optind)
410 1.24 christos return usage();
411 1.1 christos
412 1.26 christos return migrate(gpt, parts, force, slice);
413 1.1 christos }
414