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