disk.c revision 105816
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 105816 2002-10-23 19:52:32Z 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#ifndef PC98 32#define HAVE_GEOM 33#endif 34#ifdef HAVE_GEOM 35#include <ctype.h> 36#include <errno.h> 37#include <assert.h> 38#endif /*HAVE_GEOM*/ 39 40#ifndef PC98 41#define DOSPTYP_EXTENDED 5 42#define DOSPTYP_ONTRACK 84 43#endif 44 45#ifdef DEBUG 46#define DPRINT(x) warn x 47#define DPRINTX(x) warnx x 48#else 49#define DPRINT(x) 50#define DPRINTX(x) 51#endif 52 53const char *chunk_n[] = { 54 "whole", 55 "unknown", 56 "fat", 57 "freebsd", 58 "extended", 59 "part", 60 "unused", 61 NULL 62}; 63 64struct disk * 65Open_Disk(const char *name) 66{ 67 return Int_Open_Disk(name, 0); 68} 69 70#ifndef PC98 71static u_int32_t 72Read_Int32(u_int32_t *p) 73{ 74 u_int8_t *bp = (u_int8_t *)p; 75 return bp[0] | (bp[1] << 8) | (bp[2] << 16) | (bp[3] << 24); 76} 77#endif 78 79#ifdef HAVE_GEOM 80/* 81 * XXX BEGIN HACK XXX 82 * Scan/parse the XML geom data to retrieve what we need to 83 * carry out the work of Int_Open_Disk. This is a total hack 84 * and should be replaced with a real XML parser. 85 */ 86typedef enum { 87 XML_MESH, 88 XML_MESH_END, 89 XML_CLASS, 90 XML_CLASS_END, 91 XML_GEOM, 92 XML_GEOM_END, 93 XML_CONFIG, 94 XML_CONFIG_END, 95 XML_PROVIDER, 96 XML_PROVIDER_END, 97 XML_NAME, 98 XML_NAME_END, 99 XML_INDEX, 100 XML_INDEX_END, 101 XML_SECLENGTH, 102 XML_SECLENGTH_END, 103 XML_SECOFFSET, 104 XML_SECOFFSET_END, 105 XML_TYPE, 106 XML_TYPE_END, 107 XML_MEDIASIZE, 108 XML_MEDIASIZE_END, 109 XML_SECTORSIZE, 110 XML_SECTORSIZE_END, 111 XML_FWHEADS, 112 XML_FWHEADS_END, 113 XML_FWSECTORS, 114 XML_FWSECTORS_END, 115 116 XML_OTHER, 117 XML_OTHER_END 118} XMLToken; 119 120const struct { 121 XMLToken t; 122 const char* token; 123 const char* name; 124} xmltokens[] = { 125 { XML_MESH, "mesh", "XML_MESH" }, 126 { XML_CLASS, "class", "XML_CLASS" }, 127 { XML_GEOM, "geom", "XML_GEOM" }, 128 { XML_CONFIG, "config", "XML_CONFIG" }, 129 { XML_PROVIDER, "provider", "XML_PROVIDE" }, 130 { XML_NAME, "name", "XML_NAME" }, 131 { XML_INDEX, "index", "XML_INDEX" }, 132 { XML_SECLENGTH, "seclength", "XML_SECLENGTH" }, 133 { XML_SECOFFSET, "secoffset", "XML_SECOFFSET" }, 134 { XML_TYPE, "type", "XML_TYPE" }, 135 { XML_FWHEADS, "fwheads", "XML_FWHEADS" }, 136 { XML_FWSECTORS, "fwsectors", "XML_FWSECTORS" }, 137 { XML_MEDIASIZE, "mediasize", "XML_MEDIASIZE" }, 138 { XML_SECTORSIZE, "sectorsize", "XML_SECTORSIZE" }, 139 /* NB: this must be last */ 140 { XML_OTHER, NULL, "XML_OTHER" }, 141}; 142#define N(x) (sizeof (x) / sizeof (x[0])) 143 144#ifdef DEBUG 145static const char* 146xmltokenname(XMLToken t) 147{ 148 int i; 149 150 for (i = 0; i < N(xmltokens); i++) { 151 if (t == xmltokens[i].t) 152 return xmltokens[i].name; 153 if ((t-1) == xmltokens[i].t) { 154 static char tbuf[80]; 155 snprintf(tbuf, sizeof (tbuf), "%s_END", 156 xmltokens[i].name); 157 return tbuf; 158 } 159 } 160 return "???"; 161} 162#endif /*DEBUG*/ 163 164/* 165 * Parse the next XML token delimited by <..>. If the token 166 * has a "builtin terminator" (<... />) then just skip it and 167 * go the next token. 168 */ 169static int 170xmltoken(const char *start, const char **next, XMLToken *t) 171{ 172 const char *cp = start; 173 const char *token; 174 int i; 175 176again: 177 while (*cp != '<') { 178 if (*cp == '\0') { 179 *next = cp; 180 DPRINTX(("xmltoken: EOD")); 181 return 0; 182 } 183 cp++; 184 } 185 token = ++cp; 186 for (; *cp && *cp != '>' && !isspace(*cp); cp++) 187 ; 188 if (*cp == '\0') { 189 *next = cp; 190 DPRINTX(("xmltoken: EOD")); 191 return 0; 192 } 193 *t = (*token == '/'); 194 if (*t) 195 token++; 196 for (i = 0; xmltokens[i].token != NULL; i++) 197 if (strncasecmp(token, xmltokens[i].token, cp-token) == 0) 198 break; 199 *t += xmltokens[i].t; 200 /* now collect the remainder of the string */ 201 for (; *cp != '>' && *cp != '\0'; cp++) 202 ; 203 if (*cp == '\0') { 204 *next = cp; 205 DPRINTX(("xmltoken: EOD")); 206 return 0; 207 } 208 if (cp > token && cp[-1] == '/') { 209 /* e.g. <geom ref="0xc1c8c100"/> */ 210 start = cp+1; 211 goto again; 212 } 213 *next = cp+1; 214 DPRINTX(("xmltoken: %s \"%.*s\"", xmltokenname(*t), cp-token, token)); 215 return 1; 216} 217 218/* 219 * Parse and discard XML up to the token terminator. 220 */ 221static int 222discardxml(const char **next, XMLToken terminator) 223{ 224 const char *xml = *next; 225 XMLToken t; 226 227 DPRINTX(("discard XML up to %s", xmltokenname(terminator))); 228 for (;;) { 229 if (xmltoken(xml, next, &t) == 0) 230 return EINVAL; 231 if (t == terminator) 232 break; 233 if ((t & 1) == 0) { 234 int error = discardxml(next, t+1); 235 if (error) 236 return error; 237 } 238 xml = *next; 239 } 240 return 0; 241} 242 243/* 244 * Parse XML from between a range of markers; e.g. <mesh> ... </mesh>. 245 * When the specified class name is located we descend looking for the 246 * geometry information given by diskname. Once inside there we process 247 * tags calling f back for each useful one. The arg is passed into f 248 * for use in storing the parsed data. 249 */ 250static int 251parsexmlpair( 252 const char *xml, 253 const char **next, 254 const char *classname, 255 XMLToken terminator, 256 const char *diskname, 257 int (*f)(void *, XMLToken, u_int *, u_int64_t), 258 void *arg 259) 260{ 261 const char *cp; 262 XMLToken t; 263 int error; 264 u_int ix = (u_int) -1; 265 266 DPRINTX(("parse XML up to %s", xmltokenname(terminator))); 267 do { 268 if (xmltoken(xml, next, &t) == 0) { 269 error = EINVAL; 270 break; 271 } 272 if (t == terminator) { 273 error = 0; 274 break; 275 } 276 if (t & 1) { /* </mumble> w/o matching <mumble> */ 277 DPRINTX(("Unexpected token %s", xmltokenname(t))); 278 error = EINVAL; 279 break; 280 } 281 switch ((int) t) { 282 case XML_NAME: 283 for (cp = *next; *cp && *cp != '<'; cp++) 284 ; 285 if (*cp == '\0') { 286 DPRINTX(("parsexmlpair: EOD")); 287 error = EINVAL; 288 goto done; 289 } 290 DPRINTX(("parsexmlpair: \"%.*s\"", cp-*next, *next)); 291 switch ((int) terminator) { 292 case XML_CLASS_END: 293 if (strncasecmp(*next, classname, cp-*next)) 294 return discardxml(next, terminator); 295 break; 296 case XML_GEOM_END: 297 if (strncasecmp(*next, diskname, cp-*next)) 298 return discardxml(next, terminator); 299 break; 300 } 301 break; 302 case XML_SECOFFSET: 303 case XML_SECLENGTH: 304 case XML_TYPE: 305 if (ix == (u_int) -1) { 306 DPRINTX(("parsexmlpair: slice data w/o " 307 "preceding index")); 308 error = EINVAL; 309 goto done; 310 } 311 /* fall thru... */ 312 case XML_INDEX: 313 case XML_FWHEADS: 314 case XML_FWSECTORS: 315 case XML_MEDIASIZE: 316 case XML_SECTORSIZE: 317 if (terminator != XML_CONFIG_END && 318 terminator != XML_PROVIDER_END) { 319 DPRINTX(("parsexmlpair: %s in unexpected " 320 "context: terminator %s", 321 xmltokenname(t), 322 xmltokenname(terminator))); 323 error = EINVAL; 324 goto done; 325 } 326 error = (*f)(arg, t, &ix, strtoull(*next, NULL, 10)); 327 if (error) 328 goto done; 329 break; 330 } 331 error = parsexmlpair(*next, &xml, classname, 332 t+1, diskname, f, arg); 333 } while (error == 0); 334done: 335 return error; 336} 337 338/* 339 * XML parser. Just barely smart enough to handle the 340 * gibberish that geom passed back from the kernel. 341 */ 342static int 343xmlparse( 344 const char *confxml, 345 const char *classname, 346 const char *diskname, 347 int (*f)(void *, XMLToken, u_int *, u_int64_t), 348 void *arg 349) 350{ 351 const char *next; 352 XMLToken t; 353 int error; 354 355 next = confxml; 356 while (xmltoken(next, &next, &t) && t != XML_MESH) 357 ; 358 if (t == XML_MESH) 359 error = parsexmlpair(next, &next, classname, XML_MESH_END, diskname, f, arg); 360 else { 361 DPRINTX(("xmlparse: expecting mesh token, got %s", 362 xmltokenname(t))); 363 error = EINVAL; 364 } 365 366 return (error ? -1 : 0); 367} 368 369/* 370 * Callback to collect slice-related data. 371 */ 372static int 373assignToSlice(void *arg, XMLToken t, u_int *slice, u_int64_t v) 374{ 375 struct diskslices *ds = (struct diskslices *) arg; 376 377 switch ((int) t) { 378 case XML_INDEX: 379 *slice = BASE_SLICE + (u_int) v; 380 if (*slice >= MAX_SLICES) { 381 DPRINTX(("assignToSlice: invalid slice index %u > max %u", 382 *slice, MAX_SLICES)); 383 return EINVAL; 384 } 385 if (*slice >= ds->dss_nslices) 386 ds->dss_nslices = (*slice)+1; 387 break; 388 case XML_SECOFFSET: 389 ds->dss_slices[*slice].ds_offset = (u_long) v; 390 break; 391 case XML_SECLENGTH: 392 ds->dss_slices[*slice].ds_size = (u_long) v; 393 break; 394 case XML_TYPE: 395 ds->dss_slices[*slice].ds_type = (int) v; 396 break; 397 } 398 return 0; 399} 400 401/* 402 * Callback to collect disk-related data. 403 */ 404static int 405assignToDisk(void *arg, XMLToken t, u_int *slice, u_int64_t v) 406{ 407 struct disklabel *dl = (struct disklabel *) arg; 408 409 switch ((int) t) { 410 case XML_FWHEADS: 411 dl->d_ntracks = (u_int32_t) v; 412 case XML_FWSECTORS: 413 dl->d_nsectors = (u_int32_t) v; 414 break; 415 case XML_MEDIASIZE: 416 /* store this temporarily; it gets moved later */ 417 dl->d_secpercyl = v >> 32; 418 dl->d_secperunit = v & 0xffffffff; 419 break; 420 case XML_SECTORSIZE: 421 dl->d_secsize = (u_int32_t) v; 422 break; 423 } 424 return 0; 425} 426 427/* 428 * Callback to collect partition-related data. 429 */ 430static int 431assignToPartition(void *arg, XMLToken t, u_int *part, u_int64_t v) 432{ 433 struct disklabel *dl = (struct disklabel *) arg; 434 435 switch ((int) t) { 436 case XML_INDEX: 437 *part = (u_int) v; 438 if (*part >= MAXPARTITIONS) { 439 DPRINTX(("assignToPartition: invalid partition index %u > max %u", 440 *part, MAXPARTITIONS)); 441 return EINVAL; 442 } 443 if (*part >= dl->d_npartitions) 444 dl->d_npartitions = (*part)+1; 445 break; 446 case XML_SECOFFSET: 447 dl->d_partitions[*part].p_offset = (u_int32_t) v; 448 break; 449 case XML_SECLENGTH: 450 dl->d_partitions[*part].p_size = (u_int32_t) v; 451 break; 452 case XML_TYPE: 453 dl->d_partitions[*part].p_fstype = (u_int8_t) v; 454 break; 455 } 456 return 0; 457} 458#undef N 459#endif /*HAVE_GEOM*/ 460 461struct disk * 462Int_Open_Disk(const char *name, u_long size) 463{ 464 int i; 465 int fd = -1; 466 struct diskslices ds; 467 struct disklabel dl; 468 char device[64]; 469 struct disk *d; 470#ifdef PC98 471 unsigned char *p; 472#else 473 struct dos_partition *dp; 474 void *p; 475#endif 476#ifdef HAVE_GEOM 477 char *confxml = NULL; 478 size_t xmlsize; 479 u_int64_t mediasize; 480 int error; 481#else 482 u_long sector_size; 483 char *buf; 484#endif /*HAVE_GEOM*/ 485 486 strlcpy(device, _PATH_DEV, sizeof(device)); 487 strlcat(device, name, sizeof(device)); 488 489 d = (struct disk *)malloc(sizeof *d); 490 if(!d) return NULL; 491 memset(d, 0, sizeof *d); 492 493 fd = open(device, O_RDONLY); 494 if (fd < 0) { 495 DPRINT(("open(%s) failed", device)); 496 goto bad; 497 } 498 499 memset(&dl, 0, sizeof dl); 500 memset(&ds, 0, sizeof ds); 501#ifdef HAVE_GEOM 502 /* 503 * Read and hack-parse the XML that provides the info we need. 504 */ 505 error = sysctlbyname("kern.geom.confxml", NULL, &xmlsize, NULL, 0); 506 if (error) { 507 warn("kern.geom.confxml sysctl not available, giving up!"); 508 goto bad; 509 } 510 confxml = (char *) malloc(xmlsize+1); 511 if (confxml == NULL) { 512 DPRINT(("cannot malloc memory for confxml")); 513 goto bad; 514 } 515 error = sysctlbyname("kern.geom.confxml", confxml, &xmlsize, NULL, 0); 516 if (error) { 517 DPRINT(("error reading kern.geom.confxml from the system")); 518 goto bad; 519 } 520 confxml[xmlsize] = '\0'; /* in case kernel bug is still there */ 521 522 if (xmlparse(confxml, "MBR", name, assignToSlice, &ds) != 0) { 523 DPRINTX(("Error parsing MBR geometry specification.")); 524 goto bad; 525 } 526 if (xmlparse(confxml, "DISK", name, assignToDisk, &dl) != 0) { 527 DPRINTX(("Error parsing DISK geometry specification.")); 528 goto bad; 529 } 530 if (dl.d_nsectors == 0) { 531 DPRINTX(("No (zero) sector information in DISK geometry")); 532 goto bad; 533 } 534 if (dl.d_ntracks == 0) { 535 DPRINTX(("No (zero) track information in DISK geometry")); 536 goto bad; 537 } 538 if (dl.d_secsize == 0) { 539 DPRINTX(("No (zero) sector size information in DISK geometry")); 540 goto bad; 541 } 542 if (dl.d_secpercyl == 0 && dl.d_secperunit == 0) { 543 DPRINTX(("No (zero) media size information in DISK geometry")); 544 goto bad; 545 } 546 /* 547 * Now patch up disklabel and diskslice. 548 */ 549 d->sector_size = dl.d_secsize; 550 /* NB: media size was stashed in two parts while parsing */ 551 mediasize = (((u_int64_t) dl.d_secpercyl) << 32) + dl.d_secperunit; 552 dl.d_secpercyl = 0; 553 dl.d_secperunit = 0; 554 size = mediasize / d->sector_size; 555 dl.d_ncylinders = size / (dl.d_ntracks * dl.d_nsectors); 556 /* "whole disk" slice maintained for compatibility */ 557 ds.dss_slices[WHOLE_DISK_SLICE].ds_size = size; 558#else /* !HAVE_GEOM */ 559 if (ioctl(fd, DIOCGDINFO, &dl) < 0) { 560 DPRINT(("DIOCGDINFO(%s) failed", device)); 561 goto bad; 562 } 563 i = ioctl(fd, DIOCGSLICEINFO, &ds); 564 if (i < 0) { 565 DPRINT(("DIOCGSLICEINFO(%s) failed", device)); 566 goto bad; 567 } 568 569#ifdef DEBUG 570 for(i = 0; i < ds.dss_nslices; i++) 571 if(ds.dss_slices[i].ds_openmask) 572 printf(" open(%d)=0x%2x", 573 i, ds.dss_slices[i].ds_openmask); 574 printf("\n"); 575#endif 576 577/* XXX --- ds.dss_slice[WHOLE_DISK_SLICE].ds.size of MO disk is wrong!!! */ 578#ifdef PC98 579 if (!size) 580 size = dl.d_ncylinders * dl.d_ntracks * dl.d_nsectors; 581#else 582 if (!size) 583 size = ds.dss_slices[WHOLE_DISK_SLICE].ds_size; 584#endif 585 586 /* determine media sector size */ 587 if ((buf = malloc(MAX_SEC_SIZE)) == NULL) 588 return NULL; 589 for (sector_size = MIN_SEC_SIZE; sector_size <= MAX_SEC_SIZE; sector_size *= 2) { 590 if (read(fd, buf, sector_size) == sector_size) { 591 d->sector_size = sector_size; 592 break; 593 } 594 } 595 free (buf); 596 if (sector_size > MAX_SEC_SIZE) { 597 DPRINT(("Int_Open_Disk: could not determine sector size, " 598 "calculated %u, max %u\n", sector_size, MAX_SEC_SIZE)); 599 /* could not determine sector size */ 600 goto bad; 601 } 602#endif /*HAVE_GEOM*/ 603 604#ifdef PC98 605 p = (unsigned char*)read_block(fd, 1, d->sector_size); 606#else 607 p = read_block(fd, 0, d->sector_size); 608 dp = (struct dos_partition*)(p + DOSPARTOFF); 609 for (i = 0; i < NDOSPART; i++) { 610 if (Read_Int32(&dp->dp_start) >= size) 611 continue; 612 if (Read_Int32(&dp->dp_start) + Read_Int32(&dp->dp_size) >= size) 613 continue; 614 if (!Read_Int32(&dp->dp_size)) 615 continue; 616 } 617 free(p); 618#endif 619 620 d->bios_sect = dl.d_nsectors; 621 d->bios_hd = dl.d_ntracks; 622 623 d->name = strdup(name); 624 625 626 if (dl.d_ntracks && dl.d_nsectors) 627 d->bios_cyl = size / (dl.d_ntracks * dl.d_nsectors); 628 629 if (Add_Chunk(d, 0, size, name, whole, 0, 0, "-")) 630 DPRINT(("Failed to add 'whole' chunk")); 631 632#ifdef __i386__ 633#ifdef PC98 634 /* XXX -- Quick Hack! 635 * Check MS-DOS MO 636 */ 637 if ((*p == 0xf0 || *p == 0xf8) && 638 (*(p+1) == 0xff) && 639 (*(p+2) == 0xff)) { 640 Add_Chunk(d, 0, size, name, fat, 0xa0a0, 0, name); 641 free(p); 642 goto pc98_mo_done; 643 } 644 free(p); 645#endif /* PC98 */ 646 for(i=BASE_SLICE;i<ds.dss_nslices;i++) { 647 char sname[20]; 648 char pname[20]; 649 chunk_e ce; 650 u_long flags=0; 651 int subtype=0; 652 int j; 653 654 if (! ds.dss_slices[i].ds_size) 655 continue; 656 snprintf(sname, sizeof(sname), "%ss%d", name, i - 1); 657#ifdef PC98 658 subtype = ds.dss_slices[i].ds_type | 659 ds.dss_slices[i].ds_subtype << 8; 660 switch (ds.dss_slices[i].ds_type & 0x7f) { 661 case 0x14: 662 ce = freebsd; 663 break; 664 case 0x20: 665 case 0x21: 666 case 0x22: 667 case 0x23: 668 case 0x24: 669 ce = fat; 670 break; 671#else /* IBM-PC */ 672 subtype = ds.dss_slices[i].ds_type; 673 switch (ds.dss_slices[i].ds_type) { 674 case 0xa5: 675 ce = freebsd; 676 break; 677 case 0x1: 678 case 0x6: 679 case 0x4: 680 case 0xb: 681 case 0xc: 682 case 0xe: 683 ce = fat; 684 break; 685 case DOSPTYP_EXTENDED: 686 case 0xf: 687 ce = extended; 688 break; 689#endif 690 default: 691 ce = unknown; 692 break; 693 } 694#ifdef PC98 695 if (Add_Chunk(d, ds.dss_slices[i].ds_offset, 696 ds.dss_slices[i].ds_size, sname, ce, subtype, flags, 697 ds.dss_slices[i].ds_name)) 698#else 699 if (Add_Chunk(d, ds.dss_slices[i].ds_offset, 700 ds.dss_slices[i].ds_size, sname, ce, subtype, flags, "")) 701#endif 702 DPRINT(("failed to add chunk for slice %d", i - 1)); 703 704#ifdef PC98 705 if ((ds.dss_slices[i].ds_type & 0x7f) != 0x14) 706#else 707 if (ds.dss_slices[i].ds_type != 0xa5) 708#endif 709 continue; 710#ifdef HAVE_GEOM 711 if (xmlparse(confxml, "BSD", sname, assignToPartition, &dl) != 0) { 712 DPRINTX(("Error parsing MBR geometry specification.")); 713 goto bad; 714 } 715#else 716 { 717 struct disklabel dl; 718 int k; 719 720 strlcpy(pname, _PATH_DEV, sizeof(pname)); 721 strlcat(pname, sname, sizeof(pname)); 722 j = open(pname, O_RDONLY); 723 if (j < 0) { 724 DPRINT(("open(%s)", pname)); 725 continue; 726 } 727 k = ioctl(j, DIOCGDINFO, &dl); 728 if (k < 0) { 729 DPRINT(("ioctl(%s, DIOCGDINFO)", pname)); 730 close(j); 731 continue; 732 } 733 close(j); 734 } 735#endif /*HAVE_GEOM*/ 736 737 for(j = 0; j <= dl.d_npartitions; j++) { 738 if (j == RAW_PART) 739 continue; 740 if (j == 3) 741 continue; 742 if (j == dl.d_npartitions) { 743 j = 3; 744 dl.d_npartitions = 0; 745 } 746 if (!dl.d_partitions[j].p_size) 747 continue; 748 if (dl.d_partitions[j].p_size + 749 dl.d_partitions[j].p_offset > 750 ds.dss_slices[i].ds_size) 751 continue; 752 snprintf(pname, sizeof(pname), "%s%c", sname, j + 'a'); 753 if (Add_Chunk(d, 754 dl.d_partitions[j].p_offset + 755 ds.dss_slices[i].ds_offset, 756 dl.d_partitions[j].p_size, 757 pname,part, 758 dl.d_partitions[j].p_fstype, 759#ifdef PC98 760 0, 761 ds.dss_slices[i].ds_name) && j != 3) 762#else 763 0, "") && j != 3) 764#endif 765 DPRINT(( 766 "Failed to add chunk for partition %c [%lu,%lu]", 767 j + 'a', dl.d_partitions[j].p_offset, 768 dl.d_partitions[j].p_size)); 769 } 770 } 771#endif /* __i386__ */ 772#ifdef __alpha__ 773 { 774 struct disklabel dl; 775 char pname[20]; 776 int j,k; 777 778 strlcpy(pname, _PATH_DEV, sizeof(pname)); 779 strlcat(pname, name, sizeof(pname)); 780 j = open(pname, O_RDONLY); 781 if (j < 0) { 782 DPRINT(("open(%s)", pname)); 783 goto nolabel; 784 } 785 k = ioctl(j, DIOCGDINFO, &dl); 786 if (k < 0) { 787 DPRINT(("ioctl(%s, DIOCGDINFO)", pname)); 788 close(j); 789 goto nolabel; 790 } 791 close(j); 792 All_FreeBSD(d, 1); 793 794 for(j = 0; j <= dl.d_npartitions; j++) { 795 if (j == RAW_PART) 796 continue; 797 if (j == 3) 798 continue; 799 if (j == dl.d_npartitions) { 800 j = 3; 801 dl.d_npartitions = 0; 802 } 803 if (!dl.d_partitions[j].p_size) 804 continue; 805 if (dl.d_partitions[j].p_size + 806 dl.d_partitions[j].p_offset > 807 ds.dss_slices[WHOLE_DISK_SLICE].ds_size) 808 continue; 809 snprintf(pname, sizeof(pname), "%s%c", name, j + 'a'); 810 if (Add_Chunk(d, 811 dl.d_partitions[j].p_offset, 812 dl.d_partitions[j].p_size, 813 pname,part, 814 dl.d_partitions[j].p_fstype, 815 0, "") && j != 3) 816 DPRINT(( 817 "Failed to add chunk for partition %c [%lu,%lu]", 818 j + 'a', dl.d_partitions[j].p_offset, 819 dl.d_partitions[j].p_size)); 820 } 821 nolabel:; 822 } 823#endif /* __alpha__ */ 824#ifdef PC98 825pc98_mo_done: 826#endif 827 close(fd); 828 Fixup_Names(d); 829 return d; 830bad: 831#ifdef HAVE_GEOM 832 if (confxml != NULL) 833 free(confxml); 834#endif 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