disk.c revision 84200
1/* 2 * ---------------------------------------------------------------------------- 3 * "THE BEER-WARE LICENSE" (Revision 42): 4 * <phk@login.dknet.dk> 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 84200 2001-09-30 21:16:57Z dillon $"); 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#include <paths.h> 26#include "libdisk.h" 27 28#define DOSPTYP_EXTENDED 5 29#define DOSPTYP_ONTRACK 84 30 31const char *chunk_n[] = { 32 "whole", 33 "unknown", 34 "fat", 35 "freebsd", 36 "extended", 37 "part", 38 "unused", 39 NULL 40}; 41 42struct disk * 43Open_Disk(const char *name) 44{ 45 return Int_Open_Disk(name, 0); 46} 47 48#ifndef PC98 49static u_int32_t 50Read_Int32(u_int32_t *p) 51{ 52 u_int8_t *bp = (u_int8_t *)p; 53 return bp[0] | (bp[1] << 8) | (bp[2] << 16) | (bp[3] << 24); 54} 55#endif 56 57struct disk * 58Int_Open_Disk(const char *name, u_long size) 59{ 60 int i,fd; 61 struct diskslices ds; 62 struct disklabel dl; 63 char device[64], *buf; 64 struct disk *d; 65 u_long sector_size; 66#ifdef PC98 67 unsigned char *p; 68#else 69 struct dos_partition *dp; 70 void *p; 71#endif 72 u_long offset = 0; 73 74 strcpy(device, _PATH_DEV); 75 strcat(device, name); 76 77 d = (struct disk *)malloc(sizeof *d); 78 if(!d) return NULL; 79 memset(d, 0, sizeof *d); 80 81 fd = open(device, O_RDONLY); 82 if (fd < 0) { 83#ifdef DEBUG 84 warn("open(%s) failed", device); 85#endif 86 return 0; 87 } 88 89 memset(&dl, 0, sizeof dl); 90 ioctl(fd, DIOCGDINFO, &dl); 91 i = ioctl(fd, DIOCGSLICEINFO, &ds); 92 if (i < 0) { 93#ifdef DEBUG 94 warn("DIOCGSLICEINFO(%s) failed", device); 95#endif 96 close(fd); 97 return 0; 98 } 99 100#ifdef DEBUG 101 for(i = 0; i < ds.dss_nslices; i++) 102 if(ds.dss_slices[i].ds_openmask) 103 printf(" open(%d)=0x%2x", 104 i, ds.dss_slices[i].ds_openmask); 105 printf("\n"); 106#endif 107 108/* XXX --- ds.dss_slice[WHOLE_DISK_SLICE].ds.size of MO disk is wrong!!! */ 109#ifdef PC98 110 if (!size) 111 size = dl.d_ncylinders * dl.d_ntracks * dl.d_nsectors; 112#else 113 if (!size) 114 size = ds.dss_slices[WHOLE_DISK_SLICE].ds_size; 115#endif 116 117 /* determine media sector size */ 118 if ((buf = malloc(MAX_SEC_SIZE)) == NULL) 119 return NULL; 120 for (sector_size = MIN_SEC_SIZE; sector_size <= MAX_SEC_SIZE; sector_size *= 2) { 121 if (read(fd, buf, sector_size) == sector_size) { 122 d->sector_size = sector_size; 123 break; 124 } 125 } 126 free (buf); 127 if (sector_size > MAX_SEC_SIZE) 128 return NULL; /* could not determine sector size */ 129 130#ifdef PC98 131 p = (unsigned char*)read_block(fd, 1, sector_size); 132#else 133 p = read_block(fd, 0, sector_size); 134 dp = (struct dos_partition*)(p + DOSPARTOFF); 135 for (i = 0; i < NDOSPART; i++) { 136 if (Read_Int32(&dp->dp_start) >= size) 137 continue; 138 if (Read_Int32(&dp->dp_start) + Read_Int32(&dp->dp_size) >= size) 139 continue; 140 if (!Read_Int32(&dp->dp_size)) 141 continue; 142 143 if (dp->dp_typ == DOSPTYP_ONTRACK) { 144 d->flags |= DISK_ON_TRACK; 145 offset = 63; 146 } 147 148 } 149 free(p); 150#endif 151 152 d->bios_sect = dl.d_nsectors; 153 d->bios_hd = dl.d_ntracks; 154 155 d->name = strdup(name); 156 157 158 if (dl.d_ntracks && dl.d_nsectors) 159 d->bios_cyl = size / (dl.d_ntracks * dl.d_nsectors); 160 161#ifdef PC98 162 if (Add_Chunk(d, -offset, size, name, whole, 0, 0, "-")) 163#else 164 if (Add_Chunk(d, -offset, size, name, whole, 0, 0)) 165#endif 166#ifdef DEBUG 167 warn("Failed to add 'whole' chunk"); 168#else 169 {} 170#endif 171 172#ifdef __i386__ 173#ifdef PC98 174 /* XXX -- Quick Hack! 175 * Check MS-DOS MO 176 */ 177 if ((*p == 0xf0 || *p == 0xf8) && 178 (*(p+1) == 0xff) && 179 (*(p+2) == 0xff)) { 180 Add_Chunk(d, 0, size, name, fat, 0xa0a0, 0, name); 181 free(p); 182 goto pc98_mo_done; 183 } 184 free(p); 185#endif /* PC98 */ 186 for(i=BASE_SLICE;i<ds.dss_nslices;i++) { 187 char sname[20]; 188 chunk_e ce; 189 u_long flags=0; 190 int subtype=0; 191 192 if (! ds.dss_slices[i].ds_size) 193 continue; 194 ds.dss_slices[i].ds_offset -= offset; 195 sprintf(sname, "%ss%d", name, i - 1); 196#ifdef PC98 197 subtype = ds.dss_slices[i].ds_type | 198 ds.dss_slices[i].ds_subtype << 8; 199 switch (ds.dss_slices[i].ds_type & 0x7f) { 200 case 0x14: 201 ce = freebsd; 202 break; 203 case 0x20: 204 case 0x21: 205 case 0x22: 206 case 0x23: 207 case 0x24: 208 ce = fat; 209 break; 210#else /* IBM-PC */ 211 subtype = ds.dss_slices[i].ds_type; 212 switch (ds.dss_slices[i].ds_type) { 213 case 0xa5: 214 ce = freebsd; 215 break; 216 case 0x1: 217 case 0x6: 218 case 0x4: 219 case 0xb: 220 case 0xc: 221 case 0xe: 222 ce = fat; 223 break; 224 case DOSPTYP_EXTENDED: 225 case 0xf: 226 ce = extended; 227 break; 228#endif 229 default: 230 ce = unknown; 231 break; 232 } 233#ifdef PC98 234 if (Add_Chunk(d, ds.dss_slices[i].ds_offset, 235 ds.dss_slices[i].ds_size, sname, ce, subtype, flags, 236 ds.dss_slices[i].ds_name)) 237#else 238 if (Add_Chunk(d, ds.dss_slices[i].ds_offset, 239 ds.dss_slices[i].ds_size, sname, ce, subtype, flags)) 240#endif 241#ifdef DEBUG 242 warn("failed to add chunk for slice %d", i - 1); 243#else 244 {} 245#endif 246 247#ifdef PC98 248 if ((ds.dss_slices[i].ds_type & 0x7f) != 0x14) 249#else 250 if (ds.dss_slices[i].ds_type != 0xa5) 251#endif 252 continue; 253 { 254 struct disklabel dl; 255 char pname[20]; 256 int j, k; 257 258 strcpy(pname, _PATH_DEV); 259 strcat(pname, sname); 260 j = open(pname, O_RDONLY); 261 if (j < 0) { 262#ifdef DEBUG 263 warn("open(%s)", pname); 264#endif 265 continue; 266 } 267 k = ioctl(j, DIOCGDINFO, &dl); 268 if (k < 0) { 269#ifdef DEBUG 270 warn("ioctl(%s, DIOCGDINFO)", pname); 271#endif 272 close(j); 273 continue; 274 } 275 close(j); 276 277 for(j = 0; j <= dl.d_npartitions; j++) { 278 if (j == RAW_PART) 279 continue; 280 if (j == 3) 281 continue; 282 if (j == dl.d_npartitions) { 283 j = 3; 284 dl.d_npartitions = 0; 285 } 286 if (!dl.d_partitions[j].p_size) 287 continue; 288 if (dl.d_partitions[j].p_size + 289 dl.d_partitions[j].p_offset > 290 ds.dss_slices[i].ds_size) 291 continue; 292 sprintf(pname, "%s%c", sname, j + 'a'); 293 if (Add_Chunk(d, 294 dl.d_partitions[j].p_offset + 295 ds.dss_slices[i].ds_offset, 296 dl.d_partitions[j].p_size, 297 pname,part, 298 dl.d_partitions[j].p_fstype, 299#ifdef PC98 300 0, 301 ds.dss_slices[i].ds_name) && j != 3) 302#else 303 0) && j != 3) 304#endif 305#ifdef DEBUG 306 warn( 307 "Failed to add chunk for partition %c [%lu,%lu]", 308 j + 'a', dl.d_partitions[j].p_offset, 309 dl.d_partitions[j].p_size); 310#else 311 {} 312#endif 313 } 314 } 315 } 316#endif /* __i386__ */ 317#ifdef __alpha__ 318 { 319 struct disklabel dl; 320 char pname[20]; 321 int j,k; 322 323 strcpy(pname, _PATH_DEV); 324 strcat(pname, name); 325 j = open(pname, O_RDONLY); 326 if (j < 0) { 327#ifdef DEBUG 328 warn("open(%s)", pname); 329#endif 330 goto nolabel; 331 } 332 k = ioctl(j, DIOCGDINFO, &dl); 333 if (k < 0) { 334#ifdef DEBUG 335 warn("ioctl(%s, DIOCGDINFO)", pname); 336#endif 337 close(j); 338 goto nolabel; 339 } 340 close(j); 341 All_FreeBSD(d, 1); 342 343 for(j = 0; j <= dl.d_npartitions; j++) { 344 if (j == RAW_PART) 345 continue; 346 if (j == 3) 347 continue; 348 if (j == dl.d_npartitions) { 349 j = 3; 350 dl.d_npartitions = 0; 351 } 352 if (!dl.d_partitions[j].p_size) 353 continue; 354 if (dl.d_partitions[j].p_size + 355 dl.d_partitions[j].p_offset > 356 ds.dss_slices[WHOLE_DISK_SLICE].ds_size) 357 continue; 358 sprintf(pname, "%s%c", name, j + 'a'); 359 if (Add_Chunk(d, 360 dl.d_partitions[j].p_offset, 361 dl.d_partitions[j].p_size, 362 pname,part, 363 dl.d_partitions[j].p_fstype, 364 0) && j != 3) 365#ifdef DEBUG 366 warn( 367 "Failed to add chunk for partition %c [%lu,%lu]", 368 j + 'a', dl.d_partitions[j].p_offset, 369 dl.d_partitions[j].p_size); 370#else 371 {} 372#endif 373 } 374 nolabel:; 375 } 376#endif /* __alpha__ */ 377#ifdef PC98 378pc98_mo_done: 379#endif 380 close(fd); 381 Fixup_Names(d); 382 return d; 383} 384 385void 386Debug_Disk(struct disk *d) 387{ 388 printf("Debug_Disk(%s)", d->name); 389 printf(" flags=%lx", d->flags); 390#if 0 391 printf(" real_geom=%lu/%lu/%lu", d->real_cyl, d->real_hd, d->real_sect); 392#endif 393 printf(" bios_geom=%lu/%lu/%lu = %lu\n", 394 d->bios_cyl, d->bios_hd, d->bios_sect, 395 d->bios_cyl * d->bios_hd * d->bios_sect); 396#if defined(PC98) 397 printf(" boot1=%p, boot2=%p, bootipl=%p, bootmenu=%p\n", 398 d->boot1, d->boot2, d->bootipl, d->bootmenu); 399#elif defined(__i386__) 400 printf(" boot1=%p, boot2=%p, bootmgr=%p\n", 401 d->boot1, d->boot2, d->bootmgr); 402#elif defined(__alpha__) 403 printf(" boot1=%p, bootmgr=%p\n", 404 d->boot1, d->bootmgr); 405#endif 406 Debug_Chunk(d->chunks); 407} 408 409void 410Free_Disk(struct disk *d) 411{ 412 if(d->chunks) Free_Chunk(d->chunks); 413 if(d->name) free(d->name); 414#ifdef PC98 415 if(d->bootipl) free(d->bootipl); 416 if(d->bootmenu) free(d->bootmenu); 417#else 418 if(d->bootmgr) free(d->bootmgr); 419#endif 420 if(d->boot1) free(d->boot1); 421#if defined(__i386__) 422 if(d->boot2) free(d->boot2); 423#endif 424 free(d); 425} 426 427struct disk * 428Clone_Disk(struct disk *d) 429{ 430 struct disk *d2; 431 432 d2 = (struct disk*) malloc(sizeof *d2); 433 if(!d2) return NULL; 434 *d2 = *d; 435 d2->name = strdup(d2->name); 436 d2->chunks = Clone_Chunk(d2->chunks); 437#ifdef PC98 438 if(d2->bootipl) { 439 d2->bootipl = malloc(d2->bootipl_size); 440 memcpy(d2->bootipl, d->bootipl, d2->bootipl_size); 441 } 442 if(d2->bootmenu) { 443 d2->bootmenu = malloc(d2->bootmenu_size); 444 memcpy(d2->bootmenu, d->bootmenu, d2->bootmenu_size); 445 } 446#else 447 if(d2->bootmgr) { 448 d2->bootmgr = malloc(d2->bootmgr_size); 449 memcpy(d2->bootmgr, d->bootmgr, d2->bootmgr_size); 450 } 451#endif 452#if defined(__i386__) 453 if(d2->boot1) { 454 d2->boot1 = malloc(512); 455 memcpy(d2->boot1, d->boot1, 512); 456 } 457 if(d2->boot2) { 458 d2->boot2 = malloc(512 * 15); 459 memcpy(d2->boot2, d->boot2, 512 * 15); 460 } 461#elif defined(__alpha__) 462 if(d2->boot1) { 463 d2->boot1 = malloc(512 * 15); 464 memcpy(d2->boot1, d->boot1, 512 * 15); 465 } 466#endif 467 return d2; 468} 469 470#if 0 471void 472Collapse_Disk(struct disk *d) 473{ 474 475 while(Collapse_Chunk(d, d->chunks)) 476 ; 477} 478#endif 479 480#ifdef PC98 481static char * device_list[] = {"wd", "aacd", "ad", "da", "afd", "fla", "idad", "mlxd", "amrd", "twed", "ar", "fd", 0}; 482#else 483static char * device_list[] = {"aacd", "ad", "da", "afd", "fla", "idad", "mlxd", "amrd", "twed", "ar", "fd", 0}; 484#endif 485 486char ** 487Disk_Names() 488{ 489 int i,j,k; 490 char disk[25]; 491 char diskname[25]; 492 struct stat st; 493 struct diskslices ds; 494 int fd; 495 static char **disks; 496 int error; 497 size_t listsize; 498 char *disklist, **dp; 499 500 disks = malloc(sizeof *disks * (1 + MAX_NO_DISKS)); 501 memset(disks,0,sizeof *disks * (1 + MAX_NO_DISKS)); 502 error = sysctlbyname("kern.disks", NULL, &listsize, NULL, 0); 503 if (!error) { 504 disklist = (char *)malloc(listsize); 505 error = sysctlbyname("kern.disks", disklist, &listsize, NULL, 0); 506 if (error) 507 return NULL; 508 k = 0; 509 for (dp = disks; ((*dp = strsep(&disklist, " ")) != NULL) && k < MAX_NO_DISKS; k++, dp++); 510 return disks; 511 } 512 warn("kern.disks sysctl not available"); 513 k = 0; 514 for (j = 0; device_list[j]; j++) { 515 for (i = 0; i < MAX_NO_DISKS; i++) { 516 sprintf(diskname, "%s%d", device_list[j], i); 517 sprintf(disk, _PATH_DEV"%s", diskname); 518 if (stat(disk, &st) || !(st.st_mode & S_IFCHR)) 519 continue; 520 if ((fd = open(disk, O_RDWR)) == -1) 521 continue; 522 if (ioctl(fd, DIOCGSLICEINFO, &ds) == -1) { 523#ifdef DEBUG 524 warn("DIOCGSLICEINFO %s", disk); 525#endif 526 close(fd); 527 continue; 528 } 529 close(fd); 530 disks[k++] = strdup(diskname); 531 if(k == MAX_NO_DISKS) 532 return disks; 533 } 534 } 535 return disks; 536} 537 538#ifdef PC98 539void 540Set_Boot_Mgr(struct disk *d, const u_char *bootipl, const size_t bootipl_size, 541 const u_char *bootmenu, const size_t bootmenu_size) 542#else 543void 544Set_Boot_Mgr(struct disk *d, const u_char *b, const size_t s) 545#endif 546{ 547#ifdef PC98 548 if (bootipl_size % d->sector_size != 0) 549 return; 550 if (d->bootipl) 551 free(d->bootipl); 552 if (!bootipl) { 553 d->bootipl = NULL; 554 } else { 555 d->bootipl_size = bootipl_size; 556 d->bootipl = malloc(bootipl_size); 557 if(!d->bootipl) return; 558 memcpy(d->bootipl, bootipl, bootipl_size); 559 } 560 561 if (bootmenu_size % d->sector_size != 0) 562 return; 563 if (d->bootmenu) 564 free(d->bootmenu); 565 if (!bootmenu) { 566 d->bootmenu = NULL; 567 } else { 568 d->bootmenu_size = bootmenu_size; 569 d->bootmenu = malloc(bootmenu_size); 570 if(!d->bootmenu) return; 571 memcpy(d->bootmenu, bootmenu, bootmenu_size); 572 } 573#else 574 if (s % d->sector_size != 0) 575 return; 576 if (d->bootmgr) 577 free(d->bootmgr); 578 if (!b) { 579 d->bootmgr = NULL; 580 } else { 581 d->bootmgr_size = s; 582 d->bootmgr = malloc(s); 583 if(!d->bootmgr) return; 584 memcpy(d->bootmgr, b, s); 585 } 586#endif 587} 588 589int 590Set_Boot_Blocks(struct disk *d, const u_char *b1, const u_char *b2) 591{ 592#if defined(__i386__) 593 if (d->boot1) free(d->boot1); 594 d->boot1 = malloc(512); 595 if(!d->boot1) return -1; 596 memcpy(d->boot1, b1, 512); 597 if (d->boot2) free(d->boot2); 598 d->boot2 = malloc(15 * 512); 599 if(!d->boot2) return -1; 600 memcpy(d->boot2, b2, 15 * 512); 601#elif defined(__alpha__) 602 if (d->boot1) free(d->boot1); 603 d->boot1 = malloc(15 * 512); 604 if(!d->boot1) return -1; 605 memcpy(d->boot1, b1, 15 * 512); 606#endif 607 return 0; 608} 609 610const char * 611slice_type_name( int type, int subtype ) 612{ 613 switch (type) { 614 case 0: return "whole"; 615#ifndef PC98 616 case 1: switch (subtype) { 617 case 1: return "fat (12-bit)"; 618 case 2: return "XENIX /"; 619 case 3: return "XENIX /usr"; 620 case 4: return "fat (16-bit,<=32Mb)"; 621 case 5: return "extended DOS"; 622 case 6: return "fat (16-bit,>32Mb)"; 623 case 7: return "NTFS/HPFS/QNX"; 624 case 8: return "AIX bootable"; 625 case 9: return "AIX data"; 626 case 10: return "OS/2 bootmgr"; 627 case 11: return "fat (32-bit)"; 628 case 12: return "fat (32-bit,LBA)"; 629 case 14: return "fat (16-bit,>32Mb,LBA)"; 630 case 15: return "extended DOS, LBA"; 631 case 18: return "Compaq Diagnostic"; 632 case 84: return "OnTrack diskmgr"; 633 case 100: return "Netware 2.x"; 634 case 101: return "Netware 3.x"; 635 case 115: return "SCO UnixWare"; 636 case 128: return "Minix 1.1"; 637 case 129: return "Minix 1.5"; 638 case 130: return "linux_swap"; 639 case 131: return "ext2fs"; 640 case 166: return "OpenBSD FFS"; /* 0xA6 */ 641 case 169: return "NetBSD FFS"; /* 0xA9 */ 642 case 182: return "OpenBSD"; /* dedicated */ 643 case 183: return "bsd/os"; 644 case 184: return "bsd/os swap"; 645 default: return "unknown"; 646 } 647#endif 648 case 2: return "fat"; 649 case 3: switch (subtype) { 650#ifdef PC98 651 case 0xc494: return "freebsd"; 652#else 653 case 165: return "freebsd"; 654#endif 655 default: return "unknown"; 656 } 657#ifndef PC98 658 case 4: return "extended"; 659 case 5: return "part"; 660 case 6: return "unused"; 661#endif 662 default: return "unknown"; 663 } 664} 665