disk.c revision 43393
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 * $Id: disk.c,v 1.39 1998/12/19 18:48:33 phk Exp $ 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/types.h> 20#include <sys/stat.h> 21#include <sys/ioctl.h> 22#include <sys/disklabel.h> 23#include <sys/diskslice.h> 24#include "libdisk.h" 25 26#define DOSPTYP_EXTENDED 5 27#define DOSPTYP_ONTRACK 84 28 29const char *chunk_n[] = { 30 "whole", 31 "unknown", 32 "fat", 33 "freebsd", 34 "extended", 35 "part", 36 "unused", 37 NULL 38}; 39 40struct disk * 41Open_Disk(const char *name) 42{ 43 return Int_Open_Disk(name,0); 44} 45 46static u_int32_t 47Read_Int32(u_int32_t *p) 48{ 49 u_int8_t *bp = (u_int8_t *)p; 50 return bp[0] | (bp[1] << 8) | (bp[2] << 16) | (bp[3] << 24); 51} 52 53static void 54Write_Int32(u_int32_t *p, u_int32_t v) 55{ 56 u_int8_t *bp = (u_int8_t *)p; 57 bp[0] = (v >> 0) & 0xff; 58 bp[1] = (v >> 8) & 0xff; 59 bp[2] = (v >> 16) & 0xff; 60 bp[3] = (v >> 24) & 0xff; 61} 62 63struct disk * 64Int_Open_Disk(const char *name, u_long size) 65{ 66 int i,fd; 67 struct diskslices ds; 68 struct disklabel dl; 69 char device[64]; 70 struct disk *d; 71 struct dos_partition *dp; 72 void *p; 73 u_long offset = 0; 74 75 strcpy(device,"/dev/r"); 76 strcat(device,name); 77 78 d = (struct disk *)malloc(sizeof *d); 79 if(!d) err(1,"malloc failed"); 80 memset(d,0,sizeof *d); 81 82 fd = open(device,O_RDONLY); 83 if (fd < 0) { 84#ifdef DEBUG 85 warn("open(%s) failed",device); 86#endif 87 return 0; 88 } 89 90 memset(&dl,0,sizeof dl); 91 ioctl(fd,DIOCGDINFO,&dl); 92 i = ioctl(fd,DIOCGSLICEINFO,&ds); 93 if (i < 0) { 94#ifdef DEBUG 95 warn("DIOCGSLICEINFO(%s) failed",device); 96#endif 97 close(fd); 98 return 0; 99 } 100 101#ifdef DEBUG 102 for(i=0;i<ds.dss_nslices;i++) 103 if(ds.dss_slices[i].ds_openmask) 104 printf(" open(%d)=0x%2x", 105 i,ds.dss_slices[i].ds_openmask); 106 printf("\n"); 107#endif 108 109 if (!size) 110 size = ds.dss_slices[WHOLE_DISK_SLICE].ds_size; 111 112 p = read_block(fd,0); 113 dp = (struct dos_partition*)(p+DOSPARTOFF); 114 for (i=0; i < NDOSPART; i++) { 115 if (Read_Int32(&dp->dp_start) >= size) 116 continue; 117 if (Read_Int32(&dp->dp_start) + Read_Int32(&dp->dp_size) >= size) 118 continue; 119 if (!Read_Int32(&dp->dp_size)) 120 continue; 121 122 if (dp->dp_typ == DOSPTYP_ONTRACK) { 123 d->flags |= DISK_ON_TRACK; 124 offset = 63; 125 } 126 127 } 128 free(p); 129 130 d->bios_sect = dl.d_nsectors; 131 d->bios_hd = dl.d_ntracks; 132 133 d->name = strdup(name); 134 135 136 if (dl.d_ntracks && dl.d_nsectors) 137 d->bios_cyl = size/(dl.d_ntracks*dl.d_nsectors); 138 139 if (Add_Chunk(d, -offset, size, name, whole, 0, 0)) 140#ifdef DEBUG 141 warn("Failed to add 'whole' chunk"); 142#else 143 {} 144#endif 145 146#ifdef __i386__ 147 for(i=BASE_SLICE;i<ds.dss_nslices;i++) { 148 char sname[20]; 149 chunk_e ce; 150 u_long flags=0; 151 int subtype=0; 152 if (! ds.dss_slices[i].ds_size) 153 continue; 154 ds.dss_slices[i].ds_offset -= offset; 155 sprintf(sname,"%ss%d",name,i-1); 156 subtype = ds.dss_slices[i].ds_type; 157 switch (ds.dss_slices[i].ds_type) { 158 case 0xa5: 159 ce = freebsd; 160 break; 161 case 0x1: 162 case 0x6: 163 case 0x4: 164 case 0xb: 165 case 0xc: 166 case 0xe: 167 ce = fat; 168 break; 169 case DOSPTYP_EXTENDED: 170 case 0xf: 171 ce = extended; 172 break; 173 default: 174 ce = unknown; 175 break; 176 } 177 if (Add_Chunk(d, ds.dss_slices[i].ds_offset, 178 ds.dss_slices[i].ds_size, sname, ce, subtype, flags)) 179#ifdef DEBUG 180 warn("failed to add chunk for slice %d", i - 1); 181#else 182 {} 183#endif 184 185 if (ds.dss_slices[i].ds_type != 0xa5) 186 continue; 187 { 188 struct disklabel dl; 189 char pname[20]; 190 int j,k; 191 192 strcpy(pname,"/dev/r"); 193 strcat(pname,sname); 194 j = open(pname,O_RDONLY); 195 if (j < 0) { 196#ifdef DEBUG 197 warn("open(%s)",pname); 198#endif 199 continue; 200 } 201 k = ioctl(j,DIOCGDINFO,&dl); 202 if (k < 0) { 203#ifdef DEBUG 204 warn("ioctl(%s,DIOCGDINFO)",pname); 205#endif 206 close(j); 207 continue; 208 } 209 close(j); 210 211 for(j=0; j <= dl.d_npartitions; j++) { 212 if (j == RAW_PART) 213 continue; 214 if (j == 3) 215 continue; 216 if (j == dl.d_npartitions) { 217 j = 3; 218 dl.d_npartitions=0; 219 } 220 if (!dl.d_partitions[j].p_size) 221 continue; 222 if (dl.d_partitions[j].p_size + 223 dl.d_partitions[j].p_offset > 224 ds.dss_slices[i].ds_size) 225 continue; 226 sprintf(pname,"%s%c",sname,j+'a'); 227 if (Add_Chunk(d, 228 dl.d_partitions[j].p_offset + 229 ds.dss_slices[i].ds_offset, 230 dl.d_partitions[j].p_size, 231 pname,part, 232 dl.d_partitions[j].p_fstype, 233 0) && j != 3) 234#ifdef DEBUG 235 warn( 236 "Failed to add chunk for partition %c [%lu,%lu]", 237 j + 'a',dl.d_partitions[j].p_offset, 238 dl.d_partitions[j].p_size); 239#else 240 {} 241#endif 242 } 243 } 244 } 245#endif /* __i386__ */ 246#ifdef __alpha__ 247 { 248 struct disklabel dl; 249 char pname[20]; 250 int j,k; 251 252 strcpy(pname,"/dev/r"); 253 strcat(pname,name); 254 j = open(pname,O_RDONLY); 255 if (j < 0) { 256#ifdef DEBUG 257 warn("open(%s)",pname); 258#endif 259 goto nolabel; 260 } 261 k = ioctl(j,DIOCGDINFO,&dl); 262 if (k < 0) { 263#ifdef DEBUG 264 warn("ioctl(%s,DIOCGDINFO)",pname); 265#endif 266 close(j); 267 goto nolabel; 268 } 269 close(j); 270 All_FreeBSD(d, 1); 271 272 for(j=0; j <= dl.d_npartitions; j++) { 273 if (j == RAW_PART) 274 continue; 275 if (j == 3) 276 continue; 277 if (j == dl.d_npartitions) { 278 j = 3; 279 dl.d_npartitions=0; 280 } 281 if (!dl.d_partitions[j].p_size) 282 continue; 283 if (dl.d_partitions[j].p_size + 284 dl.d_partitions[j].p_offset > 285 ds.dss_slices[WHOLE_DISK_SLICE].ds_size) 286 continue; 287 sprintf(pname,"%s%c",name,j+'a'); 288 if (Add_Chunk(d, 289 dl.d_partitions[j].p_offset, 290 dl.d_partitions[j].p_size, 291 pname,part, 292 dl.d_partitions[j].p_fstype, 293 0) && j != 3) 294#ifdef DEBUG 295 warn( 296 "Failed to add chunk for partition %c [%lu,%lu]", 297 j + 'a',dl.d_partitions[j].p_offset, 298 dl.d_partitions[j].p_size); 299#else 300 {} 301#endif 302 } 303 nolabel:; 304 } 305#endif /* __alpha__ */ 306 close(fd); 307 Fixup_Names(d); 308 Bios_Limit_Chunk(d->chunks,1024*d->bios_hd*d->bios_sect); 309 return d; 310} 311 312void 313Debug_Disk(struct disk *d) 314{ 315 printf("Debug_Disk(%s)",d->name); 316 printf(" flags=%lx",d->flags); 317#if 0 318 printf(" real_geom=%lu/%lu/%lu",d->real_cyl,d->real_hd,d->real_sect); 319#endif 320 printf(" bios_geom=%lu/%lu/%lu = %lu\n", 321 d->bios_cyl,d->bios_hd,d->bios_sect, 322 d->bios_cyl*d->bios_hd*d->bios_sect); 323#if defined(__i386__) 324 printf(" boot1=%p, boot2=%p, bootmgr=%p\n", 325 d->boot1,d->boot2,d->bootmgr); 326#elif defined(__alpha__) 327 printf(" boot1=%p, bootmgr=%p\n", 328 d->boot1,d->bootmgr); 329#endif 330 Debug_Chunk(d->chunks); 331} 332 333void 334Free_Disk(struct disk *d) 335{ 336 if(d->chunks) Free_Chunk(d->chunks); 337 if(d->name) free(d->name); 338 if(d->bootmgr) free(d->bootmgr); 339 if(d->boot1) free(d->boot1); 340#if defined(__i386__) 341 if(d->boot2) free(d->boot2); 342#endif 343 free(d); 344} 345 346struct disk * 347Clone_Disk(struct disk *d) 348{ 349 struct disk *d2; 350 351 d2 = (struct disk*) malloc(sizeof *d2); 352 if(!d2) err(1,"malloc failed"); 353 *d2 = *d; 354 d2->name = strdup(d2->name); 355 d2->chunks = Clone_Chunk(d2->chunks); 356 if(d2->bootmgr) { 357 d2->bootmgr = malloc(DOSPARTOFF); 358 memcpy(d2->bootmgr,d->bootmgr,DOSPARTOFF); 359 } 360#if defined(__i386__) 361 if(d2->boot1) { 362 d2->boot1 = malloc(512); 363 memcpy(d2->boot1,d->boot1,512); 364 } 365 if(d2->boot2) { 366 d2->boot2 = malloc(512*15); 367 memcpy(d2->boot2,d->boot2,512*15); 368 } 369#elif defined(__alpha__) 370 if(d2->boot1) { 371 d2->boot1 = malloc(512*15); 372 memcpy(d2->boot1,d->boot1,512*15); 373 } 374#endif 375 return d2; 376} 377 378#if 0 379void 380Collapse_Disk(struct disk *d) 381{ 382 383 while(Collapse_Chunk(d,d->chunks)) 384 ; 385} 386#endif 387 388static char * device_list[] = {"wd", "sd", "da", "wfd", "fla", 0}; 389 390char ** 391Disk_Names() 392{ 393 int i,j,k; 394 char disk[25]; 395 char diskname[25]; 396 struct stat st; 397 struct diskslices ds; 398 int fd; 399 static char **disks; 400 401 disks = malloc(sizeof *disks * (1 + MAX_NO_DISKS)); 402 memset(disks,0,sizeof *disks * (1 + MAX_NO_DISKS)); 403 k = 0; 404 for (j = 0; device_list[j]; j++) { 405 for (i = 0; i < MAX_NO_DISKS; i++) { 406 sprintf(diskname, "%s%d", device_list[j], i); 407 sprintf(disk, "/dev/r%s", diskname); 408 if (stat(disk, &st) || !(st.st_mode & S_IFCHR)) 409 continue; 410 if ((fd = open(disk, O_RDWR)) == -1) 411 continue; 412 if (ioctl(fd, DIOCGSLICEINFO, &ds) == -1) { 413 close(fd); 414 continue; 415 } 416 disks[k++] = strdup(diskname); 417 if(k == MAX_NO_DISKS) 418 return disks; 419 } 420 } 421 return disks; 422} 423 424void 425Set_Boot_Mgr(struct disk *d, const u_char *b) 426{ 427 if (d->bootmgr) 428 free(d->bootmgr); 429 if (!b) { 430 d->bootmgr = 0; 431 } else { 432 d->bootmgr = malloc(DOSPARTOFF); 433 if(!d->bootmgr) err(1,"malloc failed"); 434 memcpy(d->bootmgr,b,DOSPARTOFF); 435 } 436} 437 438void 439Set_Boot_Blocks(struct disk *d, const u_char *b1, const u_char *b2) 440{ 441#if defined(__i386__) 442 if (d->boot1) free(d->boot1); 443 d->boot1 = malloc(512); 444 if(!d->boot1) err(1,"malloc failed"); 445 memcpy(d->boot1,b1,512); 446 if (d->boot2) free(d->boot2); 447 d->boot2 = malloc(15*512); 448 if(!d->boot2) err(1,"malloc failed"); 449 memcpy(d->boot2,b2,15*512); 450#elif defined(__alpha__) 451 if (d->boot1) free(d->boot1); 452 d->boot1 = malloc(15*512); 453 if(!d->boot1) err(1,"malloc failed"); 454 memcpy(d->boot1,b1,15*512); 455#endif 456} 457 458const char * 459slice_type_name( int type, int subtype ) 460{ 461 switch (type) { 462 case 0: return "whole"; 463 case 1: switch (subtype) { 464 case 1: return "fat (12-bit)"; 465 case 2: return "XENIX /"; 466 case 3: return "XENIX /usr"; 467 case 4: return "fat (16-bit,<=32Mb)"; 468 case 5: return "extended DOS"; 469 case 6: return "fat (16-bit,>32Mb)"; 470 case 7: return "NTFS/HPFS/QNX"; 471 case 8: return "AIX bootable"; 472 case 9: return "AIX data"; 473 case 10: return "OS/2 bootmgr"; 474 case 11: return "fat (32-bit)"; 475 case 12: return "fat (32-bit,LBA)"; 476 case 14: return "fat (16-bit,>32Mb,LBA)"; 477 case 15: return "extended DOS, LBA"; 478 case 18: return "Compaq Diagnostic"; 479 case 84: return "OnTrack diskmgr"; 480 case 100: return "Netware 2.x"; 481 case 101: return "Netware 3.x"; 482 case 115: return "SCO UnixWare"; 483 case 128: return "Minix 1.1"; 484 case 129: return "Minix 1.5"; 485 case 130: return "linux_swap"; 486 case 131: return "ext2fs"; 487 case 166: return "OpenBSD FFS"; /* 0xA6 */ 488 case 169: return "NetBSD FFS"; /* 0xA9 */ 489 case 182: return "OpenBSD"; /* dedicated */ 490 case 183: return "bsd/os"; 491 case 184: return "bsd/os swap"; 492 default: return "unknown"; 493 } 494 case 2: return "fat"; 495 case 3: switch (subtype) { 496 case 165: return "freebsd"; 497 default: return "unknown"; 498 } 499 case 4: return "extended"; 500 case 5: return "part"; 501 case 6: return "unused"; 502 default: return "unknown"; 503 } 504} 505