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