disk.c revision 41941
1171195Sscf/* 2171195Sscf * ---------------------------------------------------------------------------- 3171195Sscf * "THE BEER-WARE LICENSE" (Revision 42): 4171195Sscf * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you 5171195Sscf * can do whatever you want with this stuff. If we meet some day, and you think 6171195Sscf * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp 7171195Sscf * ---------------------------------------------------------------------------- 8171195Sscf * 9171195Sscf * $Id: disk.c,v 1.38 1998/10/06 11:57:08 dfr Exp $ 10171195Sscf * 11171195Sscf */ 12171195Sscf 13171195Sscf#include <stdio.h> 14171195Sscf#include <stdlib.h> 15171195Sscf#include <unistd.h> 16171195Sscf#include <fcntl.h> 17171195Sscf#include <string.h> 18171195Sscf#include <err.h> 19171195Sscf#include <sys/types.h> 20171195Sscf#include <sys/stat.h> 21171195Sscf#include <sys/ioctl.h> 22171195Sscf#include <sys/disklabel.h> 23171195Sscf#include <sys/diskslice.h> 24171195Sscf#include "libdisk.h" 25171195Sscf 26171525Sscf#define DOSPTYP_EXTENDED 5 27171195Sscf#define DOSPTYP_ONTRACK 84 28171525Sscf 29171195Sscfconst char *chunk_n[] = { 30171195Sscf "whole", 31171195Sscf "unknown", 32171195Sscf "fat", 33171195Sscf "freebsd", 34171195Sscf "extended", 35171195Sscf "part", 36171195Sscf "unused", 37171195Sscf NULL 38171195Sscf}; 39171195Sscf 40171195Sscfstruct disk * 41171195SscfOpen_Disk(const char *name) 42171195Sscf{ 43171195Sscf return Int_Open_Disk(name,0); 44171195Sscf} 45171195Sscf 46171195Sscfstatic u_int32_t 47171195SscfRead_Int32(u_int32_t *p) 48171195Sscf{ 49171195Sscf u_int8_t *bp = (u_int8_t *)p; 50171195Sscf return bp[0] | (bp[1] << 8) | (bp[2] << 16) | (bp[3] << 24); 51171195Sscf} 52171195Sscf 53171195Sscfstatic void 54171195SscfWrite_Int32(u_int32_t *p, u_int32_t v) 55171195Sscf{ 56171195Sscf u_int8_t *bp = (u_int8_t *)p; 57171195Sscf bp[0] = (v >> 0) & 0xff; 58171195Sscf bp[1] = (v >> 8) & 0xff; 59171195Sscf bp[2] = (v >> 16) & 0xff; 60171195Sscf bp[3] = (v >> 24) & 0xff; 61171195Sscf} 62171195Sscf 63171195Sscfstruct disk * 64171195SscfInt_Open_Disk(const char *name, u_long size) 65171195Sscf{ 66171195Sscf int i,fd; 67171195Sscf struct diskslices ds; 68171195Sscf struct disklabel dl; 69171525Sscf char device[64]; 70171525Sscf struct disk *d; 71171195Sscf struct dos_partition *dp; 72171195Sscf void *p; 73171195Sscf u_long offset = 0; 74171195Sscf 75171525Sscf strcpy(device,"/dev/r"); 76171195Sscf strcat(device,name); 77171195Sscf 78171195Sscf d = (struct disk *)malloc(sizeof *d); 79171195Sscf if(!d) err(1,"malloc failed"); 80171195Sscf memset(d,0,sizeof *d); 81171195Sscf 82171525Sscf fd = open(device,O_RDONLY); 83171195Sscf if (fd < 0) { 84171525Sscf#ifdef DEBUG 85171195Sscf warn("open(%s) failed",device); 86171195Sscf#endif 87171195Sscf return 0; 88171195Sscf } 89171195Sscf 90171525Sscf memset(&dl,0,sizeof dl); 91171195Sscf ioctl(fd,DIOCGDINFO,&dl); 92171195Sscf i = ioctl(fd,DIOCGSLICEINFO,&ds); 93171195Sscf if (i < 0) { 94171195Sscf#ifdef DEBUG 95171195Sscf warn("DIOCGSLICEINFO(%s) failed",device); 96171195Sscf#endif 97171525Sscf close(fd); 98171195Sscf return 0; 99171525Sscf } 100171525Sscf 101171195Sscf#ifdef DEBUG 102171195Sscf for(i=0;i<ds.dss_nslices;i++) 103171195Sscf if(ds.dss_slices[i].ds_openmask) 104171195Sscf printf(" open(%d)=0x%2x", 105171195Sscf i,ds.dss_slices[i].ds_openmask); 106171525Sscf printf("\n"); 107171195Sscf#endif 108171195Sscf 109171195Sscf if (!size) 110171195Sscf size = ds.dss_slices[WHOLE_DISK_SLICE].ds_size; 111171195Sscf 112171195Sscf p = read_block(fd,0); 113171195Sscf dp = (struct dos_partition*)(p+DOSPARTOFF); 114171525Sscf for (i=0; i < NDOSPART; i++) { 115171195Sscf if (Read_Int32(&dp->dp_start) >= size) 116171525Sscf continue; 117171195Sscf if (Read_Int32(&dp->dp_start) + Read_Int32(&dp->dp_size) >= size) 118171195Sscf continue; 119171195Sscf if (!Read_Int32(&dp->dp_size)) 120171195Sscf continue; 121171195Sscf 122171525Sscf if (dp->dp_typ == DOSPTYP_ONTRACK) { 123171195Sscf d->flags |= DISK_ON_TRACK; 124171195Sscf offset = 63; 125171195Sscf } 126171195Sscf 127171195Sscf } 128171195Sscf free(p); 129171195Sscf 130171525Sscf d->bios_sect = dl.d_nsectors; 131171195Sscf d->bios_hd = dl.d_ntracks; 132171525Sscf 133171195Sscf d->name = strdup(name); 134171195Sscf 135171195Sscf 136171195Sscf if (dl.d_ntracks && dl.d_nsectors) 137171195Sscf d->bios_cyl = size/(dl.d_ntracks*dl.d_nsectors); 138171525Sscf 139171195Sscf if (Add_Chunk(d, -offset, size, name, whole, 0, 0)) 140171195Sscf#ifdef DEBUG 141171195Sscf warn("Failed to add 'whole' chunk"); 142171195Sscf#else 143171195Sscf {} 144171195Sscf#endif 145171525Sscf 146171195Sscf for(i=BASE_SLICE;i<ds.dss_nslices;i++) { 147171525Sscf char sname[20]; 148171525Sscf chunk_e ce; 149171195Sscf u_long flags=0; 150171195Sscf int subtype=0; 151171195Sscf if (! ds.dss_slices[i].ds_size) 152171195Sscf continue; 153171195Sscf ds.dss_slices[i].ds_offset -= offset; 154171525Sscf sprintf(sname,"%ss%d",name,i-1); 155171195Sscf subtype = ds.dss_slices[i].ds_type; 156171195Sscf switch (ds.dss_slices[i].ds_type) { 157171195Sscf case 0xa5: 158171195Sscf ce = freebsd; 159171195Sscf break; 160171195Sscf case 0x1: 161171195Sscf case 0x6: 162171525Sscf case 0x4: 163171195Sscf case 0xb: 164171525Sscf case 0xc: 165171195Sscf case 0xe: 166171195Sscf ce = fat; 167171195Sscf break; 168171195Sscf case DOSPTYP_EXTENDED: 169171195Sscf case 0xf: 170171525Sscf ce = extended; 171171195Sscf break; 172171195Sscf default: 173171195Sscf ce = unknown; 174171195Sscf break; 175171195Sscf } 176171195Sscf if (Add_Chunk(d, ds.dss_slices[i].ds_offset, 177171195Sscf ds.dss_slices[i].ds_size, sname, ce, subtype, flags)) 178171525Sscf#ifdef DEBUG 179171195Sscf warn("failed to add chunk for slice %d", i - 1); 180171525Sscf#else 181171195Sscf {} 182171195Sscf#endif 183171195Sscf 184171195Sscf if (ds.dss_slices[i].ds_type != 0xa5) 185171195Sscf continue; 186171525Sscf { 187171195Sscf struct disklabel dl; 188171195Sscf char pname[20]; 189171195Sscf int j,k; 190171195Sscf 191171195Sscf strcpy(pname,"/dev/r"); 192171195Sscf strcat(pname,sname); 193171525Sscf j = open(pname,O_RDONLY); 194171195Sscf if (j < 0) { 195171525Sscf#ifdef DEBUG 196171525Sscf warn("open(%s)",pname); 197171195Sscf#endif 198171195Sscf continue; 199171195Sscf } 200171195Sscf k = ioctl(j,DIOCGDINFO,&dl); 201 if (k < 0) { 202#ifdef DEBUG 203 warn("ioctl(%s,DIOCGDINFO)",pname); 204#endif 205 close(j); 206 continue; 207 } 208 close(j); 209 210 for(j=0; j <= dl.d_npartitions; j++) { 211 if (j == RAW_PART) 212 continue; 213 if (j == 3) 214 continue; 215 if (j == dl.d_npartitions) { 216 j = 3; 217 dl.d_npartitions=0; 218 } 219 if (!dl.d_partitions[j].p_size) 220 continue; 221 if (dl.d_partitions[j].p_size + 222 dl.d_partitions[j].p_offset > 223 ds.dss_slices[i].ds_size) 224 continue; 225 sprintf(pname,"%s%c",sname,j+'a'); 226 if (Add_Chunk(d, 227 dl.d_partitions[j].p_offset + 228 ds.dss_slices[i].ds_offset, 229 dl.d_partitions[j].p_size, 230 pname,part, 231 dl.d_partitions[j].p_fstype, 232 0) && j != 3) 233#ifdef DEBUG 234 warn( 235 "Failed to add chunk for partition %c [%lu,%lu]", 236 j + 'a',dl.d_partitions[j].p_offset, 237 dl.d_partitions[j].p_size); 238#else 239 {} 240#endif 241 } 242 } 243 } 244 close(fd); 245 Fixup_Names(d); 246 Bios_Limit_Chunk(d->chunks,1024*d->bios_hd*d->bios_sect); 247 return d; 248} 249 250void 251Debug_Disk(struct disk *d) 252{ 253 printf("Debug_Disk(%s)",d->name); 254 printf(" flags=%lx",d->flags); 255#if 0 256 printf(" real_geom=%lu/%lu/%lu",d->real_cyl,d->real_hd,d->real_sect); 257#endif 258 printf(" bios_geom=%lu/%lu/%lu = %lu\n", 259 d->bios_cyl,d->bios_hd,d->bios_sect, 260 d->bios_cyl*d->bios_hd*d->bios_sect); 261#if defined(__i386__) 262 printf(" boot1=%p, boot2=%p, bootmgr=%p\n", 263 d->boot1,d->boot2,d->bootmgr); 264#elif defined(__alpha__) 265 printf(" boot1=%p, bootmgr=%p\n", 266 d->boot1,d->bootmgr); 267#endif 268 Debug_Chunk(d->chunks); 269} 270 271void 272Free_Disk(struct disk *d) 273{ 274 if(d->chunks) Free_Chunk(d->chunks); 275 if(d->name) free(d->name); 276 if(d->bootmgr) free(d->bootmgr); 277 if(d->boot1) free(d->boot1); 278#if defined(__i386__) 279 if(d->boot2) free(d->boot2); 280#endif 281 free(d); 282} 283 284struct disk * 285Clone_Disk(struct disk *d) 286{ 287 struct disk *d2; 288 289 d2 = (struct disk*) malloc(sizeof *d2); 290 if(!d2) err(1,"malloc failed"); 291 *d2 = *d; 292 d2->name = strdup(d2->name); 293 d2->chunks = Clone_Chunk(d2->chunks); 294 if(d2->bootmgr) { 295 d2->bootmgr = malloc(DOSPARTOFF); 296 memcpy(d2->bootmgr,d->bootmgr,DOSPARTOFF); 297 } 298#if defined(__i386__) 299 if(d2->boot1) { 300 d2->boot1 = malloc(512); 301 memcpy(d2->boot1,d->boot1,512); 302 } 303 if(d2->boot2) { 304 d2->boot2 = malloc(512*15); 305 memcpy(d2->boot2,d->boot2,512*15); 306 } 307#elif defined(__alpha__) 308 if(d2->boot1) { 309 d2->boot1 = malloc(512*15); 310 memcpy(d2->boot1,d->boot1,512*15); 311 } 312#endif 313 return d2; 314} 315 316#if 0 317void 318Collapse_Disk(struct disk *d) 319{ 320 321 while(Collapse_Chunk(d,d->chunks)) 322 ; 323} 324#endif 325 326static char * device_list[] = {"wd", "sd", "da", "wfd", "fla", 0}; 327 328char ** 329Disk_Names() 330{ 331 int i,j,k; 332 char disk[25]; 333 char diskname[25]; 334 struct stat st; 335 struct diskslices ds; 336 int fd; 337 static char **disks; 338 339 disks = malloc(sizeof *disks * (1 + MAX_NO_DISKS)); 340 memset(disks,0,sizeof *disks * (1 + MAX_NO_DISKS)); 341 k = 0; 342 for (j = 0; device_list[j]; j++) { 343 for (i = 0; i < MAX_NO_DISKS; i++) { 344 sprintf(diskname, "%s%d", device_list[j], i); 345 sprintf(disk, "/dev/r%s", diskname); 346 if (stat(disk, &st) || !(st.st_mode & S_IFCHR)) 347 continue; 348 if ((fd = open(disk, O_RDWR)) == -1) 349 continue; 350 if (ioctl(fd, DIOCGSLICEINFO, &ds) == -1) { 351 close(fd); 352 continue; 353 } 354 disks[k++] = strdup(diskname); 355 if(k == MAX_NO_DISKS) 356 return disks; 357 } 358 } 359 return disks; 360} 361 362void 363Set_Boot_Mgr(struct disk *d, const u_char *b) 364{ 365 if (d->bootmgr) 366 free(d->bootmgr); 367 if (!b) { 368 d->bootmgr = 0; 369 } else { 370 d->bootmgr = malloc(DOSPARTOFF); 371 if(!d->bootmgr) err(1,"malloc failed"); 372 memcpy(d->bootmgr,b,DOSPARTOFF); 373 } 374} 375 376void 377Set_Boot_Blocks(struct disk *d, const u_char *b1, const u_char *b2) 378{ 379#if defined(__i386__) 380 if (d->boot1) free(d->boot1); 381 d->boot1 = malloc(512); 382 if(!d->boot1) err(1,"malloc failed"); 383 memcpy(d->boot1,b1,512); 384 if (d->boot2) free(d->boot2); 385 d->boot2 = malloc(15*512); 386 if(!d->boot2) err(1,"malloc failed"); 387 memcpy(d->boot2,b2,15*512); 388#elif defined(__alpha__) 389 if (d->boot1) free(d->boot1); 390 d->boot1 = malloc(15*512); 391 if(!d->boot1) err(1,"malloc failed"); 392 memcpy(d->boot1,b1,15*512); 393#endif 394} 395 396const char * 397slice_type_name( int type, int subtype ) 398{ 399 switch (type) { 400 case 0: return "whole"; 401 case 1: switch (subtype) { 402 case 1: return "fat (12-bit)"; 403 case 2: return "XENIX /"; 404 case 3: return "XENIX /usr"; 405 case 4: return "fat (16-bit,<=32Mb)"; 406 case 5: return "extended DOS"; 407 case 6: return "fat (16-bit,>32Mb)"; 408 case 7: return "NTFS/HPFS/QNX"; 409 case 8: return "AIX bootable"; 410 case 9: return "AIX data"; 411 case 10: return "OS/2 bootmgr"; 412 case 11: return "fat (32-bit)"; 413 case 12: return "fat (32-bit,LBA)"; 414 case 14: return "fat (16-bit,>32Mb,LBA)"; 415 case 15: return "extended DOS, LBA"; 416 case 18: return "Compaq Diagnostic"; 417 case 84: return "OnTrack diskmgr"; 418 case 100: return "Netware 2.x"; 419 case 101: return "Netware 3.x"; 420 case 115: return "SCO UnixWare"; 421 case 128: return "Minix 1.1"; 422 case 129: return "Minix 1.5"; 423 case 130: return "linux_swap"; 424 case 131: return "ext2fs"; 425 case 166: return "OpenBSD FFS"; /* 0xA6 */ 426 case 169: return "NetBSD FFS"; /* 0xA9 */ 427 case 182: return "OpenBSD"; /* dedicated */ 428 case 183: return "bsd/os"; 429 case 184: return "bsd/os swap"; 430 default: return "unknown"; 431 } 432 case 2: return "fat"; 433 case 3: switch (subtype) { 434 case 165: return "freebsd"; 435 default: return "unknown"; 436 } 437 case 4: return "extended"; 438 case 5: return "part"; 439 case 6: return "unused"; 440 default: return "unknown"; 441 } 442} 443