1 /* $NetBSD: mbr.c,v 1.32 2020/04/22 23:43:12 joerg 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; 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 bool 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 { 534 struct mbr_partition *mbrp; 535 struct mbr_sector *mbrs = &mbri->mbr; 536 mbr_info_t *ext = NULL; 537 char diskpath[MAXPATHLEN]; 538 int fd, i; 539 uint32_t ext_base = 0, next_ext = 0; 540 int rval = -1; 541 #ifdef BOOTSEL 542 mbr_info_t *ombri = mbri; 543 int bootkey = 0; 544 #endif 545 546 memset(mbri, 0, sizeof *mbri); 547 548 /* Open the disk. */ 549 fd = opendisk(disk, O_RDONLY, diskpath, sizeof(diskpath), 0); 550 if (fd < 0) 551 goto bad_mbr; 552 553 for (;;) { 554 if (blockread(fd, secsize, mbrs, sizeof *mbrs, 555 (ext_base + next_ext) * (off_t)MBR_SECSIZE) - sizeof *mbrs != 0) 556 break; 557 558 if (!valid_mbr(mbrs)) 559 break; 560 561 mbrp = &mbrs->mbr_parts[0]; 562 if (ext_base != 0) { 563 /* sanity check extended chain */ 564 if (MBR_IS_EXTENDED(mbrp[0].mbrp_type)) 565 break; 566 if (mbrp[1].mbrp_type != MBR_PTYPE_UNUSED && 567 !MBR_IS_EXTENDED(mbrp[1].mbrp_type)) 568 break; 569 if (mbrp[2].mbrp_type != MBR_PTYPE_UNUSED 570 || mbrp[3].mbrp_type != MBR_PTYPE_UNUSED) 571 break; 572 /* Looks ok, link into extended chain */ 573 mbri->extended = ext; 574 ext->extended = NULL; 575 mbri = ext; 576 ext = NULL; 577 } 578 #if BOOTSEL 579 if (mbrs->mbr_bootsel_magic == htole16(MBR_MAGIC)) { 580 /* old bootsel, grab bootsel info */ 581 bootkey = validate_and_set_names(mbri, 582 (struct mbr_bootsel *) 583 ((uint8_t *)mbrs + MBR_BS_OLD_OFFSET), 584 ext_base); 585 } else if (mbrs->mbr_bootsel_magic == htole16(MBR_BS_MAGIC)) { 586 /* new location */ 587 bootkey = validate_and_set_names(mbri, 588 &mbrs->mbr_bootsel, ext_base); 589 } 590 /* Save original flags for mbr code update tests */ 591 mbri->oflags = mbri->mbrb.mbrbs_flags; 592 #endif 593 mbri->sector = next_ext + ext_base; 594 next_ext = 0; 595 rval = 0; 596 for (i = 0; i < MBR_PART_COUNT; mbrp++, i++) { 597 if (mbrp->mbrp_type == MBR_PTYPE_UNUSED) { 598 /* type is unused, discard scum */ 599 memset(mbrp, 0, sizeof *mbrp); 600 continue; 601 } 602 mbrp->mbrp_start = le32toh(mbrp->mbrp_start); 603 mbrp->mbrp_size = le32toh(mbrp->mbrp_size); 604 if (MBR_IS_EXTENDED(mbrp->mbrp_type)) { 605 next_ext = mbrp->mbrp_start; 606 } else { 607 uint flags = 0; 608 if (mbrp->mbrp_type == MBR_PTYPE_NETBSD) 609 flags |= GLM_LIKELY_FFS; 610 else if (mbrp->mbrp_type == MBR_PTYPE_FAT12 || 611 mbrp->mbrp_type == MBR_PTYPE_FAT16S || 612 mbrp->mbrp_type == MBR_PTYPE_FAT16B || 613 mbrp->mbrp_type == MBR_PTYPE_FAT32 || 614 mbrp->mbrp_type == MBR_PTYPE_FAT32L || 615 mbrp->mbrp_type == MBR_PTYPE_FAT16L) 616 flags |= GLM_MAYBE_FAT32; 617 else if (mbrp->mbrp_type == MBR_PTYPE_NTFS) 618 flags |= GLM_MAYBE_NTFS; 619 if (flags != 0) { 620 const char *mount = get_last_mounted( 621 fd, mbri->sector + mbrp->mbrp_start, 622 &mbri->fs_type[i], 623 &mbri->fs_sub_type[i], 624 flags); 625 char *p = strdup(mount); 626 canonicalize_last_mounted(p); 627 mbri->last_mounted[i] = p; 628 } 629 } 630 #if BOOTSEL 631 if (mbri->mbrb.mbrbs_nametab[i][0] != 0 632 && bootkey-- == 0) 633 ombri->bootsec = mbri->sector + 634 mbrp->mbrp_start; 635 #endif 636 } 637 638 if (next_ext == 0 || ext_base + next_ext <= mbri->sector) 639 break; 640 if (ext_base == 0) { 641 ext_base = next_ext; 642 next_ext = 0; 643 } 644 ext = calloc(1, sizeof *ext); 645 if (!ext) 646 break; 647 mbrs = &ext->mbr; 648 } 649 650 bad_mbr: 651 free_mbr_info(ext); 652 if (fd >= 0) 653 close(fd); 654 if (rval == -1) { 655 memset(&mbrs->mbr_parts, 0, sizeof mbrs->mbr_parts); 656 mbrs->mbr_magic = htole16(MBR_MAGIC); 657 } 658 dump_mbr(ombri, "read"); 659 return rval; 660 } 661 662 static int 663 write_mbr(const char *disk, size_t secsize, mbr_info_t *mbri, int bsec, 664 int bhead, int bcyl) 665 { 666 char diskpath[MAXPATHLEN]; 667 int fd, i, ret = 0, bits = 0; 668 struct mbr_partition *mbrp; 669 u_int32_t pstart, psize; 670 #ifdef BOOTSEL 671 struct mbr_sector *mbrs; 672 #endif 673 struct mbr_sector mbrsec; 674 mbr_info_t *ext; 675 uint sector; 676 677 dump_mbr(mbri, "write"); 678 679 /* Open the disk. */ 680 fd = opendisk(disk, secsize == 512 ? O_WRONLY : O_RDWR, 681 diskpath, sizeof(diskpath), 0); 682 if (fd < 0) 683 return -1; 684 685 /* Remove all wedges */ 686 if (ioctl(fd, DIOCRMWEDGES, &bits) == -1) 687 return -1; 688 689 #ifdef BOOTSEL 690 /* 691 * If the main boot code (appears to) contain the netbsd bootcode, 692 * copy in all the menu strings and set the default keycode 693 * to be that for the default partition. 694 * Unfortunately we can't rely on the user having actually updated 695 * to the new mbr code :-( 696 */ 697 if (mbri->mbr.mbr_bootsel_magic == htole16(MBR_BS_MAGIC) 698 || mbri->mbr.mbr_bootsel_magic == htole16(MBR_MAGIC)) { 699 int8_t key = SCAN_1; 700 uint offset = MBR_BS_OFFSET; 701 if (mbri->mbr.mbr_bootsel_magic == htole16(MBR_MAGIC)) 702 offset = MBR_BS_OLD_OFFSET; 703 mbri->mbrb.mbrbs_defkey = SCAN_ENTER; 704 if (mbri->mbrb.mbrbs_timeo == 0) 705 mbri->mbrb.mbrbs_timeo = 182; /* 10 seconds */ 706 for (ext = mbri; ext != NULL; ext = ext->extended) { 707 mbrs = &ext->mbr; 708 mbrp = &mbrs->mbr_parts[0]; 709 /* Ensure marker is set in each sector */ 710 mbrs->mbr_bootsel_magic = mbri->mbr.mbr_bootsel_magic; 711 /* and copy in bootsel parameters */ 712 *(struct mbr_bootsel *)((uint8_t *)mbrs + offset) = 713 ext->mbrb; 714 for (i = 0; i < MBR_PART_COUNT; i++) { 715 if (ext->mbrb.mbrbs_nametab[i][0] == 0) 716 continue; 717 if (ext->sector + mbrp->mbrp_start == 718 mbri->bootsec) 719 mbri->mbrb.mbrbs_defkey = key; 720 key++; 721 } 722 } 723 /* copy main data (again) since we've put the 'key' in */ 724 *(struct mbr_bootsel *)((uint8_t *)&mbri->mbr + offset) = 725 mbri->mbrb; 726 } 727 #endif 728 729 for (ext = mbri; ext != NULL; ext = ext->extended) { 730 memset(mbri->wedge, 0, sizeof mbri->wedge); 731 sector = ext->sector; 732 mbrsec = ext->mbr; /* copy sector */ 733 mbrp = &mbrsec.mbr_parts[0]; 734 735 if (sector != 0 && ext->extended != NULL 736 && ext->extended->mbr.mbr_parts[0].mbrp_type 737 == MBR_PTYPE_UNUSED) { 738 739 /* 740 * This should never happen nowadays, old code 741 * inserted empty ext sectors in the chain to 742 * help the gui out - we do not do that anymore. 743 */ 744 assert(false); 745 746 /* We are followed by an empty slot, collapse out */ 747 ext = ext->extended; 748 /* Make us describe the next non-empty partition */ 749 mbrp[1] = ext->mbr.mbr_parts[1]; 750 } 751 752 for (i = 0; i < MBR_PART_COUNT; i++) { 753 if (mbrp[i].mbrp_start == 0 && mbrp[i].mbrp_size == 0) { 754 mbrp[i].mbrp_scyl = 0; 755 mbrp[i].mbrp_shd = 0; 756 mbrp[i].mbrp_ssect = 0; 757 mbrp[i].mbrp_ecyl = 0; 758 mbrp[i].mbrp_ehd = 0; 759 mbrp[i].mbrp_esect = 0; 760 continue; 761 } 762 pstart = mbrp[i].mbrp_start; 763 psize = mbrp[i].mbrp_size; 764 mbrp[i].mbrp_start = htole32(pstart); 765 mbrp[i].mbrp_size = htole32(psize); 766 if (bsec && bcyl && bhead) { 767 convert_mbr_chs(bcyl, bhead, bsec, 768 &mbrp[i].mbrp_scyl, &mbrp[i].mbrp_shd, 769 &mbrp[i].mbrp_ssect, pstart); 770 convert_mbr_chs(bcyl, bhead, bsec, 771 &mbrp[i].mbrp_ecyl, &mbrp[i].mbrp_ehd, 772 &mbrp[i].mbrp_esect, pstart + psize - 1); 773 } 774 } 775 776 mbrsec.mbr_magic = htole16(MBR_MAGIC); 777 if (blockwrite(fd, secsize, &mbrsec, sizeof mbrsec, 778 sector * (off_t)MBR_SECSIZE) < 0) { 779 ret = -1; 780 break; 781 } 782 } 783 784 (void)close(fd); 785 return ret; 786 } 787 788 static void 789 convert_mbr_chs(int cyl, int head, int sec, 790 uint8_t *cylp, uint8_t *headp, uint8_t *secp, 791 uint32_t relsecs) 792 { 793 unsigned int tcyl, temp, thead, tsec; 794 795 temp = head * sec; 796 tcyl = relsecs / temp; 797 relsecs -= tcyl * temp; 798 799 thead = relsecs / sec; 800 tsec = relsecs - thead * sec + 1; 801 802 if (tcyl > MAXCYL) 803 tcyl = MAXCYL; 804 805 *cylp = MBR_PUT_LSCYL(tcyl); 806 *headp = thead; 807 *secp = MBR_PUT_MSCYLANDSEC(tcyl, tsec); 808 } 809 810 /* 811 * This function is ONLY to be used as a last resort to provide a 812 * hint for the user. Ports should provide a more reliable way 813 * of getting the BIOS geometry. The i386 code, for example, 814 * uses the BIOS geometry as passed on from the bootblocks, 815 * and only uses this as a hint to the user when that information 816 * is not present, or a match could not be made with a NetBSD 817 * device. 818 */ 819 int 820 guess_biosgeom_from_parts(struct disk_partitions *parts, 821 int *cyl, int *head, int *sec) 822 { 823 824 /* 825 * The physical parameters may be invalid as bios geometry. 826 * If we cannot determine the actual bios geometry, we are 827 * better off picking a likely 'faked' geometry than leaving 828 * the invalid physical one. 829 */ 830 831 int xcylinders = pm->dlcyl; 832 int xheads = pm->dlhead; 833 daddr_t xsectors = pm->dlsec; 834 daddr_t xsize = min(pm->dlsize, mbr_parts.size_limit); 835 if (xcylinders > MAXCYL || xheads > MAXHEAD || xsectors > MAXSECTOR) { 836 xsectors = MAXSECTOR; 837 xheads = MAXHEAD; 838 xcylinders = xsize / (MAXSECTOR * MAXHEAD); 839 if (xcylinders > MAXCYL) 840 xcylinders = MAXCYL; 841 } 842 *cyl = xcylinders; 843 *head = xheads; 844 *sec = xsectors; 845 846 if (parts->pscheme->guess_disk_geom == NULL) 847 return -1; 848 849 return parts->pscheme->guess_disk_geom(parts, cyl, head, sec); 850 } 851 852 static int 853 mbr_comp_part_entry(const void *a, const void *b) 854 { 855 const struct mbr_partition *part_a = a, 856 *part_b = b; 857 858 if (part_a->mbrp_type == MBR_PTYPE_UNUSED 859 && part_b->mbrp_type != MBR_PTYPE_UNUSED) 860 return 1; 861 862 if (part_b->mbrp_type == MBR_PTYPE_UNUSED 863 && part_a->mbrp_type != MBR_PTYPE_UNUSED) 864 return -1; 865 866 return part_a->mbrp_start < part_b->mbrp_start ? -1 : 1; 867 } 868 869 static void 870 mbr_sort_main_mbr(struct mbr_sector *m) 871 { 872 qsort(&m->mbr_parts[0], MBR_PART_COUNT, 873 sizeof(m->mbr_parts[0]), mbr_comp_part_entry); 874 } 875 876 static void 877 mbr_init_default_alignments(struct mbr_disk_partitions *parts, uint track) 878 { 879 if (track == 0) 880 track = 16065; 881 882 assert(parts->dp.disk_size > 0); 883 if (parts->dp.disk_size < 0) 884 return; 885 886 /* Use 1MB offset/alignemnt for large (>128GB) disks */ 887 if (parts->dp.disk_size > HUGE_DISK_SIZE) { 888 parts->ptn_alignment = 2048; 889 parts->ptn_0_offset = 2048; 890 } else if (parts->dp.disk_size > TINY_DISK_SIZE) { 891 parts->ptn_alignment = 64; 892 parts->ptn_0_offset = parts->geo_sec; 893 } else { 894 parts->ptn_alignment = 1; 895 parts->ptn_0_offset = parts->geo_sec; 896 } 897 parts->ext_ptn_alignment = track; 898 } 899 900 static struct disk_partitions * 901 mbr_create_new(const char *disk, daddr_t start, daddr_t len, 902 bool is_boot_drive, struct disk_partitions *parent) 903 { 904 struct mbr_disk_partitions *parts; 905 struct disk_geom geo; 906 907 assert(start == 0); 908 if (start != 0) 909 return NULL; 910 911 parts = calloc(1, sizeof(*parts)); 912 if (!parts) 913 return NULL; 914 915 parts->dp.pscheme = &mbr_parts; 916 parts->dp.disk = strdup(disk); 917 if (len > mbr_parts.size_limit) 918 len = mbr_parts.size_limit; 919 parts->dp.disk_start = start; 920 parts->dp.disk_size = len; 921 parts->dp.free_space = len-1; 922 parts->dp.bytes_per_sector = 512; 923 parts->geo_sec = MAXSECTOR; 924 parts->geo_head = MAXHEAD; 925 parts->geo_cyl = len/MAXHEAD/MAXSECTOR+1; 926 927 if (get_disk_geom(disk, &geo)) { 928 parts->geo_sec = geo.dg_nsectors; 929 parts->geo_head = geo.dg_ntracks; 930 parts->geo_cyl = geo.dg_ncylinders; 931 parts->dp.bytes_per_sector = geo.dg_secsize; 932 } 933 934 mbr_init_default_alignments(parts, 0); 935 936 return &parts->dp; 937 } 938 939 static void 940 mbr_calc_free_space(struct mbr_disk_partitions *parts) 941 { 942 size_t i; 943 mbr_info_t *m; 944 945 parts->dp.free_space = parts->dp.disk_size - 1; 946 parts->dp.num_part = 0; 947 m = &parts->mbr; 948 do { 949 for (i = 0; i < MBR_PART_COUNT; i++) { 950 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 951 continue; 952 953 if (m != &parts->mbr && i > 0 && 954 MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) 955 break; 956 957 parts->dp.num_part++; 958 if (MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) 959 continue; 960 961 daddr_t psize = m->mbr.mbr_parts[i].mbrp_size; 962 if (m != &parts->mbr) 963 psize += m->mbr.mbr_parts[i].mbrp_start; 964 965 if (psize > parts->dp.free_space) 966 parts->dp.free_space = 0; 967 else 968 parts->dp.free_space -= psize; 969 970 } 971 } while ((m = m->extended)); 972 } 973 974 static struct disk_partitions * 975 mbr_read_from_disk(const char *disk, daddr_t start, daddr_t len, size_t bps, 976 const struct disk_partitioning_scheme *scheme) 977 { 978 struct mbr_disk_partitions *parts; 979 980 assert(start == 0); 981 if (start != 0) 982 return NULL; 983 984 parts = calloc(1, sizeof(*parts)); 985 if (!parts) 986 return NULL; 987 988 parts->dp.pscheme = scheme; 989 parts->dp.disk = strdup(disk); 990 if (len >= mbr_parts.size_limit) 991 len = mbr_parts.size_limit; 992 parts->dp.disk_start = start; 993 parts->dp.disk_size = len; 994 parts->geo_sec = MAXSECTOR; 995 parts->geo_head = MAXHEAD; 996 parts->geo_cyl = len/MAXHEAD/MAXSECTOR+1; 997 parts->dp.bytes_per_sector = bps; 998 mbr_init_default_alignments(parts, 0); 999 if (read_mbr(disk, parts->dp.bytes_per_sector, &parts->mbr) == -1) { 1000 free(parts); 1001 return NULL; 1002 } 1003 mbr_calc_free_space(parts); 1004 if (parts->dp.num_part == 1 && 1005 parts->dp.free_space < parts->ptn_alignment) { 1006 struct disk_part_info info; 1007 1008 /* 1009 * Check if this is a GPT protective MBR 1010 */ 1011 if (parts->dp.pscheme->get_part_info(&parts->dp, 0, &info) 1012 && info.nat_type != NULL 1013 && mbr_type_from_gen_desc(info.nat_type) == 0xEE) { 1014 parts->dp.pscheme->free(&parts->dp); 1015 return NULL; 1016 } 1017 } 1018 1019 return &parts->dp; 1020 } 1021 1022 static bool 1023 mbr_write_to_disk(struct disk_partitions *new_state) 1024 { 1025 struct mbr_disk_partitions *parts = 1026 (struct mbr_disk_partitions *)new_state; 1027 unsigned long bsec, bhead, bcyl; 1028 daddr_t t; 1029 1030 assert(parts->geo_sec != 0); 1031 if (parts->geo_sec != 0) { 1032 bsec = parts->geo_sec; 1033 bhead = parts->ext_ptn_alignment / bsec; 1034 } else { 1035 bsec = MAXSECTOR; 1036 bhead = MAXHEAD; 1037 } 1038 t = bsec * bhead; 1039 assert(t != 0); 1040 if ((daddr_t)(1UL<<10) * t <= parts->dp.disk_size) 1041 bcyl = (1UL<<10) - 1; 1042 else 1043 bcyl = (unsigned long)(parts->dp.disk_size / t); 1044 1045 return write_mbr(parts->dp.disk, parts->dp.bytes_per_sector, 1046 &parts->mbr, bsec, bhead, bcyl) == 0; 1047 } 1048 1049 static bool 1050 mbr_change_disk_geom(struct disk_partitions *arg, int ncyl, int nhead, 1051 int nsec) 1052 { 1053 struct mbr_disk_partitions *parts = (struct mbr_disk_partitions *)arg; 1054 daddr_t ptn_0_base, ptn_0_limit; 1055 struct disk_part_info info; 1056 1057 /* Default to using 'traditional' cylinder alignment */ 1058 mbr_init_chs(parts, ncyl, nhead, nsec); 1059 mbr_init_default_alignments(parts, nhead * nsec); 1060 1061 if (parts->dp.disk_size <= TINY_DISK_SIZE) { 1062 set_default_sizemult(arg->disk, 1063 parts->dp.bytes_per_sector, parts->dp.bytes_per_sector); 1064 return true; 1065 } 1066 1067 if (parts->dp.num_part > 0 && 1068 parts->dp.pscheme->get_part_info(arg, 0, &info)) { 1069 1070 /* Try to copy offset of first partition */ 1071 ptn_0_base = info.start; 1072 ptn_0_limit = info.start + info.size; 1073 if (!(ptn_0_limit & 2047)) { 1074 /* Partition ends on a 1MB boundary, align to 1MB */ 1075 parts->ptn_alignment = 2048; 1076 if ((ptn_0_base <= 2048 1077 && !(ptn_0_base & (ptn_0_base - 1))) 1078 || (ptn_0_base < parts->ptn_0_offset)) { 1079 /* 1080 * If ptn_base is a power of 2, use it. 1081 * Also use it if the first partition 1082 * already is close to the begining 1083 * of the disk and we can't enforce 1084 * better alignment. 1085 */ 1086 parts->ptn_0_offset = ptn_0_base; 1087 } 1088 } 1089 } 1090 set_default_sizemult(arg->disk, MEG, parts->dp.bytes_per_sector); 1091 return true; 1092 } 1093 1094 static size_t 1095 mbr_type_from_gen_desc(const struct part_type_desc *desc) 1096 { 1097 for (size_t i = 0; i < __arraycount(mbr_gen_type_desc); i++) 1098 if (&mbr_gen_type_desc[i].gen == desc) 1099 return i; 1100 1101 return SIZE_T_MAX; 1102 } 1103 1104 static enum part_type 1105 mbr_map_part_type(unsigned int t) 1106 { 1107 /* Map some special MBR partition types */ 1108 switch (t) { 1109 case MBR_PTYPE_FAT32: 1110 case MBR_PTYPE_FAT32L: 1111 case MBR_PTYPE_FAT16S: 1112 case MBR_PTYPE_FAT16B: 1113 case MBR_PTYPE_FAT16L: 1114 case MBR_PTYPE_FAT12: 1115 case MBR_PTYPE_FT_FAT32: 1116 case MBR_PTYPE_FT_FAT32_EXT: 1117 return PT_FAT; 1118 case MBR_PTYPE_EFI: 1119 return PT_EFI_SYSTEM; 1120 case MBR_PTYPE_NETBSD: 1121 return PT_root; 1122 } 1123 1124 return PT_unknown; 1125 } 1126 1127 static void 1128 map_mbr_part_types(void) 1129 { 1130 1131 for (size_t i = 0; i < __arraycount(mbr_part_types_src); i++) { 1132 unsigned int v = mbr_part_types_src[i].ptype; 1133 1134 snprintf(mbr_gen_type_desc[v].short_buf, 1135 sizeof(mbr_gen_type_desc[v].short_buf), "%u", v); 1136 mbr_gen_type_desc[v].gen.short_desc = 1137 mbr_gen_type_desc[v].short_buf; 1138 mbr_gen_type_desc[v].gen.description = 1139 mbr_part_types_src[i].desc; 1140 mbr_gen_type_desc[v].gen.generic_ptype = mbr_map_part_type(v); 1141 mbr_gen_type_desc[v].next_ptype = ~0U; 1142 mbr_gen_type_desc[last_added_part_type].next_ptype = v; 1143 known_part_types++; 1144 last_added_part_type = v; 1145 } 1146 } 1147 1148 static size_t 1149 mbr_get_part_type_count(void) 1150 { 1151 if (known_part_types == 0) 1152 map_mbr_part_types(); 1153 1154 return known_part_types; 1155 } 1156 1157 static const struct part_type_desc * 1158 mbr_get_fs_part_type(enum part_type pt, unsigned fs_type, unsigned sub_type) 1159 { 1160 if (known_part_types == 0) 1161 map_mbr_part_types(); 1162 1163 switch (fs_type) { 1164 case FS_BSDFFS: 1165 return &mbr_gen_type_desc[MBR_PTYPE_NETBSD].gen; 1166 case FS_EX2FS: 1167 return &mbr_gen_type_desc[MBR_PTYPE_LNXEXT2].gen; 1168 case FS_MSDOS: 1169 if (sub_type == 0) 1170 sub_type = MBR_PTYPE_FAT32L; 1171 1172 switch (sub_type) { 1173 case MBR_PTYPE_FAT12: 1174 case MBR_PTYPE_FAT16S: 1175 case MBR_PTYPE_FAT16B: 1176 case MBR_PTYPE_FAT32: 1177 case MBR_PTYPE_FAT32L: 1178 case MBR_PTYPE_FAT16L: 1179 return &mbr_gen_type_desc[sub_type].gen; 1180 } 1181 break; 1182 } 1183 1184 return NULL; 1185 } 1186 1187 static const struct part_type_desc * 1188 mbr_get_part_type(size_t index) 1189 { 1190 size_t i, no; 1191 1192 if (known_part_types == 0) 1193 map_mbr_part_types(); 1194 1195 if (index >= known_part_types) 1196 return NULL; 1197 1198 for (i = first_part_type, no = 0; i < __arraycount(mbr_gen_type_desc) 1199 && no != index; no++) 1200 i = mbr_gen_type_desc[i].next_ptype; 1201 1202 if (i >= __arraycount(mbr_gen_type_desc)) 1203 return NULL; 1204 return &mbr_gen_type_desc[i].gen; 1205 } 1206 1207 static const struct part_type_desc * 1208 mbr_new_custom_part_type(unsigned int v) 1209 { 1210 snprintf(mbr_gen_type_desc[v].short_buf, 1211 sizeof(mbr_gen_type_desc[v].short_buf), "%u", v); 1212 snprintf(mbr_gen_type_desc[v].desc_buf, 1213 sizeof(mbr_gen_type_desc[v].desc_buf), "%s (%u)", 1214 msg_string(MSG_custom_type), v); 1215 mbr_gen_type_desc[v].gen.short_desc = mbr_gen_type_desc[v].short_buf; 1216 mbr_gen_type_desc[v].gen.description = mbr_gen_type_desc[v].desc_buf; 1217 mbr_gen_type_desc[v].gen.generic_ptype = mbr_map_part_type(v); 1218 mbr_gen_type_desc[v].next_ptype = ~0U; 1219 mbr_gen_type_desc[last_added_part_type].next_ptype = v; 1220 known_part_types++; 1221 last_added_part_type = v; 1222 1223 return &mbr_gen_type_desc[v].gen; 1224 } 1225 1226 static const struct part_type_desc * 1227 mbr_custom_part_type(const char *custom, const char **err_msg) 1228 { 1229 unsigned long v; 1230 char *endp; 1231 1232 if (known_part_types == 0) 1233 map_mbr_part_types(); 1234 1235 v = strtoul(custom, &endp, 10); 1236 if (v > 255 || (v == 0 && *endp != 0)) { 1237 if (err_msg != NULL) 1238 *err_msg = msg_string(MSG_mbr_type_invalid); 1239 return NULL; 1240 } 1241 1242 if (mbr_gen_type_desc[v].gen.short_desc != NULL) 1243 return &mbr_gen_type_desc[v].gen; 1244 1245 return mbr_new_custom_part_type(v); 1246 } 1247 1248 static const struct part_type_desc * 1249 mbr_create_unknown_part_type(void) 1250 { 1251 1252 if (mbr_gen_type_desc[MBR_UNKNOWN_PTYPE].gen.short_desc != NULL) 1253 return &mbr_gen_type_desc[MBR_UNKNOWN_PTYPE].gen; 1254 1255 return mbr_new_custom_part_type(MBR_UNKNOWN_PTYPE); 1256 } 1257 1258 static const struct part_type_desc * 1259 mbr_get_gen_type_desc(unsigned int pt) 1260 { 1261 1262 if (known_part_types == 0) 1263 map_mbr_part_types(); 1264 1265 if (pt >= __arraycount(mbr_gen_type_desc)) 1266 return NULL; 1267 1268 if (mbr_gen_type_desc[pt].gen.short_desc != NULL) 1269 return &mbr_gen_type_desc[pt].gen; 1270 1271 return mbr_new_custom_part_type(pt); 1272 } 1273 1274 static const struct part_type_desc * 1275 mbr_get_generic_part_type(enum part_type pt) 1276 { 1277 switch (pt) { 1278 case PT_root: 1279 return mbr_get_gen_type_desc(MBR_PTYPE_NETBSD); 1280 case PT_FAT: 1281 return mbr_get_gen_type_desc(MBR_PTYPE_FAT32L); 1282 case PT_EFI_SYSTEM: 1283 return mbr_get_gen_type_desc(MBR_PTYPE_EFI); 1284 default: 1285 break; 1286 } 1287 assert(false); 1288 return NULL; 1289 } 1290 1291 static void 1292 mbr_partition_to_info(const struct mbr_partition *mp, daddr_t start_off, 1293 struct disk_part_info *info) 1294 { 1295 memset(info, 0, sizeof(*info)); 1296 info->start = mp->mbrp_start + start_off; 1297 info->size = mp->mbrp_size; 1298 info->nat_type = mbr_get_gen_type_desc(mp->mbrp_type); 1299 if (mp->mbrp_type == MBR_PTYPE_NETBSD) { 1300 info->flags |= PTI_SEC_CONTAINER; 1301 } else if (MBR_IS_EXTENDED(mp->mbrp_type)) 1302 info->flags |= PTI_PSCHEME_INTERNAL; 1303 } 1304 1305 static bool 1306 mbr_part_apply(const struct disk_partitions *arg, part_id id, 1307 bool (*func)(const struct disk_partitions *arg, part_id id, 1308 const mbr_info_t *mb, int i, bool primary, 1309 const struct mbr_partition *mp, void *), 1310 void *cookie) 1311 { 1312 const struct mbr_disk_partitions *parts = 1313 (const struct mbr_disk_partitions*)arg; 1314 part_id i, j, no; 1315 const mbr_info_t *m = &parts->mbr, *me; 1316 1317 no = 0; 1318 for (i = 0; i < MBR_PART_COUNT; i++) { 1319 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 1320 continue; 1321 1322 if (no == id) { 1323 return func(arg, id, m, i, true, 1324 &m->mbr.mbr_parts[i], cookie); 1325 } 1326 no++; 1327 1328 if (MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) { 1329 for (me = m->extended; me != NULL; me = me->extended) { 1330 for (j = 0; j < MBR_PART_COUNT; j++) { 1331 if (me->mbr.mbr_parts[j].mbrp_type == 1332 MBR_PTYPE_UNUSED) 1333 continue; 1334 if (j > 0 && MBR_IS_EXTENDED( 1335 me->mbr.mbr_parts[j].mbrp_type)) 1336 break; 1337 if (no == id) { 1338 return func(arg, id, me, j, 1339 false, 1340 &me->mbr.mbr_parts[j], 1341 cookie); 1342 } 1343 no++; 1344 } 1345 } 1346 } 1347 } 1348 1349 1350 return false; 1351 } 1352 1353 static bool 1354 mbr_do_get_part_info(const struct disk_partitions *arg, part_id id, 1355 const mbr_info_t *mb, int i, bool primary, 1356 const struct mbr_partition *mp, void *cookie) 1357 { 1358 struct disk_part_info *info = cookie; 1359 1360 mbr_partition_to_info(mp, mb->sector, info); 1361 if (mb->last_mounted[i] != NULL && mb->last_mounted[i][0] != 0) 1362 info->last_mounted = mb->last_mounted[i]; 1363 if (mb->fs_type[i] != FS_UNUSED) { 1364 info->fs_type = mb->fs_type[i]; 1365 info->fs_sub_type = mb->fs_sub_type[i]; 1366 } else { 1367 info->fs_sub_type = 0; 1368 switch (mp->mbrp_type) { 1369 case MBR_PTYPE_FAT12: 1370 case MBR_PTYPE_FAT16S: 1371 case MBR_PTYPE_FAT16B: 1372 case MBR_PTYPE_FAT32: 1373 case MBR_PTYPE_FAT32L: 1374 case MBR_PTYPE_FAT16L: 1375 case MBR_PTYPE_OS2_DOS12: 1376 case MBR_PTYPE_OS2_DOS16S: 1377 case MBR_PTYPE_OS2_DOS16B: 1378 case MBR_PTYPE_HID_FAT32: 1379 case MBR_PTYPE_HID_FAT32_LBA: 1380 case MBR_PTYPE_HID_FAT16_LBA: 1381 case MBR_PTYPE_MDOS_FAT12: 1382 case MBR_PTYPE_MDOS_FAT16S: 1383 case MBR_PTYPE_MDOS_EXT: 1384 case MBR_PTYPE_MDOS_FAT16B: 1385 case MBR_PTYPE_SPEEDSTOR_16S: 1386 case MBR_PTYPE_EFI: 1387 info->fs_type = FS_MSDOS; 1388 break; 1389 case MBR_PTYPE_XENIX_ROOT: 1390 case MBR_PTYPE_XENIX_USR: 1391 info->fs_type = FS_SYSV; 1392 break; 1393 case MBR_PTYPE_NTFS: 1394 info->fs_type = FS_NTFS; 1395 break; 1396 case MBR_PTYPE_APPLE_HFS: 1397 info->fs_type = FS_HFS; 1398 break; 1399 case MBR_PTYPE_VMWARE: 1400 info->fs_type = FS_VMFS; 1401 break; 1402 case MBR_PTYPE_AST_SWAP: 1403 case MBR_PTYPE_DRDOS_LSWAP: 1404 case MBR_PTYPE_LNXSWAP: 1405 case MBR_PTYPE_BSDI_SWAP: 1406 case MBR_PTYPE_HID_LNX_SWAP: 1407 case MBR_PTYPE_VMWARE_SWAP: 1408 info->fs_type = FS_SWAP; 1409 break; 1410 } 1411 } 1412 return true; 1413 } 1414 1415 static bool 1416 get_wedge_devname(const struct disk_partitions *arg, part_id id, 1417 const mbr_info_t *mb, int i, bool primary, 1418 const struct mbr_partition *mp, void *cookie) 1419 { 1420 char **res = cookie; 1421 1422 if (!res) 1423 return false; 1424 1425 *res = __UNCONST(mb->wedge[i]); 1426 return true; 1427 } 1428 1429 static bool 1430 mbr_part_get_wedge(const struct disk_partitions *arg, part_id id, 1431 char **res) 1432 { 1433 return mbr_part_apply(arg, id, get_wedge_devname, res); 1434 } 1435 1436 static bool 1437 mbr_get_part_info(const struct disk_partitions *arg, part_id id, 1438 struct disk_part_info *info) 1439 { 1440 return mbr_part_apply(arg, id, mbr_do_get_part_info, info); 1441 } 1442 1443 static bool 1444 type_can_change(const struct disk_partitions *arg, part_id id, 1445 const mbr_info_t *mb, int i, bool primary, 1446 const struct mbr_partition *mp, void *cookie) 1447 { 1448 /* 1449 * The extended partition can only change type or be 1450 * deleted if it is empty 1451 */ 1452 if (!MBR_IS_EXTENDED(mp->mbrp_type)) 1453 return true; 1454 return primary && mb->extended == NULL; 1455 } 1456 1457 static bool 1458 mbr_part_type_can_change(const struct disk_partitions *arg, part_id id) 1459 { 1460 return mbr_part_apply(arg, id, type_can_change, NULL); 1461 } 1462 1463 struct part_get_str_data { 1464 char *str; 1465 size_t avail_space; 1466 size_t col; 1467 }; 1468 1469 1470 static bool 1471 mbr_get_part_table_str(const struct disk_partitions *arg, part_id id, 1472 const mbr_info_t *mb, int i, bool primary, 1473 const struct mbr_partition *mp, void *cookie) 1474 { 1475 struct part_get_str_data *data = cookie; 1476 char *str = data->str; 1477 const struct part_type_desc *ptype; 1478 1479 switch (data->col) { 1480 case 0: 1481 ptype = mbr_get_gen_type_desc(mp->mbrp_type); 1482 if (ptype != NULL) 1483 strncpy(str, ptype->description, data->avail_space); 1484 else 1485 snprintf(str, data->avail_space, "%u", mp->mbrp_type); 1486 str[data->avail_space-1] = 0; 1487 break; 1488 case 1: 1489 if (mb->last_mounted[i]) 1490 strlcpy(str, mb->last_mounted[i], data->avail_space); 1491 else 1492 *str = 0; 1493 break; 1494 #ifdef BOOTSEL 1495 case 2: 1496 if (mb->mbrb.mbrbs_nametab[i][0] != 0) 1497 strlcpy(str, mb->mbrb.mbrbs_nametab[i], 1498 data->avail_space); 1499 else 1500 *str = 0; 1501 break; 1502 #endif 1503 } 1504 1505 return true; 1506 } 1507 1508 static bool 1509 mbr_table_str(const struct disk_partitions *arg, part_id id, size_t col, 1510 char *str, size_t avail_space) 1511 { 1512 struct part_get_str_data data; 1513 1514 data.str = str; 1515 data.avail_space = avail_space; 1516 data.col = col; 1517 return mbr_part_apply(arg, id, mbr_get_part_table_str, &data); 1518 } 1519 1520 static bool 1521 mbr_get_part_attr_str(const struct disk_partitions *arg, part_id id, 1522 const mbr_info_t *mb, int i, bool primary, 1523 const struct mbr_partition *mp, void *cookie) 1524 { 1525 #ifdef BOOTSEL 1526 const struct mbr_disk_partitions *parts = 1527 (const struct mbr_disk_partitions*)arg; 1528 #endif 1529 struct part_get_str_data *data = cookie; 1530 static const char *flags = NULL; 1531 char *str = data->str; 1532 1533 if (flags == NULL) 1534 flags = msg_string(MSG_mbr_flags); 1535 1536 if (mp->mbrp_flag & MBR_PFLAG_ACTIVE) 1537 *str++ = flags[0]; 1538 #ifdef BOOTSEL 1539 if (parts->mbr.bootsec == mb->sector+mp->mbrp_start) 1540 *str++ = flags[1]; 1541 #endif 1542 *str = 0; 1543 return true; 1544 } 1545 1546 static bool 1547 mbr_part_attr_str(const struct disk_partitions *arg, part_id id, 1548 char *str, size_t avail_space) 1549 { 1550 struct part_get_str_data data; 1551 1552 if (avail_space < 3) 1553 return false; 1554 1555 data.str = str; 1556 data.avail_space = avail_space; 1557 return mbr_part_apply(arg, id, mbr_get_part_attr_str, &data); 1558 } 1559 1560 static bool 1561 mbr_info_to_partitition(const struct disk_part_info *info, 1562 struct mbr_partition *mp, uint sector, const char **err_msg) 1563 { 1564 size_t pt = mbr_type_from_gen_desc(info->nat_type); 1565 if (info->start + info->size > UINT_MAX 1566 || pt > __arraycount(mbr_gen_type_desc)) { 1567 if (err_msg) 1568 *err_msg = err_outofmem; 1569 return false; 1570 } 1571 mp->mbrp_start = info->start - sector; 1572 mp->mbrp_size = info->size; 1573 mp->mbrp_type = pt; 1574 1575 return true; 1576 } 1577 1578 static bool 1579 inside_ext_part(mbr_info_t *m, daddr_t start) 1580 { 1581 size_t i; 1582 struct mbr_partition *mp = NULL; 1583 1584 for (i = 0; i < MBR_PART_COUNT; i++) { 1585 if (!MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) 1586 continue; 1587 mp = &m->mbr.mbr_parts[i]; 1588 break; 1589 } 1590 1591 if (mp == NULL) { 1592 assert(false); 1593 return false; 1594 } 1595 1596 if (mp->mbrp_start > start) 1597 return false; 1598 1599 return true; 1600 } 1601 1602 static void 1603 adjust_ext_part(mbr_info_t *m, daddr_t start, daddr_t size) 1604 { 1605 size_t i; 1606 struct mbr_partition *mp = NULL; 1607 1608 for (i = 0; i < MBR_PART_COUNT; i++) { 1609 if (!MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) 1610 continue; 1611 mp = &m->mbr.mbr_parts[i]; 1612 break; 1613 } 1614 1615 if (mp == NULL) { 1616 assert(false); 1617 return; 1618 } 1619 1620 if (mp->mbrp_start + mp->mbrp_size >= start + size) 1621 return; 1622 1623 daddr_t new_end = start + size; 1624 mp->mbrp_size = new_end - mp->mbrp_start; 1625 } 1626 1627 static bool 1628 ext_part_good(mbr_info_t *m, daddr_t ext_start, daddr_t ext_size) 1629 { 1630 for (m = m->extended; m != NULL; m = m->extended) { 1631 for (size_t i = 0; i < MBR_PART_COUNT; i++) { 1632 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 1633 continue; 1634 1635 if (i > 0 && 1636 MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) 1637 break; 1638 1639 daddr_t pstart = m->mbr.mbr_parts[i].mbrp_start + 1640 m->sector; 1641 daddr_t pend = pstart + m->mbr.mbr_parts[i].mbrp_size; 1642 1643 if (pstart < ext_start || pend > ext_start+ext_size) 1644 return false; 1645 } 1646 } 1647 1648 return true; 1649 } 1650 1651 static bool 1652 mbr_set_part_info(struct disk_partitions *arg, part_id id, 1653 const struct disk_part_info *info, const char **err_msg) 1654 { 1655 struct mbr_disk_partitions *parts = 1656 (struct mbr_disk_partitions*)arg; 1657 struct disk_part_info data = *info; 1658 part_id i, j, no, ext_ndx, t; 1659 mbr_info_t *m = &parts->mbr, *me; 1660 uint pt = mbr_type_from_gen_desc(info->nat_type); 1661 1662 if (MBR_IS_EXTENDED(pt)) { 1663 /* check for duplicate ext part */ 1664 no = 0; 1665 t = ext_ndx = MBR_PART_COUNT; 1666 for (i = 0; i < MBR_PART_COUNT; i++) { 1667 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 1668 continue; 1669 if (MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) 1670 ext_ndx = i; 1671 if (no == id) 1672 t = i; 1673 no++; 1674 } 1675 if (ext_ndx < MBR_PART_COUNT && t != ext_ndx) { 1676 if (err_msg) 1677 *err_msg = 1678 msg_string(MSG_Only_one_extended_ptn); 1679 return false; 1680 } 1681 /* this partition becomes an extended one, apply alignment */ 1682 data.start = max(roundup(data.start, parts->ext_ptn_alignment), 1683 parts->ext_ptn_alignment); 1684 } 1685 1686 no = 0; 1687 for (i = 0; i < MBR_PART_COUNT; i++) { 1688 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 1689 continue; 1690 1691 if (no == id) 1692 goto found; 1693 no++; 1694 1695 if (MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) { 1696 for (me = m->extended; me != NULL; me = me->extended) { 1697 for (j = 0; j < MBR_PART_COUNT; j++) { 1698 if (me->mbr.mbr_parts[j].mbrp_type == 1699 MBR_PTYPE_UNUSED) 1700 continue; 1701 if (j > 0 && MBR_IS_EXTENDED( 1702 me->mbr.mbr_parts[j].mbrp_type)) 1703 break; 1704 if (no == id) { 1705 i = j; 1706 m = me; 1707 goto found; 1708 } 1709 no++; 1710 } 1711 } 1712 } 1713 } 1714 1715 if (err_msg) 1716 *err_msg = INTERNAL_ERROR; 1717 return false; 1718 1719 found: 1720 /* 1721 * We assume that m is the mbr we want to update and 1722 * i is the local partition index into it. 1723 */ 1724 if (m == &parts->mbr) { 1725 if (MBR_IS_EXTENDED( 1726 m->mbr.mbr_parts[i].mbrp_type) && 1727 !ext_part_good(&parts->mbr, data.start, data.size)) { 1728 if (err_msg) 1729 *err_msg = 1730 MSG_mbr_ext_nofit; 1731 return false; 1732 } 1733 } else if (!inside_ext_part(&parts->mbr, data.start)) { 1734 if (err_msg) 1735 *err_msg = msg_string(MSG_mbr_inside_ext); 1736 return false; 1737 } 1738 uint start = data.start, size = data.size; 1739 uint oldstart = m->mbr.mbr_parts[i].mbrp_start + m->sector; 1740 if (parts->ptn_0_offset > 0 && 1741 start < parts->ptn_0_offset) 1742 start = parts->ptn_0_offset; 1743 if (find_mbr_space(m, &start, &size, start, parts->dp.disk_size, 1744 oldstart, false) < 0) { 1745 if (err_msg != NULL) 1746 *err_msg = INTERNAL_ERROR; 1747 return false; 1748 } 1749 data.start = start; 1750 if (size < data.size) 1751 data.size = size; 1752 uint old_start = m->mbr.mbr_parts[i].mbrp_start; 1753 if (!mbr_info_to_partitition(&data, 1754 &m->mbr.mbr_parts[i], m->sector, err_msg)) 1755 return false; 1756 if (data.last_mounted && m->last_mounted[i] && 1757 data.last_mounted != m->last_mounted[i]) { 1758 free(__UNCONST(m->last_mounted[i])); 1759 m->last_mounted[i] = strdup(data.last_mounted); 1760 } 1761 if (data.fs_type != 0) 1762 m->fs_type[i] = data.fs_type; 1763 if (data.fs_sub_type != 0) 1764 m->fs_sub_type[i] = data.fs_sub_type; 1765 1766 if (m == &parts->mbr) { 1767 if (m->mbr.mbr_parts[i].mbrp_start != 1768 old_start) 1769 mbr_sort_main_mbr(&m->mbr); 1770 } else { 1771 adjust_ext_part(&parts->mbr, 1772 data.start, data.size); 1773 } 1774 mbr_calc_free_space(parts); 1775 return true; 1776 } 1777 1778 static bool 1779 mbr_find_netbsd(const struct mbr_info_t *m, uint start, 1780 struct disk_part_info *info) 1781 { 1782 size_t i; 1783 bool prim = true; 1784 1785 do { 1786 for (i = 0; i < MBR_PART_COUNT; i++) { 1787 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 1788 continue; 1789 1790 if (!prim && i > 0 && 1791 MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) 1792 break; 1793 1794 const struct mbr_partition *mp = &m->mbr.mbr_parts[i]; 1795 if (mp->mbrp_type != MBR_PTYPE_NETBSD) 1796 continue; 1797 1798 mbr_partition_to_info(mp, m->sector, info); 1799 if (m->last_mounted[i] && *m->last_mounted[i] != 0) 1800 info->last_mounted = 1801 m->last_mounted[i]; 1802 info->fs_type = m->fs_type[i]; 1803 info->fs_sub_type = m->fs_sub_type[i]; 1804 if (start > 0 && start != info->start) 1805 continue; 1806 return true; 1807 } 1808 prim = false; 1809 } while ((m = m->extended)); 1810 1811 return false; 1812 } 1813 1814 static struct disk_partitions * 1815 mbr_read_disklabel(struct disk_partitions *arg, daddr_t start, bool force_empty) 1816 { 1817 struct mbr_disk_partitions *myparts = 1818 (struct mbr_disk_partitions*)arg; 1819 struct disk_part_info part; 1820 struct disk_part_free_space space; 1821 1822 if (force_empty && myparts->dlabel) 1823 myparts->dlabel->pscheme->delete_all_partitions( 1824 myparts->dlabel); 1825 1826 if (myparts->dlabel == NULL) { 1827 /* 1828 * Find the NetBSD MBR partition 1829 */ 1830 if (!mbr_find_netbsd(&myparts->mbr, start, &part)) { 1831 if (!force_empty) 1832 return NULL; 1833 1834 /* add a "whole disk" NetBSD partition */ 1835 memset(&part, 0, sizeof part); 1836 part.start = min(myparts->ptn_0_offset,start); 1837 if (!mbr_get_free_spaces(arg, &space, 1, 1838 part.start, myparts->ptn_alignment, -1, -1)) 1839 return NULL; 1840 part.start = space.start; 1841 part.size = space.size; 1842 part.nat_type = &mbr_gen_type_desc[MBR_PTYPE_NETBSD].gen; 1843 mbr_add_part(arg, &part, NULL); 1844 if (!mbr_find_netbsd(&myparts->mbr, start, &part)) 1845 return NULL; 1846 } 1847 1848 if (!force_empty) { 1849 myparts->dlabel = disklabel_parts.read_from_disk( 1850 myparts->dp.disk, part.start, part.size, 1851 myparts->dp.bytes_per_sector, &disklabel_parts); 1852 if (myparts->dlabel != NULL) 1853 myparts->dlabel->parent = &myparts->dp; 1854 } 1855 1856 if (myparts->dlabel == NULL && part.size > 0) { 1857 /* we just created the outer partitions? */ 1858 myparts->dlabel = 1859 disklabel_parts.create_new_for_disk( 1860 myparts->dp.disk, part.start, part.size, 1861 false, &myparts->dp); 1862 } 1863 1864 if (myparts->dlabel != NULL) 1865 myparts->dlabel->pscheme->change_disk_geom( 1866 myparts->dlabel, myparts->geo_cyl, 1867 myparts->geo_head, myparts->geo_sec); 1868 } 1869 return myparts->dlabel; 1870 } 1871 1872 static int 1873 get_mapping(struct mbr_partition *parts, int i, 1874 int *cylinder, int *head, int *sector, daddr_t *absolute) 1875 { 1876 struct mbr_partition *apart = &parts[i / 2]; 1877 1878 if (apart->mbrp_type == MBR_PTYPE_UNUSED) 1879 return -1; 1880 if (i % 2 == 0) { 1881 *cylinder = MBR_PCYL(apart->mbrp_scyl, apart->mbrp_ssect); 1882 *head = apart->mbrp_shd; 1883 *sector = MBR_PSECT(apart->mbrp_ssect) - 1; 1884 *absolute = le32toh(apart->mbrp_start); 1885 } else { 1886 *cylinder = MBR_PCYL(apart->mbrp_ecyl, apart->mbrp_esect); 1887 *head = apart->mbrp_ehd; 1888 *sector = MBR_PSECT(apart->mbrp_esect) - 1; 1889 *absolute = le32toh(apart->mbrp_start) 1890 + le32toh(apart->mbrp_size) - 1; 1891 } 1892 /* Sanity check the data against max values */ 1893 if ((((*cylinder * MAXHEAD) + *head) * (uint32_t)MAXSECTOR + *sector) < *absolute) 1894 /* cannot be a CHS mapping */ 1895 return -1; 1896 1897 return 0; 1898 } 1899 1900 static bool 1901 mbr_delete_all(struct disk_partitions *arg) 1902 { 1903 struct mbr_disk_partitions *myparts = (struct mbr_disk_partitions*)arg; 1904 struct mbr_sector *mbrs = &myparts->mbr.mbr; 1905 struct mbr_info_t *mbri = &myparts->mbr; 1906 mbr_info_t *ext; 1907 struct mbr_partition *part; 1908 1909 part = &mbrs->mbr_parts[0]; 1910 /* Set the partition information for full disk usage. */ 1911 while ((ext = mbri->extended)) { 1912 mbri->extended = ext->extended; 1913 free_mbr_info(ext); 1914 } 1915 memset(part, 0, MBR_PART_COUNT * sizeof *part); 1916 #ifdef BOOTSEL 1917 memset(&mbri->mbrb, 0, sizeof mbri->mbrb); 1918 #endif 1919 1920 /* 1921 * We may have changed alignment settings due to partitions 1922 * ending on an MB boundary - undo that, now that the partitions 1923 * are gone. 1924 */ 1925 mbr_change_disk_geom(arg, myparts->geo_cyl, myparts->geo_head, 1926 myparts->geo_sec); 1927 1928 return true; 1929 } 1930 1931 /* 1932 * helper function to fix up mbrp_start and mbrp_size for the 1933 * extended MBRs "partition b" entries after addition/deletion 1934 * of some partition. 1935 */ 1936 static void 1937 mbr_fixup_ext_chain(mbr_info_t *primary, uint ext_start, uint ext_end) 1938 { 1939 for (mbr_info_t *m = primary->extended; m != NULL; m = m->extended) { 1940 if (m->extended == NULL) { 1941 m->mbr.mbr_parts[1].mbrp_type = MBR_PTYPE_UNUSED; 1942 m->mbr.mbr_parts[1].mbrp_start = 0; 1943 m->mbr.mbr_parts[1].mbrp_size = 0; 1944 } else { 1945 uint n_end, n_start = m->extended->sector; 1946 if (m->extended->extended) 1947 n_end = m->extended->extended->sector; 1948 else 1949 n_end = ext_end; 1950 m->mbr.mbr_parts[1].mbrp_type = MBR_PTYPE_EXT; 1951 m->mbr.mbr_parts[1].mbrp_start = n_start - ext_start; 1952 m->mbr.mbr_parts[1].mbrp_size = n_end - n_start; 1953 } 1954 } 1955 } 1956 1957 struct delete_part_args { 1958 struct mbr_disk_partitions *parts; 1959 daddr_t start, size; 1960 const char **err_msg; 1961 }; 1962 1963 static bool 1964 mbr_do_delete_part(const struct disk_partitions *arg, part_id id, 1965 const mbr_info_t *mb, int i, bool primary, 1966 const struct mbr_partition *mp, void *cookie) 1967 { 1968 struct delete_part_args *marg = cookie; 1969 bool is_ext_part = MBR_IS_EXTENDED(mp->mbrp_type); 1970 1971 /* can not delete non-empty extended partitions */ 1972 if (MBR_IS_EXTENDED(mp->mbrp_type) 1973 && marg->parts->mbr.extended != NULL) { 1974 if (marg->err_msg) 1975 *marg->err_msg = msg_string(MSG_mbr_ext_not_empty); 1976 return false; 1977 } 1978 1979 /* return position/size to caller */ 1980 marg->start = mb->sector + mp->mbrp_start; 1981 marg->size = mp->mbrp_size; 1982 1983 if (primary) { 1984 /* if deleting the primary extended partition, just kill it */ 1985 struct mbr_partition *md = &marg->parts->mbr.mbr.mbr_parts[i]; 1986 md->mbrp_size = 0; 1987 md->mbrp_start = 0; 1988 md->mbrp_type = MBR_PTYPE_UNUSED; 1989 if (marg->parts->mbr.last_mounted[i]) { 1990 free(__UNCONST(marg->parts->mbr.last_mounted[i])); 1991 marg->parts->mbr.last_mounted[i] = NULL; 1992 } 1993 if (is_ext_part) { 1994 for (mbr_info_t *m = marg->parts->mbr.extended; 1995 m != NULL; ) { 1996 mbr_info_t *n = m->extended; 1997 free_mbr_info(m); 1998 m = n; 1999 } 2000 marg->parts->mbr.extended = NULL; 2001 } 2002 } else { 2003 /* find the size of the primary extended partition */ 2004 uint ext_start = 0, ext_size = 0; 2005 for (i = 0; i < MBR_PART_COUNT; i++) { 2006 if (!MBR_IS_EXTENDED(marg->parts->mbr.mbr.mbr_parts[i] 2007 .mbrp_type)) 2008 continue; 2009 ext_start = marg->parts->mbr.mbr.mbr_parts[i] 2010 .mbrp_start; 2011 ext_size = marg->parts->mbr.mbr.mbr_parts[i] 2012 .mbrp_size; 2013 break; 2014 } 2015 2016 /* 2017 * If we are in an extended partition chain, unlink this MBR, 2018 * unless it is the very first one at the start of the extended 2019 * partition (we would have no previos ext mbr to fix up 2020 * the chain in that case) 2021 */ 2022 if (marg->parts->mbr.extended == mb) { 2023 struct mbr_partition *part = 2024 &marg->parts->mbr.extended->mbr.mbr_parts[0]; 2025 part->mbrp_type = MBR_PTYPE_UNUSED; 2026 part->mbrp_start = 0; 2027 part->mbrp_size = 0; 2028 } else { 2029 mbr_info_t *p, *last; 2030 for (last = NULL, p = &marg->parts->mbr; p != NULL; 2031 last = p, p = p->extended) 2032 if (p == mb) 2033 break; 2034 if (last == NULL) { 2035 if (marg->err_msg != NULL) 2036 *marg->err_msg= INTERNAL_ERROR; 2037 return false; 2038 } 2039 last->extended = p->extended; 2040 free_mbr_info(p); 2041 if (last == &marg->parts->mbr && last->extended && 2042 last->extended->extended == NULL && 2043 last->extended->mbr.mbr_parts[0].mbrp_type == 2044 MBR_PTYPE_UNUSED) { 2045 /* 2046 * we deleted the last extended sector, 2047 * remove the whole chain 2048 */ 2049 free_mbr_info(last->extended); 2050 last->extended = NULL; 2051 } 2052 } 2053 mbr_fixup_ext_chain(&marg->parts->mbr, ext_start, 2054 ext_start+ext_size); 2055 } 2056 mbr_calc_free_space(marg->parts); 2057 return true; 2058 } 2059 2060 static bool 2061 mbr_delete_part(struct disk_partitions *arg, part_id pno, const char **err_msg) 2062 { 2063 struct mbr_disk_partitions *parts = 2064 (struct mbr_disk_partitions*)arg; 2065 struct delete_part_args data = { .parts = parts, .err_msg = err_msg }; 2066 2067 if (!mbr_part_apply(arg, pno, mbr_do_delete_part, &data)) { 2068 if (err_msg) 2069 *err_msg = INTERNAL_ERROR; 2070 return false; 2071 } 2072 2073 if (parts->dlabel) { 2074 /* 2075 * If we change the mbr partitioning, the we must 2076 * remove any references in the netbsd disklabel 2077 * to the part we changed. 2078 */ 2079 parts->dlabel->pscheme->delete_partitions_in_range( 2080 parts->dlabel, data.start, data.size); 2081 } 2082 2083 if (err_msg) 2084 *err_msg = NULL; 2085 2086 dump_mbr(&parts->mbr, "after delete"); 2087 return true; 2088 } 2089 2090 static struct mbr_partition * 2091 mbr_ptr_from_start(mbr_info_t *m, daddr_t start) 2092 { 2093 bool primary = true; 2094 2095 do { 2096 for (uint i = 0; i < MBR_PART_COUNT; i++) { 2097 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 2098 continue; 2099 if (!primary && 2100 MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) 2101 break; 2102 2103 daddr_t pstart = m->sector + 2104 m->mbr.mbr_parts[i].mbrp_start; 2105 if (pstart == start) 2106 return &m->mbr.mbr_parts[i]; 2107 2108 } 2109 primary = false; 2110 } while ((m = m->extended)); 2111 2112 return NULL; 2113 } 2114 2115 static uint8_t 2116 mbr_type_from_start(const mbr_info_t *m, daddr_t start) 2117 { 2118 bool primary = true; 2119 2120 do { 2121 for (uint i = 0; i < MBR_PART_COUNT; i++) { 2122 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 2123 continue; 2124 if (!primary && 2125 MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) 2126 break; 2127 2128 daddr_t pstart = m->sector + 2129 m->mbr.mbr_parts[i].mbrp_start; 2130 if (pstart == start) 2131 return m->mbr.mbr_parts[i].mbrp_type; 2132 2133 } 2134 primary = false; 2135 } while ((m = m->extended)); 2136 2137 return MBR_PTYPE_UNUSED; 2138 } 2139 2140 static part_id 2141 mbr_add_part(struct disk_partitions *arg, 2142 const struct disk_part_info *info, const char **errmsg) 2143 { 2144 struct mbr_disk_partitions *parts = 2145 (struct mbr_disk_partitions*)arg; 2146 part_id i, j, no, free_primary = UINT_MAX; 2147 mbr_info_t *m = &parts->mbr, *me, *last, *t; 2148 daddr_t ext_start = 0, ext_size = 0; 2149 uint start, size; 2150 struct disk_part_info data = *info; 2151 struct mbr_partition *newp; 2152 2153 if (errmsg != NULL) 2154 *errmsg = NULL; 2155 2156 assert(info->nat_type != NULL); 2157 if (info->nat_type == NULL) { 2158 if (errmsg != NULL) 2159 *errmsg = INTERNAL_ERROR; 2160 return NO_PART; 2161 } 2162 if (mbr_type_from_gen_desc(info->nat_type) == MBR_PTYPE_UNUSED) { 2163 if (errmsg != NULL) 2164 *errmsg = INTERNAL_ERROR; 2165 return NO_PART; 2166 } 2167 2168 /* do we have free primary slots and/or an extended partition? */ 2169 for (i = 0; i < MBR_PART_COUNT; i++) { 2170 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED 2171 && free_primary > MBR_PART_COUNT) 2172 free_primary = i; 2173 if (MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) { 2174 ext_start = m->mbr.mbr_parts[i].mbrp_start+m->sector; 2175 ext_size = m->mbr.mbr_parts[i].mbrp_size; 2176 continue; 2177 } 2178 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED 2179 && m->mbr.mbr_parts[i].mbrp_size == 0) 2180 continue; 2181 } 2182 if (ext_start > 0 && ext_size > 0 && 2183 MBR_IS_EXTENDED(mbr_type_from_gen_desc(info->nat_type))) { 2184 /* 2185 * Do not allow a second extended partition 2186 */ 2187 if (errmsg) 2188 *errmsg = MSG_Only_one_extended_ptn; 2189 return NO_PART; 2190 } 2191 2192 /* should this go into the extended partition? */ 2193 if (ext_size > 0 && info->start >= ext_start 2194 && info->start < ext_start + ext_size) { 2195 2196 /* must fit into the extended partition */ 2197 if (info->start + info->size > ext_start + ext_size) { 2198 if (errmsg != NULL) 2199 *errmsg = MSG_mbr_ext_nofit; 2200 return NO_PART; 2201 } 2202 2203 /* walk the chain untill we find a proper insert position */ 2204 daddr_t e_end, e_start; 2205 for (last = m, m = m->extended; m != NULL; 2206 last = m, m = m->extended) { 2207 e_start = m->mbr.mbr_parts[1].mbrp_start 2208 + ext_start; 2209 e_end = e_start + m->mbr.mbr_parts[1].mbrp_size; 2210 if (data.start <= e_start) 2211 break; 2212 } 2213 if (m == NULL) { 2214 /* add new tail record */ 2215 e_end = ext_start + ext_size; 2216 /* new part needs to fit inside primary extended one */ 2217 if (data.start + data.size > e_end) { 2218 if (errmsg) 2219 *errmsg = MSG_No_free_space; 2220 return NO_PART; 2221 } 2222 } else if (data.start + data.size > e_start) { 2223 /* new part needs to fit before next extended */ 2224 if (errmsg) 2225 *errmsg = MSG_No_free_space; 2226 return NO_PART; 2227 } 2228 /* 2229 * now last points to previous mbr (maybe primary), m 2230 * points to the one that should take the new partition 2231 * or we have to insert a new mbr between the two, or 2232 * m needs to be split and we go into the one after it. 2233 */ 2234 if (m && m->mbr.mbr_parts[0].mbrp_type == MBR_PTYPE_UNUSED) { 2235 /* empty slot, we can just use it */ 2236 newp = &m->mbr.mbr_parts[0]; 2237 mbr_info_to_partitition(&data, &m->mbr.mbr_parts[0], 2238 m->sector, errmsg); 2239 if (data.last_mounted && m->last_mounted[0] && 2240 data.last_mounted != m->last_mounted[0]) { 2241 free(__UNCONST(m->last_mounted[0])); 2242 m->last_mounted[0] = strdup(data.last_mounted); 2243 } 2244 } else { 2245 mbr_info_t *new_mbr; 2246 if (m == NULL) 2247 m = last; 2248 daddr_t p_start = m->mbr.mbr_parts[0].mbrp_start 2249 + m->sector; 2250 daddr_t p_end = p_start 2251 + m->mbr.mbr_parts[0].mbrp_size; 2252 bool before; 2253 if (m == last || data.start > p_end) 2254 before = false; 2255 else if (data.start + data.size < p_start) 2256 before = true; 2257 else { 2258 if (errmsg) 2259 *errmsg = MSG_No_free_space; 2260 return NO_PART; 2261 } 2262 new_mbr = calloc(1, sizeof *new_mbr); 2263 if (!new_mbr) { 2264 if (errmsg) 2265 *errmsg = err_outofmem; 2266 return NO_PART; 2267 } 2268 new_mbr->mbr.mbr_magic = htole16(MBR_MAGIC); 2269 new_mbr->mbr.mbr_parts[1].mbrp_type = MBR_PTYPE_EXT; 2270 if (before) { 2271 /* 2272 * This is a hypthetical case where 2273 * an extended MBR uses an unusual high 2274 * offset (m->sector to parts[0].mbrp_start) 2275 * and we want to go into that space. 2276 * Should not happen in the real world (tm) 2277 * and is untested.... 2278 */ 2279 2280 /* make sure the aligned new mbr fits */ 2281 uint mbrsec = rounddown(p_start, 2282 parts->ext_ptn_alignment); 2283 if (mbrsec <= data.start + data.size) 2284 data.size = mbrsec-1-data.start; 2285 2286 /* now the new partition data is ready, 2287 * write out to old position */ 2288 new_mbr->sector = m->sector; 2289 newp = &new_mbr->mbr.mbr_parts[0]; 2290 mbr_info_to_partitition(&data, 2291 &new_mbr->mbr.mbr_parts[0], 2292 new_mbr->sector, errmsg); 2293 if (data.last_mounted && m->last_mounted[0] && 2294 data.last_mounted != m->last_mounted[0]) { 2295 free(__UNCONST(m->last_mounted[0])); 2296 m->last_mounted[0] = 2297 strdup(data.last_mounted); 2298 } 2299 new_mbr->extended = m; 2300 } else { 2301 new_mbr->sector = max(roundup(data.start, 2302 parts->ext_ptn_alignment), 2303 parts->ext_ptn_alignment); 2304 uint off = new_mbr->sector - data.start; 2305 data.start += parts->ptn_0_offset+off; 2306 if (data.start + data.size > e_end) 2307 data.size = e_end - data.start; 2308 newp = &new_mbr->mbr.mbr_parts[0]; 2309 mbr_info_to_partitition(&data, 2310 &new_mbr->mbr.mbr_parts[0], 2311 new_mbr->sector, errmsg); 2312 if (data.last_mounted && m->last_mounted[0] && 2313 data.last_mounted != m->last_mounted[0]) { 2314 free(__UNCONST(m->last_mounted[0])); 2315 m->last_mounted[0] = 2316 strdup(data.last_mounted); 2317 } 2318 /* 2319 * Special case: if we are creating the 2320 * first extended mbr, but do not start 2321 * at the beginning of the primary 2322 * extended partition, we need to insert 2323 * another extended mbr at the start. 2324 */ 2325 if (m == &parts->mbr && m->extended == NULL 2326 && new_mbr->sector > ext_start) { 2327 t = calloc(1, sizeof *new_mbr); 2328 if (!t) { 2329 free_mbr_info(new_mbr); 2330 if (errmsg) 2331 *errmsg = err_outofmem; 2332 return NO_PART; 2333 } 2334 t->sector = ext_start; 2335 t->mbr.mbr_magic = htole16(MBR_MAGIC); 2336 t->mbr.mbr_parts[1].mbrp_type = 2337 MBR_PTYPE_EXT; 2338 m->extended = t; 2339 m = t; 2340 } 2341 new_mbr->extended = m->extended; 2342 m->extended = new_mbr; 2343 } 2344 } 2345 mbr_fixup_ext_chain(&parts->mbr, ext_start, ext_start+ext_size); 2346 dump_mbr(&parts->mbr, "after adding in extended"); 2347 goto find_rval; 2348 } 2349 2350 /* this one is for the primary boot block */ 2351 if (free_primary > MBR_PART_COUNT) { 2352 if (errmsg != NULL) 2353 *errmsg = ext_size > 0 ? 2354 MSG_mbr_no_free_primary_have_ext 2355 : MSG_mbr_no_free_primary_no_ext; 2356 return NO_PART; 2357 } 2358 2359 start = max(info->start, parts->ptn_0_offset); 2360 size = info->size; 2361 if (find_mbr_space(m, &start, &size, start, parts->dp.disk_size, 2362 start, true) < 0 || size < info->size) { 2363 if (errmsg != NULL) 2364 *errmsg = MSG_No_free_space; 2365 return NO_PART; 2366 } 2367 data.start = start; 2368 if (MBR_IS_EXTENDED(mbr_type_from_gen_desc(info->nat_type))) { 2369 data.start = max(roundup(data.start, parts->ext_ptn_alignment), 2370 parts->ext_ptn_alignment); 2371 } 2372 if (data.start + data.size > start + size) 2373 data.size = start + size - data.start; 2374 mbr_info_to_partitition(&data, &m->mbr.mbr_parts[free_primary], 2375 m->sector, errmsg); 2376 if (data.last_mounted && m->last_mounted[free_primary] && 2377 data.last_mounted != m->last_mounted[free_primary]) { 2378 free(__UNCONST(m->last_mounted[free_primary])); 2379 m->last_mounted[free_primary] = strdup(data.last_mounted); 2380 } 2381 start = m->mbr.mbr_parts[free_primary].mbrp_start; 2382 mbr_sort_main_mbr(&m->mbr); 2383 2384 /* find the partition again after sorting */ 2385 newp = NULL; 2386 for (i = 0; i < MBR_PART_COUNT; i++) { 2387 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 2388 continue; 2389 if (m->mbr.mbr_parts[i].mbrp_start != start) 2390 continue; 2391 newp = &m->mbr.mbr_parts[i]; 2392 break; 2393 } 2394 2395 dump_mbr(&parts->mbr, "after adding in primary"); 2396 2397 find_rval: 2398 mbr_calc_free_space(parts); 2399 if (newp == NULL) 2400 return 0; 2401 2402 /* 2403 * Now newp points to the modified partition entry but we do not know 2404 * a good part_id for it. 2405 * Iterate from start and find it. 2406 */ 2407 no = 0; 2408 for (i = 0; i < MBR_PART_COUNT; i++) { 2409 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 2410 continue; 2411 2412 if (newp == &m->mbr.mbr_parts[i]) 2413 return no; 2414 no++; 2415 2416 if (MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) { 2417 for (me = m->extended; me != NULL; me = me->extended) { 2418 for (j = 0; j < MBR_PART_COUNT; j++) { 2419 if (me->mbr.mbr_parts[j].mbrp_type == 2420 MBR_PTYPE_UNUSED) 2421 continue; 2422 if (j > 0 && MBR_IS_EXTENDED( 2423 me->mbr.mbr_parts[j].mbrp_type)) 2424 break; 2425 if (newp == &me->mbr.mbr_parts[j]) 2426 return no; 2427 no++; 2428 } 2429 } 2430 } 2431 } 2432 return 0; 2433 } 2434 2435 static int 2436 mbr_guess_geom(struct disk_partitions *arg, int *cyl, int *head, int *sec) 2437 { 2438 struct mbr_disk_partitions *myparts = (struct mbr_disk_partitions*)arg; 2439 struct mbr_sector *mbrs = &myparts->mbr.mbr; 2440 struct mbr_partition *parts = &mbrs->mbr_parts[0]; 2441 int xcylinders, xheads, i, j; 2442 daddr_t xsectors, xsize; 2443 int c1, h1, s1, c2, h2, s2; 2444 daddr_t a1, a2; 2445 uint64_t num, denom; 2446 2447 xheads = -1; 2448 2449 /* Try to deduce the number of heads from two different mappings. */ 2450 for (i = 0; i < MBR_PART_COUNT * 2 - 1; i++) { 2451 if (get_mapping(parts, i, &c1, &h1, &s1, &a1) < 0) 2452 continue; 2453 a1 -= s1; 2454 for (j = i + 1; j < MBR_PART_COUNT * 2; j++) { 2455 if (get_mapping(parts, j, &c2, &h2, &s2, &a2) < 0) 2456 continue; 2457 a2 -= s2; 2458 num = (uint64_t)h1 * a2 - (quad_t)h2 * a1; 2459 denom = (uint64_t)c2 * a1 - (quad_t)c1 * a2; 2460 if (num != 0 && denom != 0 && num % denom == 0) { 2461 xheads = (int)(num / denom); 2462 xsectors = a1 / (c1 * xheads + h1); 2463 break; 2464 } 2465 } 2466 if (xheads != -1) 2467 break; 2468 } 2469 2470 if (xheads == -1) 2471 return -1; 2472 2473 /* 2474 * Estimate the number of cylinders. 2475 * XXX relies on get_disks having been called. 2476 */ 2477 xsize = min(pm->dlsize, mbr_parts.size_limit); 2478 xcylinders = xsize / xheads / xsectors; 2479 if (xsize != xcylinders * xheads * xsectors) 2480 xcylinders++; 2481 2482 /* 2483 * Now verify consistency with each of the partition table entries. 2484 * Be willing to shove cylinders up a little bit to make things work, 2485 * but translation mismatches are fatal. 2486 */ 2487 for (i = 0; i < MBR_PART_COUNT * 2; i++) { 2488 if (get_mapping(parts, i, &c1, &h1, &s1, &a1) < 0) 2489 continue; 2490 if (c1 >= MAXCYL - 1) 2491 /* Ignore anything that is near the CHS limit */ 2492 continue; 2493 if (xsectors * (c1 * xheads + h1) + s1 != a1) 2494 return -1; 2495 } 2496 2497 /* 2498 * Everything checks out. Reset the geometry to use for further 2499 * calculations. 2500 */ 2501 *cyl = MIN(xcylinders, MAXCYL); 2502 *head = xheads; 2503 *sec = xsectors; 2504 return 0; 2505 } 2506 2507 static size_t 2508 mbr_get_cylinder(const struct disk_partitions *arg) 2509 { 2510 const struct mbr_disk_partitions *parts = 2511 (const struct mbr_disk_partitions*)arg; 2512 2513 return parts->geo_cyl; 2514 } 2515 2516 static daddr_t 2517 mbr_max_part_size(const struct disk_partitions *arg, daddr_t fp_start) 2518 { 2519 const struct mbr_disk_partitions *parts = 2520 (const struct mbr_disk_partitions*)arg; 2521 uint start = fp_start, size = 0; 2522 uint8_t pt; 2523 2524 start = fp_start; 2525 pt = mbr_type_from_start(&parts->mbr, start); 2526 if (find_mbr_space(&parts->mbr, &start, &size, start, 2527 parts->dp.disk_size, start, MBR_IS_EXTENDED(pt)) < 0) 2528 return 0; 2529 2530 return size; 2531 } 2532 2533 static size_t 2534 mbr_get_free_spaces(const struct disk_partitions *arg, 2535 struct disk_part_free_space *result, size_t max_num_result, 2536 daddr_t min_size, daddr_t align, daddr_t lower_bound, daddr_t ignore) 2537 { 2538 const struct mbr_disk_partitions *parts = 2539 (const struct mbr_disk_partitions*)arg; 2540 uint start = 0, size = 0, from, next; 2541 size_t spaces = 0; 2542 2543 if (min_size < 1) 2544 min_size = 1; 2545 from = parts->ptn_0_offset; 2546 if (lower_bound > from) 2547 from = lower_bound; 2548 for ( ; from < parts->dp.disk_size && spaces < max_num_result; ) { 2549 if (find_mbr_space(&parts->mbr, &start, &size, from, 2550 parts->dp.disk_size, ignore > 0 ? (uint)ignore : UINT_MAX, 2551 false) < 0) 2552 break; 2553 next = start + size + 1; 2554 if (align > 0) { 2555 uint nv = max(roundup(start, align), align); 2556 uint off = nv - start; 2557 start = nv; 2558 if (size > off) 2559 size -= off; 2560 else 2561 size = 0; 2562 } 2563 if (size > min_size) { 2564 result[spaces].start = start; 2565 result[spaces].size = size; 2566 spaces++; 2567 } 2568 if ((daddr_t)start + (daddr_t)size + 1 >= mbr_parts.size_limit) 2569 break; 2570 from = next; 2571 } 2572 2573 return spaces; 2574 } 2575 2576 static bool 2577 mbr_can_add_partition(const struct disk_partitions *arg) 2578 { 2579 const struct mbr_disk_partitions *myparts = 2580 (const struct mbr_disk_partitions*)arg; 2581 struct disk_part_free_space space; 2582 bool free_primary, have_extended; 2583 2584 if (arg->free_space < myparts->ptn_alignment) 2585 return false; 2586 2587 if (mbr_get_free_spaces(arg, &space, 1, myparts->ptn_alignment, 2588 myparts->ptn_alignment, 0, -1) < 1) 2589 return false; 2590 2591 for (int i = 0; i < MBR_PART_COUNT; i++) { 2592 uint8_t t = myparts->mbr.mbr.mbr_parts[i].mbrp_type; 2593 2594 if (t == MBR_PTYPE_UNUSED && 2595 myparts->mbr.mbr.mbr_parts[i].mbrp_size == 0) 2596 free_primary = true; 2597 2598 if (MBR_IS_EXTENDED(t)) 2599 have_extended = true; 2600 } 2601 2602 if (have_extended) 2603 return true; 2604 2605 return free_primary; 2606 } 2607 2608 static void 2609 mbr_free_wedge(int *fd, const char *disk, const char *wedge) 2610 { 2611 struct dkwedge_info dkw; 2612 char diskpath[MAXPATHLEN]; 2613 2614 if (*fd == -1) 2615 *fd = opendisk(disk, O_RDWR, diskpath, 2616 sizeof(diskpath), 0); 2617 if (*fd != -1) { 2618 memset(&dkw, 0, sizeof(dkw)); 2619 strlcpy(dkw.dkw_devname, wedge, 2620 sizeof(dkw.dkw_devname)); 2621 ioctl(*fd, DIOCDWEDGE, &dkw); 2622 } 2623 } 2624 2625 static void 2626 mbr_free(struct disk_partitions *arg) 2627 { 2628 struct mbr_disk_partitions *parts = (struct mbr_disk_partitions*)arg; 2629 mbr_info_t *m; 2630 int i, fd; 2631 2632 assert(parts != NULL); 2633 2634 fd = -1; 2635 m = &parts->mbr; 2636 do { 2637 for (i = 0; i < MBR_PART_COUNT; i++) { 2638 if (m->wedge[i][0] != 0) 2639 mbr_free_wedge(&fd, arg->disk, m->wedge[i]); 2640 } 2641 } while ((m = m->extended)); 2642 2643 if (fd != -1) 2644 close(fd); 2645 2646 if (parts->dlabel) 2647 parts->dlabel->pscheme->free(parts->dlabel); 2648 2649 free_mbr_info(parts->mbr.extended); 2650 free_last_mounted(&parts->mbr); 2651 free(__UNCONST(parts->dp.disk)); 2652 free(parts); 2653 } 2654 2655 static bool 2656 mbr_verify_for_update(struct disk_partitions *arg) 2657 { 2658 struct mbr_disk_partitions *parts = 2659 (struct mbr_disk_partitions*)arg; 2660 2661 return md_mbr_update_check(arg, &parts->mbr); 2662 } 2663 2664 static int 2665 mbr_verify(struct disk_partitions *arg, bool quiet) 2666 { 2667 struct mbr_disk_partitions *parts = 2668 (struct mbr_disk_partitions*)arg; 2669 mbr_info_t *m = &parts->mbr; 2670 int i; 2671 bool active_found = false; 2672 2673 for (i = 0; i < MBR_PART_COUNT; i++) { 2674 if (m->mbr.mbr_parts[i].mbrp_flag & MBR_PFLAG_ACTIVE) { 2675 active_found = true; 2676 break; 2677 } 2678 } 2679 2680 if (!active_found && pm->ptstart > 0) { 2681 struct mbr_partition *mp = mbr_ptr_from_start(m, pm->ptstart); 2682 2683 if (mp) { 2684 if (!quiet) 2685 msg_display(MSG_noactivepart); 2686 if (quiet || ask_yesno(MSG_fixactivepart)) { 2687 mp->mbrp_flag |= MBR_PFLAG_ACTIVE; 2688 active_found = true; 2689 } 2690 } 2691 } 2692 if (!active_found && !quiet) { 2693 msg_display(MSG_noactivepart); 2694 i = ask_reedit(arg); 2695 if (i <= 1) 2696 return i; 2697 } 2698 2699 for (i = 0; i < MBR_PART_COUNT; i++) { 2700 if (m->mbr.mbr_parts[i].mbrp_type != MBR_PTYPE_NETBSD) 2701 continue; 2702 m->mbr.mbr_parts[i].mbrp_flag |= MBR_PFLAG_ACTIVE; 2703 break; 2704 } 2705 2706 return md_check_mbr(arg, &parts->mbr, quiet); 2707 } 2708 2709 static bool 2710 mbr_guess_root(const struct disk_partitions *arg, 2711 daddr_t *start, daddr_t *size) 2712 { 2713 const struct mbr_disk_partitions *parts = 2714 (const struct mbr_disk_partitions*)arg; 2715 const mbr_info_t *m = &parts->mbr; 2716 size_t i, num_found; 2717 bool prim = true; 2718 daddr_t pstart, psize; 2719 2720 num_found = 0; 2721 do { 2722 for (i = 0; i < MBR_PART_COUNT; i++) { 2723 if (m->mbr.mbr_parts[i].mbrp_type == MBR_PTYPE_UNUSED) 2724 continue; 2725 2726 if (!prim && i > 0 && 2727 MBR_IS_EXTENDED(m->mbr.mbr_parts[i].mbrp_type)) 2728 break; 2729 2730 const struct mbr_partition *mp = &m->mbr.mbr_parts[i]; 2731 if (mp->mbrp_type != MBR_PTYPE_NETBSD) 2732 continue; 2733 2734 if (num_found == 0) { 2735 pstart = m->sector + mp->mbrp_start; 2736 psize = mp->mbrp_size; 2737 } 2738 num_found++; 2739 2740 if (m->last_mounted[i] != NULL && 2741 strcmp(m->last_mounted[i], "/") == 0) { 2742 *start = pstart; 2743 *size = psize; 2744 return true; 2745 } 2746 } 2747 prim = false; 2748 } while ((m = m->extended)); 2749 2750 if (num_found == 1) { 2751 *start = pstart; 2752 *size = psize; 2753 return true; 2754 } 2755 2756 return false; 2757 } 2758 2759 struct part_attr_fmt_data { 2760 char *str; 2761 size_t avail_space, attr_no; 2762 const struct mbr_disk_partitions *parts; 2763 const struct disk_part_info *info; 2764 }; 2765 2766 struct part_attr_set_data { 2767 size_t attr_no; 2768 const struct mbr_disk_partitions *parts; 2769 const char *str; 2770 mbr_info_t *mbr; 2771 }; 2772 2773 static bool 2774 part_attr_fornat_str(const struct disk_partitions *arg, part_id id, 2775 const mbr_info_t *mb, int i, bool primary, 2776 const struct mbr_partition *mp, void *cookie) 2777 { 2778 const struct mbr_disk_partitions *parts = 2779 (const struct mbr_disk_partitions*)arg; 2780 struct part_attr_fmt_data *data = cookie; 2781 const char *attrtype = parts->dp.pscheme 2782 ->custom_attributes[data->attr_no].label; 2783 2784 if (attrtype == MSG_ptn_active) { 2785 strlcpy(data->str, 2786 msg_string(primary && (mp->mbrp_flag & MBR_PFLAG_ACTIVE) ? 2787 MSG_Yes : MSG_No), data->avail_space); 2788 return true; 2789 #if BOOTSEL 2790 } else if (attrtype == MSG_boot_dflt) { 2791 strlcpy(data->str, 2792 msg_string( 2793 (parts->mbr.bootsec == mb->sector+mp->mbrp_start) ? 2794 MSG_Yes : MSG_No), data->avail_space); 2795 return true; 2796 } else if (attrtype == MSG_bootmenu) { 2797 strlcpy(data->str, mb->mbrb.mbrbs_nametab[i], 2798 data->avail_space); 2799 #endif 2800 } 2801 2802 return false; 2803 } 2804 2805 static bool 2806 part_attr_set_str(const struct disk_partitions *arg, part_id id, 2807 const mbr_info_t *mb, int i, bool primary, 2808 const struct mbr_partition *mp, void *cookie) 2809 { 2810 struct part_attr_set_data *data = cookie; 2811 const char *str = data->str; 2812 #ifdef BOOTSEL 2813 const struct mbr_disk_partitions *parts = 2814 (const struct mbr_disk_partitions*)arg; 2815 const char *attrtype = parts->dp.pscheme 2816 ->custom_attributes[data->attr_no].label; 2817 mbr_info_t *m; 2818 #endif 2819 2820 while (*str == ' ') 2821 str++; 2822 2823 #if BOOTSEL 2824 if (attrtype == MSG_bootmenu) { 2825 for (m = data->mbr; m != mb; m = m->extended) 2826 ; 2827 strncpy(m->mbrb.mbrbs_nametab[i], str, 2828 sizeof(m->mbrb.mbrbs_nametab[i])); 2829 } 2830 #endif 2831 2832 return false; 2833 } 2834 2835 static bool 2836 part_attr_toggle(const struct disk_partitions *arg, part_id id, 2837 const mbr_info_t *mb, int i, bool primary, 2838 const struct mbr_partition *mp, void *cookie) 2839 { 2840 const struct mbr_disk_partitions *parts = 2841 (const struct mbr_disk_partitions*)arg; 2842 struct part_attr_set_data *data = cookie; 2843 const char *attrtype = parts->dp.pscheme 2844 ->custom_attributes[data->attr_no].label; 2845 int j; 2846 2847 if (attrtype == MSG_ptn_active) { 2848 if (!primary) 2849 return false; 2850 2851 data->mbr->mbr.mbr_parts[i].mbrp_flag ^= MBR_PFLAG_ACTIVE; 2852 for (j = 0; j < MBR_PART_COUNT; j++) { 2853 if (j == i) 2854 continue; 2855 data->mbr->mbr.mbr_parts[j].mbrp_flag 2856 &= ~MBR_PFLAG_ACTIVE; 2857 } 2858 return true; 2859 #ifdef BOOTSEL 2860 } else if (attrtype == MSG_boot_dflt) { 2861 if (data->mbr->bootsec == mb->sector+mp->mbrp_start) 2862 data->mbr->bootsec = 0; 2863 else 2864 data->mbr->bootsec = mb->sector+mp->mbrp_start; 2865 return true; 2866 #endif 2867 } 2868 2869 return false; 2870 } 2871 2872 static bool 2873 mbr_custom_attribute_format(const struct disk_partitions *arg, 2874 part_id id, size_t attr_no, const struct disk_part_info *info, 2875 char *res, size_t space) 2876 { 2877 const struct mbr_disk_partitions *parts = 2878 (const struct mbr_disk_partitions*)arg; 2879 struct part_attr_fmt_data data; 2880 2881 data.str = res; 2882 data.avail_space = space; 2883 data.attr_no = attr_no; 2884 data.parts = parts; 2885 data.info = info; 2886 2887 return mbr_part_apply(arg, id, part_attr_fornat_str, &data); 2888 } 2889 2890 static bool 2891 mbr_custom_attribute_toggle(struct disk_partitions *arg, 2892 part_id id, size_t attr_no) 2893 { 2894 struct mbr_disk_partitions *parts = 2895 (struct mbr_disk_partitions*)arg; 2896 struct part_attr_set_data data; 2897 2898 data.attr_no = attr_no; 2899 data.parts = parts; 2900 data.str = NULL; 2901 #ifdef BOOTSEL 2902 data.mbr = &parts->mbr; 2903 #endif 2904 2905 return mbr_part_apply(arg, id, part_attr_toggle, &data); 2906 } 2907 2908 static bool 2909 mbr_custom_attribute_set_str(struct disk_partitions *arg, 2910 part_id id, size_t attr_no, const char *new_val) 2911 { 2912 struct mbr_disk_partitions *parts = 2913 (struct mbr_disk_partitions*)arg; 2914 struct part_attr_set_data data; 2915 2916 data.attr_no = attr_no; 2917 data.parts = parts; 2918 data.str = new_val; 2919 #ifdef BOOTSEL 2920 data.mbr = &parts->mbr; 2921 #endif 2922 2923 return mbr_part_apply(arg, id, part_attr_set_str, &data); 2924 } 2925 2926 static daddr_t 2927 mbr_part_alignment(const struct disk_partitions *arg) 2928 { 2929 const struct mbr_disk_partitions *parts = 2930 (const struct mbr_disk_partitions*)arg; 2931 2932 return parts->ptn_alignment; 2933 } 2934 2935 static bool 2936 add_wedge(const char *disk, daddr_t start, daddr_t size, 2937 char *wname, size_t max_len) 2938 { 2939 struct dkwedge_info dkw; 2940 char diskpath[MAXPATHLEN]; 2941 int fd; 2942 2943 memset(&dkw, 0, sizeof(dkw)); 2944 dkw.dkw_offset = start; 2945 dkw.dkw_size = size; 2946 snprintf((char*)dkw.dkw_wname, sizeof dkw.dkw_wname, 2947 "%s_%" PRIi64 "@%" PRIi64, disk, size, start); 2948 2949 *wname = 0; 2950 2951 fd = opendisk(disk, O_RDWR, diskpath, sizeof(diskpath), 0); 2952 if (fd < 0) 2953 return false; 2954 if (ioctl(fd, DIOCAWEDGE, &dkw) == -1) { 2955 close(fd); 2956 return false; 2957 } 2958 close(fd); 2959 strlcpy(wname, dkw.dkw_devname, max_len); 2960 return true; 2961 } 2962 2963 static bool 2964 mbr_get_part_device(const struct disk_partitions *arg, 2965 part_id ptn, char *devname, size_t max_devname_len, int *part, 2966 enum dev_name_usage usage, bool with_path, bool life) 2967 { 2968 const struct mbr_disk_partitions *parts = 2969 (const struct mbr_disk_partitions*)arg; 2970 struct disk_part_info info, tmp; 2971 part_id dptn; 2972 char *wedge_dev; 2973 2974 if (!mbr_get_part_info(arg, ptn, &info)) 2975 return false; 2976 2977 if (!mbr_part_get_wedge(arg, ptn, &wedge_dev) || wedge_dev == NULL) 2978 return false; 2979 2980 if (wedge_dev[0] == 0) { 2981 /* 2982 * If we have secondary partitions, try to find a match there 2983 * and use that... 2984 */ 2985 if (parts->dlabel != NULL) { 2986 for (dptn = 0; dptn < parts->dlabel->num_part; dptn++) { 2987 if (!parts->dlabel->pscheme->get_part_info( 2988 parts->dlabel, dptn, &tmp)) 2989 continue; 2990 if (tmp.start != info.start || 2991 tmp.size != info.size) 2992 continue; 2993 return parts->dlabel->pscheme->get_part_device( 2994 parts->dlabel, dptn, devname, 2995 max_devname_len, 2996 part, usage, with_path, life); 2997 } 2998 } 2999 3000 /* 3001 * Configure a new wedge and remember the name 3002 */ 3003 if (!add_wedge(arg->disk, info.start, info.size, wedge_dev, 3004 MBR_DEV_LEN)) 3005 return false; 3006 } 3007 3008 assert(wedge_dev[0] != 0); 3009 3010 switch (usage) { 3011 case logical_name: 3012 case plain_name: 3013 if (with_path) 3014 snprintf(devname, max_devname_len, _PATH_DEV "%s", 3015 wedge_dev); 3016 else 3017 strlcpy(devname, wedge_dev, max_devname_len); 3018 return true; 3019 case raw_dev_name: 3020 if (with_path) 3021 snprintf(devname, max_devname_len, _PATH_DEV "r%s", 3022 wedge_dev); 3023 else 3024 snprintf(devname, max_devname_len, "r%s", 3025 wedge_dev); 3026 return true; 3027 default: 3028 return false; 3029 } 3030 } 3031 3032 static bool 3033 is_custom_attribute_writable(const struct disk_partitions *arg, part_id id, 3034 const mbr_info_t *mb, int i, bool primary, 3035 const struct mbr_partition *mp, void *cookie) 3036 { 3037 const struct mbr_disk_partitions *parts = 3038 (const struct mbr_disk_partitions*)arg; 3039 struct part_attr_set_data *data = cookie; 3040 const char *attrtype = parts->dp.pscheme 3041 ->custom_attributes[data->attr_no].label; 3042 3043 if (attrtype == MSG_ptn_active) 3044 /* Only 'normal' partitions can be 'Active' */ 3045 return primary && !MBR_IS_EXTENDED(mp->mbrp_type); 3046 #ifdef BOOTSEL 3047 else if (attrtype == MSG_boot_dflt) 3048 /* Only partitions with bootmenu names can be default */ 3049 return mb->mbrb.mbrbs_nametab[i][0] != 0; 3050 else if (attrtype == MSG_bootmenu) 3051 /* The extended partition isn't bootable */ 3052 return !MBR_IS_EXTENDED(mp->mbrp_type); 3053 #endif 3054 3055 return false; 3056 } 3057 3058 static bool 3059 mbr_custom_attribute_writable(const struct disk_partitions *arg, 3060 part_id id, size_t attr_no) 3061 { 3062 const struct mbr_disk_partitions *parts = 3063 (const struct mbr_disk_partitions*)arg; 3064 struct part_attr_set_data data; 3065 3066 data.attr_no = attr_no; 3067 data.parts = parts; 3068 data.str = NULL; 3069 #ifdef BOOTSEL 3070 data.mbr = NULL; 3071 #endif 3072 3073 return mbr_part_apply(arg, id, is_custom_attribute_writable, &data); 3074 } 3075 3076 const struct disk_part_edit_column_desc mbr_edit_columns[] = { 3077 { .title = MSG_mbr_part_header_1, 3078 #if BOOTSEL 3079 .width = 16U 3080 #else 3081 .width = 26U 3082 #endif 3083 }, 3084 { .title = MSG_mbr_part_header_2, .width = 8U }, 3085 #if BOOTSEL 3086 { .title = MSG_mbr_part_header_3, .width = 9U }, 3087 #endif 3088 }; 3089 3090 const struct disk_part_custom_attribute mbr_custom_attrs[] = { 3091 { .label = MSG_ptn_active, .type = pet_bool }, 3092 #if BOOTSEL 3093 { .label = MSG_boot_dflt, .type = pet_bool }, 3094 { .label = MSG_bootmenu, .type = pet_str, 3095 .strlen = MBR_BS_PARTNAMESIZE }, 3096 #endif 3097 }; 3098 3099 const struct disk_partitioning_scheme 3100 mbr_parts = { 3101 .name = MSG_parttype_mbr, 3102 .short_name = MSG_parttype_mbr_short, 3103 .new_type_prompt = MSG_mbr_get_ptn_id, 3104 .part_flag_desc = MSG_mbr_flag_desc, 3105 .size_limit = (daddr_t)UINT32_MAX, 3106 .secondary_scheme = &disklabel_parts, 3107 .edit_columns_count = __arraycount(mbr_edit_columns), 3108 .edit_columns = mbr_edit_columns, 3109 .custom_attribute_count = __arraycount(mbr_custom_attrs), 3110 .custom_attributes = mbr_custom_attrs, 3111 .get_part_alignment = mbr_part_alignment, 3112 .get_part_info = mbr_get_part_info, 3113 .get_part_attr_str = mbr_part_attr_str, 3114 .format_partition_table_str = mbr_table_str, 3115 .part_type_can_change = mbr_part_type_can_change, 3116 .can_add_partition = mbr_can_add_partition, 3117 .custom_attribute_writable = mbr_custom_attribute_writable, 3118 .format_custom_attribute = mbr_custom_attribute_format, 3119 .custom_attribute_toggle = mbr_custom_attribute_toggle, 3120 .custom_attribute_set_str = mbr_custom_attribute_set_str, 3121 .get_part_types_count = mbr_get_part_type_count, 3122 .adapt_foreign_part_info = generic_adapt_foreign_part_info, 3123 .get_part_type = mbr_get_part_type, 3124 .get_fs_part_type = mbr_get_fs_part_type, 3125 .get_generic_part_type = mbr_get_generic_part_type, 3126 .create_custom_part_type = mbr_custom_part_type, 3127 .create_unknown_part_type = mbr_create_unknown_part_type, 3128 .secondary_partitions = mbr_read_disklabel, 3129 .write_to_disk = mbr_write_to_disk, 3130 .read_from_disk = mbr_read_from_disk, 3131 .create_new_for_disk = mbr_create_new, 3132 .guess_disk_geom = mbr_guess_geom, 3133 .get_cylinder_size = mbr_get_cylinder, 3134 .change_disk_geom = mbr_change_disk_geom, 3135 .get_part_device = mbr_get_part_device, 3136 .max_free_space_at = mbr_max_part_size, 3137 .get_free_spaces = mbr_get_free_spaces, 3138 .set_part_info = mbr_set_part_info, 3139 .delete_all_partitions = mbr_delete_all, 3140 .delete_partition = mbr_delete_part, 3141 .add_partition = mbr_add_part, 3142 .guess_install_target = mbr_guess_root, 3143 .post_edit_verify = mbr_verify, 3144 .pre_update_verify = mbr_verify_for_update, 3145 .free = mbr_free, 3146 }; 3147 3148 #endif 3149