diff options
Diffstat (limited to 'lib/libdisk/disk.c')
-rw-r--r-- | lib/libdisk/disk.c | 494 |
1 files changed, 494 insertions, 0 deletions
diff --git a/lib/libdisk/disk.c b/lib/libdisk/disk.c new file mode 100644 index 0000000..cae69a0 --- /dev/null +++ b/lib/libdisk/disk.c @@ -0,0 +1,494 @@ +/* + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp + * ---------------------------------------------------------------------------- + * + * $FreeBSD$ + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include <err.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <sys/disklabel.h> +#include <sys/diskslice.h> +#include "libdisk.h" + +#define DOSPTYP_EXTENDED 5 +#define DOSPTYP_ONTRACK 84 + +const char *chunk_n[] = { + "whole", + "unknown", + "fat", + "freebsd", + "extended", + "part", + "unused", + NULL +}; + +struct disk * +Open_Disk(const char *name) +{ + return Int_Open_Disk(name,0); +} + +static u_int32_t +Read_Int32(u_int32_t *p) +{ + u_int8_t *bp = (u_int8_t *)p; + return bp[0] | (bp[1] << 8) | (bp[2] << 16) | (bp[3] << 24); +} + +struct disk * +Int_Open_Disk(const char *name, u_long size) +{ + int i,fd; + struct diskslices ds; + struct disklabel dl; + char device[64]; + struct disk *d; + struct dos_partition *dp; + void *p; + u_long offset = 0; + + strcpy(device,"/dev/r"); + strcat(device,name); + + d = (struct disk *)malloc(sizeof *d); + if(!d) err(1,"malloc failed"); + memset(d,0,sizeof *d); + + fd = open(device,O_RDONLY); + if (fd < 0) { +#ifdef DEBUG + warn("open(%s) failed",device); +#endif + return 0; + } + + memset(&dl,0,sizeof dl); + ioctl(fd,DIOCGDINFO,&dl); + i = ioctl(fd,DIOCGSLICEINFO,&ds); + if (i < 0) { +#ifdef DEBUG + warn("DIOCGSLICEINFO(%s) failed",device); +#endif + close(fd); + return 0; + } + +#ifdef DEBUG + for(i=0;i<ds.dss_nslices;i++) + if(ds.dss_slices[i].ds_openmask) + printf(" open(%d)=0x%2x", + i,ds.dss_slices[i].ds_openmask); + printf("\n"); +#endif + + if (!size) + size = ds.dss_slices[WHOLE_DISK_SLICE].ds_size; + + p = read_block(fd,0); + dp = (struct dos_partition*)(p+DOSPARTOFF); + for (i=0; i < NDOSPART; i++) { + if (Read_Int32(&dp->dp_start) >= size) + continue; + if (Read_Int32(&dp->dp_start) + Read_Int32(&dp->dp_size) >= size) + continue; + if (!Read_Int32(&dp->dp_size)) + continue; + + if (dp->dp_typ == DOSPTYP_ONTRACK) { + d->flags |= DISK_ON_TRACK; + offset = 63; + } + + } + free(p); + + d->bios_sect = dl.d_nsectors; + d->bios_hd = dl.d_ntracks; + + d->name = strdup(name); + + + if (dl.d_ntracks && dl.d_nsectors) + d->bios_cyl = size/(dl.d_ntracks*dl.d_nsectors); + + if (Add_Chunk(d, -offset, size, name, whole, 0, 0)) +#ifdef DEBUG + warn("Failed to add 'whole' chunk"); +#else + {} +#endif + +#ifdef __i386__ + for(i=BASE_SLICE;i<ds.dss_nslices;i++) { + char sname[20]; + chunk_e ce; + u_long flags=0; + int subtype=0; + if (! ds.dss_slices[i].ds_size) + continue; + ds.dss_slices[i].ds_offset -= offset; + sprintf(sname,"%ss%d",name,i-1); + subtype = ds.dss_slices[i].ds_type; + switch (ds.dss_slices[i].ds_type) { + case 0xa5: + ce = freebsd; + break; + case 0x1: + case 0x6: + case 0x4: + case 0xb: + case 0xc: + case 0xe: + ce = fat; + break; + case DOSPTYP_EXTENDED: + case 0xf: + ce = extended; + break; + default: + ce = unknown; + break; + } + if (Add_Chunk(d, ds.dss_slices[i].ds_offset, + ds.dss_slices[i].ds_size, sname, ce, subtype, flags)) +#ifdef DEBUG + warn("failed to add chunk for slice %d", i - 1); +#else + {} +#endif + + if (ds.dss_slices[i].ds_type != 0xa5) + continue; + { + struct disklabel dl; + char pname[20]; + int j,k; + + strcpy(pname,"/dev/r"); + strcat(pname,sname); + j = open(pname,O_RDONLY); + if (j < 0) { +#ifdef DEBUG + warn("open(%s)",pname); +#endif + continue; + } + k = ioctl(j,DIOCGDINFO,&dl); + if (k < 0) { +#ifdef DEBUG + warn("ioctl(%s,DIOCGDINFO)",pname); +#endif + close(j); + continue; + } + close(j); + + for(j=0; j <= dl.d_npartitions; j++) { + if (j == RAW_PART) + continue; + if (j == 3) + continue; + if (j == dl.d_npartitions) { + j = 3; + dl.d_npartitions=0; + } + if (!dl.d_partitions[j].p_size) + continue; + if (dl.d_partitions[j].p_size + + dl.d_partitions[j].p_offset > + ds.dss_slices[i].ds_size) + continue; + sprintf(pname,"%s%c",sname,j+'a'); + if (Add_Chunk(d, + dl.d_partitions[j].p_offset + + ds.dss_slices[i].ds_offset, + dl.d_partitions[j].p_size, + pname,part, + dl.d_partitions[j].p_fstype, + 0) && j != 3) +#ifdef DEBUG + warn( + "Failed to add chunk for partition %c [%lu,%lu]", + j + 'a',dl.d_partitions[j].p_offset, + dl.d_partitions[j].p_size); +#else + {} +#endif + } + } + } +#endif /* __i386__ */ +#ifdef __alpha__ + { + struct disklabel dl; + char pname[20]; + int j,k; + + strcpy(pname,"/dev/r"); + strcat(pname,name); + j = open(pname,O_RDONLY); + if (j < 0) { +#ifdef DEBUG + warn("open(%s)",pname); +#endif + goto nolabel; + } + k = ioctl(j,DIOCGDINFO,&dl); + if (k < 0) { +#ifdef DEBUG + warn("ioctl(%s,DIOCGDINFO)",pname); +#endif + close(j); + goto nolabel; + } + close(j); + All_FreeBSD(d, 1); + + for(j=0; j <= dl.d_npartitions; j++) { + if (j == RAW_PART) + continue; + if (j == 3) + continue; + if (j == dl.d_npartitions) { + j = 3; + dl.d_npartitions=0; + } + if (!dl.d_partitions[j].p_size) + continue; + if (dl.d_partitions[j].p_size + + dl.d_partitions[j].p_offset > + ds.dss_slices[WHOLE_DISK_SLICE].ds_size) + continue; + sprintf(pname,"%s%c",name,j+'a'); + if (Add_Chunk(d, + dl.d_partitions[j].p_offset, + dl.d_partitions[j].p_size, + pname,part, + dl.d_partitions[j].p_fstype, + 0) && j != 3) +#ifdef DEBUG + warn( + "Failed to add chunk for partition %c [%lu,%lu]", + j + 'a',dl.d_partitions[j].p_offset, + dl.d_partitions[j].p_size); +#else + {} +#endif + } + nolabel:; + } +#endif /* __alpha__ */ + close(fd); + Fixup_Names(d); + Bios_Limit_Chunk(d->chunks,1024*d->bios_hd*d->bios_sect); + return d; +} + +void +Debug_Disk(struct disk *d) +{ + printf("Debug_Disk(%s)",d->name); + printf(" flags=%lx",d->flags); +#if 0 + printf(" real_geom=%lu/%lu/%lu",d->real_cyl,d->real_hd,d->real_sect); +#endif + printf(" bios_geom=%lu/%lu/%lu = %lu\n", + d->bios_cyl,d->bios_hd,d->bios_sect, + d->bios_cyl*d->bios_hd*d->bios_sect); +#if defined(__i386__) + printf(" boot1=%p, boot2=%p, bootmgr=%p\n", + d->boot1,d->boot2,d->bootmgr); +#elif defined(__alpha__) + printf(" boot1=%p, bootmgr=%p\n", + d->boot1,d->bootmgr); +#endif + Debug_Chunk(d->chunks); +} + +void +Free_Disk(struct disk *d) +{ + if(d->chunks) Free_Chunk(d->chunks); + if(d->name) free(d->name); + if(d->bootmgr) free(d->bootmgr); + if(d->boot1) free(d->boot1); +#if defined(__i386__) + if(d->boot2) free(d->boot2); +#endif + free(d); +} + +struct disk * +Clone_Disk(struct disk *d) +{ + struct disk *d2; + + d2 = (struct disk*) malloc(sizeof *d2); + if(!d2) err(1,"malloc failed"); + *d2 = *d; + d2->name = strdup(d2->name); + d2->chunks = Clone_Chunk(d2->chunks); + if(d2->bootmgr) { + d2->bootmgr = malloc(DOSPARTOFF); + memcpy(d2->bootmgr,d->bootmgr,DOSPARTOFF); + } +#if defined(__i386__) + if(d2->boot1) { + d2->boot1 = malloc(512); + memcpy(d2->boot1,d->boot1,512); + } + if(d2->boot2) { + d2->boot2 = malloc(512*15); + memcpy(d2->boot2,d->boot2,512*15); + } +#elif defined(__alpha__) + if(d2->boot1) { + d2->boot1 = malloc(512*15); + memcpy(d2->boot1,d->boot1,512*15); + } +#endif + return d2; +} + +#if 0 +void +Collapse_Disk(struct disk *d) +{ + + while(Collapse_Chunk(d,d->chunks)) + ; +} +#endif + +static char * device_list[] = {"wd", "ad", "da", "wfd", "fla", "ida", "mlxd", "amrd", 0}; + +char ** +Disk_Names() +{ + int i,j,k; + char disk[25]; + char diskname[25]; + struct stat st; + struct diskslices ds; + int fd; + static char **disks; + + disks = malloc(sizeof *disks * (1 + MAX_NO_DISKS)); + memset(disks,0,sizeof *disks * (1 + MAX_NO_DISKS)); + k = 0; + for (j = 0; device_list[j]; j++) { + for (i = 0; i < MAX_NO_DISKS; i++) { + sprintf(diskname, "%s%d", device_list[j], i); + sprintf(disk, "/dev/r%s", diskname); + if (stat(disk, &st) || !(st.st_mode & S_IFCHR)) + continue; + if ((fd = open(disk, O_RDWR)) == -1) + continue; + if (ioctl(fd, DIOCGSLICEINFO, &ds) == -1) { + close(fd); + continue; + } + disks[k++] = strdup(diskname); + if(k == MAX_NO_DISKS) + return disks; + } + } + return disks; +} + +void +Set_Boot_Mgr(struct disk *d, const u_char *b) +{ + if (d->bootmgr) + free(d->bootmgr); + if (!b) { + d->bootmgr = 0; + } else { + d->bootmgr = malloc(DOSPARTOFF); + if(!d->bootmgr) err(1,"malloc failed"); + memcpy(d->bootmgr,b,DOSPARTOFF); + } +} + +void +Set_Boot_Blocks(struct disk *d, const u_char *b1, const u_char *b2) +{ +#if defined(__i386__) + if (d->boot1) free(d->boot1); + d->boot1 = malloc(512); + if(!d->boot1) err(1,"malloc failed"); + memcpy(d->boot1,b1,512); + if (d->boot2) free(d->boot2); + d->boot2 = malloc(15*512); + if(!d->boot2) err(1,"malloc failed"); + memcpy(d->boot2,b2,15*512); +#elif defined(__alpha__) + if (d->boot1) free(d->boot1); + d->boot1 = malloc(15*512); + if(!d->boot1) err(1,"malloc failed"); + memcpy(d->boot1,b1,15*512); +#endif +} + +const char * +slice_type_name( int type, int subtype ) +{ + switch (type) { + case 0: return "whole"; + case 1: switch (subtype) { + case 1: return "fat (12-bit)"; + case 2: return "XENIX /"; + case 3: return "XENIX /usr"; + case 4: return "fat (16-bit,<=32Mb)"; + case 5: return "extended DOS"; + case 6: return "fat (16-bit,>32Mb)"; + case 7: return "NTFS/HPFS/QNX"; + case 8: return "AIX bootable"; + case 9: return "AIX data"; + case 10: return "OS/2 bootmgr"; + case 11: return "fat (32-bit)"; + case 12: return "fat (32-bit,LBA)"; + case 14: return "fat (16-bit,>32Mb,LBA)"; + case 15: return "extended DOS, LBA"; + case 18: return "Compaq Diagnostic"; + case 84: return "OnTrack diskmgr"; + case 100: return "Netware 2.x"; + case 101: return "Netware 3.x"; + case 115: return "SCO UnixWare"; + case 128: return "Minix 1.1"; + case 129: return "Minix 1.5"; + case 130: return "linux_swap"; + case 131: return "ext2fs"; + case 166: return "OpenBSD FFS"; /* 0xA6 */ + case 169: return "NetBSD FFS"; /* 0xA9 */ + case 182: return "OpenBSD"; /* dedicated */ + case 183: return "bsd/os"; + case 184: return "bsd/os swap"; + default: return "unknown"; + } + case 2: return "fat"; + case 3: switch (subtype) { + case 165: return "freebsd"; + default: return "unknown"; + } + case 4: return "extended"; + case 5: return "part"; + case 6: return "unused"; + default: return "unknown"; + } +} |