1 /* $NetBSD: mbr.c,v 1.10 2018/11/27 17:13:41 martin Exp $ */ 2 3 /* 4 * Copyright 1997 Piermont Information Systems Inc. 5 * All rights reserved. 6 * 7 * Written by Philip A. Nelson for Piermont Information Systems Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. The name of Piermont Information Systems Inc. may not be used to endorse 18 * or promote products derived from this software without specific prior 19 * written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS'' 22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE 25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 31 * THE POSSIBILITY OF SUCH DAMAGE. 32 * 33 */ 34 35 /* 36 * Following applies to the geometry guessing code 37 */ 38 39 /* 40 * Mach Operating System 41 * Copyright (c) 1992 Carnegie Mellon University 42 * All Rights Reserved. 43 * 44 * Permission to use, copy, modify and distribute this software and its 45 * documentation is hereby granted, provided that both the copyright 46 * notice and this permission notice appear in all copies of the 47 * software, derivative works or modified versions, and any portions 48 * thereof, and that both notices appear in supporting documentation. 49 * 50 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 51 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 52 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 53 * 54 * Carnegie Mellon requests users of this software to return to 55 * 56 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 57 * School of Computer Science 58 * Carnegie Mellon University 59 * Pittsburgh PA 15213-3890 60 * 61 * any improvements or extensions that they make and grant Carnegie Mellon 62 * the rights to redistribute these changes. 63 */ 64 65 /* mbr.c -- DOS Master Boot Record editing code */ 66 67 #include <sys/param.h> 68 #include <sys/types.h> 69 #include <stdio.h> 70 #include <unistd.h> 71 #include <fcntl.h> 72 #include <util.h> 73 #include "defs.h" 74 #include "mbr.h" 75 #include "md.h" 76 #include "msg_defs.h" 77 #include "menu_defs.h" 78 #include "defsizes.h" 79 #include "endian.h" 80 81 #define NO_BOOTMENU (-0x100) 82 83 #define MAXCYL 1023 /* Possibly 1024 */ 84 #define MAXHEAD 255 /* Possibly 256 */ 85 #define MAXSECTOR 63 86 87 struct part_id { 88 int id; 89 const char *name; 90 } part_ids[] = { 91 {0, "unused"}, 92 {MBR_PTYPE_NETBSD, "NetBSD"}, 93 {MBR_PTYPE_EXT_LBA, "Extended partition, LBA"}, 94 {MBR_PTYPE_386BSD, "FreeBSD/386BSD"}, 95 {MBR_PTYPE_OPENBSD, "OpenBSD"}, 96 {MBR_PTYPE_LNXEXT2, "Linux native"}, 97 {MBR_PTYPE_LNXSWAP, "Linux swap"}, 98 {MBR_PTYPE_FAT12, "DOS FAT12"}, 99 {MBR_PTYPE_FAT16S, "DOS FAT16, <32M"}, 100 {MBR_PTYPE_FAT16B, "DOS FAT16, >32M"}, 101 {MBR_PTYPE_FAT16L, "Windows FAT16, LBA"}, 102 {MBR_PTYPE_FAT32, "Windows FAT32"}, 103 {MBR_PTYPE_FAT32L, "Windows FAT32, LBA"}, 104 {MBR_PTYPE_NTFSVOL, "NTFS volume set"}, 105 {MBR_PTYPE_NTFS, "NTFS"}, 106 {MBR_PTYPE_PREP, "PReP Boot"}, 107 #ifdef MBR_PTYPE_SOLARIS 108 {MBR_PTYPE_SOLARIS, "Solaris"}, 109 #endif 110 {-1, "Unknown"}, 111 }; 112 113 static int get_mapping(struct mbr_partition *, int, int *, int *, int *, 114 daddr_t *); 115 static void convert_mbr_chs(int, int, int, uint8_t *, uint8_t *, 116 uint8_t *, uint32_t); 117 static void get_ptn_alignment(struct mbr_partition *); 118 119 static unsigned int ptn_alignment; 120 static unsigned int ptn_0_offset; 121 122 /* 123 * Notes on the extended partition editor. 124 * 125 * The extended partition structure is actually a singly linked list. 126 * Each of the 'mbr' sectors can only contain 2 items, the first describes 127 * a user partition (relative to that mbr sector), the second describes 128 * the following partition (relative to the start of the extended partition). 129 * 130 * The 'start' sector for the user partition is always the size of one 131 * track - very often 63. The extended partitions themselves should 132 * always start on a cylinder boundary using the BIOS geometry - often 133 * 16065 sectors per cylinder. 134 * 135 * The disk is also always described in increasing sector order. 136 * 137 * During editing we keep the mbr sectors accurate (it might have been 138 * easier to use absolute sector numbers though), and keep a copy of the 139 * entire sector - to preserve any information any other OS has tried 140 * to squirrel away in the (apparently) unused space. 141 * 142 * For simplicity we add entries for unused space. These should not 143 * get written to the disk. 144 * 145 * Typical disk (with some small numbers): 146 * 147 * 0 -> a 63 37 dos 148 * b 100 1000 extended LBA (type 15) 149 * 150 * 100 -> a 63 37 user 151 * b 100 200 extended partiton (type 5) 152 * 153 * 200 -> a 63 37 user 154 * b 200 300 extended partiton (type 5) 155 * 156 * 300 -> a 63 37 user 157 * b 0 0 0 (end of chain) 158 * 159 * If there is a gap, the 'b' partition will start beyond the area 160 * described by the 'a' partition. 161 * 162 * While writing this comment, I can't remember what happens is there 163 * is space at the start of the extended partition. 164 */ 165 166 #ifndef debug_extended 167 #define dump_mbr(mbr, msg) 168 #else 169 void 170 dump_mbr(mbr_info_t *mbr, const char *msg) 171 { 172 int i; 173 174 fprintf(stderr, "%s: bsec %d\n", msg, bsec); 175 do { 176 fprintf(stderr, "%9p: %9d %9p %6.6s:", 177 mbr, mbr->sector, mbr->extended, 178 mbr->prev_ext, mbr->last_mounted); 179 for (i = 0; i < 4; i++) 180 fprintf(stderr, " %*d %9d %9d %9d,\n", 181 i ? 41 : 3, 182 mbr->mbr.mbr_parts[i].mbrp_type, 183 mbr->mbr.mbr_parts[i].mbrp_start, 184 mbr->mbr.mbr_parts[i].mbrp_size, 185 mbr->mbr.mbr_parts[i].mbrp_start + 186 mbr->mbr.mbr_parts[i].mbrp_size); 187 } while ((mbr = mbr->extended)); 188 } 189 #endif 190 191 /* 192 * To be used only on ports which cannot provide any bios geometry 193 */ 194 int 195 set_bios_geom_with_mbr_guess(void) 196 { 197 int cyl, head; 198 daddr_t sec; 199 200 read_mbr(pm->diskdev, &mbr); 201 msg_display(MSG_nobiosgeom, pm->dlcyl, pm->dlhead, pm->dlsec); 202 if (guess_biosgeom_from_mbr(&mbr, &cyl, &head, &sec) >= 0) 203 msg_display_add(MSG_biosguess, cyl, head, sec); 204 set_bios_geom(cyl, head, sec); 205 return edit_mbr(&mbr); 206 } 207 208 /* 209 * get C/H/S geometry from user via menu interface and 210 * store in globals. 211 */ 212 void 213 set_bios_geom(int cyl, int head, int sec) 214 { 215 char res[80]; 216 217 msg_display_add(MSG_setbiosgeom); 218 219 do { 220 snprintf(res, 80, "%d", sec); 221 msg_prompt_add(MSG_sectors, res, res, 80); 222 bsec = atoi(res); 223 } while (bsec <= 0 || bsec > 63); 224 225 do { 226 snprintf(res, 80, "%d", head); 227 msg_prompt_add(MSG_heads, res, res, 80); 228 bhead = atoi(res); 229 } while (bhead <= 0 || bhead > 256); 230 231 bcyl = pm->dlsize / bsec / bhead; 232 if (pm->dlsize != bcyl * bsec * bhead) 233 bcyl++; 234 } 235 236 #ifdef notdef 237 void 238 disp_cur_geom(void) 239 { 240 241 msg_display_add(MSG_realgeom, pm->dlcyl, pm->dlhead, pm->dlsec); 242 msg_display_add(MSG_biosgeom, bcyl, bhead, bsec); 243 } 244 #endif 245 246 247 /* 248 * Then, the partition stuff... 249 */ 250 251 /* 252 * If we change the mbr partitioning, the we must remove any references 253 * in the netbsd disklabel to the part we changed. 254 */ 255 static void 256 remove_old_partitions(uint start, int64_t size) 257 { 258 partinfo *p; 259 uint end; 260 261 if (size > 0) { 262 end = start + size; 263 } else { 264 end = start; 265 start = end - size; 266 } 267 268 if (end == 0) 269 return; 270 271 for (p = pm->oldlabel; p < pm->oldlabel + nelem(pm->oldlabel); p++) { 272 if (p->pi_offset >= end || p->pi_offset + p->pi_size <= start) 273 continue; 274 memset(p, 0, sizeof *p); 275 } 276 } 277 278 static int 279 find_mbr_space(struct mbr_sector *mbrs, uint *start, uint *size, uint from, int ignore) 280 { 281 uint sz; 282 int i; 283 uint s, e; 284 285 check_again: 286 sz = pm->dlsize - from; 287 for (i = 0; i < MBR_PART_COUNT; i++) { 288 if (i == ignore) 289 continue; 290 s = mbrs->mbr_parts[i].mbrp_start; 291 e = s + mbrs->mbr_parts[i].mbrp_size; 292 if (s <= from && e > from) { 293 from = e; 294 goto check_again; 295 } 296 if (s > from && s - from < sz) 297 sz = s - from; 298 } 299 if (sz == 0) 300 return -1; 301 if (start != NULL) 302 *start = from; 303 if (size != NULL) 304 *size = sz; 305 return 0; 306 } 307 308 static struct mbr_partition * 309 get_mbrp(mbr_info_t **mbrip, int opt) 310 { 311 mbr_info_t *mbri = *mbrip; 312 313 if (opt >= MBR_PART_COUNT) 314 for (opt -= MBR_PART_COUNT - 1; opt; opt--) 315 mbri = mbri->extended; 316 317 *mbrip = mbri; 318 return &mbri->mbr.mbr_parts[opt]; 319 } 320 321 static int 322 err_msg_win(const char *errmsg) 323 { 324 const char *cont; 325 int l, l1; 326 327 errmsg = msg_string(errmsg); 328 cont = msg_string(MSG_Hit_enter_to_continue); 329 330 l = strlen(errmsg); 331 l1 = strlen(cont); 332 if (l < l1) 333 l = l1; 334 335 msg_prompt_win("%s.\n%s", -1, 18, l + 5, 4, 336 NULL, NULL, 1, errmsg, cont); 337 return 0; 338 } 339 340 static int 341 set_mbr_type(menudesc *m, void *arg) 342 { 343 mbr_info_t *mbri = arg; 344 mbr_info_t *ombri = arg; 345 mbr_info_t *ext; 346 struct mbr_partition *mbrp; 347 char *cp; 348 int opt = mbri->opt; 349 int type; 350 u_int start, sz; 351 int i; 352 char numbuf[5]; 353 354 dump_mbr(ombri, "set type"); 355 356 mbrp = get_mbrp(&mbri, opt); 357 if (opt >= MBR_PART_COUNT) 358 opt = 0; 359 360 type = m->cursel; 361 if (type == 0) 362 return 1; 363 type = part_ids[type - 1].id; 364 while (type == -1) { 365 snprintf(numbuf, sizeof numbuf, "%u", mbrp->mbrp_type); 366 msg_prompt_win(MSG_get_ptn_id, -1, 18, 0, 0, 367 numbuf, numbuf, sizeof numbuf); 368 type = strtoul(numbuf, &cp, 0); 369 if (*cp != 0) 370 type = -1; 371 } 372 373 if (type == mbrp->mbrp_type) 374 /* type not changed... */ 375 return 1; 376 377 mbri->last_mounted[opt < MBR_PART_COUNT ? opt : 0] = NULL; 378 379 if (MBR_IS_EXTENDED(mbrp->mbrp_type)) { 380 /* deleting extended partition.... */ 381 if (mbri->sector || mbri->extended->extended) 382 /* We should have stopped this happening... */ 383 return err_msg_win("can't delete extended"); 384 free(mbri->extended); 385 mbri->extended = NULL; 386 } 387 388 if (type == 0) { 389 /* Deleting partition */ 390 mbrp->mbrp_type = 0; 391 /* Remove references to this space from the NetBSD label */ 392 remove_old_partitions(mbri->sector + mbrp->mbrp_start, 393 mbrp->mbrp_size); 394 #ifdef BOOTSEL 395 if (ombri->bootsec == mbri->sector + mbrp->mbrp_start) 396 ombri->bootsec = 0; 397 398 memset(mbri->mbrb.mbrbs_nametab[opt], 0, 399 sizeof mbri->mbrb.mbrbs_nametab[opt]); 400 #endif 401 if (mbri->sector == 0) { 402 /* A main partition */ 403 memset(mbrp, 0, sizeof *mbrp); 404 return 1; 405 } 406 407 /* Merge with previous and next free areas */ 408 ext = mbri->prev_ext; 409 if (ext != NULL && ext->mbr.mbr_parts[0].mbrp_type == 0) { 410 /* previous was free - back up one entry */ 411 mbri = ext; 412 ombri->opt--; 413 } 414 while ((ext = mbri->extended)) { 415 if (ext->mbr.mbr_parts[0].mbrp_type != 0) 416 break; 417 sz = ext->mbr.mbr_parts[0].mbrp_start + 418 ext->mbr.mbr_parts[0].mbrp_size; 419 /* Increase size of our (empty) partition */ 420 mbri->mbr.mbr_parts[0].mbrp_size += sz; 421 /* Make us describe the next partition */ 422 mbri->mbr.mbr_parts[1] = ext->mbr.mbr_parts[1]; 423 /* fix list of extended partitions */ 424 mbri->extended = ext->extended; 425 if (ext->extended != NULL) 426 ext->extended->prev_ext = mbri; 427 free(ext); 428 /* Make previous size cover all our ptn */ 429 ext = mbri->prev_ext; 430 if (ext != NULL) 431 ext->mbr.mbr_parts[1].mbrp_size += sz; 432 } 433 return 1; 434 } 435 436 if (mbrp->mbrp_start == 0) { 437 /* Find first chunk of space... */ 438 /* Must be in the main partition */ 439 if (mbri->sector != 0) 440 /* shouldn't be possible to have null start... */ 441 return err_msg_win("main-extended mixup"); 442 if (find_mbr_space(&mbri->mbr, &start, &sz, bsec, -1) != 0) 443 /* no space */ 444 return err_msg_win(MSG_No_free_space); 445 mbrp->mbrp_start = start; 446 mbrp->mbrp_size = sz; 447 /* If there isn't an active partition mark this one active */ 448 if (!MBR_IS_EXTENDED(type)) { 449 for (i = 0; i < MBR_PART_COUNT; i++) 450 if (mbri->mbr.mbr_parts[i].mbrp_flag != 0) 451 break; 452 if (i == MBR_PART_COUNT) 453 mbrp->mbrp_flag = MBR_PFLAG_ACTIVE; 454 } 455 } 456 457 if (MBR_IS_EXTENDED(type)) { 458 if (mbri->sector != 0) 459 /* Can't set extended partition in an extended one */ 460 return err_msg_win(MSG_Only_one_extended_ptn); 461 if (mbri->extended) 462 /* Can't have two extended partitions */ 463 return err_msg_win(MSG_Only_one_extended_ptn); 464 /* Create new extended partition */ 465 ext = calloc(1, sizeof *mbri->extended); 466 if (!ext) 467 return 0; 468 mbri->extended = ext; 469 ext->sector = mbrp->mbrp_start; 470 ext->mbr.mbr_parts[0].mbrp_start = ptn_0_offset; 471 ext->mbr.mbr_parts[0].mbrp_size = 472 mbrp->mbrp_size - ptn_0_offset; 473 } 474 mbrp->mbrp_type = type; 475 476 return 1; 477 } 478 479 static void 480 set_type_label(menudesc *m, int opt, void *arg) 481 { 482 483 if (opt == 0) { 484 wprintw(m->mw, "%s", msg_string(MSG_Dont_change)); 485 return; 486 } 487 if (opt == 1) { 488 wprintw(m->mw, "%s", msg_string(MSG_Delete_partition)); 489 return; 490 } 491 if (part_ids[opt - 1].id == -1) { 492 wprintw(m->mw, "%s", msg_string(MSG_Other_kind)); 493 return; 494 } 495 wprintw(m->mw, "%s", part_ids[opt - 1].name); 496 } 497 498 static int 499 edit_mbr_type(menudesc *m, void *arg) 500 { 501 static menu_ent type_opts[1 + nelem(part_ids)]; 502 static int type_menu = -1; 503 unsigned int i; 504 505 if (type_menu == -1) { 506 for (i = 0; i < nelem(type_opts); i++) { 507 type_opts[i].opt_menu = OPT_NOMENU; 508 type_opts[i].opt_action = set_mbr_type; 509 } 510 type_menu = new_menu(NULL, type_opts, nelem(type_opts), 511 13, 12, 0, 30, 512 MC_SUBMENU | MC_SCROLL | MC_NOEXITOPT | MC_NOCLEAR, 513 NULL, set_type_label, NULL, 514 NULL, NULL); 515 } 516 517 if (type_menu != -1) 518 process_menu(type_menu, arg); 519 520 return 0; 521 } 522 523 static int 524 edit_mbr_start(menudesc *m, void *arg) 525 { 526 mbr_info_t *mbri = arg; 527 mbr_info_t *ext; 528 struct mbr_partition *mbrp; 529 int opt = mbri->opt; 530 uint start, sz; 531 uint new_r, new, limit, dflt_r; 532 int64_t delta; 533 const char *errmsg; 534 char *cp; 535 struct { 536 uint start; 537 uint start_r; 538 uint limit; 539 } freespace[MBR_PART_COUNT]; 540 unsigned int spaces; 541 unsigned int i; 542 char prompt[MBR_PART_COUNT * 60]; 543 unsigned int len; 544 char numbuf[12]; 545 546 if (opt >= MBR_PART_COUNT) 547 /* should not be able to get here... */ 548 return 1; 549 550 mbrp = mbri->mbr.mbr_parts + opt; 551 /* locate the start of all free areas */ 552 spaces = 0; 553 for (start = bsec, i = 0; i < MBR_PART_COUNT; start += sz, i++) { 554 if (find_mbr_space(&mbri->mbr, &start, &sz, start, opt)) 555 break; 556 if (MBR_IS_EXTENDED(mbrp->mbrp_type)) { 557 /* Only want the area that contains this partition */ 558 if (mbrp->mbrp_start < start || 559 mbrp->mbrp_start >= start + sz) 560 continue; 561 i = MBR_PART_COUNT - 1; 562 } 563 freespace[spaces].start = start; 564 freespace[spaces].start_r = start / sizemult; 565 freespace[spaces].limit = start + sz; 566 if (++spaces >= sizeof freespace) 567 /* shouldn't happen... */ 568 break; 569 } 570 571 /* Add description of start/size to user prompt */ 572 len = 0; 573 for (i = 0; i < spaces; i++) { 574 len += snprintf(prompt + len, sizeof prompt - len, 575 msg_string(MSG_ptn_starts), 576 freespace[i].start_r, 577 freespace[i].limit / sizemult, multname, 578 freespace[i].limit / sizemult - freespace[i].start_r, 579 multname); 580 if (len >= sizeof prompt) 581 break; 582 } 583 584 /* And loop until the user gives a sensible answer */ 585 dflt_r = mbrp->mbrp_start / sizemult; 586 errmsg = ""; 587 for (;;) { 588 snprintf(numbuf, sizeof numbuf, "%d", dflt_r); 589 msg_prompt_win(MSG_get_ptn_start, -1, 18, 60, spaces + 3, 590 numbuf, numbuf, sizeof numbuf, 591 prompt, msg_string(errmsg), multname); 592 new_r = strtoul(numbuf, &cp, 0); 593 if (*cp != 0) { 594 errmsg = MSG_Invalid_numeric; 595 continue; 596 } 597 if (new_r == dflt_r) 598 /* Unchanged */ 599 return 0; 600 /* 601 * Check that the start address from the user is inside one 602 * of the free areas. 603 */ 604 new = new_r * sizemult; 605 for (i = 0; i < spaces; i++) { 606 if (new_r == freespace[i].start_r) { 607 new = freespace[i].start; 608 break; 609 } 610 if (new >= freespace[i].start && 611 new < freespace[i].limit) 612 break; 613 } 614 if (i >= spaces) { 615 errmsg = MSG_Space_allocated; 616 continue; 617 } 618 limit = freespace[i].limit; 619 /* 620 * We can only increase the start of an extended partition 621 * if the corresponding space inside the partition isn't used. 622 */ 623 if (new > mbrp->mbrp_start && 624 MBR_IS_EXTENDED(mbrp->mbrp_type) && 625 (mbri->extended->mbr.mbr_parts[0].mbrp_type != 0 || 626 mbri->extended->mbr.mbr_parts[0].mbrp_size < 627 new - mbrp->mbrp_start)) { 628 errmsg = MSG_Space_allocated; 629 continue; 630 } 631 break; 632 } 633 634 if (new < mbrp->mbrp_start + mbrp->mbrp_size && 635 limit > mbrp->mbrp_start) 636 /* Keep end of partition in the same place */ 637 limit = mbrp->mbrp_start + mbrp->mbrp_size; 638 639 delta = new - mbrp->mbrp_start; 640 if (MBR_IS_EXTENDED(mbrp->mbrp_type)) { 641 ext = mbri->extended; 642 if (ext->mbr.mbr_parts[0].mbrp_type != 0) { 643 /* allocate an extended ptn for the free item */ 644 ext = calloc(1, sizeof *ext); 645 if (!ext) 646 return 0; 647 ext->sector = mbrp->mbrp_start; 648 ext->extended = mbri->extended; 649 mbri->extended->prev_ext = ext; 650 mbri->extended = ext; 651 ext->mbr.mbr_parts[0].mbrp_start = bsec; 652 ext->mbr.mbr_parts[0].mbrp_size = -bsec; 653 ext->mbr.mbr_parts[1].mbrp_type = MBR_PTYPE_EXT; 654 ext->mbr.mbr_parts[1].mbrp_start = 0; 655 ext->mbr.mbr_parts[1].mbrp_size = 656 ext->extended->mbr.mbr_parts[0].mbrp_start + 657 ext->extended->mbr.mbr_parts[0].mbrp_size; 658 } 659 /* adjust size of first free item */ 660 ext->mbr.mbr_parts[0].mbrp_size -= delta; 661 ext->sector += delta; 662 /* and the link of all extended partitions */ 663 do 664 if (ext->extended) 665 ext->mbr.mbr_parts[1].mbrp_start -= delta; 666 while ((ext = ext->extended)); 667 } 668 remove_old_partitions(mbri->sector + mbrp->mbrp_start, delta); 669 670 /* finally set partition base and size */ 671 mbrp->mbrp_start = new; 672 mbrp->mbrp_size = limit - new; 673 mbri->last_mounted[opt] = NULL; 674 675 return 0; 676 } 677 678 static int 679 edit_mbr_size(menudesc *m, void *arg) 680 { 681 mbr_info_t *mbri = arg; 682 mbr_info_t *ombri = arg; 683 mbr_info_t *ext; 684 struct mbr_partition *mbrp; 685 int opt = mbri->opt; 686 uint start, max, max_r, dflt, dflt_r, new; 687 uint freespace; 688 int delta; 689 char numbuf[12]; 690 char *cp; 691 const char *errmsg; 692 693 mbrp = get_mbrp(&mbri, opt); 694 dflt = mbrp->mbrp_size; 695 if (opt < MBR_PART_COUNT) { 696 max = 0; 697 find_mbr_space(&mbri->mbr, &start, &max, mbrp->mbrp_start, opt); 698 if (start != mbrp->mbrp_start) 699 return 0; 700 if (dflt == 0) 701 dflt = max; 702 } else { 703 ext = mbri->extended; 704 max = dflt; 705 /* 706 * If the next extended partition describes a free area, 707 * then merge it onto this area. 708 */ 709 if (ext != NULL && ext->mbr.mbr_parts[0].mbrp_type == 0) { 710 if (ext->extended) 711 ext->extended->prev_ext = mbri; 712 mbri->extended = ext->extended; 713 if (mbri->prev_ext) 714 mbri->prev_ext->mbr.mbr_parts[1].mbrp_size 715 += mbri->mbr.mbr_parts[1].mbrp_size; 716 mbrp->mbrp_size += mbri->mbr.mbr_parts[1].mbrp_size; 717 max += mbri->mbr.mbr_parts[1].mbrp_size; 718 mbri->mbr.mbr_parts[1] = ext->mbr.mbr_parts[1]; 719 free(ext); 720 } 721 } 722 723 start = mbri->sector + mbrp->mbrp_start; 724 /* We need to keep both the unrounded and rounded (_r) max and dflt */ 725 dflt_r = (start + dflt) / sizemult - start / sizemult; 726 if (max == dflt) 727 max_r = dflt_r; 728 else 729 max_r = max / sizemult; 730 for (errmsg = "";;) { 731 snprintf(numbuf, sizeof numbuf, "%d", dflt_r); 732 msg_prompt_win(MSG_get_ptn_size, -1, 18, 0, 0, 733 numbuf, numbuf, sizeof numbuf, 734 msg_string(errmsg), max_r, multname); 735 new = strtoul(numbuf, &cp, 0); 736 if (*cp != 0) { 737 errmsg = MSG_Invalid_numeric; 738 continue; 739 } 740 if (new > max_r) { 741 errmsg = MSG_Too_large; 742 continue; 743 } 744 if (new == 0) 745 /* Treat zero as a request for the maximum */ 746 new = max_r; 747 if (new == dflt_r) 748 /* If unchanged, don't re-round size */ 749 new = dflt; 750 else { 751 /* Round end to the partition alignment */ 752 if (sizemult != 1) { 753 new *= sizemult; 754 new += rounddown(start, ptn_alignment); 755 new = roundup(new, ptn_alignment); 756 new -= start; 757 while (new <= 0) 758 new += ptn_alignment; 759 } 760 } 761 if (new > max) 762 /* We rounded the value to above the max */ 763 new = max; 764 765 if (new == dflt || opt >= MBR_PART_COUNT 766 || !MBR_IS_EXTENDED(mbrp->mbrp_type)) 767 break; 768 /* 769 * We've been asked to change the size of the main extended 770 * partition. If this reduces the size, then that space 771 * must be unallocated. If it increases the size then 772 * we must add a description ofthe new free space. 773 */ 774 /* Find last extended partition */ 775 for (ext = mbri->extended; ext->extended; ext = ext->extended) 776 continue; 777 if ((new < dflt && (ext->mbr.mbr_parts[0].mbrp_type != 0 778 || (mbrp->mbrp_start + new < ext->sector + bsec 779 && mbrp->mbrp_start + new != ext->sector))) 780 || (new > dflt && ext->mbr.mbr_parts[0].mbrp_type != 0 781 && new < dflt + bsec)) { 782 errmsg = MSG_Space_allocated; 783 continue; 784 } 785 delta = new - dflt; 786 if (ext->mbr.mbr_parts[0].mbrp_type == 0) { 787 /* adjust size of last item (free space) */ 788 if (mbrp->mbrp_start + new == ext->sector) { 789 /* kill last extended ptn */ 790 ext = ext->prev_ext; 791 free(ext->extended); 792 ext->extended = NULL; 793 memset(&ext->mbr.mbr_parts[1], 0, 794 sizeof ext->mbr.mbr_parts[1]); 795 break; 796 } 797 ext->mbr.mbr_parts[0].mbrp_size += delta; 798 ext = ext->prev_ext; 799 if (ext != NULL) 800 ext->mbr.mbr_parts[1].mbrp_size += delta; 801 break; 802 } 803 /* Joy of joys, we must allocate another extended ptn */ 804 mbri = ext; 805 ext = calloc(1, sizeof *ext); 806 if (!ext) 807 return 0; 808 mbri->extended = ext; 809 ext->prev_ext = mbri; 810 ext->mbr.mbr_parts[0].mbrp_start = bsec; 811 ext->mbr.mbr_parts[0].mbrp_size = delta - bsec; 812 ext->sector = mbri->sector + mbri->mbr.mbr_parts[0].mbrp_start 813 + mbri->mbr.mbr_parts[0].mbrp_size; 814 mbri->mbr.mbr_parts[1].mbrp_start = ext->sector - ombri->extended->sector; 815 mbri->mbr.mbr_parts[1].mbrp_type = MBR_PTYPE_EXT; 816 mbri->mbr.mbr_parts[1].mbrp_size = delta; 817 break; 818 } 819 820 if (opt >= MBR_PART_COUNT && max - new <= (uint32_t)bsec) 821 /* Round up if not enough space for a header for free area */ 822 new = max; 823 824 if (new != mbrp->mbrp_size) { 825 /* Kill information about old partition from label */ 826 mbri->last_mounted[opt < MBR_PART_COUNT ? opt : 0] = NULL; 827 remove_old_partitions(mbri->sector + mbrp->mbrp_start + 828 mbrp->mbrp_size, (int64_t)new - mbrp->mbrp_size); 829 } 830 831 mbrp->mbrp_size = new; 832 if (opt < MBR_PART_COUNT || new == max) 833 return 0; 834 835 /* Add extended partition for the free space */ 836 ext = calloc(1, sizeof *ext); 837 if (!ext) { 838 mbrp->mbrp_size = max; 839 return 0; 840 } 841 /* Link into our extended chain */ 842 ext->extended = mbri->extended; 843 mbri->extended = ext; 844 ext->prev_ext = mbri; 845 if (ext->extended != NULL) 846 ext->extended->prev_ext = ext; 847 ext->mbr.mbr_parts[1] = mbri->mbr.mbr_parts[1]; 848 freespace = max - new; 849 if (mbri->prev_ext != NULL) 850 mbri->prev_ext->mbr.mbr_parts[1].mbrp_size -= freespace; 851 852 ext->mbr.mbr_parts[0].mbrp_start = bsec; 853 ext->mbr.mbr_parts[0].mbrp_size = freespace - bsec; 854 855 ext->sector = mbri->sector + mbri->mbr.mbr_parts[0].mbrp_start 856 + mbri->mbr.mbr_parts[0].mbrp_size; 857 mbri->mbr.mbr_parts[1].mbrp_start = ext->sector - ombri->extended->sector; 858 mbri->mbr.mbr_parts[1].mbrp_type = MBR_PTYPE_EXT; 859 mbri->mbr.mbr_parts[1].mbrp_size = freespace; 860 861 return 0; 862 } 863 864 static int 865 edit_mbr_active(menudesc *m, void *arg) 866 { 867 mbr_info_t *mbri = arg; 868 int i; 869 uint8_t *fl; 870 871 if (mbri->opt >= MBR_PART_COUNT) 872 /* sanity */ 873 return 0; 874 875 /* Invert active flag */ 876 fl = &mbri->mbr.mbr_parts[mbri->opt].mbrp_flag; 877 if (*fl == MBR_PFLAG_ACTIVE) { 878 *fl = 0; 879 return 0; 880 } 881 882 /* Ensure there is at most one active partition */ 883 for (i = 0; i < MBR_PART_COUNT; i++) 884 mbri->mbr.mbr_parts[i].mbrp_flag = 0; 885 *fl = MBR_PFLAG_ACTIVE; 886 887 return 0; 888 } 889 890 static int 891 edit_mbr_install(menudesc *m, void *arg) 892 { 893 mbr_info_t *mbri = arg; 894 mbr_info_t *ombri = arg; 895 struct mbr_partition *mbrp; 896 int opt = mbri->opt; 897 uint start; 898 899 mbrp = get_mbrp(&mbri, opt); 900 if (opt >= MBR_PART_COUNT) 901 opt = 0; 902 903 start = mbri->sector + mbrp->mbrp_start; 904 /* We just remember the start address of the partition... */ 905 if (start == ombri->install) 906 ombri->install = 0; 907 else 908 ombri->install = start; 909 return 0; 910 } 911 912 #ifdef BOOTSEL 913 static int 914 edit_mbr_bootmenu(menudesc *m, void *arg) 915 { 916 mbr_info_t *mbri = arg; 917 mbr_info_t *ombri = arg; 918 struct mbr_partition *mbrp; 919 int opt = mbri->opt; 920 921 mbrp = get_mbrp(&mbri, opt); 922 if (opt >= MBR_PART_COUNT) 923 opt = 0; 924 925 msg_prompt_win(/* XXX translate? */ "bootmenu", -1, 18, 0, 0, 926 mbri->mbrb.mbrbs_nametab[opt], 927 mbri->mbrb.mbrbs_nametab[opt], 928 sizeof mbri->mbrb.mbrbs_nametab[opt]); 929 if (mbri->mbrb.mbrbs_nametab[opt][0] == ' ') 930 mbri->mbrb.mbrbs_nametab[opt][0] = 0; 931 if (mbri->mbrb.mbrbs_nametab[opt][0] == 0 932 && ombri->bootsec == mbri->sector + mbrp->mbrp_start) 933 ombri->bootsec = 0; 934 return 0; 935 } 936 937 static int 938 edit_mbr_bootdefault(menudesc *m, void *arg) 939 { 940 mbr_info_t *mbri = arg; 941 mbr_info_t *ombri = arg; 942 struct mbr_partition *mbrp; 943 944 mbrp = get_mbrp(&mbri, mbri->opt); 945 946 ombri->bootsec = mbri->sector + mbrp->mbrp_start; 947 return 0; 948 } 949 #endif 950 951 static void set_ptn_label(menudesc *m, int line, void *arg); 952 static void set_ptn_header(menudesc *m, void *arg); 953 954 static int 955 edit_mbr_entry(menudesc *m, void *arg) 956 { 957 mbr_info_t *mbri = arg; 958 static int ptn_menu = -1; 959 960 static menu_ent ptn_opts[] = { 961 #define PTN_OPT_TYPE 0 962 { .opt_menu=OPT_NOMENU, .opt_action=edit_mbr_type }, 963 #define PTN_OPT_START 1 964 { .opt_menu=OPT_NOMENU, .opt_action=edit_mbr_start }, 965 #define PTN_OPT_SIZE 2 966 { .opt_menu=OPT_NOMENU, .opt_action=edit_mbr_size }, 967 #define PTN_OPT_END 3 968 { .opt_menu=OPT_NOMENU, .opt_flags=OPT_IGNORE }, /* display end */ 969 #define PTN_OPT_ACTIVE 4 970 { .opt_menu=OPT_NOMENU, .opt_action=edit_mbr_active }, 971 #define PTN_OPT_INSTALL 5 972 { .opt_menu=OPT_NOMENU, .opt_action=edit_mbr_install }, 973 #ifdef BOOTSEL 974 #define PTN_OPT_BOOTMENU 6 975 { .opt_menu=OPT_NOMENU, .opt_action=edit_mbr_bootmenu }, 976 #define PTN_OPT_BOOTDEFAULT 7 977 { .opt_menu=OPT_NOMENU, .opt_action=edit_mbr_bootdefault }, 978 #endif 979 { .opt_name=MSG_askunits, .opt_menu=MENU_sizechoice, 980 .opt_flags=OPT_SUB }, 981 }; 982 983 if (ptn_menu == -1) 984 ptn_menu = new_menu(NULL, ptn_opts, nelem(ptn_opts), 985 15, 6, 0, 54, 986 MC_SUBMENU | MC_SCROLL | MC_NOCLEAR, 987 set_ptn_header, set_ptn_label, NULL, 988 NULL, MSG_Partition_OK); 989 if (ptn_menu == -1) 990 return 1; 991 992 mbri->opt = m->cursel; 993 process_menu(ptn_menu, mbri); 994 return 0; 995 } 996 997 static void 998 set_ptn_label(menudesc *m, int line, void *arg) 999 { 1000 mbr_info_t *mbri = arg; 1001 mbr_info_t *ombri = arg; 1002 struct mbr_partition *mbrp; 1003 int opt; 1004 static const char *yes, *no; 1005 1006 if (yes == NULL) { 1007 yes = msg_string(MSG_Yes); 1008 no = msg_string(MSG_No); 1009 } 1010 1011 opt = mbri->opt; 1012 mbrp = get_mbrp(&mbri, opt); 1013 if (opt >= MBR_PART_COUNT) 1014 opt = 0; 1015 1016 switch (line) { 1017 case PTN_OPT_TYPE: 1018 wprintw(m->mw, msg_string(MSG_ptn_type), 1019 get_partname(mbrp->mbrp_type)); 1020 break; 1021 case PTN_OPT_START: 1022 wprintw(m->mw, msg_string(MSG_ptn_start), 1023 (mbri->sector + mbrp->mbrp_start) / sizemult, multname); 1024 break; 1025 case PTN_OPT_SIZE: 1026 wprintw(m->mw, msg_string(MSG_ptn_size), 1027 (mbri->sector + mbrp->mbrp_start + mbrp->mbrp_size) / 1028 sizemult - 1029 (mbri->sector + mbrp->mbrp_start) / sizemult, multname); 1030 break; 1031 case PTN_OPT_END: 1032 wprintw(m->mw, msg_string(MSG_ptn_end), 1033 (mbri->sector + mbrp->mbrp_start + mbrp->mbrp_size) / 1034 sizemult, multname); 1035 break; 1036 case PTN_OPT_ACTIVE: 1037 wprintw(m->mw, msg_string(MSG_ptn_active), 1038 mbrp->mbrp_flag == MBR_PFLAG_ACTIVE ? yes : no); 1039 break; 1040 case PTN_OPT_INSTALL: 1041 wprintw(m->mw, msg_string(MSG_ptn_install), 1042 mbri->sector + mbrp->mbrp_start == ombri->install && 1043 mbrp->mbrp_type == MBR_PTYPE_NETBSD ? yes : no); 1044 break; 1045 #ifdef BOOTSEL 1046 case PTN_OPT_BOOTMENU: 1047 wprintw(m->mw, msg_string(MSG_bootmenu), 1048 mbri->mbrb.mbrbs_nametab[opt]); 1049 break; 1050 case PTN_OPT_BOOTDEFAULT: 1051 wprintw(m->mw, msg_string(MSG_boot_dflt), 1052 ombri->bootsec == mbri->sector + mbrp->mbrp_start ? yes 1053 : no); 1054 break; 1055 #endif 1056 } 1057 1058 } 1059 1060 static void 1061 set_ptn_header(menudesc *m, void *arg) 1062 { 1063 mbr_info_t *mbri = arg; 1064 struct mbr_partition *mbrp; 1065 int opt = mbri->opt; 1066 int typ; 1067 1068 mbrp = get_mbrp(&mbri, opt); 1069 if (opt >= MBR_PART_COUNT) 1070 opt = 0; 1071 typ = mbrp->mbrp_type; 1072 1073 #define DISABLE(opt,cond) \ 1074 if (cond) \ 1075 m->opts[opt].opt_flags |= OPT_IGNORE; \ 1076 else \ 1077 m->opts[opt].opt_flags &= ~OPT_IGNORE; 1078 1079 /* Can't change type of the extended partition unless it is empty */ 1080 DISABLE(PTN_OPT_TYPE, MBR_IS_EXTENDED(typ) && 1081 (mbri->extended->mbr.mbr_parts[0].mbrp_type != 0 || 1082 mbri->extended->extended != NULL)); 1083 1084 /* It is unnecessary to be able to change the base of an extended ptn */ 1085 DISABLE(PTN_OPT_START, mbri->sector || typ == 0); 1086 1087 /* or the size of a free area */ 1088 DISABLE(PTN_OPT_SIZE, typ == 0); 1089 1090 /* Only 'normal' partitions can be 'Active' */ 1091 DISABLE(PTN_OPT_ACTIVE, mbri->sector != 0 || MBR_IS_EXTENDED(typ) || typ == 0); 1092 1093 /* Can only install into NetBSD partition */ 1094 DISABLE(PTN_OPT_INSTALL, typ != MBR_PTYPE_NETBSD); 1095 1096 #ifdef BOOTSEL 1097 /* The extended partition isn't bootable */ 1098 DISABLE(PTN_OPT_BOOTMENU, MBR_IS_EXTENDED(typ) || typ == 0); 1099 1100 if (typ == 0) 1101 mbri->mbrb.mbrbs_nametab[opt][0] = 0; 1102 1103 /* Only partitions with bootmenu names can be made the default */ 1104 DISABLE(PTN_OPT_BOOTDEFAULT, mbri->mbrb.mbrbs_nametab[opt][0] == 0); 1105 #endif 1106 #undef DISABLE 1107 } 1108 1109 static void 1110 set_mbr_label(menudesc *m, int opt, void *arg) 1111 { 1112 mbr_info_t *mbri = arg; 1113 mbr_info_t *ombri = arg; 1114 struct mbr_partition *mbrp; 1115 uint rstart, rend; 1116 const char *name, *cp, *mounted; 1117 int len; 1118 1119 mbrp = get_mbrp(&mbri, opt); 1120 if (opt >= MBR_PART_COUNT) 1121 opt = 0; 1122 1123 if (mbrp->mbrp_type == 0 && mbri->sector == 0) { 1124 len = snprintf(0, 0, msg_string(MSG_part_row_used), 0, 0, 0); 1125 wprintw(m->mw, "%*s", len, ""); 1126 } else { 1127 rstart = mbri->sector + mbrp->mbrp_start; 1128 rend = (rstart + mbrp->mbrp_size) / sizemult; 1129 rstart = rstart / sizemult; 1130 wprintw(m->mw, msg_string(MSG_part_row_used), 1131 rstart, rend - rstart, 1132 mbrp->mbrp_flag == MBR_PFLAG_ACTIVE ? 'a' : ' ', 1133 #ifdef BOOTSEL 1134 ombri->bootsec == mbri->sector + mbrp->mbrp_start ? 'd' : 1135 #endif 1136 ' ', 1137 mbri->sector + mbrp->mbrp_start == ombri->install && 1138 mbrp->mbrp_type == MBR_PTYPE_NETBSD ? 'I' : ' '); 1139 } 1140 name = get_partname(mbrp->mbrp_type); 1141 mounted = mbri->last_mounted[opt]; 1142 len = strlen(name); 1143 cp = strchr(name, ','); 1144 if (cp != NULL) 1145 len = cp - name; 1146 if (mounted && *mounted != 0) { 1147 wprintw(m->mw, " %*s (%s)", len, name, mounted); 1148 } else 1149 wprintw(m->mw, " %.*s", len, name); 1150 #ifdef BOOTSEL 1151 if (mbri->mbrb.mbrbs_nametab[opt][0] != 0) { 1152 int x, y; 1153 1154 getyx(m->mw, y, x); 1155 if (x > 52) { 1156 x = 52; 1157 wmove(m->mw, y, x); 1158 } 1159 wprintw(m->mw, "%*s %s", 53 - x, "", 1160 mbri->mbrb.mbrbs_nametab[opt]); 1161 } 1162 #endif 1163 } 1164 1165 static void 1166 set_mbr_header(menudesc *m, void *arg) 1167 { 1168 mbr_info_t *mbri = arg; 1169 static menu_ent *opts; 1170 static int num_opts; 1171 mbr_info_t *ext; 1172 menu_ent *op; 1173 int i; 1174 int left; 1175 1176 msg_display(MSG_editparttable); 1177 1178 msg_table_add(MSG_part_header, (unsigned long)(pm->dlsize/sizemult), 1179 multname, multname, multname, multname); 1180 1181 if (num_opts == 0) { 1182 num_opts = 6; 1183 opts = malloc(6 * sizeof *opts); 1184 if (opts == NULL) { 1185 m->numopts = 0; 1186 return; 1187 } 1188 } 1189 1190 /* First four items are the main partitions */ 1191 for (op = opts, i = 0; i < MBR_PART_COUNT; op++, i++) { 1192 op->opt_name = NULL; 1193 op->opt_menu = OPT_NOMENU; 1194 op->opt_flags = OPT_SUB; 1195 op->opt_action = edit_mbr_entry; 1196 } 1197 left = num_opts - MBR_PART_COUNT; 1198 1199 /* Followed by the extended partitions */ 1200 for (ext = mbri->extended; ext; left--, op++, ext = ext->extended) { 1201 if (left <= 1) { 1202 menu_ent *new = realloc(opts, 1203 (num_opts + 4) * sizeof *opts); 1204 if (new == NULL) 1205 break; 1206 num_opts += 4; 1207 left += 4; 1208 op = new + (op - opts); 1209 opts = new; 1210 } 1211 op->opt_name = NULL; 1212 op->opt_menu = OPT_NOMENU; 1213 op->opt_flags = 0; 1214 op->opt_action = edit_mbr_entry; 1215 } 1216 1217 /* and unit changer */ 1218 op->opt_name = MSG_askunits; 1219 op->opt_menu = MENU_sizechoice; 1220 op->opt_flags = OPT_SUB; 1221 op->opt_action = NULL; 1222 op++; 1223 1224 m->opts = opts; 1225 m->numopts = op - opts; 1226 } 1227 1228 int 1229 mbr_use_wholedisk(mbr_info_t *mbri) 1230 { 1231 struct mbr_sector *mbrs = &mbri->mbr; 1232 mbr_info_t *ext; 1233 struct mbr_partition *part; 1234 1235 part = &mbrs->mbr_parts[0]; 1236 /* Set the partition information for full disk usage. */ 1237 while ((ext = mbri->extended)) { 1238 mbri->extended = ext->extended; 1239 free(ext); 1240 } 1241 memset(part, 0, MBR_PART_COUNT * sizeof *part); 1242 #ifdef BOOTSEL 1243 memset(&mbri->mbrb, 0, sizeof mbri->mbrb); 1244 #endif 1245 part[0].mbrp_type = MBR_PTYPE_NETBSD; 1246 part[0].mbrp_size = pm->dlsize - ptn_0_offset; 1247 part[0].mbrp_start = ptn_0_offset; 1248 part[0].mbrp_flag = MBR_PFLAG_ACTIVE; 1249 1250 pm->ptstart = ptn_0_offset; 1251 pm->ptsize = pm->dlsize - ptn_0_offset; 1252 return 1; 1253 } 1254 1255 /* 1256 * Let user change incore Master Boot Record partitions via menu. 1257 */ 1258 int 1259 edit_mbr(mbr_info_t *mbri) 1260 { 1261 struct mbr_sector *mbrs = &mbri->mbr; 1262 mbr_info_t *ext; 1263 struct mbr_partition *part; 1264 int i, j; 1265 int usefull; 1266 int mbr_menu; 1267 int activepart; 1268 int numbsd; 1269 uint bsdstart, bsdsize; 1270 uint start; 1271 1272 /* If targeting a wedge, do not ask for further partitioning */ 1273 if (pm && pm->no_part) 1274 return 1; 1275 1276 /* Ask full/part */ 1277 part = &mbrs->mbr_parts[0]; 1278 get_ptn_alignment(part); /* update ptn_alignment */ 1279 if (partman_go) 1280 usefull = 0; 1281 else { 1282 uint64_t m_size = 1283 DEFROOTSIZE + DEFSWAPSIZE + DEFUSRSIZE + XNEEDMB; 1284 char min_size[5], build_size[5]; 1285 1286 humanize_number(min_size, sizeof(min_size), 1287 2 * m_size * MEG, 1288 "", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); 1289 humanize_number(build_size, sizeof(build_size), 1290 SYSTEM_BUILD_SIZE * MEG, "", HN_AUTOSCALE, 1291 HN_B | HN_NOSPACE | HN_DECIMAL); 1292 1293 msg_display_subst(MSG_fullpart, 7, 1294 pm->diskdev, 1295 msg_string(MSG_parttype_mbr), 1296 msg_string(MSG_parttype_disklabel), 1297 msg_string(MSG_parttype_mbr_short), 1298 msg_string(MSG_parttype_disklabel_short), 1299 min_size, build_size); 1300 process_menu(MENU_fullpart, &usefull); 1301 } 1302 1303 /* DOS fdisk label checking and value setting. */ 1304 if (usefull) { 1305 /* Count nonempty, non-BSD partitions. */ 1306 numbsd = 0; 1307 for (i = 0; i < MBR_PART_COUNT; i++) { 1308 j = part[i].mbrp_type; 1309 if (j == 0) 1310 continue; 1311 numbsd++; 1312 if (j != MBR_PTYPE_NETBSD) 1313 numbsd++; 1314 } 1315 1316 /* Ask if we really want to blow away non-NetBSD stuff */ 1317 if (numbsd > 1) { 1318 msg_display(MSG_ovrwrite); 1319 if (!ask_noyes(NULL)) { 1320 if (logfp) 1321 (void)fprintf(logfp, "User answered no to destroy other data, aborting.\n"); 1322 return 0; 1323 } 1324 } 1325 return(md_mbr_use_wholedisk(mbri)); 1326 } 1327 1328 mbr_menu = new_menu(NULL, NULL, 16, 0, -1, 15, 70, 1329 MC_NOBOX | MC_ALWAYS_SCROLL | MC_NOCLEAR, 1330 set_mbr_header, set_mbr_label, NULL, 1331 NULL, MSG_Partition_table_ok); 1332 if (mbr_menu == -1) 1333 return 0; 1334 1335 /* Default to MB, and use bios geometry for cylinder size */ 1336 set_sizemultname_meg(); 1337 pm->current_cylsize = bhead * bsec; 1338 1339 for (;;) { 1340 pm->ptstart = 0; 1341 pm->ptsize = 0; 1342 process_menu(mbr_menu, mbri); 1343 1344 activepart = 0; 1345 bsdstart = 0; 1346 bsdsize = 0; 1347 for (ext = mbri; ext; ext = ext->extended) { 1348 part = ext->mbr.mbr_parts; 1349 for (i = 0; i < MBR_PART_COUNT; part++, i++) { 1350 if (part->mbrp_flag != 0) 1351 activepart = 1; 1352 if (part->mbrp_type != MBR_PTYPE_NETBSD) 1353 continue; 1354 start = ext->sector + part->mbrp_start; 1355 if (start == mbri->install) { 1356 pm->ptstart = mbri->install; 1357 pm->ptsize = part->mbrp_size; 1358 } 1359 if (bsdstart != 0) 1360 bsdstart = ~0; 1361 else { 1362 bsdstart = start; 1363 bsdsize = part->mbrp_size; 1364 } 1365 } 1366 } 1367 1368 /* Install in only netbsd partition if none tagged */ 1369 if (pm->ptstart == 0 && bsdstart != ~0u) { 1370 pm->ptstart = bsdstart; 1371 pm->ptsize = bsdsize; 1372 } 1373 1374 if (pm->ptstart == 0) { 1375 if (bsdstart == 0) 1376 msg_display(MSG_nobsdpart); 1377 else 1378 msg_display(MSG_multbsdpart, 0); 1379 msg_display_add(MSG_reeditpart, 0); 1380 if (!ask_yesno(NULL)) 1381 return 0; 1382 continue; 1383 } 1384 1385 if (activepart == 0) { 1386 msg_display(MSG_noactivepart); 1387 if (ask_yesno(NULL)) 1388 continue; 1389 } 1390 /* the md_check_mbr function has 3 ret codes to deal with 1391 * the different possible states. 0, 1, >1 1392 */ 1393 j = md_check_mbr(mbri); 1394 if (j == 0) 1395 return 0; 1396 if (j == 1) 1397 continue; 1398 1399 break; 1400 } 1401 1402 free_menu(mbr_menu); 1403 1404 return 1; 1405 } 1406 1407 const char * 1408 get_partname(int typ) 1409 { 1410 int j; 1411 static char unknown[32]; 1412 1413 for (j = 0; part_ids[j].id != -1; j++) 1414 if (part_ids[j].id == typ) 1415 return part_ids[j].name; 1416 1417 snprintf(unknown, sizeof unknown, "Unknown (%d)", typ); 1418 return unknown; 1419 } 1420 1421 #ifdef BOOTSEL 1422 static int 1423 validate_and_set_names(mbr_info_t *mbri, const struct mbr_bootsel *src, 1424 uint32_t ext_base) 1425 { 1426 size_t i, l; 1427 const unsigned char *p; 1428 1429 /* 1430 * The 16 bit magic used to detect whether mbr_bootsel is valid 1431 * or not is pretty week - collisions have been seen in the wild; 1432 * but maybe it is just foreign tools corruption reminiscents 1433 * of NetBSD MBRs. Anyway, before accepting a boot menu definition, 1434 * make sure it is kinda "sane". 1435 */ 1436 1437 for (i = 0; i < MBR_PART_COUNT; i++) { 1438 /* 1439 * Make sure the name does not contain controll chars 1440 * (not using iscntrl due to minimalistic locale support 1441 * in miniroot environments) and is properly 0-terminated. 1442 */ 1443 for (l = 0, p = (const unsigned char *)&src->mbrbs_nametab[i]; 1444 *p != 0; l++, p++) { 1445 if (l > MBR_BS_PARTNAMESIZE) 1446 return 0; 1447 if (*p < ' ') /* hacky 'iscntrl' */ 1448 return 0; 1449 } 1450 } 1451 1452 memcpy(&mbri->mbrb, src, sizeof(*src)); 1453 1454 if (ext_base == 0) 1455 return mbri->mbrb.mbrbs_defkey - SCAN_1; 1456 return 0; 1457 } 1458 #endif 1459 1460 int 1461 read_mbr(const char *disk, mbr_info_t *mbri) 1462 { 1463 struct mbr_partition *mbrp; 1464 struct mbr_sector *mbrs = &mbri->mbr; 1465 mbr_info_t *ext = NULL; 1466 char diskpath[MAXPATHLEN]; 1467 int fd, i; 1468 uint32_t ext_base = 0, next_ext = 0, ext_size = 0; 1469 int rval = -1; 1470 #ifdef BOOTSEL 1471 mbr_info_t *ombri = mbri; 1472 int bootkey = 0; 1473 #endif 1474 1475 /* 1476 * Fake up a likely 'bios sectors per track' for any extended 1477 * partition headers we might have to produce. 1478 */ 1479 if (bsec == 0) 1480 bsec = pm->dlsec; 1481 if (bhead == 0) 1482 bhead = pm->dlhead; 1483 if (bcyl == 0) 1484 bhead = pm->dlcyl; 1485 1486 ptn_0_offset = bsec; 1487 /* use 1MB default offset on large disks as fdisk(8) */ 1488 if ((unsigned long)pm->dlsize > 128 * GIG / 512) 1489 ptn_0_offset = 2048; 1490 1491 memset(mbri, 0, sizeof *mbri); 1492 1493 /* Open the disk. */ 1494 fd = opendisk(disk, O_RDONLY, diskpath, sizeof(diskpath), 0); 1495 if (fd < 0) 1496 goto bad_mbr; 1497 1498 for (;;) { 1499 if (pread(fd, mbrs, sizeof *mbrs, 1500 (ext_base + next_ext) * (off_t)MBR_SECSIZE) - sizeof *mbrs != 0) 1501 break; 1502 1503 if (!valid_mbr(mbrs)) 1504 break; 1505 1506 mbrp = &mbrs->mbr_parts[0]; 1507 if (ext_base == 0) { 1508 get_ptn_alignment(mbrp); /* get ptn_0_offset */ 1509 } else { 1510 /* sanity check extended chain */ 1511 if (MBR_IS_EXTENDED(mbrp[0].mbrp_type)) 1512 break; 1513 if (mbrp[1].mbrp_type != 0 && 1514 !MBR_IS_EXTENDED(mbrp[1].mbrp_type)) 1515 break; 1516 if (mbrp[2].mbrp_type != 0 || mbrp[3].mbrp_type != 0) 1517 break; 1518 /* Looks ok, link into extended chain */ 1519 mbri->extended = ext; 1520 ext->prev_ext = next_ext != 0 ? mbri : NULL; 1521 ext->extended = NULL; 1522 mbri = ext; 1523 ext = NULL; 1524 } 1525 #if BOOTSEL 1526 if (mbrs->mbr_bootsel_magic == htole16(MBR_MAGIC)) { 1527 /* old bootsel, grab bootsel info */ 1528 bootkey = validate_and_set_names(mbri, 1529 (struct mbr_bootsel *) 1530 ((uint8_t *)mbrs + MBR_BS_OLD_OFFSET), 1531 ext_base); 1532 } else if (mbrs->mbr_bootsel_magic == htole16(MBR_BS_MAGIC)) { 1533 /* new location */ 1534 bootkey = validate_and_set_names(mbri, 1535 &mbrs->mbr_bootsel, ext_base); 1536 } 1537 /* Save original flags for mbr code update tests */ 1538 mbri->oflags = mbri->mbrb.mbrbs_flags; 1539 #endif 1540 mbri->sector = next_ext + ext_base; 1541 next_ext = 0; 1542 rval = 0; 1543 for (i = 0; i < MBR_PART_COUNT; mbrp++, i++) { 1544 if (mbrp->mbrp_type == 0) { 1545 /* type is unused, discard scum */ 1546 memset(mbrp, 0, sizeof *mbrp); 1547 continue; 1548 } 1549 mbrp->mbrp_start = le32toh(mbrp->mbrp_start); 1550 mbrp->mbrp_size = le32toh(mbrp->mbrp_size); 1551 if (MBR_IS_EXTENDED(mbrp->mbrp_type)) { 1552 next_ext = mbrp->mbrp_start; 1553 if (ext_base == 0) 1554 ext_size = mbrp->mbrp_size; 1555 } else { 1556 mbri->last_mounted[i] = strdup(get_last_mounted( 1557 fd, mbri->sector + mbrp->mbrp_start, NULL)); 1558 #if BOOTSEL 1559 if (ombri->install == 0 && 1560 strcmp(mbri->last_mounted[i], "/") == 0) 1561 ombri->install = mbri->sector + 1562 mbrp->mbrp_start; 1563 #endif 1564 } 1565 #if BOOTSEL 1566 if (mbri->mbrb.mbrbs_nametab[i][0] != 0 1567 && bootkey-- == 0) 1568 ombri->bootsec = mbri->sector + 1569 mbrp->mbrp_start; 1570 #endif 1571 } 1572 1573 if (ext_base != 0) { 1574 /* Is there a gap before the next partition? */ 1575 unsigned int limit = next_ext; 1576 unsigned int base; 1577 if (limit == 0) 1578 limit = ext_size; 1579 mbrp -= MBR_PART_COUNT; 1580 base =mbri->sector + mbrp->mbrp_start + mbrp->mbrp_size; 1581 if (mbrp->mbrp_type != 0 && ext_base + limit != base) { 1582 /* Mock up an extry for the space */ 1583 ext = calloc(1, sizeof *ext); 1584 if (!ext) 1585 break; 1586 ext->sector = base; 1587 ext->mbr.mbr_magic = htole16(MBR_MAGIC); 1588 ext->mbr.mbr_parts[1] = mbrp[1]; 1589 ext->mbr.mbr_parts[0].mbrp_start = ptn_0_offset; 1590 ext->mbr.mbr_parts[0].mbrp_size = 1591 ext_base + limit - base - ptn_0_offset; 1592 mbrp[1].mbrp_type = MBR_PTYPE_EXT; 1593 mbrp[1].mbrp_start = base - ext_base; 1594 mbrp[1].mbrp_size = limit - mbrp[1].mbrp_start; 1595 mbri->extended = ext; 1596 ext->prev_ext = mbri; 1597 ext->extended = NULL; 1598 mbri = ext; 1599 ext = NULL; 1600 } 1601 } 1602 1603 if (next_ext == 0 || ext_base + next_ext <= mbri->sector) 1604 break; 1605 if (ext_base == 0) { 1606 ext_base = next_ext; 1607 next_ext = 0; 1608 } 1609 ext = calloc(sizeof *ext, 1); 1610 if (!ext) 1611 break; 1612 mbrs = &ext->mbr; 1613 } 1614 1615 bad_mbr: 1616 free(ext); 1617 if (fd >= 0) 1618 close(fd); 1619 if (rval == -1) { 1620 memset(&mbrs->mbr_parts, 0, sizeof mbrs->mbr_parts); 1621 mbrs->mbr_magic = htole16(MBR_MAGIC); 1622 } 1623 dump_mbr(ombri, "read"); 1624 return rval; 1625 } 1626 1627 int 1628 write_mbr(const char *disk, mbr_info_t *mbri, int convert) 1629 { 1630 char diskpath[MAXPATHLEN]; 1631 int fd, i, ret = 0; 1632 struct mbr_partition *mbrp; 1633 u_int32_t pstart, psize; 1634 #ifdef BOOTSEL 1635 struct mbr_sector *mbrs; 1636 #endif 1637 struct mbr_sector mbrsec; 1638 mbr_info_t *ext; 1639 uint sector; 1640 1641 /* Open the disk. */ 1642 fd = opendisk(disk, O_WRONLY, diskpath, sizeof(diskpath), 0); 1643 if (fd < 0) 1644 return -1; 1645 1646 #ifdef BOOTSEL 1647 /* 1648 * If the main boot code (appears to) contain the netbsd bootcode, 1649 * copy in all the menu strings and set the default keycode 1650 * to be that for the default partition. 1651 * Unfortunately we can't rely on the user having actually updated 1652 * to the new mbr code :-( 1653 */ 1654 if (mbri->mbr.mbr_bootsel_magic == htole16(MBR_BS_MAGIC) 1655 || mbri->mbr.mbr_bootsel_magic == htole16(MBR_MAGIC)) { 1656 int8_t key = SCAN_1; 1657 uint offset = MBR_BS_OFFSET; 1658 if (mbri->mbr.mbr_bootsel_magic == htole16(MBR_MAGIC)) 1659 offset = MBR_BS_OLD_OFFSET; 1660 mbri->mbrb.mbrbs_defkey = SCAN_ENTER; 1661 if (mbri->mbrb.mbrbs_timeo == 0) 1662 mbri->mbrb.mbrbs_timeo = 182; /* 10 seconds */ 1663 for (ext = mbri; ext != NULL; ext = ext->extended) { 1664 mbrs = &ext->mbr; 1665 mbrp = &mbrs->mbr_parts[0]; 1666 /* Ensure marker is set in each sector */ 1667 mbrs->mbr_bootsel_magic = mbri->mbr.mbr_bootsel_magic; 1668 /* and copy in bootsel parameters */ 1669 *(struct mbr_bootsel *)((uint8_t *)mbrs + offset) = 1670 ext->mbrb; 1671 for (i = 0; i < MBR_PART_COUNT; i++) { 1672 if (ext->mbrb.mbrbs_nametab[i][0] == 0) 1673 continue; 1674 if (ext->sector + mbrp->mbrp_start == 1675 mbri->bootsec) 1676 mbri->mbrb.mbrbs_defkey = key; 1677 key++; 1678 } 1679 } 1680 /* copy main data (again) since we've put the 'key' in */ 1681 *(struct mbr_bootsel *)((uint8_t *)&mbri->mbr + offset) = 1682 mbri->mbrb; 1683 } 1684 #endif 1685 1686 for (ext = mbri; ext != NULL; ext = ext->extended) { 1687 sector = ext->sector; 1688 mbrsec = ext->mbr; /* copy sector */ 1689 mbrp = &mbrsec.mbr_parts[0]; 1690 1691 if (sector != 0 && ext->extended != NULL 1692 && ext->extended->mbr.mbr_parts[0].mbrp_type == 0) { 1693 /* We are followed by an empty slot, collapse out */ 1694 ext = ext->extended; 1695 /* Make us describe the next non-empty partition */ 1696 mbrp[1] = ext->mbr.mbr_parts[1]; 1697 } 1698 1699 for (i = 0; i < MBR_PART_COUNT; i++) { 1700 if (mbrp[i].mbrp_start == 0 && mbrp[i].mbrp_size == 0) { 1701 mbrp[i].mbrp_scyl = 0; 1702 mbrp[i].mbrp_shd = 0; 1703 mbrp[i].mbrp_ssect = 0; 1704 mbrp[i].mbrp_ecyl = 0; 1705 mbrp[i].mbrp_ehd = 0; 1706 mbrp[i].mbrp_esect = 0; 1707 continue; 1708 } 1709 pstart = mbrp[i].mbrp_start; 1710 psize = mbrp[i].mbrp_size; 1711 mbrp[i].mbrp_start = htole32(pstart); 1712 mbrp[i].mbrp_size = htole32(psize); 1713 if (convert) { 1714 convert_mbr_chs(bcyl, bhead, bsec, 1715 &mbrp[i].mbrp_scyl, &mbrp[i].mbrp_shd, 1716 &mbrp[i].mbrp_ssect, pstart); 1717 convert_mbr_chs(bcyl, bhead, bsec, 1718 &mbrp[i].mbrp_ecyl, &mbrp[i].mbrp_ehd, 1719 &mbrp[i].mbrp_esect, pstart + psize - 1); 1720 } 1721 } 1722 1723 mbrsec.mbr_magic = htole16(MBR_MAGIC); 1724 if (pwrite(fd, &mbrsec, sizeof mbrsec, 1725 sector * (off_t)MBR_SECSIZE) < 0) { 1726 ret = -1; 1727 break; 1728 } 1729 } 1730 1731 (void)close(fd); 1732 return ret; 1733 } 1734 1735 int 1736 valid_mbr(struct mbr_sector *mbrs) 1737 { 1738 1739 return (le16toh(mbrs->mbr_magic) == MBR_MAGIC); 1740 } 1741 1742 static void 1743 convert_mbr_chs(int cyl, int head, int sec, 1744 uint8_t *cylp, uint8_t *headp, uint8_t *secp, 1745 uint32_t relsecs) 1746 { 1747 unsigned int tcyl, temp, thead, tsec; 1748 1749 temp = head * sec; 1750 tcyl = relsecs / temp; 1751 relsecs -= tcyl * temp; 1752 1753 thead = relsecs / sec; 1754 tsec = relsecs - thead * sec + 1; 1755 1756 if (tcyl > MAXCYL) 1757 tcyl = MAXCYL; 1758 1759 *cylp = MBR_PUT_LSCYL(tcyl); 1760 *headp = thead; 1761 *secp = MBR_PUT_MSCYLANDSEC(tcyl, tsec); 1762 } 1763 1764 /* 1765 * This function is ONLY to be used as a last resort to provide a 1766 * hint for the user. Ports should provide a more reliable way 1767 * of getting the BIOS geometry. The i386 code, for example, 1768 * uses the BIOS geometry as passed on from the bootblocks, 1769 * and only uses this as a hint to the user when that information 1770 * is not present, or a match could not be made with a NetBSD 1771 * device. 1772 */ 1773 1774 int 1775 guess_biosgeom_from_mbr(mbr_info_t *mbri, int *cyl, int *head, daddr_t *sec) 1776 { 1777 struct mbr_sector *mbrs = &mbri->mbr; 1778 struct mbr_partition *parts = &mbrs->mbr_parts[0]; 1779 int xcylinders, xheads, i, j; 1780 daddr_t xsectors; 1781 int c1, h1, s1, c2, h2, s2; 1782 daddr_t a1, a2; 1783 uint64_t num, denom; 1784 1785 /* 1786 * The physical parameters may be invalid as bios geometry. 1787 * If we cannot determine the actual bios geometry, we are 1788 * better off picking a likely 'faked' geometry than leaving 1789 * the invalid physical one. 1790 */ 1791 1792 xcylinders = pm->dlcyl; 1793 xheads = pm->dlhead; 1794 xsectors = pm->dlsec; 1795 if (xcylinders > MAXCYL || xheads > MAXHEAD || xsectors > MAXSECTOR) { 1796 xsectors = MAXSECTOR; 1797 xheads = MAXHEAD; 1798 xcylinders = pm->dlsize / (MAXSECTOR * MAXHEAD); 1799 if (xcylinders > MAXCYL) 1800 xcylinders = MAXCYL; 1801 } 1802 *cyl = xcylinders; 1803 *head = xheads; 1804 *sec = xsectors; 1805 1806 xheads = -1; 1807 1808 /* Try to deduce the number of heads from two different mappings. */ 1809 for (i = 0; i < MBR_PART_COUNT * 2 - 1; i++) { 1810 if (get_mapping(parts, i, &c1, &h1, &s1, &a1) < 0) 1811 continue; 1812 a1 -= s1; 1813 for (j = i + 1; j < MBR_PART_COUNT * 2; j++) { 1814 if (get_mapping(parts, j, &c2, &h2, &s2, &a2) < 0) 1815 continue; 1816 a2 -= s2; 1817 num = (uint64_t)h1 * a2 - (quad_t)h2 * a1; 1818 denom = (uint64_t)c2 * a1 - (quad_t)c1 * a2; 1819 if (num != 0 && denom != 0 && num % denom == 0) { 1820 xheads = (int)(num / denom); 1821 xsectors = a1 / (c1 * xheads + h1); 1822 break; 1823 } 1824 } 1825 if (xheads != -1) 1826 break; 1827 } 1828 1829 if (xheads == -1) 1830 return -1; 1831 1832 /* 1833 * Estimate the number of cylinders. 1834 * XXX relies on get_disks having been called. 1835 */ 1836 xcylinders = pm->dlsize / xheads / xsectors; 1837 if (pm->dlsize != xcylinders * xheads * xsectors) 1838 xcylinders++; 1839 1840 /* 1841 * Now verify consistency with each of the partition table entries. 1842 * Be willing to shove cylinders up a little bit to make things work, 1843 * but translation mismatches are fatal. 1844 */ 1845 for (i = 0; i < MBR_PART_COUNT * 2; i++) { 1846 if (get_mapping(parts, i, &c1, &h1, &s1, &a1) < 0) 1847 continue; 1848 if (c1 >= MAXCYL - 1) 1849 /* Ignore anything that is near the CHS limit */ 1850 continue; 1851 if (xsectors * (c1 * xheads + h1) + s1 != a1) 1852 return -1; 1853 } 1854 1855 /* 1856 * Everything checks out. Reset the geometry to use for further 1857 * calculations. 1858 */ 1859 *cyl = MIN(xcylinders, MAXCYL); 1860 *head = xheads; 1861 *sec = xsectors; 1862 return 0; 1863 } 1864 1865 static int 1866 get_mapping(struct mbr_partition *parts, int i, 1867 int *cylinder, int *head, int *sector, daddr_t *absolute) 1868 { 1869 struct mbr_partition *apart = &parts[i / 2]; 1870 1871 if (apart->mbrp_type == 0) 1872 return -1; 1873 if (i % 2 == 0) { 1874 *cylinder = MBR_PCYL(apart->mbrp_scyl, apart->mbrp_ssect); 1875 *head = apart->mbrp_shd; 1876 *sector = MBR_PSECT(apart->mbrp_ssect) - 1; 1877 *absolute = le32toh(apart->mbrp_start); 1878 } else { 1879 *cylinder = MBR_PCYL(apart->mbrp_ecyl, apart->mbrp_esect); 1880 *head = apart->mbrp_ehd; 1881 *sector = MBR_PSECT(apart->mbrp_esect) - 1; 1882 *absolute = le32toh(apart->mbrp_start) 1883 + le32toh(apart->mbrp_size) - 1; 1884 } 1885 /* Sanity check the data against max values */ 1886 if ((((*cylinder * MAXHEAD) + *head) * (uint32_t)MAXSECTOR + *sector) < *absolute) 1887 /* cannot be a CHS mapping */ 1888 return -1; 1889 1890 return 0; 1891 } 1892 1893 /* 1894 * Determine partition boundary alignment as fdisk(8) does. 1895 */ 1896 static void 1897 get_ptn_alignment(struct mbr_partition *mbrp0) 1898 { 1899 uint32_t ptn_0_base, ptn_0_limit; 1900 1901 /* Default to using 'traditional' cylinder alignment */ 1902 ptn_alignment = bhead * bsec; 1903 ptn_0_offset = bsec; 1904 1905 if (mbrp0->mbrp_type != 0) { 1906 /* Try to copy offset of first partition */ 1907 ptn_0_base = le32toh(mbrp0->mbrp_start); 1908 ptn_0_limit = ptn_0_base + le32toh(mbrp0->mbrp_size); 1909 if (!(ptn_0_limit & 2047)) { 1910 /* Partition ends on a 1MB boundary, align to 1MB */ 1911 ptn_alignment = 2048; 1912 if (ptn_0_base <= 2048 1913 && !(ptn_0_base & (ptn_0_base - 1))) { 1914 /* ptn_base is a power of 2, use it */ 1915 ptn_0_offset = ptn_0_base; 1916 } 1917 } 1918 } else { 1919 /* Use 1MB offset for large (>128GB) disks */ 1920 if ((unsigned long)pm->dlsize > 128 * GIG / 512) { 1921 ptn_alignment = 2048; 1922 ptn_0_offset = 2048; 1923 } 1924 } 1925 } 1926