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