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