disk.c revision 57898
1234751Sadrian/* 2234751Sadrian * ---------------------------------------------------------------------------- 3234751Sadrian * "THE BEER-WARE LICENSE" (Revision 42): 4234751Sadrian * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you 5234751Sadrian * can do whatever you want with this stuff. If we meet some day, and you think 6234751Sadrian * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp 7234751Sadrian * ---------------------------------------------------------------------------- 8234751Sadrian * 9234751Sadrian * $FreeBSD: head/lib/libdisk/disk.c 57898 2000-03-10 22:54:04Z imp $ 10234751Sadrian * 11234751Sadrian */ 12234751Sadrian 13234751Sadrian#include <stdio.h> 14234751Sadrian#include <stdlib.h> 15234751Sadrian#include <unistd.h> 16234751Sadrian#include <fcntl.h> 17234751Sadrian#include <string.h> 18234751Sadrian#include <err.h> 19234751Sadrian#include <sys/types.h> 20234751Sadrian#include <sys/stat.h> 21234751Sadrian#include <sys/ioctl.h> 22234751Sadrian#include <sys/disklabel.h> 23234751Sadrian#include <sys/diskslice.h> 24234751Sadrian#include "libdisk.h" 25234751Sadrian 26234751Sadrian#define DOSPTYP_EXTENDED 5 27234751Sadrian#define DOSPTYP_ONTRACK 84 28234751Sadrian 29234751Sadrianconst char *chunk_n[] = { 30234751Sadrian "whole", 31234751Sadrian "unknown", 32234751Sadrian "fat", 33234751Sadrian "freebsd", 34234751Sadrian "extended", 35234751Sadrian "part", 36234751Sadrian "unused", 37234751Sadrian NULL 38234751Sadrian}; 39234751Sadrian 40234751Sadrianstruct disk * 41234751SadrianOpen_Disk(const char *name) 42234751Sadrian{ 43234751Sadrian return Int_Open_Disk(name,0); 44234751Sadrian} 45234751Sadrian 46234751Sadrianstatic u_int32_t 47234751SadrianRead_Int32(u_int32_t *p) 48234751Sadrian{ 49234751Sadrian u_int8_t *bp = (u_int8_t *)p; 50234751Sadrian return bp[0] | (bp[1] << 8) | (bp[2] << 16) | (bp[3] << 24); 51234751Sadrian} 52234751Sadrian 53234751Sadrianstruct disk * 54234751SadrianInt_Open_Disk(const char *name, u_long size) 55234751Sadrian{ 56234751Sadrian int i,fd; 57234751Sadrian struct diskslices ds; 58234751Sadrian struct disklabel dl; 59234751Sadrian char device[64]; 60234751Sadrian struct disk *d; 61234751Sadrian struct dos_partition *dp; 62234751Sadrian void *p; 63234751Sadrian u_long offset = 0; 64234751Sadrian 65234751Sadrian strcpy(device,"/dev/r"); 66234751Sadrian strcat(device,name); 67234751Sadrian 68234751Sadrian d = (struct disk *)malloc(sizeof *d); 69244968Sadrian if(!d) err(1,"malloc failed"); 70234751Sadrian memset(d,0,sizeof *d); 71234751Sadrian 72234751Sadrian fd = open(device,O_RDONLY); 73234751Sadrian if (fd < 0) { 74234751Sadrian#ifdef DEBUG 75234751Sadrian warn("open(%s) failed",device); 76234751Sadrian#endif 77234751Sadrian return 0; 78234751Sadrian } 79234751Sadrian 80234751Sadrian memset(&dl,0,sizeof dl); 81234751Sadrian ioctl(fd,DIOCGDINFO,&dl); 82234751Sadrian i = ioctl(fd,DIOCGSLICEINFO,&ds); 83234751Sadrian if (i < 0) { 84234751Sadrian#ifdef DEBUG 85234751Sadrian warn("DIOCGSLICEINFO(%s) failed",device); 86234751Sadrian#endif 87234751Sadrian close(fd); 88234751Sadrian return 0; 89234751Sadrian } 90234751Sadrian 91234751Sadrian#ifdef DEBUG 92234751Sadrian for(i=0;i<ds.dss_nslices;i++) 93234751Sadrian if(ds.dss_slices[i].ds_openmask) 94234751Sadrian printf(" open(%d)=0x%2x", 95234751Sadrian i,ds.dss_slices[i].ds_openmask); 96234751Sadrian printf("\n"); 97234751Sadrian#endif 98234751Sadrian 99234751Sadrian if (!size) 100234751Sadrian size = ds.dss_slices[WHOLE_DISK_SLICE].ds_size; 101234751Sadrian 102234751Sadrian p = read_block(fd,0); 103234751Sadrian dp = (struct dos_partition*)(p+DOSPARTOFF); 104234751Sadrian for (i=0; i < NDOSPART; i++) { 105234751Sadrian if (Read_Int32(&dp->dp_start) >= size) 106234751Sadrian continue; 107234751Sadrian if (Read_Int32(&dp->dp_start) + Read_Int32(&dp->dp_size) >= size) 108234751Sadrian continue; 109234751Sadrian if (!Read_Int32(&dp->dp_size)) 110234751Sadrian continue; 111234751Sadrian 112234751Sadrian if (dp->dp_typ == DOSPTYP_ONTRACK) { 113234751Sadrian d->flags |= DISK_ON_TRACK; 114234751Sadrian offset = 63; 115234751Sadrian } 116234751Sadrian 117234751Sadrian } 118234751Sadrian free(p); 119234751Sadrian 120234751Sadrian d->bios_sect = dl.d_nsectors; 121234751Sadrian d->bios_hd = dl.d_ntracks; 122234751Sadrian 123234751Sadrian d->name = strdup(name); 124234751Sadrian 125234751Sadrian 126234751Sadrian if (dl.d_ntracks && dl.d_nsectors) 127234751Sadrian d->bios_cyl = size/(dl.d_ntracks*dl.d_nsectors); 128234751Sadrian 129234751Sadrian if (Add_Chunk(d, -offset, size, name, whole, 0, 0)) 130234751Sadrian#ifdef DEBUG 131234751Sadrian warn("Failed to add 'whole' chunk"); 132234751Sadrian#else 133234751Sadrian {} 134234751Sadrian#endif 135234751Sadrian 136234751Sadrian#ifdef __i386__ 137234751Sadrian for(i=BASE_SLICE;i<ds.dss_nslices;i++) { 138234751Sadrian char sname[20]; 139234751Sadrian chunk_e ce; 140234751Sadrian u_long flags=0; 141234751Sadrian int subtype=0; 142234751Sadrian if (! ds.dss_slices[i].ds_size) 143234751Sadrian continue; 144234751Sadrian ds.dss_slices[i].ds_offset -= offset; 145234751Sadrian sprintf(sname,"%ss%d",name,i-1); 146234751Sadrian subtype = ds.dss_slices[i].ds_type; 147234751Sadrian switch (ds.dss_slices[i].ds_type) { 148234751Sadrian case 0xa5: 149234751Sadrian ce = freebsd; 150234751Sadrian break; 151234751Sadrian case 0x1: 152234751Sadrian case 0x6: 153234751Sadrian case 0x4: 154234751Sadrian case 0xb: 155234751Sadrian case 0xc: 156234751Sadrian case 0xe: 157234751Sadrian ce = fat; 158234751Sadrian break; 159234751Sadrian case DOSPTYP_EXTENDED: 160234751Sadrian case 0xf: 161234751Sadrian ce = extended; 162234751Sadrian break; 163234751Sadrian default: 164234751Sadrian ce = unknown; 165234751Sadrian break; 166234751Sadrian } 167234751Sadrian if (Add_Chunk(d, ds.dss_slices[i].ds_offset, 168234751Sadrian ds.dss_slices[i].ds_size, sname, ce, subtype, flags)) 169234751Sadrian#ifdef DEBUG 170234751Sadrian warn("failed to add chunk for slice %d", i - 1); 171234751Sadrian#else 172234751Sadrian {} 173234751Sadrian#endif 174234751Sadrian 175234751Sadrian if (ds.dss_slices[i].ds_type != 0xa5) 176234751Sadrian continue; 177234751Sadrian { 178234751Sadrian struct disklabel dl; 179234751Sadrian char pname[20]; 180234751Sadrian int j,k; 181234751Sadrian 182234751Sadrian strcpy(pname,"/dev/r"); 183234751Sadrian strcat(pname,sname); 184234751Sadrian j = open(pname,O_RDONLY); 185234751Sadrian if (j < 0) { 186234751Sadrian#ifdef DEBUG 187234751Sadrian warn("open(%s)",pname); 188234751Sadrian#endif 189234751Sadrian continue; 190234751Sadrian } 191234751Sadrian k = ioctl(j,DIOCGDINFO,&dl); 192234751Sadrian if (k < 0) { 193234751Sadrian#ifdef DEBUG 194234751Sadrian warn("ioctl(%s,DIOCGDINFO)",pname); 195234751Sadrian#endif 196234751Sadrian close(j); 197234751Sadrian continue; 198234751Sadrian } 199234751Sadrian close(j); 200234751Sadrian 201234751Sadrian for(j=0; j <= dl.d_npartitions; j++) { 202234751Sadrian if (j == RAW_PART) 203234751Sadrian continue; 204234777Sadrian if (j == 3) 205234777Sadrian continue; 206234777Sadrian if (j == dl.d_npartitions) { 207234751Sadrian j = 3; 208234751Sadrian dl.d_npartitions=0; 209234751Sadrian } 210234751Sadrian if (!dl.d_partitions[j].p_size) 211234751Sadrian continue; 212234751Sadrian if (dl.d_partitions[j].p_size + 213234751Sadrian dl.d_partitions[j].p_offset > 214234751Sadrian ds.dss_slices[i].ds_size) 215234751Sadrian continue; 216234751Sadrian sprintf(pname,"%s%c",sname,j+'a'); 217 if (Add_Chunk(d, 218 dl.d_partitions[j].p_offset + 219 ds.dss_slices[i].ds_offset, 220 dl.d_partitions[j].p_size, 221 pname,part, 222 dl.d_partitions[j].p_fstype, 223 0) && j != 3) 224#ifdef DEBUG 225 warn( 226 "Failed to add chunk for partition %c [%lu,%lu]", 227 j + 'a',dl.d_partitions[j].p_offset, 228 dl.d_partitions[j].p_size); 229#else 230 {} 231#endif 232 } 233 } 234 } 235#endif /* __i386__ */ 236#ifdef __alpha__ 237 { 238 struct disklabel dl; 239 char pname[20]; 240 int j,k; 241 242 strcpy(pname,"/dev/r"); 243 strcat(pname,name); 244 j = open(pname,O_RDONLY); 245 if (j < 0) { 246#ifdef DEBUG 247 warn("open(%s)",pname); 248#endif 249 goto nolabel; 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 goto nolabel; 258 } 259 close(j); 260 All_FreeBSD(d, 1); 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[WHOLE_DISK_SLICE].ds_size) 276 continue; 277 sprintf(pname,"%s%c",name,j+'a'); 278 if (Add_Chunk(d, 279 dl.d_partitions[j].p_offset, 280 dl.d_partitions[j].p_size, 281 pname,part, 282 dl.d_partitions[j].p_fstype, 283 0) && j != 3) 284#ifdef DEBUG 285 warn( 286 "Failed to add chunk for partition %c [%lu,%lu]", 287 j + 'a',dl.d_partitions[j].p_offset, 288 dl.d_partitions[j].p_size); 289#else 290 {} 291#endif 292 } 293 nolabel:; 294 } 295#endif /* __alpha__ */ 296 close(fd); 297 Fixup_Names(d); 298 Bios_Limit_Chunk(d->chunks,1024*d->bios_hd*d->bios_sect); 299 return d; 300} 301 302void 303Debug_Disk(struct disk *d) 304{ 305 printf("Debug_Disk(%s)",d->name); 306 printf(" flags=%lx",d->flags); 307#if 0 308 printf(" real_geom=%lu/%lu/%lu",d->real_cyl,d->real_hd,d->real_sect); 309#endif 310 printf(" bios_geom=%lu/%lu/%lu = %lu\n", 311 d->bios_cyl,d->bios_hd,d->bios_sect, 312 d->bios_cyl*d->bios_hd*d->bios_sect); 313#if defined(__i386__) 314 printf(" boot1=%p, boot2=%p, bootmgr=%p\n", 315 d->boot1,d->boot2,d->bootmgr); 316#elif defined(__alpha__) 317 printf(" boot1=%p, bootmgr=%p\n", 318 d->boot1,d->bootmgr); 319#endif 320 Debug_Chunk(d->chunks); 321} 322 323void 324Free_Disk(struct disk *d) 325{ 326 if(d->chunks) Free_Chunk(d->chunks); 327 if(d->name) free(d->name); 328 if(d->bootmgr) free(d->bootmgr); 329 if(d->boot1) free(d->boot1); 330#if defined(__i386__) 331 if(d->boot2) free(d->boot2); 332#endif 333 free(d); 334} 335 336struct disk * 337Clone_Disk(struct disk *d) 338{ 339 struct disk *d2; 340 341 d2 = (struct disk*) malloc(sizeof *d2); 342 if(!d2) err(1,"malloc failed"); 343 *d2 = *d; 344 d2->name = strdup(d2->name); 345 d2->chunks = Clone_Chunk(d2->chunks); 346 if(d2->bootmgr) { 347 d2->bootmgr = malloc(DOSPARTOFF); 348 memcpy(d2->bootmgr,d->bootmgr,DOSPARTOFF); 349 } 350#if defined(__i386__) 351 if(d2->boot1) { 352 d2->boot1 = malloc(512); 353 memcpy(d2->boot1,d->boot1,512); 354 } 355 if(d2->boot2) { 356 d2->boot2 = malloc(512*15); 357 memcpy(d2->boot2,d->boot2,512*15); 358 } 359#elif defined(__alpha__) 360 if(d2->boot1) { 361 d2->boot1 = malloc(512*15); 362 memcpy(d2->boot1,d->boot1,512*15); 363 } 364#endif 365 return d2; 366} 367 368#if 0 369void 370Collapse_Disk(struct disk *d) 371{ 372 373 while(Collapse_Chunk(d,d->chunks)) 374 ; 375} 376#endif 377 378static char * device_list[] = {"wd", "ad", "da", "wfd", "fla", "idad", "mlxd", "amrd", 0}; 379 380char ** 381Disk_Names() 382{ 383 int i,j,k; 384 char disk[25]; 385 char diskname[25]; 386 struct stat st; 387 struct diskslices ds; 388 int fd; 389 static char **disks; 390 391 disks = malloc(sizeof *disks * (1 + MAX_NO_DISKS)); 392 memset(disks,0,sizeof *disks * (1 + MAX_NO_DISKS)); 393 k = 0; 394 for (j = 0; device_list[j]; j++) { 395 for (i = 0; i < MAX_NO_DISKS; i++) { 396 sprintf(diskname, "%s%d", device_list[j], i); 397 sprintf(disk, "/dev/r%s", diskname); 398 if (stat(disk, &st) || !(st.st_mode & S_IFCHR)) 399 continue; 400 if ((fd = open(disk, O_RDWR)) == -1) 401 continue; 402 if (ioctl(fd, DIOCGSLICEINFO, &ds) == -1) { 403#ifdef DEBUG 404 warn("DIOCGSLICEINFO %s", disk); 405#endif 406 close(fd); 407 continue; 408 } 409 close(fd); 410 disks[k++] = strdup(diskname); 411 if(k == MAX_NO_DISKS) 412 return disks; 413 } 414 } 415 return disks; 416} 417 418void 419Set_Boot_Mgr(struct disk *d, const u_char *b) 420{ 421 if (d->bootmgr) 422 free(d->bootmgr); 423 if (!b) { 424 d->bootmgr = 0; 425 } else { 426 d->bootmgr = malloc(DOSPARTOFF); 427 if(!d->bootmgr) err(1,"malloc failed"); 428 memcpy(d->bootmgr,b,DOSPARTOFF); 429 } 430} 431 432void 433Set_Boot_Blocks(struct disk *d, const u_char *b1, const u_char *b2) 434{ 435#if defined(__i386__) 436 if (d->boot1) free(d->boot1); 437 d->boot1 = malloc(512); 438 if(!d->boot1) err(1,"malloc failed"); 439 memcpy(d->boot1,b1,512); 440 if (d->boot2) free(d->boot2); 441 d->boot2 = malloc(15*512); 442 if(!d->boot2) err(1,"malloc failed"); 443 memcpy(d->boot2,b2,15*512); 444#elif defined(__alpha__) 445 if (d->boot1) free(d->boot1); 446 d->boot1 = malloc(15*512); 447 if(!d->boot1) err(1,"malloc failed"); 448 memcpy(d->boot1,b1,15*512); 449#endif 450} 451 452const char * 453slice_type_name( int type, int subtype ) 454{ 455 switch (type) { 456 case 0: return "whole"; 457 case 1: switch (subtype) { 458 case 1: return "fat (12-bit)"; 459 case 2: return "XENIX /"; 460 case 3: return "XENIX /usr"; 461 case 4: return "fat (16-bit,<=32Mb)"; 462 case 5: return "extended DOS"; 463 case 6: return "fat (16-bit,>32Mb)"; 464 case 7: return "NTFS/HPFS/QNX"; 465 case 8: return "AIX bootable"; 466 case 9: return "AIX data"; 467 case 10: return "OS/2 bootmgr"; 468 case 11: return "fat (32-bit)"; 469 case 12: return "fat (32-bit,LBA)"; 470 case 14: return "fat (16-bit,>32Mb,LBA)"; 471 case 15: return "extended DOS, LBA"; 472 case 18: return "Compaq Diagnostic"; 473 case 84: return "OnTrack diskmgr"; 474 case 100: return "Netware 2.x"; 475 case 101: return "Netware 3.x"; 476 case 115: return "SCO UnixWare"; 477 case 128: return "Minix 1.1"; 478 case 129: return "Minix 1.5"; 479 case 130: return "linux_swap"; 480 case 131: return "ext2fs"; 481 case 166: return "OpenBSD FFS"; /* 0xA6 */ 482 case 169: return "NetBSD FFS"; /* 0xA9 */ 483 case 182: return "OpenBSD"; /* dedicated */ 484 case 183: return "bsd/os"; 485 case 184: return "bsd/os swap"; 486 default: return "unknown"; 487 } 488 case 2: return "fat"; 489 case 3: switch (subtype) { 490 case 165: return "freebsd"; 491 default: return "unknown"; 492 } 493 case 4: return "extended"; 494 case 5: return "part"; 495 case 6: return "unused"; 496 default: return "unknown"; 497 } 498} 499