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