disk.c revision 8233
1224793Sjonathan/* 2224793Sjonathan * ---------------------------------------------------------------------------- 3224793Sjonathan * "THE BEER-WARE LICENSE" (Revision 42): 4224793Sjonathan * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you 5224793Sjonathan * can do whatever you want with this stuff. If we meet some day, and you think 6224793Sjonathan * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp 7224793Sjonathan * ---------------------------------------------------------------------------- 8224793Sjonathan * 9224793Sjonathan * $Id: disk.c,v 1.12 1995/05/02 20:16:16 jkh Exp $ 10224793Sjonathan * 11224793Sjonathan */ 12224793Sjonathan 13224793Sjonathan#include <stdio.h> 14224793Sjonathan#include <stdlib.h> 15224793Sjonathan#include <unistd.h> 16224793Sjonathan#include <fcntl.h> 17224793Sjonathan#include <string.h> 18224793Sjonathan#include <err.h> 19224793Sjonathan#include <sys/types.h> 20224793Sjonathan#include <sys/stat.h> 21224793Sjonathan#include <sys/ioctl.h> 22224793Sjonathan#include <sys/disklabel.h> 23224793Sjonathan#include <sys/diskslice.h> 24224793Sjonathan#include "libdisk.h" 25224793Sjonathan 26224793Sjonathan#define DOSPTYP_EXTENDED 5 27224793Sjonathan#define DOSPTYP_ONTRACK 84 28224793Sjonathan 29224793Sjonathanstruct disk * 30224793SjonathanOpen_Disk(char *name) 31224793Sjonathan{ 32224793Sjonathan return Int_Open_Disk(name,0); 33224793Sjonathan} 34280250Srwatson 35224793Sjonathanstruct disk * 36224793SjonathanInt_Open_Disk(char *name, u_long size) 37224793Sjonathan{ 38224793Sjonathan int i,fd; 39224793Sjonathan struct diskslices ds; 40224793Sjonathan struct disklabel dl; 41224793Sjonathan char device[64]; 42224793Sjonathan struct disk *d; 43224793Sjonathan struct dos_partition *dp; 44224793Sjonathan void *p; 45224793Sjonathan 46224793Sjonathan strcpy(device,"/dev/r"); 47224793Sjonathan strcat(device,name); 48224793Sjonathan 49224793Sjonathan d = (struct disk *)malloc(sizeof *d); 50224793Sjonathan if(!d) err(1,"malloc failed"); 51224793Sjonathan memset(d,0,sizeof *d); 52224793Sjonathan 53224793Sjonathan fd = open(device,O_RDONLY); 54224793Sjonathan if (fd < 0) { 55224793Sjonathan warn("open(%s) failed",device); 56224793Sjonathan return 0; 57224793Sjonathan } 58224793Sjonathan 59224793Sjonathan memset(&dl,0,sizeof dl); 60224793Sjonathan ioctl(fd,DIOCGDINFO,&dl); 61224793Sjonathan i = ioctl(fd,DIOCGSLICEINFO,&ds); 62224793Sjonathan if (i < 0) { 63224793Sjonathan warn("DIOCGSLICEINFO(%s) failed",device); 64247605Spjd close(fd); 65247605Spjd return 0; 66224793Sjonathan } 67224793Sjonathan 68224793Sjonathan#ifdef DEBUG 69224793Sjonathan for(i=0;i<ds.dss_nslices;i++) 70224793Sjonathan if(ds.dss_slices[i].ds_openmask) 71224793Sjonathan printf(" open(%d)=0x%2x", 72224793Sjonathan i,ds.dss_slices[i].ds_openmask); 73224793Sjonathan printf("\n"); 74224793Sjonathan#endif 75224793Sjonathan 76224793Sjonathan if (!size) 77224793Sjonathan size = ds.dss_slices[WHOLE_DISK_SLICE].ds_size; 78224793Sjonathan 79224793Sjonathan p = read_block(fd,0); 80224793Sjonathan dp = (struct dos_partition*)(p+DOSPARTOFF); 81224793Sjonathan for(i=0;i<NDOSPART;i++) { 82224793Sjonathan if (dp->dp_start >= size) continue; 83224793Sjonathan if (dp->dp_start+dp->dp_size >= size) continue; 84224793Sjonathan if (!dp->dp_size) continue; 85224793Sjonathan 86224793Sjonathan if (dp->dp_typ == DOSPTYP_ONTRACK) 87224793Sjonathan d->flags |= DISK_ON_TRACK; 88224793Sjonathan 89224793Sjonathan } 90224793Sjonathan free(p); 91224793Sjonathan 92224793Sjonathan d->bios_sect = dl.d_nsectors; 93224793Sjonathan d->bios_hd = dl.d_ntracks; 94224793Sjonathan 95224793Sjonathan d->name = strdup(name); 96224793Sjonathan 97224793Sjonathan 98224793Sjonathan if (dl.d_ntracks && dl.d_nsectors) 99224793Sjonathan d->bios_cyl = size/(dl.d_ntracks*dl.d_nsectors); 100224793Sjonathan 101224793Sjonathan if (Add_Chunk(d, 0, size, name,whole,0,0)) 102224793Sjonathan warn("Failed to add 'whole' chunk"); 103224793Sjonathan 104224793Sjonathan for(i=BASE_SLICE;i<ds.dss_nslices;i++) { 105224793Sjonathan char sname[20]; 106224793Sjonathan chunk_e ce; 107224793Sjonathan u_long flags=0; 108224793Sjonathan int subtype=0; 109224793Sjonathan if (! ds.dss_slices[i].ds_size) 110224793Sjonathan continue; 111224793Sjonathan sprintf(sname,"%ss%d",name,i-1); 112224793Sjonathan subtype = ds.dss_slices[i].ds_type; 113224793Sjonathan switch (ds.dss_slices[i].ds_type) { 114224793Sjonathan case 0xa5: 115224793Sjonathan ce = freebsd; 116224793Sjonathan break; 117224793Sjonathan case 0x1: 118224793Sjonathan case 0x4: 119224793Sjonathan ce = fat; 120224793Sjonathan break; 121224793Sjonathan case DOSPTYP_EXTENDED: 122224793Sjonathan ce = extended; 123224793Sjonathan break; 124224793Sjonathan default: 125224793Sjonathan ce = unknown; 126224793Sjonathan break; 127224793Sjonathan } 128224793Sjonathan flags |= CHUNK_ALIGN; 129224793Sjonathan if (Add_Chunk(d,ds.dss_slices[i].ds_offset, 130224793Sjonathan ds.dss_slices[i].ds_size, sname,ce,subtype,flags)) 131224793Sjonathan warn("failed to add chunk for slice %d",i - 1); 132224793Sjonathan 133224793Sjonathan if (ds.dss_slices[i].ds_type != 0xa5) 134224793Sjonathan continue; 135224793Sjonathan { 136224793Sjonathan struct disklabel dl; 137224793Sjonathan char pname[20]; 138224793Sjonathan int j,k; 139224793Sjonathan 140224793Sjonathan strcpy(pname,"/dev/r"); 141224793Sjonathan strcat(pname,sname); 142224793Sjonathan j = open(pname,O_RDONLY); 143224793Sjonathan if (j < 0) { 144224793Sjonathan warn("open(%s)",pname); 145224793Sjonathan continue; 146224793Sjonathan } 147224793Sjonathan k = ioctl(j,DIOCGDINFO,&dl); 148224793Sjonathan if (k < 0) { 149224793Sjonathan warn("ioctl(%s,DIOCGDINFO)",pname); 150224793Sjonathan close(j); 151224793Sjonathan continue; 152224793Sjonathan } 153 close(j); 154 155 for(j=0; j <= dl.d_npartitions; j++) { 156 if (j == RAW_PART) 157 continue; 158 if (j == 3) 159 continue; 160 if (j == dl.d_npartitions) { 161 j = 3; 162 dl.d_npartitions=0; 163 } 164 if (!dl.d_partitions[j].p_size) 165 continue; 166 if (dl.d_partitions[j].p_size + 167 dl.d_partitions[j].p_offset > 168 ds.dss_slices[i].ds_size) 169 continue; 170 sprintf(pname,"%s%c",sname,j+'a'); 171 if (Add_Chunk(d, 172 dl.d_partitions[j].p_offset + 173 ds.dss_slices[i].ds_offset, 174 dl.d_partitions[j].p_size, 175 pname,part, 176 dl.d_partitions[j].p_fstype, 177 j == 0 ? CHUNK_IS_ROOT : 0) && j != 3) 178 warn( 179 "Failed to add chunk for partition %c [%lu,%lu]", 180 j + 'a',dl.d_partitions[j].p_offset, 181 dl.d_partitions[j].p_size); 182 } 183 } 184 } 185 close(fd); 186 Fixup_Names(d); 187 return d; 188} 189 190void 191Debug_Disk(struct disk *d) 192{ 193 printf("Debug_Disk(%s)",d->name); 194 printf(" flags=%lx",d->flags); 195 printf(" real_geom=%lu/%lu/%lu",d->real_cyl,d->real_hd,d->real_sect); 196 printf(" bios_geom=%lu/%lu/%lu\n",d->bios_cyl,d->bios_hd,d->bios_sect); 197 printf(" boot1=%p, boot2=%p, bootmgr=%p\n", 198 d->boot1,d->boot2,d->bootmgr); 199 Debug_Chunk(d->chunks); 200} 201 202void 203Free_Disk(struct disk *d) 204{ 205 if(d->chunks) Free_Chunk(d->chunks); 206 if(d->name) free(d->name); 207 if(d->bootmgr) free(d->bootmgr); 208 if(d->boot1) free(d->boot1); 209 if(d->boot2) free(d->boot2); 210 free(d); 211} 212 213struct disk * 214Clone_Disk(struct disk *d) 215{ 216 struct disk *d2; 217 218 d2 = (struct disk*) malloc(sizeof *d2); 219 if(!d2) err(1,"malloc failed"); 220 *d2 = *d; 221 d2->name = strdup(d2->name); 222 d2->chunks = Clone_Chunk(d2->chunks); 223 if(d2->bootmgr) { 224 d2->bootmgr = malloc(DOSPARTOFF); 225 memcpy(d2->bootmgr,d->bootmgr,DOSPARTOFF); 226 } 227 if(d2->boot1) { 228 d2->boot1 = malloc(512); 229 memcpy(d2->boot1,d->boot1,512); 230 } 231 if(d2->boot2) { 232 d2->boot2 = malloc(512*15); 233 memcpy(d2->boot2,d->boot2,512*15); 234 } 235 return d2; 236} 237 238void 239Collapse_Disk(struct disk *d) 240{ 241 242 while(Collapse_Chunk(d,d->chunks)) 243 ; 244} 245 246static char * device_list[] = {"wd","sd",0}; 247 248char ** 249Disk_Names() 250{ 251 int i,j,k; 252 char disk[25]; 253 char diskname[25]; 254 struct stat st; 255 struct diskslices ds; 256 int fd; 257 static char **disks; 258 259 disks = malloc(sizeof *disks * (1 + MAX_NO_DISKS)); 260 memset(disks,0,sizeof *disks * (1 + MAX_NO_DISKS)); 261 k = 0; 262 for (j = 0; device_list[j]; j++) { 263 for (i = 0; i < 10; i++) { 264 sprintf(diskname, "%s%d", device_list[j], i); 265 sprintf(disk, "/dev/r%s", diskname); 266 if (stat(disk, &st) || !(st.st_mode & S_IFCHR)) 267 continue; 268 if ((fd = open(disk, O_RDWR)) == -1) 269 continue; 270 if (ioctl(fd, DIOCGSLICEINFO, &ds) == -1) { 271 close(fd); 272 continue; 273 } 274 disks[k++] = strdup(diskname); 275 if(k == MAX_NO_DISKS) 276 return disks; 277 } 278 } 279 return disks; 280} 281 282void 283Set_Boot_Mgr(struct disk *d, u_char *b) 284{ 285 if (d->bootmgr) 286 free(d->bootmgr); 287 if (!b) { 288 d->bootmgr = 0; 289 } else { 290 d->bootmgr = malloc(DOSPARTOFF); 291 if(!d->bootmgr) err(1,"malloc failed"); 292 memcpy(d->bootmgr,b,DOSPARTOFF); 293 } 294} 295 296void 297Set_Boot_Blocks(struct disk *d, u_char *b1, u_char *b2) 298{ 299 if (d->boot1) free(d->boot1); 300 d->boot1 = malloc(512); 301 if(!d->boot1) err(1,"malloc failed"); 302 memcpy(d->boot1,b1,512); 303 if (d->boot2) free(d->boot2); 304 d->boot2 = malloc(15*512); 305 if(!d->boot2) err(1,"malloc failed"); 306 memcpy(d->boot2,b2,15*512); 307} 308