Annotation of src/sbin/gpt/migrate.c, Revision 1.20
1.1 christos 1: /*-
2: * Copyright (c) 2002 Marcel Moolenaar
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms, with or without
6: * modification, are permitted provided that the following conditions
7: * are met:
8: *
9: * 1. Redistributions of source code must retain the above copyright
10: * notice, this list of conditions and the following disclaimer.
11: * 2. Redistributions in binary form must reproduce the above copyright
12: * notice, this list of conditions and the following disclaimer in the
13: * documentation and/or other materials provided with the distribution.
14: *
15: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25: */
26:
1.15 christos 27: #if HAVE_NBTOOL_CONFIG_H
28: #include "nbtool_config.h"
29: #endif
30:
1.1 christos 31: #include <sys/cdefs.h>
1.2 christos 32: #ifdef __FBSDID
1.1 christos 33: __FBSDID("$FreeBSD: src/sbin/gpt/migrate.c,v 1.16 2005/09/01 02:42:52 marcel Exp $");
1.2 christos 34: #endif
35: #ifdef __RCSID
1.20 ! jnemeth 36: __RCSID("$NetBSD: migrate.c,v 1.19 2014/09/30 17:59:59 christos Exp $");
1.2 christos 37: #endif
1.1 christos 38:
39: #include <sys/types.h>
1.3 he 40: #include <sys/param.h>
1.17 christos 41: #ifdef HAVE_NBTOOL_CONFIG_H
42: #include <nbinclude/sys/bootblock.h>
43: #include <nbinclude/sys/disklabel.h>
44: #else
1.9 jnemeth 45: #include <sys/bootblock.h>
1.1 christos 46: #include <sys/disklabel.h>
1.17 christos 47: #endif
1.1 christos 48:
49: #include <err.h>
50: #include <stddef.h>
51: #include <stdio.h>
52: #include <stdlib.h>
53: #include <string.h>
54: #include <unistd.h>
55:
56: #include "map.h"
57: #include "gpt.h"
58:
59: /*
60: * Allow compilation on platforms that do not have a BSD label.
61: * The values are valid for amd64, i386 and ia64 disklabels.
1.15 christos 62: * XXX: use disklabel_params from disklabel.c
1.1 christos 63: */
64: #ifndef LABELOFFSET
65: #define LABELOFFSET 0
66: #endif
67: #ifndef LABELSECTOR
68: #define LABELSECTOR 1
69: #endif
1.15 christos 70: #ifndef RAW_PART
71: #define RAW_PART 3
72: #endif
1.1 christos 73:
1.10 jnemeth 74: /* FreeBSD filesystem types that don't match corresponding NetBSD types */
75: #define FREEBSD_FS_VINUM 14
76: #define FREEBSD_FS_ZFS 27
77:
1.1 christos 78: static int force;
79: static int slice;
80:
1.4 riz 81: const char migratemsg[] = "migrate [-fs] device ...";
82:
1.5 joerg 83: __dead static void
1.1 christos 84: usage_migrate(void)
85: {
86:
87: fprintf(stderr,
1.4 riz 88: "usage: %s %s\n", getprogname(), migratemsg);
1.1 christos 89: exit(1);
90: }
91:
92: static struct gpt_ent*
93: migrate_disklabel(int fd, off_t start, struct gpt_ent *ent)
94: {
95: char *buf;
96: struct disklabel *dl;
97: off_t ofs, rawofs;
98: int i;
99:
100: buf = gpt_read(fd, start + LABELSECTOR, 1);
101: dl = (void*)(buf + LABELOFFSET);
102:
103: if (le32toh(dl->d_magic) != DISKMAGIC ||
104: le32toh(dl->d_magic2) != DISKMAGIC) {
105: warnx("%s: warning: FreeBSD slice without disklabel",
106: device_name);
1.12 christos 107: free(buf);
1.1 christos 108: return (ent);
109: }
110:
111: rawofs = le32toh(dl->d_partitions[RAW_PART].p_offset) *
112: le32toh(dl->d_secsize);
113: for (i = 0; i < le16toh(dl->d_npartitions); i++) {
114: if (dl->d_partitions[i].p_fstype == FS_UNUSED)
115: continue;
116: ofs = le32toh(dl->d_partitions[i].p_offset) *
117: le32toh(dl->d_secsize);
118: if (ofs < rawofs)
119: rawofs = 0;
120: }
121: rawofs /= secsz;
122:
123: for (i = 0; i < le16toh(dl->d_npartitions); i++) {
124: switch (dl->d_partitions[i].p_fstype) {
125: case FS_UNUSED:
126: continue;
127: case FS_SWAP: {
1.19 christos 128: gpt_uuid_create(GPT_TYPE_FREEBSD_SWAP, ent->ent_type,
129: ent->ent_name, sizeof(ent->ent_name));
1.1 christos 130: break;
131: }
132: case FS_BSDFFS: {
1.19 christos 133: gpt_uuid_create(GPT_TYPE_FREEBSD_UFS, ent->ent_type,
134: ent->ent_name, sizeof(ent->ent_name));
1.1 christos 135: break;
136: }
1.10 jnemeth 137: case FREEBSD_FS_VINUM: {
1.19 christos 138: gpt_uuid_create(GPT_TYPE_FREEBSD_VINUM, ent->ent_type,
139: ent->ent_name, sizeof(ent->ent_name));
1.1 christos 140: break;
141: }
1.10 jnemeth 142: case FREEBSD_FS_ZFS: {
1.19 christos 143: gpt_uuid_create(GPT_TYPE_FREEBSD_ZFS, ent->ent_type,
144: ent->ent_name, sizeof(ent->ent_name));
1.8 jnemeth 145: break;
146: }
1.1 christos 147: default:
148: warnx("%s: warning: unknown FreeBSD partition (%d)",
149: device_name, dl->d_partitions[i].p_fstype);
150: continue;
151: }
152:
153: ofs = (le32toh(dl->d_partitions[i].p_offset) *
154: le32toh(dl->d_secsize)) / secsz;
155: ofs = (ofs > 0) ? ofs - rawofs : 0;
156: ent->ent_lba_start = htole64(start + ofs);
157: ent->ent_lba_end = htole64(start + ofs +
158: le32toh(dl->d_partitions[i].p_size) - 1LL);
159: ent++;
160: }
161:
1.12 christos 162: free(buf);
1.1 christos 163: return (ent);
164: }
165:
1.9 jnemeth 166: static struct gpt_ent*
167: migrate_netbsd_disklabel(int fd, off_t start, struct gpt_ent *ent)
168: {
169: char *buf;
170: struct disklabel *dl;
171: off_t ofs, rawofs;
172: int i;
173:
174: buf = gpt_read(fd, start + LABELSECTOR, 1);
175: dl = (void*)(buf + LABELOFFSET);
176:
177: if (le32toh(dl->d_magic) != DISKMAGIC ||
178: le32toh(dl->d_magic2) != DISKMAGIC) {
179: warnx("%s: warning: NetBSD slice without disklabel",
180: device_name);
1.12 christos 181: free(buf);
1.9 jnemeth 182: return (ent);
183: }
184:
185: rawofs = le32toh(dl->d_partitions[RAW_PART].p_offset) *
186: le32toh(dl->d_secsize);
187: for (i = 0; i < le16toh(dl->d_npartitions); i++) {
188: if (dl->d_partitions[i].p_fstype == FS_UNUSED)
189: continue;
190: ofs = le32toh(dl->d_partitions[i].p_offset) *
191: le32toh(dl->d_secsize);
192: if (ofs < rawofs)
193: rawofs = 0;
194: }
195: rawofs /= secsz;
196:
197: for (i = 0; i < le16toh(dl->d_npartitions); i++) {
198: switch (dl->d_partitions[i].p_fstype) {
199: case FS_UNUSED:
200: continue;
201: case FS_SWAP: {
1.19 christos 202: gpt_uuid_create(GPT_TYPE_NETBSD_SWAP, ent->ent_type,
203: ent->ent_name, sizeof(ent->ent_name));
1.9 jnemeth 204: break;
205: }
206: case FS_BSDFFS: {
1.19 christos 207: gpt_uuid_create(GPT_TYPE_NETBSD_FFS, ent->ent_type,
208: ent->ent_name, sizeof(ent->ent_name));
1.9 jnemeth 209: break;
210: }
211: case FS_BSDLFS: {
1.19 christos 212: gpt_uuid_create(GPT_TYPE_NETBSD_LFS, ent->ent_type,
213: ent->ent_name, sizeof(ent->ent_name));
1.9 jnemeth 214: break;
215: }
216: case FS_RAID: {
1.19 christos 217: gpt_uuid_create(GPT_TYPE_NETBSD_RAIDFRAME, ent->ent_type,
218: ent->ent_name, sizeof(ent->ent_name));
1.9 jnemeth 219: break;
220: }
221: case FS_CCD: {
1.19 christos 222: gpt_uuid_create(GPT_TYPE_NETBSD_CCD, ent->ent_type,
223: ent->ent_name, sizeof(ent->ent_name));
1.9 jnemeth 224: break;
225: }
226: case FS_CGD: {
1.19 christos 227: gpt_uuid_create(GPT_TYPE_NETBSD_CGD, ent->ent_type,
228: ent->ent_name, sizeof(ent->ent_name));
1.9 jnemeth 229: break;
230: }
231: default:
232: warnx("%s: warning: unknown NetBSD partition (%d)",
233: device_name, dl->d_partitions[i].p_fstype);
234: continue;
235: }
236:
237: ofs = (le32toh(dl->d_partitions[i].p_offset) *
238: le32toh(dl->d_secsize)) / secsz;
239: ofs = (ofs > 0) ? ofs - rawofs : 0;
1.11 jnemeth 240: ent->ent_lba_start = htole64(ofs);
241: ent->ent_lba_end = htole64(ofs +
1.9 jnemeth 242: le32toh(dl->d_partitions[i].p_size) - 1LL);
243: ent++;
244: }
245:
1.12 christos 246: free(buf);
1.9 jnemeth 247: return (ent);
248: }
249:
1.1 christos 250: static void
251: migrate(int fd)
252: {
253: off_t blocks, last;
254: map_t *gpt, *tpg;
255: map_t *tbl, *lbt;
256: map_t *map;
257: struct gpt_hdr *hdr;
258: struct gpt_ent *ent;
259: struct mbr *mbr;
260: uint32_t start, size;
261: unsigned int i;
262:
263: last = mediasz / secsz - 1LL;
264:
265: map = map_find(MAP_TYPE_MBR);
266: if (map == NULL || map->map_start != 0) {
267: warnx("%s: error: no partitions to convert", device_name);
268: return;
269: }
270:
271: mbr = map->map_data;
272:
273: if (map_find(MAP_TYPE_PRI_GPT_HDR) != NULL ||
274: map_find(MAP_TYPE_SEC_GPT_HDR) != NULL) {
275: warnx("%s: error: device already contains a GPT", device_name);
276: return;
277: }
278:
279: /* Get the amount of free space after the MBR */
280: blocks = map_free(1LL, 0LL);
281: if (blocks == 0LL) {
282: warnx("%s: error: no room for the GPT header", device_name);
283: return;
284: }
285:
286: /* Don't create more than parts entries. */
287: if ((uint64_t)(blocks - 1) * secsz > parts * sizeof(struct gpt_ent)) {
288: blocks = (parts * sizeof(struct gpt_ent)) / secsz;
289: if ((parts * sizeof(struct gpt_ent)) % secsz)
290: blocks++;
291: blocks++; /* Don't forget the header itself */
292: }
293:
294: /* Never cross the median of the device. */
295: if ((blocks + 1LL) > ((last + 1LL) >> 1))
296: blocks = ((last + 1LL) >> 1) - 1LL;
297:
298: /*
299: * Get the amount of free space at the end of the device and
300: * calculate the size for the GPT structures.
301: */
302: map = map_last();
303: if (map->map_type != MAP_TYPE_UNUSED) {
304: warnx("%s: error: no room for the backup header", device_name);
305: return;
306: }
307:
308: if (map->map_size < blocks)
309: blocks = map->map_size;
310: if (blocks == 1LL) {
311: warnx("%s: error: no room for the GPT table", device_name);
312: return;
313: }
314:
315: blocks--; /* Number of blocks in the GPT table. */
316: gpt = map_add(1LL, 1LL, MAP_TYPE_PRI_GPT_HDR, calloc(1, secsz));
317: tbl = map_add(2LL, blocks, MAP_TYPE_PRI_GPT_TBL,
318: calloc(blocks, secsz));
319: if (gpt == NULL || tbl == NULL)
320: return;
321:
322: lbt = map_add(last - blocks, blocks, MAP_TYPE_SEC_GPT_TBL,
323: tbl->map_data);
324: tpg = map_add(last, 1LL, MAP_TYPE_SEC_GPT_HDR, calloc(1, secsz));
325:
326: hdr = gpt->map_data;
327: memcpy(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig));
328: hdr->hdr_revision = htole32(GPT_HDR_REVISION);
329: /*
330: * XXX struct gpt_hdr is not a multiple of 8 bytes in size and thus
331: * contains padding we must not include in the size.
332: */
1.18 christos 333: hdr->hdr_size = htole32(GPT_HDR_SIZE);
1.1 christos 334: hdr->hdr_lba_self = htole64(gpt->map_start);
335: hdr->hdr_lba_alt = htole64(tpg->map_start);
336: hdr->hdr_lba_start = htole64(tbl->map_start + blocks);
337: hdr->hdr_lba_end = htole64(lbt->map_start - 1LL);
1.20 ! jnemeth 338: gpt_uuid_create_new(hdr->hdr_guid);
1.1 christos 339: hdr->hdr_lba_table = htole64(tbl->map_start);
340: hdr->hdr_entries = htole32((blocks * secsz) / sizeof(struct gpt_ent));
341: if (le32toh(hdr->hdr_entries) > parts)
342: hdr->hdr_entries = htole32(parts);
343: hdr->hdr_entsz = htole32(sizeof(struct gpt_ent));
344:
345: ent = tbl->map_data;
346: for (i = 0; i < le32toh(hdr->hdr_entries); i++) {
1.20 ! jnemeth 347: gpt_uuid_create_new(ent[i].ent_guid);
1.1 christos 348: }
349:
350: /* Mirror partitions. */
351: for (i = 0; i < 4; i++) {
352: start = le16toh(mbr->mbr_part[i].part_start_hi);
353: start = (start << 16) + le16toh(mbr->mbr_part[i].part_start_lo);
354: size = le16toh(mbr->mbr_part[i].part_size_hi);
355: size = (size << 16) + le16toh(mbr->mbr_part[i].part_size_lo);
356:
357: switch (mbr->mbr_part[i].part_typ) {
1.9 jnemeth 358: case MBR_PTYPE_UNUSED:
1.1 christos 359: continue;
1.9 jnemeth 360: case MBR_PTYPE_386BSD: { /* FreeBSD */
1.1 christos 361: if (slice) {
1.19 christos 362: gpt_uuid_create(GPT_TYPE_FREEBSD,
363: ent->ent_type, ent->ent_name,
364: sizeof(ent->ent_name));
1.1 christos 365: ent->ent_lba_start = htole64((uint64_t)start);
366: ent->ent_lba_end = htole64(start + size - 1LL);
367: ent++;
368: } else
369: ent = migrate_disklabel(fd, start, ent);
370: break;
371: }
1.9 jnemeth 372: case MBR_PTYPE_NETBSD:
373: ent = migrate_netbsd_disklabel(fd, start, ent);
374: break;
375: case MBR_PTYPE_EFI: {
1.19 christos 376: gpt_uuid_create(GPT_TYPE_EFI,
377: ent->ent_type, ent->ent_name,
378: sizeof(ent->ent_name));
1.1 christos 379: ent->ent_lba_start = htole64((uint64_t)start);
380: ent->ent_lba_end = htole64(start + size - 1LL);
381: ent++;
382: break;
383: }
384: default:
385: if (!force) {
386: warnx("%s: error: unknown partition type (%d)",
387: device_name, mbr->mbr_part[i].part_typ);
388: return;
389: }
390: }
391: }
392: ent = tbl->map_data;
393:
394: hdr->hdr_crc_table = htole32(crc32(ent, le32toh(hdr->hdr_entries) *
395: le32toh(hdr->hdr_entsz)));
396: hdr->hdr_crc_self = htole32(crc32(hdr, le32toh(hdr->hdr_size)));
397:
398: gpt_write(fd, gpt);
399: gpt_write(fd, tbl);
400:
401: /*
402: * Create backup GPT.
403: */
404: memcpy(tpg->map_data, gpt->map_data, secsz);
405: hdr = tpg->map_data;
406: hdr->hdr_lba_self = htole64(tpg->map_start);
407: hdr->hdr_lba_alt = htole64(gpt->map_start);
408: hdr->hdr_lba_table = htole64(lbt->map_start);
409: hdr->hdr_crc_self = 0; /* Don't ever forget this! */
410: hdr->hdr_crc_self = htole32(crc32(hdr, le32toh(hdr->hdr_size)));
411:
412: gpt_write(fd, lbt);
413: gpt_write(fd, tpg);
414:
415: map = map_find(MAP_TYPE_MBR);
416: mbr = map->map_data;
417: /*
418: * Turn the MBR into a Protective MBR.
419: */
1.16 christos 420: memset(mbr->mbr_part, 0, sizeof(mbr->mbr_part));
1.13 jakllsch 421: mbr->mbr_part[0].part_shd = 0x00;
422: mbr->mbr_part[0].part_ssect = 0x02;
423: mbr->mbr_part[0].part_scyl = 0x00;
1.14 jakllsch 424: mbr->mbr_part[0].part_typ = MBR_PTYPE_PMBR;
1.13 jakllsch 425: mbr->mbr_part[0].part_ehd = 0xfe;
1.1 christos 426: mbr->mbr_part[0].part_esect = 0xff;
427: mbr->mbr_part[0].part_ecyl = 0xff;
428: mbr->mbr_part[0].part_start_lo = htole16(1);
429: if (last > 0xffffffff) {
430: mbr->mbr_part[0].part_size_lo = htole16(0xffff);
431: mbr->mbr_part[0].part_size_hi = htole16(0xffff);
432: } else {
433: mbr->mbr_part[0].part_size_lo = htole16(last);
434: mbr->mbr_part[0].part_size_hi = htole16(last >> 16);
435: }
436: gpt_write(fd, map);
437: }
438:
439: int
440: cmd_migrate(int argc, char *argv[])
441: {
442: int ch, fd;
443:
444: /* Get the migrate options */
445: while ((ch = getopt(argc, argv, "fs")) != -1) {
446: switch(ch) {
447: case 'f':
448: force = 1;
449: break;
450: case 's':
451: slice = 1;
452: break;
453: default:
454: usage_migrate();
455: }
456: }
457:
458: if (argc == optind)
459: usage_migrate();
460:
461: while (optind < argc) {
462: fd = gpt_open(argv[optind++]);
463: if (fd == -1) {
464: warn("unable to open device '%s'", device_name);
465: continue;
466: }
467:
468: migrate(fd);
469:
470: gpt_close(fd);
471: }
472:
473: return (0);
474: }
CVSweb <webmaster@jp.NetBSD.org>