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