disk.c revision 105784
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 105784 2002-10-23 10:47:00Z 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 if (Add_Chunk(d, 0, size, name, whole, 0, 0, "-")) 628 DPRINT(("Failed to add 'whole' chunk")); 629 630#ifdef __i386__ 631#ifdef PC98 632 /* XXX -- Quick Hack! 633 * Check MS-DOS MO 634 */ 635 if ((*p == 0xf0 || *p == 0xf8) && 636 (*(p+1) == 0xff) && 637 (*(p+2) == 0xff)) { 638 Add_Chunk(d, 0, size, name, fat, 0xa0a0, 0, name); 639 free(p); 640 goto pc98_mo_done; 641 } 642 free(p); 643#endif /* PC98 */ 644 for(i=BASE_SLICE;i<ds.dss_nslices;i++) { 645 char sname[20]; 646 char pname[20]; 647 chunk_e ce; 648 u_long flags=0; 649 int subtype=0; 650 int j; 651 652 if (! ds.dss_slices[i].ds_size) 653 continue; 654 snprintf(sname, sizeof(sname), "%ss%d", name, i - 1); 655#ifdef PC98 656 subtype = ds.dss_slices[i].ds_type | 657 ds.dss_slices[i].ds_subtype << 8; 658 switch (ds.dss_slices[i].ds_type & 0x7f) { 659 case 0x14: 660 ce = freebsd; 661 break; 662 case 0x20: 663 case 0x21: 664 case 0x22: 665 case 0x23: 666 case 0x24: 667 ce = fat; 668 break; 669#else /* IBM-PC */ 670 subtype = ds.dss_slices[i].ds_type; 671 switch (ds.dss_slices[i].ds_type) { 672 case 0xa5: 673 ce = freebsd; 674 break; 675 case 0x1: 676 case 0x6: 677 case 0x4: 678 case 0xb: 679 case 0xc: 680 case 0xe: 681 ce = fat; 682 break; 683 case DOSPTYP_EXTENDED: 684 case 0xf: 685 ce = extended; 686 break; 687#endif 688 default: 689 ce = unknown; 690 break; 691 } 692#ifdef PC98 693 if (Add_Chunk(d, ds.dss_slices[i].ds_offset, 694 ds.dss_slices[i].ds_size, sname, ce, subtype, flags, 695 ds.dss_slices[i].ds_name)) 696#else 697 if (Add_Chunk(d, ds.dss_slices[i].ds_offset, 698 ds.dss_slices[i].ds_size, sname, ce, subtype, flags, "")) 699#endif 700 DPRINT(("failed to add chunk for slice %d", i - 1)); 701 702#ifdef PC98 703 if ((ds.dss_slices[i].ds_type & 0x7f) != 0x14) 704#else 705 if (ds.dss_slices[i].ds_type != 0xa5) 706#endif 707 continue; 708#ifdef HAVE_GEOM 709 if (xmlparse(confxml, "BSD", sname, assignToPartition, &dl) != 0) { 710 DPRINTX(("Error parsing MBR geometry specification.")); 711 goto bad; 712 } 713#else 714 { 715 struct disklabel dl; 716 int k; 717 718 strlcpy(pname, _PATH_DEV, sizeof(pname)); 719 strlcat(pname, sname, sizeof(pname)); 720 j = open(pname, O_RDONLY); 721 if (j < 0) { 722 DPRINT(("open(%s)", pname)); 723 continue; 724 } 725 k = ioctl(j, DIOCGDINFO, &dl); 726 if (k < 0) { 727 DPRINT(("ioctl(%s, DIOCGDINFO)", pname)); 728 close(j); 729 continue; 730 } 731 close(j); 732 } 733#endif /*HAVE_GEOM*/ 734 735 for(j = 0; j <= dl.d_npartitions; j++) { 736 if (j == RAW_PART) 737 continue; 738 if (j == 3) 739 continue; 740 if (j == dl.d_npartitions) { 741 j = 3; 742 dl.d_npartitions = 0; 743 } 744 if (!dl.d_partitions[j].p_size) 745 continue; 746 if (dl.d_partitions[j].p_size + 747 dl.d_partitions[j].p_offset > 748 ds.dss_slices[i].ds_size) 749 continue; 750 snprintf(pname, sizeof(pname), "%s%c", sname, j + 'a'); 751 if (Add_Chunk(d, 752 dl.d_partitions[j].p_offset + 753 ds.dss_slices[i].ds_offset, 754 dl.d_partitions[j].p_size, 755 pname,part, 756 dl.d_partitions[j].p_fstype, 757#ifdef PC98 758 0, 759 ds.dss_slices[i].ds_name) && j != 3) 760#else 761 0, "") && j != 3) 762#endif 763 DPRINT(( 764 "Failed to add chunk for partition %c [%lu,%lu]", 765 j + 'a', dl.d_partitions[j].p_offset, 766 dl.d_partitions[j].p_size)); 767 } 768 } 769#endif /* __i386__ */ 770#ifdef __alpha__ 771 { 772 struct disklabel dl; 773 char pname[20]; 774 int j,k; 775 776 strlcpy(pname, _PATH_DEV, sizeof(pname)); 777 strlcat(pname, name, sizeof(pname)); 778 j = open(pname, O_RDONLY); 779 if (j < 0) { 780 DPRINT(("open(%s)", pname)); 781 goto nolabel; 782 } 783 k = ioctl(j, DIOCGDINFO, &dl); 784 if (k < 0) { 785 DPRINT(("ioctl(%s, DIOCGDINFO)", pname)); 786 close(j); 787 goto nolabel; 788 } 789 close(j); 790 All_FreeBSD(d, 1); 791 792 for(j = 0; j <= dl.d_npartitions; j++) { 793 if (j == RAW_PART) 794 continue; 795 if (j == 3) 796 continue; 797 if (j == dl.d_npartitions) { 798 j = 3; 799 dl.d_npartitions = 0; 800 } 801 if (!dl.d_partitions[j].p_size) 802 continue; 803 if (dl.d_partitions[j].p_size + 804 dl.d_partitions[j].p_offset > 805 ds.dss_slices[WHOLE_DISK_SLICE].ds_size) 806 continue; 807 snprintf(pname, sizeof(pname), "%s%c", name, j + 'a'); 808 if (Add_Chunk(d, 809 dl.d_partitions[j].p_offset, 810 dl.d_partitions[j].p_size, 811 pname,part, 812 dl.d_partitions[j].p_fstype, 813 0, "") && j != 3) 814 DPRINT(( 815 "Failed to add chunk for partition %c [%lu,%lu]", 816 j + 'a', dl.d_partitions[j].p_offset, 817 dl.d_partitions[j].p_size)); 818 } 819 nolabel:; 820 } 821#endif /* __alpha__ */ 822#ifdef PC98 823pc98_mo_done: 824#endif 825 close(fd); 826 Fixup_Names(d); 827 return d; 828bad: 829 if (confxml != NULL) 830 free(confxml); 831 if (fd >= 0) 832 close(fd); 833 return NULL; 834} 835 836void 837Debug_Disk(struct disk *d) 838{ 839 printf("Debug_Disk(%s)", d->name); 840#if 0 841 printf(" real_geom=%lu/%lu/%lu", d->real_cyl, d->real_hd, d->real_sect); 842#endif 843 printf(" bios_geom=%lu/%lu/%lu = %lu\n", 844 d->bios_cyl, d->bios_hd, d->bios_sect, 845 d->bios_cyl * d->bios_hd * d->bios_sect); 846#if defined(PC98) 847 printf(" boot1=%p, boot2=%p, bootipl=%p, bootmenu=%p\n", 848 d->boot1, d->boot2, d->bootipl, d->bootmenu); 849#elif defined(__i386__) 850 printf(" boot1=%p, boot2=%p, bootmgr=%p\n", 851 d->boot1, d->boot2, d->bootmgr); 852#elif defined(__alpha__) 853 printf(" boot1=%p, bootmgr=%p\n", 854 d->boot1, d->bootmgr); 855#endif 856 Debug_Chunk(d->chunks); 857} 858 859void 860Free_Disk(struct disk *d) 861{ 862 if(d->chunks) Free_Chunk(d->chunks); 863 if(d->name) free(d->name); 864#ifdef PC98 865 if(d->bootipl) free(d->bootipl); 866 if(d->bootmenu) free(d->bootmenu); 867#else 868 if(d->bootmgr) free(d->bootmgr); 869#endif 870 if(d->boot1) free(d->boot1); 871#if defined(__i386__) 872 if(d->boot2) free(d->boot2); 873#endif 874 free(d); 875} 876 877#if 0 878void 879Collapse_Disk(struct disk *d) 880{ 881 882 while(Collapse_Chunk(d, d->chunks)) 883 ; 884} 885#endif 886 887#ifdef PC98 888static char * device_list[] = {"wd", "aacd", "ad", "da", "afd", "fla", "idad", "mlxd", "amrd", "twed", "ar", "fd", 0}; 889#else 890static char * device_list[] = {"aacd", "ad", "da", "afd", "fla", "idad", "mlxd", "amrd", "twed", "ar", "fd", 0}; 891#endif 892 893int qstrcmp(const void* a, const void* b) { 894 895 char *str1 = *(char**)a; 896 char *str2 = *(char**)b; 897 return strcmp(str1, str2); 898 899} 900 901char ** 902Disk_Names() 903{ 904 int i,j,disk_cnt; 905 char disk[25]; 906 char diskname[25]; 907 struct stat st; 908 struct diskslices ds; 909 int fd; 910 static char **disks; 911 int error; 912 size_t listsize; 913 char *disklist; 914 915 disks = malloc(sizeof *disks * (1 + MAX_NO_DISKS)); 916 if (disks == NULL) 917 return NULL; 918 memset(disks,0,sizeof *disks * (1 + MAX_NO_DISKS)); 919 error = sysctlbyname("kern.disks", NULL, &listsize, NULL, 0); 920 if (!error) { 921 disklist = (char *)malloc(listsize+1); 922 if (disklist == NULL) { 923 free(disks); 924 return NULL; 925 } 926 memset(disklist, 0, listsize+1); 927 error = sysctlbyname("kern.disks", disklist, &listsize, NULL, 0); 928 if (error) { 929 free(disklist); 930 free(disks); 931 return NULL; 932 } 933 for (disk_cnt = 0; disk_cnt < MAX_NO_DISKS; disk_cnt++) { 934 disks[disk_cnt] = strsep(&disklist, " "); 935 if (disks[disk_cnt] == NULL) 936 break; 937 } 938 } else { 939 warn("kern.disks sysctl not available"); 940 disk_cnt = 0; 941 for (j = 0; device_list[j]; j++) { 942 if(disk_cnt >= MAX_NO_DISKS) 943 break; 944 for (i = 0; i < MAX_NO_DISKS; i++) { 945 snprintf(diskname, sizeof(diskname), "%s%d", 946 device_list[j], i); 947 snprintf(disk, sizeof(disk), _PATH_DEV"%s", diskname); 948 if (stat(disk, &st) || !(st.st_mode & S_IFCHR)) 949 continue; 950 if ((fd = open(disk, O_RDWR)) == -1) 951 continue; 952 if (ioctl(fd, DIOCGSLICEINFO, &ds) == -1) { 953 DPRINT(("DIOCGSLICEINFO %s", disk)); 954 close(fd); 955 continue; 956 } 957 close(fd); 958 disks[disk_cnt++] = strdup(diskname); 959 if(disk_cnt >= MAX_NO_DISKS) 960 break; 961 } 962 } 963 } 964 qsort(disks, disk_cnt, sizeof(char*), qstrcmp); 965 966 return disks; 967} 968 969#ifdef PC98 970void 971Set_Boot_Mgr(struct disk *d, const u_char *bootipl, const size_t bootipl_size, 972 const u_char *bootmenu, const size_t bootmenu_size) 973#else 974void 975Set_Boot_Mgr(struct disk *d, const u_char *b, const size_t s) 976#endif 977{ 978#ifdef PC98 979 if (bootipl_size % d->sector_size != 0) 980 return; 981 if (d->bootipl) 982 free(d->bootipl); 983 if (!bootipl) { 984 d->bootipl = NULL; 985 } else { 986 d->bootipl_size = bootipl_size; 987 d->bootipl = malloc(bootipl_size); 988 if(!d->bootipl) return; 989 memcpy(d->bootipl, bootipl, bootipl_size); 990 } 991 992 if (bootmenu_size % d->sector_size != 0) 993 return; 994 if (d->bootmenu) 995 free(d->bootmenu); 996 if (!bootmenu) { 997 d->bootmenu = NULL; 998 } else { 999 d->bootmenu_size = bootmenu_size; 1000 d->bootmenu = malloc(bootmenu_size); 1001 if(!d->bootmenu) return; 1002 memcpy(d->bootmenu, bootmenu, bootmenu_size); 1003 } 1004#else 1005 if (s % d->sector_size != 0) 1006 return; 1007 if (d->bootmgr) 1008 free(d->bootmgr); 1009 if (!b) { 1010 d->bootmgr = NULL; 1011 } else { 1012 d->bootmgr_size = s; 1013 d->bootmgr = malloc(s); 1014 if(!d->bootmgr) return; 1015 memcpy(d->bootmgr, b, s); 1016 } 1017#endif 1018} 1019 1020int 1021Set_Boot_Blocks(struct disk *d, const u_char *b1, const u_char *b2) 1022{ 1023#if defined(__i386__) 1024 if (d->boot1) free(d->boot1); 1025 d->boot1 = malloc(512); 1026 if(!d->boot1) return -1; 1027 memcpy(d->boot1, b1, 512); 1028 if (d->boot2) free(d->boot2); 1029 d->boot2 = malloc(15 * 512); 1030 if(!d->boot2) return -1; 1031 memcpy(d->boot2, b2, 15 * 512); 1032#elif defined(__alpha__) 1033 if (d->boot1) free(d->boot1); 1034 d->boot1 = malloc(15 * 512); 1035 if(!d->boot1) return -1; 1036 memcpy(d->boot1, b1, 15 * 512); 1037#endif 1038 return 0; 1039} 1040 1041const char * 1042slice_type_name( int type, int subtype ) 1043{ 1044 switch (type) { 1045 case 0: return "whole"; 1046#ifndef PC98 1047 case 1: switch (subtype) { 1048 case 1: return "fat (12-bit)"; 1049 case 2: return "XENIX /"; 1050 case 3: return "XENIX /usr"; 1051 case 4: return "fat (16-bit,<=32Mb)"; 1052 case 5: return "extended DOS"; 1053 case 6: return "fat (16-bit,>32Mb)"; 1054 case 7: return "NTFS/HPFS/QNX"; 1055 case 8: return "AIX bootable"; 1056 case 9: return "AIX data"; 1057 case 10: return "OS/2 bootmgr"; 1058 case 11: return "fat (32-bit)"; 1059 case 12: return "fat (32-bit,LBA)"; 1060 case 14: return "fat (16-bit,>32Mb,LBA)"; 1061 case 15: return "extended DOS, LBA"; 1062 case 18: return "Compaq Diagnostic"; 1063 case 84: return "OnTrack diskmgr"; 1064 case 100: return "Netware 2.x"; 1065 case 101: return "Netware 3.x"; 1066 case 115: return "SCO UnixWare"; 1067 case 128: return "Minix 1.1"; 1068 case 129: return "Minix 1.5"; 1069 case 130: return "linux_swap"; 1070 case 131: return "ext2fs"; 1071 case 166: return "OpenBSD FFS"; /* 0xA6 */ 1072 case 169: return "NetBSD FFS"; /* 0xA9 */ 1073 case 182: return "OpenBSD"; /* dedicated */ 1074 case 183: return "bsd/os"; 1075 case 184: return "bsd/os swap"; 1076 case 238: return "EFI GPT"; 1077 case 239: return "EFI Sys. Part."; 1078 default: return "unknown"; 1079 } 1080#endif 1081 case 2: return "fat"; 1082 case 3: switch (subtype) { 1083#ifdef PC98 1084 case 0xc494: return "freebsd"; 1085#else 1086 case 165: return "freebsd"; 1087#endif 1088 default: return "unknown"; 1089 } 1090#ifndef PC98 1091 case 4: return "extended"; 1092 case 5: return "part"; 1093 case 6: return "unused"; 1094#endif 1095 default: return "unknown"; 1096 } 1097} 1098