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