1 /* $NetBSD: md.c,v 1.8 2019/07/13 17:13:38 martin Exp $ */ 2 3 /* 4 * Copyright 1997 Piermont Information Systems Inc. 5 * All rights reserved. 6 * 7 * Based on code written by Philip A. Nelson for Piermont Information 8 * Systems Inc. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. The name of Piermont Information Systems Inc. may not be used to endorse 19 * or promote products derived from this software without specific prior 20 * written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS'' 23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE 26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 32 * THE POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 /* md.c -- mac68k machine specific routines */ 36 37 #include <stdio.h> 38 #include <util.h> 39 #include <unistd.h> 40 #include <fcntl.h> 41 #include <sys/ioctl.h> 42 #include <sys/utsname.h> 43 #include <machine/int_fmtio.h> 44 45 #include "defs.h" 46 #include "md.h" 47 #include "msg_defs.h" 48 #include "menu_defs.h" 49 50 static int stricmp(const char *c1, const char *c2); 51 static void setpartition(struct apple_part_map_entry *, char *, int); 52 static int getFreeLabelEntry(char *); 53 static char *getFstype(struct apple_part_map_entry *, int, char *); 54 static char *getUse(struct apple_part_map_entry *, int, char *); 55 static char *getName(struct apple_part_map_entry *, int, char *); 56 static int findStdType(int, char *, int, int *, int); 57 static int check_for_errors(void); 58 static int edit_diskmap(void); 59 #ifdef MD_DEBUG_SORT_MERGE 60 static int md_debug_dump(char *); 61 #endif 62 63 int blk_size; 64 65 MAP_TYPE map_types[] = { 66 {MAP_RESERVED, APPLE_PART_TYPE_DRIVER}, 67 {MAP_RESERVED, APPLE_PART_TYPE_DRIVER43}, 68 {MAP_RESERVED, APPLE_PART_TYPE_DRIVERATA}, 69 {MAP_RESERVED, APPLE_PART_TYPE_FWB_COMPONENT}, 70 {MAP_MACOS, APPLE_PART_TYPE_MAC}, 71 {MAP_NETBSD, APPLE_PART_TYPE_NETBSD}, 72 {MAP_RESERVED, APPLE_PART_TYPE_PARTMAP}, 73 {MAP_OTHER, APPLE_PART_TYPE_SCRATCH}, 74 {MAP_NETBSD, APPLE_PART_TYPE_UNIX}, 75 {MAP_EOL, NULL} 76 }; 77 78 MAP map = {0, 0, 0, 0, 0, 0, 0, 0, {0}, NULL}; 79 80 struct apple_part_map_entry new_map[] = 81 { 82 { APPLE_PART_MAP_ENTRY_MAGIC, 0xa5a5, 6, 1, NEW_MAP_SIZE & 0x7e, 83 "Apple", "Apple_Partition_Map", 0, NEW_MAP_SIZE, 0x37, 84 0, 0, 0, 0, 0, 0, 0, {0}, {0}, {0}}, 85 { APPLE_PART_MAP_ENTRY_MAGIC, 0, 6, 64, 32, 86 "Macintosh", "Apple_Driver", 0, 0, 0x37, 87 0, 0, 0, 0, 0, 0, 0, {0}, {0}, {0}}, 88 { APPLE_PART_MAP_ENTRY_MAGIC, 0, 6, 96, 64, 89 "Macintosh", "Apple_Driver43", 0, 0, 0x37, 90 0, 0, 0, 0, 0, 0, 0, {0}, {0}, {0}}, 91 { APPLE_PART_MAP_ENTRY_MAGIC, 0, 6, 160, 64, 92 "Macintosh", "Apple_Driver_ATA", 0, 0, 0x37, 93 0, 0, 0, 0, 0, 0, 0, {0}, {0}, {0}}, 94 { APPLE_PART_MAP_ENTRY_MAGIC, 0, 6, 224, 4096, 95 "untitled", "Apple_HFS", 0, 0, 0x37, 96 0, 0, 0, 0, 0, 0, 0, {0}, {0}, {0}}, 97 { APPLE_PART_MAP_ENTRY_MAGIC, 0, 6,4320, 0, 98 "untitled", "Apple_Free", 0, 0, 0x37, 99 0, 0, 0, 0, 0, 0, 0, {0}, {0}, {0}} 100 }; 101 102 void 103 md_init(void) 104 { 105 } 106 107 void 108 md_init_set_status(int flags) 109 { 110 struct utsname instsys; 111 112 (void)flags; 113 114 /* 115 * Get the name of the Install Kernel we are running under and 116 * enable the installation of the corresponding GENERIC kernel. 117 * 118 * Note: In md.h the two kernels are disabled. If they are 119 * enabled there the logic here needs to be switched. 120 */ 121 uname(&instsys); 122 if (strstr(instsys.version, "(INSTALLSBC)")) 123 /* 124 * Running the SBC Installation Kernel, so enable GENERICSBC 125 */ 126 set_kernel_set(SET_KERNEL_2); 127 else 128 /* 129 * Running the GENERIC Installation Kernel, so enable GENERIC 130 */ 131 set_kernel_set(SET_KERNEL_1); 132 } 133 134 bool 135 md_get_info(struct install_partition_desc *install) 136 { 137 struct disklabel disklabel; 138 int fd, i; 139 char dev_name[100]; 140 struct apple_part_map_entry block; 141 142 snprintf(dev_name, sizeof(dev_name), "/dev/r%s%c", 143 pm->diskdev, 'a' + getrawpartition()); 144 145 /* 146 * Open the disk as a raw device 147 */ 148 fd = open(dev_name, O_RDONLY, 0); 149 if (fd < 0) { 150 endwin(); 151 fprintf (stderr, "Can't open %s\n", dev_name); 152 exit(1); 153 } 154 /* 155 * Try to get the default disklabel info for the device 156 */ 157 if (ioctl(fd, DIOCGDINFO, &disklabel) == -1) { 158 endwin(); 159 fprintf (stderr, "Can't read disklabel on %s\n", dev_name); 160 close(fd); 161 exit(1); 162 } 163 /* 164 * Get the disk parameters from the disk driver. It should have 165 * obained them by querying the disk itself. 166 */ 167 blk_size = disklabel.d_secsize; 168 pm->dlcyl = disklabel.d_ncylinders; 169 pm->dlhead = disklabel.d_ntracks; 170 pm->dlsec = disklabel.d_nsectors; 171 /* 172 * Just in case, initialize the structures we'll need if we 173 * need to completely initialize the disk. 174 */ 175 pm->dlsize = disklabel.d_secperunit; 176 /* 177 * XXX this code is broken: it accesses off the end of new_map[], 178 * because NEW_MAP_SIZE is substantially larger than the number of 179 * entries in new_map[]. Based on the description of struct 180 * apple_part_map_entry in sys/bootblock.h, and the usage of it in 181 * new_map[], NEW_MAP_SIZE is expected to be a block count, not an 182 * entry count. As far I can tell the logic here is just wrong; it 183 * needs someone with platform knowledge to sort it out. 184 * 185 * Note that nothing uses the data this writes into new_map[] so 186 * disabling it should have no adverse consequences. 187 * 188 * - dholland 20160530 189 */ 190 #if 0 /* XXX broken */ 191 for (i=0;i<NEW_MAP_SIZE;i++) { 192 if (i > 0) 193 new_map[i].pmPyPartStart = new_map[i-1].pmPyPartStart + 194 new_map[i-1].pmPartBlkCnt; 195 new_map[i].pmDataCnt = new_map[i].pmPartBlkCnt; 196 if (new_map[i].pmPartBlkCnt == 0) { 197 new_map[i].pmPartBlkCnt = pm->dlsize; 198 new_map[i].pmDataCnt = pm->dlsize; 199 break; 200 } 201 pm->dlsize -= new_map[i].pmPartBlkCnt; 202 } 203 #endif /* 0 - broken */ 204 pm->dlsize = disklabel.d_secperunit; 205 #if 0 206 msg_fmt_display(MSG_dldebug, "%d%d%d%d%d", 207 blk_size, pm->dlcyl, pm->dlhead, pm->dlsec, pm->dlsize); 208 process_menu(MENU_ok, NULL); 209 #endif 210 map.size = 0; 211 /* 212 * Verify the disk has been initialized for MacOS use by checking 213 * to see if the disk have a Boot Block 214 */ 215 if (lseek(fd, (off_t)0 * blk_size, SEEK_SET) < 0 || 216 read(fd, &block, sizeof(block)) - sizeof(block) != 0 || 217 block.pmSig != 0x4552) { 218 process_menu(MENU_nodiskmap, NULL); 219 } 220 else { 221 /* 222 * Scan for the Partition Map entry that describes the Partition 223 * Map itself. We need to know the number of blocks allocated 224 * to it and the number currently in use. 225 */ 226 for (i=0;i<MAXMAXPARTITIONS;i++) { 227 lseek(fd, (off_t)(i+1) * blk_size, SEEK_SET); 228 read(fd, &block, sizeof(block)); 229 if (stricmp("Apple_partition_map", (char *)block.pmPartType) == 0) { 230 map.size = block.pmPartBlkCnt; 231 map.in_use_cnt = block.pmMapBlkCnt; 232 map.blk = (struct apple_part_map_entry *)malloc(map.size * blk_size); 233 break; 234 } 235 } 236 lseek(fd, (off_t)1 * blk_size, SEEK_SET); 237 read(fd, map.blk, map.size * blk_size); 238 } 239 close(fd); 240 241 return edit_diskmap(); 242 } 243 244 /* 245 * md back-end code for menu-driven BSD disklabel editor. 246 */ 247 bool 248 md_make_bsd_partitions(struct install_partition_desc *install) 249 { 250 int rv; 251 #if 0 // XXX 252 FILE *f; 253 int i, j, pl; 254 EBZB *bzb; 255 #endif 256 257 /* 258 * Scan for any problems and report them before continuing. 259 * The user can abort installation and we'll take them back 260 * to the main menu; continue ignoring the warnings, or 261 * ask to reedit the Disk Partition Map. 262 */ 263 while (1) { 264 if (check_for_errors()) { 265 process_menu (MENU_sanity, &rv); 266 if (rv < 0) 267 return false; 268 else if (rv) 269 break; 270 edit_diskmap(); 271 } else 272 break; 273 } 274 275 #if 0 // XXX 276 /* Build standard partitions */ 277 memset(&pm->bsdlabel, 0, sizeof pm->bsdlabel); 278 279 /* 280 * The mac68k port has a predefined partition for "c" which 281 * is the size of the disk, everything else is unused. 282 */ 283 pm->bsdlabel[RAW_PART].pi_size = pm->dlsize; 284 /* 285 * Now, scan through the Disk Partition Map and transfer the 286 * information into the incore disklabel. 287 */ 288 for (i=0;i<map.usable_cnt;i++) { 289 j = map.mblk[i]; 290 bzb = (EBZB *)&map.blk[j].pmBootArgs[0]; 291 if (bzb->flags.part) { 292 pl = bzb->flags.part - 'a'; 293 switch (whichType(&map.blk[j])) { 294 case HFS_PART: 295 pm->bsdlabel[pl].pi_fstype = FS_HFS; 296 strcpy (pm->bsdlabel[pl].pi_mount, (char *)bzb->mount_point); 297 break; 298 case ROOT_PART: 299 case UFS_PART: 300 pm->bsdlabel[pl].pi_fstype = FS_BSDFFS; 301 strcpy (pm->bsdlabel[pl].pi_mount, (char *)bzb->mount_point); 302 pm->bsdlabel[pl].pi_flags |= PIF_NEWFS | PIF_MOUNT; 303 break; 304 case SWAP_PART: 305 pm->bsdlabel[pl].pi_fstype = FS_SWAP; 306 break; 307 case SCRATCH_PART: 308 pm->bsdlabel[pl].pi_fstype = FS_OTHER; 309 strcpy (pm->bsdlabel[pl].pi_mount, (char *)bzb->mount_point); 310 default: 311 break; 312 } 313 if (pm->bsdlabel[pl].pi_fstype != FS_UNUSED) { 314 pm->bsdlabel[pl].pi_size = map.blk[j].pmPartBlkCnt; 315 pm->bsdlabel[pl].pi_offset = map.blk[j].pmPyPartStart; 316 if (pm->bsdlabel[pl].pi_fstype != FS_SWAP) { 317 pm->bsdlabel[pl].pi_frag = 8; 318 pm->bsdlabel[pl].pi_fsize = 1024; 319 } 320 } 321 } 322 } 323 324 /* Disk name - don't bother asking, just use the physical name*/ 325 strcpy (pm->bsddiskname, pm->diskdev); 326 327 #ifdef DEBUG 328 f = fopen ("/tmp/disktab", "w"); 329 #else 330 f = fopen ("/etc/disktab", "w"); 331 #endif 332 if (f == NULL) { 333 endwin(); 334 (void) fprintf (stderr, "Could not open /etc/disktab"); 335 exit (1); 336 } 337 (void)fprintf (f, "%s|NetBSD installation generated:\\\n", pm->bsddiskname); 338 (void)fprintf (f, "\t:dt=%s:ty=winchester:\\\n", pm->disktype); 339 (void)fprintf (f, "\t:nc#%d:nt#%d:ns#%d:\\\n", pm->dlcyl, pm->dlhead, pm->dlsec); 340 (void)fprintf (f, "\t:sc#%d:su#%" PRIu32 ":\\\n", pm->dlhead*pm->dlsec, (uint32_t)pm->dlsize); 341 (void)fprintf (f, "\t:se#%d:%s\\\n", blk_size, pm->doessf); 342 for (i=0; i<8; i++) { 343 if (pm->bsdlabel[i].pi_fstype == FS_HFS) 344 (void)fprintf (f, "\t:p%c#%d:o%c#%d:t%c=macos:", 345 'a'+i, pm->bsdlabel[i].pi_size, 346 'a'+i, pm->bsdlabel[i].pi_offset, 347 'a'+i); 348 else 349 (void)fprintf (f, "\t:p%c#%d:o%c#%d:t%c=%s:", 350 'a'+i, pm->bsdlabel[i].pi_size, 351 'a'+i, pm->bsdlabel[i].pi_offset, 352 'a'+i, getfslabelname(pm->bsdlabel[i].pi_fstype)); 353 if (pm->bsdlabel[i].pi_fstype == FS_BSDFFS) 354 (void)fprintf (f, "b%c#%d:f%c#%d", 355 'a'+i, pm->bsdlabel[i].pi_fsize * pm->bsdlabel[i].pi_frag, 356 'a'+i, pm->bsdlabel[i].pi_fsize); 357 if (i < 7) 358 (void)fprintf (f, "\\\n"); 359 else 360 (void)fprintf (f, "\n"); 361 } 362 fclose (f); 363 #endif 364 365 /* Everything looks OK. */ 366 return true; 367 } 368 369 /* 370 * any additional partition validation 371 */ 372 bool 373 md_check_partitions(struct install_partition_desc *install) 374 { 375 return true; 376 } 377 378 /* 379 * hook called before writing new disklabel. 380 */ 381 bool 382 md_pre_disklabel(struct install_partition_desc *install, 383 struct disk_partitions *parts) 384 { 385 int fd; 386 char dev_name[100]; 387 struct disklabel lp; 388 Block0 new_block0 = {APPLE_DRVR_MAP_MAGIC, 512, 389 0, 0, 0, 0, 0, 0, 0, 0, {0}}; 390 391 /* 392 * Danger Will Robinson! We're about to turn that nice MacOS disk 393 * into an expensive doorstop... 394 */ 395 printf ("%s", msg_string (MSG_dodiskmap)); 396 397 snprintf (dev_name, sizeof(dev_name), "/dev/r%sc", pm->diskdev); 398 /* 399 * Open the disk as a raw device 400 */ 401 if ((fd = open(dev_name, O_WRONLY, 0)) < 0) { 402 endwin(); 403 fprintf(stderr, "Can't open %s to rewrite the Disk Map\n", dev_name); 404 exit (1); 405 } 406 /* 407 * First check the pmSigPad field of the first block in the incore 408 * Partition Map. It should be zero, but if it's 0xa5a5 that means 409 * we need to write out Block0 too. 410 */ 411 if (map.blk[0].pmSigPad == 0xa5a5) { 412 if (lseek (fd, (off_t)0 * blk_size, SEEK_SET) < 0) { 413 endwin(); 414 fprintf (stderr, "Can't position to write Block0\n"); 415 close (fd); 416 exit (1); 417 } 418 new_block0.sbBlkCount = pm->dlsize; /* Set disk size */ 419 if (write (fd, &new_block0, blk_size) != blk_size) { 420 endwin(); 421 fprintf (stderr, "I/O error writing Block0\n"); 422 close (fd); 423 exit (1); 424 } 425 map.blk[0].pmSigPad = 0; 426 } 427 if (lseek (fd, (off_t)1 * blk_size, SEEK_SET) < 0) { 428 endwin(); 429 fprintf (stderr, "Can't position disk to rewrite Disk Map\n"); 430 close (fd); 431 exit (1); 432 } 433 if (write (fd, map.blk, map.size * blk_size) != (map.size * blk_size)) { 434 endwin(); 435 fprintf(stderr, "I/O error writing Disk Map\n"); 436 close (fd); 437 exit (1); 438 } 439 fsync(fd); 440 /* 441 * Well, if we get here the dirty deed has been done. 442 * 443 * Now we need to force the incore disk table to get updated. This 444 * should be done by disklabel -- which is normally called right after 445 * we return -- but may be commented out for the mac68k port. We'll 446 * instead update the incore table by forcing a dummy write here. This 447 * relies on a change in the mac68k-specific write_disklabel() routine. 448 * If that change doesn't exist nothing bad happens here. If disklabel 449 * properly updates the ondisk and incore labels everything still 450 * works. Only if we fail here and if disklabel fails are we in 451 * in a state where we've updated the disk but not the incore and 452 * a reboot is necessary. 453 * 454 * First, we grab a copy of the incore label as it existed before 455 * we did anything to it. Then we invoke the "write label" ioctl to 456 * rewrite it to disk. As a result, the ondisk partition map is 457 * re-read and the incore label is reconstructed from it. If 458 * disklabel() is then called to update again, either that fails 459 * because the mac68k port doesn't support native disklabels, or it 460 * succeeds and writes out a new ondisk copy. 461 */ 462 ioctl(fd, DIOCGDINFO, &lp); /* Get the current disk label */ 463 ioctl(fd, DIOCWDINFO, &lp); /* Write it out again */ 464 465 close (fd); 466 return true; 467 } 468 469 /* 470 * hook called after writing disklabel to new target disk. 471 */ 472 bool 473 md_post_disklabel(struct install_partition_desc *install, 474 struct disk_partitions *parts) 475 { 476 #if 0 // XXX 477 struct disklabel updated_label; 478 int fd, i, no_match; 479 char dev_name[100], buf[80]; 480 const char *fst[] = {"free", "swap", " v6 ", " v7 ", "sysv", "v71k", 481 " v8 ", "ffs ", "dos ", "lfs ", "othr", "hpfs", 482 "9660", "boot", "ados", "hfs ", "fcor", "ex2f", 483 "ntfs", "raid", "ccd "}; 484 485 snprintf(dev_name, sizeof(dev_name), "/dev/r%sc", pm->diskdev); 486 /* 487 * Open the disk as a raw device 488 */ 489 if ((fd = open(dev_name, O_RDONLY, 0)) < 0) 490 return false; 491 /* 492 * Get the "new" label to see if we were successful. If we aren't 493 * we'll return an error to keep from destroying the user's disk. 494 */ 495 ioctl(fd, DIOCGDINFO, &updated_label); 496 close(fd); 497 /* 498 * Make sure the in-core label matches the on-disk one 499 */ 500 no_match = 0; 501 for (i=0;i<MAXPARTITIONS;i++) { 502 if (i > updated_label.d_npartitions) 503 break; 504 if (pm->bsdlabel[i].pi_size != updated_label.d_partitions[i].p_size) 505 no_match = 1; 506 if (pm->bsdlabel[i].pi_size) { 507 if (pm->bsdlabel[i].pi_offset != updated_label.d_partitions[i].p_offset) 508 no_match = 1; 509 if (pm->bsdlabel[i].pi_fstype != updated_label.d_partitions[i].p_fstype) 510 no_match = 1; 511 } 512 if (no_match) 513 break; 514 } 515 /* 516 * If the labels don't match, tell the user why 517 */ 518 if (no_match) { 519 msg_clear(); 520 msg_display(MSG_label_error); 521 msg_fmt_table_add(MSG_dump_line, "%s", 522 " in-core: offset size type on-disk: offset size type"); 523 for (i=0;i<MAXPARTITIONS;i++) { 524 snprintf(buf, sizeof(buf), 525 " %c:%13.8x%10.8x%5s%16.8x%10.8x%5s", i+'a', 526 pm->bsdlabel[i].pi_offset, pm->bsdlabel[i].pi_size, 527 fst[pm->bsdlabel[i].pi_fstype], 528 updated_label.d_partitions[i].p_offset, 529 updated_label.d_partitions[i].p_size, 530 fst[updated_label.d_partitions[i].p_fstype]); 531 msg_fmt_table_add(MSG_dump_line, "%s", buf); 532 } 533 process_menu(MENU_ok2, NULL); 534 } 535 return no_match == 0; 536 #else 537 return true; 538 #endif 539 } 540 541 /* 542 * hook called after upgrade() or install() has finished setting 543 * up the target disk but immediately before the user is given the 544 * ``disks are now set up'' message. 545 */ 546 int 547 md_post_newfs(struct install_partition_desc *install) 548 { 549 return 0; 550 } 551 552 int 553 md_post_extract(struct install_partition_desc *install) 554 { 555 return 0; 556 } 557 558 void 559 md_cleanup_install(struct install_partition_desc *install) 560 { 561 #ifndef DEBUG 562 enable_rc_conf(); 563 #endif 564 } 565 566 int 567 md_pre_update(struct install_partition_desc *install) 568 { 569 return 1; 570 } 571 572 /* Upgrade support */ 573 int 574 md_update(struct install_partition_desc *install) 575 { 576 md_post_newfs(install); 577 return 1; 578 } 579 580 /* 581 * Compare lexigraphically two strings 582 */ 583 static int 584 stricmp(s1, s2) 585 const char *s1; 586 const char *s2; 587 { 588 char c1, c2; 589 590 while (1) { 591 c1 = tolower((unsigned char)*s1++); 592 c2 = tolower((unsigned char)*s2++); 593 if (c1 < c2) return -1; 594 if (c1 > c2) return 1; 595 if (c1 == 0) return 0; 596 } 597 } 598 599 static void 600 setpartition(part, in_use, slot) 601 struct apple_part_map_entry *part; 602 char in_use[]; 603 int slot; 604 { 605 EBZB *bzb; 606 607 bzb = (EBZB *)&part->pmBootArgs[0]; 608 in_use[slot] = 1; 609 bzb->flags.used = 1; 610 bzb->flags.part = 'a' + slot; 611 } 612 613 /* 614 * Find an entry in a use array that is unused and return it or 615 * -1 if no entry is available 616 */ 617 static int 618 getFreeLabelEntry(slots) 619 char *slots; 620 { 621 int i; 622 623 for ( i = 0; i < MAXPARTITIONS; i++) { 624 if (i != RAW_PART && slots[i] == 0) 625 return i; 626 } 627 return -1; 628 } 629 630 /* 631 * Figure out what type type of the given partition is and return it. 632 */ 633 int 634 whichType(part) 635 struct apple_part_map_entry *part; 636 { 637 MAP_TYPE *map_entry = (MAP_TYPE *)&map_types; 638 EBZB *bzb; 639 char partyp[32]; 640 int type, maxsiz, entry_type = MAP_OTHER; 641 642 bzb = (EBZB *)&part->pmBootArgs[0]; 643 if (part->pmSig != APPLE_PART_MAP_ENTRY_MAGIC) 644 return 0; 645 maxsiz = sizeof(part->pmPartType); 646 if (maxsiz > (int)sizeof(partyp)) 647 maxsiz = sizeof(partyp); 648 strncpy(partyp, (char *)part->pmPartType, maxsiz); 649 partyp[maxsiz-1] = '\0'; 650 651 /* 652 * Find out how to treat the partition type under NetBSD 653 */ 654 while (map_entry->type != MAP_EOL) { 655 if (stricmp(map_entry->name, partyp) == 0) { 656 entry_type = map_entry->type; 657 break; 658 } 659 map_entry++; 660 } 661 662 /* 663 * Now classify the use for NetBSD 664 */ 665 if (entry_type == MAP_RESERVED) 666 type = 0; 667 else if (entry_type == MAP_NETBSD) { 668 if (bzb->magic != APPLE_BZB_MAGIC) 669 type = 0; 670 else if (bzb->type == APPLE_BZB_TYPEFS) { 671 if (bzb->flags.root) 672 type = ROOT_PART; 673 else if (bzb->flags.usr) 674 type = UFS_PART; 675 else 676 type = SCRATCH_PART; 677 } else if (bzb->type == APPLE_BZB_TYPESWAP) 678 type = SWAP_PART; 679 else 680 type = SCRATCH_PART; 681 } else if (entry_type == MAP_MACOS) 682 type = HFS_PART; 683 else 684 type = SCRATCH_PART; 685 return type; 686 } 687 688 static char * 689 getFstype(part, len_type, type) 690 struct apple_part_map_entry *part; 691 int len_type; 692 char *type; 693 { 694 *type = '\0'; 695 switch(whichType(part)) { 696 case ROOT_PART: 697 case UFS_PART: 698 strncpy(type, "4.2BSD", len_type); 699 break; 700 case SWAP_PART: 701 strncpy(type, "swap", len_type); 702 break; 703 case HFS_PART: 704 strncpy(type, "HFS", len_type); 705 break; 706 case SCRATCH_PART: 707 default: 708 break; 709 } 710 return (type); 711 } 712 713 static char * 714 getUse(part, len_use, use) 715 struct apple_part_map_entry *part; 716 int len_use; 717 char *use; 718 { 719 EBZB *bzb; 720 char partyp[32]; 721 722 *use = '\0'; 723 bzb = (EBZB *)&part->pmBootArgs[0]; 724 switch(whichType(part)) { 725 case ROOT_PART: 726 if (bzb->flags.usr) 727 strncpy(use, "Root&Usr", len_use); 728 else 729 strncpy(use, "Root", len_use); 730 break; 731 case UFS_PART: 732 strncpy(use, "Usr", len_use); 733 break; 734 case SWAP_PART: 735 break; 736 case HFS_PART: 737 strncpy(use, "MacOS", len_use); 738 break; 739 case SCRATCH_PART: 740 strncpy(partyp, (char *)part->pmPartType, sizeof(partyp)); 741 partyp[sizeof(partyp)-1] = '\0'; 742 if (stricmp("Apple_Free", partyp) == 0) 743 strncpy(use, "Free", len_use); 744 else if (stricmp("Apple_Scratch", partyp) == 0) 745 strncpy(use, "Scratch", len_use); 746 else if (stricmp("Apple_MFS", partyp) == 0) 747 strncpy(use, "MFS", len_use); 748 else if (stricmp("Apple_PRODOS", partyp) == 0) 749 strncpy(use, "PRODOS", len_use); 750 else 751 strncpy(use, "unknown", len_use); 752 default: 753 break; 754 } 755 return(use); 756 } 757 758 static char * 759 getName(part, len_name, name) 760 struct apple_part_map_entry *part; 761 int len_name; 762 char *name; 763 { 764 EBZB *bzb; 765 int fd; 766 off_t seek; 767 char dev_name[100], macosblk[512]; 768 769 *name = '\0'; 770 bzb = (EBZB *)&part->pmBootArgs[0]; 771 switch(whichType(part)) { 772 case SCRATCH_PART: 773 case ROOT_PART: 774 case UFS_PART: 775 strncpy(name, (char *)bzb->mount_point, len_name); 776 break; 777 case SWAP_PART: 778 break; 779 case HFS_PART: 780 /* 781 * OK, this is stupid but it's damn nice to know! 782 */ 783 snprintf (dev_name, sizeof(dev_name), "/dev/r%sc", pm->diskdev); 784 /* 785 * Open the disk as a raw device 786 */ 787 if ((fd = open(dev_name, O_RDONLY, 0)) >= 0) { 788 seek = (off_t)part->pmPyPartStart + (off_t)2; 789 seek *= (off_t)blk_size; 790 lseek(fd, seek, SEEK_SET); 791 read(fd, &macosblk, sizeof(macosblk)); 792 macosblk[37+32] = '\0'; 793 strncpy(name, (char *)bzb->mount_point, len_name); 794 strncat(name, " (", len_name-strlen(name)); 795 strncat(name, &macosblk[37], len_name-strlen(name)); 796 strncat(name, ")", len_name-strlen(name)); 797 close(fd); 798 } 799 break; 800 default: 801 break; 802 } 803 return(name); 804 } 805 806 /* 807 * Find the first occurance of a Standard Type partition and 808 * mark it for use along with the default mount slot. 809 */ 810 static int 811 findStdType(num_parts, in_use, type, count, alt) 812 int num_parts; 813 char in_use[]; 814 int type; 815 int *count; 816 int alt; 817 { 818 EBZB *bzb; 819 int i; 820 821 for (i = 0; i < num_parts; i++) { 822 bzb = (EBZB *)&map.blk[i].pmBootArgs[0]; 823 if (whichType(&map.blk[i]) != type || bzb->flags.used) 824 continue; 825 if (type == ROOT_PART) { 826 if (alt >= 0 && alt != bzb->cluster) 827 continue; 828 setpartition(&map.blk[i], in_use, 0); 829 strcpy ((char *)bzb->mount_point, "/"); 830 *count += 1; 831 } else if (type == UFS_PART) { 832 if (alt >= 0 && alt != bzb->cluster) 833 continue; 834 setpartition(&map.blk[i], in_use, 6); 835 if (bzb->mount_point[0] == '\0') 836 strcpy ((char *)bzb->mount_point, "/usr"); 837 *count += 1; 838 } else if (type == SWAP_PART) { 839 setpartition(&map.blk[i], in_use, 1); 840 *count += 1; 841 } 842 return 0; 843 } 844 return -1; 845 } 846 847 /* 848 * Reset the flags and reserved fields in the selected partition. 849 * This functions isn't called to process any of the reserved partitions 850 * where the boot code for MacOS is stored, so (hopefully) we won't 851 * do more damage that we're trying to avoid. Eventually the NetBSD 852 * Boot Code will need to go into a partition too, but that should go 853 * into a reserved partition as well. I'd suggest using a partition 854 * named something like "NetBSD_Boot" with a pmPartName of "Macintosh". 855 * The Apple Start Manager (in ROM) will then recognize the partition 856 * as the one containing the system bootstrip for the volume. 857 */ 858 void 859 reset_part_flags(part) 860 struct apple_part_map_entry *part; 861 { 862 EBZB *bzb; 863 864 /* 865 * Clear out the MacOS fields that might be used for booting just 866 * in case we've clobbered the boot code. 867 */ 868 part->pmLgDataStart = 0; 869 part->pmPartStatus = 0x77; /* make sure the partition shows up */ 870 part->pmLgBootStart = 0; 871 part->pmBootSize = 0; 872 part->pmBootLoad = 0; 873 part->pmBootLoad2 = 0; 874 part->pmBootEntry = 0; 875 part->pmBootEntry2 = 0; 876 part->pmBootCksum = 0; 877 878 /* 879 * Clear out all the NetBSD fields too. We only clear out the ones 880 * that should get reset during our processing. 881 */ 882 bzb = (EBZB *)&part->pmBootArgs[0]; 883 bzb->magic = 0; 884 bzb->cluster = 0; 885 bzb->inode = 0; 886 bzb->type = 0; 887 bzb->flags.root = 0; 888 bzb->flags.usr = 0; 889 bzb->flags.crit = 0; 890 bzb->flags.slice = 0; 891 bzb->flags.used = 0; 892 return; 893 } 894 895 /* 896 * sortmerge: 897 * 1) Moves all the Partition Map entries to the front of the Map. 898 * This is required because some disk formatters leave holes. 899 * 2) Sorts all entries by ascending start block number. 900 * Needed so the NetBSD algorithm for finding partitions works 901 * consistently from a user perspective. 902 * 3) Collapse multiple adjected "free" entries into a single entry. 903 * 4) Identify the NetBSD mount_points. 904 */ 905 void 906 sortmerge(void) 907 { 908 struct apple_part_map_entry tmp_blk; 909 char in_use[MAXPARTITIONS]; 910 int i, j; 911 EBZB *bzb; 912 913 /* 914 * Step 1, squeeze out the holes that some disk formatters leave in 915 * the Map. Also convert any "old" Map entries to the new entry 916 * type. Also clear out our used flag which is used to indicte 917 * we've mapped the partition. 918 */ 919 map.in_use_cnt = 0; 920 for (i=0;i<map.size-1;i++) { 921 if (map.blk[i].pmSig == 0x5453) 922 map.blk[i].pmSig = APPLE_PART_MAP_ENTRY_MAGIC; 923 if (map.blk[i].pmSig != APPLE_PART_MAP_ENTRY_MAGIC) { 924 for (j=i+1;j<map.size;j++) { 925 if (map.blk[j].pmSig == 0x5453) 926 map.blk[j].pmSig = APPLE_PART_MAP_ENTRY_MAGIC; 927 if (map.blk[j].pmSig == APPLE_PART_MAP_ENTRY_MAGIC) { 928 memcpy (&map.blk[i], &map.blk[j], sizeof(map.blk[i])); 929 map.blk[j].pmSig = 0; 930 break; 931 } 932 } 933 } else { 934 map.in_use_cnt += 1; 935 bzb = (EBZB *)&map.blk[i].pmBootArgs[0]; 936 bzb->flags.used = 0; 937 bzb->flags.part = 0; 938 } 939 } 940 941 /* 942 * Step 2, sort by ascending starting block number. Since 943 * we've already removed the holes we only need to 944 * deal with the in_use count of blocks. 945 */ 946 for (i=0;i<map.in_use_cnt-1;i++) { 947 for (j=i+1;j<map.in_use_cnt;j++) { 948 if (map.blk[i].pmPyPartStart > map.blk[j].pmPyPartStart) { 949 memcpy (&tmp_blk, &map.blk[i], sizeof(tmp_blk)); 950 memcpy (&map.blk[i], &map.blk[j], sizeof(map.blk[i])); 951 memcpy (&map.blk[j], &tmp_blk, sizeof(map.blk[j])); 952 } 953 } 954 } 955 956 /* 957 * Step 3, merge adjacent free space 958 */ 959 for (i=0;i<map.in_use_cnt-1;i++) { 960 if (stricmp("Apple_Free", (char *)map.blk[i].pmPartType) == 0 && 961 stricmp("Apple_Free", (char *)map.blk[i+1].pmPartType) == 0) { 962 map.blk[i].pmPartBlkCnt += map.blk[i+1].pmPartBlkCnt; 963 map.blk[i].pmDataCnt += map.blk[i+1].pmDataCnt; 964 map.blk[i+1].pmSig = 0; 965 for (j=i+1;j<map.in_use_cnt-1;j++) { 966 memcpy (&map.blk[j], &map.blk[j+1], sizeof(map.blk[j])); 967 map.blk[j+1].pmSig = 0; 968 } 969 map.in_use_cnt -= 1; 970 } 971 } 972 973 /* 974 * Step 4, try to identify the mount points for the partitions 975 * and adjust the pmMapBlkCnt in each Map entry. Set 976 * up the display array for the non-reserved partitions, 977 * and count the number of NetBSD usable partitions 978 */ 979 map.hfs_cnt = 0; 980 map.root_cnt = 0; 981 map.swap_cnt = 0; 982 map.usr_cnt = 0; 983 map.usable_cnt = 0; 984 /* 985 * Clear out record of partition slots already in use 986 */ 987 memset(&in_use, 0, sizeof(in_use)); 988 for (i=0,j=0;i<map.in_use_cnt;i++) { 989 map.blk[i].pmSig = APPLE_PART_MAP_ENTRY_MAGIC; 990 map.blk[i].pmMapBlkCnt = map.in_use_cnt; 991 /* 992 * Since MAXPARTITIONS == 8 for mac68k, and we do not display 993 * the c partition, we only need 7 partition slots on the screen. 994 * If/when MAXPARTITIONS is changed, the "Edit Disk Partition Map" 995 * needs to be a scrollable view of the partition table. 996 */ 997 if (whichType(&map.blk[i]) && (j < MAXPARTITIONS - 1)) { 998 map.mblk[j++] = i; 999 map.usable_cnt += 1; 1000 } 1001 } 1002 /* 1003 * Fill in standard partitions. Look for a Cluster "0" first and use 1004 * it, otherwise take any Cluster value. 1005 */ 1006 if (findStdType(map.in_use_cnt, in_use, ROOT_PART, &map.root_cnt, 0)) 1007 findStdType(map.in_use_cnt, in_use, ROOT_PART, &map.root_cnt, -1); 1008 if (findStdType(map.in_use_cnt, in_use, UFS_PART, &map.usr_cnt, 0)) 1009 findStdType(map.in_use_cnt, in_use, UFS_PART, &map.usr_cnt, -1); 1010 if (findStdType(map.in_use_cnt, in_use, SWAP_PART, &map.swap_cnt, 0)) 1011 findStdType(map.in_use_cnt, in_use, SWAP_PART, &map.swap_cnt, -1); 1012 1013 #ifdef MD_DEBUG_SORT_MERGE 1014 md_debug_dump("After marking Standard Types"); 1015 #endif 1016 /* 1017 * Now fill in the remaining partitions counting them by type and 1018 * assigning them the slot the where the kernel should map them. 1019 * This will be where they are displayed in the Edit Map. 1020 */ 1021 for (i=0; i < map.in_use_cnt; i++) { 1022 bzb = (EBZB *)&map.blk[i].pmBootArgs[0]; 1023 if (bzb->flags.used == 0) { 1024 if ((j = getFreeLabelEntry(in_use)) < 0) 1025 break; 1026 switch (whichType(&map.blk[i])) { 1027 case ROOT_PART: 1028 map.root_cnt += 1; 1029 setpartition(&map.blk[i], in_use, j); 1030 break; 1031 case UFS_PART: 1032 map.usr_cnt += 1; 1033 setpartition(&map.blk[i], in_use, j); 1034 break; 1035 case SWAP_PART: 1036 map.swap_cnt += 1; 1037 setpartition(&map.blk[i], in_use, j); 1038 break; 1039 case HFS_PART: 1040 map.hfs_cnt += 1; 1041 setpartition(&map.blk[i], in_use, j); 1042 break; 1043 case SCRATCH_PART: 1044 setpartition(&map.blk[i], in_use, j); 1045 default: 1046 break; 1047 } 1048 } 1049 } 1050 #ifdef MD_DEBUG_SORT_MERGE 1051 md_debug_dump("After sort merge"); 1052 #endif 1053 return; 1054 } 1055 1056 void 1057 disp_selected_part(sel) 1058 int sel; 1059 { 1060 int i,j; 1061 char fstyp[16], use[16], name[32]; 1062 EBZB *bzb; 1063 1064 msg_table_add(MSG_mac68k_part_header); 1065 for (i=0;i<map.usable_cnt;i++) { 1066 if (i == sel) msg_standout(); 1067 j = map.mblk[i]; 1068 getFstype(&map.blk[j], sizeof(fstyp), fstyp); 1069 getUse(&map.blk[j], sizeof(use), use); 1070 getName(&map.blk[j], sizeof(name), name); 1071 bzb = (EBZB *)&map.blk[j].pmBootArgs[0]; 1072 msg_fmt_table_add(MSG_part_row, "%s%c%d%d%s%s%s", 1073 pm->diskdev, 1074 bzb->flags.part, map.blk[j].pmPyPartStart, 1075 map.blk[j].pmPartBlkCnt, fstyp, use, name); 1076 if (i == sel) msg_standend(); 1077 } 1078 return; 1079 } 1080 1081 /* 1082 * check for any anomalies on the requested setup 1083 */ 1084 static int 1085 check_for_errors() 1086 { 1087 int i, j; 1088 int errs = 0; 1089 1090 errs = (!map.root_cnt) || (map.root_cnt > 1) || (!map.swap_cnt) || 1091 (map.swap_cnt > 1); 1092 1093 for (i=0;i<map.usable_cnt;i++) { 1094 j = map.mblk[i]; 1095 if (map.blk[j].pmPyPartStart > pm->dlsize) 1096 errs++; 1097 if ((map.blk[j].pmPyPartStart + map.blk[j].pmPartBlkCnt) > pm->dlsize + 1) 1098 errs++; 1099 } 1100 return(errs); 1101 } 1102 1103 /* 1104 * check for and report anomalies on the requested setup 1105 */ 1106 void 1107 report_errors() 1108 { 1109 int i, j; 1110 int errs = 0; 1111 EBZB *bzb; 1112 1113 if (!map.root_cnt) { 1114 msg_display_add(MSG_disksetup_no_root); 1115 errs++; 1116 } 1117 if (map.root_cnt > 1) { 1118 msg_display_add(MSG_disksetup_multiple_roots); 1119 errs++; 1120 } 1121 if (!map.swap_cnt) { 1122 msg_display_add(MSG_disksetup_no_swap); 1123 errs++; 1124 } 1125 if (map.swap_cnt > 1) { 1126 msg_display_add(MSG_disksetup_multiple_swaps); 1127 errs++; 1128 } 1129 for (i=0;i<map.usable_cnt;i++) { 1130 j = map.mblk[i]; 1131 if (map.blk[j].pmPyPartStart > pm->dlsize) { 1132 bzb = (EBZB *)&map.blk[j].pmBootArgs[0]; 1133 msg_fmt_display_add(MSG_disksetup_part_beginning, "%s%c", 1134 pm->diskdev, bzb->flags.part); 1135 errs++; 1136 } 1137 if ((map.blk[j].pmPyPartStart + map.blk[j].pmPartBlkCnt) > pm->dlsize) { 1138 bzb = (EBZB *)&map.blk[j].pmBootArgs[0]; 1139 msg_fmt_display_add(MSG_disksetup_part_size, "%s%c", 1140 pm->diskdev, bzb->flags.part); 1141 errs++; 1142 } 1143 } 1144 if (!errs) 1145 msg_display_add(MSG_disksetup_noerrors); 1146 return; 1147 } 1148 1149 static int 1150 edit_diskmap(void) 1151 { 1152 int i; 1153 1154 /* Ask full/part */ 1155 msg_fmt_display (MSG_mac68k_fullpart, "%s", pm->diskdev); 1156 process_menu (MENU_fullpart, NULL); 1157 1158 map.selected = 0; 1159 sortmerge(); 1160 1161 /* If blowing away the whole disk, let user know if there 1162 * are any active disk partitions */ 1163 if (usefull) { 1164 if (map.usable_cnt > (map.root_cnt+map.swap_cnt+map.usr_cnt)) { 1165 msg_display (MSG_mac68k_ovrwrite); 1166 if (!ask_noyes(NULL)) { 1167 endwin(); 1168 return 0; 1169 } 1170 } 1171 /* 1172 * mark all non-reserved partitions as "free" 1173 * then sort and merge the map into something sensible 1174 */ 1175 for (i=0;i<map.size;i++) 1176 if (whichType(&map.blk[i])) 1177 strcpy ((char *)map.blk[i].pmPartType, "Apple_Free"); 1178 sortmerge(); 1179 } 1180 process_menu (MENU_editparttable, NULL); 1181 return 1; 1182 } 1183 1184 #ifdef MD_DEBUG_SORT_MERGE 1185 static int 1186 md_debug_dump(title) 1187 char *title; 1188 { 1189 char buf[96], type; 1190 char fstyp[16], use[16], name[64]; 1191 int i, j, rv; 1192 EBZB *bzb; 1193 1194 msg_clear(); 1195 sprintf(buf, "Apple Disk Partition Map: %s", title); 1196 msg_fmt_table_add(MSG_dump_line, "%s", buf); 1197 msg_fmt_table_add(MSG_dump_line, "%s", 1198 "slot base fstype use name"); 1199 for (i=0;i<map.in_use_cnt;i++) { 1200 j = whichType(&map.blk[i]); 1201 getFstype(&map.blk[i], sizeof(fstyp), fstyp); 1202 getUse(&map.blk[i], sizeof(use), use); 1203 getName(&map.blk[i], sizeof(name), name); 1204 bzb = (EBZB *) &map.blk[i].pmBootArgs[0]; 1205 type = bzb->flags.part; 1206 if (type < 'a' || type > 'h') type = '?'; 1207 if (j == 0) strcpy (name, "reserved for Apple"); 1208 sprintf(buf, " %02d:%c %08x %8s %10s %s", i+1, type, 1209 map.blk[i].pmPyPartStart, fstyp, use, name); 1210 msg_fmt_table_add(MSG_dump_line, "%s", buf); 1211 } 1212 process_menu(MENU_okabort, &rv); 1213 msg_clear(); 1214 return rv; 1215 } 1216 #endif /* MD_DEBUG_SORT_MERGE */ 1217 1218 int 1219 md_pre_mount(struct install_partition_desc *install, size_t ndx) 1220 { 1221 return 0; 1222 } 1223 1224 bool 1225 md_parts_use_wholedisk(struct disk_partitions *parts) 1226 { 1227 return parts_use_wholedisk(parts, 0, NULL); 1228 } 1229 1230 #ifdef HAVE_GPT 1231 bool 1232 md_gpt_post_write(struct disk_partitions *parts, part_id root_id, 1233 bool root_is_new, part_id efi_id, bool efi_is_new) 1234 { 1235 /* no GPT boot support, nothing needs to be done here */ 1236 return true; 1237 } 1238 #endif 1239 1240