disk.c revision 105873
1169689Skan/* 2169689Skan * ---------------------------------------------------------------------------- 3169689Skan * "THE BEER-WARE LICENSE" (Revision 42): 4169689Skan * <phk@FreeBSD.org> wrote this file. As long as you retain this notice you 5169689Skan * can do whatever you want with this stuff. If we meet some day, and you think 6169689Skan * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp 7169689Skan * ---------------------------------------------------------------------------- 8169689Skan */ 9169689Skan 10169689Skan#include <sys/cdefs.h> 11169689Skan__FBSDID("$FreeBSD: head/lib/libdisk/disk.c 105873 2002-10-24 13:35:52Z gallatin $"); 12169689Skan 13169689Skan#include <stdio.h> 14169689Skan#include <stdlib.h> 15169689Skan#include <unistd.h> 16169689Skan#include <fcntl.h> 17169689Skan#include <string.h> 18169689Skan#include <err.h> 19169689Skan#include <sys/sysctl.h> 20169689Skan#include <sys/types.h> 21169689Skan#include <sys/stat.h> 22169689Skan#include <sys/ioctl.h> 23169689Skan#include <sys/disklabel.h> 24169689Skan#include <sys/diskslice.h> 25169689Skan#ifndef PC98 26169689Skan#include <sys/diskmbr.h> 27169689Skan#endif 28169689Skan#include <paths.h> 29169689Skan#include "libdisk.h" 30169689Skan 31169689Skan#ifndef PC98 32169689Skan#define HAVE_GEOM 33169689Skan#endif 34169689Skan#include <ctype.h> 35169689Skan#include <errno.h> 36169689Skan#include <assert.h> 37169689Skan 38169689Skan#ifndef PC98 39169689Skan#define DOSPTYP_EXTENDED 5 40169689Skan#endif 41169689Skan 42169689Skan#ifdef DEBUG 43169689Skan#define DPRINT(x) warn x 44169689Skan#define DPRINTX(x) warnx x 45169689Skan#else 46169689Skan#define DPRINT(x) 47169689Skan#define DPRINTX(x) 48169689Skan#endif 49169689Skan 50169689Skanconst char *chunk_n[] = { 51169689Skan "whole", 52169689Skan "unknown", 53169689Skan "fat", 54169689Skan "freebsd", 55169689Skan "extended", 56169689Skan "part", 57169689Skan "unused", 58169689Skan NULL 59169689Skan}; 60169689Skan 61169689Skanstruct disk * 62169689SkanOpen_Disk(const char *name) 63169689Skan{ 64169689Skan return Int_Open_Disk(name, 0); 65169689Skan} 66169689Skan 67169689Skan#ifndef PC98 68169689Skanstatic u_int32_t 69169689SkanRead_Int32(u_int32_t *p) 70169689Skan{ 71169689Skan u_int8_t *bp = (u_int8_t *)p; 72169689Skan return bp[0] | (bp[1] << 8) | (bp[2] << 16) | (bp[3] << 24); 73169689Skan} 74169689Skan#endif 75169689Skan 76169689Skan/* 77169689Skan * XXX BEGIN HACK XXX 78169689Skan * Scan/parse the XML geom data to retrieve what we need to 79169689Skan * carry out the work of Int_Open_Disk. This is a total hack 80169689Skan * and should be replaced with a real XML parser. 81169689Skan */ 82169689Skantypedef enum { 83169689Skan XML_MESH, 84169689Skan XML_MESH_END, 85169689Skan XML_CLASS, 86169689Skan XML_CLASS_END, 87169689Skan XML_GEOM, 88169689Skan XML_GEOM_END, 89169689Skan XML_CONFIG, 90169689Skan XML_CONFIG_END, 91169689Skan XML_PROVIDER, 92169689Skan XML_PROVIDER_END, 93169689Skan XML_NAME, 94169689Skan XML_NAME_END, 95169689Skan XML_INDEX, 96169689Skan XML_INDEX_END, 97169689Skan XML_SECLENGTH, 98169689Skan XML_SECLENGTH_END, 99169689Skan XML_SECOFFSET, 100169689Skan XML_SECOFFSET_END, 101169689Skan XML_TYPE, 102169689Skan XML_TYPE_END, 103169689Skan XML_MEDIASIZE, 104169689Skan XML_MEDIASIZE_END, 105169689Skan XML_SECTORSIZE, 106169689Skan XML_SECTORSIZE_END, 107169689Skan XML_FWHEADS, 108169689Skan XML_FWHEADS_END, 109169689Skan XML_FWSECTORS, 110169689Skan XML_FWSECTORS_END, 111169689Skan 112169689Skan XML_OTHER, 113169689Skan XML_OTHER_END 114169689Skan} XMLToken; 115169689Skan 116169689Skanconst struct { 117169689Skan XMLToken t; 118169689Skan const char* token; 119169689Skan const char* name; 120169689Skan} xmltokens[] = { 121169689Skan { XML_MESH, "mesh", "XML_MESH" }, 122169689Skan { XML_CLASS, "class", "XML_CLASS" }, 123169689Skan { XML_GEOM, "geom", "XML_GEOM" }, 124169689Skan { XML_CONFIG, "config", "XML_CONFIG" }, 125169689Skan { XML_PROVIDER, "provider", "XML_PROVIDE" }, 126169689Skan { XML_NAME, "name", "XML_NAME" }, 127169689Skan { XML_INDEX, "index", "XML_INDEX" }, 128169689Skan { XML_SECLENGTH, "seclength", "XML_SECLENGTH" }, 129169689Skan { XML_SECOFFSET, "secoffset", "XML_SECOFFSET" }, 130169689Skan { XML_TYPE, "type", "XML_TYPE" }, 131169689Skan { XML_FWHEADS, "fwheads", "XML_FWHEADS" }, 132169689Skan { XML_FWSECTORS, "fwsectors", "XML_FWSECTORS" }, 133169689Skan { XML_MEDIASIZE, "mediasize", "XML_MEDIASIZE" }, 134169689Skan { XML_SECTORSIZE, "sectorsize", "XML_SECTORSIZE" }, 135169689Skan /* NB: this must be last */ 136169689Skan { XML_OTHER, NULL, "XML_OTHER" }, 137169689Skan}; 138169689Skan#define N(x) (sizeof (x) / sizeof (x[0])) 139169689Skan 140169689Skan#ifdef DEBUG 141169689Skanstatic const char* 142169689Skanxmltokenname(XMLToken t) 143169689Skan{ 144169689Skan int i; 145169689Skan 146169689Skan for (i = 0; i < N(xmltokens); i++) { 147169689Skan if (t == xmltokens[i].t) 148169689Skan return xmltokens[i].name; 149169689Skan if ((t-1) == xmltokens[i].t) { 150169689Skan static char tbuf[80]; 151169689Skan snprintf(tbuf, sizeof (tbuf), "%s_END", 152169689Skan xmltokens[i].name); 153169689Skan return tbuf; 154169689Skan } 155169689Skan } 156169689Skan return "???"; 157169689Skan} 158169689Skan#endif /*DEBUG*/ 159169689Skan 160169689Skan/* 161169689Skan * Parse the next XML token delimited by <..>. If the token 162169689Skan * has a "builtin terminator" (<... />) then just skip it and 163169689Skan * go the next token. 164169689Skan */ 165169689Skanstatic int 166169689Skanxmltoken(const char *start, const char **next, XMLToken *t) 167169689Skan{ 168169689Skan const char *cp = start; 169169689Skan const char *token; 170169689Skan int i; 171169689Skan 172169689Skanagain: 173169689Skan while (*cp != '<') { 174169689Skan if (*cp == '\0') { 175169689Skan *next = cp; 176169689Skan DPRINTX(("xmltoken: EOD")); 177169689Skan return 0; 178169689Skan } 179169689Skan cp++; 180169689Skan } 181169689Skan token = ++cp; 182169689Skan for (; *cp && *cp != '>' && !isspace(*cp); cp++) 183169689Skan ; 184169689Skan if (*cp == '\0') { 185169689Skan *next = cp; 186169689Skan DPRINTX(("xmltoken: EOD")); 187169689Skan return 0; 188169689Skan } 189169689Skan *t = (*token == '/'); 190169689Skan if (*t) 191169689Skan token++; 192169689Skan for (i = 0; xmltokens[i].token != NULL; i++) 193169689Skan if (strncasecmp(token, xmltokens[i].token, cp-token) == 0) 194169689Skan break; 195169689Skan *t += xmltokens[i].t; 196169689Skan /* now collect the remainder of the string */ 197169689Skan for (; *cp != '>' && *cp != '\0'; cp++) 198169689Skan ; 199169689Skan if (*cp == '\0') { 200169689Skan *next = cp; 201169689Skan DPRINTX(("xmltoken: EOD")); 202169689Skan return 0; 203169689Skan } 204169689Skan if (cp > token && cp[-1] == '/') { 205169689Skan /* e.g. <geom ref="0xc1c8c100"/> */ 206169689Skan start = cp+1; 207169689Skan goto again; 208169689Skan } 209169689Skan *next = cp+1; 210169689Skan DPRINTX(("xmltoken: %s \"%.*s\"", xmltokenname(*t), cp-token, token)); 211169689Skan return 1; 212169689Skan} 213169689Skan 214169689Skan/* 215169689Skan * Parse and discard XML up to the token terminator. 216169689Skan */ 217169689Skanstatic int 218169689Skandiscardxml(const char **next, XMLToken terminator) 219169689Skan{ 220169689Skan const char *xml = *next; 221169689Skan XMLToken t; 222169689Skan 223169689Skan DPRINTX(("discard XML up to %s", xmltokenname(terminator))); 224169689Skan for (;;) { 225169689Skan if (xmltoken(xml, next, &t) == 0) 226169689Skan return EINVAL; 227169689Skan if (t == terminator) 228169689Skan break; 229169689Skan if ((t & 1) == 0) { 230169689Skan int error = discardxml(next, t+1); 231169689Skan if (error) 232169689Skan return error; 233169689Skan } 234169689Skan xml = *next; 235169689Skan } 236169689Skan return 0; 237169689Skan} 238169689Skan 239169689Skan/* 240169689Skan * Parse XML from between a range of markers; e.g. <mesh> ... </mesh>. 241169689Skan * When the specified class name is located we descend looking for the 242169689Skan * geometry information given by diskname. Once inside there we process 243169689Skan * tags calling f back for each useful one. The arg is passed into f 244169689Skan * for use in storing the parsed data. 245169689Skan */ 246169689Skanstatic int 247169689Skanparsexmlpair( 248169689Skan const char *xml, 249169689Skan const char **next, 250169689Skan const char *classname, 251169689Skan XMLToken terminator, 252169689Skan const char *diskname, 253169689Skan int (*f)(void *, XMLToken, u_int *, u_int64_t), 254169689Skan void *arg 255169689Skan) 256169689Skan{ 257169689Skan const char *cp; 258169689Skan XMLToken t; 259169689Skan int error; 260169689Skan u_int ix = (u_int) -1; 261169689Skan 262169689Skan DPRINTX(("parse XML up to %s", xmltokenname(terminator))); 263169689Skan do { 264169689Skan if (xmltoken(xml, next, &t) == 0) { 265169689Skan error = EINVAL; 266169689Skan break; 267169689Skan } 268169689Skan if (t == terminator) { 269169689Skan error = 0; 270169689Skan break; 271169689Skan } 272169689Skan if (t & 1) { /* </mumble> w/o matching <mumble> */ 273169689Skan DPRINTX(("Unexpected token %s", xmltokenname(t))); 274169689Skan error = EINVAL; 275169689Skan break; 276169689Skan } 277169689Skan switch ((int) t) { 278169689Skan case XML_NAME: 279169689Skan for (cp = *next; *cp && *cp != '<'; cp++) 280169689Skan ; 281169689Skan if (*cp == '\0') { 282169689Skan DPRINTX(("parsexmlpair: EOD")); 283169689Skan error = EINVAL; 284169689Skan goto done; 285169689Skan } 286169689Skan DPRINTX(("parsexmlpair: \"%.*s\"", cp-*next, *next)); 287169689Skan switch ((int) terminator) { 288169689Skan case XML_CLASS_END: 289169689Skan if (strncasecmp(*next, classname, cp-*next)) 290169689Skan return discardxml(next, terminator); 291169689Skan break; 292169689Skan case XML_GEOM_END: 293169689Skan if (strncasecmp(*next, diskname, cp-*next)) 294169689Skan return discardxml(next, terminator); 295169689Skan break; 296169689Skan } 297169689Skan break; 298169689Skan case XML_SECOFFSET: 299169689Skan case XML_SECLENGTH: 300169689Skan case XML_TYPE: 301169689Skan if (ix == (u_int) -1) { 302169689Skan DPRINTX(("parsexmlpair: slice data w/o " 303169689Skan "preceding index")); 304169689Skan error = EINVAL; 305169689Skan goto done; 306169689Skan } 307169689Skan /* fall thru... */ 308169689Skan case XML_INDEX: 309169689Skan case XML_FWHEADS: 310169689Skan case XML_FWSECTORS: 311169689Skan case XML_MEDIASIZE: 312169689Skan case XML_SECTORSIZE: 313169689Skan if (terminator != XML_CONFIG_END && 314169689Skan terminator != XML_PROVIDER_END) { 315169689Skan DPRINTX(("parsexmlpair: %s in unexpected " 316169689Skan "context: terminator %s", 317169689Skan xmltokenname(t), 318169689Skan xmltokenname(terminator))); 319169689Skan error = EINVAL; 320169689Skan goto done; 321169689Skan } 322169689Skan error = (*f)(arg, t, &ix, strtoull(*next, NULL, 10)); 323169689Skan if (error) 324169689Skan goto done; 325169689Skan break; 326169689Skan } 327169689Skan error = parsexmlpair(*next, &xml, classname, 328169689Skan t+1, diskname, f, arg); 329169689Skan } while (error == 0); 330169689Skandone: 331169689Skan return error; 332169689Skan} 333169689Skan 334169689Skan/* 335169689Skan * XML parser. Just barely smart enough to handle the 336169689Skan * gibberish that geom passed back from the kernel. 337169689Skan */ 338169689Skanstatic int 339169689Skanxmlparse( 340169689Skan const char *confxml, 341169689Skan const char *classname, 342169689Skan const char *diskname, 343169689Skan int (*f)(void *, XMLToken, u_int *, u_int64_t), 344169689Skan void *arg 345169689Skan) 346169689Skan{ 347169689Skan const char *next; 348169689Skan XMLToken t; 349169689Skan int error; 350169689Skan 351169689Skan next = confxml; 352169689Skan while (xmltoken(next, &next, &t) && t != XML_MESH) 353169689Skan ; 354169689Skan if (t == XML_MESH) 355169689Skan error = parsexmlpair(next, &next, classname, XML_MESH_END, diskname, f, arg); 356169689Skan else { 357169689Skan DPRINTX(("xmlparse: expecting mesh token, got %s", 358169689Skan xmltokenname(t))); 359169689Skan error = EINVAL; 360169689Skan } 361169689Skan 362169689Skan return (error ? -1 : 0); 363169689Skan} 364169689Skan 365169689Skan/* 366169689Skan * Callback to collect slice-related data. 367169689Skan */ 368169689Skanstatic int 369169689SkanassignToSlice(void *arg, XMLToken t, u_int *slice, u_int64_t v) 370169689Skan{ 371169689Skan struct diskslices *ds = (struct diskslices *) arg; 372169689Skan 373169689Skan switch ((int) t) { 374169689Skan case XML_INDEX: 375169689Skan *slice = BASE_SLICE + (u_int) v; 376169689Skan if (*slice >= MAX_SLICES) { 377169689Skan DPRINTX(("assignToSlice: invalid slice index %u > max %u", 378169689Skan *slice, MAX_SLICES)); 379169689Skan return EINVAL; 380169689Skan } 381169689Skan if (*slice >= ds->dss_nslices) 382169689Skan ds->dss_nslices = (*slice)+1; 383169689Skan break; 384169689Skan case XML_SECOFFSET: 385169689Skan ds->dss_slices[*slice].ds_offset = (u_long) v; 386169689Skan break; 387169689Skan case XML_SECLENGTH: 388169689Skan ds->dss_slices[*slice].ds_size = (u_long) v; 389169689Skan break; 390169689Skan case XML_TYPE: 391169689Skan ds->dss_slices[*slice].ds_type = (int) v; 392169689Skan break; 393169689Skan } 394169689Skan return 0; 395169689Skan} 396169689Skan 397169689Skan/* 398169689Skan * Callback to collect disk-related data. 399169689Skan */ 400169689Skanstatic int 401169689SkanassignToDisk(void *arg, XMLToken t, u_int *slice, u_int64_t v) 402169689Skan{ 403169689Skan struct disklabel *dl = (struct disklabel *) arg; 404169689Skan 405169689Skan switch ((int) t) { 406169689Skan case XML_FWHEADS: 407169689Skan dl->d_ntracks = (u_int32_t) v; 408169689Skan case XML_FWSECTORS: 409169689Skan dl->d_nsectors = (u_int32_t) v; 410169689Skan break; 411169689Skan case XML_MEDIASIZE: 412169689Skan /* store this temporarily; it gets moved later */ 413169689Skan dl->d_secpercyl = v >> 32; 414169689Skan dl->d_secperunit = v & 0xffffffff; 415169689Skan break; 416169689Skan case XML_SECTORSIZE: 417169689Skan dl->d_secsize = (u_int32_t) v; 418169689Skan break; 419169689Skan } 420169689Skan return 0; 421169689Skan} 422169689Skan 423169689Skan#ifdef __i386__ 424169689Skan/* 425169689Skan * Callback to collect partition-related data. 426169689Skan */ 427169689Skanstatic int 428169689SkanassignToPartition(void *arg, XMLToken t, u_int *part, u_int64_t v) 429169689Skan{ 430169689Skan struct disklabel *dl = (struct disklabel *) arg; 431169689Skan 432169689Skan switch ((int) t) { 433169689Skan case XML_INDEX: 434169689Skan *part = (u_int) v; 435169689Skan if (*part >= MAXPARTITIONS) { 436169689Skan DPRINTX(("assignToPartition: invalid partition index %u > max %u", 437169689Skan *part, MAXPARTITIONS)); 438169689Skan return EINVAL; 439169689Skan } 440169689Skan if (*part >= dl->d_npartitions) 441169689Skan 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#endif 782 Debug_Chunk(d->chunks); 783} 784 785void 786Free_Disk(struct disk *d) 787{ 788 if(d->chunks) Free_Chunk(d->chunks); 789 if(d->name) free(d->name); 790#ifdef PC98 791 if(d->bootipl) free(d->bootipl); 792 if(d->bootmenu) free(d->bootmenu); 793#else 794 if(d->bootmgr) free(d->bootmgr); 795#endif 796 if(d->boot1) free(d->boot1); 797#if defined(__i386__) 798 if(d->boot2) free(d->boot2); 799#endif 800 free(d); 801} 802 803#if 0 804void 805Collapse_Disk(struct disk *d) 806{ 807 808 while(Collapse_Chunk(d, d->chunks)) 809 ; 810} 811#endif 812 813static int 814qstrcmp(const void* a, const void* b) 815{ 816 817 char *str1 = *(char**)a; 818 char *str2 = *(char**)b; 819 return strcmp(str1, str2); 820} 821 822char ** 823Disk_Names() 824{ 825 int disk_cnt; 826 static char **disks; 827 int error; 828 size_t listsize; 829 char *disklist; 830 831 error = sysctlbyname("kern.disks", NULL, &listsize, NULL, 0); 832 if (error) { 833 warn("kern.disks sysctl not available"); 834 return NULL; 835 } 836 837 disks = malloc(sizeof *disks * (1 + MAX_NO_DISKS)); 838 if (disks == NULL) 839 return NULL; 840 disklist = (char *)malloc(listsize + 1); 841 if (disklist == NULL) { 842 free(disks); 843 return NULL; 844 } 845 memset(disks,0,sizeof *disks * (1 + MAX_NO_DISKS)); 846 memset(disklist, 0, listsize + 1); 847 error = sysctlbyname("kern.disks", disklist, &listsize, NULL, 0); 848 if (error) { 849 free(disklist); 850 free(disks); 851 return NULL; 852 } 853 for (disk_cnt = 0; disk_cnt < MAX_NO_DISKS; disk_cnt++) { 854 disks[disk_cnt] = strsep(&disklist, " "); 855 if (disks[disk_cnt] == NULL) 856 break; 857 } 858 qsort(disks, disk_cnt, sizeof(char*), qstrcmp); 859 return disks; 860} 861 862#ifdef PC98 863void 864Set_Boot_Mgr(struct disk *d, const u_char *bootipl, const size_t bootipl_size, 865 const u_char *bootmenu, const size_t bootmenu_size) 866#else 867void 868Set_Boot_Mgr(struct disk *d, const u_char *b, const size_t s) 869#endif 870{ 871#ifdef PC98 872 if (bootipl_size % d->sector_size != 0) 873 return; 874 if (d->bootipl) 875 free(d->bootipl); 876 if (!bootipl) { 877 d->bootipl = NULL; 878 } else { 879 d->bootipl_size = bootipl_size; 880 d->bootipl = malloc(bootipl_size); 881 if(!d->bootipl) return; 882 memcpy(d->bootipl, bootipl, bootipl_size); 883 } 884 885 if (bootmenu_size % d->sector_size != 0) 886 return; 887 if (d->bootmenu) 888 free(d->bootmenu); 889 if (!bootmenu) { 890 d->bootmenu = NULL; 891 } else { 892 d->bootmenu_size = bootmenu_size; 893 d->bootmenu = malloc(bootmenu_size); 894 if(!d->bootmenu) return; 895 memcpy(d->bootmenu, bootmenu, bootmenu_size); 896 } 897#else 898 if (s % d->sector_size != 0) 899 return; 900 if (d->bootmgr) 901 free(d->bootmgr); 902 if (!b) { 903 d->bootmgr = NULL; 904 } else { 905 d->bootmgr_size = s; 906 d->bootmgr = malloc(s); 907 if(!d->bootmgr) return; 908 memcpy(d->bootmgr, b, s); 909 } 910#endif 911} 912 913int 914Set_Boot_Blocks(struct disk *d, const u_char *b1, const u_char *b2) 915{ 916#if defined(__i386__) 917 if (d->boot1) free(d->boot1); 918 d->boot1 = malloc(512); 919 if(!d->boot1) return -1; 920 memcpy(d->boot1, b1, 512); 921 if (d->boot2) free(d->boot2); 922 d->boot2 = malloc(15 * 512); 923 if(!d->boot2) return -1; 924 memcpy(d->boot2, b2, 15 * 512); 925#elif defined(__alpha__) 926 if (d->boot1) free(d->boot1); 927 d->boot1 = malloc(15 * 512); 928 if(!d->boot1) return -1; 929 memcpy(d->boot1, b1, 15 * 512); 930#endif 931 return 0; 932} 933 934const char * 935slice_type_name( int type, int subtype ) 936{ 937 switch (type) { 938 case 0: return "whole"; 939#ifndef PC98 940 case 1: switch (subtype) { 941 case 1: return "fat (12-bit)"; 942 case 2: return "XENIX /"; 943 case 3: return "XENIX /usr"; 944 case 4: return "fat (16-bit,<=32Mb)"; 945 case 5: return "extended DOS"; 946 case 6: return "fat (16-bit,>32Mb)"; 947 case 7: return "NTFS/HPFS/QNX"; 948 case 8: return "AIX bootable"; 949 case 9: return "AIX data"; 950 case 10: return "OS/2 bootmgr"; 951 case 11: return "fat (32-bit)"; 952 case 12: return "fat (32-bit,LBA)"; 953 case 14: return "fat (16-bit,>32Mb,LBA)"; 954 case 15: return "extended DOS, LBA"; 955 case 18: return "Compaq Diagnostic"; 956 case 84: return "OnTrack diskmgr"; 957 case 100: return "Netware 2.x"; 958 case 101: return "Netware 3.x"; 959 case 115: return "SCO UnixWare"; 960 case 128: return "Minix 1.1"; 961 case 129: return "Minix 1.5"; 962 case 130: return "linux_swap"; 963 case 131: return "ext2fs"; 964 case 166: return "OpenBSD FFS"; /* 0xA6 */ 965 case 169: return "NetBSD FFS"; /* 0xA9 */ 966 case 182: return "OpenBSD"; /* dedicated */ 967 case 183: return "bsd/os"; 968 case 184: return "bsd/os swap"; 969 case 238: return "EFI GPT"; 970 case 239: return "EFI Sys. Part."; 971 default: return "unknown"; 972 } 973#endif 974 case 2: return "fat"; 975 case 3: switch (subtype) { 976#ifdef PC98 977 case 0xc494: return "freebsd"; 978#else 979 case 165: return "freebsd"; 980#endif 981 default: return "unknown"; 982 } 983#ifndef PC98 984 case 4: return "extended"; 985 case 5: return "part"; 986 case 6: return "unused"; 987#endif 988 default: return "unknown"; 989 } 990} 991