disk.c revision 60886
11844Swollman/* 250476Speter * ---------------------------------------------------------------------------- 31844Swollman * "THE BEER-WARE LICENSE" (Revision 42): 41638Srgrimes * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you 594940Sru * can do whatever you want with this stuff. If we meet some day, and you think 61638Srgrimes * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp 742915Sjdp * ---------------------------------------------------------------------------- 842915Sjdp * 942915Sjdp * $FreeBSD: head/lib/libdisk/disk.c 60886 2000-05-24 20:25:42Z jkh $ 1042915Sjdp * 11139106Sru */ 1242915Sjdp 1342915Sjdp#include <stdio.h> 1442915Sjdp#include <stdlib.h> 15129024Sdes#include <unistd.h> 16129024Sdes#include <fcntl.h> 1729141Speter#include <string.h> 18129024Sdes#include <err.h> 19129024Sdes#include <sys/types.h> 20129024Sdes#include <sys/stat.h> 21125119Sru#include <sys/ioctl.h> 22100332Sru#include <sys/disklabel.h> 23100332Sru#include <sys/diskslice.h> 2442915Sjdp#include "libdisk.h" 2542915Sjdp 2629141Speter#define DOSPTYP_EXTENDED 5 27119607Sru#define DOSPTYP_ONTRACK 84 28117034Sgordon 29119607Sruconst char *chunk_n[] = { 30117034Sgordon "whole", 312827Sjkh "unknown", 322827Sjkh "fat", 332827Sjkh "freebsd", 342827Sjkh "extended", 352827Sjkh "part", 361638Srgrimes "unused", 372827Sjkh NULL 381638Srgrimes}; 3918529Sbde 4018529Sbdestruct disk * 411638SrgrimesOpen_Disk(const char *name) 4242450Sjdp{ 431638Srgrimes return Int_Open_Disk(name,0); 44117173Sru} 451638Srgrimes 4696512Srustatic u_int32_t 4796512SruRead_Int32(u_int32_t *p) 4896512Sru{ 4996512Sru u_int8_t *bp = (u_int8_t *)p; 5096512Sru return bp[0] | (bp[1] << 8) | (bp[2] << 16) | (bp[3] << 24); 5196512Sru} 5296512Sru 5396512Srustruct disk * 54126890StrhodesInt_Open_Disk(const char *name, u_long size) 55126890Strhodes{ 56126890Strhodes int i,fd; 57126890Strhodes struct diskslices ds; 58126890Strhodes struct disklabel dl; 59126890Strhodes char device[64]; 601638Srgrimes struct disk *d; 61126890Strhodes#ifdef PC98 621638Srgrimes unsigned char *p; 6342450Sjdp#else 641844Swollman struct dos_partition *dp; 651844Swollman void *p; 6636673Sdt#endif 67126890Strhodes u_long offset = 0; 681844Swollman 6942450Sjdp strcpy(device,"/dev/r"); 701844Swollman strcat(device,name); 711844Swollman 721844Swollman d = (struct disk *)malloc(sizeof *d); 73127027Strhodes if(!d) err(1,"malloc failed"); 741844Swollman memset(d,0,sizeof *d); 7542450Sjdp 761844Swollman fd = open(device,O_RDONLY); 771844Swollman if (fd < 0) { 7836054Sbde#ifdef DEBUG 7936054Sbde warn("open(%s) failed",device); 8036054Sbde#endif 8142450Sjdp return 0; 8236054Sbde } 8336054Sbde 84117173Sru memset(&dl,0,sizeof dl); 85117159Sru ioctl(fd,DIOCGDINFO,&dl); 861638Srgrimes i = ioctl(fd,DIOCGSLICEINFO,&ds); 87117173Sru if (i < 0) { 88117173Sru#ifdef DEBUG 89117173Sru warn("DIOCGSLICEINFO(%s) failed",device); 90117173Sru#endif 91117173Sru close(fd); 92117173Sru return 0; 93117173Sru } 941844Swollman 95117122Sru#ifdef DEBUG 961844Swollman for(i=0;i<ds.dss_nslices;i++) 9742450Sjdp if(ds.dss_slices[i].ds_openmask) 98117122Sru printf(" open(%d)=0x%2x", 991844Swollman i,ds.dss_slices[i].ds_openmask); 10096512Sru printf("\n"); 1011638Srgrimes#endif 10299362Sru 10399362Sru/* XXX --- ds.dss_slice[WHOLE_DISK_SLCIE].ds.size of MO disk is wrong!!! */ 10499362Sru#ifdef PC98 10599362Sru if (!size) 10696512Sru size = dl.d_ncylinders * dl.d_ntracks * dl.d_nsectors; 10796512Sru#else 1081638Srgrimes if (!size) 10996512Sru size = ds.dss_slices[WHOLE_DISK_SLICE].ds_size; 11096512Sru#endif 11196512Sru 11296512Sru#ifdef PC98 11396512Sru p = (unsigned char*)read_block(fd,1); 11499362Sru#else 1151638Srgrimes p = read_block(fd,0); 11696512Sru dp = (struct dos_partition*)(p+DOSPARTOFF); 11795114Sobrien for (i=0; i < NDOSPART; i++) { 118139106Sru if (Read_Int32(&dp->dp_start) >= size) 11996512Sru continue; 12096512Sru if (Read_Int32(&dp->dp_start) + Read_Int32(&dp->dp_size) >= size) 12195306Sru continue; 12296512Sru if (!Read_Int32(&dp->dp_size)) 12396512Sru continue; 12496512Sru 12596512Sru if (dp->dp_typ == DOSPTYP_ONTRACK) { 12696512Sru d->flags |= DISK_ON_TRACK; 12774805Sru offset = 63; 1281844Swollman } 12999362Sru 13099362Sru } 13196512Sru free(p); 13299362Sru#endif 1331844Swollman 13496512Sru d->bios_sect = dl.d_nsectors; 13596512Sru d->bios_hd = dl.d_ntracks; 1361638Srgrimes 13742915Sjdp d->name = strdup(name); 13842915Sjdp 13996512Sru 14042915Sjdp if (dl.d_ntracks && dl.d_nsectors) 14196512Sru d->bios_cyl = size/(dl.d_ntracks*dl.d_nsectors); 14242915Sjdp 14396343Sobrien#ifdef PC98 14496512Sru if (Add_Chunk(d, -offset, size, name, whole, 0, 0, "-")) 14591011Sru#else 14628945Speter if (Add_Chunk(d, -offset, size, name, whole, 0, 0)) 1471844Swollman#endif 14899362Sru#ifdef DEBUG 14996512Sru warn("Failed to add 'whole' chunk"); 15096512Sru#else 15196512Sru {} 1522353Sbde#endif 15396512Sru 15496512Sru#ifdef __i386__ 15596512Sru#ifdef PC98 1563859Sbde /* XXX -- Quick Hack! 1571844Swollman * Check MS-DOG MO 158139106Sru */ 15996512Sru if ((*p == 0xf0 || *p == 0xf8) && 16096512Sru (*(p+1) == 0xff) && 16196512Sru (*(p+2) == 0xff)) { 16296512Sru Add_Chunk(d, 0, size, name, fat, 0xa0a0, 0, name); 16392491Smarkm free(p); 16496512Sru goto pc98_mo_done; 16596512Sru } 16692491Smarkm free(p); 16792491Smarkm#endif /* PC98 */ 1681638Srgrimes for(i=BASE_SLICE;i<ds.dss_nslices;i++) { 169126938Strhodes char sname[20]; 17096512Sru chunk_e ce; 17196512Sru u_long flags=0; 17296512Sru int subtype=0; 173139103Sru if (! ds.dss_slices[i].ds_size) 17496512Sru continue; 1751638Srgrimes ds.dss_slices[i].ds_offset -= offset; 1761638Srgrimes sprintf(sname,"%ss%d",name,i-1); 17734179Sbde#ifdef PC98 17824750Sbde subtype = ds.dss_slices[i].ds_type | 17942450Sjdp ds.dss_slices[i].ds_subtype << 8; 18024750Sbde switch (ds.dss_slices[i].ds_type & 0x7f) { 18124750Sbde case 0x14: 18242915Sjdp ce = freebsd; 18331809Sbde break; 18442915Sjdp case 0x20: 18527910Sasami case 0x21: 18628945Speter case 0x22: 1871638Srgrimes case 0x23: 1881638Srgrimes ce = fat; 1891638Srgrimes break; 190136019Sru#else /* IBM-PC */ 191136019Sru subtype = ds.dss_slices[i].ds_type; 1922298Swollman switch (ds.dss_slices[i].ds_type) { 1932298Swollman case 0xa5: 194136019Sru ce = freebsd; 195136019Sru break; 1962298Swollman case 0x1: 19749328Shoek case 0x6: 19849328Shoek case 0x4: 19949328Shoek case 0xb: 20049328Shoek case 0xc: 20156971Sru case 0xe: 20249328Shoek ce = fat; 20349328Shoek break; 20449328Shoek case DOSPTYP_EXTENDED: 20549328Shoek case 0xf: 20699362Sru ce = extended; 20795306Sru break; 20899343Sru#endif 20995306Sru default: 21099362Sru ce = unknown; 21192980Sdes break; 21249328Shoek } 21396512Sru#ifdef PC98 214139106Sru if (Add_Chunk(d,ds.dss_slices[i].ds_offset, 21592980Sdes ds.dss_slices[i].ds_size, sname, ce, subtype, flags, 21649328Shoek ds.dss_slices[i].ds_name)) 2171638Srgrimes#else 218116144Sobrien if (Add_Chunk(d, ds.dss_slices[i].ds_offset, 219100872Sru ds.dss_slices[i].ds_size, sname, ce, subtype, flags)) 22049328Shoek#endif 22142915Sjdp#ifdef DEBUG 22242915Sjdp warn("failed to add chunk for slice %d", i - 1); 223119846Sru#else 224119846Sru {} 225119846Sru#endif 226119846Sru 227119730Speter#ifdef PC98 228119846Sru if ((ds.dss_slices[i].ds_type & 0x7f) != 0x14) 229119846Sru#else 230119846Sru if (ds.dss_slices[i].ds_type != 0xa5) 2311844Swollman#endif 23228945Speter continue; 233119730Speter { 234119846Sru struct disklabel dl; 23599362Sru char pname[20]; 236100872Sru int j,k; 23749328Shoek 2381844Swollman strcpy(pname,"/dev/r"); 239139106Sru strcat(pname,sname); 240100872Sru j = open(pname,O_RDONLY); 24196462Sru if (j < 0) { 24296462Sru#ifdef DEBUG 24399362Sru warn("open(%s)",pname); 24496462Sru#endif 24597769Sru continue; 24696668Sru } 24799256Sru k = ioctl(j,DIOCGDINFO,&dl); 24896462Sru if (k < 0) { 249139103Sru#ifdef DEBUG 25096164Sru warn("ioctl(%s,DIOCGDINFO)",pname); 25199343Sru#endif 25296162Sru close(j); 25396162Sru continue; 2541638Srgrimes } 2551638Srgrimes close(j); 2561638Srgrimes 25795306Sru for(j=0; j <= dl.d_npartitions; j++) { 258103713Smarkm if (j == RAW_PART) 2591638Srgrimes continue; 2601638Srgrimes if (j == 3) 261139103Sru continue; 2621638Srgrimes if (j == dl.d_npartitions) { 26374842Sru j = 3; 2641844Swollman dl.d_npartitions=0; 2651844Swollman } 26634092Sbde if (!dl.d_partitions[j].p_size) 26799362Sru continue; 26896512Sru if (dl.d_partitions[j].p_size + 26999362Sru dl.d_partitions[j].p_offset > 270124637Sru ds.dss_slices[i].ds_size) 271124637Sru continue; 272124637Sru sprintf(pname,"%s%c",sname,j+'a'); 27334092Sbde if (Add_Chunk(d, 27499362Sru dl.d_partitions[j].p_offset + 27599362Sru ds.dss_slices[i].ds_offset, 27699362Sru dl.d_partitions[j].p_size, 277124637Sru pname,part, 278124637Sru dl.d_partitions[j].p_fstype, 279124637Sru#ifdef PC98 28096512Sru 0, 28199362Sru ds.dss_slices[i].ds_name) && j != 3) 28234092Sbde#else 283100457Sru 0) && j != 3) 284100457Sru#endif 285100457Sru#ifdef DEBUG 286100457Sru warn( 287100457Sru "Failed to add chunk for partition %c [%lu,%lu]", 288100457Sru j + 'a',dl.d_partitions[j].p_offset, 289100457Sru dl.d_partitions[j].p_size); 290100457Sru#else 291100457Sru {} 292139106Sru#endif 293100457Sru } 294100457Sru } 295100457Sru } 296100457Sru#endif /* __i386__ */ 297100457Sru#ifdef __alpha__ 298100457Sru { 299100457Sru struct disklabel dl; 300100457Sru char pname[20]; 301100457Sru int j,k; 302100457Sru 303100457Sru strcpy(pname,"/dev/r"); 304100457Sru strcat(pname,name); 305100457Sru j = open(pname,O_RDONLY); 306100457Sru if (j < 0) { 307100457Sru#ifdef DEBUG 308100457Sru warn("open(%s)",pname); 309100457Sru#endif 310100457Sru goto nolabel; 311100457Sru } 312100457Sru k = ioctl(j,DIOCGDINFO,&dl); 313100457Sru if (k < 0) { 314100457Sru#ifdef DEBUG 315100457Sru warn("ioctl(%s,DIOCGDINFO)",pname); 316100457Sru#endif 317100457Sru close(j); 318100457Sru goto nolabel; 31916663Sjkh } 32076861Skris close(j); 32176861Skris All_FreeBSD(d, 1); 322 323 for(j=0; j <= dl.d_npartitions; j++) { 324 if (j == RAW_PART) 325 continue; 326 if (j == 3) 327 continue; 328 if (j == dl.d_npartitions) { 329 j = 3; 330 dl.d_npartitions=0; 331 } 332 if (!dl.d_partitions[j].p_size) 333 continue; 334 if (dl.d_partitions[j].p_size + 335 dl.d_partitions[j].p_offset > 336 ds.dss_slices[WHOLE_DISK_SLICE].ds_size) 337 continue; 338 sprintf(pname,"%s%c",name,j+'a'); 339 if (Add_Chunk(d, 340 dl.d_partitions[j].p_offset, 341 dl.d_partitions[j].p_size, 342 pname,part, 343 dl.d_partitions[j].p_fstype, 344 0) && j != 3) 345#ifdef DEBUG 346 warn( 347 "Failed to add chunk for partition %c [%lu,%lu]", 348 j + 'a',dl.d_partitions[j].p_offset, 349 dl.d_partitions[j].p_size); 350#else 351 {} 352#endif 353 } 354 nolabel:; 355 } 356#endif /* __alpha__ */ 357#ifdef PC98 358pc98_mo_done: 359#endif 360 close(fd); 361 Fixup_Names(d); 362#ifndef PC98 363 Bios_Limit_Chunk(d->chunks,1024*d->bios_hd*d->bios_sect); 364#endif 365 return d; 366} 367 368void 369Debug_Disk(struct disk *d) 370{ 371 printf("Debug_Disk(%s)",d->name); 372 printf(" flags=%lx",d->flags); 373#if 0 374 printf(" real_geom=%lu/%lu/%lu",d->real_cyl,d->real_hd,d->real_sect); 375#endif 376 printf(" bios_geom=%lu/%lu/%lu = %lu\n", 377 d->bios_cyl,d->bios_hd,d->bios_sect, 378 d->bios_cyl*d->bios_hd*d->bios_sect); 379#if defined(__i386__) 380 printf(" boot1=%p, boot2=%p, bootmgr=%p\n", 381 d->boot1,d->boot2,d->bootmgr); 382#elif defined(__alpha__) 383 printf(" boot1=%p, bootmgr=%p\n", 384 d->boot1,d->bootmgr); 385#endif 386 Debug_Chunk(d->chunks); 387} 388 389void 390Free_Disk(struct disk *d) 391{ 392 if(d->chunks) Free_Chunk(d->chunks); 393 if(d->name) free(d->name); 394 if(d->bootmgr) free(d->bootmgr); 395 if(d->boot1) free(d->boot1); 396#if defined(__i386__) 397 if(d->boot2) free(d->boot2); 398#endif 399 free(d); 400} 401 402struct disk * 403Clone_Disk(struct disk *d) 404{ 405 struct disk *d2; 406 407 d2 = (struct disk*) malloc(sizeof *d2); 408 if(!d2) err(1,"malloc failed"); 409 *d2 = *d; 410 d2->name = strdup(d2->name); 411 d2->chunks = Clone_Chunk(d2->chunks); 412 if(d2->bootmgr) { 413 d2->bootmgr = malloc(DOSPARTOFF); 414 memcpy(d2->bootmgr,d->bootmgr,DOSPARTOFF); 415 } 416#if defined(__i386__) 417 if(d2->boot1) { 418 d2->boot1 = malloc(512); 419 memcpy(d2->boot1,d->boot1,512); 420 } 421 if(d2->boot2) { 422 d2->boot2 = malloc(512*15); 423 memcpy(d2->boot2,d->boot2,512*15); 424 } 425#elif defined(__alpha__) 426 if(d2->boot1) { 427 d2->boot1 = malloc(512*15); 428 memcpy(d2->boot1,d->boot1,512*15); 429 } 430#endif 431 return d2; 432} 433 434#if 0 435void 436Collapse_Disk(struct disk *d) 437{ 438 439 while(Collapse_Chunk(d,d->chunks)) 440 ; 441} 442#endif 443 444static char * device_list[] = {"wd", "ad", "da", "afd", "fla", "idad", "mlxd", "amrd", "fd", 0}; 445 446char ** 447Disk_Names() 448{ 449 int i,j,k; 450 char disk[25]; 451 char diskname[25]; 452 struct stat st; 453 struct diskslices ds; 454 int fd; 455 static char **disks; 456 457 disks = malloc(sizeof *disks * (1 + MAX_NO_DISKS)); 458 memset(disks,0,sizeof *disks * (1 + MAX_NO_DISKS)); 459 k = 0; 460 for (j = 0; device_list[j]; j++) { 461 for (i = 0; i < MAX_NO_DISKS; i++) { 462 sprintf(diskname, "%s%d", device_list[j], i); 463 sprintf(disk, "/dev/%s", diskname); 464 if (stat(disk, &st) || !(st.st_mode & S_IFCHR)) 465 continue; 466 if ((fd = open(disk, O_RDWR)) == -1) 467 continue; 468 if (ioctl(fd, DIOCGSLICEINFO, &ds) == -1) { 469#ifdef DEBUG 470 warn("DIOCGSLICEINFO %s", disk); 471#endif 472 close(fd); 473 continue; 474 } 475 close(fd); 476 disks[k++] = strdup(diskname); 477 if(k == MAX_NO_DISKS) 478 return disks; 479 } 480 } 481 return disks; 482} 483 484void 485Set_Boot_Mgr(struct disk *d, const u_char *b) 486{ 487#ifndef PC98 488 if (d->bootmgr) 489 free(d->bootmgr); 490 if (!b) { 491 d->bootmgr = 0; 492 } else { 493 d->bootmgr = malloc(DOSPARTOFF); 494 if(!d->bootmgr) err(1,"malloc failed"); 495 memcpy(d->bootmgr,b,DOSPARTOFF); 496 } 497#endif 498} 499 500void 501Set_Boot_Blocks(struct disk *d, const u_char *b1, const u_char *b2) 502{ 503#if defined(__i386__) 504 if (d->boot1) free(d->boot1); 505 d->boot1 = malloc(512); 506 if(!d->boot1) err(1,"malloc failed"); 507 memcpy(d->boot1,b1,512); 508 if (d->boot2) free(d->boot2); 509 d->boot2 = malloc(15*512); 510 if(!d->boot2) err(1,"malloc failed"); 511 memcpy(d->boot2,b2,15*512); 512#elif defined(__alpha__) 513 if (d->boot1) free(d->boot1); 514 d->boot1 = malloc(15*512); 515 if(!d->boot1) err(1,"malloc failed"); 516 memcpy(d->boot1,b1,15*512); 517#endif 518} 519 520const char * 521slice_type_name( int type, int subtype ) 522{ 523 switch (type) { 524 case 0: return "whole"; 525#ifndef PC98 526 case 1: switch (subtype) { 527 case 1: return "fat (12-bit)"; 528 case 2: return "XENIX /"; 529 case 3: return "XENIX /usr"; 530 case 4: return "fat (16-bit,<=32Mb)"; 531 case 5: return "extended DOS"; 532 case 6: return "fat (16-bit,>32Mb)"; 533 case 7: return "NTFS/HPFS/QNX"; 534 case 8: return "AIX bootable"; 535 case 9: return "AIX data"; 536 case 10: return "OS/2 bootmgr"; 537 case 11: return "fat (32-bit)"; 538 case 12: return "fat (32-bit,LBA)"; 539 case 14: return "fat (16-bit,>32Mb,LBA)"; 540 case 15: return "extended DOS, LBA"; 541 case 18: return "Compaq Diagnostic"; 542 case 84: return "OnTrack diskmgr"; 543 case 100: return "Netware 2.x"; 544 case 101: return "Netware 3.x"; 545 case 115: return "SCO UnixWare"; 546 case 128: return "Minix 1.1"; 547 case 129: return "Minix 1.5"; 548 case 130: return "linux_swap"; 549 case 131: return "ext2fs"; 550 case 166: return "OpenBSD FFS"; /* 0xA6 */ 551 case 169: return "NetBSD FFS"; /* 0xA9 */ 552 case 182: return "OpenBSD"; /* dedicated */ 553 case 183: return "bsd/os"; 554 case 184: return "bsd/os swap"; 555 default: return "unknown"; 556 } 557#endif 558 case 2: return "fat"; 559 case 3: switch (subtype) { 560#ifdef PC98 561 case 0xc494: return "freebsd"; 562#else 563 case 165: return "freebsd"; 564#endif 565 default: return "unknown"; 566 } 567#ifndef PC98 568 case 4: return "extended"; 569 case 5: return "part"; 570 case 6: return "unused"; 571#endif 572 default: return "unknown"; 573 } 574} 575