disk.c revision 106008
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 106008 2002-10-27 00:21:02Z peter $"); 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#ifdef __i386__ 424/* 425 * Callback to collect partition-related data. 426 */ 427static int 428assignToPartition(void *arg, XMLToken t, u_int *part, u_int64_t v) 429{ 430 struct disklabel *dl = (struct disklabel *) arg; 431 432 switch ((int) t) { 433 case XML_INDEX: 434 *part = (u_int) v; 435 if (*part >= MAXPARTITIONS) { 436 DPRINTX(("assignToPartition: invalid partition index %u > max %u", 437 *part, MAXPARTITIONS)); 438 return EINVAL; 439 } 440 if (*part >= dl->d_npartitions) 441 dl->d_npartitions = (*part)+1; 442 break; 443 case XML_SECOFFSET: 444 dl->d_partitions[*part].p_offset = (u_int32_t) v; 445 break; 446 case XML_SECLENGTH: 447 dl->d_partitions[*part].p_size = (u_int32_t) v; 448 break; 449 case XML_TYPE: 450 dl->d_partitions[*part].p_fstype = (u_int8_t) v; 451 break; 452 } 453 return 0; 454} 455#endif /* __i386__ */ 456#undef N 457 458struct disk * 459Int_Open_Disk(const char *name, u_long size) 460{ 461 int i; 462 int fd = -1; 463 struct diskslices ds; 464 struct disklabel dl; 465 char device[64]; 466 struct disk *d; 467#ifdef PC98 468 unsigned char *p; 469#else 470 struct dos_partition *dp; 471 void *p; 472#endif 473 char *confxml = NULL; 474 size_t xmlsize; 475 u_int64_t mediasize; 476 int error; 477 478 strlcpy(device, _PATH_DEV, sizeof(device)); 479 strlcat(device, name, sizeof(device)); 480 481 d = (struct disk *)malloc(sizeof *d); 482 if(!d) return NULL; 483 memset(d, 0, sizeof *d); 484 485 fd = open(device, O_RDONLY); 486 if (fd < 0) { 487 DPRINT(("open(%s) failed", device)); 488 goto bad; 489 } 490 491 memset(&dl, 0, sizeof dl); 492 memset(&ds, 0, sizeof ds); 493 /* 494 * Read and hack-parse the XML that provides the info we need. 495 */ 496 error = sysctlbyname("kern.geom.confxml", NULL, &xmlsize, NULL, 0); 497 if (error) { 498 warn("kern.geom.confxml sysctl not available, giving up!"); 499 goto bad; 500 } 501 confxml = (char *) malloc(xmlsize+1); 502 if (confxml == NULL) { 503 DPRINT(("cannot malloc memory for confxml")); 504 goto bad; 505 } 506 error = sysctlbyname("kern.geom.confxml", confxml, &xmlsize, NULL, 0); 507 if (error) { 508 DPRINT(("error reading kern.geom.confxml from the system")); 509 goto bad; 510 } 511 confxml[xmlsize] = '\0'; /* in case kernel bug is still there */ 512 513 if (xmlparse(confxml, "MBR", name, assignToSlice, &ds) != 0) { 514 DPRINTX(("Error parsing MBR geometry specification.")); 515 goto bad; 516 } 517 if (xmlparse(confxml, "DISK", name, assignToDisk, &dl) != 0) { 518 DPRINTX(("Error parsing DISK geometry specification.")); 519 goto bad; 520 } 521 if (dl.d_nsectors == 0) { 522 DPRINTX(("No (zero) sector information in DISK geometry")); 523 goto bad; 524 } 525 if (dl.d_ntracks == 0) { 526 DPRINTX(("No (zero) track information in DISK geometry")); 527 goto bad; 528 } 529 if (dl.d_secsize == 0) { 530 DPRINTX(("No (zero) sector size information in DISK geometry")); 531 goto bad; 532 } 533 if (dl.d_secpercyl == 0 && dl.d_secperunit == 0) { 534 DPRINTX(("No (zero) media size information in DISK geometry")); 535 goto bad; 536 } 537 /* 538 * Now patch up disklabel and diskslice. 539 */ 540 d->sector_size = dl.d_secsize; 541 /* NB: media size was stashed in two parts while parsing */ 542 mediasize = (((u_int64_t) dl.d_secpercyl) << 32) + dl.d_secperunit; 543 dl.d_secpercyl = 0; 544 dl.d_secperunit = 0; 545 size = mediasize / d->sector_size; 546 dl.d_ncylinders = size / (dl.d_ntracks * dl.d_nsectors); 547 /* "whole disk" slice maintained for compatibility */ 548 ds.dss_slices[WHOLE_DISK_SLICE].ds_size = size; 549 550#ifdef PC98 551 p = (unsigned char*)read_block(fd, 1, d->sector_size); 552#else 553 p = read_block(fd, 0, d->sector_size); 554 dp = (struct dos_partition*)(p + DOSPARTOFF); 555 for (i = 0; i < NDOSPART; i++) { 556 if (Read_Int32(&dp->dp_start) >= size) 557 continue; 558 if (Read_Int32(&dp->dp_start) + Read_Int32(&dp->dp_size) >= size) 559 continue; 560 if (!Read_Int32(&dp->dp_size)) 561 continue; 562 } 563 free(p); 564#endif 565 566 d->bios_sect = dl.d_nsectors; 567 d->bios_hd = dl.d_ntracks; 568 569 d->name = strdup(name); 570 571 572 if (dl.d_ntracks && dl.d_nsectors) 573 d->bios_cyl = size / (dl.d_ntracks * dl.d_nsectors); 574 575 if (Add_Chunk(d, 0, size, name, whole, 0, 0, "-")) 576 DPRINT(("Failed to add 'whole' chunk")); 577 578#ifdef __i386__ 579#ifdef PC98 580 /* XXX -- Quick Hack! 581 * Check MS-DOS MO 582 */ 583 if ((*p == 0xf0 || *p == 0xf8) && 584 (*(p+1) == 0xff) && 585 (*(p+2) == 0xff)) { 586 Add_Chunk(d, 0, size, name, fat, 0xa0a0, 0, name); 587 free(p); 588 goto pc98_mo_done; 589 } 590 free(p); 591#endif /* PC98 */ 592 for(i=BASE_SLICE;i<ds.dss_nslices;i++) { 593 char sname[20]; 594 char pname[20]; 595 chunk_e ce; 596 u_long flags=0; 597 int subtype=0; 598 int j; 599 600 if (! ds.dss_slices[i].ds_size) 601 continue; 602 snprintf(sname, sizeof(sname), "%ss%d", name, i - 1); 603#ifdef PC98 604 subtype = ds.dss_slices[i].ds_type | 605 ds.dss_slices[i].ds_subtype << 8; 606 switch (ds.dss_slices[i].ds_type & 0x7f) { 607 case 0x14: 608 ce = freebsd; 609 break; 610 case 0x20: 611 case 0x21: 612 case 0x22: 613 case 0x23: 614 case 0x24: 615 ce = fat; 616 break; 617#else /* IBM-PC */ 618 subtype = ds.dss_slices[i].ds_type; 619 switch (ds.dss_slices[i].ds_type) { 620 case 0xa5: 621 ce = freebsd; 622 break; 623 case 0x1: 624 case 0x6: 625 case 0x4: 626 case 0xb: 627 case 0xc: 628 case 0xe: 629 ce = fat; 630 break; 631 case DOSPTYP_EXTENDED: 632 case 0xf: 633 ce = extended; 634 break; 635#endif 636 default: 637 ce = unknown; 638 break; 639 } 640#ifdef PC98 641 if (Add_Chunk(d, ds.dss_slices[i].ds_offset, 642 ds.dss_slices[i].ds_size, sname, ce, subtype, flags, 643 ds.dss_slices[i].ds_name)) 644#else 645 if (Add_Chunk(d, ds.dss_slices[i].ds_offset, 646 ds.dss_slices[i].ds_size, sname, ce, subtype, flags, "")) 647#endif 648 DPRINT(("failed to add chunk for slice %d", i - 1)); 649 650#ifdef PC98 651 if ((ds.dss_slices[i].ds_type & 0x7f) != 0x14) 652#else 653 if (ds.dss_slices[i].ds_type != 0xa5) 654#endif 655 continue; 656 if (xmlparse(confxml, "BSD", sname, assignToPartition, &dl) != 0) { 657 DPRINTX(("Error parsing MBR geometry specification.")); 658 goto bad; 659 } 660 661 for(j = 0; j <= dl.d_npartitions; j++) { 662 if (j == RAW_PART) 663 continue; 664 if (j == 3) 665 continue; 666 if (j == dl.d_npartitions) { 667 j = 3; 668 dl.d_npartitions = 0; 669 } 670 if (!dl.d_partitions[j].p_size) 671 continue; 672 if (dl.d_partitions[j].p_size + 673 dl.d_partitions[j].p_offset > 674 ds.dss_slices[i].ds_size) 675 continue; 676 snprintf(pname, sizeof(pname), "%s%c", sname, j + 'a'); 677 if (Add_Chunk(d, 678 dl.d_partitions[j].p_offset + 679 ds.dss_slices[i].ds_offset, 680 dl.d_partitions[j].p_size, 681 pname,part, 682 dl.d_partitions[j].p_fstype, 683#ifdef PC98 684 0, 685 ds.dss_slices[i].ds_name) && j != 3) 686#else 687 0, "") && j != 3) 688#endif 689 DPRINT(( 690 "Failed to add chunk for partition %c [%lu,%lu]", 691 j + 'a', dl.d_partitions[j].p_offset, 692 dl.d_partitions[j].p_size)); 693 } 694 } 695#endif /* __i386__ */ 696#ifdef __alpha__ 697 { 698 struct disklabel dl; 699 char pname[20]; 700 int j,k; 701 702 strlcpy(pname, _PATH_DEV, sizeof(pname)); 703 strlcat(pname, name, sizeof(pname)); 704 j = open(pname, O_RDONLY); 705 if (j < 0) { 706 DPRINT(("open(%s)", pname)); 707 goto nolabel; 708 } 709 k = ioctl(j, DIOCGDINFO, &dl); 710 if (k < 0) { 711 DPRINT(("ioctl(%s, DIOCGDINFO)", pname)); 712 close(j); 713 goto nolabel; 714 } 715 close(j); 716 All_FreeBSD(d, 1); 717 718 for(j = 0; j <= dl.d_npartitions; j++) { 719 if (j == RAW_PART) 720 continue; 721 if (j == 3) 722 continue; 723 if (j == dl.d_npartitions) { 724 j = 3; 725 dl.d_npartitions = 0; 726 } 727 if (!dl.d_partitions[j].p_size) 728 continue; 729 if (dl.d_partitions[j].p_size + 730 dl.d_partitions[j].p_offset > 731 ds.dss_slices[WHOLE_DISK_SLICE].ds_size) 732 continue; 733 snprintf(pname, sizeof(pname), "%s%c", name, j + 'a'); 734 if (Add_Chunk(d, 735 dl.d_partitions[j].p_offset, 736 dl.d_partitions[j].p_size, 737 pname,part, 738 dl.d_partitions[j].p_fstype, 739 0, "") && j != 3) 740 DPRINT(( 741 "Failed to add chunk for partition %c [%lu,%lu]", 742 j + 'a', dl.d_partitions[j].p_offset, 743 dl.d_partitions[j].p_size)); 744 } 745 nolabel:; 746 } 747#endif /* __alpha__ */ 748#ifdef PC98 749pc98_mo_done: 750#endif 751 close(fd); 752 Fixup_Names(d); 753 return d; 754bad: 755 if (confxml != NULL) 756 free(confxml); 757 if (fd >= 0) 758 close(fd); 759 return NULL; 760} 761 762void 763Debug_Disk(struct disk *d) 764{ 765 printf("Debug_Disk(%s)", d->name); 766#if 0 767 printf(" real_geom=%lu/%lu/%lu", d->real_cyl, d->real_hd, d->real_sect); 768#endif 769 printf(" bios_geom=%lu/%lu/%lu = %lu\n", 770 d->bios_cyl, d->bios_hd, d->bios_sect, 771 d->bios_cyl * d->bios_hd * d->bios_sect); 772#if defined(PC98) 773 printf(" boot1=%p, boot2=%p, bootipl=%p, bootmenu=%p\n", 774 d->boot1, d->boot2, d->bootipl, d->bootmenu); 775#elif defined(__i386__) 776 printf(" boot1=%p, boot2=%p, bootmgr=%p\n", 777 d->boot1, d->boot2, d->bootmgr); 778#elif defined(__alpha__) 779 printf(" boot1=%p, bootmgr=%p\n", 780 d->boot1, d->bootmgr); 781#elif defined(__ia64__) 782 printf("\n"); 783#else 784/* Should be: error "Debug_Disk: unknown arch"; */ 785#endif 786 Debug_Chunk(d->chunks); 787} 788 789void 790Free_Disk(struct disk *d) 791{ 792 if(d->chunks) Free_Chunk(d->chunks); 793 if(d->name) free(d->name); 794#ifdef PC98 795 if(d->bootipl) free(d->bootipl); 796 if(d->bootmenu) free(d->bootmenu); 797#else 798#if !defined(__ia64__) 799 if(d->bootmgr) free(d->bootmgr); 800#endif 801#endif 802#if !defined(__ia64__) 803 if(d->boot1) free(d->boot1); 804#endif 805#if defined(__i386__) 806 if(d->boot2) free(d->boot2); 807#endif 808 free(d); 809} 810 811#if 0 812void 813Collapse_Disk(struct disk *d) 814{ 815 816 while(Collapse_Chunk(d, d->chunks)) 817 ; 818} 819#endif 820 821static int 822qstrcmp(const void* a, const void* b) 823{ 824 825 char *str1 = *(char**)a; 826 char *str2 = *(char**)b; 827 return strcmp(str1, str2); 828} 829 830char ** 831Disk_Names() 832{ 833 int disk_cnt; 834 static char **disks; 835 int error; 836 size_t listsize; 837 char *disklist; 838 839 error = sysctlbyname("kern.disks", NULL, &listsize, NULL, 0); 840 if (error) { 841 warn("kern.disks sysctl not available"); 842 return NULL; 843 } 844 845 disks = malloc(sizeof *disks * (1 + MAX_NO_DISKS)); 846 if (disks == NULL) 847 return NULL; 848 disklist = (char *)malloc(listsize + 1); 849 if (disklist == NULL) { 850 free(disks); 851 return NULL; 852 } 853 memset(disks,0,sizeof *disks * (1 + MAX_NO_DISKS)); 854 memset(disklist, 0, listsize + 1); 855 error = sysctlbyname("kern.disks", disklist, &listsize, NULL, 0); 856 if (error) { 857 free(disklist); 858 free(disks); 859 return NULL; 860 } 861 for (disk_cnt = 0; disk_cnt < MAX_NO_DISKS; disk_cnt++) { 862 disks[disk_cnt] = strsep(&disklist, " "); 863 if (disks[disk_cnt] == NULL) 864 break; 865 } 866 qsort(disks, disk_cnt, sizeof(char*), qstrcmp); 867 return disks; 868} 869 870#ifdef PC98 871void 872Set_Boot_Mgr(struct disk *d, const u_char *bootipl, const size_t bootipl_size, 873 const u_char *bootmenu, const size_t bootmenu_size) 874#else 875void 876Set_Boot_Mgr(struct disk *d, const u_char *b, const size_t s) 877#endif 878{ 879#if !defined(__ia64__) 880#ifdef PC98 881 if (bootipl_size % d->sector_size != 0) 882 return; 883 if (d->bootipl) 884 free(d->bootipl); 885 if (!bootipl) { 886 d->bootipl = NULL; 887 } else { 888 d->bootipl_size = bootipl_size; 889 d->bootipl = malloc(bootipl_size); 890 if(!d->bootipl) return; 891 memcpy(d->bootipl, bootipl, bootipl_size); 892 } 893 894 if (bootmenu_size % d->sector_size != 0) 895 return; 896 if (d->bootmenu) 897 free(d->bootmenu); 898 if (!bootmenu) { 899 d->bootmenu = NULL; 900 } else { 901 d->bootmenu_size = bootmenu_size; 902 d->bootmenu = malloc(bootmenu_size); 903 if(!d->bootmenu) return; 904 memcpy(d->bootmenu, bootmenu, bootmenu_size); 905 } 906#else 907 if (s % d->sector_size != 0) 908 return; 909 if (d->bootmgr) 910 free(d->bootmgr); 911 if (!b) { 912 d->bootmgr = NULL; 913 } else { 914 d->bootmgr_size = s; 915 d->bootmgr = malloc(s); 916 if(!d->bootmgr) return; 917 memcpy(d->bootmgr, b, s); 918 } 919#endif 920#endif 921} 922 923int 924Set_Boot_Blocks(struct disk *d, const u_char *b1, const u_char *b2) 925{ 926#if defined(__i386__) 927 if (d->boot1) free(d->boot1); 928 d->boot1 = malloc(512); 929 if(!d->boot1) return -1; 930 memcpy(d->boot1, b1, 512); 931 if (d->boot2) free(d->boot2); 932 d->boot2 = malloc(15 * 512); 933 if(!d->boot2) return -1; 934 memcpy(d->boot2, b2, 15 * 512); 935#elif defined(__alpha__) 936 if (d->boot1) free(d->boot1); 937 d->boot1 = malloc(15 * 512); 938 if(!d->boot1) return -1; 939 memcpy(d->boot1, b1, 15 * 512); 940#elif defined(__ia64__) 941 /* nothing */ 942#else 943/* Should be: #error "Set_Boot_Blocks: unknown arch"; */ 944#endif 945 return 0; 946} 947 948const char * 949slice_type_name( int type, int subtype ) 950{ 951 switch (type) { 952 case 0: return "whole"; 953#ifndef PC98 954 case 1: switch (subtype) { 955 case 1: return "fat (12-bit)"; 956 case 2: return "XENIX /"; 957 case 3: return "XENIX /usr"; 958 case 4: return "fat (16-bit,<=32Mb)"; 959 case 5: return "extended DOS"; 960 case 6: return "fat (16-bit,>32Mb)"; 961 case 7: return "NTFS/HPFS/QNX"; 962 case 8: return "AIX bootable"; 963 case 9: return "AIX data"; 964 case 10: return "OS/2 bootmgr"; 965 case 11: return "fat (32-bit)"; 966 case 12: return "fat (32-bit,LBA)"; 967 case 14: return "fat (16-bit,>32Mb,LBA)"; 968 case 15: return "extended DOS, LBA"; 969 case 18: return "Compaq Diagnostic"; 970 case 84: return "OnTrack diskmgr"; 971 case 100: return "Netware 2.x"; 972 case 101: return "Netware 3.x"; 973 case 115: return "SCO UnixWare"; 974 case 128: return "Minix 1.1"; 975 case 129: return "Minix 1.5"; 976 case 130: return "linux_swap"; 977 case 131: return "ext2fs"; 978 case 166: return "OpenBSD FFS"; /* 0xA6 */ 979 case 169: return "NetBSD FFS"; /* 0xA9 */ 980 case 182: return "OpenBSD"; /* dedicated */ 981 case 183: return "bsd/os"; 982 case 184: return "bsd/os swap"; 983 case 238: return "EFI GPT"; 984 case 239: return "EFI Sys. Part."; 985 default: return "unknown"; 986 } 987#endif 988 case 2: return "fat"; 989 case 3: switch (subtype) { 990#ifdef PC98 991 case 0xc494: return "freebsd"; 992#else 993 case 165: return "freebsd"; 994#endif 995 default: return "unknown"; 996 } 997#ifndef PC98 998 case 4: return "extended"; 999 case 5: return "part"; 1000 case 6: return "unused"; 1001#endif 1002 default: return "unknown"; 1003 } 1004} 1005