disk.c revision 105821
1/* 2 * ---------------------------------------------------------------------------- 3 * "THE BEER-WARE LICENSE" (Revision 42): 4 * <phk@FreeBSD.org> wrote this file. As long as you retain this notice you 5 * can do whatever you want with this stuff. If we meet some day, and you think 6 * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp 7 * ---------------------------------------------------------------------------- 8 */ 9 10#include <sys/cdefs.h> 11__FBSDID("$FreeBSD: head/lib/libdisk/disk.c 105821 2002-10-23 21:05:42Z phk $"); 12 13#include <stdio.h> 14#include <stdlib.h> 15#include <unistd.h> 16#include <fcntl.h> 17#include <string.h> 18#include <err.h> 19#include <sys/sysctl.h> 20#include <sys/types.h> 21#include <sys/stat.h> 22#include <sys/ioctl.h> 23#include <sys/disklabel.h> 24#include <sys/diskslice.h> 25#ifndef PC98 26#include <sys/diskmbr.h> 27#endif 28#include <paths.h> 29#include "libdisk.h" 30 31#ifndef PC98 32#define HAVE_GEOM 33#endif 34#include <ctype.h> 35#include <errno.h> 36#include <assert.h> 37 38#ifndef PC98 39#define DOSPTYP_EXTENDED 5 40#endif 41 42#ifdef DEBUG 43#define DPRINT(x) warn x 44#define DPRINTX(x) warnx x 45#else 46#define DPRINT(x) 47#define DPRINTX(x) 48#endif 49 50const char *chunk_n[] = { 51 "whole", 52 "unknown", 53 "fat", 54 "freebsd", 55 "extended", 56 "part", 57 "unused", 58 NULL 59}; 60 61struct disk * 62Open_Disk(const char *name) 63{ 64 return Int_Open_Disk(name, 0); 65} 66 67#ifndef PC98 68static u_int32_t 69Read_Int32(u_int32_t *p) 70{ 71 u_int8_t *bp = (u_int8_t *)p; 72 return bp[0] | (bp[1] << 8) | (bp[2] << 16) | (bp[3] << 24); 73} 74#endif 75 76/* 77 * XXX BEGIN HACK XXX 78 * Scan/parse the XML geom data to retrieve what we need to 79 * carry out the work of Int_Open_Disk. This is a total hack 80 * and should be replaced with a real XML parser. 81 */ 82typedef enum { 83 XML_MESH, 84 XML_MESH_END, 85 XML_CLASS, 86 XML_CLASS_END, 87 XML_GEOM, 88 XML_GEOM_END, 89 XML_CONFIG, 90 XML_CONFIG_END, 91 XML_PROVIDER, 92 XML_PROVIDER_END, 93 XML_NAME, 94 XML_NAME_END, 95 XML_INDEX, 96 XML_INDEX_END, 97 XML_SECLENGTH, 98 XML_SECLENGTH_END, 99 XML_SECOFFSET, 100 XML_SECOFFSET_END, 101 XML_TYPE, 102 XML_TYPE_END, 103 XML_MEDIASIZE, 104 XML_MEDIASIZE_END, 105 XML_SECTORSIZE, 106 XML_SECTORSIZE_END, 107 XML_FWHEADS, 108 XML_FWHEADS_END, 109 XML_FWSECTORS, 110 XML_FWSECTORS_END, 111 112 XML_OTHER, 113 XML_OTHER_END 114} XMLToken; 115 116const struct { 117 XMLToken t; 118 const char* token; 119 const char* name; 120} xmltokens[] = { 121 { XML_MESH, "mesh", "XML_MESH" }, 122 { XML_CLASS, "class", "XML_CLASS" }, 123 { XML_GEOM, "geom", "XML_GEOM" }, 124 { XML_CONFIG, "config", "XML_CONFIG" }, 125 { XML_PROVIDER, "provider", "XML_PROVIDE" }, 126 { XML_NAME, "name", "XML_NAME" }, 127 { XML_INDEX, "index", "XML_INDEX" }, 128 { XML_SECLENGTH, "seclength", "XML_SECLENGTH" }, 129 { XML_SECOFFSET, "secoffset", "XML_SECOFFSET" }, 130 { XML_TYPE, "type", "XML_TYPE" }, 131 { XML_FWHEADS, "fwheads", "XML_FWHEADS" }, 132 { XML_FWSECTORS, "fwsectors", "XML_FWSECTORS" }, 133 { XML_MEDIASIZE, "mediasize", "XML_MEDIASIZE" }, 134 { XML_SECTORSIZE, "sectorsize", "XML_SECTORSIZE" }, 135 /* NB: this must be last */ 136 { XML_OTHER, NULL, "XML_OTHER" }, 137}; 138#define N(x) (sizeof (x) / sizeof (x[0])) 139 140#ifdef DEBUG 141static const char* 142xmltokenname(XMLToken t) 143{ 144 int i; 145 146 for (i = 0; i < N(xmltokens); i++) { 147 if (t == xmltokens[i].t) 148 return xmltokens[i].name; 149 if ((t-1) == xmltokens[i].t) { 150 static char tbuf[80]; 151 snprintf(tbuf, sizeof (tbuf), "%s_END", 152 xmltokens[i].name); 153 return tbuf; 154 } 155 } 156 return "???"; 157} 158#endif /*DEBUG*/ 159 160/* 161 * Parse the next XML token delimited by <..>. If the token 162 * has a "builtin terminator" (<... />) then just skip it and 163 * go the next token. 164 */ 165static int 166xmltoken(const char *start, const char **next, XMLToken *t) 167{ 168 const char *cp = start; 169 const char *token; 170 int i; 171 172again: 173 while (*cp != '<') { 174 if (*cp == '\0') { 175 *next = cp; 176 DPRINTX(("xmltoken: EOD")); 177 return 0; 178 } 179 cp++; 180 } 181 token = ++cp; 182 for (; *cp && *cp != '>' && !isspace(*cp); cp++) 183 ; 184 if (*cp == '\0') { 185 *next = cp; 186 DPRINTX(("xmltoken: EOD")); 187 return 0; 188 } 189 *t = (*token == '/'); 190 if (*t) 191 token++; 192 for (i = 0; xmltokens[i].token != NULL; i++) 193 if (strncasecmp(token, xmltokens[i].token, cp-token) == 0) 194 break; 195 *t += xmltokens[i].t; 196 /* now collect the remainder of the string */ 197 for (; *cp != '>' && *cp != '\0'; cp++) 198 ; 199 if (*cp == '\0') { 200 *next = cp; 201 DPRINTX(("xmltoken: EOD")); 202 return 0; 203 } 204 if (cp > token && cp[-1] == '/') { 205 /* e.g. <geom ref="0xc1c8c100"/> */ 206 start = cp+1; 207 goto again; 208 } 209 *next = cp+1; 210 DPRINTX(("xmltoken: %s \"%.*s\"", xmltokenname(*t), cp-token, token)); 211 return 1; 212} 213 214/* 215 * Parse and discard XML up to the token terminator. 216 */ 217static int 218discardxml(const char **next, XMLToken terminator) 219{ 220 const char *xml = *next; 221 XMLToken t; 222 223 DPRINTX(("discard XML up to %s", xmltokenname(terminator))); 224 for (;;) { 225 if (xmltoken(xml, next, &t) == 0) 226 return EINVAL; 227 if (t == terminator) 228 break; 229 if ((t & 1) == 0) { 230 int error = discardxml(next, t+1); 231 if (error) 232 return error; 233 } 234 xml = *next; 235 } 236 return 0; 237} 238 239/* 240 * Parse XML from between a range of markers; e.g. <mesh> ... </mesh>. 241 * When the specified class name is located we descend looking for the 242 * geometry information given by diskname. Once inside there we process 243 * tags calling f back for each useful one. The arg is passed into f 244 * for use in storing the parsed data. 245 */ 246static int 247parsexmlpair( 248 const char *xml, 249 const char **next, 250 const char *classname, 251 XMLToken terminator, 252 const char *diskname, 253 int (*f)(void *, XMLToken, u_int *, u_int64_t), 254 void *arg 255) 256{ 257 const char *cp; 258 XMLToken t; 259 int error; 260 u_int ix = (u_int) -1; 261 262 DPRINTX(("parse XML up to %s", xmltokenname(terminator))); 263 do { 264 if (xmltoken(xml, next, &t) == 0) { 265 error = EINVAL; 266 break; 267 } 268 if (t == terminator) { 269 error = 0; 270 break; 271 } 272 if (t & 1) { /* </mumble> w/o matching <mumble> */ 273 DPRINTX(("Unexpected token %s", xmltokenname(t))); 274 error = EINVAL; 275 break; 276 } 277 switch ((int) t) { 278 case XML_NAME: 279 for (cp = *next; *cp && *cp != '<'; cp++) 280 ; 281 if (*cp == '\0') { 282 DPRINTX(("parsexmlpair: EOD")); 283 error = EINVAL; 284 goto done; 285 } 286 DPRINTX(("parsexmlpair: \"%.*s\"", cp-*next, *next)); 287 switch ((int) terminator) { 288 case XML_CLASS_END: 289 if (strncasecmp(*next, classname, cp-*next)) 290 return discardxml(next, terminator); 291 break; 292 case XML_GEOM_END: 293 if (strncasecmp(*next, diskname, cp-*next)) 294 return discardxml(next, terminator); 295 break; 296 } 297 break; 298 case XML_SECOFFSET: 299 case XML_SECLENGTH: 300 case XML_TYPE: 301 if (ix == (u_int) -1) { 302 DPRINTX(("parsexmlpair: slice data w/o " 303 "preceding index")); 304 error = EINVAL; 305 goto done; 306 } 307 /* fall thru... */ 308 case XML_INDEX: 309 case XML_FWHEADS: 310 case XML_FWSECTORS: 311 case XML_MEDIASIZE: 312 case XML_SECTORSIZE: 313 if (terminator != XML_CONFIG_END && 314 terminator != XML_PROVIDER_END) { 315 DPRINTX(("parsexmlpair: %s in unexpected " 316 "context: terminator %s", 317 xmltokenname(t), 318 xmltokenname(terminator))); 319 error = EINVAL; 320 goto done; 321 } 322 error = (*f)(arg, t, &ix, strtoull(*next, NULL, 10)); 323 if (error) 324 goto done; 325 break; 326 } 327 error = parsexmlpair(*next, &xml, classname, 328 t+1, diskname, f, arg); 329 } while (error == 0); 330done: 331 return error; 332} 333 334/* 335 * XML parser. Just barely smart enough to handle the 336 * gibberish that geom passed back from the kernel. 337 */ 338static int 339xmlparse( 340 const char *confxml, 341 const char *classname, 342 const char *diskname, 343 int (*f)(void *, XMLToken, u_int *, u_int64_t), 344 void *arg 345) 346{ 347 const char *next; 348 XMLToken t; 349 int error; 350 351 next = confxml; 352 while (xmltoken(next, &next, &t) && t != XML_MESH) 353 ; 354 if (t == XML_MESH) 355 error = parsexmlpair(next, &next, classname, XML_MESH_END, diskname, f, arg); 356 else { 357 DPRINTX(("xmlparse: expecting mesh token, got %s", 358 xmltokenname(t))); 359 error = EINVAL; 360 } 361 362 return (error ? -1 : 0); 363} 364 365/* 366 * Callback to collect slice-related data. 367 */ 368static int 369assignToSlice(void *arg, XMLToken t, u_int *slice, u_int64_t v) 370{ 371 struct diskslices *ds = (struct diskslices *) arg; 372 373 switch ((int) t) { 374 case XML_INDEX: 375 *slice = BASE_SLICE + (u_int) v; 376 if (*slice >= MAX_SLICES) { 377 DPRINTX(("assignToSlice: invalid slice index %u > max %u", 378 *slice, MAX_SLICES)); 379 return EINVAL; 380 } 381 if (*slice >= ds->dss_nslices) 382 ds->dss_nslices = (*slice)+1; 383 break; 384 case XML_SECOFFSET: 385 ds->dss_slices[*slice].ds_offset = (u_long) v; 386 break; 387 case XML_SECLENGTH: 388 ds->dss_slices[*slice].ds_size = (u_long) v; 389 break; 390 case XML_TYPE: 391 ds->dss_slices[*slice].ds_type = (int) v; 392 break; 393 } 394 return 0; 395} 396 397/* 398 * Callback to collect disk-related data. 399 */ 400static int 401assignToDisk(void *arg, XMLToken t, u_int *slice, u_int64_t v) 402{ 403 struct disklabel *dl = (struct disklabel *) arg; 404 405 switch ((int) t) { 406 case XML_FWHEADS: 407 dl->d_ntracks = (u_int32_t) v; 408 case XML_FWSECTORS: 409 dl->d_nsectors = (u_int32_t) v; 410 break; 411 case XML_MEDIASIZE: 412 /* store this temporarily; it gets moved later */ 413 dl->d_secpercyl = v >> 32; 414 dl->d_secperunit = v & 0xffffffff; 415 break; 416 case XML_SECTORSIZE: 417 dl->d_secsize = (u_int32_t) v; 418 break; 419 } 420 return 0; 421} 422 423/* 424 * Callback to collect partition-related data. 425 */ 426static int 427assignToPartition(void *arg, XMLToken t, u_int *part, u_int64_t v) 428{ 429 struct disklabel *dl = (struct disklabel *) arg; 430 431 switch ((int) t) { 432 case XML_INDEX: 433 *part = (u_int) v; 434 if (*part >= MAXPARTITIONS) { 435 DPRINTX(("assignToPartition: invalid partition index %u > max %u", 436 *part, MAXPARTITIONS)); 437 return EINVAL; 438 } 439 if (*part >= dl->d_npartitions) 440 dl->d_npartitions = (*part)+1; 441 break; 442 case XML_SECOFFSET: 443 dl->d_partitions[*part].p_offset = (u_int32_t) v; 444 break; 445 case XML_SECLENGTH: 446 dl->d_partitions[*part].p_size = (u_int32_t) v; 447 break; 448 case XML_TYPE: 449 dl->d_partitions[*part].p_fstype = (u_int8_t) v; 450 break; 451 } 452 return 0; 453} 454#undef N 455 456struct disk * 457Int_Open_Disk(const char *name, u_long size) 458{ 459 int i; 460 int fd = -1; 461 struct diskslices ds; 462 struct disklabel dl; 463 char device[64]; 464 struct disk *d; 465#ifdef PC98 466 unsigned char *p; 467#else 468 struct dos_partition *dp; 469 void *p; 470#endif 471 char *confxml = NULL; 472 size_t xmlsize; 473 u_int64_t mediasize; 474 int error; 475 476 strlcpy(device, _PATH_DEV, sizeof(device)); 477 strlcat(device, name, sizeof(device)); 478 479 d = (struct disk *)malloc(sizeof *d); 480 if(!d) return NULL; 481 memset(d, 0, sizeof *d); 482 483 fd = open(device, O_RDONLY); 484 if (fd < 0) { 485 DPRINT(("open(%s) failed", device)); 486 goto bad; 487 } 488 489 memset(&dl, 0, sizeof dl); 490 memset(&ds, 0, sizeof ds); 491 /* 492 * Read and hack-parse the XML that provides the info we need. 493 */ 494 error = sysctlbyname("kern.geom.confxml", NULL, &xmlsize, NULL, 0); 495 if (error) { 496 warn("kern.geom.confxml sysctl not available, giving up!"); 497 goto bad; 498 } 499 confxml = (char *) malloc(xmlsize+1); 500 if (confxml == NULL) { 501 DPRINT(("cannot malloc memory for confxml")); 502 goto bad; 503 } 504 error = sysctlbyname("kern.geom.confxml", confxml, &xmlsize, NULL, 0); 505 if (error) { 506 DPRINT(("error reading kern.geom.confxml from the system")); 507 goto bad; 508 } 509 confxml[xmlsize] = '\0'; /* in case kernel bug is still there */ 510 511 if (xmlparse(confxml, "MBR", name, assignToSlice, &ds) != 0) { 512 DPRINTX(("Error parsing MBR geometry specification.")); 513 goto bad; 514 } 515 if (xmlparse(confxml, "DISK", name, assignToDisk, &dl) != 0) { 516 DPRINTX(("Error parsing DISK geometry specification.")); 517 goto bad; 518 } 519 if (dl.d_nsectors == 0) { 520 DPRINTX(("No (zero) sector information in DISK geometry")); 521 goto bad; 522 } 523 if (dl.d_ntracks == 0) { 524 DPRINTX(("No (zero) track information in DISK geometry")); 525 goto bad; 526 } 527 if (dl.d_secsize == 0) { 528 DPRINTX(("No (zero) sector size information in DISK geometry")); 529 goto bad; 530 } 531 if (dl.d_secpercyl == 0 && dl.d_secperunit == 0) { 532 DPRINTX(("No (zero) media size information in DISK geometry")); 533 goto bad; 534 } 535 /* 536 * Now patch up disklabel and diskslice. 537 */ 538 d->sector_size = dl.d_secsize; 539 /* NB: media size was stashed in two parts while parsing */ 540 mediasize = (((u_int64_t) dl.d_secpercyl) << 32) + dl.d_secperunit; 541 dl.d_secpercyl = 0; 542 dl.d_secperunit = 0; 543 size = mediasize / d->sector_size; 544 dl.d_ncylinders = size / (dl.d_ntracks * dl.d_nsectors); 545 /* "whole disk" slice maintained for compatibility */ 546 ds.dss_slices[WHOLE_DISK_SLICE].ds_size = size; 547 548#ifdef PC98 549 p = (unsigned char*)read_block(fd, 1, d->sector_size); 550#else 551 p = read_block(fd, 0, d->sector_size); 552 dp = (struct dos_partition*)(p + DOSPARTOFF); 553 for (i = 0; i < NDOSPART; i++) { 554 if (Read_Int32(&dp->dp_start) >= size) 555 continue; 556 if (Read_Int32(&dp->dp_start) + Read_Int32(&dp->dp_size) >= size) 557 continue; 558 if (!Read_Int32(&dp->dp_size)) 559 continue; 560 } 561 free(p); 562#endif 563 564 d->bios_sect = dl.d_nsectors; 565 d->bios_hd = dl.d_ntracks; 566 567 d->name = strdup(name); 568 569 570 if (dl.d_ntracks && dl.d_nsectors) 571 d->bios_cyl = size / (dl.d_ntracks * dl.d_nsectors); 572 573 if (Add_Chunk(d, 0, size, name, whole, 0, 0, "-")) 574 DPRINT(("Failed to add 'whole' chunk")); 575 576#ifdef __i386__ 577#ifdef PC98 578 /* XXX -- Quick Hack! 579 * Check MS-DOS MO 580 */ 581 if ((*p == 0xf0 || *p == 0xf8) && 582 (*(p+1) == 0xff) && 583 (*(p+2) == 0xff)) { 584 Add_Chunk(d, 0, size, name, fat, 0xa0a0, 0, name); 585 free(p); 586 goto pc98_mo_done; 587 } 588 free(p); 589#endif /* PC98 */ 590 for(i=BASE_SLICE;i<ds.dss_nslices;i++) { 591 char sname[20]; 592 char pname[20]; 593 chunk_e ce; 594 u_long flags=0; 595 int subtype=0; 596 int j; 597 598 if (! ds.dss_slices[i].ds_size) 599 continue; 600 snprintf(sname, sizeof(sname), "%ss%d", name, i - 1); 601#ifdef PC98 602 subtype = ds.dss_slices[i].ds_type | 603 ds.dss_slices[i].ds_subtype << 8; 604 switch (ds.dss_slices[i].ds_type & 0x7f) { 605 case 0x14: 606 ce = freebsd; 607 break; 608 case 0x20: 609 case 0x21: 610 case 0x22: 611 case 0x23: 612 case 0x24: 613 ce = fat; 614 break; 615#else /* IBM-PC */ 616 subtype = ds.dss_slices[i].ds_type; 617 switch (ds.dss_slices[i].ds_type) { 618 case 0xa5: 619 ce = freebsd; 620 break; 621 case 0x1: 622 case 0x6: 623 case 0x4: 624 case 0xb: 625 case 0xc: 626 case 0xe: 627 ce = fat; 628 break; 629 case DOSPTYP_EXTENDED: 630 case 0xf: 631 ce = extended; 632 break; 633#endif 634 default: 635 ce = unknown; 636 break; 637 } 638#ifdef PC98 639 if (Add_Chunk(d, ds.dss_slices[i].ds_offset, 640 ds.dss_slices[i].ds_size, sname, ce, subtype, flags, 641 ds.dss_slices[i].ds_name)) 642#else 643 if (Add_Chunk(d, ds.dss_slices[i].ds_offset, 644 ds.dss_slices[i].ds_size, sname, ce, subtype, flags, "")) 645#endif 646 DPRINT(("failed to add chunk for slice %d", i - 1)); 647 648#ifdef PC98 649 if ((ds.dss_slices[i].ds_type & 0x7f) != 0x14) 650#else 651 if (ds.dss_slices[i].ds_type != 0xa5) 652#endif 653 continue; 654 if (xmlparse(confxml, "BSD", sname, assignToPartition, &dl) != 0) { 655 DPRINTX(("Error parsing MBR geometry specification.")); 656 goto bad; 657 } 658 659 for(j = 0; j <= dl.d_npartitions; j++) { 660 if (j == RAW_PART) 661 continue; 662 if (j == 3) 663 continue; 664 if (j == dl.d_npartitions) { 665 j = 3; 666 dl.d_npartitions = 0; 667 } 668 if (!dl.d_partitions[j].p_size) 669 continue; 670 if (dl.d_partitions[j].p_size + 671 dl.d_partitions[j].p_offset > 672 ds.dss_slices[i].ds_size) 673 continue; 674 snprintf(pname, sizeof(pname), "%s%c", sname, j + 'a'); 675 if (Add_Chunk(d, 676 dl.d_partitions[j].p_offset + 677 ds.dss_slices[i].ds_offset, 678 dl.d_partitions[j].p_size, 679 pname,part, 680 dl.d_partitions[j].p_fstype, 681#ifdef PC98 682 0, 683 ds.dss_slices[i].ds_name) && j != 3) 684#else 685 0, "") && j != 3) 686#endif 687 DPRINT(( 688 "Failed to add chunk for partition %c [%lu,%lu]", 689 j + 'a', dl.d_partitions[j].p_offset, 690 dl.d_partitions[j].p_size)); 691 } 692 } 693#endif /* __i386__ */ 694#ifdef __alpha__ 695 { 696 struct disklabel dl; 697 char pname[20]; 698 int j,k; 699 700 strlcpy(pname, _PATH_DEV, sizeof(pname)); 701 strlcat(pname, name, sizeof(pname)); 702 j = open(pname, O_RDONLY); 703 if (j < 0) { 704 DPRINT(("open(%s)", pname)); 705 goto nolabel; 706 } 707 k = ioctl(j, DIOCGDINFO, &dl); 708 if (k < 0) { 709 DPRINT(("ioctl(%s, DIOCGDINFO)", pname)); 710 close(j); 711 goto nolabel; 712 } 713 close(j); 714 All_FreeBSD(d, 1); 715 716 for(j = 0; j <= dl.d_npartitions; j++) { 717 if (j == RAW_PART) 718 continue; 719 if (j == 3) 720 continue; 721 if (j == dl.d_npartitions) { 722 j = 3; 723 dl.d_npartitions = 0; 724 } 725 if (!dl.d_partitions[j].p_size) 726 continue; 727 if (dl.d_partitions[j].p_size + 728 dl.d_partitions[j].p_offset > 729 ds.dss_slices[WHOLE_DISK_SLICE].ds_size) 730 continue; 731 snprintf(pname, sizeof(pname), "%s%c", name, j + 'a'); 732 if (Add_Chunk(d, 733 dl.d_partitions[j].p_offset, 734 dl.d_partitions[j].p_size, 735 pname,part, 736 dl.d_partitions[j].p_fstype, 737 0, "") && j != 3) 738 DPRINT(( 739 "Failed to add chunk for partition %c [%lu,%lu]", 740 j + 'a', dl.d_partitions[j].p_offset, 741 dl.d_partitions[j].p_size)); 742 } 743 nolabel:; 744 } 745#endif /* __alpha__ */ 746#ifdef PC98 747pc98_mo_done: 748#endif 749 close(fd); 750 Fixup_Names(d); 751 return d; 752bad: 753 if (confxml != NULL) 754 free(confxml); 755 if (fd >= 0) 756 close(fd); 757 return NULL; 758} 759 760void 761Debug_Disk(struct disk *d) 762{ 763 printf("Debug_Disk(%s)", d->name); 764#if 0 765 printf(" real_geom=%lu/%lu/%lu", d->real_cyl, d->real_hd, d->real_sect); 766#endif 767 printf(" bios_geom=%lu/%lu/%lu = %lu\n", 768 d->bios_cyl, d->bios_hd, d->bios_sect, 769 d->bios_cyl * d->bios_hd * d->bios_sect); 770#if defined(PC98) 771 printf(" boot1=%p, boot2=%p, bootipl=%p, bootmenu=%p\n", 772 d->boot1, d->boot2, d->bootipl, d->bootmenu); 773#elif defined(__i386__) 774 printf(" boot1=%p, boot2=%p, bootmgr=%p\n", 775 d->boot1, d->boot2, d->bootmgr); 776#elif defined(__alpha__) 777 printf(" boot1=%p, bootmgr=%p\n", 778 d->boot1, d->bootmgr); 779#endif 780 Debug_Chunk(d->chunks); 781} 782 783void 784Free_Disk(struct disk *d) 785{ 786 if(d->chunks) Free_Chunk(d->chunks); 787 if(d->name) free(d->name); 788#ifdef PC98 789 if(d->bootipl) free(d->bootipl); 790 if(d->bootmenu) free(d->bootmenu); 791#else 792 if(d->bootmgr) free(d->bootmgr); 793#endif 794 if(d->boot1) free(d->boot1); 795#if defined(__i386__) 796 if(d->boot2) free(d->boot2); 797#endif 798 free(d); 799} 800 801#if 0 802void 803Collapse_Disk(struct disk *d) 804{ 805 806 while(Collapse_Chunk(d, d->chunks)) 807 ; 808} 809#endif 810 811static int 812qstrcmp(const void* a, const void* b) 813{ 814 815 char *str1 = *(char**)a; 816 char *str2 = *(char**)b; 817 return strcmp(str1, str2); 818} 819 820char ** 821Disk_Names() 822{ 823 int disk_cnt; 824 static char **disks; 825 int error; 826 size_t listsize; 827 char *disklist; 828 829 error = sysctlbyname("kern.disks", NULL, &listsize, NULL, 0); 830 if (error) { 831 warn("kern.disks sysctl not available"); 832 return NULL; 833 } 834 835 disks = malloc(sizeof *disks * (1 + MAX_NO_DISKS)); 836 if (disks == NULL) 837 return NULL; 838 disklist = (char *)malloc(listsize + 1); 839 if (disklist == NULL) { 840 free(disks); 841 return NULL; 842 } 843 memset(disks,0,sizeof *disks * (1 + MAX_NO_DISKS)); 844 memset(disklist, 0, listsize + 1); 845 error = sysctlbyname("kern.disks", disklist, &listsize, NULL, 0); 846 if (error) { 847 free(disklist); 848 free(disks); 849 return NULL; 850 } 851 for (disk_cnt = 0; disk_cnt < MAX_NO_DISKS; disk_cnt++) { 852 disks[disk_cnt] = strsep(&disklist, " "); 853 if (disks[disk_cnt] == NULL) 854 break; 855 } 856 qsort(disks, disk_cnt, sizeof(char*), qstrcmp); 857 return disks; 858} 859 860#ifdef PC98 861void 862Set_Boot_Mgr(struct disk *d, const u_char *bootipl, const size_t bootipl_size, 863 const u_char *bootmenu, const size_t bootmenu_size) 864#else 865void 866Set_Boot_Mgr(struct disk *d, const u_char *b, const size_t s) 867#endif 868{ 869#ifdef PC98 870 if (bootipl_size % d->sector_size != 0) 871 return; 872 if (d->bootipl) 873 free(d->bootipl); 874 if (!bootipl) { 875 d->bootipl = NULL; 876 } else { 877 d->bootipl_size = bootipl_size; 878 d->bootipl = malloc(bootipl_size); 879 if(!d->bootipl) return; 880 memcpy(d->bootipl, bootipl, bootipl_size); 881 } 882 883 if (bootmenu_size % d->sector_size != 0) 884 return; 885 if (d->bootmenu) 886 free(d->bootmenu); 887 if (!bootmenu) { 888 d->bootmenu = NULL; 889 } else { 890 d->bootmenu_size = bootmenu_size; 891 d->bootmenu = malloc(bootmenu_size); 892 if(!d->bootmenu) return; 893 memcpy(d->bootmenu, bootmenu, bootmenu_size); 894 } 895#else 896 if (s % d->sector_size != 0) 897 return; 898 if (d->bootmgr) 899 free(d->bootmgr); 900 if (!b) { 901 d->bootmgr = NULL; 902 } else { 903 d->bootmgr_size = s; 904 d->bootmgr = malloc(s); 905 if(!d->bootmgr) return; 906 memcpy(d->bootmgr, b, s); 907 } 908#endif 909} 910 911int 912Set_Boot_Blocks(struct disk *d, const u_char *b1, const u_char *b2) 913{ 914#if defined(__i386__) 915 if (d->boot1) free(d->boot1); 916 d->boot1 = malloc(512); 917 if(!d->boot1) return -1; 918 memcpy(d->boot1, b1, 512); 919 if (d->boot2) free(d->boot2); 920 d->boot2 = malloc(15 * 512); 921 if(!d->boot2) return -1; 922 memcpy(d->boot2, b2, 15 * 512); 923#elif defined(__alpha__) 924 if (d->boot1) free(d->boot1); 925 d->boot1 = malloc(15 * 512); 926 if(!d->boot1) return -1; 927 memcpy(d->boot1, b1, 15 * 512); 928#endif 929 return 0; 930} 931 932const char * 933slice_type_name( int type, int subtype ) 934{ 935 switch (type) { 936 case 0: return "whole"; 937#ifndef PC98 938 case 1: switch (subtype) { 939 case 1: return "fat (12-bit)"; 940 case 2: return "XENIX /"; 941 case 3: return "XENIX /usr"; 942 case 4: return "fat (16-bit,<=32Mb)"; 943 case 5: return "extended DOS"; 944 case 6: return "fat (16-bit,>32Mb)"; 945 case 7: return "NTFS/HPFS/QNX"; 946 case 8: return "AIX bootable"; 947 case 9: return "AIX data"; 948 case 10: return "OS/2 bootmgr"; 949 case 11: return "fat (32-bit)"; 950 case 12: return "fat (32-bit,LBA)"; 951 case 14: return "fat (16-bit,>32Mb,LBA)"; 952 case 15: return "extended DOS, LBA"; 953 case 18: return "Compaq Diagnostic"; 954 case 84: return "OnTrack diskmgr"; 955 case 100: return "Netware 2.x"; 956 case 101: return "Netware 3.x"; 957 case 115: return "SCO UnixWare"; 958 case 128: return "Minix 1.1"; 959 case 129: return "Minix 1.5"; 960 case 130: return "linux_swap"; 961 case 131: return "ext2fs"; 962 case 166: return "OpenBSD FFS"; /* 0xA6 */ 963 case 169: return "NetBSD FFS"; /* 0xA9 */ 964 case 182: return "OpenBSD"; /* dedicated */ 965 case 183: return "bsd/os"; 966 case 184: return "bsd/os swap"; 967 case 238: return "EFI GPT"; 968 case 239: return "EFI Sys. Part."; 969 default: return "unknown"; 970 } 971#endif 972 case 2: return "fat"; 973 case 3: switch (subtype) { 974#ifdef PC98 975 case 0xc494: return "freebsd"; 976#else 977 case 165: return "freebsd"; 978#endif 979 default: return "unknown"; 980 } 981#ifndef PC98 982 case 4: return "extended"; 983 case 5: return "part"; 984 case 6: return "unused"; 985#endif 986 default: return "unknown"; 987 } 988} 989