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