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