1 /* $NetBSD: md.c,v 1.5 2016/05/31 02:49:50 dholland 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 int 135 md_get_info(void) 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_display(MSG_dldebug, blk_size, pm->dlcyl, pm->dlhead, pm->dlsec, pm->dlsize); 207 process_menu(MENU_ok, NULL); 208 #endif 209 map.size = 0; 210 /* 211 * Verify the disk has been initialized for MacOS use by checking 212 * to see if the disk have a Boot Block 213 */ 214 if (lseek(fd, (off_t)0 * blk_size, SEEK_SET) < 0 || 215 read(fd, &block, sizeof(block)) - sizeof(block) != 0 || 216 block.pmSig != 0x4552) { 217 process_menu(MENU_nodiskmap, NULL); 218 } 219 else { 220 /* 221 * Scan for the Partition Map entry that describes the Partition 222 * Map itself. We need to know the number of blocks allocated 223 * to it and the number currently in use. 224 */ 225 for (i=0;i<MAXMAXPARTITIONS;i++) { 226 lseek(fd, (off_t)(i+1) * blk_size, SEEK_SET); 227 read(fd, &block, sizeof(block)); 228 if (stricmp("Apple_partition_map", (char *)block.pmPartType) == 0) { 229 map.size = block.pmPartBlkCnt; 230 map.in_use_cnt = block.pmMapBlkCnt; 231 map.blk = (struct apple_part_map_entry *)malloc(map.size * blk_size); 232 break; 233 } 234 } 235 lseek(fd, (off_t)1 * blk_size, SEEK_SET); 236 read(fd, map.blk, map.size * blk_size); 237 } 238 close(fd); 239 /* 240 * Setup the disktype so /etc/disktab gets proper info 241 */ 242 if (strncmp(pm->diskdev, "sd", 2) == 0) { 243 pm->disktype = "SCSI"; 244 pm->doessf = "sf:"; 245 } else 246 pm->disktype = "IDE"; 247 248 return edit_diskmap(); 249 } 250 251 /* 252 * md back-end code for menu-driven BSD disklabel editor. 253 */ 254 int 255 md_make_bsd_partitions(void) 256 { 257 FILE *f; 258 int i, j, pl, rv; 259 EBZB *bzb; 260 261 /* 262 * Scan for any problems and report them before continuing. 263 * The user can abort installation and we'll take them back 264 * to the main menu; continue ignoring the warnings, or 265 * ask to reedit the Disk Partition Map. 266 */ 267 while (1) { 268 if (check_for_errors()) { 269 process_menu (MENU_sanity, &rv); 270 if (rv < 0) 271 return 0; 272 else if (rv) 273 break; 274 edit_diskmap(); 275 } else 276 break; 277 } 278 279 /* Build standard partitions */ 280 memset(&pm->bsdlabel, 0, sizeof pm->bsdlabel); 281 282 /* 283 * The mac68k port has a predefined partition for "c" which 284 * is the size of the disk, everything else is unused. 285 */ 286 pm->bsdlabel[RAW_PART].pi_size = pm->dlsize; 287 /* 288 * Now, scan through the Disk Partition Map and transfer the 289 * information into the incore disklabel. 290 */ 291 for (i=0;i<map.usable_cnt;i++) { 292 j = map.mblk[i]; 293 bzb = (EBZB *)&map.blk[j].pmBootArgs[0]; 294 if (bzb->flags.part) { 295 pl = bzb->flags.part - 'a'; 296 switch (whichType(&map.blk[j])) { 297 case HFS_PART: 298 pm->bsdlabel[pl].pi_fstype = FS_HFS; 299 strcpy (pm->bsdlabel[pl].pi_mount, (char *)bzb->mount_point); 300 break; 301 case ROOT_PART: 302 case UFS_PART: 303 pm->bsdlabel[pl].pi_fstype = FS_BSDFFS; 304 strcpy (pm->bsdlabel[pl].pi_mount, (char *)bzb->mount_point); 305 pm->bsdlabel[pl].pi_flags |= PIF_NEWFS | PIF_MOUNT; 306 break; 307 case SWAP_PART: 308 pm->bsdlabel[pl].pi_fstype = FS_SWAP; 309 break; 310 case SCRATCH_PART: 311 pm->bsdlabel[pl].pi_fstype = FS_OTHER; 312 strcpy (pm->bsdlabel[pl].pi_mount, (char *)bzb->mount_point); 313 default: 314 break; 315 } 316 if (pm->bsdlabel[pl].pi_fstype != FS_UNUSED) { 317 pm->bsdlabel[pl].pi_size = map.blk[j].pmPartBlkCnt; 318 pm->bsdlabel[pl].pi_offset = map.blk[j].pmPyPartStart; 319 if (pm->bsdlabel[pl].pi_fstype != FS_SWAP) { 320 pm->bsdlabel[pl].pi_frag = 8; 321 pm->bsdlabel[pl].pi_fsize = 1024; 322 } 323 } 324 } 325 } 326 327 /* Disk name - don't bother asking, just use the physical name*/ 328 strcpy (pm->bsddiskname, pm->diskdev); 329 330 #ifdef DEBUG 331 f = fopen ("/tmp/disktab", "w"); 332 #else 333 f = fopen ("/etc/disktab", "w"); 334 #endif 335 if (f == NULL) { 336 endwin(); 337 (void) fprintf (stderr, "Could not open /etc/disktab"); 338 exit (1); 339 } 340 (void)fprintf (f, "%s|NetBSD installation generated:\\\n", pm->bsddiskname); 341 (void)fprintf (f, "\t:dt=%s:ty=winchester:\\\n", pm->disktype); 342 (void)fprintf (f, "\t:nc#%d:nt#%d:ns#%d:\\\n", pm->dlcyl, pm->dlhead, pm->dlsec); 343 (void)fprintf (f, "\t:sc#%d:su#%" PRIu32 ":\\\n", pm->dlhead*pm->dlsec, (uint32_t)pm->dlsize); 344 (void)fprintf (f, "\t:se#%d:%s\\\n", blk_size, pm->doessf); 345 for (i=0; i<8; i++) { 346 if (pm->bsdlabel[i].pi_fstype == FS_HFS) 347 (void)fprintf (f, "\t:p%c#%d:o%c#%d:t%c=macos:", 348 'a'+i, pm->bsdlabel[i].pi_size, 349 'a'+i, pm->bsdlabel[i].pi_offset, 350 'a'+i); 351 else 352 (void)fprintf (f, "\t:p%c#%d:o%c#%d:t%c=%s:", 353 'a'+i, pm->bsdlabel[i].pi_size, 354 'a'+i, pm->bsdlabel[i].pi_offset, 355 'a'+i, getfslabelname(pm->bsdlabel[i].pi_fstype)); 356 if (pm->bsdlabel[i].pi_fstype == FS_BSDFFS) 357 (void)fprintf (f, "b%c#%d:f%c#%d", 358 'a'+i, pm->bsdlabel[i].pi_fsize * pm->bsdlabel[i].pi_frag, 359 'a'+i, pm->bsdlabel[i].pi_fsize); 360 if (i < 7) 361 (void)fprintf (f, "\\\n"); 362 else 363 (void)fprintf (f, "\n"); 364 } 365 fclose (f); 366 367 /* Everything looks OK. */ 368 return 1; 369 } 370 371 /* 372 * any additional partition validation 373 */ 374 int 375 md_check_partitions(void) 376 { 377 return 1; 378 } 379 380 /* 381 * hook called before writing new disklabel. 382 */ 383 int 384 md_pre_disklabel(void) 385 { 386 int fd; 387 char dev_name[100]; 388 struct disklabel lp; 389 Block0 new_block0 = {APPLE_DRVR_MAP_MAGIC, 512, 390 0, 0, 0, 0, 0, 0, 0, 0, {0}}; 391 392 /* 393 * Danger Will Robinson! We're about to turn that nice MacOS disk 394 * into an expensive doorstop... 395 */ 396 printf ("%s", msg_string (MSG_dodiskmap)); 397 398 snprintf (dev_name, sizeof(dev_name), "/dev/r%sc", pm->diskdev); 399 /* 400 * Open the disk as a raw device 401 */ 402 if ((fd = open(dev_name, O_WRONLY, 0)) < 0) { 403 endwin(); 404 fprintf(stderr, "Can't open %s to rewrite the Disk Map\n", dev_name); 405 exit (1); 406 } 407 /* 408 * First check the pmSigPad field of the first block in the incore 409 * Partition Map. It should be zero, but if it's 0xa5a5 that means 410 * we need to write out Block0 too. 411 */ 412 if (map.blk[0].pmSigPad == 0xa5a5) { 413 if (lseek (fd, (off_t)0 * blk_size, SEEK_SET) < 0) { 414 endwin(); 415 fprintf (stderr, "Can't position to write Block0\n"); 416 close (fd); 417 exit (1); 418 } 419 new_block0.sbBlkCount = pm->dlsize; /* Set disk size */ 420 if (write (fd, &new_block0, blk_size) != blk_size) { 421 endwin(); 422 fprintf (stderr, "I/O error writing Block0\n"); 423 close (fd); 424 exit (1); 425 } 426 map.blk[0].pmSigPad = 0; 427 } 428 if (lseek (fd, (off_t)1 * blk_size, SEEK_SET) < 0) { 429 endwin(); 430 fprintf (stderr, "Can't position disk to rewrite Disk Map\n"); 431 close (fd); 432 exit (1); 433 } 434 if (write (fd, map.blk, map.size * blk_size) != (map.size * blk_size)) { 435 endwin(); 436 fprintf(stderr, "I/O error writing Disk Map\n"); 437 close (fd); 438 exit (1); 439 } 440 fsync(fd); 441 /* 442 * Well, if we get here the dirty deed has been done. 443 * 444 * Now we need to force the incore disk table to get updated. This 445 * should be done by disklabel -- which is normally called right after 446 * we return -- but may be commented out for the mac68k port. We'll 447 * instead update the incore table by forcing a dummy write here. This 448 * relies on a change in the mac68k-specific write_disklabel() routine. 449 * If that change doesn't exist nothing bad happens here. If disklabel 450 * properly updates the ondisk and incore labels everything still 451 * works. Only if we fail here and if disklabel fails are we in 452 * in a state where we've updated the disk but not the incore and 453 * a reboot is necessary. 454 * 455 * First, we grab a copy of the incore label as it existed before 456 * we did anything to it. Then we invoke the "write label" ioctl to 457 * rewrite it to disk. As a result, the ondisk partition map is 458 * re-read and the incore label is reconstructed from it. If 459 * disklabel() is then called to update again, either that fails 460 * because the mac68k port doesn't support native disklabels, or it 461 * succeeds and writes out a new ondisk copy. 462 */ 463 ioctl(fd, DIOCGDINFO, &lp); /* Get the current disk label */ 464 ioctl(fd, DIOCWDINFO, &lp); /* Write it out again */ 465 466 close (fd); 467 return 0; 468 } 469 470 /* 471 * hook called after writing disklabel to new target disk. 472 */ 473 int 474 md_post_disklabel(void) 475 { 476 struct disklabel updated_label; 477 int fd, i, no_match; 478 char dev_name[100], buf[80]; 479 const char *fst[] = {"free", "swap", " v6 ", " v7 ", "sysv", "v71k", 480 " v8 ", "ffs ", "dos ", "lfs ", "othr", "hpfs", 481 "9660", "boot", "ados", "hfs ", "fcor", "ex2f", 482 "ntfs", "raid", "ccd "}; 483 484 snprintf(dev_name, sizeof(dev_name), "/dev/r%sc", pm->diskdev); 485 /* 486 * Open the disk as a raw device 487 */ 488 if ((fd = open(dev_name, O_RDONLY, 0)) < 0) 489 return 0; 490 /* 491 * Get the "new" label to see if we were successful. If we aren't 492 * we'll return an error to keep from destroying the user's disk. 493 */ 494 ioctl(fd, DIOCGDINFO, &updated_label); 495 close(fd); 496 /* 497 * Make sure the in-core label matches the on-disk one 498 */ 499 no_match = 0; 500 for (i=0;i<MAXPARTITIONS;i++) { 501 if (i > updated_label.d_npartitions) 502 break; 503 if (pm->bsdlabel[i].pi_size != updated_label.d_partitions[i].p_size) 504 no_match = 1; 505 if (pm->bsdlabel[i].pi_size) { 506 if (pm->bsdlabel[i].pi_offset != updated_label.d_partitions[i].p_offset) 507 no_match = 1; 508 if (pm->bsdlabel[i].pi_fstype != updated_label.d_partitions[i].p_fstype) 509 no_match = 1; 510 } 511 if (no_match) 512 break; 513 } 514 /* 515 * If the labels don't match, tell the user why 516 */ 517 if (no_match) { 518 msg_clear(); 519 msg_display(MSG_label_error); 520 msg_table_add(MSG_dump_line, 521 " in-core: offset size type on-disk: offset size type"); 522 for (i=0;i<MAXPARTITIONS;i++) { 523 sprintf(buf, " %c:%13.8x%10.8x%5s%16.8x%10.8x%5s", i+'a', 524 pm->bsdlabel[i].pi_offset, pm->bsdlabel[i].pi_size, 525 fst[pm->bsdlabel[i].pi_fstype], 526 updated_label.d_partitions[i].p_offset, 527 updated_label.d_partitions[i].p_size, 528 fst[updated_label.d_partitions[i].p_fstype]); 529 msg_table_add(MSG_dump_line, buf); 530 } 531 process_menu(MENU_ok2, NULL); 532 } 533 return no_match; 534 } 535 536 /* 537 * hook called after upgrade() or install() has finished setting 538 * up the target disk but immediately before the user is given the 539 * ``disks are now set up'' message. 540 */ 541 int 542 md_post_newfs(void) 543 { 544 return 0; 545 } 546 547 int 548 md_post_extract(void) 549 { 550 return 0; 551 } 552 553 void 554 md_cleanup_install(void) 555 { 556 #ifndef DEBUG 557 enable_rc_conf(); 558 #endif 559 } 560 561 int 562 md_pre_update(void) 563 { 564 return 1; 565 } 566 567 /* Upgrade support */ 568 int 569 md_update(void) 570 { 571 md_post_newfs(); 572 return 1; 573 } 574 575 /* 576 * Compare lexigraphically two strings 577 */ 578 static int 579 stricmp(s1, s2) 580 const char *s1; 581 const char *s2; 582 { 583 char c1, c2; 584 585 while (1) { 586 c1 = tolower((unsigned char)*s1++); 587 c2 = tolower((unsigned char)*s2++); 588 if (c1 < c2) return -1; 589 if (c1 > c2) return 1; 590 if (c1 == 0) return 0; 591 } 592 } 593 594 static void 595 setpartition(part, in_use, slot) 596 struct apple_part_map_entry *part; 597 char in_use[]; 598 int slot; 599 { 600 EBZB *bzb; 601 602 bzb = (EBZB *)&part->pmBootArgs[0]; 603 in_use[slot] = 1; 604 bzb->flags.used = 1; 605 bzb->flags.part = 'a' + slot; 606 } 607 608 /* 609 * Find an entry in a use array that is unused and return it or 610 * -1 if no entry is available 611 */ 612 static int 613 getFreeLabelEntry(slots) 614 char *slots; 615 { 616 int i; 617 618 for ( i = 0; i < MAXPARTITIONS; i++) { 619 if (i != RAW_PART && slots[i] == 0) 620 return i; 621 } 622 return -1; 623 } 624 625 /* 626 * Figure out what type type of the given partition is and return it. 627 */ 628 int 629 whichType(part) 630 struct apple_part_map_entry *part; 631 { 632 MAP_TYPE *map_entry = (MAP_TYPE *)&map_types; 633 EBZB *bzb; 634 char partyp[32]; 635 int type, maxsiz, entry_type = MAP_OTHER; 636 637 bzb = (EBZB *)&part->pmBootArgs[0]; 638 if (part->pmSig != APPLE_PART_MAP_ENTRY_MAGIC) 639 return 0; 640 maxsiz = sizeof(part->pmPartType); 641 if (maxsiz > (int)sizeof(partyp)) 642 maxsiz = sizeof(partyp); 643 strncpy(partyp, (char *)part->pmPartType, maxsiz); 644 partyp[maxsiz-1] = '\0'; 645 646 /* 647 * Find out how to treat the partition type under NetBSD 648 */ 649 while (map_entry->type != MAP_EOL) { 650 if (stricmp(map_entry->name, partyp) == 0) { 651 entry_type = map_entry->type; 652 break; 653 } 654 map_entry++; 655 } 656 657 /* 658 * Now classify the use for NetBSD 659 */ 660 if (entry_type == MAP_RESERVED) 661 type = 0; 662 else if (entry_type == MAP_NETBSD) { 663 if (bzb->magic != APPLE_BZB_MAGIC) 664 type = 0; 665 else if (bzb->type == APPLE_BZB_TYPEFS) { 666 if (bzb->flags.root) 667 type = ROOT_PART; 668 else if (bzb->flags.usr) 669 type = UFS_PART; 670 else 671 type = SCRATCH_PART; 672 } else if (bzb->type == APPLE_BZB_TYPESWAP) 673 type = SWAP_PART; 674 else 675 type = SCRATCH_PART; 676 } else if (entry_type == MAP_MACOS) 677 type = HFS_PART; 678 else 679 type = SCRATCH_PART; 680 return type; 681 } 682 683 static char * 684 getFstype(part, len_type, type) 685 struct apple_part_map_entry *part; 686 int len_type; 687 char *type; 688 { 689 *type = '\0'; 690 switch(whichType(part)) { 691 case ROOT_PART: 692 case UFS_PART: 693 strncpy(type, "4.2BSD", len_type); 694 break; 695 case SWAP_PART: 696 strncpy(type, "swap", len_type); 697 break; 698 case HFS_PART: 699 strncpy(type, "HFS", len_type); 700 break; 701 case SCRATCH_PART: 702 default: 703 break; 704 } 705 return (type); 706 } 707 708 static char * 709 getUse(part, len_use, use) 710 struct apple_part_map_entry *part; 711 int len_use; 712 char *use; 713 { 714 EBZB *bzb; 715 char partyp[32]; 716 717 *use = '\0'; 718 bzb = (EBZB *)&part->pmBootArgs[0]; 719 switch(whichType(part)) { 720 case ROOT_PART: 721 if (bzb->flags.usr) 722 strncpy(use, "Root&Usr", len_use); 723 else 724 strncpy(use, "Root", len_use); 725 break; 726 case UFS_PART: 727 strncpy(use, "Usr", len_use); 728 break; 729 case SWAP_PART: 730 break; 731 case HFS_PART: 732 strncpy(use, "MacOS", len_use); 733 break; 734 case SCRATCH_PART: 735 strncpy(partyp, (char *)part->pmPartType, sizeof(partyp)); 736 partyp[sizeof(partyp)-1] = '\0'; 737 if (stricmp("Apple_Free", partyp) == 0) 738 strncpy(use, "Free", len_use); 739 else if (stricmp("Apple_Scratch", partyp) == 0) 740 strncpy(use, "Scratch", len_use); 741 else if (stricmp("Apple_MFS", partyp) == 0) 742 strncpy(use, "MFS", len_use); 743 else if (stricmp("Apple_PRODOS", partyp) == 0) 744 strncpy(use, "PRODOS", len_use); 745 else 746 strncpy(use, "unknown", len_use); 747 default: 748 break; 749 } 750 return(use); 751 } 752 753 static char * 754 getName(part, len_name, name) 755 struct apple_part_map_entry *part; 756 int len_name; 757 char *name; 758 { 759 EBZB *bzb; 760 int fd; 761 off_t seek; 762 char dev_name[100], macosblk[512]; 763 764 *name = '\0'; 765 bzb = (EBZB *)&part->pmBootArgs[0]; 766 switch(whichType(part)) { 767 case SCRATCH_PART: 768 case ROOT_PART: 769 case UFS_PART: 770 strncpy(name, (char *)bzb->mount_point, len_name); 771 break; 772 case SWAP_PART: 773 break; 774 case HFS_PART: 775 /* 776 * OK, this is stupid but it's damn nice to know! 777 */ 778 snprintf (dev_name, sizeof(dev_name), "/dev/r%sc", pm->diskdev); 779 /* 780 * Open the disk as a raw device 781 */ 782 if ((fd = open(dev_name, O_RDONLY, 0)) >= 0) { 783 seek = (off_t)part->pmPyPartStart + (off_t)2; 784 seek *= (off_t)blk_size; 785 lseek(fd, seek, SEEK_SET); 786 read(fd, &macosblk, sizeof(macosblk)); 787 macosblk[37+32] = '\0'; 788 strncpy(name, (char *)bzb->mount_point, len_name); 789 strncat(name, " (", len_name-strlen(name)); 790 strncat(name, &macosblk[37], len_name-strlen(name)); 791 strncat(name, ")", len_name-strlen(name)); 792 close(fd); 793 } 794 break; 795 default: 796 break; 797 } 798 return(name); 799 } 800 801 /* 802 * Find the first occurance of a Standard Type partition and 803 * mark it for use along with the default mount slot. 804 */ 805 static int 806 findStdType(num_parts, in_use, type, count, alt) 807 int num_parts; 808 char in_use[]; 809 int type; 810 int *count; 811 int alt; 812 { 813 EBZB *bzb; 814 int i; 815 816 for (i = 0; i < num_parts; i++) { 817 bzb = (EBZB *)&map.blk[i].pmBootArgs[0]; 818 if (whichType(&map.blk[i]) != type || bzb->flags.used) 819 continue; 820 if (type == ROOT_PART) { 821 if (alt >= 0 && alt != bzb->cluster) 822 continue; 823 setpartition(&map.blk[i], in_use, 0); 824 strcpy ((char *)bzb->mount_point, "/"); 825 *count += 1; 826 } else if (type == UFS_PART) { 827 if (alt >= 0 && alt != bzb->cluster) 828 continue; 829 setpartition(&map.blk[i], in_use, 6); 830 if (bzb->mount_point[0] == '\0') 831 strcpy ((char *)bzb->mount_point, "/usr"); 832 *count += 1; 833 } else if (type == SWAP_PART) { 834 setpartition(&map.blk[i], in_use, 1); 835 *count += 1; 836 } 837 return 0; 838 } 839 return -1; 840 } 841 842 /* 843 * Reset the flags and reserved fields in the selected partition. 844 * This functions isn't called to process any of the reserved partitions 845 * where the boot code for MacOS is stored, so (hopefully) we won't 846 * do more damage that we're trying to avoid. Eventually the NetBSD 847 * Boot Code will need to go into a partition too, but that should go 848 * into a reserved partition as well. I'd suggest using a partition 849 * named something like "NetBSD_Boot" with a pmPartName of "Macintosh". 850 * The Apple Start Manager (in ROM) will then recognize the partition 851 * as the one containing the system bootstrip for the volume. 852 */ 853 void 854 reset_part_flags(part) 855 struct apple_part_map_entry *part; 856 { 857 EBZB *bzb; 858 859 /* 860 * Clear out the MacOS fields that might be used for booting just 861 * in case we've clobbered the boot code. 862 */ 863 part->pmLgDataStart = 0; 864 part->pmPartStatus = 0x77; /* make sure the partition shows up */ 865 part->pmLgBootStart = 0; 866 part->pmBootSize = 0; 867 part->pmBootLoad = 0; 868 part->pmBootLoad2 = 0; 869 part->pmBootEntry = 0; 870 part->pmBootEntry2 = 0; 871 part->pmBootCksum = 0; 872 873 /* 874 * Clear out all the NetBSD fields too. We only clear out the ones 875 * that should get reset during our processing. 876 */ 877 bzb = (EBZB *)&part->pmBootArgs[0]; 878 bzb->magic = 0; 879 bzb->cluster = 0; 880 bzb->inode = 0; 881 bzb->type = 0; 882 bzb->flags.root = 0; 883 bzb->flags.usr = 0; 884 bzb->flags.crit = 0; 885 bzb->flags.slice = 0; 886 bzb->flags.used = 0; 887 return; 888 } 889 890 /* 891 * sortmerge: 892 * 1) Moves all the Partition Map entries to the front of the Map. 893 * This is required because some disk formatters leave holes. 894 * 2) Sorts all entries by ascending start block number. 895 * Needed so the NetBSD algorithm for finding partitions works 896 * consistently from a user perspective. 897 * 3) Collapse multiple adjected "free" entries into a single entry. 898 * 4) Identify the NetBSD mount_points. 899 */ 900 void 901 sortmerge(void) 902 { 903 struct apple_part_map_entry tmp_blk; 904 char in_use[MAXPARTITIONS]; 905 int i, j; 906 EBZB *bzb; 907 908 /* 909 * Step 1, squeeze out the holes that some disk formatters leave in 910 * the Map. Also convert any "old" Map entries to the new entry 911 * type. Also clear out our used flag which is used to indicte 912 * we've mapped the partition. 913 */ 914 map.in_use_cnt = 0; 915 for (i=0;i<map.size-1;i++) { 916 if (map.blk[i].pmSig == 0x5453) 917 map.blk[i].pmSig = APPLE_PART_MAP_ENTRY_MAGIC; 918 if (map.blk[i].pmSig != APPLE_PART_MAP_ENTRY_MAGIC) { 919 for (j=i+1;j<map.size;j++) { 920 if (map.blk[j].pmSig == 0x5453) 921 map.blk[j].pmSig = APPLE_PART_MAP_ENTRY_MAGIC; 922 if (map.blk[j].pmSig == APPLE_PART_MAP_ENTRY_MAGIC) { 923 memcpy (&map.blk[i], &map.blk[j], sizeof(map.blk[i])); 924 map.blk[j].pmSig = 0; 925 break; 926 } 927 } 928 } else { 929 map.in_use_cnt += 1; 930 bzb = (EBZB *)&map.blk[i].pmBootArgs[0]; 931 bzb->flags.used = 0; 932 bzb->flags.part = 0; 933 } 934 } 935 936 /* 937 * Step 2, sort by ascending starting block number. Since 938 * we've already removed the holes we only need to 939 * deal with the in_use count of blocks. 940 */ 941 for (i=0;i<map.in_use_cnt-1;i++) { 942 for (j=i+1;j<map.in_use_cnt;j++) { 943 if (map.blk[i].pmPyPartStart > map.blk[j].pmPyPartStart) { 944 memcpy (&tmp_blk, &map.blk[i], sizeof(tmp_blk)); 945 memcpy (&map.blk[i], &map.blk[j], sizeof(map.blk[i])); 946 memcpy (&map.blk[j], &tmp_blk, sizeof(map.blk[j])); 947 } 948 } 949 } 950 951 /* 952 * Step 3, merge adjacent free space 953 */ 954 for (i=0;i<map.in_use_cnt-1;i++) { 955 if (stricmp("Apple_Free", (char *)map.blk[i].pmPartType) == 0 && 956 stricmp("Apple_Free", (char *)map.blk[i+1].pmPartType) == 0) { 957 map.blk[i].pmPartBlkCnt += map.blk[i+1].pmPartBlkCnt; 958 map.blk[i].pmDataCnt += map.blk[i+1].pmDataCnt; 959 map.blk[i+1].pmSig = 0; 960 for (j=i+1;j<map.in_use_cnt-1;j++) { 961 memcpy (&map.blk[j], &map.blk[j+1], sizeof(map.blk[j])); 962 map.blk[j+1].pmSig = 0; 963 } 964 map.in_use_cnt -= 1; 965 } 966 } 967 968 /* 969 * Step 4, try to identify the mount points for the partitions 970 * and adjust the pmMapBlkCnt in each Map entry. Set 971 * up the display array for the non-reserved partitions, 972 * and count the number of NetBSD usable partitions 973 */ 974 map.hfs_cnt = 0; 975 map.root_cnt = 0; 976 map.swap_cnt = 0; 977 map.usr_cnt = 0; 978 map.usable_cnt = 0; 979 /* 980 * Clear out record of partition slots already in use 981 */ 982 memset(&in_use, 0, sizeof(in_use)); 983 for (i=0,j=0;i<map.in_use_cnt;i++) { 984 map.blk[i].pmSig = APPLE_PART_MAP_ENTRY_MAGIC; 985 map.blk[i].pmMapBlkCnt = map.in_use_cnt; 986 /* 987 * Since MAXPARTITIONS == 8 for mac68k, and we do not display 988 * the c partition, we only need 7 partition slots on the screen. 989 * If/when MAXPARTITIONS is changed, the "Edit Disk Partition Map" 990 * needs to be a scrollable view of the partition table. 991 */ 992 if (whichType(&map.blk[i]) && (j < MAXPARTITIONS - 1)) { 993 map.mblk[j++] = i; 994 map.usable_cnt += 1; 995 } 996 } 997 /* 998 * Fill in standard partitions. Look for a Cluster "0" first and use 999 * it, otherwise take any Cluster value. 1000 */ 1001 if (findStdType(map.in_use_cnt, in_use, ROOT_PART, &map.root_cnt, 0)) 1002 findStdType(map.in_use_cnt, in_use, ROOT_PART, &map.root_cnt, -1); 1003 if (findStdType(map.in_use_cnt, in_use, UFS_PART, &map.usr_cnt, 0)) 1004 findStdType(map.in_use_cnt, in_use, UFS_PART, &map.usr_cnt, -1); 1005 if (findStdType(map.in_use_cnt, in_use, SWAP_PART, &map.swap_cnt, 0)) 1006 findStdType(map.in_use_cnt, in_use, SWAP_PART, &map.swap_cnt, -1); 1007 1008 #ifdef MD_DEBUG_SORT_MERGE 1009 md_debug_dump("After marking Standard Types"); 1010 #endif 1011 /* 1012 * Now fill in the remaining partitions counting them by type and 1013 * assigning them the slot the where the kernel should map them. 1014 * This will be where they are displayed in the Edit Map. 1015 */ 1016 for (i=0; i < map.in_use_cnt; i++) { 1017 bzb = (EBZB *)&map.blk[i].pmBootArgs[0]; 1018 if (bzb->flags.used == 0) { 1019 if ((j = getFreeLabelEntry(in_use)) < 0) 1020 break; 1021 switch (whichType(&map.blk[i])) { 1022 case ROOT_PART: 1023 map.root_cnt += 1; 1024 setpartition(&map.blk[i], in_use, j); 1025 break; 1026 case UFS_PART: 1027 map.usr_cnt += 1; 1028 setpartition(&map.blk[i], in_use, j); 1029 break; 1030 case SWAP_PART: 1031 map.swap_cnt += 1; 1032 setpartition(&map.blk[i], in_use, j); 1033 break; 1034 case HFS_PART: 1035 map.hfs_cnt += 1; 1036 setpartition(&map.blk[i], in_use, j); 1037 break; 1038 case SCRATCH_PART: 1039 setpartition(&map.blk[i], in_use, j); 1040 default: 1041 break; 1042 } 1043 } 1044 } 1045 #ifdef MD_DEBUG_SORT_MERGE 1046 md_debug_dump("After sort merge"); 1047 #endif 1048 return; 1049 } 1050 1051 void 1052 disp_selected_part(sel) 1053 int sel; 1054 { 1055 int i,j; 1056 char fstyp[16], use[16], name[32]; 1057 EBZB *bzb; 1058 1059 msg_table_add(MSG_part_header); 1060 for (i=0;i<map.usable_cnt;i++) { 1061 if (i == sel) msg_standout(); 1062 j = map.mblk[i]; 1063 getFstype(&map.blk[j], sizeof(fstyp), fstyp); 1064 getUse(&map.blk[j], sizeof(use), use); 1065 getName(&map.blk[j], sizeof(name), name); 1066 bzb = (EBZB *)&map.blk[j].pmBootArgs[0]; 1067 msg_table_add(MSG_part_row, pm->diskdev, 1068 bzb->flags.part, map.blk[j].pmPyPartStart, 1069 map.blk[j].pmPartBlkCnt, fstyp, use, name); 1070 if (i == sel) msg_standend(); 1071 } 1072 return; 1073 } 1074 1075 /* 1076 * check for any anomalies on the requested setup 1077 */ 1078 static int 1079 check_for_errors() 1080 { 1081 int i, j; 1082 int errs = 0; 1083 1084 errs = (!map.root_cnt) || (map.root_cnt > 1) || (!map.swap_cnt) || 1085 (map.swap_cnt > 1); 1086 1087 for (i=0;i<map.usable_cnt;i++) { 1088 j = map.mblk[i]; 1089 if (map.blk[j].pmPyPartStart > pm->dlsize) 1090 errs++; 1091 if ((map.blk[j].pmPyPartStart + map.blk[j].pmPartBlkCnt) > pm->dlsize + 1) 1092 errs++; 1093 } 1094 return(errs); 1095 } 1096 1097 /* 1098 * check for and report anomalies on the requested setup 1099 */ 1100 void 1101 report_errors() 1102 { 1103 int i, j; 1104 int errs = 0; 1105 EBZB *bzb; 1106 1107 if (!map.root_cnt) { 1108 msg_display_add(MSG_disksetup_no_root); 1109 errs++; 1110 } 1111 if (map.root_cnt > 1) { 1112 msg_display_add(MSG_disksetup_multiple_roots); 1113 errs++; 1114 } 1115 if (!map.swap_cnt) { 1116 msg_display_add(MSG_disksetup_no_swap); 1117 errs++; 1118 } 1119 if (map.swap_cnt > 1) { 1120 msg_display_add(MSG_disksetup_multiple_swaps); 1121 errs++; 1122 } 1123 for (i=0;i<map.usable_cnt;i++) { 1124 j = map.mblk[i]; 1125 if (map.blk[j].pmPyPartStart > pm->dlsize) { 1126 bzb = (EBZB *)&map.blk[j].pmBootArgs[0]; 1127 msg_display_add(MSG_disksetup_part_beginning, 1128 pm->diskdev, bzb->flags.part); 1129 errs++; 1130 } 1131 if ((map.blk[j].pmPyPartStart + map.blk[j].pmPartBlkCnt) > pm->dlsize) { 1132 bzb = (EBZB *)&map.blk[j].pmBootArgs[0]; 1133 msg_display_add(MSG_disksetup_part_size, 1134 pm->diskdev, bzb->flags.part); 1135 errs++; 1136 } 1137 } 1138 if (!errs) 1139 msg_display_add(MSG_disksetup_noerrors); 1140 return; 1141 } 1142 1143 static int 1144 edit_diskmap(void) 1145 { 1146 int i; 1147 1148 /* Ask full/part */ 1149 msg_display (MSG_fullpart, pm->diskdev); 1150 process_menu (MENU_fullpart, NULL); 1151 1152 map.selected = 0; 1153 sortmerge(); 1154 1155 /* If blowing away the whole disk, let user know if there 1156 * are any active disk partitions */ 1157 if (usefull) { 1158 if (map.usable_cnt > (map.root_cnt+map.swap_cnt+map.usr_cnt)) { 1159 msg_display (MSG_ovrwrite); 1160 if (!ask_noyes(NULL)) { 1161 endwin(); 1162 return 0; 1163 } 1164 } 1165 /* 1166 * mark all non-reserved partitions as "free" 1167 * then sort and merge the map into something sensible 1168 */ 1169 for (i=0;i<map.size;i++) 1170 if (whichType(&map.blk[i])) 1171 strcpy ((char *)map.blk[i].pmPartType, "Apple_Free"); 1172 sortmerge(); 1173 } 1174 process_menu (MENU_editparttable, NULL); 1175 return 1; 1176 } 1177 1178 #ifdef MD_DEBUG_SORT_MERGE 1179 static int 1180 md_debug_dump(title) 1181 char *title; 1182 { 1183 char buf[96], type; 1184 char fstyp[16], use[16], name[64]; 1185 int i, j, rv; 1186 EBZB *bzb; 1187 1188 msg_clear(); 1189 sprintf(buf, "Apple Disk Partition Map: %s", title); 1190 msg_table_add(MSG_dump_line, buf); 1191 msg_table_add(MSG_dump_line, 1192 "slot base fstype use name"); 1193 for (i=0;i<map.in_use_cnt;i++) { 1194 j = whichType(&map.blk[i]); 1195 getFstype(&map.blk[i], sizeof(fstyp), fstyp); 1196 getUse(&map.blk[i], sizeof(use), use); 1197 getName(&map.blk[i], sizeof(name), name); 1198 bzb = (EBZB *) &map.blk[i].pmBootArgs[0]; 1199 type = bzb->flags.part; 1200 if (type < 'a' || type > 'h') type = '?'; 1201 if (j == 0) strcpy (name, "reserved for Apple"); 1202 sprintf(buf, " %02d:%c %08x %8s %10s %s", i+1, type, 1203 map.blk[i].pmPyPartStart, fstyp, use, name); 1204 msg_table_add(MSG_dump_line, buf); 1205 } 1206 process_menu(MENU_okabort, &rv); 1207 msg_clear(); 1208 return rv; 1209 } 1210 #endif /* MD_DEBUG_SORT_MERGE */ 1211 1212 int 1213 md_pre_mount() 1214 { 1215 return 0; 1216 } 1217