Home | History | Annotate | Line # | Download | only in gpt
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