version 1.14, 2013/12/04 20:15:51 |
version 1.14.4.2, 2018/08/13 16:12:12 |
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
*/ |
|
|
|
#if HAVE_NBTOOL_CONFIG_H |
|
#include "nbtool_config.h" |
|
#endif |
|
|
#include <sys/cdefs.h> |
#include <sys/cdefs.h> |
#ifdef __FBSDID |
#ifdef __FBSDID |
__FBSDID("$FreeBSD: src/sbin/gpt/migrate.c,v 1.16 2005/09/01 02:42:52 marcel Exp $"); |
__FBSDID("$FreeBSD: src/sbin/gpt/migrate.c,v 1.16 2005/09/01 02:42:52 marcel Exp $"); |
Line 34 __RCSID("$NetBSD$"); |
|
Line 38 __RCSID("$NetBSD$"); |
|
|
|
#include <sys/types.h> |
#include <sys/types.h> |
#include <sys/param.h> |
#include <sys/param.h> |
|
#define FSTYPENAMES |
|
#define MBRPTYPENAMES |
|
#ifdef HAVE_NBTOOL_CONFIG_H |
|
#include <nbinclude/sys/bootblock.h> |
|
#include <nbinclude/sys/disklabel.h> |
|
#else |
#include <sys/bootblock.h> |
#include <sys/bootblock.h> |
#include <sys/disklabel.h> |
#include <sys/disklabel.h> |
|
#endif |
|
|
#include <err.h> |
#include <err.h> |
#include <stddef.h> |
#include <stddef.h> |
Line 46 __RCSID("$NetBSD$"); |
|
Line 57 __RCSID("$NetBSD$"); |
|
|
|
#include "map.h" |
#include "map.h" |
#include "gpt.h" |
#include "gpt.h" |
|
#include "gpt_private.h" |
|
|
/* |
/* |
* Allow compilation on platforms that do not have a BSD label. |
* Allow compilation on platforms that do not have a BSD label. |
* The values are valid for amd64, i386 and ia64 disklabels. |
* The values are valid for amd64, i386 and ia64 disklabels. |
|
* XXX: use disklabel_params from disklabel.c |
*/ |
*/ |
#ifndef LABELOFFSET |
#ifndef LABELOFFSET |
#define LABELOFFSET 0 |
#define LABELOFFSET 0 |
Line 57 __RCSID("$NetBSD$"); |
|
Line 70 __RCSID("$NetBSD$"); |
|
#ifndef LABELSECTOR |
#ifndef LABELSECTOR |
#define LABELSECTOR 1 |
#define LABELSECTOR 1 |
#endif |
#endif |
|
#ifndef RAW_PART |
|
#define RAW_PART 3 |
|
#endif |
|
|
/* FreeBSD filesystem types that don't match corresponding NetBSD types */ |
/* FreeBSD filesystem types that don't match corresponding NetBSD types */ |
#define FREEBSD_FS_VINUM 14 |
#define FREEBSD_FS_VINUM 14 |
#define FREEBSD_FS_ZFS 27 |
#define FREEBSD_FS_ZFS 27 |
|
|
static int force; |
static int cmd_migrate(gpt_t, int, char *[]); |
static int slice; |
|
|
|
const char migratemsg[] = "migrate [-fs] device ..."; |
static const char *migratehelp[] = { |
|
"[-Afs] [-p partitions]", |
|
}; |
|
|
|
struct gpt_cmd c_migrate = { |
|
"migrate", |
|
cmd_migrate, |
|
migratehelp, __arraycount(migratehelp), |
|
GPT_SYNC, |
|
}; |
|
|
__dead static void |
#define usage() gpt_usage(NULL, &c_migrate) |
usage_migrate(void) |
|
{ |
|
|
|
fprintf(stderr, |
static const char * |
"usage: %s %s\n", getprogname(), migratemsg); |
fstypename(u_int t) |
exit(1); |
{ |
|
static char buf[64]; |
|
if (t >= __arraycount(fstypenames)) { |
|
snprintf(buf, sizeof(buf), "*%u*", t); |
|
return buf; |
|
} |
|
return fstypenames[t]; |
} |
} |
|
|
static struct gpt_ent* |
static const char * |
migrate_disklabel(int fd, off_t start, struct gpt_ent *ent) |
mbrptypename(u_int t) |
{ |
{ |
char *buf; |
static char buf[64]; |
struct disklabel *dl; |
size_t i; |
off_t ofs, rawofs; |
|
int i; |
|
|
|
buf = gpt_read(fd, start + LABELSECTOR, 1); |
for (i = 0; i < __arraycount(mbr_ptypes); i++) |
dl = (void*)(buf + LABELOFFSET); |
if ((u_int)mbr_ptypes[i].id == t) |
|
return mbr_ptypes[i].name; |
|
|
if (le32toh(dl->d_magic) != DISKMAGIC || |
snprintf(buf, sizeof(buf), "*%u*", t); |
le32toh(dl->d_magic2) != DISKMAGIC) { |
return buf; |
warnx("%s: warning: FreeBSD slice without disklabel", |
} |
device_name); |
|
free(buf); |
|
return (ent); |
|
} |
|
|
|
rawofs = le32toh(dl->d_partitions[RAW_PART].p_offset) * |
static gpt_type_t |
le32toh(dl->d_secsize); |
freebsd_fstype_to_gpt_type(gpt_t gpt, u_int i, u_int fstype) |
for (i = 0; i < le16toh(dl->d_npartitions); i++) { |
{ |
if (dl->d_partitions[i].p_fstype == FS_UNUSED) |
switch (fstype) { |
continue; |
case FS_UNUSED: |
ofs = le32toh(dl->d_partitions[i].p_offset) * |
return GPT_TYPE_INVALID; |
le32toh(dl->d_secsize); |
case FS_SWAP: |
if (ofs < rawofs) |
return GPT_TYPE_FREEBSD_SWAP; |
rawofs = 0; |
case FS_BSDFFS: |
|
return GPT_TYPE_FREEBSD_UFS; |
|
case FREEBSD_FS_VINUM: |
|
return GPT_TYPE_FREEBSD_VINUM; |
|
case FREEBSD_FS_ZFS: |
|
return GPT_TYPE_FREEBSD_ZFS; |
|
default: |
|
gpt_warnx(gpt, "Unknown FreeBSD partition (%d)", fstype); |
|
return GPT_TYPE_INVALID; |
} |
} |
rawofs /= secsz; |
} |
|
|
for (i = 0; i < le16toh(dl->d_npartitions); i++) { |
|
switch (dl->d_partitions[i].p_fstype) { |
|
case FS_UNUSED: |
|
continue; |
|
case FS_SWAP: { |
|
static const uuid_t swap = GPT_ENT_TYPE_FREEBSD_SWAP; |
|
le_uuid_enc(ent->ent_type, &swap); |
|
utf8_to_utf16((const uint8_t *)"FreeBSD swap partition", |
|
ent->ent_name, 36); |
|
break; |
|
} |
|
case FS_BSDFFS: { |
|
static const uuid_t ufs = GPT_ENT_TYPE_FREEBSD_UFS; |
|
le_uuid_enc(ent->ent_type, &ufs); |
|
utf8_to_utf16((const uint8_t *)"FreeBSD UFS partition", |
|
ent->ent_name, 36); |
|
break; |
|
} |
|
case FREEBSD_FS_VINUM: { |
|
static const uuid_t vinum = GPT_ENT_TYPE_FREEBSD_VINUM; |
|
le_uuid_enc(ent->ent_type, &vinum); |
|
utf8_to_utf16((const uint8_t *)"FreeBSD vinum partition", |
|
ent->ent_name, 36); |
|
break; |
|
} |
|
case FREEBSD_FS_ZFS: { |
|
static const uuid_t zfs = GPT_ENT_TYPE_FREEBSD_ZFS; |
|
le_uuid_enc(ent->ent_type, &zfs); |
|
utf8_to_utf16((const uint8_t *)"FreeBSD ZFS partition", |
|
ent->ent_name, 36); |
|
break; |
|
} |
|
default: |
|
warnx("%s: warning: unknown FreeBSD partition (%d)", |
|
device_name, dl->d_partitions[i].p_fstype); |
|
continue; |
|
} |
|
|
|
ofs = (le32toh(dl->d_partitions[i].p_offset) * |
static gpt_type_t |
le32toh(dl->d_secsize)) / secsz; |
netbsd_fstype_to_gpt_type(gpt_t gpt, u_int i, u_int fstype) |
ofs = (ofs > 0) ? ofs - rawofs : 0; |
{ |
ent->ent_lba_start = htole64(start + ofs); |
switch (fstype) { |
ent->ent_lba_end = htole64(start + ofs + |
case FS_UNUSED: |
le32toh(dl->d_partitions[i].p_size) - 1LL); |
return GPT_TYPE_INVALID; |
ent++; |
case FS_HFS: |
|
return GPT_TYPE_APPLE_HFS; |
|
case FS_EX2FS: |
|
return GPT_TYPE_LINUX_DATA; |
|
case FS_SWAP: |
|
return GPT_TYPE_NETBSD_SWAP; |
|
case FS_BSDFFS: |
|
return GPT_TYPE_NETBSD_FFS; |
|
case FS_BSDLFS: |
|
return GPT_TYPE_NETBSD_LFS; |
|
case FS_RAID: |
|
return GPT_TYPE_NETBSD_RAIDFRAME; |
|
case FS_CCD: |
|
return GPT_TYPE_NETBSD_CCD; |
|
case FS_CGD: |
|
return GPT_TYPE_NETBSD_CGD; |
|
default: |
|
gpt_warnx(gpt, "Partition %u unknown type %s, " |
|
"using \"Microsoft Basic Data\"", i, fstypename(fstype)); |
|
return GPT_TYPE_MS_BASIC_DATA; |
} |
} |
|
|
free(buf); |
|
return (ent); |
|
} |
} |
|
|
static struct gpt_ent* |
static struct gpt_ent * |
migrate_netbsd_disklabel(int fd, off_t start, struct gpt_ent *ent) |
migrate_disklabel(gpt_t gpt, off_t start, struct gpt_ent *ent, |
|
gpt_type_t (*convert)(gpt_t, u_int, u_int)) |
{ |
{ |
char *buf; |
char *buf; |
struct disklabel *dl; |
struct disklabel *dl; |
off_t ofs, rawofs; |
off_t ofs, rawofs; |
int i; |
unsigned int i; |
|
gpt_type_t type; |
|
|
buf = gpt_read(fd, start + LABELSECTOR, 1); |
buf = gpt_read(gpt, start + LABELSECTOR, 1); |
|
if (buf == NULL) { |
|
gpt_warn(gpt, "Error reading label"); |
|
return NULL; |
|
} |
dl = (void*)(buf + LABELOFFSET); |
dl = (void*)(buf + LABELOFFSET); |
|
|
if (le32toh(dl->d_magic) != DISKMAGIC || |
if (le32toh(dl->d_magic) != DISKMAGIC || |
le32toh(dl->d_magic2) != DISKMAGIC) { |
le32toh(dl->d_magic2) != DISKMAGIC) { |
warnx("%s: warning: NetBSD slice without disklabel", |
gpt_warnx(gpt, "MBR partition without disklabel"); |
device_name); |
|
free(buf); |
free(buf); |
return (ent); |
return ent; |
} |
} |
|
|
rawofs = le32toh(dl->d_partitions[RAW_PART].p_offset) * |
rawofs = le32toh(dl->d_partitions[RAW_PART].p_offset) * |
Line 187 migrate_netbsd_disklabel(int fd, off_t s |
|
Line 201 migrate_netbsd_disklabel(int fd, off_t s |
|
if (ofs < rawofs) |
if (ofs < rawofs) |
rawofs = 0; |
rawofs = 0; |
} |
} |
rawofs /= secsz; |
|
|
if (gpt->verbose > 1) |
|
gpt_msg(gpt, "rawofs=%ju", (uintmax_t)rawofs); |
|
rawofs /= gpt->secsz; |
|
|
for (i = 0; i < le16toh(dl->d_npartitions); i++) { |
for (i = 0; i < le16toh(dl->d_npartitions); i++) { |
switch (dl->d_partitions[i].p_fstype) { |
if (gpt->verbose > 1) |
case FS_UNUSED: |
gpt_msg(gpt, "Disklabel partition %u type %s", i, |
continue; |
fstypename(dl->d_partitions[i].p_fstype)); |
case FS_SWAP: { |
|
static const uuid_t swap = GPT_ENT_TYPE_NETBSD_SWAP; |
type = (*convert)(gpt, i, dl->d_partitions[i].p_fstype); |
le_uuid_enc(ent->ent_type, &swap); |
if (type == GPT_TYPE_INVALID) |
utf8_to_utf16((const uint8_t *)"NetBSD swap partition", |
|
ent->ent_name, 36); |
|
break; |
|
} |
|
case FS_BSDFFS: { |
|
static const uuid_t ufs = GPT_ENT_TYPE_NETBSD_FFS; |
|
le_uuid_enc(ent->ent_type, &ufs); |
|
utf8_to_utf16((const uint8_t *)"NetBSD FFS partition", |
|
ent->ent_name, 36); |
|
break; |
|
} |
|
case FS_BSDLFS: { |
|
static const uuid_t zfs = GPT_ENT_TYPE_NETBSD_LFS; |
|
le_uuid_enc(ent->ent_type, &zfs); |
|
utf8_to_utf16((const uint8_t *)"NetBSD LFS partition", |
|
ent->ent_name, 36); |
|
break; |
|
} |
|
case FS_RAID: { |
|
static const uuid_t zfs = GPT_ENT_TYPE_NETBSD_RAIDFRAME; |
|
le_uuid_enc(ent->ent_type, &zfs); |
|
utf8_to_utf16((const uint8_t *)"NetBSD RAIDframe partition", |
|
ent->ent_name, 36); |
|
break; |
|
} |
|
case FS_CCD: { |
|
static const uuid_t zfs = GPT_ENT_TYPE_NETBSD_CCD; |
|
le_uuid_enc(ent->ent_type, &zfs); |
|
utf8_to_utf16((const uint8_t *)"NetBSD CCD partition", |
|
ent->ent_name, 36); |
|
break; |
|
} |
|
case FS_CGD: { |
|
static const uuid_t zfs = GPT_ENT_TYPE_NETBSD_CGD; |
|
le_uuid_enc(ent->ent_type, &zfs); |
|
utf8_to_utf16((const uint8_t *)"NetBSD CGD partition", |
|
ent->ent_name, 36); |
|
break; |
|
} |
|
default: |
|
warnx("%s: warning: unknown NetBSD partition (%d)", |
|
device_name, dl->d_partitions[i].p_fstype); |
|
continue; |
continue; |
} |
|
|
gpt_uuid_create(type, ent->ent_type, |
|
ent->ent_name, sizeof(ent->ent_name)); |
|
|
ofs = (le32toh(dl->d_partitions[i].p_offset) * |
ofs = (le32toh(dl->d_partitions[i].p_offset) * |
le32toh(dl->d_secsize)) / secsz; |
le32toh(dl->d_secsize)) / gpt->secsz; |
ofs = (ofs > 0) ? ofs - rawofs : 0; |
ofs = (ofs > 0) ? ofs - rawofs : 0; |
ent->ent_lba_start = htole64(ofs); |
ent->ent_lba_start = htole64((uint64_t)ofs); |
ent->ent_lba_end = htole64(ofs + |
ent->ent_lba_end = htole64((uint64_t)(ofs + |
le32toh(dl->d_partitions[i].p_size) - 1LL); |
(off_t)le32toh((uint64_t)dl->d_partitions[i].p_size) |
|
- 1LL)); |
ent++; |
ent++; |
} |
} |
|
|
free(buf); |
free(buf); |
return (ent); |
return ent; |
} |
} |
|
|
static void |
static int |
migrate(int fd) |
migrate(gpt_t gpt, u_int parts, int force, int slice, int active) |
{ |
{ |
uuid_t uuid; |
off_t last = gpt_last(gpt); |
off_t blocks, last; |
map_t map; |
map_t *gpt, *tpg; |
|
map_t *tbl, *lbt; |
|
map_t *map; |
|
struct gpt_hdr *hdr; |
|
struct gpt_ent *ent; |
struct gpt_ent *ent; |
struct mbr *mbr; |
struct mbr *mbr; |
uint32_t start, size; |
uint32_t start, size; |
unsigned int i; |
unsigned int i; |
|
gpt_type_t type = GPT_TYPE_INVALID; |
|
|
last = mediasz / secsz - 1LL; |
map = map_find(gpt, MAP_TYPE_MBR); |
|
|
map = map_find(MAP_TYPE_MBR); |
|
if (map == NULL || map->map_start != 0) { |
if (map == NULL || map->map_start != 0) { |
warnx("%s: error: no partitions to convert", device_name); |
gpt_warnx(gpt, "No MBR in disk to convert"); |
return; |
return -1; |
} |
} |
|
|
mbr = map->map_data; |
mbr = map->map_data; |
|
|
if (map_find(MAP_TYPE_PRI_GPT_HDR) != NULL || |
if (gpt_create(gpt, last, parts, 0) == -1) |
map_find(MAP_TYPE_SEC_GPT_HDR) != NULL) { |
return -1; |
warnx("%s: error: device already contains a GPT", device_name); |
|
return; |
|
} |
|
|
|
/* Get the amount of free space after the MBR */ |
|
blocks = map_free(1LL, 0LL); |
|
if (blocks == 0LL) { |
|
warnx("%s: error: no room for the GPT header", device_name); |
|
return; |
|
} |
|
|
|
/* Don't create more than parts entries. */ |
|
if ((uint64_t)(blocks - 1) * secsz > parts * sizeof(struct gpt_ent)) { |
|
blocks = (parts * sizeof(struct gpt_ent)) / secsz; |
|
if ((parts * sizeof(struct gpt_ent)) % secsz) |
|
blocks++; |
|
blocks++; /* Don't forget the header itself */ |
|
} |
|
|
|
/* Never cross the median of the device. */ |
|
if ((blocks + 1LL) > ((last + 1LL) >> 1)) |
|
blocks = ((last + 1LL) >> 1) - 1LL; |
|
|
|
/* |
ent = gpt->tbl->map_data; |
* Get the amount of free space at the end of the device and |
|
* calculate the size for the GPT structures. |
|
*/ |
|
map = map_last(); |
|
if (map->map_type != MAP_TYPE_UNUSED) { |
|
warnx("%s: error: no room for the backup header", device_name); |
|
return; |
|
} |
|
|
|
if (map->map_size < blocks) |
|
blocks = map->map_size; |
|
if (blocks == 1LL) { |
|
warnx("%s: error: no room for the GPT table", device_name); |
|
return; |
|
} |
|
|
|
blocks--; /* Number of blocks in the GPT table. */ |
|
gpt = map_add(1LL, 1LL, MAP_TYPE_PRI_GPT_HDR, calloc(1, secsz)); |
|
tbl = map_add(2LL, blocks, MAP_TYPE_PRI_GPT_TBL, |
|
calloc(blocks, secsz)); |
|
if (gpt == NULL || tbl == NULL) |
|
return; |
|
|
|
lbt = map_add(last - blocks, blocks, MAP_TYPE_SEC_GPT_TBL, |
|
tbl->map_data); |
|
tpg = map_add(last, 1LL, MAP_TYPE_SEC_GPT_HDR, calloc(1, secsz)); |
|
|
|
hdr = gpt->map_data; |
|
memcpy(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig)); |
|
hdr->hdr_revision = htole32(GPT_HDR_REVISION); |
|
/* |
|
* XXX struct gpt_hdr is not a multiple of 8 bytes in size and thus |
|
* contains padding we must not include in the size. |
|
*/ |
|
hdr->hdr_size = htole32(GPT_SIZE); |
|
hdr->hdr_lba_self = htole64(gpt->map_start); |
|
hdr->hdr_lba_alt = htole64(tpg->map_start); |
|
hdr->hdr_lba_start = htole64(tbl->map_start + blocks); |
|
hdr->hdr_lba_end = htole64(lbt->map_start - 1LL); |
|
uuid_create(&uuid, NULL); |
|
le_uuid_enc(hdr->hdr_uuid, &uuid); |
|
hdr->hdr_lba_table = htole64(tbl->map_start); |
|
hdr->hdr_entries = htole32((blocks * secsz) / sizeof(struct gpt_ent)); |
|
if (le32toh(hdr->hdr_entries) > parts) |
|
hdr->hdr_entries = htole32(parts); |
|
hdr->hdr_entsz = htole32(sizeof(struct gpt_ent)); |
|
|
|
ent = tbl->map_data; |
|
for (i = 0; i < le32toh(hdr->hdr_entries); i++) { |
|
uuid_create(&uuid, NULL); |
|
le_uuid_enc(ent[i].ent_uuid, &uuid); |
|
} |
|
|
|
/* Mirror partitions. */ |
/* Mirror partitions. */ |
for (i = 0; i < 4; i++) { |
for (i = 0; i < 4; i++) { |
|
|
size = le16toh(mbr->mbr_part[i].part_size_hi); |
size = le16toh(mbr->mbr_part[i].part_size_hi); |
size = (size << 16) + le16toh(mbr->mbr_part[i].part_size_lo); |
size = (size << 16) + le16toh(mbr->mbr_part[i].part_size_lo); |
|
|
|
if (gpt->verbose > 1) |
|
gpt_msg(gpt, "MBR partition %u type %s", i, |
|
mbrptypename(mbr->mbr_part[i].part_typ)); |
switch (mbr->mbr_part[i].part_typ) { |
switch (mbr->mbr_part[i].part_typ) { |
case MBR_PTYPE_UNUSED: |
case MBR_PTYPE_UNUSED: |
continue; |
continue; |
case MBR_PTYPE_386BSD: { /* FreeBSD */ |
|
|
case MBR_PTYPE_386BSD: /* FreeBSD */ |
if (slice) { |
if (slice) { |
static const uuid_t freebsd = GPT_ENT_TYPE_FREEBSD; |
type = GPT_TYPE_FREEBSD; |
le_uuid_enc(ent->ent_type, &freebsd); |
break; |
ent->ent_lba_start = htole64((uint64_t)start); |
} else { |
ent->ent_lba_end = htole64(start + size - 1LL); |
ent = migrate_disklabel(gpt, start, ent, |
utf8_to_utf16((const uint8_t *)"FreeBSD disklabel partition", |
freebsd_fstype_to_gpt_type); |
ent->ent_name, 36); |
continue; |
ent++; |
} |
} else |
|
ent = migrate_disklabel(fd, start, ent); |
case MBR_PTYPE_NETBSD: /* NetBSD */ |
break; |
ent = migrate_disklabel(gpt, start, ent, |
} |
netbsd_fstype_to_gpt_type); |
case MBR_PTYPE_NETBSD: |
continue; |
ent = migrate_netbsd_disklabel(fd, start, ent); |
|
break; |
case MBR_PTYPE_EFI: |
case MBR_PTYPE_EFI: { |
type = GPT_TYPE_EFI; |
static const uuid_t efi_slice = GPT_ENT_TYPE_EFI; |
|
le_uuid_enc(ent->ent_type, &efi_slice); |
|
ent->ent_lba_start = htole64((uint64_t)start); |
|
ent->ent_lba_end = htole64(start + size - 1LL); |
|
utf8_to_utf16((const uint8_t *)"EFI system partition", |
|
ent->ent_name, 36); |
|
ent++; |
|
break; |
break; |
} |
|
default: |
default: |
if (!force) { |
if (!force) { |
warnx("%s: error: unknown partition type (%d)", |
gpt_warnx(gpt, "unknown partition type (%d)", |
device_name, mbr->mbr_part[i].part_typ); |
mbr->mbr_part[i].part_typ); |
return; |
return -1; |
} |
} |
|
continue; |
} |
} |
|
gpt_uuid_create(type, ent->ent_type, ent->ent_name, |
|
sizeof(ent->ent_name)); |
|
ent->ent_lba_start = htole64((uint64_t)start); |
|
ent->ent_lba_end = htole64((uint64_t)(start + size - 1LL)); |
|
ent++; |
} |
} |
ent = tbl->map_data; |
|
|
|
hdr->hdr_crc_table = htole32(crc32(ent, le32toh(hdr->hdr_entries) * |
|
le32toh(hdr->hdr_entsz))); |
|
hdr->hdr_crc_self = htole32(crc32(hdr, le32toh(hdr->hdr_size))); |
|
|
|
gpt_write(fd, gpt); |
if (gpt_write_primary(gpt) == -1) |
gpt_write(fd, tbl); |
return -1; |
|
|
/* |
if (gpt_write_backup(gpt) == -1) |
* Create backup GPT. |
return -1; |
*/ |
|
memcpy(tpg->map_data, gpt->map_data, secsz); |
|
hdr = tpg->map_data; |
|
hdr->hdr_lba_self = htole64(tpg->map_start); |
|
hdr->hdr_lba_alt = htole64(gpt->map_start); |
|
hdr->hdr_lba_table = htole64(lbt->map_start); |
|
hdr->hdr_crc_self = 0; /* Don't ever forget this! */ |
|
hdr->hdr_crc_self = htole32(crc32(hdr, le32toh(hdr->hdr_size))); |
|
|
|
gpt_write(fd, lbt); |
|
gpt_write(fd, tpg); |
|
|
|
map = map_find(MAP_TYPE_MBR); |
|
mbr = map->map_data; |
|
/* |
/* |
* Turn the MBR into a Protective MBR. |
* Turn the MBR into a Protective MBR. |
*/ |
*/ |
bzero(mbr->mbr_part, sizeof(mbr->mbr_part)); |
memset(mbr->mbr_part, 0, sizeof(mbr->mbr_part)); |
mbr->mbr_part[0].part_shd = 0x00; |
gpt_create_pmbr_part(mbr->mbr_part, last, active); |
mbr->mbr_part[0].part_ssect = 0x02; |
if (gpt_write(gpt, map) == -1) { |
mbr->mbr_part[0].part_scyl = 0x00; |
gpt_warn(gpt, "Cant write PMBR"); |
mbr->mbr_part[0].part_typ = MBR_PTYPE_PMBR; |
return -1; |
mbr->mbr_part[0].part_ehd = 0xfe; |
|
mbr->mbr_part[0].part_esect = 0xff; |
|
mbr->mbr_part[0].part_ecyl = 0xff; |
|
mbr->mbr_part[0].part_start_lo = htole16(1); |
|
if (last > 0xffffffff) { |
|
mbr->mbr_part[0].part_size_lo = htole16(0xffff); |
|
mbr->mbr_part[0].part_size_hi = htole16(0xffff); |
|
} else { |
|
mbr->mbr_part[0].part_size_lo = htole16(last); |
|
mbr->mbr_part[0].part_size_hi = htole16(last >> 16); |
|
} |
} |
gpt_write(fd, map); |
return 0; |
} |
} |
|
|
int |
static int |
cmd_migrate(int argc, char *argv[]) |
cmd_migrate(gpt_t gpt, int argc, char *argv[]) |
{ |
{ |
int ch, fd; |
int ch; |
|
int force = 0; |
|
int slice = 0; |
|
int active = 0; |
|
u_int parts = 128; |
|
|
/* Get the migrate options */ |
/* Get the migrate options */ |
while ((ch = getopt(argc, argv, "fs")) != -1) { |
while ((ch = getopt(argc, argv, "Afp:s")) != -1) { |
switch(ch) { |
switch(ch) { |
|
case 'A': |
|
active = 1; |
|
break; |
case 'f': |
case 'f': |
force = 1; |
force = 1; |
break; |
break; |
|
case 'p': |
|
if (gpt_uint_get(gpt, &parts) == -1) |
|
return usage(); |
|
break; |
case 's': |
case 's': |
slice = 1; |
slice = 1; |
break; |
break; |
default: |
default: |
usage_migrate(); |
return usage(); |
} |
} |
} |
} |
|
|
if (argc == optind) |
if (argc != optind) |
usage_migrate(); |
return usage(); |
|
|
while (optind < argc) { |
|
fd = gpt_open(argv[optind++]); |
|
if (fd == -1) { |
|
warn("unable to open device '%s'", device_name); |
|
continue; |
|
} |
|
|
|
migrate(fd); |
|
|
|
gpt_close(fd); |
|
} |
|
|
|
return (0); |
return migrate(gpt, parts, force, slice, active); |
} |
} |