1 /* $NetBSD: mbr.c,v 1.39 2021/05/09 10:37:49 martin 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 */ 98 const struct { 99 unsigned int ptype; 100 char short_desc[12]; 101 const char *desc; 102 } mbr_part_types_src[] = { 103 { .ptype=MBR_PTYPE_NETBSD, .desc="NetBSD" }, 104 { .ptype=MBR_PTYPE_FAT32L, .desc="Windows FAT32, LBA" }, 105 { .ptype=MBR_PTYPE_EXT_LBA, .desc="Extended partition, LBA" }, 106 { .ptype=MBR_PTYPE_386BSD, .desc="FreeBSD/386BSD" }, 107 { .ptype=MBR_PTYPE_OPENBSD, .desc="OpenBSD" }, 108 { .ptype=MBR_PTYPE_LNXEXT2, .desc="Linux native" }, 109 { .ptype=MBR_PTYPE_LNXSWAP, .desc="Linux swap" }, 110 { .ptype=MBR_PTYPE_NTFSVOL, .desc="NTFS volume set" }, 111 { .ptype=MBR_PTYPE_NTFS, .desc="NTFS" }, 112 { .ptype=MBR_PTYPE_PREP, .desc="PReP Boot" }, 113 #ifdef MBR_PTYPE_SOLARIS 114 { .ptype=MBR_PTYPE_SOLARIS, .desc="Solaris" }, 115 #endif 116 { .ptype=MBR_PTYPE_FAT12, .desc="DOS FAT12" }, 117 { .ptype=MBR_PTYPE_FAT16S, .desc="DOS FAT16, <32M" }, 118 { .ptype=MBR_PTYPE_FAT16B, .desc="DOS FAT16, >32M" }, 119 { .ptype=MBR_PTYPE_FAT16L, .desc="Windows FAT16, LBA" }, 120 { .ptype=MBR_PTYPE_FAT32, .desc="Windows FAT32" }, 121 { .ptype=MBR_PTYPE_EFI, .desc="(U)EFI Boot" }, 122 }; 123 124 /* bookeeping of available partition types (including custom ones) */ 125 struct mbr_part_type_info { 126 struct part_type_desc gen; /* generic description */ 127 char desc_buf[40], short_buf[10]; 128 size_t next_ptype; /* user interface order */ 129 }; 130 131 const struct disk_partitioning_scheme mbr_parts; 132 struct mbr_disk_partitions { 133 struct disk_partitions dp, *dlabel; 134 mbr_info_t mbr; 135 uint ptn_alignment, ptn_0_offset, ext_ptn_alignment, 136 geo_sec, geo_head, geo_cyl, target; 137 }; 138 139 const struct disk_partitioning_scheme mbr_parts; 140 141 static size_t known_part_types = 0, last_added_part_type = 0; 142 static const size_t first_part_type = MBR_PTYPE_NETBSD; 143 144 /* all partition types (we are lucky, only a fixed number is possible) */ 145 struct mbr_part_type_info mbr_gen_type_desc[256]; 146 147 extern const struct disk_partitioning_scheme disklabel_parts; 148 149 static void convert_mbr_chs(int, int, int, uint8_t *, uint8_t *, 150 uint8_t *, uint32_t); 151 152 static part_id mbr_add_part(struct disk_partitions *arg, 153 const struct disk_part_info *info, const char **errmsg); 154 155 static size_t mbr_get_free_spaces(const struct disk_partitions *arg, 156 struct disk_part_free_space *result, size_t max_num_result, 157 daddr_t min_size, daddr_t align, daddr_t lower_bound, daddr_t ignore); 158 159 static size_t mbr_type_from_gen_desc(const struct part_type_desc *desc); 160 161 /* 162 * Notes on the extended partition editor. 163 * 164 * The extended partition structure is actually a singly linked list. 165 * Each of the 'mbr' sectors can only contain 2 items, the first describes 166 * a user partition (relative to that mbr sector), the second describes 167 * the following partition (relative to the start of the extended partition). 168 * 169 * The 'start' sector for the user partition is always the size of one 170 * track - very often 63. The extended partitions themselves should 171 * always start on a cylinder boundary using the BIOS geometry - often 172 * 16065 sectors per cylinder. 173 * 174 * The disk is also always described in increasing sector order. 175 * 176 * During editing we keep the mbr sectors accurate (it might have been 177 * easier to use absolute sector numbers though), and keep a copy of the 178 * entire sector - to preserve any information any other OS has tried 179 * to squirrel away in the (apparently) unused space. 180 * 181 * Typical disk (with some small numbers): 182 * 183 * 0 -> a 63 37 dos 184 * b 100 1000 extended LBA (type 15) 185 * 186 * 100 -> a 63 37 user 187 * b 100 200 extended partiton (type 5) 188 * 189 * 200 -> a 63 37 user 190 * b 200 300 extended partiton (type 5) 191 * 192 * 300 -> a 63 37 user 193 * b 0 0 0 (end of chain) 194 * 195 */ 196 197 #ifndef debug_extended 198 #define dump_mbr(mbr, msg) 199 #else 200 static void 201 dump_mbr(mbr_info_t *m, const char *label) 202 { 203 int i; 204 uint ext_base = 0; 205 206 fprintf(stderr, "\n%s: bsec %d\n", label, bsec); 207 do { 208 fprintf(stderr, "%p: %12u %p\n", 209 m, m->sector, m->extended); 210 for (i = 0; i < MBR_PART_COUNT; i++) { 211 fprintf(stderr, " %*d %12u %12u %12" PRIu64, 212 10, 213 m->mbr.mbr_parts[i].mbrp_type, 214 m->mbr.mbr_parts[i].mbrp_start, 215 m->mbr.mbr_parts[i].mbrp_size, 216 (uint64_t)m->mbr.mbr_parts[i].mbrp_start + 217 (uint64_t)m->mbr.mbr_parts[i].mbrp_size); 218 if (m->sector == 0 && 219 MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) 220 ext_base = m->mbr.mbr_parts[i].mbrp_start; 221 if (m->sector > 0 && 222 m->mbr.mbr_parts[i].mbrp_size > 0) { 223 uint off = MBR_IS_EXTENDED( 224 m->mbr.mbr_parts[i].mbrp_type) 225 ? ext_base : m->sector; 226 fprintf(stderr, " -> [%u .. %u]", 227 m->mbr.mbr_parts[i].mbrp_start + off, 228 m->mbr.mbr_parts[i].mbrp_size + 229 m->mbr.mbr_parts[i].mbrp_start + off); 230 } 231 fprintf(stderr, ",\n"); 232 if (m->sector > 0 && i >= 1) 233 break; 234 } 235 } while ((m = m->extended)); 236 } 237 #endif 238 239 /* 240 * Like pread, but handles re-blocking for non 512 byte sector disks 241 */ 242 static ssize_t 243 blockread(int fd, size_t secsize, void *buf, size_t nbytes, off_t offset) 244 { 245 ssize_t nr; 246 off_t sector = offset / 512; 247 off_t offs = sector * (off_t)secsize; 248 off_t mod = offs & (secsize - 1); 249 off_t rnd = offs & ~(secsize - 1); 250 char *iobuf; 251 252 assert(nbytes <= 512); 253 254 if (secsize == 512) 255 return pread(fd, buf, nbytes, offset); 256 257 iobuf = malloc(secsize); 258 if (iobuf == NULL) 259 return -1; 260 nr = pread(fd, iobuf, secsize, rnd); 261 if (nr == (off_t)secsize) 262 memcpy(buf, &iobuf[mod], nbytes); 263 free(iobuf); 264 265 return nr == (off_t)secsize ? (off_t)nbytes : -1; 266 } 267 268 /* 269 * Same for pwrite 270 */ 271 static ssize_t 272 blockwrite(int fd, size_t secsize, const void *buf, size_t nbytes, 273 off_t offset) 274 { 275 ssize_t nr; 276 off_t sector = offset / secsize; 277 off_t offs = sector * (off_t)secsize; 278 off_t mod = offs & (secsize - 1); 279 off_t rnd = offs & ~(secsize - 1); 280 char *iobuf; 281 282 assert(nbytes <= 512); 283 284 if (secsize == 512) 285 return pwrite(fd, buf, nbytes, offset); 286 287 iobuf = malloc(secsize); 288 if (iobuf == NULL) 289 return -1; 290 nr = pread(fd, iobuf, secsize, rnd); 291 if (nr == (off_t)secsize) { 292 memcpy(&iobuf[mod], buf, nbytes); 293 nr = pwrite(fd, iobuf, secsize, rnd); 294 } 295 free(iobuf); 296 297 return nr == (off_t)secsize ? (off_t)nbytes : -1; 298 } 299 300 static void 301 free_last_mounted(mbr_info_t *m) 302 { 303 size_t i; 304 305 for (i = 0; i < MBR_PART_COUNT; i++) 306 free(__UNCONST(m->last_mounted[i])); 307 } 308 309 static void 310 free_mbr_info(mbr_info_t *m) 311 { 312 if (m == NULL) 313 return; 314 free_last_mounted(m); 315 free(m); 316 } 317 318 /* 319 * To be used only on ports which cannot provide any bios geometry 320 */ 321 int 322 set_bios_geom_with_mbr_guess(struct disk_partitions *parts) 323 { 324 int cyl, head, sec; 325 326 msg_fmt_display(MSG_nobiosgeom, "%d%d%d", 327 pm->dlcyl, pm->dlsec, pm->dlhead); 328 if (guess_biosgeom_from_parts(parts, &cyl, &head, &sec) >= 0) 329 msg_fmt_display_add(MSG_biosguess, "%d%d%d", cyl, head, sec); 330 set_bios_geom(parts, &cyl, &head, &sec); 331 if (parts->pscheme->change_disk_geom) 332 parts->pscheme->change_disk_geom(parts, cyl, head, sec); 333 334 return edit_outer_parts(parts); 335 } 336 337 static void 338 mbr_init_chs(struct mbr_disk_partitions *parts, int ncyl, int nhead, int nsec) 339 { 340 if (ncyl > MAXCYL) 341 ncyl = MAXCYL; 342 pm->current_cylsize = nhead*nsec; 343 pm->max_chs = (unsigned long)ncyl*nhead*nsec; 344 parts->geo_sec = nsec; 345 parts->geo_head = nhead; 346 parts->geo_cyl = ncyl; 347 } 348 349 /* 350 * get C/H/S geometry from user via menu interface and 351 * store in globals. 352 */ 353 void 354 set_bios_geom(struct disk_partitions *parts, int *cyl, int *head, int *sec) 355 { 356 char res[80]; 357 int bsec, bhead, bcyl; 358 daddr_t s; 359 360 if (parts->pscheme->change_disk_geom == NULL) 361 return; 362 363 msg_display_add(MSG_setbiosgeom); 364 365 do { 366 snprintf(res, 80, "%d", *sec); 367 msg_prompt_add(MSG_sectors, res, res, 80); 368 bsec = atoi(res); 369 } while (bsec <= 0 || bsec > MAXSECTOR); 370 371 do { 372 snprintf(res, 80, "%d", *head); 373 msg_prompt_add(MSG_heads, res, res, 80); 374 bhead = atoi(res); 375 } while (bhead <= 0 || bhead > MAXHEAD); 376 s = min(pm->dlsize, mbr_parts.size_limit); 377 bcyl = s / bsec / bhead; 378 if (s != bcyl * bsec * bhead) 379 bcyl++; 380 if (bcyl > MAXCYL) 381 bcyl = MAXCYL; 382 pm->max_chs = (unsigned long)bcyl * bhead * bsec; 383 pm->current_cylsize = bhead * bsec; 384 parts->pscheme->change_disk_geom(parts, bcyl, bhead, bsec); 385 *cyl = bcyl; 386 *head = bhead; 387 *sec = bsec; 388 } 389 390 static int 391 find_mbr_space(const struct mbr_info_t *mbrs, uint *start, uint *size, 392 uint from, uint end_of_disk, uint ignore_at, bool primary_only) 393 { 394 uint sz; 395 int i, j; 396 uint s, e; 397 const mbr_info_t *m, *me; 398 bool is_extended; 399 400 check_again: 401 m = mbrs; 402 sz = end_of_disk-from; 403 if (from >= end_of_disk) 404 return -1; 405 406 for (i = 0; i < MBR_PART_COUNT; i++) { 407 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 408 continue; 409 410 is_extended = MBR_IS_EXTENDED( 411 m->mbr.mbr_parts[i].mbrp_type); 412 413 s = m->mbr.mbr_parts[i].mbrp_start + m->sector; 414 if (s == ignore_at) 415 continue; 416 e = s + m->mbr.mbr_parts[i].mbrp_size; 417 if (s <= from && e > from 418 && (!is_extended || primary_only)) { 419 if (e - 1 >= end_of_disk) 420 break; 421 if (e >= UINT_MAX) { 422 sz = 0; 423 break; 424 } 425 from = e + 1; 426 goto check_again; 427 } 428 if (s <= from && e > from && is_extended) { 429 /* 430 * if we start in the extended partiton, 431 * we must end before its end 432 */ 433 sz = e - from; 434 } 435 if (s > from && s - from < sz) 436 sz = s - from; 437 438 if (is_extended) { 439 for (me = m->extended; me != NULL; me = me->extended) { 440 for (j = 0; j < MBR_PART_COUNT; j++) { 441 if (me->mbr.mbr_parts[j].mbrp_type == 442 MBR_PTYPE_UNUSED) 443 continue; 444 445 is_extended = MBR_IS_EXTENDED( 446 me->mbr.mbr_parts[j].mbrp_type); 447 448 if (is_extended && i > 0) 449 break; 450 451 s = me->mbr.mbr_parts[j].mbrp_start + 452 me->sector; 453 if (s == ignore_at) 454 continue; 455 e = s + me->mbr.mbr_parts[j].mbrp_size; 456 if (me->sector != 0 && me->sector< s) 457 /* 458 * can not allow to overwrite 459 * the ext mbr 460 */ 461 s = me->sector; 462 if (s <= from && e > from) { 463 if (e - 1 >= end_of_disk) 464 break; 465 from = e + 1; 466 goto check_again; 467 } 468 if (s > from && s - from < sz) 469 sz = s - from; 470 471 } 472 } 473 } 474 } 475 476 if (sz == 0) 477 return -1; 478 if (start != NULL) 479 *start = from; 480 if (size != NULL) 481 *size = sz; 482 return 0; 483 } 484 485 #ifdef BOOTSEL 486 static int 487 validate_and_set_names(mbr_info_t *mbri, const struct mbr_bootsel *src, 488 uint32_t ext_base) 489 { 490 size_t i, l; 491 const unsigned char *p; 492 493 /* 494 * The 16 bit magic used to detect whether mbr_bootsel is valid 495 * or not is pretty week - collisions have been seen in the wild; 496 * but maybe it is just foreign tools corruption reminiscents 497 * of NetBSD MBRs. Anyway, before accepting a boot menu definition, 498 * make sure it is kinda "sane". 499 */ 500 501 for (i = 0; i < MBR_PART_COUNT; i++) { 502 /* 503 * Make sure the name does not contain controll chars 504 * (not using iscntrl due to minimalistic locale support 505 * in miniroot environments) and is properly 0-terminated. 506 */ 507 for (l = 0, p = (const unsigned char *)&src->mbrbs_nametab[i]; 508 *p != 0; l++, p++) { 509 if (l > MBR_BS_PARTNAMESIZE) 510 return 0; 511 if (*p < ' ') /* hacky 'iscntrl' */ 512 return 0; 513 } 514 } 515 516 memcpy(&mbri->mbrb, src, sizeof(*src)); 517 518 if (ext_base == 0) 519 return mbri->mbrb.mbrbs_defkey - SCAN_1; 520 return 0; 521 } 522 #endif 523 524 static int 525 valid_mbr(struct mbr_sector *mbrs) 526 { 527 528 return (le16toh(mbrs->mbr_magic) == MBR_MAGIC); 529 } 530 531 static int 532 read_mbr(const char *disk, size_t secsize, mbr_info_t *mbri, 533 struct mbr_disk_partitions *parts) 534 { 535 struct mbr_partition *mbrp; 536 struct mbr_sector *mbrs = &mbri->mbr; 537 mbr_info_t *ext = NULL; 538 char diskpath[MAXPATHLEN]; 539 int fd, i; 540 uint32_t ext_base = 0, next_ext = 0; 541 int rval = -1; 542 #ifdef BOOTSEL 543 mbr_info_t *ombri = mbri; 544 int bootkey = 0; 545 #endif 546 547 memset(mbri, 0, sizeof *mbri); 548 549 /* Open the disk. */ 550 fd = opendisk(disk, O_RDONLY, diskpath, sizeof(diskpath), 0); 551 if (fd < 0) 552 goto bad_mbr; 553 554 for (;;) { 555 if (blockread(fd, secsize, mbrs, sizeof *mbrs, 556 (ext_base + next_ext) * (off_t)MBR_SECSIZE) 557 - sizeof *mbrs != 0) 558 break; 559 560 if (!valid_mbr(mbrs)) 561 break; 562 563 mbrp = &mbrs->mbr_parts[0]; 564 if (ext_base != 0) { 565 /* sanity check extended chain */ 566 if (MBR_IS_EXTENDED(mbrp[0].mbrp_type)) 567 break; 568 if (mbrp[1].mbrp_type != MBR_PTYPE_UNUSED && 569 !MBR_IS_EXTENDED(mbrp[1].mbrp_type)) 570 break; 571 if (mbrp[2].mbrp_type != MBR_PTYPE_UNUSED 572 || mbrp[3].mbrp_type != MBR_PTYPE_UNUSED) 573 break; 574 /* Looks ok, link into extended chain */ 575 mbri->extended = ext; 576 ext->extended = NULL; 577 mbri = ext; 578 ext = NULL; 579 } 580 #if BOOTSEL 581 if (mbrs->mbr_bootsel_magic == htole16(MBR_MAGIC)) { 582 /* old bootsel, grab bootsel info */ 583 bootkey = validate_and_set_names(mbri, 584 (struct mbr_bootsel *) 585 ((uint8_t *)mbrs + MBR_BS_OLD_OFFSET), 586 ext_base); 587 } else if (mbrs->mbr_bootsel_magic == htole16(MBR_BS_MAGIC)) { 588 /* new location */ 589 bootkey = validate_and_set_names(mbri, 590 &mbrs->mbr_bootsel, ext_base); 591 } 592 /* Save original flags for mbr code update tests */ 593 mbri->oflags = mbri->mbrb.mbrbs_flags; 594 #endif 595 mbri->sector = next_ext + ext_base; 596 next_ext = 0; 597 rval = 0; 598 for (i = 0; i < MBR_PART_COUNT; mbrp++, i++) { 599 if (mbrp->mbrp_type == MBR_PTYPE_UNUSED) { 600 /* type is unused, discard scum */ 601 memset(mbrp, 0, sizeof *mbrp); 602 continue; 603 } 604 mbrp->mbrp_start = le32toh(mbrp->mbrp_start); 605 mbrp->mbrp_size = le32toh(mbrp->mbrp_size); 606 if (MBR_IS_EXTENDED(mbrp->mbrp_type)) { 607 next_ext = mbrp->mbrp_start; 608 } else { 609 uint flags = 0; 610 if (mbrp->mbrp_type == MBR_PTYPE_NETBSD) { 611 flags |= GLM_LIKELY_FFS; 612 if (parts->target == ~0U) 613 parts->target = 614 mbri->sector + 615 mbrp->mbrp_start; 616 } else if (mbrp->mbrp_type == MBR_PTYPE_FAT12 || 617 mbrp->mbrp_type == MBR_PTYPE_FAT16S || 618 mbrp->mbrp_type == MBR_PTYPE_FAT16B || 619 mbrp->mbrp_type == MBR_PTYPE_FAT32 || 620 mbrp->mbrp_type == MBR_PTYPE_FAT32L || 621 mbrp->mbrp_type == MBR_PTYPE_FAT16L) 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 668 static int 669 write_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 794 static void 795 convert_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 */ 825 int 826 guess_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 858 static int 859 mbr_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 875 static void 876 mbr_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 882 static void 883 mbr_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/alignemnt 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 905 static struct disk_partitions * 906 mbr_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 945 static void 946 mbr_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 979 static struct disk_partitions * 980 mbr_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 1029 static bool 1030 mbr_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 1056 static bool 1057 mbr_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 begining 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 1101 static size_t 1102 mbr_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 1111 static enum part_type 1112 mbr_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 1136 static void 1137 map_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 1157 static size_t 1158 mbr_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 1166 static const struct part_type_desc * 1167 mbr_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 } 1192 1193 return NULL; 1194 } 1195 1196 static const struct part_type_desc * 1197 mbr_get_part_type(size_t index) 1198 { 1199 size_t i, no; 1200 1201 if (known_part_types == 0) 1202 map_mbr_part_types(); 1203 1204 if (index >= known_part_types) 1205 return NULL; 1206 1207 for (i = first_part_type, no = 0; i < __arraycount(mbr_gen_type_desc) 1208 && no != index; no++) 1209 i = mbr_gen_type_desc[i].next_ptype; 1210 1211 if (i >= __arraycount(mbr_gen_type_desc)) 1212 return NULL; 1213 return &mbr_gen_type_desc[i].gen; 1214 } 1215 1216 static const struct part_type_desc * 1217 mbr_new_custom_part_type(unsigned int v) 1218 { 1219 snprintf(mbr_gen_type_desc[v].short_buf, 1220 sizeof(mbr_gen_type_desc[v].short_buf), "%u", v); 1221 snprintf(mbr_gen_type_desc[v].desc_buf, 1222 sizeof(mbr_gen_type_desc[v].desc_buf), "%s (%u)", 1223 msg_string(MSG_custom_type), v); 1224 mbr_gen_type_desc[v].gen.short_desc = mbr_gen_type_desc[v].short_buf; 1225 mbr_gen_type_desc[v].gen.description = mbr_gen_type_desc[v].desc_buf; 1226 mbr_gen_type_desc[v].gen.generic_ptype = mbr_map_part_type(v); 1227 mbr_gen_type_desc[v].next_ptype = ~0U; 1228 mbr_gen_type_desc[last_added_part_type].next_ptype = v; 1229 known_part_types++; 1230 last_added_part_type = v; 1231 1232 return &mbr_gen_type_desc[v].gen; 1233 } 1234 1235 static const struct part_type_desc * 1236 mbr_custom_part_type(const char *custom, const char **err_msg) 1237 { 1238 unsigned long v; 1239 char *endp; 1240 1241 if (known_part_types == 0) 1242 map_mbr_part_types(); 1243 1244 v = strtoul(custom, &endp, 10); 1245 if (v > 255 || (v == 0 && *endp != 0)) { 1246 if (err_msg != NULL) 1247 *err_msg = msg_string(MSG_mbr_type_invalid); 1248 return NULL; 1249 } 1250 1251 if (mbr_gen_type_desc[v].gen.short_desc != NULL) 1252 return &mbr_gen_type_desc[v].gen; 1253 1254 return mbr_new_custom_part_type(v); 1255 } 1256 1257 static const struct part_type_desc * 1258 mbr_create_unknown_part_type(void) 1259 { 1260 1261 if (mbr_gen_type_desc[MBR_UNKNOWN_PTYPE].gen.short_desc != NULL) 1262 return &mbr_gen_type_desc[MBR_UNKNOWN_PTYPE].gen; 1263 1264 return mbr_new_custom_part_type(MBR_UNKNOWN_PTYPE); 1265 } 1266 1267 static const struct part_type_desc * 1268 mbr_get_gen_type_desc(unsigned int pt) 1269 { 1270 1271 if (known_part_types == 0) 1272 map_mbr_part_types(); 1273 1274 if (pt >= __arraycount(mbr_gen_type_desc)) 1275 return NULL; 1276 1277 if (mbr_gen_type_desc[pt].gen.short_desc != NULL) 1278 return &mbr_gen_type_desc[pt].gen; 1279 1280 return mbr_new_custom_part_type(pt); 1281 } 1282 1283 static const struct part_type_desc * 1284 mbr_get_generic_part_type(enum part_type pt) 1285 { 1286 switch (pt) { 1287 case PT_root: 1288 return mbr_get_gen_type_desc(MBR_PTYPE_NETBSD); 1289 case PT_FAT: 1290 return mbr_get_gen_type_desc(MBR_PTYPE_FAT32L); 1291 case PT_EXT2: 1292 return mbr_get_gen_type_desc(MBR_PTYPE_LNXEXT2); 1293 case PT_EFI_SYSTEM: 1294 return mbr_get_gen_type_desc(MBR_PTYPE_EFI); 1295 default: 1296 break; 1297 } 1298 assert(false); 1299 return NULL; 1300 } 1301 1302 static void 1303 mbr_partition_to_info(const struct mbr_partition *mp, daddr_t start_off, 1304 struct disk_part_info *info) 1305 { 1306 memset(info, 0, sizeof(*info)); 1307 info->start = mp->mbrp_start + start_off; 1308 info->size = mp->mbrp_size; 1309 info->nat_type = mbr_get_gen_type_desc(mp->mbrp_type); 1310 if (mp->mbrp_type == MBR_PTYPE_NETBSD) { 1311 info->flags |= PTI_SEC_CONTAINER; 1312 } else if (MBR_IS_EXTENDED(mp->mbrp_type)) 1313 info->flags |= PTI_PSCHEME_INTERNAL; 1314 } 1315 1316 static bool 1317 mbr_part_apply(const struct disk_partitions *arg, part_id id, 1318 bool (*func)(const struct disk_partitions *arg, part_id id, 1319 const mbr_info_t *mb, int i, bool primary, 1320 const struct mbr_partition *mp, void *), 1321 void *cookie) 1322 { 1323 const struct mbr_disk_partitions *parts = 1324 (const struct mbr_disk_partitions*)arg; 1325 part_id i, j, no; 1326 const mbr_info_t *m = &parts->mbr, *me; 1327 1328 no = 0; 1329 for (i = 0; i < MBR_PART_COUNT; i++) { 1330 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 1331 continue; 1332 1333 if (no == id) { 1334 return func(arg, id, m, i, true, 1335 &m->mbr.mbr_parts[i], cookie); 1336 } 1337 no++; 1338 1339 if (MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) { 1340 for (me = m->extended; me != NULL; me = me->extended) { 1341 for (j = 0; j < MBR_PART_COUNT; j++) { 1342 if (me->mbr.mbr_parts[j].mbrp_type == 1343 MBR_PTYPE_UNUSED) 1344 continue; 1345 if (j > 0 && MBR_IS_EXTENDED( 1346 me->mbr.mbr_parts[j].mbrp_type)) 1347 break; 1348 if (no == id) { 1349 return func(arg, id, me, j, 1350 false, 1351 &me->mbr.mbr_parts[j], 1352 cookie); 1353 } 1354 no++; 1355 } 1356 } 1357 } 1358 } 1359 1360 1361 return false; 1362 } 1363 1364 static bool 1365 mbr_do_get_part_info(const struct disk_partitions *arg, part_id id, 1366 const mbr_info_t *mb, int i, bool primary, 1367 const struct mbr_partition *mp, void *cookie) 1368 { 1369 struct disk_part_info *info = cookie; 1370 const struct mbr_disk_partitions *parts = 1371 (const struct mbr_disk_partitions*)arg; 1372 1373 mbr_partition_to_info(mp, mb->sector, info); 1374 if (mp->mbrp_start + mb->sector == parts->target) 1375 info->flags |= PTI_INSTALL_TARGET; 1376 if (mb->last_mounted[i] != NULL && mb->last_mounted[i][0] != 0) 1377 info->last_mounted = mb->last_mounted[i]; 1378 if (mb->fs_type[i] != FS_UNUSED) { 1379 info->fs_type = mb->fs_type[i]; 1380 info->fs_sub_type = mb->fs_sub_type[i]; 1381 } else { 1382 info->fs_sub_type = 0; 1383 switch (mp->mbrp_type) { 1384 case MBR_PTYPE_FAT12: 1385 case MBR_PTYPE_FAT16S: 1386 case MBR_PTYPE_FAT16B: 1387 case MBR_PTYPE_FAT32: 1388 case MBR_PTYPE_FAT32L: 1389 case MBR_PTYPE_FAT16L: 1390 case MBR_PTYPE_OS2_DOS12: 1391 case MBR_PTYPE_OS2_DOS16S: 1392 case MBR_PTYPE_OS2_DOS16B: 1393 case MBR_PTYPE_HID_FAT32: 1394 case MBR_PTYPE_HID_FAT32_LBA: 1395 case MBR_PTYPE_HID_FAT16_LBA: 1396 case MBR_PTYPE_MDOS_FAT12: 1397 case MBR_PTYPE_MDOS_FAT16S: 1398 case MBR_PTYPE_MDOS_EXT: 1399 case MBR_PTYPE_MDOS_FAT16B: 1400 case MBR_PTYPE_SPEEDSTOR_16S: 1401 case MBR_PTYPE_EFI: 1402 info->fs_type = FS_MSDOS; 1403 info->fs_sub_type = mp->mbrp_type; 1404 break; 1405 case MBR_PTYPE_LNXEXT2: 1406 info->fs_type = FS_EX2FS; 1407 break; 1408 case MBR_PTYPE_XENIX_ROOT: 1409 case MBR_PTYPE_XENIX_USR: 1410 info->fs_type = FS_SYSV; 1411 break; 1412 case MBR_PTYPE_NTFS: 1413 info->fs_type = FS_NTFS; 1414 break; 1415 case MBR_PTYPE_APPLE_HFS: 1416 info->fs_type = FS_HFS; 1417 break; 1418 case MBR_PTYPE_VMWARE: 1419 info->fs_type = FS_VMFS; 1420 break; 1421 case MBR_PTYPE_AST_SWAP: 1422 case MBR_PTYPE_DRDOS_LSWAP: 1423 case MBR_PTYPE_LNXSWAP: 1424 case MBR_PTYPE_BSDI_SWAP: 1425 case MBR_PTYPE_HID_LNX_SWAP: 1426 case MBR_PTYPE_VMWARE_SWAP: 1427 info->fs_type = FS_SWAP; 1428 break; 1429 } 1430 } 1431 return true; 1432 } 1433 1434 static bool 1435 get_wedge_devname(const struct disk_partitions *arg, part_id id, 1436 const mbr_info_t *mb, int i, bool primary, 1437 const struct mbr_partition *mp, void *cookie) 1438 { 1439 char **res = cookie; 1440 1441 if (!res) 1442 return false; 1443 1444 *res = __UNCONST(mb->wedge[i]); 1445 return true; 1446 } 1447 1448 static bool 1449 mbr_part_get_wedge(const struct disk_partitions *arg, part_id id, 1450 char **res) 1451 { 1452 return mbr_part_apply(arg, id, get_wedge_devname, res); 1453 } 1454 1455 static bool 1456 mbr_get_part_info(const struct disk_partitions *arg, part_id id, 1457 struct disk_part_info *info) 1458 { 1459 return mbr_part_apply(arg, id, mbr_do_get_part_info, info); 1460 } 1461 1462 static bool 1463 type_can_change(const struct disk_partitions *arg, part_id id, 1464 const mbr_info_t *mb, int i, bool primary, 1465 const struct mbr_partition *mp, void *cookie) 1466 { 1467 /* 1468 * The extended partition can only change type or be 1469 * deleted if it is empty 1470 */ 1471 if (!MBR_IS_EXTENDED(mp->mbrp_type)) 1472 return true; 1473 return primary && mb->extended == NULL; 1474 } 1475 1476 static bool 1477 mbr_part_type_can_change(const struct disk_partitions *arg, part_id id) 1478 { 1479 return mbr_part_apply(arg, id, type_can_change, NULL); 1480 } 1481 1482 struct part_get_str_data { 1483 char *str; 1484 size_t avail_space; 1485 size_t col; 1486 }; 1487 1488 1489 static bool 1490 mbr_get_part_table_str(const struct disk_partitions *arg, part_id id, 1491 const mbr_info_t *mb, int i, bool primary, 1492 const struct mbr_partition *mp, void *cookie) 1493 { 1494 struct part_get_str_data *data = cookie; 1495 char *str = data->str; 1496 const struct part_type_desc *ptype; 1497 1498 switch (data->col) { 1499 case 0: 1500 ptype = mbr_get_gen_type_desc(mp->mbrp_type); 1501 if (ptype != NULL) 1502 strncpy(str, ptype->description, data->avail_space); 1503 else 1504 snprintf(str, data->avail_space, "%u", mp->mbrp_type); 1505 str[data->avail_space-1] = 0; 1506 break; 1507 case 1: 1508 if (mb->last_mounted[i]) 1509 strlcpy(str, mb->last_mounted[i], data->avail_space); 1510 else 1511 *str = 0; 1512 break; 1513 #ifdef BOOTSEL 1514 case 2: 1515 if (mb->mbrb.mbrbs_nametab[i][0] != 0) 1516 strlcpy(str, mb->mbrb.mbrbs_nametab[i], 1517 data->avail_space); 1518 else 1519 *str = 0; 1520 break; 1521 #endif 1522 } 1523 1524 return true; 1525 } 1526 1527 static bool 1528 mbr_table_str(const struct disk_partitions *arg, part_id id, size_t col, 1529 char *str, size_t avail_space) 1530 { 1531 struct part_get_str_data data; 1532 1533 data.str = str; 1534 data.avail_space = avail_space; 1535 data.col = col; 1536 return mbr_part_apply(arg, id, mbr_get_part_table_str, &data); 1537 } 1538 1539 static bool 1540 mbr_get_part_attr_str(const struct disk_partitions *arg, part_id id, 1541 const mbr_info_t *mb, int i, bool primary, 1542 const struct mbr_partition *mp, void *cookie) 1543 { 1544 #ifdef BOOTSEL 1545 const struct mbr_disk_partitions *parts = 1546 (const struct mbr_disk_partitions*)arg; 1547 #endif 1548 struct part_get_str_data *data = cookie; 1549 static const char *flags = NULL; 1550 char *str = data->str; 1551 1552 if (flags == NULL) 1553 flags = msg_string(MSG_mbr_flags); 1554 1555 if (mp->mbrp_flag & MBR_PFLAG_ACTIVE) 1556 *str++ = flags[0]; 1557 #ifdef BOOTSEL 1558 if (parts->mbr.bootsec == mb->sector+mp->mbrp_start) 1559 *str++ = flags[1]; 1560 #endif 1561 *str = 0; 1562 return true; 1563 } 1564 1565 static bool 1566 mbr_part_attr_str(const struct disk_partitions *arg, part_id id, 1567 char *str, size_t avail_space) 1568 { 1569 struct part_get_str_data data; 1570 1571 if (avail_space < 3) 1572 return false; 1573 1574 data.str = str; 1575 data.avail_space = avail_space; 1576 return mbr_part_apply(arg, id, mbr_get_part_attr_str, &data); 1577 } 1578 1579 static bool 1580 mbr_info_to_partitition(const struct disk_part_info *info, 1581 struct mbr_partition *mp, uint sector, 1582 struct mbr_info_t *mb, size_t index, const char **err_msg) 1583 { 1584 size_t pt = mbr_type_from_gen_desc(info->nat_type); 1585 if (info->start + info->size > UINT_MAX 1586 || pt > __arraycount(mbr_gen_type_desc)) { 1587 if (err_msg) 1588 *err_msg = err_outofmem; 1589 return false; 1590 } 1591 mp->mbrp_start = info->start - sector; 1592 mp->mbrp_size = info->size; 1593 mp->mbrp_type = pt; 1594 if (info->flags & PTI_INSTALL_TARGET) { 1595 mp->mbrp_flag |= MBR_PFLAG_ACTIVE; 1596 #ifdef BOOTSEL 1597 strcpy(mb->mbrb.mbrbs_nametab[index], "NetBSD"); 1598 #endif 1599 } 1600 1601 return true; 1602 } 1603 1604 static bool 1605 inside_ext_part(mbr_info_t *m, daddr_t start) 1606 { 1607 size_t i; 1608 struct mbr_partition *mp = NULL; 1609 1610 for (i = 0; i < MBR_PART_COUNT; i++) { 1611 if (!MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) 1612 continue; 1613 mp = &m->mbr.mbr_parts[i]; 1614 break; 1615 } 1616 1617 if (mp == NULL) { 1618 assert(false); 1619 return false; 1620 } 1621 1622 if (mp->mbrp_start > start) 1623 return false; 1624 1625 return true; 1626 } 1627 1628 static void 1629 adjust_ext_part(mbr_info_t *m, daddr_t start, daddr_t size) 1630 { 1631 size_t i; 1632 struct mbr_partition *mp = NULL; 1633 1634 for (i = 0; i < MBR_PART_COUNT; i++) { 1635 if (!MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) 1636 continue; 1637 mp = &m->mbr.mbr_parts[i]; 1638 break; 1639 } 1640 1641 if (mp == NULL) { 1642 assert(false); 1643 return; 1644 } 1645 1646 if (mp->mbrp_start + mp->mbrp_size >= start + size) 1647 return; 1648 1649 daddr_t new_end = start + size; 1650 mp->mbrp_size = new_end - mp->mbrp_start; 1651 } 1652 1653 static bool 1654 ext_part_good(mbr_info_t *m, daddr_t ext_start, daddr_t ext_size) 1655 { 1656 for (m = m->extended; m != NULL; m = m->extended) { 1657 for (size_t i = 0; i < MBR_PART_COUNT; i++) { 1658 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 1659 continue; 1660 1661 if (i > 0 && 1662 MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) 1663 break; 1664 1665 daddr_t pstart = m->mbr.mbr_parts[i].mbrp_start + 1666 m->sector; 1667 daddr_t pend = pstart + m->mbr.mbr_parts[i].mbrp_size; 1668 1669 if (pstart < ext_start || pend > ext_start+ext_size) 1670 return false; 1671 } 1672 } 1673 1674 return true; 1675 } 1676 1677 static bool 1678 mbr_set_part_info(struct disk_partitions *arg, part_id id, 1679 const struct disk_part_info *info, const char **err_msg) 1680 { 1681 struct mbr_disk_partitions *parts = 1682 (struct mbr_disk_partitions*)arg; 1683 struct disk_part_info data = *info; 1684 part_id i, j, no, ext_ndx, t; 1685 mbr_info_t *m = &parts->mbr, *me; 1686 uint pt = mbr_type_from_gen_desc(info->nat_type); 1687 1688 if (MBR_IS_EXTENDED(pt)) { 1689 /* check for duplicate ext part */ 1690 no = 0; 1691 t = ext_ndx = MBR_PART_COUNT; 1692 for (i = 0; i < MBR_PART_COUNT; i++) { 1693 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 1694 continue; 1695 if (MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) 1696 ext_ndx = i; 1697 if (no == id) 1698 t = i; 1699 no++; 1700 } 1701 if (ext_ndx < MBR_PART_COUNT && t != ext_ndx) { 1702 if (err_msg) 1703 *err_msg = 1704 msg_string(MSG_Only_one_extended_ptn); 1705 return false; 1706 } 1707 /* this partition becomes an extended one, apply alignment */ 1708 data.start = max(roundup(data.start, parts->ext_ptn_alignment), 1709 parts->ext_ptn_alignment); 1710 } 1711 1712 no = 0; 1713 for (i = 0; i < MBR_PART_COUNT; i++) { 1714 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 1715 continue; 1716 1717 if (no == id) 1718 goto found; 1719 no++; 1720 1721 if (MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) { 1722 for (me = m->extended; me != NULL; me = me->extended) { 1723 for (j = 0; j < MBR_PART_COUNT; j++) { 1724 if (me->mbr.mbr_parts[j].mbrp_type == 1725 MBR_PTYPE_UNUSED) 1726 continue; 1727 if (j > 0 && MBR_IS_EXTENDED( 1728 me->mbr.mbr_parts[j].mbrp_type)) 1729 break; 1730 if (no == id) { 1731 i = j; 1732 m = me; 1733 goto found; 1734 } 1735 no++; 1736 } 1737 } 1738 } 1739 } 1740 1741 if (err_msg) 1742 *err_msg = INTERNAL_ERROR; 1743 return false; 1744 1745 found: 1746 /* 1747 * We assume that m is the mbr we want to update and 1748 * i is the local partition index into it. 1749 */ 1750 if (m == &parts->mbr) { 1751 if (MBR_IS_EXTENDED( 1752 m->mbr.mbr_parts[i].mbrp_type) && 1753 !ext_part_good(&parts->mbr, data.start, data.size)) { 1754 if (err_msg) 1755 *err_msg = 1756 MSG_mbr_ext_nofit; 1757 return false; 1758 } 1759 } else if (!inside_ext_part(&parts->mbr, data.start)) { 1760 if (err_msg) 1761 *err_msg = msg_string(MSG_mbr_inside_ext); 1762 return false; 1763 } 1764 uint start = data.start, size = data.size; 1765 uint oldstart = m->mbr.mbr_parts[i].mbrp_start + m->sector; 1766 if (parts->ptn_0_offset > 0 && 1767 start < parts->ptn_0_offset) 1768 start = parts->ptn_0_offset; 1769 if (find_mbr_space(m, &start, &size, start, parts->dp.disk_size, 1770 oldstart, false) < 0) { 1771 if (err_msg != NULL) 1772 *err_msg = INTERNAL_ERROR; 1773 return false; 1774 } 1775 data.start = start; 1776 if (size < data.size) 1777 data.size = size; 1778 uint old_start = m->mbr.mbr_parts[i].mbrp_start; 1779 if (!mbr_info_to_partitition(&data, 1780 &m->mbr.mbr_parts[i], m->sector, m, i, err_msg)) 1781 return false; 1782 if (data.flags & PTI_INSTALL_TARGET) 1783 parts->target = start; 1784 else if (old_start == parts->target) 1785 parts->target = -1; 1786 if (data.last_mounted && m->last_mounted[i] && 1787 data.last_mounted != m->last_mounted[i]) { 1788 free(__UNCONST(m->last_mounted[i])); 1789 m->last_mounted[i] = strdup(data.last_mounted); 1790 } 1791 if (data.fs_type != 0) 1792 m->fs_type[i] = data.fs_type; 1793 if (data.fs_sub_type != 0) 1794 m->fs_sub_type[i] = data.fs_sub_type; 1795 1796 if (m == &parts->mbr) { 1797 if (m->mbr.mbr_parts[i].mbrp_start != 1798 old_start) 1799 mbr_sort_main_mbr(&m->mbr); 1800 } else { 1801 adjust_ext_part(&parts->mbr, 1802 data.start, data.size); 1803 } 1804 mbr_calc_free_space(parts); 1805 return true; 1806 } 1807 1808 static bool 1809 mbr_find_netbsd(const struct mbr_info_t *m, uint start, 1810 struct disk_part_info *info) 1811 { 1812 size_t i; 1813 bool prim = true; 1814 1815 do { 1816 for (i = 0; i < MBR_PART_COUNT; i++) { 1817 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 1818 continue; 1819 1820 if (!prim && i > 0 && 1821 MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) 1822 break; 1823 1824 const struct mbr_partition *mp = &m->mbr.mbr_parts[i]; 1825 if (mp->mbrp_type != MBR_PTYPE_NETBSD) 1826 continue; 1827 1828 mbr_partition_to_info(mp, m->sector, info); 1829 if (m->last_mounted[i] && *m->last_mounted[i] != 0) 1830 info->last_mounted = 1831 m->last_mounted[i]; 1832 info->fs_type = m->fs_type[i]; 1833 info->fs_sub_type = m->fs_sub_type[i]; 1834 if (start > 0 && start != info->start) 1835 continue; 1836 return true; 1837 } 1838 prim = false; 1839 } while ((m = m->extended)); 1840 1841 return false; 1842 } 1843 1844 static struct disk_partitions * 1845 mbr_read_disklabel(struct disk_partitions *arg, daddr_t start, bool force_empty) 1846 { 1847 struct mbr_disk_partitions *myparts = 1848 (struct mbr_disk_partitions*)arg; 1849 struct disk_part_info part; 1850 struct disk_part_free_space space; 1851 1852 if (force_empty && myparts->dlabel) 1853 myparts->dlabel->pscheme->delete_all_partitions( 1854 myparts->dlabel); 1855 1856 if (myparts->dlabel == NULL) { 1857 /* 1858 * Find the NetBSD MBR partition 1859 */ 1860 if (!mbr_find_netbsd(&myparts->mbr, start, &part)) { 1861 if (!force_empty) 1862 return NULL; 1863 1864 /* add a "whole disk" NetBSD partition */ 1865 memset(&part, 0, sizeof part); 1866 part.start = min(myparts->ptn_0_offset,start); 1867 if (!mbr_get_free_spaces(arg, &space, 1, 1868 part.start, myparts->ptn_alignment, -1, -1)) 1869 return NULL; 1870 part.start = space.start; 1871 part.size = space.size; 1872 part.nat_type = &mbr_gen_type_desc[MBR_PTYPE_NETBSD].gen; 1873 mbr_add_part(arg, &part, NULL); 1874 if (!mbr_find_netbsd(&myparts->mbr, start, &part)) 1875 return NULL; 1876 } 1877 1878 if (!force_empty) { 1879 myparts->dlabel = disklabel_parts.read_from_disk( 1880 myparts->dp.disk, part.start, part.size, 1881 myparts->dp.bytes_per_sector, &disklabel_parts); 1882 if (myparts->dlabel != NULL) 1883 myparts->dlabel->parent = &myparts->dp; 1884 } 1885 1886 if (myparts->dlabel == NULL && part.size > 0) { 1887 /* we just created the outer partitions? */ 1888 myparts->dlabel = 1889 disklabel_parts.create_new_for_disk( 1890 myparts->dp.disk, part.start, part.size, 1891 false, &myparts->dp); 1892 } 1893 1894 if (myparts->dlabel != NULL) 1895 myparts->dlabel->pscheme->change_disk_geom( 1896 myparts->dlabel, myparts->geo_cyl, 1897 myparts->geo_head, myparts->geo_sec); 1898 } 1899 return myparts->dlabel; 1900 } 1901 1902 static int 1903 get_mapping(struct mbr_partition *parts, int i, 1904 int *cylinder, int *head, int *sector, daddr_t *absolute) 1905 { 1906 struct mbr_partition *apart = &parts[i / 2]; 1907 1908 if (apart->mbrp_type == MBR_PTYPE_UNUSED) 1909 return -1; 1910 if (i % 2 == 0) { 1911 *cylinder = MBR_PCYL(apart->mbrp_scyl, apart->mbrp_ssect); 1912 *head = apart->mbrp_shd; 1913 *sector = MBR_PSECT(apart->mbrp_ssect) - 1; 1914 *absolute = le32toh(apart->mbrp_start); 1915 } else { 1916 *cylinder = MBR_PCYL(apart->mbrp_ecyl, apart->mbrp_esect); 1917 *head = apart->mbrp_ehd; 1918 *sector = MBR_PSECT(apart->mbrp_esect) - 1; 1919 *absolute = le32toh(apart->mbrp_start) 1920 + le32toh(apart->mbrp_size) - 1; 1921 } 1922 /* Sanity check the data against max values */ 1923 if ((((*cylinder * MAXHEAD) + *head) * (uint32_t)MAXSECTOR + *sector) < *absolute) 1924 /* cannot be a CHS mapping */ 1925 return -1; 1926 1927 return 0; 1928 } 1929 1930 static bool 1931 mbr_delete_all(struct disk_partitions *arg) 1932 { 1933 struct mbr_disk_partitions *myparts = (struct mbr_disk_partitions*)arg; 1934 struct mbr_sector *mbrs = &myparts->mbr.mbr; 1935 struct mbr_info_t *mbri = &myparts->mbr; 1936 mbr_info_t *ext; 1937 struct mbr_partition *part; 1938 1939 part = &mbrs->mbr_parts[0]; 1940 /* Set the partition information for full disk usage. */ 1941 while ((ext = mbri->extended)) { 1942 mbri->extended = ext->extended; 1943 free_mbr_info(ext); 1944 } 1945 memset(part, 0, MBR_PART_COUNT * sizeof *part); 1946 #ifdef BOOTSEL 1947 memset(&mbri->mbrb, 0, sizeof mbri->mbrb); 1948 #endif 1949 1950 /* 1951 * We may have changed alignment settings due to partitions 1952 * ending on an MB boundary - undo that, now that the partitions 1953 * are gone. 1954 */ 1955 mbr_change_disk_geom(arg, myparts->geo_cyl, myparts->geo_head, 1956 myparts->geo_sec); 1957 1958 return true; 1959 } 1960 1961 /* 1962 * helper function to fix up mbrp_start and mbrp_size for the 1963 * extended MBRs "partition b" entries after addition/deletion 1964 * of some partition. 1965 */ 1966 static void 1967 mbr_fixup_ext_chain(mbr_info_t *primary, uint ext_start, uint ext_end) 1968 { 1969 for (mbr_info_t *m = primary->extended; m != NULL; m = m->extended) { 1970 if (m->extended == NULL) { 1971 m->mbr.mbr_parts[1].mbrp_type = MBR_PTYPE_UNUSED; 1972 m->mbr.mbr_parts[1].mbrp_start = 0; 1973 m->mbr.mbr_parts[1].mbrp_size = 0; 1974 } else { 1975 uint n_end, n_start = m->extended->sector; 1976 if (m->extended->extended) 1977 n_end = m->extended->extended->sector; 1978 else 1979 n_end = ext_end; 1980 m->mbr.mbr_parts[1].mbrp_type = MBR_PTYPE_EXT; 1981 m->mbr.mbr_parts[1].mbrp_start = n_start - ext_start; 1982 m->mbr.mbr_parts[1].mbrp_size = n_end - n_start; 1983 } 1984 } 1985 } 1986 1987 struct delete_part_args { 1988 struct mbr_disk_partitions *parts; 1989 daddr_t start, size; 1990 const char **err_msg; 1991 }; 1992 1993 static bool 1994 mbr_do_delete_part(const struct disk_partitions *arg, part_id id, 1995 const mbr_info_t *mb, int i, bool primary, 1996 const struct mbr_partition *mp, void *cookie) 1997 { 1998 struct delete_part_args *marg = cookie; 1999 bool is_ext_part = MBR_IS_EXTENDED(mp->mbrp_type); 2000 2001 /* can not delete non-empty extended partitions */ 2002 if (MBR_IS_EXTENDED(mp->mbrp_type) 2003 && marg->parts->mbr.extended != NULL) { 2004 if (marg->err_msg) 2005 *marg->err_msg = msg_string(MSG_mbr_ext_not_empty); 2006 return false; 2007 } 2008 2009 /* return position/size to caller */ 2010 marg->start = mb->sector + mp->mbrp_start; 2011 marg->size = mp->mbrp_size; 2012 2013 if (primary) { 2014 /* if deleting the primary extended partition, just kill it */ 2015 struct mbr_partition *md = &marg->parts->mbr.mbr.mbr_parts[i]; 2016 md->mbrp_size = 0; 2017 md->mbrp_start = 0; 2018 md->mbrp_type = MBR_PTYPE_UNUSED; 2019 if (marg->parts->mbr.last_mounted[i]) { 2020 free(__UNCONST(marg->parts->mbr.last_mounted[i])); 2021 marg->parts->mbr.last_mounted[i] = NULL; 2022 } 2023 if (is_ext_part) { 2024 for (mbr_info_t *m = marg->parts->mbr.extended; 2025 m != NULL; ) { 2026 mbr_info_t *n = m->extended; 2027 free_mbr_info(m); 2028 m = n; 2029 } 2030 marg->parts->mbr.extended = NULL; 2031 } 2032 } else { 2033 /* find the size of the primary extended partition */ 2034 uint ext_start = 0, ext_size = 0; 2035 for (i = 0; i < MBR_PART_COUNT; i++) { 2036 if (!MBR_IS_EXTENDED(marg->parts->mbr.mbr.mbr_parts[i] 2037 .mbrp_type)) 2038 continue; 2039 ext_start = marg->parts->mbr.mbr.mbr_parts[i] 2040 .mbrp_start; 2041 ext_size = marg->parts->mbr.mbr.mbr_parts[i] 2042 .mbrp_size; 2043 break; 2044 } 2045 2046 /* 2047 * If we are in an extended partition chain, unlink this MBR, 2048 * unless it is the very first one at the start of the extended 2049 * partition (we would have no previos ext mbr to fix up 2050 * the chain in that case) 2051 */ 2052 if (marg->parts->mbr.extended == mb) { 2053 struct mbr_partition *part = 2054 &marg->parts->mbr.extended->mbr.mbr_parts[0]; 2055 part->mbrp_type = MBR_PTYPE_UNUSED; 2056 part->mbrp_start = 0; 2057 part->mbrp_size = 0; 2058 } else { 2059 mbr_info_t *p, *last; 2060 for (last = NULL, p = &marg->parts->mbr; p != NULL; 2061 last = p, p = p->extended) 2062 if (p == mb) 2063 break; 2064 if (last == NULL) { 2065 if (marg->err_msg != NULL) 2066 *marg->err_msg= INTERNAL_ERROR; 2067 return false; 2068 } 2069 last->extended = p->extended; 2070 free_mbr_info(p); 2071 if (last == &marg->parts->mbr && last->extended && 2072 last->extended->extended == NULL && 2073 last->extended->mbr.mbr_parts[0].mbrp_type == 2074 MBR_PTYPE_UNUSED) { 2075 /* 2076 * we deleted the last extended sector, 2077 * remove the whole chain 2078 */ 2079 free_mbr_info(last->extended); 2080 last->extended = NULL; 2081 } 2082 } 2083 mbr_fixup_ext_chain(&marg->parts->mbr, ext_start, 2084 ext_start+ext_size); 2085 } 2086 mbr_calc_free_space(marg->parts); 2087 return true; 2088 } 2089 2090 static bool 2091 mbr_delete_part(struct disk_partitions *arg, part_id pno, const char **err_msg) 2092 { 2093 struct mbr_disk_partitions *parts = 2094 (struct mbr_disk_partitions*)arg; 2095 struct delete_part_args data = { .parts = parts, .err_msg = err_msg }; 2096 2097 if (!mbr_part_apply(arg, pno, mbr_do_delete_part, &data)) { 2098 if (err_msg) 2099 *err_msg = INTERNAL_ERROR; 2100 return false; 2101 } 2102 2103 if (parts->target == data.start) 2104 parts->target = ~0U; 2105 2106 if (parts->dlabel) { 2107 /* 2108 * If we change the mbr partitioning, the we must 2109 * remove any references in the netbsd disklabel 2110 * to the part we changed. 2111 */ 2112 parts->dlabel->pscheme->delete_partitions_in_range( 2113 parts->dlabel, data.start, data.size); 2114 } 2115 2116 if (err_msg) 2117 *err_msg = NULL; 2118 2119 dump_mbr(&parts->mbr, "after delete"); 2120 return true; 2121 } 2122 2123 static struct mbr_partition * 2124 mbr_ptr_from_start(mbr_info_t *m, daddr_t start) 2125 { 2126 bool primary = true; 2127 2128 do { 2129 for (uint i = 0; i < MBR_PART_COUNT; i++) { 2130 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 2131 continue; 2132 if (!primary && 2133 MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) 2134 break; 2135 2136 daddr_t pstart = m->sector + 2137 m->mbr.mbr_parts[i].mbrp_start; 2138 if (pstart == start) 2139 return &m->mbr.mbr_parts[i]; 2140 2141 } 2142 primary = false; 2143 } while ((m = m->extended)); 2144 2145 return NULL; 2146 } 2147 2148 static uint8_t 2149 mbr_type_from_start(const mbr_info_t *m, daddr_t start) 2150 { 2151 bool primary = true; 2152 2153 do { 2154 for (uint i = 0; i < MBR_PART_COUNT; i++) { 2155 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 2156 continue; 2157 if (!primary && 2158 MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) 2159 break; 2160 2161 daddr_t pstart = m->sector + 2162 m->mbr.mbr_parts[i].mbrp_start; 2163 if (pstart == start) 2164 return m->mbr.mbr_parts[i].mbrp_type; 2165 2166 } 2167 primary = false; 2168 } while ((m = m->extended)); 2169 2170 return MBR_PTYPE_UNUSED; 2171 } 2172 2173 static part_id 2174 mbr_add_part(struct disk_partitions *arg, 2175 const struct disk_part_info *info, const char **errmsg) 2176 { 2177 struct mbr_disk_partitions *parts = 2178 (struct mbr_disk_partitions*)arg; 2179 part_id i, j, no, free_primary = UINT_MAX; 2180 mbr_info_t *m = &parts->mbr, *me, *last, *t; 2181 daddr_t ext_start = 0, ext_size = 0; 2182 uint start, size; 2183 struct disk_part_info data = *info; 2184 struct mbr_partition *newp; 2185 2186 if (errmsg != NULL) 2187 *errmsg = NULL; 2188 2189 assert(info->nat_type != NULL); 2190 if (info->nat_type == NULL) { 2191 if (errmsg != NULL) 2192 *errmsg = INTERNAL_ERROR; 2193 return NO_PART; 2194 } 2195 if (mbr_type_from_gen_desc(info->nat_type) == MBR_PTYPE_UNUSED) { 2196 if (errmsg != NULL) 2197 *errmsg = INTERNAL_ERROR; 2198 return NO_PART; 2199 } 2200 2201 /* do we have free primary slots and/or an extended partition? */ 2202 for (i = 0; i < MBR_PART_COUNT; i++) { 2203 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED 2204 && free_primary > MBR_PART_COUNT) 2205 free_primary = i; 2206 if (MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) { 2207 ext_start = m->mbr.mbr_parts[i].mbrp_start+m->sector; 2208 ext_size = m->mbr.mbr_parts[i].mbrp_size; 2209 continue; 2210 } 2211 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED 2212 && m->mbr.mbr_parts[i].mbrp_size == 0) 2213 continue; 2214 } 2215 if (ext_start > 0 && ext_size > 0 && 2216 MBR_IS_EXTENDED(mbr_type_from_gen_desc(info->nat_type))) { 2217 /* 2218 * Do not allow a second extended partition 2219 */ 2220 if (errmsg) 2221 *errmsg = MSG_Only_one_extended_ptn; 2222 return NO_PART; 2223 } 2224 2225 /* should this go into the extended partition? */ 2226 if (ext_size > 0 && info->start >= ext_start 2227 && info->start < ext_start + ext_size) { 2228 2229 /* must fit into the extended partition */ 2230 if (info->start + info->size > ext_start + ext_size) { 2231 if (errmsg != NULL) 2232 *errmsg = MSG_mbr_ext_nofit; 2233 return NO_PART; 2234 } 2235 2236 /* walk the chain untill we find a proper insert position */ 2237 daddr_t e_end, e_start; 2238 for (last = m, m = m->extended; m != NULL; 2239 last = m, m = m->extended) { 2240 e_start = m->mbr.mbr_parts[1].mbrp_start 2241 + ext_start; 2242 e_end = e_start + m->mbr.mbr_parts[1].mbrp_size; 2243 if (data.start <= e_start) 2244 break; 2245 } 2246 if (m == NULL) { 2247 /* add new tail record */ 2248 e_end = ext_start + ext_size; 2249 /* new part needs to fit inside primary extended one */ 2250 if (data.start + data.size > e_end) { 2251 if (errmsg) 2252 *errmsg = MSG_No_free_space; 2253 return NO_PART; 2254 } 2255 } else if (data.start + data.size > e_start) { 2256 /* new part needs to fit before next extended */ 2257 if (errmsg) 2258 *errmsg = MSG_No_free_space; 2259 return NO_PART; 2260 } 2261 /* 2262 * now last points to previous mbr (maybe primary), m 2263 * points to the one that should take the new partition 2264 * or we have to insert a new mbr between the two, or 2265 * m needs to be split and we go into the one after it. 2266 */ 2267 if (m && m->mbr.mbr_parts[0].mbrp_type == MBR_PTYPE_UNUSED) { 2268 /* empty slot, we can just use it */ 2269 newp = &m->mbr.mbr_parts[0]; 2270 mbr_info_to_partitition(&data, &m->mbr.mbr_parts[0], 2271 m->sector, m, 0, errmsg); 2272 if (data.last_mounted && m->last_mounted[0] && 2273 data.last_mounted != m->last_mounted[0]) { 2274 free(__UNCONST(m->last_mounted[0])); 2275 m->last_mounted[0] = strdup(data.last_mounted); 2276 } 2277 } else { 2278 mbr_info_t *new_mbr; 2279 if (m == NULL) 2280 m = last; 2281 daddr_t p_start = m->mbr.mbr_parts[0].mbrp_start 2282 + m->sector; 2283 daddr_t p_end = p_start 2284 + m->mbr.mbr_parts[0].mbrp_size; 2285 bool before; 2286 if (m == last || data.start > p_end) 2287 before = false; 2288 else if (data.start + data.size < p_start) 2289 before = true; 2290 else { 2291 if (errmsg) 2292 *errmsg = MSG_No_free_space; 2293 return NO_PART; 2294 } 2295 new_mbr = calloc(1, sizeof *new_mbr); 2296 if (!new_mbr) { 2297 if (errmsg) 2298 *errmsg = err_outofmem; 2299 return NO_PART; 2300 } 2301 new_mbr->mbr.mbr_magic = htole16(MBR_MAGIC); 2302 new_mbr->mbr.mbr_parts[1].mbrp_type = MBR_PTYPE_EXT; 2303 if (before) { 2304 /* 2305 * This is a hypthetical case where 2306 * an extended MBR uses an unusual high 2307 * offset (m->sector to parts[0].mbrp_start) 2308 * and we want to go into that space. 2309 * Should not happen in the real world (tm) 2310 * and is untested.... 2311 */ 2312 2313 /* make sure the aligned new mbr fits */ 2314 uint mbrsec = rounddown(p_start, 2315 parts->ext_ptn_alignment); 2316 if (mbrsec <= data.start + data.size) 2317 data.size = mbrsec-1-data.start; 2318 2319 /* now the new partition data is ready, 2320 * write out to old position */ 2321 new_mbr->sector = m->sector; 2322 newp = &new_mbr->mbr.mbr_parts[0]; 2323 mbr_info_to_partitition(&data, 2324 &new_mbr->mbr.mbr_parts[0], 2325 new_mbr->sector, new_mbr, 0, errmsg); 2326 if (data.last_mounted && m->last_mounted[0] && 2327 data.last_mounted != m->last_mounted[0]) { 2328 free(__UNCONST(m->last_mounted[0])); 2329 m->last_mounted[0] = 2330 strdup(data.last_mounted); 2331 } 2332 new_mbr->extended = m; 2333 } else { 2334 new_mbr->sector = max(roundup(data.start, 2335 parts->ext_ptn_alignment), 2336 parts->ext_ptn_alignment); 2337 uint off = new_mbr->sector - data.start; 2338 data.start += parts->ptn_0_offset+off; 2339 if (data.start + data.size > e_end) 2340 data.size = e_end - data.start; 2341 newp = &new_mbr->mbr.mbr_parts[0]; 2342 mbr_info_to_partitition(&data, 2343 &new_mbr->mbr.mbr_parts[0], 2344 new_mbr->sector, new_mbr, 0, errmsg); 2345 if (data.last_mounted && m->last_mounted[0] && 2346 data.last_mounted != m->last_mounted[0]) { 2347 free(__UNCONST(m->last_mounted[0])); 2348 m->last_mounted[0] = 2349 strdup(data.last_mounted); 2350 } 2351 /* 2352 * Special case: if we are creating the 2353 * first extended mbr, but do not start 2354 * at the beginning of the primary 2355 * extended partition, we need to insert 2356 * another extended mbr at the start. 2357 */ 2358 if (m == &parts->mbr && m->extended == NULL 2359 && new_mbr->sector > ext_start) { 2360 t = calloc(1, sizeof *new_mbr); 2361 if (!t) { 2362 free_mbr_info(new_mbr); 2363 if (errmsg) 2364 *errmsg = err_outofmem; 2365 return NO_PART; 2366 } 2367 t->sector = ext_start; 2368 t->mbr.mbr_magic = htole16(MBR_MAGIC); 2369 t->mbr.mbr_parts[1].mbrp_type = 2370 MBR_PTYPE_EXT; 2371 m->extended = t; 2372 m = t; 2373 } 2374 new_mbr->extended = m->extended; 2375 m->extended = new_mbr; 2376 } 2377 } 2378 mbr_fixup_ext_chain(&parts->mbr, ext_start, ext_start+ext_size); 2379 dump_mbr(&parts->mbr, "after adding in extended"); 2380 goto find_rval; 2381 } 2382 2383 /* this one is for the primary boot block */ 2384 if (free_primary > MBR_PART_COUNT) { 2385 if (errmsg != NULL) 2386 *errmsg = ext_size > 0 ? 2387 MSG_mbr_no_free_primary_have_ext 2388 : MSG_mbr_no_free_primary_no_ext; 2389 return NO_PART; 2390 } 2391 2392 start = max(info->start, parts->ptn_0_offset); 2393 size = info->size; 2394 if (find_mbr_space(m, &start, &size, start, parts->dp.disk_size, 2395 start, true) < 0 || size < info->size) { 2396 if (errmsg != NULL) 2397 *errmsg = MSG_No_free_space; 2398 return NO_PART; 2399 } 2400 data.start = start; 2401 if (MBR_IS_EXTENDED(mbr_type_from_gen_desc(info->nat_type))) { 2402 data.start = max(roundup(data.start, parts->ext_ptn_alignment), 2403 parts->ext_ptn_alignment); 2404 } 2405 if (data.start + data.size > start + size) 2406 data.size = start + size - data.start; 2407 mbr_info_to_partitition(&data, &m->mbr.mbr_parts[free_primary], 2408 m->sector, m, free_primary, errmsg); 2409 if (data.last_mounted && m->last_mounted[free_primary] && 2410 data.last_mounted != m->last_mounted[free_primary]) { 2411 free(__UNCONST(m->last_mounted[free_primary])); 2412 m->last_mounted[free_primary] = strdup(data.last_mounted); 2413 } 2414 start = m->mbr.mbr_parts[free_primary].mbrp_start; 2415 mbr_sort_main_mbr(&m->mbr); 2416 2417 /* find the partition again after sorting */ 2418 newp = NULL; 2419 for (i = 0; i < MBR_PART_COUNT; i++) { 2420 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 2421 continue; 2422 if (m->mbr.mbr_parts[i].mbrp_start != start) 2423 continue; 2424 newp = &m->mbr.mbr_parts[i]; 2425 break; 2426 } 2427 2428 dump_mbr(&parts->mbr, "after adding in primary"); 2429 2430 find_rval: 2431 mbr_calc_free_space(parts); 2432 if (newp == NULL) 2433 return 0; 2434 2435 /* 2436 * Now newp points to the modified partition entry but we do not know 2437 * a good part_id for it. 2438 * Iterate from start and find it. 2439 */ 2440 no = 0; 2441 for (i = 0; i < MBR_PART_COUNT; i++) { 2442 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 2443 continue; 2444 2445 if (newp == &m->mbr.mbr_parts[i]) 2446 return no; 2447 no++; 2448 2449 if (MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) { 2450 for (me = m->extended; me != NULL; me = me->extended) { 2451 for (j = 0; j < MBR_PART_COUNT; j++) { 2452 if (me->mbr.mbr_parts[j].mbrp_type == 2453 MBR_PTYPE_UNUSED) 2454 continue; 2455 if (j > 0 && MBR_IS_EXTENDED( 2456 me->mbr.mbr_parts[j].mbrp_type)) 2457 break; 2458 if (newp == &me->mbr.mbr_parts[j]) 2459 return no; 2460 no++; 2461 } 2462 } 2463 } 2464 } 2465 return 0; 2466 } 2467 2468 static int 2469 mbr_guess_geom(struct disk_partitions *arg, int *cyl, int *head, int *sec) 2470 { 2471 struct mbr_disk_partitions *myparts = (struct mbr_disk_partitions*)arg; 2472 struct mbr_sector *mbrs = &myparts->mbr.mbr; 2473 struct mbr_partition *parts = &mbrs->mbr_parts[0]; 2474 int xcylinders, xheads, i, j; 2475 daddr_t xsectors, xsize; 2476 int c1, h1, s1, c2, h2, s2; 2477 daddr_t a1, a2; 2478 uint64_t num, denom; 2479 2480 xheads = -1; 2481 2482 /* Try to deduce the number of heads from two different mappings. */ 2483 for (i = 0; i < MBR_PART_COUNT * 2 - 1; i++) { 2484 if (get_mapping(parts, i, &c1, &h1, &s1, &a1) < 0) 2485 continue; 2486 a1 -= s1; 2487 for (j = i + 1; j < MBR_PART_COUNT * 2; j++) { 2488 if (get_mapping(parts, j, &c2, &h2, &s2, &a2) < 0) 2489 continue; 2490 a2 -= s2; 2491 num = (uint64_t)h1 * a2 - (quad_t)h2 * a1; 2492 denom = (uint64_t)c2 * a1 - (quad_t)c1 * a2; 2493 if (num != 0 && denom != 0 && num % denom == 0) { 2494 xheads = (int)(num / denom); 2495 xsectors = a1 / (c1 * xheads + h1); 2496 break; 2497 } 2498 } 2499 if (xheads != -1) 2500 break; 2501 } 2502 2503 if (xheads == -1) 2504 return -1; 2505 2506 /* 2507 * Estimate the number of cylinders. 2508 * XXX relies on get_disks having been called. 2509 */ 2510 xsize = min(pm->dlsize, mbr_parts.size_limit); 2511 xcylinders = xsize / xheads / xsectors; 2512 if (xsize != xcylinders * xheads * xsectors) 2513 xcylinders++; 2514 2515 /* 2516 * Now verify consistency with each of the partition table entries. 2517 * Be willing to shove cylinders up a little bit to make things work, 2518 * but translation mismatches are fatal. 2519 */ 2520 for (i = 0; i < MBR_PART_COUNT * 2; i++) { 2521 if (get_mapping(parts, i, &c1, &h1, &s1, &a1) < 0) 2522 continue; 2523 if (c1 >= MAXCYL - 1) 2524 /* Ignore anything that is near the CHS limit */ 2525 continue; 2526 if (xsectors * (c1 * xheads + h1) + s1 != a1) 2527 return -1; 2528 } 2529 2530 /* 2531 * Everything checks out. Reset the geometry to use for further 2532 * calculations. 2533 */ 2534 *cyl = MIN(xcylinders, MAXCYL); 2535 *head = xheads; 2536 *sec = xsectors; 2537 return 0; 2538 } 2539 2540 static size_t 2541 mbr_get_cylinder(const struct disk_partitions *arg) 2542 { 2543 const struct mbr_disk_partitions *parts = 2544 (const struct mbr_disk_partitions*)arg; 2545 2546 return parts->geo_cyl; 2547 } 2548 2549 static daddr_t 2550 mbr_max_part_size(const struct disk_partitions *arg, daddr_t fp_start) 2551 { 2552 const struct mbr_disk_partitions *parts = 2553 (const struct mbr_disk_partitions*)arg; 2554 uint start = fp_start, size = 0; 2555 uint8_t pt; 2556 2557 start = fp_start; 2558 pt = mbr_type_from_start(&parts->mbr, start); 2559 if (find_mbr_space(&parts->mbr, &start, &size, start, 2560 parts->dp.disk_size, start, MBR_IS_EXTENDED(pt)) < 0) 2561 return 0; 2562 2563 return size; 2564 } 2565 2566 static size_t 2567 mbr_get_free_spaces(const struct disk_partitions *arg, 2568 struct disk_part_free_space *result, size_t max_num_result, 2569 daddr_t min_size, daddr_t align, daddr_t lower_bound, daddr_t ignore) 2570 { 2571 const struct mbr_disk_partitions *parts = 2572 (const struct mbr_disk_partitions*)arg; 2573 uint start = 0, size = 0, from, next; 2574 size_t spaces = 0; 2575 2576 if (min_size < 1) 2577 min_size = 1; 2578 from = parts->ptn_0_offset; 2579 if (lower_bound > from) 2580 from = lower_bound; 2581 for ( ; from < parts->dp.disk_size && spaces < max_num_result; ) { 2582 if (find_mbr_space(&parts->mbr, &start, &size, from, 2583 parts->dp.disk_size, ignore > 0 ? (uint)ignore : UINT_MAX, 2584 false) < 0) 2585 break; 2586 next = start + size + 1; 2587 if (align > 0) { 2588 uint nv = max(roundup(start, align), align); 2589 uint off = nv - start; 2590 start = nv; 2591 if (size > off) 2592 size -= off; 2593 else 2594 size = 0; 2595 } 2596 if (size > min_size) { 2597 result[spaces].start = start; 2598 result[spaces].size = size; 2599 spaces++; 2600 } 2601 if ((daddr_t)start + (daddr_t)size + 1 >= mbr_parts.size_limit) 2602 break; 2603 from = next; 2604 } 2605 2606 return spaces; 2607 } 2608 2609 static bool 2610 mbr_can_add_partition(const struct disk_partitions *arg) 2611 { 2612 const struct mbr_disk_partitions *myparts = 2613 (const struct mbr_disk_partitions*)arg; 2614 struct disk_part_free_space space; 2615 bool free_primary, have_extended; 2616 2617 if (arg->free_space < myparts->ptn_alignment) 2618 return false; 2619 2620 if (mbr_get_free_spaces(arg, &space, 1, myparts->ptn_alignment, 2621 myparts->ptn_alignment, 0, -1) < 1) 2622 return false; 2623 2624 for (int i = 0; i < MBR_PART_COUNT; i++) { 2625 uint8_t t = myparts->mbr.mbr.mbr_parts[i].mbrp_type; 2626 2627 if (t == MBR_PTYPE_UNUSED && 2628 myparts->mbr.mbr.mbr_parts[i].mbrp_size == 0) 2629 free_primary = true; 2630 2631 if (MBR_IS_EXTENDED(t)) 2632 have_extended = true; 2633 } 2634 2635 if (have_extended) 2636 return true; 2637 2638 return free_primary; 2639 } 2640 2641 static void 2642 mbr_free_wedge(int *fd, const char *disk, const char *wedge) 2643 { 2644 struct dkwedge_info dkw; 2645 char diskpath[MAXPATHLEN]; 2646 2647 if (*fd == -1) 2648 *fd = opendisk(disk, O_RDWR, diskpath, 2649 sizeof(diskpath), 0); 2650 if (*fd != -1) { 2651 memset(&dkw, 0, sizeof(dkw)); 2652 strlcpy(dkw.dkw_devname, wedge, 2653 sizeof(dkw.dkw_devname)); 2654 ioctl(*fd, DIOCDWEDGE, &dkw); 2655 } 2656 } 2657 2658 static void 2659 mbr_free(struct disk_partitions *arg) 2660 { 2661 struct mbr_disk_partitions *parts = (struct mbr_disk_partitions*)arg; 2662 mbr_info_t *m; 2663 int i, fd; 2664 2665 assert(parts != NULL); 2666 2667 fd = -1; 2668 m = &parts->mbr; 2669 do { 2670 for (i = 0; i < MBR_PART_COUNT; i++) { 2671 if (m->wedge[i][0] != 0) 2672 mbr_free_wedge(&fd, arg->disk, m->wedge[i]); 2673 } 2674 } while ((m = m->extended)); 2675 2676 if (fd != -1) 2677 close(fd); 2678 2679 if (parts->dlabel) 2680 parts->dlabel->pscheme->free(parts->dlabel); 2681 2682 free_mbr_info(parts->mbr.extended); 2683 free_last_mounted(&parts->mbr); 2684 free(__UNCONST(parts->dp.disk)); 2685 free(parts); 2686 } 2687 2688 static void 2689 mbr_destroy_part_scheme(struct disk_partitions *arg) 2690 { 2691 struct mbr_disk_partitions *parts = (struct mbr_disk_partitions*)arg; 2692 char diskpath[MAXPATHLEN]; 2693 int fd; 2694 2695 if (parts->dlabel != NULL) 2696 parts->dlabel->pscheme->destroy_part_scheme(parts->dlabel); 2697 fd = opendisk(arg->disk, O_RDWR, diskpath, sizeof(diskpath), 0); 2698 if (fd != -1) { 2699 char *buf; 2700 2701 buf = calloc(arg->bytes_per_sector, 1); 2702 if (buf != NULL) { 2703 write(fd, buf, arg->bytes_per_sector); 2704 free(buf); 2705 } 2706 close(fd); 2707 } 2708 mbr_free(arg); 2709 } 2710 2711 static bool 2712 mbr_verify_for_update(struct disk_partitions *arg) 2713 { 2714 struct mbr_disk_partitions *parts = 2715 (struct mbr_disk_partitions*)arg; 2716 2717 return md_mbr_update_check(arg, &parts->mbr); 2718 } 2719 2720 static int 2721 mbr_verify(struct disk_partitions *arg, bool quiet) 2722 { 2723 struct mbr_disk_partitions *parts = 2724 (struct mbr_disk_partitions*)arg; 2725 mbr_info_t *m = &parts->mbr; 2726 int i; 2727 bool active_found = false; 2728 2729 for (i = 0; i < MBR_PART_COUNT; i++) { 2730 if (m->mbr.mbr_parts[i].mbrp_flag & MBR_PFLAG_ACTIVE) { 2731 active_found = true; 2732 break; 2733 } 2734 } 2735 2736 if (!active_found && pm->ptstart > 0) { 2737 struct mbr_partition *mp = mbr_ptr_from_start(m, pm->ptstart); 2738 2739 if (mp) { 2740 if (!quiet) 2741 msg_display(MSG_noactivepart); 2742 if (quiet || ask_yesno(MSG_fixactivepart)) { 2743 mp->mbrp_flag |= MBR_PFLAG_ACTIVE; 2744 active_found = true; 2745 } 2746 } 2747 } 2748 if (!active_found && !quiet) { 2749 msg_display(MSG_noactivepart); 2750 i = ask_reedit(arg); 2751 if (i <= 1) 2752 return i; 2753 } 2754 2755 for (i = 0; i < MBR_PART_COUNT; i++) { 2756 if (m->mbr.mbr_parts[i].mbrp_type != MBR_PTYPE_NETBSD) 2757 continue; 2758 m->mbr.mbr_parts[i].mbrp_flag |= MBR_PFLAG_ACTIVE; 2759 break; 2760 } 2761 2762 return md_check_mbr(arg, &parts->mbr, quiet); 2763 } 2764 2765 static bool 2766 mbr_guess_root(const struct disk_partitions *arg, 2767 daddr_t *start, daddr_t *size) 2768 { 2769 const struct mbr_disk_partitions *parts = 2770 (const struct mbr_disk_partitions*)arg; 2771 const mbr_info_t *m = &parts->mbr; 2772 size_t i, num_found; 2773 bool prim = true; 2774 daddr_t pstart, psize; 2775 2776 num_found = 0; 2777 do { 2778 for (i = 0; i < MBR_PART_COUNT; i++) { 2779 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 2780 continue; 2781 2782 if (!prim && i > 0 && 2783 MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) 2784 break; 2785 2786 const struct mbr_partition *mp = &m->mbr.mbr_parts[i]; 2787 if (mp->mbrp_type != MBR_PTYPE_NETBSD) 2788 continue; 2789 2790 if (num_found == 0) { 2791 pstart = m->sector + mp->mbrp_start; 2792 psize = mp->mbrp_size; 2793 } 2794 num_found++; 2795 2796 if (m->last_mounted[i] != NULL && 2797 strcmp(m->last_mounted[i], "/") == 0) { 2798 *start = pstart; 2799 *size = psize; 2800 return true; 2801 } 2802 } 2803 prim = false; 2804 } while ((m = m->extended)); 2805 2806 if (num_found == 1) { 2807 *start = pstart; 2808 *size = psize; 2809 return true; 2810 } 2811 2812 return false; 2813 } 2814 2815 struct part_attr_fmt_data { 2816 char *str; 2817 size_t avail_space, attr_no; 2818 const struct mbr_disk_partitions *parts; 2819 const struct disk_part_info *info; 2820 }; 2821 2822 struct part_attr_set_data { 2823 size_t attr_no; 2824 const struct mbr_disk_partitions *parts; 2825 const char *str; 2826 mbr_info_t *mbr; 2827 }; 2828 2829 static bool 2830 part_attr_fornat_str(const struct disk_partitions *arg, part_id id, 2831 const mbr_info_t *mb, int i, bool primary, 2832 const struct mbr_partition *mp, void *cookie) 2833 { 2834 const struct mbr_disk_partitions *parts = 2835 (const struct mbr_disk_partitions*)arg; 2836 struct part_attr_fmt_data *data = cookie; 2837 const char *attrtype = parts->dp.pscheme 2838 ->custom_attributes[data->attr_no].label; 2839 2840 if (attrtype == MSG_ptn_active) { 2841 strlcpy(data->str, 2842 msg_string(primary && (mp->mbrp_flag & MBR_PFLAG_ACTIVE) ? 2843 MSG_Yes : MSG_No), data->avail_space); 2844 return true; 2845 #if BOOTSEL 2846 } else if (attrtype == MSG_boot_dflt) { 2847 strlcpy(data->str, 2848 msg_string( 2849 (parts->mbr.bootsec == mb->sector+mp->mbrp_start) ? 2850 MSG_Yes : MSG_No), data->avail_space); 2851 return true; 2852 } else if (attrtype == MSG_bootmenu) { 2853 strlcpy(data->str, mb->mbrb.mbrbs_nametab[i], 2854 data->avail_space); 2855 #endif 2856 } 2857 2858 return false; 2859 } 2860 2861 static bool 2862 part_attr_set_str(const struct disk_partitions *arg, part_id id, 2863 const mbr_info_t *mb, int i, bool primary, 2864 const struct mbr_partition *mp, void *cookie) 2865 { 2866 struct part_attr_set_data *data = cookie; 2867 const char *str = data->str; 2868 #ifdef BOOTSEL 2869 const struct mbr_disk_partitions *parts = 2870 (const struct mbr_disk_partitions*)arg; 2871 const char *attrtype = parts->dp.pscheme 2872 ->custom_attributes[data->attr_no].label; 2873 mbr_info_t *m; 2874 #endif 2875 2876 while (*str == ' ') 2877 str++; 2878 2879 #if BOOTSEL 2880 if (attrtype == MSG_bootmenu) { 2881 for (m = data->mbr; m != mb; m = m->extended) 2882 ; 2883 strncpy(m->mbrb.mbrbs_nametab[i], str, 2884 sizeof(m->mbrb.mbrbs_nametab[i])); 2885 } 2886 #endif 2887 2888 return false; 2889 } 2890 2891 static bool 2892 part_attr_toggle(const struct disk_partitions *arg, part_id id, 2893 const mbr_info_t *mb, int i, bool primary, 2894 const struct mbr_partition *mp, void *cookie) 2895 { 2896 const struct mbr_disk_partitions *parts = 2897 (const struct mbr_disk_partitions*)arg; 2898 struct part_attr_set_data *data = cookie; 2899 const char *attrtype = parts->dp.pscheme 2900 ->custom_attributes[data->attr_no].label; 2901 int j; 2902 2903 if (attrtype == MSG_ptn_active) { 2904 if (!primary) 2905 return false; 2906 2907 data->mbr->mbr.mbr_parts[i].mbrp_flag ^= MBR_PFLAG_ACTIVE; 2908 for (j = 0; j < MBR_PART_COUNT; j++) { 2909 if (j == i) 2910 continue; 2911 data->mbr->mbr.mbr_parts[j].mbrp_flag 2912 &= ~MBR_PFLAG_ACTIVE; 2913 } 2914 return true; 2915 #ifdef BOOTSEL 2916 } else if (attrtype == MSG_boot_dflt) { 2917 if (data->mbr->bootsec == mb->sector+mp->mbrp_start) 2918 data->mbr->bootsec = 0; 2919 else 2920 data->mbr->bootsec = mb->sector+mp->mbrp_start; 2921 return true; 2922 #endif 2923 } 2924 2925 return false; 2926 } 2927 2928 static bool 2929 mbr_custom_attribute_format(const struct disk_partitions *arg, 2930 part_id id, size_t attr_no, const struct disk_part_info *info, 2931 char *res, size_t space) 2932 { 2933 const struct mbr_disk_partitions *parts = 2934 (const struct mbr_disk_partitions*)arg; 2935 struct part_attr_fmt_data data; 2936 2937 data.str = res; 2938 data.avail_space = space; 2939 data.attr_no = attr_no; 2940 data.parts = parts; 2941 data.info = info; 2942 2943 return mbr_part_apply(arg, id, part_attr_fornat_str, &data); 2944 } 2945 2946 static bool 2947 mbr_custom_attribute_toggle(struct disk_partitions *arg, 2948 part_id id, size_t attr_no) 2949 { 2950 struct mbr_disk_partitions *parts = 2951 (struct mbr_disk_partitions*)arg; 2952 struct part_attr_set_data data; 2953 2954 data.attr_no = attr_no; 2955 data.parts = parts; 2956 data.str = NULL; 2957 #ifdef BOOTSEL 2958 data.mbr = &parts->mbr; 2959 #endif 2960 2961 return mbr_part_apply(arg, id, part_attr_toggle, &data); 2962 } 2963 2964 static bool 2965 mbr_custom_attribute_set_str(struct disk_partitions *arg, 2966 part_id id, size_t attr_no, const char *new_val) 2967 { 2968 struct mbr_disk_partitions *parts = 2969 (struct mbr_disk_partitions*)arg; 2970 struct part_attr_set_data data; 2971 2972 data.attr_no = attr_no; 2973 data.parts = parts; 2974 data.str = new_val; 2975 #ifdef BOOTSEL 2976 data.mbr = &parts->mbr; 2977 #endif 2978 2979 return mbr_part_apply(arg, id, part_attr_set_str, &data); 2980 } 2981 2982 static daddr_t 2983 mbr_part_alignment(const struct disk_partitions *arg) 2984 { 2985 const struct mbr_disk_partitions *parts = 2986 (const struct mbr_disk_partitions*)arg; 2987 2988 return parts->ptn_alignment; 2989 } 2990 2991 static bool 2992 add_wedge(const char *disk, daddr_t start, daddr_t size, 2993 char *wname, size_t max_len) 2994 { 2995 struct dkwedge_info dkw; 2996 char diskpath[MAXPATHLEN]; 2997 int fd; 2998 2999 memset(&dkw, 0, sizeof(dkw)); 3000 dkw.dkw_offset = start; 3001 dkw.dkw_size = size; 3002 snprintf((char*)dkw.dkw_wname, sizeof dkw.dkw_wname, 3003 "%s_%" PRIi64 "@%" PRIi64, disk, size, start); 3004 3005 *wname = 0; 3006 3007 fd = opendisk(disk, O_RDWR, diskpath, sizeof(diskpath), 0); 3008 if (fd < 0) 3009 return false; 3010 if (ioctl(fd, DIOCAWEDGE, &dkw) == -1) { 3011 close(fd); 3012 return false; 3013 } 3014 close(fd); 3015 strlcpy(wname, dkw.dkw_devname, max_len); 3016 return true; 3017 } 3018 3019 static bool 3020 mbr_get_part_device(const struct disk_partitions *arg, 3021 part_id ptn, char *devname, size_t max_devname_len, int *part, 3022 enum dev_name_usage usage, bool with_path, bool life) 3023 { 3024 const struct mbr_disk_partitions *parts = 3025 (const struct mbr_disk_partitions*)arg; 3026 struct disk_part_info info, tmp; 3027 part_id dptn; 3028 char *wedge_dev; 3029 3030 if (!mbr_get_part_info(arg, ptn, &info)) 3031 return false; 3032 3033 if (!mbr_part_get_wedge(arg, ptn, &wedge_dev) || wedge_dev == NULL) 3034 return false; 3035 3036 if (wedge_dev[0] == 0) { 3037 /* 3038 * If we have secondary partitions, try to find a match there 3039 * and use that... 3040 */ 3041 if (parts->dlabel != NULL) { 3042 for (dptn = 0; dptn < parts->dlabel->num_part; dptn++) { 3043 if (!parts->dlabel->pscheme->get_part_info( 3044 parts->dlabel, dptn, &tmp)) 3045 continue; 3046 if (tmp.start != info.start || 3047 tmp.size != info.size) 3048 continue; 3049 return parts->dlabel->pscheme->get_part_device( 3050 parts->dlabel, dptn, devname, 3051 max_devname_len, 3052 part, usage, with_path, life); 3053 } 3054 } 3055 3056 /* 3057 * Configure a new wedge and remember the name 3058 */ 3059 if (!add_wedge(arg->disk, info.start, info.size, wedge_dev, 3060 MBR_DEV_LEN)) 3061 return false; 3062 } 3063 3064 assert(wedge_dev[0] != 0); 3065 3066 switch (usage) { 3067 case logical_name: 3068 case plain_name: 3069 if (with_path) 3070 snprintf(devname, max_devname_len, _PATH_DEV "%s", 3071 wedge_dev); 3072 else 3073 strlcpy(devname, wedge_dev, max_devname_len); 3074 return true; 3075 case raw_dev_name: 3076 if (with_path) 3077 snprintf(devname, max_devname_len, _PATH_DEV "r%s", 3078 wedge_dev); 3079 else 3080 snprintf(devname, max_devname_len, "r%s", 3081 wedge_dev); 3082 return true; 3083 default: 3084 return false; 3085 } 3086 } 3087 3088 static bool 3089 is_custom_attribute_writable(const struct disk_partitions *arg, part_id id, 3090 const mbr_info_t *mb, int i, bool primary, 3091 const struct mbr_partition *mp, void *cookie) 3092 { 3093 const struct mbr_disk_partitions *parts = 3094 (const struct mbr_disk_partitions*)arg; 3095 struct part_attr_set_data *data = cookie; 3096 const char *attrtype = parts->dp.pscheme 3097 ->custom_attributes[data->attr_no].label; 3098 3099 if (attrtype == MSG_ptn_active) 3100 /* Only 'normal' partitions can be 'Active' */ 3101 return primary && !MBR_IS_EXTENDED(mp->mbrp_type); 3102 #ifdef BOOTSEL 3103 else if (attrtype == MSG_boot_dflt) 3104 /* Only partitions with bootmenu names can be default */ 3105 return mb->mbrb.mbrbs_nametab[i][0] != 0; 3106 else if (attrtype == MSG_bootmenu) 3107 /* The extended partition isn't bootable */ 3108 return !MBR_IS_EXTENDED(mp->mbrp_type); 3109 #endif 3110 3111 return false; 3112 } 3113 3114 static bool 3115 mbr_custom_attribute_writable(const struct disk_partitions *arg, 3116 part_id id, size_t attr_no) 3117 { 3118 const struct mbr_disk_partitions *parts = 3119 (const struct mbr_disk_partitions*)arg; 3120 struct part_attr_set_data data; 3121 3122 data.attr_no = attr_no; 3123 data.parts = parts; 3124 data.str = NULL; 3125 #ifdef BOOTSEL 3126 data.mbr = NULL; 3127 #endif 3128 3129 return mbr_part_apply(arg, id, is_custom_attribute_writable, &data); 3130 } 3131 3132 const struct disk_part_edit_column_desc mbr_edit_columns[] = { 3133 { .title = MSG_mbr_part_header_1, 3134 #if BOOTSEL 3135 .width = 16U 3136 #else 3137 .width = 26U 3138 #endif 3139 }, 3140 { .title = MSG_mbr_part_header_2, .width = 8U }, 3141 #if BOOTSEL 3142 { .title = MSG_mbr_part_header_3, .width = 9U }, 3143 #endif 3144 }; 3145 3146 const struct disk_part_custom_attribute mbr_custom_attrs[] = { 3147 { .label = MSG_ptn_active, .type = pet_bool }, 3148 #if BOOTSEL 3149 { .label = MSG_boot_dflt, .type = pet_bool }, 3150 { .label = MSG_bootmenu, .type = pet_str, 3151 .strlen = MBR_BS_PARTNAMESIZE }, 3152 #endif 3153 }; 3154 3155 const struct disk_partitioning_scheme 3156 mbr_parts = { 3157 .name = MSG_parttype_mbr, 3158 .short_name = MSG_parttype_mbr_short, 3159 .new_type_prompt = MSG_mbr_get_ptn_id, 3160 .part_flag_desc = MSG_mbr_flag_desc, 3161 .size_limit = (daddr_t)UINT32_MAX, 3162 .secondary_scheme = &disklabel_parts, 3163 .edit_columns_count = __arraycount(mbr_edit_columns), 3164 .edit_columns = mbr_edit_columns, 3165 .custom_attribute_count = __arraycount(mbr_custom_attrs), 3166 .custom_attributes = mbr_custom_attrs, 3167 .get_part_alignment = mbr_part_alignment, 3168 .get_part_info = mbr_get_part_info, 3169 .get_part_attr_str = mbr_part_attr_str, 3170 .format_partition_table_str = mbr_table_str, 3171 .part_type_can_change = mbr_part_type_can_change, 3172 .can_add_partition = mbr_can_add_partition, 3173 .custom_attribute_writable = mbr_custom_attribute_writable, 3174 .format_custom_attribute = mbr_custom_attribute_format, 3175 .custom_attribute_toggle = mbr_custom_attribute_toggle, 3176 .custom_attribute_set_str = mbr_custom_attribute_set_str, 3177 .get_part_types_count = mbr_get_part_type_count, 3178 .adapt_foreign_part_info = generic_adapt_foreign_part_info, 3179 .get_part_type = mbr_get_part_type, 3180 .get_fs_part_type = mbr_get_fs_part_type, 3181 .get_generic_part_type = mbr_get_generic_part_type, 3182 .create_custom_part_type = mbr_custom_part_type, 3183 .create_unknown_part_type = mbr_create_unknown_part_type, 3184 .secondary_partitions = mbr_read_disklabel, 3185 .write_to_disk = mbr_write_to_disk, 3186 .read_from_disk = mbr_read_from_disk, 3187 .create_new_for_disk = mbr_create_new, 3188 .guess_disk_geom = mbr_guess_geom, 3189 .get_cylinder_size = mbr_get_cylinder, 3190 .change_disk_geom = mbr_change_disk_geom, 3191 .get_part_device = mbr_get_part_device, 3192 .max_free_space_at = mbr_max_part_size, 3193 .get_free_spaces = mbr_get_free_spaces, 3194 .set_part_info = mbr_set_part_info, 3195 .delete_all_partitions = mbr_delete_all, 3196 .delete_partition = mbr_delete_part, 3197 .add_partition = mbr_add_part, 3198 .guess_install_target = mbr_guess_root, 3199 .post_edit_verify = mbr_verify, 3200 .pre_update_verify = mbr_verify_for_update, 3201 .free = mbr_free, 3202 .destroy_part_scheme = mbr_destroy_part_scheme, 3203 }; 3204 3205 #endif 3206