1 /* $NetBSD: mbr.c,v 1.38 2021/01/31 22:45:46 rillig 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 break; 1404 case MBR_PTYPE_LNXEXT2: 1405 info->fs_type = FS_EX2FS; 1406 break; 1407 case MBR_PTYPE_XENIX_ROOT: 1408 case MBR_PTYPE_XENIX_USR: 1409 info->fs_type = FS_SYSV; 1410 break; 1411 case MBR_PTYPE_NTFS: 1412 info->fs_type = FS_NTFS; 1413 break; 1414 case MBR_PTYPE_APPLE_HFS: 1415 info->fs_type = FS_HFS; 1416 break; 1417 case MBR_PTYPE_VMWARE: 1418 info->fs_type = FS_VMFS; 1419 break; 1420 case MBR_PTYPE_AST_SWAP: 1421 case MBR_PTYPE_DRDOS_LSWAP: 1422 case MBR_PTYPE_LNXSWAP: 1423 case MBR_PTYPE_BSDI_SWAP: 1424 case MBR_PTYPE_HID_LNX_SWAP: 1425 case MBR_PTYPE_VMWARE_SWAP: 1426 info->fs_type = FS_SWAP; 1427 break; 1428 } 1429 } 1430 return true; 1431 } 1432 1433 static bool 1434 get_wedge_devname(const struct disk_partitions *arg, part_id id, 1435 const mbr_info_t *mb, int i, bool primary, 1436 const struct mbr_partition *mp, void *cookie) 1437 { 1438 char **res = cookie; 1439 1440 if (!res) 1441 return false; 1442 1443 *res = __UNCONST(mb->wedge[i]); 1444 return true; 1445 } 1446 1447 static bool 1448 mbr_part_get_wedge(const struct disk_partitions *arg, part_id id, 1449 char **res) 1450 { 1451 return mbr_part_apply(arg, id, get_wedge_devname, res); 1452 } 1453 1454 static bool 1455 mbr_get_part_info(const struct disk_partitions *arg, part_id id, 1456 struct disk_part_info *info) 1457 { 1458 return mbr_part_apply(arg, id, mbr_do_get_part_info, info); 1459 } 1460 1461 static bool 1462 type_can_change(const struct disk_partitions *arg, part_id id, 1463 const mbr_info_t *mb, int i, bool primary, 1464 const struct mbr_partition *mp, void *cookie) 1465 { 1466 /* 1467 * The extended partition can only change type or be 1468 * deleted if it is empty 1469 */ 1470 if (!MBR_IS_EXTENDED(mp->mbrp_type)) 1471 return true; 1472 return primary && mb->extended == NULL; 1473 } 1474 1475 static bool 1476 mbr_part_type_can_change(const struct disk_partitions *arg, part_id id) 1477 { 1478 return mbr_part_apply(arg, id, type_can_change, NULL); 1479 } 1480 1481 struct part_get_str_data { 1482 char *str; 1483 size_t avail_space; 1484 size_t col; 1485 }; 1486 1487 1488 static bool 1489 mbr_get_part_table_str(const struct disk_partitions *arg, part_id id, 1490 const mbr_info_t *mb, int i, bool primary, 1491 const struct mbr_partition *mp, void *cookie) 1492 { 1493 struct part_get_str_data *data = cookie; 1494 char *str = data->str; 1495 const struct part_type_desc *ptype; 1496 1497 switch (data->col) { 1498 case 0: 1499 ptype = mbr_get_gen_type_desc(mp->mbrp_type); 1500 if (ptype != NULL) 1501 strncpy(str, ptype->description, data->avail_space); 1502 else 1503 snprintf(str, data->avail_space, "%u", mp->mbrp_type); 1504 str[data->avail_space-1] = 0; 1505 break; 1506 case 1: 1507 if (mb->last_mounted[i]) 1508 strlcpy(str, mb->last_mounted[i], data->avail_space); 1509 else 1510 *str = 0; 1511 break; 1512 #ifdef BOOTSEL 1513 case 2: 1514 if (mb->mbrb.mbrbs_nametab[i][0] != 0) 1515 strlcpy(str, mb->mbrb.mbrbs_nametab[i], 1516 data->avail_space); 1517 else 1518 *str = 0; 1519 break; 1520 #endif 1521 } 1522 1523 return true; 1524 } 1525 1526 static bool 1527 mbr_table_str(const struct disk_partitions *arg, part_id id, size_t col, 1528 char *str, size_t avail_space) 1529 { 1530 struct part_get_str_data data; 1531 1532 data.str = str; 1533 data.avail_space = avail_space; 1534 data.col = col; 1535 return mbr_part_apply(arg, id, mbr_get_part_table_str, &data); 1536 } 1537 1538 static bool 1539 mbr_get_part_attr_str(const struct disk_partitions *arg, part_id id, 1540 const mbr_info_t *mb, int i, bool primary, 1541 const struct mbr_partition *mp, void *cookie) 1542 { 1543 #ifdef BOOTSEL 1544 const struct mbr_disk_partitions *parts = 1545 (const struct mbr_disk_partitions*)arg; 1546 #endif 1547 struct part_get_str_data *data = cookie; 1548 static const char *flags = NULL; 1549 char *str = data->str; 1550 1551 if (flags == NULL) 1552 flags = msg_string(MSG_mbr_flags); 1553 1554 if (mp->mbrp_flag & MBR_PFLAG_ACTIVE) 1555 *str++ = flags[0]; 1556 #ifdef BOOTSEL 1557 if (parts->mbr.bootsec == mb->sector+mp->mbrp_start) 1558 *str++ = flags[1]; 1559 #endif 1560 *str = 0; 1561 return true; 1562 } 1563 1564 static bool 1565 mbr_part_attr_str(const struct disk_partitions *arg, part_id id, 1566 char *str, size_t avail_space) 1567 { 1568 struct part_get_str_data data; 1569 1570 if (avail_space < 3) 1571 return false; 1572 1573 data.str = str; 1574 data.avail_space = avail_space; 1575 return mbr_part_apply(arg, id, mbr_get_part_attr_str, &data); 1576 } 1577 1578 static bool 1579 mbr_info_to_partitition(const struct disk_part_info *info, 1580 struct mbr_partition *mp, uint sector, 1581 struct mbr_info_t *mb, size_t index, const char **err_msg) 1582 { 1583 size_t pt = mbr_type_from_gen_desc(info->nat_type); 1584 if (info->start + info->size > UINT_MAX 1585 || pt > __arraycount(mbr_gen_type_desc)) { 1586 if (err_msg) 1587 *err_msg = err_outofmem; 1588 return false; 1589 } 1590 mp->mbrp_start = info->start - sector; 1591 mp->mbrp_size = info->size; 1592 mp->mbrp_type = pt; 1593 if (info->flags & PTI_INSTALL_TARGET) { 1594 mp->mbrp_flag |= MBR_PFLAG_ACTIVE; 1595 #ifdef BOOTSEL 1596 strcpy(mb->mbrb.mbrbs_nametab[index], "NetBSD"); 1597 #endif 1598 } 1599 1600 return true; 1601 } 1602 1603 static bool 1604 inside_ext_part(mbr_info_t *m, daddr_t start) 1605 { 1606 size_t i; 1607 struct mbr_partition *mp = NULL; 1608 1609 for (i = 0; i < MBR_PART_COUNT; i++) { 1610 if (!MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) 1611 continue; 1612 mp = &m->mbr.mbr_parts[i]; 1613 break; 1614 } 1615 1616 if (mp == NULL) { 1617 assert(false); 1618 return false; 1619 } 1620 1621 if (mp->mbrp_start > start) 1622 return false; 1623 1624 return true; 1625 } 1626 1627 static void 1628 adjust_ext_part(mbr_info_t *m, daddr_t start, daddr_t size) 1629 { 1630 size_t i; 1631 struct mbr_partition *mp = NULL; 1632 1633 for (i = 0; i < MBR_PART_COUNT; i++) { 1634 if (!MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) 1635 continue; 1636 mp = &m->mbr.mbr_parts[i]; 1637 break; 1638 } 1639 1640 if (mp == NULL) { 1641 assert(false); 1642 return; 1643 } 1644 1645 if (mp->mbrp_start + mp->mbrp_size >= start + size) 1646 return; 1647 1648 daddr_t new_end = start + size; 1649 mp->mbrp_size = new_end - mp->mbrp_start; 1650 } 1651 1652 static bool 1653 ext_part_good(mbr_info_t *m, daddr_t ext_start, daddr_t ext_size) 1654 { 1655 for (m = m->extended; m != NULL; m = m->extended) { 1656 for (size_t i = 0; i < MBR_PART_COUNT; i++) { 1657 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 1658 continue; 1659 1660 if (i > 0 && 1661 MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) 1662 break; 1663 1664 daddr_t pstart = m->mbr.mbr_parts[i].mbrp_start + 1665 m->sector; 1666 daddr_t pend = pstart + m->mbr.mbr_parts[i].mbrp_size; 1667 1668 if (pstart < ext_start || pend > ext_start+ext_size) 1669 return false; 1670 } 1671 } 1672 1673 return true; 1674 } 1675 1676 static bool 1677 mbr_set_part_info(struct disk_partitions *arg, part_id id, 1678 const struct disk_part_info *info, const char **err_msg) 1679 { 1680 struct mbr_disk_partitions *parts = 1681 (struct mbr_disk_partitions*)arg; 1682 struct disk_part_info data = *info; 1683 part_id i, j, no, ext_ndx, t; 1684 mbr_info_t *m = &parts->mbr, *me; 1685 uint pt = mbr_type_from_gen_desc(info->nat_type); 1686 1687 if (MBR_IS_EXTENDED(pt)) { 1688 /* check for duplicate ext part */ 1689 no = 0; 1690 t = ext_ndx = MBR_PART_COUNT; 1691 for (i = 0; i < MBR_PART_COUNT; i++) { 1692 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 1693 continue; 1694 if (MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) 1695 ext_ndx = i; 1696 if (no == id) 1697 t = i; 1698 no++; 1699 } 1700 if (ext_ndx < MBR_PART_COUNT && t != ext_ndx) { 1701 if (err_msg) 1702 *err_msg = 1703 msg_string(MSG_Only_one_extended_ptn); 1704 return false; 1705 } 1706 /* this partition becomes an extended one, apply alignment */ 1707 data.start = max(roundup(data.start, parts->ext_ptn_alignment), 1708 parts->ext_ptn_alignment); 1709 } 1710 1711 no = 0; 1712 for (i = 0; i < MBR_PART_COUNT; i++) { 1713 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 1714 continue; 1715 1716 if (no == id) 1717 goto found; 1718 no++; 1719 1720 if (MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) { 1721 for (me = m->extended; me != NULL; me = me->extended) { 1722 for (j = 0; j < MBR_PART_COUNT; j++) { 1723 if (me->mbr.mbr_parts[j].mbrp_type == 1724 MBR_PTYPE_UNUSED) 1725 continue; 1726 if (j > 0 && MBR_IS_EXTENDED( 1727 me->mbr.mbr_parts[j].mbrp_type)) 1728 break; 1729 if (no == id) { 1730 i = j; 1731 m = me; 1732 goto found; 1733 } 1734 no++; 1735 } 1736 } 1737 } 1738 } 1739 1740 if (err_msg) 1741 *err_msg = INTERNAL_ERROR; 1742 return false; 1743 1744 found: 1745 /* 1746 * We assume that m is the mbr we want to update and 1747 * i is the local partition index into it. 1748 */ 1749 if (m == &parts->mbr) { 1750 if (MBR_IS_EXTENDED( 1751 m->mbr.mbr_parts[i].mbrp_type) && 1752 !ext_part_good(&parts->mbr, data.start, data.size)) { 1753 if (err_msg) 1754 *err_msg = 1755 MSG_mbr_ext_nofit; 1756 return false; 1757 } 1758 } else if (!inside_ext_part(&parts->mbr, data.start)) { 1759 if (err_msg) 1760 *err_msg = msg_string(MSG_mbr_inside_ext); 1761 return false; 1762 } 1763 uint start = data.start, size = data.size; 1764 uint oldstart = m->mbr.mbr_parts[i].mbrp_start + m->sector; 1765 if (parts->ptn_0_offset > 0 && 1766 start < parts->ptn_0_offset) 1767 start = parts->ptn_0_offset; 1768 if (find_mbr_space(m, &start, &size, start, parts->dp.disk_size, 1769 oldstart, false) < 0) { 1770 if (err_msg != NULL) 1771 *err_msg = INTERNAL_ERROR; 1772 return false; 1773 } 1774 data.start = start; 1775 if (size < data.size) 1776 data.size = size; 1777 uint old_start = m->mbr.mbr_parts[i].mbrp_start; 1778 if (!mbr_info_to_partitition(&data, 1779 &m->mbr.mbr_parts[i], m->sector, m, i, err_msg)) 1780 return false; 1781 if (data.flags & PTI_INSTALL_TARGET) 1782 parts->target = start; 1783 else if (old_start == parts->target) 1784 parts->target = -1; 1785 if (data.last_mounted && m->last_mounted[i] && 1786 data.last_mounted != m->last_mounted[i]) { 1787 free(__UNCONST(m->last_mounted[i])); 1788 m->last_mounted[i] = strdup(data.last_mounted); 1789 } 1790 if (data.fs_type != 0) 1791 m->fs_type[i] = data.fs_type; 1792 if (data.fs_sub_type != 0) 1793 m->fs_sub_type[i] = data.fs_sub_type; 1794 1795 if (m == &parts->mbr) { 1796 if (m->mbr.mbr_parts[i].mbrp_start != 1797 old_start) 1798 mbr_sort_main_mbr(&m->mbr); 1799 } else { 1800 adjust_ext_part(&parts->mbr, 1801 data.start, data.size); 1802 } 1803 mbr_calc_free_space(parts); 1804 return true; 1805 } 1806 1807 static bool 1808 mbr_find_netbsd(const struct mbr_info_t *m, uint start, 1809 struct disk_part_info *info) 1810 { 1811 size_t i; 1812 bool prim = true; 1813 1814 do { 1815 for (i = 0; i < MBR_PART_COUNT; i++) { 1816 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 1817 continue; 1818 1819 if (!prim && i > 0 && 1820 MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) 1821 break; 1822 1823 const struct mbr_partition *mp = &m->mbr.mbr_parts[i]; 1824 if (mp->mbrp_type != MBR_PTYPE_NETBSD) 1825 continue; 1826 1827 mbr_partition_to_info(mp, m->sector, info); 1828 if (m->last_mounted[i] && *m->last_mounted[i] != 0) 1829 info->last_mounted = 1830 m->last_mounted[i]; 1831 info->fs_type = m->fs_type[i]; 1832 info->fs_sub_type = m->fs_sub_type[i]; 1833 if (start > 0 && start != info->start) 1834 continue; 1835 return true; 1836 } 1837 prim = false; 1838 } while ((m = m->extended)); 1839 1840 return false; 1841 } 1842 1843 static struct disk_partitions * 1844 mbr_read_disklabel(struct disk_partitions *arg, daddr_t start, bool force_empty) 1845 { 1846 struct mbr_disk_partitions *myparts = 1847 (struct mbr_disk_partitions*)arg; 1848 struct disk_part_info part; 1849 struct disk_part_free_space space; 1850 1851 if (force_empty && myparts->dlabel) 1852 myparts->dlabel->pscheme->delete_all_partitions( 1853 myparts->dlabel); 1854 1855 if (myparts->dlabel == NULL) { 1856 /* 1857 * Find the NetBSD MBR partition 1858 */ 1859 if (!mbr_find_netbsd(&myparts->mbr, start, &part)) { 1860 if (!force_empty) 1861 return NULL; 1862 1863 /* add a "whole disk" NetBSD partition */ 1864 memset(&part, 0, sizeof part); 1865 part.start = min(myparts->ptn_0_offset,start); 1866 if (!mbr_get_free_spaces(arg, &space, 1, 1867 part.start, myparts->ptn_alignment, -1, -1)) 1868 return NULL; 1869 part.start = space.start; 1870 part.size = space.size; 1871 part.nat_type = &mbr_gen_type_desc[MBR_PTYPE_NETBSD].gen; 1872 mbr_add_part(arg, &part, NULL); 1873 if (!mbr_find_netbsd(&myparts->mbr, start, &part)) 1874 return NULL; 1875 } 1876 1877 if (!force_empty) { 1878 myparts->dlabel = disklabel_parts.read_from_disk( 1879 myparts->dp.disk, part.start, part.size, 1880 myparts->dp.bytes_per_sector, &disklabel_parts); 1881 if (myparts->dlabel != NULL) 1882 myparts->dlabel->parent = &myparts->dp; 1883 } 1884 1885 if (myparts->dlabel == NULL && part.size > 0) { 1886 /* we just created the outer partitions? */ 1887 myparts->dlabel = 1888 disklabel_parts.create_new_for_disk( 1889 myparts->dp.disk, part.start, part.size, 1890 false, &myparts->dp); 1891 } 1892 1893 if (myparts->dlabel != NULL) 1894 myparts->dlabel->pscheme->change_disk_geom( 1895 myparts->dlabel, myparts->geo_cyl, 1896 myparts->geo_head, myparts->geo_sec); 1897 } 1898 return myparts->dlabel; 1899 } 1900 1901 static int 1902 get_mapping(struct mbr_partition *parts, int i, 1903 int *cylinder, int *head, int *sector, daddr_t *absolute) 1904 { 1905 struct mbr_partition *apart = &parts[i / 2]; 1906 1907 if (apart->mbrp_type == MBR_PTYPE_UNUSED) 1908 return -1; 1909 if (i % 2 == 0) { 1910 *cylinder = MBR_PCYL(apart->mbrp_scyl, apart->mbrp_ssect); 1911 *head = apart->mbrp_shd; 1912 *sector = MBR_PSECT(apart->mbrp_ssect) - 1; 1913 *absolute = le32toh(apart->mbrp_start); 1914 } else { 1915 *cylinder = MBR_PCYL(apart->mbrp_ecyl, apart->mbrp_esect); 1916 *head = apart->mbrp_ehd; 1917 *sector = MBR_PSECT(apart->mbrp_esect) - 1; 1918 *absolute = le32toh(apart->mbrp_start) 1919 + le32toh(apart->mbrp_size) - 1; 1920 } 1921 /* Sanity check the data against max values */ 1922 if ((((*cylinder * MAXHEAD) + *head) * (uint32_t)MAXSECTOR + *sector) < *absolute) 1923 /* cannot be a CHS mapping */ 1924 return -1; 1925 1926 return 0; 1927 } 1928 1929 static bool 1930 mbr_delete_all(struct disk_partitions *arg) 1931 { 1932 struct mbr_disk_partitions *myparts = (struct mbr_disk_partitions*)arg; 1933 struct mbr_sector *mbrs = &myparts->mbr.mbr; 1934 struct mbr_info_t *mbri = &myparts->mbr; 1935 mbr_info_t *ext; 1936 struct mbr_partition *part; 1937 1938 part = &mbrs->mbr_parts[0]; 1939 /* Set the partition information for full disk usage. */ 1940 while ((ext = mbri->extended)) { 1941 mbri->extended = ext->extended; 1942 free_mbr_info(ext); 1943 } 1944 memset(part, 0, MBR_PART_COUNT * sizeof *part); 1945 #ifdef BOOTSEL 1946 memset(&mbri->mbrb, 0, sizeof mbri->mbrb); 1947 #endif 1948 1949 /* 1950 * We may have changed alignment settings due to partitions 1951 * ending on an MB boundary - undo that, now that the partitions 1952 * are gone. 1953 */ 1954 mbr_change_disk_geom(arg, myparts->geo_cyl, myparts->geo_head, 1955 myparts->geo_sec); 1956 1957 return true; 1958 } 1959 1960 /* 1961 * helper function to fix up mbrp_start and mbrp_size for the 1962 * extended MBRs "partition b" entries after addition/deletion 1963 * of some partition. 1964 */ 1965 static void 1966 mbr_fixup_ext_chain(mbr_info_t *primary, uint ext_start, uint ext_end) 1967 { 1968 for (mbr_info_t *m = primary->extended; m != NULL; m = m->extended) { 1969 if (m->extended == NULL) { 1970 m->mbr.mbr_parts[1].mbrp_type = MBR_PTYPE_UNUSED; 1971 m->mbr.mbr_parts[1].mbrp_start = 0; 1972 m->mbr.mbr_parts[1].mbrp_size = 0; 1973 } else { 1974 uint n_end, n_start = m->extended->sector; 1975 if (m->extended->extended) 1976 n_end = m->extended->extended->sector; 1977 else 1978 n_end = ext_end; 1979 m->mbr.mbr_parts[1].mbrp_type = MBR_PTYPE_EXT; 1980 m->mbr.mbr_parts[1].mbrp_start = n_start - ext_start; 1981 m->mbr.mbr_parts[1].mbrp_size = n_end - n_start; 1982 } 1983 } 1984 } 1985 1986 struct delete_part_args { 1987 struct mbr_disk_partitions *parts; 1988 daddr_t start, size; 1989 const char **err_msg; 1990 }; 1991 1992 static bool 1993 mbr_do_delete_part(const struct disk_partitions *arg, part_id id, 1994 const mbr_info_t *mb, int i, bool primary, 1995 const struct mbr_partition *mp, void *cookie) 1996 { 1997 struct delete_part_args *marg = cookie; 1998 bool is_ext_part = MBR_IS_EXTENDED(mp->mbrp_type); 1999 2000 /* can not delete non-empty extended partitions */ 2001 if (MBR_IS_EXTENDED(mp->mbrp_type) 2002 && marg->parts->mbr.extended != NULL) { 2003 if (marg->err_msg) 2004 *marg->err_msg = msg_string(MSG_mbr_ext_not_empty); 2005 return false; 2006 } 2007 2008 /* return position/size to caller */ 2009 marg->start = mb->sector + mp->mbrp_start; 2010 marg->size = mp->mbrp_size; 2011 2012 if (primary) { 2013 /* if deleting the primary extended partition, just kill it */ 2014 struct mbr_partition *md = &marg->parts->mbr.mbr.mbr_parts[i]; 2015 md->mbrp_size = 0; 2016 md->mbrp_start = 0; 2017 md->mbrp_type = MBR_PTYPE_UNUSED; 2018 if (marg->parts->mbr.last_mounted[i]) { 2019 free(__UNCONST(marg->parts->mbr.last_mounted[i])); 2020 marg->parts->mbr.last_mounted[i] = NULL; 2021 } 2022 if (is_ext_part) { 2023 for (mbr_info_t *m = marg->parts->mbr.extended; 2024 m != NULL; ) { 2025 mbr_info_t *n = m->extended; 2026 free_mbr_info(m); 2027 m = n; 2028 } 2029 marg->parts->mbr.extended = NULL; 2030 } 2031 } else { 2032 /* find the size of the primary extended partition */ 2033 uint ext_start = 0, ext_size = 0; 2034 for (i = 0; i < MBR_PART_COUNT; i++) { 2035 if (!MBR_IS_EXTENDED(marg->parts->mbr.mbr.mbr_parts[i] 2036 .mbrp_type)) 2037 continue; 2038 ext_start = marg->parts->mbr.mbr.mbr_parts[i] 2039 .mbrp_start; 2040 ext_size = marg->parts->mbr.mbr.mbr_parts[i] 2041 .mbrp_size; 2042 break; 2043 } 2044 2045 /* 2046 * If we are in an extended partition chain, unlink this MBR, 2047 * unless it is the very first one at the start of the extended 2048 * partition (we would have no previos ext mbr to fix up 2049 * the chain in that case) 2050 */ 2051 if (marg->parts->mbr.extended == mb) { 2052 struct mbr_partition *part = 2053 &marg->parts->mbr.extended->mbr.mbr_parts[0]; 2054 part->mbrp_type = MBR_PTYPE_UNUSED; 2055 part->mbrp_start = 0; 2056 part->mbrp_size = 0; 2057 } else { 2058 mbr_info_t *p, *last; 2059 for (last = NULL, p = &marg->parts->mbr; p != NULL; 2060 last = p, p = p->extended) 2061 if (p == mb) 2062 break; 2063 if (last == NULL) { 2064 if (marg->err_msg != NULL) 2065 *marg->err_msg= INTERNAL_ERROR; 2066 return false; 2067 } 2068 last->extended = p->extended; 2069 free_mbr_info(p); 2070 if (last == &marg->parts->mbr && last->extended && 2071 last->extended->extended == NULL && 2072 last->extended->mbr.mbr_parts[0].mbrp_type == 2073 MBR_PTYPE_UNUSED) { 2074 /* 2075 * we deleted the last extended sector, 2076 * remove the whole chain 2077 */ 2078 free_mbr_info(last->extended); 2079 last->extended = NULL; 2080 } 2081 } 2082 mbr_fixup_ext_chain(&marg->parts->mbr, ext_start, 2083 ext_start+ext_size); 2084 } 2085 mbr_calc_free_space(marg->parts); 2086 return true; 2087 } 2088 2089 static bool 2090 mbr_delete_part(struct disk_partitions *arg, part_id pno, const char **err_msg) 2091 { 2092 struct mbr_disk_partitions *parts = 2093 (struct mbr_disk_partitions*)arg; 2094 struct delete_part_args data = { .parts = parts, .err_msg = err_msg }; 2095 2096 if (!mbr_part_apply(arg, pno, mbr_do_delete_part, &data)) { 2097 if (err_msg) 2098 *err_msg = INTERNAL_ERROR; 2099 return false; 2100 } 2101 2102 if (parts->target == data.start) 2103 parts->target = ~0U; 2104 2105 if (parts->dlabel) { 2106 /* 2107 * If we change the mbr partitioning, the we must 2108 * remove any references in the netbsd disklabel 2109 * to the part we changed. 2110 */ 2111 parts->dlabel->pscheme->delete_partitions_in_range( 2112 parts->dlabel, data.start, data.size); 2113 } 2114 2115 if (err_msg) 2116 *err_msg = NULL; 2117 2118 dump_mbr(&parts->mbr, "after delete"); 2119 return true; 2120 } 2121 2122 static struct mbr_partition * 2123 mbr_ptr_from_start(mbr_info_t *m, daddr_t start) 2124 { 2125 bool primary = true; 2126 2127 do { 2128 for (uint i = 0; i < MBR_PART_COUNT; i++) { 2129 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 2130 continue; 2131 if (!primary && 2132 MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) 2133 break; 2134 2135 daddr_t pstart = m->sector + 2136 m->mbr.mbr_parts[i].mbrp_start; 2137 if (pstart == start) 2138 return &m->mbr.mbr_parts[i]; 2139 2140 } 2141 primary = false; 2142 } while ((m = m->extended)); 2143 2144 return NULL; 2145 } 2146 2147 static uint8_t 2148 mbr_type_from_start(const mbr_info_t *m, daddr_t start) 2149 { 2150 bool primary = true; 2151 2152 do { 2153 for (uint i = 0; i < MBR_PART_COUNT; i++) { 2154 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 2155 continue; 2156 if (!primary && 2157 MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) 2158 break; 2159 2160 daddr_t pstart = m->sector + 2161 m->mbr.mbr_parts[i].mbrp_start; 2162 if (pstart == start) 2163 return m->mbr.mbr_parts[i].mbrp_type; 2164 2165 } 2166 primary = false; 2167 } while ((m = m->extended)); 2168 2169 return MBR_PTYPE_UNUSED; 2170 } 2171 2172 static part_id 2173 mbr_add_part(struct disk_partitions *arg, 2174 const struct disk_part_info *info, const char **errmsg) 2175 { 2176 struct mbr_disk_partitions *parts = 2177 (struct mbr_disk_partitions*)arg; 2178 part_id i, j, no, free_primary = UINT_MAX; 2179 mbr_info_t *m = &parts->mbr, *me, *last, *t; 2180 daddr_t ext_start = 0, ext_size = 0; 2181 uint start, size; 2182 struct disk_part_info data = *info; 2183 struct mbr_partition *newp; 2184 2185 if (errmsg != NULL) 2186 *errmsg = NULL; 2187 2188 assert(info->nat_type != NULL); 2189 if (info->nat_type == NULL) { 2190 if (errmsg != NULL) 2191 *errmsg = INTERNAL_ERROR; 2192 return NO_PART; 2193 } 2194 if (mbr_type_from_gen_desc(info->nat_type) == MBR_PTYPE_UNUSED) { 2195 if (errmsg != NULL) 2196 *errmsg = INTERNAL_ERROR; 2197 return NO_PART; 2198 } 2199 2200 /* do we have free primary slots and/or an extended partition? */ 2201 for (i = 0; i < MBR_PART_COUNT; i++) { 2202 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED 2203 && free_primary > MBR_PART_COUNT) 2204 free_primary = i; 2205 if (MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) { 2206 ext_start = m->mbr.mbr_parts[i].mbrp_start+m->sector; 2207 ext_size = m->mbr.mbr_parts[i].mbrp_size; 2208 continue; 2209 } 2210 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED 2211 && m->mbr.mbr_parts[i].mbrp_size == 0) 2212 continue; 2213 } 2214 if (ext_start > 0 && ext_size > 0 && 2215 MBR_IS_EXTENDED(mbr_type_from_gen_desc(info->nat_type))) { 2216 /* 2217 * Do not allow a second extended partition 2218 */ 2219 if (errmsg) 2220 *errmsg = MSG_Only_one_extended_ptn; 2221 return NO_PART; 2222 } 2223 2224 /* should this go into the extended partition? */ 2225 if (ext_size > 0 && info->start >= ext_start 2226 && info->start < ext_start + ext_size) { 2227 2228 /* must fit into the extended partition */ 2229 if (info->start + info->size > ext_start + ext_size) { 2230 if (errmsg != NULL) 2231 *errmsg = MSG_mbr_ext_nofit; 2232 return NO_PART; 2233 } 2234 2235 /* walk the chain untill we find a proper insert position */ 2236 daddr_t e_end, e_start; 2237 for (last = m, m = m->extended; m != NULL; 2238 last = m, m = m->extended) { 2239 e_start = m->mbr.mbr_parts[1].mbrp_start 2240 + ext_start; 2241 e_end = e_start + m->mbr.mbr_parts[1].mbrp_size; 2242 if (data.start <= e_start) 2243 break; 2244 } 2245 if (m == NULL) { 2246 /* add new tail record */ 2247 e_end = ext_start + ext_size; 2248 /* new part needs to fit inside primary extended one */ 2249 if (data.start + data.size > e_end) { 2250 if (errmsg) 2251 *errmsg = MSG_No_free_space; 2252 return NO_PART; 2253 } 2254 } else if (data.start + data.size > e_start) { 2255 /* new part needs to fit before next extended */ 2256 if (errmsg) 2257 *errmsg = MSG_No_free_space; 2258 return NO_PART; 2259 } 2260 /* 2261 * now last points to previous mbr (maybe primary), m 2262 * points to the one that should take the new partition 2263 * or we have to insert a new mbr between the two, or 2264 * m needs to be split and we go into the one after it. 2265 */ 2266 if (m && m->mbr.mbr_parts[0].mbrp_type == MBR_PTYPE_UNUSED) { 2267 /* empty slot, we can just use it */ 2268 newp = &m->mbr.mbr_parts[0]; 2269 mbr_info_to_partitition(&data, &m->mbr.mbr_parts[0], 2270 m->sector, m, 0, errmsg); 2271 if (data.last_mounted && m->last_mounted[0] && 2272 data.last_mounted != m->last_mounted[0]) { 2273 free(__UNCONST(m->last_mounted[0])); 2274 m->last_mounted[0] = strdup(data.last_mounted); 2275 } 2276 } else { 2277 mbr_info_t *new_mbr; 2278 if (m == NULL) 2279 m = last; 2280 daddr_t p_start = m->mbr.mbr_parts[0].mbrp_start 2281 + m->sector; 2282 daddr_t p_end = p_start 2283 + m->mbr.mbr_parts[0].mbrp_size; 2284 bool before; 2285 if (m == last || data.start > p_end) 2286 before = false; 2287 else if (data.start + data.size < p_start) 2288 before = true; 2289 else { 2290 if (errmsg) 2291 *errmsg = MSG_No_free_space; 2292 return NO_PART; 2293 } 2294 new_mbr = calloc(1, sizeof *new_mbr); 2295 if (!new_mbr) { 2296 if (errmsg) 2297 *errmsg = err_outofmem; 2298 return NO_PART; 2299 } 2300 new_mbr->mbr.mbr_magic = htole16(MBR_MAGIC); 2301 new_mbr->mbr.mbr_parts[1].mbrp_type = MBR_PTYPE_EXT; 2302 if (before) { 2303 /* 2304 * This is a hypthetical case where 2305 * an extended MBR uses an unusual high 2306 * offset (m->sector to parts[0].mbrp_start) 2307 * and we want to go into that space. 2308 * Should not happen in the real world (tm) 2309 * and is untested.... 2310 */ 2311 2312 /* make sure the aligned new mbr fits */ 2313 uint mbrsec = rounddown(p_start, 2314 parts->ext_ptn_alignment); 2315 if (mbrsec <= data.start + data.size) 2316 data.size = mbrsec-1-data.start; 2317 2318 /* now the new partition data is ready, 2319 * write out to old position */ 2320 new_mbr->sector = m->sector; 2321 newp = &new_mbr->mbr.mbr_parts[0]; 2322 mbr_info_to_partitition(&data, 2323 &new_mbr->mbr.mbr_parts[0], 2324 new_mbr->sector, new_mbr, 0, errmsg); 2325 if (data.last_mounted && m->last_mounted[0] && 2326 data.last_mounted != m->last_mounted[0]) { 2327 free(__UNCONST(m->last_mounted[0])); 2328 m->last_mounted[0] = 2329 strdup(data.last_mounted); 2330 } 2331 new_mbr->extended = m; 2332 } else { 2333 new_mbr->sector = max(roundup(data.start, 2334 parts->ext_ptn_alignment), 2335 parts->ext_ptn_alignment); 2336 uint off = new_mbr->sector - data.start; 2337 data.start += parts->ptn_0_offset+off; 2338 if (data.start + data.size > e_end) 2339 data.size = e_end - data.start; 2340 newp = &new_mbr->mbr.mbr_parts[0]; 2341 mbr_info_to_partitition(&data, 2342 &new_mbr->mbr.mbr_parts[0], 2343 new_mbr->sector, new_mbr, 0, errmsg); 2344 if (data.last_mounted && m->last_mounted[0] && 2345 data.last_mounted != m->last_mounted[0]) { 2346 free(__UNCONST(m->last_mounted[0])); 2347 m->last_mounted[0] = 2348 strdup(data.last_mounted); 2349 } 2350 /* 2351 * Special case: if we are creating the 2352 * first extended mbr, but do not start 2353 * at the beginning of the primary 2354 * extended partition, we need to insert 2355 * another extended mbr at the start. 2356 */ 2357 if (m == &parts->mbr && m->extended == NULL 2358 && new_mbr->sector > ext_start) { 2359 t = calloc(1, sizeof *new_mbr); 2360 if (!t) { 2361 free_mbr_info(new_mbr); 2362 if (errmsg) 2363 *errmsg = err_outofmem; 2364 return NO_PART; 2365 } 2366 t->sector = ext_start; 2367 t->mbr.mbr_magic = htole16(MBR_MAGIC); 2368 t->mbr.mbr_parts[1].mbrp_type = 2369 MBR_PTYPE_EXT; 2370 m->extended = t; 2371 m = t; 2372 } 2373 new_mbr->extended = m->extended; 2374 m->extended = new_mbr; 2375 } 2376 } 2377 mbr_fixup_ext_chain(&parts->mbr, ext_start, ext_start+ext_size); 2378 dump_mbr(&parts->mbr, "after adding in extended"); 2379 goto find_rval; 2380 } 2381 2382 /* this one is for the primary boot block */ 2383 if (free_primary > MBR_PART_COUNT) { 2384 if (errmsg != NULL) 2385 *errmsg = ext_size > 0 ? 2386 MSG_mbr_no_free_primary_have_ext 2387 : MSG_mbr_no_free_primary_no_ext; 2388 return NO_PART; 2389 } 2390 2391 start = max(info->start, parts->ptn_0_offset); 2392 size = info->size; 2393 if (find_mbr_space(m, &start, &size, start, parts->dp.disk_size, 2394 start, true) < 0 || size < info->size) { 2395 if (errmsg != NULL) 2396 *errmsg = MSG_No_free_space; 2397 return NO_PART; 2398 } 2399 data.start = start; 2400 if (MBR_IS_EXTENDED(mbr_type_from_gen_desc(info->nat_type))) { 2401 data.start = max(roundup(data.start, parts->ext_ptn_alignment), 2402 parts->ext_ptn_alignment); 2403 } 2404 if (data.start + data.size > start + size) 2405 data.size = start + size - data.start; 2406 mbr_info_to_partitition(&data, &m->mbr.mbr_parts[free_primary], 2407 m->sector, m, free_primary, errmsg); 2408 if (data.last_mounted && m->last_mounted[free_primary] && 2409 data.last_mounted != m->last_mounted[free_primary]) { 2410 free(__UNCONST(m->last_mounted[free_primary])); 2411 m->last_mounted[free_primary] = strdup(data.last_mounted); 2412 } 2413 start = m->mbr.mbr_parts[free_primary].mbrp_start; 2414 mbr_sort_main_mbr(&m->mbr); 2415 2416 /* find the partition again after sorting */ 2417 newp = NULL; 2418 for (i = 0; i < MBR_PART_COUNT; i++) { 2419 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 2420 continue; 2421 if (m->mbr.mbr_parts[i].mbrp_start != start) 2422 continue; 2423 newp = &m->mbr.mbr_parts[i]; 2424 break; 2425 } 2426 2427 dump_mbr(&parts->mbr, "after adding in primary"); 2428 2429 find_rval: 2430 mbr_calc_free_space(parts); 2431 if (newp == NULL) 2432 return 0; 2433 2434 /* 2435 * Now newp points to the modified partition entry but we do not know 2436 * a good part_id for it. 2437 * Iterate from start and find it. 2438 */ 2439 no = 0; 2440 for (i = 0; i < MBR_PART_COUNT; i++) { 2441 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 2442 continue; 2443 2444 if (newp == &m->mbr.mbr_parts[i]) 2445 return no; 2446 no++; 2447 2448 if (MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) { 2449 for (me = m->extended; me != NULL; me = me->extended) { 2450 for (j = 0; j < MBR_PART_COUNT; j++) { 2451 if (me->mbr.mbr_parts[j].mbrp_type == 2452 MBR_PTYPE_UNUSED) 2453 continue; 2454 if (j > 0 && MBR_IS_EXTENDED( 2455 me->mbr.mbr_parts[j].mbrp_type)) 2456 break; 2457 if (newp == &me->mbr.mbr_parts[j]) 2458 return no; 2459 no++; 2460 } 2461 } 2462 } 2463 } 2464 return 0; 2465 } 2466 2467 static int 2468 mbr_guess_geom(struct disk_partitions *arg, int *cyl, int *head, int *sec) 2469 { 2470 struct mbr_disk_partitions *myparts = (struct mbr_disk_partitions*)arg; 2471 struct mbr_sector *mbrs = &myparts->mbr.mbr; 2472 struct mbr_partition *parts = &mbrs->mbr_parts[0]; 2473 int xcylinders, xheads, i, j; 2474 daddr_t xsectors, xsize; 2475 int c1, h1, s1, c2, h2, s2; 2476 daddr_t a1, a2; 2477 uint64_t num, denom; 2478 2479 xheads = -1; 2480 2481 /* Try to deduce the number of heads from two different mappings. */ 2482 for (i = 0; i < MBR_PART_COUNT * 2 - 1; i++) { 2483 if (get_mapping(parts, i, &c1, &h1, &s1, &a1) < 0) 2484 continue; 2485 a1 -= s1; 2486 for (j = i + 1; j < MBR_PART_COUNT * 2; j++) { 2487 if (get_mapping(parts, j, &c2, &h2, &s2, &a2) < 0) 2488 continue; 2489 a2 -= s2; 2490 num = (uint64_t)h1 * a2 - (quad_t)h2 * a1; 2491 denom = (uint64_t)c2 * a1 - (quad_t)c1 * a2; 2492 if (num != 0 && denom != 0 && num % denom == 0) { 2493 xheads = (int)(num / denom); 2494 xsectors = a1 / (c1 * xheads + h1); 2495 break; 2496 } 2497 } 2498 if (xheads != -1) 2499 break; 2500 } 2501 2502 if (xheads == -1) 2503 return -1; 2504 2505 /* 2506 * Estimate the number of cylinders. 2507 * XXX relies on get_disks having been called. 2508 */ 2509 xsize = min(pm->dlsize, mbr_parts.size_limit); 2510 xcylinders = xsize / xheads / xsectors; 2511 if (xsize != xcylinders * xheads * xsectors) 2512 xcylinders++; 2513 2514 /* 2515 * Now verify consistency with each of the partition table entries. 2516 * Be willing to shove cylinders up a little bit to make things work, 2517 * but translation mismatches are fatal. 2518 */ 2519 for (i = 0; i < MBR_PART_COUNT * 2; i++) { 2520 if (get_mapping(parts, i, &c1, &h1, &s1, &a1) < 0) 2521 continue; 2522 if (c1 >= MAXCYL - 1) 2523 /* Ignore anything that is near the CHS limit */ 2524 continue; 2525 if (xsectors * (c1 * xheads + h1) + s1 != a1) 2526 return -1; 2527 } 2528 2529 /* 2530 * Everything checks out. Reset the geometry to use for further 2531 * calculations. 2532 */ 2533 *cyl = MIN(xcylinders, MAXCYL); 2534 *head = xheads; 2535 *sec = xsectors; 2536 return 0; 2537 } 2538 2539 static size_t 2540 mbr_get_cylinder(const struct disk_partitions *arg) 2541 { 2542 const struct mbr_disk_partitions *parts = 2543 (const struct mbr_disk_partitions*)arg; 2544 2545 return parts->geo_cyl; 2546 } 2547 2548 static daddr_t 2549 mbr_max_part_size(const struct disk_partitions *arg, daddr_t fp_start) 2550 { 2551 const struct mbr_disk_partitions *parts = 2552 (const struct mbr_disk_partitions*)arg; 2553 uint start = fp_start, size = 0; 2554 uint8_t pt; 2555 2556 start = fp_start; 2557 pt = mbr_type_from_start(&parts->mbr, start); 2558 if (find_mbr_space(&parts->mbr, &start, &size, start, 2559 parts->dp.disk_size, start, MBR_IS_EXTENDED(pt)) < 0) 2560 return 0; 2561 2562 return size; 2563 } 2564 2565 static size_t 2566 mbr_get_free_spaces(const struct disk_partitions *arg, 2567 struct disk_part_free_space *result, size_t max_num_result, 2568 daddr_t min_size, daddr_t align, daddr_t lower_bound, daddr_t ignore) 2569 { 2570 const struct mbr_disk_partitions *parts = 2571 (const struct mbr_disk_partitions*)arg; 2572 uint start = 0, size = 0, from, next; 2573 size_t spaces = 0; 2574 2575 if (min_size < 1) 2576 min_size = 1; 2577 from = parts->ptn_0_offset; 2578 if (lower_bound > from) 2579 from = lower_bound; 2580 for ( ; from < parts->dp.disk_size && spaces < max_num_result; ) { 2581 if (find_mbr_space(&parts->mbr, &start, &size, from, 2582 parts->dp.disk_size, ignore > 0 ? (uint)ignore : UINT_MAX, 2583 false) < 0) 2584 break; 2585 next = start + size + 1; 2586 if (align > 0) { 2587 uint nv = max(roundup(start, align), align); 2588 uint off = nv - start; 2589 start = nv; 2590 if (size > off) 2591 size -= off; 2592 else 2593 size = 0; 2594 } 2595 if (size > min_size) { 2596 result[spaces].start = start; 2597 result[spaces].size = size; 2598 spaces++; 2599 } 2600 if ((daddr_t)start + (daddr_t)size + 1 >= mbr_parts.size_limit) 2601 break; 2602 from = next; 2603 } 2604 2605 return spaces; 2606 } 2607 2608 static bool 2609 mbr_can_add_partition(const struct disk_partitions *arg) 2610 { 2611 const struct mbr_disk_partitions *myparts = 2612 (const struct mbr_disk_partitions*)arg; 2613 struct disk_part_free_space space; 2614 bool free_primary, have_extended; 2615 2616 if (arg->free_space < myparts->ptn_alignment) 2617 return false; 2618 2619 if (mbr_get_free_spaces(arg, &space, 1, myparts->ptn_alignment, 2620 myparts->ptn_alignment, 0, -1) < 1) 2621 return false; 2622 2623 for (int i = 0; i < MBR_PART_COUNT; i++) { 2624 uint8_t t = myparts->mbr.mbr.mbr_parts[i].mbrp_type; 2625 2626 if (t == MBR_PTYPE_UNUSED && 2627 myparts->mbr.mbr.mbr_parts[i].mbrp_size == 0) 2628 free_primary = true; 2629 2630 if (MBR_IS_EXTENDED(t)) 2631 have_extended = true; 2632 } 2633 2634 if (have_extended) 2635 return true; 2636 2637 return free_primary; 2638 } 2639 2640 static void 2641 mbr_free_wedge(int *fd, const char *disk, const char *wedge) 2642 { 2643 struct dkwedge_info dkw; 2644 char diskpath[MAXPATHLEN]; 2645 2646 if (*fd == -1) 2647 *fd = opendisk(disk, O_RDWR, diskpath, 2648 sizeof(diskpath), 0); 2649 if (*fd != -1) { 2650 memset(&dkw, 0, sizeof(dkw)); 2651 strlcpy(dkw.dkw_devname, wedge, 2652 sizeof(dkw.dkw_devname)); 2653 ioctl(*fd, DIOCDWEDGE, &dkw); 2654 } 2655 } 2656 2657 static void 2658 mbr_free(struct disk_partitions *arg) 2659 { 2660 struct mbr_disk_partitions *parts = (struct mbr_disk_partitions*)arg; 2661 mbr_info_t *m; 2662 int i, fd; 2663 2664 assert(parts != NULL); 2665 2666 fd = -1; 2667 m = &parts->mbr; 2668 do { 2669 for (i = 0; i < MBR_PART_COUNT; i++) { 2670 if (m->wedge[i][0] != 0) 2671 mbr_free_wedge(&fd, arg->disk, m->wedge[i]); 2672 } 2673 } while ((m = m->extended)); 2674 2675 if (fd != -1) 2676 close(fd); 2677 2678 if (parts->dlabel) 2679 parts->dlabel->pscheme->free(parts->dlabel); 2680 2681 free_mbr_info(parts->mbr.extended); 2682 free_last_mounted(&parts->mbr); 2683 free(__UNCONST(parts->dp.disk)); 2684 free(parts); 2685 } 2686 2687 static void 2688 mbr_destroy_part_scheme(struct disk_partitions *arg) 2689 { 2690 struct mbr_disk_partitions *parts = (struct mbr_disk_partitions*)arg; 2691 char diskpath[MAXPATHLEN]; 2692 int fd; 2693 2694 if (parts->dlabel != NULL) 2695 parts->dlabel->pscheme->destroy_part_scheme(parts->dlabel); 2696 fd = opendisk(arg->disk, O_RDWR, diskpath, sizeof(diskpath), 0); 2697 if (fd != -1) { 2698 char *buf; 2699 2700 buf = calloc(arg->bytes_per_sector, 1); 2701 if (buf != NULL) { 2702 write(fd, buf, arg->bytes_per_sector); 2703 free(buf); 2704 } 2705 close(fd); 2706 } 2707 mbr_free(arg); 2708 } 2709 2710 static bool 2711 mbr_verify_for_update(struct disk_partitions *arg) 2712 { 2713 struct mbr_disk_partitions *parts = 2714 (struct mbr_disk_partitions*)arg; 2715 2716 return md_mbr_update_check(arg, &parts->mbr); 2717 } 2718 2719 static int 2720 mbr_verify(struct disk_partitions *arg, bool quiet) 2721 { 2722 struct mbr_disk_partitions *parts = 2723 (struct mbr_disk_partitions*)arg; 2724 mbr_info_t *m = &parts->mbr; 2725 int i; 2726 bool active_found = false; 2727 2728 for (i = 0; i < MBR_PART_COUNT; i++) { 2729 if (m->mbr.mbr_parts[i].mbrp_flag & MBR_PFLAG_ACTIVE) { 2730 active_found = true; 2731 break; 2732 } 2733 } 2734 2735 if (!active_found && pm->ptstart > 0) { 2736 struct mbr_partition *mp = mbr_ptr_from_start(m, pm->ptstart); 2737 2738 if (mp) { 2739 if (!quiet) 2740 msg_display(MSG_noactivepart); 2741 if (quiet || ask_yesno(MSG_fixactivepart)) { 2742 mp->mbrp_flag |= MBR_PFLAG_ACTIVE; 2743 active_found = true; 2744 } 2745 } 2746 } 2747 if (!active_found && !quiet) { 2748 msg_display(MSG_noactivepart); 2749 i = ask_reedit(arg); 2750 if (i <= 1) 2751 return i; 2752 } 2753 2754 for (i = 0; i < MBR_PART_COUNT; i++) { 2755 if (m->mbr.mbr_parts[i].mbrp_type != MBR_PTYPE_NETBSD) 2756 continue; 2757 m->mbr.mbr_parts[i].mbrp_flag |= MBR_PFLAG_ACTIVE; 2758 break; 2759 } 2760 2761 return md_check_mbr(arg, &parts->mbr, quiet); 2762 } 2763 2764 static bool 2765 mbr_guess_root(const struct disk_partitions *arg, 2766 daddr_t *start, daddr_t *size) 2767 { 2768 const struct mbr_disk_partitions *parts = 2769 (const struct mbr_disk_partitions*)arg; 2770 const mbr_info_t *m = &parts->mbr; 2771 size_t i, num_found; 2772 bool prim = true; 2773 daddr_t pstart, psize; 2774 2775 num_found = 0; 2776 do { 2777 for (i = 0; i < MBR_PART_COUNT; i++) { 2778 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 2779 continue; 2780 2781 if (!prim && i > 0 && 2782 MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) 2783 break; 2784 2785 const struct mbr_partition *mp = &m->mbr.mbr_parts[i]; 2786 if (mp->mbrp_type != MBR_PTYPE_NETBSD) 2787 continue; 2788 2789 if (num_found == 0) { 2790 pstart = m->sector + mp->mbrp_start; 2791 psize = mp->mbrp_size; 2792 } 2793 num_found++; 2794 2795 if (m->last_mounted[i] != NULL && 2796 strcmp(m->last_mounted[i], "/") == 0) { 2797 *start = pstart; 2798 *size = psize; 2799 return true; 2800 } 2801 } 2802 prim = false; 2803 } while ((m = m->extended)); 2804 2805 if (num_found == 1) { 2806 *start = pstart; 2807 *size = psize; 2808 return true; 2809 } 2810 2811 return false; 2812 } 2813 2814 struct part_attr_fmt_data { 2815 char *str; 2816 size_t avail_space, attr_no; 2817 const struct mbr_disk_partitions *parts; 2818 const struct disk_part_info *info; 2819 }; 2820 2821 struct part_attr_set_data { 2822 size_t attr_no; 2823 const struct mbr_disk_partitions *parts; 2824 const char *str; 2825 mbr_info_t *mbr; 2826 }; 2827 2828 static bool 2829 part_attr_fornat_str(const struct disk_partitions *arg, part_id id, 2830 const mbr_info_t *mb, int i, bool primary, 2831 const struct mbr_partition *mp, void *cookie) 2832 { 2833 const struct mbr_disk_partitions *parts = 2834 (const struct mbr_disk_partitions*)arg; 2835 struct part_attr_fmt_data *data = cookie; 2836 const char *attrtype = parts->dp.pscheme 2837 ->custom_attributes[data->attr_no].label; 2838 2839 if (attrtype == MSG_ptn_active) { 2840 strlcpy(data->str, 2841 msg_string(primary && (mp->mbrp_flag & MBR_PFLAG_ACTIVE) ? 2842 MSG_Yes : MSG_No), data->avail_space); 2843 return true; 2844 #if BOOTSEL 2845 } else if (attrtype == MSG_boot_dflt) { 2846 strlcpy(data->str, 2847 msg_string( 2848 (parts->mbr.bootsec == mb->sector+mp->mbrp_start) ? 2849 MSG_Yes : MSG_No), data->avail_space); 2850 return true; 2851 } else if (attrtype == MSG_bootmenu) { 2852 strlcpy(data->str, mb->mbrb.mbrbs_nametab[i], 2853 data->avail_space); 2854 #endif 2855 } 2856 2857 return false; 2858 } 2859 2860 static bool 2861 part_attr_set_str(const struct disk_partitions *arg, part_id id, 2862 const mbr_info_t *mb, int i, bool primary, 2863 const struct mbr_partition *mp, void *cookie) 2864 { 2865 struct part_attr_set_data *data = cookie; 2866 const char *str = data->str; 2867 #ifdef BOOTSEL 2868 const struct mbr_disk_partitions *parts = 2869 (const struct mbr_disk_partitions*)arg; 2870 const char *attrtype = parts->dp.pscheme 2871 ->custom_attributes[data->attr_no].label; 2872 mbr_info_t *m; 2873 #endif 2874 2875 while (*str == ' ') 2876 str++; 2877 2878 #if BOOTSEL 2879 if (attrtype == MSG_bootmenu) { 2880 for (m = data->mbr; m != mb; m = m->extended) 2881 ; 2882 strncpy(m->mbrb.mbrbs_nametab[i], str, 2883 sizeof(m->mbrb.mbrbs_nametab[i])); 2884 } 2885 #endif 2886 2887 return false; 2888 } 2889 2890 static bool 2891 part_attr_toggle(const struct disk_partitions *arg, part_id id, 2892 const mbr_info_t *mb, int i, bool primary, 2893 const struct mbr_partition *mp, void *cookie) 2894 { 2895 const struct mbr_disk_partitions *parts = 2896 (const struct mbr_disk_partitions*)arg; 2897 struct part_attr_set_data *data = cookie; 2898 const char *attrtype = parts->dp.pscheme 2899 ->custom_attributes[data->attr_no].label; 2900 int j; 2901 2902 if (attrtype == MSG_ptn_active) { 2903 if (!primary) 2904 return false; 2905 2906 data->mbr->mbr.mbr_parts[i].mbrp_flag ^= MBR_PFLAG_ACTIVE; 2907 for (j = 0; j < MBR_PART_COUNT; j++) { 2908 if (j == i) 2909 continue; 2910 data->mbr->mbr.mbr_parts[j].mbrp_flag 2911 &= ~MBR_PFLAG_ACTIVE; 2912 } 2913 return true; 2914 #ifdef BOOTSEL 2915 } else if (attrtype == MSG_boot_dflt) { 2916 if (data->mbr->bootsec == mb->sector+mp->mbrp_start) 2917 data->mbr->bootsec = 0; 2918 else 2919 data->mbr->bootsec = mb->sector+mp->mbrp_start; 2920 return true; 2921 #endif 2922 } 2923 2924 return false; 2925 } 2926 2927 static bool 2928 mbr_custom_attribute_format(const struct disk_partitions *arg, 2929 part_id id, size_t attr_no, const struct disk_part_info *info, 2930 char *res, size_t space) 2931 { 2932 const struct mbr_disk_partitions *parts = 2933 (const struct mbr_disk_partitions*)arg; 2934 struct part_attr_fmt_data data; 2935 2936 data.str = res; 2937 data.avail_space = space; 2938 data.attr_no = attr_no; 2939 data.parts = parts; 2940 data.info = info; 2941 2942 return mbr_part_apply(arg, id, part_attr_fornat_str, &data); 2943 } 2944 2945 static bool 2946 mbr_custom_attribute_toggle(struct disk_partitions *arg, 2947 part_id id, size_t attr_no) 2948 { 2949 struct mbr_disk_partitions *parts = 2950 (struct mbr_disk_partitions*)arg; 2951 struct part_attr_set_data data; 2952 2953 data.attr_no = attr_no; 2954 data.parts = parts; 2955 data.str = NULL; 2956 #ifdef BOOTSEL 2957 data.mbr = &parts->mbr; 2958 #endif 2959 2960 return mbr_part_apply(arg, id, part_attr_toggle, &data); 2961 } 2962 2963 static bool 2964 mbr_custom_attribute_set_str(struct disk_partitions *arg, 2965 part_id id, size_t attr_no, const char *new_val) 2966 { 2967 struct mbr_disk_partitions *parts = 2968 (struct mbr_disk_partitions*)arg; 2969 struct part_attr_set_data data; 2970 2971 data.attr_no = attr_no; 2972 data.parts = parts; 2973 data.str = new_val; 2974 #ifdef BOOTSEL 2975 data.mbr = &parts->mbr; 2976 #endif 2977 2978 return mbr_part_apply(arg, id, part_attr_set_str, &data); 2979 } 2980 2981 static daddr_t 2982 mbr_part_alignment(const struct disk_partitions *arg) 2983 { 2984 const struct mbr_disk_partitions *parts = 2985 (const struct mbr_disk_partitions*)arg; 2986 2987 return parts->ptn_alignment; 2988 } 2989 2990 static bool 2991 add_wedge(const char *disk, daddr_t start, daddr_t size, 2992 char *wname, size_t max_len) 2993 { 2994 struct dkwedge_info dkw; 2995 char diskpath[MAXPATHLEN]; 2996 int fd; 2997 2998 memset(&dkw, 0, sizeof(dkw)); 2999 dkw.dkw_offset = start; 3000 dkw.dkw_size = size; 3001 snprintf((char*)dkw.dkw_wname, sizeof dkw.dkw_wname, 3002 "%s_%" PRIi64 "@%" PRIi64, disk, size, start); 3003 3004 *wname = 0; 3005 3006 fd = opendisk(disk, O_RDWR, diskpath, sizeof(diskpath), 0); 3007 if (fd < 0) 3008 return false; 3009 if (ioctl(fd, DIOCAWEDGE, &dkw) == -1) { 3010 close(fd); 3011 return false; 3012 } 3013 close(fd); 3014 strlcpy(wname, dkw.dkw_devname, max_len); 3015 return true; 3016 } 3017 3018 static bool 3019 mbr_get_part_device(const struct disk_partitions *arg, 3020 part_id ptn, char *devname, size_t max_devname_len, int *part, 3021 enum dev_name_usage usage, bool with_path, bool life) 3022 { 3023 const struct mbr_disk_partitions *parts = 3024 (const struct mbr_disk_partitions*)arg; 3025 struct disk_part_info info, tmp; 3026 part_id dptn; 3027 char *wedge_dev; 3028 3029 if (!mbr_get_part_info(arg, ptn, &info)) 3030 return false; 3031 3032 if (!mbr_part_get_wedge(arg, ptn, &wedge_dev) || wedge_dev == NULL) 3033 return false; 3034 3035 if (wedge_dev[0] == 0) { 3036 /* 3037 * If we have secondary partitions, try to find a match there 3038 * and use that... 3039 */ 3040 if (parts->dlabel != NULL) { 3041 for (dptn = 0; dptn < parts->dlabel->num_part; dptn++) { 3042 if (!parts->dlabel->pscheme->get_part_info( 3043 parts->dlabel, dptn, &tmp)) 3044 continue; 3045 if (tmp.start != info.start || 3046 tmp.size != info.size) 3047 continue; 3048 return parts->dlabel->pscheme->get_part_device( 3049 parts->dlabel, dptn, devname, 3050 max_devname_len, 3051 part, usage, with_path, life); 3052 } 3053 } 3054 3055 /* 3056 * Configure a new wedge and remember the name 3057 */ 3058 if (!add_wedge(arg->disk, info.start, info.size, wedge_dev, 3059 MBR_DEV_LEN)) 3060 return false; 3061 } 3062 3063 assert(wedge_dev[0] != 0); 3064 3065 switch (usage) { 3066 case logical_name: 3067 case plain_name: 3068 if (with_path) 3069 snprintf(devname, max_devname_len, _PATH_DEV "%s", 3070 wedge_dev); 3071 else 3072 strlcpy(devname, wedge_dev, max_devname_len); 3073 return true; 3074 case raw_dev_name: 3075 if (with_path) 3076 snprintf(devname, max_devname_len, _PATH_DEV "r%s", 3077 wedge_dev); 3078 else 3079 snprintf(devname, max_devname_len, "r%s", 3080 wedge_dev); 3081 return true; 3082 default: 3083 return false; 3084 } 3085 } 3086 3087 static bool 3088 is_custom_attribute_writable(const struct disk_partitions *arg, part_id id, 3089 const mbr_info_t *mb, int i, bool primary, 3090 const struct mbr_partition *mp, void *cookie) 3091 { 3092 const struct mbr_disk_partitions *parts = 3093 (const struct mbr_disk_partitions*)arg; 3094 struct part_attr_set_data *data = cookie; 3095 const char *attrtype = parts->dp.pscheme 3096 ->custom_attributes[data->attr_no].label; 3097 3098 if (attrtype == MSG_ptn_active) 3099 /* Only 'normal' partitions can be 'Active' */ 3100 return primary && !MBR_IS_EXTENDED(mp->mbrp_type); 3101 #ifdef BOOTSEL 3102 else if (attrtype == MSG_boot_dflt) 3103 /* Only partitions with bootmenu names can be default */ 3104 return mb->mbrb.mbrbs_nametab[i][0] != 0; 3105 else if (attrtype == MSG_bootmenu) 3106 /* The extended partition isn't bootable */ 3107 return !MBR_IS_EXTENDED(mp->mbrp_type); 3108 #endif 3109 3110 return false; 3111 } 3112 3113 static bool 3114 mbr_custom_attribute_writable(const struct disk_partitions *arg, 3115 part_id id, size_t attr_no) 3116 { 3117 const struct mbr_disk_partitions *parts = 3118 (const struct mbr_disk_partitions*)arg; 3119 struct part_attr_set_data data; 3120 3121 data.attr_no = attr_no; 3122 data.parts = parts; 3123 data.str = NULL; 3124 #ifdef BOOTSEL 3125 data.mbr = NULL; 3126 #endif 3127 3128 return mbr_part_apply(arg, id, is_custom_attribute_writable, &data); 3129 } 3130 3131 const struct disk_part_edit_column_desc mbr_edit_columns[] = { 3132 { .title = MSG_mbr_part_header_1, 3133 #if BOOTSEL 3134 .width = 16U 3135 #else 3136 .width = 26U 3137 #endif 3138 }, 3139 { .title = MSG_mbr_part_header_2, .width = 8U }, 3140 #if BOOTSEL 3141 { .title = MSG_mbr_part_header_3, .width = 9U }, 3142 #endif 3143 }; 3144 3145 const struct disk_part_custom_attribute mbr_custom_attrs[] = { 3146 { .label = MSG_ptn_active, .type = pet_bool }, 3147 #if BOOTSEL 3148 { .label = MSG_boot_dflt, .type = pet_bool }, 3149 { .label = MSG_bootmenu, .type = pet_str, 3150 .strlen = MBR_BS_PARTNAMESIZE }, 3151 #endif 3152 }; 3153 3154 const struct disk_partitioning_scheme 3155 mbr_parts = { 3156 .name = MSG_parttype_mbr, 3157 .short_name = MSG_parttype_mbr_short, 3158 .new_type_prompt = MSG_mbr_get_ptn_id, 3159 .part_flag_desc = MSG_mbr_flag_desc, 3160 .size_limit = (daddr_t)UINT32_MAX, 3161 .secondary_scheme = &disklabel_parts, 3162 .edit_columns_count = __arraycount(mbr_edit_columns), 3163 .edit_columns = mbr_edit_columns, 3164 .custom_attribute_count = __arraycount(mbr_custom_attrs), 3165 .custom_attributes = mbr_custom_attrs, 3166 .get_part_alignment = mbr_part_alignment, 3167 .get_part_info = mbr_get_part_info, 3168 .get_part_attr_str = mbr_part_attr_str, 3169 .format_partition_table_str = mbr_table_str, 3170 .part_type_can_change = mbr_part_type_can_change, 3171 .can_add_partition = mbr_can_add_partition, 3172 .custom_attribute_writable = mbr_custom_attribute_writable, 3173 .format_custom_attribute = mbr_custom_attribute_format, 3174 .custom_attribute_toggle = mbr_custom_attribute_toggle, 3175 .custom_attribute_set_str = mbr_custom_attribute_set_str, 3176 .get_part_types_count = mbr_get_part_type_count, 3177 .adapt_foreign_part_info = generic_adapt_foreign_part_info, 3178 .get_part_type = mbr_get_part_type, 3179 .get_fs_part_type = mbr_get_fs_part_type, 3180 .get_generic_part_type = mbr_get_generic_part_type, 3181 .create_custom_part_type = mbr_custom_part_type, 3182 .create_unknown_part_type = mbr_create_unknown_part_type, 3183 .secondary_partitions = mbr_read_disklabel, 3184 .write_to_disk = mbr_write_to_disk, 3185 .read_from_disk = mbr_read_from_disk, 3186 .create_new_for_disk = mbr_create_new, 3187 .guess_disk_geom = mbr_guess_geom, 3188 .get_cylinder_size = mbr_get_cylinder, 3189 .change_disk_geom = mbr_change_disk_geom, 3190 .get_part_device = mbr_get_part_device, 3191 .max_free_space_at = mbr_max_part_size, 3192 .get_free_spaces = mbr_get_free_spaces, 3193 .set_part_info = mbr_set_part_info, 3194 .delete_all_partitions = mbr_delete_all, 3195 .delete_partition = mbr_delete_part, 3196 .add_partition = mbr_add_part, 3197 .guess_install_target = mbr_guess_root, 3198 .post_edit_verify = mbr_verify, 3199 .pre_update_verify = mbr_verify_for_update, 3200 .free = mbr_free, 3201 .destroy_part_scheme = mbr_destroy_part_scheme, 3202 }; 3203 3204 #endif 3205