disk.c revision 34579
1129202Scognet/* 2129202Scognet * ---------------------------------------------------------------------------- 3129202Scognet * "THE BEER-WARE LICENSE" (Revision 42): 4129202Scognet * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you 5129202Scognet * can do whatever you want with this stuff. If we meet some day, and you think 6129202Scognet * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp 7129202Scognet * ---------------------------------------------------------------------------- 8129202Scognet * 9129202Scognet * $Id: disk.c,v 1.30 1998/03/07 08:45:46 ache Exp $ 10129202Scognet * 11129202Scognet */ 12129202Scognet 13129202Scognet#include <stdio.h> 14129202Scognet#include <stdlib.h> 15129202Scognet#include <unistd.h> 16129202Scognet#include <fcntl.h> 17129202Scognet#include <string.h> 18129202Scognet#include <err.h> 19129202Scognet#include <sys/types.h> 20129202Scognet#include <sys/stat.h> 21129202Scognet#include <sys/ioctl.h> 22129202Scognet#include <sys/disklabel.h> 23129202Scognet#include <sys/diskslice.h> 24129202Scognet#include "libdisk.h" 25129202Scognet 26129202Scognet#define DOSPTYP_EXTENDED 5 27129202Scognet#define DOSPTYP_ONTRACK 84 28129202Scognet 29129202Scognetconst char *chunk_n[] = { 30129202Scognet "whole", 31129202Scognet "unknown", 32129202Scognet "fat", 33129202Scognet "freebsd", 34129202Scognet "extended", 35129202Scognet "part", 36129202Scognet "unused", 37129202Scognet NULL 38129202Scognet}; 39129202Scognet 40129202Scognetstruct disk * 41129202ScognetOpen_Disk(const char *name) 42129202Scognet{ 43129202Scognet return Int_Open_Disk(name,0); 44129202Scognet} 45129202Scognet 46129202Scognetstruct disk * 47129202ScognetInt_Open_Disk(const char *name, u_long size) 48129202Scognet{ 49129202Scognet int i,fd; 50 struct diskslices ds; 51 struct disklabel dl; 52 char device[64]; 53 struct disk *d; 54 struct dos_partition *dp; 55 void *p; 56 u_long offset = 0; 57 58 strcpy(device,"/dev/r"); 59 strcat(device,name); 60 61 d = (struct disk *)malloc(sizeof *d); 62 if(!d) err(1,"malloc failed"); 63 memset(d,0,sizeof *d); 64 65 fd = open(device,O_RDONLY); 66 if (fd < 0) { 67#ifdef DEBUG 68 warn("open(%s) failed",device); 69#endif 70 return 0; 71 } 72 73 memset(&dl,0,sizeof dl); 74 ioctl(fd,DIOCGDINFO,&dl); 75 i = ioctl(fd,DIOCGSLICEINFO,&ds); 76 if (i < 0) { 77#ifdef DEBUG 78 warn("DIOCGSLICEINFO(%s) failed",device); 79#endif 80 close(fd); 81 return 0; 82 } 83 84#ifdef DEBUG 85 for(i=0;i<ds.dss_nslices;i++) 86 if(ds.dss_slices[i].ds_openmask) 87 printf(" open(%d)=0x%2x", 88 i,ds.dss_slices[i].ds_openmask); 89 printf("\n"); 90#endif 91 92 if (!size) 93 size = ds.dss_slices[WHOLE_DISK_SLICE].ds_size; 94 95 p = read_block(fd,0); 96 dp = (struct dos_partition*)(p+DOSPARTOFF); 97 for(i=0;i<NDOSPART;i++) { 98 if (dp->dp_start >= size) continue; 99 if (dp->dp_start+dp->dp_size >= size) continue; 100 if (!dp->dp_size) continue; 101 102 if (dp->dp_typ == DOSPTYP_ONTRACK) { 103 d->flags |= DISK_ON_TRACK; 104 offset = 63; 105 } 106 107 } 108 free(p); 109 110 d->bios_sect = dl.d_nsectors; 111 d->bios_hd = dl.d_ntracks; 112 113 d->name = strdup(name); 114 115 116 if (dl.d_ntracks && dl.d_nsectors) 117 d->bios_cyl = size/(dl.d_ntracks*dl.d_nsectors); 118 119 if (Add_Chunk(d, -offset, size, name, whole, 0, 0)) 120#ifdef DEBUG 121 warn("Failed to add 'whole' chunk"); 122#else 123 {} 124#endif 125 126 for(i=BASE_SLICE;i<ds.dss_nslices;i++) { 127 char sname[20]; 128 chunk_e ce; 129 u_long flags=0; 130 int subtype=0; 131 if (! ds.dss_slices[i].ds_size) 132 continue; 133 ds.dss_slices[i].ds_offset -= offset; 134 sprintf(sname,"%ss%d",name,i-1); 135 subtype = ds.dss_slices[i].ds_type; 136 switch (ds.dss_slices[i].ds_type) { 137 case 0xa5: 138 ce = freebsd; 139 break; 140 case 0x1: 141 case 0x6: 142 case 0x4: 143 case 0xb: 144 case 0xc: 145 case 0xe: 146 ce = fat; 147 break; 148 case DOSPTYP_EXTENDED: 149 case 0xf: 150 ce = extended; 151 break; 152 default: 153 ce = unknown; 154 break; 155 } 156 if (Add_Chunk(d, ds.dss_slices[i].ds_offset, 157 ds.dss_slices[i].ds_size, sname, ce, subtype, flags)) 158#ifdef DEBUG 159 warn("failed to add chunk for slice %d", i - 1); 160#else 161 {} 162#endif 163 164 if (ds.dss_slices[i].ds_type != 0xa5) 165 continue; 166 { 167 struct disklabel dl; 168 char pname[20]; 169 int j,k; 170 171 strcpy(pname,"/dev/r"); 172 strcat(pname,sname); 173 j = open(pname,O_RDONLY); 174 if (j < 0) { 175#ifdef DEBUG 176 warn("open(%s)",pname); 177#endif 178 continue; 179 } 180 k = ioctl(j,DIOCGDINFO,&dl); 181 if (k < 0) { 182#ifdef DEBUG 183 warn("ioctl(%s,DIOCGDINFO)",pname); 184#endif 185 close(j); 186 continue; 187 } 188 close(j); 189 190 for(j=0; j <= dl.d_npartitions; j++) { 191 if (j == RAW_PART) 192 continue; 193 if (j == 3) 194 continue; 195 if (j == dl.d_npartitions) { 196 j = 3; 197 dl.d_npartitions=0; 198 } 199 if (!dl.d_partitions[j].p_size) 200 continue; 201 if (dl.d_partitions[j].p_size + 202 dl.d_partitions[j].p_offset > 203 ds.dss_slices[i].ds_size) 204 continue; 205 sprintf(pname,"%s%c",sname,j+'a'); 206 if (Add_Chunk(d, 207 dl.d_partitions[j].p_offset + 208 ds.dss_slices[i].ds_offset, 209 dl.d_partitions[j].p_size, 210 pname,part, 211 dl.d_partitions[j].p_fstype, 212 0) && j != 3) 213#ifdef DEBUG 214 warn( 215 "Failed to add chunk for partition %c [%lu,%lu]", 216 j + 'a',dl.d_partitions[j].p_offset, 217 dl.d_partitions[j].p_size); 218#else 219 {} 220#endif 221 } 222 } 223 } 224 close(fd); 225 Fixup_Names(d); 226 Bios_Limit_Chunk(d->chunks,1024*d->bios_hd*d->bios_sect); 227 return d; 228} 229 230void 231Debug_Disk(struct disk *d) 232{ 233 printf("Debug_Disk(%s)",d->name); 234 printf(" flags=%lx",d->flags); 235#if 0 236 printf(" real_geom=%lu/%lu/%lu",d->real_cyl,d->real_hd,d->real_sect); 237#endif 238 printf(" bios_geom=%lu/%lu/%lu = %lu\n", 239 d->bios_cyl,d->bios_hd,d->bios_sect, 240 d->bios_cyl*d->bios_hd*d->bios_sect); 241 printf(" boot1=%p, boot2=%p, bootmgr=%p\n", 242 d->boot1,d->boot2,d->bootmgr); 243 Debug_Chunk(d->chunks); 244} 245 246void 247Free_Disk(struct disk *d) 248{ 249 if(d->chunks) Free_Chunk(d->chunks); 250 if(d->name) free(d->name); 251 if(d->bootmgr) free(d->bootmgr); 252 if(d->boot1) free(d->boot1); 253 if(d->boot2) free(d->boot2); 254 free(d); 255} 256 257struct disk * 258Clone_Disk(struct disk *d) 259{ 260 struct disk *d2; 261 262 d2 = (struct disk*) malloc(sizeof *d2); 263 if(!d2) err(1,"malloc failed"); 264 *d2 = *d; 265 d2->name = strdup(d2->name); 266 d2->chunks = Clone_Chunk(d2->chunks); 267 if(d2->bootmgr) { 268 d2->bootmgr = malloc(DOSPARTOFF); 269 memcpy(d2->bootmgr,d->bootmgr,DOSPARTOFF); 270 } 271 if(d2->boot1) { 272 d2->boot1 = malloc(512); 273 memcpy(d2->boot1,d->boot1,512); 274 } 275 if(d2->boot2) { 276 d2->boot2 = malloc(512*15); 277 memcpy(d2->boot2,d->boot2,512*15); 278 } 279 return d2; 280} 281 282#if 0 283void 284Collapse_Disk(struct disk *d) 285{ 286 287 while(Collapse_Chunk(d,d->chunks)) 288 ; 289} 290#endif 291 292static char * device_list[] = {"wd","sd","da","od",0}; 293 294char ** 295Disk_Names() 296{ 297 int i,j,k; 298 char disk[25]; 299 char diskname[25]; 300 struct stat st; 301 struct diskslices ds; 302 int fd; 303 static char **disks; 304 305 disks = malloc(sizeof *disks * (1 + MAX_NO_DISKS)); 306 memset(disks,0,sizeof *disks * (1 + MAX_NO_DISKS)); 307 k = 0; 308 for (j = 0; device_list[j]; j++) { 309 for (i = 0; i < 10; i++) { 310 sprintf(diskname, "%s%d", device_list[j], i); 311 sprintf(disk, "/dev/r%s", diskname); 312 if (stat(disk, &st) || !(st.st_mode & S_IFCHR)) 313 continue; 314 if ((fd = open(disk, O_RDWR)) == -1) 315 continue; 316 if (ioctl(fd, DIOCGSLICEINFO, &ds) == -1) { 317 close(fd); 318 continue; 319 } 320 disks[k++] = strdup(diskname); 321 if(k == MAX_NO_DISKS) 322 return disks; 323 } 324 } 325 return disks; 326} 327 328void 329Set_Boot_Mgr(struct disk *d, const u_char *b) 330{ 331 if (d->bootmgr) 332 free(d->bootmgr); 333 if (!b) { 334 d->bootmgr = 0; 335 } else { 336 d->bootmgr = malloc(DOSPARTOFF); 337 if(!d->bootmgr) err(1,"malloc failed"); 338 memcpy(d->bootmgr,b,DOSPARTOFF); 339 } 340} 341 342void 343Set_Boot_Blocks(struct disk *d, const u_char *b1, const u_char *b2) 344{ 345 if (d->boot1) free(d->boot1); 346 d->boot1 = malloc(512); 347 if(!d->boot1) err(1,"malloc failed"); 348 memcpy(d->boot1,b1,512); 349 if (d->boot2) free(d->boot2); 350 d->boot2 = malloc(15*512); 351 if(!d->boot2) err(1,"malloc failed"); 352 memcpy(d->boot2,b2,15*512); 353} 354 355const char * 356slice_type_name( int type, int subtype ) 357{ 358 switch (type) { 359 case 0: return "whole"; 360 case 1: switch (subtype) { 361 case 1: return "fat (12-bit)"; 362 case 2: return "XENIX /"; 363 case 3: return "XENIX /usr"; 364 case 4: return "fat (16-bit,<=32Mb)"; 365 case 5: return "extended DOS"; 366 case 6: return "fat (16-bit,>32Mb)"; 367 case 7: return "NTFS/HPFS/QNX"; 368 case 8: return "AIX bootable"; 369 case 9: return "AIX data"; 370 case 10: return "OS/2 bootmgr"; 371 case 11: return "fat (32-bit)"; 372 case 12: return "fat (32-bit,LBA)"; 373 case 14: return "fat (16-bit,>32Mb,LBA)"; 374 case 15: return "extended DOS, LBA"; 375 case 84: return "OnTrack diskmgr"; 376 case 100: return "Netware 2.x"; 377 case 101: return "Netware 3.x"; 378 case 128: return "Minix 1.1"; 379 case 129: return "Minix 1.5"; 380 case 130: return "linux_swap"; 381 case 131: return "ext2fs"; 382 case 166: return "OpenBSD FFS"; /* 0xA6 */ 383 case 182: return "OpenBSD"; /* dedicated */ 384 case 183: return "bsd/os"; 385 case 184: return "bsd/os swap"; 386 default: return "unknown"; 387 } 388 case 2: return "fat"; 389 case 3: switch (subtype) { 390 case 165: return "freebsd"; 391 default: return "unknown"; 392 } 393 case 4: return "extended"; 394 case 5: return "part"; 395 case 6: return "unused"; 396 default: return "unknown"; 397 } 398} 399