1/* $NetBSD: mbr.c,v 1.48 2024/04/11 06:42:18 andvar Exp $ */ 2 3/* 4 * Copyright 1997 Piermont Information Systems Inc. 5 * All rights reserved. 6 * 7 * Written by Philip A. Nelson for Piermont Information Systems Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. The name of Piermont Information Systems Inc. may not be used to endorse 18 * or promote products derived from this software without specific prior 19 * written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS'' 22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE 25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 31 * THE POSSIBILITY OF SUCH DAMAGE. 32 * 33 */ 34 35/* 36 * Following applies to the geometry guessing code 37 */ 38 39/* 40 * Mach Operating System 41 * Copyright (c) 1992 Carnegie Mellon University 42 * All Rights Reserved. 43 * 44 * Permission to use, copy, modify and distribute this software and its 45 * documentation is hereby granted, provided that both the copyright 46 * notice and this permission notice appear in all copies of the 47 * software, derivative works or modified versions, and any portions 48 * thereof, and that both notices appear in supporting documentation. 49 * 50 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 51 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 52 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 53 * 54 * Carnegie Mellon requests users of this software to return to 55 * 56 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 57 * School of Computer Science 58 * Carnegie Mellon University 59 * Pittsburgh PA 15213-3890 60 * 61 * any improvements or extensions that they make and grant Carnegie Mellon 62 * the rights to redistribute these changes. 63 */ 64 65/* mbr.c -- DOS Master Boot Record editing code */ 66 67#ifdef HAVE_MBR 68 69#include <sys/param.h> 70#include <sys/types.h> 71#include <assert.h> 72#include <stdio.h> 73#include <stdlib.h> 74#include <unistd.h> 75#include <fcntl.h> 76#include <util.h> 77#include <paths.h> 78#include <sys/ioctl.h> 79#include "defs.h" 80#include "mbr.h" 81#include "md.h" 82#include "msg_defs.h" 83#include "menu_defs.h" 84#include "defsizes.h" 85#include "endian.h" 86 87#define NO_BOOTMENU (-0x100) 88 89#define MAXCYL 1023 /* Possibly 1024 */ 90#define MAXHEAD 255 /* Possibly 256 */ 91#define MAXSECTOR 63 92 93 94#define MBR_UNKNOWN_PTYPE 94 /* arbitrary not widely used value */ 95 96 97/* A list of predefined partition types */ 98const struct { 99 unsigned int ptype; 100 const char *desc; 101} mbr_part_types_src[] = { 102 { .ptype=MBR_PTYPE_NETBSD, .desc="NetBSD" }, 103 { .ptype=MBR_PTYPE_FAT32L, .desc="Windows FAT32, LBA" }, 104 { .ptype=MBR_PTYPE_EXT_LBA, .desc="Extended partition, LBA" }, 105 { .ptype=MBR_PTYPE_386BSD, .desc="FreeBSD/386BSD" }, 106 { .ptype=MBR_PTYPE_OPENBSD, .desc="OpenBSD" }, 107 { .ptype=MBR_PTYPE_LNXEXT2, .desc="Linux native" }, 108 { .ptype=MBR_PTYPE_LNXSWAP, .desc="Linux swap" }, 109 { .ptype=MBR_PTYPE_NTFSVOL, .desc="NTFS volume set" }, 110 { .ptype=MBR_PTYPE_NTFS, .desc="NTFS" }, 111 { .ptype=MBR_PTYPE_PREP, .desc="PReP Boot" }, 112#ifdef MBR_PTYPE_SOLARIS 113 { .ptype=MBR_PTYPE_SOLARIS, .desc="Solaris" }, 114#endif 115 { .ptype=MBR_PTYPE_FAT12, .desc="DOS FAT12" }, 116 { .ptype=MBR_PTYPE_FAT16S, .desc="DOS FAT16, <32M" }, 117 { .ptype=MBR_PTYPE_FAT16B, .desc="DOS FAT16, >32M" }, 118 { .ptype=MBR_PTYPE_FAT16L, .desc="Windows FAT16, LBA" }, 119 { .ptype=MBR_PTYPE_FAT32, .desc="Windows FAT32" }, 120 { .ptype=MBR_PTYPE_EFI, .desc="(U)EFI system partition" }, 121}; 122 123/* bookeeping of available partition types (including custom ones) */ 124struct mbr_part_type_info { 125 struct part_type_desc gen; /* generic description */ 126 char desc_buf[40], short_buf[10]; 127 size_t next_ptype; /* user interface order */ 128}; 129 130const struct disk_partitioning_scheme mbr_parts; 131struct mbr_disk_partitions { 132 struct disk_partitions dp, *dlabel; 133 mbr_info_t mbr; 134 uint ptn_alignment, ptn_0_offset, ext_ptn_alignment, 135 geo_sec, geo_head, geo_cyl, target; 136}; 137 138const struct disk_partitioning_scheme mbr_parts; 139 140static size_t known_part_types = 0, last_added_part_type = 0; 141static const size_t first_part_type = MBR_PTYPE_NETBSD; 142 143/* all partition types (we are lucky, only a fixed number is possible) */ 144struct mbr_part_type_info mbr_gen_type_desc[256]; 145 146extern const struct disk_partitioning_scheme disklabel_parts; 147 148static void convert_mbr_chs(int, int, int, uint8_t *, uint8_t *, 149 uint8_t *, uint32_t); 150 151static part_id mbr_add_part(struct disk_partitions *arg, 152 const struct disk_part_info *info, const char **errmsg); 153 154static size_t mbr_get_free_spaces(const struct disk_partitions *arg, 155 struct disk_part_free_space *result, size_t max_num_result, 156 daddr_t min_size, daddr_t align, daddr_t lower_bound, daddr_t ignore); 157 158static size_t mbr_type_from_gen_desc(const struct part_type_desc *desc); 159 160/* 161 * Notes on the extended partition editor. 162 * 163 * The extended partition structure is actually a singly linked list. 164 * Each of the 'mbr' sectors can only contain 2 items, the first describes 165 * a user partition (relative to that mbr sector), the second describes 166 * the following partition (relative to the start of the extended partition). 167 * 168 * The 'start' sector for the user partition is always the size of one 169 * track - very often 63. The extended partitions themselves should 170 * always start on a cylinder boundary using the BIOS geometry - often 171 * 16065 sectors per cylinder. 172 * 173 * The disk is also always described in increasing sector order. 174 * 175 * During editing we keep the mbr sectors accurate (it might have been 176 * easier to use absolute sector numbers though), and keep a copy of the 177 * entire sector - to preserve any information any other OS has tried 178 * to squirrel away in the (apparently) unused space. 179 * 180 * Typical disk (with some small numbers): 181 * 182 * 0 -> a 63 37 dos 183 * b 100 1000 extended LBA (type 15) 184 * 185 * 100 -> a 63 37 user 186 * b 100 200 extended partition (type 5) 187 * 188 * 200 -> a 63 37 user 189 * b 200 300 extended partition (type 5) 190 * 191 * 300 -> a 63 37 user 192 * b 0 0 0 (end of chain) 193 * 194 */ 195 196#ifndef debug_extended 197#define dump_mbr(mbr, msg) 198#else 199static void 200dump_mbr(mbr_info_t *m, const char *label) 201{ 202 int i; 203 uint ext_base = 0; 204 205 fprintf(stderr, "\n%s: bsec %d\n", label, bsec); 206 do { 207 fprintf(stderr, "%p: %12u %p\n", 208 m, m->sector, m->extended); 209 for (i = 0; i < MBR_PART_COUNT; i++) { 210 fprintf(stderr, " %*d %12u %12u %12" PRIu64, 211 10, 212 m->mbr.mbr_parts[i].mbrp_type, 213 m->mbr.mbr_parts[i].mbrp_start, 214 m->mbr.mbr_parts[i].mbrp_size, 215 (uint64_t)m->mbr.mbr_parts[i].mbrp_start + 216 (uint64_t)m->mbr.mbr_parts[i].mbrp_size); 217 if (m->sector == 0 && 218 MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) 219 ext_base = m->mbr.mbr_parts[i].mbrp_start; 220 if (m->sector > 0 && 221 m->mbr.mbr_parts[i].mbrp_size > 0) { 222 uint off = MBR_IS_EXTENDED( 223 m->mbr.mbr_parts[i].mbrp_type) 224 ? ext_base : m->sector; 225 fprintf(stderr, " -> [%u .. %u]", 226 m->mbr.mbr_parts[i].mbrp_start + off, 227 m->mbr.mbr_parts[i].mbrp_size + 228 m->mbr.mbr_parts[i].mbrp_start + off); 229 } 230 fprintf(stderr, ",\n"); 231 if (m->sector > 0 && i >= 1) 232 break; 233 } 234 } while ((m = m->extended)); 235} 236#endif 237 238/* 239 * Like pread, but handles re-blocking for non 512 byte sector disks 240 */ 241static ssize_t 242blockread(int fd, size_t secsize, void *buf, size_t nbytes, off_t offset) 243{ 244 ssize_t nr; 245 off_t sector = offset / 512; 246 off_t offs = sector * (off_t)secsize; 247 off_t mod = offs & (secsize - 1); 248 off_t rnd = offs & ~(secsize - 1); 249 char *iobuf; 250 251 assert(nbytes <= 512); 252 253 if (secsize == 512) 254 return pread(fd, buf, nbytes, offset); 255 256 iobuf = malloc(secsize); 257 if (iobuf == NULL) 258 return -1; 259 nr = pread(fd, iobuf, secsize, rnd); 260 if (nr == (off_t)secsize) 261 memcpy(buf, &iobuf[mod], nbytes); 262 free(iobuf); 263 264 return nr == (off_t)secsize ? (off_t)nbytes : -1; 265} 266 267/* 268 * Same for pwrite 269 */ 270static ssize_t 271blockwrite(int fd, size_t secsize, const void *buf, size_t nbytes, 272 off_t offset) 273{ 274 ssize_t nr; 275 off_t sector = offset / secsize; 276 off_t offs = sector * (off_t)secsize; 277 off_t mod = offs & (secsize - 1); 278 off_t rnd = offs & ~(secsize - 1); 279 char *iobuf; 280 281 assert(nbytes <= 512); 282 283 if (secsize == 512) 284 return pwrite(fd, buf, nbytes, offset); 285 286 iobuf = malloc(secsize); 287 if (iobuf == NULL) 288 return -1; 289 nr = pread(fd, iobuf, secsize, rnd); 290 if (nr == (off_t)secsize) { 291 memcpy(&iobuf[mod], buf, nbytes); 292 nr = pwrite(fd, iobuf, secsize, rnd); 293 } 294 free(iobuf); 295 296 return nr == (off_t)secsize ? (off_t)nbytes : -1; 297} 298 299static void 300free_last_mounted(mbr_info_t *m) 301{ 302 size_t i; 303 304 for (i = 0; i < MBR_PART_COUNT; i++) 305 free(__UNCONST(m->last_mounted[i])); 306} 307 308static void 309free_mbr_info(mbr_info_t *m) 310{ 311 if (m == NULL) 312 return; 313 free_last_mounted(m); 314 free(m); 315} 316 317/* 318 * To be used only on ports which cannot provide any bios geometry 319 */ 320int 321set_bios_geom_with_mbr_guess(struct disk_partitions *parts) 322{ 323 int cyl, head, sec; 324 325 msg_fmt_display(MSG_nobiosgeom, "%d%d%d", 326 pm->dlcyl, pm->dlsec, pm->dlhead); 327 if (guess_biosgeom_from_parts(parts, &cyl, &head, &sec) >= 0) 328 msg_fmt_display_add(MSG_biosguess, "%d%d%d", cyl, head, sec); 329 set_bios_geom(parts, &cyl, &head, &sec); 330 if (parts->pscheme->change_disk_geom) 331 parts->pscheme->change_disk_geom(parts, cyl, head, sec); 332 333 return edit_outer_parts(parts); 334} 335 336static void 337mbr_init_chs(struct mbr_disk_partitions *parts, int ncyl, int nhead, int nsec) 338{ 339 if (ncyl > MAXCYL) 340 ncyl = MAXCYL; 341 pm->current_cylsize = nhead*nsec; 342 pm->max_chs = (unsigned long)ncyl*nhead*nsec; 343 parts->geo_sec = nsec; 344 parts->geo_head = nhead; 345 parts->geo_cyl = ncyl; 346} 347 348/* 349 * get C/H/S geometry from user via menu interface and 350 * store in globals. 351 */ 352void 353set_bios_geom(struct disk_partitions *parts, int *cyl, int *head, int *sec) 354{ 355 char res[80]; 356 int bsec, bhead, bcyl; 357 daddr_t s; 358 359 if (parts->pscheme->change_disk_geom == NULL) 360 return; 361 362 msg_display_add(MSG_setbiosgeom); 363 364 do { 365 snprintf(res, 80, "%d", *sec); 366 msg_prompt_add(MSG_sectors, res, res, 80); 367 bsec = atoi(res); 368 } while (bsec <= 0 || bsec > MAXSECTOR); 369 370 do { 371 snprintf(res, 80, "%d", *head); 372 msg_prompt_add(MSG_heads, res, res, 80); 373 bhead = atoi(res); 374 } while (bhead <= 0 || bhead > MAXHEAD); 375 s = min(pm->dlsize, mbr_parts.size_limit); 376 bcyl = s / bsec / bhead; 377 if (s != bcyl * bsec * bhead) 378 bcyl++; 379 if (bcyl > MAXCYL) 380 bcyl = MAXCYL; 381 pm->max_chs = (unsigned long)bcyl * bhead * bsec; 382 pm->current_cylsize = bhead * bsec; 383 parts->pscheme->change_disk_geom(parts, bcyl, bhead, bsec); 384 *cyl = bcyl; 385 *head = bhead; 386 *sec = bsec; 387} 388 389static int 390find_mbr_space(const struct mbr_info_t *mbrs, uint *start, uint *size, 391 uint from, uint end_of_disk, uint ignore_at, bool primary_only) 392{ 393 uint sz; 394 int i, j; 395 uint s, e; 396 const mbr_info_t *m, *me; 397 bool is_extended; 398 399 check_again: 400 m = mbrs; 401 sz = end_of_disk-from; 402 if (from >= end_of_disk) 403 return -1; 404 405 for (i = 0; i < MBR_PART_COUNT; i++) { 406 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 407 continue; 408 409 is_extended = MBR_IS_EXTENDED( 410 m->mbr.mbr_parts[i].mbrp_type); 411 412 s = m->mbr.mbr_parts[i].mbrp_start + m->sector; 413 if (s == ignore_at) 414 continue; 415 e = s + m->mbr.mbr_parts[i].mbrp_size; 416 if (s <= from && e > from 417 && (!is_extended || primary_only)) { 418 if (e - 1 >= end_of_disk) 419 break; 420 if (e >= UINT_MAX) { 421 sz = 0; 422 break; 423 } 424 from = e + 1; 425 goto check_again; 426 } 427 if (s <= from && e > from && is_extended) { 428 /* 429 * if we start in the extended partition, 430 * we must end before its end 431 */ 432 sz = e - from; 433 } 434 if (s > from && s - from < sz) 435 sz = s - from; 436 437 if (is_extended) { 438 for (me = m->extended; me != NULL; me = me->extended) { 439 for (j = 0; j < MBR_PART_COUNT; j++) { 440 if (me->mbr.mbr_parts[j].mbrp_type == 441 MBR_PTYPE_UNUSED) 442 continue; 443 444 is_extended = MBR_IS_EXTENDED( 445 me->mbr.mbr_parts[j].mbrp_type); 446 447 if (is_extended && i > 0) 448 break; 449 450 s = me->mbr.mbr_parts[j].mbrp_start + 451 me->sector; 452 if (s == ignore_at) 453 continue; 454 e = s + me->mbr.mbr_parts[j].mbrp_size; 455 if (me->sector != 0 && me->sector< s) 456 /* 457 * can not allow to overwrite 458 * the ext mbr 459 */ 460 s = me->sector; 461 if (s <= from && e > from) { 462 if (e - 1 >= end_of_disk) 463 break; 464 from = e + 1; 465 goto check_again; 466 } 467 if (s > from && s - from < sz) 468 sz = s - from; 469 470 } 471 } 472 } 473 } 474 475 if (sz == 0) 476 return -1; 477 if (start != NULL) 478 *start = from; 479 if (size != NULL) 480 *size = sz; 481 return 0; 482} 483 484#ifdef BOOTSEL 485static int 486validate_and_set_names(mbr_info_t *mbri, const struct mbr_bootsel *src, 487 uint32_t ext_base) 488{ 489 size_t i, l; 490 const unsigned char *p; 491 492 /* 493 * The 16 bit magic used to detect whether mbr_bootsel is valid 494 * or not is pretty week - collisions have been seen in the wild; 495 * but maybe it is just foreign tools corruption reminiscents 496 * of NetBSD MBRs. Anyway, before accepting a boot menu definition, 497 * make sure it is kinda "sane". 498 */ 499 500 for (i = 0; i < MBR_PART_COUNT; i++) { 501 /* 502 * Make sure the name does not contain control chars 503 * (not using iscntrl due to minimalistic locale support 504 * in miniroot environments) and is properly 0-terminated. 505 */ 506 for (l = 0, p = (const unsigned char *)&src->mbrbs_nametab[i]; 507 *p != 0; l++, p++) { 508 if (l > MBR_BS_PARTNAMESIZE) 509 return 0; 510 if (*p < ' ') /* hacky 'iscntrl' */ 511 return 0; 512 } 513 } 514 515 memcpy(&mbri->mbrb, src, sizeof(*src)); 516 517 if (ext_base == 0) 518 return mbri->mbrb.mbrbs_defkey - SCAN_1; 519 return 0; 520} 521#endif 522 523static int 524valid_mbr(struct mbr_sector *mbrs) 525{ 526 527 return (le16toh(mbrs->mbr_magic) == MBR_MAGIC); 528} 529 530static int 531read_mbr(const char *disk, size_t secsize, mbr_info_t *mbri, 532 struct mbr_disk_partitions *parts) 533{ 534 struct mbr_partition *mbrp; 535 struct mbr_sector *mbrs = &mbri->mbr; 536 mbr_info_t *ext = NULL; 537 char diskpath[MAXPATHLEN]; 538 int fd, i; 539 uint32_t ext_base = 0, next_ext = 0; 540 int rval = -1; 541#ifdef BOOTSEL 542 mbr_info_t *ombri = mbri; 543 int bootkey = 0; 544#endif 545 546 memset(mbri, 0, sizeof *mbri); 547 548 /* Open the disk. */ 549 fd = opendisk(disk, O_RDONLY, diskpath, sizeof(diskpath), 0); 550 if (fd < 0) 551 goto bad_mbr; 552 553 for (;;) { 554 if (blockread(fd, secsize, mbrs, sizeof *mbrs, 555 (ext_base + next_ext) * (off_t)MBR_SECSIZE) 556 - sizeof *mbrs != 0) 557 break; 558 559 if (!valid_mbr(mbrs)) 560 break; 561 562 mbrp = &mbrs->mbr_parts[0]; 563 if (ext_base != 0) { 564 /* sanity check extended chain */ 565 if (MBR_IS_EXTENDED(mbrp[0].mbrp_type)) 566 break; 567 if (mbrp[1].mbrp_type != MBR_PTYPE_UNUSED && 568 !MBR_IS_EXTENDED(mbrp[1].mbrp_type)) 569 break; 570 if (mbrp[2].mbrp_type != MBR_PTYPE_UNUSED 571 || mbrp[3].mbrp_type != MBR_PTYPE_UNUSED) 572 break; 573 /* Looks ok, link into extended chain */ 574 mbri->extended = ext; 575 ext->extended = NULL; 576 mbri = ext; 577 ext = NULL; 578 } 579#if BOOTSEL 580 if (mbrs->mbr_bootsel_magic == htole16(MBR_MAGIC)) { 581 /* old bootsel, grab bootsel info */ 582 bootkey = validate_and_set_names(mbri, 583 (struct mbr_bootsel *) 584 ((uint8_t *)mbrs + MBR_BS_OLD_OFFSET), 585 ext_base); 586 } else if (mbrs->mbr_bootsel_magic == htole16(MBR_BS_MAGIC)) { 587 /* new location */ 588 bootkey = validate_and_set_names(mbri, 589 &mbrs->mbr_bootsel, ext_base); 590 } 591 /* Save original flags for mbr code update tests */ 592 mbri->oflags = mbri->mbrb.mbrbs_flags; 593#endif 594 mbri->sector = next_ext + ext_base; 595 next_ext = 0; 596 rval = 0; 597 for (i = 0; i < MBR_PART_COUNT; mbrp++, i++) { 598 if (mbrp->mbrp_type == MBR_PTYPE_UNUSED) { 599 /* type is unused, discard scum */ 600 memset(mbrp, 0, sizeof *mbrp); 601 continue; 602 } 603 mbrp->mbrp_start = le32toh(mbrp->mbrp_start); 604 mbrp->mbrp_size = le32toh(mbrp->mbrp_size); 605 if (MBR_IS_EXTENDED(mbrp->mbrp_type)) { 606 next_ext = mbrp->mbrp_start; 607 } else { 608 uint flags = 0; 609 if (mbrp->mbrp_type == MBR_PTYPE_NETBSD) { 610 flags |= GLM_LIKELY_FFS; 611 if (parts->target == ~0U) 612 parts->target = 613 mbri->sector + 614 mbrp->mbrp_start; 615 } else if (mbrp->mbrp_type == MBR_PTYPE_FAT12 || 616 mbrp->mbrp_type == MBR_PTYPE_FAT16S || 617 mbrp->mbrp_type == MBR_PTYPE_FAT16B || 618 mbrp->mbrp_type == MBR_PTYPE_FAT32 || 619 mbrp->mbrp_type == MBR_PTYPE_FAT32L || 620 mbrp->mbrp_type == MBR_PTYPE_FAT16L || 621 mbrp->mbrp_type == MBR_PTYPE_EFI) 622 flags |= GLM_MAYBE_FAT32; 623 else if (mbrp->mbrp_type == MBR_PTYPE_NTFS) 624 flags |= GLM_MAYBE_NTFS; 625 if (flags != 0) { 626 const char *mount = get_last_mounted( 627 fd, mbri->sector + mbrp->mbrp_start, 628 &mbri->fs_type[i], 629 &mbri->fs_sub_type[i], 630 flags); 631 char *p = strdup(mount); 632 canonicalize_last_mounted(p); 633 mbri->last_mounted[i] = p; 634 } 635 } 636#if BOOTSEL 637 if (mbri->mbrb.mbrbs_nametab[i][0] != 0 638 && bootkey-- == 0) 639 ombri->bootsec = mbri->sector + 640 mbrp->mbrp_start; 641#endif 642 } 643 644 if (next_ext == 0 || ext_base + next_ext <= mbri->sector) 645 break; 646 if (ext_base == 0) { 647 ext_base = next_ext; 648 next_ext = 0; 649 } 650 ext = calloc(1, sizeof *ext); 651 if (!ext) 652 break; 653 mbrs = &ext->mbr; 654 } 655 656 bad_mbr: 657 free_mbr_info(ext); 658 if (fd >= 0) 659 close(fd); 660 if (rval == -1) { 661 memset(&mbrs->mbr_parts, 0, sizeof mbrs->mbr_parts); 662 mbrs->mbr_magic = htole16(MBR_MAGIC); 663 } 664 dump_mbr(ombri, "read"); 665 return rval; 666} 667 668static int 669write_mbr(const char *disk, size_t secsize, mbr_info_t *mbri, int bsec, 670 int bhead, int bcyl) 671{ 672 char diskpath[MAXPATHLEN]; 673 int fd, i, ret = 0, bits = 0; 674 struct mbr_partition *mbrp; 675 u_int32_t pstart, psize; 676#ifdef BOOTSEL 677 struct mbr_sector *mbrs; 678#endif 679 struct mbr_sector mbrsec; 680 mbr_info_t *ext; 681 uint sector; 682 683 dump_mbr(mbri, "write"); 684 685 /* Open the disk. */ 686 fd = opendisk(disk, secsize == 512 ? O_WRONLY : O_RDWR, 687 diskpath, sizeof(diskpath), 0); 688 if (fd < 0) 689 return -1; 690 691 /* Remove all wedges */ 692 if (ioctl(fd, DIOCRMWEDGES, &bits) == -1) 693 return -1; 694 695#ifdef BOOTSEL 696 /* 697 * If the main boot code (appears to) contain the netbsd bootcode, 698 * copy in all the menu strings and set the default keycode 699 * to be that for the default partition. 700 * Unfortunately we can't rely on the user having actually updated 701 * to the new mbr code :-( 702 */ 703 if (mbri->mbr.mbr_bootsel_magic == htole16(MBR_BS_MAGIC) 704 || mbri->mbr.mbr_bootsel_magic == htole16(MBR_MAGIC)) { 705 int8_t key = SCAN_1; 706 uint offset = MBR_BS_OFFSET; 707 if (mbri->mbr.mbr_bootsel_magic == htole16(MBR_MAGIC)) 708 offset = MBR_BS_OLD_OFFSET; 709 mbri->mbrb.mbrbs_defkey = SCAN_ENTER; 710 if (mbri->mbrb.mbrbs_timeo == 0) 711 mbri->mbrb.mbrbs_timeo = 182; /* 10 seconds */ 712 for (ext = mbri; ext != NULL; ext = ext->extended) { 713 mbrs = &ext->mbr; 714 mbrp = &mbrs->mbr_parts[0]; 715 /* Ensure marker is set in each sector */ 716 mbrs->mbr_bootsel_magic = mbri->mbr.mbr_bootsel_magic; 717 /* and copy in bootsel parameters */ 718 *(struct mbr_bootsel *)((uint8_t *)mbrs + offset) = 719 ext->mbrb; 720 for (i = 0; i < MBR_PART_COUNT; i++) { 721 if (ext->mbrb.mbrbs_nametab[i][0] == 0) 722 continue; 723 if (ext->sector + mbrp->mbrp_start == 724 mbri->bootsec) 725 mbri->mbrb.mbrbs_defkey = key; 726 key++; 727 } 728 } 729 /* copy main data (again) since we've put the 'key' in */ 730 *(struct mbr_bootsel *)((uint8_t *)&mbri->mbr + offset) = 731 mbri->mbrb; 732 } 733#endif 734 735 for (ext = mbri; ext != NULL; ext = ext->extended) { 736 memset(mbri->wedge, 0, sizeof mbri->wedge); 737 sector = ext->sector; 738 mbrsec = ext->mbr; /* copy sector */ 739 mbrp = &mbrsec.mbr_parts[0]; 740 741 if (sector != 0 && ext->extended != NULL 742 && ext->extended->mbr.mbr_parts[0].mbrp_type 743 == MBR_PTYPE_UNUSED) { 744 745 /* 746 * This should never happen nowadays, old code 747 * inserted empty ext sectors in the chain to 748 * help the gui out - we do not do that anymore. 749 */ 750 assert(false); 751 752 /* We are followed by an empty slot, collapse out */ 753 ext = ext->extended; 754 /* Make us describe the next non-empty partition */ 755 mbrp[1] = ext->mbr.mbr_parts[1]; 756 } 757 758 for (i = 0; i < MBR_PART_COUNT; i++) { 759 if (mbrp[i].mbrp_start == 0 && mbrp[i].mbrp_size == 0) { 760 mbrp[i].mbrp_scyl = 0; 761 mbrp[i].mbrp_shd = 0; 762 mbrp[i].mbrp_ssect = 0; 763 mbrp[i].mbrp_ecyl = 0; 764 mbrp[i].mbrp_ehd = 0; 765 mbrp[i].mbrp_esect = 0; 766 continue; 767 } 768 pstart = mbrp[i].mbrp_start; 769 psize = mbrp[i].mbrp_size; 770 mbrp[i].mbrp_start = htole32(pstart); 771 mbrp[i].mbrp_size = htole32(psize); 772 if (bsec && bcyl && bhead) { 773 convert_mbr_chs(bcyl, bhead, bsec, 774 &mbrp[i].mbrp_scyl, &mbrp[i].mbrp_shd, 775 &mbrp[i].mbrp_ssect, pstart); 776 convert_mbr_chs(bcyl, bhead, bsec, 777 &mbrp[i].mbrp_ecyl, &mbrp[i].mbrp_ehd, 778 &mbrp[i].mbrp_esect, pstart + psize - 1); 779 } 780 } 781 782 mbrsec.mbr_magic = htole16(MBR_MAGIC); 783 if (blockwrite(fd, secsize, &mbrsec, sizeof mbrsec, 784 sector * (off_t)MBR_SECSIZE) < 0) { 785 ret = -1; 786 break; 787 } 788 } 789 790 (void)close(fd); 791 return ret; 792} 793 794static void 795convert_mbr_chs(int cyl, int head, int sec, 796 uint8_t *cylp, uint8_t *headp, uint8_t *secp, 797 uint32_t relsecs) 798{ 799 unsigned int tcyl, temp, thead, tsec; 800 801 temp = head * sec; 802 tcyl = relsecs / temp; 803 relsecs -= tcyl * temp; 804 805 thead = relsecs / sec; 806 tsec = relsecs - thead * sec + 1; 807 808 if (tcyl > MAXCYL) 809 tcyl = MAXCYL; 810 811 *cylp = MBR_PUT_LSCYL(tcyl); 812 *headp = thead; 813 *secp = MBR_PUT_MSCYLANDSEC(tcyl, tsec); 814} 815 816/* 817 * This function is ONLY to be used as a last resort to provide a 818 * hint for the user. Ports should provide a more reliable way 819 * of getting the BIOS geometry. The i386 code, for example, 820 * uses the BIOS geometry as passed on from the bootblocks, 821 * and only uses this as a hint to the user when that information 822 * is not present, or a match could not be made with a NetBSD 823 * device. 824 */ 825int 826guess_biosgeom_from_parts(struct disk_partitions *parts, 827 int *cyl, int *head, int *sec) 828{ 829 830 /* 831 * The physical parameters may be invalid as bios geometry. 832 * If we cannot determine the actual bios geometry, we are 833 * better off picking a likely 'faked' geometry than leaving 834 * the invalid physical one. 835 */ 836 837 int xcylinders = pm->dlcyl; 838 int xheads = pm->dlhead; 839 daddr_t xsectors = pm->dlsec; 840 daddr_t xsize = min(pm->dlsize, mbr_parts.size_limit); 841 if (xcylinders > MAXCYL || xheads > MAXHEAD || xsectors > MAXSECTOR) { 842 xsectors = MAXSECTOR; 843 xheads = MAXHEAD; 844 xcylinders = xsize / (MAXSECTOR * MAXHEAD); 845 if (xcylinders > MAXCYL) 846 xcylinders = MAXCYL; 847 } 848 *cyl = xcylinders; 849 *head = xheads; 850 *sec = xsectors; 851 852 if (parts->pscheme->guess_disk_geom == NULL) 853 return -1; 854 855 return parts->pscheme->guess_disk_geom(parts, cyl, head, sec); 856} 857 858static int 859mbr_comp_part_entry(const void *a, const void *b) 860{ 861 const struct mbr_partition *part_a = a, 862 *part_b = b; 863 864 if (part_a->mbrp_type == MBR_PTYPE_UNUSED 865 && part_b->mbrp_type != MBR_PTYPE_UNUSED) 866 return 1; 867 868 if (part_b->mbrp_type == MBR_PTYPE_UNUSED 869 && part_a->mbrp_type != MBR_PTYPE_UNUSED) 870 return -1; 871 872 return part_a->mbrp_start < part_b->mbrp_start ? -1 : 1; 873} 874 875static void 876mbr_sort_main_mbr(struct mbr_sector *m) 877{ 878 qsort(&m->mbr_parts[0], MBR_PART_COUNT, 879 sizeof(m->mbr_parts[0]), mbr_comp_part_entry); 880} 881 882static void 883mbr_init_default_alignments(struct mbr_disk_partitions *parts, uint track) 884{ 885 if (track == 0) 886 track = 16065; 887 888 assert(parts->dp.disk_size > 0); 889 if (parts->dp.disk_size < 0) 890 return; 891 892 parts->ptn_0_offset = parts->geo_sec; 893 894 /* Use 1MB offset/alignment for large (>128GB) disks */ 895 if (parts->dp.disk_size > HUGE_DISK_SIZE) { 896 parts->ptn_alignment = 2048; 897 } else if (parts->dp.disk_size > TINY_DISK_SIZE) { 898 parts->ptn_alignment = 64; 899 } else { 900 parts->ptn_alignment = 1; 901 } 902 parts->ext_ptn_alignment = track; 903} 904 905static struct disk_partitions * 906mbr_create_new(const char *disk, daddr_t start, daddr_t len, 907 bool is_boot_drive, struct disk_partitions *parent) 908{ 909 struct mbr_disk_partitions *parts; 910 struct disk_geom geo; 911 912 assert(start == 0); 913 if (start != 0) 914 return NULL; 915 916 parts = calloc(1, sizeof(*parts)); 917 if (!parts) 918 return NULL; 919 920 parts->dp.pscheme = &mbr_parts; 921 parts->dp.disk = strdup(disk); 922 if (len > mbr_parts.size_limit) 923 len = mbr_parts.size_limit; 924 parts->dp.disk_start = start; 925 parts->dp.disk_size = len; 926 parts->dp.free_space = len-1; 927 parts->dp.bytes_per_sector = 512; 928 parts->geo_sec = MAXSECTOR; 929 parts->geo_head = MAXHEAD; 930 parts->geo_cyl = len/MAXHEAD/MAXSECTOR+1; 931 parts->target = ~0U; 932 933 if (get_disk_geom(disk, &geo)) { 934 parts->geo_sec = geo.dg_nsectors; 935 parts->geo_head = geo.dg_ntracks; 936 parts->geo_cyl = geo.dg_ncylinders; 937 parts->dp.bytes_per_sector = geo.dg_secsize; 938 } 939 940 mbr_init_default_alignments(parts, 0); 941 942 return &parts->dp; 943} 944 945static void 946mbr_calc_free_space(struct mbr_disk_partitions *parts) 947{ 948 size_t i; 949 mbr_info_t *m; 950 951 parts->dp.free_space = parts->dp.disk_size - 1; 952 parts->dp.num_part = 0; 953 m = &parts->mbr; 954 do { 955 for (i = 0; i < MBR_PART_COUNT; i++) { 956 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 957 continue; 958 959 if (m != &parts->mbr && i > 0 && 960 MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) 961 break; 962 963 parts->dp.num_part++; 964 if (MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) 965 continue; 966 967 daddr_t psize = m->mbr.mbr_parts[i].mbrp_size; 968 if (m != &parts->mbr) 969 psize += m->mbr.mbr_parts[i].mbrp_start; 970 971 if (psize > parts->dp.free_space) 972 parts->dp.free_space = 0; 973 else 974 parts->dp.free_space -= psize; 975 } 976 } while ((m = m->extended)); 977} 978 979static struct disk_partitions * 980mbr_read_from_disk(const char *disk, daddr_t start, daddr_t len, size_t bps, 981 const struct disk_partitioning_scheme *scheme) 982{ 983 struct mbr_disk_partitions *parts; 984 985 assert(start == 0); 986 if (start != 0) 987 return NULL; 988 989 parts = calloc(1, sizeof(*parts)); 990 if (!parts) 991 return NULL; 992 993 parts->dp.pscheme = scheme; 994 parts->dp.disk = strdup(disk); 995 if (len >= mbr_parts.size_limit) 996 len = mbr_parts.size_limit; 997 parts->dp.disk_start = start; 998 parts->dp.disk_size = len; 999 parts->geo_sec = MAXSECTOR; 1000 parts->geo_head = MAXHEAD; 1001 parts->geo_cyl = len/MAXHEAD/MAXSECTOR+1; 1002 parts->dp.bytes_per_sector = bps; 1003 parts->target = ~0U; 1004 mbr_init_default_alignments(parts, 0); 1005 if (read_mbr(disk, parts->dp.bytes_per_sector, &parts->mbr, parts) 1006 == -1) { 1007 free(parts); 1008 return NULL; 1009 } 1010 mbr_calc_free_space(parts); 1011 if (parts->dp.num_part == 1 && 1012 parts->dp.free_space < parts->ptn_alignment) { 1013 struct disk_part_info info; 1014 1015 /* 1016 * Check if this is a GPT protective MBR 1017 */ 1018 if (parts->dp.pscheme->get_part_info(&parts->dp, 0, &info) 1019 && info.nat_type != NULL 1020 && mbr_type_from_gen_desc(info.nat_type) == 0xEE) { 1021 parts->dp.pscheme->free(&parts->dp); 1022 return NULL; 1023 } 1024 } 1025 1026 return &parts->dp; 1027} 1028 1029static bool 1030mbr_write_to_disk(struct disk_partitions *new_state) 1031{ 1032 struct mbr_disk_partitions *parts = 1033 (struct mbr_disk_partitions *)new_state; 1034 unsigned long bsec, bhead, bcyl; 1035 daddr_t t; 1036 1037 assert(parts->geo_sec != 0); 1038 if (parts->geo_sec != 0) { 1039 bsec = parts->geo_sec; 1040 bhead = parts->ext_ptn_alignment / bsec; 1041 } else { 1042 bsec = MAXSECTOR; 1043 bhead = MAXHEAD; 1044 } 1045 t = bsec * bhead; 1046 assert(t != 0); 1047 if ((daddr_t)(1UL<<10) * t <= parts->dp.disk_size) 1048 bcyl = (1UL<<10) - 1; 1049 else 1050 bcyl = (unsigned long)(parts->dp.disk_size / t); 1051 1052 return write_mbr(parts->dp.disk, parts->dp.bytes_per_sector, 1053 &parts->mbr, bsec, bhead, bcyl) == 0; 1054} 1055 1056static bool 1057mbr_change_disk_geom(struct disk_partitions *arg, int ncyl, int nhead, 1058 int nsec) 1059{ 1060 struct mbr_disk_partitions *parts = (struct mbr_disk_partitions *)arg; 1061 daddr_t ptn_0_base, ptn_0_limit; 1062 struct disk_part_info info; 1063 1064 /* Default to using 'traditional' cylinder alignment */ 1065 mbr_init_chs(parts, ncyl, nhead, nsec); 1066 mbr_init_default_alignments(parts, nhead * nsec); 1067 1068 if (parts->dp.disk_size <= TINY_DISK_SIZE) { 1069 set_default_sizemult(arg->disk, 1070 parts->dp.bytes_per_sector, parts->dp.bytes_per_sector); 1071 return true; 1072 } 1073 1074 if (parts->dp.num_part > 0 && 1075 parts->dp.pscheme->get_part_info(arg, 0, &info)) { 1076 1077 /* Try to copy offset of first partition */ 1078 ptn_0_base = info.start; 1079 ptn_0_limit = info.start + info.size; 1080 if (!(ptn_0_limit & 2047)) { 1081 /* Partition ends on a 1MB boundary, align to 1MB */ 1082 parts->ptn_alignment = 2048; 1083 if ((ptn_0_base <= 2048 1084 && !(ptn_0_base & (ptn_0_base - 1))) 1085 || (ptn_0_base < parts->ptn_0_offset)) { 1086 /* 1087 * If ptn_base is a power of 2, use it. 1088 * Also use it if the first partition 1089 * already is close to the beginning 1090 * of the disk and we can't enforce 1091 * better alignment. 1092 */ 1093 parts->ptn_0_offset = ptn_0_base; 1094 } 1095 } 1096 } 1097 set_default_sizemult(arg->disk, MEG, parts->dp.bytes_per_sector); 1098 return true; 1099} 1100 1101static size_t 1102mbr_type_from_gen_desc(const struct part_type_desc *desc) 1103{ 1104 for (size_t i = 0; i < __arraycount(mbr_gen_type_desc); i++) 1105 if (&mbr_gen_type_desc[i].gen == desc) 1106 return i; 1107 1108 return SIZE_T_MAX; 1109} 1110 1111static enum part_type 1112mbr_map_part_type(unsigned int t) 1113{ 1114 /* Map some special MBR partition types */ 1115 switch (t) { 1116 case MBR_PTYPE_FAT32: 1117 case MBR_PTYPE_FAT32L: 1118 case MBR_PTYPE_FAT16S: 1119 case MBR_PTYPE_FAT16B: 1120 case MBR_PTYPE_FAT16L: 1121 case MBR_PTYPE_FAT12: 1122 case MBR_PTYPE_FT_FAT32: 1123 case MBR_PTYPE_FT_FAT32_EXT: 1124 return PT_FAT; 1125 case MBR_PTYPE_EFI: 1126 return PT_EFI_SYSTEM; 1127 case MBR_PTYPE_LNXEXT2: 1128 return PT_EXT2; 1129 case MBR_PTYPE_NETBSD: 1130 return PT_root; 1131 } 1132 1133 return PT_unknown; 1134} 1135 1136static void 1137map_mbr_part_types(void) 1138{ 1139 1140 for (size_t i = 0; i < __arraycount(mbr_part_types_src); i++) { 1141 unsigned int v = mbr_part_types_src[i].ptype; 1142 1143 snprintf(mbr_gen_type_desc[v].short_buf, 1144 sizeof(mbr_gen_type_desc[v].short_buf), "%u", v); 1145 mbr_gen_type_desc[v].gen.short_desc = 1146 mbr_gen_type_desc[v].short_buf; 1147 mbr_gen_type_desc[v].gen.description = 1148 mbr_part_types_src[i].desc; 1149 mbr_gen_type_desc[v].gen.generic_ptype = mbr_map_part_type(v); 1150 mbr_gen_type_desc[v].next_ptype = ~0U; 1151 mbr_gen_type_desc[last_added_part_type].next_ptype = v; 1152 known_part_types++; 1153 last_added_part_type = v; 1154 } 1155} 1156 1157static size_t 1158mbr_get_part_type_count(void) 1159{ 1160 if (known_part_types == 0) 1161 map_mbr_part_types(); 1162 1163 return known_part_types; 1164} 1165 1166static const struct part_type_desc * 1167mbr_get_fs_part_type(enum part_type pt, unsigned fs_type, unsigned sub_type) 1168{ 1169 if (known_part_types == 0) 1170 map_mbr_part_types(); 1171 1172 switch (fs_type) { 1173 case FS_BSDFFS: 1174 return &mbr_gen_type_desc[MBR_PTYPE_NETBSD].gen; 1175 case FS_EX2FS: 1176 return &mbr_gen_type_desc[MBR_PTYPE_LNXEXT2].gen; 1177 case FS_MSDOS: 1178 if (sub_type == 0) 1179 sub_type = MBR_PTYPE_FAT32L; 1180 1181 switch (sub_type) { 1182 case MBR_PTYPE_FAT12: 1183 case MBR_PTYPE_FAT16S: 1184 case MBR_PTYPE_FAT16B: 1185 case MBR_PTYPE_FAT32: 1186 case MBR_PTYPE_FAT32L: 1187 case MBR_PTYPE_FAT16L: 1188 return &mbr_gen_type_desc[sub_type].gen; 1189 } 1190 break; 1191 case FS_EFI_SP: 1192 return &mbr_gen_type_desc[MBR_PTYPE_EFI].gen; 1193 } 1194 1195 return NULL; 1196} 1197 1198static const struct part_type_desc * 1199mbr_get_part_type(size_t index) 1200{ 1201 size_t i, no; 1202 1203 if (known_part_types == 0) 1204 map_mbr_part_types(); 1205 1206 if (index >= known_part_types) 1207 return NULL; 1208 1209 for (i = first_part_type, no = 0; i < __arraycount(mbr_gen_type_desc) 1210 && no != index; no++) 1211 i = mbr_gen_type_desc[i].next_ptype; 1212 1213 if (i >= __arraycount(mbr_gen_type_desc)) 1214 return NULL; 1215 return &mbr_gen_type_desc[i].gen; 1216} 1217 1218static const struct part_type_desc * 1219mbr_new_custom_part_type(unsigned int v) 1220{ 1221 snprintf(mbr_gen_type_desc[v].short_buf, 1222 sizeof(mbr_gen_type_desc[v].short_buf), "%u", v); 1223 snprintf(mbr_gen_type_desc[v].desc_buf, 1224 sizeof(mbr_gen_type_desc[v].desc_buf), "%s (%u)", 1225 msg_string(MSG_custom_type), v); 1226 mbr_gen_type_desc[v].gen.short_desc = mbr_gen_type_desc[v].short_buf; 1227 mbr_gen_type_desc[v].gen.description = mbr_gen_type_desc[v].desc_buf; 1228 mbr_gen_type_desc[v].gen.generic_ptype = mbr_map_part_type(v); 1229 mbr_gen_type_desc[v].next_ptype = ~0U; 1230 mbr_gen_type_desc[last_added_part_type].next_ptype = v; 1231 known_part_types++; 1232 last_added_part_type = v; 1233 1234 return &mbr_gen_type_desc[v].gen; 1235} 1236 1237static const struct part_type_desc * 1238mbr_custom_part_type(const char *custom, const char **err_msg) 1239{ 1240 unsigned long v; 1241 char *endp; 1242 1243 if (known_part_types == 0) 1244 map_mbr_part_types(); 1245 1246 v = strtoul(custom, &endp, 10); 1247 if (v > 255 || (v == 0 && *endp != 0)) { 1248 if (err_msg != NULL) 1249 *err_msg = msg_string(MSG_mbr_type_invalid); 1250 return NULL; 1251 } 1252 1253 if (mbr_gen_type_desc[v].gen.short_desc != NULL) 1254 return &mbr_gen_type_desc[v].gen; 1255 1256 return mbr_new_custom_part_type(v); 1257} 1258 1259static const struct part_type_desc * 1260mbr_create_unknown_part_type(void) 1261{ 1262 1263 if (mbr_gen_type_desc[MBR_UNKNOWN_PTYPE].gen.short_desc != NULL) 1264 return &mbr_gen_type_desc[MBR_UNKNOWN_PTYPE].gen; 1265 1266 return mbr_new_custom_part_type(MBR_UNKNOWN_PTYPE); 1267} 1268 1269static const struct part_type_desc * 1270mbr_get_gen_type_desc(unsigned int pt) 1271{ 1272 1273 if (known_part_types == 0) 1274 map_mbr_part_types(); 1275 1276 if (pt >= __arraycount(mbr_gen_type_desc)) 1277 return NULL; 1278 1279 if (mbr_gen_type_desc[pt].gen.short_desc != NULL) 1280 return &mbr_gen_type_desc[pt].gen; 1281 1282 return mbr_new_custom_part_type(pt); 1283} 1284 1285static const struct part_type_desc * 1286mbr_get_generic_part_type(enum part_type pt) 1287{ 1288 switch (pt) { 1289 case PT_root: 1290 return mbr_get_gen_type_desc(MBR_PTYPE_NETBSD); 1291 case PT_FAT: 1292 return mbr_get_gen_type_desc(MBR_PTYPE_FAT32L); 1293 case PT_EXT2: 1294 return mbr_get_gen_type_desc(MBR_PTYPE_LNXEXT2); 1295 case PT_EFI_SYSTEM: 1296 return mbr_get_gen_type_desc(MBR_PTYPE_EFI); 1297 default: 1298 break; 1299 } 1300 assert(false); 1301 return NULL; 1302} 1303 1304static void 1305mbr_partition_to_info(const struct mbr_partition *mp, daddr_t start_off, 1306 struct disk_part_info *info) 1307{ 1308 memset(info, 0, sizeof(*info)); 1309 info->start = mp->mbrp_start + start_off; 1310 info->size = mp->mbrp_size; 1311 info->nat_type = mbr_get_gen_type_desc(mp->mbrp_type); 1312 if (mp->mbrp_type == MBR_PTYPE_NETBSD) { 1313 info->flags |= PTI_SEC_CONTAINER; 1314 } else if (MBR_IS_EXTENDED(mp->mbrp_type)) 1315 info->flags |= PTI_PSCHEME_INTERNAL; 1316} 1317 1318static bool 1319mbr_part_apply(const struct disk_partitions *arg, part_id id, 1320 bool (*func)(const struct disk_partitions *arg, part_id id, 1321 const mbr_info_t *mb, int i, bool primary, 1322 const struct mbr_partition *mp, void *), 1323 void *cookie) 1324{ 1325 const struct mbr_disk_partitions *parts = 1326 (const struct mbr_disk_partitions*)arg; 1327 part_id i, j, no; 1328 const mbr_info_t *m = &parts->mbr, *me; 1329 1330 no = 0; 1331 for (i = 0; i < MBR_PART_COUNT; i++) { 1332 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 1333 continue; 1334 1335 if (no == id) { 1336 return func(arg, id, m, i, true, 1337 &m->mbr.mbr_parts[i], cookie); 1338 } 1339 no++; 1340 1341 if (MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) { 1342 for (me = m->extended; me != NULL; me = me->extended) { 1343 for (j = 0; j < MBR_PART_COUNT; j++) { 1344 if (me->mbr.mbr_parts[j].mbrp_type == 1345 MBR_PTYPE_UNUSED) 1346 continue; 1347 if (j > 0 && MBR_IS_EXTENDED( 1348 me->mbr.mbr_parts[j].mbrp_type)) 1349 break; 1350 if (no == id) { 1351 return func(arg, id, me, j, 1352 false, 1353 &me->mbr.mbr_parts[j], 1354 cookie); 1355 } 1356 no++; 1357 } 1358 } 1359 } 1360 } 1361 1362 1363 return false; 1364} 1365 1366static bool 1367mbr_do_get_part_info(const struct disk_partitions *arg, part_id id, 1368 const mbr_info_t *mb, int i, bool primary, 1369 const struct mbr_partition *mp, void *cookie) 1370{ 1371 struct disk_part_info *info = cookie; 1372 const struct mbr_disk_partitions *parts = 1373 (const struct mbr_disk_partitions*)arg; 1374 1375 mbr_partition_to_info(mp, mb->sector, info); 1376 if (mp->mbrp_start + mb->sector == parts->target) 1377 info->flags |= PTI_INSTALL_TARGET; 1378 if (mb->last_mounted[i] != NULL && mb->last_mounted[i][0] != 0) 1379 info->last_mounted = mb->last_mounted[i]; 1380 if (mb->fs_type[i] != FS_UNUSED) { 1381 info->fs_type = mb->fs_type[i]; 1382 info->fs_sub_type = mb->fs_sub_type[i]; 1383 } else { 1384 info->fs_sub_type = 0; 1385 switch (mp->mbrp_type) { 1386 case MBR_PTYPE_FAT12: 1387 case MBR_PTYPE_FAT16S: 1388 case MBR_PTYPE_FAT16B: 1389 case MBR_PTYPE_FAT32: 1390 case MBR_PTYPE_FAT32L: 1391 case MBR_PTYPE_FAT16L: 1392 case MBR_PTYPE_OS2_DOS12: 1393 case MBR_PTYPE_OS2_DOS16S: 1394 case MBR_PTYPE_OS2_DOS16B: 1395 case MBR_PTYPE_HID_FAT32: 1396 case MBR_PTYPE_HID_FAT32_LBA: 1397 case MBR_PTYPE_HID_FAT16_LBA: 1398 case MBR_PTYPE_MDOS_FAT12: 1399 case MBR_PTYPE_MDOS_FAT16S: 1400 case MBR_PTYPE_MDOS_EXT: 1401 case MBR_PTYPE_MDOS_FAT16B: 1402 case MBR_PTYPE_SPEEDSTOR_16S: 1403 case MBR_PTYPE_EFI: 1404 info->fs_type = FS_MSDOS; 1405 info->fs_sub_type = mp->mbrp_type; 1406 break; 1407 case MBR_PTYPE_LNXEXT2: 1408 info->fs_type = FS_EX2FS; 1409 break; 1410 case MBR_PTYPE_XENIX_ROOT: 1411 case MBR_PTYPE_XENIX_USR: 1412 info->fs_type = FS_SYSV; 1413 break; 1414 case MBR_PTYPE_NTFS: 1415 info->fs_type = FS_NTFS; 1416 break; 1417 case MBR_PTYPE_APPLE_HFS: 1418 info->fs_type = FS_HFS; 1419 break; 1420 case MBR_PTYPE_VMWARE: 1421 info->fs_type = FS_VMFS; 1422 break; 1423 case MBR_PTYPE_AST_SWAP: 1424 case MBR_PTYPE_DRDOS_LSWAP: 1425 case MBR_PTYPE_LNXSWAP: 1426 case MBR_PTYPE_BSDI_SWAP: 1427 case MBR_PTYPE_HID_LNX_SWAP: 1428 case MBR_PTYPE_VMWARE_SWAP: 1429 info->fs_type = FS_SWAP; 1430 break; 1431 } 1432 } 1433 return true; 1434} 1435 1436static bool 1437get_wedge_devname(const struct disk_partitions *arg, part_id id, 1438 const mbr_info_t *mb, int i, bool primary, 1439 const struct mbr_partition *mp, void *cookie) 1440{ 1441 char **res = cookie; 1442 1443 if (!res) 1444 return false; 1445 1446 *res = __UNCONST(mb->wedge[i]); 1447 return true; 1448} 1449 1450static bool 1451mbr_part_get_wedge(const struct disk_partitions *arg, part_id id, 1452 char **res) 1453{ 1454 return mbr_part_apply(arg, id, get_wedge_devname, res); 1455} 1456 1457static bool 1458mbr_get_part_info(const struct disk_partitions *arg, part_id id, 1459 struct disk_part_info *info) 1460{ 1461 return mbr_part_apply(arg, id, mbr_do_get_part_info, info); 1462} 1463 1464static bool 1465type_can_change(const struct disk_partitions *arg, part_id id, 1466 const mbr_info_t *mb, int i, bool primary, 1467 const struct mbr_partition *mp, void *cookie) 1468{ 1469 /* 1470 * The extended partition can only change type or be 1471 * deleted if it is empty 1472 */ 1473 if (!MBR_IS_EXTENDED(mp->mbrp_type)) 1474 return true; 1475 return primary && mb->extended == NULL; 1476} 1477 1478static bool 1479mbr_part_type_can_change(const struct disk_partitions *arg, part_id id) 1480{ 1481 return mbr_part_apply(arg, id, type_can_change, NULL); 1482} 1483 1484struct part_get_str_data { 1485 char *str; 1486 size_t avail_space; 1487 size_t col; 1488}; 1489 1490 1491static bool 1492mbr_get_part_table_str(const struct disk_partitions *arg, part_id id, 1493 const mbr_info_t *mb, int i, bool primary, 1494 const struct mbr_partition *mp, void *cookie) 1495{ 1496 struct part_get_str_data *data = cookie; 1497 char *str = data->str; 1498 const struct part_type_desc *ptype; 1499 1500 switch (data->col) { 1501 case 0: 1502 ptype = mbr_get_gen_type_desc(mp->mbrp_type); 1503 if (ptype != NULL) 1504 strncpy(str, ptype->description, data->avail_space); 1505 else 1506 snprintf(str, data->avail_space, "%u", mp->mbrp_type); 1507 str[data->avail_space-1] = 0; 1508 break; 1509 case 1: 1510 if (mb->last_mounted[i]) 1511 strlcpy(str, mb->last_mounted[i], data->avail_space); 1512 else 1513 *str = 0; 1514 break; 1515#ifdef BOOTSEL 1516 case 2: 1517 if (mb->mbrb.mbrbs_nametab[i][0] != 0) 1518 strlcpy(str, mb->mbrb.mbrbs_nametab[i], 1519 data->avail_space); 1520 else 1521 *str = 0; 1522 break; 1523#endif 1524 } 1525 1526 return true; 1527} 1528 1529static bool 1530mbr_table_str(const struct disk_partitions *arg, part_id id, size_t col, 1531 char *str, size_t avail_space) 1532{ 1533 struct part_get_str_data data; 1534 1535 data.str = str; 1536 data.avail_space = avail_space; 1537 data.col = col; 1538 return mbr_part_apply(arg, id, mbr_get_part_table_str, &data); 1539} 1540 1541static bool 1542mbr_get_part_attr_str(const struct disk_partitions *arg, part_id id, 1543 const mbr_info_t *mb, int i, bool primary, 1544 const struct mbr_partition *mp, void *cookie) 1545{ 1546#ifdef BOOTSEL 1547 const struct mbr_disk_partitions *parts = 1548 (const struct mbr_disk_partitions*)arg; 1549#endif 1550 struct part_get_str_data *data = cookie; 1551 static const char *flags = NULL; 1552 char *str = data->str; 1553 1554 if (flags == NULL) 1555 flags = msg_string(MSG_mbr_flags); 1556 1557 if (mp->mbrp_flag & MBR_PFLAG_ACTIVE) 1558 *str++ = flags[0]; 1559#ifdef BOOTSEL 1560 if (parts->mbr.bootsec == mb->sector+mp->mbrp_start) 1561 *str++ = flags[1]; 1562#endif 1563 *str = 0; 1564 return true; 1565} 1566 1567static bool 1568mbr_part_attr_str(const struct disk_partitions *arg, part_id id, 1569 char *str, size_t avail_space) 1570{ 1571 struct part_get_str_data data; 1572 1573 if (avail_space < 3) 1574 return false; 1575 1576 data.str = str; 1577 data.avail_space = avail_space; 1578 return mbr_part_apply(arg, id, mbr_get_part_attr_str, &data); 1579} 1580 1581static bool 1582mbr_info_to_partitition(const struct disk_part_info *info, 1583 struct mbr_partition *mp, uint sector, 1584 struct mbr_info_t *mb, size_t index, const char **err_msg) 1585{ 1586 size_t pt = mbr_type_from_gen_desc(info->nat_type); 1587 if (info->start + info->size > UINT_MAX 1588 || pt > __arraycount(mbr_gen_type_desc)) { 1589 if (err_msg) 1590 *err_msg = err_outofmem; 1591 return false; 1592 } 1593 mp->mbrp_start = info->start - sector; 1594 mp->mbrp_size = info->size; 1595 mp->mbrp_type = pt; 1596 if (info->flags & PTI_INSTALL_TARGET) { 1597 mp->mbrp_flag |= MBR_PFLAG_ACTIVE; 1598#ifdef BOOTSEL 1599 strcpy(mb->mbrb.mbrbs_nametab[index], "NetBSD"); 1600#endif 1601 } 1602 1603 return true; 1604} 1605 1606static bool 1607inside_ext_part(mbr_info_t *m, daddr_t start) 1608{ 1609 size_t i; 1610 struct mbr_partition *mp = NULL; 1611 1612 for (i = 0; i < MBR_PART_COUNT; i++) { 1613 if (!MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) 1614 continue; 1615 mp = &m->mbr.mbr_parts[i]; 1616 break; 1617 } 1618 1619 if (mp == NULL) { 1620 assert(false); 1621 return false; 1622 } 1623 1624 if (mp->mbrp_start > start) 1625 return false; 1626 1627 return true; 1628} 1629 1630static void 1631adjust_ext_part(mbr_info_t *m, daddr_t start, daddr_t size) 1632{ 1633 size_t i; 1634 struct mbr_partition *mp = NULL; 1635 1636 for (i = 0; i < MBR_PART_COUNT; i++) { 1637 if (!MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) 1638 continue; 1639 mp = &m->mbr.mbr_parts[i]; 1640 break; 1641 } 1642 1643 if (mp == NULL) { 1644 assert(false); 1645 return; 1646 } 1647 1648 if (mp->mbrp_start + mp->mbrp_size >= start + size) 1649 return; 1650 1651 daddr_t new_end = start + size; 1652 mp->mbrp_size = new_end - mp->mbrp_start; 1653} 1654 1655static bool 1656ext_part_good(mbr_info_t *m, daddr_t ext_start, daddr_t ext_size) 1657{ 1658 for (m = m->extended; m != NULL; m = m->extended) { 1659 for (size_t i = 0; i < MBR_PART_COUNT; i++) { 1660 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 1661 continue; 1662 1663 if (i > 0 && 1664 MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) 1665 break; 1666 1667 daddr_t pstart = m->mbr.mbr_parts[i].mbrp_start + 1668 m->sector; 1669 daddr_t pend = pstart + m->mbr.mbr_parts[i].mbrp_size; 1670 1671 if (pstart < ext_start || pend > ext_start+ext_size) 1672 return false; 1673 } 1674 } 1675 1676 return true; 1677} 1678 1679static bool 1680mbr_set_part_info(struct disk_partitions *arg, part_id id, 1681 const struct disk_part_info *info, const char **err_msg) 1682{ 1683 struct mbr_disk_partitions *parts = 1684 (struct mbr_disk_partitions*)arg; 1685 struct disk_part_info data = *info; 1686 part_id i, j, no, ext_ndx, t; 1687 mbr_info_t *m = &parts->mbr, *me; 1688 uint pt = mbr_type_from_gen_desc(info->nat_type); 1689 1690 if (MBR_IS_EXTENDED(pt)) { 1691 /* check for duplicate ext part */ 1692 no = 0; 1693 t = ext_ndx = MBR_PART_COUNT; 1694 for (i = 0; i < MBR_PART_COUNT; i++) { 1695 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 1696 continue; 1697 if (MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) 1698 ext_ndx = i; 1699 if (no == id) 1700 t = i; 1701 no++; 1702 } 1703 if (ext_ndx < MBR_PART_COUNT && t != ext_ndx) { 1704 if (err_msg) 1705 *err_msg = 1706 msg_string(MSG_Only_one_extended_ptn); 1707 return false; 1708 } 1709 /* this partition becomes an extended one, apply alignment */ 1710 data.start = max(roundup(data.start, parts->ext_ptn_alignment), 1711 parts->ext_ptn_alignment); 1712 } 1713 1714 no = 0; 1715 for (i = 0; i < MBR_PART_COUNT; i++) { 1716 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 1717 continue; 1718 1719 if (no == id) 1720 goto found; 1721 no++; 1722 1723 if (MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) { 1724 for (me = m->extended; me != NULL; me = me->extended) { 1725 for (j = 0; j < MBR_PART_COUNT; j++) { 1726 if (me->mbr.mbr_parts[j].mbrp_type == 1727 MBR_PTYPE_UNUSED) 1728 continue; 1729 if (j > 0 && MBR_IS_EXTENDED( 1730 me->mbr.mbr_parts[j].mbrp_type)) 1731 break; 1732 if (no == id) { 1733 i = j; 1734 m = me; 1735 goto found; 1736 } 1737 no++; 1738 } 1739 } 1740 } 1741 } 1742 1743 if (err_msg) 1744 *err_msg = INTERNAL_ERROR; 1745 return false; 1746 1747found: 1748 /* 1749 * We assume that m is the mbr we want to update and 1750 * i is the local partition index into it. 1751 */ 1752 if (m == &parts->mbr) { 1753 if (MBR_IS_EXTENDED( 1754 m->mbr.mbr_parts[i].mbrp_type) && 1755 !ext_part_good(&parts->mbr, data.start, data.size)) { 1756 if (err_msg) 1757 *err_msg = 1758 MSG_mbr_ext_nofit; 1759 return false; 1760 } 1761 } else if (!inside_ext_part(&parts->mbr, data.start)) { 1762 if (err_msg) 1763 *err_msg = msg_string(MSG_mbr_inside_ext); 1764 return false; 1765 } 1766 uint start = data.start, size = data.size; 1767 uint oldstart = m->mbr.mbr_parts[i].mbrp_start + m->sector; 1768 if (parts->ptn_0_offset > 0 && 1769 start < parts->ptn_0_offset) 1770 start = parts->ptn_0_offset; 1771 if (find_mbr_space(m, &start, &size, start, parts->dp.disk_size, 1772 oldstart, false) < 0) { 1773 if (err_msg != NULL) 1774 *err_msg = INTERNAL_ERROR; 1775 return false; 1776 } 1777 data.start = start; 1778 if (size < data.size) 1779 data.size = size; 1780 uint old_start = m->mbr.mbr_parts[i].mbrp_start; 1781 if (!mbr_info_to_partitition(&data, 1782 &m->mbr.mbr_parts[i], m->sector, m, i, err_msg)) 1783 return false; 1784 if (data.flags & PTI_INSTALL_TARGET) 1785 parts->target = start; 1786 else if (old_start == parts->target) 1787 parts->target = -1; 1788 if (data.last_mounted && m->last_mounted[i] && 1789 data.last_mounted != m->last_mounted[i]) { 1790 free(__UNCONST(m->last_mounted[i])); 1791 m->last_mounted[i] = strdup(data.last_mounted); 1792 } 1793 if (data.fs_type != 0) 1794 m->fs_type[i] = data.fs_type; 1795 if (data.fs_sub_type != 0) 1796 m->fs_sub_type[i] = data.fs_sub_type; 1797 1798 if (m == &parts->mbr) { 1799 if (m->mbr.mbr_parts[i].mbrp_start != 1800 old_start) 1801 mbr_sort_main_mbr(&m->mbr); 1802 } else { 1803 adjust_ext_part(&parts->mbr, 1804 data.start, data.size); 1805 } 1806 mbr_calc_free_space(parts); 1807 return true; 1808} 1809 1810static bool 1811mbr_find_netbsd(const struct mbr_info_t *m, uint start, 1812 struct disk_part_info *info) 1813{ 1814 size_t i; 1815 bool prim = true; 1816 1817 do { 1818 for (i = 0; i < MBR_PART_COUNT; i++) { 1819 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 1820 continue; 1821 1822 if (!prim && i > 0 && 1823 MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) 1824 break; 1825 1826 const struct mbr_partition *mp = &m->mbr.mbr_parts[i]; 1827 if (mp->mbrp_type != MBR_PTYPE_NETBSD) 1828 continue; 1829 1830 mbr_partition_to_info(mp, m->sector, info); 1831 if (m->last_mounted[i] && *m->last_mounted[i] != 0) 1832 info->last_mounted = 1833 m->last_mounted[i]; 1834 info->fs_type = m->fs_type[i]; 1835 info->fs_sub_type = m->fs_sub_type[i]; 1836 if (start > 0 && start != info->start) 1837 continue; 1838 return true; 1839 } 1840 prim = false; 1841 } while ((m = m->extended)); 1842 1843 return false; 1844} 1845 1846static struct disk_partitions * 1847mbr_read_disklabel(struct disk_partitions *arg, daddr_t start, bool force_empty) 1848{ 1849 struct mbr_disk_partitions *myparts = 1850 (struct mbr_disk_partitions*)arg; 1851 struct disk_part_info part; 1852 struct disk_part_free_space space; 1853 1854 if (force_empty && myparts->dlabel) 1855 myparts->dlabel->pscheme->delete_all_partitions( 1856 myparts->dlabel); 1857 1858 if (myparts->dlabel == NULL) { 1859 /* 1860 * Find the NetBSD MBR partition 1861 */ 1862 if (!mbr_find_netbsd(&myparts->mbr, start, &part)) { 1863 if (!force_empty) 1864 return NULL; 1865 1866 /* add a "whole disk" NetBSD partition */ 1867 memset(&part, 0, sizeof part); 1868 part.start = min(myparts->ptn_0_offset,start); 1869 if (!mbr_get_free_spaces(arg, &space, 1, 1870 part.start, myparts->ptn_alignment, -1, -1)) 1871 return NULL; 1872 part.start = space.start; 1873 part.size = space.size; 1874 part.nat_type = &mbr_gen_type_desc[MBR_PTYPE_NETBSD].gen; 1875 mbr_add_part(arg, &part, NULL); 1876 if (!mbr_find_netbsd(&myparts->mbr, start, &part)) 1877 return NULL; 1878 } 1879 1880 if (!force_empty) { 1881 myparts->dlabel = disklabel_parts.read_from_disk( 1882 myparts->dp.disk, part.start, part.size, 1883 myparts->dp.bytes_per_sector, &disklabel_parts); 1884 if (myparts->dlabel != NULL) 1885 myparts->dlabel->parent = &myparts->dp; 1886 } 1887 1888 if (myparts->dlabel == NULL && part.size > 0) { 1889 /* we just created the outer partitions? */ 1890 myparts->dlabel = 1891 disklabel_parts.create_new_for_disk( 1892 myparts->dp.disk, part.start, part.size, 1893 false, &myparts->dp); 1894 } 1895 1896 if (myparts->dlabel != NULL) 1897 myparts->dlabel->pscheme->change_disk_geom( 1898 myparts->dlabel, myparts->geo_cyl, 1899 myparts->geo_head, myparts->geo_sec); 1900 } 1901 return myparts->dlabel; 1902} 1903 1904static int 1905get_mapping(struct mbr_partition *parts, int i, 1906 int *cylinder, int *head, int *sector, daddr_t *absolute) 1907{ 1908 struct mbr_partition *apart = &parts[i / 2]; 1909 1910 if (apart->mbrp_type == MBR_PTYPE_UNUSED) 1911 return -1; 1912 if (i % 2 == 0) { 1913 *cylinder = MBR_PCYL(apart->mbrp_scyl, apart->mbrp_ssect); 1914 *head = apart->mbrp_shd; 1915 *sector = MBR_PSECT(apart->mbrp_ssect) - 1; 1916 *absolute = le32toh(apart->mbrp_start); 1917 } else { 1918 *cylinder = MBR_PCYL(apart->mbrp_ecyl, apart->mbrp_esect); 1919 *head = apart->mbrp_ehd; 1920 *sector = MBR_PSECT(apart->mbrp_esect) - 1; 1921 *absolute = le32toh(apart->mbrp_start) 1922 + le32toh(apart->mbrp_size) - 1; 1923 } 1924 /* Sanity check the data against max values */ 1925 if ((((*cylinder * MAXHEAD) + *head) * (uint32_t)MAXSECTOR + *sector) < *absolute) 1926 /* cannot be a CHS mapping */ 1927 return -1; 1928 1929 return 0; 1930} 1931 1932static bool 1933mbr_delete_all(struct disk_partitions *arg) 1934{ 1935 struct mbr_disk_partitions *myparts = (struct mbr_disk_partitions*)arg; 1936 struct mbr_sector *mbrs = &myparts->mbr.mbr; 1937 struct mbr_info_t *mbri = &myparts->mbr; 1938 mbr_info_t *ext; 1939 struct mbr_partition *part; 1940 1941 part = &mbrs->mbr_parts[0]; 1942 /* Set the partition information for full disk usage. */ 1943 while ((ext = mbri->extended)) { 1944 mbri->extended = ext->extended; 1945 free_mbr_info(ext); 1946 } 1947 memset(part, 0, MBR_PART_COUNT * sizeof *part); 1948#ifdef BOOTSEL 1949 memset(&mbri->mbrb, 0, sizeof mbri->mbrb); 1950#endif 1951 1952 /* 1953 * We may have changed alignment settings due to partitions 1954 * ending on an MB boundary - undo that, now that the partitions 1955 * are gone. 1956 */ 1957 mbr_change_disk_geom(arg, myparts->geo_cyl, myparts->geo_head, 1958 myparts->geo_sec); 1959 1960 return true; 1961} 1962 1963/* 1964 * helper function to fix up mbrp_start and mbrp_size for the 1965 * extended MBRs "partition b" entries after addition/deletion 1966 * of some partition. 1967 */ 1968static void 1969mbr_fixup_ext_chain(mbr_info_t *primary, uint ext_start, uint ext_end) 1970{ 1971 for (mbr_info_t *m = primary->extended; m != NULL; m = m->extended) { 1972 if (m->extended == NULL) { 1973 m->mbr.mbr_parts[1].mbrp_type = MBR_PTYPE_UNUSED; 1974 m->mbr.mbr_parts[1].mbrp_start = 0; 1975 m->mbr.mbr_parts[1].mbrp_size = 0; 1976 } else { 1977 uint n_end, n_start = m->extended->sector; 1978 if (m->extended->extended) 1979 n_end = m->extended->extended->sector; 1980 else 1981 n_end = ext_end; 1982 m->mbr.mbr_parts[1].mbrp_type = MBR_PTYPE_EXT; 1983 m->mbr.mbr_parts[1].mbrp_start = n_start - ext_start; 1984 m->mbr.mbr_parts[1].mbrp_size = n_end - n_start; 1985 } 1986 } 1987} 1988 1989struct delete_part_args { 1990 struct mbr_disk_partitions *parts; 1991 daddr_t start, size; 1992 const char **err_msg; 1993}; 1994 1995static bool 1996mbr_do_delete_part(const struct disk_partitions *arg, part_id id, 1997 const mbr_info_t *mb, int i, bool primary, 1998 const struct mbr_partition *mp, void *cookie) 1999{ 2000 struct delete_part_args *marg = cookie; 2001 bool is_ext_part = MBR_IS_EXTENDED(mp->mbrp_type); 2002 2003 /* can not delete non-empty extended partitions */ 2004 if (MBR_IS_EXTENDED(mp->mbrp_type) 2005 && marg->parts->mbr.extended != NULL) { 2006 if (marg->err_msg) 2007 *marg->err_msg = msg_string(MSG_mbr_ext_not_empty); 2008 return false; 2009 } 2010 2011 /* return position/size to caller */ 2012 marg->start = mb->sector + mp->mbrp_start; 2013 marg->size = mp->mbrp_size; 2014 2015 if (primary) { 2016 /* if deleting the primary extended partition, just kill it */ 2017 struct mbr_partition *md = &marg->parts->mbr.mbr.mbr_parts[i]; 2018 md->mbrp_size = 0; 2019 md->mbrp_start = 0; 2020 md->mbrp_type = MBR_PTYPE_UNUSED; 2021 if (marg->parts->mbr.last_mounted[i]) { 2022 free(__UNCONST(marg->parts->mbr.last_mounted[i])); 2023 marg->parts->mbr.last_mounted[i] = NULL; 2024 } 2025 if (is_ext_part) { 2026 for (mbr_info_t *m = marg->parts->mbr.extended; 2027 m != NULL; ) { 2028 mbr_info_t *n = m->extended; 2029 free_mbr_info(m); 2030 m = n; 2031 } 2032 marg->parts->mbr.extended = NULL; 2033 } 2034 } else { 2035 /* find the size of the primary extended partition */ 2036 uint ext_start = 0, ext_size = 0; 2037 for (i = 0; i < MBR_PART_COUNT; i++) { 2038 if (!MBR_IS_EXTENDED(marg->parts->mbr.mbr.mbr_parts[i] 2039 .mbrp_type)) 2040 continue; 2041 ext_start = marg->parts->mbr.mbr.mbr_parts[i] 2042 .mbrp_start; 2043 ext_size = marg->parts->mbr.mbr.mbr_parts[i] 2044 .mbrp_size; 2045 break; 2046 } 2047 2048 /* 2049 * If we are in an extended partition chain, unlink this MBR, 2050 * unless it is the very first one at the start of the extended 2051 * partition (we would have no previous ext mbr to fix up 2052 * the chain in that case) 2053 */ 2054 if (marg->parts->mbr.extended == mb) { 2055 struct mbr_partition *part = 2056 &marg->parts->mbr.extended->mbr.mbr_parts[0]; 2057 part->mbrp_type = MBR_PTYPE_UNUSED; 2058 part->mbrp_start = 0; 2059 part->mbrp_size = 0; 2060 } else { 2061 mbr_info_t *p, *last; 2062 for (last = NULL, p = &marg->parts->mbr; p != NULL; 2063 last = p, p = p->extended) 2064 if (p == mb) 2065 break; 2066 if (last == NULL) { 2067 if (marg->err_msg != NULL) 2068 *marg->err_msg= INTERNAL_ERROR; 2069 return false; 2070 } 2071 last->extended = p->extended; 2072 free_mbr_info(p); 2073 if (last == &marg->parts->mbr && last->extended && 2074 last->extended->extended == NULL && 2075 last->extended->mbr.mbr_parts[0].mbrp_type == 2076 MBR_PTYPE_UNUSED) { 2077 /* 2078 * we deleted the last extended sector, 2079 * remove the whole chain 2080 */ 2081 free_mbr_info(last->extended); 2082 last->extended = NULL; 2083 } 2084 } 2085 mbr_fixup_ext_chain(&marg->parts->mbr, ext_start, 2086 ext_start+ext_size); 2087 } 2088 mbr_calc_free_space(marg->parts); 2089 return true; 2090} 2091 2092static bool 2093mbr_delete_part(struct disk_partitions *arg, part_id pno, const char **err_msg) 2094{ 2095 struct mbr_disk_partitions *parts = 2096 (struct mbr_disk_partitions*)arg; 2097 struct delete_part_args data = { .parts = parts, .err_msg = err_msg }; 2098 2099 if (!mbr_part_apply(arg, pno, mbr_do_delete_part, &data)) { 2100 if (err_msg) 2101 *err_msg = INTERNAL_ERROR; 2102 return false; 2103 } 2104 2105 if (parts->target == data.start) 2106 parts->target = ~0U; 2107 2108 if (parts->dlabel) { 2109 /* 2110 * If we change the mbr partitioning, the we must 2111 * remove any references in the netbsd disklabel 2112 * to the part we changed. 2113 */ 2114 parts->dlabel->pscheme->delete_partitions_in_range( 2115 parts->dlabel, data.start, data.size); 2116 } 2117 2118 if (err_msg) 2119 *err_msg = NULL; 2120 2121 dump_mbr(&parts->mbr, "after delete"); 2122 return true; 2123} 2124 2125static struct mbr_partition * 2126mbr_ptr_from_start(mbr_info_t *m, daddr_t start) 2127{ 2128 bool primary = true; 2129 2130 do { 2131 for (uint i = 0; i < MBR_PART_COUNT; i++) { 2132 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 2133 continue; 2134 if (!primary && 2135 MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) 2136 break; 2137 2138 daddr_t pstart = m->sector + 2139 m->mbr.mbr_parts[i].mbrp_start; 2140 if (pstart == start) 2141 return &m->mbr.mbr_parts[i]; 2142 2143 } 2144 primary = false; 2145 } while ((m = m->extended)); 2146 2147 return NULL; 2148} 2149 2150static uint8_t 2151mbr_type_from_start(const mbr_info_t *m, daddr_t start) 2152{ 2153 bool primary = true; 2154 2155 do { 2156 for (uint i = 0; i < MBR_PART_COUNT; i++) { 2157 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 2158 continue; 2159 if (!primary && 2160 MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) 2161 break; 2162 2163 daddr_t pstart = m->sector + 2164 m->mbr.mbr_parts[i].mbrp_start; 2165 if (pstart == start) 2166 return m->mbr.mbr_parts[i].mbrp_type; 2167 2168 } 2169 primary = false; 2170 } while ((m = m->extended)); 2171 2172 return MBR_PTYPE_UNUSED; 2173} 2174 2175static part_id 2176mbr_add_part(struct disk_partitions *arg, 2177 const struct disk_part_info *info, const char **errmsg) 2178{ 2179 struct mbr_disk_partitions *parts = 2180 (struct mbr_disk_partitions*)arg; 2181 part_id i, j, no, free_primary = UINT_MAX; 2182 mbr_info_t *m = &parts->mbr, *me, *last, *t; 2183 daddr_t ext_start = 0, ext_size = 0; 2184 uint start, size; 2185 struct disk_part_info data = *info; 2186 struct mbr_partition *newp; 2187 2188 if (errmsg != NULL) 2189 *errmsg = NULL; 2190 2191 assert(info->nat_type != NULL); 2192 if (info->nat_type == NULL) { 2193 if (errmsg != NULL) 2194 *errmsg = INTERNAL_ERROR; 2195 return NO_PART; 2196 } 2197 if (mbr_type_from_gen_desc(info->nat_type) == MBR_PTYPE_UNUSED) { 2198 if (errmsg != NULL) 2199 *errmsg = INTERNAL_ERROR; 2200 return NO_PART; 2201 } 2202 2203 /* do we have free primary slots and/or an extended partition? */ 2204 for (i = 0; i < MBR_PART_COUNT; i++) { 2205 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED 2206 && free_primary > MBR_PART_COUNT) 2207 free_primary = i; 2208 if (MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) { 2209 ext_start = m->mbr.mbr_parts[i].mbrp_start+m->sector; 2210 ext_size = m->mbr.mbr_parts[i].mbrp_size; 2211 continue; 2212 } 2213 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED 2214 && m->mbr.mbr_parts[i].mbrp_size == 0) 2215 continue; 2216 } 2217 if (ext_start > 0 && ext_size > 0 && 2218 MBR_IS_EXTENDED(mbr_type_from_gen_desc(info->nat_type))) { 2219 /* 2220 * Do not allow a second extended partition 2221 */ 2222 if (errmsg) 2223 *errmsg = MSG_Only_one_extended_ptn; 2224 return NO_PART; 2225 } 2226 2227 /* should this go into the extended partition? */ 2228 if (ext_size > 0 && info->start >= ext_start 2229 && info->start < ext_start + ext_size) { 2230 2231 /* must fit into the extended partition */ 2232 if (info->start + info->size > ext_start + ext_size) { 2233 if (errmsg != NULL) 2234 *errmsg = MSG_mbr_ext_nofit; 2235 return NO_PART; 2236 } 2237 2238 /* walk the chain untill we find a proper insert position */ 2239 daddr_t e_end, e_start; 2240 for (last = m, m = m->extended; m != NULL; 2241 last = m, m = m->extended) { 2242 e_start = m->mbr.mbr_parts[1].mbrp_start 2243 + ext_start; 2244 e_end = e_start + m->mbr.mbr_parts[1].mbrp_size; 2245 if (data.start <= e_start) 2246 break; 2247 } 2248 if (m == NULL) { 2249 /* add new tail record */ 2250 e_end = ext_start + ext_size; 2251 /* new part needs to fit inside primary extended one */ 2252 if (data.start + data.size > e_end) { 2253 if (errmsg) 2254 *errmsg = MSG_No_free_space; 2255 return NO_PART; 2256 } 2257 } else if (data.start + data.size > e_start) { 2258 /* new part needs to fit before next extended */ 2259 if (errmsg) 2260 *errmsg = MSG_No_free_space; 2261 return NO_PART; 2262 } 2263 /* 2264 * now last points to previous mbr (maybe primary), m 2265 * points to the one that should take the new partition 2266 * or we have to insert a new mbr between the two, or 2267 * m needs to be split and we go into the one after it. 2268 */ 2269 if (m && m->mbr.mbr_parts[0].mbrp_type == MBR_PTYPE_UNUSED) { 2270 /* empty slot, we can just use it */ 2271 newp = &m->mbr.mbr_parts[0]; 2272 mbr_info_to_partitition(&data, &m->mbr.mbr_parts[0], 2273 m->sector, m, 0, errmsg); 2274 if (data.last_mounted && m->last_mounted[0] && 2275 data.last_mounted != m->last_mounted[0]) { 2276 free(__UNCONST(m->last_mounted[0])); 2277 m->last_mounted[0] = strdup(data.last_mounted); 2278 } 2279 } else { 2280 mbr_info_t *new_mbr; 2281 if (m == NULL) 2282 m = last; 2283 daddr_t p_start = m->mbr.mbr_parts[0].mbrp_start 2284 + m->sector; 2285 daddr_t p_end = p_start 2286 + m->mbr.mbr_parts[0].mbrp_size; 2287 bool before; 2288 if (m == last || data.start > p_end) 2289 before = false; 2290 else if (data.start + data.size < p_start) 2291 before = true; 2292 else { 2293 if (errmsg) 2294 *errmsg = MSG_No_free_space; 2295 return NO_PART; 2296 } 2297 new_mbr = calloc(1, sizeof *new_mbr); 2298 if (!new_mbr) { 2299 if (errmsg) 2300 *errmsg = err_outofmem; 2301 return NO_PART; 2302 } 2303 new_mbr->mbr.mbr_magic = htole16(MBR_MAGIC); 2304 new_mbr->mbr.mbr_parts[1].mbrp_type = MBR_PTYPE_EXT; 2305 if (before) { 2306 /* 2307 * This is a hypthetical case where 2308 * an extended MBR uses an unusual high 2309 * offset (m->sector to parts[0].mbrp_start) 2310 * and we want to go into that space. 2311 * Should not happen in the real world (tm) 2312 * and is untested.... 2313 */ 2314 2315 /* make sure the aligned new mbr fits */ 2316 uint mbrsec = rounddown(p_start, 2317 parts->ext_ptn_alignment); 2318 if (mbrsec <= data.start + data.size) 2319 data.size = mbrsec-1-data.start; 2320 2321 /* now the new partition data is ready, 2322 * write out to old position */ 2323 new_mbr->sector = m->sector; 2324 newp = &new_mbr->mbr.mbr_parts[0]; 2325 mbr_info_to_partitition(&data, 2326 &new_mbr->mbr.mbr_parts[0], 2327 new_mbr->sector, new_mbr, 0, errmsg); 2328 if (data.last_mounted && m->last_mounted[0] && 2329 data.last_mounted != m->last_mounted[0]) { 2330 free(__UNCONST(m->last_mounted[0])); 2331 m->last_mounted[0] = 2332 strdup(data.last_mounted); 2333 } 2334 new_mbr->extended = m; 2335 } else { 2336 new_mbr->sector = max(roundup(data.start, 2337 parts->ext_ptn_alignment), 2338 parts->ext_ptn_alignment); 2339 uint off = new_mbr->sector - data.start; 2340 data.start += parts->ptn_0_offset+off; 2341 if (data.start + data.size > e_end) 2342 data.size = e_end - data.start; 2343 newp = &new_mbr->mbr.mbr_parts[0]; 2344 mbr_info_to_partitition(&data, 2345 &new_mbr->mbr.mbr_parts[0], 2346 new_mbr->sector, new_mbr, 0, errmsg); 2347 if (data.last_mounted && m->last_mounted[0] && 2348 data.last_mounted != m->last_mounted[0]) { 2349 free(__UNCONST(m->last_mounted[0])); 2350 m->last_mounted[0] = 2351 strdup(data.last_mounted); 2352 } 2353 /* 2354 * Special case: if we are creating the 2355 * first extended mbr, but do not start 2356 * at the beginning of the primary 2357 * extended partition, we need to insert 2358 * another extended mbr at the start. 2359 */ 2360 if (m == &parts->mbr && m->extended == NULL 2361 && new_mbr->sector > ext_start) { 2362 t = calloc(1, sizeof *new_mbr); 2363 if (!t) { 2364 free_mbr_info(new_mbr); 2365 if (errmsg) 2366 *errmsg = err_outofmem; 2367 return NO_PART; 2368 } 2369 t->sector = ext_start; 2370 t->mbr.mbr_magic = htole16(MBR_MAGIC); 2371 t->mbr.mbr_parts[1].mbrp_type = 2372 MBR_PTYPE_EXT; 2373 m->extended = t; 2374 m = t; 2375 } 2376 new_mbr->extended = m->extended; 2377 m->extended = new_mbr; 2378 } 2379 } 2380 mbr_fixup_ext_chain(&parts->mbr, ext_start, ext_start+ext_size); 2381 dump_mbr(&parts->mbr, "after adding in extended"); 2382 goto find_rval; 2383 } 2384 2385 /* this one is for the primary boot block */ 2386 if (free_primary > MBR_PART_COUNT) { 2387 if (errmsg != NULL) 2388 *errmsg = ext_size > 0 ? 2389 MSG_mbr_no_free_primary_have_ext 2390 : MSG_mbr_no_free_primary_no_ext; 2391 return NO_PART; 2392 } 2393 2394 start = max(info->start, parts->ptn_0_offset); 2395 size = info->size; 2396 if (find_mbr_space(m, &start, &size, start, parts->dp.disk_size, 2397 start, true) < 0 || size < info->size) { 2398 if (errmsg != NULL) 2399 *errmsg = MSG_No_free_space; 2400 return NO_PART; 2401 } 2402 data.start = start; 2403 if (MBR_IS_EXTENDED(mbr_type_from_gen_desc(info->nat_type))) { 2404 data.start = max(roundup(data.start, parts->ext_ptn_alignment), 2405 parts->ext_ptn_alignment); 2406 } 2407 if (data.start + data.size > start + size) 2408 data.size = start + size - data.start; 2409 mbr_info_to_partitition(&data, &m->mbr.mbr_parts[free_primary], 2410 m->sector, m, free_primary, errmsg); 2411 if (data.last_mounted && m->last_mounted[free_primary] && 2412 data.last_mounted != m->last_mounted[free_primary]) { 2413 free(__UNCONST(m->last_mounted[free_primary])); 2414 m->last_mounted[free_primary] = strdup(data.last_mounted); 2415 } 2416 start = m->mbr.mbr_parts[free_primary].mbrp_start; 2417 mbr_sort_main_mbr(&m->mbr); 2418 2419 /* find the partition again after sorting */ 2420 newp = NULL; 2421 for (i = 0; i < MBR_PART_COUNT; i++) { 2422 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 2423 continue; 2424 if (m->mbr.mbr_parts[i].mbrp_start != start) 2425 continue; 2426 newp = &m->mbr.mbr_parts[i]; 2427 break; 2428 } 2429 2430 dump_mbr(&parts->mbr, "after adding in primary"); 2431 2432find_rval: 2433 mbr_calc_free_space(parts); 2434 if (newp == NULL) 2435 return 0; 2436 2437 /* 2438 * Now newp points to the modified partition entry but we do not know 2439 * a good part_id for it. 2440 * Iterate from start and find it. 2441 */ 2442 no = 0; 2443 for (i = 0; i < MBR_PART_COUNT; i++) { 2444 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 2445 continue; 2446 2447 if (newp == &m->mbr.mbr_parts[i]) 2448 return no; 2449 no++; 2450 2451 if (MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) { 2452 for (me = m->extended; me != NULL; me = me->extended) { 2453 for (j = 0; j < MBR_PART_COUNT; j++) { 2454 if (me->mbr.mbr_parts[j].mbrp_type == 2455 MBR_PTYPE_UNUSED) 2456 continue; 2457 if (j > 0 && MBR_IS_EXTENDED( 2458 me->mbr.mbr_parts[j].mbrp_type)) 2459 break; 2460 if (newp == &me->mbr.mbr_parts[j]) 2461 return no; 2462 no++; 2463 } 2464 } 2465 } 2466 } 2467 return 0; 2468} 2469 2470static int 2471mbr_guess_geom(struct disk_partitions *arg, int *cyl, int *head, int *sec) 2472{ 2473 struct mbr_disk_partitions *myparts = (struct mbr_disk_partitions*)arg; 2474 struct mbr_sector *mbrs = &myparts->mbr.mbr; 2475 struct mbr_partition *parts = &mbrs->mbr_parts[0]; 2476 int xcylinders, xheads, i, j; 2477 daddr_t xsectors, xsize; 2478 int c1, h1, s1, c2, h2, s2; 2479 daddr_t a1, a2; 2480 uint64_t num, denom; 2481 2482 xheads = -1; 2483 2484 /* Try to deduce the number of heads from two different mappings. */ 2485 for (i = 0; i < MBR_PART_COUNT * 2 - 1; i++) { 2486 if (get_mapping(parts, i, &c1, &h1, &s1, &a1) < 0) 2487 continue; 2488 a1 -= s1; 2489 for (j = i + 1; j < MBR_PART_COUNT * 2; j++) { 2490 if (get_mapping(parts, j, &c2, &h2, &s2, &a2) < 0) 2491 continue; 2492 a2 -= s2; 2493 num = (uint64_t)h1 * a2 - (quad_t)h2 * a1; 2494 denom = (uint64_t)c2 * a1 - (quad_t)c1 * a2; 2495 if (num != 0 && denom != 0 && num % denom == 0) { 2496 xheads = (int)(num / denom); 2497 xsectors = a1 / (c1 * xheads + h1); 2498 break; 2499 } 2500 } 2501 if (xheads != -1) 2502 break; 2503 } 2504 2505 if (xheads == -1) 2506 return -1; 2507 2508 /* 2509 * Estimate the number of cylinders. 2510 * XXX relies on get_disks having been called. 2511 */ 2512 xsize = min(pm->dlsize, mbr_parts.size_limit); 2513 xcylinders = xsize / xheads / xsectors; 2514 if (xsize != xcylinders * xheads * xsectors) 2515 xcylinders++; 2516 2517 /* 2518 * Now verify consistency with each of the partition table entries. 2519 * Be willing to shove cylinders up a little bit to make things work, 2520 * but translation mismatches are fatal. 2521 */ 2522 for (i = 0; i < MBR_PART_COUNT * 2; i++) { 2523 if (get_mapping(parts, i, &c1, &h1, &s1, &a1) < 0) 2524 continue; 2525 if (c1 >= MAXCYL - 1) 2526 /* Ignore anything that is near the CHS limit */ 2527 continue; 2528 if (xsectors * (c1 * xheads + h1) + s1 != a1) 2529 return -1; 2530 } 2531 2532 /* 2533 * Everything checks out. Reset the geometry to use for further 2534 * calculations. 2535 */ 2536 *cyl = MIN(xcylinders, MAXCYL); 2537 *head = xheads; 2538 *sec = xsectors; 2539 return 0; 2540} 2541 2542static size_t 2543mbr_get_cylinder(const struct disk_partitions *arg) 2544{ 2545 const struct mbr_disk_partitions *parts = 2546 (const struct mbr_disk_partitions*)arg; 2547 2548 return parts->geo_cyl; 2549} 2550 2551static daddr_t 2552mbr_max_part_size(const struct disk_partitions *arg, daddr_t fp_start) 2553{ 2554 const struct mbr_disk_partitions *parts = 2555 (const struct mbr_disk_partitions*)arg; 2556 uint start = fp_start, size = 0; 2557 uint8_t pt; 2558 2559 start = fp_start; 2560 pt = mbr_type_from_start(&parts->mbr, start); 2561 if (find_mbr_space(&parts->mbr, &start, &size, start, 2562 parts->dp.disk_size, start, MBR_IS_EXTENDED(pt)) < 0) 2563 return 0; 2564 2565 return size; 2566} 2567 2568static size_t 2569mbr_get_free_spaces(const struct disk_partitions *arg, 2570 struct disk_part_free_space *result, size_t max_num_result, 2571 daddr_t min_size, daddr_t align, daddr_t lower_bound, daddr_t ignore) 2572{ 2573 const struct mbr_disk_partitions *parts = 2574 (const struct mbr_disk_partitions*)arg; 2575 uint start = 0, size = 0, from, next; 2576 size_t spaces = 0; 2577 2578 if (min_size < 1) 2579 min_size = 1; 2580 from = parts->ptn_0_offset; 2581 if (lower_bound > from) 2582 from = lower_bound; 2583 for ( ; from < parts->dp.disk_size && spaces < max_num_result; ) { 2584 if (find_mbr_space(&parts->mbr, &start, &size, from, 2585 parts->dp.disk_size, ignore > 0 ? (uint)ignore : UINT_MAX, 2586 false) < 0) 2587 break; 2588 next = start + size + 1; 2589 if (align > 0) { 2590 uint nv = max(roundup(start, align), align); 2591 uint off = nv - start; 2592 start = nv; 2593 if (size > off) 2594 size -= off; 2595 else 2596 size = 0; 2597 } 2598 if (size > min_size) { 2599 result[spaces].start = start; 2600 result[spaces].size = size; 2601 spaces++; 2602 } 2603 if ((daddr_t)start + (daddr_t)size + 1 >= mbr_parts.size_limit) 2604 break; 2605 from = next; 2606 } 2607 2608 return spaces; 2609} 2610 2611static bool 2612mbr_can_add_partition(const struct disk_partitions *arg) 2613{ 2614 const struct mbr_disk_partitions *myparts = 2615 (const struct mbr_disk_partitions*)arg; 2616 struct disk_part_free_space space; 2617 bool free_primary, have_extended; 2618 2619 if (arg->free_space < myparts->ptn_alignment) 2620 return false; 2621 2622 if (mbr_get_free_spaces(arg, &space, 1, myparts->ptn_alignment, 2623 myparts->ptn_alignment, 0, -1) < 1) 2624 return false; 2625 2626 for (int i = 0; i < MBR_PART_COUNT; i++) { 2627 uint8_t t = myparts->mbr.mbr.mbr_parts[i].mbrp_type; 2628 2629 if (t == MBR_PTYPE_UNUSED && 2630 myparts->mbr.mbr.mbr_parts[i].mbrp_size == 0) 2631 free_primary = true; 2632 2633 if (MBR_IS_EXTENDED(t)) 2634 have_extended = true; 2635 } 2636 2637 if (have_extended) 2638 return true; 2639 2640 return free_primary; 2641} 2642 2643static void 2644mbr_free_wedge(int *fd, const char *disk, const char *wedge) 2645{ 2646 struct dkwedge_info dkw; 2647 char diskpath[MAXPATHLEN]; 2648 2649 if (*fd == -1) 2650 *fd = opendisk(disk, O_RDWR, diskpath, 2651 sizeof(diskpath), 0); 2652 if (*fd != -1) { 2653 memset(&dkw, 0, sizeof(dkw)); 2654 strlcpy(dkw.dkw_devname, wedge, 2655 sizeof(dkw.dkw_devname)); 2656 ioctl(*fd, DIOCDWEDGE, &dkw); 2657 } 2658} 2659 2660static void 2661mbr_free(struct disk_partitions *arg) 2662{ 2663 struct mbr_disk_partitions *parts = (struct mbr_disk_partitions*)arg; 2664 mbr_info_t *m; 2665 int i, fd; 2666 2667 assert(parts != NULL); 2668 2669 fd = -1; 2670 m = &parts->mbr; 2671 do { 2672 for (i = 0; i < MBR_PART_COUNT; i++) { 2673 if (m->wedge[i][0] != 0) 2674 mbr_free_wedge(&fd, arg->disk, m->wedge[i]); 2675 } 2676 } while ((m = m->extended)); 2677 2678 if (fd != -1) 2679 close(fd); 2680 2681 if (parts->dlabel) 2682 parts->dlabel->pscheme->free(parts->dlabel); 2683 2684 free_mbr_info(parts->mbr.extended); 2685 free_last_mounted(&parts->mbr); 2686 free(__UNCONST(parts->dp.disk)); 2687 free(parts); 2688} 2689 2690static void 2691mbr_destroy_part_scheme(struct disk_partitions *arg) 2692{ 2693 struct mbr_disk_partitions *parts = (struct mbr_disk_partitions*)arg; 2694 char diskpath[MAXPATHLEN]; 2695 int fd; 2696 2697 if (parts->dlabel != NULL) 2698 parts->dlabel->pscheme->destroy_part_scheme(parts->dlabel); 2699 fd = opendisk(arg->disk, O_RDWR, diskpath, sizeof(diskpath), 0); 2700 if (fd != -1) { 2701 char *buf; 2702 2703 buf = calloc(arg->bytes_per_sector, 1); 2704 if (buf != NULL) { 2705 write(fd, buf, arg->bytes_per_sector); 2706 free(buf); 2707 } 2708 close(fd); 2709 } 2710 mbr_free(arg); 2711} 2712 2713static bool 2714mbr_verify_for_update(struct disk_partitions *arg) 2715{ 2716 struct mbr_disk_partitions *parts = 2717 (struct mbr_disk_partitions*)arg; 2718 2719 return md_mbr_update_check(arg, &parts->mbr); 2720} 2721 2722static int 2723mbr_verify(struct disk_partitions *arg, bool quiet) 2724{ 2725 struct mbr_disk_partitions *parts = 2726 (struct mbr_disk_partitions*)arg; 2727 mbr_info_t *m = &parts->mbr; 2728 int i; 2729 bool active_found = false; 2730 2731 for (i = 0; i < MBR_PART_COUNT; i++) { 2732 if (m->mbr.mbr_parts[i].mbrp_flag & MBR_PFLAG_ACTIVE) { 2733 active_found = true; 2734 break; 2735 } 2736 } 2737 2738 if (!active_found && pm->ptstart > 0) { 2739 struct mbr_partition *mp = mbr_ptr_from_start(m, pm->ptstart); 2740 2741 if (mp) { 2742 if (!quiet) 2743 msg_display(MSG_noactivepart); 2744 if (quiet || ask_yesno(MSG_fixactivepart)) { 2745 mp->mbrp_flag |= MBR_PFLAG_ACTIVE; 2746 active_found = true; 2747 } 2748 } 2749 } 2750 if (!active_found && !quiet) { 2751 msg_display(MSG_noactivepart); 2752 i = ask_reedit(arg); 2753 if (i <= 1) 2754 return i; 2755 } 2756 2757 for (i = 0; i < MBR_PART_COUNT; i++) { 2758 if (m->mbr.mbr_parts[i].mbrp_type != MBR_PTYPE_NETBSD) 2759 continue; 2760 m->mbr.mbr_parts[i].mbrp_flag |= MBR_PFLAG_ACTIVE; 2761 break; 2762 } 2763 2764 return md_check_mbr(arg, &parts->mbr, quiet); 2765} 2766 2767static bool 2768mbr_guess_root(const struct disk_partitions *arg, 2769 daddr_t *start, daddr_t *size) 2770{ 2771 const struct mbr_disk_partitions *parts = 2772 (const struct mbr_disk_partitions*)arg; 2773 const mbr_info_t *m = &parts->mbr; 2774 size_t i, num_found; 2775 bool prim = true; 2776 daddr_t pstart, psize; 2777 2778 num_found = 0; 2779 do { 2780 for (i = 0; i < MBR_PART_COUNT; i++) { 2781 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 2782 continue; 2783 2784 if (!prim && i > 0 && 2785 MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) 2786 break; 2787 2788 const struct mbr_partition *mp = &m->mbr.mbr_parts[i]; 2789 if (mp->mbrp_type != MBR_PTYPE_NETBSD) 2790 continue; 2791 2792 if (num_found == 0) { 2793 pstart = m->sector + mp->mbrp_start; 2794 psize = mp->mbrp_size; 2795 } 2796 num_found++; 2797 2798 if (m->last_mounted[i] != NULL && 2799 strcmp(m->last_mounted[i], "/") == 0) { 2800 *start = pstart; 2801 *size = psize; 2802 return true; 2803 } 2804 } 2805 prim = false; 2806 } while ((m = m->extended)); 2807 2808 if (num_found == 1) { 2809 *start = pstart; 2810 *size = psize; 2811 return true; 2812 } 2813 2814 return false; 2815} 2816 2817struct part_attr_fmt_data { 2818 char *str; 2819 size_t avail_space, attr_no; 2820 const struct mbr_disk_partitions *parts; 2821 const struct disk_part_info *info; 2822}; 2823 2824struct part_attr_set_data { 2825 size_t attr_no; 2826 const struct mbr_disk_partitions *parts; 2827 const char *str; 2828 mbr_info_t *mbr; 2829}; 2830 2831static bool 2832part_attr_format_str(const struct disk_partitions *arg, part_id id, 2833 const mbr_info_t *mb, int i, bool primary, 2834 const struct mbr_partition *mp, void *cookie) 2835{ 2836 const struct mbr_disk_partitions *parts = 2837 (const struct mbr_disk_partitions*)arg; 2838 struct part_attr_fmt_data *data = cookie; 2839 const char *attrtype = parts->dp.pscheme 2840 ->custom_attributes[data->attr_no].label; 2841 2842 if (attrtype == MSG_ptn_active) { 2843 strlcpy(data->str, 2844 msg_string(primary && (mp->mbrp_flag & MBR_PFLAG_ACTIVE) ? 2845 MSG_Yes : MSG_No), data->avail_space); 2846 return true; 2847#if BOOTSEL 2848 } else if (attrtype == MSG_boot_dflt) { 2849 strlcpy(data->str, 2850 msg_string( 2851 (parts->mbr.bootsec == mb->sector+mp->mbrp_start) ? 2852 MSG_Yes : MSG_No), data->avail_space); 2853 return true; 2854 } else if (attrtype == MSG_bootmenu) { 2855 strlcpy(data->str, mb->mbrb.mbrbs_nametab[i], 2856 data->avail_space); 2857#endif 2858 } 2859 2860 return false; 2861} 2862 2863static bool 2864part_attr_set_str(const struct disk_partitions *arg, part_id id, 2865 const mbr_info_t *mb, int i, bool primary, 2866 const struct mbr_partition *mp, void *cookie) 2867{ 2868 struct part_attr_set_data *data = cookie; 2869 const char *str = data->str; 2870#ifdef BOOTSEL 2871 const struct mbr_disk_partitions *parts = 2872 (const struct mbr_disk_partitions*)arg; 2873 const char *attrtype = parts->dp.pscheme 2874 ->custom_attributes[data->attr_no].label; 2875 mbr_info_t *m; 2876#endif 2877 2878 while (*str == ' ') 2879 str++; 2880 2881#if BOOTSEL 2882 if (attrtype == MSG_bootmenu) { 2883 for (m = data->mbr; m != mb; m = m->extended) 2884 ; 2885 strncpy(m->mbrb.mbrbs_nametab[i], str, 2886 sizeof(m->mbrb.mbrbs_nametab[i])); 2887 } 2888#endif 2889 2890 return false; 2891} 2892 2893static bool 2894part_attr_toggle(const struct disk_partitions *arg, part_id id, 2895 const mbr_info_t *mb, int i, bool primary, 2896 const struct mbr_partition *mp, void *cookie) 2897{ 2898 const struct mbr_disk_partitions *parts = 2899 (const struct mbr_disk_partitions*)arg; 2900 struct part_attr_set_data *data = cookie; 2901 const char *attrtype = parts->dp.pscheme 2902 ->custom_attributes[data->attr_no].label; 2903 int j; 2904 2905 if (attrtype == MSG_ptn_active) { 2906 if (!primary) 2907 return false; 2908 2909 data->mbr->mbr.mbr_parts[i].mbrp_flag ^= MBR_PFLAG_ACTIVE; 2910 for (j = 0; j < MBR_PART_COUNT; j++) { 2911 if (j == i) 2912 continue; 2913 data->mbr->mbr.mbr_parts[j].mbrp_flag 2914 &= ~MBR_PFLAG_ACTIVE; 2915 } 2916 return true; 2917#ifdef BOOTSEL 2918 } else if (attrtype == MSG_boot_dflt) { 2919 if (data->mbr->bootsec == mb->sector+mp->mbrp_start) 2920 data->mbr->bootsec = 0; 2921 else 2922 data->mbr->bootsec = mb->sector+mp->mbrp_start; 2923 return true; 2924#endif 2925 } 2926 2927 return false; 2928} 2929 2930static bool 2931mbr_custom_attribute_format(const struct disk_partitions *arg, 2932 part_id id, size_t attr_no, const struct disk_part_info *info, 2933 char *res, size_t space) 2934{ 2935 const struct mbr_disk_partitions *parts = 2936 (const struct mbr_disk_partitions*)arg; 2937 struct part_attr_fmt_data data; 2938 2939 data.str = res; 2940 data.avail_space = space; 2941 data.attr_no = attr_no; 2942 data.parts = parts; 2943 data.info = info; 2944 2945 return mbr_part_apply(arg, id, part_attr_format_str, &data); 2946} 2947 2948static bool 2949mbr_custom_attribute_toggle(struct disk_partitions *arg, 2950 part_id id, size_t attr_no) 2951{ 2952 struct mbr_disk_partitions *parts = 2953 (struct mbr_disk_partitions*)arg; 2954 struct part_attr_set_data data; 2955 2956 data.attr_no = attr_no; 2957 data.parts = parts; 2958 data.str = NULL; 2959#ifdef BOOTSEL 2960 data.mbr = &parts->mbr; 2961#endif 2962 2963 return mbr_part_apply(arg, id, part_attr_toggle, &data); 2964} 2965 2966static bool 2967mbr_custom_attribute_set_str(struct disk_partitions *arg, 2968 part_id id, size_t attr_no, const char *new_val) 2969{ 2970 struct mbr_disk_partitions *parts = 2971 (struct mbr_disk_partitions*)arg; 2972 struct part_attr_set_data data; 2973 2974 data.attr_no = attr_no; 2975 data.parts = parts; 2976 data.str = new_val; 2977#ifdef BOOTSEL 2978 data.mbr = &parts->mbr; 2979#endif 2980 2981 return mbr_part_apply(arg, id, part_attr_set_str, &data); 2982} 2983 2984static daddr_t 2985mbr_part_alignment(const struct disk_partitions *arg) 2986{ 2987 const struct mbr_disk_partitions *parts = 2988 (const struct mbr_disk_partitions*)arg; 2989 2990 return parts->ptn_alignment; 2991} 2992 2993static bool 2994add_wedge(const char *disk, daddr_t start, daddr_t size, 2995 char *wname, size_t max_len) 2996{ 2997 struct dkwedge_info dkw; 2998 char diskpath[MAXPATHLEN]; 2999 int fd; 3000 3001 memset(&dkw, 0, sizeof(dkw)); 3002 dkw.dkw_offset = start; 3003 dkw.dkw_size = size; 3004 snprintf((char*)dkw.dkw_wname, sizeof dkw.dkw_wname, 3005 "%s_%" PRIi64 "@%" PRIi64, disk, size, start); 3006 3007 *wname = 0; 3008 3009 fd = opendisk(disk, O_RDWR, diskpath, sizeof(diskpath), 0); 3010 if (fd < 0) 3011 return false; 3012 if (ioctl(fd, DIOCAWEDGE, &dkw) == -1) { 3013 close(fd); 3014 return false; 3015 } 3016 close(fd); 3017 strlcpy(wname, dkw.dkw_devname, max_len); 3018 return true; 3019} 3020 3021static bool 3022mbr_get_part_device(const struct disk_partitions *arg, 3023 part_id ptn, char *devname, size_t max_devname_len, int *part, 3024 enum dev_name_usage usage, bool with_path, bool life) 3025{ 3026 const struct mbr_disk_partitions *parts = 3027 (const struct mbr_disk_partitions*)arg; 3028 struct disk_part_info info, tmp; 3029 part_id dptn; 3030 char *wedge_dev; 3031 3032 if (!mbr_get_part_info(arg, ptn, &info)) 3033 return false; 3034 3035 if (!mbr_part_get_wedge(arg, ptn, &wedge_dev) || wedge_dev == NULL) 3036 return false; 3037 3038 if (wedge_dev[0] == 0) { 3039 /* 3040 * If we have secondary partitions, try to find a match there 3041 * and use that... 3042 */ 3043 if (parts->dlabel != NULL) { 3044 for (dptn = 0; dptn < parts->dlabel->num_part; dptn++) { 3045 if (!parts->dlabel->pscheme->get_part_info( 3046 parts->dlabel, dptn, &tmp)) 3047 continue; 3048 if (tmp.start != info.start || 3049 tmp.size != info.size) 3050 continue; 3051 return parts->dlabel->pscheme->get_part_device( 3052 parts->dlabel, dptn, devname, 3053 max_devname_len, 3054 part, usage, with_path, life); 3055 } 3056 } 3057 3058 /* 3059 * Configure a new wedge and remember the name 3060 */ 3061 if (!add_wedge(arg->disk, info.start, info.size, wedge_dev, 3062 MBR_DEV_LEN)) 3063 return false; 3064 } 3065 3066 assert(wedge_dev[0] != 0); 3067 3068 switch (usage) { 3069 case logical_name: 3070 case plain_name: 3071 if (with_path) 3072 snprintf(devname, max_devname_len, _PATH_DEV "%s", 3073 wedge_dev); 3074 else 3075 strlcpy(devname, wedge_dev, max_devname_len); 3076 return true; 3077 case raw_dev_name: 3078 if (with_path) 3079 snprintf(devname, max_devname_len, _PATH_DEV "r%s", 3080 wedge_dev); 3081 else 3082 snprintf(devname, max_devname_len, "r%s", 3083 wedge_dev); 3084 return true; 3085 default: 3086 return false; 3087 } 3088} 3089 3090static bool 3091is_custom_attribute_writable(const struct disk_partitions *arg, part_id id, 3092 const mbr_info_t *mb, int i, bool primary, 3093 const struct mbr_partition *mp, void *cookie) 3094{ 3095 const struct mbr_disk_partitions *parts = 3096 (const struct mbr_disk_partitions*)arg; 3097 struct part_attr_set_data *data = cookie; 3098 const char *attrtype = parts->dp.pscheme 3099 ->custom_attributes[data->attr_no].label; 3100 3101 if (attrtype == MSG_ptn_active) 3102 /* Only 'normal' partitions can be 'Active' */ 3103 return primary && !MBR_IS_EXTENDED(mp->mbrp_type); 3104#ifdef BOOTSEL 3105 else if (attrtype == MSG_boot_dflt) 3106 /* Only partitions with bootmenu names can be default */ 3107 return mb->mbrb.mbrbs_nametab[i][0] != 0; 3108 else if (attrtype == MSG_bootmenu) 3109 /* The extended partition isn't bootable */ 3110 return !MBR_IS_EXTENDED(mp->mbrp_type); 3111#endif 3112 3113 return false; 3114} 3115 3116static bool 3117mbr_custom_attribute_writable(const struct disk_partitions *arg, 3118 part_id id, size_t attr_no) 3119{ 3120 const struct mbr_disk_partitions *parts = 3121 (const struct mbr_disk_partitions*)arg; 3122 struct part_attr_set_data data; 3123 3124 data.attr_no = attr_no; 3125 data.parts = parts; 3126 data.str = NULL; 3127#ifdef BOOTSEL 3128 data.mbr = NULL; 3129#endif 3130 3131 return mbr_part_apply(arg, id, is_custom_attribute_writable, &data); 3132} 3133 3134const struct disk_part_edit_column_desc mbr_edit_columns[] = { 3135 { .title = MSG_mbr_part_header_1, 3136#if BOOTSEL 3137 .width = 16U 3138#else 3139 .width = 26U 3140#endif 3141 }, 3142 { .title = MSG_mbr_part_header_2, .width = 8U }, 3143#if BOOTSEL 3144 { .title = MSG_mbr_part_header_3, .width = 9U }, 3145#endif 3146}; 3147 3148const struct disk_part_custom_attribute mbr_custom_attrs[] = { 3149 { .label = MSG_ptn_active, .type = pet_bool }, 3150#if BOOTSEL 3151 { .label = MSG_boot_dflt, .type = pet_bool }, 3152 { .label = MSG_bootmenu, .type = pet_str, 3153 .strlen = MBR_BS_PARTNAMESIZE }, 3154#endif 3155}; 3156 3157const struct disk_partitioning_scheme 3158mbr_parts = { 3159 .name = MSG_parttype_mbr, 3160 .short_name = MSG_parttype_mbr_short, 3161 .new_type_prompt = MSG_mbr_get_ptn_id, 3162 .part_flag_desc = MSG_mbr_flag_desc, 3163 .size_limit = (daddr_t)UINT32_MAX, 3164 .secondary_scheme = &disklabel_parts, 3165 .edit_columns_count = __arraycount(mbr_edit_columns), 3166 .edit_columns = mbr_edit_columns, 3167 .custom_attribute_count = __arraycount(mbr_custom_attrs), 3168 .custom_attributes = mbr_custom_attrs, 3169 .get_part_alignment = mbr_part_alignment, 3170 .get_part_info = mbr_get_part_info, 3171 .get_part_attr_str = mbr_part_attr_str, 3172 .format_partition_table_str = mbr_table_str, 3173 .part_type_can_change = mbr_part_type_can_change, 3174 .can_add_partition = mbr_can_add_partition, 3175 .custom_attribute_writable = mbr_custom_attribute_writable, 3176 .format_custom_attribute = mbr_custom_attribute_format, 3177 .custom_attribute_toggle = mbr_custom_attribute_toggle, 3178 .custom_attribute_set_str = mbr_custom_attribute_set_str, 3179 .get_part_types_count = mbr_get_part_type_count, 3180 .adapt_foreign_part_info = generic_adapt_foreign_part_info, 3181 .get_part_type = mbr_get_part_type, 3182 .get_fs_part_type = mbr_get_fs_part_type, 3183 .get_generic_part_type = mbr_get_generic_part_type, 3184 .create_custom_part_type = mbr_custom_part_type, 3185 .create_unknown_part_type = mbr_create_unknown_part_type, 3186 .secondary_partitions = mbr_read_disklabel, 3187 .write_to_disk = mbr_write_to_disk, 3188 .read_from_disk = mbr_read_from_disk, 3189 .create_new_for_disk = mbr_create_new, 3190 .guess_disk_geom = mbr_guess_geom, 3191 .get_cylinder_size = mbr_get_cylinder, 3192 .change_disk_geom = mbr_change_disk_geom, 3193 .get_part_device = mbr_get_part_device, 3194 .max_free_space_at = mbr_max_part_size, 3195 .get_free_spaces = mbr_get_free_spaces, 3196 .set_part_info = mbr_set_part_info, 3197 .delete_all_partitions = mbr_delete_all, 3198 .delete_partition = mbr_delete_part, 3199 .add_partition = mbr_add_part, 3200 .guess_install_target = mbr_guess_root, 3201 .post_edit_verify = mbr_verify, 3202 .pre_update_verify = mbr_verify_for_update, 3203 .free = mbr_free, 3204 .destroy_part_scheme = mbr_destroy_part_scheme, 3205}; 3206 3207#endif 3208