disk.c revision 40000
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.37 1998/09/30 21:40:51 jkh 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 for(i=BASE_SLICE;i<ds.dss_nslices;i++) { 147 char sname[20]; 148 chunk_e ce; 149 u_long flags=0; 150 int subtype=0; 151 if (! ds.dss_slices[i].ds_size) 152 continue; 153 ds.dss_slices[i].ds_offset -= offset; 154 sprintf(sname,"%ss%d",name,i-1); 155 subtype = ds.dss_slices[i].ds_type; 156 switch (ds.dss_slices[i].ds_type) { 157 case 0xa5: 158 ce = freebsd; 159 break; 160 case 0x1: 161 case 0x6: 162 case 0x4: 163 case 0xb: 164 case 0xc: 165 case 0xe: 166 ce = fat; 167 break; 168 case DOSPTYP_EXTENDED: 169 case 0xf: 170 ce = extended; 171 break; 172 default: 173 ce = unknown; 174 break; 175 } 176 if (Add_Chunk(d, ds.dss_slices[i].ds_offset, 177 ds.dss_slices[i].ds_size, sname, ce, subtype, flags)) 178#ifdef DEBUG 179 warn("failed to add chunk for slice %d", i - 1); 180#else 181 {} 182#endif 183 184 if (ds.dss_slices[i].ds_type != 0xa5) 185 continue; 186 { 187 struct disklabel dl; 188 char pname[20]; 189 int j,k; 190 191 strcpy(pname,"/dev/r"); 192 strcat(pname,sname); 193 j = open(pname,O_RDONLY); 194 if (j < 0) { 195#ifdef DEBUG 196 warn("open(%s)",pname); 197#endif 198 continue; 199 } 200 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",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